@datarecce/ui 0.1.30 → 0.1.32
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{state-lPCQsWy5.js → RecceCheckContext-BOGmP80K.js} +4367 -5089
- package/dist/RecceCheckContext-BOGmP80K.js.map +1 -0
- package/dist/{state-B9yzhuKs.mjs → RecceCheckContext-CwUCo6AW.mjs} +4273 -4541
- package/dist/RecceCheckContext-CwUCo6AW.mjs.map +1 -0
- package/dist/{state-DOUPNifc.css → RecceCheckContext-DPnWB_aU.css} +57 -57
- package/dist/RecceCheckContext-DPnWB_aU.css.map +1 -0
- package/dist/{state-IA7HWYOs.css → RecceCheckContext-DyxOeUsX.css} +57 -57
- package/dist/RecceCheckContext-DyxOeUsX.css.map +1 -0
- package/dist/api.d.mts +1 -1
- package/dist/api.d.ts +1 -1
- package/dist/api.js +65 -26
- package/dist/api.js.map +1 -0
- package/dist/api.mjs +44 -5
- package/dist/api.mjs.map +1 -0
- package/dist/{components-DCOI1YlQ.mjs → components-DQUwJlNQ.mjs} +20 -21
- package/dist/{components-DCOI1YlQ.mjs.map → components-DQUwJlNQ.mjs.map} +1 -1
- package/dist/{components-B-YxuuPz.js → components-uVp0e4cH.js} +231 -241
- package/dist/{components-B-YxuuPz.js.map → components-uVp0e4cH.js.map} +1 -1
- package/dist/components.d.mts +1 -1
- package/dist/components.d.ts +1 -1
- package/dist/components.js +38 -38
- package/dist/components.mjs +5 -5
- package/dist/{urls-B1Ymdoz-.mjs → const-CaIm1Z8g.mjs} +2 -6
- package/dist/const-CaIm1Z8g.mjs.map +1 -0
- package/dist/{urls-C4eAc82S.js → const-CvdZO0FN.js} +1 -11
- package/dist/const-CvdZO0FN.js.map +1 -0
- package/dist/global-styles.css +84 -0
- package/dist/global-styles.css.map +1 -0
- package/dist/global-styles.js +1 -0
- package/dist/global-styles.mjs +1 -0
- package/dist/{hooks-DjBNmTdh.mjs → hooks-C6Kma5ld.mjs} +2 -3
- package/dist/{hooks-DjBNmTdh.mjs.map → hooks-C6Kma5ld.mjs.map} +1 -1
- package/dist/hooks-CfZ4UBBF.js +40 -0
- package/dist/{hooks-B9hsc1oD.js.map → hooks-CfZ4UBBF.js.map} +1 -1
- package/dist/hooks.d.mts +1 -1
- package/dist/hooks.d.ts +1 -1
- package/dist/hooks.js +26 -26
- package/dist/hooks.mjs +4 -4
- package/dist/{html2canvas-pro.esm-WJxOmKlq.js → html2canvas-pro.esm-CsuSOHXp.js} +1 -1
- package/dist/{html2canvas-pro.esm-WJxOmKlq.js.map → html2canvas-pro.esm-CsuSOHXp.js.map} +1 -1
- package/dist/{html2canvas-pro.esm-BInzOtWO.mjs → html2canvas-pro.esm-E7kpobrC.mjs} +1 -1
- package/dist/{html2canvas-pro.esm-BInzOtWO.mjs.map → html2canvas-pro.esm-E7kpobrC.mjs.map} +1 -1
- package/dist/{index-BNUP2V_N.d.ts → index-B9lSPJTi.d.ts} +184 -2
- package/dist/index-B9lSPJTi.d.ts.map +1 -0
- package/dist/{index-DOPZuhD8.d.mts → index-DsCU2oGL.d.mts} +259 -77
- package/dist/index-DsCU2oGL.d.mts.map +1 -0
- package/dist/index.d.mts +2 -2
- package/dist/index.d.ts +2 -2
- package/dist/index.js +92 -84
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +12 -10
- package/dist/index.mjs.map +1 -1
- package/dist/{mui-theme-B2wm_cvZ.js → mui-theme-iBHkjXJq.js} +2 -2
- package/dist/{mui-theme-B2wm_cvZ.js.map → mui-theme-iBHkjXJq.js.map} +1 -1
- package/dist/state-CTITyT0R.js +795 -0
- package/dist/state-CTITyT0R.js.map +1 -0
- package/dist/state-Sc2b4jri.mjs +382 -0
- package/dist/state-Sc2b4jri.mjs.map +1 -0
- package/dist/styles.css +5 -0
- package/dist/theme.d.mts +2 -185
- package/dist/theme.d.ts +2 -185
- package/dist/theme.js +1 -1
- package/dist/{tooltipMessage-DosF13kZ.js → tooltipMessage-BC5W7H3X.js} +1 -1
- package/dist/{tooltipMessage-DosF13kZ.js.map → tooltipMessage-BC5W7H3X.js.map} +1 -1
- package/dist/{tooltipMessage-B--I3p1V.mjs → tooltipMessage-B_xMIKWL.mjs} +1 -1
- package/dist/{tooltipMessage-B--I3p1V.mjs.map → tooltipMessage-B_xMIKWL.mjs.map} +1 -1
- package/dist/types.d.mts +1 -1
- package/dist/types.d.ts +1 -1
- package/dist/types.js +5 -4
- package/dist/types.mjs +3 -2
- package/dist/urls-BQW5wjg-.js +13 -0
- package/dist/urls-BQW5wjg-.js.map +1 -0
- package/dist/urls-DT7FVEcS.mjs +7 -0
- package/dist/urls-DT7FVEcS.mjs.map +1 -0
- package/dist/version-B9s8yne-.js +300 -0
- package/dist/version-B9s8yne-.js.map +1 -0
- package/dist/version-DP1kU_7v.mjs +162 -0
- package/dist/version-DP1kU_7v.mjs.map +1 -0
- package/package.json +5 -3
- package/recce-source/.editorconfig +26 -0
- package/recce-source/.flake8 +37 -0
- package/recce-source/.github/ISSUE_TEMPLATE/bug_report.yml +67 -0
- package/recce-source/.github/ISSUE_TEMPLATE/custom.md +10 -0
- package/recce-source/.github/ISSUE_TEMPLATE/feature_request.yml +42 -0
- package/recce-source/.github/PULL_REQUEST_TEMPLATE.md +21 -0
- package/recce-source/.github/copilot-instructions.md +331 -0
- package/recce-source/.github/instructions/backend-instructions.md +541 -0
- package/recce-source/.github/instructions/frontend-instructions.md +317 -0
- package/recce-source/.github/workflows/build-statics.yaml +72 -0
- package/recce-source/.github/workflows/bump.yaml +48 -0
- package/recce-source/.github/workflows/integration-tests-cloud.yaml +92 -0
- package/recce-source/.github/workflows/integration-tests-sqlmesh.yaml +33 -0
- package/recce-source/.github/workflows/integration-tests.yaml +52 -0
- package/recce-source/.github/workflows/nightly.yaml +246 -0
- package/recce-source/.github/workflows/release.yaml +196 -0
- package/recce-source/.github/workflows/tests-js.yaml +58 -0
- package/recce-source/.github/workflows/tests-python.yaml +128 -0
- package/recce-source/.pre-commit-config.yaml +26 -0
- package/recce-source/CLAUDE.md +483 -0
- package/recce-source/CODE_OF_CONDUCT.md +128 -0
- package/recce-source/CONTRIBUTING.md +107 -0
- package/recce-source/LICENSE +201 -0
- package/recce-source/Makefile +126 -0
- package/recce-source/README.md +182 -0
- package/recce-source/RECCE_CLOUD.md +81 -0
- package/recce-source/SECURITY.md +25 -0
- package/recce-source/docs/PACKAGING.md +340 -0
- package/recce-source/docs/README.md +1 -0
- package/recce-source/integration_tests/dbt/dbt_project.yml +26 -0
- package/recce-source/integration_tests/dbt/models/customers.sql +69 -0
- package/recce-source/integration_tests/dbt/models/docs.md +14 -0
- package/recce-source/integration_tests/dbt/models/orders.sql +56 -0
- package/recce-source/integration_tests/dbt/models/schema.yml +82 -0
- package/recce-source/integration_tests/dbt/models/staging/schema.yml +31 -0
- package/recce-source/integration_tests/dbt/models/staging/stg_customers.sql +22 -0
- package/recce-source/integration_tests/dbt/models/staging/stg_orders.sql +23 -0
- package/recce-source/integration_tests/dbt/models/staging/stg_payments.sql +25 -0
- package/recce-source/integration_tests/dbt/packages.yml +7 -0
- package/recce-source/integration_tests/dbt/profiles.yml +8 -0
- package/recce-source/integration_tests/dbt/seeds/raw_customers.csv +101 -0
- package/recce-source/integration_tests/dbt/seeds/raw_orders.csv +100 -0
- package/recce-source/integration_tests/dbt/seeds/raw_payments.csv +114 -0
- package/recce-source/integration_tests/dbt/seeds/raw_statuses.csv +5 -0
- package/recce-source/integration_tests/dbt/smoke_test.sh +72 -0
- package/recce-source/integration_tests/dbt/smoke_test_cloud.sh +71 -0
- package/recce-source/integration_tests/sqlmesh/__init__.py +0 -0
- package/recce-source/integration_tests/sqlmesh/audits/assert_item_price_above_zero.sql +9 -0
- package/recce-source/integration_tests/sqlmesh/audits/items.sql +7 -0
- package/recce-source/integration_tests/sqlmesh/audits/order_items.sql +7 -0
- package/recce-source/integration_tests/sqlmesh/config.py +171 -0
- package/recce-source/integration_tests/sqlmesh/helper.py +20 -0
- 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 +8 -0
- package/recce-source/integration_tests/sqlmesh/macros/macros.sql +8 -0
- package/recce-source/integration_tests/sqlmesh/macros/utils.py +11 -0
- package/recce-source/integration_tests/sqlmesh/metrics/metrics.sql +25 -0
- package/recce-source/integration_tests/sqlmesh/models/customer_revenue_by_day.sql +41 -0
- package/recce-source/integration_tests/sqlmesh/models/customer_revenue_lifetime.sql +60 -0
- package/recce-source/integration_tests/sqlmesh/models/customers.sql +32 -0
- package/recce-source/integration_tests/sqlmesh/models/items.py +95 -0
- package/recce-source/integration_tests/sqlmesh/models/marketing.sql +15 -0
- package/recce-source/integration_tests/sqlmesh/models/order_items.py +95 -0
- package/recce-source/integration_tests/sqlmesh/models/orders.py +70 -0
- package/recce-source/integration_tests/sqlmesh/models/raw_marketing.py +62 -0
- package/recce-source/integration_tests/sqlmesh/models/top_waiters.sql +23 -0
- package/recce-source/integration_tests/sqlmesh/models/waiter_as_customer_by_day.sql +29 -0
- package/recce-source/integration_tests/sqlmesh/models/waiter_names.sql +10 -0
- package/recce-source/integration_tests/sqlmesh/models/waiter_revenue_by_day.sql +29 -0
- package/recce-source/integration_tests/sqlmesh/models/waiters.py +62 -0
- package/recce-source/integration_tests/sqlmesh/prep_env.sh +16 -0
- package/recce-source/integration_tests/sqlmesh/schema.yaml +5 -0
- package/recce-source/integration_tests/sqlmesh/seeds/waiter_names.csv +11 -0
- package/recce-source/integration_tests/sqlmesh/test_server.sh +29 -0
- package/recce-source/integration_tests/sqlmesh/tests/test_customer_revenue_by_day.yaml +63 -0
- package/recce-source/integration_tests/sqlmesh/tests/test_order_items.yaml +72 -0
- package/recce-source/js/.editorconfig +27 -0
- package/recce-source/js/.env.development +5 -0
- package/recce-source/js/.husky/pre-commit +29 -0
- package/recce-source/js/.nvmrc +1 -0
- package/recce-source/js/README.md +39 -0
- package/recce-source/js/app/(mainComponents)/DisplayModeToggle.tsx +65 -0
- package/recce-source/js/app/(mainComponents)/NavBar.tsx +228 -0
- package/recce-source/js/app/(mainComponents)/RecceVersionBadge.tsx +107 -0
- package/recce-source/js/app/(mainComponents)/TopBar.tsx +252 -0
- package/recce-source/js/app/@lineage/default.tsx +20 -0
- package/recce-source/js/app/@lineage/page.tsx +14 -0
- package/recce-source/js/app/MainLayout.tsx +170 -0
- package/recce-source/js/app/Providers.tsx +49 -0
- package/recce-source/js/app/checks/page.tsx +296 -0
- package/recce-source/js/app/error.tsx +93 -0
- package/recce-source/js/app/favicon.ico +0 -0
- package/recce-source/js/app/global-error.tsx +115 -0
- package/recce-source/js/app/global.css +82 -0
- package/recce-source/js/app/layout.tsx +48 -0
- package/recce-source/js/app/lineage/page.tsx +15 -0
- package/recce-source/js/app/page.tsx +12 -0
- package/recce-source/js/app/query/page.tsx +8 -0
- package/recce-source/js/biome.json +313 -0
- package/recce-source/js/jest.config.js +34 -0
- package/recce-source/js/jest.globals.d.ts +32 -0
- package/recce-source/js/jest.setup.js +91 -0
- package/recce-source/js/next.config.js +16 -0
- package/recce-source/js/package-lock.json +13843 -0
- package/recce-source/js/package.json +123 -0
- package/recce-source/js/pnpm-lock.yaml +9235 -0
- package/recce-source/js/pnpm-workspace.yaml +6 -0
- package/recce-source/js/postcss.config.js +5 -0
- package/recce-source/js/public/auth_callback.html +68 -0
- 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 +4 -0
- package/recce-source/js/public/logo/recce-logo-white.png +0 -0
- package/recce-source/js/src/components/AuthModal/AuthModal.tsx +202 -0
- package/recce-source/js/src/components/app/AvatarDropdown.tsx +159 -0
- package/recce-source/js/src/components/app/EnvInfo.tsx +357 -0
- package/recce-source/js/src/components/app/Filename.tsx +388 -0
- package/recce-source/js/src/components/app/SetupConnectionPopover.tsx +91 -0
- package/recce-source/js/src/components/app/StateExporter.tsx +57 -0
- package/recce-source/js/src/components/app/StateImporter.tsx +198 -0
- package/recce-source/js/src/components/app/StateSharing.tsx +145 -0
- package/recce-source/js/src/components/app/StateSynchronizer.tsx +205 -0
- package/recce-source/js/src/components/charts/HistogramChart.tsx +291 -0
- package/recce-source/js/src/components/charts/SquareIcon.tsx +51 -0
- package/recce-source/js/src/components/charts/TopKSummaryList.tsx +457 -0
- package/recce-source/js/src/components/charts/chartTheme.ts +74 -0
- package/recce-source/js/src/components/check/CheckBreadcrumb.tsx +97 -0
- package/recce-source/js/src/components/check/CheckDescription.tsx +134 -0
- package/recce-source/js/src/components/check/CheckDetail.tsx +797 -0
- package/recce-source/js/src/components/check/CheckEmptyState.tsx +84 -0
- package/recce-source/js/src/components/check/CheckList.tsx +320 -0
- package/recce-source/js/src/components/check/LineageDiffView.tsx +32 -0
- package/recce-source/js/src/components/check/PresetCheckTemplateView.tsx +48 -0
- package/recce-source/js/src/components/check/SchemaDiffView.tsx +290 -0
- package/recce-source/js/src/components/check/check.ts +25 -0
- package/recce-source/js/src/components/check/timeline/CheckTimeline.tsx +163 -0
- package/recce-source/js/src/components/check/timeline/CommentInput.tsx +84 -0
- package/recce-source/js/src/components/check/timeline/TimelineEvent.tsx +468 -0
- package/recce-source/js/src/components/check/timeline/index.ts +12 -0
- package/recce-source/js/src/components/check/utils.ts +12 -0
- package/recce-source/js/src/components/data-grid/ScreenshotDataGrid.tsx +333 -0
- package/recce-source/js/src/components/data-grid/agGridStyles.css +55 -0
- package/recce-source/js/src/components/data-grid/agGridTheme.ts +43 -0
- package/recce-source/js/src/components/editor/CodeEditor.tsx +107 -0
- package/recce-source/js/src/components/editor/DiffEditor.tsx +162 -0
- package/recce-source/js/src/components/editor/index.ts +12 -0
- package/recce-source/js/src/components/errorboundary/ErrorBoundary.tsx +87 -0
- package/recce-source/js/src/components/histogram/HistogramDiffForm.tsx +147 -0
- package/recce-source/js/src/components/histogram/HistogramDiffResultView.tsx +63 -0
- package/recce-source/js/src/components/icons/index.tsx +142 -0
- package/recce-source/js/src/components/lineage/ActionControl.tsx +63 -0
- package/recce-source/js/src/components/lineage/ActionTag.tsx +141 -0
- package/recce-source/js/src/components/lineage/ChangeStatusLegend.tsx +46 -0
- package/recce-source/js/src/components/lineage/ColumnLevelLineageControl.tsx +327 -0
- package/recce-source/js/src/components/lineage/ColumnLevelLineageLegend.tsx +57 -0
- package/recce-source/js/src/components/lineage/GraphColumnNode.tsx +199 -0
- package/recce-source/js/src/components/lineage/GraphEdge.tsx +59 -0
- package/recce-source/js/src/components/lineage/GraphNode.tsx +555 -0
- package/recce-source/js/src/components/lineage/LineagePage.tsx +10 -0
- package/recce-source/js/src/components/lineage/LineageView.tsx +1384 -0
- package/recce-source/js/src/components/lineage/LineageViewContext.tsx +86 -0
- package/recce-source/js/src/components/lineage/LineageViewContextMenu.tsx +637 -0
- package/recce-source/js/src/components/lineage/LineageViewNotification.tsx +64 -0
- package/recce-source/js/src/components/lineage/LineageViewTopBar.tsx +596 -0
- package/recce-source/js/src/components/lineage/NodeSqlView.tsx +136 -0
- package/recce-source/js/src/components/lineage/NodeTag.tsx +278 -0
- package/recce-source/js/src/components/lineage/NodeView.tsx +642 -0
- package/recce-source/js/src/components/lineage/SandboxView.tsx +436 -0
- package/recce-source/js/src/components/lineage/ServerDisconnectedModalContent.tsx +105 -0
- package/recce-source/js/src/components/lineage/SetupConnectionBanner.tsx +52 -0
- package/recce-source/js/src/components/lineage/SingleEnvironmentQueryView.tsx +152 -0
- package/recce-source/js/src/components/lineage/graph.test.ts +31 -0
- package/recce-source/js/src/components/lineage/graph.ts +58 -0
- package/recce-source/js/src/components/lineage/lineage.test.ts +169 -0
- package/recce-source/js/src/components/lineage/lineage.ts +521 -0
- package/recce-source/js/src/components/lineage/styles.css +42 -0
- package/recce-source/js/src/components/lineage/styles.tsx +165 -0
- package/recce-source/js/src/components/lineage/useMultiNodesAction.ts +352 -0
- package/recce-source/js/src/components/lineage/useValueDiffAlertDialog.tsx +108 -0
- package/recce-source/js/src/components/onboarding-guide/Notification.tsx +62 -0
- package/recce-source/js/src/components/profile/ProfileDiffForm.tsx +134 -0
- package/recce-source/js/src/components/profile/ProfileDiffResultView.tsx +245 -0
- package/recce-source/js/src/components/query/ChangedOnlyCheckbox.tsx +29 -0
- package/recce-source/js/src/components/query/DiffText.tsx +120 -0
- package/recce-source/js/src/components/query/QueryDiffResultView.tsx +470 -0
- package/recce-source/js/src/components/query/QueryForm.tsx +80 -0
- package/recce-source/js/src/components/query/QueryPage.tsx +282 -0
- package/recce-source/js/src/components/query/QueryResultView.tsx +180 -0
- package/recce-source/js/src/components/query/SetupConnectionGuide.tsx +57 -0
- package/recce-source/js/src/components/query/SqlEditor.tsx +245 -0
- package/recce-source/js/src/components/query/ToggleSwitch.tsx +84 -0
- package/recce-source/js/src/components/query/styles.css +21 -0
- package/recce-source/js/src/components/routing/DirectUrlAccess.test.tsx +428 -0
- package/recce-source/js/src/components/routing/LineageStatePreservation.test.tsx +311 -0
- package/recce-source/js/src/components/routing/Navigation.test.tsx +256 -0
- package/recce-source/js/src/components/rowcount/RowCountDiffResultView.tsx +109 -0
- package/recce-source/js/src/components/rowcount/delta.ts +11 -0
- package/recce-source/js/src/components/run/RunList.tsx +303 -0
- package/recce-source/js/src/components/run/RunModal.tsx +191 -0
- package/recce-source/js/src/components/run/RunPage.tsx +26 -0
- package/recce-source/js/src/components/run/RunResultPane.tsx +454 -0
- package/recce-source/js/src/components/run/RunStatusAndDate.tsx +106 -0
- package/recce-source/js/src/components/run/RunToolbar.tsx +70 -0
- package/recce-source/js/src/components/run/RunView.tsx +196 -0
- package/recce-source/js/src/components/run/registry.ts +214 -0
- package/recce-source/js/src/components/run/types.ts +14 -0
- package/recce-source/js/src/components/schema/ColumnNameCell.test.tsx +169 -0
- package/recce-source/js/src/components/schema/ColumnNameCell.tsx +198 -0
- package/recce-source/js/src/components/schema/SchemaView.tsx +337 -0
- package/recce-source/js/src/components/schema/schemaDiff.ts +32 -0
- package/recce-source/js/src/components/schema/style.css +134 -0
- package/recce-source/js/src/components/screenshot/ScreenshotBox.tsx +39 -0
- package/recce-source/js/src/components/shared/HistoryToggle.tsx +35 -0
- package/recce-source/js/src/components/split/Split.tsx +40 -0
- package/recce-source/js/src/components/split/styles.css +24 -0
- package/recce-source/js/src/components/summary/ChangeSummary.tsx +264 -0
- package/recce-source/js/src/components/summary/SchemaSummary.tsx +123 -0
- package/recce-source/js/src/components/summary/SummaryView.tsx +29 -0
- package/recce-source/js/src/components/timeout/IdleTimeoutBadge.tsx +48 -0
- package/recce-source/js/src/components/top-k/TopKDiffForm.tsx +58 -0
- package/recce-source/js/src/components/top-k/TopKDiffResultView.tsx +73 -0
- package/recce-source/js/src/components/ui/dataGrid/DataFrameColumnGroupHeader.tsx +228 -0
- package/recce-source/js/src/components/ui/dataGrid/DataFrameColumnHeader.tsx +113 -0
- package/recce-source/js/src/components/ui/dataGrid/defaultRenderCell.tsx +72 -0
- package/recce-source/js/src/components/ui/dataGrid/index.ts +23 -0
- package/recce-source/js/src/components/ui/dataGrid/inlineRenderCell.test.tsx +607 -0
- package/recce-source/js/src/components/ui/dataGrid/inlineRenderCell.tsx +211 -0
- package/recce-source/js/src/components/ui/dataGrid/schemaCells.test.tsx +452 -0
- package/recce-source/js/src/components/ui/dataGrid/schemaCells.tsx +142 -0
- package/recce-source/js/src/components/ui/dataGrid/valueDiffCells.test.tsx +178 -0
- package/recce-source/js/src/components/ui/dataGrid/valueDiffCells.tsx +275 -0
- package/recce-source/js/src/components/ui/markdown/ExternalLinkConfirmDialog.tsx +134 -0
- package/recce-source/js/src/components/ui/markdown/MarkdownContent.tsx +364 -0
- package/recce-source/js/src/components/ui/mui/index.ts +13 -0
- package/recce-source/js/src/components/ui/mui-provider.tsx +67 -0
- package/recce-source/js/src/components/ui/mui-theme.ts +1039 -0
- package/recce-source/js/src/components/ui/mui-utils.ts +113 -0
- package/recce-source/js/src/components/ui/toaster.tsx +288 -0
- package/recce-source/js/src/components/valuediff/ValueDiffDetailResultView.tsx +217 -0
- package/recce-source/js/src/components/valuediff/ValueDiffForm.tsx +246 -0
- package/recce-source/js/src/components/valuediff/ValueDiffResultView.tsx +82 -0
- package/recce-source/js/src/components/valuediff/shared.ts +33 -0
- package/recce-source/js/src/constants/tooltipMessage.ts +3 -0
- package/recce-source/js/src/constants/urls.ts +1 -0
- package/recce-source/js/src/lib/UrlHash.ts +12 -0
- package/recce-source/js/src/lib/api/adhocQuery.ts +70 -0
- package/recce-source/js/src/lib/api/axiosClient.ts +9 -0
- package/recce-source/js/src/lib/api/cacheKeys.ts +13 -0
- package/recce-source/js/src/lib/api/checkEvents.ts +252 -0
- package/recce-source/js/src/lib/api/checks.ts +129 -0
- package/recce-source/js/src/lib/api/cll.ts +53 -0
- package/recce-source/js/src/lib/api/connectToCloud.ts +13 -0
- package/recce-source/js/src/lib/api/flag.ts +37 -0
- package/recce-source/js/src/lib/api/info.ts +198 -0
- package/recce-source/js/src/lib/api/instanceInfo.ts +25 -0
- package/recce-source/js/src/lib/api/keepAlive.ts +108 -0
- package/recce-source/js/src/lib/api/lineagecheck.ts +35 -0
- package/recce-source/js/src/lib/api/localStorageKeys.ts +7 -0
- package/recce-source/js/src/lib/api/models.ts +59 -0
- package/recce-source/js/src/lib/api/profile.ts +65 -0
- package/recce-source/js/src/lib/api/rowcount.ts +19 -0
- package/recce-source/js/src/lib/api/runs.ts +174 -0
- package/recce-source/js/src/lib/api/schemacheck.ts +31 -0
- package/recce-source/js/src/lib/api/select.ts +25 -0
- package/recce-source/js/src/lib/api/sessionStorageKeys.ts +8 -0
- package/recce-source/js/src/lib/api/state.ts +117 -0
- package/recce-source/js/src/lib/api/track.ts +281 -0
- package/recce-source/js/src/lib/api/types.ts +284 -0
- package/recce-source/js/src/lib/api/user.ts +42 -0
- package/recce-source/js/src/lib/api/valuediff.ts +46 -0
- package/recce-source/js/src/lib/api/version.ts +40 -0
- package/recce-source/js/src/lib/const.ts +9 -0
- package/recce-source/js/src/lib/dataGrid/crossFunctionConsistency.test.ts +626 -0
- package/recce-source/js/src/lib/dataGrid/dataGridFactory.test.ts +2140 -0
- package/recce-source/js/src/lib/dataGrid/dataGridFactory.ts +397 -0
- package/recce-source/js/src/lib/dataGrid/generators/rowCountUtils.test.ts +132 -0
- package/recce-source/js/src/lib/dataGrid/generators/rowCountUtils.ts +126 -0
- package/recce-source/js/src/lib/dataGrid/generators/toDataDiffGrid.test.ts +1627 -0
- package/recce-source/js/src/lib/dataGrid/generators/toDataDiffGrid.ts +140 -0
- package/recce-source/js/src/lib/dataGrid/generators/toDataGrid.ts +67 -0
- package/recce-source/js/src/lib/dataGrid/generators/toRowCountDataGrid.test.ts +142 -0
- package/recce-source/js/src/lib/dataGrid/generators/toRowCountDataGrid.ts +71 -0
- package/recce-source/js/src/lib/dataGrid/generators/toRowCountDiffDataGrid.test.ts +258 -0
- package/recce-source/js/src/lib/dataGrid/generators/toRowCountDiffDataGrid.ts +153 -0
- package/recce-source/js/src/lib/dataGrid/generators/toSchemaDataGrid.test.ts +951 -0
- package/recce-source/js/src/lib/dataGrid/generators/toSchemaDataGrid.ts +221 -0
- package/recce-source/js/src/lib/dataGrid/generators/toValueDataGrid.test.ts +395 -0
- package/recce-source/js/src/lib/dataGrid/generators/toValueDataGrid.ts +184 -0
- package/recce-source/js/src/lib/dataGrid/generators/toValueDiffGrid.test.ts +884 -0
- package/recce-source/js/src/lib/dataGrid/generators/toValueDiffGrid.ts +113 -0
- package/recce-source/js/src/lib/dataGrid/index.ts +51 -0
- package/recce-source/js/src/lib/dataGrid/propertyBased.test.ts +858 -0
- package/recce-source/js/src/lib/dataGrid/shared/columnBuilders.test.ts +482 -0
- package/recce-source/js/src/lib/dataGrid/shared/columnBuilders.ts +345 -0
- package/recce-source/js/src/lib/dataGrid/shared/dataTypeEdgeCases.test.ts +698 -0
- package/recce-source/js/src/lib/dataGrid/shared/diffColumnBuilder.test.tsx +820 -0
- package/recce-source/js/src/lib/dataGrid/shared/diffColumnBuilder.tsx +277 -0
- package/recce-source/js/src/lib/dataGrid/shared/gridUtils.test.ts +785 -0
- package/recce-source/js/src/lib/dataGrid/shared/gridUtils.ts +370 -0
- package/recce-source/js/src/lib/dataGrid/shared/index.ts +81 -0
- package/recce-source/js/src/lib/dataGrid/shared/rowBuilders.test.ts +909 -0
- package/recce-source/js/src/lib/dataGrid/shared/rowBuilders.ts +325 -0
- package/recce-source/js/src/lib/dataGrid/shared/simpleColumnBuilder.tsx +240 -0
- package/recce-source/js/src/lib/dataGrid/shared/toDiffColumn.test.tsx +719 -0
- package/recce-source/js/src/lib/dataGrid/shared/toDiffColumn.tsx +231 -0
- package/recce-source/js/src/lib/dataGrid/shared/validation.test.ts +559 -0
- package/recce-source/js/src/lib/dataGrid/shared/validation.ts +367 -0
- package/recce-source/js/src/lib/dataGrid/warehouseNamingConventions.test.ts +1117 -0
- package/recce-source/js/src/lib/formatSelect.ts +50 -0
- package/recce-source/js/src/lib/hooks/ApiConfigContext.tsx +181 -0
- package/recce-source/js/src/lib/hooks/IdleTimeoutContext.tsx +177 -0
- package/recce-source/js/src/lib/hooks/LineageGraphContext.tsx +512 -0
- package/recce-source/js/src/lib/hooks/RecceActionContext.tsx +269 -0
- package/recce-source/js/src/lib/hooks/RecceCheckContext.tsx +33 -0
- package/recce-source/js/src/lib/hooks/RecceContextProvider.tsx +54 -0
- package/recce-source/js/src/lib/hooks/RecceInstanceContext.tsx +129 -0
- package/recce-source/js/src/lib/hooks/RecceQueryContext.tsx +98 -0
- package/recce-source/js/src/lib/hooks/RecceShareStateContext.tsx +59 -0
- package/recce-source/js/src/lib/hooks/ScreenShot.tsx +399 -0
- package/recce-source/js/src/lib/hooks/useAppRouter.test.ts +211 -0
- package/recce-source/js/src/lib/hooks/useAppRouter.ts +200 -0
- package/recce-source/js/src/lib/hooks/useCheckEvents.ts +99 -0
- package/recce-source/js/src/lib/hooks/useCheckToast.tsx +14 -0
- package/recce-source/js/src/lib/hooks/useClipBoardToast.tsx +27 -0
- package/recce-source/js/src/lib/hooks/useCountdownToast.tsx +102 -0
- package/recce-source/js/src/lib/hooks/useFeedbackCollectionToast.tsx +130 -0
- package/recce-source/js/src/lib/hooks/useGuideToast.tsx +45 -0
- package/recce-source/js/src/lib/hooks/useIdleDetection.tsx +185 -0
- package/recce-source/js/src/lib/hooks/useModelColumns.tsx +113 -0
- package/recce-source/js/src/lib/hooks/useRecceInstanceInfo.tsx +13 -0
- package/recce-source/js/src/lib/hooks/useRecceServerFlag.tsx +13 -0
- package/recce-source/js/src/lib/hooks/useRun.tsx +89 -0
- package/recce-source/js/src/lib/hooks/useThemeColors.ts +115 -0
- package/recce-source/js/src/lib/mergeKeys.test.ts +89 -0
- package/recce-source/js/src/lib/mergeKeys.ts +86 -0
- package/recce-source/js/src/lib/result/ResultErrorFallback.tsx +9 -0
- package/recce-source/js/src/lib/utils/formatTime.ts +84 -0
- package/recce-source/js/src/lib/utils/urls.ts +16 -0
- package/recce-source/js/src/utils/DropdownValuesInput.tsx +297 -0
- package/recce-source/js/src/utils/formatters.tsx +237 -0
- package/recce-source/js/src/utils/transforms.ts +81 -0
- package/recce-source/js/tsconfig.json +47 -0
- package/recce-source/macros/README.md +8 -0
- package/recce-source/macros/recce_athena.sql +73 -0
- package/recce-source/pyproject.toml +109 -0
- package/recce-source/recce/VERSION +1 -0
- package/recce-source/recce/__init__.py +84 -0
- package/recce-source/recce/adapter/__init__.py +0 -0
- package/recce-source/recce/adapter/base.py +109 -0
- package/recce-source/recce/adapter/dbt_adapter/__init__.py +1699 -0
- package/recce-source/recce/adapter/dbt_adapter/dbt_version.py +42 -0
- package/recce-source/recce/adapter/sqlmesh_adapter.py +141 -0
- package/recce-source/recce/apis/__init__.py +0 -0
- package/recce-source/recce/apis/check_api.py +203 -0
- package/recce-source/recce/apis/check_events_api.py +353 -0
- package/recce-source/recce/apis/check_func.py +130 -0
- package/recce-source/recce/apis/run_api.py +130 -0
- package/recce-source/recce/apis/run_func.py +258 -0
- package/recce-source/recce/artifact.py +266 -0
- package/recce-source/recce/cli.py +1846 -0
- package/recce-source/recce/config.py +127 -0
- package/recce-source/recce/connect_to_cloud.py +138 -0
- package/recce-source/recce/core.py +334 -0
- package/recce-source/recce/diff.py +26 -0
- package/recce-source/recce/event/CONFIG +1 -0
- package/recce-source/recce/event/SENTRY_DNS +1 -0
- package/recce-source/recce/event/__init__.py +304 -0
- package/recce-source/recce/event/collector.py +184 -0
- package/recce-source/recce/event/track.py +158 -0
- package/recce-source/recce/exceptions.py +21 -0
- package/recce-source/recce/git.py +77 -0
- package/recce-source/recce/github.py +222 -0
- package/recce-source/recce/mcp_server.py +861 -0
- package/recce-source/recce/models/__init__.py +6 -0
- package/recce-source/recce/models/check.py +473 -0
- package/recce-source/recce/models/run.py +46 -0
- package/recce-source/recce/models/types.py +218 -0
- package/recce-source/recce/pull_request.py +124 -0
- package/recce-source/recce/run.py +390 -0
- package/recce-source/recce/server.py +877 -0
- package/recce-source/recce/state/__init__.py +31 -0
- package/recce-source/recce/state/cloud.py +644 -0
- package/recce-source/recce/state/const.py +26 -0
- package/recce-source/recce/state/local.py +56 -0
- package/recce-source/recce/state/state.py +119 -0
- package/recce-source/recce/state/state_loader.py +174 -0
- package/recce-source/recce/summary.py +575 -0
- package/recce-source/recce/tasks/__init__.py +23 -0
- package/recce-source/recce/tasks/core.py +134 -0
- package/recce-source/recce/tasks/dataframe.py +170 -0
- package/recce-source/recce/tasks/histogram.py +433 -0
- package/recce-source/recce/tasks/lineage.py +19 -0
- package/recce-source/recce/tasks/profile.py +298 -0
- package/recce-source/recce/tasks/query.py +450 -0
- package/recce-source/recce/tasks/rowcount.py +277 -0
- package/recce-source/recce/tasks/schema.py +65 -0
- package/recce-source/recce/tasks/top_k.py +172 -0
- package/recce-source/recce/tasks/utils.py +147 -0
- package/recce-source/recce/tasks/valuediff.py +497 -0
- package/recce-source/recce/util/__init__.py +4 -0
- package/recce-source/recce/util/api_token.py +80 -0
- package/recce-source/recce/util/breaking.py +330 -0
- package/recce-source/recce/util/cache.py +25 -0
- package/recce-source/recce/util/cll.py +355 -0
- package/recce-source/recce/util/cloud/__init__.py +15 -0
- package/recce-source/recce/util/cloud/base.py +115 -0
- package/recce-source/recce/util/cloud/check_events.py +190 -0
- package/recce-source/recce/util/cloud/checks.py +242 -0
- package/recce-source/recce/util/io.py +120 -0
- package/recce-source/recce/util/lineage.py +83 -0
- package/recce-source/recce/util/logger.py +25 -0
- package/recce-source/recce/util/onboarding_state.py +45 -0
- package/recce-source/recce/util/perf_tracking.py +85 -0
- package/recce-source/recce/util/pydantic_model.py +22 -0
- package/recce-source/recce/util/recce_cloud.py +454 -0
- package/recce-source/recce/util/singleton.py +18 -0
- package/recce-source/recce/util/startup_perf.py +121 -0
- package/recce-source/recce/yaml/__init__.py +58 -0
- package/recce-source/recce_cloud/README.md +780 -0
- package/recce-source/recce_cloud/VERSION +1 -0
- package/recce-source/recce_cloud/__init__.py +24 -0
- package/recce-source/recce_cloud/api/__init__.py +17 -0
- package/recce-source/recce_cloud/api/base.py +132 -0
- package/recce-source/recce_cloud/api/client.py +186 -0
- package/recce-source/recce_cloud/api/exceptions.py +26 -0
- package/recce-source/recce_cloud/api/factory.py +63 -0
- package/recce-source/recce_cloud/api/github.py +106 -0
- package/recce-source/recce_cloud/api/gitlab.py +111 -0
- package/recce-source/recce_cloud/artifact.py +57 -0
- package/recce-source/recce_cloud/ci_providers/__init__.py +9 -0
- package/recce-source/recce_cloud/ci_providers/base.py +82 -0
- package/recce-source/recce_cloud/ci_providers/detector.py +147 -0
- package/recce-source/recce_cloud/ci_providers/github_actions.py +136 -0
- package/recce-source/recce_cloud/ci_providers/gitlab_ci.py +130 -0
- package/recce-source/recce_cloud/cli.py +434 -0
- package/recce-source/recce_cloud/download.py +230 -0
- package/recce-source/recce_cloud/hatch_build.py +20 -0
- package/recce-source/recce_cloud/pyproject.toml +49 -0
- package/recce-source/recce_cloud/upload.py +214 -0
- 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 +17 -0
- package/recce-source/tests/adapter/dbt_adapter/dbt_test_helper.py +298 -0
- package/recce-source/tests/adapter/dbt_adapter/test_dbt_adapter.py +25 -0
- package/recce-source/tests/adapter/dbt_adapter/test_dbt_cll.py +717 -0
- package/recce-source/tests/adapter/dbt_adapter/test_proj/dbt_project.yml +4 -0
- package/recce-source/tests/adapter/dbt_adapter/test_proj/manifest.json +1 -0
- package/recce-source/tests/adapter/dbt_adapter/test_proj/package-lock.yml +8 -0
- package/recce-source/tests/adapter/dbt_adapter/test_proj/packages.yml +7 -0
- package/recce-source/tests/adapter/dbt_adapter/test_proj/profiles.yml +6 -0
- package/recce-source/tests/adapter/dbt_adapter/test_selector.py +205 -0
- package/recce-source/tests/apis/__init__.py +0 -0
- package/recce-source/tests/apis/row_count_diff.json +59 -0
- package/recce-source/tests/apis/test_check_events_api.py +615 -0
- package/recce-source/tests/apis/test_run_func.py +433 -0
- package/recce-source/tests/catalog.json +527 -0
- package/recce-source/tests/data/manifest/base/catalog.json +1 -0
- package/recce-source/tests/data/manifest/base/manifest.json +1 -0
- package/recce-source/tests/data/manifest/pr2/catalog.json +1 -0
- package/recce-source/tests/data/manifest/pr2/manifest.json +1 -0
- package/recce-source/tests/manifest.json +10655 -0
- package/recce-source/tests/models/__init__.py +0 -0
- package/recce-source/tests/models/test_check.py +731 -0
- package/recce-source/tests/models/test_run_models.py +295 -0
- package/recce-source/tests/recce_cloud/__init__.py +0 -0
- package/recce-source/tests/recce_cloud/test_ci_providers.py +351 -0
- package/recce-source/tests/recce_cloud/test_cli.py +735 -0
- package/recce-source/tests/recce_cloud/test_client.py +379 -0
- package/recce-source/tests/recce_cloud/test_platform_clients.py +483 -0
- package/recce-source/tests/recce_state.json +1 -0
- package/recce-source/tests/state/test_cloud.py +719 -0
- package/recce-source/tests/state/test_local.py +164 -0
- package/recce-source/tests/state/test_state_loader.py +211 -0
- package/recce-source/tests/tasks/__init__.py +0 -0
- package/recce-source/tests/tasks/conftest.py +4 -0
- package/recce-source/tests/tasks/test_histogram.py +129 -0
- package/recce-source/tests/tasks/test_lineage.py +55 -0
- package/recce-source/tests/tasks/test_preset_checks.py +64 -0
- package/recce-source/tests/tasks/test_profile.py +397 -0
- package/recce-source/tests/tasks/test_query.py +528 -0
- package/recce-source/tests/tasks/test_row_count.py +133 -0
- package/recce-source/tests/tasks/test_schema.py +122 -0
- package/recce-source/tests/tasks/test_top_k.py +77 -0
- package/recce-source/tests/tasks/test_utils.py +439 -0
- package/recce-source/tests/tasks/test_valuediff.py +361 -0
- package/recce-source/tests/test_cli.py +236 -0
- package/recce-source/tests/test_cli_mcp_optional.py +45 -0
- package/recce-source/tests/test_cloud_listing_cli.py +324 -0
- package/recce-source/tests/test_config.py +43 -0
- package/recce-source/tests/test_connect_to_cloud.py +82 -0
- package/recce-source/tests/test_core.py +174 -0
- package/recce-source/tests/test_dbt.py +36 -0
- package/recce-source/tests/test_mcp_server.py +505 -0
- package/recce-source/tests/test_pull_request.py +130 -0
- package/recce-source/tests/test_server.py +202 -0
- package/recce-source/tests/test_server_lifespan.py +138 -0
- package/recce-source/tests/test_summary.py +73 -0
- 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 +255 -0
- package/recce-source/tests/util/cloud/test_checks.py +204 -0
- package/recce-source/tests/util/test_api_token.py +119 -0
- package/recce-source/tests/util/test_breaking.py +1427 -0
- package/recce-source/tests/util/test_cll.py +706 -0
- package/recce-source/tests/util/test_lineage.py +122 -0
- package/recce-source/tests/util/test_onboarding_state.py +84 -0
- package/recce-source/tests/util/test_recce_cloud.py +231 -0
- package/recce-source/tox.ini +40 -0
- package/recce-source/uv.lock +3928 -0
- package/src/api/index.ts +32 -0
- package/src/components/index.ts +154 -0
- package/src/global-styles.css +81 -0
- package/src/global.d.ts +14 -0
- package/src/hooks/index.ts +56 -0
- package/src/index.ts +17 -0
- package/src/lib/hooks/RouteConfigContext.ts +139 -0
- package/src/lib/hooks/useAppRouter.ts +240 -0
- package/src/mui-augmentation.d.ts +139 -0
- package/src/theme/index.ts +13 -0
- package/src/theme.ts +23 -0
- package/src/types/index.ts +23 -0
- package/dist/RecceCheckContext-DPpu9nG5.js +0 -303
- package/dist/RecceCheckContext-DPpu9nG5.js.map +0 -1
- package/dist/RecceCheckContext-bXdfQLGG.mjs +0 -229
- package/dist/RecceCheckContext-bXdfQLGG.mjs.map +0 -1
- package/dist/hooks-B9hsc1oD.js +0 -40
- package/dist/index-BNUP2V_N.d.ts.map +0 -1
- package/dist/index-DOPZuhD8.d.mts.map +0 -1
- package/dist/state-B9yzhuKs.mjs.map +0 -1
- package/dist/state-DOUPNifc.css.map +0 -1
- package/dist/state-IA7HWYOs.css.map +0 -1
- package/dist/state-lPCQsWy5.js.map +0 -1
- package/dist/theme.d.mts.map +0 -1
- package/dist/theme.d.ts.map +0 -1
- package/dist/urls-B1Ymdoz-.mjs.map +0 -1
- package/dist/urls-C4eAc82S.js.map +0 -1
- package/dist/version-Dh8sZhvs.js +0 -147
- package/dist/version-Dh8sZhvs.js.map +0 -1
- package/dist/version-OnOKzBeQ.mjs +0 -93
- package/dist/version-OnOKzBeQ.mjs.map +0 -1
|
@@ -0,0 +1,497 @@
|
|
|
1
|
+
from typing import List, Optional, TypedDict, Union
|
|
2
|
+
|
|
3
|
+
from pydantic import BaseModel
|
|
4
|
+
|
|
5
|
+
from ..core import default_context
|
|
6
|
+
from ..exceptions import RecceException
|
|
7
|
+
from ..models import Check
|
|
8
|
+
from .core import CheckValidator, Task, TaskResultDiffer
|
|
9
|
+
from .dataframe import DataFrame
|
|
10
|
+
from .utils import normalize_boolean_flag_columns, normalize_keys_to_columns
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
class ValueDiffParams(BaseModel):
|
|
14
|
+
model: str
|
|
15
|
+
primary_key: Union[str, List[str]]
|
|
16
|
+
columns: Optional[List[str]] = None
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
class ValueDiffResult(BaseModel):
|
|
20
|
+
class Summary(BaseModel):
|
|
21
|
+
total: int
|
|
22
|
+
added: int
|
|
23
|
+
removed: int
|
|
24
|
+
|
|
25
|
+
summary: Summary
|
|
26
|
+
data: DataFrame
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
class ValueDiffMixin:
|
|
30
|
+
def _verify_primary_key(self, dbt_adapter, primary_key: Union[str, List[str]], model: str):
|
|
31
|
+
self.update_progress(message=f"Verify primary key: {primary_key}")
|
|
32
|
+
composite = True if isinstance(primary_key, List) else False
|
|
33
|
+
|
|
34
|
+
if composite:
|
|
35
|
+
if len(primary_key) == 0:
|
|
36
|
+
raise RecceException("Primary key cannot be empty")
|
|
37
|
+
sql_template = r"""
|
|
38
|
+
{%- set column_list = primary_key %}
|
|
39
|
+
{%- set columns_csv = column_list | join(', ') %}
|
|
40
|
+
|
|
41
|
+
with validation_errors as (
|
|
42
|
+
select
|
|
43
|
+
{{ columns_csv }}
|
|
44
|
+
from {{ relation }}
|
|
45
|
+
group by {{ columns_csv }}
|
|
46
|
+
having count(*) > 1
|
|
47
|
+
)
|
|
48
|
+
|
|
49
|
+
select *
|
|
50
|
+
from validation_errors
|
|
51
|
+
"""
|
|
52
|
+
else:
|
|
53
|
+
if primary_key is None or len(primary_key) == 0:
|
|
54
|
+
raise RecceException("Primary key cannot be empty")
|
|
55
|
+
sql_template = r"""{{ adapter.dispatch('test_unique', 'dbt')(relation, primary_key) }}"""
|
|
56
|
+
|
|
57
|
+
# check primary keys
|
|
58
|
+
for base in [True, False]:
|
|
59
|
+
relation = dbt_adapter.create_relation(model, base)
|
|
60
|
+
context = dict(
|
|
61
|
+
relation=relation,
|
|
62
|
+
primary_key=primary_key,
|
|
63
|
+
)
|
|
64
|
+
|
|
65
|
+
sql = dbt_adapter.generate_sql(sql_template, context=context)
|
|
66
|
+
sql_test = f"""SELECT COUNT(*) AS INVALIDS FROM ({sql}) AS T"""
|
|
67
|
+
|
|
68
|
+
response, table = dbt_adapter.adapter.execute(sql_test, fetch=True)
|
|
69
|
+
for row in table.rows:
|
|
70
|
+
invalids = row[0]
|
|
71
|
+
if invalids > 0:
|
|
72
|
+
raise RecceException(
|
|
73
|
+
f"Invalid primary key: \"{primary_key}\". The column should be unique. Please check by this sql: '{sql}'"
|
|
74
|
+
)
|
|
75
|
+
break
|
|
76
|
+
else:
|
|
77
|
+
# it will never happen unless we use a wrong check sql
|
|
78
|
+
raise RecceException("Cannot verify primary key")
|
|
79
|
+
|
|
80
|
+
|
|
81
|
+
class ValueDiffTask(Task, ValueDiffMixin):
|
|
82
|
+
def __init__(self, params):
|
|
83
|
+
super().__init__()
|
|
84
|
+
self.params = ValueDiffParams(**params)
|
|
85
|
+
self.connection = None
|
|
86
|
+
self.legacy_surrogate_key = True
|
|
87
|
+
|
|
88
|
+
def _query_value_diff(
|
|
89
|
+
self,
|
|
90
|
+
dbt_adapter,
|
|
91
|
+
primary_key: Union[str, List[str]],
|
|
92
|
+
model: str,
|
|
93
|
+
columns: List[str] = None,
|
|
94
|
+
):
|
|
95
|
+
"""
|
|
96
|
+
Query value diff between base and current relations.
|
|
97
|
+
Compares column values between base and current relations using the primary key.
|
|
98
|
+
Mutates `self.params.primary_key` to normalize primary key names to match actual column names.
|
|
99
|
+
|
|
100
|
+
:param dbt_adapter: The dbt adapter instance.
|
|
101
|
+
:param primary_key: Single column name or list of column names for composite key.
|
|
102
|
+
:param model: The model name to compare.
|
|
103
|
+
:param columns: Optional list of columns to compare. If None, uses common columns.
|
|
104
|
+
:return: ValueDiffResult with summary and per-column match data, or None if invalid.
|
|
105
|
+
"""
|
|
106
|
+
import agate
|
|
107
|
+
|
|
108
|
+
column_groups = {}
|
|
109
|
+
composite = True if isinstance(primary_key, List) else False
|
|
110
|
+
|
|
111
|
+
if columns is None or len(columns) == 0:
|
|
112
|
+
base_columns = [column.column for column in dbt_adapter.get_columns(model, base=True)]
|
|
113
|
+
curr_columns = [column.column for column in dbt_adapter.get_columns(model, base=False)]
|
|
114
|
+
columns = [column for column in base_columns if column in curr_columns]
|
|
115
|
+
completed = 0
|
|
116
|
+
|
|
117
|
+
if composite:
|
|
118
|
+
for primary_key_comp in primary_key[::-1]:
|
|
119
|
+
if primary_key_comp not in columns:
|
|
120
|
+
columns.insert(0, primary_key_comp)
|
|
121
|
+
else:
|
|
122
|
+
if primary_key not in columns:
|
|
123
|
+
columns.insert(0, primary_key)
|
|
124
|
+
|
|
125
|
+
sql_template = r"""
|
|
126
|
+
{%- set default_null_value = "_recce_surrogate_key_null_" -%}
|
|
127
|
+
{%- set fields = [] -%}
|
|
128
|
+
|
|
129
|
+
{%- for field in primary_keys -%}
|
|
130
|
+
{%- do fields.append(
|
|
131
|
+
"coalesce(cast(" ~ field ~ " as " ~ dbt.type_string() ~ "), '" ~ default_null_value ~"')"
|
|
132
|
+
) -%}
|
|
133
|
+
|
|
134
|
+
{%- if not loop.last %}
|
|
135
|
+
{%- do fields.append("'-'") -%}
|
|
136
|
+
{%- endif -%}
|
|
137
|
+
{%- endfor -%}
|
|
138
|
+
|
|
139
|
+
{%- set _pk = dbt.hash(dbt.concat(fields)) -%}
|
|
140
|
+
|
|
141
|
+
with a_query as (
|
|
142
|
+
select {{ _pk }} as _pk, * from {{ base_relation }}
|
|
143
|
+
),
|
|
144
|
+
|
|
145
|
+
b_query as (
|
|
146
|
+
select {{ _pk }} as _pk, * from {{ curr_relation }}
|
|
147
|
+
),
|
|
148
|
+
|
|
149
|
+
joined as (
|
|
150
|
+
select
|
|
151
|
+
coalesce(a_query._pk, b_query._pk) as _pk,
|
|
152
|
+
a_query.{{ column_to_compare }} as a_query_value,
|
|
153
|
+
b_query.{{ column_to_compare }} as b_query_value,
|
|
154
|
+
case
|
|
155
|
+
when a_query.{{ column_to_compare }} = b_query.{{ column_to_compare }} then 'perfect match'
|
|
156
|
+
when a_query.{{ column_to_compare }} is null and b_query.{{ column_to_compare }} is null then 'both are null'
|
|
157
|
+
when a_query._pk is null then 'missing from {{ a_relation_name }}'
|
|
158
|
+
when b_query._pk is null then 'missing from {{ b_relation_name }}'
|
|
159
|
+
when a_query.{{ column_to_compare }} is null then 'value is null in {{ a_relation_name }} only'
|
|
160
|
+
when b_query.{{ column_to_compare }} is null then 'value is null in {{ b_relation_name }} only'
|
|
161
|
+
when a_query.{{ column_to_compare }} != b_query.{{ column_to_compare }} then 'values do not match'
|
|
162
|
+
else 'unknown' -- this should never happen
|
|
163
|
+
end as match_status
|
|
164
|
+
from a_query
|
|
165
|
+
full outer join b_query on a_query._pk = b_query._pk
|
|
166
|
+
),
|
|
167
|
+
|
|
168
|
+
aggregated as (
|
|
169
|
+
select
|
|
170
|
+
'{{ column_to_compare }}' as column_name,
|
|
171
|
+
match_status,
|
|
172
|
+
count(*) as count_records
|
|
173
|
+
from joined
|
|
174
|
+
group by 1, 2
|
|
175
|
+
)
|
|
176
|
+
|
|
177
|
+
select
|
|
178
|
+
column_name,
|
|
179
|
+
match_status,
|
|
180
|
+
count_records,
|
|
181
|
+
round(100.0 * count_records / sum(count_records) over (), 2) as percent_of_total
|
|
182
|
+
from aggregated
|
|
183
|
+
"""
|
|
184
|
+
|
|
185
|
+
for column in columns:
|
|
186
|
+
self.update_progress(message=f"Diff column: {column}", percentage=completed / len(columns))
|
|
187
|
+
|
|
188
|
+
sql = dbt_adapter.generate_sql(
|
|
189
|
+
sql_template,
|
|
190
|
+
context=dict(
|
|
191
|
+
base_relation=dbt_adapter.create_relation(model, base=True),
|
|
192
|
+
curr_relation=dbt_adapter.create_relation(model, base=False),
|
|
193
|
+
primary_keys=primary_key if composite else [primary_key],
|
|
194
|
+
column_to_compare=column,
|
|
195
|
+
),
|
|
196
|
+
)
|
|
197
|
+
|
|
198
|
+
_, table = dbt_adapter.execute(sql, fetch=True)
|
|
199
|
+
if column not in column_groups:
|
|
200
|
+
column_groups[column] = dict(added=0, removed=0, mismatched=0, matched=0)
|
|
201
|
+
for row in table.rows:
|
|
202
|
+
# data example:
|
|
203
|
+
# ('COLUMN_NAME', 'MATCH_STATUS', 'COUNT_RECORDS', 'PERCENT_OF_TOTAL')
|
|
204
|
+
# ('EVENT_ID', 'perfect match', 158601510, Decimal('100.00'))
|
|
205
|
+
column_name, column_state, row_count, total_rate = row
|
|
206
|
+
if "column_name" == row[0].lower():
|
|
207
|
+
# skip column names
|
|
208
|
+
return
|
|
209
|
+
|
|
210
|
+
# sample data like this:
|
|
211
|
+
# https://github.com/dbt-labs/dbt-audit-helper/blob/main/macros/compare_column_values.sql
|
|
212
|
+
#
|
|
213
|
+
# 'perfect match' -> matched
|
|
214
|
+
# 'both are null' -> matched
|
|
215
|
+
# 'missing from a' -> row added
|
|
216
|
+
# 'missing from b' -> row removed
|
|
217
|
+
# 'value is null in a only' -> mismatched
|
|
218
|
+
# 'value is null in b only' -> mismatched
|
|
219
|
+
# 'values do not match' -> mismatched
|
|
220
|
+
# 'unknown' -> this should never happen
|
|
221
|
+
# end as match_status,
|
|
222
|
+
|
|
223
|
+
state_mappings = {
|
|
224
|
+
"perfect match": "matched",
|
|
225
|
+
"both are null": "matched",
|
|
226
|
+
"missing from a": "added",
|
|
227
|
+
"missing from b": "removed",
|
|
228
|
+
"value is null in a only": "mismatched",
|
|
229
|
+
"value is null in b only": "mismatched",
|
|
230
|
+
"values do not match": "mismatched",
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
# Use the mapping to update counts
|
|
234
|
+
for state, action in state_mappings.items():
|
|
235
|
+
if state in column_state:
|
|
236
|
+
column_groups[column_name][action] += row_count
|
|
237
|
+
|
|
238
|
+
# Cancel as early as possible
|
|
239
|
+
self.check_cancel()
|
|
240
|
+
|
|
241
|
+
completed = completed + 1
|
|
242
|
+
|
|
243
|
+
first = list(column_groups.values())[0]
|
|
244
|
+
added = first["added"]
|
|
245
|
+
removed = first["removed"]
|
|
246
|
+
common = first["matched"] + first["mismatched"]
|
|
247
|
+
total = common + added + removed
|
|
248
|
+
|
|
249
|
+
row = []
|
|
250
|
+
for k, v in column_groups.items():
|
|
251
|
+
if composite and k.lower() == "_pk":
|
|
252
|
+
continue
|
|
253
|
+
# This is incorrect when there are one side null
|
|
254
|
+
# https://github.com/dbt-labs/dbt-audit-helper/blob/main/macros/compare_column_values.sql#L20-L23
|
|
255
|
+
# matched = v['matched']
|
|
256
|
+
matched = common - v["mismatched"]
|
|
257
|
+
rate = None if common == 0 else matched / common
|
|
258
|
+
record = [k, matched, rate]
|
|
259
|
+
row.append(record)
|
|
260
|
+
|
|
261
|
+
column_names = ["column", "matched", "matched_p"]
|
|
262
|
+
column_types = [agate.Text(), agate.Number(), agate.Number()]
|
|
263
|
+
table = agate.Table(row, column_names=column_names, column_types=column_types)
|
|
264
|
+
|
|
265
|
+
# Normalize primary_key to match actual column keys
|
|
266
|
+
# For ValueDiff, 'columns' refers to the model's column list (from metadata), not a DataFrame result.
|
|
267
|
+
composite = isinstance(primary_key, list)
|
|
268
|
+
if composite:
|
|
269
|
+
self.params.primary_key = normalize_keys_to_columns(primary_key, columns) # columns list from the model
|
|
270
|
+
else:
|
|
271
|
+
normalized = normalize_keys_to_columns([primary_key], columns)
|
|
272
|
+
if normalized:
|
|
273
|
+
self.params.primary_key = normalized[0]
|
|
274
|
+
|
|
275
|
+
return ValueDiffResult(
|
|
276
|
+
summary=ValueDiffResult.Summary(total=total, added=added, removed=removed),
|
|
277
|
+
data=DataFrame.from_agate(table),
|
|
278
|
+
)
|
|
279
|
+
|
|
280
|
+
def execute(self):
|
|
281
|
+
dbt_adapter = default_context().adapter
|
|
282
|
+
|
|
283
|
+
with dbt_adapter.connection_named("value diff"):
|
|
284
|
+
self.connection = dbt_adapter.get_thread_connection()
|
|
285
|
+
|
|
286
|
+
primary_key: Union[str, List[str]] = self.params.primary_key
|
|
287
|
+
model: str = self.params.model
|
|
288
|
+
columns: List[str] = self.params.columns
|
|
289
|
+
|
|
290
|
+
self._verify_primary_key(dbt_adapter, primary_key, model)
|
|
291
|
+
self.check_cancel()
|
|
292
|
+
|
|
293
|
+
return self._query_value_diff(dbt_adapter, primary_key, model, columns=columns)
|
|
294
|
+
|
|
295
|
+
def cancel(self):
|
|
296
|
+
super().cancel()
|
|
297
|
+
from recce.adapter.dbt_adapter import DbtAdapter
|
|
298
|
+
|
|
299
|
+
if self.connection:
|
|
300
|
+
adapter: DbtAdapter = default_context().adapter
|
|
301
|
+
with adapter.connection_named("cancel"):
|
|
302
|
+
adapter.cancel(self.connection)
|
|
303
|
+
|
|
304
|
+
|
|
305
|
+
class ValueDiffTaskResultDiffer(TaskResultDiffer):
|
|
306
|
+
def _check_result_changed_fn(self, result):
|
|
307
|
+
is_changed = False
|
|
308
|
+
summary = result.get("summary", {})
|
|
309
|
+
added = summary.get("added", 0)
|
|
310
|
+
removed = summary.get("removed", 0)
|
|
311
|
+
changes = {"column_changed": []}
|
|
312
|
+
|
|
313
|
+
if added > 0:
|
|
314
|
+
is_changed = True
|
|
315
|
+
changes["row_added"] = added
|
|
316
|
+
|
|
317
|
+
if removed > 0:
|
|
318
|
+
is_changed = True
|
|
319
|
+
changes["row_removed"] = removed
|
|
320
|
+
|
|
321
|
+
row_data = result.get("data", {}).get("data", [])
|
|
322
|
+
for row in row_data:
|
|
323
|
+
column, matched, matched_p = row
|
|
324
|
+
if float(matched_p) < 1.0:
|
|
325
|
+
# if there is any mismatched, we consider it as changed
|
|
326
|
+
is_changed = True
|
|
327
|
+
changes["column_changed"].append(
|
|
328
|
+
{
|
|
329
|
+
"column": column,
|
|
330
|
+
"matched": matched,
|
|
331
|
+
"matched_p": matched_p,
|
|
332
|
+
}
|
|
333
|
+
)
|
|
334
|
+
|
|
335
|
+
return changes if is_changed else None
|
|
336
|
+
|
|
337
|
+
|
|
338
|
+
class ValueDiffDetailParams(TypedDict):
|
|
339
|
+
primary_key: str
|
|
340
|
+
model: str
|
|
341
|
+
columns: List[str]
|
|
342
|
+
|
|
343
|
+
|
|
344
|
+
class ValueDiffDetailResult(DataFrame):
|
|
345
|
+
pass
|
|
346
|
+
|
|
347
|
+
|
|
348
|
+
class ValueDiffDetailTask(Task, ValueDiffMixin):
|
|
349
|
+
def __init__(self, params):
|
|
350
|
+
super().__init__()
|
|
351
|
+
self.params = ValueDiffParams(**params)
|
|
352
|
+
self.connection = None
|
|
353
|
+
self.legacy_surrogate_key = True
|
|
354
|
+
|
|
355
|
+
def _query_value_diff(
|
|
356
|
+
self,
|
|
357
|
+
dbt_adapter,
|
|
358
|
+
primary_key: Union[str, List[str]],
|
|
359
|
+
model: str,
|
|
360
|
+
columns: List[str] = None,
|
|
361
|
+
):
|
|
362
|
+
composite = True if isinstance(primary_key, List) else False
|
|
363
|
+
|
|
364
|
+
if columns is None or len(columns) == 0:
|
|
365
|
+
base_columns = [column.column for column in dbt_adapter.get_columns(model, base=True)]
|
|
366
|
+
curr_columns = [column.column for column in dbt_adapter.get_columns(model, base=False)]
|
|
367
|
+
columns = [column for column in base_columns if column in curr_columns]
|
|
368
|
+
|
|
369
|
+
if composite:
|
|
370
|
+
for primary_key_comp in primary_key[::-1]:
|
|
371
|
+
if primary_key_comp not in columns:
|
|
372
|
+
columns.insert(0, primary_key_comp)
|
|
373
|
+
else:
|
|
374
|
+
if primary_key not in columns:
|
|
375
|
+
columns.insert(0, primary_key)
|
|
376
|
+
|
|
377
|
+
sql_template = r"""
|
|
378
|
+
with a_query as (select {{ columns | join (',\n') }}
|
|
379
|
+
from {{ base_relation }}
|
|
380
|
+
), b_query as (
|
|
381
|
+
select {{ columns | join (',\n') }}
|
|
382
|
+
from {{ curr_relation }}
|
|
383
|
+
), a_intersect_b as (
|
|
384
|
+
select *
|
|
385
|
+
from a_query
|
|
386
|
+
{{ dbt.intersect() }}
|
|
387
|
+
select *
|
|
388
|
+
from b_query
|
|
389
|
+
), a_except_b as (
|
|
390
|
+
select *
|
|
391
|
+
from a_query
|
|
392
|
+
{{ dbt.except() }}
|
|
393
|
+
select *
|
|
394
|
+
from b_query
|
|
395
|
+
), b_except_a as (
|
|
396
|
+
select *
|
|
397
|
+
from b_query
|
|
398
|
+
{{ dbt.except() }}
|
|
399
|
+
select *
|
|
400
|
+
from a_query
|
|
401
|
+
), all_records as (
|
|
402
|
+
select
|
|
403
|
+
*, true as in_a, true as in_b
|
|
404
|
+
from a_intersect_b
|
|
405
|
+
|
|
406
|
+
union all
|
|
407
|
+
|
|
408
|
+
select
|
|
409
|
+
*, true as in_a, false as in_b
|
|
410
|
+
from a_except_b
|
|
411
|
+
|
|
412
|
+
union all
|
|
413
|
+
|
|
414
|
+
select
|
|
415
|
+
*, false as in_a, true as in_b
|
|
416
|
+
from b_except_a
|
|
417
|
+
)
|
|
418
|
+
|
|
419
|
+
select *
|
|
420
|
+
from all_records
|
|
421
|
+
where not (in_a and in_b)
|
|
422
|
+
order by {{ primary_keys | join (',\n') }}, in_a desc, in_b desc
|
|
423
|
+
limit {{ limit }}
|
|
424
|
+
"""
|
|
425
|
+
|
|
426
|
+
sql = dbt_adapter.generate_sql(
|
|
427
|
+
sql_template,
|
|
428
|
+
context=dict(
|
|
429
|
+
base_relation=dbt_adapter.create_relation(model, base=True),
|
|
430
|
+
curr_relation=dbt_adapter.create_relation(model, base=False),
|
|
431
|
+
primary_keys=primary_key if composite else [primary_key],
|
|
432
|
+
columns=columns,
|
|
433
|
+
limit=1000,
|
|
434
|
+
),
|
|
435
|
+
)
|
|
436
|
+
|
|
437
|
+
_, table = dbt_adapter.execute(sql, fetch=True)
|
|
438
|
+
self.check_cancel()
|
|
439
|
+
|
|
440
|
+
result_df = DataFrame.from_agate(table)
|
|
441
|
+
# Normalize in_a/in_b columns to lowercase for cross-warehouse consistency
|
|
442
|
+
result_df = normalize_boolean_flag_columns(result_df)
|
|
443
|
+
|
|
444
|
+
# Normalize primary_key to match actual column keys from result
|
|
445
|
+
column_keys = [col.key for col in result_df.columns]
|
|
446
|
+
composite = isinstance(primary_key, list)
|
|
447
|
+
if composite:
|
|
448
|
+
self.params.primary_key = normalize_keys_to_columns(primary_key, column_keys)
|
|
449
|
+
else:
|
|
450
|
+
normalized = normalize_keys_to_columns([primary_key], column_keys)
|
|
451
|
+
if normalized:
|
|
452
|
+
self.params.primary_key = normalized[0]
|
|
453
|
+
|
|
454
|
+
return result_df
|
|
455
|
+
|
|
456
|
+
def execute(self):
|
|
457
|
+
from recce.adapter.dbt_adapter import DbtAdapter
|
|
458
|
+
|
|
459
|
+
dbt_adapter: DbtAdapter = default_context().adapter
|
|
460
|
+
|
|
461
|
+
with dbt_adapter.connection_named("value diff"):
|
|
462
|
+
self.connection = dbt_adapter.get_thread_connection()
|
|
463
|
+
|
|
464
|
+
primary_key: Union[str, List[str]] = self.params.primary_key
|
|
465
|
+
model: str = self.params.model
|
|
466
|
+
columns: List[str] = self.params.columns
|
|
467
|
+
|
|
468
|
+
self._verify_primary_key(dbt_adapter, primary_key, model)
|
|
469
|
+
self.check_cancel()
|
|
470
|
+
|
|
471
|
+
return self._query_value_diff(dbt_adapter, primary_key, model, columns)
|
|
472
|
+
|
|
473
|
+
def cancel(self):
|
|
474
|
+
from recce.adapter.dbt_adapter import DbtAdapter
|
|
475
|
+
|
|
476
|
+
if self.connection:
|
|
477
|
+
adapter: DbtAdapter = default_context().adapter
|
|
478
|
+
with adapter.connection_named("cancel"):
|
|
479
|
+
adapter.cancel(self.connection)
|
|
480
|
+
|
|
481
|
+
|
|
482
|
+
class ValueDiffDetailTaskResultDiffer(TaskResultDiffer):
|
|
483
|
+
def _check_result_changed_fn(self, result):
|
|
484
|
+
diff_data = result.get("data")
|
|
485
|
+
if diff_data is None or len(diff_data) == 0:
|
|
486
|
+
return None
|
|
487
|
+
|
|
488
|
+
# TODO: Implement detailed information of values changed
|
|
489
|
+
return dict(values_changed={})
|
|
490
|
+
|
|
491
|
+
|
|
492
|
+
class ValueDiffCheckValidator(CheckValidator):
|
|
493
|
+
def validate_check(self, check: Check):
|
|
494
|
+
try:
|
|
495
|
+
ValueDiffParams(**check.params)
|
|
496
|
+
except Exception as e:
|
|
497
|
+
raise ValueError(f"Invalid check: {str(e)}")
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
import click
|
|
2
|
+
from rich.console import Console
|
|
3
|
+
|
|
4
|
+
from recce import event
|
|
5
|
+
from recce.event import get_recce_api_token, update_recce_api_token
|
|
6
|
+
from recce.exceptions import RecceConfigException
|
|
7
|
+
from recce.util.recce_cloud import (
|
|
8
|
+
RECCE_CLOUD_BASE_URL,
|
|
9
|
+
RecceCloud,
|
|
10
|
+
)
|
|
11
|
+
|
|
12
|
+
console = Console()
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
def show_invalid_api_token_message():
|
|
16
|
+
"""
|
|
17
|
+
Show the message when the API token is invalid.
|
|
18
|
+
"""
|
|
19
|
+
console.print("[[red]Error[/red]] Invalid Recce Cloud API token.")
|
|
20
|
+
console.print("Please associate with your Recce Cloud account by the following command 'recce connect-to-cloud'.")
|
|
21
|
+
console.print(
|
|
22
|
+
"For more information, please visit: https://docs.reccehq.com/recce-cloud/share-recce-session-securely/#configure-recce-cloud-association-manually"
|
|
23
|
+
)
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
def prepare_api_token(
|
|
27
|
+
interaction=False,
|
|
28
|
+
**kwargs,
|
|
29
|
+
):
|
|
30
|
+
"""
|
|
31
|
+
Prepare the API token for the request.
|
|
32
|
+
"""
|
|
33
|
+
# Verify the API token for Recce Cloud Share Link
|
|
34
|
+
api_token = get_recce_api_token()
|
|
35
|
+
new_api_token = kwargs.get("api_token")
|
|
36
|
+
if new_api_token is not None and new_api_token.startswith("rct-"):
|
|
37
|
+
# Task Token
|
|
38
|
+
valid = RecceCloud(new_api_token).verify_token()
|
|
39
|
+
if not valid:
|
|
40
|
+
raise RecceConfigException("Invalid Recce Cloud Task token")
|
|
41
|
+
api_token = new_api_token
|
|
42
|
+
elif api_token != new_api_token and new_api_token is not None:
|
|
43
|
+
# Handle the API token provided by option `--api-token`
|
|
44
|
+
valid = RecceCloud(new_api_token).verify_token()
|
|
45
|
+
if not valid:
|
|
46
|
+
raise RecceConfigException("Invalid Recce Cloud API token")
|
|
47
|
+
event.log_connected_to_cloud()
|
|
48
|
+
api_token = new_api_token
|
|
49
|
+
update_recce_api_token(api_token)
|
|
50
|
+
console.print(
|
|
51
|
+
"[[green]Success[/green]] User profile has been updated to include the Recce Cloud API Token. "
|
|
52
|
+
"You no longer need to append --api-token to the recce command"
|
|
53
|
+
)
|
|
54
|
+
elif api_token:
|
|
55
|
+
# Verify the API token from the user profile
|
|
56
|
+
valid = RecceCloud(api_token).verify_token()
|
|
57
|
+
if not valid:
|
|
58
|
+
console.print("[[yellow]Warning[/yellow]] Invalid Recce Cloud API token. Skipping the share link.")
|
|
59
|
+
api_token = None
|
|
60
|
+
if valid:
|
|
61
|
+
event.log_connected_to_cloud()
|
|
62
|
+
else:
|
|
63
|
+
# No api_token provided
|
|
64
|
+
if interaction:
|
|
65
|
+
console.print(
|
|
66
|
+
"An API token is required for this feature. This can be obtained in your user account settings.\n"
|
|
67
|
+
f"{RECCE_CLOUD_BASE_URL}/settings#tokens\n"
|
|
68
|
+
"Your API token can be added to '~/.recce/profile.yml' for more convenient sharing."
|
|
69
|
+
)
|
|
70
|
+
api_token = click.prompt("Your Recce API token", type=str, hide_input=True, show_default=False)
|
|
71
|
+
valid = RecceCloud(api_token).verify_token()
|
|
72
|
+
if not valid:
|
|
73
|
+
raise RecceConfigException("Invalid Recce Cloud API token")
|
|
74
|
+
update_recce_api_token(api_token)
|
|
75
|
+
console.print(
|
|
76
|
+
"[[green]Success[/green]] User profile has been updated to include the Recce Cloud API Token. "
|
|
77
|
+
"You no longer need to append --api-token to the recce command"
|
|
78
|
+
)
|
|
79
|
+
|
|
80
|
+
return api_token
|