@openshift-assisted/ui-lib 2.16.3-cim → 2.16.5-cim
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/build/@types/cim/components/Agent/tableUtils.d.ts +4 -1
- package/build/@types/cim/components/Agent/tableUtils.d.ts.map +1 -1
- package/build/@types/cim/components/ClusterDeployment/hostDiscovery/ClusterDeploymentHostDiscoveryTable.d.ts.map +1 -1
- package/build/@types/cim/components/ClusterDeployment/hostSelection/ClusterDeploymentHostSelectionStep.d.ts.map +1 -1
- package/build/@types/cim/components/ClusterDeployment/hostSelection/ClusterDeploymentHostsSelection.d.ts.map +1 -1
- package/build/@types/cim/components/ClusterDeployment/types.d.ts +1 -0
- package/build/@types/cim/components/ClusterDeployment/types.d.ts.map +1 -1
- package/build/@types/cim/components/InfraEnv/InfraEnvAgentTable.d.ts.map +1 -1
- package/build/@types/cim/components/InfraEnv/InfraEnvOpenShiftVersionDropdown.d.ts.map +1 -1
- package/build/@types/cim/components/InfraEnv/InfraTableToolbar.d.ts +5 -0
- package/build/@types/cim/components/InfraEnv/InfraTableToolbar.d.ts.map +1 -1
- package/build/@types/cim/components/helpers/agents.d.ts +1 -1
- package/build/@types/cim/components/helpers/agents.d.ts.map +1 -1
- package/build/@types/cim/components/helpers/toAssisted.d.ts.map +1 -1
- package/build/@types/common/components/hosts/tableUtils.d.ts +2 -0
- package/build/@types/common/components/hosts/tableUtils.d.ts.map +1 -1
- package/build/@types/common/components/hosts/utils.d.ts +3 -0
- package/build/@types/common/components/hosts/utils.d.ts.map +1 -1
- package/build/cjs/cim/components/Agent/tableUtils.js +31 -3
- package/build/cjs/cim/components/Agent/tableUtils.js.map +1 -1
- package/build/cjs/cim/components/ClusterDeployment/hostDiscovery/ClusterDeploymentHostDiscoveryTable.js +8 -1
- package/build/cjs/cim/components/ClusterDeployment/hostDiscovery/ClusterDeploymentHostDiscoveryTable.js.map +1 -1
- package/build/cjs/cim/components/ClusterDeployment/hostSelection/ClusterDeploymentHostSelectionStep.js +1 -1
- package/build/cjs/cim/components/ClusterDeployment/hostSelection/ClusterDeploymentHostSelectionStep.js.map +1 -1
- package/build/cjs/cim/components/ClusterDeployment/hostSelection/ClusterDeploymentHostsSelection.js +3 -3
- package/build/cjs/cim/components/ClusterDeployment/hostSelection/ClusterDeploymentHostsSelection.js.map +1 -1
- package/build/cjs/cim/components/InfraEnv/InfraEnvAgentTable.js +5 -2
- package/build/cjs/cim/components/InfraEnv/InfraEnvAgentTable.js.map +1 -1
- package/build/cjs/cim/components/InfraEnv/InfraEnvOpenShiftVersionDropdown.js +3 -1
- package/build/cjs/cim/components/InfraEnv/InfraEnvOpenShiftVersionDropdown.js.map +1 -1
- package/build/cjs/cim/components/InfraEnv/InfraTableToolbar.js +25 -3
- package/build/cjs/cim/components/InfraEnv/InfraTableToolbar.js.map +1 -1
- package/build/cjs/cim/components/helpers/agents.js +4 -1
- package/build/cjs/cim/components/helpers/agents.js.map +1 -1
- package/build/cjs/cim/components/helpers/toAssisted.js +2 -1
- package/build/cjs/cim/components/helpers/toAssisted.js.map +1 -1
- package/build/cjs/cim/components/modals/MassApproveAgentModal.js +2 -2
- package/build/cjs/cim/components/modals/MassApproveAgentModal.js.map +1 -1
- package/build/cjs/common/components/clusterWizard/clusterDetailsValidation.js +7 -7
- package/build/cjs/common/components/clusterWizard/clusterDetailsValidation.js.map +1 -1
- package/build/cjs/common/components/hosts/tableUtils.js +41 -1
- package/build/cjs/common/components/hosts/tableUtils.js.map +1 -1
- package/build/cjs/common/components/hosts/utils.js +5 -1
- package/build/cjs/common/components/hosts/utils.js.map +1 -1
- package/build/cjs/common/components/ui/formik/validationSchemas.js +1 -1
- package/build/cjs/common/components/ui/formik/validationSchemas.js.map +1 -1
- package/lib/cim/components/Agent/tableUtils.tsx +43 -2
- package/lib/cim/components/ClusterDeployment/hostDiscovery/ClusterDeploymentHostDiscoveryTable.tsx +10 -1
- package/lib/cim/components/ClusterDeployment/hostSelection/ClusterDeploymentHostSelectionStep.tsx +1 -0
- package/lib/cim/components/ClusterDeployment/hostSelection/ClusterDeploymentHostsSelection.tsx +3 -2
- package/lib/cim/components/ClusterDeployment/types.ts +1 -0
- package/lib/cim/components/InfraEnv/InfraEnvAgentTable.tsx +11 -0
- package/lib/cim/components/InfraEnv/InfraEnvOpenShiftVersionDropdown.tsx +11 -9
- package/lib/cim/components/InfraEnv/InfraTableToolbar.tsx +71 -1
- package/lib/cim/components/helpers/agents.ts +5 -1
- package/lib/cim/components/helpers/toAssisted.ts +1 -0
- package/lib/cim/components/modals/MassApproveAgentModal.tsx +1 -1
- package/lib/common/components/clusterWizard/clusterDetailsValidation.ts +7 -7
- package/lib/common/components/hosts/tableUtils.tsx +45 -0
- package/lib/common/components/hosts/utils.ts +4 -0
- package/lib/common/components/ui/formik/validationSchemas.ts +1 -1
- package/package.json +3 -3
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import * as React from 'react';
|
|
2
2
|
import { Link } from 'react-router-dom-v5-compat';
|
|
3
|
+
import countBy from 'lodash-es/countBy';
|
|
3
4
|
|
|
4
5
|
import {
|
|
5
6
|
HostsTableActions,
|
|
@@ -25,7 +26,7 @@ import {
|
|
|
25
26
|
getBMHStatusKey,
|
|
26
27
|
getWizardStepAgentStatus,
|
|
27
28
|
} from '../helpers/status';
|
|
28
|
-
import { filterByHostname } from '../../../common/components/hosts/utils';
|
|
29
|
+
import { filterByHostname, getHostLabels } from '../../../common/components/hosts/utils';
|
|
29
30
|
import { agentStatus } from '../helpers/agentStatus';
|
|
30
31
|
import noop from 'lodash-es/noop.js';
|
|
31
32
|
import { useTranslation } from '../../../common/hooks/use-translation-wrapper';
|
|
@@ -401,6 +402,7 @@ export const useAgentsTable = (
|
|
|
401
402
|
} = tableActions || {};
|
|
402
403
|
const { t } = useTranslation();
|
|
403
404
|
const agentStatuses = agentStatus(t);
|
|
405
|
+
|
|
404
406
|
const [hosts, actions] = React.useMemo(
|
|
405
407
|
(): [Host[], HostsTableActions] => [
|
|
406
408
|
getAIHosts(agents, bmhs, infraEnv),
|
|
@@ -548,6 +550,22 @@ const filterByStatus = (
|
|
|
548
550
|
});
|
|
549
551
|
};
|
|
550
552
|
|
|
553
|
+
const filterByLabels = (hosts: Host[], labelFilter: string[]) => {
|
|
554
|
+
if (!labelFilter.length) {
|
|
555
|
+
return hosts;
|
|
556
|
+
}
|
|
557
|
+
|
|
558
|
+
return hosts.filter((h) => {
|
|
559
|
+
const labels = getHostLabels(h);
|
|
560
|
+
|
|
561
|
+
return labelFilter.some((l) =>
|
|
562
|
+
Object.entries(labels)
|
|
563
|
+
.map(([key, value]) => `${key} = ${value}`)
|
|
564
|
+
.includes(l),
|
|
565
|
+
);
|
|
566
|
+
});
|
|
567
|
+
};
|
|
568
|
+
|
|
551
569
|
export const filterHosts = (
|
|
552
570
|
hosts: Host[],
|
|
553
571
|
agents: AgentK8sResource[],
|
|
@@ -555,11 +573,26 @@ export const filterHosts = (
|
|
|
555
573
|
bareMetalHosts: BareMetalHostK8sResource[],
|
|
556
574
|
hostnameFilter: string | undefined,
|
|
557
575
|
statusFilter: string[],
|
|
576
|
+
labelFilter: string[],
|
|
558
577
|
) => {
|
|
559
578
|
const { hosts: byHostname, sorted } = filterByHostname(hosts, hostnameFilter);
|
|
560
579
|
const byStatus = filterByStatus(byHostname, agents, agentStatuses, bareMetalHosts, statusFilter);
|
|
580
|
+
const byLabels = filterByLabels(byStatus, labelFilter);
|
|
561
581
|
|
|
562
|
-
return { hosts:
|
|
582
|
+
return { hosts: byLabels, sorted };
|
|
583
|
+
};
|
|
584
|
+
|
|
585
|
+
const getAllLabels = (hosts: Host[]) => {
|
|
586
|
+
const labelArray = hosts
|
|
587
|
+
.map((host) => {
|
|
588
|
+
const labels = getHostLabels(host);
|
|
589
|
+
|
|
590
|
+
return Object.entries(labels).map(([key, val]) => `${key} = ${val}`);
|
|
591
|
+
})
|
|
592
|
+
.flat()
|
|
593
|
+
.sort();
|
|
594
|
+
|
|
595
|
+
return countBy(labelArray);
|
|
563
596
|
};
|
|
564
597
|
|
|
565
598
|
type UseAgentsFilterArgs = {
|
|
@@ -581,10 +614,12 @@ export const useAgentsFilter = ({
|
|
|
581
614
|
}: UseAgentsFilterArgs) => {
|
|
582
615
|
const [hostnameFilter, setHostnameFilter] = React.useState<string>();
|
|
583
616
|
const [statusFilter, setStatusFilter] = React.useState<string[]>([]);
|
|
617
|
+
const [labelFilter, setLabelFilter] = React.useState<string[]>([]);
|
|
584
618
|
const statusCount = Object.keys(agentStatuses).reduce((acc, curr) => {
|
|
585
619
|
acc[agentStatuses[curr].title] = 0;
|
|
586
620
|
return acc;
|
|
587
621
|
}, {} as StatusCount);
|
|
622
|
+
|
|
588
623
|
hosts.forEach((host) => {
|
|
589
624
|
const agent = agents.find((a) => a.metadata?.uid === host.id);
|
|
590
625
|
const bmh = bmhs.find((bmh) => bmh.metadata?.uid === host.id);
|
|
@@ -597,6 +632,8 @@ export const useAgentsFilter = ({
|
|
|
597
632
|
}
|
|
598
633
|
});
|
|
599
634
|
|
|
635
|
+
const hostLabels = getAllLabels(hosts);
|
|
636
|
+
|
|
600
637
|
const { hosts: filteredHosts, sorted } = filterHosts(
|
|
601
638
|
hosts,
|
|
602
639
|
agents,
|
|
@@ -604,6 +641,7 @@ export const useAgentsFilter = ({
|
|
|
604
641
|
bmhs,
|
|
605
642
|
hostnameFilter,
|
|
606
643
|
statusFilter,
|
|
644
|
+
labelFilter,
|
|
607
645
|
);
|
|
608
646
|
|
|
609
647
|
return {
|
|
@@ -612,6 +650,9 @@ export const useAgentsFilter = ({
|
|
|
612
650
|
setHostnameFilter,
|
|
613
651
|
statusFilter,
|
|
614
652
|
setStatusFilter,
|
|
653
|
+
hostLabels,
|
|
654
|
+
labelFilter,
|
|
655
|
+
setLabelFilter,
|
|
615
656
|
filteredHosts,
|
|
616
657
|
sorted,
|
|
617
658
|
};
|
package/lib/cim/components/ClusterDeployment/hostDiscovery/ClusterDeploymentHostDiscoveryTable.tsx
CHANGED
|
@@ -15,7 +15,9 @@ import {
|
|
|
15
15
|
cpuCoresColumn,
|
|
16
16
|
discoveredAtColumn,
|
|
17
17
|
disksColumn,
|
|
18
|
+
gpusColumn,
|
|
18
19
|
hostnameColumn,
|
|
20
|
+
labelsColumn,
|
|
19
21
|
memoryColumn,
|
|
20
22
|
roleColumn,
|
|
21
23
|
} from '../../../../common/components/hosts/tableUtils';
|
|
@@ -93,7 +95,14 @@ const ClusterDeploymentHostDiscoveryTable: React.FC<ClusterDeploymentHostDiscove
|
|
|
93
95
|
}),
|
|
94
96
|
roleColumn(t, hostActions.canEditRole, hostActions.onEditRole),
|
|
95
97
|
...(addAll
|
|
96
|
-
? [
|
|
98
|
+
? [
|
|
99
|
+
discoveredAtColumn(t),
|
|
100
|
+
cpuCoresColumn(t),
|
|
101
|
+
gpusColumn(t),
|
|
102
|
+
memoryColumn(t),
|
|
103
|
+
disksColumn(t),
|
|
104
|
+
labelsColumn(t),
|
|
105
|
+
]
|
|
97
106
|
: []),
|
|
98
107
|
],
|
|
99
108
|
[
|
package/lib/cim/components/ClusterDeployment/hostSelection/ClusterDeploymentHostSelectionStep.tsx
CHANGED
|
@@ -313,6 +313,7 @@ const HostSelectionForm: React.FC<HostSelectionFormProps> = ({
|
|
|
313
313
|
onAutoSelectChange={onAutoSelectChange}
|
|
314
314
|
onHostSelect={onHostSelect}
|
|
315
315
|
isNutanix={isNutanix}
|
|
316
|
+
hostsBinding={nextRequested && !showClusterErrors}
|
|
316
317
|
/>
|
|
317
318
|
</GridItem>
|
|
318
319
|
{(showClusterErrors || showFormErrors) && !!alerts.length && (
|
package/lib/cim/components/ClusterDeployment/hostSelection/ClusterDeploymentHostsSelection.tsx
CHANGED
|
@@ -42,6 +42,7 @@ const ClusterDeploymentHostsSelection: React.FC<ClusterDeploymentHostsSelectionP
|
|
|
42
42
|
onHostSelect,
|
|
43
43
|
onSetInstallationDiskId,
|
|
44
44
|
isNutanix,
|
|
45
|
+
hostsBinding,
|
|
45
46
|
}) => {
|
|
46
47
|
const { t } = useTranslation();
|
|
47
48
|
const { values } = useFormikContext<ClusterDeploymentHostsSelectionValues>();
|
|
@@ -54,7 +55,7 @@ const ClusterDeploymentHostsSelection: React.FC<ClusterDeploymentHostsSelectionP
|
|
|
54
55
|
const cpuArchitecture = getClusterDeploymentCpuArchitecture(clusterDeployment);
|
|
55
56
|
|
|
56
57
|
const availableAgents = React.useMemo(() => {
|
|
57
|
-
const filtered = getAgentsForSelection(agents).filter(
|
|
58
|
+
const filtered = getAgentsForSelection(agents, hostsBinding).filter(
|
|
58
59
|
(agent) =>
|
|
59
60
|
(agent.spec.clusterDeploymentName?.name === cdName &&
|
|
60
61
|
agent.spec.clusterDeploymentName?.namespace === cdNamespace) ||
|
|
@@ -66,7 +67,7 @@ const ClusterDeploymentHostsSelection: React.FC<ClusterDeploymentHostsSelectionP
|
|
|
66
67
|
return isNutanix
|
|
67
68
|
? filtered.filter((a) => a.status?.inventory?.systemVendor?.manufacturer === 'Nutanix')
|
|
68
69
|
: filtered;
|
|
69
|
-
}, [agents,
|
|
70
|
+
}, [agents, hostsBinding, isNutanix, cdName, cdNamespace, cpuArchitecture]);
|
|
70
71
|
|
|
71
72
|
const hostRequirementText = getHostRequirementText(isSNOCluster, isTNA, t);
|
|
72
73
|
|
|
@@ -22,7 +22,9 @@ import {
|
|
|
22
22
|
cpuCoresColumn,
|
|
23
23
|
discoveredAtColumn,
|
|
24
24
|
disksColumn,
|
|
25
|
+
gpusColumn,
|
|
25
26
|
memoryColumn,
|
|
27
|
+
labelsColumn,
|
|
26
28
|
} from '../../../common/components/hosts/tableUtils';
|
|
27
29
|
import {
|
|
28
30
|
DiscoveryTroubleshootingModal,
|
|
@@ -122,6 +124,9 @@ const InfraEnvAgentTable: React.FC<InfraEnvAgentTableProps> = ({
|
|
|
122
124
|
setHostnameFilter,
|
|
123
125
|
setStatusFilter,
|
|
124
126
|
statusFilter,
|
|
127
|
+
labelFilter,
|
|
128
|
+
setLabelFilter,
|
|
129
|
+
hostLabels,
|
|
125
130
|
filteredHosts: hosts,
|
|
126
131
|
sorted,
|
|
127
132
|
} = useAgentsFilter({
|
|
@@ -157,8 +162,10 @@ const InfraEnvAgentTable: React.FC<InfraEnvAgentTableProps> = ({
|
|
|
157
162
|
clusterColumn(agents, agentMachines, getClusterDeploymentLink, t),
|
|
158
163
|
discoveredAtColumn(t),
|
|
159
164
|
cpuCoresColumn(t),
|
|
165
|
+
gpusColumn(t),
|
|
160
166
|
memoryColumn(t),
|
|
161
167
|
disksColumn(t),
|
|
168
|
+
labelsColumn(t),
|
|
162
169
|
].filter(Boolean),
|
|
163
170
|
[
|
|
164
171
|
t,
|
|
@@ -219,6 +226,9 @@ const InfraEnvAgentTable: React.FC<InfraEnvAgentTableProps> = ({
|
|
|
219
226
|
hostnameFilter={hostnameFilter}
|
|
220
227
|
statusFilter={statusFilter}
|
|
221
228
|
setStatusFilter={setStatusFilter}
|
|
229
|
+
hostLabels={hostLabels}
|
|
230
|
+
labelFilter={labelFilter}
|
|
231
|
+
setLabelFilter={setLabelFilter}
|
|
222
232
|
selectedHostIDs={selectedHostIDs}
|
|
223
233
|
setHostnameFilter={setHostnameFilter}
|
|
224
234
|
{...paginationProps}
|
|
@@ -241,6 +251,7 @@ const InfraEnvAgentTable: React.FC<InfraEnvAgentTableProps> = ({
|
|
|
241
251
|
onClearFilters={() => {
|
|
242
252
|
setHostnameFilter(undefined);
|
|
243
253
|
setStatusFilter([]);
|
|
254
|
+
setLabelFilter([]);
|
|
244
255
|
}}
|
|
245
256
|
/>
|
|
246
257
|
) : (
|
|
@@ -65,15 +65,17 @@ const InfraEnvOpenShiftVersionDropdown = ({ osImages }: { osImages: OsImage[] })
|
|
|
65
65
|
onOpenChange={() => setOsImageOpen(!osImageOpen)}
|
|
66
66
|
>
|
|
67
67
|
<DropdownList>
|
|
68
|
-
{filteredImages
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
68
|
+
{filteredImages
|
|
69
|
+
.sort((a, b) => b.openshiftVersion.localeCompare(a.openshiftVersion))
|
|
70
|
+
.map((image) => (
|
|
71
|
+
<DropdownItem
|
|
72
|
+
key={image.openshiftVersion}
|
|
73
|
+
id={image.openshiftVersion}
|
|
74
|
+
value={image.openshiftVersion}
|
|
75
|
+
>
|
|
76
|
+
{`OpenShift ${image.openshiftVersion}`}
|
|
77
|
+
</DropdownItem>
|
|
78
|
+
))}
|
|
77
79
|
</DropdownList>
|
|
78
80
|
</Dropdown>
|
|
79
81
|
</Tooltip>
|
|
@@ -66,11 +66,14 @@ type InfraTableToolbarProps = ReturnType<typeof usePagination> & {
|
|
|
66
66
|
setSelectedHostIDs: (items: string[]) => void;
|
|
67
67
|
massActions: React.ReactNode[];
|
|
68
68
|
hosts: Host[];
|
|
69
|
+
hostLabels: { [key in string]: number };
|
|
69
70
|
statusFilter: string[];
|
|
71
|
+
labelFilter: string[];
|
|
70
72
|
statusCount: StatusCount;
|
|
71
73
|
hostnameFilter: string | undefined;
|
|
72
74
|
setHostnameFilter: (hostname: string | undefined) => void;
|
|
73
75
|
setStatusFilter: (status: string[]) => void;
|
|
76
|
+
setLabelFilter: (label: string[]) => void;
|
|
74
77
|
selectedHostIDs: string[];
|
|
75
78
|
};
|
|
76
79
|
|
|
@@ -78,17 +81,22 @@ const InfraTableToolbar: React.FC<InfraTableToolbarProps> = ({
|
|
|
78
81
|
setSelectedHostIDs,
|
|
79
82
|
massActions,
|
|
80
83
|
hosts,
|
|
84
|
+
hostLabels,
|
|
81
85
|
statusFilter,
|
|
86
|
+
labelFilter,
|
|
82
87
|
statusCount,
|
|
83
88
|
hostnameFilter,
|
|
84
89
|
setHostnameFilter,
|
|
85
90
|
setStatusFilter,
|
|
91
|
+
setLabelFilter,
|
|
86
92
|
selectedHostIDs,
|
|
87
93
|
...paginationProps
|
|
88
94
|
}) => {
|
|
89
95
|
const { t } = useTranslation();
|
|
90
96
|
const agentStatuses = agentStatus(t);
|
|
91
97
|
const [statusFilterOpen, setStatusFilterOpen] = React.useState(false);
|
|
98
|
+
const [labelFilterOpen, setLabelFilterOpen] = React.useState(false);
|
|
99
|
+
|
|
92
100
|
const itemIDs = React.useMemo(() => hosts.map((h) => h.id), [hosts]);
|
|
93
101
|
const filterStatuses = React.useMemo(() => getStatusesForFilter(agentStatuses), [agentStatuses]);
|
|
94
102
|
const categoryLabels = getCategoryLabels(t);
|
|
@@ -106,13 +114,29 @@ const InfraTableToolbar: React.FC<InfraTableToolbarProps> = ({
|
|
|
106
114
|
}
|
|
107
115
|
};
|
|
108
116
|
|
|
117
|
+
const onLabelFilterToggle = () => setLabelFilterOpen(!labelFilterOpen);
|
|
118
|
+
const onLabelFilterSelect = (
|
|
119
|
+
e?: React.MouseEvent<Element, MouseEvent>,
|
|
120
|
+
value?: string | number,
|
|
121
|
+
) => {
|
|
122
|
+
if (!labelFilter?.includes(value as string)) {
|
|
123
|
+
const newItems = (labelFilter ? [...labelFilter, value] : [value]) as string[];
|
|
124
|
+
setLabelFilter(newItems);
|
|
125
|
+
} else {
|
|
126
|
+
setLabelFilter(labelFilter?.filter((f) => f !== value));
|
|
127
|
+
}
|
|
128
|
+
};
|
|
129
|
+
|
|
109
130
|
return (
|
|
110
131
|
<TableToolbar
|
|
111
132
|
selectedIDs={selectedHostIDs || []}
|
|
112
133
|
itemIDs={itemIDs}
|
|
113
134
|
setSelectedIDs={setSelectedHostIDs}
|
|
114
135
|
actions={massActions}
|
|
115
|
-
clearAllFilters={() =>
|
|
136
|
+
clearAllFilters={() => {
|
|
137
|
+
setStatusFilter([]);
|
|
138
|
+
setLabelFilter([]);
|
|
139
|
+
}}
|
|
116
140
|
{...paginationProps}
|
|
117
141
|
>
|
|
118
142
|
<ToolbarItem>
|
|
@@ -123,6 +147,7 @@ const InfraTableToolbar: React.FC<InfraTableToolbarProps> = ({
|
|
|
123
147
|
onClear={() => setHostnameFilter(undefined)}
|
|
124
148
|
/>
|
|
125
149
|
</ToolbarItem>
|
|
150
|
+
|
|
126
151
|
<ToolbarItem>
|
|
127
152
|
<ToolbarFilter
|
|
128
153
|
chips={statusFilter}
|
|
@@ -175,6 +200,51 @@ const InfraTableToolbar: React.FC<InfraTableToolbarProps> = ({
|
|
|
175
200
|
</Dropdown>
|
|
176
201
|
</ToolbarFilter>
|
|
177
202
|
</ToolbarItem>
|
|
203
|
+
|
|
204
|
+
<ToolbarItem>
|
|
205
|
+
<ToolbarFilter
|
|
206
|
+
chips={labelFilter}
|
|
207
|
+
deleteChip={(_, chip) => setLabelFilter(labelFilter.filter((f) => f !== chip))}
|
|
208
|
+
deleteChipGroup={() => setLabelFilter([])}
|
|
209
|
+
categoryName={'Labels'}
|
|
210
|
+
>
|
|
211
|
+
<Dropdown
|
|
212
|
+
isOpen={labelFilterOpen}
|
|
213
|
+
onSelect={onLabelFilterSelect}
|
|
214
|
+
onOpenChange={onLabelFilterToggle}
|
|
215
|
+
shouldFocusToggleOnSelect
|
|
216
|
+
toggle={(toggleRef: React.Ref<MenuToggleElement>) => (
|
|
217
|
+
<MenuToggle
|
|
218
|
+
ref={toggleRef}
|
|
219
|
+
isFullWidth
|
|
220
|
+
onClick={onLabelFilterToggle}
|
|
221
|
+
isExpanded={labelFilterOpen}
|
|
222
|
+
icon={<FilterIcon />}
|
|
223
|
+
>
|
|
224
|
+
{t('ai:Labels')}
|
|
225
|
+
</MenuToggle>
|
|
226
|
+
)}
|
|
227
|
+
>
|
|
228
|
+
<DropdownGroup label={t('ai:Labels')}>
|
|
229
|
+
{Object.entries(hostLabels).map(([label, count]) => (
|
|
230
|
+
<DropdownItem
|
|
231
|
+
hasCheckbox
|
|
232
|
+
key={`host-label-${label}`}
|
|
233
|
+
value={label}
|
|
234
|
+
isSelected={labelFilter?.includes(label)}
|
|
235
|
+
>
|
|
236
|
+
<Split hasGutter>
|
|
237
|
+
<SplitItem>{label}</SplitItem>
|
|
238
|
+
<SplitItem>
|
|
239
|
+
<Badge isRead>{count || 0}</Badge>
|
|
240
|
+
</SplitItem>
|
|
241
|
+
</Split>
|
|
242
|
+
</DropdownItem>
|
|
243
|
+
))}
|
|
244
|
+
</DropdownGroup>
|
|
245
|
+
</Dropdown>
|
|
246
|
+
</ToolbarFilter>
|
|
247
|
+
</ToolbarItem>
|
|
178
248
|
</TableToolbar>
|
|
179
249
|
);
|
|
180
250
|
};
|
|
@@ -18,9 +18,13 @@ const AGENT_FOR_SELECTION_STATUSES: AgentStatus[] = [
|
|
|
18
18
|
export const hostToAgent = (agents: AgentK8sResource[] = [], host: Host) =>
|
|
19
19
|
agents.find((a) => a.metadata?.uid === host.id) as AgentK8sResource;
|
|
20
20
|
|
|
21
|
-
export const getAgentsForSelection = (agents: AgentK8sResource[]) =>
|
|
21
|
+
export const getAgentsForSelection = (agents: AgentK8sResource[], isSubmitting?: boolean) =>
|
|
22
22
|
agents.filter((agent) => {
|
|
23
23
|
const key = getAgentStatusKey(agent);
|
|
24
|
+
if (isSubmitting) {
|
|
25
|
+
return [...AGENT_FOR_SELECTION_STATUSES, 'specSyncErr'].includes(key as AgentStatus);
|
|
26
|
+
}
|
|
27
|
+
|
|
24
28
|
return AGENT_FOR_SELECTION_STATUSES.includes(key as AgentStatus);
|
|
25
29
|
});
|
|
26
30
|
|
|
@@ -41,7 +41,7 @@ const hostnameColumn = (agents: AgentK8sResource[], t: TFunction): TableRow<Host
|
|
|
41
41
|
},
|
|
42
42
|
cell: (host) => {
|
|
43
43
|
const agent = agents.find((a) => a.metadata?.uid === host.id);
|
|
44
|
-
const hostname = agent?.spec
|
|
44
|
+
const hostname = agent?.spec?.hostname || agent?.status?.inventory?.hostname;
|
|
45
45
|
return {
|
|
46
46
|
title: <ApproveTableRow agent={agent}>{hostname}</ApproveTableRow>,
|
|
47
47
|
props: { 'data-testid': 'hostname' },
|
|
@@ -104,16 +104,16 @@ export const getClusterDetailsValidationSchema = ({
|
|
|
104
104
|
return Yup.object({
|
|
105
105
|
name: validateName(),
|
|
106
106
|
baseDnsDomain: isOcm
|
|
107
|
-
? baseDomainValidationSchema.required('Required')
|
|
108
|
-
: dnsNameValidationSchema.required('Required'),
|
|
107
|
+
? baseDomainValidationSchema.required(t('ai:Required field'))
|
|
108
|
+
: dnsNameValidationSchema.required(t('ai:Required field')),
|
|
109
109
|
});
|
|
110
110
|
}
|
|
111
111
|
return Yup.object({
|
|
112
112
|
name: validateName(),
|
|
113
113
|
baseDnsDomain: isOcm
|
|
114
|
-
? baseDomainValidationSchema.required('Required')
|
|
115
|
-
: dnsNameValidationSchema.required('Required'),
|
|
116
|
-
pullSecret: pullSecretValidationSchema.required('Required
|
|
114
|
+
? baseDomainValidationSchema.required(t('ai:Required field'))
|
|
115
|
+
: dnsNameValidationSchema.required(t('ai:Required field')),
|
|
116
|
+
pullSecret: pullSecretValidationSchema.required(t('ai:Required field')),
|
|
117
117
|
diskEncryptionTangServers: Yup.array().when('diskEncryptionMode', {
|
|
118
118
|
is: (diskEncryptionMode: DiskEncryption['mode']) => {
|
|
119
119
|
return diskEncryptionMode === 'tang';
|
|
@@ -125,8 +125,8 @@ export const getClusterDetailsValidationSchema = ({
|
|
|
125
125
|
.url(
|
|
126
126
|
t('ai:Tang Server URL must be a valid URL starting with "http://" or "https://"'),
|
|
127
127
|
)
|
|
128
|
-
.required(t('ai:Required
|
|
129
|
-
thumbprint: Yup.string().required(t('ai:Required
|
|
128
|
+
.required(t('ai:Required field')),
|
|
129
|
+
thumbprint: Yup.string().required(t('ai:Required field')),
|
|
130
130
|
}),
|
|
131
131
|
),
|
|
132
132
|
}),
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import * as React from 'react';
|
|
2
|
+
import { Label, LabelGroup } from '@patternfly/react-core';
|
|
2
3
|
import { Address4, Address6 } from 'ip-address';
|
|
3
4
|
import type {
|
|
4
5
|
Cluster,
|
|
@@ -20,6 +21,7 @@ import HostStatus from './HostStatus';
|
|
|
20
21
|
import RoleCell from './RoleCell';
|
|
21
22
|
import {
|
|
22
23
|
areOnlySoftValidationsFailing,
|
|
24
|
+
getHostLabels,
|
|
23
25
|
getHostname,
|
|
24
26
|
getHostRole,
|
|
25
27
|
getHostStatus,
|
|
@@ -280,6 +282,24 @@ export const disksColumn = (t: TFunction): TableRow<Host> => ({
|
|
|
280
282
|
},
|
|
281
283
|
});
|
|
282
284
|
|
|
285
|
+
export const gpusColumn = (t: TFunction): TableRow<Host> => ({
|
|
286
|
+
header: {
|
|
287
|
+
title: t('ai:GPUs'),
|
|
288
|
+
props: {
|
|
289
|
+
id: 'col-header-gpus',
|
|
290
|
+
},
|
|
291
|
+
sort: true,
|
|
292
|
+
},
|
|
293
|
+
cell: (host) => {
|
|
294
|
+
const { gpus } = getInventory(host);
|
|
295
|
+
return {
|
|
296
|
+
title: <>{gpus?.length ?? '--'}</>,
|
|
297
|
+
props: { 'data-testid': 'host-gpus' },
|
|
298
|
+
sortableValue: gpus?.length ?? 0,
|
|
299
|
+
};
|
|
300
|
+
},
|
|
301
|
+
});
|
|
302
|
+
|
|
283
303
|
export const countColumn = (cluster: Cluster): TableRow<Host> => ({
|
|
284
304
|
header: { title: <HostsCount cluster={cluster} inParenthesis /> },
|
|
285
305
|
});
|
|
@@ -363,6 +383,31 @@ export const macAddressColumn = (cluster: Cluster): TableRow<Host> => ({
|
|
|
363
383
|
},
|
|
364
384
|
});
|
|
365
385
|
|
|
386
|
+
export const labelsColumn = (t: TFunction): TableRow<Host> => ({
|
|
387
|
+
header: {
|
|
388
|
+
title: t('ai:Labels'),
|
|
389
|
+
props: {
|
|
390
|
+
id: 'col-header-labels',
|
|
391
|
+
},
|
|
392
|
+
sort: false,
|
|
393
|
+
},
|
|
394
|
+
cell: (host) => {
|
|
395
|
+
const labels = getHostLabels(host);
|
|
396
|
+
return {
|
|
397
|
+
title: (
|
|
398
|
+
<LabelGroup>
|
|
399
|
+
{Object.entries(labels).map(([key, value], index) => (
|
|
400
|
+
<Label key={`${host.id}-host-label-${index}`} isCompact>
|
|
401
|
+
{key} = {value}
|
|
402
|
+
</Label>
|
|
403
|
+
))}
|
|
404
|
+
</LabelGroup>
|
|
405
|
+
),
|
|
406
|
+
props: { 'data-testid': 'host-labels' },
|
|
407
|
+
};
|
|
408
|
+
},
|
|
409
|
+
});
|
|
410
|
+
|
|
366
411
|
const ActionTitle: React.FC<{ disabled: boolean; description?: string; title: string }> = ({
|
|
367
412
|
title,
|
|
368
413
|
description,
|
|
@@ -205,6 +205,10 @@ export const getInventory = (host: Host) => {
|
|
|
205
205
|
return stringToJSON<Inventory>(inventoryString) || {};
|
|
206
206
|
};
|
|
207
207
|
|
|
208
|
+
export const getHostLabels = (host: Host) => {
|
|
209
|
+
return host.nodeLabels ? (JSON.parse(host.nodeLabels) as { [key: string]: string }) : {};
|
|
210
|
+
};
|
|
211
|
+
|
|
208
212
|
export const filterByHostname = (hosts: Host[], hostnameFilter: string | undefined) => {
|
|
209
213
|
if (!hostnameFilter) {
|
|
210
214
|
return { hosts, sorted: false };
|
|
@@ -57,7 +57,7 @@ export const nameValidationSchema = (
|
|
|
57
57
|
) => {
|
|
58
58
|
const clusterNameValidationMessagesList = clusterNameValidationMessages(t);
|
|
59
59
|
return Yup.string()
|
|
60
|
-
.required('Required')
|
|
60
|
+
.required(t('ai:Required field'))
|
|
61
61
|
.matches(CLUSTER_NAME_VALID_CHARS_REGEX, {
|
|
62
62
|
message: clusterNameValidationMessagesList.INVALID_VALUE,
|
|
63
63
|
excludeEmptyString: true,
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"dependencies": {
|
|
3
|
-
"@openshift-assisted/locales": "2.16.
|
|
4
|
-
"@openshift-assisted/types": "2.16.
|
|
3
|
+
"@openshift-assisted/locales": "2.16.5-cim",
|
|
4
|
+
"@openshift-assisted/types": "2.16.5-cim",
|
|
5
5
|
"@openshift-console/dynamic-plugin-sdk": "1.0.0",
|
|
6
6
|
"@patternfly/patternfly": "5.2.0",
|
|
7
7
|
"@patternfly/react-code-editor": "5.2.0",
|
|
@@ -140,5 +140,5 @@
|
|
|
140
140
|
]
|
|
141
141
|
}
|
|
142
142
|
},
|
|
143
|
-
"version": "2.16.
|
|
143
|
+
"version": "2.16.5-cim"
|
|
144
144
|
}
|