Skip to content

Commit 74fa194

Browse files
committed
Merge branch 'main' of https://github.com/kyma-project/busola into post-conversations
2 parents d5193c0 + f7a3aa8 commit 74fa194

File tree

12 files changed

+208
-38
lines changed

12 files changed

+208
-38
lines changed

public/i18n/en.yaml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ cluster-overview:
4141
total-persistentvolumes: 'Total Persistent Volumes'
4242
persistent-volumes-total-capacity: 'Total Capacity'
4343
nodes: 'Nodes'
44+
modules-overview: 'Modules Overview'
4445
tooltips:
4546
cpu-used-percentage: 'CPU used: {{percentage}}'
4647
memory-used-percentage: 'Memory used: {{percentage}}'
@@ -369,6 +370,9 @@ common:
369370
statuses:
370371
error: Error
371372
ready: Ready
373+
warning: Warning
374+
processing: Processing
375+
other: Other
372376
unknown: Unknown
373377
tabs:
374378
edit: Edit

src/components/Clusters/views/ClusterOverview/ClusterDetails.js

Lines changed: 3 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -5,11 +5,8 @@ import { useGetVersions } from './useGetVersions';
55
import { useFeature } from 'hooks/useFeature';
66
import { DynamicPageComponent } from 'shared/components/DynamicPageComponent/DynamicPageComponent';
77
import ResourceDetailsCard from 'shared/components/ResourceDetails/ResourceDetailsCard';
8-
import { Button, Text } from '@ui5/webcomponents-react';
9-
import { CountingCard } from 'shared/components/CountingCard/CountingCard';
10-
import { useKymaModulesQuery } from 'components/KymaModules/kymaModulesQueries';
11-
import { useUrl } from 'hooks/useUrl';
12-
import { useNavigate } from 'react-router-dom';
8+
import { Text } from '@ui5/webcomponents-react';
9+
import ClusterModulesCard from './ClusterModulesCard';
1310

1411
const GardenerProvider = () => {
1512
const { t } = useTranslation();
@@ -33,9 +30,6 @@ export default function ClusterDetails({ currentCluster }) {
3330
const { t } = useTranslation();
3431
const { loading, kymaVersion, k8sVersion } = useGetVersions();
3532
const config = currentCluster?.config;
36-
const { modules, error, loading: loadingModules } = useKymaModulesQuery();
37-
const { clusterUrl } = useUrl();
38-
const navigate = useNavigate();
3933

4034
return (
4135
<div className="resource-details-container">
@@ -72,23 +66,7 @@ export default function ClusterDetails({ currentCluster }) {
7266
</>
7367
}
7468
/>
75-
{!error && !loadingModules && modules && (
76-
<div className="item-wrapper sap-margin-x-small">
77-
<CountingCard
78-
className="item"
79-
value={modules?.length}
80-
title={t('kyma-modules.installed-modules')}
81-
additionalContent={
82-
<Button
83-
design="Emphasized"
84-
onClick={() => navigate(clusterUrl('kymamodules'))}
85-
>
86-
{t('kyma-modules.modify-modules')}
87-
</Button>
88-
}
89-
/>
90-
</div>
91-
)}
69+
<ClusterModulesCard />
9270
</div>
9371
);
9472
}
Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
1+
import { useTranslation } from 'react-i18next';
2+
import { Button } from '@ui5/webcomponents-react';
3+
import { CountingCard } from 'shared/components/CountingCard/CountingCard';
4+
import { useKymaModulesQuery } from 'components/KymaModules/kymaModulesQueries';
5+
import { useUrl } from 'hooks/useUrl';
6+
import { useNavigate } from 'react-router-dom';
7+
import { useGetAllModulesStatuses } from 'components/KymaModules/support';
8+
import { useMemo } from 'react';
9+
10+
export default function ClusterModulesCard() {
11+
const { t } = useTranslation();
12+
const { modules, error, loading: loadingModules } = useKymaModulesQuery();
13+
const { clusterUrl } = useUrl();
14+
const navigate = useNavigate();
15+
const {
16+
data: statuses,
17+
loading: loadingStatuses,
18+
error: statusesError,
19+
} = useGetAllModulesStatuses(modules);
20+
21+
const moduleStatusCounts = useMemo(() => {
22+
if (statuses && !loadingStatuses && !statusesError) {
23+
return statuses.reduce(
24+
(
25+
acc: {
26+
ready: number;
27+
error: number;
28+
warning: number;
29+
processing: number;
30+
other: number;
31+
},
32+
m: { status: string },
33+
) => {
34+
if (m?.status === 'Ready') acc.ready++;
35+
else if (m?.status === 'Error') acc.error++;
36+
else if (m?.status === 'Warning') acc.warning++;
37+
else if (m?.status === 'Processing') acc.processing++;
38+
else acc.other++;
39+
return acc;
40+
},
41+
{ ready: 0, error: 0, warning: 0, processing: 0, other: 0 },
42+
);
43+
}
44+
return { ready: 0, error: 0, warning: 0, processing: 0, other: 0 };
45+
46+
// eslint-disable-next-line react-hooks/exhaustive-deps
47+
}, [statuses, statusesError]);
48+
49+
return (
50+
<>
51+
{!error && !loadingModules && modules && (
52+
<CountingCard
53+
className="modules-statuses"
54+
value={modules?.length}
55+
title={t('cluster-overview.statistics.modules-overview')}
56+
subTitle={t('kyma-modules.installed-modules')}
57+
extraInfo={[
58+
{
59+
title: t('common.statuses.ready'),
60+
value: moduleStatusCounts.ready,
61+
},
62+
{
63+
title: t('common.statuses.warning'),
64+
value: moduleStatusCounts.warning,
65+
},
66+
{
67+
title: t('common.statuses.processing'),
68+
value: moduleStatusCounts.processing,
69+
},
70+
{
71+
title: t('common.statuses.error'),
72+
value: moduleStatusCounts.error,
73+
},
74+
moduleStatusCounts.other > 0
75+
? {
76+
title: t('common.statuses.other'),
77+
value: moduleStatusCounts.other,
78+
}
79+
: null,
80+
]}
81+
additionalContent={
82+
<Button
83+
design="Emphasized"
84+
onClick={() => navigate(clusterUrl('kymamodules'))}
85+
>
86+
{t('kyma-modules.modify-modules')}
87+
</Button>
88+
}
89+
/>
90+
)}
91+
</>
92+
);
93+
}
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,12 @@
11
.gardener-provider {
22
text-transform: uppercase;
33
}
4+
5+
.modules-statuses {
6+
max-width: 400px !important;
7+
width: max-content !important;
8+
9+
span {
10+
max-width: unset;
11+
}
12+
}

src/components/KymaModules/KymaModulesAddModule.scss

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@
5050
}
5151

5252
.settings-panel {
53-
width: 350px;
53+
width: var(--card-width);
5454

5555
&::part(header) {
5656
font-family: var(--sapFontFamily);
@@ -108,7 +108,25 @@
108108
}
109109

110110
@container (max-width: 260px) {
111+
.add-modules-form {
112+
padding: 0 0.25rem;
113+
}
114+
111115
.gridbox-addModule {
112116
--card-width: 230px;
113117
}
114118
}
119+
120+
@container (max-width: 250px) {
121+
.gridbox-addModule {
122+
--card-width: 200px;
123+
124+
.gridbox-addModule-column {
125+
.settings-panel {
126+
&::part(content) {
127+
padding: 0 1rem 0 var(--left-spacing);
128+
}
129+
}
130+
}
131+
}
132+
}

src/components/KymaModules/support.ts

Lines changed: 64 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -22,13 +22,9 @@ type KymaResourceType = {
2222
};
2323
};
2424

25-
export function useModuleStatus(resource: KymaResourceType) {
26-
const fetch = useFetch();
27-
const [data, setData] = useState<any>(null);
28-
const [loading, setLoading] = useState(true);
29-
const [error, setError] = useState<Error | null>(null);
30-
31-
const path = resource?.metadata?.namespace
25+
const getResourcePath = (resource: KymaResourceType) => {
26+
if (!resource) return '';
27+
return resource?.metadata?.namespace
3228
? `/apis/${resource?.apiVersion}/namespaces/${
3329
resource?.metadata?.namespace
3430
}/${pluralize(resource?.kind || '').toLowerCase()}/${
@@ -37,6 +33,15 @@ export function useModuleStatus(resource: KymaResourceType) {
3733
: `/apis/${resource?.apiVersion}/${pluralize(
3834
resource?.kind || '',
3935
).toLowerCase()}/${resource?.metadata?.name}`;
36+
};
37+
38+
export function useModuleStatus(resource: KymaResourceType) {
39+
const fetch = useFetch();
40+
const [data, setData] = useState<any>(null);
41+
const [loading, setLoading] = useState(true);
42+
const [error, setError] = useState<Error | null>(null);
43+
44+
const path = getResourcePath(resource);
4045

4146
useEffect(() => {
4247
async function fetchModule() {
@@ -61,6 +66,58 @@ export function useModuleStatus(resource: KymaResourceType) {
6166
return { data, loading, error };
6267
}
6368

69+
export function useGetAllModulesStatuses(modules: any[]) {
70+
const fetch = useFetch();
71+
const [data, setData] = useState<Record<string, any>>({});
72+
const [loading, setLoading] = useState(true);
73+
const [error, setError] = useState<Error | null>(null);
74+
75+
useEffect(() => {
76+
async function fetchModules() {
77+
if (!modules || modules.length === 0) return;
78+
setLoading(true);
79+
try {
80+
const results = await Promise.all(
81+
modules.map(async module => {
82+
const resource = module?.resource ?? module;
83+
84+
if (!resource) return null;
85+
const path = getResourcePath(resource);
86+
87+
try {
88+
const response = await fetch({ relativeUrl: path });
89+
const status = (await response.json())?.status;
90+
return {
91+
key: resource?.metadata?.name ?? resource?.name,
92+
status: status?.state || 'Unknown',
93+
};
94+
} catch (e) {
95+
return {
96+
key: resource?.metadata?.name ?? resource?.name,
97+
status: null,
98+
error: e,
99+
};
100+
}
101+
}),
102+
);
103+
104+
setData(results);
105+
} catch (e) {
106+
if (e instanceof Error) {
107+
setError(e);
108+
}
109+
} finally {
110+
setLoading(false);
111+
}
112+
}
113+
114+
fetchModules();
115+
// eslint-disable-next-line react-hooks/exhaustive-deps
116+
}, [JSON.stringify(modules)]);
117+
118+
return { data, loading, error };
119+
}
120+
64121
export const findModuleStatus = (
65122
kymaResource: KymaResourceType,
66123
moduleName: string,

src/shared/ResourceForm/components/ModeSelector.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ export function ModeSelector({ mode, setMode, isDisabled = false }) {
3939
>
4040
{buttonsToDisplay.map(button => (
4141
<SegmentedButtonItem
42+
className="min-width-button"
4243
key={button.mode}
4344
selected={mode === button.mode}
4445
disabled={isDisabled}

src/shared/ResourceForm/components/ResourceForm.scss

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,7 @@ form .resource-form {
5555

5656
&__content {
5757
width: fit-content;
58+
min-width: 100px;
5859
}
5960
}
6061

src/shared/components/CountingCard/CountingCard.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ import './CountingCard.scss';
1111

1212
type CountingCardProps = {
1313
value: number;
14-
extraInfo: [ExtraInfo];
14+
extraInfo: ExtraInfo[];
1515
title: string;
1616
subTitle: string;
1717
resourceUrl?: string;
@@ -24,7 +24,7 @@ type CountingCardProps = {
2424
type ExtraInfo = {
2525
value: string;
2626
title: string;
27-
};
27+
} | null;
2828

2929
export const CountingCard = ({
3030
value,

src/shared/components/ResourceCreate/ResourceCreate.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -120,6 +120,7 @@ export const ResourceCreate = ({
120120
function renderConfirmButton() {
121121
return (
122122
<Button
123+
className="min-width-button"
123124
disabled={readOnly || disableEdit}
124125
aria-disabled={readOnly || disableEdit}
125126
onClick={handleFormSubmit}

0 commit comments

Comments
 (0)