@shipfox/client-agent 22.0.2 → 22.0.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.storybook/preview.tsx +2 -2
- package/.turbo/turbo-build.log +1 -1
- package/CHANGELOG.md +19 -0
- package/dist/components/form-errors.d.ts.map +1 -1
- package/dist/components/form-errors.js +3 -0
- package/dist/components/form-errors.js.map +1 -1
- package/dist/components/harness-availability.d.ts +2 -2
- package/dist/components/harness-availability.d.ts.map +1 -1
- package/dist/components/harness-availability.js +4 -3
- package/dist/components/harness-availability.js.map +1 -1
- package/dist/components/harnesses-section.d.ts.map +1 -1
- package/dist/components/harnesses-section.js +4 -2
- package/dist/components/harnesses-section.js.map +1 -1
- package/dist/components/model-provider-usage-modal.d.ts.map +1 -1
- package/dist/components/model-provider-usage-modal.js +23 -5
- package/dist/components/model-provider-usage-modal.js.map +1 -1
- package/dist/components/model-provider-usage-target.d.ts +6 -6
- package/dist/components/model-provider-usage-target.d.ts.map +1 -1
- package/dist/components/model-provider-usage-target.js +3 -1
- package/dist/components/model-provider-usage-target.js.map +1 -1
- package/dist/components/model-providers-section.d.ts.map +1 -1
- package/dist/components/model-providers-section.js +277 -170
- package/dist/components/model-providers-section.js.map +1 -1
- package/dist/components/model-providers-section.stories.d.ts +2 -1
- package/dist/components/model-providers-section.stories.d.ts.map +1 -1
- package/dist/components/model-providers-section.stories.js +45 -1
- package/dist/components/model-providers-section.stories.js.map +1 -1
- package/dist/core/harness-policy.d.ts +5 -2
- package/dist/core/harness-policy.d.ts.map +1 -1
- package/dist/core/harness-policy.js +7 -1
- package/dist/core/harness-policy.js.map +1 -1
- package/dist/core/models.d.ts +3 -0
- package/dist/core/models.d.ts.map +1 -1
- package/dist/core/models.js.map +1 -1
- package/dist/core/provider-policy.d.ts +3 -1
- package/dist/core/provider-policy.d.ts.map +1 -1
- package/dist/core/provider-policy.js +7 -0
- package/dist/core/provider-policy.js.map +1 -1
- package/dist/hooks/api/model-provider-mapper.d.ts.map +1 -1
- package/dist/hooks/api/model-provider-mapper.js +5 -1
- package/dist/hooks/api/model-provider-mapper.js.map +1 -1
- package/dist/pages/model-provider-onboarding-page.d.ts +1 -1
- package/dist/pages/model-provider-onboarding-page.d.ts.map +1 -1
- package/dist/pages/model-provider-onboarding-page.js +58 -44
- package/dist/pages/model-provider-onboarding-page.js.map +1 -1
- package/dist/pages/model-provider-onboarding-page.stories.d.ts.map +1 -1
- package/dist/pages/model-provider-onboarding-page.stories.js +5 -17
- package/dist/pages/model-provider-onboarding-page.stories.js.map +1 -1
- package/dist/tsconfig.test.tsbuildinfo +1 -1
- package/package.json +5 -5
- package/src/components/form-errors.test.ts +9 -0
- package/src/components/form-errors.ts +3 -0
- package/src/components/harness-availability.test.ts +49 -2
- package/src/components/harness-availability.ts +18 -3
- package/src/components/harnesses-section.test.tsx +51 -9
- package/src/components/harnesses-section.tsx +4 -1
- package/src/components/model-provider-usage-modal.test.tsx +23 -0
- package/src/components/model-provider-usage-modal.tsx +32 -6
- package/src/components/model-provider-usage-target.ts +9 -3
- package/src/components/model-providers-section.stories.tsx +33 -1
- package/src/components/model-providers-section.test.tsx +41 -0
- package/src/components/model-providers-section.tsx +264 -155
- package/src/core/harness-policy.ts +21 -1
- package/src/core/models.ts +3 -0
- package/src/core/provider-policy.ts +12 -0
- package/src/hooks/api/model-provider-mapper.test.ts +18 -0
- package/src/hooks/api/model-provider-mapper.ts +6 -1
- package/src/hooks/api/model-providers.test.ts +11 -0
- package/src/pages/model-provider-onboarding-page.stories.tsx +10 -14
- package/src/pages/model-provider-onboarding-page.test.tsx +133 -24
- package/src/pages/model-provider-onboarding-page.tsx +47 -34
- package/test/fixtures/model-providers.ts +22 -1
- package/tsconfig.build.tsbuildinfo +1 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/core/provider-policy.ts"],"sourcesContent":["import type {\n HarnessDescriptor,\n ProviderCatalogEntry,\n ProviderConfig,\n SupportedProvider,\n} from './models.js';\n\nexport function isSupportedProvider(entry: ProviderCatalogEntry): entry is SupportedProvider {\n return entry.kind === 'supported';\n}\n\nexport function supportsProvider(harness: HarnessDescriptor, providerId: string): boolean {\n return harness.supportedProviderIds.includes(providerId);\n}\n\nexport function availableProviders(\n catalog: readonly ProviderCatalogEntry[],\n configs: readonly ProviderConfig[],\n): SupportedProvider[] {\n const configuredIds = new Set(configs.map((config) => config.providerId));\n return catalog.filter(isSupportedProvider).filter((provider) => !configuredIds.has(provider.id));\n}\n\nexport function providerMatchesSearch(entry: SupportedProvider, query: string): boolean {\n const needle = query.trim().toLocaleLowerCase();\n if (!needle) return true;\n const terms = [\n entry.id,\n entry.label,\n ...entry.models.flatMap((model) => [model.id, model.label]),\n ];\n return terms.some((term) => term.toLocaleLowerCase().includes(needle));\n}\n\nexport function customProviderCardMatchesSearch(query: string): boolean {\n const needle = query.trim().toLocaleLowerCase();\n if (!needle) return true;\n return 'custom provider openai anthropic google endpoint https public'.includes(needle);\n}\n\nexport function deriveProviderSlug(displayName: string): string {\n return displayName\n .trim()\n .toLocaleLowerCase()\n .replace(/[^a-z0-9]+/g, '-')\n .replace(/^-+|-+$/g, '');\n}\n\nconst PROVIDER_SLUG_RE = /^[a-z][a-z0-9-]{1,62}$/;\n\nexport function isProviderSlugValid(slug: string): boolean {\n return PROVIDER_SLUG_RE.test(slug);\n}\n"],"names":["isSupportedProvider","entry","kind","supportsProvider","harness","providerId","supportedProviderIds","includes","
|
|
1
|
+
{"version":3,"sources":["../../src/core/provider-policy.ts"],"sourcesContent":["import type {\n HarnessDescriptor,\n ProviderCatalog,\n ProviderCatalogEntry,\n ProviderConfig,\n SupportedProvider,\n} from './models.js';\n\nexport function isSupportedProvider(entry: ProviderCatalogEntry): entry is SupportedProvider {\n return entry.kind === 'supported';\n}\n\nexport function supportsProvider(harness: HarnessDescriptor, providerId: string): boolean {\n return harness.supportedProviderIds.includes(providerId);\n}\n\nexport function isManagedOnlyCatalog(catalog: ProviderCatalog | undefined): boolean {\n return catalog?.workspaceProviders === 'disabled';\n}\n\nexport function managedProviderFromCatalog(\n catalog: ProviderCatalog | undefined,\n): SupportedProvider | undefined {\n if (!isManagedOnlyCatalog(catalog)) return undefined;\n return catalog?.providers.find(isSupportedProvider);\n}\n\nexport function availableProviders(\n catalog: readonly ProviderCatalogEntry[],\n configs: readonly ProviderConfig[],\n): SupportedProvider[] {\n const configuredIds = new Set(configs.map((config) => config.providerId));\n return catalog.filter(isSupportedProvider).filter((provider) => !configuredIds.has(provider.id));\n}\n\nexport function providerMatchesSearch(entry: SupportedProvider, query: string): boolean {\n const needle = query.trim().toLocaleLowerCase();\n if (!needle) return true;\n const terms = [\n entry.id,\n entry.label,\n ...entry.models.flatMap((model) => [model.id, model.label]),\n ];\n return terms.some((term) => term.toLocaleLowerCase().includes(needle));\n}\n\nexport function customProviderCardMatchesSearch(query: string): boolean {\n const needle = query.trim().toLocaleLowerCase();\n if (!needle) return true;\n return 'custom provider openai anthropic google endpoint https public'.includes(needle);\n}\n\nexport function deriveProviderSlug(displayName: string): string {\n return displayName\n .trim()\n .toLocaleLowerCase()\n .replace(/[^a-z0-9]+/g, '-')\n .replace(/^-+|-+$/g, '');\n}\n\nconst PROVIDER_SLUG_RE = /^[a-z][a-z0-9-]{1,62}$/;\n\nexport function isProviderSlugValid(slug: string): boolean {\n return PROVIDER_SLUG_RE.test(slug);\n}\n"],"names":["isSupportedProvider","entry","kind","supportsProvider","harness","providerId","supportedProviderIds","includes","isManagedOnlyCatalog","catalog","workspaceProviders","managedProviderFromCatalog","undefined","providers","find","availableProviders","configs","configuredIds","Set","map","config","filter","provider","has","id","providerMatchesSearch","query","needle","trim","toLocaleLowerCase","terms","label","models","flatMap","model","some","term","customProviderCardMatchesSearch","deriveProviderSlug","displayName","replace","PROVIDER_SLUG_RE","isProviderSlugValid","slug","test"],"mappings":"AAQA,OAAO,SAASA,oBAAoBC,KAA2B;IAC7D,OAAOA,MAAMC,IAAI,KAAK;AACxB;AAEA,OAAO,SAASC,iBAAiBC,OAA0B,EAAEC,UAAkB;IAC7E,OAAOD,QAAQE,oBAAoB,CAACC,QAAQ,CAACF;AAC/C;AAEA,OAAO,SAASG,qBAAqBC,OAAoC;IACvE,OAAOA,SAASC,uBAAuB;AACzC;AAEA,OAAO,SAASC,2BACdF,OAAoC;IAEpC,IAAI,CAACD,qBAAqBC,UAAU,OAAOG;IAC3C,OAAOH,SAASI,UAAUC,KAAKd;AACjC;AAEA,OAAO,SAASe,mBACdN,OAAwC,EACxCO,OAAkC;IAElC,MAAMC,gBAAgB,IAAIC,IAAIF,QAAQG,GAAG,CAAC,CAACC,SAAWA,OAAOf,UAAU;IACvE,OAAOI,QAAQY,MAAM,CAACrB,qBAAqBqB,MAAM,CAAC,CAACC,WAAa,CAACL,cAAcM,GAAG,CAACD,SAASE,EAAE;AAChG;AAEA,OAAO,SAASC,sBAAsBxB,KAAwB,EAAEyB,KAAa;IAC3E,MAAMC,SAASD,MAAME,IAAI,GAAGC,iBAAiB;IAC7C,IAAI,CAACF,QAAQ,OAAO;IACpB,MAAMG,QAAQ;QACZ7B,MAAMuB,EAAE;QACRvB,MAAM8B,KAAK;WACR9B,MAAM+B,MAAM,CAACC,OAAO,CAAC,CAACC,QAAU;gBAACA,MAAMV,EAAE;gBAAEU,MAAMH,KAAK;aAAC;KAC3D;IACD,OAAOD,MAAMK,IAAI,CAAC,CAACC,OAASA,KAAKP,iBAAiB,GAAGtB,QAAQ,CAACoB;AAChE;AAEA,OAAO,SAASU,gCAAgCX,KAAa;IAC3D,MAAMC,SAASD,MAAME,IAAI,GAAGC,iBAAiB;IAC7C,IAAI,CAACF,QAAQ,OAAO;IACpB,OAAO,gEAAgEpB,QAAQ,CAACoB;AAClF;AAEA,OAAO,SAASW,mBAAmBC,WAAmB;IACpD,OAAOA,YACJX,IAAI,GACJC,iBAAiB,GACjBW,OAAO,CAAC,eAAe,KACvBA,OAAO,CAAC,YAAY;AACzB;AAEA,MAAMC,mBAAmB;AAEzB,OAAO,SAASC,oBAAoBC,IAAY;IAC9C,OAAOF,iBAAiBG,IAAI,CAACD;AAC/B"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"model-provider-mapper.d.ts","sourceRoot":"","sources":["../../../src/hooks/api/model-provider-mapper.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,4BAA4B,EAC5B,mCAAmC,EACnC,4BAA4B,EAC5B,+BAA+B,EAC/B,sBAAsB,EACtB,8BAA8B,EAC9B,4BAA4B,EAC5B,kCAAkC,EACnC,MAAM,wBAAwB,CAAC;AAChC,OAAO,KAAK,EAEV,qBAAqB,EACrB,oBAAoB,EACpB,uBAAuB,EACvB,6BAA6B,EAC7B,eAAe,EACf,oBAAoB,EACpB,cAAc,EACd,qBAAqB,EACtB,MAAM,iBAAiB,CAAC;AAEzB,wBAAgB,iBAAiB,CAAC,QAAQ,EAAE,+BAA+B,GAAG,eAAe,
|
|
1
|
+
{"version":3,"file":"model-provider-mapper.d.ts","sourceRoot":"","sources":["../../../src/hooks/api/model-provider-mapper.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,4BAA4B,EAC5B,mCAAmC,EACnC,4BAA4B,EAC5B,+BAA+B,EAC/B,sBAAsB,EACtB,8BAA8B,EAC9B,4BAA4B,EAC5B,kCAAkC,EACnC,MAAM,wBAAwB,CAAC;AAChC,OAAO,KAAK,EAEV,qBAAqB,EACrB,oBAAoB,EACpB,uBAAuB,EACvB,6BAA6B,EAC7B,eAAe,EACf,oBAAoB,EACpB,cAAc,EACd,qBAAqB,EACtB,MAAM,iBAAiB,CAAC;AAEzB,wBAAgB,iBAAiB,CAAC,QAAQ,EAAE,+BAA+B,GAAG,eAAe,CAK5F;AAED,wBAAgB,sBAAsB,CAAC,KAAK,EAAE,4BAA4B,GAAG,oBAAoB,CAqBhG;AAED,wBAAgB,uBAAuB,CACrC,QAAQ,EAAE,mCAAmC,GAC5C,qBAAqB,CAMvB;AAED,wBAAgB,+BAA+B,CAC7C,QAAQ,EAAE,kCAAkC,GAC3C,6BAA6B,CAE/B;AAED,wBAAgB,yBAAyB,CACvC,QAAQ,EAAE,4BAA4B,GACrC,uBAAuB,CAEzB;AAED,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,8BAA8B,GAAG,cAAc,CAIvF;AAED,wBAAgB,uBAAuB,CAAC,MAAM,EAAE,sBAAsB,GAAG,qBAAqB,CAQ7F;AAED,wBAAgB,sBAAsB,CAAC,MAAM,EAAE,4BAA4B,GAAG,oBAAoB,CAcjG"}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
export function toProviderCatalog(response) {
|
|
2
2
|
return {
|
|
3
|
-
providers: response.providers.map(toProviderCatalogEntry)
|
|
3
|
+
providers: response.providers.map(toProviderCatalogEntry),
|
|
4
|
+
workspaceProviders: response.workspace_providers ?? 'enabled'
|
|
4
5
|
};
|
|
5
6
|
}
|
|
6
7
|
export function toProviderCatalogEntry(entry) {
|
|
@@ -76,6 +77,9 @@ function toAgentModel(model) {
|
|
|
76
77
|
return {
|
|
77
78
|
id: model.id,
|
|
78
79
|
label: model.label,
|
|
80
|
+
...model.api === undefined ? {} : {
|
|
81
|
+
api: model.api
|
|
82
|
+
},
|
|
79
83
|
...model.context_window === undefined ? {} : {
|
|
80
84
|
contextWindow: model.context_window
|
|
81
85
|
},
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/hooks/api/model-provider-mapper.ts"],"sourcesContent":["import type {\n CustomModelProviderConfigDto,\n ListModelProviderConfigsResponseDto,\n ModelProviderCatalogEntryDto,\n ModelProviderCatalogResponseDto,\n ModelProviderConfigDto,\n ModelProviderConfigResponseDto,\n SetDefaultHarnessResponseDto,\n SetDefaultModelProviderResponseDto,\n} from '@shipfox/api-agent-dto';\nimport type {\n AgentModel,\n BuiltinProviderConfig,\n CustomProviderConfig,\n DefaultHarnessSelection,\n DefaultModelProviderSelection,\n ProviderCatalog,\n ProviderCatalogEntry,\n ProviderConfig,\n ProviderConfiguration,\n} from '#core/models.js';\n\nexport function toProviderCatalog(response: ModelProviderCatalogResponseDto): ProviderCatalog {\n return {providers: response.providers.map(toProviderCatalogEntry)};\n}\n\nexport function toProviderCatalogEntry(entry: ModelProviderCatalogEntryDto): ProviderCatalogEntry {\n if (entry.support_status === 'unsupported') {\n return {\n kind: 'unsupported',\n id: entry.id,\n label: entry.label,\n unsupportedReason: entry.unsupported_reason ?? 'Unsupported provider',\n };\n }\n return {\n kind: 'supported',\n id: entry.id,\n label: entry.label,\n defaultModel: entry.default_model,\n credentialFields: entry.credential_fields.map((field) => ({\n key: field.key,\n label: field.label,\n secret: field.secret,\n })),\n models: entry.models.map(toAgentModel),\n };\n}\n\nexport function toProviderConfiguration(\n response: ListModelProviderConfigsResponseDto,\n): ProviderConfiguration {\n return {\n configs: response.configs.map(toProviderConfig),\n defaultHarnessId: response.default_harness_id,\n defaultProviderId: response.default_provider_id,\n };\n}\n\nexport function toDefaultModelProviderSelection(\n response: SetDefaultModelProviderResponseDto,\n): DefaultModelProviderSelection {\n return {defaultProviderId: response.default_provider_id};\n}\n\nexport function toDefaultHarnessSelection(\n response: SetDefaultHarnessResponseDto,\n): DefaultHarnessSelection {\n return {defaultHarnessId: response.default_harness_id};\n}\n\nexport function toProviderConfig(config: ModelProviderConfigResponseDto): ProviderConfig {\n return config.kind === 'builtin'\n ? toBuiltinProviderConfig(config)\n : toCustomProviderConfig(config);\n}\n\nexport function toBuiltinProviderConfig(config: ModelProviderConfigDto): BuiltinProviderConfig {\n return {\n kind: 'builtin',\n providerId: config.provider_id,\n defaultModel: config.default_model,\n createdAt: config.created_at,\n updatedAt: config.updated_at,\n };\n}\n\nexport function toCustomProviderConfig(config: CustomModelProviderConfigDto): CustomProviderConfig {\n return {\n kind: 'custom',\n providerId: config.provider_id,\n displayName: config.display_name,\n api: config.api,\n baseUrl: config.base_url,\n headers: config.headers.map((header) => ({name: header.name, value: header.value})),\n secretHeaderNames: config.secret_header_names,\n models: config.models.map(toAgentModel),\n defaultModel: config.default_model,\n createdAt: config.created_at,\n updatedAt: config.updated_at,\n };\n}\n\nfunction toAgentModel(model: {\n id: string;\n label: string;\n context_window?: number | undefined;\n max_output_tokens?: number | undefined;\n input_image?: boolean | undefined;\n reasoning?: boolean | undefined;\n}): AgentModel {\n return {\n id: model.id,\n label: model.label,\n ...(model.context_window === undefined ? {} : {contextWindow: model.context_window}),\n ...(model.max_output_tokens === undefined ? {} : {maxOutputTokens: model.max_output_tokens}),\n ...(model.input_image === undefined ? {} : {inputImage: model.input_image}),\n ...(model.reasoning === undefined ? {} : {reasoning: model.reasoning}),\n };\n}\n"],"names":["toProviderCatalog","response","providers","map","toProviderCatalogEntry","entry","support_status","kind","id","label","unsupportedReason","unsupported_reason","defaultModel","default_model","credentialFields","credential_fields","field","key","secret","models","toAgentModel","toProviderConfiguration","configs","toProviderConfig","defaultHarnessId","default_harness_id","defaultProviderId","default_provider_id","toDefaultModelProviderSelection","toDefaultHarnessSelection","config","toBuiltinProviderConfig","toCustomProviderConfig","providerId","provider_id","createdAt","created_at","updatedAt","updated_at","displayName","display_name","api","baseUrl","base_url","headers","header","name","value","secretHeaderNames","secret_header_names","model","
|
|
1
|
+
{"version":3,"sources":["../../../src/hooks/api/model-provider-mapper.ts"],"sourcesContent":["import type {\n CustomModelProviderConfigDto,\n ListModelProviderConfigsResponseDto,\n ModelProviderCatalogEntryDto,\n ModelProviderCatalogResponseDto,\n ModelProviderConfigDto,\n ModelProviderConfigResponseDto,\n SetDefaultHarnessResponseDto,\n SetDefaultModelProviderResponseDto,\n} from '@shipfox/api-agent-dto';\nimport type {\n AgentModel,\n BuiltinProviderConfig,\n CustomProviderConfig,\n DefaultHarnessSelection,\n DefaultModelProviderSelection,\n ProviderCatalog,\n ProviderCatalogEntry,\n ProviderConfig,\n ProviderConfiguration,\n} from '#core/models.js';\n\nexport function toProviderCatalog(response: ModelProviderCatalogResponseDto): ProviderCatalog {\n return {\n providers: response.providers.map(toProviderCatalogEntry),\n workspaceProviders: response.workspace_providers ?? 'enabled',\n };\n}\n\nexport function toProviderCatalogEntry(entry: ModelProviderCatalogEntryDto): ProviderCatalogEntry {\n if (entry.support_status === 'unsupported') {\n return {\n kind: 'unsupported',\n id: entry.id,\n label: entry.label,\n unsupportedReason: entry.unsupported_reason ?? 'Unsupported provider',\n };\n }\n return {\n kind: 'supported',\n id: entry.id,\n label: entry.label,\n defaultModel: entry.default_model,\n credentialFields: entry.credential_fields.map((field) => ({\n key: field.key,\n label: field.label,\n secret: field.secret,\n })),\n models: entry.models.map(toAgentModel),\n };\n}\n\nexport function toProviderConfiguration(\n response: ListModelProviderConfigsResponseDto,\n): ProviderConfiguration {\n return {\n configs: response.configs.map(toProviderConfig),\n defaultHarnessId: response.default_harness_id,\n defaultProviderId: response.default_provider_id,\n };\n}\n\nexport function toDefaultModelProviderSelection(\n response: SetDefaultModelProviderResponseDto,\n): DefaultModelProviderSelection {\n return {defaultProviderId: response.default_provider_id};\n}\n\nexport function toDefaultHarnessSelection(\n response: SetDefaultHarnessResponseDto,\n): DefaultHarnessSelection {\n return {defaultHarnessId: response.default_harness_id};\n}\n\nexport function toProviderConfig(config: ModelProviderConfigResponseDto): ProviderConfig {\n return config.kind === 'builtin'\n ? toBuiltinProviderConfig(config)\n : toCustomProviderConfig(config);\n}\n\nexport function toBuiltinProviderConfig(config: ModelProviderConfigDto): BuiltinProviderConfig {\n return {\n kind: 'builtin',\n providerId: config.provider_id,\n defaultModel: config.default_model,\n createdAt: config.created_at,\n updatedAt: config.updated_at,\n };\n}\n\nexport function toCustomProviderConfig(config: CustomModelProviderConfigDto): CustomProviderConfig {\n return {\n kind: 'custom',\n providerId: config.provider_id,\n displayName: config.display_name,\n api: config.api,\n baseUrl: config.base_url,\n headers: config.headers.map((header) => ({name: header.name, value: header.value})),\n secretHeaderNames: config.secret_header_names,\n models: config.models.map(toAgentModel),\n defaultModel: config.default_model,\n createdAt: config.created_at,\n updatedAt: config.updated_at,\n };\n}\n\nfunction toAgentModel(model: {\n id: string;\n label: string;\n api?: AgentModel['api'];\n context_window?: number | undefined;\n max_output_tokens?: number | undefined;\n input_image?: boolean | undefined;\n reasoning?: boolean | undefined;\n}): AgentModel {\n return {\n id: model.id,\n label: model.label,\n ...(model.api === undefined ? {} : {api: model.api}),\n ...(model.context_window === undefined ? {} : {contextWindow: model.context_window}),\n ...(model.max_output_tokens === undefined ? {} : {maxOutputTokens: model.max_output_tokens}),\n ...(model.input_image === undefined ? {} : {inputImage: model.input_image}),\n ...(model.reasoning === undefined ? {} : {reasoning: model.reasoning}),\n };\n}\n"],"names":["toProviderCatalog","response","providers","map","toProviderCatalogEntry","workspaceProviders","workspace_providers","entry","support_status","kind","id","label","unsupportedReason","unsupported_reason","defaultModel","default_model","credentialFields","credential_fields","field","key","secret","models","toAgentModel","toProviderConfiguration","configs","toProviderConfig","defaultHarnessId","default_harness_id","defaultProviderId","default_provider_id","toDefaultModelProviderSelection","toDefaultHarnessSelection","config","toBuiltinProviderConfig","toCustomProviderConfig","providerId","provider_id","createdAt","created_at","updatedAt","updated_at","displayName","display_name","api","baseUrl","base_url","headers","header","name","value","secretHeaderNames","secret_header_names","model","undefined","context_window","contextWindow","max_output_tokens","maxOutputTokens","input_image","inputImage","reasoning"],"mappings":"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"}
|
|
@@ -2,5 +2,5 @@ export declare function ModelProviderOnboardingPage({ workspaceId, onSkip, onCon
|
|
|
2
2
|
workspaceId: string;
|
|
3
3
|
onSkip: () => void;
|
|
4
4
|
onConfigured: () => void;
|
|
5
|
-
}): import("react").JSX.Element;
|
|
5
|
+
}): import("react").JSX.Element | null;
|
|
6
6
|
//# sourceMappingURL=model-provider-onboarding-page.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"model-provider-onboarding-page.d.ts","sourceRoot":"","sources":["../../src/pages/model-provider-onboarding-page.tsx"],"names":[],"mappings":"AAuBA,wBAAgB,2BAA2B,CAAC,EAC1C,WAAW,EACX,MAAM,EACN,YAAY,GACb,EAAE;IACD,WAAW,EAAE,MAAM,CAAC;IACpB,MAAM,EAAE,MAAM,IAAI,CAAC;IACnB,YAAY,EAAE,MAAM,IAAI,CAAC;CAC1B
|
|
1
|
+
{"version":3,"file":"model-provider-onboarding-page.d.ts","sourceRoot":"","sources":["../../src/pages/model-provider-onboarding-page.tsx"],"names":[],"mappings":"AAuBA,wBAAgB,2BAA2B,CAAC,EAC1C,WAAW,EACX,MAAM,EACN,YAAY,GACb,EAAE;IACD,WAAW,EAAE,MAAM,CAAC;IACpB,MAAM,EAAE,MAAM,IAAI,CAAC;IACnB,YAAY,EAAE,MAAM,IAAI,CAAC;CAC1B,sCA0MA"}
|
|
@@ -7,14 +7,14 @@ import { Modal, ModalContent, ModalHeader, ModalTitle } from '@shipfox/react-ui/
|
|
|
7
7
|
import { Panel, PanelBody, PanelCell, PanelCellAction, PanelGrid } from '@shipfox/react-ui/panel';
|
|
8
8
|
import { toast } from '@shipfox/react-ui/toast';
|
|
9
9
|
import { Header, Text } from '@shipfox/react-ui/typography';
|
|
10
|
-
import { useEffect, useMemo, useReducer } from 'react';
|
|
10
|
+
import { useEffect, useMemo, useReducer, useRef } from 'react';
|
|
11
11
|
import { AvailableProvidersGrid } from '#components/available-providers-grid.js';
|
|
12
12
|
import { modelProviderConfigErrorToFormError } from '#components/form-errors.js';
|
|
13
13
|
import { ModelProviderGridSkeleton } from '#components/model-provider-grid-skeleton.js';
|
|
14
14
|
import { ModelProviderTestAndSaveForm } from '#components/test-and-save-form.js';
|
|
15
15
|
import { DEFAULT_HARNESS, harnessSupportsProvider, listHarnesses } from '#core/harness-policy.js';
|
|
16
16
|
import { initialOnboardingState, onboardingReducer } from '#core/onboarding-reducer.js';
|
|
17
|
-
import { isSupportedProvider } from '#core/provider-policy.js';
|
|
17
|
+
import { isManagedOnlyCatalog, isSupportedProvider } from '#core/provider-policy.js';
|
|
18
18
|
import { useModelProviderCatalogQuery, useSetDefaultHarnessMutation } from '#hooks/api/model-providers.js';
|
|
19
19
|
import { dismissModelProviderOnboarding } from '#state/model-provider-onboarding.js';
|
|
20
20
|
export function ModelProviderOnboardingPage({ workspaceId, onSkip, onConfigured }) {
|
|
@@ -22,6 +22,11 @@ export function ModelProviderOnboardingPage({ workspaceId, onSkip, onConfigured
|
|
|
22
22
|
const setDefaultHarness = useSetDefaultHarnessMutation();
|
|
23
23
|
const [onboarding, dispatch] = useReducer(onboardingReducer, initialOnboardingState);
|
|
24
24
|
const supportedProviders = catalogQuery.data?.providers.filter(isSupportedProvider) ?? [];
|
|
25
|
+
const catalogLoaded = catalogQuery.data !== undefined;
|
|
26
|
+
const catalogLoading = catalogQuery.isPending;
|
|
27
|
+
const catalogLoadError = catalogQuery.isError && catalogQuery.data === undefined;
|
|
28
|
+
const managedOnly = isManagedOnlyCatalog(catalogQuery.data);
|
|
29
|
+
const managedOnlyForwarded = useRef(false);
|
|
25
30
|
const filteredProviders = useMemo(()=>{
|
|
26
31
|
if (onboarding.step === 'choose-harness') return [];
|
|
27
32
|
return supportedProviders.filter((provider)=>harnessSupportsProvider(onboarding.harnessId, provider.id));
|
|
@@ -30,10 +35,22 @@ export function ModelProviderOnboardingPage({ workspaceId, onSkip, onConfigured
|
|
|
30
35
|
supportedProviders
|
|
31
36
|
]);
|
|
32
37
|
useEffect(()=>{
|
|
38
|
+
if (!managedOnly || managedOnlyForwarded.current) return;
|
|
39
|
+
managedOnlyForwarded.current = true;
|
|
40
|
+
onConfigured();
|
|
41
|
+
}, [
|
|
42
|
+
managedOnly,
|
|
43
|
+
onConfigured
|
|
44
|
+
]);
|
|
45
|
+
useEffect(()=>{
|
|
46
|
+
if (managedOnly || !catalogLoaded) return;
|
|
33
47
|
document.getElementById(onboarding.step === 'choose-harness' ? 'model-provider-harness-step' : 'model-provider-provider-step')?.focus();
|
|
34
48
|
}, [
|
|
49
|
+
catalogLoaded,
|
|
50
|
+
managedOnly,
|
|
35
51
|
onboarding.step
|
|
36
52
|
]);
|
|
53
|
+
if (managedOnly) return null;
|
|
37
54
|
function handleSkip() {
|
|
38
55
|
try {
|
|
39
56
|
dismissModelProviderOnboarding(workspaceId);
|
|
@@ -108,38 +125,46 @@ export function ModelProviderOnboardingPage({ workspaceId, onSkip, onConfigured
|
|
|
108
125
|
})
|
|
109
126
|
]
|
|
110
127
|
}),
|
|
111
|
-
/*#__PURE__*/
|
|
128
|
+
/*#__PURE__*/ _jsxs("section", {
|
|
112
129
|
"aria-labelledby": headingId,
|
|
113
130
|
className: "flex flex-col gap-group",
|
|
114
|
-
children:
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
type: 'back'
|
|
127
|
-
}),
|
|
128
|
-
children: "Back"
|
|
131
|
+
children: [
|
|
132
|
+
catalogLoading ? /*#__PURE__*/ _jsx(ModelProviderGridSkeleton, {
|
|
133
|
+
label: "Loading model providers"
|
|
134
|
+
}) : null,
|
|
135
|
+
catalogLoadError ? /*#__PURE__*/ _jsx(QueryLoadError, {
|
|
136
|
+
query: catalogQuery,
|
|
137
|
+
subject: "model provider catalog"
|
|
138
|
+
}) : null,
|
|
139
|
+
!catalogLoading && !catalogLoadError ? onboarding.step === 'choose-harness' ? /*#__PURE__*/ _jsx(HarnessPicker, {
|
|
140
|
+
onSelect: (harnessId)=>dispatch({
|
|
141
|
+
type: 'harness-selected',
|
|
142
|
+
harnessId
|
|
129
143
|
})
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
144
|
+
}) : /*#__PURE__*/ _jsxs(_Fragment, {
|
|
145
|
+
children: [
|
|
146
|
+
/*#__PURE__*/ _jsx("div", {
|
|
147
|
+
children: /*#__PURE__*/ _jsx(Button, {
|
|
148
|
+
type: "button",
|
|
149
|
+
variant: "transparent",
|
|
150
|
+
onClick: ()=>dispatch({
|
|
151
|
+
type: 'back'
|
|
152
|
+
}),
|
|
153
|
+
children: "Back"
|
|
154
|
+
})
|
|
155
|
+
}),
|
|
156
|
+
/*#__PURE__*/ _jsx(ModelProviderPicker, {
|
|
157
|
+
supportedProviders: filteredProviders,
|
|
158
|
+
onSelect: (entry)=>{
|
|
159
|
+
dispatch({
|
|
160
|
+
type: 'provider-selected',
|
|
161
|
+
provider: entry
|
|
162
|
+
});
|
|
163
|
+
}
|
|
164
|
+
}, onboarding.harnessId)
|
|
165
|
+
]
|
|
166
|
+
}) : null
|
|
167
|
+
]
|
|
143
168
|
}),
|
|
144
169
|
/*#__PURE__*/ _jsx(Modal, {
|
|
145
170
|
open: onboarding.step === 'configure-provider' || onboarding.step === 'saving-default-harness',
|
|
@@ -255,19 +280,8 @@ function HarnessCard({ harness, onChoose }) {
|
|
|
255
280
|
})
|
|
256
281
|
});
|
|
257
282
|
}
|
|
258
|
-
function ModelProviderPicker({
|
|
259
|
-
if (
|
|
260
|
-
return /*#__PURE__*/ _jsx(ModelProviderGridSkeleton, {
|
|
261
|
-
label: "Loading model providers"
|
|
262
|
-
});
|
|
263
|
-
}
|
|
264
|
-
if (catalogQuery.isError && catalogQuery.data === undefined) {
|
|
265
|
-
return /*#__PURE__*/ _jsx(QueryLoadError, {
|
|
266
|
-
query: catalogQuery,
|
|
267
|
-
subject: "model provider catalog"
|
|
268
|
-
});
|
|
269
|
-
}
|
|
270
|
-
if (catalogQuery.data !== undefined && supportedProviders.length === 0) {
|
|
283
|
+
function ModelProviderPicker({ supportedProviders, onSelect }) {
|
|
284
|
+
if (supportedProviders.length === 0) {
|
|
271
285
|
return /*#__PURE__*/ _jsx(EmptyState, {
|
|
272
286
|
icon: "componentLine",
|
|
273
287
|
title: "No providers available to configure",
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/pages/model-provider-onboarding-page.tsx"],"sourcesContent":["import {QueryLoadError} from '@shipfox/client-ui';\nimport {Button} from '@shipfox/react-ui/button';\nimport {Callout} from '@shipfox/react-ui/callout';\nimport {EmptyState} from '@shipfox/react-ui/empty-state';\nimport {Modal, ModalContent, ModalHeader, ModalTitle} from '@shipfox/react-ui/modal';\nimport {Panel, PanelBody, PanelCell, PanelCellAction, PanelGrid} from '@shipfox/react-ui/panel';\nimport {toast} from '@shipfox/react-ui/toast';\nimport {Header, Text} from '@shipfox/react-ui/typography';\nimport {useEffect, useMemo, useReducer} from 'react';\nimport {AvailableProvidersGrid} from '#components/available-providers-grid.js';\nimport {modelProviderConfigErrorToFormError} from '#components/form-errors.js';\nimport {ModelProviderGridSkeleton} from '#components/model-provider-grid-skeleton.js';\nimport {ModelProviderTestAndSaveForm} from '#components/test-and-save-form.js';\nimport {DEFAULT_HARNESS, harnessSupportsProvider, listHarnesses} from '#core/harness-policy.js';\nimport type {HarnessDescriptor, HarnessId, SupportedProvider} from '#core/models.js';\nimport {initialOnboardingState, onboardingReducer} from '#core/onboarding-reducer.js';\nimport {isSupportedProvider} from '#core/provider-policy.js';\nimport {\n useModelProviderCatalogQuery,\n useSetDefaultHarnessMutation,\n} from '#hooks/api/model-providers.js';\nimport {dismissModelProviderOnboarding} from '#state/model-provider-onboarding.js';\n\nexport function ModelProviderOnboardingPage({\n workspaceId,\n onSkip,\n onConfigured,\n}: {\n workspaceId: string;\n onSkip: () => void;\n onConfigured: () => void;\n}) {\n const catalogQuery = useModelProviderCatalogQuery();\n const setDefaultHarness = useSetDefaultHarnessMutation();\n const [onboarding, dispatch] = useReducer(onboardingReducer, initialOnboardingState);\n const supportedProviders = catalogQuery.data?.providers.filter(isSupportedProvider) ?? [];\n const filteredProviders = useMemo(() => {\n if (onboarding.step === 'choose-harness') return [];\n return supportedProviders.filter((provider) =>\n harnessSupportsProvider(onboarding.harnessId, provider.id),\n );\n }, [onboarding, supportedProviders]);\n\n useEffect(() => {\n document\n .getElementById(\n onboarding.step === 'choose-harness'\n ? 'model-provider-harness-step'\n : 'model-provider-provider-step',\n )\n ?.focus();\n }, [onboarding.step]);\n\n function handleSkip() {\n try {\n dismissModelProviderOnboarding(workspaceId);\n } catch {\n // Skip is best-effort persistence; access to the product must not depend on storage.\n }\n onSkip();\n }\n\n async function handleProviderSaved() {\n if (onboarding.step !== 'configure-provider' && onboarding.step !== 'saving-default-harness')\n return;\n\n const provider = onboarding.provider;\n if (onboarding.step === 'configure-provider') dispatch({type: 'provider-saved'});\n if (onboarding.harnessId === DEFAULT_HARNESS) {\n toast.success(`${provider.label} saved`);\n dispatch({type: 'default-harness-saved'});\n onConfigured();\n return;\n }\n\n try {\n await setDefaultHarness.mutateAsync({\n workspaceId,\n harnessId: onboarding.harnessId,\n });\n toast.success(`${provider.label} saved`);\n dispatch({type: 'default-harness-saved'});\n onConfigured();\n } catch (error) {\n const mapped = modelProviderConfigErrorToFormError(error);\n dispatch({\n type: 'default-harness-failed',\n message: mapped.message || 'Could not save default harness. Try again.',\n });\n }\n }\n\n const selectedHarnessDescriptor =\n onboarding.step === 'choose-harness'\n ? null\n : listHarnesses().find((harness) => harness.id === onboarding.harnessId);\n const headingId =\n onboarding.step === 'choose-harness'\n ? 'model-provider-harness-step'\n : 'model-provider-provider-step';\n\n return (\n <div className=\"flex w-full flex-col gap-section\">\n <header className=\"flex flex-col gap-cluster\">\n <div className=\"flex items-start justify-between gap-group max-[520px]:flex-col max-[520px]:gap-inline\">\n <Header id={headingId} variant=\"h1\" tabIndex={-1} className=\"outline-none\">\n {selectedHarnessDescriptor\n ? `Configure ${selectedHarnessDescriptor.label}`\n : 'Choose agent harness'}\n </Header>\n <Button type=\"button\" variant=\"secondary\" onClick={handleSkip} className=\"shrink-0\">\n Skip for now\n </Button>\n </div>\n <Text size=\"md\" className=\"text-foreground-neutral-muted\">\n {selectedHarnessDescriptor\n ? `${selectedHarnessDescriptor.label} needs a compatible model provider. Add your own API key, or go back to choose a different harness.`\n : 'A harness runs agent steps. Choose the engine you want first, then connect a compatible model provider.'}\n </Text>\n </header>\n\n <section aria-labelledby={headingId} className=\"flex flex-col gap-group\">\n {onboarding.step === 'choose-harness' ? (\n <HarnessPicker\n onSelect={(harnessId) => dispatch({type: 'harness-selected', harnessId})}\n />\n ) : (\n <>\n <div>\n <Button type=\"button\" variant=\"transparent\" onClick={() => dispatch({type: 'back'})}>\n Back\n </Button>\n </div>\n <ModelProviderPicker\n key={onboarding.harnessId}\n catalogQuery={catalogQuery}\n supportedProviders={filteredProviders}\n onSelect={(entry) => {\n dispatch({type: 'provider-selected', provider: entry});\n }}\n />\n </>\n )}\n </section>\n\n <Modal\n open={\n onboarding.step === 'configure-provider' || onboarding.step === 'saving-default-harness'\n }\n onOpenChange={(open) => {\n if (!open && onboarding.step === 'configure-provider') dispatch({type: 'back'});\n }}\n >\n <ModalContent aria-describedby={undefined}>\n <ModalTitle className=\"sr-only\">\n {onboarding.step === 'configure-provider' ||\n onboarding.step === 'saving-default-harness'\n ? `Configure ${onboarding.provider.label}`\n : ''}\n </ModalTitle>\n <ModalHeader>\n <Text\n size=\"lg\"\n aria-hidden=\"true\"\n className=\"overflow-ellipsis overflow-hidden whitespace-nowrap\"\n >\n {onboarding.step === 'configure-provider' ||\n onboarding.step === 'saving-default-harness'\n ? `Configure ${onboarding.provider.label}`\n : ''}\n </Text>\n </ModalHeader>\n {onboarding.step === 'configure-provider' ||\n onboarding.step === 'saving-default-harness' ? (\n <div className=\"flex min-h-0 flex-1 flex-col gap-inline\">\n {onboarding.step === 'saving-default-harness' ? (\n <div role=\"status\" className=\"px-row\">\n <Text size=\"sm\" className=\"text-foreground-neutral-muted\">\n Saving harness default...\n </Text>\n </div>\n ) : null}\n {onboarding.step === 'saving-default-harness' && onboarding.error ? (\n <div className=\"px-row\">\n <Callout role=\"alert\" type=\"error\">\n <div className=\"flex flex-col gap-inline\">\n <Text size=\"sm\" bold>\n Could not save default harness\n </Text>\n <Text size=\"sm\">{onboarding.error}</Text>\n </div>\n </Callout>\n </div>\n ) : null}\n <div className=\"flex min-h-0 flex-1 flex-col\">\n <ModelProviderTestAndSaveForm\n workspaceId={workspaceId}\n entry={onboarding.provider}\n setAsDefaultOnSave\n onSaved={() => {\n void handleProviderSaved();\n }}\n />\n </div>\n </div>\n ) : null}\n </ModalContent>\n </Modal>\n </div>\n );\n}\n\nfunction HarnessPicker({onSelect}: {onSelect: (harness: HarnessId) => void}) {\n return (\n <Panel>\n <PanelBody>\n <PanelGrid aria-label=\"Agent harnesses\">\n {listHarnesses().map((harness) => (\n <HarnessCard key={harness.id} harness={harness} onChoose={() => onSelect(harness.id)} />\n ))}\n </PanelGrid>\n </PanelBody>\n </Panel>\n );\n}\n\nfunction HarnessCard({harness, onChoose}: {harness: HarnessDescriptor; onChoose: () => void}) {\n return (\n <PanelCell>\n <PanelCellAction action=\"Choose\" aria-label={`Choose ${harness.label}`} onClick={onChoose}>\n <span className=\"flex min-w-0 flex-col gap-tight\">\n <Text as=\"span\" size=\"md\" bold className=\"min-w-0 truncate\">\n {harness.label}\n </Text>\n <Text as=\"span\" size=\"sm\" className=\"text-foreground-neutral-muted\">\n {harness.description}\n </Text>\n </span>\n </PanelCellAction>\n </PanelCell>\n );\n}\n\nfunction ModelProviderPicker({\n catalogQuery,\n supportedProviders,\n onSelect,\n}: {\n catalogQuery: ReturnType<typeof useModelProviderCatalogQuery>;\n supportedProviders: SupportedProvider[];\n onSelect: (entry: SupportedProvider) => void;\n}) {\n if (catalogQuery.isPending) {\n return <ModelProviderGridSkeleton label=\"Loading model providers\" />;\n }\n\n if (catalogQuery.isError && catalogQuery.data === undefined) {\n return <QueryLoadError query={catalogQuery} subject=\"model provider catalog\" />;\n }\n\n if (catalogQuery.data !== undefined && supportedProviders.length === 0) {\n return (\n <EmptyState\n icon=\"componentLine\"\n title=\"No providers available to configure\"\n description=\"Skip for now and add one later from workspace settings.\"\n />\n );\n }\n\n return <AvailableProvidersGrid entries={supportedProviders} onSelect={onSelect} />;\n}\n"],"names":["QueryLoadError","Button","Callout","EmptyState","Modal","ModalContent","ModalHeader","ModalTitle","Panel","PanelBody","PanelCell","PanelCellAction","PanelGrid","toast","Header","Text","useEffect","useMemo","useReducer","AvailableProvidersGrid","modelProviderConfigErrorToFormError","ModelProviderGridSkeleton","ModelProviderTestAndSaveForm","DEFAULT_HARNESS","harnessSupportsProvider","listHarnesses","initialOnboardingState","onboardingReducer","isSupportedProvider","useModelProviderCatalogQuery","useSetDefaultHarnessMutation","dismissModelProviderOnboarding","ModelProviderOnboardingPage","workspaceId","onSkip","onConfigured","catalogQuery","setDefaultHarness","onboarding","dispatch","supportedProviders","data","providers","filter","filteredProviders","step","provider","harnessId","id","document","getElementById","focus","handleSkip","handleProviderSaved","type","success","label","mutateAsync","error","mapped","message","selectedHarnessDescriptor","find","harness","headingId","div","className","header","variant","tabIndex","onClick","size","section","aria-labelledby","HarnessPicker","onSelect","ModelProviderPicker","entry","open","onOpenChange","aria-describedby","undefined","aria-hidden","role","bold","setAsDefaultOnSave","onSaved","aria-label","map","HarnessCard","onChoose","action","span","as","description","isPending","isError","query","subject","length","icon","title","entries"],"mappings":"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"}
|
|
1
|
+
{"version":3,"sources":["../../src/pages/model-provider-onboarding-page.tsx"],"sourcesContent":["import {QueryLoadError} from '@shipfox/client-ui';\nimport {Button} from '@shipfox/react-ui/button';\nimport {Callout} from '@shipfox/react-ui/callout';\nimport {EmptyState} from '@shipfox/react-ui/empty-state';\nimport {Modal, ModalContent, ModalHeader, ModalTitle} from '@shipfox/react-ui/modal';\nimport {Panel, PanelBody, PanelCell, PanelCellAction, PanelGrid} from '@shipfox/react-ui/panel';\nimport {toast} from '@shipfox/react-ui/toast';\nimport {Header, Text} from '@shipfox/react-ui/typography';\nimport {useEffect, useMemo, useReducer, useRef} from 'react';\nimport {AvailableProvidersGrid} from '#components/available-providers-grid.js';\nimport {modelProviderConfigErrorToFormError} from '#components/form-errors.js';\nimport {ModelProviderGridSkeleton} from '#components/model-provider-grid-skeleton.js';\nimport {ModelProviderTestAndSaveForm} from '#components/test-and-save-form.js';\nimport {DEFAULT_HARNESS, harnessSupportsProvider, listHarnesses} from '#core/harness-policy.js';\nimport type {HarnessDescriptor, HarnessId, SupportedProvider} from '#core/models.js';\nimport {initialOnboardingState, onboardingReducer} from '#core/onboarding-reducer.js';\nimport {isManagedOnlyCatalog, isSupportedProvider} from '#core/provider-policy.js';\nimport {\n useModelProviderCatalogQuery,\n useSetDefaultHarnessMutation,\n} from '#hooks/api/model-providers.js';\nimport {dismissModelProviderOnboarding} from '#state/model-provider-onboarding.js';\n\nexport function ModelProviderOnboardingPage({\n workspaceId,\n onSkip,\n onConfigured,\n}: {\n workspaceId: string;\n onSkip: () => void;\n onConfigured: () => void;\n}) {\n const catalogQuery = useModelProviderCatalogQuery();\n const setDefaultHarness = useSetDefaultHarnessMutation();\n const [onboarding, dispatch] = useReducer(onboardingReducer, initialOnboardingState);\n const supportedProviders = catalogQuery.data?.providers.filter(isSupportedProvider) ?? [];\n const catalogLoaded = catalogQuery.data !== undefined;\n const catalogLoading = catalogQuery.isPending;\n const catalogLoadError = catalogQuery.isError && catalogQuery.data === undefined;\n const managedOnly = isManagedOnlyCatalog(catalogQuery.data);\n const managedOnlyForwarded = useRef(false);\n const filteredProviders = useMemo(() => {\n if (onboarding.step === 'choose-harness') return [];\n return supportedProviders.filter((provider) =>\n harnessSupportsProvider(onboarding.harnessId, provider.id),\n );\n }, [onboarding, supportedProviders]);\n\n useEffect(() => {\n if (!managedOnly || managedOnlyForwarded.current) return;\n managedOnlyForwarded.current = true;\n onConfigured();\n }, [managedOnly, onConfigured]);\n\n useEffect(() => {\n if (managedOnly || !catalogLoaded) return;\n document\n .getElementById(\n onboarding.step === 'choose-harness'\n ? 'model-provider-harness-step'\n : 'model-provider-provider-step',\n )\n ?.focus();\n }, [catalogLoaded, managedOnly, onboarding.step]);\n\n if (managedOnly) return null;\n\n function handleSkip() {\n try {\n dismissModelProviderOnboarding(workspaceId);\n } catch {\n // Skip is best-effort persistence; access to the product must not depend on storage.\n }\n onSkip();\n }\n\n async function handleProviderSaved() {\n if (onboarding.step !== 'configure-provider' && onboarding.step !== 'saving-default-harness')\n return;\n\n const provider = onboarding.provider;\n if (onboarding.step === 'configure-provider') dispatch({type: 'provider-saved'});\n if (onboarding.harnessId === DEFAULT_HARNESS) {\n toast.success(`${provider.label} saved`);\n dispatch({type: 'default-harness-saved'});\n onConfigured();\n return;\n }\n\n try {\n await setDefaultHarness.mutateAsync({\n workspaceId,\n harnessId: onboarding.harnessId,\n });\n toast.success(`${provider.label} saved`);\n dispatch({type: 'default-harness-saved'});\n onConfigured();\n } catch (error) {\n const mapped = modelProviderConfigErrorToFormError(error);\n dispatch({\n type: 'default-harness-failed',\n message: mapped.message || 'Could not save default harness. Try again.',\n });\n }\n }\n\n const selectedHarnessDescriptor =\n onboarding.step === 'choose-harness'\n ? null\n : listHarnesses().find((harness) => harness.id === onboarding.harnessId);\n const headingId =\n onboarding.step === 'choose-harness'\n ? 'model-provider-harness-step'\n : 'model-provider-provider-step';\n\n return (\n <div className=\"flex w-full flex-col gap-section\">\n <header className=\"flex flex-col gap-cluster\">\n <div className=\"flex items-start justify-between gap-group max-[520px]:flex-col max-[520px]:gap-inline\">\n <Header id={headingId} variant=\"h1\" tabIndex={-1} className=\"outline-none\">\n {selectedHarnessDescriptor\n ? `Configure ${selectedHarnessDescriptor.label}`\n : 'Choose agent harness'}\n </Header>\n <Button type=\"button\" variant=\"secondary\" onClick={handleSkip} className=\"shrink-0\">\n Skip for now\n </Button>\n </div>\n <Text size=\"md\" className=\"text-foreground-neutral-muted\">\n {selectedHarnessDescriptor\n ? `${selectedHarnessDescriptor.label} needs a compatible model provider. Add your own API key, or go back to choose a different harness.`\n : 'A harness runs agent steps. Choose the engine you want first, then connect a compatible model provider.'}\n </Text>\n </header>\n\n <section aria-labelledby={headingId} className=\"flex flex-col gap-group\">\n {catalogLoading ? <ModelProviderGridSkeleton label=\"Loading model providers\" /> : null}\n {catalogLoadError ? (\n <QueryLoadError query={catalogQuery} subject=\"model provider catalog\" />\n ) : null}\n {!catalogLoading && !catalogLoadError ? (\n onboarding.step === 'choose-harness' ? (\n <HarnessPicker\n onSelect={(harnessId) => dispatch({type: 'harness-selected', harnessId})}\n />\n ) : (\n <>\n <div>\n <Button\n type=\"button\"\n variant=\"transparent\"\n onClick={() => dispatch({type: 'back'})}\n >\n Back\n </Button>\n </div>\n <ModelProviderPicker\n key={onboarding.harnessId}\n supportedProviders={filteredProviders}\n onSelect={(entry) => {\n dispatch({type: 'provider-selected', provider: entry});\n }}\n />\n </>\n )\n ) : null}\n </section>\n\n <Modal\n open={\n onboarding.step === 'configure-provider' || onboarding.step === 'saving-default-harness'\n }\n onOpenChange={(open) => {\n if (!open && onboarding.step === 'configure-provider') dispatch({type: 'back'});\n }}\n >\n <ModalContent aria-describedby={undefined}>\n <ModalTitle className=\"sr-only\">\n {onboarding.step === 'configure-provider' ||\n onboarding.step === 'saving-default-harness'\n ? `Configure ${onboarding.provider.label}`\n : ''}\n </ModalTitle>\n <ModalHeader>\n <Text\n size=\"lg\"\n aria-hidden=\"true\"\n className=\"overflow-ellipsis overflow-hidden whitespace-nowrap\"\n >\n {onboarding.step === 'configure-provider' ||\n onboarding.step === 'saving-default-harness'\n ? `Configure ${onboarding.provider.label}`\n : ''}\n </Text>\n </ModalHeader>\n {onboarding.step === 'configure-provider' ||\n onboarding.step === 'saving-default-harness' ? (\n <div className=\"flex min-h-0 flex-1 flex-col gap-inline\">\n {onboarding.step === 'saving-default-harness' ? (\n <div role=\"status\" className=\"px-row\">\n <Text size=\"sm\" className=\"text-foreground-neutral-muted\">\n Saving harness default...\n </Text>\n </div>\n ) : null}\n {onboarding.step === 'saving-default-harness' && onboarding.error ? (\n <div className=\"px-row\">\n <Callout role=\"alert\" type=\"error\">\n <div className=\"flex flex-col gap-inline\">\n <Text size=\"sm\" bold>\n Could not save default harness\n </Text>\n <Text size=\"sm\">{onboarding.error}</Text>\n </div>\n </Callout>\n </div>\n ) : null}\n <div className=\"flex min-h-0 flex-1 flex-col\">\n <ModelProviderTestAndSaveForm\n workspaceId={workspaceId}\n entry={onboarding.provider}\n setAsDefaultOnSave\n onSaved={() => {\n void handleProviderSaved();\n }}\n />\n </div>\n </div>\n ) : null}\n </ModalContent>\n </Modal>\n </div>\n );\n}\n\nfunction HarnessPicker({onSelect}: {onSelect: (harness: HarnessId) => void}) {\n return (\n <Panel>\n <PanelBody>\n <PanelGrid aria-label=\"Agent harnesses\">\n {listHarnesses().map((harness) => (\n <HarnessCard key={harness.id} harness={harness} onChoose={() => onSelect(harness.id)} />\n ))}\n </PanelGrid>\n </PanelBody>\n </Panel>\n );\n}\n\nfunction HarnessCard({harness, onChoose}: {harness: HarnessDescriptor; onChoose: () => void}) {\n return (\n <PanelCell>\n <PanelCellAction action=\"Choose\" aria-label={`Choose ${harness.label}`} onClick={onChoose}>\n <span className=\"flex min-w-0 flex-col gap-tight\">\n <Text as=\"span\" size=\"md\" bold className=\"min-w-0 truncate\">\n {harness.label}\n </Text>\n <Text as=\"span\" size=\"sm\" className=\"text-foreground-neutral-muted\">\n {harness.description}\n </Text>\n </span>\n </PanelCellAction>\n </PanelCell>\n );\n}\n\nfunction ModelProviderPicker({\n supportedProviders,\n onSelect,\n}: {\n supportedProviders: SupportedProvider[];\n onSelect: (entry: SupportedProvider) => void;\n}) {\n if (supportedProviders.length === 0) {\n return (\n <EmptyState\n icon=\"componentLine\"\n title=\"No providers available to configure\"\n description=\"Skip for now and add one later from workspace settings.\"\n />\n );\n }\n\n return <AvailableProvidersGrid entries={supportedProviders} onSelect={onSelect} />;\n}\n"],"names":["QueryLoadError","Button","Callout","EmptyState","Modal","ModalContent","ModalHeader","ModalTitle","Panel","PanelBody","PanelCell","PanelCellAction","PanelGrid","toast","Header","Text","useEffect","useMemo","useReducer","useRef","AvailableProvidersGrid","modelProviderConfigErrorToFormError","ModelProviderGridSkeleton","ModelProviderTestAndSaveForm","DEFAULT_HARNESS","harnessSupportsProvider","listHarnesses","initialOnboardingState","onboardingReducer","isManagedOnlyCatalog","isSupportedProvider","useModelProviderCatalogQuery","useSetDefaultHarnessMutation","dismissModelProviderOnboarding","ModelProviderOnboardingPage","workspaceId","onSkip","onConfigured","catalogQuery","setDefaultHarness","onboarding","dispatch","supportedProviders","data","providers","filter","catalogLoaded","undefined","catalogLoading","isPending","catalogLoadError","isError","managedOnly","managedOnlyForwarded","filteredProviders","step","provider","harnessId","id","current","document","getElementById","focus","handleSkip","handleProviderSaved","type","success","label","mutateAsync","error","mapped","message","selectedHarnessDescriptor","find","harness","headingId","div","className","header","variant","tabIndex","onClick","size","section","aria-labelledby","query","subject","HarnessPicker","onSelect","ModelProviderPicker","entry","open","onOpenChange","aria-describedby","aria-hidden","role","bold","setAsDefaultOnSave","onSaved","aria-label","map","HarnessCard","onChoose","action","span","as","description","length","icon","title","entries"],"mappings":";AAAA,SAAQA,cAAc,QAAO,qBAAqB;AAClD,SAAQC,MAAM,QAAO,2BAA2B;AAChD,SAAQC,OAAO,QAAO,4BAA4B;AAClD,SAAQC,UAAU,QAAO,gCAAgC;AACzD,SAAQC,KAAK,EAAEC,YAAY,EAAEC,WAAW,EAAEC,UAAU,QAAO,0BAA0B;AACrF,SAAQC,KAAK,EAAEC,SAAS,EAAEC,SAAS,EAAEC,eAAe,EAAEC,SAAS,QAAO,0BAA0B;AAChG,SAAQC,KAAK,QAAO,0BAA0B;AAC9C,SAAQC,MAAM,EAAEC,IAAI,QAAO,+BAA+B;AAC1D,SAAQC,SAAS,EAAEC,OAAO,EAAEC,UAAU,EAAEC,MAAM,QAAO,QAAQ;AAC7D,SAAQC,sBAAsB,QAAO,0CAA0C;AAC/E,SAAQC,mCAAmC,QAAO,6BAA6B;AAC/E,SAAQC,yBAAyB,QAAO,8CAA8C;AACtF,SAAQC,4BAA4B,QAAO,oCAAoC;AAC/E,SAAQC,eAAe,EAAEC,uBAAuB,EAAEC,aAAa,QAAO,0BAA0B;AAEhG,SAAQC,sBAAsB,EAAEC,iBAAiB,QAAO,8BAA8B;AACtF,SAAQC,oBAAoB,EAAEC,mBAAmB,QAAO,2BAA2B;AACnF,SACEC,4BAA4B,EAC5BC,4BAA4B,QACvB,gCAAgC;AACvC,SAAQC,8BAA8B,QAAO,sCAAsC;AAEnF,OAAO,SAASC,4BAA4B,EAC1CC,WAAW,EACXC,MAAM,EACNC,YAAY,EAKb;IACC,MAAMC,eAAeP;IACrB,MAAMQ,oBAAoBP;IAC1B,MAAM,CAACQ,YAAYC,SAAS,GAAGvB,WAAWU,mBAAmBD;IAC7D,MAAMe,qBAAqBJ,aAAaK,IAAI,EAAEC,UAAUC,OAAOf,wBAAwB,EAAE;IACzF,MAAMgB,gBAAgBR,aAAaK,IAAI,KAAKI;IAC5C,MAAMC,iBAAiBV,aAAaW,SAAS;IAC7C,MAAMC,mBAAmBZ,aAAaa,OAAO,IAAIb,aAAaK,IAAI,KAAKI;IACvE,MAAMK,cAAcvB,qBAAqBS,aAAaK,IAAI;IAC1D,MAAMU,uBAAuBlC,OAAO;IACpC,MAAMmC,oBAAoBrC,QAAQ;QAChC,IAAIuB,WAAWe,IAAI,KAAK,kBAAkB,OAAO,EAAE;QACnD,OAAOb,mBAAmBG,MAAM,CAAC,CAACW,WAChC/B,wBAAwBe,WAAWiB,SAAS,EAAED,SAASE,EAAE;IAE7D,GAAG;QAAClB;QAAYE;KAAmB;IAEnC1B,UAAU;QACR,IAAI,CAACoC,eAAeC,qBAAqBM,OAAO,EAAE;QAClDN,qBAAqBM,OAAO,GAAG;QAC/BtB;IACF,GAAG;QAACe;QAAaf;KAAa;IAE9BrB,UAAU;QACR,IAAIoC,eAAe,CAACN,eAAe;QACnCc,SACGC,cAAc,CACbrB,WAAWe,IAAI,KAAK,mBAChB,gCACA,iCAEJO;IACN,GAAG;QAAChB;QAAeM;QAAaZ,WAAWe,IAAI;KAAC;IAEhD,IAAIH,aAAa,OAAO;IAExB,SAASW;QACP,IAAI;YACF9B,+BAA+BE;QACjC,EAAE,OAAM;QACN,qFAAqF;QACvF;QACAC;IACF;IAEA,eAAe4B;QACb,IAAIxB,WAAWe,IAAI,KAAK,wBAAwBf,WAAWe,IAAI,KAAK,0BAClE;QAEF,MAAMC,WAAWhB,WAAWgB,QAAQ;QACpC,IAAIhB,WAAWe,IAAI,KAAK,sBAAsBd,SAAS;YAACwB,MAAM;QAAgB;QAC9E,IAAIzB,WAAWiB,SAAS,KAAKjC,iBAAiB;YAC5CX,MAAMqD,OAAO,CAAC,GAAGV,SAASW,KAAK,CAAC,MAAM,CAAC;YACvC1B,SAAS;gBAACwB,MAAM;YAAuB;YACvC5B;YACA;QACF;QAEA,IAAI;YACF,MAAME,kBAAkB6B,WAAW,CAAC;gBAClCjC;gBACAsB,WAAWjB,WAAWiB,SAAS;YACjC;YACA5C,MAAMqD,OAAO,CAAC,GAAGV,SAASW,KAAK,CAAC,MAAM,CAAC;YACvC1B,SAAS;gBAACwB,MAAM;YAAuB;YACvC5B;QACF,EAAE,OAAOgC,OAAO;YACd,MAAMC,SAASjD,oCAAoCgD;YACnD5B,SAAS;gBACPwB,MAAM;gBACNM,SAASD,OAAOC,OAAO,IAAI;YAC7B;QACF;IACF;IAEA,MAAMC,4BACJhC,WAAWe,IAAI,KAAK,mBAChB,OACA7B,gBAAgB+C,IAAI,CAAC,CAACC,UAAYA,QAAQhB,EAAE,KAAKlB,WAAWiB,SAAS;IAC3E,MAAMkB,YACJnC,WAAWe,IAAI,KAAK,mBAChB,gCACA;IAEN,qBACE,MAACqB;QAAIC,WAAU;;0BACb,MAACC;gBAAOD,WAAU;;kCAChB,MAACD;wBAAIC,WAAU;;0CACb,KAAC/D;gCAAO4C,IAAIiB;gCAAWI,SAAQ;gCAAKC,UAAU,CAAC;gCAAGH,WAAU;0CACzDL,4BACG,CAAC,UAAU,EAAEA,0BAA0BL,KAAK,EAAE,GAC9C;;0CAEN,KAAClE;gCAAOgE,MAAK;gCAASc,SAAQ;gCAAYE,SAASlB;gCAAYc,WAAU;0CAAW;;;;kCAItF,KAAC9D;wBAAKmE,MAAK;wBAAKL,WAAU;kCACvBL,4BACG,GAAGA,0BAA0BL,KAAK,CAAC,mGAAmG,CAAC,GACvI;;;;0BAIR,MAACgB;gBAAQC,mBAAiBT;gBAAWE,WAAU;;oBAC5C7B,+BAAiB,KAAC1B;wBAA0B6C,OAAM;yBAA+B;oBACjFjB,iCACC,KAAClD;wBAAeqF,OAAO/C;wBAAcgD,SAAQ;yBAC3C;oBACH,CAACtC,kBAAkB,CAACE,mBACnBV,WAAWe,IAAI,KAAK,iCAClB,KAACgC;wBACCC,UAAU,CAAC/B,YAAchB,SAAS;gCAACwB,MAAM;gCAAoBR;4BAAS;uCAGxE;;0CACE,KAACmB;0CACC,cAAA,KAAC3E;oCACCgE,MAAK;oCACLc,SAAQ;oCACRE,SAAS,IAAMxC,SAAS;4CAACwB,MAAM;wCAAM;8CACtC;;;0CAIH,KAACwB;gCAEC/C,oBAAoBY;gCACpBkC,UAAU,CAACE;oCACTjD,SAAS;wCAACwB,MAAM;wCAAqBT,UAAUkC;oCAAK;gCACtD;+BAJKlD,WAAWiB,SAAS;;yBAQ7B;;;0BAGN,KAACrD;gBACCuF,MACEnD,WAAWe,IAAI,KAAK,wBAAwBf,WAAWe,IAAI,KAAK;gBAElEqC,cAAc,CAACD;oBACb,IAAI,CAACA,QAAQnD,WAAWe,IAAI,KAAK,sBAAsBd,SAAS;wBAACwB,MAAM;oBAAM;gBAC/E;0BAEA,cAAA,MAAC5D;oBAAawF,oBAAkB9C;;sCAC9B,KAACxC;4BAAWsE,WAAU;sCACnBrC,WAAWe,IAAI,KAAK,wBACrBf,WAAWe,IAAI,KAAK,2BAChB,CAAC,UAAU,EAAEf,WAAWgB,QAAQ,CAACW,KAAK,EAAE,GACxC;;sCAEN,KAAC7D;sCACC,cAAA,KAACS;gCACCmE,MAAK;gCACLY,eAAY;gCACZjB,WAAU;0CAETrC,WAAWe,IAAI,KAAK,wBACrBf,WAAWe,IAAI,KAAK,2BAChB,CAAC,UAAU,EAAEf,WAAWgB,QAAQ,CAACW,KAAK,EAAE,GACxC;;;wBAGP3B,WAAWe,IAAI,KAAK,wBACrBf,WAAWe,IAAI,KAAK,yCAClB,MAACqB;4BAAIC,WAAU;;gCACZrC,WAAWe,IAAI,KAAK,yCACnB,KAACqB;oCAAImB,MAAK;oCAASlB,WAAU;8CAC3B,cAAA,KAAC9D;wCAAKmE,MAAK;wCAAKL,WAAU;kDAAgC;;qCAI1D;gCACHrC,WAAWe,IAAI,KAAK,4BAA4Bf,WAAW6B,KAAK,iBAC/D,KAACO;oCAAIC,WAAU;8CACb,cAAA,KAAC3E;wCAAQ6F,MAAK;wCAAQ9B,MAAK;kDACzB,cAAA,MAACW;4CAAIC,WAAU;;8DACb,KAAC9D;oDAAKmE,MAAK;oDAAKc,IAAI;8DAAC;;8DAGrB,KAACjF;oDAAKmE,MAAK;8DAAM1C,WAAW6B,KAAK;;;;;qCAIrC;8CACJ,KAACO;oCAAIC,WAAU;8CACb,cAAA,KAACtD;wCACCY,aAAaA;wCACbuD,OAAOlD,WAAWgB,QAAQ;wCAC1ByC,kBAAkB;wCAClBC,SAAS;4CACP,KAAKlC;wCACP;;;;6BAIJ;;;;;;AAKd;AAEA,SAASuB,cAAc,EAACC,QAAQ,EAA2C;IACzE,qBACE,KAAChF;kBACC,cAAA,KAACC;sBACC,cAAA,KAACG;gBAAUuF,cAAW;0BACnBzE,gBAAgB0E,GAAG,CAAC,CAAC1B,wBACpB,KAAC2B;wBAA6B3B,SAASA;wBAAS4B,UAAU,IAAMd,SAASd,QAAQhB,EAAE;uBAAjEgB,QAAQhB,EAAE;;;;AAMxC;AAEA,SAAS2C,YAAY,EAAC3B,OAAO,EAAE4B,QAAQ,EAAqD;IAC1F,qBACE,KAAC5F;kBACC,cAAA,KAACC;YAAgB4F,QAAO;YAASJ,cAAY,CAAC,OAAO,EAAEzB,QAAQP,KAAK,EAAE;YAAEc,SAASqB;sBAC/E,cAAA,MAACE;gBAAK3B,WAAU;;kCACd,KAAC9D;wBAAK0F,IAAG;wBAAOvB,MAAK;wBAAKc,IAAI;wBAACnB,WAAU;kCACtCH,QAAQP,KAAK;;kCAEhB,KAACpD;wBAAK0F,IAAG;wBAAOvB,MAAK;wBAAKL,WAAU;kCACjCH,QAAQgC,WAAW;;;;;;AAMhC;AAEA,SAASjB,oBAAoB,EAC3B/C,kBAAkB,EAClB8C,QAAQ,EAIT;IACC,IAAI9C,mBAAmBiE,MAAM,KAAK,GAAG;QACnC,qBACE,KAACxG;YACCyG,MAAK;YACLC,OAAM;YACNH,aAAY;;IAGlB;IAEA,qBAAO,KAACtF;QAAuB0F,SAASpE;QAAoB8C,UAAUA;;AACxE"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"model-provider-onboarding-page.stories.d.ts","sourceRoot":"","sources":["../../src/pages/model-provider-onboarding-page.stories.tsx"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAO,QAAQ,EAAC,MAAM,kBAAkB,CAAC;AAQrD,KAAK,QAAQ,GAAG,WAAW,GAAG,SAAS,GAAG,eAAe,GAAG,cAAc,GAAG,YAAY,CAAC;AAE1F,UAAU,iCAAiC;IACzC,QAAQ,EAAE,QAAQ,CAAC;CACpB;AA+ED,iBAAS,4BAA4B,CAAC,EAAC,QAAQ,EAAC,EAAE,iCAAiC,+BAuBlF;AAED,QAAA,MAAM,IAAI;;;;QAGK,MAAM;;;;;CAEgC,CAAC;eAEvC,IAAI;AACnB,KAAK,KAAK,GAAG,QAAQ,CAAC,OAAO,IAAI,CAAC,CAAC;AAEnC,eAAO,MAAM,UAAU,EAAE,KAAU,CAAC;AAEpC,eAAO,MAAM,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"model-provider-onboarding-page.stories.d.ts","sourceRoot":"","sources":["../../src/pages/model-provider-onboarding-page.stories.tsx"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAO,QAAQ,EAAC,MAAM,kBAAkB,CAAC;AAQrD,KAAK,QAAQ,GAAG,WAAW,GAAG,SAAS,GAAG,eAAe,GAAG,cAAc,GAAG,YAAY,CAAC;AAE1F,UAAU,iCAAiC;IACzC,QAAQ,EAAE,QAAQ,CAAC;CACpB;AA+ED,iBAAS,4BAA4B,CAAC,EAAC,QAAQ,EAAC,EAAE,iCAAiC,+BAuBlF;AAED,QAAA,MAAM,IAAI;;;;QAGK,MAAM;;;;;CAEgC,CAAC;eAEvC,IAAI;AACnB,KAAK,KAAK,GAAG,QAAQ,CAAC,OAAO,IAAI,CAAC,CAAC;AAEnC,eAAO,MAAM,UAAU,EAAE,KAAU,CAAC;AAEpC,eAAO,MAAM,OAAO,EAAE,KAErB,CAAC;AAEF,eAAO,MAAM,YAAY,EAAE,KAE1B,CAAC;AAEF,eAAO,MAAM,oBAAoB,EAAE,KAMlC,CAAC;AAEF,eAAO,MAAM,SAAS,EAAE,KAMvB,CAAC;AAEF,eAAO,MAAM,iBAAiB,EAAE,KAW/B,CAAC;AAEF,eAAO,MAAM,mBAAmB,EAAE,KAWjC,CAAC;AAEF,eAAO,MAAM,kBAAkB,EAAE,KAQhC,CAAC"}
|
|
@@ -176,23 +176,11 @@ export const Playground = {};
|
|
|
176
176
|
export const Loading = {
|
|
177
177
|
args: {
|
|
178
178
|
scenario: 'loading'
|
|
179
|
-
},
|
|
180
|
-
play: async ({ canvasElement })=>{
|
|
181
|
-
const canvas = within(canvasElement);
|
|
182
|
-
await userEvent.click(canvas.getByRole('button', {
|
|
183
|
-
name: 'Choose pi'
|
|
184
|
-
}));
|
|
185
179
|
}
|
|
186
180
|
};
|
|
187
181
|
export const CatalogError = {
|
|
188
182
|
args: {
|
|
189
183
|
scenario: 'catalog-error'
|
|
190
|
-
},
|
|
191
|
-
play: async ({ canvasElement })=>{
|
|
192
|
-
const canvas = within(canvasElement);
|
|
193
|
-
await userEvent.click(canvas.getByRole('button', {
|
|
194
|
-
name: 'Choose pi'
|
|
195
|
-
}));
|
|
196
184
|
}
|
|
197
185
|
};
|
|
198
186
|
export const NoProvidersAvailable = {
|
|
@@ -201,7 +189,7 @@ export const NoProvidersAvailable = {
|
|
|
201
189
|
},
|
|
202
190
|
play: async ({ canvasElement })=>{
|
|
203
191
|
const canvas = within(canvasElement);
|
|
204
|
-
await userEvent.click(canvas.
|
|
192
|
+
await userEvent.click(await canvas.findByRole('button', {
|
|
205
193
|
name: 'Choose pi'
|
|
206
194
|
}));
|
|
207
195
|
}
|
|
@@ -212,7 +200,7 @@ export const LongNames = {
|
|
|
212
200
|
},
|
|
213
201
|
play: async ({ canvasElement })=>{
|
|
214
202
|
const canvas = within(canvasElement);
|
|
215
|
-
await userEvent.click(canvas.
|
|
203
|
+
await userEvent.click(await canvas.findByRole('button', {
|
|
216
204
|
name: 'Choose pi'
|
|
217
205
|
}));
|
|
218
206
|
}
|
|
@@ -223,7 +211,7 @@ export const FilteredProviders = {
|
|
|
223
211
|
},
|
|
224
212
|
play: async ({ canvasElement })=>{
|
|
225
213
|
const canvas = within(canvasElement);
|
|
226
|
-
await userEvent.click(canvas.
|
|
214
|
+
await userEvent.click(await canvas.findByRole('button', {
|
|
227
215
|
name: 'Choose pi'
|
|
228
216
|
}));
|
|
229
217
|
await userEvent.type(await canvas.findByRole('searchbox', {
|
|
@@ -240,7 +228,7 @@ export const NoMatchingProviders = {
|
|
|
240
228
|
},
|
|
241
229
|
play: async ({ canvasElement })=>{
|
|
242
230
|
const canvas = within(canvasElement);
|
|
243
|
-
await userEvent.click(canvas.
|
|
231
|
+
await userEvent.click(await canvas.findByRole('button', {
|
|
244
232
|
name: 'Choose pi'
|
|
245
233
|
}));
|
|
246
234
|
await userEvent.type(await canvas.findByRole('searchbox', {
|
|
@@ -257,7 +245,7 @@ export const ConfigureModalOpen = {
|
|
|
257
245
|
},
|
|
258
246
|
play: async ({ canvasElement })=>{
|
|
259
247
|
const canvas = within(canvasElement);
|
|
260
|
-
await userEvent.click(canvas.
|
|
248
|
+
await userEvent.click(await canvas.findByRole('button', {
|
|
261
249
|
name: 'Choose pi'
|
|
262
250
|
}));
|
|
263
251
|
await userEvent.click(await canvas.findByRole('button', {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/pages/model-provider-onboarding-page.stories.tsx"],"sourcesContent":["import type {ModelProviderCatalogEntryDto, ModelProviderConfigDto} from '@shipfox/api-agent-dto';\nimport {configureApiClient} from '@shipfox/client-api';\nimport {Toaster} from '@shipfox/react-ui/toast';\nimport type {Meta, StoryObj} from '@storybook/react';\nimport {QueryClient, QueryClientProvider} from '@tanstack/react-query';\nimport {useMemo} from 'react';\nimport {screen, userEvent, within} from 'storybook/test';\nimport {ModelProviderOnboardingPage} from './model-provider-onboarding-page.js';\n\nconst WORKSPACE_ID = '11111111-1111-4111-8111-111111111111';\n\ntype Scenario = 'available' | 'loading' | 'catalog-error' | 'no-providers' | 'long-names';\n\ninterface ModelProviderOnboardingStoryProps {\n scenario: Scenario;\n}\n\nconst CATALOG: ModelProviderCatalogEntryDto[] = [\n providerEntry({\n id: 'anthropic',\n label: 'Anthropic',\n default_model: 'claude-opus-4-8',\n models: [\n {id: 'claude-opus-4-8', label: 'Claude Opus 4.8'},\n {id: 'claude-haiku-4-5', label: 'Claude Haiku 4.5'},\n ],\n }),\n providerEntry({\n id: 'openai',\n label: 'OpenAI',\n default_model: 'gpt-5.5-pro',\n models: [\n {id: 'gpt-5.5-pro', label: 'GPT-5.5 Pro'},\n {id: 'gpt-5-mini', label: 'GPT-5 Mini'},\n ],\n }),\n providerEntry({\n id: 'xai',\n label: 'xAI',\n default_model: 'grok-code-fast-1',\n models: [{id: 'grok-code-fast-1', label: 'Grok Code Fast 1'}],\n }),\n providerEntry({\n id: 'openrouter',\n label: 'OpenRouter',\n default_model: 'openrouter/auto',\n models: [{id: 'openrouter/auto', label: 'OpenRouter Auto'}],\n }),\n providerEntry({\n id: 'google',\n label: 'Google Gemini',\n default_model: 'gemini-3-pro',\n models: [{id: 'gemini-3-pro', label: 'Gemini 3 Pro'}],\n }),\n providerEntry({\n id: 'mistral',\n label: 'Mistral AI',\n default_model: 'codestral-latest',\n models: [{id: 'codestral-latest', label: 'Codestral Latest'}],\n }),\n providerEntry({\n id: 'groq',\n label: 'Groq',\n default_model: 'llama-4-fast',\n models: [{id: 'llama-4-fast', label: 'Llama 4 Fast'}],\n }),\n providerEntry({\n id: 'deepseek',\n label: 'DeepSeek',\n default_model: 'deepseek-coder',\n models: [{id: 'deepseek-coder', label: 'DeepSeek Coder'}],\n }),\n providerEntry({\n id: 'moonshotai',\n label: 'Moonshot AI',\n default_model: 'kimi-k2',\n models: [{id: 'kimi-k2', label: 'Kimi K2'}],\n }),\n providerEntry({\n id: 'azure-openai-responses',\n label: 'Azure OpenAI Responses',\n default_model: 'gpt-5.5-pro',\n models: [{id: 'gpt-5.5-pro', label: 'GPT-5.5 Pro'}],\n }),\n providerEntry({\n id: 'amazon-bedrock',\n label: 'Amazon Bedrock',\n support_status: 'unsupported',\n credential_fields: [],\n unsupported_reason: 'AWS cloud credentials are not supported yet.',\n models: [],\n }),\n];\n\nfunction ModelProviderOnboardingStory({scenario}: ModelProviderOnboardingStoryProps) {\n configureApiClient({\n baseUrl: 'https://api.example.test',\n fetchImpl: fetchForScenario(scenario),\n });\n\n const queryClient = useMemo(\n () => new QueryClient({defaultOptions: {queries: {retry: false}}}),\n [],\n );\n\n return (\n <QueryClientProvider client={queryClient}>\n <div className=\"bg-background-subtle-base px-24 py-32\">\n <ModelProviderOnboardingPage\n workspaceId={WORKSPACE_ID}\n onSkip={() => undefined}\n onConfigured={() => undefined}\n />\n </div>\n <Toaster />\n </QueryClientProvider>\n );\n}\n\nconst meta = {\n title: 'Agent/ProviderOnboarding',\n component: ModelProviderOnboardingStory,\n parameters: {layout: 'fullscreen'},\n args: {scenario: 'available'},\n} satisfies Meta<typeof ModelProviderOnboardingStory>;\n\nexport default meta;\ntype Story = StoryObj<typeof meta>;\n\nexport const Playground: Story = {};\n\nexport const Loading: Story = {\n args: {scenario: 'loading'},\n play: async ({canvasElement}) => {\n const canvas = within(canvasElement);\n await userEvent.click(canvas.getByRole('button', {name: 'Choose pi'}));\n },\n};\n\nexport const CatalogError: Story = {\n args: {scenario: 'catalog-error'},\n play: async ({canvasElement}) => {\n const canvas = within(canvasElement);\n await userEvent.click(canvas.getByRole('button', {name: 'Choose pi'}));\n },\n};\n\nexport const NoProvidersAvailable: Story = {\n args: {scenario: 'no-providers'},\n play: async ({canvasElement}) => {\n const canvas = within(canvasElement);\n await userEvent.click(canvas.getByRole('button', {name: 'Choose pi'}));\n },\n};\n\nexport const LongNames: Story = {\n args: {scenario: 'long-names'},\n play: async ({canvasElement}) => {\n const canvas = within(canvasElement);\n await userEvent.click(canvas.getByRole('button', {name: 'Choose pi'}));\n },\n};\n\nexport const FilteredProviders: Story = {\n args: {scenario: 'available'},\n play: async ({canvasElement}) => {\n const canvas = within(canvasElement);\n await userEvent.click(canvas.getByRole('button', {name: 'Choose pi'}));\n await userEvent.type(\n await canvas.findByRole('searchbox', {name: 'Search providers'}),\n 'openrouter',\n );\n await canvas.findByRole('button', {name: 'Configure OpenRouter'});\n },\n};\n\nexport const NoMatchingProviders: Story = {\n args: {scenario: 'available'},\n play: async ({canvasElement}) => {\n const canvas = within(canvasElement);\n await userEvent.click(canvas.getByRole('button', {name: 'Choose pi'}));\n await userEvent.type(\n await canvas.findByRole('searchbox', {name: 'Search providers'}),\n 'not-a-provider',\n );\n await canvas.findByRole('button', {name: 'Clear search'});\n },\n};\n\nexport const ConfigureModalOpen: Story = {\n args: {scenario: 'available'},\n play: async ({canvasElement}) => {\n const canvas = within(canvasElement);\n await userEvent.click(canvas.getByRole('button', {name: 'Choose pi'}));\n await userEvent.click(await canvas.findByRole('button', {name: 'Configure Anthropic'}));\n await screen.findByLabelText('API key');\n },\n};\n\nfunction fetchForScenario(scenario: Scenario): typeof fetch {\n return (input) => {\n const url = requestUrl(input);\n const request = input instanceof Request ? input : undefined;\n if (scenario === 'loading') return new Promise<Response>(() => undefined);\n if (url.pathname.endsWith('/agent/model-provider-catalog')) {\n if (scenario === 'catalog-error') return Promise.resolve(errorResponse());\n return Promise.resolve(jsonResponse({providers: catalogForScenario(scenario)}));\n }\n if (request?.method === 'PUT' && url.pathname.includes('/agent/model-providers/')) {\n return Promise.resolve(\n jsonResponse(\n providerConfig({\n provider_id: url.pathname.endsWith('/openai') ? 'openai' : 'anthropic',\n }),\n ),\n );\n }\n return Promise.resolve(jsonResponse({}, {status: 404}));\n };\n}\n\nfunction catalogForScenario(scenario: Scenario): ModelProviderCatalogEntryDto[] {\n if (scenario === 'no-providers') return [];\n if (scenario !== 'long-names') return CATALOG;\n return [\n providerEntry({\n id: 'anthropic',\n label: 'Anthropic Enterprise Production Claude Provider With Long Label',\n default_model: 'claude-opus-4-8',\n }),\n providerEntry({\n id: 'openai',\n label: 'OpenAI Platform Shared Workspace Credentials With Long Label',\n default_model: 'gpt-5.5-pro',\n models: [{id: 'gpt-5.5-pro', label: 'GPT-5.5 Pro'}],\n }),\n ];\n}\n\nfunction providerEntry(\n overrides: Partial<ModelProviderCatalogEntryDto> = {},\n): ModelProviderCatalogEntryDto {\n return {\n id: 'anthropic',\n label: 'Anthropic',\n support_status: 'supported',\n default_model: null,\n credential_fields: [{key: 'api_key', label: 'API key', secret: true}],\n unsupported_reason: null,\n models: [{id: 'claude-opus-4-8', label: 'Claude Opus 4.8'}],\n ...overrides,\n };\n}\n\nfunction providerConfig(\n overrides: Partial<Omit<ModelProviderConfigDto, 'kind'>> = {},\n): ModelProviderConfigDto {\n return {\n kind: 'builtin',\n provider_id: 'anthropic',\n default_model: null,\n created_at: '2026-05-08T00:00:00.000Z',\n updated_at: '2026-05-08T00:00:00.000Z',\n ...overrides,\n };\n}\n\nfunction requestUrl(input: RequestInfo | URL): URL {\n if (typeof input === 'string') return new URL(input);\n if (input instanceof URL) return input;\n return new URL(input.url);\n}\n\nfunction jsonResponse(body: unknown, init: ResponseInit = {}) {\n return new Response(JSON.stringify(body), {\n status: 200,\n headers: {'content-type': 'application/json'},\n ...init,\n });\n}\n\nfunction errorResponse() {\n return jsonResponse({code: 'server-error'}, {status: 500, statusText: 'Server error'});\n}\n"],"names":["configureApiClient","Toaster","QueryClient","QueryClientProvider","useMemo","screen","userEvent","within","ModelProviderOnboardingPage","WORKSPACE_ID","CATALOG","providerEntry","id","label","default_model","models","support_status","credential_fields","unsupported_reason","ModelProviderOnboardingStory","scenario","baseUrl","fetchImpl","fetchForScenario","queryClient","defaultOptions","queries","retry","client","div","className","workspaceId","onSkip","undefined","onConfigured","meta","title","component","parameters","layout","args","Playground","Loading","play","canvasElement","canvas","click","getByRole","name","CatalogError","NoProvidersAvailable","LongNames","FilteredProviders","type","findByRole","NoMatchingProviders","ConfigureModalOpen","findByLabelText","input","url","requestUrl","request","Request","Promise","pathname","endsWith","resolve","errorResponse","jsonResponse","providers","catalogForScenario","method","includes","providerConfig","provider_id","status","overrides","key","secret","kind","created_at","updated_at","URL","body","init","Response","JSON","stringify","headers","code","statusText"],"mappings":";AACA,SAAQA,kBAAkB,QAAO,sBAAsB;AACvD,SAAQC,OAAO,QAAO,0BAA0B;AAEhD,SAAQC,WAAW,EAAEC,mBAAmB,QAAO,wBAAwB;AACvE,SAAQC,OAAO,QAAO,QAAQ;AAC9B,SAAQC,MAAM,EAAEC,SAAS,EAAEC,MAAM,QAAO,iBAAiB;AACzD,SAAQC,2BAA2B,QAAO,sCAAsC;AAEhF,MAAMC,eAAe;AAQrB,MAAMC,UAA0C;IAC9CC,cAAc;QACZC,IAAI;QACJC,OAAO;QACPC,eAAe;QACfC,QAAQ;YACN;gBAACH,IAAI;gBAAmBC,OAAO;YAAiB;YAChD;gBAACD,IAAI;gBAAoBC,OAAO;YAAkB;SACnD;IACH;IACAF,cAAc;QACZC,IAAI;QACJC,OAAO;QACPC,eAAe;QACfC,QAAQ;YACN;gBAACH,IAAI;gBAAeC,OAAO;YAAa;YACxC;gBAACD,IAAI;gBAAcC,OAAO;YAAY;SACvC;IACH;IACAF,cAAc;QACZC,IAAI;QACJC,OAAO;QACPC,eAAe;QACfC,QAAQ;YAAC;gBAACH,IAAI;gBAAoBC,OAAO;YAAkB;SAAE;IAC/D;IACAF,cAAc;QACZC,IAAI;QACJC,OAAO;QACPC,eAAe;QACfC,QAAQ;YAAC;gBAACH,IAAI;gBAAmBC,OAAO;YAAiB;SAAE;IAC7D;IACAF,cAAc;QACZC,IAAI;QACJC,OAAO;QACPC,eAAe;QACfC,QAAQ;YAAC;gBAACH,IAAI;gBAAgBC,OAAO;YAAc;SAAE;IACvD;IACAF,cAAc;QACZC,IAAI;QACJC,OAAO;QACPC,eAAe;QACfC,QAAQ;YAAC;gBAACH,IAAI;gBAAoBC,OAAO;YAAkB;SAAE;IAC/D;IACAF,cAAc;QACZC,IAAI;QACJC,OAAO;QACPC,eAAe;QACfC,QAAQ;YAAC;gBAACH,IAAI;gBAAgBC,OAAO;YAAc;SAAE;IACvD;IACAF,cAAc;QACZC,IAAI;QACJC,OAAO;QACPC,eAAe;QACfC,QAAQ;YAAC;gBAACH,IAAI;gBAAkBC,OAAO;YAAgB;SAAE;IAC3D;IACAF,cAAc;QACZC,IAAI;QACJC,OAAO;QACPC,eAAe;QACfC,QAAQ;YAAC;gBAACH,IAAI;gBAAWC,OAAO;YAAS;SAAE;IAC7C;IACAF,cAAc;QACZC,IAAI;QACJC,OAAO;QACPC,eAAe;QACfC,QAAQ;YAAC;gBAACH,IAAI;gBAAeC,OAAO;YAAa;SAAE;IACrD;IACAF,cAAc;QACZC,IAAI;QACJC,OAAO;QACPG,gBAAgB;QAChBC,mBAAmB,EAAE;QACrBC,oBAAoB;QACpBH,QAAQ,EAAE;IACZ;CACD;AAED,SAASI,6BAA6B,EAACC,QAAQ,EAAoC;IACjFpB,mBAAmB;QACjBqB,SAAS;QACTC,WAAWC,iBAAiBH;IAC9B;IAEA,MAAMI,cAAcpB,QAClB,IAAM,IAAIF,YAAY;YAACuB,gBAAgB;gBAACC,SAAS;oBAACC,OAAO;gBAAK;YAAC;QAAC,IAChE,EAAE;IAGJ,qBACE,MAACxB;QAAoByB,QAAQJ;;0BAC3B,KAACK;gBAAIC,WAAU;0BACb,cAAA,KAACtB;oBACCuB,aAAatB;oBACbuB,QAAQ,IAAMC;oBACdC,cAAc,IAAMD;;;0BAGxB,KAAChC;;;AAGP;AAEA,MAAMkC,OAAO;IACXC,OAAO;IACPC,WAAWlB;IACXmB,YAAY;QAACC,QAAQ;IAAY;IACjCC,MAAM;QAACpB,UAAU;IAAW;AAC9B;AAEA,eAAee,KAAK;AAGpB,OAAO,MAAMM,aAAoB,CAAC,EAAE;AAEpC,OAAO,MAAMC,UAAiB;IAC5BF,MAAM;QAACpB,UAAU;IAAS;IAC1BuB,MAAM,OAAO,EAACC,aAAa,EAAC;QAC1B,MAAMC,SAAStC,OAAOqC;QACtB,MAAMtC,UAAUwC,KAAK,CAACD,OAAOE,SAAS,CAAC,UAAU;YAACC,MAAM;QAAW;IACrE;AACF,EAAE;AAEF,OAAO,MAAMC,eAAsB;IACjCT,MAAM;QAACpB,UAAU;IAAe;IAChCuB,MAAM,OAAO,EAACC,aAAa,EAAC;QAC1B,MAAMC,SAAStC,OAAOqC;QACtB,MAAMtC,UAAUwC,KAAK,CAACD,OAAOE,SAAS,CAAC,UAAU;YAACC,MAAM;QAAW;IACrE;AACF,EAAE;AAEF,OAAO,MAAME,uBAA8B;IACzCV,MAAM;QAACpB,UAAU;IAAc;IAC/BuB,MAAM,OAAO,EAACC,aAAa,EAAC;QAC1B,MAAMC,SAAStC,OAAOqC;QACtB,MAAMtC,UAAUwC,KAAK,CAACD,OAAOE,SAAS,CAAC,UAAU;YAACC,MAAM;QAAW;IACrE;AACF,EAAE;AAEF,OAAO,MAAMG,YAAmB;IAC9BX,MAAM;QAACpB,UAAU;IAAY;IAC7BuB,MAAM,OAAO,EAACC,aAAa,EAAC;QAC1B,MAAMC,SAAStC,OAAOqC;QACtB,MAAMtC,UAAUwC,KAAK,CAACD,OAAOE,SAAS,CAAC,UAAU;YAACC,MAAM;QAAW;IACrE;AACF,EAAE;AAEF,OAAO,MAAMI,oBAA2B;IACtCZ,MAAM;QAACpB,UAAU;IAAW;IAC5BuB,MAAM,OAAO,EAACC,aAAa,EAAC;QAC1B,MAAMC,SAAStC,OAAOqC;QACtB,MAAMtC,UAAUwC,KAAK,CAACD,OAAOE,SAAS,CAAC,UAAU;YAACC,MAAM;QAAW;QACnE,MAAM1C,UAAU+C,IAAI,CAClB,MAAMR,OAAOS,UAAU,CAAC,aAAa;YAACN,MAAM;QAAkB,IAC9D;QAEF,MAAMH,OAAOS,UAAU,CAAC,UAAU;YAACN,MAAM;QAAsB;IACjE;AACF,EAAE;AAEF,OAAO,MAAMO,sBAA6B;IACxCf,MAAM;QAACpB,UAAU;IAAW;IAC5BuB,MAAM,OAAO,EAACC,aAAa,EAAC;QAC1B,MAAMC,SAAStC,OAAOqC;QACtB,MAAMtC,UAAUwC,KAAK,CAACD,OAAOE,SAAS,CAAC,UAAU;YAACC,MAAM;QAAW;QACnE,MAAM1C,UAAU+C,IAAI,CAClB,MAAMR,OAAOS,UAAU,CAAC,aAAa;YAACN,MAAM;QAAkB,IAC9D;QAEF,MAAMH,OAAOS,UAAU,CAAC,UAAU;YAACN,MAAM;QAAc;IACzD;AACF,EAAE;AAEF,OAAO,MAAMQ,qBAA4B;IACvChB,MAAM;QAACpB,UAAU;IAAW;IAC5BuB,MAAM,OAAO,EAACC,aAAa,EAAC;QAC1B,MAAMC,SAAStC,OAAOqC;QACtB,MAAMtC,UAAUwC,KAAK,CAACD,OAAOE,SAAS,CAAC,UAAU;YAACC,MAAM;QAAW;QACnE,MAAM1C,UAAUwC,KAAK,CAAC,MAAMD,OAAOS,UAAU,CAAC,UAAU;YAACN,MAAM;QAAqB;QACpF,MAAM3C,OAAOoD,eAAe,CAAC;IAC/B;AACF,EAAE;AAEF,SAASlC,iBAAiBH,QAAkB;IAC1C,OAAO,CAACsC;QACN,MAAMC,MAAMC,WAAWF;QACvB,MAAMG,UAAUH,iBAAiBI,UAAUJ,QAAQzB;QACnD,IAAIb,aAAa,WAAW,OAAO,IAAI2C,QAAkB,IAAM9B;QAC/D,IAAI0B,IAAIK,QAAQ,CAACC,QAAQ,CAAC,kCAAkC;YAC1D,IAAI7C,aAAa,iBAAiB,OAAO2C,QAAQG,OAAO,CAACC;YACzD,OAAOJ,QAAQG,OAAO,CAACE,aAAa;gBAACC,WAAWC,mBAAmBlD;YAAS;QAC9E;QACA,IAAIyC,SAASU,WAAW,SAASZ,IAAIK,QAAQ,CAACQ,QAAQ,CAAC,4BAA4B;YACjF,OAAOT,QAAQG,OAAO,CACpBE,aACEK,eAAe;gBACbC,aAAaf,IAAIK,QAAQ,CAACC,QAAQ,CAAC,aAAa,WAAW;YAC7D;QAGN;QACA,OAAOF,QAAQG,OAAO,CAACE,aAAa,CAAC,GAAG;YAACO,QAAQ;QAAG;IACtD;AACF;AAEA,SAASL,mBAAmBlD,QAAkB;IAC5C,IAAIA,aAAa,gBAAgB,OAAO,EAAE;IAC1C,IAAIA,aAAa,cAAc,OAAOV;IACtC,OAAO;QACLC,cAAc;YACZC,IAAI;YACJC,OAAO;YACPC,eAAe;QACjB;QACAH,cAAc;YACZC,IAAI;YACJC,OAAO;YACPC,eAAe;YACfC,QAAQ;gBAAC;oBAACH,IAAI;oBAAeC,OAAO;gBAAa;aAAE;QACrD;KACD;AACH;AAEA,SAASF,cACPiE,YAAmD,CAAC,CAAC;IAErD,OAAO;QACLhE,IAAI;QACJC,OAAO;QACPG,gBAAgB;QAChBF,eAAe;QACfG,mBAAmB;YAAC;gBAAC4D,KAAK;gBAAWhE,OAAO;gBAAWiE,QAAQ;YAAI;SAAE;QACrE5D,oBAAoB;QACpBH,QAAQ;YAAC;gBAACH,IAAI;gBAAmBC,OAAO;YAAiB;SAAE;QAC3D,GAAG+D,SAAS;IACd;AACF;AAEA,SAASH,eACPG,YAA2D,CAAC,CAAC;IAE7D,OAAO;QACLG,MAAM;QACNL,aAAa;QACb5D,eAAe;QACfkE,YAAY;QACZC,YAAY;QACZ,GAAGL,SAAS;IACd;AACF;AAEA,SAAShB,WAAWF,KAAwB;IAC1C,IAAI,OAAOA,UAAU,UAAU,OAAO,IAAIwB,IAAIxB;IAC9C,IAAIA,iBAAiBwB,KAAK,OAAOxB;IACjC,OAAO,IAAIwB,IAAIxB,MAAMC,GAAG;AAC1B;AAEA,SAASS,aAAae,IAAa,EAAEC,OAAqB,CAAC,CAAC;IAC1D,OAAO,IAAIC,SAASC,KAAKC,SAAS,CAACJ,OAAO;QACxCR,QAAQ;QACRa,SAAS;YAAC,gBAAgB;QAAkB;QAC5C,GAAGJ,IAAI;IACT;AACF;AAEA,SAASjB;IACP,OAAOC,aAAa;QAACqB,MAAM;IAAc,GAAG;QAACd,QAAQ;QAAKe,YAAY;IAAc;AACtF"}
|
|
1
|
+
{"version":3,"sources":["../../src/pages/model-provider-onboarding-page.stories.tsx"],"sourcesContent":["import type {ModelProviderCatalogEntryDto, ModelProviderConfigDto} from '@shipfox/api-agent-dto';\nimport {configureApiClient} from '@shipfox/client-api';\nimport {Toaster} from '@shipfox/react-ui/toast';\nimport type {Meta, StoryObj} from '@storybook/react';\nimport {QueryClient, QueryClientProvider} from '@tanstack/react-query';\nimport {useMemo} from 'react';\nimport {screen, userEvent, within} from 'storybook/test';\nimport {ModelProviderOnboardingPage} from './model-provider-onboarding-page.js';\n\nconst WORKSPACE_ID = '11111111-1111-4111-8111-111111111111';\n\ntype Scenario = 'available' | 'loading' | 'catalog-error' | 'no-providers' | 'long-names';\n\ninterface ModelProviderOnboardingStoryProps {\n scenario: Scenario;\n}\n\nconst CATALOG: ModelProviderCatalogEntryDto[] = [\n providerEntry({\n id: 'anthropic',\n label: 'Anthropic',\n default_model: 'claude-opus-4-8',\n models: [\n {id: 'claude-opus-4-8', label: 'Claude Opus 4.8'},\n {id: 'claude-haiku-4-5', label: 'Claude Haiku 4.5'},\n ],\n }),\n providerEntry({\n id: 'openai',\n label: 'OpenAI',\n default_model: 'gpt-5.5-pro',\n models: [\n {id: 'gpt-5.5-pro', label: 'GPT-5.5 Pro'},\n {id: 'gpt-5-mini', label: 'GPT-5 Mini'},\n ],\n }),\n providerEntry({\n id: 'xai',\n label: 'xAI',\n default_model: 'grok-code-fast-1',\n models: [{id: 'grok-code-fast-1', label: 'Grok Code Fast 1'}],\n }),\n providerEntry({\n id: 'openrouter',\n label: 'OpenRouter',\n default_model: 'openrouter/auto',\n models: [{id: 'openrouter/auto', label: 'OpenRouter Auto'}],\n }),\n providerEntry({\n id: 'google',\n label: 'Google Gemini',\n default_model: 'gemini-3-pro',\n models: [{id: 'gemini-3-pro', label: 'Gemini 3 Pro'}],\n }),\n providerEntry({\n id: 'mistral',\n label: 'Mistral AI',\n default_model: 'codestral-latest',\n models: [{id: 'codestral-latest', label: 'Codestral Latest'}],\n }),\n providerEntry({\n id: 'groq',\n label: 'Groq',\n default_model: 'llama-4-fast',\n models: [{id: 'llama-4-fast', label: 'Llama 4 Fast'}],\n }),\n providerEntry({\n id: 'deepseek',\n label: 'DeepSeek',\n default_model: 'deepseek-coder',\n models: [{id: 'deepseek-coder', label: 'DeepSeek Coder'}],\n }),\n providerEntry({\n id: 'moonshotai',\n label: 'Moonshot AI',\n default_model: 'kimi-k2',\n models: [{id: 'kimi-k2', label: 'Kimi K2'}],\n }),\n providerEntry({\n id: 'azure-openai-responses',\n label: 'Azure OpenAI Responses',\n default_model: 'gpt-5.5-pro',\n models: [{id: 'gpt-5.5-pro', label: 'GPT-5.5 Pro'}],\n }),\n providerEntry({\n id: 'amazon-bedrock',\n label: 'Amazon Bedrock',\n support_status: 'unsupported',\n credential_fields: [],\n unsupported_reason: 'AWS cloud credentials are not supported yet.',\n models: [],\n }),\n];\n\nfunction ModelProviderOnboardingStory({scenario}: ModelProviderOnboardingStoryProps) {\n configureApiClient({\n baseUrl: 'https://api.example.test',\n fetchImpl: fetchForScenario(scenario),\n });\n\n const queryClient = useMemo(\n () => new QueryClient({defaultOptions: {queries: {retry: false}}}),\n [],\n );\n\n return (\n <QueryClientProvider client={queryClient}>\n <div className=\"bg-background-subtle-base px-24 py-32\">\n <ModelProviderOnboardingPage\n workspaceId={WORKSPACE_ID}\n onSkip={() => undefined}\n onConfigured={() => undefined}\n />\n </div>\n <Toaster />\n </QueryClientProvider>\n );\n}\n\nconst meta = {\n title: 'Agent/ProviderOnboarding',\n component: ModelProviderOnboardingStory,\n parameters: {layout: 'fullscreen'},\n args: {scenario: 'available'},\n} satisfies Meta<typeof ModelProviderOnboardingStory>;\n\nexport default meta;\ntype Story = StoryObj<typeof meta>;\n\nexport const Playground: Story = {};\n\nexport const Loading: Story = {\n args: {scenario: 'loading'},\n};\n\nexport const CatalogError: Story = {\n args: {scenario: 'catalog-error'},\n};\n\nexport const NoProvidersAvailable: Story = {\n args: {scenario: 'no-providers'},\n play: async ({canvasElement}) => {\n const canvas = within(canvasElement);\n await userEvent.click(await canvas.findByRole('button', {name: 'Choose pi'}));\n },\n};\n\nexport const LongNames: Story = {\n args: {scenario: 'long-names'},\n play: async ({canvasElement}) => {\n const canvas = within(canvasElement);\n await userEvent.click(await canvas.findByRole('button', {name: 'Choose pi'}));\n },\n};\n\nexport const FilteredProviders: Story = {\n args: {scenario: 'available'},\n play: async ({canvasElement}) => {\n const canvas = within(canvasElement);\n await userEvent.click(await canvas.findByRole('button', {name: 'Choose pi'}));\n await userEvent.type(\n await canvas.findByRole('searchbox', {name: 'Search providers'}),\n 'openrouter',\n );\n await canvas.findByRole('button', {name: 'Configure OpenRouter'});\n },\n};\n\nexport const NoMatchingProviders: Story = {\n args: {scenario: 'available'},\n play: async ({canvasElement}) => {\n const canvas = within(canvasElement);\n await userEvent.click(await canvas.findByRole('button', {name: 'Choose pi'}));\n await userEvent.type(\n await canvas.findByRole('searchbox', {name: 'Search providers'}),\n 'not-a-provider',\n );\n await canvas.findByRole('button', {name: 'Clear search'});\n },\n};\n\nexport const ConfigureModalOpen: Story = {\n args: {scenario: 'available'},\n play: async ({canvasElement}) => {\n const canvas = within(canvasElement);\n await userEvent.click(await canvas.findByRole('button', {name: 'Choose pi'}));\n await userEvent.click(await canvas.findByRole('button', {name: 'Configure Anthropic'}));\n await screen.findByLabelText('API key');\n },\n};\n\nfunction fetchForScenario(scenario: Scenario): typeof fetch {\n return (input) => {\n const url = requestUrl(input);\n const request = input instanceof Request ? input : undefined;\n if (scenario === 'loading') return new Promise<Response>(() => undefined);\n if (url.pathname.endsWith('/agent/model-provider-catalog')) {\n if (scenario === 'catalog-error') return Promise.resolve(errorResponse());\n return Promise.resolve(\n jsonResponse({\n providers: catalogForScenario(scenario),\n }),\n );\n }\n if (request?.method === 'PUT' && url.pathname.includes('/agent/model-providers/')) {\n return Promise.resolve(\n jsonResponse(\n providerConfig({\n provider_id: url.pathname.endsWith('/openai') ? 'openai' : 'anthropic',\n }),\n ),\n );\n }\n return Promise.resolve(jsonResponse({}, {status: 404}));\n };\n}\n\nfunction catalogForScenario(scenario: Scenario): ModelProviderCatalogEntryDto[] {\n if (scenario === 'no-providers') return [];\n if (scenario !== 'long-names') return CATALOG;\n return [\n providerEntry({\n id: 'anthropic',\n label: 'Anthropic Enterprise Production Claude Provider With Long Label',\n default_model: 'claude-opus-4-8',\n }),\n providerEntry({\n id: 'openai',\n label: 'OpenAI Platform Shared Workspace Credentials With Long Label',\n default_model: 'gpt-5.5-pro',\n models: [{id: 'gpt-5.5-pro', label: 'GPT-5.5 Pro'}],\n }),\n ];\n}\n\nfunction providerEntry(\n overrides: Partial<ModelProviderCatalogEntryDto> = {},\n): ModelProviderCatalogEntryDto {\n return {\n id: 'anthropic',\n label: 'Anthropic',\n support_status: 'supported',\n default_model: null,\n credential_fields: [{key: 'api_key', label: 'API key', secret: true}],\n unsupported_reason: null,\n models: [{id: 'claude-opus-4-8', label: 'Claude Opus 4.8'}],\n ...overrides,\n };\n}\n\nfunction providerConfig(\n overrides: Partial<Omit<ModelProviderConfigDto, 'kind'>> = {},\n): ModelProviderConfigDto {\n return {\n kind: 'builtin',\n provider_id: 'anthropic',\n default_model: null,\n created_at: '2026-05-08T00:00:00.000Z',\n updated_at: '2026-05-08T00:00:00.000Z',\n ...overrides,\n };\n}\n\nfunction requestUrl(input: RequestInfo | URL): URL {\n if (typeof input === 'string') return new URL(input);\n if (input instanceof URL) return input;\n return new URL(input.url);\n}\n\nfunction jsonResponse(body: unknown, init: ResponseInit = {}) {\n return new Response(JSON.stringify(body), {\n status: 200,\n headers: {'content-type': 'application/json'},\n ...init,\n });\n}\n\nfunction errorResponse() {\n return jsonResponse({code: 'server-error'}, {status: 500, statusText: 'Server error'});\n}\n"],"names":["configureApiClient","Toaster","QueryClient","QueryClientProvider","useMemo","screen","userEvent","within","ModelProviderOnboardingPage","WORKSPACE_ID","CATALOG","providerEntry","id","label","default_model","models","support_status","credential_fields","unsupported_reason","ModelProviderOnboardingStory","scenario","baseUrl","fetchImpl","fetchForScenario","queryClient","defaultOptions","queries","retry","client","div","className","workspaceId","onSkip","undefined","onConfigured","meta","title","component","parameters","layout","args","Playground","Loading","CatalogError","NoProvidersAvailable","play","canvasElement","canvas","click","findByRole","name","LongNames","FilteredProviders","type","NoMatchingProviders","ConfigureModalOpen","findByLabelText","input","url","requestUrl","request","Request","Promise","pathname","endsWith","resolve","errorResponse","jsonResponse","providers","catalogForScenario","method","includes","providerConfig","provider_id","status","overrides","key","secret","kind","created_at","updated_at","URL","body","init","Response","JSON","stringify","headers","code","statusText"],"mappings":";AACA,SAAQA,kBAAkB,QAAO,sBAAsB;AACvD,SAAQC,OAAO,QAAO,0BAA0B;AAEhD,SAAQC,WAAW,EAAEC,mBAAmB,QAAO,wBAAwB;AACvE,SAAQC,OAAO,QAAO,QAAQ;AAC9B,SAAQC,MAAM,EAAEC,SAAS,EAAEC,MAAM,QAAO,iBAAiB;AACzD,SAAQC,2BAA2B,QAAO,sCAAsC;AAEhF,MAAMC,eAAe;AAQrB,MAAMC,UAA0C;IAC9CC,cAAc;QACZC,IAAI;QACJC,OAAO;QACPC,eAAe;QACfC,QAAQ;YACN;gBAACH,IAAI;gBAAmBC,OAAO;YAAiB;YAChD;gBAACD,IAAI;gBAAoBC,OAAO;YAAkB;SACnD;IACH;IACAF,cAAc;QACZC,IAAI;QACJC,OAAO;QACPC,eAAe;QACfC,QAAQ;YACN;gBAACH,IAAI;gBAAeC,OAAO;YAAa;YACxC;gBAACD,IAAI;gBAAcC,OAAO;YAAY;SACvC;IACH;IACAF,cAAc;QACZC,IAAI;QACJC,OAAO;QACPC,eAAe;QACfC,QAAQ;YAAC;gBAACH,IAAI;gBAAoBC,OAAO;YAAkB;SAAE;IAC/D;IACAF,cAAc;QACZC,IAAI;QACJC,OAAO;QACPC,eAAe;QACfC,QAAQ;YAAC;gBAACH,IAAI;gBAAmBC,OAAO;YAAiB;SAAE;IAC7D;IACAF,cAAc;QACZC,IAAI;QACJC,OAAO;QACPC,eAAe;QACfC,QAAQ;YAAC;gBAACH,IAAI;gBAAgBC,OAAO;YAAc;SAAE;IACvD;IACAF,cAAc;QACZC,IAAI;QACJC,OAAO;QACPC,eAAe;QACfC,QAAQ;YAAC;gBAACH,IAAI;gBAAoBC,OAAO;YAAkB;SAAE;IAC/D;IACAF,cAAc;QACZC,IAAI;QACJC,OAAO;QACPC,eAAe;QACfC,QAAQ;YAAC;gBAACH,IAAI;gBAAgBC,OAAO;YAAc;SAAE;IACvD;IACAF,cAAc;QACZC,IAAI;QACJC,OAAO;QACPC,eAAe;QACfC,QAAQ;YAAC;gBAACH,IAAI;gBAAkBC,OAAO;YAAgB;SAAE;IAC3D;IACAF,cAAc;QACZC,IAAI;QACJC,OAAO;QACPC,eAAe;QACfC,QAAQ;YAAC;gBAACH,IAAI;gBAAWC,OAAO;YAAS;SAAE;IAC7C;IACAF,cAAc;QACZC,IAAI;QACJC,OAAO;QACPC,eAAe;QACfC,QAAQ;YAAC;gBAACH,IAAI;gBAAeC,OAAO;YAAa;SAAE;IACrD;IACAF,cAAc;QACZC,IAAI;QACJC,OAAO;QACPG,gBAAgB;QAChBC,mBAAmB,EAAE;QACrBC,oBAAoB;QACpBH,QAAQ,EAAE;IACZ;CACD;AAED,SAASI,6BAA6B,EAACC,QAAQ,EAAoC;IACjFpB,mBAAmB;QACjBqB,SAAS;QACTC,WAAWC,iBAAiBH;IAC9B;IAEA,MAAMI,cAAcpB,QAClB,IAAM,IAAIF,YAAY;YAACuB,gBAAgB;gBAACC,SAAS;oBAACC,OAAO;gBAAK;YAAC;QAAC,IAChE,EAAE;IAGJ,qBACE,MAACxB;QAAoByB,QAAQJ;;0BAC3B,KAACK;gBAAIC,WAAU;0BACb,cAAA,KAACtB;oBACCuB,aAAatB;oBACbuB,QAAQ,IAAMC;oBACdC,cAAc,IAAMD;;;0BAGxB,KAAChC;;;AAGP;AAEA,MAAMkC,OAAO;IACXC,OAAO;IACPC,WAAWlB;IACXmB,YAAY;QAACC,QAAQ;IAAY;IACjCC,MAAM;QAACpB,UAAU;IAAW;AAC9B;AAEA,eAAee,KAAK;AAGpB,OAAO,MAAMM,aAAoB,CAAC,EAAE;AAEpC,OAAO,MAAMC,UAAiB;IAC5BF,MAAM;QAACpB,UAAU;IAAS;AAC5B,EAAE;AAEF,OAAO,MAAMuB,eAAsB;IACjCH,MAAM;QAACpB,UAAU;IAAe;AAClC,EAAE;AAEF,OAAO,MAAMwB,uBAA8B;IACzCJ,MAAM;QAACpB,UAAU;IAAc;IAC/ByB,MAAM,OAAO,EAACC,aAAa,EAAC;QAC1B,MAAMC,SAASxC,OAAOuC;QACtB,MAAMxC,UAAU0C,KAAK,CAAC,MAAMD,OAAOE,UAAU,CAAC,UAAU;YAACC,MAAM;QAAW;IAC5E;AACF,EAAE;AAEF,OAAO,MAAMC,YAAmB;IAC9BX,MAAM;QAACpB,UAAU;IAAY;IAC7ByB,MAAM,OAAO,EAACC,aAAa,EAAC;QAC1B,MAAMC,SAASxC,OAAOuC;QACtB,MAAMxC,UAAU0C,KAAK,CAAC,MAAMD,OAAOE,UAAU,CAAC,UAAU;YAACC,MAAM;QAAW;IAC5E;AACF,EAAE;AAEF,OAAO,MAAME,oBAA2B;IACtCZ,MAAM;QAACpB,UAAU;IAAW;IAC5ByB,MAAM,OAAO,EAACC,aAAa,EAAC;QAC1B,MAAMC,SAASxC,OAAOuC;QACtB,MAAMxC,UAAU0C,KAAK,CAAC,MAAMD,OAAOE,UAAU,CAAC,UAAU;YAACC,MAAM;QAAW;QAC1E,MAAM5C,UAAU+C,IAAI,CAClB,MAAMN,OAAOE,UAAU,CAAC,aAAa;YAACC,MAAM;QAAkB,IAC9D;QAEF,MAAMH,OAAOE,UAAU,CAAC,UAAU;YAACC,MAAM;QAAsB;IACjE;AACF,EAAE;AAEF,OAAO,MAAMI,sBAA6B;IACxCd,MAAM;QAACpB,UAAU;IAAW;IAC5ByB,MAAM,OAAO,EAACC,aAAa,EAAC;QAC1B,MAAMC,SAASxC,OAAOuC;QACtB,MAAMxC,UAAU0C,KAAK,CAAC,MAAMD,OAAOE,UAAU,CAAC,UAAU;YAACC,MAAM;QAAW;QAC1E,MAAM5C,UAAU+C,IAAI,CAClB,MAAMN,OAAOE,UAAU,CAAC,aAAa;YAACC,MAAM;QAAkB,IAC9D;QAEF,MAAMH,OAAOE,UAAU,CAAC,UAAU;YAACC,MAAM;QAAc;IACzD;AACF,EAAE;AAEF,OAAO,MAAMK,qBAA4B;IACvCf,MAAM;QAACpB,UAAU;IAAW;IAC5ByB,MAAM,OAAO,EAACC,aAAa,EAAC;QAC1B,MAAMC,SAASxC,OAAOuC;QACtB,MAAMxC,UAAU0C,KAAK,CAAC,MAAMD,OAAOE,UAAU,CAAC,UAAU;YAACC,MAAM;QAAW;QAC1E,MAAM5C,UAAU0C,KAAK,CAAC,MAAMD,OAAOE,UAAU,CAAC,UAAU;YAACC,MAAM;QAAqB;QACpF,MAAM7C,OAAOmD,eAAe,CAAC;IAC/B;AACF,EAAE;AAEF,SAASjC,iBAAiBH,QAAkB;IAC1C,OAAO,CAACqC;QACN,MAAMC,MAAMC,WAAWF;QACvB,MAAMG,UAAUH,iBAAiBI,UAAUJ,QAAQxB;QACnD,IAAIb,aAAa,WAAW,OAAO,IAAI0C,QAAkB,IAAM7B;QAC/D,IAAIyB,IAAIK,QAAQ,CAACC,QAAQ,CAAC,kCAAkC;YAC1D,IAAI5C,aAAa,iBAAiB,OAAO0C,QAAQG,OAAO,CAACC;YACzD,OAAOJ,QAAQG,OAAO,CACpBE,aAAa;gBACXC,WAAWC,mBAAmBjD;YAChC;QAEJ;QACA,IAAIwC,SAASU,WAAW,SAASZ,IAAIK,QAAQ,CAACQ,QAAQ,CAAC,4BAA4B;YACjF,OAAOT,QAAQG,OAAO,CACpBE,aACEK,eAAe;gBACbC,aAAaf,IAAIK,QAAQ,CAACC,QAAQ,CAAC,aAAa,WAAW;YAC7D;QAGN;QACA,OAAOF,QAAQG,OAAO,CAACE,aAAa,CAAC,GAAG;YAACO,QAAQ;QAAG;IACtD;AACF;AAEA,SAASL,mBAAmBjD,QAAkB;IAC5C,IAAIA,aAAa,gBAAgB,OAAO,EAAE;IAC1C,IAAIA,aAAa,cAAc,OAAOV;IACtC,OAAO;QACLC,cAAc;YACZC,IAAI;YACJC,OAAO;YACPC,eAAe;QACjB;QACAH,cAAc;YACZC,IAAI;YACJC,OAAO;YACPC,eAAe;YACfC,QAAQ;gBAAC;oBAACH,IAAI;oBAAeC,OAAO;gBAAa;aAAE;QACrD;KACD;AACH;AAEA,SAASF,cACPgE,YAAmD,CAAC,CAAC;IAErD,OAAO;QACL/D,IAAI;QACJC,OAAO;QACPG,gBAAgB;QAChBF,eAAe;QACfG,mBAAmB;YAAC;gBAAC2D,KAAK;gBAAW/D,OAAO;gBAAWgE,QAAQ;YAAI;SAAE;QACrE3D,oBAAoB;QACpBH,QAAQ;YAAC;gBAACH,IAAI;gBAAmBC,OAAO;YAAiB;SAAE;QAC3D,GAAG8D,SAAS;IACd;AACF;AAEA,SAASH,eACPG,YAA2D,CAAC,CAAC;IAE7D,OAAO;QACLG,MAAM;QACNL,aAAa;QACb3D,eAAe;QACfiE,YAAY;QACZC,YAAY;QACZ,GAAGL,SAAS;IACd;AACF;AAEA,SAAShB,WAAWF,KAAwB;IAC1C,IAAI,OAAOA,UAAU,UAAU,OAAO,IAAIwB,IAAIxB;IAC9C,IAAIA,iBAAiBwB,KAAK,OAAOxB;IACjC,OAAO,IAAIwB,IAAIxB,MAAMC,GAAG;AAC1B;AAEA,SAASS,aAAae,IAAa,EAAEC,OAAqB,CAAC,CAAC;IAC1D,OAAO,IAAIC,SAASC,KAAKC,SAAS,CAACJ,OAAO;QACxCR,QAAQ;QACRa,SAAS;YAAC,gBAAgB;QAAkB;QAC5C,GAAGJ,IAAI;IACT;AACF;AAEA,SAASjB;IACP,OAAOC,aAAa;QAACqB,MAAM;IAAc,GAAG;QAACd,QAAQ;QAAKe,YAAY;IAAc;AACtF"}
|