@parallelworks/ui 0.18.0 → 0.19.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 +86 -6
- package/dist/ai/adapter/memoryStore.d.ts +8 -0
- package/dist/ai/adapter/mock/index.d.ts +2 -0
- package/dist/ai/adapter/mock/index.js +81 -0
- package/dist/ai/adapter/mock/mockAdapter.d.ts +4 -0
- package/dist/ai/adapter/openai/createOpenAIStream.d.ts +9 -0
- package/dist/ai/adapter/openai/errors.d.ts +3 -0
- package/dist/ai/adapter/openai/index.d.ts +6 -0
- package/dist/ai/adapter/openai/index.js +334 -0
- package/dist/ai/adapter/openai/openaiAdapter.d.ts +9 -0
- package/dist/ai/adapter/openai/responses.d.ts +4 -0
- package/dist/ai/adapter/openai/sse.d.ts +24 -0
- package/dist/ai/adapter/openai/wire.d.ts +40 -0
- package/dist/ai/adapter/types.d.ts +131 -0
- package/dist/ai/agent/classifier.d.ts +2 -0
- package/dist/ai/agent/diff.d.ts +35 -0
- package/dist/ai/agent/diffHighlight.d.ts +6 -0
- package/dist/ai/agent/index.d.ts +6 -0
- package/dist/ai/agent/permissions.d.ts +11 -0
- package/dist/ai/agent/toolfmt.d.ts +18 -0
- package/dist/ai/agent/transcript.d.ts +38 -0
- package/dist/ai/ai.css +325 -0
- package/dist/ai/components/AllocationSelector.d.ts +4 -0
- package/dist/ai/components/AttachmentManager.d.ts +1 -0
- package/dist/ai/components/AttachmentUpload.d.ts +24 -0
- package/dist/ai/components/BlockedGroupBanner.d.ts +1 -0
- package/dist/ai/components/BranchNavigator.d.ts +8 -0
- package/dist/ai/components/ChatEmptyState.d.ts +3 -0
- package/dist/ai/components/ChatInput.d.ts +45 -0
- package/dist/ai/components/ChatLayout.d.ts +5 -0
- package/dist/ai/components/ChatMessage.d.ts +24 -0
- package/dist/ai/components/ChatMessageList.d.ts +35 -0
- package/dist/ai/components/ChatSidebar.d.ts +5 -0
- package/dist/ai/components/ChatThread.d.ts +3 -0
- package/dist/ai/components/ComposerChrome.d.ts +18 -0
- package/dist/ai/components/ComposerFrame.d.ts +16 -0
- package/dist/ai/components/DragOverlay.d.ts +5 -0
- package/dist/ai/components/ModelSelector.d.ts +6 -0
- package/dist/ai/components/ShareDialog.d.ts +11 -0
- package/dist/ai/components/SlashMenu.d.ts +28 -0
- package/dist/ai/components/agent/ActivityLine.d.ts +21 -0
- package/dist/ai/components/agent/AgentMessageParts.d.ts +54 -0
- package/dist/ai/components/agent/PermissionPicker.d.ts +11 -0
- package/dist/ai/components/attachmentKeys.d.ts +4 -0
- package/dist/ai/core/ChatProvider.d.ts +66 -0
- package/dist/ai/core/KeyboardShortcutsProvider.d.ts +5 -0
- package/dist/ai/core/chatReducer.d.ts +114 -0
- package/dist/ai/core/config.d.ts +47 -0
- package/dist/ai/core/events.d.ts +1 -0
- package/dist/ai/core/exportConversation.d.ts +4 -0
- package/dist/ai/core/greeting.d.ts +3 -0
- package/dist/ai/core/parts.d.ts +11 -0
- package/dist/ai/core/useDragDrop.d.ts +14 -0
- package/dist/ai/core/useKeyboardShortcuts.d.ts +12 -0
- package/dist/ai/core/useSSEStream.d.ts +34 -0
- package/dist/ai/index.d.ts +40 -0
- package/dist/ai/index.js +6645 -0
- package/dist/ai/strings.d.ts +167 -0
- package/dist/ai/types.d.ts +236 -0
- package/dist/ai/ui/Avatar.d.ts +8 -0
- package/dist/ai/ui/Dropdown.d.ts +31 -0
- package/dist/ai/ui/Markdown.d.ts +8 -0
- package/dist/ai/ui/Notice.d.ts +21 -0
- package/dist/ai/ui/buttons.d.ts +1 -0
- package/dist/ai/ui/codeBreaks.d.ts +16 -0
- package/dist/ai/ui/prose.d.ts +1 -0
- package/dist/ai/ui/sidebar.d.ts +81 -0
- package/dist/ai/utils.d.ts +4 -0
- package/dist/assets/{editor.worker-CuBRIwi-.js → editor.worker-BmHUIVG4.js} +194 -163
- package/dist/assets/{json.worker-8ytS02vz.js → json.worker-D8bJ92nw.js} +384 -338
- package/dist/assets/{yaml.worker-DJC-VUcv.js → yaml.worker-C4gyGAko.js} +15657 -13823
- package/dist/chunks/{CodePreviewEditor-4lx3kE-w.js → CodePreviewEditor-YqQBz1YL.js} +1 -1
- package/dist/chunks/ConfirmModal-aOR4O1QE.js +79 -0
- package/dist/chunks/{FieldWrapper-Bef01EWO.js → FieldWrapper-Cszwg-4B.js} +3 -7
- package/dist/chunks/{CreateModal-BY6DLmur.js → Markdown-CM-FenNE.js} +19 -91
- package/dist/chunks/Monaco-DJ8MW-Dq.js +110 -0
- package/dist/chunks/{PageHeader-l49p1nM9.js → PageHeader-0kG_iypP.js} +67 -65
- package/dist/chunks/{Provider-Ghua9PkN.js → Provider-CDYurraE.js} +54 -20
- package/dist/chunks/{SwitchToggle-CHPP8uZQ.js → SwitchToggle-DShNdcao.js} +135 -132
- package/dist/chunks/{Table-4OHjdKdO.js → Table-DU2MW8xz.js} +5 -3
- package/dist/chunks/{Tooltip-Crxo_eU_.js → Tooltip-K5HJr4_p.js} +31 -4
- package/dist/chunks/duration-BOv8Phl8.js +17 -0
- package/dist/chunks/{editor-9_uVtUyy.js → editor-Dk1rbV75.js} +32 -18
- package/dist/chunks/focus-D_iZJTW1.js +7 -0
- package/dist/chunks/{list-qrojZZNv.js → list-CJm875m7.js} +377 -370
- package/dist/chunks/logviewer-BTKuQWzw.js +828 -0
- package/dist/chunks/memoryStore-CC91S5LP.js +152 -0
- package/dist/chunks/types-Yy0NrerF.js +11 -0
- package/dist/components/Avatar.d.ts +1 -1
- package/dist/components/Breadcrumbs.d.ts +1 -1
- package/dist/components/Dropdown.d.ts +1 -1
- package/dist/components/EmptyState.d.ts +1 -1
- package/dist/components/Indicator.d.ts +2 -2
- package/dist/components/Input.d.ts +1 -1
- package/dist/components/LetterBadge.d.ts +1 -1
- package/dist/components/MarkdownImpl.d.ts +1 -1
- package/dist/components/Provider.d.ts +16 -65
- package/dist/components/SettingRow.d.ts +1 -1
- package/dist/components/SettingsGroup.d.ts +1 -1
- package/dist/components/focus.d.ts +2 -0
- package/dist/components/keys.d.ts +12 -0
- package/dist/duration.d.ts +3 -0
- package/dist/editor/Monaco.d.ts +1 -20
- package/dist/editor/index.d.ts +2 -1
- package/dist/editor/index.js +2 -2
- package/dist/editor/yaml.d.ts +5 -0
- package/dist/engine.d.ts +98 -0
- package/dist/file-explorer/FileExplorer.d.ts +11 -2
- package/dist/file-explorer/FileExplorerContext.d.ts +1 -1
- package/dist/file-explorer/FilePreview/CodePreviewEditor.d.ts +1 -1
- package/dist/file-explorer/FilePreview/previewType.d.ts +1 -1
- package/dist/file-explorer/FileRow.d.ts +1 -1
- package/dist/file-explorer/helpers.d.ts +4 -4
- package/dist/file-explorer/index.d.ts +3 -3
- package/dist/file-explorer/index.js +613 -647
- package/dist/file-explorer/lib/types.d.ts +6 -1
- package/dist/file-explorer/lib/utils.d.ts +1 -3
- package/dist/file-explorer/useNearEnd.d.ts +1 -1
- package/dist/form/FieldWrapper.d.ts +2 -2
- package/dist/form/Fields/ResourceOptionIcon.d.ts +1 -1
- package/dist/form/Form.d.ts +4 -21
- package/dist/form/index.d.ts +11 -12
- package/dist/form/index.js +1488 -1611
- package/dist/form/lib.d.ts +6 -1
- package/dist/form/types/fieldComponentTypes.d.ts +3 -2
- package/dist/form/types/fieldTypes.d.ts +6 -20
- package/dist/form/useParsedOpts.d.ts +1 -1
- package/dist/form/utils/{slurmDuration.d.ts → duration.d.ts} +2 -2
- package/dist/{workflow → graph}/MatrixGroup.d.ts +2 -2
- package/dist/{workflow → graph}/index.d.ts +1 -1
- package/dist/{workflow → graph}/index.js +215 -180
- package/dist/{workflow → graph}/types.d.ts +3 -3
- package/dist/icons.d.ts +20 -21
- package/dist/index.d.ts +38 -40
- package/dist/index.js +347 -346
- package/dist/list/ListTable.d.ts +1 -1
- package/dist/list/ListViewControls.d.ts +2 -2
- package/dist/list/index.d.ts +9 -9
- package/dist/list/index.js +2 -2
- package/dist/logviewer/LogViewer.d.ts +1 -1
- package/dist/logviewer/index.d.ts +1 -0
- package/dist/logviewer/index.js +2 -742
- package/dist/logviewer/segments.d.ts +9 -0
- package/dist/styles/fonts.css +4 -4
- package/dist/styles/theme.css +6 -4
- package/dist/styles.css +1 -1
- package/dist/theme/index.js +2 -2
- package/package.json +38 -14
- package/LICENSE +0 -202
- package/dist/chunks/Monaco-C1POOdVv.js +0 -1046
- package/dist/editor/usesGitlab.d.ts +0 -97
- package/dist/form/Fields/BucketReadOnlyField.d.ts +0 -7
- package/dist/form/types/workflow-schema.d.ts +0 -1145
- package/dist/form/utils/pwResolver.d.ts +0 -18
- package/dist/chunks/{MarkdownImpl-Bq4QhrtA.js → MarkdownImpl-CyeTVvSt.js} +1 -1
- /package/dist/{workflow → graph}/AnnotationBanner.d.ts +0 -0
- /package/dist/{workflow → graph}/Collapse.d.ts +0 -0
- /package/dist/{workflow → graph}/DependencyGraph.d.ts +0 -0
- /package/dist/{workflow → graph}/JobSummary.d.ts +0 -0
- /package/dist/{workflow → graph}/Reveal.d.ts +0 -0
- /package/dist/{workflow → graph}/TreeView.d.ts +0 -0
package/dist/form/index.js
CHANGED
|
@@ -1,997 +1,844 @@
|
|
|
1
|
-
import { l as useSlots, u as useStrings } from "../chunks/Provider-
|
|
2
|
-
import { AngleRightIcon, EyeIcon, EyeOffIcon,
|
|
3
|
-
import {
|
|
1
|
+
import { d as useWorkflowEngine, l as useSlots, u as useStrings } from "../chunks/Provider-CDYurraE.js";
|
|
2
|
+
import { AngleRightIcon, EyeIcon, EyeOffIcon, TrashIcon } from "../icons.js";
|
|
3
|
+
import { r as TooltipInfo } from "../chunks/Tooltip-K5HJr4_p.js";
|
|
4
|
+
import { a as Dropdown, c as UncontrolledCollapsiblePanel, i as CustomListbox, n as SectionHeader, o as ControlledCollapsiblePanel, r as MultiSelectDropdown, t as SwitchToggle } from "../chunks/SwitchToggle-DShNdcao.js";
|
|
4
5
|
import { c as isCategory, n as StatusDot } from "../chunks/StatusBadge-C1Blx_cW.js";
|
|
5
|
-
import { a as UncontrolledCollapsiblePanel, c as Dropdown, n as SectionHeader, o as MultiSelectDropdown, r as ControlledCollapsiblePanel, s as CustomListbox, t as SwitchToggle } from "../chunks/SwitchToggle-CHPP8uZQ.js";
|
|
6
6
|
import { t as Loader } from "../chunks/Loader-BXoXTZGc.js";
|
|
7
|
-
import { n as Table } from "../chunks/Table-
|
|
8
|
-
import { a as initializeValues, c as findSecondaryOption, d as useFieldLabelledByProps, f as useFieldRequired, i as impureSetValueFromPath, l as FieldProvider, n as enforceOneMustBeTrue, o as resolvedFlag, r as flattenGroups, s as applySecondaryField, t as FieldWrapper, u as useFieldControlProps } from "../chunks/FieldWrapper-
|
|
7
|
+
import { n as Table } from "../chunks/Table-DU2MW8xz.js";
|
|
8
|
+
import { a as initializeValues, c as findSecondaryOption, d as useFieldLabelledByProps, f as useFieldRequired, i as impureSetValueFromPath, l as FieldProvider, n as enforceOneMustBeTrue, o as resolvedFlag, r as flattenGroups, s as applySecondaryField, t as FieldWrapper, u as useFieldControlProps } from "../chunks/FieldWrapper-Cszwg-4B.js";
|
|
9
9
|
import cx from "classnames";
|
|
10
|
-
import React, { Suspense, createContext, memo, useCallback, useContext, useEffect, useId, useMemo, useRef, useState } from "react";
|
|
10
|
+
import React, { Suspense, createContext, memo, useCallback, useContext, useEffect, useEffectEvent, useId, useMemo, useRef, useState } from "react";
|
|
11
11
|
import { Fragment as Fragment$1, jsx, jsxs } from "react/jsx-runtime";
|
|
12
12
|
import deepEqual from "fast-deep-equal";
|
|
13
13
|
import { Duration } from "luxon";
|
|
14
|
-
import {
|
|
15
|
-
import { Field, Form, Formik, getIn, useField, useFormikContext } from "formik";
|
|
14
|
+
import { Field, Form, Formik, useField, useFormikContext } from "formik";
|
|
16
15
|
import { NumericFormat } from "react-number-format";
|
|
17
|
-
//#region src/form/
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
for (const key of keys) {
|
|
23
|
-
if (!current || typeof current !== "object") return;
|
|
24
|
-
const container = current;
|
|
25
|
-
if (key.includes("[")) {
|
|
26
|
-
const [arrayKey = "", indexStr = ""] = key.split("[");
|
|
27
|
-
const index = parseInt(indexStr.slice(0, -1), 10);
|
|
28
|
-
const list = container[arrayKey];
|
|
29
|
-
if (!Array.isArray(list) || isNaN(index)) return;
|
|
30
|
-
current = list[index];
|
|
31
|
-
} else {
|
|
32
|
-
if (!(key in container)) return;
|
|
33
|
-
current = container[key];
|
|
34
|
-
}
|
|
35
|
-
}
|
|
36
|
-
return current;
|
|
16
|
+
//#region src/form/Fields/durationValidity.ts
|
|
17
|
+
var invalidPaths = /* @__PURE__ */ new Set();
|
|
18
|
+
function setDurationValidity(path, valid) {
|
|
19
|
+
if (valid) invalidPaths.delete(path);
|
|
20
|
+
else invalidPaths.add(path);
|
|
37
21
|
}
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
function checkShowIfObject(showIfObject, formValues, index) {
|
|
41
|
-
const valueList = [];
|
|
42
|
-
for (let [key, value] of Object.entries(showIfObject)) {
|
|
43
|
-
if (index !== void 0) key = key.replace("[index]", `[${index}]`);
|
|
44
|
-
const dependsOnValue = getValueUsingPath(formValues, key);
|
|
45
|
-
if (typeof value === "boolean" || typeof value === "string" || typeof value === "number") valueList.push(dependsOnValue !== null && dependsOnValue !== void 0 && dependsOnValue.toString() === value.toString());
|
|
46
|
-
else if (Array.isArray(value)) valueList.push(value.includes(dependsOnValue));
|
|
47
|
-
}
|
|
48
|
-
return valueList;
|
|
22
|
+
function getInvalidDurationPaths() {
|
|
23
|
+
return [...invalidPaths];
|
|
49
24
|
}
|
|
50
25
|
//#endregion
|
|
51
|
-
//#region src/form/
|
|
52
|
-
function
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
26
|
+
//#region src/form/SpecialTypes/FormikCustomDropdown.tsx
|
|
27
|
+
function toComparableOptions(options) {
|
|
28
|
+
return options?.map((option) => {
|
|
29
|
+
if (typeof option === "string") return option;
|
|
30
|
+
if (isCategory(option)) return {
|
|
31
|
+
category: option.category,
|
|
32
|
+
options: option.options.map((o) => {
|
|
33
|
+
const base = {
|
|
34
|
+
label: o.label,
|
|
35
|
+
value: o.value,
|
|
36
|
+
disabled: o.disabled
|
|
37
|
+
};
|
|
38
|
+
return o.description !== void 0 ? {
|
|
39
|
+
...base,
|
|
40
|
+
description: o.description
|
|
41
|
+
} : base;
|
|
42
|
+
})
|
|
43
|
+
};
|
|
44
|
+
const base = {
|
|
45
|
+
label: option.label,
|
|
46
|
+
value: option.value,
|
|
47
|
+
disabled: option.disabled
|
|
48
|
+
};
|
|
49
|
+
return option.description !== void 0 ? {
|
|
50
|
+
...base,
|
|
51
|
+
description: option.description
|
|
52
|
+
} : base;
|
|
53
|
+
});
|
|
69
54
|
}
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
const
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
55
|
+
function arePropsEqual(prev, next) {
|
|
56
|
+
for (const key of Object.keys(next)) if (key === "options") {
|
|
57
|
+
if (!deepEqual(toComparableOptions(prev.options), toComparableOptions(next.options))) return false;
|
|
58
|
+
} else if (prev[key] !== next[key]) return false;
|
|
59
|
+
return true;
|
|
60
|
+
}
|
|
61
|
+
var FormikCustomDropdown_default = memo(function FormikCustomDropdown({ name, ariaLabel, options, setFormDirty, onChange, parentValue, className, secondaryField, disabled = false, loading = false, invalid = false, autoselect, value, allowCustomValue = false, customValueLabel, placeholder, currentValue, setFieldValue, setFieldTouched }) {
|
|
62
|
+
const required = useFieldRequired();
|
|
63
|
+
const controlProps = useFieldControlProps();
|
|
64
|
+
const prevParentRef = useRef(parentValue);
|
|
65
|
+
const handleChange = (val) => {
|
|
66
|
+
if (secondaryField && typeof options[0] !== "string") {
|
|
67
|
+
const option = findSecondaryOption(options, val);
|
|
68
|
+
if (option) applySecondaryField(secondaryField, option.secondaryValue, setFieldValue);
|
|
69
|
+
}
|
|
70
|
+
if (onChange) onChange(val);
|
|
71
|
+
setFieldValue(name, val);
|
|
72
|
+
setFieldTouched(name, true);
|
|
73
|
+
setFormDirty(true);
|
|
74
|
+
};
|
|
75
|
+
useEffect(() => {
|
|
76
|
+
prevParentRef.current = parentValue;
|
|
77
|
+
});
|
|
78
|
+
const prevOptions = useRef(null);
|
|
79
|
+
const syncAutoselect = useEffectEvent((options, autoselect) => {
|
|
80
|
+
if (deepEqual(prevOptions.current, toComparableOptions(options))) return;
|
|
81
|
+
if (prevOptions.current === null && currentValue !== void 0 && currentValue !== null) {
|
|
82
|
+
prevOptions.current = toComparableOptions(options);
|
|
83
|
+
return;
|
|
84
|
+
}
|
|
85
|
+
prevOptions.current = toComparableOptions(options);
|
|
86
|
+
if (autoselect === false || !options?.length) return;
|
|
87
|
+
if (autoselect === void 0) {
|
|
88
|
+
if (options.length && isCategory(options[0])) {
|
|
89
|
+
let optionCount = 0;
|
|
90
|
+
for (const category of options) {
|
|
91
|
+
if (isCategory(category)) optionCount += category.options.length;
|
|
92
|
+
if (optionCount > 1) return;
|
|
93
|
+
}
|
|
94
|
+
} else if (options.length !== 1) return;
|
|
95
|
+
}
|
|
96
|
+
if (!options?.find((option) => {
|
|
97
|
+
if (typeof option === "string") return option === currentValue;
|
|
98
|
+
else if (isCategory(option)) return option.options.some((subOption) => {
|
|
99
|
+
return subOption.value === currentValue;
|
|
100
|
+
});
|
|
101
|
+
return option.value === currentValue;
|
|
102
|
+
}) || autoselect) {
|
|
103
|
+
let val;
|
|
104
|
+
for (const option of options) if (typeof option === "string") {
|
|
105
|
+
val = option;
|
|
106
|
+
break;
|
|
107
|
+
} else if (isCategory(option)) {
|
|
108
|
+
const enabled = option.options.find((o) => !o.disabled);
|
|
109
|
+
if (enabled) {
|
|
110
|
+
val = enabled.value;
|
|
111
|
+
break;
|
|
112
|
+
}
|
|
113
|
+
} else if (!option.disabled) {
|
|
114
|
+
val = option.value;
|
|
115
|
+
break;
|
|
116
|
+
}
|
|
117
|
+
if (val !== void 0) handleChange(val);
|
|
111
118
|
}
|
|
112
|
-
if (!inputsChanged) return c.result;
|
|
113
|
-
}
|
|
114
|
-
const parsed = parseStringsOfObj({
|
|
115
|
-
inputs: values,
|
|
116
|
-
obj: c.converted,
|
|
117
|
-
orgVars: organizationVariables,
|
|
118
|
-
userVars,
|
|
119
|
-
secretKeys,
|
|
120
|
-
remoteVars
|
|
121
119
|
});
|
|
122
|
-
c.result = parsed;
|
|
123
|
-
c.relevantSnapshot = {};
|
|
124
|
-
for (const key of c.inputDeps) c.relevantSnapshot[key] = values[key];
|
|
125
|
-
return parsed;
|
|
126
|
-
}
|
|
127
|
-
//#endregion
|
|
128
|
-
//#region src/form/usePrevious.ts
|
|
129
|
-
function usePrevious(value) {
|
|
130
|
-
const ref = useRef(void 0);
|
|
131
120
|
useEffect(() => {
|
|
132
|
-
|
|
121
|
+
syncAutoselect(options, autoselect);
|
|
122
|
+
}, [options, autoselect]);
|
|
123
|
+
return /* @__PURE__ */ jsx(Dropdown, {
|
|
124
|
+
...controlProps,
|
|
125
|
+
textBoxClassName: cx(className, invalid && "invalid"),
|
|
126
|
+
ariaLabel,
|
|
127
|
+
required,
|
|
128
|
+
onChange: (val) => handleChange(val),
|
|
129
|
+
value: options?.length === 0 && !allowCustomValue ? value : currentValue,
|
|
130
|
+
options,
|
|
131
|
+
placeholder,
|
|
132
|
+
disabled,
|
|
133
|
+
loading,
|
|
134
|
+
allowCustomValue,
|
|
135
|
+
customValueLabel
|
|
133
136
|
});
|
|
134
|
-
|
|
135
|
-
}
|
|
137
|
+
}, arePropsEqual);
|
|
136
138
|
//#endregion
|
|
137
|
-
//#region src/form/
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
const [
|
|
141
|
-
const
|
|
142
|
-
const
|
|
143
|
-
|
|
144
|
-
|
|
139
|
+
//#region src/form/SpecialTypes/FormikCustomInput.tsx
|
|
140
|
+
var DEBOUNCE_MS$2 = 500;
|
|
141
|
+
function FormikCustomInput({ name, type, step, placeholder, onChange, disabled, min, max, sanitize, invalid = false, lowercase = false, minLength, maxLength, defaultValue = "", value }) {
|
|
142
|
+
const [field] = useField(name);
|
|
143
|
+
const required = useFieldRequired();
|
|
144
|
+
const controlProps = useFieldControlProps();
|
|
145
|
+
const { setFieldValue, setFieldTouched } = useFormikContext();
|
|
146
|
+
const [showPassword, setShowPassword] = useState(false);
|
|
147
|
+
const isPassword = type === "password";
|
|
148
|
+
const [localValue, setLocalValue] = useState(value ?? field.value);
|
|
149
|
+
const isFocused = useRef(false);
|
|
150
|
+
const debounceRef = useRef(null);
|
|
151
|
+
useEffect(() => {
|
|
152
|
+
if (!isFocused.current) setLocalValue(value ?? field.value);
|
|
153
|
+
}, [field.value, value]);
|
|
154
|
+
const sanitizeName = useCallback((val) => {
|
|
155
|
+
if (sanitize === void 0) return lowercase ? val.toLowerCase() : val;
|
|
145
156
|
try {
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
}
|
|
150
|
-
|
|
157
|
+
const regexp = new RegExp(sanitize);
|
|
158
|
+
if (lowercase) val = val.toLowerCase();
|
|
159
|
+
return val.replace(regexp, "");
|
|
160
|
+
} catch {
|
|
161
|
+
console.error("Invalid regex for sanitization:", sanitize);
|
|
151
162
|
}
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
163
|
+
return val;
|
|
164
|
+
}, [sanitize, lowercase]);
|
|
165
|
+
const flushToFormik = useCallback((val) => {
|
|
166
|
+
if (onChange) onChange(val);
|
|
167
|
+
setFieldTouched(name, true);
|
|
168
|
+
setFieldValue(name, val);
|
|
169
|
+
}, [
|
|
170
|
+
name,
|
|
171
|
+
onChange,
|
|
172
|
+
setFieldTouched,
|
|
173
|
+
setFieldValue
|
|
174
|
+
]);
|
|
175
|
+
const handleChange = (e) => {
|
|
176
|
+
const text = sanitize ? sanitizeName(e.target.value) : e.target.value;
|
|
177
|
+
let val = text;
|
|
178
|
+
if (type === "number") {
|
|
179
|
+
const parsed = parseFloat(text);
|
|
180
|
+
val = isNaN(parsed) ? void 0 : parsed;
|
|
162
181
|
}
|
|
182
|
+
if (type === "password" && val === "") val = defaultValue;
|
|
183
|
+
setLocalValue(val);
|
|
184
|
+
clearTimeout(debounceRef.current ?? void 0);
|
|
185
|
+
debounceRef.current = setTimeout(() => flushToFormik(val), DEBOUNCE_MS$2);
|
|
163
186
|
};
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
187
|
+
const handleFocus = () => {
|
|
188
|
+
isFocused.current = true;
|
|
189
|
+
};
|
|
190
|
+
const handleBlur = () => {
|
|
191
|
+
isFocused.current = false;
|
|
192
|
+
clearTimeout(debounceRef.current ?? void 0);
|
|
193
|
+
const current = localValue;
|
|
194
|
+
if (current === void 0 || current === null) return;
|
|
195
|
+
const text = current.toString();
|
|
196
|
+
let val = text;
|
|
197
|
+
if (type === "number") {
|
|
198
|
+
const parsed = parseFloat(text);
|
|
199
|
+
if (Number.isNaN(parsed)) val = void 0;
|
|
200
|
+
else if (min !== void 0 && parsed < min) val = min;
|
|
201
|
+
else if (max !== void 0 && parsed > max) val = max;
|
|
202
|
+
else val = parsed;
|
|
203
|
+
}
|
|
204
|
+
setLocalValue(val);
|
|
205
|
+
flushToFormik(val);
|
|
206
|
+
};
|
|
207
|
+
const displayValue = isPassword && localValue === defaultValue ? "" : localValue ?? "";
|
|
208
|
+
const resolvedType = isPassword ? showPassword ? "text" : "password" : type === "string" ? "text" : type;
|
|
209
|
+
const input = /* @__PURE__ */ jsx("input", {
|
|
210
|
+
...controlProps,
|
|
211
|
+
"data-1p-ignore": true,
|
|
212
|
+
className: cx("w-full", disabled && "disabled", invalid && "invalid", isPassword && "pr-8"),
|
|
213
|
+
name,
|
|
214
|
+
value: displayValue,
|
|
215
|
+
type: resolvedType,
|
|
216
|
+
"aria-required": required || void 0,
|
|
217
|
+
disabled,
|
|
218
|
+
placeholder,
|
|
219
|
+
minLength,
|
|
220
|
+
maxLength,
|
|
221
|
+
onChange: handleChange,
|
|
222
|
+
onFocus: handleFocus,
|
|
223
|
+
onBlur: handleBlur,
|
|
224
|
+
min,
|
|
225
|
+
max,
|
|
226
|
+
step
|
|
227
|
+
});
|
|
228
|
+
if (!isPassword) return input;
|
|
229
|
+
return /* @__PURE__ */ jsxs("div", {
|
|
230
|
+
className: "relative w-full",
|
|
231
|
+
children: [input, /* @__PURE__ */ jsx("button", {
|
|
205
232
|
type: "button",
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
},
|
|
213
|
-
onMouseLeave: (e) => {
|
|
214
|
-
e.currentTarget.style.filter = "brightness(1)";
|
|
215
|
-
},
|
|
216
|
-
"aria-label": "Go to next step",
|
|
217
|
-
children: [isLoading && /* @__PURE__ */ jsx(Loader, {
|
|
218
|
-
size: 16,
|
|
219
|
-
full: false
|
|
220
|
-
}), nextLabel || "Next →"]
|
|
233
|
+
className: "absolute right-2 top-1/2 -translate-y-1/2 theme-muted-text",
|
|
234
|
+
onClick: () => setShowPassword((prev) => !prev),
|
|
235
|
+
disabled,
|
|
236
|
+
tabIndex: -1,
|
|
237
|
+
"aria-label": showPassword ? "Hide value" : "Show value",
|
|
238
|
+
children: showPassword ? /* @__PURE__ */ jsx(EyeOffIcon, { className: "h-4 w-4" }) : /* @__PURE__ */ jsx(EyeIcon, { className: "h-4 w-4" })
|
|
221
239
|
})]
|
|
222
|
-
})] });
|
|
223
|
-
}
|
|
224
|
-
//#endregion
|
|
225
|
-
//#region src/form/Wizard/WizardStepContent.tsx
|
|
226
|
-
function WizardStepContent({ currentStep, stepConfig, flatten = true, values, onValuesChange, setFormDirty, setFieldValue, setFieldTouched, ...fieldsProps }) {
|
|
227
|
-
if (!stepConfig?.options) return null;
|
|
228
|
-
return /* @__PURE__ */ jsxs("div", {
|
|
229
|
-
className: "mb-4 w-full",
|
|
230
|
-
children: [
|
|
231
|
-
stepConfig.title && /* @__PURE__ */ jsx("h2", {
|
|
232
|
-
className: "text-2xl font-bold mb-2",
|
|
233
|
-
style: { color: "var(--theme-app)" },
|
|
234
|
-
children: stepConfig.title
|
|
235
|
-
}),
|
|
236
|
-
stepConfig.description && /* @__PURE__ */ jsx("p", {
|
|
237
|
-
className: "mb-4 leading-relaxed",
|
|
238
|
-
style: { color: "var(--theme-muted-text-color)" },
|
|
239
|
-
children: stepConfig.description
|
|
240
|
-
}),
|
|
241
|
-
/* @__PURE__ */ jsx(FieldsFromOptions, {
|
|
242
|
-
options: stepConfig.options,
|
|
243
|
-
values,
|
|
244
|
-
setFormDirty,
|
|
245
|
-
setFieldValue,
|
|
246
|
-
setFieldTouched,
|
|
247
|
-
...flatten === false ? { parentInfo: {
|
|
248
|
-
parentName: currentStep,
|
|
249
|
-
fieldNamePrefix: `${currentStep}.`
|
|
250
|
-
} } : {},
|
|
251
|
-
...fieldsProps
|
|
252
|
-
}, currentStep)
|
|
253
|
-
]
|
|
254
240
|
});
|
|
255
241
|
}
|
|
256
242
|
//#endregion
|
|
257
|
-
//#region src/form/
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
const
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
const
|
|
266
|
-
|
|
267
|
-
|
|
243
|
+
//#region src/form/SpecialTypes/FormikNumericInput.tsx
|
|
244
|
+
var DEBOUNCE_MS$1 = 500;
|
|
245
|
+
function FormikNumericInput({ name, placeholder, onChange, disabled, min, max, invalid = false }) {
|
|
246
|
+
const [field] = useField(name);
|
|
247
|
+
const required = useFieldRequired();
|
|
248
|
+
const controlProps = useFieldControlProps();
|
|
249
|
+
const { setFieldValue, setFieldTouched } = useFormikContext();
|
|
250
|
+
const [localValue, setLocalValue] = useState(field.value);
|
|
251
|
+
const isFocused = useRef(false);
|
|
252
|
+
const debounceRef = useRef(null);
|
|
253
|
+
useEffect(() => {
|
|
254
|
+
if (!isFocused.current) setLocalValue(field.value);
|
|
255
|
+
}, [field.value]);
|
|
256
|
+
const flush = (val) => {
|
|
257
|
+
onChange?.(val);
|
|
258
|
+
setFieldTouched(name, true);
|
|
259
|
+
setFieldValue(name, val);
|
|
268
260
|
};
|
|
269
|
-
const
|
|
270
|
-
|
|
261
|
+
const handleBlur = () => {
|
|
262
|
+
isFocused.current = false;
|
|
263
|
+
clearTimeout(debounceRef.current ?? void 0);
|
|
264
|
+
let val = localValue;
|
|
265
|
+
if (val !== void 0) {
|
|
266
|
+
if (min !== void 0 && val < min) val = min;
|
|
267
|
+
if (max !== void 0 && val > max) val = max;
|
|
268
|
+
}
|
|
269
|
+
setLocalValue(val);
|
|
270
|
+
flush(val);
|
|
271
271
|
};
|
|
272
|
-
return /* @__PURE__ */ jsx(
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
"text-white": isDotActive,
|
|
294
|
-
"bg-green-500 border-green-600 text-white shadow-md": isDotCompleted && !isInvalid,
|
|
295
|
-
"bg-(--theme-border) theme-border theme-muted-text shadow-sm": isDotUpcoming && !isInvalid,
|
|
296
|
-
"bg-(--theme-muted-panel-bg) theme-border theme-muted-text shadow-sm": !isDotActive && !isDotCompleted && !isDotUpcoming && !isInvalid,
|
|
297
|
-
"bg-red-50 border-red-500 text-red-600 shadow-sm": isInvalid && status !== "active"
|
|
298
|
-
}),
|
|
299
|
-
style: isDotActive ? {
|
|
300
|
-
backgroundColor: "var(--theme-element)",
|
|
301
|
-
borderColor: "var(--theme-element)",
|
|
302
|
-
color: "var(--theme-element-text)",
|
|
303
|
-
boxShadow: "0 4px 12px rgba(0, 0, 0, 0.15)",
|
|
304
|
-
zIndex: 10
|
|
305
|
-
} : { zIndex: 10 },
|
|
306
|
-
"aria-label": `Step ${index + 1}: ${stepConfig?.title}`,
|
|
307
|
-
title: stepConfig?.title,
|
|
308
|
-
children: [!hideStepNumbers && /* @__PURE__ */ jsx("span", {
|
|
309
|
-
className: cx({ hidden: status === "completed" }),
|
|
310
|
-
children: index + 1
|
|
311
|
-
}), status === "completed" && /* @__PURE__ */ jsx("svg", {
|
|
312
|
-
"aria-hidden": "true",
|
|
313
|
-
className: "w-4 h-4",
|
|
314
|
-
fill: "none",
|
|
315
|
-
stroke: "currentColor",
|
|
316
|
-
viewBox: "0 0 24 24",
|
|
317
|
-
children: /* @__PURE__ */ jsx("path", {
|
|
318
|
-
strokeLinecap: "round",
|
|
319
|
-
strokeLinejoin: "round",
|
|
320
|
-
strokeWidth: 3,
|
|
321
|
-
d: "M5 13l4 4L19 7"
|
|
322
|
-
})
|
|
323
|
-
})]
|
|
324
|
-
}),
|
|
325
|
-
index < stepOrder.length - 1 && /* @__PURE__ */ jsx("div", {
|
|
326
|
-
className: cx("absolute h-1 transition-all duration-300", {
|
|
327
|
-
"bg-green-500": index < currentIndex,
|
|
328
|
-
"bg-(--theme-border)": index >= currentIndex,
|
|
329
|
-
"opacity-25": index >= currentIndex
|
|
330
|
-
}),
|
|
331
|
-
style: {
|
|
332
|
-
top: "24px",
|
|
333
|
-
left: "calc(50% + 24px)",
|
|
334
|
-
right: "-50%",
|
|
335
|
-
boxShadow: index < currentIndex ? "0 1px 2px rgba(34, 197, 94, 0.2)" : "none"
|
|
336
|
-
},
|
|
337
|
-
"aria-hidden": "true"
|
|
338
|
-
}),
|
|
339
|
-
/* @__PURE__ */ jsxs("div", {
|
|
340
|
-
className: "mt-2 text-center",
|
|
341
|
-
children: [/* @__PURE__ */ jsx("div", {
|
|
342
|
-
className: cx("text-sm text-center transition-colors duration-300 max-w-30", {
|
|
343
|
-
"font-bold text-green-600": isDotCompleted && !isInvalid,
|
|
344
|
-
"font-bold text-red-600": isInvalid && status !== "active",
|
|
345
|
-
"font-semibold theme-muted-text": !isDotActive && !isDotCompleted && !isInvalid,
|
|
346
|
-
"font-bold text-white": isDotActive
|
|
347
|
-
}),
|
|
348
|
-
style: isDotActive ? { color: "var(--theme-element)" } : {},
|
|
349
|
-
children: stepConfig?.title
|
|
350
|
-
}), stepConfig?.description && /* @__PURE__ */ jsx("div", {
|
|
351
|
-
className: "text-xs theme-muted-text mt-1 text-center max-w-30",
|
|
352
|
-
children: stepConfig.description
|
|
353
|
-
})]
|
|
354
|
-
})
|
|
355
|
-
]
|
|
356
|
-
}, stepKey);
|
|
357
|
-
})
|
|
272
|
+
return /* @__PURE__ */ jsx(NumericFormat, {
|
|
273
|
+
...controlProps,
|
|
274
|
+
"data-1p-ignore": true,
|
|
275
|
+
className: cx("w-full", disabled && "disabled", invalid && "invalid"),
|
|
276
|
+
name,
|
|
277
|
+
...localValue === void 0 ? {} : { value: localValue },
|
|
278
|
+
"aria-required": required || void 0,
|
|
279
|
+
thousandSeparator: ",",
|
|
280
|
+
decimalScale: 20,
|
|
281
|
+
allowNegative: true,
|
|
282
|
+
disabled,
|
|
283
|
+
placeholder,
|
|
284
|
+
onValueChange: (v) => {
|
|
285
|
+
setLocalValue(v.floatValue);
|
|
286
|
+
clearTimeout(debounceRef.current ?? void 0);
|
|
287
|
+
debounceRef.current = setTimeout(() => flush(v.floatValue), DEBOUNCE_MS$1);
|
|
288
|
+
},
|
|
289
|
+
onFocus: () => {
|
|
290
|
+
isFocused.current = true;
|
|
291
|
+
},
|
|
292
|
+
onBlur: handleBlur
|
|
358
293
|
});
|
|
359
294
|
}
|
|
360
295
|
//#endregion
|
|
361
|
-
//#region src/form/
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
const
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
/**
|
|
377
|
-
* Mark step as invalid
|
|
378
|
-
*/
|
|
379
|
-
const markStepInvalid = useCallback((stepKey, invalid) => {
|
|
380
|
-
setInvalidSteps((prev) => {
|
|
381
|
-
const next = new Set(prev);
|
|
382
|
-
if (invalid) next.add(stepKey);
|
|
383
|
-
else next.delete(stepKey);
|
|
384
|
-
return next;
|
|
385
|
-
});
|
|
386
|
-
}, []);
|
|
387
|
-
const goToNext = useCallback(async () => {
|
|
388
|
-
if (isLastStep) return false;
|
|
389
|
-
if (steps[currentStep]?.validateOnNext !== false) {
|
|
390
|
-
if (!await validateStep(currentStep)) {
|
|
391
|
-
markStepInvalid(currentStep, true);
|
|
392
|
-
return false;
|
|
393
|
-
}
|
|
394
|
-
}
|
|
395
|
-
markStepInvalid(currentStep, false);
|
|
396
|
-
const nextStepKey = stepOrder[currentStepIndex + 1];
|
|
397
|
-
setCurrentStep(nextStepKey ?? "");
|
|
398
|
-
markStepVisited(nextStepKey ?? "");
|
|
399
|
-
return true;
|
|
400
|
-
}, [
|
|
401
|
-
currentStep,
|
|
402
|
-
currentStepIndex,
|
|
403
|
-
isLastStep,
|
|
404
|
-
steps,
|
|
405
|
-
stepOrder,
|
|
406
|
-
validateStep,
|
|
407
|
-
markStepInvalid,
|
|
408
|
-
markStepVisited
|
|
409
|
-
]);
|
|
410
|
-
const goToPrevious = useCallback(() => {
|
|
411
|
-
if (!canGoBack) return;
|
|
412
|
-
const prevStepKey = stepOrder[currentStepIndex - 1];
|
|
413
|
-
setCurrentStep(prevStepKey ?? "");
|
|
414
|
-
}, [
|
|
415
|
-
canGoBack,
|
|
416
|
-
currentStepIndex,
|
|
417
|
-
stepOrder
|
|
418
|
-
]);
|
|
419
|
-
const jumpToStep = useCallback((stepKey) => {
|
|
420
|
-
if (!stepOrder.includes(stepKey)) return false;
|
|
421
|
-
if (!visitedSteps.has(stepKey) && stepKey !== currentStep) return false;
|
|
422
|
-
setCurrentStep(stepKey);
|
|
423
|
-
return true;
|
|
424
|
-
}, [
|
|
425
|
-
stepOrder,
|
|
426
|
-
visitedSteps,
|
|
427
|
-
currentStep
|
|
428
|
-
]);
|
|
429
|
-
/**
|
|
430
|
-
* Reset wizard to initial state
|
|
431
|
-
*/
|
|
432
|
-
const reset = useCallback(() => {
|
|
433
|
-
setCurrentStep(firstStep);
|
|
434
|
-
setVisitedSteps(new Set([firstStep]));
|
|
435
|
-
setInvalidSteps(/* @__PURE__ */ new Set());
|
|
436
|
-
}, [firstStep]);
|
|
437
|
-
/**
|
|
438
|
-
* Get current wizard state
|
|
439
|
-
*/
|
|
440
|
-
const getState = useCallback(() => {
|
|
441
|
-
return {
|
|
442
|
-
currentStep,
|
|
443
|
-
visitedSteps,
|
|
444
|
-
invalidSteps,
|
|
445
|
-
stepOrder,
|
|
446
|
-
totalSteps: stepOrder.length,
|
|
447
|
-
isLastStep,
|
|
448
|
-
canProceedToNext: !isLastStep,
|
|
449
|
-
canGoBack
|
|
450
|
-
};
|
|
296
|
+
//#region src/form/utils/getPlaceholder.ts
|
|
297
|
+
/** `placeholder=""` (empty string) intentionally overrides the default; undefined does not. */
|
|
298
|
+
function getPlaceholder(placeholder, defaultValue) {
|
|
299
|
+
if (placeholder !== void 0) return placeholder;
|
|
300
|
+
if (defaultValue && (typeof defaultValue === "string" || typeof defaultValue === "number")) return defaultValue.toString();
|
|
301
|
+
return "";
|
|
302
|
+
}
|
|
303
|
+
//#endregion
|
|
304
|
+
//#region src/form/Fields/NumberField.tsx
|
|
305
|
+
function NumberField(props) {
|
|
306
|
+
const { field, label, labelPosition, missing, disabled, onChange, tooltipComponent, spaceCompact } = props;
|
|
307
|
+
const [fieldState] = useField(field.name);
|
|
308
|
+
const { setFieldValue } = useFormikContext();
|
|
309
|
+
useEffect(() => {
|
|
310
|
+
if (field.prefillDefault && field.default !== void 0 && (fieldState.value === void 0 || fieldState.value === null || fieldState.value === "")) setFieldValue(field.name, field.default);
|
|
451
311
|
}, [
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
canGoBack
|
|
312
|
+
field.prefillDefault,
|
|
313
|
+
field.default,
|
|
314
|
+
field.name,
|
|
315
|
+
fieldState.value,
|
|
316
|
+
setFieldValue
|
|
458
317
|
]);
|
|
459
|
-
return {
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
318
|
+
return /* @__PURE__ */ jsx(FieldWrapper, {
|
|
319
|
+
optional: field.optional,
|
|
320
|
+
label,
|
|
321
|
+
tooltipComponent,
|
|
322
|
+
labelPosition,
|
|
323
|
+
spaceCompact,
|
|
324
|
+
children: field.thousandsSeparator ? /* @__PURE__ */ jsx(FormikNumericInput, {
|
|
325
|
+
invalid: missing,
|
|
326
|
+
name: field.name,
|
|
327
|
+
placeholder: getPlaceholder(field.placeholder, field.default),
|
|
328
|
+
disabled,
|
|
329
|
+
min: field.min,
|
|
330
|
+
max: field.max,
|
|
331
|
+
...onChange && { onChange }
|
|
332
|
+
}, field.name) : /* @__PURE__ */ jsx(FormikCustomInput, {
|
|
333
|
+
invalid: missing,
|
|
334
|
+
name: field.name,
|
|
335
|
+
type: "number",
|
|
336
|
+
placeholder: getPlaceholder(field.placeholder, field.default),
|
|
337
|
+
disabled,
|
|
338
|
+
step: field.step,
|
|
339
|
+
min: field.min,
|
|
340
|
+
max: field.max,
|
|
341
|
+
defaultValue: field.default,
|
|
342
|
+
...onChange && { onChange }
|
|
343
|
+
}, field.name)
|
|
344
|
+
});
|
|
475
345
|
}
|
|
476
346
|
//#endregion
|
|
477
|
-
//#region src/form/
|
|
478
|
-
function
|
|
479
|
-
return
|
|
347
|
+
//#region src/form/Fields/ResourceOptionIcon.tsx
|
|
348
|
+
function ResourceOptionIcon({ imageUrl, fallbackIcon, alt, variant = "success", dotSize = 6 }) {
|
|
349
|
+
return /* @__PURE__ */ jsxs("span", {
|
|
350
|
+
className: "flex items-center gap-1.5 shrink-0",
|
|
351
|
+
children: [/* @__PURE__ */ jsx(StatusDot, {
|
|
352
|
+
variant,
|
|
353
|
+
size: dotSize
|
|
354
|
+
}), /* @__PURE__ */ jsx("img", {
|
|
355
|
+
src: imageUrl || fallbackIcon,
|
|
356
|
+
alt,
|
|
357
|
+
className: "h-4 w-4 object-contain",
|
|
358
|
+
onError: (e) => {
|
|
359
|
+
e.currentTarget.src = fallbackIcon;
|
|
360
|
+
}
|
|
361
|
+
})]
|
|
362
|
+
});
|
|
480
363
|
}
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
const {
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
onChange
|
|
526
|
-
]);
|
|
527
|
-
const handleJumpToStep = useCallback((stepKey) => {
|
|
528
|
-
if (!config_.allowJump || !visitedSteps.has(stepKey)) return false;
|
|
529
|
-
return jumpToStep(stepKey);
|
|
530
|
-
}, [
|
|
531
|
-
jumpToStep,
|
|
532
|
-
config_.allowJump,
|
|
533
|
-
visitedSteps
|
|
534
|
-
]);
|
|
535
|
-
const handleSubmit = useCallback(async () => {
|
|
536
|
-
if (!isLastStep) return;
|
|
537
|
-
const errors = await validateForm();
|
|
538
|
-
if (Object.keys(errors).length > 0) {
|
|
539
|
-
const touchedFields = Object.keys(values).reduce((acc, fieldName) => {
|
|
540
|
-
acc[fieldName] = true;
|
|
541
|
-
return acc;
|
|
542
|
-
}, {});
|
|
543
|
-
setTouched({
|
|
544
|
-
...touched,
|
|
545
|
-
...touchedFields
|
|
546
|
-
}, false);
|
|
547
|
-
throw new Error("Please fix errors before submitting");
|
|
548
|
-
}
|
|
549
|
-
await onSubmit?.(values);
|
|
550
|
-
}, [
|
|
551
|
-
isLastStep,
|
|
552
|
-
validateForm,
|
|
553
|
-
values,
|
|
554
|
-
setTouched,
|
|
555
|
-
touched,
|
|
556
|
-
onSubmit
|
|
557
|
-
]);
|
|
558
|
-
return /* @__PURE__ */ jsxs("div", {
|
|
559
|
-
className,
|
|
560
|
-
children: [
|
|
561
|
-
config_.showSteps !== false && /* @__PURE__ */ jsx(WizardStepIndicator, {
|
|
562
|
-
stepOrder,
|
|
563
|
-
currentStep,
|
|
564
|
-
steps,
|
|
565
|
-
visitedSteps,
|
|
566
|
-
invalidSteps,
|
|
567
|
-
onStepClick: handleJumpToStep,
|
|
568
|
-
allowJump: config_.allowJump,
|
|
569
|
-
hideStepNumbers: config_.hideStepNumbers
|
|
570
|
-
}),
|
|
571
|
-
currentStepConfig && /* @__PURE__ */ jsx("div", {
|
|
572
|
-
className: "mb-4",
|
|
573
|
-
children: /* @__PURE__ */ jsx(WizardStepContent, {
|
|
574
|
-
currentStep,
|
|
575
|
-
stepConfig: currentStepConfig,
|
|
576
|
-
flatten: config.flatten,
|
|
577
|
-
values,
|
|
578
|
-
onValuesChange: onChange,
|
|
579
|
-
labelPosition,
|
|
580
|
-
missingFields,
|
|
581
|
-
spaceCompact,
|
|
582
|
-
setFormDirty: () => onChange?.(values),
|
|
583
|
-
workflowForm,
|
|
584
|
-
setFieldValue,
|
|
585
|
-
setFieldTouched
|
|
586
|
-
})
|
|
587
|
-
}),
|
|
588
|
-
/* @__PURE__ */ jsx(WizardNavigation, {
|
|
589
|
-
currentStep,
|
|
590
|
-
stepOrder,
|
|
591
|
-
canGoToNext: !isLastStep,
|
|
592
|
-
canGoBack,
|
|
593
|
-
isCurrentStepValid: !invalidSteps.has(currentStep),
|
|
594
|
-
nextLabel: currentStepConfig?.nextLabel,
|
|
595
|
-
prevLabel: currentStepConfig?.prevLabel,
|
|
596
|
-
submitLabel: config.submitLabel || "Execute",
|
|
597
|
-
onNext: handleGoToNext,
|
|
598
|
-
onPrevious: goToPrevious,
|
|
599
|
-
onSubmit: handleSubmit
|
|
600
|
-
})
|
|
601
|
-
]
|
|
364
|
+
//#endregion
|
|
365
|
+
//#region src/form/Fields/BooleanField.tsx
|
|
366
|
+
function BooleanField(props) {
|
|
367
|
+
const { field, label, labelPosition, missing, disabled, onChange, tooltipComponent, spaceCompact, setFormDirty } = props;
|
|
368
|
+
const [fieldState] = useField(field.name);
|
|
369
|
+
const { setFieldValue, setFieldTouched } = useFormikContext();
|
|
370
|
+
const handleChange = (val) => {
|
|
371
|
+
if (disabled) return;
|
|
372
|
+
if (onChange) onChange(val);
|
|
373
|
+
setFieldTouched(field.name, true);
|
|
374
|
+
setFieldValue(field.name, val);
|
|
375
|
+
setFormDirty(true);
|
|
376
|
+
};
|
|
377
|
+
const value = fieldState.value;
|
|
378
|
+
const options = field.options ? {
|
|
379
|
+
onOption: String(field.options.onOption ?? true),
|
|
380
|
+
offOption: String(field.options.offOption ?? false)
|
|
381
|
+
} : void 0;
|
|
382
|
+
const displayLabel = (option) => option.charAt(0).toUpperCase() + option.slice(1).toLowerCase();
|
|
383
|
+
return /* @__PURE__ */ jsx(FieldWrapper, {
|
|
384
|
+
optional: true,
|
|
385
|
+
label,
|
|
386
|
+
tooltipComponent: /* @__PURE__ */ jsx("div", { children: tooltipComponent }),
|
|
387
|
+
description: field.description,
|
|
388
|
+
labelPosition,
|
|
389
|
+
spaceCompact,
|
|
390
|
+
children: ({ id, describedBy }) => options ? /* @__PURE__ */ jsx(SwitchToggle, {
|
|
391
|
+
id,
|
|
392
|
+
"aria-describedby": describedBy,
|
|
393
|
+
onChange: (on) => handleChange(on ? options.onOption : options.offOption),
|
|
394
|
+
value: value === true || value === options.onOption,
|
|
395
|
+
yesLabel: displayLabel(options.onOption),
|
|
396
|
+
noLabel: displayLabel(options.offOption),
|
|
397
|
+
disabled,
|
|
398
|
+
invalid: missing
|
|
399
|
+
}) : /* @__PURE__ */ jsx(SwitchToggle, {
|
|
400
|
+
id,
|
|
401
|
+
"aria-describedby": describedBy,
|
|
402
|
+
datatip: field.disabled_message,
|
|
403
|
+
onChange: handleChange,
|
|
404
|
+
value: value === true || value === "true",
|
|
405
|
+
disabled,
|
|
406
|
+
invalid: missing
|
|
407
|
+
})
|
|
602
408
|
});
|
|
603
409
|
}
|
|
604
410
|
//#endregion
|
|
605
|
-
//#region src/form/
|
|
606
|
-
function
|
|
607
|
-
|
|
411
|
+
//#region src/form/Fields/CheckboxGroupField.tsx
|
|
412
|
+
function impliedFrom(values, implies = {}) {
|
|
413
|
+
const result = /* @__PURE__ */ new Set();
|
|
414
|
+
for (const value of values) for (const target of implies[value] ?? []) result.add(target);
|
|
415
|
+
return result;
|
|
608
416
|
}
|
|
609
|
-
function
|
|
610
|
-
return
|
|
417
|
+
function union(manual, forced) {
|
|
418
|
+
return [...manual, ...[...forced].filter((v) => !manual.includes(v))];
|
|
611
419
|
}
|
|
612
|
-
function
|
|
613
|
-
const
|
|
614
|
-
const
|
|
615
|
-
|
|
616
|
-
const
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
if (key === "$meta") return;
|
|
621
|
-
if (isStepField(field)) {
|
|
622
|
-
steps[key] = field;
|
|
623
|
-
stepOrder.push(key);
|
|
624
|
-
} else otherFields[key] = field;
|
|
420
|
+
function CheckboxGroupField({ field, label, labelPosition, missing, disabled, onChange, tooltipComponent, spaceCompact, setFormDirty }) {
|
|
421
|
+
const [fieldState] = useField(field.name);
|
|
422
|
+
const { setFieldValue, setFieldTouched } = useFormikContext();
|
|
423
|
+
const implies = field.implies;
|
|
424
|
+
const [manual, setManual] = useState(() => {
|
|
425
|
+
const saved = fieldState.value || [];
|
|
426
|
+
const impliedBySaved = impliedFrom(saved, implies);
|
|
427
|
+
return saved.filter((v) => !impliedBySaved.has(v));
|
|
625
428
|
});
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
return
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
429
|
+
const forced = impliedFrom(manual, implies);
|
|
430
|
+
const handleToggle = (value) => {
|
|
431
|
+
if (disabled) return;
|
|
432
|
+
const nextManual = manual.includes(value) ? manual.filter((v) => v !== value) : [...manual, value];
|
|
433
|
+
const next = union(nextManual, impliedFrom(nextManual, implies));
|
|
434
|
+
setManual(nextManual);
|
|
435
|
+
setFieldTouched(field.name, true);
|
|
436
|
+
setFieldValue(field.name, next);
|
|
437
|
+
if (onChange) onChange(next);
|
|
438
|
+
setFormDirty(true);
|
|
635
439
|
};
|
|
440
|
+
return /* @__PURE__ */ jsx(FieldWrapper, {
|
|
441
|
+
optional: field.optional,
|
|
442
|
+
label,
|
|
443
|
+
tooltipComponent,
|
|
444
|
+
labelPosition,
|
|
445
|
+
spaceCompact,
|
|
446
|
+
children: ({ labelId, describedBy }) => /* @__PURE__ */ jsx("fieldset", {
|
|
447
|
+
"aria-labelledby": labelId,
|
|
448
|
+
"aria-describedby": describedBy,
|
|
449
|
+
className: "flex min-w-0 max-w-lg flex-col gap-1",
|
|
450
|
+
children: field.options?.map((option) => {
|
|
451
|
+
const locked = forced.has(option.value);
|
|
452
|
+
const optionDisabled = disabled || locked;
|
|
453
|
+
return /* @__PURE__ */ jsxs("label", {
|
|
454
|
+
className: cx("-mx-2 flex items-start gap-2.5 rounded-md px-2 py-1.5 transition-colors", optionDisabled ? "cursor-not-allowed opacity-60" : "cursor-pointer hover:bg-(--theme-hover) has-[:focus-visible]:bg-(--theme-hover)"),
|
|
455
|
+
children: [/* @__PURE__ */ jsx("input", {
|
|
456
|
+
type: "checkbox",
|
|
457
|
+
checked: manual.includes(option.value) || locked,
|
|
458
|
+
disabled: optionDisabled,
|
|
459
|
+
onChange: () => handleToggle(option.value),
|
|
460
|
+
className: cx("mt-px h-4 w-4 rounded accent-(--theme-link)", optionDisabled ? "cursor-not-allowed" : "cursor-pointer", missing && "invalid")
|
|
461
|
+
}), /* @__PURE__ */ jsxs("div", {
|
|
462
|
+
className: "flex min-w-0 flex-col",
|
|
463
|
+
children: [/* @__PURE__ */ jsx("span", {
|
|
464
|
+
className: "font-medium leading-tight theme-text",
|
|
465
|
+
children: option.label
|
|
466
|
+
}), option.description && /* @__PURE__ */ jsx("span", {
|
|
467
|
+
className: "mt-0.5 text-xs leading-snug theme-muted-text",
|
|
468
|
+
children: option.description
|
|
469
|
+
})]
|
|
470
|
+
})]
|
|
471
|
+
}, field.name + option.value);
|
|
472
|
+
})
|
|
473
|
+
})
|
|
474
|
+
});
|
|
636
475
|
}
|
|
637
476
|
//#endregion
|
|
638
|
-
//#region src/form/
|
|
639
|
-
function
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
const base = {
|
|
646
|
-
label: o.label,
|
|
647
|
-
value: o.value,
|
|
648
|
-
disabled: o.disabled
|
|
649
|
-
};
|
|
650
|
-
return o.description !== void 0 ? {
|
|
651
|
-
...base,
|
|
652
|
-
description: o.description
|
|
653
|
-
} : base;
|
|
654
|
-
})
|
|
655
|
-
};
|
|
656
|
-
const base = {
|
|
657
|
-
label: option.label,
|
|
658
|
-
value: option.value,
|
|
659
|
-
disabled: option.disabled
|
|
660
|
-
};
|
|
661
|
-
return option.description !== void 0 ? {
|
|
662
|
-
...base,
|
|
663
|
-
description: option.description
|
|
664
|
-
} : base;
|
|
665
|
-
});
|
|
666
|
-
}
|
|
667
|
-
function arePropsEqual(prev, next) {
|
|
668
|
-
for (const key of Object.keys(next)) if (key === "options") {
|
|
669
|
-
if (!deepEqual(toComparableOptions(prev.options), toComparableOptions(next.options))) return false;
|
|
670
|
-
} else if (prev[key] !== next[key]) return false;
|
|
671
|
-
return true;
|
|
672
|
-
}
|
|
673
|
-
var FormikCustomDropdown_default = memo(function FormikCustomDropdown({ name, ariaLabel, options, setFormDirty, onChange, parentValue, className, secondaryField, disabled = false, loading = false, invalid = false, autoselect, value, allowCustomValue = false, customValueLabel, placeholder, currentValue, setFieldValue, setFieldTouched }) {
|
|
674
|
-
const required = useFieldRequired();
|
|
675
|
-
const controlProps = useFieldControlProps();
|
|
676
|
-
const prevParentRef = useRef(parentValue);
|
|
677
|
-
const handleChange = (val) => {
|
|
678
|
-
if (secondaryField && typeof options[0] !== "string") {
|
|
679
|
-
const option = findSecondaryOption(options, val);
|
|
680
|
-
if (option) applySecondaryField(secondaryField, option.secondaryValue, setFieldValue);
|
|
681
|
-
}
|
|
477
|
+
//#region src/form/Fields/ColorField.tsx
|
|
478
|
+
function ColorField(props) {
|
|
479
|
+
const { field, label, labelPosition, onChange, tooltipComponent, spaceCompact } = props;
|
|
480
|
+
const [fieldState] = useField(field.name);
|
|
481
|
+
const { setFieldValue, setFieldTouched } = useFormikContext();
|
|
482
|
+
const handleChange = (e) => {
|
|
483
|
+
const val = e.target.value;
|
|
682
484
|
if (onChange) onChange(val);
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
setFormDirty(true);
|
|
485
|
+
setFieldTouched(field.name, true);
|
|
486
|
+
setFieldValue(field.name, val);
|
|
686
487
|
};
|
|
687
|
-
|
|
688
|
-
|
|
488
|
+
return /* @__PURE__ */ jsx(FieldWrapper, {
|
|
489
|
+
optional: field.optional,
|
|
490
|
+
label,
|
|
491
|
+
tooltipComponent,
|
|
492
|
+
labelPosition,
|
|
493
|
+
spaceCompact,
|
|
494
|
+
children: ({ id }) => /* @__PURE__ */ jsx(Field, {
|
|
495
|
+
className: "theme-input h-8 w-18 rounded border border-neutral-400 placeholder:text-xs",
|
|
496
|
+
id,
|
|
497
|
+
name: field.name,
|
|
498
|
+
value: fieldState.value || "#fbbf24",
|
|
499
|
+
type: "color",
|
|
500
|
+
"aria-required": field.optional ? void 0 : true,
|
|
501
|
+
onChange: handleChange
|
|
502
|
+
})
|
|
689
503
|
});
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
if (
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
|
|
504
|
+
}
|
|
505
|
+
//#endregion
|
|
506
|
+
//#region src/form/Fields/DropdownField.tsx
|
|
507
|
+
function DropdownField(props) {
|
|
508
|
+
const { field, label, labelPosition, missing, disabled, onChange, tooltipComponent, spaceCompact, setFieldValue, setFieldTouched, currentValue } = props;
|
|
509
|
+
let parentValue = field.parentValue;
|
|
510
|
+
let options = Array.isArray(field.options) && field.options || [];
|
|
511
|
+
if (field.depends_on) {
|
|
512
|
+
parentValue = field.depends_on;
|
|
513
|
+
if (!Array.isArray(field.options)) options = field.options[parentValue] ?? [];
|
|
514
|
+
}
|
|
515
|
+
const secondaryField = Array.isArray(field.secondaryField) ? field.secondaryField[0] : field.secondaryField;
|
|
516
|
+
return /* @__PURE__ */ jsx(FieldWrapper, {
|
|
517
|
+
optional: field.optional,
|
|
518
|
+
label,
|
|
519
|
+
tooltipComponent,
|
|
520
|
+
description: field.description,
|
|
521
|
+
labelPosition,
|
|
522
|
+
spaceCompact,
|
|
523
|
+
children: /* @__PURE__ */ jsx("div", {
|
|
524
|
+
className: "grow min-w-0",
|
|
525
|
+
children: /* @__PURE__ */ jsx(FormikCustomDropdown_default, {
|
|
526
|
+
invalid: missing,
|
|
527
|
+
className: "w-full",
|
|
528
|
+
name: field.name,
|
|
529
|
+
ariaLabel: label,
|
|
530
|
+
options,
|
|
531
|
+
setFormDirty: props.setFormDirty,
|
|
532
|
+
parentValue,
|
|
533
|
+
onChange,
|
|
534
|
+
secondaryField,
|
|
535
|
+
disabled,
|
|
536
|
+
resetOnChange: field.resetOnChange ? field.name : "",
|
|
537
|
+
loading: false,
|
|
538
|
+
autoselect: field.autoselect,
|
|
539
|
+
allowCustomValue: field.allowCustomValue,
|
|
540
|
+
customValueLabel: field.customValueLabel,
|
|
541
|
+
placeholder: getPlaceholder(field.placeholder, typeof field.default === "string" ? field.default : void 0),
|
|
542
|
+
currentValue,
|
|
543
|
+
setFieldValue,
|
|
544
|
+
setFieldTouched
|
|
545
|
+
}, field.name)
|
|
546
|
+
})
|
|
547
|
+
});
|
|
548
|
+
}
|
|
549
|
+
//#endregion
|
|
550
|
+
//#region src/form/utils/duration.ts
|
|
551
|
+
var WITH_DAYS = /^(\d+)-(\d{1,2})(?::(\d{1,2})(?::(\d{1,2}))?)?$/;
|
|
552
|
+
var WITHOUT_DAYS = /^(\d+):(\d{1,2}):(\d{1,2})$/;
|
|
553
|
+
function parseDuration(text) {
|
|
554
|
+
const trimmed = text.trim();
|
|
555
|
+
let days = 0;
|
|
556
|
+
let hours;
|
|
557
|
+
let minutes;
|
|
558
|
+
let seconds;
|
|
559
|
+
const withDays = trimmed.match(WITH_DAYS);
|
|
560
|
+
if (withDays) {
|
|
561
|
+
days = Number(withDays[1]);
|
|
562
|
+
hours = Number(withDays[2]);
|
|
563
|
+
minutes = Number(withDays[3] ?? 0);
|
|
564
|
+
seconds = Number(withDays[4] ?? 0);
|
|
565
|
+
if (hours > 23) return null;
|
|
566
|
+
} else {
|
|
567
|
+
const withoutDays = trimmed.match(WITHOUT_DAYS);
|
|
568
|
+
if (!withoutDays) return null;
|
|
569
|
+
hours = Number(withoutDays[1]);
|
|
570
|
+
minutes = Number(withoutDays[2]);
|
|
571
|
+
seconds = Number(withoutDays[3]);
|
|
572
|
+
}
|
|
573
|
+
if (minutes > 59 || seconds > 59) return null;
|
|
574
|
+
return days * 86400 + hours * 3600 + minutes * 60 + seconds;
|
|
575
|
+
}
|
|
576
|
+
function formatDuration(totalSeconds) {
|
|
577
|
+
if (!Number.isFinite(totalSeconds) || totalSeconds < 0) return "";
|
|
578
|
+
const parts = Duration.fromObject({ seconds: Math.floor(totalSeconds) }).shiftTo("days", "hours", "minutes", "seconds");
|
|
579
|
+
const pad = (n) => String(n).padStart(2, "0");
|
|
580
|
+
const time = `${pad(parts.hours)}:${pad(parts.minutes)}:${pad(parts.seconds)}`;
|
|
581
|
+
return parts.days > 0 ? `${parts.days}-${time}` : time;
|
|
582
|
+
}
|
|
583
|
+
var FLEX_MAX_DURATION_RANGE = {
|
|
584
|
+
min: 600,
|
|
585
|
+
max: 604800
|
|
586
|
+
};
|
|
587
|
+
var FLEX_WAIT_TIME_RANGE = {
|
|
588
|
+
min: 30,
|
|
589
|
+
max: 604800
|
|
590
|
+
};
|
|
591
|
+
var STANDARD_MAX_DURATION_RANGE = {
|
|
592
|
+
min: 30,
|
|
593
|
+
max: 10368e3
|
|
594
|
+
};
|
|
595
|
+
var DURATION_PATH = /^partitions\[\d+\]\.(maxDuration|flexStartWaitTime|suspendTime)$/;
|
|
596
|
+
function collectPartitionDurationIssues(partitions, invalidDurationPaths) {
|
|
597
|
+
const issues = new Set(invalidDurationPaths.filter((path) => DURATION_PATH.test(path)));
|
|
598
|
+
(partitions ?? []).forEach((partition, i) => {
|
|
599
|
+
const p = partition;
|
|
600
|
+
const check = (fieldName, range, required) => {
|
|
601
|
+
const raw = p?.[fieldName];
|
|
602
|
+
if (raw === void 0 || raw === null || raw === "") {
|
|
603
|
+
if (required) issues.add(`partitions[${i}].${fieldName}`);
|
|
604
|
+
return;
|
|
728
605
|
}
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
return /* @__PURE__ */ jsx(Dropdown, {
|
|
737
|
-
...controlProps,
|
|
738
|
-
textBoxClassName: cx(className, invalid && "invalid"),
|
|
739
|
-
ariaLabel,
|
|
740
|
-
required,
|
|
741
|
-
onChange: (val) => handleChange(val),
|
|
742
|
-
value: options?.length === 0 && !allowCustomValue ? value : currentValue,
|
|
743
|
-
options,
|
|
744
|
-
placeholder,
|
|
745
|
-
disabled,
|
|
746
|
-
loading,
|
|
747
|
-
allowCustomValue,
|
|
748
|
-
customValueLabel
|
|
606
|
+
const value = Number(raw);
|
|
607
|
+
if (!Number.isFinite(value) || value < range.min || value > range.max) issues.add(`partitions[${i}].${fieldName}`);
|
|
608
|
+
};
|
|
609
|
+
if (p?.provisioningMode === "flex") {
|
|
610
|
+
check("maxDuration", FLEX_MAX_DURATION_RANGE, true);
|
|
611
|
+
check("flexStartWaitTime", FLEX_WAIT_TIME_RANGE, true);
|
|
612
|
+
} else check("maxDuration", STANDARD_MAX_DURATION_RANGE, false);
|
|
749
613
|
});
|
|
750
|
-
|
|
614
|
+
return [...issues];
|
|
615
|
+
}
|
|
751
616
|
//#endregion
|
|
752
|
-
//#region src/form/
|
|
753
|
-
var DEBOUNCE_MS
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
const
|
|
762
|
-
const
|
|
617
|
+
//#region src/form/Fields/DurationField.tsx
|
|
618
|
+
var DEBOUNCE_MS = 500;
|
|
619
|
+
var isNumericString = (value) => typeof value === "string" && /^\d+$/.test(value.trim());
|
|
620
|
+
var toDisplay = (value) => {
|
|
621
|
+
if (typeof value === "number") return formatDuration(value);
|
|
622
|
+
if (isNumericString(value)) return formatDuration(Number(value));
|
|
623
|
+
return "";
|
|
624
|
+
};
|
|
625
|
+
var DurationField_default = memo(function DurationField({ field, label, labelPosition, missing, disabled, onChange, tooltipComponent, spaceCompact, setFormDirty, currentValue, setFieldValue, setFieldTouched }) {
|
|
626
|
+
const { form: t } = useStrings();
|
|
627
|
+
const name = field.name;
|
|
628
|
+
const min = field.min !== void 0 ? Number(field.min) : Number.NEGATIVE_INFINITY;
|
|
629
|
+
const max = field.max !== void 0 ? Number(field.max) : Number.POSITIVE_INFINITY;
|
|
630
|
+
const disableValue = field.disableValue;
|
|
631
|
+
const hasDisableCheckbox = disableValue !== void 0 && field.disableLabel !== void 0;
|
|
632
|
+
const isSentinel = hasDisableCheckbox && currentValue !== "" && Number(currentValue) === disableValue;
|
|
633
|
+
const [text, setText] = useState(() => toDisplay(currentValue));
|
|
634
|
+
const focusedRef = useRef(false);
|
|
763
635
|
const debounceRef = useRef(null);
|
|
764
636
|
useEffect(() => {
|
|
765
|
-
if (
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
if (
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
|
|
773
|
-
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
}, [
|
|
783
|
-
|
|
784
|
-
|
|
785
|
-
setFieldTouched,
|
|
786
|
-
setFieldValue
|
|
787
|
-
]);
|
|
788
|
-
const handleChange = (e) => {
|
|
789
|
-
const text = sanitize ? sanitizeName(e.target.value) : e.target.value;
|
|
790
|
-
let val = text;
|
|
791
|
-
if (type === "number") {
|
|
792
|
-
const parsed = parseFloat(text);
|
|
793
|
-
val = isNaN(parsed) ? void 0 : parsed;
|
|
794
|
-
}
|
|
795
|
-
if (type === "password" && val === "") val = defaultValue;
|
|
796
|
-
setLocalValue(val);
|
|
637
|
+
if (isSentinel) {
|
|
638
|
+
if (typeof currentValue !== "number") setFieldValue?.(name, disableValue);
|
|
639
|
+
} else if (isNumericString(currentValue)) setFieldValue?.(name, Number(currentValue));
|
|
640
|
+
else if ((currentValue === void 0 || currentValue === null || currentValue === "") && typeof field.default === "number") setFieldValue?.(name, field.default);
|
|
641
|
+
}, []);
|
|
642
|
+
useEffect(() => {
|
|
643
|
+
if (!focusedRef.current) setText(toDisplay(currentValue));
|
|
644
|
+
}, [currentValue]);
|
|
645
|
+
const trimmed = text.trim();
|
|
646
|
+
const parsed = trimmed === "" ? null : parseDuration(trimmed);
|
|
647
|
+
let error = null;
|
|
648
|
+
if (!isSentinel && trimmed !== "") {
|
|
649
|
+
if (parsed === null) error = t.invalidDuration;
|
|
650
|
+
else if (parsed < min || parsed > max) error = Number.isFinite(max) ? t.durationOutOfRange(formatDuration(Math.max(min, 0)), formatDuration(max)) : t.durationBelowMin(formatDuration(Math.max(min, 0)));
|
|
651
|
+
}
|
|
652
|
+
useEffect(() => {
|
|
653
|
+
setDurationValidity(name, error === null);
|
|
654
|
+
}, [name, error]);
|
|
655
|
+
useEffect(() => () => {
|
|
656
|
+
setDurationValidity(name, true);
|
|
797
657
|
clearTimeout(debounceRef.current ?? void 0);
|
|
798
|
-
|
|
658
|
+
}, [name]);
|
|
659
|
+
const flushToFormik = (val) => {
|
|
660
|
+
setFieldValue?.(name, val);
|
|
661
|
+
onChange?.(val);
|
|
662
|
+
setFieldTouched?.(name, true);
|
|
799
663
|
};
|
|
800
|
-
const
|
|
801
|
-
|
|
664
|
+
const handleDisableToggle = (checked) => {
|
|
665
|
+
clearTimeout(debounceRef.current ?? void 0);
|
|
666
|
+
setFormDirty(true);
|
|
667
|
+
if (checked) {
|
|
668
|
+
setText("");
|
|
669
|
+
flushToFormik(disableValue);
|
|
670
|
+
} else flushToFormik(typeof field.default === "number" ? field.default : "");
|
|
802
671
|
};
|
|
803
|
-
const
|
|
804
|
-
|
|
672
|
+
const handleChange = (e) => {
|
|
673
|
+
const raw = e.target.value;
|
|
674
|
+
setText(raw);
|
|
675
|
+
setFormDirty(true);
|
|
805
676
|
clearTimeout(debounceRef.current ?? void 0);
|
|
806
|
-
const
|
|
807
|
-
|
|
808
|
-
|
|
809
|
-
let val = text;
|
|
810
|
-
if (type === "number") {
|
|
811
|
-
const parsed = parseFloat(text);
|
|
812
|
-
if (Number.isNaN(parsed)) val = void 0;
|
|
813
|
-
else if (min !== void 0 && parsed < min) val = min;
|
|
814
|
-
else if (max !== void 0 && parsed > max) val = max;
|
|
815
|
-
else val = parsed;
|
|
816
|
-
}
|
|
817
|
-
setLocalValue(val);
|
|
818
|
-
flushToFormik(val);
|
|
677
|
+
const rawTrimmed = raw.trim();
|
|
678
|
+
const value = rawTrimmed === "" ? "" : parseDuration(rawTrimmed);
|
|
679
|
+
if (value === "" || typeof value === "number" && value >= min && value <= max) debounceRef.current = setTimeout(() => flushToFormik(value), DEBOUNCE_MS);
|
|
819
680
|
};
|
|
820
|
-
const
|
|
821
|
-
|
|
822
|
-
const input = /* @__PURE__ */ jsx("input", {
|
|
823
|
-
...controlProps,
|
|
824
|
-
"data-1p-ignore": true,
|
|
825
|
-
className: cx("w-full", disabled && "disabled", invalid && "invalid", isPassword && "pr-8"),
|
|
826
|
-
name,
|
|
827
|
-
value: displayValue,
|
|
828
|
-
type: resolvedType,
|
|
829
|
-
"aria-required": required || void 0,
|
|
830
|
-
disabled,
|
|
831
|
-
placeholder,
|
|
832
|
-
minLength,
|
|
833
|
-
maxLength,
|
|
834
|
-
onChange: handleChange,
|
|
835
|
-
onFocus: handleFocus,
|
|
836
|
-
onBlur: handleBlur,
|
|
837
|
-
min,
|
|
838
|
-
max,
|
|
839
|
-
step
|
|
840
|
-
});
|
|
841
|
-
if (!isPassword) return input;
|
|
842
|
-
return /* @__PURE__ */ jsxs("div", {
|
|
843
|
-
className: "relative w-full",
|
|
844
|
-
children: [input, /* @__PURE__ */ jsx("button", {
|
|
845
|
-
type: "button",
|
|
846
|
-
className: "absolute right-2 top-1/2 -translate-y-1/2 theme-muted-text",
|
|
847
|
-
onClick: () => setShowPassword((prev) => !prev),
|
|
848
|
-
disabled,
|
|
849
|
-
tabIndex: -1,
|
|
850
|
-
"aria-label": showPassword ? "Hide value" : "Show value",
|
|
851
|
-
children: showPassword ? /* @__PURE__ */ jsx(EyeOffIcon, { className: "h-4 w-4" }) : /* @__PURE__ */ jsx(EyeIcon, { className: "h-4 w-4" })
|
|
852
|
-
})]
|
|
853
|
-
});
|
|
854
|
-
}
|
|
855
|
-
//#endregion
|
|
856
|
-
//#region src/form/SpecialTypes/FormikNumericInput.tsx
|
|
857
|
-
var DEBOUNCE_MS$1 = 500;
|
|
858
|
-
function FormikNumericInput({ name, placeholder, onChange, disabled, min, max, invalid = false }) {
|
|
859
|
-
const [field] = useField(name);
|
|
860
|
-
const required = useFieldRequired();
|
|
861
|
-
const controlProps = useFieldControlProps();
|
|
862
|
-
const { setFieldValue, setFieldTouched } = useFormikContext();
|
|
863
|
-
const [localValue, setLocalValue] = useState(field.value);
|
|
864
|
-
const isFocused = useRef(false);
|
|
865
|
-
const debounceRef = useRef(null);
|
|
866
|
-
useEffect(() => {
|
|
867
|
-
if (!isFocused.current) setLocalValue(field.value);
|
|
868
|
-
}, [field.value]);
|
|
869
|
-
const flush = (val) => {
|
|
870
|
-
onChange?.(val);
|
|
871
|
-
setFieldTouched(name, true);
|
|
872
|
-
setFieldValue(name, val);
|
|
681
|
+
const handleFocus = () => {
|
|
682
|
+
focusedRef.current = true;
|
|
873
683
|
};
|
|
874
684
|
const handleBlur = () => {
|
|
875
|
-
|
|
685
|
+
focusedRef.current = false;
|
|
876
686
|
clearTimeout(debounceRef.current ?? void 0);
|
|
877
|
-
|
|
878
|
-
|
|
879
|
-
|
|
880
|
-
|
|
687
|
+
if (trimmed === "") {
|
|
688
|
+
setText("");
|
|
689
|
+
flushToFormik("");
|
|
690
|
+
} else if (parsed !== null && parsed >= min && parsed <= max) {
|
|
691
|
+
setText(formatDuration(parsed));
|
|
692
|
+
flushToFormik(parsed);
|
|
881
693
|
}
|
|
882
|
-
setLocalValue(val);
|
|
883
|
-
flush(val);
|
|
884
694
|
};
|
|
885
|
-
return /* @__PURE__ */ jsx(
|
|
886
|
-
|
|
887
|
-
|
|
888
|
-
|
|
889
|
-
|
|
890
|
-
|
|
891
|
-
|
|
892
|
-
|
|
893
|
-
|
|
894
|
-
|
|
895
|
-
|
|
896
|
-
|
|
897
|
-
|
|
898
|
-
|
|
899
|
-
|
|
900
|
-
|
|
901
|
-
|
|
902
|
-
|
|
903
|
-
|
|
904
|
-
|
|
905
|
-
|
|
695
|
+
return /* @__PURE__ */ jsx(FieldWrapper, {
|
|
696
|
+
optional: field.optional ?? false,
|
|
697
|
+
label,
|
|
698
|
+
tooltipComponent,
|
|
699
|
+
labelPosition,
|
|
700
|
+
spaceCompact: spaceCompact ?? false,
|
|
701
|
+
...field.description !== void 0 && { description: field.description },
|
|
702
|
+
children: ({ id, describedBy }) => /* @__PURE__ */ jsxs(Fragment$1, { children: [
|
|
703
|
+
!isSentinel && /* @__PURE__ */ jsx("input", {
|
|
704
|
+
"data-1p-ignore": true,
|
|
705
|
+
className: cx("w-full", disabled && "disabled", (missing || error !== null) && "invalid"),
|
|
706
|
+
id,
|
|
707
|
+
"aria-describedby": describedBy,
|
|
708
|
+
name,
|
|
709
|
+
value: text,
|
|
710
|
+
type: "text",
|
|
711
|
+
"aria-required": field.optional ? void 0 : true,
|
|
712
|
+
disabled,
|
|
713
|
+
placeholder: field.placeholder ?? "DD-HH:MM:SS",
|
|
714
|
+
onChange: handleChange,
|
|
715
|
+
onFocus: handleFocus,
|
|
716
|
+
onBlur: handleBlur
|
|
717
|
+
}),
|
|
718
|
+
error && /* @__PURE__ */ jsx("div", {
|
|
719
|
+
className: "text-xs text-red-500 mt-1",
|
|
720
|
+
children: error
|
|
721
|
+
}),
|
|
722
|
+
hasDisableCheckbox && /* @__PURE__ */ jsxs("label", {
|
|
723
|
+
className: cx("flex items-center gap-2 mt-1", disabled ? "cursor-not-allowed opacity-60" : "cursor-pointer"),
|
|
724
|
+
children: [/* @__PURE__ */ jsx("input", {
|
|
725
|
+
type: "checkbox",
|
|
726
|
+
checked: isSentinel,
|
|
727
|
+
disabled,
|
|
728
|
+
onChange: (e) => handleDisableToggle(e.target.checked),
|
|
729
|
+
className: cx("h-4 w-4 accent-(--theme-link)", disabled ? "cursor-not-allowed" : "cursor-pointer")
|
|
730
|
+
}), /* @__PURE__ */ jsx("span", {
|
|
731
|
+
className: "theme-text",
|
|
732
|
+
children: field.disableLabel
|
|
733
|
+
})]
|
|
734
|
+
})
|
|
735
|
+
] })
|
|
906
736
|
});
|
|
907
|
-
}
|
|
737
|
+
});
|
|
908
738
|
//#endregion
|
|
909
|
-
//#region src/form/
|
|
910
|
-
|
|
911
|
-
|
|
912
|
-
|
|
913
|
-
|
|
914
|
-
|
|
739
|
+
//#region src/form/Fields/LabelField.tsx
|
|
740
|
+
function LabelField(props) {
|
|
741
|
+
const { field, label } = props;
|
|
742
|
+
return /* @__PURE__ */ jsx("div", {
|
|
743
|
+
className: "flex items-center w-full",
|
|
744
|
+
children: /* @__PURE__ */ jsx("h3", {
|
|
745
|
+
style: field.size ? {
|
|
746
|
+
fontSize: field.size.toString() + "px",
|
|
747
|
+
whiteSpace: "pre-wrap"
|
|
748
|
+
} : { whiteSpace: "pre-wrap" },
|
|
749
|
+
className: cx("relative", "text-md", field.bold !== false ? "font-bold" : ""),
|
|
750
|
+
children: field.text && field.text.toString().replace(/(\r)/g, "").replace(/(\\n)/g, "\n") || label
|
|
751
|
+
})
|
|
752
|
+
});
|
|
915
753
|
}
|
|
916
754
|
//#endregion
|
|
917
|
-
//#region src/form/Fields/
|
|
918
|
-
|
|
919
|
-
|
|
920
|
-
|
|
755
|
+
//#region src/form/Fields/MultiDropdownField.tsx
|
|
756
|
+
function MultiDropdownField({ field, label, tooltipComponent, labelPosition, spaceCompact, disabled, missing, setFormDirty, onChange }) {
|
|
757
|
+
let parentValue = field.parentValue;
|
|
758
|
+
let options = field.options;
|
|
759
|
+
if (field.depends_on) {
|
|
760
|
+
parentValue = field.depends_on;
|
|
761
|
+
if (!Array.isArray(field.options)) options = field.options[parentValue] || [];
|
|
762
|
+
}
|
|
921
763
|
return /* @__PURE__ */ jsx(FieldWrapper, {
|
|
922
764
|
optional: field.optional,
|
|
923
765
|
label,
|
|
924
766
|
tooltipComponent,
|
|
925
|
-
description: field.description,
|
|
926
767
|
labelPosition,
|
|
927
768
|
spaceCompact,
|
|
928
|
-
children: /* @__PURE__ */ jsx(
|
|
929
|
-
|
|
769
|
+
children: ({ id }) => disabled ? /* @__PURE__ */ jsx(Field, {
|
|
770
|
+
className: "theme-input h-7 w-full rounded border placeholder:text-xs",
|
|
771
|
+
id,
|
|
772
|
+
type: "search",
|
|
930
773
|
name: field.name,
|
|
931
|
-
|
|
932
|
-
|
|
933
|
-
|
|
934
|
-
|
|
935
|
-
step: field.step,
|
|
936
|
-
min: field.min,
|
|
937
|
-
max: field.max,
|
|
938
|
-
minLength: field.minLength,
|
|
939
|
-
maxLength: field.maxLength,
|
|
940
|
-
sanitize: field.sanitize,
|
|
941
|
-
defaultValue: field.default,
|
|
942
|
-
value,
|
|
943
|
-
...onChange && { onChange }
|
|
944
|
-
}, field.name)
|
|
945
|
-
});
|
|
946
|
-
});
|
|
947
|
-
//#endregion
|
|
948
|
-
//#region src/form/Fields/NumberField.tsx
|
|
949
|
-
function NumberField(props) {
|
|
950
|
-
const { field, label, labelPosition, missing, disabled, onChange, tooltipComponent, spaceCompact } = props;
|
|
951
|
-
const [fieldState] = useField(field.name);
|
|
952
|
-
const { setFieldValue } = useFormikContext();
|
|
953
|
-
useEffect(() => {
|
|
954
|
-
if (field.prefillDefault && field.default !== void 0 && (fieldState.value === void 0 || fieldState.value === null || fieldState.value === "")) setFieldValue(field.name, field.default);
|
|
955
|
-
}, [
|
|
956
|
-
field.prefillDefault,
|
|
957
|
-
field.default,
|
|
958
|
-
field.name,
|
|
959
|
-
fieldState.value,
|
|
960
|
-
setFieldValue
|
|
961
|
-
]);
|
|
962
|
-
return /* @__PURE__ */ jsx(FieldWrapper, {
|
|
963
|
-
optional: field.optional,
|
|
964
|
-
label,
|
|
965
|
-
tooltipComponent,
|
|
966
|
-
labelPosition,
|
|
967
|
-
spaceCompact,
|
|
968
|
-
children: field.thousandsSeparator ? /* @__PURE__ */ jsx(FormikNumericInput, {
|
|
969
|
-
invalid: missing,
|
|
970
|
-
name: field.name,
|
|
971
|
-
placeholder: getPlaceholder(field.placeholder, field.default),
|
|
972
|
-
disabled,
|
|
973
|
-
min: field.min,
|
|
974
|
-
max: field.max,
|
|
975
|
-
...onChange && { onChange }
|
|
976
|
-
}, field.name) : /* @__PURE__ */ jsx(FormikCustomInput, {
|
|
977
|
-
invalid: missing,
|
|
774
|
+
disabled: true,
|
|
775
|
+
onChange
|
|
776
|
+
}, field.name) : /* @__PURE__ */ jsx(MultiSelectionDropdown, {
|
|
777
|
+
className: "themee-input h-7 w-full rounded border flex items-center px-3 py-2",
|
|
978
778
|
name: field.name,
|
|
979
|
-
|
|
980
|
-
|
|
981
|
-
|
|
982
|
-
|
|
983
|
-
|
|
984
|
-
|
|
985
|
-
|
|
986
|
-
...onChange && { onChange }
|
|
779
|
+
label: field.label || label,
|
|
780
|
+
options: Array.isArray(options) ? options : [],
|
|
781
|
+
setFormDirty,
|
|
782
|
+
parentValue,
|
|
783
|
+
onChange,
|
|
784
|
+
secondaryField: typeof field.secondaryField === "string" ? field.secondaryField : void 0,
|
|
785
|
+
invalid: missing
|
|
987
786
|
}, field.name)
|
|
988
787
|
});
|
|
989
788
|
}
|
|
990
789
|
//#endregion
|
|
991
|
-
//#region src/form/Fields/
|
|
992
|
-
function
|
|
790
|
+
//#region src/form/Fields/ObjectField.tsx
|
|
791
|
+
function ObjectField({ field, label, tooltipComponent, missingFields, setFormDirty, workflowForm, labelPosition, spaceCompact }) {
|
|
792
|
+
const [open, setOpen] = useState(field.collapsed !== void 0 ? !field.collapsed : true);
|
|
793
|
+
const { values, setFieldValue, setFieldTouched } = useFormikContext();
|
|
794
|
+
const meta = resolveMetaOverrides(field.options, labelPosition, spaceCompact ?? false);
|
|
795
|
+
const HeaderElement = field.noCollapse ? React.Fragment : ControlledCollapsiblePanel;
|
|
796
|
+
return /* @__PURE__ */ jsxs("div", {
|
|
797
|
+
className: "flex flex-col w-full",
|
|
798
|
+
children: [field.noCollapse && /* @__PURE__ */ jsx("div", {
|
|
799
|
+
className: "flex items-center w-full mb-[15px]",
|
|
800
|
+
children: /* @__PURE__ */ jsxs("h3", {
|
|
801
|
+
className: "flex items-center gap-1 text-md font-bold",
|
|
802
|
+
children: [
|
|
803
|
+
label,
|
|
804
|
+
" ",
|
|
805
|
+
tooltipComponent
|
|
806
|
+
]
|
|
807
|
+
})
|
|
808
|
+
}), /* @__PURE__ */ jsx(HeaderElement, {
|
|
809
|
+
open,
|
|
810
|
+
setOpen,
|
|
811
|
+
title: /* @__PURE__ */ jsx(GroupHeader, {
|
|
812
|
+
open,
|
|
813
|
+
setOpen,
|
|
814
|
+
title: field.label || label
|
|
815
|
+
}),
|
|
816
|
+
children: /* @__PURE__ */ jsx("div", {
|
|
817
|
+
className: "w-full",
|
|
818
|
+
children: /* @__PURE__ */ jsx(FieldsFromOptions, {
|
|
819
|
+
options: field.options,
|
|
820
|
+
values,
|
|
821
|
+
setFormDirty,
|
|
822
|
+
setFieldValue,
|
|
823
|
+
setFieldTouched,
|
|
824
|
+
missingFields,
|
|
825
|
+
workflowForm,
|
|
826
|
+
labelPosition: meta.labelPosition,
|
|
827
|
+
spaceCompact: meta.spaceCompact,
|
|
828
|
+
parentInfo: {
|
|
829
|
+
parentName: field.name,
|
|
830
|
+
fieldNamePrefix: `${field.name}.`
|
|
831
|
+
}
|
|
832
|
+
})
|
|
833
|
+
})
|
|
834
|
+
})]
|
|
835
|
+
});
|
|
836
|
+
}
|
|
837
|
+
//#endregion
|
|
838
|
+
//#region src/form/Fields/RadioField.tsx
|
|
839
|
+
function RadioField(props) {
|
|
993
840
|
const { field, label, labelPosition, missing, disabled, onChange, tooltipComponent, spaceCompact, setFormDirty } = props;
|
|
994
|
-
const
|
|
841
|
+
const uid = useId();
|
|
995
842
|
const { setFieldValue, setFieldTouched } = useFormikContext();
|
|
996
843
|
const handleChange = (val) => {
|
|
997
844
|
if (disabled) return;
|
|
@@ -1000,106 +847,34 @@ function BooleanField(props) {
|
|
|
1000
847
|
setFieldValue(field.name, val);
|
|
1001
848
|
setFormDirty(true);
|
|
1002
849
|
};
|
|
1003
|
-
const value = fieldState.value;
|
|
1004
|
-
const options = field.options ? {
|
|
1005
|
-
onOption: String(field.options.onOption ?? true),
|
|
1006
|
-
offOption: String(field.options.offOption ?? false)
|
|
1007
|
-
} : void 0;
|
|
1008
|
-
const displayLabel = (option) => option.charAt(0).toUpperCase() + option.slice(1).toLowerCase();
|
|
1009
|
-
return /* @__PURE__ */ jsx(FieldWrapper, {
|
|
1010
|
-
optional: true,
|
|
1011
|
-
label,
|
|
1012
|
-
tooltipComponent: /* @__PURE__ */ jsx("div", { children: tooltipComponent }),
|
|
1013
|
-
description: field.description,
|
|
1014
|
-
labelPosition,
|
|
1015
|
-
spaceCompact,
|
|
1016
|
-
children: ({ id, describedBy }) => options ? /* @__PURE__ */ jsx(SwitchToggle, {
|
|
1017
|
-
id,
|
|
1018
|
-
"aria-describedby": describedBy,
|
|
1019
|
-
onChange: (on) => handleChange(on ? options.onOption : options.offOption),
|
|
1020
|
-
value: value === true || value === options.onOption,
|
|
1021
|
-
yesLabel: displayLabel(options.onOption),
|
|
1022
|
-
noLabel: displayLabel(options.offOption),
|
|
1023
|
-
disabled,
|
|
1024
|
-
invalid: missing
|
|
1025
|
-
}) : /* @__PURE__ */ jsx(SwitchToggle, {
|
|
1026
|
-
id,
|
|
1027
|
-
"aria-describedby": describedBy,
|
|
1028
|
-
datatip: field.disabled_message,
|
|
1029
|
-
onChange: handleChange,
|
|
1030
|
-
value: value === true || value === "true",
|
|
1031
|
-
disabled,
|
|
1032
|
-
invalid: missing
|
|
1033
|
-
})
|
|
1034
|
-
});
|
|
1035
|
-
}
|
|
1036
|
-
//#endregion
|
|
1037
|
-
//#region src/form/Fields/DropdownField.tsx
|
|
1038
|
-
function DropdownField(props) {
|
|
1039
|
-
const { field, label, labelPosition, missing, disabled, onChange, tooltipComponent, spaceCompact, setFieldValue, setFieldTouched, currentValue } = props;
|
|
1040
|
-
let parentValue = field.parentValue;
|
|
1041
|
-
let options = Array.isArray(field.options) && field.options || [];
|
|
1042
|
-
if (field.depends_on) {
|
|
1043
|
-
parentValue = field.depends_on;
|
|
1044
|
-
if (!Array.isArray(field.options)) options = field.options[parentValue] ?? [];
|
|
1045
|
-
}
|
|
1046
|
-
const secondaryField = Array.isArray(field.secondaryField) ? field.secondaryField[0] : field.secondaryField;
|
|
1047
|
-
return /* @__PURE__ */ jsx(FieldWrapper, {
|
|
1048
|
-
optional: field.optional,
|
|
1049
|
-
label,
|
|
1050
|
-
tooltipComponent,
|
|
1051
|
-
description: field.description,
|
|
1052
|
-
labelPosition,
|
|
1053
|
-
spaceCompact,
|
|
1054
|
-
children: /* @__PURE__ */ jsx("div", {
|
|
1055
|
-
className: "grow min-w-0",
|
|
1056
|
-
children: /* @__PURE__ */ jsx(FormikCustomDropdown_default, {
|
|
1057
|
-
invalid: missing,
|
|
1058
|
-
className: "w-full",
|
|
1059
|
-
name: field.name,
|
|
1060
|
-
ariaLabel: label,
|
|
1061
|
-
options,
|
|
1062
|
-
setFormDirty: props.setFormDirty,
|
|
1063
|
-
parentValue,
|
|
1064
|
-
onChange,
|
|
1065
|
-
secondaryField,
|
|
1066
|
-
disabled,
|
|
1067
|
-
resetOnChange: field.resetOnChange ? field.name : "",
|
|
1068
|
-
loading: false,
|
|
1069
|
-
autoselect: field.autoselect,
|
|
1070
|
-
allowCustomValue: field.allowCustomValue,
|
|
1071
|
-
customValueLabel: field.customValueLabel,
|
|
1072
|
-
placeholder: getPlaceholder(field.placeholder, typeof field.default === "string" ? field.default : void 0),
|
|
1073
|
-
currentValue,
|
|
1074
|
-
setFieldValue,
|
|
1075
|
-
setFieldTouched
|
|
1076
|
-
}, field.name)
|
|
1077
|
-
})
|
|
1078
|
-
});
|
|
1079
|
-
}
|
|
1080
|
-
//#endregion
|
|
1081
|
-
//#region src/form/Fields/TextAreaField.tsx
|
|
1082
|
-
function TextAreaField(props) {
|
|
1083
|
-
const { field, label, labelPosition, missing, disabled, onChange, tooltipComponent, spaceCompact } = props;
|
|
1084
850
|
return /* @__PURE__ */ jsx(FieldWrapper, {
|
|
1085
851
|
optional: field.optional,
|
|
1086
852
|
label,
|
|
1087
853
|
tooltipComponent,
|
|
1088
|
-
description: field.description,
|
|
1089
854
|
labelPosition,
|
|
1090
855
|
spaceCompact,
|
|
1091
|
-
children: ({
|
|
1092
|
-
|
|
1093
|
-
|
|
1094
|
-
id,
|
|
856
|
+
children: ({ labelId, describedBy }) => /* @__PURE__ */ jsx("div", {
|
|
857
|
+
role: "radiogroup",
|
|
858
|
+
"aria-labelledby": labelId,
|
|
1095
859
|
"aria-describedby": describedBy,
|
|
1096
860
|
"aria-required": field.optional ? void 0 : true,
|
|
1097
|
-
|
|
1098
|
-
|
|
1099
|
-
|
|
1100
|
-
|
|
1101
|
-
|
|
1102
|
-
|
|
861
|
+
className: cx("flex", field.optionLabelPosition === "top" ? "flex-col" : "flex-row"),
|
|
862
|
+
children: field.options?.map((option) => /* @__PURE__ */ jsxs("label", {
|
|
863
|
+
htmlFor: `${uid}-${option}`,
|
|
864
|
+
className: "capitalize",
|
|
865
|
+
children: [/* @__PURE__ */ jsx(Field, {
|
|
866
|
+
id: `${uid}-${option}`,
|
|
867
|
+
className: cx("theme-input mr-1", disabled && "disabled", missing && "invalid"),
|
|
868
|
+
name: field.name,
|
|
869
|
+
type: "radio",
|
|
870
|
+
value: option,
|
|
871
|
+
disabled,
|
|
872
|
+
onChange: (e) => {
|
|
873
|
+
handleChange(e.target.value);
|
|
874
|
+
}
|
|
875
|
+
}), option]
|
|
876
|
+
}, field.name + option))
|
|
877
|
+
})
|
|
1103
878
|
});
|
|
1104
879
|
}
|
|
1105
880
|
//#endregion
|
|
@@ -1156,513 +931,719 @@ function RangeField(props) {
|
|
|
1156
931
|
});
|
|
1157
932
|
}
|
|
1158
933
|
//#endregion
|
|
1159
|
-
//#region src/form/
|
|
1160
|
-
|
|
1161
|
-
|
|
1162
|
-
function parseSlurmDuration(text) {
|
|
1163
|
-
const trimmed = text.trim();
|
|
1164
|
-
let days = 0;
|
|
1165
|
-
let hours;
|
|
1166
|
-
let minutes;
|
|
1167
|
-
let seconds;
|
|
1168
|
-
const withDays = trimmed.match(WITH_DAYS);
|
|
1169
|
-
if (withDays) {
|
|
1170
|
-
days = Number(withDays[1]);
|
|
1171
|
-
hours = Number(withDays[2]);
|
|
1172
|
-
minutes = Number(withDays[3] ?? 0);
|
|
1173
|
-
seconds = Number(withDays[4] ?? 0);
|
|
1174
|
-
if (hours > 23) return null;
|
|
1175
|
-
} else {
|
|
1176
|
-
const withoutDays = trimmed.match(WITHOUT_DAYS);
|
|
1177
|
-
if (!withoutDays) return null;
|
|
1178
|
-
hours = Number(withoutDays[1]);
|
|
1179
|
-
minutes = Number(withoutDays[2]);
|
|
1180
|
-
seconds = Number(withoutDays[3]);
|
|
1181
|
-
}
|
|
1182
|
-
if (minutes > 59 || seconds > 59) return null;
|
|
1183
|
-
return days * 86400 + hours * 3600 + minutes * 60 + seconds;
|
|
1184
|
-
}
|
|
1185
|
-
function formatSecondsAsSlurmDuration(totalSeconds) {
|
|
1186
|
-
if (!Number.isFinite(totalSeconds) || totalSeconds < 0) return "";
|
|
1187
|
-
const parts = Duration.fromObject({ seconds: Math.floor(totalSeconds) }).shiftTo("days", "hours", "minutes", "seconds");
|
|
1188
|
-
const pad = (n) => String(n).padStart(2, "0");
|
|
1189
|
-
const time = `${pad(parts.hours)}:${pad(parts.minutes)}:${pad(parts.seconds)}`;
|
|
1190
|
-
return parts.days > 0 ? `${parts.days}-${time}` : time;
|
|
1191
|
-
}
|
|
1192
|
-
var FLEX_MAX_DURATION_RANGE = {
|
|
1193
|
-
min: 600,
|
|
1194
|
-
max: 604800
|
|
1195
|
-
};
|
|
1196
|
-
var FLEX_WAIT_TIME_RANGE = {
|
|
1197
|
-
min: 30,
|
|
1198
|
-
max: 604800
|
|
1199
|
-
};
|
|
1200
|
-
var STANDARD_MAX_DURATION_RANGE = {
|
|
1201
|
-
min: 30,
|
|
1202
|
-
max: 10368e3
|
|
1203
|
-
};
|
|
1204
|
-
var DURATION_PATH = /^partitions\[\d+\]\.(maxDuration|flexStartWaitTime|suspendTime)$/;
|
|
1205
|
-
function collectPartitionDurationIssues(partitions, invalidDurationPaths) {
|
|
1206
|
-
const issues = new Set(invalidDurationPaths.filter((path) => DURATION_PATH.test(path)));
|
|
1207
|
-
(partitions ?? []).forEach((partition, i) => {
|
|
1208
|
-
const p = partition;
|
|
1209
|
-
const check = (fieldName, range, required) => {
|
|
1210
|
-
const raw = p?.[fieldName];
|
|
1211
|
-
if (raw === void 0 || raw === null || raw === "") {
|
|
1212
|
-
if (required) issues.add(`partitions[${i}].${fieldName}`);
|
|
1213
|
-
return;
|
|
1214
|
-
}
|
|
1215
|
-
const value = Number(raw);
|
|
1216
|
-
if (!Number.isFinite(value) || value < range.min || value > range.max) issues.add(`partitions[${i}].${fieldName}`);
|
|
1217
|
-
};
|
|
1218
|
-
if (p?.provisioningMode === "flex") {
|
|
1219
|
-
check("maxDuration", FLEX_MAX_DURATION_RANGE, true);
|
|
1220
|
-
check("flexStartWaitTime", FLEX_WAIT_TIME_RANGE, true);
|
|
1221
|
-
} else check("maxDuration", STANDARD_MAX_DURATION_RANGE, false);
|
|
1222
|
-
});
|
|
1223
|
-
return [...issues];
|
|
1224
|
-
}
|
|
1225
|
-
//#endregion
|
|
1226
|
-
//#region src/form/Fields/durationValidity.ts
|
|
1227
|
-
var invalidPaths = /* @__PURE__ */ new Set();
|
|
1228
|
-
function setDurationValidity(path, valid) {
|
|
1229
|
-
if (valid) invalidPaths.delete(path);
|
|
1230
|
-
else invalidPaths.add(path);
|
|
1231
|
-
}
|
|
1232
|
-
function getInvalidDurationPaths() {
|
|
1233
|
-
return [...invalidPaths];
|
|
934
|
+
//#region src/form/Fields/StepField.tsx
|
|
935
|
+
function StepField(_props) {
|
|
936
|
+
return null;
|
|
1234
937
|
}
|
|
1235
938
|
//#endregion
|
|
1236
|
-
//#region src/form/Fields/
|
|
1237
|
-
var
|
|
1238
|
-
|
|
1239
|
-
|
|
1240
|
-
if (typeof value === "number") return formatSecondsAsSlurmDuration(value);
|
|
1241
|
-
if (isNumericString(value)) return formatSecondsAsSlurmDuration(Number(value));
|
|
1242
|
-
return "";
|
|
1243
|
-
};
|
|
1244
|
-
var DurationField_default = memo(function DurationField({ field, label, labelPosition, missing, disabled, onChange, tooltipComponent, spaceCompact, setFormDirty, currentValue, setFieldValue, setFieldTouched }) {
|
|
1245
|
-
const { form: t } = useStrings();
|
|
1246
|
-
const name = field.name;
|
|
1247
|
-
const min = field.min !== void 0 ? Number(field.min) : Number.NEGATIVE_INFINITY;
|
|
1248
|
-
const max = field.max !== void 0 ? Number(field.max) : Number.POSITIVE_INFINITY;
|
|
1249
|
-
const disableValue = field.disableValue;
|
|
1250
|
-
const hasDisableCheckbox = disableValue !== void 0 && field.disableLabel !== void 0;
|
|
1251
|
-
const isSentinel = hasDisableCheckbox && currentValue !== "" && Number(currentValue) === disableValue;
|
|
1252
|
-
const [text, setText] = useState(() => toDisplay(currentValue));
|
|
1253
|
-
const focusedRef = useRef(false);
|
|
1254
|
-
const debounceRef = useRef(null);
|
|
1255
|
-
useEffect(() => {
|
|
1256
|
-
if (isSentinel) {
|
|
1257
|
-
if (typeof currentValue !== "number") setFieldValue?.(name, disableValue);
|
|
1258
|
-
} else if (isNumericString(currentValue)) setFieldValue?.(name, Number(currentValue));
|
|
1259
|
-
else if ((currentValue === void 0 || currentValue === null || currentValue === "") && typeof field.default === "number") setFieldValue?.(name, field.default);
|
|
1260
|
-
}, []);
|
|
1261
|
-
useEffect(() => {
|
|
1262
|
-
if (!focusedRef.current) setText(toDisplay(currentValue));
|
|
1263
|
-
}, [currentValue]);
|
|
1264
|
-
const trimmed = text.trim();
|
|
1265
|
-
const parsed = trimmed === "" ? null : parseSlurmDuration(trimmed);
|
|
1266
|
-
let error = null;
|
|
1267
|
-
if (!isSentinel && trimmed !== "") {
|
|
1268
|
-
if (parsed === null) error = t.invalidDuration;
|
|
1269
|
-
else if (parsed < min || parsed > max) error = Number.isFinite(max) ? t.durationOutOfRange(formatSecondsAsSlurmDuration(Math.max(min, 0)), formatSecondsAsSlurmDuration(max)) : t.durationBelowMin(formatSecondsAsSlurmDuration(Math.max(min, 0)));
|
|
1270
|
-
}
|
|
1271
|
-
useEffect(() => {
|
|
1272
|
-
setDurationValidity(name, error === null);
|
|
1273
|
-
}, [name, error]);
|
|
1274
|
-
useEffect(() => () => {
|
|
1275
|
-
setDurationValidity(name, true);
|
|
1276
|
-
clearTimeout(debounceRef.current ?? void 0);
|
|
1277
|
-
}, [name]);
|
|
1278
|
-
const flushToFormik = (val) => {
|
|
1279
|
-
setFieldValue?.(name, val);
|
|
1280
|
-
onChange?.(val);
|
|
1281
|
-
setFieldTouched?.(name, true);
|
|
1282
|
-
};
|
|
1283
|
-
const handleDisableToggle = (checked) => {
|
|
1284
|
-
clearTimeout(debounceRef.current ?? void 0);
|
|
1285
|
-
setFormDirty(true);
|
|
1286
|
-
if (checked) {
|
|
1287
|
-
setText("");
|
|
1288
|
-
flushToFormik(disableValue);
|
|
1289
|
-
} else flushToFormik(typeof field.default === "number" ? field.default : "");
|
|
1290
|
-
};
|
|
1291
|
-
const handleChange = (e) => {
|
|
1292
|
-
const raw = e.target.value;
|
|
1293
|
-
setText(raw);
|
|
1294
|
-
setFormDirty(true);
|
|
1295
|
-
clearTimeout(debounceRef.current ?? void 0);
|
|
1296
|
-
const rawTrimmed = raw.trim();
|
|
1297
|
-
const value = rawTrimmed === "" ? "" : parseSlurmDuration(rawTrimmed);
|
|
1298
|
-
if (value === "" || typeof value === "number" && value >= min && value <= max) debounceRef.current = setTimeout(() => flushToFormik(value), DEBOUNCE_MS);
|
|
1299
|
-
};
|
|
1300
|
-
const handleFocus = () => {
|
|
1301
|
-
focusedRef.current = true;
|
|
1302
|
-
};
|
|
1303
|
-
const handleBlur = () => {
|
|
1304
|
-
focusedRef.current = false;
|
|
1305
|
-
clearTimeout(debounceRef.current ?? void 0);
|
|
1306
|
-
if (trimmed === "") {
|
|
1307
|
-
setText("");
|
|
1308
|
-
flushToFormik("");
|
|
1309
|
-
} else if (parsed !== null && parsed >= min && parsed <= max) {
|
|
1310
|
-
setText(formatSecondsAsSlurmDuration(parsed));
|
|
1311
|
-
flushToFormik(parsed);
|
|
1312
|
-
}
|
|
1313
|
-
};
|
|
939
|
+
//#region src/form/Fields/StringField.tsx
|
|
940
|
+
var StringField_default = memo(function StringField(props) {
|
|
941
|
+
const { field, label, labelPosition, missing, disabled, onChange, tooltipComponent, spaceCompact, currentValue } = props;
|
|
942
|
+
const value = field.prefillDefault ? currentValue : void 0;
|
|
1314
943
|
return /* @__PURE__ */ jsx(FieldWrapper, {
|
|
1315
|
-
optional: field.optional
|
|
944
|
+
optional: field.optional,
|
|
1316
945
|
label,
|
|
1317
946
|
tooltipComponent,
|
|
947
|
+
description: field.description,
|
|
1318
948
|
labelPosition,
|
|
1319
|
-
spaceCompact
|
|
1320
|
-
|
|
1321
|
-
|
|
1322
|
-
|
|
1323
|
-
|
|
1324
|
-
|
|
1325
|
-
|
|
1326
|
-
|
|
1327
|
-
|
|
1328
|
-
|
|
1329
|
-
|
|
1330
|
-
|
|
1331
|
-
|
|
1332
|
-
|
|
1333
|
-
|
|
1334
|
-
|
|
1335
|
-
|
|
1336
|
-
|
|
1337
|
-
error && /* @__PURE__ */ jsx("div", {
|
|
1338
|
-
className: "text-xs text-red-500 mt-1",
|
|
1339
|
-
children: error
|
|
1340
|
-
}),
|
|
1341
|
-
hasDisableCheckbox && /* @__PURE__ */ jsxs("label", {
|
|
1342
|
-
className: cx("flex items-center gap-2 mt-1", disabled ? "cursor-not-allowed opacity-60" : "cursor-pointer"),
|
|
1343
|
-
children: [/* @__PURE__ */ jsx("input", {
|
|
1344
|
-
type: "checkbox",
|
|
1345
|
-
checked: isSentinel,
|
|
1346
|
-
disabled,
|
|
1347
|
-
onChange: (e) => handleDisableToggle(e.target.checked),
|
|
1348
|
-
className: cx("h-4 w-4 accent-(--theme-link)", disabled ? "cursor-not-allowed" : "cursor-pointer")
|
|
1349
|
-
}), /* @__PURE__ */ jsx("span", {
|
|
1350
|
-
className: "theme-text",
|
|
1351
|
-
children: field.disableLabel
|
|
1352
|
-
})]
|
|
1353
|
-
})
|
|
1354
|
-
] })
|
|
949
|
+
spaceCompact,
|
|
950
|
+
children: /* @__PURE__ */ jsx(FormikCustomInput, {
|
|
951
|
+
invalid: missing,
|
|
952
|
+
name: field.name,
|
|
953
|
+
type: field.type,
|
|
954
|
+
lowercase: field.lowercase,
|
|
955
|
+
placeholder: field.type === "password" && field.placeholder === void 0 ? "•".repeat((field.default ?? "").toString().length > 0 ? 16 : 0) : getPlaceholder(field.placeholder, field.default),
|
|
956
|
+
disabled,
|
|
957
|
+
step: field.step,
|
|
958
|
+
min: field.min,
|
|
959
|
+
max: field.max,
|
|
960
|
+
minLength: field.minLength,
|
|
961
|
+
maxLength: field.maxLength,
|
|
962
|
+
sanitize: field.sanitize,
|
|
963
|
+
defaultValue: field.default,
|
|
964
|
+
value,
|
|
965
|
+
...onChange && { onChange }
|
|
966
|
+
}, field.name)
|
|
1355
967
|
});
|
|
1356
968
|
});
|
|
1357
969
|
//#endregion
|
|
1358
|
-
//#region src/form/Fields/
|
|
1359
|
-
function
|
|
1360
|
-
const { field, label, labelPosition, missing, disabled, onChange, tooltipComponent, spaceCompact
|
|
1361
|
-
const uid = useId();
|
|
1362
|
-
const { setFieldValue, setFieldTouched } = useFormikContext();
|
|
1363
|
-
const handleChange = (val) => {
|
|
1364
|
-
if (disabled) return;
|
|
1365
|
-
if (onChange) onChange(val);
|
|
1366
|
-
setFieldTouched(field.name, true);
|
|
1367
|
-
setFieldValue(field.name, val);
|
|
1368
|
-
setFormDirty(true);
|
|
1369
|
-
};
|
|
970
|
+
//#region src/form/Fields/TextAreaField.tsx
|
|
971
|
+
function TextAreaField(props) {
|
|
972
|
+
const { field, label, labelPosition, missing, disabled, onChange, tooltipComponent, spaceCompact } = props;
|
|
1370
973
|
return /* @__PURE__ */ jsx(FieldWrapper, {
|
|
1371
974
|
optional: field.optional,
|
|
1372
975
|
label,
|
|
1373
976
|
tooltipComponent,
|
|
977
|
+
description: field.description,
|
|
1374
978
|
labelPosition,
|
|
1375
979
|
spaceCompact,
|
|
1376
|
-
children: ({
|
|
1377
|
-
|
|
1378
|
-
"
|
|
980
|
+
children: ({ id, describedBy }) => /* @__PURE__ */ jsx(Field, {
|
|
981
|
+
className: cx("theme-input h-[82px] w-full rounded leading-4 overflow-y-scroll", disabled && "disabled", missing && "border-red-600 focus:border-red-600 focus:ring-red-500"),
|
|
982
|
+
as: "textarea",
|
|
983
|
+
id,
|
|
1379
984
|
"aria-describedby": describedBy,
|
|
1380
985
|
"aria-required": field.optional ? void 0 : true,
|
|
1381
|
-
|
|
1382
|
-
|
|
1383
|
-
|
|
1384
|
-
|
|
1385
|
-
|
|
1386
|
-
|
|
1387
|
-
className: cx("theme-input mr-1", disabled && "disabled", missing && "invalid"),
|
|
1388
|
-
name: field.name,
|
|
1389
|
-
type: "radio",
|
|
1390
|
-
value: option,
|
|
1391
|
-
disabled,
|
|
1392
|
-
onChange: (e) => {
|
|
1393
|
-
handleChange(e.target.value);
|
|
1394
|
-
}
|
|
1395
|
-
}), option]
|
|
1396
|
-
}, field.name + option))
|
|
1397
|
-
})
|
|
986
|
+
name: field.name,
|
|
987
|
+
type: "search",
|
|
988
|
+
placeholder: getPlaceholder(field.placeholder, field.default),
|
|
989
|
+
disabled,
|
|
990
|
+
...onChange && { onChange }
|
|
991
|
+
}, field.name)
|
|
1398
992
|
});
|
|
1399
993
|
}
|
|
1400
994
|
//#endregion
|
|
1401
|
-
//#region src/form/
|
|
1402
|
-
|
|
1403
|
-
|
|
1404
|
-
|
|
1405
|
-
|
|
1406
|
-
|
|
1407
|
-
|
|
1408
|
-
|
|
1409
|
-
|
|
1410
|
-
|
|
1411
|
-
|
|
1412
|
-
|
|
1413
|
-
|
|
995
|
+
//#region src/form/fieldRegistry.tsx
|
|
996
|
+
var CORE_FIELD_COMPONENTS = {
|
|
997
|
+
string: StringField_default,
|
|
998
|
+
password: StringField_default,
|
|
999
|
+
number: NumberField,
|
|
1000
|
+
boolean: BooleanField,
|
|
1001
|
+
dropdown: DropdownField,
|
|
1002
|
+
textarea: TextAreaField,
|
|
1003
|
+
range: RangeField,
|
|
1004
|
+
duration: DurationField_default,
|
|
1005
|
+
radio: RadioField,
|
|
1006
|
+
label: LabelField,
|
|
1007
|
+
color: ColorField,
|
|
1008
|
+
"multi-dropdown": MultiDropdownField,
|
|
1009
|
+
"checkbox-group": CheckboxGroupField,
|
|
1010
|
+
object: ObjectField,
|
|
1011
|
+
step: StepField
|
|
1012
|
+
};
|
|
1013
|
+
var FieldRegistryContext = createContext({});
|
|
1014
|
+
/** Returns null for field types no registry knows. Per-form `fields` win over
|
|
1015
|
+
* the provider's `slots.formFields`, which win over the core registry. */
|
|
1016
|
+
function Registry(props) {
|
|
1017
|
+
const injected = useContext(FieldRegistryContext);
|
|
1018
|
+
const { formFields } = useSlots();
|
|
1019
|
+
const Component = injected[props.field.type] ?? formFields?.[props.field.type] ?? CORE_FIELD_COMPONENTS[props.field.type];
|
|
1020
|
+
if (!Component) return null;
|
|
1021
|
+
return /* @__PURE__ */ jsx(Suspense, {
|
|
1022
|
+
fallback: null,
|
|
1023
|
+
children: /* @__PURE__ */ jsx(Component, { ...props })
|
|
1414
1024
|
});
|
|
1415
1025
|
}
|
|
1416
1026
|
//#endregion
|
|
1417
|
-
//#region src/form/
|
|
1418
|
-
|
|
1419
|
-
|
|
1420
|
-
|
|
1421
|
-
|
|
1422
|
-
|
|
1423
|
-
|
|
1424
|
-
|
|
1425
|
-
|
|
1426
|
-
|
|
1427
|
-
|
|
1428
|
-
|
|
1429
|
-
|
|
1430
|
-
|
|
1431
|
-
|
|
1432
|
-
|
|
1433
|
-
|
|
1434
|
-
|
|
1435
|
-
|
|
1436
|
-
|
|
1437
|
-
|
|
1438
|
-
|
|
1439
|
-
|
|
1440
|
-
|
|
1441
|
-
|
|
1442
|
-
|
|
1027
|
+
//#region src/form/useParsedOpts.ts
|
|
1028
|
+
var EMPTY_VARS = {};
|
|
1029
|
+
var EMPTY_KEYS = [];
|
|
1030
|
+
/**
|
|
1031
|
+
* useMemo won't work here — Formik values changes on every keystroke, so this hook extracts which inputs.* keys the schema references and re-parses only when those change. Defaults `userVars`/`secretKeys` to empty — callers in React scope should pass them from `useUserVars()` so the parser leaves `${{ var.SECRET }}` literal during template eval (otherwise the recursive substitution turns `"https://${{ var.PAT }}@host/"` into `"https://@host/"`).
|
|
1032
|
+
*/
|
|
1033
|
+
function useParsedOpts(rawOptions, values, organizationVariables, userVars = EMPTY_VARS, secretKeys = EMPTY_KEYS, remoteVars = EMPTY_VARS) {
|
|
1034
|
+
const engine = useWorkflowEngine();
|
|
1035
|
+
const c = useRef({
|
|
1036
|
+
rawOptions: null,
|
|
1037
|
+
orgVars: void 0,
|
|
1038
|
+
userVars: null,
|
|
1039
|
+
secretKeys: null,
|
|
1040
|
+
remoteVars: null,
|
|
1041
|
+
converted: {},
|
|
1042
|
+
inputDeps: /* @__PURE__ */ new Set(),
|
|
1043
|
+
hasExpressions: false,
|
|
1044
|
+
relevantSnapshot: {},
|
|
1045
|
+
result: null
|
|
1046
|
+
}).current;
|
|
1047
|
+
if (rawOptions !== c.rawOptions) {
|
|
1048
|
+
c.rawOptions = rawOptions;
|
|
1049
|
+
c.converted = engine.convertInputs(rawOptions);
|
|
1050
|
+
const { inputDeps, hasExpressions } = engine.inputDependencies(c.converted);
|
|
1051
|
+
c.inputDeps = inputDeps;
|
|
1052
|
+
c.hasExpressions = hasExpressions;
|
|
1053
|
+
c.result = null;
|
|
1054
|
+
}
|
|
1055
|
+
if (organizationVariables !== c.orgVars || userVars !== c.userVars || secretKeys !== c.secretKeys || remoteVars !== c.remoteVars) {
|
|
1056
|
+
c.orgVars = organizationVariables;
|
|
1057
|
+
c.userVars = userVars;
|
|
1058
|
+
c.secretKeys = secretKeys;
|
|
1059
|
+
c.remoteVars = remoteVars;
|
|
1060
|
+
c.result = null;
|
|
1061
|
+
}
|
|
1062
|
+
if (c.result !== null) {
|
|
1063
|
+
if (c.inputDeps.size === 0) return c.result;
|
|
1064
|
+
let inputsChanged = false;
|
|
1065
|
+
for (const key of c.inputDeps) if (!deepEqual(values[key], c.relevantSnapshot[key])) {
|
|
1066
|
+
inputsChanged = true;
|
|
1067
|
+
break;
|
|
1068
|
+
}
|
|
1069
|
+
if (!inputsChanged) return c.result;
|
|
1070
|
+
}
|
|
1071
|
+
const parsed = engine.evaluate({
|
|
1072
|
+
inputs: values,
|
|
1073
|
+
obj: c.converted,
|
|
1074
|
+
orgVars: organizationVariables,
|
|
1075
|
+
userVars,
|
|
1076
|
+
secretKeys,
|
|
1077
|
+
remoteVars
|
|
1443
1078
|
});
|
|
1079
|
+
c.result = parsed;
|
|
1080
|
+
c.relevantSnapshot = {};
|
|
1081
|
+
for (const key of c.inputDeps) c.relevantSnapshot[key] = values[key];
|
|
1082
|
+
return parsed;
|
|
1444
1083
|
}
|
|
1445
1084
|
//#endregion
|
|
1446
|
-
//#region src/form/
|
|
1447
|
-
function
|
|
1448
|
-
|
|
1449
|
-
|
|
1450
|
-
|
|
1451
|
-
parentValue = field.depends_on;
|
|
1452
|
-
if (!Array.isArray(field.options)) options = field.options[parentValue] || [];
|
|
1453
|
-
}
|
|
1454
|
-
return /* @__PURE__ */ jsx(FieldWrapper, {
|
|
1455
|
-
optional: field.optional,
|
|
1456
|
-
label,
|
|
1457
|
-
tooltipComponent,
|
|
1458
|
-
labelPosition,
|
|
1459
|
-
spaceCompact,
|
|
1460
|
-
children: ({ id }) => disabled ? /* @__PURE__ */ jsx(Field, {
|
|
1461
|
-
className: "theme-input h-7 w-full rounded border placeholder:text-xs",
|
|
1462
|
-
id,
|
|
1463
|
-
type: "search",
|
|
1464
|
-
name: field.name,
|
|
1465
|
-
disabled: true,
|
|
1466
|
-
onChange
|
|
1467
|
-
}, field.name) : /* @__PURE__ */ jsx(MultiSelectionDropdown, {
|
|
1468
|
-
className: "themee-input h-7 w-full rounded border flex items-center px-3 py-2",
|
|
1469
|
-
name: field.name,
|
|
1470
|
-
label: field.label || label,
|
|
1471
|
-
options: Array.isArray(options) ? options : [],
|
|
1472
|
-
setFormDirty,
|
|
1473
|
-
parentValue,
|
|
1474
|
-
onChange,
|
|
1475
|
-
secondaryField: typeof field.secondaryField === "string" ? field.secondaryField : void 0,
|
|
1476
|
-
invalid: missing
|
|
1477
|
-
}, field.name)
|
|
1085
|
+
//#region src/form/usePrevious.ts
|
|
1086
|
+
function usePrevious(value) {
|
|
1087
|
+
const ref = useRef(void 0);
|
|
1088
|
+
useEffect(() => {
|
|
1089
|
+
ref.current = value;
|
|
1478
1090
|
});
|
|
1091
|
+
return ref.current;
|
|
1479
1092
|
}
|
|
1480
1093
|
//#endregion
|
|
1481
|
-
//#region src/form/
|
|
1482
|
-
function
|
|
1483
|
-
|
|
1484
|
-
|
|
1485
|
-
|
|
1094
|
+
//#region src/form/utils/getValueUsingPath.ts
|
|
1095
|
+
function getValueUsingPath(obj, path) {
|
|
1096
|
+
if (typeof path !== "string" || !path) return;
|
|
1097
|
+
const keys = path.split(".");
|
|
1098
|
+
let current = obj;
|
|
1099
|
+
for (const key of keys) {
|
|
1100
|
+
if (!current || typeof current !== "object") return;
|
|
1101
|
+
const container = current;
|
|
1102
|
+
if (key.includes("[")) {
|
|
1103
|
+
const [arrayKey = "", indexStr = ""] = key.split("[");
|
|
1104
|
+
const index = parseInt(indexStr.slice(0, -1), 10);
|
|
1105
|
+
const list = container[arrayKey];
|
|
1106
|
+
if (!Array.isArray(list) || isNaN(index)) return;
|
|
1107
|
+
current = list[index];
|
|
1108
|
+
} else {
|
|
1109
|
+
if (!(key in container)) return;
|
|
1110
|
+
current = container[key];
|
|
1111
|
+
}
|
|
1112
|
+
}
|
|
1113
|
+
return current;
|
|
1486
1114
|
}
|
|
1487
|
-
|
|
1488
|
-
|
|
1115
|
+
//#endregion
|
|
1116
|
+
//#region src/form/utils/checkShowIfObject.ts
|
|
1117
|
+
function checkShowIfObject(showIfObject, formValues, index) {
|
|
1118
|
+
const valueList = [];
|
|
1119
|
+
for (let [key, value] of Object.entries(showIfObject)) {
|
|
1120
|
+
if (index !== void 0) key = key.replace("[index]", `[${index}]`);
|
|
1121
|
+
const dependsOnValue = getValueUsingPath(formValues, key);
|
|
1122
|
+
if (typeof value === "boolean" || typeof value === "string" || typeof value === "number") valueList.push(dependsOnValue !== null && dependsOnValue !== void 0 && dependsOnValue.toString() === value.toString());
|
|
1123
|
+
else if (Array.isArray(value)) valueList.push(value.includes(dependsOnValue));
|
|
1124
|
+
}
|
|
1125
|
+
return valueList;
|
|
1489
1126
|
}
|
|
1490
|
-
|
|
1491
|
-
|
|
1492
|
-
|
|
1493
|
-
|
|
1494
|
-
|
|
1495
|
-
|
|
1496
|
-
|
|
1497
|
-
|
|
1127
|
+
//#endregion
|
|
1128
|
+
//#region src/form/utils/getParentValue.ts
|
|
1129
|
+
function getParentValue(index, targetField, values, dependentPath, field) {
|
|
1130
|
+
let parentValue;
|
|
1131
|
+
if (typeof targetField === "object" && targetField !== null && !Array.isArray(targetField)) parentValue = !checkShowIfObject(targetField, values, index).includes(false);
|
|
1132
|
+
else if (field.depends_on) {
|
|
1133
|
+
dependentPath = field.depends_on;
|
|
1134
|
+
if (index !== void 0) dependentPath = field.depends_on.replace("[index]", `[${index}]`);
|
|
1135
|
+
const dependsOnValue = getValueUsingPath(values, dependentPath);
|
|
1136
|
+
const dependsOnText = dependsOnValue === null || dependsOnValue === void 0 ? void 0 : String(dependsOnValue);
|
|
1137
|
+
if (Array.isArray(targetField)) parentValue = targetField.includes(dependsOnValue) || targetField.includes(dependsOnText);
|
|
1138
|
+
else if (typeof targetField === "string") parentValue = dependsOnText !== void 0 && targetField.includes(dependsOnText);
|
|
1139
|
+
else parentValue = targetField === dependsOnValue;
|
|
1140
|
+
} else {
|
|
1141
|
+
dependentPath = typeof targetField === "string" ? targetField : "";
|
|
1142
|
+
if (index !== void 0 && typeof targetField === "string") dependentPath = targetField.replace("[index]", `[${index}]`);
|
|
1143
|
+
parentValue = getValueUsingPath(values, dependentPath);
|
|
1144
|
+
}
|
|
1145
|
+
return parentValue;
|
|
1146
|
+
}
|
|
1147
|
+
//#endregion
|
|
1148
|
+
//#region src/form/Wizard/utils.ts
|
|
1149
|
+
function isWizardMeta(value) {
|
|
1150
|
+
return typeof value === "object" && value !== null && "wizard" in value;
|
|
1151
|
+
}
|
|
1152
|
+
function isStepField(field) {
|
|
1153
|
+
return typeof field === "object" && field !== null && "type" in field && field.type === "step";
|
|
1154
|
+
}
|
|
1155
|
+
function parseWizardConfig(options) {
|
|
1156
|
+
const meta = options["$meta"];
|
|
1157
|
+
const wizardConfig = isWizardMeta(meta) ? meta.wizard : void 0;
|
|
1158
|
+
if (!wizardConfig || wizardConfig.mode !== "wizard") return null;
|
|
1159
|
+
const steps = {};
|
|
1160
|
+
const stepOrder = [];
|
|
1161
|
+
const otherFields = {};
|
|
1162
|
+
Object.entries(options).forEach(([key, field]) => {
|
|
1163
|
+
if (key === "$meta") return;
|
|
1164
|
+
if (isStepField(field)) {
|
|
1165
|
+
steps[key] = field;
|
|
1166
|
+
stepOrder.push(key);
|
|
1167
|
+
} else otherFields[key] = field;
|
|
1498
1168
|
});
|
|
1499
|
-
|
|
1500
|
-
|
|
1501
|
-
|
|
1502
|
-
|
|
1503
|
-
|
|
1504
|
-
|
|
1505
|
-
|
|
1506
|
-
|
|
1507
|
-
|
|
1508
|
-
setFormDirty(true);
|
|
1169
|
+
if (stepOrder.length === 0) {
|
|
1170
|
+
console.warn("Wizard mode enabled but no steps found");
|
|
1171
|
+
return null;
|
|
1172
|
+
}
|
|
1173
|
+
return {
|
|
1174
|
+
config: wizardConfig,
|
|
1175
|
+
steps,
|
|
1176
|
+
stepOrder,
|
|
1177
|
+
otherFields
|
|
1509
1178
|
};
|
|
1510
|
-
|
|
1511
|
-
|
|
1512
|
-
|
|
1513
|
-
|
|
1514
|
-
|
|
1515
|
-
|
|
1516
|
-
|
|
1517
|
-
|
|
1518
|
-
|
|
1519
|
-
|
|
1520
|
-
|
|
1521
|
-
|
|
1522
|
-
|
|
1523
|
-
|
|
1524
|
-
|
|
1525
|
-
|
|
1526
|
-
|
|
1527
|
-
|
|
1528
|
-
|
|
1529
|
-
|
|
1530
|
-
|
|
1531
|
-
|
|
1532
|
-
|
|
1533
|
-
|
|
1534
|
-
|
|
1535
|
-
|
|
1536
|
-
|
|
1537
|
-
|
|
1538
|
-
|
|
1539
|
-
|
|
1540
|
-
|
|
1541
|
-
|
|
1542
|
-
|
|
1179
|
+
}
|
|
1180
|
+
//#endregion
|
|
1181
|
+
//#region src/form/Wizard/useWizardState.ts
|
|
1182
|
+
function useWizardState({ stepOrder, steps, validateStep, initialStep }) {
|
|
1183
|
+
const firstStep = initialStep || stepOrder[0] || "";
|
|
1184
|
+
const [currentStep, setCurrentStep] = useState(firstStep);
|
|
1185
|
+
const [visitedSteps, setVisitedSteps] = useState(/* @__PURE__ */ new Set([firstStep]));
|
|
1186
|
+
const [invalidSteps, setInvalidSteps] = useState(/* @__PURE__ */ new Set());
|
|
1187
|
+
const currentStepIndex = stepOrder.indexOf(currentStep);
|
|
1188
|
+
const isLastStep = currentStepIndex === stepOrder.length - 1;
|
|
1189
|
+
const canGoBack = currentStepIndex > 0;
|
|
1190
|
+
/**
|
|
1191
|
+
* Mark step as visited
|
|
1192
|
+
*/
|
|
1193
|
+
const markStepVisited = useCallback((stepKey) => {
|
|
1194
|
+
setVisitedSteps((prev) => /* @__PURE__ */ new Set([...prev, stepKey]));
|
|
1195
|
+
}, []);
|
|
1196
|
+
/**
|
|
1197
|
+
* Mark step as invalid
|
|
1198
|
+
*/
|
|
1199
|
+
const markStepInvalid = useCallback((stepKey, invalid) => {
|
|
1200
|
+
setInvalidSteps((prev) => {
|
|
1201
|
+
const next = new Set(prev);
|
|
1202
|
+
if (invalid) next.add(stepKey);
|
|
1203
|
+
else next.delete(stepKey);
|
|
1204
|
+
return next;
|
|
1205
|
+
});
|
|
1206
|
+
}, []);
|
|
1207
|
+
const goToNext = useCallback(async () => {
|
|
1208
|
+
if (isLastStep) return false;
|
|
1209
|
+
if (steps[currentStep]?.validateOnNext !== false) {
|
|
1210
|
+
if (!await validateStep(currentStep)) {
|
|
1211
|
+
markStepInvalid(currentStep, true);
|
|
1212
|
+
return false;
|
|
1213
|
+
}
|
|
1214
|
+
}
|
|
1215
|
+
markStepInvalid(currentStep, false);
|
|
1216
|
+
const nextStepKey = stepOrder[currentStepIndex + 1];
|
|
1217
|
+
setCurrentStep(nextStepKey ?? "");
|
|
1218
|
+
markStepVisited(nextStepKey ?? "");
|
|
1219
|
+
return true;
|
|
1220
|
+
}, [
|
|
1221
|
+
currentStep,
|
|
1222
|
+
currentStepIndex,
|
|
1223
|
+
isLastStep,
|
|
1224
|
+
steps,
|
|
1225
|
+
stepOrder,
|
|
1226
|
+
validateStep,
|
|
1227
|
+
markStepInvalid,
|
|
1228
|
+
markStepVisited
|
|
1229
|
+
]);
|
|
1230
|
+
const goToPrevious = useCallback(() => {
|
|
1231
|
+
if (!canGoBack) return;
|
|
1232
|
+
const prevStepKey = stepOrder[currentStepIndex - 1];
|
|
1233
|
+
setCurrentStep(prevStepKey ?? "");
|
|
1234
|
+
}, [
|
|
1235
|
+
canGoBack,
|
|
1236
|
+
currentStepIndex,
|
|
1237
|
+
stepOrder
|
|
1238
|
+
]);
|
|
1239
|
+
const jumpToStep = useCallback((stepKey) => {
|
|
1240
|
+
if (!stepOrder.includes(stepKey)) return false;
|
|
1241
|
+
if (!visitedSteps.has(stepKey) && stepKey !== currentStep) return false;
|
|
1242
|
+
setCurrentStep(stepKey);
|
|
1243
|
+
return true;
|
|
1244
|
+
}, [
|
|
1245
|
+
stepOrder,
|
|
1246
|
+
visitedSteps,
|
|
1247
|
+
currentStep
|
|
1248
|
+
]);
|
|
1249
|
+
/**
|
|
1250
|
+
* Reset wizard to initial state
|
|
1251
|
+
*/
|
|
1252
|
+
const reset = useCallback(() => {
|
|
1253
|
+
setCurrentStep(firstStep);
|
|
1254
|
+
setVisitedSteps(/* @__PURE__ */ new Set([firstStep]));
|
|
1255
|
+
setInvalidSteps(/* @__PURE__ */ new Set());
|
|
1256
|
+
}, [firstStep]);
|
|
1257
|
+
/**
|
|
1258
|
+
* Get current wizard state
|
|
1259
|
+
*/
|
|
1260
|
+
const getState = useCallback(() => {
|
|
1261
|
+
return {
|
|
1262
|
+
currentStep,
|
|
1263
|
+
visitedSteps,
|
|
1264
|
+
invalidSteps,
|
|
1265
|
+
stepOrder,
|
|
1266
|
+
totalSteps: stepOrder.length,
|
|
1267
|
+
isLastStep,
|
|
1268
|
+
canProceedToNext: !isLastStep,
|
|
1269
|
+
canGoBack
|
|
1270
|
+
};
|
|
1271
|
+
}, [
|
|
1272
|
+
currentStep,
|
|
1273
|
+
visitedSteps,
|
|
1274
|
+
invalidSteps,
|
|
1275
|
+
stepOrder,
|
|
1276
|
+
isLastStep,
|
|
1277
|
+
canGoBack
|
|
1278
|
+
]);
|
|
1279
|
+
return {
|
|
1280
|
+
currentStep,
|
|
1281
|
+
visitedSteps,
|
|
1282
|
+
invalidSteps,
|
|
1283
|
+
isLastStep,
|
|
1284
|
+
canGoBack,
|
|
1285
|
+
currentStepIndex,
|
|
1286
|
+
totalSteps: stepOrder.length,
|
|
1287
|
+
goToNext,
|
|
1288
|
+
goToPrevious,
|
|
1289
|
+
jumpToStep,
|
|
1290
|
+
reset,
|
|
1291
|
+
markStepVisited,
|
|
1292
|
+
markStepInvalid,
|
|
1293
|
+
getState
|
|
1294
|
+
};
|
|
1295
|
+
}
|
|
1296
|
+
//#endregion
|
|
1297
|
+
//#region src/form/Wizard/WizardNavigation.tsx
|
|
1298
|
+
function WizardNavigation({ currentStep, stepOrder, canGoToNext, canGoBack, isCurrentStepValid, nextLabel, prevLabel, submitLabel = "Submit", onNext, onPrevious, onSubmit }) {
|
|
1299
|
+
const [isLoading, setIsLoading] = useState(false);
|
|
1300
|
+
const [error, setError] = useState(null);
|
|
1301
|
+
const isLastStep = stepOrder.indexOf(currentStep) === stepOrder.length - 1;
|
|
1302
|
+
const handleNext = async () => {
|
|
1303
|
+
setIsLoading(true);
|
|
1304
|
+
setError(null);
|
|
1305
|
+
try {
|
|
1306
|
+
if (!await onNext()) setError("Please fix errors before proceeding");
|
|
1307
|
+
} catch (err) {
|
|
1308
|
+
setError(err instanceof Error ? err.message : "An error occurred");
|
|
1309
|
+
} finally {
|
|
1310
|
+
setIsLoading(false);
|
|
1311
|
+
}
|
|
1312
|
+
};
|
|
1313
|
+
const handleSubmit = async () => {
|
|
1314
|
+
setIsLoading(true);
|
|
1315
|
+
setError(null);
|
|
1316
|
+
try {
|
|
1317
|
+
await onSubmit();
|
|
1318
|
+
} catch (err) {
|
|
1319
|
+
setError(err instanceof Error ? err.message : "An error occurred");
|
|
1320
|
+
} finally {
|
|
1321
|
+
setIsLoading(false);
|
|
1322
|
+
}
|
|
1323
|
+
};
|
|
1324
|
+
return /* @__PURE__ */ jsxs("div", { children: [error && /* @__PURE__ */ jsx("div", {
|
|
1325
|
+
className: "mb-4 p-3 bg-red-50 border border-red-200 rounded text-sm text-red-700",
|
|
1326
|
+
children: error
|
|
1327
|
+
}), /* @__PURE__ */ jsxs("div", {
|
|
1328
|
+
className: "flex gap-3 justify-between pt-4",
|
|
1329
|
+
children: [/* @__PURE__ */ jsx("button", {
|
|
1330
|
+
type: "button",
|
|
1331
|
+
onClick: onPrevious,
|
|
1332
|
+
disabled: !canGoBack || isLoading,
|
|
1333
|
+
className: "px-6 py-3 rounded-lg font-medium transition-all duration-200 border flex items-center gap-2 disabled:opacity-50 disabled:cursor-not-allowed",
|
|
1334
|
+
style: {
|
|
1335
|
+
color: "var(--theme-app)",
|
|
1336
|
+
borderColor: "var(--theme-border)",
|
|
1337
|
+
backgroundColor: "var(--theme-app-bg)"
|
|
1338
|
+
},
|
|
1339
|
+
onMouseEnter: (e) => {
|
|
1340
|
+
if (!(!canGoBack || isLoading)) e.currentTarget.style.backgroundColor = "var(--theme-hover)";
|
|
1341
|
+
},
|
|
1342
|
+
onMouseLeave: (e) => {
|
|
1343
|
+
e.currentTarget.style.backgroundColor = "var(--theme-app-bg)";
|
|
1344
|
+
},
|
|
1345
|
+
"aria-label": "Go to previous step",
|
|
1346
|
+
children: prevLabel || "← Previous"
|
|
1347
|
+
}), isLastStep ? /* @__PURE__ */ jsxs("button", {
|
|
1348
|
+
type: "button",
|
|
1349
|
+
onClick: handleSubmit,
|
|
1350
|
+
disabled: !isCurrentStepValid || isLoading,
|
|
1351
|
+
className: "px-8 py-3 rounded-lg font-medium transition-all duration-200 text-white flex items-center gap-2 disabled:opacity-50 disabled:cursor-not-allowed shadow-md hover:shadow-lg",
|
|
1352
|
+
style: { backgroundColor: "var(--theme-element)" },
|
|
1353
|
+
onMouseEnter: (e) => {
|
|
1354
|
+
if (!(!isCurrentStepValid || isLoading)) e.currentTarget.style.filter = "brightness(0.9)";
|
|
1355
|
+
},
|
|
1356
|
+
onMouseLeave: (e) => {
|
|
1357
|
+
e.currentTarget.style.filter = "brightness(1)";
|
|
1358
|
+
},
|
|
1359
|
+
"aria-label": submitLabel,
|
|
1360
|
+
children: [isLoading && /* @__PURE__ */ jsx(Loader, {
|
|
1361
|
+
size: 16,
|
|
1362
|
+
full: false
|
|
1363
|
+
}), submitLabel]
|
|
1364
|
+
}) : /* @__PURE__ */ jsxs("button", {
|
|
1365
|
+
type: "button",
|
|
1366
|
+
onClick: handleNext,
|
|
1367
|
+
disabled: !canGoToNext || isLoading,
|
|
1368
|
+
className: "px-8 py-3 rounded-lg font-medium transition-all duration-200 text-white flex items-center gap-2 disabled:opacity-50 disabled:cursor-not-allowed shadow-md hover:shadow-lg",
|
|
1369
|
+
style: { backgroundColor: "var(--theme-element)" },
|
|
1370
|
+
onMouseEnter: (e) => {
|
|
1371
|
+
if (!(!canGoToNext || isLoading)) e.currentTarget.style.filter = "brightness(0.9)";
|
|
1372
|
+
},
|
|
1373
|
+
onMouseLeave: (e) => {
|
|
1374
|
+
e.currentTarget.style.filter = "brightness(1)";
|
|
1375
|
+
},
|
|
1376
|
+
"aria-label": "Go to next step",
|
|
1377
|
+
children: [isLoading && /* @__PURE__ */ jsx(Loader, {
|
|
1378
|
+
size: 16,
|
|
1379
|
+
full: false
|
|
1380
|
+
}), nextLabel || "Next →"]
|
|
1381
|
+
})]
|
|
1382
|
+
})] });
|
|
1383
|
+
}
|
|
1384
|
+
//#endregion
|
|
1385
|
+
//#region src/form/Wizard/WizardStepContent.tsx
|
|
1386
|
+
function WizardStepContent({ currentStep, stepConfig, flatten = true, values, onValuesChange, setFormDirty, setFieldValue, setFieldTouched, ...fieldsProps }) {
|
|
1387
|
+
if (!stepConfig?.options) return null;
|
|
1388
|
+
return /* @__PURE__ */ jsxs("div", {
|
|
1389
|
+
className: "mb-4 w-full",
|
|
1390
|
+
children: [
|
|
1391
|
+
stepConfig.title && /* @__PURE__ */ jsx("h2", {
|
|
1392
|
+
className: "text-2xl font-bold mb-2",
|
|
1393
|
+
style: { color: "var(--theme-app)" },
|
|
1394
|
+
children: stepConfig.title
|
|
1395
|
+
}),
|
|
1396
|
+
stepConfig.description && /* @__PURE__ */ jsx("p", {
|
|
1397
|
+
className: "mb-4 leading-relaxed",
|
|
1398
|
+
style: { color: "var(--theme-muted-text-color)" },
|
|
1399
|
+
children: stepConfig.description
|
|
1400
|
+
}),
|
|
1401
|
+
/* @__PURE__ */ jsx(FieldsFromOptions, {
|
|
1402
|
+
options: stepConfig.options,
|
|
1403
|
+
values,
|
|
1404
|
+
setFormDirty,
|
|
1405
|
+
setFieldValue,
|
|
1406
|
+
setFieldTouched,
|
|
1407
|
+
...flatten === false ? { parentInfo: {
|
|
1408
|
+
parentName: currentStep,
|
|
1409
|
+
fieldNamePrefix: `${currentStep}.`
|
|
1410
|
+
} } : {},
|
|
1411
|
+
...fieldsProps
|
|
1412
|
+
}, currentStep)
|
|
1413
|
+
]
|
|
1414
|
+
});
|
|
1415
|
+
}
|
|
1416
|
+
//#endregion
|
|
1417
|
+
//#region src/form/Wizard/WizardStepIndicator.tsx
|
|
1418
|
+
function WizardStepIndicator({ stepOrder, currentStep, steps, visitedSteps, invalidSteps, onStepClick, allowJump = false, hideStepNumbers = false }) {
|
|
1419
|
+
const currentIndex = useMemo(() => stepOrder.indexOf(currentStep), [stepOrder, currentStep]);
|
|
1420
|
+
const getStepStatus = (stepKey, index) => {
|
|
1421
|
+
if (stepKey === currentStep) return "active";
|
|
1422
|
+
if (index < currentIndex) return "completed";
|
|
1423
|
+
return "upcoming";
|
|
1424
|
+
};
|
|
1425
|
+
const handleStepClick = (stepKey) => {
|
|
1426
|
+
if (!allowJump || !visitedSteps.has(stepKey)) return;
|
|
1427
|
+
onStepClick?.(stepKey);
|
|
1428
|
+
};
|
|
1429
|
+
const isClickable = (stepKey) => {
|
|
1430
|
+
return allowJump && visitedSteps.has(stepKey) && stepKey !== currentStep;
|
|
1431
|
+
};
|
|
1432
|
+
return /* @__PURE__ */ jsx("div", {
|
|
1433
|
+
className: "flex items-start justify-between w-full mb-2 gap-4 py-2",
|
|
1434
|
+
children: stepOrder.map((stepKey, index) => {
|
|
1435
|
+
const stepConfig = steps[stepKey];
|
|
1436
|
+
const status = getStepStatus(stepKey, index);
|
|
1437
|
+
const isInvalid = invalidSteps.has(stepKey);
|
|
1438
|
+
const isClickable_ = isClickable(stepKey);
|
|
1439
|
+
const isDotActive = status === "active";
|
|
1440
|
+
const isDotCompleted = status === "completed";
|
|
1441
|
+
const isDotUpcoming = status === "upcoming";
|
|
1442
|
+
return /* @__PURE__ */ jsxs("div", {
|
|
1443
|
+
className: "flex flex-col items-center flex-1 relative",
|
|
1444
|
+
children: [
|
|
1445
|
+
/* @__PURE__ */ jsxs("button", {
|
|
1446
|
+
type: "button",
|
|
1447
|
+
onClick: () => handleStepClick(stepKey),
|
|
1448
|
+
disabled: !isClickable_,
|
|
1449
|
+
className: cx("w-12 h-12 rounded-full border-3 flex items-center justify-center font-bold text-base transition-all duration-300 flex-shrink-0 relative", {
|
|
1450
|
+
"cursor-pointer": isClickable_,
|
|
1451
|
+
"cursor-not-allowed": !isClickable_
|
|
1452
|
+
}, {
|
|
1453
|
+
"text-white": isDotActive,
|
|
1454
|
+
"bg-green-500 border-green-600 text-white shadow-md": isDotCompleted && !isInvalid,
|
|
1455
|
+
"bg-(--theme-border) theme-border theme-muted-text shadow-sm": isDotUpcoming && !isInvalid,
|
|
1456
|
+
"bg-(--theme-muted-panel-bg) theme-border theme-muted-text shadow-sm": !isDotActive && !isDotCompleted && !isDotUpcoming && !isInvalid,
|
|
1457
|
+
"bg-red-50 border-red-500 text-red-600 shadow-sm": isInvalid && status !== "active"
|
|
1458
|
+
}),
|
|
1459
|
+
style: isDotActive ? {
|
|
1460
|
+
backgroundColor: "var(--theme-element)",
|
|
1461
|
+
borderColor: "var(--theme-element)",
|
|
1462
|
+
color: "var(--theme-element-text)",
|
|
1463
|
+
boxShadow: "0 4px 12px rgba(0, 0, 0, 0.15)",
|
|
1464
|
+
zIndex: 10
|
|
1465
|
+
} : { zIndex: 10 },
|
|
1466
|
+
"aria-label": `Step ${index + 1}: ${stepConfig?.title}`,
|
|
1467
|
+
title: stepConfig?.title,
|
|
1468
|
+
children: [!hideStepNumbers && /* @__PURE__ */ jsx("span", {
|
|
1469
|
+
className: cx({ hidden: status === "completed" }),
|
|
1470
|
+
children: index + 1
|
|
1471
|
+
}), status === "completed" && /* @__PURE__ */ jsx("svg", {
|
|
1472
|
+
"aria-hidden": "true",
|
|
1473
|
+
className: "w-4 h-4",
|
|
1474
|
+
fill: "none",
|
|
1475
|
+
stroke: "currentColor",
|
|
1476
|
+
viewBox: "0 0 24 24",
|
|
1477
|
+
children: /* @__PURE__ */ jsx("path", {
|
|
1478
|
+
strokeLinecap: "round",
|
|
1479
|
+
strokeLinejoin: "round",
|
|
1480
|
+
strokeWidth: 3,
|
|
1481
|
+
d: "M5 13l4 4L19 7"
|
|
1482
|
+
})
|
|
1483
|
+
})]
|
|
1484
|
+
}),
|
|
1485
|
+
index < stepOrder.length - 1 && /* @__PURE__ */ jsx("div", {
|
|
1486
|
+
className: cx("absolute h-1 transition-all duration-300", {
|
|
1487
|
+
"bg-green-500": index < currentIndex,
|
|
1488
|
+
"bg-(--theme-border)": index >= currentIndex,
|
|
1489
|
+
"opacity-25": index >= currentIndex
|
|
1490
|
+
}),
|
|
1491
|
+
style: {
|
|
1492
|
+
top: "24px",
|
|
1493
|
+
left: "calc(50% + 24px)",
|
|
1494
|
+
right: "-50%",
|
|
1495
|
+
boxShadow: index < currentIndex ? "0 1px 2px rgba(34, 197, 94, 0.2)" : "none"
|
|
1496
|
+
},
|
|
1497
|
+
"aria-hidden": "true"
|
|
1498
|
+
}),
|
|
1499
|
+
/* @__PURE__ */ jsxs("div", {
|
|
1500
|
+
className: "mt-2 text-center",
|
|
1501
|
+
children: [/* @__PURE__ */ jsx("div", {
|
|
1502
|
+
className: cx("text-sm text-center transition-colors duration-300 max-w-30", {
|
|
1503
|
+
"font-bold text-green-600": isDotCompleted && !isInvalid,
|
|
1504
|
+
"font-bold text-red-600": isInvalid && status !== "active",
|
|
1505
|
+
"font-semibold theme-muted-text": !isDotActive && !isDotCompleted && !isInvalid,
|
|
1506
|
+
"font-bold text-white": isDotActive
|
|
1507
|
+
}),
|
|
1508
|
+
style: isDotActive ? { color: "var(--theme-element)" } : {},
|
|
1509
|
+
children: stepConfig?.title
|
|
1510
|
+
}), stepConfig?.description && /* @__PURE__ */ jsx("div", {
|
|
1511
|
+
className: "text-xs theme-muted-text mt-1 text-center max-w-30",
|
|
1512
|
+
children: stepConfig.description
|
|
1513
|
+
})]
|
|
1514
|
+
})
|
|
1515
|
+
]
|
|
1516
|
+
}, stepKey);
|
|
1543
1517
|
})
|
|
1544
1518
|
});
|
|
1545
1519
|
}
|
|
1546
1520
|
//#endregion
|
|
1547
|
-
//#region src/form/
|
|
1548
|
-
function
|
|
1549
|
-
|
|
1550
|
-
|
|
1551
|
-
|
|
1552
|
-
const
|
|
1521
|
+
//#region src/form/Wizard/WizardContainer.tsx
|
|
1522
|
+
function hasNestedError(stepErrors, fieldName) {
|
|
1523
|
+
return typeof stepErrors === "object" && stepErrors !== null && fieldName in stepErrors;
|
|
1524
|
+
}
|
|
1525
|
+
function WizardContainer({ wizardConfig, values, onChange, onSubmit, className = "", labelPosition = "left", missingFields = [], spaceCompact = false, workflowForm = false, setFieldValue, setFieldTouched }) {
|
|
1526
|
+
const { validateForm, setTouched, touched } = useFormikContext();
|
|
1527
|
+
const { config, steps, stepOrder } = wizardConfig;
|
|
1528
|
+
const { currentStep, visitedSteps, invalidSteps, isLastStep, canGoBack, goToNext, goToPrevious, jumpToStep } = useWizardState({
|
|
1529
|
+
stepOrder,
|
|
1530
|
+
steps,
|
|
1531
|
+
validateStep: useCallback(async (stepKey) => {
|
|
1532
|
+
const stepConfig = steps[stepKey];
|
|
1533
|
+
if (!stepConfig?.options) return true;
|
|
1534
|
+
const stepFieldNames = Object.keys(stepConfig.options);
|
|
1535
|
+
const shouldFlatten = config.flatten !== false;
|
|
1536
|
+
const errors = await validateForm();
|
|
1537
|
+
const hasStepErrors = shouldFlatten ? stepFieldNames.some((fieldName) => errors[fieldName]) : stepFieldNames.some((fieldName) => hasNestedError(errors[stepKey], fieldName));
|
|
1538
|
+
if (hasStepErrors) {
|
|
1539
|
+
const touchedFields = stepFieldNames.reduce((acc, fieldName) => {
|
|
1540
|
+
acc[fieldName] = true;
|
|
1541
|
+
return acc;
|
|
1542
|
+
}, {});
|
|
1543
|
+
if (shouldFlatten) setTouched({
|
|
1544
|
+
...touched,
|
|
1545
|
+
...touchedFields
|
|
1546
|
+
}, false);
|
|
1547
|
+
else setTouched({
|
|
1548
|
+
...touched,
|
|
1549
|
+
[stepKey]: touchedFields
|
|
1550
|
+
}, false);
|
|
1551
|
+
}
|
|
1552
|
+
return !hasStepErrors;
|
|
1553
|
+
}, [
|
|
1554
|
+
steps,
|
|
1555
|
+
config,
|
|
1556
|
+
validateForm,
|
|
1557
|
+
setTouched,
|
|
1558
|
+
touched
|
|
1559
|
+
])
|
|
1560
|
+
});
|
|
1561
|
+
const currentStepConfig = steps[currentStep];
|
|
1562
|
+
const config_ = config.navigation || {};
|
|
1563
|
+
const handleGoToNext = useCallback(async () => {
|
|
1564
|
+
const success = await goToNext();
|
|
1565
|
+
if (success) onChange?.(values);
|
|
1566
|
+
return success;
|
|
1567
|
+
}, [
|
|
1568
|
+
goToNext,
|
|
1569
|
+
values,
|
|
1570
|
+
onChange
|
|
1571
|
+
]);
|
|
1572
|
+
const handleJumpToStep = useCallback((stepKey) => {
|
|
1573
|
+
if (!config_.allowJump || !visitedSteps.has(stepKey)) return false;
|
|
1574
|
+
return jumpToStep(stepKey);
|
|
1575
|
+
}, [
|
|
1576
|
+
jumpToStep,
|
|
1577
|
+
config_.allowJump,
|
|
1578
|
+
visitedSteps
|
|
1579
|
+
]);
|
|
1580
|
+
const handleSubmit = useCallback(async () => {
|
|
1581
|
+
if (!isLastStep) return;
|
|
1582
|
+
const errors = await validateForm();
|
|
1583
|
+
if (Object.keys(errors).length > 0) {
|
|
1584
|
+
const touchedFields = Object.keys(values).reduce((acc, fieldName) => {
|
|
1585
|
+
acc[fieldName] = true;
|
|
1586
|
+
return acc;
|
|
1587
|
+
}, {});
|
|
1588
|
+
setTouched({
|
|
1589
|
+
...touched,
|
|
1590
|
+
...touchedFields
|
|
1591
|
+
}, false);
|
|
1592
|
+
throw new Error("Please fix errors before submitting");
|
|
1593
|
+
}
|
|
1594
|
+
await onSubmit?.(values);
|
|
1595
|
+
}, [
|
|
1596
|
+
isLastStep,
|
|
1597
|
+
validateForm,
|
|
1598
|
+
values,
|
|
1599
|
+
setTouched,
|
|
1600
|
+
touched,
|
|
1601
|
+
onSubmit
|
|
1602
|
+
]);
|
|
1553
1603
|
return /* @__PURE__ */ jsxs("div", {
|
|
1554
|
-
className
|
|
1555
|
-
children: [
|
|
1556
|
-
|
|
1557
|
-
|
|
1558
|
-
|
|
1559
|
-
|
|
1560
|
-
|
|
1561
|
-
|
|
1562
|
-
|
|
1563
|
-
|
|
1564
|
-
|
|
1565
|
-
}), /* @__PURE__ */ jsx(HeaderElement, {
|
|
1566
|
-
open,
|
|
1567
|
-
setOpen,
|
|
1568
|
-
title: /* @__PURE__ */ jsx(GroupHeader, {
|
|
1569
|
-
open,
|
|
1570
|
-
setOpen,
|
|
1571
|
-
title: field.label || label
|
|
1604
|
+
className,
|
|
1605
|
+
children: [
|
|
1606
|
+
config_.showSteps !== false && /* @__PURE__ */ jsx(WizardStepIndicator, {
|
|
1607
|
+
stepOrder,
|
|
1608
|
+
currentStep,
|
|
1609
|
+
steps,
|
|
1610
|
+
visitedSteps,
|
|
1611
|
+
invalidSteps,
|
|
1612
|
+
onStepClick: handleJumpToStep,
|
|
1613
|
+
allowJump: config_.allowJump,
|
|
1614
|
+
hideStepNumbers: config_.hideStepNumbers
|
|
1572
1615
|
}),
|
|
1573
|
-
|
|
1574
|
-
className: "
|
|
1575
|
-
children: /* @__PURE__ */ jsx(
|
|
1576
|
-
|
|
1616
|
+
currentStepConfig && /* @__PURE__ */ jsx("div", {
|
|
1617
|
+
className: "mb-4",
|
|
1618
|
+
children: /* @__PURE__ */ jsx(WizardStepContent, {
|
|
1619
|
+
currentStep,
|
|
1620
|
+
stepConfig: currentStepConfig,
|
|
1621
|
+
flatten: config.flatten,
|
|
1577
1622
|
values,
|
|
1578
|
-
|
|
1579
|
-
|
|
1580
|
-
setFieldTouched,
|
|
1623
|
+
onValuesChange: onChange,
|
|
1624
|
+
labelPosition,
|
|
1581
1625
|
missingFields,
|
|
1626
|
+
spaceCompact,
|
|
1627
|
+
setFormDirty: () => onChange?.(values),
|
|
1582
1628
|
workflowForm,
|
|
1583
|
-
|
|
1584
|
-
|
|
1585
|
-
parentInfo: {
|
|
1586
|
-
parentName: field.name,
|
|
1587
|
-
fieldNamePrefix: `${field.name}.`
|
|
1588
|
-
}
|
|
1629
|
+
setFieldValue,
|
|
1630
|
+
setFieldTouched
|
|
1589
1631
|
})
|
|
1632
|
+
}),
|
|
1633
|
+
/* @__PURE__ */ jsx(WizardNavigation, {
|
|
1634
|
+
currentStep,
|
|
1635
|
+
stepOrder,
|
|
1636
|
+
canGoToNext: !isLastStep,
|
|
1637
|
+
canGoBack,
|
|
1638
|
+
isCurrentStepValid: !invalidSteps.has(currentStep),
|
|
1639
|
+
nextLabel: currentStepConfig?.nextLabel,
|
|
1640
|
+
prevLabel: currentStepConfig?.prevLabel,
|
|
1641
|
+
submitLabel: config.submitLabel || "Execute",
|
|
1642
|
+
onNext: handleGoToNext,
|
|
1643
|
+
onPrevious: goToPrevious,
|
|
1644
|
+
onSubmit: handleSubmit
|
|
1590
1645
|
})
|
|
1591
|
-
|
|
1592
|
-
});
|
|
1593
|
-
}
|
|
1594
|
-
//#endregion
|
|
1595
|
-
//#region src/form/Fields/StepField.tsx
|
|
1596
|
-
function StepField(_props) {
|
|
1597
|
-
return null;
|
|
1598
|
-
}
|
|
1599
|
-
//#endregion
|
|
1600
|
-
//#region src/form/Fields/BucketReadOnlyField.tsx
|
|
1601
|
-
function BucketReadOnlyField({ field, disabled, missing, labelPosition, setFormDirty }) {
|
|
1602
|
-
const { form: t } = useStrings();
|
|
1603
|
-
const [fieldState] = useField(field.name);
|
|
1604
|
-
const { setFieldTouched, setFieldValue, values } = useFormikContext();
|
|
1605
|
-
const accessFieldName = field.name?.replace(/readOnly$/, "bucketAccessWritable");
|
|
1606
|
-
const forced = fieldState.value === true && !!accessFieldName && getIn(values, accessFieldName) === false;
|
|
1607
|
-
return /* @__PURE__ */ jsx(FieldWrapper, {
|
|
1608
|
-
optional: true,
|
|
1609
|
-
label: t.readOnly,
|
|
1610
|
-
description: t.readOnlyDescription,
|
|
1611
|
-
labelPosition,
|
|
1612
|
-
children: ({ id, describedBy }) => /* @__PURE__ */ jsxs("div", {
|
|
1613
|
-
className: "flex flex-col gap-2",
|
|
1614
|
-
children: [/* @__PURE__ */ jsx(SwitchToggle, {
|
|
1615
|
-
id,
|
|
1616
|
-
"aria-describedby": describedBy,
|
|
1617
|
-
onChange: (value) => {
|
|
1618
|
-
if (disabled) return;
|
|
1619
|
-
setFieldTouched(field.name, true);
|
|
1620
|
-
setFieldValue(field.name, value);
|
|
1621
|
-
setFormDirty(true);
|
|
1622
|
-
},
|
|
1623
|
-
value: fieldState.value === true,
|
|
1624
|
-
disabled,
|
|
1625
|
-
invalid: missing,
|
|
1626
|
-
yesLabel: t.readOnly,
|
|
1627
|
-
noLabel: t.readWrite
|
|
1628
|
-
}), /* @__PURE__ */ jsx("p", {
|
|
1629
|
-
className: cx("theme-muted-text max-w-[65ch]", !forced && "hidden"),
|
|
1630
|
-
children: t.readOnlyForced
|
|
1631
|
-
})]
|
|
1632
|
-
})
|
|
1633
|
-
});
|
|
1634
|
-
}
|
|
1635
|
-
//#endregion
|
|
1636
|
-
//#region src/form/fieldRegistry.tsx
|
|
1637
|
-
var CORE_FIELD_COMPONENTS = {
|
|
1638
|
-
string: StringField_default,
|
|
1639
|
-
password: StringField_default,
|
|
1640
|
-
number: NumberField,
|
|
1641
|
-
boolean: BooleanField,
|
|
1642
|
-
dropdown: DropdownField,
|
|
1643
|
-
textarea: TextAreaField,
|
|
1644
|
-
range: RangeField,
|
|
1645
|
-
duration: DurationField_default,
|
|
1646
|
-
radio: RadioField,
|
|
1647
|
-
label: LabelField,
|
|
1648
|
-
color: ColorField,
|
|
1649
|
-
"multi-dropdown": MultiDropdownField,
|
|
1650
|
-
"checkbox-group": CheckboxGroupField,
|
|
1651
|
-
object: ObjectField,
|
|
1652
|
-
step: StepField,
|
|
1653
|
-
"bucket-read-only": BucketReadOnlyField
|
|
1654
|
-
};
|
|
1655
|
-
var FieldRegistryContext = createContext({});
|
|
1656
|
-
/** Returns null for field types no registry knows. Per-form `fields` win over
|
|
1657
|
-
* the provider's `slots.formFields`, which win over the core registry. */
|
|
1658
|
-
function Registry(props) {
|
|
1659
|
-
const injected = useContext(FieldRegistryContext);
|
|
1660
|
-
const { formFields } = useSlots();
|
|
1661
|
-
const Component = injected[props.field.type] ?? formFields?.[props.field.type] ?? CORE_FIELD_COMPONENTS[props.field.type];
|
|
1662
|
-
if (!Component) return null;
|
|
1663
|
-
return /* @__PURE__ */ jsx(Suspense, {
|
|
1664
|
-
fallback: null,
|
|
1665
|
-
children: /* @__PURE__ */ jsx(Component, { ...props })
|
|
1646
|
+
]
|
|
1666
1647
|
});
|
|
1667
1648
|
}
|
|
1668
1649
|
//#endregion
|
|
@@ -1759,15 +1740,16 @@ function defaultReferencesField(defaultValue, fieldPath) {
|
|
|
1759
1740
|
function findSelfReferencingFieldNames(schema, values = {}) {
|
|
1760
1741
|
return collectFieldsWithDefaults(schema, values).filter(({ name, defaultValue }) => defaultReferencesField(defaultValue, name)).map(({ name }) => name);
|
|
1761
1742
|
}
|
|
1762
|
-
/** Resolves schema defaults into form values as dependencies change. Store-agnostic so the
|
|
1763
|
-
* form
|
|
1743
|
+
/** Resolves schema defaults into form values as dependencies change. Store-agnostic so the Formik
|
|
1744
|
+
* form and hosts with their own store share one implementation. */
|
|
1764
1745
|
function useDynamicDefaultsSync({ options, values, setValue, isTouched }) {
|
|
1746
|
+
const engine = useWorkflowEngine();
|
|
1765
1747
|
const listSig = useMemo(() => listLengthsSignature(options, values), [options, values]);
|
|
1766
1748
|
const fieldsWithDefaults = useMemo(() => collectFieldsWithDefaults(options, values).map((f) => {
|
|
1767
1749
|
if (typeof f.defaultValue !== "string" || !f.defaultValue.includes("${{")) return f;
|
|
1768
1750
|
const lastRowIndex = [...f.name.matchAll(/\[(\d+)\]/g)].at(-1)?.[1];
|
|
1769
1751
|
const index = lastRowIndex === void 0 ? -1 : Number(lastRowIndex);
|
|
1770
|
-
const parsed =
|
|
1752
|
+
const parsed = engine.evaluate({
|
|
1771
1753
|
inputs: values,
|
|
1772
1754
|
obj: { v: f.defaultValue },
|
|
1773
1755
|
orgVars: {},
|
|
@@ -1863,7 +1845,7 @@ function deleteFieldByPath(obj, path) {
|
|
|
1863
1845
|
if (acc && typeof acc === "object") return acc[curr];
|
|
1864
1846
|
return {};
|
|
1865
1847
|
}, obj);
|
|
1866
|
-
if (parent && typeof parent === "object" && Object.
|
|
1848
|
+
if (parent && typeof parent === "object" && Object.hasOwn(parent, fieldToRemove)) delete parent[fieldToRemove];
|
|
1867
1849
|
}
|
|
1868
1850
|
function getClosestParentIndex(parentPath) {
|
|
1869
1851
|
for (let i = parentPath.length - 1; i >= 0; i--) if (parentPath[i] === "]") {
|
|
@@ -1872,33 +1854,6 @@ function getClosestParentIndex(parentPath) {
|
|
|
1872
1854
|
return parseInt(parentPath.slice(j + 1, i));
|
|
1873
1855
|
}
|
|
1874
1856
|
}
|
|
1875
|
-
function getInstanceTypesForForm(instances) {
|
|
1876
|
-
return Object.entries(instances).map(([name, instance]) => {
|
|
1877
|
-
const flexLabel = instance.isFlex ? ", Flex" : "";
|
|
1878
|
-
const localDisk = instance.localDiskSizeGb ? ` , ${instance.localDiskSizeGb} GB Local Disk` : "";
|
|
1879
|
-
return {
|
|
1880
|
-
value: name,
|
|
1881
|
-
label: `${name} (${instance.vcpus} vCPUs, ${instance.memoryGb} GB Memory, ${instance.arch}${localDisk}${flexLabel})`,
|
|
1882
|
-
secondaryValue: [
|
|
1883
|
-
instance.arch,
|
|
1884
|
-
!!instance.acceleratedNetworking,
|
|
1885
|
-
!!instance.acceleratedNetworking,
|
|
1886
|
-
!!instance.localDiskSizeGb,
|
|
1887
|
-
!!instance.isFlex
|
|
1888
|
-
]
|
|
1889
|
-
};
|
|
1890
|
-
});
|
|
1891
|
-
}
|
|
1892
|
-
function StatusBlock({ status }) {
|
|
1893
|
-
return /* @__PURE__ */ jsx("div", { children: /* @__PURE__ */ jsx("div", {
|
|
1894
|
-
"data-tooltip-id": TOOLTIP_ID,
|
|
1895
|
-
"data-tooltip-content": status ? "Storage has been attached." : "Attaching the storage to cluster...",
|
|
1896
|
-
children: status ? /* @__PURE__ */ jsx(SuccessCheckmark, {}) : /* @__PURE__ */ jsx(Loader, {
|
|
1897
|
-
size: 13,
|
|
1898
|
-
full: false
|
|
1899
|
-
})
|
|
1900
|
-
}) });
|
|
1901
|
-
}
|
|
1902
1857
|
function MultiSelectionDropdown({ name, label = "", invalid = false, options: initialOptions = [], setFormDirty, onChange, parentValue }) {
|
|
1903
1858
|
const [field] = useField(name);
|
|
1904
1859
|
const required = useFieldRequired();
|
|
@@ -1925,14 +1880,20 @@ function MultiSelectionDropdown({ name, label = "", invalid = false, options: in
|
|
|
1925
1880
|
};
|
|
1926
1881
|
const t = useStrings().common;
|
|
1927
1882
|
const handleRemoveOption = (key) => {
|
|
1928
|
-
|
|
1883
|
+
const selected = [...field.value.filter((item) => item !== key)];
|
|
1884
|
+
setFieldValue(name, selected);
|
|
1929
1885
|
if (onChange) onChange(options);
|
|
1930
1886
|
setFormDirty(true);
|
|
1931
1887
|
};
|
|
1932
1888
|
const prevParent = usePrevious(parentValue);
|
|
1933
1889
|
useEffect(() => {
|
|
1934
1890
|
if (prevParent && parentValue && prevParent !== parentValue) setFieldValue(name, []);
|
|
1935
|
-
}, [
|
|
1891
|
+
}, [
|
|
1892
|
+
parentValue,
|
|
1893
|
+
prevParent,
|
|
1894
|
+
name,
|
|
1895
|
+
setFieldValue
|
|
1896
|
+
]);
|
|
1936
1897
|
return /* @__PURE__ */ jsxs(Fragment$1, { children: [/* @__PURE__ */ jsx(CustomListbox, {
|
|
1937
1898
|
...controlProps,
|
|
1938
1899
|
options,
|
|
@@ -1942,7 +1903,7 @@ function MultiSelectionDropdown({ name, label = "", invalid = false, options: in
|
|
|
1942
1903
|
className: "mb-3",
|
|
1943
1904
|
invalid,
|
|
1944
1905
|
closeOnSelect: false
|
|
1945
|
-
}), /* @__PURE__ */ jsx(Table, { children: field.value && field.value.length > 0 ? options.filter((option) => option.selected).map((option
|
|
1906
|
+
}), /* @__PURE__ */ jsx(Table, { children: field.value && field.value.length > 0 ? options.filter((option) => option.selected).map((option) => {
|
|
1946
1907
|
return /* @__PURE__ */ jsxs("tr", { children: [/* @__PURE__ */ jsx(Table.Item, {
|
|
1947
1908
|
className: "w-full",
|
|
1948
1909
|
children: option?.label
|
|
@@ -1952,7 +1913,7 @@ function MultiSelectionDropdown({ name, label = "", invalid = false, options: in
|
|
|
1952
1913
|
className: "inline-flex bg-transparent p-0 cursor-pointer",
|
|
1953
1914
|
onClick: () => handleRemoveOption(option.value),
|
|
1954
1915
|
children: /* @__PURE__ */ jsx(TrashIcon, { className: "link mr-4" })
|
|
1955
|
-
}) })] },
|
|
1916
|
+
}) })] }, String(option.value));
|
|
1956
1917
|
}) : /* @__PURE__ */ jsx("tr", { children: /* @__PURE__ */ jsxs(Table.Item, { children: [
|
|
1957
1918
|
"No ",
|
|
1958
1919
|
label !== "" ? label.toLowerCase() : "options",
|
|
@@ -1974,11 +1935,12 @@ var InputField = React.memo(function InputField({ label, field, setFormDirty, on
|
|
|
1974
1935
|
text: typeof fieldObj.tooltip === "string" ? fieldObj.tooltip.replace(/\r/g, "") : fieldObj.tooltip.filter(Boolean).join("\n")
|
|
1975
1936
|
});
|
|
1976
1937
|
}, [fieldObj.tooltip]);
|
|
1938
|
+
const missing = missingFields.includes(fieldObj.name ?? "");
|
|
1977
1939
|
return /* @__PURE__ */ jsx(Registry, {
|
|
1978
1940
|
field: fieldObj,
|
|
1979
1941
|
label,
|
|
1980
1942
|
labelPosition,
|
|
1981
|
-
missing
|
|
1943
|
+
missing,
|
|
1982
1944
|
missingFields,
|
|
1983
1945
|
values,
|
|
1984
1946
|
setFormDirty,
|
|
@@ -2020,6 +1982,7 @@ function DirtyStateBridge({ setFormDirty }) {
|
|
|
2020
1982
|
}
|
|
2021
1983
|
/** Three-tier cache: no expressions → raw pass-through; input-dep expressions → re-parse on dep change; org-var/path expressions → parse once. */
|
|
2022
1984
|
function useFieldParse(optionsField, values, arrayIndex) {
|
|
1985
|
+
const engine = useWorkflowEngine();
|
|
2023
1986
|
const c = useRef({
|
|
2024
1987
|
lastOptField: null,
|
|
2025
1988
|
convertedField: null,
|
|
@@ -2031,8 +1994,8 @@ function useFieldParse(optionsField, values, arrayIndex) {
|
|
|
2031
1994
|
}).current;
|
|
2032
1995
|
if (optionsField !== c.lastOptField) {
|
|
2033
1996
|
c.lastOptField = optionsField;
|
|
2034
|
-
c.convertedField =
|
|
2035
|
-
const { inputDeps, hasExpressions } =
|
|
1997
|
+
c.convertedField = engine.convertInputs(asRecord(optionsField));
|
|
1998
|
+
const { inputDeps, hasExpressions } = engine.inputDependencies(c.convertedField);
|
|
2036
1999
|
c.inputDeps = inputDeps;
|
|
2037
2000
|
c.hasExpressions = hasExpressions;
|
|
2038
2001
|
c.result = null;
|
|
@@ -2051,7 +2014,7 @@ function useFieldParse(optionsField, values, arrayIndex) {
|
|
|
2051
2014
|
}
|
|
2052
2015
|
if (!changed) return c.result;
|
|
2053
2016
|
}
|
|
2054
|
-
c.result =
|
|
2017
|
+
c.result = engine.evaluate({
|
|
2055
2018
|
inputs: values,
|
|
2056
2019
|
obj: c.convertedField,
|
|
2057
2020
|
orgVars: {},
|
|
@@ -2088,8 +2051,10 @@ var FormField = React.memo(function FormField({ id, optionsField, fieldName, val
|
|
|
2088
2051
|
}
|
|
2089
2052
|
if (field.show_if !== void 0 || field.show_if_not !== void 0) {
|
|
2090
2053
|
let index;
|
|
2091
|
-
if (parentInfo)
|
|
2092
|
-
|
|
2054
|
+
if (parentInfo) {
|
|
2055
|
+
if (!parentInfo?.arrayIndex) index = getClosestParentIndex(parentInfo.fieldNamePrefix);
|
|
2056
|
+
else index = parentInfo.arrayIndex;
|
|
2057
|
+
}
|
|
2093
2058
|
let shouldShowField = true;
|
|
2094
2059
|
if (field.show_if !== void 0) shouldShowField = !!getParentValue(index, field.show_if, values, "", field);
|
|
2095
2060
|
if (shouldShowField && field.show_if_not !== void 0) shouldShowField = !getParentValue(index, field.show_if_not, values, "", field);
|
|
@@ -2161,8 +2126,10 @@ var FormField = React.memo(function FormField({ id, optionsField, fieldName, val
|
|
|
2161
2126
|
if (prevParentValue !== void 0 && prevParentValue !== parentValue) deleteFieldByPath(values, fieldObj["name"]);
|
|
2162
2127
|
field.prevParentValue = parentValue;
|
|
2163
2128
|
}
|
|
2164
|
-
if (field.secondaryField)
|
|
2165
|
-
|
|
2129
|
+
if (field.secondaryField) {
|
|
2130
|
+
if (Array.isArray(field.secondaryField)) fieldObj["secondaryField"] = field.secondaryField.map((secondaryField) => fieldNamePrefix + secondaryField);
|
|
2131
|
+
else fieldObj["secondaryField"] = fieldNamePrefix + field.secondaryField;
|
|
2132
|
+
}
|
|
2166
2133
|
return /* @__PURE__ */ jsx("div", {
|
|
2167
2134
|
className: cx("flex w-full", labelPosition === "left" ? "mb-[15px]" : "mb-[5px]"),
|
|
2168
2135
|
children: /* @__PURE__ */ jsx(InputField, {
|
|
@@ -2206,7 +2173,7 @@ function FieldsFromOptions({ options = {}, values, setFormDirty, setFieldValue,
|
|
|
2206
2173
|
missingFields,
|
|
2207
2174
|
spaceCompact,
|
|
2208
2175
|
workflowForm
|
|
2209
|
-
},
|
|
2176
|
+
}, fieldName));
|
|
2210
2177
|
}
|
|
2211
2178
|
var noop = () => {};
|
|
2212
2179
|
function DynamicFormContent({ options, setValues, setFormDirty, labelPosition, missingFields, spaceCompact, organizationVariables, remoteVars, workflowForm, onSubmit, submitLabel, values, contextKey }) {
|
|
@@ -2252,13 +2219,14 @@ function DynamicFormContent({ options, setValues, setFormDirty, labelPosition, m
|
|
|
2252
2219
|
}
|
|
2253
2220
|
var NO_FIELDS = {};
|
|
2254
2221
|
function DynamicForm({ formJSONs: options = {}, reinitialize = false, initialValues, setValues, setFormDirty = noop, formikRef, labelPosition = "left", missingFields = [], spaceCompact = false, organizationVariables, remoteVars, needsOrganizationVariables = false, onSubmit = void 0, submitLabel = "Submit", className = "w-full", workflowForm = false, contextKey, skipValueParse = false, fields = NO_FIELDS }) {
|
|
2255
|
-
const
|
|
2222
|
+
const engine = useWorkflowEngine();
|
|
2223
|
+
const [parseReady, setParseReady] = useState(() => engine.isReady());
|
|
2256
2224
|
useEffect(() => {
|
|
2257
|
-
|
|
2258
|
-
return
|
|
2259
|
-
}, []);
|
|
2225
|
+
engine.init();
|
|
2226
|
+
return engine.onReady(setParseReady);
|
|
2227
|
+
}, [engine]);
|
|
2260
2228
|
if (!parseReady) return /* @__PURE__ */ jsx(Loader, {});
|
|
2261
|
-
const parsedInitVals = skipValueParse ? initialValues : initialValues &&
|
|
2229
|
+
const parsedInitVals = skipValueParse ? initialValues : initialValues && engine.evaluate({
|
|
2262
2230
|
inputs: initialValues,
|
|
2263
2231
|
obj: initialValues,
|
|
2264
2232
|
orgVars: organizationVariables,
|
|
@@ -2351,95 +2319,4 @@ function FormikMultiSelectDropdown({ name, options, setFormDirty, onChange, disa
|
|
|
2351
2319
|
});
|
|
2352
2320
|
}
|
|
2353
2321
|
//#endregion
|
|
2354
|
-
|
|
2355
|
-
function resolvePwString(raw, options, fallbackUsername, opts) {
|
|
2356
|
-
let inputForm = null;
|
|
2357
|
-
let owner;
|
|
2358
|
-
let name;
|
|
2359
|
-
if (typeof raw === "string" && raw.startsWith("pw://")) {
|
|
2360
|
-
const parts = raw.slice(5).split("/");
|
|
2361
|
-
if (parts.length === 1 && parts[0]) {
|
|
2362
|
-
inputForm = "shorthand";
|
|
2363
|
-
name = parts[0];
|
|
2364
|
-
owner = fallbackUsername;
|
|
2365
|
-
} else if (parts.length === 2 && parts[0] && parts[1]) {
|
|
2366
|
-
inputForm = "full";
|
|
2367
|
-
owner = parts[0];
|
|
2368
|
-
name = parts[1];
|
|
2369
|
-
}
|
|
2370
|
-
} else if (raw !== null && typeof raw === "object" && !Array.isArray(raw)) {
|
|
2371
|
-
const obj = raw;
|
|
2372
|
-
if (typeof obj["uri"] === "string" && obj["uri"].startsWith("pw://")) {
|
|
2373
|
-
const parts = obj["uri"].slice(5).split("/");
|
|
2374
|
-
if (parts.length === 1 && parts[0]) {
|
|
2375
|
-
inputForm = "shorthand";
|
|
2376
|
-
name = parts[0];
|
|
2377
|
-
owner = fallbackUsername;
|
|
2378
|
-
} else if (parts.length === 2 && parts[0] && parts[1]) {
|
|
2379
|
-
inputForm = "full";
|
|
2380
|
-
owner = parts[0];
|
|
2381
|
-
name = parts[1];
|
|
2382
|
-
}
|
|
2383
|
-
} else if (typeof obj["name"] === "string") {
|
|
2384
|
-
name = obj["name"];
|
|
2385
|
-
const ownerVal = typeof obj["user"] === "string" ? obj["user"] : typeof obj["namespace"] === "string" ? obj["namespace"] : void 0;
|
|
2386
|
-
if (obj["type"] === "managed-cluster" || !ownerVal) {
|
|
2387
|
-
inputForm = "shorthand";
|
|
2388
|
-
owner = fallbackUsername;
|
|
2389
|
-
} else {
|
|
2390
|
-
inputForm = "full";
|
|
2391
|
-
owner = ownerVal;
|
|
2392
|
-
}
|
|
2393
|
-
} else if (typeof obj["id"] === "string" && obj["id"]) {
|
|
2394
|
-
inputForm = "shorthand";
|
|
2395
|
-
name = obj["id"];
|
|
2396
|
-
owner = fallbackUsername;
|
|
2397
|
-
}
|
|
2398
|
-
}
|
|
2399
|
-
if (!inputForm || !name || !owner) return raw;
|
|
2400
|
-
const special = opts.specialCase?.(name, owner);
|
|
2401
|
-
if (special !== void 0) return special;
|
|
2402
|
-
const find = (pred) => {
|
|
2403
|
-
for (const category of options) for (const opt of category.options) if (opt.value && pred(opt.value)) return opt.value;
|
|
2404
|
-
};
|
|
2405
|
-
if (inputForm === "full") return find((v) => v.name === name && v[opts.ownerKey] === owner) ?? raw;
|
|
2406
|
-
const managed = find((v) => v.name === name && v.type === "managed-cluster");
|
|
2407
|
-
if (managed) return managed;
|
|
2408
|
-
const ownedByCaller = find((v) => v.name === name && v[opts.ownerKey] === fallbackUsername);
|
|
2409
|
-
if (ownedByCaller) return ownedByCaller;
|
|
2410
|
-
const sharedWithCaller = find((v) => v.name === name && typeof v[opts.ownerKey] === "string" && v[opts.ownerKey] !== fallbackUsername);
|
|
2411
|
-
if (sharedWithCaller) return sharedWithCaller;
|
|
2412
|
-
return raw;
|
|
2413
|
-
}
|
|
2414
|
-
function resolvePwValue(currentValue, options, fallbackUsername, opts) {
|
|
2415
|
-
if (Array.isArray(currentValue)) {
|
|
2416
|
-
let changed = false;
|
|
2417
|
-
const next = currentValue.map((v) => {
|
|
2418
|
-
const resolved = resolvePwString(v, options, fallbackUsername, opts);
|
|
2419
|
-
if (resolved !== v) changed = true;
|
|
2420
|
-
return resolved;
|
|
2421
|
-
});
|
|
2422
|
-
return changed ? next : currentValue;
|
|
2423
|
-
}
|
|
2424
|
-
return resolvePwString(currentValue, options, fallbackUsername, opts);
|
|
2425
|
-
}
|
|
2426
|
-
//#endregion
|
|
2427
|
-
//#region src/form/Fields/ResourceOptionIcon.tsx
|
|
2428
|
-
function ResourceOptionIcon({ imageUrl, fallbackIcon, alt, variant = "success", dotSize = 6 }) {
|
|
2429
|
-
return /* @__PURE__ */ jsxs("span", {
|
|
2430
|
-
className: "flex items-center gap-1.5 shrink-0",
|
|
2431
|
-
children: [/* @__PURE__ */ jsx(StatusDot, {
|
|
2432
|
-
variant,
|
|
2433
|
-
size: dotSize
|
|
2434
|
-
}), /* @__PURE__ */ jsx("img", {
|
|
2435
|
-
src: imageUrl || fallbackIcon,
|
|
2436
|
-
alt,
|
|
2437
|
-
className: "h-4 w-4 object-contain",
|
|
2438
|
-
onError: (e) => {
|
|
2439
|
-
e.currentTarget.src = fallbackIcon;
|
|
2440
|
-
}
|
|
2441
|
-
})]
|
|
2442
|
-
});
|
|
2443
|
-
}
|
|
2444
|
-
//#endregion
|
|
2445
|
-
export { DropdownWrapper, DynamicDefaultsSync, DynamicForm, FLEX_MAX_DURATION_RANGE, FLEX_WAIT_TIME_RANGE, FieldProvider, FieldRegistryContext, FieldWrapper, FieldsFromOptions, FormikCustomDropdown_default as FormikCustomDropdown, FormikCustomInput, FormikMultiSelectDropdown, FormikNumericInput, GroupHeader, MultiSelectionDropdown, NumberField, Registry, ResourceOptionIcon, STANDARD_MAX_DURATION_RANGE, StatusBlock, applySecondaryField, collectFieldsWithDefaults, collectPartitionDurationIssues, enforceOneMustBeTrue, findSecondaryOption, findSelfReferencingFieldNames, flattenGroups, formatSecondsAsSlurmDuration, getInstanceTypesForForm, getInvalidDurationPaths, getPlaceholder, impureSetValueFromPath, initializeValues, parseSlurmDuration, resolveMetaOverrides, resolvePwString, resolvePwValue, resolvedFlag, setDurationValidity, useDynamicDefaultsSync, useFieldControlProps, useFieldLabelledByProps, useFieldRequired, useParsedOpts };
|
|
2322
|
+
export { DropdownWrapper, DynamicDefaultsSync, DynamicForm, FLEX_MAX_DURATION_RANGE, FLEX_WAIT_TIME_RANGE, FieldProvider, FieldRegistryContext, FieldWrapper, FieldsFromOptions, FormikCustomDropdown_default as FormikCustomDropdown, FormikCustomInput, FormikMultiSelectDropdown, FormikNumericInput, GroupHeader, MultiSelectionDropdown, NumberField, Registry, ResourceOptionIcon, STANDARD_MAX_DURATION_RANGE, applySecondaryField, collectFieldsWithDefaults, collectPartitionDurationIssues, enforceOneMustBeTrue, findSecondaryOption, findSelfReferencingFieldNames, flattenGroups, formatDuration, getInvalidDurationPaths, getPlaceholder, impureSetValueFromPath, initializeValues, parseDuration, resolveMetaOverrides, resolvedFlag, setDurationValidity, useDynamicDefaultsSync, useFieldControlProps, useFieldLabelledByProps, useFieldRequired, useParsedOpts };
|