mirror of
https://github.com/open-metadata/OpenMetadata.git
synced 2025-08-17 21:46:50 +00:00
fix lineage child node column name not taking remaining space in card and showMoreButton (#21473)
* fix lineage child node column name not taking remaning space in card * fix the showColumn button which was apperaring even if there were no columns
This commit is contained in:
parent
4c96b85a47
commit
bb54555daa
@ -137,8 +137,7 @@ export const getColumnContent = (
|
|||||||
<div
|
<div
|
||||||
className={classNames(
|
className={classNames(
|
||||||
'custom-node-column-container',
|
'custom-node-column-container',
|
||||||
isColumnTraced && 'custom-node-header-tracing',
|
isColumnTraced && 'custom-node-header-tracing'
|
||||||
showDataObservabilitySummary && 'p-r-md'
|
|
||||||
)}
|
)}
|
||||||
data-testid={`column-${fullyQualifiedName}`}
|
data-testid={`column-${fullyQualifiedName}`}
|
||||||
key={fullyQualifiedName}
|
key={fullyQualifiedName}
|
||||||
@ -152,16 +151,16 @@ export const getColumnContent = (
|
|||||||
'lineage-column-node-handle',
|
'lineage-column-node-handle',
|
||||||
encodeLineageHandles(fullyQualifiedName ?? '')
|
encodeLineageHandles(fullyQualifiedName ?? '')
|
||||||
)}
|
)}
|
||||||
<Row gutter={24}>
|
<Row className="d-flex items-center" gutter={12}>
|
||||||
<Col
|
<Col className="custom-node-name-container" flex="1">
|
||||||
className="custom-node-name-container"
|
{column.dataType && (
|
||||||
span={showDataObservabilitySummary ? 8 : 12}>
|
<div className="custom-node-name-icon">
|
||||||
<div className="custom-node-name-icon">
|
{getColumnDataTypeIcon({
|
||||||
{getColumnDataTypeIcon({
|
dataType: column.dataType,
|
||||||
dataType: column.dataType,
|
width: '14px',
|
||||||
width: '14px',
|
})}
|
||||||
})}
|
</div>
|
||||||
</div>
|
)}
|
||||||
<Typography.Text
|
<Typography.Text
|
||||||
className="custom-node-column-label"
|
className="custom-node-column-label"
|
||||||
ellipsis={{ tooltip: true }}>
|
ellipsis={{ tooltip: true }}>
|
||||||
@ -169,16 +168,18 @@ export const getColumnContent = (
|
|||||||
</Typography.Text>
|
</Typography.Text>
|
||||||
</Col>
|
</Col>
|
||||||
|
|
||||||
<Col
|
{column.constraint && (
|
||||||
className={classNames(
|
<Col
|
||||||
'custom-node-constraint',
|
className={classNames(
|
||||||
showDataObservabilitySummary ? 'text-left' : 'text-right'
|
'custom-node-constraint',
|
||||||
)}
|
showDataObservabilitySummary ? 'text-left' : 'text-right'
|
||||||
span={showDataObservabilitySummary ? 8 : 12}>
|
)}
|
||||||
{column.constraint}
|
flex="80px">
|
||||||
</Col>
|
{column.constraint}
|
||||||
|
</Col>
|
||||||
|
)}
|
||||||
{showDataObservabilitySummary && (
|
{showDataObservabilitySummary && (
|
||||||
<Col span={8}>
|
<Col flex="80px">
|
||||||
<TestSuiteSummaryWidget
|
<TestSuiteSummaryWidget
|
||||||
isLoading={isLoading}
|
isLoading={isLoading}
|
||||||
size="small"
|
size="small"
|
||||||
|
@ -0,0 +1,139 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2025 Collate.
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
import { act, fireEvent, render, screen } from '@testing-library/react';
|
||||||
|
import React from 'react';
|
||||||
|
import { useLineageProvider } from '../../../../context/LineageProvider/LineageProvider';
|
||||||
|
import { EntityType } from '../../../../enums/entity.enum';
|
||||||
|
import { LineageLayer } from '../../../../generated/settings/settings';
|
||||||
|
import NodeChildren from './NodeChildren.component';
|
||||||
|
|
||||||
|
const mockNode = {
|
||||||
|
id: 'test-id',
|
||||||
|
entityType: EntityType.TABLE,
|
||||||
|
fullyQualifiedName: 'test.fqn',
|
||||||
|
name: 'test',
|
||||||
|
columns: [
|
||||||
|
{
|
||||||
|
name: 'column1',
|
||||||
|
fullyQualifiedName: 'test.fqn.column1',
|
||||||
|
dataType: 'STRING',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'column2',
|
||||||
|
fullyQualifiedName: 'test.fqn.column2',
|
||||||
|
dataType: 'STRING',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
};
|
||||||
|
|
||||||
|
const mockLineageProvider = {
|
||||||
|
tracedColumns: [],
|
||||||
|
activeLayer: [LineageLayer.ColumnLevelLineage],
|
||||||
|
onColumnClick: jest.fn(),
|
||||||
|
columnsHavingLineage: ['test.fqn.column1'],
|
||||||
|
isEditMode: false,
|
||||||
|
expandAllColumns: false,
|
||||||
|
};
|
||||||
|
|
||||||
|
jest.mock('../../../../context/LineageProvider/LineageProvider', () => ({
|
||||||
|
useLineageProvider: jest.fn().mockImplementation(() => mockLineageProvider),
|
||||||
|
}));
|
||||||
|
|
||||||
|
jest.mock('../../../../rest/testAPI', () => ({
|
||||||
|
getTestCaseExecutionSummary: jest.fn(),
|
||||||
|
}));
|
||||||
|
|
||||||
|
jest.mock('../../../../utils/EntityLink', () => ({
|
||||||
|
EntityLink: jest.fn(),
|
||||||
|
}));
|
||||||
|
|
||||||
|
jest.mock('../../../../utils/SearchClassBase', () => ({
|
||||||
|
getEntityIcon: jest.fn().mockReturnValue('entityIcon'),
|
||||||
|
}));
|
||||||
|
|
||||||
|
jest.mock('../CustomNode.utils', () => ({
|
||||||
|
getColumnContent: jest
|
||||||
|
.fn()
|
||||||
|
.mockImplementation((column) => <p>{column.name}</p>),
|
||||||
|
}));
|
||||||
|
|
||||||
|
jest.mock('../TestSuiteSummaryWidget/TestSuiteSummaryWidget.component', () =>
|
||||||
|
jest.fn().mockReturnValue(<p>TestSuiteSummaryWidget</p>)
|
||||||
|
);
|
||||||
|
|
||||||
|
describe('NodeChildren Component', () => {
|
||||||
|
it('should show show more button when there are columns without lineage', () => {
|
||||||
|
render(<NodeChildren isConnectable={false} node={mockNode} />);
|
||||||
|
|
||||||
|
const showMoreButton = screen.getByTestId('show-more-columns-btn');
|
||||||
|
|
||||||
|
expect(showMoreButton).toBeInTheDocument();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should hide show more button when all columns are shown after clicking show more button', () => {
|
||||||
|
render(<NodeChildren isConnectable={false} node={mockNode} />);
|
||||||
|
|
||||||
|
const showMoreButton = screen.getByTestId('show-more-columns-btn');
|
||||||
|
fireEvent.click(showMoreButton);
|
||||||
|
|
||||||
|
expect(
|
||||||
|
screen.queryByTestId('show-more-columns-btn')
|
||||||
|
).not.toBeInTheDocument();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should hide show more button when all columns are shown', () => {
|
||||||
|
(useLineageProvider as jest.Mock).mockImplementation(() => ({
|
||||||
|
...mockLineageProvider,
|
||||||
|
columnsHavingLineage: ['test.fqn.column1', 'test.fqn.column2'],
|
||||||
|
}));
|
||||||
|
|
||||||
|
render(<NodeChildren isConnectable={false} node={mockNode} />);
|
||||||
|
|
||||||
|
expect(
|
||||||
|
screen.queryByTestId('show-more-columns-btn')
|
||||||
|
).not.toBeInTheDocument();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should show all columns when searching', () => {
|
||||||
|
render(<NodeChildren isConnectable={false} node={mockNode} />);
|
||||||
|
|
||||||
|
const searchInput = screen.getByPlaceholderText('label.search-entity');
|
||||||
|
act(() => {
|
||||||
|
fireEvent.change(searchInput, { target: { value: 'column' } });
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(screen.getByText('column1')).toBeInTheDocument();
|
||||||
|
expect(screen.getByText('column2')).toBeInTheDocument();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should hide show more button when searching', () => {
|
||||||
|
render(<NodeChildren isConnectable={false} node={mockNode} />);
|
||||||
|
|
||||||
|
const searchInput = screen.getByPlaceholderText('label.search-entity');
|
||||||
|
fireEvent.change(searchInput, { target: { value: 'column' } });
|
||||||
|
|
||||||
|
expect(
|
||||||
|
screen.queryByTestId('show-more-columns-btn')
|
||||||
|
).not.toBeInTheDocument();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should filter columns based on search input', () => {
|
||||||
|
render(<NodeChildren isConnectable={false} node={mockNode} />);
|
||||||
|
|
||||||
|
const searchInput = screen.getByPlaceholderText('label.search-entity');
|
||||||
|
fireEvent.change(searchInput, { target: { value: 'column1' } });
|
||||||
|
|
||||||
|
expect(screen.getByText('column1')).toBeInTheDocument();
|
||||||
|
expect(screen.queryByText('column2')).not.toBeInTheDocument();
|
||||||
|
});
|
||||||
|
});
|
@ -115,6 +115,7 @@ const NodeChildren = ({ node, isConnectable }: NodeChildrenProps) => {
|
|||||||
getEntityName(column).toLowerCase().includes(value.toLowerCase())
|
getEntityName(column).toLowerCase().includes(value.toLowerCase())
|
||||||
);
|
);
|
||||||
setFilteredColumns(filtered);
|
setFilteredColumns(filtered);
|
||||||
|
setShowAllColumns(true);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
[children]
|
[children]
|
||||||
@ -151,7 +152,7 @@ const NodeChildren = ({ node, isConnectable }: NodeChildrenProps) => {
|
|||||||
try {
|
try {
|
||||||
const response = await getTestCaseExecutionSummary(testSuite.id);
|
const response = await getTestCaseExecutionSummary(testSuite.id);
|
||||||
setSummary(response);
|
setSummary(response);
|
||||||
} catch (error) {
|
} catch {
|
||||||
setSummary(undefined);
|
setSummary(undefined);
|
||||||
} finally {
|
} finally {
|
||||||
setIsLoading(false);
|
setIsLoading(false);
|
||||||
@ -286,7 +287,9 @@ const NodeChildren = ({ node, isConnectable }: NodeChildrenProps) => {
|
|||||||
|
|
||||||
// Pre-render column data outside of the return statement
|
// Pre-render column data outside of the return statement
|
||||||
const renderedColumns = useMemo(() => {
|
const renderedColumns = useMemo(() => {
|
||||||
return filteredColumns.map((column) => renderColumnsData(column as Column));
|
return filteredColumns
|
||||||
|
.map((column) => renderColumnsData(column as Column))
|
||||||
|
.filter(Boolean);
|
||||||
}, [filteredColumns, renderColumnsData]);
|
}, [filteredColumns, renderColumnsData]);
|
||||||
|
|
||||||
// Memoize the expand/collapse icon to prevent unnecessary re-renders
|
// Memoize the expand/collapse icon to prevent unnecessary re-renders
|
||||||
@ -303,6 +306,15 @@ const NodeChildren = ({ node, isConnectable }: NodeChildrenProps) => {
|
|||||||
return searchClassBase.getEntityIcon(node.entityType ?? '');
|
return searchClassBase.getEntityIcon(node.entityType ?? '');
|
||||||
}, [node.entityType]);
|
}, [node.entityType]);
|
||||||
|
|
||||||
|
const shouldShowMoreButton = useMemo(() => {
|
||||||
|
return (
|
||||||
|
!showAllColumns &&
|
||||||
|
!isEmpty(children) &&
|
||||||
|
renderedColumns.length !== children.length &&
|
||||||
|
!searchValue
|
||||||
|
);
|
||||||
|
}, [showAllColumns, children, renderedColumns, searchValue]);
|
||||||
|
|
||||||
// Memoize the expand/collapse click handler
|
// Memoize the expand/collapse click handler
|
||||||
const handleExpandCollapseClick = useCallback((e: React.MouseEvent) => {
|
const handleExpandCollapseClick = useCallback((e: React.MouseEvent) => {
|
||||||
e.stopPropagation();
|
e.stopPropagation();
|
||||||
@ -346,18 +358,21 @@ const NodeChildren = ({ node, isConnectable }: NodeChildrenProps) => {
|
|||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<section className="m-t-md" id="table-columns">
|
{!isEmpty(renderedColumns) && (
|
||||||
<div
|
<section className="m-t-md" id="table-columns">
|
||||||
className={classNames('rounded-4 overflow-hidden', {
|
<div
|
||||||
border: !showAllColumns,
|
className={classNames('rounded-4 overflow-hidden', {
|
||||||
})}>
|
border: !showAllColumns,
|
||||||
{renderedColumns}
|
})}>
|
||||||
</div>
|
{renderedColumns}
|
||||||
</section>
|
</div>
|
||||||
|
</section>
|
||||||
|
)}
|
||||||
|
|
||||||
{!showAllColumns && (
|
{shouldShowMoreButton && (
|
||||||
<Button
|
<Button
|
||||||
className="m-t-xs text-primary"
|
className="m-t-xs text-primary"
|
||||||
|
data-testid="show-more-columns-btn"
|
||||||
type="text"
|
type="text"
|
||||||
onClick={handleShowMoreClick}>
|
onClick={handleShowMoreClick}>
|
||||||
{t('label.show-more-entity', {
|
{t('label.show-more-entity', {
|
||||||
|
@ -78,6 +78,7 @@
|
|||||||
|
|
||||||
.column-container {
|
.column-container {
|
||||||
min-height: 48px;
|
min-height: 48px;
|
||||||
|
max-width: 320px;
|
||||||
padding: 12px;
|
padding: 12px;
|
||||||
background-color: @grey-1;
|
background-color: @grey-1;
|
||||||
|
|
||||||
@ -284,16 +285,17 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.custom-node-column-container {
|
.custom-node-column-container {
|
||||||
padding: 6px;
|
padding: 6px 8px;
|
||||||
background: @white;
|
background: @white;
|
||||||
position: relative;
|
position: relative;
|
||||||
font-size: 12px;
|
font-size: 12px;
|
||||||
font-weight: 400;
|
font-weight: 400;
|
||||||
|
|
||||||
.custom-node-name-container {
|
.custom-node-name-container {
|
||||||
|
min-width: 0;
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
padding-left: 12px;
|
text-align: left;
|
||||||
gap: 4px;
|
gap: 4px;
|
||||||
|
|
||||||
.custom-node-name-icon {
|
.custom-node-name-icon {
|
||||||
@ -302,7 +304,8 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.custom-node-column-label {
|
.custom-node-column-label {
|
||||||
max-width: 140px;
|
width: 100%;
|
||||||
|
display: block;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -92,12 +92,6 @@
|
|||||||
.w-11-12 {
|
.w-11-12 {
|
||||||
width: 91.666667%;
|
width: 91.666667%;
|
||||||
}
|
}
|
||||||
.w-min-0 {
|
|
||||||
min-width: 0;
|
|
||||||
}
|
|
||||||
.w-max-full {
|
|
||||||
max-width: 100%;
|
|
||||||
}
|
|
||||||
.w-max-20 {
|
.w-max-20 {
|
||||||
max-width: 20%;
|
max-width: 20%;
|
||||||
}
|
}
|
||||||
@ -191,6 +185,9 @@
|
|||||||
width: 100vw;
|
width: 100vw;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.w-min-0 {
|
||||||
|
min-width: 0;
|
||||||
|
}
|
||||||
.w-min-10 {
|
.w-min-10 {
|
||||||
min-width: 10rem;
|
min-width: 10rem;
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user