torch-glare 2.3.0 → 2.4.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 +8 -0
- package/apps/lib/components/ActionButton.tsx +7 -12
- package/apps/lib/components/ActionsGroup.tsx +4 -15
- package/apps/lib/components/AlertDialog.tsx +173 -191
- package/apps/lib/components/Avatar.tsx +13 -16
- package/apps/lib/components/Badge.tsx +7 -3
- package/apps/lib/components/BadgeField.tsx +76 -71
- package/apps/lib/components/Breadcrumb.tsx +49 -85
- package/apps/lib/components/Button.tsx +20 -19
- package/apps/lib/components/ButtonGroup.tsx +31 -41
- package/apps/lib/components/Calendar.tsx +51 -29
- package/apps/lib/components/Card.tsx +2 -13
- package/apps/lib/components/ChartBlockTool.ts +17 -52
- package/apps/lib/components/Checkbox.tsx +9 -16
- package/apps/lib/components/ContextMenu.tsx +110 -106
- package/apps/lib/components/CountBadge.tsx +4 -6
- package/apps/lib/components/DataTable.tsx +196 -216
- package/apps/lib/components/DataViews/DataViewRadio.tsx +10 -8
- package/apps/lib/components/DataViews/DataViewsConfigPanel.tsx +21 -55
- package/apps/lib/components/DataViews/DataViewsHeader.tsx +1 -3
- package/apps/lib/components/DataViews/DataViewsLayout.tsx +5 -12
- package/apps/lib/components/DataViews/FilterPanel.tsx +173 -150
- package/apps/lib/components/DataViews/HeaderSearch.tsx +1 -5
- package/apps/lib/components/DataViews/InboxView.tsx +22 -68
- package/apps/lib/components/DataViews/InboxViewCard.tsx +68 -77
- package/apps/lib/components/DataViews/KanbanView.tsx +8 -25
- package/apps/lib/components/DataViews/PanelControls.tsx +3 -13
- package/apps/lib/components/DataViews/SettingsPanel.tsx +83 -89
- package/apps/lib/components/DataViews/TableView.tsx +8 -28
- package/apps/lib/components/DataViews/TreeView.tsx +12 -40
- package/apps/lib/components/DataViews/badgeAdapter.ts +32 -28
- package/apps/lib/components/DataViews/fieldRenderers.tsx +106 -141
- package/apps/lib/components/DataViews/filters/DatePickerRangeFilter.tsx +87 -0
- package/apps/lib/components/DataViews/filters/DateRangePopover.tsx +39 -32
- package/apps/lib/components/DataViews/filters/PresetChips.tsx +15 -15
- package/apps/lib/components/DataViews/filters/RangeSliderWithInputs.tsx +69 -58
- package/apps/lib/components/DataViews/index.ts +26 -26
- package/apps/lib/components/DataViews/tree/TreeDrawer.tsx +12 -16
- package/apps/lib/components/DataViews/tree/TreeSidebar.tsx +28 -31
- package/apps/lib/components/DataViews/types.ts +111 -114
- package/apps/lib/components/DatePicker.tsx +198 -191
- package/apps/lib/components/Dialog.tsx +92 -105
- package/apps/lib/components/Divider.tsx +21 -24
- package/apps/lib/components/Drawer.tsx +79 -139
- package/apps/lib/components/DropdownMenu.tsx +144 -181
- package/apps/lib/components/FieldHint.tsx +4 -11
- package/apps/lib/components/Form.tsx +146 -155
- package/apps/lib/components/FormStepper.tsx +9 -39
- package/apps/lib/components/HeaderBar.tsx +119 -0
- package/apps/lib/components/ImageAttachment.tsx +111 -73
- package/apps/lib/components/InnerLabelField.tsx +20 -16
- package/apps/lib/components/Input.tsx +171 -172
- package/apps/lib/components/InputField.tsx +44 -45
- package/apps/lib/components/InputOTP.tsx +68 -69
- package/apps/lib/components/Label.tsx +31 -35
- package/apps/lib/components/LabelField.tsx +4 -5
- package/apps/lib/components/LabeledCheckBox.tsx +8 -12
- package/apps/lib/components/LabeledRadio.tsx +7 -5
- package/apps/lib/components/LinkButton.tsx +2 -9
- package/apps/lib/components/LoginButton.tsx +4 -9
- package/apps/lib/components/PasswordLevel.tsx +5 -5
- package/apps/lib/components/Popover.tsx +15 -33
- package/apps/lib/components/ProfileMenu.tsx +67 -72
- package/apps/lib/components/Radio.tsx +1 -5
- package/apps/lib/components/RadioCard.tsx +9 -28
- package/apps/lib/components/ScrollArea.tsx +45 -43
- package/apps/lib/components/SearchField.tsx +49 -39
- package/apps/lib/components/SearchableSelect.tsx +46 -52
- package/apps/lib/components/SearchableTable.tsx +199 -219
- package/apps/lib/components/SearchableTree.tsx +469 -0
- package/apps/lib/components/SearchableTreeDialog.tsx +493 -0
- package/apps/lib/components/SectionBlock.tsx +4 -16
- package/apps/lib/components/Select.tsx +53 -80
- package/apps/lib/components/SimpleSelect.tsx +196 -187
- package/apps/lib/components/Skeleton.tsx +9 -12
- package/apps/lib/components/SlideDatePicker.tsx +215 -166
- package/apps/lib/components/SpinLoading.tsx +33 -49
- package/apps/lib/components/Stepper.tsx +13 -56
- package/apps/lib/components/Switch.tsx +8 -10
- package/apps/lib/components/TabFormItem.tsx +3 -12
- package/apps/lib/components/TabSwitch.tsx +7 -34
- package/apps/lib/components/Table.tsx +60 -75
- package/apps/lib/components/TableDnDWrapper.ts +15 -48
- package/apps/lib/components/TextEditor.tsx +93 -104
- package/apps/lib/components/Textarea.tsx +8 -12
- package/apps/lib/components/Timeline.tsx +21 -41
- package/apps/lib/components/Toast.tsx +83 -83
- package/apps/lib/components/Toggle.tsx +112 -114
- package/apps/lib/components/ToggleButton.tsx +1 -1
- package/apps/lib/components/Tooltip.tsx +24 -19
- package/apps/lib/components/TransparentLabel.tsx +61 -62
- package/apps/lib/components/TreeDropDown.tsx +86 -52
- package/apps/lib/components/TreeFolder/TreeFolder.tsx +15 -48
- package/apps/lib/components/TreeFolder/TreeFolderBreadcrumb.tsx +16 -21
- package/apps/lib/components/TreeFolder/TreeFolderRow.tsx +9 -20
- package/apps/lib/components/TreeFolder/TreeFolderStyles.tsx +3 -3
- package/apps/lib/components/TreeFolder/icons.tsx +14 -17
- package/apps/lib/components/TreeFolder/index.ts +15 -8
- package/apps/lib/components/TreeFolder/treeFolderUtils.ts +47 -52
- package/apps/lib/components/TreeFolder/types.ts +32 -32
- package/apps/lib/components/TreeFolder/useTreeFolderDnD.ts +117 -123
- package/apps/lib/hooks/useActiveTreeItem.ts +52 -55
- package/apps/lib/hooks/useClickOutside.ts +21 -20
- package/apps/lib/hooks/useDataViewsState.ts +86 -80
- package/apps/lib/hooks/useIsMobile.ts +12 -12
- package/apps/lib/hooks/useResize.ts +54 -65
- package/apps/lib/hooks/useTagSelection.ts +201 -201
- package/apps/lib/layouts/CNLayout.tsx +181 -140
- package/apps/lib/layouts/DataViewCard.tsx +4 -18
- package/apps/lib/layouts/FieldSection.tsx +2 -6
- package/apps/lib/layouts/TreeSubLayout.tsx +24 -38
- package/apps/lib/providers/ThemeProvider.tsx +8 -23
- package/apps/lib/registry.json +1004 -0
- package/apps/lib/tsconfig.json +9 -0
- package/apps/lib/utils/cn.ts +1 -1
- package/apps/lib/utils/dataViews/columnUtils.ts +46 -44
- package/apps/lib/utils/dataViews/fieldUtils.ts +70 -71
- package/apps/lib/utils/dataViews/nestedDataUtils.tsx +129 -122
- package/apps/lib/utils/dataViews/pathUtils.ts +74 -67
- package/apps/lib/utils/dataViews/rangeUtils.ts +121 -112
- package/apps/lib/utils/dataViews/treeUtils.ts +204 -211
- package/apps/lib/utils/dateFormat.ts +64 -54
- package/apps/lib/utils/markdownParser.ts +2 -7
- package/apps/lib/utils/resize.ts +21 -25
- package/apps/lib/utils/types.ts +13 -13
- package/dist/bin/index.js +8 -2
- package/dist/bin/index.js.map +1 -1
- package/dist/src/shared/getAvailableFiles.d.ts.map +1 -1
- package/dist/src/shared/getAvailableFiles.js +6 -1
- package/dist/src/shared/getAvailableFiles.js.map +1 -1
- package/dist/src/shared/loadRegistry.d.ts +7 -0
- package/dist/src/shared/loadRegistry.d.ts.map +1 -0
- package/dist/src/shared/loadRegistry.js +31 -0
- package/dist/src/shared/loadRegistry.js.map +1 -0
- package/dist/src/shared/resolveInstallPlan.d.ts +12 -0
- package/dist/src/shared/resolveInstallPlan.d.ts.map +1 -0
- package/dist/src/shared/resolveInstallPlan.js +39 -0
- package/dist/src/shared/resolveInstallPlan.js.map +1 -0
- package/dist/src/types/main.d.ts +24 -0
- package/dist/src/types/main.d.ts.map +1 -1
- package/docs/README.md +10 -2
- package/docs/components/action-button.md +30 -24
- package/docs/components/actions-group.md +26 -20
- package/docs/components/alert-dialog.md +45 -45
- package/docs/components/avatar.md +6 -2
- package/docs/components/badge-field.md +6 -2
- package/docs/components/badge.md +7 -1
- package/docs/components/breadcrumb.md +15 -40
- package/docs/components/button-group.md +13 -10
- package/docs/components/button.md +58 -33
- package/docs/components/calendar.md +26 -19
- package/docs/components/card.md +19 -16
- package/docs/components/chart-block-tool.md +128 -0
- package/docs/components/checkbox.md +16 -8
- package/docs/components/cn-layout.md +7 -1
- package/docs/components/context-menu.md +47 -24
- package/docs/components/count-badge.md +7 -1
- package/docs/components/data-table.md +45 -33
- package/docs/components/data-views-config-panel.md +18 -14
- package/docs/components/data-views-layout.md +20 -17
- package/docs/components/date-picker.md +30 -23
- package/docs/components/dialog.md +43 -42
- package/docs/components/divider.md +10 -4
- package/docs/components/drawer.md +8 -33
- package/docs/components/dropdown-menu.md +51 -32
- package/docs/components/field-hint.md +37 -25
- package/docs/components/field-section.md +9 -3
- package/docs/components/form-stepper.md +6 -0
- package/docs/components/form.md +17 -20
- package/docs/components/header-bar.md +187 -0
- package/docs/components/image-attachment.md +33 -41
- package/docs/components/inbox-view.md +16 -5
- package/docs/components/inner-label-field.md +34 -24
- package/docs/components/input-field.md +18 -10
- package/docs/components/input-otp.md +14 -11
- package/docs/components/input.md +22 -16
- package/docs/components/kanban-view.md +15 -5
- package/docs/components/label-field.md +32 -22
- package/docs/components/label.md +43 -32
- package/docs/components/labeled-check-box.md +16 -8
- package/docs/components/labeled-radio.md +18 -11
- package/docs/components/link-button.md +7 -1
- package/docs/components/login-button.md +8 -2
- package/docs/components/password-level.md +37 -24
- package/docs/components/popover.md +26 -23
- package/docs/components/profile-menu.md +38 -27
- package/docs/components/radio-card.md +16 -9
- package/docs/components/radio.md +16 -8
- package/docs/components/scroll-area.md +6 -2
- package/docs/components/search-field.md +14 -6
- package/docs/components/searchable-select.md +19 -14
- package/docs/components/searchable-table.md +60 -41
- package/docs/components/searchable-tree-dialog.md +190 -0
- package/docs/components/searchable-tree.md +200 -0
- package/docs/components/section-block.md +130 -4
- package/docs/components/select.md +23 -18
- package/docs/components/simple-select.md +14 -10
- package/docs/components/skeleton.md +43 -33
- package/docs/components/slide-date-picker.md +37 -29
- package/docs/components/spin-loading.md +32 -23
- package/docs/components/stepper.md +6 -0
- package/docs/components/switch.md +14 -6
- package/docs/components/tab-form-item.md +7 -1
- package/docs/components/tab-switch.md +13 -6
- package/docs/components/table-dnd-wrapper.md +105 -0
- package/docs/components/table-view.md +15 -5
- package/docs/components/table.md +28 -28
- package/docs/components/text-editor.md +19 -13
- package/docs/components/textarea.md +15 -7
- package/docs/components/timeline.md +6 -0
- package/docs/components/toast.md +35 -26
- package/docs/components/toggle-button.md +24 -21
- package/docs/components/toggle.md +23 -15
- package/docs/components/tooltip.md +42 -30
- package/docs/components/transparent-label.md +29 -20
- package/docs/components/tree-drop-down.md +31 -23
- package/docs/components/tree-sub-layout.md +6 -2
- package/docs/components/tree-view.md +16 -5
- package/docs/explanation/architecture.md +54 -0
- package/docs/explanation/design-system.md +52 -0
- package/docs/how-to/data-views-from-backend-response.md +7 -4
- package/docs/how-to/guides.md +24 -18
- package/docs/migration/changelog.md +38 -0
- package/docs/reference/cli.md +87 -0
- package/docs/reference/components.md +11 -12
- package/docs/reference/hooks.md +8 -8
- package/docs/reference/providers.md +22 -22
- package/docs/reference/tailwind-plugins.md +2 -2
- package/docs/reference/theme.md +85 -0
- package/docs/reference/types.md +4 -4
- package/docs/reference/utilities.md +19 -26
- package/docs/tutorials/building-first-form.md +20 -13
- package/docs/tutorials/component-composition.md +34 -50
- package/docs/tutorials/getting-started.md +2 -2
- package/docs/tutorials/theming-basics.md +13 -10
- package/package.json +31 -3
- package/dist/src/commands/block.d.ts +0 -5
- package/dist/src/commands/block.d.ts.map +0 -1
- package/dist/src/commands/block.js +0 -255
- package/dist/src/commands/block.js.map +0 -1
- package/dist/src/shared/configureFonts.d.ts +0 -6
- package/dist/src/shared/configureFonts.d.ts.map +0 -1
- package/dist/src/shared/configureFonts.js +0 -106
- package/dist/src/shared/configureFonts.js.map +0 -1
- package/dist/src/shared/configureGlobalCss.d.ts +0 -6
- package/dist/src/shared/configureGlobalCss.d.ts.map +0 -1
- package/dist/src/shared/configureGlobalCss.js +0 -154
- package/dist/src/shared/configureGlobalCss.js.map +0 -1
- package/dist/src/shared/configureTailwind.d.ts +0 -7
- package/dist/src/shared/configureTailwind.d.ts.map +0 -1
- package/dist/src/shared/configureTailwind.js +0 -163
- package/dist/src/shared/configureTailwind.js.map +0 -1
- package/dist/src/shared/detectFramework.d.ts +0 -23
- package/dist/src/shared/detectFramework.d.ts.map +0 -1
- package/dist/src/shared/detectFramework.js +0 -119
- package/dist/src/shared/detectFramework.js.map +0 -1
- package/dist/src/shared/installBaseUtils.d.ts +0 -5
- package/dist/src/shared/installBaseUtils.d.ts.map +0 -1
- package/dist/src/shared/installBaseUtils.js +0 -79
- package/dist/src/shared/installBaseUtils.js.map +0 -1
- package/dist/src/shared/resolveAliases.d.ts +0 -24
- package/dist/src/shared/resolveAliases.d.ts.map +0 -1
- package/dist/src/shared/resolveAliases.js +0 -98
- package/dist/src/shared/resolveAliases.js.map +0 -1
|
@@ -1,24 +1,26 @@
|
|
|
1
|
-
import type { ReactElement } from "react"
|
|
2
|
-
import { Badge } from "../../components/Badge"
|
|
3
|
-
import { Divider } from "../../components/Divider"
|
|
4
|
-
import { cn } from "../cn"
|
|
5
|
-
import type { DynamicRecord, DynamicColumnConfig } from "../../components/DataViews/types"
|
|
1
|
+
import type { ReactElement } from "react";
|
|
2
|
+
import { Badge } from "../../components/Badge";
|
|
3
|
+
import { Divider } from "../../components/Divider";
|
|
4
|
+
import { cn } from "../cn";
|
|
5
|
+
import type { DynamicRecord, DynamicColumnConfig } from "../../components/DataViews/types";
|
|
6
6
|
|
|
7
7
|
export type NestedFieldMetadata = {
|
|
8
|
-
key: string
|
|
9
|
-
label: string
|
|
10
|
-
type:
|
|
11
|
-
valueType?:
|
|
12
|
-
isArrayOfObjects?: boolean
|
|
13
|
-
depth: number
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
export function isPlainObject(value:
|
|
17
|
-
return
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
8
|
+
key: string;
|
|
9
|
+
label: string;
|
|
10
|
+
type: "object" | "array" | "primitive";
|
|
11
|
+
valueType?: "string" | "number" | "boolean" | "date";
|
|
12
|
+
isArrayOfObjects?: boolean;
|
|
13
|
+
depth: number;
|
|
14
|
+
};
|
|
15
|
+
|
|
16
|
+
export function isPlainObject(value: unknown): boolean {
|
|
17
|
+
return (
|
|
18
|
+
value !== null &&
|
|
19
|
+
typeof value === "object" &&
|
|
20
|
+
!Array.isArray(value) &&
|
|
21
|
+
!(value instanceof Date) &&
|
|
22
|
+
Object.keys(value).length > 0
|
|
23
|
+
);
|
|
22
24
|
}
|
|
23
25
|
|
|
24
26
|
export function formatFieldName(fieldName: string): string {
|
|
@@ -26,84 +28,85 @@ export function formatFieldName(fieldName: string): string {
|
|
|
26
28
|
return fieldName
|
|
27
29
|
.split("_")
|
|
28
30
|
.map((word) => word.charAt(0).toUpperCase() + word.slice(1))
|
|
29
|
-
.join(" ")
|
|
31
|
+
.join(" ");
|
|
30
32
|
}
|
|
31
33
|
|
|
32
34
|
return fieldName
|
|
33
35
|
.replace(/([A-Z])/g, " $1")
|
|
34
36
|
.replace(/^./, (str) => str.toUpperCase())
|
|
35
|
-
.trim()
|
|
37
|
+
.trim();
|
|
36
38
|
}
|
|
37
39
|
|
|
38
40
|
export function analyzeNestedFields(
|
|
39
41
|
item: DynamicRecord,
|
|
40
42
|
visibleColumnIds: Set<string> = new Set(),
|
|
41
|
-
excludeKeys: string[] = [
|
|
43
|
+
excludeKeys: string[] = ["id", "isRead", "isStarred", "hasAttachment", "priority"],
|
|
42
44
|
): NestedFieldMetadata[] {
|
|
43
|
-
const nestedFields: NestedFieldMetadata[] = []
|
|
45
|
+
const nestedFields: NestedFieldMetadata[] = [];
|
|
44
46
|
|
|
45
47
|
Object.entries(item).forEach(([key, value]) => {
|
|
46
48
|
if (visibleColumnIds.has(key) || excludeKeys.includes(key)) {
|
|
47
|
-
return
|
|
49
|
+
return;
|
|
48
50
|
}
|
|
49
51
|
|
|
50
52
|
if (isPlainObject(value)) {
|
|
51
53
|
nestedFields.push({
|
|
52
54
|
key,
|
|
53
55
|
label: formatFieldName(key),
|
|
54
|
-
type:
|
|
55
|
-
depth: 0
|
|
56
|
-
})
|
|
56
|
+
type: "object",
|
|
57
|
+
depth: 0,
|
|
58
|
+
});
|
|
57
59
|
} else if (Array.isArray(value) && value.length > 0) {
|
|
58
60
|
nestedFields.push({
|
|
59
61
|
key,
|
|
60
62
|
label: formatFieldName(key),
|
|
61
|
-
type:
|
|
63
|
+
type: "array",
|
|
62
64
|
isArrayOfObjects: isPlainObject(value[0]),
|
|
63
|
-
depth: 0
|
|
64
|
-
})
|
|
65
|
+
depth: 0,
|
|
66
|
+
});
|
|
65
67
|
}
|
|
66
|
-
})
|
|
68
|
+
});
|
|
67
69
|
|
|
68
|
-
return nestedFields
|
|
70
|
+
return nestedFields;
|
|
69
71
|
}
|
|
70
72
|
|
|
71
73
|
export function isCurrencyField(key: string): boolean {
|
|
72
|
-
const lowerKey = key.toLowerCase()
|
|
73
|
-
return
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
74
|
+
const lowerKey = key.toLowerCase();
|
|
75
|
+
return (
|
|
76
|
+
lowerKey.includes("salary") ||
|
|
77
|
+
lowerKey.includes("price") ||
|
|
78
|
+
lowerKey.includes("cost") ||
|
|
79
|
+
lowerKey.includes("amount") ||
|
|
80
|
+
lowerKey.includes("pay") ||
|
|
81
|
+
lowerKey.includes("fee")
|
|
82
|
+
);
|
|
79
83
|
}
|
|
80
84
|
|
|
81
85
|
export function isRatingField(key: string): boolean {
|
|
82
|
-
const lowerKey = key.toLowerCase()
|
|
83
|
-
return lowerKey.includes(
|
|
84
|
-
lowerKey.includes('score')
|
|
86
|
+
const lowerKey = key.toLowerCase();
|
|
87
|
+
return lowerKey.includes("rating") || lowerKey.includes("score");
|
|
85
88
|
}
|
|
86
89
|
|
|
87
90
|
export function renderPrimitiveValue(
|
|
88
91
|
key: string,
|
|
89
|
-
value:
|
|
92
|
+
value: unknown,
|
|
90
93
|
options: {
|
|
91
|
-
showLabel?: boolean
|
|
92
|
-
labelClassName?: string
|
|
93
|
-
valueClassName?: string
|
|
94
|
-
} = {}
|
|
94
|
+
showLabel?: boolean;
|
|
95
|
+
labelClassName?: string;
|
|
96
|
+
valueClassName?: string;
|
|
97
|
+
} = {},
|
|
95
98
|
): ReactElement | null {
|
|
96
99
|
const {
|
|
97
100
|
showLabel = true,
|
|
98
101
|
labelClassName = "text-content-presentation-global-tertiary",
|
|
99
|
-
valueClassName = "text-content-presentation-global-primary"
|
|
100
|
-
} = options
|
|
102
|
+
valueClassName = "text-content-presentation-global-primary",
|
|
103
|
+
} = options;
|
|
101
104
|
|
|
102
|
-
if (value == null) return null
|
|
105
|
+
if (value == null) return null;
|
|
103
106
|
|
|
104
|
-
const label = showLabel ? formatFieldName(key) : null
|
|
107
|
+
const label = showLabel ? formatFieldName(key) : null;
|
|
105
108
|
|
|
106
|
-
if (typeof value ===
|
|
109
|
+
if (typeof value === "boolean") {
|
|
107
110
|
return (
|
|
108
111
|
<div className="flex items-center gap-2">
|
|
109
112
|
{label && <span className={labelClassName}>{label}:</span>}
|
|
@@ -112,15 +115,14 @@ export function renderPrimitiveValue(
|
|
|
112
115
|
badgeStyle={value ? "solid" : "subtle"}
|
|
113
116
|
label={value ? "Yes" : "No"}
|
|
114
117
|
size="XS"
|
|
115
|
-
|
|
116
118
|
/>
|
|
117
119
|
</div>
|
|
118
|
-
)
|
|
120
|
+
);
|
|
119
121
|
}
|
|
120
122
|
|
|
121
|
-
if (typeof value ===
|
|
122
|
-
const isCurrency = isCurrencyField(key)
|
|
123
|
-
const isRating = isRatingField(key)
|
|
123
|
+
if (typeof value === "number") {
|
|
124
|
+
const isCurrency = isCurrencyField(key);
|
|
125
|
+
const isRating = isRatingField(key);
|
|
124
126
|
|
|
125
127
|
if (isRating && value <= 5) {
|
|
126
128
|
return (
|
|
@@ -129,7 +131,10 @@ export function renderPrimitiveValue(
|
|
|
129
131
|
<div className="flex items-center gap-2">
|
|
130
132
|
<div className="flex">
|
|
131
133
|
{[...Array(5)].map((_, i) => (
|
|
132
|
-
<span
|
|
134
|
+
<span
|
|
135
|
+
key={i}
|
|
136
|
+
className={i < Math.floor(value) ? "text-yellow-500" : "text-gray-300"}
|
|
137
|
+
>
|
|
133
138
|
⭐
|
|
134
139
|
</span>
|
|
135
140
|
))}
|
|
@@ -137,20 +142,17 @@ export function renderPrimitiveValue(
|
|
|
137
142
|
<span className="font-semibold text-sm">{value}</span>
|
|
138
143
|
</div>
|
|
139
144
|
</div>
|
|
140
|
-
)
|
|
145
|
+
);
|
|
141
146
|
}
|
|
142
147
|
|
|
143
148
|
return (
|
|
144
149
|
<div className="flex items-center gap-2">
|
|
145
150
|
{label && <span className={labelClassName}>{label}:</span>}
|
|
146
|
-
<span className={cn(
|
|
147
|
-
valueClassName,
|
|
148
|
-
isCurrency && "font-semibold text-green-600"
|
|
149
|
-
)}>
|
|
151
|
+
<span className={cn(valueClassName, isCurrency && "font-semibold text-green-600")}>
|
|
150
152
|
{isCurrency ? `$${value.toLocaleString()}` : value.toLocaleString()}
|
|
151
153
|
</span>
|
|
152
154
|
</div>
|
|
153
|
-
)
|
|
155
|
+
);
|
|
154
156
|
}
|
|
155
157
|
|
|
156
158
|
return (
|
|
@@ -158,24 +160,24 @@ export function renderPrimitiveValue(
|
|
|
158
160
|
{label && <span className={labelClassName}>{label}:</span>}
|
|
159
161
|
<span className={valueClassName}>{String(value)}</span>
|
|
160
162
|
</div>
|
|
161
|
-
)
|
|
163
|
+
);
|
|
162
164
|
}
|
|
163
165
|
|
|
164
166
|
export function renderArrayValue(
|
|
165
167
|
key: string,
|
|
166
|
-
value:
|
|
168
|
+
value: unknown[],
|
|
167
169
|
options: {
|
|
168
|
-
showLabel?: boolean
|
|
169
|
-
maxItems?: number
|
|
170
|
-
renderItem?: (item:
|
|
171
|
-
} = {}
|
|
170
|
+
showLabel?: boolean;
|
|
171
|
+
maxItems?: number;
|
|
172
|
+
renderItem?: (item: unknown, index: number) => ReactElement;
|
|
173
|
+
} = {},
|
|
172
174
|
): ReactElement | null {
|
|
173
|
-
const { showLabel = true, maxItems, renderItem } = options
|
|
175
|
+
const { showLabel = true, maxItems, renderItem } = options;
|
|
174
176
|
|
|
175
|
-
if (!Array.isArray(value) || value.length === 0) return null
|
|
177
|
+
if (!Array.isArray(value) || value.length === 0) return null;
|
|
176
178
|
|
|
177
|
-
const label = showLabel ? formatFieldName(key) : null
|
|
178
|
-
const displayItems = maxItems ? value.slice(0, maxItems) : value
|
|
179
|
+
const label = showLabel ? formatFieldName(key) : null;
|
|
180
|
+
const displayItems = maxItems ? value.slice(0, maxItems) : value;
|
|
179
181
|
|
|
180
182
|
if (isPlainObject(value[0])) {
|
|
181
183
|
return (
|
|
@@ -186,15 +188,15 @@ export function renderArrayValue(
|
|
|
186
188
|
</div>
|
|
187
189
|
)}
|
|
188
190
|
<div className="space-y-2">
|
|
189
|
-
{displayItems.map((item:
|
|
191
|
+
{displayItems.map((item: unknown, idx: number) => {
|
|
190
192
|
if (renderItem) {
|
|
191
|
-
return renderItem(item, idx)
|
|
193
|
+
return renderItem(item, idx);
|
|
192
194
|
}
|
|
193
195
|
return (
|
|
194
196
|
<div key={idx} className="p-2 rounded bg-background-presentation-form-field-primary">
|
|
195
197
|
{renderNestedObject(item, 1)}
|
|
196
198
|
</div>
|
|
197
|
-
)
|
|
199
|
+
);
|
|
198
200
|
})}
|
|
199
201
|
{maxItems && value.length > maxItems && (
|
|
200
202
|
<div className="text-xs text-content-presentation-global-tertiary">
|
|
@@ -203,14 +205,14 @@ export function renderArrayValue(
|
|
|
203
205
|
)}
|
|
204
206
|
</div>
|
|
205
207
|
</div>
|
|
206
|
-
)
|
|
208
|
+
);
|
|
207
209
|
}
|
|
208
210
|
|
|
209
211
|
return (
|
|
210
212
|
<div className="flex items-start gap-2">
|
|
211
213
|
{label && <span className="text-content-presentation-global-tertiary">{label}:</span>}
|
|
212
214
|
<div className="flex flex-wrap gap-1">
|
|
213
|
-
{displayItems.map((item:
|
|
215
|
+
{displayItems.map((item: unknown, idx: number) => (
|
|
214
216
|
<Badge key={idx} color="blue" badgeStyle="solid" label={String(item)} size="XS" />
|
|
215
217
|
))}
|
|
216
218
|
{maxItems && value.length > maxItems && (
|
|
@@ -218,26 +220,26 @@ export function renderArrayValue(
|
|
|
218
220
|
)}
|
|
219
221
|
</div>
|
|
220
222
|
</div>
|
|
221
|
-
)
|
|
223
|
+
);
|
|
222
224
|
}
|
|
223
225
|
|
|
224
226
|
export function renderNestedObject(
|
|
225
|
-
obj:
|
|
227
|
+
obj: unknown,
|
|
226
228
|
depth: number = 0,
|
|
227
229
|
options: {
|
|
228
|
-
maxDepth?: number
|
|
229
|
-
showSeparators?: boolean
|
|
230
|
-
} = {}
|
|
230
|
+
maxDepth?: number;
|
|
231
|
+
showSeparators?: boolean;
|
|
232
|
+
} = {},
|
|
231
233
|
): ReactElement {
|
|
232
|
-
const { maxDepth = 3 } = options
|
|
234
|
+
const { maxDepth = 3 } = options;
|
|
233
235
|
|
|
234
236
|
if (depth >= maxDepth) {
|
|
235
|
-
return <div className="text-xs text-content-presentation-global-tertiary">...</div
|
|
237
|
+
return <div className="text-xs text-content-presentation-global-tertiary">...</div>;
|
|
236
238
|
}
|
|
237
239
|
|
|
238
240
|
return (
|
|
239
241
|
<div className="space-y-2 text-sm">
|
|
240
|
-
{Object.entries(obj).map(([key, value]) => {
|
|
242
|
+
{Object.entries(obj as Record<string, unknown>).map(([key, value]) => {
|
|
241
243
|
if (isPlainObject(value)) {
|
|
242
244
|
return (
|
|
243
245
|
<div key={key} className="space-y-1">
|
|
@@ -248,34 +250,39 @@ export function renderNestedObject(
|
|
|
248
250
|
{renderNestedObject(value, depth + 1, options)}
|
|
249
251
|
</div>
|
|
250
252
|
</div>
|
|
251
|
-
)
|
|
253
|
+
);
|
|
252
254
|
}
|
|
253
255
|
|
|
254
256
|
if (Array.isArray(value)) {
|
|
255
|
-
return <div key={key}>{renderArrayValue(key, value)}</div
|
|
257
|
+
return <div key={key}>{renderArrayValue(key, value)}</div>;
|
|
256
258
|
}
|
|
257
259
|
|
|
258
|
-
return <div key={key}>{renderPrimitiveValue(key, value)}</div
|
|
260
|
+
return <div key={key}>{renderPrimitiveValue(key, value)}</div>;
|
|
259
261
|
})}
|
|
260
262
|
</div>
|
|
261
|
-
)
|
|
263
|
+
);
|
|
262
264
|
}
|
|
263
265
|
|
|
264
266
|
export function renderDetailView(
|
|
265
267
|
selectedItem: DynamicRecord,
|
|
266
268
|
visibleColumns: DynamicColumnConfig[],
|
|
267
|
-
renderCellValue: (
|
|
269
|
+
renderCellValue: (
|
|
270
|
+
value: unknown,
|
|
271
|
+
column: DynamicColumnConfig,
|
|
272
|
+
row: DynamicRecord,
|
|
273
|
+
) => React.ReactNode,
|
|
268
274
|
): ReactElement {
|
|
269
|
-
const visibleColumnIds = new Set(visibleColumns.map(col => col.id))
|
|
270
|
-
const nestedFields = analyzeNestedFields(selectedItem, visibleColumnIds)
|
|
275
|
+
const visibleColumnIds = new Set(visibleColumns.map((col) => col.id));
|
|
276
|
+
const nestedFields = analyzeNestedFields(selectedItem, visibleColumnIds);
|
|
271
277
|
|
|
272
278
|
return (
|
|
273
279
|
<div className="space-y-6">
|
|
274
280
|
{visibleColumns.slice(2).length > 0 && (
|
|
275
281
|
<div className="grid grid-cols-1 md:grid-cols-2 gap-4">
|
|
276
282
|
{visibleColumns.slice(2).map((col) => {
|
|
277
|
-
const value = selectedItem[col.id]
|
|
278
|
-
|
|
283
|
+
const value = selectedItem[col.id];
|
|
284
|
+
// Skip empty cells (null/undefined); 0 and false are rendered.
|
|
285
|
+
if (value === null || value === undefined) return null;
|
|
279
286
|
return (
|
|
280
287
|
<div key={col.id} className="space-y-1">
|
|
281
288
|
<dt className="text-xs font-medium text-content-presentation-global-tertiary uppercase tracking-wide">
|
|
@@ -285,15 +292,15 @@ export function renderDetailView(
|
|
|
285
292
|
{renderCellValue(value, col, selectedItem)}
|
|
286
293
|
</dd>
|
|
287
294
|
</div>
|
|
288
|
-
)
|
|
295
|
+
);
|
|
289
296
|
})}
|
|
290
297
|
</div>
|
|
291
298
|
)}
|
|
292
299
|
|
|
293
300
|
{nestedFields.map((field, index) => {
|
|
294
|
-
const value = selectedItem[field.key]
|
|
301
|
+
const value = selectedItem[field.key];
|
|
295
302
|
|
|
296
|
-
if (field.type ===
|
|
303
|
+
if (field.type === "object" && isPlainObject(value)) {
|
|
297
304
|
return (
|
|
298
305
|
<div key={field.key}>
|
|
299
306
|
{index > 0 && <Divider />}
|
|
@@ -304,10 +311,10 @@ export function renderDetailView(
|
|
|
304
311
|
{renderNestedObject(value)}
|
|
305
312
|
</div>
|
|
306
313
|
</div>
|
|
307
|
-
)
|
|
314
|
+
);
|
|
308
315
|
}
|
|
309
316
|
|
|
310
|
-
if (field.type ===
|
|
317
|
+
if (field.type === "array" && Array.isArray(value)) {
|
|
311
318
|
return (
|
|
312
319
|
<div key={field.key}>
|
|
313
320
|
{index > 0 && <Divider />}
|
|
@@ -318,47 +325,47 @@ export function renderDetailView(
|
|
|
318
325
|
{renderArrayValue(field.key, value, { showLabel: false })}
|
|
319
326
|
</div>
|
|
320
327
|
</div>
|
|
321
|
-
)
|
|
328
|
+
);
|
|
322
329
|
}
|
|
323
330
|
|
|
324
|
-
return null
|
|
331
|
+
return null;
|
|
325
332
|
})}
|
|
326
333
|
</div>
|
|
327
|
-
)
|
|
334
|
+
);
|
|
328
335
|
}
|
|
329
336
|
|
|
330
337
|
export function getDataStructureSummary(data: DynamicRecord[]): {
|
|
331
|
-
totalFields: number
|
|
332
|
-
nestedFields: string[]
|
|
333
|
-
arrayFields: string[]
|
|
334
|
-
primitiveFields: string[]
|
|
338
|
+
totalFields: number;
|
|
339
|
+
nestedFields: string[];
|
|
340
|
+
arrayFields: string[];
|
|
341
|
+
primitiveFields: string[];
|
|
335
342
|
} {
|
|
336
343
|
if (!data || data.length === 0) {
|
|
337
|
-
return { totalFields: 0, nestedFields: [], arrayFields: [], primitiveFields: [] }
|
|
344
|
+
return { totalFields: 0, nestedFields: [], arrayFields: [], primitiveFields: [] };
|
|
338
345
|
}
|
|
339
346
|
|
|
340
|
-
const allKeys = new Set<string>()
|
|
341
|
-
const nestedKeys = new Set<string>()
|
|
342
|
-
const arrayKeys = new Set<string>()
|
|
343
|
-
const primitiveKeys = new Set<string>()
|
|
347
|
+
const allKeys = new Set<string>();
|
|
348
|
+
const nestedKeys = new Set<string>();
|
|
349
|
+
const arrayKeys = new Set<string>();
|
|
350
|
+
const primitiveKeys = new Set<string>();
|
|
344
351
|
|
|
345
|
-
data.forEach(item => {
|
|
352
|
+
data.forEach((item) => {
|
|
346
353
|
Object.entries(item).forEach(([key, value]) => {
|
|
347
|
-
allKeys.add(key)
|
|
354
|
+
allKeys.add(key);
|
|
348
355
|
if (isPlainObject(value)) {
|
|
349
|
-
nestedKeys.add(key)
|
|
356
|
+
nestedKeys.add(key);
|
|
350
357
|
} else if (Array.isArray(value)) {
|
|
351
|
-
arrayKeys.add(key)
|
|
358
|
+
arrayKeys.add(key);
|
|
352
359
|
} else {
|
|
353
|
-
primitiveKeys.add(key)
|
|
360
|
+
primitiveKeys.add(key);
|
|
354
361
|
}
|
|
355
|
-
})
|
|
356
|
-
})
|
|
362
|
+
});
|
|
363
|
+
});
|
|
357
364
|
|
|
358
365
|
return {
|
|
359
366
|
totalFields: allKeys.size,
|
|
360
367
|
nestedFields: Array.from(nestedKeys),
|
|
361
368
|
arrayFields: Array.from(arrayKeys),
|
|
362
|
-
primitiveFields: Array.from(primitiveKeys)
|
|
363
|
-
}
|
|
369
|
+
primitiveFields: Array.from(primitiveKeys),
|
|
370
|
+
};
|
|
364
371
|
}
|
|
@@ -1,132 +1,139 @@
|
|
|
1
|
-
export type Path = string
|
|
1
|
+
export type Path = string;
|
|
2
2
|
|
|
3
|
-
const PATH_CACHE = new Map<string, string[]>()
|
|
3
|
+
const PATH_CACHE = new Map<string, string[]>();
|
|
4
4
|
|
|
5
5
|
function splitPath(path: Path): string[] {
|
|
6
|
-
const cached = PATH_CACHE.get(path)
|
|
7
|
-
if (cached) return cached
|
|
8
|
-
const parts = path.split(".")
|
|
9
|
-
PATH_CACHE.set(path, parts)
|
|
10
|
-
return parts
|
|
6
|
+
const cached = PATH_CACHE.get(path);
|
|
7
|
+
if (cached) return cached;
|
|
8
|
+
const parts = path.split(".");
|
|
9
|
+
PATH_CACHE.set(path, parts);
|
|
10
|
+
return parts;
|
|
11
11
|
}
|
|
12
12
|
|
|
13
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- generic path accessor returns arbitrary runtime values
|
|
13
14
|
export function getByPath(obj: unknown, path: Path | undefined | null): any {
|
|
14
|
-
if (obj == null || path == null || path === "") return undefined
|
|
15
|
-
if (typeof obj !== "object") return undefined
|
|
15
|
+
if (obj == null || path == null || path === "") return undefined;
|
|
16
|
+
if (typeof obj !== "object") return undefined;
|
|
16
17
|
|
|
17
|
-
const parts = splitPath(path)
|
|
18
|
-
let cur:
|
|
18
|
+
const parts = splitPath(path);
|
|
19
|
+
let cur: unknown = obj;
|
|
19
20
|
for (let i = 0; i < parts.length; i++) {
|
|
20
|
-
if (cur == null) return undefined
|
|
21
|
-
cur = cur[parts[i]]
|
|
21
|
+
if (cur == null) return undefined;
|
|
22
|
+
cur = (cur as Record<string, unknown>)[parts[i]];
|
|
22
23
|
}
|
|
23
|
-
return cur
|
|
24
|
+
return cur;
|
|
24
25
|
}
|
|
25
26
|
|
|
26
|
-
export function setByPath<T extends Record<string,
|
|
27
|
+
export function setByPath<T extends Record<string, unknown>>(
|
|
27
28
|
obj: T,
|
|
28
29
|
path: Path,
|
|
29
|
-
value:
|
|
30
|
+
value: unknown,
|
|
30
31
|
): T {
|
|
31
|
-
if (!path) return obj
|
|
32
|
-
const parts = splitPath(path)
|
|
33
|
-
if (parts.length === 0) return obj
|
|
32
|
+
if (!path) return obj;
|
|
33
|
+
const parts = splitPath(path);
|
|
34
|
+
if (parts.length === 0) return obj;
|
|
34
35
|
|
|
35
|
-
const root
|
|
36
|
-
let cur:
|
|
36
|
+
const root = (Array.isArray(obj) ? [...obj] : { ...obj }) as Record<string, unknown>;
|
|
37
|
+
let cur: Record<string, unknown> = root;
|
|
37
38
|
|
|
38
39
|
for (let i = 0; i < parts.length - 1; i++) {
|
|
39
|
-
const key = parts[i]
|
|
40
|
-
const next = cur[key]
|
|
41
|
-
const cloned =
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
40
|
+
const key = parts[i];
|
|
41
|
+
const next = cur[key];
|
|
42
|
+
const cloned = (
|
|
43
|
+
next != null && typeof next === "object" && !Array.isArray(next)
|
|
44
|
+
? { ...next }
|
|
45
|
+
: Array.isArray(next)
|
|
46
|
+
? [...next]
|
|
47
|
+
: {}
|
|
48
|
+
) as Record<string, unknown>;
|
|
49
|
+
cur[key] = cloned;
|
|
50
|
+
cur = cloned;
|
|
48
51
|
}
|
|
49
52
|
|
|
50
|
-
cur[parts[parts.length - 1]] = value
|
|
51
|
-
return root
|
|
53
|
+
cur[parts[parts.length - 1]] = value;
|
|
54
|
+
return root as T;
|
|
52
55
|
}
|
|
53
56
|
|
|
54
57
|
export function hasPath(obj: unknown, path: Path | undefined | null): boolean {
|
|
55
|
-
return getByPath(obj, path) !== undefined
|
|
58
|
+
return getByPath(obj, path) !== undefined;
|
|
56
59
|
}
|
|
57
60
|
|
|
58
61
|
export function formatPathLabel(path: Path): string {
|
|
59
|
-
if (!path) return ""
|
|
60
|
-
const tail = path.includes(".") ? path.split(".").pop()! : path
|
|
62
|
+
if (!path) return "";
|
|
63
|
+
const tail = path.includes(".") ? path.split(".").pop()! : path;
|
|
61
64
|
|
|
62
65
|
if (tail.includes("_")) {
|
|
63
66
|
return tail
|
|
64
67
|
.split("_")
|
|
65
68
|
.filter(Boolean)
|
|
66
69
|
.map((w) => w.charAt(0).toUpperCase() + w.slice(1))
|
|
67
|
-
.join(" ")
|
|
70
|
+
.join(" ");
|
|
68
71
|
}
|
|
69
72
|
|
|
70
73
|
return tail
|
|
71
74
|
.replace(/([A-Z])/g, " $1")
|
|
72
75
|
.replace(/^./, (s) => s.toUpperCase())
|
|
73
|
-
.trim()
|
|
76
|
+
.trim();
|
|
74
77
|
}
|
|
75
78
|
|
|
76
|
-
export function findFirstDefined(data:
|
|
79
|
+
export function findFirstDefined(data: unknown[], path: Path): unknown {
|
|
77
80
|
for (const item of data) {
|
|
78
|
-
const v = getByPath(item, path)
|
|
79
|
-
if (v != null) return v
|
|
81
|
+
const v = getByPath(item, path);
|
|
82
|
+
if (v != null) return v;
|
|
80
83
|
}
|
|
81
|
-
return undefined
|
|
84
|
+
return undefined;
|
|
82
85
|
}
|
|
83
86
|
|
|
84
87
|
export function matchesFilterValues(
|
|
85
88
|
item: unknown,
|
|
86
89
|
path: Path,
|
|
87
|
-
filter:
|
|
90
|
+
filter:
|
|
91
|
+
| string[]
|
|
92
|
+
| { kind: "number"; min?: number; max?: number }
|
|
93
|
+
| { kind: "date"; from?: string; to?: string }
|
|
94
|
+
| undefined,
|
|
88
95
|
): boolean {
|
|
89
|
-
if (filter == null) return true
|
|
96
|
+
if (filter == null) return true;
|
|
90
97
|
|
|
91
98
|
if (Array.isArray(filter)) {
|
|
92
|
-
if (filter.length === 0) return true
|
|
93
|
-
const value = getByPath(item, path)
|
|
99
|
+
if (filter.length === 0) return true;
|
|
100
|
+
const value = getByPath(item, path);
|
|
94
101
|
if (Array.isArray(value)) {
|
|
95
|
-
const set = new Set(value.map((v) => String(v)))
|
|
96
|
-
return filter.some((s) => set.has(s))
|
|
102
|
+
const set = new Set(value.map((v) => String(v)));
|
|
103
|
+
return filter.some((s) => set.has(s));
|
|
97
104
|
}
|
|
98
105
|
if (typeof value === "boolean") {
|
|
99
|
-
return filter.includes(value ? "true" : "false")
|
|
106
|
+
return filter.includes(value ? "true" : "false");
|
|
100
107
|
}
|
|
101
|
-
return filter.includes(String(value ?? ""))
|
|
108
|
+
return filter.includes(String(value ?? ""));
|
|
102
109
|
}
|
|
103
110
|
|
|
104
111
|
if (filter.kind === "number") {
|
|
105
|
-
if (filter.min == null && filter.max == null) return true
|
|
106
|
-
const raw = getByPath(item, path)
|
|
107
|
-
const n = typeof raw === "number" ? raw : Number(raw)
|
|
108
|
-
if (!Number.isFinite(n)) return false
|
|
109
|
-
if (filter.min != null && n < filter.min) return false
|
|
110
|
-
if (filter.max != null && n > filter.max) return false
|
|
111
|
-
return true
|
|
112
|
+
if (filter.min == null && filter.max == null) return true;
|
|
113
|
+
const raw = getByPath(item, path);
|
|
114
|
+
const n = typeof raw === "number" ? raw : Number(raw);
|
|
115
|
+
if (!Number.isFinite(n)) return false;
|
|
116
|
+
if (filter.min != null && n < filter.min) return false;
|
|
117
|
+
if (filter.max != null && n > filter.max) return false;
|
|
118
|
+
return true;
|
|
112
119
|
}
|
|
113
120
|
|
|
114
121
|
if (filter.kind === "date") {
|
|
115
|
-
if (filter.from == null && filter.to == null) return true
|
|
116
|
-
const raw = getByPath(item, path)
|
|
117
|
-
if (raw == null) return false
|
|
118
|
-
const ms = raw instanceof Date ? raw.getTime() : Date.parse(String(raw))
|
|
119
|
-
if (!Number.isFinite(ms)) return false
|
|
122
|
+
if (filter.from == null && filter.to == null) return true;
|
|
123
|
+
const raw = getByPath(item, path);
|
|
124
|
+
if (raw == null) return false;
|
|
125
|
+
const ms = raw instanceof Date ? raw.getTime() : Date.parse(String(raw));
|
|
126
|
+
if (!Number.isFinite(ms)) return false;
|
|
120
127
|
if (filter.from != null) {
|
|
121
|
-
const fromMs = Date.parse(filter.from)
|
|
122
|
-
if (Number.isFinite(fromMs) && ms < fromMs) return false
|
|
128
|
+
const fromMs = Date.parse(filter.from);
|
|
129
|
+
if (Number.isFinite(fromMs) && ms < fromMs) return false;
|
|
123
130
|
}
|
|
124
131
|
if (filter.to != null) {
|
|
125
|
-
const toMs = Date.parse(filter.to)
|
|
126
|
-
if (Number.isFinite(toMs) && ms > toMs + 24 * 60 * 60 * 1000 - 1) return false
|
|
132
|
+
const toMs = Date.parse(filter.to);
|
|
133
|
+
if (Number.isFinite(toMs) && ms > toMs + 24 * 60 * 60 * 1000 - 1) return false;
|
|
127
134
|
}
|
|
128
|
-
return true
|
|
135
|
+
return true;
|
|
129
136
|
}
|
|
130
137
|
|
|
131
|
-
return true
|
|
138
|
+
return true;
|
|
132
139
|
}
|