Skip to content

Commit 2fc0cfb

Browse files
committed
Refactor withDashboardResources in with-dashboard-resources.tsx into a hook
1 parent 4fb4f4f commit 2fc0cfb

14 files changed

Lines changed: 1132 additions & 1398 deletions

File tree

frontend/packages/console-shared/src/components/dashboard/utilization-card/TopConsumerPopover.tsx

Lines changed: 127 additions & 141 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,19 @@
11
/* eslint-disable @typescript-eslint/no-use-before-define */
22
import type { FC, ReactNode, ReactText } from 'react';
3-
import { memo, useState, useCallback, useMemo, useEffect } from 'react';
3+
import { memo, useState, useCallback, useMemo } from 'react';
44
import { Button, Popover, PopoverPosition } from '@patternfly/react-core';
55
import { useTranslation } from 'react-i18next';
66
import { Link } from 'react-router-dom-v5-compat';
77
import { LIMIT_STATE, Humanize } from '@console/dynamic-plugin-sdk';
88
import { getPrometheusQueryResponse } from '@console/internal/actions/dashboards';
9-
import {
10-
withDashboardResources,
11-
DashboardItemProps,
12-
} from '@console/internal/components/dashboard/with-dashboard-resources';
139
import { DataPoint } from '@console/internal/components/graphs';
1410
import { getInstantVectorStats } from '@console/internal/components/graphs/utils';
1511
import { ConsoleSelect } from '@console/internal/components/utils/console-select';
1612
import { useK8sWatchResource } from '@console/internal/components/utils/k8s-watch-hook';
1713
import { resourcePathFromModel } from '@console/internal/components/utils/resource-link';
1814
import { K8sKind, referenceForModel, K8sResourceCommon } from '@console/internal/module/k8s';
1915
import { getName, getNamespace } from '../../..';
16+
import { useDashboardResources } from '../../../hooks/useDashboardResources';
2017
import { RedExclamationCircleIcon, YellowExclamationTriangleIcon } from '../../status';
2118
import Status from '../status-card/StatusPopup';
2219

@@ -116,157 +113,146 @@ export const LimitsBody: FC<LimitsBodyProps> = ({
116113
);
117114
};
118115

119-
export const PopoverBody = withDashboardResources<DashboardItemProps & PopoverBodyProps>(
120-
memo(
121-
({
122-
humanize,
123-
consumers,
116+
export const PopoverBody: FC<PopoverBodyProps> = memo(
117+
({ humanize, consumers, namespace, isOpen, description, children }) => {
118+
const { t } = useTranslation();
119+
const [currentConsumer, setCurrentConsumer] = useState(consumers[0]);
120+
const { query, model, metric, fieldSelector } = currentConsumer;
121+
const k8sResource = useMemo(
122+
() => (isOpen ? getResourceToWatch(model, namespace, fieldSelector) : null),
123+
[fieldSelector, isOpen, model, namespace],
124+
);
125+
const [consumerData, consumerLoaded, consumersLoadError] = useK8sWatchResource<
126+
K8sResourceCommon[]
127+
>(k8sResource);
128+
129+
const prometheusQueries = useMemo(() => (isOpen ? [{ query, namespace }] : []), [
130+
query,
124131
namespace,
125-
watchPrometheus,
126-
stopWatchPrometheusQuery,
127-
prometheusResults,
128132
isOpen,
129-
description,
130-
children,
131-
}) => {
132-
const { t } = useTranslation();
133-
const [currentConsumer, setCurrentConsumer] = useState(consumers[0]);
134-
const { query, model, metric, fieldSelector } = currentConsumer;
135-
const k8sResource = useMemo(
136-
() => (isOpen ? getResourceToWatch(model, namespace, fieldSelector) : null),
137-
[fieldSelector, isOpen, model, namespace],
138-
);
139-
const [consumerData, consumerLoaded, consumersLoadError] = useK8sWatchResource<
140-
K8sResourceCommon[]
141-
>(k8sResource);
142-
useEffect(() => {
143-
if (!isOpen) {
144-
return () => {};
145-
}
146-
watchPrometheus(query, namespace);
147-
return () => {
148-
stopWatchPrometheusQuery(query);
149-
};
150-
}, [query, stopWatchPrometheusQuery, watchPrometheus, namespace, isOpen]);
133+
]);
134+
135+
const { prometheusResults } = useDashboardResources({
136+
prometheusQueries,
137+
});
151138

152-
const top5Data = [];
139+
const top5Data = [];
153140

154-
const [data, error] = getPrometheusQueryResponse(prometheusResults, query);
155-
const bodyData = getInstantVectorStats(data, metric);
141+
const [data, error] = getPrometheusQueryResponse(prometheusResults, query);
142+
const bodyData = getInstantVectorStats(data, metric);
156143

157-
if (k8sResource && consumerLoaded && !consumersLoadError) {
158-
for (const d of bodyData) {
159-
const consumerExists = consumerData.some(
160-
(consumer) =>
161-
getName(consumer) === d.metric[metric] &&
162-
(model.namespaced ? getNamespace(consumer) === d.metric.namespace : true),
163-
);
164-
if (consumerExists) {
165-
top5Data.push({ ...d, y: humanize(d.y).string });
166-
}
167-
if (top5Data.length === 5) {
168-
break;
169-
}
144+
if (k8sResource && consumerLoaded && !consumersLoadError) {
145+
for (const d of bodyData) {
146+
const consumerExists = consumerData.some(
147+
(consumer) =>
148+
getName(consumer) === d.metric[metric] &&
149+
(model.namespaced ? getNamespace(consumer) === d.metric.namespace : true),
150+
);
151+
if (consumerExists) {
152+
top5Data.push({ ...d, y: humanize(d.y).string });
153+
}
154+
if (top5Data.length === 5) {
155+
break;
170156
}
171157
}
158+
}
172159

173-
const monitoringParams = useMemo(() => {
174-
const params = new URLSearchParams();
175-
params.set('query0', currentConsumer.query);
176-
if (namespace) {
177-
params.set('namespace', namespace);
178-
}
179-
return params;
180-
}, [currentConsumer.query, namespace]);
160+
const monitoringParams = useMemo(() => {
161+
const params = new URLSearchParams();
162+
params.set('query0', currentConsumer.query);
163+
if (namespace) {
164+
params.set('namespace', namespace);
165+
}
166+
return params;
167+
}, [currentConsumer.query, namespace]);
181168

182-
const dropdownItems = useMemo(
183-
() =>
184-
consumers.reduce((items, curr) => {
185-
items[referenceForModel(curr.model)] = t('console-shared~By {{label}}', {
186-
label: curr.model.labelKey ? t(curr.model.labelKey) : curr.model.label,
187-
});
188-
return items;
189-
}, {}),
190-
[consumers, t],
191-
);
169+
const dropdownItems = useMemo(
170+
() =>
171+
consumers.reduce((items, curr) => {
172+
items[referenceForModel(curr.model)] = t('console-shared~By {{label}}', {
173+
label: curr.model.labelKey ? t(curr.model.labelKey) : curr.model.label,
174+
});
175+
return items;
176+
}, {}),
177+
[consumers, t],
178+
);
192179

193-
const onDropdownChange = useCallback(
194-
(key) => setCurrentConsumer(consumers.find((c) => referenceForModel(c.model) === key)),
195-
[consumers],
196-
);
180+
const onDropdownChange = useCallback(
181+
(key) => setCurrentConsumer(consumers.find((c) => referenceForModel(c.model) === key)),
182+
[consumers],
183+
);
197184

198-
const monitoringURL = `/monitoring/query-browser?${monitoringParams.toString()}`;
185+
const monitoringURL = `/monitoring/query-browser?${monitoringParams.toString()}`;
199186

200-
let body: ReactNode;
201-
if (error || consumersLoadError) {
202-
body = <div className="pf-v6-u-text-color-subtle">{t('console-shared~Not available')}</div>;
203-
} else if (!consumerLoaded || !data) {
204-
body = (
205-
<ul className="co-utilization-card-popover__consumer-list">
206-
<li className="skeleton-consumer" />
207-
<li className="skeleton-consumer" />
208-
<li className="skeleton-consumer" />
209-
<li className="skeleton-consumer" />
210-
<li className="skeleton-consumer" />
187+
let body: ReactNode;
188+
if (error || consumersLoadError) {
189+
body = <div className="pf-v6-u-text-color-subtle">{t('console-shared~Not available')}</div>;
190+
} else if (!consumerLoaded || !data) {
191+
body = (
192+
<ul className="co-utilization-card-popover__consumer-list">
193+
<li className="skeleton-consumer" />
194+
<li className="skeleton-consumer" />
195+
<li className="skeleton-consumer" />
196+
<li className="skeleton-consumer" />
197+
<li className="skeleton-consumer" />
198+
</ul>
199+
);
200+
} else {
201+
body = (
202+
<>
203+
<ul
204+
className="co-utilization-card-popover__consumer-list"
205+
aria-label={t('console-shared~Top consumer by {{label}}', { label: model.label })}
206+
>
207+
{top5Data &&
208+
top5Data.map((item) => {
209+
const title = String(item.x);
210+
return (
211+
<ListItem key={title} value={item.y}>
212+
<Link
213+
className="co-utilization-card-popover__consumer-name"
214+
to={resourcePathFromModel(model, title, item.metric.namespace)}
215+
>
216+
{title}
217+
</Link>
218+
</ListItem>
219+
);
220+
})}
211221
</ul>
212-
);
213-
} else {
214-
body = (
215-
<>
216-
<ul
217-
className="co-utilization-card-popover__consumer-list"
218-
aria-label={t('console-shared~Top consumer by {{label}}', { label: model.label })}
219-
>
220-
{top5Data &&
221-
top5Data.map((item) => {
222-
const title = String(item.x);
223-
return (
224-
<ListItem key={title} value={item.y}>
225-
<Link
226-
className="co-utilization-card-popover__consumer-name"
227-
to={resourcePathFromModel(model, title, item.metric.namespace)}
228-
>
229-
{title}
230-
</Link>
231-
</ListItem>
232-
);
233-
})}
234-
</ul>
235-
<Link to={monitoringURL}>{t('console-shared~View more')}</Link>
236-
</>
237-
);
238-
}
222+
<Link to={monitoringURL}>{t('console-shared~View more')}</Link>
223+
</>
224+
);
225+
}
239226

240-
return (
241-
<div className="co-utilization-card-popover__body">
242-
{description && (
243-
<div className="co-utilization-card-popover__description">{description}</div>
244-
)}
245-
{children}
246-
<div className="co-utilization-card-popover__title">
247-
{consumers.length === 1
248-
? t('console-shared~Top {{label}} consumers', {
249-
label: currentConsumer.model.label.toLowerCase(),
250-
})
251-
: t('console-shared~Top consumers')}
252-
</div>
253-
{consumers.length > 1 && (
254-
<ConsoleSelect
255-
id="consumer-select"
256-
renderInline // needed for popover to not close on selection
257-
isFullWidth
258-
buttonClassName="pf-v6-u-my-sm"
259-
aria-label={t('console-shared~Select consumer type')}
260-
items={dropdownItems}
261-
onChange={onDropdownChange}
262-
selectedKey={referenceForModel(model)}
263-
/>
264-
)}
265-
{body}
227+
return (
228+
<div className="co-utilization-card-popover__body">
229+
{description && (
230+
<div className="co-utilization-card-popover__description">{description}</div>
231+
)}
232+
{children}
233+
<div className="co-utilization-card-popover__title">
234+
{consumers.length === 1
235+
? t('console-shared~Top {{label}} consumers', {
236+
label: currentConsumer.model.label.toLowerCase(),
237+
})
238+
: t('console-shared~Top consumers')}
266239
</div>
267-
);
268-
},
269-
),
240+
{consumers.length > 1 && (
241+
<ConsoleSelect
242+
id="consumer-select"
243+
renderInline // needed for popover to not close on selection
244+
isFullWidth
245+
buttonClassName="pf-v6-u-my-sm"
246+
aria-label={t('console-shared~Select consumer type')}
247+
items={dropdownItems}
248+
onChange={onDropdownChange}
249+
selectedKey={referenceForModel(model)}
250+
/>
251+
)}
252+
{body}
253+
</div>
254+
);
255+
},
270256
);
271257

272258
const ListItem: React.FCC<ListItemProps> = ({ children, value }) => (

frontend/packages/console-shared/src/hooks/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,3 +36,4 @@ export * from './useCopyCodeModal';
3636
export * from './useCopyLoginCommands';
3737
export * from './useQuickStartContext';
3838
export * from './useUser';
39+
export * from './useDynamicK8sWatchResources';

frontend/packages/console-shared/src/hooks/useDashboardResources.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ export const useDashboardResources: UseDashboardResources = ({
2525
prometheusQueries?.forEach((query) =>
2626
dispatch(watchPrometheusQuery(query.query, null, query.timespan)),
2727
);
28-
urls?.forEach((url) => dispatch(watchURL(url?.url)));
28+
urls?.forEach((url) => dispatch(watchURL(url?.url, url?.fetch)));
2929

3030
return () => {
3131
prometheusQueries?.forEach((query) => {

0 commit comments

Comments
 (0)