Skip to content

Conversation

@harsh-vador
Copy link
Contributor

@harsh-vador harsh-vador commented Nov 11, 2025

Describe your changes:

Fixes #25083

I worked on ... because ...

Screen.Recording.2025-12-11.at.5.06.36.PM.mov

Type of change:

  • Bug fix
  • Improvement
  • New feature
  • Breaking change (fix or feature that would cause existing functionality to not work as expected)
  • Documentation

Checklist:

  • I have read the CONTRIBUTING document.
  • My PR title is Fixes <issue-number>: <short explanation>
  • I have commented on my code, particularly in hard-to-understand areas.
  • For JSON Schema changes: I updated the migration scripts or explained why it is not needed.

Summary by Gitar

  • New component:
    • ColumnDetailPanel (678 lines) displays column metadata in side drawer with tabs for Overview, Data Quality, Lineage, and Custom Properties
  • Multi-entity integration:
    • Integrated across 7 entity types: Tables, Topics, Pipelines, API Endpoints, ML Models, Containers, Dashboard Data Models
  • New utilities:
    • flattenColumns, buildColumnBreadcrumbPath, mergeTagsWithGlossary in TableUtils handle nested columns and tag/glossary preservation
  • Comprehensive testing:
    • 740 lines of unit tests plus 14 E2E test scenarios across all entity types (321→335 total tests)
  • Subcomponents:
    • KeyProfileMetrics displays profile metrics (Uniqueness, Nullness, Distinct, Value Count); NestedColumnsSection enables nested column navigation

This will update automatically on new commits.


@github-actions
Copy link
Contributor

Hi there 👋 Thanks for your contribution!

The OpenMetadata team will review the PR shortly! Once it has been labeled as safe to test, the CI workflows
will start executing and we'll be able to make sure everything is working as expected.

Let us know if you need any help!

@harsh-vador harsh-vador marked this pull request as draft November 11, 2025 13:42
@github-actions
Copy link
Contributor

Hi there 👋 Thanks for your contribution!

The OpenMetadata team will review the PR shortly! Once it has been labeled as safe to test, the CI workflows
will start executing and we'll be able to make sure everything is working as expected.

Let us know if you need any help!

@github-actions
Copy link
Contributor

Hi there 👋 Thanks for your contribution!

The OpenMetadata team will review the PR shortly! Once it has been labeled as safe to test, the CI workflows
will start executing and we'll be able to make sure everything is working as expected.

Let us know if you need any help!

@github-actions
Copy link
Contributor

Hi there 👋 Thanks for your contribution!

The OpenMetadata team will review the PR shortly! Once it has been labeled as safe to test, the CI workflows
will start executing and we'll be able to make sure everything is working as expected.

Let us know if you need any help!

@github-actions
Copy link
Contributor

github-actions bot commented Dec 1, 2025

Hi there 👋 Thanks for your contribution!

The OpenMetadata team will review the PR shortly! Once it has been labeled as safe to test, the CI workflows
will start executing and we'll be able to make sure everything is working as expected.

Let us know if you need any help!

@github-actions
Copy link
Contributor

github-actions bot commented Dec 2, 2025

Hi there 👋 Thanks for your contribution!

The OpenMetadata team will review the PR shortly! Once it has been labeled as safe to test, the CI workflows
will start executing and we'll be able to make sure everything is working as expected.

Let us know if you need any help!

@github-actions
Copy link
Contributor

Hi there 👋 Thanks for your contribution!

The OpenMetadata team will review the PR shortly! Once it has been labeled as safe to test, the CI workflows
will start executing and we'll be able to make sure everything is working as expected.

Let us know if you need any help!

@github-actions
Copy link
Contributor

Hi there 👋 Thanks for your contribution!

The OpenMetadata team will review the PR shortly! Once it has been labeled as safe to test, the CI workflows
will start executing and we'll be able to make sure everything is working as expected.

Let us know if you need any help!

… Provider (#25074)

* refactor: Simplify ColumnDetailPanel props and integrate with GenericProvider

This refactoring improves code maintainability and reduces duplication across
8 components that use ColumnDetailPanel by introducing simplified props pattern
and optional GenericProvider integration.

Key Improvements:

1. Simplified Props Pattern
   - Added 'permissions' and 'deleted' props to automatically compute edit/view permissions
   - Maintains backward compatibility with existing hasEditPermission/hasViewPermission props
   - Reduces boilerplate code in all consuming components

2. Permission Auto-computation
   - ColumnDetailPanel now derives edit permissions from OperationPermission when 'permissions' prop is provided
   - Automatically handles 'deleted' state to disable editing on deleted entities
   - Consolidates permission logic in one place

3. GenericProvider Integration
   - Added optional columnDetailPanelConfig to GenericProvider for centralized state management
   - Provides openColumnDetailPanel and closeColumnDetailPanel methods via context
   - Allows components to optionally use centralized ColumnDetailPanel rendering

4. Codebase-wide Updates
   Updated all 8 files using ColumnDetailPanel to use the new simplified pattern:
   - SchemaTable.component.tsx
   - TopicSchema.tsx
   - APIEndpointSchema.tsx
   - ContainerDataModel.tsx
   - ModelTab.component.tsx
   - MlModelFeaturesList.tsx
   - PipelineTaskTab.tsx
   - SearchIndexFieldsTable.tsx

5. Bug Fixes
   - Fixed TagsSection popover placement from 'topRight' to 'top'
   - Removed unused viewCustomPropertiesPermission variable in ModelTab

Benefits:
- Reduced code duplication across 8+ components
- More maintainable and consistent permission handling
- Easier to add new permission types in the future
- Cleaner component props with fewer required parameters
- Backward compatible - existing code continues to work

Testing:
- All ColumnDetailPanel tests pass (10/10)
- No TypeScript errors introduced
- ESLint warnings resolved

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Sonnet 4.5 <[email protected]>

* add generic provider support for mlmodel, pipeline, topic

* replace columndetailPanel component with generic provider for pending types

* remove unnecessary props & fix failing test

* minor fixes

* fix test

* remove unwanted code

* major code refactoring

* fix failing tests

* major code refactoring improvements

* nit

* improve types

* remove unwanted logic

* address comments

* refactor

---------

Co-authored-by: Claude Sonnet 4.5 <[email protected]>
Comment on lines +354 to +372
if (isColumnDetailPanel && testCases.length > 0) {
const allPromises = testCases.map((testCase) =>
getListTestCaseIncidentStatus({
latest: true,
include: Include.NonDeleted,
testCaseFQN: testCase.fullyQualifiedName,
startTs,
endTs,
limit: 50,
}).catch(() => ({ data: [] }))
);

const results = await Promise.all(allPromises);
allIncidents = results.flatMap((result) => result.data || []);
} else {
// For table/entity level, use originEntityFQN
const response = await getListTestCaseIncidentStatus({
latest: true,
include: Include.NonDeleted,
Copy link

Choose a reason for hiding this comment

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

⚠️ Performance: N+1 API calls when fetching incidents for column panel

Details

In DataQualityTab.tsx, when isColumnDetailPanel is true, the code makes separate API calls for each test case to fetch incidents. This results in N API calls where N is the number of test cases, which can be slow for columns with many tests.

if (isColumnDetailPanel && testCases.length > 0) {
  const allPromises = testCases.map((testCase) =>
    getListTestCaseIncidentStatus({
      latest: true,
      include: Include.NonDeleted,
      testCaseFQN: testCase.fullyQualifiedName,
      ...
    }).catch(() => ({ data: [] }))
  );
  const results = await Promise.all(allPromises);
  allIncidents = results.flatMap((result) => result.data || []);
}

Impact: For a column with 20 test cases, this will make 20 API calls in parallel, which may:

  1. Create significant load on the backend
  2. Slow down the panel opening experience
  3. Risk rate limiting

Suggestion: Consider batching these requests or implementing a backend endpoint that accepts multiple test case FQNs in a single call. Alternatively, add pagination/limiting to the number of concurrent requests.

Comment on lines +51 to +54
const response = await getTableColumnsByFQN(tableFqn, {
fields: TabSpecificField.PROFILE,
limit: 1000,
});
Copy link

Choose a reason for hiding this comment

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

💡 Performance: API fetches all 1000 columns to get profile for single column

Details

In KeyProfileMetrics.component.tsx, the code fetches all columns (with limit 1000) just to find the profile for a single column:

const response = await getTableColumnsByFQN(tableFqn, {
  fields: TabSpecificField.PROFILE,
  limit: 1000,
});

const columnData = response.data?.find(
  (col) => col.fullyQualifiedName === columnFqn
);

Impact: This fetches potentially thousands of column profiles when only one is needed. For tables with many columns, this is wasteful in terms of bandwidth and processing.

Suggestion: If the API supports it, filter by the specific column FQN on the backend. Alternatively, consider caching the profile data at the table level to avoid repeated fetches as users navigate between columns.

@gitar-bot
Copy link

gitar-bot bot commented Jan 8, 2026

Code Review 👍 Approved with suggestions

Well-structured implementation of column detail view with comprehensive testing, but two performance issues from the previous review remain unaddressed.

⚠️ Performance: N+1 API calls when fetching incidents for column panel

📄 openmetadata-ui/src/main/resources/ui/src/components/Explore/EntitySummaryPanel/DataQualityTab/DataQualityTab.tsx:5899-5911

In DataQualityTab.tsx, when isColumnDetailPanel is true, the code makes separate API calls for each test case to fetch incidents. This results in N API calls where N is the number of test cases, which can be slow for columns with many tests.

if (isColumnDetailPanel && testCases.length > 0) {
  const allPromises = testCases.map((testCase) =>
    getListTestCaseIncidentStatus({
      latest: true,
      include: Include.NonDeleted,
      testCaseFQN: testCase.fullyQualifiedName,
      ...
    }).catch(() => ({ data: [] }))
  );
  const results = await Promise.all(allPromises);
  allIncidents = results.flatMap((result) => result.data || []);
}

Impact: For a column with 20 test cases, this will make 20 API calls in parallel, which may:

  1. Create significant load on the backend
  2. Slow down the panel opening experience
  3. Risk rate limiting

Suggestion: Consider batching these requests or implementing a backend endpoint that accepts multiple test case FQNs in a single call. Alternatively, add pagination/limiting to the number of concurrent requests.

More details 💡 1 suggestion ✅ 3 resolved
💡 Performance: API fetches all 1000 columns to get profile for single column

📄 openmetadata-ui/src/main/resources/ui/src/components/Database/ColumnDetailPanel/KeyProfileMetrics/KeyProfileMetrics.component.tsx:3887-3896

In KeyProfileMetrics.component.tsx, the code fetches all columns (with limit 1000) just to find the profile for a single column:

const response = await getTableColumnsByFQN(tableFqn, {
  fields: TabSpecificField.PROFILE,
  limit: 1000,
});

const columnData = response.data?.find(
  (col) => col.fullyQualifiedName === columnFqn
);

Impact: This fetches potentially thousands of column profiles when only one is needed. For tables with many columns, this is wasteful in terms of bandwidth and processing.

Suggestion: If the API supports it, filter by the specific column FQN on the backend. Alternatively, consider caching the profile data at the table level to avoid repeated fetches as users navigate between columns.

Edge Case: Missing null check on updateColumnDescription return value

📄 openmetadata-ui/src/main/resources/ui/src/components/Container/ContainerDataModel/ContainerDataModel.tsx:1927-1941
In ContainerDataModel.tsx, the updateColumnDescription callback for ColumnDetailPanel may return undefined if the column is not found, but the return type is Promise<Column>:

updateColumnDescription={async (fqn, description) => {
  const containerDataModel = cloneDeep(dataModel);
  updateContainerColumnDescription(
    containerDataModel?.columns,
    fqn,
    description
  );
  await onUpdate(containerDataModel);
  // Find and return the updated column
  const updatedColumn = findFieldByFQN<Column>(
    containerDataModel?.columns ?? [],
    fqn
  );
  return updatedColumn as Column;  // Could be undefined
}}

Impact: If findFieldByFQN returns undefined (e.g., if the FQN doesn't match any column), this will return undefined cast as Column, which could cause runtime errors downstream.

Suggestion: Add proper handling for the case when the column is not found:

const updatedColumn = findFieldByFQN<Column>(containerDataModel?.columns ?? [], fqn);
if (!updatedColumn) {
  throw new Error(`Column not found: ${fqn}`);
}
return updatedColumn;
Bug: Missing `fetchIncidents` in useEffect dependency array

📄 openmetadata-ui/src/main/resources/ui/src/components/Explore/EntitySummaryPanel/DataQualityTab/DataQualityTab.tsx:444-455
The useEffect that calls fetchIncidents() when isColumnDetailPanel && testCases.length > 0 has a dependency array that only includes [testCases.length, isColumnDetailPanel], but fetchIncidents itself is a function that likely depends on other values like entityFQN and testCases.

Impact: This can lead to stale closures where fetchIncidents captures outdated values, or the linter may flag this as a missing dependency warning.

Suggested fix: Either:

  1. Add fetchIncidents to the dependency array (after wrapping it in useCallback with proper dependencies)
  2. Or inline the fetch logic directly in the useEffect
useEffect(() => {
  if (isColumnDetailPanel && testCases.length > 0) {
    fetchIncidents();
  }
}, [testCases.length, isColumnDetailPanel, fetchIncidents]); // Add fetchIncidents

// Make sure fetchIncidents is wrapped in useCallback with proper deps
Performance: Sequential batched API calls can cause performance issues

📄 openmetadata-ui/src/main/resources/ui/src/components/Explore/EntitySummaryPanel/DataQualityTab/DataQualityTab.tsx:360-380
The fetchIncidents function in DataQualityTab processes test cases in batches of 10 sequentially using for loop with await Promise.all() inside. This creates a waterfall pattern where each batch must complete before the next starts.

For example, with 100 test cases, this results in 10 sequential batch requests instead of parallelizing all requests.

Impact: Slow UI response when there are many test cases, as the total time is the sum of all batch times rather than the max.

Suggested fix: Consider using Promise.all for all batches in parallel, or use a more efficient approach like fetching all incidents with a single API call using a filter for multiple test case FQNs if the API supports it:

// Option 1: Parallel batches
const allBatchPromises = [];
for (let i = 0; i < testCases.length; i += BATCH_SIZE) {
  const batch = testCases.slice(i, i + BATCH_SIZE);
  allBatchPromises.push(
    Promise.all(batch.map((testCase) => 
      getListTestCaseIncidentStatus({...}).catch(() => ({ data: [] }))
    ))
  );
}
const results = await Promise.all(allBatchPromises);

What Works Well

Clean component architecture with good separation of concerns across ColumnDetailPanel, KeyProfileMetrics, and NestedColumnsSection. Excellent test coverage with 740+ lines of unit tests plus E2E scenarios. The GenericProvider abstraction nicely consolidates column panel state management across 7+ entity types. Good use of utility functions for tag/glossary merging and column extraction.

Recommendations

Consider batching the incident status API calls or using a different API endpoint that supports filtering by entity FQN for column-level queries. For KeyProfileMetrics, investigate if there's an API that fetches profile data for a single column by FQN rather than fetching all columns.

Options

Auto-apply is off Gitar will not commit updates to this branch.
Display: compact Hiding non-applicable rules.

Comment with these commands to change:

Auto-apply Compact
gitar auto-apply:on         
gitar display:verbose         

This comment will update automatically (Docs)

@sonarqubecloud
Copy link

sonarqubecloud bot commented Jan 8, 2026

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.

Column level detail panel

4 participants