@datarecce/ui 0.1.29 → 0.1.31
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/{RecceCheckContext-fAKHgsGz.js → RecceCheckContext-DPpu9nG5.js} +2 -2
- package/dist/{RecceCheckContext-fAKHgsGz.js.map → RecceCheckContext-DPpu9nG5.js.map} +1 -1
- package/dist/{RecceCheckContext-PT4-g1bW.mjs → RecceCheckContext-bXdfQLGG.mjs} +2 -2
- package/dist/{RecceCheckContext-PT4-g1bW.mjs.map → RecceCheckContext-bXdfQLGG.mjs.map} +1 -1
- package/dist/api.d.mts +1 -1
- package/dist/api.d.ts +1 -1
- package/dist/api.js +4 -3
- package/dist/api.mjs +4 -3
- package/dist/{components-B9F5oJbK.js → components-B-YxuuPz.js} +66 -65
- package/dist/{components-B9F5oJbK.js.map → components-B-YxuuPz.js.map} +1 -1
- package/dist/{components-D2DRqJsz.css → components-BeAjVBV3.css} +1 -1
- package/dist/{components-D2DRqJsz.css.map → components-BeAjVBV3.css.map} +1 -1
- package/dist/{components-gDC1ucjo.mjs → components-DCOI1YlQ.mjs} +8 -7
- package/dist/{components-gDC1ucjo.mjs.map → components-DCOI1YlQ.mjs.map} +1 -1
- package/dist/{components-dVXbmdqd.css → components-iUxcqtUB.css} +1 -1
- package/dist/{components-dVXbmdqd.css.map → components-iUxcqtUB.css.map} +1 -1
- package/dist/components.d.mts +1 -1
- package/dist/components.d.ts +1 -1
- package/dist/components.js +6 -5
- package/dist/components.mjs +6 -5
- package/dist/{hooks-C2jUJ9EN.js → hooks-B9hsc1oD.js} +3 -3
- package/dist/{hooks-C2jUJ9EN.js.map → hooks-B9hsc1oD.js.map} +1 -1
- package/dist/{hooks-4hRUjy9Q.mjs → hooks-DjBNmTdh.mjs} +3 -3
- package/dist/{hooks-4hRUjy9Q.mjs.map → hooks-DjBNmTdh.mjs.map} +1 -1
- package/dist/hooks.d.mts +1 -1
- package/dist/hooks.d.ts +1 -1
- package/dist/hooks.js +5 -4
- package/dist/hooks.mjs +5 -4
- package/dist/{html2canvas-pro.esm-BR5xeFe-.mjs → html2canvas-pro.esm-BInzOtWO.mjs} +1 -1
- package/dist/{html2canvas-pro.esm-BR5xeFe-.mjs.map → html2canvas-pro.esm-BInzOtWO.mjs.map} +1 -1
- package/dist/{html2canvas-pro.esm-CVOsBdk0.js → html2canvas-pro.esm-WJxOmKlq.js} +1 -1
- package/dist/{html2canvas-pro.esm-CVOsBdk0.js.map → html2canvas-pro.esm-WJxOmKlq.js.map} +1 -1
- package/dist/{index-Bv5R8iLo.d.mts → index-B9lSPJTi.d.ts} +192 -12
- package/dist/index-B9lSPJTi.d.ts.map +1 -0
- package/dist/{index-CUtFlKOo.d.ts → index-IIXVIoOL.d.mts} +262 -78
- package/dist/index-IIXVIoOL.d.mts.map +1 -0
- package/dist/index.d.mts +2 -2
- package/dist/index.d.ts +2 -2
- package/dist/index.js +15 -7
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +10 -8
- package/dist/index.mjs.map +1 -1
- package/dist/mui-theme-B2wm_cvZ.js +732 -0
- package/dist/mui-theme-B2wm_cvZ.js.map +1 -0
- package/dist/mui-theme-CUhybmBq.mjs +696 -0
- package/dist/mui-theme-CUhybmBq.mjs.map +1 -0
- package/dist/{state-CELzQ0tM.mjs → state-B9yzhuKs.mjs} +5 -694
- package/dist/state-B9yzhuKs.mjs.map +1 -0
- package/dist/{state-eEsMhIy4.css → state-DOUPNifc.css} +1 -1
- package/dist/{state-eEsMhIy4.css.map → state-DOUPNifc.css.map} +1 -1
- package/dist/{state-CemiRRon.js → state-lPCQsWy5.js} +24 -737
- package/dist/state-lPCQsWy5.js.map +1 -0
- package/dist/styles.css +4 -0
- package/dist/theme.d.mts +3 -0
- package/dist/theme.d.ts +3 -0
- package/dist/theme.js +9 -0
- package/dist/theme.mjs +4 -0
- package/dist/{tooltipMessage-CrXjOmVM.mjs → tooltipMessage-B--I3p1V.mjs} +1 -1
- package/dist/{tooltipMessage-CrXjOmVM.mjs.map → tooltipMessage-B--I3p1V.mjs.map} +1 -1
- package/dist/{tooltipMessage-Dbi1kkfi.js → tooltipMessage-DosF13kZ.js} +1 -1
- package/dist/{tooltipMessage-Dbi1kkfi.js.map → tooltipMessage-DosF13kZ.js.map} +1 -1
- package/dist/types.d.mts +1 -1
- package/dist/types.d.ts +1 -1
- package/dist/types.js +2 -2
- package/dist/types.mjs +2 -2
- package/dist/{urls-D7PrPolY.mjs → urls-B1Ymdoz-.mjs} +1 -1
- package/dist/{urls-D7PrPolY.mjs.map → urls-B1Ymdoz-.mjs.map} +1 -1
- package/dist/{urls-SazAekCZ.js → urls-C4eAc82S.js} +1 -1
- package/dist/{urls-SazAekCZ.js.map → urls-C4eAc82S.js.map} +1 -1
- package/dist/{version-bWg7XwOu.js → version-Dh8sZhvs.js} +2 -2
- package/dist/{version-bWg7XwOu.js.map → version-Dh8sZhvs.js.map} +1 -1
- package/dist/{version-paZ9esBk.mjs → version-OnOKzBeQ.mjs} +2 -2
- package/dist/{version-paZ9esBk.mjs.map → version-OnOKzBeQ.mjs.map} +1 -1
- package/package.json +9 -2
- 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.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/index-Bv5R8iLo.d.mts.map +0 -1
- package/dist/index-CUtFlKOo.d.ts.map +0 -1
- package/dist/state-CELzQ0tM.mjs.map +0 -1
- package/dist/state-CemiRRon.js.map +0 -1
|
@@ -0,0 +1,353 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Check Events API endpoints.
|
|
3
|
+
|
|
4
|
+
This module provides REST endpoints for check events (timeline/conversation),
|
|
5
|
+
proxying requests to Recce Cloud. This feature is only available for cloud users.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
import logging
|
|
9
|
+
from typing import List, Optional
|
|
10
|
+
from uuid import UUID
|
|
11
|
+
|
|
12
|
+
from fastapi import APIRouter, HTTPException
|
|
13
|
+
from pydantic import BaseModel
|
|
14
|
+
|
|
15
|
+
from recce.core import default_context
|
|
16
|
+
from recce.event import get_recce_api_token
|
|
17
|
+
from recce.exceptions import RecceException
|
|
18
|
+
from recce.util.cloud.check_events import CheckEventsCloud
|
|
19
|
+
from recce.util.recce_cloud import RecceCloud, RecceCloudException
|
|
20
|
+
|
|
21
|
+
logger = logging.getLogger("uvicorn")
|
|
22
|
+
|
|
23
|
+
check_events_router = APIRouter(tags=["check_events"])
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
# ============================================================================
|
|
27
|
+
# Helper Functions
|
|
28
|
+
# ============================================================================
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
def _is_cloud_user() -> bool:
|
|
32
|
+
"""Check if the current user is connected to Recce Cloud."""
|
|
33
|
+
ctx = default_context()
|
|
34
|
+
if ctx is None or ctx.state_loader is None:
|
|
35
|
+
return False
|
|
36
|
+
return hasattr(ctx.state_loader, "session_id") and ctx.state_loader.session_id is not None
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
def _get_session_info() -> tuple:
|
|
40
|
+
"""
|
|
41
|
+
Get organization ID, project ID, and session ID from state loader.
|
|
42
|
+
|
|
43
|
+
Returns:
|
|
44
|
+
tuple: (org_id, project_id, session_id)
|
|
45
|
+
|
|
46
|
+
Raises:
|
|
47
|
+
HTTPException: If not in cloud mode or session info unavailable
|
|
48
|
+
"""
|
|
49
|
+
if not _is_cloud_user():
|
|
50
|
+
raise HTTPException(
|
|
51
|
+
status_code=400,
|
|
52
|
+
detail="Check events are only available when connected to Recce Cloud.",
|
|
53
|
+
)
|
|
54
|
+
|
|
55
|
+
ctx = default_context()
|
|
56
|
+
state_loader = ctx.state_loader
|
|
57
|
+
|
|
58
|
+
session_id = state_loader.session_id
|
|
59
|
+
|
|
60
|
+
# Check if org_id and project_id are cached
|
|
61
|
+
if hasattr(state_loader, "org_id") and hasattr(state_loader, "project_id"):
|
|
62
|
+
return state_loader.org_id, state_loader.project_id, session_id
|
|
63
|
+
|
|
64
|
+
# Fetch from cloud API
|
|
65
|
+
api_token = get_recce_api_token() or state_loader.token
|
|
66
|
+
if not api_token:
|
|
67
|
+
raise HTTPException(
|
|
68
|
+
status_code=401,
|
|
69
|
+
detail="Cannot access Recce Cloud: no API token available.",
|
|
70
|
+
)
|
|
71
|
+
|
|
72
|
+
try:
|
|
73
|
+
recce_cloud = RecceCloud(api_token)
|
|
74
|
+
session = recce_cloud.get_session(session_id)
|
|
75
|
+
|
|
76
|
+
org_id = session.get("org_id")
|
|
77
|
+
project_id = session.get("project_id")
|
|
78
|
+
|
|
79
|
+
if not org_id or not project_id:
|
|
80
|
+
raise HTTPException(
|
|
81
|
+
status_code=400,
|
|
82
|
+
detail=f"Session {session_id} does not belong to a valid organization or project.",
|
|
83
|
+
)
|
|
84
|
+
|
|
85
|
+
# Cache for future use
|
|
86
|
+
state_loader.org_id = org_id
|
|
87
|
+
state_loader.project_id = project_id
|
|
88
|
+
|
|
89
|
+
return org_id, project_id, session_id
|
|
90
|
+
|
|
91
|
+
except RecceCloudException as e:
|
|
92
|
+
logger.error(f"Failed to get session info: {e}")
|
|
93
|
+
raise HTTPException(status_code=e.status_code, detail=str(e.reason))
|
|
94
|
+
|
|
95
|
+
|
|
96
|
+
def _get_events_client() -> CheckEventsCloud:
|
|
97
|
+
"""
|
|
98
|
+
Get the CheckEventsCloud client.
|
|
99
|
+
|
|
100
|
+
Returns:
|
|
101
|
+
CheckEventsCloud: Cloud client for event operations
|
|
102
|
+
|
|
103
|
+
Raises:
|
|
104
|
+
HTTPException: If client cannot be initialized
|
|
105
|
+
"""
|
|
106
|
+
ctx = default_context()
|
|
107
|
+
api_token = get_recce_api_token() or ctx.state_loader.token
|
|
108
|
+
|
|
109
|
+
if not api_token:
|
|
110
|
+
raise HTTPException(
|
|
111
|
+
status_code=401,
|
|
112
|
+
detail="Cannot access Recce Cloud: no API token available.",
|
|
113
|
+
)
|
|
114
|
+
|
|
115
|
+
return CheckEventsCloud(api_token)
|
|
116
|
+
|
|
117
|
+
|
|
118
|
+
# ============================================================================
|
|
119
|
+
# Pydantic Models
|
|
120
|
+
# ============================================================================
|
|
121
|
+
|
|
122
|
+
|
|
123
|
+
class CheckEventActorOut(BaseModel):
|
|
124
|
+
"""Actor who performed the event."""
|
|
125
|
+
|
|
126
|
+
type: str # "user", "recce_ai", "preset_system"
|
|
127
|
+
user_id: Optional[int] = None
|
|
128
|
+
login: Optional[str] = None
|
|
129
|
+
fullname: Optional[str] = None
|
|
130
|
+
|
|
131
|
+
|
|
132
|
+
class CheckEventOut(BaseModel):
|
|
133
|
+
"""Check event response model."""
|
|
134
|
+
|
|
135
|
+
id: str
|
|
136
|
+
check_id: str
|
|
137
|
+
event_type: str
|
|
138
|
+
actor: CheckEventActorOut
|
|
139
|
+
content: Optional[str] = None
|
|
140
|
+
old_value: Optional[str] = None
|
|
141
|
+
new_value: Optional[str] = None
|
|
142
|
+
is_edited: bool = False
|
|
143
|
+
is_deleted: bool = False
|
|
144
|
+
created_at: str
|
|
145
|
+
updated_at: str
|
|
146
|
+
|
|
147
|
+
|
|
148
|
+
class CreateCommentIn(BaseModel):
|
|
149
|
+
"""Request body for creating a comment."""
|
|
150
|
+
|
|
151
|
+
content: str
|
|
152
|
+
|
|
153
|
+
|
|
154
|
+
class UpdateCommentIn(BaseModel):
|
|
155
|
+
"""Request body for updating a comment."""
|
|
156
|
+
|
|
157
|
+
content: str
|
|
158
|
+
|
|
159
|
+
|
|
160
|
+
# ============================================================================
|
|
161
|
+
# API Endpoints
|
|
162
|
+
# ============================================================================
|
|
163
|
+
|
|
164
|
+
|
|
165
|
+
@check_events_router.get(
|
|
166
|
+
"/checks/{check_id}/events",
|
|
167
|
+
status_code=200,
|
|
168
|
+
response_model=List[CheckEventOut],
|
|
169
|
+
)
|
|
170
|
+
async def list_check_events(check_id: UUID):
|
|
171
|
+
"""
|
|
172
|
+
List all events for a check in chronological order.
|
|
173
|
+
|
|
174
|
+
This endpoint returns all events (comments, state changes, etc.) for the
|
|
175
|
+
specified check. Events are returned in chronological order (oldest first).
|
|
176
|
+
|
|
177
|
+
Args:
|
|
178
|
+
check_id: The check ID
|
|
179
|
+
|
|
180
|
+
Returns:
|
|
181
|
+
List of CheckEventOut objects
|
|
182
|
+
|
|
183
|
+
Raises:
|
|
184
|
+
400: Not connected to Recce Cloud
|
|
185
|
+
401: No API token available
|
|
186
|
+
404: Check not found
|
|
187
|
+
"""
|
|
188
|
+
try:
|
|
189
|
+
org_id, project_id, session_id = _get_session_info()
|
|
190
|
+
client = _get_events_client()
|
|
191
|
+
|
|
192
|
+
events = client.list_events(org_id, project_id, session_id, str(check_id))
|
|
193
|
+
return events
|
|
194
|
+
|
|
195
|
+
except RecceCloudException as e:
|
|
196
|
+
logger.error(f"Failed to list check events: {e}")
|
|
197
|
+
raise HTTPException(status_code=e.status_code, detail=str(e.reason))
|
|
198
|
+
except RecceException as e:
|
|
199
|
+
logger.error(f"Failed to list check events: {e}")
|
|
200
|
+
raise HTTPException(status_code=400, detail=str(e))
|
|
201
|
+
|
|
202
|
+
|
|
203
|
+
@check_events_router.get(
|
|
204
|
+
"/checks/{check_id}/events/{event_id}",
|
|
205
|
+
status_code=200,
|
|
206
|
+
response_model=CheckEventOut,
|
|
207
|
+
)
|
|
208
|
+
async def get_check_event(check_id: UUID, event_id: UUID):
|
|
209
|
+
"""
|
|
210
|
+
Get a specific event by ID.
|
|
211
|
+
|
|
212
|
+
Args:
|
|
213
|
+
check_id: The check ID
|
|
214
|
+
event_id: The event ID
|
|
215
|
+
|
|
216
|
+
Returns:
|
|
217
|
+
CheckEventOut object
|
|
218
|
+
|
|
219
|
+
Raises:
|
|
220
|
+
400: Not connected to Recce Cloud
|
|
221
|
+
401: No API token available
|
|
222
|
+
404: Event not found
|
|
223
|
+
"""
|
|
224
|
+
try:
|
|
225
|
+
org_id, project_id, session_id = _get_session_info()
|
|
226
|
+
client = _get_events_client()
|
|
227
|
+
|
|
228
|
+
event = client.get_event(org_id, project_id, session_id, str(check_id), str(event_id))
|
|
229
|
+
return event
|
|
230
|
+
|
|
231
|
+
except RecceCloudException as e:
|
|
232
|
+
logger.error(f"Failed to get check event: {e}")
|
|
233
|
+
raise HTTPException(status_code=e.status_code, detail=str(e.reason))
|
|
234
|
+
except RecceException as e:
|
|
235
|
+
logger.error(f"Failed to get check event: {e}")
|
|
236
|
+
raise HTTPException(status_code=400, detail=str(e))
|
|
237
|
+
|
|
238
|
+
|
|
239
|
+
@check_events_router.post(
|
|
240
|
+
"/checks/{check_id}/events",
|
|
241
|
+
status_code=201,
|
|
242
|
+
response_model=CheckEventOut,
|
|
243
|
+
)
|
|
244
|
+
async def create_comment(check_id: UUID, body: CreateCommentIn):
|
|
245
|
+
"""
|
|
246
|
+
Create a new comment on a check.
|
|
247
|
+
|
|
248
|
+
Args:
|
|
249
|
+
check_id: The check ID
|
|
250
|
+
body: Request body containing comment content
|
|
251
|
+
|
|
252
|
+
Returns:
|
|
253
|
+
Created CheckEventOut object
|
|
254
|
+
|
|
255
|
+
Raises:
|
|
256
|
+
400: Not connected to Recce Cloud or invalid content
|
|
257
|
+
401: No API token available
|
|
258
|
+
404: Check not found
|
|
259
|
+
"""
|
|
260
|
+
if not body.content or not body.content.strip():
|
|
261
|
+
raise HTTPException(status_code=400, detail="Comment content cannot be empty.")
|
|
262
|
+
|
|
263
|
+
try:
|
|
264
|
+
org_id, project_id, session_id = _get_session_info()
|
|
265
|
+
client = _get_events_client()
|
|
266
|
+
|
|
267
|
+
event = client.create_comment(org_id, project_id, session_id, str(check_id), body.content)
|
|
268
|
+
return event
|
|
269
|
+
|
|
270
|
+
except RecceCloudException as e:
|
|
271
|
+
logger.error(f"Failed to create comment: {e}")
|
|
272
|
+
raise HTTPException(status_code=e.status_code, detail=str(e.reason))
|
|
273
|
+
except RecceException as e:
|
|
274
|
+
logger.error(f"Failed to create comment: {e}")
|
|
275
|
+
raise HTTPException(status_code=400, detail=str(e))
|
|
276
|
+
|
|
277
|
+
|
|
278
|
+
@check_events_router.patch(
|
|
279
|
+
"/checks/{check_id}/events/{event_id}",
|
|
280
|
+
status_code=200,
|
|
281
|
+
response_model=CheckEventOut,
|
|
282
|
+
)
|
|
283
|
+
async def update_comment(check_id: UUID, event_id: UUID, body: UpdateCommentIn):
|
|
284
|
+
"""
|
|
285
|
+
Update an existing comment.
|
|
286
|
+
|
|
287
|
+
Only the author or an admin can update a comment.
|
|
288
|
+
|
|
289
|
+
Args:
|
|
290
|
+
check_id: The check ID
|
|
291
|
+
event_id: The event ID of the comment to update
|
|
292
|
+
body: Request body containing new comment content
|
|
293
|
+
|
|
294
|
+
Returns:
|
|
295
|
+
Updated CheckEventOut object
|
|
296
|
+
|
|
297
|
+
Raises:
|
|
298
|
+
400: Not connected to Recce Cloud or invalid content
|
|
299
|
+
401: No API token available
|
|
300
|
+
403: Not authorized to update this comment
|
|
301
|
+
404: Comment not found
|
|
302
|
+
"""
|
|
303
|
+
if not body.content or not body.content.strip():
|
|
304
|
+
raise HTTPException(status_code=400, detail="Comment content cannot be empty.")
|
|
305
|
+
|
|
306
|
+
try:
|
|
307
|
+
org_id, project_id, session_id = _get_session_info()
|
|
308
|
+
client = _get_events_client()
|
|
309
|
+
|
|
310
|
+
event = client.update_comment(org_id, project_id, session_id, str(check_id), str(event_id), body.content)
|
|
311
|
+
return event
|
|
312
|
+
|
|
313
|
+
except RecceCloudException as e:
|
|
314
|
+
logger.error(f"Failed to update comment: {e}")
|
|
315
|
+
raise HTTPException(status_code=e.status_code, detail=str(e.reason))
|
|
316
|
+
except RecceException as e:
|
|
317
|
+
logger.error(f"Failed to update comment: {e}")
|
|
318
|
+
raise HTTPException(status_code=400, detail=str(e))
|
|
319
|
+
|
|
320
|
+
|
|
321
|
+
@check_events_router.delete(
|
|
322
|
+
"/checks/{check_id}/events/{event_id}",
|
|
323
|
+
status_code=204,
|
|
324
|
+
)
|
|
325
|
+
async def delete_comment(check_id: UUID, event_id: UUID):
|
|
326
|
+
"""
|
|
327
|
+
Delete a comment (soft delete).
|
|
328
|
+
|
|
329
|
+
Only the author or an admin can delete a comment. The comment will be
|
|
330
|
+
marked as deleted but remain in the timeline with a "Comment deleted" indicator.
|
|
331
|
+
|
|
332
|
+
Args:
|
|
333
|
+
check_id: The check ID
|
|
334
|
+
event_id: The event ID of the comment to delete
|
|
335
|
+
|
|
336
|
+
Raises:
|
|
337
|
+
400: Not connected to Recce Cloud
|
|
338
|
+
401: No API token available
|
|
339
|
+
403: Not authorized to delete this comment
|
|
340
|
+
404: Comment not found
|
|
341
|
+
"""
|
|
342
|
+
try:
|
|
343
|
+
org_id, project_id, session_id = _get_session_info()
|
|
344
|
+
client = _get_events_client()
|
|
345
|
+
|
|
346
|
+
client.delete_comment(org_id, project_id, session_id, str(check_id), str(event_id))
|
|
347
|
+
|
|
348
|
+
except RecceCloudException as e:
|
|
349
|
+
logger.error(f"Failed to delete comment: {e}")
|
|
350
|
+
raise HTTPException(status_code=e.status_code, detail=str(e.reason))
|
|
351
|
+
except RecceException as e:
|
|
352
|
+
logger.error(f"Failed to delete comment: {e}")
|
|
353
|
+
raise HTTPException(status_code=400, detail=str(e))
|
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
from datetime import datetime
|
|
2
|
+
from typing import Optional
|
|
3
|
+
|
|
4
|
+
from fastapi import HTTPException
|
|
5
|
+
|
|
6
|
+
from recce.apis.run_func import generate_run_name
|
|
7
|
+
from recce.core import default_context
|
|
8
|
+
from recce.models import Check, CheckDAO, RunDAO, RunType
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
def validate_schema_diff_check(params):
|
|
12
|
+
node_id = params.get("node_id")
|
|
13
|
+
if node_id is None:
|
|
14
|
+
raise HTTPException(status_code=400, detail="node_id is required for schema diff")
|
|
15
|
+
node_name = default_context().get_node_name_by_id(node_id)
|
|
16
|
+
if node_name is None:
|
|
17
|
+
raise HTTPException(status_code=400, detail=f"node_id '{node_id}' not found in dbt manifest")
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
def get_node_name_by_id(node_id):
|
|
21
|
+
node_name = default_context().get_node_name_by_id(node_id)
|
|
22
|
+
if node_name is None:
|
|
23
|
+
raise HTTPException(status_code=400, detail=f"node_id '{node_id}' not found in dbt manifest")
|
|
24
|
+
return node_name
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
def _validate_check(check_type, params):
|
|
28
|
+
if check_type == RunType.SCHEMA_DIFF:
|
|
29
|
+
validate_schema_diff_check(params)
|
|
30
|
+
pass
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
def _get_ref_model(sql_template: str) -> Optional[str]:
|
|
34
|
+
import re
|
|
35
|
+
|
|
36
|
+
pattern = r'\bref\(["\']?(\w+)["\']?\)\s*}}'
|
|
37
|
+
matches = re.findall(pattern, sql_template)
|
|
38
|
+
if len(matches) == 1:
|
|
39
|
+
ref = matches[0]
|
|
40
|
+
return ref
|
|
41
|
+
|
|
42
|
+
return None
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
def _generate_check_name(check_type, params, view_options):
|
|
46
|
+
now = datetime.utcnow().strftime("%d %b %Y")
|
|
47
|
+
if check_type == RunType.SCHEMA_DIFF:
|
|
48
|
+
if params.get("node_id"):
|
|
49
|
+
nodeIds = params.get("node_id") if isinstance(params.get("node_id"), list) else [params.get("node_id")]
|
|
50
|
+
if len(nodeIds) == 1:
|
|
51
|
+
node_name = get_node_name_by_id(nodeIds[0])
|
|
52
|
+
return f"schema diff of {node_name}".capitalize()
|
|
53
|
+
else:
|
|
54
|
+
return f"schema diff of {len(nodeIds)} nodes".capitalize()
|
|
55
|
+
return f"{'schema diff'.capitalize()} - {now}"
|
|
56
|
+
elif check_type == RunType.LINEAGE_DIFF:
|
|
57
|
+
nodes = view_options.get("node_ids") if view_options else params.get("node_ids")
|
|
58
|
+
if nodes is not None:
|
|
59
|
+
return f"lineage diff of {len(nodes)} nodes".capitalize()
|
|
60
|
+
return f"{'lineage diff'.capitalize()} - {now}"
|
|
61
|
+
else:
|
|
62
|
+
return f"{'check'.capitalize()} - {now}"
|
|
63
|
+
|
|
64
|
+
|
|
65
|
+
def create_check_from_run(
|
|
66
|
+
run_id, check_name=None, check_description="", check_view_options=None, is_preset=False, is_checked=False
|
|
67
|
+
):
|
|
68
|
+
if run_id is None:
|
|
69
|
+
raise ValueError("run_id is required")
|
|
70
|
+
|
|
71
|
+
run = RunDAO().find_run_by_id(run_id)
|
|
72
|
+
if run is None:
|
|
73
|
+
raise NameError(f"Run '{run_id}' not found")
|
|
74
|
+
|
|
75
|
+
run_type = run.type
|
|
76
|
+
run_params = run.params
|
|
77
|
+
|
|
78
|
+
_validate_check(run_type, run_params)
|
|
79
|
+
name = check_name if check_name is not None else generate_run_name(run)
|
|
80
|
+
check = Check(
|
|
81
|
+
name=name,
|
|
82
|
+
description=check_description,
|
|
83
|
+
type=run_type,
|
|
84
|
+
params=run_params,
|
|
85
|
+
view_options=check_view_options,
|
|
86
|
+
is_preset=is_preset,
|
|
87
|
+
is_checked=is_checked,
|
|
88
|
+
)
|
|
89
|
+
new_check = CheckDAO().create(check)
|
|
90
|
+
run.check_id = new_check.check_id
|
|
91
|
+
|
|
92
|
+
return new_check
|
|
93
|
+
|
|
94
|
+
|
|
95
|
+
def create_check_without_run(
|
|
96
|
+
check_name, check_description, check_type, params, check_view_options, is_preset=False, is_checked=False
|
|
97
|
+
):
|
|
98
|
+
name = check_name if check_name is not None else _generate_check_name(check_type, params, check_view_options)
|
|
99
|
+
check = Check(
|
|
100
|
+
name=name,
|
|
101
|
+
description=check_description,
|
|
102
|
+
type=check_type,
|
|
103
|
+
params=params,
|
|
104
|
+
view_options=check_view_options,
|
|
105
|
+
is_preset=is_preset,
|
|
106
|
+
is_checked=is_checked,
|
|
107
|
+
)
|
|
108
|
+
new_check = CheckDAO().create(check)
|
|
109
|
+
return new_check
|
|
110
|
+
|
|
111
|
+
|
|
112
|
+
def purge_preset_checks():
|
|
113
|
+
checks = CheckDAO().list()
|
|
114
|
+
for check in checks:
|
|
115
|
+
if check.is_preset:
|
|
116
|
+
related_runs = RunDAO().list_by_check_id(check.check_id)
|
|
117
|
+
for run in related_runs:
|
|
118
|
+
RunDAO().delete(run.run_id)
|
|
119
|
+
CheckDAO().delete(check.check_id)
|
|
120
|
+
|
|
121
|
+
|
|
122
|
+
def export_persistent_state():
|
|
123
|
+
ctx = default_context()
|
|
124
|
+
state_loader = ctx.state_loader
|
|
125
|
+
if state_loader is not None:
|
|
126
|
+
is_conflict = state_loader.check_conflict()
|
|
127
|
+
if is_conflict:
|
|
128
|
+
ctx.sync_state("merge")
|
|
129
|
+
else:
|
|
130
|
+
ctx.sync_state("overwrite")
|
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
import asyncio
|
|
2
|
+
from typing import List, Optional
|
|
3
|
+
from uuid import UUID
|
|
4
|
+
|
|
5
|
+
from fastapi import APIRouter, HTTPException, Query
|
|
6
|
+
from pydantic import BaseModel
|
|
7
|
+
|
|
8
|
+
from recce.apis.run_func import cancel_run, materialize_run_results, submit_run
|
|
9
|
+
from recce.event import log_api_event
|
|
10
|
+
from recce.exceptions import RecceException
|
|
11
|
+
from recce.models import RunDAO
|
|
12
|
+
|
|
13
|
+
run_router = APIRouter(tags=["run"])
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
class CreateRunIn(BaseModel):
|
|
17
|
+
type: str
|
|
18
|
+
params: dict
|
|
19
|
+
check_id: Optional[str] = None
|
|
20
|
+
nowait: Optional[bool] = False
|
|
21
|
+
track_props: Optional[dict] = None
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
@run_router.post("/runs", status_code=201)
|
|
25
|
+
async def create_run_handler(input: CreateRunIn):
|
|
26
|
+
log_api_event(
|
|
27
|
+
"create_run",
|
|
28
|
+
dict(
|
|
29
|
+
type=input.type,
|
|
30
|
+
track_props=input.track_props,
|
|
31
|
+
),
|
|
32
|
+
)
|
|
33
|
+
try:
|
|
34
|
+
run, future = submit_run(input.type, input.params)
|
|
35
|
+
except RecceException as e:
|
|
36
|
+
raise HTTPException(status_code=400, detail=str(e))
|
|
37
|
+
|
|
38
|
+
if input.nowait:
|
|
39
|
+
return run
|
|
40
|
+
else:
|
|
41
|
+
run.result = await future
|
|
42
|
+
return run
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
@run_router.post("/runs/{run_id}/cancel")
|
|
46
|
+
async def cancel_run_handler(run_id: UUID):
|
|
47
|
+
try:
|
|
48
|
+
cancel_run(run_id)
|
|
49
|
+
except NotImplementedError:
|
|
50
|
+
pass
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
@run_router.get("/runs/{run_id}/wait")
|
|
54
|
+
async def wait_run_handler(run_id: UUID, timeout: int = Query(None, description="Maximum number of seconds to wait")):
|
|
55
|
+
run = RunDAO().find_run_by_id(run_id)
|
|
56
|
+
if run is None:
|
|
57
|
+
raise HTTPException(status_code=404, detail="Not Found")
|
|
58
|
+
|
|
59
|
+
start_time = asyncio.get_event_loop().time()
|
|
60
|
+
while run.result is None and run.error is None:
|
|
61
|
+
await asyncio.sleep(1)
|
|
62
|
+
if timeout is not None and (asyncio.get_event_loop().time() - start_time) > timeout:
|
|
63
|
+
break
|
|
64
|
+
return run
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
@run_router.get("/runs", status_code=200)
|
|
68
|
+
async def list_run_handler():
|
|
69
|
+
runs = RunDAO().list() or []
|
|
70
|
+
|
|
71
|
+
result = [
|
|
72
|
+
{
|
|
73
|
+
"run_id": run.run_id,
|
|
74
|
+
"run_at": run.run_at,
|
|
75
|
+
"name": run.name,
|
|
76
|
+
"type": run.type,
|
|
77
|
+
"params": run.params,
|
|
78
|
+
"status": run.status,
|
|
79
|
+
"check_id": run.check_id,
|
|
80
|
+
}
|
|
81
|
+
for run in runs
|
|
82
|
+
]
|
|
83
|
+
|
|
84
|
+
# sort by run_at
|
|
85
|
+
result = sorted(result, key=lambda x: x["run_at"], reverse=True)
|
|
86
|
+
|
|
87
|
+
return result
|
|
88
|
+
|
|
89
|
+
|
|
90
|
+
class SearchRunsIn(BaseModel):
|
|
91
|
+
type: str
|
|
92
|
+
params: dict
|
|
93
|
+
limit: Optional[int] = None
|
|
94
|
+
|
|
95
|
+
|
|
96
|
+
@run_router.post("/runs/search", status_code=200)
|
|
97
|
+
async def search_runs_handler(search: SearchRunsIn):
|
|
98
|
+
runs = RunDAO().list()
|
|
99
|
+
|
|
100
|
+
result = []
|
|
101
|
+
for run in runs:
|
|
102
|
+
if run.type.value != search.type:
|
|
103
|
+
continue
|
|
104
|
+
if not all(search.params[key] == run.params.get(key) for key in search.params.keys()):
|
|
105
|
+
continue
|
|
106
|
+
|
|
107
|
+
result.append(run)
|
|
108
|
+
|
|
109
|
+
if search.limit:
|
|
110
|
+
return result[-search.limit :]
|
|
111
|
+
|
|
112
|
+
return result
|
|
113
|
+
|
|
114
|
+
|
|
115
|
+
class AggregateRunsIn(BaseModel):
|
|
116
|
+
class AggregateFilter(BaseModel):
|
|
117
|
+
nodes: Optional[List[str]] = None
|
|
118
|
+
|
|
119
|
+
filter: Optional[AggregateFilter] = None
|
|
120
|
+
|
|
121
|
+
|
|
122
|
+
@run_router.post("/runs/aggregate", status_code=200)
|
|
123
|
+
async def aggregate_runs_handler(input: AggregateRunsIn):
|
|
124
|
+
try:
|
|
125
|
+
runs = RunDAO().list()
|
|
126
|
+
nodes = input.filter.nodes if input.filter and input.filter.nodes else None
|
|
127
|
+
result = materialize_run_results(runs, nodes=nodes)
|
|
128
|
+
return result
|
|
129
|
+
except Exception as e:
|
|
130
|
+
raise HTTPException(status_code=405, detail=str(e))
|