@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,1336 @@
|
|
|
1
|
+
'use client'
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Split view — renders a TREE of registered tables in one screen.
|
|
5
|
+
*
|
|
6
|
+
* A table page renders this instead of its table component, naming itself as
|
|
7
|
+
* the only pane. With one pane it looks exactly like the page did before this
|
|
8
|
+
* feature existed; pane headers and dividers appear only once a second table is
|
|
9
|
+
* opened. That is what makes it ambient — you split from where you already are.
|
|
10
|
+
*
|
|
11
|
+
* The layout is a tree so nested arrangements are expressible — notably "two
|
|
12
|
+
* side by side with a third full-width beneath", which the earlier flat model
|
|
13
|
+
* could not represent at all. Rendering is recursive: a split node lays its
|
|
14
|
+
* children along its own axis and drops a divider between each pair.
|
|
15
|
+
*
|
|
16
|
+
* The grid needs no changes to work here: its event bus is per-element, copy
|
|
17
|
+
* and paste are both target-guarded, `height: 'fill'` measures against the
|
|
18
|
+
* nearest scroll ancestor (each pane is one), and the cell store — including
|
|
19
|
+
* its undo stack — is created per instance.
|
|
20
|
+
*
|
|
21
|
+
* Spec: .ai/specs/2026-08-04-dynamic-table-split-view.md
|
|
22
|
+
*/
|
|
23
|
+
|
|
24
|
+
import * as React from 'react'
|
|
25
|
+
import ReactDOM from 'react-dom'
|
|
26
|
+
import { Columns2, Rows2, X, ExternalLink, Save, ChevronDown, Trash2, LayoutGrid, Grid2x2, PanelLeft, PanelRight, PanelTop, PanelBottom, MoreHorizontal, Check, SlidersHorizontal } from 'lucide-react'
|
|
27
|
+
import { useTableById, useTableRegistry } from '../registry/TableRegistryContext'
|
|
28
|
+
import { useToolbarOverflowClose, ToolbarOverflowCloseProvider } from '../components/ToolbarOverflow'
|
|
29
|
+
import { computeAnchoredPosition } from '../utils/anchoredPosition'
|
|
30
|
+
import { ContentPicker } from './ContentPicker'
|
|
31
|
+
import { WidgetPane } from './WidgetPane'
|
|
32
|
+
import { EmptySlot } from './EmptySlot'
|
|
33
|
+
import { WorkspaceFilterBar, type UnmappedPaneReport } from './WorkspaceFilterBar'
|
|
34
|
+
import {
|
|
35
|
+
mapCriteriaForTable,
|
|
36
|
+
mapCriteriaForWidget,
|
|
37
|
+
type SharedCriteria,
|
|
38
|
+
} from './sharedCriteria'
|
|
39
|
+
import type { FilterRow } from '../types/index'
|
|
40
|
+
import { useSplitViewLayouts } from './useSplitViewLayouts'
|
|
41
|
+
import { readStoredLayout, writeStoredLayout } from './layoutPersistence'
|
|
42
|
+
import {
|
|
43
|
+
ARRANGE_PRESETS,
|
|
44
|
+
GRID_TEMPLATE_LIST,
|
|
45
|
+
PANE_MIN_HEIGHT_PX,
|
|
46
|
+
PANE_MIN_WIDTH_PX,
|
|
47
|
+
SPLIT_LAYOUT_VERSION,
|
|
48
|
+
applyGridTemplate,
|
|
49
|
+
applyPreset,
|
|
50
|
+
countPanes,
|
|
51
|
+
countSlots,
|
|
52
|
+
evenAll,
|
|
53
|
+
fillSlot,
|
|
54
|
+
listPanes,
|
|
55
|
+
listSlots,
|
|
56
|
+
makePaneId,
|
|
57
|
+
removePane,
|
|
58
|
+
resizeAt,
|
|
59
|
+
setPaneChrome,
|
|
60
|
+
setPaneContentSettings,
|
|
61
|
+
splitPane,
|
|
62
|
+
tableContent,
|
|
63
|
+
type GridTemplateId,
|
|
64
|
+
type LayoutNode,
|
|
65
|
+
type NodePath,
|
|
66
|
+
type PaneChrome,
|
|
67
|
+
type PaneContentRef,
|
|
68
|
+
type PresetId,
|
|
69
|
+
type SplitDirection,
|
|
70
|
+
type SplitLayout,
|
|
71
|
+
} from './types'
|
|
72
|
+
|
|
73
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
74
|
+
|
|
75
|
+
/**
|
|
76
|
+
* Material 3 chrome, shared by every menu the split view draws.
|
|
77
|
+
*
|
|
78
|
+
* The row string below was duplicated verbatim in five places, which is how
|
|
79
|
+
* three of them drifted onto raw pixel type. One const, one look.
|
|
80
|
+
*
|
|
81
|
+
* `h-7` (28px) is kept DELIBERATELY: M3 specifies a 48dp menu item, and this is
|
|
82
|
+
* a dense operations tool where six 48dp rows are most of a pane. Shape, colour,
|
|
83
|
+
* state layers and motion are adopted from M3; its touch geometry is not — the
|
|
84
|
+
* same trade `m3.css` documents at the top of the file.
|
|
85
|
+
*/
|
|
86
|
+
export const M3_MENU_ROW =
|
|
87
|
+
'flex h-7 w-full items-center gap-2 rounded-m3-xs px-1.5 text-left text-body-regular-xs text-[var(--m3-on-surface)] transition-colors duration-[var(--m3-duration-short2)] ease-m3-standard hover:bg-[var(--m3-state-layer-hover)] active:bg-[var(--m3-state-layer-pressed)]'
|
|
88
|
+
|
|
89
|
+
/**
|
|
90
|
+
* The SELECTED form of a menu row. M3 marks selection by swapping the
|
|
91
|
+
* container, never by an icon alone — the same `secondary-container` role the
|
|
92
|
+
* grid uses for a selected row, so selection reads identically everywhere.
|
|
93
|
+
*/
|
|
94
|
+
export const M3_MENU_ROW_ON =
|
|
95
|
+
`${M3_MENU_ROW} bg-[var(--m3-secondary-container)] text-[var(--m3-on-secondary-container)]`
|
|
96
|
+
|
|
97
|
+
/**
|
|
98
|
+
* A section caption inside a menu ("Add table", "Show"). 10px chrome uses the
|
|
99
|
+
* 10px token: routing it through a 12/16 token would grow every menu by 20%.
|
|
100
|
+
*/
|
|
101
|
+
export const M3_MENU_CAPTION =
|
|
102
|
+
'text-label-semibold-2xs uppercase text-[var(--m3-on-surface-variant)]'
|
|
103
|
+
|
|
104
|
+
/**
|
|
105
|
+
* A portalled menu panel — an M3 elevated surface: a `md` (12px) corner, the
|
|
106
|
+
* softer `outline-variant` hairline, a container step for the fill, and the
|
|
107
|
+
* two-shadow elevation rather than Tailwind's `shadow-*`.
|
|
108
|
+
*
|
|
109
|
+
* `WidgetPane` imports this. The resulting import cycle is safe: the binding is
|
|
110
|
+
* read at RENDER time, long after both module bodies have initialised.
|
|
111
|
+
*/
|
|
112
|
+
export const M3_MENU_PANEL =
|
|
113
|
+
'fixed z-[1000] overflow-y-auto rounded-m3-md border border-[var(--m3-outline-variant)] bg-[var(--m3-surface-container)] py-1 shadow-m3-2'
|
|
114
|
+
|
|
115
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
116
|
+
|
|
117
|
+
function PaneBody({
|
|
118
|
+
content,
|
|
119
|
+
paneId,
|
|
120
|
+
isPrimary,
|
|
121
|
+
multiview,
|
|
122
|
+
overflowExtras,
|
|
123
|
+
chrome,
|
|
124
|
+
onWidgetSettingsChange,
|
|
125
|
+
sharedFilters,
|
|
126
|
+
sharedSearch,
|
|
127
|
+
}: {
|
|
128
|
+
content: PaneContentRef
|
|
129
|
+
paneId: string
|
|
130
|
+
isPrimary: boolean
|
|
131
|
+
multiview: boolean
|
|
132
|
+
overflowExtras?: React.ReactNode
|
|
133
|
+
chrome?: PaneChrome
|
|
134
|
+
onWidgetSettingsChange?: (next: unknown) => void
|
|
135
|
+
sharedFilters?: FilterRow[]
|
|
136
|
+
sharedSearch?: string
|
|
137
|
+
}) {
|
|
138
|
+
if (content.kind === 'widget') {
|
|
139
|
+
return (
|
|
140
|
+
<WidgetPane
|
|
141
|
+
content={content}
|
|
142
|
+
slotId={paneId}
|
|
143
|
+
onSettingsChange={onWidgetSettingsChange}
|
|
144
|
+
overflowExtras={overflowExtras}
|
|
145
|
+
hideToolbar={chrome?.toolbar === false}
|
|
146
|
+
/>
|
|
147
|
+
)
|
|
148
|
+
}
|
|
149
|
+
return (
|
|
150
|
+
<TablePaneBody
|
|
151
|
+
tableId={content.tableId}
|
|
152
|
+
paneId={paneId}
|
|
153
|
+
isPrimary={isPrimary}
|
|
154
|
+
multiview={multiview}
|
|
155
|
+
overflowExtras={overflowExtras}
|
|
156
|
+
chrome={chrome}
|
|
157
|
+
sharedFilters={sharedFilters}
|
|
158
|
+
sharedSearch={sharedSearch}
|
|
159
|
+
/>
|
|
160
|
+
)
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
function TablePaneBody({
|
|
164
|
+
tableId,
|
|
165
|
+
paneId,
|
|
166
|
+
isPrimary,
|
|
167
|
+
multiview,
|
|
168
|
+
overflowExtras,
|
|
169
|
+
chrome,
|
|
170
|
+
sharedFilters,
|
|
171
|
+
sharedSearch,
|
|
172
|
+
}: {
|
|
173
|
+
tableId: string
|
|
174
|
+
paneId: string
|
|
175
|
+
isPrimary: boolean
|
|
176
|
+
multiview: boolean
|
|
177
|
+
overflowExtras?: React.ReactNode
|
|
178
|
+
chrome?: PaneChrome
|
|
179
|
+
sharedFilters?: FilterRow[]
|
|
180
|
+
sharedSearch?: string
|
|
181
|
+
}) {
|
|
182
|
+
const { definition, status } = useTableById(tableId)
|
|
183
|
+
|
|
184
|
+
if (status === 'unknown') {
|
|
185
|
+
return (
|
|
186
|
+
<PaneMessage data-pane-status="unknown">
|
|
187
|
+
This table is no longer available.
|
|
188
|
+
</PaneMessage>
|
|
189
|
+
)
|
|
190
|
+
}
|
|
191
|
+
if (status === 'denied') {
|
|
192
|
+
return (
|
|
193
|
+
<PaneMessage data-pane-status="denied">
|
|
194
|
+
You don’t have access to {definition?.metadata.title ?? 'this table'}.
|
|
195
|
+
</PaneMessage>
|
|
196
|
+
)
|
|
197
|
+
}
|
|
198
|
+
// `loading` = the grant check (a POST to /api/auth/feature-check) has not
|
|
199
|
+
// answered yet. Falling through to the grid here meant a revoked table
|
|
200
|
+
// mounted, fired its list request, and only then swapped to "no access" —
|
|
201
|
+
// which contradicts the ACL-re-checked-at-render contract this file states.
|
|
202
|
+
//
|
|
203
|
+
// But holding EVERY pane would put a placeholder on the first load of every
|
|
204
|
+
// list page in the app, because that check is a real round-trip on first
|
|
205
|
+
// paint (react-query serves it from cache thereafter). That trades a visible
|
|
206
|
+
// slowdown on the common path against a flash on a rare one.
|
|
207
|
+
//
|
|
208
|
+
// So it is split by provenance. The PRIMARY pane is the page's own table and
|
|
209
|
+
// the server already authorised this route to render it at all, so it is
|
|
210
|
+
// drawn optimistically and the common path is unchanged. SECONDARY panes come
|
|
211
|
+
// out of a SAVED LAYOUT, which can name a table whose grant was revoked since
|
|
212
|
+
// it was saved — that is the case worth waiting for.
|
|
213
|
+
if (status === 'loading' && !isPrimary) {
|
|
214
|
+
return <PaneMessage data-pane-status="loading">Checking access…</PaneMessage>
|
|
215
|
+
}
|
|
216
|
+
if (!definition) return null
|
|
217
|
+
|
|
218
|
+
const Table = definition.Table
|
|
219
|
+
// The PRIMARY pane is the page's own table, so it keeps the unscoped keys —
|
|
220
|
+
// byte-identical to before split view existed. Anything else would break
|
|
221
|
+
// persistence outright: pane ids are minted per mount, so scoping the primary
|
|
222
|
+
// pane would hand every page load a fresh key and silently discard the user's
|
|
223
|
+
// saved column widths on every navigation. (Caught in the browser, not by
|
|
224
|
+
// typecheck — the code was "correct" and the behaviour was wrong.)
|
|
225
|
+
//
|
|
226
|
+
// Secondary panes DO get a per-pane scope, which is what stops two panes of
|
|
227
|
+
// the same table overwriting each other. A saved layout persists its pane
|
|
228
|
+
// ids, so reopening one restores the same scopes and the same widths.
|
|
229
|
+
const storageScope = isPrimary ? '' : `pane:${paneId}:`
|
|
230
|
+
return (
|
|
231
|
+
<Table
|
|
232
|
+
storageScope={storageScope}
|
|
233
|
+
embedded
|
|
234
|
+
// The primary pane IS the page — its table is what the route exists to
|
|
235
|
+
// show, so opening a row is the page doing its job, not a click tearing
|
|
236
|
+
// a host down. `embedded` alone said "do not navigate" to every pane, and
|
|
237
|
+
// the Files list (whose only affordance to open a file is its row links
|
|
238
|
+
// and row click) was left with no way in at all. See
|
|
239
|
+
// `ownsPageNavigation` in registry/types.ts.
|
|
240
|
+
ownsPageNavigation={isPrimary}
|
|
241
|
+
multiview={multiview}
|
|
242
|
+
overflowExtras={overflowExtras}
|
|
243
|
+
hideToolbar={chrome?.toolbar === false}
|
|
244
|
+
// The workspace bar REPLACES each pane's search row while it is on, so
|
|
245
|
+
// the density cost of the bar is paid back by the rows it reclaims.
|
|
246
|
+
hideSearch={chrome?.search === false || sharedSearch !== undefined}
|
|
247
|
+
hideViews={chrome?.viewsBar === false}
|
|
248
|
+
hidePagination={chrome?.viewsBar === false}
|
|
249
|
+
sharedFilters={sharedFilters}
|
|
250
|
+
sharedSearch={sharedSearch}
|
|
251
|
+
/>
|
|
252
|
+
)
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
function PaneMessage({ children, ...rest }: React.HTMLAttributes<HTMLDivElement>) {
|
|
256
|
+
return (
|
|
257
|
+
<div className="flex h-full items-center justify-center p-6 text-center text-body-regular-sm text-[var(--m3-on-surface-variant)]" {...rest}>
|
|
258
|
+
{children}
|
|
259
|
+
</div>
|
|
260
|
+
)
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
|
|
264
|
+
/**
|
|
265
|
+
* Everything a pane can do, in ONE overflow menu inside the table's own
|
|
266
|
+
* toolbar.
|
|
267
|
+
*
|
|
268
|
+
* Replaces a dedicated pane-header row that carried six icon buttons AND
|
|
269
|
+
* repeated the table title the toolbar already showed. That row cost ~32px per
|
|
270
|
+
* pane and bought nothing the toolbar could not hold.
|
|
271
|
+
*/
|
|
272
|
+
/**
|
|
273
|
+
* The pane's own items, as ROWS — no button, no panel of its own.
|
|
274
|
+
*
|
|
275
|
+
* These are injected into the table's single overflow menu via
|
|
276
|
+
* `uiConfig.toolbarOverflowExtras`. An earlier build rendered them behind a
|
|
277
|
+
* second button sitting right next to the table's overflow, which left two
|
|
278
|
+
* near-identical menus in one toolbar.
|
|
279
|
+
*/
|
|
280
|
+
function PaneMenuRows({
|
|
281
|
+
href,
|
|
282
|
+
chrome,
|
|
283
|
+
canClose,
|
|
284
|
+
extras,
|
|
285
|
+
onSplit,
|
|
286
|
+
onToggleChrome,
|
|
287
|
+
onClose,
|
|
288
|
+
}: {
|
|
289
|
+
href?: string
|
|
290
|
+
chrome?: PaneChrome
|
|
291
|
+
canClose: boolean
|
|
292
|
+
extras?: React.ReactNode
|
|
293
|
+
onSplit: (direction: SplitDirection, before: boolean, anchor: DOMRect) => void
|
|
294
|
+
onToggleChrome: (patch: Partial<PaneChrome>) => void
|
|
295
|
+
onClose: () => void
|
|
296
|
+
}) {
|
|
297
|
+
// Terminal actions dismiss the menu; the Show toggles deliberately do not,
|
|
298
|
+
// so several can be flipped in one visit.
|
|
299
|
+
const closeMenu = useToolbarOverflowClose()
|
|
300
|
+
|
|
301
|
+
const shows: Array<{ key: keyof PaneChrome; label: string }> = [
|
|
302
|
+
{ key: 'toolbar', label: 'Toolbar' },
|
|
303
|
+
{ key: 'search', label: 'Search' },
|
|
304
|
+
{ key: 'viewsBar', label: 'Views bar' },
|
|
305
|
+
]
|
|
306
|
+
|
|
307
|
+
const ADD_TABLE: Array<{ dir: SplitDirection; before: boolean; label: string; Icon: typeof PanelLeft; attr: string }> = [
|
|
308
|
+
{ dir: 'row', before: true, label: 'Left', Icon: PanelLeft, attr: 'data-pane-split-left' },
|
|
309
|
+
{ dir: 'row', before: false, label: 'Right', Icon: PanelRight, attr: 'data-pane-split-right' },
|
|
310
|
+
{ dir: 'column', before: true, label: 'Above', Icon: PanelTop, attr: 'data-pane-split-up' },
|
|
311
|
+
{ dir: 'column', before: false, label: 'Below', Icon: PanelBottom, attr: 'data-pane-split-down' },
|
|
312
|
+
]
|
|
313
|
+
|
|
314
|
+
const row = M3_MENU_ROW
|
|
315
|
+
const gutter = 'flex w-4 shrink-0 justify-center'
|
|
316
|
+
|
|
317
|
+
return (
|
|
318
|
+
<div data-pane-menu-rows="">
|
|
319
|
+
<div className={`px-2 pb-1 pt-1 ${M3_MENU_CAPTION}`}>
|
|
320
|
+
Add table
|
|
321
|
+
</div>
|
|
322
|
+
<div className="px-2 pb-2">
|
|
323
|
+
{/* An M3 connected button group: one pill, hairline-divided. The
|
|
324
|
+
container's `overflow-hidden` is what gives the first and last
|
|
325
|
+
segment their end caps. */}
|
|
326
|
+
<div className="flex overflow-hidden rounded-m3-full border border-[var(--m3-outline)]">
|
|
327
|
+
{ADD_TABLE.map((item, index) => (
|
|
328
|
+
<button
|
|
329
|
+
key={item.label}
|
|
330
|
+
type="button"
|
|
331
|
+
title={item.label}
|
|
332
|
+
aria-label={`Add table ${item.label.toLowerCase()}`}
|
|
333
|
+
onClick={(event) => { onSplit(item.dir, item.before, event.currentTarget.getBoundingClientRect()); closeMenu() }}
|
|
334
|
+
className={`flex flex-1 flex-col items-center gap-0.5 py-1.5 text-[var(--m3-on-surface-variant)] transition-colors duration-[var(--m3-duration-short2)] ease-m3-standard hover:bg-[var(--m3-state-layer-hover)] hover:text-[var(--m3-on-surface)] active:bg-[var(--m3-state-layer-pressed)] ${
|
|
335
|
+
index > 0 ? 'border-l border-[var(--m3-outline)]' : ''
|
|
336
|
+
}`}
|
|
337
|
+
{...{ [item.attr]: '' }}
|
|
338
|
+
>
|
|
339
|
+
<item.Icon className="h-3.5 w-3.5" />
|
|
340
|
+
<span className="text-label-semibold-2xs">{item.label}</span>
|
|
341
|
+
</button>
|
|
342
|
+
))}
|
|
343
|
+
</div>
|
|
344
|
+
</div>
|
|
345
|
+
|
|
346
|
+
<div className={`px-2 pb-0.5 ${M3_MENU_CAPTION}`}>Show</div>
|
|
347
|
+
<div className="px-1">
|
|
348
|
+
{shows.map((item) => {
|
|
349
|
+
const on = chrome?.[item.key] !== false
|
|
350
|
+
return (
|
|
351
|
+
<button
|
|
352
|
+
key={item.key}
|
|
353
|
+
type="button"
|
|
354
|
+
onClick={(event) => { event.stopPropagation(); onToggleChrome({ [item.key]: !on } as Partial<PaneChrome>) }}
|
|
355
|
+
className={on ? M3_MENU_ROW_ON : M3_MENU_ROW}
|
|
356
|
+
data-pane-chrome={item.key}
|
|
357
|
+
data-pane-chrome-on={on ? 'true' : 'false'}
|
|
358
|
+
>
|
|
359
|
+
<span className={gutter}>{on && <Check className="h-3.5 w-3.5" />}</span>
|
|
360
|
+
<span className={on ? '' : 'text-[var(--m3-on-surface-variant)]'}>{item.label}</span>
|
|
361
|
+
</button>
|
|
362
|
+
)
|
|
363
|
+
})}
|
|
364
|
+
</div>
|
|
365
|
+
|
|
366
|
+
{extras && <div className="mt-1 border-t border-[var(--m3-outline-variant)] px-1 pt-1">{extras}</div>}
|
|
367
|
+
|
|
368
|
+
<div className="mt-1 border-t border-[var(--m3-outline-variant)] px-1 pt-1">
|
|
369
|
+
{href && (
|
|
370
|
+
<a href={href} className={row} data-pane-open-full="" onClick={closeMenu}>
|
|
371
|
+
<span className={gutter}><ExternalLink className="h-3.5 w-3.5 text-[var(--m3-on-surface-variant)]" /></span>
|
|
372
|
+
Open full page
|
|
373
|
+
</a>
|
|
374
|
+
)}
|
|
375
|
+
{canClose && (
|
|
376
|
+
<button type="button" onClick={() => { onClose(); closeMenu() }} className={row} data-pane-close="">
|
|
377
|
+
<span className={gutter}><X className="h-3.5 w-3.5 text-[var(--m3-on-surface-variant)]" /></span>
|
|
378
|
+
Close pane
|
|
379
|
+
</button>
|
|
380
|
+
)}
|
|
381
|
+
</div>
|
|
382
|
+
</div>
|
|
383
|
+
)
|
|
384
|
+
}
|
|
385
|
+
|
|
386
|
+
/**
|
|
387
|
+
* The way back when a pane's toolbar is hidden — hiding it also hides the
|
|
388
|
+
* overflow menu that turned it off.
|
|
389
|
+
*
|
|
390
|
+
* Portalled to `document.body`, like every other menu in the grid. As a plain
|
|
391
|
+
* `absolute` panel it sat at `z-40` INSIDE a pane that clips its overflow, so
|
|
392
|
+
* the grid's sticky columns painted over it and clicks landed on `td.hot-cell`
|
|
393
|
+
* instead — the handle opened a menu that could not be used.
|
|
394
|
+
*/
|
|
395
|
+
function PaneRestoreMenu({ children }: { children: React.ReactNode }) {
|
|
396
|
+
const [open, setOpen] = React.useState(false)
|
|
397
|
+
const triggerRef = React.useRef<HTMLButtonElement>(null)
|
|
398
|
+
const panelRef = React.useRef<HTMLDivElement>(null)
|
|
399
|
+
const [placement, setPlacement] = React.useState({ top: 0, left: 0, maxHeight: 720 })
|
|
400
|
+
|
|
401
|
+
const reposition = React.useCallback(() => {
|
|
402
|
+
const trigger = triggerRef.current
|
|
403
|
+
if (!trigger) return
|
|
404
|
+
const next = computeAnchoredPosition(
|
|
405
|
+
trigger.getBoundingClientRect(),
|
|
406
|
+
{ width: window.innerWidth, height: window.innerHeight },
|
|
407
|
+
// Clamped to what fits — see ToolbarOverflow's MENU_MAX_HEIGHT note.
|
|
408
|
+
{ width: 216, preferredHeight: 720, align: 'end', minHeight: 180 },
|
|
409
|
+
)
|
|
410
|
+
setPlacement({ top: next.top, left: next.left, maxHeight: next.maxHeight })
|
|
411
|
+
}, [])
|
|
412
|
+
|
|
413
|
+
React.useLayoutEffect(() => { if (open) reposition() }, [open, reposition])
|
|
414
|
+
|
|
415
|
+
React.useEffect(() => {
|
|
416
|
+
if (!open) return
|
|
417
|
+
const onDown = (event: MouseEvent) => {
|
|
418
|
+
const target = event.target as Node
|
|
419
|
+
if (!panelRef.current?.contains(target) && !triggerRef.current?.contains(target)) setOpen(false)
|
|
420
|
+
}
|
|
421
|
+
const onKey = (event: KeyboardEvent) => { if (event.key === 'Escape') setOpen(false) }
|
|
422
|
+
const onScroll = () => reposition()
|
|
423
|
+
document.addEventListener('mousedown', onDown)
|
|
424
|
+
document.addEventListener('keydown', onKey)
|
|
425
|
+
window.addEventListener('scroll', onScroll, true)
|
|
426
|
+
window.addEventListener('resize', onScroll)
|
|
427
|
+
return () => {
|
|
428
|
+
document.removeEventListener('mousedown', onDown)
|
|
429
|
+
document.removeEventListener('keydown', onKey)
|
|
430
|
+
window.removeEventListener('scroll', onScroll, true)
|
|
431
|
+
window.removeEventListener('resize', onScroll)
|
|
432
|
+
}
|
|
433
|
+
}, [open, reposition])
|
|
434
|
+
|
|
435
|
+
const close = React.useCallback(() => setOpen(false), [])
|
|
436
|
+
|
|
437
|
+
return (
|
|
438
|
+
<div className="absolute right-2 top-1.5 z-30" data-pane-restore="">
|
|
439
|
+
<button
|
|
440
|
+
ref={triggerRef}
|
|
441
|
+
type="button"
|
|
442
|
+
onClick={() => setOpen((value) => !value)}
|
|
443
|
+
aria-label="Pane options"
|
|
444
|
+
aria-expanded={open}
|
|
445
|
+
className="flex h-6 w-6 cursor-pointer items-center justify-center rounded-m3-full border border-[var(--m3-outline-variant)] bg-[var(--m3-surface-container-high)] text-[var(--m3-on-surface-variant)] shadow-m3-1 transition-colors duration-[var(--m3-duration-short2)] ease-m3-standard hover:bg-[var(--m3-surface-container-highest)] hover:text-[var(--m3-on-surface)]"
|
|
446
|
+
data-pane-restore-btn=""
|
|
447
|
+
>
|
|
448
|
+
<SlidersHorizontal className="h-3.5 w-3.5" />
|
|
449
|
+
</button>
|
|
450
|
+
{open && typeof document !== 'undefined' && ReactDOM.createPortal(
|
|
451
|
+
<div
|
|
452
|
+
ref={panelRef}
|
|
453
|
+
className={M3_MENU_PANEL}
|
|
454
|
+
style={{ top: placement.top, left: placement.left, width: 216, maxHeight: placement.maxHeight }}
|
|
455
|
+
data-pane-restore-menu=""
|
|
456
|
+
>
|
|
457
|
+
<ToolbarOverflowCloseProvider value={close}>{children}</ToolbarOverflowCloseProvider>
|
|
458
|
+
</div>,
|
|
459
|
+
document.body,
|
|
460
|
+
)}
|
|
461
|
+
</div>
|
|
462
|
+
)
|
|
463
|
+
}
|
|
464
|
+
|
|
465
|
+
/** Pick an arrangement. Presets that need more panes than exist are disabled
|
|
466
|
+
* rather than hidden, so the shape you want is discoverable before you have
|
|
467
|
+
* enough tables open to use it. */
|
|
468
|
+
/**
|
|
469
|
+
* One row that turns the workspace search/filter bar on and off.
|
|
470
|
+
*
|
|
471
|
+
* A plain toggle rather than a submenu: it has exactly two states, and the bar
|
|
472
|
+
* it reveals IS the rest of the interface. Deliberately does NOT dismiss the
|
|
473
|
+
* overflow menu — the neighbouring "Show" toggles behave the same way, so
|
|
474
|
+
* several settings can be flipped in one visit.
|
|
475
|
+
*/
|
|
476
|
+
function SharedFilterToggle({
|
|
477
|
+
enabled,
|
|
478
|
+
onToggle,
|
|
479
|
+
}: {
|
|
480
|
+
enabled: boolean
|
|
481
|
+
onToggle: () => void
|
|
482
|
+
}) {
|
|
483
|
+
return (
|
|
484
|
+
<button
|
|
485
|
+
type="button"
|
|
486
|
+
onClick={onToggle}
|
|
487
|
+
role="menuitemcheckbox"
|
|
488
|
+
aria-checked={enabled}
|
|
489
|
+
title={
|
|
490
|
+
enabled
|
|
491
|
+
? 'Each pane goes back to its own search and filters'
|
|
492
|
+
: 'Drive every pane from one search and filter bar'
|
|
493
|
+
}
|
|
494
|
+
className={enabled ? M3_MENU_ROW_ON : M3_MENU_ROW}
|
|
495
|
+
data-split-shared-filters={enabled ? 'on' : 'off'}
|
|
496
|
+
>
|
|
497
|
+
<span className="flex w-4 shrink-0 justify-center">
|
|
498
|
+
{enabled ? <Check className="h-3.5 w-3.5" /> : <SlidersHorizontal className="h-3.5 w-3.5 text-[var(--m3-on-surface-variant)]" />}
|
|
499
|
+
</span>
|
|
500
|
+
<span className="flex-1">Shared search & filters</span>
|
|
501
|
+
</button>
|
|
502
|
+
)
|
|
503
|
+
}
|
|
504
|
+
|
|
505
|
+
function ArrangeMenu({
|
|
506
|
+
layout,
|
|
507
|
+
onApply,
|
|
508
|
+
}: {
|
|
509
|
+
layout: SplitLayout
|
|
510
|
+
onApply: (next: SplitLayout) => void
|
|
511
|
+
}) {
|
|
512
|
+
const [open, setOpen] = React.useState(false)
|
|
513
|
+
const closeMenu = useToolbarOverflowClose()
|
|
514
|
+
const paneCount = countPanes(layout.root)
|
|
515
|
+
|
|
516
|
+
const pick = (preset: PresetId) => {
|
|
517
|
+
onApply(applyPreset(layout, preset))
|
|
518
|
+
setOpen(false)
|
|
519
|
+
closeMenu()
|
|
520
|
+
}
|
|
521
|
+
|
|
522
|
+
return (
|
|
523
|
+
<div data-split-arrange-section="">
|
|
524
|
+
<button
|
|
525
|
+
type="button"
|
|
526
|
+
onClick={() => setOpen((value) => !value)}
|
|
527
|
+
title="Arrange panes"
|
|
528
|
+
aria-expanded={open}
|
|
529
|
+
className={M3_MENU_ROW}
|
|
530
|
+
data-split-arrange=""
|
|
531
|
+
>
|
|
532
|
+
<span className="flex w-4 shrink-0 justify-center"><LayoutGrid className="h-3.5 w-3.5 text-[var(--m3-on-surface-variant)]" /></span>
|
|
533
|
+
<span className="flex-1">Arrange</span>
|
|
534
|
+
<ChevronDown className={`h-3 w-3 text-[var(--m3-on-surface-variant)] transition-transform duration-[var(--m3-duration-short2)] ease-m3-standard ${open ? 'rotate-180' : ''}`} />
|
|
535
|
+
</button>
|
|
536
|
+
|
|
537
|
+
{/* Expands IN PLACE. A flyout here was `absolute` inside the overflow
|
|
538
|
+
panel, which scrolls — so it was clipped by its own container and
|
|
539
|
+
read as a dead control. */}
|
|
540
|
+
{open && (
|
|
541
|
+
<div className="mb-1 ml-1.5 border-l border-[var(--m3-outline-variant)] pl-1.5" data-split-arrange-menu="">
|
|
542
|
+
{ARRANGE_PRESETS.map((preset) => {
|
|
543
|
+
const enabled = paneCount >= preset.minPanes
|
|
544
|
+
return (
|
|
545
|
+
<button
|
|
546
|
+
key={preset.id}
|
|
547
|
+
type="button"
|
|
548
|
+
disabled={!enabled}
|
|
549
|
+
onClick={() => pick(preset.id)}
|
|
550
|
+
className={`flex w-full items-start gap-2 rounded-m3-sm px-2 py-1.5 text-left transition-colors duration-[var(--m3-duration-short2)] ease-m3-standard ${
|
|
551
|
+
enabled
|
|
552
|
+
? 'hover:bg-[var(--m3-state-layer-hover)] active:bg-[var(--m3-state-layer-pressed)]'
|
|
553
|
+
: 'cursor-not-allowed text-[var(--m3-on-surface-variant)] opacity-[var(--m3-disabled-content-opacity)]'
|
|
554
|
+
}`}
|
|
555
|
+
data-split-arrange-preset={preset.id}
|
|
556
|
+
title={enabled ? preset.hint : `Needs at least ${preset.minPanes} tables`}
|
|
557
|
+
>
|
|
558
|
+
{preset.id === 'rows'
|
|
559
|
+
? <Rows2 className="mt-0.5 h-3.5 w-3.5 shrink-0 text-[var(--m3-on-surface-variant)]" />
|
|
560
|
+
: preset.id === 'columns'
|
|
561
|
+
? <Columns2 className="mt-0.5 h-3.5 w-3.5 shrink-0 text-[var(--m3-on-surface-variant)]" />
|
|
562
|
+
: <LayoutGrid className="mt-0.5 h-3.5 w-3.5 shrink-0 text-[var(--m3-on-surface-variant)]" />}
|
|
563
|
+
<span className="min-w-0">
|
|
564
|
+
<span className="block text-body-regular-xs">{preset.label}</span>
|
|
565
|
+
<span className="block text-body-regular-xs text-[var(--m3-on-surface-variant)]">{preset.hint}</span>
|
|
566
|
+
</span>
|
|
567
|
+
</button>
|
|
568
|
+
)
|
|
569
|
+
})}
|
|
570
|
+
<button
|
|
571
|
+
type="button"
|
|
572
|
+
onClick={() => { onApply({ ...layout, root: evenAll(layout.root) }); setOpen(false); closeMenu() }}
|
|
573
|
+
className="w-full rounded-m3-sm px-2 py-1.5 text-left text-body-regular-xs transition-colors duration-[var(--m3-duration-short2)] ease-m3-standard hover:bg-[var(--m3-state-layer-hover)] active:bg-[var(--m3-state-layer-pressed)]"
|
|
574
|
+
data-split-arrange-even=""
|
|
575
|
+
>
|
|
576
|
+
Reset sizes
|
|
577
|
+
</button>
|
|
578
|
+
</div>
|
|
579
|
+
)}
|
|
580
|
+
</div>
|
|
581
|
+
)
|
|
582
|
+
}
|
|
583
|
+
|
|
584
|
+
/**
|
|
585
|
+
* A template's shape, drawn from the tree itself.
|
|
586
|
+
*
|
|
587
|
+
* Deriving the thumbnail from `build()` rather than hand-drawing six icons
|
|
588
|
+
* means a template can never advertise a shape it does not produce.
|
|
589
|
+
*/
|
|
590
|
+
function TemplatePreview({ node, selected }: { node: LayoutNode; selected?: boolean }) {
|
|
591
|
+
if (node.kind !== 'split') {
|
|
592
|
+
return (
|
|
593
|
+
<div
|
|
594
|
+
className={`flex-1 rounded-m3-xs ${
|
|
595
|
+
selected
|
|
596
|
+
? 'bg-[color-mix(in_srgb,var(--m3-on-secondary-container)_60%,transparent)]'
|
|
597
|
+
: 'bg-[var(--m3-outline)]'
|
|
598
|
+
}`}
|
|
599
|
+
/>
|
|
600
|
+
)
|
|
601
|
+
}
|
|
602
|
+
return (
|
|
603
|
+
<div className={`flex flex-1 gap-[2px] ${node.direction === 'row' ? 'flex-row' : 'flex-col'}`}>
|
|
604
|
+
{node.children.map((child, index) => (
|
|
605
|
+
<TemplatePreview key={index} node={child} selected={selected} />
|
|
606
|
+
))}
|
|
607
|
+
</div>
|
|
608
|
+
)
|
|
609
|
+
}
|
|
610
|
+
|
|
611
|
+
/**
|
|
612
|
+
* A layout's SHAPE, ignoring what fills it — `p`, `r(p,p)`, `c(p,r(p,p))`.
|
|
613
|
+
*
|
|
614
|
+
* Two layouts with the same signature occupy the same grid, which is exactly
|
|
615
|
+
* what makes a template "the one you are currently in". The gallery had no
|
|
616
|
+
* selected state at all before this.
|
|
617
|
+
*/
|
|
618
|
+
function shapeSignature(node: LayoutNode): string {
|
|
619
|
+
if (node.kind !== 'split') return 'p'
|
|
620
|
+
return `${node.direction === 'row' ? 'r' : 'c'}(${node.children.map(shapeSignature).join(',')})`
|
|
621
|
+
}
|
|
622
|
+
|
|
623
|
+
/**
|
|
624
|
+
* Pick a SHAPE, fill it afterwards — the layout-first flow.
|
|
625
|
+
*
|
|
626
|
+
* Sits beside `ArrangeMenu` in the same overflow menu, and the two are labelled
|
|
627
|
+
* apart because they answer different questions: a template says how many cells
|
|
628
|
+
* there are, a preset says where the cells you already filled should go.
|
|
629
|
+
* Existing panes are poured into the new shape, so choosing one never closes
|
|
630
|
+
* the table you are looking at.
|
|
631
|
+
*/
|
|
632
|
+
function TemplatesMenu({
|
|
633
|
+
layout,
|
|
634
|
+
onApply,
|
|
635
|
+
}: {
|
|
636
|
+
layout: SplitLayout
|
|
637
|
+
onApply: (next: SplitLayout) => void
|
|
638
|
+
}) {
|
|
639
|
+
const [open, setOpen] = React.useState(false)
|
|
640
|
+
const closeMenu = useToolbarOverflowClose()
|
|
641
|
+
const currentShape = shapeSignature(layout.root)
|
|
642
|
+
|
|
643
|
+
const pick = (id: GridTemplateId) => {
|
|
644
|
+
onApply(applyGridTemplate(layout, id))
|
|
645
|
+
setOpen(false)
|
|
646
|
+
closeMenu()
|
|
647
|
+
}
|
|
648
|
+
|
|
649
|
+
return (
|
|
650
|
+
<div data-split-templates-section="">
|
|
651
|
+
<button
|
|
652
|
+
type="button"
|
|
653
|
+
onClick={() => setOpen((value) => !value)}
|
|
654
|
+
title="Choose a grid"
|
|
655
|
+
aria-expanded={open}
|
|
656
|
+
className={M3_MENU_ROW}
|
|
657
|
+
data-split-templates=""
|
|
658
|
+
>
|
|
659
|
+
<span className="flex w-4 shrink-0 justify-center"><Grid2x2 className="h-3.5 w-3.5 text-[var(--m3-on-surface-variant)]" /></span>
|
|
660
|
+
<span className="flex-1">Grid template</span>
|
|
661
|
+
<ChevronDown className={`h-3 w-3 text-[var(--m3-on-surface-variant)] transition-transform duration-[var(--m3-duration-short2)] ease-m3-standard ${open ? 'rotate-180' : ''}`} />
|
|
662
|
+
</button>
|
|
663
|
+
|
|
664
|
+
{/* Expands IN PLACE for the same reason ArrangeMenu does — a flyout is
|
|
665
|
+
clipped by the scrolling overflow panel it lives in. */}
|
|
666
|
+
{open && (
|
|
667
|
+
<div className="mb-1 ml-1.5 grid grid-cols-3 gap-1 border-l border-[var(--m3-outline-variant)] py-1 pl-1.5" data-split-templates-menu="">
|
|
668
|
+
{GRID_TEMPLATE_LIST.map((template) => {
|
|
669
|
+
const shape = template.build()
|
|
670
|
+
// The template whose SHAPE the workspace is already in. Marked with
|
|
671
|
+
// the same `secondary-container` swap selection uses everywhere.
|
|
672
|
+
const isCurrent = shapeSignature(shape) === currentShape
|
|
673
|
+
return (
|
|
674
|
+
<button
|
|
675
|
+
key={template.id}
|
|
676
|
+
type="button"
|
|
677
|
+
onClick={() => pick(template.id)}
|
|
678
|
+
title={`${template.label} — ${template.hint}`}
|
|
679
|
+
aria-label={template.label}
|
|
680
|
+
aria-pressed={isCurrent}
|
|
681
|
+
className={`flex flex-col items-center gap-1 rounded-m3-sm p-1 transition-colors duration-[var(--m3-duration-short2)] ease-m3-standard ${
|
|
682
|
+
isCurrent
|
|
683
|
+
? 'bg-[var(--m3-secondary-container)] text-[var(--m3-on-secondary-container)]'
|
|
684
|
+
: 'text-[var(--m3-on-surface-variant)] hover:bg-[var(--m3-state-layer-hover)] active:bg-[var(--m3-state-layer-pressed)]'
|
|
685
|
+
}`}
|
|
686
|
+
data-split-template={template.id}
|
|
687
|
+
>
|
|
688
|
+
<span className="flex h-8 w-full gap-[2px] rounded-m3-xs border border-[var(--m3-outline-variant)] p-[2px]">
|
|
689
|
+
<TemplatePreview node={shape} selected={isCurrent} />
|
|
690
|
+
</span>
|
|
691
|
+
<span className="text-body-regular-xs">{template.slots}</span>
|
|
692
|
+
</button>
|
|
693
|
+
)
|
|
694
|
+
})}
|
|
695
|
+
</div>
|
|
696
|
+
)}
|
|
697
|
+
</div>
|
|
698
|
+
)
|
|
699
|
+
}
|
|
700
|
+
|
|
701
|
+
/** Save / reopen named layouts. Personal-only in v1. */
|
|
702
|
+
function LayoutsMenu({
|
|
703
|
+
anchorTableId,
|
|
704
|
+
layout,
|
|
705
|
+
onApply,
|
|
706
|
+
}: {
|
|
707
|
+
anchorTableId: string
|
|
708
|
+
layout: SplitLayout
|
|
709
|
+
onApply: (layout: SplitLayout) => void
|
|
710
|
+
}) {
|
|
711
|
+
const { layouts, save, remove } = useSplitViewLayouts(anchorTableId)
|
|
712
|
+
const [open, setOpen] = React.useState(false)
|
|
713
|
+
const [name, setName] = React.useState('')
|
|
714
|
+
const closeMenu = useToolbarOverflowClose()
|
|
715
|
+
|
|
716
|
+
const commit = async () => {
|
|
717
|
+
const trimmed = name.trim()
|
|
718
|
+
if (!trimmed) return
|
|
719
|
+
await save(trimmed, layout)
|
|
720
|
+
setName('')
|
|
721
|
+
setOpen(false)
|
|
722
|
+
closeMenu()
|
|
723
|
+
}
|
|
724
|
+
|
|
725
|
+
return (
|
|
726
|
+
<div data-split-layouts-section="">
|
|
727
|
+
<button
|
|
728
|
+
type="button"
|
|
729
|
+
onClick={() => setOpen((v) => !v)}
|
|
730
|
+
aria-expanded={open}
|
|
731
|
+
className={M3_MENU_ROW}
|
|
732
|
+
data-split-layouts=""
|
|
733
|
+
>
|
|
734
|
+
<span className="flex w-4 shrink-0 justify-center"><Save className="h-3.5 w-3.5 text-[var(--m3-on-surface-variant)]" /></span>
|
|
735
|
+
<span className="flex-1">Layouts</span>
|
|
736
|
+
<ChevronDown className={`h-3 w-3 text-[var(--m3-on-surface-variant)] transition-transform duration-[var(--m3-duration-short2)] ease-m3-standard ${open ? 'rotate-180' : ''}`} />
|
|
737
|
+
</button>
|
|
738
|
+
|
|
739
|
+
{open && (
|
|
740
|
+
<div className="mb-1 ml-1.5 border-l border-[var(--m3-outline-variant)] pl-1.5" data-split-layouts-menu="">
|
|
741
|
+
<div className="flex items-center gap-1 pb-1">
|
|
742
|
+
<input
|
|
743
|
+
value={name}
|
|
744
|
+
onChange={(e) => setName(e.target.value)}
|
|
745
|
+
onKeyDown={(e) => {
|
|
746
|
+
// Cmd/Ctrl+Enter submits, Escape cancels — the dialog contract.
|
|
747
|
+
if (e.key === 'Enter') { e.preventDefault(); void commit() }
|
|
748
|
+
if (e.key === 'Escape') { e.preventDefault(); setOpen(false) }
|
|
749
|
+
}}
|
|
750
|
+
placeholder="Save current as…"
|
|
751
|
+
// Was `outline-none` with no field affordance whatsoever — an
|
|
752
|
+
// a11y defect. A field now looks like a field, and focus is the
|
|
753
|
+
// teal interaction-affirmative signal, not the blue selection one.
|
|
754
|
+
className="min-w-0 flex-1 rounded-m3-xs border border-[var(--m3-outline)] bg-[var(--m3-surface-container-lowest)] px-1.5 py-1 text-body-regular-xs text-[var(--m3-on-surface)] transition-[color,background-color,border-color,box-shadow] duration-[var(--m3-duration-short2)] ease-m3-standard placeholder:text-[var(--m3-on-surface-variant)] focus-visible:border-[var(--m3-focus-ring-color)] focus-visible:shadow-[var(--m3-focus-halo)] focus-visible:outline-none"
|
|
755
|
+
data-split-layout-name=""
|
|
756
|
+
/>
|
|
757
|
+
<button
|
|
758
|
+
type="button"
|
|
759
|
+
onClick={() => void commit()}
|
|
760
|
+
className="shrink-0 rounded-m3-full px-2 py-1 text-body-regular-xs text-[var(--m3-on-surface)] transition-colors duration-[var(--m3-duration-short2)] ease-m3-standard hover:bg-[var(--m3-state-layer-hover)] active:bg-[var(--m3-state-layer-pressed)]"
|
|
761
|
+
data-split-layout-save=""
|
|
762
|
+
>
|
|
763
|
+
Save
|
|
764
|
+
</button>
|
|
765
|
+
</div>
|
|
766
|
+
|
|
767
|
+
{layouts.length === 0 && (
|
|
768
|
+
<div className="px-2 py-3 text-center text-body-regular-xs text-[var(--m3-on-surface-variant)]" data-split-layouts-empty="">
|
|
769
|
+
No saved layouts yet.
|
|
770
|
+
</div>
|
|
771
|
+
)}
|
|
772
|
+
{layouts.map((saved) => (
|
|
773
|
+
<div key={saved.id} className="flex items-center gap-1">
|
|
774
|
+
<button
|
|
775
|
+
type="button"
|
|
776
|
+
onClick={() => { onApply(saved.layout); setOpen(false); closeMenu() }}
|
|
777
|
+
className="flex-1 truncate rounded-m3-xs px-2 py-1 text-left text-body-regular-xs text-[var(--m3-on-surface)] transition-colors duration-[var(--m3-duration-short2)] ease-m3-standard hover:bg-[var(--m3-state-layer-hover)] active:bg-[var(--m3-state-layer-pressed)]"
|
|
778
|
+
data-split-layout-open={saved.name}
|
|
779
|
+
>
|
|
780
|
+
{saved.name}
|
|
781
|
+
</button>
|
|
782
|
+
<button
|
|
783
|
+
type="button"
|
|
784
|
+
onClick={() => void remove(saved.id)}
|
|
785
|
+
aria-label={`Delete ${saved.name}`}
|
|
786
|
+
className="rounded-m3-full p-1 text-[var(--m3-on-surface-variant)] transition-colors duration-[var(--m3-duration-short2)] ease-m3-standard hover:bg-[var(--m3-state-layer-error-hover)] hover:text-[var(--m3-error)]"
|
|
787
|
+
data-split-layout-delete={saved.name}
|
|
788
|
+
>
|
|
789
|
+
<Trash2 className="h-3 w-3" />
|
|
790
|
+
</button>
|
|
791
|
+
</div>
|
|
792
|
+
))}
|
|
793
|
+
</div>
|
|
794
|
+
)}
|
|
795
|
+
</div>
|
|
796
|
+
)
|
|
797
|
+
}
|
|
798
|
+
|
|
799
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
800
|
+
|
|
801
|
+
export type SplitViewHostProps = {
|
|
802
|
+
/** The table this page is for — the initial, and always first, pane. */
|
|
803
|
+
tableId: string
|
|
804
|
+
}
|
|
805
|
+
|
|
806
|
+
/**
|
|
807
|
+
* Fill the available height.
|
|
808
|
+
*
|
|
809
|
+
* `h-full` cannot chain here: the AppShell's `<main>` has a real flex height,
|
|
810
|
+
* but the page wrappers between it and us are block-level with `height: auto`,
|
|
811
|
+
* so a percentage height resolves against `auto` and collapses to content.
|
|
812
|
+
* Panes then sit at their minimum and the layout looks broken at any pane
|
|
813
|
+
* count > 1.
|
|
814
|
+
*
|
|
815
|
+
* Measure the nearest SCROLL ancestor's client bottom and set an explicit
|
|
816
|
+
* height — the same technique `DynamicTable` already uses for `height: 'fill'`
|
|
817
|
+
* (DynamicTable.tsx), so the two agree instead of fighting.
|
|
818
|
+
*/
|
|
819
|
+
function useFilledHeight(enabled: boolean) {
|
|
820
|
+
const ref = React.useRef<HTMLDivElement>(null)
|
|
821
|
+
const [height, setHeight] = React.useState<number | null>(null)
|
|
822
|
+
|
|
823
|
+
React.useLayoutEffect(() => {
|
|
824
|
+
if (!enabled) {
|
|
825
|
+
setHeight(null)
|
|
826
|
+
return
|
|
827
|
+
}
|
|
828
|
+
const element = ref.current
|
|
829
|
+
if (!element) return
|
|
830
|
+
|
|
831
|
+
let scrollPane: HTMLElement | null = element.parentElement
|
|
832
|
+
while (scrollPane && scrollPane !== document.body) {
|
|
833
|
+
const overflowY = getComputedStyle(scrollPane).overflowY
|
|
834
|
+
if (overflowY === 'auto' || overflowY === 'scroll') break
|
|
835
|
+
scrollPane = scrollPane.parentElement
|
|
836
|
+
}
|
|
837
|
+
|
|
838
|
+
const measure = () => {
|
|
839
|
+
const rect = element.getBoundingClientRect()
|
|
840
|
+
const bottom =
|
|
841
|
+
scrollPane && scrollPane !== document.body
|
|
842
|
+
? Math.min(
|
|
843
|
+
window.innerHeight,
|
|
844
|
+
Math.round(scrollPane.getBoundingClientRect().top) + scrollPane.clientHeight,
|
|
845
|
+
)
|
|
846
|
+
: window.innerHeight
|
|
847
|
+
setHeight(Math.max(Math.floor(bottom - rect.top), 320))
|
|
848
|
+
}
|
|
849
|
+
|
|
850
|
+
measure()
|
|
851
|
+
window.addEventListener('resize', measure)
|
|
852
|
+
const observer = new ResizeObserver(measure)
|
|
853
|
+
if (scrollPane && scrollPane !== document.body) observer.observe(scrollPane)
|
|
854
|
+
return () => {
|
|
855
|
+
window.removeEventListener('resize', measure)
|
|
856
|
+
observer.disconnect()
|
|
857
|
+
}
|
|
858
|
+
}, [enabled])
|
|
859
|
+
|
|
860
|
+
return { ref, height }
|
|
861
|
+
}
|
|
862
|
+
|
|
863
|
+
/**
|
|
864
|
+
* The "no shared criteria" value, frozen at module scope.
|
|
865
|
+
*
|
|
866
|
+
* Identity matters: `criteria` is read off the layout and feeds the memo that
|
|
867
|
+
* projects criteria onto every pane. A fresh `{ rules: [] }` per render would
|
|
868
|
+
* change identity each time and re-project on every render of the host — the
|
|
869
|
+
* same reason `sharedCriteria.ts` freezes its own `NOTHING`.
|
|
870
|
+
*/
|
|
871
|
+
const EMPTY_CRITERIA: SharedCriteria = Object.freeze({
|
|
872
|
+
rules: Object.freeze([]) as unknown as SharedCriteria['rules'],
|
|
873
|
+
})
|
|
874
|
+
|
|
875
|
+
export function SplitViewHost({ tableId }: SplitViewHostProps) {
|
|
876
|
+
const registry = useTableRegistry()
|
|
877
|
+
|
|
878
|
+
// Restored SYNCHRONOUSLY in the initializer, not in an effect: an effect
|
|
879
|
+
// would paint one default pane first and then swap in the real arrangement,
|
|
880
|
+
// which reads as a flash and remounts every grid it restores.
|
|
881
|
+
//
|
|
882
|
+
// `registry.tables` is the accessible set, so a pane whose table the user
|
|
883
|
+
// may no longer open is dropped rather than mounted as an empty box.
|
|
884
|
+
const [layout, setLayout] = React.useState<SplitLayout>(() => {
|
|
885
|
+
const known = new Set(registry.tables.map((table) => table.metadata.id))
|
|
886
|
+
// Tables are pruned against the registry, which is available synchronously.
|
|
887
|
+
//
|
|
888
|
+
// Widgets are NOT pruned here, deliberately. The widget catalogue is
|
|
889
|
+
// fetched (react-query), so at this first synchronous paint it is still
|
|
890
|
+
// empty — pruning against it would drop every widget pane on every reload,
|
|
891
|
+
// which is exactly the defect TC-APP-604 caught: widgets rendered fine in
|
|
892
|
+
// session and silently vanished on refresh.
|
|
893
|
+
//
|
|
894
|
+
// Nothing is lost by keeping them: `WidgetPane` resolves its own content
|
|
895
|
+
// through `useContentById` and already renders the same 'unknown' /
|
|
896
|
+
// 'denied' messages a table pane does, so a widget the user can no longer
|
|
897
|
+
// open degrades in THAT PANE ALONE rather than being deleted from their
|
|
898
|
+
// saved arrangement behind their back.
|
|
899
|
+
const stored = readStoredLayout(tableId, (content) =>
|
|
900
|
+
content.kind === 'table' ? known.has(content.tableId) : true,
|
|
901
|
+
)
|
|
902
|
+
return (
|
|
903
|
+
stored ?? {
|
|
904
|
+
root: { kind: 'pane', id: makePaneId(), content: tableContent(tableId) },
|
|
905
|
+
version: SPLIT_LAYOUT_VERSION,
|
|
906
|
+
}
|
|
907
|
+
)
|
|
908
|
+
})
|
|
909
|
+
|
|
910
|
+
// Every mutation funnels through `setLayout`, so one effect covers splits,
|
|
911
|
+
// closes, divider drags, arrange presets, chrome toggles and named-layout
|
|
912
|
+
// opens — there is no path that changes the layout without being saved.
|
|
913
|
+
//
|
|
914
|
+
// Coalesced on an animation frame because ONE of those paths is continuous:
|
|
915
|
+
// a divider drag calls `setLayout` per `mousemove`, and each write does a
|
|
916
|
+
// `getItem` for scope resolution, a `JSON.stringify` of the whole tree, a
|
|
917
|
+
// `setItem` and up to two `removeItem`s — ~60 synchronous storage round-trips
|
|
918
|
+
// a second, on the same thread that is re-rendering every grid in the layout.
|
|
919
|
+
// The frame callback keeps discrete mutations effectively immediate (next
|
|
920
|
+
// paint) while collapsing a drag to one write per frame, and the cleanup
|
|
921
|
+
// flushes synchronously so nothing is lost on unmount or a tableId change.
|
|
922
|
+
React.useEffect(() => {
|
|
923
|
+
let frame: number | null = requestAnimationFrame(() => {
|
|
924
|
+
frame = null
|
|
925
|
+
writeStoredLayout(tableId, layout)
|
|
926
|
+
})
|
|
927
|
+
return () => {
|
|
928
|
+
if (frame === null) return
|
|
929
|
+
cancelAnimationFrame(frame)
|
|
930
|
+
writeStoredLayout(tableId, layout)
|
|
931
|
+
}
|
|
932
|
+
}, [tableId, layout])
|
|
933
|
+
/**
|
|
934
|
+
* What the picker will do with the table you choose: split an existing pane
|
|
935
|
+
* along an axis, or fill an empty slot in place.
|
|
936
|
+
*/
|
|
937
|
+
const [pending, setPending] = React.useState<
|
|
938
|
+
| { mode: 'split'; slotId: string; direction: SplitDirection; before: boolean; anchor: DOMRect | null }
|
|
939
|
+
| { mode: 'fill'; slotId: string; anchor: DOMRect | null }
|
|
940
|
+
| null
|
|
941
|
+
>(null)
|
|
942
|
+
const containerRef = React.useRef<HTMLDivElement>(null)
|
|
943
|
+
const fill = useFilledHeight(true)
|
|
944
|
+
|
|
945
|
+
// ── Workspace-shared search and filtering ──
|
|
946
|
+
//
|
|
947
|
+
// Held HERE, at the host, because it is a property of the workspace rather
|
|
948
|
+
// than of any pane. Each pane receives only the projection of it that that
|
|
949
|
+
// pane can actually honour, translated into its own field names.
|
|
950
|
+
//
|
|
951
|
+
// Off by default: a workspace only starts driving its panes once the user
|
|
952
|
+
// asks it to, so a single-pane page behaves exactly as it always did.
|
|
953
|
+
//
|
|
954
|
+
// These live ON THE LAYOUT, not in component state beside it.
|
|
955
|
+
//
|
|
956
|
+
// `SplitLayout` has carried `sharedCriteria` / `sharedFiltersEnabled` since v3
|
|
957
|
+
// and `normalizeLayout` deliberately preserves both, but the host used to hold
|
|
958
|
+
// them in `useState` and never read or wrote the layout fields — so enabling
|
|
959
|
+
// the bar, adding a rule and reloading lost all of it. (The persistence test
|
|
960
|
+
// passes either way: it drives the storage layer directly, never the host.)
|
|
961
|
+
//
|
|
962
|
+
// Deriving rather than mirroring is what makes opening a SAVED NAMED LAYOUT
|
|
963
|
+
// work: its criteria arrive through `setLayout` like any other change, and are
|
|
964
|
+
// simply read. A `useState` seeded once at mount would have been overwritten by
|
|
965
|
+
// the stale component value the moment the named layout landed.
|
|
966
|
+
//
|
|
967
|
+
// Reads go through the layout; writes go through `setLayout`, so they ride the
|
|
968
|
+
// same persistence funnel as every other mutation — no second save path.
|
|
969
|
+
const sharedEnabled = layout.sharedFiltersEnabled ?? false
|
|
970
|
+
// `sharedCriteria` is typed `unknown` on the layout ON PURPOSE — the persistence
|
|
971
|
+
// layer carries it through a write/read cycle without knowing the vocabulary
|
|
972
|
+
// (types.ts:117-122). Narrowing happens here, at the one place that does know,
|
|
973
|
+
// and anything that is not a well-formed criteria object degrades to empty
|
|
974
|
+
// rather than throwing on a hand-edited or older stored layout.
|
|
975
|
+
const criteria = React.useMemo<SharedCriteria>(() => {
|
|
976
|
+
const stored = layout.sharedCriteria
|
|
977
|
+
if (!stored || typeof stored !== 'object') return EMPTY_CRITERIA
|
|
978
|
+
const candidate = stored as Partial<SharedCriteria>
|
|
979
|
+
return Array.isArray(candidate.rules) ? (stored as SharedCriteria) : EMPTY_CRITERIA
|
|
980
|
+
}, [layout.sharedCriteria])
|
|
981
|
+
const setSharedEnabled = React.useCallback(
|
|
982
|
+
(next: boolean | ((on: boolean) => boolean)) => {
|
|
983
|
+
setLayout((current) => {
|
|
984
|
+
const was = current.sharedFiltersEnabled ?? false
|
|
985
|
+
const value = typeof next === 'function' ? next(was) : next
|
|
986
|
+
return value === was ? current : { ...current, sharedFiltersEnabled: value }
|
|
987
|
+
})
|
|
988
|
+
},
|
|
989
|
+
[],
|
|
990
|
+
)
|
|
991
|
+
const setCriteria = React.useCallback((next: SharedCriteria) => {
|
|
992
|
+
setLayout((current) =>
|
|
993
|
+
current.sharedCriteria === next ? current : { ...current, sharedCriteria: next },
|
|
994
|
+
)
|
|
995
|
+
}, [])
|
|
996
|
+
const liveCriteria = sharedEnabled ? criteria : null
|
|
997
|
+
const hrefFor = React.useCallback(
|
|
998
|
+
(id: string) => registry.tables.find((table) => table.metadata.id === id)?.metadata.href,
|
|
999
|
+
[registry.tables],
|
|
1000
|
+
)
|
|
1001
|
+
|
|
1002
|
+
const panes = React.useMemo(() => listPanes(layout.root), [layout])
|
|
1003
|
+
const slotCount = React.useMemo(() => countSlots(layout.root), [layout])
|
|
1004
|
+
const isSplit = slotCount > 1
|
|
1005
|
+
/**
|
|
1006
|
+
* The primary pane is the one holding THIS PAGE'S table — matched by identity,
|
|
1007
|
+
* never by position.
|
|
1008
|
+
*
|
|
1009
|
+
* This used to be `panes[0]`, i.e. document order. But `splitPane(..., before)`
|
|
1010
|
+
* inserts the new pane FIRST (`types.ts:436`), and the "Left" and "Above"
|
|
1011
|
+
* actions both pass `before: true` — so adding a table to the left of the page's
|
|
1012
|
+
* own table handed pane[0], and with it the UNSCOPED storage keys, to the newly
|
|
1013
|
+
* added table. Two things broke at once: the new pane wrote its column widths
|
|
1014
|
+
* over the standalone page's keys for that table, and the page's own table was
|
|
1015
|
+
* demoted to a `pane:<id>:` scope, silently discarding the widths and last-used
|
|
1016
|
+
* view the user had saved. Closing the pane flipped it back mid-session.
|
|
1017
|
+
* `applyPreset` / `applyGridTemplate` pour panes into slots in document order
|
|
1018
|
+
* too, so they inverted it the same way.
|
|
1019
|
+
*
|
|
1020
|
+
* Falls back to the first pane only when this page's table is not in the layout
|
|
1021
|
+
* at all (every pane replaced), which keeps a single pane unscoped as before.
|
|
1022
|
+
*/
|
|
1023
|
+
const primaryPaneId = React.useMemo(() => {
|
|
1024
|
+
const own = panes.find(
|
|
1025
|
+
(pane) => pane.content.kind === 'table' && pane.content.tableId === tableId,
|
|
1026
|
+
)
|
|
1027
|
+
return (own ?? panes[0])?.id
|
|
1028
|
+
}, [panes, tableId])
|
|
1029
|
+
|
|
1030
|
+
/**
|
|
1031
|
+
* Project the workspace criteria onto each pane, in that pane's own field
|
|
1032
|
+
* names — plus the list of criteria it could NOT honour.
|
|
1033
|
+
*
|
|
1034
|
+
* Computed here rather than inside each pane because the unmapped report is a
|
|
1035
|
+
* WORKSPACE-level statement ("2 panes are not filtered by customer"), and a
|
|
1036
|
+
* pane reporting upward during its own render would be a write during render.
|
|
1037
|
+
*/
|
|
1038
|
+
const perPane = React.useMemo(() => {
|
|
1039
|
+
const filters = new Map<string, FilterRow[]>()
|
|
1040
|
+
const unmapped: UnmappedPaneReport[] = []
|
|
1041
|
+
for (const pane of panes) {
|
|
1042
|
+
const isTable = pane.content.kind === 'table'
|
|
1043
|
+
const definition = isTable
|
|
1044
|
+
? registry.tables.find((t) => t.metadata.id === (pane.content as { tableId: string }).tableId)
|
|
1045
|
+
: undefined
|
|
1046
|
+
const result = isTable
|
|
1047
|
+
? mapCriteriaForTable(liveCriteria, definition?.metadata)
|
|
1048
|
+
: mapCriteriaForWidget(liveCriteria, (pane.content as { widgetId: string }).widgetId)
|
|
1049
|
+
filters.set(pane.id, result.filters)
|
|
1050
|
+
if (result.unmapped.length > 0) {
|
|
1051
|
+
unmapped.push({
|
|
1052
|
+
paneId: pane.id,
|
|
1053
|
+
title: definition?.metadata.title ?? 'This pane',
|
|
1054
|
+
unmapped: result.unmapped,
|
|
1055
|
+
})
|
|
1056
|
+
}
|
|
1057
|
+
}
|
|
1058
|
+
return { filters, unmapped }
|
|
1059
|
+
}, [panes, registry.tables, liveCriteria])
|
|
1060
|
+
|
|
1061
|
+
// `''` (bar on, box empty) must reach the panes so their hidden search boxes
|
|
1062
|
+
// stop filtering; `undefined` (bar off) must NOT, so each pane keeps its own.
|
|
1063
|
+
const sharedSearch = liveCriteria ? (liveCriteria.search ?? '') : undefined
|
|
1064
|
+
|
|
1065
|
+
// Read `pending` from state, never from inside a `setPending` updater: React
|
|
1066
|
+
// treats updaters as pure and calls them twice under StrictMode, so a
|
|
1067
|
+
// setLayout side-effect in there is dropped or duplicated. That bug made
|
|
1068
|
+
// every split silently do nothing.
|
|
1069
|
+
const handlePick = React.useCallback(
|
|
1070
|
+
// Takes a full `PaneContentRef` rather than a table id, because the picker
|
|
1071
|
+
// now offers widgets too and only it knows which kind was chosen.
|
|
1072
|
+
(content: PaneContentRef) => {
|
|
1073
|
+
if (!pending) return
|
|
1074
|
+
setLayout((current) =>
|
|
1075
|
+
pending.mode === 'fill'
|
|
1076
|
+
? fillSlot(current, pending.slotId, content)
|
|
1077
|
+
: splitPane(current, pending.slotId, content, pending.direction, pending.before),
|
|
1078
|
+
)
|
|
1079
|
+
setPending(null)
|
|
1080
|
+
},
|
|
1081
|
+
[pending],
|
|
1082
|
+
)
|
|
1083
|
+
|
|
1084
|
+
const handleClose = React.useCallback((paneId: string) => {
|
|
1085
|
+
setLayout((current) => removePane(current, paneId))
|
|
1086
|
+
}, [])
|
|
1087
|
+
|
|
1088
|
+
/**
|
|
1089
|
+
* Divider drag. The delta is converted to a fraction of the SPLIT NODE's own
|
|
1090
|
+
* extent along its own axis, so a drag means the same proportion wherever the
|
|
1091
|
+
* node sits in the tree and whichever way it runs.
|
|
1092
|
+
*/
|
|
1093
|
+
const startDrag = React.useCallback(
|
|
1094
|
+
(splitPath: NodePath, index: number, start: number, axis: SplitDirection, element: HTMLElement) => {
|
|
1095
|
+
const container = element.parentElement
|
|
1096
|
+
if (!container) return
|
|
1097
|
+
const rect = container.getBoundingClientRect()
|
|
1098
|
+
const extent = axis === 'row' ? rect.width : rect.height
|
|
1099
|
+
if (extent <= 0) return
|
|
1100
|
+
let last = start
|
|
1101
|
+
|
|
1102
|
+
const onMove = (event: MouseEvent) => {
|
|
1103
|
+
const position = axis === 'row' ? event.clientX : event.clientY
|
|
1104
|
+
const delta = position - last
|
|
1105
|
+
if (delta === 0) return
|
|
1106
|
+
last = position
|
|
1107
|
+
setLayout((current) => resizeAt(current, splitPath, index, delta / extent))
|
|
1108
|
+
}
|
|
1109
|
+
const onUp = () => {
|
|
1110
|
+
document.removeEventListener('mousemove', onMove, true)
|
|
1111
|
+
document.removeEventListener('mouseup', onUp, true)
|
|
1112
|
+
document.body.style.userSelect = ''
|
|
1113
|
+
document.body.style.cursor = ''
|
|
1114
|
+
}
|
|
1115
|
+
// Suppress selection for the drag — without it a drag across a grid
|
|
1116
|
+
// selects cell text and the pointer flickers.
|
|
1117
|
+
document.body.style.userSelect = 'none'
|
|
1118
|
+
document.body.style.cursor = axis === 'row' ? 'col-resize' : 'row-resize'
|
|
1119
|
+
document.addEventListener('mousemove', onMove, true)
|
|
1120
|
+
document.addEventListener('mouseup', onUp, true)
|
|
1121
|
+
},
|
|
1122
|
+
[],
|
|
1123
|
+
)
|
|
1124
|
+
|
|
1125
|
+
/** Recursive renderer: a slot (filled or not), or a split laying children along its axis. */
|
|
1126
|
+
const renderNode = (node: LayoutNode, path: NodePath): React.ReactNode => {
|
|
1127
|
+
if (node.kind === 'empty') {
|
|
1128
|
+
return (
|
|
1129
|
+
<EmptySlot
|
|
1130
|
+
slotId={node.id}
|
|
1131
|
+
canRemove={slotCount > 1}
|
|
1132
|
+
onAdd={(anchor) => setPending({ mode: 'fill', slotId: node.id, anchor })}
|
|
1133
|
+
onRemove={() => handleClose(node.id)}
|
|
1134
|
+
/>
|
|
1135
|
+
)
|
|
1136
|
+
}
|
|
1137
|
+
|
|
1138
|
+
if (node.kind === 'pane') {
|
|
1139
|
+
const isPrimary = node.id === primaryPaneId
|
|
1140
|
+
const definitionHref = node.content.kind === 'table' ? hrefFor(node.content.tableId) : undefined
|
|
1141
|
+
// The pane's items are ROWS injected into the table's ONE overflow menu —
|
|
1142
|
+
// not a second button beside it.
|
|
1143
|
+
const paneRows = (
|
|
1144
|
+
<PaneMenuRows
|
|
1145
|
+
href={definitionHref}
|
|
1146
|
+
chrome={node.chrome}
|
|
1147
|
+
canClose={isSplit}
|
|
1148
|
+
// On EVERY pane, not just the primary one. Arrange and Layouts act on
|
|
1149
|
+
// the whole layout, so gating them behind one privileged pane meant
|
|
1150
|
+
// the controls appeared or vanished depending on which table's menu
|
|
1151
|
+
// you happened to open — with nothing on screen saying which pane was
|
|
1152
|
+
// the special one. Arrange also shows when unsplit: its presets
|
|
1153
|
+
// disable themselves with a "needs at least N tables" hint, which is
|
|
1154
|
+
// the discoverability this menu was designed for.
|
|
1155
|
+
extras={
|
|
1156
|
+
<>
|
|
1157
|
+
<TemplatesMenu layout={layout} onApply={setLayout} />
|
|
1158
|
+
<ArrangeMenu layout={layout} onApply={setLayout} />
|
|
1159
|
+
<SharedFilterToggle
|
|
1160
|
+
enabled={sharedEnabled}
|
|
1161
|
+
onToggle={() => setSharedEnabled((on) => !on)}
|
|
1162
|
+
/>
|
|
1163
|
+
<LayoutsMenu anchorTableId={tableId} layout={layout} onApply={setLayout} />
|
|
1164
|
+
</>
|
|
1165
|
+
}
|
|
1166
|
+
onSplit={(direction, before, anchor) =>
|
|
1167
|
+
setPending({ mode: 'split', slotId: node.id, direction, before, anchor })
|
|
1168
|
+
}
|
|
1169
|
+
onToggleChrome={(patch) => setLayout((current) => setPaneChrome(current, node.id, patch))}
|
|
1170
|
+
onClose={() => handleClose(node.id)}
|
|
1171
|
+
/>
|
|
1172
|
+
)
|
|
1173
|
+
const toolbarHidden = node.chrome?.toolbar === false
|
|
1174
|
+
return (
|
|
1175
|
+
<div
|
|
1176
|
+
// `flex-1` matters: without it a pane sizes to its CONTENT inside a
|
|
1177
|
+
// wrapper that has already been given a share, so after a height drag
|
|
1178
|
+
// the wrapper grows and the pane does not — leaving a visible gap.
|
|
1179
|
+
// The pane is an M3 OUTLINED card: a 16px corner, the softer
|
|
1180
|
+
// `outline-variant` hairline, elevation 0. Card chrome is applied
|
|
1181
|
+
// only when split — unsplit, `.hot-card` still draws its own frame
|
|
1182
|
+
// and a second one here would read as a concentric double hairline.
|
|
1183
|
+
// `overflow-hidden` is what clips the grid's square header to the
|
|
1184
|
+
// card radius, so it stays whatever else changes.
|
|
1185
|
+
className={`relative flex min-h-0 min-w-0 flex-1 flex-col overflow-hidden${
|
|
1186
|
+
isSplit
|
|
1187
|
+
? ' rounded-m3-lg border border-[var(--m3-outline-variant)] bg-[var(--m3-surface-container-lowest)]'
|
|
1188
|
+
: ''
|
|
1189
|
+
}`}
|
|
1190
|
+
data-pane-id={node.id}
|
|
1191
|
+
data-pane-table={node.content.kind === 'table' ? node.content.tableId : undefined}
|
|
1192
|
+
data-pane-widget={node.content.kind === 'widget' ? node.content.widgetId : undefined}
|
|
1193
|
+
data-pane-toolbar={toolbarHidden ? 'hidden' : undefined}
|
|
1194
|
+
>
|
|
1195
|
+
{/* Toolbar hidden means the overflow menu is hidden with it, so a user
|
|
1196
|
+
who hid it would have no way back. Float the same rows behind one
|
|
1197
|
+
small handle in the corner. */}
|
|
1198
|
+
{toolbarHidden && <PaneRestoreMenu>{paneRows}</PaneRestoreMenu>}
|
|
1199
|
+
<div className="min-h-0 flex-1 overflow-auto">
|
|
1200
|
+
<PaneBody
|
|
1201
|
+
content={node.content}
|
|
1202
|
+
paneId={node.id}
|
|
1203
|
+
isPrimary={isPrimary}
|
|
1204
|
+
multiview={isSplit}
|
|
1205
|
+
overflowExtras={paneRows}
|
|
1206
|
+
chrome={node.chrome}
|
|
1207
|
+
onWidgetSettingsChange={(next) =>
|
|
1208
|
+
setLayout((current) => setPaneContentSettings(current, node.id, next))
|
|
1209
|
+
}
|
|
1210
|
+
sharedFilters={perPane.filters.get(node.id)}
|
|
1211
|
+
sharedSearch={sharedSearch}
|
|
1212
|
+
/>
|
|
1213
|
+
</div>
|
|
1214
|
+
</div>
|
|
1215
|
+
)
|
|
1216
|
+
}
|
|
1217
|
+
|
|
1218
|
+
const isRow = node.direction === 'row'
|
|
1219
|
+
return (
|
|
1220
|
+
<div
|
|
1221
|
+
key={`split-${path.join('-')}`}
|
|
1222
|
+
className={`flex min-h-0 min-w-0 flex-1 ${isRow ? 'flex-row' : 'flex-col'}`}
|
|
1223
|
+
data-split-node={path.join('-') || 'root'}
|
|
1224
|
+
data-split-direction={node.direction}
|
|
1225
|
+
>
|
|
1226
|
+
{/* A nested split has no id of its own, so the key used to fall back to
|
|
1227
|
+
the array INDEX — and an index shifts when an earlier sibling is
|
|
1228
|
+
removed. Closing the first of `[paneA, split(B,C), paneD]` moved the
|
|
1229
|
+
nested split's key from `s1` to `s0`, so React unmounted and remounted
|
|
1230
|
+
that whole subtree: B and C lost scroll position, cell selection, any
|
|
1231
|
+
in-progress inline edit and any unsaved add-row draft, and each
|
|
1232
|
+
CellStore was recreated with its undo stack. Keying on the subtree's
|
|
1233
|
+
first SLOT id is stable across sibling removal, because slot ids are
|
|
1234
|
+
preserved by every tree op. */}
|
|
1235
|
+
{node.children.map((child, index) => (
|
|
1236
|
+
<React.Fragment
|
|
1237
|
+
key={child.kind === 'split' ? `s:${listSlots(child)[0]?.id ?? index}` : child.id}
|
|
1238
|
+
>
|
|
1239
|
+
<div
|
|
1240
|
+
className="flex min-h-0 min-w-0 flex-col"
|
|
1241
|
+
style={{
|
|
1242
|
+
flexGrow: node.sizes[index] ?? 1,
|
|
1243
|
+
flexShrink: 1,
|
|
1244
|
+
flexBasis: 0,
|
|
1245
|
+
minWidth: isRow ? PANE_MIN_WIDTH_PX : undefined,
|
|
1246
|
+
minHeight: !isRow ? PANE_MIN_HEIGHT_PX : undefined,
|
|
1247
|
+
}}
|
|
1248
|
+
>
|
|
1249
|
+
{renderNode(child, [...path, index])}
|
|
1250
|
+
</div>
|
|
1251
|
+
{index < node.children.length - 1 && (
|
|
1252
|
+
<div
|
|
1253
|
+
role="separator"
|
|
1254
|
+
aria-orientation={isRow ? 'vertical' : 'horizontal'}
|
|
1255
|
+
title="Drag to resize"
|
|
1256
|
+
onMouseDown={(event) => {
|
|
1257
|
+
event.preventDefault()
|
|
1258
|
+
startDrag(path, index, isRow ? event.clientX : event.clientY, node.direction, event.currentTarget)
|
|
1259
|
+
}}
|
|
1260
|
+
onDoubleClick={() => setLayout((current) => ({ ...current, root: evenAll(current.root) }))}
|
|
1261
|
+
// Stays 4px of LAYOUT. Widening it to a "real" 8px gutter
|
|
1262
|
+
// would take 4px of grid height off every horizontal split,
|
|
1263
|
+
// and density is the product — so the bigger pointer target is
|
|
1264
|
+
// bought for free by an OVERLAY (`::after`, -2px on each side)
|
|
1265
|
+
// that costs no space at all.
|
|
1266
|
+
//
|
|
1267
|
+
// At rest the gutter is EMPTY: the two pane cards already draw
|
|
1268
|
+
// their own outlines, so a hairline down the middle would put
|
|
1269
|
+
// three lines inside 4px. `::before` is the drag handle and
|
|
1270
|
+
// only colours in on hover — an accent pill, eased in.
|
|
1271
|
+
//
|
|
1272
|
+
// It must also stay a DIRECT sibling of the size wrappers:
|
|
1273
|
+
// `startDrag` measures `element.parentElement` for the drag
|
|
1274
|
+
// extent, so no wrapper, no `gap`, no padding on the split node.
|
|
1275
|
+
className={`relative z-10 shrink-0 bg-transparent before:absolute before:rounded-m3-full before:bg-transparent before:transition-colors before:duration-[var(--m3-duration-short2)] before:ease-m3-standard before:content-[''] hover:before:bg-[var(--m3-accent)] after:absolute after:content-[''] ${
|
|
1276
|
+
isRow
|
|
1277
|
+
? "w-1 cursor-col-resize before:inset-y-0 before:left-1/2 before:w-0.5 before:-translate-x-1/2 after:inset-y-0 after:-left-0.5 after:-right-0.5"
|
|
1278
|
+
: "h-1 cursor-row-resize before:inset-x-0 before:top-1/2 before:h-0.5 before:-translate-y-1/2 after:inset-x-0 after:-top-0.5 after:-bottom-0.5"
|
|
1279
|
+
}`}
|
|
1280
|
+
data-split-divider={`${path.join('-') || 'root'}:${index}`}
|
|
1281
|
+
/>
|
|
1282
|
+
)}
|
|
1283
|
+
</React.Fragment>
|
|
1284
|
+
))}
|
|
1285
|
+
</div>
|
|
1286
|
+
)
|
|
1287
|
+
}
|
|
1288
|
+
|
|
1289
|
+
return (
|
|
1290
|
+
<div
|
|
1291
|
+
ref={fill.ref}
|
|
1292
|
+
className="flex h-full min-h-0 flex-col bg-[var(--m3-surface)]"
|
|
1293
|
+
style={fill.height ? { height: fill.height } : undefined}
|
|
1294
|
+
data-split-view={isSplit ? 'true' : 'false'}
|
|
1295
|
+
data-shared-filters={sharedEnabled ? 'on' : 'off'}
|
|
1296
|
+
>
|
|
1297
|
+
{/* One row, and only while it is on. It replaces each pane's search row
|
|
1298
|
+
rather than adding to it, so N panes give back N rows for this one. */}
|
|
1299
|
+
{sharedEnabled && (
|
|
1300
|
+
<WorkspaceFilterBar
|
|
1301
|
+
criteria={criteria}
|
|
1302
|
+
onChange={setCriteria}
|
|
1303
|
+
unmappedByPane={perPane.unmapped}
|
|
1304
|
+
onToggleOff={() => setSharedEnabled(false)}
|
|
1305
|
+
/>
|
|
1306
|
+
)}
|
|
1307
|
+
<div
|
|
1308
|
+
ref={containerRef}
|
|
1309
|
+
// `px-2` and NEVER `p-2`: horizontal breathing room for the outermost
|
|
1310
|
+
// cards is free, but vertical padding would cost 16px of grid height on
|
|
1311
|
+
// every list page. Only while split, so an unsplit page is unchanged.
|
|
1312
|
+
className={`flex min-h-0 flex-1${isSplit ? ' px-2' : ''}`}
|
|
1313
|
+
// When the panes' minimums exceed the container, scroll rather than
|
|
1314
|
+
// crushing every pane below legibility.
|
|
1315
|
+
style={isSplit ? { overflow: 'auto' } : undefined}
|
|
1316
|
+
data-split-root=""
|
|
1317
|
+
>
|
|
1318
|
+
{renderNode(layout.root, [])}
|
|
1319
|
+
</div>
|
|
1320
|
+
|
|
1321
|
+
{pending && (
|
|
1322
|
+
<ContentPicker
|
|
1323
|
+
anchorRect={pending.anchor}
|
|
1324
|
+
// Tables AND widgets, both marked when already on screen rather than
|
|
1325
|
+
// hidden — a user looking for what they just opened should find it
|
|
1326
|
+
// where they expect, greyed, not absent.
|
|
1327
|
+
openContent={panes.map((pane) => pane.content)}
|
|
1328
|
+
onPick={handlePick}
|
|
1329
|
+
onClose={() => setPending(null)}
|
|
1330
|
+
/>
|
|
1331
|
+
)}
|
|
1332
|
+
</div>
|
|
1333
|
+
)
|
|
1334
|
+
}
|
|
1335
|
+
|
|
1336
|
+
export default SplitViewHost
|