@stigmer/react 3.11.1-dev.20260812192248 → 3.12.1
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/activity/useRecentActivity.d.ts +3 -2
- package/activity/useRecentActivity.d.ts.map +1 -1
- package/activity/useRecentActivity.js +3 -2
- package/activity/useRecentActivity.js.map +1 -1
- package/agent/AgentDetailView.d.ts +2 -12
- package/agent/AgentDetailView.d.ts.map +1 -1
- package/agent/AgentDetailView.js +10 -42
- package/agent/AgentDetailView.js.map +1 -1
- package/agent/internal/agentToInput.d.ts.map +1 -1
- package/agent/internal/agentToInput.js +0 -8
- package/agent/internal/agentToInput.js.map +1 -1
- package/dependency-graph/DependencyTreeNode.d.ts.map +1 -1
- package/dependency-graph/DependencyTreeNode.js +1 -7
- package/dependency-graph/DependencyTreeNode.js.map +1 -1
- package/dependency-graph/types.d.ts +8 -20
- package/dependency-graph/types.d.ts.map +1 -1
- package/dependency-graph/useDependencyGraph.d.ts.map +1 -1
- package/dependency-graph/useDependencyGraph.js +2 -20
- package/dependency-graph/useDependencyGraph.js.map +1 -1
- package/execution/useCreateAgentExecution.d.ts +3 -2
- package/execution/useCreateAgentExecution.d.ts.map +1 -1
- package/execution/useCreateAgentExecution.js.map +1 -1
- package/index.d.ts +0 -2
- package/index.d.ts.map +1 -1
- package/index.js +0 -6
- package/index.js.map +1 -1
- package/internal/isUnimplemented.d.ts +17 -0
- package/internal/isUnimplemented.d.ts.map +1 -0
- package/internal/isUnimplemented.js +26 -0
- package/internal/isUnimplemented.js.map +1 -0
- package/library/useExportResource.d.ts +3 -4
- package/library/useExportResource.d.ts.map +1 -1
- package/library/useExportResource.js +1 -1
- package/library/useExportResource.js.map +1 -1
- package/manifest/EditResourceYamlDialog.d.ts.map +1 -1
- package/manifest/EditResourceYamlDialog.js.map +1 -1
- package/mcp-server/McpServerConnectDialog.js +7 -3
- package/mcp-server/McpServerConnectDialog.js.map +1 -1
- package/mcp-server/useMcpServerCredentials.d.ts +38 -10
- package/mcp-server/useMcpServerCredentials.d.ts.map +1 -1
- package/mcp-server/useMcpServerCredentials.js +50 -7
- package/mcp-server/useMcpServerCredentials.js.map +1 -1
- package/mcp-server/useOrgOAuthApp.d.ts +22 -0
- package/mcp-server/useOrgOAuthApp.d.ts.map +1 -1
- package/mcp-server/useOrgOAuthApp.js +39 -7
- package/mcp-server/useOrgOAuthApp.js.map +1 -1
- package/package.json +4 -4
- package/session/useSessionConversation.d.ts +4 -2
- package/session/useSessionConversation.d.ts.map +1 -1
- package/session/useSessionConversation.js.map +1 -1
- package/skill/useSkillVersions.d.ts.map +1 -1
- package/skill/useSkillVersions.js +1 -9
- package/skill/useSkillVersions.js.map +1 -1
- package/src/activity/useRecentActivity.ts +3 -2
- package/src/agent/AgentDetailView.tsx +6 -130
- package/src/agent/internal/__tests__/agentToInput.test.ts +2 -11
- package/src/agent/internal/agentToInput.ts +0 -11
- package/src/dependency-graph/DependencyTreeNode.tsx +1 -7
- package/src/dependency-graph/__tests__/useDependencyGraph.test.ts +18 -34
- package/src/dependency-graph/types.ts +8 -20
- package/src/dependency-graph/useDependencyGraph.ts +2 -22
- package/src/execution/useCreateAgentExecution.ts +3 -2
- package/src/index.ts +0 -82
- package/src/internal/isUnimplemented.ts +26 -0
- package/src/library/useExportResource.ts +3 -4
- package/src/manifest/EditResourceYamlDialog.tsx +1 -2
- package/src/manifest/__tests__/ApplyManifestDialog.test.tsx +2 -2
- package/src/manifest/__tests__/EditResourceYamlDialog.test.tsx +9 -9
- package/src/mcp-server/McpServerConnectDialog.tsx +29 -11
- package/src/mcp-server/__tests__/VendorApprovalBlocked.surfaces.test.tsx +103 -5
- package/src/mcp-server/__tests__/byoaEditionDegradation.test.tsx +323 -0
- package/src/mcp-server/__tests__/useMcpServerCredentials.test.tsx +306 -0
- package/src/mcp-server/useMcpServerCredentials.ts +87 -19
- package/src/mcp-server/useOrgOAuthApp.ts +54 -8
- package/src/session/useSessionConversation.ts +4 -2
- package/src/skill/useSkillVersions.ts +1 -11
- package/src/workflow/WorkflowCanvasEditor.tsx +37 -7
- package/src/workflow/WorkflowExecutionGraph.tsx +26 -1
- package/src/workflow/WorkflowExecutionViewer.tsx +27 -13
- package/src/workflow/WorkflowNode.tsx +5 -2
- package/src/workflow/WorkflowRunDialog.tsx +28 -1
- package/src/workflow/__tests__/WorkflowExecutionViewer.reconciliation.test.tsx +48 -1
- package/src/workflow/__tests__/WorkflowNode.test.tsx +93 -0
- package/src/workflow/__tests__/WorkflowRunDialog.test.tsx +127 -0
- package/src/workflow/__tests__/graph-history.test.ts +103 -0
- package/src/workflow/__tests__/overview-graph.test.ts +17 -0
- package/src/workflow/__tests__/useCanvasKeyboardShortcuts.undo.test.ts +115 -0
- package/src/workflow/__tests__/useWorkflowCanvas.undo.test.tsx +133 -0
- package/src/workflow/instance/CreateWorkflowInstanceDialog.tsx +16 -7
- package/src/workflow/instance/useDeleteWorkflowInstance.ts +9 -4
- package/src/workflow/layout/registry-dimensions.ts +2 -5
- package/src/workflow/node-shell/NodeShell.tsx +4 -0
- package/src/workflow/task-type-visual-registry.ts +5 -3
- package/src/workflow/useCanvasKeyboardShortcuts.ts +33 -3
- package/src/workflow/useGraphHistory.ts +22 -41
- package/src/workflow/useWorkflowCanvas.ts +12 -10
- package/src/workflow/useWorkflowSave.ts +2 -15
- package/src/workflow/workflow-graph-conversions.ts +25 -3
- package/styles.css +1 -1
- package/workflow/CanvasTransitionEdge.d.ts +1 -1
- package/workflow/WorkflowCanvasEditor.d.ts.map +1 -1
- package/workflow/WorkflowCanvasEditor.js +31 -6
- package/workflow/WorkflowCanvasEditor.js.map +1 -1
- package/workflow/WorkflowExecutionGraph.d.ts.map +1 -1
- package/workflow/WorkflowExecutionGraph.js +27 -1
- package/workflow/WorkflowExecutionGraph.js.map +1 -1
- package/workflow/WorkflowExecutionViewer.d.ts.map +1 -1
- package/workflow/WorkflowExecutionViewer.js +26 -12
- package/workflow/WorkflowExecutionViewer.js.map +1 -1
- package/workflow/WorkflowNode.d.ts.map +1 -1
- package/workflow/WorkflowNode.js +2 -2
- package/workflow/WorkflowNode.js.map +1 -1
- package/workflow/WorkflowRunDialog.d.ts +11 -1
- package/workflow/WorkflowRunDialog.d.ts.map +1 -1
- package/workflow/WorkflowRunDialog.js +16 -2
- package/workflow/WorkflowRunDialog.js.map +1 -1
- package/workflow/instance/CreateWorkflowInstanceDialog.d.ts.map +1 -1
- package/workflow/instance/CreateWorkflowInstanceDialog.js +10 -2
- package/workflow/instance/CreateWorkflowInstanceDialog.js.map +1 -1
- package/workflow/instance/useDeleteWorkflowInstance.d.ts +9 -4
- package/workflow/instance/useDeleteWorkflowInstance.d.ts.map +1 -1
- package/workflow/instance/useDeleteWorkflowInstance.js +4 -2
- package/workflow/instance/useDeleteWorkflowInstance.js.map +1 -1
- package/workflow/layout/registry-dimensions.d.ts.map +1 -1
- package/workflow/layout/registry-dimensions.js +2 -5
- package/workflow/layout/registry-dimensions.js.map +1 -1
- package/workflow/node-shell/NodeShell.js +1 -1
- package/workflow/node-shell/NodeShell.js.map +1 -1
- package/workflow/task-type-visual-registry.d.ts.map +1 -1
- package/workflow/task-type-visual-registry.js +5 -3
- package/workflow/task-type-visual-registry.js.map +1 -1
- package/workflow/useCanvasKeyboardShortcuts.d.ts +15 -4
- package/workflow/useCanvasKeyboardShortcuts.d.ts.map +1 -1
- package/workflow/useCanvasKeyboardShortcuts.js +25 -4
- package/workflow/useCanvasKeyboardShortcuts.js.map +1 -1
- package/workflow/useGraphHistory.d.ts +16 -9
- package/workflow/useGraphHistory.d.ts.map +1 -1
- package/workflow/useGraphHistory.js +19 -33
- package/workflow/useGraphHistory.js.map +1 -1
- package/workflow/useWorkflowCanvas.d.ts +1 -3
- package/workflow/useWorkflowCanvas.d.ts.map +1 -1
- package/workflow/useWorkflowCanvas.js +15 -9
- package/workflow/useWorkflowCanvas.js.map +1 -1
- package/workflow/useWorkflowSave.d.ts.map +1 -1
- package/workflow/useWorkflowSave.js +2 -15
- package/workflow/useWorkflowSave.js.map +1 -1
- package/workflow/workflow-graph-conversions.d.ts +19 -1
- package/workflow/workflow-graph-conversions.d.ts.map +1 -1
- package/workflow/workflow-graph-conversions.js +17 -3
- package/workflow/workflow-graph-conversions.js.map +1 -1
- package/datastore/CollectionRecordsBrowser.d.ts +0 -34
- package/datastore/CollectionRecordsBrowser.d.ts.map +0 -1
- package/datastore/CollectionRecordsBrowser.js +0 -226
- package/datastore/CollectionRecordsBrowser.js.map +0 -1
- package/datastore/CollectionSchemaView.d.ts +0 -29
- package/datastore/CollectionSchemaView.d.ts.map +0 -1
- package/datastore/CollectionSchemaView.js +0 -93
- package/datastore/CollectionSchemaView.js.map +0 -1
- package/datastore/DatastoreDetailView.d.ts +0 -44
- package/datastore/DatastoreDetailView.d.ts.map +0 -1
- package/datastore/DatastoreDetailView.js +0 -76
- package/datastore/DatastoreDetailView.js.map +0 -1
- package/datastore/DatastoreSyncReport.d.ts +0 -19
- package/datastore/DatastoreSyncReport.d.ts.map +0 -1
- package/datastore/DatastoreSyncReport.js +0 -45
- package/datastore/DatastoreSyncReport.js.map +0 -1
- package/datastore/DeleteDatastoreDialog.d.ts +0 -35
- package/datastore/DeleteDatastoreDialog.d.ts.map +0 -1
- package/datastore/DeleteDatastoreDialog.js +0 -90
- package/datastore/DeleteDatastoreDialog.js.map +0 -1
- package/datastore/FieldValueControl.d.ts +0 -55
- package/datastore/FieldValueControl.d.ts.map +0 -1
- package/datastore/FieldValueControl.js +0 -138
- package/datastore/FieldValueControl.js.map +0 -1
- package/datastore/RecordFilterBuilder.d.ts +0 -37
- package/datastore/RecordFilterBuilder.d.ts.map +0 -1
- package/datastore/RecordFilterBuilder.js +0 -122
- package/datastore/RecordFilterBuilder.js.map +0 -1
- package/datastore/RecordFormPanel.d.ts +0 -45
- package/datastore/RecordFormPanel.d.ts.map +0 -1
- package/datastore/RecordFormPanel.js +0 -215
- package/datastore/RecordFormPanel.js.map +0 -1
- package/datastore/index.d.ts +0 -43
- package/datastore/index.d.ts.map +0 -1
- package/datastore/index.js +0 -22
- package/datastore/index.js.map +0 -1
- package/datastore/recordFilter.d.ts +0 -62
- package/datastore/recordFilter.d.ts.map +0 -1
- package/datastore/recordFilter.js +0 -104
- package/datastore/recordFilter.js.map +0 -1
- package/datastore/recordValues.d.ts +0 -85
- package/datastore/recordValues.d.ts.map +0 -1
- package/datastore/recordValues.js +0 -282
- package/datastore/recordValues.js.map +0 -1
- package/datastore/useDatastore.d.ts +0 -39
- package/datastore/useDatastore.d.ts.map +0 -1
- package/datastore/useDatastore.js +0 -44
- package/datastore/useDatastore.js.map +0 -1
- package/datastore/useDatastoreCount.d.ts +0 -50
- package/datastore/useDatastoreCount.d.ts.map +0 -1
- package/datastore/useDatastoreCount.js +0 -27
- package/datastore/useDatastoreCount.js.map +0 -1
- package/datastore/useDatastoreDescription.d.ts +0 -54
- package/datastore/useDatastoreDescription.d.ts.map +0 -1
- package/datastore/useDatastoreDescription.js +0 -50
- package/datastore/useDatastoreDescription.js.map +0 -1
- package/datastore/useDatastoreList.d.ts +0 -57
- package/datastore/useDatastoreList.d.ts.map +0 -1
- package/datastore/useDatastoreList.js +0 -29
- package/datastore/useDatastoreList.js.map +0 -1
- package/datastore/useDatastoreSearch.d.ts +0 -19
- package/datastore/useDatastoreSearch.d.ts.map +0 -1
- package/datastore/useDatastoreSearch.js +0 -22
- package/datastore/useDatastoreSearch.js.map +0 -1
- package/datastore/useDeleteDatastore.d.ts +0 -53
- package/datastore/useDeleteDatastore.d.ts.map +0 -1
- package/datastore/useDeleteDatastore.js +0 -40
- package/datastore/useDeleteDatastore.js.map +0 -1
- package/datastore/useDeleteRecord.d.ts +0 -34
- package/datastore/useDeleteRecord.d.ts.map +0 -1
- package/datastore/useDeleteRecord.js +0 -43
- package/datastore/useDeleteRecord.js.map +0 -1
- package/datastore/useInsertRecord.d.ts +0 -50
- package/datastore/useInsertRecord.d.ts.map +0 -1
- package/datastore/useInsertRecord.js +0 -55
- package/datastore/useInsertRecord.js.map +0 -1
- package/datastore/useRecordCollection.d.ts +0 -104
- package/datastore/useRecordCollection.d.ts.map +0 -1
- package/datastore/useRecordCollection.js +0 -136
- package/datastore/useRecordCollection.js.map +0 -1
- package/datastore/useRecordList.d.ts +0 -66
- package/datastore/useRecordList.d.ts.map +0 -1
- package/datastore/useRecordList.js +0 -58
- package/datastore/useRecordList.js.map +0 -1
- package/datastore/useUpdateRecord.d.ts +0 -52
- package/datastore/useUpdateRecord.d.ts.map +0 -1
- package/datastore/useUpdateRecord.js +0 -55
- package/datastore/useUpdateRecord.js.map +0 -1
- package/src/agent/__tests__/AgentDetailView.datastores.test.tsx +0 -166
- package/src/datastore/CollectionRecordsBrowser.tsx +0 -571
- package/src/datastore/CollectionSchemaView.tsx +0 -247
- package/src/datastore/DatastoreDetailView.tsx +0 -201
- package/src/datastore/DatastoreSyncReport.tsx +0 -105
- package/src/datastore/DeleteDatastoreDialog.tsx +0 -202
- package/src/datastore/FieldValueControl.tsx +0 -289
- package/src/datastore/RecordFilterBuilder.tsx +0 -422
- package/src/datastore/RecordFormPanel.tsx +0 -432
- package/src/datastore/__tests__/CollectionRecordsBrowser.test.tsx +0 -245
- package/src/datastore/__tests__/DeleteDatastoreDialog.test.tsx +0 -133
- package/src/datastore/__tests__/FieldValueControl.test.tsx +0 -160
- package/src/datastore/__tests__/RecordFilterBuilder.test.tsx +0 -155
- package/src/datastore/__tests__/RecordFormPanel.test.tsx +0 -227
- package/src/datastore/__tests__/recordFilter.test.ts +0 -169
- package/src/datastore/__tests__/recordMutations.test.tsx +0 -195
- package/src/datastore/__tests__/recordValues.test.ts +0 -359
- package/src/datastore/__tests__/schemaAndSyncViews.test.tsx +0 -142
- package/src/datastore/__tests__/useDatastoreDescription.test.tsx +0 -143
- package/src/datastore/__tests__/useRecordCollection.test.tsx +0 -250
- package/src/datastore/__tests__/useRecordList.test.tsx +0 -85
- package/src/datastore/index.ts +0 -111
- package/src/datastore/recordFilter.ts +0 -154
- package/src/datastore/recordValues.ts +0 -327
- package/src/datastore/useDatastore.ts +0 -67
- package/src/datastore/useDatastoreCount.ts +0 -69
- package/src/datastore/useDatastoreDescription.ts +0 -90
- package/src/datastore/useDatastoreList.ts +0 -79
- package/src/datastore/useDatastoreSearch.ts +0 -39
- package/src/datastore/useDeleteDatastore.ts +0 -87
- package/src/datastore/useDeleteRecord.ts +0 -77
- package/src/datastore/useInsertRecord.ts +0 -92
- package/src/datastore/useRecordCollection.ts +0 -256
- package/src/datastore/useRecordList.ts +0 -131
- package/src/datastore/useUpdateRecord.ts +0 -95
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Detect gRPC/Connect UNIMPLEMENTED (code 12) from any error the SDK
|
|
3
|
+
* client can throw.
|
|
4
|
+
*
|
|
5
|
+
* UNIMPLEMENTED is how the shared SDK discovers edition capabilities:
|
|
6
|
+
* the OSS server deliberately leaves hosted-only RPCs unimplemented
|
|
7
|
+
* (e.g. the org-OAuth-app override surface, stigmer/stigmer#558), and
|
|
8
|
+
* hooks probe for it to degrade gracefully instead of surfacing an
|
|
9
|
+
* error. The SDK's generated CODE_MAP does not include Unimplemented —
|
|
10
|
+
* a `StigmerError` wrapping one reports `code: "unknown"` — so
|
|
11
|
+
* detection must go through `connectCode` (or the message shapes used
|
|
12
|
+
* by transports that never produce a structured error).
|
|
13
|
+
*
|
|
14
|
+
* @internal
|
|
15
|
+
*/
|
|
16
|
+
export function isUnimplemented(err: unknown): boolean {
|
|
17
|
+
if (!err || typeof err !== "object") return false;
|
|
18
|
+
if (
|
|
19
|
+
"connectCode" in err &&
|
|
20
|
+
(err as { connectCode: unknown }).connectCode === 12
|
|
21
|
+
) {
|
|
22
|
+
return true;
|
|
23
|
+
}
|
|
24
|
+
const msg = (err as { message?: string }).message ?? "";
|
|
25
|
+
return msg.includes("[unimplemented]") || msg.includes("UNIMPLEMENTED");
|
|
26
|
+
}
|
|
@@ -3,7 +3,6 @@
|
|
|
3
3
|
import { useCallback, useMemo } from "react";
|
|
4
4
|
import { parse as parseYaml } from "yaml";
|
|
5
5
|
import type { Agent } from "@stigmer/protos/ai/stigmer/agentic/agent/v1/api_pb";
|
|
6
|
-
import type { Datastore } from "@stigmer/protos/ai/stigmer/agentic/datastore/v1/api_pb";
|
|
7
6
|
import type { McpServer } from "@stigmer/protos/ai/stigmer/agentic/mcpserver/v1/api_pb";
|
|
8
7
|
import type { Schedule } from "@stigmer/protos/ai/stigmer/agentic/schedule/v1/api_pb";
|
|
9
8
|
import type { Workflow } from "@stigmer/protos/ai/stigmer/agentic/workflow/v1/api_pb";
|
|
@@ -18,9 +17,9 @@ import { serializeWorkflowYaml } from "../workflow/serialize-workflow-yaml.js";
|
|
|
18
17
|
/** Options for {@link useExportResource}. */
|
|
19
18
|
export interface UseExportResourceOptions {
|
|
20
19
|
/** The resource kind — determines which serializer is used. */
|
|
21
|
-
readonly kind: "Agent" | "McpServer" | "Workflow" | "
|
|
20
|
+
readonly kind: "Agent" | "McpServer" | "Workflow" | "Schedule";
|
|
22
21
|
/** The proto resource to export, or `null` when not yet loaded. */
|
|
23
|
-
readonly resource: Agent | McpServer | Workflow |
|
|
22
|
+
readonly resource: Agent | McpServer | Workflow | Schedule | null;
|
|
24
23
|
}
|
|
25
24
|
|
|
26
25
|
/** Return value of {@link useExportResource}. */
|
|
@@ -45,7 +44,7 @@ export interface UseExportResourceReturn {
|
|
|
45
44
|
|
|
46
45
|
/**
|
|
47
46
|
* Headless export hook for Stigmer resources (Agent, McpServer,
|
|
48
|
-
* Workflow,
|
|
47
|
+
* Workflow, Schedule).
|
|
49
48
|
*
|
|
50
49
|
* Serializes the resource into YAML and JSON formats and provides
|
|
51
50
|
* stable callbacks for copying to clipboard or triggering a file
|
|
@@ -155,8 +155,7 @@ export function EditResourceYamlDialog({
|
|
|
155
155
|
</div>
|
|
156
156
|
)}
|
|
157
157
|
|
|
158
|
-
{/* Apply error — the server's refusal
|
|
159
|
-
collection-removal rejection) rendered verbatim, with an
|
|
158
|
+
{/* Apply error — the server's refusal rendered verbatim, with an
|
|
160
159
|
acknowledge-and-retry affordance: the operator reads the
|
|
161
160
|
guard, edits or decides, and re-applies without reopening
|
|
162
161
|
the dialog. */}
|
|
@@ -36,7 +36,7 @@ function entry(
|
|
|
36
36
|
): ManifestPreviewEntry {
|
|
37
37
|
return {
|
|
38
38
|
document: {
|
|
39
|
-
handler: { yamlKind: "
|
|
39
|
+
handler: { yamlKind: "mcpserver", displayName: "McpServer" },
|
|
40
40
|
name: slug,
|
|
41
41
|
slug,
|
|
42
42
|
org: "acme",
|
|
@@ -55,7 +55,7 @@ const applyAllMock = vi.fn(async () => applyAllResult);
|
|
|
55
55
|
vi.mock("../useApplyManifest", () => ({
|
|
56
56
|
useApplyManifest: (): UseApplyManifestReturn =>
|
|
57
57
|
({
|
|
58
|
-
content: "kind:
|
|
58
|
+
content: "kind: McpServer",
|
|
59
59
|
setContent: vi.fn(),
|
|
60
60
|
readFile: vi.fn(),
|
|
61
61
|
entries: mockEntries,
|
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
// Tests for the shared Edit-YAML dialog's apply-error affordance
|
|
2
2
|
// (DD-008 SD-6): the server's refusal renders verbatim with
|
|
3
|
-
// Try-again/Dismiss — shared by every kind (McpServer, Agent, Skill,
|
|
4
|
-
//
|
|
5
|
-
//
|
|
3
|
+
// Try-again/Dismiss — shared by every kind (McpServer, Agent, Skill),
|
|
4
|
+
// so any apply-time guard gets the same acknowledge-and-retry
|
|
5
|
+
// treatment.
|
|
6
6
|
|
|
7
7
|
import { describe, it, expect, vi, beforeAll, afterEach } from "vitest";
|
|
8
8
|
import { render, screen, cleanup, fireEvent } from "@testing-library/react";
|
|
9
9
|
import { create } from "@bufbuild/protobuf";
|
|
10
|
-
import {
|
|
10
|
+
import { McpServerSchema } from "@stigmer/protos/ai/stigmer/agentic/mcpserver/v1/api_pb";
|
|
11
11
|
import { EditResourceYamlDialog } from "../EditResourceYamlDialog";
|
|
12
12
|
import type { useEditResourceYaml } from "../useEditResourceYaml";
|
|
13
13
|
|
|
@@ -34,7 +34,7 @@ let editState: Partial<EditState>;
|
|
|
34
34
|
|
|
35
35
|
vi.mock("../useEditResourceYaml", () => ({
|
|
36
36
|
useEditResourceYaml: () => ({
|
|
37
|
-
yaml: "kind:
|
|
37
|
+
yaml: "kind: McpServer",
|
|
38
38
|
setYaml: vi.fn(),
|
|
39
39
|
validation: { status: "valid" as const },
|
|
40
40
|
target: { action: "update" as const, slug: "clinic" },
|
|
@@ -54,8 +54,8 @@ vi.mock("../YamlEditor", () => ({
|
|
|
54
54
|
YamlEditor: () => <div data-testid="yaml-editor" />,
|
|
55
55
|
}));
|
|
56
56
|
|
|
57
|
-
const RESOURCE = create(
|
|
58
|
-
metadata: { id: "
|
|
57
|
+
const RESOURCE = create(McpServerSchema, {
|
|
58
|
+
metadata: { id: "mcp_1", slug: "clinic", org: "acme", name: "Clinic" },
|
|
59
59
|
});
|
|
60
60
|
|
|
61
61
|
function renderDialog() {
|
|
@@ -73,14 +73,14 @@ describe("EditResourceYamlDialog — apply-error affordance", () => {
|
|
|
73
73
|
it("renders the server's refusal verbatim with Try again and Dismiss", () => {
|
|
74
74
|
editState = {
|
|
75
75
|
error: new Error(
|
|
76
|
-
'
|
|
76
|
+
'spec change refused by an apply-time guard; re-apply with the change acknowledged',
|
|
77
77
|
),
|
|
78
78
|
};
|
|
79
79
|
renderDialog();
|
|
80
80
|
|
|
81
81
|
const alert = screen.getByRole("alert");
|
|
82
82
|
expect(alert.textContent).toContain(
|
|
83
|
-
|
|
83
|
+
"spec change refused by an apply-time guard",
|
|
84
84
|
);
|
|
85
85
|
expect(screen.getByRole("button", { name: "Try again" })).toBeTruthy();
|
|
86
86
|
expect(screen.getByRole("button", { name: "Dismiss error" })).toBeTruthy();
|
|
@@ -344,6 +344,7 @@ function ConnectDialogContent({
|
|
|
344
344
|
onSignIn={handleOAuthSignIn}
|
|
345
345
|
isVendorApprovalBlocked={creds.isVendorApprovalBlocked}
|
|
346
346
|
isVendorApprovalPending={creds.isVendorApprovalPending}
|
|
347
|
+
isOrgOAuthApp={creds.isOrgOAuthApp}
|
|
347
348
|
manualEntrySupported={creds.manualEntrySupported}
|
|
348
349
|
canBringOwnApp={creds.canBringOwnApp}
|
|
349
350
|
vendorApprovalDocsUrl={creds.vendorApprovalDocsUrl}
|
|
@@ -459,6 +460,7 @@ function OAuthSection({
|
|
|
459
460
|
onSignIn,
|
|
460
461
|
isVendorApprovalBlocked,
|
|
461
462
|
isVendorApprovalPending,
|
|
463
|
+
isOrgOAuthApp,
|
|
462
464
|
manualEntrySupported,
|
|
463
465
|
canBringOwnApp,
|
|
464
466
|
vendorApprovalDocsUrl,
|
|
@@ -471,6 +473,14 @@ function OAuthSection({
|
|
|
471
473
|
readonly onSignIn: () => void;
|
|
472
474
|
readonly isVendorApprovalBlocked: boolean;
|
|
473
475
|
readonly isVendorApprovalPending: boolean;
|
|
476
|
+
/**
|
|
477
|
+
* `true` when the org's own BYOA OAuth app is the effective one. The
|
|
478
|
+
* vendor-approval block describes the PLATFORM app, so it neither
|
|
479
|
+
* disables sign-in nor warrants the blocked notice when the org's own
|
|
480
|
+
* app is what sign-in will use (the caller-side org-override gate the
|
|
481
|
+
* notice's contract expects).
|
|
482
|
+
*/
|
|
483
|
+
readonly isOrgOAuthApp: boolean;
|
|
474
484
|
readonly manualEntrySupported: boolean;
|
|
475
485
|
readonly canBringOwnApp: boolean;
|
|
476
486
|
readonly vendorApprovalDocsUrl: string | null;
|
|
@@ -502,7 +512,9 @@ function OAuthSection({
|
|
|
502
512
|
<button
|
|
503
513
|
type="button"
|
|
504
514
|
onClick={onSignIn}
|
|
505
|
-
disabled={
|
|
515
|
+
disabled={
|
|
516
|
+
disabled || isInProgress || (isVendorApprovalBlocked && !isOrgOAuthApp)
|
|
517
|
+
}
|
|
506
518
|
className={cn(
|
|
507
519
|
"stg:inline-flex stg:w-full stg:items-center stg:justify-center stg:gap-2 stg:rounded-md stg:px-4 stg:py-2 stg:text-sm stg:font-medium",
|
|
508
520
|
"stg:bg-primary stg:text-primary-foreground",
|
|
@@ -512,17 +524,23 @@ function OAuthSection({
|
|
|
512
524
|
)}
|
|
513
525
|
>
|
|
514
526
|
{isInProgress && <LoadingSpinner size="sm" />}
|
|
515
|
-
{isInProgress
|
|
527
|
+
{isInProgress
|
|
528
|
+
? (phaseLabel[phase] ?? "Connecting...")
|
|
529
|
+
: isOrgOAuthApp
|
|
530
|
+
? "Sign in with your app"
|
|
531
|
+
: "Sign in with OAuth"}
|
|
516
532
|
</button>
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
533
|
+
{!isOrgOAuthApp && (
|
|
534
|
+
<VendorApprovalBlockedNotice
|
|
535
|
+
blocked={isVendorApprovalBlocked}
|
|
536
|
+
pending={isVendorApprovalPending}
|
|
537
|
+
manualEntrySupported={manualEntrySupported}
|
|
538
|
+
canBringOwnApp={canBringOwnApp}
|
|
539
|
+
docsUrl={vendorApprovalDocsUrl}
|
|
540
|
+
onBringOwnApp={onOpenDetails}
|
|
541
|
+
className="stg:rounded-md stg:border stg:border-amber-500/20"
|
|
542
|
+
/>
|
|
543
|
+
)}
|
|
526
544
|
{onSwitchToManual && (
|
|
527
545
|
<button
|
|
528
546
|
type="button"
|
|
@@ -5,7 +5,10 @@ import { create } from "@bufbuild/protobuf";
|
|
|
5
5
|
import { createRouterTransport } from "@connectrpc/connect";
|
|
6
6
|
import { Stigmer } from "@stigmer/sdk";
|
|
7
7
|
import { McpServerQueryController } from "@stigmer/protos/ai/stigmer/agentic/mcpserver/v1/query_pb";
|
|
8
|
-
import {
|
|
8
|
+
import {
|
|
9
|
+
GetOAuthGrantStatusOutputSchema,
|
|
10
|
+
GetOrgOAuthAppOutputSchema,
|
|
11
|
+
} from "@stigmer/protos/ai/stigmer/agentic/mcpserver/v1/io_pb";
|
|
9
12
|
import {
|
|
10
13
|
McpServerSpecSchema,
|
|
11
14
|
McpServerAuthSchema,
|
|
@@ -14,7 +17,6 @@ import {
|
|
|
14
17
|
import {
|
|
15
18
|
McpServerStatusSchema,
|
|
16
19
|
OAuthStatusSchema,
|
|
17
|
-
OAuthAppSource,
|
|
18
20
|
ValidationState,
|
|
19
21
|
} from "@stigmer/protos/ai/stigmer/agentic/mcpserver/v1/status_pb";
|
|
20
22
|
import { VendorApprovalStatus } from "@stigmer/protos/ai/stigmer/iam/oauthapp/v1/spec_pb";
|
|
@@ -53,8 +55,11 @@ const DOCS_URL = "https://vendor.example.com/oauth-docs";
|
|
|
53
55
|
|
|
54
56
|
/**
|
|
55
57
|
* An oauth_only vendor-OAuth server whose platform OAuth app is blocked.
|
|
56
|
-
* `withAppRef` controls the BYOA arm: with a ref and
|
|
57
|
-
*
|
|
58
|
+
* `withAppRef` controls the BYOA arm: with a ref and no org override,
|
|
59
|
+
* `canBringOwnApp` is true. The org-override state itself comes from the
|
|
60
|
+
* `getOrgOAuthApp` transport handler (client-side derivation,
|
|
61
|
+
* stigmer-cloud#401) — status.oauth_status carries only the
|
|
62
|
+
* vendor-approval fields, matching what backends actually populate.
|
|
58
63
|
*/
|
|
59
64
|
function buildBlockedOAuthOnlyServer(options: {
|
|
60
65
|
status: VendorApprovalStatus;
|
|
@@ -86,7 +91,6 @@ function buildBlockedOAuthOnlyServer(options: {
|
|
|
86
91
|
oauthStatus: create(OAuthStatusSchema, {
|
|
87
92
|
vendorApprovalStatus: options.status,
|
|
88
93
|
vendorApprovalDocsUrl: DOCS_URL,
|
|
89
|
-
effectiveOauthSource: OAuthAppSource.OAUTH_APP_SOURCE_PLATFORM,
|
|
90
94
|
}),
|
|
91
95
|
});
|
|
92
96
|
return server;
|
|
@@ -96,6 +100,15 @@ function noGrant() {
|
|
|
96
100
|
return create(GetOAuthGrantStatusOutputSchema, { connected: false });
|
|
97
101
|
}
|
|
98
102
|
|
|
103
|
+
// BYOA affordances render only where the org-override surface exists —
|
|
104
|
+
// canBringOwnApp is gated on a getOrgOAuthApp capability probe
|
|
105
|
+
// (stigmer/stigmer#558), so the BYOA arms of these tests must register the
|
|
106
|
+
// RPC to simulate the hosted edition. The OSS arm (probe UNIMPLEMENTED →
|
|
107
|
+
// affordances hidden) is pinned in byoaEditionDegradation.test.tsx.
|
|
108
|
+
function noOverride() {
|
|
109
|
+
return create(GetOrgOAuthAppOutputSchema, { hasOverride: false });
|
|
110
|
+
}
|
|
111
|
+
|
|
99
112
|
function renderWithTransport(
|
|
100
113
|
ui: ReactNode,
|
|
101
114
|
register: Parameters<typeof createRouterTransport>[0] = () => {},
|
|
@@ -128,6 +141,7 @@ describe("McpServerConnectDialog — oauth_only + vendor-blocked", () => {
|
|
|
128
141
|
router.service(McpServerQueryController, {
|
|
129
142
|
getByReference: () => server,
|
|
130
143
|
getOAuthGrantStatus: noGrant,
|
|
144
|
+
getOrgOAuthApp: noOverride,
|
|
131
145
|
});
|
|
132
146
|
},
|
|
133
147
|
);
|
|
@@ -199,6 +213,48 @@ describe("McpServerConnectDialog — oauth_only + vendor-blocked", () => {
|
|
|
199
213
|
});
|
|
200
214
|
expect(docs.getAttribute("href")).toBe(DOCS_URL);
|
|
201
215
|
});
|
|
216
|
+
|
|
217
|
+
it("enables sign-in with the org's own app when a BYOA override is active", async () => {
|
|
218
|
+
// The platform app is still vendor-blocked, but the org brought its
|
|
219
|
+
// own approved app — the block describes an app sign-in won't use
|
|
220
|
+
// (stigmer-cloud#401). Before the client-side derivation this state
|
|
221
|
+
// was a dead end: disabled button AND no way forward.
|
|
222
|
+
renderWithTransport(
|
|
223
|
+
<McpServerConnectDialog
|
|
224
|
+
org={ORG}
|
|
225
|
+
slug={SLUG}
|
|
226
|
+
open
|
|
227
|
+
onClose={() => {}}
|
|
228
|
+
/>,
|
|
229
|
+
(router) => {
|
|
230
|
+
router.service(McpServerQueryController, {
|
|
231
|
+
getByReference: () =>
|
|
232
|
+
buildBlockedOAuthOnlyServer({
|
|
233
|
+
status: VendorApprovalStatus.PENDING,
|
|
234
|
+
withAppRef: true,
|
|
235
|
+
}),
|
|
236
|
+
getOAuthGrantStatus: noGrant,
|
|
237
|
+
getOrgOAuthApp: () =>
|
|
238
|
+
create(GetOrgOAuthAppOutputSchema, {
|
|
239
|
+
hasOverride: true,
|
|
240
|
+
oauthAppId: "oauthapp_01acme",
|
|
241
|
+
clientId: "acme-client-id",
|
|
242
|
+
}),
|
|
243
|
+
});
|
|
244
|
+
},
|
|
245
|
+
);
|
|
246
|
+
|
|
247
|
+
const signIn = await screen.findByRole("button", {
|
|
248
|
+
name: "Sign in with your app",
|
|
249
|
+
});
|
|
250
|
+
expect((signIn as HTMLButtonElement).disabled).toBe(false);
|
|
251
|
+
// The blocked notice describes the platform app — suppressed while
|
|
252
|
+
// the org's own app is the effective one.
|
|
253
|
+
expect(screen.queryByText(/awaiting vendor approval/)).toBeNull();
|
|
254
|
+
expect(
|
|
255
|
+
screen.queryByRole("button", { name: "Use your own OAuth app" }),
|
|
256
|
+
).toBeNull();
|
|
257
|
+
});
|
|
202
258
|
});
|
|
203
259
|
|
|
204
260
|
// ---------------------------------------------------------------------------
|
|
@@ -231,6 +287,7 @@ describe("McpServerDetailView — oauth_only + vendor-blocked", () => {
|
|
|
231
287
|
(router) => {
|
|
232
288
|
router.service(McpServerQueryController, {
|
|
233
289
|
getOAuthGrantStatus: noGrant,
|
|
290
|
+
getOrgOAuthApp: noOverride,
|
|
234
291
|
});
|
|
235
292
|
},
|
|
236
293
|
);
|
|
@@ -252,6 +309,47 @@ describe("McpServerDetailView — oauth_only + vendor-blocked", () => {
|
|
|
252
309
|
// extraction into the shared notice.
|
|
253
310
|
expect(cta.getAttribute("data-cursor-target")).toBe("byoa-cta-button");
|
|
254
311
|
});
|
|
312
|
+
|
|
313
|
+
it("enables 'Sign in with your app' when the org's BYOA override is active", async () => {
|
|
314
|
+
// The vendor block gates the PLATFORM app; with the org's own app
|
|
315
|
+
// effective, sign-in must be enabled and the BYOA CTA retired
|
|
316
|
+
// (stigmer-cloud#401 — the signal these gates key on never fired).
|
|
317
|
+
renderWithTransport(
|
|
318
|
+
<McpServerDetailView
|
|
319
|
+
org={ORG}
|
|
320
|
+
slug={SLUG}
|
|
321
|
+
mcpServerState={loadedState(
|
|
322
|
+
buildBlockedOAuthOnlyServer({
|
|
323
|
+
status: VendorApprovalStatus.PENDING,
|
|
324
|
+
withAppRef: true,
|
|
325
|
+
}),
|
|
326
|
+
)}
|
|
327
|
+
/>,
|
|
328
|
+
(router) => {
|
|
329
|
+
router.service(McpServerQueryController, {
|
|
330
|
+
getOAuthGrantStatus: noGrant,
|
|
331
|
+
getOrgOAuthApp: () =>
|
|
332
|
+
create(GetOrgOAuthAppOutputSchema, {
|
|
333
|
+
hasOverride: true,
|
|
334
|
+
oauthAppId: "oauthapp_01acme",
|
|
335
|
+
clientId: "acme-client-id",
|
|
336
|
+
}),
|
|
337
|
+
});
|
|
338
|
+
},
|
|
339
|
+
);
|
|
340
|
+
|
|
341
|
+
const signIn = await screen.findByRole("button", {
|
|
342
|
+
name: "Sign in with your app",
|
|
343
|
+
});
|
|
344
|
+
expect((signIn as HTMLButtonElement).disabled).toBe(false);
|
|
345
|
+
expect(screen.getByText("Using your OAuth app")).toBeTruthy();
|
|
346
|
+
// The blocked banner and BYOA offer describe the platform app —
|
|
347
|
+
// both retire while the override is active.
|
|
348
|
+
expect(screen.queryByText(/awaiting vendor approval/)).toBeNull();
|
|
349
|
+
expect(
|
|
350
|
+
screen.queryByRole("button", { name: "Use your own OAuth app" }),
|
|
351
|
+
).toBeNull();
|
|
352
|
+
});
|
|
255
353
|
});
|
|
256
354
|
|
|
257
355
|
// ---------------------------------------------------------------------------
|