@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/dist/editor/index.js
CHANGED
|
@@ -1,7 +1,11 @@
|
|
|
1
|
+
import { INPUT_YAML_PATH, JOB_YAML_PATH, SETTINGS_YAML_PATH, STEP_YAML_PATH, settingsSchemas } from "./settingsYaml.js";
|
|
1
2
|
import Editor from "./Editor.js";
|
|
2
3
|
import EditorField from "./EditorField.js";
|
|
3
4
|
import FormCodePanel from "./FormCodePanel.js";
|
|
5
|
+
import { HOST_MARKER_OWNER, LINT_OWNER } from "./lintOwner.js";
|
|
6
|
+
import { nestedWorkflowText } from "./nestedText.js";
|
|
7
|
+
import { revealLines } from "./reveal.js";
|
|
4
8
|
import { defineEditorThemes, getThemeName } from "./themes.js";
|
|
5
9
|
import { setupMonacoWorkers } from "./workers.js";
|
|
6
10
|
import { configureEditorYaml } from "./yaml.js";
|
|
7
|
-
export { Editor, EditorField, FormCodePanel, configureEditorYaml, defineEditorThemes, getThemeName, setupMonacoWorkers };
|
|
11
|
+
export { Editor, EditorField, FormCodePanel, HOST_MARKER_OWNER, INPUT_YAML_PATH, JOB_YAML_PATH, LINT_OWNER, SETTINGS_YAML_PATH, STEP_YAML_PATH, configureEditorYaml, defineEditorThemes, getThemeName, nestedWorkflowText, revealLines, settingsSchemas, setupMonacoWorkers };
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import type { WorkflowEditing, WorkflowLintContext } from '../editing.js';
|
|
2
|
+
import { type UsesSources } from '../graph/usesInputs.js';
|
|
3
|
+
export { HOST_MARKER_OWNER, LINT_OWNER } from './lintOwner.js';
|
|
4
|
+
export interface LintSources extends UsesSources {
|
|
5
|
+
secrets?: (() => Promise<string[]>) | undefined;
|
|
6
|
+
/** `uses` values the host runs itself, which have no workflow to read inputs from. */
|
|
7
|
+
actions?: Record<string, unknown> | undefined;
|
|
8
|
+
}
|
|
9
|
+
/**
|
|
10
|
+
* What the linter can't read from `source`: the inputs of each workflow a step uses, and which
|
|
11
|
+
* of the user's variables are secret, as far as they have arrived. `onMore` runs when more does.
|
|
12
|
+
*/
|
|
13
|
+
export declare function lintContext(editing: WorkflowEditing, source: string, sources: LintSources, onMore: () => void): WorkflowLintContext;
|
|
14
|
+
export declare function useLintSources(): LintSources;
|
|
15
|
+
/** lintContext for a component, which renders again when more of it arrives. */
|
|
16
|
+
export declare function useLintContext(source: string | undefined): WorkflowLintContext;
|
|
17
|
+
/**
|
|
18
|
+
* The engine's editing once its checks have loaded, rendering again when they have; undefined
|
|
19
|
+
* before then, without an engine that edits, or with `load` false.
|
|
20
|
+
*/
|
|
21
|
+
export declare function useLintEditing(load?: boolean): WorkflowEditing | undefined;
|
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
import { useLoadedWorkflowEngine, useRepoSuggestions, useSecretVariablesResolver, useWorkflowActions, useWorkflowJsonResolver } from "../components/Provider.js";
|
|
2
|
+
import { asRecord } from "../graph/records.js";
|
|
3
|
+
import { HOST_MARKER_OWNER, LINT_OWNER } from "./lintOwner.js";
|
|
4
|
+
import { DEFAULT_GITLAB_HOST, DEFAULT_REPO_YAML, loadUsesInputs } from "../graph/usesInputs.js";
|
|
5
|
+
import { useEffect, useMemo, useState } from "react";
|
|
6
|
+
//#region src/editor/lintContext.ts
|
|
7
|
+
var KEEP_MS = 6e4;
|
|
8
|
+
var KEEP_FAILED_MS = 1e4;
|
|
9
|
+
var stale = (kept) => !kept || Date.now() - kept.at > (kept.value === null ? KEEP_FAILED_MS : KEEP_MS);
|
|
10
|
+
function failed(kept) {
|
|
11
|
+
return kept?.value ? {
|
|
12
|
+
value: kept.value,
|
|
13
|
+
at: Date.now() - KEEP_MS + KEEP_FAILED_MS
|
|
14
|
+
} : {
|
|
15
|
+
value: null,
|
|
16
|
+
at: Date.now()
|
|
17
|
+
};
|
|
18
|
+
}
|
|
19
|
+
var targets = /* @__PURE__ */ new Map();
|
|
20
|
+
var secretNames;
|
|
21
|
+
var waiting = /* @__PURE__ */ new Map();
|
|
22
|
+
var SECRETS = "\0secrets";
|
|
23
|
+
function fetchOnce(key, onMore, load) {
|
|
24
|
+
const waiters = waiting.get(key);
|
|
25
|
+
if (waiters) {
|
|
26
|
+
waiters.add(onMore);
|
|
27
|
+
return;
|
|
28
|
+
}
|
|
29
|
+
const told = /* @__PURE__ */ new Set([onMore]);
|
|
30
|
+
waiting.set(key, told);
|
|
31
|
+
load().finally(() => {
|
|
32
|
+
waiting.delete(key);
|
|
33
|
+
for (const tell of told) tell();
|
|
34
|
+
});
|
|
35
|
+
}
|
|
36
|
+
var text = (value, fallback) => typeof value === "string" && value ? value : fallback;
|
|
37
|
+
/**
|
|
38
|
+
* What the linter can't read from `source`: the inputs of each workflow a step uses, and which
|
|
39
|
+
* of the user's variables are secret, as far as they have arrived. `onMore` runs when more does.
|
|
40
|
+
*/
|
|
41
|
+
function lintContext(editing, source, sources, onMore) {
|
|
42
|
+
let doc;
|
|
43
|
+
try {
|
|
44
|
+
doc = editing.loadYaml(source);
|
|
45
|
+
} catch {
|
|
46
|
+
doc = void 0;
|
|
47
|
+
}
|
|
48
|
+
const wanted = /* @__PURE__ */ new Map();
|
|
49
|
+
for (const job of Object.values(asRecord(asRecord(doc)["jobs"]))) {
|
|
50
|
+
const steps = asRecord(job)["steps"];
|
|
51
|
+
for (const step of Array.isArray(steps) ? steps : []) {
|
|
52
|
+
const uses = asRecord(step)["uses"];
|
|
53
|
+
if (typeof uses !== "string" || uses.includes("${{") || Object.hasOwn(sources.actions ?? {}, uses.trim())) continue;
|
|
54
|
+
const withBlock = asRecord(asRecord(step)["with"]);
|
|
55
|
+
const key = [
|
|
56
|
+
uses.trim(),
|
|
57
|
+
text(withBlock["$yaml"], DEFAULT_REPO_YAML),
|
|
58
|
+
text(withBlock["$host"], DEFAULT_GITLAB_HOST)
|
|
59
|
+
].join("\n");
|
|
60
|
+
wanted.set(uses.trim(), (wanted.get(uses.trim()) ?? /* @__PURE__ */ new Set()).add(key));
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
const usesInputs = {};
|
|
64
|
+
for (const [uses, keys] of wanted) {
|
|
65
|
+
const key = keys.size === 1 ? [...keys][0] : void 0;
|
|
66
|
+
if (key === void 0) continue;
|
|
67
|
+
const kept = targets.get(key);
|
|
68
|
+
if (kept?.value) usesInputs[uses] = kept.value;
|
|
69
|
+
if (stale(kept)) {
|
|
70
|
+
const [, yamlPath = DEFAULT_REPO_YAML, host = DEFAULT_GITLAB_HOST] = key.split("\n");
|
|
71
|
+
fetchOnce(key, onMore, () => loadUsesInputs(editing, uses, {
|
|
72
|
+
yamlPath,
|
|
73
|
+
host
|
|
74
|
+
}, sources).then((inputs) => {
|
|
75
|
+
targets.set(key, {
|
|
76
|
+
value: inputs,
|
|
77
|
+
at: Date.now()
|
|
78
|
+
});
|
|
79
|
+
}, () => {
|
|
80
|
+
targets.set(key, failed(targets.get(key)));
|
|
81
|
+
}));
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
const secrets = sources.secrets;
|
|
85
|
+
if (secrets && stale(secretNames)) fetchOnce(SECRETS, onMore, () => secrets().then((names) => {
|
|
86
|
+
secretNames = {
|
|
87
|
+
value: names,
|
|
88
|
+
at: Date.now()
|
|
89
|
+
};
|
|
90
|
+
}, () => {
|
|
91
|
+
secretNames = failed(secretNames);
|
|
92
|
+
}));
|
|
93
|
+
return {
|
|
94
|
+
usesInputs,
|
|
95
|
+
...secretNames?.value ? { secretVars: secretNames.value } : {}
|
|
96
|
+
};
|
|
97
|
+
}
|
|
98
|
+
function useLintSources() {
|
|
99
|
+
const resolve = useWorkflowJsonResolver();
|
|
100
|
+
const repos = useRepoSuggestions();
|
|
101
|
+
const secrets = useSecretVariablesResolver();
|
|
102
|
+
const actions = useWorkflowActions();
|
|
103
|
+
return useMemo(() => ({
|
|
104
|
+
resolve,
|
|
105
|
+
repos,
|
|
106
|
+
secrets,
|
|
107
|
+
actions
|
|
108
|
+
}), [
|
|
109
|
+
resolve,
|
|
110
|
+
repos,
|
|
111
|
+
secrets,
|
|
112
|
+
actions
|
|
113
|
+
]);
|
|
114
|
+
}
|
|
115
|
+
/**
|
|
116
|
+
* The engine's editing once its checks have loaded, rendering again when they have; undefined
|
|
117
|
+
* before then, without an engine that edits, or with `load` false.
|
|
118
|
+
*/
|
|
119
|
+
function useLintEditing(load = true) {
|
|
120
|
+
const engine = useLoadedWorkflowEngine();
|
|
121
|
+
const [ready, setReady] = useState(() => !!engine?.isReady());
|
|
122
|
+
useEffect(() => {
|
|
123
|
+
if (!load || !engine?.editing) return;
|
|
124
|
+
if (engine.isReady()) {
|
|
125
|
+
setReady(true);
|
|
126
|
+
return;
|
|
127
|
+
}
|
|
128
|
+
engine.init();
|
|
129
|
+
return engine.onReady((loaded) => {
|
|
130
|
+
if (loaded) setReady(true);
|
|
131
|
+
});
|
|
132
|
+
}, [load, engine]);
|
|
133
|
+
return load && ready ? engine?.editing : void 0;
|
|
134
|
+
}
|
|
135
|
+
//#endregion
|
|
136
|
+
export { HOST_MARKER_OWNER, LINT_OWNER, lintContext, useLintEditing, useLintSources };
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/** An editor holding one job or step of a workflow, whose inputs live outside its text. */
|
|
2
|
+
export interface NestedWorkflowText {
|
|
3
|
+
/** The workflow's inputs, so a new group is named clear of them. */
|
|
4
|
+
inputs: () => Record<string, unknown>;
|
|
5
|
+
/** Adds the group of inputs a `with:` completion's expressions read. */
|
|
6
|
+
addInputs: (name: string, definition: Record<string, unknown>) => void;
|
|
7
|
+
}
|
|
8
|
+
/** Lets completions reach the workflow around the editor of model `uri`; returns the undo. */
|
|
9
|
+
export declare function publishNestedText(uri: string, text: {
|
|
10
|
+
current: NestedWorkflowText | undefined;
|
|
11
|
+
}): () => void;
|
|
12
|
+
/** The workflow around the editor of model `uri`, or undefined when its text is a whole workflow. */
|
|
13
|
+
export declare function nestedWorkflowText(uri: string): NestedWorkflowText | undefined;
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
//#region src/editor/nestedText.ts
|
|
2
|
+
var published = /* @__PURE__ */ new Map();
|
|
3
|
+
/** Lets completions reach the workflow around the editor of model `uri`; returns the undo. */
|
|
4
|
+
function publishNestedText(uri, text) {
|
|
5
|
+
published.set(uri, text);
|
|
6
|
+
return () => {
|
|
7
|
+
if (published.get(uri) === text) published.delete(uri);
|
|
8
|
+
};
|
|
9
|
+
}
|
|
10
|
+
/** The workflow around the editor of model `uri`, or undefined when its text is a whole workflow. */
|
|
11
|
+
function nestedWorkflowText(uri) {
|
|
12
|
+
return published.get(uri)?.current;
|
|
13
|
+
}
|
|
14
|
+
//#endregion
|
|
15
|
+
export { nestedWorkflowText, publishNestedText };
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
/** Lets revealLines reach the editor showing `path`; returns the function that undoes it. */
|
|
2
|
+
export declare function registerRevealer(path: string, reveal: (start: number, end: number) => void): () => void;
|
|
3
|
+
/** Scrolls the editor showing `path` to 1-based lines `start`–`end` and flashes them. */
|
|
4
|
+
export declare function revealLines(path: string, start: number, end: number): void;
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
//#region src/editor/reveal.ts
|
|
2
|
+
var revealers = /* @__PURE__ */ new Map();
|
|
3
|
+
/** Lets revealLines reach the editor showing `path`; returns the function that undoes it. */
|
|
4
|
+
function registerRevealer(path, reveal) {
|
|
5
|
+
revealers.set(path, reveal);
|
|
6
|
+
return () => {
|
|
7
|
+
if (revealers.get(path) === reveal) revealers.delete(path);
|
|
8
|
+
};
|
|
9
|
+
}
|
|
10
|
+
/** Scrolls the editor showing `path` to 1-based lines `start`–`end` and flashes them. */
|
|
11
|
+
function revealLines(path, start, end) {
|
|
12
|
+
revealers.get(path)?.(start, end);
|
|
13
|
+
}
|
|
14
|
+
//#endregion
|
|
15
|
+
export { registerRevealer, revealLines };
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/** Editors holding one job's, step's or input's settings, each checked against that part of the workflow schema. */
|
|
2
|
+
export declare const JOB_YAML_PATH = "file:///workflow-job.yaml";
|
|
3
|
+
export declare const STEP_YAML_PATH = "file:///workflow-step.yaml";
|
|
4
|
+
export declare const INPUT_YAML_PATH = "file:///workflow-input.yaml";
|
|
5
|
+
export declare const SETTINGS_YAML_PATH = "file:///workflow-settings.yaml";
|
|
6
|
+
export type JsonSchema = Record<string, unknown>;
|
|
7
|
+
export declare function settingsSchemas(workflow: JsonSchema): {
|
|
8
|
+
job: JsonSchema;
|
|
9
|
+
step: JsonSchema;
|
|
10
|
+
input: JsonSchema;
|
|
11
|
+
settings: JsonSchema;
|
|
12
|
+
};
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
//#region src/editor/settingsYaml.ts
|
|
2
|
+
/** Editors holding one job's, step's or input's settings, each checked against that part of the workflow schema. */
|
|
3
|
+
var JOB_YAML_PATH = "file:///workflow-job.yaml";
|
|
4
|
+
var STEP_YAML_PATH = "file:///workflow-step.yaml";
|
|
5
|
+
var INPUT_YAML_PATH = "file:///workflow-input.yaml";
|
|
6
|
+
var SETTINGS_YAML_PATH = "file:///workflow-settings.yaml";
|
|
7
|
+
var record = (value) => typeof value === "object" && value !== null ? value : {};
|
|
8
|
+
function settingsSchemas(workflow) {
|
|
9
|
+
const patterns = record(record(record(workflow["properties"])["jobs"])["patternProperties"]);
|
|
10
|
+
const job = record(Object.values(patterns)[0]);
|
|
11
|
+
const step = record(record(record(job["properties"])["steps"])["items"]);
|
|
12
|
+
const inputs = record(record(record(workflow["$defs"])["inputs"])["patternProperties"]);
|
|
13
|
+
const input = record(Object.values(inputs)[0]);
|
|
14
|
+
const shared = {
|
|
15
|
+
$schema: workflow["$schema"],
|
|
16
|
+
$defs: workflow["$defs"]
|
|
17
|
+
};
|
|
18
|
+
const { jobs: _jobs, on: _on, ...settings } = record(workflow["properties"]);
|
|
19
|
+
return {
|
|
20
|
+
job: {
|
|
21
|
+
...job,
|
|
22
|
+
...shared
|
|
23
|
+
},
|
|
24
|
+
step: {
|
|
25
|
+
...step,
|
|
26
|
+
...shared
|
|
27
|
+
},
|
|
28
|
+
input: {
|
|
29
|
+
...input,
|
|
30
|
+
...shared
|
|
31
|
+
},
|
|
32
|
+
settings: {
|
|
33
|
+
type: "object",
|
|
34
|
+
properties: settings,
|
|
35
|
+
additionalProperties: false,
|
|
36
|
+
...shared
|
|
37
|
+
}
|
|
38
|
+
};
|
|
39
|
+
}
|
|
40
|
+
//#endregion
|
|
41
|
+
export { INPUT_YAML_PATH, JOB_YAML_PATH, SETTINGS_YAML_PATH, STEP_YAML_PATH, settingsSchemas };
|
|
@@ -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,
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { FieldWrapper } from "../FieldWrapper.js";
|
|
2
2
|
import FormikCustomDropdown_default from "../SpecialTypes/FormikCustomDropdown.js";
|
|
3
|
-
import { getPlaceholder } from "../utils/getPlaceholder.js";
|
|
4
3
|
import { dependentOptions } from "../utils/dependentOptions.js";
|
|
4
|
+
import { getPlaceholder } from "../utils/getPlaceholder.js";
|
|
5
5
|
import { jsx } from "react/jsx-runtime";
|
|
6
6
|
//#region src/form/Fields/DropdownField.tsx
|
|
7
7
|
var missingSetter = () => {
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { useStrings } from "../../components/Provider.js";
|
|
2
2
|
import { FieldWrapper } from "../FieldWrapper.js";
|
|
3
|
-
import { setDurationValidity } from "./durationValidity.js";
|
|
4
3
|
import { formatDuration, parseDuration } from "../utils/duration.js";
|
|
4
|
+
import { setDurationValidity } from "./durationValidity.js";
|
|
5
5
|
import cx from "classnames";
|
|
6
6
|
import { memo, useEffect, useRef, useState } from "react";
|
|
7
7
|
import { Fragment as Fragment$1, jsx, jsxs } from "react/jsx-runtime";
|
package/dist/form/Form.js
CHANGED
|
@@ -9,11 +9,12 @@ import SectionHeader from "../components/SectionHeader.js";
|
|
|
9
9
|
import { Table } from "../components/Table.js";
|
|
10
10
|
import { parseWizardConfig } from "./Wizard/utils.js";
|
|
11
11
|
import { inputWidth, resolvedFlag } from "./lib.js";
|
|
12
|
-
import { useFieldControlProps, useFieldRequired } from "./fieldContext.js";
|
|
13
12
|
import { resolveFormLayout } from "./layout.js";
|
|
14
13
|
import { FormLayout, LayoutCSSContext } from "./FormLayout.js";
|
|
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: [
|