mirror of
https://github.com/fleetdm/fleet
synced 2026-05-23 08:58:41 +00:00
Dashboard UI: Hosts change on team selection (#2839)
This commit is contained in:
parent
2d1e4c0898
commit
81ccbab31f
5 changed files with 110 additions and 46 deletions
1
changes/issue-2822-dashboard-host-change-on-team
Normal file
1
changes/issue-2822-dashboard-host-change-on-team
Normal file
|
|
@ -0,0 +1 @@
|
|||
* Dashboard hosts change on team selection
|
||||
|
|
@ -92,6 +92,7 @@ describe(
|
|||
cy.findByText(/back to queries/i).should("exist");
|
||||
cy.visit("/queries/manage");
|
||||
|
||||
cy.wait(2000); // eslint-disable-line cypress/no-unnecessary-waiting
|
||||
cy.findByText(/query all/i).click();
|
||||
|
||||
cy.wait(2000); // eslint-disable-line cypress/no-unnecessary-waiting
|
||||
|
|
|
|||
|
|
@ -25,6 +25,12 @@ interface ITeamsResponse {
|
|||
|
||||
const baseClass = "homepage";
|
||||
|
||||
const TAGGED_TEMPLATES = {
|
||||
hostsByTeamRoute: (teamId: number | undefined | null) => {
|
||||
return `${teamId ? `/?team_id=${teamId}` : ""}`;
|
||||
},
|
||||
};
|
||||
|
||||
const Homepage = (): JSX.Element => {
|
||||
const { MANAGE_HOSTS } = paths;
|
||||
const {
|
||||
|
|
@ -76,9 +82,14 @@ const Homepage = (): JSX.Element => {
|
|||
<div className={`${baseClass}__section one-column`}>
|
||||
<InfoCard
|
||||
title="Hosts"
|
||||
action={{ type: "link", to: MANAGE_HOSTS, text: "View all hosts" }}
|
||||
action={{
|
||||
type: "link",
|
||||
to:
|
||||
MANAGE_HOSTS + TAGGED_TEMPLATES.hostsByTeamRoute(currentTeam?.id),
|
||||
text: "View all hosts",
|
||||
}}
|
||||
>
|
||||
<HostsSummary />
|
||||
<HostsSummary currentTeamId={currentTeam?.id} />
|
||||
</InfoCard>
|
||||
</div>
|
||||
{isPreviewMode && (
|
||||
|
|
|
|||
|
|
@ -1,61 +1,100 @@
|
|||
import React, { useEffect } from "react";
|
||||
import { useDispatch, useSelector } from "react-redux";
|
||||
import { reduce } from "lodash";
|
||||
import React, { useState } from "react";
|
||||
import { useQuery } from "react-query";
|
||||
import { ILabel } from "interfaces/label";
|
||||
// @ts-ignore
|
||||
import { getLabels } from "redux/nodes/components/ManageHostsPage/actions";
|
||||
|
||||
import hostCountAPI from "services/entities/host_count";
|
||||
import labelsAPI from "services/entities/labels";
|
||||
|
||||
import WindowsIcon from "../../../../../assets/images/icon-windows-48x48@2x.png";
|
||||
import LinuxIcon from "../../../../../assets/images/icon-linux-48x48@2x.png";
|
||||
import MacIcon from "../../../../../assets/images/icon-mac-48x48@2x.png";
|
||||
|
||||
const baseClass = "hosts-summary";
|
||||
|
||||
interface IRootState {
|
||||
entities: {
|
||||
labels: {
|
||||
isLoading: boolean;
|
||||
data: {
|
||||
[id: number]: ILabel;
|
||||
};
|
||||
};
|
||||
};
|
||||
interface IHostsSummaryProps {
|
||||
currentTeamId: number | undefined;
|
||||
}
|
||||
|
||||
const PLATFORM_STRINGS = {
|
||||
macOS: ["macOS"],
|
||||
windows: ["MS Windows"],
|
||||
linux: ["All Linux"],
|
||||
};
|
||||
interface ILabelsResponse {
|
||||
labels: ILabel[];
|
||||
}
|
||||
|
||||
const HostsSummary = (): JSX.Element => {
|
||||
const dispatch = useDispatch();
|
||||
interface IHostCountResponse {
|
||||
count: number;
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
dispatch(getLabels());
|
||||
}, []);
|
||||
const HostsSummary = ({ currentTeamId }: IHostsSummaryProps): JSX.Element => {
|
||||
const [macCount, setMacCount] = useState<string | undefined>();
|
||||
const [windowsCount, setWindowsCount] = useState<string | undefined>();
|
||||
const [linuxCount, setLinuxCount] = useState<string | undefined>();
|
||||
|
||||
const labels = useSelector((state: IRootState) => state.entities.labels.data);
|
||||
|
||||
// Builtin labels from state populate os counts
|
||||
const getCount = (platformTitles: string[]) => {
|
||||
return reduce(
|
||||
Object.values(labels),
|
||||
(total, label) => {
|
||||
return label.label_type === "builtin" &&
|
||||
platformTitles.includes(label.name) &&
|
||||
label.count
|
||||
? total + label.count
|
||||
: total;
|
||||
},
|
||||
0
|
||||
);
|
||||
const getLabel = (labelString: string, labels: ILabel[]) => {
|
||||
return Object.values(labels).filter((label: ILabel) => {
|
||||
return label.label_type === "builtin" && label.name === labelString;
|
||||
});
|
||||
};
|
||||
|
||||
const macCount = getCount(PLATFORM_STRINGS.macOS).toLocaleString("en-US");
|
||||
const windowsCount = getCount(PLATFORM_STRINGS.windows).toLocaleString(
|
||||
"en-US"
|
||||
const { data: labels } = useQuery<ILabelsResponse, Error, ILabel[]>(
|
||||
["labels"],
|
||||
() => labelsAPI.loadAll(),
|
||||
{
|
||||
select: (data: ILabelsResponse) => data.labels,
|
||||
}
|
||||
);
|
||||
|
||||
useQuery<IHostCountResponse, Error, number>(
|
||||
["mac host count", currentTeamId],
|
||||
() => {
|
||||
const macOsLabel = getLabel("macOS", labels || []);
|
||||
return (
|
||||
hostCountAPI.load({
|
||||
selectedLabels: [`labels/${macOsLabel[0].id}`],
|
||||
teamId: currentTeamId,
|
||||
}) || { count: 0 }
|
||||
);
|
||||
},
|
||||
{
|
||||
select: (data: IHostCountResponse) => data.count,
|
||||
enabled: !!labels,
|
||||
onSuccess: (data: number) => setMacCount(data.toLocaleString("en-US")),
|
||||
}
|
||||
);
|
||||
|
||||
useQuery<IHostCountResponse, Error, number>(
|
||||
["windows host count", currentTeamId],
|
||||
() => {
|
||||
const windowsLabel = getLabel("MS Windows", labels || []);
|
||||
return (
|
||||
hostCountAPI.load({
|
||||
selectedLabels: [`labels/${windowsLabel[0].id}`],
|
||||
teamId: currentTeamId,
|
||||
}) || { count: 0 }
|
||||
);
|
||||
},
|
||||
{
|
||||
select: (data: IHostCountResponse) => data.count,
|
||||
enabled: !!labels,
|
||||
onSuccess: (data: number) =>
|
||||
setWindowsCount(data.toLocaleString("en-US")),
|
||||
}
|
||||
);
|
||||
|
||||
useQuery<IHostCountResponse, Error, number>(
|
||||
["linux host count", currentTeamId],
|
||||
() => {
|
||||
const linuxLabel = getLabel("All Linux", labels || []);
|
||||
return (
|
||||
hostCountAPI.load({
|
||||
selectedLabels: [`labels/${linuxLabel[0].id}`],
|
||||
teamId: currentTeamId,
|
||||
}) || { count: 0 }
|
||||
);
|
||||
},
|
||||
{
|
||||
select: (data: IHostCountResponse) => data.count,
|
||||
enabled: !!labels,
|
||||
onSuccess: (data: number) => setLinuxCount(data.toLocaleString("en-US")),
|
||||
}
|
||||
);
|
||||
const linuxCount = getCount(PLATFORM_STRINGS.linux).toLocaleString("en-US");
|
||||
|
||||
return (
|
||||
<div className={baseClass}>
|
||||
|
|
|
|||
|
|
@ -323,6 +323,10 @@ const ManageHostsPage = ({
|
|||
),
|
||||
};
|
||||
|
||||
if (queryParams.team_id) {
|
||||
options.teamId = queryParams.team_id;
|
||||
}
|
||||
|
||||
try {
|
||||
const { hosts: returnedHosts, software } = await hostsAPI.loadAll(
|
||||
options
|
||||
|
|
@ -350,6 +354,10 @@ const ManageHostsPage = ({
|
|||
),
|
||||
};
|
||||
|
||||
if (queryParams.team_id) {
|
||||
options.teamId = queryParams.team_id;
|
||||
}
|
||||
|
||||
try {
|
||||
const { count: returnedHostCount } = await hostCountAPI.load(options);
|
||||
setFilteredHostCount(returnedHostCount);
|
||||
|
|
@ -658,6 +666,10 @@ const ManageHostsPage = ({
|
|||
newQueryParams.team_id = teamId;
|
||||
}
|
||||
|
||||
if (queryParams.team_id) {
|
||||
newQueryParams.team_id = queryParams.team_id;
|
||||
}
|
||||
|
||||
if (policyId) {
|
||||
newQueryParams.policy_id = policyId;
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue