@stigmer/react 3.2.2 → 3.3.0
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/agent/AgentDetailView.d.ts.map +1 -1
- package/agent/AgentDetailView.js +6 -3
- package/agent/AgentDetailView.js.map +1 -1
- package/agent/steps/ReviewStep.d.ts.map +1 -1
- package/agent/steps/ReviewStep.js +2 -3
- package/agent/steps/ReviewStep.js.map +1 -1
- package/billing/BaselineEditor.d.ts +9 -0
- package/billing/BaselineEditor.d.ts.map +1 -0
- package/billing/BaselineEditor.js +253 -0
- package/billing/BaselineEditor.js.map +1 -0
- package/billing/ModelCatalogPanel.d.ts +28 -0
- package/billing/ModelCatalogPanel.d.ts.map +1 -0
- package/billing/ModelCatalogPanel.js +102 -0
- package/billing/ModelCatalogPanel.js.map +1 -0
- package/billing/ModelGovernanceDetail.d.ts +8 -0
- package/billing/ModelGovernanceDetail.d.ts.map +1 -0
- package/billing/ModelGovernanceDetail.js +64 -0
- package/billing/ModelGovernanceDetail.js.map +1 -0
- package/billing/OperatorAccessNotice.d.ts +12 -0
- package/billing/OperatorAccessNotice.d.ts.map +1 -0
- package/billing/OperatorAccessNotice.js +15 -0
- package/billing/OperatorAccessNotice.js.map +1 -0
- package/billing/PricingGovernanceConsole.d.ts +57 -0
- package/billing/PricingGovernanceConsole.d.ts.map +1 -0
- package/billing/PricingGovernanceConsole.js +164 -0
- package/billing/PricingGovernanceConsole.js.map +1 -0
- package/billing/PricingGovernancePanel.d.ts +26 -0
- package/billing/PricingGovernancePanel.d.ts.map +1 -0
- package/billing/PricingGovernancePanel.js +64 -0
- package/billing/PricingGovernancePanel.js.map +1 -0
- package/billing/RetireConfirm.d.ts +9 -0
- package/billing/RetireConfirm.d.ts.map +1 -0
- package/billing/RetireConfirm.js +19 -0
- package/billing/RetireConfirm.js.map +1 -0
- package/billing/form-primitives.d.ts +18 -0
- package/billing/form-primitives.d.ts.map +1 -0
- package/billing/form-primitives.js +19 -0
- package/billing/form-primitives.js.map +1 -0
- package/billing/governance-primitives.d.ts +33 -0
- package/billing/governance-primitives.d.ts.map +1 -0
- package/billing/governance-primitives.js +43 -0
- package/billing/governance-primitives.js.map +1 -0
- package/billing/index.d.ts +18 -0
- package/billing/index.d.ts.map +1 -1
- package/billing/index.js +9 -0
- package/billing/index.js.map +1 -1
- package/billing/pricing-format.d.ts +12 -0
- package/billing/pricing-format.d.ts.map +1 -0
- package/billing/pricing-format.js +50 -0
- package/billing/pricing-format.js.map +1 -0
- package/billing/useDecidePricingOverride.d.ts +46 -0
- package/billing/useDecidePricingOverride.d.ts.map +1 -0
- package/billing/useDecidePricingOverride.js +44 -0
- package/billing/useDecidePricingOverride.js.map +1 -0
- package/billing/useModelGovernanceView.d.ts +103 -0
- package/billing/useModelGovernanceView.d.ts.map +1 -0
- package/billing/useModelGovernanceView.js +144 -0
- package/billing/useModelGovernanceView.js.map +1 -0
- package/billing/useModelPricingBaselines.d.ts +40 -0
- package/billing/useModelPricingBaselines.d.ts.map +1 -0
- package/billing/useModelPricingBaselines.js +32 -0
- package/billing/useModelPricingBaselines.js.map +1 -0
- package/billing/usePricingGovernance.d.ts +39 -0
- package/billing/usePricingGovernance.d.ts.map +1 -0
- package/billing/usePricingGovernance.js +31 -0
- package/billing/usePricingGovernance.js.map +1 -0
- package/billing/useRetireModelPricingBaseline.d.ts +31 -0
- package/billing/useRetireModelPricingBaseline.d.ts.map +1 -0
- package/billing/useRetireModelPricingBaseline.js +36 -0
- package/billing/useRetireModelPricingBaseline.js.map +1 -0
- package/billing/useUpsertModelPricingBaseline.d.ts +38 -0
- package/billing/useUpsertModelPricingBaseline.d.ts.map +1 -0
- package/billing/useUpsertModelPricingBaseline.js +37 -0
- package/billing/useUpsertModelPricingBaseline.js.map +1 -0
- package/channel/AgentChannelsPanel.d.ts.map +1 -1
- package/channel/AgentChannelsPanel.js +11 -5
- package/channel/AgentChannelsPanel.js.map +1 -1
- package/composer/SessionComposer.d.ts +1 -1
- package/cursor-accounts/CursorAccountEditor.d.ts +28 -0
- package/cursor-accounts/CursorAccountEditor.d.ts.map +1 -0
- package/cursor-accounts/CursorAccountEditor.js +51 -0
- package/cursor-accounts/CursorAccountEditor.js.map +1 -0
- package/cursor-accounts/CursorAccountsAccessNotice.d.ts +11 -0
- package/cursor-accounts/CursorAccountsAccessNotice.d.ts.map +1 -0
- package/cursor-accounts/CursorAccountsAccessNotice.js +14 -0
- package/cursor-accounts/CursorAccountsAccessNotice.js.map +1 -0
- package/cursor-accounts/CursorAccountsConsole.d.ts +28 -0
- package/cursor-accounts/CursorAccountsConsole.d.ts.map +1 -0
- package/cursor-accounts/CursorAccountsConsole.js +275 -0
- package/cursor-accounts/CursorAccountsConsole.js.map +1 -0
- package/cursor-accounts/cursor-account-format.d.ts +10 -0
- package/cursor-accounts/cursor-account-format.d.ts.map +1 -0
- package/cursor-accounts/cursor-account-format.js +26 -0
- package/cursor-accounts/cursor-account-format.js.map +1 -0
- package/cursor-accounts/index.d.ts +18 -0
- package/cursor-accounts/index.d.ts.map +1 -0
- package/cursor-accounts/index.js +13 -0
- package/cursor-accounts/index.js.map +1 -0
- package/cursor-accounts/useCursorAccountView.d.ts +30 -0
- package/cursor-accounts/useCursorAccountView.d.ts.map +1 -0
- package/cursor-accounts/useCursorAccountView.js +25 -0
- package/cursor-accounts/useCursorAccountView.js.map +1 -0
- package/cursor-accounts/useCursorAccounts.d.ts +33 -0
- package/cursor-accounts/useCursorAccounts.d.ts.map +1 -0
- package/cursor-accounts/useCursorAccounts.js +25 -0
- package/cursor-accounts/useCursorAccounts.js.map +1 -0
- package/cursor-accounts/useCursorMemberKeyActions.d.ts +49 -0
- package/cursor-accounts/useCursorMemberKeyActions.d.ts.map +1 -0
- package/cursor-accounts/useCursorMemberKeyActions.js +38 -0
- package/cursor-accounts/useCursorMemberKeyActions.js.map +1 -0
- package/cursor-accounts/useDeleteCursorAccount.d.ts +30 -0
- package/cursor-accounts/useDeleteCursorAccount.d.ts.map +1 -0
- package/cursor-accounts/useDeleteCursorAccount.js +32 -0
- package/cursor-accounts/useDeleteCursorAccount.js.map +1 -0
- package/cursor-accounts/useSyncCursorAccount.d.ts +23 -0
- package/cursor-accounts/useSyncCursorAccount.d.ts.map +1 -0
- package/cursor-accounts/useSyncCursorAccount.js +31 -0
- package/cursor-accounts/useSyncCursorAccount.js.map +1 -0
- package/cursor-accounts/useUpsertCursorAccount.d.ts +26 -0
- package/cursor-accounts/useUpsertCursorAccount.d.ts.map +1 -0
- package/cursor-accounts/useUpsertCursorAccount.js +34 -0
- package/cursor-accounts/useUpsertCursorAccount.js.map +1 -0
- package/datastore/CollectionRecordsBrowser.d.ts +34 -0
- package/datastore/CollectionRecordsBrowser.d.ts.map +1 -0
- package/datastore/CollectionRecordsBrowser.js +209 -0
- package/datastore/CollectionRecordsBrowser.js.map +1 -0
- package/datastore/CollectionSchemaView.d.ts +29 -0
- package/datastore/CollectionSchemaView.d.ts.map +1 -0
- package/datastore/CollectionSchemaView.js +93 -0
- package/datastore/CollectionSchemaView.js.map +1 -0
- package/datastore/DatastoreDetailView.d.ts +44 -0
- package/datastore/DatastoreDetailView.d.ts.map +1 -0
- package/datastore/DatastoreDetailView.js +76 -0
- package/datastore/DatastoreDetailView.js.map +1 -0
- package/datastore/DatastoreSyncReport.d.ts +19 -0
- package/datastore/DatastoreSyncReport.d.ts.map +1 -0
- package/datastore/DatastoreSyncReport.js +45 -0
- package/datastore/DatastoreSyncReport.js.map +1 -0
- package/datastore/DeleteDatastoreDialog.d.ts +35 -0
- package/datastore/DeleteDatastoreDialog.d.ts.map +1 -0
- package/datastore/DeleteDatastoreDialog.js +90 -0
- package/datastore/DeleteDatastoreDialog.js.map +1 -0
- package/datastore/FieldValueControl.d.ts +55 -0
- package/datastore/FieldValueControl.d.ts.map +1 -0
- package/datastore/FieldValueControl.js +138 -0
- package/datastore/FieldValueControl.js.map +1 -0
- package/datastore/RecordFilterBuilder.d.ts +30 -0
- package/datastore/RecordFilterBuilder.d.ts.map +1 -0
- package/datastore/RecordFilterBuilder.js +122 -0
- package/datastore/RecordFilterBuilder.js.map +1 -0
- package/datastore/RecordFormPanel.d.ts +45 -0
- package/datastore/RecordFormPanel.d.ts.map +1 -0
- package/datastore/RecordFormPanel.js +215 -0
- package/datastore/RecordFormPanel.js.map +1 -0
- package/datastore/index.d.ts +43 -0
- package/datastore/index.d.ts.map +1 -0
- package/datastore/index.js +22 -0
- package/datastore/index.js.map +1 -0
- package/datastore/recordFilter.d.ts +54 -0
- package/datastore/recordFilter.d.ts.map +1 -0
- package/datastore/recordFilter.js +93 -0
- package/datastore/recordFilter.js.map +1 -0
- package/datastore/recordValues.d.ts +85 -0
- package/datastore/recordValues.d.ts.map +1 -0
- package/datastore/recordValues.js +282 -0
- package/datastore/recordValues.js.map +1 -0
- package/datastore/useDatastore.d.ts +39 -0
- package/datastore/useDatastore.d.ts.map +1 -0
- package/datastore/useDatastore.js +44 -0
- package/datastore/useDatastore.js.map +1 -0
- package/datastore/useDatastoreCount.d.ts +48 -0
- package/datastore/useDatastoreCount.d.ts.map +1 -0
- package/datastore/useDatastoreCount.js +27 -0
- package/datastore/useDatastoreCount.js.map +1 -0
- package/datastore/useDatastoreDescription.d.ts +54 -0
- package/datastore/useDatastoreDescription.d.ts.map +1 -0
- package/datastore/useDatastoreDescription.js +50 -0
- package/datastore/useDatastoreDescription.js.map +1 -0
- package/datastore/useDatastoreList.d.ts +57 -0
- package/datastore/useDatastoreList.d.ts.map +1 -0
- package/datastore/useDatastoreList.js +29 -0
- package/datastore/useDatastoreList.js.map +1 -0
- package/datastore/useDatastoreSearch.d.ts +19 -0
- package/datastore/useDatastoreSearch.d.ts.map +1 -0
- package/datastore/useDatastoreSearch.js +22 -0
- package/datastore/useDatastoreSearch.js.map +1 -0
- package/datastore/useDeleteDatastore.d.ts +53 -0
- package/datastore/useDeleteDatastore.d.ts.map +1 -0
- package/datastore/useDeleteDatastore.js +40 -0
- package/datastore/useDeleteDatastore.js.map +1 -0
- package/datastore/useDeleteRecord.d.ts +34 -0
- package/datastore/useDeleteRecord.d.ts.map +1 -0
- package/datastore/useDeleteRecord.js +43 -0
- package/datastore/useDeleteRecord.js.map +1 -0
- package/datastore/useInsertRecord.d.ts +50 -0
- package/datastore/useInsertRecord.d.ts.map +1 -0
- package/datastore/useInsertRecord.js +55 -0
- package/datastore/useInsertRecord.js.map +1 -0
- package/datastore/useRecordCollection.d.ts +104 -0
- package/datastore/useRecordCollection.d.ts.map +1 -0
- package/datastore/useRecordCollection.js +136 -0
- package/datastore/useRecordCollection.js.map +1 -0
- package/datastore/useRecordList.d.ts +66 -0
- package/datastore/useRecordList.d.ts.map +1 -0
- package/datastore/useRecordList.js +58 -0
- package/datastore/useRecordList.js.map +1 -0
- package/datastore/useUpdateRecord.d.ts +52 -0
- package/datastore/useUpdateRecord.d.ts.map +1 -0
- package/datastore/useUpdateRecord.js +55 -0
- package/datastore/useUpdateRecord.js.map +1 -0
- package/environment/EnvironmentListPanel.d.ts.map +1 -1
- package/environment/EnvironmentListPanel.js +12 -7
- package/environment/EnvironmentListPanel.js.map +1 -1
- package/execution/index.d.ts +1 -2
- package/execution/index.d.ts.map +1 -1
- package/execution/index.js +0 -1
- package/execution/index.js.map +1 -1
- package/execution/useLiveAgentExecution.d.ts +17 -1
- package/execution/useLiveAgentExecution.d.ts.map +1 -1
- package/execution/useLiveAgentExecution.js +19 -4
- package/execution/useLiveAgentExecution.js.map +1 -1
- package/iam-policy/index.d.ts +1 -1
- package/iam-policy/index.d.ts.map +1 -1
- package/iam-policy/index.js.map +1 -1
- package/iam-policy/useCheckPermission.d.ts +32 -11
- package/iam-policy/useCheckPermission.d.ts.map +1 -1
- package/iam-policy/useCheckPermission.js +24 -19
- package/iam-policy/useCheckPermission.js.map +1 -1
- package/index.d.ts +16 -10
- package/index.d.ts.map +1 -1
- package/index.js +16 -5
- package/index.js.map +1 -1
- package/internal/useInViewport.d.ts +24 -0
- package/internal/useInViewport.d.ts.map +1 -0
- package/internal/useInViewport.js +49 -0
- package/internal/useInViewport.js.map +1 -0
- package/library/VisibilitySelector.d.ts +22 -6
- package/library/VisibilitySelector.d.ts.map +1 -1
- package/library/VisibilitySelector.js +12 -4
- package/library/VisibilitySelector.js.map +1 -1
- package/library/index.d.ts +1 -8
- package/library/index.d.ts.map +1 -1
- package/library/index.js +0 -4
- package/library/index.js.map +1 -1
- package/library/useApplyResource.d.ts +12 -12
- package/library/useApplyResource.d.ts.map +1 -1
- package/library/useApplyResource.js +16 -25
- package/library/useApplyResource.js.map +1 -1
- package/library/useExportResource.d.ts +13 -9
- package/library/useExportResource.d.ts.map +1 -1
- package/library/useExportResource.js +18 -36
- package/library/useExportResource.js.map +1 -1
- package/manifest/ApplyManifestDialog.d.ts +48 -0
- package/manifest/ApplyManifestDialog.d.ts.map +1 -0
- package/manifest/ApplyManifestDialog.js +135 -0
- package/manifest/ApplyManifestDialog.js.map +1 -0
- package/manifest/EditResourceYamlDialog.d.ts +51 -0
- package/manifest/EditResourceYamlDialog.d.ts.map +1 -0
- package/manifest/EditResourceYamlDialog.js +104 -0
- package/manifest/EditResourceYamlDialog.js.map +1 -0
- package/manifest/RedactedSecretsNotice.d.ts +14 -0
- package/manifest/RedactedSecretsNotice.d.ts.map +1 -0
- package/manifest/RedactedSecretsNotice.js +14 -0
- package/manifest/RedactedSecretsNotice.js.map +1 -0
- package/manifest/YamlEditor.d.ts +44 -0
- package/manifest/YamlEditor.d.ts.map +1 -0
- package/manifest/YamlEditor.js +216 -0
- package/manifest/YamlEditor.js.map +1 -0
- package/manifest/index.d.ts +13 -0
- package/manifest/index.d.ts.map +1 -0
- package/manifest/index.js +13 -0
- package/manifest/index.js.map +1 -0
- package/manifest/useApplyManifest.d.ts +82 -0
- package/manifest/useApplyManifest.d.ts.map +1 -0
- package/manifest/useApplyManifest.js +180 -0
- package/manifest/useApplyManifest.js.map +1 -0
- package/manifest/useEditResourceYaml.d.ts +106 -0
- package/manifest/useEditResourceYaml.d.ts.map +1 -0
- package/manifest/useEditResourceYaml.js +168 -0
- package/manifest/useEditResourceYaml.js.map +1 -0
- package/mcp-server/McpServerDetailView.d.ts.map +1 -1
- package/mcp-server/McpServerDetailView.js +4 -3
- package/mcp-server/McpServerDetailView.js.map +1 -1
- package/mcp-server/steps/ReviewStep.d.ts.map +1 -1
- package/mcp-server/steps/ReviewStep.js +2 -3
- package/mcp-server/steps/ReviewStep.js.map +1 -1
- package/package.json +4 -4
- package/resource-creation/templates/workflow-templates.js +4 -4
- package/session/SessionViewer.js +8 -1
- package/session/SessionViewer.js.map +1 -1
- package/session/audience.d.ts +6 -1
- package/session/audience.d.ts.map +1 -1
- package/session/useEditSessionPrep.js +3 -3
- package/session/useEditSessionPrep.js.map +1 -1
- package/settings/index.d.ts +2 -1
- package/settings/index.d.ts.map +1 -1
- package/settings/index.js +2 -1
- package/settings/index.js.map +1 -1
- package/settings/settings-nav.d.ts +22 -0
- package/settings/settings-nav.d.ts.map +1 -1
- package/settings/settings-nav.js +32 -1
- package/settings/settings-nav.js.map +1 -1
- package/settings/useSettingsNavGroups.d.ts +29 -0
- package/settings/useSettingsNavGroups.d.ts.map +1 -0
- package/settings/useSettingsNavGroups.js +61 -0
- package/settings/useSettingsNavGroups.js.map +1 -0
- package/skill/SkillDetailView.d.ts.map +1 -1
- package/skill/SkillDetailView.js +4 -3
- package/skill/SkillDetailView.js.map +1 -1
- package/src/access/__tests__/useManageAccess.test.tsx +104 -0
- package/src/agent/AgentDetailView.tsx +9 -3
- package/src/agent/steps/ReviewStep.tsx +2 -3
- package/src/billing/BaselineEditor.tsx +619 -0
- package/src/billing/ModelCatalogPanel.tsx +283 -0
- package/src/billing/ModelGovernanceDetail.tsx +289 -0
- package/src/billing/OperatorAccessNotice.tsx +32 -0
- package/src/billing/PricingGovernanceConsole.tsx +465 -0
- package/src/billing/PricingGovernancePanel.tsx +166 -0
- package/src/billing/RetireConfirm.tsx +82 -0
- package/src/billing/__tests__/ModelCatalogPanel.test.tsx +253 -0
- package/src/billing/__tests__/PricingGovernanceConsole.test.tsx +410 -0
- package/src/billing/__tests__/useModelGovernanceView.test.tsx +308 -0
- package/src/billing/form-primitives.tsx +68 -0
- package/src/billing/governance-primitives.tsx +133 -0
- package/src/billing/index.ts +37 -0
- package/src/billing/pricing-format.ts +53 -0
- package/src/billing/useDecidePricingOverride.ts +78 -0
- package/src/billing/useModelGovernanceView.ts +290 -0
- package/src/billing/useModelPricingBaselines.ts +69 -0
- package/src/billing/usePricingGovernance.ts +57 -0
- package/src/billing/useRetireModelPricingBaseline.ts +65 -0
- package/src/billing/useUpsertModelPricingBaseline.ts +72 -0
- package/src/channel/AgentChannelsPanel.tsx +27 -1
- package/src/composer/SessionComposer.tsx +1 -1
- package/src/cursor-accounts/CursorAccountEditor.tsx +181 -0
- package/src/cursor-accounts/CursorAccountsAccessNotice.tsx +36 -0
- package/src/cursor-accounts/CursorAccountsConsole.tsx +810 -0
- package/src/cursor-accounts/__tests__/CursorAccountsConsole.test.tsx +384 -0
- package/src/cursor-accounts/cursor-account-format.ts +29 -0
- package/src/cursor-accounts/index.ts +29 -0
- package/src/cursor-accounts/useCursorAccountView.ts +49 -0
- package/src/cursor-accounts/useCursorAccounts.ts +49 -0
- package/src/cursor-accounts/useCursorMemberKeyActions.ts +106 -0
- package/src/cursor-accounts/useDeleteCursorAccount.ts +62 -0
- package/src/cursor-accounts/useSyncCursorAccount.ts +54 -0
- package/src/cursor-accounts/useUpsertCursorAccount.ts +57 -0
- package/src/datastore/CollectionRecordsBrowser.tsx +544 -0
- package/src/datastore/CollectionSchemaView.tsx +247 -0
- package/src/datastore/DatastoreDetailView.tsx +201 -0
- package/src/datastore/DatastoreSyncReport.tsx +105 -0
- package/src/datastore/DeleteDatastoreDialog.tsx +202 -0
- package/src/datastore/FieldValueControl.tsx +289 -0
- package/src/datastore/RecordFilterBuilder.tsx +411 -0
- package/src/datastore/RecordFormPanel.tsx +432 -0
- package/src/datastore/__tests__/CollectionRecordsBrowser.test.tsx +207 -0
- package/src/datastore/__tests__/DeleteDatastoreDialog.test.tsx +133 -0
- package/src/datastore/__tests__/FieldValueControl.test.tsx +160 -0
- package/src/datastore/__tests__/RecordFilterBuilder.test.tsx +141 -0
- package/src/datastore/__tests__/RecordFormPanel.test.tsx +227 -0
- package/src/datastore/__tests__/recordFilter.test.ts +156 -0
- package/src/datastore/__tests__/recordMutations.test.tsx +195 -0
- package/src/datastore/__tests__/recordValues.test.ts +359 -0
- package/src/datastore/__tests__/schemaAndSyncViews.test.tsx +142 -0
- package/src/datastore/__tests__/useDatastoreDescription.test.tsx +143 -0
- package/src/datastore/__tests__/useRecordCollection.test.tsx +250 -0
- package/src/datastore/__tests__/useRecordList.test.tsx +85 -0
- package/src/datastore/index.ts +111 -0
- package/src/datastore/recordFilter.ts +140 -0
- package/src/datastore/recordValues.ts +327 -0
- package/src/datastore/useDatastore.ts +67 -0
- package/src/datastore/useDatastoreCount.ts +67 -0
- package/src/datastore/useDatastoreDescription.ts +90 -0
- package/src/datastore/useDatastoreList.ts +79 -0
- package/src/datastore/useDatastoreSearch.ts +39 -0
- package/src/datastore/useDeleteDatastore.ts +87 -0
- package/src/datastore/useDeleteRecord.ts +77 -0
- package/src/datastore/useInsertRecord.ts +92 -0
- package/src/datastore/useRecordCollection.ts +256 -0
- package/src/datastore/useRecordList.ts +131 -0
- package/src/datastore/useUpdateRecord.ts +95 -0
- package/src/environment/EnvironmentListPanel.tsx +24 -0
- package/src/execution/__tests__/useArtifactInspection.test.tsx +12 -2
- package/src/execution/__tests__/useLiveAgentExecution.test.tsx +125 -0
- package/src/execution/index.ts +4 -7
- package/src/execution/useLiveAgentExecution.ts +41 -3
- package/src/iam-policy/__tests__/useCheckPermission.test.tsx +221 -0
- package/src/iam-policy/index.ts +1 -0
- package/src/iam-policy/useCheckPermission.ts +45 -19
- package/src/index.ts +167 -18
- package/src/internal/__tests__/useInViewport.test.tsx +115 -0
- package/src/internal/useInViewport.ts +63 -0
- package/src/library/VisibilitySelector.tsx +50 -9
- package/src/library/__tests__/VisibilitySelector.test.tsx +38 -0
- package/src/library/index.ts +4 -21
- package/src/library/useApplyResource.ts +27 -34
- package/src/library/useExportResource.ts +21 -40
- package/src/manifest/ApplyManifestDialog.tsx +315 -0
- package/src/manifest/EditResourceYamlDialog.tsx +265 -0
- package/src/manifest/RedactedSecretsNotice.tsx +30 -0
- package/src/manifest/YamlEditor.tsx +272 -0
- package/src/manifest/__tests__/EditResourceYamlDialog.test.tsx +118 -0
- package/src/manifest/__tests__/useApplyManifest.test.tsx +237 -0
- package/src/manifest/__tests__/useEditResourceYaml.test.tsx +252 -0
- package/src/manifest/index.ts +33 -0
- package/src/manifest/useApplyManifest.ts +270 -0
- package/src/manifest/useEditResourceYaml.ts +273 -0
- package/src/mcp-server/McpServerDetailView.tsx +7 -3
- package/src/mcp-server/steps/ReviewStep.tsx +2 -3
- package/src/resource-creation/templates/workflow-templates.ts +4 -4
- package/src/session/SessionViewer.tsx +7 -1
- package/src/session/__tests__/audienceWiring.test.tsx +31 -1
- package/src/session/audience.ts +6 -1
- package/src/session/useEditSessionPrep.ts +3 -3
- package/src/settings/__tests__/useSettingsNavGroups.test.tsx +138 -0
- package/src/settings/index.ts +5 -1
- package/src/settings/settings-nav.ts +43 -0
- package/src/settings/useSettingsNavGroups.ts +81 -0
- package/src/skill/SkillDetailView.tsx +7 -3
- package/src/workflow/WorkflowAgentCallTranscript.tsx +279 -0
- package/src/workflow/WorkflowDetailView.tsx +7 -3
- package/src/workflow/WorkflowExecutionViewer.tsx +20 -77
- package/src/workflow/WorkflowTaskApprovalSummary.tsx +45 -8
- package/src/workflow/WorkflowYamlEditor.tsx +6 -270
- package/src/workflow/__tests__/WorkflowAgentCallTranscript.liveregion.test.tsx +124 -0
- package/src/workflow/__tests__/{WorkflowAgentExecutionDocument.test.tsx → WorkflowAgentCallTranscript.test.tsx} +146 -121
- package/src/workflow/__tests__/WorkflowExecutionViewer.approvals.test.tsx +81 -220
- package/src/workflow/__tests__/WorkflowExecutionViewer.reconciliation.test.tsx +17 -16
- package/src/workflow/__tests__/WorkflowTaskApprovalSummary.test.tsx +52 -2
- package/src/workflow/__tests__/WorkflowTaskThread.test.tsx +168 -185
- package/src/workflow/__tests__/agent-call-live-experience.test.ts +4 -4
- package/src/workflow/__tests__/task-approval.test.ts +119 -0
- package/src/workflow/__tests__/task-presentation.test.ts +35 -1
- package/src/workflow/__tests__/useWorkflowExecutionPanel.test.ts +0 -57
- package/src/workflow/index.ts +6 -3
- package/src/workflow/task-detail/index.ts +3 -0
- package/src/workflow/task-detail/task-approval.ts +95 -1
- package/src/workflow/thread/WorkflowTaskThread.tsx +96 -252
- package/src/workflow/thread/task-presentation.ts +8 -2
- package/src/workflow/useWorkflowExecutionPanel.ts +0 -47
- package/styles.css +1 -1
- package/workflow/CanvasTransitionEdge.d.ts +1 -1
- package/workflow/WorkflowAgentCallTranscript.d.ts +87 -0
- package/workflow/WorkflowAgentCallTranscript.d.ts.map +1 -0
- package/workflow/WorkflowAgentCallTranscript.js +98 -0
- package/workflow/WorkflowAgentCallTranscript.js.map +1 -0
- package/workflow/WorkflowDetailView.d.ts.map +1 -1
- package/workflow/WorkflowDetailView.js +4 -3
- package/workflow/WorkflowDetailView.js.map +1 -1
- package/workflow/WorkflowExecutionViewer.d.ts.map +1 -1
- package/workflow/WorkflowExecutionViewer.js +23 -52
- package/workflow/WorkflowExecutionViewer.js.map +1 -1
- package/workflow/WorkflowTaskApprovalSummary.d.ts +1 -1
- package/workflow/WorkflowTaskApprovalSummary.d.ts.map +1 -1
- package/workflow/WorkflowTaskApprovalSummary.js +18 -1
- package/workflow/WorkflowTaskApprovalSummary.js.map +1 -1
- package/workflow/WorkflowYamlEditor.d.ts +2 -42
- package/workflow/WorkflowYamlEditor.d.ts.map +1 -1
- package/workflow/WorkflowYamlEditor.js +5 -214
- package/workflow/WorkflowYamlEditor.js.map +1 -1
- package/workflow/index.d.ts +2 -2
- package/workflow/index.d.ts.map +1 -1
- package/workflow/index.js +2 -2
- package/workflow/index.js.map +1 -1
- package/workflow/task-detail/index.d.ts +1 -1
- package/workflow/task-detail/index.d.ts.map +1 -1
- package/workflow/task-detail/index.js +1 -1
- package/workflow/task-detail/index.js.map +1 -1
- package/workflow/task-detail/task-approval.d.ts +44 -1
- package/workflow/task-detail/task-approval.d.ts.map +1 -1
- package/workflow/task-detail/task-approval.js +47 -0
- package/workflow/task-detail/task-approval.js.map +1 -1
- package/workflow/thread/WorkflowTaskThread.d.ts +17 -25
- package/workflow/thread/WorkflowTaskThread.d.ts.map +1 -1
- package/workflow/thread/WorkflowTaskThread.js +60 -105
- package/workflow/thread/WorkflowTaskThread.js.map +1 -1
- package/workflow/thread/task-presentation.d.ts.map +1 -1
- package/workflow/thread/task-presentation.js +7 -2
- package/workflow/thread/task-presentation.js.map +1 -1
- package/workflow/useWorkflowExecutionPanel.d.ts +0 -12
- package/workflow/useWorkflowExecutionPanel.d.ts.map +1 -1
- package/workflow/useWorkflowExecutionPanel.js +0 -12
- package/workflow/useWorkflowExecutionPanel.js.map +1 -1
- package/execution/agent-execution-document.d.ts +0 -31
- package/execution/agent-execution-document.d.ts.map +0 -1
- package/execution/agent-execution-document.js +0 -48
- package/execution/agent-execution-document.js.map +0 -1
- package/library/ImportResourceDialog.d.ts +0 -43
- package/library/ImportResourceDialog.d.ts.map +0 -1
- package/library/ImportResourceDialog.js +0 -90
- package/library/ImportResourceDialog.js.map +0 -1
- package/library/parse-resource-yaml.d.ts +0 -63
- package/library/parse-resource-yaml.d.ts.map +0 -1
- package/library/parse-resource-yaml.js +0 -407
- package/library/parse-resource-yaml.js.map +0 -1
- package/library/serialize-resource-yaml.d.ts +0 -103
- package/library/serialize-resource-yaml.d.ts.map +0 -1
- package/library/serialize-resource-yaml.js +0 -565
- package/library/serialize-resource-yaml.js.map +0 -1
- package/library/useImportResource.d.ts +0 -84
- package/library/useImportResource.d.ts.map +0 -1
- package/library/useImportResource.js +0 -188
- package/library/useImportResource.js.map +0 -1
- package/src/execution/__tests__/agent-execution-document.test.ts +0 -45
- package/src/execution/agent-execution-document.ts +0 -54
- package/src/library/ImportResourceDialog.tsx +0 -227
- package/src/library/parse-resource-yaml.ts +0 -630
- package/src/library/serialize-resource-yaml.ts +0 -756
- package/src/library/useImportResource.ts +0 -253
- package/src/workflow/WorkflowAgentExecutionDocument.tsx +0 -283
- package/workflow/WorkflowAgentExecutionDocument.d.ts +0 -79
- package/workflow/WorkflowAgentExecutionDocument.d.ts.map +0 -1
- package/workflow/WorkflowAgentExecutionDocument.js +0 -87
- package/workflow/WorkflowAgentExecutionDocument.js.map +0 -1
|
@@ -0,0 +1,810 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
|
|
3
|
+
import { useCallback, useState } from "react";
|
|
4
|
+
import { cn } from "@stigmer/theme";
|
|
5
|
+
import { getUserMessage, isPermissionDenied } from "@stigmer/sdk";
|
|
6
|
+
import type { CursorAccount } from "@stigmer/protos/ai/stigmer/platform/cursoraccount/v1/cursor_account_pb";
|
|
7
|
+
import {
|
|
8
|
+
CursorMemberKeyState,
|
|
9
|
+
type CursorAccountSummary,
|
|
10
|
+
type CursorMemberKeyView,
|
|
11
|
+
} from "@stigmer/protos/ai/stigmer/platform/cursoraccount/v1/io_pb";
|
|
12
|
+
import { Button } from "../button/index.js";
|
|
13
|
+
import { INPUT_CLASSES } from "../billing/form-primitives.js";
|
|
14
|
+
import { toError } from "../internal/toError.js";
|
|
15
|
+
import { CursorAccountEditor } from "./CursorAccountEditor.js";
|
|
16
|
+
import { CursorAccountsAccessNotice } from "./CursorAccountsAccessNotice.js";
|
|
17
|
+
import { formatSpendMicros, formatSyncTime } from "./cursor-account-format.js";
|
|
18
|
+
import { useCursorAccounts } from "./useCursorAccounts.js";
|
|
19
|
+
import { useCursorAccountView } from "./useCursorAccountView.js";
|
|
20
|
+
import { useCursorMemberKeyActions } from "./useCursorMemberKeyActions.js";
|
|
21
|
+
import { useDeleteCursorAccount } from "./useDeleteCursorAccount.js";
|
|
22
|
+
import { useSyncCursorAccount } from "./useSyncCursorAccount.js";
|
|
23
|
+
import { useUpsertCursorAccount } from "./useUpsertCursorAccount.js";
|
|
24
|
+
|
|
25
|
+
/** Props for {@link CursorAccountsConsole}. */
|
|
26
|
+
export interface CursorAccountsConsoleProps {
|
|
27
|
+
/** Additional CSS class names. */
|
|
28
|
+
readonly className?: string;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
type Flow =
|
|
32
|
+
| { readonly phase: "list" }
|
|
33
|
+
| { readonly phase: "create" }
|
|
34
|
+
| { readonly phase: "detail"; readonly accountId: string; readonly editing: boolean };
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* The platform-operator console for managed Cursor accounts: the Cursor
|
|
38
|
+
* teams (admin keys, member execution keys, org assignments) that back
|
|
39
|
+
* the cursor harness, with roster coverage and per-member cycle spend
|
|
40
|
+
* from the hourly sync.
|
|
41
|
+
*
|
|
42
|
+
* - **List** — every account with routability at a glance (an account
|
|
43
|
+
* with zero enabled member keys cannot serve executions).
|
|
44
|
+
* - **Detail** — org assignments, the member-key panel (add / disable /
|
|
45
|
+
* remove, each key joined with its owner's roster state and spend),
|
|
46
|
+
* coverage gaps (active members without keys), and "Sync now".
|
|
47
|
+
*
|
|
48
|
+
* Requires `can_manage_cursor_accounts` on `platform:stigmer` —
|
|
49
|
+
* non-operators see the designed access notice. Key material never
|
|
50
|
+
* reaches this component; the server redacts it on every read.
|
|
51
|
+
*
|
|
52
|
+
* @example
|
|
53
|
+
* ```tsx
|
|
54
|
+
* <CursorAccountsConsole />
|
|
55
|
+
* ```
|
|
56
|
+
*/
|
|
57
|
+
export function CursorAccountsConsole({ className }: CursorAccountsConsoleProps) {
|
|
58
|
+
const [flow, setFlow] = useState<Flow>({ phase: "list" });
|
|
59
|
+
const list = useCursorAccounts();
|
|
60
|
+
|
|
61
|
+
const backToList = useCallback(() => setFlow({ phase: "list" }), []);
|
|
62
|
+
|
|
63
|
+
if (list.isLoading) {
|
|
64
|
+
return (
|
|
65
|
+
<div className={cn("space-y-2", className)} aria-busy="true">
|
|
66
|
+
<div className="h-4 w-40 animate-pulse rounded bg-muted-subtle" />
|
|
67
|
+
{Array.from({ length: 3 }, (_, i) => (
|
|
68
|
+
<div key={i} className="h-10 animate-pulse rounded-lg bg-muted-subtle" />
|
|
69
|
+
))}
|
|
70
|
+
</div>
|
|
71
|
+
);
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
if (list.error) {
|
|
75
|
+
// A non-operator landing here is expected (the route is reachable by
|
|
76
|
+
// URL) — show the designed access notice, not a raw RPC error.
|
|
77
|
+
if (isPermissionDenied(list.error)) {
|
|
78
|
+
return <CursorAccountsAccessNotice className={className} />;
|
|
79
|
+
}
|
|
80
|
+
return (
|
|
81
|
+
<p className={cn("text-destructive text-xs", className)} role="alert">
|
|
82
|
+
{getUserMessage(list.error)}
|
|
83
|
+
</p>
|
|
84
|
+
);
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
if (flow.phase === "create") {
|
|
88
|
+
return (
|
|
89
|
+
<CreatePane
|
|
90
|
+
className={className}
|
|
91
|
+
onSaved={() => {
|
|
92
|
+
list.refetch();
|
|
93
|
+
backToList();
|
|
94
|
+
}}
|
|
95
|
+
onCancel={backToList}
|
|
96
|
+
/>
|
|
97
|
+
);
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
if (flow.phase === "detail") {
|
|
101
|
+
return (
|
|
102
|
+
<AccountDetail
|
|
103
|
+
className={className}
|
|
104
|
+
accountId={flow.accountId}
|
|
105
|
+
editing={flow.editing}
|
|
106
|
+
onEditingChange={(editing) =>
|
|
107
|
+
setFlow({ phase: "detail", accountId: flow.accountId, editing })
|
|
108
|
+
}
|
|
109
|
+
onDeleted={() => {
|
|
110
|
+
list.refetch();
|
|
111
|
+
backToList();
|
|
112
|
+
}}
|
|
113
|
+
onChanged={list.refetch}
|
|
114
|
+
onBack={backToList}
|
|
115
|
+
/>
|
|
116
|
+
);
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
const accounts = list.accounts?.accounts ?? [];
|
|
120
|
+
|
|
121
|
+
return (
|
|
122
|
+
<div className={cn("space-y-3", className)}>
|
|
123
|
+
<div className="flex items-center justify-between gap-3">
|
|
124
|
+
<h3 className="text-sm font-semibold text-foreground">Cursor accounts</h3>
|
|
125
|
+
<Button size="sm" onClick={() => setFlow({ phase: "create" })}>
|
|
126
|
+
Add account
|
|
127
|
+
</Button>
|
|
128
|
+
</div>
|
|
129
|
+
|
|
130
|
+
<div className="rounded-lg border border-border bg-card">
|
|
131
|
+
<div
|
|
132
|
+
aria-hidden="true"
|
|
133
|
+
className="grid grid-cols-[2fr_1fr_1fr_1fr_1fr] gap-2 border-b border-border px-3 py-2 text-[11px] font-medium text-muted-foreground"
|
|
134
|
+
>
|
|
135
|
+
<span>Account</span>
|
|
136
|
+
<span>Orgs</span>
|
|
137
|
+
<span>Status</span>
|
|
138
|
+
<span>Execution keys</span>
|
|
139
|
+
<span className="text-right">Last synced</span>
|
|
140
|
+
</div>
|
|
141
|
+
{accounts.length === 0 ? (
|
|
142
|
+
<p className="px-3 py-2 text-xs text-muted-foreground">
|
|
143
|
+
No Cursor accounts yet. Add one with its team Admin API key, then
|
|
144
|
+
add member execution keys to make it routable.
|
|
145
|
+
</p>
|
|
146
|
+
) : (
|
|
147
|
+
<ul role="list" aria-label="Cursor accounts" className="m-0 list-none p-0">
|
|
148
|
+
{accounts.map((summary) => (
|
|
149
|
+
<AccountRow
|
|
150
|
+
key={summary.account?.accountId}
|
|
151
|
+
summary={summary}
|
|
152
|
+
onOpen={() =>
|
|
153
|
+
setFlow({
|
|
154
|
+
phase: "detail",
|
|
155
|
+
accountId: summary.account?.accountId ?? "",
|
|
156
|
+
editing: false,
|
|
157
|
+
})
|
|
158
|
+
}
|
|
159
|
+
/>
|
|
160
|
+
))}
|
|
161
|
+
</ul>
|
|
162
|
+
)}
|
|
163
|
+
</div>
|
|
164
|
+
</div>
|
|
165
|
+
);
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
// ---------------------------------------------------------------------------
|
|
169
|
+
// List row (internal)
|
|
170
|
+
// ---------------------------------------------------------------------------
|
|
171
|
+
|
|
172
|
+
function AccountRow({
|
|
173
|
+
summary,
|
|
174
|
+
onOpen,
|
|
175
|
+
}: {
|
|
176
|
+
readonly summary: CursorAccountSummary;
|
|
177
|
+
readonly onOpen: () => void;
|
|
178
|
+
}) {
|
|
179
|
+
const account = summary.account;
|
|
180
|
+
if (!account) return null;
|
|
181
|
+
|
|
182
|
+
return (
|
|
183
|
+
<li className="border-b border-border last:border-b-0">
|
|
184
|
+
<button
|
|
185
|
+
type="button"
|
|
186
|
+
onClick={onOpen}
|
|
187
|
+
className={cn(
|
|
188
|
+
"grid w-full grid-cols-[2fr_1fr_1fr_1fr_1fr] items-center gap-2 px-3 py-2 text-left text-xs",
|
|
189
|
+
"transition-colors hover:bg-accent",
|
|
190
|
+
"focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring",
|
|
191
|
+
)}
|
|
192
|
+
>
|
|
193
|
+
<span className="min-w-0">
|
|
194
|
+
<span className="block truncate font-medium text-foreground">
|
|
195
|
+
{account.displayName}
|
|
196
|
+
</span>
|
|
197
|
+
{account.isPlatformDefault && (
|
|
198
|
+
<span className="block text-[11px] text-muted-foreground">
|
|
199
|
+
platform default
|
|
200
|
+
</span>
|
|
201
|
+
)}
|
|
202
|
+
</span>
|
|
203
|
+
<span className="text-muted-foreground">
|
|
204
|
+
{account.orgIds.length > 0 ? account.orgIds.length : "—"}
|
|
205
|
+
</span>
|
|
206
|
+
<span>
|
|
207
|
+
<StateBadge
|
|
208
|
+
tone={account.enabled ? "ok" : "muted"}
|
|
209
|
+
label={account.enabled ? "Enabled" : "Disabled"}
|
|
210
|
+
/>
|
|
211
|
+
</span>
|
|
212
|
+
<span>
|
|
213
|
+
{summary.enabledKeyCount > 0 ? (
|
|
214
|
+
<span className="text-muted-foreground">{summary.enabledKeyCount}</span>
|
|
215
|
+
) : (
|
|
216
|
+
<StateBadge tone="warn" label="Not routable" />
|
|
217
|
+
)}
|
|
218
|
+
</span>
|
|
219
|
+
<span className="text-right text-muted-foreground">
|
|
220
|
+
{formatSyncTime(summary.lastSyncedAt)}
|
|
221
|
+
</span>
|
|
222
|
+
</button>
|
|
223
|
+
</li>
|
|
224
|
+
);
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
// ---------------------------------------------------------------------------
|
|
228
|
+
// Create pane (internal)
|
|
229
|
+
// ---------------------------------------------------------------------------
|
|
230
|
+
|
|
231
|
+
function CreatePane({
|
|
232
|
+
className,
|
|
233
|
+
onSaved,
|
|
234
|
+
onCancel,
|
|
235
|
+
}: {
|
|
236
|
+
readonly className?: string;
|
|
237
|
+
readonly onSaved: () => void;
|
|
238
|
+
readonly onCancel: () => void;
|
|
239
|
+
}) {
|
|
240
|
+
const { upsert, isSubmitting, error } = useUpsertCursorAccount();
|
|
241
|
+
|
|
242
|
+
return (
|
|
243
|
+
<div className={className}>
|
|
244
|
+
<CursorAccountEditor
|
|
245
|
+
initial={null}
|
|
246
|
+
isSubmitting={isSubmitting}
|
|
247
|
+
submitError={error}
|
|
248
|
+
onSubmit={(account) => {
|
|
249
|
+
void upsert(account).then(onSaved, () => {
|
|
250
|
+
// Surfaced via submitError.
|
|
251
|
+
});
|
|
252
|
+
}}
|
|
253
|
+
onCancel={onCancel}
|
|
254
|
+
/>
|
|
255
|
+
</div>
|
|
256
|
+
);
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
// ---------------------------------------------------------------------------
|
|
260
|
+
// Detail pane (internal)
|
|
261
|
+
// ---------------------------------------------------------------------------
|
|
262
|
+
|
|
263
|
+
function AccountDetail({
|
|
264
|
+
className,
|
|
265
|
+
accountId,
|
|
266
|
+
editing,
|
|
267
|
+
onEditingChange,
|
|
268
|
+
onDeleted,
|
|
269
|
+
onChanged,
|
|
270
|
+
onBack,
|
|
271
|
+
}: {
|
|
272
|
+
readonly className?: string;
|
|
273
|
+
readonly accountId: string;
|
|
274
|
+
readonly editing: boolean;
|
|
275
|
+
readonly onEditingChange: (editing: boolean) => void;
|
|
276
|
+
readonly onDeleted: () => void;
|
|
277
|
+
readonly onChanged: () => void;
|
|
278
|
+
readonly onBack: () => void;
|
|
279
|
+
}) {
|
|
280
|
+
const detail = useCursorAccountView(accountId);
|
|
281
|
+
const { upsert, isSubmitting: isSaving, error: saveError, clearError: clearSaveError } =
|
|
282
|
+
useUpsertCursorAccount();
|
|
283
|
+
const { remove, isSubmitting: isDeleting, error: deleteError } =
|
|
284
|
+
useDeleteCursorAccount();
|
|
285
|
+
const { sync, isSyncing, error: syncError } = useSyncCursorAccount();
|
|
286
|
+
const keyActions = useCursorMemberKeyActions();
|
|
287
|
+
|
|
288
|
+
const refreshAll = useCallback(() => {
|
|
289
|
+
detail.refetch();
|
|
290
|
+
onChanged();
|
|
291
|
+
}, [detail.refetch, onChanged]);
|
|
292
|
+
|
|
293
|
+
// After a bulk import, run the roster sync automatically so key badges
|
|
294
|
+
// (Active / Owner unknown / Owner left team) are current without a
|
|
295
|
+
// manual "Sync now". Sync failure still refreshes — the keys ARE added
|
|
296
|
+
// — and is surfaced via syncError.
|
|
297
|
+
const syncAfterImport = useCallback(() => {
|
|
298
|
+
void sync(accountId).then(refreshAll, refreshAll);
|
|
299
|
+
}, [sync, accountId, refreshAll]);
|
|
300
|
+
|
|
301
|
+
if (detail.isLoading) {
|
|
302
|
+
return (
|
|
303
|
+
<div className={cn("space-y-2", className)} aria-busy="true">
|
|
304
|
+
<div className="h-4 w-40 animate-pulse rounded bg-muted-subtle" />
|
|
305
|
+
<div className="h-24 animate-pulse rounded-lg bg-muted-subtle" />
|
|
306
|
+
</div>
|
|
307
|
+
);
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
if (detail.error || !detail.view?.account) {
|
|
311
|
+
return (
|
|
312
|
+
<div className={cn("space-y-2", className)}>
|
|
313
|
+
<p className="text-destructive text-xs" role="alert">
|
|
314
|
+
{detail.error ? getUserMessage(detail.error) : "Account not found."}
|
|
315
|
+
</p>
|
|
316
|
+
<Button size="sm" variant="outline" onClick={onBack}>
|
|
317
|
+
Back to accounts
|
|
318
|
+
</Button>
|
|
319
|
+
</div>
|
|
320
|
+
);
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
const view = detail.view;
|
|
324
|
+
const account = view.account as CursorAccount;
|
|
325
|
+
|
|
326
|
+
if (editing) {
|
|
327
|
+
return (
|
|
328
|
+
<div className={className}>
|
|
329
|
+
<CursorAccountEditor
|
|
330
|
+
initial={account}
|
|
331
|
+
isSubmitting={isSaving}
|
|
332
|
+
submitError={saveError}
|
|
333
|
+
onSubmit={(edited) => {
|
|
334
|
+
void upsert(edited).then(() => {
|
|
335
|
+
refreshAll();
|
|
336
|
+
onEditingChange(false);
|
|
337
|
+
}, () => {
|
|
338
|
+
// Surfaced via submitError.
|
|
339
|
+
});
|
|
340
|
+
}}
|
|
341
|
+
onCancel={() => {
|
|
342
|
+
clearSaveError();
|
|
343
|
+
onEditingChange(false);
|
|
344
|
+
}}
|
|
345
|
+
/>
|
|
346
|
+
</div>
|
|
347
|
+
);
|
|
348
|
+
}
|
|
349
|
+
|
|
350
|
+
return (
|
|
351
|
+
<div className={cn("space-y-4", className)}>
|
|
352
|
+
<div className="flex flex-wrap items-center justify-between gap-2">
|
|
353
|
+
<div>
|
|
354
|
+
<h3 className="text-sm font-semibold text-foreground">
|
|
355
|
+
{account.displayName}
|
|
356
|
+
</h3>
|
|
357
|
+
<p className="text-[11px] text-muted-foreground">
|
|
358
|
+
{account.orgIds.length > 0
|
|
359
|
+
? `Serves ${account.orgIds.length} org(s): ${account.orgIds.join(", ")}`
|
|
360
|
+
: account.isPlatformDefault
|
|
361
|
+
? "Platform default — serves all unassigned orgs"
|
|
362
|
+
: "No org assignments"}
|
|
363
|
+
{" · "}
|
|
364
|
+
{account.enabled ? "enabled" : "disabled"}
|
|
365
|
+
{" · synced "}
|
|
366
|
+
{formatSyncTime(view.snapshot?.syncedAt)}
|
|
367
|
+
</p>
|
|
368
|
+
</div>
|
|
369
|
+
<div className="flex gap-2">
|
|
370
|
+
<Button size="sm" variant="outline" onClick={onBack}>
|
|
371
|
+
Back
|
|
372
|
+
</Button>
|
|
373
|
+
<Button
|
|
374
|
+
size="sm"
|
|
375
|
+
variant="outline"
|
|
376
|
+
disabled={isSyncing}
|
|
377
|
+
onClick={() => {
|
|
378
|
+
void sync(accountId).then(refreshAll, () => {
|
|
379
|
+
// Surfaced via syncError.
|
|
380
|
+
});
|
|
381
|
+
}}
|
|
382
|
+
>
|
|
383
|
+
{isSyncing ? "Syncing…" : "Sync now"}
|
|
384
|
+
</Button>
|
|
385
|
+
<Button size="sm" variant="outline" onClick={() => onEditingChange(true)}>
|
|
386
|
+
Edit
|
|
387
|
+
</Button>
|
|
388
|
+
<Button
|
|
389
|
+
size="sm"
|
|
390
|
+
variant="destructive"
|
|
391
|
+
disabled={isDeleting}
|
|
392
|
+
onClick={() => {
|
|
393
|
+
void remove({ accountId }).then(onDeleted, () => {
|
|
394
|
+
// Surfaced via deleteError (incl. the live-pin guard's
|
|
395
|
+
// "disable instead, or force" message).
|
|
396
|
+
});
|
|
397
|
+
}}
|
|
398
|
+
>
|
|
399
|
+
{isDeleting ? "Deleting…" : "Delete"}
|
|
400
|
+
</Button>
|
|
401
|
+
</div>
|
|
402
|
+
</div>
|
|
403
|
+
|
|
404
|
+
{syncError && (
|
|
405
|
+
<p className="text-destructive text-xs" role="alert">
|
|
406
|
+
{getUserMessage(syncError)}
|
|
407
|
+
</p>
|
|
408
|
+
)}
|
|
409
|
+
{deleteError && (
|
|
410
|
+
<p className="text-destructive text-xs" role="alert">
|
|
411
|
+
{getUserMessage(deleteError)}
|
|
412
|
+
</p>
|
|
413
|
+
)}
|
|
414
|
+
{view.snapshot?.syncError && (
|
|
415
|
+
<p className="text-xs text-muted-foreground" role="status">
|
|
416
|
+
Last sync was partial: {view.snapshot.syncError}
|
|
417
|
+
</p>
|
|
418
|
+
)}
|
|
419
|
+
|
|
420
|
+
<MemberKeysPanel
|
|
421
|
+
accountId={accountId}
|
|
422
|
+
keyViews={view.keyViews}
|
|
423
|
+
actions={keyActions}
|
|
424
|
+
onChanged={refreshAll}
|
|
425
|
+
onImported={syncAfterImport}
|
|
426
|
+
/>
|
|
427
|
+
|
|
428
|
+
{view.membersWithoutKeys.length > 0 && (
|
|
429
|
+
<section className="space-y-1">
|
|
430
|
+
<h4 className="text-xs font-semibold text-foreground">
|
|
431
|
+
Members without execution keys
|
|
432
|
+
</h4>
|
|
433
|
+
<p className="text-[11px] text-muted-foreground">
|
|
434
|
+
Active team members Stigmer holds no key for — sessions can never
|
|
435
|
+
run under their identity or included quota.
|
|
436
|
+
</p>
|
|
437
|
+
<ul role="list" className="m-0 list-none space-y-0.5 p-0 text-xs text-muted-foreground">
|
|
438
|
+
{view.membersWithoutKeys.map((member) => (
|
|
439
|
+
<li key={member.email}>
|
|
440
|
+
{member.name || member.email} · {member.email}
|
|
441
|
+
</li>
|
|
442
|
+
))}
|
|
443
|
+
</ul>
|
|
444
|
+
</section>
|
|
445
|
+
)}
|
|
446
|
+
</div>
|
|
447
|
+
);
|
|
448
|
+
}
|
|
449
|
+
|
|
450
|
+
// ---------------------------------------------------------------------------
|
|
451
|
+
// Member keys panel (internal)
|
|
452
|
+
// ---------------------------------------------------------------------------
|
|
453
|
+
|
|
454
|
+
/** One line's outcome from a bulk key import. */
|
|
455
|
+
interface ImportLineResult {
|
|
456
|
+
/** Masked identification of the key (never the full material). */
|
|
457
|
+
readonly keyPreview: string;
|
|
458
|
+
readonly ok: boolean;
|
|
459
|
+
/** Bound email on success; the server/Cursor error on failure. */
|
|
460
|
+
readonly message: string;
|
|
461
|
+
}
|
|
462
|
+
|
|
463
|
+
/** Parse bulk-import text: one key per line, trimmed, deduped. */
|
|
464
|
+
function parseImportKeys(text: string): string[] {
|
|
465
|
+
return [...new Set(text.split(/\r?\n/).map((s) => s.trim()).filter((s) => s !== ""))];
|
|
466
|
+
}
|
|
467
|
+
|
|
468
|
+
function maskKey(key: string, index: number): string {
|
|
469
|
+
return key.length >= 8 ? `key ${index + 1} (…${key.slice(-4)})` : `key ${index + 1}`;
|
|
470
|
+
}
|
|
471
|
+
|
|
472
|
+
function MemberKeysPanel({
|
|
473
|
+
accountId,
|
|
474
|
+
keyViews,
|
|
475
|
+
actions,
|
|
476
|
+
onChanged,
|
|
477
|
+
onImported,
|
|
478
|
+
}: {
|
|
479
|
+
readonly accountId: string;
|
|
480
|
+
readonly keyViews: readonly CursorMemberKeyView[];
|
|
481
|
+
readonly actions: ReturnType<typeof useCursorMemberKeyActions>;
|
|
482
|
+
readonly onChanged: () => void;
|
|
483
|
+
/** Called after a bulk import added at least one key (triggers sync). */
|
|
484
|
+
readonly onImported: () => void;
|
|
485
|
+
}) {
|
|
486
|
+
const [newKey, setNewKey] = useState("");
|
|
487
|
+
const [newLabel, setNewLabel] = useState("");
|
|
488
|
+
const [showImport, setShowImport] = useState(false);
|
|
489
|
+
const [importText, setImportText] = useState("");
|
|
490
|
+
const [isImporting, setIsImporting] = useState(false);
|
|
491
|
+
const [importProgress, setImportProgress] = useState<
|
|
492
|
+
{ readonly done: number; readonly total: number } | null
|
|
493
|
+
>(null);
|
|
494
|
+
const [importResults, setImportResults] = useState<readonly ImportLineResult[] | null>(
|
|
495
|
+
null,
|
|
496
|
+
);
|
|
497
|
+
|
|
498
|
+
const submitNewKey = (e: React.FormEvent) => {
|
|
499
|
+
e.preventDefault();
|
|
500
|
+
if (newKey.trim() === "" || actions.isSubmitting) return;
|
|
501
|
+
void actions
|
|
502
|
+
.addKey({ accountId, apiKey: newKey.trim(), label: newLabel.trim() || undefined })
|
|
503
|
+
.then(() => {
|
|
504
|
+
setNewKey("");
|
|
505
|
+
setNewLabel("");
|
|
506
|
+
onChanged();
|
|
507
|
+
}, () => {
|
|
508
|
+
// Surfaced via actions.error (incl. Cursor's own key-class 401 text).
|
|
509
|
+
});
|
|
510
|
+
};
|
|
511
|
+
|
|
512
|
+
const importKeyCount = parseImportKeys(importText).length;
|
|
513
|
+
|
|
514
|
+
const submitImport = async (e: React.FormEvent) => {
|
|
515
|
+
e.preventDefault();
|
|
516
|
+
const keys = parseImportKeys(importText);
|
|
517
|
+
if (keys.length === 0 || isImporting) return;
|
|
518
|
+
|
|
519
|
+
setIsImporting(true);
|
|
520
|
+
setImportResults(null);
|
|
521
|
+
|
|
522
|
+
// Sequential on purpose: each key is validated live against Cursor's
|
|
523
|
+
// /v1/me, and per-key errors (wrong key class, revoked, duplicate)
|
|
524
|
+
// must be attributable to their line.
|
|
525
|
+
const knownKeyIds = new Set(
|
|
526
|
+
keyViews.map((kv) => kv.key?.keyId).filter((id): id is string => !!id),
|
|
527
|
+
);
|
|
528
|
+
const results: ImportLineResult[] = [];
|
|
529
|
+
const failedKeys: string[] = [];
|
|
530
|
+
for (const [i, key] of keys.entries()) {
|
|
531
|
+
setImportProgress({ done: i, total: keys.length });
|
|
532
|
+
try {
|
|
533
|
+
const account = await actions.addKey({ accountId, apiKey: key });
|
|
534
|
+
const addedKey = account.memberKeys.find((mk) => !knownKeyIds.has(mk.keyId));
|
|
535
|
+
if (addedKey) knownKeyIds.add(addedKey.keyId);
|
|
536
|
+
results.push({
|
|
537
|
+
keyPreview: maskKey(key, i),
|
|
538
|
+
ok: true,
|
|
539
|
+
message: addedKey?.boundEmail
|
|
540
|
+
? `added — bound to ${addedKey.boundEmail}`
|
|
541
|
+
: "added",
|
|
542
|
+
});
|
|
543
|
+
} catch (err) {
|
|
544
|
+
actions.clearError();
|
|
545
|
+
failedKeys.push(key);
|
|
546
|
+
results.push({
|
|
547
|
+
keyPreview: maskKey(key, i),
|
|
548
|
+
ok: false,
|
|
549
|
+
message: getUserMessage(toError(err)),
|
|
550
|
+
});
|
|
551
|
+
}
|
|
552
|
+
}
|
|
553
|
+
|
|
554
|
+
setImportProgress(null);
|
|
555
|
+
setImportResults(results);
|
|
556
|
+
// Failed lines stay in the box so the operator can fix and retry.
|
|
557
|
+
setImportText(failedKeys.join("\n"));
|
|
558
|
+
setIsImporting(false);
|
|
559
|
+
if (failedKeys.length < keys.length) onImported();
|
|
560
|
+
};
|
|
561
|
+
|
|
562
|
+
return (
|
|
563
|
+
<section className="space-y-2">
|
|
564
|
+
<h4 className="text-xs font-semibold text-foreground">Member execution keys</h4>
|
|
565
|
+
|
|
566
|
+
{keyViews.length === 0 ? (
|
|
567
|
+
<p className="text-xs text-muted-foreground" role="status">
|
|
568
|
+
No execution keys — this account is <strong>not routable</strong>.
|
|
569
|
+
Add a member's user-scoped API key below.
|
|
570
|
+
</p>
|
|
571
|
+
) : (
|
|
572
|
+
<ul role="list" aria-label="Member keys" className="m-0 list-none space-y-1 p-0">
|
|
573
|
+
{keyViews.map((keyView) => (
|
|
574
|
+
<MemberKeyRow
|
|
575
|
+
key={keyView.key?.keyId}
|
|
576
|
+
accountId={accountId}
|
|
577
|
+
keyView={keyView}
|
|
578
|
+
actions={actions}
|
|
579
|
+
onChanged={onChanged}
|
|
580
|
+
/>
|
|
581
|
+
))}
|
|
582
|
+
</ul>
|
|
583
|
+
)}
|
|
584
|
+
|
|
585
|
+
{actions.error && (
|
|
586
|
+
<p className="text-destructive text-xs" role="alert">
|
|
587
|
+
{getUserMessage(actions.error)}
|
|
588
|
+
</p>
|
|
589
|
+
)}
|
|
590
|
+
|
|
591
|
+
<form className="flex flex-wrap items-end gap-2" onSubmit={submitNewKey}>
|
|
592
|
+
<label className="block min-w-56 flex-1 space-y-1">
|
|
593
|
+
<span className="text-[11px] font-medium text-muted-foreground">
|
|
594
|
+
User-scoped API key
|
|
595
|
+
</span>
|
|
596
|
+
<input
|
|
597
|
+
className={INPUT_CLASSES}
|
|
598
|
+
type="password"
|
|
599
|
+
value={newKey}
|
|
600
|
+
onChange={(e) => setNewKey(e.target.value)}
|
|
601
|
+
placeholder="the member's personal Cursor API key"
|
|
602
|
+
disabled={actions.isSubmitting}
|
|
603
|
+
autoComplete="off"
|
|
604
|
+
/>
|
|
605
|
+
</label>
|
|
606
|
+
<label className="block min-w-40 space-y-1">
|
|
607
|
+
<span className="text-[11px] font-medium text-muted-foreground">
|
|
608
|
+
Label (optional)
|
|
609
|
+
</span>
|
|
610
|
+
<input
|
|
611
|
+
className={INPUT_CLASSES}
|
|
612
|
+
value={newLabel}
|
|
613
|
+
onChange={(e) => setNewLabel(e.target.value)}
|
|
614
|
+
placeholder="e.g. zane — prod"
|
|
615
|
+
disabled={actions.isSubmitting}
|
|
616
|
+
/>
|
|
617
|
+
</label>
|
|
618
|
+
<Button type="submit" size="sm" disabled={newKey.trim() === "" || actions.isSubmitting}>
|
|
619
|
+
{actions.isSubmitting ? "Verifying…" : "Add key"}
|
|
620
|
+
</Button>
|
|
621
|
+
<Button
|
|
622
|
+
type="button"
|
|
623
|
+
size="sm"
|
|
624
|
+
variant="outline"
|
|
625
|
+
disabled={isImporting}
|
|
626
|
+
onClick={() => {
|
|
627
|
+
setShowImport((v) => !v);
|
|
628
|
+
setImportResults(null);
|
|
629
|
+
}}
|
|
630
|
+
>
|
|
631
|
+
{showImport ? "Hide import" : "Import keys"}
|
|
632
|
+
</Button>
|
|
633
|
+
</form>
|
|
634
|
+
|
|
635
|
+
{showImport && (
|
|
636
|
+
<form className="space-y-2 rounded-md border border-border bg-card p-3" onSubmit={submitImport}>
|
|
637
|
+
<label className="block space-y-1">
|
|
638
|
+
<span className="text-[11px] font-medium text-muted-foreground">
|
|
639
|
+
Bulk import — one user-scoped API key per line
|
|
640
|
+
</span>
|
|
641
|
+
<textarea
|
|
642
|
+
className={cn(INPUT_CLASSES, "min-h-24 font-mono")}
|
|
643
|
+
value={importText}
|
|
644
|
+
onChange={(e) => setImportText(e.target.value)}
|
|
645
|
+
placeholder={"key_...\nkey_...\nkey_..."}
|
|
646
|
+
disabled={isImporting}
|
|
647
|
+
autoComplete="off"
|
|
648
|
+
spellCheck={false}
|
|
649
|
+
/>
|
|
650
|
+
</label>
|
|
651
|
+
<p className="text-[11px] text-muted-foreground">
|
|
652
|
+
Each key is verified against Cursor and bound to its owning team
|
|
653
|
+
member, one at a time. Lines that fail stay in the box so you can
|
|
654
|
+
fix and retry them. A roster sync runs automatically afterwards,
|
|
655
|
+
so the key badges reflect current team membership.
|
|
656
|
+
</p>
|
|
657
|
+
<div className="flex items-center gap-2">
|
|
658
|
+
<Button type="submit" size="sm" disabled={importKeyCount === 0 || isImporting}>
|
|
659
|
+
{isImporting && importProgress
|
|
660
|
+
? `Importing ${importProgress.done + 1} of ${importProgress.total}…`
|
|
661
|
+
: importKeyCount > 0
|
|
662
|
+
? `Import ${importKeyCount} ${importKeyCount === 1 ? "key" : "keys"}`
|
|
663
|
+
: "Import keys"}
|
|
664
|
+
</Button>
|
|
665
|
+
<Button
|
|
666
|
+
type="button"
|
|
667
|
+
size="sm"
|
|
668
|
+
variant="outline"
|
|
669
|
+
disabled={isImporting}
|
|
670
|
+
onClick={() => {
|
|
671
|
+
setShowImport(false);
|
|
672
|
+
setImportText("");
|
|
673
|
+
setImportResults(null);
|
|
674
|
+
}}
|
|
675
|
+
>
|
|
676
|
+
Close
|
|
677
|
+
</Button>
|
|
678
|
+
</div>
|
|
679
|
+
{importResults && (
|
|
680
|
+
<ul
|
|
681
|
+
role="list"
|
|
682
|
+
aria-label="Import results"
|
|
683
|
+
className="m-0 list-none space-y-0.5 p-0 text-[11px]"
|
|
684
|
+
>
|
|
685
|
+
{importResults.map((result) => (
|
|
686
|
+
<li
|
|
687
|
+
key={result.keyPreview}
|
|
688
|
+
className={result.ok ? "text-muted-foreground" : "text-destructive"}
|
|
689
|
+
>
|
|
690
|
+
{result.keyPreview}: {result.message}
|
|
691
|
+
</li>
|
|
692
|
+
))}
|
|
693
|
+
</ul>
|
|
694
|
+
)}
|
|
695
|
+
</form>
|
|
696
|
+
)}
|
|
697
|
+
</section>
|
|
698
|
+
);
|
|
699
|
+
}
|
|
700
|
+
|
|
701
|
+
function MemberKeyRow({
|
|
702
|
+
accountId,
|
|
703
|
+
keyView,
|
|
704
|
+
actions,
|
|
705
|
+
onChanged,
|
|
706
|
+
}: {
|
|
707
|
+
readonly accountId: string;
|
|
708
|
+
readonly keyView: CursorMemberKeyView;
|
|
709
|
+
readonly actions: ReturnType<typeof useCursorMemberKeyActions>;
|
|
710
|
+
readonly onChanged: () => void;
|
|
711
|
+
}) {
|
|
712
|
+
const key = keyView.key;
|
|
713
|
+
if (!key) return null;
|
|
714
|
+
|
|
715
|
+
return (
|
|
716
|
+
<li className="flex flex-wrap items-center justify-between gap-2 rounded-md border border-border bg-card px-3 py-2">
|
|
717
|
+
<span className="min-w-0">
|
|
718
|
+
<span className="block truncate text-xs font-medium text-foreground">
|
|
719
|
+
{key.boundEmail}
|
|
720
|
+
{key.label ? ` · ${key.label}` : ""}
|
|
721
|
+
</span>
|
|
722
|
+
<span className="block text-[11px] text-muted-foreground">
|
|
723
|
+
{key.cursorKeyName || "unnamed key"}
|
|
724
|
+
{keyView.spend
|
|
725
|
+
? ` · ${formatSpendMicros(
|
|
726
|
+
keyView.spend.includedSpendUsdMicros + keyView.spend.overageSpendUsdMicros,
|
|
727
|
+
)} this cycle`
|
|
728
|
+
: ""}
|
|
729
|
+
</span>
|
|
730
|
+
</span>
|
|
731
|
+
<span className="flex items-center gap-2">
|
|
732
|
+
<KeyStateBadge state={keyView.state} enabled={key.enabled} />
|
|
733
|
+
<Button
|
|
734
|
+
size="sm"
|
|
735
|
+
variant="outline"
|
|
736
|
+
disabled={actions.isSubmitting}
|
|
737
|
+
onClick={() => {
|
|
738
|
+
void actions
|
|
739
|
+
.setKeyEnabled(accountId, key.keyId, !key.enabled)
|
|
740
|
+
.then(onChanged, () => {
|
|
741
|
+
// Surfaced via actions.error.
|
|
742
|
+
});
|
|
743
|
+
}}
|
|
744
|
+
>
|
|
745
|
+
{key.enabled ? "Disable" : "Enable"}
|
|
746
|
+
</Button>
|
|
747
|
+
<Button
|
|
748
|
+
size="sm"
|
|
749
|
+
variant="destructive"
|
|
750
|
+
disabled={actions.isSubmitting}
|
|
751
|
+
onClick={() => {
|
|
752
|
+
void actions
|
|
753
|
+
.removeKey({ accountId, keyId: key.keyId })
|
|
754
|
+
.then(onChanged, () => {
|
|
755
|
+
// Surfaced via actions.error (incl. the live-pin guard's
|
|
756
|
+
// "disable instead, or force" message).
|
|
757
|
+
});
|
|
758
|
+
}}
|
|
759
|
+
>
|
|
760
|
+
Remove
|
|
761
|
+
</Button>
|
|
762
|
+
</span>
|
|
763
|
+
</li>
|
|
764
|
+
);
|
|
765
|
+
}
|
|
766
|
+
|
|
767
|
+
// ---------------------------------------------------------------------------
|
|
768
|
+
// Badges (internal)
|
|
769
|
+
// ---------------------------------------------------------------------------
|
|
770
|
+
|
|
771
|
+
function StateBadge({
|
|
772
|
+
tone,
|
|
773
|
+
label,
|
|
774
|
+
}: {
|
|
775
|
+
readonly tone: "ok" | "warn" | "muted";
|
|
776
|
+
readonly label: string;
|
|
777
|
+
}) {
|
|
778
|
+
return (
|
|
779
|
+
<span
|
|
780
|
+
className={cn(
|
|
781
|
+
"inline-block rounded px-1.5 py-0.5 text-[10px] font-medium",
|
|
782
|
+
tone === "ok" && "bg-accent text-primary",
|
|
783
|
+
tone === "warn" && "bg-muted-subtle text-destructive",
|
|
784
|
+
tone === "muted" && "bg-muted-subtle text-muted-foreground",
|
|
785
|
+
)}
|
|
786
|
+
>
|
|
787
|
+
{label}
|
|
788
|
+
</span>
|
|
789
|
+
);
|
|
790
|
+
}
|
|
791
|
+
|
|
792
|
+
function KeyStateBadge({
|
|
793
|
+
state,
|
|
794
|
+
enabled,
|
|
795
|
+
}: {
|
|
796
|
+
readonly state: CursorMemberKeyState;
|
|
797
|
+
readonly enabled: boolean;
|
|
798
|
+
}) {
|
|
799
|
+
if (state === CursorMemberKeyState.member_key_owner_removed) {
|
|
800
|
+
return <StateBadge tone="warn" label="Owner left team" />;
|
|
801
|
+
}
|
|
802
|
+
if (state === CursorMemberKeyState.member_key_owner_unknown) {
|
|
803
|
+
return <StateBadge tone="muted" label="Owner unknown" />;
|
|
804
|
+
}
|
|
805
|
+
return enabled ? (
|
|
806
|
+
<StateBadge tone="ok" label="Active" />
|
|
807
|
+
) : (
|
|
808
|
+
<StateBadge tone="muted" label="Disabled" />
|
|
809
|
+
);
|
|
810
|
+
}
|