@stigmer/react 3.12.4 → 3.12.6
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.js +2 -2
- package/agent/AgentDetailView.js.map +1 -1
- package/agent/index.d.ts +0 -1
- package/agent/index.d.ts.map +1 -1
- package/agent/index.js +0 -1
- package/agent/index.js.map +1 -1
- package/agent/useUpdateAgent.d.ts +3 -3
- package/agent/useUpdateAgent.js +3 -3
- package/agent-instance/AgentInstanceDetailPanel.d.ts.map +1 -1
- package/agent-instance/AgentInstanceDetailPanel.js +5 -7
- package/agent-instance/AgentInstanceDetailPanel.js.map +1 -1
- package/agent-instance/useUpdateAgentInstance.d.ts +1 -1
- package/agent-instance/useUpdateAgentInstance.js +1 -1
- package/attachment/AttachmentChipList.js +16 -6
- package/attachment/AttachmentChipList.js.map +1 -1
- package/attachment/index.d.ts +1 -1
- package/attachment/index.d.ts.map +1 -1
- package/attachment/index.js.map +1 -1
- package/attachment/useAttachments.d.ts +51 -8
- package/attachment/useAttachments.d.ts.map +1 -1
- package/attachment/useAttachments.js +74 -3
- package/attachment/useAttachments.js.map +1 -1
- package/channel/AgentChannelsPanel.d.ts.map +1 -1
- package/channel/AgentChannelsPanel.js +10 -5
- package/channel/AgentChannelsPanel.js.map +1 -1
- package/channel/ChannelRunConfigDialog.d.ts +51 -0
- package/channel/ChannelRunConfigDialog.d.ts.map +1 -0
- package/channel/ChannelRunConfigDialog.js +121 -0
- package/channel/ChannelRunConfigDialog.js.map +1 -0
- package/channel/index.d.ts +2 -0
- package/channel/index.d.ts.map +1 -1
- package/channel/index.js +1 -0
- package/channel/index.js.map +1 -1
- package/channel/useSaveAgentChannel.d.ts.map +1 -1
- package/channel/useSaveAgentChannel.js +6 -3
- package/channel/useSaveAgentChannel.js.map +1 -1
- package/channel-app/ChannelAppDetailPanel.js +9 -9
- package/channel-app/ChannelAppDetailPanel.js.map +1 -1
- package/composer/ComposerToolbar.d.ts +6 -1
- package/composer/ComposerToolbar.d.ts.map +1 -1
- package/composer/ComposerToolbar.js +2 -2
- package/composer/ComposerToolbar.js.map +1 -1
- package/composer/SessionComposer.d.ts +9 -0
- package/composer/SessionComposer.d.ts.map +1 -1
- package/composer/SessionComposer.js +39 -13
- package/composer/SessionComposer.js.map +1 -1
- package/conversation/ConversationComposer.d.ts +19 -3
- package/conversation/ConversationComposer.d.ts.map +1 -1
- package/conversation/ConversationComposer.js +4 -4
- package/conversation/ConversationComposer.js.map +1 -1
- package/conversation/ConversationTemplatePickerDialog.d.ts +63 -0
- package/conversation/ConversationTemplatePickerDialog.d.ts.map +1 -0
- package/conversation/ConversationTemplatePickerDialog.js +151 -0
- package/conversation/ConversationTemplatePickerDialog.js.map +1 -0
- package/conversation/ConversationsWorkbench.d.ts.map +1 -1
- package/conversation/ConversationsWorkbench.js +16 -5
- package/conversation/ConversationsWorkbench.js.map +1 -1
- package/conversation/index.d.ts +3 -1
- package/conversation/index.d.ts.map +1 -1
- package/conversation/index.js +1 -0
- package/conversation/index.js.map +1 -1
- package/conversation/useConversationParticipation.d.ts +41 -4
- package/conversation/useConversationParticipation.d.ts.map +1 -1
- package/conversation/useConversationParticipation.js +13 -2
- package/conversation/useConversationParticipation.js.map +1 -1
- package/cursor-accounts/CursorAccountsConsole.d.ts.map +1 -1
- package/cursor-accounts/CursorAccountsConsole.js +12 -3
- package/cursor-accounts/CursorAccountsConsole.js.map +1 -1
- package/cursor-accounts/cursor-account-coverage.d.ts +30 -1
- package/cursor-accounts/cursor-account-coverage.d.ts.map +1 -1
- package/cursor-accounts/cursor-account-coverage.js +21 -0
- package/cursor-accounts/cursor-account-coverage.js.map +1 -1
- package/execution/useCreateAgentExecution.d.ts +15 -0
- package/execution/useCreateAgentExecution.d.ts.map +1 -1
- package/execution/useCreateAgentExecution.js +5 -0
- package/execution/useCreateAgentExecution.js.map +1 -1
- package/identity-account/AccountPreferencesPanel.d.ts +36 -0
- package/identity-account/AccountPreferencesPanel.d.ts.map +1 -0
- package/identity-account/AccountPreferencesPanel.js +202 -0
- package/identity-account/AccountPreferencesPanel.js.map +1 -0
- package/identity-account/index.d.ts +8 -0
- package/identity-account/index.d.ts.map +1 -1
- package/identity-account/index.js +4 -0
- package/identity-account/index.js.map +1 -1
- package/identity-account/useAccountExecutionDefaults.d.ts +36 -0
- package/identity-account/useAccountExecutionDefaults.d.ts.map +1 -0
- package/identity-account/useAccountExecutionDefaults.js +46 -0
- package/identity-account/useAccountExecutionDefaults.js.map +1 -0
- package/identity-account/useMyIdentityAccount.d.ts +55 -0
- package/identity-account/useMyIdentityAccount.d.ts.map +1 -0
- package/identity-account/useMyIdentityAccount.js +37 -0
- package/identity-account/useMyIdentityAccount.js.map +1 -0
- package/identity-account/useUpdateIdentityAccount.d.ts +42 -0
- package/identity-account/useUpdateIdentityAccount.d.ts.map +1 -0
- package/identity-account/useUpdateIdentityAccount.js +53 -0
- package/identity-account/useUpdateIdentityAccount.js.map +1 -0
- package/identity-provider/IdentityProviderDetailPanel.d.ts.map +1 -1
- package/identity-provider/IdentityProviderDetailPanel.js +16 -15
- package/identity-provider/IdentityProviderDetailPanel.js.map +1 -1
- package/index.d.ts +15 -13
- package/index.d.ts.map +1 -1
- package/index.js +11 -8
- package/index.js.map +1 -1
- package/internal/StandingContextField.d.ts +37 -0
- package/internal/StandingContextField.d.ts.map +1 -0
- package/internal/StandingContextField.js +24 -0
- package/internal/StandingContextField.js.map +1 -0
- package/library/InstanceVisibilitySelector.d.ts.map +1 -1
- package/library/InstanceVisibilitySelector.js +9 -2
- package/library/InstanceVisibilitySelector.js.map +1 -1
- package/library/ResourceVisibilityControl.d.ts +13 -3
- package/library/ResourceVisibilityControl.d.ts.map +1 -1
- package/library/ResourceVisibilityControl.js +33 -5
- package/library/ResourceVisibilityControl.js.map +1 -1
- package/library/VisibilityOptionRow.d.ts +6 -0
- package/library/VisibilityOptionRow.d.ts.map +1 -1
- package/library/VisibilityOptionRow.js +11 -1
- package/library/VisibilityOptionRow.js.map +1 -1
- package/library/VisibilitySelector.d.ts.map +1 -1
- package/library/VisibilitySelector.js +14 -2
- package/library/VisibilitySelector.js.map +1 -1
- package/library/index.d.ts +4 -2
- package/library/index.d.ts.map +1 -1
- package/library/index.js +2 -1
- package/library/index.js.map +1 -1
- package/library/useCanSetPublicVisibility.d.ts +30 -0
- package/library/useCanSetPublicVisibility.d.ts.map +1 -0
- package/library/useCanSetPublicVisibility.js +41 -0
- package/library/useCanSetPublicVisibility.js.map +1 -0
- package/library/visibilityLevels.d.ts +32 -1
- package/library/visibilityLevels.d.ts.map +1 -1
- package/library/visibilityLevels.js +34 -14
- package/library/visibilityLevels.js.map +1 -1
- package/mcp-server/McpServerDetailView.js +2 -2
- package/mcp-server/McpServerDetailView.js.map +1 -1
- package/mcp-server/index.d.ts +0 -1
- package/mcp-server/index.d.ts.map +1 -1
- package/mcp-server/index.js +0 -1
- package/mcp-server/index.js.map +1 -1
- package/mcp-server/internal/definitionDrift.d.ts +14 -12
- package/mcp-server/internal/definitionDrift.d.ts.map +1 -1
- package/mcp-server/internal/definitionDrift.js +22 -19
- package/mcp-server/internal/definitionDrift.js.map +1 -1
- package/mcp-server/useMcpServerConnect.d.ts +8 -5
- package/mcp-server/useMcpServerConnect.d.ts.map +1 -1
- package/mcp-server/useMcpServerConnect.js +2 -1
- package/mcp-server/useMcpServerConnect.js.map +1 -1
- package/mcp-server/useMcpServerOAuthConnect.d.ts.map +1 -1
- package/mcp-server/useMcpServerOAuthConnect.js +7 -2
- package/mcp-server/useMcpServerOAuthConnect.js.map +1 -1
- package/mcp-server/useUpdateMcpServer.d.ts +3 -3
- package/mcp-server/useUpdateMcpServer.js +3 -3
- package/models/ModelSelector.d.ts +33 -1
- package/models/ModelSelector.d.ts.map +1 -1
- package/models/ModelSelector.js +37 -4
- package/models/ModelSelector.js.map +1 -1
- package/models/index.d.ts +2 -0
- package/models/index.d.ts.map +1 -1
- package/models/index.js +1 -0
- package/models/index.js.map +1 -1
- package/models/registry.d.ts +16 -0
- package/models/registry.d.ts.map +1 -1
- package/models/registry.js +13 -0
- package/models/registry.js.map +1 -1
- package/models/thinking-mode.d.ts +27 -0
- package/models/thinking-mode.d.ts.map +1 -0
- package/models/thinking-mode.js +32 -0
- package/models/thinking-mode.js.map +1 -0
- package/oauth-app/CreateOAuthAppForm.d.ts +2 -2
- package/oauth-app/CreateOAuthAppForm.d.ts.map +1 -1
- package/oauth-app/CreateOAuthAppForm.js +13 -4
- package/oauth-app/CreateOAuthAppForm.js.map +1 -1
- package/oauth-app/OAuthAppDetailPanel.d.ts.map +1 -1
- package/oauth-app/OAuthAppDetailPanel.js +50 -22
- package/oauth-app/OAuthAppDetailPanel.js.map +1 -1
- package/organization/OrgPreferencesPanel.d.ts +32 -0
- package/organization/OrgPreferencesPanel.d.ts.map +1 -0
- package/organization/OrgPreferencesPanel.js +90 -0
- package/organization/OrgPreferencesPanel.js.map +1 -0
- package/organization/OrgProfilePanel.d.ts.map +1 -1
- package/organization/OrgProfilePanel.js +5 -4
- package/organization/OrgProfilePanel.js.map +1 -1
- package/organization/index.d.ts +2 -0
- package/organization/index.d.ts.map +1 -1
- package/organization/index.js +1 -0
- package/organization/index.js.map +1 -1
- package/package.json +4 -4
- package/platform-client/PlatformClientDetailPanel.d.ts.map +1 -1
- package/platform-client/PlatformClientDetailPanel.js +12 -13
- package/platform-client/PlatformClientDetailPanel.js.map +1 -1
- package/schedule/ScheduleDetailView.d.ts.map +1 -1
- package/schedule/ScheduleDetailView.js +21 -10
- package/schedule/ScheduleDetailView.js.map +1 -1
- package/schedule/ScheduleForm.d.ts.map +1 -1
- package/schedule/ScheduleForm.js +13 -3
- package/schedule/ScheduleForm.js.map +1 -1
- package/session/NewSessionViewer.d.ts +10 -1
- package/session/NewSessionViewer.d.ts.map +1 -1
- package/session/NewSessionViewer.js +2 -1
- package/session/NewSessionViewer.js.map +1 -1
- package/session/run-config.d.ts +9 -0
- package/session/run-config.d.ts.map +1 -1
- package/session/run-config.js +5 -0
- package/session/run-config.js.map +1 -1
- package/session/useNewSessionFlow.d.ts +27 -1
- package/session/useNewSessionFlow.d.ts.map +1 -1
- package/session/useNewSessionFlow.js +51 -8
- package/session/useNewSessionFlow.js.map +1 -1
- package/session/useSessionConversation.d.ts +12 -1
- package/session/useSessionConversation.d.ts.map +1 -1
- package/session/useSessionConversation.js +15 -24
- package/session/useSessionConversation.js.map +1 -1
- package/session/useSessionPageFlow.d.ts.map +1 -1
- package/session/useSessionPageFlow.js +14 -10
- package/session/useSessionPageFlow.js.map +1 -1
- package/session/useUpdateSession.d.ts +18 -24
- package/session/useUpdateSession.d.ts.map +1 -1
- package/session/useUpdateSession.js +18 -24
- package/session/useUpdateSession.js.map +1 -1
- package/settings/AccountPreferencesSection.d.ts +3 -0
- package/settings/AccountPreferencesSection.d.ts.map +1 -0
- package/settings/AccountPreferencesSection.js +10 -0
- package/settings/AccountPreferencesSection.js.map +1 -0
- package/settings/OrgPreferencesSection.d.ts +3 -0
- package/settings/OrgPreferencesSection.d.ts.map +1 -0
- package/settings/OrgPreferencesSection.js +13 -0
- package/settings/OrgPreferencesSection.js.map +1 -0
- package/settings/index.d.ts +2 -0
- package/settings/index.d.ts.map +1 -1
- package/settings/index.js +2 -0
- package/settings/index.js.map +1 -1
- package/settings/settings-nav.d.ts.map +1 -1
- package/settings/settings-nav.js +17 -1
- package/settings/settings-nav.js.map +1 -1
- package/src/agent/AgentDetailView.tsx +2 -2
- package/src/agent/index.ts +0 -2
- package/src/agent/useUpdateAgent.ts +3 -3
- package/src/agent-instance/AgentInstanceDetailPanel.tsx +5 -7
- package/src/agent-instance/__tests__/AgentInstanceDetailPanel.test.tsx +75 -0
- package/src/agent-instance/useUpdateAgentInstance.ts +1 -1
- package/src/attachment/AttachmentChipList.tsx +19 -8
- package/src/attachment/__tests__/AttachmentChipList.test.tsx +12 -0
- package/src/attachment/__tests__/useAttachments.test.ts +293 -0
- package/src/attachment/index.ts +1 -0
- package/src/attachment/useAttachments.ts +143 -11
- package/src/channel/AgentChannelsPanel.tsx +26 -1
- package/src/channel/ChannelRunConfigDialog.tsx +351 -0
- package/src/channel/__tests__/ChannelRunConfigDialog.test.tsx +210 -0
- package/src/channel/index.ts +2 -0
- package/src/channel/useSaveAgentChannel.ts +6 -3
- package/src/channel-app/ChannelAppDetailPanel.tsx +9 -9
- package/src/channel-app/__tests__/channelAppWhatsApp.test.tsx +2 -0
- package/src/channel-app/__tests__/channelAppWipeSafety.test.tsx +87 -0
- package/src/composer/ComposerToolbar.tsx +9 -0
- package/src/composer/SessionComposer.tsx +59 -16
- package/src/composer/__tests__/SessionComposer-thinkingMode.test.tsx +176 -0
- package/src/conversation/ConversationComposer.tsx +38 -4
- package/src/conversation/ConversationTemplatePickerDialog.tsx +441 -0
- package/src/conversation/ConversationsWorkbench.tsx +40 -4
- package/src/conversation/__tests__/ConversationComposer.test.tsx +56 -1
- package/src/conversation/__tests__/ConversationTemplatePickerDialog.test.tsx +224 -0
- package/src/conversation/__tests__/useConversationParticipation.test.tsx +45 -4
- package/src/conversation/index.ts +4 -0
- package/src/conversation/useConversationParticipation.ts +58 -6
- package/src/cursor-accounts/CursorAccountsConsole.tsx +40 -5
- package/src/cursor-accounts/__tests__/CursorAccountsConsole.test.tsx +32 -0
- package/src/cursor-accounts/__tests__/cursor-account-coverage.test.ts +58 -1
- package/src/cursor-accounts/cursor-account-coverage.ts +55 -0
- package/src/execution/useCreateAgentExecution.ts +19 -0
- package/src/identity-account/AccountPreferencesPanel.tsx +532 -0
- package/src/identity-account/__tests__/AccountPreferencesPanel.test.tsx +267 -0
- package/src/identity-account/__tests__/useAccountExecutionDefaults.test.tsx +116 -0
- package/src/identity-account/__tests__/useMyIdentityAccount.test.tsx +121 -0
- package/src/identity-account/index.ts +11 -0
- package/src/identity-account/useAccountExecutionDefaults.ts +63 -0
- package/src/identity-account/useMyIdentityAccount.ts +75 -0
- package/src/identity-account/useUpdateIdentityAccount.ts +73 -0
- package/src/identity-provider/IdentityProviderDetailPanel.tsx +18 -15
- package/src/identity-provider/__tests__/IdentityProviderDetailPanel.test.tsx +80 -0
- package/src/index.ts +26 -4
- package/src/internal/StandingContextField.tsx +92 -0
- package/src/library/InstanceVisibilitySelector.tsx +9 -2
- package/src/library/ResourceVisibilityControl.tsx +46 -13
- package/src/library/VisibilityOptionRow.tsx +28 -6
- package/src/library/VisibilitySelector.tsx +14 -2
- package/src/library/__tests__/VisibilitySelector.test.tsx +48 -1
- package/src/library/__tests__/visibilityLevels.test.ts +67 -1
- package/src/library/index.ts +6 -1
- package/src/library/useCanSetPublicVisibility.ts +56 -0
- package/src/library/visibilityLevels.ts +65 -14
- package/src/mcp-server/McpServerDetailView.tsx +2 -2
- package/src/mcp-server/__tests__/useMcpServerConnect.asyncLane.test.tsx +117 -0
- package/src/mcp-server/index.ts +0 -2
- package/src/mcp-server/internal/definitionDrift.ts +22 -20
- package/src/mcp-server/useMcpServerConnect.ts +9 -6
- package/src/mcp-server/useMcpServerOAuthConnect.ts +7 -2
- package/src/mcp-server/useUpdateMcpServer.ts +3 -3
- package/src/models/ModelSelector.tsx +94 -1
- package/src/models/index.ts +2 -0
- package/src/models/registry.ts +29 -0
- package/src/models/thinking-mode.ts +48 -0
- package/src/oauth-app/CreateOAuthAppForm.tsx +58 -3
- package/src/oauth-app/OAuthAppDetailPanel.tsx +103 -20
- package/src/oauth-app/__tests__/OAuthAppDetailPanel.test.tsx +94 -0
- package/src/organization/OrgPreferencesPanel.tsx +221 -0
- package/src/organization/OrgProfilePanel.tsx +5 -4
- package/src/organization/__tests__/OrgPreferencesPanel.test.tsx +145 -0
- package/src/organization/__tests__/OrgProfilePanel.test.tsx +108 -0
- package/src/organization/index.ts +2 -0
- package/src/platform-client/PlatformClientDetailPanel.tsx +14 -13
- package/src/platform-client/__tests__/PlatformClientDetailPanel.test.tsx +82 -0
- package/src/schedule/ScheduleDetailView.tsx +29 -4
- package/src/schedule/ScheduleForm.tsx +14 -1
- package/src/session/NewSessionViewer.tsx +12 -0
- package/src/session/__tests__/useNewSessionFlow.test.tsx +151 -0
- package/src/session/run-config.ts +16 -0
- package/src/session/useNewSessionFlow.ts +82 -9
- package/src/session/useSessionConversation.ts +32 -40
- package/src/session/useSessionPageFlow.ts +14 -11
- package/src/session/useUpdateSession.ts +18 -24
- package/src/settings/AccountPreferencesSection.tsx +25 -0
- package/src/settings/OrgPreferencesSection.tsx +35 -0
- package/src/settings/__tests__/settings-nav.test.ts +27 -0
- package/src/settings/index.ts +2 -0
- package/src/settings/settings-nav.ts +18 -0
- package/src/workflow/ApprovalFormBuilder.tsx +20 -27
- package/src/workflow/WorkflowDetailView.tsx +2 -2
- package/src/workflow/__tests__/WorkflowInstanceDetailPanel.test.tsx +83 -0
- package/src/workflow/index.ts +0 -2
- package/src/workflow/instance/WorkflowInstanceDetailPanel.tsx +6 -7
- package/src/workflow/useUpdateWorkflow.ts +3 -3
- package/styles.css +1 -1
- package/workflow/ApprovalFormBuilder.d.ts.map +1 -1
- package/workflow/ApprovalFormBuilder.js +10 -5
- package/workflow/ApprovalFormBuilder.js.map +1 -1
- package/workflow/WorkflowDetailView.js +2 -2
- package/workflow/WorkflowDetailView.js.map +1 -1
- package/workflow/index.d.ts +0 -1
- package/workflow/index.d.ts.map +1 -1
- package/workflow/index.js +0 -1
- package/workflow/index.js.map +1 -1
- package/workflow/instance/WorkflowInstanceDetailPanel.d.ts.map +1 -1
- package/workflow/instance/WorkflowInstanceDetailPanel.js +6 -7
- package/workflow/instance/WorkflowInstanceDetailPanel.js.map +1 -1
- package/workflow/useUpdateWorkflow.d.ts +3 -3
- package/workflow/useUpdateWorkflow.js +3 -3
- package/agent/internal/agentToInput.d.ts +0 -15
- package/agent/internal/agentToInput.d.ts.map +0 -1
- package/agent/internal/agentToInput.js +0 -84
- package/agent/internal/agentToInput.js.map +0 -1
- package/mcp-server/internal/mcpServerToInput.d.ts +0 -12
- package/mcp-server/internal/mcpServerToInput.d.ts.map +0 -1
- package/mcp-server/internal/mcpServerToInput.js +0 -84
- package/mcp-server/internal/mcpServerToInput.js.map +0 -1
- package/session/session-spec-converters.d.ts +0 -24
- package/session/session-spec-converters.d.ts.map +0 -1
- package/session/session-spec-converters.js +0 -72
- package/session/session-spec-converters.js.map +0 -1
- package/src/agent/internal/__tests__/agentToInput.test.ts +0 -145
- package/src/agent/internal/agentToInput.ts +0 -102
- package/src/mcp-server/__tests__/mcpServerToInput.test.ts +0 -201
- package/src/mcp-server/internal/mcpServerToInput.ts +0 -98
- package/src/session/__tests__/session-spec-converters.test.ts +0 -183
- package/src/session/session-spec-converters.ts +0 -86
- package/src/workflow/internal/workflowToInput.ts +0 -96
- package/workflow/internal/workflowToInput.d.ts +0 -12
- package/workflow/internal/workflowToInput.d.ts.map +0 -1
- package/workflow/internal/workflowToInput.js +0 -73
- package/workflow/internal/workflowToInput.js.map +0 -1
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
|
|
3
|
+
import { useCallback, useState } from "react";
|
|
4
|
+
import type { IdentityAccountInput } from "@stigmer/sdk";
|
|
5
|
+
import type { IdentityAccount } from "@stigmer/protos/ai/stigmer/iam/identityaccount/v1/api_pb";
|
|
6
|
+
import { useStigmer } from "../hooks.js";
|
|
7
|
+
import { toError } from "../internal/toError.js";
|
|
8
|
+
|
|
9
|
+
/** Return value of {@link useUpdateIdentityAccount}. */
|
|
10
|
+
export interface UseUpdateIdentityAccountReturn {
|
|
11
|
+
/** Submit an {@link IdentityAccountInput} to update an identity account. Resolves with the updated resource. */
|
|
12
|
+
readonly update: (input: IdentityAccountInput) => Promise<IdentityAccount>;
|
|
13
|
+
/** `true` while the update request is in flight. */
|
|
14
|
+
readonly isUpdating: boolean;
|
|
15
|
+
/** Error from the last failed update, or `null` when healthy. */
|
|
16
|
+
readonly error: Error | null;
|
|
17
|
+
/** Reset `error` to `null`. */
|
|
18
|
+
readonly clearError: () => void;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* Mutation hook that wraps `identityAccount.update()` with loading and
|
|
23
|
+
* error state.
|
|
24
|
+
*
|
|
25
|
+
* The update RPC is a full-spec replacement addressed by `org` + `slug`
|
|
26
|
+
* (the generated input carries no id). Build the input from the loaded
|
|
27
|
+
* resource with `toIdentityAccountUpdateInput` from `@stigmer/sdk` and
|
|
28
|
+
* override only the fields being edited — sending a partial input wipes
|
|
29
|
+
* the unsent spec fields. The same rule applies INSIDE nested messages:
|
|
30
|
+
* override `preferences` by spreading the mapper's complete value first,
|
|
31
|
+
* or the untouched preference fields wipe.
|
|
32
|
+
*
|
|
33
|
+
* Self-service: a user can always update their own account (`can_edit`
|
|
34
|
+
* via the self-ownership relationship written at account creation).
|
|
35
|
+
*
|
|
36
|
+
* @example
|
|
37
|
+
* ```tsx
|
|
38
|
+
* const { update, isUpdating, error } = useUpdateIdentityAccount();
|
|
39
|
+
*
|
|
40
|
+
* const mapped = toIdentityAccountUpdateInput(account);
|
|
41
|
+
* await update({
|
|
42
|
+
* ...mapped,
|
|
43
|
+
* preferences: { ...mapped.preferences, standingContext: "Keep answers terse." },
|
|
44
|
+
* });
|
|
45
|
+
* refetch(); // re-sync the editor
|
|
46
|
+
* ```
|
|
47
|
+
*/
|
|
48
|
+
export function useUpdateIdentityAccount(): UseUpdateIdentityAccountReturn {
|
|
49
|
+
const stigmer = useStigmer();
|
|
50
|
+
const [isUpdating, setIsUpdating] = useState(false);
|
|
51
|
+
const [error, setError] = useState<Error | null>(null);
|
|
52
|
+
|
|
53
|
+
const clearError = useCallback(() => setError(null), []);
|
|
54
|
+
|
|
55
|
+
const update = useCallback(
|
|
56
|
+
async (input: IdentityAccountInput): Promise<IdentityAccount> => {
|
|
57
|
+
setIsUpdating(true);
|
|
58
|
+
setError(null);
|
|
59
|
+
|
|
60
|
+
try {
|
|
61
|
+
return await stigmer.identityAccount.update(input);
|
|
62
|
+
} catch (err) {
|
|
63
|
+
setError(toError(err));
|
|
64
|
+
throw err;
|
|
65
|
+
} finally {
|
|
66
|
+
setIsUpdating(false);
|
|
67
|
+
}
|
|
68
|
+
},
|
|
69
|
+
[stigmer],
|
|
70
|
+
);
|
|
71
|
+
|
|
72
|
+
return { update, isUpdating, error, clearError };
|
|
73
|
+
}
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
import { type FormEvent, useCallback, useId, useRef, useState } from "react";
|
|
4
4
|
import { cn } from "@stigmer/theme";
|
|
5
5
|
import { UNSTYLED_FIELDSET } from "../internal/element-resets.js";
|
|
6
|
-
import { getUserMessage } from "@stigmer/sdk";
|
|
6
|
+
import { getUserMessage, toIdentityProviderUpdateInput } from "@stigmer/sdk";
|
|
7
7
|
import type { IdentityProvider } from "@stigmer/protos/ai/stigmer/iam/identityprovider/v1/api_pb";
|
|
8
8
|
import { IamRole } from "@stigmer/protos/ai/stigmer/iam/v1/enum_pb";
|
|
9
9
|
import { timestampDate, type Timestamp } from "@bufbuild/protobuf/wkt";
|
|
@@ -132,10 +132,13 @@ export function IdentityProviderDetailPanel({
|
|
|
132
132
|
e.preventDefault();
|
|
133
133
|
clearError();
|
|
134
134
|
try {
|
|
135
|
+
// Full-spec-replace safety: spread the complete mapped input and
|
|
136
|
+
// override only the edited fields, so unlisted spec fields (e.g.
|
|
137
|
+
// rate_limit_budget) survive the save. Fields the form clears
|
|
138
|
+
// (SSO providers have no JIT settings) are set to undefined
|
|
139
|
+
// explicitly — omitting them would carry the stale mapped value.
|
|
135
140
|
const updated = await update({
|
|
136
|
-
|
|
137
|
-
slug: meta?.slug,
|
|
138
|
-
org: meta?.org ?? "",
|
|
141
|
+
...toIdentityProviderUpdateInput(identityProvider),
|
|
139
142
|
displayName: displayName.trim(),
|
|
140
143
|
jwksUri: jwksUri.trim(),
|
|
141
144
|
allowedIssuers: issuers
|
|
@@ -146,16 +149,16 @@ export function IdentityProviderDetailPanel({
|
|
|
146
149
|
userinfoEndpoint: userinfoEndpoint.trim() || undefined,
|
|
147
150
|
isSsoProvider: isSso,
|
|
148
151
|
oidcClientId: isSso ? oidcClientId.trim() : undefined,
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
autoGrantRole
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
152
|
+
autoProvisionAccounts: !isSso && autoProvision ? true : undefined,
|
|
153
|
+
autoGrantOnOrg: !isSso && autoGrant ? true : undefined,
|
|
154
|
+
autoGrantRole:
|
|
155
|
+
!isSso && autoGrant && autoGrantRole !== IamRole.iam_role_unspecified
|
|
156
|
+
? autoGrantRole
|
|
157
|
+
: undefined,
|
|
158
|
+
tenantOrgClaim:
|
|
159
|
+
!isSso && autoGrant && tenantOrgClaim.trim()
|
|
160
|
+
? tenantOrgClaim.trim()
|
|
161
|
+
: undefined,
|
|
159
162
|
});
|
|
160
163
|
setMode("view");
|
|
161
164
|
onUpdated?.(updated);
|
|
@@ -164,7 +167,7 @@ export function IdentityProviderDetailPanel({
|
|
|
164
167
|
}
|
|
165
168
|
},
|
|
166
169
|
[
|
|
167
|
-
|
|
170
|
+
identityProvider, displayName, jwksUri, issuers, audience,
|
|
168
171
|
userinfoEndpoint, isSso, oidcClientId, autoProvision, autoGrant,
|
|
169
172
|
autoGrantRole, tenantOrgClaim, update, clearError, onUpdated,
|
|
170
173
|
],
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
import { describe, it, expect, vi, afterEach } from "vitest";
|
|
2
|
+
import { cleanup, fireEvent, render, screen, waitFor } from "@testing-library/react";
|
|
3
|
+
import { create } from "@bufbuild/protobuf";
|
|
4
|
+
import {
|
|
5
|
+
IdentityProviderSchema,
|
|
6
|
+
type IdentityProvider,
|
|
7
|
+
} from "@stigmer/protos/ai/stigmer/iam/identityprovider/v1/api_pb";
|
|
8
|
+
import { IamRole } from "@stigmer/protos/ai/stigmer/iam/v1/enum_pb";
|
|
9
|
+
import type { IdentityProviderInput } from "@stigmer/sdk";
|
|
10
|
+
import { StigmerContext } from "../../context";
|
|
11
|
+
import { IdentityProviderDetailPanel } from "../IdentityProviderDetailPanel";
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Regression suite for the full-spec-replace wipe bug: before the
|
|
15
|
+
* generated-mapper migration, this panel hand-built its update input and
|
|
16
|
+
* NEVER sent `rate_limit_budget` — editing any IdP field zeroed the
|
|
17
|
+
* provider's rate limit. The panel must spread
|
|
18
|
+
* `toIdentityProviderUpdateInput` and override only what it edits.
|
|
19
|
+
*/
|
|
20
|
+
|
|
21
|
+
const IDP: IdentityProvider = create(IdentityProviderSchema, {
|
|
22
|
+
metadata: {
|
|
23
|
+
id: "idp-1",
|
|
24
|
+
name: "Acme Okta",
|
|
25
|
+
slug: "acme-okta",
|
|
26
|
+
org: "acme",
|
|
27
|
+
},
|
|
28
|
+
spec: {
|
|
29
|
+
displayName: "Acme Okta",
|
|
30
|
+
jwksUri: "https://acme.okta.example/jwks",
|
|
31
|
+
allowedIssuers: ["https://acme.okta.example"],
|
|
32
|
+
expectedAudience: "stigmer",
|
|
33
|
+
rateLimitBudget: 120,
|
|
34
|
+
isSsoProvider: false,
|
|
35
|
+
autoProvisionAccounts: true,
|
|
36
|
+
autoGrantOnOrg: true,
|
|
37
|
+
autoGrantRole: IamRole.admin,
|
|
38
|
+
tenantOrgClaim: "org_slug",
|
|
39
|
+
},
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
function renderPanel(update: ReturnType<typeof vi.fn>) {
|
|
43
|
+
const client = {
|
|
44
|
+
identityProvider: { update },
|
|
45
|
+
} as never;
|
|
46
|
+
return render(
|
|
47
|
+
<StigmerContext.Provider value={client}>
|
|
48
|
+
<IdentityProviderDetailPanel identityProvider={IDP} />
|
|
49
|
+
</StigmerContext.Provider>,
|
|
50
|
+
);
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
afterEach(cleanup);
|
|
54
|
+
|
|
55
|
+
describe("IdentityProviderDetailPanel save payload", () => {
|
|
56
|
+
it("round-trips rate_limit_budget on a display-name edit (the wipe bug)", async () => {
|
|
57
|
+
const update = vi.fn(async (_input: IdentityProviderInput) => IDP);
|
|
58
|
+
renderPanel(update);
|
|
59
|
+
|
|
60
|
+
fireEvent.click(screen.getByRole("button", { name: "Edit" }));
|
|
61
|
+
const displayName = await screen.findByLabelText("Display name");
|
|
62
|
+
fireEvent.change(displayName, { target: { value: "Acme Okta (renamed)" } });
|
|
63
|
+
fireEvent.click(screen.getByRole("button", { name: "Save changes" }));
|
|
64
|
+
|
|
65
|
+
await waitFor(() => expect(update).toHaveBeenCalledTimes(1));
|
|
66
|
+
const input = update.mock.calls[0]![0];
|
|
67
|
+
|
|
68
|
+
// The wipe-bug guard: the form does not render the rate limit, yet it
|
|
69
|
+
// must survive the save.
|
|
70
|
+
expect(input.rateLimitBudget).toBe(120);
|
|
71
|
+
// The edited field.
|
|
72
|
+
expect(input.displayName).toBe("Acme Okta (renamed)");
|
|
73
|
+
// JIT settings round-trip from the edit state.
|
|
74
|
+
expect(input.autoGrantRole).toBe(IamRole.admin);
|
|
75
|
+
expect(input.tenantOrgClaim).toBe("org_slug");
|
|
76
|
+
// Addressing fields.
|
|
77
|
+
expect(input.org).toBe("acme");
|
|
78
|
+
expect(input.slug).toBe("acme-okta");
|
|
79
|
+
});
|
|
80
|
+
});
|
package/src/index.ts
CHANGED
|
@@ -502,6 +502,7 @@ export {
|
|
|
502
502
|
visionPreflightMessage,
|
|
503
503
|
} from "./attachment/index.js";
|
|
504
504
|
export type {
|
|
505
|
+
AddFilesOptions,
|
|
505
506
|
AttachmentPhase,
|
|
506
507
|
AttachmentEntry,
|
|
507
508
|
AssessVisionPreflightOptions,
|
|
@@ -566,7 +567,6 @@ export {
|
|
|
566
567
|
McpToolSelector,
|
|
567
568
|
useCreateMcpServer,
|
|
568
569
|
useUpdateMcpServer,
|
|
569
|
-
mcpServerToInput,
|
|
570
570
|
toServerKey,
|
|
571
571
|
IdentityTransportStep,
|
|
572
572
|
EnvironmentAuthStep,
|
|
@@ -695,7 +695,6 @@ export {
|
|
|
695
695
|
useDefaultAgent,
|
|
696
696
|
useCreateAgent,
|
|
697
697
|
useUpdateAgent,
|
|
698
|
-
agentToInput,
|
|
699
698
|
AgentCreationWizard,
|
|
700
699
|
} from "./agent/index.js";
|
|
701
700
|
export type {
|
|
@@ -833,13 +832,23 @@ export type {
|
|
|
833
832
|
ToolCredentialsReadiness,
|
|
834
833
|
} from "./environment/index.js";
|
|
835
834
|
|
|
836
|
-
// Identity Account — gate hook
|
|
835
|
+
// Identity Account — gate hook, self-account data/mutation hooks, the
|
|
836
|
+
// account preferences editor, and the composer-seeding execution defaults
|
|
837
837
|
export {
|
|
838
838
|
useIdentityAccountGate,
|
|
839
|
+
useMyIdentityAccount,
|
|
840
|
+
useAccountExecutionDefaults,
|
|
841
|
+
useUpdateIdentityAccount,
|
|
842
|
+
AccountPreferencesPanel,
|
|
839
843
|
} from "./identity-account/index.js";
|
|
840
844
|
export type {
|
|
841
845
|
IdentityAccountGateState,
|
|
842
846
|
UseIdentityAccountGateReturn,
|
|
847
|
+
UseMyIdentityAccountOptions,
|
|
848
|
+
UseMyIdentityAccountReturn,
|
|
849
|
+
AccountExecutionDefaults,
|
|
850
|
+
UseUpdateIdentityAccountReturn,
|
|
851
|
+
AccountPreferencesPanelProps,
|
|
843
852
|
} from "./identity-account/index.js";
|
|
844
853
|
|
|
845
854
|
// IAM Policy — data hooks, behavior hooks, headless hook, and styled components for access management
|
|
@@ -921,6 +930,7 @@ export {
|
|
|
921
930
|
useUpdateOrganization,
|
|
922
931
|
CreateOrganizationForm,
|
|
923
932
|
OrgProfilePanel,
|
|
933
|
+
OrgPreferencesPanel,
|
|
924
934
|
OrgSwitcher,
|
|
925
935
|
} from "./organization/index.js";
|
|
926
936
|
export type {
|
|
@@ -933,6 +943,7 @@ export type {
|
|
|
933
943
|
UseUpdateOrganizationReturn,
|
|
934
944
|
CreateOrganizationFormProps,
|
|
935
945
|
OrgProfilePanelProps,
|
|
946
|
+
OrgPreferencesPanelProps,
|
|
936
947
|
OrgSwitcherProps,
|
|
937
948
|
} from "./organization/index.js";
|
|
938
949
|
|
|
@@ -1065,6 +1076,8 @@ export type { SettingsNavItem, SettingsNavGroup } from "./settings/index.js";
|
|
|
1065
1076
|
export { ApiKeysSection } from "./settings/index.js";
|
|
1066
1077
|
export { MembersSection } from "./settings/index.js";
|
|
1067
1078
|
export { OrgProfileSection } from "./settings/index.js";
|
|
1079
|
+
export { OrgPreferencesSection } from "./settings/index.js";
|
|
1080
|
+
export { AccountPreferencesSection } from "./settings/index.js";
|
|
1068
1081
|
export { EnvironmentsSection } from "./settings/index.js";
|
|
1069
1082
|
export { InvitationsSection } from "./settings/index.js";
|
|
1070
1083
|
export { IdentityProvidersSection } from "./settings/index.js";
|
|
@@ -1296,6 +1309,7 @@ export {
|
|
|
1296
1309
|
ConnectSlackDialog,
|
|
1297
1310
|
ConnectWhatsAppDialog,
|
|
1298
1311
|
ChannelCredentialsDialog,
|
|
1312
|
+
ChannelRunConfigDialog,
|
|
1299
1313
|
ChannelToolCredentials,
|
|
1300
1314
|
ChannelConversationsDialog,
|
|
1301
1315
|
ChannelTemplatesDialog,
|
|
@@ -1319,6 +1333,7 @@ export type {
|
|
|
1319
1333
|
ConnectSlackDialogProps,
|
|
1320
1334
|
ConnectWhatsAppDialogProps,
|
|
1321
1335
|
ChannelCredentialsDialogProps,
|
|
1336
|
+
ChannelRunConfigDialogProps,
|
|
1322
1337
|
ChannelToolCredentialsProps,
|
|
1323
1338
|
ChannelConversationsDialogProps,
|
|
1324
1339
|
ChannelTemplatesDialogProps,
|
|
@@ -1335,6 +1350,7 @@ export {
|
|
|
1335
1350
|
ConversationControlBanner,
|
|
1336
1351
|
ConversationAttentionBanner,
|
|
1337
1352
|
ConversationComposer,
|
|
1353
|
+
ConversationTemplatePickerDialog,
|
|
1338
1354
|
useConversation,
|
|
1339
1355
|
useConversationList,
|
|
1340
1356
|
useConversationMediaUrl,
|
|
@@ -1364,6 +1380,8 @@ export type {
|
|
|
1364
1380
|
ConversationControlBannerProps,
|
|
1365
1381
|
ConversationAttentionBannerProps,
|
|
1366
1382
|
ConversationComposerProps,
|
|
1383
|
+
ConversationTemplatePickerDialogProps,
|
|
1384
|
+
ConversationReplyPayload,
|
|
1367
1385
|
UseConversationOptions,
|
|
1368
1386
|
UseConversationReturn,
|
|
1369
1387
|
UseConversationListOptions,
|
|
@@ -1422,9 +1440,11 @@ export {
|
|
|
1422
1440
|
VisibilitySelector,
|
|
1423
1441
|
VisibilityBadge,
|
|
1424
1442
|
blueprintVisibilityLevels,
|
|
1425
|
-
|
|
1443
|
+
instanceVisibilityLevels,
|
|
1444
|
+
PUBLIC_LOCKED_REASON,
|
|
1426
1445
|
visibilityLabel,
|
|
1427
1446
|
useUpdateVisibility,
|
|
1447
|
+
useCanSetPublicVisibility,
|
|
1428
1448
|
} from "./library/index.js";
|
|
1429
1449
|
export type {
|
|
1430
1450
|
ScopeToggleProps,
|
|
@@ -1444,8 +1464,10 @@ export type {
|
|
|
1444
1464
|
VisibilityBadgeProps,
|
|
1445
1465
|
VisibilityLevelOption,
|
|
1446
1466
|
BlueprintVisibilityLevelsContext,
|
|
1467
|
+
InstanceVisibilityLevelsContext,
|
|
1447
1468
|
VisibilityResourceKind,
|
|
1448
1469
|
UseUpdateVisibilityReturn,
|
|
1470
|
+
UseCanSetPublicVisibilityReturn,
|
|
1449
1471
|
} from "./library/index.js";
|
|
1450
1472
|
|
|
1451
1473
|
// Manifest — kind-agnostic YAML edit/apply (editor, hooks, dialogs)
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
|
|
3
|
+
import type { ReactNode } from "react";
|
|
4
|
+
import { cn } from "@stigmer/theme";
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Both `OrganizationPreferences.standing_context` and
|
|
8
|
+
* `IdentityAccountPreferences.standing_context` pin `max_len = 2000`
|
|
9
|
+
* (buf.validate, spec.proto in each package).
|
|
10
|
+
*/
|
|
11
|
+
export const STANDING_CONTEXT_MAX_LEN = 2000;
|
|
12
|
+
/** Show the remaining-characters counter once within this margin. */
|
|
13
|
+
const COUNTER_THRESHOLD = 200;
|
|
14
|
+
|
|
15
|
+
/** Props for {@link StandingContextField}. */
|
|
16
|
+
export interface StandingContextFieldProps {
|
|
17
|
+
/** DOM id for the textarea (label association). */
|
|
18
|
+
readonly id: string;
|
|
19
|
+
/** Current field value. */
|
|
20
|
+
readonly value: string;
|
|
21
|
+
/** Fired with the new value on every edit. */
|
|
22
|
+
readonly onChange: (value: string) => void;
|
|
23
|
+
/** Disables editing while a save is in flight. */
|
|
24
|
+
readonly disabled?: boolean;
|
|
25
|
+
/**
|
|
26
|
+
* Renders the field as read-only (still selectable/copyable) for
|
|
27
|
+
* viewers without edit permission.
|
|
28
|
+
*/
|
|
29
|
+
readonly readOnly?: boolean;
|
|
30
|
+
/** Example text shown when the field is empty. */
|
|
31
|
+
readonly placeholder?: string;
|
|
32
|
+
/** Helper line rendered under the textarea. */
|
|
33
|
+
readonly helperText?: ReactNode;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* Shared textarea for declared-preference standing context — the one
|
|
38
|
+
* free-text field both the organization and account preference editors
|
|
39
|
+
* render. Owns the proto length cap and the remaining-characters
|
|
40
|
+
* counter; the parent panel owns label, load/save, and dirty state.
|
|
41
|
+
*
|
|
42
|
+
* Internal to `@stigmer/react` — the public surface is the panels.
|
|
43
|
+
*/
|
|
44
|
+
export function StandingContextField({
|
|
45
|
+
id,
|
|
46
|
+
value,
|
|
47
|
+
onChange,
|
|
48
|
+
disabled,
|
|
49
|
+
readOnly,
|
|
50
|
+
placeholder,
|
|
51
|
+
helperText,
|
|
52
|
+
}: StandingContextFieldProps) {
|
|
53
|
+
const remaining = STANDING_CONTEXT_MAX_LEN - value.length;
|
|
54
|
+
|
|
55
|
+
return (
|
|
56
|
+
<div className="stg:space-y-1">
|
|
57
|
+
<label
|
|
58
|
+
htmlFor={id}
|
|
59
|
+
className="stg:text-xs stg:font-medium stg:text-foreground"
|
|
60
|
+
>
|
|
61
|
+
Standing context
|
|
62
|
+
</label>
|
|
63
|
+
<textarea
|
|
64
|
+
id={id}
|
|
65
|
+
value={value}
|
|
66
|
+
onChange={(e) => onChange(e.target.value)}
|
|
67
|
+
maxLength={STANDING_CONTEXT_MAX_LEN}
|
|
68
|
+
rows={6}
|
|
69
|
+
disabled={disabled}
|
|
70
|
+
readOnly={readOnly}
|
|
71
|
+
placeholder={readOnly ? undefined : placeholder}
|
|
72
|
+
className={cn(
|
|
73
|
+
"stg:w-full stg:resize-y stg:rounded-md stg:border stg:border-input stg:bg-background stg:px-2.5 stg:py-1.5 stg:text-xs stg:text-foreground",
|
|
74
|
+
"stg:placeholder:text-muted-foreground",
|
|
75
|
+
"stg:focus-visible:outline-none stg:focus-visible:ring-1 stg:focus-visible:ring-ring",
|
|
76
|
+
"stg:disabled:pointer-events-none stg:disabled:opacity-50",
|
|
77
|
+
readOnly && "stg:bg-muted-subtle stg:text-muted-foreground",
|
|
78
|
+
)}
|
|
79
|
+
/>
|
|
80
|
+
{helperText && (
|
|
81
|
+
<p className="stg:text-[0.65rem] stg:text-muted-foreground">
|
|
82
|
+
{helperText}
|
|
83
|
+
</p>
|
|
84
|
+
)}
|
|
85
|
+
{!readOnly && remaining <= COUNTER_THRESHOLD && (
|
|
86
|
+
<p className="stg:text-[0.65rem] stg:text-muted-foreground">
|
|
87
|
+
{remaining} characters left
|
|
88
|
+
</p>
|
|
89
|
+
)}
|
|
90
|
+
</div>
|
|
91
|
+
);
|
|
92
|
+
}
|
|
@@ -5,7 +5,8 @@ import {
|
|
|
5
5
|
VisibilitySelector,
|
|
6
6
|
type VisibilitySelectorMode,
|
|
7
7
|
} from "./VisibilitySelector.js";
|
|
8
|
-
import {
|
|
8
|
+
import { useCanSetPublicVisibility } from "./useCanSetPublicVisibility.js";
|
|
9
|
+
import { instanceVisibilityLevels } from "./visibilityLevels.js";
|
|
9
10
|
|
|
10
11
|
/** Props for {@link InstanceVisibilitySelector}. */
|
|
11
12
|
export interface InstanceVisibilitySelectorProps {
|
|
@@ -69,10 +70,16 @@ export function InstanceVisibilitySelector({
|
|
|
69
70
|
disabled = false,
|
|
70
71
|
className,
|
|
71
72
|
}: InstanceVisibilitySelectorProps) {
|
|
73
|
+
// Public is operator-granted in the cloud edition; the hook resolves the
|
|
74
|
+
// caller's grant here so every consumer (create dialogs, list rows) gets
|
|
75
|
+
// the locked Public row without wiring anything.
|
|
76
|
+
const canSetPublic = useCanSetPublicVisibility();
|
|
72
77
|
return (
|
|
73
78
|
<VisibilitySelector
|
|
74
79
|
visibility={visibility}
|
|
75
|
-
options={
|
|
80
|
+
options={instanceVisibilityLevels({
|
|
81
|
+
canSetPublicVisibility: canSetPublic.allowed,
|
|
82
|
+
})}
|
|
76
83
|
onVisibilityChange={onVisibilityChange}
|
|
77
84
|
mode={mode}
|
|
78
85
|
isPending={isPending}
|
|
@@ -1,15 +1,16 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
|
|
3
3
|
import { useCallback } from "react";
|
|
4
|
-
import
|
|
4
|
+
import { ApiResourceVisibility } from "@stigmer/protos/ai/stigmer/commons/apiresource/enum_pb";
|
|
5
5
|
import { useDeploymentMode } from "../deployment-mode.js";
|
|
6
6
|
import { PermissionGate } from "../iam-policy/PermissionGate.js";
|
|
7
7
|
import { useSsoProvider } from "../identity-provider/useSsoProvider.js";
|
|
8
|
+
import { useCanSetPublicVisibility } from "./useCanSetPublicVisibility.js";
|
|
8
9
|
import { VisibilityBadge, VisibilitySelector } from "./VisibilitySelector.js";
|
|
9
10
|
import {
|
|
10
11
|
blueprintVisibilityLevels,
|
|
11
12
|
environmentVisibilityLevels,
|
|
12
|
-
|
|
13
|
+
instanceVisibilityLevels,
|
|
13
14
|
} from "./visibilityLevels.js";
|
|
14
15
|
import {
|
|
15
16
|
useUpdateVisibility,
|
|
@@ -85,9 +86,19 @@ export interface ResourceVisibilityControlProps {
|
|
|
85
86
|
* the org boundary. In `local` mode there are no levels to choose (the
|
|
86
87
|
* OSS backend is single-user), so the control degrades to a badge.
|
|
87
88
|
*
|
|
89
|
+
* The Public level is operator-gated in the cloud edition (publishing is a
|
|
90
|
+
* curation decision): for callers without `can_set_public_visibility`
|
|
91
|
+
* ({@link useCanSetPublicVisibility}) the option renders locked with copy
|
|
92
|
+
* naming the path forward. The same permission opens the operator takedown
|
|
93
|
+
* lane — on a currently-public resource, an operator gets the interactive
|
|
94
|
+
* selector even without resource `can_edit`, so noisy public resources can
|
|
95
|
+
* be un-published directly from the console (every offered move off PUBLIC
|
|
96
|
+
* is a downgrade, which the backend allows operators unilaterally).
|
|
97
|
+
*
|
|
88
98
|
* The backend remains the enforcer (`ValidateVisibilityStep` rejects
|
|
89
|
-
* platform without an IdP
|
|
90
|
-
*
|
|
99
|
+
* platform without an IdP; `AuthorizeVisibilityTransitionStep` gates the
|
|
100
|
+
* PUBLIC level); the gates here only prevent offering an option that is
|
|
101
|
+
* guaranteed to fail.
|
|
91
102
|
*/
|
|
92
103
|
export function ResourceVisibilityControl({
|
|
93
104
|
kind,
|
|
@@ -99,6 +110,7 @@ export function ResourceVisibilityControl({
|
|
|
99
110
|
}: ResourceVisibilityControlProps) {
|
|
100
111
|
const { updateVisibility, isPending } = useUpdateVisibility(kind, resourceId);
|
|
101
112
|
const deploymentMode = useDeploymentMode();
|
|
113
|
+
const canSetPublic = useCanSetPublicVisibility();
|
|
102
114
|
|
|
103
115
|
const isInstance = INSTANCE_KINDS.has(kind);
|
|
104
116
|
const isEnvironment = kind === "environment";
|
|
@@ -113,10 +125,13 @@ export function ResourceVisibilityControl({
|
|
|
113
125
|
const options = isEnvironment
|
|
114
126
|
? environmentVisibilityLevels(deploymentMode)
|
|
115
127
|
: isInstance
|
|
116
|
-
?
|
|
128
|
+
? instanceVisibilityLevels({
|
|
129
|
+
canSetPublicVisibility: canSetPublic.allowed,
|
|
130
|
+
})
|
|
117
131
|
: blueprintVisibilityLevels({
|
|
118
132
|
deploymentMode,
|
|
119
133
|
hasIdentityProvider: ssoProvider !== null,
|
|
134
|
+
canSetPublicVisibility: canSetPublic.allowed,
|
|
120
135
|
});
|
|
121
136
|
|
|
122
137
|
const handleChange = useCallback(
|
|
@@ -141,6 +156,31 @@ export function ResourceVisibilityControl({
|
|
|
141
156
|
return badge;
|
|
142
157
|
}
|
|
143
158
|
|
|
159
|
+
const selector = (
|
|
160
|
+
<VisibilitySelector
|
|
161
|
+
visibility={visibility}
|
|
162
|
+
options={options}
|
|
163
|
+
onVisibilityChange={handleChange}
|
|
164
|
+
isPending={isPending}
|
|
165
|
+
ariaLabel={isInstance ? "Instance visibility" : "Resource visibility"}
|
|
166
|
+
className={className}
|
|
167
|
+
/>
|
|
168
|
+
);
|
|
169
|
+
|
|
170
|
+
// Operator takedown lane: on a currently-public resource, a caller holding
|
|
171
|
+
// can_set_public_visibility gets the control without resource can_edit —
|
|
172
|
+
// every offered move is a downgrade off PUBLIC, which the backend allows
|
|
173
|
+
// operators unilaterally (AuthorizeVisibilityTransitionStep), so no
|
|
174
|
+
// offered action can fail authorization. Scoped to the public state on
|
|
175
|
+
// purpose: on non-public foreign resources most transitions would be
|
|
176
|
+
// denied, and publishing those stays a request-to-operator flow.
|
|
177
|
+
if (
|
|
178
|
+
canSetPublic.allowed &&
|
|
179
|
+
visibility === ApiResourceVisibility.visibility_public
|
|
180
|
+
) {
|
|
181
|
+
return selector;
|
|
182
|
+
}
|
|
183
|
+
|
|
144
184
|
return (
|
|
145
185
|
<PermissionGate
|
|
146
186
|
resource={{ kind: FGA_KIND[kind], id: resourceId }}
|
|
@@ -148,14 +188,7 @@ export function ResourceVisibilityControl({
|
|
|
148
188
|
fallback={badge}
|
|
149
189
|
loading={badge}
|
|
150
190
|
>
|
|
151
|
-
|
|
152
|
-
visibility={visibility}
|
|
153
|
-
options={options}
|
|
154
|
-
onVisibilityChange={handleChange}
|
|
155
|
-
isPending={isPending}
|
|
156
|
-
ariaLabel={isInstance ? "Instance visibility" : "Resource visibility"}
|
|
157
|
-
className={className}
|
|
158
|
-
/>
|
|
191
|
+
{selector}
|
|
159
192
|
</PermissionGate>
|
|
160
193
|
);
|
|
161
194
|
}
|
|
@@ -53,6 +53,12 @@ export interface VisibilityOptionRowProps {
|
|
|
53
53
|
* label, one-line description, and a check when current. Shared by the
|
|
54
54
|
* {@link VisibilitySelector} popover and its create-mode inline list so
|
|
55
55
|
* option presentation has exactly one source.
|
|
56
|
+
*
|
|
57
|
+
* A level carrying {@link VisibilityLevelOption.lockedReason} renders
|
|
58
|
+
* non-interactive with a lock affordance and the reason as its detail line
|
|
59
|
+
* — the level stays discoverable (the reason names the path forward)
|
|
60
|
+
* without being selectable. The locked row keeps its normal opacity: it is
|
|
61
|
+
* informative, not in a transient disabled state.
|
|
56
62
|
*/
|
|
57
63
|
export const VisibilityOptionRow = forwardRef<
|
|
58
64
|
HTMLButtonElement,
|
|
@@ -71,6 +77,7 @@ export const VisibilityOptionRow = forwardRef<
|
|
|
71
77
|
},
|
|
72
78
|
ref,
|
|
73
79
|
) {
|
|
80
|
+
const locked = option.lockedReason !== undefined;
|
|
74
81
|
const selectionAttr =
|
|
75
82
|
role === "radio"
|
|
76
83
|
? { "aria-checked": isSelected }
|
|
@@ -82,16 +89,20 @@ export const VisibilityOptionRow = forwardRef<
|
|
|
82
89
|
type="button"
|
|
83
90
|
role={role}
|
|
84
91
|
{...selectionAttr}
|
|
92
|
+
aria-disabled={locked || undefined}
|
|
85
93
|
tabIndex={tabIndex}
|
|
86
|
-
disabled={disabled}
|
|
94
|
+
disabled={disabled || locked}
|
|
87
95
|
onClick={onSelect}
|
|
88
96
|
onMouseEnter={onMouseEnter}
|
|
89
97
|
onKeyDown={onKeyDown}
|
|
90
98
|
className={cn(
|
|
91
99
|
"stg:flex stg:w-full stg:items-start stg:gap-2 stg:rounded-md stg:px-2.5 stg:py-2 stg:text-left stg:transition-colors",
|
|
92
100
|
"stg:focus-visible:outline-none stg:focus-visible:ring-2 stg:focus-visible:ring-ring",
|
|
93
|
-
|
|
94
|
-
|
|
101
|
+
locked
|
|
102
|
+
? "stg:disabled:pointer-events-none stg:cursor-default"
|
|
103
|
+
: "stg:disabled:pointer-events-none stg:disabled:opacity-50",
|
|
104
|
+
!locked &&
|
|
105
|
+
(isHighlighted ? "stg:bg-accent stg:text-foreground" : "stg:hover:bg-accent-hover"),
|
|
95
106
|
)}
|
|
96
107
|
>
|
|
97
108
|
<VisibilityIcon
|
|
@@ -99,14 +110,25 @@ export const VisibilityOptionRow = forwardRef<
|
|
|
99
110
|
className="stg:mt-0.5 stg:size-3.5 stg:shrink-0 stg:text-muted-foreground"
|
|
100
111
|
/>
|
|
101
112
|
<span className="stg:min-w-0 stg:flex-1">
|
|
102
|
-
<span
|
|
113
|
+
<span
|
|
114
|
+
className={cn(
|
|
115
|
+
"stg:block stg:text-xs stg:font-medium",
|
|
116
|
+
locked ? "stg:text-muted-foreground" : "stg:text-foreground",
|
|
117
|
+
)}
|
|
118
|
+
>
|
|
103
119
|
{option.label}
|
|
104
120
|
</span>
|
|
105
121
|
<span className="stg:block stg:text-[0.65rem] stg:leading-snug stg:text-muted-foreground">
|
|
106
|
-
{option.description}
|
|
122
|
+
{locked ? option.lockedReason : option.description}
|
|
107
123
|
</span>
|
|
108
124
|
</span>
|
|
109
|
-
{
|
|
125
|
+
{locked ? (
|
|
126
|
+
<LockIcon className="stg:mt-0.5 stg:size-3.5 stg:shrink-0 stg:text-muted-foreground" />
|
|
127
|
+
) : (
|
|
128
|
+
isSelected && (
|
|
129
|
+
<CheckIcon className="stg:mt-0.5 stg:size-3.5 stg:shrink-0 stg:text-primary" />
|
|
130
|
+
)
|
|
131
|
+
)}
|
|
110
132
|
</button>
|
|
111
133
|
);
|
|
112
134
|
});
|
|
@@ -150,6 +150,12 @@ export function VisibilitySelector({
|
|
|
150
150
|
|
|
151
151
|
const handleSelect = useCallback(
|
|
152
152
|
(option: VisibilityLevelOption) => {
|
|
153
|
+
// Locked levels are not selectable; the row is disabled, this guard
|
|
154
|
+
// is defense in depth for programmatic activation.
|
|
155
|
+
if (option.lockedReason !== undefined) {
|
|
156
|
+
return;
|
|
157
|
+
}
|
|
158
|
+
|
|
153
159
|
const value = option.value;
|
|
154
160
|
if (value === visibility) {
|
|
155
161
|
setPendingInline(null);
|
|
@@ -193,11 +199,17 @@ export function VisibilitySelector({
|
|
|
193
199
|
const moveFocus = useCallback(
|
|
194
200
|
(from: number, delta: number) => {
|
|
195
201
|
const count = effectiveOptions.length;
|
|
196
|
-
|
|
202
|
+
// Skip locked rows: their buttons are disabled and cannot take focus,
|
|
203
|
+
// so landing on one would strand the roving tabindex.
|
|
204
|
+
let next = from;
|
|
205
|
+
for (let step = 0; step < count; step++) {
|
|
206
|
+
next = (next + delta + count) % count;
|
|
207
|
+
if (effectiveOptions[next]?.lockedReason === undefined) break;
|
|
208
|
+
}
|
|
197
209
|
setHighlightIdx(next);
|
|
198
210
|
optionRefs.current[next]?.focus();
|
|
199
211
|
},
|
|
200
|
-
[effectiveOptions
|
|
212
|
+
[effectiveOptions],
|
|
201
213
|
);
|
|
202
214
|
|
|
203
215
|
const handleRowKeyDown = useCallback(
|