@parallelworks/ui 0.18.0 → 0.19.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (161) hide show
  1. package/README.md +86 -6
  2. package/dist/ai/adapter/memoryStore.d.ts +8 -0
  3. package/dist/ai/adapter/mock/index.d.ts +2 -0
  4. package/dist/ai/adapter/mock/index.js +81 -0
  5. package/dist/ai/adapter/mock/mockAdapter.d.ts +4 -0
  6. package/dist/ai/adapter/openai/createOpenAIStream.d.ts +9 -0
  7. package/dist/ai/adapter/openai/errors.d.ts +3 -0
  8. package/dist/ai/adapter/openai/index.d.ts +6 -0
  9. package/dist/ai/adapter/openai/index.js +334 -0
  10. package/dist/ai/adapter/openai/openaiAdapter.d.ts +9 -0
  11. package/dist/ai/adapter/openai/responses.d.ts +4 -0
  12. package/dist/ai/adapter/openai/sse.d.ts +24 -0
  13. package/dist/ai/adapter/openai/wire.d.ts +40 -0
  14. package/dist/ai/adapter/types.d.ts +131 -0
  15. package/dist/ai/agent/classifier.d.ts +2 -0
  16. package/dist/ai/agent/diff.d.ts +35 -0
  17. package/dist/ai/agent/diffHighlight.d.ts +6 -0
  18. package/dist/ai/agent/index.d.ts +6 -0
  19. package/dist/ai/agent/permissions.d.ts +11 -0
  20. package/dist/ai/agent/toolfmt.d.ts +18 -0
  21. package/dist/ai/agent/transcript.d.ts +38 -0
  22. package/dist/ai/ai.css +325 -0
  23. package/dist/ai/components/AllocationSelector.d.ts +4 -0
  24. package/dist/ai/components/AttachmentManager.d.ts +1 -0
  25. package/dist/ai/components/AttachmentUpload.d.ts +24 -0
  26. package/dist/ai/components/BlockedGroupBanner.d.ts +1 -0
  27. package/dist/ai/components/BranchNavigator.d.ts +8 -0
  28. package/dist/ai/components/ChatEmptyState.d.ts +3 -0
  29. package/dist/ai/components/ChatInput.d.ts +45 -0
  30. package/dist/ai/components/ChatLayout.d.ts +5 -0
  31. package/dist/ai/components/ChatMessage.d.ts +24 -0
  32. package/dist/ai/components/ChatMessageList.d.ts +35 -0
  33. package/dist/ai/components/ChatSidebar.d.ts +5 -0
  34. package/dist/ai/components/ChatThread.d.ts +3 -0
  35. package/dist/ai/components/ComposerChrome.d.ts +18 -0
  36. package/dist/ai/components/ComposerFrame.d.ts +16 -0
  37. package/dist/ai/components/DragOverlay.d.ts +5 -0
  38. package/dist/ai/components/ModelSelector.d.ts +6 -0
  39. package/dist/ai/components/ShareDialog.d.ts +11 -0
  40. package/dist/ai/components/SlashMenu.d.ts +28 -0
  41. package/dist/ai/components/agent/ActivityLine.d.ts +21 -0
  42. package/dist/ai/components/agent/AgentMessageParts.d.ts +54 -0
  43. package/dist/ai/components/agent/PermissionPicker.d.ts +11 -0
  44. package/dist/ai/components/attachmentKeys.d.ts +4 -0
  45. package/dist/ai/core/ChatProvider.d.ts +66 -0
  46. package/dist/ai/core/KeyboardShortcutsProvider.d.ts +5 -0
  47. package/dist/ai/core/chatReducer.d.ts +114 -0
  48. package/dist/ai/core/config.d.ts +47 -0
  49. package/dist/ai/core/events.d.ts +1 -0
  50. package/dist/ai/core/exportConversation.d.ts +4 -0
  51. package/dist/ai/core/greeting.d.ts +3 -0
  52. package/dist/ai/core/parts.d.ts +11 -0
  53. package/dist/ai/core/useDragDrop.d.ts +14 -0
  54. package/dist/ai/core/useKeyboardShortcuts.d.ts +12 -0
  55. package/dist/ai/core/useSSEStream.d.ts +34 -0
  56. package/dist/ai/index.d.ts +40 -0
  57. package/dist/ai/index.js +6645 -0
  58. package/dist/ai/strings.d.ts +167 -0
  59. package/dist/ai/types.d.ts +236 -0
  60. package/dist/ai/ui/Avatar.d.ts +8 -0
  61. package/dist/ai/ui/Dropdown.d.ts +31 -0
  62. package/dist/ai/ui/Markdown.d.ts +8 -0
  63. package/dist/ai/ui/Notice.d.ts +21 -0
  64. package/dist/ai/ui/buttons.d.ts +1 -0
  65. package/dist/ai/ui/codeBreaks.d.ts +16 -0
  66. package/dist/ai/ui/prose.d.ts +1 -0
  67. package/dist/ai/ui/sidebar.d.ts +81 -0
  68. package/dist/ai/utils.d.ts +4 -0
  69. package/dist/assets/{editor.worker-CuBRIwi-.js → editor.worker-BmHUIVG4.js} +194 -163
  70. package/dist/assets/{json.worker-8ytS02vz.js → json.worker-D8bJ92nw.js} +384 -338
  71. package/dist/assets/{yaml.worker-DJC-VUcv.js → yaml.worker-C4gyGAko.js} +15657 -13823
  72. package/dist/chunks/{CodePreviewEditor-4lx3kE-w.js → CodePreviewEditor-YqQBz1YL.js} +1 -1
  73. package/dist/chunks/ConfirmModal-aOR4O1QE.js +79 -0
  74. package/dist/chunks/{FieldWrapper-Bef01EWO.js → FieldWrapper-Cszwg-4B.js} +3 -7
  75. package/dist/chunks/{CreateModal-BY6DLmur.js → Markdown-CM-FenNE.js} +19 -91
  76. package/dist/chunks/Monaco-DJ8MW-Dq.js +110 -0
  77. package/dist/chunks/{PageHeader-l49p1nM9.js → PageHeader-0kG_iypP.js} +67 -65
  78. package/dist/chunks/{Provider-Ghua9PkN.js → Provider-CDYurraE.js} +54 -20
  79. package/dist/chunks/{SwitchToggle-CHPP8uZQ.js → SwitchToggle-DShNdcao.js} +135 -132
  80. package/dist/chunks/{Table-4OHjdKdO.js → Table-DU2MW8xz.js} +5 -3
  81. package/dist/chunks/{Tooltip-Crxo_eU_.js → Tooltip-K5HJr4_p.js} +31 -4
  82. package/dist/chunks/duration-BOv8Phl8.js +17 -0
  83. package/dist/chunks/{editor-9_uVtUyy.js → editor-Dk1rbV75.js} +32 -18
  84. package/dist/chunks/focus-D_iZJTW1.js +7 -0
  85. package/dist/chunks/{list-qrojZZNv.js → list-CJm875m7.js} +377 -370
  86. package/dist/chunks/logviewer-BTKuQWzw.js +828 -0
  87. package/dist/chunks/memoryStore-CC91S5LP.js +152 -0
  88. package/dist/chunks/types-Yy0NrerF.js +11 -0
  89. package/dist/components/Avatar.d.ts +1 -1
  90. package/dist/components/Breadcrumbs.d.ts +1 -1
  91. package/dist/components/Dropdown.d.ts +1 -1
  92. package/dist/components/EmptyState.d.ts +1 -1
  93. package/dist/components/Indicator.d.ts +2 -2
  94. package/dist/components/Input.d.ts +1 -1
  95. package/dist/components/LetterBadge.d.ts +1 -1
  96. package/dist/components/MarkdownImpl.d.ts +1 -1
  97. package/dist/components/Provider.d.ts +16 -65
  98. package/dist/components/SettingRow.d.ts +1 -1
  99. package/dist/components/SettingsGroup.d.ts +1 -1
  100. package/dist/components/focus.d.ts +2 -0
  101. package/dist/components/keys.d.ts +12 -0
  102. package/dist/duration.d.ts +3 -0
  103. package/dist/editor/Monaco.d.ts +1 -20
  104. package/dist/editor/index.d.ts +2 -1
  105. package/dist/editor/index.js +2 -2
  106. package/dist/editor/yaml.d.ts +5 -0
  107. package/dist/engine.d.ts +98 -0
  108. package/dist/file-explorer/FileExplorer.d.ts +11 -2
  109. package/dist/file-explorer/FileExplorerContext.d.ts +1 -1
  110. package/dist/file-explorer/FilePreview/CodePreviewEditor.d.ts +1 -1
  111. package/dist/file-explorer/FilePreview/previewType.d.ts +1 -1
  112. package/dist/file-explorer/FileRow.d.ts +1 -1
  113. package/dist/file-explorer/helpers.d.ts +4 -4
  114. package/dist/file-explorer/index.d.ts +3 -3
  115. package/dist/file-explorer/index.js +613 -647
  116. package/dist/file-explorer/lib/types.d.ts +6 -1
  117. package/dist/file-explorer/lib/utils.d.ts +1 -3
  118. package/dist/file-explorer/useNearEnd.d.ts +1 -1
  119. package/dist/form/FieldWrapper.d.ts +2 -2
  120. package/dist/form/Fields/ResourceOptionIcon.d.ts +1 -1
  121. package/dist/form/Form.d.ts +4 -21
  122. package/dist/form/index.d.ts +11 -12
  123. package/dist/form/index.js +1488 -1611
  124. package/dist/form/lib.d.ts +6 -1
  125. package/dist/form/types/fieldComponentTypes.d.ts +3 -2
  126. package/dist/form/types/fieldTypes.d.ts +6 -20
  127. package/dist/form/useParsedOpts.d.ts +1 -1
  128. package/dist/form/utils/{slurmDuration.d.ts → duration.d.ts} +2 -2
  129. package/dist/{workflow → graph}/MatrixGroup.d.ts +2 -2
  130. package/dist/{workflow → graph}/index.d.ts +1 -1
  131. package/dist/{workflow → graph}/index.js +215 -180
  132. package/dist/{workflow → graph}/types.d.ts +3 -3
  133. package/dist/icons.d.ts +20 -21
  134. package/dist/index.d.ts +38 -40
  135. package/dist/index.js +347 -346
  136. package/dist/list/ListTable.d.ts +1 -1
  137. package/dist/list/ListViewControls.d.ts +2 -2
  138. package/dist/list/index.d.ts +9 -9
  139. package/dist/list/index.js +2 -2
  140. package/dist/logviewer/LogViewer.d.ts +1 -1
  141. package/dist/logviewer/index.d.ts +1 -0
  142. package/dist/logviewer/index.js +2 -742
  143. package/dist/logviewer/segments.d.ts +9 -0
  144. package/dist/styles/fonts.css +4 -4
  145. package/dist/styles/theme.css +6 -4
  146. package/dist/styles.css +1 -1
  147. package/dist/theme/index.js +2 -2
  148. package/package.json +38 -14
  149. package/LICENSE +0 -202
  150. package/dist/chunks/Monaco-C1POOdVv.js +0 -1046
  151. package/dist/editor/usesGitlab.d.ts +0 -97
  152. package/dist/form/Fields/BucketReadOnlyField.d.ts +0 -7
  153. package/dist/form/types/workflow-schema.d.ts +0 -1145
  154. package/dist/form/utils/pwResolver.d.ts +0 -18
  155. package/dist/chunks/{MarkdownImpl-Bq4QhrtA.js → MarkdownImpl-CyeTVvSt.js} +1 -1
  156. /package/dist/{workflow → graph}/AnnotationBanner.d.ts +0 -0
  157. /package/dist/{workflow → graph}/Collapse.d.ts +0 -0
  158. /package/dist/{workflow → graph}/DependencyGraph.d.ts +0 -0
  159. /package/dist/{workflow → graph}/JobSummary.d.ts +0 -0
  160. /package/dist/{workflow → graph}/Reveal.d.ts +0 -0
  161. /package/dist/{workflow → graph}/TreeView.d.ts +0 -0
@@ -1,4 +1,4 @@
1
- import { createContext, useContext, useMemo } from "react";
1
+ import { createContext, use, useCallback, useContext, useEffect, useMemo } from "react";
2
2
  import { useLocalStorage } from "usehooks-ts";
3
3
  import { Fragment as Fragment$1, jsx, jsxs } from "react/jsx-runtime";
4
4
  //#region src/components/Provider.tsx
@@ -85,7 +85,7 @@ var DEFAULTS = {
85
85
  timeRangeActive: "Time range active",
86
86
  timeRangeOn: "ON",
87
87
  filterByTimeRange: "Filter by time range",
88
- timeRangeHelp: "Times are interpreted in your local timezone. Applying a range re-queries the journal on the cluster and replaces what is loaded. Setting an end time stops live tailing until you clear it.",
88
+ timeRangeHelp: "Times are interpreted in your local timezone. Applying a range re-queries the log source and replaces what is loaded. Setting an end time stops live tailing until you clear it.",
89
89
  timeRangeFrom: "From",
90
90
  timeRangeTo: "To",
91
91
  apply: "Apply",
@@ -188,7 +188,7 @@ var DEFAULTS = {
188
188
  },
189
189
  propagating: {
190
190
  title: "Propagating CORS rules",
191
- description: "Azure is rolling out the new rules to its storage endpoints. This usually completes within a minute.",
191
+ description: "The storage provider is rolling out the new rules to its endpoints. This usually completes within a minute.",
192
192
  stages: {
193
193
  submitted: "Submitted",
194
194
  propagating: "Propagating",
@@ -246,6 +246,7 @@ var DEFAULTS = {
246
246
  collapse: "Collapse",
247
247
  upload: "Upload",
248
248
  download: "Download",
249
+ downloadFromBrowser: "From browser",
249
250
  access: "Access",
250
251
  manageAccess: "Manage Access",
251
252
  delete: "Delete",
@@ -319,11 +320,7 @@ var DEFAULTS = {
319
320
  form: {
320
321
  invalidDuration: "Enter a duration as DD-HH:MM:SS or HH:MM:SS.",
321
322
  durationOutOfRange: (min, max) => `Must be between ${min} and ${max}.`,
322
- durationBelowMin: (min) => `Must be at least ${min}.`,
323
- readOnly: "Read-only",
324
- readWrite: "Read-write",
325
- readOnlyDescription: "Read-only mounts can list and download objects, but cannot upload, modify, or delete them.",
326
- readOnlyForced: "Your access to this bucket is read-only, so this mount cannot be writable."
323
+ durationBelowMin: (min) => `Must be at least ${min}.`
327
324
  },
328
325
  time: {
329
326
  now: "now",
@@ -392,8 +389,8 @@ var DEFAULTS = {
392
389
  className: "font-medium",
393
390
  children: startTime
394
391
  }),
392
+ " to",
395
393
  " ",
396
- "to ",
397
394
  /* @__PURE__ */ jsx("span", {
398
395
  className: "font-medium",
399
396
  children: endTime
@@ -403,8 +400,9 @@ var DEFAULTS = {
403
400
  },
404
401
  navigation: {
405
402
  goTo: (to) => window.location.assign(to),
406
- toWorkflow: () => {},
407
- toMarketItem: () => {},
403
+ openStepSource: (_uses, sourceUrl) => {
404
+ if (sourceUrl) window.open(sourceUrl, "_blank");
405
+ },
408
406
  openExternal: (href) => window.open(href, "_blank")
409
407
  },
410
408
  data: {
@@ -426,15 +424,46 @@ function useNavigation() {
426
424
  function useSlots() {
427
425
  return useContext(UIContext).slots;
428
426
  }
429
- function useWorkflowJsonResolver() {
430
- return useContext(UIContext).data.resolveWorkflowJson;
427
+ var loadedEngines = /* @__PURE__ */ new WeakMap();
428
+ function loadEngine(load) {
429
+ let entry = loadedEngines.get(load);
430
+ if (!entry) {
431
+ const created = { promise: load() };
432
+ created.promise.then((engine) => {
433
+ created.engine = engine;
434
+ });
435
+ loadedEngines.set(load, created);
436
+ entry = created;
437
+ }
438
+ return entry;
439
+ }
440
+ function resolveEngine(source) {
441
+ if (typeof source !== "function") return source;
442
+ const entry = loadEngine(source);
443
+ return entry.engine ?? use(entry.promise);
444
+ }
445
+ /** The engine when one is provided and `enabled`; suspends while a loader resolves. */
446
+ function useOptionalWorkflowEngine(enabled = true) {
447
+ const source = useContext(UIContext).engine;
448
+ if (!enabled || !source) return;
449
+ return resolveEngine(source);
450
+ }
451
+ function useWorkflowEngine() {
452
+ const source = useContext(UIContext).engine;
453
+ if (!source) throw new Error("Workflow forms and graphs need a UIProvider with an engine.");
454
+ return resolveEngine(source);
455
+ }
456
+ /** Resolves the engine without suspending, for async callers such as editor completions. */
457
+ function useWorkflowEngineLoader() {
458
+ const source = useContext(UIContext).engine;
459
+ return useCallback(async () => {
460
+ if (!source) return;
461
+ return typeof source === "function" ? loadEngine(source).promise : source;
462
+ }, [source]);
431
463
  }
432
464
  function useProvisionCorsRules() {
433
465
  return useContext(UIContext).data.provisionCorsRules;
434
466
  }
435
- function useRepoSuggestions() {
436
- return useContext(UIContext).data.repoSuggestions;
437
- }
438
467
  function useRunFile(slug, path, options) {
439
468
  const { useRunFile: boundUseRunFile } = useContext(UIContext).data;
440
469
  return boundUseRunFile(slug, path, options);
@@ -443,7 +472,10 @@ function usePersistedState(key, defaultValue) {
443
472
  const { usePersistedState: boundUsePersistedState } = useContext(UIContext).data;
444
473
  return boundUsePersistedState(key, defaultValue);
445
474
  }
446
- function UIProvider({ notify, strings, navigation, data, slots, children }) {
475
+ function UIProvider({ notify, strings, navigation, data, slots, engine, children }) {
476
+ useEffect(() => {
477
+ if (typeof engine === "function") loadEngine(engine);
478
+ }, [engine]);
447
479
  const value = useMemo(() => ({
448
480
  notify: {
449
481
  ...DEFAULTS.notify,
@@ -500,13 +532,15 @@ function UIProvider({ notify, strings, navigation, data, slots, children }) {
500
532
  ...DEFAULTS.data,
501
533
  ...data
502
534
  },
503
- slots: slots ?? DEFAULTS.slots
535
+ slots: slots ?? DEFAULTS.slots,
536
+ engine
504
537
  }), [
505
538
  notify,
506
539
  strings,
507
540
  navigation,
508
541
  data,
509
- slots
542
+ slots,
543
+ engine
510
544
  ]);
511
545
  return /* @__PURE__ */ jsx(UIContext.Provider, {
512
546
  value,
@@ -514,4 +548,4 @@ function UIProvider({ notify, strings, navigation, data, slots, children }) {
514
548
  });
515
549
  }
516
550
  //#endregion
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 };
551
+ export { useOptionalWorkflowEngine as a, useRunFile as c, useWorkflowEngine as d, useWorkflowEngineLoader as f, useNotify as i, useSlots as l, useLink as n, usePersistedState as o, useNavigation as r, useProvisionCorsRules as s, UIProvider as t, useStrings as u };
@@ -1,22 +1,91 @@
1
- import { u as useStrings } from "./Provider-Ghua9PkN.js";
1
+ import { u as useStrings } from "./Provider-CDYurraE.js";
2
2
  import { AngleDownIcon, AngleRightIcon, CaretDownIcon } from "../icons.js";
3
- import { a as truncationTooltipProps, n as TOOLTIP_ID } from "./Tooltip-Crxo_eU_.js";
3
+ import { a as truncationTooltipProps, n as TOOLTIP_ID, o as keyedByContent } from "./Tooltip-K5HJr4_p.js";
4
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
+ import { t as focusOnMount } from "./focus-D_iZJTW1.js";
6
+ import { Combobox, ComboboxButton, ComboboxInput, ComboboxOption, ComboboxOptions, Listbox, ListboxButton, ListboxOption, ListboxOptions, Switch, Transition } from "@headlessui/react";
5
7
  import cx from "classnames";
6
8
  import React, { useCallback, useEffect, useMemo, useRef, useState } from "react";
7
9
  import { Fragment as Fragment$1, jsx, jsxs } from "react/jsx-runtime";
8
10
  import { createPortal } from "react-dom";
9
- import { Combobox, ComboboxButton, ComboboxInput, ComboboxOption, ComboboxOptions, Listbox, ListboxButton, ListboxOption, ListboxOptions, Switch, Transition } from "@headlessui/react";
11
+ import AnimateHeight from "react-animate-height";
10
12
  import deepEqual from "fast-deep-equal";
11
13
  import { usePopper } from "react-popper";
12
- import AnimateHeight from "react-animate-height";
14
+ //#region src/components/CollapsiblePanel.tsx
15
+ var noop = () => {};
16
+ function ControlledCollapsiblePanel({ title = "", children, open, setOpen, onClick = noop, wrapperElement, customizedButton = null, titleAction, className }) {
17
+ const toggleOpen = useCallback(() => {
18
+ if (onClick) onClick();
19
+ setOpen?.((open) => !open);
20
+ }, [setOpen, onClick]);
21
+ const contentId = React.useId();
22
+ const Wrapper = wrapperElement ? wrapperElement : React.Fragment;
23
+ return React.isValidElement(title) ? /* @__PURE__ */ jsxs(Fragment$1, { children: [title, /* @__PURE__ */ jsx(Wrapper, { children: /* @__PURE__ */ jsx(AnimateHeight, {
24
+ duration: 300,
25
+ height: open ? "auto" : 0,
26
+ children
27
+ }) })] }) : /* @__PURE__ */ jsxs("div", {
28
+ className: cx("border border-solid rounded-2xl border-(--theme-border) bg-(--theme-panel-bg) text-(--theme-panel) mb-1 w-full", className),
29
+ children: [/* @__PURE__ */ jsxs("div", {
30
+ className: cx(!open && "text-(--theme-muted-text-color)", "w-full flex items-center transform ease-in transition text-sm py-3 px-2 cursor-pointer"),
31
+ children: [
32
+ /* @__PURE__ */ jsxs("button", {
33
+ type: "button",
34
+ "aria-expanded": !!open,
35
+ "aria-controls": contentId,
36
+ className: cx("flex items-center text-left cursor-pointer", !titleAction && "w-full"),
37
+ onClick: toggleOpen,
38
+ children: [/* @__PURE__ */ jsx(AngleRightIcon, { className: cx(open && "transform rotate-90", "px-1 ml-1 text-[1.25rem] transition ease-in") }), /* @__PURE__ */ jsx("span", {
39
+ className: "px-2 font-bold select-none",
40
+ children: title?.toString()
41
+ })]
42
+ }),
43
+ titleAction,
44
+ /* @__PURE__ */ jsx("div", {
45
+ className: "ml-auto",
46
+ children: customizedButton
47
+ })
48
+ ]
49
+ }), /* @__PURE__ */ jsx(AnimateHeight, {
50
+ id: contentId,
51
+ duration: 300,
52
+ height: open ? "auto" : 0,
53
+ children
54
+ })]
55
+ });
56
+ }
57
+ function UncontrolledCollapsiblePanel({ title, children, onClick, wrapperElement, initialState = true, className, customizedButton = null }) {
58
+ const [open, setOpen] = React.useState(initialState);
59
+ const passTitle = typeof title === "function" ? title(open, setOpen) : title;
60
+ return /* @__PURE__ */ jsx(ControlledCollapsiblePanel, {
61
+ title: passTitle,
62
+ open,
63
+ setOpen,
64
+ onClick,
65
+ wrapperElement,
66
+ className,
67
+ customizedButton,
68
+ children
69
+ });
70
+ }
71
+ function MaybeCollapsible({ className, initialState, children, title, customizedButton, collapsible }) {
72
+ if (collapsible) return /* @__PURE__ */ jsx(UncontrolledCollapsiblePanel, {
73
+ className,
74
+ initialState,
75
+ title,
76
+ customizedButton,
77
+ children
78
+ });
79
+ return /* @__PURE__ */ jsx("div", {
80
+ className,
81
+ children
82
+ });
83
+ }
84
+ //#endregion
13
85
  //#region src/components/Dropdown.tsx
14
86
  var defaultCollapsedLabel = (count) => `${count} more`;
15
- function isResourceValue(value) {
16
- if (typeof value !== "object" || value === null || !("name" in value)) return false;
17
- if (typeof value.name !== "string") return false;
18
- if ("$type" in value && value.$type === "computeResource") return true;
19
- return "type" in value && (value.type === "computeResource" || value.type === "bucket");
87
+ function isNamedValue(value) {
88
+ return typeof value === "object" && value !== null && "name" in value && typeof value.name === "string";
20
89
  }
21
90
  var checkEquals = (val, opt) => {
22
91
  if (typeof val === "object" && !Array.isArray(val)) return deepEqual(val, opt);
@@ -32,20 +101,22 @@ function getOptionFromValue(value, options) {
32
101
  else if (isCategory(option)) return option.options.find((opt) => checkEquals(value, opt.value));
33
102
  else return checkEquals(value, option.value);
34
103
  });
35
- if (found) if (typeof found === "string") return {
36
- label: found,
37
- value: found
38
- };
39
- else if (isCategory(found)) return found.options.find((opt) => checkEquals(value, opt.value)) || {
40
- label: JSON.stringify(value),
41
- value
42
- };
43
- else return found;
44
- const isResourceObject = isResourceValue(value);
45
- const fallbackLabel = typeof value === "string" ? value : isResourceObject ? value.name : JSON.stringify(value);
104
+ if (found) {
105
+ if (typeof found === "string") return {
106
+ label: found,
107
+ value: found
108
+ };
109
+ else if (isCategory(found)) return found.options.find((opt) => checkEquals(value, opt.value)) || {
110
+ label: JSON.stringify(value),
111
+ value
112
+ };
113
+ else return found;
114
+ }
115
+ const isNamedObject = isNamedValue(value);
116
+ const fallbackLabel = typeof value === "string" ? value : isNamedObject ? value.name : JSON.stringify(value);
46
117
  return {
47
118
  label: fallbackLabel,
48
- value: isResourceObject ? value : fallbackLabel
119
+ value: isNamedObject ? value : fallbackLabel
49
120
  };
50
121
  }
51
122
  function Dropdown(props) {
@@ -56,29 +127,30 @@ function Dropdown(props) {
56
127
  const wrapperOnchange = (value) => {
57
128
  if (onChange) onChange(value?.value);
58
129
  };
130
+ const transformedOptions = useMemo(() => {
131
+ if (!options || options.length === 0) return [];
132
+ return options.map((item) => {
133
+ if (isCategory(item)) return {
134
+ ...item,
135
+ options: item.options.map((opt) => {
136
+ if (typeof opt === "string") return {
137
+ label: opt,
138
+ value: opt
139
+ };
140
+ return opt;
141
+ })
142
+ };
143
+ else if (typeof item === "string") return {
144
+ label: item,
145
+ value: item
146
+ };
147
+ return item;
148
+ });
149
+ }, [options]);
59
150
  return /* @__PURE__ */ jsx(DropdownHelper, {
60
151
  value: val,
61
152
  onChange: wrapperOnchange,
62
- options: useMemo(() => {
63
- if (!options || options.length === 0) return [];
64
- return options.map((item) => {
65
- if (isCategory(item)) return {
66
- ...item,
67
- options: item.options.map((opt) => {
68
- if (typeof opt === "string") return {
69
- label: opt,
70
- value: opt
71
- };
72
- return opt;
73
- })
74
- };
75
- else if (typeof item === "string") return {
76
- label: item,
77
- value: item
78
- };
79
- return item;
80
- });
81
- }, [options]),
153
+ options: transformedOptions,
82
154
  ...others
83
155
  });
84
156
  }
@@ -180,19 +252,20 @@ function DropdownHelper({ wrapperClassName = "w-full", className, textBoxClassNa
180
252
  if (reference instanceof HTMLElement) popper.style.width = `${reference.offsetWidth}px`;
181
253
  }
182
254
  }), []);
255
+ const popperModifiers = useMemo(() => boundaryEl ? [
256
+ sameWidthModifier,
257
+ {
258
+ name: "flip",
259
+ options: { boundary: boundaryEl }
260
+ },
261
+ {
262
+ name: "preventOverflow",
263
+ options: { boundary: boundaryEl }
264
+ }
265
+ ] : [sameWidthModifier], [boundaryEl, sameWidthModifier]);
183
266
  const { styles, attributes } = usePopper(referenceElement, popperElement, {
184
267
  strategy: "fixed",
185
- modifiers: useMemo(() => boundaryEl ? [
186
- sameWidthModifier,
187
- {
188
- name: "flip",
189
- options: { boundary: boundaryEl }
190
- },
191
- {
192
- name: "preventOverflow",
193
- options: { boundary: boundaryEl }
194
- }
195
- ] : [sameWidthModifier], [boundaryEl, sameWidthModifier])
268
+ modifiers: popperModifiers
196
269
  });
197
270
  const debounceRef = useRef(null);
198
271
  const buttonRef = useRef(null);
@@ -202,7 +275,7 @@ function DropdownHelper({ wrapperClassName = "w-full", className, textBoxClassNa
202
275
  useEffect(() => {
203
276
  if (!selectedCategory || checkEquals(lastAutoExpandedValue.current, value.value)) return;
204
277
  lastAutoExpandedValue.current = value.value;
205
- setExpandedCategories((prev) => prev.size === 1 && prev.has(selectedCategory) ? prev : new Set([selectedCategory]));
278
+ setExpandedCategories((prev) => prev.size === 1 && prev.has(selectedCategory) ? prev : /* @__PURE__ */ new Set([selectedCategory]));
206
279
  }, [selectedCategory, value]);
207
280
  const toggleCategory = (category) => setExpandedCategories((prev) => toggleSetMember(prev, category));
208
281
  const flushCustomValue = useCallback((val) => {
@@ -377,7 +450,7 @@ function CustomListbox({ options = [], handleOptionSelected, type, allowSearch =
377
450
  children: /* @__PURE__ */ jsx("input", {
378
451
  autoComplete: "off",
379
452
  type: "search",
380
- autoFocus: true,
453
+ ref: focusOnMount,
381
454
  onChange: (e) => setFilter(e.target.value),
382
455
  value: filter,
383
456
  className: "w-full p-1 theme-input",
@@ -394,7 +467,7 @@ function CustomListbox({ options = [], handleOptionSelected, type, allowSearch =
394
467
  })
395
468
  }), /* @__PURE__ */ jsx("div", {
396
469
  className: "overflow-auto max-h-60 theme-panel",
397
- children: optionsToShow.length > 0 ? optionsToShow.map((option, index) => /* @__PURE__ */ jsx(ListboxOption, {
470
+ children: optionsToShow.length > 0 ? keyedByContent(optionsToShow, (o) => String(o.value)).map(({ key, item: option }) => /* @__PURE__ */ jsx(ListboxOption, {
398
471
  className: "relative hover:theme-hover select-none pl-2 pr-4",
399
472
  value: option.value,
400
473
  children: /* @__PURE__ */ jsx("div", {
@@ -420,8 +493,8 @@ function CustomListbox({ options = [], handleOptionSelected, type, allowSearch =
420
493
  })
421
494
  ]
422
495
  })
423
- }, index)
424
- }, index)) : /* @__PURE__ */ jsx("div", {
496
+ })
497
+ }, key)) : /* @__PURE__ */ jsx("div", {
425
498
  className: "w-full flex flex-row",
426
499
  children: /* @__PURE__ */ jsx("div", {
427
500
  className: "w-3/4 py-2 pl-2 capitalize flex items-center",
@@ -565,19 +638,19 @@ function MultiSelectDropdown({ options, value, onChange, id, "aria-labelledby":
565
638
  value: query,
566
639
  onChange: (e) => setQuery(e.target.value),
567
640
  onKeyDown: (e) => e.stopPropagation(),
568
- autoFocus: true
641
+ ref: focusOnMount
569
642
  })
570
643
  }), /* @__PURE__ */ jsx("div", {
571
644
  className: "py-1",
572
645
  children: isEmpty ? /* @__PURE__ */ jsx("div", {
573
646
  className: "px-4 py-2 text-sm theme-muted-text",
574
647
  children: strings.dropdown.noOptionsFound
575
- }) : filteredOptions.map((opt, index) => {
648
+ }) : keyedByContent(filteredOptions, (o) => isCategory(o) ? `category-${o.category ?? "uncat"}` : `option-${String(o.value)}`).map(({ key, item: opt }) => {
576
649
  if (isCategory(opt)) return /* @__PURE__ */ jsx("li", {
577
650
  role: "presentation",
578
651
  className: "px-4 py-2 text-sm font-bold theme-muted-text",
579
652
  children: opt.category
580
- }, `category-${opt.category ?? "uncat"}-${index}`);
653
+ }, key);
581
654
  const option = opt;
582
655
  return /* @__PURE__ */ jsx(ComboboxOption, {
583
656
  value: option.value,
@@ -612,7 +685,7 @@ function MultiSelectDropdown({ options, value, onChange, id, "aria-labelledby":
612
685
  })
613
686
  ]
614
687
  })
615
- }, `option-${String(option.value)}`);
688
+ }, key);
616
689
  })
617
690
  })]
618
691
  })
@@ -621,76 +694,6 @@ function MultiSelectDropdown({ options, value, onChange, id, "aria-labelledby":
621
694
  });
622
695
  }
623
696
  //#endregion
624
- //#region src/components/CollapsiblePanel.tsx
625
- var noop = () => {};
626
- function ControlledCollapsiblePanel({ title = "", children, open, setOpen, onClick = noop, wrapperElement, customizedButton = null, titleAction, className }) {
627
- const toggleOpen = useCallback(() => {
628
- if (onClick) onClick();
629
- setOpen?.((open) => !open);
630
- }, [setOpen, onClick]);
631
- const contentId = React.useId();
632
- const Wrapper = wrapperElement ? wrapperElement : React.Fragment;
633
- return React.isValidElement(title) ? /* @__PURE__ */ jsxs(Fragment$1, { children: [title, /* @__PURE__ */ jsx(Wrapper, { children: /* @__PURE__ */ jsx(AnimateHeight, {
634
- duration: 300,
635
- height: open ? "auto" : 0,
636
- children
637
- }) })] }) : /* @__PURE__ */ jsxs("div", {
638
- className: cx("border border-solid rounded-2xl border-(--theme-border) bg-(--theme-panel-bg) text-(--theme-panel) mb-1 w-full", className),
639
- children: [/* @__PURE__ */ jsxs("div", {
640
- className: cx(!open && "text-(--theme-muted-text-color)", "w-full flex items-center transform ease-in transition text-sm py-3 px-2 cursor-pointer"),
641
- children: [
642
- /* @__PURE__ */ jsxs("button", {
643
- type: "button",
644
- "aria-expanded": !!open,
645
- "aria-controls": contentId,
646
- className: cx("flex items-center text-left cursor-pointer", !titleAction && "w-full"),
647
- onClick: toggleOpen,
648
- children: [/* @__PURE__ */ jsx(AngleRightIcon, { className: cx(open && "transform rotate-90", "px-1 ml-1 text-[1.25rem] transition ease-in") }), /* @__PURE__ */ jsx("span", {
649
- className: "px-2 font-bold select-none",
650
- children: title?.toString()
651
- })]
652
- }),
653
- titleAction,
654
- /* @__PURE__ */ jsx("div", {
655
- className: "ml-auto",
656
- children: customizedButton
657
- })
658
- ]
659
- }), /* @__PURE__ */ jsx(AnimateHeight, {
660
- id: contentId,
661
- duration: 300,
662
- height: open ? "auto" : 0,
663
- children
664
- })]
665
- });
666
- }
667
- function UncontrolledCollapsiblePanel({ title, children, onClick, wrapperElement, initialState = true, className, customizedButton = null }) {
668
- const [open, setOpen] = React.useState(initialState);
669
- return /* @__PURE__ */ jsx(ControlledCollapsiblePanel, {
670
- title: typeof title === "function" ? title(open, setOpen) : title,
671
- open,
672
- setOpen,
673
- onClick,
674
- wrapperElement,
675
- className,
676
- customizedButton,
677
- children
678
- });
679
- }
680
- function MaybeCollapsible({ className, initialState, children, title, customizedButton, collapsible }) {
681
- if (collapsible) return /* @__PURE__ */ jsx(UncontrolledCollapsiblePanel, {
682
- className,
683
- initialState,
684
- title,
685
- customizedButton,
686
- children
687
- });
688
- return /* @__PURE__ */ jsx("div", {
689
- className,
690
- children
691
- });
692
- }
693
- //#endregion
694
697
  //#region src/components/SectionHeader.tsx
695
698
  function SectionHeader({ children, className = "", size = "md" }) {
696
699
  return /* @__PURE__ */ jsx("div", {
@@ -752,4 +755,4 @@ function SwitchToggle({ onChange, id, "aria-describedby": describedBy, value = v
752
755
  });
753
756
  }
754
757
  //#endregion
755
- export { UncontrolledCollapsiblePanel as a, Dropdown as c, MaybeCollapsible as i, SectionHeader as n, MultiSelectDropdown as o, ControlledCollapsiblePanel as r, CustomListbox as s, SwitchToggle as t };
758
+ export { Dropdown as a, UncontrolledCollapsiblePanel as c, CustomListbox as i, SectionHeader as n, ControlledCollapsiblePanel as o, MultiSelectDropdown as r, MaybeCollapsible as s, SwitchToggle as t };
@@ -1,4 +1,4 @@
1
- import { u as useStrings } from "./Provider-Ghua9PkN.js";
1
+ import { u as useStrings } from "./Provider-CDYurraE.js";
2
2
  import { t as Loader } from "./Loader-BXoXTZGc.js";
3
3
  import cx from "classnames";
4
4
  import React from "react";
@@ -49,9 +49,10 @@ function Table({ borderless = false, panel = true, className = "", wrapperClassN
49
49
  const { loading } = useStrings();
50
50
  const ChildrenArr = React.Children.toArray(children);
51
51
  const Headers = getHeaders(ChildrenArr);
52
+ const hasOverflow = wrapperClassName.split(" ").some((cls) => cls.startsWith("overflow-"));
52
53
  return /* @__PURE__ */ jsx("div", {
53
54
  "aria-busy": isLoading,
54
- className: cx("flex flex-col w-full", !wrapperClassName.split(" ").some((cls) => cls.startsWith("overflow-")) && "overflow-hidden", wrapperClassName),
55
+ className: cx("flex flex-col w-full", !hasOverflow && "overflow-hidden", wrapperClassName),
55
56
  children: isLoading ? /* @__PURE__ */ jsxs("div", {
56
57
  role: "status",
57
58
  "aria-label": loading,
@@ -79,8 +80,9 @@ function Table({ borderless = false, panel = true, className = "", wrapperClassN
79
80
  function CompactTable({ wrapperClassName = "", className = "", tbodyClassName = "divide-y", children, roundedTop = false, rounded = false, roundedBottom = false }) {
80
81
  const ChildrenArr = React.Children.toArray(children);
81
82
  const Headers = getHeaders(ChildrenArr);
83
+ const hasOverflow = wrapperClassName.split(" ").some((cls) => cls.startsWith("overflow-"));
82
84
  return /* @__PURE__ */ jsx("div", {
83
- className: cx("flex flex-col w-full", !wrapperClassName.split(" ").some((cls) => cls.startsWith("overflow-")) && "overflow-hidden", wrapperClassName),
85
+ className: cx("flex flex-col w-full", !hasOverflow && "overflow-hidden", wrapperClassName),
84
86
  children: /* @__PURE__ */ jsx("div", {
85
87
  className: cx("theme-panel inline-block min-w-full align-middle overflow-x-auto", rounded && "rounded-2xl", roundedBottom && "rounded-b-2xl pb-1", roundedTop && "rounded-t-2xl"),
86
88
  children: /* @__PURE__ */ jsxs("table", {
@@ -2,6 +2,32 @@ import { TooltipIcon } from "../icons.js";
2
2
  import { Fragment } from "react";
3
3
  import { jsx, jsxs } from "react/jsx-runtime";
4
4
  import { Tooltip } from "react-tooltip";
5
+ //#region src/components/keys.ts
6
+ /** Pairs each item with a React key from its content, suffixing repeats so keys stay unique. */
7
+ function keyedByContent(items, toKey) {
8
+ const seen = /* @__PURE__ */ new Map();
9
+ return items.map((item) => {
10
+ const base = toKey(item);
11
+ const count = (seen.get(base) ?? 0) + 1;
12
+ seen.set(base, count);
13
+ return {
14
+ key: count === 1 ? base : `${base}#${count}`,
15
+ item
16
+ };
17
+ });
18
+ }
19
+ /** Keys for a list whose position is its identity, such as placeholder rows or a fixed grid. */
20
+ function positionKeys(count, prefix = "position") {
21
+ return Array.from({ length: count }, (_, position) => `${prefix}-${position}`);
22
+ }
23
+ /** Pairs each item of a list that never reorders with a key from its position. */
24
+ function withPositionKeys(items, prefix = "position") {
25
+ return items.map((item, position) => ({
26
+ key: `${prefix}-${position}`,
27
+ item
28
+ }));
29
+ }
30
+ //#endregion
5
31
  //#region src/components/Tooltip.tsx
6
32
  var TOOLTIP_ID = "global-tooltip";
7
33
  /** Anchor props that reveal `content` only while the text is ellipsized; `measure` picks the clipped descendant when it isn't the anchor. */
@@ -39,18 +65,19 @@ function formatLine(line) {
39
65
  function formatTooltipContent(content) {
40
66
  if (typeof content !== "string") return content || null;
41
67
  if (!content) return null;
42
- return content.split(/<br\s*\/?>|\n/i).map((line, idx) => /* @__PURE__ */ jsxs(Fragment, { children: [idx > 0 && /* @__PURE__ */ jsx("br", {}), formatLine(line)] }, idx));
68
+ return keyedByContent(content.split(/<br\s*\/?>|\n/i), (l) => l).map(({ key, item: line }, idx) => /* @__PURE__ */ jsxs(Fragment, { children: [idx > 0 && /* @__PURE__ */ jsx("br", {}), formatLine(line)] }, key));
43
69
  }
44
70
  function KbdShortcut({ keys }) {
71
+ const parts = keys.split("+").map((part) => part.trim()).filter(Boolean);
45
72
  return /* @__PURE__ */ jsx("span", {
46
73
  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, { children: [idx > 0 && /* @__PURE__ */ jsx("span", {
74
+ children: keyedByContent(parts, (p) => p).map(({ key, item: part }, idx) => /* @__PURE__ */ jsxs(Fragment, { children: [idx > 0 && /* @__PURE__ */ jsx("span", {
48
75
  className: "opacity-60 text-[11px]",
49
76
  children: "+"
50
77
  }), /* @__PURE__ */ jsx("kbd", {
51
78
  className: "inline-flex items-center justify-center min-w-[18px] h-[18px] px-1 rounded border border-white/30 bg-white/10 font-sans text-[11px] font-semibold leading-none",
52
79
  children: part
53
- })] }, `${part}-${idx}`))
80
+ })] }, key))
54
81
  });
55
82
  }
56
83
  var globalCloseEvents = { escape: true };
@@ -93,4 +120,4 @@ function TooltipInfo({ text, className = "", children, place = "top", tabIndex }
93
120
  });
94
121
  }
95
122
  //#endregion
96
- export { truncationTooltipProps as a, formatTooltipContent as i, TOOLTIP_ID as n, TooltipInfo as r, GlobalTooltip as t };
123
+ export { truncationTooltipProps as a, withPositionKeys as c, formatTooltipContent as i, TOOLTIP_ID as n, keyedByContent as o, TooltipInfo as r, positionKeys as s, GlobalTooltip as t };
@@ -0,0 +1,17 @@
1
+ import { Duration } from "luxon";
2
+ //#region src/duration.ts
3
+ var UnitDisplay = { ja: "short" };
4
+ function durationToAbsHumanDuration(d) {
5
+ const duration = d.shiftTo("days", "hours", "minutes", "seconds").toObject();
6
+ if ("seconds" in duration) duration.seconds = Math.round(duration.seconds);
7
+ const cleanedDuration = Object.fromEntries(Object.entries(duration).filter(([, value]) => value !== 0).map(([key, value]) => [key, Math.abs(value)]));
8
+ if (Object.keys(cleanedDuration).length === 0) cleanedDuration.seconds = 0;
9
+ const human = Duration.fromObject(cleanedDuration);
10
+ const unitDisplay = UnitDisplay[human.locale] || "narrow";
11
+ return human.toHuman({ unitDisplay }).replaceAll(/[,、]/g, "");
12
+ }
13
+ function toAbsHumanDuration(start, end) {
14
+ return durationToAbsHumanDuration(end.diff(start));
15
+ }
16
+ //#endregion
17
+ export { toAbsHumanDuration as n, durationToAbsHumanDuration as t };