@parallelworks/ui 0.36.0 → 0.38.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 +16 -0
- package/dist/ai/agent/permissions.d.ts +2 -2
- package/dist/ai/agent/permissions.js +3 -1
- package/dist/ai/components/ChatSidebar.js +7 -4
- package/dist/ai/components/agent/PermissionPicker.js +1 -0
- package/dist/ai/index.d.ts +1 -1
- package/dist/ai/index.js +2 -2
- package/dist/ai/strings.d.ts +2 -0
- package/dist/ai/strings.js +2 -0
- package/dist/ai/ui/sidebar.d.ts +6 -0
- package/dist/ai/ui/sidebar.js +15 -1
- package/dist/components/Dropdown.d.ts +2 -0
- package/dist/components/Dropdown.js +7 -2
- package/dist/components/Input.d.ts +11 -6
- package/dist/components/Input.js +93 -74
- package/dist/components/Provider.d.ts +31 -0
- package/dist/components/Provider.js +50 -2
- package/dist/editing.d.ts +404 -0
- package/dist/editor/EditorField.js +1 -1
- package/dist/editor/Monaco.d.ts +15 -1
- package/dist/editor/Monaco.js +117 -13
- package/dist/editor/editorModel.d.ts +5 -0
- package/dist/editor/editorModel.js +23 -0
- package/dist/editor/index.d.ts +4 -0
- package/dist/editor/index.js +5 -1
- package/dist/editor/lintContext.d.ts +21 -0
- package/dist/editor/lintContext.js +136 -0
- package/dist/editor/lintOwner.d.ts +2 -0
- package/dist/editor/lintOwner.js +5 -0
- package/dist/editor/nestedText.d.ts +13 -0
- package/dist/editor/nestedText.js +15 -0
- package/dist/editor/reveal.d.ts +4 -0
- package/dist/editor/reveal.js +15 -0
- package/dist/editor/settingsYaml.d.ts +12 -0
- package/dist/editor/settingsYaml.js +41 -0
- package/dist/form/FieldWrapper.js +1 -0
- package/dist/form/Fields/DropdownField.js +1 -1
- package/dist/form/Fields/DurationField.js +1 -1
- package/dist/form/Form.js +65 -24
- 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/fieldRegistry.js +1 -1
- package/dist/form/formEditing.d.ts +25 -0
- package/dist/form/formEditing.js +20 -0
- package/dist/form/index.js +5 -5
- package/dist/graph/InputDialog.d.ts +80 -0
- package/dist/graph/InputDialog.js +2110 -0
- package/dist/graph/InputsEditor.d.ts +12 -0
- package/dist/graph/InputsEditor.js +1594 -0
- package/dist/graph/ProblemsButton.d.ts +9 -0
- package/dist/graph/ProblemsButton.js +61 -0
- package/dist/graph/ShortcutsButton.d.ts +15 -0
- package/dist/graph/ShortcutsButton.js +56 -0
- package/dist/graph/SuggestionInput.d.ts +18 -0
- package/dist/graph/SuggestionInput.js +29 -0
- package/dist/graph/ToolbarPopover.d.ts +8 -0
- package/dist/graph/ToolbarPopover.js +71 -0
- package/dist/graph/editorApi.d.ts +51 -0
- package/dist/graph/editorApi.js +8 -0
- package/dist/graph/editorChrome.d.ts +27 -0
- package/dist/graph/editorChrome.js +75 -0
- package/dist/graph/editorFields.d.ts +180 -0
- package/dist/graph/editorFields.js +394 -0
- package/dist/graph/editorPrimitives.d.ts +60 -0
- package/dist/graph/editorPrimitives.js +150 -0
- package/dist/graph/editorStrings.d.ts +695 -0
- package/dist/graph/editorStrings.js +707 -0
- package/dist/graph/expressionRefs.d.ts +12 -0
- package/dist/graph/fieldProblems.d.ts +32 -0
- package/dist/graph/fieldProblems.js +77 -0
- package/dist/graph/index.d.ts +7 -0
- package/dist/graph/index.js +6 -1
- package/dist/graph/inputLayout.d.ts +25 -0
- 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.d.ts +103 -0
- package/dist/graph/inputRefs.js +196 -0
- package/dist/graph/inputRows.d.ts +43 -0
- package/dist/graph/inputRows.js +65 -0
- package/dist/graph/records.d.ts +3 -0
- package/dist/graph/records.js +7 -0
- package/dist/graph/refusalText.d.ts +6 -0
- package/dist/graph/settingsViews.d.ts +26 -0
- package/dist/graph/settingsViews.js +62 -0
- package/dist/graph/usesInputs.d.ts +17 -0
- package/dist/graph/usesInputs.js +40 -0
- package/dist/icons/bi/BiRedo.js +16 -0
- package/dist/icons/bi/BiUndo.js +16 -0
- package/dist/icons/lu/LuBraces.js +27 -0
- package/dist/icons/lu/LuCode.js +27 -0
- package/dist/icons/lu/LuKeyboard.js +71 -0
- package/dist/icons/lu/LuNetwork.js +63 -0
- package/dist/icons/lu/LuTextCursorInput.js +45 -0
- package/dist/icons.d.ts +2 -2
- package/dist/icons.js +8 -1
- package/dist/index.d.ts +2 -1
- package/dist/index.js +2 -2
- package/dist/list/ActionToolbar.d.ts +2 -0
- package/dist/list/ActionToolbar.js +18 -5
- package/dist/list/RowContextMenu.d.ts +10 -1
- package/dist/list/RowContextMenu.js +185 -30
- package/dist/styles.css +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -99,6 +99,22 @@ const engine = { ...createWorkflowEngine(), editing: workflowPackage }
|
|
|
99
99
|
|
|
100
100
|
Without `editing`, the graph lays its jobs out by their needs alone.
|
|
101
101
|
|
|
102
|
+
The editor checks YAML against the schemas a host registers with `configureEditorYaml` from
|
|
103
|
+
`@parallelworks/ui/editor`. The job, step, input and settings dialogs edit their YAML at their own
|
|
104
|
+
paths (`JOB_YAML_PATH`, `STEP_YAML_PATH`, `INPUT_YAML_PATH`, `SETTINGS_YAML_PATH`); `settingsSchemas`
|
|
105
|
+
cuts the part of a workflow schema each one edits, for the host to register at that path under a URI
|
|
106
|
+
of its own (the YAML service reads a `#fragment` as an anchor and stops validating):
|
|
107
|
+
|
|
108
|
+
```ts
|
|
109
|
+
const { job, step, input, settings } = settingsSchemas(workflowSchema)
|
|
110
|
+
configureEditorYaml([
|
|
111
|
+
{ fileMatch: [JOB_YAML_PATH], uri: `${origin}/workflow-job.schema.json`, schema: job },
|
|
112
|
+
// ...and the same for step, input and settings
|
|
113
|
+
])
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
Without them, those views still edit, but check nothing against the schema.
|
|
117
|
+
|
|
102
118
|
## AI chat
|
|
103
119
|
|
|
104
120
|
`@parallelworks/ui/ai` is a chat interface (thread, composer, streaming,
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
declare const REQUESTABLE_PERMISSION_MODES: readonly ['read-only', 'accept-edits', 'bypass-permissions'];
|
|
2
|
-
export declare const NAMED_PERMISSION_MODES: readonly ["read-only", "accept-edits", "bypass-permissions", "plan"];
|
|
1
|
+
declare const REQUESTABLE_PERMISSION_MODES: readonly ['read-only', 'accept-edits', 'auto', 'bypass-permissions'];
|
|
2
|
+
export declare const NAMED_PERMISSION_MODES: readonly ["read-only", "accept-edits", "auto", "bypass-permissions", "plan"];
|
|
3
3
|
export type PermissionMode = (typeof REQUESTABLE_PERMISSION_MODES)[number];
|
|
4
4
|
export type NamedPermissionMode = (typeof NAMED_PERMISSION_MODES)[number];
|
|
5
5
|
export declare const DEFAULT_PERMISSION_MODE: PermissionMode;
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
var REQUESTABLE_PERMISSION_MODES = [
|
|
3
3
|
"read-only",
|
|
4
4
|
"accept-edits",
|
|
5
|
+
"auto",
|
|
5
6
|
"bypass-permissions"
|
|
6
7
|
];
|
|
7
8
|
var NAMED_PERMISSION_MODES = [...REQUESTABLE_PERMISSION_MODES, "plan"];
|
|
@@ -10,7 +11,8 @@ var PERMISSION_RANK = {
|
|
|
10
11
|
"read-only": 0,
|
|
11
12
|
plan: 1,
|
|
12
13
|
"accept-edits": 2,
|
|
13
|
-
|
|
14
|
+
auto: 3,
|
|
15
|
+
"bypass-permissions": 4
|
|
14
16
|
};
|
|
15
17
|
function isNamedPermissionMode(mode) {
|
|
16
18
|
return NAMED_PERMISSION_MODES.some((m) => m === mode);
|
|
@@ -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
|
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/strings.d.ts
CHANGED
|
@@ -163,10 +163,12 @@ export interface ChatStrings {
|
|
|
163
163
|
choose: string;
|
|
164
164
|
readOnly: string;
|
|
165
165
|
acceptEdits: string;
|
|
166
|
+
auto: string;
|
|
166
167
|
bypassPermissions: string;
|
|
167
168
|
plan: string;
|
|
168
169
|
readOnlyHint: string;
|
|
169
170
|
acceptEditsHint: string;
|
|
171
|
+
autoHint: string;
|
|
170
172
|
bypassPermissionsHint: string;
|
|
171
173
|
planHint: string;
|
|
172
174
|
};
|
package/dist/ai/strings.js
CHANGED
|
@@ -163,10 +163,12 @@ var defaultChatStrings = {
|
|
|
163
163
|
choose: "Choose what the agent may do",
|
|
164
164
|
readOnly: "Read only",
|
|
165
165
|
acceptEdits: "Accept edits",
|
|
166
|
+
auto: "Auto",
|
|
166
167
|
bypassPermissions: "Bypass permissions",
|
|
167
168
|
plan: "Plan",
|
|
168
169
|
readOnlyHint: "The workspace can be read but not changed.",
|
|
169
170
|
acceptEditsHint: "File edits are applied without asking. The workspace can be changed without your review.",
|
|
171
|
+
autoHint: "File edits are applied without asking. An automatic reviewer approves or denies most actions that would ask you.",
|
|
170
172
|
bypassPermissionsHint: "Every action is taken without asking, including commands that change the system.",
|
|
171
173
|
planHint: "The workspace is left unchanged while a plan is drafted."
|
|
172
174
|
},
|
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 };
|
|
@@ -22,5 +22,7 @@ export interface IProps {
|
|
|
22
22
|
portalEl?: HTMLElement;
|
|
23
23
|
/** Smaller option rows and text, for dense toolbars. */
|
|
24
24
|
compact?: boolean | undefined;
|
|
25
|
+
/** False hides the caret, for a field that has nothing to pick from yet. */
|
|
26
|
+
showCaret?: boolean | undefined;
|
|
25
27
|
}
|
|
26
28
|
export default function Dropdown(props: IProps): import("react").JSX.Element;
|
|
@@ -129,7 +129,7 @@ function ToggleOption({ option, category, expanded, onToggle, ...virtualRowProps
|
|
|
129
129
|
})
|
|
130
130
|
});
|
|
131
131
|
}
|
|
132
|
-
function DropdownHelper({ wrapperClassName = "w-full", className, textBoxClassName = "w-full", options = [], onChange, onActiveChange, value, id, ariaLabel, "aria-describedby": describedBy, required, disabled = false, placeholder = "", loading = false, allowCustomValue = false, customValueLabel = "Use", collapsedLabel = defaultCollapsedLabel, portalEl, compact = false }) {
|
|
132
|
+
function DropdownHelper({ wrapperClassName = "w-full", className, textBoxClassName = "w-full", options = [], onChange, onActiveChange, value, id, ariaLabel, "aria-describedby": describedBy, required, disabled = false, placeholder = "", loading = false, allowCustomValue = false, customValueLabel = "Use", collapsedLabel = defaultCollapsedLabel, portalEl, compact = false, showCaret = true }) {
|
|
133
133
|
const DEBOUNCE_MS = 500;
|
|
134
134
|
const t = useStrings().dropdown;
|
|
135
135
|
const [query, setQuery] = useState("");
|
|
@@ -164,6 +164,11 @@ function DropdownHelper({ wrapperClassName = "w-full", className, textBoxClassNa
|
|
|
164
164
|
}
|
|
165
165
|
setBoundaryEl(dialog);
|
|
166
166
|
}, [referenceElement]);
|
|
167
|
+
useEffect(() => {
|
|
168
|
+
if (!referenceElement) return;
|
|
169
|
+
if (describedBy) referenceElement.setAttribute("aria-describedby", describedBy);
|
|
170
|
+
else referenceElement.removeAttribute("aria-describedby");
|
|
171
|
+
}, [referenceElement, describedBy]);
|
|
167
172
|
const sameWidthModifier = useMemo(() => ({
|
|
168
173
|
name: "sameWidth",
|
|
169
174
|
enabled: true,
|
|
@@ -336,7 +341,7 @@ function DropdownHelper({ wrapperClassName = "w-full", className, textBoxClassNa
|
|
|
336
341
|
/* @__PURE__ */ jsx(ComboboxButton, {
|
|
337
342
|
ref: buttonRef,
|
|
338
343
|
"aria-label": t.showOptions,
|
|
339
|
-
className: "absolute inset-y-0 right-0 flex items-center pr-3 disabled:cursor-not-allowed",
|
|
344
|
+
className: cx("absolute inset-y-0 right-0 flex items-center pr-3 disabled:cursor-not-allowed", !showCaret && "hidden"),
|
|
340
345
|
"data-testid": "combobox-button",
|
|
341
346
|
disabled,
|
|
342
347
|
children: /* @__PURE__ */ jsx(DropdownCaret, {})
|
|
@@ -1,14 +1,19 @@
|
|
|
1
1
|
import type { InputHTMLAttributes, ReactNode, TextareaHTMLAttributes } from 'react';
|
|
2
|
-
interface
|
|
2
|
+
interface FieldProps {
|
|
3
3
|
label?: ReactNode;
|
|
4
|
+
/** Shown beside the label, outside it, so it stays out of the field's name. */
|
|
5
|
+
labelHint?: ReactNode;
|
|
6
|
+
/** Help text shown under the label. */
|
|
7
|
+
description?: ReactNode;
|
|
4
8
|
error?: string | undefined;
|
|
5
9
|
mono?: boolean;
|
|
6
10
|
}
|
|
7
|
-
|
|
8
|
-
interface TextareaProps extends TextareaHTMLAttributes<HTMLTextAreaElement> {
|
|
9
|
-
label?: string;
|
|
10
|
-
error?: string;
|
|
11
|
-
mono?: boolean;
|
|
11
|
+
interface InputProps extends InputHTMLAttributes<HTMLInputElement>, FieldProps {
|
|
12
12
|
}
|
|
13
|
+
interface TextareaProps extends TextareaHTMLAttributes<HTMLTextAreaElement>, FieldProps {
|
|
14
|
+
}
|
|
15
|
+
/** The box a text field draws, for other controls that should look like one. */
|
|
16
|
+
export declare const fieldBoxClasses: string;
|
|
17
|
+
export declare const Input: import("react").ForwardRefExoticComponent<InputProps & import("react").RefAttributes<HTMLInputElement>>;
|
|
13
18
|
export declare const Textarea: import("react").ForwardRefExoticComponent<TextareaProps & import("react").RefAttributes<HTMLTextAreaElement>>;
|
|
14
19
|
export {};
|
package/dist/components/Input.js
CHANGED
|
@@ -6,85 +6,104 @@ import cx from "classnames";
|
|
|
6
6
|
import { forwardRef, useId, useState } from "react";
|
|
7
7
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
8
8
|
//#region src/components/Input.tsx
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
const
|
|
9
|
+
/** The box a text field draws, for other controls that should look like one. */
|
|
10
|
+
var fieldBoxClasses = cx("w-full py-3 px-4 bg-[var(--theme-muted-panel-bg)] border border-[var(--theme-border)] rounded-lg text-[var(--theme-app)] text-sm transition-all duration-200 box-border", "focus:outline-none focus:border-[var(--theme-element)] focus:shadow-[0_0_0_3px_color-mix(in_srgb,var(--theme-element)_25%,transparent)]", "placeholder:text-[var(--theme-muted-text-color)]");
|
|
11
|
+
function LabelRow({ id, label, hint, required }) {
|
|
12
|
+
const element = /* @__PURE__ */ jsxs("label", {
|
|
13
|
+
className: "text-[0.8125rem] font-medium text-[var(--theme-app)]",
|
|
14
|
+
htmlFor: id,
|
|
15
|
+
children: [label, required && /* @__PURE__ */ jsx(RequiredMark, {})]
|
|
16
|
+
});
|
|
17
|
+
return hint ? /* @__PURE__ */ jsxs("div", {
|
|
18
|
+
className: "flex flex-wrap items-baseline gap-x-1.5",
|
|
19
|
+
children: [element, hint]
|
|
20
|
+
}) : element;
|
|
21
|
+
}
|
|
22
|
+
function useFieldFrame({ label, labelHint, description, error }, ownId, describedBy, required) {
|
|
13
23
|
const generatedId = useId();
|
|
14
|
-
const id =
|
|
24
|
+
const id = ownId ?? generatedId;
|
|
15
25
|
const errorId = `${id}-error`;
|
|
16
|
-
const
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
children: [/* @__PURE__ */ jsx("input", {
|
|
29
|
-
ref,
|
|
30
|
-
type: inputType,
|
|
31
|
-
className: inputClasses,
|
|
32
|
-
...props,
|
|
26
|
+
const descriptionId = `${id}-description`;
|
|
27
|
+
return {
|
|
28
|
+
id,
|
|
29
|
+
describedBy: [
|
|
30
|
+
describedBy,
|
|
31
|
+
description ? descriptionId : void 0,
|
|
32
|
+
error ? errorId : void 0
|
|
33
|
+
].filter(Boolean).join(" ") || void 0,
|
|
34
|
+
frame: (control) => /* @__PURE__ */ jsxs("div", {
|
|
35
|
+
className: "flex flex-col gap-1.5",
|
|
36
|
+
children: [
|
|
37
|
+
label && /* @__PURE__ */ jsx(LabelRow, {
|
|
33
38
|
id,
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
}),
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
39
|
+
label,
|
|
40
|
+
hint: labelHint,
|
|
41
|
+
required
|
|
42
|
+
}),
|
|
43
|
+
description && /* @__PURE__ */ jsx("span", {
|
|
44
|
+
id: descriptionId,
|
|
45
|
+
className: "-mt-1 text-xs text-(--theme-muted-text-color)",
|
|
46
|
+
children: description
|
|
47
|
+
}),
|
|
48
|
+
control,
|
|
49
|
+
error && /* @__PURE__ */ jsxs("span", {
|
|
50
|
+
id: errorId,
|
|
51
|
+
role: "alert",
|
|
52
|
+
className: "text-[0.8125rem] text-[#ef4444] flex items-center gap-1.5",
|
|
53
|
+
children: [/* @__PURE__ */ jsx(TbAlertTriangle, { className: "w-4 h-4" }), error]
|
|
54
|
+
})
|
|
55
|
+
]
|
|
56
|
+
})
|
|
57
|
+
};
|
|
58
|
+
}
|
|
59
|
+
var Input = forwardRef(({ label, labelHint, description, error, className = "", mono, type, required, ...props }, ref) => {
|
|
60
|
+
const [showPassword, setShowPassword] = useState(false);
|
|
61
|
+
const isPassword = type === "password";
|
|
62
|
+
const field = useFieldFrame({
|
|
63
|
+
label,
|
|
64
|
+
labelHint,
|
|
65
|
+
description,
|
|
66
|
+
error
|
|
67
|
+
}, props.id, props["aria-describedby"], required);
|
|
68
|
+
return field.frame(/* @__PURE__ */ jsxs("div", {
|
|
69
|
+
className: isPassword ? "relative w-full" : "",
|
|
70
|
+
children: [/* @__PURE__ */ jsx("input", {
|
|
71
|
+
ref,
|
|
72
|
+
type: isPassword && showPassword ? "text" : type,
|
|
73
|
+
className: cx(fieldBoxClasses, "disabled:bg-[var(--theme-muted-panel-bg)] disabled:text-[var(--theme-muted-text-color)] disabled:cursor-not-allowed disabled:opacity-70", mono && "font-mono text-[0.8125rem]", error && "!border-[#ef4444]", isPassword && "pr-11", className),
|
|
74
|
+
...props,
|
|
75
|
+
id: field.id,
|
|
76
|
+
required,
|
|
77
|
+
"aria-invalid": error ? true : props["aria-invalid"],
|
|
78
|
+
"aria-describedby": field.describedBy
|
|
79
|
+
}), isPassword && /* @__PURE__ */ jsx("button", {
|
|
80
|
+
type: "button",
|
|
81
|
+
className: "absolute right-3 top-1/2 -translate-y-1/2 bg-transparent border-none text-[var(--theme-muted-text-color)] cursor-pointer p-1 transition-colors duration-200 flex items-center justify-center hover:text-[var(--theme-app)]",
|
|
82
|
+
onClick: () => setShowPassword(!showPassword),
|
|
83
|
+
tabIndex: -1,
|
|
84
|
+
"aria-label": showPassword ? "Hide password" : "Show password",
|
|
85
|
+
children: showPassword ? /* @__PURE__ */ jsx(LuEyeOff, { className: "w-5 h-5" }) : /* @__PURE__ */ jsx(LuEye, { className: "w-5 h-5" })
|
|
86
|
+
})]
|
|
87
|
+
}));
|
|
54
88
|
});
|
|
55
89
|
Input.displayName = "Input";
|
|
56
|
-
var Textarea = forwardRef(({ label, error, className = "", mono, required, ...props }, ref) => {
|
|
57
|
-
const
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
className: textareaClasses,
|
|
73
|
-
...props,
|
|
74
|
-
id,
|
|
75
|
-
required,
|
|
76
|
-
"aria-invalid": error ? true : props["aria-invalid"],
|
|
77
|
-
"aria-describedby": describedBy
|
|
78
|
-
}),
|
|
79
|
-
error && /* @__PURE__ */ jsxs("span", {
|
|
80
|
-
id: errorId,
|
|
81
|
-
role: "alert",
|
|
82
|
-
className: "text-[0.8125rem] text-[#ef4444] flex items-center gap-1.5",
|
|
83
|
-
children: [/* @__PURE__ */ jsx(TbAlertTriangle, { className: "w-4 h-4" }), error]
|
|
84
|
-
})
|
|
85
|
-
]
|
|
86
|
-
});
|
|
90
|
+
var Textarea = forwardRef(({ label, labelHint, description, error, className = "", mono, required, ...props }, ref) => {
|
|
91
|
+
const field = useFieldFrame({
|
|
92
|
+
label,
|
|
93
|
+
labelHint,
|
|
94
|
+
description,
|
|
95
|
+
error
|
|
96
|
+
}, props.id, props["aria-describedby"], required);
|
|
97
|
+
return field.frame(/* @__PURE__ */ jsx("textarea", {
|
|
98
|
+
ref,
|
|
99
|
+
className: cx(fieldBoxClasses, "min-h-[140px] resize-y", mono && "font-mono text-[0.8125rem]", error && "!border-[#ef4444]", className),
|
|
100
|
+
...props,
|
|
101
|
+
id: field.id,
|
|
102
|
+
required,
|
|
103
|
+
"aria-invalid": error ? true : props["aria-invalid"],
|
|
104
|
+
"aria-describedby": field.describedBy
|
|
105
|
+
}));
|
|
87
106
|
});
|
|
88
107
|
Textarea.displayName = "Textarea";
|
|
89
108
|
//#endregion
|
|
90
|
-
export { Input, Textarea };
|
|
109
|
+
export { Input, Textarea, fieldBoxClasses };
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import type { Dispatch, ReactNode, SetStateAction } from 'react';
|
|
2
|
+
import type { WorkflowAction, WorkflowEditing } from '../editing.js';
|
|
2
3
|
import type { WorkflowEngine } from '../engine.js';
|
|
4
|
+
import type { GraphEditorStrings, InputsEditorStrings } from '../graph/editorStrings.js';
|
|
3
5
|
import type { RunLink } from '../graph/types.js';
|
|
4
6
|
export type UIToastId = string | number;
|
|
5
7
|
export interface UIToastOptions {
|
|
@@ -118,6 +120,9 @@ export interface UIStrings {
|
|
|
118
120
|
openOriginalWorkflow: string;
|
|
119
121
|
openInNewGraph: string;
|
|
120
122
|
};
|
|
123
|
+
/** The visual editor's text a host translates; the editor fills in the rest in English. */
|
|
124
|
+
graphEditor: Partial<GraphEditorStrings>;
|
|
125
|
+
inputsEditor: Partial<InputsEditorStrings>;
|
|
121
126
|
fileExplorer: {
|
|
122
127
|
preview: {
|
|
123
128
|
shareFile: string;
|
|
@@ -348,6 +353,8 @@ export interface UIStrings {
|
|
|
348
353
|
copied: (label: string) => string;
|
|
349
354
|
couldntCopy: (label: string) => string;
|
|
350
355
|
moreActions: string;
|
|
356
|
+
/** A toolbar toggle's name in the overflow menu, where a row can't be pressed. */
|
|
357
|
+
toggleState: (label: string, on: boolean) => string;
|
|
351
358
|
labelName: string;
|
|
352
359
|
labelEmail: string;
|
|
353
360
|
labelUsername: string;
|
|
@@ -392,6 +399,14 @@ export interface UINavigation {
|
|
|
392
399
|
openStepSource: (uses: string, sourceUrl?: string) => void;
|
|
393
400
|
openExternal: (href: string) => void;
|
|
394
401
|
}
|
|
402
|
+
export type WorkflowJsonRef = {
|
|
403
|
+
kind: 'marketplace';
|
|
404
|
+
slug: string;
|
|
405
|
+
version: string;
|
|
406
|
+
} | {
|
|
407
|
+
kind: 'workflow';
|
|
408
|
+
name: string;
|
|
409
|
+
};
|
|
395
410
|
export interface RunFileResult {
|
|
396
411
|
data: string | undefined;
|
|
397
412
|
isLoading: boolean;
|
|
@@ -407,6 +422,14 @@ export interface UIData {
|
|
|
407
422
|
useRunFile: (slug: string, path: string | null, options?: {
|
|
408
423
|
refreshInterval?: number;
|
|
409
424
|
}) => RunFileResult;
|
|
425
|
+
resolveWorkflowJson?: (ref: WorkflowJsonRef) => Promise<unknown>;
|
|
426
|
+
/** The built-in actions a workflow step can use, for the editor's step form. */
|
|
427
|
+
workflowActions?: Record<string, WorkflowAction>;
|
|
428
|
+
resolveSecretVariables?: () => Promise<string[]>;
|
|
429
|
+
/** Repository files, so the editor can read the workflow a step's repository `uses` names. */
|
|
430
|
+
repoSuggestions?: {
|
|
431
|
+
file: (repo: string, ref: string, path: string) => Promise<string>;
|
|
432
|
+
};
|
|
410
433
|
/**
|
|
411
434
|
* Provisions browser-access CORS rules on a storage. Absent, the storage
|
|
412
435
|
* explorer hides its "add CORS rules" affordance.
|
|
@@ -496,10 +519,18 @@ export type WorkflowEngineSource = WorkflowEngine | (() => Promise<WorkflowEngin
|
|
|
496
519
|
export declare function useNotify(): UINotify;
|
|
497
520
|
export declare function useStrings(): UIStrings;
|
|
498
521
|
export declare function useNavigation(): UINavigation;
|
|
522
|
+
export declare function useWorkflowJsonResolver(): UIData['resolveWorkflowJson'];
|
|
523
|
+
export declare function useRepoSuggestions(): UIData['repoSuggestions'];
|
|
524
|
+
export declare function useWorkflowActions(): Record<string, WorkflowAction>;
|
|
525
|
+
export declare function useSecretVariablesResolver(): UIData['resolveSecretVariables'];
|
|
499
526
|
export declare function useSlots(): UISlots;
|
|
500
527
|
/** The engine when one is provided and `enabled`; suspends while a loader resolves. */
|
|
501
528
|
export declare function useOptionalWorkflowEngine(enabled?: boolean): WorkflowEngine | undefined;
|
|
502
529
|
export declare function useWorkflowEngine(): WorkflowEngine;
|
|
530
|
+
/** The engine once it has loaded, without suspending; renders again when a loader resolves. */
|
|
531
|
+
export declare function useLoadedWorkflowEngine(): WorkflowEngine | undefined;
|
|
532
|
+
/** The engine's workflow editing, which the visual editor can't work without. */
|
|
533
|
+
export declare function useWorkflowEditing(): WorkflowEditing;
|
|
503
534
|
/** Resolves the engine without suspending, for async callers such as editor completions. */
|
|
504
535
|
export declare function useWorkflowEngineLoader(): () => Promise<WorkflowEngine | undefined>;
|
|
505
536
|
export declare function useProvisionCorsRules(): UIData['provisionCorsRules'];
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { safeUrl } from "../safeUrl.js";
|
|
2
|
-
import { createContext, use, useCallback, useContext, useEffect, useMemo } from "react";
|
|
2
|
+
import { createContext, use, useCallback, useContext, useEffect, useMemo, useState } from "react";
|
|
3
3
|
import { useLocalStorage } from "usehooks-ts";
|
|
4
4
|
import { Fragment as Fragment$1, jsx, jsxs } from "react/jsx-runtime";
|
|
5
5
|
//#region src/components/Provider.tsx
|
|
@@ -122,6 +122,8 @@ var DEFAULTS = {
|
|
|
122
122
|
openOriginalWorkflow: "Open original workflow",
|
|
123
123
|
openInNewGraph: "Open in new graph"
|
|
124
124
|
},
|
|
125
|
+
graphEditor: {},
|
|
126
|
+
inputsEditor: {},
|
|
125
127
|
fileExplorer: {
|
|
126
128
|
preview: {
|
|
127
129
|
shareFile: "Share file",
|
|
@@ -348,6 +350,7 @@ var DEFAULTS = {
|
|
|
348
350
|
copied: (label) => `Copied ${label}`,
|
|
349
351
|
couldntCopy: (label) => `Couldn't copy ${label}`,
|
|
350
352
|
moreActions: "More actions",
|
|
353
|
+
toggleState: (label, on) => `${label}, ${on ? "on" : "off"}`,
|
|
351
354
|
labelName: "name",
|
|
352
355
|
labelEmail: "email",
|
|
353
356
|
labelUsername: "username",
|
|
@@ -442,6 +445,19 @@ function useStrings() {
|
|
|
442
445
|
function useNavigation() {
|
|
443
446
|
return useContext(UIContext).navigation;
|
|
444
447
|
}
|
|
448
|
+
function useWorkflowJsonResolver() {
|
|
449
|
+
return useContext(UIContext).data.resolveWorkflowJson;
|
|
450
|
+
}
|
|
451
|
+
function useRepoSuggestions() {
|
|
452
|
+
return useContext(UIContext).data.repoSuggestions;
|
|
453
|
+
}
|
|
454
|
+
var NO_ACTIONS = {};
|
|
455
|
+
function useWorkflowActions() {
|
|
456
|
+
return useContext(UIContext).data.workflowActions ?? NO_ACTIONS;
|
|
457
|
+
}
|
|
458
|
+
function useSecretVariablesResolver() {
|
|
459
|
+
return useContext(UIContext).data.resolveSecretVariables;
|
|
460
|
+
}
|
|
445
461
|
function useSlots() {
|
|
446
462
|
return useContext(UIContext).slots;
|
|
447
463
|
}
|
|
@@ -474,6 +490,30 @@ function useWorkflowEngine() {
|
|
|
474
490
|
if (!source) throw new Error("Workflow forms and graphs need a UIProvider with an engine.");
|
|
475
491
|
return resolveEngine(source);
|
|
476
492
|
}
|
|
493
|
+
/** The engine once it has loaded, without suspending; renders again when a loader resolves. */
|
|
494
|
+
function useLoadedWorkflowEngine() {
|
|
495
|
+
const source = useContext(UIContext).engine;
|
|
496
|
+
const [, setLoaded] = useState(0);
|
|
497
|
+
const entry = typeof source === "function" ? loadEngine(source) : void 0;
|
|
498
|
+
const engine = typeof source === "function" ? entry?.engine : source;
|
|
499
|
+
useEffect(() => {
|
|
500
|
+
if (!entry || entry.engine) return;
|
|
501
|
+
let live = true;
|
|
502
|
+
entry.promise.then(() => {
|
|
503
|
+
if (live) setLoaded((n) => n + 1);
|
|
504
|
+
});
|
|
505
|
+
return () => {
|
|
506
|
+
live = false;
|
|
507
|
+
};
|
|
508
|
+
}, [entry]);
|
|
509
|
+
return engine;
|
|
510
|
+
}
|
|
511
|
+
/** The engine's workflow editing, which the visual editor can't work without. */
|
|
512
|
+
function useWorkflowEditing() {
|
|
513
|
+
const { editing } = useWorkflowEngine();
|
|
514
|
+
if (!editing) throw new Error("The workflow editor needs a UIProvider engine with editing.");
|
|
515
|
+
return editing;
|
|
516
|
+
}
|
|
477
517
|
/** Resolves the engine without suspending, for async callers such as editor completions. */
|
|
478
518
|
function useWorkflowEngineLoader() {
|
|
479
519
|
const source = useContext(UIContext).engine;
|
|
@@ -528,6 +568,14 @@ function UIProvider({ notify, strings, navigation, data, slots, engine, children
|
|
|
528
568
|
...DEFAULTS.strings.jobActions,
|
|
529
569
|
...strings?.jobActions
|
|
530
570
|
},
|
|
571
|
+
graphEditor: {
|
|
572
|
+
...DEFAULTS.strings.graphEditor,
|
|
573
|
+
...strings?.graphEditor
|
|
574
|
+
},
|
|
575
|
+
inputsEditor: {
|
|
576
|
+
...DEFAULTS.strings.inputsEditor,
|
|
577
|
+
...strings?.inputsEditor
|
|
578
|
+
},
|
|
531
579
|
fileExplorer: {
|
|
532
580
|
...DEFAULTS.strings.fileExplorer,
|
|
533
581
|
...strings?.fileExplorer
|
|
@@ -569,4 +617,4 @@ function UIProvider({ notify, strings, navigation, data, slots, engine, children
|
|
|
569
617
|
});
|
|
570
618
|
}
|
|
571
619
|
//#endregion
|
|
572
|
-
export { UIProvider, useLink, useNavigation, useNotify, useOptionalWorkflowEngine, usePersistedState, useProvisionCorsRules, useRunFile, useSlots, useStrings, useWorkflowEngine, useWorkflowEngineLoader };
|
|
620
|
+
export { UIProvider, useLink, useLoadedWorkflowEngine, useNavigation, useNotify, useOptionalWorkflowEngine, usePersistedState, useProvisionCorsRules, useRepoSuggestions, useRunFile, useSecretVariablesResolver, useSlots, useStrings, useWorkflowActions, useWorkflowEditing, useWorkflowEngine, useWorkflowEngineLoader, useWorkflowJsonResolver };
|