@marimo-team/frontend 0.16.0 → 0.16.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/assets/ConnectedDataExplorerComponent-2wVcyvDj.js +19 -0
- package/dist/assets/{ImageComparisonComponent-fTHv1Ih0.js → ImageComparisonComponent-D2j6i0hv.js} +1 -1
- package/dist/assets/{VegaLite-Bdi-TyfY.js → VegaLite-BckFaf2D.js} +1 -1
- package/dist/assets/_baseEach-CvTX9w0Y.js +1 -0
- package/dist/assets/_baseMap-CtlwA90f.js +1 -0
- package/dist/assets/_baseUniq-BKktIGQ1.js +1 -0
- package/dist/assets/{_createAggregator-DcD0kTA5.js → _createAggregator-C5CVY-0t.js} +1 -1
- package/dist/assets/{agent-panel-Crv430aI.js → agent-panel-RGLNjkYe.js} +76 -57
- package/dist/assets/{any-language-editor-CQh552Wu.js → any-language-editor-DjuXwGCA.js} +1 -1
- package/dist/assets/{architectureDiagram-W76B3OCA-BAJeBxzt.js → architectureDiagram-W76B3OCA-Dyj4ds_R.js} +1 -1
- package/dist/assets/{between-horizontal-start-Boxgxbt_.js → between-horizontal-start-Dt2aKpPf.js} +1 -1
- package/dist/assets/{blockDiagram-QIGZ2CNN-CL-1svEK.js → blockDiagram-QIGZ2CNN-o-i7DDvN.js} +1 -1
- package/dist/assets/{c4Diagram-FPNF74CW-BbEqbCTl.js → c4Diagram-FPNF74CW-DGHEwWrx.js} +1 -1
- package/dist/assets/channel-Co6iMgWq.js +1 -0
- package/dist/assets/chat-panel-9alr8FS4.js +3 -0
- package/dist/assets/{chunk-4BX2VUAB-C--8TXeE.js → chunk-4BX2VUAB-BJecb-Ri.js} +1 -1
- package/dist/assets/{chunk-55IACEB6-Bj00HDqq.js → chunk-55IACEB6-CAATkc4w.js} +1 -1
- package/dist/assets/{chunk-FMBD7UC4-C-lhB6hN.js → chunk-FMBD7UC4-DPuNbQ-f.js} +1 -1
- package/dist/assets/{chunk-K7UQS3LO-B-pGTXPt.js → chunk-K7UQS3LO-C8TWVLiH.js} +1 -1
- package/dist/assets/{chunk-QN33PNHL-DqUzGhvm.js → chunk-QN33PNHL-DiZZ09q4.js} +1 -1
- package/dist/assets/{chunk-QZHKN3VN-TntJHfSk.js → chunk-QZHKN3VN-BIUM7usu.js} +1 -1
- package/dist/assets/{chunk-TVAH2DTR-HUJb1psV.js → chunk-TVAH2DTR-vGTArPBG.js} +1 -1
- package/dist/assets/{chunk-TZMSLE5B-BK3C__t3.js → chunk-TZMSLE5B-D2KRqp_x.js} +1 -1
- package/dist/assets/{circle-play-DBLOv1Yu.js → circle-play-cjeNez0N.js} +1 -1
- package/dist/assets/classDiagram-KNZD7YFC-BbJ0rY3y.js +1 -0
- package/dist/assets/classDiagram-v2-RKCZMP56-BbJ0rY3y.js +1 -0
- package/dist/assets/{clear-button-BeoFbEKH.js → clear-button-C97JtAez.js} +1 -1
- package/dist/assets/clone-BMP0PsTa.js +1 -0
- package/dist/assets/{command-palette-CXZiSv0I.js → command-palette-B93Pjcky.js} +1 -1
- package/dist/assets/{common-C7oJcmCT.js → common-Du9rSOwD.js} +1 -1
- package/dist/assets/{compile-7L0MwhyI.js → compile-CZXqyOxa.js} +1 -1
- package/dist/assets/{cose-bilkent-S5V4N54A-BMkGLcVC.js → cose-bilkent-S5V4N54A-CqUN5Y9b.js} +1 -1
- package/dist/assets/{dagre-5GWH7T2D-BJtRienS.js → dagre-5GWH7T2D-RJqTI9DM.js} +1 -1
- package/dist/assets/{data-grid-overlay-editor-DBkmGtNs.js → data-grid-overlay-editor-DZN0q1LV.js} +1 -1
- package/dist/assets/datasources-panel-v7H3cR0p.js +1 -0
- package/dist/assets/{dependency-graph-panel-DEdOxp2X.js → dependency-graph-panel-CEog_O7V.js} +1 -1
- package/dist/assets/{diagram-N5W7TBWH-CmECY3nb.js → diagram-N5W7TBWH-D-l4zZ9d.js} +1 -1
- package/dist/assets/{diagram-QEK2KX5R-DMOVSNKD.js → diagram-QEK2KX5R-CCOmBUt-.js} +1 -1
- package/dist/assets/{diagram-S2PKOQOG-BiJ96PNQ.js → diagram-S2PKOQOG-C_I_9jnZ.js} +1 -1
- package/dist/assets/{documentation-panel-xULhaEv3.js → documentation-panel-C1BtMZ3M.js} +1 -1
- package/dist/assets/edit-page-B-oevUZ9.js +129 -0
- package/dist/assets/{ellipsis-vertical-BBqXIlc2.js → ellipsis-vertical-BEb-J8z6.js} +1 -1
- package/dist/assets/{empty-state-B3dA3G5P.js → empty-state-C99UyDE3.js} +1 -1
- package/dist/assets/{erDiagram-AWTI2OKA-MP1DiFRo.js → erDiagram-AWTI2OKA-BePOLi5M.js} +1 -1
- package/dist/assets/{error-panel-Cc1sv-Ag.js → error-panel-Bs34jXFh.js} +1 -1
- package/dist/assets/file-explorer-panel-Ck6UL861.js +1 -0
- package/dist/assets/{flowDiagram-PVAE7QVJ-BX7caPp7.js → flowDiagram-PVAE7QVJ-BgjFu5l7.js} +1 -1
- package/dist/assets/{ganttDiagram-OWAHRB6G-B462g4Yf.js → ganttDiagram-OWAHRB6G-YOPb3XSV.js} +4 -4
- package/dist/assets/{gitGraphDiagram-NY62KEGX-CGgvZ9-9.js → gitGraphDiagram-NY62KEGX-CGhqaDTy.js} +1 -1
- package/dist/assets/{glide-data-editor-C0gUFZON.js → glide-data-editor-9QUH6iso.js} +11 -11
- package/dist/assets/{graph-CHRVBzY5.js → graph-DQQFGrho.js} +1 -1
- package/dist/assets/home-page-DRKpPCrF.js +9 -0
- package/dist/assets/{index-C1v_Z9et.js → index-2252nrk6.js} +1 -1
- package/dist/assets/{index-CQDrxQ0j.js → index-Aeo6WiK7.js} +1 -1
- package/dist/assets/{index-C4Tn5NvJ.js → index-B8jXZ12t.js} +1 -1
- package/dist/assets/{index-DoRmcrKM.js → index-BAbIIxHU.js} +1 -1
- package/dist/assets/{index-BY93Ejhl.js → index-BJNCMUmG.js} +1 -1
- package/dist/assets/{index-CpTPJo4k.js → index-BW3k9Gss.js} +1 -1
- package/dist/assets/{index-D1vmG6DS.js → index-BjgnbONl.js} +1 -1
- package/dist/assets/{index-z9bohSQJ.js → index-BprjMYH5.js} +1 -1
- package/dist/assets/{index-BVgAenPd.js → index-C1ez98sk.js} +1 -1
- package/dist/assets/{index-D9UKkrr2.js → index-C2MD0vgD.js} +1 -1
- package/dist/assets/index-C7CoaNFb.js +578 -0
- package/dist/assets/{index-C-GhZ7ti.js → index-CFKO7WXI.js} +1 -1
- package/dist/assets/{index-lYa_leQE.js → index-CUFv_thQ.js} +1 -1
- package/dist/assets/{index-vmICa5KN.js → index-C_tkBKNO.js} +1 -1
- package/dist/assets/{index-C77h_TXN.js → index-CfaDbEdi.js} +1 -1
- package/dist/assets/{index-DEQvTChO.js → index-ClzeQrN7.js} +1 -1
- package/dist/assets/index-DadI618h.css +1 -0
- package/dist/assets/{index-DRMm6SNo.js → index-DdnKZNxM.js} +1 -1
- package/dist/assets/{index-CWMgowgL.js → index-G5QZppK2.js} +1 -1
- package/dist/assets/{index-Clbi_Yaq.js → index-SGLNXrGP.js} +1 -1
- package/dist/assets/{index-C-8WADat.js → index-aE43R74q.js} +1 -1
- package/dist/assets/infoDiagram-STP46IZ2-CJLOpSAf.js +2 -0
- package/dist/assets/{isEmpty-DU_ogP_D.js → isEmpty-D-4c7sMv.js} +1 -1
- package/dist/assets/{journeyDiagram-BIP6EPQ6-C6EgLP_Q.js → journeyDiagram-BIP6EPQ6-C94u3Mv3.js} +1 -1
- package/dist/assets/{kanban-definition-6OIFK2YF-BXzYO1yj.js → kanban-definition-6OIFK2YF-BEXYFzz7.js} +1 -1
- package/dist/assets/{layout-jihVw5-i.js → layout-Bz2BJ2ru.js} +1 -1
- package/dist/assets/{linear-C4blANlC.js → linear-D8s7K76e.js} +1 -1
- package/dist/assets/links-BpXlz1GG.js +7 -0
- package/dist/assets/{logs-panel-D401qzZh.js → logs-panel-DC7wpmPz.js} +1 -1
- package/dist/assets/{markdown-renderer-Cd9eYyaL.js → markdown-renderer-DRdSWR9X.js} +20 -20
- package/dist/assets/{mermaid-BEVuRz_O.js → mermaid-Y3x4hmD0.js} +1 -1
- package/dist/assets/{mermaid.core-CaSnaLH0.js → mermaid.core-DzthE35Y.js} +4 -4
- package/dist/assets/min-BBO3-1Hg.js +1 -0
- package/dist/assets/{mindmap-definition-Q6HEUPPD-BXUM5MT2.js → mindmap-definition-Q6HEUPPD-DktvuLe1.js} +1 -1
- package/dist/assets/{number-overlay-editor-4uWXGlPG.js → number-overlay-editor-BEfwI1IT.js} +1 -1
- package/dist/assets/outline-panel-CdsnAy2w.js +1 -0
- package/dist/assets/{packages-panel-CJL0MVlj.js → packages-panel-DiTA-d_D.js} +1 -1
- package/dist/assets/{pieDiagram-ADFJNKIX-Dxt5PVNo.js → pieDiagram-ADFJNKIX-DQDNQ-de.js} +1 -1
- package/dist/assets/{quadrantDiagram-LMRXKWRM-D4pUaA31.js → quadrantDiagram-LMRXKWRM-0kgIXc2-.js} +1 -1
- package/dist/assets/{react-plotly-cJZ0VWBq.js → react-plotly-DJqqfM7c.js} +1 -1
- package/dist/assets/{requirementDiagram-4UW4RH46-DVRTjgas.js → requirementDiagram-4UW4RH46-B5rb0ypd.js} +1 -1
- package/dist/assets/{run-page-BUEnMC9w.js → run-page-CFmLrv1R.js} +1 -1
- package/dist/assets/{sankeyDiagram-GR3RE2ED-CVFnD9C-.js → sankeyDiagram-GR3RE2ED-Dom7IlnF.js} +1 -1
- package/dist/assets/{scratchpad-panel-BIgRENkI.js → scratchpad-panel-CuHWpHO8.js} +1 -1
- package/dist/assets/{secrets-panel-xY5-V_BD.js → secrets-panel-CfHc5YD0.js} +1 -1
- package/dist/assets/{sequenceDiagram-C3RYC4MD-_lY4ZN_S.js → sequenceDiagram-C3RYC4MD-PNJWXQbw.js} +1 -1
- package/dist/assets/{slides-component-DMjQomc3.css → slides-component-C-LoGC1U.css} +1 -1
- package/dist/assets/{slides-component-Xjymwj7X.js → slides-component-CJgaTRZ0.js} +1 -1
- package/dist/assets/snippets-panel-B2EC1txM.js +1 -0
- package/dist/assets/sortBy-DZnlX29-.js +1 -0
- package/dist/assets/{state-C4NiC9tO.js → state-CWict9RU.js} +1 -1
- package/dist/assets/{stateDiagram-KXAO66HF-Da0JQWCn.js → stateDiagram-KXAO66HF-BE58aJnr.js} +1 -1
- package/dist/assets/stateDiagram-v2-UMBNRL4Z-CdThjimL.js +1 -0
- package/dist/assets/storage-DRaR04wR.js +26 -0
- package/dist/assets/{terminal-BPwTkXae.js → terminal-BX3Su5q7.js} +1 -1
- package/dist/assets/{time-Dv5_Ouz_.js → time-hUzZfpNE.js} +1 -1
- package/dist/assets/{timeline-definition-XQNQX7LJ-Dxh5Zu2e.js → timeline-definition-XQNQX7LJ-CqQP9t51.js} +1 -1
- package/dist/assets/tracing-B10Q1n-L.js +2 -0
- package/dist/assets/{tracing-panel-DAzrzNmm.js → tracing-panel-Du8WCnno.js} +2 -2
- package/dist/assets/{trash-Dc6DSjz_.js → trash-B81GTiv6.js} +1 -1
- package/dist/assets/{tree-jheoerAX.js → tree-6vW2ogkh.js} +1 -1
- package/dist/assets/{treemap-75Q7IDZK-IgpxeGaf.js → treemap-75Q7IDZK-CdwDwwsz.js} +27 -27
- package/dist/assets/variable-panel-D5qgJI7k.js +1 -0
- package/dist/assets/{vega-component-BpfpiPKI.js → vega-component-DJaJWMJM.js} +1 -1
- package/dist/assets/worker-fHbtoWvT.js +1 -0
- package/dist/assets/{xychartDiagram-6GGTOJPD-CmNigJ31.js → xychartDiagram-6GGTOJPD-WFtXqaM9.js} +1 -1
- package/dist/index.html +2 -2
- package/package.json +3 -2
- package/src/components/app-config/user-config-form.tsx +46 -1
- package/src/components/chat/acp/__tests__/__snapshots__/prompt.test.ts.snap +62 -43
- package/src/components/chat/acp/__tests__/atoms.test.ts +1 -1
- package/src/components/chat/acp/__tests__/state.test.ts +36 -36
- package/src/components/chat/acp/agent-panel.tsx +24 -27
- package/src/components/chat/acp/blocks.tsx +6 -6
- package/src/components/chat/acp/prompt.ts +62 -43
- package/src/components/chat/chat-panel.tsx +5 -1
- package/src/components/chat/markdown-renderer.tsx +6 -10
- package/src/components/chat/tool-call-accordion.tsx +52 -20
- package/src/components/data-table/SearchBar.tsx +8 -7
- package/src/components/data-table/__tests__/column_formatting.test.ts +50 -35
- package/src/components/data-table/__tests__/data-table.test.tsx +39 -1
- package/src/components/data-table/cell-hover-template/feature.ts +14 -0
- package/src/components/data-table/cell-hover-template/types.ts +11 -0
- package/src/components/data-table/charts/components/form-fields.tsx +41 -37
- package/src/components/data-table/charts/forms/common-chart.tsx +2 -2
- package/src/components/data-table/column-explorer-panel/column-explorer.tsx +5 -2
- package/src/components/data-table/column-formatting/feature.ts +62 -29
- package/src/components/data-table/column-formatting/types.ts +1 -0
- package/src/components/data-table/column-header.tsx +3 -1
- package/src/components/data-table/column-summary/chart-spec-model.tsx +24 -7
- package/src/components/data-table/column-summary/column-summary.tsx +18 -9
- package/src/components/data-table/columns.tsx +42 -18
- package/src/components/data-table/data-table.tsx +10 -2
- package/src/components/data-table/date-popover.tsx +85 -75
- package/src/components/data-table/filter-pills.tsx +14 -9
- package/src/components/data-table/header-items.tsx +5 -1
- package/src/components/data-table/pagination.tsx +20 -13
- package/src/components/data-table/renderers.tsx +28 -0
- package/src/components/data-table/row-viewer-panel/row-viewer.tsx +10 -8
- package/src/components/datasources/column-preview.tsx +6 -2
- package/src/components/datasources/datasources.tsx +8 -12
- package/src/components/editor/ai/transport/chat-transport.tsx +4 -1
- package/src/components/editor/cell/CellStatus.tsx +23 -20
- package/src/components/editor/cell/CreateCellButton.tsx +3 -4
- package/src/components/editor/cell/code/language-toggle.tsx +3 -4
- package/src/components/editor/chrome/wrapper/footer-items/machine-stats.tsx +39 -28
- package/src/components/editor/controls/notebook-menu-dropdown.tsx +4 -2
- package/src/components/editor/file-tree/requesting-tree.tsx +14 -8
- package/src/components/editor/renderers/CellArray.tsx +3 -4
- package/src/components/editor/renderers/slides-layout/slides-layout.tsx +3 -3
- package/src/components/editor/renderers/slides-layout/types.ts +1 -0
- package/src/components/pages/home-page.tsx +4 -1
- package/src/components/slides/slides-component.tsx +1 -1
- package/src/components/slides/slides.css +6 -0
- package/src/components/terminal/theme.tsx +1 -0
- package/src/components/tracing/tracing-spec.ts +5 -4
- package/src/components/ui/range-slider.tsx +4 -2
- package/src/components/ui/slider.tsx +3 -1
- package/src/components/variables/variables-table.tsx +3 -0
- package/src/core/MarimoApp.tsx +9 -6
- package/src/core/ai/context/__tests__/registry.test.ts +6 -4
- package/src/core/ai/context/providers/cell-output.ts +3 -2
- package/src/core/ai/context/providers/error.ts +3 -1
- package/src/core/ai/context/providers/file.ts +7 -2
- package/src/core/ai/context/providers/tables.ts +3 -2
- package/src/core/ai/context/providers/variable.ts +6 -4
- package/src/core/ai/staged-cells.ts +34 -1
- package/src/core/cells/__tests__/add-missing-import.test.ts +67 -22
- package/src/core/cells/add-missing-import.ts +24 -7
- package/src/core/cells/cells.ts +26 -27
- package/src/core/cells/logs.ts +1 -1
- package/src/core/codemirror/find-replace/search-highlight.ts +3 -1
- package/src/core/codemirror/language/LanguageAdapters.ts +9 -3
- package/src/core/codemirror/lsp/notebook-lsp.ts +8 -2
- package/src/core/codemirror/readonly/__tests__/extension.test.ts +1 -1
- package/src/core/codemirror/rtc/loro/awareness.ts +52 -17
- package/src/core/codemirror/rtc/loro/sync.ts +12 -4
- package/src/core/config/config-schema.ts +1 -0
- package/src/core/config/config.ts +4 -0
- package/src/core/hotkeys/hotkeys.ts +8 -4
- package/src/core/i18n/__tests__/locale-provider.test.tsx +176 -0
- package/src/core/i18n/locale-provider.tsx +35 -0
- package/src/core/i18n/with-locale.tsx +12 -0
- package/src/core/islands/components/web-components.tsx +13 -10
- package/src/core/kernel/RuntimeState.ts +4 -1
- package/src/core/kernel/messages.ts +2 -2
- package/src/core/network/DeferredRequestRegistry.ts +16 -4
- package/src/core/runtime/runtime.ts +5 -4
- package/src/core/wasm/bridge.ts +5 -1
- package/src/core/wasm/store.ts +4 -1
- package/src/core/wasm/worker/message-buffer.ts +3 -2
- package/src/core/websocket/types.ts +22 -16
- package/src/hooks/useFormatting.ts +97 -0
- package/src/hooks/useTimer.ts +8 -5
- package/src/plugins/core/registerReactComponent.tsx +16 -10
- package/src/plugins/impl/DataTablePlugin.tsx +4 -0
- package/src/plugins/impl/RangeSliderPlugin.tsx +5 -3
- package/src/plugins/impl/SliderPlugin.tsx +3 -1
- package/src/plugins/impl/anywidget/model.ts +16 -5
- package/src/plugins/impl/data-editor/types.ts +7 -5
- package/src/plugins/impl/data-explorer/components/column-summary.tsx +20 -13
- package/src/plugins/impl/panel/utils.ts +6 -4
- package/src/plugins/layout/OutlinePlugin.tsx +69 -0
- package/src/plugins/layout/StatPlugin.tsx +4 -1
- package/src/plugins/plugins.ts +2 -0
- package/src/utils/__tests__/dates.test.ts +45 -24
- package/src/utils/__tests__/numbers.test.ts +42 -30
- package/src/utils/__tests__/once.test.ts +187 -0
- package/src/utils/dates.ts +15 -10
- package/src/utils/edit-distance.ts +8 -6
- package/src/utils/errors.ts +1 -1
- package/src/utils/id-tree.tsx +21 -10
- package/src/utils/localStorage.ts +13 -4
- package/src/utils/numbers.ts +11 -11
- package/src/utils/once.ts +32 -0
- package/src/utils/paths.ts +4 -1
- package/src/utils/pluralize.ts +12 -5
- package/src/utils/python-poet/poet.ts +30 -15
- package/src/utils/time.ts +5 -1
- package/dist/assets/ConnectedDataExplorerComponent-BErMbWvG.js +0 -19
- package/dist/assets/_baseEach-CNBxBxvS.js +0 -1
- package/dist/assets/_baseMap-D1WHjKrd.js +0 -1
- package/dist/assets/_baseUniq-CCgDNtZb.js +0 -1
- package/dist/assets/channel-_2eNSz0n.js +0 -1
- package/dist/assets/chat-panel-CXh5Wl6C.js +0 -3
- package/dist/assets/classDiagram-KNZD7YFC-BGmh9POF.js +0 -1
- package/dist/assets/classDiagram-v2-RKCZMP56-BGmh9POF.js +0 -1
- package/dist/assets/clone-BFDSPAj3.js +0 -1
- package/dist/assets/datasources-panel-B7FbYLiy.js +0 -1
- package/dist/assets/edit-page-BrYda9VE.js +0 -129
- package/dist/assets/file-explorer-panel-Bw59Kva1.js +0 -1
- package/dist/assets/home-page-Fb2osjys.js +0 -9
- package/dist/assets/index-Cx0bsY1w.css +0 -1
- package/dist/assets/index-DKEudB02.js +0 -578
- package/dist/assets/infoDiagram-STP46IZ2-CVyrdLc8.js +0 -2
- package/dist/assets/links-D59GIweI.js +0 -7
- package/dist/assets/min-DUMu_zeK.js +0 -1
- package/dist/assets/outline-panel-DIzkvm2I.js +0 -1
- package/dist/assets/snippets-panel-CTPYW41n.js +0 -1
- package/dist/assets/sortBy-BNZKwiq_.js +0 -1
- package/dist/assets/stateDiagram-v2-UMBNRL4Z-D5lYZOOt.js +0 -1
- package/dist/assets/storage-CMdLzB_c.js +0 -26
- package/dist/assets/tracing-BCIurUfa.js +0 -2
- package/dist/assets/variable-panel-DYAiLBmF.js +0 -1
- package/dist/assets/worker-X5rxzQGQ.js +0 -1
|
@@ -19,11 +19,13 @@ import {
|
|
|
19
19
|
useReactTable,
|
|
20
20
|
} from "@tanstack/react-table";
|
|
21
21
|
import React, { memo } from "react";
|
|
22
|
+
import { useLocale } from "react-aria";
|
|
22
23
|
|
|
23
24
|
import { Table } from "@/components/ui/table";
|
|
24
25
|
import type { GetRowIds } from "@/plugins/impl/DataTablePlugin";
|
|
25
26
|
import { cn } from "@/utils/cn";
|
|
26
27
|
import type { PanelType } from "../editor/chrome/panels/context-aware-panel/context-aware-panel";
|
|
28
|
+
import { CellHoverTemplateFeature } from "./cell-hover-template/feature";
|
|
27
29
|
import { CellSelectionFeature } from "./cell-selection/feature";
|
|
28
30
|
import type { CellSelectionState } from "./cell-selection/types";
|
|
29
31
|
import { CellStylingFeature } from "./cell-styling/feature";
|
|
@@ -63,6 +65,7 @@ interface DataTableProps<TData> extends Partial<DownloadActionProps> {
|
|
|
63
65
|
rowSelection?: RowSelectionState;
|
|
64
66
|
cellSelection?: CellSelectionState;
|
|
65
67
|
cellStyling?: CellStyleState | null;
|
|
68
|
+
hoverTemplate?: string | null;
|
|
66
69
|
onRowSelectionChange?: OnChangeFn<RowSelectionState>;
|
|
67
70
|
onCellSelectionChange?: OnChangeFn<CellSelectionState>;
|
|
68
71
|
getRowIds?: GetRowIds;
|
|
@@ -103,6 +106,7 @@ const DataTableInternal = <TData,>({
|
|
|
103
106
|
rowSelection,
|
|
104
107
|
cellSelection,
|
|
105
108
|
cellStyling,
|
|
109
|
+
hoverTemplate,
|
|
106
110
|
paginationState,
|
|
107
111
|
setPaginationState,
|
|
108
112
|
downloadAs,
|
|
@@ -131,6 +135,7 @@ const DataTableInternal = <TData,>({
|
|
|
131
135
|
}: DataTableProps<TData>) => {
|
|
132
136
|
const [isSearchEnabled, setIsSearchEnabled] = React.useState<boolean>(false);
|
|
133
137
|
const [showLoadingBar, setShowLoadingBar] = React.useState<boolean>(false);
|
|
138
|
+
const { locale } = useLocale();
|
|
134
139
|
|
|
135
140
|
const { columnPinning, setColumnPinning } = useColumnPinning(
|
|
136
141
|
freezeColumnsLeft,
|
|
@@ -176,6 +181,7 @@ const DataTableInternal = <TData,>({
|
|
|
176
181
|
ColumnFormattingFeature,
|
|
177
182
|
CellSelectionFeature,
|
|
178
183
|
CellStylingFeature,
|
|
184
|
+
CellHoverTemplateFeature,
|
|
179
185
|
CopyColumnFeature,
|
|
180
186
|
FocusRowFeature,
|
|
181
187
|
],
|
|
@@ -199,6 +205,7 @@ const DataTableInternal = <TData,>({
|
|
|
199
205
|
},
|
|
200
206
|
}
|
|
201
207
|
: {}),
|
|
208
|
+
locale: locale,
|
|
202
209
|
manualPagination: manualPagination,
|
|
203
210
|
getPaginationRowModel: getPaginationRowModel(),
|
|
204
211
|
// sorting
|
|
@@ -233,10 +240,11 @@ const DataTableInternal = <TData,>({
|
|
|
233
240
|
? {}
|
|
234
241
|
: // No pagination, show all rows
|
|
235
242
|
{ pagination: { pageIndex: 0, pageSize: data.length } }),
|
|
236
|
-
rowSelection,
|
|
237
|
-
cellSelection,
|
|
243
|
+
rowSelection: rowSelection ?? {},
|
|
244
|
+
cellSelection: cellSelection ?? [],
|
|
238
245
|
cellStyling,
|
|
239
246
|
columnPinning: columnPinning,
|
|
247
|
+
cellHoverTemplate: hoverTemplate,
|
|
240
248
|
},
|
|
241
249
|
});
|
|
242
250
|
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
/* Copyright 2024 Marimo. All rights reserved. */
|
|
2
2
|
import React from "react";
|
|
3
|
+
import { useDateFormatter, useLocale } from "react-aria";
|
|
3
4
|
import { Tooltip } from "@/components/ui/tooltip";
|
|
4
5
|
|
|
5
6
|
interface DatePopoverProps {
|
|
@@ -19,33 +20,17 @@ export const DatePopover: React.FC<DatePopoverProps> = ({
|
|
|
19
20
|
}
|
|
20
21
|
|
|
21
22
|
const dateObj = new Date(date);
|
|
22
|
-
const relativeTime = getRelativeTime(dateObj);
|
|
23
23
|
|
|
24
24
|
const content = (
|
|
25
25
|
<div className="min-w-[240px] p-1 text-sm">
|
|
26
|
-
<div className="text-muted-foreground mb-2">
|
|
26
|
+
<div className="text-muted-foreground mb-2">
|
|
27
|
+
<RelativeTime date={dateObj} />
|
|
28
|
+
</div>
|
|
27
29
|
<div className="space-y-1">
|
|
28
30
|
{type === "datetime" ? (
|
|
29
|
-
|
|
30
|
-
([timezone, formattedDate]) => (
|
|
31
|
-
<div
|
|
32
|
-
key={timezone}
|
|
33
|
-
className="grid grid-cols-[fit-content(40px)_1fr] gap-4 items-center justify-items-end"
|
|
34
|
-
>
|
|
35
|
-
<span className="bg-muted rounded-md py-1 px-2 w-fit ml-auto">
|
|
36
|
-
{timezone}
|
|
37
|
-
</span>
|
|
38
|
-
<span>{formattedDate}</span>
|
|
39
|
-
</div>
|
|
40
|
-
),
|
|
41
|
-
)
|
|
31
|
+
<TimezoneDisplay date={dateObj} />
|
|
42
32
|
) : (
|
|
43
|
-
<
|
|
44
|
-
{dateObj.toLocaleDateString("en-US", {
|
|
45
|
-
timeZone: "UTC",
|
|
46
|
-
dateStyle: "long",
|
|
47
|
-
})}
|
|
48
|
-
</span>
|
|
33
|
+
<DateDisplay date={dateObj} />
|
|
49
34
|
)}
|
|
50
35
|
</div>
|
|
51
36
|
</div>
|
|
@@ -58,57 +43,79 @@ export const DatePopover: React.FC<DatePopoverProps> = ({
|
|
|
58
43
|
);
|
|
59
44
|
};
|
|
60
45
|
|
|
61
|
-
|
|
62
|
-
const
|
|
63
|
-
|
|
46
|
+
const TimezoneDisplay = ({ date }: { date: Date }) => {
|
|
47
|
+
const { locale } = useLocale();
|
|
48
|
+
const localTimezone = Intl.DateTimeFormat(locale).resolvedOptions().timeZone;
|
|
64
49
|
const hasSubSeconds = date.getUTCMilliseconds() !== 0;
|
|
65
|
-
if (hasSubSeconds) {
|
|
66
|
-
return {
|
|
67
|
-
UTC: new Intl.DateTimeFormat("en-US", {
|
|
68
|
-
timeZone: "UTC",
|
|
69
|
-
year: "numeric",
|
|
70
|
-
month: "2-digit",
|
|
71
|
-
day: "2-digit",
|
|
72
|
-
hour: "2-digit",
|
|
73
|
-
minute: "2-digit",
|
|
74
|
-
second: "2-digit",
|
|
75
|
-
fractionalSecondDigits: 3,
|
|
76
|
-
}).format(date),
|
|
77
|
-
[localTimezone]: new Intl.DateTimeFormat("en-US", {
|
|
78
|
-
timeZone: localTimezone,
|
|
79
|
-
year: "numeric",
|
|
80
|
-
month: "2-digit",
|
|
81
|
-
day: "2-digit",
|
|
82
|
-
hour: "2-digit",
|
|
83
|
-
minute: "2-digit",
|
|
84
|
-
second: "2-digit",
|
|
85
|
-
fractionalSecondDigits: 3,
|
|
86
|
-
}).format(date),
|
|
87
|
-
};
|
|
88
|
-
}
|
|
89
50
|
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
51
|
+
const utcFormatter = useDateFormatter(
|
|
52
|
+
hasSubSeconds
|
|
53
|
+
? {
|
|
54
|
+
timeZone: "UTC",
|
|
55
|
+
year: "numeric",
|
|
56
|
+
month: "2-digit",
|
|
57
|
+
day: "2-digit",
|
|
58
|
+
hour: "2-digit",
|
|
59
|
+
minute: "2-digit",
|
|
60
|
+
second: "2-digit",
|
|
61
|
+
fractionalSecondDigits: 3,
|
|
62
|
+
}
|
|
63
|
+
: {
|
|
64
|
+
timeZone: "UTC",
|
|
65
|
+
dateStyle: "long",
|
|
66
|
+
timeStyle: "medium",
|
|
67
|
+
},
|
|
68
|
+
);
|
|
69
|
+
|
|
70
|
+
const localFormatter = useDateFormatter(
|
|
71
|
+
hasSubSeconds
|
|
72
|
+
? {
|
|
73
|
+
timeZone: localTimezone,
|
|
74
|
+
year: "numeric",
|
|
75
|
+
month: "2-digit",
|
|
76
|
+
day: "2-digit",
|
|
77
|
+
hour: "2-digit",
|
|
78
|
+
minute: "2-digit",
|
|
79
|
+
second: "2-digit",
|
|
80
|
+
fractionalSecondDigits: 3,
|
|
81
|
+
}
|
|
82
|
+
: {
|
|
83
|
+
timeZone: localTimezone,
|
|
84
|
+
dateStyle: "long",
|
|
85
|
+
timeStyle: "medium",
|
|
86
|
+
},
|
|
87
|
+
);
|
|
88
|
+
|
|
89
|
+
return (
|
|
90
|
+
<>
|
|
91
|
+
<div className="grid grid-cols-[fit-content(40px)_1fr] gap-4 items-center justify-items-end">
|
|
92
|
+
<span className="bg-muted rounded-md py-1 px-2 w-fit ml-auto">UTC</span>
|
|
93
|
+
<span>{utcFormatter.format(date)}</span>
|
|
94
|
+
</div>
|
|
95
|
+
<div className="grid grid-cols-[fit-content(40px)_1fr] gap-4 items-center justify-items-end">
|
|
96
|
+
<span className="bg-muted rounded-md py-1 px-2 w-fit ml-auto">
|
|
97
|
+
{localTimezone}
|
|
98
|
+
</span>
|
|
99
|
+
<span>{localFormatter.format(date)}</span>
|
|
100
|
+
</div>
|
|
101
|
+
</>
|
|
102
|
+
);
|
|
103
|
+
};
|
|
104
|
+
|
|
105
|
+
const DateDisplay = ({ date }: { date: Date }) => {
|
|
106
|
+
const dateFormatter = useDateFormatter({
|
|
107
|
+
timeZone: "UTC",
|
|
108
|
+
dateStyle: "long",
|
|
109
|
+
});
|
|
103
110
|
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
//
|
|
111
|
-
const relativeTimeFormatter = new Intl.RelativeTimeFormat(
|
|
111
|
+
return <span>{dateFormatter.format(date)}</span>;
|
|
112
|
+
};
|
|
113
|
+
|
|
114
|
+
const RelativeTime = ({ date }: { date: Date }) => {
|
|
115
|
+
const { locale } = useLocale();
|
|
116
|
+
|
|
117
|
+
// Initialize relative time formatter with current locale and "auto" numeric style
|
|
118
|
+
const relativeTimeFormatter = new Intl.RelativeTimeFormat(locale, {
|
|
112
119
|
numeric: "auto",
|
|
113
120
|
});
|
|
114
121
|
|
|
@@ -117,7 +124,6 @@ function getRelativeTime(date: Date): string {
|
|
|
117
124
|
const differenceInSeconds = (currentTime.getTime() - date.getTime()) / 1000;
|
|
118
125
|
|
|
119
126
|
// Define time units with their thresholds and conversion factors
|
|
120
|
-
// Format: [threshold before next unit, seconds in this unit, unit name]
|
|
121
127
|
const timeUnits: Array<[number, number, string]> = [
|
|
122
128
|
[60, 1, "second"], // Less than 60 seconds
|
|
123
129
|
[60, 60, "minute"], // Less than 60 minutes
|
|
@@ -134,13 +140,17 @@ function getRelativeTime(date: Date): string {
|
|
|
134
140
|
// Convert to fixed decimal and negate since RelativeTimeFormat expects
|
|
135
141
|
// negative values for past times and positive for future times
|
|
136
142
|
const roundedValue = -Number(valueInUnits.toFixed(1));
|
|
137
|
-
return
|
|
138
|
-
|
|
139
|
-
|
|
143
|
+
return (
|
|
144
|
+
<span>
|
|
145
|
+
{relativeTimeFormatter.format(
|
|
146
|
+
roundedValue,
|
|
147
|
+
unitName as Intl.RelativeTimeFormatUnit,
|
|
148
|
+
)}
|
|
149
|
+
</span>
|
|
140
150
|
);
|
|
141
151
|
}
|
|
142
152
|
}
|
|
143
153
|
|
|
144
154
|
// Should never reach here due to Infinity threshold, but provide fallback
|
|
145
|
-
return relativeTimeFormatter.format(0, "second")
|
|
146
|
-
}
|
|
155
|
+
return <span>{relativeTimeFormatter.format(0, "second")}</span>;
|
|
156
|
+
};
|
|
@@ -7,6 +7,7 @@ import type {
|
|
|
7
7
|
Table,
|
|
8
8
|
} from "@tanstack/react-table";
|
|
9
9
|
import { XIcon } from "lucide-react";
|
|
10
|
+
import { type DateFormatter, useDateFormatter } from "react-aria";
|
|
10
11
|
import { logNever } from "@/utils/assertNever";
|
|
11
12
|
import { Badge } from "../ui/badge";
|
|
12
13
|
import type { ColumnFilterValue } from "./filters";
|
|
@@ -18,12 +19,21 @@ interface Props<TData> {
|
|
|
18
19
|
}
|
|
19
20
|
|
|
20
21
|
export const FilterPills = <TData,>({ filters, table }: Props<TData>) => {
|
|
22
|
+
const timeFormatter = useDateFormatter({
|
|
23
|
+
hour: "2-digit",
|
|
24
|
+
minute: "2-digit",
|
|
25
|
+
second: "2-digit",
|
|
26
|
+
});
|
|
27
|
+
|
|
21
28
|
if (!filters || filters.length === 0) {
|
|
22
29
|
return null;
|
|
23
30
|
}
|
|
24
31
|
|
|
25
32
|
function renderFilterPill(filter: ColumnFilter) {
|
|
26
|
-
const formattedValue = formatValue(
|
|
33
|
+
const formattedValue = formatValue(
|
|
34
|
+
filter.value as ColumnFilterValue,
|
|
35
|
+
timeFormatter,
|
|
36
|
+
);
|
|
27
37
|
if (!formattedValue) {
|
|
28
38
|
return null;
|
|
29
39
|
}
|
|
@@ -52,7 +62,7 @@ export const FilterPills = <TData,>({ filters, table }: Props<TData>) => {
|
|
|
52
62
|
);
|
|
53
63
|
};
|
|
54
64
|
|
|
55
|
-
function formatValue(value: ColumnFilterValue) {
|
|
65
|
+
function formatValue(value: ColumnFilterValue, timeFormatter: DateFormatter) {
|
|
56
66
|
if (!("type" in value)) {
|
|
57
67
|
return;
|
|
58
68
|
}
|
|
@@ -71,14 +81,9 @@ function formatValue(value: ColumnFilterValue) {
|
|
|
71
81
|
return formatMinMax(value.min?.toISOString(), value.max?.toISOString());
|
|
72
82
|
}
|
|
73
83
|
if (value.type === "time") {
|
|
74
|
-
const formatTime = new Intl.DateTimeFormat("en-US", {
|
|
75
|
-
hour: "2-digit",
|
|
76
|
-
minute: "2-digit",
|
|
77
|
-
second: "2-digit",
|
|
78
|
-
});
|
|
79
84
|
return formatMinMax(
|
|
80
|
-
value.min ?
|
|
81
|
-
value.max ?
|
|
85
|
+
value.min ? timeFormatter.format(value.min) : undefined,
|
|
86
|
+
value.max ? timeFormatter.format(value.max) : undefined,
|
|
82
87
|
);
|
|
83
88
|
}
|
|
84
89
|
if (value.type === "datetime") {
|
|
@@ -34,6 +34,7 @@ import { NAMELESS_COLUMN_PREFIX } from "./columns";
|
|
|
34
34
|
|
|
35
35
|
export function renderFormatOptions<TData, TValue>(
|
|
36
36
|
column: Column<TData, TValue>,
|
|
37
|
+
locale: string,
|
|
37
38
|
) {
|
|
38
39
|
const dataType: DataType | undefined = column.columnDef.meta?.dataType;
|
|
39
40
|
const columnFormatOptions = dataType ? formatOptions[dataType] : [];
|
|
@@ -51,6 +52,9 @@ export function renderFormatOptions<TData, TValue>(
|
|
|
51
52
|
</DropdownMenuSubTrigger>
|
|
52
53
|
<DropdownMenuPortal>
|
|
53
54
|
<DropdownMenuSubContent>
|
|
55
|
+
<div className="text-xs text-muted-foreground px-2 py-1">
|
|
56
|
+
Locale: {locale}
|
|
57
|
+
</div>
|
|
54
58
|
{Boolean(currentFormat) && (
|
|
55
59
|
<>
|
|
56
60
|
<DropdownMenuItem
|
|
@@ -72,7 +76,7 @@ export function renderFormatOptions<TData, TValue>(
|
|
|
72
76
|
{option}
|
|
73
77
|
</span>
|
|
74
78
|
<span className="ml-auto pl-5 text-xs text-muted-foreground">
|
|
75
|
-
{formattingExample(option)}
|
|
79
|
+
{formattingExample(option, locale)}
|
|
76
80
|
</span>
|
|
77
81
|
</DropdownMenuItem>
|
|
78
82
|
))}
|
|
@@ -9,8 +9,10 @@ import {
|
|
|
9
9
|
ChevronsLeft,
|
|
10
10
|
ChevronsRight,
|
|
11
11
|
} from "lucide-react";
|
|
12
|
+
import { useLocale } from "react-aria";
|
|
12
13
|
import { Button } from "@/components/ui/button";
|
|
13
14
|
import { Events } from "@/utils/events";
|
|
15
|
+
import { prettyNumber } from "@/utils/numbers";
|
|
14
16
|
import { PluralWord } from "@/utils/pluralize";
|
|
15
17
|
import {
|
|
16
18
|
Select,
|
|
@@ -40,6 +42,8 @@ export const DataTablePagination = <TData,>({
|
|
|
40
42
|
tableLoading,
|
|
41
43
|
showPageSizeSelector,
|
|
42
44
|
}: DataTablePaginationProps<TData>) => {
|
|
45
|
+
const { locale } = useLocale();
|
|
46
|
+
|
|
43
47
|
const renderTotal = () => {
|
|
44
48
|
const { rowSelection, cellSelection } = table.getState();
|
|
45
49
|
let selected = Object.keys(rowSelection).length;
|
|
@@ -58,7 +62,7 @@ export const DataTablePagination = <TData,>({
|
|
|
58
62
|
if (isAllPageSelected && !isAllSelected) {
|
|
59
63
|
return (
|
|
60
64
|
<>
|
|
61
|
-
<span>{prettyNumber(selected)} selected</span>
|
|
65
|
+
<span>{prettyNumber(selected, locale)} selected</span>
|
|
62
66
|
<Button
|
|
63
67
|
size="xs"
|
|
64
68
|
data-testid="select-all-button"
|
|
@@ -73,7 +77,7 @@ export const DataTablePagination = <TData,>({
|
|
|
73
77
|
}
|
|
74
78
|
}}
|
|
75
79
|
>
|
|
76
|
-
Select all {prettyNumber(numRows)}
|
|
80
|
+
Select all {prettyNumber(numRows, locale)}
|
|
77
81
|
</Button>
|
|
78
82
|
</>
|
|
79
83
|
);
|
|
@@ -82,7 +86,7 @@ export const DataTablePagination = <TData,>({
|
|
|
82
86
|
if (selected) {
|
|
83
87
|
return (
|
|
84
88
|
<>
|
|
85
|
-
<span>{prettyNumber(selected)} selected</span>
|
|
89
|
+
<span>{prettyNumber(selected, locale)} selected</span>
|
|
86
90
|
<Button
|
|
87
91
|
size="xs"
|
|
88
92
|
data-testid="clear-selection-button"
|
|
@@ -107,7 +111,11 @@ export const DataTablePagination = <TData,>({
|
|
|
107
111
|
);
|
|
108
112
|
}
|
|
109
113
|
|
|
110
|
-
const rowColumnCount = prettifyRowColumnCount(
|
|
114
|
+
const rowColumnCount = prettifyRowColumnCount(
|
|
115
|
+
numRows,
|
|
116
|
+
totalColumns,
|
|
117
|
+
locale,
|
|
118
|
+
);
|
|
111
119
|
return <span>{rowColumnCount}</span>;
|
|
112
120
|
};
|
|
113
121
|
const currentPage = Math.min(
|
|
@@ -199,7 +207,9 @@ export const DataTablePagination = <TData,>({
|
|
|
199
207
|
handlePageChange(() => table.setPageIndex(page))
|
|
200
208
|
}
|
|
201
209
|
/>
|
|
202
|
-
<span className="shrink-0">
|
|
210
|
+
<span className="shrink-0">
|
|
211
|
+
of {prettyNumber(totalPages, locale)}
|
|
212
|
+
</span>
|
|
203
213
|
</div>
|
|
204
214
|
<Button
|
|
205
215
|
size="xs"
|
|
@@ -232,10 +242,6 @@ export const DataTablePagination = <TData,>({
|
|
|
232
242
|
);
|
|
233
243
|
};
|
|
234
244
|
|
|
235
|
-
function prettyNumber(value: number): string {
|
|
236
|
-
return new Intl.NumberFormat().format(value);
|
|
237
|
-
}
|
|
238
|
-
|
|
239
245
|
export const PageSelector = ({
|
|
240
246
|
currentPage,
|
|
241
247
|
totalPages,
|
|
@@ -313,17 +319,18 @@ export const PageSelector = ({
|
|
|
313
319
|
);
|
|
314
320
|
};
|
|
315
321
|
|
|
316
|
-
export function prettifyRowCount(rowCount: number): string {
|
|
317
|
-
return `${prettyNumber(rowCount)} ${new PluralWord("row").pluralize(rowCount)}`;
|
|
322
|
+
export function prettifyRowCount(rowCount: number, locale: string): string {
|
|
323
|
+
return `${prettyNumber(rowCount, locale)} ${new PluralWord("row").pluralize(rowCount)}`;
|
|
318
324
|
}
|
|
319
325
|
|
|
320
326
|
export const prettifyRowColumnCount = (
|
|
321
327
|
numRows: number | "too_many",
|
|
322
328
|
totalColumns: number,
|
|
329
|
+
locale: string,
|
|
323
330
|
): string => {
|
|
324
331
|
const rowsLabel =
|
|
325
|
-
numRows === "too_many" ? "Unknown" : prettifyRowCount(numRows);
|
|
326
|
-
const columnsLabel = `${prettyNumber(totalColumns)} ${new PluralWord("column").pluralize(totalColumns)}`;
|
|
332
|
+
numRows === "too_many" ? "Unknown" : prettifyRowCount(numRows, locale);
|
|
333
|
+
const columnsLabel = `${prettyNumber(totalColumns, locale)} ${new PluralWord("column").pluralize(totalColumns)}`;
|
|
327
334
|
|
|
328
335
|
return [rowsLabel, columnsLabel].join(", ");
|
|
329
336
|
};
|
|
@@ -93,6 +93,25 @@ export const DataTableBody = <TData,>({
|
|
|
93
93
|
handleCellsKeyDown,
|
|
94
94
|
} = useCellRangeSelection({ table });
|
|
95
95
|
|
|
96
|
+
function applyHoverTemplate(
|
|
97
|
+
template: string,
|
|
98
|
+
cells: Array<Cell<TData, unknown>>,
|
|
99
|
+
): string {
|
|
100
|
+
const variableRegex = /{{(\w+)}}/g;
|
|
101
|
+
// Map column id -> stringified value
|
|
102
|
+
const idToValue = new Map<string, string>();
|
|
103
|
+
for (const c of cells) {
|
|
104
|
+
const v = c.getValue();
|
|
105
|
+
// Prefer empty string for nulls to keep tooltip clean
|
|
106
|
+
const s = renderUnknownValue({ value: v, nullAsEmptyString: true });
|
|
107
|
+
idToValue.set(c.column.id, s);
|
|
108
|
+
}
|
|
109
|
+
return template.replace(variableRegex, (_substr, varName: string) => {
|
|
110
|
+
const val = idToValue.get(varName);
|
|
111
|
+
return val !== undefined ? val : `{{${varName}}}`;
|
|
112
|
+
});
|
|
113
|
+
}
|
|
114
|
+
|
|
96
115
|
const renderCells = (cells: Array<Cell<TData, unknown>>) => {
|
|
97
116
|
return cells.map((cell) => {
|
|
98
117
|
const { className, style: pinningstyle } = getPinningStyles(cell.column);
|
|
@@ -101,6 +120,7 @@ export const DataTableBody = <TData,>({
|
|
|
101
120
|
cell.getUserStyling?.() || {},
|
|
102
121
|
pinningstyle,
|
|
103
122
|
);
|
|
123
|
+
|
|
104
124
|
return (
|
|
105
125
|
<TableCell
|
|
106
126
|
tabIndex={0}
|
|
@@ -145,10 +165,18 @@ export const DataTableBody = <TData,>({
|
|
|
145
165
|
const isRowViewedInPanel =
|
|
146
166
|
rowViewerPanelOpen && viewedRowIdx === rowIndex;
|
|
147
167
|
|
|
168
|
+
// Compute hover title once per row using this row's cells (visible or hidden)
|
|
169
|
+
const hoverTemplate = table.getState().cellHoverTemplate || null;
|
|
170
|
+
const rowCells = row.getAllCells();
|
|
171
|
+
const rowTitle = hoverTemplate
|
|
172
|
+
? applyHoverTemplate(hoverTemplate, rowCells)
|
|
173
|
+
: undefined;
|
|
174
|
+
|
|
148
175
|
return (
|
|
149
176
|
<TableRow
|
|
150
177
|
key={row.id}
|
|
151
178
|
data-state={row.getIsSelected() && "selected"}
|
|
179
|
+
title={rowTitle}
|
|
152
180
|
// These classes ensure that empty rows (nulls) still render
|
|
153
181
|
className={cn(
|
|
154
182
|
"border-t h-6",
|
|
@@ -15,6 +15,7 @@ import {
|
|
|
15
15
|
SearchIcon,
|
|
16
16
|
} from "lucide-react";
|
|
17
17
|
import { useRef, useState } from "react";
|
|
18
|
+
import { useLocale } from "react-aria";
|
|
18
19
|
import { ColumnName } from "@/components/datasources/components";
|
|
19
20
|
import { CopyClipboardIcon } from "@/components/icons/copy-icon";
|
|
20
21
|
import { KeyboardHotkeys } from "@/components/shortcuts/renderShortcut";
|
|
@@ -66,6 +67,7 @@ export const RowViewerPanel: React.FC<RowViewerPanelProps> = ({
|
|
|
66
67
|
const [searchQuery, setSearchQuery] = useState("");
|
|
67
68
|
const panelRef = useRef<HTMLDivElement>(null);
|
|
68
69
|
const searchInputRef = useRef<HTMLInputElement>(null);
|
|
70
|
+
const { locale } = useLocale();
|
|
69
71
|
|
|
70
72
|
const tooManyRows = totalRows === TOO_MANY_ROWS;
|
|
71
73
|
|
|
@@ -204,13 +206,13 @@ export const RowViewerPanel: React.FC<RowViewerPanelProps> = ({
|
|
|
204
206
|
applyColumnFormatting: (value) => value,
|
|
205
207
|
} as Column<unknown>;
|
|
206
208
|
|
|
207
|
-
const cellContent = renderCellValue(
|
|
208
|
-
mockColumn,
|
|
209
|
-
() => columnValue,
|
|
210
|
-
() => columnValue,
|
|
211
|
-
undefined,
|
|
212
|
-
"text-left break-word",
|
|
213
|
-
);
|
|
209
|
+
const cellContent = renderCellValue({
|
|
210
|
+
column: mockColumn,
|
|
211
|
+
renderValue: () => columnValue,
|
|
212
|
+
getValue: () => columnValue,
|
|
213
|
+
selectCell: undefined,
|
|
214
|
+
cellStyles: "text-left break-word",
|
|
215
|
+
});
|
|
214
216
|
|
|
215
217
|
const copyValue =
|
|
216
218
|
typeof columnValue === "object"
|
|
@@ -286,7 +288,7 @@ export const RowViewerPanel: React.FC<RowViewerPanelProps> = ({
|
|
|
286
288
|
<span className="text-xs">
|
|
287
289
|
{tooManyRows
|
|
288
290
|
? `Row ${rowIdx + 1}`
|
|
289
|
-
: `Row ${rowIdx + 1} of ${prettifyRowCount(totalRows)}`}
|
|
291
|
+
: `Row ${rowIdx + 1} of ${prettifyRowCount(totalRows, locale)}`}
|
|
290
292
|
</span>
|
|
291
293
|
<Button
|
|
292
294
|
variant="outline"
|
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
import { useAtomValue } from "jotai";
|
|
4
4
|
import { PlusSquareIcon } from "lucide-react";
|
|
5
5
|
import React, { Suspense } from "react";
|
|
6
|
+
import { useLocale } from "react-aria";
|
|
6
7
|
import { maybeAddAltairImport } from "@/core/cells/add-missing-import";
|
|
7
8
|
import { useCellActions } from "@/core/cells/cells";
|
|
8
9
|
import { useLastFocusedCellId } from "@/core/cells/focus";
|
|
@@ -42,6 +43,7 @@ export const DatasetColumnPreview: React.FC<{
|
|
|
42
43
|
}> = ({ table, column, preview, onAddColumnChart, sqlTableContext }) => {
|
|
43
44
|
const { theme } = useTheme();
|
|
44
45
|
const { previewDatasetColumn } = useRequestClient();
|
|
46
|
+
const { locale } = useLocale();
|
|
45
47
|
|
|
46
48
|
const previewColumn = () => {
|
|
47
49
|
previewDatasetColumn({
|
|
@@ -107,7 +109,8 @@ export const DatasetColumnPreview: React.FC<{
|
|
|
107
109
|
refetchPreview: previewColumn,
|
|
108
110
|
});
|
|
109
111
|
|
|
110
|
-
const stats =
|
|
112
|
+
const stats =
|
|
113
|
+
preview.stats && renderStats(preview.stats, column.type, locale);
|
|
111
114
|
|
|
112
115
|
const chart = preview.chart_spec && renderChart(preview.chart_spec, theme);
|
|
113
116
|
|
|
@@ -175,6 +178,7 @@ export function renderPreviewError({
|
|
|
175
178
|
export function renderStats(
|
|
176
179
|
stats: Partial<Record<ColumnHeaderStatsKey, unknown>>,
|
|
177
180
|
dataType: DataType,
|
|
181
|
+
locale: string,
|
|
178
182
|
) {
|
|
179
183
|
return (
|
|
180
184
|
<div className="gap-x-16 gap-y-1 grid grid-cols-2-fit border rounded p-2 empty:hidden">
|
|
@@ -189,7 +193,7 @@ export function renderStats(
|
|
|
189
193
|
{convertStatsName(key as ColumnHeaderStatsKey, dataType)}
|
|
190
194
|
</span>
|
|
191
195
|
<span className="text-xs font-bold text-muted-foreground tracking-wide">
|
|
192
|
-
{prettyNumber(value)}
|
|
196
|
+
{prettyNumber(value, locale)}
|
|
193
197
|
</span>
|
|
194
198
|
<CopyClipboardIcon
|
|
195
199
|
className="h-3 w-3 invisible group-hover:visible"
|
|
@@ -304,10 +304,12 @@ const DatabaseItem: React.FC<{
|
|
|
304
304
|
}> = ({ hasSearch, engineName, database, children }) => {
|
|
305
305
|
const [isExpanded, setIsExpanded] = React.useState(false);
|
|
306
306
|
const [isSelected, setIsSelected] = React.useState(false);
|
|
307
|
+
const [prevHasSearch, setPrevHasSearch] = React.useState(hasSearch);
|
|
307
308
|
|
|
308
|
-
|
|
309
|
+
if (prevHasSearch !== hasSearch) {
|
|
310
|
+
setPrevHasSearch(hasSearch);
|
|
309
311
|
setIsExpanded(hasSearch);
|
|
310
|
-
}
|
|
312
|
+
}
|
|
311
313
|
|
|
312
314
|
return (
|
|
313
315
|
<>
|
|
@@ -399,14 +401,10 @@ const SchemaItem: React.FC<{
|
|
|
399
401
|
children: React.ReactNode;
|
|
400
402
|
hasSearch: boolean;
|
|
401
403
|
}> = ({ databaseName, schema, children, hasSearch }) => {
|
|
402
|
-
const [isExpanded, setIsExpanded] = React.useState(
|
|
404
|
+
const [isExpanded, setIsExpanded] = React.useState(hasSearch);
|
|
403
405
|
const [isSelected, setIsSelected] = React.useState(false);
|
|
404
406
|
const uniqueValue = `${databaseName}:${schema.name}`;
|
|
405
407
|
|
|
406
|
-
React.useEffect(() => {
|
|
407
|
-
setIsExpanded(hasSearch);
|
|
408
|
-
}, [hasSearch]);
|
|
409
|
-
|
|
410
408
|
if (isSchemaless(schema.name)) {
|
|
411
409
|
return children;
|
|
412
410
|
}
|
|
@@ -693,11 +691,9 @@ const DatasetColumnItem: React.FC<{
|
|
|
693
691
|
const closeAllColumns = useAtomValue(closeAllColumnsAtom);
|
|
694
692
|
const setExpandedColumns = useSetAtom(expandedColumnsAtom);
|
|
695
693
|
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
}
|
|
700
|
-
}, [closeAllColumns]);
|
|
694
|
+
if (closeAllColumns && isExpanded) {
|
|
695
|
+
setIsExpanded(false);
|
|
696
|
+
}
|
|
701
697
|
|
|
702
698
|
if (isExpanded) {
|
|
703
699
|
setExpandedColumns(
|
|
@@ -13,11 +13,14 @@ import {
|
|
|
13
13
|
export class StreamingChunkTransport<
|
|
14
14
|
UI_MESSAGE extends UIMessage,
|
|
15
15
|
> extends DefaultChatTransport<UI_MESSAGE> {
|
|
16
|
+
private onChunkReceived: (chunk: UIMessageChunk) => void;
|
|
17
|
+
|
|
16
18
|
constructor(
|
|
17
19
|
options: HttpChatTransportInitOptions<UI_MESSAGE> = {},
|
|
18
|
-
|
|
20
|
+
onChunkReceived: (chunk: UIMessageChunk) => void,
|
|
19
21
|
) {
|
|
20
22
|
super(options);
|
|
23
|
+
this.onChunkReceived = onChunkReceived;
|
|
21
24
|
}
|
|
22
25
|
|
|
23
26
|
protected override processResponseStream(
|