@undefineds.co/xpod 0.4.10 → 0.4.12
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/config/components-ignore.json +5 -1
- package/config/notifications.json +68 -0
- package/config/xpod.base.json +9 -11
- package/dist/ai/service/AiCredentialSecret.d.ts +30 -0
- package/dist/ai/service/AiCredentialSecret.js +120 -0
- package/dist/ai/service/CredentialReaderImpl.d.ts +18 -0
- package/dist/ai/service/CredentialReaderImpl.js +81 -5
- package/dist/ai/service/CredentialReaderImpl.jsonld +42 -2
- package/dist/ai/service/EmbeddingModelPolicy.d.ts +79 -0
- package/dist/ai/service/EmbeddingModelPolicy.js +134 -0
- package/dist/ai/service/EmbeddingProviderError.js +6 -0
- package/dist/ai/service/EmbeddingServiceImpl.d.ts +13 -1
- package/dist/ai/service/EmbeddingServiceImpl.js +18 -5
- package/dist/ai/service/EmbeddingServiceImpl.jsonld +35 -0
- package/dist/ai/service/index.d.ts +2 -0
- package/dist/ai/service/index.js +2 -0
- package/dist/api/ai-gateway/connect/index.d.ts +20 -2
- package/dist/api/ai-gateway/connect/index.js +162 -16
- package/dist/api/ai-gateway/credentials/AiCredentialSecretDecoder.d.ts +12 -0
- package/dist/api/ai-gateway/credentials/AiCredentialSecretDecoder.js +30 -0
- package/dist/api/ai-gateway/errors.d.ts +1 -1
- package/dist/api/ai-gateway/models/GatewayEmbeddingModelCatalog.d.ts +11 -0
- package/dist/api/ai-gateway/models/GatewayEmbeddingModelCatalog.js +31 -0
- package/dist/api/ai-gateway/models/PodModelSelectionRepository.js +7 -3
- package/dist/api/ai-gateway/models/ProviderCustomModelsService.d.ts +18 -0
- package/dist/api/ai-gateway/models/ProviderCustomModelsService.js +23 -0
- package/dist/api/ai-gateway/models/ProviderModelDiscoveryAdapters.d.ts +3 -1
- package/dist/api/ai-gateway/models/ProviderModelDiscoveryAdapters.js +2 -45
- package/dist/api/ai-gateway/models/ProviderModelSelectionService.d.ts +10 -0
- package/dist/api/ai-gateway/models/ProviderModelSelectionService.js +57 -20
- package/dist/api/ai-gateway/models/ProviderModelType.d.ts +28 -0
- package/dist/api/ai-gateway/models/ProviderModelType.js +34 -0
- package/dist/api/ai-gateway/models/ProviderModelsAdapter.d.ts +10 -0
- package/dist/api/ai-gateway/models/ProviderModelsAdapter.js +3 -4
- package/dist/api/ai-gateway/models/index.d.ts +1 -0
- package/dist/api/ai-gateway/models/index.js +3 -1
- package/dist/api/ai-gateway/providers/CustomRuntimeAdapter.d.ts +7 -0
- package/dist/api/ai-gateway/providers/CustomRuntimeAdapter.js +9 -2
- package/dist/api/ai-gateway/providers/ModelsDevCatalog.d.ts +7 -1
- package/dist/api/ai-gateway/providers/ModelsDevCatalog.js +4 -10
- package/dist/api/ai-gateway/providers/ProviderRegistry.d.ts +107 -0
- package/dist/api/ai-gateway/providers/ProviderRegistry.js +244 -21
- package/dist/api/ai-gateway/providers/ProviderRuntimeRegistry.d.ts +5 -0
- package/dist/api/ai-gateway/providers/ProviderRuntimeRegistry.js +5 -1
- package/dist/api/ai-gateway/quota/SubscriptionQuotaAdapters.d.ts +12 -4
- package/dist/api/ai-gateway/quota/SubscriptionQuotaAdapters.js +11 -11
- package/dist/api/ai-gateway/routing/ModelRouter.d.ts +14 -0
- package/dist/api/ai-gateway/routing/ModelRouter.js +43 -4
- package/dist/api/ai-gateway/service-access/AiConnectionsServiceAccess.d.ts +9 -1
- package/dist/api/ai-gateway/service-access/AiConnectionsServiceAccess.js +3 -27
- package/dist/api/auth/ClientCredentialsAuthenticator.d.ts +0 -1
- package/dist/api/auth/ClientCredentialsAuthenticator.js +0 -3
- package/dist/api/auth/index.d.ts +1 -0
- package/dist/api/auth/index.js +1 -1
- package/dist/api/chatkit/pod-store.d.ts +31 -0
- package/dist/api/chatkit/pod-store.js +132 -8
- package/dist/api/container/common.js +24 -4
- package/dist/api/container/routes.js +17 -2
- package/dist/api/container/types.d.ts +3 -1
- package/dist/api/handlers/AdminHandler.d.ts +13 -0
- package/dist/api/handlers/AdminHandler.js +47 -18
- package/dist/api/handlers/AiConfigHandler.d.ts +6 -0
- package/dist/api/handlers/AiConfigHandler.js +28 -0
- package/dist/api/handlers/AiGatewayManagementHandler.js +36 -0
- package/dist/api/runs/RdfRunContextRetriever.d.ts +14 -0
- package/dist/api/runs/RdfRunContextRetriever.js +41 -5
- package/dist/api/runtime.js +2 -1
- package/dist/cli/commands/secret.d.ts +1 -0
- package/dist/cli/commands/secret.js +25 -7
- package/dist/components/components.jsonld +3 -1
- package/dist/components/context.jsonld +53 -1
- package/dist/http/SubgraphSparqlHttpHandler.d.ts +59 -2
- package/dist/http/SubgraphSparqlHttpHandler.js +145 -13
- package/dist/http/SubgraphSparqlHttpHandler.jsonld +37 -0
- package/dist/identity/drizzle/AccountRoleRepository.d.ts +30 -2
- package/dist/identity/drizzle/AccountRoleRepository.js +163 -15
- package/dist/identity/drizzle/EdgeNodeRepository.d.ts +0 -12
- package/dist/identity/drizzle/EdgeNodeRepository.js +5 -13
- package/dist/identity/drizzle/PodLookupRepository.d.ts +58 -4
- package/dist/identity/drizzle/PodLookupRepository.js +248 -105
- package/dist/identity/drizzle/db.d.ts +19 -0
- package/dist/identity/drizzle/db.js +39 -4
- package/dist/index.d.ts +2 -1
- package/dist/index.js +7 -3
- package/dist/logging/log-file.d.ts +17 -0
- package/dist/logging/log-file.js +69 -0
- package/dist/main.js +2 -1
- package/dist/notifications/NotificationChannelSweeper.d.ts +50 -0
- package/dist/notifications/NotificationChannelSweeper.js +131 -0
- package/dist/notifications/NotificationChannelSweeper.jsonld +136 -0
- package/dist/notifications/ReclaimingWebSocket2023Storer.d.ts +25 -0
- package/dist/notifications/ReclaimingWebSocket2023Storer.js +56 -0
- package/dist/notifications/ReclaimingWebSocket2023Storer.jsonld +77 -0
- package/dist/notifications/index.d.ts +2 -0
- package/dist/notifications/index.js +2 -0
- package/dist/runtime/Proxy.d.ts +37 -0
- package/dist/runtime/Proxy.js +88 -16
- package/dist/runtime/bootstrap.js +2 -1
- package/dist/runtime/upgrade/BunNativeUpgradeRelay.d.ts +116 -0
- package/dist/runtime/upgrade/BunNativeUpgradeRelay.js +423 -0
- package/dist/runtime/upgrade/UpgradeHandshake.d.ts +63 -0
- package/dist/runtime/upgrade/UpgradeHandshake.js +199 -0
- package/dist/runtime/upgrade/WebSocketFrames.d.ts +67 -0
- package/dist/runtime/upgrade/WebSocketFrames.js +224 -0
- package/node_modules/@undefineds.co/ai-connections/dist/AiApiKeyPool.js +8 -1
- package/node_modules/@undefineds.co/ai-connections/dist/AiAuthorizationActions.d.ts +11 -2
- package/node_modules/@undefineds.co/ai-connections/dist/AiAuthorizationActions.js +27 -10
- package/node_modules/@undefineds.co/ai-connections/dist/AiClientConfigurationSection.d.ts +7 -0
- package/node_modules/@undefineds.co/ai-connections/dist/AiClientConfigurationSection.js +13 -11
- package/node_modules/@undefineds.co/ai-connections/dist/AiConnectDialog.js +1 -1
- package/node_modules/@undefineds.co/ai-connections/dist/AiConnectionsList.js +10 -6
- package/node_modules/@undefineds.co/ai-connections/dist/AiConnectionsMain.d.ts +15 -0
- package/node_modules/@undefineds.co/ai-connections/dist/AiConnectionsMain.js +29 -3
- package/node_modules/@undefineds.co/ai-connections/dist/AiConnectionsMainHeader.js +18 -3
- package/node_modules/@undefineds.co/ai-connections/dist/AiConnectionsPanel.d.ts +16 -1
- package/node_modules/@undefineds.co/ai-connections/dist/AiConnectionsPanel.js +92 -20
- package/node_modules/@undefineds.co/ai-connections/dist/AiCopyButton.d.ts +35 -0
- package/node_modules/@undefineds.co/ai-connections/dist/AiCopyButton.js +45 -0
- package/node_modules/@undefineds.co/ai-connections/dist/AiCredentialPoolSection.js +71 -11
- package/node_modules/@undefineds.co/ai-connections/dist/AiCredentialRow.js +9 -7
- package/node_modules/@undefineds.co/ai-connections/dist/AiEndpointList.d.ts +23 -0
- package/node_modules/@undefineds.co/ai-connections/dist/AiEndpointList.js +24 -0
- package/node_modules/@undefineds.co/ai-connections/dist/AiGatewayKeysSection.d.ts +13 -4
- package/node_modules/@undefineds.co/ai-connections/dist/AiGatewayKeysSection.js +35 -38
- package/node_modules/@undefineds.co/ai-connections/dist/AiGatewayModelsSection.d.ts +21 -0
- package/node_modules/@undefineds.co/ai-connections/dist/AiGatewayModelsSection.js +51 -0
- package/node_modules/@undefineds.co/ai-connections/dist/AiInfoTooltip.d.ts +15 -0
- package/node_modules/@undefineds.co/ai-connections/dist/AiInfoTooltip.js +16 -0
- package/node_modules/@undefineds.co/ai-connections/dist/AiModelCatalog.d.ts +175 -0
- package/node_modules/@undefineds.co/ai-connections/dist/AiModelCatalog.js +133 -0
- package/node_modules/@undefineds.co/ai-connections/dist/AiOfferingDetails.js +2 -2
- package/node_modules/@undefineds.co/ai-connections/dist/AiProviderCard.js +13 -64
- package/node_modules/@undefineds.co/ai-connections/dist/AiProviderHeader.d.ts +21 -0
- package/node_modules/@undefineds.co/ai-connections/dist/AiProviderHeader.js +12 -0
- package/node_modules/@undefineds.co/ai-connections/dist/AiRowAction.d.ts +15 -0
- package/node_modules/@undefineds.co/ai-connections/dist/AiRowAction.js +12 -0
- package/node_modules/@undefineds.co/ai-connections/dist/AiSortableCredentialList.js +2 -1
- package/node_modules/@undefineds.co/ai-connections/dist/ai-connections-client.d.ts +7 -0
- package/node_modules/@undefineds.co/ai-connections/dist/ai-connections-client.js +6 -0
- package/node_modules/@undefineds.co/ai-connections/dist/authorization-methods.d.ts +36 -5
- package/node_modules/@undefineds.co/ai-connections/dist/authorization-methods.js +52 -9
- package/node_modules/@undefineds.co/ai-connections/dist/client/normalize.js +30 -3
- package/node_modules/@undefineds.co/ai-connections/dist/client/types.d.ts +21 -1
- package/node_modules/@undefineds.co/ai-connections/dist/client-config/base-adapter.d.ts +1 -3
- package/node_modules/@undefineds.co/ai-connections/dist/client-config/base-adapter.js +3 -7
- package/node_modules/@undefineds.co/ai-connections/dist/client-config/index.cjs +9 -7
- package/node_modules/@undefineds.co/ai-connections/dist/collection-runtime.d.ts +46 -0
- package/node_modules/@undefineds.co/ai-connections/dist/collection-runtime.js +231 -0
- package/node_modules/@undefineds.co/ai-connections/dist/collections.d.ts +119 -0
- package/node_modules/@undefineds.co/ai-connections/dist/collections.js +173 -0
- package/node_modules/@undefineds.co/ai-connections/dist/controller.d.ts +71 -5
- package/node_modules/@undefineds.co/ai-connections/dist/controller.js +285 -16
- package/node_modules/@undefineds.co/ai-connections/dist/credential-labels.d.ts +5 -0
- package/node_modules/@undefineds.co/ai-connections/dist/credential-labels.js +8 -3
- package/node_modules/@undefineds.co/ai-connections/dist/credential-storage.d.ts +59 -0
- package/node_modules/@undefineds.co/ai-connections/dist/credential-storage.js +131 -0
- package/node_modules/@undefineds.co/ai-connections/dist/endpoint-urls.d.ts +15 -0
- package/node_modules/@undefineds.co/ai-connections/dist/endpoint-urls.js +20 -0
- package/node_modules/@undefineds.co/ai-connections/dist/gateway-endpoints.d.ts +14 -0
- package/node_modules/@undefineds.co/ai-connections/dist/gateway-endpoints.js +20 -0
- package/node_modules/@undefineds.co/ai-connections/dist/index.d.ts +8 -0
- package/node_modules/@undefineds.co/ai-connections/dist/index.js +8 -0
- package/node_modules/@undefineds.co/ai-connections/dist/manifest.js +1 -1
- package/node_modules/@undefineds.co/ai-connections/dist/offering-endpoints.d.ts +14 -0
- package/node_modules/@undefineds.co/ai-connections/dist/offering-endpoints.js +17 -0
- package/node_modules/@undefineds.co/ai-connections/dist/provider-catalog.cjs +68 -1
- package/node_modules/@undefineds.co/ai-connections/dist/provider-catalog.d.ts +75 -1
- package/node_modules/@undefineds.co/ai-connections/dist/provider-catalog.js +119 -0
- package/node_modules/@undefineds.co/ai-connections/dist/provider-visuals.d.ts +5 -0
- package/node_modules/@undefineds.co/ai-connections/dist/provider-visuals.js +5 -0
- package/node_modules/@undefineds.co/ai-connections/dist/service-access.js +2 -27
- package/node_modules/@undefineds.co/ai-connections/package.json +1 -0
- package/node_modules/@undefineds.co/extension-sdk/dist/manifest.d.ts +1 -1
- package/node_modules/@undefineds.co/extension-sdk/dist/manifest.js +2 -0
- package/node_modules/@undefineds.co/extension-sdk/dist/web.d.ts +150 -0
- package/node_modules/@undefineds.co/extension-sdk/package.json +2 -1
- package/node_modules/@undefineds.co/models/README.md +1 -1
- package/node_modules/@undefineds.co/models/dist/ai-config/index.d.ts +3 -3
- package/node_modules/@undefineds.co/models/dist/ai-gateway.schema.d.ts +5 -0
- package/node_modules/@undefineds.co/models/dist/ai-gateway.schema.js +9 -0
- package/node_modules/@undefineds.co/models/dist/ai-runtime.repository.d.ts +1 -1
- package/node_modules/@undefineds.co/models/dist/approval.repository.d.ts +2 -2
- package/node_modules/@undefineds.co/models/dist/audit.presentation.d.ts +2 -2
- package/node_modules/@undefineds.co/models/dist/capture.repository.d.ts +1 -1
- package/node_modules/@undefineds.co/models/dist/chat-project.repository.d.ts +1 -1
- package/node_modules/@undefineds.co/models/dist/chat.repository.d.ts +2 -2
- package/node_modules/@undefineds.co/models/dist/control-request.repository.d.ts +2 -2
- package/node_modules/@undefineds.co/models/dist/conversation-share.repository.d.ts +1 -1
- package/node_modules/@undefineds.co/models/dist/credential.schema.d.ts +12 -0
- package/node_modules/@undefineds.co/models/dist/credential.schema.js +15 -1
- package/node_modules/@undefineds.co/models/dist/discovery/index.d.ts +2 -2
- package/node_modules/@undefineds.co/models/dist/discovery/providers.json +248 -7
- package/node_modules/@undefineds.co/models/dist/discovery/types.d.ts +31 -0
- package/node_modules/@undefineds.co/models/dist/extension/index.d.ts +1 -1
- package/node_modules/@undefineds.co/models/dist/favorite/index.d.ts +2 -2
- package/node_modules/@undefineds.co/models/dist/fixtures/contracts-chat-contact.d.ts +5 -5
- package/node_modules/@undefineds.co/models/dist/import/index.d.ts +1 -1
- package/node_modules/@undefineds.co/models/dist/index.d.ts +73 -73
- package/node_modules/@undefineds.co/models/dist/index.js +1 -1
- package/node_modules/@undefineds.co/models/dist/input-request.repository.d.ts +2 -2
- package/node_modules/@undefineds.co/models/dist/knowledge/index.d.ts +1 -1
- package/node_modules/@undefineds.co/models/dist/message.repository.d.ts +1 -1
- package/node_modules/@undefineds.co/models/dist/namespaces.js +5 -0
- package/node_modules/@undefineds.co/models/dist/pod-storage-descriptor.d.ts +4815 -26
- package/node_modules/@undefineds.co/models/dist/pod-storage-descriptor.js +482 -132
- package/node_modules/@undefineds.co/models/dist/schema.d.ts +4 -0
- package/node_modules/@undefineds.co/models/dist/session/index.d.ts +1 -1
- package/node_modules/@undefineds.co/models/dist/settings/index.d.ts +1 -1
- package/node_modules/@undefineds.co/models/dist/sidecar/persistence-mapping.d.ts +5 -5
- package/node_modules/@undefineds.co/models/dist/thread.repository.d.ts +2 -2
- package/node_modules/@undefineds.co/models/dist/types/message-block.d.ts +1 -1
- package/node_modules/@undefineds.co/models/dist/vocab/_namespaces.d.ts +1 -1
- package/node_modules/@undefineds.co/models/dist/vocab/index.d.ts +10 -10
- package/node_modules/@undefineds.co/models/dist/vocab/sidecar.vocab.d.ts +1 -0
- package/node_modules/@undefineds.co/models/dist/vocab/sidecar.vocab.js +1 -0
- package/node_modules/@undefineds.co/models/package.json +4 -2
- package/node_modules/@undefineds.co/pod-collections/README.md +71 -0
- package/node_modules/@undefineds.co/pod-collections/dist/diff.d.ts +85 -0
- package/node_modules/@undefineds.co/pod-collections/dist/diff.js +166 -0
- package/node_modules/@undefineds.co/pod-collections/dist/feed.d.ts +17 -0
- package/node_modules/@undefineds.co/pod-collections/dist/feed.js +27 -0
- package/node_modules/@undefineds.co/pod-collections/dist/index.cjs +1042 -0
- package/node_modules/@undefineds.co/pod-collections/dist/index.d.ts +37 -0
- package/node_modules/@undefineds.co/pod-collections/dist/index.js +89 -0
- package/node_modules/@undefineds.co/pod-collections/dist/layout.d.ts +75 -0
- package/node_modules/@undefineds.co/pod-collections/dist/layout.js +173 -0
- package/node_modules/@undefineds.co/pod-collections/dist/mapping.d.ts +78 -0
- package/node_modules/@undefineds.co/pod-collections/dist/mapping.js +287 -0
- package/node_modules/@undefineds.co/pod-collections/dist/mutations.d.ts +83 -0
- package/node_modules/@undefineds.co/pod-collections/dist/mutations.js +273 -0
- package/node_modules/@undefineds.co/pod-collections/dist/react.d.ts +21 -0
- package/node_modules/@undefineds.co/pod-collections/dist/react.js +22 -0
- package/node_modules/@undefineds.co/pod-collections/dist/read.d.ts +65 -0
- package/node_modules/@undefineds.co/pod-collections/dist/read.js +31 -0
- package/node_modules/@undefineds.co/pod-collections/dist/sync.d.ts +66 -0
- package/node_modules/@undefineds.co/pod-collections/dist/sync.js +260 -0
- package/node_modules/@undefineds.co/pod-collections/dist/types.d.ts +155 -0
- package/node_modules/@undefineds.co/pod-collections/dist/types.js +9 -0
- package/node_modules/@undefineds.co/pod-collections/package.json +42 -0
- package/node_modules/@undefineds.co/shared-ui/dist/index.d.ts +0 -1
- package/node_modules/@undefineds.co/shared-ui/dist/index.js +0 -1
- package/package.json +15 -7
- package/static/app/assets/main.css +1 -1
- package/static/app/assets/main.js +12 -13
- package/static/auth-callback/assets/AiConfigContext-DnQs1ZpW.js +1 -0
- package/static/auth-callback/assets/AiConfigPage-DOtvlxH0.js +1 -0
- package/static/auth-callback/assets/DocumentProcessingPanel-BS2voQgL.js +1 -0
- package/static/auth-callback/assets/IndexLifecyclePanel-Cvt0cJtN.js +1 -0
- package/static/auth-callback/assets/{IndexSubjectPanel-C4YG0whI.js → IndexSubjectPanel-Dhf01GqF.js} +1 -1
- package/static/auth-callback/assets/ModelAssignmentsPanel-BJutWaAF.js +1 -0
- package/static/auth-callback/assets/ModelsPage-BRS0sje3.js +11 -0
- package/static/auth-callback/assets/{NetworkPage-Cbdn_P1e.js → NetworkPage-B3qBfANA.js} +2 -2
- package/static/auth-callback/assets/{PaneListHeader-jy70Q00L.js → PaneListHeader-QQeJGTp4.js} +1 -1
- package/static/auth-callback/assets/SearchIndexingPanel-MyNUSEwT.js +1 -0
- package/static/auth-callback/assets/{StatusSubjectPanel-hfjoB5aS.js → StatusSubjectPanel-DQkEVsFs.js} +1 -1
- package/static/{settings/assets/StatusWorkspace-CKD_Rzdr.js → auth-callback/assets/StatusWorkspace-Dkv63Uwk.js} +1 -1
- package/static/auth-callback/assets/SystemSettingsPage-TIsUfX5d.js +1 -0
- package/static/auth-callback/assets/SystemSettingsSubjectPanel-BJWEt2-7.js +33 -0
- package/static/auth-callback/assets/XpodAiConnectionsPodStore-BJiXm-PF.js +3 -0
- package/static/auth-callback/assets/{activity-BcsZZxxw.js → activity-5hNeNKnL.js} +1 -1
- package/static/auth-callback/assets/admin-C6qCRFiY.js +1 -0
- package/static/auth-callback/assets/ai-connections-CryuHGKW.js +1 -0
- package/static/auth-callback/assets/{auth-callback-atKg_oig.js → auth-callback-CAFZ3R0B.js} +80 -84
- package/static/auth-callback/assets/auth-callback-rk080mvG.css +1 -0
- package/static/auth-callback/assets/{badge-BWbRHThQ.js → badge-CAIPI0CB.js} +1 -1
- package/static/auth-callback/assets/collection-runtime-D9s7h9YA.js +1 -0
- package/static/auth-callback/assets/dialog-BjA109aX.js +1 -0
- package/static/auth-callback/assets/{download-BmvG1Vya.js → download-B3Up5W2G.js} +1 -1
- package/static/auth-callback/assets/{external-link-DZ34d3g3.js → external-link-BTXgSPzB.js} +1 -1
- package/static/auth-callback/assets/index-BppXlxcp.js +41 -0
- package/static/auth-callback/assets/index-CirW4CJf.js +1 -0
- package/static/auth-callback/assets/index-DlLYWOhw.js +4 -0
- package/static/auth-callback/assets/{index-browser-B9Z7GU-T.js → index-browser-DtU38ni3.js} +1 -1
- package/static/auth-callback/assets/{key-round-tjP76Se-.js → key-round-CQCOrZ7x.js} +1 -1
- package/static/auth-callback/assets/layout-DB3pMyTl.js +1 -0
- package/static/auth-callback/assets/pod-collections-host-KnnGFZHL.js +8 -0
- package/static/auth-callback/assets/{rotate-ccw-C_L5ZLx1.js → rotate-ccw-C1zM2KtS.js} +1 -1
- package/static/auth-callback/assets/settings-projection-CUkyprDQ.js +1 -0
- package/static/auth-callback/assets/{skeleton-C7tGDQIs.js → skeleton-Cqp7_M9-.js} +1 -1
- package/static/auth-callback/assets/{waypoints-VMNQlWdU.js → waypoints-Bj6gAUSQ.js} +1 -1
- package/static/auth-callback/assets/{workspace-layout-SAp6BtYK.js → workspace-layout-DK8mDzrY.js} +1 -1
- package/static/auth-callback/auth-callback.html +2 -2
- package/static/dashboard/assets/AiConfigContext-BsE7MqX8.js +1 -0
- package/static/dashboard/assets/AiConfigPage-DvM-lRXa.js +1 -0
- package/static/dashboard/assets/DocumentProcessingPanel-BPfdlfuf.js +1 -0
- package/static/dashboard/assets/IndexLifecyclePanel--m0AGxvh.js +1 -0
- package/static/dashboard/assets/{IndexSubjectPanel-DQFPP6-p.js → IndexSubjectPanel-Bb7m1k3d.js} +1 -1
- package/static/dashboard/assets/ModelAssignmentsPanel-BLi_zbMa.js +1 -0
- package/static/dashboard/assets/ModelsPage-CxdpgnfR.js +11 -0
- package/static/dashboard/assets/{NetworkPage-CHQ3YxIB.js → NetworkPage-BAIPw-D_.js} +2 -2
- package/static/dashboard/assets/{PaneListHeader-DsXemAdR.js → PaneListHeader-BBCMei0r.js} +1 -1
- package/static/dashboard/assets/SearchIndexingPanel-Ck4Y-xjR.js +1 -0
- package/static/dashboard/assets/{StatusSubjectPanel-D3PGEYT4.js → StatusSubjectPanel-D1KWfAXE.js} +1 -1
- package/static/dashboard/assets/{StatusWorkspace-BcpePYUW.js → StatusWorkspace-JbA5gzXx.js} +1 -1
- package/static/dashboard/assets/SystemSettingsPage-BbwQWsSR.js +1 -0
- package/static/dashboard/assets/SystemSettingsSubjectPanel-N117nMt5.js +33 -0
- package/static/dashboard/assets/XpodAiConnectionsPodStore-CdDOb4SV.js +18 -0
- package/static/dashboard/assets/{activity-j5zrznu-.js → activity-DX1I96o_.js} +1 -1
- package/static/dashboard/assets/admin-C6qCRFiY.js +1 -0
- package/static/dashboard/assets/ai-connections-DwCRqOQa.js +1 -0
- package/static/dashboard/assets/{badge-CzeBdG7h.js → badge-k2vhtDqH.js} +1 -1
- package/static/dashboard/assets/collection-runtime-BFQ8teQJ.js +1 -0
- package/static/dashboard/assets/{dashboard-D-xANHk1.js → dashboard-DWZ-fmCT.js} +105 -109
- package/static/dashboard/assets/dashboard-rk080mvG.css +1 -0
- package/static/dashboard/assets/dialog-1CCw-iHT.js +1 -0
- package/static/dashboard/assets/{download-IcNdEZWi.js → download-C6-SNY1q.js} +1 -1
- package/static/dashboard/assets/{external-link-DxBxK8Vu.js → external-link-BgPcZ_j2.js} +1 -1
- package/static/dashboard/assets/index-6LcIUIYO.js +1 -0
- package/static/dashboard/assets/index-D7A8U6Pt.js +41 -0
- package/static/dashboard/assets/index-UD6QOE7H.js +4 -0
- package/static/dashboard/assets/{key-round-D1K7warM.js → key-round-BOd7Jo0Q.js} +1 -1
- package/static/dashboard/assets/layout-DB3pMyTl.js +1 -0
- package/static/dashboard/assets/pod-collections-host-KnnGFZHL.js +8 -0
- package/static/dashboard/assets/{rotate-ccw-CcN1N6p9.js → rotate-ccw-CCgJqsvx.js} +1 -1
- package/static/dashboard/assets/settings-projection-CUkyprDQ.js +1 -0
- package/static/dashboard/assets/{skeleton-CKnmJMUH.js → skeleton-Bc7abAn5.js} +1 -1
- package/static/dashboard/assets/{waypoints-DuZPO_wu.js → waypoints-s-opmJxx.js} +1 -1
- package/static/dashboard/assets/{workspace-layout-BUj3wZ_m.js → workspace-layout-DqIQeTBV.js} +1 -1
- package/static/dashboard/dashboard.html +2 -2
- package/static/settings/assets/AiConfigContext-BB9KZySa.js +1 -0
- package/static/settings/assets/AiConfigPage-DGSXUkLs.js +1 -0
- package/static/settings/assets/DocumentProcessingPanel-Da2Re6Rg.js +1 -0
- package/static/settings/assets/IndexLifecyclePanel-BSZuIzgr.js +1 -0
- package/static/settings/assets/{IndexSubjectPanel-73sM16Ma.js → IndexSubjectPanel-CFd0ay-r.js} +1 -1
- package/static/settings/assets/ModelAssignmentsPanel-CSAryvWJ.js +1 -0
- package/static/settings/assets/ModelsPage-BQwCwLHU.js +11 -0
- package/static/settings/assets/{NetworkPage-i6j-M2RY.js → NetworkPage-BKymvsQc.js} +2 -2
- package/static/settings/assets/{PaneListHeader-DpqC0jd5.js → PaneListHeader-Bjh3hRdQ.js} +1 -1
- package/static/settings/assets/SearchIndexingPanel-MjKL5QLU.js +1 -0
- package/static/settings/assets/{StatusSubjectPanel-Dv4q3PGh.js → StatusSubjectPanel-Bvl6K4mx.js} +1 -1
- package/static/settings/assets/StatusWorkspace-B0NzrP--.js +1 -0
- package/static/settings/assets/SystemSettingsPage-D2z6Z4FE.js +1 -0
- package/static/settings/assets/SystemSettingsSubjectPanel-4sxma4X4.js +33 -0
- package/static/settings/assets/XpodAiConnectionsPodStore-BkNQ8fZx.js +3 -0
- package/static/settings/assets/{activity-DaFkk8f3.js → activity-CgJJGpjx.js} +1 -1
- package/static/settings/assets/admin-C6qCRFiY.js +1 -0
- package/static/settings/assets/ai-connections-CryuHGKW.js +1 -0
- package/static/settings/assets/{badge-d5SHdc-x.js → badge-C4NypVyT.js} +1 -1
- package/static/settings/assets/collection-runtime-CTLCDxAi.js +1 -0
- package/static/settings/assets/dialog-Csq0vWUi.js +1 -0
- package/static/settings/assets/{download-CpkwomDr.js → download-DaLJJ-Wp.js} +1 -1
- package/static/settings/assets/{external-link-_4YT42Mf.js → external-link--w_iW5Au.js} +1 -1
- package/static/settings/assets/index-B0mQa59b.js +4 -0
- package/static/settings/assets/index-BukHiu4y.js +1 -0
- package/static/settings/assets/index-COmVnZi2.js +41 -0
- package/static/settings/assets/{index-browser-B06xjBdZ.js → index-browser-BGpvHwD0.js} +1 -1
- package/static/settings/assets/{key-round-Dlqmp1Kq.js → key-round-Bk4YRjBu.js} +1 -1
- package/static/settings/assets/layout-DB3pMyTl.js +1 -0
- package/static/settings/assets/pod-collections-host-KnnGFZHL.js +8 -0
- package/static/settings/assets/{rotate-ccw-TAY65xWT.js → rotate-ccw-TCabbqsr.js} +1 -1
- package/static/settings/assets/{settings-ExBXGgbj.js → settings-CJWpdbNC.js} +105 -109
- package/static/settings/assets/settings-projection-CUkyprDQ.js +1 -0
- package/static/settings/assets/settings-rk080mvG.css +1 -0
- package/static/settings/assets/{skeleton-DKIWjNr9.js → skeleton-JDHYVe7t.js} +1 -1
- package/static/settings/assets/{waypoints-9erLIxyR.js → waypoints-DDvEl-MU.js} +1 -1
- package/static/settings/assets/{workspace-layout-CYXfYIa3.js → workspace-layout-DV5QU30U.js} +1 -1
- package/static/settings/settings.html +2 -2
- package/node_modules/@undefineds.co/shared-ui/dist/oidc-consent.d.ts +0 -54
- package/node_modules/@undefineds.co/shared-ui/dist/oidc-consent.js +0 -21
- package/static/auth-callback/assets/AiConfigContext-C81deMM9.js +0 -1
- package/static/auth-callback/assets/AiConfigPage-evWI8T56.js +0 -1
- package/static/auth-callback/assets/DocumentProcessingPanel-B9GrDEMe.js +0 -1
- package/static/auth-callback/assets/IndexLifecyclePanel-qCo8ABQZ.js +0 -1
- package/static/auth-callback/assets/ModelAssignmentsPanel-DG7Lxh3t.js +0 -1
- package/static/auth-callback/assets/ModelsPage-CgEuqE6p.js +0 -10
- package/static/auth-callback/assets/SearchIndexingPanel-ByU3u7kp.js +0 -1
- package/static/auth-callback/assets/StatusWorkspace-BZd617sV.js +0 -1
- package/static/auth-callback/assets/SystemSettingsPage-BirzWAQM.js +0 -1
- package/static/auth-callback/assets/SystemSettingsSubjectPanel-CmsVWNCx.js +0 -31
- package/static/auth-callback/assets/admin-BU4m6Ko2.js +0 -1
- package/static/auth-callback/assets/ai-connections-CHNTKemd.js +0 -1
- package/static/auth-callback/assets/auth-callback-C_7MUXJb.css +0 -1
- package/static/auth-callback/assets/index-BpV1hsqs.js +0 -4
- package/static/auth-callback/assets/index-D9oE6FXK.js +0 -41
- package/static/dashboard/assets/AiConfigContext-De-OtAWo.js +0 -1
- package/static/dashboard/assets/AiConfigPage-macP4Mop.js +0 -1
- package/static/dashboard/assets/DocumentProcessingPanel-C5ObvCCl.js +0 -1
- package/static/dashboard/assets/IndexLifecyclePanel-xVNa2l40.js +0 -1
- package/static/dashboard/assets/ModelAssignmentsPanel-DMOATFpQ.js +0 -1
- package/static/dashboard/assets/ModelsPage-91UbnETA.js +0 -25
- package/static/dashboard/assets/SearchIndexingPanel-Dh70PNFZ.js +0 -1
- package/static/dashboard/assets/SystemSettingsPage-BiN5GcKx.js +0 -1
- package/static/dashboard/assets/SystemSettingsSubjectPanel-B9QrSiFp.js +0 -31
- package/static/dashboard/assets/admin-BU4m6Ko2.js +0 -1
- package/static/dashboard/assets/ai-connections-CHNTKemd.js +0 -1
- package/static/dashboard/assets/dashboard-C_7MUXJb.css +0 -1
- package/static/dashboard/assets/index-FWZ-s52O.js +0 -41
- package/static/dashboard/assets/index-ZiQZ96oC.js +0 -4
- package/static/settings/assets/AiConfigContext-C0cQMPfG.js +0 -1
- package/static/settings/assets/AiConfigPage-CPhB4iFb.js +0 -1
- package/static/settings/assets/DocumentProcessingPanel-sYI7OpuH.js +0 -1
- package/static/settings/assets/IndexLifecyclePanel-yj8iyiT8.js +0 -1
- package/static/settings/assets/ModelAssignmentsPanel-BFIgUX5v.js +0 -1
- package/static/settings/assets/ModelsPage-BdppXl7E.js +0 -10
- package/static/settings/assets/SearchIndexingPanel-BlPnrkT3.js +0 -1
- package/static/settings/assets/SystemSettingsPage-CiOm2NzV.js +0 -1
- package/static/settings/assets/SystemSettingsSubjectPanel-Cd-GECon.js +0 -31
- package/static/settings/assets/admin-BU4m6Ko2.js +0 -1
- package/static/settings/assets/ai-connections-CHNTKemd.js +0 -1
- package/static/settings/assets/index-BFi9yn7_.js +0 -41
- package/static/settings/assets/index-BGgEhIUy.js +0 -4
- package/static/settings/assets/settings-C_7MUXJb.css +0 -1
|
@@ -1,14 +1,35 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
-
import { AI_CONNECTIONS_PINNED_SECTIONS, PROVIDERS, useProviderLoadError, useProviderProducts, useProviderSummaries, useSelectedCredentialId, useSelectedProvider, useSelectedSection, } from './controller.js';
|
|
2
|
+
import { AI_CONNECTIONS_PINNED_SECTIONS, PROVIDERS, useLiveRevision, useProviderLoadError, useProviderProducts, useProviderSummaries, useSelectedCredentialId, useSelectedProvider, useSelectedSection, } from './controller.js';
|
|
3
|
+
import { useCredentialRows } from './collections.js';
|
|
3
4
|
import { AiConnectionsPanel } from './AiConnectionsPanel.js';
|
|
4
5
|
import { useEffect } from 'react';
|
|
6
|
+
/**
|
|
7
|
+
* The page's live credentials table.
|
|
8
|
+
*
|
|
9
|
+
* `useCredentialRows` subscribes to the controller's snapshot of the collection:
|
|
10
|
+
* the rows it returns already include optimistic writes, so a create/update/
|
|
11
|
+
* delete shows before the Pod has confirmed it, and the projection diff keeps
|
|
12
|
+
* unchanged rows identical. Both the table and the layer that reads it are
|
|
13
|
+
* loaded lazily, so this hook is a plain `useSyncExternalStore` over whatever the
|
|
14
|
+
* controller has - which is nothing until the collection's first read lands.
|
|
15
|
+
*
|
|
16
|
+
* Until then - while the layer is still loading, after a failed first read, or
|
|
17
|
+
* when the host offers no collection at all - `credentialRows` stays undefined
|
|
18
|
+
* and the page keeps rendering what the store reported, so a table that cannot
|
|
19
|
+
* load is never shown as an empty table.
|
|
20
|
+
*/
|
|
5
21
|
export function AiConnectionsMain({ controller, renderToaster = true }) {
|
|
22
|
+
const liveCredentialRows = useCredentialRows(controller);
|
|
23
|
+
return (_jsx(AiConnectionsMainBody, { controller: controller, renderToaster: renderToaster, liveCredentialRows: liveCredentialRows }));
|
|
24
|
+
}
|
|
25
|
+
function AiConnectionsMainBody({ controller, renderToaster, liveCredentialRows, }) {
|
|
6
26
|
const selectedSection = useSelectedSection(controller);
|
|
7
27
|
const selectedProvider = useSelectedProvider(controller);
|
|
8
28
|
const selectedCredentialId = useSelectedCredentialId(controller);
|
|
9
29
|
const providerSummaries = useProviderSummaries(controller);
|
|
10
30
|
const providerProducts = useProviderProducts(controller);
|
|
11
31
|
const providerLoadError = useProviderLoadError(controller);
|
|
32
|
+
const liveRevision = useLiveRevision(controller);
|
|
12
33
|
const provider = PROVIDERS.find((item) => item.id === selectedProvider);
|
|
13
34
|
const selectedCredential = selectedProvider === 'custom'
|
|
14
35
|
? providerProducts.custom?.credentials.find((credential) => credential.id === selectedCredentialId)
|
|
@@ -28,15 +49,20 @@ export function AiConnectionsMain({ controller, renderToaster = true }) {
|
|
|
28
49
|
},
|
|
29
50
|
}
|
|
30
51
|
: providerProducts;
|
|
52
|
+
useEffect(() => {
|
|
53
|
+
// The open page holds the live subscriptions for the tables it renders, and
|
|
54
|
+
// releases them when it goes away. Re-entrant, so StrictMode is harmless.
|
|
55
|
+
return controller.watchPageTables();
|
|
56
|
+
}, [controller]);
|
|
31
57
|
useEffect(() => {
|
|
32
58
|
if (controller.client)
|
|
33
59
|
void controller.loadProviders();
|
|
34
60
|
return () => controller.cancelProviderLoads();
|
|
35
|
-
}, [controller]);
|
|
61
|
+
}, [controller, liveRevision]);
|
|
36
62
|
if (!controller.client) {
|
|
37
63
|
return (_jsxs("section", { role: "alert", "aria-label": "AI Connections unavailable", children: [_jsx("h2", { children: "AI Connections \u5C1A\u672A\u5C31\u7EEA" }), _jsx("p", { children: "\u5BBF\u4E3B\u9700\u8981\u5148\u63D0\u4F9B\u5DF2\u767B\u5F55\u7684 WebID \u548C\u53EF\u7528\u7684 Pod\u3002" })] }));
|
|
38
64
|
}
|
|
39
|
-
return (_jsx("section", { role: "region", "aria-label": regionLabel, children: _jsx(AiConnectionsPanel, { client: controller.client, renderToaster: renderToaster, clientConfigurationBridge: controller.clientConfigurationBridge, selectedSection: selectedSection, selectedProvider: selectedProvider, selectedCredentialId: selectedCredentialId, openExternal: controller.openExternal, providerSummaries: providerSummaries, providerProducts: scopedProducts, providerLoadError: providerLoadError, providerLoading: !providerProducts[selectedProvider] && !providerLoadError, onProviderStateChange: controller.setProviderState }) }));
|
|
65
|
+
return (_jsx("section", { role: "region", "aria-label": regionLabel, children: _jsx(AiConnectionsPanel, { client: controller.client, renderToaster: renderToaster, clientConfigurationBridge: controller.clientConfigurationBridge, selectedSection: selectedSection, selectedProvider: selectedProvider, selectedCredentialId: selectedCredentialId, openExternal: controller.openExternal, providerSummaries: providerSummaries, providerProducts: scopedProducts, providerLoadError: providerLoadError, providerLoading: !providerProducts[selectedProvider] && !providerLoadError, onProviderStateChange: controller.setProviderState, liveRevision: liveRevision, liveCredentialRows: liveCredentialRows }) }));
|
|
40
66
|
}
|
|
41
67
|
function scopedCustomOfferings(product, credential) {
|
|
42
68
|
if (!credential)
|
|
@@ -1,13 +1,28 @@
|
|
|
1
|
-
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
-
import { AI_CONNECTIONS_PINNED_SECTIONS, PROVIDERS, useProviderProducts, useSelectedProvider, useSelectedSection, } from './controller.js';
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { AI_CONNECTIONS_PINNED_SECTIONS, PROVIDERS, useLiveUpdates, useProviderProducts, useSelectedProvider, useSelectedSection, } from './controller.js';
|
|
3
|
+
/** One short line per state; the title carries the explanation. */
|
|
4
|
+
const LIVE_UPDATE_AFFORDANCE = {
|
|
5
|
+
live: {
|
|
6
|
+
label: '实时',
|
|
7
|
+
title: '实时更新已开启:Pod 中的改动会立即反映到本页。',
|
|
8
|
+
dotClass: 'bg-emerald-500',
|
|
9
|
+
},
|
|
10
|
+
unavailable: {
|
|
11
|
+
label: '实时不可用',
|
|
12
|
+
title: '实时更新当前不可用;本页仍会正常读取与操作。',
|
|
13
|
+
dotClass: 'bg-muted-foreground/60',
|
|
14
|
+
},
|
|
15
|
+
};
|
|
3
16
|
export function AiConnectionsMainHeader({ controller, }) {
|
|
4
17
|
const selectedSection = useSelectedSection(controller);
|
|
5
18
|
const selectedProvider = useSelectedProvider(controller);
|
|
6
19
|
const providerProducts = useProviderProducts(controller);
|
|
20
|
+
const liveUpdates = useLiveUpdates(controller);
|
|
7
21
|
const provider = PROVIDERS.find((candidate) => candidate.id === selectedProvider);
|
|
8
22
|
const title = AI_CONNECTIONS_PINNED_SECTIONS.find((item) => item.id === selectedSection)?.title
|
|
9
23
|
?? providerProducts[selectedProvider]?.name
|
|
10
24
|
?? provider?.name
|
|
11
25
|
?? selectedProvider;
|
|
12
|
-
|
|
26
|
+
const liveAffordance = liveUpdates === 'idle' ? undefined : LIVE_UPDATE_AFFORDANCE[liveUpdates];
|
|
27
|
+
return (_jsxs("div", { className: "flex h-full min-w-0 items-center gap-2 px-4", children: [_jsx("h1", { className: "truncate text-sm font-medium text-foreground", children: title }), liveAffordance && (_jsxs("span", { "data-live-updates": liveUpdates, title: liveAffordance.title, "aria-label": liveAffordance.title, className: "ml-auto inline-flex shrink-0 items-center gap-1 text-[10px] font-medium text-muted-foreground", children: [_jsx("span", { "aria-hidden": "true", className: `h-1.5 w-1.5 rounded-full ${liveAffordance.dotClass}` }), liveAffordance.label] }))] }));
|
|
13
28
|
}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { type AiConnectionsClient, type AiConnectionsProvider, type AiProviderConnectionSummary, type AiProviderSummary } from './ai-connections-client';
|
|
2
2
|
import { type AiConnectionsWorkspaceSection, type ProviderProductState } from './controller';
|
|
3
3
|
import type { AiClientConfigurationBridge } from './AiClientConfigurationSection';
|
|
4
|
+
import { type CredentialRow } from './collections';
|
|
4
5
|
export interface AiConnectionsPanelProps {
|
|
5
6
|
client: AiConnectionsClient;
|
|
6
7
|
/** Disable when the embedding application already renders shared-ui Toaster. */
|
|
@@ -16,5 +17,19 @@ export interface AiConnectionsPanelProps {
|
|
|
16
17
|
providerLoading?: boolean;
|
|
17
18
|
onProviderStateChange?: (provider: AiConnectionsProvider, state: ProviderProductState) => void;
|
|
18
19
|
onModelSelectionChange?: (provider: AiConnectionsProvider, modelIds: string[]) => void;
|
|
20
|
+
/**
|
|
21
|
+
* Advances when a watched Pod table document changed; the page re-reads the
|
|
22
|
+
* tables it renders through its existing loaders.
|
|
23
|
+
*/
|
|
24
|
+
liveRevision?: number;
|
|
25
|
+
/**
|
|
26
|
+
* Live rows of the credentials table, when the host exposes a collection.
|
|
27
|
+
*
|
|
28
|
+
* Present, every credential list the page renders is rebuilt from these rows
|
|
29
|
+
* (including optimistic writes) instead of from the summary the store read, so
|
|
30
|
+
* one table has one owner. The store's summaries stay the enrichment source
|
|
31
|
+
* for the attributes the descriptor cannot project.
|
|
32
|
+
*/
|
|
33
|
+
liveCredentialRows?: readonly CredentialRow[];
|
|
19
34
|
}
|
|
20
|
-
export declare function AiConnectionsPanel({ client, renderToaster, openExternal, clientConfigurationBridge, selectedSection, selectedProvider, selectedCredentialId, providerSummaries: providerSummariesInput, providerProducts, providerLoadError, providerLoading, onProviderStateChange, onModelSelectionChange, }: AiConnectionsPanelProps): import("react").JSX.Element;
|
|
35
|
+
export declare function AiConnectionsPanel({ client, renderToaster, openExternal, clientConfigurationBridge, selectedSection, selectedProvider, selectedCredentialId, providerSummaries: providerSummariesInput, providerProducts, providerLoadError, providerLoading, onProviderStateChange, onModelSelectionChange, liveRevision, liveCredentialRows, }: AiConnectionsPanelProps): import("react").JSX.Element;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { jsxs as _jsxs, jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
-
import { useCallback, useEffect, useRef, useState } from 'react';
|
|
2
|
+
import { useCallback, useEffect, useMemo, useRef, useState } from 'react';
|
|
3
3
|
import { Toaster, toast, } from '@undefineds.co/shared-ui';
|
|
4
4
|
import { normalizeAiConnectionsThrownError, } from './ai-connections-client.js';
|
|
5
5
|
import { PROVIDERS, } from './controller.js';
|
|
@@ -7,8 +7,10 @@ import { offeringTitle } from './offering-label.js';
|
|
|
7
7
|
import { AiProviderCard, } from './AiProviderCard.js';
|
|
8
8
|
import { AiModelEditorDialog, } from './AiModelEditorDialog.js';
|
|
9
9
|
import { AiGatewayKeysSection } from './AiGatewayKeysSection.js';
|
|
10
|
+
import { credentialCarriers, withLiveCredentials } from './collections.js';
|
|
11
|
+
import { modelCatalogId, withCatalogModelId } from './AiModelCatalog.js';
|
|
10
12
|
const EMPTY_PROVIDER_SUMMARIES = {};
|
|
11
|
-
export function AiConnectionsPanel({ client, renderToaster = true, openExternal = openExternalUrl, clientConfigurationBridge, selectedSection = 'provider', selectedProvider, selectedCredentialId, providerSummaries: providerSummariesInput = EMPTY_PROVIDER_SUMMARIES, providerProducts = {}, providerLoadError, providerLoading = false, onProviderStateChange, onModelSelectionChange, }) {
|
|
13
|
+
export function AiConnectionsPanel({ client, renderToaster = true, openExternal = openExternalUrl, clientConfigurationBridge, selectedSection = 'provider', selectedProvider, selectedCredentialId, providerSummaries: providerSummariesInput = EMPTY_PROVIDER_SUMMARIES, providerProducts = {}, providerLoadError, providerLoading = false, onProviderStateChange, onModelSelectionChange, liveRevision = 0, liveCredentialRows, }) {
|
|
12
14
|
const [connectionStates, setConnectionStates] = useState({});
|
|
13
15
|
const [models, setModels] = useState([]);
|
|
14
16
|
const [gatewayModels, setGatewayModels] = useState();
|
|
@@ -29,10 +31,17 @@ export function AiConnectionsPanel({ client, renderToaster = true, openExternal
|
|
|
29
31
|
const [providerProductOverrides, setProviderProductOverrides] = useState({});
|
|
30
32
|
const pollingGeneration = useRef(0);
|
|
31
33
|
const modelSelectionGeneration = useRef({});
|
|
32
|
-
|
|
34
|
+
/**
|
|
35
|
+
* Credentials come from the live rows whenever the host has a collection for
|
|
36
|
+
* that table; the store's own list is only the enrichment carrier, and an
|
|
37
|
+
* override produced by a mutation is a projection of those same rows, never an
|
|
38
|
+
* independent read. Everything else about a product (offerings, models,
|
|
39
|
+
* status) still comes from the merged products.
|
|
40
|
+
*/
|
|
41
|
+
const effectiveProviderProducts = withLiveCredentials({
|
|
33
42
|
...providerProducts,
|
|
34
43
|
...providerProductOverrides,
|
|
35
|
-
};
|
|
44
|
+
}, credentialCarriers(providerProducts, providerProductOverrides), liveCredentialRows);
|
|
36
45
|
const updateConnectionState = useCallback((provider, state) => {
|
|
37
46
|
setConnectionStates((current) => ({ ...current, [provider]: state }));
|
|
38
47
|
onProviderStateChange?.(provider, productStateFromConnection(state));
|
|
@@ -80,7 +89,7 @@ export function AiConnectionsPanel({ client, renderToaster = true, openExternal
|
|
|
80
89
|
active = false;
|
|
81
90
|
pollingGeneration.current += 1;
|
|
82
91
|
};
|
|
83
|
-
}, [client]);
|
|
92
|
+
}, [client, liveRevision]);
|
|
84
93
|
useEffect(() => {
|
|
85
94
|
let active = true;
|
|
86
95
|
setGatewayModels(undefined);
|
|
@@ -130,14 +139,15 @@ export function AiConnectionsPanel({ client, renderToaster = true, openExternal
|
|
|
130
139
|
setBusy(provider, false);
|
|
131
140
|
}
|
|
132
141
|
};
|
|
142
|
+
/**
|
|
143
|
+
* The provider-level browser entry the legacy connect path still calls.
|
|
144
|
+
*
|
|
145
|
+
* Which ways in exist is offering data, so a definition can no longer name a
|
|
146
|
+
* mode; the only mode left at this level is the API-key flow, which is what
|
|
147
|
+
* this handler starts.
|
|
148
|
+
*/
|
|
133
149
|
const beginBrowserConnect = async (definition) => {
|
|
134
|
-
|
|
135
|
-
return;
|
|
136
|
-
if (definition.browserMode === 'browserAssistedApiKey') {
|
|
137
|
-
await beginApiKey(definition.id);
|
|
138
|
-
return;
|
|
139
|
-
}
|
|
140
|
-
await beginConnectMode(definition.id, definition.browserMode);
|
|
150
|
+
await beginApiKey(definition.id);
|
|
141
151
|
};
|
|
142
152
|
const beginOfferingConnect = async (provider, offering, mode, method) => {
|
|
143
153
|
if (mode === 'browserAssistedApiKey') {
|
|
@@ -651,10 +661,39 @@ export function AiConnectionsPanel({ client, renderToaster = true, openExternal
|
|
|
651
661
|
}
|
|
652
662
|
})();
|
|
653
663
|
}, [client, effectiveProviderProducts, modelSelectionGeneration, models, onModelSelectionChange, selectedCredentialId, selectedModelIds]);
|
|
664
|
+
/** Selection ids a provider currently has, however they were last reported. */
|
|
665
|
+
const selectionIdsFor = useCallback((provider) => (selectedModelIds[provider]
|
|
666
|
+
?? effectiveProviderProducts[provider]?.selectedModels.map(modelSelectionId)
|
|
667
|
+
?? []), [selectedModelIds, effectiveProviderProducts]);
|
|
668
|
+
/**
|
|
669
|
+
* The key a gateway row is selected under.
|
|
670
|
+
*
|
|
671
|
+
* The projection names a model by its id; the Pod stores the selection as the
|
|
672
|
+
* model's resource URI. Selecting by the bare id would therefore compare
|
|
673
|
+
* unequal against everything already stored and resolve to a resource the
|
|
674
|
+
* write cannot find, so the row's own id is used whenever the account has one.
|
|
675
|
+
*/
|
|
676
|
+
const gatewaySelectionId = useCallback((model) => {
|
|
677
|
+
const stored = models.find((candidate) => candidate.provider === model.provider
|
|
678
|
+
&& modelCatalogId(candidate) === modelCatalogId(model));
|
|
679
|
+
return stored ? modelSelectionId(stored) : modelSelectionId(model);
|
|
680
|
+
}, [models]);
|
|
681
|
+
/** The gateway list switches the same selection the provider pages switch. */
|
|
682
|
+
const gatewayModelSelection = useMemo(() => ({
|
|
683
|
+
isSelected: (model) => selectionIdsFor(model.provider).includes(gatewaySelectionId(model)),
|
|
684
|
+
toggle: (model) => {
|
|
685
|
+
const current = selectionIdsFor(model.provider);
|
|
686
|
+
const selectionId = gatewaySelectionId(model);
|
|
687
|
+
void handleModelSelectionChange(model.provider, current.includes(selectionId)
|
|
688
|
+
? current.filter((id) => id !== selectionId)
|
|
689
|
+
: [...current, selectionId]);
|
|
690
|
+
},
|
|
691
|
+
disabled: providerLoading,
|
|
692
|
+
}), [gatewaySelectionId, handleModelSelectionChange, providerLoading, selectionIdsFor]);
|
|
654
693
|
const providerContent = (_jsxs("section", { children: [providerLoadError ? (_jsxs("p", { className: "mb-4 rounded-md border border-destructive/30 px-3 py-2 text-sm text-destructive", children: ["Provider \u72B6\u6001\u8BFB\u53D6\u5931\u8D25\uFF1A", providerLoadError] })) : null, PROVIDERS.filter((definition) => definition.id === (selectedProvider ?? 'openai')).map((definition) => {
|
|
655
694
|
const providerProduct = effectiveProviderProducts[definition.id];
|
|
656
695
|
const providerModels = mergeProviderModelCatalog(models.filter((model) => model.provider === definition.id
|
|
657
|
-
&& (definition.id !== 'custom' || !selectedCredentialId || model.credentialId === selectedCredentialId)), providerProduct?.selectedModels ?? []);
|
|
696
|
+
&& (definition.id !== 'custom' || !selectedCredentialId || model.credentialId === selectedCredentialId)), providerProduct?.selectedModels ?? [], gatewayModels ?? []);
|
|
658
697
|
const providerSelectedModelIds = selectedModelIds[definition.id]
|
|
659
698
|
?? providerProduct?.selectedModels.map(modelSelectionId)
|
|
660
699
|
?? [];
|
|
@@ -666,7 +705,7 @@ export function AiConnectionsPanel({ client, renderToaster = true, openExternal
|
|
|
666
705
|
[definition.id]: value,
|
|
667
706
|
})), onBeginApiKey: () => void beginApiKey(definition.id), onBeginOffering: (offering, mode, method) => void beginOfferingConnect(definition.id, offering, mode, method), onCancelConnect: (attempt) => void cancelConnect(definition.id, attempt), onBeginBrowser: () => void beginBrowserConnect(definition), onSaveApiKey: () => void saveApiKey(definition), onDisconnect: (credential) => void disconnect(definition.id, credential?.id), onCreateApiKeyCredential: (offering, input) => createApiKeyCredential(definition.id, offering, input), onCreateLocalCredential: (offering, method) => createLocalCredential(definition.id, offering, method), onUpdateCredential: (credential, patch) => updateProviderCredential(definition.id, credential, patch), onDeleteCredential: (credential) => void deleteProviderCredential(definition.id, credential), onTestCredential: (credential) => void testProviderCredential(definition.id, credential), onReorderCredentials: (offering, credentials, fromIndex, toIndex) => void reorderProviderCredentials(definition.id, offering, credentials, fromIndex, toIndex), onRefreshQuota: (offering, credential) => void refreshQuota(definition.id, offering, credential), verifyPending: Boolean(verifyingProviders[definition.id]), onVerify: () => void verifyProvider(definition.id), onAddModel: () => openModelEditor(definition.id), onEditModel: (model) => openModelEditor(definition.id, model), onDeleteModel: (model) => void deleteProviderModel(definition.id, model), onModelSelectionChange: handleModelSelectionChange, onDismissError: () => setProviderError(definition.id) }, definition.id));
|
|
668
707
|
})] }));
|
|
669
|
-
const keyContent = (_jsx(AiGatewayKeysSection, { client: client, clientConfigurationBridge: clientConfigurationBridge, gatewayModels: gatewayModels }));
|
|
708
|
+
const keyContent = (_jsx(AiGatewayKeysSection, { client: client, clientConfigurationBridge: clientConfigurationBridge, gatewayModels: gatewayModels, modelSelection: gatewayModelSelection, liveRevision: liveRevision }));
|
|
670
709
|
return (_jsxs("div", { "data-testid": "ai-connections-panel", className: "mx-auto w-full max-w-5xl space-y-10 px-4 py-6 sm:px-8 sm:py-8", children: [renderToaster ? _jsx(Toaster, {}) : null, selectedSection === 'keys' ? keyContent : null, selectedSection === 'provider' ? providerContent : null, selectedSection === 'provider' && modelEditor ? (_jsx(AiModelEditorDialog, { open: true, providerName: PROVIDERS.find((definition) => definition.id === modelEditor.provider)?.name ?? modelEditor.provider, initialValue: modelEditor.model
|
|
671
710
|
? {
|
|
672
711
|
id: modelEditor.model.id,
|
|
@@ -836,6 +875,9 @@ function delay(milliseconds) {
|
|
|
836
875
|
return new Promise((resolve) => window.setTimeout(resolve, milliseconds));
|
|
837
876
|
}
|
|
838
877
|
function errorMessage(error) {
|
|
878
|
+
if (error instanceof TypeError && /failed to fetch|fetch failed|networkerror|load failed/i.test(error.message)) {
|
|
879
|
+
return '暂时无法连接 Xpod,请在连接恢复后确认操作结果,再重试。';
|
|
880
|
+
}
|
|
839
881
|
const message = normalizeAiConnectionsThrownError(error);
|
|
840
882
|
return message === 'AI Connection request failed. Please try again.'
|
|
841
883
|
? '请求未完成。请确认 Xpod 正在运行且登录仍有效,然后重试。'
|
|
@@ -936,22 +978,52 @@ function markMissingSelectedModelsUnavailable(current, provider, selectedModels,
|
|
|
936
978
|
}
|
|
937
979
|
return merged;
|
|
938
980
|
}
|
|
939
|
-
|
|
940
|
-
|
|
941
|
-
|
|
981
|
+
/**
|
|
982
|
+
* Fold the discovered catalog and the Pod's pinned selections into one list.
|
|
983
|
+
*
|
|
984
|
+
* Entries are folded onto the model id they name first (`withCatalogModelId`),
|
|
985
|
+
* so a pinned selection which only carries its stored resource reference lands
|
|
986
|
+
* on the catalog row it belongs to instead of being listed a second time. The
|
|
987
|
+
* two rows still keep their own resource ids: the card collects every
|
|
988
|
+
* `selectionId` it sees, so unpicking the model releases all of them.
|
|
989
|
+
*
|
|
990
|
+
* `projection` carries the capability evidence. Capabilities are not Pod data -
|
|
991
|
+
* a row records what was discovered and nothing more - so they are derived from
|
|
992
|
+
* the model id against the provider catalog, and the Gateway projection is that
|
|
993
|
+
* derivation for the models it publishes.
|
|
994
|
+
*/
|
|
995
|
+
function mergeProviderModelCatalog(catalog, selectedModels, projection = []) {
|
|
996
|
+
const evidence = new Map();
|
|
997
|
+
for (const model of projection) {
|
|
998
|
+
evidence.set(`${model.provider}\0${modelCatalogId(model)}`, model);
|
|
999
|
+
}
|
|
1000
|
+
const withEvidence = (model) => {
|
|
1001
|
+
const source = evidence.get(`${model.provider}\0${modelCatalogId(model)}`);
|
|
1002
|
+
const capabilities = [...new Set([...(model.capabilities ?? []), ...(source?.capabilities ?? [])])];
|
|
1003
|
+
const inputModalities = model.inputModalities ?? source?.inputModalities;
|
|
1004
|
+
if (capabilities.length === 0 && !inputModalities)
|
|
1005
|
+
return model;
|
|
1006
|
+
return compactModel({
|
|
1007
|
+
...model,
|
|
1008
|
+
...(capabilities.length > 0 ? { capabilities } : {}),
|
|
1009
|
+
...(inputModalities ? { inputModalities } : {}),
|
|
1010
|
+
});
|
|
1011
|
+
};
|
|
1012
|
+
const merged = catalog.map((model) => withEvidence(withCatalogModelId(model)));
|
|
1013
|
+
for (const selectedModel of selectedModels.map(withCatalogModelId)) {
|
|
942
1014
|
const index = merged.findIndex((model) => modelSelectionId(model) === modelSelectionId(selectedModel));
|
|
943
1015
|
if (index === -1) {
|
|
944
|
-
merged.push(selectedModel);
|
|
1016
|
+
merged.push(withEvidence(selectedModel));
|
|
945
1017
|
continue;
|
|
946
1018
|
}
|
|
947
|
-
merged[index] = compactModel({
|
|
1019
|
+
merged[index] = withEvidence(compactModel({
|
|
948
1020
|
...merged[index],
|
|
949
1021
|
...selectedModel,
|
|
950
1022
|
displayName: merged[index].displayName ?? selectedModel.displayName,
|
|
951
1023
|
availability: merged[index].availability === 'unavailable'
|
|
952
1024
|
? 'unavailable'
|
|
953
1025
|
: selectedModel.availability,
|
|
954
|
-
});
|
|
1026
|
+
}));
|
|
955
1027
|
}
|
|
956
1028
|
return merged;
|
|
957
1029
|
}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { type ComponentProps } from 'react';
|
|
2
|
+
import { Button } from '@undefineds.co/shared-ui';
|
|
3
|
+
/**
|
|
4
|
+
* One clipboard affordance for the whole applet: the copied flag, its reset
|
|
5
|
+
* timer, and the "no clipboard access" failure all live here instead of being
|
|
6
|
+
* re-implemented by every caller that hands a value to the user.
|
|
7
|
+
*/
|
|
8
|
+
export declare function useCopyToClipboard(resetMs?: number): {
|
|
9
|
+
copied: boolean;
|
|
10
|
+
copy: (value: string) => Promise<void>;
|
|
11
|
+
};
|
|
12
|
+
/**
|
|
13
|
+
* Copy button carrying the applet's established affordance: a `复制 <what>`
|
|
14
|
+
* accessible name, the visible label swapping to `已复制`, and a check glyph in
|
|
15
|
+
* place of the copy glyph for the length of the feedback window.
|
|
16
|
+
*/
|
|
17
|
+
export declare function AiCopyButton({ value, label, text, title, variant, size, disabled, className, iconClassName, copiedIconClassName, onError, }: {
|
|
18
|
+
/**
|
|
19
|
+
* Text to copy. A function is resolved when the button is pressed, for
|
|
20
|
+
* secrets that only exist for the length of one flow.
|
|
21
|
+
*/
|
|
22
|
+
value: string | (() => string);
|
|
23
|
+
/** What is copied; the accessible name becomes `复制 ${label}`. */
|
|
24
|
+
label: string;
|
|
25
|
+
/** Visible label. Omit for an icon-only button. */
|
|
26
|
+
text?: string;
|
|
27
|
+
title?: string;
|
|
28
|
+
variant?: ComponentProps<typeof Button>['variant'];
|
|
29
|
+
size?: ComponentProps<typeof Button>['size'];
|
|
30
|
+
disabled?: boolean;
|
|
31
|
+
className?: string;
|
|
32
|
+
iconClassName?: string;
|
|
33
|
+
copiedIconClassName?: string;
|
|
34
|
+
onError?: (cause: unknown) => void;
|
|
35
|
+
}): import("react").JSX.Element;
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { useCallback, useEffect, useRef, useState } from 'react';
|
|
3
|
+
import { Button, cn } from '@undefineds.co/shared-ui';
|
|
4
|
+
import { Check, Copy } from 'lucide-react';
|
|
5
|
+
const CLIPBOARD_UNAVAILABLE = '当前浏览器无法访问剪贴板,请允许剪贴板访问后重试。';
|
|
6
|
+
/**
|
|
7
|
+
* One clipboard affordance for the whole applet: the copied flag, its reset
|
|
8
|
+
* timer, and the "no clipboard access" failure all live here instead of being
|
|
9
|
+
* re-implemented by every caller that hands a value to the user.
|
|
10
|
+
*/
|
|
11
|
+
export function useCopyToClipboard(resetMs = 1500) {
|
|
12
|
+
const [copied, setCopied] = useState(false);
|
|
13
|
+
const timer = useRef(undefined);
|
|
14
|
+
useEffect(() => () => clearTimeout(timer.current), []);
|
|
15
|
+
const copy = useCallback(async (value) => {
|
|
16
|
+
if (!navigator.clipboard?.writeText)
|
|
17
|
+
throw new Error(CLIPBOARD_UNAVAILABLE);
|
|
18
|
+
await navigator.clipboard.writeText(value);
|
|
19
|
+
setCopied(true);
|
|
20
|
+
clearTimeout(timer.current);
|
|
21
|
+
timer.current = setTimeout(() => setCopied(false), resetMs);
|
|
22
|
+
}, [resetMs]);
|
|
23
|
+
return { copied, copy };
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* Copy button carrying the applet's established affordance: a `复制 <what>`
|
|
27
|
+
* accessible name, the visible label swapping to `已复制`, and a check glyph in
|
|
28
|
+
* place of the copy glyph for the length of the feedback window.
|
|
29
|
+
*/
|
|
30
|
+
export function AiCopyButton({ value, label, text, title, variant = 'outline', size = 'sm', disabled = false, className, iconClassName = 'h-3.5 w-3.5', copiedIconClassName, onError, }) {
|
|
31
|
+
const { copied, copy } = useCopyToClipboard();
|
|
32
|
+
const iconOnly = text === undefined;
|
|
33
|
+
const Icon = copied ? Check : Copy;
|
|
34
|
+
const handleClick = () => {
|
|
35
|
+
void (async () => {
|
|
36
|
+
try {
|
|
37
|
+
await copy(typeof value === 'function' ? value() : value);
|
|
38
|
+
}
|
|
39
|
+
catch (cause) {
|
|
40
|
+
onError?.(cause);
|
|
41
|
+
}
|
|
42
|
+
})();
|
|
43
|
+
};
|
|
44
|
+
return (_jsxs(Button, { type: "button", variant: variant, size: size, disabled: disabled, className: className, "aria-label": `复制 ${label}`, title: title ?? `复制 ${label}`, onClick: handleClick, children: [_jsx(Icon, { "aria-hidden": "true", className: cn(iconClassName, copied && copiedIconClassName) }), _jsx("span", { className: iconOnly ? 'sr-only' : 'ml-1.5', children: copied ? '已复制' : text ?? '复制' })] }));
|
|
45
|
+
}
|
|
@@ -2,7 +2,7 @@ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
|
2
2
|
import { Button, TooltipProvider } from '@undefineds.co/shared-ui';
|
|
3
3
|
import { ExternalLink, Plus, Settings2 } from 'lucide-react';
|
|
4
4
|
import { offeringTitle } from './offering-label.js';
|
|
5
|
-
import { authorizationMethodsForOffering, isApiKeyMethod, isLocalMethod, isOAuthMethod, isOAuthMode, isPendingAttempt, } from './authorization-methods.js';
|
|
5
|
+
import { authorizationMethodsForOffering, connectEntryRank, isApiKeyMethod, isBrowserConnectMethod, isLocalMethod, isOAuthMethod, isOAuthMode, isPendingAttempt, } from './authorization-methods.js';
|
|
6
6
|
import { credentialDisplayLabel, maskAccountLabel } from './credential-labels.js';
|
|
7
7
|
import { AiQuotaCard } from './AiQuotaCard.js';
|
|
8
8
|
import { AiAuthorizationActions } from './AiAuthorizationActions.js';
|
|
@@ -25,7 +25,56 @@ export function AiCredentialPoolSection({ definition, product, status, accountLa
|
|
|
25
25
|
}];
|
|
26
26
|
const credentials = product?.credentials ?? [];
|
|
27
27
|
const offerings = product?.offerings.length ? product.offerings : fallbackOfferings;
|
|
28
|
-
|
|
28
|
+
/**
|
|
29
|
+
* The connect entries ARE the offerings' authorization methods, rendered as
|
|
30
|
+
* ONE ordered list.
|
|
31
|
+
*
|
|
32
|
+
* Two of them are actions of the page rather than of a single offering: the
|
|
33
|
+
* key entry (the dialog already lists every offering that accepts a key) and
|
|
34
|
+
* the console entry (every offering of a provider opens the same console, so
|
|
35
|
+
* four offerings declaring it stay one button). Everything else keeps its
|
|
36
|
+
* offering, because the click has to name which authorization it starts.
|
|
37
|
+
*
|
|
38
|
+
* The order comes from the method kind alone (`connectEntryRank`), so the
|
|
39
|
+
* toolbar reads the same on every provider - browser sign-in, device code,
|
|
40
|
+
* local login state, key - and no provider can reorder it. The console entry
|
|
41
|
+
* also yields to an entry that already carries its label: an offering's own
|
|
42
|
+
* browser login names that action, and two buttons with one name would be two
|
|
43
|
+
* claims about the same click.
|
|
44
|
+
*/
|
|
45
|
+
const offeringMethods = offerings.map((offering) => ({
|
|
46
|
+
offering,
|
|
47
|
+
methods: authorizationMethodsForOffering(offering),
|
|
48
|
+
}));
|
|
49
|
+
const apiOfferings = offeringMethods
|
|
50
|
+
.filter((entry) => entry.methods.some((method) => method.lifecycle === 'active' && isApiKeyMethod(method)))
|
|
51
|
+
.map((entry) => entry.offering);
|
|
52
|
+
const apiKeyMethod = offeringMethods
|
|
53
|
+
.flatMap((entry) => entry.methods)
|
|
54
|
+
.find((method) => isApiKeyMethod(method) && !isBrowserConnectMethod(method) && method.lifecycle === 'active' && method.label)
|
|
55
|
+
?? offeringMethods.flatMap((entry) => entry.methods)
|
|
56
|
+
.find((method) => isApiKeyMethod(method) && !isBrowserConnectMethod(method) && method.label);
|
|
57
|
+
const authorizationEntries = offeringMethods.flatMap((entry) => entry.methods
|
|
58
|
+
.filter((method) => method.label && (isOAuthMethod(method) || isLocalMethod(method)))
|
|
59
|
+
.map((method) => ({ offering: entry.offering, method })));
|
|
60
|
+
const consoleMethod = offeringMethods
|
|
61
|
+
.flatMap((entry) => entry.methods)
|
|
62
|
+
.find((method) => isBrowserConnectMethod(method) && method.lifecycle === 'active' && method.label)
|
|
63
|
+
?? offeringMethods.flatMap((entry) => entry.methods)
|
|
64
|
+
.find((method) => isBrowserConnectMethod(method) && method.label);
|
|
65
|
+
const consoleEntry = consoleMethod?.label
|
|
66
|
+
&& !authorizationEntries.some((entry) => entry.method.label === consoleMethod.label)
|
|
67
|
+
? consoleMethod
|
|
68
|
+
: undefined;
|
|
69
|
+
const connectEntries = [
|
|
70
|
+
...authorizationEntries.map((entry) => ({
|
|
71
|
+
key: `${entry.offering.id}:${entry.method.id}`,
|
|
72
|
+
rank: connectEntryRank(entry.method),
|
|
73
|
+
authorization: entry,
|
|
74
|
+
})),
|
|
75
|
+
...(consoleEntry ? [{ key: 'console-login', rank: connectEntryRank(consoleEntry), consoleMethod: consoleEntry }] : []),
|
|
76
|
+
...(apiKeyMethod ? [{ key: 'api-key', rank: connectEntryRank(apiKeyMethod), apiKeyMethod }] : []),
|
|
77
|
+
].sort((left, right) => left.rank - right.rank);
|
|
29
78
|
const authorizationPending = isPendingAttempt(attempt) && isOAuthMode(attempt?.mode);
|
|
30
79
|
const orderedCredentials = [...credentials].sort((a, b) => a.priority - b.priority);
|
|
31
80
|
const quotaBusy = credentials.some((credential) => quotas[credential.id]?.busy);
|
|
@@ -36,13 +85,18 @@ export function AiCredentialPoolSection({ definition, product, status, accountLa
|
|
|
36
85
|
onBeginBrowser,
|
|
37
86
|
onCreateLocalCredential,
|
|
38
87
|
});
|
|
39
|
-
return (_jsx(TooltipProvider, { children: _jsxs("section", { className: "space-y-3", "aria-label": "\u5F53\u524D\u8FDE\u63A5", children: [_jsxs("div", { className: "flex flex-wrap items-center justify-between gap-2", children: [_jsxs("h3", { className: "flex items-center gap-2 text-sm font-medium text-foreground/90", children: [_jsx(Settings2, { className: "h-4 w-4 text-primary" }), "\u5F53\u524D\u8FDE\u63A5"] }), _jsxs("div", { className: "flex flex-wrap items-center justify-end gap-2", children: [credentials.length > 1 ? (_jsx(Button, { variant: "ghost", size: "sm", "aria-label": `刷新全部 ${definition.name}额度`, disabled: disabled || quotaBusy || !credentials.some((c) => c.enabled) || !onRefreshQuota, onClick: () => offerings.forEach((offering) => onRefreshQuota?.(offering)), children: quotaBusy ? '查询中' : '刷新全部额度' })) : null,
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
88
|
+
return (_jsx(TooltipProvider, { children: _jsxs("section", { className: "space-y-3", "aria-label": "\u5F53\u524D\u8FDE\u63A5", children: [_jsxs("div", { className: "flex flex-wrap items-center justify-between gap-2", children: [_jsxs("h3", { className: "flex items-center gap-2 text-sm font-medium text-foreground/90", children: [_jsx(Settings2, { "aria-hidden": "true", className: "h-4 w-4 text-primary" }), "\u5F53\u524D\u8FDE\u63A5"] }), _jsxs("div", { "data-testid": "provider-connect-actions", className: "flex flex-wrap items-center justify-end gap-2", children: [credentials.length > 1 ? (_jsx(Button, { variant: "ghost", size: "sm", "aria-label": `刷新全部 ${definition.name}额度`, disabled: disabled || quotaBusy || !credentials.some((c) => c.enabled) || !onRefreshQuota, onClick: () => offerings.forEach((offering) => onRefreshQuota?.(offering)), children: quotaBusy ? '查询中' : '刷新全部额度' })) : null, connectEntries.map((item) => {
|
|
89
|
+
if ('authorization' in item) {
|
|
90
|
+
return (_jsx("fieldset", { className: "m-0 min-w-0 border-0 p-0", "aria-label": `${offeringTitle(item.authorization.offering)}快捷接入`, children: _jsx(AiAuthorizationActions, { methods: [item.authorization.method], offering: item.authorization.offering, busy: busy || dialog.saving, disabled: disabled || authorizationPending, onBeginOffering: onBeginOffering ? dialog.beginAuthorization : undefined, onCreateLocalCredential: onCreateLocalCredential ? dialog.beginLocal : undefined }) }, item.key));
|
|
91
|
+
}
|
|
92
|
+
if ('consoleMethod' in item) {
|
|
93
|
+
return (_jsxs(Button, { variant: "outline", size: "sm", className: "h-8 gap-1.5 text-xs", title: item.consoleMethod.lifecycle === 'unavailable' ? item.consoleMethod.reason : undefined, disabled: busy || dialog.saving || disabled || authorizationPending
|
|
94
|
+
|| item.consoleMethod.lifecycle === 'unavailable', onClick: dialog.beginBrowser, children: [_jsx(ExternalLink, { "aria-hidden": "true", className: "h-3.5 w-3.5" }), item.consoleMethod.label] }, item.key));
|
|
95
|
+
}
|
|
96
|
+
return (_jsxs(Button, { variant: "outline", size: "sm", className: "h-8 gap-1.5 text-xs", "aria-label": "\u65B0\u5EFA API Key \u8FDE\u63A5", title: item.apiKeyMethod.lifecycle === 'unavailable' ? item.apiKeyMethod.reason : undefined, disabled: busy || dialog.saving || disabled || authorizationPending
|
|
97
|
+
|| item.apiKeyMethod.lifecycle === 'unavailable'
|
|
98
|
+
|| (!product && status === 'pending' && !attempt), onClick: dialog.beginApiKey, children: [_jsx(Plus, { "aria-hidden": "true", className: "h-3.5 w-3.5" }), item.apiKeyMethod.label] }, item.key));
|
|
99
|
+
})] })] }), _jsxs("div", { "aria-label": "\u51ED\u636E\u5217\u8868", className: "space-y-2", children: [_jsx(AiSortableCredentialList, { credentials: orderedCredentials, disabled: busy || disabled, onMove: onReorderCredentials ? (from, to) => {
|
|
46
100
|
const offering = offerings.find((item) => item.id === orderedCredentials[from]?.offeringId);
|
|
47
101
|
if (offering)
|
|
48
102
|
onReorderCredentials(offering, orderedCredentials, from, to);
|
|
@@ -54,7 +108,13 @@ export function AiCredentialPoolSection({ definition, product, status, accountLa
|
|
|
54
108
|
: credential.label ? maskAccountLabel(credential.label) : credentialDisplayLabel(credential);
|
|
55
109
|
const state = quotas[credential.id];
|
|
56
110
|
const quotaState = state?.credentialId === credential.id ? state : undefined;
|
|
57
|
-
return _jsx(AiCredentialRow, { credential: credential, label: label, dragHandle: handle, kindLabel: credential.authMode === 'apiKey' ? 'API Key' : offeringTitle(offering), busy: busy, disabled: disabled,
|
|
58
|
-
|
|
111
|
+
return _jsx(AiCredentialRow, { credential: credential, label: label, dragHandle: handle, kindLabel: credential.authMode === 'apiKey' ? 'API Key' : offeringTitle(offering), busy: busy, disabled: disabled,
|
|
112
|
+
// A row action is a click, not a call site: the failure is already
|
|
113
|
+
// reported through `setProviderError`, so it must not also surface
|
|
114
|
+
// as an unhandled rejection from the button.
|
|
115
|
+
onToggle: onUpdateCredential
|
|
116
|
+
? (current, patch) => { void onUpdateCredential(current, patch).catch(() => undefined); }
|
|
117
|
+
: undefined, onTest: onTestCredential, onEdit: credential.authMode === 'apiKey' ? () => dialog.beginEdit(credential) : undefined, onDelete: () => credential.authMode === 'apiKey' ? onDeleteCredential?.(credential) : onDisconnect(credential), deleteAriaLabel: credential.authMode === 'apiKey' ? `删除 ${label}` : `${label} 移除`, quota: _jsx(AiQuotaCard, { compact: true, providerName: definition.name, offeringName: offeringTitle(offering), credentialLabel: credentialDisplayLabel(credential), multiple: credentials.length > 1, quota: quotaState?.quota, busy: quotaState?.busy ?? false, error: quotaState?.error, paused: !credential.enabled, disabled: disabled || !onRefreshQuota, onRefresh: () => onRefreshQuota?.(offering, credential) }) });
|
|
118
|
+
} }), !credentials.length ? (_jsx("p", { className: "flex items-center gap-2 py-6 text-sm text-muted-foreground", children: accountLabel ? maskAccountLabel(accountLabel) : '尚未添加连接' })) : null, credentials.length === 0 && (status === 'configured' || status === 'connected') ? (_jsx(Button, { variant: "ghost", size: "sm", disabled: busy || disabled, onClick: () => onDisconnect(), children: status === 'configured' ? '移除配置' : '断开连接' })) : null] }), _jsx(AiConnectDialog, { controller: dialog, definition: definition, offerings: offerings, apiOfferings: apiOfferings, credentials: credentials, status: status, attempt: attempt, attemptOfferingId: attemptOfferingId, apiKey: apiKey, baseUrl: baseUrl, busy: busy, disabled: disabled, error: error, onApiKeyChange: onApiKeyChange, onBaseUrlChange: onBaseUrlChange, onBeginApiKey: onBeginApiKey, onBeginBrowser: onBeginBrowser, onSaveApiKey: onSaveApiKey, onDisconnect: onDisconnect, onUpdateCredential: onUpdateCredential, onCreateApiKeyCredential: onCreateApiKeyCredential, onBeginOffering: onBeginOffering, onCancelConnect: onCancelConnect, onDismissError: onDismissError }), _jsxs("details", { className: "text-xs text-muted-foreground", children: [_jsx("summary", { className: "w-fit cursor-pointer", children: "\u63A5\u5165\u4FE1\u606F" }), _jsx("div", { className: "mt-2 space-y-3", children: offerings.map((offering) => _jsx(AiOfferingDetails, { offering: offering }, offering.id)) })] }), dialog.error && !dialog.open && dialog.error !== error?.message ? _jsx("p", { role: "alert", className: "text-sm text-destructive", children: dialog.error }) : null, error && (error.offeringId ? !dialog.open : !suppressError)
|
|
59
119
|
? _jsx("p", { role: "alert", className: "text-sm text-destructive", children: error.message }) : null] }) }));
|
|
60
120
|
}
|
|
@@ -1,17 +1,19 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
-
import {
|
|
2
|
+
import { Tooltip, TooltipContent, TooltipTrigger, cn } from '@undefineds.co/shared-ui';
|
|
3
|
+
import { AiRowAction } from './AiRowAction.js';
|
|
3
4
|
import { Pause, Pencil, Play, PlugZap, Trash2 } from 'lucide-react';
|
|
4
5
|
import { credentialDisplayLabel, healthLabel, healthTone } from './credential-labels.js';
|
|
5
6
|
export function AiCredentialRow({ credential, label, busy, disabled, dragHandle, kindLabel, quota, onToggle, onTest, onEdit, onDelete, deleteAriaLabel, }) {
|
|
6
7
|
const actionDisabled = disabled || busy;
|
|
7
8
|
const tone = healthTone(credential.health);
|
|
8
9
|
const stateLabel = `${credential.enabled ? '已启用' : '已停用'} · ${healthLabel(credential.health)}`;
|
|
9
|
-
return (_jsxs("div", { "data-credential-state": credential.enabled ? 'enabled' : 'disabled', className: cn(
|
|
10
|
+
return (_jsxs("div", { "data-credential-state": credential.enabled ? 'enabled' : 'disabled', className: cn(
|
|
11
|
+
// The list owns the box and the dividers, so a row carries only its own
|
|
12
|
+
// tint: `rounded-[inherit]` keeps the first and last tint inside the
|
|
13
|
+
// container's corners.
|
|
14
|
+
'flex flex-wrap items-center gap-x-3 gap-y-2 rounded-[inherit] px-4 py-3 transition-colors', credential.enabled ? tone.row : 'bg-muted/40 opacity-70'), children: [dragHandle, _jsxs(Tooltip, { children: [_jsx(TooltipTrigger, { asChild: true, children: _jsx("span", { "aria-label": stateLabel, className: cn('h-2 w-2 shrink-0 rounded-full', credential.enabled ? tone.dot : 'bg-muted-foreground/40') }) }), _jsx(TooltipContent, { className: "text-xs", children: stateLabel })] }), _jsxs("div", { className: "min-w-0 flex-1 basis-24", children: [_jsx("p", { className: "truncate text-sm font-medium text-foreground", children: label }), kindLabel ? _jsx("p", { className: "text-xs text-muted-foreground", children: kindLabel }) : null, credential.maskedHint && !label.includes(credential.maskedHint)
|
|
10
15
|
? _jsx("p", { className: "mt-1 truncate font-mono text-xs text-muted-foreground", children: credential.maskedHint })
|
|
11
|
-
: null] }), _jsx("div", { className: "order-last w-full min-w-0 sm:order-none sm:w-auto sm:max-w-[45%]", role: "group", "aria-label": `${credentialDisplayLabel(credential)}额度`, children: quota }), _jsxs("div", { className: "flex shrink-0 items-center gap-1", children: [onTest ? (_jsx(
|
|
16
|
+
: null] }), _jsx("div", { className: "order-last w-full min-w-0 sm:order-none sm:w-auto sm:max-w-[45%]", role: "group", "aria-label": `${credentialDisplayLabel(credential)}额度`, children: quota }), _jsxs("div", { className: "flex shrink-0 items-center gap-1", children: [onTest ? (_jsx(AiRowAction, { label: `测试连接 ${label}`, disabled: actionDisabled, onClick: () => onTest(credential), children: _jsx(PlugZap, { "aria-hidden": "true", className: "h-3.5 w-3.5" }) })) : null, onEdit ? (_jsx(AiRowAction, { label: `编辑 ${label}`, disabled: actionDisabled, onClick: onEdit, children: _jsx(Pencil, { "aria-hidden": "true", className: "h-3.5 w-3.5" }) })) : null, onToggle ? (_jsx(AiRowAction, { label: `${credential.enabled ? '停用' : '启用'} ${label}`, disabled: actionDisabled, onClick: () => onToggle(credential, { enabled: !credential.enabled }), children: credential.enabled
|
|
12
17
|
? _jsx(Pause, { "aria-hidden": "true", className: "h-3.5 w-3.5" })
|
|
13
|
-
: _jsx(Play, { "aria-hidden": "true", className: "h-3.5 w-3.5" }) })) : null, onDelete ? (_jsx(
|
|
14
|
-
}
|
|
15
|
-
function RowAction({ label, disabled, onClick, children, }) {
|
|
16
|
-
return (_jsxs(Tooltip, { children: [_jsx(TooltipTrigger, { asChild: true, children: _jsx(Button, { variant: "ghost", size: "icon", className: "h-7 w-7", "aria-label": label, disabled: disabled, onClick: onClick, children: children }) }), _jsx(TooltipContent, { className: "text-xs", children: label })] }));
|
|
18
|
+
: _jsx(Play, { "aria-hidden": "true", className: "h-3.5 w-3.5" }) })) : null, onDelete ? (_jsx(AiRowAction, { label: deleteAriaLabel ?? `删除 ${label}`, disabled: actionDisabled, onClick: onDelete, children: _jsx(Trash2, { "aria-hidden": "true", className: "h-3.5 w-3.5" }) })) : null] })] }));
|
|
17
19
|
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { type AiEndpointEntry } from './offering-endpoints';
|
|
2
|
+
/**
|
|
3
|
+
* Protocol/endpoint list shared by a provider offering's details and Xpod's own
|
|
4
|
+
* 接入信息: in both places a list of `protocol → base URL` pairs is what the user
|
|
5
|
+
* reads, so the rows (and their copy affordance) are one implementation.
|
|
6
|
+
*
|
|
7
|
+
* `copy` is opt-in because the provider pages read their upstream endpoints
|
|
8
|
+
* without offering them for pasting, while Xpod's own endpoints exist to be
|
|
9
|
+
* copied into a client.
|
|
10
|
+
*/
|
|
11
|
+
export declare function AiEndpointList({ endpoints, copy, display }: {
|
|
12
|
+
endpoints: readonly AiEndpointEntry[];
|
|
13
|
+
copy?: boolean;
|
|
14
|
+
/**
|
|
15
|
+
* `compact` shortens the address, `full` shows it in full.
|
|
16
|
+
*
|
|
17
|
+
* `protocol` drops the address and lists the accept-compatible protocols as
|
|
18
|
+
* chips. Xpod publishes three protocols from one gateway, so two of them even
|
|
19
|
+
* share an address: repeating it tells the reader less than naming the
|
|
20
|
+
* protocol they should pick, and the address stays one click away.
|
|
21
|
+
*/
|
|
22
|
+
display?: 'compact' | 'full' | 'protocol';
|
|
23
|
+
}): import("react").JSX.Element;
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { compatibleProtocolLabel, endpointDisplayValue, endpointProtocolLabel } from './offering-endpoints.js';
|
|
3
|
+
import { AiCopyButton } from './AiCopyButton.js';
|
|
4
|
+
/**
|
|
5
|
+
* Protocol/endpoint list shared by a provider offering's details and Xpod's own
|
|
6
|
+
* 接入信息: in both places a list of `protocol → base URL` pairs is what the user
|
|
7
|
+
* reads, so the rows (and their copy affordance) are one implementation.
|
|
8
|
+
*
|
|
9
|
+
* `copy` is opt-in because the provider pages read their upstream endpoints
|
|
10
|
+
* without offering them for pasting, while Xpod's own endpoints exist to be
|
|
11
|
+
* copied into a client.
|
|
12
|
+
*/
|
|
13
|
+
export function AiEndpointList({ endpoints, copy = false, display = 'compact' }) {
|
|
14
|
+
if (display === 'protocol') {
|
|
15
|
+
return (_jsx("ul", { className: "flex flex-wrap gap-2", children: endpoints.map((endpoint) => {
|
|
16
|
+
const label = compatibleProtocolLabel(endpoint.protocol);
|
|
17
|
+
return (_jsx("li", { children: copy ? (_jsx(AiCopyButton, { value: endpoint.baseUrl, label: `${label} 地址`, text: label, variant: "outline", className: "h-7 gap-1.5 px-2 text-[11px] font-normal", iconClassName: "h-3 w-3" })) : (_jsx("span", { className: "inline-flex h-7 items-center rounded-md border border-border px-2 text-[11px] text-muted-foreground", children: label })) }, endpoint.protocol));
|
|
18
|
+
}) }));
|
|
19
|
+
}
|
|
20
|
+
return (_jsx("dl", { className: "space-y-1 text-[11px] text-muted-foreground", children: endpoints.map((endpoint) => {
|
|
21
|
+
const label = endpointProtocolLabel(endpoint.protocol);
|
|
22
|
+
return (_jsxs("div", { className: "flex min-w-0 items-baseline gap-2", children: [_jsx("dt", { className: "shrink-0 text-foreground/70", children: label }), _jsx("dd", { className: "min-w-0 truncate font-mono", title: endpoint.baseUrl, children: display === 'full' ? endpoint.baseUrl : endpointDisplayValue(endpoint.baseUrl) }), copy ? (_jsx("dd", { className: "shrink-0", children: _jsx(AiCopyButton, { value: endpoint.baseUrl, label: `${label} 地址`, variant: "ghost", className: "h-6 gap-1 px-1.5 text-[11px]", iconClassName: "h-3 w-3" }) })) : null] }, `${endpoint.protocol}:${endpoint.baseUrl}`));
|
|
23
|
+
}) }));
|
|
24
|
+
}
|