mirror of
https://github.com/fleetdm/fleet
synced 2026-05-24 01:18:42 +00:00
Fix wrong number of host in mdm solutions modal and fix mdm solutions table UI to work for null named solutions (#17336)
relates to #16837, #17334, #17335 This fixes a UI bug for the case where the mdm solution name can be null. We now handle this case properly and show the mdm solution data in the modal. This also fixes a UI bug where we showed the incorrect number of hosts in the mdm solutions modal. There is various cleanup here to the js and scss code in this PR too. - [x] Added/updated tests - [x] Manual QA for all new/changed functionality
This commit is contained in:
parent
6c7130efa6
commit
60167ff0c6
6 changed files with 74 additions and 97 deletions
|
|
@ -21,15 +21,16 @@ describe("MDM Card", () => {
|
|||
createMockMdmSolution({ name: "Test Solution", id: 3 }),
|
||||
createMockMdmSolution({ name: "Test Solution", id: 4 }),
|
||||
createMockMdmSolution({ name: "Test Solution 2", id: 5 }),
|
||||
createMockMdmSolution({ name: null, id: 6 }),
|
||||
createMockMdmSolution({ name: null, id: 7 }),
|
||||
]}
|
||||
/>
|
||||
);
|
||||
|
||||
debug();
|
||||
|
||||
expect(screen.getAllByText("MDM Solution").length).toBe(1);
|
||||
expect(screen.getAllByText("Test Solution").length).toBe(1);
|
||||
expect(screen.getAllByText("Test Solution 2").length).toBe(1);
|
||||
expect(screen.getAllByText("Unknown").length).toBe(1);
|
||||
});
|
||||
|
||||
it("render the correct number of Enrollment status", async () => {
|
||||
|
|
|
|||
|
|
@ -65,6 +65,28 @@ const EmptyMdmSolutions = (): JSX.Element => (
|
|||
/>
|
||||
);
|
||||
|
||||
type IMdmSolutionMap = Record<string, IMdmSolution>;
|
||||
|
||||
const reduceSolutionsToObj = (mdmSolutions: IMdmSolution[]) => {
|
||||
return mdmSolutions.reduce<IMdmSolutionMap>((acc, nextSolution) => {
|
||||
// The solution name can be null so we add an Unknown key to the
|
||||
// accumulator in this case.
|
||||
if (nextSolution.name === null) {
|
||||
if (acc.Unknown) {
|
||||
acc.Unknown.hosts_count += nextSolution.hosts_count;
|
||||
} else {
|
||||
acc.Unknown = Object.assign({ ...nextSolution });
|
||||
}
|
||||
} else if (acc[nextSolution.name]) {
|
||||
acc[nextSolution.name].hosts_count += nextSolution.hosts_count;
|
||||
} else {
|
||||
acc[nextSolution.name] = Object.assign({ ...nextSolution });
|
||||
}
|
||||
|
||||
return acc;
|
||||
}, {});
|
||||
};
|
||||
|
||||
const Mdm = ({
|
||||
isFetching,
|
||||
error,
|
||||
|
|
@ -85,19 +107,7 @@ const Mdm = ({
|
|||
return [];
|
||||
}
|
||||
|
||||
return mdmSolutions.reduce<IMdmSolution[]>((acc, nextSolution) => {
|
||||
const existingSolution = acc.find(
|
||||
(solution) => solution.name === nextSolution.name
|
||||
);
|
||||
|
||||
if (existingSolution) {
|
||||
existingSolution.hosts_count += nextSolution.hosts_count;
|
||||
} else {
|
||||
acc.push(nextSolution);
|
||||
}
|
||||
|
||||
return acc;
|
||||
}, []);
|
||||
return Object.values(reduceSolutionsToObj(mdmSolutions));
|
||||
}, [mdmSolutions]);
|
||||
|
||||
const solutionsTableHeaders = useMemo(
|
||||
|
|
@ -108,10 +118,7 @@ const Mdm = ({
|
|||
() => generateStatusTableHeaders(selectedTeamId),
|
||||
[selectedTeamId]
|
||||
);
|
||||
const solutionsDataSet = generateSolutionsDataSet(
|
||||
rolledupMdmSolutionsData,
|
||||
selectedPlatformLabelId
|
||||
);
|
||||
const solutionsDataSet = generateSolutionsDataSet(rolledupMdmSolutionsData);
|
||||
const statusDataSet = generateStatusDataSet(
|
||||
mdmStatusData,
|
||||
selectedPlatformLabelId
|
||||
|
|
@ -143,6 +150,7 @@ const Mdm = ({
|
|||
<TableDataError card />
|
||||
) : (
|
||||
<TableContainer<IRowProps>
|
||||
className={`${baseClass}__mdm-solutions-table`}
|
||||
columnConfigs={solutionsTableHeaders}
|
||||
data={solutionsDataSet}
|
||||
isLoading={isFetching}
|
||||
|
|
@ -163,6 +171,7 @@ const Mdm = ({
|
|||
<TableDataError card />
|
||||
) : (
|
||||
<TableContainer
|
||||
className={`${baseClass}__mdm-status-table`}
|
||||
columnConfigs={statusTableHeaders}
|
||||
data={statusDataSet}
|
||||
isLoading={isFetching}
|
||||
|
|
|
|||
|
|
@ -2,11 +2,7 @@ import React from "react";
|
|||
|
||||
import { IMdmSolution } from "interfaces/mdm";
|
||||
|
||||
import { greyCell } from "utilities/helpers";
|
||||
import HeaderCell from "components/TableContainer/DataTable/HeaderCell";
|
||||
import TextCell from "components/TableContainer/DataTable/TextCell";
|
||||
import ViewAllHostsLink from "components/ViewAllHostsLink";
|
||||
import LinkCell from "components/TableContainer/DataTable/LinkCell";
|
||||
import InternalLinkCell from "../../../../components/TableContainer/DataTable/InternalLinkCell";
|
||||
|
||||
// NOTE: cellProps come from react-table
|
||||
|
|
@ -47,7 +43,7 @@ export const generateSolutionsTableHeaders = (): IDataColumn[] => [
|
|||
title: "Name",
|
||||
Header: "Name",
|
||||
disableSortBy: true,
|
||||
accessor: "name",
|
||||
accessor: "displayName",
|
||||
Cell: (cellProps: ICellProps) => (
|
||||
<InternalLinkCell value={cellProps.cell.value} />
|
||||
),
|
||||
|
|
@ -61,27 +57,17 @@ export const generateSolutionsTableHeaders = (): IDataColumn[] => [
|
|||
},
|
||||
];
|
||||
|
||||
const enhanceSolutionsData = (
|
||||
solutions: IMdmSolution[],
|
||||
selectedPlatformLabelId?: number
|
||||
): IMdmSolution[] => {
|
||||
return Object.values(solutions).map((solution) => {
|
||||
return {
|
||||
id: solution.id,
|
||||
name: solution.name || "Unknown",
|
||||
server_url: solution.server_url,
|
||||
hosts_count: solution.hosts_count,
|
||||
selectedPlatformLabelId,
|
||||
};
|
||||
});
|
||||
};
|
||||
|
||||
export const generateSolutionsDataSet = (
|
||||
solutions: IMdmSolution[] | null,
|
||||
selectedPlatformLabelId?: number
|
||||
solutions: IMdmSolution[] | null
|
||||
): IMdmSolution[] => {
|
||||
if (!solutions) {
|
||||
return [];
|
||||
}
|
||||
return [...enhanceSolutionsData(solutions, selectedPlatformLabelId)];
|
||||
|
||||
return solutions.map((solution) => {
|
||||
return {
|
||||
...solution,
|
||||
displayName: solution.name ?? "Unknown",
|
||||
};
|
||||
});
|
||||
};
|
||||
|
|
|
|||
|
|
@ -7,47 +7,39 @@
|
|||
display: none;
|
||||
}
|
||||
|
||||
.data-table-block {
|
||||
.data-table__table {
|
||||
table-layout: fixed;
|
||||
&__mdm-status-table {
|
||||
.data-table-block {
|
||||
.data-table__table {
|
||||
thead {
|
||||
.status__header {
|
||||
width: 30%;
|
||||
}
|
||||
|
||||
thead {
|
||||
.name__header,
|
||||
.status__header {
|
||||
width: 30%;
|
||||
}
|
||||
.server_url__header {
|
||||
width: 30%;
|
||||
}
|
||||
.hosts_count__header,
|
||||
.hosts__header {
|
||||
border-right: 0;
|
||||
padding-right: 0;
|
||||
width: 60px;
|
||||
}
|
||||
.linkToFilteredHosts__header {
|
||||
width: 140px;
|
||||
}
|
||||
}
|
||||
.hosts__header {
|
||||
border-right: 0;
|
||||
padding-right: 0;
|
||||
width: 60px;
|
||||
}
|
||||
|
||||
tbody {
|
||||
.mdm-solution-link {
|
||||
opacity: 0;
|
||||
transition: 250ms;
|
||||
text-overflow: none;
|
||||
}
|
||||
tr:hover {
|
||||
.mdm-solution-link {
|
||||
opacity: 1;
|
||||
.linkToFilteredHosts__header {
|
||||
width: 140px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
.count-loading {
|
||||
color: $ui-fleet-black-50;
|
||||
}
|
||||
.count-error {
|
||||
color: $ui-error;
|
||||
|
||||
tbody {
|
||||
.mdm-solution-link {
|
||||
opacity: 0;
|
||||
transition: 250ms;
|
||||
text-overflow: none;
|
||||
}
|
||||
tr:hover {
|
||||
.mdm-solution-link {
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -29,8 +29,6 @@ const MdmSolutionsModal = ({
|
|||
selectedTeamId,
|
||||
onCancel,
|
||||
}: IMdmSolutionModalProps) => {
|
||||
console.log(mdmSolutions);
|
||||
|
||||
const solutionsTableHeaders = useMemo(
|
||||
() => generateSolutionsTableHeaders(selectedTeamId),
|
||||
[selectedTeamId]
|
||||
|
|
@ -43,7 +41,7 @@ const MdmSolutionsModal = ({
|
|||
return (
|
||||
<Modal
|
||||
className={baseClass}
|
||||
title={mdmSolutions[0].name ?? "Mdm solution"}
|
||||
title={mdmSolutions[0].name ?? "Unknown mdm solution"}
|
||||
width="large"
|
||||
onExit={onCancel}
|
||||
>
|
||||
|
|
|
|||
|
|
@ -86,21 +86,6 @@ export const generateSolutionsTableHeaders = (
|
|||
},
|
||||
];
|
||||
|
||||
const enhanceSolutionsData = (
|
||||
solutions: IMdmSolution[],
|
||||
selectedPlatformLabelId?: number
|
||||
): IMdmSolution[] => {
|
||||
return Object.values(solutions).map((solution) => {
|
||||
return {
|
||||
id: solution.id,
|
||||
name: solution.name || "Unknown",
|
||||
server_url: solution.server_url,
|
||||
hosts_count: solution.hosts_count,
|
||||
selectedPlatformLabelId,
|
||||
};
|
||||
});
|
||||
};
|
||||
|
||||
export const generateSolutionsDataSet = (
|
||||
solutions: IMdmSolution[] | null,
|
||||
selectedPlatformLabelId?: number
|
||||
|
|
@ -108,5 +93,11 @@ export const generateSolutionsDataSet = (
|
|||
if (!solutions) {
|
||||
return [];
|
||||
}
|
||||
return [...enhanceSolutionsData(solutions, selectedPlatformLabelId)];
|
||||
|
||||
return solutions.map((solution) => {
|
||||
return {
|
||||
...solution,
|
||||
selectedPlatformLabelId,
|
||||
};
|
||||
});
|
||||
};
|
||||
|
|
|
|||
Loading…
Reference in a new issue