@parallelworks/ui 0.77.0 → 0.79.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.
- package/README.md +42 -6
- package/dist/access/AccessDrawer.d.ts +49 -7
- package/dist/access/AccessDrawer.js +243 -38
- package/dist/access/AccessList.d.ts +19 -1
- package/dist/access/AccessList.js +220 -9
- package/dist/access/GrantView.d.ts +3 -1
- package/dist/access/GrantView.js +17 -4
- package/dist/access/PrincipalPicker.js +5 -5
- package/dist/access/focus.js +1 -1
- package/dist/access/index.d.ts +2 -2
- package/dist/access/index.js +2 -2
- package/dist/access/strings.d.ts +25 -1
- package/dist/access/strings.js +27 -3
- package/dist/access/types.d.ts +26 -0
- package/dist/ai/components/AllocationSelector.js +1 -1
- package/dist/ai/components/AttachmentManager.js +5 -5
- package/dist/ai/components/AttachmentUpload.js +2 -2
- package/dist/ai/components/BranchNavigator.js +1 -1
- package/dist/ai/components/ChatActivity.js +1 -1
- package/dist/ai/components/ChatEmptyState.js +3 -3
- package/dist/ai/components/ChatInput.js +3 -5
- package/dist/ai/components/ChatLayout.js +1 -1
- package/dist/ai/components/ChatMessage.js +1 -1
- package/dist/ai/components/ChatMessageList.js +23 -8
- package/dist/ai/components/ChatSidebar.js +3 -3
- package/dist/ai/components/ChatThread.js +4 -4
- package/dist/ai/components/ComposerAddMenu.js +9 -20
- package/dist/ai/components/ModelSelector.js +3 -3
- package/dist/ai/components/PastedText.js +5 -5
- package/dist/ai/components/SessionView.js +1 -1
- package/dist/ai/components/ShareDialog.js +3 -3
- package/dist/ai/components/SlashMenu.d.ts +31 -4
- package/dist/ai/components/SlashMenu.js +36 -63
- package/dist/ai/components/agent/ActivityLine.js +1 -1
- package/dist/ai/components/agent/AgentMessageParts.js +13 -13
- package/dist/ai/components/conversationActions.js +3 -3
- package/dist/ai/core/ChatProvider.js +1 -1
- package/dist/ai/core/config.js +1 -1
- package/dist/ai/ui/ConversationSidebar.js +3 -3
- package/dist/ai/ui/sidebar.js +3 -3
- package/dist/assets/yaml.worker-DOBV2lND.js +884 -0
- package/dist/components/ActionMenu.d.ts +38 -9
- package/dist/components/ActionMenu.js +48 -22
- package/dist/components/Avatar.d.ts +66 -6
- package/dist/components/Avatar.js +130 -18
- package/dist/components/Breadcrumbs.d.ts +4 -0
- package/dist/components/Breadcrumbs.js +26 -10
- package/dist/components/Button.d.ts +3 -2
- package/dist/components/Button.js +11 -1
- package/dist/components/Callout.d.ts +3 -2
- package/dist/components/Callout.js +3 -2
- package/dist/components/Card.d.ts +33 -9
- package/dist/components/Card.js +24 -8
- package/dist/components/Checkbox.d.ts +3 -1
- package/dist/components/Checkbox.js +4 -2
- package/dist/components/ColorInput.js +1 -1
- package/dist/components/Combobox.d.ts +23 -0
- package/dist/components/Combobox.js +252 -86
- package/dist/components/ConfirmModal.d.ts +28 -2
- package/dist/components/ConfirmModal.js +100 -15
- package/dist/components/ContextMenu.d.ts +29 -2
- package/dist/components/ContextMenu.js +60 -8
- package/dist/components/CopyButton.d.ts +21 -8
- package/dist/components/CopyButton.js +29 -9
- package/dist/components/CreateModal.d.ts +20 -4
- package/dist/components/CreateModal.js +28 -17
- package/dist/components/DatePicker.d.ts +31 -1
- package/dist/components/DatePicker.js +178 -47
- package/dist/components/DescriptionList.d.ts +13 -3
- package/dist/components/DescriptionList.js +43 -11
- package/dist/components/Disclosure.d.ts +10 -2
- package/dist/components/Disclosure.js +18 -7
- package/dist/components/Drawer.js +5 -5
- package/dist/components/EmptyState.d.ts +12 -4
- package/dist/components/EmptyState.js +18 -10
- package/dist/components/ErrorPage.d.ts +40 -0
- package/dist/components/ErrorPage.js +101 -0
- package/dist/components/ExternalLink.d.ts +4 -1
- package/dist/components/ExternalLink.js +4 -5
- package/dist/components/Field.d.ts +21 -6
- package/dist/components/Field.js +32 -16
- package/dist/components/FileButton.d.ts +19 -0
- package/dist/components/FileButton.js +32 -0
- package/dist/components/HoverCard.d.ts +26 -6
- package/dist/components/HoverCard.js +11 -5
- package/dist/components/IconButton.js +4 -2
- package/dist/components/InfoTip.js +3 -3
- package/dist/components/Input.d.ts +33 -3
- package/dist/components/Input.js +149 -14
- package/dist/components/Kbd.d.ts +40 -0
- package/dist/components/Kbd.js +168 -0
- package/dist/components/Listbox.d.ts +103 -0
- package/dist/components/Listbox.js +190 -0
- package/dist/components/Loader.d.ts +8 -2
- package/dist/components/Loader.js +16 -1
- package/dist/components/Markdown.js +1 -1
- package/dist/components/MarkdownImpl.js +1 -1
- package/dist/components/Menu.d.ts +20 -2
- package/dist/components/Menu.js +48 -19
- package/dist/components/MenuEntries.d.ts +41 -4
- package/dist/components/MenuEntries.js +266 -39
- package/dist/components/Meter.d.ts +50 -11
- package/dist/components/Meter.js +71 -21
- package/dist/components/Modal.d.ts +9 -3
- package/dist/components/Modal.js +68 -29
- package/dist/components/OneTimeCodeInput.js +1 -1
- package/dist/components/PageHeader.js +111 -7
- package/dist/components/PageHeaderAction.d.ts +8 -3
- package/dist/components/PageHeaderAction.js +122 -34
- package/dist/components/Pagination.d.ts +13 -1
- package/dist/components/Pagination.js +90 -19
- package/dist/components/Popover.d.ts +16 -2
- package/dist/components/Popover.js +20 -21
- package/dist/components/Provider.d.ts +172 -5
- package/dist/components/Provider.js +157 -14
- package/dist/components/RefreshButton.d.ts +13 -6
- package/dist/components/RefreshButton.js +17 -9
- package/dist/components/RunStatusIcon.d.ts +16 -7
- package/dist/components/RunStatusIcon.js +21 -8
- package/dist/components/Section.d.ts +11 -4
- package/dist/components/Section.js +33 -22
- package/dist/components/SegmentedControl.d.ts +16 -3
- package/dist/components/SegmentedControl.js +7 -3
- package/dist/components/Select.d.ts +19 -3
- package/dist/components/Select.js +114 -68
- package/dist/components/SelectionCopy.d.ts +10 -0
- package/dist/components/SelectionCopy.js +105 -0
- package/dist/components/SettingModeOption.js +1 -1
- package/dist/components/SettingsCard.js +1 -1
- package/dist/components/Skeleton.js +1 -1
- package/dist/components/StatusBadge.d.ts +55 -10
- package/dist/components/StatusBadge.js +91 -15
- package/dist/components/StickyBar.js +1 -1
- package/dist/components/Table.d.ts +22 -4
- package/dist/components/Table.js +46 -24
- package/dist/components/Tabs.d.ts +9 -4
- package/dist/components/Tabs.js +9 -4
- package/dist/components/Tag.d.ts +49 -0
- package/dist/components/Tag.js +199 -0
- package/dist/components/ThemeEditor.js +1 -1
- package/dist/components/Toast.js +1 -1
- package/dist/components/ToggleGroup.d.ts +4 -1
- package/dist/components/ToggleGroup.js +30 -13
- package/dist/components/Tooltip.d.ts +9 -3
- package/dist/components/Tooltip.js +55 -39
- package/dist/components/buttonClasses.d.ts +5 -2
- package/dist/components/buttonClasses.js +11 -10
- package/dist/components/chart.d.ts +69 -0
- package/dist/components/chart.js +145 -0
- package/dist/components/comboboxItems.d.ts +7 -1
- package/dist/components/comboboxItems.js +6 -2
- package/dist/components/dismiss.d.ts +5 -1
- package/dist/components/dismiss.js +6 -2
- package/dist/components/floating.d.ts +4 -4
- package/dist/components/floating.js +5 -5
- package/dist/components/headerActionsFit.d.ts +37 -0
- package/dist/components/headerActionsFit.js +81 -0
- package/dist/components/pageHeaderStore.d.ts +3 -0
- package/dist/components/pageHeaderStore.js +3 -0
- package/dist/components/pathBreaks.js +2 -2
- package/dist/components/popupContainer.d.ts +17 -0
- package/dist/components/popupContainer.js +69 -0
- package/dist/components/relativeTime.d.ts +21 -10
- package/dist/components/relativeTime.js +50 -22
- package/dist/components/segmented.d.ts +18 -4
- package/dist/components/segmented.js +48 -6
- package/dist/components/typedDate.d.ts +5 -0
- package/dist/components/typedDate.js +50 -0
- package/dist/components/useClosingValue.d.ts +4 -0
- package/dist/components/useClosingValue.js +12 -0
- package/dist/components/useCopy.d.ts +6 -0
- package/dist/components/useCopy.js +3 -3
- package/dist/components/useNarrow.d.ts +2 -0
- package/dist/components/useNarrow.js +16 -0
- package/dist/editor/Editor.js +1 -1
- package/dist/editor/FormCodePanel.js +1 -1
- package/dist/editor/Monaco.js +1 -1
- package/dist/editor/workers.js +1 -1
- package/dist/file-explorer/FileExplorer.js +16 -15
- package/dist/file-explorer/FileExplorerContext.js +2 -2
- package/dist/file-explorer/FilePreview/Viewer.js +3 -3
- package/dist/file-explorer/FilePreview/index.js +2 -2
- package/dist/file-explorer/FileRowsWindow.js +3 -3
- package/dist/file-explorer/FileTable.js +1 -1
- package/dist/file-explorer/LoadMoreRow.js +1 -1
- package/dist/file-explorer/TreeView.js +5 -5
- package/dist/file-explorer/helpers.js +2 -2
- package/dist/file-explorer/toasts.js +2 -2
- package/dist/form/Fields/CheckboxGroupField.js +1 -1
- package/dist/form/Fields/DropdownField.js +1 -1
- package/dist/form/Fields/DurationField.js +2 -2
- package/dist/form/Fields/MultiDropdownField.js +1 -1
- package/dist/form/Fields/NumberField.js +1 -1
- package/dist/form/Fields/ObjectField.js +1 -1
- package/dist/form/Fields/RangeField.js +1 -1
- package/dist/form/Fields/StringField.js +1 -1
- package/dist/form/Form.js +3 -3
- package/dist/form/FormLayout.js +1 -1
- package/dist/form/Wizard/WizardContainer.js +1 -1
- package/dist/form/Wizard/WizardNavigation.js +1 -1
- package/dist/form/Wizard/WizardStepContent.js +1 -1
- package/dist/form/fieldRegistry.js +1 -1
- package/dist/form/formEditing.js +1 -1
- package/dist/format.d.ts +17 -7
- package/dist/format.js +39 -16
- package/dist/graph/AnnotationBanner.js +2 -2
- package/dist/graph/Connectors.js +5 -5
- package/dist/graph/DependencyGraph.js +10 -9
- package/dist/graph/GraphEditor.js +4 -4
- package/dist/graph/GraphEditorDialogs.js +13 -12
- package/dist/graph/GraphNode.js +1 -1
- package/dist/graph/InputDialog.js +5 -5
- package/dist/graph/InputsEditor.js +10 -9
- package/dist/graph/MatrixGroup.js +2 -2
- package/dist/graph/ProblemPageLink.d.ts +9 -0
- package/dist/graph/ProblemPageLink.js +21 -0
- package/dist/graph/ProblemsButton.js +26 -16
- package/dist/graph/Reveal.js +1 -1
- package/dist/graph/RunWarningsList.js +21 -12
- package/dist/graph/ShortcutsButton.js +25 -8
- package/dist/graph/StepSummaries.js +1 -1
- package/dist/graph/TreeView.js +2 -2
- package/dist/graph/WorkflowSettingsDialog.js +3 -3
- package/dist/graph/editorApi.d.ts +10 -0
- package/dist/graph/editorFields.js +3 -3
- package/dist/graph/editorPrimitives.js +1 -1
- package/dist/graph/editorRows.js +8 -6
- package/dist/graph/editorStrings.d.ts +1 -0
- package/dist/graph/editorStrings.js +1 -0
- package/dist/graph/fieldProblems.js +2 -2
- package/dist/graph/inputRefs.js +7 -6
- package/dist/graph/runWarnings.d.ts +12 -1
- package/dist/graph/stepWith.js +2 -2
- package/dist/index.d.ts +30 -21
- package/dist/index.js +20 -12
- package/dist/list/ActionToolbar.d.ts +4 -0
- package/dist/list/ActionToolbar.js +35 -12
- package/dist/list/ListFilterBar.d.ts +42 -0
- package/dist/list/ListFilterBar.js +789 -0
- package/dist/list/ListPage.d.ts +42 -4
- package/dist/list/ListPage.js +56 -22
- package/dist/list/ListTable.d.ts +27 -3
- package/dist/list/ListTable.js +48 -23
- package/dist/list/ListToolbar.d.ts +31 -0
- package/dist/list/ListToolbar.js +43 -0
- package/dist/list/ListViewControls.d.ts +8 -4
- package/dist/list/ListViewControls.js +22 -14
- package/dist/list/UserHoverCard.d.ts +8 -2
- package/dist/list/UserHoverCard.js +26 -13
- package/dist/list/filterModel.d.ts +122 -0
- package/dist/list/filterModel.js +308 -0
- package/dist/list/index.d.ts +6 -2
- package/dist/list/index.js +6 -2
- package/dist/list/listSearch.d.ts +1 -1
- package/dist/list/listSearch.js +8 -4
- package/dist/list/listView.d.ts +24 -2
- package/dist/list/listView.js +47 -45
- package/dist/list/rowMenu.d.ts +10 -5
- package/dist/list/rowMenu.js +17 -7
- package/dist/list/useListFilters.d.ts +68 -0
- package/dist/list/useListFilters.js +252 -0
- package/dist/logviewer/LogViewer.js +4 -4
- package/dist/styles/theme.css +94 -0
- package/dist/styles.css +1 -1
- package/package.json +11 -11
- package/dist/assets/yaml.worker-k9AdOqzf.js +0 -1441
- package/dist/components/fullscreen.d.ts +0 -4
- package/dist/components/fullscreen.js +0 -18
package/dist/list/listView.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { usePersistedState, useStrings } from "../components/Provider.js";
|
|
2
2
|
import { actionsColumnWidth } from "./ListTable.js";
|
|
3
|
+
import { useListFilters } from "./useListFilters.js";
|
|
3
4
|
import { useCallback, useMemo } from "react";
|
|
4
5
|
//#region src/list/listView.tsx
|
|
5
6
|
var PRIORITY_SHOW_CLASS = {
|
|
@@ -14,11 +15,16 @@ function columnResponsiveClass(col, i) {
|
|
|
14
15
|
if (stacks(col, i)) return PRIORITY_SHOW_CLASS.medium;
|
|
15
16
|
return col.priority ? PRIORITY_SHOW_CLASS[col.priority] : "";
|
|
16
17
|
}
|
|
18
|
+
/** A column's classes for its header and every cell: when it shows, and how it aligns. */
|
|
19
|
+
function columnClass(col, i) {
|
|
20
|
+
const show = columnResponsiveClass(col, i);
|
|
21
|
+
return col.align === "end" ? show ? `${show} text-right` : "text-right" : show;
|
|
22
|
+
}
|
|
17
23
|
var DEFAULT_ORDER = "__default";
|
|
18
24
|
var FAVORITE_ORDER = "__favorite";
|
|
19
25
|
/** Persisted grouping + column-visibility + field-filter state for a list page,
|
|
20
26
|
* driving the shared Display/Filter menus. */
|
|
21
|
-
function useListView({ storageKey, sharedFiltersKey, columns, groupBys = [], defaultGroupBy, orderBys = [], defaultOrderBy, facets = [], actions = [], actionCount, defaultShowColumnHeaders = true, defaultShowActions = true, isFavorite, isOn, createdAt }) {
|
|
27
|
+
function useListView({ storageKey, sharedFiltersKey, columns, groupBys = [], defaultGroupBy, orderBys = [], defaultOrderBy, facets = [], filterFields, defaultFilters, filterStore, rememberFilters = true, actions = [], actionCount, defaultShowColumnHeaders = true, defaultShowActions = true, isFavorite, isOn, createdAt }) {
|
|
22
28
|
const t = useStrings().list;
|
|
23
29
|
const tiebreak = orderBys[0]?.compare;
|
|
24
30
|
const effectiveOrderBys = useMemo(() => {
|
|
@@ -59,23 +65,20 @@ function useListView({ storageKey, sharedFiltersKey, columns, groupBys = [], def
|
|
|
59
65
|
const [alwaysShowActions, setAlwaysShowActions] = usePersistedState(`${storageKey}:alwaysShowActions`, false);
|
|
60
66
|
const [orderBy, setOrderBy] = usePersistedState(`${storageKey}:orderBy`, defaultOrderByValue);
|
|
61
67
|
const [orderDir, setOrderDir] = usePersistedState(`${storageKey}:orderDir`, "asc");
|
|
62
|
-
const [
|
|
63
|
-
const
|
|
64
|
-
|
|
68
|
+
const fields = useMemo(() => [...facets.map(facetField), ...filterFields ?? []], [facets, filterFields]);
|
|
69
|
+
const filterState = useListFilters({
|
|
70
|
+
storageKey,
|
|
71
|
+
sharedFiltersKey,
|
|
72
|
+
fields,
|
|
73
|
+
defaultFilters,
|
|
74
|
+
store: filterStore,
|
|
75
|
+
remember: rememberFilters
|
|
76
|
+
});
|
|
65
77
|
const filters = useMemo(() => {
|
|
66
|
-
|
|
67
|
-
const
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
const values = sharedFilters[key];
|
|
71
|
-
if (values?.length) merged[key] = values;
|
|
72
|
-
}
|
|
73
|
-
return merged;
|
|
74
|
-
}, [
|
|
75
|
-
localFilters,
|
|
76
|
-
sharedFilters,
|
|
77
|
-
sharedKeys
|
|
78
|
-
]);
|
|
78
|
+
const out = {};
|
|
79
|
+
for (const f of filterState.active) if (f.op === "is") out[f.field] = [...f.values];
|
|
80
|
+
return out;
|
|
81
|
+
}, [filterState.active]);
|
|
79
82
|
const pinnedCount = actionCount ?? pinnedKeys.filter((key) => actions.some((action) => action.key === key)).length;
|
|
80
83
|
const effectiveShowActions = showActions || alwaysShowActions;
|
|
81
84
|
const actionsWidth = effectiveShowActions ? actionsColumnWidth(pinnedCount) : 0;
|
|
@@ -84,35 +87,24 @@ function useListView({ storageKey, sharedFiltersKey, columns, groupBys = [], def
|
|
|
84
87
|
return Boolean(col?.alwaysVisible) || !hiddenKeys.includes(key);
|
|
85
88
|
}, [columns, hiddenKeys]);
|
|
86
89
|
const visibleColumns = useMemo(() => columns.filter((c) => !c.inline && (c.alwaysVisible || !hiddenKeys.includes(c.key))), [columns, hiddenKeys]);
|
|
87
|
-
const columnClasses = useMemo(() => visibleColumns.map(
|
|
90
|
+
const columnClasses = useMemo(() => visibleColumns.map(columnClass), [visibleColumns]);
|
|
88
91
|
const columnStacks = useMemo(() => visibleColumns.map(stacks), [visibleColumns]);
|
|
89
92
|
const toggleColumn = useCallback((key) => setHiddenKeys((prev) => prev.includes(key) ? prev.filter((k) => k !== key) : [...prev, key]), [setHiddenKeys]);
|
|
93
|
+
const { add, update, remove } = filterState;
|
|
90
94
|
const setFacetValues = useCallback((key, values) => {
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
return next;
|
|
96
|
-
};
|
|
97
|
-
if (sharedKeys.has(key)) setSharedFilters(update);
|
|
98
|
-
else setLocalFilters(update);
|
|
99
|
-
}, [
|
|
100
|
-
setLocalFilters,
|
|
101
|
-
setSharedFilters,
|
|
102
|
-
sharedKeys
|
|
103
|
-
]);
|
|
104
|
-
const clearFilters = useCallback(() => {
|
|
105
|
-
setLocalFilters({});
|
|
106
|
-
if (sharedKeys.size > 0) setSharedFilters((prev) => {
|
|
107
|
-
const next = { ...prev };
|
|
108
|
-
for (const key of sharedKeys) delete next[key];
|
|
109
|
-
return next;
|
|
95
|
+
if (values.length === 0) remove(key);
|
|
96
|
+
else if (filterState.active.some((f) => f.field === key)) update(key, {
|
|
97
|
+
op: "is",
|
|
98
|
+
values
|
|
110
99
|
});
|
|
100
|
+
else add(key, "is", values);
|
|
111
101
|
}, [
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
102
|
+
add,
|
|
103
|
+
update,
|
|
104
|
+
remove,
|
|
105
|
+
filterState.active
|
|
115
106
|
]);
|
|
107
|
+
const clearFilters = filterState.clear;
|
|
116
108
|
const isPinned = useCallback((key) => pinnedKeys.includes(key), [pinnedKeys]);
|
|
117
109
|
const togglePinned = useCallback((key) => setPinnedKeys((prev) => prev.includes(key) ? prev.filter((k) => k !== key) : [...prev, key]), [setPinnedKeys]);
|
|
118
110
|
const toggleColumnHeaders = useCallback(() => setShowColumnHeaders((prev) => !prev), [setShowColumnHeaders]);
|
|
@@ -206,14 +198,12 @@ function useListView({ storageKey, sharedFiltersKey, columns, groupBys = [], def
|
|
|
206
198
|
sortBy,
|
|
207
199
|
applyOrder,
|
|
208
200
|
facets,
|
|
201
|
+
filterState,
|
|
209
202
|
filters,
|
|
210
203
|
setFacetValues,
|
|
211
204
|
clearFilters,
|
|
212
|
-
activeFilterCount:
|
|
213
|
-
applyFilters: useCallback((rows) =>
|
|
214
|
-
const selected = filters[f.key];
|
|
215
|
-
return !selected || selected.length === 0 ? true : f.matches(row, selected);
|
|
216
|
-
})), [facets, filters]),
|
|
205
|
+
activeFilterCount: filterState.count,
|
|
206
|
+
applyFilters: useCallback((rows) => filterState.apply(rows), [filterState.apply]),
|
|
217
207
|
actions,
|
|
218
208
|
isPinned,
|
|
219
209
|
togglePinned,
|
|
@@ -227,5 +217,17 @@ function useListView({ storageKey, sharedFiltersKey, columns, groupBys = [], def
|
|
|
227
217
|
resetDisplay
|
|
228
218
|
};
|
|
229
219
|
}
|
|
220
|
+
/** A facet as the field it is shorthand for. */
|
|
221
|
+
function facetField(facet) {
|
|
222
|
+
return {
|
|
223
|
+
key: facet.key,
|
|
224
|
+
label: facet.label,
|
|
225
|
+
kind: "enum",
|
|
226
|
+
options: facet.options,
|
|
227
|
+
searchable: facet.searchable,
|
|
228
|
+
shared: facet.shared,
|
|
229
|
+
matches: (row, filter) => filter.op === "isNot" ? !facet.matches(row, [...filter.values]) : facet.matches(row, [...filter.values])
|
|
230
|
+
};
|
|
231
|
+
}
|
|
230
232
|
//#endregion
|
|
231
233
|
export { DEFAULT_ORDER, FAVORITE_ORDER, useListView };
|
package/dist/list/rowMenu.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { MouseEvent as ReactMouseEvent, ReactNode } from 'react';
|
|
2
|
-
import type
|
|
2
|
+
import { type OpenMenu } from '../components/ContextMenu.js';
|
|
3
3
|
import type { MenuAction, MenuEntry, MenuSubmenu } from '../components/MenuEntries.js';
|
|
4
4
|
/** An action on a row, which its menu lists and its pinned buttons show, named by `key`. */
|
|
5
5
|
export type RowAction = MenuAction & {
|
|
@@ -29,8 +29,8 @@ export declare function useRowMenuActive(openMenu: OpenMenu): {
|
|
|
29
29
|
active: boolean;
|
|
30
30
|
openMenu: OpenMenu;
|
|
31
31
|
};
|
|
32
|
-
/** Opens the row's menu on a right-click
|
|
33
|
-
* list's menus only when one opens, not on every render. */
|
|
32
|
+
/** Opens the row's menu on a right-click; Shift+right-click keeps the browser's own. Pass a
|
|
33
|
+
* function to build a large list's menus only when one opens, not on every render. */
|
|
34
34
|
export declare function rowContextMenuProps(openMenu: OpenMenu, entries: MenuEntry[] | (() => MenuEntry[])): {
|
|
35
35
|
onContextMenu: (e: ReactMouseEvent) => void;
|
|
36
36
|
};
|
|
@@ -56,8 +56,13 @@ export declare function useCopySubmenu(): CopySubmenu;
|
|
|
56
56
|
* stays while its menu is `open`, though the pointer has left the row. A touch
|
|
57
57
|
* screen has no hover, so there it always shows: the row's menu is otherwise
|
|
58
58
|
* out of reach. */
|
|
59
|
-
export declare function MoreButton({ onOpen, open, visible, label, className, }: {
|
|
60
|
-
|
|
59
|
+
export declare function MoreButton({ onOpen, items, open: openProp, visible: visibleProp, label, className, }: {
|
|
60
|
+
/** Opens a menu of the host's own under the button. */
|
|
61
|
+
onOpen?: ((button: HTMLElement) => void) | undefined;
|
|
62
|
+
/** The menu's rows, opened in the shared menu, which a second press closes. A function
|
|
63
|
+
* builds them only when it opens. Use this or `onOpen`. */
|
|
64
|
+
items?: MenuEntry[] | (() => MenuEntry[]) | undefined;
|
|
65
|
+
/** Whether its menu is open; with `items` the shared menu tells it. */
|
|
61
66
|
open?: boolean;
|
|
62
67
|
/** Shows at rest too. */
|
|
63
68
|
visible?: boolean;
|
package/dist/list/rowMenu.js
CHANGED
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
import { cx } from "../cx.js";
|
|
2
2
|
import { CopyIcon, IdCardIcon, KeyIcon, LinkIcon, MailIcon, MoreIcon, UserIcon } from "../icons.js";
|
|
3
|
+
import { useMenuOpenedBy, useOpenMenu } from "../components/ContextMenu.js";
|
|
3
4
|
import { useStrings } from "../components/Provider.js";
|
|
4
5
|
import { IconButton } from "../components/IconButton.js";
|
|
6
|
+
import { useCallback, useRef, useState } from "react";
|
|
5
7
|
import { jsx } from "react/jsx-runtime";
|
|
6
|
-
import { useCallback, useState } from "react";
|
|
7
8
|
//#region src/list/rowMenu.tsx
|
|
8
9
|
/** Assembles a row's context menu in the shared order: leading link(s) → middle
|
|
9
10
|
* actions → extra items → Copy submenu → trailing (destructive) actions last. */
|
|
@@ -31,21 +32,23 @@ function useRowMenuActive(openMenu) {
|
|
|
31
32
|
return {
|
|
32
33
|
active,
|
|
33
34
|
openMenu: useCallback((at, items, options) => {
|
|
34
|
-
|
|
35
|
-
openMenu(at, items, {
|
|
35
|
+
const opened = openMenu(at, items, {
|
|
36
36
|
...options,
|
|
37
37
|
onClose: () => {
|
|
38
38
|
setActive(false);
|
|
39
39
|
options?.onClose?.();
|
|
40
40
|
}
|
|
41
41
|
});
|
|
42
|
+
if (opened !== false) setActive(true);
|
|
43
|
+
return opened;
|
|
42
44
|
}, [openMenu])
|
|
43
45
|
};
|
|
44
46
|
}
|
|
45
|
-
/** Opens the row's menu on a right-click
|
|
46
|
-
* list's menus only when one opens, not on every render. */
|
|
47
|
+
/** Opens the row's menu on a right-click; Shift+right-click keeps the browser's own. Pass a
|
|
48
|
+
* function to build a large list's menus only when one opens, not on every render. */
|
|
47
49
|
function rowContextMenuProps(openMenu, entries) {
|
|
48
50
|
return { onContextMenu: (e) => {
|
|
51
|
+
if (e.shiftKey) return;
|
|
49
52
|
const items = typeof entries === "function" ? entries() : entries;
|
|
50
53
|
e.preventDefault();
|
|
51
54
|
if (items.length > 0) e.stopPropagation();
|
|
@@ -111,9 +114,15 @@ function useCopySubmenu() {
|
|
|
111
114
|
* stays while its menu is `open`, though the pointer has left the row. A touch
|
|
112
115
|
* screen has no hover, so there it always shows: the row's menu is otherwise
|
|
113
116
|
* out of reach. */
|
|
114
|
-
function MoreButton({ onOpen, open
|
|
117
|
+
function MoreButton({ onOpen, items, open: openProp, visible: visibleProp, label, className }) {
|
|
115
118
|
const { list: t } = useStrings();
|
|
119
|
+
const openMenu = useOpenMenu();
|
|
120
|
+
const openedBy = useMenuOpenedBy();
|
|
121
|
+
const button = useRef(null);
|
|
122
|
+
const open = openProp ?? (items !== void 0 && openedBy !== null && openedBy === button.current);
|
|
123
|
+
const visible = visibleProp ?? open;
|
|
116
124
|
return /* @__PURE__ */ jsx(IconButton, {
|
|
125
|
+
ref: button,
|
|
117
126
|
label: label ?? t.moreActions,
|
|
118
127
|
icon: /* @__PURE__ */ jsx(MoreIcon, {}),
|
|
119
128
|
"aria-haspopup": "menu",
|
|
@@ -121,7 +130,8 @@ function MoreButton({ onOpen, open = false, visible = open, label, className })
|
|
|
121
130
|
"data-popup-open": open || void 0,
|
|
122
131
|
onClick: (e) => {
|
|
123
132
|
e.stopPropagation();
|
|
124
|
-
|
|
133
|
+
if (items !== void 0) openMenu(e.currentTarget, typeof items === "function" ? items() : items);
|
|
134
|
+
else onOpen?.(e.currentTarget);
|
|
125
135
|
},
|
|
126
136
|
className: cx("focus-visible:opacity-100", visible ? "opacity-100" : "opacity-0 group-hover:opacity-100 pointer-coarse:opacity-100", className)
|
|
127
137
|
});
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import { type ActiveFilter, type FilterField, type FilterOperator } from './filterModel.js';
|
|
2
|
+
/** Where filters live besides what the list remembers, such as the page's URL. */
|
|
3
|
+
export interface FilterStore {
|
|
4
|
+
/** The filters it holds, or `null` when it holds none, such as a URL with no filter params,
|
|
5
|
+
* so the remembered filters apply. */
|
|
6
|
+
value: readonly ActiveFilter[] | null;
|
|
7
|
+
onChange: (next: ActiveFilter[]) => void;
|
|
8
|
+
}
|
|
9
|
+
export interface ListFiltersConfig<T> {
|
|
10
|
+
/** Remembers the filters under `${storageKey}:filters`, through the host's persisted state
|
|
11
|
+
* (the browser's storage unless the host binds its own, such as an account preference). */
|
|
12
|
+
storageKey: string;
|
|
13
|
+
/** Fields marked `shared` keep one value under `${sharedFiltersKey}:sharedFilters`. */
|
|
14
|
+
sharedFiltersKey?: string | undefined;
|
|
15
|
+
fields: readonly FilterField<T>[];
|
|
16
|
+
/** What the page shows before the reader changes anything, and what Reset returns to. */
|
|
17
|
+
defaultFilters?: readonly ActiveFilter[] | undefined;
|
|
18
|
+
/** Filters held outside the list, such as the URL. Its filters win while it has any, and
|
|
19
|
+
* every change goes to it and to what the list remembers. */
|
|
20
|
+
store?: FilterStore | undefined;
|
|
21
|
+
/** False leaves remembering to the store alone. */
|
|
22
|
+
remember?: boolean | undefined;
|
|
23
|
+
}
|
|
24
|
+
/** A request for a chip to open one of its pickers, which the chip clears once it has. */
|
|
25
|
+
export interface FilterEditRequest {
|
|
26
|
+
field: string;
|
|
27
|
+
part: 'value' | 'field' | 'operator';
|
|
28
|
+
id: number;
|
|
29
|
+
}
|
|
30
|
+
/** A list's filters, the state behind the chip row and the Filter menu. */
|
|
31
|
+
export interface ListFilters {
|
|
32
|
+
fields: readonly FilterField<any>[];
|
|
33
|
+
/** The filters in effect, in the order they were added. */
|
|
34
|
+
active: readonly ActiveFilter[];
|
|
35
|
+
/** The chips to show: the filters in effect, then one being added that has no value yet. */
|
|
36
|
+
chips: readonly ActiveFilter[];
|
|
37
|
+
/** The field of a chip just added and still waiting for its value. */
|
|
38
|
+
draft: string | null;
|
|
39
|
+
/** Starts a filter: a chip for the field appears and its value picker opens. A field
|
|
40
|
+
* already in use opens its chip's picker instead. */
|
|
41
|
+
begin: (field: string) => void;
|
|
42
|
+
add: (field: string, op?: FilterOperator, values?: readonly string[]) => void;
|
|
43
|
+
update: (field: string, patch: Partial<Omit<ActiveFilter, 'field'>>) => void;
|
|
44
|
+
/** Swaps a chip's field for another, keeping its values when the kinds match. */
|
|
45
|
+
replaceField: (field: string, next: string) => void;
|
|
46
|
+
remove: (field: string) => void;
|
|
47
|
+
/** Drops the chip being added, if it never got a value. */
|
|
48
|
+
discardDraft: () => void;
|
|
49
|
+
/** Empties every filter but the required ones. */
|
|
50
|
+
clear: () => void;
|
|
51
|
+
/** Returns to the page's default filters. */
|
|
52
|
+
reset: () => void;
|
|
53
|
+
hasDefaults: boolean;
|
|
54
|
+
isDefault: boolean;
|
|
55
|
+
/** How many filters narrow the list. */
|
|
56
|
+
count: number;
|
|
57
|
+
apply: <R>(rows: readonly R[]) => R[];
|
|
58
|
+
editRequest: FilterEditRequest | null;
|
|
59
|
+
requestEdit: (field: string, part?: FilterEditRequest['part']) => void;
|
|
60
|
+
clearEditRequest: (id: number) => void;
|
|
61
|
+
/** Set by a mounted chip row, so the Filter menu knows a new chip has somewhere to show. */
|
|
62
|
+
barMounted: boolean;
|
|
63
|
+
registerBar: () => () => void;
|
|
64
|
+
}
|
|
65
|
+
/** A list's active filters: which, in what order, where they are remembered and how rows
|
|
66
|
+
* match them. `useListView` builds one from its facets and fields; a page not on it, or
|
|
67
|
+
* filtering on the server, can call this alone. */
|
|
68
|
+
export declare function useListFilters<T>({ storageKey, sharedFiltersKey, fields, defaultFilters, store, remember, }: ListFiltersConfig<T>): ListFilters;
|
|
@@ -0,0 +1,252 @@
|
|
|
1
|
+
import { usePersistedState } from "../components/Provider.js";
|
|
2
|
+
import { applyFilterList, fieldOperators, fromStored, isComplete, sameFilters, toStored } from "./filterModel.js";
|
|
3
|
+
import { useCallback, useMemo, useRef, useState } from "react";
|
|
4
|
+
//#region src/list/useListFilters.ts
|
|
5
|
+
var NONE = [];
|
|
6
|
+
/** A list's active filters: which, in what order, where they are remembered and how rows
|
|
7
|
+
* match them. `useListView` builds one from its facets and fields; a page not on it, or
|
|
8
|
+
* filtering on the server, can call this alone. */
|
|
9
|
+
function useListFilters({ storageKey, sharedFiltersKey, fields, defaultFilters = NONE, store, remember = true }) {
|
|
10
|
+
const sharedKeys = useMemo(() => new Set(fields.filter((f) => f.shared).map((f) => f.key)), [fields]);
|
|
11
|
+
const defaults = useMemo(() => defaultFilters.filter((f) => !sharedKeys.has(f.field)), [defaultFilters, sharedKeys]);
|
|
12
|
+
const sharedDefaults = useMemo(() => defaultFilters.filter((f) => sharedKeys.has(f.field)), [defaultFilters, sharedKeys]);
|
|
13
|
+
const [localStored, setLocalStored] = usePersistedState(`${storageKey}:filters`, toStored(defaults));
|
|
14
|
+
const [sharedStored, setSharedStored] = usePersistedState(`${sharedFiltersKey ?? storageKey}:sharedFilters`, toStored(sharedDefaults));
|
|
15
|
+
const known = useMemo(() => new Set(fields.map((f) => f.key)), [fields]);
|
|
16
|
+
const remembered = useMemo(() => {
|
|
17
|
+
const local = fromStored(localStored).filter((f) => !sharedKeys.has(f.field));
|
|
18
|
+
const shared = fromStored(sharedStored).filter((f) => sharedKeys.has(f.field));
|
|
19
|
+
return [...local, ...shared];
|
|
20
|
+
}, [
|
|
21
|
+
localStored,
|
|
22
|
+
sharedStored,
|
|
23
|
+
sharedKeys
|
|
24
|
+
]);
|
|
25
|
+
const source = store?.value ?? (remember ? remembered : defaultFilters);
|
|
26
|
+
const active = useMemo(() => source.filter((f) => known.has(f.field) && isComplete(f)), [source, known]);
|
|
27
|
+
const latest = useRef(active);
|
|
28
|
+
latest.current = active;
|
|
29
|
+
const write = useCallback((next) => {
|
|
30
|
+
latest.current = next;
|
|
31
|
+
if (remember) {
|
|
32
|
+
setLocalStored(toStored(next.filter((f) => !sharedKeys.has(f.field))));
|
|
33
|
+
if (sharedKeys.size > 0) setSharedStored((prev) => {
|
|
34
|
+
const kept = {};
|
|
35
|
+
for (const [key, value] of Object.entries(prev ?? {})) if (!sharedKeys.has(key)) kept[key] = value;
|
|
36
|
+
return {
|
|
37
|
+
...kept,
|
|
38
|
+
...toStored(next.filter((f) => sharedKeys.has(f.field)))
|
|
39
|
+
};
|
|
40
|
+
});
|
|
41
|
+
}
|
|
42
|
+
store?.onChange(next);
|
|
43
|
+
}, [
|
|
44
|
+
remember,
|
|
45
|
+
setLocalStored,
|
|
46
|
+
setSharedStored,
|
|
47
|
+
sharedKeys,
|
|
48
|
+
store
|
|
49
|
+
]);
|
|
50
|
+
const [draftState, setDraftStateRaw] = useState(null);
|
|
51
|
+
const draftRef = useRef(draftState);
|
|
52
|
+
const setDraft = useCallback((filter, index) => {
|
|
53
|
+
const next = filter ? {
|
|
54
|
+
filter,
|
|
55
|
+
index: index ?? Number.POSITIVE_INFINITY
|
|
56
|
+
} : null;
|
|
57
|
+
draftRef.current = next;
|
|
58
|
+
setDraftStateRaw(next);
|
|
59
|
+
}, []);
|
|
60
|
+
const draft = draftState && !active.some((f) => f.field === draftState.filter.field) ? draftState : null;
|
|
61
|
+
const [editRequest, setEditRequest] = useState(null);
|
|
62
|
+
const nextId = useRef(0);
|
|
63
|
+
const requestEdit = useCallback((field, part = "value") => {
|
|
64
|
+
nextId.current += 1;
|
|
65
|
+
setEditRequest({
|
|
66
|
+
field,
|
|
67
|
+
part,
|
|
68
|
+
id: nextId.current
|
|
69
|
+
});
|
|
70
|
+
}, []);
|
|
71
|
+
const clearEditRequest = useCallback((id) => setEditRequest((prev) => prev?.id === id ? null : prev), []);
|
|
72
|
+
const fieldOf = useCallback((key) => fields.find((f) => f.key === key), [fields]);
|
|
73
|
+
const add = useCallback((key, op, values = []) => {
|
|
74
|
+
const field = fieldOf(key);
|
|
75
|
+
if (!field) return;
|
|
76
|
+
const filter = {
|
|
77
|
+
field: key,
|
|
78
|
+
op: op ?? fieldOperators(field)[0] ?? "is",
|
|
79
|
+
values: field.kind === "boolean" && values.length === 0 ? ["true"] : values
|
|
80
|
+
};
|
|
81
|
+
const rest = latest.current.filter((f) => f.field !== key);
|
|
82
|
+
if (!isComplete(filter)) {
|
|
83
|
+
if (rest.length !== latest.current.length) write(rest);
|
|
84
|
+
setDraft(filter);
|
|
85
|
+
return;
|
|
86
|
+
}
|
|
87
|
+
if (draftRef.current?.filter.field === key) setDraft(null);
|
|
88
|
+
write([...rest, filter]);
|
|
89
|
+
}, [
|
|
90
|
+
fieldOf,
|
|
91
|
+
write,
|
|
92
|
+
setDraft
|
|
93
|
+
]);
|
|
94
|
+
const update = useCallback((key, patch) => {
|
|
95
|
+
const index = latest.current.findIndex((f) => f.field === key);
|
|
96
|
+
const current = latest.current[index];
|
|
97
|
+
if (!current) {
|
|
98
|
+
const held = draftRef.current;
|
|
99
|
+
if (held?.filter.field !== key) {
|
|
100
|
+
const field = fieldOf(key);
|
|
101
|
+
const next = {
|
|
102
|
+
field: key,
|
|
103
|
+
op: patch.op ?? (field ? fieldOperators(field)[0] : void 0) ?? "is",
|
|
104
|
+
values: patch.values ?? []
|
|
105
|
+
};
|
|
106
|
+
if (field && isComplete(next)) write([...latest.current, next]);
|
|
107
|
+
return;
|
|
108
|
+
}
|
|
109
|
+
const next = {
|
|
110
|
+
...held.filter,
|
|
111
|
+
...patch
|
|
112
|
+
};
|
|
113
|
+
if (isComplete(next)) {
|
|
114
|
+
setDraft(null);
|
|
115
|
+
const at = Math.min(held.index, latest.current.length);
|
|
116
|
+
write([
|
|
117
|
+
...latest.current.slice(0, at),
|
|
118
|
+
next,
|
|
119
|
+
...latest.current.slice(at)
|
|
120
|
+
]);
|
|
121
|
+
} else setDraft(next, held.index);
|
|
122
|
+
return;
|
|
123
|
+
}
|
|
124
|
+
const next = {
|
|
125
|
+
...current,
|
|
126
|
+
...patch
|
|
127
|
+
};
|
|
128
|
+
if (isComplete(next)) {
|
|
129
|
+
write(latest.current.map((f) => f.field === key ? next : f));
|
|
130
|
+
return;
|
|
131
|
+
}
|
|
132
|
+
const field = fieldOf(key);
|
|
133
|
+
if (!field?.required && !field?.pinned) setDraft(next, index);
|
|
134
|
+
write(latest.current.filter((f) => f.field !== key));
|
|
135
|
+
}, [
|
|
136
|
+
fieldOf,
|
|
137
|
+
write,
|
|
138
|
+
setDraft
|
|
139
|
+
]);
|
|
140
|
+
const remove = useCallback((key) => {
|
|
141
|
+
if (draftRef.current?.filter.field === key) setDraft(null);
|
|
142
|
+
if (latest.current.some((f) => f.field === key)) write(latest.current.filter((f) => f.field !== key));
|
|
143
|
+
}, [write, setDraft]);
|
|
144
|
+
const replaceField = useCallback((key, nextKey) => {
|
|
145
|
+
const from = fieldOf(key);
|
|
146
|
+
const to = fieldOf(nextKey);
|
|
147
|
+
const index = latest.current.findIndex((f) => f.field === key);
|
|
148
|
+
const held = draftRef.current?.filter.field === key ? draftRef.current : void 0;
|
|
149
|
+
const current = latest.current[index] ?? held?.filter;
|
|
150
|
+
if (!from || !to || !current || key === nextKey) return;
|
|
151
|
+
const ops = fieldOperators(to);
|
|
152
|
+
const op = ops.includes(current.op) ? current.op : ops[0] ?? "is";
|
|
153
|
+
const listed = from.kind === "enum" || from.kind === "people";
|
|
154
|
+
const carries = from.kind === to.kind && (!listed || current.values.every((v) => to.options?.some((o) => o.value === v) ?? false));
|
|
155
|
+
const next = {
|
|
156
|
+
field: nextKey,
|
|
157
|
+
op,
|
|
158
|
+
values: to.kind === "boolean" ? ["true"] : carries ? current.values : []
|
|
159
|
+
};
|
|
160
|
+
const rest = latest.current.filter((f) => f.field !== nextKey);
|
|
161
|
+
const at = index >= 0 ? rest.findIndex((f) => f.field === key) : held?.index ?? rest.length;
|
|
162
|
+
const without = rest.filter((f) => f.field !== key);
|
|
163
|
+
if (isComplete(next)) {
|
|
164
|
+
setDraft(null);
|
|
165
|
+
const pos = Math.min(Math.max(at, 0), without.length);
|
|
166
|
+
write([
|
|
167
|
+
...without.slice(0, pos),
|
|
168
|
+
next,
|
|
169
|
+
...without.slice(pos)
|
|
170
|
+
]);
|
|
171
|
+
} else {
|
|
172
|
+
if (without.length !== latest.current.length) write(without);
|
|
173
|
+
setDraft(next, at);
|
|
174
|
+
requestEdit(nextKey);
|
|
175
|
+
}
|
|
176
|
+
}, [
|
|
177
|
+
fieldOf,
|
|
178
|
+
write,
|
|
179
|
+
setDraft,
|
|
180
|
+
requestEdit
|
|
181
|
+
]);
|
|
182
|
+
const begin = useCallback((key) => {
|
|
183
|
+
const field = fieldOf(key);
|
|
184
|
+
if (!field) return;
|
|
185
|
+
if (latest.current.some((f) => f.field === key) || field.required || field.pinned) {
|
|
186
|
+
requestEdit(key);
|
|
187
|
+
return;
|
|
188
|
+
}
|
|
189
|
+
add(key);
|
|
190
|
+
if (field.kind !== "boolean") requestEdit(key);
|
|
191
|
+
}, [
|
|
192
|
+
fieldOf,
|
|
193
|
+
add,
|
|
194
|
+
requestEdit
|
|
195
|
+
]);
|
|
196
|
+
const discardDraft = useCallback(() => setDraft(null), [setDraft]);
|
|
197
|
+
const clear = useCallback(() => {
|
|
198
|
+
setDraft(null);
|
|
199
|
+
write(latest.current.filter((f) => fieldOf(f.field)?.required));
|
|
200
|
+
}, [
|
|
201
|
+
fieldOf,
|
|
202
|
+
write,
|
|
203
|
+
setDraft
|
|
204
|
+
]);
|
|
205
|
+
const reset = useCallback(() => {
|
|
206
|
+
setDraft(null);
|
|
207
|
+
write([...defaultFilters]);
|
|
208
|
+
}, [
|
|
209
|
+
defaultFilters,
|
|
210
|
+
write,
|
|
211
|
+
setDraft
|
|
212
|
+
]);
|
|
213
|
+
const [bars, setBars] = useState(0);
|
|
214
|
+
const registerBar = useCallback(() => {
|
|
215
|
+
setBars((n) => n + 1);
|
|
216
|
+
return () => setBars((n) => n - 1);
|
|
217
|
+
}, []);
|
|
218
|
+
const apply = useCallback((rows) => applyFilterList(rows, active, fields), [active, fields]);
|
|
219
|
+
return {
|
|
220
|
+
fields,
|
|
221
|
+
active,
|
|
222
|
+
chips: useMemo(() => {
|
|
223
|
+
if (!draft) return active;
|
|
224
|
+
const at = Math.min(draft.index, active.length);
|
|
225
|
+
return [
|
|
226
|
+
...active.slice(0, at),
|
|
227
|
+
draft.filter,
|
|
228
|
+
...active.slice(at)
|
|
229
|
+
];
|
|
230
|
+
}, [active, draft]),
|
|
231
|
+
draft: draft?.filter.field ?? null,
|
|
232
|
+
begin,
|
|
233
|
+
add,
|
|
234
|
+
update,
|
|
235
|
+
replaceField,
|
|
236
|
+
remove,
|
|
237
|
+
discardDraft,
|
|
238
|
+
clear,
|
|
239
|
+
reset,
|
|
240
|
+
hasDefaults: defaultFilters.length > 0,
|
|
241
|
+
isDefault: sameFilters(active, defaultFilters),
|
|
242
|
+
count: active.length,
|
|
243
|
+
apply,
|
|
244
|
+
editRequest,
|
|
245
|
+
requestEdit,
|
|
246
|
+
clearEditRequest,
|
|
247
|
+
barMounted: bars > 0,
|
|
248
|
+
registerBar
|
|
249
|
+
};
|
|
250
|
+
}
|
|
251
|
+
//#endregion
|
|
252
|
+
export { useListFilters };
|
|
@@ -11,8 +11,8 @@ import { InfoTip } from "../components/InfoTip.js";
|
|
|
11
11
|
import { DatePicker } from "../components/DatePicker.js";
|
|
12
12
|
import { SearchInput } from "../components/SearchInput.js";
|
|
13
13
|
import { highlightSegments, parseAnsiSegments, plainSegments } from "./segments.js";
|
|
14
|
-
import { Fragment,
|
|
15
|
-
import { Fragment as Fragment$1,
|
|
14
|
+
import { Fragment, memo, useCallback, useEffect, useId, useLayoutEffect, useMemo, useRef, useState } from "react";
|
|
15
|
+
import { Fragment as Fragment$1, jsx, jsxs } from "react/jsx-runtime";
|
|
16
16
|
import { useVirtualizer } from "@tanstack/react-virtual";
|
|
17
17
|
import { DateTime } from "luxon";
|
|
18
18
|
//#region src/logviewer/LogViewer.tsx
|
|
@@ -24,7 +24,7 @@ function LogSegments({ segments }) {
|
|
|
24
24
|
}, i) : segment.className ? /* @__PURE__ */ jsx("span", {
|
|
25
25
|
className: segment.className,
|
|
26
26
|
children: segment.content
|
|
27
|
-
}, i) : /* @__PURE__ */ jsx(Fragment
|
|
27
|
+
}, i) : /* @__PURE__ */ jsx(Fragment, { children: segment.content }, i));
|
|
28
28
|
}
|
|
29
29
|
var ANNOTATION_TONES = {
|
|
30
30
|
error: {
|
|
@@ -419,7 +419,7 @@ function LogViewer({ log, height = "unset", width, downloadName = "log.txt", rou
|
|
|
419
419
|
/* @__PURE__ */ jsxs("div", {
|
|
420
420
|
className: "flex flex-auto flex-wrap gap-2",
|
|
421
421
|
children: [
|
|
422
|
-
!inline && /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsx(Button, {
|
|
422
|
+
!inline && /* @__PURE__ */ jsxs(Fragment$1, { children: [/* @__PURE__ */ jsx(Button, {
|
|
423
423
|
variant: "secondary",
|
|
424
424
|
size: "sm",
|
|
425
425
|
icon: /* @__PURE__ */ jsx(ArrowUpIcon, {}),
|