@parallelworks/ui 0.19.0 → 0.20.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 (233) hide show
  1. package/README.md +1 -1
  2. package/dist/{chunks/memoryStore-CC91S5LP.js → ai/adapter/memoryStore.js} +2 -2
  3. package/dist/ai/adapter/mock/index.js +2 -80
  4. package/dist/ai/adapter/mock/mockAdapter.js +81 -0
  5. package/dist/ai/adapter/openai/createOpenAIStream.js +33 -0
  6. package/dist/ai/adapter/openai/errors.js +37 -0
  7. package/dist/ai/adapter/openai/index.js +5 -333
  8. package/dist/ai/adapter/openai/openaiAdapter.js +54 -0
  9. package/dist/ai/adapter/openai/responses.js +108 -0
  10. package/dist/ai/adapter/openai/sse.js +112 -0
  11. package/dist/{chunks/types-Yy0NrerF.js → ai/adapter/types.js} +1 -1
  12. package/dist/ai/agent/classifier.js +12 -0
  13. package/dist/ai/agent/diff.js +223 -0
  14. package/dist/ai/agent/diffHighlight.js +101 -0
  15. package/dist/ai/agent/permissions.js +29 -0
  16. package/dist/ai/agent/toolfmt.js +383 -0
  17. package/dist/ai/agent/transcript.js +127 -0
  18. package/dist/ai/components/AllocationSelector.js +56 -0
  19. package/dist/ai/components/AttachmentManager.js +147 -0
  20. package/dist/ai/components/AttachmentUpload.js +179 -0
  21. package/dist/ai/components/BlockedGroupBanner.js +29 -0
  22. package/dist/ai/components/BranchNavigator.js +57 -0
  23. package/dist/ai/components/ChatEmptyState.js +171 -0
  24. package/dist/ai/components/ChatInput.js +265 -0
  25. package/dist/ai/components/ChatLayout.js +15 -0
  26. package/dist/ai/components/ChatMessage.js +341 -0
  27. package/dist/ai/components/ChatMessageList.js +301 -0
  28. package/dist/ai/components/ChatSidebar.js +345 -0
  29. package/dist/ai/components/ChatThread.js +198 -0
  30. package/dist/ai/components/ComposerChrome.js +50 -0
  31. package/dist/ai/components/ComposerFrame.js +33 -0
  32. package/dist/ai/components/DragOverlay.js +20 -0
  33. package/dist/ai/components/ModelSelector.js +343 -0
  34. package/dist/ai/components/ShareDialog.js +260 -0
  35. package/dist/ai/components/SlashMenu.js +91 -0
  36. package/dist/ai/components/agent/ActivityLine.js +151 -0
  37. package/dist/ai/components/agent/AgentMessageParts.js +721 -0
  38. package/dist/ai/components/agent/PermissionPicker.js +38 -0
  39. package/dist/ai/components/attachmentKeys.js +10 -0
  40. package/dist/ai/core/ChatProvider.js +848 -0
  41. package/dist/ai/core/KeyboardShortcutsProvider.js +9 -0
  42. package/dist/ai/core/chatReducer.js +223 -0
  43. package/dist/ai/core/config.js +46 -0
  44. package/dist/ai/core/events.js +4 -0
  45. package/dist/ai/core/exportConversation.js +42 -0
  46. package/dist/ai/core/greeting.js +38 -0
  47. package/dist/ai/core/parts.js +84 -0
  48. package/dist/ai/core/useDragDrop.js +36 -0
  49. package/dist/ai/core/useKeyboardShortcuts.js +77 -0
  50. package/dist/ai/core/useSSEStream.js +98 -0
  51. package/dist/ai/index.js +43 -6644
  52. package/dist/ai/strings.js +175 -0
  53. package/dist/ai/ui/Avatar.js +35 -0
  54. package/dist/ai/ui/Dropdown.js +110 -0
  55. package/dist/ai/ui/Markdown.js +79 -0
  56. package/dist/ai/ui/Notice.js +77 -0
  57. package/dist/ai/ui/codeBreaks.js +36 -0
  58. package/dist/ai/ui/prose.js +13 -0
  59. package/dist/ai/ui/sidebar.js +148 -0
  60. package/dist/ai/utils.js +23 -0
  61. package/dist/assets/editor.worker-DfmPPyOL.js +60 -0
  62. package/dist/assets/json.worker-Dqgjpq9F.js +92 -0
  63. package/dist/assets/yaml.worker-DLx0whrM.js +1441 -0
  64. package/dist/components/AddMenu.js +46 -0
  65. package/dist/components/Avatar.js +46 -0
  66. package/dist/{chunks/BareModal-BtRiQezg.js → components/BareModal.js} +1 -1
  67. package/dist/components/Breadcrumbs.js +83 -0
  68. package/dist/components/Button.js +83 -0
  69. package/dist/components/Callout.js +23 -0
  70. package/dist/components/Card.js +31 -0
  71. package/dist/components/CollapsiblePanel.js +77 -0
  72. package/dist/{chunks/ConfirmModal-aOR4O1QE.js → components/ConfirmModal.js} +4 -9
  73. package/dist/components/CopyToClipboard.js +81 -0
  74. package/dist/{chunks/Markdown-CM-FenNE.js → components/CreateModal.js} +9 -116
  75. package/dist/components/DescriptionList.js +42 -0
  76. package/dist/components/Dropdown.js +349 -0
  77. package/dist/components/EmptyState.js +27 -0
  78. package/dist/components/Filter.js +32 -0
  79. package/dist/components/FilterPill.js +13 -0
  80. package/dist/components/IconButton.js +34 -0
  81. package/dist/{chunks/Indicator-hBSIxOPK.js → components/Indicator.js} +1 -1
  82. package/dist/components/Input.js +88 -0
  83. package/dist/components/LetterBadge.js +13 -0
  84. package/dist/components/Listbox.js +123 -0
  85. package/dist/{chunks/Loader-BXoXTZGc.js → components/Loader.js} +1 -1
  86. package/dist/components/Markdown.js +15 -0
  87. package/dist/components/MultiSelect.js +171 -0
  88. package/dist/components/Overview.js +39 -0
  89. package/dist/components/PageHeader.js +194 -0
  90. package/dist/components/Pagination.js +35 -0
  91. package/dist/{chunks/Provider-CDYurraE.js → components/Provider.js} +13 -5
  92. package/dist/{chunks/RequiredMark-DfLdYbYZ.js → components/RequiredMark.js} +1 -1
  93. package/dist/components/SectionHeader.js +11 -0
  94. package/dist/components/SettingModeOption.js +30 -0
  95. package/dist/components/SettingRow.js +35 -0
  96. package/dist/components/SettingsCard.js +31 -0
  97. package/dist/components/SettingsGroup.js +17 -0
  98. package/dist/components/Sort.js +42 -0
  99. package/dist/components/StatusBadge.js +63 -0
  100. package/dist/components/SwitchToggle.js +59 -0
  101. package/dist/{chunks/SwitchToggleSmall-FcsaYSTs.js → components/SwitchToggleSmall.js} +1 -1
  102. package/dist/{chunks/Table-DU2MW8xz.js → components/Table.js} +3 -3
  103. package/dist/components/Toggle.js +20 -0
  104. package/dist/{chunks/Tooltip-K5HJr4_p.js → components/Tooltip.js} +2 -27
  105. package/dist/{chunks/StatusBadge-C1Blx_cW.js → components/dropdownUtils.js} +2 -63
  106. package/dist/{chunks/focus-D_iZJTW1.js → components/focus.js} +1 -1
  107. package/dist/components/ghostButton.js +7 -0
  108. package/dist/components/inputClasses.js +4 -0
  109. package/dist/components/keys.js +27 -0
  110. package/dist/components/relativeTime.js +32 -0
  111. package/dist/{chunks/useCssIsDark-DHr05dG2.js → components/useCssIsDark.js} +1 -1
  112. package/dist/{chunks/duration-BOv8Phl8.js → duration.js} +1 -1
  113. package/dist/editor/Editor.js +13 -0
  114. package/dist/editor/EditorField.js +53 -0
  115. package/dist/editor/FormCodePanel.js +173 -0
  116. package/dist/{chunks/Monaco-DJ8MW-Dq.js → editor/Monaco.js} +5 -26
  117. package/dist/editor/index.js +6 -1
  118. package/dist/editor/themes.js +91 -0
  119. package/dist/editor/workers.d.ts +5 -0
  120. package/dist/editor/workers.js +35 -0
  121. package/dist/editor/yaml.d.ts +9 -1
  122. package/dist/editor/yaml.js +15 -0
  123. package/dist/editor/yaml.worker.d.ts +1 -0
  124. package/dist/editor/yamlLanguage.d.ts +6 -0
  125. package/dist/editor/yamlLanguage.js +312 -0
  126. package/dist/file-explorer/FileExplorer.js +1405 -0
  127. package/dist/file-explorer/FileExplorerContext.js +370 -0
  128. package/dist/{chunks/CodePreviewEditor-YqQBz1YL.js → file-explorer/FilePreview/CodePreviewEditor.js} +3 -2
  129. package/dist/file-explorer/FilePreview/Inline.js +45 -0
  130. package/dist/file-explorer/FilePreview/StreamedBadge.js +16 -0
  131. package/dist/file-explorer/FilePreview/Viewer.js +526 -0
  132. package/dist/file-explorer/FilePreview/index.js +266 -0
  133. package/dist/file-explorer/FilePreview/parse.js +63 -0
  134. package/dist/file-explorer/FilePreview/previewCache.js +98 -0
  135. package/dist/file-explorer/FilePreview/previewType.js +151 -0
  136. package/dist/file-explorer/FilePreview/readCappedBytes.js +196 -0
  137. package/dist/file-explorer/FilePreview/useObjectBlobUrl.js +95 -0
  138. package/dist/file-explorer/FilePreview/useObjectText.js +109 -0
  139. package/dist/file-explorer/FilePreview/usePresignedUrl.js +73 -0
  140. package/dist/file-explorer/FileRow.js +165 -0
  141. package/dist/file-explorer/FileRowsWindow.js +92 -0
  142. package/dist/file-explorer/FileTable.js +172 -0
  143. package/dist/file-explorer/FileTableHeaders.js +49 -0
  144. package/dist/file-explorer/LoadMoreRow.js +46 -0
  145. package/dist/file-explorer/TreeView.js +376 -0
  146. package/dist/file-explorer/helpers.js +537 -0
  147. package/dist/file-explorer/index.js +7 -5671
  148. package/dist/file-explorer/lib/batch.js +39 -0
  149. package/dist/file-explorer/lib/errors.js +9 -0
  150. package/dist/file-explorer/lib/paging.js +124 -0
  151. package/dist/file-explorer/lib/utils.js +322 -0
  152. package/dist/file-explorer/toasts.js +400 -0
  153. package/dist/file-explorer/treeRows.js +73 -0
  154. package/dist/file-explorer/useNearEnd.js +27 -0
  155. package/dist/form/FieldWrapper.js +54 -0
  156. package/dist/form/Fields/BooleanField.js +51 -0
  157. package/dist/form/Fields/CheckboxGroupField.js +72 -0
  158. package/dist/form/Fields/ColorField.js +33 -0
  159. package/dist/form/Fields/DropdownField.js +49 -0
  160. package/dist/form/Fields/DurationField.js +130 -0
  161. package/dist/form/Fields/LabelField.js +19 -0
  162. package/dist/form/Fields/MultiDropdownField.js +40 -0
  163. package/dist/form/Fields/NumberField.js +51 -0
  164. package/dist/form/Fields/ObjectField.js +54 -0
  165. package/dist/form/Fields/RadioField.js +49 -0
  166. package/dist/form/Fields/RangeField.js +58 -0
  167. package/dist/form/Fields/ResourceOptionIcon.js +21 -0
  168. package/dist/form/Fields/StepField.js +6 -0
  169. package/dist/form/Fields/StringField.js +37 -0
  170. package/dist/form/Fields/TextAreaField.js +31 -0
  171. package/dist/form/Fields/durationValidity.js +11 -0
  172. package/dist/form/Form.js +643 -0
  173. package/dist/form/SpecialTypes/DropdownWrapper.js +30 -0
  174. package/dist/form/SpecialTypes/FormikCustomDropdown.js +122 -0
  175. package/dist/form/SpecialTypes/FormikCustomInput.js +111 -0
  176. package/dist/form/SpecialTypes/FormikMultiSelectDropdown.js +31 -0
  177. package/dist/form/SpecialTypes/FormikNumericInput.js +60 -0
  178. package/dist/form/Wizard/WizardContainer.js +138 -0
  179. package/dist/form/Wizard/WizardNavigation.js +92 -0
  180. package/dist/form/Wizard/WizardStepContent.js +35 -0
  181. package/dist/form/Wizard/WizardStepIndicator.js +108 -0
  182. package/dist/form/Wizard/useWizardState.js +118 -0
  183. package/dist/form/Wizard/utils.js +34 -0
  184. package/dist/form/fieldContext.js +26 -0
  185. package/dist/form/fieldRegistry.js +50 -0
  186. package/dist/form/index.js +17 -2321
  187. package/dist/{chunks/FieldWrapper-Cszwg-4B.js → form/lib.js} +2 -97
  188. package/dist/form/useParsedOpts.js +62 -0
  189. package/dist/form/usePrevious.js +11 -0
  190. package/dist/form/utils/checkShowIfObject.js +14 -0
  191. package/dist/form/utils/duration.js +69 -0
  192. package/dist/form/utils/getParentValue.js +23 -0
  193. package/dist/form/utils/getPlaceholder.js +9 -0
  194. package/dist/form/utils/getValueUsingPath.js +23 -0
  195. package/dist/form/utils/secondaryField.js +22 -0
  196. package/dist/graph/AnnotationBanner.js +141 -0
  197. package/dist/graph/Collapse.js +41 -0
  198. package/dist/graph/DependencyGraph.js +1398 -0
  199. package/dist/graph/JobSummary.js +104 -0
  200. package/dist/graph/MatrixGroup.js +107 -0
  201. package/dist/graph/Reveal.js +57 -0
  202. package/dist/graph/TreeView.js +711 -0
  203. package/dist/graph/index.js +1 -2519
  204. package/dist/graph/types.js +6 -0
  205. package/dist/icons.d.ts +4 -4
  206. package/dist/icons.js +5 -5
  207. package/dist/index.js +46 -599
  208. package/dist/list/ActionToolbar.js +184 -0
  209. package/dist/list/HoverCard.js +73 -0
  210. package/dist/list/ListPage.js +145 -0
  211. package/dist/list/ListPager.js +59 -0
  212. package/dist/list/ListTable.js +163 -0
  213. package/dist/list/ListViewControls.js +372 -0
  214. package/dist/list/RowContextMenu.js +351 -0
  215. package/dist/list/UserHoverCard.js +117 -0
  216. package/dist/list/index.js +11 -2
  217. package/dist/list/listSearch.js +137 -0
  218. package/dist/list/listView.js +210 -0
  219. package/dist/list/textEntry.js +10 -0
  220. package/dist/{chunks/logviewer-BTKuQWzw.js → logviewer/LogViewer.js} +4 -82
  221. package/dist/logviewer/index.js +2 -1
  222. package/dist/logviewer/segments.js +80 -0
  223. package/dist/safeUrl.d.ts +6 -0
  224. package/dist/safeUrl.js +22 -0
  225. package/package.json +7 -9
  226. package/dist/assets/editor.worker-BmHUIVG4.js +0 -14807
  227. package/dist/assets/json.worker-D8bJ92nw.js +0 -22207
  228. package/dist/assets/yaml.worker-C4gyGAko.js +0 -50201
  229. package/dist/chunks/PageHeader-0kG_iypP.js +0 -692
  230. package/dist/chunks/SwitchToggle-DShNdcao.js +0 -758
  231. package/dist/chunks/editor-Dk1rbV75.js +0 -361
  232. package/dist/chunks/list-CJm875m7.js +0 -1418
  233. /package/dist/{chunks/MarkdownImpl-CyeTVvSt.js → components/MarkdownImpl.js} +0 -0
@@ -0,0 +1,210 @@
1
+ import { usePersistedState, useStrings } from "../components/Provider.js";
2
+ import { actionsColumnWidth } from "./ListTable.js";
3
+ import { useCallback, useMemo } from "react";
4
+ //#region src/list/listView.tsx
5
+ var PRIORITY_SHOW_CLASS = {
6
+ low: "hidden @[52rem]:table-cell",
7
+ medium: "hidden @[36rem]:table-cell"
8
+ };
9
+ function columnResponsiveClass(col) {
10
+ return col.priority ? PRIORITY_SHOW_CLASS[col.priority] : "";
11
+ }
12
+ var DEFAULT_ORDER = "__default";
13
+ var FAVORITE_ORDER = "__favorite";
14
+ /** Persisted grouping + column-visibility + field-filter state for a list page,
15
+ * driving the shared Display/Filter menus. */
16
+ function useListView({ storageKey, sharedFiltersKey, columns, groupBys = [], defaultGroupBy, orderBys = [], defaultOrderBy, facets = [], actions = [], actionCount, defaultShowColumnHeaders = false, defaultShowActions = true, isFavorite, isOn, createdAt }) {
17
+ const t = useStrings().list;
18
+ const tiebreak = orderBys[0]?.compare;
19
+ const effectiveOrderBys = useMemo(() => {
20
+ if (!isFavorite) return orderBys;
21
+ const favoriteRank = (row) => isFavorite(row) ? 0 : 1;
22
+ const onRank = (row) => isOn?.(row) ? 0 : 1;
23
+ const createdMs = (row) => {
24
+ const v = createdAt?.(row);
25
+ return v === null || v === void 0 || Number.isNaN(v) ? 0 : v;
26
+ };
27
+ const newestFirst = (a, b) => createdMs(b) - createdMs(a);
28
+ return [...[{
29
+ value: DEFAULT_ORDER,
30
+ label: t.orderDefault,
31
+ compare: (a, b) => onRank(a) - onRank(b) || favoriteRank(a) - favoriteRank(b) || newestFirst(a, b) || (tiebreak?.(a, b) ?? 0)
32
+ }, {
33
+ value: FAVORITE_ORDER,
34
+ label: t.orderFavorites,
35
+ compare: (a, b) => favoriteRank(a) - favoriteRank(b) || (tiebreak?.(a, b) ?? 0)
36
+ }], ...orderBys];
37
+ }, [
38
+ orderBys,
39
+ isFavorite,
40
+ isOn,
41
+ createdAt,
42
+ tiebreak,
43
+ t
44
+ ]);
45
+ const defaultGroupByValue = defaultGroupBy ?? groupBys[0]?.value ?? "";
46
+ const defaultOrderByValue = isFavorite ? DEFAULT_ORDER : defaultOrderBy ?? orderBys[0]?.value ?? "";
47
+ const defaultHiddenKeys = useMemo(() => columns.filter((c) => c.defaultHidden && !c.alwaysVisible).map((c) => c.key), [columns]);
48
+ const defaultPinnedKeys = useMemo(() => actions.filter((a) => a.defaultPinned).map((a) => a.key), [actions]);
49
+ const [hiddenKeys, setHiddenKeys] = usePersistedState(`${storageKey}:hiddenColumns`, defaultHiddenKeys);
50
+ const [pinnedKeys, setPinnedKeys] = usePersistedState(`${storageKey}:pinnedActions`, defaultPinnedKeys);
51
+ const [groupBy, setGroupBy] = usePersistedState(`${storageKey}:groupBy`, defaultGroupByValue);
52
+ const [showColumnHeaders, setShowColumnHeaders] = usePersistedState(`${storageKey}:showColumnHeaders`, defaultShowColumnHeaders);
53
+ const [showActions, setShowActions] = usePersistedState(`${storageKey}:showActions`, defaultShowActions);
54
+ const [alwaysShowActions, setAlwaysShowActions] = usePersistedState(`${storageKey}:alwaysShowActions`, false);
55
+ const [orderBy, setOrderBy] = usePersistedState(`${storageKey}:orderBy`, defaultOrderByValue);
56
+ const [orderDir, setOrderDir] = usePersistedState(`${storageKey}:orderDir`, "asc");
57
+ const [localFilters, setLocalFilters] = usePersistedState(`${storageKey}:filters`, {});
58
+ const [sharedFilters, setSharedFilters] = usePersistedState(`${sharedFiltersKey ?? storageKey}:sharedFilters`, {});
59
+ const sharedKeys = useMemo(() => new Set(facets.filter((f) => f.shared).map((f) => f.key)), [facets]);
60
+ const filters = useMemo(() => {
61
+ if (sharedKeys.size === 0) return localFilters;
62
+ const merged = {};
63
+ for (const [key, values] of Object.entries(localFilters)) if (!sharedKeys.has(key)) merged[key] = values;
64
+ for (const key of sharedKeys) {
65
+ const values = sharedFilters[key];
66
+ if (values?.length) merged[key] = values;
67
+ }
68
+ return merged;
69
+ }, [
70
+ localFilters,
71
+ sharedFilters,
72
+ sharedKeys
73
+ ]);
74
+ const pinnedCount = actionCount ?? pinnedKeys.filter((key) => actions.some((action) => action.key === key)).length;
75
+ const effectiveShowActions = showActions || alwaysShowActions;
76
+ const actionsWidth = effectiveShowActions ? actionsColumnWidth(pinnedCount) : 0;
77
+ const isVisible = useCallback((key) => {
78
+ const col = columns.find((c) => c.key === key);
79
+ return Boolean(col?.alwaysVisible) || !hiddenKeys.includes(key);
80
+ }, [columns, hiddenKeys]);
81
+ const visibleColumns = useMemo(() => columns.filter((c) => !c.inline && (c.alwaysVisible || !hiddenKeys.includes(c.key))), [columns, hiddenKeys]);
82
+ const columnClasses = useMemo(() => visibleColumns.map(columnResponsiveClass), [visibleColumns]);
83
+ const toggleColumn = useCallback((key) => setHiddenKeys((prev) => prev.includes(key) ? prev.filter((k) => k !== key) : [...prev, key]), [setHiddenKeys]);
84
+ const setFacetValues = useCallback((key, values) => {
85
+ const update = (prev) => {
86
+ const next = { ...prev };
87
+ if (values.length) next[key] = values;
88
+ else delete next[key];
89
+ return next;
90
+ };
91
+ if (sharedKeys.has(key)) setSharedFilters(update);
92
+ else setLocalFilters(update);
93
+ }, [
94
+ setLocalFilters,
95
+ setSharedFilters,
96
+ sharedKeys
97
+ ]);
98
+ const clearFilters = useCallback(() => {
99
+ setLocalFilters({});
100
+ if (sharedKeys.size > 0) setSharedFilters((prev) => {
101
+ const next = { ...prev };
102
+ for (const key of sharedKeys) delete next[key];
103
+ return next;
104
+ });
105
+ }, [
106
+ setLocalFilters,
107
+ setSharedFilters,
108
+ sharedKeys
109
+ ]);
110
+ const isPinned = useCallback((key) => pinnedKeys.includes(key), [pinnedKeys]);
111
+ const togglePinned = useCallback((key) => setPinnedKeys((prev) => prev.includes(key) ? prev.filter((k) => k !== key) : [...prev, key]), [setPinnedKeys]);
112
+ const toggleColumnHeaders = useCallback(() => setShowColumnHeaders((prev) => !prev), [setShowColumnHeaders]);
113
+ const toggleShowActions = useCallback(() => {
114
+ if (effectiveShowActions) {
115
+ setShowActions(false);
116
+ setAlwaysShowActions(false);
117
+ } else setShowActions(true);
118
+ }, [
119
+ effectiveShowActions,
120
+ setShowActions,
121
+ setAlwaysShowActions
122
+ ]);
123
+ const toggleAlwaysShowActions = useCallback(() => {
124
+ const next = !alwaysShowActions;
125
+ setAlwaysShowActions(next);
126
+ if (next) setShowActions(true);
127
+ }, [
128
+ alwaysShowActions,
129
+ setAlwaysShowActions,
130
+ setShowActions
131
+ ]);
132
+ const toggleOrderDir = useCallback(() => setOrderDir((d) => d === "asc" ? "desc" : "asc"), [setOrderDir]);
133
+ const applyOrder = useCallback((rows) => {
134
+ const opt = effectiveOrderBys.find((o) => o.value === orderBy);
135
+ if (!opt) return rows;
136
+ const sign = orderDir === "asc" ? 1 : -1;
137
+ return [...rows].sort((a, b) => opt.compare(a, b) * sign);
138
+ }, [
139
+ effectiveOrderBys,
140
+ orderBy,
141
+ orderDir
142
+ ]);
143
+ const sameKeys = (a, b) => a.length === b.length && a.every((k) => b.includes(k));
144
+ const isDisplayDefault = groupBy === defaultGroupByValue && orderBy === defaultOrderByValue && orderDir === "asc" && showColumnHeaders === defaultShowColumnHeaders && showActions === defaultShowActions && alwaysShowActions === false && sameKeys(hiddenKeys, defaultHiddenKeys) && sameKeys(pinnedKeys, defaultPinnedKeys);
145
+ const resetDisplay = useCallback(() => {
146
+ setGroupBy(defaultGroupByValue);
147
+ setOrderBy(defaultOrderByValue);
148
+ setOrderDir("asc");
149
+ setShowColumnHeaders(defaultShowColumnHeaders);
150
+ setShowActions(defaultShowActions);
151
+ setAlwaysShowActions(false);
152
+ setHiddenKeys(defaultHiddenKeys);
153
+ setPinnedKeys(defaultPinnedKeys);
154
+ }, [
155
+ setGroupBy,
156
+ setOrderBy,
157
+ setOrderDir,
158
+ defaultOrderByValue,
159
+ setShowColumnHeaders,
160
+ setShowActions,
161
+ setAlwaysShowActions,
162
+ setHiddenKeys,
163
+ setPinnedKeys,
164
+ defaultGroupByValue,
165
+ defaultHiddenKeys,
166
+ defaultPinnedKeys,
167
+ defaultShowColumnHeaders,
168
+ defaultShowActions
169
+ ]);
170
+ return {
171
+ columns,
172
+ visibleColumns,
173
+ columnClasses,
174
+ isVisible,
175
+ pinnedCount,
176
+ actionsWidth,
177
+ toggleColumn,
178
+ groupBys,
179
+ groupBy,
180
+ setGroupBy,
181
+ orderBys: effectiveOrderBys,
182
+ orderBy,
183
+ setOrderBy,
184
+ orderDir,
185
+ toggleOrderDir,
186
+ applyOrder,
187
+ facets,
188
+ filters,
189
+ setFacetValues,
190
+ clearFilters,
191
+ activeFilterCount: useMemo(() => Object.values(filters).filter((v) => v && v.length > 0).length, [filters]),
192
+ applyFilters: useCallback((rows) => rows.filter((row) => facets.every((f) => {
193
+ const selected = filters[f.key];
194
+ return !selected || selected.length === 0 ? true : f.matches(row, selected);
195
+ })), [facets, filters]),
196
+ actions,
197
+ isPinned,
198
+ togglePinned,
199
+ showColumnHeaders,
200
+ toggleColumnHeaders,
201
+ showActions: effectiveShowActions,
202
+ toggleShowActions,
203
+ alwaysShowActions,
204
+ toggleAlwaysShowActions,
205
+ isDisplayDefault,
206
+ resetDisplay
207
+ };
208
+ }
209
+ //#endregion
210
+ export { DEFAULT_ORDER, FAVORITE_ORDER, useListView };
@@ -0,0 +1,10 @@
1
+ //#region src/list/textEntry.ts
2
+ /** Guards list-page shortcuts from firing inside inputs, terminals, editors, and dialogs. */
3
+ function isTextEntryContext(target) {
4
+ const el = target;
5
+ if (!el) return false;
6
+ if (el.tagName === "INPUT" || el.tagName === "TEXTAREA" || el.isContentEditable) return true;
7
+ return Boolean(el.closest?.(".xterm, .monaco-editor, .cm-editor, [role=\"dialog\"]"));
8
+ }
9
+ //#endregion
10
+ export { isTextEntryContext };
@@ -1,89 +1,11 @@
1
- import { a as useOptionalWorkflowEngine, i as useNotify, u as useStrings } from "./Provider-CDYurraE.js";
1
+ import { useNotify, useOptionalWorkflowEngine, useStrings } from "../components/Provider.js";
2
2
  import { ArrowDownIcon, ArrowUpIcon, CheckIcon, ChevronDownIcon, ChevronRightIcon, ClockIcon, CopyIcon, DownloadIcon, ExpandIcon, ShrinkIcon, XIcon } from "../icons.js";
3
- import { r as TooltipInfo } from "./Tooltip-K5HJr4_p.js";
3
+ import { TooltipInfo } from "../components/Tooltip.js";
4
+ import { highlightSegments, parseAnsiSegments, plainSegments } from "./segments.js";
4
5
  import cx from "classnames";
5
6
  import { Fragment, memo, useCallback, useEffect, useLayoutEffect, useMemo, useRef, useState } from "react";
6
7
  import { Fragment as Fragment$1, jsx, jsxs } from "react/jsx-runtime";
7
8
  import { DateTime } from "luxon";
8
- import Anser from "anser";
9
- //#region src/logviewer/segments.ts
10
- function segmentClassName(chunk) {
11
- const classes = [];
12
- if (chunk.fg) classes.push(`${chunk.fg}-fg`);
13
- if (chunk.bg) classes.push(`${chunk.bg}-bg`);
14
- for (const decoration of chunk.decorations) classes.push(`ansi-${decoration}`);
15
- return classes.join(" ");
16
- }
17
- function parseAnsiSegments(line) {
18
- return Anser.ansiToJson(line, {
19
- use_classes: true,
20
- remove_empty: true
21
- }).map((chunk) => ({
22
- content: chunk.content,
23
- className: segmentClassName(chunk)
24
- }));
25
- }
26
- function plainSegments(text) {
27
- return [{
28
- content: text,
29
- className: ""
30
- }];
31
- }
32
- /**
33
- * Matches are located on the concatenated line text so a term straddling an
34
- * ANSI colour boundary still highlights, then sliced back onto the segments it
35
- * covers.
36
- */
37
- function highlightSegments(segments, searchTerm) {
38
- if (!searchTerm) return segments;
39
- const haystack = segments.map((segment) => segment.content).join("").toLowerCase();
40
- const needle = searchTerm.toLowerCase();
41
- if (!haystack.includes(needle)) return segments;
42
- const matchStarts = [];
43
- let found = haystack.indexOf(needle);
44
- while (found !== -1) {
45
- matchStarts.push(found);
46
- found = haystack.indexOf(needle, found + needle.length);
47
- }
48
- const result = [];
49
- let matchIndex = 0;
50
- let offset = 0;
51
- for (const segment of segments) {
52
- const segmentEnd = offset + segment.content.length;
53
- let cursor = offset;
54
- while (cursor < segmentEnd) {
55
- let matchStart = matchStarts[matchIndex];
56
- while (matchStart !== void 0 && matchStart + needle.length <= cursor) {
57
- matchIndex++;
58
- matchStart = matchStarts[matchIndex];
59
- }
60
- if (matchStart === void 0 || matchStart >= segmentEnd) {
61
- result.push({
62
- ...segment,
63
- content: segment.content.slice(cursor - offset)
64
- });
65
- break;
66
- }
67
- if (matchStart > cursor) {
68
- result.push({
69
- ...segment,
70
- content: segment.content.slice(cursor - offset, matchStart - offset)
71
- });
72
- cursor = matchStart;
73
- }
74
- const matchEnd = Math.min(matchStart + needle.length, segmentEnd);
75
- result.push({
76
- ...segment,
77
- content: segment.content.slice(cursor - offset, matchEnd - offset),
78
- highlighted: true
79
- });
80
- cursor = matchEnd;
81
- }
82
- offset = segmentEnd;
83
- }
84
- return result;
85
- }
86
- //#endregion
87
9
  //#region src/logviewer/LogViewer.tsx
88
10
  function LogSegments({ segments }) {
89
11
  return segments.map((segment, i) => segment.highlighted ? /* @__PURE__ */ jsx("mark", {
@@ -825,4 +747,4 @@ function LogViewer({ log, height = "unset", width, roundedBottom = false, lineNu
825
747
  });
826
748
  }
827
749
  //#endregion
828
- export { plainSegments as i, highlightSegments as n, parseAnsiSegments as r, LogViewer as t };
750
+ export { LogViewer };
@@ -1,2 +1,3 @@
1
- import { i as plainSegments, n as highlightSegments, r as parseAnsiSegments, t as LogViewer } from "../chunks/logviewer-BTKuQWzw.js";
1
+ import { highlightSegments, parseAnsiSegments, plainSegments } from "./segments.js";
2
+ import { LogViewer } from "./LogViewer.js";
2
3
  export { LogViewer, highlightSegments, parseAnsiSegments, plainSegments };
@@ -0,0 +1,80 @@
1
+ import Anser from "anser";
2
+ //#region src/logviewer/segments.ts
3
+ function segmentClassName(chunk) {
4
+ const classes = [];
5
+ if (chunk.fg) classes.push(`${chunk.fg}-fg`);
6
+ if (chunk.bg) classes.push(`${chunk.bg}-bg`);
7
+ for (const decoration of chunk.decorations) classes.push(`ansi-${decoration}`);
8
+ return classes.join(" ");
9
+ }
10
+ function parseAnsiSegments(line) {
11
+ return Anser.ansiToJson(line, {
12
+ use_classes: true,
13
+ remove_empty: true
14
+ }).map((chunk) => ({
15
+ content: chunk.content,
16
+ className: segmentClassName(chunk)
17
+ }));
18
+ }
19
+ function plainSegments(text) {
20
+ return [{
21
+ content: text,
22
+ className: ""
23
+ }];
24
+ }
25
+ /**
26
+ * Matches are located on the concatenated line text so a term straddling an
27
+ * ANSI colour boundary still highlights, then sliced back onto the segments it
28
+ * covers.
29
+ */
30
+ function highlightSegments(segments, searchTerm) {
31
+ if (!searchTerm) return segments;
32
+ const haystack = segments.map((segment) => segment.content).join("").toLowerCase();
33
+ const needle = searchTerm.toLowerCase();
34
+ if (!haystack.includes(needle)) return segments;
35
+ const matchStarts = [];
36
+ let found = haystack.indexOf(needle);
37
+ while (found !== -1) {
38
+ matchStarts.push(found);
39
+ found = haystack.indexOf(needle, found + needle.length);
40
+ }
41
+ const result = [];
42
+ let matchIndex = 0;
43
+ let offset = 0;
44
+ for (const segment of segments) {
45
+ const segmentEnd = offset + segment.content.length;
46
+ let cursor = offset;
47
+ while (cursor < segmentEnd) {
48
+ let matchStart = matchStarts[matchIndex];
49
+ while (matchStart !== void 0 && matchStart + needle.length <= cursor) {
50
+ matchIndex++;
51
+ matchStart = matchStarts[matchIndex];
52
+ }
53
+ if (matchStart === void 0 || matchStart >= segmentEnd) {
54
+ result.push({
55
+ ...segment,
56
+ content: segment.content.slice(cursor - offset)
57
+ });
58
+ break;
59
+ }
60
+ if (matchStart > cursor) {
61
+ result.push({
62
+ ...segment,
63
+ content: segment.content.slice(cursor - offset, matchStart - offset)
64
+ });
65
+ cursor = matchStart;
66
+ }
67
+ const matchEnd = Math.min(matchStart + needle.length, segmentEnd);
68
+ result.push({
69
+ ...segment,
70
+ content: segment.content.slice(cursor - offset, matchEnd - offset),
71
+ highlighted: true
72
+ });
73
+ cursor = matchEnd;
74
+ }
75
+ offset = segmentEnd;
76
+ }
77
+ return result;
78
+ }
79
+ //#endregion
80
+ export { highlightSegments, parseAnsiSegments, plainSegments };
@@ -0,0 +1,6 @@
1
+ /**
2
+ * Returns url when following it cannot run script in the app's origin: a
3
+ * relative path or an http, https or blob URL. Hosts and servers supply these
4
+ * URLs, so a javascript: URL from either would otherwise run when clicked.
5
+ */
6
+ export declare function safeUrl(url: string | null | undefined): string | undefined;
@@ -0,0 +1,22 @@
1
+ //#region src/safeUrl.ts
2
+ var SAFE_PROTOCOLS = /* @__PURE__ */ new Set([
3
+ "http:",
4
+ "https:",
5
+ "blob:"
6
+ ]);
7
+ /**
8
+ * Returns url when following it cannot run script in the app's origin: a
9
+ * relative path or an http, https or blob URL. Hosts and servers supply these
10
+ * URLs, so a javascript: URL from either would otherwise run when clicked.
11
+ */
12
+ function safeUrl(url) {
13
+ if (!url) return;
14
+ try {
15
+ const { protocol } = new URL(url, "https://relative.invalid");
16
+ return SAFE_PROTOCOLS.has(protocol) ? url : void 0;
17
+ } catch {
18
+ return;
19
+ }
20
+ }
21
+ //#endregion
22
+ export { safeUrl };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@parallelworks/ui",
3
- "version": "0.19.0",
3
+ "version": "0.20.0",
4
4
  "description": "React UI components: a theme contract, icons, primitives, lists, forms, a job graph, a code editor, a log viewer, a file explorer and an AI chat, each on its own subpath",
5
5
  "license": "Apache-2.0",
6
6
  "repository": {
@@ -76,8 +76,7 @@
76
76
  ],
77
77
  "peerDependencies": {
78
78
  "formik": "^2.4.9",
79
- "monaco-editor": "^0.55.1",
80
- "monaco-yaml": "^5.5.1",
79
+ "monaco-editor": "^0.57.0",
81
80
  "react": "^19.0.0",
82
81
  "react-dom": "^19.0.0"
83
82
  },
@@ -123,23 +122,22 @@
123
122
  "@vitejs/plugin-react": "^6.0.2",
124
123
  "formik": "^2.4.9",
125
124
  "jsdom": "^26.1.0",
126
- "monaco-editor": "^0.55.1",
127
- "monaco-yaml": "^5.5.1",
125
+ "monaco-editor": "^0.57.0",
126
+ "path-browserify": "^1.0.1",
128
127
  "publint": "^0.3.14",
129
128
  "react": "19.3.0",
130
129
  "react-dom": "19.3.0",
131
130
  "storybook": "10.5.8",
132
131
  "tailwindcss": "^4.3.0",
133
132
  "typescript": "^7.0.0",
133
+ "url": "^0.11.4",
134
134
  "vite": "^8.0.16",
135
- "vitest": "^4.1.8"
135
+ "vitest": "^4.1.8",
136
+ "yaml-language-server": "^1.24.0"
136
137
  },
137
138
  "peerDependenciesMeta": {
138
139
  "monaco-editor": {
139
140
  "optional": true
140
- },
141
- "monaco-yaml": {
142
- "optional": true
143
141
  }
144
142
  },
145
143
  "scripts": {