@freighttech/ui 0.13.18
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/LICENSE +21 -0
- package/README.md +31 -0
- package/dist/backend/AppShell.js +1289 -0
- package/dist/backend/AppShell.js.map +7 -0
- package/dist/backend/BackendChromeProvider.js +83 -0
- package/dist/backend/BackendChromeProvider.js.map +7 -0
- package/dist/backend/BackendPageSurface.js +19 -0
- package/dist/backend/BackendPageSurface.js.map +7 -0
- package/dist/backend/CollapsibleNavSection.js +149 -0
- package/dist/backend/CollapsibleNavSection.js.map +7 -0
- package/dist/backend/ContextHelp.js +33 -0
- package/dist/backend/ContextHelp.js.map +7 -0
- package/dist/backend/CrudForm.js +3163 -0
- package/dist/backend/CrudForm.js.map +7 -0
- package/dist/backend/DataTable.js +2091 -0
- package/dist/backend/DataTable.js.map +7 -0
- package/dist/backend/EmptyState.js +52 -0
- package/dist/backend/EmptyState.js.map +7 -0
- package/dist/backend/FilterBar.js +147 -0
- package/dist/backend/FilterBar.js.map +7 -0
- package/dist/backend/FilterOverlay.js +337 -0
- package/dist/backend/FilterOverlay.js.map +7 -0
- package/dist/backend/FlashMessages.js +158 -0
- package/dist/backend/FlashMessages.js.map +7 -0
- package/dist/backend/HtmlRichTextEditor.js +129 -0
- package/dist/backend/HtmlRichTextEditor.js.map +7 -0
- package/dist/backend/IntegrationsButton.js +25 -0
- package/dist/backend/IntegrationsButton.js.map +7 -0
- package/dist/backend/JsonBuilder.js +323 -0
- package/dist/backend/JsonBuilder.js.map +7 -0
- package/dist/backend/JsonDisplay.js +207 -0
- package/dist/backend/JsonDisplay.js.map +7 -0
- package/dist/backend/NextStepCallout.js +79 -0
- package/dist/backend/NextStepCallout.js.map +7 -0
- package/dist/backend/Page.js +27 -0
- package/dist/backend/Page.js.map +7 -0
- package/dist/backend/PerspectiveSidebar.js +456 -0
- package/dist/backend/PerspectiveSidebar.js.map +7 -0
- package/dist/backend/ProfileDropdown.js +341 -0
- package/dist/backend/ProfileDropdown.js.map +7 -0
- package/dist/backend/RowActions.js +155 -0
- package/dist/backend/RowActions.js.map +7 -0
- package/dist/backend/SectionHeader.js +74 -0
- package/dist/backend/SectionHeader.js.map +7 -0
- package/dist/backend/SettingsButton.js +25 -0
- package/dist/backend/SettingsButton.js.map +7 -0
- package/dist/backend/Sidebar.js +510 -0
- package/dist/backend/Sidebar.js.map +7 -0
- package/dist/backend/Sidebar.stories.js +166 -0
- package/dist/backend/Sidebar.stories.js.map +7 -0
- package/dist/backend/TruncatedCell.js +92 -0
- package/dist/backend/TruncatedCell.js.map +7 -0
- package/dist/backend/UserMenu.js +146 -0
- package/dist/backend/UserMenu.js.map +7 -0
- package/dist/backend/ValueIcons.js +34 -0
- package/dist/backend/ValueIcons.js.map +7 -0
- package/dist/backend/WebhookSetupGuide.js +79 -0
- package/dist/backend/WebhookSetupGuide.js.map +7 -0
- package/dist/backend/charts/BarChart.js +154 -0
- package/dist/backend/charts/BarChart.js.map +7 -0
- package/dist/backend/charts/ChartUtils.js +141 -0
- package/dist/backend/charts/ChartUtils.js.map +7 -0
- package/dist/backend/charts/ComboChart.js +261 -0
- package/dist/backend/charts/ComboChart.js.map +7 -0
- package/dist/backend/charts/ComboChart.stories.js +88 -0
- package/dist/backend/charts/ComboChart.stories.js.map +7 -0
- package/dist/backend/charts/KpiCard.js +96 -0
- package/dist/backend/charts/KpiCard.js.map +7 -0
- package/dist/backend/charts/LineChart.js +165 -0
- package/dist/backend/charts/LineChart.js.map +7 -0
- package/dist/backend/charts/PieChart.js +121 -0
- package/dist/backend/charts/PieChart.js.map +7 -0
- package/dist/backend/charts/ScatterChart.js +320 -0
- package/dist/backend/charts/ScatterChart.js.map +7 -0
- package/dist/backend/charts/TopNTable.js +91 -0
- package/dist/backend/charts/TopNTable.js.map +7 -0
- package/dist/backend/charts/WaterfallChart.js +136 -0
- package/dist/backend/charts/WaterfallChart.js.map +7 -0
- package/dist/backend/charts/index.js +30 -0
- package/dist/backend/charts/index.js.map +7 -0
- package/dist/backend/columns/ColumnChooserPanel.js +244 -0
- package/dist/backend/columns/ColumnChooserPanel.js.map +7 -0
- package/dist/backend/confirm-dialog/ConfirmDialog.js +214 -0
- package/dist/backend/confirm-dialog/ConfirmDialog.js.map +7 -0
- package/dist/backend/confirm-dialog/index.js +7 -0
- package/dist/backend/confirm-dialog/index.js.map +7 -0
- package/dist/backend/confirm-dialog/useConfirmDialog.js +113 -0
- package/dist/backend/confirm-dialog/useConfirmDialog.js.map +7 -0
- package/dist/backend/custom-fields/FieldDefinitionsEditor.js +1352 -0
- package/dist/backend/custom-fields/FieldDefinitionsEditor.js.map +7 -0
- package/dist/backend/custom-fields/FieldDefinitionsManager.js +332 -0
- package/dist/backend/custom-fields/FieldDefinitionsManager.js.map +7 -0
- package/dist/backend/dashboard/DashboardScreen.js +598 -0
- package/dist/backend/dashboard/DashboardScreen.js.map +7 -0
- package/dist/backend/dashboard/index.js +5 -0
- package/dist/backend/dashboard/index.js.map +7 -0
- package/dist/backend/dashboard/widgetRegistry.js +55 -0
- package/dist/backend/dashboard/widgetRegistry.js.map +7 -0
- package/dist/backend/date-range/DateRangeSelect.js +39 -0
- package/dist/backend/date-range/DateRangeSelect.js.map +7 -0
- package/dist/backend/date-range/InlineDateRangeSelect.js +42 -0
- package/dist/backend/date-range/InlineDateRangeSelect.js.map +7 -0
- package/dist/backend/date-range/InlineGranularitySelect.js +40 -0
- package/dist/backend/date-range/InlineGranularitySelect.js.map +7 -0
- package/dist/backend/date-range/dateRanges.js +176 -0
- package/dist/backend/date-range/dateRanges.js.map +7 -0
- package/dist/backend/date-range/index.js +25 -0
- package/dist/backend/date-range/index.js.map +7 -0
- package/dist/backend/detail/AccessDeniedMessage.js +28 -0
- package/dist/backend/detail/AccessDeniedMessage.js.map +7 -0
- package/dist/backend/detail/ActivitiesSection.js +947 -0
- package/dist/backend/detail/ActivitiesSection.js.map +7 -0
- package/dist/backend/detail/AddressEditor.js +417 -0
- package/dist/backend/detail/AddressEditor.js.map +7 -0
- package/dist/backend/detail/AddressTiles.js +441 -0
- package/dist/backend/detail/AddressTiles.js.map +7 -0
- package/dist/backend/detail/AddressesSection.js +274 -0
- package/dist/backend/detail/AddressesSection.js.map +7 -0
- package/dist/backend/detail/AttachmentDeleteDialog.js +41 -0
- package/dist/backend/detail/AttachmentDeleteDialog.js.map +7 -0
- package/dist/backend/detail/AttachmentMetadataDialog.js +519 -0
- package/dist/backend/detail/AttachmentMetadataDialog.js.map +7 -0
- package/dist/backend/detail/AttachmentVisualPreview.js +132 -0
- package/dist/backend/detail/AttachmentVisualPreview.js.map +7 -0
- package/dist/backend/detail/AttachmentsSection.js +281 -0
- package/dist/backend/detail/AttachmentsSection.js.map +7 -0
- package/dist/backend/detail/CustomDataSection.js +575 -0
- package/dist/backend/detail/CustomDataSection.js.map +7 -0
- package/dist/backend/detail/DetailFieldsSection.js +85 -0
- package/dist/backend/detail/DetailFieldsSection.js.map +7 -0
- package/dist/backend/detail/ErrorMessage.js +28 -0
- package/dist/backend/detail/ErrorMessage.js.map +7 -0
- package/dist/backend/detail/InlineEditors.js +697 -0
- package/dist/backend/detail/InlineEditors.js.map +7 -0
- package/dist/backend/detail/LoadingMessage.js +14 -0
- package/dist/backend/detail/LoadingMessage.js.map +7 -0
- package/dist/backend/detail/NotesSection.js +1022 -0
- package/dist/backend/detail/NotesSection.js.map +7 -0
- package/dist/backend/detail/TabEmptyState.js +25 -0
- package/dist/backend/detail/TabEmptyState.js.map +7 -0
- package/dist/backend/detail/TagsSection.js +375 -0
- package/dist/backend/detail/TagsSection.js.map +7 -0
- package/dist/backend/detail/addressFormat.js +77 -0
- package/dist/backend/detail/addressFormat.js.map +7 -0
- package/dist/backend/detail/index.js +36 -0
- package/dist/backend/detail/index.js.map +7 -0
- package/dist/backend/devtools/UmesDevToolsPanel.js +109 -0
- package/dist/backend/devtools/UmesDevToolsPanel.js.map +7 -0
- package/dist/backend/devtools/components/ConflictWarnings.js +32 -0
- package/dist/backend/devtools/components/ConflictWarnings.js.map +7 -0
- package/dist/backend/devtools/components/EnricherTiming.js +46 -0
- package/dist/backend/devtools/components/EnricherTiming.js.map +7 -0
- package/dist/backend/devtools/components/EventFlow.js +34 -0
- package/dist/backend/devtools/components/EventFlow.js.map +7 -0
- package/dist/backend/devtools/components/ExtensionPointList.js +58 -0
- package/dist/backend/devtools/components/ExtensionPointList.js.map +7 -0
- package/dist/backend/devtools/components/InterceptorActivity.js +36 -0
- package/dist/backend/devtools/components/InterceptorActivity.js.map +7 -0
- package/dist/backend/devtools/index.js +7 -0
- package/dist/backend/devtools/index.js.map +7 -0
- package/dist/backend/devtools/useUmesDevTools.js +125 -0
- package/dist/backend/devtools/useUmesDevTools.js.map +7 -0
- package/dist/backend/document-viewer/RegionOverlay.js +92 -0
- package/dist/backend/document-viewer/RegionOverlay.js.map +7 -0
- package/dist/backend/document-viewer/index.js +6 -0
- package/dist/backend/document-viewer/index.js.map +7 -0
- package/dist/backend/dynamic-grid/DynamicGrid.js +130 -0
- package/dist/backend/dynamic-grid/DynamicGrid.js.map +7 -0
- package/dist/backend/dynamic-grid/adapters.js +34 -0
- package/dist/backend/dynamic-grid/adapters.js.map +7 -0
- package/dist/backend/dynamic-grid/components/GridCell.js +149 -0
- package/dist/backend/dynamic-grid/components/GridCell.js.map +7 -0
- package/dist/backend/dynamic-grid/components/GridRow.js +32 -0
- package/dist/backend/dynamic-grid/components/GridRow.js.map +7 -0
- package/dist/backend/dynamic-grid/hooks/useGridKeyboardNav.js +115 -0
- package/dist/backend/dynamic-grid/hooks/useGridKeyboardNav.js.map +7 -0
- package/dist/backend/dynamic-grid/index.js +9 -0
- package/dist/backend/dynamic-grid/index.js.map +7 -0
- package/dist/backend/dynamic-grid/types.js +1 -0
- package/dist/backend/dynamic-grid/types.js.map +7 -0
- package/dist/backend/dynamic-table/DynamicTable.js +2607 -0
- package/dist/backend/dynamic-table/DynamicTable.js.map +7 -0
- package/dist/backend/dynamic-table/DynamicTable.stories.js +233 -0
- package/dist/backend/dynamic-table/DynamicTable.stories.js.map +7 -0
- package/dist/backend/dynamic-table/components/ActiveFilterChips.js +60 -0
- package/dist/backend/dynamic-table/components/ActiveFilterChips.js.map +7 -0
- package/dist/backend/dynamic-table/components/BulkActionsBar.js +58 -0
- package/dist/backend/dynamic-table/components/BulkActionsBar.js.map +7 -0
- package/dist/backend/dynamic-table/components/Cell.js +155 -0
- package/dist/backend/dynamic-table/components/Cell.js.map +7 -0
- package/dist/backend/dynamic-table/components/CellCommentDialog.js +726 -0
- package/dist/backend/dynamic-table/components/CellCommentDialog.js.map +7 -0
- package/dist/backend/dynamic-table/components/CellCommentHoverPopup.js +77 -0
- package/dist/backend/dynamic-table/components/CellCommentHoverPopup.js.map +7 -0
- package/dist/backend/dynamic-table/components/ColumnFilterPopover.js +485 -0
- package/dist/backend/dynamic-table/components/ColumnFilterPopover.js.map +7 -0
- package/dist/backend/dynamic-table/components/ColumnHeaderMenu.js +173 -0
- package/dist/backend/dynamic-table/components/ColumnHeaderMenu.js.map +7 -0
- package/dist/backend/dynamic-table/components/ColumnHeaders.js +528 -0
- package/dist/backend/dynamic-table/components/ColumnHeaders.js.map +7 -0
- package/dist/backend/dynamic-table/components/CompactLabelCell.js +64 -0
- package/dist/backend/dynamic-table/components/CompactLabelCell.js.map +7 -0
- package/dist/backend/dynamic-table/components/ConfigureViewFields.js +139 -0
- package/dist/backend/dynamic-table/components/ConfigureViewFields.js.map +7 -0
- package/dist/backend/dynamic-table/components/ConfigureViewFilters.js +305 -0
- package/dist/backend/dynamic-table/components/ConfigureViewFilters.js.map +7 -0
- package/dist/backend/dynamic-table/components/ConfigureViewFormatting.js +169 -0
- package/dist/backend/dynamic-table/components/ConfigureViewFormatting.js.map +7 -0
- package/dist/backend/dynamic-table/components/ConfigureViewFormulas.js +298 -0
- package/dist/backend/dynamic-table/components/ConfigureViewFormulas.js.map +7 -0
- package/dist/backend/dynamic-table/components/ConfigureViewGrouping.js +224 -0
- package/dist/backend/dynamic-table/components/ConfigureViewGrouping.js.map +7 -0
- package/dist/backend/dynamic-table/components/ConfigureViewLinkedColumns.js +167 -0
- package/dist/backend/dynamic-table/components/ConfigureViewLinkedColumns.js.map +7 -0
- package/dist/backend/dynamic-table/components/ConfigureViewPanel.js +592 -0
- package/dist/backend/dynamic-table/components/ConfigureViewPanel.js.map +7 -0
- package/dist/backend/dynamic-table/components/ConfigureViewRollups.js +269 -0
- package/dist/backend/dynamic-table/components/ConfigureViewRollups.js.map +7 -0
- package/dist/backend/dynamic-table/components/ConfigureViewSorting.js +107 -0
- package/dist/backend/dynamic-table/components/ConfigureViewSorting.js.map +7 -0
- package/dist/backend/dynamic-table/components/ContextMenu.js +91 -0
- package/dist/backend/dynamic-table/components/ContextMenu.js.map +7 -0
- package/dist/backend/dynamic-table/components/DateCell.js +80 -0
- package/dist/backend/dynamic-table/components/DateCell.js.map +7 -0
- package/dist/backend/dynamic-table/components/Debugger.js +311 -0
- package/dist/backend/dynamic-table/components/Debugger.js.map +7 -0
- package/dist/backend/dynamic-table/components/DensityControl.js +289 -0
- package/dist/backend/dynamic-table/components/DensityControl.js.map +7 -0
- package/dist/backend/dynamic-table/components/EmptyState.js +42 -0
- package/dist/backend/dynamic-table/components/EmptyState.js.map +7 -0
- package/dist/backend/dynamic-table/components/EntitySearchEditor.js +369 -0
- package/dist/backend/dynamic-table/components/EntitySearchEditor.js.map +7 -0
- package/dist/backend/dynamic-table/components/ExportMenu.js +63 -0
- package/dist/backend/dynamic-table/components/ExportMenu.js.map +7 -0
- package/dist/backend/dynamic-table/components/FilterDatePicker.js +165 -0
- package/dist/backend/dynamic-table/components/FilterDatePicker.js.map +7 -0
- package/dist/backend/dynamic-table/components/FilterValueInput.js +200 -0
- package/dist/backend/dynamic-table/components/FilterValueInput.js.map +7 -0
- package/dist/backend/dynamic-table/components/FooterTotalsRow.js +165 -0
- package/dist/backend/dynamic-table/components/FooterTotalsRow.js.map +7 -0
- package/dist/backend/dynamic-table/components/FullscreenOverlay.js +51 -0
- package/dist/backend/dynamic-table/components/FullscreenOverlay.js.map +7 -0
- package/dist/backend/dynamic-table/components/GroupHeaderRow.js +108 -0
- package/dist/backend/dynamic-table/components/GroupHeaderRow.js.map +7 -0
- package/dist/backend/dynamic-table/components/GroupSummaryRow.js +134 -0
- package/dist/backend/dynamic-table/components/GroupSummaryRow.js.map +7 -0
- package/dist/backend/dynamic-table/components/ImportPanel.js +341 -0
- package/dist/backend/dynamic-table/components/ImportPanel.js.map +7 -0
- package/dist/backend/dynamic-table/components/ImportPreviewGrid.js +114 -0
- package/dist/backend/dynamic-table/components/ImportPreviewGrid.js.map +7 -0
- package/dist/backend/dynamic-table/components/LoadErrorState.js +23 -0
- package/dist/backend/dynamic-table/components/LoadErrorState.js.map +7 -0
- package/dist/backend/dynamic-table/components/MentionPopup.js +149 -0
- package/dist/backend/dynamic-table/components/MentionPopup.js.map +7 -0
- package/dist/backend/dynamic-table/components/PerspectiveDeleteDialog.js +57 -0
- package/dist/backend/dynamic-table/components/PerspectiveDeleteDialog.js.map +7 -0
- package/dist/backend/dynamic-table/components/PerspectivePublishDialog.js +100 -0
- package/dist/backend/dynamic-table/components/PerspectivePublishDialog.js.map +7 -0
- package/dist/backend/dynamic-table/components/PerspectiveTabMenu.js +159 -0
- package/dist/backend/dynamic-table/components/PerspectiveTabMenu.js.map +7 -0
- package/dist/backend/dynamic-table/components/PerspectiveTabs.js +319 -0
- package/dist/backend/dynamic-table/components/PerspectiveTabs.js.map +7 -0
- package/dist/backend/dynamic-table/components/PerspectiveTemplateMenu.js +90 -0
- package/dist/backend/dynamic-table/components/PerspectiveTemplateMenu.js.map +7 -0
- package/dist/backend/dynamic-table/components/RowHeaderCell.js +58 -0
- package/dist/backend/dynamic-table/components/RowHeaderCell.js.map +7 -0
- package/dist/backend/dynamic-table/components/SearchBar.js +221 -0
- package/dist/backend/dynamic-table/components/SearchBar.js.map +7 -0
- package/dist/backend/dynamic-table/components/SelectMenu.js +186 -0
- package/dist/backend/dynamic-table/components/SelectMenu.js.map +7 -0
- package/dist/backend/dynamic-table/components/StaleDataBar.js +26 -0
- package/dist/backend/dynamic-table/components/StaleDataBar.js.map +7 -0
- package/dist/backend/dynamic-table/components/TableDeleteDialog.js +48 -0
- package/dist/backend/dynamic-table/components/TableDeleteDialog.js.map +7 -0
- package/dist/backend/dynamic-table/components/TablePagination.js +69 -0
- package/dist/backend/dynamic-table/components/TablePagination.js.map +7 -0
- package/dist/backend/dynamic-table/components/TableSkeleton.js +43 -0
- package/dist/backend/dynamic-table/components/TableSkeleton.js.map +7 -0
- package/dist/backend/dynamic-table/components/ToolbarOverflow.js +204 -0
- package/dist/backend/dynamic-table/components/ToolbarOverflow.js.map +7 -0
- package/dist/backend/dynamic-table/components/ViewModeSwitch.js +50 -0
- package/dist/backend/dynamic-table/components/ViewModeSwitch.js.map +7 -0
- package/dist/backend/dynamic-table/components/VirtualRow.js +214 -0
- package/dist/backend/dynamic-table/components/VirtualRow.js.map +7 -0
- package/dist/backend/dynamic-table/components/editors.js +1483 -0
- package/dist/backend/dynamic-table/components/editors.js.map +7 -0
- package/dist/backend/dynamic-table/components/renderers.js +131 -0
- package/dist/backend/dynamic-table/components/renderers.js.map +7 -0
- package/dist/backend/dynamic-table/events/events.js +73 -0
- package/dist/backend/dynamic-table/events/events.js.map +7 -0
- package/dist/backend/dynamic-table/formula/check.js +243 -0
- package/dist/backend/dynamic-table/formula/check.js.map +7 -0
- package/dist/backend/dynamic-table/formula/evaluate.js +302 -0
- package/dist/backend/dynamic-table/formula/evaluate.js.map +7 -0
- package/dist/backend/dynamic-table/formula/functions.js +602 -0
- package/dist/backend/dynamic-table/formula/functions.js.map +7 -0
- package/dist/backend/dynamic-table/formula/index.js +47 -0
- package/dist/backend/dynamic-table/formula/index.js.map +7 -0
- package/dist/backend/dynamic-table/formula/parse.js +293 -0
- package/dist/backend/dynamic-table/formula/parse.js.map +7 -0
- package/dist/backend/dynamic-table/formula/types.js +24 -0
- package/dist/backend/dynamic-table/formula/types.js.map +7 -0
- package/dist/backend/dynamic-table/handlers/cellWrites.js +143 -0
- package/dist/backend/dynamic-table/handlers/cellWrites.js.map +7 -0
- package/dist/backend/dynamic-table/handlers/index.js +504 -0
- package/dist/backend/dynamic-table/handlers/index.js.map +7 -0
- package/dist/backend/dynamic-table/handlers/perspectiveHandlers.js +377 -0
- package/dist/backend/dynamic-table/handlers/perspectiveHandlers.js.map +7 -0
- package/dist/backend/dynamic-table/hooks/index.js +524 -0
- package/dist/backend/dynamic-table/hooks/index.js.map +7 -0
- package/dist/backend/dynamic-table/hooks/useAbbreviations.js +19 -0
- package/dist/backend/dynamic-table/hooks/useAbbreviations.js.map +7 -0
- package/dist/backend/dynamic-table/hooks/useAnnotations.js +115 -0
- package/dist/backend/dynamic-table/hooks/useAnnotations.js.map +7 -0
- package/dist/backend/dynamic-table/hooks/useColumnVirtualizer.js +155 -0
- package/dist/backend/dynamic-table/hooks/useColumnVirtualizer.js.map +7 -0
- package/dist/backend/dynamic-table/hooks/useColumnWidthPersistence.js +135 -0
- package/dist/backend/dynamic-table/hooks/useColumnWidthPersistence.js.map +7 -0
- package/dist/backend/dynamic-table/hooks/useDensityPreference.js +203 -0
- package/dist/backend/dynamic-table/hooks/useDensityPreference.js.map +7 -0
- package/dist/backend/dynamic-table/hooks/useDynamicTablePage.js +1005 -0
- package/dist/backend/dynamic-table/hooks/useDynamicTablePage.js.map +7 -0
- package/dist/backend/dynamic-table/hooks/useEscapeLayer.js +32 -0
- package/dist/backend/dynamic-table/hooks/useEscapeLayer.js.map +7 -0
- package/dist/backend/dynamic-table/hooks/useGrouping.js +256 -0
- package/dist/backend/dynamic-table/hooks/useGrouping.js.map +7 -0
- package/dist/backend/dynamic-table/hooks/useSuggestionFetch.js +63 -0
- package/dist/backend/dynamic-table/hooks/useSuggestionFetch.js.map +7 -0
- package/dist/backend/dynamic-table/hooks/useTableDateFormat.js +11 -0
- package/dist/backend/dynamic-table/hooks/useTableDateFormat.js.map +7 -0
- package/dist/backend/dynamic-table/index.js +476 -0
- package/dist/backend/dynamic-table/index.js.map +7 -0
- package/dist/backend/dynamic-table/registry/ContentRegistryContext.js +126 -0
- package/dist/backend/dynamic-table/registry/ContentRegistryContext.js.map +7 -0
- package/dist/backend/dynamic-table/registry/TableRegistryContext.js +43 -0
- package/dist/backend/dynamic-table/registry/TableRegistryContext.js.map +7 -0
- package/dist/backend/dynamic-table/registry/filterAccessibleTables.js +13 -0
- package/dist/backend/dynamic-table/registry/filterAccessibleTables.js.map +7 -0
- package/dist/backend/dynamic-table/registry/index.js +44 -0
- package/dist/backend/dynamic-table/registry/index.js.map +7 -0
- package/dist/backend/dynamic-table/registry/lazyTable.js +55 -0
- package/dist/backend/dynamic-table/registry/lazyTable.js.map +7 -0
- package/dist/backend/dynamic-table/registry/types.js +1 -0
- package/dist/backend/dynamic-table/registry/types.js.map +7 -0
- package/dist/backend/dynamic-table/registry/widgetCatalog.js +96 -0
- package/dist/backend/dynamic-table/registry/widgetCatalog.js.map +7 -0
- package/dist/backend/dynamic-table/server/aggregate.js +261 -0
- package/dist/backend/dynamic-table/server/aggregate.js.map +7 -0
- package/dist/backend/dynamic-table/server/dateWindows.js +105 -0
- package/dist/backend/dynamic-table/server/dateWindows.js.map +7 -0
- package/dist/backend/dynamic-table/server/filterParser.js +97 -0
- package/dist/backend/dynamic-table/server/filterParser.js.map +7 -0
- package/dist/backend/dynamic-table/server/filterSuggestions.js +70 -0
- package/dist/backend/dynamic-table/server/filterSuggestions.js.map +7 -0
- package/dist/backend/dynamic-table/server/index.js +47 -0
- package/dist/backend/dynamic-table/server/index.js.map +7 -0
- package/dist/backend/dynamic-table/server/makeDynamicTableRoute.js +270 -0
- package/dist/backend/dynamic-table/server/makeDynamicTableRoute.js.map +7 -0
- package/dist/backend/dynamic-table/split-view/ContentPicker.js +171 -0
- package/dist/backend/dynamic-table/split-view/ContentPicker.js.map +7 -0
- package/dist/backend/dynamic-table/split-view/EmptySlot.js +47 -0
- package/dist/backend/dynamic-table/split-view/EmptySlot.js.map +7 -0
- package/dist/backend/dynamic-table/split-view/SplitViewHost.js +863 -0
- package/dist/backend/dynamic-table/split-view/SplitViewHost.js.map +7 -0
- package/dist/backend/dynamic-table/split-view/WidgetPane.js +280 -0
- package/dist/backend/dynamic-table/split-view/WidgetPane.js.map +7 -0
- package/dist/backend/dynamic-table/split-view/WorkspaceFilterBar.js +524 -0
- package/dist/backend/dynamic-table/split-view/WorkspaceFilterBar.js.map +7 -0
- package/dist/backend/dynamic-table/split-view/index.js +61 -0
- package/dist/backend/dynamic-table/split-view/index.js.map +7 -0
- package/dist/backend/dynamic-table/split-view/layoutPersistence.js +91 -0
- package/dist/backend/dynamic-table/split-view/layoutPersistence.js.map +7 -0
- package/dist/backend/dynamic-table/split-view/sharedCriteria.js +62 -0
- package/dist/backend/dynamic-table/split-view/sharedCriteria.js.map +7 -0
- package/dist/backend/dynamic-table/split-view/types.js +426 -0
- package/dist/backend/dynamic-table/split-view/types.js.map +7 -0
- package/dist/backend/dynamic-table/split-view/useSplitViewLayouts.js +79 -0
- package/dist/backend/dynamic-table/split-view/useSplitViewLayouts.js.map +7 -0
- package/dist/backend/dynamic-table/store/index.js +611 -0
- package/dist/backend/dynamic-table/store/index.js.map +7 -0
- package/dist/backend/dynamic-table/styles/ContextMenu.css.js +2 -0
- package/dist/backend/dynamic-table/styles/DynamicTable.css.js +2 -0
- package/dist/backend/dynamic-table/styles/DynamicTable.v2.css.js +2 -0
- package/dist/backend/dynamic-table/styles/SearchBar.css.js +2 -0
- package/dist/backend/dynamic-table/styles/dateCell.css.js +2 -0
- package/dist/backend/dynamic-table/styles/density.css.js +2 -0
- package/dist/backend/dynamic-table/types/density.js +29 -0
- package/dist/backend/dynamic-table/types/density.js.map +7 -0
- package/dist/backend/dynamic-table/types/filters.js +124 -0
- package/dist/backend/dynamic-table/types/filters.js.map +7 -0
- package/dist/backend/dynamic-table/types/grouping.js +34 -0
- package/dist/backend/dynamic-table/types/grouping.js.map +7 -0
- package/dist/backend/dynamic-table/types/import.js +7 -0
- package/dist/backend/dynamic-table/types/import.js.map +7 -0
- package/dist/backend/dynamic-table/types/index.js +46 -0
- package/dist/backend/dynamic-table/types/index.js.map +7 -0
- package/dist/backend/dynamic-table/types/perspective.js +79 -0
- package/dist/backend/dynamic-table/types/perspective.js.map +7 -0
- package/dist/backend/dynamic-table/types/rollup.js +13 -0
- package/dist/backend/dynamic-table/types/rollup.js.map +7 -0
- package/dist/backend/dynamic-table/utils/abbreviations.js +228 -0
- package/dist/backend/dynamic-table/utils/abbreviations.js.map +7 -0
- package/dist/backend/dynamic-table/utils/anchoredPosition.js +21 -0
- package/dist/backend/dynamic-table/utils/anchoredPosition.js.map +7 -0
- package/dist/backend/dynamic-table/utils/badgeAutoFit.js +35 -0
- package/dist/backend/dynamic-table/utils/badgeAutoFit.js.map +7 -0
- package/dist/backend/dynamic-table/utils/clipboard.js +172 -0
- package/dist/backend/dynamic-table/utils/clipboard.js.map +7 -0
- package/dist/backend/dynamic-table/utils/coerceCellValue.js +52 -0
- package/dist/backend/dynamic-table/utils/coerceCellValue.js.map +7 -0
- package/dist/backend/dynamic-table/utils/colorAdjacency.js +27 -0
- package/dist/backend/dynamic-table/utils/colorAdjacency.js.map +7 -0
- package/dist/backend/dynamic-table/utils/columnFill.js +36 -0
- package/dist/backend/dynamic-table/utils/columnFill.js.map +7 -0
- package/dist/backend/dynamic-table/utils/columnSpacerStyle.js +21 -0
- package/dist/backend/dynamic-table/utils/columnSpacerStyle.js.map +7 -0
- package/dist/backend/dynamic-table/utils/columnWindow.js +293 -0
- package/dist/backend/dynamic-table/utils/columnWindow.js.map +7 -0
- package/dist/backend/dynamic-table/utils/conditionalFormat.js +188 -0
- package/dist/backend/dynamic-table/utils/conditionalFormat.js.map +7 -0
- package/dist/backend/dynamic-table/utils/exportTable.js +82 -0
- package/dist/backend/dynamic-table/utils/exportTable.js.map +7 -0
- package/dist/backend/dynamic-table/utils/fillGeometry.js +92 -0
- package/dist/backend/dynamic-table/utils/fillGeometry.js.map +7 -0
- package/dist/backend/dynamic-table/utils/fillPatterns.js +241 -0
- package/dist/backend/dynamic-table/utils/fillPatterns.js.map +7 -0
- package/dist/backend/dynamic-table/utils/formatAggregate.js +82 -0
- package/dist/backend/dynamic-table/utils/formatAggregate.js.map +7 -0
- package/dist/backend/dynamic-table/utils/formatDateCompact.js +508 -0
- package/dist/backend/dynamic-table/utils/formatDateCompact.js.map +7 -0
- package/dist/backend/dynamic-table/utils/formatLabelCompact.js +312 -0
- package/dist/backend/dynamic-table/utils/formatLabelCompact.js.map +7 -0
- package/dist/backend/dynamic-table/utils/formulaColumns.js +158 -0
- package/dist/backend/dynamic-table/utils/formulaColumns.js.map +7 -0
- package/dist/backend/dynamic-table/utils/importMapping.js +118 -0
- package/dist/backend/dynamic-table/utils/importMapping.js.map +7 -0
- package/dist/backend/dynamic-table/utils/importParse.js +121 -0
- package/dist/backend/dynamic-table/utils/importParse.js.map +7 -0
- package/dist/backend/dynamic-table/utils/lookupColumns.js +28 -0
- package/dist/backend/dynamic-table/utils/lookupColumns.js.map +7 -0
- package/dist/backend/dynamic-table/utils/perspectiveTransforms.js +191 -0
- package/dist/backend/dynamic-table/utils/perspectiveTransforms.js.map +7 -0
- package/dist/backend/dynamic-table/utils/rollupColumns.js +81 -0
- package/dist/backend/dynamic-table/utils/rollupColumns.js.map +7 -0
- package/dist/backend/dynamic-table/validators/index.js +36 -0
- package/dist/backend/dynamic-table/validators/index.js.map +7 -0
- package/dist/backend/fields/registry.generated.js +8 -0
- package/dist/backend/fields/registry.generated.js.map +7 -0
- package/dist/backend/fields/registry.js +29 -0
- package/dist/backend/fields/registry.js.map +7 -0
- package/dist/backend/filters/AdvancedFilterBuilder.js +280 -0
- package/dist/backend/filters/AdvancedFilterBuilder.js.map +7 -0
- package/dist/backend/forms/ActionsDropdown.js +160 -0
- package/dist/backend/forms/ActionsDropdown.js.map +7 -0
- package/dist/backend/forms/FormActionButtons.js +59 -0
- package/dist/backend/forms/FormActionButtons.js.map +7 -0
- package/dist/backend/forms/FormFooter.js +18 -0
- package/dist/backend/forms/FormFooter.js.map +7 -0
- package/dist/backend/forms/FormHeader.js +125 -0
- package/dist/backend/forms/FormHeader.js.map +7 -0
- package/dist/backend/forms/index.js +11 -0
- package/dist/backend/forms/index.js.map +7 -0
- package/dist/backend/hooks/useAdvancedFilter.js +64 -0
- package/dist/backend/hooks/useAdvancedFilter.js.map +7 -0
- package/dist/backend/indexes/PartialIndexBanner.js +74 -0
- package/dist/backend/indexes/PartialIndexBanner.js.map +7 -0
- package/dist/backend/indexes/store.js +62 -0
- package/dist/backend/indexes/store.js.map +7 -0
- package/dist/backend/injection/ComponentOverrideProvider.js +55 -0
- package/dist/backend/injection/ComponentOverrideProvider.js.map +7 -0
- package/dist/backend/injection/InjectedField.js +166 -0
- package/dist/backend/injection/InjectedField.js.map +7 -0
- package/dist/backend/injection/InjectionSpot.js +323 -0
- package/dist/backend/injection/InjectionSpot.js.map +7 -0
- package/dist/backend/injection/InjectionWizard.js +256 -0
- package/dist/backend/injection/InjectionWizard.js.map +7 -0
- package/dist/backend/injection/PageInjectionBoundary.js +26 -0
- package/dist/backend/injection/PageInjectionBoundary.js.map +7 -0
- package/dist/backend/injection/SseEventIndicator.js +8 -0
- package/dist/backend/injection/SseEventIndicator.js.map +7 -0
- package/dist/backend/injection/StatusBadgeInjectionSpot.js +34 -0
- package/dist/backend/injection/StatusBadgeInjectionSpot.js.map +7 -0
- package/dist/backend/injection/StatusBadgeRenderer.js +58 -0
- package/dist/backend/injection/StatusBadgeRenderer.js.map +7 -0
- package/dist/backend/injection/WidgetSharedState.js +49 -0
- package/dist/backend/injection/WidgetSharedState.js.map +7 -0
- package/dist/backend/injection/WizardInjectionSpot.js +30 -0
- package/dist/backend/injection/WizardInjectionSpot.js.map +7 -0
- package/dist/backend/injection/eventBridge.js +129 -0
- package/dist/backend/injection/eventBridge.js.map +7 -0
- package/dist/backend/injection/helpers.js +26 -0
- package/dist/backend/injection/helpers.js.map +7 -0
- package/dist/backend/injection/mergeMenuItems.js +49 -0
- package/dist/backend/injection/mergeMenuItems.js.map +7 -0
- package/dist/backend/injection/mutationEvents.js +20 -0
- package/dist/backend/injection/mutationEvents.js.map +7 -0
- package/dist/backend/injection/resolveInjectedIcon.js +23 -0
- package/dist/backend/injection/resolveInjectedIcon.js.map +7 -0
- package/dist/backend/injection/spotIds.js +72 -0
- package/dist/backend/injection/spotIds.js.map +7 -0
- package/dist/backend/injection/useAppEvent.js +35 -0
- package/dist/backend/injection/useAppEvent.js.map +7 -0
- package/dist/backend/injection/useGuardedMutation.js +71 -0
- package/dist/backend/injection/useGuardedMutation.js.map +7 -0
- package/dist/backend/injection/useInjectedMenuItems.js +49 -0
- package/dist/backend/injection/useInjectedMenuItems.js.map +7 -0
- package/dist/backend/injection/useInjectionDataWidgets.js +36 -0
- package/dist/backend/injection/useInjectionDataWidgets.js.map +7 -0
- package/dist/backend/injection/useOperationProgress.js +64 -0
- package/dist/backend/injection/useOperationProgress.js.map +7 -0
- package/dist/backend/injection/useRegisteredComponent.js +89 -0
- package/dist/backend/injection/useRegisteredComponent.js.map +7 -0
- package/dist/backend/injection/useWidgetSharedState.js +26 -0
- package/dist/backend/injection/useWidgetSharedState.js.map +7 -0
- package/dist/backend/injection/visibility-utils.js +29 -0
- package/dist/backend/injection/visibility-utils.js.map +7 -0
- package/dist/backend/injection/widgetRegistry.js +55 -0
- package/dist/backend/injection/widgetRegistry.js.map +7 -0
- package/dist/backend/inputs/ComboboxInput.js +228 -0
- package/dist/backend/inputs/ComboboxInput.js.map +7 -0
- package/dist/backend/inputs/DatePicker.js +148 -0
- package/dist/backend/inputs/DatePicker.js.map +7 -0
- package/dist/backend/inputs/DateTimePicker.js +188 -0
- package/dist/backend/inputs/DateTimePicker.js.map +7 -0
- package/dist/backend/inputs/EventPatternInput.js +38 -0
- package/dist/backend/inputs/EventPatternInput.js.map +7 -0
- package/dist/backend/inputs/EventSelect.js +115 -0
- package/dist/backend/inputs/EventSelect.js.map +7 -0
- package/dist/backend/inputs/LookupSelect.js +197 -0
- package/dist/backend/inputs/LookupSelect.js.map +7 -0
- package/dist/backend/inputs/PhoneNumberField.js +133 -0
- package/dist/backend/inputs/PhoneNumberField.js.map +7 -0
- package/dist/backend/inputs/SwitchableMarkdownInput.js +73 -0
- package/dist/backend/inputs/SwitchableMarkdownInput.js.map +7 -0
- package/dist/backend/inputs/TagsInput.js +258 -0
- package/dist/backend/inputs/TagsInput.js.map +7 -0
- package/dist/backend/inputs/TimeInput.js +132 -0
- package/dist/backend/inputs/TimeInput.js.map +7 -0
- package/dist/backend/inputs/TimePicker.js +105 -0
- package/dist/backend/inputs/TimePicker.js.map +7 -0
- package/dist/backend/inputs/index.js +12 -0
- package/dist/backend/inputs/index.js.map +7 -0
- package/dist/backend/markdown/MarkdownContent.js +20 -0
- package/dist/backend/markdown/MarkdownContent.js.map +7 -0
- package/dist/backend/markdown/index.js +3 -0
- package/dist/backend/markdown/index.js.map +7 -0
- package/dist/backend/markdown/useMarkdownRemarkPlugins.js +33 -0
- package/dist/backend/markdown/useMarkdownRemarkPlugins.js.map +7 -0
- package/dist/backend/messages/MessageComposer.js +158 -0
- package/dist/backend/messages/MessageComposer.js.map +7 -0
- package/dist/backend/messages/MessageObjectDetail.js +81 -0
- package/dist/backend/messages/MessageObjectDetail.js.map +7 -0
- package/dist/backend/messages/MessageObjectPreview.js +48 -0
- package/dist/backend/messages/MessageObjectPreview.js.map +7 -0
- package/dist/backend/messages/MessageObjectRecordPicker.js +89 -0
- package/dist/backend/messages/MessageObjectRecordPicker.js.map +7 -0
- package/dist/backend/messages/MessagePrioritySelector.js +74 -0
- package/dist/backend/messages/MessagePrioritySelector.js.map +7 -0
- package/dist/backend/messages/MessagesIcon.js +22 -0
- package/dist/backend/messages/MessagesIcon.js.map +7 -0
- package/dist/backend/messages/SendObjectMessageDialog.js +65 -0
- package/dist/backend/messages/SendObjectMessageDialog.js.map +7 -0
- package/dist/backend/messages/index.js +17 -0
- package/dist/backend/messages/index.js.map +7 -0
- package/dist/backend/messages/message-compose-form-groups.js +333 -0
- package/dist/backend/messages/message-compose-form-groups.js.map +7 -0
- package/dist/backend/messages/message-composer.types.js +1 -0
- package/dist/backend/messages/message-composer.types.js.map +7 -0
- package/dist/backend/messages/message-priority.js +40 -0
- package/dist/backend/messages/message-priority.js.map +7 -0
- package/dist/backend/messages/useMessageCompose.js +488 -0
- package/dist/backend/messages/useMessageCompose.js.map +7 -0
- package/dist/backend/messages/useMessageComposeOperations.js +163 -0
- package/dist/backend/messages/useMessageComposeOperations.js.map +7 -0
- package/dist/backend/messages/useMessagesPoll.js +79 -0
- package/dist/backend/messages/useMessagesPoll.js.map +7 -0
- package/dist/backend/notifications/NotificationBell.js +83 -0
- package/dist/backend/notifications/NotificationBell.js.map +7 -0
- package/dist/backend/notifications/NotificationCountBadge.js +9 -0
- package/dist/backend/notifications/NotificationCountBadge.js.map +7 -0
- package/dist/backend/notifications/NotificationDispatcher.js +165 -0
- package/dist/backend/notifications/NotificationDispatcher.js.map +7 -0
- package/dist/backend/notifications/NotificationItem.js +187 -0
- package/dist/backend/notifications/NotificationItem.js.map +7 -0
- package/dist/backend/notifications/NotificationPanel.js +146 -0
- package/dist/backend/notifications/NotificationPanel.js.map +7 -0
- package/dist/backend/notifications/index.js +19 -0
- package/dist/backend/notifications/index.js.map +7 -0
- package/dist/backend/notifications/useNotificationActions.js +124 -0
- package/dist/backend/notifications/useNotificationActions.js.map +7 -0
- package/dist/backend/notifications/useNotificationEffect.js +13 -0
- package/dist/backend/notifications/useNotificationEffect.js.map +7 -0
- package/dist/backend/notifications/useNotifications.js +11 -0
- package/dist/backend/notifications/useNotifications.js.map +7 -0
- package/dist/backend/notifications/useNotificationsPoll.js +135 -0
- package/dist/backend/notifications/useNotificationsPoll.js.map +7 -0
- package/dist/backend/notifications/useNotificationsSse.js +173 -0
- package/dist/backend/notifications/useNotificationsSse.js.map +7 -0
- package/dist/backend/operations/LastOperationBanner.js +80 -0
- package/dist/backend/operations/LastOperationBanner.js.map +7 -0
- package/dist/backend/operations/store.js +183 -0
- package/dist/backend/operations/store.js.map +7 -0
- package/dist/backend/progress/ProgressTopBar.js +129 -0
- package/dist/backend/progress/ProgressTopBar.js.map +7 -0
- package/dist/backend/progress/useProgress.js +11 -0
- package/dist/backend/progress/useProgress.js.map +7 -0
- package/dist/backend/progress/useProgressPoll.js +69 -0
- package/dist/backend/progress/useProgressPoll.js.map +7 -0
- package/dist/backend/progress/useProgressSse.js +104 -0
- package/dist/backend/progress/useProgressSse.js.map +7 -0
- package/dist/backend/schedule/ScheduleAgenda.js +107 -0
- package/dist/backend/schedule/ScheduleAgenda.js.map +7 -0
- package/dist/backend/schedule/ScheduleGrid.js +107 -0
- package/dist/backend/schedule/ScheduleGrid.js.map +7 -0
- package/dist/backend/schedule/ScheduleToolbar.js +166 -0
- package/dist/backend/schedule/ScheduleToolbar.js.map +7 -0
- package/dist/backend/schedule/ScheduleView.js +168 -0
- package/dist/backend/schedule/ScheduleView.js.map +7 -0
- package/dist/backend/schedule/index.js +6 -0
- package/dist/backend/schedule/index.js.map +7 -0
- package/dist/backend/schedule/recurrence.js +83 -0
- package/dist/backend/schedule/recurrence.js.map +7 -0
- package/dist/backend/schedule/types.js +1 -0
- package/dist/backend/schedule/types.js.map +7 -0
- package/dist/backend/section-page/SectionNav.js +104 -0
- package/dist/backend/section-page/SectionNav.js.map +7 -0
- package/dist/backend/section-page/SectionPage.js +33 -0
- package/dist/backend/section-page/SectionPage.js.map +7 -0
- package/dist/backend/section-page/index.js +7 -0
- package/dist/backend/section-page/index.js.map +7 -0
- package/dist/backend/section-page/types.js +1 -0
- package/dist/backend/section-page/types.js.map +7 -0
- package/dist/backend/settings/SettingsNavigation.js +43 -0
- package/dist/backend/settings/SettingsNavigation.js.map +7 -0
- package/dist/backend/settings/SettingsPageWrapper.js +66 -0
- package/dist/backend/settings/SettingsPageWrapper.js.map +7 -0
- package/dist/backend/settings/index.js +6 -0
- package/dist/backend/settings/index.js.map +7 -0
- package/dist/backend/upgrades/UpgradeActionBanner.js +91 -0
- package/dist/backend/upgrades/UpgradeActionBanner.js.map +7 -0
- package/dist/backend/utils/api.js +178 -0
- package/dist/backend/utils/api.js.map +7 -0
- package/dist/backend/utils/apiCall.js +68 -0
- package/dist/backend/utils/apiCall.js.map +7 -0
- package/dist/backend/utils/crud.js +126 -0
- package/dist/backend/utils/crud.js.map +7 -0
- package/dist/backend/utils/customFieldColumns.js +100 -0
- package/dist/backend/utils/customFieldColumns.js.map +7 -0
- package/dist/backend/utils/customFieldDefs.js +143 -0
- package/dist/backend/utils/customFieldDefs.js.map +7 -0
- package/dist/backend/utils/customFieldFilters.js +151 -0
- package/dist/backend/utils/customFieldFilters.js.map +7 -0
- package/dist/backend/utils/customFieldForms.js +169 -0
- package/dist/backend/utils/customFieldForms.js.map +7 -0
- package/dist/backend/utils/customFieldRelationDisplay.js +239 -0
- package/dist/backend/utils/customFieldRelationDisplay.js.map +7 -0
- package/dist/backend/utils/customFieldValues.js +26 -0
- package/dist/backend/utils/customFieldValues.js.map +7 -0
- package/dist/backend/utils/flash.js +16 -0
- package/dist/backend/utils/flash.js.map +7 -0
- package/dist/backend/utils/nav.js +280 -0
- package/dist/backend/utils/nav.js.map +7 -0
- package/dist/backend/utils/richTextSanitizer.js +11 -0
- package/dist/backend/utils/richTextSanitizer.js.map +7 -0
- package/dist/backend/utils/scopedHeaderStack.js +44 -0
- package/dist/backend/utils/scopedHeaderStack.js.map +7 -0
- package/dist/backend/utils/serverErrors.js +237 -0
- package/dist/backend/utils/serverErrors.js.map +7 -0
- package/dist/backend/utils/useAutoDiscoveredFields.js +96 -0
- package/dist/backend/utils/useAutoDiscoveredFields.js.map +7 -0
- package/dist/backend/version-history/VersionHistoryAction.js +67 -0
- package/dist/backend/version-history/VersionHistoryAction.js.map +7 -0
- package/dist/backend/version-history/VersionHistoryDetail.js +57 -0
- package/dist/backend/version-history/VersionHistoryDetail.js.map +7 -0
- package/dist/backend/version-history/VersionHistoryPanel.js +270 -0
- package/dist/backend/version-history/VersionHistoryPanel.js.map +7 -0
- package/dist/backend/version-history/index.js +13 -0
- package/dist/backend/version-history/index.js.map +7 -0
- package/dist/backend/version-history/labels.js +52 -0
- package/dist/backend/version-history/labels.js.map +7 -0
- package/dist/backend/version-history/types.js +1 -0
- package/dist/backend/version-history/types.js.map +7 -0
- package/dist/backend/version-history/useAuditPermissions.js +72 -0
- package/dist/backend/version-history/useAuditPermissions.js.map +7 -0
- package/dist/backend/version-history/useVersionHistory.js +141 -0
- package/dist/backend/version-history/useVersionHistory.js.map +7 -0
- package/dist/backend/views/NewViewForm.js +56 -0
- package/dist/backend/views/NewViewForm.js.map +7 -0
- package/dist/backend/views/ShareForm.js +49 -0
- package/dist/backend/views/ShareForm.js.map +7 -0
- package/dist/backend/views/ViewChip.js +112 -0
- package/dist/backend/views/ViewChip.js.map +7 -0
- package/dist/backend/views/ViewChipMenu.js +89 -0
- package/dist/backend/views/ViewChipMenu.js.map +7 -0
- package/dist/backend/views/types.js +1 -0
- package/dist/backend/views/types.js.map +7 -0
- package/dist/frontend/AuthFooter.js +23 -0
- package/dist/frontend/AuthFooter.js.map +7 -0
- package/dist/frontend/LanguageSwitcher.js +57 -0
- package/dist/frontend/LanguageSwitcher.js.map +7 -0
- package/dist/frontend/Layout.js +14 -0
- package/dist/frontend/Layout.js.map +7 -0
- package/dist/hooks/useIsMobile.js +21 -0
- package/dist/hooks/useIsMobile.js.map +7 -0
- package/dist/index.js +40 -0
- package/dist/index.js.map +7 -0
- package/dist/portal/PortalContext.js +113 -0
- package/dist/portal/PortalContext.js.map +7 -0
- package/dist/portal/PortalLayoutProvider.js +5 -0
- package/dist/portal/PortalLayoutProvider.js.map +7 -0
- package/dist/portal/PortalLayoutShell.js +44 -0
- package/dist/portal/PortalLayoutShell.js.map +7 -0
- package/dist/portal/PortalShell.js +229 -0
- package/dist/portal/PortalShell.js.map +7 -0
- package/dist/portal/components/PortalCard.js +31 -0
- package/dist/portal/components/PortalCard.js.map +7 -0
- package/dist/portal/components/PortalEmptyState.js +16 -0
- package/dist/portal/components/PortalEmptyState.js.map +7 -0
- package/dist/portal/components/PortalFeatureCard.js +21 -0
- package/dist/portal/components/PortalFeatureCard.js.map +7 -0
- package/dist/portal/components/PortalNotificationBell.js +67 -0
- package/dist/portal/components/PortalNotificationBell.js.map +7 -0
- package/dist/portal/components/PortalNotificationPanel.js +158 -0
- package/dist/portal/components/PortalNotificationPanel.js.map +7 -0
- package/dist/portal/components/PortalPageHeader.js +16 -0
- package/dist/portal/components/PortalPageHeader.js.map +7 -0
- package/dist/portal/components/index.js +18 -0
- package/dist/portal/components/index.js.map +7 -0
- package/dist/portal/hooks/useCustomerAuth.js +69 -0
- package/dist/portal/hooks/useCustomerAuth.js.map +7 -0
- package/dist/portal/hooks/usePortalAppEvent.js +26 -0
- package/dist/portal/hooks/usePortalAppEvent.js.map +7 -0
- package/dist/portal/hooks/usePortalDashboardWidgets.js +37 -0
- package/dist/portal/hooks/usePortalDashboardWidgets.js.map +7 -0
- package/dist/portal/hooks/usePortalEventBridge.js +129 -0
- package/dist/portal/hooks/usePortalEventBridge.js.map +7 -0
- package/dist/portal/hooks/usePortalInjectedMenuItems.js +88 -0
- package/dist/portal/hooks/usePortalInjectedMenuItems.js.map +7 -0
- package/dist/portal/hooks/usePortalNotifications.js +85 -0
- package/dist/portal/hooks/usePortalNotifications.js.map +7 -0
- package/dist/portal/hooks/useTenantContext.js +53 -0
- package/dist/portal/hooks/useTenantContext.js.map +7 -0
- package/dist/primitives/DataLoader.js +68 -0
- package/dist/primitives/DataLoader.js.map +7 -0
- package/dist/primitives/ErrorNotice.js +14 -0
- package/dist/primitives/ErrorNotice.js.map +7 -0
- package/dist/primitives/Notice.js +55 -0
- package/dist/primitives/Notice.js.map +7 -0
- package/dist/primitives/alert.js +38 -0
- package/dist/primitives/alert.js.map +7 -0
- package/dist/primitives/badge.js +33 -0
- package/dist/primitives/badge.js.map +7 -0
- package/dist/primitives/button.js +45 -0
- package/dist/primitives/button.js.map +7 -0
- package/dist/primitives/calendar.js +62 -0
- package/dist/primitives/calendar.js.map +7 -0
- package/dist/primitives/card.js +91 -0
- package/dist/primitives/card.js.map +7 -0
- package/dist/primitives/checkbox.js +28 -0
- package/dist/primitives/checkbox.js.map +7 -0
- package/dist/primitives/dialog.js +101 -0
- package/dist/primitives/dialog.js.map +7 -0
- package/dist/primitives/form-field.js +78 -0
- package/dist/primitives/form-field.js.map +7 -0
- package/dist/primitives/icon-button.js +40 -0
- package/dist/primitives/icon-button.js.map +7 -0
- package/dist/primitives/input.js +22 -0
- package/dist/primitives/input.js.map +7 -0
- package/dist/primitives/label.js +21 -0
- package/dist/primitives/label.js.map +7 -0
- package/dist/primitives/popover.js +36 -0
- package/dist/primitives/popover.js.map +7 -0
- package/dist/primitives/primitives.stories.js +187 -0
- package/dist/primitives/primitives.stories.js.map +7 -0
- package/dist/primitives/progress.js +28 -0
- package/dist/primitives/progress.js.map +7 -0
- package/dist/primitives/separator.js +9 -0
- package/dist/primitives/separator.js.map +7 -0
- package/dist/primitives/sheet.js +103 -0
- package/dist/primitives/sheet.js.map +7 -0
- package/dist/primitives/spinner.js +24 -0
- package/dist/primitives/spinner.js.map +7 -0
- package/dist/primitives/status-badge.js +38 -0
- package/dist/primitives/status-badge.js.map +7 -0
- package/dist/primitives/switch.js +80 -0
- package/dist/primitives/switch.js.map +7 -0
- package/dist/primitives/table.js +29 -0
- package/dist/primitives/table.js.map +7 -0
- package/dist/primitives/tabs.js +90 -0
- package/dist/primitives/tabs.js.map +7 -0
- package/dist/primitives/textarea.js +21 -0
- package/dist/primitives/textarea.js.map +7 -0
- package/dist/primitives/tooltip.js +60 -0
- package/dist/primitives/tooltip.js.map +7 -0
- package/dist/primitives-v2/Alert.js +69 -0
- package/dist/primitives-v2/Alert.js.map +7 -0
- package/dist/primitives-v2/Alert.stories.js +42 -0
- package/dist/primitives-v2/Alert.stories.js.map +7 -0
- package/dist/primitives-v2/Avatar.js +93 -0
- package/dist/primitives-v2/Avatar.js.map +7 -0
- package/dist/primitives-v2/Avatar.stories.js +57 -0
- package/dist/primitives-v2/Avatar.stories.js.map +7 -0
- package/dist/primitives-v2/Badge.js +50 -0
- package/dist/primitives-v2/Badge.js.map +7 -0
- package/dist/primitives-v2/Badge.stories.js +66 -0
- package/dist/primitives-v2/Badge.stories.js.map +7 -0
- package/dist/primitives-v2/Breadcrumb.js +53 -0
- package/dist/primitives-v2/Breadcrumb.js.map +7 -0
- package/dist/primitives-v2/Breadcrumb.stories.js +70 -0
- package/dist/primitives-v2/Breadcrumb.stories.js.map +7 -0
- package/dist/primitives-v2/Button.js +85 -0
- package/dist/primitives-v2/Button.js.map +7 -0
- package/dist/primitives-v2/Button.stories.js +48 -0
- package/dist/primitives-v2/Button.stories.js.map +7 -0
- package/dist/primitives-v2/Checkbox.js +65 -0
- package/dist/primitives-v2/Checkbox.js.map +7 -0
- package/dist/primitives-v2/Checkbox.stories.js +31 -0
- package/dist/primitives-v2/Checkbox.stories.js.map +7 -0
- package/dist/primitives-v2/IconButton.js +13 -0
- package/dist/primitives-v2/IconButton.js.map +7 -0
- package/dist/primitives-v2/IconButton.stories.js +37 -0
- package/dist/primitives-v2/IconButton.stories.js.map +7 -0
- package/dist/primitives-v2/Input.js +74 -0
- package/dist/primitives-v2/Input.js.map +7 -0
- package/dist/primitives-v2/Input.stories.js +56 -0
- package/dist/primitives-v2/Input.stories.js.map +7 -0
- package/dist/primitives-v2/NavGroup.js +54 -0
- package/dist/primitives-v2/NavGroup.js.map +7 -0
- package/dist/primitives-v2/NavGroup.stories.js +39 -0
- package/dist/primitives-v2/NavGroup.stories.js.map +7 -0
- package/dist/primitives-v2/NavItem.js +61 -0
- package/dist/primitives-v2/NavItem.js.map +7 -0
- package/dist/primitives-v2/NavItem.stories.js +56 -0
- package/dist/primitives-v2/NavItem.stories.js.map +7 -0
- package/dist/primitives-v2/SearchInput.js +93 -0
- package/dist/primitives-v2/SearchInput.js.map +7 -0
- package/dist/primitives-v2/SearchInput.stories.js +41 -0
- package/dist/primitives-v2/SearchInput.stories.js.map +7 -0
- package/dist/primitives-v2/Sidebar.js +48 -0
- package/dist/primitives-v2/Sidebar.js.map +7 -0
- package/dist/primitives-v2/Sidebar.stories.js +76 -0
- package/dist/primitives-v2/Sidebar.stories.js.map +7 -0
- package/dist/primitives-v2/Tab.js +78 -0
- package/dist/primitives-v2/Tab.js.map +7 -0
- package/dist/primitives-v2/Tab.stories.js +51 -0
- package/dist/primitives-v2/Tab.stories.js.map +7 -0
- package/dist/primitives-v2/Tag.js +61 -0
- package/dist/primitives-v2/Tag.js.map +7 -0
- package/dist/primitives-v2/Tag.stories.js +121 -0
- package/dist/primitives-v2/Tag.stories.js.map +7 -0
- package/dist/primitives-v2/Toggle.js +72 -0
- package/dist/primitives-v2/Toggle.js.map +7 -0
- package/dist/primitives-v2/Toggle.stories.js +34 -0
- package/dist/primitives-v2/Toggle.stories.js.map +7 -0
- package/dist/primitives-v2/Topbar.js +24 -0
- package/dist/primitives-v2/Topbar.js.map +7 -0
- package/dist/primitives-v2/Topbar.stories.js +58 -0
- package/dist/primitives-v2/Topbar.stories.js.map +7 -0
- package/dist/primitives-v2/index.js +41 -0
- package/dist/primitives-v2/index.js.map +7 -0
- package/dist/primitives-v2/utils.js +7 -0
- package/dist/primitives-v2/utils.js.map +7 -0
- package/dist/theme/BrandThemeProvider.js +49 -0
- package/dist/theme/BrandThemeProvider.js.map +7 -0
- package/dist/theme/QueryProvider.js +44 -0
- package/dist/theme/QueryProvider.js.map +7 -0
- package/dist/theme/ThemeProvider.js +96 -0
- package/dist/theme/ThemeProvider.js.map +7 -0
- package/dist/theme/ThemeToggle.js +88 -0
- package/dist/theme/ThemeToggle.js.map +7 -0
- package/dist/theme/index.js +12 -0
- package/dist/theme/index.js.map +7 -0
- package/dist/theme/m3.css.js +2 -0
- package/dist/theme/tokens.v2.css.js +2 -0
- package/dist/theme/typography.css.js +2 -0
- package/dist/theme/typography.stories.js +123 -0
- package/dist/theme/typography.stories.js.map +7 -0
- package/dist/theme/typography.tokens.js +281 -0
- package/dist/theme/typography.tokens.js.map +7 -0
- package/dist/types/react-big-calendar.d.js +1 -0
- package/dist/types/react-big-calendar.d.js.map +7 -0
- package/package.json +411 -0
- package/src/backend/AppShell.tsx +1606 -0
- package/src/backend/BackendChromeProvider.tsx +99 -0
- package/src/backend/BackendPageSurface.tsx +57 -0
- package/src/backend/CollapsibleNavSection.tsx +201 -0
- package/src/backend/ContextHelp.tsx +40 -0
- package/src/backend/CrudForm.tsx +3796 -0
- package/src/backend/DataTable.tsx +2584 -0
- package/src/backend/EmptyState.tsx +65 -0
- package/src/backend/FilterBar.tsx +171 -0
- package/src/backend/FilterOverlay.tsx +388 -0
- package/src/backend/FlashMessages.tsx +189 -0
- package/src/backend/HtmlRichTextEditor.tsx +124 -0
- package/src/backend/IntegrationsButton.tsx +29 -0
- package/src/backend/JsonBuilder.tsx +359 -0
- package/src/backend/JsonDisplay.tsx +258 -0
- package/src/backend/NextStepCallout.tsx +134 -0
- package/src/backend/Page.tsx +30 -0
- package/src/backend/PerspectiveSidebar.tsx +506 -0
- package/src/backend/ProfileDropdown.tsx +369 -0
- package/src/backend/RowActions.tsx +158 -0
- package/src/backend/SectionHeader.tsx +119 -0
- package/src/backend/SettingsButton.tsx +28 -0
- package/src/backend/Sidebar.stories.tsx +183 -0
- package/src/backend/Sidebar.tsx +737 -0
- package/src/backend/TruncatedCell.tsx +133 -0
- package/src/backend/UserMenu.tsx +153 -0
- package/src/backend/ValueIcons.tsx +48 -0
- package/src/backend/WebhookSetupGuide.tsx +127 -0
- package/src/backend/__tests__/AppShell.test.tsx +392 -0
- package/src/backend/__tests__/CrudForm.custom-fields.test.tsx +180 -0
- package/src/backend/__tests__/CrudForm.datetime.test.tsx +95 -0
- package/src/backend/__tests__/CrudForm.defaults.test.tsx +195 -0
- package/src/backend/__tests__/CrudForm.navigation.test.tsx +156 -0
- package/src/backend/__tests__/CrudForm.render.test.tsx +146 -0
- package/src/backend/__tests__/CrudForm.transformData.test.tsx +231 -0
- package/src/backend/__tests__/CrudForm.unsavedNavigation.test.tsx +145 -0
- package/src/backend/__tests__/CrudForm.validation.test.tsx +178 -0
- package/src/backend/__tests__/CustomDataSection.test.tsx +465 -0
- package/src/backend/__tests__/DataTable.extensions.test.tsx +339 -0
- package/src/backend/__tests__/DataTable.namespaces.test.ts +32 -0
- package/src/backend/__tests__/DataTable.render.test.tsx +48 -0
- package/src/backend/__tests__/FieldDefinitionsEditor.test.tsx +64 -0
- package/src/backend/__tests__/FlashMessages.test.tsx +105 -0
- package/src/backend/__tests__/FormHeader.test.tsx +81 -0
- package/src/backend/__tests__/NotificationDispatcher.test.ts +172 -0
- package/src/backend/__tests__/VersionHistoryPanel.test.tsx +109 -0
- package/src/backend/__tests__/component-replacement.test.tsx +270 -0
- package/src/backend/__tests__/custom-field-filters.test.ts +72 -0
- package/src/backend/__tests__/custom-field-forms.test.ts +54 -0
- package/src/backend/__tests__/nav-utils.test.ts +175 -0
- package/src/backend/__tests__/serverErrors.test.ts +83 -0
- package/src/backend/__tests__/useAuditPermissions.test.tsx +51 -0
- package/src/backend/__tests__/useNotifications.strategy.test.ts +58 -0
- package/src/backend/__tests__/useProgress.strategy.test.ts +62 -0
- package/src/backend/charts/BarChart.tsx +208 -0
- package/src/backend/charts/ChartUtils.tsx +196 -0
- package/src/backend/charts/ComboChart.stories.tsx +103 -0
- package/src/backend/charts/ComboChart.tsx +350 -0
- package/src/backend/charts/KpiCard.tsx +155 -0
- package/src/backend/charts/LineChart.tsx +207 -0
- package/src/backend/charts/PieChart.tsx +157 -0
- package/src/backend/charts/ScatterChart.tsx +498 -0
- package/src/backend/charts/TopNTable.tsx +141 -0
- package/src/backend/charts/WaterfallChart.tsx +213 -0
- package/src/backend/charts/index.ts +21 -0
- package/src/backend/columns/ColumnChooserPanel.tsx +293 -0
- package/src/backend/confirm-dialog/ConfirmDialog.tsx +275 -0
- package/src/backend/confirm-dialog/index.ts +7 -0
- package/src/backend/confirm-dialog/useConfirmDialog.tsx +146 -0
- package/src/backend/custom-fields/FieldDefinitionsEditor.tsx +1413 -0
- package/src/backend/custom-fields/FieldDefinitionsManager.tsx +381 -0
- package/src/backend/dashboard/DashboardScreen.tsx +706 -0
- package/src/backend/dashboard/__tests__/DashboardScreen.test.tsx +114 -0
- package/src/backend/dashboard/index.ts +1 -0
- package/src/backend/dashboard/widgetRegistry.ts +68 -0
- package/src/backend/date-range/DateRangeSelect.tsx +50 -0
- package/src/backend/date-range/InlineDateRangeSelect.tsx +52 -0
- package/src/backend/date-range/InlineGranularitySelect.tsx +63 -0
- package/src/backend/date-range/__tests__/dateRanges.test.ts +224 -0
- package/src/backend/date-range/dateRanges.ts +218 -0
- package/src/backend/date-range/index.ts +15 -0
- package/src/backend/detail/AccessDeniedMessage.tsx +32 -0
- package/src/backend/detail/ActivitiesSection.tsx +1261 -0
- package/src/backend/detail/AddressEditor.tsx +479 -0
- package/src/backend/detail/AddressTiles.tsx +591 -0
- package/src/backend/detail/AddressesSection.tsx +362 -0
- package/src/backend/detail/AttachmentDeleteDialog.tsx +56 -0
- package/src/backend/detail/AttachmentMetadataDialog.tsx +674 -0
- package/src/backend/detail/AttachmentVisualPreview.tsx +155 -0
- package/src/backend/detail/AttachmentsSection.tsx +327 -0
- package/src/backend/detail/CustomDataSection.tsx +700 -0
- package/src/backend/detail/DetailFieldsSection.tsx +163 -0
- package/src/backend/detail/ErrorMessage.tsx +32 -0
- package/src/backend/detail/InlineEditors.tsx +894 -0
- package/src/backend/detail/LoadingMessage.tsx +14 -0
- package/src/backend/detail/NotesSection.tsx +1266 -0
- package/src/backend/detail/TabEmptyState.tsx +48 -0
- package/src/backend/detail/TagsSection.tsx +470 -0
- package/src/backend/detail/__tests__/InlineEditors.test.tsx +59 -0
- package/src/backend/detail/addressFormat.tsx +121 -0
- package/src/backend/detail/index.ts +46 -0
- package/src/backend/devtools/UmesDevToolsPanel.tsx +122 -0
- package/src/backend/devtools/components/ConflictWarnings.tsx +36 -0
- package/src/backend/devtools/components/EnricherTiming.tsx +50 -0
- package/src/backend/devtools/components/EventFlow.tsx +45 -0
- package/src/backend/devtools/components/ExtensionPointList.tsx +59 -0
- package/src/backend/devtools/components/InterceptorActivity.tsx +48 -0
- package/src/backend/devtools/index.ts +2 -0
- package/src/backend/devtools/useUmesDevTools.ts +188 -0
- package/src/backend/document-viewer/RegionOverlay.tsx +150 -0
- package/src/backend/document-viewer/index.ts +2 -0
- package/src/backend/dynamic-grid/DynamicGrid.tsx +161 -0
- package/src/backend/dynamic-grid/adapters.ts +57 -0
- package/src/backend/dynamic-grid/components/GridCell.tsx +194 -0
- package/src/backend/dynamic-grid/components/GridRow.tsx +40 -0
- package/src/backend/dynamic-grid/hooks/useGridKeyboardNav.ts +134 -0
- package/src/backend/dynamic-grid/index.ts +4 -0
- package/src/backend/dynamic-grid/types.ts +55 -0
- package/src/backend/dynamic-table/DynamicTable.stories.tsx +274 -0
- package/src/backend/dynamic-table/DynamicTable.tsx +4419 -0
- package/src/backend/dynamic-table/README.md +1199 -0
- package/src/backend/dynamic-table/URL_FILTERING.md +217 -0
- package/src/backend/dynamic-table/__e2e__/GridHarness.ts +1155 -0
- package/src/backend/dynamic-table/__e2e__/SplitViewHarness.ts +366 -0
- package/src/backend/dynamic-table/__tests__/BulkActionsBar.test.tsx +143 -0
- package/src/backend/dynamic-table/__tests__/ColumnQuickFilter.test.tsx +607 -0
- package/src/backend/dynamic-table/__tests__/ConfigureViewFilters.suggestions.test.tsx +177 -0
- package/src/backend/dynamic-table/__tests__/ConfigureViewFormatting.test.tsx +125 -0
- package/src/backend/dynamic-table/__tests__/ConfigureViewFormulas.test.tsx +228 -0
- package/src/backend/dynamic-table/__tests__/ConfigureViewGrouping.aggregations.test.tsx +131 -0
- package/src/backend/dynamic-table/__tests__/ConfigureViewPanel.baseView.test.tsx +162 -0
- package/src/backend/dynamic-table/__tests__/ConfigureViewPanel.focus.test.tsx +54 -0
- package/src/backend/dynamic-table/__tests__/ConfigureViewPanel.sections.test.tsx +142 -0
- package/src/backend/dynamic-table/__tests__/ConfigureViewRollups.test.tsx +228 -0
- package/src/backend/dynamic-table/__tests__/ContextMenu.test.tsx +89 -0
- package/src/backend/dynamic-table/__tests__/DynamicTable.density.test.tsx +299 -0
- package/src/backend/dynamic-table/__tests__/DynamicTable.exportTruncation.test.tsx +145 -0
- package/src/backend/dynamic-table/__tests__/DynamicTable.loadError.test.tsx +173 -0
- package/src/backend/dynamic-table/__tests__/DynamicTable.wiring.test.tsx +357 -0
- package/src/backend/dynamic-table/__tests__/EmptyState.test.tsx +70 -0
- package/src/backend/dynamic-table/__tests__/ExportMenu.test.tsx +82 -0
- package/src/backend/dynamic-table/__tests__/FooterTotalsRow.test.tsx +154 -0
- package/src/backend/dynamic-table/__tests__/GroupSummaryRow.render.test.tsx +131 -0
- package/src/backend/dynamic-table/__tests__/LoadErrorState.test.tsx +74 -0
- package/src/backend/dynamic-table/__tests__/MentionPopup.search.test.tsx +127 -0
- package/src/backend/dynamic-table/__tests__/PerspectiveTabs.test.tsx +170 -0
- package/src/backend/dynamic-table/__tests__/RowHeaderCell.selection.test.tsx +80 -0
- package/src/backend/dynamic-table/__tests__/abbreviationsSubscription.test.ts +171 -0
- package/src/backend/dynamic-table/__tests__/aggregate.spec.test.ts +224 -0
- package/src/backend/dynamic-table/__tests__/aggregateDimension.test.tsx +191 -0
- package/src/backend/dynamic-table/__tests__/anchoredPosition.test.ts +88 -0
- package/src/backend/dynamic-table/__tests__/badgeAutoFit.test.ts +121 -0
- package/src/backend/dynamic-table/__tests__/cellHandlers.save.test.ts +282 -0
- package/src/backend/dynamic-table/__tests__/cellWrites.test.ts +274 -0
- package/src/backend/dynamic-table/__tests__/clipboard.test.ts +230 -0
- package/src/backend/dynamic-table/__tests__/coerceCellValue.test.ts +117 -0
- package/src/backend/dynamic-table/__tests__/colorAdjacency.test.ts +151 -0
- package/src/backend/dynamic-table/__tests__/columnFill.test.ts +66 -0
- package/src/backend/dynamic-table/__tests__/columnHeaderHandlers.sort.test.ts +100 -0
- package/src/backend/dynamic-table/__tests__/columnHeaderReorder.test.tsx +209 -0
- package/src/backend/dynamic-table/__tests__/columnReorderPersistence.test.tsx +127 -0
- package/src/backend/dynamic-table/__tests__/columnVirtualization.render.test.tsx +420 -0
- package/src/backend/dynamic-table/__tests__/columnVisibilityPersistence.test.tsx +136 -0
- package/src/backend/dynamic-table/__tests__/columnWindow.test.ts +643 -0
- package/src/backend/dynamic-table/__tests__/commentAudience.test.tsx +137 -0
- package/src/backend/dynamic-table/__tests__/commentScope.test.tsx +214 -0
- package/src/backend/dynamic-table/__tests__/conditionalFormat.test.ts +175 -0
- package/src/backend/dynamic-table/__tests__/contentRegistry.test.ts +267 -0
- package/src/backend/dynamic-table/__tests__/dateWindows.test.ts +149 -0
- package/src/backend/dynamic-table/__tests__/density.test.ts +204 -0
- package/src/backend/dynamic-table/__tests__/exportTable.test.ts +146 -0
- package/src/backend/dynamic-table/__tests__/fillGeometry.test.ts +201 -0
- package/src/backend/dynamic-table/__tests__/fillPatterns.test.ts +272 -0
- package/src/backend/dynamic-table/__tests__/filterParser.presets.test.ts +64 -0
- package/src/backend/dynamic-table/__tests__/filterParser.relative.test.ts +109 -0
- package/src/backend/dynamic-table/__tests__/filterSuggestions.test.ts +152 -0
- package/src/backend/dynamic-table/__tests__/formatAggregate.test.ts +99 -0
- package/src/backend/dynamic-table/__tests__/formatDateCompact.test.ts +489 -0
- package/src/backend/dynamic-table/__tests__/formatLabelCompact.test.ts +717 -0
- package/src/backend/dynamic-table/__tests__/formula.check.test.ts +257 -0
- package/src/backend/dynamic-table/__tests__/formula.evaluate.test.ts +274 -0
- package/src/backend/dynamic-table/__tests__/formula.functions.test.ts +226 -0
- package/src/backend/dynamic-table/__tests__/formula.noEval.test.ts +92 -0
- package/src/backend/dynamic-table/__tests__/formula.parse.test.ts +233 -0
- package/src/backend/dynamic-table/__tests__/formulaColumns.test.tsx +213 -0
- package/src/backend/dynamic-table/__tests__/handlerIdentity.test.ts +77 -0
- package/src/backend/dynamic-table/__tests__/importMapping.test.ts +174 -0
- package/src/backend/dynamic-table/__tests__/importParse.test.ts +130 -0
- package/src/backend/dynamic-table/__tests__/importServerOnly.test.ts +37 -0
- package/src/backend/dynamic-table/__tests__/layoutPersistence.test.ts +372 -0
- package/src/backend/dynamic-table/__tests__/mouseHandlers.doubleClick.test.ts +155 -0
- package/src/backend/dynamic-table/__tests__/perspectivePersonalization.test.ts +188 -0
- package/src/backend/dynamic-table/__tests__/perspectiveResolver.test.ts +133 -0
- package/src/backend/dynamic-table/__tests__/perspectiveState.defaultGrouping.test.ts +306 -0
- package/src/backend/dynamic-table/__tests__/perspectiveState.defaults.test.ts +107 -0
- package/src/backend/dynamic-table/__tests__/perspectiveTemplates.test.tsx +269 -0
- package/src/backend/dynamic-table/__tests__/perspectiveTransforms.aggregations.test.ts +105 -0
- package/src/backend/dynamic-table/__tests__/perspectiveTransforms.conditionalFormats.test.ts +107 -0
- package/src/backend/dynamic-table/__tests__/perspectiveTransforms.dateFormat.test.ts +61 -0
- package/src/backend/dynamic-table/__tests__/perspectiveTransforms.formulas.test.ts +85 -0
- package/src/backend/dynamic-table/__tests__/perspectiveTransforms.frozenColumns.test.ts +124 -0
- package/src/backend/dynamic-table/__tests__/rollupColumns.test.ts +149 -0
- package/src/backend/dynamic-table/__tests__/sharedCriteria.test.ts +255 -0
- package/src/backend/dynamic-table/__tests__/splitViewTree.test.ts +324 -0
- package/src/backend/dynamic-table/__tests__/store.clipboardMarker.test.ts +143 -0
- package/src/backend/dynamic-table/__tests__/store.fillPreview.test.ts +168 -0
- package/src/backend/dynamic-table/__tests__/store.mutations.test.ts +345 -0
- package/src/backend/dynamic-table/__tests__/store.selection.test.ts +157 -0
- package/src/backend/dynamic-table/__tests__/store.undo.test.ts +225 -0
- package/src/backend/dynamic-table/__tests__/store.valueSource.test.tsx +204 -0
- package/src/backend/dynamic-table/__tests__/useAnnotations.legacyOptions.test.tsx +58 -0
- package/src/backend/dynamic-table/__tests__/useColumnVirtualizer.test.ts +290 -0
- package/src/backend/dynamic-table/__tests__/useDensityPreference.test.ts +435 -0
- package/src/backend/dynamic-table/__tests__/useDynamicTablePage.duplicate.test.tsx +99 -0
- package/src/backend/dynamic-table/__tests__/useDynamicTablePage.export.test.tsx +281 -0
- package/src/backend/dynamic-table/__tests__/useDynamicTablePage.personalization.test.tsx +313 -0
- package/src/backend/dynamic-table/__tests__/useDynamicTablePage.perspectiveRestore.test.tsx +126 -0
- package/src/backend/dynamic-table/__tests__/useGrouping.aggregations.test.ts +158 -0
- package/src/backend/dynamic-table/__tests__/useGrouping.groupKey.test.ts +58 -0
- package/src/backend/dynamic-table/__tests__/useKeyboardNavigation.test.ts +594 -0
- package/src/backend/dynamic-table/__tests__/useStickyOffsets.memo.test.tsx +75 -0
- package/src/backend/dynamic-table/__tests__/useStickyOffsets.test.ts +106 -0
- package/src/backend/dynamic-table/__tests__/widgetPane.test.tsx +338 -0
- package/src/backend/dynamic-table/components/ActiveFilterChips.tsx +109 -0
- package/src/backend/dynamic-table/components/BulkActionsBar.tsx +89 -0
- package/src/backend/dynamic-table/components/Cell.tsx +292 -0
- package/src/backend/dynamic-table/components/CellCommentDialog.tsx +887 -0
- package/src/backend/dynamic-table/components/CellCommentHoverPopup.tsx +94 -0
- package/src/backend/dynamic-table/components/ColumnFilterPopover.tsx +775 -0
- package/src/backend/dynamic-table/components/ColumnHeaderMenu.tsx +189 -0
- package/src/backend/dynamic-table/components/ColumnHeaders.tsx +867 -0
- package/src/backend/dynamic-table/components/CompactLabelCell.tsx +293 -0
- package/src/backend/dynamic-table/components/ConfigureViewFields.tsx +173 -0
- package/src/backend/dynamic-table/components/ConfigureViewFilters.tsx +346 -0
- package/src/backend/dynamic-table/components/ConfigureViewFormatting.tsx +205 -0
- package/src/backend/dynamic-table/components/ConfigureViewFormulas.tsx +423 -0
- package/src/backend/dynamic-table/components/ConfigureViewGrouping.tsx +264 -0
- package/src/backend/dynamic-table/components/ConfigureViewLinkedColumns.tsx +249 -0
- package/src/backend/dynamic-table/components/ConfigureViewPanel.tsx +857 -0
- package/src/backend/dynamic-table/components/ConfigureViewRollups.tsx +364 -0
- package/src/backend/dynamic-table/components/ConfigureViewSorting.tsx +121 -0
- package/src/backend/dynamic-table/components/ContextMenu.tsx +140 -0
- package/src/backend/dynamic-table/components/DateCell.tsx +205 -0
- package/src/backend/dynamic-table/components/Debugger.tsx +340 -0
- package/src/backend/dynamic-table/components/DensityControl.tsx +441 -0
- package/src/backend/dynamic-table/components/EmptyState.tsx +103 -0
- package/src/backend/dynamic-table/components/EntitySearchEditor.tsx +528 -0
- package/src/backend/dynamic-table/components/ExportMenu.tsx +90 -0
- package/src/backend/dynamic-table/components/FilterDatePicker.tsx +194 -0
- package/src/backend/dynamic-table/components/FilterValueInput.tsx +294 -0
- package/src/backend/dynamic-table/components/FooterTotalsRow.tsx +291 -0
- package/src/backend/dynamic-table/components/FullscreenOverlay.tsx +66 -0
- package/src/backend/dynamic-table/components/GroupHeaderRow.tsx +136 -0
- package/src/backend/dynamic-table/components/GroupSummaryRow.tsx +184 -0
- package/src/backend/dynamic-table/components/ImportPanel.tsx +445 -0
- package/src/backend/dynamic-table/components/ImportPreviewGrid.tsx +155 -0
- package/src/backend/dynamic-table/components/LoadErrorState.tsx +70 -0
- package/src/backend/dynamic-table/components/MentionPopup.tsx +224 -0
- package/src/backend/dynamic-table/components/PerspectiveDeleteDialog.tsx +96 -0
- package/src/backend/dynamic-table/components/PerspectivePublishDialog.tsx +152 -0
- package/src/backend/dynamic-table/components/PerspectiveTabMenu.tsx +215 -0
- package/src/backend/dynamic-table/components/PerspectiveTabs.tsx +426 -0
- package/src/backend/dynamic-table/components/PerspectiveTemplateMenu.tsx +135 -0
- package/src/backend/dynamic-table/components/RowHeaderCell.tsx +73 -0
- package/src/backend/dynamic-table/components/SearchBar.tsx +309 -0
- package/src/backend/dynamic-table/components/SelectMenu.tsx +237 -0
- package/src/backend/dynamic-table/components/StaleDataBar.tsx +74 -0
- package/src/backend/dynamic-table/components/TableDeleteDialog.tsx +74 -0
- package/src/backend/dynamic-table/components/TablePagination.tsx +96 -0
- package/src/backend/dynamic-table/components/TableSkeleton.tsx +123 -0
- package/src/backend/dynamic-table/components/ToolbarOverflow.tsx +284 -0
- package/src/backend/dynamic-table/components/ViewModeSwitch.tsx +92 -0
- package/src/backend/dynamic-table/components/VirtualRow.tsx +346 -0
- package/src/backend/dynamic-table/components/editors.tsx +1727 -0
- package/src/backend/dynamic-table/components/renderers.tsx +162 -0
- package/src/backend/dynamic-table/events/events.ts +107 -0
- package/src/backend/dynamic-table/formula/check.ts +359 -0
- package/src/backend/dynamic-table/formula/evaluate.ts +473 -0
- package/src/backend/dynamic-table/formula/functions.ts +737 -0
- package/src/backend/dynamic-table/formula/index.ts +57 -0
- package/src/backend/dynamic-table/formula/parse.ts +414 -0
- package/src/backend/dynamic-table/formula/types.ts +151 -0
- package/src/backend/dynamic-table/handlers/cellWrites.ts +362 -0
- package/src/backend/dynamic-table/handlers/index.ts +789 -0
- package/src/backend/dynamic-table/handlers/perspectiveHandlers.ts +684 -0
- package/src/backend/dynamic-table/hooks/index.ts +888 -0
- package/src/backend/dynamic-table/hooks/useAbbreviations.ts +67 -0
- package/src/backend/dynamic-table/hooks/useAnnotations.ts +215 -0
- package/src/backend/dynamic-table/hooks/useColumnVirtualizer.ts +303 -0
- package/src/backend/dynamic-table/hooks/useColumnWidthPersistence.ts +214 -0
- package/src/backend/dynamic-table/hooks/useDensityPreference.ts +451 -0
- package/src/backend/dynamic-table/hooks/useDynamicTablePage.tsx +1681 -0
- package/src/backend/dynamic-table/hooks/useEscapeLayer.ts +72 -0
- package/src/backend/dynamic-table/hooks/useGrouping.ts +428 -0
- package/src/backend/dynamic-table/hooks/useSuggestionFetch.ts +109 -0
- package/src/backend/dynamic-table/hooks/useTableDateFormat.tsx +19 -0
- package/src/backend/dynamic-table/index.ts +497 -0
- package/src/backend/dynamic-table/registry/ContentRegistryContext.tsx +244 -0
- package/src/backend/dynamic-table/registry/TableRegistryContext.tsx +84 -0
- package/src/backend/dynamic-table/registry/filterAccessibleTables.ts +36 -0
- package/src/backend/dynamic-table/registry/index.ts +38 -0
- package/src/backend/dynamic-table/registry/lazyTable.tsx +80 -0
- package/src/backend/dynamic-table/registry/types.ts +181 -0
- package/src/backend/dynamic-table/registry/widgetCatalog.ts +226 -0
- package/src/backend/dynamic-table/server/aggregate.ts +474 -0
- package/src/backend/dynamic-table/server/dateWindows.ts +201 -0
- package/src/backend/dynamic-table/server/filterParser.ts +132 -0
- package/src/backend/dynamic-table/server/filterSuggestions.ts +150 -0
- package/src/backend/dynamic-table/server/index.ts +47 -0
- package/src/backend/dynamic-table/server/makeDynamicTableRoute.ts +426 -0
- package/src/backend/dynamic-table/split-view/ContentPicker.tsx +251 -0
- package/src/backend/dynamic-table/split-view/EmptySlot.tsx +69 -0
- package/src/backend/dynamic-table/split-view/SplitViewHost.tsx +1336 -0
- package/src/backend/dynamic-table/split-view/WidgetPane.tsx +390 -0
- package/src/backend/dynamic-table/split-view/WorkspaceFilterBar.tsx +728 -0
- package/src/backend/dynamic-table/split-view/index.ts +48 -0
- package/src/backend/dynamic-table/split-view/layoutPersistence.ts +185 -0
- package/src/backend/dynamic-table/split-view/sharedCriteria.ts +196 -0
- package/src/backend/dynamic-table/split-view/types.ts +778 -0
- package/src/backend/dynamic-table/split-view/useSplitViewLayouts.ts +97 -0
- package/src/backend/dynamic-table/store/index.ts +1011 -0
- package/src/backend/dynamic-table/styles/ContextMenu.css +387 -0
- package/src/backend/dynamic-table/styles/DynamicTable.css +3659 -0
- package/src/backend/dynamic-table/styles/DynamicTable.v2.css +2651 -0
- package/src/backend/dynamic-table/styles/SearchBar.css +426 -0
- package/src/backend/dynamic-table/styles/dateCell.css +146 -0
- package/src/backend/dynamic-table/styles/density.css +690 -0
- package/src/backend/dynamic-table/types/density.ts +179 -0
- package/src/backend/dynamic-table/types/filters.ts +156 -0
- package/src/backend/dynamic-table/types/grouping.ts +189 -0
- package/src/backend/dynamic-table/types/import.ts +132 -0
- package/src/backend/dynamic-table/types/index.ts +1198 -0
- package/src/backend/dynamic-table/types/perspective.ts +436 -0
- package/src/backend/dynamic-table/types/rollup.ts +111 -0
- package/src/backend/dynamic-table/utils/abbreviations.ts +556 -0
- package/src/backend/dynamic-table/utils/anchoredPosition.ts +106 -0
- package/src/backend/dynamic-table/utils/badgeAutoFit.ts +108 -0
- package/src/backend/dynamic-table/utils/clipboard.ts +294 -0
- package/src/backend/dynamic-table/utils/coerceCellValue.ts +96 -0
- package/src/backend/dynamic-table/utils/colorAdjacency.ts +87 -0
- package/src/backend/dynamic-table/utils/columnFill.ts +93 -0
- package/src/backend/dynamic-table/utils/columnSpacerStyle.ts +53 -0
- package/src/backend/dynamic-table/utils/columnWindow.ts +668 -0
- package/src/backend/dynamic-table/utils/conditionalFormat.ts +300 -0
- package/src/backend/dynamic-table/utils/exportTable.ts +140 -0
- package/src/backend/dynamic-table/utils/fillGeometry.ts +187 -0
- package/src/backend/dynamic-table/utils/fillPatterns.ts +422 -0
- package/src/backend/dynamic-table/utils/formatAggregate.ts +145 -0
- package/src/backend/dynamic-table/utils/formatDateCompact.ts +879 -0
- package/src/backend/dynamic-table/utils/formatLabelCompact.ts +640 -0
- package/src/backend/dynamic-table/utils/formulaColumns.tsx +237 -0
- package/src/backend/dynamic-table/utils/importMapping.ts +202 -0
- package/src/backend/dynamic-table/utils/importParse.ts +220 -0
- package/src/backend/dynamic-table/utils/lookupColumns.tsx +47 -0
- package/src/backend/dynamic-table/utils/perspectiveTransforms.ts +368 -0
- package/src/backend/dynamic-table/utils/rollupColumns.ts +162 -0
- package/src/backend/dynamic-table/validators/index.ts +40 -0
- package/src/backend/fields/registry.generated.ts +8 -0
- package/src/backend/fields/registry.ts +38 -0
- package/src/backend/filters/AdvancedFilterBuilder.tsx +339 -0
- package/src/backend/forms/ActionsDropdown.tsx +198 -0
- package/src/backend/forms/FormActionButtons.tsx +98 -0
- package/src/backend/forms/FormFooter.tsx +27 -0
- package/src/backend/forms/FormHeader.tsx +204 -0
- package/src/backend/forms/index.ts +4 -0
- package/src/backend/hooks/useAdvancedFilter.ts +77 -0
- package/src/backend/indexes/PartialIndexBanner.tsx +86 -0
- package/src/backend/indexes/store.ts +88 -0
- package/src/backend/injection/ComponentOverrideProvider.tsx +66 -0
- package/src/backend/injection/InjectedField.tsx +196 -0
- package/src/backend/injection/InjectionSpot.tsx +457 -0
- package/src/backend/injection/InjectionWizard.tsx +335 -0
- package/src/backend/injection/PageInjectionBoundary.tsx +31 -0
- package/src/backend/injection/SseEventIndicator.tsx +11 -0
- package/src/backend/injection/StatusBadgeInjectionSpot.tsx +50 -0
- package/src/backend/injection/StatusBadgeRenderer.tsx +100 -0
- package/src/backend/injection/WidgetSharedState.ts +58 -0
- package/src/backend/injection/WizardInjectionSpot.tsx +46 -0
- package/src/backend/injection/eventBridge.ts +158 -0
- package/src/backend/injection/helpers.ts +35 -0
- package/src/backend/injection/mergeMenuItems.ts +80 -0
- package/src/backend/injection/mutationEvents.ts +22 -0
- package/src/backend/injection/resolveInjectedIcon.tsx +30 -0
- package/src/backend/injection/spotIds.ts +64 -0
- package/src/backend/injection/useAppEvent.ts +76 -0
- package/src/backend/injection/useGuardedMutation.ts +101 -0
- package/src/backend/injection/useInjectedMenuItems.ts +67 -0
- package/src/backend/injection/useInjectionDataWidgets.ts +41 -0
- package/src/backend/injection/useOperationProgress.ts +105 -0
- package/src/backend/injection/useRegisteredComponent.tsx +106 -0
- package/src/backend/injection/useWidgetSharedState.ts +28 -0
- package/src/backend/injection/visibility-utils.ts +31 -0
- package/src/backend/injection/widgetRegistry.ts +68 -0
- package/src/backend/inputs/ComboboxInput.tsx +272 -0
- package/src/backend/inputs/DatePicker.tsx +162 -0
- package/src/backend/inputs/DateTimePicker.tsx +199 -0
- package/src/backend/inputs/EventPatternInput.tsx +46 -0
- package/src/backend/inputs/EventSelect.tsx +183 -0
- package/src/backend/inputs/LookupSelect.tsx +253 -0
- package/src/backend/inputs/PhoneNumberField.tsx +166 -0
- package/src/backend/inputs/SwitchableMarkdownInput.tsx +106 -0
- package/src/backend/inputs/TagsInput.tsx +297 -0
- package/src/backend/inputs/TimeInput.tsx +146 -0
- package/src/backend/inputs/TimePicker.tsx +120 -0
- package/src/backend/inputs/__tests__/DatePicker.test.tsx +76 -0
- package/src/backend/inputs/__tests__/DateTimePicker.logic.test.ts +126 -0
- package/src/backend/inputs/__tests__/PhoneNumberField.test.tsx +73 -0
- package/src/backend/inputs/__tests__/TagsInput.test.tsx +78 -0
- package/src/backend/inputs/__tests__/TimeInput.test.tsx +134 -0
- package/src/backend/inputs/__tests__/TimePicker.test.tsx +50 -0
- package/src/backend/inputs/index.ts +11 -0
- package/src/backend/markdown/MarkdownContent.tsx +33 -0
- package/src/backend/markdown/index.ts +2 -0
- package/src/backend/markdown/useMarkdownRemarkPlugins.ts +39 -0
- package/src/backend/messages/MessageComposer.tsx +197 -0
- package/src/backend/messages/MessageObjectDetail.tsx +95 -0
- package/src/backend/messages/MessageObjectPreview.tsx +64 -0
- package/src/backend/messages/MessageObjectRecordPicker.tsx +149 -0
- package/src/backend/messages/MessagePrioritySelector.tsx +78 -0
- package/src/backend/messages/MessagesIcon.tsx +32 -0
- package/src/backend/messages/SendObjectMessageDialog.tsx +74 -0
- package/src/backend/messages/__tests__/MessageComposer.test.tsx +350 -0
- package/src/backend/messages/__tests__/SendObjectMessageDialog.test.tsx +77 -0
- package/src/backend/messages/index.ts +22 -0
- package/src/backend/messages/message-compose-form-groups.tsx +383 -0
- package/src/backend/messages/message-composer.types.ts +82 -0
- package/src/backend/messages/message-priority.ts +53 -0
- package/src/backend/messages/useMessageCompose.ts +666 -0
- package/src/backend/messages/useMessageComposeOperations.ts +259 -0
- package/src/backend/messages/useMessagesPoll.ts +118 -0
- package/src/backend/notifications/NotificationBell.tsx +91 -0
- package/src/backend/notifications/NotificationCountBadge.tsx +14 -0
- package/src/backend/notifications/NotificationDispatcher.ts +213 -0
- package/src/backend/notifications/NotificationItem.tsx +262 -0
- package/src/backend/notifications/NotificationPanel.tsx +225 -0
- package/src/backend/notifications/__tests__/NotificationCountBadge.test.tsx +34 -0
- package/src/backend/notifications/index.ts +20 -0
- package/src/backend/notifications/useNotificationActions.ts +161 -0
- package/src/backend/notifications/useNotificationEffect.ts +17 -0
- package/src/backend/notifications/useNotifications.ts +12 -0
- package/src/backend/notifications/useNotificationsPoll.ts +167 -0
- package/src/backend/notifications/useNotificationsSse.ts +220 -0
- package/src/backend/operations/LastOperationBanner.tsx +85 -0
- package/src/backend/operations/__tests__/LastOperationBanner.test.tsx +101 -0
- package/src/backend/operations/store.ts +230 -0
- package/src/backend/progress/ProgressTopBar.tsx +189 -0
- package/src/backend/progress/useProgress.ts +12 -0
- package/src/backend/progress/useProgressPoll.ts +100 -0
- package/src/backend/progress/useProgressSse.ts +118 -0
- package/src/backend/schedule/ScheduleAgenda.tsx +136 -0
- package/src/backend/schedule/ScheduleGrid.tsx +136 -0
- package/src/backend/schedule/ScheduleToolbar.tsx +178 -0
- package/src/backend/schedule/ScheduleView.tsx +201 -0
- package/src/backend/schedule/index.ts +5 -0
- package/src/backend/schedule/recurrence.ts +99 -0
- package/src/backend/schedule/types.ts +26 -0
- package/src/backend/section-page/SectionNav.tsx +140 -0
- package/src/backend/section-page/SectionPage.tsx +34 -0
- package/src/backend/section-page/index.ts +3 -0
- package/src/backend/section-page/types.ts +30 -0
- package/src/backend/settings/SettingsNavigation.tsx +74 -0
- package/src/backend/settings/SettingsPageWrapper.tsx +78 -0
- package/src/backend/settings/index.ts +3 -0
- package/src/backend/upgrades/UpgradeActionBanner.tsx +128 -0
- package/src/backend/utils/__tests__/api.scoped-headers.test.ts +58 -0
- package/src/backend/utils/__tests__/api.test.ts +148 -0
- package/src/backend/utils/__tests__/apiCall.scoped-request-headers.test.ts +58 -0
- package/src/backend/utils/__tests__/apiCall.test.ts +109 -0
- package/src/backend/utils/__tests__/crud.test.ts +87 -0
- package/src/backend/utils/__tests__/customFieldDefs.test.ts +25 -0
- package/src/backend/utils/__tests__/customFieldValues.test.ts +35 -0
- package/src/backend/utils/__tests__/richTextSanitizer.test.ts +57 -0
- package/src/backend/utils/api.ts +214 -0
- package/src/backend/utils/apiCall.ts +123 -0
- package/src/backend/utils/crud.ts +174 -0
- package/src/backend/utils/customFieldColumns.ts +118 -0
- package/src/backend/utils/customFieldDefs.ts +247 -0
- package/src/backend/utils/customFieldFilters.ts +174 -0
- package/src/backend/utils/customFieldForms.ts +203 -0
- package/src/backend/utils/customFieldRelationDisplay.ts +302 -0
- package/src/backend/utils/customFieldValues.ts +41 -0
- package/src/backend/utils/flash.ts +17 -0
- package/src/backend/utils/nav.ts +402 -0
- package/src/backend/utils/richTextSanitizer.ts +7 -0
- package/src/backend/utils/scopedHeaderStack.ts +49 -0
- package/src/backend/utils/serverErrors.ts +313 -0
- package/src/backend/utils/useAutoDiscoveredFields.ts +138 -0
- package/src/backend/version-history/VersionHistoryAction.tsx +76 -0
- package/src/backend/version-history/VersionHistoryDetail.tsx +87 -0
- package/src/backend/version-history/VersionHistoryPanel.tsx +331 -0
- package/src/backend/version-history/index.ts +9 -0
- package/src/backend/version-history/labels.ts +56 -0
- package/src/backend/version-history/types.ts +27 -0
- package/src/backend/version-history/useAuditPermissions.ts +94 -0
- package/src/backend/version-history/useVersionHistory.ts +173 -0
- package/src/backend/views/NewViewForm.tsx +54 -0
- package/src/backend/views/ShareForm.tsx +62 -0
- package/src/backend/views/ViewChip.tsx +123 -0
- package/src/backend/views/ViewChipMenu.tsx +94 -0
- package/src/backend/views/types.ts +4 -0
- package/src/frontend/AuthFooter.tsx +29 -0
- package/src/frontend/LanguageSwitcher.tsx +66 -0
- package/src/frontend/Layout.tsx +13 -0
- package/src/hooks/useIsMobile.ts +27 -0
- package/src/index.ts +40 -0
- package/src/portal/PortalContext.tsx +180 -0
- package/src/portal/PortalLayoutProvider.tsx +5 -0
- package/src/portal/PortalLayoutShell.tsx +64 -0
- package/src/portal/PortalShell.tsx +370 -0
- package/src/portal/components/PortalCard.tsx +77 -0
- package/src/portal/components/PortalEmptyState.tsx +32 -0
- package/src/portal/components/PortalFeatureCard.tsx +41 -0
- package/src/portal/components/PortalNotificationBell.tsx +81 -0
- package/src/portal/components/PortalNotificationPanel.tsx +230 -0
- package/src/portal/components/PortalPageHeader.tsx +33 -0
- package/src/portal/components/index.ts +6 -0
- package/src/portal/hooks/useCustomerAuth.ts +97 -0
- package/src/portal/hooks/usePortalAppEvent.ts +56 -0
- package/src/portal/hooks/usePortalDashboardWidgets.ts +50 -0
- package/src/portal/hooks/usePortalEventBridge.ts +162 -0
- package/src/portal/hooks/usePortalInjectedMenuItems.ts +130 -0
- package/src/portal/hooks/usePortalNotifications.ts +116 -0
- package/src/portal/hooks/useTenantContext.ts +83 -0
- package/src/primitives/DataLoader.tsx +93 -0
- package/src/primitives/ErrorNotice.tsx +17 -0
- package/src/primitives/Notice.tsx +83 -0
- package/src/primitives/alert.tsx +59 -0
- package/src/primitives/badge.tsx +43 -0
- package/src/primitives/button.tsx +60 -0
- package/src/primitives/calendar.tsx +69 -0
- package/src/primitives/card.tsx +92 -0
- package/src/primitives/checkbox.tsx +34 -0
- package/src/primitives/dialog.tsx +122 -0
- package/src/primitives/form-field.tsx +106 -0
- package/src/primitives/icon-button.tsx +48 -0
- package/src/primitives/input.tsx +26 -0
- package/src/primitives/label.tsx +18 -0
- package/src/primitives/popover.tsx +37 -0
- package/src/primitives/primitives.stories.tsx +223 -0
- package/src/primitives/progress.tsx +28 -0
- package/src/primitives/separator.tsx +7 -0
- package/src/primitives/sheet.tsx +137 -0
- package/src/primitives/spinner.tsx +27 -0
- package/src/primitives/status-badge.tsx +62 -0
- package/src/primitives/switch.tsx +92 -0
- package/src/primitives/table.tsx +27 -0
- package/src/primitives/tabs.tsx +131 -0
- package/src/primitives/textarea.tsx +20 -0
- package/src/primitives/tooltip.tsx +85 -0
- package/src/primitives-v2/AGENTS.md +66 -0
- package/src/primitives-v2/Alert.stories.tsx +56 -0
- package/src/primitives-v2/Alert.tsx +108 -0
- package/src/primitives-v2/Avatar.stories.tsx +60 -0
- package/src/primitives-v2/Avatar.tsx +139 -0
- package/src/primitives-v2/Badge.stories.tsx +80 -0
- package/src/primitives-v2/Badge.tsx +99 -0
- package/src/primitives-v2/Breadcrumb.stories.tsx +61 -0
- package/src/primitives-v2/Breadcrumb.tsx +96 -0
- package/src/primitives-v2/Button.stories.tsx +72 -0
- package/src/primitives-v2/Button.tsx +178 -0
- package/src/primitives-v2/Checkbox.stories.tsx +34 -0
- package/src/primitives-v2/Checkbox.tsx +103 -0
- package/src/primitives-v2/IconButton.stories.tsx +40 -0
- package/src/primitives-v2/IconButton.tsx +40 -0
- package/src/primitives-v2/Input.stories.tsx +60 -0
- package/src/primitives-v2/Input.tsx +113 -0
- package/src/primitives-v2/NavGroup.stories.tsx +50 -0
- package/src/primitives-v2/NavGroup.tsx +76 -0
- package/src/primitives-v2/NavItem.stories.tsx +68 -0
- package/src/primitives-v2/NavItem.tsx +105 -0
- package/src/primitives-v2/SearchInput.stories.tsx +44 -0
- package/src/primitives-v2/SearchInput.tsx +123 -0
- package/src/primitives-v2/Sidebar.stories.tsx +91 -0
- package/src/primitives-v2/Sidebar.tsx +92 -0
- package/src/primitives-v2/Tab.stories.tsx +62 -0
- package/src/primitives-v2/Tab.tsx +148 -0
- package/src/primitives-v2/Tag.stories.tsx +123 -0
- package/src/primitives-v2/Tag.tsx +115 -0
- package/src/primitives-v2/Toggle.stories.tsx +37 -0
- package/src/primitives-v2/Toggle.tsx +93 -0
- package/src/primitives-v2/Topbar.stories.tsx +65 -0
- package/src/primitives-v2/Topbar.tsx +37 -0
- package/src/primitives-v2/index.ts +31 -0
- package/src/primitives-v2/utils.ts +9 -0
- package/src/theme/BrandThemeProvider.tsx +122 -0
- package/src/theme/QueryProvider.tsx +46 -0
- package/src/theme/ThemeProvider.tsx +120 -0
- package/src/theme/ThemeToggle.tsx +88 -0
- package/src/theme/index.ts +4 -0
- package/src/theme/m3.css +622 -0
- package/src/theme/tokens.v2.css +559 -0
- package/src/theme/typography.css +163 -0
- package/src/theme/typography.stories.tsx +157 -0
- package/src/theme/typography.tokens.ts +326 -0
- package/src/types/react-big-calendar.d.ts +16 -0
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../../../src/backend/dynamic-table/types/index.ts"],
|
|
4
|
+
"sourcesContent": ["// types/index.ts\n\nimport type { PerspectiveConfig } from './perspective';\n// The batch-save event strings are DEFINED in `handlers/cellWrites` (the module\n// that emits them) and imported here so there is exactly one spelling of each.\n// Do not retype them below.\nimport {\n CELL_BATCH_SAVE_EVENT,\n CELL_BATCH_SAVE_RESULT_EVENT,\n} from '../handlers/cellWrites';\nimport type {\n CellWrite,\n CellWriteOrigin,\n CellWriteReport,\n CellWriteResult,\n CellWriteRejectReason,\n CellWriteRejectionCounts,\n CellValueCoercer,\n CoerceReason,\n CoerceResult,\n} from '../handlers/cellWrites';\nimport type {\n FillDetector,\n FillMode,\n FillPattern,\n FillSeed,\n} from '../utils/fillPatterns';\nimport type { DensityLevel } from './density';\n\n// Multi-cell write vocabulary. RE-EXPORTED, never redeclared \u2014 a second\n// declaration of `FillMode` is exactly the drift this barrel exists to prevent.\nexport type {\n CellWrite,\n CellWriteOrigin,\n CellWriteReport,\n CellWriteResult,\n CellWriteRejectReason,\n CellWriteRejectionCounts,\n CellValueCoercer,\n CoerceReason,\n CoerceResult,\n FillDetector,\n FillMode,\n FillPattern,\n FillSeed,\n};\n\nexport type CellId = `${number}:${number}`;\n\nexport interface SelectionState {\n type: 'cell' | 'range' | 'row' | 'column' | 'rowRange' | 'colRange' | null;\n anchor: { row: number; col: number } | null;\n focus: { row: number; col: number } | null;\n}\n\nexport interface SelectionBounds {\n startRow: number;\n endRow: number;\n startCol: number;\n endCol: number;\n}\n\nexport interface RangeEdges {\n top?: boolean;\n bottom?: boolean;\n left?: boolean;\n right?: boolean;\n}\n\n/** Which way a fill drag runs. Excel locks to ONE axis; so does this. */\nexport type FillAxis = 'vertical' | 'horizontal';\n\n/**\n * Active drag-to-fill (\"fill handle\") preview \u2014 a RECTANGLE, exactly as Excel\n * draws it. Built on `SelectionBounds` so there is one rectangle type in the\n * grid, not two.\n *\n * `source` is the block the drag started from (the selection at mousedown);\n * `bounds` is the union of source + extension, i.e. the outline the user sees.\n * When the handle is dragged BACK INTO the source, `bounds === source`,\n * `clearing` is true and `cleared` names the sub-rect that will be EMPTIED.\n */\nexport interface FillPreview {\n /** The block the drag started from (the selection at mousedown). */\n source: SelectionBounds;\n /** Union of source + extension \u2014 the outline Excel draws. */\n bounds: SelectionBounds;\n axis: FillAxis;\n /** True when the extension runs up/left, so the series extrapolates backwards. */\n backwards: boolean;\n /** True when the handle was dragged back into the source: `bounds === source`. */\n clearing: boolean;\n /** Only set while `clearing`. Always a sub-rect of `source`. */\n cleared: SelectionBounds | null;\n mode: FillMode;\n}\n\n/**\n * Excel's MARCHING ANTS: the animated dashed outline that marks what is on the\n * clipboard, from `Ctrl+C`/`Ctrl+X` until it is dismissed.\n *\n * It is a SEPARATE rectangle from the selection on purpose \u2014 the whole point is\n * that it survives you moving the cursor somewhere else, which is exactly when\n * a user needs to be told what a `Ctrl+V` is about to paste.\n *\n * Addressed by INDEX into the full view-order column array and the loaded row\n * list, like every other rectangle in this grid, so a marked column that is\n * outside the virtualization window is still marked.\n */\nexport interface ClipboardMarker {\n /** Which gesture produced it. Both draw the same outline (Excel does too). */\n mode: 'copy' | 'cut';\n bounds: SelectionBounds;\n}\n\nexport interface CellState {\n value: any;\n isSelected: boolean;\n isInRange: boolean;\n rangeEdges: RangeEdges;\n isEditing: boolean;\n saveState: SaveStateType;\n isNewRow: boolean;\n /** True while a fill-handle drag is previewing this cell (source OR extension). */\n isFillPreview: boolean;\n /** In the extension only \u2014 this cell will be WRITTEN on release. */\n isFillTarget: boolean;\n /** In `cleared` \u2014 this cell will be EMPTIED on release (back-drag). */\n isFillClearing: boolean;\n /**\n * Carries the drag nub: the bottom-right corner of a selection with at least\n * one fillable column. Computed in the STORE (it needs the whole selection\n * and the column defs) so `Cell` holds no column knowledge.\n */\n isFillOrigin: boolean;\n /** Outer edges of the fill-preview rectangle, for the dashed border. */\n fillEdges: RangeEdges;\n /** Inside the clipboard marker \u2014 carries the marching-ants outline. */\n isClipboardSource: boolean;\n /** Outer edges of the clipboard rectangle. Only these are painted. */\n clipboardEdges: RangeEdges;\n /** `null` when this cell is not in the marker. */\n clipboardMode: 'copy' | 'cut' | null;\n /**\n * The one cell the pointer is currently over. Lives in the STORE, not in\n * React state: a `useState` on DynamicTable would re-render every mounted row\n * on every pointer move, whereas `setHoveredCell` repaints exactly the cell\n * left and the cell entered \u2014 the same two-cell cost `setEditingCell` pays.\n * Used by the hover comment affordance (ledger 8.1).\n */\n isHovered: boolean;\n}\n\nexport type SaveStateType = 'saving' | 'success' | 'error' | null;\n\n/** One cell mutation captured for undo/redo, keyed by stable row id + column. */\nexport interface UndoCellChange {\n rowId: any;\n colKey: string;\n oldValue: any;\n newValue: any;\n}\n\n/** A single undoable action \u2014 one inline edit (1 change) or one fill (N changes). */\nexport interface UndoEntry {\n changes: UndoCellChange[];\n}\n\n// ============================================\n// IN-GRID FIND & REPLACE\n// ============================================\n// Not persisted, and deliberately NOT part of `PerspectiveConfig` \u2014 a saved view\n// must not carry a stale search.\n\nexport interface FindOptions {\n query: string;\n matchCase: boolean;\n /** Match the whole cell rather than a substring (Excel's \"Match entire cell\"). */\n wholeCell: boolean;\n}\n\n\n\nexport type ReplaceRejectReason = 'readOnly' | 'unsupportedColumn' | 'uncoercible' | 'rowGone';\n\nexport interface ReplaceResult {\n replaced: number;\n rejected: Array<{ row: number; col: number; reason: ReplaceRejectReason }>;\n}\n\nexport type CellSubscriber = () => void;\n\n/**\n * Status-palette variant for `type: 'badge'` cells. Maps 1:1 onto the\n * `--status-v2-*` token triplets (bg / border / text). v2 design system.\n */\nexport type DynamicTableBadgeVariant =\n | 'neutral' | 'primary' | 'outline' | 'success' | 'error' | 'warning'\n | 'info' | 'purple' | 'teal' | 'orange' | 'sky' | 'rose';\n\nexport interface ColumnDef {\n data: string;\n title?: string;\n /** Tooltip text shown on hover over the column header */\n headerTooltip?: string;\n width?: number;\n type?: 'text' | 'numeric' | 'date' | 'dropdown' | 'boolean' | 'multiselect';\n /** Horizontal alignment of cell content. v2 design (right-align numbers, centre checkboxes). */\n align?: 'left' | 'center' | 'right';\n /** Render the cell text in the monospace (Geist Mono) face \u2014 refs, codes, dates, amounts. v2 design. */\n mono?: boolean;\n /**\n * Render the cell value as a status pill (v2 design). Presentation-only \u2014\n * the column's `type` still governs sort/filter/edit behaviour, so a status\n * column stays `type: 'dropdown'`/`'text'` and just *displays* as a badge.\n */\n badge?: boolean;\n /**\n * With `badge`: resolve a cell value to a status-palette variant.\n * A function wins over `badgeMap`; both fall back to `'neutral'`.\n */\n badgeVariant?: DynamicTableBadgeVariant | ((value: any, rowData: any) => DynamicTableBadgeVariant);\n /** With `badge`: static value \u2192 variant lookup (e.g. `{ Active: 'success' }`). */\n badgeMap?: Record<string, DynamicTableBadgeVariant>;\n readOnly?: boolean;\n /**\n * The module refuses an empty value for this field (its create/update\n * validator would 400). Multi-cell writes reject an emptying write on a\n * required column up front with reason `'required'`, rather than firing N\n * doomed PATCHes and leaving the grid showing values the server never took.\n */\n required?: boolean;\n /**\n * Fill-series behaviour for the drag handle. `'auto'` (default) runs the\n * pattern chain \u2014 numeric step, date step, weekday step, `REF-001` suffix \u2014\n * and falls back to copying. `'copy'` forces plain tiling for a column whose\n * values only *look* like a series (a postcode, a phone number).\n */\n fillSeries?: 'auto' | 'copy';\n /**\n * Exclude this column from the drag-to-fill handle while still allowing normal\n * inline edits. Use for unique / identity fields (e.g. an invoice number)\n * where copying one value down would create duplicates. Default: false.\n */\n disableFill?: boolean;\n sticky?: 'left' | 'right';\n source?: any[];\n renderer?: (value: any, rowData: any, col: any, rowIndex: number, colIndex: number) => React.ReactNode;\n /**\n * Optional formatter for this column's value in a group-summary (subtotal)\n * row. When omitted, the table uses a dedicated locale number formatter.\n * Use this for columns that need bespoke summary formatting (e.g. currency).\n */\n summaryRenderer?: (value: number, col: any) => React.ReactNode;\n editor?: (\n value: any,\n onChange: (v: any) => void,\n onSave: () => void,\n onCancel: () => void,\n rowData: any,\n col: any,\n rowIndex: number,\n colIndex: number\n ) => React.ReactNode;\n /** Returns CSS class name(s) for conditional cell styling based on value/row data */\n cellClassName?: (value: any, rowData: any, rowIndex: number, colIndex: number) => string | undefined;\n /**\n * Optional formatter for this column's value when the row is exported to\n * CSV/Excel. Use it for columns whose stored cell value is not human-readable\n * (e.g. a relation column that stores `JSON.stringify({ id, name })`).\n * When omitted, the raw cell value is stringified \u2014 matching the Copy button.\n */\n exportValue?: (value: any, rowData: any) => string | number | null | undefined;\n}\n\nexport interface DragState {\n isDragging: boolean;\n type: 'cell' | 'row' | 'column' | null;\n start: { row: number; col: number } | null;\n}\n\nexport interface SortState {\n columnIndex: number | null;\n direction: 'asc' | 'desc' | null;\n}\n\nexport interface ContextMenuState {\n isOpen: boolean;\n position: { x: number; y: number };\n actions: ContextMenuAction[];\n type: 'column' | 'row' | 'cell' | null;\n index: number | null;\n colIndex?: number | null;\n}\n\nexport interface ContextMenuAction {\n id: string;\n label: string;\n icon?: string;\n disabled?: boolean;\n separator?: boolean;\n}\n\nexport interface FilterRow {\n id: string;\n field: string;\n operator: string;\n values: any[];\n}\n\nexport type FilterColor = 'blue' | 'green' | 'purple' | 'orange' | 'pink' | 'teal' | 'yellow' | 'red';\n\nexport interface SavedFilter {\n id: string;\n name: string;\n rows: FilterRow[];\n color?: FilterColor;\n}\n\n// Event types\nexport interface CellEditSaveEvent {\n rowIndex: number;\n colIndex: number;\n oldValue: any;\n newValue: any;\n prop: string;\n rowData: any;\n id?: string;\n}\n\n/** One cell inside a {@link CellBatchSaveEvent}. Mirrors `CellEditSaveEvent`. */\nexport interface CellBatchSaveEntry {\n rowIndex: number;\n colIndex: number;\n prop: string;\n oldValue: any;\n newValue: any;\n rowData: any;\n id?: string;\n}\n\n/**\n * Emitted ONCE per multi-cell write, alongside the per-cell `CELL_EDIT_SAVE`s.\n * Additive: a consumer that ignores it keeps working exactly as before.\n */\nexport interface CellBatchSaveEvent {\n origin: CellWriteOrigin;\n writes: CellBatchSaveEntry[];\n}\n\n/** The applied/rejected tally for one multi-cell write. */\nexport interface CellBatchSaveResultEvent {\n applied: number;\n rejected: { rowIndex: number; colIndex: number; reason?: CellWriteRejectReason }[];\n}\n\nexport interface CellSaveStartEvent {\n rowIndex: number;\n colIndex: number;\n}\n\nexport interface CellSaveSuccessEvent {\n rowIndex: number;\n colIndex: number;\n}\n\nexport interface CellSaveErrorEvent {\n rowIndex: number;\n colIndex: number;\n error?: string;\n}\n\nexport interface NewRowSaveEvent {\n rowIndex: number;\n rowData: any;\n}\n\nexport interface NewRowSaveStartEvent {\n rowIndex: number;\n}\n\nexport interface NewRowSaveSuccessEvent {\n rowIndex: number;\n savedRowData: any;\n}\n\nexport interface NewRowSaveErrorEvent {\n rowIndex: number;\n error?: string;\n}\n\nexport interface ColumnSortEvent {\n columnIndex: number;\n columnName: string;\n direction: 'asc' | 'desc' | null;\n}\n\nexport interface SearchEvent {\n query: string;\n timestamp: number;\n}\n\nexport interface FilterChangeEvent {\n filters: FilterRow[];\n savedFilterId?: string | null;\n}\n\nexport interface FilterSaveEvent {\n filter: SavedFilter;\n}\n\nexport interface FilterSelectEvent {\n id: string | null;\n filterRows: FilterRow[];\n}\n\nexport interface FilterRenameEvent {\n id: string;\n newName: string;\n}\n\nexport interface FilterDeleteEvent {\n id: string;\n}\n\nexport interface ColumnContextMenuEvent {\n columnIndex: number;\n columnName: string;\n actionId: string;\n}\n\nexport interface RowContextMenuEvent {\n rowIndex: number;\n rowData: any;\n actionId: string;\n}\n\nexport interface CellContextMenuEvent {\n rowIndex: number;\n colIndex: number;\n rowData: any;\n col: ColumnDef;\n actionId: string;\n}\n\nexport const TableEvents = {\n CELL_EDIT_SAVE: 'table:cell:edit:save',\n CELL_SAVE_START: 'table:cell:save:start',\n CELL_SAVE_SUCCESS: 'table:cell:save:success',\n CELL_SAVE_ERROR: 'table:cell:save:error',\n /** One multi-cell write (paste / cut / clear / fill / replace / import). */\n CELL_BATCH_SAVE: CELL_BATCH_SAVE_EVENT,\n /** The applied/rejected tally for that same write. */\n CELL_BATCH_SAVE_RESULT: CELL_BATCH_SAVE_RESULT_EVENT,\n NEW_ROW_SAVE: 'table:new:row:save',\n NEW_ROW_SAVE_START: 'table:new:row:save:start',\n NEW_ROW_SAVE_SUCCESS: 'table:new:row:save:success',\n NEW_ROW_SAVE_ERROR: 'table:new:row:save:error',\n FILTER_CHANGE: 'table:filter:change',\n FILTER_SAVE: 'table:filter:save',\n FILTER_SELECT: 'table:filter:select',\n FILTER_RENAME: 'table:filter:rename',\n FILTER_DELETE: 'table:filter:delete',\n COLUMN_SORT: 'table:column:sort',\n SEARCH: 'table:search',\n COLUMN_CONTEXT_MENU_ACTION: 'table:column:context:action',\n ROW_CONTEXT_MENU_ACTION: 'table:row:context:action',\n CELL_CONTEXT_MENU_ACTION: 'table:cell:context:action',\n // Perspective events\n PERSPECTIVE_SAVE: 'table:perspective:save',\n PERSPECTIVE_SELECT: 'table:perspective:select',\n PERSPECTIVE_RENAME: 'table:perspective:rename',\n PERSPECTIVE_DELETE: 'table:perspective:delete',\n PERSPECTIVE_CHANGE: 'table:perspective:change',\n PERSPECTIVE_DUPLICATE: 'table:perspective:duplicate',\n PERSPECTIVE_SET_DEFAULT: 'table:perspective:setDefault',\n PERSPECTIVE_PUBLISH: 'table:perspective:publish',\n PERSPECTIVE_TEMPLATE_COPY: 'table:perspective:templateCopy',\n} as const;\n\n// Type mapping for event payloads - maps event names to their payload types\nexport type TableEventPayloads = {\n [TableEvents.CELL_EDIT_SAVE]: CellEditSaveEvent;\n [TableEvents.CELL_SAVE_START]: CellSaveStartEvent;\n [TableEvents.CELL_SAVE_SUCCESS]: CellSaveSuccessEvent;\n [TableEvents.CELL_SAVE_ERROR]: CellSaveErrorEvent;\n [TableEvents.CELL_BATCH_SAVE]: CellBatchSaveEvent;\n [TableEvents.CELL_BATCH_SAVE_RESULT]: CellBatchSaveResultEvent;\n [TableEvents.NEW_ROW_SAVE]: NewRowSaveEvent;\n [TableEvents.NEW_ROW_SAVE_START]: NewRowSaveStartEvent;\n [TableEvents.NEW_ROW_SAVE_SUCCESS]: NewRowSaveSuccessEvent;\n [TableEvents.NEW_ROW_SAVE_ERROR]: NewRowSaveErrorEvent;\n [TableEvents.FILTER_CHANGE]: FilterChangeEvent;\n [TableEvents.FILTER_SAVE]: FilterSaveEvent;\n [TableEvents.FILTER_SELECT]: FilterSelectEvent;\n [TableEvents.FILTER_RENAME]: FilterRenameEvent;\n [TableEvents.FILTER_DELETE]: FilterDeleteEvent;\n [TableEvents.COLUMN_SORT]: ColumnSortEvent;\n [TableEvents.SEARCH]: SearchEvent;\n [TableEvents.COLUMN_CONTEXT_MENU_ACTION]: ColumnContextMenuEvent;\n [TableEvents.ROW_CONTEXT_MENU_ACTION]: RowContextMenuEvent;\n [TableEvents.CELL_CONTEXT_MENU_ACTION]: CellContextMenuEvent;\n // Perspective event payloads (types imported from ./perspective)\n [TableEvents.PERSPECTIVE_SAVE]: import('./perspective').PerspectiveSaveEvent;\n [TableEvents.PERSPECTIVE_SELECT]: import('./perspective').PerspectiveSelectEvent;\n [TableEvents.PERSPECTIVE_RENAME]: import('./perspective').PerspectiveRenameEvent;\n [TableEvents.PERSPECTIVE_DELETE]: import('./perspective').PerspectiveDeleteEvent;\n [TableEvents.PERSPECTIVE_CHANGE]: import('./perspective').PerspectiveChangeEvent;\n [TableEvents.PERSPECTIVE_DUPLICATE]: import('./perspective').PerspectiveDuplicateEvent;\n [TableEvents.PERSPECTIVE_SET_DEFAULT]: import('./perspective').PerspectiveSetDefaultEvent;\n [TableEvents.PERSPECTIVE_PUBLISH]: import('./perspective').PerspectivePublishEvent;\n [TableEvents.PERSPECTIVE_TEMPLATE_COPY]: import('./perspective').PerspectiveTemplateCopyEvent;\n};\n\n// Type for event handler map - each key is an event name, value is handler function\nexport type EventHandlers = {\n [K in keyof TableEventPayloads]?: (payload: TableEventPayloads[K], event?: Event) => void;\n};\n\nexport interface PaginationProps {\n currentPage: number;\n totalPages: number;\n limit: number;\n /** Total record count across all pages \u2014 drives the v2 footer's \"X\u2013Y of Z\" text. */\n total?: number;\n limitOptions?: number[];\n onPageChange: (page: number) => void;\n onLimitChange: (limit: number) => void;\n}\n\n/**\n * Style preset for read-only cells.\n * - 'muted': Gray background (default) - indicates cells are not editable\n * - 'normal': Same as editable cells - white/transparent background\n * - 'subtle': Very subtle background tint - minimal visual difference\n */\nexport type ReadOnlyStyle = 'muted' | 'normal' | 'subtle';\n\n/**\n * Style preset for row hover in clickable row mode.\n * - 'default': Light blue background (same as selection)\n * - 'subtle': Very light gray background\n * - 'accent': Uses theme accent color\n */\nexport type RowHoverStyle = 'default' | 'subtle' | 'accent';\n\n/**\n * A custom batch action shown in the grouped-actions (bulk) bar that appears\n * when \u22651 row is selected. Configured per-table via `uiConfig.bulkActions`;\n * rendered after the built-in Copy (and optional Delete) buttons.\n */\nexport interface BulkActionConfig {\n /** Stable identifier (used as the React key). */\n id: string;\n /** Button label. */\n label: string;\n /** Optional leading icon (e.g. a lucide-react element). */\n icon?: React.ReactNode;\n /** Invoked with the currently-selected row ids when the button is clicked. */\n onClick: (selectedIds: string[]) => void | Promise<void>;\n /** Optionally disable the action for the current selection. */\n disabled?: (selectedIds: string[]) => boolean;\n}\n\n/**\n * What `TableUIConfig.searchSuggestions` receives.\n *\n * `inputRef` is handed over so the panel can attach its OWN `keydown` listener\n * to the input: arrow-key navigation of a list has to be driven from the control\n * that holds focus, and focus never leaves the box. `submit` puts a query into\n * the box AND into the dataset in one move \u2014 what clicking a hint does.\n */\nexport type SearchSuggestionsContext = {\n /** What the box holds right now, undebounced. */\n query: string;\n inputRef: React.RefObject<HTMLInputElement | null>;\n /** Close the panel and leave the query alone. */\n close: () => void;\n /** Set the query and search for it immediately. */\n submit: (query: string) => void;\n};\n\nexport type SearchSuggestionsRenderer = (ctx: SearchSuggestionsContext) => React.ReactNode;\n\n/**\n * What `searchBarStart` is handed when it is a function.\n *\n * Deliberately small: the rows currently loaded and the filter pair. A header\n * is not a body renderer and must not be given selection, grouping toggles or\n * paging \u2014 those belong to the table's own chrome, and handing them out is how\n * two controls end up disagreeing about one piece of state.\n */\nexport interface SearchBarRenderContext {\n /** The rows on this page, after search and filters. */\n data: any[];\n filters: FilterRow[];\n setFilters: (filters: FilterRow[]) => void;\n}\n\nexport interface TableUIConfig {\n /** Hide the entire toolbar (header with title, search, buttons) */\n hideToolbar?: boolean;\n /** Hide just the title in the toolbar */\n hideTitle?: boolean;\n /** Hide just the search bar */\n hideSearch?: boolean;\n /** Hide the \"Add Row\" button */\n hideAddRowButton?: boolean;\n /** Hide the perspective tabs row (All, Base, +) */\n hidePerspectiveTabs?: boolean;\n /**\n * Offer a view switcher in the toolbar's icon cluster.\n *\n * Two or more entries render an M3 segmented button; fewer render nothing,\n * so a table with one way to draw itself is byte-identical to today. The\n * chosen mode is a property of the SAVED VIEW (`PerspectiveConfig.viewMode`),\n * not of the session \u2014 see that type for why.\n *\n * A mode other than `'table'` needs `renderBody`; without it the switcher\n * would offer a mode that draws nothing.\n */\n viewModes?: TableViewModeOption[];\n /**\n * Fired when the view switcher changes mode, and once on mount with the\n * initial mode.\n *\n * The table owns `viewMode` internally, which is right \u2014 it decides whether\n * to call `renderBody`. But a host often has chrome that belongs to only one\n * of the two renderers: the documents list draws folders as a row of tiles\n * INSIDE its grid body, so the folder chips it puts in `searchBarStart` are\n * a duplicate there and the only thing that can reach a folder in the list.\n * Without this the host cannot tell which it is looking at, and the same\n * folders appear twice in two different shapes.\n */\n onViewModeChange?: (mode: import('./perspective').TableViewMode) => void;\n /** Hide the pagination controls */\n hidePagination?: boolean;\n /** Hide the Actions column */\n hideActionsColumn?: boolean;\n /**\n * Hide the toolbar Export button (CSV/Excel download of the selected rows,\n * or the current page when nothing is selected). Default: false (shown).\n */\n hideExportButton?: boolean;\n /**\n * Base file name (without extension) for exported CSV/Excel files. When\n * omitted, the table name is slugified. Example: 'invoices' \u2192 'invoices.csv'.\n */\n exportFileName?: string;\n /** Custom content rendered at the start of the top bar (before title) */\n topBarStart?: React.ReactNode;\n /** Custom content rendered at the end of the top bar (after add button) */\n topBarEnd?: React.ReactNode;\n /** v2 only: content rendered at the right end of the search row (e.g. a\n * primary action button placed on the same line as the search input). */\n searchBarEnd?: React.ReactNode;\n /**\n * v2 only: content rendered FIRST in the search-row actions (before the add\n * button / searchBarEnd / export), e.g. a leading toolbar action.\n *\n * MAY BE A RENDER FUNCTION, and that is what makes chrome shared between the\n * two renderers possible. `renderBody` is called only when the view mode is\n * not `table`, so anything needing `filters` / `setFilters` could previously\n * only exist in the GRID \u2014 the documents module drew its folder row there and\n * the list view saw no change at all, which is precisely the bug that\n * prompted this. A header that narrows the table has to be reachable from\n * both, and this slot is the one both render.\n */\n searchBarStart?: React.ReactNode | ((ctx: SearchBarRenderContext) => React.ReactNode);\n\n /**\n * Full-width content between the toolbar and the table body, in BOTH view\n * modes.\n *\n * `searchBarStart` puts its content INSIDE the search row, squeezed beside\n * the title and the search box. That is right for a leading toolbar action\n * and wrong for a band: the documents module's folder row landed there and\n * came out as a cramped strip to the right of the heading, nothing like the\n * row of folders it is meant to be.\n *\n * A function receives the same small context, so a band can narrow the\n * table from a place both renderers paint.\n */\n beforeBody?: React.ReactNode | ((ctx: SearchBarRenderContext) => React.ReactNode);\n /**\n * A suggestions panel under the search box \u2014 the Drive-style \"hits as you\n * type\" affordance.\n *\n * NOT a `ReactNode` like the slots above, and not anywhere near them: those\n * render into `.hot-toolbar-actions`, which sits AFTER the toolbar spacer, on\n * the far right of the row. A hint panel has to be under the input it\n * belongs to, so `SearchBar` owns the anchoring (measured + portalled, because\n * `.hot-card` clips) and this hands back only the contents.\n *\n * A render prop because relevance is domain knowledge: what a good hint shows,\n * where it comes from and what it means to click one is the host's business.\n */\n searchSuggestions?: SearchSuggestionsRenderer;\n /** Debounce before the search box publishes a query. Default 300ms; a table\n * with `searchSuggestions` usually wants less, so the panel feels live. */\n searchDebounceMs?: number;\n /** Placeholder for the search box. Default: \"Search\u2026\". */\n searchPlaceholder?: string;\n /**\n * Rename a group heading \u2014 given the field, the raw value and the row count.\n *\n * The grouping engine has one word for a group with no value, `(Empty)`\n * (`EMPTY_GROUP_VALUE`), and it names the TABLE'S INTERNALS rather than the\n * data. Grouped by case, that pile is \"No case\" \u2014 the documents nobody has\n * filed \u2014 and only the host knows that. Without this hook a host can rename\n * the sections in its own body renderer and not in the table, which is how one\n * list ends up calling the same pile two different things.\n *\n * Return `undefined` to keep the default.\n */\n formatGroupValue?: (ctx: { field: string; value: string; count: number }) => string | undefined;\n /** Enable fullscreen toggle button. Default: false */\n enableFullscreen?: boolean;\n /** Callback when fullscreen state changes */\n onFullscreenChange?: (isFullscreen: boolean) => void;\n /**\n * Enable the Excel/Airtable-style fill handle: a grab-nub on the single\n * active editable cell that drag-fills its value up/down the column.\n * Default: false (opt-in per table).\n */\n enableFillHandle?: boolean;\n /**\n * Above this many target cells, a fill drag asks for confirmation before\n * writing (each filled cell fires a save \u2192 a persist request). Default: 100.\n */\n fillConfirmThreshold?: number;\n /**\n * Visual style for read-only cells. Default: 'muted'\n * - 'muted': Gray background - indicates cells are not editable\n * - 'normal': Same as editable cells - no visual difference\n * - 'subtle': Very subtle background - minimal visual indication\n */\n readOnlyStyle?: ReadOnlyStyle;\n /**\n * Hover style for clickable rows. Only applies when onRowClick is set.\n * - 'default': Light blue (selection color)\n * - 'subtle': Light gray\n * - 'accent': Theme accent color\n * @default 'default'\n */\n rowHoverStyle?: RowHoverStyle;\n /**\n * Disable the built-in column header context menu (modern layout).\n * When true, reverts to classic double-click behavior for column actions.\n * @default false\n */\n disableBuiltinColumnMenu?: boolean;\n /**\n * Remove the outer border and border-radius from the table container.\n * Use when the table fills the full page and should blend with the layout.\n * @default false\n */\n borderless?: boolean;\n /**\n * Custom batch actions appended to the grouped-actions (bulk) bar shown when\n * \u22651 row is selected. Each is rendered after the built-in Copy / Delete\n * buttons and receives the selected row ids on click.\n */\n bulkActions?: BulkActionConfig[];\n /**\n * Virtualize COLUMNS in addition to rows.\n *\n * Default FALSE \u2014 opt-in per table, because it changes rendering for 56\n * consumer files. With it off the grid mounts every column exactly as it does\n * today (the window \"fails open\" to the full set), so switching the flag off\n * is a byte-identical render, not a fallback path.\n *\n * THE NAME IS LOAD-BEARING: `apps/web/src/app/dev/dynamic-table-stress/`\n * spreads this literal key when `?colvirt=1`. Any other spelling and the\n * measurement toggle silently no-ops.\n *\n * @default false\n */\n enableColumnVirtualization?: boolean;\n /**\n * Horizontal overscan in columns, i.e. how many unseen columns are mounted\n * either side of the viewport. Raising it spends the density budget this\n * feature exists to buy \u2014 diagnose blank columns as a commit-latency problem\n * before reaching for this.\n *\n * @default 3 (DEFAULT_COLUMN_OVERSCAN)\n */\n columnOverscan?: number;\n /**\n * Hide the row-density picker in the toolbar. Density is a PER-USER\n * preference (see `hooks/useDensityPreference`), so hiding the control does\n * not pin the level \u2014 a user who set `dense` elsewhere still gets `dense`\n * here. Use `densityLevel` for that.\n *\n * @default false\n */\n hideDensityControl?: boolean;\n /**\n * Keep Export / Row height / Fullscreen as separate toolbar buttons.\n *\n * Default is CONDENSED \u2014 one overflow button \u2014 because those three are\n * secondary controls that were each spending toolbar width on every table in\n * the app, crowding out the primary action a page actually cares about\n * (\"Create Offer\", \"Add Location\"). Set this when a table genuinely wants\n * them one click away.\n */\n expandToolbarActions?: boolean;\n /**\n * Rows a HOST appends inside the toolbar's overflow menu.\n *\n * Exists so a host adds items to the table's one menu instead of rendering a\n * second button next to it \u2014 which is what an earlier build did, leaving two\n * near-identical overflow buttons side by side.\n */\n toolbarOverflowExtras?: React.ReactNode;\n /**\n * DEVELOPER override for tables whose structure demands a fixed density (a\n * two-row summary strip, a fixed-height drawer sub-table). Read-only: it wins\n * for THIS table and is never persisted, so it cannot silently become the\n * user's setting everywhere. Omit for the normal case.\n */\n densityLevel?: DensityLevel;\n}\n\n/**\n * Function type for loading filter suggestions from a server.\n * When provided, the filter popover will use this instead of extracting values from loaded data.\n * This is recommended for large datasets (1000+ rows) to avoid client-side performance issues.\n *\n * @param field - The field/column name to get suggestions for\n * @param query - The current search query typed by the user (for filtering suggestions server-side)\n * @returns Promise resolving to an array of suggestion strings\n */\nexport type LoadFilterSuggestions = (field: string, query: string) => Promise<string[]>;\n\n/**\n * A whitelisted field a linked (lookup) column can surface from a related record.\n */\nexport interface LookupSourceFieldOption {\n /** Target field key, e.g. `'tax_id'`. */\n key: string;\n /** Translated, user-facing field label. */\n label: string;\n}\n\n/**\n * A foreign-key relationship the current table can attach linked columns to.\n * Supplied by the host (which knows its `tableId`) via {@link LoadLookupSources}\n * so `packages/ui` never imports the host's lookup module.\n */\nexport interface LookupSourceOption {\n /** Registered lookup source key (an FK relationship), e.g. `'contractor'`. */\n key: string;\n /** Translated, user-facing relationship label, e.g. `'Contractor'`. */\n label: string;\n /** Whitelisted fields that may be surfaced as linked columns. */\n fields: LookupSourceFieldOption[];\n}\n\n/**\n * Loads the foreign-key lookup sources available for this table. When provided,\n * the Configure View drawer shows a \"Linked columns\" section. Called lazily when\n * the drawer opens.\n */\nexport type LoadLookupSources = () => Promise<LookupSourceOption[]>;\n\n// ============================================\n// KEYBOARD SHORTCUTS\n// ============================================\n\n/**\n * Defines a keyboard shortcut for a row action.\n * Shortcuts only fire when a single cell is selected (not editing, not multi-select).\n */\nexport interface RowActionShortcut {\n /** Unique identifier for this shortcut (e.g., 'view', 'delete') */\n id: string;\n /** Display label for documentation/tooltips (e.g., 'Open detail') */\n label: string;\n /** The key to match (e.g., 'Enter', 'd', 'Backspace') \u2014 uses KeyboardEvent.key */\n key: string;\n /** Whether Shift must be held. Default: false */\n shift?: boolean;\n /** Whether Ctrl/Cmd must be held. Default: false */\n ctrlOrCmd?: boolean;\n /** Whether Alt must be held. Default: false */\n alt?: boolean;\n}\n\n/**\n * Configuration for DynamicTable keyboard shortcuts.\n */\nexport interface KeyboardShortcutsConfig {\n /** Row-level action shortcuts (fire when a single row is selected) */\n rowActions?: RowActionShortcut[];\n}\n\n/**\n * Callback fired when a keyboard shortcut triggers a row action.\n * @param actionId - The `id` of the matched RowActionShortcut\n * @param rowData - The data object for the currently selected row\n * @param rowIndex - The index of the currently selected row\n */\nexport type OnRowAction = (actionId: string, rowData: any, rowIndex: number) => void;\n\nexport interface DynamicTableProps {\n data?: any[];\n columns?: ColumnDef[];\n colHeaders?: boolean;\n rowHeaders?: boolean;\n height?: string | number;\n width?: string | number;\n idColumnName?: string;\n tableName?: string;\n /**\n * Stable identifier for this table, used to persist per-user column widths in\n * localStorage across reloads. Scoped to the signed-in user (falling back to\n * the active organization). When omitted, manual column resizes are not\n * remembered. Pass the same id you use for `perspectives` so widths track the\n * table, not the page instance.\n */\n tableId?: string;\n tableRef: React.RefObject<HTMLDivElement | null>;\n columnActions?: (column: ColumnDef, colIndex: number) => ContextMenuAction[];\n rowActions?: (rowData: any, rowIndex: number) => ContextMenuAction[];\n actionsRenderer?: (rowData: any, rowIndex: number) => React.ReactNode;\n pagination?: PaginationProps;\n /**\n * The dataset-wide search term currently narrowing `data` (the `SearchBar`'s\n * query). Read-only, and used for ONE thing: find-and-replace's scope label\n * says \"\u2026in 100 loaded rows (filtered by \"abc\")\" so a loaded-page match count\n * can never be mistaken for a dataset count. Omitted \u2192 the clause is omitted.\n */\n searchQuery?: string;\n\n\n\n // DEPRECATED - Keep for backward compatibility (converts to perspectives internally)\n savedFilters?: SavedFilter[];\n activeFilterId?: string | null;\n hiddenColumns?: string[];\n\n // Debug mode - shows floating event log panel\n debug?: boolean;\n\n // UI visibility configuration\n uiConfig?: TableUIConfig;\n\n\n /**\n * Refs to adjacent DynamicTable containers for cross-table navigation.\n * ArrowDown at the last row / ArrowUp at the first row moves focus to\n * `next` / `prev`. Tab past the last editable cell also moves to `next`,\n * and Shift+Tab before the first editable cell moves to `prev`.\n */\n /** When true, automatically selects the first cell when table receives focus */\n autoSelectOnFocus?: boolean;\n /** When true, Tab navigation enters edit mode on the target cell. @default true */\n autoEditOnTab?: boolean;\n /** Function to load filter suggestions from the server */\n loadFilterSuggestions?: LoadFilterSuggestions;\n /** Function to load the table's FK lookup sources. When set, the Configure\n * View drawer shows a \"Linked columns\" section. */\n loadLookupSources?: LoadLookupSources;\n /** Keyboard shortcuts for row-level actions */\n keyboardShortcuts?: KeyboardShortcutsConfig;\n /** Callback fired when a keyboard shortcut triggers a row action */\n onRowAction?: OnRowAction;\n /** Refs to adjacent DynamicTable containers for cross-table navigation */\n siblingTableRefs?: {\n prev?: React.RefObject<HTMLDivElement | null>;\n next?: React.RefObject<HTMLDivElement | null>;\n };\n /** Callback when a row is clicked. Enables clickable row mode with hover highlighting. */\n onRowClick?: (rowIndex: number, rowData: any, event: React.MouseEvent) => void;\n /** Callback when a row is double-clicked */\n onRowDoubleClick?: (rowIndex: number, rowData: any, event: React.MouseEvent) => void;\n /** ID of the row to highlight (same style as hover) */\n highlightedRowId?: string | null;\n /** Width in pixels for the actions column. @default 80 */\n actionsColumnWidth?: number;\n /** Enable cell comments and color annotations */\n enableComments?: boolean;\n /** Entity type for annotations. String or function that resolves per-row. */\n commentsEntityType?: string | ((row: any) => string);\n /**\n * B8a \u2014 resolve the annotation target for ONE CELL, so a row that is not one\n * record can scope each column to the record its value actually belongs to.\n * Defaults to `{ entityType: commentsEntityType, rowId: row[idColumnName] }`.\n * See the same prop on `DynamicTable` for the full rationale.\n */\n commentsCellTarget?: (row: Record<string, any>, col: ColumnDef) => { entityType: string; rowId: string };\n /** Optional view context label stored as metadata (e.g., \"project_sea_containers\"). */\n commentsViewContext?: string;\n /** Called after any annotation or comment change (create, update, delete). */\n onAnnotationChange?: () => void;\n /** Message to display when table has no data */\n emptyMessage?: string;\n /** Saved perspective configurations */\n savedPerspectives?: PerspectiveConfig[];\n /** Currently active perspective ID */\n activePerspectiveId?: string | null;\n /**\n * The view that opens by default FOR THIS USER (workshop A4). Drives the star\n * on the tab and the enabled state of \"Set as my default\". Per-user: upstream\n * scopes `isDefault` by `userId`.\n */\n defaultPerspectiveId?: string | null;\n /**\n * Views colleagues published as SHARED TEMPLATES. Offered for copying only \u2014\n * never applied to anyone automatically, which is what keeps every saved\n * setting per-user after sharing exists.\n */\n sharedTemplates?: import('./perspective').PerspectiveTemplate[];\n /** Whether this user may publish a view (server's `perspectives.role_defaults` answer). */\n canPublishTemplates?: boolean;\n /** Roles a template can be published to. Empty unless `canPublishTemplates`. */\n publishableRoles?: Array<{ id: string; name: string }>;\n /** Columns hidden by default */\n defaultHiddenColumns?: string[];\n /** Density of row padding (v2 design). */\n density?: 'sm' | 'md';\n /** Zebra-stripe alternate rows with the secondary surface (v2 design). */\n striped?: boolean;\n /** Called with the selected row IDs whenever the v2 checkbox-column\n * selection changes. Drives bulk actions (e.g. mark-paid). */\n onSelectionChange?: (selectedIds: string[]) => void;\n /**\n * Fetch the entire dataset (all pages, ignoring the active perspective's\n * filters) for a whole-table export. Supplied by `useDynamicTablePage`. When\n * present, the toolbar Export button exports every row across all columns;\n * when absent it falls back to the currently-loaded page.\n *\n * MAY REJECT, and the caller must let it (HEDGE-123). A page that fails\n * mid-pagination must abort the export, never shorten it \u2014 a short CSV looks\n * exactly like a complete one and goes into a reconciliation unnoticed.\n *\n * May also resolve to an {@link ExportAllResult} instead of a bare array, to\n * report a result it could not prove complete. A bare array still means\n * \"complete\", so existing implementations are unaffected.\n */\n onExportAll?: () => Promise<any[] | ExportAllResult>;\n /**\n * Server-computed aggregate over the whole filtered dataset, from\n * `useDynamicTablePage`. Absent/null \u2192 the pinned totals row folds the loaded\n * page instead and says so.\n */\n aggregateResult?: import('./grouping').AggregateResult | null;\n aggregateLoading?: boolean;\n aggregateError?: boolean;\n /**\n * The LIST request itself failed (HEDGE-119) \u2014 not \"the table is empty\".\n *\n * Supplied by `useDynamicTablePage` from the dataset query's error state.\n * When true the zero-row region renders `LoadErrorState` instead of\n * `EmptyState`, because a rejected query and a genuinely empty table both\n * arrive as `data: []` and were previously indistinguishable on screen.\n * Defaults false, so every existing host keeps its current behaviour.\n */\n loadError: boolean;\n /** Re-runs the failed list request from the error state's retry button. */\n onRetryLoad?: () => void;\n /**\n * Draw the table's BODY as something other than rows.\n *\n * THE POINT OF THIS PROP is that the alternative renderer cannot own state\n * the table also owns. `DynamicTable` stays mounted and keeps everything it\n * already keeps \u2014 the toolbar, the search box, the filters, the perspective\n * tabs, the grouping, the selection, the pagination and the bulk-action bar.\n * Only the region between the toolbar and the footer changes. So a second\n * view cannot diverge from the table by construction, rather than by anyone\n * remembering to keep them in step.\n *\n * Called only while `viewMode` is not `'table'`. When it is absent the mode\n * has nothing to switch to and the switcher is not rendered.\n */\n renderBody?: (ctx: TableBodyRenderContext) => React.ReactNode;\n\n /**\n * \u26A0 `DynamicTableProps` IS DECLARED TWICE \u2014 here and in `DynamicTable.tsx`.\n *\n * They have drifted in BOTH directions, which is how FMS's production build\n * broke: this copy carried `defaultGrouping` and not `renderBody`, the other\n * carried `renderBody` and not `defaultGrouping`, and the component and its\n * consumers each resolved a different one. `tsc` reported a prop that is\n * plainly used as not existing.\n *\n * Reconciled rather than merged: collapsing two ~150-member interfaces is a\n * change worth doing on its own, not while unblocking a deploy. Anything\n * added to one MUST be added to the other until then.\n */\n /** Grouping applied when a perspective declares none. See the fuller note on\n * the sibling declaration. */\n defaultGrouping?: import('./grouping').GroupRule[];\n}\n\n/**\n * Everything an alternative body renderer is given. It is READ-MOSTLY on\n * purpose: the callbacks mutate the table's own state, so a renderer changes\n * the same thing the table would have changed.\n */\nexport interface TableBodyRenderContext {\n /** The current page of rows, exactly as the table has them. */\n data: any[];\n /** The resolved, visible columns in display order. */\n columns: ColumnDef[];\n /**\n * The grouped layout when a `GroupRule[]` is active, else `null`. Section\n * headers carry `memberDataIndices`, which is what makes a group's\n * select-all select rows a collapsed section is hiding.\n */\n visualRows: import('./grouping').VisualRow[] | null;\n /** The active grouping. Empty \u21D2 the body renders one flat run of rows. */\n groupRules: import('./grouping').GroupRule[];\n collapsedGroups: ReadonlySet<string>;\n toggleGroup: (groupKey: string) => void;\n /** Row-key values of the selected rows. Same set the bulk bar counts. */\n selectedRowIds: ReadonlySet<string>;\n /** The column whose value identifies a row for selection. */\n rowKeyColumn: string;\n selectable: boolean;\n toggleRowSelect: (rowId: string, opts?: { shiftKey?: boolean }) => void;\n toggleGroupSelect: (rowIds: string[]) => void;\n clearSelection: () => void;\n /** The needle currently narrowing the rows, for an honest empty state. */\n searchQuery?: string;\n /**\n * The live filter rules \u2014 the SAME array the Configure View drawer and the\n * header quick filters edit.\n *\n * A body renderer that offers its own quick filter (a chip row, a facet\n * list) writes through `setFilters` rather than holding a selection of its\n * own. That is what makes such a control visible to the table view, to the\n * active-filter chips and to a saved view; a private selection would be a\n * second filter model that can disagree with the list.\n */\n filters: FilterRow[];\n setFilters: (filters: FilterRow[]) => void;\n /** How many filter rules are active, for an honest empty state. */\n filterCount: number;\n /** Drop the search / the filters \u2014 the two ways out of an empty result. */\n clearSearch: () => void;\n clearFilters?: () => void;\n}\n\n/** One segment of the view switcher. */\nexport interface TableViewModeOption {\n mode: import('./perspective').TableViewMode;\n /** Accessible label. Also the tooltip. */\n label: string;\n icon: React.ReactNode;\n}\n\n// Re-export filter types\nexport * from './filters';\n\n// Re-export perspective types\nexport * from './perspective';\n\n// Re-export grouping types\nexport * from './grouping';\n\n// Re-export rollup (\"summarised column\") types. Single export site \u2014 see the\n// header of ./rollup for why nothing else may re-export these names.\nexport * from './rollup';\n\n/**\n * The outcome of a whole-table export fetch (HEDGE-123).\n *\n * Exists so a partial result can never be mistaken for a complete one. The\n * defect this replaces returned a bare `any[]` whichever happened: a page that\n * 500'd, a page that came back as `200` with an unparseable body, and a walk\n * that hit an internal iteration cap all produced the same value as a clean\n * finish \u2014 a shorter array, with nothing to distinguish it.\n *\n * That is the CSV mirror of the empty-list defect in HEDGE-119. There the user\n * read a failed fetch as \"no rows\"; here they read a truncated file as \"these\n * are all the rows\". The second is worse, because a file looks like an answer:\n * a failure is visible and can be retried, a short export goes into a\n * reconciliation and is never questioned.\n *\n * Hard failures REJECT rather than resolving to this. This type is only for\n * the case where rows were genuinely fetched but completeness cannot be proven.\n */\nexport interface ExportAllResult {\n /** The rows actually collected. */\n rows: any[];\n /** How many rows the server said exist, when it reported a total. */\n expected: number | null;\n /**\n * False when the walk stopped without proving it had everything. The caller\n * must NOT hand the user a file in that case \u2014 it must say how many of how\n * many it got.\n */\n complete: boolean;\n /** Why completeness could not be proven. Present only when `complete` is false. */\n reason?: string;\n}\n"],
|
|
5
|
+
"mappings": "AAMA;AAAA,EACE;AAAA,EACA;AAAA,OACK;AAobA,MAAM,cAAc;AAAA,EACzB,gBAAgB;AAAA,EAChB,iBAAiB;AAAA,EACjB,mBAAmB;AAAA,EACnB,iBAAiB;AAAA;AAAA,EAEjB,iBAAiB;AAAA;AAAA,EAEjB,wBAAwB;AAAA,EACxB,cAAc;AAAA,EACd,oBAAoB;AAAA,EACpB,sBAAsB;AAAA,EACtB,oBAAoB;AAAA,EACpB,eAAe;AAAA,EACf,aAAa;AAAA,EACb,eAAe;AAAA,EACf,eAAe;AAAA,EACf,eAAe;AAAA,EACf,aAAa;AAAA,EACb,QAAQ;AAAA,EACR,4BAA4B;AAAA,EAC5B,yBAAyB;AAAA,EACzB,0BAA0B;AAAA;AAAA,EAE1B,kBAAkB;AAAA,EAClB,oBAAoB;AAAA,EACpB,oBAAoB;AAAA,EACpB,oBAAoB;AAAA,EACpB,oBAAoB;AAAA,EACpB,uBAAuB;AAAA,EACvB,yBAAyB;AAAA,EACzB,qBAAqB;AAAA,EACrB,2BAA2B;AAC7B;AAoqBA,cAAc;AAGd,cAAc;AAGd,cAAc;AAId,cAAc;",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
const TABLE_VIEW_MODES = ["table", "grid"];
|
|
2
|
+
function isTableViewMode(value) {
|
|
3
|
+
return typeof value === "string" && TABLE_VIEW_MODES.includes(value);
|
|
4
|
+
}
|
|
5
|
+
const BASE_VIEW_PERSPECTIVE_NAME = "__base__";
|
|
6
|
+
const PERSPECTIVE_NAME_MAX_LENGTH = 120;
|
|
7
|
+
const PerspectiveEvents = {
|
|
8
|
+
PERSPECTIVE_SAVE: "table:perspective:save",
|
|
9
|
+
PERSPECTIVE_SELECT: "table:perspective:select",
|
|
10
|
+
PERSPECTIVE_RENAME: "table:perspective:rename",
|
|
11
|
+
PERSPECTIVE_DELETE: "table:perspective:delete",
|
|
12
|
+
PERSPECTIVE_CHANGE: "table:perspective:change",
|
|
13
|
+
PERSPECTIVE_DUPLICATE: "table:perspective:duplicate",
|
|
14
|
+
PERSPECTIVE_SET_DEFAULT: "table:perspective:setDefault",
|
|
15
|
+
PERSPECTIVE_PUBLISH: "table:perspective:publish",
|
|
16
|
+
PERSPECTIVE_TEMPLATE_COPY: "table:perspective:templateCopy"
|
|
17
|
+
};
|
|
18
|
+
function createDefaultPerspective(columns, hiddenColumns = []) {
|
|
19
|
+
const allColumnKeys = columns.map((col) => col.data);
|
|
20
|
+
const visible = allColumnKeys.filter((key) => !hiddenColumns.includes(key));
|
|
21
|
+
const hidden = hiddenColumns.filter((key) => allColumnKeys.includes(key));
|
|
22
|
+
return {
|
|
23
|
+
columns: { visible, hidden },
|
|
24
|
+
filters: [],
|
|
25
|
+
sorting: [],
|
|
26
|
+
grouping: [],
|
|
27
|
+
aggregations: [],
|
|
28
|
+
lookupColumns: [],
|
|
29
|
+
rollupColumns: [],
|
|
30
|
+
formulas: [],
|
|
31
|
+
conditionalFormats: []
|
|
32
|
+
};
|
|
33
|
+
}
|
|
34
|
+
function mergePerspectiveConfig(base, partial) {
|
|
35
|
+
return {
|
|
36
|
+
columns: partial.columns ?? base.columns,
|
|
37
|
+
filters: partial.filters ?? base.filters,
|
|
38
|
+
sorting: partial.sorting ?? base.sorting,
|
|
39
|
+
grouping: partial.grouping ?? base.grouping,
|
|
40
|
+
aggregations: partial.aggregations ?? base.aggregations,
|
|
41
|
+
lookupColumns: partial.lookupColumns ?? base.lookupColumns,
|
|
42
|
+
rollupColumns: partial.rollupColumns ?? base.rollupColumns,
|
|
43
|
+
formulas: partial.formulas ?? base.formulas,
|
|
44
|
+
conditionalFormats: partial.conditionalFormats ?? base.conditionalFormats,
|
|
45
|
+
dateFormat: partial.dateFormat ?? base.dateFormat,
|
|
46
|
+
viewMode: partial.viewMode ?? base.viewMode
|
|
47
|
+
};
|
|
48
|
+
}
|
|
49
|
+
function generatePerspectiveId() {
|
|
50
|
+
return `perspective-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`;
|
|
51
|
+
}
|
|
52
|
+
function generateSortRuleId() {
|
|
53
|
+
return `sort-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`;
|
|
54
|
+
}
|
|
55
|
+
function getSortDirectionLabels(type) {
|
|
56
|
+
switch (type) {
|
|
57
|
+
case "date":
|
|
58
|
+
return { asc: "Old \u2192 New", desc: "New \u2192 Old" };
|
|
59
|
+
case "numeric":
|
|
60
|
+
return { asc: "1 \u2192 9", desc: "9 \u2192 1" };
|
|
61
|
+
case "boolean":
|
|
62
|
+
return { asc: "False \u2192 True", desc: "True \u2192 False" };
|
|
63
|
+
default:
|
|
64
|
+
return { asc: "A \u2192 Z", desc: "Z \u2192 A" };
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
export {
|
|
68
|
+
BASE_VIEW_PERSPECTIVE_NAME,
|
|
69
|
+
PERSPECTIVE_NAME_MAX_LENGTH,
|
|
70
|
+
PerspectiveEvents,
|
|
71
|
+
TABLE_VIEW_MODES,
|
|
72
|
+
createDefaultPerspective,
|
|
73
|
+
generatePerspectiveId,
|
|
74
|
+
generateSortRuleId,
|
|
75
|
+
getSortDirectionLabels,
|
|
76
|
+
isTableViewMode,
|
|
77
|
+
mergePerspectiveConfig
|
|
78
|
+
};
|
|
79
|
+
//# sourceMappingURL=perspective.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../../../src/backend/dynamic-table/types/perspective.ts"],
|
|
4
|
+
"sourcesContent": ["// types/perspective.ts\n\nimport { FilterRow, FilterColor } from './index';\nimport type { GroupRule, AggregationRule } from './grouping';\nimport type { ConditionalFormatRule } from '../utils/conditionalFormat';\n// TYPE-ONLY IMPORT, deliberately NOT re-exported. `FormulaColumnRef` has exactly\n// one export site \u2014 `formula/index.ts`, which the package barrel re-exports.\n// Re-exporting it here too would give the barrel two `export *` sources for the\n// same name; ES semantics then drops the name silently and consumers lose it.\nimport type { FormulaColumnRef } from '../formula/types';\n// Same rule as `FormulaColumnRef`: ONE export site (`./rollup`, which\n// `types/index.ts` re-exports). Imported type-only, never re-exported here.\nimport type { RollupColumnRef } from './rollup';\n\n// ============================================\n// PERSPECTIVE DATA STRUCTURES\n// ============================================\n\nexport interface SortRule {\n id: string;\n field: string;\n direction: 'asc' | 'desc';\n}\n\nexport interface ColumnConfig {\n /** Column data keys in display order (visible columns) */\n visible: string[];\n /** Hidden column data keys */\n hidden: string[];\n}\n\n/**\n * A read-only linked (lookup) column attached to a perspective. It surfaces\n * `field` of the record reached through the host table's foreign-key relationship\n * `source` (a code-declared lookup source). The grid renders it as a read-only\n * column keyed `lookup__<source>__<field>`, and the server enriches each row with\n * that value. View-scoped: different perspectives can show different linked columns.\n */\nexport interface LookupColumnRef {\n /** Registered lookup source key (a foreign-key relationship), e.g. `'contractor'`. */\n source: string;\n /** Whitelisted target field key surfaced by this column, e.g. `'tax_id'`. */\n field: string;\n /** Column header, captured when the column is added (defaulted from the field's\n * translated label, user-editable in the Configure View drawer). */\n label: string;\n}\n\n/**\n * Where a copied view came from.\n *\n * The personalization decision (3 Aug 2026) accepts that a copy of a shared\n * template DRIFTS from the template \u2014 that is the point of copying rather than\n * subscribing. What it does NOT accept is drifting *invisibly*: a user must be\n * able to be told later \"the shared template changed \u2014 update yours?\".\n *\n * `version` is the template's `updatedAt` (falling back to `createdAt`) at the\n * moment of the copy. A plain ISO string rather than an integer on purpose:\n * the upstream `role_perspectives` row has no version column, and inventing one\n * would mean a migration on an entity this distribution does not own. Comparing\n * the stored stamp with the template's current stamp answers \"has it changed?\"\n * exactly, and needs no schema at all.\n */\nexport interface PerspectiveOrigin {\n /** Id of the shared template row this view was copied from. */\n templateId: string;\n /** The template's `updatedAt ?? createdAt` at copy time. */\n version: string;\n /** The template's name at copy time, so drift can be described without a refetch. */\n name: string;\n /** When the copy was taken. */\n copiedAt: string;\n}\n\n/**\n * Set on a PERSONAL view that its owner has published as a shared template.\n * Purely informational for the UI (\"Update shared template\" instead of\n * \"Publish\u2026\"); the authoritative copy lives in the role-scoped template rows.\n */\nexport interface PerspectivePublication {\n /** Roles the view is currently published to. */\n roleIds: string[];\n /** ISO stamp of the last publish. */\n publishedAt: string;\n}\n\n/**\n * How a view draws its rows.\n *\n * A property of the VIEW, not of the session \u2014 the Notion borrow, and the\n * load-bearing one. Google Drive's list/grid toggle is global and remembers one\n * preference; making the mode belong to the view is what lets \"Due for payment\"\n * and \"By counterparty\" disagree about how they want to be drawn.\n *\n * Rides `settings.filters._viewMode` \u2014 see `parseViewMode`. Unknown values\n * degrade to `'table'`; they never throw.\n */\nexport type TableViewMode = 'table' | 'grid';\n\nexport const TABLE_VIEW_MODES: readonly TableViewMode[] = ['table', 'grid'] as const;\n\nexport function isTableViewMode(value: unknown): value is TableViewMode {\n return typeof value === 'string' && (TABLE_VIEW_MODES as readonly string[]).includes(value);\n}\n\nexport interface PerspectiveConfig {\n id: string;\n name: string;\n color?: FilterColor;\n columns: ColumnConfig;\n filters: FilterRow[];\n sorting: SortRule[];\n grouping?: GroupRule[];\n /** Per-group numeric aggregations (e.g. SUM of a cost column). */\n aggregations?: AggregationRule[];\n /** Read-only linked (lookup) columns surfaced from FK-related records. */\n lookupColumns?: LookupColumnRef[];\n /**\n * Read-only aggregate (\"summarised\") columns over linked CHILD records \u2014\n * the one-to-many direction. Rides the `filters._rollups` passthrough on the\n * wire, for the same reason `_lookups` does.\n */\n rollupColumns?: RollupColumnRef[];\n /** View-scoped calculated (\"formula\") columns. Display-only; not persisted per row. */\n formulas?: FormulaColumnRef[];\n /**\n * View-scoped conditional formatting (\"Highlighting\") rules. Rides the\n * `filters._conditionalFormats` passthrough on the wire \u2014 see\n * `utils/perspectiveTransforms.ts` for why a top-level key would vanish.\n */\n conditionalFormats?: ConditionalFormatRule[];\n /**\n * Columns frozen (sticky-left) in this view, in the order they were pinned.\n *\n * Declared by the upstream fork and marked \"Not persisted by default\" for as\n * long as nothing read or wrote it \u2014 freezing a column changed a `useState`\n * Set and reached neither the server nor the browser, so it was gone on the\n * next reload (HEDGE-102).\n *\n * Rides `filters._frozenColumns` on the wire, like every other view-scoped\n * extra here. A top-level key would look right and be dropped in transit:\n * the upstream settings schema is a bare `z.object` and Zod strips what it\n * does not name. See `utils/perspectiveTransforms.ts`.\n */\n frozenColumns?: string[];\n /**\n * View-scoped date/time display format. An opaque token owned by the host\n * (e.g. a preset key its renderers understand); the table stores and\n * round-trips it but never interprets it. Undefined = no explicit choice, so\n * renderers keep their own default.\n */\n dateFormat?: string;\n /**\n * This user's default view \u2014 the one that opens when the page is entered\n * fresh. PER-USER by contract (workshop A4): `isDefault` is a first-class\n * column on the upstream `Perspective` entity, scoped to `userId`, so\n * setting it never changes what anyone else sees.\n */\n isDefault?: boolean;\n /**\n * This user's saved personalization of the BASE (\"Default view\") tab.\n *\n * Before this existed there was no save path for the base view at all \u2014\n * `ConfigureViewPanel` refused to save without a name and always minted a new\n * id \u2014 so hiding a column on the default tab survived exactly until the next\n * reload. That is the other half of workshop A5 (\"my changes disappeared\").\n *\n * It is an ordinary personal perspective row, so it is per-user by the same\n * construction as every other view; it is simply not rendered as its own tab,\n * because the tab it personalizes is already on screen.\n */\n isBaseView?: boolean;\n /**\n * Columns this view has never expressed an opinion about \u2014 present in the\n * table's config, absent from everything this view stored about columns.\n *\n * Distinct from `columns.hidden`, which is derived and therefore cannot tell\n * \"the user hid this\" from \"this column did not exist when the view was\n * saved\". Populated by `apiToDynamicTable`, which is the last place the raw\n * `columnOrder` / `columnVisibility` maps are still available.\n */\n unseenColumns?: string[];\n /** Set when this view was copied from a shared template. See `PerspectiveOrigin`. */\n origin?: PerspectiveOrigin;\n /** Set when this view has been published as a shared template. */\n publication?: PerspectivePublication;\n /**\n * How this view draws its rows. Rides `settings.filters._viewMode` for the\n * same reason `_aggregations` does \u2014 the upstream settings schema strips\n * unknown TOP-LEVEL keys, so a `viewMode` field alongside `columnOrder` would\n * be silently dropped on the way to the database and the view would forget\n * its own shape on the very first reload.\n *\n * Undefined = never chosen, which renders as `'table'`. Absence and an\n * explicit `'table'` are deliberately NOT distinguished: there is nothing a\n * user could do differently if they were.\n */\n viewMode?: TableViewMode;\n}\n\n/**\n * A view someone published for other people to COPY.\n *\n * Persisted as an upstream role-scoped perspective (`role_perspectives`), which\n * already carries `organization_id` + `tenant_id`, is already returned by\n * `GET /api/perspectives/:tableId` for the caller's own roles, and is already\n * guarded by real ACL features (`perspectives.use` to read,\n * `perspectives.role_defaults` to write). No new entity, endpoint or migration.\n *\n * A template is NEVER applied to anyone automatically \u2014 it is a thing you copy,\n * and the copy is yours. That is what makes \"no shared thing a user can silently\n * mutate\" true: publishing is explicit, and it changes nobody's active view.\n */\nexport interface PerspectiveTemplate extends PerspectiveConfig {\n /** Role this template is published to. */\n roleId: string;\n /** Human-readable role name, when the server could resolve one. */\n roleName?: string | null;\n /** `updatedAt ?? createdAt` \u2014 the version stamp a copy records. */\n version: string;\n}\n\n/** The reserved name of the personal base-view row. Never shown in the UI. */\nexport const BASE_VIEW_PERSPECTIVE_NAME = '__base__';\n\n/**\n * Longest name the perspectives API will accept.\n *\n * Mirrors `z.string().min(1).max(120)` in the upstream perspectives validator\n * (`@open-mercato/core/modules/perspectives/data/validators`). The server\n * answers a longer name with a 400 that carries no field-level detail, so the\n * UI used to close the drawer as if the view had been created and simply not\n * create one. Enforced on the INPUT instead: the field stops accepting\n * characters at the limit and says why, which is a thing the user can act on.\n *\n * If upstream ever raises the limit this constant is the only place to change \u2014\n * over-reporting here is safe (a shorter name always saves), under-reporting is\n * not.\n */\nexport const PERSPECTIVE_NAME_MAX_LENGTH = 120;\n\n// ============================================\n// PERSPECTIVE EVENT TYPES\n// ============================================\n\nexport interface PerspectiveSaveEvent {\n perspective: PerspectiveConfig;\n /**\n * Suppresses the host's success toast. Set for saves the USER did not ask for\n * explicitly \u2014 today that is the column order written back after a header\n * drag. The write still happens and a FAILURE is still reported; only the\n * \"Perspective saved\" confirmation is dropped, because one toast per dragged\n * column is noise, not feedback. Never set it for a Save the user clicked.\n */\n silent?: boolean;\n}\n\nexport interface PerspectiveSelectEvent {\n id: string | null;\n config: PerspectiveConfig | null;\n}\n\nexport interface PerspectiveRenameEvent {\n id: string;\n newName: string;\n}\n\nexport interface PerspectiveDeleteEvent {\n id: string;\n hardDelete?: boolean;\n}\n\nexport interface PerspectiveChangeEvent {\n /** Partial config - only changed fields */\n config: Partial<Omit<PerspectiveConfig, 'id' | 'name'>>;\n}\n\n/**\n * Copy an existing view under a new name (workshop A6 \u2014 \"duplicate\" is the\n * safe alternative to editing a view you rely on). The source's whole config\n * travels with the event so the host does not have to re-read it.\n */\nexport interface PerspectiveDuplicateEvent {\n sourceId: string;\n newName: string;\n perspective: PerspectiveConfig;\n}\n\n/**\n * Make this view the user's own default (workshop A4). PER-USER: the upstream\n * service demotes the caller's other views in one `nativeUpdate` and never\n * touches another user's rows.\n */\nexport interface PerspectiveSetDefaultEvent {\n id: string;\n isDefault: boolean;\n}\n\n/**\n * Publish one of MY views so colleagues can copy it. Explicit by design: a view\n * is private until its owner takes this action, and even then nobody's screen\n * changes until they copy it.\n */\nexport interface PerspectivePublishEvent {\n /** The personal view being published. */\n id: string;\n /** Roles that should see the template. */\n roleIds: string[];\n /** Template name (defaults to the view's own name, editable before publishing). */\n name: string;\n}\n\n/** Copy a shared template into my own space. The copy is mine; the template is untouched. */\nexport interface PerspectiveTemplateCopyEvent {\n template: PerspectiveTemplate;\n /** De-duplicated name for the copy. */\n newName: string;\n}\n\n// ============================================\n// TABLE EVENTS EXTENSION\n// ============================================\n\nexport const PerspectiveEvents = {\n PERSPECTIVE_SAVE: 'table:perspective:save',\n PERSPECTIVE_SELECT: 'table:perspective:select',\n PERSPECTIVE_RENAME: 'table:perspective:rename',\n PERSPECTIVE_DELETE: 'table:perspective:delete',\n PERSPECTIVE_CHANGE: 'table:perspective:change',\n PERSPECTIVE_DUPLICATE: 'table:perspective:duplicate',\n PERSPECTIVE_SET_DEFAULT: 'table:perspective:setDefault',\n PERSPECTIVE_PUBLISH: 'table:perspective:publish',\n PERSPECTIVE_TEMPLATE_COPY: 'table:perspective:templateCopy',\n} as const;\n\n// Type mapping for perspective event payloads\nexport type PerspectiveEventPayloads = {\n [PerspectiveEvents.PERSPECTIVE_SAVE]: PerspectiveSaveEvent;\n [PerspectiveEvents.PERSPECTIVE_SELECT]: PerspectiveSelectEvent;\n [PerspectiveEvents.PERSPECTIVE_RENAME]: PerspectiveRenameEvent;\n [PerspectiveEvents.PERSPECTIVE_DELETE]: PerspectiveDeleteEvent;\n [PerspectiveEvents.PERSPECTIVE_CHANGE]: PerspectiveChangeEvent;\n [PerspectiveEvents.PERSPECTIVE_DUPLICATE]: PerspectiveDuplicateEvent;\n [PerspectiveEvents.PERSPECTIVE_SET_DEFAULT]: PerspectiveSetDefaultEvent;\n [PerspectiveEvents.PERSPECTIVE_PUBLISH]: PerspectivePublishEvent;\n [PerspectiveEvents.PERSPECTIVE_TEMPLATE_COPY]: PerspectiveTemplateCopyEvent;\n};\n\n// Type for perspective event handler map\nexport type PerspectiveEventHandlers = {\n [K in keyof PerspectiveEventPayloads]?: (payload: PerspectiveEventPayloads[K]) => void;\n};\n\n// ============================================\n// UTILITY FUNCTIONS\n// ============================================\n\n/**\n * Creates a default perspective config from column definitions\n */\nexport function createDefaultPerspective(\n columns: { data: string }[],\n hiddenColumns: string[] = []\n): Omit<PerspectiveConfig, 'id' | 'name'> {\n const allColumnKeys = columns.map(col => col.data);\n const visible = allColumnKeys.filter(key => !hiddenColumns.includes(key));\n const hidden = hiddenColumns.filter(key => allColumnKeys.includes(key));\n\n return {\n columns: { visible, hidden },\n filters: [],\n sorting: [],\n grouping: [],\n aggregations: [],\n lookupColumns: [],\n rollupColumns: [],\n formulas: [],\n conditionalFormats: [],\n };\n}\n\n/**\n * Merges a partial perspective config with defaults\n */\nexport function mergePerspectiveConfig(\n base: Omit<PerspectiveConfig, 'id' | 'name'>,\n partial: Partial<Omit<PerspectiveConfig, 'id' | 'name'>>\n): Omit<PerspectiveConfig, 'id' | 'name'> {\n return {\n columns: partial.columns ?? base.columns,\n filters: partial.filters ?? base.filters,\n sorting: partial.sorting ?? base.sorting,\n grouping: partial.grouping ?? base.grouping,\n aggregations: partial.aggregations ?? base.aggregations,\n lookupColumns: partial.lookupColumns ?? base.lookupColumns,\n rollupColumns: partial.rollupColumns ?? base.rollupColumns,\n formulas: partial.formulas ?? base.formulas,\n conditionalFormats: partial.conditionalFormats ?? base.conditionalFormats,\n dateFormat: partial.dateFormat ?? base.dateFormat,\n viewMode: partial.viewMode ?? base.viewMode,\n };\n}\n\n/**\n * Generates a unique ID for new perspective items\n */\nexport function generatePerspectiveId(): string {\n return `perspective-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`;\n}\n\n/**\n * Generates a unique ID for sort rules\n */\nexport function generateSortRuleId(): string {\n return `sort-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`;\n}\n\n/**\n * Sort direction labels keyed to the column's data type. The default A\u2192Z labels\n * read as text-only and led users to think date columns weren't actually being\n * sorted chronologically.\n */\nexport type ColumnDataType = 'text' | 'numeric' | 'date' | 'dropdown' | 'boolean' | 'multiselect';\n\nexport function getSortDirectionLabels(type?: ColumnDataType): { asc: string; desc: string } {\n switch (type) {\n case 'date':\n return { asc: 'Old \u2192 New', desc: 'New \u2192 Old' };\n case 'numeric':\n return { asc: '1 \u2192 9', desc: '9 \u2192 1' };\n case 'boolean':\n return { asc: 'False \u2192 True', desc: 'True \u2192 False' };\n default:\n return { asc: 'A \u2192 Z', desc: 'Z \u2192 A' };\n }\n}\n"],
|
|
5
|
+
"mappings": "AAmGO,MAAM,mBAA6C,CAAC,SAAS,MAAM;AAEnE,SAAS,gBAAgB,OAAwC;AACtE,SAAO,OAAO,UAAU,YAAa,iBAAuC,SAAS,KAAK;AAC5F;AAwHO,MAAM,6BAA6B;AAgBnC,MAAM,8BAA8B;AAoFpC,MAAM,oBAAoB;AAAA,EAC/B,kBAAkB;AAAA,EAClB,oBAAoB;AAAA,EACpB,oBAAoB;AAAA,EACpB,oBAAoB;AAAA,EACpB,oBAAoB;AAAA,EACpB,uBAAuB;AAAA,EACvB,yBAAyB;AAAA,EACzB,qBAAqB;AAAA,EACrB,2BAA2B;AAC7B;AA2BO,SAAS,yBACd,SACA,gBAA0B,CAAC,GACa;AACxC,QAAM,gBAAgB,QAAQ,IAAI,SAAO,IAAI,IAAI;AACjD,QAAM,UAAU,cAAc,OAAO,SAAO,CAAC,cAAc,SAAS,GAAG,CAAC;AACxE,QAAM,SAAS,cAAc,OAAO,SAAO,cAAc,SAAS,GAAG,CAAC;AAEtE,SAAO;AAAA,IACL,SAAS,EAAE,SAAS,OAAO;AAAA,IAC3B,SAAS,CAAC;AAAA,IACV,SAAS,CAAC;AAAA,IACV,UAAU,CAAC;AAAA,IACX,cAAc,CAAC;AAAA,IACf,eAAe,CAAC;AAAA,IAChB,eAAe,CAAC;AAAA,IAChB,UAAU,CAAC;AAAA,IACX,oBAAoB,CAAC;AAAA,EACvB;AACF;AAKO,SAAS,uBACd,MACA,SACwC;AACxC,SAAO;AAAA,IACL,SAAS,QAAQ,WAAW,KAAK;AAAA,IACjC,SAAS,QAAQ,WAAW,KAAK;AAAA,IACjC,SAAS,QAAQ,WAAW,KAAK;AAAA,IACjC,UAAU,QAAQ,YAAY,KAAK;AAAA,IACnC,cAAc,QAAQ,gBAAgB,KAAK;AAAA,IAC3C,eAAe,QAAQ,iBAAiB,KAAK;AAAA,IAC7C,eAAe,QAAQ,iBAAiB,KAAK;AAAA,IAC7C,UAAU,QAAQ,YAAY,KAAK;AAAA,IACnC,oBAAoB,QAAQ,sBAAsB,KAAK;AAAA,IACvD,YAAY,QAAQ,cAAc,KAAK;AAAA,IACvC,UAAU,QAAQ,YAAY,KAAK;AAAA,EACrC;AACF;AAKO,SAAS,wBAAgC;AAC9C,SAAO,eAAe,KAAK,IAAI,CAAC,IAAI,KAAK,OAAO,EAAE,SAAS,EAAE,EAAE,OAAO,GAAG,CAAC,CAAC;AAC7E;AAKO,SAAS,qBAA6B;AAC3C,SAAO,QAAQ,KAAK,IAAI,CAAC,IAAI,KAAK,OAAO,EAAE,SAAS,EAAE,EAAE,OAAO,GAAG,CAAC,CAAC;AACtE;AASO,SAAS,uBAAuB,MAAsD;AAC3F,UAAQ,MAAM;AAAA,IACZ,KAAK;AACH,aAAO,EAAE,KAAK,kBAAa,MAAM,iBAAY;AAAA,IAC/C,KAAK;AACH,aAAO,EAAE,KAAK,cAAS,MAAM,aAAQ;AAAA,IACvC,KAAK;AACH,aAAO,EAAE,KAAK,qBAAgB,MAAM,oBAAe;AAAA,IACrD;AACE,aAAO,EAAE,KAAK,cAAS,MAAM,aAAQ;AAAA,EACzC;AACF;",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
const ROLLUP_FNS = ["count", "sum", "avg", "min", "max"];
|
|
2
|
+
function isRollupFn(value) {
|
|
3
|
+
return typeof value === "string" && ROLLUP_FNS.includes(value);
|
|
4
|
+
}
|
|
5
|
+
const ROLLUP_COUNT_FIELD = "id";
|
|
6
|
+
const MAX_ROLLUP_COLUMNS = 20;
|
|
7
|
+
export {
|
|
8
|
+
MAX_ROLLUP_COLUMNS,
|
|
9
|
+
ROLLUP_COUNT_FIELD,
|
|
10
|
+
ROLLUP_FNS,
|
|
11
|
+
isRollupFn
|
|
12
|
+
};
|
|
13
|
+
//# sourceMappingURL=rollup.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../../../src/backend/dynamic-table/types/rollup.ts"],
|
|
4
|
+
"sourcesContent": ["// types/rollup.ts\n//\n// Rollup (\"summarised\") columns \u2014 the ONE-TO-MANY sibling of a linked (lookup)\n// column.\n//\n// LookupColumnRef: the FK lives on the HOST row (many-to-one)\n// \"this folder's contractor's tax id\"\n//\n// RollupColumnRef: the FK lives on the CHILD row (one-to-many)\n// \"the SUM of this folder's cost lines\"\n//\n// Everything here is a plain type: `packages/ui` never learns what a\n// `folder_line` is. The contract with a host module is one opaque string key\n// on the row \u2014 `rollup__<source>__<field>__<fn>` \u2014 exactly as it is for lookups.\n//\n// EXPORT SITE. These names are declared here and re-exported by `types/index`\n// (which the package barrel `export *`s). `utils/rollupColumns.ts` imports them\n// type-only and does NOT re-export: two `export *` sources for one name make ES\n// drop it silently, which is how `FormulaColumnRef` was nearly lost.\n\n/**\n * Aggregate applied to the linked child records. Deliberately NOT the same type\n * as grouping's `AggregationFn`: that one aggregates rows *within a group on\n * this page*, this one aggregates *records in another table*. Coupling them\n * would let one union widen and silently offer functions the server-side\n * resolver cannot emit.\n */\nexport type RollupFn = 'count' | 'sum' | 'avg' | 'min' | 'max';\n\nexport const ROLLUP_FNS: readonly RollupFn[] = ['count', 'sum', 'avg', 'min', 'max'] as const;\n\nexport function isRollupFn(value: unknown): value is RollupFn {\n return typeof value === 'string' && (ROLLUP_FNS as readonly string[]).includes(value);\n}\n\n/**\n * The child column `count` aggregates. `COUNT(child.id)` is exactly \"number of\n * linked records\" because id is NOT NULL, and it keeps a `'*'` sentinel out of\n * column keys, perspective JSON, URL params and test selectors.\n *\n * MUST match `ROLLUP_COUNT_FIELD` on the server side of whichever module\n * answers the list route \u2014 it is half of the wire key.\n */\nexport const ROLLUP_COUNT_FIELD = 'id';\n\n/**\n * A read-only column summarising the records that point AT this row.\n * View-scoped: it lives in the perspective (persisted through the\n * `filters._rollups` passthrough), never in a database table.\n */\nexport interface RollupColumnRef {\n /** Registered rollup source key (a one-to-many relationship), e.g. `'lines'`. */\n source: string;\n /** Child column aggregated; {@link ROLLUP_COUNT_FIELD} when `fn` is `'count'`. */\n field: string;\n fn: RollupFn;\n /** Column header, captured when the column is added (`Source \u00B7 Fn of Field`). */\n label: string;\n}\n\n/** A child field a rollup source will let you aggregate. */\nexport interface RollupSourceFieldOption {\n /** Child column, e.g. `'estimated_cost'`. */\n key: string;\n /** Already translated by the host loader. */\n label: string;\n type: 'numeric' | 'integer' | 'date';\n /** Which aggregates make sense here. `count` is never listed \u2014 it is always\n * available and needs no field. */\n fns: Array<Exclude<RollupFn, 'count'>>;\n}\n\n/**\n * A one-to-many relationship a table can summarise. Supplied by the host\n * (which knows its `tableId`) via {@link LoadRollupSources}, so `packages/ui`\n * never imports the host's rollup registry.\n */\nexport interface RollupSourceOption {\n key: string;\n /** Translated relationship label, e.g. `'Cost lines'`. */\n label: string;\n /** Noun for the count column, e.g. `'Lines'`. Count is always offered. */\n countLabel: string;\n /** Aggregatable child fields. Empty = a count-only source, which is legitimate. */\n fields: RollupSourceFieldOption[];\n /** Host-declared: can the list route ORDER BY this rollup? */\n sortable?: boolean;\n /** Host-declared: can the list route FILTER on this rollup? */\n filterable?: boolean;\n /** False when the host row grain repeats the same total, so a subtotal would\n * double-count. Carried through for the grouping/footer surfaces. */\n aggregatable?: boolean;\n}\n\n/**\n * Loads the rollup sources available for this table. When provided, the\n * Configure View drawer shows a \"Summarised columns\" section. Called lazily\n * when that section is opened.\n *\n * Symmetric with `LoadLookupSources` on purpose \u2014 a host wires the two the same\n * way.\n */\nexport type LoadRollupSources = () => Promise<RollupSourceOption[]>;\n\n/**\n * Hard cap on rollup columns in one view. Each distinct SOURCE costs one\n * `GROUP BY` on every request of every user of that view, so this is a cost\n * ceiling, not a taste judgement. Matches the server-side `MAX_ROLLUPS`; going\n * above it would have requests silently truncated instead of refused.\n */\nexport const MAX_ROLLUP_COLUMNS = 20;\n"],
|
|
5
|
+
"mappings": "AA6BO,MAAM,aAAkC,CAAC,SAAS,OAAO,OAAO,OAAO,KAAK;AAE5E,SAAS,WAAW,OAAmC;AAC5D,SAAO,OAAO,UAAU,YAAa,WAAiC,SAAS,KAAK;AACtF;AAUO,MAAM,qBAAqB;AAmE3B,MAAM,qBAAqB;",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|
|
@@ -0,0 +1,228 @@
|
|
|
1
|
+
const ABBREV_FACILITY = "facility";
|
|
2
|
+
const ABBREV_CONTRACTOR = "contractor";
|
|
3
|
+
const RESOLVED_CACHE_LIMIT = 4096;
|
|
4
|
+
const registry = /* @__PURE__ */ new Map();
|
|
5
|
+
let version = 0;
|
|
6
|
+
const listeners = /* @__PURE__ */ new Set();
|
|
7
|
+
function notifyAbbreviationChange() {
|
|
8
|
+
version += 1;
|
|
9
|
+
for (const listener of listeners) {
|
|
10
|
+
try {
|
|
11
|
+
listener();
|
|
12
|
+
} catch {
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
function subscribeAbbreviations(listener) {
|
|
17
|
+
listeners.add(listener);
|
|
18
|
+
return () => {
|
|
19
|
+
listeners.delete(listener);
|
|
20
|
+
};
|
|
21
|
+
}
|
|
22
|
+
function stateFor(namespace) {
|
|
23
|
+
let state = registry.get(namespace);
|
|
24
|
+
if (!state) {
|
|
25
|
+
state = { runtime: /* @__PURE__ */ new Map(), seed: /* @__PURE__ */ new Map(), resolved: /* @__PURE__ */ new Map() };
|
|
26
|
+
registry.set(namespace, state);
|
|
27
|
+
}
|
|
28
|
+
return state;
|
|
29
|
+
}
|
|
30
|
+
const DIACRITIC_MAP = {
|
|
31
|
+
\u0105: "a",
|
|
32
|
+
\u0107: "c",
|
|
33
|
+
\u0119: "e",
|
|
34
|
+
\u0142: "l",
|
|
35
|
+
\u0144: "n",
|
|
36
|
+
\u00F3: "o",
|
|
37
|
+
\u015B: "s",
|
|
38
|
+
\u017A: "z",
|
|
39
|
+
\u017C: "z",
|
|
40
|
+
\u00E0: "a",
|
|
41
|
+
\u00E1: "a",
|
|
42
|
+
\u00E2: "a",
|
|
43
|
+
\u00E3: "a",
|
|
44
|
+
\u00E4: "a",
|
|
45
|
+
\u00E5: "a",
|
|
46
|
+
\u00E8: "e",
|
|
47
|
+
\u00E9: "e",
|
|
48
|
+
\u00EA: "e",
|
|
49
|
+
\u00EB: "e",
|
|
50
|
+
\u00EC: "i",
|
|
51
|
+
\u00ED: "i",
|
|
52
|
+
\u00EE: "i",
|
|
53
|
+
\u00EF: "i",
|
|
54
|
+
\u00F2: "o",
|
|
55
|
+
\u00F4: "o",
|
|
56
|
+
\u00F5: "o",
|
|
57
|
+
\u00F6: "o",
|
|
58
|
+
\u00F8: "o",
|
|
59
|
+
\u00F9: "u",
|
|
60
|
+
\u00FA: "u",
|
|
61
|
+
\u00FB: "u",
|
|
62
|
+
\u00FC: "u",
|
|
63
|
+
\u00FD: "y",
|
|
64
|
+
\u00FF: "y",
|
|
65
|
+
\u00F1: "n",
|
|
66
|
+
\u00E7: "c",
|
|
67
|
+
\u0161: "s",
|
|
68
|
+
\u017E: "z",
|
|
69
|
+
\u010D: "c",
|
|
70
|
+
\u0159: "r",
|
|
71
|
+
\u011B: "e",
|
|
72
|
+
\u016F: "u",
|
|
73
|
+
\u00DF: "ss",
|
|
74
|
+
\u00E6: "ae"
|
|
75
|
+
};
|
|
76
|
+
const DIACRITIC_PATTERN = /[ąćęłńóśźżàáâãäåèéêëìíîïòôõöøùúûüýÿñçšžčřěůßæ]/g;
|
|
77
|
+
const WHITESPACE_PATTERN = /\s+/g;
|
|
78
|
+
function normalizeAbbreviationKey(value) {
|
|
79
|
+
const lowered = value.toLowerCase();
|
|
80
|
+
const folded = DIACRITIC_PATTERN.test(lowered) ? (
|
|
81
|
+
// `.test` on a /g regex advances lastIndex; reset before reuse.
|
|
82
|
+
(DIACRITIC_PATTERN.lastIndex = 0, lowered.replace(DIACRITIC_PATTERN, (ch) => DIACRITIC_MAP[ch] ?? ch))
|
|
83
|
+
) : lowered;
|
|
84
|
+
DIACRITIC_PATTERN.lastIndex = 0;
|
|
85
|
+
return folded.replace(WHITESPACE_PATTERN, " ").trim();
|
|
86
|
+
}
|
|
87
|
+
function registerAbbreviations(namespace, entries, options) {
|
|
88
|
+
const state = stateFor(namespace);
|
|
89
|
+
if (!options?.merge) state.runtime.clear();
|
|
90
|
+
indexInto(state.runtime, entries);
|
|
91
|
+
state.resolved.clear();
|
|
92
|
+
notifyAbbreviationChange();
|
|
93
|
+
}
|
|
94
|
+
function registerAbbreviationSeed(namespace, entries, options) {
|
|
95
|
+
const state = stateFor(namespace);
|
|
96
|
+
if (!options?.merge) state.seed.clear();
|
|
97
|
+
indexInto(state.seed, entries);
|
|
98
|
+
state.resolved.clear();
|
|
99
|
+
notifyAbbreviationChange();
|
|
100
|
+
}
|
|
101
|
+
function indexInto(layer, entries) {
|
|
102
|
+
for (const entry of entries) {
|
|
103
|
+
if (!entry || !entry.short) continue;
|
|
104
|
+
for (const raw of entry.match) {
|
|
105
|
+
if (typeof raw !== "string") continue;
|
|
106
|
+
const key = normalizeAbbreviationKey(raw);
|
|
107
|
+
if (key) layer.set(key, entry);
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
function lookupAbbreviation(namespace, value) {
|
|
112
|
+
if (!value) return null;
|
|
113
|
+
const state = registry.get(namespace);
|
|
114
|
+
if (!state) return null;
|
|
115
|
+
const cached = state.resolved.get(value);
|
|
116
|
+
if (cached !== void 0) return cached;
|
|
117
|
+
const key = normalizeAbbreviationKey(value);
|
|
118
|
+
const found = state.runtime.get(key) ?? state.seed.get(key) ?? null;
|
|
119
|
+
if (state.resolved.size >= RESOLVED_CACHE_LIMIT) state.resolved.clear();
|
|
120
|
+
state.resolved.set(value, found);
|
|
121
|
+
return found;
|
|
122
|
+
}
|
|
123
|
+
function abbreviate(namespace, value) {
|
|
124
|
+
return lookupAbbreviation(namespace, value)?.short ?? null;
|
|
125
|
+
}
|
|
126
|
+
function abbreviationsVersion() {
|
|
127
|
+
return version;
|
|
128
|
+
}
|
|
129
|
+
function resetAbbreviations() {
|
|
130
|
+
registry.clear();
|
|
131
|
+
notifyAbbreviationChange();
|
|
132
|
+
installDefaultSeed();
|
|
133
|
+
}
|
|
134
|
+
function getAbbreviationSnapshot(namespace) {
|
|
135
|
+
const state = registry.get(namespace);
|
|
136
|
+
return {
|
|
137
|
+
runtime: state?.runtime.size ?? 0,
|
|
138
|
+
seed: state?.seed.size ?? 0,
|
|
139
|
+
cached: state?.resolved.size ?? 0
|
|
140
|
+
};
|
|
141
|
+
}
|
|
142
|
+
const MAX_ABBREVIATION_LENGTH = 8;
|
|
143
|
+
function looksLikeHumanCode(candidate) {
|
|
144
|
+
return candidate.length > 0 && candidate.length <= MAX_ABBREVIATION_LENGTH;
|
|
145
|
+
}
|
|
146
|
+
function facilityToAbbreviation(row) {
|
|
147
|
+
const curated = row.shortName?.trim();
|
|
148
|
+
const code = row.code?.trim();
|
|
149
|
+
const locode = row.locode?.trim();
|
|
150
|
+
const short = curated || (code && looksLikeHumanCode(code) ? code : "") || (locode && looksLikeHumanCode(locode) ? locode : "");
|
|
151
|
+
if (!short) return null;
|
|
152
|
+
const match = [];
|
|
153
|
+
if (row.name?.trim()) match.push(row.name.trim());
|
|
154
|
+
if (row.code?.trim()) match.push(row.code.trim());
|
|
155
|
+
if (row.locode?.trim()) match.push(row.locode.trim());
|
|
156
|
+
if (match.length === 0) return null;
|
|
157
|
+
return { match, short, full: row.name?.trim() || void 0 };
|
|
158
|
+
}
|
|
159
|
+
function contractorToAbbreviation(row) {
|
|
160
|
+
const short = row.shortName?.trim();
|
|
161
|
+
const name = row.name?.trim();
|
|
162
|
+
if (!short || !name || short === name) return null;
|
|
163
|
+
return { match: [name], short, full: name };
|
|
164
|
+
}
|
|
165
|
+
const BALTIC_TERMINAL_SEED = [
|
|
166
|
+
{
|
|
167
|
+
match: ["Baltic Container Terminal", "Baltic Container Terminal Gdynia", "BCT Gdynia", "BCT"],
|
|
168
|
+
short: "BCT",
|
|
169
|
+
full: "Baltic Container Terminal Gdynia"
|
|
170
|
+
},
|
|
171
|
+
{
|
|
172
|
+
match: ["Gdynia Container Terminal", "GCT Gdynia", "GCT"],
|
|
173
|
+
short: "GCT",
|
|
174
|
+
full: "Gdynia Container Terminal"
|
|
175
|
+
},
|
|
176
|
+
{
|
|
177
|
+
match: ["Baltic Hub", "Baltic Hub Container Terminal", "DCT Gdansk", "DCT Gda\u0144sk", "BHCT", "DCT"],
|
|
178
|
+
short: "BHCT",
|
|
179
|
+
full: "Baltic Hub Container Terminal (ex DCT Gda\u0144sk)"
|
|
180
|
+
},
|
|
181
|
+
{
|
|
182
|
+
match: ["Gdansk Container Terminal", "Gda\u0144sk Container Terminal", "GTK", "GTK Gdansk"],
|
|
183
|
+
short: "GTK",
|
|
184
|
+
full: "Gda\u0144ski Terminal Kontenerowy"
|
|
185
|
+
},
|
|
186
|
+
{
|
|
187
|
+
match: ["Port Gdansk", "Port Gda\u0144sk", "Port of Gdansk", "Port of Gda\u0144sk", "PLGDN"],
|
|
188
|
+
short: "GDN",
|
|
189
|
+
full: "Port Gda\u0144sk"
|
|
190
|
+
},
|
|
191
|
+
{
|
|
192
|
+
match: ["Port Gdynia", "Port of Gdynia", "PLGDY"],
|
|
193
|
+
short: "GDY",
|
|
194
|
+
full: "Port Gdynia"
|
|
195
|
+
},
|
|
196
|
+
{
|
|
197
|
+
match: ["Port Szczecin", "Port of Szczecin", "PLSZZ"],
|
|
198
|
+
short: "SZZ",
|
|
199
|
+
full: "Port Szczecin"
|
|
200
|
+
},
|
|
201
|
+
{
|
|
202
|
+
match: ["Port Swinoujscie", "Port \u015Awinouj\u015Bcie", "Port of Swinoujscie", "PLSWI"],
|
|
203
|
+
short: "SWI",
|
|
204
|
+
full: "Port \u015Awinouj\u015Bcie"
|
|
205
|
+
}
|
|
206
|
+
];
|
|
207
|
+
function installDefaultSeed() {
|
|
208
|
+
registerAbbreviationSeed(ABBREV_FACILITY, BALTIC_TERMINAL_SEED);
|
|
209
|
+
}
|
|
210
|
+
installDefaultSeed();
|
|
211
|
+
export {
|
|
212
|
+
ABBREV_CONTRACTOR,
|
|
213
|
+
ABBREV_FACILITY,
|
|
214
|
+
BALTIC_TERMINAL_SEED,
|
|
215
|
+
abbreviate,
|
|
216
|
+
abbreviationsVersion,
|
|
217
|
+
contractorToAbbreviation,
|
|
218
|
+
facilityToAbbreviation,
|
|
219
|
+
getAbbreviationSnapshot,
|
|
220
|
+
looksLikeHumanCode,
|
|
221
|
+
lookupAbbreviation,
|
|
222
|
+
normalizeAbbreviationKey,
|
|
223
|
+
registerAbbreviationSeed,
|
|
224
|
+
registerAbbreviations,
|
|
225
|
+
resetAbbreviations,
|
|
226
|
+
subscribeAbbreviations
|
|
227
|
+
};
|
|
228
|
+
//# sourceMappingURL=abbreviations.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../../../src/backend/dynamic-table/utils/abbreviations.ts"],
|
|
4
|
+
"sourcesContent": ["/**\n * Central abbreviation registry for dense grid labels.\n *\n * \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n * WHY THIS FILE EXISTS, AND WHAT IT IS DELIBERATELY *NOT*\n *\n * Workshop item A9 (3 Aug 2026): labels must shorten \u2014 ports must render as\n * terminal codes (\"BCT\", \"GCT\", \"BHCT\") rather than \"Port Gdansk\". Agnieszka's\n * hard constraint was recorded verbatim: *\"nie zebysmy co fajl zmieniali\"* \u2014\n * the mapping must be configured CENTRALLY, in ONE place, not re-declared per\n * table, per page, or per column.\n *\n * So the first question is: where does the mapping actually LIVE?\n *\n * \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n * IT ALREADY LIVES IN THE DATABASE. THIS FILE IS NOT THE SOURCE OF TRUTH.\n *\n * Searching before building found that FMS already has the curated data and\n * already has the admin screen:\n *\n * - `facilities.short_name` \u2014 text, nullable, added by\n * `Migration20260722120000_facility_short_name`. Its own doc comment says\n * it is the \"curated abbreviation shown in dense list views\". Editable at\n * `/backend/facilities` (`packages/facilities/.../backend/facilities/page.tsx`)\n * and through the terminal/port drawers.\n * - `facilities.code` / `facilities.locode` \u2014 the terminal's own identifier\n * (this is literally where \"BCT\" is stored).\n * - `contractors.short_name` \u2014 same idea, and the workshop notes confirm it\n * is already live and working.\n *\n * There is therefore NO case for a second, code-owned mapping table, and no\n * case for building a new admin UI. Answering the question the task asks\n * directly: **yes, the mapping should be database-backed with an admin screen,\n * and it already is.** The gap is not storage and not administration \u2014 it is\n * *delivery*: nothing currently carries those curated strings into the grid's\n * render path, so cells still show the long `name`.\n *\n * This file is that delivery mechanism, and nothing more: a process-local,\n * O(1) lookup that the app populates ONCE from the existing tables.\n *\n * \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n * THE SMALLEST v1 THAT IS CENTRAL WITHOUT NEEDING NEW ADMIN UI\n *\n * 1. On app boot (one call site \u2014 see the wiring contract), fetch the\n * facility dictionary (`/api/facilities/unified`, projecting\n * `{ id, name, code, shortName, locode }`) and call\n * `registerAbbreviations(ABBREV_FACILITY, \u2026)` once.\n * 2. Same for contractors, from `contractors.short_name`.\n * 3. Every grid on every page then abbreviates identically, because they all\n * read this one registry. Changing a label is an edit in the facilities\n * admin screen \u2014 not a code change, and not a per-file change.\n *\n * That is central by Agnieszka's definition, requires no new screen, no new\n * table, and no new migration.\n *\n * \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n * PRECEDENCE \u2014 three layers, highest first\n *\n * 1. RUNTIME \u2014 registered from the DB. Curated by staff. Always wins.\n * 2. SEED \u2014 the small static table at the bottom of this file. Covers\n * the Polish terminals everyone at INF says out loud, so a\n * fresh/unseeded deployment is still readable on day one.\n * 3. (none) \u2014 caller falls back to the full value. A missing abbreviation\n * renders the long name; it never renders blank.\n *\n * A deployment \"overrides or extends\" the mapping by editing the DATABASE\n * (layer 1), which by construction outranks anything shipped in code. The seed\n * exists only so that layer 1 being empty is not a blank-screen scenario. No\n * deployment should ever need to fork this file \u2014 if one does, that is the bug.\n *\n * \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n * PERFORMANCE \u2014 this runs in thousands of cells per render pass\n *\n * The grid virtualizes ROWS ONLY (`VirtualRow` does a plain `columns.map`), so\n * every column of every mounted row calls into here on every pass. Two rules\n * follow, and both are load-bearing:\n *\n * - NEVER scan an array per cell. Lookups are `Map.get`, built once at\n * registration time.\n * - NEVER normalize per cell in steady state. Normalization (case-folding,\n * diacritic-folding, whitespace collapse) allocates strings, so every raw\n * input string is normalized AT MOST ONCE and the *resolved answer* is\n * memoized against the raw input. A freight grid shows the same ~20 ports\n * across 5 000 rows, so the hit rate here is essentially 100%: the second\n * through five-thousandth cell each cost one `Map.get` on the original\n * string and nothing else \u2014 no allocation, no regex, no lowercase.\n *\n * Everything here is a pure function of (registry contents, input). The\n * registry is versioned so memoized consumers can invalidate; see\n * `abbreviationsVersion()`.\n */\n\n/**\n * Namespaces keep unrelated dictionaries from colliding: a contractor called\n * \"Baltic\" must not be abbreviated by a port rule that happens to match.\n *\n * A plain string type (rather than a closed union) is deliberate \u2014 a Tier-3 app\n * or a future module can register its own dictionary without this file, in the\n * `@freighttech/ui` package, needing to know it exists.\n */\nexport type AbbreviationNamespace = string\n\n/** Facilities: ports, terminals, airports, depots. Fed from `facilities`. */\nexport const ABBREV_FACILITY: AbbreviationNamespace = 'facility'\n/** Contractors. Fed from `contractors.short_name`. */\nexport const ABBREV_CONTRACTOR: AbbreviationNamespace = 'contractor'\n\n/**\n * One row of the dictionary.\n *\n * `match` is everything that should resolve to `short`. For a facility that is\n * its name, its code, its LOCODE and any alias \u2014 all pointing at one label, so\n * a grid column bound to the name and another bound to the code both abbreviate\n * to the same thing.\n */\nexport type AbbreviationEntry = {\n /**\n * Values that resolve to `short`. Matched after normalization (case- and\n * diacritic-insensitive), so \"Port Gda\u0144sk\", \"port gdansk\" and \"PORT GDANSK\"\n * are one key.\n */\n match: readonly string[]\n /** The compact label rendered in the cell, e.g. \"BCT\". */\n short: string\n /**\n * The full value to show on hover. Optional \u2014 when absent the caller uses the\n * raw cell value, which is usually the better tooltip anyway.\n */\n full?: string\n}\n\ntype Layer = Map<string, AbbreviationEntry>\n\ntype NamespaceState = {\n /** From the database. Curated. Wins. */\n runtime: Layer\n /** Static fallback shipped in code. */\n seed: Layer\n /**\n * Memoized answers keyed by the RAW (un-normalized) input string. This is the\n * hot path: in steady state every cell lookup terminates here.\n *\n * Holds `null` for known-misses too \u2014 a miss is just as worth caching as a\n * hit, and a grid full of un-curated values would otherwise re-normalize on\n * every pass.\n */\n resolved: Map<string, AbbreviationEntry | null>\n}\n\n/**\n * Upper bound on the memo cache, per namespace.\n *\n * A dictionary lookup column is inherently low-cardinality (ports, contractors,\n * people) so this is never reached in practice. It exists to bound the damage\n * if someone points a namespaced lookup at a high-cardinality column such as a\n * container number: without a cap the cache would grow with the dataset and\n * become a leak. On overflow the cache is cleared wholesale rather than evicted\n * LRU \u2014 an LRU needs bookkeeping on every *hit*, which is exactly the operation\n * that has to stay free.\n */\nconst RESOLVED_CACHE_LIMIT = 4096\n\nconst registry = new Map<AbbreviationNamespace, NamespaceState>()\n\nlet version = 0\n\n/**\n * Change subscribers.\n *\n * The dictionary is fetched ONCE at app boot, which means every grid mounted\n * before that fetch resolves has already rendered its cells with the long\n * names. `lookupAbbreviation` would return the right answer on the NEXT render\n * \u2014 but nothing was scheduling one, so the delivery silently appeared to do\n * nothing until the user happened to sort or page.\n *\n * A version counter alone cannot fix that: React has no way to observe a plain\n * module-level integer. So registration notifies, and `useAbbreviationsVersion`\n * turns that into a `useSyncExternalStore` subscription.\n *\n * Deliberately a plain Set of thunks rather than an event emitter: this fires\n * once or twice in the lifetime of a page, so there is nothing to optimise, and\n * a listener that throws must not prevent the others from being told.\n */\nconst listeners = new Set<() => void>()\n\nfunction notifyAbbreviationChange(): void {\n version += 1\n for (const listener of listeners) {\n try {\n listener()\n } catch {\n // A broken subscriber must not stop the dictionary reaching the rest.\n }\n }\n}\n\n/**\n * Subscribe to dictionary changes. Returns an unsubscribe function.\n *\n * Pair with {@link abbreviationsVersion} as the snapshot \u2014 that is exactly the\n * `useSyncExternalStore` contract, and `useAbbreviationsVersion` is the hook\n * that wires the two together.\n */\nexport function subscribeAbbreviations(listener: () => void): () => void {\n listeners.add(listener)\n return () => {\n listeners.delete(listener)\n }\n}\n\nfunction stateFor(namespace: AbbreviationNamespace): NamespaceState {\n let state = registry.get(namespace)\n if (!state) {\n state = { runtime: new Map(), seed: new Map(), resolved: new Map() }\n registry.set(namespace, state)\n }\n return state\n}\n\n/**\n * Polish (and general Latin-1) diacritic folding.\n *\n * Precomputed as a single character-class regex plus an object lookup, both\n * built ONCE at module scope. The alternative \u2014 `String.prototype.normalize`\n * \u2014 is correct but allocates an intermediate NFD string on every call, and\n * `\u0142` is not decomposable by NFD anyway (it is a distinct letter, not `l` plus\n * a combining mark), so normalize alone would still miss the single most\n * common Polish case: \"Gda\u0144sk\"/\"Gdansk\" is fine but \"\u0141\u00F3d\u017A\"/\"Lodz\" is not.\n */\nconst DIACRITIC_MAP: Readonly<Record<string, string>> = {\n \u0105: 'a', \u0107: 'c', \u0119: 'e', \u0142: 'l', \u0144: 'n', \u00F3: 'o', \u015B: 's', \u017A: 'z', \u017C: 'z',\n \u00E0: 'a', \u00E1: 'a', \u00E2: 'a', \u00E3: 'a', \u00E4: 'a', \u00E5: 'a',\n \u00E8: 'e', \u00E9: 'e', \u00EA: 'e', \u00EB: 'e',\n \u00EC: 'i', \u00ED: 'i', \u00EE: 'i', \u00EF: 'i',\n \u00F2: 'o', \u00F4: 'o', \u00F5: 'o', \u00F6: 'o', \u00F8: 'o',\n \u00F9: 'u', \u00FA: 'u', \u00FB: 'u', \u00FC: 'u',\n \u00FD: 'y', \u00FF: 'y', \u00F1: 'n', \u00E7: 'c', \u0161: 's', \u017E: 'z', \u010D: 'c', \u0159: 'r', \u011B: 'e', \u016F: 'u',\n \u00DF: 'ss', \u00E6: 'ae',\n}\n\n/** Compiled once. Never inside a function \u2014 that would recompile per cell. */\nconst DIACRITIC_PATTERN = /[\u0105\u0107\u0119\u0142\u0144\u00F3\u015B\u017A\u017C\u00E0\u00E1\u00E2\u00E3\u00E4\u00E5\u00E8\u00E9\u00EA\u00EB\u00EC\u00ED\u00EE\u00EF\u00F2\u00F4\u00F5\u00F6\u00F8\u00F9\u00FA\u00FB\u00FC\u00FD\u00FF\u00F1\u00E7\u0161\u017E\u010D\u0159\u011B\u016F\u00DF\u00E6]/g\n\nconst WHITESPACE_PATTERN = /\\s+/g\n\n/**\n * Fold a raw value to its lookup key.\n *\n * Case-insensitive, diacritic-insensitive, whitespace-collapsed. NOT free \u2014\n * it allocates \u2014 which is exactly why `lookupAbbreviation` memoizes on the raw\n * string and only ever reaches this on a cache miss.\n */\nexport function normalizeAbbreviationKey(value: string): string {\n const lowered = value.toLowerCase()\n const folded = DIACRITIC_PATTERN.test(lowered)\n ? // `.test` on a /g regex advances lastIndex; reset before reuse.\n ((DIACRITIC_PATTERN.lastIndex = 0),\n lowered.replace(DIACRITIC_PATTERN, (ch) => DIACRITIC_MAP[ch] ?? ch))\n : lowered\n DIACRITIC_PATTERN.lastIndex = 0\n return folded.replace(WHITESPACE_PATTERN, ' ').trim()\n}\n\n/**\n * Install (or replace) the RUNTIME layer for a namespace \u2014 the database-backed,\n * highest-precedence dictionary.\n *\n * Call this ONCE per namespace at app boot, from ONE place. It is not a\n * per-table or per-page API; wiring it into a page component is the \"co fajl\n * zmieniali\" failure mode this file exists to prevent.\n *\n * Replaces rather than merges by default, so a refetch cannot leave tombstones\n * of entries that were deleted in the admin screen. Pass `{ merge: true }` when\n * feeding a dictionary in pages.\n */\nexport function registerAbbreviations(\n namespace: AbbreviationNamespace,\n entries: readonly AbbreviationEntry[],\n options?: { merge?: boolean },\n): void {\n const state = stateFor(namespace)\n if (!options?.merge) state.runtime.clear()\n indexInto(state.runtime, entries)\n // Any cached answer may now be stale \u2014 including cached MISSES, which is the\n // common case: the grid rendered before the dictionary arrived.\n state.resolved.clear()\n notifyAbbreviationChange()\n}\n\n/**\n * Install the SEED layer \u2014 the static, lowest-precedence fallback.\n *\n * Exposed so a Tier-3 deployment can extend the shipped defaults for its own\n * trade lane without forking this file, while still losing cleanly to whatever\n * staff curate in the admin screen.\n */\nexport function registerAbbreviationSeed(\n namespace: AbbreviationNamespace,\n entries: readonly AbbreviationEntry[],\n options?: { merge?: boolean },\n): void {\n const state = stateFor(namespace)\n if (!options?.merge) state.seed.clear()\n indexInto(state.seed, entries)\n state.resolved.clear()\n notifyAbbreviationChange()\n}\n\nfunction indexInto(layer: Layer, entries: readonly AbbreviationEntry[]): void {\n for (const entry of entries) {\n if (!entry || !entry.short) continue\n for (const raw of entry.match) {\n if (typeof raw !== 'string') continue\n const key = normalizeAbbreviationKey(raw)\n // An empty key would match every blank cell.\n if (key) layer.set(key, entry)\n }\n }\n}\n\n/**\n * Resolve a raw cell value to its dictionary entry, or `null` if uncurated.\n *\n * THE HOT PATH. In steady state this is one `Map.get` against the original\n * string: no allocation, no lowercase, no regex. Pure with respect to registry\n * contents \u2014 see `abbreviationsVersion()` for invalidating downstream memos.\n */\nexport function lookupAbbreviation(\n namespace: AbbreviationNamespace,\n value: string | null | undefined,\n): AbbreviationEntry | null {\n if (!value) return null\n const state = registry.get(namespace)\n if (!state) return null\n\n const cached = state.resolved.get(value)\n // `undefined` = never asked. `null` = asked, genuinely absent.\n if (cached !== undefined) return cached\n\n const key = normalizeAbbreviationKey(value)\n const found = state.runtime.get(key) ?? state.seed.get(key) ?? null\n\n if (state.resolved.size >= RESOLVED_CACHE_LIMIT) state.resolved.clear()\n state.resolved.set(value, found)\n return found\n}\n\n/**\n * Convenience: the compact label, or `null`.\n *\n * Callers should fall back to the full value on `null` \u2014 never to a blank cell,\n * and never to a guess. An abbreviation nobody curated is not better than the\n * name; a WRONG abbreviation is strictly worse than a long one, because the\n * operator can no longer tell two terminals apart.\n */\nexport function abbreviate(\n namespace: AbbreviationNamespace,\n value: string | null | undefined,\n): string | null {\n return lookupAbbreviation(namespace, value)?.short ?? null\n}\n\n/**\n * Monotonic counter, bumped on every registration.\n *\n * Consumers that memoize derived output (a `useMemo` over a column's rendered\n * labels, a precomputed initials index) must include this in their dependency\n * list, otherwise the grid keeps showing long names after the dictionary loads.\n */\nexport function abbreviationsVersion(): number {\n return version\n}\n\n/**\n * Drop everything. Test-support only \u2014 production code has no reason to\n * un-register a dictionary.\n */\nexport function resetAbbreviations(): void {\n registry.clear()\n notifyAbbreviationChange()\n installDefaultSeed()\n}\n\n/**\n * Read-only view of a namespace, for debugging and for the Debugger panel.\n * Allocates; never call from a render path.\n */\nexport function getAbbreviationSnapshot(namespace: AbbreviationNamespace): {\n runtime: number\n seed: number\n cached: number\n} {\n const state = registry.get(namespace)\n return {\n runtime: state?.runtime.size ?? 0,\n seed: state?.seed.size ?? 0,\n cached: state?.resolved.size ?? 0,\n }\n}\n\n/**\n * Adapt a facility row straight from the DB/API into a dictionary entry.\n *\n * Encodes the precedence the facilities module already implies: the curated\n * `short_name` is the label if present, otherwise the facility's own `code`\n * (which for terminals IS \"BCT\"/\"GCT\"/\"DCT\"), otherwise the LOCODE. If none of\n * the three exist the facility is skipped entirely rather than guessed at \u2014 an\n * uncurated facility renders its full name, which is correct behaviour.\n *\n * Every identifier the row carries becomes a `match`, so a column bound to\n * `name`, one bound to `code` and one bound to `locode` all abbreviate alike.\n */\n/**\n * Longest string still worth calling an abbreviation.\n *\n * Sized from the real identifiers: a terminal trade code is 3\u20134 characters\n * (\"BCT\", \"BHCT\"), a UN/LOCODE is exactly 5 (\"PLGDN\"), and an IATA code is 3.\n * Eight leaves headroom for a curated oddity while still rejecting the thing\n * this constant exists to reject \u2014 see `looksLikeHumanCode`.\n */\nconst MAX_ABBREVIATION_LENGTH = 8\n\n/**\n * Is this candidate a label a human would recognise, or an internal id?\n *\n * FOUND IN THE BROWSER, NOT REASONED ABOUT. The live `facilities` table has\n * 1738 rows in which `short_name` is null and `code` holds a generated\n * geohash-like key: \"N057E010-02981\", \"ADDR-1BF4-9C3E\". Those are not\n * abbreviations of anything. Preferring `code` over `locode` \u2014 which the\n * original precedence did, on the stated assumption that \"code for terminals IS\n * BCT/GCT/DCT\" \u2014 turned \"Port Gda\u0144sk\" into \"N031E031-04\u2026\" in an 84px column:\n * longer than the LOCODE, less readable than the name, and truncated on top.\n * That is strictly worse than not abbreviating at all.\n *\n * A length test is the whole check, and deliberately so. It needs no pattern\n * catalogue, it cannot be defeated by the next id scheme somebody invents, and\n * it fails in the SAFE direction: an unrecognised value is simply not used as a\n * label, so the cell renders the full name \u2014 which is exactly the documented\n * behaviour for an uncurated facility.\n */\nexport function looksLikeHumanCode(candidate: string): boolean {\n return candidate.length > 0 && candidate.length <= MAX_ABBREVIATION_LENGTH\n}\n\nexport function facilityToAbbreviation(row: {\n name?: string | null\n code?: string | null\n shortName?: string | null\n locode?: string | null\n}): AbbreviationEntry | null {\n // Precedence, and why it is not simply \"first non-empty\":\n // 1. `short_name` \u2014 CURATED BY STAFF. Always wins, never length-checked:\n // if a human typed it into the admin screen it is the intended label,\n // and second-guessing them here is how a central mapping stops being\n // the source of truth.\n // 2. `code` \u2014 the terminal's own trade code (\"BCT\"), WHEN it is one.\n // 3. `locode` \u2014 the UN/LOCODE. Always 5 characters and always a real\n // standard, so it is the reliable fallback when `code` is an internal id.\n const curated = row.shortName?.trim()\n const code = row.code?.trim()\n const locode = row.locode?.trim()\n\n const short =\n curated ||\n (code && looksLikeHumanCode(code) ? code : '') ||\n (locode && looksLikeHumanCode(locode) ? locode : '')\n if (!short) return null\n\n const match: string[] = []\n if (row.name?.trim()) match.push(row.name.trim())\n if (row.code?.trim()) match.push(row.code.trim())\n if (row.locode?.trim()) match.push(row.locode.trim())\n if (match.length === 0) return null\n\n return { match, short, full: row.name?.trim() || undefined }\n}\n\n/**\n * Same adapter for contractors.\n *\n * NOTE: this deliberately does NOT abbreviate anything itself. `contractors`\n * already has a curated `short_name`, populated by the GUS REGON lookup and by\n * `deriveContractorShortName` in `packages/contractors/.../lib/short-name.ts`,\n * and the workshop confirmed it is live and working. Re-deriving here would be\n * a second, competing scheme that drifts from the one users maintain. When\n * `shortName` is absent the contractor keeps its full name.\n */\nexport function contractorToAbbreviation(row: {\n name?: string | null\n shortName?: string | null\n}): AbbreviationEntry | null {\n const short = row.shortName?.trim()\n const name = row.name?.trim()\n if (!short || !name || short === name) return null\n return { match: [name], short, full: name }\n}\n\n/**\n * Static seed \u2014 the Polish terminals INF staff name out loud every day.\n *\n * Scope is deliberately tiny. This is a day-one readability floor for an\n * unseeded deployment, NOT a maintained gazetteer: the moment the facilities\n * table is populated, layer 1 supersedes all of it. Resist growing this list \u2014\n * every entry added here is an entry that can silently disagree with the\n * database, and the database is right.\n *\n * Codes are the terminals' own SMDG/common trade codes.\n */\nexport const BALTIC_TERMINAL_SEED: readonly AbbreviationEntry[] = [\n {\n match: ['Baltic Container Terminal', 'Baltic Container Terminal Gdynia', 'BCT Gdynia', 'BCT'],\n short: 'BCT',\n full: 'Baltic Container Terminal Gdynia',\n },\n {\n match: ['Gdynia Container Terminal', 'GCT Gdynia', 'GCT'],\n short: 'GCT',\n full: 'Gdynia Container Terminal',\n },\n {\n match: ['Baltic Hub', 'Baltic Hub Container Terminal', 'DCT Gdansk', 'DCT Gda\u0144sk', 'BHCT', 'DCT'],\n short: 'BHCT',\n full: 'Baltic Hub Container Terminal (ex DCT Gda\u0144sk)',\n },\n {\n match: ['Gdansk Container Terminal', 'Gda\u0144sk Container Terminal', 'GTK', 'GTK Gdansk'],\n short: 'GTK',\n full: 'Gda\u0144ski Terminal Kontenerowy',\n },\n {\n match: ['Port Gdansk', 'Port Gda\u0144sk', 'Port of Gdansk', 'Port of Gda\u0144sk', 'PLGDN'],\n short: 'GDN',\n full: 'Port Gda\u0144sk',\n },\n {\n match: ['Port Gdynia', 'Port of Gdynia', 'PLGDY'],\n short: 'GDY',\n full: 'Port Gdynia',\n },\n {\n match: ['Port Szczecin', 'Port of Szczecin', 'PLSZZ'],\n short: 'SZZ',\n full: 'Port Szczecin',\n },\n {\n match: ['Port Swinoujscie', 'Port \u015Awinouj\u015Bcie', 'Port of Swinoujscie', 'PLSWI'],\n short: 'SWI',\n full: 'Port \u015Awinouj\u015Bcie',\n },\n]\n\nfunction installDefaultSeed(): void {\n registerAbbreviationSeed(ABBREV_FACILITY, BALTIC_TERMINAL_SEED)\n}\n\ninstallDefaultSeed()\n"],
|
|
5
|
+
"mappings": "AAuGO,MAAM,kBAAyC;AAE/C,MAAM,oBAA2C;AAuDxD,MAAM,uBAAuB;AAE7B,MAAM,WAAW,oBAAI,IAA2C;AAEhE,IAAI,UAAU;AAmBd,MAAM,YAAY,oBAAI,IAAgB;AAEtC,SAAS,2BAAiC;AACxC,aAAW;AACX,aAAW,YAAY,WAAW;AAChC,QAAI;AACF,eAAS;AAAA,IACX,QAAQ;AAAA,IAER;AAAA,EACF;AACF;AASO,SAAS,uBAAuB,UAAkC;AACvE,YAAU,IAAI,QAAQ;AACtB,SAAO,MAAM;AACX,cAAU,OAAO,QAAQ;AAAA,EAC3B;AACF;AAEA,SAAS,SAAS,WAAkD;AAClE,MAAI,QAAQ,SAAS,IAAI,SAAS;AAClC,MAAI,CAAC,OAAO;AACV,YAAQ,EAAE,SAAS,oBAAI,IAAI,GAAG,MAAM,oBAAI,IAAI,GAAG,UAAU,oBAAI,IAAI,EAAE;AACnE,aAAS,IAAI,WAAW,KAAK;AAAA,EAC/B;AACA,SAAO;AACT;AAYA,MAAM,gBAAkD;AAAA,EACtD,QAAG;AAAA,EAAK,QAAG;AAAA,EAAK,QAAG;AAAA,EAAK,QAAG;AAAA,EAAK,QAAG;AAAA,EAAK,QAAG;AAAA,EAAK,QAAG;AAAA,EAAK,QAAG;AAAA,EAAK,QAAG;AAAA,EACnE,QAAG;AAAA,EAAK,QAAG;AAAA,EAAK,QAAG;AAAA,EAAK,QAAG;AAAA,EAAK,QAAG;AAAA,EAAK,QAAG;AAAA,EAC3C,QAAG;AAAA,EAAK,QAAG;AAAA,EAAK,QAAG;AAAA,EAAK,QAAG;AAAA,EAC3B,QAAG;AAAA,EAAK,QAAG;AAAA,EAAK,QAAG;AAAA,EAAK,QAAG;AAAA,EAC3B,QAAG;AAAA,EAAK,QAAG;AAAA,EAAK,QAAG;AAAA,EAAK,QAAG;AAAA,EAAK,QAAG;AAAA,EACnC,QAAG;AAAA,EAAK,QAAG;AAAA,EAAK,QAAG;AAAA,EAAK,QAAG;AAAA,EAC3B,QAAG;AAAA,EAAK,QAAG;AAAA,EAAK,QAAG;AAAA,EAAK,QAAG;AAAA,EAAK,QAAG;AAAA,EAAK,QAAG;AAAA,EAAK,QAAG;AAAA,EAAK,QAAG;AAAA,EAAK,QAAG;AAAA,EAAK,QAAG;AAAA,EAC3E,QAAG;AAAA,EAAM,QAAG;AACd;AAGA,MAAM,oBAAoB;AAE1B,MAAM,qBAAqB;AASpB,SAAS,yBAAyB,OAAuB;AAC9D,QAAM,UAAU,MAAM,YAAY;AAClC,QAAM,SAAS,kBAAkB,KAAK,OAAO;AAAA;AAAA,KAEvC,kBAAkB,YAAY,GAChC,QAAQ,QAAQ,mBAAmB,CAAC,OAAO,cAAc,EAAE,KAAK,EAAE;AAAA,MAClE;AACJ,oBAAkB,YAAY;AAC9B,SAAO,OAAO,QAAQ,oBAAoB,GAAG,EAAE,KAAK;AACtD;AAcO,SAAS,sBACd,WACA,SACA,SACM;AACN,QAAM,QAAQ,SAAS,SAAS;AAChC,MAAI,CAAC,SAAS,MAAO,OAAM,QAAQ,MAAM;AACzC,YAAU,MAAM,SAAS,OAAO;AAGhC,QAAM,SAAS,MAAM;AACrB,2BAAyB;AAC3B;AASO,SAAS,yBACd,WACA,SACA,SACM;AACN,QAAM,QAAQ,SAAS,SAAS;AAChC,MAAI,CAAC,SAAS,MAAO,OAAM,KAAK,MAAM;AACtC,YAAU,MAAM,MAAM,OAAO;AAC7B,QAAM,SAAS,MAAM;AACrB,2BAAyB;AAC3B;AAEA,SAAS,UAAU,OAAc,SAA6C;AAC5E,aAAW,SAAS,SAAS;AAC3B,QAAI,CAAC,SAAS,CAAC,MAAM,MAAO;AAC5B,eAAW,OAAO,MAAM,OAAO;AAC7B,UAAI,OAAO,QAAQ,SAAU;AAC7B,YAAM,MAAM,yBAAyB,GAAG;AAExC,UAAI,IAAK,OAAM,IAAI,KAAK,KAAK;AAAA,IAC/B;AAAA,EACF;AACF;AASO,SAAS,mBACd,WACA,OAC0B;AAC1B,MAAI,CAAC,MAAO,QAAO;AACnB,QAAM,QAAQ,SAAS,IAAI,SAAS;AACpC,MAAI,CAAC,MAAO,QAAO;AAEnB,QAAM,SAAS,MAAM,SAAS,IAAI,KAAK;AAEvC,MAAI,WAAW,OAAW,QAAO;AAEjC,QAAM,MAAM,yBAAyB,KAAK;AAC1C,QAAM,QAAQ,MAAM,QAAQ,IAAI,GAAG,KAAK,MAAM,KAAK,IAAI,GAAG,KAAK;AAE/D,MAAI,MAAM,SAAS,QAAQ,qBAAsB,OAAM,SAAS,MAAM;AACtE,QAAM,SAAS,IAAI,OAAO,KAAK;AAC/B,SAAO;AACT;AAUO,SAAS,WACd,WACA,OACe;AACf,SAAO,mBAAmB,WAAW,KAAK,GAAG,SAAS;AACxD;AASO,SAAS,uBAA+B;AAC7C,SAAO;AACT;AAMO,SAAS,qBAA2B;AACzC,WAAS,MAAM;AACf,2BAAyB;AACzB,qBAAmB;AACrB;AAMO,SAAS,wBAAwB,WAItC;AACA,QAAM,QAAQ,SAAS,IAAI,SAAS;AACpC,SAAO;AAAA,IACL,SAAS,OAAO,QAAQ,QAAQ;AAAA,IAChC,MAAM,OAAO,KAAK,QAAQ;AAAA,IAC1B,QAAQ,OAAO,SAAS,QAAQ;AAAA,EAClC;AACF;AAsBA,MAAM,0BAA0B;AAoBzB,SAAS,mBAAmB,WAA4B;AAC7D,SAAO,UAAU,SAAS,KAAK,UAAU,UAAU;AACrD;AAEO,SAAS,uBAAuB,KAKV;AAS3B,QAAM,UAAU,IAAI,WAAW,KAAK;AACpC,QAAM,OAAO,IAAI,MAAM,KAAK;AAC5B,QAAM,SAAS,IAAI,QAAQ,KAAK;AAEhC,QAAM,QACJ,YACC,QAAQ,mBAAmB,IAAI,IAAI,OAAO,QAC1C,UAAU,mBAAmB,MAAM,IAAI,SAAS;AACnD,MAAI,CAAC,MAAO,QAAO;AAEnB,QAAM,QAAkB,CAAC;AACzB,MAAI,IAAI,MAAM,KAAK,EAAG,OAAM,KAAK,IAAI,KAAK,KAAK,CAAC;AAChD,MAAI,IAAI,MAAM,KAAK,EAAG,OAAM,KAAK,IAAI,KAAK,KAAK,CAAC;AAChD,MAAI,IAAI,QAAQ,KAAK,EAAG,OAAM,KAAK,IAAI,OAAO,KAAK,CAAC;AACpD,MAAI,MAAM,WAAW,EAAG,QAAO;AAE/B,SAAO,EAAE,OAAO,OAAO,MAAM,IAAI,MAAM,KAAK,KAAK,OAAU;AAC7D;AAYO,SAAS,yBAAyB,KAGZ;AAC3B,QAAM,QAAQ,IAAI,WAAW,KAAK;AAClC,QAAM,OAAO,IAAI,MAAM,KAAK;AAC5B,MAAI,CAAC,SAAS,CAAC,QAAQ,UAAU,KAAM,QAAO;AAC9C,SAAO,EAAE,OAAO,CAAC,IAAI,GAAG,OAAO,MAAM,KAAK;AAC5C;AAaO,MAAM,uBAAqD;AAAA,EAChE;AAAA,IACE,OAAO,CAAC,6BAA6B,oCAAoC,cAAc,KAAK;AAAA,IAC5F,OAAO;AAAA,IACP,MAAM;AAAA,EACR;AAAA,EACA;AAAA,IACE,OAAO,CAAC,6BAA6B,cAAc,KAAK;AAAA,IACxD,OAAO;AAAA,IACP,MAAM;AAAA,EACR;AAAA,EACA;AAAA,IACE,OAAO,CAAC,cAAc,iCAAiC,cAAc,mBAAc,QAAQ,KAAK;AAAA,IAChG,OAAO;AAAA,IACP,MAAM;AAAA,EACR;AAAA,EACA;AAAA,IACE,OAAO,CAAC,6BAA6B,kCAA6B,OAAO,YAAY;AAAA,IACrF,OAAO;AAAA,IACP,MAAM;AAAA,EACR;AAAA,EACA;AAAA,IACE,OAAO,CAAC,eAAe,oBAAe,kBAAkB,uBAAkB,OAAO;AAAA,IACjF,OAAO;AAAA,IACP,MAAM;AAAA,EACR;AAAA,EACA;AAAA,IACE,OAAO,CAAC,eAAe,kBAAkB,OAAO;AAAA,IAChD,OAAO;AAAA,IACP,MAAM;AAAA,EACR;AAAA,EACA;AAAA,IACE,OAAO,CAAC,iBAAiB,oBAAoB,OAAO;AAAA,IACpD,OAAO;AAAA,IACP,MAAM;AAAA,EACR;AAAA,EACA;AAAA,IACE,OAAO,CAAC,oBAAoB,8BAAoB,uBAAuB,OAAO;AAAA,IAC9E,OAAO;AAAA,IACP,MAAM;AAAA,EACR;AACF;AAEA,SAAS,qBAA2B;AAClC,2BAAyB,iBAAiB,oBAAoB;AAChE;AAEA,mBAAmB;",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
function computeAnchoredPosition(anchor, viewport, options) {
|
|
2
|
+
const { width, preferredHeight, align = "start", gap = 4, margin = 8, minHeight = 120 } = options;
|
|
3
|
+
const spaceBelow = viewport.height - anchor.bottom - gap - margin;
|
|
4
|
+
const spaceAbove = anchor.top - gap - margin;
|
|
5
|
+
const flipAbove = spaceBelow < preferredHeight && spaceAbove > spaceBelow;
|
|
6
|
+
const available = flipAbove ? spaceAbove : spaceBelow;
|
|
7
|
+
const maxHeight = Math.max(minHeight, Math.min(preferredHeight, available));
|
|
8
|
+
const preferredLeft = align === "end" ? anchor.right - width : anchor.left;
|
|
9
|
+
const maxLeft = viewport.width - width - margin;
|
|
10
|
+
const left = Math.max(margin, Math.min(preferredLeft, maxLeft));
|
|
11
|
+
return {
|
|
12
|
+
top: flipAbove ? anchor.top - gap : anchor.bottom + gap,
|
|
13
|
+
left,
|
|
14
|
+
maxHeight,
|
|
15
|
+
flipAbove
|
|
16
|
+
};
|
|
17
|
+
}
|
|
18
|
+
export {
|
|
19
|
+
computeAnchoredPosition
|
|
20
|
+
};
|
|
21
|
+
//# sourceMappingURL=anchoredPosition.js.map
|