Skip to content

Fixes #35536: Add and edit custom metrics in one drawer - #35493

Queued
ShaileshParmar11 wants to merge 15 commits into
mainfrom
ShaileshParmar11/custom-metric-form-drawer
Queued

ShaileshParmar11 wants to merge 15 commits into
mainfrom
ShaileshParmar11/custom-metric-form-drawer

Conversation

@ShaileshParmar11

@ShaileshParmar11 ShaileshParmar11 commented Oct 15, 2026 •

Copy link
Copy Markdown
Contributor

Describe your changes:

Fixes #35536

Custom metrics are now added and edited in a single drawer. The standalone /add-custom-metric/:dashboardType/:fqn page and the edit modal are gone, so there is one way to create or change a custom metric. The drawer keeps the page's documentation panel: the table profile charts for a table metric, and the selected column's profile for a column metric. It follows #35190 (merged), which moved Classic Observability off Ant Design.

image image image

Type of change:

  • Improvement

High-level design:

  • One host. TableProfilerProvider renders a lazy CustomMetricFormDrawer, the same way it hosts the test case drawer, and exposes onCustomMetricDrawerOpen(isColumnMetric, metric?) on the profiler context.
    • The profiler Add → Custom Metric menu (TabFilters) opens it empty.
    • Edit on a metric graph (CustomMetricGraphs) opens it prefilled, with name and column locked.
  • Drawer layout. Core Grid: the form (CustomMetricForm, unchanged API) takes 14 of 24 columns, and the profile preview takes 10: TableProfilerChart, or SingleColumnProfile for the column picked in the form.
    • The drawer gets a read-only copy of the profiler context (permissions cleared) instead of none. The preview reads testCaseSummary, isProfilingEnabled and the custom metrics, so Data Quality Tests and the empty state match the profiler page. CustomMetricGraphs only offers Edit/Delete when permissions is set, and TableProfilerChart only blocks when permissions lacks ViewDataProfile, so the preview stays read-only. permissions is now optional on the context type; every consumer already guarded it.
    • It uses tw:z-40, because the core SlideoutMenu overlay has no z-index and the profiler sub-tabs painted through it. The test case drawer has the same fix in LESS.
  • Behaviour kept from the old page.
    • A new column metric defaults to the active profiler column.
    • After a column metric is saved, the URL moves to that column's profile so the new graph is visible.
    • The drawer refreshes the profiler's custom metrics from the PUT response, with no page reload.
  • Validation. The duplicate-name check now follows the column selected in the form instead of activeColumnFqn in the URL.
  • Query editor. The custom metric SQL field moved from SchemaEditor to the core CodeEditor (copy button header, no line numbers), matching the test case form's SQL Expression.
  • Profiler cards on core components. ProfilerDetailsCard, ProfilerLatestValue, ProfilerStateWrapper, ColumnSummary and the Data Quality Tests card now use the core Card, Box and Grid instead of hand-rolled bordered divs. This intentionally changes padding, radius (now the core 12px) and header size on the Table and Column Profile pages, not only in the drawer. The column summary and Data Quality Tests cards sit side by side on the page and wrap to a stack in narrow containers such as the drawer preview; latest-value metrics wrap instead of breaking labels per character, and the no-profiler message wraps instead of overflowing.
  • Removed: AddCustomMetricPage and its test, ROUTES.ADD_CUSTOM_METRIC, getAddCustomMetricPath and PLACEHOLDER_DASHBOARD_TYPE. Collate's own code does not reference any of them. .github/playwright/impact-map.json now maps components/DataQuality/CustomMetricForm/** instead of the removed page.
  • Alternative considered: a per-field Form Hint column like the test case drawer. Rejected because the old page's panel was the profile preview, which was the documentation being asked for.

Tests:

Use cases covered

  • Add a table metric from Table Profile: validation, create, the drawer closes and the new graph appears.
  • Add a column metric from Column Profile: the active column is preselected, the preview follows the column choice, and saving lands on that column's profile.
  • Edit a table or column metric from its graph menu: prefilled, name and column locked, and the PUT keeps persisted fields but not id.
  • A failed save keeps the drawer open and shows a toast.
  • A duplicate name is rejected.
  • The large column Select keeps keyboard navigation inside the drawer.
  • The drawer preview reads the profiler's test summary and profiling state but no permissions.

Unit tests

  • Added and updated unit tests.
  • New: CustomMetricFormDrawer.test.tsx, covering create, column preselect and preview, navigation after a column create, the edit payload, the error path and duplicate names. The TableProfilerProvider.test.tsx drawer test covers open, close, add vs edit, and the read-only context (the drawer sees the provider-computed test summary and profiling state, and permissions is undefined).
  • Updated: CustomMetricGraphs.test.tsx (real Edit → drawer), TabFilters.test.tsx (Add → drawer for table and column), SingleColumnProfile.test.tsx, TableProfilerChart.test.tsx, ProfilerStateWrapper.test.tsx.
  • Ran Jest on CustomMetricForm, Database/Profiler, RouterUtils and AuthenticatedAppRouter on 3579d983d4b: 29 suites, 416 tests passed.
  • Coverage %: not measured.

Backend integration tests

  • Not applicable (no backend changes).

Ingestion integration tests

  • Not applicable (no ingestion changes).

Playwright (UI) tests

  • Updated playwright/e2e/Features/CustomMetric.spec.ts and playwright/utils/customMetric.ts for the drawer flow. They add Edit steps for both table and column metrics, and the large-column Select test now runs in the drawer.

npx playwright test playwright/e2e/Features/CustomMetric.spec.ts --project=chromium on 3579d983d4b, against a Docker stack built from the same commit (./docker/run_local_docker.sh -m ui -d mysql, server revision 3579d983d4b) with sample data: 6 passed (30.1s), setup and teardown included.

✓ [setup] auth.setup.ts › authenticate all users (10.6s)
✓ [entity-data-setup] entity-data.setup.ts › create entity data prerequisites (6.3s)
✓ [chromium] CustomMetric.spec.ts:137 › Large column Select preserves keyboard navigation and fully reveals the focused option (6.1s)
✓ [chromium] CustomMetric.spec.ts:34 › Table custom metric (8.8s)
✓ [chromium] CustomMetric.spec.ts:85 › Column custom metric (9.2s)
✓ [entity-data-teardown] entity-data.teardown.ts › cleanup entity data prerequisites (838ms)

Earlier, on the commits before the profiler-card refactor, the wider impacted set (90 tests across CustomMetric, Profiler, ColumnProfileGraphsAfterReindex, NestedColumnsExpandCollapse, AddTestCaseNewFlow, DataQuality, DataQualityPermissions, Dimensionality, TestSuiteMultiPipeline, TableLevelTests, ColumnLevelTests and FailureThreshold) passed; one DataQuality tooltip test was flaky and passed on retry:

image image

Manual testing performed

  1. Built and started the stack from this branch (./docker/run_local_docker.sh -m ui -d mysql), checked /api/v1/system/version reports revision 3579d983d4b, and waited for the sample data DAG to finish.
  2. On sample_data.ecommerce_db.shopify.dim_address → Data Observability → Table Profile, used Add → Custom Metric: the drawer showed the form and the table profile preview. Created a metric: toast, drawer closed, graph appeared.
  3. Opened the graph menu → Edit: the drawer was prefilled, the name locked, and the preview graphs had no Edit/Delete menu. Changed the SQL and saved.
  4. On Column Profile with address_id active, used Add → Custom Metric: the column was preselected and previewed. Switched to shop_id: the preview followed, including its Data Quality Tests (1 success), and saving moved the page to shop_id.
  5. Deleted the demo metrics through the API.

UI screen recording:

Recorded on 3579d983d4b against the Docker stack above (server revision 3579d983d4b, MySQL, Elasticsearch, ingestion healthy; repository sample data loaded by the runner). 1600×900, 35s. Shows: Table Profile → Add → Custom Metric → create; Edit from the graph menu (prefilled, name locked); Column Profile → Add with address_id preselected, switching to shop_id with the preview following, and saving to shop_id.

custom-metric-drawer.mp4

Checklist:

  • I have read the CONTRIBUTING document.
  • My PR title is Fixes <issue-number>: <short explanation>
  • My PR is linked to a GitHub issue via Fixes #35536 above.
  • I have commented on my code, particularly in hard-to-understand areas.
  • For JSON Schema changes: not applicable.
  • For a UI feature or feature task: as part of PR creation, I ran the PR build in Docker with sample data and embedded a verified GitHub-hosted recording plus build/health evidence above.
  • I have added tests (unit / integration / Playwright as applicable) and listed them above.
  • Decision check: no new cross-component contract. This removes a UI-only route.

🤖 Generated with Claude Code


Summary by Gitar

  • Refactored profiler cards:
    • Moved ProfilerLatestValue, ProfilerDetailsCard and ProfilerStateWrapper onto core Card and Box components
    • Rebuilt ColumnSummary and SingleColumnProfile layouts with core Card, Grid and Box
  • Custom metric editor:
    • Switched the custom query field from SchemaEditor to core CodeEditor with a copy button

This will update automatically on new commits.

@github-actions github-actions Bot added safe to test Add this label to run secure Github workflows on PRs UI UI specific issues labels Oct 15, 2026
Replace the standalone /add-custom-metric page and the edit modal with a
single CustomMetricFormDrawer hosted by TableProfilerProvider. The profiler
Add menu opens it for a new table/column metric and the metric graph's Edit
action opens it prefilled. The drawer keeps the page's profile preview (table
profile charts, or the selected column's profile) beside the form, rendered
outside the profiler context so its metric graphs stay read-only.

Duplicate-name validation now follows the selected column instead of the URL.
The former add page navigated back to the metric's column; without that the
drawer left users on the column list, where the new graph is not shown.
@ShaileshParmar11
ShaileshParmar11 force-pushed the ShaileshParmar11/custom-metric-form-drawer branch from f2ebeef to ca44e77 Compare October 15, 2026 08:08
…olumn

Shrink the preview to two fifths of the drawer and let the profile widgets
reflow there: the column summary and Data Quality Tests cards stack when
their container is narrow (container query, so the page layout is
unchanged), latest-value metrics wrap instead of breaking labels per
character, and the no-profiler message wraps instead of overflowing.
The column summary, Data Quality Tests, profiler details and state wrapper
cards had no background and borrowed the page's white card. On the custom
metric drawer's grey preview column they turned grey; tw:bg-surface keeps
them white there and follows the card surface in dark mode.
… preview

A 24-column grid's 23 gaps (460px) are wider than the drawer's preview
column, so the stacked cards spilled past it and the panel scrolled
sideways. Use a single-column grid until the container is wide enough for
the 24-column side-by-side layout.
Swap SchemaEditor for CodeEditor so the custom metric SQL Query field
matches the test case drawer's SQL Expression box: copy button header,
no line-number gutter.
…d add page

The impact map still pointed at pages/AddCustomMetricPage/**, which no
longer exists, so changes to the drawer would not select CustomMetric.spec.ts.
…core components

Per review: the column summary and Data Quality Tests cards now use the core
Card (default style, Card.Header/Card.Content) instead of hand-rolled bordered
divs, their row is a wrapping core Box that stacks when the container is too
narrow for two 20rem cards (replacing the container query), and the custom
metric drawer lays out its form and preview with core Grid/Grid.Item.
Per review: ProfilerDetailsCard and ProfilerStateWrapper drop their
hand-rolled bordered divs (custom 10px radius) for the core Card with
Card.Content, so the profiler cards share the design system's radius,
border and surface. The cards stay overflow-visible so chart tooltips near
the edge are not clipped.
…ontent and Box

Drop the custom padding and flex classes on the latest-value card for
Card.Content's default padding and core Box layout, matching the other
profiler cards.
@ShaileshParmar11
ShaileshParmar11 marked this pull request as ready for review October 15, 2026 11:51
Copilot AI balanced review requested due to automatic review settings October 15, 2026 11:51

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

@github-actions

github-actions Bot commented Oct 15, 2026 •

Copy link
Copy Markdown
Contributor

✅ PR checks passed

The linked issue has a description and all required Shipping project fields set. Thanks!

@github-actions

Copy link
Copy Markdown
Contributor

🔄 Playwright impact map auto-refreshed

This PR touched specs or UI source that changed the source→spec routing map. I regenerated .github/playwright/impact-map.generated.json and pushed the diff to this branch.

- source entries: 932 → 935
- 3 added, 0 removed, 14 changed spec-list

New source→spec entries:
  openmetadata-ui/src/main/resources/ui/src/components/observability/data-quality/ThresholdPreview/ThresholdPreview.tsx
  openmetadata-ui/src/main/resources/ui/src/pages/ForgotPassword/ForgotPassword.component.tsx
  openmetadata-ui/src/main/resources/ui/src/pages/ResetPassword/ResetPassword.component.tsx

Entries whose spec list changed:
  openmetadata-ui/src/main/resources/ui/playwright/constant/config.ts
  openmetadata-ui/src/main/resources/ui/playwright/e2e/Utils/appMode.ts
  openmetadata-ui/src/main/resources/ui/playwright/e2e/fixtures/pages.ts
  openmetadata-ui/src/main/resources/ui/playwright/support/entity/TableClass.ts
  openmetadata-ui/src/main/resources/ui/playwright/utils/codeEditor.ts
  openmetadata-ui/src/main/resources/ui/playwright/utils/common.ts
  openmetadata-ui/src/main/resources/ui/playwright/utils/dataQuality.ts
  openmetadata-ui/src/main/resources/ui/playwright/utils/testCases.ts
  openmetadata-ui/src/main/resources/ui/src/components/DataQuality/AddDataQualityTest/components/TestCaseFormBody.tsx
  openmetadata-ui/src/main/resources/ui/src/components/DataQuality/IncidentManager/RunDetailsCard/RunDetailsCard.tsx
  … and 4 more

What is this file? It is the auto-generated half of Playwright's PR planner. It routes "if source X changes, run specs Y" by walking spec imports and cross-referencing getByTestId strings. Hand-authored routing in impact-map.json always wins on conflict.

What if I want to regenerate locally instead? Run this before pushing your next change to skip the bot commit:

python3 .github/scripts/generate_playwright_impact_map.py
git add .github/playwright/impact-map.generated.json
git commit --amend --no-edit  # or a separate commit

Copilot AI balanced review requested due to automatic review settings October 15, 2026 11:52

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

@github-actions

Copy link
Copy Markdown
Contributor

⚠️ UI Checkstyle passed — lint findings in changed files

🔍 ESLint findings in this PR's files — 0 error(s), 18 warning(s)

Errors block the build. Warnings do not yet — they are rules whose backlog is still
being worked down, listed so this PR does not add to it. See docs/ui-code-quality-gate.md.

0 error(s), 18 warning(s) across 7 changed file(s).

Count Rule
16 react-hooks/exhaustive-deps
2 openmetadata-imports/no-lower-layer-page-imports
All findings
Location Rule Message
🟡 src/components/DataQuality/CustomMetricForm/CustomMetricFormDrawer.tsx:91:6 react-hooks/exhaustive-deps React Hook useEffect has missing dependencies: 'activeColumnFqn', 'form', and 'table?.columns'. Either include them or remove the dependency array.
🟡 src/components/Database/Profiler/DataObservability/TabFilters/TabFilters.tsx:78:6 react-hooks/exhaustive-deps React Hook useMemo has an unnecessary dependency: 'isTourOpen'. Either exclude it or remove the dependency array.
🟡 src/components/Database/Profiler/DataObservability/TabFilters/TabFilters.tsx:108:9 react-hooks/exhaustive-deps The 'handleTestCaseClick' function makes the dependencies of useMemo Hook (at line 139) change on every render. Move it inside the useMemo callback. Alternative
🟡 src/components/Database/Profiler/DataObservability/TabFilters/TabFilters.tsx:113:9 react-hooks/exhaustive-deps The 'handleCustomMetricClick' function makes the dependencies of useMemo Hook (at line 139) change on every render. Move it inside the useMemo callback. Alterna
🟡 src/components/Database/Profiler/TableProfiler/CustomMetricGraphs/CustomMetricGraphs.component.tsx:119:5 react-hooks/exhaustive-deps React Hook useMemo has a missing dependency: 't'. Either include it or remove the dependency array.
🟡 src/components/Database/Profiler/TableProfiler/SingleColumnProfile.tsx:152:6 react-hooks/exhaustive-deps React Hook useMemo has missing dependencies: 'profilerDocsLink' and 't'. Either include them or remove the dependency array.
🟡 src/components/Database/Profiler/TableProfiler/SingleColumnProfile.tsx:224:6 react-hooks/exhaustive-deps React Hook useEffect has a missing dependency: 'createMetricsChartData'. Either include it or remove the dependency array.
🟡 src/components/Database/Profiler/TableProfiler/TableProfilerChart/TableProfilerChart.tsx:133:6 react-hooks/exhaustive-deps React Hook useMemo has missing dependencies: 'profilerDocsLink' and 't'. Either include them or remove the dependency array.
🟡 src/components/Database/Profiler/TableProfiler/TableProfilerChart/TableProfilerChart.tsx:154:5 react-hooks/exhaustive-deps React Hook useCallback has an unnecessary dependency: 'profileMetrics'. Either exclude it or remove the dependency array.
🟡 src/components/Database/Profiler/TableProfiler/TableProfilerChart/TableProfilerChart.tsx:192:6 react-hooks/exhaustive-deps React Hook useEffect has a missing dependency: 'fetchProfilerData'. Either include it or remove the dependency array.
🟡 src/components/Database/Profiler/TableProfiler/TableProfilerProvider.tsx:213:6 react-hooks/exhaustive-deps React Hook useMemo has a missing dependency: 'getProfileSampleValue'. Either include it or remove the dependency array.
🟡 src/components/Database/Profiler/TableProfiler/TableProfilerProvider.tsx:238:5 react-hooks/exhaustive-deps React Hook useCallback has an unnecessary dependency: 'allTestCases'. Either exclude it or remove the dependency array.
🟡 src/components/Database/Profiler/TableProfiler/TableProfilerProvider.tsx:354:6 react-hooks/exhaustive-deps React Hook useEffect has missing dependencies: 'fetchLatestProfilerData', 'isTableDeleted', and 'tableProfiler'. Either include them or remove the dependency ar
🟡 src/components/Database/Profiler/TableProfiler/TableProfilerProvider.tsx:366:6 react-hooks/exhaustive-deps React Hook useEffect has a missing dependency: 'fetchAllTests'. Either include it or remove the dependency array.
🟡 src/components/Database/Profiler/TableProfiler/TableProfilerProvider.tsx:392:6 react-hooks/exhaustive-deps React Hook useEffect has a missing dependency: 'fetchTestCaseSummary'. Either include it or remove the dependency array.
🟡 src/components/Database/Profiler/TableProfiler/TableProfilerProvider.tsx:417:6 react-hooks/exhaustive-deps React Hook useMemo has a missing dependency: 'fetchAllTests'. Either include it or remove the dependency array.
🟡 src/utils/RouterUtils.ts:47:1 openmetadata-imports/no-lower-layer-page-imports Pages are route-level composition modules. Move the shared implementation/type to a lower layer instead of importing a page from here.
🟡 src/utils/RouterUtils.ts:48:1 openmetadata-imports/no-lower-layer-page-imports Pages are route-level composition modules. Move the shared implementation/type to a lower layer instead of importing a page from here.

Fix locally (fast - only checks files changed in this branch):

make ui-checkstyle-changed

@github-actions

github-actions Bot commented Oct 15, 2026 •

Copy link
Copy Markdown
Contributor

Jest test Coverage

UI tests summary

Lines Statements Branches Functions
Coverage: 77%
77.78% (126553/162686) 64.44% (80099/124285) 65.67% (26717/40681)

The drawer rendered outside TableProfilerContext, so its profile preview
read an empty context: the column's Data Quality Tests showed 0/0/0 and the
charts showed the set-up-profiler message even when profiling was enabled.

Wrap the drawer in a copy of the profiler context with permissions cleared.
The preview now reads testCaseSummary, isProfilingEnabled and the custom
metrics, while CustomMetricGraphs (Edit/Delete only when permissions is set)
and TableProfilerChart (blocks only when permissions lack ViewDataProfile)
stay read-only. permissions becomes optional on the context interface; every
consumer already guards it.
Copilot AI balanced review requested due to automatic review settings October 15, 2026 12:19

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

@ShaileshParmar11 ShaileshParmar11 changed the title feat(ui): add and edit custom metrics in one drawer Fixes #35536: Add and edit custom metrics in one drawer Oct 15, 2026
@gitar-bot

gitar-bot Bot commented Oct 15, 2026

Copy link
Copy Markdown
Code Review ✅ Approved 1 closed / 1 findings

🟡 Medium risk · Moving custom metric creation and edits into a shared drawer changes persisted SQL expressions; a mistaken edit could distort reported metrics.

Custom metric drawer now wraps the profile preview in a read-only copy of the profiler context with permissions cleared, so Data Quality Tests and the empty state match the profiler page. No open issues remain.

✅ 1 closed
✅ Bug: Drawer preview outside provider shows 0 tests and wrong empty state

📄 openmetadata-ui/src/main/resources/ui/src/components/Database/Profiler/TableProfiler/TableProfilerProvider.tsx:456-466 📄 openmetadata-ui/src/main/resources/ui/src/components/Database/Profiler/TableProfiler/SingleColumnProfile.tsx:74-79 📄 openmetadata-ui/src/main/resources/ui/src/components/Database/Profiler/TableProfiler/TableProfilerChart/TableProfilerChart.tsx:112-117
CustomMetricFormDrawer is rendered outside TableProfilerContext.Provider (TableProfilerProvider.tsx:459-466), so useTableProfiler() returns {} inside the preview. SingleColumnProfile reads testCaseSummary from that context (SingleColumnProfile.tsx:78, 176-198), so the Data Quality Tests card in the column preview always shows 0 total, 0 passed and 0 failed, even for a column that has tests. isProfilingEnabled is also undefined there. As a result, both SingleColumnProfile and TableProfilerChart (TableProfilerChart.tsx:64, 112) show the "set up the profiler" documentation message on empty charts, not "profiler is enabled but no data". Keeping the edit/delete menus away was the goal, and it does not need the whole context removed. Wrap the drawer in a provider whose value is read-only: the real context with permissions cleared. CustomMetricGraphs only shows the menu when permissions is set, and TableProfilerChart only blocks when permissions is set but lacks ViewDataProfile, so both behave correctly with it cleared. Then update the provider test, which currently asserts the context is absent.

Verification

Rules No rules evaluated

Functional validation Not enabled

Set up

Auto-approval Not enabled

Set up

For more verification details, comment gitar display:verbose.

Options

Display: compact → Showing compact verification results.

Comment with these commands to change the behavior for this request:

Compact
gitar display:verbose         

Was this helpful? React with 👍 / 👎 | Powered by Gitar — free for open source

@sonarqubecloud

Copy link
Copy Markdown

@ShaileshParmar11
ShaileshParmar11 added this pull request to the merge queue Oct 15, 2026
Any commits made after this event will not be merged.

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

safe to test Add this label to run secure Github workflows on PRs UI UI specific issues

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Add and edit custom metrics in one drawer

3 participants