@stigmer/react 0.0.39 → 0.0.40
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/agent/AgentDetailView.d.ts +12 -1
- package/agent/AgentDetailView.d.ts.map +1 -1
- package/agent/AgentDetailView.js +6 -5
- package/agent/AgentDetailView.js.map +1 -1
- package/agent/agentSetupReducer.d.ts +1 -0
- package/agent/agentSetupReducer.d.ts.map +1 -1
- package/agent/agentSetupReducer.js +11 -0
- package/agent/agentSetupReducer.js.map +1 -1
- package/agent/useAgentSetup.d.ts.map +1 -1
- package/agent/useAgentSetup.js +41 -6
- package/agent/useAgentSetup.js.map +1 -1
- package/api-key/ApiKeyCreatedAlert.d.ts +33 -0
- package/api-key/ApiKeyCreatedAlert.d.ts.map +1 -0
- package/api-key/ApiKeyCreatedAlert.js +61 -0
- package/api-key/ApiKeyCreatedAlert.js.map +1 -0
- package/api-key/ApiKeyListPanel.d.ts +30 -0
- package/api-key/ApiKeyListPanel.d.ts.map +1 -0
- package/api-key/ApiKeyListPanel.js +126 -0
- package/api-key/ApiKeyListPanel.js.map +1 -0
- package/api-key/CreateApiKeyForm.d.ts +35 -0
- package/api-key/CreateApiKeyForm.d.ts.map +1 -0
- package/api-key/CreateApiKeyForm.js +81 -0
- package/api-key/CreateApiKeyForm.js.map +1 -0
- package/api-key/index.d.ts +13 -0
- package/api-key/index.d.ts.map +1 -0
- package/api-key/index.js +7 -0
- package/api-key/index.js.map +1 -0
- package/api-key/useApiKeyList.d.ts +28 -0
- package/api-key/useApiKeyList.d.ts.map +1 -0
- package/api-key/useApiKeyList.js +52 -0
- package/api-key/useApiKeyList.js.map +1 -0
- package/api-key/useCreateApiKey.d.ts +40 -0
- package/api-key/useCreateApiKey.d.ts.map +1 -0
- package/api-key/useCreateApiKey.js +56 -0
- package/api-key/useCreateApiKey.js.map +1 -0
- package/api-key/useDeleteApiKey.d.ts +26 -0
- package/api-key/useDeleteApiKey.d.ts.map +1 -0
- package/api-key/useDeleteApiKey.js +43 -0
- package/api-key/useDeleteApiKey.js.map +1 -0
- package/composer/SessionComposer.d.ts.map +1 -1
- package/composer/SessionComposer.js +12 -0
- package/composer/SessionComposer.js.map +1 -1
- package/index.d.ts +5 -3
- package/index.d.ts.map +1 -1
- package/index.js +5 -3
- package/index.js.map +1 -1
- package/library/VisibilityToggle.d.ts +41 -0
- package/library/VisibilityToggle.d.ts.map +1 -0
- package/library/VisibilityToggle.js +80 -0
- package/library/VisibilityToggle.js.map +1 -0
- package/library/index.d.ts +4 -0
- package/library/index.d.ts.map +1 -1
- package/library/index.js +2 -0
- package/library/index.js.map +1 -1
- package/library/useUpdateVisibility.d.ts +40 -0
- package/library/useUpdateVisibility.d.ts.map +1 -0
- package/library/useUpdateVisibility.js +67 -0
- package/library/useUpdateVisibility.js.map +1 -0
- package/mcp-server/McpServerDetailView.d.ts +12 -1
- package/mcp-server/McpServerDetailView.d.ts.map +1 -1
- package/mcp-server/McpServerDetailView.js +6 -5
- package/mcp-server/McpServerDetailView.js.map +1 -1
- package/package.json +4 -4
- package/search/useResourceCount.d.ts +2 -2
- package/search/useResourceCount.js +2 -2
- package/search/useResourceCount.js.map +1 -1
- package/search/useResourceList.d.ts +8 -3
- package/search/useResourceList.d.ts.map +1 -1
- package/search/useResourceList.js +2 -2
- package/search/useResourceList.js.map +1 -1
- package/session/index.d.ts +1 -0
- package/session/index.d.ts.map +1 -1
- package/session/index.js +2 -0
- package/session/index.js.map +1 -1
- package/session/useCreateSession.d.ts +1 -1
- package/session/useCreateSession.d.ts.map +1 -1
- package/session/useCreateSession.js +2 -1
- package/session/useCreateSession.js.map +1 -1
- package/skill/SkillDetailView.d.ts +12 -1
- package/skill/SkillDetailView.d.ts.map +1 -1
- package/skill/SkillDetailView.js +6 -5
- package/skill/SkillDetailView.js.map +1 -1
- package/src/agent/AgentDetailView.tsx +32 -6
- package/src/agent/agentSetupReducer.ts +12 -0
- package/src/agent/useAgentSetup.ts +69 -19
- package/src/api-key/ApiKeyCreatedAlert.tsx +184 -0
- package/src/api-key/ApiKeyListPanel.tsx +359 -0
- package/src/api-key/CreateApiKeyForm.tsx +250 -0
- package/src/api-key/index.ts +12 -0
- package/src/api-key/useApiKeyList.ts +68 -0
- package/src/api-key/useCreateApiKey.ts +71 -0
- package/src/api-key/useDeleteApiKey.ts +57 -0
- package/src/composer/SessionComposer.tsx +13 -0
- package/src/index.ts +26 -1
- package/src/library/VisibilityToggle.tsx +205 -0
- package/src/library/index.ts +9 -0
- package/src/library/useUpdateVisibility.ts +94 -0
- package/src/mcp-server/McpServerDetailView.tsx +32 -6
- package/src/search/useResourceCount.ts +4 -4
- package/src/search/useResourceList.ts +10 -5
- package/src/session/index.ts +3 -0
- package/src/session/useCreateSession.ts +6 -5
- package/src/skill/SkillDetailView.tsx +32 -6
- package/styles.css +1 -1
|
@@ -0,0 +1,205 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
|
|
3
|
+
import { useCallback, useRef, useState } from "react";
|
|
4
|
+
import { cn } from "@stigmer/theme";
|
|
5
|
+
import { ApiResourceVisibility } from "@stigmer/protos/ai/stigmer/commons/apiresource/enum_pb";
|
|
6
|
+
|
|
7
|
+
export interface VisibilityToggleProps {
|
|
8
|
+
/** Current visibility of the resource. */
|
|
9
|
+
readonly visibility: ApiResourceVisibility;
|
|
10
|
+
/**
|
|
11
|
+
* Called when the user confirms a visibility change.
|
|
12
|
+
* The toggle shows an inline confirmation before invoking this
|
|
13
|
+
* callback when switching to PUBLIC.
|
|
14
|
+
*/
|
|
15
|
+
readonly onVisibilityChange: (v: ApiResourceVisibility) => void;
|
|
16
|
+
/** Shows a spinner/disabled state while the RPC is in flight. */
|
|
17
|
+
readonly isPending?: boolean;
|
|
18
|
+
/** Disables all interaction (e.g., when the user lacks can_edit). */
|
|
19
|
+
readonly disabled?: boolean;
|
|
20
|
+
/** Additional CSS classes applied to the root element. */
|
|
21
|
+
readonly className?: string;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
const OPTIONS: readonly {
|
|
25
|
+
readonly value: ApiResourceVisibility;
|
|
26
|
+
readonly label: string;
|
|
27
|
+
}[] = [
|
|
28
|
+
{ value: ApiResourceVisibility.visibility_private, label: "Private" },
|
|
29
|
+
{ value: ApiResourceVisibility.visibility_public, label: "Public" },
|
|
30
|
+
];
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* Segmented control for toggling resource visibility between
|
|
34
|
+
* Private and Public.
|
|
35
|
+
*
|
|
36
|
+
* Switching to PUBLIC shows a brief inline confirmation prompt
|
|
37
|
+
* since making a resource publicly visible is a consequential
|
|
38
|
+
* action. Switching to PRIVATE applies immediately without
|
|
39
|
+
* confirmation (revoking access is always safe).
|
|
40
|
+
*
|
|
41
|
+
* Follows the same visual pattern as {@link ScopeToggle} —
|
|
42
|
+
* WAI-ARIA Radio Group with roving tabindex. All visual
|
|
43
|
+
* properties flow through `--stgm-*` design tokens.
|
|
44
|
+
*
|
|
45
|
+
* @example
|
|
46
|
+
* ```tsx
|
|
47
|
+
* <VisibilityToggle
|
|
48
|
+
* visibility={skill.metadata.visibility}
|
|
49
|
+
* onVisibilityChange={handleVisibilityChange}
|
|
50
|
+
* isPending={isPending}
|
|
51
|
+
* />
|
|
52
|
+
* ```
|
|
53
|
+
*/
|
|
54
|
+
export function VisibilityToggle({
|
|
55
|
+
visibility,
|
|
56
|
+
onVisibilityChange,
|
|
57
|
+
isPending = false,
|
|
58
|
+
disabled = false,
|
|
59
|
+
className,
|
|
60
|
+
}: VisibilityToggleProps) {
|
|
61
|
+
const [confirming, setConfirming] = useState(false);
|
|
62
|
+
const optionRefs = useRef<(HTMLButtonElement | null)[]>([]);
|
|
63
|
+
|
|
64
|
+
const isPublic =
|
|
65
|
+
visibility === ApiResourceVisibility.visibility_public;
|
|
66
|
+
const effectivelyDisabled = disabled || isPending;
|
|
67
|
+
|
|
68
|
+
const handleSelect = useCallback(
|
|
69
|
+
(value: ApiResourceVisibility) => {
|
|
70
|
+
if (value === visibility) return;
|
|
71
|
+
|
|
72
|
+
if (value === ApiResourceVisibility.visibility_public) {
|
|
73
|
+
setConfirming(true);
|
|
74
|
+
return;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
onVisibilityChange(value);
|
|
78
|
+
},
|
|
79
|
+
[visibility, onVisibilityChange],
|
|
80
|
+
);
|
|
81
|
+
|
|
82
|
+
const confirmPublic = useCallback(() => {
|
|
83
|
+
setConfirming(false);
|
|
84
|
+
onVisibilityChange(ApiResourceVisibility.visibility_public);
|
|
85
|
+
}, [onVisibilityChange]);
|
|
86
|
+
|
|
87
|
+
const cancelConfirm = useCallback(() => {
|
|
88
|
+
setConfirming(false);
|
|
89
|
+
}, []);
|
|
90
|
+
|
|
91
|
+
const handleKeyDown = useCallback(
|
|
92
|
+
(e: React.KeyboardEvent<HTMLButtonElement>, index: number) => {
|
|
93
|
+
let nextIndex: number | null = null;
|
|
94
|
+
|
|
95
|
+
if (e.key === "ArrowRight" || e.key === "ArrowDown") {
|
|
96
|
+
e.preventDefault();
|
|
97
|
+
nextIndex = (index + 1) % OPTIONS.length;
|
|
98
|
+
} else if (e.key === "ArrowLeft" || e.key === "ArrowUp") {
|
|
99
|
+
e.preventDefault();
|
|
100
|
+
nextIndex = (index - 1 + OPTIONS.length) % OPTIONS.length;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
if (nextIndex !== null) {
|
|
104
|
+
optionRefs.current[nextIndex]?.focus();
|
|
105
|
+
handleSelect(OPTIONS[nextIndex].value);
|
|
106
|
+
}
|
|
107
|
+
},
|
|
108
|
+
[handleSelect],
|
|
109
|
+
);
|
|
110
|
+
|
|
111
|
+
const currentIndex = OPTIONS.findIndex((o) => o.value === visibility);
|
|
112
|
+
|
|
113
|
+
return (
|
|
114
|
+
<div className={cn("inline-flex flex-col gap-1.5", className)}>
|
|
115
|
+
<div
|
|
116
|
+
role="radiogroup"
|
|
117
|
+
aria-label="Resource visibility"
|
|
118
|
+
aria-disabled={effectivelyDisabled || undefined}
|
|
119
|
+
className={cn(
|
|
120
|
+
"inline-flex rounded-md bg-muted p-0.5",
|
|
121
|
+
effectivelyDisabled && "pointer-events-none opacity-50",
|
|
122
|
+
)}
|
|
123
|
+
>
|
|
124
|
+
{OPTIONS.map((option, index) => {
|
|
125
|
+
const isSelected = visibility === option.value;
|
|
126
|
+
|
|
127
|
+
return (
|
|
128
|
+
<button
|
|
129
|
+
key={option.value}
|
|
130
|
+
ref={(el) => {
|
|
131
|
+
optionRefs.current[index] = el;
|
|
132
|
+
}}
|
|
133
|
+
type="button"
|
|
134
|
+
role="radio"
|
|
135
|
+
aria-checked={isSelected}
|
|
136
|
+
tabIndex={isSelected ? 0 : -1}
|
|
137
|
+
disabled={effectivelyDisabled}
|
|
138
|
+
onClick={() => handleSelect(option.value)}
|
|
139
|
+
onKeyDown={(e) => handleKeyDown(e, index)}
|
|
140
|
+
className={cn(
|
|
141
|
+
"cursor-pointer rounded-sm px-3 py-1 text-xs font-medium transition-colors",
|
|
142
|
+
"focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring",
|
|
143
|
+
isSelected && option.value === ApiResourceVisibility.visibility_public
|
|
144
|
+
? "bg-emerald-100 text-emerald-800 shadow-sm dark:bg-emerald-900/40 dark:text-emerald-300"
|
|
145
|
+
: isSelected
|
|
146
|
+
? "bg-background text-foreground shadow-sm"
|
|
147
|
+
: "text-muted-foreground hover:text-foreground",
|
|
148
|
+
)}
|
|
149
|
+
>
|
|
150
|
+
{isPending && isSelected ? (
|
|
151
|
+
<span className="inline-flex items-center gap-1">
|
|
152
|
+
<span
|
|
153
|
+
className="inline-block h-3 w-3 animate-spin rounded-full border-2 border-current border-t-transparent"
|
|
154
|
+
aria-hidden="true"
|
|
155
|
+
/>
|
|
156
|
+
{option.label}
|
|
157
|
+
</span>
|
|
158
|
+
) : (
|
|
159
|
+
option.label
|
|
160
|
+
)}
|
|
161
|
+
</button>
|
|
162
|
+
);
|
|
163
|
+
})}
|
|
164
|
+
</div>
|
|
165
|
+
|
|
166
|
+
{confirming && (
|
|
167
|
+
<div
|
|
168
|
+
className={cn(
|
|
169
|
+
"flex items-center gap-2 rounded-md border border-amber-200 bg-amber-50 px-3 py-1.5 text-xs",
|
|
170
|
+
"dark:border-amber-800/50 dark:bg-amber-950/30",
|
|
171
|
+
)}
|
|
172
|
+
role="alert"
|
|
173
|
+
>
|
|
174
|
+
<span className="text-amber-800 dark:text-amber-200">
|
|
175
|
+
Make visible to all users?
|
|
176
|
+
</span>
|
|
177
|
+
<button
|
|
178
|
+
type="button"
|
|
179
|
+
onClick={confirmPublic}
|
|
180
|
+
className={cn(
|
|
181
|
+
"rounded px-2 py-0.5 text-xs font-medium",
|
|
182
|
+
"bg-amber-600 text-white hover:bg-amber-700",
|
|
183
|
+
"dark:bg-amber-600 dark:hover:bg-amber-500",
|
|
184
|
+
"focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring",
|
|
185
|
+
)}
|
|
186
|
+
>
|
|
187
|
+
Confirm
|
|
188
|
+
</button>
|
|
189
|
+
<button
|
|
190
|
+
type="button"
|
|
191
|
+
onClick={cancelConfirm}
|
|
192
|
+
className={cn(
|
|
193
|
+
"rounded px-2 py-0.5 text-xs font-medium",
|
|
194
|
+
"text-amber-700 hover:text-amber-900",
|
|
195
|
+
"dark:text-amber-300 dark:hover:text-amber-100",
|
|
196
|
+
"focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring",
|
|
197
|
+
)}
|
|
198
|
+
>
|
|
199
|
+
Cancel
|
|
200
|
+
</button>
|
|
201
|
+
</div>
|
|
202
|
+
)}
|
|
203
|
+
</div>
|
|
204
|
+
);
|
|
205
|
+
}
|
package/src/library/index.ts
CHANGED
|
@@ -39,4 +39,13 @@ export type {
|
|
|
39
39
|
PushSkillParams,
|
|
40
40
|
} from "./useApplyResource";
|
|
41
41
|
|
|
42
|
+
export { VisibilityToggle } from "./VisibilityToggle";
|
|
43
|
+
export type { VisibilityToggleProps } from "./VisibilityToggle";
|
|
44
|
+
|
|
45
|
+
export { useUpdateVisibility } from "./useUpdateVisibility";
|
|
46
|
+
export type {
|
|
47
|
+
VisibilityResourceKind,
|
|
48
|
+
UseUpdateVisibilityReturn,
|
|
49
|
+
} from "./useUpdateVisibility";
|
|
50
|
+
|
|
42
51
|
export type { ResourceListScope } from "../search";
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
|
|
3
|
+
import { useCallback, useState } from "react";
|
|
4
|
+
import { create } from "@bufbuild/protobuf";
|
|
5
|
+
import { ApiResourceVisibility } from "@stigmer/protos/ai/stigmer/commons/apiresource/enum_pb";
|
|
6
|
+
import { UpdateVisibilityInputSchema } from "@stigmer/protos/ai/stigmer/commons/apiresource/io_pb";
|
|
7
|
+
import { useStigmer } from "../hooks";
|
|
8
|
+
import { toError } from "../internal/toError";
|
|
9
|
+
|
|
10
|
+
/** Resource kinds that support the `updateVisibility` RPC. */
|
|
11
|
+
export type VisibilityResourceKind = "skill" | "agent" | "mcpServer";
|
|
12
|
+
|
|
13
|
+
export interface UseUpdateVisibilityReturn {
|
|
14
|
+
/**
|
|
15
|
+
* Call the `updateVisibility` RPC for the specified resource.
|
|
16
|
+
* Resolves when the server confirms the change.
|
|
17
|
+
*/
|
|
18
|
+
readonly updateVisibility: (
|
|
19
|
+
visibility: ApiResourceVisibility,
|
|
20
|
+
) => Promise<void>;
|
|
21
|
+
/** `true` while the RPC is in flight. */
|
|
22
|
+
readonly isPending: boolean;
|
|
23
|
+
/** The last error from the RPC, or `null`. */
|
|
24
|
+
readonly error: Error | null;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* Behavior hook that updates the visibility of a Skill, Agent, or
|
|
29
|
+
* MCP Server.
|
|
30
|
+
*
|
|
31
|
+
* Wraps the generated `stigmer.{kind}.updateVisibility()` SDK method
|
|
32
|
+
* with loading and error state management. The hook is stateless with
|
|
33
|
+
* respect to the resource — the caller is responsible for refreshing
|
|
34
|
+
* the resource after a successful update (e.g., via `refetch` from
|
|
35
|
+
* the corresponding data hook).
|
|
36
|
+
*
|
|
37
|
+
* Pass `null` for `resourceId` to produce a stable no-op (useful when
|
|
38
|
+
* the resource hasn't loaded yet).
|
|
39
|
+
*
|
|
40
|
+
* @example
|
|
41
|
+
* ```tsx
|
|
42
|
+
* const { updateVisibility, isPending } = useUpdateVisibility("skill", skill.metadata.id);
|
|
43
|
+
*
|
|
44
|
+
* <VisibilityToggle
|
|
45
|
+
* visibility={skill.metadata.visibility}
|
|
46
|
+
* onVisibilityChange={updateVisibility}
|
|
47
|
+
* isPending={isPending}
|
|
48
|
+
* />
|
|
49
|
+
* ```
|
|
50
|
+
*/
|
|
51
|
+
export function useUpdateVisibility(
|
|
52
|
+
kind: VisibilityResourceKind,
|
|
53
|
+
resourceId: string | null,
|
|
54
|
+
): UseUpdateVisibilityReturn {
|
|
55
|
+
const stigmer = useStigmer();
|
|
56
|
+
const [isPending, setIsPending] = useState(false);
|
|
57
|
+
const [error, setError] = useState<Error | null>(null);
|
|
58
|
+
|
|
59
|
+
const updateVisibility = useCallback(
|
|
60
|
+
async (visibility: ApiResourceVisibility) => {
|
|
61
|
+
if (!resourceId) return;
|
|
62
|
+
|
|
63
|
+
setIsPending(true);
|
|
64
|
+
setError(null);
|
|
65
|
+
|
|
66
|
+
try {
|
|
67
|
+
const input = create(UpdateVisibilityInputSchema, {
|
|
68
|
+
resourceId,
|
|
69
|
+
visibility,
|
|
70
|
+
});
|
|
71
|
+
|
|
72
|
+
switch (kind) {
|
|
73
|
+
case "skill":
|
|
74
|
+
await stigmer.skill.updateVisibility(input);
|
|
75
|
+
break;
|
|
76
|
+
case "agent":
|
|
77
|
+
await stigmer.agent.updateVisibility(input);
|
|
78
|
+
break;
|
|
79
|
+
case "mcpServer":
|
|
80
|
+
await stigmer.mcpServer.updateVisibility(input);
|
|
81
|
+
break;
|
|
82
|
+
}
|
|
83
|
+
} catch (err) {
|
|
84
|
+
setError(toError(err));
|
|
85
|
+
throw err;
|
|
86
|
+
} finally {
|
|
87
|
+
setIsPending(false);
|
|
88
|
+
}
|
|
89
|
+
},
|
|
90
|
+
[kind, resourceId, stigmer],
|
|
91
|
+
);
|
|
92
|
+
|
|
93
|
+
return { updateVisibility, isPending, error };
|
|
94
|
+
}
|
|
@@ -13,6 +13,7 @@ import type { EnvironmentValue } from "@stigmer/protos/ai/stigmer/agentic/enviro
|
|
|
13
13
|
import { ApiResourceVisibility } from "@stigmer/protos/ai/stigmer/commons/apiresource/enum_pb";
|
|
14
14
|
import { useMcpServer } from "./useMcpServer";
|
|
15
15
|
import { ErrorMessage } from "../error/ErrorMessage";
|
|
16
|
+
import { VisibilityToggle } from "../library/VisibilityToggle";
|
|
16
17
|
|
|
17
18
|
export interface McpServerDetailViewProps {
|
|
18
19
|
/** Organization slug that owns the MCP server. */
|
|
@@ -27,7 +28,16 @@ export interface McpServerDetailViewProps {
|
|
|
27
28
|
*
|
|
28
29
|
* Not called on error or not-found states.
|
|
29
30
|
*/
|
|
30
|
-
readonly onResourceLoad?: (meta: { name: string }) => void;
|
|
31
|
+
readonly onResourceLoad?: (meta: { name: string; id: string }) => void;
|
|
32
|
+
/**
|
|
33
|
+
* Called when the user toggles visibility via the inline control.
|
|
34
|
+
* When provided, the header renders an interactive
|
|
35
|
+
* {@link VisibilityToggle} instead of a read-only badge.
|
|
36
|
+
* When omitted, visibility is displayed as a static "Public" pill.
|
|
37
|
+
*/
|
|
38
|
+
readonly onVisibilityChange?: (v: ApiResourceVisibility) => void;
|
|
39
|
+
/** `true` while a visibility update RPC is in flight. */
|
|
40
|
+
readonly isVisibilityPending?: boolean;
|
|
31
41
|
/** Additional CSS classes for the root container. */
|
|
32
42
|
readonly className?: string;
|
|
33
43
|
}
|
|
@@ -58,6 +68,8 @@ export function McpServerDetailView({
|
|
|
58
68
|
org,
|
|
59
69
|
slug,
|
|
60
70
|
onResourceLoad,
|
|
71
|
+
onVisibilityChange,
|
|
72
|
+
isVisibilityPending,
|
|
61
73
|
className,
|
|
62
74
|
}: McpServerDetailViewProps) {
|
|
63
75
|
const { mcpServer, isLoading, error, refetch } = useMcpServer(org, slug);
|
|
@@ -67,7 +79,7 @@ export function McpServerDetailView({
|
|
|
67
79
|
|
|
68
80
|
useEffect(() => {
|
|
69
81
|
if (mcpServer?.metadata?.name) {
|
|
70
|
-
onResourceLoadRef.current?.({ name: mcpServer.metadata.name });
|
|
82
|
+
onResourceLoadRef.current?.({ name: mcpServer.metadata.name, id: mcpServer.metadata.id });
|
|
71
83
|
}
|
|
72
84
|
}, [mcpServer]);
|
|
73
85
|
|
|
@@ -101,6 +113,8 @@ export function McpServerDetailView({
|
|
|
101
113
|
? timestampDate(capabilities.lastDiscoveredAt)
|
|
102
114
|
: null
|
|
103
115
|
}
|
|
116
|
+
onVisibilityChange={onVisibilityChange}
|
|
117
|
+
isVisibilityPending={isVisibilityPending}
|
|
104
118
|
/>
|
|
105
119
|
|
|
106
120
|
{spec?.serverType.case && (
|
|
@@ -152,11 +166,15 @@ function Header({
|
|
|
152
166
|
createdAt,
|
|
153
167
|
updatedAt,
|
|
154
168
|
lastDiscoveredAt,
|
|
169
|
+
onVisibilityChange,
|
|
170
|
+
isVisibilityPending,
|
|
155
171
|
}: {
|
|
156
172
|
readonly server: McpServer;
|
|
157
173
|
readonly createdAt: Date | null;
|
|
158
174
|
readonly updatedAt: Date | null;
|
|
159
175
|
readonly lastDiscoveredAt: Date | null;
|
|
176
|
+
readonly onVisibilityChange?: (v: ApiResourceVisibility) => void;
|
|
177
|
+
readonly isVisibilityPending?: boolean;
|
|
160
178
|
}) {
|
|
161
179
|
const meta = server.metadata;
|
|
162
180
|
const spec = server.spec;
|
|
@@ -181,10 +199,18 @@ function Header({
|
|
|
181
199
|
<h2 className="truncate text-lg font-semibold text-foreground">
|
|
182
200
|
{displayName}
|
|
183
201
|
</h2>
|
|
184
|
-
{
|
|
185
|
-
<
|
|
186
|
-
|
|
187
|
-
|
|
202
|
+
{onVisibilityChange && meta ? (
|
|
203
|
+
<VisibilityToggle
|
|
204
|
+
visibility={meta.visibility}
|
|
205
|
+
onVisibilityChange={onVisibilityChange}
|
|
206
|
+
isPending={isVisibilityPending}
|
|
207
|
+
/>
|
|
208
|
+
) : (
|
|
209
|
+
isPublic && (
|
|
210
|
+
<span className="shrink-0 rounded-full bg-muted px-2 py-0.5 text-[10px] font-medium text-muted-foreground">
|
|
211
|
+
Public
|
|
212
|
+
</span>
|
|
213
|
+
)
|
|
188
214
|
)}
|
|
189
215
|
</div>
|
|
190
216
|
<div className="mt-0.5 flex flex-wrap items-center gap-x-1.5 text-xs text-muted-foreground">
|
|
@@ -10,8 +10,8 @@ export interface UseResourceCountOptions {
|
|
|
10
10
|
/**
|
|
11
11
|
* Controls resource visibility scope.
|
|
12
12
|
*
|
|
13
|
-
* - `"org"` —
|
|
14
|
-
* - `"all"` —
|
|
13
|
+
* - `"org"` — all resources owned by the given organization, regardless of visibility.
|
|
14
|
+
* - `"all"` — all resources the caller is authorized to access, across all organizations.
|
|
15
15
|
*
|
|
16
16
|
* @default "org"
|
|
17
17
|
*/
|
|
@@ -72,9 +72,9 @@ export function useResourceCount(
|
|
|
72
72
|
setError(null);
|
|
73
73
|
|
|
74
74
|
const params: ListParams = {
|
|
75
|
-
org,
|
|
75
|
+
org: scope === "all" ? "" : org,
|
|
76
76
|
query: query || undefined,
|
|
77
|
-
excludePublic:
|
|
77
|
+
excludePublic: false,
|
|
78
78
|
page: { num: 1, size: 1 },
|
|
79
79
|
};
|
|
80
80
|
|
|
@@ -4,7 +4,12 @@ import { useCallback, useEffect, useRef, useState } from "react";
|
|
|
4
4
|
import type { ListParams, ListResult } from "@stigmer/sdk";
|
|
5
5
|
import type { SearchResult } from "@stigmer/protos/ai/stigmer/search/v1/io_pb";
|
|
6
6
|
|
|
7
|
-
/**
|
|
7
|
+
/**
|
|
8
|
+
* Scope controls resource listing boundaries.
|
|
9
|
+
*
|
|
10
|
+
* - `"org"` — resources owned by the active organization (public and private).
|
|
11
|
+
* - `"all"` — all resources the caller can access, across every organization.
|
|
12
|
+
*/
|
|
8
13
|
export type ResourceListScope = "org" | "all";
|
|
9
14
|
|
|
10
15
|
export interface UseResourceListOptions {
|
|
@@ -17,8 +22,8 @@ export interface UseResourceListOptions {
|
|
|
17
22
|
/**
|
|
18
23
|
* Controls resource visibility scope.
|
|
19
24
|
*
|
|
20
|
-
* - `"org"` —
|
|
21
|
-
* - `"all"` —
|
|
25
|
+
* - `"org"` — all resources owned by the given organization, regardless of visibility.
|
|
26
|
+
* - `"all"` — all resources the caller is authorized to access, across all organizations.
|
|
22
27
|
*
|
|
23
28
|
* @default "org"
|
|
24
29
|
*/
|
|
@@ -83,9 +88,9 @@ export function useResourceList(
|
|
|
83
88
|
setError(null);
|
|
84
89
|
|
|
85
90
|
const params: ListParams = {
|
|
86
|
-
org,
|
|
91
|
+
org: scope === "all" ? "" : org,
|
|
87
92
|
query: query || undefined,
|
|
88
|
-
excludePublic:
|
|
93
|
+
excludePublic: false,
|
|
89
94
|
page: { num: page, size: pageSize },
|
|
90
95
|
};
|
|
91
96
|
|
package/src/session/index.ts
CHANGED
|
@@ -31,3 +31,6 @@ export type { UseAgentRefFromSessionReturn } from "./useAgentRefFromSession";
|
|
|
31
31
|
|
|
32
32
|
export { groupSessionsByTime } from "./group-sessions";
|
|
33
33
|
export type { SessionGroup } from "./group-sessions";
|
|
34
|
+
|
|
35
|
+
// Session utilities (re-exported from @stigmer/sdk)
|
|
36
|
+
export { PENDING_SUBJECT, resolvedSubject } from "@stigmer/sdk";
|
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
|
|
3
3
|
import { useCallback, useState } from "react";
|
|
4
|
-
import
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
4
|
+
import {
|
|
5
|
+
PENDING_SUBJECT,
|
|
6
|
+
type McpServerUsageInput,
|
|
7
|
+
type ResourceRef,
|
|
8
|
+
type WorkspaceEntryInput,
|
|
8
9
|
} from "@stigmer/sdk";
|
|
9
10
|
import { useStigmer } from "../hooks";
|
|
10
11
|
import { toError } from "../internal/toError";
|
|
@@ -119,7 +120,7 @@ export function useCreateSession(): UseCreateSessionReturn {
|
|
|
119
120
|
const session = await stigmer.session.create({
|
|
120
121
|
name: `session-${Date.now()}`,
|
|
121
122
|
org: input.org,
|
|
122
|
-
subject: input.subject,
|
|
123
|
+
subject: input.subject ?? PENDING_SUBJECT,
|
|
123
124
|
workspaceEntries: input.workspaceEntries,
|
|
124
125
|
mcpServerUsages: input.mcpServerUsages,
|
|
125
126
|
skillRefs: input.skillRefs,
|
|
@@ -10,6 +10,7 @@ import { SkillState } from "@stigmer/protos/ai/stigmer/agentic/skill/v1/status_p
|
|
|
10
10
|
import { ApiResourceVisibility } from "@stigmer/protos/ai/stigmer/commons/apiresource/enum_pb";
|
|
11
11
|
import { useSkill } from "./useSkill";
|
|
12
12
|
import { ErrorMessage } from "../error/ErrorMessage";
|
|
13
|
+
import { VisibilityToggle } from "../library/VisibilityToggle";
|
|
13
14
|
import { MARKDOWN_COMPONENTS, REMARK_PLUGINS } from "../internal/markdown-components";
|
|
14
15
|
|
|
15
16
|
export interface SkillDetailViewProps {
|
|
@@ -27,7 +28,16 @@ export interface SkillDetailViewProps {
|
|
|
27
28
|
*
|
|
28
29
|
* Not called on error or not-found states.
|
|
29
30
|
*/
|
|
30
|
-
readonly onResourceLoad?: (meta: { name: string }) => void;
|
|
31
|
+
readonly onResourceLoad?: (meta: { name: string; id: string }) => void;
|
|
32
|
+
/**
|
|
33
|
+
* Called when the user toggles visibility via the inline control.
|
|
34
|
+
* When provided, the header renders an interactive
|
|
35
|
+
* {@link VisibilityToggle} instead of a read-only badge.
|
|
36
|
+
* When omitted, visibility is displayed as a static "Public" pill.
|
|
37
|
+
*/
|
|
38
|
+
readonly onVisibilityChange?: (v: ApiResourceVisibility) => void;
|
|
39
|
+
/** `true` while a visibility update RPC is in flight. */
|
|
40
|
+
readonly isVisibilityPending?: boolean;
|
|
31
41
|
/** Additional CSS classes for the root container. */
|
|
32
42
|
readonly className?: string;
|
|
33
43
|
}
|
|
@@ -65,6 +75,8 @@ export function SkillDetailView({
|
|
|
65
75
|
slug,
|
|
66
76
|
version,
|
|
67
77
|
onResourceLoad,
|
|
78
|
+
onVisibilityChange,
|
|
79
|
+
isVisibilityPending,
|
|
68
80
|
className,
|
|
69
81
|
}: SkillDetailViewProps) {
|
|
70
82
|
const { skill, isLoading, error, refetch } = useSkill(org, slug, version);
|
|
@@ -74,7 +86,7 @@ export function SkillDetailView({
|
|
|
74
86
|
|
|
75
87
|
useEffect(() => {
|
|
76
88
|
if (skill?.metadata?.name) {
|
|
77
|
-
onResourceLoadRef.current?.({ name: skill.metadata.name });
|
|
89
|
+
onResourceLoadRef.current?.({ name: skill.metadata.name, id: skill.metadata.id });
|
|
78
90
|
}
|
|
79
91
|
}, [skill]);
|
|
80
92
|
|
|
@@ -97,6 +109,8 @@ export function SkillDetailView({
|
|
|
97
109
|
updatedAt={
|
|
98
110
|
specAudit?.updatedAt ? timestampDate(specAudit.updatedAt) : null
|
|
99
111
|
}
|
|
112
|
+
onVisibilityChange={onVisibilityChange}
|
|
113
|
+
isVisibilityPending={isVisibilityPending}
|
|
100
114
|
/>
|
|
101
115
|
|
|
102
116
|
{spec?.skillMd && (
|
|
@@ -121,10 +135,14 @@ function Header({
|
|
|
121
135
|
skill,
|
|
122
136
|
createdAt,
|
|
123
137
|
updatedAt,
|
|
138
|
+
onVisibilityChange,
|
|
139
|
+
isVisibilityPending,
|
|
124
140
|
}: {
|
|
125
141
|
readonly skill: Skill;
|
|
126
142
|
readonly createdAt: Date | null;
|
|
127
143
|
readonly updatedAt: Date | null;
|
|
144
|
+
readonly onVisibilityChange?: (v: ApiResourceVisibility) => void;
|
|
145
|
+
readonly isVisibilityPending?: boolean;
|
|
128
146
|
}) {
|
|
129
147
|
const meta = skill.metadata;
|
|
130
148
|
const spec = skill.spec;
|
|
@@ -141,10 +159,18 @@ function Header({
|
|
|
141
159
|
<h2 className="truncate text-lg font-semibold text-foreground">
|
|
142
160
|
{displayName}
|
|
143
161
|
</h2>
|
|
144
|
-
{
|
|
145
|
-
<
|
|
146
|
-
|
|
147
|
-
|
|
162
|
+
{onVisibilityChange && meta ? (
|
|
163
|
+
<VisibilityToggle
|
|
164
|
+
visibility={meta.visibility}
|
|
165
|
+
onVisibilityChange={onVisibilityChange}
|
|
166
|
+
isPending={isVisibilityPending}
|
|
167
|
+
/>
|
|
168
|
+
) : (
|
|
169
|
+
isPublic && (
|
|
170
|
+
<span className="shrink-0 rounded-full bg-muted px-2 py-0.5 text-[10px] font-medium text-muted-foreground">
|
|
171
|
+
Public
|
|
172
|
+
</span>
|
|
173
|
+
)
|
|
148
174
|
)}
|
|
149
175
|
</div>
|
|
150
176
|
<div className="mt-0.5 flex flex-wrap items-center gap-x-1.5 text-xs text-muted-foreground">
|