Fix task source fallback for Linear integration (#2440)

* Fix task source fallback for Linear integration

* Ignore malformed saved task provider defaults

Co-authored-by: Orca <help@stably.ai>

---------

Co-authored-by: Jinjing <6427696+AmethystLiang@users.noreply.github.com>
Co-authored-by: Orca <help@stably.ai>
This commit is contained in:
Jonathan Avila 2026-05-20 21:10:35 -04:00 committed by GitHub
parent beb97006d0
commit 115eccdba6
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 101 additions and 14 deletions

View File

@ -1798,13 +1798,23 @@ export default function TaskPage(): React.JSX.Element {
() => normalizeVisibleTaskProviders(settings?.visibleTaskProviders),
[settings?.visibleTaskProviders]
)
const defaultTaskSource = settings?.defaultTaskSource ?? 'github'
const visibleTaskProviders = useMemo(
() =>
filterAvailableTaskProviders(preferredVisibleTaskProviders, {
gitlabInstalled: preflightStatus?.glab?.installed === true,
linearConnected: linearStatus.connected === true
}),
[linearStatus.connected, preferredVisibleTaskProviders, preflightStatus?.glab?.installed]
filterAvailableTaskProviders(
preferredVisibleTaskProviders,
{
gitlabInstalled: preflightStatus?.glab?.installed === true,
linearConnected: linearStatus.connected === true
},
defaultTaskSource
),
[
defaultTaskSource,
linearStatus.connected,
preferredVisibleTaskProviders,
preflightStatus?.glab?.installed
]
)
const visibleSourceOptions = useMemo(
() => SOURCE_OPTIONS.filter((source) => visibleTaskProviders.includes(source.id)),
@ -1819,7 +1829,6 @@ export default function TaskPage(): React.JSX.Element {
const defaultTaskViewPreset = normalizeGitHubTaskPreset(settings?.defaultTaskViewPreset ?? 'all')
const initialTaskQuery = getTaskPresetQuery(defaultTaskViewPreset)
const defaultTaskSource = settings?.defaultTaskSource ?? 'github'
const preferredTaskSource = pageData.taskSource ?? defaultTaskSource
const [taskSource, setTaskSource] = useState<TaskSource>(
resolveVisibleTaskProvider(preferredTaskSource, visibleTaskProviders)

View File

@ -49,11 +49,20 @@ const SidebarNav = React.memo(function SidebarNav() {
)
const visibleTaskProviders = React.useMemo(
() =>
filterAvailableTaskProviders(preferredVisibleTaskProviders, {
gitlabInstalled: preflightStatus?.glab?.installed === true,
linearConnected: linearStatus.connected === true
}),
[linearStatus.connected, preferredVisibleTaskProviders, preflightStatus?.glab?.installed]
filterAvailableTaskProviders(
preferredVisibleTaskProviders,
{
gitlabInstalled: preflightStatus?.glab?.installed === true,
linearConnected: linearStatus.connected === true
},
defaultTaskSource
),
[
defaultTaskSource,
linearStatus.connected,
preferredVisibleTaskProviders,
preflightStatus?.glab?.installed
]
)
const resolvedDefaultTaskSource = React.useMemo(
() => resolveVisibleTaskProvider(defaultTaskSource, visibleTaskProviders),

View File

@ -30,6 +30,58 @@ describe('task providers', () => {
).toEqual(['github', 'linear'])
})
it('keeps an available saved default visible when provider visibility drifted', () => {
expect(
filterAvailableTaskProviders(
['linear'],
{
gitlabInstalled: false,
linearConnected: true
},
'github'
)
).toEqual(['github', 'linear'])
})
it('preserves intentionally narrowed providers when the saved default matches them', () => {
expect(
filterAvailableTaskProviders(
['linear'],
{
gitlabInstalled: false,
linearConnected: true
},
'linear'
)
).toEqual(['linear'])
})
it('does not restore an unavailable saved default', () => {
expect(
filterAvailableTaskProviders(
['linear'],
{
gitlabInstalled: false,
linearConnected: true
},
'gitlab'
)
).toEqual(['linear'])
})
it('ignores malformed saved defaults when every preferred provider is unavailable', () => {
expect(
filterAvailableTaskProviders(
['gitlab'],
{
gitlabInstalled: false,
linearConnected: true
},
'jira' as never
)
).toEqual(['github'])
})
it('falls back to GitHub when every preferred provider is unavailable', () => {
expect(
filterAvailableTaskProviders(['gitlab', 'linear'], {

View File

@ -31,9 +31,12 @@ export type TaskProviderAvailability = {
export function filterAvailableTaskProviders(
visibleProviders: readonly TaskProvider[],
availability: TaskProviderAvailability
availability: TaskProviderAvailability,
preferredProvider?: TaskProvider | null
): TaskProvider[] {
const available = visibleProviders.filter((provider) => {
const normalizedPreferredProvider =
preferredProvider && TASK_PROVIDER_SET.has(preferredProvider) ? preferredProvider : null
const isProviderAvailable = (provider: TaskProvider): boolean => {
if (provider === 'github') {
return true
}
@ -41,7 +44,21 @@ export function filterAvailableTaskProviders(
return availability.gitlabInstalled
}
return availability.linearConnected
})
}
const available = visibleProviders.filter(isProviderAvailable)
// Why: older or drifted settings can hide the saved default while another
// provider becomes available. Keep that default reachable after hydration.
if (
normalizedPreferredProvider &&
isProviderAvailable(normalizedPreferredProvider) &&
!available.includes(normalizedPreferredProvider)
) {
return TASK_PROVIDERS.filter(
(provider) => provider === normalizedPreferredProvider || available.includes(provider)
)
}
return available.length > 0 ? available : ['github']
}