@parallelworks/ui 0.38.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/chatDraft.d.ts +7 -0
- package/dist/ai/components/chatDraft.js +66 -0
- 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/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 +4 -4
- package/dist/graph/InputsEditor.js +2 -2
- 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/WorkflowSettingsDialog.d.ts +21 -0
- package/dist/graph/WorkflowSettingsDialog.js +670 -0
- package/dist/graph/editorFields.js +144 -3
- 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 +1 -0
- package/dist/graph/expressionRefs.js +39 -0
- package/dist/graph/fieldProblems.js +36 -2
- package/dist/graph/graphEditorState.d.ts +191 -0
- package/dist/graph/graphEditorState.js +74 -0
- package/dist/graph/index.d.ts +3 -0
- package/dist/graph/index.js +5 -2
- package/dist/graph/inputLayout.js +1 -1
- package/dist/graph/inputRefs.js +196 -4
- package/dist/graph/refusalText.js +13 -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);
|
|
@@ -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/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 };
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
2
|
import type { GraphLayout } from '../editing.js';
|
|
3
3
|
import type { MatrixGroup, WorkflowEngine } from '../engine.js';
|
|
4
|
+
import type { DependencyGraphEditor } from './editorApi.js';
|
|
4
5
|
import { type RunLink, type WorkflowJob } from './types.js';
|
|
5
6
|
export type ViewMode = 'dag' | 'tree';
|
|
6
7
|
export declare const addCleanupSteps: ({ jobs }: {
|
|
@@ -17,6 +18,7 @@ export declare function computeGraphLayout(engine: WorkflowEngine, jobs: Record<
|
|
|
17
18
|
ancestorDists: Record<string, Map<string, number>>;
|
|
18
19
|
descendantDists: Record<string, Map<string, number>>;
|
|
19
20
|
};
|
|
21
|
+
export declare function intoView(start: number, end: number, low: number, high: number): number;
|
|
20
22
|
interface GraphRun {
|
|
21
23
|
id?: string | undefined;
|
|
22
24
|
number?: number | undefined;
|
|
@@ -29,20 +31,25 @@ interface GraphRun {
|
|
|
29
31
|
executedJobs?: Record<string, unknown> | undefined;
|
|
30
32
|
links?: Record<string, RunLink> | undefined;
|
|
31
33
|
}
|
|
32
|
-
export default function DependencyGraph({ run, preview, removeBorder, viewMode, setViewMode, layout, yamlJobs, fixedHeight, }: {
|
|
34
|
+
export default function DependencyGraph({ run, preview, removeBorder, viewMode, setViewMode, layout, editor, yamlJobs, inputs, workflow, fixedHeight, }: {
|
|
33
35
|
run: GraphRun;
|
|
34
36
|
preview?: boolean;
|
|
35
37
|
removeBorder?: boolean | undefined;
|
|
36
38
|
viewMode?: ViewMode;
|
|
37
39
|
setViewMode?: (mode: ViewMode) => void;
|
|
38
40
|
layout?: GraphLayout | undefined;
|
|
41
|
+
editor?: DependencyGraphEditor | undefined;
|
|
39
42
|
yamlJobs?: Record<string, unknown> | undefined;
|
|
43
|
+
inputs?: Record<string, unknown> | undefined;
|
|
44
|
+
/** The workflow as written, for what the editor's expressions can read. */
|
|
45
|
+
workflow?: Record<string, unknown> | undefined;
|
|
40
46
|
fixedHeight?: string | undefined;
|
|
41
47
|
}): React.JSX.Element | undefined;
|
|
42
48
|
export declare function DependencyGraphPreview(inputs: {
|
|
43
49
|
yml?: Record<string, unknown>;
|
|
44
50
|
removeBorder?: boolean;
|
|
45
51
|
layout?: GraphLayout | undefined;
|
|
52
|
+
editor?: DependencyGraphEditor | undefined;
|
|
46
53
|
/** A fixed panel height; without one the panel is only as tall as the graph. */
|
|
47
54
|
height?: string | undefined;
|
|
48
55
|
}): React.JSX.Element;
|