@parallelworks/ui 0.16.0 → 0.18.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 (59) hide show
  1. package/LICENSE +202 -21
  2. package/dist/chunks/{CodePreviewEditor-DuMZMA_k.js → CodePreviewEditor-4lx3kE-w.js} +2 -2
  3. package/dist/chunks/{CreateModal-B7smkHkv.js → CreateModal-BY6DLmur.js} +11 -11
  4. package/dist/chunks/{lib-CUTRDpa6.js → FieldWrapper-Bef01EWO.js} +49 -48
  5. package/dist/chunks/{Monaco-BXDH2jVj.js → Monaco-C1POOdVv.js} +485 -172
  6. package/dist/chunks/{PageHeader-CoZWF0pJ.js → PageHeader-l49p1nM9.js} +145 -82
  7. package/dist/chunks/{Provider-CbFVFB7O.js → Provider-Ghua9PkN.js} +34 -6
  8. package/dist/chunks/{StatusBadge-zvEtK16a.js → StatusBadge-C1Blx_cW.js} +23 -6
  9. package/dist/chunks/{SwitchToggle-3V836Cn7.js → SwitchToggle-CHPP8uZQ.js} +17 -14
  10. package/dist/chunks/{Table-CutP1bRt.js → Table-4OHjdKdO.js} +2 -2
  11. package/dist/chunks/{Tooltip-n9w7Tkt1.js → Tooltip-Crxo_eU_.js} +3 -3
  12. package/dist/chunks/{editor-Ko3zX22Y.js → editor-9_uVtUyy.js} +4 -4
  13. package/dist/chunks/{list-CduoUsMW.js → list-qrojZZNv.js} +146 -33
  14. package/dist/components/AddMenu.d.ts +1 -0
  15. package/dist/components/Avatar.d.ts +13 -0
  16. package/dist/components/Button.d.ts +2 -1
  17. package/dist/components/Dropdown.d.ts +2 -0
  18. package/dist/components/Provider.d.ts +59 -2
  19. package/dist/components/SectionHeader.d.ts +3 -1
  20. package/dist/components/StatusBadge.d.ts +7 -2
  21. package/dist/components/relativeTime.d.ts +15 -0
  22. package/dist/editor/index.js +1 -1
  23. package/dist/editor/usesGitlab.d.ts +97 -0
  24. package/dist/file-explorer/index.js +275 -274
  25. package/dist/file-explorer/lib/paging.d.ts +27 -28
  26. package/dist/file-explorer/lib/types.d.ts +0 -1
  27. package/dist/file-explorer/lib/utils.d.ts +16 -5
  28. package/dist/form/FieldWrapper.d.ts +2 -1
  29. package/dist/form/Form.d.ts +3 -1
  30. package/dist/form/index.js +23 -21
  31. package/dist/form/types/fieldComponentTypes.d.ts +1 -0
  32. package/dist/form/types/fieldTypes.d.ts +4 -4
  33. package/dist/form/types/workflow-schema.d.ts +38 -0
  34. package/dist/form/useParsedOpts.d.ts +1 -1
  35. package/dist/icons.d.ts +1 -1
  36. package/dist/icons.js +3 -3
  37. package/dist/index.d.ts +5 -2
  38. package/dist/index.js +49 -18
  39. package/dist/list/ListPage.d.ts +3 -1
  40. package/dist/list/ListPager.d.ts +3 -1
  41. package/dist/list/ListTable.d.ts +2 -1
  42. package/dist/list/RowContextMenu.d.ts +9 -9
  43. package/dist/list/UserHoverCard.d.ts +45 -0
  44. package/dist/list/index.d.ts +2 -1
  45. package/dist/list/index.js +3 -3
  46. package/dist/list/listView.d.ts +1 -1
  47. package/dist/logviewer/index.js +7 -7
  48. package/dist/styles/Geist-Variable.woff2 +0 -0
  49. package/dist/styles/GeistMono-Variable.woff2 +0 -0
  50. package/dist/styles/base.css +57 -0
  51. package/dist/styles/fonts.css +15 -0
  52. package/dist/styles/theme.css +6 -40
  53. package/dist/styles.css +1 -1
  54. package/dist/workflow/DependencyGraph.d.ts +2 -0
  55. package/dist/workflow/index.d.ts +1 -0
  56. package/dist/workflow/index.js +10 -9
  57. package/dist/workflow/types.d.ts +5 -0
  58. package/package.json +12 -11
  59. package/dist/chunks/{BareModal-BqroLbZ5.js → BareModal-BtRiQezg.js} +1 -1
@@ -1,13 +1,65 @@
1
+ import { i as useNotify, l as useSlots, n as useLink, u as useStrings } from "./Provider-Ghua9PkN.js";
1
2
  import { AddIcon, CheckIcon, ChevronRightIcon, ClipboardIcon, CopyIcon, EditIcon, IdCardIcon, KeyIcon, LinkIcon, MailIcon, MoreIcon, UserIcon } from "../icons.js";
2
- import { c as useStrings, i as useNotify, n as useLink, s as useSlots } from "./Provider-CbFVFB7O.js";
3
- import { n as TOOLTIP_ID } from "./Tooltip-n9w7Tkt1.js";
3
+ import { n as TOOLTIP_ID } from "./Tooltip-Crxo_eU_.js";
4
4
  import cx from "classnames";
5
- import { Fragment, jsx, jsxs } from "react/jsx-runtime";
6
- import React, { Fragment as Fragment$1, createContext, useCallback, useContext, useEffect, useLayoutEffect, useRef, useState } from "react";
5
+ import React, { Fragment, createContext, useCallback, useContext, useEffect, useLayoutEffect, useRef, useState } from "react";
6
+ import { Fragment as Fragment$1, jsx, jsxs } from "react/jsx-runtime";
7
7
  import { createPortal } from "react-dom";
8
8
  import { Menu, MenuButton, MenuItem, MenuItems } from "@headlessui/react";
9
+ //#region src/components/Avatar.tsx
10
+ var SIZE_CLASSES = {
11
+ sm: "w-6 h-6 text-xs",
12
+ md: "w-8 h-8 text-sm",
13
+ lg: "w-10 h-10 text-base",
14
+ xl: "w-12 h-12 text-lg",
15
+ "2xl": "w-16 h-16 text-xl"
16
+ };
17
+ var STATUS_CLASSES = {
18
+ online: "bg-green-500",
19
+ offline: "bg-(--theme-muted-text-color)",
20
+ busy: "bg-red-500",
21
+ away: "bg-yellow-500"
22
+ };
23
+ /** Up to two initials: the first and last word of a name split on spaces and dots. */
24
+ function avatarInitials(name) {
25
+ const parts = (name ?? "").split(/[\s.]+/).filter(Boolean);
26
+ if (parts.length >= 2) return (parts[0][0] + parts[parts.length - 1][0]).toUpperCase();
27
+ return parts[0]?.[0]?.toUpperCase() || "?";
28
+ }
29
+ function Avatar({ src, name, size = "md", status, className }) {
30
+ const strings = useStrings();
31
+ const [erroredUrl, setErroredUrl] = useState(null);
32
+ const showImage = !!src && erroredUrl !== src;
33
+ return /* @__PURE__ */ jsxs("div", {
34
+ className: cx("relative inline-flex", className),
35
+ children: [showImage ? /* @__PURE__ */ jsx("img", {
36
+ src,
37
+ alt: name || strings.common.userAvatar,
38
+ onError: () => setErroredUrl(src),
39
+ className: cx("rounded-full object-cover", SIZE_CLASSES[size])
40
+ }) : /* @__PURE__ */ jsx("div", {
41
+ className: cx("rounded-full flex items-center justify-center font-medium", "bg-gradient-to-br from-[var(--gradient-start,var(--theme-element))] to-[var(--gradient-mid,var(--theme-link))] text-white", SIZE_CLASSES[size]),
42
+ children: avatarInitials(name)
43
+ }), status && /* @__PURE__ */ jsx("span", {
44
+ "data-testid": "online-indicator",
45
+ className: cx("absolute bottom-0 right-0 block rounded-full ring-2 ring-(--theme-app-bg)", STATUS_CLASSES[status], size === "sm" ? "w-1.5 h-1.5" : "w-2.5 h-2.5")
46
+ })]
47
+ });
48
+ }
49
+ //#endregion
9
50
  //#region src/components/AddMenu.tsx
10
51
  var addMenuItemClasses = "flex w-full items-center gap-2 px-3 py-1.5 text-[13px] text-(--theme-app) data-[focus]:bg-(--theme-muted-panel-bg) cursor-pointer";
52
+ function itemButtonProps(item) {
53
+ if (!item.disabled) return { onClick: item.onSelect };
54
+ return {
55
+ "aria-disabled": true,
56
+ ...item.hint ? {
57
+ "aria-label": `${item.label}. ${item.hint}`,
58
+ "data-tooltip-id": TOOLTIP_ID,
59
+ "data-tooltip-content": item.hint
60
+ } : {}
61
+ };
62
+ }
11
63
  function AddMenu({ items, label, buttonClassName, zClassName = "z-50", children }) {
12
64
  const Link = useLink();
13
65
  return /* @__PURE__ */ jsxs(Menu, { children: [/* @__PURE__ */ jsx(MenuButton, {
@@ -18,17 +70,19 @@ function AddMenu({ items, label, buttonClassName, zClassName = "z-50", children
18
70
  }), /* @__PURE__ */ jsx(MenuItems, {
19
71
  anchor: "bottom start",
20
72
  className: cx("mt-1 min-w-52 rounded-lg border border-(--theme-border) bg-(--theme-app-bg) py-1 shadow-lg focus:outline-none", zClassName),
21
- children: items.map((item) => /* @__PURE__ */ jsxs(Fragment$1, { children: [item.separatorAbove && /* @__PURE__ */ jsx("div", { className: "my-1 border-t border-(--theme-border)" }), /* @__PURE__ */ jsx(MenuItem, { children: item.to && !item.disabled ? /* @__PURE__ */ jsxs(Link, {
22
- to: item.to,
23
- className: addMenuItemClasses,
24
- children: [item.icon, item.label]
25
- }) : /* @__PURE__ */ jsxs("button", {
26
- type: "button",
27
- onClick: item.onSelect,
28
- disabled: item.disabled,
29
- className: cx(addMenuItemClasses, item.disabled && "opacity-50 cursor-not-allowed"),
30
- children: [item.icon, item.label]
31
- }) })] }, item.label))
73
+ children: items.map((item) => /* @__PURE__ */ jsxs(Fragment, { children: [item.separatorAbove && /* @__PURE__ */ jsx("div", { className: "my-1 border-t border-(--theme-border)" }), /* @__PURE__ */ jsx(MenuItem, {
74
+ disabled: item.disabled ?? false,
75
+ children: item.to && !item.disabled ? /* @__PURE__ */ jsxs(Link, {
76
+ to: item.to,
77
+ className: addMenuItemClasses,
78
+ children: [item.icon, item.label]
79
+ }) : /* @__PURE__ */ jsxs("button", {
80
+ type: "button",
81
+ ...itemButtonProps(item),
82
+ className: cx(addMenuItemClasses, item.disabled && "opacity-50 cursor-not-allowed"),
83
+ children: [item.icon, item.label]
84
+ })
85
+ })] }, item.label))
32
86
  })] });
33
87
  }
34
88
  //#endregion
@@ -338,12 +392,21 @@ function MenuRow({ item, onClose, side }) {
338
392
  })]
339
393
  });
340
394
  }
341
- if (item.kind === "link") return /* @__PURE__ */ jsxs(Link, {
342
- to: item.to,
343
- onClick: onClose,
344
- className: cx(MENU_ITEM_CLASSES, item.destructive ? "text-red-500" : "text-(--theme-app)"),
345
- children: [item.icon, item.label]
346
- });
395
+ if (item.kind === "link") {
396
+ const className = cx(MENU_ITEM_CLASSES, item.destructive ? "text-red-500" : "text-(--theme-app)");
397
+ if (item.reloadDocument) return /* @__PURE__ */ jsxs("a", {
398
+ href: item.to,
399
+ onClick: onClose,
400
+ className,
401
+ children: [item.icon, item.label]
402
+ });
403
+ return /* @__PURE__ */ jsxs(Link, {
404
+ to: item.to,
405
+ onClick: onClose,
406
+ className,
407
+ children: [item.icon, item.label]
408
+ });
409
+ }
347
410
  return /* @__PURE__ */ jsxs("button", {
348
411
  type: "button",
349
412
  disabled: item.disabled && !item.tooltip,
@@ -369,62 +432,62 @@ function MenuRow({ item, onClose, side }) {
369
432
  ]
370
433
  });
371
434
  }
372
- /** Builds the Copy submenu entries for whichever fields a row has, in stable
373
- * order. The menu itself performs the copy and notifies; `t` is an optional
374
- * host translator for the field labels (falls back to the provider defaults'
375
- * English). */
376
- function copySubmenu({ name, nameLabel, email, username, uid, id, url, extra, t }) {
377
- const items = [
378
- {
379
- label: nameLabel ?? (t ? t("rowContextMenu.labelName") : "name"),
380
- value: name,
381
- icon: /* @__PURE__ */ jsx(CopyIcon, {})
382
- },
383
- {
384
- label: t ? t("rowContextMenu.labelEmail") : "email",
385
- value: email,
386
- icon: /* @__PURE__ */ jsx(MailIcon, {})
387
- },
388
- {
389
- label: t ? t("rowContextMenu.labelUsername") : "username",
390
- value: username,
391
- icon: /* @__PURE__ */ jsx(UserIcon, {})
392
- },
393
- {
394
- label: t ? t("rowContextMenu.labelUid") : "UID",
395
- value: uid === null || uid === void 0 ? null : String(uid),
396
- icon: /* @__PURE__ */ jsx(KeyIcon, {})
397
- },
398
- {
399
- label: t ? t("rowContextMenu.labelId") : "ID",
400
- value: id,
401
- icon: /* @__PURE__ */ jsx(IdCardIcon, {})
402
- },
403
- {
404
- label: t ? t("rowContextMenu.labelUrl") : "URL",
405
- value: url,
406
- icon: /* @__PURE__ */ jsx(LinkIcon, {})
407
- },
408
- ...(extra ?? []).map((e) => ({
409
- label: e.label,
410
- value: e.value,
411
- icon: e.icon ?? /* @__PURE__ */ jsx(CopyIcon, {})
412
- }))
413
- ].filter((f) => f.value).map((f) => ({
414
- kind: "action",
415
- label: t ? t("rowContextMenu.copy", { label: f.label }) : `Copy ${f.label}`,
416
- icon: f.icon,
417
- copy: {
418
- text: f.value,
419
- label: f.label
420
- }
421
- }));
422
- return {
423
- kind: "submenu",
424
- label: t ? t("common.copy") : "Copy",
425
- icon: /* @__PURE__ */ jsx(ClipboardIcon, {}),
426
- items
427
- };
435
+ /** Returns a builder for the Copy submenu, labeled from the provider's strings. */
436
+ function useCopySubmenu() {
437
+ const { list: t } = useStrings();
438
+ return useCallback(({ name, nameLabel, email, username, uid, id, url, extra }) => {
439
+ const items = [
440
+ {
441
+ label: nameLabel ?? t.labelName,
442
+ value: name,
443
+ icon: /* @__PURE__ */ jsx(CopyIcon, {})
444
+ },
445
+ {
446
+ label: t.labelEmail,
447
+ value: email,
448
+ icon: /* @__PURE__ */ jsx(MailIcon, {})
449
+ },
450
+ {
451
+ label: t.labelUsername,
452
+ value: username,
453
+ icon: /* @__PURE__ */ jsx(UserIcon, {})
454
+ },
455
+ {
456
+ label: t.labelUid,
457
+ value: uid === null || uid === void 0 ? null : String(uid),
458
+ icon: /* @__PURE__ */ jsx(KeyIcon, {})
459
+ },
460
+ {
461
+ label: t.labelId,
462
+ value: id,
463
+ icon: /* @__PURE__ */ jsx(IdCardIcon, {})
464
+ },
465
+ {
466
+ label: t.labelUrl,
467
+ value: url,
468
+ icon: /* @__PURE__ */ jsx(LinkIcon, {})
469
+ },
470
+ ...(extra ?? []).map((e) => ({
471
+ label: e.label,
472
+ value: e.value,
473
+ icon: e.icon ?? /* @__PURE__ */ jsx(CopyIcon, {})
474
+ }))
475
+ ].filter((f) => f.value).map((f) => ({
476
+ kind: "action",
477
+ label: t.copy(f.label),
478
+ icon: f.icon,
479
+ copy: {
480
+ text: f.value,
481
+ label: f.label
482
+ }
483
+ }));
484
+ return {
485
+ kind: "submenu",
486
+ label: t.copyMenu,
487
+ icon: /* @__PURE__ */ jsx(ClipboardIcon, {}),
488
+ items
489
+ };
490
+ }, [t]);
428
491
  }
429
492
  /** Stays visible while active (menu open) so it doesn't vanish behind the overlay. */
430
493
  function MoreButton({ onOpen, active, className }) {
@@ -451,7 +514,7 @@ var headerAddButtonClasses = "inline-flex h-[26px] shrink-0 items-center gap-1.5
451
514
  function HeaderAddButton({ to, onClick, label, word = "add", menu, disabled = false, disabledHint }) {
452
515
  const { common } = useStrings();
453
516
  const Link = useLink();
454
- const content = /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsx(AddIcon, { className: "w-3 h-3" }), /* @__PURE__ */ jsx("span", { children: word === "create" ? common.create : common.add })] });
517
+ const content = /* @__PURE__ */ jsxs(Fragment$1, { children: [/* @__PURE__ */ jsx(AddIcon, { className: "w-3 h-3" }), /* @__PURE__ */ jsx("span", { children: word === "create" ? common.create : common.add })] });
455
518
  if (menu) return /* @__PURE__ */ jsx(AddMenu, {
456
519
  items: menu,
457
520
  label,
@@ -493,7 +556,7 @@ function HeaderActionMenu({ items, label = "Actions" }) {
493
556
  function HeaderRowMenu({ items, label = "Actions" }) {
494
557
  const { openMenu, contextMenu } = useRowMenu();
495
558
  if (items.length === 0) return null;
496
- return /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsx("button", {
559
+ return /* @__PURE__ */ jsxs(Fragment$1, { children: [/* @__PURE__ */ jsx("button", {
497
560
  type: "button",
498
561
  "aria-label": label,
499
562
  title: label,
@@ -548,7 +611,7 @@ function BreadcrumbsActionButton({ icon: Icon, label, ariaLabel, to, onClick, di
548
611
  "data-tooltip-id": TOOLTIP_ID,
549
612
  "data-tooltip-content": tooltip
550
613
  } : {};
551
- const content = /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsx(Icon, { className: "w-3 h-3" }), label] });
614
+ const content = /* @__PURE__ */ jsxs(Fragment$1, { children: [/* @__PURE__ */ jsx(Icon, { className: "w-3 h-3" }), label] });
552
615
  if (to && !disabled) return /* @__PURE__ */ jsx(Link, {
553
616
  to,
554
617
  className: breadcrumbsActionClasses,
@@ -588,7 +651,7 @@ function PageHeader({ breadcrumbs, title, titleAction, actions, toolbar, classNa
588
651
  className: "m-0 text-[13px] font-medium leading-none text-(--theme-app) truncate",
589
652
  children: crumb.label
590
653
  }, `${crumb.label}-${idx}`);
591
- return /* @__PURE__ */ jsxs(Fragment$1, { children: [crumb.href ? /* @__PURE__ */ jsx(Link, {
654
+ return /* @__PURE__ */ jsxs(Fragment, { children: [crumb.href ? /* @__PURE__ */ jsx(Link, {
592
655
  to: crumb.href,
593
656
  className: "text-(--theme-muted-text-color) hover:text-(--theme-app) transition-colors cursor-pointer whitespace-nowrap",
594
657
  children: crumb.label
@@ -624,4 +687,4 @@ function PageHeader({ breadcrumbs, title, titleAction, actions, toolbar, classNa
624
687
  });
625
688
  }
626
689
  //#endregion
627
- export { useSetDefaultBreadcrumbs as C, useSetBreadcrumbs as S, useRowMenuActive as _, HeaderAddButton as a, useClearBreadcrumbs as b, PageHeader as c, assembleRowMenu as d, copySubmenu as f, useRowMenu as g, toolbarActionToRowAction as h, HeaderActionMenu as i, headerActionButtonClasses as l, toRowMenuItem as m, BreadcrumbsRightAction as n, HeaderEditButton as o, rowContextMenuProps as p, BreadcrumbsTitleAction as r, HeaderRowMenu as s, BreadcrumbsActionButton as t, MoreButton as u, BreadcrumbProvider as v, AddMenu as w, useHideBreadcrumbs as x, useBreadcrumb as y };
690
+ export { useSetDefaultBreadcrumbs as C, avatarInitials as E, useSetBreadcrumbs as S, Avatar as T, useRowMenuActive as _, HeaderAddButton as a, useClearBreadcrumbs as b, PageHeader as c, assembleRowMenu as d, rowContextMenuProps as f, useRowMenu as g, useCopySubmenu as h, HeaderActionMenu as i, headerActionButtonClasses as l, toolbarActionToRowAction as m, BreadcrumbsRightAction as n, HeaderEditButton as o, toRowMenuItem as p, BreadcrumbsTitleAction as r, HeaderRowMenu as s, BreadcrumbsActionButton as t, MoreButton as u, BreadcrumbProvider as v, AddMenu as w, useHideBreadcrumbs as x, useBreadcrumb as y };
@@ -1,5 +1,6 @@
1
- import { Fragment, jsx, jsxs } from "react/jsx-runtime";
2
1
  import { createContext, useContext, useMemo } from "react";
2
+ import { useLocalStorage } from "usehooks-ts";
3
+ import { Fragment as Fragment$1, jsx, jsxs } from "react/jsx-runtime";
3
4
  //#region src/components/Provider.tsx
4
5
  var DefaultLink = ({ to, onClick, className, children, ...rest }) => /* @__PURE__ */ jsx("a", {
5
6
  href: to,
@@ -17,6 +18,10 @@ var defaultUseRunFile = () => ({
17
18
  isLoading: false,
18
19
  error: void 0
19
20
  });
21
+ function useLocalStoragePersistedState(key, defaultValue) {
22
+ const [value, setValue] = useLocalStorage(key, defaultValue);
23
+ return [value, setValue];
24
+ }
20
25
  var DEFAULTS = {
21
26
  notify: {
22
27
  info: () => {},
@@ -53,7 +58,8 @@ var DEFAULTS = {
53
58
  showHiddenFieldsHint: "Includes fields hidden by default because they're specific to each resource, such as name and group.",
54
59
  jsonHasErrors: "JSON has errors, please fix before saving",
55
60
  remove: "Remove",
56
- sort: "Sort"
61
+ sort: "Sort",
62
+ userAvatar: "User avatar"
57
63
  },
58
64
  dropdown: {
59
65
  select: (type) => `Select ${type}`,
@@ -319,7 +325,15 @@ var DEFAULTS = {
319
325
  readOnlyDescription: "Read-only mounts can list and download objects, but cannot upload, modify, or delete them.",
320
326
  readOnlyForced: "Your access to this bucket is read-only, so this mount cannot be writable."
321
327
  },
328
+ time: {
329
+ now: "now",
330
+ minutes: (n) => `${n}m`,
331
+ hours: (n) => `${n}h`,
332
+ days: (n) => `${n}d`,
333
+ years: (n) => `${n}y`
334
+ },
322
335
  list: {
336
+ copyMenu: "Copy",
323
337
  copy: (label) => `Copy ${label}`,
324
338
  copied: (label) => `Copied ${label}`,
325
339
  couldntCopy: (label) => `Couldn't copy ${label}`,
@@ -355,7 +369,7 @@ var DEFAULTS = {
355
369
  perPage: "Per page",
356
370
  paginationPrevious: "Previous",
357
371
  paginationNext: "Next",
358
- paginationShowing: (name, start, end) => /* @__PURE__ */ jsxs(Fragment, { children: [
372
+ paginationShowing: (name, start, end) => /* @__PURE__ */ jsxs(Fragment$1, { children: [
359
373
  "Showing ",
360
374
  name,
361
375
  " ",
@@ -370,7 +384,7 @@ var DEFAULTS = {
370
384
  children: end
371
385
  })
372
386
  ] }),
373
- paginationShowingTimeRange: (name, startTime, endTime) => /* @__PURE__ */ jsxs(Fragment, { children: [
387
+ paginationShowingTimeRange: (name, startTime, endTime) => /* @__PURE__ */ jsxs(Fragment$1, { children: [
374
388
  "Showing ",
375
389
  name,
376
390
  " from ",
@@ -393,7 +407,10 @@ var DEFAULTS = {
393
407
  toMarketItem: () => {},
394
408
  openExternal: (href) => window.open(href, "_blank")
395
409
  },
396
- data: { useRunFile: defaultUseRunFile },
410
+ data: {
411
+ useRunFile: defaultUseRunFile,
412
+ usePersistedState: useLocalStoragePersistedState
413
+ },
397
414
  slots: {}
398
415
  };
399
416
  var UIContext = createContext(DEFAULTS);
@@ -415,10 +432,17 @@ function useWorkflowJsonResolver() {
415
432
  function useProvisionCorsRules() {
416
433
  return useContext(UIContext).data.provisionCorsRules;
417
434
  }
435
+ function useRepoSuggestions() {
436
+ return useContext(UIContext).data.repoSuggestions;
437
+ }
418
438
  function useRunFile(slug, path, options) {
419
439
  const { useRunFile: boundUseRunFile } = useContext(UIContext).data;
420
440
  return boundUseRunFile(slug, path, options);
421
441
  }
442
+ function usePersistedState(key, defaultValue) {
443
+ const { usePersistedState: boundUsePersistedState } = useContext(UIContext).data;
444
+ return boundUsePersistedState(key, defaultValue);
445
+ }
422
446
  function UIProvider({ notify, strings, navigation, data, slots, children }) {
423
447
  const value = useMemo(() => ({
424
448
  notify: {
@@ -459,6 +483,10 @@ function UIProvider({ notify, strings, navigation, data, slots, children }) {
459
483
  ...DEFAULTS.strings.form,
460
484
  ...strings?.form
461
485
  },
486
+ time: {
487
+ ...DEFAULTS.strings.time,
488
+ ...strings?.time
489
+ },
462
490
  list: {
463
491
  ...DEFAULTS.strings.list,
464
492
  ...strings?.list
@@ -486,4 +514,4 @@ function UIProvider({ notify, strings, navigation, data, slots, children }) {
486
514
  });
487
515
  }
488
516
  //#endregion
489
- export { useProvisionCorsRules as a, useStrings as c, useNotify as i, useWorkflowJsonResolver as l, useLink as n, useRunFile as o, useNavigation as r, useSlots as s, UIProvider as t };
517
+ export { usePersistedState as a, useRunFile as c, useWorkflowJsonResolver as d, useNotify as i, useSlots as l, useLink as n, useProvisionCorsRules as o, useNavigation as r, useRepoSuggestions as s, UIProvider as t, useStrings as u };
@@ -115,13 +115,30 @@ var pulseColors = {
115
115
  info: "bg-blue-500",
116
116
  muted: "bg-(--theme-muted-text-color)"
117
117
  };
118
- function StatusBadge({ children, variant = "default", pulse = false, size = "sm", className }) {
118
+ var textColors = {
119
+ default: "text-(--theme-app)",
120
+ success: "text-emerald-600 dark:text-emerald-400",
121
+ warning: "text-amber-600 dark:text-amber-400",
122
+ error: "text-red-600 dark:text-red-400",
123
+ info: "text-blue-600 dark:text-blue-400",
124
+ muted: "text-(--theme-muted-text-color)"
125
+ };
126
+ /** A line of text in a variant's colour, for a status that stands beside a
127
+ * dot rather than inside a badge. */
128
+ function statusTextClass(variant) {
129
+ return textColors[variant];
130
+ }
131
+ function StatusBadge({ children, variant = "default", pulse = false, dot = false, size = "sm", className }) {
119
132
  return /* @__PURE__ */ jsxs("span", {
120
133
  className: cx("inline-flex items-center gap-1.5 rounded-full border font-medium", size === "sm" && "px-2 py-0.5 text-[10px]", size === "md" && "px-2.5 py-1 text-xs", variantStyles[variant], className),
121
- children: [pulse && /* @__PURE__ */ jsxs("span", {
122
- className: "relative flex h-2 w-2",
123
- children: [/* @__PURE__ */ jsx("span", { className: cx("absolute inline-flex h-full w-full animate-ping rounded-full opacity-75", pulseColors[variant]) }), /* @__PURE__ */ jsx("span", { className: cx("relative inline-flex h-2 w-2 rounded-full", pulseColors[variant]) })]
124
- }), children]
134
+ children: [
135
+ pulse && /* @__PURE__ */ jsxs("span", {
136
+ className: "relative flex h-2 w-2",
137
+ children: [/* @__PURE__ */ jsx("span", { className: cx("absolute inline-flex h-full w-full animate-ping rounded-full opacity-75", pulseColors[variant]) }), /* @__PURE__ */ jsx("span", { className: cx("relative inline-flex h-2 w-2 rounded-full", pulseColors[variant]) })]
138
+ }),
139
+ dot && !pulse && /* @__PURE__ */ jsx("span", { className: cx("inline-flex h-1.5 w-1.5 rounded-full", pulseColors[variant]) }),
140
+ children
141
+ ]
125
142
  });
126
143
  }
127
144
  function StatusDot({ variant = "default", pulse = false, size = 8, className }) {
@@ -141,4 +158,4 @@ function StatusDot({ variant = "default", pulse = false, size = 8, className })
141
158
  });
142
159
  }
143
160
  //#endregion
144
- export { flattenDisplayOptions as a, isOption as c, filterOption as i, toggleSetMember as l, StatusDot as n, flattenOptions as o, DropdownCaret as r, isCategory as s, StatusBadge as t };
161
+ export { filterOption as a, isCategory as c, DropdownCaret as i, isOption as l, StatusDot as n, flattenDisplayOptions as o, statusTextClass as r, flattenOptions as s, StatusBadge as t, toggleSetMember as u };
@@ -1,10 +1,10 @@
1
+ import { u as useStrings } from "./Provider-Ghua9PkN.js";
1
2
  import { AngleDownIcon, AngleRightIcon, CaretDownIcon } from "../icons.js";
2
- import { c as useStrings } from "./Provider-CbFVFB7O.js";
3
- import { a as truncationTooltipProps, n as TOOLTIP_ID } from "./Tooltip-n9w7Tkt1.js";
4
- import { a as flattenDisplayOptions, c as isOption, i as filterOption, l as toggleSetMember, o as flattenOptions, r as DropdownCaret, s as isCategory } from "./StatusBadge-zvEtK16a.js";
3
+ import { a as truncationTooltipProps, n as TOOLTIP_ID } from "./Tooltip-Crxo_eU_.js";
4
+ import { a as filterOption, c as isCategory, i as DropdownCaret, l as isOption, o as flattenDisplayOptions, s as flattenOptions, u as toggleSetMember } from "./StatusBadge-C1Blx_cW.js";
5
5
  import cx from "classnames";
6
- import { Fragment, jsx, jsxs } from "react/jsx-runtime";
7
6
  import React, { useCallback, useEffect, useMemo, useRef, useState } from "react";
7
+ import { Fragment as Fragment$1, jsx, jsxs } from "react/jsx-runtime";
8
8
  import { createPortal } from "react-dom";
9
9
  import { Combobox, ComboboxButton, ComboboxInput, ComboboxOption, ComboboxOptions, Listbox, ListboxButton, ListboxOption, ListboxOptions, Switch, Transition } from "@headlessui/react";
10
10
  import deepEqual from "fast-deep-equal";
@@ -131,7 +131,7 @@ function ToggleOption({ option, category, expanded, onToggle, ...virtualRowProps
131
131
  })
132
132
  });
133
133
  }
134
- function DropdownHelper({ wrapperClassName = "w-full", className, textBoxClassName = "w-full", options = [], onChange, onActiveChange, value, id, ariaLabel, "aria-describedby": describedBy, required, disabled = false, placeholder = "", loading = false, allowCustomValue = false, customValueLabel = "Use", collapsedLabel = defaultCollapsedLabel, portalEl }) {
134
+ function DropdownHelper({ wrapperClassName = "w-full", className, textBoxClassName = "w-full", options = [], onChange, onActiveChange, value, id, ariaLabel, "aria-describedby": describedBy, required, disabled = false, placeholder = "", loading = false, allowCustomValue = false, customValueLabel = "Use", collapsedLabel = defaultCollapsedLabel, portalEl, compact = false }) {
135
135
  const DEBOUNCE_MS = 500;
136
136
  const t = useStrings().dropdown;
137
137
  const [query, setQuery] = useState("");
@@ -253,10 +253,11 @@ function DropdownHelper({ wrapperClassName = "w-full", className, textBoxClassNa
253
253
  allowCustomValue,
254
254
  customValueLabel
255
255
  ]);
256
- const comboOptions = /* @__PURE__ */ jsx(Fragment, { children: /* @__PURE__ */ jsx(ComboboxOptions, {
256
+ const comboOptions = /* @__PURE__ */ jsx(Fragment$1, { children: /* @__PURE__ */ jsx(ComboboxOptions, {
257
+ modal: false,
257
258
  ref: setPopperElement,
258
259
  style: styles["popper"],
259
- className: "bg-(--theme-input-bg) border-(--theme-border) text-(--theme-app) max-h-60! empty:invisible border overflow-auto rounded-md shadow-lg focus:outline-hidden sm:text-sm z-9999 data-[popper-reference-hidden=true]:invisible data-[popper-reference-hidden=true]:pointer-events-none",
260
+ className: cx("bg-(--theme-input-bg) border-(--theme-border) text-(--theme-app) max-h-60! empty:invisible border overflow-auto rounded-md shadow-lg focus:outline-hidden z-9999 data-[popper-reference-hidden=true]:invisible data-[popper-reference-hidden=true]:pointer-events-none", compact ? "text-xs" : "sm:text-sm"),
260
261
  ...attributes["popper"],
261
262
  children: ({ option }) => {
262
263
  const optionLabel = typeof option === "string" ? option : option.label;
@@ -273,7 +274,7 @@ function DropdownHelper({ wrapperClassName = "w-full", className, textBoxClassNa
273
274
  return /* @__PURE__ */ jsx(ComboboxOption, {
274
275
  "data-testid": "combobox-option",
275
276
  value: option,
276
- className: cx("w-full group relative flex", optionDescription ? "min-h-10 py-2" : "h-10", isCategoryRow ? "text-[14px] font-bold pl-1 items-center" : "data-disabled:text-(--theme-muted-text-color) data-disabled:bg-(--theme-muted-panel-bg) data-disabled:cursor-not-allowed cursor-pointer items-center pr-9 pl-3 leading-5 data-focus:bg-(--theme-muted-panel-bg) data-focus:text-(--theme-app) data-focus:outline-hidden", "data-selected:border-l-2 data-selected:border-(--theme-link) data-selected:bg-(--theme-muted-panel-bg) data-selected:text-(--theme-app)", isPinned && "border-t border-(--theme-border) font-medium"),
277
+ className: cx("w-full group relative flex", optionDescription ? "min-h-10 py-2" : compact ? "h-8" : "h-10", isCategoryRow ? "text-[14px] font-bold pl-1 items-center" : "data-disabled:text-(--theme-muted-text-color) data-disabled:bg-(--theme-muted-panel-bg) data-disabled:cursor-not-allowed cursor-pointer items-center pr-9 pl-3 leading-5 data-focus:bg-(--theme-muted-panel-bg) data-focus:text-(--theme-app) data-focus:outline-hidden", "data-selected:border-l-2 data-selected:border-(--theme-link) data-selected:bg-(--theme-muted-panel-bg) data-selected:text-(--theme-app)", isPinned && "border-t border-(--theme-border) font-medium"),
277
278
  children: /* @__PURE__ */ jsx(OptionContent, {
278
279
  label: optionLabel,
279
280
  description: optionDescription,
@@ -301,7 +302,7 @@ function DropdownHelper({ wrapperClassName = "w-full", className, textBoxClassNa
301
302
  disabled: (option) => Boolean(option.disabled)
302
303
  },
303
304
  disabled,
304
- children: ({ activeOption, open }) => /* @__PURE__ */ jsxs(Fragment, { children: [
305
+ children: ({ activeOption, open }) => /* @__PURE__ */ jsxs(Fragment$1, { children: [
305
306
  onActiveChange && /* @__PURE__ */ jsx(ActiveWatcher, {
306
307
  active: activeOption,
307
308
  onChange: onActiveChange
@@ -368,6 +369,7 @@ function CustomListbox({ options = [], handleOptionSelected, type, allowSearch =
368
369
  const wrapperRef = useRef(null);
369
370
  useOutsideAlerter(wrapperRef);
370
371
  const optionsElement = /* @__PURE__ */ jsxs(ListboxOptions, {
372
+ modal: false,
371
373
  static: true,
372
374
  className: "absolute w-full py-1 z-50 theme-input rounded-md",
373
375
  children: [allowSearch && /* @__PURE__ */ jsx("div", {
@@ -454,7 +456,7 @@ function CustomListbox({ options = [], handleOptionSelected, type, allowSearch =
454
456
  leaveFrom: "opacity-100",
455
457
  leaveTo: "opacity-0",
456
458
  children: optionsElement || null
457
- }) : /* @__PURE__ */ jsx(Fragment, { children: controlledOpen && optionsElement })]
459
+ }) : /* @__PURE__ */ jsx(Fragment$1, { children: controlledOpen && optionsElement })]
458
460
  });
459
461
  }
460
462
  //#endregion
@@ -532,7 +534,7 @@ function MultiSelectDropdown({ options, value, onChange, id, "aria-labelledby":
532
534
  children: loading ? /* @__PURE__ */ jsx("span", {
533
535
  className: "theme-muted-text",
534
536
  children: strings.loading
535
- }) : selectedOptions.length > 0 ? /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsx("span", {
537
+ }) : selectedOptions.length > 0 ? /* @__PURE__ */ jsxs(Fragment$1, { children: [/* @__PURE__ */ jsx("span", {
536
538
  className: "min-w-0 truncate",
537
539
  children: display.label
538
540
  }), display.overflow > 0 && /* @__PURE__ */ jsxs("span", {
@@ -545,6 +547,7 @@ function MultiSelectDropdown({ options, value, onChange, id, "aria-labelledby":
545
547
  }),
546
548
  /* @__PURE__ */ jsx(DropdownCaret, {}),
547
549
  open && /* @__PURE__ */ jsxs(ComboboxOptions, {
550
+ modal: false,
548
551
  ref: setPopperEl,
549
552
  static: true,
550
553
  "data-testid": "msd-list",
@@ -627,7 +630,7 @@ function ControlledCollapsiblePanel({ title = "", children, open, setOpen, onCli
627
630
  }, [setOpen, onClick]);
628
631
  const contentId = React.useId();
629
632
  const Wrapper = wrapperElement ? wrapperElement : React.Fragment;
630
- return React.isValidElement(title) ? /* @__PURE__ */ jsxs(Fragment, { children: [title, /* @__PURE__ */ jsx(Wrapper, { children: /* @__PURE__ */ jsx(AnimateHeight, {
633
+ return React.isValidElement(title) ? /* @__PURE__ */ jsxs(Fragment$1, { children: [title, /* @__PURE__ */ jsx(Wrapper, { children: /* @__PURE__ */ jsx(AnimateHeight, {
631
634
  duration: 300,
632
635
  height: open ? "auto" : 0,
633
636
  children
@@ -689,9 +692,9 @@ function MaybeCollapsible({ className, initialState, children, title, customized
689
692
  }
690
693
  //#endregion
691
694
  //#region src/components/SectionHeader.tsx
692
- function SectionHeader({ children, className = "" }) {
695
+ function SectionHeader({ children, className = "", size = "md" }) {
693
696
  return /* @__PURE__ */ jsx("div", {
694
- className: cx("w-full text-lg font-semibold", className),
697
+ className: cx("w-full font-semibold", size === "sm" ? "mb-2 text-sm theme-text" : "text-lg", className),
695
698
  children
696
699
  });
697
700
  }
@@ -1,8 +1,8 @@
1
- import { c as useStrings } from "./Provider-CbFVFB7O.js";
1
+ import { u as useStrings } from "./Provider-Ghua9PkN.js";
2
2
  import { t as Loader } from "./Loader-BXoXTZGc.js";
3
3
  import cx from "classnames";
4
- import { jsx, jsxs } from "react/jsx-runtime";
5
4
  import React from "react";
5
+ import { jsx, jsxs } from "react/jsx-runtime";
6
6
  //#region src/components/Table.tsx
7
7
  function Item({ wrap = false, children, className, colspan = 1, ...tdProps }) {
8
8
  const yPadding = className?.includes("py-") ? "" : "py-4";
@@ -1,6 +1,6 @@
1
1
  import { TooltipIcon } from "../icons.js";
2
+ import { Fragment } from "react";
2
3
  import { jsx, jsxs } from "react/jsx-runtime";
3
- import { Fragment as Fragment$1 } from "react";
4
4
  import { Tooltip } from "react-tooltip";
5
5
  //#region src/components/Tooltip.tsx
6
6
  var TOOLTIP_ID = "global-tooltip";
@@ -39,12 +39,12 @@ function formatLine(line) {
39
39
  function formatTooltipContent(content) {
40
40
  if (typeof content !== "string") return content || null;
41
41
  if (!content) return null;
42
- return content.split(/<br\s*\/?>|\n/i).map((line, idx) => /* @__PURE__ */ jsxs(Fragment$1, { children: [idx > 0 && /* @__PURE__ */ jsx("br", {}), formatLine(line)] }, idx));
42
+ return content.split(/<br\s*\/?>|\n/i).map((line, idx) => /* @__PURE__ */ jsxs(Fragment, { children: [idx > 0 && /* @__PURE__ */ jsx("br", {}), formatLine(line)] }, idx));
43
43
  }
44
44
  function KbdShortcut({ keys }) {
45
45
  return /* @__PURE__ */ jsx("span", {
46
46
  className: "inline-flex items-center gap-1 align-middle",
47
- children: keys.split("+").map((part) => part.trim()).filter(Boolean).map((part, idx) => /* @__PURE__ */ jsxs(Fragment$1, { children: [idx > 0 && /* @__PURE__ */ jsx("span", {
47
+ children: keys.split("+").map((part) => part.trim()).filter(Boolean).map((part, idx) => /* @__PURE__ */ jsxs(Fragment, { children: [idx > 0 && /* @__PURE__ */ jsx("span", {
48
48
  className: "opacity-60 text-[11px]",
49
49
  children: "+"
50
50
  }), /* @__PURE__ */ jsx("kbd", {
@@ -1,15 +1,15 @@
1
+ import { i as useNotify, u as useStrings } from "./Provider-Ghua9PkN.js";
1
2
  import { CheckIcon, CopyIcon, EyeIcon, EyeOffIcon } from "../icons.js";
2
- import { c as useStrings, i as useNotify } from "./Provider-CbFVFB7O.js";
3
3
  import { t as Loader } from "./Loader-BXoXTZGc.js";
4
4
  import { t as SwitchToggleSmall } from "./SwitchToggleSmall-FcsaYSTs.js";
5
- import { c as FieldWrapper, n as flattenGroups, r as impureSetValueFromPath } from "./lib-CUTRDpa6.js";
5
+ import { i as impureSetValueFromPath, r as flattenGroups, t as FieldWrapper } from "./FieldWrapper-Bef01EWO.js";
6
6
  import cx from "classnames";
7
- import { jsx, jsxs } from "react/jsx-runtime";
8
7
  import { Suspense, lazy, useId, useMemo, useRef, useState } from "react";
8
+ import { jsx, jsxs } from "react/jsx-runtime";
9
9
  import { convertToDynamicForm, parseStringsOfObj, parseStringsOfObjReady } from "@parallelworks/workflow-parser";
10
10
  import { useField, useFormikContext } from "formik";
11
11
  //#region src/editor/Editor.tsx
12
- var MonacoEditor = lazy(() => import("./Monaco-BXDH2jVj.js"));
12
+ var MonacoEditor = lazy(() => import("./Monaco-C1POOdVv.js"));
13
13
  function Editor({ ...props }) {
14
14
  return /* @__PURE__ */ jsx(Suspense, {
15
15
  fallback: /* @__PURE__ */ jsx(Loader, { text: "Loading editor..." }),