@parallelworks/ui 0.2.0 → 0.3.1

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.
Files changed (62) hide show
  1. package/README.md +5 -0
  2. package/dist/chunks/CodePreviewEditor-CSPRILMp.js +61 -0
  3. package/dist/chunks/Indicator-hBSIxOPK.js +39 -0
  4. package/dist/chunks/Markdown-C5Re2ezs.js +101 -0
  5. package/dist/chunks/{Indicator-fF8AVbjQ.js → Modal-sOUEwebV.js} +1 -38
  6. package/dist/chunks/{Monaco-CP_cL9gp.js → Monaco-CC4ak1JG.js} +3 -31
  7. package/dist/chunks/Provider-DvVvScTQ.js +391 -0
  8. package/dist/chunks/StatusBadge-DXp4zkSd.js +46 -0
  9. package/dist/chunks/{Table-DWuRINhu.js → SwitchToggle-2uRw8ZeJ.js} +2 -132
  10. package/dist/chunks/Table-C5z6qWjM.js +91 -0
  11. package/dist/chunks/editor-D55tumuZ.js +372 -0
  12. package/dist/chunks/list-7PyDF1tz.js +465 -0
  13. package/dist/components/Provider.d.ts +293 -0
  14. package/dist/editor/index.d.ts +1 -0
  15. package/dist/editor/index.js +2 -219
  16. package/dist/editor/useCssIsDark.d.ts +6 -0
  17. package/dist/file-explorer/FileExplorer.d.ts +23 -0
  18. package/dist/file-explorer/FileExplorerContext.d.ts +17 -0
  19. package/dist/file-explorer/FilePreview/CodePreviewEditor.d.ts +6 -0
  20. package/dist/file-explorer/FilePreview/Inline.d.ts +13 -0
  21. package/dist/file-explorer/FilePreview/StreamedBadge.d.ts +1 -0
  22. package/dist/file-explorer/FilePreview/Viewer.d.ts +15 -0
  23. package/dist/file-explorer/FilePreview/index.d.ts +15 -0
  24. package/dist/file-explorer/FilePreview/parse.d.ts +24 -0
  25. package/dist/file-explorer/FilePreview/previewCache.d.ts +26 -0
  26. package/dist/file-explorer/FilePreview/previewType.d.ts +21 -0
  27. package/dist/file-explorer/FilePreview/readCappedBytes.d.ts +37 -0
  28. package/dist/file-explorer/FilePreview/useObjectBlobUrl.d.ts +16 -0
  29. package/dist/file-explorer/FilePreview/useObjectText.d.ts +23 -0
  30. package/dist/file-explorer/FilePreview/usePresignedUrl.d.ts +12 -0
  31. package/dist/file-explorer/FileRow.d.ts +35 -0
  32. package/dist/file-explorer/FileRowsWindow.d.ts +43 -0
  33. package/dist/file-explorer/FileTable.d.ts +26 -0
  34. package/dist/file-explorer/FileTableHeaders.d.ts +13 -0
  35. package/dist/file-explorer/LoadMoreRow.d.ts +15 -0
  36. package/dist/file-explorer/TreeView.d.ts +28 -0
  37. package/dist/file-explorer/helpers.d.ts +47 -0
  38. package/dist/file-explorer/index.d.ts +10 -0
  39. package/dist/file-explorer/index.js +5646 -0
  40. package/dist/file-explorer/lib/batch.d.ts +3 -0
  41. package/dist/file-explorer/lib/errors.d.ts +3 -0
  42. package/dist/file-explorer/lib/fileExplorer.d.ts +32 -0
  43. package/dist/file-explorer/lib/paging.d.ts +93 -0
  44. package/dist/file-explorer/lib/types.d.ts +92 -0
  45. package/dist/file-explorer/lib/utils.d.ts +37 -0
  46. package/dist/file-explorer/toasts.d.ts +9 -0
  47. package/dist/file-explorer/treeRows.d.ts +35 -0
  48. package/dist/file-explorer/useNearEnd.d.ts +7 -0
  49. package/dist/form/index.js +4 -2
  50. package/dist/index.d.ts +1 -1
  51. package/dist/index.js +9 -101
  52. package/dist/list/ListTable.d.ts +63 -0
  53. package/dist/list/RowContextMenu.d.ts +113 -0
  54. package/dist/list/index.d.ts +2 -0
  55. package/dist/list/index.js +2 -0
  56. package/dist/logviewer/index.js +1 -1
  57. package/dist/styles/theme.css +30 -0
  58. package/dist/styles.css +1 -1
  59. package/dist/workflow/index.js +3 -2
  60. package/package.json +20 -3
  61. package/dist/chunks/Provider-C2VtPnh5.js +0 -151
  62. package/dist/chunks/workers-Cjfjb8E7.js +0 -119
@@ -0,0 +1,372 @@
1
+ import { CheckIcon, CopyIcon, EyeIcon, EyeOffIcon } from "../icons.js";
2
+ import { c as useStrings, i as useNotify } from "./Provider-DvVvScTQ.js";
3
+ import { t as Loader } from "./Loader-DQiZ75fa.js";
4
+ import { t as SwitchToggleSmall } from "./SwitchToggleSmall-FcsaYSTs.js";
5
+ import { c as FieldWrapper, n as flattenGroups, r as impureSetValueFromPath } from "./lib-DTgL8klR.js";
6
+ import cx from "classnames";
7
+ import { jsx, jsxs } from "react/jsx-runtime";
8
+ import { Suspense, lazy, useEffect, useMemo, useRef, useState } from "react";
9
+ import { convertToDynamicForm, parseStringsOfObj, parseStringsOfObjReady } from "@parallelworks/workflow-parser";
10
+ import { useField, useFormikContext } from "formik";
11
+ //#region src/editor/Editor.tsx
12
+ var MonacoEditor = lazy(() => import("./Monaco-CC4ak1JG.js"));
13
+ function Editor({ ...props }) {
14
+ return /* @__PURE__ */ jsx(Suspense, {
15
+ fallback: /* @__PURE__ */ jsx(Loader, { text: "Loading editor..." }),
16
+ children: /* @__PURE__ */ jsx(MonacoEditor, { ...props })
17
+ });
18
+ }
19
+ //#endregion
20
+ //#region src/editor/EditorField.tsx
21
+ function hasResetKeys(obj) {
22
+ return obj.editorKeyPostfix !== void 0;
23
+ }
24
+ function EditorField(props) {
25
+ const { field, label, labelPosition, disabled, onChange, tooltipComponent, spaceCompact, setFormDirty } = props;
26
+ const [fieldState] = useField(field.name);
27
+ const { setFieldValue, setFieldTouched, values } = useFormikContext();
28
+ const debounceRef = useRef(null);
29
+ const touchedRef = useRef(false);
30
+ const handleChange = (val) => {
31
+ touchedRef.current = true;
32
+ if (debounceRef.current) clearTimeout(debounceRef.current);
33
+ debounceRef.current = setTimeout(() => {
34
+ if (onChange) onChange(val);
35
+ setFieldTouched(field.name, true);
36
+ setFieldValue(field.name, val);
37
+ setFormDirty(true);
38
+ }, 500);
39
+ };
40
+ let editorKeyPostfix = "";
41
+ if (hasResetKeys(values)) editorKeyPostfix = values.editorKeyPostfix;
42
+ const postfixKey = useMemo(() => {
43
+ const randomKey = Math.random().toString(36).substring(7);
44
+ return editorKeyPostfix || randomKey;
45
+ }, [editorKeyPostfix]);
46
+ const value = fieldState.value;
47
+ return /* @__PURE__ */ jsx(FieldWrapper, {
48
+ optional: field.optional,
49
+ label,
50
+ tooltipComponent,
51
+ labelPosition,
52
+ spaceCompact,
53
+ children: /* @__PURE__ */ jsx(Editor, {
54
+ height: "200px",
55
+ path: field.name,
56
+ value: touchedRef.current ? void 0 : value,
57
+ className: cx("bg-(--theme-input-bg) w-11 border focus:border rounded text-[10px] leading-4 pl-[6px]", disabled && "opacity-75"),
58
+ readOnly: disabled,
59
+ onChange: handleChange,
60
+ language: field.options?.language || "shell"
61
+ }, field.name + postfixKey)
62
+ });
63
+ }
64
+ //#endregion
65
+ //#region src/editor/FormCodePanel.tsx
66
+ var shouldIgnoreField = (fieldSchema, inputs, arrayIndex) => {
67
+ if (!fieldSchema?.ignore || !fieldSchema?.hidden) return false;
68
+ if (!parseStringsOfObjReady) return false;
69
+ return parseStringsOfObj({
70
+ inputs,
71
+ obj: convertToDynamicForm(fieldSchema),
72
+ index: arrayIndex ?? -1
73
+ }).hidden === true;
74
+ };
75
+ var filterFields = (formJSON, data, prefix, rootData, arrayIndex) => {
76
+ const filteredFields = [];
77
+ return {
78
+ filteredFields,
79
+ filtered: Object.keys(data).reduce((acc, key) => {
80
+ if (data[key] !== null && Array.isArray(data[key])) {
81
+ acc[key] = [];
82
+ if (!formJSON[key]) return acc;
83
+ for (let i = 0; i < data[key].length; i++) {
84
+ let filteredFieldsNested = [];
85
+ let filteredNested = {};
86
+ if (typeof data[key][i] === "object") {
87
+ const result = filterFields(formJSON[key].options, data[key][i], key + `[${i}].`, rootData || data, i);
88
+ filteredNested = result.filtered;
89
+ filteredFieldsNested = result.filteredFields;
90
+ } else filteredNested = data[key][i];
91
+ filteredFields.push(...filteredFieldsNested);
92
+ acc[key][i] = filteredNested;
93
+ }
94
+ return acc;
95
+ }
96
+ if (data[key] !== null && formJSON && formJSON[key] && typeof data[key] === "object") {
97
+ const { filteredFields: filteredFieldsNested, filtered: filteredNested } = filterFields(formJSON[key], data[key], key + ".", rootData || data, arrayIndex);
98
+ filteredFields.push(...filteredFieldsNested);
99
+ acc[key] = filteredNested;
100
+ return acc;
101
+ }
102
+ if (formJSON?.[key]?.sensitive) {
103
+ const name = prefix ? prefix + key : key;
104
+ filteredFields.push({
105
+ key: name,
106
+ value: data[key]
107
+ });
108
+ return acc;
109
+ }
110
+ const contextData = rootData || data;
111
+ if (formJSON && shouldIgnoreField(formJSON[key], contextData, arrayIndex)) return acc;
112
+ acc[key] = data[key];
113
+ return acc;
114
+ }, {})
115
+ };
116
+ };
117
+ var populateFiltered = (filteredFields, data) => {
118
+ filteredFields.forEach((element) => {
119
+ impureSetValueFromPath(data, element.key, element.value);
120
+ });
121
+ return data;
122
+ };
123
+ function FormCodePanel({ formJSON, data, mutate, height = "600px", disabled = false }) {
124
+ const notify = useNotify();
125
+ const { common: t } = useStrings();
126
+ const [jsonHasErrors, setJsonHasErrors] = useState(false);
127
+ const [showHidden, setShowHidden] = useState(false);
128
+ const [copied, setCopied] = useState(false);
129
+ const copyResetRef = useRef(void 0);
130
+ const isValidJson = (errors) => {
131
+ setJsonHasErrors(errors.length > 0);
132
+ };
133
+ const { filteredFields, filtered } = filterFields(flattenGroups(formJSON), data || {});
134
+ const hasHiddenFields = filteredFields.length > 0;
135
+ const displayObj = showHidden && hasHiddenFields ? populateFiltered(filteredFields, structuredClone(filtered)) : filtered;
136
+ const showHiddenRef = useRef(showHidden);
137
+ showHiddenRef.current = showHidden;
138
+ const filteredFieldsRef = useRef(filteredFields);
139
+ filteredFieldsRef.current = filteredFields;
140
+ const json = JSON.stringify(displayObj, null, 2);
141
+ const handleCopy = async () => {
142
+ try {
143
+ await navigator.clipboard.writeText(json);
144
+ setCopied(true);
145
+ clearTimeout(copyResetRef.current);
146
+ copyResetRef.current = setTimeout(() => setCopied(false), 2e3);
147
+ } catch {
148
+ notify.error(t.copyFailed);
149
+ }
150
+ };
151
+ return /* @__PURE__ */ jsxs("div", {
152
+ style: { height },
153
+ className: "flex w-full flex-col gap-2",
154
+ children: [/* @__PURE__ */ jsxs("div", {
155
+ className: cx("flex min-h-0 flex-1 flex-col overflow-hidden rounded-md border", jsonHasErrors ? "border-red-500" : "border-(--theme-border)"),
156
+ children: [/* @__PURE__ */ jsxs("div", {
157
+ className: "bg-(--theme-muted-panel-bg) text-(--theme-muted-panel-color) flex shrink-0 items-center gap-3 border-b border-(--theme-border) px-3 py-2",
158
+ children: [hasHiddenFields && /* @__PURE__ */ jsxs("label", {
159
+ title: t.showHiddenFieldsHint,
160
+ className: "flex cursor-pointer select-none items-center gap-2 text-sm text-(--theme-app)",
161
+ children: [/* @__PURE__ */ jsx(SwitchToggleSmall, {
162
+ value: showHidden,
163
+ "aria-label": t.showHiddenFields,
164
+ onClick: () => setShowHidden((prev) => !prev)
165
+ }), /* @__PURE__ */ jsxs("span", {
166
+ className: "flex items-center gap-1.5",
167
+ children: [showHidden ? /* @__PURE__ */ jsx(EyeIcon, {}) : /* @__PURE__ */ jsx(EyeOffIcon, {}), t.showHiddenFields]
168
+ })]
169
+ }), /* @__PURE__ */ jsxs("button", {
170
+ type: "button",
171
+ onClick: handleCopy,
172
+ "aria-label": copied ? t.copied : t.copy,
173
+ className: "ml-auto flex shrink-0 items-center gap-1.5 rounded-md border border-(--theme-border) px-2.5 py-1.5 text-sm text-(--theme-app) transition-colors duration-150 hover:bg-(--theme-hover) focus:outline-none focus-visible:ring-2 focus-visible:ring-(--theme-link)",
174
+ children: [copied ? /* @__PURE__ */ jsx(CheckIcon, { className: "text-green-500" }) : /* @__PURE__ */ jsx(CopyIcon, { className: "text-(--theme-muted-text-color)" }), copied ? t.copied : t.copy]
175
+ })]
176
+ }), /* @__PURE__ */ jsx("div", {
177
+ className: "min-h-0 flex-1",
178
+ children: /* @__PURE__ */ jsx(Editor, {
179
+ height: "100%",
180
+ value: json,
181
+ onValidate: isValidJson,
182
+ className: "!rounded-none !border-0",
183
+ minimap: { enabled: false },
184
+ scrollBeyondLastLine: false,
185
+ overviewRulerLanes: 0,
186
+ overviewRulerBorder: false,
187
+ lineNumbersMinChars: 3,
188
+ lineDecorationsWidth: 8,
189
+ renderLineHighlight: "none",
190
+ padding: {
191
+ top: 12,
192
+ bottom: 12
193
+ },
194
+ fontSize: 13,
195
+ scrollbar: {
196
+ verticalScrollbarSize: 10,
197
+ horizontalScrollbarSize: 10
198
+ },
199
+ onChange: (e) => {
200
+ try {
201
+ const parsed = JSON.parse(e);
202
+ mutate(showHiddenRef.current ? parsed : populateFiltered(filteredFieldsRef.current, parsed));
203
+ } catch {
204
+ console.log("JSON.parse error in slurm editor");
205
+ }
206
+ },
207
+ language: "json",
208
+ disabled
209
+ })
210
+ })]
211
+ }), jsonHasErrors && /* @__PURE__ */ jsx("p", {
212
+ className: "shrink-0 text-sm text-red-500",
213
+ children: t.jsonHasErrors
214
+ })]
215
+ });
216
+ }
217
+ //#endregion
218
+ //#region src/editor/themes.ts
219
+ function expandShorthandHex(color) {
220
+ return /^#([0-9a-fA-F]{3,4})$/.test(color) ? "#" + color.slice(1).split("").map((c) => c + c).join("") : color;
221
+ }
222
+ function normalizeThemeColors(colors) {
223
+ return Object.fromEntries(Object.entries(colors).map(([key, value]) => [key, expandShorthandHex(value)]));
224
+ }
225
+ function themeVar(name, fallback) {
226
+ if (typeof window === "undefined") return fallback;
227
+ return getComputedStyle(document.documentElement).getPropertyValue(name).trim() || fallback;
228
+ }
229
+ function createEditorThemes() {
230
+ const dark = {
231
+ foreground: themeVar("--theme-app", "#e6edf3"),
232
+ background: themeVar("--theme-panel-bg", "#161b22"),
233
+ border: themeVar("--theme-border", "#30363d"),
234
+ lineHighlight: themeVar("--theme-muted-panel-bg", "#21262d"),
235
+ lineNumber: themeVar("--theme-muted-text-color", "#8b949e"),
236
+ selection: themeVar("--theme-element", "#2f81f7"),
237
+ selectionFg: themeVar("--theme-element-text", "#ffffff"),
238
+ disabledBg: themeVar("--theme-input-disabled-bg", "#1c2128"),
239
+ disabledFg: themeVar("--theme-muted-text-color", "#8b949e")
240
+ };
241
+ const light = {
242
+ disabledBg: themeVar("--theme-input-disabled-bg", "#f3f4f6"),
243
+ disabledFg: themeVar("--theme-muted-text-color", "#6c757d"),
244
+ border: themeVar("--theme-border", "#d1d5db"),
245
+ selection: themeVar("--theme-element", "#2f81f7"),
246
+ selectionFg: themeVar("--theme-element-text", "#ffffff")
247
+ };
248
+ return {
249
+ "app-dark": {
250
+ base: "vs-dark",
251
+ inherit: true,
252
+ rules: [],
253
+ colors: {
254
+ "editor.foreground": dark.foreground,
255
+ "editor.background": dark.background,
256
+ "editor.border": dark.border,
257
+ "editorCursor.foreground": dark.foreground,
258
+ "editor.lineHighlightBackground": dark.lineHighlight,
259
+ "editorLineNumber.foreground": dark.lineNumber,
260
+ "editor.selectionBackground": dark.selection,
261
+ "editor.selectionForeground": dark.selectionFg
262
+ }
263
+ },
264
+ "app-dark-disabled": {
265
+ base: "vs-dark",
266
+ inherit: true,
267
+ rules: [],
268
+ colors: {
269
+ "editor.foreground": dark.disabledFg,
270
+ "editor.background": dark.disabledBg,
271
+ "editor.border": dark.border,
272
+ "editorCursor.foreground": "transparent",
273
+ "editor.lineHighlightBackground": dark.disabledBg,
274
+ "editorLineNumber.foreground": dark.disabledFg,
275
+ "editor.selectionBackground": dark.selection,
276
+ "editor.selectionForeground": dark.selectionFg
277
+ }
278
+ },
279
+ "app-light-disabled": {
280
+ base: "vs",
281
+ inherit: true,
282
+ rules: [],
283
+ colors: {
284
+ "editor.foreground": light.disabledFg,
285
+ "editor.background": light.disabledBg,
286
+ "editor.border": light.border,
287
+ "editorCursor.foreground": "transparent",
288
+ "editor.lineHighlightBackground": light.disabledBg,
289
+ "editorLineNumber.foreground": light.disabledFg,
290
+ "editor.selectionBackground": light.selection,
291
+ "editor.selectionForeground": light.selectionFg
292
+ }
293
+ }
294
+ };
295
+ }
296
+ function defineEditorThemes(monacoEditor) {
297
+ const themes = createEditorThemes();
298
+ for (const [name, themeData] of Object.entries(themes)) monacoEditor.defineTheme(name, {
299
+ ...themeData,
300
+ colors: normalizeThemeColors(themeData.colors)
301
+ });
302
+ }
303
+ function getThemeName(isDark, disabled) {
304
+ if (isDark) return disabled ? "app-dark-disabled" : "app-dark";
305
+ return disabled ? "app-light-disabled" : "vs";
306
+ }
307
+ //#endregion
308
+ //#region src/editor/workers.ts
309
+ var monacoEnvironment = { getWorker(_moduleId, label) {
310
+ if (label === "json") return new Worker(new URL(
311
+ /* @vite-ignore */
312
+ "/assets/json.worker-8ytS02vz.js",
313
+ "" + import.meta.url
314
+ ), { type: "module" });
315
+ if (label === "yaml") return new Worker(new URL(
316
+ /* @vite-ignore */
317
+ "/assets/yaml.worker-DJC-VUcv.js",
318
+ "" + import.meta.url
319
+ ), { type: "module" });
320
+ return new Worker(new URL(
321
+ /* @vite-ignore */
322
+ "/assets/editor.worker-CuBRIwi-.js",
323
+ "" + import.meta.url
324
+ ), { type: "module" });
325
+ } };
326
+ /**
327
+ * Points window.MonacoEnvironment at the bundled workers. Idempotent, and a
328
+ * host that already configured its own MonacoEnvironment wins — the editor
329
+ * calls this on first load only when nothing is configured.
330
+ */
331
+ function setupMonacoWorkers() {
332
+ if (window.MonacoEnvironment) return;
333
+ window.MonacoEnvironment = monacoEnvironment;
334
+ }
335
+ //#endregion
336
+ //#region src/editor/useCssIsDark.ts
337
+ function readIsDark() {
338
+ const scheme = getComputedStyle(document.documentElement).colorScheme;
339
+ const dark = scheme.includes("dark");
340
+ if (dark !== scheme.includes("light")) return dark;
341
+ if (typeof window.matchMedia !== "function") return false;
342
+ return window.matchMedia("(prefers-color-scheme: dark)").matches;
343
+ }
344
+ /**
345
+ * Follows the host's CSS color-scheme, the same signal the log viewer's
346
+ * light-dark() palette uses — no provider API involved. For the rare concrete
347
+ * pick (editor themes, image variants) the tokens cannot express.
348
+ */
349
+ function useCssIsDark() {
350
+ const [isDark, setIsDark] = useState(readIsDark);
351
+ useEffect(() => {
352
+ const update = () => setIsDark(readIsDark());
353
+ const media = typeof window.matchMedia === "function" ? window.matchMedia("(prefers-color-scheme: dark)") : void 0;
354
+ media?.addEventListener("change", update);
355
+ const observer = new MutationObserver(update);
356
+ observer.observe(document.documentElement, {
357
+ attributes: true,
358
+ attributeFilter: [
359
+ "style",
360
+ "class",
361
+ "data-theme"
362
+ ]
363
+ });
364
+ return () => {
365
+ media?.removeEventListener("change", update);
366
+ observer.disconnect();
367
+ };
368
+ }, []);
369
+ return isDark;
370
+ }
371
+ //#endregion
372
+ export { FormCodePanel as a, getThemeName as i, setupMonacoWorkers as n, EditorField as o, defineEditorThemes as r, Editor as s, useCssIsDark as t };