From c95acea309e20f4d94cdaabb645883228a16e562 Mon Sep 17 00:00:00 2001 From: anuj-kumary Date: Tue, 28 Apr 2026 13:40:45 +0530 Subject: [PATCH 1/8] Add load more button on header --- .../OntologyExplorer/ExportGraphPanel.tsx | 34 ++-- .../OntologyExplorer/FilterToolbar.tsx | 57 +++++-- .../OntologyExplorer.interface.ts | 6 + .../OntologyExplorer/OntologyExplorer.tsx | 95 +++++++++-- .../OntologyNodeRelationsContent.tsx | 19 +-- .../hooks/useOntologyExplorer.ts | 154 +++++++++++++----- .../hooks/useOntologyGraph.ts | 16 +- .../hooks/useOntologyGraphDerived.ts | 6 +- .../utils/graphSearchHighlight.ts | 8 +- .../ui/src/locale/languages/ar-sa.json | 3 + .../ui/src/locale/languages/de-de.json | 3 + .../ui/src/locale/languages/en-us.json | 3 + .../ui/src/locale/languages/es-es.json | 3 + .../ui/src/locale/languages/fr-fr.json | 3 + .../ui/src/locale/languages/gl-es.json | 3 + .../ui/src/locale/languages/he-he.json | 3 + .../ui/src/locale/languages/ja-jp.json | 3 + .../ui/src/locale/languages/ko-kr.json | 3 + .../ui/src/locale/languages/mr-in.json | 3 + .../ui/src/locale/languages/nl-nl.json | 3 + .../ui/src/locale/languages/pr-pr.json | 3 + .../ui/src/locale/languages/pt-br.json | 3 + .../ui/src/locale/languages/pt-pt.json | 3 + .../ui/src/locale/languages/ru-ru.json | 3 + .../ui/src/locale/languages/th-th.json | 3 + .../ui/src/locale/languages/tr-tr.json | 3 + .../ui/src/locale/languages/zh-cn.json | 3 + .../ui/src/locale/languages/zh-tw.json | 3 + 28 files changed, 350 insertions(+), 102 deletions(-) diff --git a/openmetadata-ui/src/main/resources/ui/src/components/OntologyExplorer/ExportGraphPanel.tsx b/openmetadata-ui/src/main/resources/ui/src/components/OntologyExplorer/ExportGraphPanel.tsx index 38b022a87d56..c9da8fc0f50d 100644 --- a/openmetadata-ui/src/main/resources/ui/src/components/OntologyExplorer/ExportGraphPanel.tsx +++ b/openmetadata-ui/src/main/resources/ui/src/components/OntologyExplorer/ExportGraphPanel.tsx @@ -16,6 +16,7 @@ import { Download01 } from '@untitledui/icons'; import React, { useState } from 'react'; import type { Key } from 'react-aria-components'; import { useTranslation } from 'react-i18next'; +import { showErrorToast } from '../../utils/ToastUtils'; export enum ExportFormat { PNG = 'png', @@ -46,6 +47,7 @@ const ExportGraphPanel: React.FC = ({ }) => { const { t } = useTranslation(); const [open, setOpen] = useState(false); + const [exporting, setExporting] = useState(false); const items = [ { id: ExportFormat.PNG, label: t('label.png-uppercase') }, @@ -69,18 +71,24 @@ const ExportGraphPanel: React.FC = ({ : items.filter((item) => supportedExports.includes(item.id)); const handleAction = async (key: Key) => { - setOpen(false); - - if (key === ExportFormat.PNG) { - await onExportPng(); - } else if (key === ExportFormat.SVG) { - await onExportSvg?.(); - } else if (key === ExportFormat.JSONLD) { - await onExportJsonLd?.(); - } else if (key === ExportFormat.TURTLE) { - await onExportTurtle?.(); - } else if (key === ExportFormat.RDFXML) { - await onExportRdfXml?.(); + setExporting(true); + try { + if (key === ExportFormat.PNG) { + await onExportPng(); + } else if (key === ExportFormat.SVG) { + await onExportSvg?.(); + } else if (key === ExportFormat.JSONLD) { + await onExportJsonLd?.(); + } else if (key === ExportFormat.TURTLE) { + await onExportTurtle?.(); + } else if (key === ExportFormat.RDFXML) { + await onExportRdfXml?.(); + } + setOpen(false); + } catch (error) { + showErrorToast(String(error), t('server.entity-fetch-error')); + } finally { + setExporting(false); } }; @@ -90,6 +98,8 @@ const ExportGraphPanel: React.FC = ({ color="secondary" data-testid={testId} iconLeading={} + isDisabled={exporting} + isLoading={exporting} size="sm"> {t('label.export-graph')} diff --git a/openmetadata-ui/src/main/resources/ui/src/components/OntologyExplorer/FilterToolbar.tsx b/openmetadata-ui/src/main/resources/ui/src/components/OntologyExplorer/FilterToolbar.tsx index 03294299402e..6a706a3d2cae 100644 --- a/openmetadata-ui/src/main/resources/ui/src/components/OntologyExplorer/FilterToolbar.tsx +++ b/openmetadata-ui/src/main/resources/ui/src/components/OntologyExplorer/FilterToolbar.tsx @@ -39,7 +39,13 @@ const FilterToolbar: React.FC = ({ onFiltersChange, onViewModeChange, onClearAll, + onLoadMore, viewModeDisabled = false, + isLoading = false, + isLoadingMore = false, + hasMoreTerms = false, + loadedTermCount, + totalTermCount, }) => { const { t } = useTranslation(); @@ -147,11 +153,13 @@ const FilterToolbar: React.FC = ({ return (
- {/* View Mode dropdown — disabled in data mode */} + {/* View Mode dropdown — disabled in data mode or while loading */}
= ({ className="tw:w-36" data-testid="view-mode-select" fontSize="sm" - isDisabled={viewModeDisabled} + isDisabled={viewModeDisabled || isLoading} items={viewModeItems} size="sm" value={filters.viewMode} @@ -184,7 +192,10 @@ const FilterToolbar: React.FC = ({ {/* Glossary filter */}
= ({
= ({ />
- {/* Isolated toggle */} + {/* Isolated toggle — disabled while loading or when Cross Glossary view removes all non-connected nodes */} = ({ } /> - {onClearAll && hasActiveFilters && ( - <> -
+
+ {onLoadMore !== undefined && + loadedTermCount !== undefined && + totalTermCount !== undefined && ( + + {loadedTermCount}/{totalTermCount} {t('label.term-plural-lowercase')} + + )} + {onClearAll && hasActiveFilters && ( - - )} + )} + {onLoadMore !== undefined && ( + + )} +
); }; diff --git a/openmetadata-ui/src/main/resources/ui/src/components/OntologyExplorer/OntologyExplorer.interface.ts b/openmetadata-ui/src/main/resources/ui/src/components/OntologyExplorer/OntologyExplorer.interface.ts index 5264232db9c9..7748456e8268 100644 --- a/openmetadata-ui/src/main/resources/ui/src/components/OntologyExplorer/OntologyExplorer.interface.ts +++ b/openmetadata-ui/src/main/resources/ui/src/components/OntologyExplorer/OntologyExplorer.interface.ts @@ -136,7 +136,13 @@ export interface FilterToolbarProps { onFiltersChange: (filters: GraphFilters) => void; onViewModeChange?: (viewMode: GraphViewMode) => void; onClearAll?: () => void; + onLoadMore?: () => void; viewModeDisabled?: boolean; + isLoading?: boolean; + isLoadingMore?: boolean; + hasMoreTerms?: boolean; + loadedTermCount?: number; + totalTermCount?: number; } export interface GraphSettingsPanelProps { diff --git a/openmetadata-ui/src/main/resources/ui/src/components/OntologyExplorer/OntologyExplorer.tsx b/openmetadata-ui/src/main/resources/ui/src/components/OntologyExplorer/OntologyExplorer.tsx index 0f8770c09ef5..8b73a9e9b962 100644 --- a/openmetadata-ui/src/main/resources/ui/src/components/OntologyExplorer/OntologyExplorer.tsx +++ b/openmetadata-ui/src/main/resources/ui/src/components/OntologyExplorer/OntologyExplorer.tsx @@ -20,7 +20,8 @@ import { } from '@openmetadata/ui-core-components'; import { SearchMd } from '@untitledui/icons'; import classNames from 'classnames'; -import React from 'react'; +import React, { useEffect, useState } from 'react'; +import { ErrorBoundary } from 'react-error-boundary'; import { useTranslation } from 'react-i18next'; import { GlossaryTerm } from '../../generated/entity/data/glossaryTerm'; import { useGenericContext } from '../Customization/GenericProvider/GenericProvider'; @@ -91,6 +92,7 @@ const OntologyExplorer: React.FC = ({ const { graphRef, loading, + fetchError, isLoadingMore, glossaries, relationTypes, @@ -101,12 +103,15 @@ const OntologyExplorer: React.FC = ({ expandedTermIds, rdfEnabled, graphDataToShow, - filteredGraphData, + combinedGraphData, hierarchyGraphData, hierarchyBakedPositions, glossaryColorMap, isHierarchyView, exportableGlossaryId, + hasMoreTerms, + loadedTermCount, + totalTermCount, setFilters, setSelectedNode, handleZoomIn, @@ -119,6 +124,7 @@ const OntologyExplorer: React.FC = ({ handleModeChange, handleViewModeChange, handleRefresh, + handleLoadMore, handleScrollNearEdge, handleSettingsChange, handleFiltersChange, @@ -134,6 +140,22 @@ const OntologyExplorer: React.FC = ({ onLoadingChange, }); + const [searchInput, setSearchInput] = useState(filters.searchQuery); + + useEffect(() => { + const timer = setTimeout(() => { + setFilters((prev) => ({ ...prev, searchQuery: searchInput })); + }, 300); + + return () => clearTimeout(timer); + }, [searchInput, setFilters]); + + useEffect(() => { + if (filters.searchQuery !== searchInput) { + setSearchInput(filters.searchQuery); + } + }, [filters.searchQuery]); + const renderGraphContent = () => { const hasNoVisibleNodes = !graphDataToShow || graphDataToShow.nodes.length === 0; @@ -159,6 +181,17 @@ const OntologyExplorer: React.FC = ({ const hasNoMatchingRelationEdges = hasRelationFilter && termToTermEdges.length === 0; + if (fetchError && !loading && !graphDataToShow) { + return ( + + ); + } + if (loading && hasNoVisibleNodes) { return (
= ({ } if (hasNoVisibleNodes && !loading && graphDataToShow !== null) { + if (hasRelationFilter) { + return ( + + ); + } + const hasActiveFilter = - withoutOntologyAutocompleteAll(filters.glossaryIds).length > 0 || - hasRelationFilter; + withoutOntologyAutocompleteAll(filters.glossaryIds).length > 0; return ( = ({ return (
+ + }> = ({ onPaneClick={handleGraphPaneClick} onScrollNearEdge={handleScrollNearEdge} /> + {isLoadingMore && ( <>
@@ -278,6 +327,22 @@ const OntologyExplorer: React.FC = ({ ); }; + if (scope === 'term' && !entityId) { + return ( +
+ + {t('message.no-glossary-terms-found')} + +
+ ); + } + return (
= ({ setFilters(DEFAULT_FILTERS)} onFiltersChange={handleFiltersChange} + onLoadMore={handleLoadMore} onViewModeChange={handleViewModeChange} /> @@ -344,10 +415,8 @@ const OntologyExplorer: React.FC = ({ icon={SearchMd} inputClassName="tw:pl-10" placeholder={t('label.search-in-graph')} - value={filters.searchQuery} - onChange={(value) => - setFilters((prev) => ({ ...prev, searchQuery: value })) - } + value={searchInput} + onChange={setSearchInput} /> = ({ ontologyExplorerRelationsSlot={ isDataAssetLikeNode(selectedNode) ? undefined : ( ) diff --git a/openmetadata-ui/src/main/resources/ui/src/components/OntologyExplorer/OntologyNodeRelationsContent.tsx b/openmetadata-ui/src/main/resources/ui/src/components/OntologyExplorer/OntologyNodeRelationsContent.tsx index 2cb3bf61d162..bc6be7db8596 100644 --- a/openmetadata-ui/src/main/resources/ui/src/components/OntologyExplorer/OntologyNodeRelationsContent.tsx +++ b/openmetadata-ui/src/main/resources/ui/src/components/OntologyExplorer/OntologyNodeRelationsContent.tsx @@ -92,12 +92,14 @@ export const OntologyNodeRelationsContent: React.FC< nodeRelations.incoming.length + nodeRelations.outgoing.length; const relatedDisplayName = useCallback( - (rel: RelationRow, end: 'from' | 'to') => { + (rel: RelationRow) => { return ( - rel.relatedNode?.originalLabel ?? rel.relatedNode?.label ?? rel[end] + rel.relatedNode?.originalLabel ?? + rel.relatedNode?.label ?? + t('label.term-not-available') ); }, - [] + [t] ); const renderSection = ( @@ -105,8 +107,7 @@ export const OntologyNodeRelationsContent: React.FC< count: number, rows: RelationRow[], labelTestId: string, - countTestId: string, - otherEnd: 'from' | 'to' + countTestId: string ) => { if (rows.length === 0) { return null; @@ -130,7 +131,7 @@ export const OntologyNodeRelationsContent: React.FC<
    {rows.map((rel, rowIndex) => { - const labelText = relatedDisplayName(rel, otherEnd); + const labelText = relatedDisplayName(rel); const hasRowBelow = rowIndex < rows.length - 1; const meta = RELATION_META[rel.relationType]; @@ -201,16 +202,14 @@ export const OntologyNodeRelationsContent: React.FC< nodeRelations.outgoing.length, nodeRelations.outgoing, 'outgoing-relation-label', - 'outgoing-relation-count', - 'to' + 'outgoing-relation-count' )} {renderSection( t('label.incoming-relation-plural'), nodeRelations.incoming.length, nodeRelations.incoming, 'incoming-relation-label', - 'incoming-relation-count', - 'from' + 'incoming-relation-count' )} ); diff --git a/openmetadata-ui/src/main/resources/ui/src/components/OntologyExplorer/hooks/useOntologyExplorer.ts b/openmetadata-ui/src/main/resources/ui/src/components/OntologyExplorer/hooks/useOntologyExplorer.ts index 118a98e1e3f3..a8764474f9ec 100644 --- a/openmetadata-ui/src/main/resources/ui/src/components/OntologyExplorer/hooks/useOntologyExplorer.ts +++ b/openmetadata-ui/src/main/resources/ui/src/components/OntologyExplorer/hooks/useOntologyExplorer.ts @@ -12,7 +12,8 @@ */ import { isAxiosError } from 'axios'; -import { useCallback, useEffect, useRef, useState } from 'react'; +import { isEqual } from 'lodash'; +import { useCallback, useEffect, useMemo, useRef, useState } from 'react'; import { useTranslation } from 'react-i18next'; import { EntityType, TabSpecificField } from '../../../enums/entity.enum'; import { SearchIndex } from '../../../enums/search.enum'; @@ -144,14 +145,18 @@ async function fetchAllGlossariesPaginated(): Promise { let pages = 0; const MAX_SAFE_PAGES = 500; do { - const response = await getGlossariesList({ - fields: 'owners,tags', - limit: 100, - after: afterCursor, - }); - collected.push(...response.data); - afterCursor = response.paging?.after; - pages += 1; + try { + const response = await getGlossariesList({ + fields: 'owners,tags,termCount', + limit: 100, + after: afterCursor, + }); + collected.push(...response.data); + afterCursor = response.paging?.after; + pages += 1; + } catch { + break; + } } while (afterCursor && pages < MAX_SAFE_PAGES); return collected; @@ -249,6 +254,7 @@ export function useOntologyExplorer({ // --- State --- const [loading, setLoading] = useState(true); + const [fetchError, setFetchError] = useState(false); const [isLoadingMore, setIsLoadingMore] = useState(false); const [graphData, setGraphData] = useState(null); const [assetGraphData, setAssetGraphData] = @@ -285,6 +291,8 @@ export function useOntologyExplorer({ const savedModelGraphRef = useRef(null); const isInGlobalDataModeRef = useRef(false); + const assetFetchControllers = useRef>(new Map()); + const scrollThrottleRef = useRef(0); const pendingGlossariesRef = useRef([]); const partialGlossaryRef = useRef<{ glossary: Glossary; @@ -311,6 +319,7 @@ export function useOntologyExplorer({ glossariesRef.current = glossaries; const { + combinedGraphData, filteredGraphData, hierarchyGraphData, graphDataToShow, @@ -338,6 +347,16 @@ export function useOntologyExplorer({ dataSource, }); + const loadedTermCount = useMemo( + () => (graphData?.nodes ?? []).filter(isTermNode).length, + [graphData] + ); + + const totalTermCount = useMemo( + () => glossaries.reduce((acc, g) => acc + (g.termCount ?? 0), 0), + [glossaries] + ); + // --- Data fetching callbacks --- const fetchTermAssetCounts = useCallback( @@ -429,6 +448,10 @@ export function useOntologyExplorer({ return; } + assetFetchControllers.current.get(termNode.id)?.abort(); + const controller = new AbortController(); + assetFetchControllers.current.set(termNode.id, controller); + setLoadingTermIds((prev) => new Set(prev).add(termNode.id)); const size = Math.max(1, pageSize); @@ -445,6 +468,10 @@ export function useOntologyExplorer({ }) as Record, }); + if (controller.signal.aborted) { + return; + } + const hits = res.hits.hits ?? []; const newAssetNodes: OntologyNode[] = []; const newEdges: OntologyEdge[] = []; @@ -506,17 +533,22 @@ export function useOntologyExplorer({ return { nodes: mergedNodes, edges: mergedEdges }; }); } catch (error) { - showErrorToast( - isAxiosError(error) ? error : String(error), - t('server.entity-fetch-error') - ); + if (!controller.signal.aborted) { + showErrorToast( + isAxiosError(error) ? error : String(error), + t('server.entity-fetch-error') + ); + } } finally { - setLoadingTermIds((prev) => { - const next = new Set(prev); - next.delete(termNode.id); + if (!controller.signal.aborted) { + setLoadingTermIds((prev) => { + const next = new Set(prev); + next.delete(termNode.id); - return next; - }); + return next; + }); + } + assetFetchControllers.current.delete(termNode.id); } }, [t] @@ -610,11 +642,13 @@ export function useOntologyExplorer({ ); if (!isDataMode) { - const loadedIds = new Set(accumulated.map((term) => term.id)); - const missingIds = collectMissingRelatedTermIds(accumulated, loadedIds); + const CONCURRENCY = 8; + const MAX_RESOLUTION_DEPTH = 5; + const loadedIds = new Set(accumulated.map((term) => term.id ?? '')); + let missingIds = collectMissingRelatedTermIds(accumulated, loadedIds); + let depth = 0; - if (missingIds.size > 0) { - const CONCURRENCY = 8; + while (missingIds.size > 0 && depth < MAX_RESOLUTION_DEPTH) { const missingIdList = Array.from(missingIds); for (let i = 0; i < missingIdList.length; i += CONCURRENCY) { const batch = missingIdList.slice(i, i + CONCURRENCY); @@ -633,9 +667,12 @@ export function useOntologyExplorer({ fetched.forEach((r) => { if (r.status === 'fulfilled') { accumulated.push(r.value); + loadedIds.add(r.value.id ?? ''); } }); } + missingIds = collectMissingRelatedTermIds(accumulated, loadedIds); + depth++; } } @@ -770,18 +807,12 @@ export function useOntologyExplorer({ } if (glossaryIdParam) { - const fetchedIds = new Set(allTerms.map((term) => term.id)); - const missingIds = new Set(); - allTerms.forEach((term) => { - term.relatedTerms?.forEach((relation) => { - const id = relation.term?.id; - if (id && !fetchedIds.has(id)) { - missingIds.add(id); - } - }); - }); + const MAX_RESOLUTION_DEPTH = 5; + const fetchedIds = new Set(allTerms.map((term) => term.id ?? '')); + let missingIds = collectMissingRelatedTermIds(allTerms, fetchedIds); + let depth = 0; - if (missingIds.size > 0) { + while (missingIds.size > 0 && depth < MAX_RESOLUTION_DEPTH) { const missingIdList = Array.from(missingIds); for (let i = 0; i < missingIdList.length; i += CONCURRENCY) { const batch = missingIdList.slice(i, i + CONCURRENCY); @@ -800,9 +831,12 @@ export function useOntologyExplorer({ fetched.forEach((r) => { if (r.status === 'fulfilled') { allTerms.push(r.value); + fetchedIds.add(r.value.id ?? ''); } }); } + missingIds = collectMissingRelatedTermIds(allTerms, fetchedIds); + depth++; } } @@ -854,6 +888,7 @@ export function useOntologyExplorer({ filterFetchedGlossariesRef.current = new Set(); setAssetGraphData(null); setTermAssetCounts({}); + setFetchError(false); setGraphData(mergedData); lastLoadCompletedRef.current = Date.now(); } catch (error) { @@ -861,6 +896,7 @@ export function useOntologyExplorer({ isAxiosError(error) ? error : String(error), t('server.entity-fetch-error') ); + setFetchError(true); setGraphData(null); } finally { setLoading(false); @@ -975,6 +1011,14 @@ export function useOntologyExplorer({ // --- Effects --- + useEffect(() => { + return () => { + graphRef.current = null; + assetFetchControllers.current.forEach((c) => c.abort()); + assetFetchControllers.current.clear(); + }; + }, []); + useEffect(() => { const initializeSettings = async () => { const [enabled, relSettings] = await Promise.all([ @@ -1263,18 +1307,16 @@ export function useOntologyExplorer({ loadAssetsForDataMode, ]); - const handleScrollNearEdge = useCallback(() => { + const performLoadMore = useCallback(() => { const activeGlossaryFilter = withoutOntologyAutocompleteAll(filters.glossaryIds).length > 0; if ( explorationMode === 'data' || - filters.viewMode !== 'overview' || activeGlossaryFilter || !hasMoreTerms || isLoadingMoreRef.current || - scope !== 'global' || - Date.now() - lastLoadCompletedRef.current < 2000 + scope !== 'global' ) { return; } @@ -1290,7 +1332,7 @@ export function useOntologyExplorer({ } const existingNodeIds = new Set(prev.nodes.map((n) => n.id)); const existingEdgeKeys = new Set( - prev.edges.map((e) => `${e.from}-${e.to}`) + prev.edges.map((e) => `${e.from}-${e.to}-${e.relationType}`) ); return { @@ -1302,15 +1344,14 @@ export function useOntologyExplorer({ edges: [ ...prev.edges, ...newPageData.edges.filter( - (e) => !existingEdgeKeys.has(`${e.from}-${e.to}`) + (e) => + !existingEdgeKeys.has(`${e.from}-${e.to}-${e.relationType}`) ), ], }; }); }) - .catch(() => { - // keep existing graph on error - }) + .catch(() => {}) .finally(() => { lastLoadCompletedRef.current = Date.now(); isLoadingMoreRef.current = false; @@ -1319,7 +1360,6 @@ export function useOntologyExplorer({ }, [ explorationMode, filters.glossaryIds, - filters.viewMode, hasMoreTerms, scope, loadNextTermPage, @@ -1327,12 +1367,30 @@ export function useOntologyExplorer({ glossaries, ]); + const handleLoadMore = useCallback(() => { + performLoadMore(); + }, [performLoadMore]); + + const handleScrollNearEdge = useCallback(() => { + const now = Date.now(); + if (now - scrollThrottleRef.current < 150) { + return; + } + scrollThrottleRef.current = now; + + if (now - lastLoadCompletedRef.current < 2000) { + return; + } + + performLoadMore(); + }, [performLoadMore]); + const handleSettingsChange = useCallback((nextSettings: GraphSettings) => { - setSettings(nextSettings); + setSettings((prev) => (isEqual(prev, nextSettings) ? prev : nextSettings)); }, []); const handleFiltersChange = useCallback((newFilters: GraphFilters) => { - setFilters(newFilters); + setFilters((prev) => (isEqual(prev, newFilters) ? prev : newFilters)); }, []); const handleViewModeChange = useCallback((viewMode: GraphViewMode) => { @@ -1412,6 +1470,7 @@ export function useOntologyExplorer({ return { graphRef, loading, + fetchError, isLoadingMore, glossaries, relationTypes, @@ -1422,6 +1481,7 @@ export function useOntologyExplorer({ expandedTermIds, rdfEnabled, graphDataToShow, + combinedGraphData, filteredGraphData, hierarchyGraphData, hierarchyBakedPositions, @@ -1429,6 +1489,9 @@ export function useOntologyExplorer({ glossaryColorMap, isHierarchyView, exportableGlossaryId, + hasMoreTerms, + loadedTermCount, + totalTermCount, setFilters, setSelectedNode, handleZoomIn, @@ -1441,6 +1504,7 @@ export function useOntologyExplorer({ handleModeChange, handleViewModeChange, handleRefresh, + handleLoadMore, handleScrollNearEdge, handleSettingsChange, handleFiltersChange, diff --git a/openmetadata-ui/src/main/resources/ui/src/components/OntologyExplorer/hooks/useOntologyGraph.ts b/openmetadata-ui/src/main/resources/ui/src/components/OntologyExplorer/hooks/useOntologyGraph.ts index 9e42fe0f9060..65b599638d51 100644 --- a/openmetadata-ui/src/main/resources/ui/src/components/OntologyExplorer/hooks/useOntologyGraph.ts +++ b/openmetadata-ui/src/main/resources/ui/src/components/OntologyExplorer/hooks/useOntologyGraph.ts @@ -1199,7 +1199,7 @@ export function useOntologyGraph({ }; graph.on('edge:click', handleEdgeClick); - const EDGE_TRIGGER_PX = 400; + const TOOLBAR_AREA_PX = 80; const checkEdgeProximity = () => { const g = graphRef.current; @@ -1216,15 +1216,15 @@ export function useOntologyGraph({ const W = c.offsetWidth; const H = c.offsetHeight; - const canvasBottom = g.getCanvasByViewport([W / 2, H]); - const cvpBottom = Array.isArray(canvasBottom) - ? canvasBottom[1] - : (canvasBottom as unknown as ArrayLike)[1]; + // Canvas Y that corresponds to the toolbar zone in viewport space. + const canvasAtToolbar = g.getCanvasByViewport([W / 2, H - TOOLBAR_AREA_PX]); + const cvpAtToolbar = Array.isArray(canvasAtToolbar) + ? canvasAtToolbar[1] + : (canvasAtToolbar as unknown as ArrayLike)[1]; const { maxY } = graphBoundsRef.current; - const nearBottom = cvpBottom >= maxY - EDGE_TRIGGER_PX; - - if (nearBottom) { + // Fire when the bottom-most nodes have scrolled up to the toolbar level. + if (cvpAtToolbar >= maxY) { onScrollNearEdgeRef.current(); } }; diff --git a/openmetadata-ui/src/main/resources/ui/src/components/OntologyExplorer/hooks/useOntologyGraphDerived.ts b/openmetadata-ui/src/main/resources/ui/src/components/OntologyExplorer/hooks/useOntologyGraphDerived.ts index dfeb09170954..22dad722f60e 100644 --- a/openmetadata-ui/src/main/resources/ui/src/components/OntologyExplorer/hooks/useOntologyGraphDerived.ts +++ b/openmetadata-ui/src/main/resources/ui/src/components/OntologyExplorer/hooks/useOntologyGraphDerived.ts @@ -306,7 +306,10 @@ export function useOntologyGraphDerived({ return { nodes: filteredNodes, edges: filteredEdges }; }, [combinedGraphData, filters, explorationMode, scope, entityId]); - const isHierarchyView = filters.viewMode === 'hierarchy'; + const isHierarchyView = useMemo( + () => filters.viewMode === 'hierarchy', + [filters.viewMode] + ); const hierarchyGraphData = useMemo(() => { if (!isHierarchyView || !filteredGraphData) { @@ -461,6 +464,7 @@ export function useOntologyGraphDerived({ }, [graphDataToShow, dataSource, explorationMode, t]); return { + combinedGraphData, filteredGraphData, hierarchyGraphData, graphDataToShow, diff --git a/openmetadata-ui/src/main/resources/ui/src/components/OntologyExplorer/utils/graphSearchHighlight.ts b/openmetadata-ui/src/main/resources/ui/src/components/OntologyExplorer/utils/graphSearchHighlight.ts index 30eab24579ec..82af9ddfff3a 100644 --- a/openmetadata-ui/src/main/resources/ui/src/components/OntologyExplorer/utils/graphSearchHighlight.ts +++ b/openmetadata-ui/src/main/resources/ui/src/components/OntologyExplorer/utils/graphSearchHighlight.ts @@ -27,12 +27,16 @@ export interface GraphSearchHighlightInput { highlightedGlossaryIds: readonly string[]; } +function normalize(text: string): string { + return toLower(text).normalize('NFD').replace(/\p{M}/gu, ''); +} + function textMatches(query: string, value: string | undefined): boolean { if (!value) { return false; } - return includes(toLower(value), query); + return includes(normalize(value), query); } export function ontologyEdgeKey(edge: OntologyEdge): string { @@ -50,7 +54,7 @@ export function computeGraphSearchHighlight( glossaries: Glossary[], relationTypes: GlossaryTermRelationType[] ): GraphSearchHighlightInput | null { - const query = rawQuery.trim().toLowerCase(); + const query = normalize(rawQuery.trim()); if (!query) { return null; } diff --git a/openmetadata-ui/src/main/resources/ui/src/locale/languages/ar-sa.json b/openmetadata-ui/src/main/resources/ui/src/locale/languages/ar-sa.json index 568e2b41ad91..56029cf0a506 100644 --- a/openmetadata-ui/src/main/resources/ui/src/locale/languages/ar-sa.json +++ b/openmetadata-ui/src/main/resources/ui/src/locale/languages/ar-sa.json @@ -1218,6 +1218,7 @@ "live": "مباشر", "live-indexing": "الفهرسة المباشرة", "load-more": "تحميل المزيد", + "loaded-x-of-y-entity": "{{loaded}}/{{total}} {{entity}}", "loading": "جاري التحميل", "loading-article": "Loading article...", "loading-graph": "مخطط التحميل", @@ -2118,7 +2119,9 @@ "term": "مصطلح", "term-boost": "تعزيز المصطلح", "term-lowercase": "مصطلح", + "term-not-available": "المصطلح غير متاح", "term-plural": "مصطلحات", + "term-plural-lowercase": "terms", "terms-of-service": "شروط الخدمة", "test": "اختبار", "test-applied-on-entity": "الاختبار المطبق على {{entity}}", diff --git a/openmetadata-ui/src/main/resources/ui/src/locale/languages/de-de.json b/openmetadata-ui/src/main/resources/ui/src/locale/languages/de-de.json index f82ff2ad44ad..5bbf6024bcbb 100644 --- a/openmetadata-ui/src/main/resources/ui/src/locale/languages/de-de.json +++ b/openmetadata-ui/src/main/resources/ui/src/locale/languages/de-de.json @@ -1218,6 +1218,7 @@ "live": "Live", "live-indexing": "Live-Indexierung", "load-more": "Mehr laden", + "loaded-x-of-y-entity": "{{loaded}}/{{total}} {{entity}}", "loading": "Laden", "loading-article": "Artikel wird geladen...", "loading-graph": "Diagramm wird geladen", @@ -2118,7 +2119,9 @@ "term": "Begriff", "term-boost": "Begriffsverstärkung", "term-lowercase": "begriff", + "term-not-available": "Begriff nicht verfügbar", "term-plural": "Begriffe", + "term-plural-lowercase": "terms", "terms-of-service": "Nutzungsbedingungen", "test": "Test", "test-applied-on-entity": "Test angewendet auf {{entity}}", diff --git a/openmetadata-ui/src/main/resources/ui/src/locale/languages/en-us.json b/openmetadata-ui/src/main/resources/ui/src/locale/languages/en-us.json index a67b7649063b..80c2301486b2 100644 --- a/openmetadata-ui/src/main/resources/ui/src/locale/languages/en-us.json +++ b/openmetadata-ui/src/main/resources/ui/src/locale/languages/en-us.json @@ -1218,6 +1218,7 @@ "live": "Live", "live-indexing": "Live Indexing", "load-more": "Load More", + "loaded-x-of-y-entity": "{{loaded}}/{{total}} {{entity}}", "loading": "Loading", "loading-article": "Loading article...", "loading-graph": "Loading Graph", @@ -2118,7 +2119,9 @@ "term": "Term", "term-boost": "Term Boost", "term-lowercase": "term", + "term-not-available": "Term not available", "term-plural": "Terms", + "term-plural-lowercase": "terms", "terms-of-service": "Terms of Service", "test": "Test", "test-applied-on-entity": "Test applied on {{entity}}", diff --git a/openmetadata-ui/src/main/resources/ui/src/locale/languages/es-es.json b/openmetadata-ui/src/main/resources/ui/src/locale/languages/es-es.json index d47a524cce19..d8dfd2cf59b4 100644 --- a/openmetadata-ui/src/main/resources/ui/src/locale/languages/es-es.json +++ b/openmetadata-ui/src/main/resources/ui/src/locale/languages/es-es.json @@ -1218,6 +1218,7 @@ "live": "Vivo", "live-indexing": "Indexación en vivo", "load-more": "Cargar más", + "loaded-x-of-y-entity": "{{loaded}}/{{total}} {{entity}}", "loading": "Cargando", "loading-article": "Cargando artículo...", "loading-graph": "Cargando gráfico", @@ -2118,7 +2119,9 @@ "term": "Término", "term-boost": "Impulso de Término", "term-lowercase": "término", + "term-not-available": "Término no disponible", "term-plural": "Términos", + "term-plural-lowercase": "terms", "terms-of-service": "Términos del servicio", "test": "Prueba", "test-applied-on-entity": "Prueba aplicada en {{entity}}", diff --git a/openmetadata-ui/src/main/resources/ui/src/locale/languages/fr-fr.json b/openmetadata-ui/src/main/resources/ui/src/locale/languages/fr-fr.json index 6aa7fefd587b..2766ba427a87 100644 --- a/openmetadata-ui/src/main/resources/ui/src/locale/languages/fr-fr.json +++ b/openmetadata-ui/src/main/resources/ui/src/locale/languages/fr-fr.json @@ -1218,6 +1218,7 @@ "live": "En Direct", "live-indexing": "Indexation en direct", "load-more": "Plus", + "loaded-x-of-y-entity": "{{loaded}}/{{total}} {{entity}}", "loading": "Chargement", "loading-article": "Chargement de l'article...", "loading-graph": "Chargement du graphique", @@ -2118,7 +2119,9 @@ "term": "Terme", "term-boost": "Boost de Terme", "term-lowercase": "terme", + "term-not-available": "Terme non disponible", "term-plural": "Termes", + "term-plural-lowercase": "terms", "terms-of-service": "Conditions d’utilisation", "test": "Test", "test-applied-on-entity": "Test appliqué sur {{entity}}", diff --git a/openmetadata-ui/src/main/resources/ui/src/locale/languages/gl-es.json b/openmetadata-ui/src/main/resources/ui/src/locale/languages/gl-es.json index 6e84b05925c7..5c1a41d84a99 100644 --- a/openmetadata-ui/src/main/resources/ui/src/locale/languages/gl-es.json +++ b/openmetadata-ui/src/main/resources/ui/src/locale/languages/gl-es.json @@ -1218,6 +1218,7 @@ "live": "En directo", "live-indexing": "Indexación en vivo", "load-more": "Cargar máis", + "loaded-x-of-y-entity": "{{loaded}}/{{total}} {{entity}}", "loading": "Cargando", "loading-article": "Loading article...", "loading-graph": "Cargando gráfico", @@ -2118,7 +2119,9 @@ "term": "Termo", "term-boost": "Impulso de Termo", "term-lowercase": "termo", + "term-not-available": "Termo non dispoñible", "term-plural": "Termos", + "term-plural-lowercase": "terms", "terms-of-service": "Termos de servizo", "test": "Proba", "test-applied-on-entity": "Proba aplicada en {{entity}}", diff --git a/openmetadata-ui/src/main/resources/ui/src/locale/languages/he-he.json b/openmetadata-ui/src/main/resources/ui/src/locale/languages/he-he.json index c9c776d49646..2171fcb355ae 100644 --- a/openmetadata-ui/src/main/resources/ui/src/locale/languages/he-he.json +++ b/openmetadata-ui/src/main/resources/ui/src/locale/languages/he-he.json @@ -1218,6 +1218,7 @@ "live": "שידור חי", "live-indexing": "אינדוקס בזמן אמת", "load-more": "טען עוד", + "loaded-x-of-y-entity": "{{loaded}}/{{total}} {{entity}}", "loading": "טוען", "loading-article": "טוען מאמר...", "loading-graph": "טוען גרף", @@ -2118,7 +2119,9 @@ "term": "מונח", "term-boost": "הגברת מונח", "term-lowercase": "מונח", + "term-not-available": "המונח אינו זמין", "term-plural": "מונחים", + "term-plural-lowercase": "terms", "terms-of-service": "תנאי שירות", "test": "בדיקה", "test-applied-on-entity": "בדיקה הוחלה על {{entity}}", diff --git a/openmetadata-ui/src/main/resources/ui/src/locale/languages/ja-jp.json b/openmetadata-ui/src/main/resources/ui/src/locale/languages/ja-jp.json index 2c6dc00701b8..bd99f79fed28 100644 --- a/openmetadata-ui/src/main/resources/ui/src/locale/languages/ja-jp.json +++ b/openmetadata-ui/src/main/resources/ui/src/locale/languages/ja-jp.json @@ -1218,6 +1218,7 @@ "live": "ライブ", "live-indexing": "ライブインデックス", "load-more": "さらに読み込む", + "loaded-x-of-y-entity": "{{loaded}}/{{total}} {{entity}}", "loading": "読み込み中", "loading-article": "記事を読み込んでいます...", "loading-graph": "グラフの読み込み中", @@ -2118,7 +2119,9 @@ "term": "用語", "term-boost": "用語ブースト", "term-lowercase": "用語", + "term-not-available": "用語は利用できません", "term-plural": "用語", + "term-plural-lowercase": "terms", "terms-of-service": "サービス利用規約", "test": "テスト", "test-applied-on-entity": "{{entity}} に適用されたテスト", diff --git a/openmetadata-ui/src/main/resources/ui/src/locale/languages/ko-kr.json b/openmetadata-ui/src/main/resources/ui/src/locale/languages/ko-kr.json index 7a09080b1343..1e06b25dc46f 100644 --- a/openmetadata-ui/src/main/resources/ui/src/locale/languages/ko-kr.json +++ b/openmetadata-ui/src/main/resources/ui/src/locale/languages/ko-kr.json @@ -1218,6 +1218,7 @@ "live": "실시간", "live-indexing": "라이브 인덱싱", "load-more": "더 불러오기", + "loaded-x-of-y-entity": "{{loaded}}/{{total}} {{entity}}", "loading": "로딩 중", "loading-article": "기사 로드 중...", "loading-graph": "그래프 로딩 중", @@ -2118,7 +2119,9 @@ "term": "용어", "term-boost": "용어 부스트", "term-lowercase": "용어", + "term-not-available": "사용할 수 없는 용어", "term-plural": "용어들", + "term-plural-lowercase": "terms", "terms-of-service": "이용 약관", "test": "테스트", "test-applied-on-entity": "{{entity}} 에 적용된 테스트", diff --git a/openmetadata-ui/src/main/resources/ui/src/locale/languages/mr-in.json b/openmetadata-ui/src/main/resources/ui/src/locale/languages/mr-in.json index bd9dddd82a89..46a8638b4ed4 100644 --- a/openmetadata-ui/src/main/resources/ui/src/locale/languages/mr-in.json +++ b/openmetadata-ui/src/main/resources/ui/src/locale/languages/mr-in.json @@ -1218,6 +1218,7 @@ "live": "थेट", "live-indexing": "लाइव्ह इंडेक्सिंग", "load-more": "अधिक लोड करा", + "loaded-x-of-y-entity": "{{loaded}}/{{total}} {{entity}}", "loading": "लोड करत आहे", "loading-article": "Loading article...", "loading-graph": "Loading Graph", @@ -2118,7 +2119,9 @@ "term": "संज्ञा", "term-boost": "टर्म बूस्ट", "term-lowercase": "संज्ञा", + "term-not-available": "संज्ञा उपलब्ध नाही", "term-plural": "संज्ञा", + "term-plural-lowercase": "terms", "terms-of-service": "सेवांची अटी", "test": "चाचणी", "test-applied-on-entity": "{{entity}} वर लागू केलेली चाचणी", diff --git a/openmetadata-ui/src/main/resources/ui/src/locale/languages/nl-nl.json b/openmetadata-ui/src/main/resources/ui/src/locale/languages/nl-nl.json index 2beda4ec8067..92af8490405d 100644 --- a/openmetadata-ui/src/main/resources/ui/src/locale/languages/nl-nl.json +++ b/openmetadata-ui/src/main/resources/ui/src/locale/languages/nl-nl.json @@ -1218,6 +1218,7 @@ "live": "Live", "live-indexing": "Live indexering", "load-more": "Meer laden", + "loaded-x-of-y-entity": "{{loaded}}/{{total}} {{entity}}", "loading": "Laden", "loading-article": "Loading article...", "loading-graph": "Loading Graph", @@ -2118,7 +2119,9 @@ "term": "Termijn", "term-boost": "Termijnboost", "term-lowercase": "termijn", + "term-not-available": "Term niet beschikbaar", "term-plural": "Termen", + "term-plural-lowercase": "terms", "terms-of-service": "Gebruiksvoorwaarden", "test": "Test", "test-applied-on-entity": "Test toegepast op {{entity}}", diff --git a/openmetadata-ui/src/main/resources/ui/src/locale/languages/pr-pr.json b/openmetadata-ui/src/main/resources/ui/src/locale/languages/pr-pr.json index 3834afdfc952..f09d3656cfd4 100644 --- a/openmetadata-ui/src/main/resources/ui/src/locale/languages/pr-pr.json +++ b/openmetadata-ui/src/main/resources/ui/src/locale/languages/pr-pr.json @@ -1218,6 +1218,7 @@ "live": "زنده", "live-indexing": "Indexação ao vivo", "load-more": "بارگذاری بیشتر", + "loaded-x-of-y-entity": "{{loaded}}/{{total}} {{entity}}", "loading": "در حال بارگذاری", "loading-article": "Loading article...", "loading-graph": "Loading Graph", @@ -2118,7 +2119,9 @@ "term": "واژه", "term-boost": "تقویت مترادف", "term-lowercase": "واژه", + "term-not-available": "اصطلاح در دسترس نیست", "term-plural": "واژه‌ها", + "term-plural-lowercase": "terms", "terms-of-service": "شرایط خدمات", "test": "تست", "test-applied-on-entity": "تست اعمال شده بر {{entity}}", diff --git a/openmetadata-ui/src/main/resources/ui/src/locale/languages/pt-br.json b/openmetadata-ui/src/main/resources/ui/src/locale/languages/pt-br.json index 6a048918d29e..650da9a9f076 100644 --- a/openmetadata-ui/src/main/resources/ui/src/locale/languages/pt-br.json +++ b/openmetadata-ui/src/main/resources/ui/src/locale/languages/pt-br.json @@ -1218,6 +1218,7 @@ "live": "Ao Vivo", "live-indexing": "Indexação ao vivo", "load-more": "Carregar Mais", + "loaded-x-of-y-entity": "{{loaded}}/{{total}} {{entity}}", "loading": "Carregando", "loading-article": "Carregando artigo...", "loading-graph": "Carregando Gráfico", @@ -2118,7 +2119,9 @@ "term": "Termo", "term-boost": "Impulso de Termo", "term-lowercase": "termo", + "term-not-available": "Termo não disponível", "term-plural": "Termos", + "term-plural-lowercase": "terms", "terms-of-service": "Termos de Serviço", "test": "Teste", "test-applied-on-entity": "Teste aplicado em {{entity}}", diff --git a/openmetadata-ui/src/main/resources/ui/src/locale/languages/pt-pt.json b/openmetadata-ui/src/main/resources/ui/src/locale/languages/pt-pt.json index 6a33fee4d2ea..9971d8158b46 100644 --- a/openmetadata-ui/src/main/resources/ui/src/locale/languages/pt-pt.json +++ b/openmetadata-ui/src/main/resources/ui/src/locale/languages/pt-pt.json @@ -1218,6 +1218,7 @@ "live": "Ao Vivo", "live-indexing": "Indexação em direto", "load-more": "Carregar Mais", + "loaded-x-of-y-entity": "{{loaded}}/{{total}} {{entity}}", "loading": "Carregando", "loading-article": "Loading article...", "loading-graph": "A carregar gráfico", @@ -2118,7 +2119,9 @@ "term": "Termo", "term-boost": "Impulso de Termo", "term-lowercase": "termo", + "term-not-available": "Termo não disponível", "term-plural": "Termos", + "term-plural-lowercase": "terms", "terms-of-service": "Termos de Serviço", "test": "Teste", "test-applied-on-entity": "Teste aplicado em {{entity}}", diff --git a/openmetadata-ui/src/main/resources/ui/src/locale/languages/ru-ru.json b/openmetadata-ui/src/main/resources/ui/src/locale/languages/ru-ru.json index ec620775723a..74decd201425 100644 --- a/openmetadata-ui/src/main/resources/ui/src/locale/languages/ru-ru.json +++ b/openmetadata-ui/src/main/resources/ui/src/locale/languages/ru-ru.json @@ -1218,6 +1218,7 @@ "live": "Процесс", "live-indexing": "Индексация в реальном времени", "load-more": "Загрузить больше", + "loaded-x-of-y-entity": "{{loaded}}/{{total}} {{entity}}", "loading": "Загрузка", "loading-article": "Загрузка статьи...", "loading-graph": "Загрузка графа", @@ -2118,7 +2119,9 @@ "term": "Термин", "term-boost": "Усиление тега", "term-lowercase": "термин", + "term-not-available": "Термин недоступен", "term-plural": "Термины", + "term-plural-lowercase": "terms", "terms-of-service": "Условия обслуживания", "test": "Тест", "test-applied-on-entity": "Тест применён к {{entity}}", diff --git a/openmetadata-ui/src/main/resources/ui/src/locale/languages/th-th.json b/openmetadata-ui/src/main/resources/ui/src/locale/languages/th-th.json index d4fa72953076..93a184641be9 100644 --- a/openmetadata-ui/src/main/resources/ui/src/locale/languages/th-th.json +++ b/openmetadata-ui/src/main/resources/ui/src/locale/languages/th-th.json @@ -1218,6 +1218,7 @@ "live": "สด", "live-indexing": "การจัดทำดัชนีแบบเรียลไทม์", "load-more": "โหลดเพิ่มเติม", + "loaded-x-of-y-entity": "{{loaded}}/{{total}} {{entity}}", "loading": "กำลังโหลด", "loading-article": "Loading article...", "loading-graph": "Loading Graph", @@ -2118,7 +2119,9 @@ "term": "คำศัพท์", "term-boost": "การเพิ่มคำศัพท์", "term-lowercase": "คำศัพท์", + "term-not-available": "ไม่มีคำศัพท์นี้", "term-plural": "คำศัพท์หลายรายการ", + "term-plural-lowercase": "terms", "terms-of-service": "ข้อตกลงการให้บริการ", "test": "ทดสอบ", "test-applied-on-entity": "ทดสอบที่ใช้กับ {{entity}}", diff --git a/openmetadata-ui/src/main/resources/ui/src/locale/languages/tr-tr.json b/openmetadata-ui/src/main/resources/ui/src/locale/languages/tr-tr.json index cfc97c8ea269..c18fdef524f6 100644 --- a/openmetadata-ui/src/main/resources/ui/src/locale/languages/tr-tr.json +++ b/openmetadata-ui/src/main/resources/ui/src/locale/languages/tr-tr.json @@ -1218,6 +1218,7 @@ "live": "Canlı", "live-indexing": "Canlı Endeksleme", "load-more": "Daha Fazla Yükle", + "loaded-x-of-y-entity": "{{loaded}}/{{total}} {{entity}}", "loading": "Yükleniyor", "loading-article": "Loading article...", "loading-graph": "Loading Graph", @@ -2118,7 +2119,9 @@ "term": "Terim", "term-boost": "Terim Desteği", "term-lowercase": "terim", + "term-not-available": "Terim mevcut değil", "term-plural": "Terimler", + "term-plural-lowercase": "terms", "terms-of-service": "Hizmet Şartları", "test": "Test", "test-applied-on-entity": "{{entity}} üzerinde uygulanan test", diff --git a/openmetadata-ui/src/main/resources/ui/src/locale/languages/zh-cn.json b/openmetadata-ui/src/main/resources/ui/src/locale/languages/zh-cn.json index 84e259c6db87..a1974ce3686a 100644 --- a/openmetadata-ui/src/main/resources/ui/src/locale/languages/zh-cn.json +++ b/openmetadata-ui/src/main/resources/ui/src/locale/languages/zh-cn.json @@ -1218,6 +1218,7 @@ "live": "实时", "live-indexing": "实时索引", "load-more": "加载更多", + "loaded-x-of-y-entity": "{{loaded}}/{{total}} {{entity}}", "loading": "加载中", "loading-article": "正在加载文章...", "loading-graph": "加载图表", @@ -2118,7 +2119,9 @@ "term": "术语", "term-boost": "术语提升", "term-lowercase": "术语", + "term-not-available": "术语不可用", "term-plural": "术语", + "term-plural-lowercase": "terms", "terms-of-service": "服务条款", "test": "测试", "test-applied-on-entity": "测试应用于 {{entity}}", diff --git a/openmetadata-ui/src/main/resources/ui/src/locale/languages/zh-tw.json b/openmetadata-ui/src/main/resources/ui/src/locale/languages/zh-tw.json index fe7332a2758e..8044f5e4c27f 100644 --- a/openmetadata-ui/src/main/resources/ui/src/locale/languages/zh-tw.json +++ b/openmetadata-ui/src/main/resources/ui/src/locale/languages/zh-tw.json @@ -1218,6 +1218,7 @@ "live": "即時", "live-indexing": "即時索引", "load-more": "載入更多", + "loaded-x-of-y-entity": "{{loaded}}/{{total}} {{entity}}", "loading": "載入中", "loading-article": "Loading article...", "loading-graph": "加载图表", @@ -2118,7 +2119,9 @@ "term": "術語", "term-boost": "術語權重", "term-lowercase": "術語", + "term-not-available": "詞彙不可用", "term-plural": "術語", + "term-plural-lowercase": "terms", "terms-of-service": "服務條款", "test": "測試", "test-applied-on-entity": "在 {{entity}} 上套用的測試", From c8baafe1ffb2df04bc4652fdcf4a0e0f73e86c11 Mon Sep 17 00:00:00 2001 From: anuj-kumary Date: Tue, 28 Apr 2026 14:04:15 +0530 Subject: [PATCH 2/8] fix lint issue --- .../OntologyExplorer/FilterToolbar.tsx | 23 +++--- .../OntologyExplorer/OntologyExplorer.tsx | 70 ++++++++++--------- .../hooks/useOntologyGraph.ts | 5 +- 3 files changed, 52 insertions(+), 46 deletions(-) diff --git a/openmetadata-ui/src/main/resources/ui/src/components/OntologyExplorer/FilterToolbar.tsx b/openmetadata-ui/src/main/resources/ui/src/components/OntologyExplorer/FilterToolbar.tsx index 6a706a3d2cae..3a83e7ae4f19 100644 --- a/openmetadata-ui/src/main/resources/ui/src/components/OntologyExplorer/FilterToolbar.tsx +++ b/openmetadata-ui/src/main/resources/ui/src/components/OntologyExplorer/FilterToolbar.tsx @@ -249,19 +249,10 @@ const FilterToolbar: React.FC = ({ as="span" className="tw:whitespace-nowrap tw:text-(--color-text-tertiary)" size="text-sm"> - {loadedTermCount}/{totalTermCount} {t('label.term-plural-lowercase')} + {loadedTermCount}/{totalTermCount}{' '} + {t('label.term-plural-lowercase')} )} - {onClearAll && hasActiveFilters && ( - - )} {onLoadMore !== undefined && ( )} + {onClearAll && hasActiveFilters && ( + + )}
); diff --git a/openmetadata-ui/src/main/resources/ui/src/components/OntologyExplorer/OntologyExplorer.tsx b/openmetadata-ui/src/main/resources/ui/src/components/OntologyExplorer/OntologyExplorer.tsx index 8b73a9e9b962..58e8f72df7fe 100644 --- a/openmetadata-ui/src/main/resources/ui/src/components/OntologyExplorer/OntologyExplorer.tsx +++ b/openmetadata-ui/src/main/resources/ui/src/components/OntologyExplorer/OntologyExplorer.tsx @@ -271,40 +271,42 @@ const OntologyExplorer: React.FC = ({ testId="ontology-graph-render-error" /> }> - ({ - glossaryId: c.glossaryId, - id: c.id, - label: c.label, - })) - : undefined - } - nodePositions={hierarchyBakedPositions} - nodes={graphDataToShow.nodes} - ref={graphRef} - selectedNodeId={ - explorationMode === 'data' && expandedTermIds.size > 1 - ? null - : selectedNode?.id - } - settings={settings} - onNodeClick={handleGraphNodeClick} - onNodeDoubleClick={handleGraphNodeDoubleClick} - onPaneClick={handleGraphPaneClick} - onScrollNearEdge={handleScrollNearEdge} - /> + ({ + glossaryId: c.glossaryId, + id: c.id, + label: c.label, + })) + : undefined + } + nodePositions={hierarchyBakedPositions} + nodes={graphDataToShow.nodes} + ref={graphRef} + selectedNodeId={ + explorationMode === 'data' && expandedTermIds.size > 1 + ? null + : selectedNode?.id + } + settings={settings} + onNodeClick={handleGraphNodeClick} + onNodeDoubleClick={handleGraphNodeDoubleClick} + onPaneClick={handleGraphPaneClick} + onScrollNearEdge={handleScrollNearEdge} + /> {isLoadingMore && ( <> diff --git a/openmetadata-ui/src/main/resources/ui/src/components/OntologyExplorer/hooks/useOntologyGraph.ts b/openmetadata-ui/src/main/resources/ui/src/components/OntologyExplorer/hooks/useOntologyGraph.ts index 65b599638d51..86db02c11e9d 100644 --- a/openmetadata-ui/src/main/resources/ui/src/components/OntologyExplorer/hooks/useOntologyGraph.ts +++ b/openmetadata-ui/src/main/resources/ui/src/components/OntologyExplorer/hooks/useOntologyGraph.ts @@ -1217,7 +1217,10 @@ export function useOntologyGraph({ const W = c.offsetWidth; const H = c.offsetHeight; // Canvas Y that corresponds to the toolbar zone in viewport space. - const canvasAtToolbar = g.getCanvasByViewport([W / 2, H - TOOLBAR_AREA_PX]); + const canvasAtToolbar = g.getCanvasByViewport([ + W / 2, + H - TOOLBAR_AREA_PX, + ]); const cvpAtToolbar = Array.isArray(canvasAtToolbar) ? canvasAtToolbar[1] : (canvasAtToolbar as unknown as ArrayLike)[1]; From 176a1f64813b0102a416684bebbd42214a725f50 Mon Sep 17 00:00:00 2001 From: anuj-kumary Date: Tue, 28 Apr 2026 14:21:13 +0530 Subject: [PATCH 3/8] fix lint issue and spacing --- .../OntologyExplorer/FilterToolbar.tsx | 12 +++++++---- .../OntologyExplorer/OntologyExplorer.tsx | 6 ++++-- .../hooks/useOntologyExplorer.ts | 21 +++++++++++++------ .../ui/src/locale/languages/ar-sa.json | 1 - .../ui/src/locale/languages/de-de.json | 1 - .../ui/src/locale/languages/en-us.json | 1 - .../ui/src/locale/languages/es-es.json | 1 - .../ui/src/locale/languages/fr-fr.json | 1 - .../ui/src/locale/languages/gl-es.json | 1 - .../ui/src/locale/languages/he-he.json | 1 - .../ui/src/locale/languages/ja-jp.json | 1 - .../ui/src/locale/languages/ko-kr.json | 1 - .../ui/src/locale/languages/mr-in.json | 1 - .../ui/src/locale/languages/nl-nl.json | 1 - .../ui/src/locale/languages/pr-pr.json | 1 - .../ui/src/locale/languages/pt-br.json | 1 - .../ui/src/locale/languages/pt-pt.json | 1 - .../ui/src/locale/languages/ru-ru.json | 1 - .../ui/src/locale/languages/th-th.json | 1 - .../ui/src/locale/languages/tr-tr.json | 1 - .../ui/src/locale/languages/zh-cn.json | 1 - .../ui/src/locale/languages/zh-tw.json | 1 - 22 files changed, 27 insertions(+), 31 deletions(-) diff --git a/openmetadata-ui/src/main/resources/ui/src/components/OntologyExplorer/FilterToolbar.tsx b/openmetadata-ui/src/main/resources/ui/src/components/OntologyExplorer/FilterToolbar.tsx index 3a83e7ae4f19..d085de2ac43b 100644 --- a/openmetadata-ui/src/main/resources/ui/src/components/OntologyExplorer/FilterToolbar.tsx +++ b/openmetadata-ui/src/main/resources/ui/src/components/OntologyExplorer/FilterToolbar.tsx @@ -241,20 +241,24 @@ const FilterToolbar: React.FC = ({ } /> -
+
{onLoadMore !== undefined && loadedTermCount !== undefined && totalTermCount !== undefined && ( - {loadedTermCount}/{totalTermCount}{' '} - {t('label.term-plural-lowercase')} + {t('label.loaded-x-of-y-entity', { + loaded: loadedTermCount, + total: totalTermCount, + entity: t('label.term-plural'), + })} )} {onLoadMore !== undefined && (