@flanksource/clicky-ui 0.1.0 → 0.2.1
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 +29 -2
- package/dist/api-explorer.d.ts +5 -0
- package/dist/api-explorer.d.ts.map +1 -0
- package/dist/api-explorer.js +25 -0
- package/dist/api-explorer.js.map +1 -0
- package/dist/clicky.d.ts +2 -0
- package/dist/clicky.d.ts.map +1 -0
- package/dist/clicky.js +5 -0
- package/dist/clicky.js.map +1 -0
- package/dist/components/DatePicker.d.ts +18 -0
- package/dist/components/DatePicker.d.ts.map +1 -0
- package/dist/components/DatePicker.js +63 -0
- package/dist/components/DatePicker.js.map +1 -0
- package/dist/components/DateTimePicker.d.ts +18 -0
- package/dist/components/DateTimePicker.d.ts.map +1 -0
- package/dist/components/DateTimePicker.js +84 -0
- package/dist/components/DateTimePicker.js.map +1 -0
- package/dist/components/FilterBar.d.ts +180 -0
- package/dist/components/FilterBar.d.ts.map +1 -0
- package/dist/components/FilterBar.js +1685 -0
- package/dist/components/FilterBar.js.map +1 -0
- package/dist/components/MultiSelect.d.ts +19 -0
- package/dist/components/MultiSelect.d.ts.map +1 -0
- package/dist/components/MultiSelect.js +143 -0
- package/dist/components/MultiSelect.js.map +1 -0
- package/dist/components/RangeSlider.d.ts +16 -0
- package/dist/components/RangeSlider.d.ts.map +1 -0
- package/dist/components/RangeSlider.js +92 -0
- package/dist/components/RangeSlider.js.map +1 -0
- package/dist/components/button.d.ts +21 -0
- package/dist/components/button.d.ts.map +1 -0
- package/dist/components/button.js +126 -0
- package/dist/components/button.js.map +1 -0
- package/dist/components/density-switcher.d.ts +7 -0
- package/dist/components/density-switcher.d.ts.map +1 -0
- package/dist/components/density-switcher.js +32 -0
- package/dist/components/density-switcher.js.map +1 -0
- package/dist/components/icon-menu-picker.d.ts +22 -0
- package/dist/components/icon-menu-picker.d.ts.map +1 -0
- package/dist/components/icon-menu-picker.js +181 -0
- package/dist/components/icon-menu-picker.js.map +1 -0
- package/dist/components/select.d.ts +15 -0
- package/dist/components/select.d.ts.map +1 -0
- package/dist/components/select.js +39 -0
- package/dist/components/select.js.map +1 -0
- package/dist/components/theme-switcher.d.ts +7 -0
- package/dist/components/theme-switcher.d.ts.map +1 -0
- package/dist/components/theme-switcher.js +42 -0
- package/dist/components/theme-switcher.js.map +1 -0
- package/dist/components.d.ts +14 -0
- package/dist/components.d.ts.map +1 -0
- package/dist/components.js +31 -0
- package/dist/components.js.map +1 -0
- package/dist/data/AnsiHtml.d.ts +7 -0
- package/dist/data/AnsiHtml.d.ts.map +1 -0
- package/dist/data/AnsiHtml.js +71 -0
- package/dist/data/AnsiHtml.js.map +1 -0
- package/dist/data/Avatar.d.ts +32 -0
- package/dist/data/Avatar.d.ts.map +1 -0
- package/dist/data/Avatar.js +201 -0
- package/dist/data/Avatar.js.map +1 -0
- package/dist/data/AvatarBadge.d.ts +26 -0
- package/dist/data/AvatarBadge.d.ts.map +1 -0
- package/dist/data/AvatarBadge.js +104 -0
- package/dist/data/AvatarBadge.js.map +1 -0
- package/dist/data/Badge.d.ts +44 -0
- package/dist/data/Badge.d.ts.map +1 -0
- package/dist/data/Badge.js +667 -0
- package/dist/data/Badge.js.map +1 -0
- package/dist/data/Clicky.d.ts +147 -0
- package/dist/data/Clicky.d.ts.map +1 -0
- package/dist/data/Clicky.fixtures.d.ts +3 -0
- package/dist/data/Clicky.fixtures.d.ts.map +1 -0
- package/dist/data/Clicky.js +1960 -0
- package/dist/data/Clicky.js.map +1 -0
- package/dist/data/DataTable.d.ts +95 -0
- package/dist/data/DataTable.d.ts.map +1 -0
- package/dist/data/DataTable.js +1464 -0
- package/dist/data/DataTable.js.map +1 -0
- package/dist/data/FilterPill.d.ts +29 -0
- package/dist/data/FilterPill.d.ts.map +1 -0
- package/dist/data/FilterPill.js +153 -0
- package/dist/data/FilterPill.js.map +1 -0
- package/dist/data/Gauge.d.ts +15 -0
- package/dist/data/Gauge.d.ts.map +1 -0
- package/dist/data/Gauge.js +63 -0
- package/dist/data/Gauge.js.map +1 -0
- package/dist/data/Icon.d.ts +53 -0
- package/dist/data/Icon.d.ts.map +1 -0
- package/dist/data/Icon.js +115 -0
- package/dist/data/Icon.js.map +1 -0
- package/dist/data/JsonView.d.ts +8 -0
- package/dist/data/JsonView.d.ts.map +1 -0
- package/dist/data/JsonView.js +74 -0
- package/dist/data/JsonView.js.map +1 -0
- package/dist/data/KeyValueList.d.ts +17 -0
- package/dist/data/KeyValueList.d.ts.map +1 -0
- package/dist/data/KeyValueList.js +33 -0
- package/dist/data/KeyValueList.js.map +1 -0
- package/dist/data/LogViewer.d.ts +10 -0
- package/dist/data/LogViewer.d.ts.map +1 -0
- package/dist/data/LogViewer.js +46 -0
- package/dist/data/LogViewer.js.map +1 -0
- package/dist/data/LogsTable.d.ts +27 -0
- package/dist/data/LogsTable.d.ts.map +1 -0
- package/dist/data/LogsTable.js +580 -0
- package/dist/data/LogsTable.js.map +1 -0
- package/dist/data/Markdown.d.ts +6 -0
- package/dist/data/Markdown.d.ts.map +1 -0
- package/dist/data/Markdown.js +59 -0
- package/dist/data/Markdown.js.map +1 -0
- package/dist/data/MatrixTable.d.ts +22 -0
- package/dist/data/MatrixTable.d.ts.map +1 -0
- package/dist/data/MatrixTable.js +164 -0
- package/dist/data/MatrixTable.js.map +1 -0
- package/dist/data/MethodBadge.d.ts +6 -0
- package/dist/data/MethodBadge.d.ts.map +1 -0
- package/dist/data/MethodBadge.js +18 -0
- package/dist/data/MethodBadge.js.map +1 -0
- package/dist/data/ProgressBar.d.ts +13 -0
- package/dist/data/ProgressBar.d.ts.map +1 -0
- package/dist/data/ProgressBar.js +34 -0
- package/dist/data/ProgressBar.js.map +1 -0
- package/dist/data/SortableHeader.d.ts +12 -0
- package/dist/data/SortableHeader.d.ts.map +1 -0
- package/dist/data/SortableHeader.js +33 -0
- package/dist/data/SortableHeader.js.map +1 -0
- package/dist/data/TabButton.d.ts +12 -0
- package/dist/data/TabButton.d.ts.map +1 -0
- package/dist/data/TabButton.js +45 -0
- package/dist/data/TabButton.js.map +1 -0
- package/dist/data/Tree.d.ts +35 -0
- package/dist/data/Tree.d.ts.map +1 -0
- package/dist/data/Tree.js +236 -0
- package/dist/data/Tree.js.map +1 -0
- package/dist/data/TreeGroupHeader.d.ts +11 -0
- package/dist/data/TreeGroupHeader.d.ts.map +1 -0
- package/dist/data/TreeGroupHeader.js +41 -0
- package/dist/data/TreeGroupHeader.js.map +1 -0
- package/dist/data/TreeNode.d.ts +43 -0
- package/dist/data/TreeNode.d.ts.map +1 -0
- package/dist/data/TreeNode.js +100 -0
- package/dist/data/TreeNode.js.map +1 -0
- package/dist/data/cells/StatusDot.d.ts +11 -0
- package/dist/data/cells/StatusDot.d.ts.map +1 -0
- package/dist/data/cells/StatusDot.js +38 -0
- package/dist/data/cells/StatusDot.js.map +1 -0
- package/dist/data/cells/TagList.d.ts +59 -0
- package/dist/data/cells/TagList.d.ts.map +1 -0
- package/dist/data/cells/TagList.js +257 -0
- package/dist/data/cells/TagList.js.map +1 -0
- package/dist/data/cells/Timestamp.d.ts +46 -0
- package/dist/data/cells/Timestamp.d.ts.map +1 -0
- package/dist/data/cells/Timestamp.js +146 -0
- package/dist/data/cells/Timestamp.js.map +1 -0
- package/dist/data/cells/status-mapping.d.ts +8 -0
- package/dist/data/cells/status-mapping.d.ts.map +1 -0
- package/dist/data/cells/status-mapping.js +44 -0
- package/dist/data/cells/status-mapping.js.map +1 -0
- package/dist/data/code-highlight.d.ts +12 -0
- package/dist/data/code-highlight.d.ts.map +1 -0
- package/dist/data/code-highlight.js +28 -0
- package/dist/data/code-highlight.js.map +1 -0
- package/dist/data/diagnostics/DiagnosticsDetailPanel.d.ts +9 -0
- package/dist/data/diagnostics/DiagnosticsDetailPanel.d.ts.map +1 -0
- package/dist/data/diagnostics/DiagnosticsDetailPanel.js +445 -0
- package/dist/data/diagnostics/DiagnosticsDetailPanel.js.map +1 -0
- package/dist/data/diagnostics/DiagnosticsTree.d.ts +9 -0
- package/dist/data/diagnostics/DiagnosticsTree.d.ts.map +1 -0
- package/dist/data/diagnostics/DiagnosticsTree.js +78 -0
- package/dist/data/diagnostics/DiagnosticsTree.js.map +1 -0
- package/dist/data/diagnostics/ErrorDetails.d.ts +20 -0
- package/dist/data/diagnostics/ErrorDetails.d.ts.map +1 -0
- package/dist/data/diagnostics/ErrorDetails.js +157 -0
- package/dist/data/diagnostics/ErrorDetails.js.map +1 -0
- package/dist/data/diagnostics/GoroutineCard.d.ts +10 -0
- package/dist/data/diagnostics/GoroutineCard.d.ts.map +1 -0
- package/dist/data/diagnostics/GoroutineCard.js +75 -0
- package/dist/data/diagnostics/GoroutineCard.js.map +1 -0
- package/dist/data/diagnostics/JvmStackTrace.d.ts +11 -0
- package/dist/data/diagnostics/JvmStackTrace.d.ts.map +1 -0
- package/dist/data/diagnostics/JvmStackTrace.js +26 -0
- package/dist/data/diagnostics/JvmStackTrace.js.map +1 -0
- package/dist/data/diagnostics/RenderedStackTrace.d.ts +18 -0
- package/dist/data/diagnostics/RenderedStackTrace.d.ts.map +1 -0
- package/dist/data/diagnostics/RenderedStackTrace.js +235 -0
- package/dist/data/diagnostics/RenderedStackTrace.js.map +1 -0
- package/dist/data/diagnostics/ThreadCard.d.ts +10 -0
- package/dist/data/diagnostics/ThreadCard.d.ts.map +1 -0
- package/dist/data/diagnostics/ThreadCard.js +78 -0
- package/dist/data/diagnostics/ThreadCard.js.map +1 -0
- package/dist/data/diagnostics/error-diagnostics.d.ts +26 -0
- package/dist/data/diagnostics/error-diagnostics.d.ts.map +1 -0
- package/dist/data/diagnostics/error-diagnostics.js +108 -0
- package/dist/data/diagnostics/error-diagnostics.js.map +1 -0
- package/dist/data/diagnostics/fixtures.d.ts +3 -0
- package/dist/data/diagnostics/fixtures.d.ts.map +1 -0
- package/dist/data/diagnostics/jvm-stacktrace.d.ts +34 -0
- package/dist/data/diagnostics/jvm-stacktrace.d.ts.map +1 -0
- package/dist/data/diagnostics/jvm-stacktrace.js +190 -0
- package/dist/data/diagnostics/jvm-stacktrace.js.map +1 -0
- package/dist/data/diagnostics/stacktrace-parse.d.ts +11 -0
- package/dist/data/diagnostics/stacktrace-parse.d.ts.map +1 -0
- package/dist/data/diagnostics/stacktrace-parse.js +87 -0
- package/dist/data/diagnostics/stacktrace-parse.js.map +1 -0
- package/dist/data/diagnostics/stacktrace.d.ts +38 -0
- package/dist/data/diagnostics/stacktrace.d.ts.map +1 -0
- package/dist/data/diagnostics/stacktrace.js +119 -0
- package/dist/data/diagnostics/stacktrace.js.map +1 -0
- package/dist/data/diagnostics/types.d.ts +30 -0
- package/dist/data/diagnostics/types.d.ts.map +1 -0
- package/dist/data/diagnostics/utils.d.ts +8 -0
- package/dist/data/diagnostics/utils.d.ts.map +1 -0
- package/dist/data/diagnostics/utils.js +59 -0
- package/dist/data/diagnostics/utils.js.map +1 -0
- package/dist/data/har/HarPanel.d.ts +9 -0
- package/dist/data/har/HarPanel.d.ts.map +1 -0
- package/dist/data/har/HarPanel.js +175 -0
- package/dist/data/har/HarPanel.js.map +1 -0
- package/dist/data/har/fixtures.d.ts +3 -0
- package/dist/data/har/fixtures.d.ts.map +1 -0
- package/dist/data/har/types.d.ts +47 -0
- package/dist/data/har/types.d.ts.map +1 -0
- package/dist/data.d.ts +39 -0
- package/dist/data.d.ts.map +1 -0
- package/dist/data.js +109 -0
- package/dist/data.js.map +1 -0
- package/dist/hooks/use-density.d.ts +22 -0
- package/dist/hooks/use-density.d.ts.map +1 -0
- package/dist/hooks/use-density.js +54 -0
- package/dist/hooks/use-density.js.map +1 -0
- package/dist/hooks/use-history-route.d.ts +6 -0
- package/dist/hooks/use-history-route.d.ts.map +1 -0
- package/dist/hooks/use-history-route.js +31 -0
- package/dist/hooks/use-history-route.js.map +1 -0
- package/dist/hooks/use-sort.d.ts +17 -0
- package/dist/hooks/use-sort.d.ts.map +1 -0
- package/dist/hooks/use-sort.js +42 -0
- package/dist/hooks/use-sort.js.map +1 -0
- package/dist/hooks/use-theme.d.ts +17 -0
- package/dist/hooks/use-theme.d.ts.map +1 -0
- package/dist/hooks/use-theme.js +68 -0
- package/dist/hooks/use-theme.js.map +1 -0
- package/dist/hooks.d.ts +5 -0
- package/dist/hooks.d.ts.map +1 -0
- package/dist/hooks.js +14 -0
- package/dist/hooks.js.map +1 -0
- package/dist/index.d.ts +7 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +193 -0
- package/dist/index.js.map +1 -0
- package/dist/layout/Section.d.ts +23 -0
- package/dist/layout/Section.d.ts.map +1 -0
- package/dist/layout/Section.js +73 -0
- package/dist/layout/Section.js.map +1 -0
- package/dist/layout/SplitPane.d.ts +13 -0
- package/dist/layout/SplitPane.d.ts.map +1 -0
- package/dist/layout/SplitPane.js +72 -0
- package/dist/layout/SplitPane.js.map +1 -0
- package/dist/lib/palette.d.ts +4 -0
- package/dist/lib/palette.d.ts.map +1 -0
- package/dist/lib/palette.js +35 -0
- package/dist/lib/palette.js.map +1 -0
- package/dist/lib/size.d.ts +6 -0
- package/dist/lib/size.d.ts.map +1 -0
- package/dist/lib/size.js +14 -0
- package/dist/lib/size.js.map +1 -0
- package/dist/lib/utils.d.ts +3 -0
- package/dist/lib/utils.d.ts.map +1 -0
- package/dist/lib/utils.js +9 -0
- package/dist/lib/utils.js.map +1 -0
- package/dist/overlay/HoverCard.d.ts +13 -0
- package/dist/overlay/HoverCard.d.ts.map +1 -0
- package/dist/overlay/HoverCard.js +170 -0
- package/dist/overlay/HoverCard.js.map +1 -0
- package/dist/overlay/Modal.d.ts +17 -0
- package/dist/overlay/Modal.d.ts.map +1 -0
- package/dist/overlay/Modal.js +91 -0
- package/dist/overlay/Modal.js.map +1 -0
- package/dist/rpc/AcceptPicker.d.ts +52 -0
- package/dist/rpc/AcceptPicker.d.ts.map +1 -0
- package/dist/rpc/AcceptPicker.js +126 -0
- package/dist/rpc/AcceptPicker.js.map +1 -0
- package/dist/rpc/ApiExplorer.d.ts +11 -0
- package/dist/rpc/ApiExplorer.d.ts.map +1 -0
- package/dist/rpc/ApiExplorer.js +37 -0
- package/dist/rpc/ApiExplorer.js.map +1 -0
- package/dist/rpc/CommandForm.d.ts +15 -0
- package/dist/rpc/CommandForm.d.ts.map +1 -0
- package/dist/rpc/CommandForm.js +356 -0
- package/dist/rpc/CommandForm.js.map +1 -0
- package/dist/rpc/CommandOutput.d.ts +11 -0
- package/dist/rpc/CommandOutput.d.ts.map +1 -0
- package/dist/rpc/CommandOutput.js +195 -0
- package/dist/rpc/CommandOutput.js.map +1 -0
- package/dist/rpc/EndpointList.d.ts +18 -0
- package/dist/rpc/EndpointList.d.ts.map +1 -0
- package/dist/rpc/EndpointList.js +56 -0
- package/dist/rpc/EndpointList.js.map +1 -0
- package/dist/rpc/EntityExplorerApp.d.ts +15 -0
- package/dist/rpc/EntityExplorerApp.d.ts.map +1 -0
- package/dist/rpc/EntityExplorerApp.js +282 -0
- package/dist/rpc/EntityExplorerApp.js.map +1 -0
- package/dist/rpc/ExecutionResult.d.ts +14 -0
- package/dist/rpc/ExecutionResult.d.ts.map +1 -0
- package/dist/rpc/ExecutionResult.js +51 -0
- package/dist/rpc/ExecutionResult.js.map +1 -0
- package/dist/rpc/FilterForm.d.ts +22 -0
- package/dist/rpc/FilterForm.d.ts.map +1 -0
- package/dist/rpc/FilterForm.js +392 -0
- package/dist/rpc/FilterForm.js.map +1 -0
- package/dist/rpc/InlineError.d.ts +7 -0
- package/dist/rpc/InlineError.d.ts.map +1 -0
- package/dist/rpc/InlineError.js +54 -0
- package/dist/rpc/InlineError.js.map +1 -0
- package/dist/rpc/OperationActionDialog.d.ts +12 -0
- package/dist/rpc/OperationActionDialog.d.ts.map +1 -0
- package/dist/rpc/OperationActionDialog.js +105 -0
- package/dist/rpc/OperationActionDialog.js.map +1 -0
- package/dist/rpc/OperationCatalog.d.ts +21 -0
- package/dist/rpc/OperationCatalog.d.ts.map +1 -0
- package/dist/rpc/OperationCatalog.js +339 -0
- package/dist/rpc/OperationCatalog.js.map +1 -0
- package/dist/rpc/OperationCommandPage.d.ts +22 -0
- package/dist/rpc/OperationCommandPage.d.ts.map +1 -0
- package/dist/rpc/OperationCommandPage.js +484 -0
- package/dist/rpc/OperationCommandPage.js.map +1 -0
- package/dist/rpc/OperationEntityPage.d.ts +23 -0
- package/dist/rpc/OperationEntityPage.d.ts.map +1 -0
- package/dist/rpc/OperationEntityPage.js +218 -0
- package/dist/rpc/OperationEntityPage.js.map +1 -0
- package/dist/rpc/classify.d.ts +8 -0
- package/dist/rpc/classify.d.ts.map +1 -0
- package/dist/rpc/classify.js +76 -0
- package/dist/rpc/classify.js.map +1 -0
- package/dist/rpc/clickyMetadata.d.ts +12 -0
- package/dist/rpc/clickyMetadata.d.ts.map +1 -0
- package/dist/rpc/clickyMetadata.js +71 -0
- package/dist/rpc/clickyMetadata.js.map +1 -0
- package/dist/rpc/formMetadata.d.ts +27 -0
- package/dist/rpc/formMetadata.d.ts.map +1 -0
- package/dist/rpc/formMetadata.js +250 -0
- package/dist/rpc/formMetadata.js.map +1 -0
- package/dist/rpc/types.d.ts +109 -0
- package/dist/rpc/types.d.ts.map +1 -0
- package/dist/rpc/types.js +8 -0
- package/dist/rpc/types.js.map +1 -0
- package/dist/rpc/useOperations.d.ts +346 -0
- package/dist/rpc/useOperations.d.ts.map +1 -0
- package/dist/rpc/useOperations.js +31 -0
- package/dist/rpc/useOperations.js.map +1 -0
- package/dist/rpc.d.ts +14 -0
- package/dist/rpc.d.ts.map +1 -0
- package/dist/rpc.js +37 -0
- package/dist/rpc.js.map +1 -0
- package/dist/styles.css +2 -0
- package/dist/styles.d.ts +1 -0
- package/dist/styles.d.ts.map +1 -0
- package/dist/styles.js +2 -0
- package/dist/styles.js.map +1 -0
- package/dist/tailwind-preset.d.ts +4 -0
- package/dist/tailwind-preset.d.ts.map +1 -0
- package/dist/tailwind-preset.js +69 -0
- package/dist/tailwind-preset.js.map +1 -0
- package/dist/utils.d.ts +4 -0
- package/dist/utils.d.ts.map +1 -0
- package/dist/utils.js +12 -0
- package/dist/utils.js.map +1 -0
- package/package.json +83 -40
- package/dist/index.d.mts +0 -834
- package/dist/index.d.mts.map +0 -1
- package/dist/index.mjs +0 -2918
- package/dist/index.mjs.map +0 -1
- package/dist/tailwind-preset.d.mts +0 -7
- package/dist/tailwind-preset.d.mts.map +0 -1
- package/dist/tailwind-preset.mjs +0 -64
- package/dist/tailwind-preset.mjs.map +0 -1
- package/src/styles/tokens.css +0 -78
|
@@ -0,0 +1,1464 @@
|
|
|
1
|
+
import { jsxs, Fragment, jsx } from "react/jsx-runtime";
|
|
2
|
+
import { useMemo, useState, useEffect, Fragment as Fragment$1 } from "react";
|
|
3
|
+
import { useSort } from "../hooks/use-sort.js";
|
|
4
|
+
import { cn } from "../lib/utils.js";
|
|
5
|
+
import { FilterBar, FilterBarFilterPanel, FilterBarRangePanel } from "../components/FilterBar.js";
|
|
6
|
+
import { Icon } from "./Icon.js";
|
|
7
|
+
import { SortableHeader } from "./SortableHeader.js";
|
|
8
|
+
import { parseTimestamp, chooseTimestampFormat, modeToFormat, resolveDateMath, Timestamp } from "./cells/Timestamp.js";
|
|
9
|
+
import { tagActionsFromRecord, TagActionsProvider, tagFilterTokens, TagList, normalizeTags, splitTagToken } from "./cells/TagList.js";
|
|
10
|
+
import { StatusDot } from "./cells/StatusDot.js";
|
|
11
|
+
import { normalizeStatus } from "./cells/status-mapping.js";
|
|
12
|
+
const DEFAULT_COLUMN_MIN_WIDTH = 64;
|
|
13
|
+
const DEFAULT_COLUMN_WIDTH = 160;
|
|
14
|
+
const DEFAULT_GROW_COLUMN_WIDTH = 224;
|
|
15
|
+
const DEFAULT_SHRINK_COLUMN_WIDTH = 96;
|
|
16
|
+
const COLUMN_WIDTH_STORAGE_PREFIX = "clicky-ui-data-table-column-widths";
|
|
17
|
+
const COLUMN_VISIBILITY_STORAGE_PREFIX = "clicky-ui-data-table-column-visibility";
|
|
18
|
+
const DENSITY_STORAGE_PREFIX = "clicky-ui-data-table-density";
|
|
19
|
+
const DENSITY_OPTIONS = [
|
|
20
|
+
{ value: "compact", icon: "ph:rows", label: "Compact" },
|
|
21
|
+
{ value: "comfortable", icon: "ph:list", label: "Comfortable" },
|
|
22
|
+
{ value: "spacious", icon: "ph:list-dashes", label: "Spacious" }
|
|
23
|
+
];
|
|
24
|
+
const DATA_TABLE_HEADER_DENSITY_CLASS = "px-2.5 py-1.5 density-compact:px-2 density-compact:py-1 density-comfortable:px-2.5 density-comfortable:py-1.5 density-spacious:px-4 density-spacious:py-3";
|
|
25
|
+
const DATA_TABLE_CELL_DENSITY_CLASS = "px-2.5 py-1.5 density-compact:px-2 density-compact:py-0.5 density-comfortable:px-2.5 density-comfortable:py-1.5 density-spacious:px-4 density-spacious:py-3";
|
|
26
|
+
const TIMESTAMP_RANGE_PRESETS = [
|
|
27
|
+
{ label: "Last 5 minutes", from: "now-5m", to: "now" },
|
|
28
|
+
{ label: "Last 15 minutes", from: "now-15m", to: "now" },
|
|
29
|
+
{ label: "Last 1 hour", from: "now-1h", to: "now" },
|
|
30
|
+
{ label: "Last 6 hours", from: "now-6h", to: "now" },
|
|
31
|
+
{ label: "Last 24 hours", from: "now-24h", to: "now" },
|
|
32
|
+
{ label: "Last 7 days", from: "now-7d", to: "now" },
|
|
33
|
+
{ label: "Last 30 days", from: "now-30d", to: "now" }
|
|
34
|
+
];
|
|
35
|
+
function DataTable({
|
|
36
|
+
data,
|
|
37
|
+
columns: columnsInput,
|
|
38
|
+
emptyMessage: _emptyMessage = "No data",
|
|
39
|
+
className,
|
|
40
|
+
autoFilter = false,
|
|
41
|
+
showGlobalFilter = true,
|
|
42
|
+
globalFilter,
|
|
43
|
+
onGlobalFilterChange,
|
|
44
|
+
globalFilterPlaceholder = "Search all columns…",
|
|
45
|
+
defaultSort,
|
|
46
|
+
filterBarProps,
|
|
47
|
+
getRowId,
|
|
48
|
+
onRowClick,
|
|
49
|
+
isRowClickable,
|
|
50
|
+
getRowHref,
|
|
51
|
+
renderExpandedRow,
|
|
52
|
+
resizableColumns = true,
|
|
53
|
+
persistColumnWidths = true,
|
|
54
|
+
columnResizeStorageKey,
|
|
55
|
+
hideableColumns = true,
|
|
56
|
+
persistColumnVisibility = true,
|
|
57
|
+
columnVisibilityStorageKey,
|
|
58
|
+
density,
|
|
59
|
+
defaultDensity,
|
|
60
|
+
onDensityChange,
|
|
61
|
+
persistDensity = true,
|
|
62
|
+
densityStorageKey,
|
|
63
|
+
showDensityControl,
|
|
64
|
+
showHeaderFilters = true
|
|
65
|
+
}) {
|
|
66
|
+
const columns = useMemo(
|
|
67
|
+
() => columnsInput.map(
|
|
68
|
+
(column) => typeof column === "string" ? { key: column, label: column } : column
|
|
69
|
+
),
|
|
70
|
+
[columnsInput]
|
|
71
|
+
);
|
|
72
|
+
const columnKeysSignature = useMemo(
|
|
73
|
+
() => columns.map((column) => column.key).join("|"),
|
|
74
|
+
[columns]
|
|
75
|
+
);
|
|
76
|
+
const resolvedColumnResizeStorageKey = columnResizeStorageKey ?? `${COLUMN_WIDTH_STORAGE_PREFIX}:${columnKeysSignature}`;
|
|
77
|
+
const resolvedColumnVisibilityStorageKey = columnVisibilityStorageKey ?? `${COLUMN_VISIBILITY_STORAGE_PREFIX}:${columnKeysSignature}`;
|
|
78
|
+
const resolvedDensityStorageKey = densityStorageKey ?? `${DENSITY_STORAGE_PREFIX}:${columnKeysSignature}`;
|
|
79
|
+
const [columnWidths, setColumnWidths] = useState(
|
|
80
|
+
() => persistColumnWidths ? readStoredColumnWidths(resolvedColumnResizeStorageKey, columns) : {}
|
|
81
|
+
);
|
|
82
|
+
const [hiddenColumns, setHiddenColumns] = useState(
|
|
83
|
+
() => persistColumnVisibility ? readStoredHiddenColumns(resolvedColumnVisibilityStorageKey, columns) : {}
|
|
84
|
+
);
|
|
85
|
+
const densityControlled = density !== void 0;
|
|
86
|
+
const [localDensityOverride, setLocalDensityOverride] = useState(() => {
|
|
87
|
+
if (densityControlled) return density;
|
|
88
|
+
if (persistDensity)
|
|
89
|
+
return readStoredDensityOverride(resolvedDensityStorageKey) ?? defaultDensity;
|
|
90
|
+
return defaultDensity;
|
|
91
|
+
});
|
|
92
|
+
const [columnMenu, setColumnMenu] = useState(null);
|
|
93
|
+
const [headerFilterMenu, setHeaderFilterMenu] = useState(null);
|
|
94
|
+
const [textFilters, setTextFilters] = useState({});
|
|
95
|
+
const [multiFilters, setMultiFilters] = useState({});
|
|
96
|
+
const [numberFilters, setNumberFilters] = useState({});
|
|
97
|
+
const [expandedRows, setExpandedRows] = useState({});
|
|
98
|
+
const [localGlobalFilter, setLocalGlobalFilter] = useState("");
|
|
99
|
+
const [timeRangeFilter, setTimeRangeFilter] = useState(() => {
|
|
100
|
+
var _a, _b, _c, _d;
|
|
101
|
+
const seed = columns.find(
|
|
102
|
+
(column) => {
|
|
103
|
+
var _a2;
|
|
104
|
+
return column.kind === "timestamp" && ((_a2 = column.timestamp) == null ? void 0 : _a2.defaultRange);
|
|
105
|
+
}
|
|
106
|
+
);
|
|
107
|
+
return {
|
|
108
|
+
from: ((_b = (_a = seed == null ? void 0 : seed.timestamp) == null ? void 0 : _a.defaultRange) == null ? void 0 : _b.from) ?? "",
|
|
109
|
+
to: ((_d = (_c = seed == null ? void 0 : seed.timestamp) == null ? void 0 : _c.defaultRange) == null ? void 0 : _d.to) ?? ""
|
|
110
|
+
};
|
|
111
|
+
});
|
|
112
|
+
useEffect(() => {
|
|
113
|
+
setColumnWidths((current) => {
|
|
114
|
+
const stored = persistColumnWidths ? readStoredColumnWidths(resolvedColumnResizeStorageKey, columns) : {};
|
|
115
|
+
const next = pruneColumnWidths({ ...stored, ...current }, columns);
|
|
116
|
+
return sameColumnWidths(current, next) ? current : next;
|
|
117
|
+
});
|
|
118
|
+
}, [columnKeysSignature, persistColumnWidths, resolvedColumnResizeStorageKey]);
|
|
119
|
+
useEffect(() => {
|
|
120
|
+
if (!persistColumnWidths) return;
|
|
121
|
+
writeStoredColumnWidths(resolvedColumnResizeStorageKey, columnWidths);
|
|
122
|
+
}, [columnWidths, persistColumnWidths, resolvedColumnResizeStorageKey]);
|
|
123
|
+
useEffect(() => {
|
|
124
|
+
setHiddenColumns((current) => {
|
|
125
|
+
const stored = persistColumnVisibility ? readStoredHiddenColumns(resolvedColumnVisibilityStorageKey, columns) : {};
|
|
126
|
+
const next = pruneHiddenColumns({ ...stored, ...current }, columns);
|
|
127
|
+
return sameHiddenColumns(current, next) ? current : next;
|
|
128
|
+
});
|
|
129
|
+
}, [columnKeysSignature, persistColumnVisibility, resolvedColumnVisibilityStorageKey]);
|
|
130
|
+
useEffect(() => {
|
|
131
|
+
if (!persistColumnVisibility) return;
|
|
132
|
+
writeStoredHiddenColumns(resolvedColumnVisibilityStorageKey, hiddenColumns);
|
|
133
|
+
}, [hiddenColumns, persistColumnVisibility, resolvedColumnVisibilityStorageKey]);
|
|
134
|
+
useEffect(() => {
|
|
135
|
+
if (densityControlled) return;
|
|
136
|
+
setLocalDensityOverride(
|
|
137
|
+
persistDensity ? readStoredDensityOverride(resolvedDensityStorageKey) ?? defaultDensity : defaultDensity
|
|
138
|
+
);
|
|
139
|
+
}, [defaultDensity, densityControlled, persistDensity, resolvedDensityStorageKey]);
|
|
140
|
+
useEffect(() => {
|
|
141
|
+
if (densityControlled || !persistDensity) return;
|
|
142
|
+
writeStoredDensityOverride(resolvedDensityStorageKey, localDensityOverride);
|
|
143
|
+
}, [densityControlled, localDensityOverride, persistDensity, resolvedDensityStorageKey]);
|
|
144
|
+
useEffect(() => {
|
|
145
|
+
if (!columnMenu && !headerFilterMenu) return;
|
|
146
|
+
const close = () => {
|
|
147
|
+
setColumnMenu(null);
|
|
148
|
+
setHeaderFilterMenu(null);
|
|
149
|
+
};
|
|
150
|
+
const closeOnEscape = (event) => {
|
|
151
|
+
if (event.key === "Escape") close();
|
|
152
|
+
};
|
|
153
|
+
document.addEventListener("click", close);
|
|
154
|
+
document.addEventListener("keydown", closeOnEscape);
|
|
155
|
+
return () => {
|
|
156
|
+
document.removeEventListener("click", close);
|
|
157
|
+
document.removeEventListener("keydown", closeOnEscape);
|
|
158
|
+
};
|
|
159
|
+
}, [columnMenu, headerFilterMenu]);
|
|
160
|
+
const rows = useMemo(
|
|
161
|
+
() => data.map((row, index) => ({
|
|
162
|
+
id: (getRowId == null ? void 0 : getRowId(row, index)) ?? String(index),
|
|
163
|
+
row
|
|
164
|
+
})),
|
|
165
|
+
[data, getRowId]
|
|
166
|
+
);
|
|
167
|
+
const timestampFormats = useMemo(() => {
|
|
168
|
+
var _a;
|
|
169
|
+
const out = {};
|
|
170
|
+
for (const column of columns) {
|
|
171
|
+
if (column.kind !== "timestamp") continue;
|
|
172
|
+
const dates = [];
|
|
173
|
+
for (const row of data) {
|
|
174
|
+
const raw = resolvePath(row, column.key);
|
|
175
|
+
const parsed = parseTimestamp(raw);
|
|
176
|
+
if (parsed) dates.push(parsed);
|
|
177
|
+
}
|
|
178
|
+
const dataFormat = chooseTimestampFormat(dates);
|
|
179
|
+
out[column.key] = modeToFormat(((_a = column.timestamp) == null ? void 0 : _a.mode) ?? "auto", dataFormat);
|
|
180
|
+
}
|
|
181
|
+
return out;
|
|
182
|
+
}, [columns, data]);
|
|
183
|
+
const effectiveColumns = useMemo(
|
|
184
|
+
() => columns.map((column) => applyKindDefaults(column, timestampFormats[column.key])),
|
|
185
|
+
[columns, timestampFormats]
|
|
186
|
+
);
|
|
187
|
+
const visibleColumns = useMemo(() => {
|
|
188
|
+
if (!hideableColumns) return effectiveColumns;
|
|
189
|
+
const next = effectiveColumns.filter((column) => !hiddenColumns[column.key]);
|
|
190
|
+
return next.length > 0 ? next : effectiveColumns;
|
|
191
|
+
}, [effectiveColumns, hiddenColumns, hideableColumns]);
|
|
192
|
+
const hideableColumnCount = useMemo(
|
|
193
|
+
() => effectiveColumns.filter(isColumnHideable).length,
|
|
194
|
+
[effectiveColumns]
|
|
195
|
+
);
|
|
196
|
+
const visibleHideableColumnCount = useMemo(
|
|
197
|
+
() => visibleColumns.filter(isColumnHideable).length,
|
|
198
|
+
[visibleColumns]
|
|
199
|
+
);
|
|
200
|
+
const showColumnVisibilityControl = hideableColumns && hideableColumnCount > 1;
|
|
201
|
+
const resolvedShowDensityControl = showDensityControl ?? showColumnVisibilityControl;
|
|
202
|
+
const showTablePreferencesControl = showColumnVisibilityControl || resolvedShowDensityControl;
|
|
203
|
+
const densityOverride = densityControlled ? density : localDensityOverride;
|
|
204
|
+
const tagActionsByColumn = useMemo(() => {
|
|
205
|
+
const out = {};
|
|
206
|
+
for (const column of visibleColumns) {
|
|
207
|
+
if (column.kind !== "tags") continue;
|
|
208
|
+
const columnKey = column.key;
|
|
209
|
+
const current = multiFilters[columnKey] ?? {};
|
|
210
|
+
const handler = (next) => setMultiFilters((state) => updateFilterRecord(state, columnKey, next));
|
|
211
|
+
out[columnKey] = tagActionsFromRecord(current, handler);
|
|
212
|
+
}
|
|
213
|
+
return out;
|
|
214
|
+
}, [multiFilters, visibleColumns]);
|
|
215
|
+
const timeRangeColumn = useMemo(() => {
|
|
216
|
+
if (filterBarProps == null ? void 0 : filterBarProps.timeRange) return null;
|
|
217
|
+
return visibleColumns.find(
|
|
218
|
+
(column) => {
|
|
219
|
+
var _a;
|
|
220
|
+
return column.kind === "timestamp" && column.filterable !== false && ((_a = column.timestamp) == null ? void 0 : _a.autoRangeFilter) !== false;
|
|
221
|
+
}
|
|
222
|
+
) ?? null;
|
|
223
|
+
}, [filterBarProps == null ? void 0 : filterBarProps.timeRange, visibleColumns]);
|
|
224
|
+
const filterableColumns = useMemo(
|
|
225
|
+
() => visibleColumns.filter((column) => {
|
|
226
|
+
if (column.filterable === false) return false;
|
|
227
|
+
if (column.kind === "timestamp") return false;
|
|
228
|
+
return true;
|
|
229
|
+
}),
|
|
230
|
+
[visibleColumns]
|
|
231
|
+
);
|
|
232
|
+
const generatedFilters = useMemo(() => {
|
|
233
|
+
if (!autoFilter) return [];
|
|
234
|
+
return filterableColumns.map((column) => {
|
|
235
|
+
var _a;
|
|
236
|
+
const numberBounds = getNumericFilterBounds(rows, column);
|
|
237
|
+
if (numberBounds) {
|
|
238
|
+
return {
|
|
239
|
+
column,
|
|
240
|
+
kind: "number",
|
|
241
|
+
options: [],
|
|
242
|
+
numberBounds
|
|
243
|
+
};
|
|
244
|
+
}
|
|
245
|
+
const values = /* @__PURE__ */ new Set();
|
|
246
|
+
for (const record of rows) {
|
|
247
|
+
for (const token of getFilterTokens(record.row, column)) {
|
|
248
|
+
if (token) values.add(token);
|
|
249
|
+
}
|
|
250
|
+
}
|
|
251
|
+
const options = Array.from(values).sort((left, right) => left.localeCompare(right, void 0, { numeric: true })).map((value) => ({ value, label: value }));
|
|
252
|
+
const multiCap = column.kind === "tags" ? 50 : 20;
|
|
253
|
+
const fitsMulti = options.length >= 2 && options.length <= multiCap;
|
|
254
|
+
if (column.kind === "tags" && fitsMulti) {
|
|
255
|
+
const separator = ((_a = column.tags) == null ? void 0 : _a.separator) ?? "=";
|
|
256
|
+
const groups = groupTagOptions(options, separator);
|
|
257
|
+
if (groups.length >= 2) {
|
|
258
|
+
return {
|
|
259
|
+
column,
|
|
260
|
+
kind: "nested-multi",
|
|
261
|
+
options,
|
|
262
|
+
groups
|
|
263
|
+
};
|
|
264
|
+
}
|
|
265
|
+
}
|
|
266
|
+
return {
|
|
267
|
+
column,
|
|
268
|
+
kind: fitsMulti ? "multi" : "text",
|
|
269
|
+
options
|
|
270
|
+
};
|
|
271
|
+
});
|
|
272
|
+
}, [autoFilter, filterableColumns, rows]);
|
|
273
|
+
useEffect(() => {
|
|
274
|
+
setTextFilters((current) => pruneTextFilterState(current, generatedFilters));
|
|
275
|
+
setMultiFilters((current) => pruneMultiFilterState(current, generatedFilters));
|
|
276
|
+
setNumberFilters((current) => pruneNumberFilterState(current, generatedFilters));
|
|
277
|
+
}, [generatedFilters]);
|
|
278
|
+
const globalFilterControlled = globalFilter !== void 0;
|
|
279
|
+
const effectiveGlobalFilter = globalFilterControlled ? globalFilter : localGlobalFilter;
|
|
280
|
+
const setEffectiveGlobalFilter = globalFilterControlled ? onGlobalFilterChange ?? (() => {
|
|
281
|
+
}) : setLocalGlobalFilter;
|
|
282
|
+
const nativeFilters = useMemo(
|
|
283
|
+
() => generatedFilters.map((filter) => {
|
|
284
|
+
var _a, _b, _c;
|
|
285
|
+
const columnKey = filter.column.key;
|
|
286
|
+
if (filter.kind === "multi") {
|
|
287
|
+
return {
|
|
288
|
+
key: columnKey,
|
|
289
|
+
kind: "multi",
|
|
290
|
+
label: labelText(filter.column),
|
|
291
|
+
value: multiFilters[columnKey] ?? {},
|
|
292
|
+
onChange: (next) => setMultiFilters((current) => updateFilterRecord(current, columnKey, next)),
|
|
293
|
+
options: filter.options
|
|
294
|
+
};
|
|
295
|
+
}
|
|
296
|
+
if (filter.kind === "nested-multi") {
|
|
297
|
+
return {
|
|
298
|
+
key: columnKey,
|
|
299
|
+
kind: "nested-multi",
|
|
300
|
+
label: labelText(filter.column),
|
|
301
|
+
value: multiFilters[columnKey] ?? {},
|
|
302
|
+
onChange: (next) => setMultiFilters((current) => updateFilterRecord(current, columnKey, next)),
|
|
303
|
+
groups: filter.groups ?? []
|
|
304
|
+
};
|
|
305
|
+
}
|
|
306
|
+
if (filter.kind === "number") {
|
|
307
|
+
const numberFilter = {
|
|
308
|
+
key: columnKey,
|
|
309
|
+
kind: "number",
|
|
310
|
+
label: labelText(filter.column),
|
|
311
|
+
value: numberFilters[columnKey] ?? {},
|
|
312
|
+
onChange: (next) => setNumberFilters((current) => updateNumberFilterValue(current, columnKey, next))
|
|
313
|
+
};
|
|
314
|
+
if (((_a = filter.numberBounds) == null ? void 0 : _a.min) !== void 0) {
|
|
315
|
+
numberFilter.domainMin = filter.numberBounds.min;
|
|
316
|
+
}
|
|
317
|
+
if (((_b = filter.numberBounds) == null ? void 0 : _b.max) !== void 0) {
|
|
318
|
+
numberFilter.domainMax = filter.numberBounds.max;
|
|
319
|
+
}
|
|
320
|
+
if (((_c = filter.numberBounds) == null ? void 0 : _c.step) !== void 0) {
|
|
321
|
+
numberFilter.step = filter.numberBounds.step;
|
|
322
|
+
}
|
|
323
|
+
return numberFilter;
|
|
324
|
+
}
|
|
325
|
+
return {
|
|
326
|
+
key: columnKey,
|
|
327
|
+
kind: "text",
|
|
328
|
+
label: labelText(filter.column),
|
|
329
|
+
value: textFilters[columnKey] ?? "",
|
|
330
|
+
onChange: (next) => setTextFilters((current) => updateFilterValue(current, columnKey, next))
|
|
331
|
+
};
|
|
332
|
+
}),
|
|
333
|
+
[generatedFilters, multiFilters, numberFilters, textFilters]
|
|
334
|
+
);
|
|
335
|
+
const nativeFilterByColumn = useMemo(
|
|
336
|
+
() => new Map(nativeFilters.map((filter) => [filter.key, filter])),
|
|
337
|
+
[nativeFilters]
|
|
338
|
+
);
|
|
339
|
+
const hasCustomFilterBarContent = Boolean(
|
|
340
|
+
(filterBarProps == null ? void 0 : filterBarProps.leading) || (filterBarProps == null ? void 0 : filterBarProps.children) || (filterBarProps == null ? void 0 : filterBarProps.trailing) || (filterBarProps == null ? void 0 : filterBarProps.timeRange) || (filterBarProps == null ? void 0 : filterBarProps.dateRange)
|
|
341
|
+
);
|
|
342
|
+
const autoTimeRange = useMemo(() => {
|
|
343
|
+
var _a;
|
|
344
|
+
if (!autoFilter || !timeRangeColumn) return null;
|
|
345
|
+
return {
|
|
346
|
+
from: timeRangeFilter.from,
|
|
347
|
+
to: timeRangeFilter.to,
|
|
348
|
+
onApply: (from, to) => setTimeRangeFilter({ from, to }),
|
|
349
|
+
presets: ((_a = timeRangeColumn.timestamp) == null ? void 0 : _a.rangePresets) ?? TIMESTAMP_RANGE_PRESETS,
|
|
350
|
+
fromPlaceholder: "now-24h",
|
|
351
|
+
toPlaceholder: "now",
|
|
352
|
+
emptyLabel: "Any time"
|
|
353
|
+
};
|
|
354
|
+
}, [autoFilter, timeRangeColumn, timeRangeFilter.from, timeRangeFilter.to]);
|
|
355
|
+
const showFilterBar = autoFilter && (showGlobalFilter || nativeFilters.length > 0 || !!autoTimeRange) || hasCustomFilterBarContent || showTablePreferencesControl;
|
|
356
|
+
const setDensityOverride = (next) => {
|
|
357
|
+
if (!densityControlled) setLocalDensityOverride(next);
|
|
358
|
+
onDensityChange == null ? void 0 : onDensityChange(next);
|
|
359
|
+
};
|
|
360
|
+
const filterBarTrailing = showTablePreferencesControl ? /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
361
|
+
filterBarProps == null ? void 0 : filterBarProps.trailing,
|
|
362
|
+
/* @__PURE__ */ jsx(ColumnVisibilityTrigger, { onOpen: (event) => setColumnMenu(menuStateFromTrigger(event)) })
|
|
363
|
+
] }) : filterBarProps == null ? void 0 : filterBarProps.trailing;
|
|
364
|
+
const showHeaderFilterControls = autoFilter && showHeaderFilters;
|
|
365
|
+
const filteredRows = useMemo(() => {
|
|
366
|
+
const globalNeedle = effectiveGlobalFilter.trim().toLowerCase();
|
|
367
|
+
const now = /* @__PURE__ */ new Date();
|
|
368
|
+
const rangeFromDate = timeRangeColumn ? resolveDateMath(timeRangeFilter.from, now) : null;
|
|
369
|
+
const rangeToDate = timeRangeColumn ? resolveDateMath(timeRangeFilter.to, now) : null;
|
|
370
|
+
const rangeColumnKey = timeRangeColumn == null ? void 0 : timeRangeColumn.key;
|
|
371
|
+
return rows.filter(({ row }) => {
|
|
372
|
+
if (rangeColumnKey && (rangeFromDate || rangeToDate)) {
|
|
373
|
+
const raw = resolvePath(row, rangeColumnKey);
|
|
374
|
+
const ts = parseTimestamp(raw);
|
|
375
|
+
if (!ts) return false;
|
|
376
|
+
if (rangeFromDate && ts.getTime() < rangeFromDate.getTime()) return false;
|
|
377
|
+
if (rangeToDate && ts.getTime() > rangeToDate.getTime()) return false;
|
|
378
|
+
}
|
|
379
|
+
if (globalNeedle) {
|
|
380
|
+
const haystack = filterableColumns.flatMap((column) => getFilterTokens(row, column)).join(" ").toLowerCase();
|
|
381
|
+
if (!haystack.includes(globalNeedle)) {
|
|
382
|
+
return false;
|
|
383
|
+
}
|
|
384
|
+
}
|
|
385
|
+
for (const filter of generatedFilters) {
|
|
386
|
+
const tokens = getFilterTokens(row, filter.column);
|
|
387
|
+
if (filter.kind === "text") {
|
|
388
|
+
const needle = (textFilters[filter.column.key] ?? "").trim().toLowerCase();
|
|
389
|
+
if (needle && !tokens.some((token) => token.toLowerCase().includes(needle))) {
|
|
390
|
+
return false;
|
|
391
|
+
}
|
|
392
|
+
} else if (filter.kind === "number") {
|
|
393
|
+
const range = numberFilters[filter.column.key] ?? {};
|
|
394
|
+
const min = parseNumberInput(range.min);
|
|
395
|
+
const max = parseNumberInput(range.max);
|
|
396
|
+
const hasMin = String(range.min ?? "").trim() !== "";
|
|
397
|
+
const hasMax = String(range.max ?? "").trim() !== "";
|
|
398
|
+
if (hasMin || hasMax) {
|
|
399
|
+
const values = getFilterNumbers(row, filter.column);
|
|
400
|
+
const matches = values.some(
|
|
401
|
+
(value) => (min == null || value >= min) && (max == null || value <= max)
|
|
402
|
+
);
|
|
403
|
+
if (!matches) {
|
|
404
|
+
return false;
|
|
405
|
+
}
|
|
406
|
+
}
|
|
407
|
+
} else {
|
|
408
|
+
const selected = multiFilters[filter.column.key] ?? {};
|
|
409
|
+
const include = Object.entries(selected).filter(([, mode]) => mode === "include").map(([value]) => value);
|
|
410
|
+
const exclude = Object.entries(selected).filter(([, mode]) => mode === "exclude").map(([value]) => value);
|
|
411
|
+
if (include.length > 0 && !tokens.some((token) => include.includes(token))) {
|
|
412
|
+
return false;
|
|
413
|
+
}
|
|
414
|
+
if (exclude.length > 0 && tokens.some((token) => exclude.includes(token))) {
|
|
415
|
+
return false;
|
|
416
|
+
}
|
|
417
|
+
}
|
|
418
|
+
}
|
|
419
|
+
return true;
|
|
420
|
+
});
|
|
421
|
+
}, [
|
|
422
|
+
effectiveGlobalFilter,
|
|
423
|
+
filterableColumns,
|
|
424
|
+
generatedFilters,
|
|
425
|
+
multiFilters,
|
|
426
|
+
numberFilters,
|
|
427
|
+
rows,
|
|
428
|
+
textFilters,
|
|
429
|
+
timeRangeColumn,
|
|
430
|
+
timeRangeFilter.from,
|
|
431
|
+
timeRangeFilter.to
|
|
432
|
+
]);
|
|
433
|
+
const sortResolvers = useMemo(
|
|
434
|
+
() => Object.fromEntries(
|
|
435
|
+
effectiveColumns.map((column) => [
|
|
436
|
+
column.key,
|
|
437
|
+
(record) => getSortValue(record.row, column)
|
|
438
|
+
])
|
|
439
|
+
),
|
|
440
|
+
[effectiveColumns]
|
|
441
|
+
);
|
|
442
|
+
const { sorted, sort, toggle } = useSort(filteredRows, {
|
|
443
|
+
defaultDir: (defaultSort == null ? void 0 : defaultSort.dir) ?? "asc",
|
|
444
|
+
resolvers: sortResolvers,
|
|
445
|
+
...(defaultSort == null ? void 0 : defaultSort.key) ? { defaultKey: defaultSort.key } : {}
|
|
446
|
+
});
|
|
447
|
+
const startColumnResize = (event, column) => {
|
|
448
|
+
event.preventDefault();
|
|
449
|
+
event.stopPropagation();
|
|
450
|
+
const startX = event.clientX;
|
|
451
|
+
const header = event.currentTarget.closest("th");
|
|
452
|
+
const measuredWidth = (header == null ? void 0 : header.getBoundingClientRect().width) ?? 0;
|
|
453
|
+
const startWidth = measuredWidth || columnWidths[column.key] || defaultColumnWidth(column);
|
|
454
|
+
const onMove = (moveEvent) => {
|
|
455
|
+
const nextWidth = clampColumnWidth(column, startWidth + moveEvent.clientX - startX);
|
|
456
|
+
setColumnWidths((current) => ({
|
|
457
|
+
...current,
|
|
458
|
+
[column.key]: nextWidth
|
|
459
|
+
}));
|
|
460
|
+
};
|
|
461
|
+
const onUp = () => {
|
|
462
|
+
document.removeEventListener("mousemove", onMove);
|
|
463
|
+
document.removeEventListener("mouseup", onUp);
|
|
464
|
+
document.body.style.cursor = "";
|
|
465
|
+
document.body.style.userSelect = "";
|
|
466
|
+
};
|
|
467
|
+
document.addEventListener("mousemove", onMove);
|
|
468
|
+
document.addEventListener("mouseup", onUp);
|
|
469
|
+
document.body.style.cursor = "col-resize";
|
|
470
|
+
document.body.style.userSelect = "none";
|
|
471
|
+
};
|
|
472
|
+
const autoFitColumn = (event, column) => {
|
|
473
|
+
var _a;
|
|
474
|
+
event.preventDefault();
|
|
475
|
+
event.stopPropagation();
|
|
476
|
+
const header = event.currentTarget.closest("th");
|
|
477
|
+
const table = event.currentTarget.closest("table");
|
|
478
|
+
if (!header || !table) return;
|
|
479
|
+
const columnIndex = Array.from(((_a = header.parentElement) == null ? void 0 : _a.children) ?? []).indexOf(header);
|
|
480
|
+
if (columnIndex < 0) return;
|
|
481
|
+
const width = measureColumnContentWidth(table, columnIndex, column);
|
|
482
|
+
setColumnWidths((current) => ({
|
|
483
|
+
...current,
|
|
484
|
+
[column.key]: width
|
|
485
|
+
}));
|
|
486
|
+
};
|
|
487
|
+
const toggleColumnVisibility = (column) => {
|
|
488
|
+
if (!isColumnHideable(column)) return;
|
|
489
|
+
setHiddenColumns((current) => {
|
|
490
|
+
const hidden = current[column.key] === true;
|
|
491
|
+
if (!hidden && visibleHideableColumnCount <= 1) return current;
|
|
492
|
+
const next = { ...current };
|
|
493
|
+
if (hidden) {
|
|
494
|
+
delete next[column.key];
|
|
495
|
+
} else {
|
|
496
|
+
next[column.key] = true;
|
|
497
|
+
}
|
|
498
|
+
return pruneHiddenColumns(next, columns);
|
|
499
|
+
});
|
|
500
|
+
};
|
|
501
|
+
const showAllColumns = () => setHiddenColumns({});
|
|
502
|
+
const openHeaderColumnMenu = (event, column) => {
|
|
503
|
+
if (!showColumnVisibilityControl) return;
|
|
504
|
+
event.preventDefault();
|
|
505
|
+
setColumnMenu(menuStateFromPointer(event, column.key));
|
|
506
|
+
};
|
|
507
|
+
const openHeaderFilterMenu = (event, columnKey) => {
|
|
508
|
+
event.preventDefault();
|
|
509
|
+
event.stopPropagation();
|
|
510
|
+
setHeaderFilterMenu(menuStateFromTrigger(event, columnKey));
|
|
511
|
+
};
|
|
512
|
+
return /* @__PURE__ */ jsxs("div", { className: cn("flex min-h-0 flex-col gap-3", className), "data-density": densityOverride, children: [
|
|
513
|
+
showFilterBar && /* @__PURE__ */ jsx(
|
|
514
|
+
FilterBar,
|
|
515
|
+
{
|
|
516
|
+
...filterBarProps,
|
|
517
|
+
...autoFilter && showGlobalFilter ? {
|
|
518
|
+
search: {
|
|
519
|
+
value: effectiveGlobalFilter,
|
|
520
|
+
onChange: setEffectiveGlobalFilter,
|
|
521
|
+
placeholder: globalFilterPlaceholder
|
|
522
|
+
}
|
|
523
|
+
} : {},
|
|
524
|
+
...autoTimeRange ? { timeRange: autoTimeRange } : {},
|
|
525
|
+
trailing: filterBarTrailing,
|
|
526
|
+
filters: nativeFilters
|
|
527
|
+
}
|
|
528
|
+
),
|
|
529
|
+
/* @__PURE__ */ jsx("div", { className: "min-h-0 flex-1 overflow-auto rounded-md border border-border", children: /* @__PURE__ */ jsxs("table", { className: "w-max table-auto text-left text-sm", children: [
|
|
530
|
+
/* @__PURE__ */ jsx("colgroup", { children: visibleColumns.map((column) => /* @__PURE__ */ jsx(
|
|
531
|
+
"col",
|
|
532
|
+
{
|
|
533
|
+
style: columnStyle(column, columnWidths),
|
|
534
|
+
className: column.shrink && !column.grow ? "w-px" : void 0
|
|
535
|
+
},
|
|
536
|
+
column.key
|
|
537
|
+
)) }),
|
|
538
|
+
/* @__PURE__ */ jsx("thead", { className: "sticky top-0 z-10 bg-muted shadow-[0_1px_0_0_var(--tw-shadow-color)] shadow-border", children: /* @__PURE__ */ jsx("tr", { className: "border-b border-border text-xs text-muted-foreground", children: visibleColumns.map((column) => /* @__PURE__ */ jsxs(
|
|
539
|
+
"th",
|
|
540
|
+
{
|
|
541
|
+
className: cn(
|
|
542
|
+
"group/header relative whitespace-nowrap font-medium",
|
|
543
|
+
DATA_TABLE_HEADER_DENSITY_CLASS,
|
|
544
|
+
alignmentClass(column.align),
|
|
545
|
+
resizableColumns && column.resizable !== false && "select-none",
|
|
546
|
+
column.headerClassName
|
|
547
|
+
),
|
|
548
|
+
onContextMenu: (event) => openHeaderColumnMenu(event, column),
|
|
549
|
+
children: [
|
|
550
|
+
/* @__PURE__ */ jsxs(
|
|
551
|
+
"div",
|
|
552
|
+
{
|
|
553
|
+
className: cn(
|
|
554
|
+
"flex min-w-0 items-center gap-1",
|
|
555
|
+
headerAlignmentClass(column.align),
|
|
556
|
+
resizableColumns && column.resizable !== false && "pr-2"
|
|
557
|
+
),
|
|
558
|
+
children: [
|
|
559
|
+
/* @__PURE__ */ jsx("span", { className: "min-w-0", children: column.sortable === false ? /* @__PURE__ */ jsx("span", { children: column.label }) : /* @__PURE__ */ jsx(
|
|
560
|
+
SortableHeader,
|
|
561
|
+
{
|
|
562
|
+
active: (sort == null ? void 0 : sort.key) === column.key,
|
|
563
|
+
...(sort == null ? void 0 : sort.key) === column.key ? { dir: sort.dir } : {},
|
|
564
|
+
...column.align ? { align: column.align } : {},
|
|
565
|
+
onClick: () => toggle(column.key),
|
|
566
|
+
children: column.label
|
|
567
|
+
}
|
|
568
|
+
) }),
|
|
569
|
+
showHeaderFilterControls && (nativeFilterByColumn.has(column.key) || autoTimeRange && (timeRangeColumn == null ? void 0 : timeRangeColumn.key) === column.key) && /* @__PURE__ */ jsx(
|
|
570
|
+
HeaderFilterButton,
|
|
571
|
+
{
|
|
572
|
+
column,
|
|
573
|
+
active: nativeFilterByColumn.has(column.key) ? isFilterBarFilterActive(nativeFilterByColumn.get(column.key)) : Boolean(timeRangeFilter.from || timeRangeFilter.to),
|
|
574
|
+
onOpen: (event) => openHeaderFilterMenu(event, column.key)
|
|
575
|
+
}
|
|
576
|
+
)
|
|
577
|
+
]
|
|
578
|
+
}
|
|
579
|
+
),
|
|
580
|
+
resizableColumns && column.resizable !== false && /* @__PURE__ */ jsx(
|
|
581
|
+
"span",
|
|
582
|
+
{
|
|
583
|
+
role: "separator",
|
|
584
|
+
"aria-label": `Resize ${labelText(column)} column`,
|
|
585
|
+
"aria-orientation": "vertical",
|
|
586
|
+
className: "absolute right-0 top-0 flex h-full w-3 cursor-col-resize touch-none items-center justify-center border-r border-border/70 bg-gradient-to-l from-border/30 to-transparent transition-colors hover:border-primary hover:from-primary/20",
|
|
587
|
+
onClick: (event) => {
|
|
588
|
+
event.preventDefault();
|
|
589
|
+
event.stopPropagation();
|
|
590
|
+
},
|
|
591
|
+
onDoubleClick: (event) => autoFitColumn(event, column),
|
|
592
|
+
onMouseDown: (event) => startColumnResize(event, column),
|
|
593
|
+
children: /* @__PURE__ */ jsx(
|
|
594
|
+
"span",
|
|
595
|
+
{
|
|
596
|
+
"aria-hidden": true,
|
|
597
|
+
className: "h-4 w-0.5 rounded-full bg-border transition-colors group-hover/header:bg-primary/70"
|
|
598
|
+
}
|
|
599
|
+
)
|
|
600
|
+
}
|
|
601
|
+
)
|
|
602
|
+
]
|
|
603
|
+
},
|
|
604
|
+
column.key
|
|
605
|
+
)) }) }),
|
|
606
|
+
/* @__PURE__ */ jsx("tbody", { children: sorted.map((record) => {
|
|
607
|
+
const href = getRowHref == null ? void 0 : getRowHref(record.row);
|
|
608
|
+
const expanded = expandedRows[record.id] ?? false;
|
|
609
|
+
const expandedContent = (renderExpandedRow == null ? void 0 : renderExpandedRow(record.row, {
|
|
610
|
+
columns: effectiveColumns,
|
|
611
|
+
visibleColumns,
|
|
612
|
+
tagActionsByColumn
|
|
613
|
+
})) ?? null;
|
|
614
|
+
const expandable = expandedContent !== null;
|
|
615
|
+
const rowClickEnabled = (isRowClickable == null ? void 0 : isRowClickable(record.row)) ?? !!onRowClick;
|
|
616
|
+
const clickable = !!href || rowClickEnabled || expandable;
|
|
617
|
+
return /* @__PURE__ */ jsxs(Fragment$1, { children: [
|
|
618
|
+
/* @__PURE__ */ jsx(
|
|
619
|
+
"tr",
|
|
620
|
+
{
|
|
621
|
+
className: cn(
|
|
622
|
+
"border-b border-border/60 align-top",
|
|
623
|
+
clickable && "cursor-pointer hover:bg-accent/40"
|
|
624
|
+
),
|
|
625
|
+
onClick: () => {
|
|
626
|
+
if (expandable) {
|
|
627
|
+
setExpandedRows((current) => ({
|
|
628
|
+
...current,
|
|
629
|
+
[record.id]: !current[record.id]
|
|
630
|
+
}));
|
|
631
|
+
}
|
|
632
|
+
if (rowClickEnabled) {
|
|
633
|
+
onRowClick == null ? void 0 : onRowClick(record.row);
|
|
634
|
+
}
|
|
635
|
+
},
|
|
636
|
+
children: visibleColumns.map((column, index) => {
|
|
637
|
+
const rawValue = resolvePath(record.row, column.key);
|
|
638
|
+
let content = column.render ? column.render(rawValue, record.row) : formatCell(rawValue);
|
|
639
|
+
if (column.kind === "tags" && tagActionsByColumn[column.key]) {
|
|
640
|
+
content = /* @__PURE__ */ jsx(TagActionsProvider, { value: tagActionsByColumn[column.key], children: content });
|
|
641
|
+
}
|
|
642
|
+
return /* @__PURE__ */ jsx(
|
|
643
|
+
"td",
|
|
644
|
+
{
|
|
645
|
+
className: cn(
|
|
646
|
+
DATA_TABLE_CELL_DENSITY_CLASS,
|
|
647
|
+
alignmentClass(column.align),
|
|
648
|
+
column.cellClassName
|
|
649
|
+
),
|
|
650
|
+
children: /* @__PURE__ */ jsx(
|
|
651
|
+
CellContent,
|
|
652
|
+
{
|
|
653
|
+
column,
|
|
654
|
+
...columnWidths[column.key] !== void 0 ? { width: columnWidths[column.key] } : {},
|
|
655
|
+
children: href && index === 0 ? /* @__PURE__ */ jsx("a", { href, className: "hover:underline", children: content }) : content
|
|
656
|
+
}
|
|
657
|
+
)
|
|
658
|
+
},
|
|
659
|
+
column.key
|
|
660
|
+
);
|
|
661
|
+
})
|
|
662
|
+
}
|
|
663
|
+
),
|
|
664
|
+
expanded && expandedContent && /* @__PURE__ */ jsx("tr", { children: /* @__PURE__ */ jsx("td", { colSpan: visibleColumns.length, className: "bg-muted/40 p-density-3", children: /* @__PURE__ */ jsx("div", { className: "rounded-md border border-border bg-background p-density-3", children: expandedContent }) }) })
|
|
665
|
+
] }, record.id);
|
|
666
|
+
}) })
|
|
667
|
+
] }) }),
|
|
668
|
+
/* @__PURE__ */ jsxs("div", { className: "px-1 text-xs text-muted-foreground", children: [
|
|
669
|
+
sorted.length,
|
|
670
|
+
" of ",
|
|
671
|
+
data.length,
|
|
672
|
+
" row",
|
|
673
|
+
data.length === 1 ? "" : "s"
|
|
674
|
+
] }),
|
|
675
|
+
columnMenu && showTablePreferencesControl && /* @__PURE__ */ jsx(
|
|
676
|
+
ColumnVisibilityMenu,
|
|
677
|
+
{
|
|
678
|
+
columns: effectiveColumns,
|
|
679
|
+
hiddenColumns,
|
|
680
|
+
anchor: columnMenu,
|
|
681
|
+
showColumnVisibilityControl,
|
|
682
|
+
showDensityControl: resolvedShowDensityControl,
|
|
683
|
+
densityOverride,
|
|
684
|
+
visibleHideableColumnCount,
|
|
685
|
+
onToggle: toggleColumnVisibility,
|
|
686
|
+
onShowAll: showAllColumns,
|
|
687
|
+
onDensityChange: setDensityOverride,
|
|
688
|
+
onClose: () => setColumnMenu(null)
|
|
689
|
+
}
|
|
690
|
+
),
|
|
691
|
+
headerFilterMenu && /* @__PURE__ */ jsx(
|
|
692
|
+
HeaderFilterMenu,
|
|
693
|
+
{
|
|
694
|
+
filter: nativeFilterByColumn.get(headerFilterMenu.columnKey ?? ""),
|
|
695
|
+
...autoTimeRange && (timeRangeColumn == null ? void 0 : timeRangeColumn.key) === headerFilterMenu.columnKey ? { timeRange: autoTimeRange } : {},
|
|
696
|
+
anchor: headerFilterMenu,
|
|
697
|
+
onClose: () => setHeaderFilterMenu(null)
|
|
698
|
+
}
|
|
699
|
+
)
|
|
700
|
+
] });
|
|
701
|
+
}
|
|
702
|
+
function HeaderFilterButton({
|
|
703
|
+
column,
|
|
704
|
+
active,
|
|
705
|
+
onOpen
|
|
706
|
+
}) {
|
|
707
|
+
return /* @__PURE__ */ jsx(
|
|
708
|
+
"button",
|
|
709
|
+
{
|
|
710
|
+
type: "button",
|
|
711
|
+
"aria-label": `Open ${labelText(column)} column filter`,
|
|
712
|
+
"aria-haspopup": "dialog",
|
|
713
|
+
"aria-pressed": active,
|
|
714
|
+
className: cn(
|
|
715
|
+
"inline-flex h-5 w-5 shrink-0 items-center justify-center rounded text-muted-foreground transition-colors hover:bg-accent hover:text-accent-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring",
|
|
716
|
+
active && "bg-accent text-foreground"
|
|
717
|
+
),
|
|
718
|
+
onClick: onOpen,
|
|
719
|
+
children: /* @__PURE__ */ jsx(Icon, { name: "codicon:filter", className: "text-xs" })
|
|
720
|
+
}
|
|
721
|
+
);
|
|
722
|
+
}
|
|
723
|
+
function HeaderFilterMenu({
|
|
724
|
+
filter,
|
|
725
|
+
timeRange,
|
|
726
|
+
anchor,
|
|
727
|
+
onClose
|
|
728
|
+
}) {
|
|
729
|
+
if (!filter && !timeRange) return null;
|
|
730
|
+
const label = (filter == null ? void 0 : filter.label) ?? "Time range";
|
|
731
|
+
const timeRangeActive = Boolean((timeRange == null ? void 0 : timeRange.from) || (timeRange == null ? void 0 : timeRange.to));
|
|
732
|
+
return /* @__PURE__ */ jsxs(
|
|
733
|
+
"div",
|
|
734
|
+
{
|
|
735
|
+
role: "dialog",
|
|
736
|
+
"aria-label": `${label} column filter`,
|
|
737
|
+
className: "fixed z-50 rounded-md border border-border bg-popover p-2 text-popover-foreground shadow-lg shadow-black/5",
|
|
738
|
+
style: { left: anchor.x, top: anchor.y },
|
|
739
|
+
onClick: (event) => event.stopPropagation(),
|
|
740
|
+
onContextMenu: (event) => event.preventDefault(),
|
|
741
|
+
children: [
|
|
742
|
+
/* @__PURE__ */ jsxs("div", { className: "mb-2 flex items-center justify-between gap-3", children: [
|
|
743
|
+
/* @__PURE__ */ jsx("div", { className: "truncate text-xs font-semibold uppercase tracking-wide text-muted-foreground", children: label }),
|
|
744
|
+
/* @__PURE__ */ jsxs("div", { className: "flex items-center gap-1", children: [
|
|
745
|
+
filter && /* @__PURE__ */ jsx(
|
|
746
|
+
"button",
|
|
747
|
+
{
|
|
748
|
+
type: "button",
|
|
749
|
+
className: "rounded px-1.5 py-0.5 text-xs text-primary transition-colors hover:bg-accent focus:bg-accent focus:outline-none disabled:text-muted-foreground",
|
|
750
|
+
onClick: () => clearFilterBarFilter(filter),
|
|
751
|
+
disabled: !isFilterBarFilterActive(filter),
|
|
752
|
+
children: "Clear all"
|
|
753
|
+
}
|
|
754
|
+
),
|
|
755
|
+
timeRange && /* @__PURE__ */ jsx(
|
|
756
|
+
"button",
|
|
757
|
+
{
|
|
758
|
+
type: "button",
|
|
759
|
+
className: "rounded px-1.5 py-0.5 text-xs text-primary transition-colors hover:bg-accent focus:bg-accent focus:outline-none disabled:text-muted-foreground",
|
|
760
|
+
onClick: () => timeRange.onApply("", ""),
|
|
761
|
+
disabled: !timeRangeActive,
|
|
762
|
+
children: "Clear all"
|
|
763
|
+
}
|
|
764
|
+
),
|
|
765
|
+
/* @__PURE__ */ jsx(
|
|
766
|
+
"button",
|
|
767
|
+
{
|
|
768
|
+
type: "button",
|
|
769
|
+
"aria-label": "Close column filter",
|
|
770
|
+
title: "Close",
|
|
771
|
+
className: "inline-flex h-6 w-6 items-center justify-center rounded text-muted-foreground transition-colors hover:bg-accent hover:text-accent-foreground focus:bg-accent focus:outline-none",
|
|
772
|
+
onClick: onClose,
|
|
773
|
+
children: /* @__PURE__ */ jsx(Icon, { name: "codicon:close", className: "text-sm" })
|
|
774
|
+
}
|
|
775
|
+
)
|
|
776
|
+
] })
|
|
777
|
+
] }),
|
|
778
|
+
/* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-2", children: [
|
|
779
|
+
filter && /* @__PURE__ */ jsx(FilterBarFilterPanel, { filter, chrome: "embedded" }),
|
|
780
|
+
timeRange && /* @__PURE__ */ jsx(FilterBarRangePanel, { kind: "time", label: "Time range", ...timeRange })
|
|
781
|
+
] })
|
|
782
|
+
]
|
|
783
|
+
}
|
|
784
|
+
);
|
|
785
|
+
}
|
|
786
|
+
function clearFilterBarFilter(filter) {
|
|
787
|
+
if (filter.kind === "text" || filter.kind === "lookup" || filter.kind === "enum") {
|
|
788
|
+
filter.onChange("");
|
|
789
|
+
return;
|
|
790
|
+
}
|
|
791
|
+
if (filter.kind === "lookup-multi" || filter.kind === "select-multi") {
|
|
792
|
+
filter.onChange([]);
|
|
793
|
+
return;
|
|
794
|
+
}
|
|
795
|
+
if (filter.kind === "number") {
|
|
796
|
+
filter.onChange({});
|
|
797
|
+
return;
|
|
798
|
+
}
|
|
799
|
+
if (filter.kind === "boolean") {
|
|
800
|
+
filter.onChange(false);
|
|
801
|
+
return;
|
|
802
|
+
}
|
|
803
|
+
filter.onChange({});
|
|
804
|
+
}
|
|
805
|
+
function ColumnVisibilityTrigger({
|
|
806
|
+
onOpen
|
|
807
|
+
}) {
|
|
808
|
+
return /* @__PURE__ */ jsx(
|
|
809
|
+
"button",
|
|
810
|
+
{
|
|
811
|
+
type: "button",
|
|
812
|
+
"aria-label": "Open column menu",
|
|
813
|
+
"aria-haspopup": "menu",
|
|
814
|
+
className: "inline-flex h-[34px] w-[34px] items-center justify-center rounded-md border border-input bg-background text-muted-foreground transition-colors hover:bg-accent hover:text-accent-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2",
|
|
815
|
+
onClick: (event) => {
|
|
816
|
+
event.stopPropagation();
|
|
817
|
+
onOpen(event);
|
|
818
|
+
},
|
|
819
|
+
children: /* @__PURE__ */ jsx(Icon, { name: "codicon:ellipsis", className: "text-sm" })
|
|
820
|
+
}
|
|
821
|
+
);
|
|
822
|
+
}
|
|
823
|
+
function ColumnVisibilityMenu({
|
|
824
|
+
columns,
|
|
825
|
+
hiddenColumns,
|
|
826
|
+
anchor,
|
|
827
|
+
showColumnVisibilityControl,
|
|
828
|
+
showDensityControl,
|
|
829
|
+
densityOverride,
|
|
830
|
+
visibleHideableColumnCount,
|
|
831
|
+
onToggle,
|
|
832
|
+
onShowAll,
|
|
833
|
+
onDensityChange,
|
|
834
|
+
onClose
|
|
835
|
+
}) {
|
|
836
|
+
const activeColumn = anchor.columnKey ? columns.find((column) => column.key === anchor.columnKey) : void 0;
|
|
837
|
+
const canHideActiveColumn = activeColumn && isColumnHideable(activeColumn) && visibleHideableColumnCount > 1;
|
|
838
|
+
return /* @__PURE__ */ jsxs(
|
|
839
|
+
"div",
|
|
840
|
+
{
|
|
841
|
+
role: "menu",
|
|
842
|
+
"aria-label": "Column menu",
|
|
843
|
+
className: "fixed z-50 min-w-[16rem] rounded-md border border-border bg-popover p-1.5 text-popover-foreground shadow-lg shadow-black/5",
|
|
844
|
+
style: { left: anchor.x, top: anchor.y },
|
|
845
|
+
onClick: (event) => event.stopPropagation(),
|
|
846
|
+
onContextMenu: (event) => event.preventDefault(),
|
|
847
|
+
children: [
|
|
848
|
+
showColumnVisibilityControl && /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
849
|
+
/* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between gap-3 px-2 py-1.5 text-xs font-medium text-muted-foreground", children: [
|
|
850
|
+
/* @__PURE__ */ jsx("span", { children: "Columns" }),
|
|
851
|
+
/* @__PURE__ */ jsx(
|
|
852
|
+
"button",
|
|
853
|
+
{
|
|
854
|
+
type: "button",
|
|
855
|
+
className: "rounded px-1.5 py-0.5 text-xs text-foreground transition-colors hover:bg-accent hover:text-accent-foreground focus:bg-accent focus:outline-none",
|
|
856
|
+
onClick: onShowAll,
|
|
857
|
+
children: "Show all"
|
|
858
|
+
}
|
|
859
|
+
)
|
|
860
|
+
] }),
|
|
861
|
+
activeColumn && /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
862
|
+
/* @__PURE__ */ jsxs(
|
|
863
|
+
"button",
|
|
864
|
+
{
|
|
865
|
+
type: "button",
|
|
866
|
+
role: "menuitem",
|
|
867
|
+
disabled: !canHideActiveColumn,
|
|
868
|
+
className: cn(
|
|
869
|
+
"flex w-full items-center gap-2 rounded-md px-2 py-1.5 text-left text-sm transition-colors hover:bg-accent hover:text-accent-foreground focus:bg-accent focus:outline-none",
|
|
870
|
+
!canHideActiveColumn && "cursor-not-allowed opacity-50"
|
|
871
|
+
),
|
|
872
|
+
onClick: () => {
|
|
873
|
+
if (!canHideActiveColumn) return;
|
|
874
|
+
onToggle(activeColumn);
|
|
875
|
+
onClose();
|
|
876
|
+
},
|
|
877
|
+
children: [
|
|
878
|
+
/* @__PURE__ */ jsx(Icon, { name: "codicon:eye-closed", className: "text-sm text-muted-foreground" }),
|
|
879
|
+
/* @__PURE__ */ jsxs("span", { children: [
|
|
880
|
+
"Hide ",
|
|
881
|
+
labelText(activeColumn)
|
|
882
|
+
] })
|
|
883
|
+
]
|
|
884
|
+
}
|
|
885
|
+
),
|
|
886
|
+
/* @__PURE__ */ jsx("div", { className: "my-1 h-px bg-border" })
|
|
887
|
+
] }),
|
|
888
|
+
/* @__PURE__ */ jsx("div", { className: "max-h-72 overflow-auto", children: columns.map((column) => {
|
|
889
|
+
const hideable = isColumnHideable(column);
|
|
890
|
+
const visible = hiddenColumns[column.key] !== true;
|
|
891
|
+
const disabled = !hideable || visible && visibleHideableColumnCount <= 1;
|
|
892
|
+
return /* @__PURE__ */ jsxs(
|
|
893
|
+
"label",
|
|
894
|
+
{
|
|
895
|
+
className: cn(
|
|
896
|
+
"flex cursor-pointer items-center gap-2 rounded-md px-2 py-1.5 text-sm transition-colors hover:bg-accent hover:text-accent-foreground",
|
|
897
|
+
disabled && "cursor-not-allowed opacity-50"
|
|
898
|
+
),
|
|
899
|
+
children: [
|
|
900
|
+
/* @__PURE__ */ jsx(
|
|
901
|
+
"input",
|
|
902
|
+
{
|
|
903
|
+
type: "checkbox",
|
|
904
|
+
className: "h-4 w-4 rounded border-border",
|
|
905
|
+
checked: visible,
|
|
906
|
+
disabled,
|
|
907
|
+
onChange: () => onToggle(column)
|
|
908
|
+
}
|
|
909
|
+
),
|
|
910
|
+
/* @__PURE__ */ jsx("span", { className: "truncate", children: labelText(column) })
|
|
911
|
+
]
|
|
912
|
+
},
|
|
913
|
+
column.key
|
|
914
|
+
);
|
|
915
|
+
}) })
|
|
916
|
+
] }),
|
|
917
|
+
showDensityControl && /* @__PURE__ */ jsx(
|
|
918
|
+
DensityMenuSection,
|
|
919
|
+
{
|
|
920
|
+
densityOverride,
|
|
921
|
+
separated: showColumnVisibilityControl,
|
|
922
|
+
onDensityChange
|
|
923
|
+
}
|
|
924
|
+
)
|
|
925
|
+
]
|
|
926
|
+
}
|
|
927
|
+
);
|
|
928
|
+
}
|
|
929
|
+
function DensityMenuSection({
|
|
930
|
+
densityOverride,
|
|
931
|
+
separated,
|
|
932
|
+
onDensityChange
|
|
933
|
+
}) {
|
|
934
|
+
const current = densityOverride ?? "inherit";
|
|
935
|
+
return /* @__PURE__ */ jsxs("div", { className: cn(separated && "mt-1 border-t border-border pt-1"), children: [
|
|
936
|
+
/* @__PURE__ */ jsx("div", { className: "px-2 py-1.5 text-xs font-medium text-muted-foreground", children: "Density" }),
|
|
937
|
+
/* @__PURE__ */ jsxs(
|
|
938
|
+
"button",
|
|
939
|
+
{
|
|
940
|
+
type: "button",
|
|
941
|
+
role: "menuitemradio",
|
|
942
|
+
"aria-checked": current === "inherit",
|
|
943
|
+
className: densityMenuItemClassName(current === "inherit"),
|
|
944
|
+
onClick: () => onDensityChange(void 0),
|
|
945
|
+
children: [
|
|
946
|
+
/* @__PURE__ */ jsx(Icon, { name: "ph:arrows-in-line-vertical", className: "text-sm text-muted-foreground" }),
|
|
947
|
+
/* @__PURE__ */ jsx("span", { className: "min-w-0 flex-1 truncate", children: "Use page density" }),
|
|
948
|
+
current === "inherit" ? /* @__PURE__ */ jsx(Icon, { name: "ph:check", className: "text-sm text-foreground" }) : /* @__PURE__ */ jsx("span", { className: "inline-block h-4 w-4", "aria-hidden": true })
|
|
949
|
+
]
|
|
950
|
+
}
|
|
951
|
+
),
|
|
952
|
+
DENSITY_OPTIONS.map((option) => {
|
|
953
|
+
const active = current === option.value;
|
|
954
|
+
return /* @__PURE__ */ jsxs(
|
|
955
|
+
"button",
|
|
956
|
+
{
|
|
957
|
+
type: "button",
|
|
958
|
+
role: "menuitemradio",
|
|
959
|
+
"aria-checked": active,
|
|
960
|
+
className: densityMenuItemClassName(active),
|
|
961
|
+
onClick: () => onDensityChange(option.value),
|
|
962
|
+
children: [
|
|
963
|
+
/* @__PURE__ */ jsx(Icon, { name: option.icon, className: "text-sm text-muted-foreground" }),
|
|
964
|
+
/* @__PURE__ */ jsx("span", { className: "min-w-0 flex-1 truncate", children: option.label }),
|
|
965
|
+
active ? /* @__PURE__ */ jsx(Icon, { name: "ph:check", className: "text-sm text-foreground" }) : /* @__PURE__ */ jsx("span", { className: "inline-block h-4 w-4", "aria-hidden": true })
|
|
966
|
+
]
|
|
967
|
+
},
|
|
968
|
+
option.value
|
|
969
|
+
);
|
|
970
|
+
})
|
|
971
|
+
] });
|
|
972
|
+
}
|
|
973
|
+
function densityMenuItemClassName(active) {
|
|
974
|
+
return cn(
|
|
975
|
+
"flex w-full items-center gap-2 rounded-md px-2 py-1.5 text-left text-sm transition-colors hover:bg-accent hover:text-accent-foreground focus:bg-accent focus:outline-none",
|
|
976
|
+
active && "text-foreground"
|
|
977
|
+
);
|
|
978
|
+
}
|
|
979
|
+
function CellContent({
|
|
980
|
+
column,
|
|
981
|
+
width,
|
|
982
|
+
children
|
|
983
|
+
}) {
|
|
984
|
+
return /* @__PURE__ */ jsx(
|
|
985
|
+
"div",
|
|
986
|
+
{
|
|
987
|
+
className: cn(cellContentClassName(column, width), alignmentClass(column.align)),
|
|
988
|
+
style: cellContentStyle(width),
|
|
989
|
+
children
|
|
990
|
+
}
|
|
991
|
+
);
|
|
992
|
+
}
|
|
993
|
+
function getSortValue(row, column) {
|
|
994
|
+
const rawValue = resolvePath(row, column.key);
|
|
995
|
+
return column.sortValue ? column.sortValue(rawValue, row) : rawValue;
|
|
996
|
+
}
|
|
997
|
+
function getFilterCandidate(row, column) {
|
|
998
|
+
const rawValue = resolvePath(row, column.key);
|
|
999
|
+
return column.filterValue ? column.filterValue(rawValue, row) : rawValue;
|
|
1000
|
+
}
|
|
1001
|
+
function getFilterTokens(row, column) {
|
|
1002
|
+
return normalizeTokens(getFilterCandidate(row, column));
|
|
1003
|
+
}
|
|
1004
|
+
function getFilterNumbers(row, column) {
|
|
1005
|
+
return normalizeNumbers(getFilterCandidate(row, column));
|
|
1006
|
+
}
|
|
1007
|
+
function normalizeTokens(value) {
|
|
1008
|
+
if (Array.isArray(value)) {
|
|
1009
|
+
return value.flatMap((item) => normalizeTokens(item)).filter(Boolean);
|
|
1010
|
+
}
|
|
1011
|
+
if (value == null) return [];
|
|
1012
|
+
if (typeof value === "object") return [JSON.stringify(value)];
|
|
1013
|
+
const token = String(value).trim();
|
|
1014
|
+
return token ? [token] : [];
|
|
1015
|
+
}
|
|
1016
|
+
function normalizeNumbers(value) {
|
|
1017
|
+
if (Array.isArray(value)) {
|
|
1018
|
+
return value.flatMap((item) => normalizeNumbers(item));
|
|
1019
|
+
}
|
|
1020
|
+
const parsed = parseNumberInput(value);
|
|
1021
|
+
return parsed == null ? [] : [parsed];
|
|
1022
|
+
}
|
|
1023
|
+
function updateFilterValue(state, key, nextValue) {
|
|
1024
|
+
const next = { ...state };
|
|
1025
|
+
if (nextValue.trim()) {
|
|
1026
|
+
next[key] = nextValue;
|
|
1027
|
+
} else {
|
|
1028
|
+
delete next[key];
|
|
1029
|
+
}
|
|
1030
|
+
return next;
|
|
1031
|
+
}
|
|
1032
|
+
function updateFilterRecord(state, key, nextValue) {
|
|
1033
|
+
const next = { ...state };
|
|
1034
|
+
if (Object.keys(nextValue).length > 0) {
|
|
1035
|
+
next[key] = nextValue;
|
|
1036
|
+
} else {
|
|
1037
|
+
delete next[key];
|
|
1038
|
+
}
|
|
1039
|
+
return next;
|
|
1040
|
+
}
|
|
1041
|
+
function updateNumberFilterValue(state, key, nextValue) {
|
|
1042
|
+
const next = { ...state };
|
|
1043
|
+
const hasMin = String(nextValue.min ?? "").trim() !== "";
|
|
1044
|
+
const hasMax = String(nextValue.max ?? "").trim() !== "";
|
|
1045
|
+
if (hasMin || hasMax) {
|
|
1046
|
+
next[key] = nextValue;
|
|
1047
|
+
} else {
|
|
1048
|
+
delete next[key];
|
|
1049
|
+
}
|
|
1050
|
+
return next;
|
|
1051
|
+
}
|
|
1052
|
+
function pruneTextFilterState(state, filters) {
|
|
1053
|
+
return pruneFilterState(state, filters, "text", (value) => !String(value ?? "").trim());
|
|
1054
|
+
}
|
|
1055
|
+
function pruneMultiFilterState(state, filters) {
|
|
1056
|
+
const allowed = new Set(
|
|
1057
|
+
filters.filter((filter) => filter.kind === "multi" || filter.kind === "nested-multi").map((filter) => filter.column.key)
|
|
1058
|
+
);
|
|
1059
|
+
return Object.fromEntries(
|
|
1060
|
+
Object.entries(state).filter(
|
|
1061
|
+
([key, value]) => allowed.has(key) && Object.keys(value).length > 0
|
|
1062
|
+
)
|
|
1063
|
+
);
|
|
1064
|
+
}
|
|
1065
|
+
function pruneNumberFilterState(state, filters) {
|
|
1066
|
+
return pruneFilterState(
|
|
1067
|
+
state,
|
|
1068
|
+
filters,
|
|
1069
|
+
"number",
|
|
1070
|
+
(value) => !String(value.min ?? "").trim() && !String(value.max ?? "").trim()
|
|
1071
|
+
);
|
|
1072
|
+
}
|
|
1073
|
+
function pruneFilterState(state, filters, kind, isEmpty) {
|
|
1074
|
+
const allowed = new Set(
|
|
1075
|
+
filters.filter((filter) => filter.kind === kind).map((filter) => filter.column.key)
|
|
1076
|
+
);
|
|
1077
|
+
return Object.fromEntries(
|
|
1078
|
+
Object.entries(state).filter(([key, value]) => allowed.has(key) && !isEmpty(value))
|
|
1079
|
+
);
|
|
1080
|
+
}
|
|
1081
|
+
function resolvePath(obj, path) {
|
|
1082
|
+
return path.split(".").reduce((current, key) => {
|
|
1083
|
+
if (current && typeof current === "object") {
|
|
1084
|
+
return current[key];
|
|
1085
|
+
}
|
|
1086
|
+
return void 0;
|
|
1087
|
+
}, obj);
|
|
1088
|
+
}
|
|
1089
|
+
function formatCell(value) {
|
|
1090
|
+
if (value == null || value === "") {
|
|
1091
|
+
return /* @__PURE__ */ jsx("span", { className: "text-muted-foreground", children: "—" });
|
|
1092
|
+
}
|
|
1093
|
+
if (typeof value === "boolean") return value ? "True" : "False";
|
|
1094
|
+
if (typeof value === "object") return JSON.stringify(value);
|
|
1095
|
+
return String(value);
|
|
1096
|
+
}
|
|
1097
|
+
function groupTagOptions(options, separator) {
|
|
1098
|
+
const byKey = /* @__PURE__ */ new Map();
|
|
1099
|
+
for (const option of options) {
|
|
1100
|
+
const { key } = splitTagToken(option.value, separator);
|
|
1101
|
+
const list = byKey.get(key) ?? [];
|
|
1102
|
+
list.push(option);
|
|
1103
|
+
byKey.set(key, list);
|
|
1104
|
+
}
|
|
1105
|
+
return Array.from(byKey.entries()).sort(([a], [b]) => {
|
|
1106
|
+
if (a === "" && b !== "") return 1;
|
|
1107
|
+
if (b === "" && a !== "") return -1;
|
|
1108
|
+
return a.localeCompare(b);
|
|
1109
|
+
}).map(([groupKey, groupOptions]) => ({
|
|
1110
|
+
groupKey,
|
|
1111
|
+
label: groupKey === "" ? "Other" : groupKey,
|
|
1112
|
+
options: groupOptions
|
|
1113
|
+
}));
|
|
1114
|
+
}
|
|
1115
|
+
function applyKindDefaults(column, timestampFormat) {
|
|
1116
|
+
if (!column.kind) return column;
|
|
1117
|
+
if (column.kind === "timestamp") {
|
|
1118
|
+
const format = timestampFormat ?? "iso";
|
|
1119
|
+
return {
|
|
1120
|
+
...column,
|
|
1121
|
+
render: column.render ?? ((value) => {
|
|
1122
|
+
var _a;
|
|
1123
|
+
return /* @__PURE__ */ jsx(
|
|
1124
|
+
Timestamp,
|
|
1125
|
+
{
|
|
1126
|
+
value,
|
|
1127
|
+
format,
|
|
1128
|
+
showTitleOnHover: ((_a = column.timestamp) == null ? void 0 : _a.alwaysShowFullOnHover) !== false
|
|
1129
|
+
}
|
|
1130
|
+
);
|
|
1131
|
+
}),
|
|
1132
|
+
sortValue: column.sortValue ?? ((value) => {
|
|
1133
|
+
var _a;
|
|
1134
|
+
return ((_a = parseTimestamp(value)) == null ? void 0 : _a.getTime()) ?? null;
|
|
1135
|
+
}),
|
|
1136
|
+
filterValue: column.filterValue ?? ((value) => {
|
|
1137
|
+
const parsed = parseTimestamp(value);
|
|
1138
|
+
return parsed ? parsed.toISOString() : "";
|
|
1139
|
+
})
|
|
1140
|
+
};
|
|
1141
|
+
}
|
|
1142
|
+
if (column.kind === "tags") {
|
|
1143
|
+
const opts = column.tags;
|
|
1144
|
+
const separator = (opts == null ? void 0 : opts.separator) ?? "=";
|
|
1145
|
+
return {
|
|
1146
|
+
...column,
|
|
1147
|
+
render: column.render ?? ((value) => /* @__PURE__ */ jsx(
|
|
1148
|
+
TagList,
|
|
1149
|
+
{
|
|
1150
|
+
tags: normalizeTags(value, separator),
|
|
1151
|
+
maxVisible: (opts == null ? void 0 : opts.maxVisible) ?? 3
|
|
1152
|
+
}
|
|
1153
|
+
)),
|
|
1154
|
+
filterValue: column.filterValue ?? ((value) => tagFilterTokens(value, separator)),
|
|
1155
|
+
sortValue: column.sortValue ?? ((value) => tagFilterTokens(value, separator).length)
|
|
1156
|
+
};
|
|
1157
|
+
}
|
|
1158
|
+
if (column.kind === "status") {
|
|
1159
|
+
const opts = column.status;
|
|
1160
|
+
const map = (opts == null ? void 0 : opts.map) ?? ((raw) => normalizeStatus(raw));
|
|
1161
|
+
return {
|
|
1162
|
+
...column,
|
|
1163
|
+
render: column.render ?? ((value, row) => {
|
|
1164
|
+
var _a;
|
|
1165
|
+
const status = map(value, row);
|
|
1166
|
+
if (!status) return /* @__PURE__ */ jsx("span", { className: "text-muted-foreground", children: "—" });
|
|
1167
|
+
const label = (opts == null ? void 0 : opts.showLabel) ? typeof value === "string" ? value : status : void 0;
|
|
1168
|
+
const title = ((_a = opts == null ? void 0 : opts.title) == null ? void 0 : _a.call(opts, value, row)) ?? (typeof value === "string" ? value : void 0);
|
|
1169
|
+
return /* @__PURE__ */ jsx(
|
|
1170
|
+
StatusDot,
|
|
1171
|
+
{
|
|
1172
|
+
status,
|
|
1173
|
+
...label ? { label } : {},
|
|
1174
|
+
...title ? { title } : {}
|
|
1175
|
+
}
|
|
1176
|
+
);
|
|
1177
|
+
}),
|
|
1178
|
+
filterValue: column.filterValue ?? ((value, row) => {
|
|
1179
|
+
const status = map(value, row);
|
|
1180
|
+
return status ?? "";
|
|
1181
|
+
}),
|
|
1182
|
+
sortValue: column.sortValue ?? ((value, row) => map(value, row) ?? "")
|
|
1183
|
+
};
|
|
1184
|
+
}
|
|
1185
|
+
return column;
|
|
1186
|
+
}
|
|
1187
|
+
function prettifyKey(key) {
|
|
1188
|
+
return key.replace(/([a-z])([A-Z])/g, "$1 $2").replace(/[_-]/g, " ").replace(/\b\w/g, (value) => value.toUpperCase()).trim();
|
|
1189
|
+
}
|
|
1190
|
+
function labelText(column) {
|
|
1191
|
+
if (typeof column.label === "string") return column.label;
|
|
1192
|
+
return prettifyKey(column.key.split(".").at(-1) ?? column.key);
|
|
1193
|
+
}
|
|
1194
|
+
function isColumnHideable(column) {
|
|
1195
|
+
return column.hideable !== false;
|
|
1196
|
+
}
|
|
1197
|
+
function isFilterBarFilterActive(filter) {
|
|
1198
|
+
if (filter.kind === "text" || filter.kind === "lookup" || filter.kind === "enum") {
|
|
1199
|
+
return String(filter.value ?? "").trim() !== "";
|
|
1200
|
+
}
|
|
1201
|
+
if (filter.kind === "lookup-multi" || filter.kind === "select-multi") {
|
|
1202
|
+
return filter.value.length > 0;
|
|
1203
|
+
}
|
|
1204
|
+
if (filter.kind === "number") {
|
|
1205
|
+
return String(filter.value.min ?? "").trim() !== "" || String(filter.value.max ?? "").trim() !== "";
|
|
1206
|
+
}
|
|
1207
|
+
if (filter.kind === "boolean") return filter.value;
|
|
1208
|
+
return Object.keys(filter.value).length > 0;
|
|
1209
|
+
}
|
|
1210
|
+
function menuStateFromPointer(event, columnKey) {
|
|
1211
|
+
const padding = 8;
|
|
1212
|
+
const width = 256;
|
|
1213
|
+
const height = 320;
|
|
1214
|
+
const viewportWidth = typeof window === "undefined" ? event.clientX + width : window.innerWidth;
|
|
1215
|
+
const viewportHeight = typeof window === "undefined" ? event.clientY + height : window.innerHeight;
|
|
1216
|
+
const position = {
|
|
1217
|
+
x: Math.max(padding, Math.min(event.clientX, viewportWidth - width - padding)),
|
|
1218
|
+
y: Math.max(padding, Math.min(event.clientY, viewportHeight - height - padding))
|
|
1219
|
+
};
|
|
1220
|
+
return columnKey ? { ...position, columnKey } : position;
|
|
1221
|
+
}
|
|
1222
|
+
function menuStateFromTrigger(event, columnKey) {
|
|
1223
|
+
const rect = event.currentTarget.getBoundingClientRect();
|
|
1224
|
+
const padding = 8;
|
|
1225
|
+
const width = 256;
|
|
1226
|
+
const height = 320;
|
|
1227
|
+
const viewportWidth = typeof window === "undefined" ? rect.right + width : window.innerWidth;
|
|
1228
|
+
const viewportHeight = typeof window === "undefined" ? rect.bottom + height : window.innerHeight;
|
|
1229
|
+
const position = {
|
|
1230
|
+
x: Math.max(padding, Math.min(rect.right - width, viewportWidth - width - padding)),
|
|
1231
|
+
y: Math.max(padding, Math.min(rect.bottom + 6, viewportHeight - height - padding))
|
|
1232
|
+
};
|
|
1233
|
+
return columnKey ? { ...position, columnKey } : position;
|
|
1234
|
+
}
|
|
1235
|
+
function columnStyle(column, widths) {
|
|
1236
|
+
const width = widths[column.key];
|
|
1237
|
+
return width ? { width: `${width}px` } : void 0;
|
|
1238
|
+
}
|
|
1239
|
+
function measureColumnContentWidth(table, columnIndex, column) {
|
|
1240
|
+
const cells = Array.from(table.querySelectorAll("th, td")).filter(
|
|
1241
|
+
(cell) => cell instanceof HTMLTableCellElement && cell.cellIndex === columnIndex && cell.colSpan === 1
|
|
1242
|
+
);
|
|
1243
|
+
const measured = cells.reduce((current, cell) => {
|
|
1244
|
+
const horizontalPadding = getHorizontalPadding(cell);
|
|
1245
|
+
const contentWidths = Array.from(cell.children).map(
|
|
1246
|
+
(child) => child instanceof HTMLElement ? child.scrollWidth + horizontalPadding : 0
|
|
1247
|
+
);
|
|
1248
|
+
return Math.max(current, cell.scrollWidth, ...contentWidths);
|
|
1249
|
+
}, 0);
|
|
1250
|
+
return clampColumnWidth(column, measured || defaultColumnWidth(column));
|
|
1251
|
+
}
|
|
1252
|
+
function getHorizontalPadding(element) {
|
|
1253
|
+
if (typeof window === "undefined") return 0;
|
|
1254
|
+
const styles = window.getComputedStyle(element);
|
|
1255
|
+
return parseCssPixelValue(styles.paddingLeft) + parseCssPixelValue(styles.paddingRight);
|
|
1256
|
+
}
|
|
1257
|
+
function parseCssPixelValue(value) {
|
|
1258
|
+
const parsed = Number.parseFloat(value);
|
|
1259
|
+
return Number.isFinite(parsed) ? parsed : 0;
|
|
1260
|
+
}
|
|
1261
|
+
function readStoredColumnWidths(storageKey, columns) {
|
|
1262
|
+
if (typeof window === "undefined") return {};
|
|
1263
|
+
try {
|
|
1264
|
+
const raw = window.localStorage.getItem(storageKey);
|
|
1265
|
+
if (!raw) return {};
|
|
1266
|
+
const parsed = JSON.parse(raw);
|
|
1267
|
+
if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) return {};
|
|
1268
|
+
return pruneColumnWidths(parsed, columns);
|
|
1269
|
+
} catch {
|
|
1270
|
+
return {};
|
|
1271
|
+
}
|
|
1272
|
+
}
|
|
1273
|
+
function writeStoredColumnWidths(storageKey, widths) {
|
|
1274
|
+
if (typeof window === "undefined") return;
|
|
1275
|
+
try {
|
|
1276
|
+
if (Object.keys(widths).length === 0) {
|
|
1277
|
+
window.localStorage.removeItem(storageKey);
|
|
1278
|
+
} else {
|
|
1279
|
+
window.localStorage.setItem(storageKey, JSON.stringify(widths));
|
|
1280
|
+
}
|
|
1281
|
+
} catch {
|
|
1282
|
+
}
|
|
1283
|
+
}
|
|
1284
|
+
function readStoredHiddenColumns(storageKey, columns) {
|
|
1285
|
+
if (typeof window === "undefined") return {};
|
|
1286
|
+
try {
|
|
1287
|
+
const raw = window.localStorage.getItem(storageKey);
|
|
1288
|
+
if (!raw) return {};
|
|
1289
|
+
const parsed = JSON.parse(raw);
|
|
1290
|
+
if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) return {};
|
|
1291
|
+
return pruneHiddenColumns(parsed, columns);
|
|
1292
|
+
} catch {
|
|
1293
|
+
return {};
|
|
1294
|
+
}
|
|
1295
|
+
}
|
|
1296
|
+
function writeStoredHiddenColumns(storageKey, hiddenColumns) {
|
|
1297
|
+
if (typeof window === "undefined") return;
|
|
1298
|
+
try {
|
|
1299
|
+
if (Object.keys(hiddenColumns).length === 0) {
|
|
1300
|
+
window.localStorage.removeItem(storageKey);
|
|
1301
|
+
} else {
|
|
1302
|
+
window.localStorage.setItem(storageKey, JSON.stringify(hiddenColumns));
|
|
1303
|
+
}
|
|
1304
|
+
} catch {
|
|
1305
|
+
}
|
|
1306
|
+
}
|
|
1307
|
+
function readStoredDensityOverride(storageKey) {
|
|
1308
|
+
if (typeof window === "undefined") return void 0;
|
|
1309
|
+
try {
|
|
1310
|
+
const raw = window.localStorage.getItem(storageKey);
|
|
1311
|
+
return isDensity(raw) ? raw : void 0;
|
|
1312
|
+
} catch {
|
|
1313
|
+
return void 0;
|
|
1314
|
+
}
|
|
1315
|
+
}
|
|
1316
|
+
function writeStoredDensityOverride(storageKey, density) {
|
|
1317
|
+
if (typeof window === "undefined") return;
|
|
1318
|
+
try {
|
|
1319
|
+
if (density) {
|
|
1320
|
+
window.localStorage.setItem(storageKey, density);
|
|
1321
|
+
} else {
|
|
1322
|
+
window.localStorage.removeItem(storageKey);
|
|
1323
|
+
}
|
|
1324
|
+
} catch {
|
|
1325
|
+
}
|
|
1326
|
+
}
|
|
1327
|
+
function isDensity(value) {
|
|
1328
|
+
return value === "compact" || value === "comfortable" || value === "spacious";
|
|
1329
|
+
}
|
|
1330
|
+
function pruneColumnWidths(widths, columns) {
|
|
1331
|
+
const byKey = new Map(columns.map((column) => [column.key, column]));
|
|
1332
|
+
const next = {};
|
|
1333
|
+
for (const [key, width] of Object.entries(widths)) {
|
|
1334
|
+
const column = byKey.get(key);
|
|
1335
|
+
if (!column || typeof width !== "number" || !Number.isFinite(width)) continue;
|
|
1336
|
+
next[key] = clampColumnWidth(column, width);
|
|
1337
|
+
}
|
|
1338
|
+
return next;
|
|
1339
|
+
}
|
|
1340
|
+
function pruneHiddenColumns(hiddenColumns, columns) {
|
|
1341
|
+
const byKey = new Map(columns.map((column) => [column.key, column]));
|
|
1342
|
+
const next = {};
|
|
1343
|
+
for (const [key, hidden] of Object.entries(hiddenColumns)) {
|
|
1344
|
+
const column = byKey.get(key);
|
|
1345
|
+
if (!column || hidden !== true || !isColumnHideable(column)) continue;
|
|
1346
|
+
next[key] = true;
|
|
1347
|
+
}
|
|
1348
|
+
const hideable = columns.filter(isColumnHideable);
|
|
1349
|
+
const visibleHideableCount = hideable.filter((column) => next[column.key] !== true).length;
|
|
1350
|
+
if (hideable.length > 0 && visibleHideableCount === 0) {
|
|
1351
|
+
delete next[hideable[0].key];
|
|
1352
|
+
}
|
|
1353
|
+
return next;
|
|
1354
|
+
}
|
|
1355
|
+
function sameColumnWidths(left, right) {
|
|
1356
|
+
const leftKeys = Object.keys(left);
|
|
1357
|
+
const rightKeys = Object.keys(right);
|
|
1358
|
+
return leftKeys.length === rightKeys.length && leftKeys.every(
|
|
1359
|
+
(key) => Object.prototype.hasOwnProperty.call(right, key) && left[key] === right[key]
|
|
1360
|
+
);
|
|
1361
|
+
}
|
|
1362
|
+
function sameHiddenColumns(left, right) {
|
|
1363
|
+
const leftKeys = Object.keys(left);
|
|
1364
|
+
const rightKeys = Object.keys(right);
|
|
1365
|
+
return leftKeys.length === rightKeys.length && leftKeys.every(
|
|
1366
|
+
(key) => Object.prototype.hasOwnProperty.call(right, key) && left[key] === right[key]
|
|
1367
|
+
);
|
|
1368
|
+
}
|
|
1369
|
+
function defaultColumnWidth(column) {
|
|
1370
|
+
if (column.grow) return DEFAULT_GROW_COLUMN_WIDTH;
|
|
1371
|
+
if (column.shrink) return DEFAULT_SHRINK_COLUMN_WIDTH;
|
|
1372
|
+
return DEFAULT_COLUMN_WIDTH;
|
|
1373
|
+
}
|
|
1374
|
+
function clampColumnWidth(column, width) {
|
|
1375
|
+
const minWidth = column.minWidth ?? DEFAULT_COLUMN_MIN_WIDTH;
|
|
1376
|
+
const maxWidth = column.maxWidth;
|
|
1377
|
+
const minimum = Number.isFinite(minWidth) ? Math.max(1, minWidth) : DEFAULT_COLUMN_MIN_WIDTH;
|
|
1378
|
+
const maximum = maxWidth != null && Number.isFinite(maxWidth) ? Math.max(minimum, maxWidth) : Infinity;
|
|
1379
|
+
return Math.round(Math.max(minimum, Math.min(maximum, width)));
|
|
1380
|
+
}
|
|
1381
|
+
function getNumericFilterBounds(rows, column) {
|
|
1382
|
+
const values = rows.flatMap(
|
|
1383
|
+
(record) => collectFilterValues(getFilterCandidate(record.row, column))
|
|
1384
|
+
);
|
|
1385
|
+
const populated = values.filter(hasFilterValue);
|
|
1386
|
+
const numericValues = populated.map((value) => parseNumberInput(value)).filter((value) => value != null);
|
|
1387
|
+
if (populated.length === 0 || numericValues.length !== populated.length) {
|
|
1388
|
+
return null;
|
|
1389
|
+
}
|
|
1390
|
+
return {
|
|
1391
|
+
min: Math.min(...numericValues),
|
|
1392
|
+
max: Math.max(...numericValues),
|
|
1393
|
+
step: inferNumericStep(numericValues)
|
|
1394
|
+
};
|
|
1395
|
+
}
|
|
1396
|
+
function collectFilterValues(value) {
|
|
1397
|
+
if (Array.isArray(value)) {
|
|
1398
|
+
return value.flatMap((item) => collectFilterValues(item));
|
|
1399
|
+
}
|
|
1400
|
+
return [value];
|
|
1401
|
+
}
|
|
1402
|
+
function hasFilterValue(value) {
|
|
1403
|
+
return value != null && !(typeof value === "string" && value.trim() === "");
|
|
1404
|
+
}
|
|
1405
|
+
function parseNumberInput(value) {
|
|
1406
|
+
if (typeof value === "number") {
|
|
1407
|
+
return Number.isFinite(value) ? value : null;
|
|
1408
|
+
}
|
|
1409
|
+
if (typeof value !== "string") {
|
|
1410
|
+
return null;
|
|
1411
|
+
}
|
|
1412
|
+
const trimmed = value.trim();
|
|
1413
|
+
if (!trimmed) return null;
|
|
1414
|
+
const parsed = Number(trimmed);
|
|
1415
|
+
return Number.isFinite(parsed) ? parsed : null;
|
|
1416
|
+
}
|
|
1417
|
+
function inferNumericStep(values) {
|
|
1418
|
+
if (values.every(Number.isInteger)) {
|
|
1419
|
+
return 1;
|
|
1420
|
+
}
|
|
1421
|
+
const maxFractionDigits = values.reduce((current, value) => {
|
|
1422
|
+
const [, fraction = ""] = String(value).split(".");
|
|
1423
|
+
return Math.max(current, fraction.length);
|
|
1424
|
+
}, 0);
|
|
1425
|
+
return 10 ** -Math.min(maxFractionDigits || 2, 6);
|
|
1426
|
+
}
|
|
1427
|
+
function alignmentClass(align) {
|
|
1428
|
+
if (align === "right") return "text-right";
|
|
1429
|
+
if (align === "center") return "text-center";
|
|
1430
|
+
return "text-left";
|
|
1431
|
+
}
|
|
1432
|
+
function headerAlignmentClass(align) {
|
|
1433
|
+
if (align === "right") return "justify-end";
|
|
1434
|
+
if (align === "center") return "justify-center";
|
|
1435
|
+
return "justify-start";
|
|
1436
|
+
}
|
|
1437
|
+
function cellContentStyle(width) {
|
|
1438
|
+
return width ? { maxWidth: `${width}px` } : void 0;
|
|
1439
|
+
}
|
|
1440
|
+
function cellContentClassName(column, width) {
|
|
1441
|
+
const resized = width !== void 0;
|
|
1442
|
+
const base = "w-full truncate";
|
|
1443
|
+
if (column.grow) return cn(base, resized ? "min-w-0" : "min-w-56 max-w-[36rem]");
|
|
1444
|
+
if (column.shrink) return cn(base, "min-w-0 whitespace-nowrap", !resized && "max-w-[16rem]");
|
|
1445
|
+
return cn(base, "min-w-0", !resized && "max-w-[18rem]");
|
|
1446
|
+
}
|
|
1447
|
+
function inferColumns(data) {
|
|
1448
|
+
if (data.length === 0) return [];
|
|
1449
|
+
const keys = /* @__PURE__ */ new Set();
|
|
1450
|
+
for (const row of data.slice(0, 20)) {
|
|
1451
|
+
Object.keys(row).filter((key) => !key.startsWith("_")).forEach((key) => keys.add(key));
|
|
1452
|
+
}
|
|
1453
|
+
return Array.from(keys).map((key) => ({
|
|
1454
|
+
key,
|
|
1455
|
+
label: prettifyKey(key),
|
|
1456
|
+
sortable: true,
|
|
1457
|
+
filterable: true
|
|
1458
|
+
}));
|
|
1459
|
+
}
|
|
1460
|
+
export {
|
|
1461
|
+
DataTable,
|
|
1462
|
+
inferColumns
|
|
1463
|
+
};
|
|
1464
|
+
//# sourceMappingURL=DataTable.js.map
|