@stigmer/react 3.1.3 → 3.1.4
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/composer/SessionComposer.d.ts +31 -0
- package/composer/SessionComposer.d.ts.map +1 -1
- package/composer/SessionComposer.js +12 -4
- package/composer/SessionComposer.js.map +1 -1
- package/execution/ArtifactApplyButton.d.ts +25 -0
- package/execution/ArtifactApplyButton.d.ts.map +1 -0
- package/execution/ArtifactApplyButton.js +21 -0
- package/execution/ArtifactApplyButton.js.map +1 -0
- package/execution/ArtifactContentBody.d.ts +36 -0
- package/execution/ArtifactContentBody.d.ts.map +1 -0
- package/execution/ArtifactContentBody.js +62 -0
- package/execution/ArtifactContentBody.js.map +1 -0
- package/execution/ArtifactDocument.d.ts +48 -0
- package/execution/ArtifactDocument.d.ts.map +1 -0
- package/execution/ArtifactDocument.js +89 -0
- package/execution/ArtifactDocument.js.map +1 -0
- package/execution/ArtifactPreviewModal.d.ts +4 -4
- package/execution/ArtifactPreviewModal.d.ts.map +1 -1
- package/execution/ArtifactPreviewModal.js +15 -142
- package/execution/ArtifactPreviewModal.js.map +1 -1
- package/execution/ArtifactRow.d.ts +49 -0
- package/execution/ArtifactRow.d.ts.map +1 -0
- package/execution/ArtifactRow.js +56 -0
- package/execution/ArtifactRow.js.map +1 -0
- package/execution/ArtifactsWidget.d.ts +6 -9
- package/execution/ArtifactsWidget.d.ts.map +1 -1
- package/execution/ArtifactsWidget.js +15 -19
- package/execution/ArtifactsWidget.js.map +1 -1
- package/execution/index.d.ts +8 -2
- package/execution/index.d.ts.map +1 -1
- package/execution/index.js +4 -1
- package/execution/index.js.map +1 -1
- package/execution/useArtifactContent.d.ts +6 -1
- package/execution/useArtifactContent.d.ts.map +1 -1
- package/execution/useArtifactContent.js +7 -2
- package/execution/useArtifactContent.js.map +1 -1
- package/execution/useArtifactInspection.d.ts +85 -0
- package/execution/useArtifactInspection.d.ts.map +1 -0
- package/execution/useArtifactInspection.js +143 -0
- package/execution/useArtifactInspection.js.map +1 -0
- package/execution/useCreateAgentExecution.d.ts +11 -0
- package/execution/useCreateAgentExecution.d.ts.map +1 -1
- package/execution/useCreateAgentExecution.js +1 -0
- package/execution/useCreateAgentExecution.js.map +1 -1
- package/index.d.ts +3 -3
- package/index.d.ts.map +1 -1
- package/index.js +2 -2
- package/index.js.map +1 -1
- package/internal/MermaidDiagram.d.ts +47 -0
- package/internal/MermaidDiagram.d.ts.map +1 -0
- package/internal/MermaidDiagram.js +118 -0
- package/internal/MermaidDiagram.js.map +1 -0
- package/internal/markdown-components.d.ts.map +1 -1
- package/internal/markdown-components.js +34 -0
- package/internal/markdown-components.js.map +1 -1
- package/internal/mermaid-loader.d.ts +26 -0
- package/internal/mermaid-loader.d.ts.map +1 -0
- package/internal/mermaid-loader.js +34 -0
- package/internal/mermaid-loader.js.map +1 -0
- package/internal/mermaid-theme-css.d.ts +41 -0
- package/internal/mermaid-theme-css.d.ts.map +1 -0
- package/internal/mermaid-theme-css.js +179 -0
- package/internal/mermaid-theme-css.js.map +1 -0
- package/internal/slug.d.ts +9 -5
- package/internal/slug.d.ts.map +1 -1
- package/internal/slug.js +10 -6
- package/internal/slug.js.map +1 -1
- package/package.json +5 -4
- package/session/SessionViewer.d.ts.map +1 -1
- package/session/SessionViewer.js +91 -18
- package/session/SessionViewer.js.map +1 -1
- package/session/artifact-document.d.ts +13 -0
- package/session/artifact-document.d.ts.map +1 -0
- package/session/artifact-document.js +22 -0
- package/session/artifact-document.js.map +1 -0
- package/session/facets/ArtifactsTab.d.ts +30 -4
- package/session/facets/ArtifactsTab.d.ts.map +1 -1
- package/session/facets/ArtifactsTab.js +32 -10
- package/session/facets/ArtifactsTab.js.map +1 -1
- package/session/index.d.ts +2 -1
- package/session/index.d.ts.map +1 -1
- package/session/index.js +4 -1
- package/session/index.js.map +1 -1
- package/session/useSessionArtifacts.d.ts +17 -0
- package/session/useSessionArtifacts.d.ts.map +1 -1
- package/session/useSessionArtifacts.js +16 -5
- package/session/useSessionArtifacts.js.map +1 -1
- package/session/useSessionConversation.d.ts +17 -1
- package/session/useSessionConversation.d.ts.map +1 -1
- package/session/useSessionConversation.js +32 -4
- package/session/useSessionConversation.js.map +1 -1
- package/session/useSessionPageFlow.d.ts.map +1 -1
- package/session/useSessionPageFlow.js +1 -0
- package/session/useSessionPageFlow.js.map +1 -1
- package/session/useSessionPanel.d.ts +20 -0
- package/session/useSessionPanel.d.ts.map +1 -1
- package/session/useSessionPanel.js +13 -0
- package/session/useSessionPanel.js.map +1 -1
- package/session/useSessionRailViews.d.ts +13 -1
- package/session/useSessionRailViews.d.ts.map +1 -1
- package/session/useSessionRailViews.js +5 -3
- package/session/useSessionRailViews.js.map +1 -1
- package/src/composer/SessionComposer.tsx +69 -1
- package/src/composer/__tests__/SessionComposer-editing.test.tsx +128 -0
- package/src/execution/ArtifactApplyButton.tsx +79 -0
- package/src/execution/ArtifactContentBody.tsx +255 -0
- package/src/execution/ArtifactDocument.tsx +344 -0
- package/src/execution/ArtifactPreviewModal.tsx +39 -405
- package/src/execution/ArtifactRow.tsx +165 -0
- package/src/execution/ArtifactsWidget.tsx +24 -33
- package/src/execution/__tests__/ArtifactContentBody.test.tsx +131 -0
- package/src/execution/__tests__/ArtifactDocument.test.tsx +100 -0
- package/src/execution/__tests__/ArtifactRow.test.tsx +139 -0
- package/src/execution/__tests__/ArtifactsWidget.test.tsx +78 -0
- package/src/execution/__tests__/message-entry.test.tsx +50 -2
- package/src/execution/__tests__/useArtifactInspection.test.tsx +151 -0
- package/src/execution/__tests__/useCreateAgentExecution.test.tsx +35 -0
- package/src/execution/index.ts +14 -2
- package/src/execution/useArtifactContent.ts +7 -0
- package/src/execution/useArtifactInspection.ts +252 -0
- package/src/execution/useCreateAgentExecution.ts +12 -0
- package/src/index.ts +11 -2
- package/src/internal/MermaidDiagram.tsx +164 -0
- package/src/internal/__tests__/a11y/mermaid-theme.a11y.test.tsx +122 -0
- package/src/internal/__tests__/markdown-components.test.tsx +93 -1
- package/src/internal/__tests__/mermaid-diagram.test.tsx +282 -0
- package/src/internal/markdown-components.tsx +36 -1
- package/src/internal/mermaid-loader.ts +44 -0
- package/src/internal/mermaid-theme-css.ts +178 -0
- package/src/internal/slug.ts +10 -6
- package/src/session/SessionViewer.tsx +177 -33
- package/src/session/__tests__/SessionViewer-artifactTabs.test.tsx +210 -0
- package/src/session/__tests__/SessionViewer-editResubmit.test.tsx +233 -0
- package/src/session/__tests__/useSessionArtifacts.test.ts +57 -0
- package/src/session/__tests__/useSessionConversation.test.tsx +172 -1
- package/src/session/__tests__/useSessionPanel.test.ts +70 -1
- package/src/session/artifact-document.ts +23 -0
- package/src/session/facets/ArtifactsTab.tsx +66 -18
- package/src/session/facets/__tests__/ArtifactsTab.test.tsx +111 -47
- package/src/session/index.ts +5 -1
- package/src/session/useSessionArtifacts.ts +16 -5
- package/src/session/useSessionConversation.ts +48 -6
- package/src/session/useSessionPageFlow.ts +1 -0
- package/src/session/useSessionPanel.ts +41 -0
- package/src/session/useSessionRailViews.tsx +21 -1
- package/styles.css +1 -1
- package/execution/ArtifactCard.d.ts +0 -81
- package/execution/ArtifactCard.d.ts.map +0 -1
- package/execution/ArtifactCard.js +0 -130
- package/execution/ArtifactCard.js.map +0 -1
- package/src/execution/ArtifactCard.tsx +0 -320
|
@@ -3,6 +3,8 @@ import { useCallback, useEffect, useMemo, useRef, useState } from "react";
|
|
|
3
3
|
import { isTerminalPhase } from "../execution/execution-phases.js";
|
|
4
4
|
import { useWorkspaceEditorsStoreRef, } from "../internal/store/index.js";
|
|
5
5
|
import { PLAN_DOCUMENT_ENTRY_ID, PLAN_DOCUMENT_PATH } from "./plan-document.js";
|
|
6
|
+
import { ARTIFACT_DOCUMENT_ENTRY_ID } from "./artifact-document.js";
|
|
7
|
+
import { artifactKey } from "./useSessionArtifacts.js";
|
|
6
8
|
/**
|
|
7
9
|
* Create a {@link SessionPanelController} for a viewer instance.
|
|
8
10
|
*/
|
|
@@ -81,6 +83,13 @@ export function useSessionPanel({ phase, hasChanges, planKey = null, defaultView
|
|
|
81
83
|
editorsStore.openPreview(entryId, path, options);
|
|
82
84
|
setIsOpen(true);
|
|
83
85
|
}, [editorsStore]);
|
|
86
|
+
const openArtifact = useCallback((artifact) => {
|
|
87
|
+
editorsStore.openPreview(ARTIFACT_DOCUMENT_ENTRY_ID, artifactKey(artifact));
|
|
88
|
+
setIsOpen(true);
|
|
89
|
+
}, [editorsStore]);
|
|
90
|
+
const pinArtifact = useCallback((artifact) => {
|
|
91
|
+
editorsStore.pin(ARTIFACT_DOCUMENT_ENTRY_ID, artifactKey(artifact));
|
|
92
|
+
}, [editorsStore]);
|
|
84
93
|
const activateEditor = useCallback((entryId, path) => editorsStore.activate(entryId, path), [editorsStore]);
|
|
85
94
|
const pinEditor = useCallback((entryId, path) => editorsStore.pin(entryId, path), [editorsStore]);
|
|
86
95
|
const closeEditor = useCallback((entryId, path) => editorsStore.close(entryId, path), [editorsStore]);
|
|
@@ -111,6 +120,8 @@ export function useSessionPanel({ phase, hasChanges, planKey = null, defaultView
|
|
|
111
120
|
pinEditor,
|
|
112
121
|
closeEditor,
|
|
113
122
|
openPlanDocument,
|
|
123
|
+
openArtifact,
|
|
124
|
+
pinArtifact,
|
|
114
125
|
notifySelection,
|
|
115
126
|
}), [
|
|
116
127
|
editorsStore,
|
|
@@ -124,6 +135,8 @@ export function useSessionPanel({ phase, hasChanges, planKey = null, defaultView
|
|
|
124
135
|
pinEditor,
|
|
125
136
|
closeEditor,
|
|
126
137
|
openPlanDocument,
|
|
138
|
+
openArtifact,
|
|
139
|
+
pinArtifact,
|
|
127
140
|
notifySelection,
|
|
128
141
|
]);
|
|
129
142
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useSessionPanel.js","sourceRoot":"","sources":["../../src/session/useSessionPanel.ts"],"names":[],"mappings":"AAAA,YAAY,CAAC;AAEb,OAAO,EAAE,WAAW,EAAE,SAAS,EAAE,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,OAAO,CAAC;
|
|
1
|
+
{"version":3,"file":"useSessionPanel.js","sourceRoot":"","sources":["../../src/session/useSessionPanel.ts"],"names":[],"mappings":"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"}
|
|
@@ -2,6 +2,7 @@ import type { AgentExecution } from "@stigmer/protos/ai/stigmer/agentic/agentexe
|
|
|
2
2
|
import type { SurfaceRailView } from "../workspace/WorkspaceSurface.js";
|
|
3
3
|
import type { SelectedThreadItem } from "../internal/store/selection-store.js";
|
|
4
4
|
import type { ApplyResourceResult } from "../library/useApplyResource.js";
|
|
5
|
+
import { type SessionArtifactEntry } from "./useSessionArtifacts.js";
|
|
5
6
|
import { type SetupTabProps } from "./facets/SetupTab.js";
|
|
6
7
|
/** Options for {@link useSessionRailViews}. */
|
|
7
8
|
export interface UseSessionRailViewsOptions {
|
|
@@ -23,6 +24,17 @@ export interface UseSessionRailViewsOptions {
|
|
|
23
24
|
* of the preview modal.
|
|
24
25
|
*/
|
|
25
26
|
readonly onOpenPlan?: (executionId: string) => void;
|
|
27
|
+
/**
|
|
28
|
+
* Open a (non-plan) artifact as an editor-pane document tab. Routed to the
|
|
29
|
+
* Artifacts facet so clicking an artifact opens it in the editor area (VS
|
|
30
|
+
* Code "each file is a tab") instead of the preview modal.
|
|
31
|
+
*/
|
|
32
|
+
readonly onOpenArtifact?: (entry: SessionArtifactEntry) => void;
|
|
33
|
+
/**
|
|
34
|
+
* Pin a (non-plan) artifact's document tab — the double-click half of the
|
|
35
|
+
* Artifacts facet's open/activate split. Routed through to the facet's rows.
|
|
36
|
+
*/
|
|
37
|
+
readonly onActivateArtifact?: (entry: SessionArtifactEntry) => void;
|
|
26
38
|
/**
|
|
27
39
|
* Whether to offer the execution-derived facets (Changes / Artifacts /
|
|
28
40
|
* Usage). The launcher passes `false` — before a session exists there are no
|
|
@@ -41,5 +53,5 @@ export interface UseSessionRailViewsOptions {
|
|
|
41
53
|
* tab rules — Changes/Artifacts surface only when data exists (with count
|
|
42
54
|
* badges), Inspect only when a thread item is selected.
|
|
43
55
|
*/
|
|
44
|
-
export declare function useSessionRailViews({ allExecutions, org, sessionConfig, selectedItem, onApplied, onImplementPlan, onOpenPlan, includeExecutionFacets, }: UseSessionRailViewsOptions): readonly SurfaceRailView[];
|
|
56
|
+
export declare function useSessionRailViews({ allExecutions, org, sessionConfig, selectedItem, onApplied, onImplementPlan, onOpenPlan, onOpenArtifact, onActivateArtifact, includeExecutionFacets, }: UseSessionRailViewsOptions): readonly SurfaceRailView[];
|
|
45
57
|
//# sourceMappingURL=useSessionRailViews.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useSessionRailViews.d.ts","sourceRoot":"","sources":["../../src/session/useSessionRailViews.tsx"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,6DAA6D,CAAC;AAClG,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,kCAAkC,CAAC;AACxE,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,sCAAsC,CAAC;AAC/E,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,gCAAgC,CAAC;
|
|
1
|
+
{"version":3,"file":"useSessionRailViews.d.ts","sourceRoot":"","sources":["../../src/session/useSessionRailViews.tsx"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,6DAA6D,CAAC;AAClG,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,kCAAkC,CAAC;AACxE,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,sCAAsC,CAAC;AAC/E,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,gCAAgC,CAAC;AAE1E,OAAO,EAEL,KAAK,oBAAoB,EAC1B,MAAM,0BAA0B,CAAC;AAClC,OAAO,EAAY,KAAK,aAAa,EAAE,MAAM,sBAAsB,CAAC;AAMpE,+CAA+C;AAC/C,MAAM,WAAW,0BAA0B;IACzC,sEAAsE;IACtE,QAAQ,CAAC,aAAa,EAAE,SAAS,cAAc,EAAE,CAAC;IAClD,gDAAgD;IAChD,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IACrB,kDAAkD;IAClD,QAAQ,CAAC,aAAa,EAAE,aAAa,GAAG,SAAS,CAAC;IAClD,mEAAmE;IACnE,QAAQ,CAAC,YAAY,EAAE,kBAAkB,GAAG,IAAI,CAAC;IACjD,mEAAmE;IACnE,QAAQ,CAAC,SAAS,CAAC,EAAE,CAAC,MAAM,EAAE,mBAAmB,KAAK,IAAI,CAAC;IAC3D,6EAA6E;IAC7E,QAAQ,CAAC,eAAe,CAAC,EAAE,MAAM,IAAI,CAAC;IACtC;;;;OAIG;IACH,QAAQ,CAAC,UAAU,CAAC,EAAE,CAAC,WAAW,EAAE,MAAM,KAAK,IAAI,CAAC;IACpD;;;;OAIG;IACH,QAAQ,CAAC,cAAc,CAAC,EAAE,CAAC,KAAK,EAAE,oBAAoB,KAAK,IAAI,CAAC;IAChE;;;OAGG;IACH,QAAQ,CAAC,kBAAkB,CAAC,EAAE,CAAC,KAAK,EAAE,oBAAoB,KAAK,IAAI,CAAC;IACpE;;;;;OAKG;IACH,QAAQ,CAAC,sBAAsB,CAAC,EAAE,OAAO,CAAC;CAC3C;AAED;;;;;;;;;GASG;AACH,wBAAgB,mBAAmB,CAAC,EAClC,aAAa,EACb,GAAG,EACH,aAAa,EACb,YAAY,EACZ,SAAS,EACT,eAAe,EACf,UAAU,EACV,cAAc,EACd,kBAAkB,EAClB,sBAA6B,GAC9B,EAAE,0BAA0B,GAAG,SAAS,eAAe,EAAE,CAiFzD"}
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
3
|
import { useMemo } from "react";
|
|
4
4
|
import { useSessionWriteBacks } from "./useSessionWriteBacks.js";
|
|
5
|
-
import { useSessionArtifacts } from "./useSessionArtifacts.js";
|
|
5
|
+
import { useSessionArtifacts, } from "./useSessionArtifacts.js";
|
|
6
6
|
import { SetupTab } from "./facets/SetupTab.js";
|
|
7
7
|
import { ChangesTab } from "./facets/ChangesTab.js";
|
|
8
8
|
import { ArtifactsTab } from "./facets/ArtifactsTab.js";
|
|
@@ -18,7 +18,7 @@ import { InspectTab } from "./facets/InspectTab.js";
|
|
|
18
18
|
* tab rules — Changes/Artifacts surface only when data exists (with count
|
|
19
19
|
* badges), Inspect only when a thread item is selected.
|
|
20
20
|
*/
|
|
21
|
-
export function useSessionRailViews({ allExecutions, org, sessionConfig, selectedItem, onApplied, onImplementPlan, onOpenPlan, includeExecutionFacets = true, }) {
|
|
21
|
+
export function useSessionRailViews({ allExecutions, org, sessionConfig, selectedItem, onApplied, onImplementPlan, onOpenPlan, onOpenArtifact, onActivateArtifact, includeExecutionFacets = true, }) {
|
|
22
22
|
const { hasWriteBacks, writeBackCount } = useSessionWriteBacks(allExecutions);
|
|
23
23
|
const { hasArtifacts, artifactCount } = useSessionArtifacts(allExecutions);
|
|
24
24
|
return useMemo(() => {
|
|
@@ -47,7 +47,7 @@ export function useSessionRailViews({ allExecutions, org, sessionConfig, selecte
|
|
|
47
47
|
label: "Artifacts",
|
|
48
48
|
icon: _jsx(ArtifactsIcon, {}),
|
|
49
49
|
badge: artifactCount,
|
|
50
|
-
content: (_jsx(ArtifactsTab, { executions: allExecutions, org: org, onApplied: onApplied, onImplementPlan: onImplementPlan, onOpenPlan: onOpenPlan })),
|
|
50
|
+
content: (_jsx(ArtifactsTab, { executions: allExecutions, org: org, onApplied: onApplied, onImplementPlan: onImplementPlan, onOpenPlan: onOpenPlan, onOpenArtifact: onOpenArtifact, onActivateArtifact: onActivateArtifact })),
|
|
51
51
|
});
|
|
52
52
|
}
|
|
53
53
|
views.push({
|
|
@@ -78,6 +78,8 @@ export function useSessionRailViews({ allExecutions, org, sessionConfig, selecte
|
|
|
78
78
|
onApplied,
|
|
79
79
|
onImplementPlan,
|
|
80
80
|
onOpenPlan,
|
|
81
|
+
onOpenArtifact,
|
|
82
|
+
onActivateArtifact,
|
|
81
83
|
selectedItem,
|
|
82
84
|
]);
|
|
83
85
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useSessionRailViews.js","sourceRoot":"","sources":["../../src/session/useSessionRailViews.tsx"],"names":[],"mappings":"AAAA,YAAY,CAAC;;AAEb,OAAO,EAAE,OAAO,EAAE,MAAM,OAAO,CAAC;AAKhC,OAAO,EAAE,oBAAoB,EAAE,MAAM,2BAA2B,CAAC;AACjE,OAAO,
|
|
1
|
+
{"version":3,"file":"useSessionRailViews.js","sourceRoot":"","sources":["../../src/session/useSessionRailViews.tsx"],"names":[],"mappings":"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"}
|
|
@@ -42,6 +42,7 @@ import {
|
|
|
42
42
|
SecretsIcon,
|
|
43
43
|
AlertTriangleIcon,
|
|
44
44
|
ResolveSpinner,
|
|
45
|
+
XIcon,
|
|
45
46
|
} from "./icons.js";
|
|
46
47
|
|
|
47
48
|
/**
|
|
@@ -168,6 +169,18 @@ export interface SessionComposerSubmitContext {
|
|
|
168
169
|
* `undefined` for ordinary submissions.
|
|
169
170
|
*/
|
|
170
171
|
readonly buildFromPlan?: boolean;
|
|
172
|
+
/**
|
|
173
|
+
* ID of the execution this submission supersedes (edit-and-resubmit).
|
|
174
|
+
*
|
|
175
|
+
* Never set by the composer itself — the session viewer merges it into
|
|
176
|
+
* the context when the user submits while the composer is in editing
|
|
177
|
+
* mode (see `SessionComposerProps.isEditing`). Pass to execution
|
|
178
|
+
* creation as `supersedesExecutionId`; chat threads hide the superseded
|
|
179
|
+
* execution so the edited message replaces the original in place.
|
|
180
|
+
*
|
|
181
|
+
* `undefined` for ordinary submissions.
|
|
182
|
+
*/
|
|
183
|
+
readonly supersedesExecutionId?: string;
|
|
171
184
|
}
|
|
172
185
|
|
|
173
186
|
/** Props for {@link SessionComposer}. */
|
|
@@ -202,6 +215,26 @@ export interface SessionComposerProps {
|
|
|
202
215
|
/** `true` while a stop request is in flight — shows a spinner on the Stop button. */
|
|
203
216
|
readonly isStopping?: boolean;
|
|
204
217
|
|
|
218
|
+
/**
|
|
219
|
+
* Marks the composer as editing a previously sent message
|
|
220
|
+
* (edit-and-resubmit). Renders an "Editing message" banner above the
|
|
221
|
+
* textarea with a cancel (X) affordance; Escape in the textarea also
|
|
222
|
+
* cancels. The banner is purely presentational — the viewer owns the
|
|
223
|
+
* editing state and attaches the supersede link on submit.
|
|
224
|
+
*
|
|
225
|
+
* Opt-in: when omitted, the composer behaves exactly as before.
|
|
226
|
+
*/
|
|
227
|
+
readonly isEditing?: boolean;
|
|
228
|
+
/**
|
|
229
|
+
* Called when the user cancels editing (banner X or Escape).
|
|
230
|
+
*
|
|
231
|
+
* The consumer clears its editing state and typically clears the
|
|
232
|
+
* prefilled text via {@link SessionComposerHandle.setMessage}.
|
|
233
|
+
* Required for the editing banner to render its cancel affordance;
|
|
234
|
+
* ignored when `isEditing` is false.
|
|
235
|
+
*/
|
|
236
|
+
readonly onCancelEdit?: () => void;
|
|
237
|
+
|
|
205
238
|
/**
|
|
206
239
|
* Currently selected execution harness.
|
|
207
240
|
*
|
|
@@ -531,6 +564,8 @@ const SessionComposerInner = forwardRef<SessionComposerHandle, SessionComposerPr
|
|
|
531
564
|
disabled = false,
|
|
532
565
|
onStop,
|
|
533
566
|
isStopping = false,
|
|
567
|
+
isEditing = false,
|
|
568
|
+
onCancelEdit,
|
|
534
569
|
harness,
|
|
535
570
|
onHarnessChange,
|
|
536
571
|
showHarnessSelector = false,
|
|
@@ -1139,13 +1174,21 @@ const SessionComposerInner = forwardRef<SessionComposerHandle, SessionComposerPr
|
|
|
1139
1174
|
|
|
1140
1175
|
const handleTextareaKeyDown = useCallback(
|
|
1141
1176
|
(e: KeyboardEvent<HTMLTextAreaElement>) => {
|
|
1177
|
+
// Escape exits edit-and-resubmit mode — same reflex as dismissing a
|
|
1178
|
+
// popover. Only intercepted while editing so it never shadows other
|
|
1179
|
+
// Escape behaviors (e.g. closing an open picker above the textarea).
|
|
1180
|
+
if (isEditing && onCancelEdit && e.key === "Escape") {
|
|
1181
|
+
e.preventDefault();
|
|
1182
|
+
onCancelEdit();
|
|
1183
|
+
return;
|
|
1184
|
+
}
|
|
1142
1185
|
if (!canSend && e.key === "Enter" && !e.shiftKey) {
|
|
1143
1186
|
e.preventDefault();
|
|
1144
1187
|
return;
|
|
1145
1188
|
}
|
|
1146
1189
|
composer.textareaProps.onKeyDown(e);
|
|
1147
1190
|
},
|
|
1148
|
-
[canSend, composer.textareaProps],
|
|
1191
|
+
[canSend, composer.textareaProps, isEditing, onCancelEdit],
|
|
1149
1192
|
);
|
|
1150
1193
|
|
|
1151
1194
|
const workspaceCount = workspace?.entries.length ?? 0;
|
|
@@ -1393,6 +1436,31 @@ const SessionComposerInner = forwardRef<SessionComposerHandle, SessionComposerPr
|
|
|
1393
1436
|
onDragLeave={handleDragLeave}
|
|
1394
1437
|
onDrop={handleDrop}
|
|
1395
1438
|
>
|
|
1439
|
+
{/* Zone 0.5: Edit-and-resubmit banner. Rendered inside the card so the
|
|
1440
|
+
editing state visually owns the text below it — the user reads
|
|
1441
|
+
"Editing message" and the prefilled prompt as one unit. */}
|
|
1442
|
+
{isEditing && (
|
|
1443
|
+
<div
|
|
1444
|
+
role="status"
|
|
1445
|
+
className="flex items-center justify-between gap-2 rounded-t-xl border-b border-border bg-muted px-3 py-1.5"
|
|
1446
|
+
>
|
|
1447
|
+
<span className="text-xs font-medium text-muted-foreground">
|
|
1448
|
+
Editing message
|
|
1449
|
+
</span>
|
|
1450
|
+
{onCancelEdit && (
|
|
1451
|
+
<button
|
|
1452
|
+
type="button"
|
|
1453
|
+
onClick={onCancelEdit}
|
|
1454
|
+
aria-label="Cancel editing"
|
|
1455
|
+
title="Cancel editing (Esc)"
|
|
1456
|
+
className="rounded p-0.5 text-muted-foreground transition-colors hover:bg-accent hover:text-foreground focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring"
|
|
1457
|
+
>
|
|
1458
|
+
<XIcon />
|
|
1459
|
+
</button>
|
|
1460
|
+
)}
|
|
1461
|
+
</div>
|
|
1462
|
+
)}
|
|
1463
|
+
|
|
1396
1464
|
{/* Zone 1: Textarea */}
|
|
1397
1465
|
<div className="relative">
|
|
1398
1466
|
<textarea
|
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
import { describe, it, expect, vi, afterEach } from "vitest";
|
|
2
|
+
import { render, screen, cleanup, fireEvent, waitFor } from "@testing-library/react";
|
|
3
|
+
import type { ReactNode } from "react";
|
|
4
|
+
import type { Stigmer } from "@stigmer/sdk";
|
|
5
|
+
import { StigmerContext } from "../../context";
|
|
6
|
+
import { ModelRegistryContext } from "../../models/ModelRegistryContext";
|
|
7
|
+
import { SessionComposer } from "../SessionComposer";
|
|
8
|
+
|
|
9
|
+
// ---------------------------------------------------------------------------
|
|
10
|
+
// Helpers
|
|
11
|
+
// ---------------------------------------------------------------------------
|
|
12
|
+
|
|
13
|
+
function createMinimalStigmerMock(): Stigmer {
|
|
14
|
+
return {
|
|
15
|
+
agentExecution: { uploadAttachment: vi.fn() },
|
|
16
|
+
environment: { getPersonal: vi.fn().mockResolvedValue(null) },
|
|
17
|
+
baseUrl: "http://localhost:8080",
|
|
18
|
+
getAuthCredential: vi.fn().mockResolvedValue("test-token"),
|
|
19
|
+
config: {
|
|
20
|
+
baseUrl: "http://localhost:8080",
|
|
21
|
+
getAccessToken: vi.fn().mockResolvedValue(""),
|
|
22
|
+
},
|
|
23
|
+
} as unknown as Stigmer;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
function createWrapper(client: Stigmer) {
|
|
27
|
+
return function Wrapper({ children }: { children: ReactNode }) {
|
|
28
|
+
return (
|
|
29
|
+
<StigmerContext.Provider value={client}>
|
|
30
|
+
<ModelRegistryContext.Provider
|
|
31
|
+
value={{ models: [], isLoading: false, error: null, refetch: vi.fn() }}
|
|
32
|
+
>
|
|
33
|
+
{children}
|
|
34
|
+
</ModelRegistryContext.Provider>
|
|
35
|
+
</StigmerContext.Provider>
|
|
36
|
+
);
|
|
37
|
+
};
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
function renderComposer(
|
|
41
|
+
props?: Partial<React.ComponentProps<typeof SessionComposer>>,
|
|
42
|
+
) {
|
|
43
|
+
const client = createMinimalStigmerMock();
|
|
44
|
+
const onSubmit = vi.fn();
|
|
45
|
+
const result = render(
|
|
46
|
+
<SessionComposer onSubmit={onSubmit} {...props} />,
|
|
47
|
+
{ wrapper: createWrapper(client) },
|
|
48
|
+
);
|
|
49
|
+
return { ...result, onSubmit, client };
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
function getTextarea(): HTMLTextAreaElement {
|
|
53
|
+
return document.querySelector("textarea") as HTMLTextAreaElement;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
afterEach(cleanup);
|
|
57
|
+
|
|
58
|
+
// ---------------------------------------------------------------------------
|
|
59
|
+
// Tests
|
|
60
|
+
// ---------------------------------------------------------------------------
|
|
61
|
+
|
|
62
|
+
describe("SessionComposer — editing mode (edit-and-resubmit)", () => {
|
|
63
|
+
it("renders no editing banner by default (backward compatible)", () => {
|
|
64
|
+
renderComposer();
|
|
65
|
+
|
|
66
|
+
expect(screen.queryByText("Editing message")).toBeNull();
|
|
67
|
+
expect(
|
|
68
|
+
screen.queryByRole("button", { name: "Cancel editing" }),
|
|
69
|
+
).toBeNull();
|
|
70
|
+
});
|
|
71
|
+
|
|
72
|
+
it("renders the editing banner with a cancel affordance while isEditing", () => {
|
|
73
|
+
renderComposer({ isEditing: true, onCancelEdit: vi.fn() });
|
|
74
|
+
|
|
75
|
+
expect(screen.getByText("Editing message")).toBeTruthy();
|
|
76
|
+
expect(
|
|
77
|
+
screen.getByRole("button", { name: "Cancel editing" }),
|
|
78
|
+
).toBeTruthy();
|
|
79
|
+
});
|
|
80
|
+
|
|
81
|
+
it("clicking the banner X calls onCancelEdit", () => {
|
|
82
|
+
const onCancelEdit = vi.fn();
|
|
83
|
+
renderComposer({ isEditing: true, onCancelEdit });
|
|
84
|
+
|
|
85
|
+
fireEvent.click(screen.getByRole("button", { name: "Cancel editing" }));
|
|
86
|
+
expect(onCancelEdit).toHaveBeenCalledTimes(1);
|
|
87
|
+
});
|
|
88
|
+
|
|
89
|
+
it("Escape in the textarea calls onCancelEdit while editing", () => {
|
|
90
|
+
const onCancelEdit = vi.fn();
|
|
91
|
+
renderComposer({ isEditing: true, onCancelEdit });
|
|
92
|
+
|
|
93
|
+
fireEvent.keyDown(getTextarea(), { key: "Escape" });
|
|
94
|
+
expect(onCancelEdit).toHaveBeenCalledTimes(1);
|
|
95
|
+
});
|
|
96
|
+
|
|
97
|
+
it("Escape does nothing when not editing", () => {
|
|
98
|
+
const onCancelEdit = vi.fn();
|
|
99
|
+
renderComposer({ isEditing: false, onCancelEdit });
|
|
100
|
+
|
|
101
|
+
fireEvent.keyDown(getTextarea(), { key: "Escape" });
|
|
102
|
+
expect(onCancelEdit).not.toHaveBeenCalled();
|
|
103
|
+
});
|
|
104
|
+
|
|
105
|
+
it("Enter still submits while editing — cancel is Escape-only", async () => {
|
|
106
|
+
const onCancelEdit = vi.fn();
|
|
107
|
+
const { onSubmit } = renderComposer({ isEditing: true, onCancelEdit });
|
|
108
|
+
|
|
109
|
+
const textarea = getTextarea();
|
|
110
|
+
fireEvent.change(textarea, { target: { value: "corrected message" } });
|
|
111
|
+
fireEvent.keyDown(textarea, { key: "Enter", shiftKey: false });
|
|
112
|
+
|
|
113
|
+
await waitFor(() => {
|
|
114
|
+
expect(onSubmit).toHaveBeenCalledTimes(1);
|
|
115
|
+
});
|
|
116
|
+
expect(onSubmit.mock.calls[0][0]).toBe("corrected message");
|
|
117
|
+
expect(onCancelEdit).not.toHaveBeenCalled();
|
|
118
|
+
});
|
|
119
|
+
|
|
120
|
+
it("renders the banner without a cancel button when onCancelEdit is omitted", () => {
|
|
121
|
+
renderComposer({ isEditing: true });
|
|
122
|
+
|
|
123
|
+
expect(screen.getByText("Editing message")).toBeTruthy();
|
|
124
|
+
expect(
|
|
125
|
+
screen.queryByRole("button", { name: "Cancel editing" }),
|
|
126
|
+
).toBeNull();
|
|
127
|
+
});
|
|
128
|
+
});
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
|
|
3
|
+
import { cn } from "@stigmer/theme";
|
|
4
|
+
|
|
5
|
+
/** Props for {@link ArtifactApplyButton}. */
|
|
6
|
+
export interface ArtifactApplyButtonProps {
|
|
7
|
+
/** CTA label (`"Apply to org"` / `"Push Skill to org"`). */
|
|
8
|
+
readonly label: string;
|
|
9
|
+
/**
|
|
10
|
+
* Whether the producing execution is terminal. The apply/push action is only
|
|
11
|
+
* enabled once the execution has finished; a mid-run artifact renders the
|
|
12
|
+
* button disabled (its content may still change).
|
|
13
|
+
*/
|
|
14
|
+
readonly isTerminal: boolean;
|
|
15
|
+
/** `true` while the apply/push is in-flight. */
|
|
16
|
+
readonly isApplying: boolean;
|
|
17
|
+
/** Perform the apply/push. */
|
|
18
|
+
readonly onApply: () => void;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* The primary "Apply to [org]" / "Push Skill to [org]" action for a detected
|
|
23
|
+
* artifact resource, shared by every artifact chrome (the preview modal's
|
|
24
|
+
* action bar and the editor-area `ArtifactDocument` toolbar) so its
|
|
25
|
+
* terminal-gating, in-flight, and disabled states are single-source.
|
|
26
|
+
*
|
|
27
|
+
* All visual properties flow through `--stgm-*` tokens (DD-005).
|
|
28
|
+
*/
|
|
29
|
+
export function ArtifactApplyButton({
|
|
30
|
+
label,
|
|
31
|
+
isTerminal,
|
|
32
|
+
isApplying,
|
|
33
|
+
onApply,
|
|
34
|
+
}: ArtifactApplyButtonProps) {
|
|
35
|
+
const canApply = isTerminal && !isApplying;
|
|
36
|
+
|
|
37
|
+
return (
|
|
38
|
+
<button
|
|
39
|
+
type="button"
|
|
40
|
+
onClick={canApply ? onApply : undefined}
|
|
41
|
+
disabled={!canApply}
|
|
42
|
+
aria-busy={isApplying}
|
|
43
|
+
className={cn(
|
|
44
|
+
"rounded-md px-4 py-1.5 text-xs font-medium transition-colors",
|
|
45
|
+
"focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2",
|
|
46
|
+
"disabled:cursor-not-allowed",
|
|
47
|
+
canApply
|
|
48
|
+
? "bg-primary text-primary-foreground hover:bg-primary-hover"
|
|
49
|
+
: "bg-muted text-muted-foreground",
|
|
50
|
+
)}
|
|
51
|
+
>
|
|
52
|
+
{isApplying ? (
|
|
53
|
+
<span className="inline-flex items-center gap-1.5">
|
|
54
|
+
<SpinnerIcon />
|
|
55
|
+
Applying{"\u2026"}
|
|
56
|
+
</span>
|
|
57
|
+
) : (
|
|
58
|
+
label
|
|
59
|
+
)}
|
|
60
|
+
</button>
|
|
61
|
+
);
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
function SpinnerIcon() {
|
|
65
|
+
return (
|
|
66
|
+
<svg
|
|
67
|
+
width="12"
|
|
68
|
+
height="12"
|
|
69
|
+
viewBox="0 0 12 12"
|
|
70
|
+
fill="none"
|
|
71
|
+
stroke="currentColor"
|
|
72
|
+
strokeWidth="1.5"
|
|
73
|
+
className="shrink-0 animate-spin"
|
|
74
|
+
aria-hidden="true"
|
|
75
|
+
>
|
|
76
|
+
<path d="M6 1.5A4.5 4.5 0 1 1 1.5 6" strokeLinecap="round" />
|
|
77
|
+
</svg>
|
|
78
|
+
);
|
|
79
|
+
}
|