Skip to content

Commit 6e582da

Browse files
ui: fix infinite loader issue in lineage section (#24896)
* ui: fix infinite loader issue in lineage section * nit * fix failing sonar * nit * Fix flaky lienage specs (#24893) * chore(ui): handle description render common with util * fix lint error * fix unit tests * fix unit tests * add license to new file * fix unit tests * address copilot comments and if metric spec failure * fix unit tests * fix flaky domain spec failure * fix domain spec issue * remove afterAll block as not required * fix(test): lineage spec failure for AUT * fix certification test issue * fix api wait issue on reload * fix tour spec --------- Co-authored-by: Chirag Madlani <12962843+chirag-madlani@users.noreply.github.com>
1 parent 6776ade commit 6e582da

12 files changed

Lines changed: 336 additions & 315 deletions

File tree

openmetadata-ui/src/main/resources/ui/playwright/e2e/Flow/Tour.spec.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -64,9 +64,9 @@ const validateTourSteps = async (page: Page) => {
6464
await page.getByTestId('searchBox').fill('dim_a');
6565
await page.getByTestId('searchBox').press('Enter', { delay: 500 });
6666

67-
await page.waitForSelector('[data-testid="loader"]', { state: 'detached' });
68-
69-
await expect(page.locator(`[data-tour-elem="badge"]`)).toHaveText('4');
67+
await expect(page.locator(`[data-tour-elem="badge"]`)).toHaveText('4', {
68+
timeout: 1000,
69+
});
7070

7171
// step 3
7272
await page.locator('[data-tour-elem="right-arrow"]').click();

openmetadata-ui/src/main/resources/ui/playwright/e2e/Pages/Lineage.spec.ts

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -120,10 +120,9 @@ for (const EntityClass of entities) {
120120
await rearrangeNodes(page);
121121
}
122122

123-
await page.reload();
124123
const lineageRes = page.waitForResponse('/api/v1/lineage/getLineage?*');
124+
await page.reload();
125125
await lineageRes;
126-
await page.waitForLoadState('networkidle');
127126
await page.waitForSelector('[data-testid="edit-lineage"]', {
128127
state: 'visible',
129128
});
@@ -296,6 +295,9 @@ test('Verify column lineage between table and topic', async ({ page }) => {
296295
`[data-testid="lineage-node-${topicServiceFqn}"]`
297296
);
298297

298+
// ensure node will be visible in the viewport
299+
await performZoomOut(page);
300+
299301
await expect(tableServiceNode).toBeVisible();
300302
await expect(topicServiceNode).toBeVisible();
301303

openmetadata-ui/src/main/resources/ui/playwright/utils/explore.ts

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,6 @@ import { expect } from '@playwright/test';
1414
import { Page } from 'playwright';
1515
import { EXPECTED_BUCKETS } from '../constant/explore';
1616
import { getApiContext, redirectToExplorePage } from './common';
17-
import { waitForAllLoadersToDisappear } from './entity';
1817
import { openEntitySummaryPanel } from './entityPanel';
1918

2019
export interface Bucket {
@@ -40,8 +39,6 @@ export const searchAndClickOnOption = async (
4039
testId = filter.value ?? '';
4140
}
4241

43-
await waitForAllLoadersToDisappear(page);
44-
4542
await page.getByTestId(testId).click();
4643

4744
await checkCheckboxStatus(page, `${testId}-checkbox`, checkedAfterClick);

openmetadata-ui/src/main/resources/ui/src/components/DataAssetSummaryPanelV1/DataAssetSummaryPanelV1.interface.ts

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,6 @@
1111
* limitations under the License.
1212
*/
1313
import { EntityTags } from 'Models';
14-
import { LineageData } from '../../components/Lineage/Lineage.interface';
1514
import { EntityType } from '../../enums/entity.enum';
1615
import { DataProduct } from '../../generated/entity/domains/dataProduct';
1716
import { EntityReference } from '../../generated/type/entityReference';
@@ -31,8 +30,6 @@ export type DataAssetSummaryPanelProps = {
3130
entityType: EntityType;
3231
isDomainVisible?: boolean;
3332
isLineageView?: boolean;
34-
lineageData?: LineageData | null;
35-
isLineageLoading?: boolean;
3633
onOwnerUpdate?: (updatedOwners: EntityReference[]) => void;
3734
onDomainUpdate?: (updatedDomains: EntityReference[]) => void;
3835
onTierUpdate?: (updatedTier?: TagLabel) => void;

openmetadata-ui/src/main/resources/ui/src/components/DataAssetSummaryPanelV1/DataAssetSummaryPanelV1.tsx

Lines changed: 8 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
* See the License for the specific language governing permissions and
1111
* limitations under the License.
1212
*/
13-
import { isEmpty, isNil } from 'lodash';
13+
import { isEmpty } from 'lodash';
1414
import { useCallback, useEffect, useMemo, useState } from 'react';
1515
import { useTranslation } from 'react-i18next';
1616
import { usePermissionProvider } from '../../context/PermissionProvider/PermissionProvider';
@@ -23,7 +23,6 @@ import {
2323
getCurrentMillis,
2424
getEpochMillisForPastDays,
2525
} from '../../utils/date-time/DateTimeUtils';
26-
import { getUpstreamDownstreamNodesEdges } from '../../utils/EntityLineageUtils';
2726
import { getEntityChildDetails } from '../../utils/EntitySummaryPanelUtils';
2827
import {
2928
DRAWER_NAVIGATION_OPTIONS,
@@ -80,8 +79,6 @@ export const DataAssetSummaryPanelV1 = ({
8079
onGlossaryTermsUpdate,
8180
onDescriptionUpdate,
8281
onLinkClick,
83-
lineageData,
84-
isLineageLoading = false,
8582
onLineageClick,
8683
}: DataAssetSummaryPanelProps) => {
8784
const { t } = useTranslation();
@@ -170,52 +167,10 @@ export const DataAssetSummaryPanelV1 = ({
170167
);
171168
}, [dataAsset, entityType, highlights, charts, chartsDetailsLoading]);
172169

173-
const { upstreamCount, downstreamCount, shouldShowLineageSection } =
174-
useMemo(() => {
175-
if (!ENTITY_RIGHT_PANEL_LINEAGE_TABS.includes(entityType)) {
176-
return {
177-
upstreamCount: 0,
178-
downstreamCount: 0,
179-
shouldShowLineageSection: false,
180-
};
181-
}
182-
183-
if (
184-
isLineageLoading ||
185-
isNil(lineageData) ||
186-
isEmpty(dataAsset.fullyQualifiedName)
187-
) {
188-
return {
189-
upstreamCount: 0,
190-
downstreamCount: 0,
191-
shouldShowLineageSection: true,
192-
};
193-
}
194-
195-
const nodes = Object.values(lineageData.nodes).map((node) => node.entity);
196-
const edges = [
197-
...Object.values(lineageData.upstreamEdges),
198-
...Object.values(lineageData.downstreamEdges),
199-
];
200-
201-
const { upstreamNodes, downstreamNodes } =
202-
getUpstreamDownstreamNodesEdges(
203-
edges,
204-
nodes,
205-
dataAsset.fullyQualifiedName!
206-
);
207-
208-
return {
209-
upstreamCount: upstreamNodes.length,
210-
downstreamCount: downstreamNodes.length,
211-
shouldShowLineageSection: true,
212-
};
213-
}, [
214-
lineageData,
215-
entityType,
216-
dataAsset.fullyQualifiedName,
217-
isLineageLoading,
218-
]);
170+
const shouldShowLineageSection = useMemo(
171+
() => ENTITY_RIGHT_PANEL_LINEAGE_TABS.includes(entityType),
172+
[entityType]
173+
);
219174

220175
const fetchIncidentCount = useCallback(async () => {
221176
if (
@@ -500,9 +455,9 @@ export const DataAssetSummaryPanelV1 = ({
500455
)}
501456
{shouldShowLineageSection && (
502457
<LineageSection
503-
downstreamCount={downstreamCount}
504-
isLoading={isLineageLoading}
505-
upstreamCount={upstreamCount}
458+
entityFqn={dataAsset.fullyQualifiedName}
459+
entityType={entityType}
460+
key={`lineage-${dataAsset.id}`}
506461
onLineageClick={onLineageClick}
507462
/>
508463
)}

openmetadata-ui/src/main/resources/ui/src/components/Explore/EntitySummaryPanel/EntitySummaryPanel.component.tsx

Lines changed: 0 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,6 @@ import Loader from '../../common/Loader/Loader';
7777
import { DataAssetSummaryPanel } from '../../DataAssetSummaryPanel/DataAssetSummaryPanel';
7878
import { DataAssetSummaryPanelV1 } from '../../DataAssetSummaryPanelV1/DataAssetSummaryPanelV1';
7979
import EntityRightPanelVerticalNav from '../../Entity/EntityRightPanel/EntityRightPanelVerticalNav';
80-
import { ENTITY_RIGHT_PANEL_LINEAGE_TABS } from '../../Entity/EntityRightPanel/EntityRightPanelVerticalNav.constants';
8180
import { EntityRightPanelTab } from '../../Entity/EntityRightPanel/EntityRightPanelVerticalNav.interface';
8281
import { SearchedDataProps } from '../../SearchedData/SearchedData.interface';
8382
import CustomPropertiesSection from './CustomPropertiesSection';
@@ -269,36 +268,30 @@ export default function EntitySummaryPanel({
269268
}
270269

271270
try {
272-
// Mark lineage as loading for the *current* entity.
273271
setIsLineageLoading(true);
274272

275273
const response = await getLineageDataByFQN({
276274
fqn: currentFqn,
277275
entityType,
278276
config: {
279-
// When called from lineage view, the parent component passes the user's configured depths.
280277
upstreamDepth: upstreamDepth ?? 1,
281278
downstreamDepth: downstreamDepth ?? 1,
282279
nodesPerLayer: nodesPerLayer ?? 50,
283280
pipelineViewMode: pipelineViewMode ?? PipelineViewMode.Node,
284281
},
285282
});
286283

287-
// If the user switched to another entity while this request was in-flight,
288-
// ignore this stale response so we don't overwrite the newest lineage state.
289284
if (entityDetails?.details?.fullyQualifiedName !== currentFqn) {
290285
return;
291286
}
292287

293288
setLineageData(response);
294289
} catch (error) {
295-
// Only surface errors for the active entity.
296290
if (entityDetails?.details?.fullyQualifiedName === currentFqn) {
297291
showErrorToast(error as AxiosError);
298292
setLineageData(null);
299293
}
300294
} finally {
301-
// Avoid toggling the loader for an entity that is no longer active.
302295
if (entityDetails?.details?.fullyQualifiedName === currentFqn) {
303296
setIsLineageLoading(false);
304297
}
@@ -436,9 +429,6 @@ export default function EntitySummaryPanel({
436429
fetchLineageData();
437430
} else if (activeTab === EntityRightPanelTab.OVERVIEW) {
438431
fetchEntityData();
439-
if (entityType && ENTITY_RIGHT_PANEL_LINEAGE_TABS.includes(entityType)) {
440-
fetchLineageData();
441-
}
442432
}
443433
}, [
444434
activeTab,
@@ -518,8 +508,6 @@ export default function EntitySummaryPanel({
518508
}
519509
entityType={type}
520510
highlights={highlights}
521-
isLineageLoading={isLineageLoading}
522-
lineageData={lineageData}
523511
panelPath={panelPath}
524512
onDataProductsUpdate={handleDataProductsUpdate}
525513
onDescriptionUpdate={handleDescriptionUpdate}
@@ -546,8 +534,6 @@ export default function EntitySummaryPanel({
546534
handleDescriptionUpdate,
547535
handleGlossaryTermsUpdate,
548536
handleLineageClick,
549-
lineageData,
550-
isLineageLoading,
551537
]);
552538
const entityLink = useMemo(
553539
() => searchClassBase.getEntityLink(entityDetails.details),

openmetadata-ui/src/main/resources/ui/src/components/Explore/EntitySummaryPanel/EntitySummaryPanel.test.tsx

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -333,6 +333,11 @@ describe('EntitySummaryPanel component tests', () => {
333333
});
334334

335335
it('should initialize with loading state for permissions', async () => {
336+
// Force permission fetch to remain pending so we can reliably assert the initial loader state.
337+
(
338+
usePermissionProvider().getEntityPermission as jest.Mock
339+
).mockImplementationOnce(() => new Promise(() => undefined));
340+
336341
const { container } = await act(async () => {
337342
return render(
338343
<EntitySummaryPanel

openmetadata-ui/src/main/resources/ui/src/components/common/LineageSection/LineageSection.interface.ts

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,9 +11,22 @@
1111
* limitations under the License.
1212
*/
1313

14+
import { SxProps, Theme } from '@mui/material';
15+
import { EntityType } from '../../../enums/entity.enum';
16+
1417
export interface LineageSectionProps {
15-
upstreamCount: number;
16-
downstreamCount: number;
17-
isLoading?: boolean;
18+
entityFqn?: string;
19+
entityType?: EntityType;
1820
onLineageClick?: () => void;
1921
}
22+
type LineageDirection = 'upstream' | 'downstream';
23+
24+
export interface LineageItemProps {
25+
type: LineageDirection;
26+
Icon: React.FC<React.SVGProps<SVGSVGElement>>;
27+
count: number;
28+
onClick?: () => void;
29+
sectionSx: SxProps<Theme>;
30+
iconWrapperSx: SxProps<Theme>;
31+
textSx: SxProps<Theme>;
32+
}

openmetadata-ui/src/main/resources/ui/src/components/common/LineageSection/LineageSection.styles.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,11 +18,12 @@ export const getTextStyles = (theme: Theme): SxProps<Theme> => ({
1818
color: theme.palette.allShades?.info?.[700],
1919
});
2020

21-
export const getSectionStyles = (): SxProps<Theme> => ({
21+
export const getSectionStyles = (gap?: number): SxProps<Theme> => ({
2222
flex: 1,
2323
display: 'flex',
2424
alignItems: 'center',
2525
cursor: 'pointer',
26+
...(gap !== undefined ? { gap } : {}),
2627
});
2728

2829
export const getIconWrapperStyles = (theme: Theme): SxProps<Theme> => ({

0 commit comments

Comments
 (0)