@parallelworks/ui 0.37.0 → 0.39.0
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/README.md +1 -1
- package/dist/ai/components/ChatInput.js +8 -23
- package/dist/ai/components/ChatSidebar.js +7 -4
- package/dist/ai/components/chatDraft.d.ts +7 -0
- package/dist/ai/components/chatDraft.js +66 -0
- package/dist/ai/index.d.ts +1 -1
- package/dist/ai/index.js +2 -2
- package/dist/ai/ui/sidebar.d.ts +6 -0
- package/dist/ai/ui/sidebar.js +15 -1
- package/dist/editing.d.ts +2 -0
- package/dist/editor/Monaco.js +1 -1
- package/dist/editor/index.js +1 -1
- package/dist/editor/lintContext.js +15 -3
- package/dist/form/FieldWrapper.js +1 -0
- package/dist/form/Form.js +64 -23
- package/dist/form/Wizard/WizardContainer.js +66 -6
- package/dist/form/Wizard/WizardStepContent.js +23 -10
- package/dist/form/Wizard/wizardPages.d.ts +12 -0
- package/dist/form/Wizard/wizardPages.js +5 -0
- package/dist/form/formEditing.d.ts +25 -0
- package/dist/form/formEditing.js +20 -0
- package/dist/graph/DependencyGraph.d.ts +8 -1
- package/dist/graph/DependencyGraph.js +433 -204
- package/dist/graph/GraphEditor.d.ts +27 -0
- package/dist/graph/GraphEditor.js +1543 -0
- package/dist/graph/GraphEditorDialogs.d.ts +87 -0
- package/dist/graph/GraphEditorDialogs.js +1808 -0
- package/dist/graph/InputDialog.js +1568 -54
- package/dist/graph/InputsEditor.d.ts +12 -0
- package/dist/graph/InputsEditor.js +1594 -0
- package/dist/graph/JobSummary.d.ts +3 -0
- package/dist/graph/JobSummary.js +34 -21
- package/dist/graph/MatrixGroup.d.ts +2 -1
- package/dist/graph/MatrixGroup.js +10 -3
- package/dist/graph/ShortcutsButton.js +56 -0
- package/dist/graph/SuggestionInput.js +29 -0
- package/dist/graph/WorkflowSettingsDialog.d.ts +21 -0
- package/dist/graph/WorkflowSettingsDialog.js +670 -0
- package/dist/graph/editorApi.js +8 -0
- package/dist/graph/editorChrome.js +75 -0
- package/dist/graph/editorFields.js +535 -0
- package/dist/graph/editorPrimitives.js +95 -4
- package/dist/graph/editorRows.d.ts +58 -0
- package/dist/graph/editorRows.js +460 -0
- package/dist/graph/editorStrings.d.ts +1 -0
- package/dist/graph/editorStrings.js +10 -1
- package/dist/graph/expressionRefs.js +39 -0
- package/dist/graph/fieldProblems.js +111 -0
- package/dist/graph/graphEditorState.d.ts +191 -0
- package/dist/graph/graphEditorState.js +74 -0
- package/dist/graph/index.d.ts +4 -0
- package/dist/graph/index.js +6 -2
- package/dist/graph/inputLayout.js +337 -0
- package/dist/graph/inputPages.d.ts +33 -0
- package/dist/graph/inputPages.js +186 -0
- package/dist/graph/inputRefs.js +388 -0
- package/dist/graph/inputRows.d.ts +43 -0
- package/dist/graph/inputRows.js +65 -0
- package/dist/graph/refusalText.js +13 -0
- package/dist/graph/settingsViews.js +62 -0
- package/dist/graph/stepWith.d.ts +38 -0
- package/dist/graph/stepWith.js +536 -0
- package/dist/styles.css +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -10,7 +10,7 @@ so an application ships only what it imports:
|
|
|
10
10
|
| `./icons` | the icon barrel |
|
|
11
11
|
| `./list` | list pages, tables, row menus and list controls |
|
|
12
12
|
| `./form` | `DynamicForm` and its field registry |
|
|
13
|
-
| `./graph` | job dependency graph and tree view |
|
|
13
|
+
| `./graph` | job dependency graph and tree view, and the visual workflow editor: the graph, the run form as an inputs editor, and their dialogs |
|
|
14
14
|
| `./editor` | Monaco editor (`monaco-editor` is an optional peer); YAML validation, completion and hover run in a bundled worker |
|
|
15
15
|
| `./logviewer` | log viewer with ANSI color and search |
|
|
16
16
|
| `./file-explorer` | object storage explorer over a host-supplied provider |
|
|
@@ -6,6 +6,7 @@ import { useChat } from "../core/ChatProvider.js";
|
|
|
6
6
|
import AttachmentUpload from "./AttachmentUpload.js";
|
|
7
7
|
import useDragDrop from "../core/useDragDrop.js";
|
|
8
8
|
import { ComposerContext, ComposerControls, ComposerSettings } from "./ComposerChrome.js";
|
|
9
|
+
import { clearDraft, readDraft, storeDraft, sweepDrafts } from "./chatDraft.js";
|
|
9
10
|
import DragOverlay from "./DragOverlay.js";
|
|
10
11
|
import { PasteFileCard } from "./PastedText.js";
|
|
11
12
|
import { SlashMenu, useSlashMenu } from "./SlashMenu.js";
|
|
@@ -14,29 +15,6 @@ import cx from "classnames";
|
|
|
14
15
|
import { forwardRef, useCallback, useEffect, useImperativeHandle, useRef, useState } from "react";
|
|
15
16
|
import { Fragment as Fragment$1, jsx, jsxs } from "react/jsx-runtime";
|
|
16
17
|
//#region src/ai/components/ChatInput.tsx
|
|
17
|
-
var DRAFT_STORAGE_PREFIX = "aiChatDraft:";
|
|
18
|
-
var DRAFT_MAX_LENGTH = 1e4;
|
|
19
|
-
function draftKey(conversationId) {
|
|
20
|
-
return `${DRAFT_STORAGE_PREFIX}${conversationId ?? "new"}`;
|
|
21
|
-
}
|
|
22
|
-
function readDraft(conversationId) {
|
|
23
|
-
try {
|
|
24
|
-
return window.localStorage.getItem(draftKey(conversationId)) ?? "";
|
|
25
|
-
} catch {
|
|
26
|
-
return "";
|
|
27
|
-
}
|
|
28
|
-
}
|
|
29
|
-
function storeDraft(conversationId, text) {
|
|
30
|
-
try {
|
|
31
|
-
if (!text || text.length > DRAFT_MAX_LENGTH) window.localStorage.removeItem(draftKey(conversationId));
|
|
32
|
-
else window.localStorage.setItem(draftKey(conversationId), text);
|
|
33
|
-
} catch {}
|
|
34
|
-
}
|
|
35
|
-
function clearDraft(conversationId) {
|
|
36
|
-
try {
|
|
37
|
-
window.localStorage.removeItem(draftKey(conversationId));
|
|
38
|
-
} catch {}
|
|
39
|
-
}
|
|
40
18
|
/** An optional box that is still empty should not wear the filled look of
|
|
41
19
|
* one waiting to send something. */
|
|
42
20
|
function sendability({ hasText, canFlushQueue, allowEmpty, disabled, modelReady, pendingCount }) {
|
|
@@ -88,8 +66,15 @@ function streamControls(chat, turn) {
|
|
|
88
66
|
queuedCount: chat.queuedMessages.length
|
|
89
67
|
};
|
|
90
68
|
}
|
|
69
|
+
var draftsSwept = false;
|
|
91
70
|
var ChatInput = forwardRef(function ChatInput({ onSend, disabled = false, placeholder, conversationId, onEditLastMessage, allowEmpty = false, attachments: attachmentsWanted = true, requireModel = true, inputLabel, sendLabel, sendTestId, slash, notices, activity, context, reserveContext = false, settingsLeft, settingsRight = /* @__PURE__ */ jsx(ComposerControls, {}), hint, turn, pastes }, ref) {
|
|
92
71
|
const [input, setInput] = useState(() => readDraft(conversationId));
|
|
72
|
+
useEffect(() => {
|
|
73
|
+
if (!draftsSwept) {
|
|
74
|
+
draftsSwept = true;
|
|
75
|
+
sweepDrafts();
|
|
76
|
+
}
|
|
77
|
+
}, []);
|
|
93
78
|
const { cards, handleTextPaste, removeCard, takeCards, blocking: pastesBlocking } = usePasteCards(pastes, input, (value) => {
|
|
94
79
|
setInput(value);
|
|
95
80
|
storeDraft(conversationId, value);
|
|
@@ -2,18 +2,19 @@ import { FaRegFileImage } from "../../icons/fa/FaRegFileImage.js";
|
|
|
2
2
|
import { FaSearch } from "../../icons/fa/FaSearch.js";
|
|
3
3
|
import { FaUsers } from "../../icons/fa/FaUsers.js";
|
|
4
4
|
import { TbEdit } from "../../icons/tb/TbEdit.js";
|
|
5
|
+
import { useRelativeTime } from "../../components/relativeTime.js";
|
|
5
6
|
import { useChatConfig } from "../core/config.js";
|
|
6
7
|
import { useChat } from "../core/ChatProvider.js";
|
|
7
8
|
import { ManageProvidersLink } from "./ComposerChrome.js";
|
|
8
9
|
import { FOCUS_SIDEBAR_SEARCH_EVENT } from "../core/events.js";
|
|
9
|
-
import { SidebarPlaceholder, SidebarRow } from "../ui/sidebar.js";
|
|
10
|
+
import { SidebarPlaceholder, SidebarRow, SidebarRowTitle } from "../ui/sidebar.js";
|
|
10
11
|
import { ConversationSidebar } from "../ui/ConversationSidebar.js";
|
|
11
12
|
import { groupConversationsByDate, useConversationActions } from "./conversationActions.js";
|
|
12
13
|
import cx from "classnames";
|
|
13
14
|
import { useEffect, useMemo, useRef, useState } from "react";
|
|
14
15
|
import { Fragment as Fragment$1, jsx, jsxs } from "react/jsx-runtime";
|
|
15
16
|
//#region src/ai/components/ChatSidebar.tsx
|
|
16
|
-
function ConversationRow({ conv, isCurrent, menuItems, openMenu, onOpen }) {
|
|
17
|
+
function ConversationRow({ conv, isCurrent, updated, menuItems, openMenu, onOpen }) {
|
|
17
18
|
const { LinkComponent, strings } = useChatConfig();
|
|
18
19
|
const t = strings.sidebar;
|
|
19
20
|
return /* @__PURE__ */ jsx(SidebarRow, {
|
|
@@ -30,8 +31,8 @@ function ConversationRow({ conv, isCurrent, menuItems, openMenu, onOpen }) {
|
|
|
30
31
|
children: [conv.isOwner === false && /* @__PURE__ */ jsx(FaUsers, {
|
|
31
32
|
className: "h-3 w-3 shrink-0 theme-muted-text",
|
|
32
33
|
title: t.sharedWithYou
|
|
33
|
-
}), /* @__PURE__ */ jsx(
|
|
34
|
-
|
|
34
|
+
}), /* @__PURE__ */ jsx(SidebarRowTitle, {
|
|
35
|
+
time: updated,
|
|
35
36
|
children: conv.title || t.untitled
|
|
36
37
|
})]
|
|
37
38
|
})
|
|
@@ -43,6 +44,7 @@ function ChatSidebar({ actions = true, top }) {
|
|
|
43
44
|
const { adapter, navigation, activeConversationId, conversations, sidebar, sidebarPresentation, drawerOpen, setSidebar, setDrawerOpen, toggleSidebar, isLoading, loadConversations, clearCurrentConversation } = useChat();
|
|
44
45
|
const attachmentsAvailable = !!adapter.attachments;
|
|
45
46
|
const { menuItems, openMenu, overlays } = useConversationActions();
|
|
47
|
+
const { compact } = useRelativeTime();
|
|
46
48
|
const drawer = sidebarPresentation === "drawer";
|
|
47
49
|
const sidebarCollapsed = !drawer && sidebar !== "expanded";
|
|
48
50
|
const closeDrawer = () => setDrawerOpen(false);
|
|
@@ -106,6 +108,7 @@ function ChatSidebar({ actions = true, top }) {
|
|
|
106
108
|
renderRow: (conv) => /* @__PURE__ */ jsx(ConversationRow, {
|
|
107
109
|
conv,
|
|
108
110
|
isCurrent: activeConversationId === conv.id,
|
|
111
|
+
updated: compact(conv.updatedAt ?? conv.createdAt),
|
|
109
112
|
menuItems: menuItems(conv),
|
|
110
113
|
openMenu,
|
|
111
114
|
onOpen: closeDrawer
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
export declare const DRAFT_MAX_LENGTH = 10000;
|
|
2
|
+
export declare const DRAFT_TTL_MS: number;
|
|
3
|
+
export declare function readDraft(conversationId?: string): string;
|
|
4
|
+
export declare function storeDraft(conversationId: string | undefined, text: string): void;
|
|
5
|
+
export declare function clearDraft(conversationId?: string): void;
|
|
6
|
+
/** Removes expired drafts, and starts the clock on ones stored without an age. */
|
|
7
|
+
export declare function sweepDrafts(now?: number): void;
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
//#region src/ai/components/chatDraft.ts
|
|
2
|
+
var DRAFT_STORAGE_PREFIX = "aiChatDraft:";
|
|
3
|
+
var DRAFT_MAX_LENGTH = 1e4;
|
|
4
|
+
var DRAFT_TTL_MS = 2592e6;
|
|
5
|
+
function draftKey(conversationId) {
|
|
6
|
+
return `${DRAFT_STORAGE_PREFIX}${conversationId ?? "new"}`;
|
|
7
|
+
}
|
|
8
|
+
/** Older versions stored the bare text, which has no age. */
|
|
9
|
+
function parseDraft(raw) {
|
|
10
|
+
try {
|
|
11
|
+
const parsed = JSON.parse(raw);
|
|
12
|
+
if (typeof parsed === "object" && parsed !== null && typeof parsed.text === "string" && typeof parsed.savedAt === "number") return parsed;
|
|
13
|
+
} catch {}
|
|
14
|
+
return { text: raw };
|
|
15
|
+
}
|
|
16
|
+
var expired = (savedAt, now) => now - savedAt > DRAFT_TTL_MS;
|
|
17
|
+
function readDraft(conversationId) {
|
|
18
|
+
try {
|
|
19
|
+
const raw = window.localStorage.getItem(draftKey(conversationId));
|
|
20
|
+
if (raw === null) return "";
|
|
21
|
+
const draft = parseDraft(raw);
|
|
22
|
+
return draft.savedAt !== void 0 && expired(draft.savedAt, Date.now()) ? "" : draft.text;
|
|
23
|
+
} catch {
|
|
24
|
+
return "";
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
function storeDraft(conversationId, text) {
|
|
28
|
+
try {
|
|
29
|
+
if (!text || text.length > 1e4) window.localStorage.removeItem(draftKey(conversationId));
|
|
30
|
+
else {
|
|
31
|
+
const draft = {
|
|
32
|
+
text,
|
|
33
|
+
savedAt: Date.now()
|
|
34
|
+
};
|
|
35
|
+
window.localStorage.setItem(draftKey(conversationId), JSON.stringify(draft));
|
|
36
|
+
}
|
|
37
|
+
} catch {}
|
|
38
|
+
}
|
|
39
|
+
function clearDraft(conversationId) {
|
|
40
|
+
try {
|
|
41
|
+
window.localStorage.removeItem(draftKey(conversationId));
|
|
42
|
+
} catch {}
|
|
43
|
+
}
|
|
44
|
+
/** Removes expired drafts, and starts the clock on ones stored without an age. */
|
|
45
|
+
function sweepDrafts(now = Date.now()) {
|
|
46
|
+
try {
|
|
47
|
+
const storage = window.localStorage;
|
|
48
|
+
const keys = [];
|
|
49
|
+
for (let i = 0; i < storage.length; i++) {
|
|
50
|
+
const key = storage.key(i);
|
|
51
|
+
if (key?.startsWith(DRAFT_STORAGE_PREFIX)) keys.push(key);
|
|
52
|
+
}
|
|
53
|
+
for (const key of keys) {
|
|
54
|
+
const raw = storage.getItem(key);
|
|
55
|
+
if (raw === null) continue;
|
|
56
|
+
const draft = parseDraft(raw);
|
|
57
|
+
if (draft.savedAt === void 0) storage.setItem(key, JSON.stringify({
|
|
58
|
+
text: draft.text,
|
|
59
|
+
savedAt: now
|
|
60
|
+
}));
|
|
61
|
+
else if (expired(draft.savedAt, now)) storage.removeItem(key);
|
|
62
|
+
}
|
|
63
|
+
} catch {}
|
|
64
|
+
}
|
|
65
|
+
//#endregion
|
|
66
|
+
export { DRAFT_MAX_LENGTH, DRAFT_TTL_MS, clearDraft, readDraft, storeDraft, sweepDrafts };
|
package/dist/ai/index.d.ts
CHANGED
|
@@ -43,5 +43,5 @@ export * from './types.js';
|
|
|
43
43
|
export { ConversationSidebar, type ConversationSidebarGroup, useResizableSidebarWidth, } from './ui/ConversationSidebar.js';
|
|
44
44
|
export { type DropdownOption, default as Dropdown } from './ui/Dropdown.js';
|
|
45
45
|
export { NoticeBar, NoticeCard, type NoticeTone, OutputCard } from './ui/Notice.js';
|
|
46
|
-
export { RenameDialog, type RowDialogStrings, SidebarDrawer, SidebarGroupHeading, SidebarPanel, SidebarPlaceholder, SidebarRailItem, SidebarRow, SidebarToggle, useRowDialogs, } from './ui/sidebar.js';
|
|
46
|
+
export { RenameDialog, type RowDialogStrings, SidebarDrawer, SidebarGroupHeading, SidebarPanel, SidebarPlaceholder, SidebarRailItem, SidebarRow, SidebarRowTitle, SidebarToggle, useRowDialogs, } from './ui/sidebar.js';
|
|
47
47
|
export { formatFileSize, isMac, isOrgModel } from './utils.js';
|
package/dist/ai/index.js
CHANGED
|
@@ -37,7 +37,7 @@ import ChatEmptyState from "./components/ChatEmptyState.js";
|
|
|
37
37
|
import { FOCUS_SIDEBAR_SEARCH_EVENT } from "./core/events.js";
|
|
38
38
|
import { useKeyboardShortcuts } from "./core/useKeyboardShortcuts.js";
|
|
39
39
|
import { KeyboardShortcutsProvider } from "./core/KeyboardShortcutsProvider.js";
|
|
40
|
-
import { RenameDialog, SidebarDrawer, SidebarGroupHeading, SidebarPanel, SidebarPlaceholder, SidebarRailItem, SidebarRow, SidebarToggle, useRowDialogs } from "./ui/sidebar.js";
|
|
40
|
+
import { RenameDialog, SidebarDrawer, SidebarGroupHeading, SidebarPanel, SidebarPlaceholder, SidebarRailItem, SidebarRow, SidebarRowTitle, SidebarToggle, useRowDialogs } from "./ui/sidebar.js";
|
|
41
41
|
import { ConversationSidebar, useResizableSidebarWidth } from "./ui/ConversationSidebar.js";
|
|
42
42
|
import ShareDialog, { ShareButton } from "./components/ShareDialog.js";
|
|
43
43
|
import { groupConversationsByDate, useConversationActions } from "./components/conversationActions.js";
|
|
@@ -46,4 +46,4 @@ import ChatLayout, { CHAT_COLUMN_SCOPE, ConversationLayout, DRAWER_BELOW_PX } fr
|
|
|
46
46
|
import ChatMessage_default from "./components/ChatMessage.js";
|
|
47
47
|
import ChatMessageList from "./components/ChatMessageList.js";
|
|
48
48
|
import ChatThread from "./components/ChatThread.js";
|
|
49
|
-
export { AGENT_COLOR_NAMES, ActivityLine, AgentMessageParts, AllocationSelector, ApprovalBlock, AttachmentManager, AttachmentUpload, BlockedGroupBanner, BranchNavigator, CHAT_COLUMN_SCOPE, ChatAdapterError, ChatEmptyState, ChatInput, ChatLayout, ChatMessageList, ChatMessage_default as ChatMessageView, ChatProvider, ChatSidebar, ChatStage, ChatThread, ComposerContext, ComposerControls, ComposerSettings, ComposerUsage, ConnectToolsLink, ConversationLayout, ConversationSidebar, DEFAULT_PERMISSION_MODE, DRAWER_BELOW_PX, DragOverlay, Dropdown, FOCUS_SIDEBAR_SEARCH_EVENT, INTERRUPTED_NOTICE, KeyboardShortcutsProvider, MAX_EDIT_DIFF_LINES, MAX_WRITE_DIFF_LINES, ManageProvidersLink, ModelSelector, NAMED_PERMISSION_MODES, NoticeBar, NoticeCard, OutputCard, PermissionPicker, ProviderIssueBanner, RenameDialog, ShareButton, ShareDialog, SidebarDrawer, SidebarGroupHeading, SidebarPanel, SidebarPlaceholder, SidebarRailItem, SidebarRow, SidebarToggle, agentColorHex, agentTypeLabel, applyPartDelta, askQuestionFromArgs, bashExitCode, chatReducer, clampPermissionMode, classifyPseudoUserMessage, clip, compactCount, computeEditDiff, computeWriteRows, defaultChatStrings, durationToAbsHumanDuration, editSummary, finalizeParts, firstNonEmptyLine, formatElapsed, formatFileSize, fullToolArgs, getGreeting, getProviderKeyFromModelId, groupConversationsByDate, hiddenTranscriptTool, initialState, interruptionNotice, isEditDiffTool, isGroupableTool, isMac, isNamedPermissionMode, isOrgModel, languageForPath, lineDelta, parseEditArgs, parseSubagentNotice, pasteInlineMaxBytes, permissionModesUpTo, planFromArgs, plural, providerIssueFor, resolveChatConfig, resultFailed, rollupSentence, sanitizeLabel, sanitizePanelText, slashMatches, subagentDeliveryLine, summarizeToolArgs, taskCallFromArgs, thinkingHeading, tokenizeDiffLines, toolHeaderFor, toolSummary, useChat, useChatConfig, useConversationActions, useDragDrop, useKeyboardShortcuts, useResizableSidebarWidth, useRowDialogs, wordEmphasisRanges };
|
|
49
|
+
export { AGENT_COLOR_NAMES, ActivityLine, AgentMessageParts, AllocationSelector, ApprovalBlock, AttachmentManager, AttachmentUpload, BlockedGroupBanner, BranchNavigator, CHAT_COLUMN_SCOPE, ChatAdapterError, ChatEmptyState, ChatInput, ChatLayout, ChatMessageList, ChatMessage_default as ChatMessageView, ChatProvider, ChatSidebar, ChatStage, ChatThread, ComposerContext, ComposerControls, ComposerSettings, ComposerUsage, ConnectToolsLink, ConversationLayout, ConversationSidebar, DEFAULT_PERMISSION_MODE, DRAWER_BELOW_PX, DragOverlay, Dropdown, FOCUS_SIDEBAR_SEARCH_EVENT, INTERRUPTED_NOTICE, KeyboardShortcutsProvider, MAX_EDIT_DIFF_LINES, MAX_WRITE_DIFF_LINES, ManageProvidersLink, ModelSelector, NAMED_PERMISSION_MODES, NoticeBar, NoticeCard, OutputCard, PermissionPicker, ProviderIssueBanner, RenameDialog, ShareButton, ShareDialog, SidebarDrawer, SidebarGroupHeading, SidebarPanel, SidebarPlaceholder, SidebarRailItem, SidebarRow, SidebarRowTitle, SidebarToggle, agentColorHex, agentTypeLabel, applyPartDelta, askQuestionFromArgs, bashExitCode, chatReducer, clampPermissionMode, classifyPseudoUserMessage, clip, compactCount, computeEditDiff, computeWriteRows, defaultChatStrings, durationToAbsHumanDuration, editSummary, finalizeParts, firstNonEmptyLine, formatElapsed, formatFileSize, fullToolArgs, getGreeting, getProviderKeyFromModelId, groupConversationsByDate, hiddenTranscriptTool, initialState, interruptionNotice, isEditDiffTool, isGroupableTool, isMac, isNamedPermissionMode, isOrgModel, languageForPath, lineDelta, parseEditArgs, parseSubagentNotice, pasteInlineMaxBytes, permissionModesUpTo, planFromArgs, plural, providerIssueFor, resolveChatConfig, resultFailed, rollupSentence, sanitizeLabel, sanitizePanelText, slashMatches, subagentDeliveryLine, summarizeToolArgs, taskCallFromArgs, thinkingHeading, tokenizeDiffLines, toolHeaderFor, toolSummary, useChat, useChatConfig, useConversationActions, useDragDrop, useKeyboardShortcuts, useResizableSidebarWidth, useRowDialogs, wordEmphasisRanges };
|
package/dist/ai/ui/sidebar.d.ts
CHANGED
|
@@ -43,6 +43,12 @@ export declare function SidebarPlaceholder({ children, testId, }: {
|
|
|
43
43
|
children: ReactNode;
|
|
44
44
|
testId?: string | undefined;
|
|
45
45
|
}): import("react").JSX.Element;
|
|
46
|
+
/** A row's first line, the same in every list: what it is, and when it last
|
|
47
|
+
* moved, abbreviated, on the right. */
|
|
48
|
+
export declare function SidebarRowTitle({ children, time, }: {
|
|
49
|
+
children: ReactNode;
|
|
50
|
+
time?: string | undefined;
|
|
51
|
+
}): import("react").JSX.Element;
|
|
46
52
|
/** One entry in the list: the row highlights while it is the open one or
|
|
47
53
|
* while its menu is up, and the menu opens from its button or a right-click. */
|
|
48
54
|
export declare function SidebarRow({ selected, menuItems, openMenu, className, children, }: {
|
package/dist/ai/ui/sidebar.js
CHANGED
|
@@ -85,6 +85,20 @@ function SidebarPlaceholder({ children, testId }) {
|
|
|
85
85
|
children
|
|
86
86
|
});
|
|
87
87
|
}
|
|
88
|
+
/** A row's first line, the same in every list: what it is, and when it last
|
|
89
|
+
* moved, abbreviated, on the right. */
|
|
90
|
+
function SidebarRowTitle({ children, time }) {
|
|
91
|
+
return /* @__PURE__ */ jsxs("span", {
|
|
92
|
+
className: "flex min-w-0 flex-1 items-baseline gap-2",
|
|
93
|
+
children: [/* @__PURE__ */ jsx("span", {
|
|
94
|
+
className: "min-w-0 flex-1 truncate text-sm theme-text",
|
|
95
|
+
children
|
|
96
|
+
}), time && /* @__PURE__ */ jsx("span", {
|
|
97
|
+
className: "min-w-8 shrink-0 text-[11px] tabular-nums theme-muted-text",
|
|
98
|
+
children: time
|
|
99
|
+
})]
|
|
100
|
+
});
|
|
101
|
+
}
|
|
88
102
|
/** One entry in the list: the row highlights while it is the open one or
|
|
89
103
|
* while its menu is up, and the menu opens from its button or a right-click. */
|
|
90
104
|
function SidebarRow({ selected, menuItems, openMenu, className, children }) {
|
|
@@ -191,4 +205,4 @@ function useRowDialogs({ strings, nameOf, onDelete, onRename }) {
|
|
|
191
205
|
};
|
|
192
206
|
}
|
|
193
207
|
//#endregion
|
|
194
|
-
export { RenameDialog, SidebarDrawer, SidebarGroupHeading, SidebarPanel, SidebarPlaceholder, SidebarRailItem, SidebarRow, SidebarToggle, useRowDialogs };
|
|
208
|
+
export { RenameDialog, SidebarDrawer, SidebarGroupHeading, SidebarPanel, SidebarPlaceholder, SidebarRailItem, SidebarRow, SidebarRowTitle, SidebarToggle, useRowDialogs };
|
package/dist/editing.d.ts
CHANGED
|
@@ -406,6 +406,8 @@ export interface WorkflowEditing {
|
|
|
406
406
|
inputChildrenKey: (type: unknown) => string | undefined;
|
|
407
407
|
isValidInputName: (name: string) => boolean;
|
|
408
408
|
newInputName: (existing: Iterable<string>) => string;
|
|
409
|
+
/** The name an `addJob` edit gives the job it adds. */
|
|
410
|
+
newJobName: (existing: Iterable<string>) => string;
|
|
409
411
|
/** `base`, or `base_2`, `base_3`… when it's taken. */
|
|
410
412
|
nextName: (taken: Iterable<string>, base: string) => string;
|
|
411
413
|
/** The first of `candidate(1)`, `candidate(2)`… that `taken` doesn't hold. */
|
package/dist/editor/Monaco.js
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import { useCssIsDark } from "../components/useCssIsDark.js";
|
|
2
2
|
import { HOST_MARKER_OWNER, LINT_OWNER } from "./lintOwner.js";
|
|
3
|
+
import { lintContext, useLintEditing, useLintSources } from "./lintContext.js";
|
|
3
4
|
import { publishNestedText } from "./nestedText.js";
|
|
4
5
|
import { registerRevealer } from "./reveal.js";
|
|
5
6
|
import { defineEditorThemes, getThemeName } from "./themes.js";
|
|
6
7
|
import { setupMonacoWorkers } from "./workers.js";
|
|
7
8
|
import { holdListeners, modelFor } from "./editorModel.js";
|
|
8
|
-
import { lintContext, useLintEditing, useLintSources } from "./lintContext.js";
|
|
9
9
|
import { ensureYamlLanguage } from "./yamlLanguage.js";
|
|
10
10
|
import cx from "classnames";
|
|
11
11
|
import { useEffect, useLayoutEffect, useRef } from "react";
|
package/dist/editor/index.js
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
|
+
import { HOST_MARKER_OWNER, LINT_OWNER } from "./lintOwner.js";
|
|
1
2
|
import { INPUT_YAML_PATH, JOB_YAML_PATH, SETTINGS_YAML_PATH, STEP_YAML_PATH, settingsSchemas } from "./settingsYaml.js";
|
|
2
3
|
import Editor from "./Editor.js";
|
|
3
4
|
import EditorField from "./EditorField.js";
|
|
4
5
|
import FormCodePanel from "./FormCodePanel.js";
|
|
5
|
-
import { HOST_MARKER_OWNER, LINT_OWNER } from "./lintOwner.js";
|
|
6
6
|
import { nestedWorkflowText } from "./nestedText.js";
|
|
7
7
|
import { revealLines } from "./reveal.js";
|
|
8
8
|
import { defineEditorThemes, getThemeName } from "./themes.js";
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import { useLoadedWorkflowEngine, useRepoSuggestions, useSecretVariablesResolver, useWorkflowActions, useWorkflowJsonResolver } from "../components/Provider.js";
|
|
1
|
+
import { useLoadedWorkflowEngine, useRepoSuggestions, useSecretVariablesResolver, useWorkflowActions, useWorkflowEditing, useWorkflowJsonResolver } from "../components/Provider.js";
|
|
2
2
|
import { asRecord } from "../graph/records.js";
|
|
3
|
-
import { HOST_MARKER_OWNER, LINT_OWNER } from "./lintOwner.js";
|
|
4
3
|
import { DEFAULT_GITLAB_HOST, DEFAULT_REPO_YAML, loadUsesInputs } from "../graph/usesInputs.js";
|
|
4
|
+
import { HOST_MARKER_OWNER, LINT_OWNER } from "./lintOwner.js";
|
|
5
5
|
import { useEffect, useMemo, useState } from "react";
|
|
6
6
|
//#region src/editor/lintContext.ts
|
|
7
7
|
var KEEP_MS = 6e4;
|
|
@@ -112,6 +112,18 @@ function useLintSources() {
|
|
|
112
112
|
actions
|
|
113
113
|
]);
|
|
114
114
|
}
|
|
115
|
+
/** lintContext for a component, which renders again when more of it arrives. */
|
|
116
|
+
function useLintContext(source) {
|
|
117
|
+
const editing = useWorkflowEditing();
|
|
118
|
+
const sources = useLintSources();
|
|
119
|
+
const [arrivals, setArrivals] = useState(0);
|
|
120
|
+
return useMemo(() => source === void 0 ? {} : lintContext(editing, source, sources, () => setArrivals((n) => n + 1)), [
|
|
121
|
+
editing,
|
|
122
|
+
source,
|
|
123
|
+
sources,
|
|
124
|
+
arrivals
|
|
125
|
+
]);
|
|
126
|
+
}
|
|
115
127
|
/**
|
|
116
128
|
* The engine's editing once its checks have loaded, rendering again when they have; undefined
|
|
117
129
|
* before then, without an engine that edits, or with `load` false.
|
|
@@ -133,4 +145,4 @@ function useLintEditing(load = true) {
|
|
|
133
145
|
return load && ready ? engine?.editing : void 0;
|
|
134
146
|
}
|
|
135
147
|
//#endregion
|
|
136
|
-
export { HOST_MARKER_OWNER, LINT_OWNER, lintContext, useLintEditing, useLintSources };
|
|
148
|
+
export { HOST_MARKER_OWNER, LINT_OWNER, lintContext, useLintContext, useLintEditing, useLintSources };
|
|
@@ -27,6 +27,7 @@ function FieldWrapper({ label, tooltipComponent, description, labelPosition = "l
|
|
|
27
27
|
children: [/* @__PURE__ */ jsxs("label", {
|
|
28
28
|
htmlFor: id,
|
|
29
29
|
id: labelId,
|
|
30
|
+
"data-field-label": true,
|
|
30
31
|
className: cx("relative", labelPosition === "left" ? "form-label" : "form-label-top", spaceCompact && "form-label-compact"),
|
|
31
32
|
children: [
|
|
32
33
|
label,
|
package/dist/form/Form.js
CHANGED
|
@@ -14,6 +14,7 @@ import { FormLayout, LayoutCSSContext } from "./FormLayout.js";
|
|
|
14
14
|
import { useFieldControlProps, useFieldRequired } from "./fieldContext.js";
|
|
15
15
|
import { getValueUsingPath } from "./utils/getValueUsingPath.js";
|
|
16
16
|
import { FieldRegistryContext, Registry } from "./fieldRegistry.js";
|
|
17
|
+
import { EditingScope, useFormEditing } from "./formEditing.js";
|
|
17
18
|
import { useParsedOpts } from "./useParsedOpts.js";
|
|
18
19
|
import { usePrevious } from "./usePrevious.js";
|
|
19
20
|
import { getParentValue } from "./utils/getParentValue.js";
|
|
@@ -209,6 +210,7 @@ function GroupHeader({ children, open, setOpen, title }) {
|
|
|
209
210
|
children: [/* @__PURE__ */ jsxs("button", {
|
|
210
211
|
type: "button",
|
|
211
212
|
"aria-expanded": open,
|
|
213
|
+
"data-field-label": true,
|
|
212
214
|
className: "w-full flex items-center text-left transform ease-in transition cursor-pointer",
|
|
213
215
|
onClick: () => setOpen((open) => !open),
|
|
214
216
|
children: [/* @__PURE__ */ jsx(FaAngleRight, { className: cx(open && "transform rotate-90 ", "px-1 text-[1.25rem] transition ease-in ") }), /* @__PURE__ */ jsx("span", { children: title })]
|
|
@@ -393,6 +395,8 @@ function useFieldParse(optionsField, values, arrayIndex) {
|
|
|
393
395
|
}
|
|
394
396
|
var FormField = React.memo(function FormField({ optionsField, fieldName, values, setFormDirty, setFieldValue, setFieldTouched, parentInfo, labelPosition = "left", missingFields = [], spaceCompact = false, workflowForm = false }) {
|
|
395
397
|
const parsedField = useFieldParse(optionsField, values, parentInfo?.arrayIndex);
|
|
398
|
+
const editing = useFormEditing();
|
|
399
|
+
const path = editing ? [...editing.parent, fieldName] : null;
|
|
396
400
|
const field = asSchemaField(parentInfo ? parsedField : optionsField);
|
|
397
401
|
if (field === null) return null;
|
|
398
402
|
const fieldNamePrefix = parentInfo?.fieldNamePrefix || "";
|
|
@@ -405,7 +409,11 @@ var FormField = React.memo(function FormField({ optionsField, fieldName, values,
|
|
|
405
409
|
if (!fieldObj.name || fieldName === "v3") return null;
|
|
406
410
|
if (field.hidden === true || !field.type) {
|
|
407
411
|
if (resolvedFlag(field.ignore) && !workflowForm) deleteFieldByPath(values, fieldObj.name);
|
|
408
|
-
return
|
|
412
|
+
return editing && path && fieldName !== "$meta" ? /* @__PURE__ */ jsx(editing.Row, {
|
|
413
|
+
path,
|
|
414
|
+
instance: fieldObj.name,
|
|
415
|
+
hidden: true
|
|
416
|
+
}) : null;
|
|
409
417
|
}
|
|
410
418
|
let onChange;
|
|
411
419
|
if (field.one_must_be_true && parentInfo?.onChange) {
|
|
@@ -421,7 +429,11 @@ var FormField = React.memo(function FormField({ optionsField, fieldName, values,
|
|
|
421
429
|
if (shouldShowField && field.show_if_not !== void 0) shouldShowField = !getParentValue(index, field.show_if_not, values, field);
|
|
422
430
|
if (!shouldShowField) {
|
|
423
431
|
if (!workflowForm) deleteFieldByPath(values, fieldObj.name);
|
|
424
|
-
return
|
|
432
|
+
return editing && path ? /* @__PURE__ */ jsx(editing.Row, {
|
|
433
|
+
path,
|
|
434
|
+
instance: fieldObj.name,
|
|
435
|
+
hidden: true
|
|
436
|
+
}) : null;
|
|
425
437
|
}
|
|
426
438
|
}
|
|
427
439
|
if (field.depends_on && parentInfo?.arrayIndex !== void 0) fieldObj.depends_on = field.depends_on.replace("[index]", `[${parentInfo.arrayIndex}]`);
|
|
@@ -436,7 +448,7 @@ var FormField = React.memo(function FormField({ optionsField, fieldName, values,
|
|
|
436
448
|
const hideHeader = field.noCollapse;
|
|
437
449
|
const HeaderElement = hideHeader ? React.Fragment : UncontrolledCollapsiblePanel;
|
|
438
450
|
const meta = resolveMetaOverrides(field.options, labelPosition, spaceCompact);
|
|
439
|
-
|
|
451
|
+
const group = /* @__PURE__ */ jsx("div", {
|
|
440
452
|
className: "flex flex-col w-full",
|
|
441
453
|
children: /* @__PURE__ */ jsx(HeaderElement, {
|
|
442
454
|
...!hideHeader && {
|
|
@@ -449,21 +461,30 @@ var FormField = React.memo(function FormField({ optionsField, fieldName, values,
|
|
|
449
461
|
},
|
|
450
462
|
children: /* @__PURE__ */ jsx("div", {
|
|
451
463
|
className: "w-full",
|
|
452
|
-
children: /* @__PURE__ */ jsx(
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
464
|
+
children: /* @__PURE__ */ jsx(EditingScope, {
|
|
465
|
+
editing,
|
|
466
|
+
path,
|
|
467
|
+
children: /* @__PURE__ */ jsx(FieldsFromOptions, {
|
|
468
|
+
options: field.options ?? {},
|
|
469
|
+
setFormDirty,
|
|
470
|
+
setFieldValue,
|
|
471
|
+
setFieldTouched,
|
|
472
|
+
values,
|
|
473
|
+
parentInfo,
|
|
474
|
+
workflowForm,
|
|
475
|
+
labelPosition: meta.labelPosition,
|
|
476
|
+
spaceCompact: meta.spaceCompact,
|
|
477
|
+
missingFields
|
|
478
|
+
})
|
|
463
479
|
})
|
|
464
480
|
})
|
|
465
481
|
})
|
|
466
482
|
});
|
|
483
|
+
return editing && path ? /* @__PURE__ */ jsx(editing.Row, {
|
|
484
|
+
path,
|
|
485
|
+
instance: fieldObj.name,
|
|
486
|
+
children: group
|
|
487
|
+
}) : group;
|
|
467
488
|
}
|
|
468
489
|
if (typeof field.type === "object" && field.depends_on) {
|
|
469
490
|
const parentValue = getValueUsingPath(values, field.depends_on);
|
|
@@ -489,7 +510,7 @@ var FormField = React.memo(function FormField({ optionsField, fieldName, values,
|
|
|
489
510
|
if (Array.isArray(field.secondaryField)) fieldObj.secondaryField = field.secondaryField.map((secondaryField) => fieldNamePrefix + secondaryField);
|
|
490
511
|
else fieldObj.secondaryField = fieldNamePrefix + field.secondaryField;
|
|
491
512
|
}
|
|
492
|
-
|
|
513
|
+
const input = /* @__PURE__ */ jsx("div", {
|
|
493
514
|
className: cx("flex w-full", labelPosition === "left" ? "mb-[15px]" : "mb-[5px]"),
|
|
494
515
|
children: /* @__PURE__ */ jsx(InputField, {
|
|
495
516
|
field: fieldObj,
|
|
@@ -508,6 +529,17 @@ var FormField = React.memo(function FormField({ optionsField, fieldName, values,
|
|
|
508
529
|
workflowForm
|
|
509
530
|
})
|
|
510
531
|
});
|
|
532
|
+
if (!editing || !path) return input;
|
|
533
|
+
const holds = fieldObj.type === "object" || fieldObj.type === "list";
|
|
534
|
+
return /* @__PURE__ */ jsx(editing.Row, {
|
|
535
|
+
path,
|
|
536
|
+
instance: fieldObj.name,
|
|
537
|
+
children: /* @__PURE__ */ jsx(EditingScope, {
|
|
538
|
+
editing,
|
|
539
|
+
path: holds ? path : null,
|
|
540
|
+
children: input
|
|
541
|
+
})
|
|
542
|
+
});
|
|
511
543
|
}, (prev, next) => {
|
|
512
544
|
if (!deepEqual(prev.optionsField, next.optionsField)) return false;
|
|
513
545
|
if (prev.values !== next.values) return false;
|
|
@@ -519,6 +551,7 @@ var FormField = React.memo(function FormField({ optionsField, fieldName, values,
|
|
|
519
551
|
return true;
|
|
520
552
|
});
|
|
521
553
|
function FieldsFromOptions({ options = {}, values, setFormDirty, setFieldValue, setFieldTouched, parentInfo, labelPosition = "left", missingFields = [], spaceCompact = false, workflowForm = false }) {
|
|
554
|
+
const editing = useFormEditing();
|
|
522
555
|
const chosen = useChosenLabelPosition(options);
|
|
523
556
|
const wizard = parseWizardConfig(options);
|
|
524
557
|
if (wizard) return /* @__PURE__ */ jsx(ChosenLabelPosition.Provider, {
|
|
@@ -556,22 +589,27 @@ function FieldsFromOptions({ options = {}, values, setFormDirty, setFieldValue,
|
|
|
556
589
|
spaceCompact,
|
|
557
590
|
workflowForm
|
|
558
591
|
}, fieldName);
|
|
592
|
+
const add = editing ? /* @__PURE__ */ jsx(editing.Add, { parent: editing.parent }) : null;
|
|
559
593
|
const layout = resolveFormLayout(asRecord(options["$meta"])["layout"], names.filter((name) => !name.startsWith("$") && asSchemaField(options[name])));
|
|
560
594
|
if (layout.layout) return /* @__PURE__ */ jsx(ChosenLabelPosition.Provider, {
|
|
561
595
|
value: chosen,
|
|
562
596
|
children: /* @__PURE__ */ jsxs("div", {
|
|
563
597
|
className: "flex min-w-0 flex-col gap-4",
|
|
564
|
-
children: [
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
598
|
+
children: [
|
|
599
|
+
/* @__PURE__ */ jsx(FormLayout, {
|
|
600
|
+
layout: layout.layout,
|
|
601
|
+
renderField: (name) => fieldOf(name, true)
|
|
602
|
+
}),
|
|
603
|
+
layout.remaining.map((name) => fieldOf(name, true)),
|
|
604
|
+
add
|
|
605
|
+
]
|
|
568
606
|
})
|
|
569
607
|
});
|
|
570
608
|
return /* @__PURE__ */ jsx(ChosenLabelPosition.Provider, {
|
|
571
609
|
value: chosen,
|
|
572
|
-
children: flows ? /* @__PURE__ */
|
|
610
|
+
children: flows ? /* @__PURE__ */ jsxs("div", {
|
|
573
611
|
className: "@container/inputs -mx-2 flex flex-wrap items-start",
|
|
574
|
-
children: columns.map((column) => {
|
|
612
|
+
children: [columns.map((column) => {
|
|
575
613
|
const width = inputWidth(asRecord(options[column.head])["width"]);
|
|
576
614
|
return /* @__PURE__ */ jsx("div", {
|
|
577
615
|
"data-input-cell": true,
|
|
@@ -587,8 +625,11 @@ function FieldsFromOptions({ options = {}, values, setFormDirty, setFieldValue,
|
|
|
587
625
|
}, name);
|
|
588
626
|
})
|
|
589
627
|
}, column.head);
|
|
590
|
-
})
|
|
591
|
-
|
|
628
|
+
}), add && /* @__PURE__ */ jsx("div", {
|
|
629
|
+
className: "order-2 w-full px-2",
|
|
630
|
+
children: add
|
|
631
|
+
})]
|
|
632
|
+
}) : /* @__PURE__ */ jsxs(Fragment$1, { children: [names.map((name) => fieldOf(name, void 0)), add] })
|
|
592
633
|
});
|
|
593
634
|
}
|
|
594
635
|
var noop = () => {};
|
|
@@ -2,16 +2,21 @@ import { useStrings, useWorkflowEngine } from "../../components/Provider.js";
|
|
|
2
2
|
import { copyBounds, stepText } from "./utils.js";
|
|
3
3
|
import { initializeValues } from "../lib.js";
|
|
4
4
|
import { getValueUsingPath } from "../utils/getValueUsingPath.js";
|
|
5
|
+
import { useFormEditing } from "../formEditing.js";
|
|
5
6
|
import { useWizardState } from "./useWizardState.js";
|
|
6
7
|
import { WizardNavigation } from "./WizardNavigation.js";
|
|
7
8
|
import { WizardStepContent } from "./WizardStepContent.js";
|
|
8
9
|
import { WizardStepIndicator } from "./WizardStepIndicator.js";
|
|
9
|
-
import {
|
|
10
|
+
import { WizardPagesContext } from "./wizardPages.js";
|
|
11
|
+
import { useCallback, useContext, useEffect, useMemo, useRef, useState } from "react";
|
|
10
12
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
11
13
|
import { useFormikContext } from "formik";
|
|
12
14
|
//#region src/form/Wizard/WizardContainer.tsx
|
|
13
15
|
function WizardContainer({ wizardConfig, values, onChange, onSubmit, className = "", labelPosition = "left", missingFields = [], spaceCompact = false, workflowForm = false, nested = false, fieldNamePrefix = "", setFieldValue, setFieldTouched }) {
|
|
14
16
|
const { validateForm, setTouched, touched, initialValues } = useFormikContext();
|
|
17
|
+
const editing = useFormEditing();
|
|
18
|
+
const pages = useContext(WizardPagesContext);
|
|
19
|
+
const [ownPage, setOwnPage] = useState(0);
|
|
15
20
|
const { form: strings } = useStrings();
|
|
16
21
|
const engine = useWorkflowEngine();
|
|
17
22
|
const { config, steps, stepOrder } = wizardConfig;
|
|
@@ -197,19 +202,39 @@ function WizardContainer({ wizardConfig, values, onChange, onSubmit, className =
|
|
|
197
202
|
touched,
|
|
198
203
|
onSubmit
|
|
199
204
|
]);
|
|
205
|
+
const last = Math.max(shown.order.length - 1, 0);
|
|
206
|
+
const wizardKey = editing ? JSON.stringify(editing.parent) : "";
|
|
207
|
+
const editIndex = Math.min(Math.max(pages ? pages.page(wizardKey) : ownPage, 0), last);
|
|
208
|
+
const turn = (to) => {
|
|
209
|
+
const next = Math.max(to, 0);
|
|
210
|
+
if (pages) pages.setPage(wizardKey, next);
|
|
211
|
+
else setOwnPage(next);
|
|
212
|
+
};
|
|
213
|
+
const drawn = shown.order.length;
|
|
214
|
+
const setCount = pages?.setCount;
|
|
215
|
+
useEffect(() => {
|
|
216
|
+
setCount?.(wizardKey, drawn);
|
|
217
|
+
}, [
|
|
218
|
+
setCount,
|
|
219
|
+
wizardKey,
|
|
220
|
+
drawn
|
|
221
|
+
]);
|
|
200
222
|
const shownBefore = useRef(shown.order);
|
|
201
223
|
useEffect(() => {
|
|
202
224
|
shownBefore.current = shown.order;
|
|
203
225
|
});
|
|
204
|
-
const
|
|
226
|
+
const runKey = shown.byKey[currentStep] ? currentStep : nearestPage(currentStep, shown.order, shownBefore.current);
|
|
205
227
|
useEffect(() => {
|
|
206
|
-
if (
|
|
228
|
+
if (!editing && runKey && runKey !== currentStep) showStep(runKey);
|
|
207
229
|
}, [
|
|
208
|
-
|
|
230
|
+
editing,
|
|
231
|
+
runKey,
|
|
209
232
|
currentStep,
|
|
210
233
|
showStep
|
|
211
234
|
]);
|
|
235
|
+
const pageKey = editing ? shown.order[editIndex] ?? "" : runKey;
|
|
212
236
|
const page = shown.byKey[pageKey];
|
|
237
|
+
const show = (key, index) => editing ? turn(index) : showStep(key);
|
|
213
238
|
const copiesOf = (step) => {
|
|
214
239
|
const rows = getValueUsingPath(values, `${fieldNamePrefix}${step}`);
|
|
215
240
|
return Array.isArray(rows) ? rows : [];
|
|
@@ -220,13 +245,15 @@ function WizardContainer({ wizardConfig, values, onChange, onSubmit, className =
|
|
|
220
245
|
const kept = Array.from({ length: shownPage.count ?? rows.length }, (_, i) => rows[i] ?? initializeValues(options, {}) ?? {});
|
|
221
246
|
const aside = setAside.current[`${fieldNamePrefix}${shownPage.step}`] ?? [];
|
|
222
247
|
setFieldValue(`${fieldNamePrefix}${shownPage.step}`, [...kept, takeAside(aside, kept.length) ?? initializeValues(options, {}) ?? {}]);
|
|
223
|
-
|
|
248
|
+
const at = shown.order.indexOf(pageKey) + (shownPage.copy === void 0 ? 0 : 1);
|
|
249
|
+
show(`${shownPage.step}[${kept.length}]`, at);
|
|
224
250
|
};
|
|
225
251
|
const removeCopy = (shownPage) => {
|
|
226
252
|
const copy = shownPage.copy ?? 0;
|
|
227
253
|
const rows = copiesOf(shownPage.step).filter((_, i) => i !== copy);
|
|
228
254
|
setFieldValue(`${fieldNamePrefix}${shownPage.step}`, rows);
|
|
229
|
-
|
|
255
|
+
const at = shown.order.indexOf(pageKey) - (copy > 0 ? 1 : 0);
|
|
256
|
+
show(rows.length > 0 ? `${shownPage.step}[${Math.max(copy - 1, 0)}]` : shownPage.step, at);
|
|
230
257
|
};
|
|
231
258
|
const rawTitle = page ? steps[page.step]?.title : void 0;
|
|
232
259
|
const titledPerCopy = Array.isArray(rawTitle) || typeof rawTitle === "string" && rawTitle.includes("${{");
|
|
@@ -264,6 +291,39 @@ function WizardContainer({ wizardConfig, values, onChange, onSubmit, className =
|
|
|
264
291
|
setFieldTouched
|
|
265
292
|
}), copies]
|
|
266
293
|
}) : null;
|
|
294
|
+
if (editing) return /* @__PURE__ */ jsxs("div", {
|
|
295
|
+
className,
|
|
296
|
+
children: [
|
|
297
|
+
navigation.showSteps !== false && /* @__PURE__ */ jsx(WizardStepIndicator, {
|
|
298
|
+
stepOrder: shown.order,
|
|
299
|
+
currentStep: pageKey,
|
|
300
|
+
steps: configs,
|
|
301
|
+
visitedSteps: new Set(shown.order),
|
|
302
|
+
invalidSteps: /* @__PURE__ */ new Set(),
|
|
303
|
+
onStepClick: (key) => {
|
|
304
|
+
turn(shown.order.indexOf(key));
|
|
305
|
+
return true;
|
|
306
|
+
},
|
|
307
|
+
allowJump: true,
|
|
308
|
+
hideStepNumbers: navigation.hideStepNumbers
|
|
309
|
+
}),
|
|
310
|
+
content,
|
|
311
|
+
/* @__PURE__ */ jsx(WizardNavigation, {
|
|
312
|
+
isLastStep: editIndex === last,
|
|
313
|
+
canGoBack: editIndex > 0,
|
|
314
|
+
isCurrentStepValid: true,
|
|
315
|
+
nextLabel: page?.config.nextLabel,
|
|
316
|
+
prevLabel: page?.config.prevLabel,
|
|
317
|
+
submitLabel: config.submitLabel || "Execute",
|
|
318
|
+
onNext: async () => {
|
|
319
|
+
turn(editIndex + 1);
|
|
320
|
+
return true;
|
|
321
|
+
},
|
|
322
|
+
onPrevious: () => turn(editIndex - 1),
|
|
323
|
+
onSubmit: nested ? void 0 : async () => {}
|
|
324
|
+
})
|
|
325
|
+
]
|
|
326
|
+
});
|
|
267
327
|
return /* @__PURE__ */ jsxs("div", {
|
|
268
328
|
className,
|
|
269
329
|
children: [
|