mirror of
https://github.com/stablyai/orca.git
synced 2026-10-30 08:37:49 +00:00
refactor(settings): one settings host-scope type and label (#27629)
Settings had two identical provider-scope types, a host-choice type that copied RuntimeClientTarget, a scope-to-environment-id getter that copied runtimeTargetEnvironmentId, and the remote-server/local label written three times. Keep one of each. getProviderAccountScope now reads the default host through defaultScopeHost, the sanctioned reader; output is unchanged (trimmed id, blank means this computer). Co-authored-by: m4air <m4air@Mac.localdomain> Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
m4air
Claude Opus 5.5
parent
c5224f70d8
commit
9d305f3ce4
@@ -41,8 +41,8 @@ import {
|
||||
} from './provider-account-visibility'
|
||||
import { GrokAccountsSection } from './GrokAccountsSection'
|
||||
import { AntigravityAccountsSection } from './AntigravityAccountsSection'
|
||||
import type { RuntimeClientTarget } from '@/runtime/runtime-rpc-client'
|
||||
import { getSettingsHostScopeEnvironmentId } from './settings-host-scope'
|
||||
import type { RuntimeClientTarget } from '@/runtime/runtime-client-target'
|
||||
import { runtimeTargetEnvironmentId } from '@/runtime/runtime-client-target'
|
||||
import { CursorAccountsSection } from './CursorAccountsSection'
|
||||
import { ZcodePlanAccountsSection } from './ZcodePlanAccountsSection'
|
||||
import type {
|
||||
@@ -112,7 +112,7 @@ export function AccountsPane({
|
||||
// below goes to the host chosen in the page, never to the focused one.
|
||||
const accountOwner = hostScope.target
|
||||
const isRemoteAccountScope = accountOwner.kind === 'environment'
|
||||
const scopeEnvironmentId = getSettingsHostScopeEnvironmentId(hostScope)
|
||||
const scopeEnvironmentId = runtimeTargetEnvironmentId(hostScope.target)
|
||||
// Why: a select/remove can outlive a host change; its result
|
||||
// belongs to the owner it was sent to, not the one now shown.
|
||||
const accountOwnerKey = getProviderAccountsOwnerKey(accountOwner)
|
||||
|
||||
@@ -51,7 +51,8 @@ import {
|
||||
import { AgentAvailabilityControl, type AgentCatalogRowProps } from './AgentCatalogRow'
|
||||
import { AgentDefaultSetting } from './AgentDefaultSetting'
|
||||
import { AgentDetectionCatalog } from './AgentDetectionCatalog'
|
||||
import { getSettingsHostScopeEnvironmentId, type SettingsHostScope } from './settings-host-scope'
|
||||
import type { SettingsHostScope } from './settings-host-scope'
|
||||
import { runtimeTargetEnvironmentId } from '@/runtime/runtime-client-target'
|
||||
|
||||
export {
|
||||
buildAgentAvailabilitySettingsUpdate,
|
||||
@@ -158,7 +159,7 @@ export function AgentsPane({
|
||||
wslDistros,
|
||||
wslCapabilitiesLoading
|
||||
}: AgentsPaneProps): React.JSX.Element {
|
||||
const activeServerEnvironmentId = getSettingsHostScopeEnvironmentId(hostScope)
|
||||
const activeServerEnvironmentId = runtimeTargetEnvironmentId(hostScope.target)
|
||||
const agentDetectionTarget = useMemo<AgentDetectionTarget>(
|
||||
() =>
|
||||
activeServerEnvironmentId
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
import { ServerCog } from 'lucide-react'
|
||||
import { Button } from '@/components/ui/button'
|
||||
import { useAppStore } from '@/store'
|
||||
import type { ProviderAccountScope, ProviderRateLimitScope } from './provider-account-scope'
|
||||
import type { ProviderHostScope } from './provider-account-scope'
|
||||
import { translate } from '@/i18n/i18n'
|
||||
|
||||
type ProviderHostScopeControlProps = {
|
||||
labelPrefix: string
|
||||
scope: ProviderAccountScope | ProviderRateLimitScope
|
||||
scope: ProviderHostScope
|
||||
className?: string
|
||||
}
|
||||
|
||||
|
||||
@@ -9,10 +9,10 @@ import { translate } from '@/i18n/i18n'
|
||||
import { getLocalExecutionHostLabel } from '../../../../shared/execution-host'
|
||||
import type { PublicKnownRuntimeEnvironment } from '../../../../shared/runtime-environments'
|
||||
import {
|
||||
getSettingsHostScopeEnvironmentId,
|
||||
type SettingsHostChoice,
|
||||
type SettingsHostScope
|
||||
} from './settings-host-scope'
|
||||
runtimeTargetEnvironmentId,
|
||||
type RuntimeClientTarget
|
||||
} from '@/runtime/runtime-client-target'
|
||||
import type { SettingsHostScope } from './settings-host-scope'
|
||||
|
||||
const LOCAL_VALUE = 'local'
|
||||
const ENVIRONMENT_VALUE_PREFIX = 'environment:'
|
||||
@@ -20,7 +20,7 @@ const ENVIRONMENT_VALUE_PREFIX = 'environment:'
|
||||
type SettingsHostScopePickerProps = {
|
||||
scope: SettingsHostScope
|
||||
environments: readonly PublicKnownRuntimeEnvironment[]
|
||||
onChoose: (choice: SettingsHostChoice) => void
|
||||
onChoose: (choice: RuntimeClientTarget) => void
|
||||
}
|
||||
|
||||
export function shouldShowSettingsHostScopePicker(
|
||||
@@ -35,7 +35,7 @@ export function SettingsHostScopePicker({
|
||||
environments,
|
||||
onChoose
|
||||
}: SettingsHostScopePickerProps): React.JSX.Element {
|
||||
const scopeEnvironmentId = getSettingsHostScopeEnvironmentId(scope)
|
||||
const scopeEnvironmentId = runtimeTargetEnvironmentId(scope.target)
|
||||
const value = scopeEnvironmentId
|
||||
? `${ENVIRONMENT_VALUE_PREFIX}${scopeEnvironmentId}`
|
||||
: LOCAL_VALUE
|
||||
|
||||
@@ -10,11 +10,13 @@ const LOCAL_HOST_LABEL = getExecutionHostLabel('local')
|
||||
|
||||
describe('getProviderAccountScope', () => {
|
||||
it('describes provider accounts as client-owned without an active runtime', () => {
|
||||
expect(getProviderAccountScope({ activeRuntimeEnvironmentId: null })).toEqual({
|
||||
label: LOCAL_HOST_LABEL,
|
||||
description:
|
||||
'Credentials and account checks for this provider are owned by this desktop client. To use a server, change Settings > Remote Orca Servers > Advanced > Default host for new projects.'
|
||||
})
|
||||
for (const activeRuntimeEnvironmentId of [null, ' ']) {
|
||||
expect(getProviderAccountScope({ activeRuntimeEnvironmentId })).toEqual({
|
||||
label: LOCAL_HOST_LABEL,
|
||||
description:
|
||||
'Credentials and account checks for this provider are owned by this desktop client. To use a server, change Settings > Remote Orca Servers > Advanced > Default host for new projects.'
|
||||
})
|
||||
}
|
||||
})
|
||||
|
||||
it('describes provider accounts as remote-server-owned with an active runtime', () => {
|
||||
|
||||
@@ -1,31 +1,38 @@
|
||||
import { translate } from '@/i18n/i18n'
|
||||
import { getLocalExecutionHostLabel } from '../../../../shared/execution-host'
|
||||
import type { GlobalSettings } from '../../../../shared/global-settings-types'
|
||||
import { defaultScopeHost } from '@/lib/default-creation-host'
|
||||
import type { RuntimeClientTarget } from '@/runtime/runtime-client-target'
|
||||
|
||||
export type ProviderAccountScope = {
|
||||
/** Which host a provider card or budget belongs to, and how to change it. */
|
||||
export type ProviderHostScope = {
|
||||
label: string
|
||||
description: string
|
||||
}
|
||||
|
||||
export type ProviderRateLimitScope = {
|
||||
label: string
|
||||
description: string
|
||||
function remoteServerScopeLabel(name: string): string {
|
||||
return translate(
|
||||
'auto.components.settings.providerAccountScope.remoteServer',
|
||||
'Remote server: {{value0}}',
|
||||
{ value0: name }
|
||||
)
|
||||
}
|
||||
|
||||
function providerHostScopeLabel(target: RuntimeClientTarget): string {
|
||||
return target.kind === 'environment'
|
||||
? remoteServerScopeLabel(target.environmentId)
|
||||
: getLocalExecutionHostLabel()
|
||||
}
|
||||
|
||||
/** Accounts-pane scope while a remote server owns the roster (#8186). */
|
||||
export function getRemoteAccountsPaneScope(serverName: string | null): ProviderAccountScope {
|
||||
export function getRemoteAccountsPaneScope(serverName: string | null): ProviderHostScope {
|
||||
const name = serverName?.trim()
|
||||
return {
|
||||
// Why: the saved-server list is still empty on first paint, and the generic
|
||||
// fallback is already a noun phrase — interpolating it would render
|
||||
// "Remote server: the remote server".
|
||||
label: name
|
||||
? translate(
|
||||
'auto.components.settings.providerAccountScope.remoteServer',
|
||||
'Remote server: {{value0}}',
|
||||
{ value0: name }
|
||||
)
|
||||
? remoteServerScopeLabel(name)
|
||||
: translate(
|
||||
'auto.components.settings.AccountsPane.accountScopeRemoteServerUnnamed',
|
||||
'Remote server'
|
||||
@@ -39,55 +46,40 @@ export function getRemoteAccountsPaneScope(serverName: string | null): ProviderA
|
||||
|
||||
export function getProviderAccountScope(
|
||||
settings: Pick<GlobalSettings, 'activeRuntimeEnvironmentId'> | null | undefined
|
||||
): ProviderAccountScope {
|
||||
const runtimeId = settings?.activeRuntimeEnvironmentId?.trim()
|
||||
if (runtimeId) {
|
||||
return {
|
||||
label: translate(
|
||||
'auto.components.settings.providerAccountScope.remoteServer',
|
||||
'Remote server: {{value0}}',
|
||||
{ value0: runtimeId }
|
||||
),
|
||||
description: translate(
|
||||
'auto.components.settings.providerAccountScope.remoteServerCredentials',
|
||||
'Credentials and account checks for this provider are owned by this remote server. To use another host, change Settings > Remote Orca Servers > Advanced > Default host for new projects.'
|
||||
)
|
||||
}
|
||||
}
|
||||
): ProviderHostScope {
|
||||
const target = defaultScopeHost(settings)
|
||||
return {
|
||||
label: getLocalExecutionHostLabel(),
|
||||
description: translate(
|
||||
'auto.components.settings.providerAccountScope.localCredentials',
|
||||
'Credentials and account checks for this provider are owned by this desktop client. To use a server, change Settings > Remote Orca Servers > Advanced > Default host for new projects.'
|
||||
)
|
||||
label: providerHostScopeLabel(target),
|
||||
description:
|
||||
target.kind === 'environment'
|
||||
? translate(
|
||||
'auto.components.settings.providerAccountScope.remoteServerCredentials',
|
||||
'Credentials and account checks for this provider are owned by this remote server. To use another host, change Settings > Remote Orca Servers > Advanced > Default host for new projects.'
|
||||
)
|
||||
: translate(
|
||||
'auto.components.settings.providerAccountScope.localCredentials',
|
||||
'Credentials and account checks for this provider are owned by this desktop client. To use a server, change Settings > Remote Orca Servers > Advanced > Default host for new projects.'
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
export function getProviderRateLimitScope(
|
||||
target: RuntimeClientTarget,
|
||||
providerLabel: string
|
||||
): ProviderRateLimitScope {
|
||||
if (target.kind === 'environment') {
|
||||
const runtimeId = target.environmentId
|
||||
return {
|
||||
label: translate(
|
||||
'auto.components.settings.providerAccountScope.remoteServer',
|
||||
'Remote server: {{value0}}',
|
||||
{ value0: runtimeId }
|
||||
),
|
||||
description: translate(
|
||||
'auto.components.settings.providerAccountScope.remoteServerRateLimit',
|
||||
'{{value0}} API budget is fetched from the CLI on this remote server. Choose another host in the Host menu at the top of Settings to see its budget.',
|
||||
{ value0: providerLabel }
|
||||
)
|
||||
}
|
||||
}
|
||||
): ProviderHostScope {
|
||||
return {
|
||||
label: getLocalExecutionHostLabel(),
|
||||
description: translate(
|
||||
'auto.components.settings.providerAccountScope.localRateLimit',
|
||||
'{{value0}} API budget is fetched from the CLI on this desktop client. Choose a server in the Host menu at the top of Settings to see its budget.',
|
||||
{ value0: providerLabel }
|
||||
)
|
||||
label: providerHostScopeLabel(target),
|
||||
description:
|
||||
target.kind === 'environment'
|
||||
? translate(
|
||||
'auto.components.settings.providerAccountScope.remoteServerRateLimit',
|
||||
'{{value0}} API budget is fetched from the CLI on this remote server. Choose another host in the Host menu at the top of Settings to see its budget.',
|
||||
{ value0: providerLabel }
|
||||
)
|
||||
: translate(
|
||||
'auto.components.settings.providerAccountScope.localRateLimit',
|
||||
'{{value0}} API budget is fetched from the CLI on this desktop client. Choose a server in the Host menu at the top of Settings to see its budget.',
|
||||
{ value0: providerLabel }
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,8 +7,6 @@ export type SettingsHostScope = {
|
||||
available: boolean
|
||||
}
|
||||
|
||||
export type SettingsHostChoice = { kind: 'local' } | { kind: 'environment'; environmentId: string }
|
||||
|
||||
export const LOCAL_SETTINGS_HOST_SCOPE: SettingsHostScope = {
|
||||
target: { kind: 'local' },
|
||||
available: true
|
||||
@@ -16,7 +14,7 @@ export const LOCAL_SETTINGS_HOST_SCOPE: SettingsHostScope = {
|
||||
|
||||
export function resolveSettingsHostScope(args: {
|
||||
/** Null until the user picks a host in the page. */
|
||||
choice: SettingsHostChoice | null
|
||||
choice: RuntimeClientTarget | null
|
||||
/** The "default host for new projects" setting; only the initial default, never a later override. */
|
||||
defaultEnvironmentId: string | null | undefined
|
||||
savedEnvironmentIds: readonly string[]
|
||||
@@ -37,7 +35,3 @@ export function resolveSettingsHostScope(args: {
|
||||
available: !args.catalogHydrated || args.savedEnvironmentIds.includes(environmentId)
|
||||
}
|
||||
}
|
||||
|
||||
export function getSettingsHostScopeEnvironmentId(scope: SettingsHostScope): string | null {
|
||||
return scope.target.kind === 'environment' ? scope.target.environmentId : null
|
||||
}
|
||||
|
||||
@@ -10,7 +10,7 @@ import { useAppStore } from '@/store'
|
||||
import { IntegrationCardDetails, IntegrationCardShell } from './integration-card-shell'
|
||||
import { useIntegrationSubordinateRowClass } from './integration-card-presentation'
|
||||
import { LinearAgentSkillInstallCta } from './linear-agent-skill-install-cta'
|
||||
import { getProviderAccountScope } from './provider-account-scope'
|
||||
import { getProviderAccountScope, type ProviderHostScope } from './provider-account-scope'
|
||||
import { ProviderHostScopeControl } from './ProviderHostScopeControl'
|
||||
import { LINEAR_INTEGRATION_SECTION_ID } from './task-provider-integration-section-ids'
|
||||
import { translate } from '@/i18n/i18n'
|
||||
@@ -236,7 +236,7 @@ export function LinearIntegrationCard(): React.JSX.Element {
|
||||
)
|
||||
}
|
||||
|
||||
function ProviderAccountScopeRow({ scope }: { scope: ReturnType<typeof getProviderAccountScope> }) {
|
||||
function ProviderAccountScopeRow({ scope }: { scope: ProviderHostScope }) {
|
||||
const subordinateRowClass = useIntegrationSubordinateRowClass('text-xs')
|
||||
|
||||
return (
|
||||
|
||||
@@ -31,7 +31,8 @@ import {
|
||||
buildSettingsProjectList,
|
||||
removeSettingsProjectFromAllHosts
|
||||
} from './settings-project-list'
|
||||
import { resolveSettingsHostScope, type SettingsHostChoice } from './settings-host-scope'
|
||||
import { resolveSettingsHostScope } from './settings-host-scope'
|
||||
import type { RuntimeClientTarget } from '@/runtime/runtime-client-target'
|
||||
import { defaultScopeHost } from '@/lib/default-creation-host'
|
||||
|
||||
export function useSettingsStoreModel() {
|
||||
@@ -148,7 +149,7 @@ export function useSettingsStoreModel() {
|
||||
const confirm = useConfirmationDialog()
|
||||
// Why: session-only (deliberately not persisted) unlock — Option-click the Experimental page title reveals the hidden group.
|
||||
const [hiddenExperimentalUnlocked, setHiddenExperimentalUnlocked] = useState(false)
|
||||
const [settingsHostChoice, setSettingsHostChoice] = useState<SettingsHostChoice | null>(null)
|
||||
const [settingsHostChoice, setSettingsHostChoice] = useState<RuntimeClientTarget | null>(null)
|
||||
const defaultScope = defaultScopeHost(settings)
|
||||
const defaultRuntimeEnvironmentId =
|
||||
defaultScope.kind === 'environment' ? defaultScope.environmentId : null
|
||||
|
||||
@@ -10,13 +10,13 @@ import { getRepoHostIdentity } from '../../store/slices/repo-host-identity'
|
||||
import { getSettingsEntryHostSelection, getSettingsProjectHostRepo } from './settings-project-list'
|
||||
import type { SettingsStoreModel } from './use-settings-store-model'
|
||||
import type { SettingsNavigationModel } from './use-settings-navigation-model'
|
||||
import { getSettingsHostScopeEnvironmentId } from './settings-host-scope'
|
||||
import { runtimeTargetEnvironmentId } from '@/runtime/runtime-client-target'
|
||||
|
||||
export function useSettingsTerminalModel(
|
||||
model: SettingsStoreModel,
|
||||
navigation: SettingsNavigationModel
|
||||
) {
|
||||
const scopeEnvironmentId = getSettingsHostScopeEnvironmentId(model.settingsHostScope)
|
||||
const scopeEnvironmentId = runtimeTargetEnvironmentId(model.settingsHostScope.target)
|
||||
const windowsTerminalCapabilityOwnerKey = useWindowsTerminalCapabilityOwnerKey(scopeEnvironmentId)
|
||||
const runtimeTarget = model.settingsHostScope.target
|
||||
const capabilityLoadTarget = useMemo(
|
||||
|
||||
Reference in New Issue
Block a user