@parallelworks/ui 0.38.0 → 0.40.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/agent/permissions.d.ts +5 -4
- package/dist/ai/agent/permissions.js +15 -6
- package/dist/ai/components/ChatInput.js +8 -23
- package/dist/ai/components/agent/PermissionPicker.d.ts +3 -1
- package/dist/ai/components/agent/PermissionPicker.js +2 -2
- 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
|
@@ -9,18 +9,20 @@ import { Button } from "../components/Button.js";
|
|
|
9
9
|
import { ghostButtonClasses, primaryButtonClasses } from "../components/ghostButton.js";
|
|
10
10
|
import { FilterPill } from "../components/FilterPill.js";
|
|
11
11
|
import { IconButton } from "../components/IconButton.js";
|
|
12
|
-
import { Textarea } from "../components/Input.js";
|
|
12
|
+
import { Input, Textarea } from "../components/Input.js";
|
|
13
13
|
import { Toggle } from "../components/Toggle.js";
|
|
14
14
|
import { useGraphEditorStrings } from "./editorStrings.js";
|
|
15
|
-
import { useFieldLint } from "./fieldProblems.js";
|
|
16
15
|
import { asRecord } from "./records.js";
|
|
16
|
+
import { useFieldLint } from "./fieldProblems.js";
|
|
17
17
|
import { SuggestionInput } from "./SuggestionInput.js";
|
|
18
18
|
import cx from "classnames";
|
|
19
19
|
import { createContext, useContext, useEffect, useId, useLayoutEffect, useRef, useState } from "react";
|
|
20
20
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
21
21
|
//#region src/graph/editorFields.tsx
|
|
22
22
|
var EXPRESSION = /^\$\{\{.*\}\}$/;
|
|
23
|
+
var ENV_KEY = /^[a-zA-Z0-9_]+$/;
|
|
23
24
|
var EMPTY_EXPRESSION = /^\$\{\{\s*\}\}$/;
|
|
25
|
+
var DURATION = /^(\d+)(d|h|m|s)?$/;
|
|
24
26
|
function withoutUndefined(value) {
|
|
25
27
|
return Object.fromEntries(Object.entries(value).filter(([, item]) => item !== void 0));
|
|
26
28
|
}
|
|
@@ -59,10 +61,36 @@ function diffPatch(original, next) {
|
|
|
59
61
|
function isEmptyPatch(patch) {
|
|
60
62
|
return Object.keys(patch.set).length === 0 && patch.unset.length === 0;
|
|
61
63
|
}
|
|
64
|
+
function conditionText(value) {
|
|
65
|
+
return typeof value === "boolean" ? String(value) : text(value);
|
|
66
|
+
}
|
|
67
|
+
function parseCondition(value) {
|
|
68
|
+
const trimmed = value.trim();
|
|
69
|
+
if (!trimmed) return;
|
|
70
|
+
if (trimmed === "true" || trimmed === "false") return trimmed === "true";
|
|
71
|
+
return trimmed;
|
|
72
|
+
}
|
|
73
|
+
function durationError(value, t, pattern = DURATION) {
|
|
74
|
+
const trimmed = value.trim();
|
|
75
|
+
return !trimmed || pattern.test(trimmed) || EXPRESSION.test(trimmed) ? void 0 : t.invalidDuration;
|
|
76
|
+
}
|
|
62
77
|
function expressionError(value, t) {
|
|
63
78
|
const trimmed = value.trim();
|
|
64
79
|
return !trimmed || EXPRESSION.test(trimmed) && !EMPTY_EXPRESSION.test(trimmed) ? void 0 : t.invalidExpressionValue;
|
|
65
80
|
}
|
|
81
|
+
function orUndefined(value) {
|
|
82
|
+
return value.trim() ? value.trim() : void 0;
|
|
83
|
+
}
|
|
84
|
+
function countError(value, min, message) {
|
|
85
|
+
const trimmed = value.trim();
|
|
86
|
+
if (!trimmed || EXPRESSION.test(trimmed)) return;
|
|
87
|
+
return /^\d+$/.test(trimmed) && Number(trimmed) >= min ? void 0 : message;
|
|
88
|
+
}
|
|
89
|
+
function parseCount(value) {
|
|
90
|
+
const trimmed = value.trim();
|
|
91
|
+
if (!trimmed) return;
|
|
92
|
+
return /^\d+$/.test(trimmed) ? Number(trimmed) : trimmed;
|
|
93
|
+
}
|
|
66
94
|
function parseJson(value) {
|
|
67
95
|
try {
|
|
68
96
|
return {
|
|
@@ -76,6 +104,39 @@ function parseJson(value) {
|
|
|
76
104
|
function unchangedValue(text, original, nested = false) {
|
|
77
105
|
return original !== void 0 && text === (nested ? JSON.stringify(original) : String(original));
|
|
78
106
|
}
|
|
107
|
+
/** Rows for a map; with `nested` false a non-scalar is shown as its JSON text and saved as a string. */
|
|
108
|
+
function rowsFrom(value, nested = true) {
|
|
109
|
+
return Object.entries(asRecord(value)).map(([key, item]) => isScalar(item) ? {
|
|
110
|
+
key,
|
|
111
|
+
value: String(item),
|
|
112
|
+
original: item
|
|
113
|
+
} : nested ? {
|
|
114
|
+
key,
|
|
115
|
+
value: JSON.stringify(item),
|
|
116
|
+
nested: true,
|
|
117
|
+
original: item
|
|
118
|
+
} : {
|
|
119
|
+
key,
|
|
120
|
+
value: JSON.stringify(item) ?? ""
|
|
121
|
+
});
|
|
122
|
+
}
|
|
123
|
+
function rowsTo(rows, parse) {
|
|
124
|
+
if (rows.length === 0) return;
|
|
125
|
+
return Object.fromEntries(rows.map((row) => [row.key.trim(), unchangedValue(row.value, row.original, row.nested) ? row.original : row.nested ? parseJson(row.value).value : parse(row.value)]));
|
|
126
|
+
}
|
|
127
|
+
function rowsError(rows, keyPattern, keyMessage, t, valueError) {
|
|
128
|
+
const keys = rows.map((row) => row.key.trim());
|
|
129
|
+
for (const [i, row] of rows.entries()) {
|
|
130
|
+
const key = keys[i] ?? "";
|
|
131
|
+
if (!keyPattern.test(key)) return keyMessage;
|
|
132
|
+
if (keys.indexOf(key) !== i) return t.duplicateKey;
|
|
133
|
+
const error = row.nested ? parseJson(row.value).ok ? void 0 : t.invalidJson : valueError?.(row.value);
|
|
134
|
+
if (error) return error;
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
function flagOf(value) {
|
|
138
|
+
return typeof value === "boolean" || typeof value === "string" ? value : void 0;
|
|
139
|
+
}
|
|
79
140
|
function flagError(value, t) {
|
|
80
141
|
return typeof value === "string" ? expressionError(value, t) : void 0;
|
|
81
142
|
}
|
|
@@ -234,6 +295,86 @@ function AddRowButton({ label, onClick }) {
|
|
|
234
295
|
children: label
|
|
235
296
|
}) });
|
|
236
297
|
}
|
|
298
|
+
function KeyValueEditor({ rows, onChange, error, valuePlaceholder, keyPlaceholder, addLabel, valueSuggestions = [], lint = false }) {
|
|
299
|
+
const t = useGraphEditorStrings();
|
|
300
|
+
return /* @__PURE__ */ jsxs("div", {
|
|
301
|
+
className: "flex flex-col gap-2",
|
|
302
|
+
children: [
|
|
303
|
+
withPositionKeys(rows).map(({ key, item: row }, i) => /* @__PURE__ */ jsx(KeyValueRow, {
|
|
304
|
+
row,
|
|
305
|
+
onChange: (next) => onChange(updateAt(rows, i, next)),
|
|
306
|
+
onRemove: () => onChange(removeAt(rows, i)),
|
|
307
|
+
keyPlaceholder: keyPlaceholder ?? t.key,
|
|
308
|
+
valuePlaceholder: valuePlaceholder ?? t.value,
|
|
309
|
+
valueSuggestions,
|
|
310
|
+
lint
|
|
311
|
+
}, key)),
|
|
312
|
+
/* @__PURE__ */ jsx(FieldError, { message: error }),
|
|
313
|
+
/* @__PURE__ */ jsx(AddRowButton, {
|
|
314
|
+
label: addLabel ?? t.addRow,
|
|
315
|
+
onClick: () => onChange([...rows, {
|
|
316
|
+
key: "",
|
|
317
|
+
value: ""
|
|
318
|
+
}])
|
|
319
|
+
})
|
|
320
|
+
]
|
|
321
|
+
});
|
|
322
|
+
}
|
|
323
|
+
function KeyValueRow({ row, onChange, onRemove, keyPlaceholder, valuePlaceholder, valueSuggestions, lint: linted }) {
|
|
324
|
+
const t = useGraphEditorStrings();
|
|
325
|
+
const id = useId();
|
|
326
|
+
const lint = useFieldLint(linted ? row.key.trim() || void 0 : void 0, id, row.value, (value) => onChange({
|
|
327
|
+
...row,
|
|
328
|
+
value
|
|
329
|
+
}));
|
|
330
|
+
return /* @__PURE__ */ jsxs("div", {
|
|
331
|
+
className: "flex flex-col gap-1.5",
|
|
332
|
+
children: [
|
|
333
|
+
/* @__PURE__ */ jsxs("div", {
|
|
334
|
+
className: "flex items-center gap-2",
|
|
335
|
+
children: [
|
|
336
|
+
/* @__PURE__ */ jsx("div", {
|
|
337
|
+
className: "w-2/5",
|
|
338
|
+
children: /* @__PURE__ */ jsx(Input, {
|
|
339
|
+
mono: true,
|
|
340
|
+
"aria-label": t.key,
|
|
341
|
+
placeholder: keyPlaceholder,
|
|
342
|
+
value: row.key,
|
|
343
|
+
onChange: (e) => onChange({
|
|
344
|
+
...row,
|
|
345
|
+
key: e.target.value
|
|
346
|
+
})
|
|
347
|
+
})
|
|
348
|
+
}),
|
|
349
|
+
/* @__PURE__ */ jsx("div", {
|
|
350
|
+
className: "flex-1",
|
|
351
|
+
title: row.nested ? t.jsonValue : void 0,
|
|
352
|
+
children: /* @__PURE__ */ jsx(SuggestionInput, {
|
|
353
|
+
id,
|
|
354
|
+
ariaLabel: t.value,
|
|
355
|
+
placeholder: valuePlaceholder,
|
|
356
|
+
value: row.value,
|
|
357
|
+
suggestions: valueSuggestions.map((value) => ({ value })),
|
|
358
|
+
onChange: (value) => onChange({
|
|
359
|
+
...row,
|
|
360
|
+
value
|
|
361
|
+
})
|
|
362
|
+
})
|
|
363
|
+
}),
|
|
364
|
+
/* @__PURE__ */ jsx(IconButton, {
|
|
365
|
+
icon: /* @__PURE__ */ jsx(IoMdClose, { className: "h-4 w-4" }),
|
|
366
|
+
label: t.removeRow,
|
|
367
|
+
variant: "ghost",
|
|
368
|
+
size: "sm",
|
|
369
|
+
onClick: onRemove
|
|
370
|
+
})
|
|
371
|
+
]
|
|
372
|
+
}),
|
|
373
|
+
/* @__PURE__ */ jsx(FieldError, { message: lint.message }),
|
|
374
|
+
lint.fixes
|
|
375
|
+
]
|
|
376
|
+
});
|
|
377
|
+
}
|
|
237
378
|
function updateAt(items, index, item) {
|
|
238
379
|
return items.map((current, i) => i === index ? item : current);
|
|
239
380
|
}
|
|
@@ -391,4 +532,4 @@ function DialogShell({ title, onClose, onSubmit, saveDisabled, dirty, locked = f
|
|
|
391
532
|
});
|
|
392
533
|
}
|
|
393
534
|
//#endregion
|
|
394
|
-
export { AddRowButton, ChoiceButtons, DialogShell, EXPRESSION, ExpressionToggle, FieldError, FieldLabel, GROWING_AREA, GrowingTextarea, KeyHint, LabelledField, Section, SectionMemory, StringListEditor, SuggestedInput, ToggleField, asRecord, diffPatch, expressionError, flagError, flagValue, isEmptyPatch, isScalar, labelled, openOnAddOf, parseJson, parseScalar, removeAt, sameValue, text, unchangedValue, updateAt, useGrowingArea, useSectionMemory, withoutUndefined };
|
|
535
|
+
export { AddRowButton, ChoiceButtons, DURATION, DialogShell, ENV_KEY, EXPRESSION, ExpressionToggle, FieldError, FieldLabel, GROWING_AREA, GrowingTextarea, KeyHint, KeyValueEditor, LabelledField, Section, SectionMemory, StringListEditor, SuggestedInput, ToggleField, asRecord, conditionText, countError, diffPatch, durationError, expressionError, flagError, flagOf, flagValue, isEmptyPatch, isScalar, labelled, openOnAddOf, orUndefined, parseCondition, parseCount, parseJson, parseScalar, removeAt, rowsError, rowsFrom, rowsTo, sameValue, text, unchangedValue, updateAt, useGrowingArea, useSectionMemory, withoutUndefined };
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import { type ReactNode } from 'react';
|
|
2
|
+
import { type Point } from './editorPrimitives.js';
|
|
3
|
+
import { type EdgeSelection } from './graphEditorState.js';
|
|
4
|
+
/** Drop indicators, the connection line and the selection, drawn in the graph's own coordinates. */
|
|
5
|
+
export declare function GraphEditorCanvas(): import("react").JSX.Element | null;
|
|
6
|
+
/** A multi-job box's handle for moving all its jobs at once. */
|
|
7
|
+
export declare function BoxGrip({ jobs }: {
|
|
8
|
+
jobs: string[];
|
|
9
|
+
}): import("react").JSX.Element | null;
|
|
10
|
+
/** A job row made draggable, with its menu and matrix badge; shift-click selects it. */
|
|
11
|
+
export declare function EditableJobRow({ job, label, badge, children, }: {
|
|
12
|
+
job: string;
|
|
13
|
+
label: string;
|
|
14
|
+
badge?: boolean;
|
|
15
|
+
children: ReactNode;
|
|
16
|
+
}): string | number | bigint | boolean | import("react").JSX.Element | Iterable<ReactNode> | Promise<string | number | bigint | boolean | Iterable<ReactNode> | import("react").ReactElement<unknown, string | import("react").JSXElementConstructor<any>> | import("react").ReactPortal | null | undefined> | null | undefined;
|
|
17
|
+
/**
|
|
18
|
+
* A node's connector circles, where the graph draws its connector dots. Drag from the
|
|
19
|
+
* right one to add jobs that depend on the node, from the left one to add what it needs.
|
|
20
|
+
*/
|
|
21
|
+
export declare function NodePorts({ jobs, left, right, drawLeft, drawRight, zIndex, }: {
|
|
22
|
+
jobs: string[];
|
|
23
|
+
left: Point;
|
|
24
|
+
right: Point;
|
|
25
|
+
drawLeft: boolean;
|
|
26
|
+
drawRight: boolean;
|
|
27
|
+
zIndex: number;
|
|
28
|
+
}): import("react").JSX.Element | null;
|
|
29
|
+
/** A step row made draggable within its job, with its menu. */
|
|
30
|
+
export declare function EditableStepRow({ job, index, label, children, }: {
|
|
31
|
+
job: string;
|
|
32
|
+
index: number;
|
|
33
|
+
label: string;
|
|
34
|
+
children: ReactNode;
|
|
35
|
+
}): string | number | bigint | boolean | import("react").JSX.Element | Iterable<ReactNode> | Promise<string | number | bigint | boolean | Iterable<ReactNode> | import("react").ReactElement<unknown, string | import("react").JSXElementConstructor<any>> | import("react").ReactPortal | null | undefined> | null | undefined;
|
|
36
|
+
export declare function AddStepButton({ job }: {
|
|
37
|
+
job: string;
|
|
38
|
+
}): import("react").JSX.Element | null;
|
|
39
|
+
/** Connector hit area: a click selects the dependency, shift adds it, a right-click opens its menu. */
|
|
40
|
+
export declare function EdgeHitPath({ d, edge }: {
|
|
41
|
+
d: string;
|
|
42
|
+
edge: EdgeSelection;
|
|
43
|
+
}): import("react").JSX.Element | null;
|
|
44
|
+
/** A selected connector's two ends; dragging one onto another job or node moves that end there. */
|
|
45
|
+
export declare function EdgeEnds({ edge, start, end, zIndex, }: {
|
|
46
|
+
edge: EdgeSelection;
|
|
47
|
+
start: Point;
|
|
48
|
+
end: Point;
|
|
49
|
+
zIndex: number;
|
|
50
|
+
}): import("react").JSX.Element | null;
|
|
51
|
+
/** Shown in place of the graph when the workflow has no jobs yet. */
|
|
52
|
+
/** The canvas of a graph with no jobs, which takes the graph's keys, so undo and paste still work. */
|
|
53
|
+
export declare function EmptyGraphEditor({ containerRef, overlays, height, removeBorder, }: {
|
|
54
|
+
containerRef: (el: HTMLDivElement | null) => void;
|
|
55
|
+
overlays: ReactNode;
|
|
56
|
+
height: string;
|
|
57
|
+
removeBorder?: boolean | undefined;
|
|
58
|
+
}): import("react").JSX.Element;
|