Skip to content

Commit cb4443b

Browse files
shah-harshitclaude
andauthored
feat(ui): extract remaining pure utils (open-metadata#28791)
* feat(ui): extract remaining pure utils (PR #12) Extract pure functions from 12 utility files into dedicated *PureUtils.ts files. Original files re-export all moved symbols for backward compatibility. New pure util files: - AgentsStatusWidgetPureUtils.ts (getAgentLabelFromType, getAgentStatusLabelFromStatus, getAgentStatusSummary) - Alerts/AlertsUtilPure.ts (20 pure alert helpers) - BlockEditorPureUtils.ts (pure block editor utils) - ContainerDetailPureUtils.ts (pure container detail utils) - ContextCenterPureUtils.ts (pure context center utils) - CuratedAssetsPureUtils.ts (pure curated assets utils) - CustomizableLandingPagePureUtils.ts (pure landing page utils) - CustomizePage/CustomizePagePureUtils.ts (pure customize page utils) - DataAssetSummaryPanelPureUtils.ts (pure data asset summary utils) - CSV/CSVPureUtils.ts (pure CSV processing utils) - Lineage/LineagePureUtils.ts (pure lineage utils) - MetricEntityUtils/MetricPureUtils.ts (pure metric utils) - UsersPureUtils.ts (pure user utils) Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * fix checkstyle * fix: drop dead duplicate code from BlockEditorPureUtils Remove isHTMLString, _convertMarkdownFormatToHtmlString, formatContentForClient from BlockEditorPureUtils.ts — all three are duplicates of code in BlockEditorUtils.ts, none were re-exported or consumed anywhere. Pure file now contains only isDescriptionContentEmpty and getTextFromHtmlString. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * fix(test): update DataAssetSummaryPanelUtils test to mock TablePureUtils getTierTags moved to TablePureUtils.ts; test was mocking TableUtils (old path) causing the mock to be ignored and the assertion to fail. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> --------- Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
1 parent c850111 commit cb4443b

26 files changed

Lines changed: 2653 additions & 2059 deletions
Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,99 @@
1+
/*
2+
* Copyright 2025 Collate.
3+
* Licensed under the Apache License, Version 2.0 (the "License");
4+
* you may not use this file except in compliance with the License.
5+
* You may obtain a copy of the License at
6+
* http://www.apache.org/licenses/LICENSE-2.0
7+
* Unless required by applicable law or agreed to in writing, software
8+
* distributed under the License is distributed on an "AS IS" BASIS,
9+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
10+
* See the License for the specific language governing permissions and
11+
* limitations under the License.
12+
*/
13+
14+
import { groupBy, isEmpty, reduce } from 'lodash';
15+
import type { AgentsInfo } from '../components/ServiceInsights/AgentsStatusWidget/AgentsStatusWidget.interface';
16+
import { AUTOPILOT_AGENTS_STATUS_ORDERED_LIST } from '../constants/AgentsStatusWidget.constant';
17+
import {
18+
COLLATE_AUTO_TIER_APP_NAME,
19+
COLLATE_DATA_QUALITY_APP_NAME,
20+
COLLATE_DOCUMENTATION_APP_NAME,
21+
} from '../constants/Applications.constant';
22+
import { NO_RUNS_STATUS } from '../constants/ServiceInsightsTab.constants';
23+
import { AgentStatus } from '../enums/ServiceInsights.enum';
24+
import { Status } from '../generated/entity/applications/appRunRecord';
25+
import {
26+
PipelineState,
27+
PipelineType,
28+
} from '../generated/entity/services/ingestionPipelines/ingestionPipeline';
29+
import { t } from './i18next/LocalUtil';
30+
31+
export const getAgentLabelFromType = (agentType: string) => {
32+
switch (agentType) {
33+
case PipelineType.Metadata:
34+
return t('label.metadata');
35+
case PipelineType.Lineage:
36+
return t('label.lineage');
37+
case PipelineType.Usage:
38+
return t('label.usage');
39+
case PipelineType.AutoClassification:
40+
return t('label.auto-classification');
41+
case PipelineType.Profiler:
42+
return t('label.profiler');
43+
case COLLATE_DOCUMENTATION_APP_NAME:
44+
return t('label.documentation');
45+
case COLLATE_DATA_QUALITY_APP_NAME:
46+
return t('label.data-quality');
47+
case COLLATE_AUTO_TIER_APP_NAME:
48+
return t('label.auto-tier');
49+
default:
50+
return '';
51+
}
52+
};
53+
54+
export const getAgentStatusLabelFromStatus = (
55+
status?: PipelineState | Status | typeof NO_RUNS_STATUS
56+
) => {
57+
switch (status) {
58+
case PipelineState.Success:
59+
case PipelineState.PartialSuccess:
60+
case Status.Active:
61+
case Status.ActiveError:
62+
case Status.Completed:
63+
return AgentStatus.Successful;
64+
case PipelineState.Failed:
65+
case Status.Failed:
66+
return AgentStatus.Failed;
67+
case PipelineState.Running:
68+
case Status.Running:
69+
case Status.Started:
70+
case Status.StopInProgress:
71+
return AgentStatus.Running;
72+
case PipelineState.Queued:
73+
case Status.Pending:
74+
case NO_RUNS_STATUS:
75+
default:
76+
return AgentStatus.Pending;
77+
}
78+
};
79+
80+
export const getAgentStatusSummary = (agentsList: AgentsInfo[]) => {
81+
const newList = groupBy(agentsList, 'status');
82+
83+
const orderedStatusList = reduce(
84+
AUTOPILOT_AGENTS_STATUS_ORDERED_LIST,
85+
(acc, status) => {
86+
if (isEmpty(newList[status])) {
87+
return acc;
88+
}
89+
90+
return {
91+
...acc,
92+
[status]: newList[status].length,
93+
};
94+
},
95+
{} as Record<string, number>
96+
);
97+
98+
return orderedStatusList;
99+
};

openmetadata-ui/src/main/resources/ui/src/utils/AgentsStatusWidgetUtils.tsx

Lines changed: 19 additions & 86 deletions
Original file line numberDiff line numberDiff line change
@@ -10,12 +10,23 @@
1010
* See the License for the specific language governing permissions and
1111
* limitations under the License.
1212
*/
13+
14+
export {
15+
getAgentLabelFromType,
16+
getAgentStatusLabelFromStatus,
17+
getAgentStatusSummary,
18+
} from './AgentsStatusWidgetPureUtils';
19+
1320
import { ReactComponent as CheckIcon } from '../assets/svg/ic-check-circle-new.svg';
1421
import { ReactComponent as ErrorIcon } from '../assets/svg/ic-close-circle.svg';
1522
import { ReactComponent as UsageIcon } from '../assets/svg/ic-database.svg';
1623
import { ReactComponent as LineageIcon } from '../assets/svg/ic-inherited-roles.svg';
1724
import { ReactComponent as PendingIcon } from '../assets/svg/ic-pending.svg';
1825
import { ReactComponent as RunningIcon } from '../assets/svg/ic-running.svg';
26+
import {
27+
getAgentLabelFromType,
28+
getAgentStatusLabelFromStatus,
29+
} from './AgentsStatusWidgetPureUtils';
1930

2031
import { ReactComponent as AutoClassificationIcon } from '../assets/svg/ic-auto-classification.svg';
2132
import { ReactComponent as AutoTieringIcon } from '../assets/svg/ic-auto-tiering.svg';
@@ -24,63 +35,32 @@ import { ReactComponent as DataQualityIcon } from '../assets/svg/ic-stack-qualit
2435
import { ReactComponent as ProfilerIcon } from '../assets/svg/ic-stack-search.svg';
2536

2637
import { Skeleton, Typography } from 'antd';
27-
import { groupBy, isEmpty, isUndefined, reduce } from 'lodash';
28-
import { AgentsInfo } from '../components/ServiceInsights/AgentsStatusWidget/AgentsStatusWidget.interface';
29-
import {
38+
import { isEmpty, isUndefined, reduce } from 'lodash';
39+
import type { AgentsInfo } from '../components/ServiceInsights/AgentsStatusWidget/AgentsStatusWidget.interface';
40+
import type {
3041
AgentsLiveInfo,
3142
CollateAgentLiveInfo,
3243
} from '../components/ServiceInsights/ServiceInsightsTab.interface';
33-
import {
34-
AUTOPILOT_AGENTS_ORDERED_LIST,
35-
AUTOPILOT_AGENTS_STATUS_ORDERED_LIST,
36-
} from '../constants/AgentsStatusWidget.constant';
44+
import { AUTOPILOT_AGENTS_ORDERED_LIST } from '../constants/AgentsStatusWidget.constant';
3745
import {
3846
COLLATE_AUTO_TIER_APP_NAME,
3947
COLLATE_DATA_QUALITY_APP_NAME,
4048
COLLATE_DOCUMENTATION_APP_NAME,
4149
} from '../constants/Applications.constant';
42-
import { NO_RUNS_STATUS } from '../constants/ServiceInsightsTab.constants';
4350
import { AgentStatus } from '../enums/ServiceInsights.enum';
44-
import { App } from '../generated/entity/applications/app';
45-
import {
46-
AppRunRecord,
47-
Status,
48-
} from '../generated/entity/applications/appRunRecord';
51+
import type { App } from '../generated/entity/applications/app';
52+
import type { AppRunRecord } from '../generated/entity/applications/appRunRecord';
4953
import {
50-
IngestionPipeline,
51-
PipelineState,
5254
PipelineType,
5355
ProviderType,
56+
type IngestionPipeline,
5457
} from '../generated/entity/services/ingestionPipelines/ingestionPipeline';
5558
import {
56-
WorkflowInstance,
5759
WorkflowStatus,
60+
type WorkflowInstance,
5861
} from '../generated/governance/workflows/workflowInstance';
5962
import { t } from './i18next/LocalUtil';
6063

61-
export const getAgentLabelFromType = (agentType: string) => {
62-
switch (agentType) {
63-
case PipelineType.Metadata:
64-
return t('label.metadata');
65-
case PipelineType.Lineage:
66-
return t('label.lineage');
67-
case PipelineType.Usage:
68-
return t('label.usage');
69-
case PipelineType.AutoClassification:
70-
return t('label.auto-classification');
71-
case PipelineType.Profiler:
72-
return t('label.profiler');
73-
case COLLATE_DOCUMENTATION_APP_NAME:
74-
return t('label.documentation');
75-
case COLLATE_DATA_QUALITY_APP_NAME:
76-
return t('label.data-quality');
77-
case COLLATE_AUTO_TIER_APP_NAME:
78-
return t('label.auto-tier');
79-
default:
80-
return '';
81-
}
82-
};
83-
8464
export const getAgentIconFromType = (agentType: string) => {
8565
let Icon: SvgComponent = () => null;
8666
let className = '';
@@ -130,32 +110,6 @@ export const getAgentIconFromType = (agentType: string) => {
130110
);
131111
};
132112

133-
export const getAgentStatusLabelFromStatus = (
134-
status?: PipelineState | Status | typeof NO_RUNS_STATUS
135-
) => {
136-
switch (status) {
137-
case PipelineState.Success:
138-
case PipelineState.PartialSuccess:
139-
case Status.Active:
140-
case Status.ActiveError:
141-
case Status.Completed:
142-
return AgentStatus.Successful;
143-
case PipelineState.Failed:
144-
case Status.Failed:
145-
return AgentStatus.Failed;
146-
case PipelineState.Running:
147-
case Status.Running:
148-
case Status.Started:
149-
case Status.StopInProgress:
150-
return AgentStatus.Running;
151-
case PipelineState.Queued:
152-
case Status.Pending:
153-
case NO_RUNS_STATUS:
154-
default:
155-
return AgentStatus.Pending;
156-
}
157-
};
158-
159113
export const getFormattedAgentsList = (
160114
recentRunStatuses: Record<string, AppRunRecord[]>,
161115
agentsList: IngestionPipeline[] = [],
@@ -249,27 +203,6 @@ export const getFormattedAgentsListFromAgentsLiveInfo = (
249203
return orderedAgentsList;
250204
};
251205

252-
export const getAgentStatusSummary = (agentsList: AgentsInfo[]) => {
253-
const newList = groupBy(agentsList, 'status');
254-
255-
const orderedStatusList = reduce(
256-
AUTOPILOT_AGENTS_STATUS_ORDERED_LIST,
257-
(acc, status) => {
258-
if (isEmpty(newList[status])) {
259-
return acc;
260-
}
261-
262-
return {
263-
...acc,
264-
[status]: newList[status].length,
265-
};
266-
},
267-
{} as Record<string, number>
268-
);
269-
270-
return orderedStatusList;
271-
};
272-
273206
export const getIconFromStatus = (status?: string) => {
274207
let Icon: SvgComponent = () => null;
275208

0 commit comments

Comments
 (0)