@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.
- package/access/ManageAccessButton.d.ts +47 -0
- package/access/ManageAccessButton.d.ts.map +1 -0
- package/access/ManageAccessButton.js +45 -0
- package/access/ManageAccessButton.js.map +1 -0
- package/access/ManageAccessDialog.d.ts +60 -0
- package/access/ManageAccessDialog.d.ts.map +1 -0
- package/access/ManageAccessDialog.js +83 -0
- package/access/ManageAccessDialog.js.map +1 -0
- package/access/index.d.ts +5 -0
- package/access/index.d.ts.map +1 -0
- package/access/index.js +7 -0
- package/access/index.js.map +1 -0
- package/access/types.d.ts +56 -0
- package/access/types.d.ts.map +1 -0
- package/access/types.js +2 -0
- package/access/types.js.map +1 -0
- package/access/useManageAccess.d.ts +60 -0
- package/access/useManageAccess.d.ts.map +1 -0
- package/access/useManageAccess.js +41 -0
- package/access/useManageAccess.js.map +1 -0
- package/agent/AgentDetailView.d.ts.map +1 -1
- package/agent/AgentDetailView.js +34 -4
- package/agent/AgentDetailView.js.map +1 -1
- package/agent-instance/AgentInstanceDetailPanel.d.ts.map +1 -1
- package/agent-instance/AgentInstanceDetailPanel.js +14 -4
- package/agent-instance/AgentInstanceDetailPanel.js.map +1 -1
- package/iam-policy/GrantAccessForm.d.ts +15 -5
- package/iam-policy/GrantAccessForm.d.ts.map +1 -1
- package/iam-policy/GrantAccessForm.js +15 -12
- package/iam-policy/GrantAccessForm.js.map +1 -1
- package/iam-policy/OrgMembersPanel.d.ts.map +1 -1
- package/iam-policy/OrgMembersPanel.js +2 -1
- package/iam-policy/OrgMembersPanel.js.map +1 -1
- package/iam-policy/PeopleWithAccess.d.ts +34 -0
- package/iam-policy/PeopleWithAccess.d.ts.map +1 -0
- package/iam-policy/PeopleWithAccess.js +55 -0
- package/iam-policy/PeopleWithAccess.js.map +1 -0
- package/iam-policy/PrincipalPicker.d.ts +48 -0
- package/iam-policy/PrincipalPicker.d.ts.map +1 -0
- package/iam-policy/PrincipalPicker.js +139 -0
- package/iam-policy/PrincipalPicker.js.map +1 -0
- package/iam-policy/ProviderBadge.d.ts +28 -0
- package/iam-policy/ProviderBadge.d.ts.map +1 -0
- package/iam-policy/ProviderBadge.js +31 -0
- package/iam-policy/ProviderBadge.js.map +1 -0
- package/iam-policy/SharePanel.d.ts +13 -5
- package/iam-policy/SharePanel.d.ts.map +1 -1
- package/iam-policy/SharePanel.js +9 -34
- package/iam-policy/SharePanel.js.map +1 -1
- package/iam-policy/index.d.ts +3 -0
- package/iam-policy/index.d.ts.map +1 -1
- package/iam-policy/index.js +3 -0
- package/iam-policy/index.js.map +1 -1
- package/index.d.ts +8 -6
- package/index.d.ts.map +1 -1
- package/index.js +6 -3
- package/index.js.map +1 -1
- package/mcp-server/McpServerDetailView.d.ts.map +1 -1
- package/mcp-server/McpServerDetailView.js +41 -12
- package/mcp-server/McpServerDetailView.js.map +1 -1
- package/organization/OrgProvider.d.ts +9 -0
- package/organization/OrgProvider.d.ts.map +1 -1
- package/organization/OrgProvider.js +12 -0
- package/organization/OrgProvider.js.map +1 -1
- package/organization/index.d.ts +1 -1
- package/organization/index.d.ts.map +1 -1
- package/organization/index.js +1 -1
- package/organization/index.js.map +1 -1
- package/package.json +4 -4
- package/skill/SkillDetailView.d.ts.map +1 -1
- package/skill/SkillDetailView.js +31 -3
- package/skill/SkillDetailView.js.map +1 -1
- package/src/access/ManageAccessButton.tsx +115 -0
- package/src/access/ManageAccessDialog.tsx +239 -0
- package/src/access/__tests__/ManageAccessButton.test.tsx +62 -0
- package/src/access/__tests__/ManageAccessDialog.test.tsx +146 -0
- package/src/access/index.ts +21 -0
- package/src/access/types.ts +58 -0
- package/src/access/useManageAccess.tsx +101 -0
- package/src/agent/AgentDetailView.tsx +50 -21
- package/src/agent-instance/AgentInstanceDetailPanel.tsx +24 -42
- package/src/iam-policy/GrantAccessForm.tsx +30 -35
- package/src/iam-policy/OrgMembersPanel.tsx +2 -0
- package/src/iam-policy/PeopleWithAccess.tsx +220 -0
- package/src/iam-policy/PrincipalPicker.tsx +347 -0
- package/src/iam-policy/ProviderBadge.tsx +53 -0
- package/src/iam-policy/SharePanel.tsx +20 -165
- package/src/iam-policy/index.ts +17 -0
- package/src/index.ts +31 -0
- package/src/mcp-server/McpServerDetailView.tsx +37 -9
- package/src/organization/OrgProvider.tsx +13 -0
- package/src/organization/index.ts +1 -1
- package/src/session/__tests__/execution-target.test.ts +18 -0
- package/src/skill/SkillDetailView.tsx +34 -9
- package/src/workflow/WorkflowDetailView.tsx +49 -22
- package/src/workflow/WorkflowExecutionHeader.tsx +12 -1
- package/src/workflow/WorkflowExecutionViewer.tsx +8 -1
- package/src/workflow/index.ts +4 -0
- package/src/workflow/instance/RunVisibilityControl.tsx +116 -0
- package/src/workflow/instance/WorkflowInstanceDetailPanel.tsx +55 -42
- package/src/workflow/instance/index.ts +5 -0
- package/src/workflow/instance/useUpdateWorkflowInstanceExecutionVisibility.ts +74 -0
- package/styles.css +1 -1
- package/workflow/WorkflowDetailView.d.ts.map +1 -1
- package/workflow/WorkflowDetailView.js +31 -3
- package/workflow/WorkflowDetailView.js.map +1 -1
- package/workflow/WorkflowExecutionHeader.d.ts +7 -0
- package/workflow/WorkflowExecutionHeader.d.ts.map +1 -1
- package/workflow/WorkflowExecutionHeader.js +2 -2
- package/workflow/WorkflowExecutionHeader.js.map +1 -1
- package/workflow/WorkflowExecutionViewer.d.ts +6 -1
- package/workflow/WorkflowExecutionViewer.d.ts.map +1 -1
- package/workflow/WorkflowExecutionViewer.js +2 -2
- package/workflow/WorkflowExecutionViewer.js.map +1 -1
- package/workflow/index.d.ts +1 -1
- package/workflow/index.d.ts.map +1 -1
- package/workflow/index.js +1 -1
- package/workflow/index.js.map +1 -1
- package/workflow/instance/RunVisibilityControl.d.ts +25 -0
- package/workflow/instance/RunVisibilityControl.d.ts.map +1 -0
- package/workflow/instance/RunVisibilityControl.js +56 -0
- package/workflow/instance/RunVisibilityControl.js.map +1 -0
- package/workflow/instance/WorkflowInstanceDetailPanel.d.ts.map +1 -1
- package/workflow/instance/WorkflowInstanceDetailPanel.js +30 -4
- package/workflow/instance/WorkflowInstanceDetailPanel.js.map +1 -1
- package/workflow/instance/index.d.ts +2 -0
- package/workflow/instance/index.d.ts.map +1 -1
- package/workflow/instance/index.js +2 -0
- package/workflow/instance/index.js.map +1 -1
- package/workflow/instance/useUpdateWorkflowInstanceExecutionVisibility.d.ts +30 -0
- package/workflow/instance/useUpdateWorkflowInstanceExecutionVisibility.d.ts.map +1 -0
- package/workflow/instance/useUpdateWorkflowInstanceExecutionVisibility.js +39 -0
- package/workflow/instance/useUpdateWorkflowInstanceExecutionVisibility.js.map +1 -0
|
@@ -1,12 +1,9 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
|
|
3
|
-
import { useCallback, useState } from "react";
|
|
4
3
|
import type { ApiResourceKind } from "@stigmer/protos/ai/stigmer/commons/apiresource/apiresourcekind/api_resource_kind_pb";
|
|
5
|
-
import type { PrincipalAccess } from "@stigmer/protos/ai/stigmer/iam/iampolicy/v1/io_pb";
|
|
6
4
|
import { cn } from "@stigmer/theme";
|
|
7
|
-
import {
|
|
8
|
-
import {
|
|
9
|
-
import { GrantAccessForm } from "./GrantAccessForm";
|
|
5
|
+
import type { ShareFlowResource } from "./useShareFlow";
|
|
6
|
+
import { PeopleWithAccess } from "./PeopleWithAccess";
|
|
10
7
|
|
|
11
8
|
/** Props for {@link SharePanel}. */
|
|
12
9
|
export interface SharePanelProps {
|
|
@@ -16,6 +13,11 @@ export interface SharePanelProps {
|
|
|
16
13
|
readonly resourceKindString: string;
|
|
17
14
|
/** ApiResourceKind enum value for grantable-role lookup. */
|
|
18
15
|
readonly resourceKind: ApiResourceKind;
|
|
16
|
+
/**
|
|
17
|
+
* Organization the resource belongs to (`metadata.org`). Drives the
|
|
18
|
+
* org-member typeahead in the grant form.
|
|
19
|
+
*/
|
|
20
|
+
readonly orgId: string;
|
|
19
21
|
/** Fired when the user closes the panel. */
|
|
20
22
|
readonly onClose?: () => void;
|
|
21
23
|
/** Additional CSS class names for the root container. */
|
|
@@ -26,9 +28,11 @@ export interface SharePanelProps {
|
|
|
26
28
|
* Self-contained sharing panel that displays who has access to a
|
|
27
29
|
* resource and allows granting/revoking access.
|
|
28
30
|
*
|
|
29
|
-
*
|
|
30
|
-
*
|
|
31
|
-
*
|
|
31
|
+
* A thin header-and-close wrapper around {@link PeopleWithAccess} — the same
|
|
32
|
+
* "people with access" body the unified Manage access dialog renders — so the
|
|
33
|
+
* two surfaces stay byte-for-byte consistent. Suitable for embedding in a
|
|
34
|
+
* popover or sidebar; for the full visibility + people experience use the
|
|
35
|
+
* Manage access dialog instead.
|
|
32
36
|
*
|
|
33
37
|
* All visual properties flow through `--stgm-*` design tokens.
|
|
34
38
|
*
|
|
@@ -38,6 +42,7 @@ export interface SharePanelProps {
|
|
|
38
42
|
* resource={{ kind: "session", id: sessionId, resourceKind: ApiResourceKind.session }}
|
|
39
43
|
* resourceKindString="session"
|
|
40
44
|
* resourceKind={ApiResourceKind.session}
|
|
45
|
+
* orgId={orgId}
|
|
41
46
|
* onClose={() => setOpen(false)}
|
|
42
47
|
* />
|
|
43
48
|
* ```
|
|
@@ -46,22 +51,10 @@ export function SharePanel({
|
|
|
46
51
|
resource,
|
|
47
52
|
resourceKindString,
|
|
48
53
|
resourceKind,
|
|
54
|
+
orgId,
|
|
49
55
|
onClose,
|
|
50
56
|
className,
|
|
51
57
|
}: SharePanelProps) {
|
|
52
|
-
const {
|
|
53
|
-
accessList,
|
|
54
|
-
isLoading,
|
|
55
|
-
fetchError,
|
|
56
|
-
revokeAccess,
|
|
57
|
-
isRevoking,
|
|
58
|
-
revokeError,
|
|
59
|
-
refetch,
|
|
60
|
-
hasGrantableRoles,
|
|
61
|
-
} = useShareFlow(resource);
|
|
62
|
-
|
|
63
|
-
const [showGrantForm, setShowGrantForm] = useState(false);
|
|
64
|
-
|
|
65
58
|
return (
|
|
66
59
|
<div
|
|
67
60
|
className={cn("flex flex-col gap-4 p-4", className)}
|
|
@@ -88,146 +81,16 @@ export function SharePanel({
|
|
|
88
81
|
)}
|
|
89
82
|
</div>
|
|
90
83
|
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
</p>
|
|
98
|
-
|
|
99
|
-
{fetchError && (
|
|
100
|
-
<p className="text-destructive text-[0.65rem]" role="alert">
|
|
101
|
-
{getUserMessage(fetchError)}
|
|
102
|
-
</p>
|
|
103
|
-
)}
|
|
104
|
-
|
|
105
|
-
{!isLoading && accessList.length > 0 && (
|
|
106
|
-
<ul className="space-y-1 mt-2" aria-label="People with access">
|
|
107
|
-
{accessList.map((entry) => (
|
|
108
|
-
<AccessEntry
|
|
109
|
-
key={entry.principal?.id ?? "unknown"}
|
|
110
|
-
entry={entry}
|
|
111
|
-
resourceKindString={resourceKindString}
|
|
112
|
-
resourceId={resource.id}
|
|
113
|
-
onRevoke={revokeAccess}
|
|
114
|
-
isRevoking={isRevoking}
|
|
115
|
-
/>
|
|
116
|
-
))}
|
|
117
|
-
</ul>
|
|
118
|
-
)}
|
|
119
|
-
|
|
120
|
-
{revokeError && (
|
|
121
|
-
<p className="text-destructive text-[0.65rem]" role="alert">
|
|
122
|
-
{getUserMessage(revokeError)}
|
|
123
|
-
</p>
|
|
124
|
-
)}
|
|
125
|
-
</div>
|
|
126
|
-
|
|
127
|
-
{/* Grant form */}
|
|
128
|
-
{hasGrantableRoles && (
|
|
129
|
-
<div className="border-t border-border pt-3">
|
|
130
|
-
{showGrantForm ? (
|
|
131
|
-
<GrantAccessForm
|
|
132
|
-
resourceKind={resourceKind}
|
|
133
|
-
resourceKindString={resourceKindString}
|
|
134
|
-
resourceId={resource.id}
|
|
135
|
-
onGranted={() => {
|
|
136
|
-
setShowGrantForm(false);
|
|
137
|
-
refetch();
|
|
138
|
-
}}
|
|
139
|
-
onCancel={() => setShowGrantForm(false)}
|
|
140
|
-
/>
|
|
141
|
-
) : (
|
|
142
|
-
<button
|
|
143
|
-
type="button"
|
|
144
|
-
onClick={() => setShowGrantForm(true)}
|
|
145
|
-
className={cn(
|
|
146
|
-
"w-full rounded-md px-3 py-1.5 text-xs font-medium text-center",
|
|
147
|
-
"border border-dashed border-border",
|
|
148
|
-
"text-muted-foreground hover:text-foreground hover:border-foreground/30",
|
|
149
|
-
"hover:bg-accent-hover transition-colors",
|
|
150
|
-
)}
|
|
151
|
-
>
|
|
152
|
-
+ Add people
|
|
153
|
-
</button>
|
|
154
|
-
)}
|
|
155
|
-
</div>
|
|
156
|
-
)}
|
|
84
|
+
<PeopleWithAccess
|
|
85
|
+
resource={resource}
|
|
86
|
+
resourceKindString={resourceKindString}
|
|
87
|
+
resourceKind={resourceKind}
|
|
88
|
+
orgId={orgId}
|
|
89
|
+
/>
|
|
157
90
|
</div>
|
|
158
91
|
);
|
|
159
92
|
}
|
|
160
93
|
|
|
161
|
-
// ---------------------------------------------------------------------------
|
|
162
|
-
// Internal subcomponents
|
|
163
|
-
// ---------------------------------------------------------------------------
|
|
164
|
-
|
|
165
|
-
function AccessEntry({
|
|
166
|
-
entry,
|
|
167
|
-
resourceKindString,
|
|
168
|
-
resourceId,
|
|
169
|
-
onRevoke,
|
|
170
|
-
isRevoking,
|
|
171
|
-
}: {
|
|
172
|
-
readonly entry: PrincipalAccess;
|
|
173
|
-
readonly resourceKindString: string;
|
|
174
|
-
readonly resourceId: string;
|
|
175
|
-
readonly onRevoke: (principalId: string, role: string) => Promise<void>;
|
|
176
|
-
readonly isRevoking: boolean;
|
|
177
|
-
}) {
|
|
178
|
-
const principal = entry.principal;
|
|
179
|
-
const roles = entry.roles;
|
|
180
|
-
|
|
181
|
-
const displayName = principal?.name || principal?.email || principal?.id || "Unknown";
|
|
182
|
-
const primaryRole = roles[0]?.role;
|
|
183
|
-
|
|
184
|
-
const handleRevoke = useCallback(async () => {
|
|
185
|
-
if (!principal?.id || !primaryRole?.code) return;
|
|
186
|
-
await onRevoke(principal.id, primaryRole.code);
|
|
187
|
-
}, [principal?.id, primaryRole?.code, onRevoke]);
|
|
188
|
-
|
|
189
|
-
return (
|
|
190
|
-
<li className="flex items-center justify-between gap-2 rounded-md px-2 py-1.5 hover:bg-accent-hover group">
|
|
191
|
-
<div className="flex items-center gap-2 min-w-0">
|
|
192
|
-
<div
|
|
193
|
-
className="h-6 w-6 rounded-full bg-muted flex items-center justify-center text-[0.6rem] font-medium text-muted-foreground shrink-0"
|
|
194
|
-
aria-hidden="true"
|
|
195
|
-
>
|
|
196
|
-
{(principal?.name?.[0] ?? principal?.email?.[0] ?? "?").toUpperCase()}
|
|
197
|
-
</div>
|
|
198
|
-
<div className="min-w-0">
|
|
199
|
-
<p className="text-xs text-foreground truncate">{displayName}</p>
|
|
200
|
-
{principal?.email && principal.name && (
|
|
201
|
-
<p className="text-[0.6rem] text-muted-foreground truncate">
|
|
202
|
-
{principal.email}
|
|
203
|
-
</p>
|
|
204
|
-
)}
|
|
205
|
-
</div>
|
|
206
|
-
</div>
|
|
207
|
-
|
|
208
|
-
<div className="flex items-center gap-1.5 shrink-0">
|
|
209
|
-
<span className="text-[0.6rem] text-muted-foreground capitalize">
|
|
210
|
-
{primaryRole?.name ?? primaryRole?.code ?? "—"}
|
|
211
|
-
</span>
|
|
212
|
-
<button
|
|
213
|
-
type="button"
|
|
214
|
-
onClick={handleRevoke}
|
|
215
|
-
disabled={isRevoking}
|
|
216
|
-
aria-label={`Remove ${displayName}'s access`}
|
|
217
|
-
className={cn(
|
|
218
|
-
"rounded p-0.5 text-muted-foreground opacity-0 group-hover:opacity-100",
|
|
219
|
-
"hover:text-destructive hover:bg-destructive/10",
|
|
220
|
-
"disabled:pointer-events-none disabled:opacity-50",
|
|
221
|
-
"transition-opacity",
|
|
222
|
-
)}
|
|
223
|
-
>
|
|
224
|
-
<RemoveIcon />
|
|
225
|
-
</button>
|
|
226
|
-
</div>
|
|
227
|
-
</li>
|
|
228
|
-
);
|
|
229
|
-
}
|
|
230
|
-
|
|
231
94
|
function CloseIcon() {
|
|
232
95
|
return (
|
|
233
96
|
<svg width="14" height="14" viewBox="0 0 16 16" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" aria-hidden="true">
|
|
@@ -235,11 +98,3 @@ function CloseIcon() {
|
|
|
235
98
|
</svg>
|
|
236
99
|
);
|
|
237
100
|
}
|
|
238
|
-
|
|
239
|
-
function RemoveIcon() {
|
|
240
|
-
return (
|
|
241
|
-
<svg width="12" height="12" viewBox="0 0 16 16" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" aria-hidden="true">
|
|
242
|
-
<path d="M4 4l8 8M12 4l-8 8" />
|
|
243
|
-
</svg>
|
|
244
|
-
);
|
|
245
|
-
}
|
package/src/iam-policy/index.ts
CHANGED
|
@@ -43,8 +43,25 @@ export {
|
|
|
43
43
|
|
|
44
44
|
export { RoleSelector, type RoleSelectorProps } from "./RoleSelector";
|
|
45
45
|
|
|
46
|
+
export {
|
|
47
|
+
PrincipalPicker,
|
|
48
|
+
type PrincipalPickerProps,
|
|
49
|
+
type SelectedPrincipal,
|
|
50
|
+
} from "./PrincipalPicker";
|
|
51
|
+
|
|
52
|
+
export {
|
|
53
|
+
ProviderBadge,
|
|
54
|
+
providerLabel,
|
|
55
|
+
type ProviderBadgeProps,
|
|
56
|
+
} from "./ProviderBadge";
|
|
57
|
+
|
|
46
58
|
export { GrantAccessForm, type GrantAccessFormProps } from "./GrantAccessForm";
|
|
47
59
|
|
|
60
|
+
export {
|
|
61
|
+
PeopleWithAccess,
|
|
62
|
+
type PeopleWithAccessProps,
|
|
63
|
+
} from "./PeopleWithAccess";
|
|
64
|
+
|
|
48
65
|
export {
|
|
49
66
|
OrgMembersPanel,
|
|
50
67
|
type OrgMembersPanelProps,
|
package/src/index.ts
CHANGED
|
@@ -150,6 +150,7 @@ export type {
|
|
|
150
150
|
SearchResultGroup,
|
|
151
151
|
SessionViewerProps,
|
|
152
152
|
NewSessionViewerProps,
|
|
153
|
+
ExecutionTargetOption,
|
|
153
154
|
RuntimeEnvProvider,
|
|
154
155
|
SessionAudience,
|
|
155
156
|
SessionInspectorProps,
|
|
@@ -588,7 +589,11 @@ export {
|
|
|
588
589
|
useShareFlow,
|
|
589
590
|
useCheckPermission,
|
|
590
591
|
RoleSelector,
|
|
592
|
+
PrincipalPicker,
|
|
593
|
+
ProviderBadge,
|
|
594
|
+
providerLabel,
|
|
591
595
|
GrantAccessForm,
|
|
596
|
+
PeopleWithAccess,
|
|
592
597
|
OrgMembersPanel,
|
|
593
598
|
SharePanel,
|
|
594
599
|
PermissionGate,
|
|
@@ -610,17 +615,39 @@ export type {
|
|
|
610
615
|
UseCheckPermissionReturn,
|
|
611
616
|
PermissionCheckResource,
|
|
612
617
|
RoleSelectorProps,
|
|
618
|
+
PrincipalPickerProps,
|
|
619
|
+
SelectedPrincipal,
|
|
620
|
+
ProviderBadgeProps,
|
|
613
621
|
GrantAccessFormProps,
|
|
622
|
+
PeopleWithAccessProps,
|
|
614
623
|
OrgMembersPanelProps,
|
|
615
624
|
SharePanelProps,
|
|
616
625
|
PermissionGateProps,
|
|
617
626
|
} from "./iam-policy";
|
|
618
627
|
|
|
628
|
+
// Access — unified "Manage access" experience (visibility + people) as one
|
|
629
|
+
// dialog, with a kebab hook and a visible-button trigger.
|
|
630
|
+
export {
|
|
631
|
+
ManageAccessDialog,
|
|
632
|
+
ManageAccessButton,
|
|
633
|
+
useManageAccess,
|
|
634
|
+
} from "./access";
|
|
635
|
+
export type {
|
|
636
|
+
ManageAccessDialogProps,
|
|
637
|
+
ManageAccessButtonProps,
|
|
638
|
+
UseManageAccessArgs,
|
|
639
|
+
UseManageAccessReturn,
|
|
640
|
+
AccessResource,
|
|
641
|
+
AccessVisibility,
|
|
642
|
+
AccessExtraSection,
|
|
643
|
+
} from "./access";
|
|
644
|
+
|
|
619
645
|
// Organization — context provider, hooks, data hooks, behavior hooks, styled form, profile panel, and org switcher
|
|
620
646
|
export {
|
|
621
647
|
OrgProvider,
|
|
622
648
|
useOrg,
|
|
623
649
|
useActiveOrgSlug,
|
|
650
|
+
useActiveOrgId,
|
|
624
651
|
useOrgGate,
|
|
625
652
|
useOrganization,
|
|
626
653
|
useCreateOrganization,
|
|
@@ -1240,11 +1267,13 @@ export {
|
|
|
1240
1267
|
useWorkflowInstance,
|
|
1241
1268
|
useCreateWorkflowInstance,
|
|
1242
1269
|
useUpdateWorkflowInstance,
|
|
1270
|
+
useUpdateWorkflowInstanceExecutionVisibility,
|
|
1243
1271
|
useDeleteWorkflowInstance,
|
|
1244
1272
|
WorkflowInstanceEmptyState,
|
|
1245
1273
|
WorkflowInstanceList,
|
|
1246
1274
|
CreateWorkflowInstanceDialog,
|
|
1247
1275
|
WorkflowInstanceDetailPanel,
|
|
1276
|
+
RunVisibilityControl,
|
|
1248
1277
|
// T15: Workflow Template Gallery
|
|
1249
1278
|
PATTERN_LABELS,
|
|
1250
1279
|
WORKFLOW_CATEGORY_LABELS,
|
|
@@ -1367,11 +1396,13 @@ export type {
|
|
|
1367
1396
|
UseWorkflowInstanceReturn,
|
|
1368
1397
|
UseCreateWorkflowInstanceReturn,
|
|
1369
1398
|
UseUpdateWorkflowInstanceReturn,
|
|
1399
|
+
UseUpdateWorkflowInstanceExecutionVisibilityReturn,
|
|
1370
1400
|
UseDeleteWorkflowInstanceReturn,
|
|
1371
1401
|
WorkflowInstanceEmptyStateProps,
|
|
1372
1402
|
WorkflowInstanceListProps,
|
|
1373
1403
|
CreateWorkflowInstanceDialogProps,
|
|
1374
1404
|
WorkflowInstanceDetailPanelProps,
|
|
1405
|
+
RunVisibilityControlProps,
|
|
1375
1406
|
// T15: Workflow Template Gallery types
|
|
1376
1407
|
WorkflowTemplateData,
|
|
1377
1408
|
WorkflowTemplateCategory,
|
|
@@ -23,10 +23,12 @@ import type { OAuthConnectPhase } from "./useMcpServerOAuthConnect";
|
|
|
23
23
|
import { useDisconnectOAuth } from "./useDisconnectOAuth";
|
|
24
24
|
import { useOrgOAuthApp } from "./useOrgOAuthApp";
|
|
25
25
|
import { OAuthAppForm } from "./OAuthAppForm";
|
|
26
|
+
import { ApiResourceKind } from "@stigmer/protos/ai/stigmer/commons/apiresource/apiresourcekind/api_resource_kind_pb";
|
|
26
27
|
import { ErrorMessage } from "../error/ErrorMessage";
|
|
27
28
|
import { EnvVarForm } from "../environment/EnvVarForm";
|
|
28
29
|
import type { EnvVarFormVariable } from "../environment/EnvVarForm";
|
|
29
|
-
import {
|
|
30
|
+
import { VisibilityBadge } from "../library/VisibilitySelector";
|
|
31
|
+
import { useManageAccess } from "../access/useManageAccess";
|
|
30
32
|
import { Tabs, type TabItem } from "../tabs/Tabs";
|
|
31
33
|
import { ResourceDetailShell } from "../resource-detail/ResourceDetailShell";
|
|
32
34
|
import { Section } from "../resource-detail/Section";
|
|
@@ -338,6 +340,29 @@ export function McpServerDetailView({
|
|
|
338
340
|
oauth.clearError();
|
|
339
341
|
}, [connection, oauth]);
|
|
340
342
|
|
|
343
|
+
// Unified Manage access — visibility (General access) over explicit grants
|
|
344
|
+
// (People), opened from the kebab. Closes the blueprint share gap for MCP
|
|
345
|
+
// servers.
|
|
346
|
+
const access = useManageAccess({
|
|
347
|
+
resource: mcpServer?.metadata
|
|
348
|
+
? {
|
|
349
|
+
kind: ApiResourceKind.mcp_server,
|
|
350
|
+
kindString: "mcp_server",
|
|
351
|
+
id: mcpServer.metadata.id,
|
|
352
|
+
org: mcpServer.metadata.org,
|
|
353
|
+
name: mcpServer.metadata.name,
|
|
354
|
+
}
|
|
355
|
+
: null,
|
|
356
|
+
visibility: mcpServer?.metadata
|
|
357
|
+
? {
|
|
358
|
+
kind: "mcpServer",
|
|
359
|
+
current: mcpServer.metadata.visibility,
|
|
360
|
+
org: mcpServer.metadata.org,
|
|
361
|
+
onChanged: refetch,
|
|
362
|
+
}
|
|
363
|
+
: undefined,
|
|
364
|
+
});
|
|
365
|
+
|
|
341
366
|
if (isLoading) return <LoadingSkeleton className={className} />;
|
|
342
367
|
if (error)
|
|
343
368
|
return <ErrorMessage error={error} retry={refetch} className={className} />;
|
|
@@ -380,16 +405,16 @@ export function McpServerDetailView({
|
|
|
380
405
|
updatedAt: specAudit?.updatedAt ? timestampDate(specAudit.updatedAt) : null,
|
|
381
406
|
};
|
|
382
407
|
|
|
408
|
+
// Inline visibility is read-only (at-a-glance); editing lives in the
|
|
409
|
+
// Manage access dialog, the single writer for both access axes.
|
|
383
410
|
const visibilityControl = meta ? (
|
|
384
|
-
<
|
|
385
|
-
kind="mcpServer"
|
|
386
|
-
resourceId={meta.id}
|
|
387
|
-
visibility={meta.visibility}
|
|
388
|
-
org={meta.org || org}
|
|
389
|
-
onChanged={refetch}
|
|
390
|
-
/>
|
|
411
|
+
<VisibilityBadge visibility={meta.visibility} />
|
|
391
412
|
) : undefined;
|
|
392
413
|
|
|
414
|
+
const mergedActions = access.action
|
|
415
|
+
? [...(actions ?? []), access.action]
|
|
416
|
+
: actions;
|
|
417
|
+
|
|
393
418
|
const headerMetaExtra = (
|
|
394
419
|
<>
|
|
395
420
|
{status && <ValidationStateBadge state={status.validationState} />}
|
|
@@ -409,13 +434,14 @@ export function McpServerDetailView({
|
|
|
409
434
|
) : undefined;
|
|
410
435
|
|
|
411
436
|
return (
|
|
437
|
+
<>
|
|
412
438
|
<ResourceDetailShell
|
|
413
439
|
header={headerMeta}
|
|
414
440
|
visibilityControl={visibilityControl}
|
|
415
441
|
headerMetaExtra={headerMetaExtra}
|
|
416
442
|
headerBanner={headerBanner}
|
|
417
443
|
primaryAction={primaryAction}
|
|
418
|
-
actions={
|
|
444
|
+
actions={mergedActions}
|
|
419
445
|
className={className}
|
|
420
446
|
>
|
|
421
447
|
{(editable || spec?.description) && (
|
|
@@ -576,6 +602,8 @@ export function McpServerDetailView({
|
|
|
576
602
|
<TagsSection tags={spec?.tags ?? []} editable={editable} isSaving={isUpdating} saveMcpField={saveMcpField} />
|
|
577
603
|
)}
|
|
578
604
|
</ResourceDetailShell>
|
|
605
|
+
{access.dialog}
|
|
606
|
+
</>
|
|
579
607
|
);
|
|
580
608
|
}
|
|
581
609
|
|
|
@@ -182,3 +182,16 @@ export function useActiveOrgSlug(): string {
|
|
|
182
182
|
const { activeOrg } = useOrg();
|
|
183
183
|
return activeOrg?.metadata?.slug ?? "";
|
|
184
184
|
}
|
|
185
|
+
|
|
186
|
+
/**
|
|
187
|
+
* Convenience accessor: returns the active org's system ID (`metadata.id`),
|
|
188
|
+
* or an empty string when no org is selected.
|
|
189
|
+
*
|
|
190
|
+
* This is the identifier used as the `organization` object in authorization
|
|
191
|
+
* (FGA) — e.g. for member lookups in the share picker — as opposed to the
|
|
192
|
+
* human-readable slug returned by {@link useActiveOrgSlug}.
|
|
193
|
+
*/
|
|
194
|
+
export function useActiveOrgId(): string {
|
|
195
|
+
const { activeOrg } = useOrg();
|
|
196
|
+
return activeOrg?.metadata?.id ?? "";
|
|
197
|
+
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export { OrgProvider, useOrg, useActiveOrgSlug } from "./OrgProvider";
|
|
1
|
+
export { OrgProvider, useOrg, useActiveOrgSlug, useActiveOrgId } from "./OrgProvider";
|
|
2
2
|
export type { OrgContextValue } from "./OrgProvider";
|
|
3
3
|
export { useOrgGate } from "./useOrgGate";
|
|
4
4
|
export type {
|
|
@@ -5,6 +5,14 @@ import {
|
|
|
5
5
|
fromProtoExecutionTarget,
|
|
6
6
|
type ExecutionTargetOption,
|
|
7
7
|
} from "../execution-target";
|
|
8
|
+
// Public-API contract guard (issue #171): ExecutionTargetOption must stay
|
|
9
|
+
// re-exported from the package root so consumers can type the
|
|
10
|
+
// StigmerProvider `executionTarget` prop. This guarantee is enforced at
|
|
11
|
+
// compile time by `tsc` (npm run typecheck) — vitest runs through esbuild and
|
|
12
|
+
// erases type-only imports, so removing the root re-export would NOT fail the
|
|
13
|
+
// test run, only the typecheck. A type-only import keeps the test fast (no
|
|
14
|
+
// root-barrel evaluation at runtime).
|
|
15
|
+
import type { ExecutionTargetOption as RootExecutionTargetOption } from "../../index";
|
|
8
16
|
|
|
9
17
|
describe("toProtoExecutionTarget", () => {
|
|
10
18
|
it("maps local to ExecutionTarget.LOCAL", () => {
|
|
@@ -43,3 +51,13 @@ describe("round-trip conversion", () => {
|
|
|
43
51
|
expect(fromProtoExecutionTarget(toProtoExecutionTarget("cloud"))).toBe("cloud");
|
|
44
52
|
});
|
|
45
53
|
});
|
|
54
|
+
|
|
55
|
+
describe("package root export", () => {
|
|
56
|
+
it("re-exports ExecutionTargetOption from the package root (issue #171)", () => {
|
|
57
|
+
// Assigning through the root-imported type forces `tsc` to resolve the
|
|
58
|
+
// root re-export; if it is dropped from src/index.ts, typecheck fails
|
|
59
|
+
// (TS2305) in CI. The runtime assertion keeps this a real test too.
|
|
60
|
+
const target: RootExecutionTargetOption = "local";
|
|
61
|
+
expect(toProtoExecutionTarget(target)).toBe(ExecutionTarget.LOCAL);
|
|
62
|
+
});
|
|
63
|
+
});
|
|
@@ -7,10 +7,12 @@ import { timestampDate } from "@bufbuild/protobuf/wkt";
|
|
|
7
7
|
import type { Skill } from "@stigmer/protos/ai/stigmer/agentic/skill/v1/api_pb";
|
|
8
8
|
import type { GitProvenance } from "@stigmer/protos/ai/stigmer/agentic/skill/v1/status_pb";
|
|
9
9
|
import { SkillState } from "@stigmer/protos/ai/stigmer/agentic/skill/v1/status_pb";
|
|
10
|
+
import { ApiResourceKind } from "@stigmer/protos/ai/stigmer/commons/apiresource/apiresourcekind/api_resource_kind_pb";
|
|
10
11
|
import { useSkill } from "./useSkill";
|
|
11
12
|
import { SkillFileBrowser } from "./SkillFileBrowser";
|
|
12
13
|
import { ErrorMessage } from "../error/ErrorMessage";
|
|
13
|
-
import {
|
|
14
|
+
import { VisibilityBadge } from "../library/VisibilitySelector";
|
|
15
|
+
import { useManageAccess } from "../access/useManageAccess";
|
|
14
16
|
import { MARKDOWN_COMPONENTS, REMARK_PLUGINS, stripFrontmatter } from "../internal/markdown-components";
|
|
15
17
|
import { ResourceDetailShell } from "../resource-detail/ResourceDetailShell";
|
|
16
18
|
import { Section } from "../resource-detail/Section";
|
|
@@ -207,6 +209,28 @@ export function SkillDetailView({
|
|
|
207
209
|
}
|
|
208
210
|
}, [skill]);
|
|
209
211
|
|
|
212
|
+
// Unified Manage access — visibility (General access) over explicit grants
|
|
213
|
+
// (People), opened from the kebab. Closes the blueprint share gap for skills.
|
|
214
|
+
const access = useManageAccess({
|
|
215
|
+
resource: skill?.metadata
|
|
216
|
+
? {
|
|
217
|
+
kind: ApiResourceKind.skill,
|
|
218
|
+
kindString: "skill",
|
|
219
|
+
id: skill.metadata.id,
|
|
220
|
+
org: skill.metadata.org,
|
|
221
|
+
name: skill.metadata.name,
|
|
222
|
+
}
|
|
223
|
+
: null,
|
|
224
|
+
visibility: skill?.metadata
|
|
225
|
+
? {
|
|
226
|
+
kind: "skill",
|
|
227
|
+
current: skill.metadata.visibility,
|
|
228
|
+
org: skill.metadata.org,
|
|
229
|
+
onChanged: refetch,
|
|
230
|
+
}
|
|
231
|
+
: undefined,
|
|
232
|
+
});
|
|
233
|
+
|
|
210
234
|
if (isLoading) return <LoadingSkeleton className={className} />;
|
|
211
235
|
if (error)
|
|
212
236
|
return <ErrorMessage error={error} retry={refetch} className={className} />;
|
|
@@ -230,16 +254,16 @@ export function SkillDetailView({
|
|
|
230
254
|
statusLabel: status ? skillStateLabel(status.state) : undefined,
|
|
231
255
|
};
|
|
232
256
|
|
|
257
|
+
// Inline visibility is read-only (at-a-glance); editing lives in the
|
|
258
|
+
// Manage access dialog, the single writer for both access axes.
|
|
233
259
|
const visibilityControl = meta ? (
|
|
234
|
-
<
|
|
235
|
-
kind="skill"
|
|
236
|
-
resourceId={meta.id}
|
|
237
|
-
visibility={meta.visibility}
|
|
238
|
-
org={meta.org || org}
|
|
239
|
-
onChanged={refetch}
|
|
240
|
-
/>
|
|
260
|
+
<VisibilityBadge visibility={meta.visibility} />
|
|
241
261
|
) : undefined;
|
|
242
262
|
|
|
263
|
+
const mergedActions = access.action
|
|
264
|
+
? [...(actions ?? []), access.action]
|
|
265
|
+
: actions;
|
|
266
|
+
|
|
243
267
|
let tabContent: React.ReactNode;
|
|
244
268
|
if (activeAdditionalTab) {
|
|
245
269
|
tabContent = activeAdditionalTab.content;
|
|
@@ -267,7 +291,7 @@ export function SkillDetailView({
|
|
|
267
291
|
header={headerMeta}
|
|
268
292
|
visibilityControl={visibilityControl}
|
|
269
293
|
primaryAction={primaryAction}
|
|
270
|
-
actions={
|
|
294
|
+
actions={mergedActions}
|
|
271
295
|
tabs={effectiveTabs}
|
|
272
296
|
activeTab={effectiveTabs ? effectiveActiveTab : undefined}
|
|
273
297
|
onTabChange={effectiveTabs ? effectiveOnTabChange : undefined}
|
|
@@ -276,6 +300,7 @@ export function SkillDetailView({
|
|
|
276
300
|
>
|
|
277
301
|
{tabContent}
|
|
278
302
|
</ResourceDetailShell>
|
|
303
|
+
{access.dialog}
|
|
279
304
|
<SkillDiffDialog state={diffState} onClose={closeDiff} />
|
|
280
305
|
</>
|
|
281
306
|
);
|
|
@@ -22,7 +22,9 @@ import { WorkflowInstanceList } from "./instance/WorkflowInstanceList";
|
|
|
22
22
|
import { WorkflowVersionsTab } from "./WorkflowVersionsTab";
|
|
23
23
|
import { useWorkflowVersions } from "./useWorkflowVersions";
|
|
24
24
|
import { ErrorMessage } from "../error/ErrorMessage";
|
|
25
|
-
import {
|
|
25
|
+
import { VisibilityBadge } from "../library/VisibilitySelector";
|
|
26
|
+
import { useManageAccess } from "../access/useManageAccess";
|
|
27
|
+
import { ApiResourceKind } from "@stigmer/protos/ai/stigmer/commons/apiresource/apiresourcekind/api_resource_kind_pb";
|
|
26
28
|
import { formatDurationSec } from "./format-utils";
|
|
27
29
|
import { ResourceDetailShell } from "../resource-detail/ResourceDetailShell";
|
|
28
30
|
import { Section } from "../resource-detail/Section";
|
|
@@ -232,6 +234,28 @@ export function WorkflowDetailView({
|
|
|
232
234
|
}
|
|
233
235
|
}, [workflow]);
|
|
234
236
|
|
|
237
|
+
// Unified Manage access — visibility (General access) over explicit grants
|
|
238
|
+
// (People), opened from the kebab. Replaces the host's bespoke share popover.
|
|
239
|
+
const access = useManageAccess({
|
|
240
|
+
resource: workflow?.metadata
|
|
241
|
+
? {
|
|
242
|
+
kind: ApiResourceKind.workflow,
|
|
243
|
+
kindString: "workflow",
|
|
244
|
+
id: workflow.metadata.id,
|
|
245
|
+
org: workflow.metadata.org || org,
|
|
246
|
+
name: workflow.metadata.name,
|
|
247
|
+
}
|
|
248
|
+
: null,
|
|
249
|
+
visibility: workflow?.metadata
|
|
250
|
+
? {
|
|
251
|
+
kind: "workflow",
|
|
252
|
+
current: workflow.metadata.visibility,
|
|
253
|
+
org: workflow.metadata.org || org,
|
|
254
|
+
onChanged: refetch,
|
|
255
|
+
}
|
|
256
|
+
: undefined,
|
|
257
|
+
});
|
|
258
|
+
|
|
235
259
|
if (isLoading) return <LoadingSkeleton className={className} />;
|
|
236
260
|
if (error)
|
|
237
261
|
return <ErrorMessage error={error} retry={refetch} className={className} />;
|
|
@@ -257,16 +281,16 @@ export function WorkflowDetailView({
|
|
|
257
281
|
<ValidationIndicator state={validationState} />
|
|
258
282
|
) : undefined;
|
|
259
283
|
|
|
284
|
+
// Inline visibility is read-only (at-a-glance); editing lives in the
|
|
285
|
+
// Manage access dialog, the single writer for both access axes.
|
|
260
286
|
const visibilityControl = meta ? (
|
|
261
|
-
<
|
|
262
|
-
kind="workflow"
|
|
263
|
-
resourceId={meta.id}
|
|
264
|
-
visibility={meta.visibility}
|
|
265
|
-
org={meta.org || org}
|
|
266
|
-
onChanged={refetch}
|
|
267
|
-
/>
|
|
287
|
+
<VisibilityBadge visibility={meta.visibility} />
|
|
268
288
|
) : undefined;
|
|
269
289
|
|
|
290
|
+
const mergedActions = access.action
|
|
291
|
+
? [...(actions ?? []), access.action]
|
|
292
|
+
: actions;
|
|
293
|
+
|
|
270
294
|
let tabContent: React.ReactNode;
|
|
271
295
|
if (activeAdditionalTab) {
|
|
272
296
|
tabContent = activeAdditionalTab.content;
|
|
@@ -309,20 +333,23 @@ export function WorkflowDetailView({
|
|
|
309
333
|
}
|
|
310
334
|
|
|
311
335
|
return (
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
336
|
+
<>
|
|
337
|
+
<ResourceDetailShell
|
|
338
|
+
header={headerMeta}
|
|
339
|
+
visibilityControl={visibilityControl}
|
|
340
|
+
headerMetaExtra={headerMetaExtra}
|
|
341
|
+
primaryAction={primaryAction}
|
|
342
|
+
actions={mergedActions}
|
|
343
|
+
tabs={effectiveTabs}
|
|
344
|
+
activeTab={effectiveActiveTab}
|
|
345
|
+
onTabChange={effectiveOnTabChange}
|
|
346
|
+
tabsAriaLabel="Workflow detail tabs"
|
|
347
|
+
className={className}
|
|
348
|
+
>
|
|
349
|
+
{tabContent}
|
|
350
|
+
</ResourceDetailShell>
|
|
351
|
+
{access.dialog}
|
|
352
|
+
</>
|
|
326
353
|
);
|
|
327
354
|
}
|
|
328
355
|
|