Skip to content

Commit 0fac6b9

Browse files
anuj-kumaryclaude
andauthored
Add graph layout option with propr support (#27392)
* Refactor permission issue for ontology data mode * nit * fix specs * nit * fix lint issue * nit * Removed untitled autocomplete with antd * nit * fix lint issue * Added missing test converage * nit * Revert font-size support from Select and SelectItem context Removes fontSize from SelectContext so it can be shipped as a standalone feature in a separate PR, keeping this branch focused on permission fixes. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * Add graph layout option with propr support * Addressed comments * fix lint issue * fix lint issue * fix spacing in layout * fix test issue --------- Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
1 parent e252263 commit 0fac6b9

11 files changed

Lines changed: 331 additions & 199 deletions

File tree

openmetadata-ui/src/main/resources/ui/playwright/e2e/Features/OntologyExplorer.spec.ts

Lines changed: 11 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -377,29 +377,25 @@ test.describe('Ontology Explorer', () => {
377377
await expect(toggle).toHaveAttribute('data-selected', 'true');
378378
});
379379

380-
test('should change layout to Radial and back to Hierarchical', async ({
380+
test('should change layout to Circular and back to Hierarchical', async ({
381381
page,
382382
}) => {
383383
await waitForGraphLoaded(page);
384384
await page.getByTestId('ontology-graph-settings').click();
385385
await expect(page.getByTestId('graph-settings-close')).toBeVisible();
386386

387-
await page.getByTestId('graph-settings-layout-button').click();
387+
const layoutSelect = page.getByTestId('graph-settings-layout-select');
388+
await layoutSelect.click();
388389
await expect(
389-
page.getByRole('menuitemradio', { name: 'Radial' })
390+
page.getByRole('option', { name: 'Circular' })
390391
).toBeVisible();
391-
await page.getByRole('menuitemradio', { name: 'Radial' }).click();
392-
393-
await expect(
394-
page.getByTestId('graph-settings-layout-button')
395-
).toContainText('Radial');
392+
await page.getByRole('option', { name: 'Circular' }).click();
393+
await expect(layoutSelect).toContainText('Circular');
396394
await waitForGraphLoaded(page);
397395

398-
await page.getByTestId('graph-settings-layout-button').click();
399-
await page.getByRole('menuitemradio', { name: 'Hierarchical' }).click();
400-
await expect(
401-
page.getByTestId('graph-settings-layout-button')
402-
).toContainText('Hierarchical');
396+
await layoutSelect.click();
397+
await page.getByRole('option', { name: 'Hierarchical' }).click();
398+
await expect(layoutSelect).toContainText('Hierarchical');
403399
});
404400
});
405401

@@ -800,6 +796,8 @@ test.describe('Ontology Explorer', () => {
800796
test('should show hierarchy empty state when no hierarchical relations', async ({
801797
page,
802798
}) => {
799+
await waitForGraphLoaded(page);
800+
await applyGlossaryFilter(page, glossary.responseData.id);
803801
await waitForGraphLoaded(page);
804802
await page.getByTestId('view-mode-select').click();
805803
await page.getByRole('option', { name: 'Hierarchy' }).click();

openmetadata-ui/src/main/resources/ui/src/components/OntologyExplorer/ExportGraphPanel.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -93,7 +93,7 @@ const ExportGraphPanel: React.FC<ExportGraphPanelProps> = ({
9393
size="sm">
9494
{t('label.export-graph')}
9595
</Button>
96-
<Dropdown.Popover aria-label={t('label.export-graph')}>
96+
<Dropdown.Popover aria-label={t('label.export-graph')} placement="top">
9797
<Dropdown.Menu items={menuItems} onAction={handleAction}>
9898
{(item) => <Dropdown.Item id={item.id} label={item.label} />}
9999
</Dropdown.Menu>

openmetadata-ui/src/main/resources/ui/src/components/OntologyExplorer/FilterToolbar.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -146,7 +146,7 @@ const FilterToolbar: React.FC<FilterToolbarProps> = ({
146146
);
147147

148148
return (
149-
<div className="tw:flex tw:w-full tw:items-center tw:gap-5">
149+
<div className="tw:flex tw:w-full tw:items-center tw:gap-5 tw:pl-2">
150150
{/* View Mode dropdown — disabled in data mode */}
151151
<div
152152
className={

openmetadata-ui/src/main/resources/ui/src/components/OntologyExplorer/GraphSettingsPanel.tsx

Lines changed: 20 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -15,10 +15,11 @@ import {
1515
Button,
1616
ButtonUtility,
1717
Dropdown,
18+
Select,
1819
Toggle,
1920
Typography,
2021
} from '@openmetadata/ui-core-components';
21-
import { ChevronDown, Settings01, X } from '@untitledui/icons';
22+
import { Settings01, X } from '@untitledui/icons';
2223
import React, { useCallback, useMemo, useState } from 'react';
2324
import { useTranslation } from 'react-i18next';
2425
import { LayoutType } from './OntologyExplorer.constants';
@@ -51,7 +52,6 @@ const GraphSettingsPanel: React.FC<GraphSettingsPanelProps> = ({
5152
const layoutItems = useMemo(
5253
() => [
5354
{ id: LayoutType.Hierarchical, label: t('label.hierarchical') },
54-
{ id: LayoutType.Radial, label: t('label.radial') },
5555
{ id: LayoutType.Circular, label: t('label.circular') },
5656
],
5757
[t]
@@ -81,32 +81,23 @@ const GraphSettingsPanel: React.FC<GraphSettingsPanelProps> = ({
8181
className="tw:text-xs tw:font-semibold tw:text-gray-500">
8282
{t('label.layout')}
8383
</Typography>
84-
<Dropdown.Root>
85-
<Button
86-
className="tw:w-full tw:justify-between"
87-
color="secondary"
88-
data-testid="graph-settings-layout-button"
89-
iconTrailing={ChevronDown}
90-
size="sm">
91-
{layoutItems.find((i) => i.id === settings.layout)?.label ??
92-
t('label.layout')}
93-
</Button>
94-
<Dropdown.Popover className="tw:w-72 tw:min-w-0">
95-
<Dropdown.Menu
96-
className="tw:w-full"
97-
items={layoutItems}
98-
onAction={(key) => {
99-
const layout = layoutItems.find((i) => i.id === key)?.id;
100-
if (layout) {
101-
handleLayoutChange(layout);
102-
}
103-
}}>
104-
{(item) => (
105-
<Dropdown.Item id={item.id} label={item.label ?? ''} />
106-
)}
107-
</Dropdown.Menu>
108-
</Dropdown.Popover>
109-
</Dropdown.Root>
84+
<Select
85+
className="tw:w-full"
86+
data-testid="graph-settings-layout-select"
87+
fontSize="sm"
88+
items={layoutItems}
89+
size="sm"
90+
value={settings.layout}
91+
onChange={(key) => {
92+
const layout = layoutItems.find((i) => i.id === key)?.id;
93+
if (layout) {
94+
handleLayoutChange(layout);
95+
}
96+
}}>
97+
{(item) => (
98+
<Select.Item id={item.id} key={item.id} label={item.label} />
99+
)}
100+
</Select>
110101
</div>
111102
<div className="tw:flex tw:flex-col tw:gap-3 tw:py-4">
112103
<Toggle
@@ -129,7 +120,7 @@ const GraphSettingsPanel: React.FC<GraphSettingsPanelProps> = ({
129120
iconLeading={<Settings01 height={20} width={20} />}
130121
size="sm"
131122
/>
132-
<Dropdown.Popover aria-label={t('label.graph-settings')}>
123+
<Dropdown.Popover aria-label={t('label.graph-settings')} placement="top">
133124
{popoverContent}
134125
</Dropdown.Popover>
135126
</Dropdown.Root>

openmetadata-ui/src/main/resources/ui/src/components/OntologyExplorer/OntologyExplorer.constants.ts

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -438,13 +438,11 @@ export const MODEL_ANTV_DAGRE_RANKSEP_WITH_COMBOS = 100;
438438

439439
export enum LayoutType {
440440
Hierarchical = 'hierarchical',
441-
Radial = 'radial',
442441
Circular = 'circular',
443442
}
444443

445444
export enum LayoutEngine {
446445
Dagre = 'dagre',
447-
Radial = 'radial',
448446
Circular = 'circular',
449447
}
450448

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

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -144,6 +144,7 @@ export interface FilterToolbarProps {
144144
export interface GraphSettingsPanelProps {
145145
settings: GraphSettings;
146146
onSettingsChange: (settings: GraphSettings) => void;
147+
isDataMode?: boolean;
147148
}
148149

149150
export interface NodeContextMenuProps {
@@ -172,7 +173,7 @@ export interface MergedEdge {
172173
}
173174

174175
export interface LayoutConfig {
175-
type: 'antv-dagre' | 'dagre' | 'radial' | 'circular';
176+
type: 'antv-dagre' | 'dagre' | 'radial' | 'circular' | 'preset';
176177
[key: string]: unknown;
177178
}
178179

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

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -531,7 +531,7 @@ const OntologyExplorer: React.FC<OntologyExplorerProps> = ({
531531
return undefined;
532532
}
533533
const engine = toLayoutEngineType(settings.layout);
534-
if (engine !== LayoutEngine.Circular && engine !== LayoutEngine.Radial) {
534+
if (engine !== LayoutEngine.Circular) {
535535
return undefined;
536536
}
537537

@@ -1937,6 +1937,7 @@ const OntologyExplorer: React.FC<OntologyExplorerProps> = ({
19371937

19381938
if (
19391939
explorationMode === 'data' ||
1940+
filters.viewMode !== 'overview' ||
19401941
activeGlossaryFilter ||
19411942
!hasMoreTerms ||
19421943
isLoadingMoreRef.current ||
@@ -1986,6 +1987,7 @@ const OntologyExplorer: React.FC<OntologyExplorerProps> = ({
19861987
}, [
19871988
explorationMode,
19881989
filters.glossaryIds,
1990+
filters.viewMode,
19891991
hasMoreTerms,
19901992
scope,
19911993
loadNextTermPage,
@@ -2349,6 +2351,7 @@ const OntologyExplorer: React.FC<OntologyExplorerProps> = ({
23492351
}
23502352
/>
23512353
<GraphSettingsPanel
2354+
isDataMode={explorationMode === 'data'}
23522355
settings={settings}
23532356
onSettingsChange={handleSettingsChange}
23542357
/>

openmetadata-ui/src/main/resources/ui/src/components/OntologyExplorer/hooks/useGraphData.ts

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,6 @@ import {
2222
DIMMED_EDGE_OPACITY,
2323
EDGE_LINE_APPEND_WIDTH,
2424
EDGE_STROKE_COLOR,
25-
LayoutEngine,
2625
NODE_BORDER_COLOR,
2726
RELATION_COLORS,
2827
} from '../OntologyExplorer.constants';
@@ -359,7 +358,7 @@ export function useGraphDataBuilder({
359358
nodesForGraph.filter(
360359
(n) => n.type !== 'dataAsset' && n.type !== 'metric'
361360
),
362-
LayoutEngine.Dagre,
361+
layoutType,
363362
termHSpacing,
364363
termVSpacing
365364
)

0 commit comments

Comments
 (0)