@stigmer/react 3.0.7 → 3.0.8-dev.20260612073024

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.
Files changed (133) hide show
  1. package/access/ManageAccessButton.d.ts +47 -0
  2. package/access/ManageAccessButton.d.ts.map +1 -0
  3. package/access/ManageAccessButton.js +45 -0
  4. package/access/ManageAccessButton.js.map +1 -0
  5. package/access/ManageAccessDialog.d.ts +60 -0
  6. package/access/ManageAccessDialog.d.ts.map +1 -0
  7. package/access/ManageAccessDialog.js +83 -0
  8. package/access/ManageAccessDialog.js.map +1 -0
  9. package/access/index.d.ts +5 -0
  10. package/access/index.d.ts.map +1 -0
  11. package/access/index.js +7 -0
  12. package/access/index.js.map +1 -0
  13. package/access/types.d.ts +56 -0
  14. package/access/types.d.ts.map +1 -0
  15. package/access/types.js +2 -0
  16. package/access/types.js.map +1 -0
  17. package/access/useManageAccess.d.ts +60 -0
  18. package/access/useManageAccess.d.ts.map +1 -0
  19. package/access/useManageAccess.js +41 -0
  20. package/access/useManageAccess.js.map +1 -0
  21. package/agent/AgentDetailView.d.ts.map +1 -1
  22. package/agent/AgentDetailView.js +34 -4
  23. package/agent/AgentDetailView.js.map +1 -1
  24. package/agent-instance/AgentInstanceDetailPanel.d.ts.map +1 -1
  25. package/agent-instance/AgentInstanceDetailPanel.js +14 -4
  26. package/agent-instance/AgentInstanceDetailPanel.js.map +1 -1
  27. package/iam-policy/GrantAccessForm.d.ts +15 -5
  28. package/iam-policy/GrantAccessForm.d.ts.map +1 -1
  29. package/iam-policy/GrantAccessForm.js +15 -12
  30. package/iam-policy/GrantAccessForm.js.map +1 -1
  31. package/iam-policy/OrgMembersPanel.d.ts.map +1 -1
  32. package/iam-policy/OrgMembersPanel.js +2 -1
  33. package/iam-policy/OrgMembersPanel.js.map +1 -1
  34. package/iam-policy/PeopleWithAccess.d.ts +34 -0
  35. package/iam-policy/PeopleWithAccess.d.ts.map +1 -0
  36. package/iam-policy/PeopleWithAccess.js +55 -0
  37. package/iam-policy/PeopleWithAccess.js.map +1 -0
  38. package/iam-policy/PrincipalPicker.d.ts +48 -0
  39. package/iam-policy/PrincipalPicker.d.ts.map +1 -0
  40. package/iam-policy/PrincipalPicker.js +139 -0
  41. package/iam-policy/PrincipalPicker.js.map +1 -0
  42. package/iam-policy/ProviderBadge.d.ts +28 -0
  43. package/iam-policy/ProviderBadge.d.ts.map +1 -0
  44. package/iam-policy/ProviderBadge.js +31 -0
  45. package/iam-policy/ProviderBadge.js.map +1 -0
  46. package/iam-policy/SharePanel.d.ts +13 -5
  47. package/iam-policy/SharePanel.d.ts.map +1 -1
  48. package/iam-policy/SharePanel.js +9 -34
  49. package/iam-policy/SharePanel.js.map +1 -1
  50. package/iam-policy/index.d.ts +3 -0
  51. package/iam-policy/index.d.ts.map +1 -1
  52. package/iam-policy/index.js +3 -0
  53. package/iam-policy/index.js.map +1 -1
  54. package/index.d.ts +8 -6
  55. package/index.d.ts.map +1 -1
  56. package/index.js +6 -3
  57. package/index.js.map +1 -1
  58. package/mcp-server/McpServerDetailView.d.ts.map +1 -1
  59. package/mcp-server/McpServerDetailView.js +41 -12
  60. package/mcp-server/McpServerDetailView.js.map +1 -1
  61. package/organization/OrgProvider.d.ts +9 -0
  62. package/organization/OrgProvider.d.ts.map +1 -1
  63. package/organization/OrgProvider.js +12 -0
  64. package/organization/OrgProvider.js.map +1 -1
  65. package/organization/index.d.ts +1 -1
  66. package/organization/index.d.ts.map +1 -1
  67. package/organization/index.js +1 -1
  68. package/organization/index.js.map +1 -1
  69. package/package.json +4 -4
  70. package/skill/SkillDetailView.d.ts.map +1 -1
  71. package/skill/SkillDetailView.js +31 -3
  72. package/skill/SkillDetailView.js.map +1 -1
  73. package/src/access/ManageAccessButton.tsx +115 -0
  74. package/src/access/ManageAccessDialog.tsx +239 -0
  75. package/src/access/__tests__/ManageAccessButton.test.tsx +62 -0
  76. package/src/access/__tests__/ManageAccessDialog.test.tsx +146 -0
  77. package/src/access/index.ts +21 -0
  78. package/src/access/types.ts +58 -0
  79. package/src/access/useManageAccess.tsx +101 -0
  80. package/src/agent/AgentDetailView.tsx +50 -21
  81. package/src/agent-instance/AgentInstanceDetailPanel.tsx +24 -42
  82. package/src/iam-policy/GrantAccessForm.tsx +30 -35
  83. package/src/iam-policy/OrgMembersPanel.tsx +2 -0
  84. package/src/iam-policy/PeopleWithAccess.tsx +220 -0
  85. package/src/iam-policy/PrincipalPicker.tsx +347 -0
  86. package/src/iam-policy/ProviderBadge.tsx +53 -0
  87. package/src/iam-policy/SharePanel.tsx +20 -165
  88. package/src/iam-policy/index.ts +17 -0
  89. package/src/index.ts +31 -0
  90. package/src/mcp-server/McpServerDetailView.tsx +37 -9
  91. package/src/organization/OrgProvider.tsx +13 -0
  92. package/src/organization/index.ts +1 -1
  93. package/src/session/__tests__/execution-target.test.ts +18 -0
  94. package/src/skill/SkillDetailView.tsx +34 -9
  95. package/src/workflow/WorkflowDetailView.tsx +49 -22
  96. package/src/workflow/WorkflowExecutionHeader.tsx +12 -1
  97. package/src/workflow/WorkflowExecutionViewer.tsx +8 -1
  98. package/src/workflow/index.ts +4 -0
  99. package/src/workflow/instance/RunVisibilityControl.tsx +116 -0
  100. package/src/workflow/instance/WorkflowInstanceDetailPanel.tsx +55 -42
  101. package/src/workflow/instance/index.ts +5 -0
  102. package/src/workflow/instance/useUpdateWorkflowInstanceExecutionVisibility.ts +74 -0
  103. package/styles.css +1 -1
  104. package/workflow/WorkflowDetailView.d.ts.map +1 -1
  105. package/workflow/WorkflowDetailView.js +31 -3
  106. package/workflow/WorkflowDetailView.js.map +1 -1
  107. package/workflow/WorkflowExecutionHeader.d.ts +7 -0
  108. package/workflow/WorkflowExecutionHeader.d.ts.map +1 -1
  109. package/workflow/WorkflowExecutionHeader.js +2 -2
  110. package/workflow/WorkflowExecutionHeader.js.map +1 -1
  111. package/workflow/WorkflowExecutionViewer.d.ts +6 -1
  112. package/workflow/WorkflowExecutionViewer.d.ts.map +1 -1
  113. package/workflow/WorkflowExecutionViewer.js +2 -2
  114. package/workflow/WorkflowExecutionViewer.js.map +1 -1
  115. package/workflow/index.d.ts +1 -1
  116. package/workflow/index.d.ts.map +1 -1
  117. package/workflow/index.js +1 -1
  118. package/workflow/index.js.map +1 -1
  119. package/workflow/instance/RunVisibilityControl.d.ts +25 -0
  120. package/workflow/instance/RunVisibilityControl.d.ts.map +1 -0
  121. package/workflow/instance/RunVisibilityControl.js +56 -0
  122. package/workflow/instance/RunVisibilityControl.js.map +1 -0
  123. package/workflow/instance/WorkflowInstanceDetailPanel.d.ts.map +1 -1
  124. package/workflow/instance/WorkflowInstanceDetailPanel.js +30 -4
  125. package/workflow/instance/WorkflowInstanceDetailPanel.js.map +1 -1
  126. package/workflow/instance/index.d.ts +2 -0
  127. package/workflow/instance/index.d.ts.map +1 -1
  128. package/workflow/instance/index.js +2 -0
  129. package/workflow/instance/index.js.map +1 -1
  130. package/workflow/instance/useUpdateWorkflowInstanceExecutionVisibility.d.ts +30 -0
  131. package/workflow/instance/useUpdateWorkflowInstanceExecutionVisibility.d.ts.map +1 -0
  132. package/workflow/instance/useUpdateWorkflowInstanceExecutionVisibility.js +39 -0
  133. package/workflow/instance/useUpdateWorkflowInstanceExecutionVisibility.js.map +1 -0
@@ -1,6 +1,6 @@
1
1
  "use client";
2
2
 
3
- import { memo, useMemo } from "react";
3
+ import { memo, useMemo, type ReactNode } from "react";
4
4
  import type { WorkflowExecution } from "@stigmer/protos/ai/stigmer/agentic/workflowexecution/v1/api_pb";
5
5
  import { ExecutionPhase } from "@stigmer/protos/ai/stigmer/agentic/workflowexecution/v1/enum_pb";
6
6
  import { cn } from "@stigmer/theme";
@@ -21,6 +21,12 @@ export interface WorkflowExecutionHeaderProps {
21
21
  readonly isDiagnosing?: boolean;
22
22
  /** Called when the user clicks "Compare with..." on a terminal execution. */
23
23
  readonly onCompare?: () => void;
24
+ /**
25
+ * Host-supplied action elements rendered at the trailing edge of the
26
+ * header (e.g. a Share control). Kept routing/auth-agnostic per DD-004 —
27
+ * the SDK renders the slot; the host owns its behavior.
28
+ */
29
+ readonly headerActions?: ReactNode;
24
30
  readonly className?: string;
25
31
  }
26
32
 
@@ -53,6 +59,7 @@ export const WorkflowExecutionHeader = memo(function WorkflowExecutionHeader({
53
59
  onDiagnose,
54
60
  isDiagnosing,
55
61
  onCompare,
62
+ headerActions,
56
63
  className,
57
64
  }: WorkflowExecutionHeaderProps) {
58
65
  const phase = execution.status?.phase ?? ExecutionPhase.EXECUTION_PHASE_UNSPECIFIED;
@@ -160,6 +167,10 @@ export const WorkflowExecutionHeader = memo(function WorkflowExecutionHeader({
160
167
  />
161
168
  </>
162
169
  )}
170
+
171
+ {headerActions && (
172
+ <div className="relative flex items-center">{headerActions}</div>
173
+ )}
163
174
  </div>
164
175
  </header>
165
176
  );
@@ -42,8 +42,13 @@ export interface WorkflowExecutionViewerProps {
42
42
  * application handles navigation to the workflow editor (DD-004).
43
43
  */
44
44
  readonly onNavigateToWorkflowEditor?: (yaml: string, workflowSlug: string) => void;
45
- /** Additional action elements to render in the header. */
45
+ /** Additional action elements to render in the sidebar inspector footer. */
46
46
  readonly additionalActions?: ReactNode;
47
+ /**
48
+ * Host-supplied action elements rendered in the header action group
49
+ * (e.g. a Share control). Routing/auth-agnostic per DD-004.
50
+ */
51
+ readonly headerActions?: ReactNode;
47
52
  /**
48
53
  * Whether task nodes in the execution graph can be dragged to
49
54
  * rearrange the layout for presentations. Drag positions are
@@ -80,6 +85,7 @@ export const WorkflowExecutionViewer = memo(function WorkflowExecutionViewer({
80
85
  onNavigateToAgentExecution,
81
86
  onNavigateToWorkflowEditor,
82
87
  additionalActions,
88
+ headerActions,
83
89
  nodesDraggable,
84
90
  className,
85
91
  }: WorkflowExecutionViewerProps) {
@@ -268,6 +274,7 @@ export const WorkflowExecutionViewer = memo(function WorkflowExecutionViewer({
268
274
  onDiagnose={org ? handleDiagnose : undefined}
269
275
  isDiagnosing={showDiagnosis}
270
276
  onCompare={handleOpenComparePicker}
277
+ headerActions={headerActions}
271
278
  />
272
279
 
273
280
  {/* Comparison picker dialog */}
@@ -705,6 +705,8 @@ export {
705
705
  type UseCreateWorkflowInstanceReturn,
706
706
  useUpdateWorkflowInstance,
707
707
  type UseUpdateWorkflowInstanceReturn,
708
+ useUpdateWorkflowInstanceExecutionVisibility,
709
+ type UseUpdateWorkflowInstanceExecutionVisibilityReturn,
708
710
  useDeleteWorkflowInstance,
709
711
  type UseDeleteWorkflowInstanceReturn,
710
712
  WorkflowInstanceEmptyState,
@@ -715,6 +717,8 @@ export {
715
717
  type CreateWorkflowInstanceDialogProps,
716
718
  WorkflowInstanceDetailPanel,
717
719
  type WorkflowInstanceDetailPanelProps,
720
+ RunVisibilityControl,
721
+ type RunVisibilityControlProps,
718
722
  } from "./instance";
719
723
 
720
724
  // Execution Comparison — run-vs-run comparison
@@ -0,0 +1,116 @@
1
+ "use client";
2
+
3
+ import { useCallback } from "react";
4
+ import { cn } from "@stigmer/theme";
5
+ import { WorkflowExecutionVisibility } from "@stigmer/protos/ai/stigmer/agentic/workflowinstance/v1/spec_pb";
6
+ import { getUserMessage } from "@stigmer/sdk";
7
+ import { useUpdateWorkflowInstanceExecutionVisibility } from "./useUpdateWorkflowInstanceExecutionVisibility";
8
+
9
+ /** Props for {@link RunVisibilityControl}. */
10
+ export interface RunVisibilityControlProps {
11
+ /** Id of the workflow instance whose run visibility is edited. */
12
+ readonly instanceId: string;
13
+ /** Current `execution_visibility` from the instance spec. */
14
+ readonly executionVisibility: WorkflowExecutionVisibility;
15
+ /** Called after a successful change so the host can refresh the instance. */
16
+ readonly onChanged?: () => void;
17
+ }
18
+
19
+ interface RunVisibilityOption {
20
+ readonly value: WorkflowExecutionVisibility;
21
+ readonly label: string;
22
+ readonly description: string;
23
+ }
24
+
25
+ const RUN_VISIBILITY_OPTIONS: readonly RunVisibilityOption[] = [
26
+ {
27
+ value: WorkflowExecutionVisibility.private,
28
+ label: "Only the person who runs it",
29
+ description: "Each run is visible only to whoever started it (and explicit shares).",
30
+ },
31
+ {
32
+ value: WorkflowExecutionVisibility.organization,
33
+ label: "All organization members",
34
+ description: "Everyone in the organization can observe every run of this instance.",
35
+ },
36
+ ];
37
+
38
+ /**
39
+ * Segmented control for an instance's run (execution) visibility — a separate
40
+ * axis from the instance's own visibility: an owner can keep the instance
41
+ * private while letting the whole org observe its runs.
42
+ *
43
+ * Writes the `execution_visibility` spec field via the dedicated RPC, which
44
+ * reconciles the dormant `workflow_instance#execution_viewer` FGA relation in
45
+ * Cloud mode. `unspecified` is treated as private (the default).
46
+ *
47
+ * Only meaningful while the instance itself is private; an ORG/PUBLIC instance
48
+ * already exposes its runs to org members by inheritance, so callers should
49
+ * render this only in the private case.
50
+ */
51
+ export function RunVisibilityControl({
52
+ instanceId,
53
+ executionVisibility,
54
+ onChanged,
55
+ }: RunVisibilityControlProps) {
56
+ const { updateExecutionVisibility, isUpdating, error } =
57
+ useUpdateWorkflowInstanceExecutionVisibility();
58
+
59
+ const current =
60
+ executionVisibility === WorkflowExecutionVisibility.unspecified
61
+ ? WorkflowExecutionVisibility.private
62
+ : executionVisibility;
63
+
64
+ const handleSelect = useCallback(
65
+ async (value: WorkflowExecutionVisibility) => {
66
+ if (value === current || isUpdating) return;
67
+ try {
68
+ await updateExecutionVisibility(instanceId, value);
69
+ onChanged?.();
70
+ } catch {
71
+ // error surfaced below
72
+ }
73
+ },
74
+ [current, isUpdating, updateExecutionVisibility, instanceId, onChanged],
75
+ );
76
+
77
+ return (
78
+ <div className="space-y-2">
79
+ <div
80
+ role="radiogroup"
81
+ aria-label="Run visibility"
82
+ className="flex flex-col gap-1.5"
83
+ >
84
+ {RUN_VISIBILITY_OPTIONS.map((option) => {
85
+ const selected = option.value === current;
86
+ return (
87
+ <button
88
+ key={option.value}
89
+ type="button"
90
+ role="radio"
91
+ aria-checked={selected}
92
+ disabled={isUpdating}
93
+ onClick={() => handleSelect(option.value)}
94
+ className={cn(
95
+ "flex flex-col items-start gap-0.5 rounded-md border px-3 py-2 text-left",
96
+ "focus:outline-none focus:ring-2 focus:ring-ring",
97
+ "disabled:opacity-60",
98
+ selected
99
+ ? "border-primary bg-primary/5"
100
+ : "border-border hover:bg-accent-hover",
101
+ )}
102
+ >
103
+ <span className="text-xs font-medium text-foreground">{option.label}</span>
104
+ <span className="text-[0.65rem] text-muted-foreground">{option.description}</span>
105
+ </button>
106
+ );
107
+ })}
108
+ </div>
109
+ {error && (
110
+ <p className="text-xs text-destructive" role="alert">
111
+ {getUserMessage(error)}
112
+ </p>
113
+ )}
114
+ </div>
115
+ );
116
+ }
@@ -6,13 +6,16 @@ import { timestampDate } from "@bufbuild/protobuf/wkt";
6
6
  import type { WorkflowInstance } from "@stigmer/protos/ai/stigmer/agentic/workflowinstance/v1/api_pb";
7
7
  import { ApiResourceVisibility } from "@stigmer/protos/ai/stigmer/commons/apiresource/enum_pb";
8
8
  import { ApiResourceKind } from "@stigmer/protos/ai/stigmer/commons/apiresource/apiresourcekind/api_resource_kind_pb";
9
+ import { WorkflowExecutionVisibility } from "@stigmer/protos/ai/stigmer/agentic/workflowinstance/v1/spec_pb";
9
10
  import type { ResourceRef } from "@stigmer/sdk";
10
11
  import { getUserMessage } from "@stigmer/sdk";
11
12
  import { useUpdateWorkflowInstance } from "./useUpdateWorkflowInstance";
12
13
  import { useDeleteWorkflowInstance } from "./useDeleteWorkflowInstance";
13
- import { ResourceVisibilityControl } from "../../library/ResourceVisibilityControl";
14
+ import { RunVisibilityControl } from "./RunVisibilityControl";
15
+ import { VisibilityBadge } from "../../library/VisibilitySelector";
14
16
  import { PermissionGate } from "../../iam-policy/PermissionGate";
15
- import { SharePanel } from "../../iam-policy/SharePanel";
17
+ import { useCheckPermission } from "../../iam-policy/useCheckPermission";
18
+ import { ManageAccessButton } from "../../access/ManageAccessButton";
16
19
  import { EnvironmentPicker } from "../../environment/EnvironmentPicker";
17
20
  import { useEnvironmentList } from "../../environment/useEnvironmentList";
18
21
 
@@ -58,10 +61,37 @@ export function WorkflowInstanceDetailPanel({
58
61
 
59
62
  const [isEditingEnvs, setIsEditingEnvs] = useState(false);
60
63
  const [editEnvRefs, setEditEnvRefs] = useState<ResourceRef[]>([]);
61
- const [showSharePanel, setShowSharePanel] = useState(false);
62
64
  const [showDeleteConfirm, setShowDeleteConfirm] = useState(false);
63
65
  const [deleteError, setDeleteError] = useState<Error | null>(null);
64
66
 
67
+ const visibility = meta?.visibility ?? ApiResourceVisibility.visibility_private;
68
+ // Run observability is a separate axis from instance visibility, and only
69
+ // meaningful while the instance is private (ORG/PUBLIC already expose runs
70
+ // by inheritance). It is offered only to those who can grant access, so it
71
+ // rides into the dialog as the resource-specific section — present only when
72
+ // both conditions hold.
73
+ const { allowed: canGrantAccess } = useCheckPermission(
74
+ id ? { kind: "workflow_instance", id } : null,
75
+ "can_grant_access",
76
+ );
77
+ const runVisibilitySection =
78
+ visibility === ApiResourceVisibility.visibility_private && canGrantAccess
79
+ ? {
80
+ title: "Run visibility",
81
+ description:
82
+ "Keep the instance private while choosing who can observe its runs.",
83
+ content: (
84
+ <RunVisibilityControl
85
+ instanceId={id}
86
+ executionVisibility={
87
+ spec?.executionVisibility ?? WorkflowExecutionVisibility.unspecified
88
+ }
89
+ onChanged={onUpdated}
90
+ />
91
+ ),
92
+ }
93
+ : undefined;
94
+
65
95
  const handleStartEditEnvs = useCallback(() => {
66
96
  const currentRefs: ResourceRef[] = (spec?.environmentRefs ?? []).map((ref) => ({
67
97
  org: ref.org || org,
@@ -115,9 +145,12 @@ export function WorkflowInstanceDetailPanel({
115
145
  {/* Header */}
116
146
  <div className="flex items-center justify-between border-b border-border px-4 py-3">
117
147
  <div>
118
- <h3 className="text-sm font-semibold text-foreground">
119
- {meta?.name || meta?.slug || "Instance"}
120
- </h3>
148
+ <div className="flex items-center gap-2">
149
+ <h3 className="text-sm font-semibold text-foreground">
150
+ {meta?.name || meta?.slug || "Instance"}
151
+ </h3>
152
+ <VisibilityBadge visibility={visibility} />
153
+ </div>
121
154
  <p className="text-[0.65rem] text-muted-foreground">
122
155
  {createdAt && `Created ${createdAt.toLocaleDateString()}`}
123
156
  {updatedAt && ` · Updated ${updatedAt.toLocaleDateString()}`}
@@ -137,19 +170,21 @@ export function WorkflowInstanceDetailPanel({
137
170
  Run
138
171
  </button>
139
172
  )}
140
- <PermissionGate resource={{ kind: "workflow_instance", id }} relation="can_grant_access">
141
- <button
142
- type="button"
143
- onClick={() => setShowSharePanel((v) => !v)}
144
- className={cn(
145
- "rounded-md px-2.5 py-1 text-xs font-medium",
146
- "border border-border text-foreground hover:bg-accent-hover",
147
- "focus:outline-none focus:ring-2 focus:ring-ring",
148
- )}
149
- >
150
- Share
151
- </button>
152
- </PermissionGate>
173
+ <ManageAccessButton
174
+ resource={{
175
+ kind: ApiResourceKind.workflow_instance,
176
+ kindString: "workflow_instance",
177
+ id,
178
+ org: meta?.org ?? "",
179
+ name: meta?.name,
180
+ }}
181
+ visibility={{
182
+ kind: "workflowInstance",
183
+ current: visibility,
184
+ onChanged: onUpdated,
185
+ }}
186
+ extraSection={runVisibilitySection}
187
+ />
153
188
  <button
154
189
  type="button"
155
190
  onClick={onClose}
@@ -241,29 +276,6 @@ export function WorkflowInstanceDetailPanel({
241
276
  )}
242
277
  </div>
243
278
 
244
- {/* Visibility */}
245
- <div className="px-4 py-3">
246
- <h4 className="text-xs font-medium text-muted-foreground mb-2">Visibility</h4>
247
- <ResourceVisibilityControl
248
- kind="workflowInstance"
249
- resourceId={id}
250
- visibility={meta?.visibility ?? ApiResourceVisibility.visibility_private}
251
- onChanged={onUpdated}
252
- />
253
- </div>
254
-
255
- {/* Share Panel */}
256
- {showSharePanel && (
257
- <div className="px-4 py-3">
258
- <SharePanel
259
- resource={{ kind: "workflow_instance", id, resourceKind: ApiResourceKind.workflow_instance }}
260
- resourceKindString="workflow_instance"
261
- resourceKind={ApiResourceKind.workflow_instance}
262
- onClose={() => setShowSharePanel(false)}
263
- />
264
- </div>
265
- )}
266
-
267
279
  {/* Delete */}
268
280
  <PermissionGate resource={{ kind: "workflow_instance", id }} relation="can_delete">
269
281
  <div className="px-4 py-3">
@@ -331,3 +343,4 @@ function CloseIcon() {
331
343
  </svg>
332
344
  );
333
345
  }
346
+
@@ -1,8 +1,13 @@
1
1
  export { useWorkflowInstance, type UseWorkflowInstanceReturn } from "./useWorkflowInstance";
2
2
  export { useCreateWorkflowInstance, type UseCreateWorkflowInstanceReturn } from "./useCreateWorkflowInstance";
3
3
  export { useUpdateWorkflowInstance, type UseUpdateWorkflowInstanceReturn } from "./useUpdateWorkflowInstance";
4
+ export {
5
+ useUpdateWorkflowInstanceExecutionVisibility,
6
+ type UseUpdateWorkflowInstanceExecutionVisibilityReturn,
7
+ } from "./useUpdateWorkflowInstanceExecutionVisibility";
4
8
  export { useDeleteWorkflowInstance, type UseDeleteWorkflowInstanceReturn } from "./useDeleteWorkflowInstance";
5
9
  export { WorkflowInstanceEmptyState, type WorkflowInstanceEmptyStateProps } from "./WorkflowInstanceEmptyState";
6
10
  export { WorkflowInstanceList, type WorkflowInstanceListProps } from "./WorkflowInstanceList";
7
11
  export { CreateWorkflowInstanceDialog, type CreateWorkflowInstanceDialogProps } from "./CreateWorkflowInstanceDialog";
8
12
  export { WorkflowInstanceDetailPanel, type WorkflowInstanceDetailPanelProps } from "./WorkflowInstanceDetailPanel";
13
+ export { RunVisibilityControl, type RunVisibilityControlProps } from "./RunVisibilityControl";
@@ -0,0 +1,74 @@
1
+ "use client";
2
+
3
+ import { useCallback, useState } from "react";
4
+ import { create } from "@bufbuild/protobuf";
5
+ import type { WorkflowInstance } from "@stigmer/protos/ai/stigmer/agentic/workflowinstance/v1/api_pb";
6
+ import { UpdateExecutionVisibilityInputSchema } from "@stigmer/protos/ai/stigmer/agentic/workflowinstance/v1/io_pb";
7
+ import type { WorkflowExecutionVisibility } from "@stigmer/protos/ai/stigmer/agentic/workflowinstance/v1/spec_pb";
8
+ import { useStigmer } from "../../hooks";
9
+ import { toError } from "../../internal/toError";
10
+
11
+ /** Return value of {@link useUpdateWorkflowInstanceExecutionVisibility}. */
12
+ export interface UseUpdateWorkflowInstanceExecutionVisibilityReturn {
13
+ /**
14
+ * Update who can observe the runs (executions) of a workflow instance.
15
+ *
16
+ * This is distinct from the instance's own visibility: it controls run
17
+ * observability via the `workflow_instance#execution_viewer` relation,
18
+ * letting an owner keep the instance private while opting all org members
19
+ * into watching its executions.
20
+ */
21
+ readonly updateExecutionVisibility: (
22
+ resourceId: string,
23
+ executionVisibility: WorkflowExecutionVisibility,
24
+ ) => Promise<WorkflowInstance>;
25
+ /** `true` while the update RPC is in flight. */
26
+ readonly isUpdating: boolean;
27
+ /** Error from the last failed update, or `null` when healthy. */
28
+ readonly error: Error | null;
29
+ /** Clear the error state. */
30
+ readonly clearError: () => void;
31
+ }
32
+
33
+ /**
34
+ * Mutation hook that updates the execution (run) visibility of a
35
+ * WorkflowInstance.
36
+ *
37
+ * Wraps `stigmer.workflowInstance.updateExecutionVisibility()` with
38
+ * loading/error state. The caller is responsible for refreshing the instance
39
+ * after a successful update.
40
+ */
41
+ export function useUpdateWorkflowInstanceExecutionVisibility(): UseUpdateWorkflowInstanceExecutionVisibilityReturn {
42
+ const stigmer = useStigmer();
43
+ const [isUpdating, setIsUpdating] = useState(false);
44
+ const [error, setError] = useState<Error | null>(null);
45
+
46
+ const clearError = useCallback(() => setError(null), []);
47
+
48
+ const updateExecutionVisibility = useCallback(
49
+ async (
50
+ resourceId: string,
51
+ executionVisibility: WorkflowExecutionVisibility,
52
+ ): Promise<WorkflowInstance> => {
53
+ setIsUpdating(true);
54
+ setError(null);
55
+
56
+ try {
57
+ return await stigmer.workflowInstance.updateExecutionVisibility(
58
+ create(UpdateExecutionVisibilityInputSchema, {
59
+ resourceId,
60
+ executionVisibility,
61
+ }),
62
+ );
63
+ } catch (err) {
64
+ setError(toError(err));
65
+ throw err;
66
+ } finally {
67
+ setIsUpdating(false);
68
+ }
69
+ },
70
+ [stigmer],
71
+ );
72
+
73
+ return { updateExecutionVisibility, isUpdating, error, clearError };
74
+ }