mirror of
https://github.com/stablyai/orca.git
synced 2026-09-22 08:02:28 +00:00
120 lines
3.8 KiB
TypeScript
120 lines
3.8 KiB
TypeScript
export type TaskProvider = 'github' | 'gitlab' | 'linear' | 'jira'
|
|
|
|
export const TASK_PROVIDERS: readonly TaskProvider[] = ['github', 'gitlab', 'linear', 'jira']
|
|
|
|
const TASK_PROVIDER_SET = new Set<TaskProvider>(TASK_PROVIDERS)
|
|
|
|
export function isTaskProvider(value: unknown): value is TaskProvider {
|
|
return TASK_PROVIDER_SET.has(value as TaskProvider)
|
|
}
|
|
|
|
export function normalizeTaskProviderSettings(value: {
|
|
visibleTaskProviders: unknown
|
|
defaultTaskSource: unknown
|
|
}): { visibleTaskProviders: TaskProvider[]; defaultTaskSource: TaskProvider } {
|
|
const visibleTaskProviders = normalizeVisibleTaskProviders(value.visibleTaskProviders)
|
|
const defaultTaskSource = isTaskProvider(value.defaultTaskSource)
|
|
? value.defaultTaskSource
|
|
: resolveVisibleTaskProvider('github', visibleTaskProviders)
|
|
|
|
if (visibleTaskProviders.includes(defaultTaskSource)) {
|
|
return { visibleTaskProviders, defaultTaskSource }
|
|
}
|
|
|
|
// Why: older profiles can keep a saved default while the visible-provider
|
|
// list drifted. Persist the default back into the list so every surface
|
|
// reads the same settings contract.
|
|
return {
|
|
defaultTaskSource,
|
|
visibleTaskProviders: TASK_PROVIDERS.filter(
|
|
(provider) => provider === defaultTaskSource || visibleTaskProviders.includes(provider)
|
|
)
|
|
}
|
|
}
|
|
|
|
export function normalizeVisibleTaskProviders(value: unknown): TaskProvider[] {
|
|
if (!Array.isArray(value)) {
|
|
return [...TASK_PROVIDERS]
|
|
}
|
|
|
|
const normalized: TaskProvider[] = []
|
|
for (const provider of value) {
|
|
if (!TASK_PROVIDER_SET.has(provider as TaskProvider)) {
|
|
continue
|
|
}
|
|
if (!normalized.includes(provider as TaskProvider)) {
|
|
normalized.push(provider as TaskProvider)
|
|
}
|
|
}
|
|
|
|
// Why: at least one provider must remain visible so the Tasks surface always
|
|
// has a valid source to select after settings hydration or manual edits.
|
|
return normalized.length > 0 ? normalized : [...TASK_PROVIDERS]
|
|
}
|
|
|
|
export type TaskProviderAvailability = {
|
|
gitlabInstalled: boolean
|
|
linearConnected: boolean
|
|
}
|
|
|
|
export function filterAvailableTaskProviders(
|
|
visibleProviders: readonly TaskProvider[],
|
|
availability: TaskProviderAvailability
|
|
): TaskProvider[] {
|
|
const available = visibleProviders.filter((provider) =>
|
|
isTaskProviderAvailable(provider, availability)
|
|
)
|
|
|
|
return available.length > 0 ? available : ['github']
|
|
}
|
|
|
|
export function restoreAvailableDefaultTaskProvider(
|
|
visibleProviders: readonly TaskProvider[],
|
|
availability: TaskProviderAvailability,
|
|
preferredProvider: unknown
|
|
): TaskProvider[] {
|
|
const available = filterAvailableTaskProviders(visibleProviders, availability)
|
|
|
|
// Why: older or drifted settings can hide the saved default while another
|
|
// provider becomes available. Keep that default reachable after hydration.
|
|
if (
|
|
isTaskProvider(preferredProvider) &&
|
|
isTaskProviderAvailable(preferredProvider, availability) &&
|
|
!available.includes(preferredProvider)
|
|
) {
|
|
return TASK_PROVIDERS.filter(
|
|
(provider) => provider === preferredProvider || available.includes(provider)
|
|
)
|
|
}
|
|
|
|
return available
|
|
}
|
|
|
|
function isTaskProviderAvailable(
|
|
provider: TaskProvider,
|
|
availability: TaskProviderAvailability
|
|
): boolean {
|
|
if (provider === 'github') {
|
|
return true
|
|
}
|
|
if (provider === 'gitlab') {
|
|
return availability.gitlabInstalled
|
|
}
|
|
// Why: Jira can be connected from the Tasks surface itself, so hiding it
|
|
// when disconnected would remove the entry point for first-time setup.
|
|
if (provider === 'jira') {
|
|
return true
|
|
}
|
|
return availability.linearConnected
|
|
}
|
|
|
|
export function resolveVisibleTaskProvider(
|
|
preferred: TaskProvider | null | undefined,
|
|
visibleProviders: readonly TaskProvider[]
|
|
): TaskProvider {
|
|
if (preferred && visibleProviders.includes(preferred)) {
|
|
return preferred
|
|
}
|
|
return visibleProviders[0] ?? 'github'
|
|
}
|