@parallelworks/ui 0.19.1 → 0.21.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.
Files changed (172) hide show
  1. package/README.md +1 -1
  2. package/dist/ai/adapter/openai/createOpenAIStream.js +3 -2
  3. package/dist/ai/agent/diff.d.ts +0 -1
  4. package/dist/ai/agent/diff.js +3 -2
  5. package/dist/ai/agent/toolfmt.js +2 -3
  6. package/dist/ai/ai.css +5 -0
  7. package/dist/ai/components/AllocationSelector.js +3 -2
  8. package/dist/ai/components/AttachmentManager.js +5 -2
  9. package/dist/ai/components/BranchNavigator.js +4 -2
  10. package/dist/ai/components/ChatInput.d.ts +2 -5
  11. package/dist/ai/components/ChatInput.js +10 -7
  12. package/dist/ai/components/ChatMessage.js +11 -8
  13. package/dist/ai/components/ChatSidebar.d.ts +0 -1
  14. package/dist/ai/components/ChatSidebar.js +4 -6
  15. package/dist/ai/components/ChatThread.js +5 -8
  16. package/dist/ai/components/ModelSelector.js +3 -2
  17. package/dist/ai/components/ShareDialog.js +6 -3
  18. package/dist/ai/components/SlashMenu.d.ts +0 -1
  19. package/dist/ai/components/agent/ActivityLine.d.ts +0 -1
  20. package/dist/ai/components/agent/ActivityLine.js +2 -2
  21. package/dist/ai/components/agent/AgentMessageParts.d.ts +1 -26
  22. package/dist/ai/components/agent/AgentMessageParts.js +4 -5
  23. package/dist/ai/core/ChatProvider.d.ts +2 -6
  24. package/dist/ai/core/ChatProvider.js +42 -67
  25. package/dist/ai/core/KeyboardShortcutsProvider.js +1 -1
  26. package/dist/ai/core/chatReducer.d.ts +0 -6
  27. package/dist/ai/core/chatReducer.js +1 -15
  28. package/dist/ai/core/config.js +2 -1
  29. package/dist/ai/core/useKeyboardShortcuts.d.ts +3 -1
  30. package/dist/ai/core/useKeyboardShortcuts.js +9 -11
  31. package/dist/ai/core/useSSEStream.d.ts +0 -1
  32. package/dist/ai/core/useSSEStream.js +5 -17
  33. package/dist/ai/strings.d.ts +0 -1
  34. package/dist/ai/strings.js +0 -1
  35. package/dist/ai/types.d.ts +1 -1
  36. package/dist/ai/ui/Avatar.d.ts +1 -2
  37. package/dist/ai/ui/Avatar.js +7 -18
  38. package/dist/ai/ui/Markdown.d.ts +1 -3
  39. package/dist/ai/ui/Markdown.js +1 -2
  40. package/dist/ai/ui/sidebar.d.ts +0 -1
  41. package/dist/ai/ui/sidebar.js +3 -1
  42. package/dist/ai/utils.js +1 -1
  43. package/dist/assets/editor.worker-DfmPPyOL.js +60 -0
  44. package/dist/assets/json.worker-Dqgjpq9F.js +92 -0
  45. package/dist/assets/yaml.worker-DLx0whrM.js +1441 -0
  46. package/dist/components/Avatar.js +4 -2
  47. package/dist/components/BareModal.js +1 -5
  48. package/dist/components/Breadcrumbs.js +21 -14
  49. package/dist/components/CollapsiblePanel.d.ts +1 -3
  50. package/dist/components/CollapsiblePanel.js +5 -5
  51. package/dist/components/Dropdown.d.ts +0 -4
  52. package/dist/components/Dropdown.js +5 -6
  53. package/dist/components/Listbox.js +14 -18
  54. package/dist/components/MultiSelect.js +5 -8
  55. package/dist/components/Pagination.js +1 -1
  56. package/dist/components/Provider.d.ts +0 -8
  57. package/dist/components/Provider.js +12 -4
  58. package/dist/components/SwitchToggle.js +3 -5
  59. package/dist/components/Table.d.ts +1 -3
  60. package/dist/components/dropdownUtils.js +5 -6
  61. package/dist/components/relativeTime.d.ts +0 -7
  62. package/dist/components/relativeTime.js +1 -1
  63. package/dist/duration.js +1 -1
  64. package/dist/editor/Editor.d.ts +1 -1
  65. package/dist/editor/Editor.js +1 -1
  66. package/dist/editor/EditorField.d.ts +0 -1
  67. package/dist/editor/EditorField.js +8 -8
  68. package/dist/editor/FormCodePanel.js +14 -20
  69. package/dist/editor/Monaco.js +2 -25
  70. package/dist/editor/workers.d.ts +5 -0
  71. package/dist/editor/workers.js +14 -8
  72. package/dist/editor/yaml.d.ts +9 -1
  73. package/dist/editor/yaml.worker.d.ts +1 -0
  74. package/dist/editor/yamlLanguage.d.ts +6 -0
  75. package/dist/editor/yamlLanguage.js +312 -0
  76. package/dist/file-explorer/FileExplorer.js +60 -60
  77. package/dist/file-explorer/FileExplorerContext.d.ts +1 -2
  78. package/dist/file-explorer/FileExplorerContext.js +92 -125
  79. package/dist/file-explorer/FilePreview/Inline.d.ts +1 -2
  80. package/dist/file-explorer/FilePreview/Inline.js +2 -2
  81. package/dist/file-explorer/FilePreview/Viewer.js +0 -4
  82. package/dist/file-explorer/FilePreview/index.d.ts +1 -2
  83. package/dist/file-explorer/FilePreview/index.js +3 -3
  84. package/dist/file-explorer/FilePreview/parse.d.ts +2 -1
  85. package/dist/file-explorer/FilePreview/useObjectBlobUrl.d.ts +5 -4
  86. package/dist/file-explorer/FilePreview/useObjectBlobUrl.js +23 -36
  87. package/dist/file-explorer/FilePreview/useObjectText.d.ts +1 -2
  88. package/dist/file-explorer/FilePreview/useObjectText.js +5 -7
  89. package/dist/file-explorer/FileRow.js +1 -1
  90. package/dist/file-explorer/FileRowsWindow.d.ts +5 -12
  91. package/dist/file-explorer/FileTable.d.ts +2 -6
  92. package/dist/file-explorer/LoadMoreRow.d.ts +8 -0
  93. package/dist/file-explorer/TreeView.d.ts +0 -1
  94. package/dist/file-explorer/TreeView.js +6 -6
  95. package/dist/file-explorer/helpers.js +2 -4
  96. package/dist/file-explorer/lib/fileExplorer.d.ts +0 -2
  97. package/dist/file-explorer/lib/types.d.ts +0 -1
  98. package/dist/file-explorer/lib/utils.js +15 -20
  99. package/dist/file-explorer/toasts.js +36 -34
  100. package/dist/form/Fields/BooleanField.js +5 -4
  101. package/dist/form/Fields/CheckboxGroupField.js +5 -4
  102. package/dist/form/Fields/ColorField.js +5 -4
  103. package/dist/form/Fields/DropdownField.d.ts +0 -1
  104. package/dist/form/Fields/DropdownField.js +10 -13
  105. package/dist/form/Fields/DurationField.js +2 -2
  106. package/dist/form/Fields/LabelField.js +5 -5
  107. package/dist/form/Fields/MultiDropdownField.d.ts +1 -1
  108. package/dist/form/Fields/MultiDropdownField.js +8 -11
  109. package/dist/form/Fields/NumberField.js +6 -5
  110. package/dist/form/Fields/ObjectField.d.ts +1 -2
  111. package/dist/form/Fields/ObjectField.js +22 -21
  112. package/dist/form/Fields/RadioField.js +4 -3
  113. package/dist/form/Fields/RangeField.js +7 -6
  114. package/dist/form/Fields/StringField.js +2 -1
  115. package/dist/form/Fields/TextAreaField.js +2 -1
  116. package/dist/form/Form.d.ts +7 -8
  117. package/dist/form/Form.js +52 -78
  118. package/dist/form/SpecialTypes/DropdownWrapper.d.ts +0 -2
  119. package/dist/form/SpecialTypes/DropdownWrapper.js +1 -3
  120. package/dist/form/SpecialTypes/FormikCustomDropdown.d.ts +1 -3
  121. package/dist/form/SpecialTypes/FormikCustomDropdown.js +4 -7
  122. package/dist/form/SpecialTypes/FormikCustomInput.js +13 -11
  123. package/dist/form/Wizard/WizardContainer.js +8 -25
  124. package/dist/form/Wizard/WizardNavigation.d.ts +1 -1
  125. package/dist/form/Wizard/WizardNavigation.js +5 -6
  126. package/dist/form/Wizard/WizardStepContent.d.ts +1 -1
  127. package/dist/form/Wizard/WizardStepContent.js +2 -2
  128. package/dist/form/Wizard/WizardStepIndicator.js +7 -17
  129. package/dist/form/Wizard/types.d.ts +4 -46
  130. package/dist/form/Wizard/useWizardState.d.ts +2 -10
  131. package/dist/form/Wizard/useWizardState.js +42 -92
  132. package/dist/form/Wizard/utils.js +6 -11
  133. package/dist/form/lib.js +28 -54
  134. package/dist/form/types/fieldTypes.d.ts +4 -5
  135. package/dist/form/utils/dependentOptions.d.ts +6 -0
  136. package/dist/form/utils/dependentOptions.js +21 -0
  137. package/dist/form/utils/getParentValue.d.ts +2 -1
  138. package/dist/form/utils/getParentValue.js +10 -15
  139. package/dist/form/utils/getValueUsingPath.js +1 -1
  140. package/dist/graph/AnnotationBanner.d.ts +1 -1
  141. package/dist/graph/AnnotationBanner.js +1 -1
  142. package/dist/graph/Collapse.d.ts +3 -3
  143. package/dist/graph/Collapse.js +3 -8
  144. package/dist/graph/DependencyGraph.d.ts +5 -4
  145. package/dist/graph/DependencyGraph.js +172 -222
  146. package/dist/graph/JobSummary.d.ts +10 -8
  147. package/dist/graph/JobSummary.js +13 -13
  148. package/dist/graph/MatrixGroup.d.ts +5 -17
  149. package/dist/graph/MatrixGroup.js +11 -22
  150. package/dist/graph/TreeView.d.ts +1 -3
  151. package/dist/graph/TreeView.js +104 -491
  152. package/dist/graph/types.d.ts +3 -2
  153. package/dist/graph/util.d.ts +5 -0
  154. package/dist/graph/util.js +18 -0
  155. package/dist/icons.d.ts +5 -5
  156. package/dist/icons.js +6 -6
  157. package/dist/index.d.ts +1 -1
  158. package/dist/list/ListViewControls.js +17 -35
  159. package/dist/list/RowContextMenu.js +9 -8
  160. package/dist/list/UserHoverCard.js +5 -5
  161. package/dist/logviewer/LogViewer.js +7 -9
  162. package/dist/logviewer/segments.js +2 -2
  163. package/dist/safeUrl.d.ts +6 -0
  164. package/dist/safeUrl.js +22 -0
  165. package/dist/styles/theme.css +1 -0
  166. package/dist/styles.css +1 -1
  167. package/dist/theme/index.js +5 -5
  168. package/package.json +33 -37
  169. package/dist/ai/ui/buttons.d.ts +0 -1
  170. package/dist/assets/editor.worker-BmHUIVG4.js +0 -14807
  171. package/dist/assets/json.worker-D8bJ92nw.js +0 -22207
  172. package/dist/assets/yaml.worker-C4gyGAko.js +0 -50201
@@ -19,8 +19,10 @@ var STATUS_CLASSES = {
19
19
  /** Up to two initials: the first and last word of a name split on spaces and dots. */
20
20
  function avatarInitials(name) {
21
21
  const parts = (name ?? "").split(/[\s.]+/).filter(Boolean);
22
- if (parts.length >= 2) return (parts[0][0] + parts[parts.length - 1][0]).toUpperCase();
23
- return parts[0]?.[0]?.toUpperCase() || "?";
22
+ const first = parts[0]?.charAt(0);
23
+ const last = parts.at(-1)?.charAt(0);
24
+ if (parts.length >= 2 && first && last) return (first + last).toUpperCase();
25
+ return first?.toUpperCase() || "?";
24
26
  }
25
27
  function Avatar({ src, name, size = "md", status, className }) {
26
28
  const strings = useStrings();
@@ -37,14 +37,10 @@ function BareModal({ open, onClose, ariaLabel, className, onPanelKeyDown, onPane
37
37
  return;
38
38
  }
39
39
  const focusable = panel.querySelectorAll(FOCUSABLE);
40
- if (focusable.length === 0) {
41
- e.preventDefault();
42
- onPanelKeyDown?.(e);
43
- return;
44
- }
45
40
  const first = focusable[0];
46
41
  const last = focusable[focusable.length - 1];
47
42
  if (!first || !last) {
43
+ e.preventDefault();
48
44
  onPanelKeyDown?.(e);
49
45
  return;
50
46
  }
@@ -1,4 +1,4 @@
1
- import React, { createContext, useContext, useEffect, useLayoutEffect } from "react";
1
+ import React, { createContext, useContext, useEffect, useLayoutEffect, useMemo } from "react";
2
2
  import { jsx } from "react/jsx-runtime";
3
3
  //#region src/components/Breadcrumbs.tsx
4
4
  var BreadcrumbContext = createContext({
@@ -22,20 +22,27 @@ function BreadcrumbProvider({ children }) {
22
22
  const [titleActionSlot, setTitleActionSlot] = React.useState(null);
23
23
  const [rightActionSlot, setRightActionSlot] = React.useState(null);
24
24
  const claimedPath = React.useRef(null);
25
+ const value = useMemo(() => ({
26
+ breadcrumbs,
27
+ setBreadcrumbs,
28
+ rightsideBreadcrumb,
29
+ setRightsideBreadcrumb,
30
+ hidden,
31
+ setHidden,
32
+ titleActionSlot,
33
+ setTitleActionSlot,
34
+ rightActionSlot,
35
+ setRightActionSlot,
36
+ claimedPath
37
+ }), [
38
+ breadcrumbs,
39
+ rightsideBreadcrumb,
40
+ hidden,
41
+ titleActionSlot,
42
+ rightActionSlot
43
+ ]);
25
44
  return /* @__PURE__ */ jsx(BreadcrumbContext.Provider, {
26
- value: {
27
- breadcrumbs,
28
- setBreadcrumbs,
29
- rightsideBreadcrumb,
30
- setRightsideBreadcrumb,
31
- hidden,
32
- setHidden,
33
- titleActionSlot,
34
- setTitleActionSlot,
35
- rightActionSlot,
36
- setRightActionSlot,
37
- claimedPath
38
- },
45
+ value,
39
46
  children
40
47
  });
41
48
  }
@@ -6,15 +6,13 @@ interface IControlledCollapsiblePanelProps {
6
6
  setOpen?: React.Dispatch<React.SetStateAction<boolean>>;
7
7
  onClick?: (() => void) | undefined;
8
8
  wrapperElement?: React.ElementType | undefined;
9
- shown?: boolean;
10
- setShown?: (shown: boolean) => void;
11
9
  customizedButton?: React.ReactNode;
12
10
  /** Rendered right after the title, outside the toggle button. */
13
11
  titleAction?: React.ReactNode;
14
12
  className?: string | undefined;
15
13
  }
16
14
  export declare function ControlledCollapsiblePanel({ title, children, open, setOpen, onClick, wrapperElement, customizedButton, titleAction, className, }: IControlledCollapsiblePanelProps): React.JSX.Element;
17
- export declare function UncontrolledCollapsiblePanel({ title, children, onClick, wrapperElement, initialState, className, customizedButton, }: Omit<IControlledCollapsiblePanelProps, 'setOpen' | 'open'> & {
15
+ export declare function UncontrolledCollapsiblePanel({ title, children, onClick, wrapperElement, initialState, className, customizedButton, titleAction, }: Omit<IControlledCollapsiblePanelProps, 'setOpen' | 'open'> & {
18
16
  initialState?: boolean | undefined;
19
17
  }): React.JSX.Element;
20
18
  type MaybeCollapsibleProps = {
@@ -4,14 +4,13 @@ import React, { useCallback } from "react";
4
4
  import { Fragment as Fragment$1, jsx, jsxs } from "react/jsx-runtime";
5
5
  import AnimateHeight from "react-animate-height";
6
6
  //#region src/components/CollapsiblePanel.tsx
7
- var noop = () => {};
8
- function ControlledCollapsiblePanel({ title = "", children, open, setOpen, onClick = noop, wrapperElement, customizedButton = null, titleAction, className }) {
7
+ function ControlledCollapsiblePanel({ title = "", children, open, setOpen, onClick, wrapperElement, customizedButton = null, titleAction, className }) {
9
8
  const toggleOpen = useCallback(() => {
10
- if (onClick) onClick();
9
+ onClick?.();
11
10
  setOpen?.((open) => !open);
12
11
  }, [setOpen, onClick]);
13
12
  const contentId = React.useId();
14
- const Wrapper = wrapperElement ? wrapperElement : React.Fragment;
13
+ const Wrapper = wrapperElement ?? React.Fragment;
15
14
  return React.isValidElement(title) ? /* @__PURE__ */ jsxs(Fragment$1, { children: [title, /* @__PURE__ */ jsx(Wrapper, { children: /* @__PURE__ */ jsx(AnimateHeight, {
16
15
  duration: 300,
17
16
  height: open ? "auto" : 0,
@@ -46,7 +45,7 @@ function ControlledCollapsiblePanel({ title = "", children, open, setOpen, onCli
46
45
  })]
47
46
  });
48
47
  }
49
- function UncontrolledCollapsiblePanel({ title, children, onClick, wrapperElement, initialState = true, className, customizedButton = null }) {
48
+ function UncontrolledCollapsiblePanel({ title, children, onClick, wrapperElement, initialState = true, className, customizedButton = null, titleAction }) {
50
49
  const [open, setOpen] = React.useState(initialState);
51
50
  const passTitle = typeof title === "function" ? title(open, setOpen) : title;
52
51
  return /* @__PURE__ */ jsx(ControlledCollapsiblePanel, {
@@ -57,6 +56,7 @@ function UncontrolledCollapsiblePanel({ title, children, onClick, wrapperElement
57
56
  wrapperElement,
58
57
  className,
59
58
  customizedButton,
59
+ titleAction,
60
60
  children
61
61
  });
62
62
  }
@@ -4,10 +4,6 @@ export interface IProps {
4
4
  options: (ICategory | IOptions | string)[];
5
5
  onActiveChange?: (option: unknown) => void;
6
6
  onChange: React.Dispatch<SetStateAction<unknown>>;
7
- onRangeChange?: (range: {
8
- min: number;
9
- max: number;
10
- }) => void;
11
7
  value: IOptions | string | Record<string, unknown>;
12
8
  id?: string | undefined;
13
9
  ariaLabel?: string | undefined;
@@ -23,7 +23,7 @@ function getOptionFromValue(value, options) {
23
23
  label: "",
24
24
  value: ""
25
25
  };
26
- const found = options?.find((option) => {
26
+ const found = options.find((option) => {
27
27
  if (typeof option === "string") return checkEquals(value, option);
28
28
  else if (isCategory(option)) return option.options.find((opt) => checkEquals(value, opt.value));
29
29
  else return checkEquals(value, option.value);
@@ -47,15 +47,14 @@ function getOptionFromValue(value, options) {
47
47
  };
48
48
  }
49
49
  function Dropdown(props) {
50
- const { onChange, value, options = [], ...others } = props;
50
+ const { onChange, value, options, ...others } = props;
51
51
  const val = useMemo(() => {
52
52
  return getOptionFromValue(value, options);
53
53
  }, [value, options]);
54
54
  const wrapperOnchange = (value) => {
55
- if (onChange) onChange(value?.value);
55
+ onChange(value?.value);
56
56
  };
57
57
  const transformedOptions = useMemo(() => {
58
- if (!options || options.length === 0) return [];
59
58
  return options.map((item) => {
60
59
  if (isCategory(item)) return {
61
60
  ...item,
@@ -253,7 +252,7 @@ function DropdownHelper({ wrapperClassName = "w-full", className, textBoxClassNa
253
252
  allowCustomValue,
254
253
  customValueLabel
255
254
  ]);
256
- const comboOptions = /* @__PURE__ */ jsx(Fragment$1, { children: /* @__PURE__ */ jsx(ComboboxOptions, {
255
+ const comboOptions = /* @__PURE__ */ jsx(ComboboxOptions, {
257
256
  modal: false,
258
257
  ref: setPopperElement,
259
258
  style: styles["popper"],
@@ -282,7 +281,7 @@ function DropdownHelper({ wrapperClassName = "w-full", className, textBoxClassNa
282
281
  })
283
282
  });
284
283
  }
285
- }) });
284
+ });
286
285
  return /* @__PURE__ */ jsx("div", {
287
286
  className: cx("relative rounded-md flex items-center", wrapperClassName),
288
287
  children: /* @__PURE__ */ jsx(Combobox, {
@@ -5,29 +5,25 @@ import { focusOnMount } from "./focus.js";
5
5
  import { Listbox, ListboxButton, ListboxOption, ListboxOptions, Transition } from "@headlessui/react";
6
6
  import cx from "classnames";
7
7
  import { useEffect, useRef, useState } from "react";
8
- import { Fragment as Fragment$1, jsx, jsxs } from "react/jsx-runtime";
8
+ import { jsx, jsxs } from "react/jsx-runtime";
9
9
  //#region src/components/Listbox.tsx
10
10
  function CustomListbox({ options = [], handleOptionSelected, type, allowSearch = false, closeOnSelect = true, className = "", invalid = false, required = false, id, "aria-describedby": describedBy }) {
11
11
  const { dropdown: strings } = useStrings();
12
12
  const [filter, setFilter] = useState("");
13
13
  const [controlledOpen, setControlledOpen] = useState(false);
14
14
  const optionsToShow = options.filter((option) => !option.selected && option.label && option.label.toLowerCase().includes(filter.toLowerCase()));
15
- function useOutsideAlerter(ref) {
16
- useEffect(() => {
17
- function handleClickOutside(event) {
18
- if (ref.current && event.target instanceof Node && !ref.current.contains(event.target)) {
19
- setControlledOpen(false);
20
- setFilter("");
21
- }
22
- }
23
- document.addEventListener("mousedown", handleClickOutside);
24
- return () => {
25
- document.removeEventListener("mousedown", handleClickOutside);
26
- };
27
- }, [ref]);
28
- }
29
15
  const wrapperRef = useRef(null);
30
- useOutsideAlerter(wrapperRef);
16
+ useEffect(() => {
17
+ function handleClickOutside(event) {
18
+ const wrapper = wrapperRef.current;
19
+ if (wrapper && event.target instanceof Node && !wrapper.contains(event.target)) {
20
+ setControlledOpen(false);
21
+ setFilter("");
22
+ }
23
+ }
24
+ document.addEventListener("mousedown", handleClickOutside);
25
+ return () => document.removeEventListener("mousedown", handleClickOutside);
26
+ }, []);
31
27
  const optionsElement = /* @__PURE__ */ jsxs(ListboxOptions, {
32
28
  modal: false,
33
29
  static: true,
@@ -115,8 +111,8 @@ function CustomListbox({ options = [], handleOptionSelected, type, allowSearch =
115
111
  leave: "transition ease-in duration-100",
116
112
  leaveFrom: "opacity-100",
117
113
  leaveTo: "opacity-0",
118
- children: optionsElement || null
119
- }) : /* @__PURE__ */ jsx(Fragment$1, { children: controlledOpen && optionsElement })]
114
+ children: optionsElement
115
+ }) : controlledOpen && optionsElement]
120
116
  });
121
117
  }
122
118
  //#endregion
@@ -4,10 +4,11 @@ import { DropdownCaret, filterOption, flattenOptions, isCategory, isOption } fro
4
4
  import { focusOnMount } from "./focus.js";
5
5
  import { Combobox, ComboboxButton, ComboboxOption, ComboboxOptions } from "@headlessui/react";
6
6
  import cx from "classnames";
7
- import { useCallback, useMemo, useState } from "react";
7
+ import { useMemo, useState } from "react";
8
8
  import { Fragment as Fragment$1, jsx, jsxs } from "react/jsx-runtime";
9
9
  import { usePopper } from "react-popper";
10
10
  //#region src/components/MultiSelect.tsx
11
+ var strictEqual = (a, b) => a === b;
11
12
  function MultiSelectDropdown({ options, value, onChange, id, "aria-labelledby": labelledBy, "aria-describedby": describedBy, required, className, wrapperClassName = "w-full", textBoxClassName, disabled = false, placeholder, loading = false, searchable = true, maxTagCount = 2, compareBy }) {
12
13
  const strings = useStrings();
13
14
  const [query, setQuery] = useState("");
@@ -21,7 +22,7 @@ function MultiSelectDropdown({ options, value, onChange, id, "aria-labelledby":
21
22
  }]
22
23
  });
23
24
  const allOptions = useMemo(() => flattenOptions(options), [options]);
24
- const compare = compareBy ?? ((a, b) => a === b);
25
+ const compare = compareBy ?? strictEqual;
25
26
  const selectedOptions = useMemo(() => {
26
27
  const result = [];
27
28
  for (const val of value) {
@@ -38,7 +39,7 @@ function MultiSelectDropdown({ options, value, onChange, id, "aria-labelledby":
38
39
  if (!searchable || query.trim() === "") return allOptions;
39
40
  const result = [];
40
41
  for (const opt of allOptions) if (isCategory(opt)) {
41
- const matchedChildren = (Array.isArray(opt.options) ? opt.options : []).filter((o) => filterOption(o, query));
42
+ const matchedChildren = opt.options.filter((o) => filterOption(o, query));
42
43
  if (matchedChildren.length > 0) result.push(opt, ...matchedChildren);
43
44
  } else if (isOption(opt) && filterOption(opt, query)) result.push(opt);
44
45
  return result;
@@ -54,16 +55,12 @@ function MultiSelectDropdown({ options, value, onChange, id, "aria-labelledby":
54
55
  overflow: selectedOptions.length - shown.length
55
56
  };
56
57
  }, [selectedOptions, maxTagCount]);
57
- const handleChange = useCallback((newValues) => {
58
- if (!Array.isArray(newValues)) return;
59
- onChange(newValues);
60
- }, [onChange]);
61
58
  const isDisabled = disabled || loading;
62
59
  const isEmpty = filteredOptions.length === 0;
63
60
  return /* @__PURE__ */ jsx(Combobox, {
64
61
  multiple: true,
65
62
  value: Array.isArray(value) ? value : [],
66
- onChange: handleChange,
63
+ onChange,
67
64
  disabled: isDisabled,
68
65
  onClose: () => setQuery(""),
69
66
  by: compare,
@@ -8,7 +8,7 @@ function Pagination({ endingNumber, endingTime, nextCallback, prevCallback, roun
8
8
  className: cx(roundedBottom && "rounded-b-2xl", "theme-muted-panel flex items-center justify-between border-t theme-border px-4 py-1 sm:px-6"),
9
9
  "aria-label": "Pagination",
10
10
  children: [/* @__PURE__ */ jsx("div", {
11
- className: cx("hidden", (startingNumber !== void 0 && startingNumber !== null && endingNumber !== void 0 && endingNumber !== null || startingTime && endingTime) && "sm:block"),
11
+ className: cx("hidden", (startingNumber !== void 0 && endingNumber !== void 0 || startingTime && endingTime) && "sm:block"),
12
12
  children: /* @__PURE__ */ jsx("p", {
13
13
  className: "text-sm whitespace-nowrap",
14
14
  children: useTimeRange && startingTime && endingTime ? t.paginationShowingTimeRange(name ?? "", startingTime, endingTime) : t.paginationShowing(name ?? "", startingNumber ?? "", endingNumber ?? "")
@@ -476,14 +476,6 @@ export interface UISlots {
476
476
  }
477
477
  /** An engine, or a loader so the host can keep the engine out of its first-load bundle. */
478
478
  export type WorkflowEngineSource = WorkflowEngine | (() => Promise<WorkflowEngine>);
479
- export interface UIProviderValue {
480
- notify: UINotify;
481
- strings: UIStrings;
482
- navigation: UINavigation;
483
- data: UIData;
484
- slots: UISlots;
485
- engine?: WorkflowEngineSource | undefined;
486
- }
487
479
  export declare function useNotify(): UINotify;
488
480
  export declare function useStrings(): UIStrings;
489
481
  export declare function useNavigation(): UINavigation;
@@ -1,9 +1,10 @@
1
+ import { safeUrl } from "../safeUrl.js";
1
2
  import { createContext, use, useCallback, useContext, useEffect, useMemo } from "react";
2
3
  import { useLocalStorage } from "usehooks-ts";
3
4
  import { Fragment as Fragment$1, jsx, jsxs } from "react/jsx-runtime";
4
5
  //#region src/components/Provider.tsx
5
6
  var DefaultLink = ({ to, onClick, className, children, ...rest }) => /* @__PURE__ */ jsx("a", {
6
- href: to,
7
+ href: safeUrl(to),
7
8
  onClick,
8
9
  className,
9
10
  ...rest,
@@ -399,11 +400,18 @@ var DEFAULTS = {
399
400
  }
400
401
  },
401
402
  navigation: {
402
- goTo: (to) => window.location.assign(to),
403
+ goTo: (to) => {
404
+ const url = safeUrl(to);
405
+ if (url) window.location.assign(url);
406
+ },
403
407
  openStepSource: (_uses, sourceUrl) => {
404
- if (sourceUrl) window.open(sourceUrl, "_blank");
408
+ const url = safeUrl(sourceUrl);
409
+ if (url) window.open(url, "_blank");
405
410
  },
406
- openExternal: (href) => window.open(href, "_blank")
411
+ openExternal: (href) => {
412
+ const url = safeUrl(href);
413
+ if (url) window.open(url, "_blank");
414
+ }
407
415
  },
408
416
  data: {
409
417
  useRunFile: defaultUseRunFile,
@@ -1,19 +1,16 @@
1
1
  import { TOOLTIP_ID } from "./Tooltip.js";
2
2
  import { Switch } from "@headlessui/react";
3
3
  import cx from "classnames";
4
- import { useEffect, useState } from "react";
4
+ import { useState } from "react";
5
5
  import { jsx, jsxs } from "react/jsx-runtime";
6
6
  //#region src/components/SwitchToggle.tsx
7
- function SwitchToggle({ onChange, id, "aria-describedby": describedBy, value = void 0, yesLabel = "Yes", noLabel = "No", disabled = false, datatip = "", invalid = false }) {
7
+ function SwitchToggle({ onChange, id, "aria-describedby": describedBy, value, yesLabel = "Yes", noLabel = "No", disabled = false, datatip = "", invalid = false }) {
8
8
  const [enabled, setEnabled] = useState(value ?? false);
9
9
  const [isFocused, setIsFocused] = useState(false);
10
10
  const setIsEnabled = (e) => {
11
11
  setEnabled(e);
12
12
  onChange(e);
13
13
  };
14
- useEffect(() => {
15
- if (value !== void 0) setEnabled(value);
16
- }, [value]);
17
14
  const checked = value ?? enabled;
18
15
  return /* @__PURE__ */ jsx("div", {
19
16
  ...datatip ? {
@@ -25,6 +22,7 @@ function SwitchToggle({ onChange, id, "aria-describedby": describedBy, value = v
25
22
  id,
26
23
  "aria-describedby": describedBy,
27
24
  checked,
25
+ disabled,
28
26
  onChange: setIsEnabled,
29
27
  className: "text-white text-sm shadow-sm rounded-md cursor-pointer",
30
28
  onClick: (e) => e.stopPropagation(),
@@ -29,8 +29,6 @@ interface ITableProps {
29
29
  roundedTop?: boolean;
30
30
  rounded?: boolean;
31
31
  roundedBottom?: boolean;
32
- Item?: typeof Item;
33
- Header?: typeof Header;
34
32
  isLoading?: boolean;
35
33
  /** Forwarded to the `<table>`, for attributes that must sit on the element owning
36
34
  * the rows — `role='grid'`, aria-activedescendant, aria-rowcount. `className` is
@@ -46,7 +44,7 @@ export declare namespace Table {
46
44
  export { Header };
47
45
  export { Item };
48
46
  }
49
- export declare function CompactTable({ wrapperClassName, className, tbodyClassName, children, roundedTop, rounded, roundedBottom, }: ITableProps): React.JSX.Element;
47
+ export declare function CompactTable({ wrapperClassName, className, tbodyClassName, children, roundedTop, rounded, roundedBottom, }: Pick<ITableProps, 'wrapperClassName' | 'className' | 'tbodyClassName' | 'children' | 'roundedTop' | 'rounded' | 'roundedBottom'>): React.JSX.Element;
50
48
  export declare namespace CompactTable {
51
49
  export { Header };
52
50
  export { CompactItem as Item };
@@ -2,7 +2,7 @@ import { CaretDownIcon } from "../icons.js";
2
2
  import { jsx } from "react/jsx-runtime";
3
3
  //#region src/components/dropdownUtils.tsx
4
4
  function isCategory(option) {
5
- return typeof option === "object" && option !== null && option !== void 0 && "options" in option;
5
+ return typeof option === "object" && option !== null && "options" in option;
6
6
  }
7
7
  function isOption(option) {
8
8
  return typeof option === "object" && "label" in option && "value" in option && !("category" in option);
@@ -12,7 +12,7 @@ function normalizeOption(option) {
12
12
  label: option,
13
13
  value: option
14
14
  };
15
- if (typeof option === "object" && option !== null && option !== void 0 && "options" in option) return {
15
+ if (typeof option === "object" && option !== null && "options" in option) return {
16
16
  category: option.category,
17
17
  options: Array.isArray(option.options) ? option.options : []
18
18
  };
@@ -30,12 +30,11 @@ function flattenOptions(options) {
30
30
  }
31
31
  return result;
32
32
  }
33
+ var normalizeForMatch = (text) => String(text).toLowerCase().replace(/-/g, "");
33
34
  function filterOption(option, query) {
34
35
  if (query === "") return true;
35
- const q = String(query ?? "").toLowerCase().replace(/(-)/gm, "");
36
- const label = String(option.label ?? "").toLowerCase().replace(/(-)/gm, "");
37
- const secondary = option.secondaryValue !== void 0 ? String(option.secondaryValue).toLowerCase().replace(/(-)/gm, "") : "";
38
- return label.includes(q) || secondary.includes(q);
36
+ const q = normalizeForMatch(query);
37
+ return normalizeForMatch(option.label ?? "").includes(q) || option.secondaryValue !== void 0 && normalizeForMatch(option.secondaryValue).includes(q);
39
38
  }
40
39
  function toggleSetMember(set, member) {
41
40
  const next = new Set(set);
@@ -1,11 +1,4 @@
1
1
  import { DateTime } from 'luxon';
2
- export declare function compactRelativeMinutes(minutes: number, t: {
3
- now: string;
4
- minutes: (n: number) => string;
5
- hours: (n: number) => string;
6
- days: (n: number) => string;
7
- years: (n: number) => string;
8
- }): string;
9
2
  /** A clock that re-reads itself, so "5m" ages while the page sits open, with
10
3
  * the abbreviated form a row has room for. */
11
4
  export declare function useRelativeTime(): {
@@ -29,4 +29,4 @@ function useRelativeTime() {
29
29
  };
30
30
  }
31
31
  //#endregion
32
- export { compactRelativeMinutes, useRelativeTime };
32
+ export { useRelativeTime };
package/dist/duration.js CHANGED
@@ -3,7 +3,7 @@ import { Duration } from "luxon";
3
3
  var UnitDisplay = { ja: "short" };
4
4
  function durationToAbsHumanDuration(d) {
5
5
  const duration = d.shiftTo("days", "hours", "minutes", "seconds").toObject();
6
- if ("seconds" in duration) duration.seconds = Math.round(duration.seconds);
6
+ if (duration.seconds !== void 0) duration.seconds = Math.round(duration.seconds);
7
7
  const cleanedDuration = Object.fromEntries(Object.entries(duration).filter(([, value]) => value !== 0).map(([key, value]) => [key, Math.abs(value)]));
8
8
  if (Object.keys(cleanedDuration).length === 0) cleanedDuration.seconds = 0;
9
9
  const human = Duration.fromObject(cleanedDuration);
@@ -1,2 +1,2 @@
1
1
  import type { IEditorProps } from './Monaco.js';
2
- export default function Editor({ ...props }: IEditorProps): import("react").JSX.Element;
2
+ export default function Editor(props: IEditorProps): import("react").JSX.Element;
@@ -3,7 +3,7 @@ import { Suspense, lazy } from "react";
3
3
  import { jsx } from "react/jsx-runtime";
4
4
  //#region src/editor/Editor.tsx
5
5
  var MonacoEditor = lazy(() => import("./Monaco.js"));
6
- function Editor({ ...props }) {
6
+ function Editor(props) {
7
7
  return /* @__PURE__ */ jsx(Suspense, {
8
8
  fallback: /* @__PURE__ */ jsx(Loader, { text: "Loading editor..." }),
9
9
  children: /* @__PURE__ */ jsx(MonacoEditor, { ...props })
@@ -5,7 +5,6 @@ export interface IEditorField extends BaseField {
5
5
  default?: string;
6
6
  options?: {
7
7
  language?: string;
8
- theme?: string;
9
8
  };
10
9
  }
11
10
  export default function EditorField(props: FieldComponentProps<IEditorField>): import("react").JSX.Element;
@@ -10,7 +10,8 @@ function hasResetKeys(obj) {
10
10
  }
11
11
  function EditorField(props) {
12
12
  const { field, label, labelPosition, disabled, onChange, tooltipComponent, spaceCompact, setFormDirty } = props;
13
- const [fieldState] = useField(field.name);
13
+ const fieldName = field.name ?? "";
14
+ const [fieldState] = useField(fieldName);
14
15
  const { setFieldValue, setFieldTouched, values } = useFormikContext();
15
16
  const debounceRef = useRef(null);
16
17
  const touchedRef = useRef(false);
@@ -18,9 +19,9 @@ function EditorField(props) {
18
19
  touchedRef.current = true;
19
20
  if (debounceRef.current) clearTimeout(debounceRef.current);
20
21
  debounceRef.current = setTimeout(() => {
21
- if (onChange) onChange(val);
22
- setFieldTouched(field.name, true);
23
- setFieldValue(field.name, val);
22
+ onChange?.(val);
23
+ setFieldTouched(fieldName, true);
24
+ setFieldValue(fieldName, val);
24
25
  setFormDirty(true);
25
26
  }, 500);
26
27
  };
@@ -30,7 +31,6 @@ function EditorField(props) {
30
31
  const randomKey = Math.random().toString(36).substring(7);
31
32
  return editorKeyPostfix || randomKey;
32
33
  }, [editorKeyPostfix]);
33
- const value = fieldState.value;
34
34
  return /* @__PURE__ */ jsx(FieldWrapper, {
35
35
  optional: field.optional,
36
36
  label,
@@ -40,13 +40,13 @@ function EditorField(props) {
40
40
  children: /* @__PURE__ */ jsx(Editor, {
41
41
  ariaLabel: label,
42
42
  height: "200px",
43
- path: field.name,
44
- ...touchedRef.current ? {} : { value },
43
+ path: fieldName,
44
+ ...touchedRef.current ? {} : { value: fieldState.value },
45
45
  className: cx("bg-(--theme-input-bg) w-11 border focus:border rounded text-[10px] leading-4 pl-[6px]", disabled && "opacity-75"),
46
46
  readOnly: disabled,
47
47
  onChange: handleChange,
48
48
  language: field.options?.language || "shell"
49
- }, field.name + postfixKey)
49
+ }, fieldName + postfixKey)
50
50
  });
51
51
  }
52
52
  //#endregion
@@ -9,7 +9,7 @@ import { jsx, jsxs } from "react/jsx-runtime";
9
9
  //#region src/editor/FormCodePanel.tsx
10
10
  var isObject = (value) => typeof value === "object" && value !== null;
11
11
  var shouldIgnoreField = (engine, fieldSchema, inputs, arrayIndex) => {
12
- if (!fieldSchema?.["ignore"] || !fieldSchema?.["hidden"]) return false;
12
+ if (!fieldSchema["ignore"] || !fieldSchema["hidden"]) return false;
13
13
  if (!engine.isReady()) return false;
14
14
  return engine.evaluate({
15
15
  inputs,
@@ -24,35 +24,31 @@ var filterFields = (engine, formJSON, data, prefix, rootData, arrayIndex) => {
24
24
  filtered: Object.keys(data).reduce((acc, key) => {
25
25
  const value = data[key];
26
26
  const fieldSchema = formJSON[key];
27
- if (value !== null && Array.isArray(value)) {
27
+ if (Array.isArray(value)) {
28
28
  const items = [];
29
29
  acc[key] = items;
30
30
  if (!fieldSchema) return acc;
31
31
  const nestedSchema = isObject(fieldSchema) ? fieldSchema["options"] : void 0;
32
- for (let i = 0; i < value.length; i++) {
33
- let filteredFieldsNested = [];
34
- let filteredNested = {};
35
- const item = value[i];
36
- if (isObject(item)) {
37
- const result = filterFields(engine, isObject(nestedSchema) ? nestedSchema : {}, item, key + `[${i}].`, rootData || data, i);
38
- filteredNested = result.filtered;
39
- filteredFieldsNested = result.filteredFields;
40
- } else filteredNested = item;
41
- filteredFields.push(...filteredFieldsNested);
42
- items[i] = filteredNested;
43
- }
32
+ value.forEach((item, i) => {
33
+ if (!isObject(item)) {
34
+ items[i] = item;
35
+ return;
36
+ }
37
+ const result = filterFields(engine, isObject(nestedSchema) ? nestedSchema : {}, item, `${key}[${i}].`, rootData || data, i);
38
+ filteredFields.push(...result.filteredFields);
39
+ items[i] = result.filtered;
40
+ });
44
41
  return acc;
45
42
  }
46
43
  if (fieldSchema && isObject(value)) {
47
- const { filteredFields: filteredFieldsNested, filtered: filteredNested } = filterFields(engine, isObject(fieldSchema) ? fieldSchema : {}, value, key + ".", rootData || data, arrayIndex);
44
+ const { filteredFields: filteredFieldsNested, filtered: filteredNested } = filterFields(engine, isObject(fieldSchema) ? fieldSchema : {}, value, `${key}.`, rootData || data, arrayIndex);
48
45
  filteredFields.push(...filteredFieldsNested);
49
46
  acc[key] = filteredNested;
50
47
  return acc;
51
48
  }
52
49
  if (isObject(fieldSchema) && fieldSchema["sensitive"]) {
53
- const name = prefix ? prefix + key : key;
54
50
  filteredFields.push({
55
- key: name,
51
+ key: `${prefix ?? ""}${key}`,
56
52
  value
57
53
  });
58
54
  return acc;
@@ -155,9 +151,7 @@ function FormCodePanel({ formJSON, data, mutate, height = "600px", disabled = fa
155
151
  const parsed = JSON.parse(e);
156
152
  if (!isObject(parsed)) return;
157
153
  mutate(showHiddenRef.current ? parsed : populateFiltered(filteredFieldsRef.current, parsed));
158
- } catch {
159
- console.log("JSON.parse error in form code editor");
160
- }
154
+ } catch {}
161
155
  },
162
156
  language: "json",
163
157
  disabled
@@ -1,36 +1,13 @@
1
1
  import { useCssIsDark } from "../components/useCssIsDark.js";
2
2
  import { defineEditorThemes, getThemeName } from "./themes.js";
3
3
  import { setupMonacoWorkers } from "./workers.js";
4
- import { onYamlSchemas } from "./yaml.js";
4
+ import { ensureYamlLanguage } from "./yamlLanguage.js";
5
5
  import cx from "classnames";
6
6
  import { useEffect, useLayoutEffect, useRef } from "react";
7
7
  import { jsx } from "react/jsx-runtime";
8
8
  import * as monaco from "monaco-editor";
9
- import { configureMonacoYaml } from "monaco-yaml";
10
9
  //#region src/editor/Monaco.tsx
11
10
  setupMonacoWorkers();
12
- var monacoWithWorkerBridge = {
13
- ...monaco,
14
- editor: {
15
- ...monaco.editor,
16
- createWebWorker: (opts) => "worker" in opts ? monaco.editor.createWebWorker(opts) : monaco.createWebWorker(opts)
17
- }
18
- };
19
- var monacoYamlConfigured = false;
20
- function ensureMonacoYamlConfigured() {
21
- if (monacoYamlConfigured) return;
22
- monacoYamlConfigured = true;
23
- const options = (schemas) => ({
24
- enableSchemaRequest: true,
25
- completion: true,
26
- validate: true,
27
- hover: true,
28
- format: { enable: true },
29
- schemas
30
- });
31
- const monacoYaml = configureMonacoYaml(monacoWithWorkerBridge, options([]));
32
- onYamlSchemas((schemas) => monacoYaml.update(options(schemas)));
33
- }
34
11
  function editorText(value) {
35
12
  return value.replace(/\r/g, "");
36
13
  }
@@ -102,7 +79,7 @@ function MonacoEditor({ className, disabled, onChange = noop, onValidate = noop,
102
79
  model.onDidChangeDecorations(() => {
103
80
  onValidate(monaco.editor.getModelMarkers({ resource: model.uri }));
104
81
  });
105
- ensureMonacoYamlConfigured();
82
+ ensureYamlLanguage();
106
83
  monacoRef.current = editor;
107
84
  }
108
85
  }