Skip to content

Commit

Permalink
UI - Host filters bug (#22132)
Browse files Browse the repository at this point in the history
## #22088 

- Hosts page filters were using the same type that had been updated with
additional, more granular options, but the filters for that page still
only support the aggregate options "install", "pending" or "failed".
Updated hosts page to use new type `SoftwareAggregateStatus` to maintain
functionality.
- Note that this does _not_ fix this related but distinct _released_
bug: #22136

- [x] Manual QA for all new/changed functionality

---------

Co-authored-by: Jacob Shandling <jacob@fleetdm.com>
  • Loading branch information
jacobshandling and Jacob Shandling authored Sep 16, 2024
1 parent ef8e48c commit c0ac242
Show file tree
Hide file tree
Showing 6 changed files with 43 additions and 22 deletions.
21 changes: 21 additions & 0 deletions frontend/interfaces/software.ts
Original file line number Diff line number Diff line change
Expand Up @@ -221,6 +221,19 @@ export const isValidSoftwareInstallStatus = (
): s is SoftwareInstallStatus =>
!!s && SOFTWARE_INSTALL_STATUSES.includes(s as SoftwareInstallStatus);

export const SOFTWARE_AGGREGATE_STATUSES = [
"installed",
"pending",
"failed",
] as const;

export type SoftwareAggregateStatus = typeof SOFTWARE_AGGREGATE_STATUSES[number];

export const isValidSoftwareAggregateStatus = (
s: string | undefined | null
): s is SoftwareAggregateStatus =>
!!s && SOFTWARE_AGGREGATE_STATUSES.includes(s as SoftwareAggregateStatus);

export const isSoftwareUninstallStatus = (
s: string | undefined | null
): s is SoftwareUninstallStatus =>
Expand Down Expand Up @@ -328,6 +341,14 @@ export const getInstallStatusPredicate = (status: string | undefined) => {
);
};

export const aggregateInstallStatusCounts = (
packageStatuses: ISoftwarePackage["status"]
) => ({
installed: packageStatuses.installed,
pending: packageStatuses.pending_install + packageStatuses.pending_uninstall,
failed: packageStatuses.failed_install + packageStatuses.failed_uninstall,
});

export const INSTALL_STATUS_ICONS: Record<
SoftwareInstallStatus | "pending" | "failed",
IconNames
Expand Down
Original file line number Diff line number Diff line change
@@ -1,16 +1,11 @@
import {
IAppStoreApp,
ISoftwarePackage,
ISoftwareTitleDetails,
isSoftwarePackage,
aggregateInstallStatusCounts,
} from "interfaces/software";
import { DEFAULT_EMPTY_CELL_VALUE } from "utilities/constants";

const mergePackageStatuses = (packageStatuses: ISoftwarePackage["status"]) => ({
installed: packageStatuses.installed,
pending: packageStatuses.pending_install + packageStatuses.pending_uninstall,
failed: packageStatuses.failed_install + packageStatuses.failed_uninstall,
});
/**
* Generates the data needed to render the package card.
*/
Expand All @@ -31,7 +26,7 @@ export const getPackageCardInfo = (softwareTitle: ISoftwareTitleDetails) => {
: packageData.latest_version) || DEFAULT_EMPTY_CELL_VALUE,
uploadedAt: isSoftwarePackage(packageData) ? packageData.uploaded_at : "",
status: isSoftwarePackage(packageData)
? mergePackageStatuses(packageData.status)
? aggregateInstallStatusCounts(packageData.status)
: packageData.status,
isSelfService: packageData.self_service,
};
Expand Down
16 changes: 10 additions & 6 deletions frontend/pages/hosts/ManageHostsPage/ManageHostsPage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -51,8 +51,8 @@ import { ILabel } from "interfaces/label";
import { IOperatingSystemVersion } from "interfaces/operating_system";
import { IPolicy, IStoredPolicyResponse } from "interfaces/policy";
import {
isValidSoftwareInstallStatus,
SoftwareInstallStatus,
isValidSoftwareAggregateStatus,
SoftwareAggregateStatus,
} from "interfaces/software";
import { ITeam } from "interfaces/team";
import { IEmptyTableProps } from "interfaces/empty_table";
Expand Down Expand Up @@ -170,6 +170,7 @@ const ManageHostsPage = ({
includeNoTeam: true,
overrideParamsOnTeamChange: {
// remove the software status filter when selecting all teams
// TODO - update if supporting 'No teams' for this filter
[HOSTS_QUERY_PARAMS.SOFTWARE_STATUS]: (newTeamId?: number) => !newTeamId,
},
});
Expand Down Expand Up @@ -242,10 +243,12 @@ const ManageHostsPage = ({
queryParams?.software_title_id !== undefined
? parseInt(queryParams.software_title_id, 10)
: undefined;
const softwareStatus = isValidSoftwareInstallStatus(
const softwareStatus = isValidSoftwareAggregateStatus(
queryParams?.[HOSTS_QUERY_PARAMS.SOFTWARE_STATUS]
)
? (queryParams[HOSTS_QUERY_PARAMS.SOFTWARE_STATUS] as SoftwareInstallStatus)
? (queryParams[
HOSTS_QUERY_PARAMS.SOFTWARE_STATUS
] as SoftwareAggregateStatus)
: undefined;
const status = isAcceptableStatus(queryParams?.status)
? queryParams?.status
Expand Down Expand Up @@ -736,7 +739,7 @@ const ManageHostsPage = ({
};

const handleSoftwareInstallStatausChange = (
newStatus: SoftwareInstallStatus
newStatus: SoftwareAggregateStatus
) => {
handleResetPageIndex();

Expand Down Expand Up @@ -846,7 +849,8 @@ const ManageHostsPage = ({
} else if (softwareTitleId) {
newQueryParams.software_title_id = softwareTitleId;
if (softwareStatus && teamIdForApi && teamIdForApi > 0) {
// software_status is only valid when software_title_id is present and a team is selected
// software_status is only valid when software_title_id is present and a team (other than
// 'No team') is selected
newQueryParams[HOSTS_QUERY_PARAMS.SOFTWARE_STATUS] = softwareStatus;
}
} else if (mdmId) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ import {
} from "interfaces/mdm";
import { IMunkiIssuesAggregate } from "interfaces/macadmins";
import { IPolicy } from "interfaces/policy";
import { SoftwareInstallStatus } from "interfaces/software";
import { SoftwareAggregateStatus } from "interfaces/software";

import {
HOSTS_QUERY_PARAMS,
Expand Down Expand Up @@ -72,7 +72,7 @@ interface IHostsFilterBlockProps {
osSettingsStatus?: MdmProfileStatus;
diskEncryptionStatus?: DiskEncryptionStatus;
bootstrapPackageStatus?: BootstrapPackageStatus;
softwareStatus?: SoftwareInstallStatus;
softwareStatus?: SoftwareAggregateStatus;
};
selectedLabel?: ILabel;
isOnlyObserver?: boolean;
Expand All @@ -88,7 +88,7 @@ interface IHostsFilterBlockProps {
newMacSettingsStatus: MacSettingsStatusQueryParam
) => void;
onChangeSoftwareInstallStatusFilter: (
newStatus: SoftwareInstallStatus
newStatus: SoftwareAggregateStatus
) => void;
onClickEditLabel: (evt: React.MouseEvent<HTMLButtonElement>) => void;
onClickDeleteLabel: () => void;
Expand Down
8 changes: 4 additions & 4 deletions frontend/services/entities/hosts.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import {
import {
IHostSoftware,
ISoftware,
SoftwareInstallStatus,
SoftwareAggregateStatus,
} from "interfaces/software";
import {
DiskEncryptionStatus,
Expand Down Expand Up @@ -72,7 +72,7 @@ export interface ILoadHostsOptions {
softwareId?: number;
softwareTitleId?: number;
softwareVersionId?: number;
softwareStatus?: SoftwareInstallStatus;
softwareStatus?: SoftwareAggregateStatus;
status?: HostStatus;
mdmId?: number;
mdmEnrollmentStatus?: string;
Expand Down Expand Up @@ -103,7 +103,7 @@ export interface IExportHostsOptions {
softwareId?: number;
softwareTitleId?: number;
softwareVersionId?: number;
softwareStatus?: SoftwareInstallStatus;
softwareStatus?: SoftwareAggregateStatus;
status?: HostStatus;
mdmId?: number;
munkiIssueId?: number;
Expand Down Expand Up @@ -133,7 +133,7 @@ export interface IActionByFilter {
softwareId?: number | null;
softwareTitleId?: number | null;
softwareVersionId?: number | null;
softwareStatus?: SoftwareInstallStatus;
softwareStatus?: SoftwareAggregateStatus;
osName?: string;
osVersion?: string;
osVersionId?: number | null;
Expand Down
5 changes: 3 additions & 2 deletions frontend/utilities/url/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import {
HOSTS_QUERY_PARAMS,
MacSettingsStatusQueryParam,
} from "services/entities/hosts";
import { isValidSoftwareInstallStatus } from "interfaces/software";
import { isValidSoftwareAggregateStatus } from "interfaces/software";

export type QueryValues = string | number | boolean | undefined | null;
export type QueryParams = Record<string, QueryValues>;
Expand Down Expand Up @@ -119,8 +119,9 @@ export const reconcileSoftwareParams = ({
| "softwareStatus"
>) => {
if (
isValidSoftwareInstallStatus(softwareStatus) &&
isValidSoftwareAggregateStatus(softwareStatus) &&
softwareTitleId &&
// TODO - update if supporting 'No team' for software status filter
teamId &&
teamId > 0
) {
Expand Down

0 comments on commit c0ac242

Please sign in to comment.