@datarecce/ui 0.1.40 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +28 -133
- package/dist/AuthModal-C8LetZNB.js +23 -0
- package/dist/AuthModal-C8LetZNB.js.map +1 -0
- package/dist/LineageCanvas-CR38SDYr.d.ts +41 -0
- package/dist/LineageCanvas-CR38SDYr.d.ts.map +1 -0
- package/dist/ResultErrorFallback-C7c-TN1p.js +3 -0
- package/dist/ResultErrorFallback-C7c-TN1p.js.map +1 -0
- package/dist/RouteConfigContext-z8YNimdP.d.ts +172 -0
- package/dist/RouteConfigContext-z8YNimdP.d.ts.map +1 -0
- package/dist/RunProgress-DyFIALbI.d.ts +429 -0
- package/dist/RunProgress-DyFIALbI.d.ts.map +1 -0
- package/dist/ScreenshotDataGrid-BfxYUThx.d.ts +64 -0
- package/dist/ScreenshotDataGrid-BfxYUThx.d.ts.map +1 -0
- package/dist/SplitPane-B-BLxZaQ.d.ts +1427 -0
- package/dist/SplitPane-B-BLxZaQ.d.ts.map +1 -0
- package/dist/advanced.d.ts +18 -0
- package/dist/advanced.d.ts.map +1 -0
- package/dist/advanced.js +3 -0
- package/dist/advanced.js.map +1 -0
- package/dist/api-ZZ4cc9b9.d.ts +255 -0
- package/dist/api-ZZ4cc9b9.d.ts.map +1 -0
- package/dist/api-_i6BZPkM.js +3 -0
- package/dist/api-_i6BZPkM.js.map +1 -0
- package/dist/api.d.ts +3 -2
- package/dist/api.js +2 -100
- package/dist/colors--47Kkns4.js +3 -0
- package/dist/colors--47Kkns4.js.map +1 -0
- package/dist/colors-vY9Yzui0.d.ts +255 -0
- package/dist/colors-vY9Yzui0.d.ts.map +1 -0
- package/dist/components-run.d.ts +8 -0
- package/dist/components-run.js +2 -0
- package/dist/components.d.ts +22 -2
- package/dist/components.js +2 -86
- package/dist/const-DbXBkrxT.js +3 -0
- package/dist/const-DbXBkrxT.js.map +1 -0
- package/dist/constants-DD5vJv2q.js +3 -0
- package/dist/constants-DD5vJv2q.js.map +1 -0
- package/dist/constants.d.ts +3 -0
- package/dist/constants.js +2 -0
- package/dist/contexts.d.ts +7 -0
- package/dist/contexts.js +2 -0
- package/dist/flag-CiR2E5oz.d.ts +898 -0
- package/dist/flag-CiR2E5oz.d.ts.map +1 -0
- package/dist/flag-koeDAqr3.js +3 -0
- package/dist/flag-koeDAqr3.js.map +1 -0
- package/dist/hooks.d.ts +15 -2
- package/dist/hooks.js +2 -43
- package/dist/index-BFkbe0aF.d.ts +698 -0
- package/dist/index-BFkbe0aF.d.ts.map +1 -0
- package/dist/index-Ba3hp2Ng.d.ts +471 -0
- package/dist/index-Ba3hp2Ng.d.ts.map +1 -0
- package/dist/index-C_kD4ZQ3.d.ts +1079 -0
- package/dist/index-C_kD4ZQ3.d.ts.map +1 -0
- package/dist/index-CiPcALu4.d.ts +146 -0
- package/dist/index-CiPcALu4.d.ts.map +1 -0
- package/dist/index-CkXLPYZY.d.ts +13 -0
- package/dist/index-CkXLPYZY.d.ts.map +1 -0
- package/dist/index-DTCpHvX_.d.ts +211 -0
- package/dist/index-DTCpHvX_.d.ts.map +1 -0
- package/dist/index-DVoQsx5c.d.ts +349 -0
- package/dist/index-DVoQsx5c.d.ts.map +1 -0
- package/dist/index-DmwYRgDR.d.ts +192 -0
- package/dist/index-DmwYRgDR.d.ts.map +1 -0
- package/dist/index-N8N7XmRj.d.ts +130 -0
- package/dist/index-N8N7XmRj.d.ts.map +1 -0
- package/dist/index-h_fw6R9U.d.ts +1501 -0
- package/dist/index-h_fw6R9U.d.ts.map +1 -0
- package/dist/index-o48TPoFN.d.ts +734 -0
- package/dist/index-o48TPoFN.d.ts.map +1 -0
- package/dist/index.d.ts +24 -2
- package/dist/index.js +2 -198
- package/dist/keepAlive-CEzyrDfg.js +3 -0
- package/dist/keepAlive-CEzyrDfg.js.map +1 -0
- package/dist/lib/api/axiosClient.d.ts +8 -0
- package/dist/lib/api/axiosClient.d.ts.map +1 -0
- package/dist/lib/api/axiosClient.js +3 -0
- package/dist/lib/api/axiosClient.js.map +1 -0
- package/dist/lib/api/track.d.ts +137 -0
- package/dist/lib/api/track.d.ts.map +1 -0
- package/dist/lib/api/track.js +2 -0
- package/dist/lib/api/user.d.ts +16 -0
- package/dist/lib/api/user.d.ts.map +1 -0
- package/dist/lib/api/user.js +2 -0
- package/dist/lib/const.d.ts +8 -0
- package/dist/lib/const.d.ts.map +1 -0
- package/dist/lib/const.js +2 -0
- package/dist/lib/result/ResultErrorFallback.d.ts +8 -0
- package/dist/lib/result/ResultErrorFallback.d.ts.map +1 -0
- package/dist/lib/result/ResultErrorFallback.js +2 -0
- package/dist/primitives-CgGUvwHB.d.ts +914 -0
- package/dist/primitives-CgGUvwHB.d.ts.map +1 -0
- package/dist/primitives.d.ts +12 -0
- package/dist/primitives.js +2 -0
- package/dist/result.d.ts +4 -0
- package/dist/result.js +2 -0
- package/dist/src-BgHSbbHk.js +67 -0
- package/dist/src-BgHSbbHk.js.map +1 -0
- package/dist/styles.css +478 -4
- package/dist/theme-CeWzymUn.js +64 -0
- package/dist/theme-CeWzymUn.js.map +1 -0
- package/dist/theme.d.ts +3 -2
- package/dist/theme.js +2 -9
- package/dist/track-9ZQpBlUK.js +3 -0
- package/dist/track-9ZQpBlUK.js.map +1 -0
- package/dist/types-CFbNxrx2.d.ts +171 -0
- package/dist/types-CFbNxrx2.d.ts.map +1 -0
- package/dist/types-CZre3j02.d.ts +231 -0
- package/dist/types-CZre3j02.d.ts.map +1 -0
- package/dist/types.d.ts +14 -2
- package/dist/types.js +3 -9
- package/dist/types.js.map +1 -0
- package/dist/useRecceServerFlag-Bg5R67J4.js +3 -0
- package/dist/useRecceServerFlag-Bg5R67J4.js.map +1 -0
- package/dist/useThemeColors--prVbMmM.js +3 -0
- package/dist/useThemeColors--prVbMmM.js.map +1 -0
- package/dist/useThemeColors-DHEroo8f.d.ts +104 -0
- package/dist/useThemeColors-DHEroo8f.d.ts.map +1 -0
- package/dist/user-DMT7E0fc.js +3 -0
- package/dist/user-DMT7E0fc.js.map +1 -0
- package/dist/utils-CW2skXm_.js +3 -0
- package/dist/utils-CW2skXm_.js.map +1 -0
- package/dist/utils-CXWhfyxC.js +5 -0
- package/dist/utils-CXWhfyxC.js.map +1 -0
- package/dist/utils.d.ts +7 -0
- package/dist/utils.js +2 -0
- package/package.json +115 -107
- package/LICENSE +0 -201
- package/dist/RecceCheckContext-BJprb2xR.js +0 -7968
- package/dist/RecceCheckContext-BJprb2xR.js.map +0 -1
- package/dist/RecceCheckContext-DPnWB_aU.css +0 -215
- package/dist/RecceCheckContext-DPnWB_aU.css.map +0 -1
- package/dist/RecceCheckContext-DbZ7BdRy.mjs +0 -7426
- package/dist/RecceCheckContext-DbZ7BdRy.mjs.map +0 -1
- package/dist/RecceCheckContext-DyxOeUsX.css +0 -215
- package/dist/RecceCheckContext-DyxOeUsX.css.map +0 -1
- package/dist/api.d.mts +0 -3
- package/dist/api.js.map +0 -1
- package/dist/api.mjs +0 -46
- package/dist/api.mjs.map +0 -1
- package/dist/components-B6oaPB5f.mjs +0 -11769
- package/dist/components-B6oaPB5f.mjs.map +0 -1
- package/dist/components-BeAjVBV3.css +0 -70
- package/dist/components-BeAjVBV3.css.map +0 -1
- package/dist/components-DTLQ2djq.js +0 -14110
- package/dist/components-DTLQ2djq.js.map +0 -1
- package/dist/components-iUxcqtUB.css +0 -70
- package/dist/components-iUxcqtUB.css.map +0 -1
- package/dist/components.d.mts +0 -3
- package/dist/components.mjs +0 -9
- package/dist/const-CaIm1Z8g.mjs +0 -12
- package/dist/const-CaIm1Z8g.mjs.map +0 -1
- package/dist/const-CvdZO0FN.js +0 -24
- package/dist/const-CvdZO0FN.js.map +0 -1
- package/dist/hooks-cQsBXBd1.js +0 -40
- package/dist/hooks-cQsBXBd1.js.map +0 -1
- package/dist/hooks-eaHm_yEp.mjs +0 -33
- package/dist/hooks-eaHm_yEp.mjs.map +0 -1
- package/dist/hooks.d.mts +0 -3
- package/dist/hooks.mjs +0 -8
- package/dist/html2canvas-pro.esm-CsuSOHXp.js +0 -7250
- package/dist/html2canvas-pro.esm-CsuSOHXp.js.map +0 -1
- package/dist/html2canvas-pro.esm-E7kpobrC.mjs +0 -7249
- package/dist/html2canvas-pro.esm-E7kpobrC.mjs.map +0 -1
- package/dist/index-B9lSPJTi.d.ts +0 -2170
- package/dist/index-B9lSPJTi.d.ts.map +0 -1
- package/dist/index-CbF0x3kW.d.mts +0 -2172
- package/dist/index-CbF0x3kW.d.mts.map +0 -1
- package/dist/index.d.mts +0 -3
- package/dist/index.js.map +0 -1
- package/dist/index.mjs +0 -20
- package/dist/index.mjs.map +0 -1
- package/dist/mui-theme-CUhybmBq.mjs +0 -696
- package/dist/mui-theme-CUhybmBq.mjs.map +0 -1
- package/dist/mui-theme-iBHkjXJq.js +0 -732
- package/dist/mui-theme-iBHkjXJq.js.map +0 -1
- package/dist/state-CTITyT0R.js +0 -795
- package/dist/state-CTITyT0R.js.map +0 -1
- package/dist/state-Sc2b4jri.mjs +0 -382
- package/dist/state-Sc2b4jri.mjs.map +0 -1
- package/dist/theme.d.mts +0 -3
- package/dist/theme.mjs +0 -4
- package/dist/tooltipMessage-BC5W7H3X.js +0 -13
- package/dist/tooltipMessage-BC5W7H3X.js.map +0 -1
- package/dist/tooltipMessage-B_xMIKWL.mjs +0 -7
- package/dist/tooltipMessage-B_xMIKWL.mjs.map +0 -1
- package/dist/types.d.mts +0 -3
- package/dist/types.mjs +0 -6
- package/dist/urls-BQW5wjg-.js +0 -13
- package/dist/urls-BQW5wjg-.js.map +0 -1
- package/dist/urls-DT7FVEcS.mjs +0 -7
- package/dist/urls-DT7FVEcS.mjs.map +0 -1
- package/dist/version-B9s8yne-.js +0 -300
- package/dist/version-B9s8yne-.js.map +0 -1
- package/dist/version-DP1kU_7v.mjs +0 -162
- package/dist/version-DP1kU_7v.mjs.map +0 -1
- package/recce-source/.editorconfig +0 -26
- package/recce-source/.flake8 +0 -37
- package/recce-source/.github/ISSUE_TEMPLATE/bug_report.yml +0 -67
- package/recce-source/.github/ISSUE_TEMPLATE/custom.md +0 -10
- package/recce-source/.github/ISSUE_TEMPLATE/feature_request.yml +0 -42
- package/recce-source/.github/PULL_REQUEST_TEMPLATE.md +0 -21
- package/recce-source/.github/copilot-instructions.md +0 -331
- package/recce-source/.github/instructions/backend-instructions.md +0 -541
- package/recce-source/.github/instructions/frontend-instructions.md +0 -317
- package/recce-source/.github/workflows/build-statics.yaml +0 -72
- package/recce-source/.github/workflows/bump.yaml +0 -48
- package/recce-source/.github/workflows/integration-tests-cloud.yaml +0 -92
- package/recce-source/.github/workflows/integration-tests-sqlmesh.yaml +0 -33
- package/recce-source/.github/workflows/integration-tests.yaml +0 -52
- package/recce-source/.github/workflows/nightly.yaml +0 -246
- package/recce-source/.github/workflows/release.yaml +0 -196
- package/recce-source/.github/workflows/tests-js.yaml +0 -58
- package/recce-source/.github/workflows/tests-python.yaml +0 -128
- package/recce-source/.pre-commit-config.yaml +0 -26
- package/recce-source/CLAUDE.md +0 -483
- package/recce-source/CODE_OF_CONDUCT.md +0 -128
- package/recce-source/CONTRIBUTING.md +0 -107
- package/recce-source/LICENSE +0 -201
- package/recce-source/Makefile +0 -126
- package/recce-source/README.md +0 -182
- package/recce-source/RECCE_CLOUD.md +0 -81
- package/recce-source/SECURITY.md +0 -25
- package/recce-source/docs/PACKAGING.md +0 -340
- package/recce-source/docs/README.md +0 -1
- package/recce-source/integration_tests/dbt/dbt_project.yml +0 -26
- package/recce-source/integration_tests/dbt/models/customers.sql +0 -69
- package/recce-source/integration_tests/dbt/models/docs.md +0 -14
- package/recce-source/integration_tests/dbt/models/orders.sql +0 -56
- package/recce-source/integration_tests/dbt/models/schema.yml +0 -82
- package/recce-source/integration_tests/dbt/models/staging/schema.yml +0 -31
- package/recce-source/integration_tests/dbt/models/staging/stg_customers.sql +0 -22
- package/recce-source/integration_tests/dbt/models/staging/stg_orders.sql +0 -23
- package/recce-source/integration_tests/dbt/models/staging/stg_payments.sql +0 -25
- package/recce-source/integration_tests/dbt/packages.yml +0 -7
- package/recce-source/integration_tests/dbt/profiles.yml +0 -8
- package/recce-source/integration_tests/dbt/seeds/raw_customers.csv +0 -101
- package/recce-source/integration_tests/dbt/seeds/raw_orders.csv +0 -100
- package/recce-source/integration_tests/dbt/seeds/raw_payments.csv +0 -114
- package/recce-source/integration_tests/dbt/seeds/raw_statuses.csv +0 -5
- package/recce-source/integration_tests/dbt/smoke_test.sh +0 -72
- package/recce-source/integration_tests/dbt/smoke_test_cloud.sh +0 -71
- package/recce-source/integration_tests/sqlmesh/__init__.py +0 -0
- package/recce-source/integration_tests/sqlmesh/audits/assert_item_price_above_zero.sql +0 -9
- package/recce-source/integration_tests/sqlmesh/audits/items.sql +0 -7
- package/recce-source/integration_tests/sqlmesh/audits/order_items.sql +0 -7
- package/recce-source/integration_tests/sqlmesh/config.py +0 -171
- package/recce-source/integration_tests/sqlmesh/helper.py +0 -20
- package/recce-source/integration_tests/sqlmesh/hooks/__init__.py +0 -0
- package/recce-source/integration_tests/sqlmesh/macros/__init__.py +0 -0
- package/recce-source/integration_tests/sqlmesh/macros/macros.py +0 -8
- package/recce-source/integration_tests/sqlmesh/macros/macros.sql +0 -8
- package/recce-source/integration_tests/sqlmesh/macros/utils.py +0 -11
- package/recce-source/integration_tests/sqlmesh/metrics/metrics.sql +0 -25
- package/recce-source/integration_tests/sqlmesh/models/customer_revenue_by_day.sql +0 -41
- package/recce-source/integration_tests/sqlmesh/models/customer_revenue_lifetime.sql +0 -60
- package/recce-source/integration_tests/sqlmesh/models/customers.sql +0 -32
- package/recce-source/integration_tests/sqlmesh/models/items.py +0 -95
- package/recce-source/integration_tests/sqlmesh/models/marketing.sql +0 -15
- package/recce-source/integration_tests/sqlmesh/models/order_items.py +0 -95
- package/recce-source/integration_tests/sqlmesh/models/orders.py +0 -70
- package/recce-source/integration_tests/sqlmesh/models/raw_marketing.py +0 -62
- package/recce-source/integration_tests/sqlmesh/models/top_waiters.sql +0 -23
- package/recce-source/integration_tests/sqlmesh/models/waiter_as_customer_by_day.sql +0 -29
- package/recce-source/integration_tests/sqlmesh/models/waiter_names.sql +0 -10
- package/recce-source/integration_tests/sqlmesh/models/waiter_revenue_by_day.sql +0 -29
- package/recce-source/integration_tests/sqlmesh/models/waiters.py +0 -62
- package/recce-source/integration_tests/sqlmesh/prep_env.sh +0 -16
- package/recce-source/integration_tests/sqlmesh/schema.yaml +0 -5
- package/recce-source/integration_tests/sqlmesh/seeds/waiter_names.csv +0 -11
- package/recce-source/integration_tests/sqlmesh/test_server.sh +0 -29
- package/recce-source/integration_tests/sqlmesh/tests/test_customer_revenue_by_day.yaml +0 -63
- package/recce-source/integration_tests/sqlmesh/tests/test_order_items.yaml +0 -72
- package/recce-source/js/.editorconfig +0 -27
- package/recce-source/js/.env.development +0 -5
- package/recce-source/js/.husky/pre-commit +0 -29
- package/recce-source/js/.nvmrc +0 -1
- package/recce-source/js/README.md +0 -39
- package/recce-source/js/app/(mainComponents)/DisplayModeToggle.tsx +0 -65
- package/recce-source/js/app/(mainComponents)/NavBar.tsx +0 -228
- package/recce-source/js/app/(mainComponents)/RecceVersionBadge.tsx +0 -107
- package/recce-source/js/app/(mainComponents)/TopBar.tsx +0 -252
- package/recce-source/js/app/@lineage/default.tsx +0 -20
- package/recce-source/js/app/@lineage/page.tsx +0 -14
- package/recce-source/js/app/MainLayout.tsx +0 -170
- package/recce-source/js/app/Providers.tsx +0 -49
- package/recce-source/js/app/checks/page.tsx +0 -296
- package/recce-source/js/app/error.tsx +0 -93
- package/recce-source/js/app/favicon.ico +0 -0
- package/recce-source/js/app/global-error.tsx +0 -115
- package/recce-source/js/app/global.css +0 -82
- package/recce-source/js/app/layout.tsx +0 -48
- package/recce-source/js/app/lineage/page.tsx +0 -15
- package/recce-source/js/app/page.tsx +0 -12
- package/recce-source/js/app/query/page.tsx +0 -8
- package/recce-source/js/biome.json +0 -313
- package/recce-source/js/jest.config.js +0 -34
- package/recce-source/js/jest.globals.d.ts +0 -32
- package/recce-source/js/jest.setup.js +0 -91
- package/recce-source/js/next.config.js +0 -16
- package/recce-source/js/package-lock.json +0 -13843
- package/recce-source/js/package.json +0 -123
- package/recce-source/js/pnpm-lock.yaml +0 -9235
- package/recce-source/js/pnpm-workspace.yaml +0 -6
- package/recce-source/js/postcss.config.js +0 -5
- package/recce-source/js/public/auth_callback.html +0 -68
- package/recce-source/js/public/imgs/feedback/thumbs-down.png +0 -0
- package/recce-source/js/public/imgs/feedback/thumbs-up.png +0 -0
- package/recce-source/js/public/imgs/reload-image.svg +0 -4
- package/recce-source/js/public/logo/recce-logo-white.png +0 -0
- package/recce-source/js/src/components/AuthModal/AuthModal.tsx +0 -202
- package/recce-source/js/src/components/app/AvatarDropdown.tsx +0 -159
- package/recce-source/js/src/components/app/EnvInfo.tsx +0 -357
- package/recce-source/js/src/components/app/Filename.tsx +0 -388
- package/recce-source/js/src/components/app/SetupConnectionPopover.tsx +0 -91
- package/recce-source/js/src/components/app/StateExporter.tsx +0 -57
- package/recce-source/js/src/components/app/StateImporter.tsx +0 -198
- package/recce-source/js/src/components/app/StateSharing.tsx +0 -145
- package/recce-source/js/src/components/app/StateSynchronizer.tsx +0 -205
- package/recce-source/js/src/components/charts/HistogramChart.tsx +0 -291
- package/recce-source/js/src/components/charts/SquareIcon.tsx +0 -51
- package/recce-source/js/src/components/charts/TopKSummaryList.tsx +0 -457
- package/recce-source/js/src/components/charts/chartTheme.ts +0 -74
- package/recce-source/js/src/components/check/CheckBreadcrumb.tsx +0 -97
- package/recce-source/js/src/components/check/CheckDescription.tsx +0 -134
- package/recce-source/js/src/components/check/CheckDetail.tsx +0 -797
- package/recce-source/js/src/components/check/CheckEmptyState.tsx +0 -84
- package/recce-source/js/src/components/check/CheckList.tsx +0 -320
- package/recce-source/js/src/components/check/LineageDiffView.tsx +0 -32
- package/recce-source/js/src/components/check/PresetCheckTemplateView.tsx +0 -48
- package/recce-source/js/src/components/check/SchemaDiffView.tsx +0 -290
- package/recce-source/js/src/components/check/check.ts +0 -25
- package/recce-source/js/src/components/check/timeline/CheckTimeline.tsx +0 -163
- package/recce-source/js/src/components/check/timeline/CommentInput.tsx +0 -84
- package/recce-source/js/src/components/check/timeline/TimelineEvent.tsx +0 -468
- package/recce-source/js/src/components/check/timeline/index.ts +0 -12
- package/recce-source/js/src/components/check/utils.ts +0 -12
- package/recce-source/js/src/components/data-grid/ScreenshotDataGrid.tsx +0 -333
- package/recce-source/js/src/components/data-grid/agGridStyles.css +0 -55
- package/recce-source/js/src/components/data-grid/agGridTheme.ts +0 -43
- package/recce-source/js/src/components/editor/CodeEditor.tsx +0 -107
- package/recce-source/js/src/components/editor/DiffEditor.tsx +0 -162
- package/recce-source/js/src/components/editor/index.ts +0 -12
- package/recce-source/js/src/components/errorboundary/ErrorBoundary.tsx +0 -87
- package/recce-source/js/src/components/histogram/HistogramDiffForm.tsx +0 -147
- package/recce-source/js/src/components/histogram/HistogramDiffResultView.tsx +0 -63
- package/recce-source/js/src/components/icons/index.tsx +0 -142
- package/recce-source/js/src/components/lineage/ActionControl.tsx +0 -63
- package/recce-source/js/src/components/lineage/ActionTag.tsx +0 -141
- package/recce-source/js/src/components/lineage/ChangeStatusLegend.tsx +0 -46
- package/recce-source/js/src/components/lineage/ColumnLevelLineageControl.tsx +0 -327
- package/recce-source/js/src/components/lineage/ColumnLevelLineageLegend.tsx +0 -57
- package/recce-source/js/src/components/lineage/GraphColumnNode.tsx +0 -199
- package/recce-source/js/src/components/lineage/GraphEdge.tsx +0 -59
- package/recce-source/js/src/components/lineage/GraphNode.tsx +0 -555
- package/recce-source/js/src/components/lineage/LineagePage.tsx +0 -10
- package/recce-source/js/src/components/lineage/LineageView.tsx +0 -1384
- package/recce-source/js/src/components/lineage/LineageViewContext.tsx +0 -86
- package/recce-source/js/src/components/lineage/LineageViewContextMenu.tsx +0 -637
- package/recce-source/js/src/components/lineage/LineageViewNotification.tsx +0 -64
- package/recce-source/js/src/components/lineage/LineageViewTopBar.tsx +0 -596
- package/recce-source/js/src/components/lineage/NodeSqlView.tsx +0 -136
- package/recce-source/js/src/components/lineage/NodeTag.tsx +0 -278
- package/recce-source/js/src/components/lineage/NodeView.tsx +0 -642
- package/recce-source/js/src/components/lineage/SandboxView.tsx +0 -436
- package/recce-source/js/src/components/lineage/ServerDisconnectedModalContent.tsx +0 -105
- package/recce-source/js/src/components/lineage/SetupConnectionBanner.tsx +0 -52
- package/recce-source/js/src/components/lineage/SingleEnvironmentQueryView.tsx +0 -152
- package/recce-source/js/src/components/lineage/graph.test.ts +0 -31
- package/recce-source/js/src/components/lineage/graph.ts +0 -58
- package/recce-source/js/src/components/lineage/lineage.test.ts +0 -169
- package/recce-source/js/src/components/lineage/lineage.ts +0 -521
- package/recce-source/js/src/components/lineage/styles.css +0 -42
- package/recce-source/js/src/components/lineage/styles.tsx +0 -165
- package/recce-source/js/src/components/lineage/useMultiNodesAction.ts +0 -352
- package/recce-source/js/src/components/lineage/useValueDiffAlertDialog.tsx +0 -108
- package/recce-source/js/src/components/onboarding-guide/Notification.tsx +0 -62
- package/recce-source/js/src/components/profile/ProfileDiffForm.tsx +0 -134
- package/recce-source/js/src/components/profile/ProfileDiffResultView.tsx +0 -243
- package/recce-source/js/src/components/query/ChangedOnlyCheckbox.tsx +0 -29
- package/recce-source/js/src/components/query/DiffText.tsx +0 -120
- package/recce-source/js/src/components/query/QueryDiffResultView.tsx +0 -468
- package/recce-source/js/src/components/query/QueryForm.tsx +0 -80
- package/recce-source/js/src/components/query/QueryPage.tsx +0 -282
- package/recce-source/js/src/components/query/QueryResultView.tsx +0 -180
- package/recce-source/js/src/components/query/SetupConnectionGuide.tsx +0 -57
- package/recce-source/js/src/components/query/SqlEditor.tsx +0 -245
- package/recce-source/js/src/components/query/ToggleSwitch.tsx +0 -84
- package/recce-source/js/src/components/query/styles.css +0 -21
- package/recce-source/js/src/components/routing/DirectUrlAccess.test.tsx +0 -428
- package/recce-source/js/src/components/routing/LineageStatePreservation.test.tsx +0 -311
- package/recce-source/js/src/components/routing/Navigation.test.tsx +0 -256
- package/recce-source/js/src/components/rowcount/RowCountDiffResultView.tsx +0 -108
- package/recce-source/js/src/components/rowcount/delta.test.ts +0 -51
- package/recce-source/js/src/components/rowcount/delta.ts +0 -16
- package/recce-source/js/src/components/run/RunList.tsx +0 -303
- package/recce-source/js/src/components/run/RunModal.tsx +0 -191
- package/recce-source/js/src/components/run/RunPage.tsx +0 -26
- package/recce-source/js/src/components/run/RunResultPane.tsx +0 -454
- package/recce-source/js/src/components/run/RunStatusAndDate.tsx +0 -106
- package/recce-source/js/src/components/run/RunToolbar.tsx +0 -70
- package/recce-source/js/src/components/run/RunView.tsx +0 -196
- package/recce-source/js/src/components/run/registry.ts +0 -214
- package/recce-source/js/src/components/run/types.ts +0 -14
- package/recce-source/js/src/components/schema/ColumnNameCell.test.tsx +0 -169
- package/recce-source/js/src/components/schema/ColumnNameCell.tsx +0 -198
- package/recce-source/js/src/components/schema/SchemaView.tsx +0 -336
- package/recce-source/js/src/components/schema/schemaDiff.ts +0 -32
- package/recce-source/js/src/components/schema/style.css +0 -134
- package/recce-source/js/src/components/screenshot/ScreenshotBox.tsx +0 -39
- package/recce-source/js/src/components/shared/HistoryToggle.tsx +0 -35
- package/recce-source/js/src/components/split/Split.tsx +0 -40
- package/recce-source/js/src/components/split/styles.css +0 -24
- package/recce-source/js/src/components/summary/ChangeSummary.tsx +0 -264
- package/recce-source/js/src/components/summary/SchemaSummary.tsx +0 -123
- package/recce-source/js/src/components/summary/SummaryView.tsx +0 -29
- package/recce-source/js/src/components/timeout/IdleTimeoutBadge.tsx +0 -48
- package/recce-source/js/src/components/top-k/TopKDiffForm.tsx +0 -58
- package/recce-source/js/src/components/top-k/TopKDiffResultView.tsx +0 -73
- package/recce-source/js/src/components/ui/dataGrid/DataFrameColumnGroupHeader.tsx +0 -228
- package/recce-source/js/src/components/ui/dataGrid/DataFrameColumnHeader.tsx +0 -113
- package/recce-source/js/src/components/ui/dataGrid/defaultRenderCell.tsx +0 -72
- package/recce-source/js/src/components/ui/dataGrid/index.ts +0 -23
- package/recce-source/js/src/components/ui/dataGrid/inlineRenderCell.test.tsx +0 -607
- package/recce-source/js/src/components/ui/dataGrid/inlineRenderCell.tsx +0 -211
- package/recce-source/js/src/components/ui/dataGrid/schemaCells.test.tsx +0 -452
- package/recce-source/js/src/components/ui/dataGrid/schemaCells.tsx +0 -142
- package/recce-source/js/src/components/ui/dataGrid/valueDiffCells.test.tsx +0 -178
- package/recce-source/js/src/components/ui/dataGrid/valueDiffCells.tsx +0 -275
- package/recce-source/js/src/components/ui/markdown/ExternalLinkConfirmDialog.tsx +0 -134
- package/recce-source/js/src/components/ui/markdown/MarkdownContent.tsx +0 -364
- package/recce-source/js/src/components/ui/mui/index.ts +0 -13
- package/recce-source/js/src/components/ui/mui-provider.tsx +0 -67
- package/recce-source/js/src/components/ui/mui-theme.ts +0 -1039
- package/recce-source/js/src/components/ui/mui-utils.ts +0 -113
- package/recce-source/js/src/components/ui/toaster.tsx +0 -288
- package/recce-source/js/src/components/valuediff/ValueDiffDetailResultView.tsx +0 -216
- package/recce-source/js/src/components/valuediff/ValueDiffForm.tsx +0 -246
- package/recce-source/js/src/components/valuediff/ValueDiffResultView.tsx +0 -81
- package/recce-source/js/src/components/valuediff/shared.ts +0 -33
- package/recce-source/js/src/constants/tooltipMessage.ts +0 -3
- package/recce-source/js/src/constants/urls.ts +0 -1
- package/recce-source/js/src/lib/UrlHash.ts +0 -12
- package/recce-source/js/src/lib/api/adhocQuery.ts +0 -70
- package/recce-source/js/src/lib/api/axiosClient.ts +0 -9
- package/recce-source/js/src/lib/api/cacheKeys.ts +0 -13
- package/recce-source/js/src/lib/api/checkEvents.ts +0 -252
- package/recce-source/js/src/lib/api/checks.ts +0 -129
- package/recce-source/js/src/lib/api/cll.ts +0 -53
- package/recce-source/js/src/lib/api/connectToCloud.ts +0 -13
- package/recce-source/js/src/lib/api/flag.ts +0 -37
- package/recce-source/js/src/lib/api/info.ts +0 -198
- package/recce-source/js/src/lib/api/instanceInfo.ts +0 -25
- package/recce-source/js/src/lib/api/keepAlive.ts +0 -108
- package/recce-source/js/src/lib/api/lineagecheck.ts +0 -35
- package/recce-source/js/src/lib/api/localStorageKeys.ts +0 -7
- package/recce-source/js/src/lib/api/models.ts +0 -59
- package/recce-source/js/src/lib/api/profile.ts +0 -65
- package/recce-source/js/src/lib/api/rowcount.ts +0 -19
- package/recce-source/js/src/lib/api/runs.ts +0 -174
- package/recce-source/js/src/lib/api/schemacheck.ts +0 -31
- package/recce-source/js/src/lib/api/select.ts +0 -25
- package/recce-source/js/src/lib/api/sessionStorageKeys.ts +0 -8
- package/recce-source/js/src/lib/api/state.ts +0 -117
- package/recce-source/js/src/lib/api/track.ts +0 -281
- package/recce-source/js/src/lib/api/types.ts +0 -284
- package/recce-source/js/src/lib/api/user.ts +0 -42
- package/recce-source/js/src/lib/api/valuediff.ts +0 -46
- package/recce-source/js/src/lib/api/version.ts +0 -40
- package/recce-source/js/src/lib/const.ts +0 -9
- package/recce-source/js/src/lib/dataGrid/crossFunctionConsistency.test.ts +0 -626
- package/recce-source/js/src/lib/dataGrid/dataGridFactory.test.ts +0 -2140
- package/recce-source/js/src/lib/dataGrid/dataGridFactory.ts +0 -397
- package/recce-source/js/src/lib/dataGrid/generators/rowCountUtils.test.ts +0 -132
- package/recce-source/js/src/lib/dataGrid/generators/rowCountUtils.ts +0 -126
- package/recce-source/js/src/lib/dataGrid/generators/toDataDiffGrid.test.ts +0 -1627
- package/recce-source/js/src/lib/dataGrid/generators/toDataDiffGrid.ts +0 -140
- package/recce-source/js/src/lib/dataGrid/generators/toDataGrid.ts +0 -67
- package/recce-source/js/src/lib/dataGrid/generators/toRowCountDataGrid.test.ts +0 -142
- package/recce-source/js/src/lib/dataGrid/generators/toRowCountDataGrid.ts +0 -71
- package/recce-source/js/src/lib/dataGrid/generators/toRowCountDiffDataGrid.test.ts +0 -258
- package/recce-source/js/src/lib/dataGrid/generators/toRowCountDiffDataGrid.ts +0 -153
- package/recce-source/js/src/lib/dataGrid/generators/toSchemaDataGrid.test.ts +0 -951
- package/recce-source/js/src/lib/dataGrid/generators/toSchemaDataGrid.ts +0 -221
- package/recce-source/js/src/lib/dataGrid/generators/toValueDataGrid.test.ts +0 -395
- package/recce-source/js/src/lib/dataGrid/generators/toValueDataGrid.ts +0 -184
- package/recce-source/js/src/lib/dataGrid/generators/toValueDiffGrid.test.ts +0 -884
- package/recce-source/js/src/lib/dataGrid/generators/toValueDiffGrid.ts +0 -113
- package/recce-source/js/src/lib/dataGrid/index.ts +0 -51
- package/recce-source/js/src/lib/dataGrid/propertyBased.test.ts +0 -858
- package/recce-source/js/src/lib/dataGrid/shared/columnBuilders.test.ts +0 -482
- package/recce-source/js/src/lib/dataGrid/shared/columnBuilders.ts +0 -345
- package/recce-source/js/src/lib/dataGrid/shared/dataTypeEdgeCases.test.ts +0 -698
- package/recce-source/js/src/lib/dataGrid/shared/diffColumnBuilder.test.tsx +0 -820
- package/recce-source/js/src/lib/dataGrid/shared/diffColumnBuilder.tsx +0 -277
- package/recce-source/js/src/lib/dataGrid/shared/gridUtils.test.ts +0 -785
- package/recce-source/js/src/lib/dataGrid/shared/gridUtils.ts +0 -370
- package/recce-source/js/src/lib/dataGrid/shared/index.ts +0 -81
- package/recce-source/js/src/lib/dataGrid/shared/rowBuilders.test.ts +0 -909
- package/recce-source/js/src/lib/dataGrid/shared/rowBuilders.ts +0 -325
- package/recce-source/js/src/lib/dataGrid/shared/simpleColumnBuilder.tsx +0 -240
- package/recce-source/js/src/lib/dataGrid/shared/toDiffColumn.test.tsx +0 -719
- package/recce-source/js/src/lib/dataGrid/shared/toDiffColumn.tsx +0 -231
- package/recce-source/js/src/lib/dataGrid/shared/validation.test.ts +0 -559
- package/recce-source/js/src/lib/dataGrid/shared/validation.ts +0 -367
- package/recce-source/js/src/lib/dataGrid/warehouseNamingConventions.test.ts +0 -1117
- package/recce-source/js/src/lib/formatSelect.ts +0 -50
- package/recce-source/js/src/lib/hooks/ApiConfigContext.tsx +0 -181
- package/recce-source/js/src/lib/hooks/IdleTimeoutContext.tsx +0 -177
- package/recce-source/js/src/lib/hooks/LineageGraphContext.tsx +0 -512
- package/recce-source/js/src/lib/hooks/RecceActionContext.tsx +0 -269
- package/recce-source/js/src/lib/hooks/RecceCheckContext.tsx +0 -33
- package/recce-source/js/src/lib/hooks/RecceContextProvider.tsx +0 -54
- package/recce-source/js/src/lib/hooks/RecceInstanceContext.tsx +0 -129
- package/recce-source/js/src/lib/hooks/RecceQueryContext.tsx +0 -98
- package/recce-source/js/src/lib/hooks/RecceShareStateContext.tsx +0 -59
- package/recce-source/js/src/lib/hooks/ScreenShot.tsx +0 -399
- package/recce-source/js/src/lib/hooks/useAppRouter.test.ts +0 -211
- package/recce-source/js/src/lib/hooks/useAppRouter.ts +0 -200
- package/recce-source/js/src/lib/hooks/useCheckEvents.ts +0 -99
- package/recce-source/js/src/lib/hooks/useCheckToast.tsx +0 -14
- package/recce-source/js/src/lib/hooks/useClipBoardToast.tsx +0 -27
- package/recce-source/js/src/lib/hooks/useCountdownToast.tsx +0 -102
- package/recce-source/js/src/lib/hooks/useFeedbackCollectionToast.tsx +0 -130
- package/recce-source/js/src/lib/hooks/useGuideToast.tsx +0 -45
- package/recce-source/js/src/lib/hooks/useIdleDetection.tsx +0 -185
- package/recce-source/js/src/lib/hooks/useModelColumns.tsx +0 -113
- package/recce-source/js/src/lib/hooks/useRecceInstanceInfo.tsx +0 -13
- package/recce-source/js/src/lib/hooks/useRecceServerFlag.tsx +0 -13
- package/recce-source/js/src/lib/hooks/useRun.tsx +0 -89
- package/recce-source/js/src/lib/hooks/useThemeColors.ts +0 -115
- package/recce-source/js/src/lib/mergeKeys.test.ts +0 -89
- package/recce-source/js/src/lib/mergeKeys.ts +0 -86
- package/recce-source/js/src/lib/result/ResultErrorFallback.tsx +0 -9
- package/recce-source/js/src/lib/utils/formatTime.ts +0 -84
- package/recce-source/js/src/lib/utils/urls.ts +0 -16
- package/recce-source/js/src/utils/DropdownValuesInput.tsx +0 -297
- package/recce-source/js/src/utils/formatters.tsx +0 -237
- package/recce-source/js/src/utils/transforms.ts +0 -81
- package/recce-source/js/tsconfig.json +0 -47
- package/recce-source/macros/README.md +0 -8
- package/recce-source/macros/recce_athena.sql +0 -73
- package/recce-source/pyproject.toml +0 -109
- package/recce-source/recce/VERSION +0 -1
- package/recce-source/recce/__init__.py +0 -84
- package/recce-source/recce/adapter/__init__.py +0 -0
- package/recce-source/recce/adapter/base.py +0 -109
- package/recce-source/recce/adapter/dbt_adapter/__init__.py +0 -1699
- package/recce-source/recce/adapter/dbt_adapter/dbt_version.py +0 -42
- package/recce-source/recce/adapter/sqlmesh_adapter.py +0 -141
- package/recce-source/recce/apis/__init__.py +0 -0
- package/recce-source/recce/apis/check_api.py +0 -203
- package/recce-source/recce/apis/check_events_api.py +0 -353
- package/recce-source/recce/apis/check_func.py +0 -130
- package/recce-source/recce/apis/run_api.py +0 -130
- package/recce-source/recce/apis/run_func.py +0 -258
- package/recce-source/recce/artifact.py +0 -266
- package/recce-source/recce/cli.py +0 -1846
- package/recce-source/recce/config.py +0 -127
- package/recce-source/recce/connect_to_cloud.py +0 -138
- package/recce-source/recce/core.py +0 -334
- package/recce-source/recce/diff.py +0 -26
- package/recce-source/recce/event/CONFIG +0 -1
- package/recce-source/recce/event/SENTRY_DNS +0 -1
- package/recce-source/recce/event/__init__.py +0 -304
- package/recce-source/recce/event/collector.py +0 -184
- package/recce-source/recce/event/track.py +0 -158
- package/recce-source/recce/exceptions.py +0 -21
- package/recce-source/recce/git.py +0 -77
- package/recce-source/recce/github.py +0 -222
- package/recce-source/recce/mcp_server.py +0 -861
- package/recce-source/recce/models/__init__.py +0 -6
- package/recce-source/recce/models/check.py +0 -473
- package/recce-source/recce/models/run.py +0 -46
- package/recce-source/recce/models/types.py +0 -218
- package/recce-source/recce/pull_request.py +0 -124
- package/recce-source/recce/run.py +0 -390
- package/recce-source/recce/server.py +0 -877
- package/recce-source/recce/state/__init__.py +0 -31
- package/recce-source/recce/state/cloud.py +0 -644
- package/recce-source/recce/state/const.py +0 -26
- package/recce-source/recce/state/local.py +0 -56
- package/recce-source/recce/state/state.py +0 -119
- package/recce-source/recce/state/state_loader.py +0 -174
- package/recce-source/recce/summary.py +0 -575
- package/recce-source/recce/tasks/__init__.py +0 -23
- package/recce-source/recce/tasks/core.py +0 -134
- package/recce-source/recce/tasks/dataframe.py +0 -170
- package/recce-source/recce/tasks/histogram.py +0 -433
- package/recce-source/recce/tasks/lineage.py +0 -19
- package/recce-source/recce/tasks/profile.py +0 -298
- package/recce-source/recce/tasks/query.py +0 -450
- package/recce-source/recce/tasks/rowcount.py +0 -277
- package/recce-source/recce/tasks/schema.py +0 -65
- package/recce-source/recce/tasks/top_k.py +0 -172
- package/recce-source/recce/tasks/utils.py +0 -147
- package/recce-source/recce/tasks/valuediff.py +0 -497
- package/recce-source/recce/util/__init__.py +0 -4
- package/recce-source/recce/util/api_token.py +0 -80
- package/recce-source/recce/util/breaking.py +0 -330
- package/recce-source/recce/util/cache.py +0 -25
- package/recce-source/recce/util/cll.py +0 -355
- package/recce-source/recce/util/cloud/__init__.py +0 -15
- package/recce-source/recce/util/cloud/base.py +0 -115
- package/recce-source/recce/util/cloud/check_events.py +0 -190
- package/recce-source/recce/util/cloud/checks.py +0 -242
- package/recce-source/recce/util/io.py +0 -120
- package/recce-source/recce/util/lineage.py +0 -83
- package/recce-source/recce/util/logger.py +0 -25
- package/recce-source/recce/util/onboarding_state.py +0 -45
- package/recce-source/recce/util/perf_tracking.py +0 -85
- package/recce-source/recce/util/pydantic_model.py +0 -22
- package/recce-source/recce/util/recce_cloud.py +0 -454
- package/recce-source/recce/util/singleton.py +0 -18
- package/recce-source/recce/util/startup_perf.py +0 -121
- package/recce-source/recce/yaml/__init__.py +0 -58
- package/recce-source/recce_cloud/README.md +0 -780
- package/recce-source/recce_cloud/VERSION +0 -1
- package/recce-source/recce_cloud/__init__.py +0 -24
- package/recce-source/recce_cloud/api/__init__.py +0 -17
- package/recce-source/recce_cloud/api/base.py +0 -132
- package/recce-source/recce_cloud/api/client.py +0 -186
- package/recce-source/recce_cloud/api/exceptions.py +0 -26
- package/recce-source/recce_cloud/api/factory.py +0 -63
- package/recce-source/recce_cloud/api/github.py +0 -106
- package/recce-source/recce_cloud/api/gitlab.py +0 -111
- package/recce-source/recce_cloud/artifact.py +0 -57
- package/recce-source/recce_cloud/ci_providers/__init__.py +0 -9
- package/recce-source/recce_cloud/ci_providers/base.py +0 -82
- package/recce-source/recce_cloud/ci_providers/detector.py +0 -147
- package/recce-source/recce_cloud/ci_providers/github_actions.py +0 -136
- package/recce-source/recce_cloud/ci_providers/gitlab_ci.py +0 -130
- package/recce-source/recce_cloud/cli.py +0 -434
- package/recce-source/recce_cloud/download.py +0 -230
- package/recce-source/recce_cloud/hatch_build.py +0 -20
- package/recce-source/recce_cloud/pyproject.toml +0 -49
- package/recce-source/recce_cloud/upload.py +0 -214
- package/recce-source/test.py +0 -0
- package/recce-source/tests/__init__.py +0 -0
- package/recce-source/tests/adapter/__init__.py +0 -0
- package/recce-source/tests/adapter/dbt_adapter/__init__.py +0 -0
- package/recce-source/tests/adapter/dbt_adapter/conftest.py +0 -17
- package/recce-source/tests/adapter/dbt_adapter/dbt_test_helper.py +0 -298
- package/recce-source/tests/adapter/dbt_adapter/test_dbt_adapter.py +0 -25
- package/recce-source/tests/adapter/dbt_adapter/test_dbt_cll.py +0 -717
- package/recce-source/tests/adapter/dbt_adapter/test_proj/dbt_project.yml +0 -4
- package/recce-source/tests/adapter/dbt_adapter/test_proj/manifest.json +0 -1
- package/recce-source/tests/adapter/dbt_adapter/test_proj/package-lock.yml +0 -8
- package/recce-source/tests/adapter/dbt_adapter/test_proj/packages.yml +0 -7
- package/recce-source/tests/adapter/dbt_adapter/test_proj/profiles.yml +0 -6
- package/recce-source/tests/adapter/dbt_adapter/test_selector.py +0 -205
- package/recce-source/tests/apis/__init__.py +0 -0
- package/recce-source/tests/apis/row_count_diff.json +0 -59
- package/recce-source/tests/apis/test_check_events_api.py +0 -615
- package/recce-source/tests/apis/test_run_func.py +0 -433
- package/recce-source/tests/catalog.json +0 -527
- package/recce-source/tests/data/manifest/base/catalog.json +0 -1
- package/recce-source/tests/data/manifest/base/manifest.json +0 -1
- package/recce-source/tests/data/manifest/pr2/catalog.json +0 -1
- package/recce-source/tests/data/manifest/pr2/manifest.json +0 -1
- package/recce-source/tests/manifest.json +0 -10655
- package/recce-source/tests/models/__init__.py +0 -0
- package/recce-source/tests/models/test_check.py +0 -731
- package/recce-source/tests/models/test_run_models.py +0 -295
- package/recce-source/tests/recce_cloud/__init__.py +0 -0
- package/recce-source/tests/recce_cloud/test_ci_providers.py +0 -351
- package/recce-source/tests/recce_cloud/test_cli.py +0 -735
- package/recce-source/tests/recce_cloud/test_client.py +0 -379
- package/recce-source/tests/recce_cloud/test_platform_clients.py +0 -483
- package/recce-source/tests/recce_state.json +0 -1
- package/recce-source/tests/state/test_cloud.py +0 -719
- package/recce-source/tests/state/test_local.py +0 -164
- package/recce-source/tests/state/test_state_loader.py +0 -211
- package/recce-source/tests/tasks/__init__.py +0 -0
- package/recce-source/tests/tasks/conftest.py +0 -4
- package/recce-source/tests/tasks/test_histogram.py +0 -129
- package/recce-source/tests/tasks/test_lineage.py +0 -55
- package/recce-source/tests/tasks/test_preset_checks.py +0 -64
- package/recce-source/tests/tasks/test_profile.py +0 -397
- package/recce-source/tests/tasks/test_query.py +0 -528
- package/recce-source/tests/tasks/test_row_count.py +0 -133
- package/recce-source/tests/tasks/test_schema.py +0 -122
- package/recce-source/tests/tasks/test_top_k.py +0 -77
- package/recce-source/tests/tasks/test_utils.py +0 -439
- package/recce-source/tests/tasks/test_valuediff.py +0 -361
- package/recce-source/tests/test_cli.py +0 -236
- package/recce-source/tests/test_cli_mcp_optional.py +0 -45
- package/recce-source/tests/test_cloud_listing_cli.py +0 -324
- package/recce-source/tests/test_config.py +0 -43
- package/recce-source/tests/test_connect_to_cloud.py +0 -82
- package/recce-source/tests/test_core.py +0 -174
- package/recce-source/tests/test_dbt.py +0 -36
- package/recce-source/tests/test_mcp_server.py +0 -505
- package/recce-source/tests/test_pull_request.py +0 -130
- package/recce-source/tests/test_server.py +0 -202
- package/recce-source/tests/test_server_lifespan.py +0 -138
- package/recce-source/tests/test_summary.py +0 -73
- package/recce-source/tests/util/__init__.py +0 -0
- package/recce-source/tests/util/cloud/__init__.py +0 -0
- package/recce-source/tests/util/cloud/test_check_events.py +0 -255
- package/recce-source/tests/util/cloud/test_checks.py +0 -204
- package/recce-source/tests/util/test_api_token.py +0 -119
- package/recce-source/tests/util/test_breaking.py +0 -1427
- package/recce-source/tests/util/test_cll.py +0 -706
- package/recce-source/tests/util/test_lineage.py +0 -122
- package/recce-source/tests/util/test_onboarding_state.py +0 -84
- package/recce-source/tests/util/test_recce_cloud.py +0 -231
- package/recce-source/tox.ini +0 -40
- package/recce-source/uv.lock +0 -3928
- package/src/api/index.ts +0 -32
- package/src/components/index.ts +0 -154
- package/src/global.d.ts +0 -14
- package/src/hooks/index.ts +0 -56
- package/src/index.ts +0 -17
- package/src/lib/hooks/RouteConfigContext.ts +0 -139
- package/src/lib/hooks/useAppRouter.ts +0 -240
- package/src/mui-augmentation.d.ts +0 -139
- package/src/theme/index.ts +0 -13
- package/src/theme.ts +0 -23
- package/src/types/index.ts +0 -23
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"utils-CXWhfyxC.js","names":["getPrimaryKeyValue","groupedRows: Map<\n string,\n { base: unknown[] | null; current: unknown[] | null }\n >","rowOrder: string[]","columns: string[]","rows: unknown[][]","row: unknown[]","maxRows","extractors: Record<\n string,\n (result: unknown, options?: CSVExportOptions) => CSVData | null\n>","nodeName: string | undefined","order: string[]","columns: ColumnConfig[]","selectOptions: { value: string; onClick: () => void }[]","selectOptions: { value: string; onClick: () => void }[]","results: string[]","result: ReturnType<typeof mergeKeysWithStatus>","baseIndexMap: Record<string, number | undefined>","result: Record<string, ColumnMapEntry>","result: Record<string, MergeColumnMapEntry>","keys: string[]","result: string[]","baseVal: unknown","currentVal: unknown","renderedValue: string","listeners: Set<(event: ToastEvent) => void>","DataFrameColumnGroupHeader","inlineRenderCell","defaultRenderCell","createIndexColumn","createPrimaryKeyColumn","DataFrameColumnGroupHeader","defaultRenderCell","columns: DiffColumnDefinition[]","rowStats: RowStats","row: RowObjectType","context?: string","details?: Record<string, unknown>","baseMap: Record<string, RowObjectType>","currentMap: Record<string, RowObjectType>","DataFrameColumnGroupHeader","defaultRenderCell","DataFrameColumnHeader","columns: SimpleColumnDefinition[]","baseMap: Record<string, RowObjectType | undefined>","currentMap: Record<string, RowObjectType | undefined>","defaultRenderComponents: DiffColumnRenderComponents","defaultSimpleRenderComponents: SimpleColumnRenderComponents","rows: RowObjectType[]","nodes: LineageGraphNode[]","parts: string[]"],"sources":["../src/utils/csv/browser.ts","../src/utils/csv/extractors.ts","../src/utils/csv/format.ts","../src/utils/csv/index.ts","../src/utils/dataGrid/columnBuilders.ts","../src/utils/dataGrid/columnPrecisionOptions.ts","../src/components/ui/DiffText.tsx","../src/components/ui/dataGrid/DataFrameColumnGroupHeader.tsx","../src/components/ui/dataGrid/DataFrameColumnHeader.tsx","../src/utils/transforms.ts","../src/utils/formatters.ts","../src/utils/mergeKeys.ts","../src/utils/dataGrid/gridUtils.ts","../src/components/ui/dataGrid/defaultRenderCell.tsx","../src/components/ui/Toaster.tsx","../src/hooks/useClipBoardToast.tsx","../src/components/ui/DiffTextWithToast.tsx","../src/components/ui/dataGrid/inlineRenderCell.tsx","../src/utils/dataGrid/toDiffColumn.tsx","../src/utils/dataGrid/diffColumnBuilder.tsx","../src/utils/dataGrid/rowBuilders.ts","../src/utils/dataGrid/validation.ts","../src/utils/dataGrid/generators/toDataDiffGrid.ts","../src/utils/dataGrid/simpleColumnBuilder.tsx","../src/utils/dataGrid/generators/toDataGrid.ts","../src/utils/dataGrid/generators/toValueDiffGrid.ts","../src/utils/dataGrid/configured.ts","../src/utils/delta.ts","../src/utils/dataGrid/rowCountUtils.ts","../src/utils/dataGrid/generators/toRowCountDataGrid.ts","../src/utils/dataGrid/generators/toRowCountDiffDataGrid.ts","../src/utils/envUtils.ts","../src/utils/formatSelect.ts","../src/utils/formatTime.ts","../src/utils/schemaDiff.ts","../src/utils/urls.ts"],"sourcesContent":["/**\n * Browser-specific CSV export utilities\n *\n * These utilities depend on browser APIs (Clipboard, file-saver) and should\n * only be used in browser environments.\n */\nimport saveAs from \"file-saver\";\n\n/**\n * Trigger browser download of CSV file\n * @param content - CSV string content\n * @param filename - Name for the downloaded file\n */\nexport function downloadCSV(content: string, filename: string): void {\n const blob = new Blob([content], { type: \"text/csv;charset=utf-8\" });\n saveAs(blob, filename);\n}\n\n/**\n * Copy CSV content to clipboard\n * Requires a secure context (HTTPS or localhost)\n * @param content - CSV string content to copy\n * @throws Error if Clipboard API is not available\n */\nexport async function copyCSVToClipboard(content: string): Promise<void> {\n if (typeof navigator === \"undefined\" || !navigator.clipboard?.writeText) {\n throw new Error(\n \"Clipboard API not available. Ensure you're using HTTPS or localhost.\",\n );\n }\n\n await navigator.clipboard.writeText(content);\n}\n","/**\n * @file csv/extractors.ts\n * @description CSV data extractors for each run type\n */\nimport type {\n DataFrame,\n ProfileDiffResult,\n QueryDiffResult,\n RowCountDiffResult,\n TopKDiffResult,\n ValueDiffResult,\n} from \"../../api\";\n\nexport interface CSVData {\n columns: string[];\n rows: unknown[][];\n}\n\nexport interface CSVExportOptions {\n displayMode?: \"inline\" | \"side_by_side\";\n primaryKeys?: string[];\n}\n\n/**\n * Format a cell value for inline diff mode\n * If base and current are the same, return the value\n * If different, return \"(base_value) (current_value)\"\n */\nfunction formatInlineDiffCell(\n baseValue: unknown,\n currentValue: unknown,\n): unknown {\n // Convert to string for comparison\n const baseStr = baseValue == null ? \"\" : String(baseValue);\n const currentStr = currentValue == null ? \"\" : String(currentValue);\n\n if (baseStr === currentStr) {\n return baseValue;\n }\n\n // Format as \"(base) (current)\" when different\n const baseDisplay = baseValue == null ? \"\" : `(${baseValue})`;\n const currentDisplay = currentValue == null ? \"\" : `(${currentValue})`;\n return `${baseDisplay} ${currentDisplay}`.trim();\n}\n\n/**\n * Extract columns and rows from a DataFrame\n */\nfunction extractDataFrame(df: DataFrame | undefined): CSVData | null {\n if (!df || !df.columns || !df.data) {\n return null;\n }\n return {\n columns: df.columns.map((col) => col.name),\n rows: df.data.map((row) => [...row]),\n };\n}\n\n/**\n * Extract CSV data from query result (single environment)\n */\nfunction extractQuery(result: unknown): CSVData | null {\n return extractDataFrame(result as DataFrame);\n}\n\n/**\n * Extract CSV data from query_base result\n */\nfunction extractQueryBase(result: unknown): CSVData | null {\n // query_base returns a DataFrame directly (QueryResult = DataFrame)\n return extractDataFrame(result as DataFrame);\n}\n\n/**\n * Extract CSV data from query_diff result\n * Supports two result shapes:\n * 1. { diff: DataFrame } - joined diff result (QueryDiffJoinResultView)\n * 2. { base: DataFrame, current: DataFrame } - separate base/current (QueryDiffResultView)\n *\n * Display modes:\n * - \"inline\": Merged rows where same values shown as-is, differing values shown as \"(base) (current)\"\n * - \"side_by_side\": Single row per record with base__col, current__col columns\n *\n * Note: When base and current have different row counts (e.g., added/removed rows),\n * the merge is done positionally. Extra rows will show null for the missing environment.\n */\nfunction extractQueryDiff(\n result: unknown,\n options?: CSVExportOptions,\n): CSVData | null {\n const typed = result as QueryDiffResult;\n const displayMode = options?.displayMode ?? \"inline\";\n const primaryKeys = options?.primaryKeys ?? [];\n\n // First, check if diff DataFrame exists (joined result)\n if (typed?.diff) {\n return extractQueryDiffJoined(typed.diff, displayMode, primaryKeys);\n }\n\n // Fall back to base/current DataFrames\n return extractQueryDiffSeparate(typed, displayMode);\n}\n\n/**\n * Extract CSV from joined diff DataFrame (QueryDiffJoinResultView)\n * The diff DataFrame has columns like: pk, col1, col2, in_a, in_b\n * where in_a/in_b indicate presence in base/current\n *\n * The DataFrame may have separate rows for base (in_a=true) and current (in_b=true)\n * records. This function groups them by primary key and merges into single output rows.\n *\n * Produces same layout as extractQueryDiffSeparate for consistency.\n */\nfunction extractQueryDiffJoined(\n diff: DataFrame,\n displayMode: \"inline\" | \"side_by_side\",\n primaryKeys: string[],\n): CSVData | null {\n if (!diff?.columns || !diff?.data) return null;\n\n // Find in_a and in_b column indices\n const inAIndex = diff.columns.findIndex(\n (col) => col.key.toLowerCase() === \"in_a\",\n );\n const inBIndex = diff.columns.findIndex(\n (col) => col.key.toLowerCase() === \"in_b\",\n );\n\n // Get data columns (exclude in_a and in_b)\n const dataColumns = diff.columns.filter(\n (col) =>\n col.key.toLowerCase() !== \"in_a\" && col.key.toLowerCase() !== \"in_b\",\n );\n const dataColumnNames = dataColumns.map((col) => col.name);\n const dataColumnIndices = dataColumns.map((col) =>\n diff.columns.findIndex((c) => c.key === col.key),\n );\n\n // Find primary key column indices\n const pkIndices = primaryKeys\n .map((pk) => diff.columns.findIndex((col) => col.key === pk))\n .filter((idx) => idx >= 0);\n\n // Extract row values for data columns only\n const extractRowValues = (rowData: unknown[]): unknown[] => {\n return dataColumnIndices.map((colIndex) => rowData[colIndex]);\n };\n\n // Generate primary key string for grouping\n const getPrimaryKeyValue = (rowData: unknown[]): string => {\n if (pkIndices.length === 0) {\n // No primary keys - use row index (will be set later)\n return \"\";\n }\n return pkIndices.map((idx) => String(rowData[idx] ?? \"\")).join(\"|||\");\n };\n\n // Group rows by primary key, separating base and current\n const groupedRows: Map<\n string,\n { base: unknown[] | null; current: unknown[] | null }\n > = new Map();\n const rowOrder: string[] = []; // Track insertion order\n\n diff.data.forEach((rowData, index) => {\n const inA = inAIndex >= 0 ? rowData[inAIndex] : true;\n const inB = inBIndex >= 0 ? rowData[inBIndex] : true;\n\n // Use primary key or index for grouping\n let pkValue = getPrimaryKeyValue(rowData);\n if (pkValue === \"\") {\n pkValue = String(index);\n }\n\n if (!groupedRows.has(pkValue)) {\n groupedRows.set(pkValue, { base: null, current: null });\n rowOrder.push(pkValue);\n }\n\n const group = groupedRows.get(pkValue);\n if (!group) return;\n\n const values = extractRowValues(rowData);\n\n if (inA) {\n group.base = values;\n }\n if (inB) {\n group.current = values;\n }\n });\n\n if (displayMode === \"side_by_side\") {\n // Side-by-side: columns like base__col1, current__col1, base__col2, current__col2\n const columns: string[] = [];\n dataColumnNames.forEach((name) => {\n columns.push(`base__${name}`, `current__${name}`);\n });\n\n const rows: unknown[][] = [];\n\n for (const pkValue of rowOrder) {\n const group = groupedRows.get(pkValue);\n if (!group) continue;\n\n const baseValues = group.base;\n const currentValues = group.current;\n\n const row: unknown[] = [];\n dataColumnNames.forEach((_, colIndex) => {\n row.push(baseValues ? baseValues[colIndex] : null);\n row.push(currentValues ? currentValues[colIndex] : null);\n });\n\n rows.push(row);\n }\n\n return { columns, rows };\n }\n\n // Inline mode: merged rows with diff shown in parentheses\n // Format: value if same, \"(base_value) (current_value)\" if different\n const columns = [...dataColumnNames];\n const rows: unknown[][] = [];\n\n for (const pkValue of rowOrder) {\n const group = groupedRows.get(pkValue);\n if (!group) continue;\n\n const baseValues = group.base;\n const currentValues = group.current;\n\n // Merge base and current into single row\n const row: unknown[] = [];\n dataColumnNames.forEach((_, colIndex) => {\n const baseVal = baseValues ? baseValues[colIndex] : null;\n const currentVal = currentValues ? currentValues[colIndex] : null;\n row.push(formatInlineDiffCell(baseVal, currentVal));\n });\n\n rows.push(row);\n }\n\n return { columns, rows };\n}\n\n/**\n * Extract CSV from separate base/current DataFrames (QueryDiffResultView)\n */\nfunction extractQueryDiffSeparate(\n typed: QueryDiffResult,\n displayMode: \"inline\" | \"side_by_side\",\n): CSVData | null {\n const df = typed?.current || typed?.base;\n if (!df) return null;\n\n // If only one exists, just return it\n if (!typed?.base || !typed?.current) {\n return extractDataFrame(df);\n }\n\n const columnNames = typed.current.columns.map((c) => c.name);\n\n if (displayMode === \"side_by_side\") {\n // Side-by-side: columns like base__col1, current__col1, base__col2, current__col2\n const columns: string[] = [];\n columnNames.forEach((name) => {\n columns.push(`base__${name}`, `current__${name}`);\n });\n\n const rows: unknown[][] = [];\n const maxRows = Math.max(typed.base.data.length, typed.current.data.length);\n\n for (let i = 0; i < maxRows; i++) {\n const row: unknown[] = [];\n const baseRow = i < typed.base.data.length ? typed.base.data[i] : null;\n const currentRow =\n i < typed.current.data.length ? typed.current.data[i] : null;\n\n columnNames.forEach((_, colIndex) => {\n row.push(baseRow ? baseRow[colIndex] : null);\n row.push(currentRow ? currentRow[colIndex] : null);\n });\n\n rows.push(row);\n }\n\n return { columns, rows };\n }\n\n // Inline mode: merged rows with diff shown in parentheses\n // Format: value if same, \"(base_value) (current_value)\" if different\n const columns = [...columnNames];\n const rows: unknown[][] = [];\n\n const maxRows = Math.max(typed.base.data.length, typed.current.data.length);\n for (let i = 0; i < maxRows; i++) {\n const baseRow = i < typed.base.data.length ? typed.base.data[i] : null;\n const currentRow =\n i < typed.current.data.length ? typed.current.data[i] : null;\n\n // Merge base and current into single row\n const row: unknown[] = [];\n columnNames.forEach((_, colIndex) => {\n const baseVal = baseRow ? baseRow[colIndex] : null;\n const currentVal = currentRow ? currentRow[colIndex] : null;\n row.push(formatInlineDiffCell(baseVal, currentVal));\n });\n\n rows.push(row);\n }\n\n return { columns, rows };\n}\n\n/**\n * Extract CSV data from profile_diff result\n */\nfunction extractProfileDiff(result: unknown): CSVData | null {\n const typed = result as ProfileDiffResult;\n\n // Profile data has metrics as columns, one row per profiled column\n const df = typed?.current || typed?.base;\n if (!df) return null;\n\n // If both exist, combine with source column\n if (typed?.base && typed?.current) {\n const columns = [\"_source\", ...typed.current.columns.map((c) => c.name)];\n const rows: unknown[][] = [];\n\n typed.base.data.forEach((row) => {\n rows.push([\"base\", ...row]);\n });\n typed.current.data.forEach((row) => {\n rows.push([\"current\", ...row]);\n });\n\n return { columns, rows };\n }\n\n return extractDataFrame(df);\n}\n\n/**\n * Extract CSV data from row_count_diff result\n */\nfunction extractRowCountDiff(result: unknown): CSVData | null {\n const typed = result as RowCountDiffResult;\n if (!typed || typeof typed !== \"object\") return null;\n\n const columns = [\n \"node\",\n \"base_count\",\n \"current_count\",\n \"diff\",\n \"diff_percent\",\n ];\n const rows: unknown[][] = [];\n\n for (const [nodeName, counts] of Object.entries(typed)) {\n if (counts && typeof counts === \"object\") {\n const base = (counts as { base?: number | null }).base;\n const current = (counts as { curr?: number | null }).curr;\n const diff = base != null && current != null ? current - base : null;\n const diffPercent =\n base && diff !== null ? ((diff / base) * 100).toFixed(2) + \"%\" : null;\n rows.push([nodeName, base, current, diff, diffPercent]);\n }\n }\n\n return { columns, rows };\n}\n\n/**\n * Extract CSV data from value_diff result\n */\nfunction extractValueDiff(result: unknown): CSVData | null {\n const typed = result as ValueDiffResult;\n if (!typed?.data) return null;\n return extractDataFrame(typed.data);\n}\n\n/**\n * Extract CSV data from value_diff_detail result\n */\nfunction extractValueDiffDetail(result: unknown): CSVData | null {\n return extractDataFrame(result as DataFrame);\n}\n\n/**\n * Extract CSV data from top_k_diff result\n */\nfunction extractTopKDiff(result: unknown): CSVData | null {\n const typed = result as TopKDiffResult;\n\n // Check if either base or current has values\n const hasBaseValues = !!typed?.base?.values;\n const hasCurrentValues = !!typed?.current?.values;\n if (!hasBaseValues && !hasCurrentValues) return null;\n\n // TopK has { values: [...], counts: [...], valids: number }\n const columns = [\"_source\", \"value\", \"count\"];\n const rows: unknown[][] = [];\n\n if (typed?.base?.values) {\n typed.base.values.forEach((value, index) => {\n rows.push([\"base\", value, typed.base.counts[index]]);\n });\n }\n if (typed?.current?.values) {\n typed.current.values.forEach((value, index) => {\n rows.push([\"current\", value, typed.current.counts[index]]);\n });\n }\n\n return { columns, rows };\n}\n\n/**\n * Map of run types to their extractor functions\n * Some extractors accept options (like query_diff for displayMode)\n */\nconst extractors: Record<\n string,\n (result: unknown, options?: CSVExportOptions) => CSVData | null\n> = {\n query: extractQuery,\n query_base: extractQueryBase,\n query_diff: extractQueryDiff,\n profile: extractProfileDiff,\n profile_diff: extractProfileDiff,\n row_count: extractRowCountDiff,\n row_count_diff: extractRowCountDiff,\n value_diff: extractValueDiff,\n value_diff_detail: extractValueDiffDetail,\n top_k_diff: extractTopKDiff,\n};\n\n/**\n * Extract CSV data from a run result\n * @param runType - The type of run (query, query_diff, etc.)\n * @param result - The run result data\n * @param options - Optional export options (e.g., displayMode for query_diff)\n * @returns CSVData or null if the run type doesn't support CSV export\n */\nexport function extractCSVData(\n runType: string,\n result: unknown,\n options?: CSVExportOptions,\n): CSVData | null {\n const extractor = extractors[runType];\n if (!extractor) return null;\n\n try {\n return extractor(result, options);\n } catch (error) {\n console.error(\n `Failed to extract CSV data for run type \"${runType}\":`,\n error,\n );\n return null;\n }\n}\n\n/**\n * Check if a run type supports CSV export\n */\nexport function supportsCSVExport(runType: string): boolean {\n return runType in extractors;\n}\n","/**\n * @file csv/format.ts\n * @description CSV formatting utilities with Excel-friendly output\n */\n\n/**\n * Escape a value for CSV format\n * - Wrap in quotes if contains comma, quote, or newline\n * - Escape quotes by doubling them\n */\nfunction escapeCSVValue(value: unknown): string {\n if (value === null || value === undefined) {\n return \"\";\n }\n\n const stringValue =\n typeof value === \"object\" ? JSON.stringify(value) : String(value);\n\n // Check if escaping is needed\n if (\n stringValue.includes(\",\") ||\n stringValue.includes('\"') ||\n stringValue.includes(\"\\n\") ||\n stringValue.includes(\"\\r\")\n ) {\n return `\"${stringValue.replace(/\"/g, '\"\"')}\"`;\n }\n\n return stringValue;\n}\n\n/**\n * Convert tabular data to CSV string\n * @param columns - Column headers\n * @param rows - Row data (array of arrays)\n * @returns CSV string with UTF-8 BOM for Excel compatibility\n */\nexport function toCSV(columns: string[], rows: unknown[][]): string {\n const BOM = \"\\uFEFF\";\n\n const headerRow = columns.map(escapeCSVValue).join(\",\");\n const dataRows = rows.map((row) => row.map(escapeCSVValue).join(\",\"));\n\n return BOM + [headerRow, ...dataRows].join(\"\\r\\n\");\n}\n","/**\n * @file csv/index.ts\n * @description CSV export utilities\n */\n\nexport { copyCSVToClipboard, downloadCSV } from \"./browser\";\nexport {\n type CSVData,\n type CSVExportOptions,\n extractCSVData,\n supportsCSVExport,\n} from \"./extractors\";\nexport { toCSV } from \"./format\";\n\n/**\n * Generate timestamp string for filenames\n * Format: YYYYMMDD-HHmmss\n */\nexport function generateTimestamp(): string {\n const now = new Date();\n const year = now.getFullYear();\n const month = String(now.getMonth() + 1).padStart(2, \"0\");\n const day = String(now.getDate()).padStart(2, \"0\");\n const hours = String(now.getHours()).padStart(2, \"0\");\n const minutes = String(now.getMinutes()).padStart(2, \"0\");\n const seconds = String(now.getSeconds()).padStart(2, \"0\");\n return `${year}${month}${day}-${hours}${minutes}${seconds}`;\n}\n\n/**\n * Generate context-aware CSV filename\n */\nexport function generateCSVFilename(\n runType: string,\n params?: Record<string, unknown>,\n): string {\n const timestamp = generateTimestamp();\n const type = runType.replace(/_/g, \"-\");\n\n // Try to extract node name from params\n let nodeName: string | undefined;\n\n if (\n params?.node_names &&\n Array.isArray(params.node_names) &&\n params.node_names.length === 1\n ) {\n nodeName = String(params.node_names[0]);\n } else if (params?.model && typeof params.model === \"string\") {\n nodeName = params.model;\n }\n\n // Sanitize node name for filesystem (preserve dots for schema.table patterns)\n if (nodeName) {\n nodeName = nodeName.replace(/[^a-zA-Z0-9_.-]/g, \"-\").toLowerCase();\n return `${type}-${nodeName}-${timestamp}.csv`;\n }\n\n return `${type}-result-${timestamp}.csv`;\n}\n","/**\n * @file columnBuilders.ts\n * @description Column configuration utilities for data grids\n *\n * Provides helper functions for building column configurations.\n * Note: React components for headers are kept in diffColumnBuilder.tsx\n * to maintain separation between pure logic and React components.\n */\n\nimport { type ColumnRenderMode, type ColumnType } from \"../../api\";\n\n// ============================================================================\n// Types\n// ============================================================================\n\nexport interface ColumnConfig {\n key: string;\n name: string;\n columnType: ColumnType;\n columnStatus?: string;\n columnRenderMode?: ColumnRenderMode;\n frozen?: boolean;\n isPrimaryKey?: boolean;\n}\n\nexport interface ColumnOrderConfig {\n primaryKeys: string[];\n pinnedColumns: string[];\n allColumns: string[];\n excludeColumns?: string[];\n}\n\nexport interface GridColumnsConfig {\n columnMap: Record<\n string,\n { key: string; colType: ColumnType; status?: string }\n >;\n primaryKeys: string[];\n pinnedColumns: string[];\n columnsRenderMode: Record<string, ColumnRenderMode>;\n changedOnly?: boolean;\n rowStats?: { added: number; removed: number; modified: number };\n excludeColumns?: string[];\n /**\n * When true, throws an error if a primary key or pinned column is not found\n * in the columnMap. When false (default), silently skips missing columns.\n *\n * - querydiff: uses false (lenient, handles schema differences)\n * - valuediff: uses true (strict, PKs must exist)\n */\n strictMode?: boolean;\n}\n\n// ============================================================================\n// Column Order Builder\n// ============================================================================\n\n/**\n * Determines the order of columns based on primary keys, pinned columns,\n * and remaining columns.\n *\n * @returns Array of column names in the correct display order\n */\nexport function buildColumnOrder(config: ColumnOrderConfig): string[] {\n const {\n primaryKeys,\n pinnedColumns,\n allColumns,\n excludeColumns = [],\n } = config;\n\n const order: string[] = [];\n const added = new Set<string>();\n\n const isExcluded = (key: string) => excludeColumns.includes(key);\n\n // Add primary keys first\n primaryKeys.forEach((key) => {\n if (!added.has(key) && !isExcluded(key)) {\n order.push(key);\n added.add(key);\n }\n });\n\n // Add pinned columns\n pinnedColumns.forEach((key) => {\n if (!added.has(key) && !isExcluded(key)) {\n order.push(key);\n added.add(key);\n }\n });\n\n // Add remaining columns\n allColumns.forEach((key) => {\n if (!added.has(key) && !isExcluded(key)) {\n order.push(key);\n added.add(key);\n }\n });\n\n return order;\n}\n\n// ============================================================================\n// Column Filtering Helpers\n// ============================================================================\n\n/**\n * Checks if a column should be included based on changedOnly filter\n */\nexport function shouldIncludeColumn(\n columnStatus: string | undefined,\n changedOnly: boolean,\n hasModifiedRows: boolean,\n): boolean {\n if (!changedOnly || !hasModifiedRows) {\n return true;\n }\n\n return (\n columnStatus === \"added\" ||\n columnStatus === \"removed\" ||\n columnStatus === \"modified\"\n );\n}\n\n/**\n * Checks if a column is a primary key (exact matching)\n */\nexport function isPrimaryKeyColumn(\n columnName: string,\n primaryKeys: string[],\n): boolean {\n return primaryKeys.includes(columnName);\n}\n\n/**\n * Checks if a column is pinned (exact matching)\n */\nexport function isPinnedColumn(\n columnName: string,\n pinnedColumns: string[],\n): boolean {\n return pinnedColumns.includes(columnName);\n}\n\n/**\n * Checks if a column should be excluded from display (exact matching)\n */\nexport function isExcludedColumn(\n columnName: string,\n excludeColumns: string[],\n): boolean {\n return excludeColumns.includes(columnName);\n}\n\n// ============================================================================\n// Internal Helpers\n// ============================================================================\n\n/**\n * Finds a column in the columnMap (exact matching)\n */\nfunction findColumn(\n columnMap: GridColumnsConfig[\"columnMap\"],\n name: string,\n): { key: string; colType: ColumnType; status?: string } | undefined {\n return columnMap[name];\n}\n\n// ============================================================================\n// Column Configuration Helpers\n// ============================================================================\n\n/**\n * Gets the list of columns to display for a diff grid\n *\n * @description Builds an ordered list of column configurations:\n * 1. Primary key columns (frozen)\n * 2. Pinned columns\n * 3. Remaining columns (filtered by changedOnly if applicable)\n *\n * @throws {Error} When strictMode is true and a primary key or pinned column\n * is not found in the columnMap\n */\nexport function getDisplayColumns(config: GridColumnsConfig): ColumnConfig[] {\n const {\n columnMap,\n primaryKeys,\n pinnedColumns,\n columnsRenderMode,\n changedOnly = false,\n rowStats,\n excludeColumns = [],\n strictMode = false,\n } = config;\n\n const hasModifiedRows = (rowStats?.modified ?? 0) > 0;\n const columns: ColumnConfig[] = [];\n\n // Add primary key columns first\n primaryKeys.forEach((name) => {\n const col = findColumn(columnMap, name);\n\n if (!col) {\n if (strictMode) {\n throw new Error(`Primary key column \"${name}\" not found in columnMap`);\n }\n return;\n }\n\n columns.push({\n key: name,\n name,\n columnType: col.colType,\n columnStatus: col.status,\n columnRenderMode: columnsRenderMode[name],\n frozen: true,\n isPrimaryKey: true,\n });\n });\n\n // Add pinned columns\n pinnedColumns.forEach((name) => {\n if (isPrimaryKeyColumn(name, primaryKeys)) return;\n if (isExcludedColumn(name, excludeColumns)) return;\n\n const col = findColumn(columnMap, name);\n\n if (!col) {\n if (strictMode) {\n throw new Error(`Pinned column \"${name}\" not found in columnMap`);\n }\n return;\n }\n\n columns.push({\n key: name,\n name,\n columnType: col.colType,\n columnStatus: col.status,\n columnRenderMode: columnsRenderMode[name],\n frozen: true,\n });\n });\n\n // Add remaining columns\n Object.entries(columnMap).forEach(([name, col]) => {\n if (isPrimaryKeyColumn(name, primaryKeys)) return;\n if (isPinnedColumn(name, pinnedColumns)) return;\n if (isExcludedColumn(name, excludeColumns)) return;\n\n if (!shouldIncludeColumn(col.status, changedOnly, hasModifiedRows)) {\n return;\n }\n\n columns.push({\n key: name,\n name,\n columnType: col.colType,\n columnStatus: col.status,\n columnRenderMode: columnsRenderMode[name],\n });\n });\n\n return columns;\n}\n\n/**\n * Gets the list of columns for a simple (non-diff) grid\n */\nexport function getSimpleDisplayColumns(\n config: Omit<GridColumnsConfig, \"changedOnly\" | \"rowStats\">,\n): ColumnConfig[] {\n const {\n columnMap,\n primaryKeys,\n pinnedColumns,\n columnsRenderMode,\n excludeColumns = [],\n strictMode = false,\n } = config;\n\n const columns: ColumnConfig[] = [];\n\n // Add primary key columns first\n primaryKeys.forEach((name) => {\n const col = columnMap[name];\n\n if (!col) {\n if (strictMode) {\n throw new Error(`Primary key column \"${name}\" not found in columnMap`);\n }\n return;\n }\n\n columns.push({\n key: name,\n name,\n columnType: col.colType,\n columnRenderMode: columnsRenderMode[name],\n frozen: true,\n isPrimaryKey: true,\n });\n });\n\n // Add pinned columns\n pinnedColumns.forEach((name) => {\n if (primaryKeys.includes(name)) return;\n if (excludeColumns.includes(name)) return;\n\n const col = columnMap[name];\n\n if (!col) {\n if (strictMode) {\n throw new Error(`Pinned column \"${name}\" not found in columnMap`);\n }\n return;\n }\n\n columns.push({\n key: col.key,\n name,\n columnType: col.colType,\n columnRenderMode: columnsRenderMode[name],\n frozen: true,\n });\n });\n\n // Add remaining columns\n Object.entries(columnMap).forEach(([name, col]) => {\n if (primaryKeys.includes(name)) return;\n if (pinnedColumns.includes(name)) return;\n if (excludeColumns.includes(name)) return;\n\n columns.push({\n key: col.key,\n name,\n columnType: col.colType,\n columnRenderMode: columnsRenderMode[name],\n });\n });\n\n return columns;\n}\n","/**\n * @file columnPrecisionOptions.ts\n * @description Column precision select options for number columns\n *\n * Provides menu options for changing how numeric columns are rendered:\n * - Raw value (no formatting)\n * - 2 decimal points\n * - Percentage format\n * - Net change (delta) display\n */\n\nimport type { ColumnRenderMode } from \"../../api\";\n\n/**\n * Option for column precision menu\n */\nexport interface ColumnPrecisionOption {\n /** Display text for the menu item */\n value: string;\n /** Callback when option is selected */\n onClick: () => void;\n}\n\n/**\n * Generates precision select options for a numeric column\n *\n * @description Returns an array of options that can be used to build\n * a menu for changing how a numeric column is rendered. Each option\n * calls the provided callback with the appropriate render mode.\n *\n * @param colName - The column name to apply the render mode to\n * @param onColumnsRenderModeChanged - Callback to update column render modes\n * @returns Array of menu options with value and onClick handler\n *\n * @example\n * ```tsx\n * const options = columnPrecisionSelectOptions(\n * \"price\",\n * (modes) => setRenderModes(prev => ({ ...prev, ...modes }))\n * );\n *\n * // Use in a menu\n * options.map(opt => (\n * <MenuItem key={opt.value} onClick={opt.onClick}>\n * {opt.value}\n * </MenuItem>\n * ));\n * ```\n */\nexport function columnPrecisionSelectOptions(\n colName: string,\n onColumnsRenderModeChanged: (col: Record<string, ColumnRenderMode>) => void,\n): ColumnPrecisionOption[] {\n return [\n {\n value: \"Show raw value\",\n onClick: () => {\n onColumnsRenderModeChanged({ [colName]: \"raw\" });\n },\n },\n {\n value: \"Show 2 decimal points\",\n onClick: () => {\n onColumnsRenderModeChanged({ [colName]: 2 });\n },\n },\n {\n value: \"Show as percentage\",\n onClick: () => {\n onColumnsRenderModeChanged({ [colName]: \"percent\" });\n },\n },\n {\n value: \"Show with net change\",\n onClick: () => {\n onColumnsRenderModeChanged({ [colName]: \"delta\" });\n },\n },\n ];\n}\n","\"use client\";\n\nimport Box from \"@mui/material/Box\";\nimport IconButton from \"@mui/material/IconButton\";\nimport Tooltip from \"@mui/material/Tooltip\";\nimport { type ReactNode, useState } from \"react\";\nimport { PiCopy } from \"react-icons/pi\";\nimport { colors } from \"../../theme/colors\";\n\n/**\n * Props for the DiffText component\n */\nexport interface DiffTextProps {\n /** The text value to display */\n value: string;\n /** Color palette for the diff indicator */\n colorPalette: \"red\" | \"green\";\n /** Whether to gray out the text (for null/missing values) */\n grayOut?: boolean;\n /** Hide the copy button */\n noCopy?: boolean;\n /** Custom font size */\n fontSize?: string;\n /**\n * Callback when copy button is clicked.\n * If provided, the component will use this for copy functionality.\n * If not provided, uses navigator.clipboard.writeText.\n */\n onCopy?: (value: string) => void;\n}\n\n/**\n * DiffText Component\n *\n * Displays a text value with diff styling (red for removed, green for added).\n * Includes an optional copy-to-clipboard button on hover.\n *\n * @example Basic usage\n * ```tsx\n * import { DiffText } from '@datarecce/ui';\n *\n * // Show a value that was added (green)\n * <DiffText value=\"new_value\" colorPalette=\"green\" />\n *\n * // Show a value that was removed (red)\n * <DiffText value=\"old_value\" colorPalette=\"red\" />\n * ```\n *\n * @example With custom copy callback\n * ```tsx\n * <DiffText\n * value=\"copy_me\"\n * colorPalette=\"green\"\n * onCopy={(value) => {\n * navigator.clipboard.writeText(value);\n * showToast(`${value} copied!`);\n * }}\n * />\n * ```\n *\n * @example Grayed out (null value)\n * ```tsx\n * <DiffText value=\"null\" colorPalette=\"red\" grayOut />\n * ```\n */\nexport function DiffText({\n value,\n colorPalette,\n grayOut,\n noCopy,\n fontSize,\n onCopy,\n}: DiffTextProps) {\n const [isHovered, setIsHovered] = useState(false);\n\n // Get the color values from the theme colors\n const textColor = colors[colorPalette][800];\n const bgColor = colors[colorPalette][100];\n\n return (\n <Box\n sx={{\n display: \"flex\",\n p: \"2px 5px\",\n minWidth: \"30px\",\n maxWidth: \"200px\",\n overflow: \"hidden\",\n textOverflow: \"ellipsis\",\n color: textColor,\n bgcolor: bgColor,\n alignItems: \"center\",\n gap: \"2px\",\n borderRadius: \"8px\",\n fontSize,\n flexShrink: noCopy ? 0 : \"inherit\",\n }}\n onMouseEnter={() => {\n setIsHovered(true);\n }}\n onMouseLeave={() => {\n setIsHovered(false);\n }}\n >\n <Box\n sx={{\n overflow: \"hidden\",\n textOverflow: \"ellipsis\",\n color: grayOut ? \"gray\" : \"inherit\",\n }}\n >\n {value}\n </Box>\n\n <CopyControl\n value={value}\n noCopy={noCopy}\n grayOut={grayOut}\n isHovered={isHovered}\n onCopy={onCopy}\n />\n </Box>\n );\n}\n\ninterface CopyControlProps {\n value: string;\n grayOut?: boolean;\n noCopy?: boolean;\n isHovered: boolean;\n onCopy?: (value: string) => void;\n}\n\nfunction CopyControl({\n value,\n noCopy,\n grayOut,\n isHovered,\n onCopy,\n}: CopyControlProps): ReactNode {\n if (noCopy || grayOut || !isHovered) {\n return null;\n }\n\n const handleCopy = () => {\n if (onCopy) {\n onCopy(value);\n } else {\n // Default to navigator.clipboard if available\n if (typeof navigator !== \"undefined\" && navigator.clipboard) {\n navigator.clipboard.writeText(value);\n }\n }\n };\n\n return (\n <Tooltip title=\"Copy Value\">\n <IconButton\n aria-label=\"Copy\"\n size=\"small\"\n onClick={handleCopy}\n sx={{\n minWidth: \"0.625rem\",\n height: \"0.625rem\",\n display: \"flex\",\n alignItems: \"center\",\n justifyContent: \"center\",\n p: 0,\n color: \"inherit\",\n }}\n >\n <PiCopy size=\"0.625rem\" />\n </IconButton>\n </Tooltip>\n );\n}\n","/**\n * @file DataFrameColumnGroupHeader.tsx\n * @description Column group header component for DataGrid with pin/primary key controls\n *\n * Provides interactive column header with:\n * - Primary key indicator and toggle\n * - Pin/unpin column functionality\n * - Number column precision options menu\n */\n\nimport Box from \"@mui/material/Box\";\nimport IconButton from \"@mui/material/IconButton\";\nimport Menu from \"@mui/material/Menu\";\nimport MenuItem from \"@mui/material/MenuItem\";\nimport { type MouseEvent, useState } from \"react\";\nimport {\n VscClose,\n VscKebabVertical,\n VscKey,\n VscPin,\n VscPinned,\n} from \"react-icons/vsc\";\nimport type { ColumnRenderMode, ColumnType } from \"../../../api\";\nimport { columnPrecisionSelectOptions } from \"../../../utils/dataGrid/columnPrecisionOptions\";\n\n/**\n * Props for the DataFrameColumnGroupHeader component\n */\nexport interface DataFrameColumnGroupHeaderProps {\n /** Column name to display */\n name: string;\n /** Column diff status: 'added', 'removed', 'modified', or empty string */\n columnStatus: string;\n /** Column data type for determining available options */\n columnType: ColumnType;\n /** List of current primary key column names */\n primaryKeys?: string[];\n /** Callback when primary keys change (enables PK toggle functionality) */\n onPrimaryKeyChange?: (primaryKeys: string[]) => void;\n /** List of currently pinned column names */\n pinnedColumns?: string[];\n /** Callback when pinned columns change */\n onPinnedColumnsChange?: (pinnedColumns: string[]) => void;\n /** Callback when column render mode changes */\n onColumnsRenderModeChanged?: (col: Record<string, ColumnRenderMode>) => void;\n}\n\n/**\n * Column group header with interactive controls\n *\n * @description Renders a column header with:\n * - Primary key icon (VscKey) when column is a primary key\n * - Primary key add/remove toggle (when onPrimaryKeyChange is provided and column can be a PK)\n * - Pin/unpin toggle (when onPinnedColumnsChange is provided and column is not a PK)\n * - Precision options menu for number columns\n *\n * Uses exact string matching for primary keys and pinned columns.\n * Backend normalization ensures column names match user-specified keys.\n *\n * @example\n * ```tsx\n * // Query diff mode with PK toggle\n * <DataFrameColumnGroupHeader\n * name=\"user_id\"\n * columnStatus=\"\"\n * columnType=\"number\"\n * primaryKeys={['user_id']}\n * onPrimaryKeyChange={setPrimaryKeys}\n * pinnedColumns={[]}\n * onPinnedColumnsChange={setPinnedColumns}\n * />\n * ```\n *\n * @example\n * ```tsx\n * // Value diff mode (display-only PK indicator)\n * <DataFrameColumnGroupHeader\n * name=\"user_id\"\n * columnStatus=\"modified\"\n * columnType=\"number\"\n * primaryKeys={['user_id']}\n * pinnedColumns={[]}\n * onPinnedColumnsChange={setPinnedColumns}\n * />\n * ```\n */\nexport function DataFrameColumnGroupHeader({\n name,\n columnStatus,\n columnType,\n primaryKeys = [],\n onPrimaryKeyChange,\n pinnedColumns = [],\n onPinnedColumnsChange,\n onColumnsRenderModeChanged,\n}: DataFrameColumnGroupHeaderProps) {\n const [anchorEl, setAnchorEl] = useState<null | HTMLElement>(null);\n const menuOpen = Boolean(anchorEl);\n\n const handleMenuClick = (event: MouseEvent<HTMLElement>) => {\n setAnchorEl(event.currentTarget);\n };\n\n const handleMenuClose = () => {\n setAnchorEl(null);\n };\n\n // Skip rendering for index column\n if (name === \"index\") {\n return <></>;\n }\n\n // Determine if column is a primary key or pinned (exact matching)\n const isPK = primaryKeys.includes(name);\n const isPinned = pinnedColumns.includes(name);\n\n // Column can be a PK only if it's not added/removed (for diff scenarios)\n const canBePk = columnStatus !== \"added\" && columnStatus !== \"removed\";\n\n // Build precision options for number columns\n let selectOptions: { value: string; onClick: () => void }[] = [];\n if (onColumnsRenderModeChanged) {\n selectOptions = columnPrecisionSelectOptions(\n name,\n onColumnsRenderModeChanged,\n );\n }\n\n // Primary key handlers\n const handleRemovePk = () => {\n if (!onPrimaryKeyChange) return;\n const newPrimaryKeys = primaryKeys.filter((item) => item !== name);\n onPrimaryKeyChange(newPrimaryKeys);\n };\n\n const handleAddPk = () => {\n if (!onPrimaryKeyChange) return;\n const newPrimaryKeys = [\n ...primaryKeys.filter((item) => item !== \"index\"),\n name,\n ];\n onPrimaryKeyChange(newPrimaryKeys);\n };\n\n // Pin/unpin handlers\n const handleUnpin = () => {\n if (!onPinnedColumnsChange) return;\n const newPinnedColumns = pinnedColumns.filter((item) => item !== name);\n onPinnedColumnsChange(newPinnedColumns);\n };\n\n const handlePin = () => {\n if (!onPinnedColumnsChange) return;\n const newPinnedColumns = [...pinnedColumns, name];\n onPinnedColumnsChange(newPinnedColumns);\n };\n\n return (\n <Box\n sx={{ display: \"flex\", alignItems: \"center\", gap: \"10px\", width: \"100%\" }}\n className=\"grid-header\"\n >\n {/* Primary key icon */}\n {isPK && <VscKey />}\n\n {/* Column name */}\n <Box\n sx={{\n flex: 1,\n overflow: \"hidden\",\n textOverflow: \"ellipsis\",\n whiteSpace: \"nowrap\",\n }}\n >\n {name}\n </Box>\n\n {/* Primary key toggle (only when onPrimaryKeyChange is provided) */}\n {canBePk && onPrimaryKeyChange && (\n <Box\n component={isPK ? VscClose : VscKey}\n className={isPK ? \"close-icon\" : \"key-icon\"}\n sx={{\n display: isPK ? \"block\" : \"none\",\n cursor: \"pointer\",\n }}\n onClick={isPK ? handleRemovePk : handleAddPk}\n />\n )}\n\n {/* Pin/unpin toggle (only for non-PK columns when callback is provided) */}\n {!isPK && onPinnedColumnsChange && (\n <Box\n component={isPinned ? VscPinned : VscPin}\n className={isPinned ? \"unpin-icon\" : \"pin-icon\"}\n sx={{\n display: isPinned ? \"block\" : \"none\",\n cursor: \"pointer\",\n }}\n onClick={isPinned ? handleUnpin : handlePin}\n />\n )}\n\n {/* Precision menu for number columns (only for non-PK columns) */}\n {!isPK && columnType === \"number\" && selectOptions.length > 0 && (\n <>\n <IconButton\n aria-label=\"Options\"\n size=\"small\"\n className=\"!size-4 !min-w-4\"\n onClick={handleMenuClick}\n >\n <VscKebabVertical />\n </IconButton>\n <Menu anchorEl={anchorEl} open={menuOpen} onClose={handleMenuClose}>\n {selectOptions.map((o) => (\n <MenuItem\n key={o.value}\n onClick={() => {\n o.onClick();\n handleMenuClose();\n }}\n >\n {o.value}\n </MenuItem>\n ))}\n </Menu>\n </>\n )}\n </Box>\n );\n}\n","/**\n * @file DataFrameColumnHeader.tsx\n * @description Column header component for standard DataGrid columns\n *\n * Provides interactive column header with:\n * - Pin/unpin column functionality\n * - Number column precision options menu\n */\n\nimport Box from \"@mui/material/Box\";\nimport IconButton from \"@mui/material/IconButton\";\nimport Menu from \"@mui/material/Menu\";\nimport MenuItem from \"@mui/material/MenuItem\";\nimport { type MouseEvent, useState } from \"react\";\nimport { PiDotsThreeVertical } from \"react-icons/pi\";\nimport { VscPin, VscPinned } from \"react-icons/vsc\";\nimport type { ColumnRenderMode, ColumnType } from \"../../../api\";\nimport { columnPrecisionSelectOptions } from \"../../../utils/dataGrid/columnPrecisionOptions\";\n\n/**\n * Props for the DataFrameColumnHeader component\n */\nexport interface DataFrameColumnHeaderProps {\n /** Column name to display */\n name: string;\n /** Column data type for determining available options */\n columnType: ColumnType;\n /** List of currently pinned column names */\n pinnedColumns?: string[];\n /** Callback when pinned columns change */\n onPinnedColumnsChange?: (pinnedColumns: string[]) => void;\n /** Callback when column render mode changes */\n onColumnsRenderModeChanged?: (col: Record<string, ColumnRenderMode>) => void;\n}\n\n/**\n * Column header with interactive controls for standard columns\n *\n * @description Renders a column header with:\n * - Pin/unpin toggle (when onPinnedColumnsChange is provided)\n * - Precision options menu for number columns\n *\n * @example\n * ```tsx\n * <DataFrameColumnHeader\n * name=\"price\"\n * columnType=\"number\"\n * pinnedColumns={['id']}\n * onPinnedColumnsChange={setPinnedColumns}\n * onColumnsRenderModeChanged={setRenderModes}\n * />\n * ```\n */\nexport function DataFrameColumnHeader({\n name,\n pinnedColumns = [],\n onPinnedColumnsChange = () => {\n return void 0;\n },\n columnType,\n onColumnsRenderModeChanged,\n}: DataFrameColumnHeaderProps) {\n const [anchorEl, setAnchorEl] = useState<null | HTMLElement>(null);\n const menuOpen = Boolean(anchorEl);\n\n const handleMenuClick = (event: MouseEvent<HTMLElement>) => {\n setAnchorEl(event.currentTarget);\n };\n\n const handleMenuClose = () => {\n setAnchorEl(null);\n };\n\n let selectOptions: { value: string; onClick: () => void }[] = [];\n if (onColumnsRenderModeChanged) {\n selectOptions = columnPrecisionSelectOptions(\n name,\n onColumnsRenderModeChanged,\n );\n }\n\n const isPinned = pinnedColumns.includes(name);\n\n const handleUnpin = () => {\n const newPinnedColumns = pinnedColumns.filter((item) => item !== name);\n onPinnedColumnsChange(newPinnedColumns);\n };\n\n const handlePin = () => {\n const newPinnedColumns = [...pinnedColumns, name];\n onPinnedColumnsChange(newPinnedColumns);\n };\n\n return (\n <Box\n sx={{ display: \"flex\", alignItems: \"center\", width: \"100%\" }}\n className=\"grid-header\"\n >\n <Box sx={{ flex: 1 }}>{name}</Box>\n\n <Box\n component={isPinned ? VscPinned : VscPin}\n className={isPinned ? \"unpin-icon\" : \"pin-icon\"}\n sx={{\n display: isPinned ? \"block\" : \"none\",\n cursor: \"pointer\",\n }}\n onClick={isPinned ? handleUnpin : handlePin}\n />\n {columnType === \"number\" && (\n <>\n <IconButton\n aria-label=\"Options\"\n size=\"small\"\n className=\"size-6!\"\n sx={{\n p: 0,\n }}\n onClick={handleMenuClick}\n >\n <PiDotsThreeVertical />\n </IconButton>\n <Menu anchorEl={anchorEl} open={menuOpen} onClose={handleMenuClose}>\n {selectOptions.map((o) => (\n <MenuItem\n key={o.value}\n onClick={() => {\n o.onClick();\n handleMenuClose();\n }}\n >\n {o.value}\n </MenuItem>\n ))}\n </Menu>\n </>\n )}\n </Box>\n );\n}\n","/**\n * @file transforms.ts\n * @description Data transformation utilities for DataFrame and row objects\n *\n * Provides utilities for:\n * - Converting DataFrames to row objects\n * - Case-insensitive property access\n * - String to number conversions with hashing\n */\n\nimport type { DataFrame, RowDataTypes, RowObjectType } from \"../api\";\n\n/**\n * Converts a DataFrame to an array of row objects.\n *\n * Each row becomes an object with column keys as properties,\n * plus __status (undefined) and _index (1-based) fields.\n *\n * @param dataFrame - The DataFrame to convert\n * @returns Array of row objects with column values and metadata\n *\n * @example\n * ```ts\n * const df = {\n * columns: [{ key: 'name' }, { key: 'age' }],\n * data: [['Alice', 30], ['Bob', 25]]\n * };\n * const rows = dataFrameToRowObjects(df);\n * // [\n * // { name: 'Alice', age: 30, __status: undefined, _index: 1 },\n * // { name: 'Bob', age: 25, __status: undefined, _index: 2 }\n * // ]\n * ```\n */\nexport function dataFrameToRowObjects(dataFrame: DataFrame): RowObjectType[] {\n return dataFrame.data.map((row, index) => ({\n ...dataFrame.columns.reduce<Record<string, RowDataTypes>>(\n (obj, column, colIndex) => {\n obj[column.key] = row[colIndex];\n return obj;\n },\n {},\n ),\n __status: undefined,\n _index: index + 1,\n }));\n}\n\n/**\n * Converts a key string to a number.\n *\n * If the key is a valid number, it is parsed and returned.\n * Otherwise, the string is hashed to a stable numeric value.\n *\n * @param key - The key to convert\n * @returns A numeric representation of the key\n *\n * @example\n * ```ts\n * keyToNumber('123') // 123\n * keyToNumber('abc') // stable hash value\n * keyToNumber('-45.6') // -45.6\n * ```\n */\nexport function keyToNumber(key: string): number {\n // Try to parse as a number first\n const parsed = Number(key);\n\n // Check if it's a valid number (not NaN, not Infinity)\n if (!Number.isNaN(parsed) && Number.isFinite(parsed)) {\n return parsed;\n }\n\n // If not a number, hash the string to a stable numeric value\n return hashStringToNumber(key);\n}\n\n/**\n * Hashes a string to a stable numeric value.\n *\n * Uses a simple hash algorithm based on Java's String.hashCode().\n * Always returns a non-negative integer.\n *\n * @param str - The string to hash\n * @returns A non-negative integer hash value\n *\n * @example\n * ```ts\n * hashStringToNumber('hello') // same value every time\n * hashStringToNumber('') // 0\n * ```\n */\nexport function hashStringToNumber(str: string): number {\n let hash = 0;\n\n for (let i = 0; i < str.length; i++) {\n const char = str.charCodeAt(i);\n hash = (hash << 5) - hash + char;\n hash = hash & hash; // Convert to 32-bit integer\n }\n\n // Return absolute value to ensure positive numbers\n return Math.abs(hash);\n}\n\n/**\n * Gets a property value from an object using case-insensitive key matching.\n *\n * First tries lowercase match, then falls back to case-insensitive search.\n *\n * @param obj - The object to search\n * @param key - The property key (case-insensitive)\n * @returns The property value, or undefined if not found\n *\n * @example\n * ```ts\n * const obj = { Name: 'Alice', AGE: 30 };\n * getCaseInsensitive(obj, 'name') // 'Alice'\n * getCaseInsensitive(obj, 'age') // 30\n * getCaseInsensitive(obj, 'foo') // undefined\n * ```\n */\nexport function getCaseInsensitive<T extends RowObjectType>(\n obj: T,\n key: string,\n): T[keyof T] | undefined {\n const lowerKey = key.toLowerCase();\n\n // First try lowercase\n if (lowerKey in obj) {\n return obj[lowerKey as keyof T];\n }\n\n // Fall back to case-insensitive search\n const foundKey = Object.keys(obj).find((k) => k.toLowerCase() === lowerKey) as\n | keyof T\n | undefined;\n\n return foundKey ? obj[foundKey] : undefined;\n}\n\n/**\n * Gets a value from an object at a given path, with case-insensitive matching.\n *\n * Tries lowercase, then uppercase, then exact match.\n *\n * @param obj - The object to search\n * @param path - The property path (case-insensitive)\n * @returns The value at the path, or undefined if not found\n *\n * @example\n * ```ts\n * const obj = { Name: 'Alice', AGE: 30 };\n * getValueAtPath(obj, 'name') // 'Alice'\n * getValueAtPath(obj, 'AGE') // 30\n * getValueAtPath(obj, 'foo') // undefined\n * ```\n */\nexport function getValueAtPath<T = RowDataTypes>(\n obj: Record<string, T | undefined>,\n path: string,\n): T | undefined {\n let col = obj[path.toLowerCase()];\n if (!col) {\n // try upper-case match\n col = obj[path.toUpperCase()];\n }\n if (!col) {\n // try fallback with strict casing match\n col = obj[path];\n }\n return col;\n}\n","/**\n * \"Formatters\" -- these are your data formatting that returns a formatted value for UI presentation (e.g. number, string, falsey)\n */\n\n/**\n *\n * @param num number type input\n * @param locales locale string\n * @param options\n * @returns a formatted string number, based on locale & options\n */\nexport function formatNumber(\n num: number | string | undefined,\n locales = \"en-US\",\n options?: Intl.NumberFormatOptions,\n) {\n if (typeof num !== \"number\") return num;\n return new Intl.NumberFormat(locales, options).format(num);\n}\n\n/**\n * @param num fractional number type input\n * @returns a formatted percentage string, based on its percentage proximity to either ends (<0.1% and >99.9%)\n */\nexport function formatIntervalMinMax(num: number) {\n // * should show <0.1 % if the value is between (0%, 0.1%]\n const isLowerBound = num > 0 && num <= 0.001;\n // * should show >99.9% if the value is between [99.9%, 100%) .\n const isUpperBound = num < 1 && num >= 0.999;\n\n const formatter = (newArg = num) =>\n formatNumber(newArg, \"en-US\", {\n style: \"percent\",\n minimumFractionDigits: 1,\n });\n\n if (isLowerBound) {\n const result = formatter(0.001);\n return `<${result}`;\n } else if (isUpperBound) {\n const result = formatter(0.999);\n return `>${result}`;\n }\n return formatter();\n}\n\n/**\n * base < -2 => 2dp, scientific (small decimals)\n * base < 0 => 3dp (big decimals)\n * base < 3 => 2dp (ones, tens, hundreds)\n * base < 6 => 1dp, K (thousands)\n * base < 9 => 1dp, M (millions)\n * base < 12 => 1dp, T (trillions)\n * base < 15 => 1dp, B (billions)\n * base >= 15 => 0dp, B (billions)\n * @param input\n * @returns a formatted number by abbreviation, based on its order of magnitude\n */\nexport function formatAsAbbreviatedNumber(input: number | string) {\n // type guard for numbers (e.g. datetime strings)\n if (typeof input !== \"number\") return input;\n else {\n // convert negatives\n const inputAsPositive = Math.abs(input);\n\n const twoDecimal = 10 ** -2;\n const thousand = 10 ** 3;\n const million = 10 ** 6;\n const billion = 10 ** 9;\n const trillion = 10 ** 12;\n const trillionPlus = 10 ** 15;\n\n const isLargeFractionals = inputAsPositive >= twoDecimal;\n const isOnesTensHundreds = inputAsPositive >= 1;\n const isThousands = inputAsPositive >= thousand;\n const isMillions = inputAsPositive >= million;\n const isBillions = inputAsPositive >= billion;\n const isSmallTrillions = inputAsPositive >= trillion;\n const isLargeTrillions = inputAsPositive >= trillionPlus;\n\n // format as 'T' and beyond (trillions+)\n if (isLargeTrillions || isSmallTrillions)\n return new Intl.NumberFormat(\"en-US\", {\n style: \"unit\",\n unit: \"liter\", //just a placeholder\n unitDisplay: \"narrow\",\n maximumFractionDigits: isLargeTrillions ? 0 : 2,\n })\n .format(input / 1.0e12)\n .replace(\"L\", \"T\");\n // format as 'B', 'M', 'K' (billions to thousands)\n else if (isBillions || isMillions || isThousands) {\n const lookup = {\n base: isBillions ? billion : isMillions ? million : thousand,\n unit: isBillions ? \"B\" : isMillions ? \"M\" : \"K\",\n };\n return new Intl.NumberFormat(\"en-US\", {\n style: \"unit\",\n unit: \"liter\", //just a placeholder\n unitDisplay: \"narrow\",\n maximumFractionDigits: 1,\n })\n .format(input / lookup.base)\n .replace(\"L\", lookup.unit);\n }\n // format as unlabeled (1 to 999)\n else if (isOnesTensHundreds)\n return new Intl.NumberFormat(\"en-US\", {\n maximumFractionDigits: 2,\n }).format(input);\n // format as fractionals (< 1)\n else\n return new Intl.NumberFormat(\"en-US\", {\n maximumFractionDigits: isLargeFractionals ? 3 : 2,\n notation:\n isLargeFractionals || inputAsPositive === 0\n ? \"standard\"\n : \"scientific\",\n }).format(input);\n }\n}\n","/**\n * @file mergeKeys.ts\n * @description Utilities for merging column arrays while detecting renames/additions/removals\n */\n\n/**\n * Merge keys from base and current tables.\n * Unlike default union, it preserves the order for column rename, added, removed cases.\n */\nexport function mergeKeys(_base: string[], _curr: string[]): string[] {\n // Merge keys from base, target tables. Unlike default union, it preserves the order for column rename, added, removed.\n const base = [..._base];\n const curr = [..._curr];\n\n const results: string[] = [];\n while (base.length > 0 && curr.length > 0) {\n if (results.includes(base[0])) {\n base.shift();\n } else if (results.includes(curr[0])) {\n curr.shift();\n } else if (base[0] === curr[0]) {\n results.push(base[0]);\n base.shift();\n curr.shift();\n } else if (curr.includes(base[0])) {\n const idx = curr.indexOf(base[0]);\n for (let i = 0; i < idx; i++) {\n if (!results.includes(curr[i])) {\n results.push(curr[i]);\n }\n }\n results.push(base[0]);\n base.shift();\n curr.splice(0, idx + 1);\n } else {\n results.push(base[0]);\n base.shift();\n }\n }\n\n base.forEach((key) => {\n if (!results.includes(key)) {\n results.push(key);\n }\n });\n\n curr.forEach((key) => {\n if (!results.includes(key)) {\n results.push(key);\n }\n });\n\n return results;\n}\n\nexport type MergeStatus = \"added\" | \"removed\" | \"reordered\" | undefined;\n\n/**\n * Merge keys from base and current tables, returning status for each key.\n * Status indicates whether the key was added, removed, reordered, or unchanged.\n */\nexport function mergeKeysWithStatus(\n _base: string[],\n _curr: string[],\n): Record<string, MergeStatus> {\n const merged = mergeKeys(_base, _curr);\n const result: ReturnType<typeof mergeKeysWithStatus> = {};\n\n for (const item of merged) {\n if (!_base.includes(item)) {\n result[item] = \"added\";\n } else if (!_curr.includes(item)) {\n result[item] = \"removed\";\n } else {\n result[item] = undefined;\n }\n }\n\n // reorder case\n const baseIndexMap: Record<string, number | undefined> = {};\n _base.forEach((item, index) => {\n baseIndexMap[item] = index;\n });\n let last = -1;\n for (const item of merged) {\n const curr = baseIndexMap[item];\n if (curr == null) {\n continue;\n }\n\n if (curr > last) {\n last = curr;\n } else {\n result[item] = \"reordered\";\n }\n }\n\n return result;\n}\n","/**\n * @file gridUtils.ts\n * @description Shared utilities for data grid generation\n *\n * This module contains common functions used across all grid generation methods.\n */\n\nimport _ from \"lodash\";\nimport type {\n ColumnRenderMode,\n ColumnType,\n DataFrame,\n RowObjectType,\n} from \"../../api/types\";\nimport { formatNumber } from \"../formatters\";\nimport { mergeKeysWithStatus } from \"../mergeKeys\";\nimport { getCaseInsensitive } from \"../transforms\";\n\n// ============================================================================\n// Types\n// ============================================================================\n\nexport interface ColumnMapEntry {\n key: string;\n colType: ColumnType;\n status?: string;\n index?: number;\n}\n\nexport interface MergeColumnMapEntry extends ColumnMapEntry {\n baseColumnKey: string;\n currentColumnKey: string;\n}\n\nexport interface RowStats {\n added: number;\n removed: number;\n modified: number;\n}\n\n// ============================================================================\n// Column Map Builders\n// ============================================================================\n\n/**\n * Builds a column map from a single DataFrame\n */\nexport function buildColumnMap(df: DataFrame): Record<string, ColumnMapEntry> {\n const result: Record<string, ColumnMapEntry> = {};\n df.columns.forEach((col, index) => {\n result[col.name] = {\n key: col.key,\n index,\n colType: col.type,\n };\n });\n return result;\n}\n\n/**\n * Builds a column map for joined data (with in_a/in_b columns)\n *\n * NOTE: Backend now guarantees in_a/in_b are always lowercase,\n * so we only need to register them as-is.\n *\n * @throws {Error} If required in_a or in_b columns are missing\n */\nexport function buildJoinedColumnMap(\n df: DataFrame,\n): Record<string, ColumnMapEntry> {\n const result: Record<string, ColumnMapEntry> = {};\n\n df.columns.forEach((col, index) => {\n result[col.key] = {\n key: col.key,\n index,\n colType: col.type,\n };\n });\n\n // Verify required columns exist (while backend guarantees \"in_a\" and \"in_b\" as lowercase, we need to verify their presence)\n if (!result.in_a) {\n throw new Error(\"Joined DataFrame missing required 'in_a' column\");\n }\n if (!result.in_b) {\n throw new Error(\"Joined DataFrame missing required 'in_b' column\");\n }\n\n return result;\n}\n\n/**\n * Builds a merged column map from two DataFrames\n * Tracks status (added/removed/unchanged) for each column\n */\nexport function buildMergedColumnMap(\n base: DataFrame,\n current: DataFrame,\n): Record<string, MergeColumnMapEntry> {\n const result: Record<string, MergeColumnMapEntry> = {};\n\n const mapStatus = mergeKeysWithStatus(\n base.columns.map((col) => col.key),\n current.columns.map((col) => col.key),\n ) as Record<string, string>;\n\n Object.entries(mapStatus).forEach(([key, status]) => {\n const baseColumn = base.columns.find((c) => c.key === key);\n const currentColumn = current.columns.find((c) => c.key === key);\n result[key] = {\n status,\n baseColumnKey: baseColumn?.key ?? \"unknown\",\n currentColumnKey: currentColumn?.key ?? \"unknown\",\n colType: baseColumn?.type ?? currentColumn?.type ?? \"unknown\",\n key: baseColumn?.key ?? currentColumn?.key ?? \"unknown\",\n };\n });\n\n return result;\n}\n\n// ============================================================================\n// Primary Key Utilities\n// ============================================================================\n\n/**\n * Validates that all primary keys exist in the columns (exact matching)\n */\nexport function validatePrimaryKeys(\n columns: DataFrame[\"columns\"],\n primaryKeys: string[],\n): string[] {\n const keys: string[] = [];\n for (const key of primaryKeys) {\n const found = columns.find((col) => col.key === key);\n\n if (!found) {\n throw new Error(`Column ${key} not found`);\n }\n keys.push(found.key);\n }\n return keys;\n}\n\n/**\n * Generates a unique key string from primary key values in a row (exact matching)\n */\nexport function getPrimaryKeyValue(\n columns: DataFrame[\"columns\"],\n primaryKeys: string[],\n row: RowObjectType,\n): string {\n if (primaryKeys.length === 0) {\n return String(row._index);\n }\n\n const result: string[] = [];\n for (const key of primaryKeys) {\n const col = columns.find((c) => c.key === key);\n\n if (!col) {\n throw new Error(`Primary Column ${key} not found`);\n }\n\n const value = row[key];\n result.push(`${col.name}=${value}`);\n }\n return result.join(\"|\");\n}\n\n// ============================================================================\n// Row Status Detection\n// ============================================================================\n\n/**\n * Determines the status of a row (added/removed/modified/unchanged)\n *\n * Supports two modes:\n * 1. Separate rows: baseRow and currentRow are different objects\n * 2. Merged rows: baseRow === currentRow, with values stored as base__key and current__key\n */\nexport function determineRowStatus(\n baseRow: RowObjectType | undefined,\n currentRow: RowObjectType | undefined,\n columnMap: Record<string, ColumnMapEntry>,\n primaryKeys: string[],\n): \"added\" | \"removed\" | \"modified\" | undefined {\n if (!baseRow) return \"added\";\n if (!currentRow) return \"removed\";\n\n // Check if this is a merged row (same object passed for both)\n const isMergedRow = baseRow === currentRow;\n\n // Check for modifications in non-PK columns\n for (const [name, column] of Object.entries(columnMap)) {\n if (name === \"index\") continue;\n\n if (primaryKeys.includes(name)) continue;\n\n let baseVal: unknown;\n let currentVal: unknown;\n\n if (isMergedRow) {\n // Merged row: compare base__key vs current__key\n const baseKey = `base__${column.key}`;\n const currentKey = `current__${column.key}`;\n baseVal = baseRow[baseKey];\n currentVal = currentRow[currentKey];\n } else {\n // Separate rows: compare same key in different row objects\n baseVal = baseRow[column.key];\n currentVal = currentRow[column.key];\n }\n\n if (!_.isEqual(baseVal, currentVal)) {\n return \"modified\";\n }\n }\n\n return undefined;\n}\n\n// ============================================================================\n// Value Rendering Utilities\n// ============================================================================\n\n/**\n * Formats a numeric value based on render mode\n *\n * Handles special values:\n * - NaN: Returns \"NaN\" (no formatting applied)\n * - Infinity: Returns \"∞\" or \"-∞\" (no formatting applied)\n */\n/**\n * Formats a number with up to maxDecimals decimal places, without trailing zeros\n * Uses banker's rounding (round half to even) for unbiased rounding.\n *\n * e.g., formatSmartDecimal(123, 2) => \"123\"\n * formatSmartDecimal(123.4, 2) => \"123.4\"\n * formatSmartDecimal(123.456, 2) => \"123.46\"\n * formatSmartDecimal(123.445, 2) => \"123.44\" (banker's rounding)\n */\nexport function formatSmartDecimal(value: number, maxDecimals = 2): string {\n // Normalize -0 to 0 (Intl.NumberFormat renders -0 as \"-0\" per ECMA-402)\n const normalizedValue = Object.is(value, -0) ? 0 : value;\n\n const result =\n formatNumber(normalizedValue, \"en-US\", {\n maximumFractionDigits: maxDecimals,\n roundingMode: \"halfEven\",\n } as Intl.NumberFormatOptions) ?? String(value);\n\n // Normalize \"-0\" to \"0\" (can happen when small negative numbers round to zero)\n return result === \"-0\" ? \"0\" : result;\n}\n\nexport function columnRenderedValue(\n value: number,\n renderMode?: ColumnRenderMode,\n): string {\n // Handle special numeric values first\n if (Number.isNaN(value)) {\n return \"NaN\";\n }\n\n if (!Number.isFinite(value)) {\n return value > 0 ? \"∞\" : \"-∞\";\n }\n\n const locale = \"en-US\";\n\n if (renderMode === \"raw\") {\n return String(value);\n }\n\n if (typeof renderMode === \"number\") {\n // Smart formatting: up to N decimals, no trailing zeros\n return formatSmartDecimal(value, renderMode);\n }\n\n if (renderMode === \"percent\") {\n return (\n formatNumber(value, locale, {\n style: \"percent\",\n maximumFractionDigits: 2,\n }) ?? String(value)\n );\n }\n\n // Default: smart 2-decimal formatting\n return formatSmartDecimal(value, 2);\n}\n\n/**\n * Converts a row value to a rendered string with gray-out indicator\n */\nexport function toRenderedValue(\n row: RowObjectType,\n key: string,\n columnType?: ColumnType,\n columnRenderMode?: ColumnRenderMode,\n): [string, boolean] {\n const value = getCaseInsensitive(row, key);\n\n if (value == null) {\n return [\"-\", true];\n }\n\n let renderedValue: string;\n let grayOut = false;\n\n // noinspection SuspiciousTypeOfGuard\n if (typeof value === \"boolean\") {\n // workaround for https://github.com/adazzle/react-data-grid/issues/882\n renderedValue = value.toString();\n } else if (value === \"\") {\n renderedValue = \"(empty)\";\n grayOut = true;\n } else if (typeof value === \"number\") {\n renderedValue = columnRenderedValue(value, columnRenderMode);\n } else {\n if (columnType === \"number\") {\n renderedValue = columnRenderedValue(parseFloat(value), columnRenderMode);\n } else {\n renderedValue = String(value);\n }\n }\n\n return [renderedValue, grayOut];\n}\n\n// ============================================================================\n// Cell Class Utilities\n// ============================================================================\n\n/**\n * Gets the CSS class for a cell based on row and column status\n */\nexport function getCellClass(\n row: RowObjectType,\n columnStatus: string | undefined,\n columnKey: string,\n isBase: boolean,\n): string | undefined {\n const rowStatus = row.__status;\n\n if (rowStatus === \"removed\") return \"diff-cell-removed\";\n if (rowStatus === \"added\") return \"diff-cell-added\";\n if (columnStatus === \"added\" || columnStatus === \"removed\") return undefined;\n\n const baseKey = `base__${columnKey}`.toLowerCase();\n const currentKey = `current__${columnKey}`.toLowerCase();\n\n if (!_.isEqual(row[baseKey], row[currentKey])) {\n return isBase ? \"diff-cell-removed\" : \"diff-cell-added\";\n }\n\n return undefined;\n}\n\n/**\n * Gets the CSS class for a header cell based on column status\n */\nexport function getHeaderCellClass(\n columnStatus: string | undefined,\n): string | undefined {\n if (columnStatus === \"added\") return \"diff-header-added\";\n if (columnStatus === \"removed\") return \"diff-header-removed\";\n return undefined;\n}\n","/**\n * @file defaultRenderCell.tsx\n * @description Default cell renderer for DataGrid columns\n *\n * Renders a cell value with optional column type formatting and gray-out styling.\n * Used for standard (non-diff) cell rendering in data grids.\n */\n\nimport Typography from \"@mui/material/Typography\";\nimport type { ColDef, ICellRendererParams } from \"ag-grid-community\";\nimport type { ColumnRenderMode, ColumnType, RowObjectType } from \"../../../api\";\nimport { toRenderedValue } from \"../../../utils/dataGrid/gridUtils\";\n\n/**\n * Custom context data for Recce columns\n * Stored in colDef.context to avoid AG Grid validation warnings\n */\nexport interface RecceColumnContext {\n columnType?: ColumnType;\n columnRenderMode?: ColumnRenderMode;\n}\n\n/**\n * Extended column definition with context metadata\n * Uses context property for custom data per AG Grid best practices\n */\nexport type ColDefWithMetadata<TData = RowObjectType> = ColDef<TData> & {\n context?: RecceColumnContext;\n};\n\n/**\n * Default cell renderer for data grid columns\n *\n * @description Extracts cell value from the row and renders it with appropriate\n * formatting based on the column type and render mode. Supports numeric\n * formatting (raw, integer, percent) and handles null/empty values with gray styling.\n *\n * @param params - AG Grid cell renderer params containing row data and column definition\n * @returns Rendered cell content as a Typography component\n *\n * @example\n * ```tsx\n * const colDef: ColDefWithMetadata = {\n * field: 'price',\n * cellRenderer: defaultRenderCell,\n * context: {\n * columnType: 'number',\n * columnRenderMode: 2, // 2 decimal places\n * },\n * };\n * ```\n */\nexport const defaultRenderCell = (\n params: ICellRendererParams<RowObjectType>,\n) => {\n const colDef = params.colDef as ColDefWithMetadata;\n const columnType = colDef?.context?.columnType;\n const columnRenderMode = colDef?.context?.columnRenderMode;\n const fieldName = colDef?.field ?? \"\";\n\n if (!params.data) {\n return null;\n }\n\n const [renderedValue, grayOut] = toRenderedValue(\n params.data,\n fieldName,\n columnType,\n columnRenderMode,\n );\n\n return (\n <Typography\n component=\"span\"\n style={{ color: grayOut ? \"gray\" : \"inherit\" }}\n >\n {renderedValue}\n </Typography>\n );\n};\n","\"use client\";\n\nimport Alert from \"@mui/material/Alert\";\nimport CircularProgress from \"@mui/material/CircularProgress\";\nimport Snackbar from \"@mui/material/Snackbar\";\nimport Stack from \"@mui/material/Stack\";\nimport Typography from \"@mui/material/Typography\";\nimport {\n createContext,\n type ReactNode,\n useCallback,\n useContext,\n useState,\n} from \"react\";\n\n/**\n * Toast types and interfaces\n */\nexport interface ToastOptions {\n id?: string;\n title?: string;\n description?: ReactNode;\n type?: \"success\" | \"error\" | \"warning\" | \"info\" | \"loading\";\n duration?: number;\n closable?: boolean;\n action?: {\n label: string;\n onClick: () => void;\n };\n}\n\ninterface ToastState extends ToastOptions {\n id: string;\n open: boolean;\n}\n\ninterface ToasterContextValue {\n toast: (options: ToastOptions) => string;\n success: (options: Omit<ToastOptions, \"type\">) => string;\n error: (options: Omit<ToastOptions, \"type\">) => string;\n warning: (options: Omit<ToastOptions, \"type\">) => string;\n info: (options: Omit<ToastOptions, \"type\">) => string;\n loading: (options: Omit<ToastOptions, \"type\">) => string;\n dismiss: (id: string) => void;\n update: (id: string, options: Partial<ToastOptions>) => void;\n}\n\nconst ToasterContext = createContext<ToasterContextValue | null>(null);\n\nlet toastIdCounter = 0;\n\n/**\n * Simple toaster implementation using MUI Snackbar\n */\nexport function ToasterProvider({ children }: { children: ReactNode }) {\n const [toasts, setToasts] = useState<ToastState[]>([]);\n\n const createToast = useCallback((options: ToastOptions): string => {\n const id = options.id || `toast-${++toastIdCounter}`;\n const newToast: ToastState = {\n id,\n open: true,\n duration: options.type === \"loading\" ? null : (options.duration ?? 5000),\n closable: options.closable ?? true,\n ...options,\n } as ToastState;\n\n setToasts((prev) => {\n // Remove existing toast with same id\n const filtered = prev.filter((t) => t.id !== id);\n return [...filtered, newToast];\n });\n\n return id;\n }, []);\n\n const dismiss = useCallback((id: string) => {\n setToasts((prev) =>\n prev.map((t) => (t.id === id ? { ...t, open: false } : t)),\n );\n // Remove after animation\n setTimeout(() => {\n setToasts((prev) => prev.filter((t) => t.id !== id));\n }, 300);\n }, []);\n\n const update = useCallback((id: string, options: Partial<ToastOptions>) => {\n setToasts((prev) =>\n prev.map((t) => (t.id === id ? { ...t, ...options } : t)),\n );\n }, []);\n\n const contextValue: ToasterContextValue = {\n toast: createToast,\n success: (opts) => createToast({ ...opts, type: \"success\" }),\n error: (opts) => createToast({ ...opts, type: \"error\" }),\n warning: (opts) => createToast({ ...opts, type: \"warning\" }),\n info: (opts) => createToast({ ...opts, type: \"info\" }),\n loading: (opts) => createToast({ ...opts, type: \"loading\" }),\n dismiss,\n update,\n };\n\n return (\n <ToasterContext.Provider value={contextValue}>\n {children}\n {toasts.map((toast) => (\n <Snackbar\n key={toast.id}\n open={toast.open}\n autoHideDuration={toast.duration}\n onClose={() => toast.closable && dismiss(toast.id)}\n anchorOrigin={{ vertical: \"bottom\", horizontal: \"right\" }}\n >\n <Alert\n severity={toast.type === \"loading\" ? \"info\" : toast.type || \"info\"}\n onClose={toast.closable ? () => dismiss(toast.id) : undefined}\n icon={\n toast.type === \"loading\" ? (\n <CircularProgress size={20} color=\"inherit\" />\n ) : undefined\n }\n sx={{ width: \"100%\", minWidth: 300 }}\n >\n <Stack spacing={0.5}>\n {toast.title && (\n <Typography variant=\"subtitle2\" fontWeight=\"bold\">\n {toast.title}\n </Typography>\n )}\n {toast.description && (\n <Typography variant=\"body2\" component=\"div\">\n {toast.description}\n </Typography>\n )}\n </Stack>\n </Alert>\n </Snackbar>\n ))}\n </ToasterContext.Provider>\n );\n}\n\n/**\n * Hook to use the toaster\n */\nexport function useToaster(): ToasterContextValue {\n const context = useContext(ToasterContext);\n if (!context) {\n throw new Error(\"useToaster must be used within ToasterProvider\");\n }\n return context;\n}\n\n/**\n * Standalone toaster instance for use outside React context\n * Uses a simple event-based system\n */\ninterface ToastEvent {\n type: \"create\" | \"dismiss\" | \"update\";\n options?: ToastOptions;\n id?: string;\n}\n\nconst listeners: Set<(event: ToastEvent) => void> = new Set();\n\nexport const toaster = {\n create: (options: ToastOptions): string => {\n const id = options.id || `toast-${++toastIdCounter}`;\n listeners.forEach((listener) =>\n listener({ type: \"create\", options: { ...options, id } }),\n );\n return id;\n },\n success: (options: Omit<ToastOptions, \"type\">) =>\n toaster.create({ ...options, type: \"success\" }),\n error: (options: Omit<ToastOptions, \"type\">) =>\n toaster.create({ ...options, type: \"error\" }),\n warning: (options: Omit<ToastOptions, \"type\">) =>\n toaster.create({ ...options, type: \"warning\" }),\n info: (options: Omit<ToastOptions, \"type\">) =>\n toaster.create({ ...options, type: \"info\" }),\n loading: (options: Omit<ToastOptions, \"type\">) =>\n toaster.create({ ...options, type: \"loading\" }),\n dismiss: (id: string) => {\n listeners.forEach((listener) => listener({ type: \"dismiss\", id }));\n },\n // Alias for dismiss (for backward compatibility)\n remove: (id: string) => {\n listeners.forEach((listener) => listener({ type: \"dismiss\", id }));\n },\n update: (id: string, options: Partial<ToastOptions>) => {\n listeners.forEach((listener) => listener({ type: \"update\", id, options }));\n },\n subscribe: (listener: (event: ToastEvent) => void) => {\n listeners.add(listener);\n return () => listeners.delete(listener);\n },\n};\n\n/**\n * Toaster component that renders toasts from the standalone toaster\n */\nexport function Toaster() {\n const [toasts, setToasts] = useState<ToastState[]>([]);\n\n // Subscribe to toast events\n useState(() => {\n const unsubscribe = toaster.subscribe((event) => {\n if (event.type === \"create\" && event.options) {\n const newToast: ToastState = {\n id: event.options.id || `toast-${++toastIdCounter}`,\n open: true,\n duration:\n event.options.type === \"loading\"\n ? undefined\n : (event.options.duration ?? 5000),\n closable: event.options.closable ?? true,\n ...event.options,\n } as ToastState;\n setToasts((prev) => {\n const filtered = prev.filter((t) => t.id !== newToast.id);\n return [...filtered, newToast];\n });\n } else if (event.type === \"dismiss\" && event.id) {\n const id = event.id;\n setToasts((prev) =>\n prev.map((t) => (t.id === id ? { ...t, open: false } : t)),\n );\n setTimeout(() => {\n setToasts((prev) => prev.filter((t) => t.id !== id));\n }, 300);\n } else if (event.type === \"update\" && event.id && event.options) {\n setToasts((prev) =>\n prev.map((t) => (t.id === event.id ? { ...t, ...event.options } : t)),\n );\n }\n });\n return unsubscribe;\n });\n\n const handleClose = (id: string) => {\n setToasts((prev) =>\n prev.map((t) => (t.id === id ? { ...t, open: false } : t)),\n );\n setTimeout(() => {\n setToasts((prev) => prev.filter((t) => t.id !== id));\n }, 300);\n };\n\n return (\n <>\n {toasts.map((toast) => (\n <Snackbar\n key={toast.id}\n open={toast.open}\n autoHideDuration={toast.duration}\n onClose={() => toast.closable && handleClose(toast.id)}\n anchorOrigin={{ vertical: \"bottom\", horizontal: \"right\" }}\n >\n <Alert\n severity={toast.type === \"loading\" ? \"info\" : toast.type || \"info\"}\n onClose={toast.closable ? () => handleClose(toast.id) : undefined}\n icon={\n toast.type === \"loading\" ? (\n <CircularProgress size={20} color=\"inherit\" />\n ) : undefined\n }\n sx={{ width: \"100%\", minWidth: 300 }}\n >\n <Stack spacing={0.5}>\n {toast.title && (\n <Typography variant=\"subtitle2\" fontWeight=\"bold\">\n {toast.title}\n </Typography>\n )}\n {toast.description && (\n <Typography variant=\"body2\" component=\"div\">\n {toast.description}\n </Typography>\n )}\n </Stack>\n </Alert>\n </Snackbar>\n ))}\n </>\n );\n}\n","import { toaster } from \"../components/ui/Toaster\";\n\nexport function useClipBoardToast() {\n function successToast(message: string) {\n toaster.create({\n description: message,\n type: \"info\",\n duration: 5000,\n closable: true,\n });\n }\n\n function failToast(title: string, error: unknown) {\n toaster.create({\n title: title,\n description: String(error),\n type: \"error\",\n duration: 5000,\n closable: true,\n });\n }\n\n return {\n successToast,\n failToast,\n };\n}\n","/**\n * DiffTextWithToast - DiffText component with integrated toast notifications\n *\n * This component wraps the base DiffText and adds toast notification\n * feedback for copy-to-clipboard actions.\n */\n\nimport { useCopyToClipboard } from \"usehooks-ts\";\nimport { useClipBoardToast } from \"../../hooks/useClipBoardToast\";\nimport { DiffText, type DiffTextProps } from \"./DiffText\";\n\n// Re-export the type for consumers (without onCopy since we handle it)\nexport type DiffTextWithToastProps = Omit<DiffTextProps, \"onCopy\">;\n\n/**\n * DiffText component with automatic copy-to-clipboard toast notifications.\n *\n * This is a convenience wrapper around the base DiffText component that adds\n * the toast notification behavior. Use this when you want the \"batteries included\"\n * experience with copy feedback.\n *\n * @example\n * ```tsx\n * // Shows toast when user clicks copy icon\n * <DiffTextWithToast base=\"old value\" current=\"new value\" />\n * ```\n */\nexport function DiffTextWithToast(props: DiffTextWithToastProps) {\n const [, copyToClipboard] = useCopyToClipboard();\n const { successToast } = useClipBoardToast();\n\n const handleCopy = (value: string) => {\n copyToClipboard(value);\n successToast(`${value} copied`);\n };\n\n return <DiffText {...props} onCopy={handleCopy} />;\n}\n","/**\n * @file inlineRenderCell.tsx\n * @description Inline diff cell renderer for DataGrid columns\n *\n * Renders base and current values side-by-side when they differ,\n * or a single value when unchanged. Used for inline diff display mode.\n */\n\nimport Box from \"@mui/material/Box\";\nimport Tooltip from \"@mui/material/Tooltip\";\nimport Typography from \"@mui/material/Typography\";\nimport type { ColDef, ICellRendererParams } from \"ag-grid-community\";\nimport type { ComponentType } from \"react\";\nimport type {\n ColumnRenderMode,\n ColumnType,\n RowDataTypes,\n RowObjectType,\n} from \"../../../api\";\nimport {\n formatSmartDecimal,\n toRenderedValue,\n} from \"../../../utils/dataGrid/gridUtils\";\nimport { DiffText, type DiffTextProps } from \"../DiffText\";\nimport { DiffTextWithToast } from \"../DiffTextWithToast\";\n\n/**\n * Custom context data for Recce columns\n * Stored in colDef.context to avoid AG Grid validation warnings\n */\ninterface RecceColumnContext {\n columnType?: ColumnType;\n columnRenderMode?: ColumnRenderMode;\n}\n\n/**\n * Extended column definition with context metadata\n * Uses context property for custom data per AG Grid best practices\n */\ntype ColDefWithMetadata = ColDef<RowObjectType> & {\n context?: RecceColumnContext;\n};\n\n/**\n * Props for DiffText component used in inline rendering\n * This allows platforms to inject their own DiffText with custom behavior\n */\nexport type InlineDiffTextProps = DiffTextProps;\n\n/**\n * Configuration for creating an inline cell renderer\n */\nexport interface InlineRenderCellConfig {\n /**\n * Custom DiffText component to use for rendering diff values.\n * If not provided, uses the default DiffText from @datarecce/ui.\n * Platforms can inject their own DiffText with additional features\n * (e.g., toast notifications on copy).\n */\n DiffTextComponent?: ComponentType<InlineDiffTextProps>;\n}\n\n/**\n * Creates an inline diff cell renderer with configurable DiffText component\n *\n * @description Factory function that creates a cell renderer with an optional\n * custom DiffText component. This allows platforms to inject their own DiffText\n * implementation (e.g., with toast notifications).\n *\n * @param config - Configuration options for the renderer\n * @returns AG Grid cell renderer function\n *\n * @example\n * ```tsx\n * // Use default DiffText\n * const renderer = createInlineRenderCell();\n *\n * // Use custom DiffText with toast\n * const renderer = createInlineRenderCell({\n * DiffTextComponent: DiffTextWithToast,\n * });\n * ```\n */\nexport function createInlineRenderCell(config: InlineRenderCellConfig = {}) {\n const DiffTextComp = config.DiffTextComponent ?? DiffText;\n\n return (params: ICellRendererParams<RowObjectType>) => {\n const colDef = params.colDef as ColDefWithMetadata;\n const columnType = colDef?.context?.columnType;\n const columnRenderMode = colDef?.context?.columnRenderMode;\n const columnKey = colDef?.field ?? \"\";\n\n if (!params.data) {\n return null;\n }\n\n const row = params.data;\n const baseKey = `base__${columnKey}`.toLowerCase();\n const currentKey = `current__${columnKey}`.toLowerCase();\n\n // Handle case where neither base nor current values exist\n if (!Object.hasOwn(row, baseKey) && !Object.hasOwn(row, currentKey)) {\n return \"-\";\n }\n\n const hasBase = Object.hasOwn(row, baseKey);\n const hasCurrent = Object.hasOwn(row, currentKey);\n\n const [baseValue, baseGrayOut] = toRenderedValue(\n row,\n `base__${columnKey}`.toLowerCase(),\n columnType,\n columnRenderMode,\n );\n\n const [currentValue, currentGrayOut] = toRenderedValue(\n row,\n `current__${columnKey}`.toLowerCase(),\n columnType,\n columnRenderMode,\n );\n\n // No change - render single value\n if (row[baseKey] === row[currentKey]) {\n return (\n <Typography\n component=\"span\"\n style={{ color: currentGrayOut ? \"gray\" : \"inherit\" }}\n >\n {currentValue}\n </Typography>\n );\n }\n\n // Check if we're using delta display mode\n const isDeltaMode = columnRenderMode === \"delta\";\n\n // For delta modes, calculate the change for numeric columns\n if (\n isDeltaMode &&\n (columnType === \"number\" || columnType === \"integer\") &&\n hasBase &&\n hasCurrent\n ) {\n // Parse values to numbers (they may be strings from the API)\n const baseNum = asNumber(row[baseKey]);\n const currentNum = asNumber(row[currentKey]);\n\n // Only show delta if both values are valid numbers\n if (Number.isFinite(baseNum) && Number.isFinite(currentNum)) {\n const netChange = currentNum - baseNum;\n const changePercent = baseNum !== 0 ? (netChange / baseNum) * 100 : 0;\n\n // Format current value and delta with smart decimals (up to 2, no trailing zeros)\n const formattedCurrent = formatSmartDecimal(currentNum);\n const formattedDelta = formatSmartDecimal(netChange);\n const deltaText = `(${netChange >= 0 ? \"+\" : \"\"}${formattedDelta})`;\n\n // Build tooltip text showing full precision\n const tooltipText = `Base: ${baseNum}\\nCurrent: ${currentNum}\\nChange: ${\n netChange >= 0 ? \"+\" : \"\"\n }${netChange} (${changePercent >= 0 ? \"+\" : \"\"}${changePercent.toFixed(\n 2,\n )}%)`;\n\n return (\n <Tooltip\n title={tooltipText}\n slotProps={{\n tooltip: { sx: { whiteSpace: \"pre-line\" } },\n }}\n enterDelay={300}\n placement=\"top\"\n >\n <Box\n gap=\"5px\"\n display=\"flex\"\n alignItems=\"center\"\n lineHeight=\"normal\"\n height=\"100%\"\n >\n <DiffTextComp\n value={formattedCurrent}\n colorPalette=\"green\"\n grayOut={currentGrayOut}\n />\n <Typography\n fontSize=\"0.75rem\"\n color={netChange >= 0 ? \"green.600\" : \"red.600\"}\n >\n {deltaText}\n </Typography>\n </Box>\n </Tooltip>\n );\n }\n }\n\n // Values differ - render inline diff with base (red) and current (green)\n return (\n <Box\n sx={{\n display: \"flex\",\n gap: \"5px\",\n alignItems: \"center\",\n lineHeight: \"normal\",\n height: \"100%\",\n }}\n >\n {hasBase && (\n <DiffTextComp\n value={baseValue}\n colorPalette=\"red\"\n grayOut={baseGrayOut}\n />\n )}\n {hasCurrent && (\n <DiffTextComp\n value={currentValue}\n colorPalette=\"green\"\n grayOut={currentGrayOut}\n />\n )}\n </Box>\n );\n };\n}\n\n/**\n * Default inline diff cell renderer using DiffTextWithToast\n *\n * @description Pre-configured inline cell renderer that uses DiffTextWithToast\n * for copy-to-clipboard toast notifications. For custom DiffText behavior,\n * use createInlineRenderCell() with a custom DiffTextComponent.\n */\nexport const inlineRenderCell = createInlineRenderCell({\n DiffTextComponent: DiffTextWithToast,\n});\n\n/**\n * Converts row data values to a number\n *\n * @param data - The row data value (number, string, or other type)\n * @returns The numeric value, or 0 if conversion fails or value is not numeric\n */\nexport function asNumber(data: RowDataTypes): number {\n if (typeof data === \"number\") return data;\n if (typeof data === \"string\") {\n const n = Number.parseFloat(data);\n return Number.isNaN(n) ? 0 : n;\n }\n return 0;\n}\n","/**\n * @file toDiffColumn.tsx\n * @description Shared column builder for diff grids (querydiff and valuediff)\n *\n * Provides a unified function to create column definitions for data diff grids,\n * supporting both inline and side-by-side display modes.\n */\n\nimport type { CellClassParams, ColDef, ColGroupDef } from \"ag-grid-community\";\nimport _ from \"lodash\";\nimport type { ColumnRenderMode, ColumnType, RowObjectType } from \"../../api\";\nimport { getHeaderCellClass } from \"./gridUtils\";\nimport type {\n DataFrameColumnGroupHeaderProps,\n DiffColumnRenderComponents,\n} from \"./renderTypes\";\n\n// ============================================================================\n// Types\n// ============================================================================\n\n/**\n * Custom context data for Recce columns\n * Stored in colDef.context to avoid AG Grid validation warnings\n */\nexport interface RecceColumnContext {\n columnType?: ColumnType;\n columnRenderMode?: ColumnRenderMode;\n}\n\n/**\n * Configuration for building a diff column\n */\nexport interface DiffColumnConfig {\n /** Column name */\n name: string;\n /** Column diff status: 'added', 'removed', 'modified', or empty */\n columnStatus: string;\n /** Column data type */\n columnType: ColumnType;\n /** How to render numeric values */\n columnRenderMode?: ColumnRenderMode;\n /** Display mode: inline shows diff in single cell, side_by_side shows two columns */\n displayMode: \"inline\" | \"side_by_side\";\n /** Title for base column in side_by_side mode */\n baseTitle?: string;\n /** Title for current column in side_by_side mode */\n currentTitle?: string;\n /** Props to pass to DataFrameColumnGroupHeader */\n headerProps?: Partial<DataFrameColumnGroupHeaderProps>;\n /** Render components for building the column */\n renderComponents: DiffColumnRenderComponents;\n}\n\n/**\n * Extended column type with context metadata\n * Uses context property for custom data per AG Grid best practices\n * Note: Distributed form allows TypeScript to narrow types correctly\n */\nexport type DiffColumnResult =\n | (ColDef<RowObjectType> & { context?: RecceColumnContext })\n | (ColGroupDef<RowObjectType> & { context?: RecceColumnContext });\n\n// ============================================================================\n// Cell Class Factories\n// ============================================================================\n\n/**\n * Creates a cell class function for base column cells\n *\n * @param columnName - The column name (used for value comparison)\n * @param columnStatus - The column's diff status\n * @returns Function that returns CSS class based on row status and value diff\n */\nexport function createCellClassBase(\n columnName: string,\n columnStatus: string,\n): (params: CellClassParams<RowObjectType>) => string | undefined {\n return (params: CellClassParams<RowObjectType>) => {\n const row = params.data;\n if (!row) return undefined;\n\n const rowStatus = row.__status;\n\n if (rowStatus === \"removed\") return \"diff-cell-removed\";\n if (rowStatus === \"added\") return \"diff-cell-added\";\n if (columnStatus === \"added\" || columnStatus === \"removed\")\n return undefined;\n\n const baseKey = `base__${columnName}`.toLowerCase();\n const currentKey = `current__${columnName}`.toLowerCase();\n\n if (!_.isEqual(row[baseKey], row[currentKey])) {\n return \"diff-cell-removed\";\n }\n\n return undefined;\n };\n}\n\n/**\n * Creates a cell class function for current column cells\n *\n * @param columnName - The column name (used for value comparison)\n * @param columnStatus - The column's diff status\n * @returns Function that returns CSS class based on row status and value diff\n */\nexport function createCellClassCurrent(\n columnName: string,\n columnStatus: string,\n): (params: CellClassParams<RowObjectType>) => string | undefined {\n return (params: CellClassParams<RowObjectType>) => {\n const row = params.data;\n if (!row) return undefined;\n\n const rowStatus = row.__status;\n\n if (rowStatus === \"removed\") return \"diff-cell-removed\";\n if (rowStatus === \"added\") return \"diff-cell-added\";\n if (columnStatus === \"added\" || columnStatus === \"removed\")\n return undefined;\n\n const baseKey = `base__${columnName}`.toLowerCase();\n const currentKey = `current__${columnName}`.toLowerCase();\n\n if (!_.isEqual(row[baseKey], row[currentKey])) {\n return \"diff-cell-added\";\n }\n\n return undefined;\n };\n}\n\n// ============================================================================\n// Main Column Builder\n// ============================================================================\n\n/**\n * Creates a diff column definition for use in data grids\n *\n * @description Builds a column configuration that supports both inline and\n * side-by-side diff display modes. In inline mode, differences are shown\n * within a single cell. In side-by-side mode, base and current values\n * appear in separate child columns.\n *\n * @param config - Column configuration options\n * @returns Column definition compatible with AG Grid\n *\n * @example\n * // Inline mode for querydiff\n * const column = toDiffColumn({\n * name: 'price',\n * columnStatus: 'modified',\n * columnType: 'number',\n * displayMode: 'inline',\n * headerProps: {\n * primaryKeys: ['id'],\n * onPrimaryKeyChange: setPrimaryKeys,\n * },\n * renderComponents: {\n * DataFrameColumnGroupHeader,\n * defaultRenderCell,\n * inlineRenderCell,\n * },\n * });\n *\n * @example\n * // Side-by-side mode for valuediff\n * const column = toDiffColumn({\n * name: 'Amount',\n * columnStatus: '',\n * columnType: 'number',\n * displayMode: 'side_by_side',\n * baseTitle: 'Before',\n * currentTitle: 'After',\n * headerProps: {\n * primaryKeys: ['id'],\n * },\n * renderComponents: {\n * DataFrameColumnGroupHeader,\n * defaultRenderCell,\n * inlineRenderCell,\n * },\n * });\n */\nexport function toDiffColumn(config: DiffColumnConfig): DiffColumnResult {\n const {\n name,\n columnStatus,\n columnType,\n columnRenderMode,\n displayMode,\n baseTitle = \"Base\",\n currentTitle = \"Current\",\n headerProps = {},\n renderComponents,\n } = config;\n\n const { DataFrameColumnGroupHeader, defaultRenderCell, inlineRenderCell } =\n renderComponents;\n\n const headerCellClass = getHeaderCellClass(columnStatus);\n\n // Build the header component\n const headerComponent = () => (\n <DataFrameColumnGroupHeader\n name={name}\n columnStatus={columnStatus}\n columnType={columnType}\n {...headerProps}\n />\n );\n\n if (displayMode === \"inline\") {\n return {\n field: name,\n headerName: name,\n headerClass: headerCellClass,\n headerComponent,\n cellRenderer: inlineRenderCell,\n context: { columnType, columnRenderMode },\n };\n }\n\n // Side-by-side mode with base/current child columns\n const cellClassBase = createCellClassBase(name, columnStatus);\n const cellClassCurrent = createCellClassCurrent(name, columnStatus);\n\n return {\n headerName: name,\n headerClass: headerCellClass,\n headerGroupComponent: headerComponent,\n context: { columnType, columnRenderMode },\n children: [\n {\n field: `base__${name}`,\n headerName: baseTitle,\n headerClass: headerCellClass,\n cellClass: cellClassBase,\n cellRenderer: defaultRenderCell,\n context: { columnType, columnRenderMode },\n } as ColDef<RowObjectType>,\n {\n field: `current__${name}`,\n headerName: currentTitle,\n headerClass: headerCellClass,\n cellClass: cellClassCurrent,\n cellRenderer: defaultRenderCell,\n context: { columnType, columnRenderMode },\n } as ColDef<RowObjectType>,\n ],\n };\n}\n","/**\n * @file diffColumnBuilder.tsx\n * @description Builds AG Grid column definitions from ColumnConfig[]\n *\n * This module transforms the pure data structures from columnBuilders.ts\n * into actual column definitions with React components for headers.\n */\n\nimport type { CellClassParams, ColDef, ColGroupDef } from \"ag-grid-community\";\nimport type { RowObjectType } from \"../../api\";\nimport type { ColumnConfig } from \"./columnBuilders\";\nimport type {\n DataFrameColumnGroupHeaderProps,\n DiffColumnRenderComponents,\n} from \"./renderTypes\";\nimport type { RecceColumnContext } from \"./toDiffColumn\";\nimport { toDiffColumn } from \"./toDiffColumn\";\n\n// ============================================================================\n// Types\n// ============================================================================\n\n/**\n * Extended column type with context metadata\n * Uses context property for custom data per AG Grid best practices\n * Note: Distributed form allows TypeScript to narrow types correctly\n */\nexport type DiffColumnDefinition =\n | (ColDef<RowObjectType> & { context?: RecceColumnContext })\n | (ColGroupDef<RowObjectType> & { context?: RecceColumnContext });\n\n/**\n * Configuration for building diff column definitions\n */\nexport interface BuildDiffColumnDefinitionsConfig {\n /**\n * Column configurations from getDisplayColumns()\n */\n columns: ColumnConfig[];\n\n /**\n * Display mode for diff columns\n * - \"inline\": Single column with inline diff rendering\n * - \"side_by_side\": Column group with base/current sub-columns\n */\n displayMode: \"inline\" | \"side_by_side\";\n\n /**\n * Props to pass to DataFrameColumnGroupHeader for all columns\n */\n headerProps: Partial<DataFrameColumnGroupHeaderProps>;\n\n /**\n * Title for base column in side_by_side mode\n */\n baseTitle?: string;\n\n /**\n * Title for current column in side_by_side mode\n */\n currentTitle?: string;\n\n /**\n * Whether to add index column when no primary keys exist\n * Only applies when columns array has no isPrimaryKey entries\n * @default false\n */\n allowIndexFallback?: boolean;\n\n /**\n * Render components for building the columns\n */\n renderComponents: DiffColumnRenderComponents;\n}\n\n/**\n * Result from building diff column definitions\n */\nexport interface BuildDiffColumnDefinitionsResult {\n /**\n * The generated column definitions ready for AG Grid\n */\n columns: DiffColumnDefinition[];\n\n /**\n * Whether an index fallback column was added\n */\n usedIndexFallback: boolean;\n}\n\n// ============================================================================\n// Helper Functions\n// ============================================================================\n\n/**\n * Creates the index fallback column used when no primary keys are specified\n */\nfunction createIndexColumn(): DiffColumnDefinition {\n return {\n field: \"_index\",\n headerName: \"\",\n width: 50,\n maxWidth: 100,\n cellClass: \"index-column\",\n resizable: false,\n pinned: \"left\",\n };\n}\n\n/**\n * Creates a primary key column definition\n *\n * Primary key columns are:\n * - Pinned left (sticky left)\n * - Have a special cellClass based on row status\n * - Use defaultRenderCell (no base__/current__ prefixing)\n */\nfunction createPrimaryKeyColumn(\n config: ColumnConfig,\n headerProps: Partial<DataFrameColumnGroupHeaderProps>,\n renderComponents: DiffColumnRenderComponents,\n): DiffColumnDefinition {\n const { key, name, columnType, columnStatus, columnRenderMode } = config;\n const { DataFrameColumnGroupHeader, defaultRenderCell } = renderComponents;\n\n return {\n field: key,\n headerName: name,\n headerComponent: () => (\n <DataFrameColumnGroupHeader\n name={name}\n columnStatus={columnStatus ?? \"\"}\n columnType={columnType}\n {...headerProps}\n />\n ),\n pinned: \"left\",\n cellClass: (params: CellClassParams<RowObjectType>) => {\n if (params.data?.__status) {\n return `diff-header-${params.data.__status}`;\n }\n return undefined;\n },\n cellRenderer: defaultRenderCell,\n context: { columnType, columnRenderMode },\n };\n}\n\n/**\n * Creates a diff column definition (non-PK column)\n *\n * Uses toDiffColumn() to handle inline vs side_by_side modes\n */\nfunction createDiffColumn(\n config: ColumnConfig,\n displayMode: \"inline\" | \"side_by_side\",\n headerProps: Partial<DataFrameColumnGroupHeaderProps>,\n renderComponents: DiffColumnRenderComponents,\n baseTitle?: string,\n currentTitle?: string,\n): DiffColumnDefinition {\n const { name, columnType, columnStatus, columnRenderMode } = config;\n\n return toDiffColumn({\n name,\n columnStatus: columnStatus ?? \"\",\n columnType,\n columnRenderMode,\n displayMode,\n baseTitle,\n currentTitle,\n headerProps,\n renderComponents,\n });\n}\n\n// ============================================================================\n// Main Function\n// ============================================================================\n\n/**\n * Builds AG Grid column definitions from ColumnConfig array\n *\n * @description Transforms pure column configuration objects into actual\n * column definitions with React JSX headers. Handles:\n *\n * - Primary key columns (pinned, special cellClass)\n * - Diff columns (via toDiffColumn for inline/side_by_side modes)\n * - Index fallback (when no PKs and allowIndexFallback is true)\n *\n * @example\n * ```tsx\n * // Get column configs from shared utility\n * const columnConfigs = getDisplayColumns({\n * columnMap,\n * primaryKeys,\n * pinnedColumns,\n * columnsRenderMode,\n * changedOnly,\n * rowStats,\n * excludeColumns: [\"in_a\", \"in_b\"],\n * });\n *\n * // Build actual column definitions\n * const { columns } = buildDiffColumnDefinitions({\n * columns: columnConfigs,\n * displayMode: \"inline\",\n * headerProps: {\n * primaryKeys,\n * pinnedColumns,\n * onPinnedColumnsChange,\n * },\n * renderComponents: {\n * DataFrameColumnGroupHeader,\n * defaultRenderCell,\n * inlineRenderCell,\n * },\n * });\n * ```\n *\n * @example\n * ```tsx\n * // With index fallback for querydiff when no PKs\n * const { columns, usedIndexFallback } = buildDiffColumnDefinitions({\n * columns: columnConfigs,\n * displayMode: \"side_by_side\",\n * allowIndexFallback: true,\n * headerProps: {\n * primaryKeys: [],\n * pinnedColumns,\n * onPrimaryKeyChange,\n * onPinnedColumnsChange,\n * },\n * renderComponents: {\n * DataFrameColumnGroupHeader,\n * defaultRenderCell,\n * inlineRenderCell,\n * },\n * });\n *\n * if (usedIndexFallback) {\n * // Index-based matching was used\n * }\n * ```\n */\nexport function buildDiffColumnDefinitions(\n config: BuildDiffColumnDefinitionsConfig,\n): BuildDiffColumnDefinitionsResult {\n const {\n columns: columnConfigs,\n displayMode,\n headerProps,\n baseTitle,\n currentTitle,\n allowIndexFallback = false,\n renderComponents,\n } = config;\n\n const columns: DiffColumnDefinition[] = [];\n let usedIndexFallback = false;\n\n // Check if we have any primary key columns\n const hasPrimaryKeys = columnConfigs.some((col) => col.isPrimaryKey);\n\n // Add index fallback if no PKs and allowed\n if (!hasPrimaryKeys && allowIndexFallback) {\n columns.push(createIndexColumn());\n usedIndexFallback = true;\n }\n\n // Build column definitions\n for (const colConfig of columnConfigs) {\n if (colConfig.isPrimaryKey) {\n // Primary key column - pinned with special cellClass\n columns.push(\n createPrimaryKeyColumn(colConfig, headerProps, renderComponents),\n );\n } else {\n // Regular diff column - uses toDiffColumn for inline/side_by_side\n const diffColumn = createDiffColumn(\n colConfig,\n displayMode,\n headerProps,\n renderComponents,\n baseTitle,\n currentTitle,\n );\n\n // Set pinned property - \"left\" for frozen columns, undefined to explicitly unpin\n // Setting undefined is important to override AG Grid's internal pinned state\n columns.push({\n ...diffColumn,\n pinned: colConfig.frozen ? \"left\" : undefined,\n });\n }\n }\n\n return { columns, usedIndexFallback };\n}\n","/**\n * @file rowBuilders.ts\n * @description Shared row building utilities for diff grids\n *\n * Provides unified row generation logic for both querydiff (dual DataFrames)\n * and valuediff (joined DataFrame with in_a/in_b) scenarios.\n */\n\nimport _ from \"lodash\";\nimport type { DataFrame, RowObjectType } from \"../../api\";\nimport { mergeKeysWithStatus } from \"../mergeKeys\";\nimport { keyToNumber } from \"../transforms\";\nimport { ColumnMapEntry, MergeColumnMapEntry, RowStats } from \"./gridUtils\";\n\n// Re-export types from gridUtils for convenience\nexport type { RowStats };\n\n// ============================================================================\n// Types\n// ============================================================================\n\n/**\n * Union type for column map entries (supports both querydiff and valuediff)\n */\nexport type DiffColumnMapEntry = ColumnMapEntry | MergeColumnMapEntry;\n\n/**\n * Type guard to check if entry is a MergeColumnMapEntry (has separate base/current keys)\n */\nfunction isMergeColumnMapEntry(\n entry: DiffColumnMapEntry,\n): entry is MergeColumnMapEntry {\n return \"baseColumnKey\" in entry && \"currentColumnKey\" in entry;\n}\n\n/**\n * Configuration for building diff rows\n */\nexport interface BuildDiffRowsConfig {\n /**\n * Map of primary key values to base row data\n * Keys should already be normalized (e.g., lowercased if case-insensitive)\n */\n baseMap: Record<string, RowObjectType | undefined>;\n\n /**\n * Map of primary key values to current row data\n * Keys should already be normalized (e.g., lowercased if case-insensitive)\n */\n currentMap: Record<string, RowObjectType | undefined>;\n\n /**\n * Column definitions for base data\n * Used to iterate and extract values from base rows\n */\n baseColumns: DataFrame[\"columns\"];\n\n /**\n * Column definitions for current data\n * Used to iterate and extract values from current rows\n * For joined data (valuediff), this is the same as baseColumns\n */\n currentColumns: DataFrame[\"columns\"];\n\n /**\n * Column map for tracking column metadata and status\n * This object WILL BE MUTATED to update column.status when modifications are detected\n */\n columnMap: Record<string, DiffColumnMapEntry>;\n\n /**\n * List of primary key column names\n * These columns are stored directly on the row (not prefixed with base__/current__)\n */\n primaryKeys: string[];\n\n /**\n * Whether to filter out unchanged rows\n * When true, only rows with status \"added\", \"removed\", or \"modified\" are returned\n */\n changedOnly?: boolean;\n}\n\n/**\n * Result from building diff rows\n */\nexport interface BuildDiffRowsResult {\n /** The generated rows with __status and prefixed column values */\n rows: RowObjectType[];\n\n /** Statistics about row changes */\n rowStats: RowStats;\n}\n\n// ============================================================================\n// Helper Functions\n// ============================================================================\n\n/**\n * Checks if a column name is a primary key (exact matching)\n */\nfunction isPrimaryKey(columnName: string, primaryKeys: string[]): boolean {\n return primaryKeys.includes(columnName);\n}\n\n/**\n * Gets the column key to use for value comparison\n * For MergeColumnMapEntry, uses baseColumnKey/currentColumnKey\n * For ColumnMapEntry, uses the single key\n */\nfunction getComparisonKeys(entry: DiffColumnMapEntry): {\n baseKey: string;\n currentKey: string;\n} {\n if (isMergeColumnMapEntry(entry)) {\n return {\n baseKey: entry.baseColumnKey,\n currentKey: entry.currentColumnKey,\n };\n }\n return {\n baseKey: entry.key,\n currentKey: entry.key,\n };\n}\n\n/**\n * Populates row values from a source row for the given columns\n *\n * @param targetRow - The row object to populate\n * @param sourceRow - The source row to extract values from\n * @param columns - Column definitions to iterate\n * @param prefix - Prefix to add to column keys (e.g., \"base__\" or \"current__\")\n * @param primaryKeys - Primary key column names (stored without prefix)\n */\nfunction populateRowValues(\n targetRow: RowObjectType,\n sourceRow: RowObjectType,\n columns: DataFrame[\"columns\"],\n prefix: string,\n primaryKeys: string[],\n): void {\n columns.forEach((col) => {\n const colKey = col.key;\n const isPK = isPrimaryKey(colKey, primaryKeys);\n\n if (isPK) {\n // Primary keys stored directly (not prefixed)\n targetRow[String(colKey).toLowerCase()] = sourceRow[colKey];\n } else {\n // Non-PK columns are prefixed\n targetRow[`${prefix}${colKey}`.toLowerCase()] = sourceRow[colKey];\n }\n });\n}\n\n/**\n * Detects if a row has been modified by comparing base and current values\n * Also mutates columnMap entries to mark modified columns\n *\n * @returns true if any non-PK column value differs\n */\nfunction detectModifications(\n baseRow: RowObjectType,\n currentRow: RowObjectType,\n columnMap: Record<string, DiffColumnMapEntry>,\n primaryKeys: string[],\n): boolean {\n let isModified = false;\n\n for (const [name, column] of Object.entries(columnMap)) {\n // Skip index column\n if (name === \"index\") continue;\n\n // Skip primary key columns\n if (isPrimaryKey(name, primaryKeys)) continue;\n\n const { baseKey, currentKey } = getComparisonKeys(column);\n\n // Skip if either key is unknown (column added/removed in schema)\n if (baseKey === \"unknown\" || currentKey === \"unknown\") continue;\n\n const baseValue = baseRow[baseKey];\n const currentValue = currentRow[currentKey];\n\n if (!_.isEqual(baseValue, currentValue)) {\n isModified = true;\n // Mutate column status to track which columns have modifications\n column.status = \"modified\";\n }\n }\n\n return isModified;\n}\n\n// ============================================================================\n// Main Function\n// ============================================================================\n\n/**\n * Builds diff rows from base and current row maps\n *\n * @description This function unifies the row generation logic from both\n * `toDataDiffGrid` (querydiff) and `toValueDiffGrid` (valuediff).\n *\n * Key behaviors:\n * - Merges base and current row keys to determine all unique rows\n * - Creates row objects with `_index` and `__status` fields\n * - Prefixes non-PK columns with `base__` or `current__` (lowercased)\n * - Stores PK columns directly without prefix\n * - Detects added/removed/modified status\n * - Mutates columnMap to mark modified columns\n * - Optionally filters to changed rows only\n *\n * @example\n * ```typescript\n * // For querydiff (two separate DataFrames)\n * const result = buildDiffRows({\n * baseMap,\n * currentMap,\n * baseColumns: base.columns,\n * currentColumns: current.columns,\n * columnMap: mergedColumnMap,\n * primaryKeys: [\"id\"],\n * changedOnly: false,\n * });\n *\n * // For valuediff (joined DataFrame)\n * const result = buildDiffRows({\n * baseMap,\n * currentMap,\n * baseColumns: df.columns,\n * currentColumns: df.columns, // Same columns for both\n * columnMap: joinedColumnMap,\n * primaryKeys: [\"id\"],\n * changedOnly: true,\n * });\n * ```\n */\nexport function buildDiffRows(\n config: BuildDiffRowsConfig,\n): BuildDiffRowsResult {\n const {\n baseMap,\n currentMap,\n baseColumns,\n currentColumns,\n columnMap,\n primaryKeys,\n changedOnly = false,\n } = config;\n\n // Merge base and current keys to get all unique row identifiers\n const mergedMap = mergeKeysWithStatus(\n Object.keys(baseMap),\n Object.keys(currentMap),\n );\n\n const rowStats: RowStats = {\n added: 0,\n removed: 0,\n modified: 0,\n };\n\n // Build rows from merged keys\n let rows = Object.entries(mergedMap).map(([key]) => {\n const baseRow = baseMap[key];\n const currentRow = currentMap[key];\n\n // Initialize row with index and undefined status\n const row: RowObjectType = {\n _index: keyToNumber(key),\n __status: undefined,\n };\n\n // Populate base values\n if (baseRow) {\n populateRowValues(row, baseRow, baseColumns, \"base__\", primaryKeys);\n }\n\n // Populate current values\n if (currentRow) {\n populateRowValues(\n row,\n currentRow,\n currentColumns,\n \"current__\",\n primaryKeys,\n );\n }\n\n // Determine row status\n if (!baseRow) {\n row.__status = \"added\";\n rowStats.added++;\n } else if (!currentRow) {\n row.__status = \"removed\";\n rowStats.removed++;\n } else {\n // Both rows exist - check for modifications\n const isModified = detectModifications(\n baseRow,\n currentRow,\n columnMap,\n primaryKeys,\n );\n\n if (isModified) {\n row.__status = \"modified\";\n rowStats.modified++;\n }\n }\n\n return row;\n });\n\n // Filter to changed rows if requested\n if (changedOnly) {\n rows = rows.filter(\n (row) =>\n row.__status === \"added\" ||\n row.__status === \"removed\" ||\n row.__status === \"modified\",\n );\n }\n\n return { rows, rowStats };\n}\n","/**\n * @file validation.ts\n * @description Input validation utilities for data grid generation\n *\n * Provides clear, actionable error messages for common issues:\n * - Malformed DataFrame structure\n * - Column-data misalignment\n * - Missing required fields\n *\n * These validations run at entry points (toDataGrid, toDataDiffGrid, toValueDiffGrid)\n * to fail fast with helpful messages rather than cryptic runtime errors.\n */\n\nimport type { DataFrame } from \"../../api\";\n\n// ============================================================================\n// Custom Error Class\n// ============================================================================\n\n/**\n * Custom error class for data grid validation failures.\n * Provides structured error information for debugging.\n */\nexport class DataGridValidationError extends Error {\n constructor(\n message: string,\n public readonly context?: string,\n public readonly details?: Record<string, unknown>,\n ) {\n super(context ? `[${context}] ${message}` : message);\n this.name = \"DataGridValidationError\";\n }\n}\n\n// ============================================================================\n// DataFrame Validation\n// ============================================================================\n\n/**\n * Validates that a DataFrame has the required structure.\n * Does NOT throw for undefined/null - those are valid (represent empty data).\n *\n * @param df - The DataFrame to validate\n * @param name - Name for error messages (e.g., \"base\", \"current\")\n * @throws DataGridValidationError if structure is invalid\n */\nexport function validateDataFrame(\n df: DataFrame | undefined | null,\n name = \"DataFrame\",\n): void {\n // undefined/null is valid - represents empty/missing data\n if (df === undefined || df === null) {\n return;\n }\n\n // Must be an object\n if (typeof df !== \"object\") {\n throw new DataGridValidationError(\n `Expected an object, got ${typeof df}`,\n name,\n );\n }\n\n // Must have columns array\n if (!(\"columns\" in df)) {\n throw new DataGridValidationError(\"Missing 'columns' property\", name, {\n receivedKeys: Object.keys(df),\n });\n }\n\n if (!Array.isArray(df.columns)) {\n throw new DataGridValidationError(\n `'columns' must be an array, got ${typeof df.columns}`,\n name,\n );\n }\n\n // Must have data array\n if (!(\"data\" in df)) {\n throw new DataGridValidationError(\"Missing 'data' property\", name, {\n receivedKeys: Object.keys(df),\n });\n }\n\n if (!Array.isArray(df.data)) {\n throw new DataGridValidationError(\n `'data' must be an array, got ${typeof df.data}`,\n name,\n );\n }\n\n // Validate column structure\n validateColumns(df.columns, name);\n\n // Validate column-data alignment (only if there's data)\n if (df.data.length > 0) {\n validateColumnDataAlignment(df, name);\n }\n}\n\n/**\n * Validates that columns have required properties.\n *\n * @param columns - Array of column definitions\n * @param context - Context for error messages\n * @throws DataGridValidationError if any column is malformed\n */\nexport function validateColumns(\n columns: DataFrame[\"columns\"],\n context = \"DataFrame\",\n): void {\n columns.forEach((col, index) => {\n if (!col || typeof col !== \"object\") {\n throw new DataGridValidationError(\n `Column at index ${index} is not an object`,\n context,\n { column: col },\n );\n }\n\n // noinspection SuspiciousTypeOfGuard\n if (typeof col.key !== \"string\" || col.key === \"\") {\n throw new DataGridValidationError(\n `Column at index ${index} has invalid 'key': expected non-empty string, got ${JSON.stringify(col.key)}`,\n context,\n { column: col },\n );\n }\n\n // noinspection SuspiciousTypeOfGuard\n if (typeof col.name !== \"string\") {\n throw new DataGridValidationError(\n `Column '${col.key}' has invalid 'name': expected string, got ${typeof col.name}`,\n context,\n { column: col },\n );\n }\n\n // noinspection SuspiciousTypeOfGuard\n if (typeof col.type !== \"string\") {\n throw new DataGridValidationError(\n `Column '${col.key}' has invalid 'type': expected string, got ${typeof col.type}`,\n context,\n { column: col },\n );\n }\n });\n}\n\n/**\n * Validates that data rows match column count.\n *\n * @param df - The DataFrame to validate\n * @param context - Context for error messages\n * @throws DataGridValidationError if misalignment detected\n */\nexport function validateColumnDataAlignment(\n df: DataFrame,\n context = \"DataFrame\",\n): void {\n const columnCount = df.columns.length;\n\n for (let i = 0; i < df.data.length; i++) {\n const row = df.data[i];\n\n if (!Array.isArray(row)) {\n throw new DataGridValidationError(\n `Row at index ${i} is not an array`,\n context,\n { row, rowType: typeof row },\n );\n }\n\n if (row.length !== columnCount) {\n throw new DataGridValidationError(\n `Row ${i} has ${row.length} values but expected ${columnCount} (column count)`,\n context,\n {\n rowIndex: i,\n rowLength: row.length,\n columnCount,\n columns: df.columns.map((c) => c.key),\n },\n );\n }\n }\n}\n\n// ============================================================================\n// Primary Key Validation\n// ============================================================================\n\n/**\n * Validates primary key configuration.\n *\n * @param primaryKeys - Array of primary key column names\n * @param columns - Available columns to check against\n * @param options - Validation options\n * @throws DataGridValidationError if validation fails\n */\nexport function validatePrimaryKeyConfig(\n primaryKeys: string[] | undefined,\n columns: DataFrame[\"columns\"],\n options: {\n required?: boolean;\n caseInsensitive?: boolean;\n context?: string;\n } = {},\n): void {\n const {\n required = false,\n caseInsensitive = false,\n context = \"primaryKeys\",\n } = options;\n\n // Check if required\n if (required && (!primaryKeys || primaryKeys.length === 0)) {\n throw new DataGridValidationError(\n \"Primary keys are required but none were provided\",\n context,\n );\n }\n\n // If no PKs provided and not required, that's fine\n if (!primaryKeys || primaryKeys.length === 0) {\n return;\n }\n\n // Validate each PK exists\n const columnKeys = columns.map((c) => c.key);\n const columnKeysLower = caseInsensitive\n ? columnKeys.map((k) => k.toLowerCase())\n : columnKeys;\n\n for (const pk of primaryKeys) {\n const pkToFind = caseInsensitive ? pk.toLowerCase() : pk;\n const found = caseInsensitive\n ? columnKeysLower.includes(pkToFind)\n : columnKeys.includes(pk);\n\n if (!found) {\n throw new DataGridValidationError(\n `Primary key column '${pk}' not found in columns`,\n context,\n {\n requestedKey: pk,\n availableColumns: columnKeys,\n caseInsensitive,\n },\n );\n }\n }\n\n // Check for duplicate PKs\n const seen = new Set<string>();\n for (const pk of primaryKeys) {\n const normalized = caseInsensitive ? pk.toLowerCase() : pk;\n if (seen.has(normalized)) {\n throw new DataGridValidationError(\n `Duplicate primary key: '${pk}'`,\n context,\n { primaryKeys },\n );\n }\n seen.add(normalized);\n }\n}\n\n// ============================================================================\n// Convenience Validators for Entry Points\n// ============================================================================\n\n/**\n * Validates inputs for toDataGrid (single DataFrame).\n */\nexport function validateToDataGridInputs(\n df: DataFrame | undefined,\n options?: { primaryKeys?: string[] },\n): void {\n validateDataFrame(df, \"dataframe\");\n\n if (df && options?.primaryKeys) {\n validatePrimaryKeyConfig(options.primaryKeys, df.columns, {\n context: \"toDataGrid\",\n });\n }\n}\n\n/**\n * Validates inputs for toDataDiffGrid (base + current DataFrames).\n */\nexport function validateToDataDiffGridInputs(\n base: DataFrame | undefined,\n current: DataFrame | undefined,\n options?: { primaryKeys?: string[] },\n): void {\n validateDataFrame(base, \"base\");\n validateDataFrame(current, \"current\");\n\n // If PKs provided, they should exist in at least one of the DataFrames\n if (options?.primaryKeys && options.primaryKeys.length > 0) {\n const baseColumns = base?.columns ?? [];\n const currentColumns = current?.columns ?? [];\n const allColumnKeys = new Set([\n ...baseColumns.map((c) => c.key),\n ...currentColumns.map((c) => c.key),\n ]);\n\n for (const pk of options.primaryKeys) {\n if (!allColumnKeys.has(pk)) {\n throw new DataGridValidationError(\n `Primary key column '${pk}' not found in either base or current DataFrame`,\n \"toDataDiffGrid\",\n {\n requestedKey: pk,\n baseColumns: baseColumns.map((c) => c.key),\n currentColumns: currentColumns.map((c) => c.key),\n },\n );\n }\n }\n }\n}\n\n/**\n * Validates inputs for toValueDiffGrid\n *\n * @throws {DataGridValidationError} If validation fails\n */\nexport function validateToValueDiffGridInputs(\n df: DataFrame | undefined,\n primaryKeys: string[],\n): void {\n // Validate DataFrame exists\n if (!df) {\n throw new DataGridValidationError(\"DataFrame is required for value diff\");\n }\n\n // Validate DataFrame structure\n validateDataFrame(df);\n\n // Validate primary keys are provided (valuediff requires PKs)\n if (!primaryKeys || primaryKeys.length === 0) {\n throw new DataGridValidationError(\n \"Primary keys are required for value diff\",\n );\n }\n\n // Validate primary keys exist in columns (exact matching)\n validatePrimaryKeyConfig(primaryKeys, df.columns, {\n required: true,\n context: \"toValueDiffGrid\",\n });\n\n // Validate in_a/in_b columns exist (lowercase, guaranteed by backend)\n const columnKeys = df.columns.map((c) => c.key);\n if (!columnKeys.includes(\"in_a\")) {\n throw new DataGridValidationError(\n \"Value diff DataFrame must include lowercase 'in_a' column\",\n );\n }\n if (!columnKeys.includes(\"in_b\")) {\n throw new DataGridValidationError(\n \"Value diff DataFrame must include lowercase 'in_b' column\",\n );\n }\n}\n","/**\n * @file toDataDiffGrid.ts\n * @description Query diff grid generation for comparing base and current DataFrames\n *\n * This module provides the core grid generation logic with render component injection.\n * OSS provides wrapped versions that inject OSS-specific components.\n */\n\nimport type { ColumnRenderMode, DataFrame, RowObjectType } from \"../../../api\";\nimport { dataFrameToRowObjects } from \"../../transforms\";\nimport { getDisplayColumns } from \"../columnBuilders\";\nimport {\n buildDiffColumnDefinitions,\n type DiffColumnDefinition,\n} from \"../diffColumnBuilder\";\nimport {\n buildMergedColumnMap,\n getPrimaryKeyValue,\n validatePrimaryKeys,\n} from \"../gridUtils\";\nimport type { DiffColumnRenderComponents } from \"../renderTypes\";\nimport { buildDiffRows, type RowStats } from \"../rowBuilders\";\nimport { validateToDataDiffGridInputs } from \"../validation\";\n\n// ============================================================================\n// Types\n// ============================================================================\n\n/**\n * Options for generating a data diff grid\n */\nexport interface QueryDataDiffGridOptions {\n primaryKeys?: string[];\n onPrimaryKeyChange?: (primaryKeys: string[]) => void;\n pinnedColumns?: string[];\n onPinnedColumnsChange?: (pinnedColumns: string[]) => void;\n columnsRenderMode?: Record<string, ColumnRenderMode>;\n onColumnsRenderModeChanged?: (col: Record<string, ColumnRenderMode>) => void;\n changedOnly?: boolean;\n baseTitle?: string;\n currentTitle?: string;\n displayMode?: \"side_by_side\" | \"inline\";\n}\n\n/**\n * Configuration for building the data diff grid\n */\nexport interface ToDataDiffGridConfig {\n /**\n * Render components for column headers and cells\n */\n renderComponents: DiffColumnRenderComponents;\n}\n\n/**\n * Result of generating a data diff grid\n */\nexport interface DataDiffGridResult {\n columns: DiffColumnDefinition[];\n rows: RowObjectType[];\n invalidPKeyBase: boolean;\n invalidPKeyCurrent: boolean;\n}\n\n// ============================================================================\n// Main Grid Generation Function\n// ============================================================================\n\n/**\n * Generates grid configuration for comparing base and current DataFrames\n *\n * @param base - The base DataFrame (optional)\n * @param current - The current DataFrame (optional)\n * @param options - Grid options (primary keys, display mode, etc.)\n * @param config - Configuration with render components\n * @returns Grid columns and rows ready for AG Grid\n *\n * @example\n * ```tsx\n * const { columns, rows } = toDataDiffGrid(\n * baseDataFrame,\n * currentDataFrame,\n * { primaryKeys: ['id'], displayMode: 'inline' },\n * { renderComponents }\n * );\n * ```\n */\nexport function toDataDiffGrid(\n _base?: DataFrame,\n _current?: DataFrame,\n options?: QueryDataDiffGridOptions,\n config?: ToDataDiffGridConfig,\n): DataDiffGridResult {\n validateToDataDiffGridInputs(_base, _current, options);\n\n const base = _base ?? { columns: [], data: [] };\n const current = _current ?? { columns: [], data: [] };\n const primaryKeys = options?.primaryKeys ?? [];\n const pinnedColumns = options?.pinnedColumns ?? [];\n const changedOnly = options?.changedOnly ?? false;\n const displayMode = options?.displayMode ?? \"side_by_side\";\n const columnsRenderMode = options?.columnsRenderMode ?? {};\n\n const baseData = dataFrameToRowObjects(base);\n const currentData = dataFrameToRowObjects(current);\n\n // Build merged column map\n const columnMap = buildMergedColumnMap(base, current);\n\n // Build row maps indexed by primary key\n const baseMap: Record<string, RowObjectType> = {};\n const currentMap: Record<string, RowObjectType> = {};\n let invalidPKeyBase = false;\n let invalidPKeyCurrent = false;\n\n if (primaryKeys.length === 0) {\n baseData.forEach((row) => {\n baseMap[String(row._index)] = row;\n });\n currentData.forEach((row) => {\n currentMap[String(row._index)] = row;\n });\n } else {\n // Validate and build base map\n const basePKKeys = validatePrimaryKeys(base.columns, primaryKeys);\n baseData.forEach((row) => {\n const key = getPrimaryKeyValue(base.columns, basePKKeys, row);\n if (key in baseMap) {\n invalidPKeyBase = true;\n }\n baseMap[key] = row;\n });\n\n // Validate and build current map\n const currentPKKeys = validatePrimaryKeys(current.columns, primaryKeys);\n currentData.forEach((row) => {\n const key = getPrimaryKeyValue(current.columns, currentPKKeys, row);\n if (key in currentMap) {\n invalidPKeyCurrent = true;\n }\n currentMap[key] = row;\n });\n }\n\n const { rows, rowStats } = buildDiffRows({\n baseMap,\n currentMap,\n baseColumns: base.columns,\n currentColumns: current.columns,\n columnMap,\n primaryKeys,\n changedOnly,\n });\n\n // Get column configurations (pure data)\n const columnConfigs = getDisplayColumns({\n columnMap,\n primaryKeys,\n pinnedColumns,\n columnsRenderMode,\n changedOnly,\n rowStats,\n excludeColumns: [\"index\"],\n strictMode: false, // querydiff is lenient with missing columns\n });\n\n // Build column definitions with React components\n const { columns } = buildDiffColumnDefinitions({\n columns: columnConfigs,\n displayMode,\n allowIndexFallback: true,\n baseTitle: options?.baseTitle,\n currentTitle: options?.currentTitle,\n headerProps: {\n primaryKeys,\n pinnedColumns,\n onPrimaryKeyChange: options?.onPrimaryKeyChange,\n onPinnedColumnsChange: options?.onPinnedColumnsChange,\n onColumnsRenderModeChanged: options?.onColumnsRenderModeChanged,\n },\n renderComponents: config?.renderComponents ?? {\n // Default render components (for testing or when not specified)\n DataFrameColumnGroupHeader: () => null,\n defaultRenderCell: () => null,\n inlineRenderCell: () => null,\n },\n });\n\n return {\n columns,\n rows,\n invalidPKeyBase,\n invalidPKeyCurrent,\n };\n}\n","/**\n * @file simpleColumnBuilder.tsx\n * @description Builds AG Grid column definitions for simple (non-diff) grids\n *\n * This module transforms the pure data structures from columnBuilders.ts\n * into actual column definitions with React components for headers.\n *\n * Unlike diffColumnBuilder.tsx, this handles simple grids without:\n * - Base/current value comparison\n * - Inline vs side-by-side display modes\n * - Column status (added/removed/modified)\n */\n\nimport type { ColDef, ColGroupDef } from \"ag-grid-community\";\nimport type { ColumnRenderMode, RowObjectType } from \"../../api\";\nimport type { ColumnConfig } from \"./columnBuilders\";\nimport type { SimpleColumnRenderComponents } from \"./renderTypes\";\nimport type { RecceColumnContext } from \"./toDiffColumn\";\n\n// Re-export RecceColumnContext for convenience\nexport type { RecceColumnContext };\n\n// ============================================================================\n// Types\n// ============================================================================\n\n/**\n * Extended column type with context metadata\n * Uses context property for custom data per AG Grid best practices\n * Note: Distributed form allows TypeScript to narrow types correctly\n */\nexport type SimpleColumnDefinition =\n | (ColDef<RowObjectType> & { context?: RecceColumnContext })\n | (ColGroupDef<RowObjectType> & { context?: RecceColumnContext });\n\n/**\n * Configuration for building simple column definitions\n */\nexport interface BuildSimpleColumnDefinitionsConfig {\n /**\n * Column configurations from getSimpleDisplayColumns()\n */\n columns: ColumnConfig[];\n\n /**\n * Props to pass to column headers\n */\n headerProps: {\n pinnedColumns?: string[];\n onPinnedColumnsChange?: (pinnedColumns: string[]) => void;\n onColumnsRenderModeChanged?: (\n cols: Record<string, ColumnRenderMode>,\n ) => void;\n };\n\n /**\n * Whether to add index column when no primary keys exist\n * Only applies when columns array has no isPrimaryKey entries\n * @default true\n */\n allowIndexFallback?: boolean;\n\n /**\n * Render components for building the columns\n */\n renderComponents: SimpleColumnRenderComponents;\n}\n\n/**\n * Result from building simple column definitions\n */\nexport interface BuildSimpleColumnDefinitionsResult {\n /**\n * The generated column definitions ready for AG Grid\n */\n columns: SimpleColumnDefinition[];\n\n /**\n * Whether an index fallback column was added\n */\n usedIndexFallback: boolean;\n}\n\n// ============================================================================\n// Helper Functions\n// ============================================================================\n\n/**\n * Creates the index fallback column used when no primary keys are specified\n */\nfunction createIndexColumn(): SimpleColumnDefinition {\n return {\n field: \"_index\",\n headerName: \"\",\n width: 50,\n cellClass: \"index-column\",\n resizable: false,\n pinned: \"left\",\n };\n}\n\n/**\n * Creates a primary key column definition\n *\n * Primary key columns are:\n * - Pinned left (sticky left)\n * - Use DataFrameColumnGroupHeader (with columnStatus=\"\")\n * - Use defaultRenderCell\n */\nfunction createPrimaryKeyColumn(\n config: ColumnConfig,\n headerProps: BuildSimpleColumnDefinitionsConfig[\"headerProps\"],\n renderComponents: SimpleColumnRenderComponents,\n): SimpleColumnDefinition {\n const { key, name, columnType, columnRenderMode } = config;\n const { DataFrameColumnGroupHeader, defaultRenderCell } = renderComponents;\n\n return {\n field: key,\n headerName: name,\n headerComponent: () => (\n <DataFrameColumnGroupHeader\n name={name}\n columnStatus=\"\"\n columnType={columnType}\n pinnedColumns={headerProps.pinnedColumns}\n onPinnedColumnsChange={headerProps.onPinnedColumnsChange}\n onColumnsRenderModeChanged={headerProps.onColumnsRenderModeChanged}\n />\n ),\n pinned: \"left\",\n cellRenderer: defaultRenderCell,\n context: { columnType, columnRenderMode },\n };\n}\n\n/**\n * Creates a regular (non-PK) column definition\n *\n * Regular columns use DataFrameColumnHeader (simpler, no PK toggle)\n */\nfunction createRegularColumn(\n config: ColumnConfig,\n headerProps: BuildSimpleColumnDefinitionsConfig[\"headerProps\"],\n renderComponents: SimpleColumnRenderComponents,\n): SimpleColumnDefinition {\n const { key, name, columnType, columnRenderMode } = config;\n const { DataFrameColumnHeader, defaultRenderCell } = renderComponents;\n\n return {\n field: key,\n headerName: name,\n headerComponent: () => (\n <DataFrameColumnHeader\n name={name}\n columnType={columnType}\n pinnedColumns={headerProps.pinnedColumns}\n onPinnedColumnsChange={headerProps.onPinnedColumnsChange}\n onColumnsRenderModeChanged={headerProps.onColumnsRenderModeChanged}\n />\n ),\n cellRenderer: defaultRenderCell,\n context: { columnType, columnRenderMode },\n };\n}\n\n// ============================================================================\n// Main Function\n// ============================================================================\n\n/**\n * Builds AG Grid column definitions from ColumnConfig array\n *\n * @description Transforms pure column configuration objects into actual\n * column definitions with React JSX headers. Handles:\n *\n * - Primary key columns (pinned, use DataFrameColumnGroupHeader)\n * - Regular columns (use DataFrameColumnHeader)\n * - Index fallback (when no PKs and allowIndexFallback is true)\n *\n * @example\n * ```tsx\n * // Get column configs from shared utility\n * const columnConfigs = getSimpleDisplayColumns({\n * columnMap,\n * primaryKeys,\n * pinnedColumns,\n * columnsRenderMode,\n * });\n *\n * // Build actual column definitions\n * const { columns } = buildSimpleColumnDefinitions({\n * columns: columnConfigs,\n * headerProps: {\n * pinnedColumns,\n * onPinnedColumnsChange,\n * onColumnsRenderModeChanged,\n * },\n * renderComponents: {\n * DataFrameColumnGroupHeader,\n * DataFrameColumnHeader,\n * defaultRenderCell,\n * },\n * });\n * ```\n */\nexport function buildSimpleColumnDefinitions(\n config: BuildSimpleColumnDefinitionsConfig,\n): BuildSimpleColumnDefinitionsResult {\n const {\n columns: columnConfigs,\n headerProps,\n allowIndexFallback = true,\n renderComponents,\n } = config;\n\n const columns: SimpleColumnDefinition[] = [];\n let usedIndexFallback = false;\n\n // Check if we have any primary key columns\n const hasPrimaryKeys = columnConfigs.some((col) => col.isPrimaryKey);\n\n // Add index fallback if no PKs and allowed\n if (!hasPrimaryKeys && allowIndexFallback) {\n columns.push(createIndexColumn());\n usedIndexFallback = true;\n }\n\n // Build column definitions\n for (const colConfig of columnConfigs) {\n if (colConfig.isPrimaryKey) {\n columns.push(\n createPrimaryKeyColumn(colConfig, headerProps, renderComponents),\n );\n } else {\n const regularColumn = createRegularColumn(\n colConfig,\n headerProps,\n renderComponents,\n );\n\n // Set pinned property - \"left\" for frozen columns, undefined to explicitly unpin\n // Setting undefined is important to override AG Grid's internal pinned state\n columns.push({\n ...regularColumn,\n pinned: colConfig.frozen ? \"left\" : undefined,\n });\n }\n }\n\n return { columns, usedIndexFallback };\n}\n","/**\n * @file toDataGrid.ts\n * @description Simple data grid generation for single DataFrame display\n *\n * Unlike toDataDiffGrid, this handles non-diff scenarios\n * where we just display a single DataFrame without base/current comparison.\n *\n * This module provides the core grid generation logic with render component injection.\n * OSS provides wrapped versions that inject OSS-specific components.\n */\n\nimport type { ColDef, ColGroupDef } from \"ag-grid-community\";\nimport type { ColumnRenderMode, DataFrame, RowObjectType } from \"../../../api\";\nimport { dataFrameToRowObjects } from \"../../transforms\";\nimport { getSimpleDisplayColumns } from \"../columnBuilders\";\nimport { buildColumnMap } from \"../gridUtils\";\nimport type { SimpleColumnRenderComponents } from \"../renderTypes\";\nimport {\n buildSimpleColumnDefinitions,\n type SimpleColumnDefinition,\n} from \"../simpleColumnBuilder\";\nimport { validateToDataGridInputs } from \"../validation\";\n\n// ============================================================================\n// Types\n// ============================================================================\n\n/**\n * Options for generating a simple data grid\n */\nexport interface QueryDataGridOptions {\n primaryKeys?: string[];\n onPrimaryKeyChange?: (primaryKeys: string[]) => void;\n pinnedColumns?: string[];\n onPinnedColumnsChange?: (pinnedColumns: string[]) => void;\n columnsRenderMode?: Record<string, ColumnRenderMode>;\n onColumnsRenderModeChanged?: (col: Record<string, ColumnRenderMode>) => void;\n}\n\n/**\n * Configuration for building the data grid\n */\nexport interface ToDataGridConfig {\n /**\n * Render components for column headers and cells\n */\n renderComponents: SimpleColumnRenderComponents;\n}\n\n/**\n * Result of generating a data grid\n */\nexport interface DataGridResult {\n columns: SimpleColumnDefinition[];\n rows: RowObjectType[];\n}\n\n// ============================================================================\n// Main Grid Generation Function\n// ============================================================================\n\n/**\n * Generates grid configuration for a simple DataFrame display\n *\n * @param result - The DataFrame to display\n * @param options - Grid options (primary keys, pinning, etc.)\n * @param config - Configuration with render components\n * @returns Grid columns and rows ready for AG Grid\n *\n * @example\n * ```tsx\n * const { columns, rows } = toDataGrid(\n * dataFrame,\n * { primaryKeys: ['id'], pinnedColumns: [] },\n * { renderComponents }\n * );\n * ```\n */\nexport function toDataGrid(\n result: DataFrame,\n options: QueryDataGridOptions,\n config: ToDataGridConfig,\n): DataGridResult {\n validateToDataGridInputs(result, options);\n\n const primaryKeys = options.primaryKeys ?? [];\n const pinnedColumns = options.pinnedColumns ?? [];\n const columnsRenderMode = options.columnsRenderMode ?? {};\n\n // Build column map from DataFrame\n const columnMap = buildColumnMap(result);\n\n // Get column configurations (pure data)\n const columnConfigs = getSimpleDisplayColumns({\n columnMap,\n primaryKeys,\n pinnedColumns,\n columnsRenderMode,\n });\n\n // Build column definitions with React components\n const { columns } = buildSimpleColumnDefinitions({\n columns: columnConfigs,\n headerProps: {\n pinnedColumns,\n onPinnedColumnsChange: options.onPinnedColumnsChange,\n onColumnsRenderModeChanged: options.onColumnsRenderModeChanged,\n },\n allowIndexFallback: true,\n renderComponents: config.renderComponents,\n });\n\n return { columns, rows: dataFrameToRowObjects(result) };\n}\n","/**\n * @file toValueDiffGrid.ts\n * @description Value diff grid generation for joined data (with in_a/in_b columns)\n *\n * This module provides the core grid generation logic with render component injection.\n * OSS provides wrapped versions that inject OSS-specific components.\n *\n * NOTE: Backend guarantees:\n * - in_a/in_b columns are always lowercase\n * - primary_keys match actual column casing\n * Therefore, exact string matching is used everywhere.\n */\n\nimport type { DataFrame, RowObjectType } from \"../../../api\";\nimport { dataFrameToRowObjects } from \"../../transforms\";\nimport { getDisplayColumns } from \"../columnBuilders\";\nimport {\n buildDiffColumnDefinitions,\n type DiffColumnDefinition,\n} from \"../diffColumnBuilder\";\nimport {\n buildJoinedColumnMap,\n getPrimaryKeyValue,\n validatePrimaryKeys,\n} from \"../gridUtils\";\nimport type { DiffColumnRenderComponents } from \"../renderTypes\";\nimport { buildDiffRows } from \"../rowBuilders\";\nimport { validateToValueDiffGridInputs } from \"../validation\";\nimport type { QueryDataDiffGridOptions } from \"./toDataDiffGrid\";\n\n// ============================================================================\n// Types\n// ============================================================================\n\n/**\n * Configuration for building the value diff grid\n */\nexport interface ToValueDiffGridConfig {\n /**\n * Render components for column headers and cells\n */\n renderComponents: DiffColumnRenderComponents;\n}\n\n/**\n * Result of generating a value diff grid\n */\nexport interface ValueDiffGridResult {\n columns: DiffColumnDefinition[];\n rows: RowObjectType[];\n}\n\n// ============================================================================\n// Main Grid Generation Function\n// ============================================================================\n\n/**\n * Generates grid configuration for value diff (joined data with in_a/in_b)\n *\n * @param df - The joined DataFrame with in_a/in_b columns\n * @param primaryKeys - Array of primary key column names\n * @param options - Grid options\n * @param config - Configuration with render components\n * @returns Grid columns and rows ready for AG Grid\n *\n * @example\n * ```tsx\n * const { columns, rows } = toValueDiffGrid(\n * joinedDataFrame,\n * ['id'],\n * { displayMode: 'inline' },\n * { renderComponents }\n * );\n * ```\n */\nexport function toValueDiffGrid(\n df: DataFrame,\n primaryKeys: string[],\n options?: QueryDataDiffGridOptions,\n config?: ToValueDiffGridConfig,\n): ValueDiffGridResult {\n validateToValueDiffGridInputs(df, primaryKeys);\n\n const pinnedColumns = options?.pinnedColumns ?? [];\n const changedOnly = options?.changedOnly ?? false;\n const displayMode = options?.displayMode ?? \"inline\";\n const columnsRenderMode = options?.columnsRenderMode ?? {};\n const transformedData = dataFrameToRowObjects(df);\n\n // Build column map (expects lowercase in_a/in_b from backend)\n const columnMap = buildJoinedColumnMap(df);\n\n // Build row maps based on in_a/in_b columns\n const baseMap: Record<string, RowObjectType | undefined> = {};\n const currentMap: Record<string, RowObjectType | undefined> = {};\n\n // Validate primary keys exist (exact matching - backend provides correct casing)\n const primaryKeyKeys = validatePrimaryKeys(df.columns, primaryKeys);\n\n // in_a/in_b are guaranteed lowercase from backend\n const inBaseKey = columnMap.in_a.key;\n const inCurrentKey = columnMap.in_b.key;\n\n transformedData.forEach((row) => {\n // Generate primary key value (exact matching)\n const key = getPrimaryKeyValue(df.columns, primaryKeyKeys, row);\n\n // Access in_a/in_b directly (guaranteed lowercase from backend)\n if (row[inBaseKey]) {\n // Store with lowercase key for internal indexing\n baseMap[key.toLowerCase()] = row;\n }\n\n if (row[inCurrentKey]) {\n currentMap[key.toLowerCase()] = row;\n }\n });\n\n const { rows, rowStats } = buildDiffRows({\n baseMap,\n currentMap,\n baseColumns: df.columns,\n currentColumns: df.columns,\n columnMap,\n primaryKeys,\n changedOnly,\n });\n\n // Get column configurations for display\n const columnConfigs = getDisplayColumns({\n columnMap,\n primaryKeys,\n pinnedColumns,\n columnsRenderMode,\n changedOnly,\n rowStats,\n excludeColumns: [\"in_a\", \"in_b\"], // Only lowercase needed\n strictMode: true,\n });\n\n // Build column definitions with React components\n const { columns } = buildDiffColumnDefinitions({\n columns: columnConfigs,\n displayMode,\n allowIndexFallback: false,\n baseTitle: options?.baseTitle,\n currentTitle: options?.currentTitle,\n headerProps: {\n primaryKeys,\n pinnedColumns,\n onPinnedColumnsChange: options?.onPinnedColumnsChange,\n onColumnsRenderModeChanged: options?.onColumnsRenderModeChanged,\n },\n renderComponents: config?.renderComponents ?? {\n // Default render components (for testing or when not specified)\n DataFrameColumnGroupHeader: () => null,\n defaultRenderCell: () => null,\n inlineRenderCell: () => null,\n },\n });\n\n return {\n columns,\n rows,\n };\n}\n","/**\n * @file configured.ts\n * @description Pre-configured grid utilities with default render components.\n *\n * These exports inject DataFrameColumnGroupHeader, defaultRenderCell, and inlineRenderCell\n * automatically, eliminating the need for consumers to provide render components.\n *\n * Use these when you want the standard UI components without customization.\n * For custom render components, use the base functions and provide your own.\n *\n * @example\n * ```tsx\n * // Pre-configured (no render components needed)\n * import { toDataDiffGridConfigured } from \"@datarecce/ui/utils\";\n * const { columns, rows } = toDataDiffGridConfigured(base, current, options);\n *\n * // Base function (bring your own render components)\n * import { toDataDiffGrid } from \"@datarecce/ui/utils\";\n * const { columns, rows } = toDataDiffGrid(base, current, options, {\n * renderComponents: myCustomComponents,\n * });\n * ```\n */\n\nimport type { DataFrame } from \"../../api\";\nimport {\n DataFrameColumnGroupHeader,\n DataFrameColumnHeader,\n defaultRenderCell,\n inlineRenderCell,\n} from \"../../components/ui\";\nimport {\n type BuildDiffColumnDefinitionsConfig,\n type BuildDiffColumnDefinitionsResult,\n buildDiffColumnDefinitions,\n} from \"./diffColumnBuilder\";\nimport {\n type DataDiffGridResult,\n type QueryDataDiffGridOptions,\n toDataDiffGrid,\n} from \"./generators/toDataDiffGrid\";\nimport {\n type DataGridResult,\n type QueryDataGridOptions,\n toDataGrid,\n} from \"./generators/toDataGrid\";\nimport {\n toValueDiffGrid,\n type ValueDiffGridResult,\n} from \"./generators/toValueDiffGrid\";\nimport type {\n DiffColumnRenderComponents,\n SimpleColumnRenderComponents,\n} from \"./renderTypes\";\nimport {\n type BuildSimpleColumnDefinitionsConfig,\n type BuildSimpleColumnDefinitionsResult,\n buildSimpleColumnDefinitions,\n} from \"./simpleColumnBuilder\";\nimport {\n type DiffColumnConfig,\n type DiffColumnResult,\n toDiffColumn,\n} from \"./toDiffColumn\";\n\n// ============================================================================\n// Default Render Components\n// ============================================================================\n\n/**\n * Default render components used by diff column pre-configured exports.\n * These are the standard UI components from @datarecce/ui.\n */\nexport const defaultRenderComponents: DiffColumnRenderComponents = {\n DataFrameColumnGroupHeader,\n defaultRenderCell,\n inlineRenderCell,\n};\n\n/**\n * Default render components used by simple column pre-configured exports.\n * These are the standard UI components from @datarecce/ui.\n */\nexport const defaultSimpleRenderComponents: SimpleColumnRenderComponents = {\n DataFrameColumnGroupHeader,\n DataFrameColumnHeader,\n defaultRenderCell,\n};\n\n// ============================================================================\n// Pre-configured toDiffColumn\n// ============================================================================\n\n/**\n * Configuration for pre-configured toDiffColumn (without renderComponents)\n */\nexport type DiffColumnConfigConfigured = Omit<\n DiffColumnConfig,\n \"renderComponents\"\n>;\n\n/**\n * Creates a diff column definition with default render components.\n *\n * @param config - Column configuration (renderComponents automatically provided)\n * @returns Column definition compatible with AG Grid\n *\n * @example\n * ```tsx\n * const column = toDiffColumnConfigured({\n * name: 'price',\n * columnStatus: 'modified',\n * columnType: 'number',\n * displayMode: 'inline',\n * });\n * ```\n */\nexport function toDiffColumnConfigured(\n config: DiffColumnConfigConfigured,\n): DiffColumnResult {\n return toDiffColumn({\n ...config,\n renderComponents: defaultRenderComponents,\n });\n}\n\n// ============================================================================\n// Pre-configured buildDiffColumnDefinitions\n// ============================================================================\n\n/**\n * Configuration for pre-configured buildDiffColumnDefinitions (without renderComponents)\n */\nexport type BuildDiffColumnDefinitionsConfigConfigured = Omit<\n BuildDiffColumnDefinitionsConfig,\n \"renderComponents\"\n>;\n\n/**\n * Builds AG Grid column definitions with default render components.\n *\n * @param config - Column configuration (renderComponents automatically provided)\n * @returns Column definitions and metadata\n *\n * @example\n * ```tsx\n * const { columns, usedIndexFallback } = buildDiffColumnDefinitionsConfigured({\n * columns: columnConfigs,\n * displayMode: \"inline\",\n * headerProps: { primaryKeys },\n * });\n * ```\n */\nexport function buildDiffColumnDefinitionsConfigured(\n config: BuildDiffColumnDefinitionsConfigConfigured,\n): BuildDiffColumnDefinitionsResult {\n return buildDiffColumnDefinitions({\n ...config,\n renderComponents: defaultRenderComponents,\n });\n}\n\n// ============================================================================\n// Pre-configured toDataDiffGrid\n// ============================================================================\n\n/**\n * Generates grid configuration for comparing base and current DataFrames\n * with default render components.\n *\n * @param base - The base DataFrame (optional)\n * @param current - The current DataFrame (optional)\n * @param options - Grid options (primary keys, display mode, etc.)\n * @returns Grid columns and rows ready for AG Grid\n *\n * @example\n * ```tsx\n * const { columns, rows, invalidPKeyBase, invalidPKeyCurrent } = toDataDiffGridConfigured(\n * baseDataFrame,\n * currentDataFrame,\n * { primaryKeys: ['id'], displayMode: 'inline' }\n * );\n * ```\n */\nexport function toDataDiffGridConfigured(\n base?: DataFrame,\n current?: DataFrame,\n options?: QueryDataDiffGridOptions,\n): DataDiffGridResult {\n return toDataDiffGrid(base, current, options, {\n renderComponents: defaultRenderComponents,\n });\n}\n\n// ============================================================================\n// Pre-configured toValueDiffGrid\n// ============================================================================\n\n/**\n * Generates grid configuration for value diff (joined data with in_a/in_b)\n * with default render components.\n *\n * @param df - The joined DataFrame with in_a/in_b columns\n * @param primaryKeys - Array of primary key column names\n * @param options - Grid options\n * @returns Grid columns and rows ready for AG Grid\n *\n * @example\n * ```tsx\n * const { columns, rows } = toValueDiffGridConfigured(\n * joinedDataFrame,\n * ['id'],\n * { displayMode: 'inline' }\n * );\n * ```\n */\nexport function toValueDiffGridConfigured(\n df: DataFrame,\n primaryKeys: string[],\n options?: QueryDataDiffGridOptions,\n): ValueDiffGridResult {\n return toValueDiffGrid(df, primaryKeys, options, {\n renderComponents: defaultRenderComponents,\n });\n}\n\n// ============================================================================\n// Pre-configured toDataGrid\n// ============================================================================\n\n/**\n * Generates grid configuration for a simple DataFrame display\n * with default render components.\n *\n * @param result - The DataFrame to display\n * @param options - Grid options (primary keys, pinning, etc.)\n * @returns Grid columns and rows ready for AG Grid\n *\n * @example\n * ```tsx\n * const { columns, rows } = toDataGridConfigured(dataFrame, {\n * primaryKeys: ['id'],\n * pinnedColumns: [],\n * });\n * ```\n */\nexport function toDataGridConfigured(\n result: DataFrame,\n options: QueryDataGridOptions,\n): DataGridResult {\n return toDataGrid(result, options, {\n renderComponents: defaultSimpleRenderComponents,\n });\n}\n\n// ============================================================================\n// Pre-configured buildSimpleColumnDefinitions\n// ============================================================================\n\n/**\n * Configuration for pre-configured buildSimpleColumnDefinitions (without renderComponents)\n */\nexport type BuildSimpleColumnDefinitionsConfigConfigured = Omit<\n BuildSimpleColumnDefinitionsConfig,\n \"renderComponents\"\n>;\n\n/**\n * Builds AG Grid column definitions for simple grids with default render components.\n *\n * @param config - Column configuration (renderComponents automatically provided)\n * @returns Column definitions and metadata\n *\n * @example\n * ```tsx\n * const { columns } = buildSimpleColumnDefinitionsConfigured({\n * columns: columnConfigs,\n * headerProps: { pinnedColumns },\n * });\n * ```\n */\nexport function buildSimpleColumnDefinitionsConfigured(\n config: BuildSimpleColumnDefinitionsConfigConfigured,\n): BuildSimpleColumnDefinitionsResult {\n return buildSimpleColumnDefinitions({\n ...config,\n renderComponents: defaultSimpleRenderComponents,\n });\n}\n","/**\n * @file delta.ts\n * @description Utility functions for calculating and formatting delta percentages\n *\n * These utilities are used to display percentage changes between base and current values\n * in data comparison views (row counts, value diffs, etc.)\n */\n\n/**\n * Calculate and format the percentage change between two values.\n *\n * @param base - The baseline value (denominator for percentage calculation)\n * @param current - The current value to compare against baseline\n * @returns Formatted percentage string with sign (+/-) or special values for edge cases\n *\n * @example\n * deltaPercentageString(100, 110) // \"+10.0%\"\n * deltaPercentageString(100, 90) // \"-10.0%\"\n * deltaPercentageString(100, 100) // \"0\"\n * deltaPercentageString(0, 100) // \"N/A\" (division by zero)\n * deltaPercentageString(1000, 1000.5) // \"+ <0.1 %\" (very small change)\n */\nexport function deltaPercentageString(base: number, current: number): string {\n // Handle divide by zero - percentage change from 0 is undefined\n if (base === 0 && current !== 0) {\n return \"N/A\";\n }\n\n if (base < current) {\n const p = ((current - base) / base) * 100;\n return `+${p >= 0.1 ? p.toFixed(1) : \" <0.1 \"}%`;\n } else if (base > current) {\n const p = ((base - current) / base) * 100;\n return `-${p >= 0.1 ? p.toFixed(1) : \" <0.1 \"}%`;\n } else {\n return \"0\";\n }\n}\n","/**\n * @file rowCountUtils.ts\n * @description Utilities for converting row count results to DataFrame format\n */\n\nimport type { DataFrame, RowCountDiffResult, RowCountResult } from \"../../api\";\nimport { deltaPercentageString } from \"../delta\";\n\n// ============================================================================\n// Types\n// ============================================================================\n\n/**\n * Extended row data for row count diff grid\n */\nexport interface RowCountDiffRowData {\n name: string;\n base: number | null;\n current: number | null;\n delta: string;\n}\n\n/**\n * Extended row data for row count grid (single env)\n */\nexport interface RowCountRowData {\n name: string;\n current: number | null;\n}\n\n// ============================================================================\n// Delta Calculation\n// ============================================================================\n\n/**\n * Calculates the delta string for row count comparison\n */\nexport function calculateDelta(\n base: number | null,\n current: number | null,\n): string {\n if (base !== null && current !== null) {\n return base !== current ? deltaPercentageString(base, current) : \"0\";\n }\n\n if (base === current) return \"N/A\";\n if (base === null) return \"Added\";\n if (current === null) return \"Removed\";\n\n return \"N/A\";\n}\n\n// ============================================================================\n// Data Conversion\n// ============================================================================\n\n/**\n * Converts RowCountDiffResult to DataFrame format\n *\n * @param result - The row count diff result from the backend\n * @returns DataFrame with name, base, current, and delta columns\n */\nexport function rowCountDiffResultToDataFrame(\n result: RowCountDiffResult,\n): DataFrame {\n const entries = Object.entries(result);\n\n return {\n columns: [\n { key: \"name\", name: \"Name\", type: \"text\" },\n { key: \"base\", name: \"Base Rows\", type: \"number\" },\n { key: \"current\", name: \"Current Rows\", type: \"number\" },\n { key: \"delta\", name: \"Delta\", type: \"text\" },\n ],\n data: entries.map(([name, counts]) => {\n const base = typeof counts.base === \"number\" ? counts.base : null;\n const current = typeof counts.curr === \"number\" ? counts.curr : null;\n const delta = calculateDelta(base, current);\n\n return [name, base, current, delta];\n }),\n };\n}\n\n/**\n * Converts RowCountResult to DataFrame format\n *\n * @param result - The row count result from the backend\n * @returns DataFrame with name and current columns\n */\nexport function rowCountResultToDataFrame(result: RowCountResult): DataFrame {\n const entries = Object.entries(result);\n\n return {\n columns: [\n { key: \"name\", name: \"Name\", type: \"text\" },\n { key: \"current\", name: \"Row Count\", type: \"number\" },\n ],\n data: entries.map(([name, counts]) => {\n const current = typeof counts.curr === \"number\" ? counts.curr : null;\n return [name, current];\n }),\n };\n}\n\n// ============================================================================\n// Row Status Determination\n// ============================================================================\n\n/**\n * Determines the diff status for a row count entry\n *\n * @param base - Base row count (null if not present)\n * @param current - Current row count (null if not present)\n * @returns Status string: \"added\" | \"removed\" | \"modified\" | undefined\n */\nexport function getRowCountDiffStatus(\n base: number | null,\n current: number | null,\n): \"added\" | \"removed\" | \"modified\" | undefined {\n if (base === null && current !== null) return \"added\";\n if (base !== null && current === null) return \"removed\";\n if (base !== null && current !== null && base !== current) return \"modified\";\n return undefined;\n}\n","/**\n * @file toRowCountDataGrid.ts\n * @description Grid generator for Row Count view (single environment)\n *\n * Generates columns and rows for displaying row counts\n * in a single environment context.\n */\n\nimport type { ColDef, ColGroupDef } from \"ag-grid-community\";\nimport type { RowCountResult, RowObjectType } from \"../../../api\";\nimport { dataFrameToRowObjects } from \"../../transforms\";\nimport { rowCountResultToDataFrame } from \"../rowCountUtils\";\n\n// ============================================================================\n// Types\n// ============================================================================\n\nexport interface RowCountDataGridResult {\n columns: (ColDef<RowObjectType> | ColGroupDef<RowObjectType>)[];\n rows: RowObjectType[];\n}\n\n// ============================================================================\n// Main Generator Function\n// ============================================================================\n\n/**\n * Generates grid data for Row Count view (single environment)\n *\n * @param result - The RowCountResult from the backend\n * @returns Grid columns and rows ready for RecceDataGrid\n *\n * @example\n * ```tsx\n * const { columns, rows } = toRowCountDataGrid(run.result);\n * return <RecceDataGrid columnDefs={columns} rowData={rows} />;\n * ```\n */\nexport function toRowCountDataGrid(\n result: RowCountResult,\n): RowCountDataGridResult {\n // Convert to DataFrame format\n const dataFrame = rowCountResultToDataFrame(result);\n\n // Convert DataFrame to row objects\n const rawRows = dataFrameToRowObjects(dataFrame);\n\n // Transform rows (display \"N/A\" for null values)\n const rows: RowObjectType[] = rawRows.map((row) => ({\n ...row,\n current: row.current ?? \"N/A\",\n __status: undefined,\n }));\n\n // Build columns (simple, no diff styling)\n const columns: ColDef<RowObjectType>[] = [\n {\n field: \"name\",\n headerName: \"Name\",\n resizable: true,\n },\n {\n field: \"current\",\n headerName: \"Row Count\",\n resizable: true,\n },\n ];\n\n return { columns, rows };\n}\n","/**\n * @file toRowCountDiffDataGrid.ts\n * @description Grid generator for Row Count Diff view\n *\n * Generates columns and rows for displaying row count comparisons\n * between base and current environments across multiple models.\n */\n\nimport type { CellClassParams, ColDef, ColGroupDef } from \"ag-grid-community\";\nimport type { RowCountDiffResult, RowObjectType } from \"../../../api\";\nimport { dataFrameToRowObjects } from \"../../transforms\";\nimport {\n getRowCountDiffStatus,\n rowCountDiffResultToDataFrame,\n} from \"../rowCountUtils\";\n\n// ============================================================================\n// Types\n// ============================================================================\n\nexport interface RowCountDiffDataGridResult {\n columns: (ColDef<RowObjectType> | ColGroupDef<RowObjectType>)[];\n rows: RowObjectType[];\n}\n\n// ============================================================================\n// Cell Class Function\n// ============================================================================\n\n/**\n * Creates a cell class function for row count diff cells\n *\n * Returns appropriate diff-cell-* class based on row status\n */\nfunction createRowCountDiffCellClass(): (\n params: CellClassParams<RowObjectType>,\n) => string | undefined {\n return (params: CellClassParams<RowObjectType>) => {\n const row = params.data;\n if (!row) return undefined;\n\n const base = row.base as number | string | null;\n const current = row.current as number | string | null;\n\n // Handle \"N/A\" string values\n const baseValue = base === \"N/A\" ? null : base;\n const currentValue = current === \"N/A\" ? null : current;\n\n // Both null or equal - no styling\n if (baseValue === currentValue) {\n return undefined;\n }\n\n // Current increased or newly added\n if (\n baseValue === null ||\n (typeof baseValue === \"number\" &&\n typeof currentValue === \"number\" &&\n baseValue < currentValue)\n ) {\n return \"diff-cell-added\";\n }\n\n // Current decreased or removed\n if (\n currentValue === null ||\n (typeof baseValue === \"number\" &&\n typeof currentValue === \"number\" &&\n baseValue > currentValue)\n ) {\n return \"diff-cell-removed\";\n }\n\n return undefined;\n };\n}\n\n// ============================================================================\n// Main Generator Function\n// ============================================================================\n\n/**\n * Generates grid data for Row Count Diff view\n *\n * @param result - The RowCountDiffResult from the backend\n * @returns Grid columns and rows ready for RecceDataGrid\n *\n * @example\n * ```tsx\n * const { columns, rows } = toRowCountDiffDataGrid(run.result);\n * return <RecceDataGrid columnDefs={columns} rowData={rows} />;\n * ```\n */\nexport function toRowCountDiffDataGrid(\n result: RowCountDiffResult,\n): RowCountDiffDataGridResult {\n // Convert to DataFrame format\n const dataFrame = rowCountDiffResultToDataFrame(result);\n\n // Convert DataFrame to row objects\n const rawRows = dataFrameToRowObjects(dataFrame);\n\n // Add __status to each row based on base/current comparison\n const rows: RowObjectType[] = rawRows.map((row) => {\n const base = row.base as number | null;\n const current = row.current as number | null;\n\n return {\n ...row,\n // Display \"N/A\" for null values\n base: base ?? \"N/A\",\n current: current ?? \"N/A\",\n __status: getRowCountDiffStatus(\n typeof base === \"number\" ? base : null,\n typeof current === \"number\" ? current : null,\n ),\n };\n });\n\n // Create cell class function\n const cellClass = createRowCountDiffCellClass();\n\n // Build columns\n const columns: ColDef<RowObjectType>[] = [\n {\n field: \"name\",\n headerName: \"Name\",\n resizable: true,\n cellClass,\n },\n {\n field: \"base\",\n headerName: \"Base Rows\",\n resizable: true,\n cellClass,\n },\n {\n field: \"current\",\n headerName: \"Current Rows\",\n resizable: true,\n cellClass,\n },\n {\n field: \"delta\",\n headerName: \"Delta\",\n resizable: true,\n cellClass,\n },\n ];\n\n return { columns, rows };\n}\n","/**\n * @file envUtils.ts\n * @description Environment information utilities for extracting data from lineage graphs.\n */\n\nimport type { LineageGraph, LineageGraphNode } from \"../contexts/lineage\";\n\n/**\n * Extract unique schema names from the lineage graph.\n *\n * Iterates through all nodes in the lineage graph and collects\n * unique schema names from both base and current environments.\n *\n * @param lineageGraph - The lineage graph data\n * @returns Tuple of [baseSchemas, currentSchemas] as Sets\n *\n * @example\n * ```ts\n * const { lineageGraph } = useLineageGraphContext();\n * const [baseSchemas, currentSchemas] = extractSchemas(lineageGraph);\n *\n * console.log(baseSchemas); // Set { \"schema_v1\", \"public\" }\n * console.log(currentSchemas); // Set { \"schema_v2\", \"public\" }\n * ```\n */\nexport function extractSchemas(\n lineageGraph: LineageGraph | undefined,\n): [Set<string>, Set<string>] {\n const baseSchemas = new Set<string>();\n const currentSchemas = new Set<string>();\n\n if (lineageGraph?.nodes) {\n const nodes: LineageGraphNode[] = Object.values(lineageGraph.nodes);\n for (const node of nodes) {\n if (node.data.data.base?.schema) {\n baseSchemas.add(node.data.data.base.schema);\n }\n if (node.data.data.current?.schema) {\n currentSchemas.add(node.data.data.current.schema);\n }\n }\n }\n return [baseSchemas, currentSchemas];\n}\n","/**\n * @file formatSelect.ts\n * @description Column format selection utilities for SQL SELECT statements\n */\n\nimport { mergeKeys } from \"./mergeKeys\";\n\n/**\n * Formats merged columns with (Added)/(Removed) annotations for SQL SELECT.\n * Adds trailing commas except for the last actual column.\n *\n * @param baseColumns - Columns from the base environment\n * @param currentColumns - Columns from the current environment\n * @returns Array of formatted column strings with annotations and commas\n */\nexport function formatSelectColumns(\n baseColumns: string[],\n currentColumns: string[],\n): string[] {\n const mergedColumns = mergeKeys(baseColumns, currentColumns);\n\n // both side have no schema\n if (mergedColumns.length === 0) {\n return [];\n }\n\n // if either side has schema (added and removed model, no catalog.json)\n if (baseColumns.length === 0 || currentColumns.length === 0) {\n return mergedColumns.map((col, idx) => {\n const last = idx === mergedColumns.length - 1;\n if (last) {\n return col;\n }\n return col + \",\";\n });\n }\n\n let lastActualColumn = \"\";\n mergedColumns.forEach((col) => {\n if (baseColumns.includes(col) && currentColumns.includes(col)) {\n lastActualColumn = col;\n }\n });\n\n const selectColumns = mergedColumns.map((col, idx) => {\n let formatCol;\n\n if (!baseColumns.includes(col)) {\n formatCol = `--- ${col} (Added)`;\n } else if (!currentColumns.includes(col)) {\n formatCol = `--- ${col} (Removed)`;\n } else {\n formatCol = col;\n }\n\n if (col === lastActualColumn || idx === mergedColumns.length - 1) {\n return formatCol;\n }\n return formatCol + \",\";\n });\n\n return selectColumns;\n}\n","/**\n * @file formatTime.ts\n * @description Time formatting utilities for duration and timestamp display\n */\n\nimport { format, formatDistance, parseISO } from \"date-fns\";\n\nexport type TimeFormatStyle = \"compact\" | \"verbose\";\n\ninterface TimeComponents {\n hours: number;\n minutes: number;\n seconds: number;\n}\n\n/**\n * Break down seconds into hours, minutes, seconds\n */\nfunction getTimeComponents(totalSeconds: number): TimeComponents {\n const seconds = Math.floor(totalSeconds);\n return {\n hours: Math.floor(seconds / 3600),\n minutes: Math.floor((seconds % 3600) / 60),\n seconds: seconds % 60,\n };\n}\n\n/**\n * Format time in compact style (MM:SS or HH:MM:SS)\n * Used for countdown badges where space is limited\n */\nfunction formatCompact({ hours, minutes, seconds }: TimeComponents): string {\n if (hours > 0) {\n return `${hours}:${minutes.toString().padStart(2, \"0\")}:${seconds.toString().padStart(2, \"0\")}`;\n }\n return `${minutes}:${seconds.toString().padStart(2, \"0\")}`;\n}\n\n/**\n * Format time in verbose style (human-readable)\n * Used for messages where clarity is more important than brevity\n *\n * Examples:\n * - Less than 1 minute: \"30 seconds\"\n * - Exact minutes: \"5 mins\"\n * - Minutes with seconds: \"2 mins 30 seconds\"\n * - With hours: \"1 hour 30 mins\"\n */\nfunction formatVerbose({ hours, minutes, seconds }: TimeComponents): string {\n const parts: string[] = [];\n\n // Add hours if present\n if (hours > 0) {\n parts.push(`${hours} hour${hours !== 1 ? \"s\" : \"\"}`);\n }\n\n // Add minutes if present (or if hours present and minutes > 0)\n if (minutes > 0) {\n parts.push(`${minutes} min${minutes !== 1 ? \"s\" : \"\"}`);\n }\n\n // Add seconds only if no hours (keep message concise for long durations)\n // or if it's the only component\n if (hours === 0 && (parts.length === 0 || seconds > 0)) {\n parts.push(`${seconds} second${seconds !== 1 ? \"s\" : \"\"}`);\n }\n\n return parts.join(\" \");\n}\n\n/**\n * Format seconds into human-readable time string\n *\n * @param totalSeconds - Total seconds to format\n * @param style - \"compact\" for MM:SS, \"verbose\" for human-readable\n */\nexport function formatDuration(\n totalSeconds: number,\n style: TimeFormatStyle = \"verbose\",\n): string {\n const components = getTimeComponents(totalSeconds);\n\n if (style === \"compact\") {\n return formatCompact(components);\n }\n return formatVerbose(components);\n}\n\n// ============================================================================\n// ISO Timestamp Utilities\n// ============================================================================\n\n/**\n * Format an ISO timestamp string to a consistent date-time format.\n *\n * @param timestamp - ISO 8601 timestamp string\n * @returns Formatted string in \"yyyy-MM-dd'T'HH:mm:ss\" format\n *\n * @example\n * ```ts\n * formatTimestamp(\"2024-01-15T10:30:00Z\")\n * // Returns: \"2024-01-15T10:30:00\"\n * ```\n */\nexport function formatTimestamp(timestamp: string): string {\n const date = parseISO(timestamp);\n return format(date, \"yyyy-MM-dd'T'HH:mm:ss\");\n}\n\n/**\n * Format an ISO timestamp as a relative time string (e.g., \"2 hours ago\").\n *\n * @param timestamp - ISO 8601 timestamp string\n * @returns Human-readable relative time string\n *\n * @example\n * ```ts\n * formatTimeToNow(\"2024-01-15T10:30:00Z\")\n * // Returns: \"2 hours ago\" (depending on current time)\n * ```\n */\nexport function formatTimeToNow(timestamp: string): string {\n const date = parseISO(timestamp);\n return formatDistance(date, new Date(), {\n addSuffix: true,\n });\n}\n","/**\n * @file utils/schemaDiff.ts\n * @description Utility functions for schema comparison and change detection\n */\n\nimport type { NodeData } from \"../api\";\n\n/**\n * Checks if a schema has changed between base and current environments.\n *\n * Detects the following types of changes:\n * - Column additions or removals (different key counts)\n * - Column reordering (same keys but different order)\n * - Type modifications (column exists in both but type differs)\n *\n * @param baseSchema - The base environment schema columns\n * @param currSchema - The current environment schema columns\n * @returns `true` if schema changed, `false` if unchanged, `undefined` if either schema is missing\n *\n * @example\n * ```typescript\n * import { isSchemaChanged } from '@datarecce/ui';\n *\n * const base = { id: { type: 'integer' }, name: { type: 'string' } };\n * const curr = { id: { type: 'integer' }, name: { type: 'varchar' } };\n *\n * isSchemaChanged(base, curr); // true (type modified)\n * ```\n */\nexport function isSchemaChanged(\n baseSchema: NodeData[\"columns\"],\n currSchema: NodeData[\"columns\"],\n): boolean | undefined {\n if (!baseSchema || !currSchema) {\n return undefined;\n }\n const baseKeys = Object.keys(baseSchema);\n const currKeys = Object.keys(currSchema);\n\n // added or removed columns\n if (baseKeys.length !== currKeys.length) {\n return true;\n }\n\n // reordered columns\n for (let i = 0; i < baseKeys.length; i++) {\n if (baseKeys[i] !== currKeys[i]) {\n return true;\n }\n }\n\n // modified column types\n for (const key of currKeys) {\n if (!baseSchema[key] || baseSchema[key].type !== currSchema[key]?.type) {\n return true;\n }\n }\n\n return false;\n}\n","import type { RecceInstanceInfo } from \"../api\";\n\n/**\n * Generate the settings URL based on instance info.\n *\n * @param instanceInfo - Recce instance information containing web_url and organization_name\n * @param fallbackUrl - URL to use when not in cloud environment (e.g., calendar booking)\n * @returns Absolute URL to settings page or the fallback URL\n *\n * @example\n * ```typescript\n * // With cloud instance info\n * getSettingsUrl(instanceInfo, \"https://cal.com/team/recce/chat\");\n * // Returns: \"https://cloud.recce.io/organizations/my-org/settings\"\n *\n * // Without cloud instance info\n * getSettingsUrl(undefined, \"https://cal.com/team/recce/chat\");\n * // Returns: \"https://cal.com/team/recce/chat\"\n * ```\n */\nexport function getSettingsUrl(\n instanceInfo: RecceInstanceInfo | undefined,\n fallbackUrl: string,\n): string {\n if (instanceInfo?.organization_name && instanceInfo.web_url) {\n // Use absolute URL from Recce Cloud\n return `${instanceInfo.web_url}/organizations/${instanceInfo.organization_name}/settings`;\n }\n // Fallback URL when not in cloud environment\n return fallbackUrl;\n}\n"],"mappings":"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"}
|
package/dist/utils.d.ts
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
|
|
2
|
+
import "./flag-CiR2E5oz.js";
|
|
3
|
+
import "./types-CZre3j02.js";
|
|
4
|
+
import "./index-DTCpHvX_.js";
|
|
5
|
+
import "./api-ZZ4cc9b9.js";
|
|
6
|
+
import { $ as RowCountDiffDataGridResult, $t as isExcludedColumn, A as RowCountRowData, At as BuildDiffColumnDefinitionsResult, B as MergeColumnMapEntry, Bt as ColumnRenderComponents, C as validateColumns, Ct as SimpleColumnDefinition, D as validateToDataGridInputs, Dt as ToDataDiffGridConfig, E as validateToDataDiffGridInputs, Et as QueryDataDiffGridOptions, F as BuildDiffRowsConfig, Ft as RecceColumnContext, G as columnRenderedValue, Gt as ColumnPrecisionOption, H as buildColumnMap, Ht as DataFrameColumnHeaderProps, I as BuildDiffRowsResult, It as createCellClassBase, J as getCellClass, Jt as ColumnOrderConfig, K as determineRowStatus, Kt as columnPrecisionSelectOptions, L as DiffColumnMapEntry, Lt as createCellClassCurrent, M as getRowCountDiffStatus, Mt as buildDiffColumnDefinitions, N as rowCountDiffResultToDataFrame, Nt as DiffColumnConfig, O as validateToValueDiffGridInputs, Ot as toDataDiffGrid, P as rowCountResultToDataFrame, Pt as DiffColumnResult, Q as validatePrimaryKeys, Qt as getSimpleDisplayColumns, R as buildDiffRows, Rt as toDiffColumn, S as validateColumnDataAlignment, St as BuildSimpleColumnDefinitionsResult, T as validatePrimaryKeyConfig, Tt as DataDiffGridResult, U as buildJoinedColumnMap, Ut as DiffColumnRenderComponents, V as RowStats, Vt as DataFrameColumnGroupHeaderProps, W as buildMergedColumnMap, Wt as SimpleColumnRenderComponents, X as getPrimaryKeyValue, Xt as buildColumnOrder, Y as getHeaderCellClass, Yt as GridColumnsConfig, Z as toRenderedValue, Zt as getDisplayColumns, _ as formatTimestamp, _t as DataGridResult, a as hashStringToNumber, an as toCSV, at as DiffColumnConfigConfigured, b as deltaPercentageString, bt as toDataGrid, c as MergeStatus, cn as extractCSVData, ct as defaultRenderComponents, d as formatAsAbbreviatedNumber, dn as downloadCSV, dt as toDataGridConfigured, en as isPinnedColumn, et as toRowCountDiffDataGrid, f as formatIntervalMinMax, ft as toDiffColumnConfigured, g as formatTimeToNow, gt as toValueDiffGrid, h as formatDuration, ht as ValueDiffGridResult, i as getValueAtPath, in as generateTimestamp, it as BuildSimpleColumnDefinitionsConfigConfigured, j as calculateDelta, jt as DiffColumnDefinition, k as RowCountDiffRowData, kt as BuildDiffColumnDefinitionsConfig, l as mergeKeys, ln as supportsCSVExport, lt as defaultSimpleRenderComponents, m as TimeFormatStyle, mt as ToValueDiffGridConfig, n as dataFrameToRowObjects, nn as shouldIncludeColumn, nt as toRowCountDataGrid, o as keyToNumber, on as CSVData, ot as buildDiffColumnDefinitionsConfigured, p as formatNumber, pt as toValueDiffGridConfigured, q as formatSmartDecimal, qt as ColumnConfig, r as getCaseInsensitive, rn as generateCSVFilename, rt as BuildDiffColumnDefinitionsConfigConfigured, s as isSchemaChanged, sn as CSVExportOptions, st as buildSimpleColumnDefinitionsConfigured, t as getSettingsUrl, tn as isPrimaryKeyColumn, tt as RowCountDataGridResult, u as mergeKeysWithStatus, un as copyCSVToClipboard, ut as toDataDiffGridConfigured, v as formatSelectColumns, vt as QueryDataGridOptions, w as validateDataFrame, wt as buildSimpleColumnDefinitions, x as DataGridValidationError, xt as BuildSimpleColumnDefinitionsConfig, y as extractSchemas, yt as ToDataGridConfig, z as ColumnMapEntry, zt as CellRendererFunction } from "./index-h_fw6R9U.js";
|
|
7
|
+
export { BuildDiffColumnDefinitionsConfig, BuildDiffColumnDefinitionsConfigConfigured, BuildDiffColumnDefinitionsResult, BuildDiffRowsConfig, BuildDiffRowsResult, BuildSimpleColumnDefinitionsConfig, BuildSimpleColumnDefinitionsConfigConfigured, BuildSimpleColumnDefinitionsResult, CSVData, CSVExportOptions, CellRendererFunction, ColumnConfig, ColumnMapEntry, ColumnOrderConfig, ColumnPrecisionOption, ColumnRenderComponents, DataDiffGridResult, DataFrameColumnGroupHeaderProps, DataFrameColumnHeaderProps, DataGridResult, DataGridValidationError, DiffColumnConfig, DiffColumnConfigConfigured, DiffColumnDefinition, DiffColumnMapEntry, DiffColumnRenderComponents, DiffColumnResult, GridColumnsConfig, MergeColumnMapEntry, MergeStatus, QueryDataDiffGridOptions, QueryDataGridOptions, RecceColumnContext, RowCountDataGridResult, RowCountDiffDataGridResult, RowCountDiffRowData, RowCountRowData, RowStats, SimpleColumnDefinition, SimpleColumnRenderComponents, TimeFormatStyle, ToDataDiffGridConfig, ToDataGridConfig, ToValueDiffGridConfig, ValueDiffGridResult, buildColumnMap, buildColumnOrder, buildDiffColumnDefinitions, buildDiffColumnDefinitionsConfigured, buildDiffRows, buildJoinedColumnMap, buildMergedColumnMap, buildSimpleColumnDefinitions, buildSimpleColumnDefinitionsConfigured, calculateDelta, columnPrecisionSelectOptions, columnRenderedValue, copyCSVToClipboard, createCellClassBase, createCellClassCurrent, dataFrameToRowObjects, defaultRenderComponents, defaultSimpleRenderComponents, deltaPercentageString, determineRowStatus, downloadCSV, extractCSVData, extractSchemas, formatAsAbbreviatedNumber, formatDuration, formatIntervalMinMax, formatNumber, formatSelectColumns, formatSmartDecimal, formatTimeToNow, formatTimestamp, generateCSVFilename, generateTimestamp, getCaseInsensitive, getCellClass, getDisplayColumns, getHeaderCellClass, getPrimaryKeyValue, getRowCountDiffStatus, getSettingsUrl, getSimpleDisplayColumns, getValueAtPath, hashStringToNumber, isExcludedColumn, isPinnedColumn, isPrimaryKeyColumn, isSchemaChanged, keyToNumber, mergeKeys, mergeKeysWithStatus, rowCountDiffResultToDataFrame, rowCountResultToDataFrame, shouldIncludeColumn, supportsCSVExport, toCSV, toDataDiffGrid, toDataDiffGridConfigured, toDataGrid, toDataGridConfigured, toDiffColumn, toDiffColumnConfigured, toRenderedValue, toRowCountDataGrid, toRowCountDiffDataGrid, toValueDiffGrid, toValueDiffGridConfigured, validateColumnDataAlignment, validateColumns, validateDataFrame, validatePrimaryKeyConfig, validatePrimaryKeys, validateToDataDiffGridInputs, validateToDataGridInputs, validateToValueDiffGridInputs };
|
package/dist/utils.js
ADDED
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import{$ as e,A as t,C as n,Ct as r,D as i,E as a,F as o,G as s,H as c,I as l,J as u,K as d,L as f,M as p,N as m,O as h,P as g,Q as _,R as v,S as y,St as b,T as x,U as S,W as C,X as w,Y as T,Z as E,_ as D,_t as O,a as k,at as A,b as j,bt as M,c as N,ct as P,d as F,dt as I,et as L,f as R,ft as z,g as B,gt as V,h as H,ht as U,i as W,it as G,j as K,k as q,l as J,m as Y,mt as X,n as Z,nt as Q,o as $,ot as ee,p as te,pt as ne,q as re,r as ie,rt as ae,s as oe,st as se,t as ce,tt as le,u as ue,ut as de,v as fe,vt as pe,w as me,wt as he,x as ge,xt as _e,y as ve,yt as ye,z as be}from"./utils-CXWhfyxC.js";export{i as DataGridValidationError,c as buildColumnMap,I as buildColumnOrder,l as buildDiffColumnDefinitions,H as buildDiffColumnDefinitionsConfigured,o as buildDiffRows,S as buildJoinedColumnMap,C as buildMergedColumnMap,x as buildSimpleColumnDefinitions,B as buildSimpleColumnDefinitionsConfigured,ue as calculateDelta,de as columnPrecisionSelectOptions,s as columnRenderedValue,r as copyCSVToClipboard,f as createCellClassBase,v as createCellClassCurrent,G as dataFrameToRowObjects,D as defaultRenderComponents,fe as defaultSimpleRenderComponents,Y as deltaPercentageString,d as determineRowStatus,he as downloadCSV,_e as extractCSVData,oe as extractSchemas,le as formatAsAbbreviatedNumber,ie as formatDuration,Q as formatIntervalMinMax,ae as formatNumber,$ as formatSelectColumns,re as formatSmartDecimal,W as formatTimeToNow,k as formatTimestamp,pe as generateCSVFilename,ye as generateTimestamp,A as getCaseInsensitive,u as getCellClass,z as getDisplayColumns,T as getHeaderCellClass,w as getPrimaryKeyValue,F as getRowCountDiffStatus,ce as getSettingsUrl,ne as getSimpleDisplayColumns,ee as getValueAtPath,se as hashStringToNumber,X as isExcludedColumn,U as isPinnedColumn,V as isPrimaryKeyColumn,Z as isSchemaChanged,P as keyToNumber,e as mergeKeys,L as mergeKeysWithStatus,R as rowCountDiffResultToDataFrame,te as rowCountResultToDataFrame,O as shouldIncludeColumn,b as supportsCSVExport,M as toCSV,a as toDataDiffGrid,ve as toDataDiffGridConfigured,me as toDataGrid,j as toDataGridConfigured,be as toDiffColumn,ge as toDiffColumnConfigured,E as toRenderedValue,J as toRowCountDataGrid,N as toRowCountDiffDataGrid,n as toValueDiffGrid,y as toValueDiffGridConfigured,h as validateColumnDataAlignment,q as validateColumns,t as validateDataFrame,K as validatePrimaryKeyConfig,_ as validatePrimaryKeys,p as validateToDataDiffGridInputs,m as validateToDataGridInputs,g as validateToValueDiffGridInputs};
|