(
+ ["config-profile", configProfileUUID],
+ () => configProfileAPI.getConfigProfile(configProfileUUID),
+ {
+ enabled: isRouteOk && !!configProfileUUID,
+ // select: (data) => data.policy,
+ }
+ );
+
const { data: osVersions } = useQuery<
IOSVersionsResponse,
Error,
@@ -422,6 +440,8 @@ const ManageHostsPage = ({
diskEncryptionStatus,
bootstrapPackageStatus,
macSettingsStatus,
+ configProfileStatus,
+ configProfileUUID,
},
],
({ queryKey }) => hostsAPI.loadHosts(queryKey[0]),
@@ -463,6 +483,8 @@ const ManageHostsPage = ({
diskEncryptionStatus,
bootstrapPackageStatus,
macSettingsStatus,
+ configProfileStatus,
+ configProfileUUID,
},
],
({ queryKey }) => hostCountAPI.load(queryKey[0]),
@@ -502,7 +524,8 @@ const ManageHostsPage = ({
refetchHostsCountAPI();
};
- const hasErrors = !!errorHosts || !!errorHostsCount || !!errorPolicy;
+ const hasErrors =
+ !!errorHosts || !!errorHostsCount || !!errorPolicy || !!errorConfigProfile;
const toggleDeleteSecretModal = () => {
// open and closes delete modal
@@ -757,6 +780,22 @@ const ManageHostsPage = ({
);
};
+ const handleConfigProfileStatusChange = (newStatus: string) => {
+ router.replace(
+ getNextLocationPath({
+ pathPrefix: PATHS.MANAGE_HOSTS,
+ routeTemplate,
+ routeParams,
+ queryParams: {
+ ...queryParams,
+ profile_status: newStatus,
+ profile_uuid: configProfileUUID,
+ page: 0, // resets page index
+ },
+ })
+ );
+ };
+
const handleRowSelect = (row: IRowProps) => {
if (row.original.id) {
const path = PATHS.HOST_DETAILS(row.original.id);
@@ -894,6 +933,9 @@ const ManageHostsPage = ({
newQueryParams[PARAMS.DISK_ENCRYPTION] = diskEncryptionStatus;
} else if (bootstrapPackageStatus && isPremiumTier) {
newQueryParams.bootstrap_package = bootstrapPackageStatus;
+ } else if (configProfileStatus && configProfileUUID) {
+ newQueryParams.profile_status = configProfileStatus;
+ newQueryParams.profile_uuid = configProfileUUID;
}
router.replace(
@@ -918,7 +960,6 @@ const ManageHostsPage = ({
softwareId,
softwareVersionId,
softwareTitleId,
- softwareStatus,
mdmId,
mdmEnrollmentStatus,
munkiIssueId,
@@ -928,13 +969,16 @@ const ManageHostsPage = ({
osVersionId,
osName,
osVersion,
- router,
- routeTemplate,
- routeParams,
+ vulnerability,
osSettingsStatus,
diskEncryptionStatus,
bootstrapPackageStatus,
- vulnerability,
+ configProfileStatus,
+ configProfileUUID,
+ router,
+ routeTemplate,
+ routeParams,
+ softwareStatus,
]
);
@@ -1610,7 +1654,12 @@ const ManageHostsPage = ({
resultsTitle="hosts"
columnConfigs={tableColumns}
data={hostsData?.hosts || []}
- isLoading={isLoadingHosts || isLoadingHostsCount || isLoadingPolicy}
+ isLoading={
+ isLoadingHosts ||
+ isLoadingHostsCount ||
+ isLoadingPolicy ||
+ isLoadingConfigProfile
+ }
manualSortBy
defaultSortHeader={(sortBy[0] && sortBy[0].key) || DEFAULT_SORT_HEADER}
defaultSortDirection={
@@ -1746,6 +1795,9 @@ const ManageHostsPage = ({
diskEncryptionStatus,
bootstrapPackageStatus,
vulnerability,
+ configProfileStatus,
+ configProfileUUID,
+ configProfile,
}}
selectedLabel={selectedLabel}
isOnlyObserver={isOnlyObserver}
@@ -1763,6 +1815,7 @@ const ManageHostsPage = ({
onChangeSoftwareInstallStatusFilter={
handleSoftwareInstallStatusChange
}
+ onChangeConfigProfileStatusFilter={handleConfigProfileStatusChange}
onClickEditLabel={onEditLabelClick}
onClickDeleteLabel={toggleDeleteLabelModal}
/>
diff --git a/frontend/pages/hosts/ManageHostsPage/components/FilterPill/FilterPill.tsx b/frontend/pages/hosts/ManageHostsPage/components/FilterPill/FilterPill.tsx
index 03e0f05920..0a5b2921fd 100644
--- a/frontend/pages/hosts/ManageHostsPage/components/FilterPill/FilterPill.tsx
+++ b/frontend/pages/hosts/ManageHostsPage/components/FilterPill/FilterPill.tsx
@@ -1,12 +1,13 @@
-import React, { ReactNode } from "react";
+import React, { ReactNode, useRef } from "react";
import ReactTooltip from "react-tooltip";
import classnames from "classnames";
-import Button from "components/buttons/Button";
+import { useCheckTruncatedElement } from "hooks/useCheckTruncatedElement";
+import { COLORS } from "styles/var/colors";
+import Button from "components/buttons/Button";
import Icon from "components/Icon";
import { IconNames } from "components/icons";
-import { COLORS } from "styles/var/colors";
interface IFilterPillProps {
label: string;
@@ -30,6 +31,9 @@ const FilterPill = ({
tooltip: tooltipDescription !== undefined && tooltipDescription !== "",
});
+ const pillText = useRef(null);
+ const isTuncated = useCheckTruncatedElement(pillText);
+
return (
{label}
@@ -59,11 +65,12 @@ const FilterPill = ({
{tooltipDescription && (
{tooltipDescription}
diff --git a/frontend/pages/hosts/ManageHostsPage/components/FilterPill/_styles.scss b/frontend/pages/hosts/ManageHostsPage/components/FilterPill/_styles.scss
index d909bf2642..cffb1cfb45 100644
--- a/frontend/pages/hosts/ManageHostsPage/components/FilterPill/_styles.scss
+++ b/frontend/pages/hosts/ManageHostsPage/components/FilterPill/_styles.scss
@@ -23,4 +23,8 @@
}
}
}
+
+ &__tooltip-text {
+ @include ellipse-text(166px);
+ }
}
diff --git a/frontend/pages/hosts/ManageHostsPage/components/HostsFilterBlock/HostsFilterBlock.tsx b/frontend/pages/hosts/ManageHostsPage/components/HostsFilterBlock/HostsFilterBlock.tsx
index 784e75e4d1..23b7a4ff53 100644
--- a/frontend/pages/hosts/ManageHostsPage/components/HostsFilterBlock/HostsFilterBlock.tsx
+++ b/frontend/pages/hosts/ManageHostsPage/components/HostsFilterBlock/HostsFilterBlock.tsx
@@ -13,6 +13,7 @@ import {
IMdmSolution,
MDM_ENROLLMENT_STATUS,
MdmProfileStatus,
+ IMdmProfile,
} from "interfaces/mdm";
import { IMunkiIssuesAggregate } from "interfaces/macadmins";
import { IPolicy } from "interfaces/policy";
@@ -77,6 +78,9 @@ interface IHostsFilterBlockProps {
diskEncryptionStatus?: DiskEncryptionStatus;
bootstrapPackageStatus?: BootstrapPackageStatus;
softwareStatus?: SoftwareAggregateStatus;
+ configProfileStatus?: string;
+ configProfileUUID?: string;
+ configProfile?: IMdmProfile;
};
selectedLabel?: ILabel;
isOnlyObserver?: boolean;
@@ -94,6 +98,7 @@ interface IHostsFilterBlockProps {
onChangeSoftwareInstallStatusFilter: (
newStatus: SoftwareAggregateStatus
) => void;
+ onChangeConfigProfileStatusFilter: (newStatus: string) => void;
onClickEditLabel: (evt: React.MouseEvent) => void;
onClickDeleteLabel: () => void;
}
@@ -127,6 +132,9 @@ const HostsFilterBlock = ({
diskEncryptionStatus,
bootstrapPackageStatus,
softwareStatus,
+ configProfileStatus,
+ configProfileUUID,
+ configProfile,
},
selectedLabel,
isOnlyObserver,
@@ -138,6 +146,7 @@ const HostsFilterBlock = ({
onChangeBootstrapPackageStatusFilter,
onChangeMacSettingsFilter,
onChangeSoftwareInstallStatusFilter,
+ onChangeConfigProfileStatusFilter,
onClickEditLabel,
onClickDeleteLabel,
}: IHostsFilterBlockProps) => {
@@ -308,19 +317,10 @@ const HostsFilterBlock = ({
clearParams.push(...additionalClearParams);
}
- // const TooltipDescription = (
- //
- // Hosts with {name || "Unknown software"},
- //
- // {version || "version unknown"} installed
- //
- // );
-
return (
handleClearFilter(clearParams)}
- // tooltipDescription={TooltipDescription}
/>
);
};
@@ -511,6 +511,38 @@ const HostsFilterBlock = ({
);
};
+ const renderConfigProfileStatusBlock = () => {
+ const OPTIONS = [
+ { value: "verified", label: "Verified" },
+ { value: "verifying", label: "Verifying" },
+ { value: "pending", label: "Pending" },
+ { value: "failed", label: "Failed" },
+ ];
+ return (
+ <>
+
+ handleClearFilter(["profile_status", "profile_uuid"])}
+ tooltipDescription={
+ <>
+ OS settings:
+
+ {configProfile?.name}
+ >
+ }
+ />
+ >
+ );
+ };
+
const showSelectedLabel = selectedLabel && selectedLabel.type !== "all";
if (
@@ -530,7 +562,8 @@ const HostsFilterBlock = ({
osSettingsStatus ||
diskEncryptionStatus ||
bootstrapPackageStatus ||
- vulnerability
+ vulnerability ||
+ (configProfileStatus && configProfileUUID && configProfile)
) {
const renderFilterPill = () => {
switch (true) {
@@ -583,6 +616,8 @@ const HostsFilterBlock = ({
return renderDiskEncryptionStatusBlock();
case !!bootstrapPackageStatus:
return renderBootstrapPackageStatusBlock();
+ case !!configProfileStatus && !!configProfileUUID && !!configProfile:
+ return renderConfigProfileStatusBlock();
default:
return null;
}
diff --git a/frontend/services/entities/config_profiles.ts b/frontend/services/entities/config_profiles.ts
index 160de6a526..2c76bcfca2 100644
--- a/frontend/services/entities/config_profiles.ts
+++ b/frontend/services/entities/config_profiles.ts
@@ -1,8 +1,9 @@
-import { getConfig } from "@testing-library/react";
-import { profile } from "console";
+import { IMdmProfile } from "interfaces/mdm";
import sendRequest from "services";
import endpoints from "utilities/endpoints";
+export type IGetConfigProfileResponse = IMdmProfile;
+
export interface IGetConfigProfileStatusResponse {
verified: number;
verifying: number;
@@ -11,20 +12,16 @@ export interface IGetConfigProfileStatusResponse {
}
export default {
+ getConfigProfile: (uuid: string): Promise => {
+ const { CONFIG_PROFILE } = endpoints;
+ return sendRequest("GET", CONFIG_PROFILE(uuid));
+ },
+
getConfigProfileStatus: (
uuid: string
): Promise => {
const { CONFIG_PROFILE_STATUS } = endpoints;
- // return sendRequest("GET", CONFIG_PROFILE_STATUS(uuid));
-
- return new Promise((resolve) => {
- resolve({
- verified: 0,
- verifying: 1,
- failed: 2,
- pending: 3,
- });
- });
+ return sendRequest("GET", CONFIG_PROFILE_STATUS(uuid));
},
batchResendConfigProfile: (uuid: string): Promise => {
diff --git a/frontend/services/entities/host_count.ts b/frontend/services/entities/host_count.ts
index e0093e3bdb..9e25eb101f 100644
--- a/frontend/services/entities/host_count.ts
+++ b/frontend/services/entities/host_count.ts
@@ -54,6 +54,8 @@ export interface IHostCountLoadOptions {
vulnerability?: string;
diskEncryptionStatus?: DiskEncryptionStatus;
bootstrapPackageStatus?: BootstrapPackageStatus;
+ configProfileStatus?: string;
+ configProfileUUID?: string;
}
export default {
@@ -83,6 +85,8 @@ export default {
const vulnerability = options?.vulnerability;
const diskEncryptionStatus = options?.diskEncryptionStatus;
const bootstrapPackageStatus = options?.bootstrapPackageStatus;
+ const configProfileStatus = options?.configProfileStatus;
+ const configProfileUUID = options?.configProfileUUID;
const queryParams = {
query: globalFilter,
@@ -113,6 +117,8 @@ export default {
vulnerability,
diskEncryptionStatus,
bootstrapPackageStatus,
+ configProfileStatus,
+ configProfileUUID,
}),
label_id: label,
status,
diff --git a/frontend/services/entities/hosts.ts b/frontend/services/entities/hosts.ts
index 17ddba1f1f..ce8d22070f 100644
--- a/frontend/services/entities/hosts.ts
+++ b/frontend/services/entities/hosts.ts
@@ -90,6 +90,8 @@ export interface ILoadHostsOptions {
osSettings?: MdmProfileStatus;
diskEncryptionStatus?: DiskEncryptionStatus;
bootstrapPackageStatus?: BootstrapPackageStatus;
+ configProfileStatus?: string;
+ configProfileUUID?: string;
}
export interface IExportHostsOptions {
@@ -411,6 +413,8 @@ export default {
osSettings,
diskEncryptionStatus,
bootstrapPackageStatus,
+ configProfileStatus,
+ configProfileUUID,
}: ILoadHostsOptions): Promise => {
const label = getLabel(selectedLabels);
const sortParams = getSortParams(sortBy);
@@ -449,6 +453,8 @@ export default {
diskEncryptionStatus,
osSettings,
bootstrapPackageStatus,
+ configProfileStatus,
+ configProfileUUID,
}),
};
diff --git a/frontend/test/handlers/config-profiles.ts b/frontend/test/handlers/config-profiles.ts
new file mode 100644
index 0000000000..5e21a97318
--- /dev/null
+++ b/frontend/test/handlers/config-profiles.ts
@@ -0,0 +1,24 @@
+import createMockConfig from "__mocks__/configMock";
+import { IConfig } from "interfaces/config";
+import { http, HttpResponse } from "msw";
+import { baseUrl } from "test/test-utils";
+
+const configProfileURL = baseUrl("/configuration_profiles");
+
+export const createGetConfigHandler = (overrides?: Partial) => {
+ return http.get(configProfileURL, () => {
+ return HttpResponse.json(createMockConfig({ ...overrides }));
+ });
+};
+
+export const defaultConfigProfileStatusHandler = http.get(
+ `${configProfileURL}/:uuid/status`,
+ () => {
+ return HttpResponse.json({
+ verified: 0,
+ verifying: 1,
+ pending: 2,
+ failed: 3,
+ });
+ }
+);
diff --git a/frontend/utilities/endpoints.ts b/frontend/utilities/endpoints.ts
index 460de70148..c860895a95 100644
--- a/frontend/utilities/endpoints.ts
+++ b/frontend/utilities/endpoints.ts
@@ -274,6 +274,8 @@ export default {
SCIM_DETAILS: `/${API_VERSION}/fleet/scim/details`,
// configuration profile endpoints
+ CONFIG_PROFILE: (uuid: string) =>
+ `/${API_VERSION}/fleet/configuration_profiles/${uuid}`,
CONFIG_PROFILE_STATUS: (uuid: string) =>
`/${API_VERSION}/fleet/configuration_profiles/${uuid}/status`,
CONFIG_PROFILE_BATCH_RESEND: `/${API_VERSION}/fleet/configuration_profiles/batch/resend`,
diff --git a/frontend/utilities/url/index.ts b/frontend/utilities/url/index.ts
index a3002c84c4..783f7cb2d5 100644
--- a/frontend/utilities/url/index.ts
+++ b/frontend/utilities/url/index.ts
@@ -46,6 +46,8 @@ interface IMutuallyExclusiveHostParams {
osSettings?: MdmProfileStatus;
diskEncryptionStatus?: DiskEncryptionStatus;
bootstrapPackageStatus?: BootstrapPackageStatus;
+ configProfileStatus?: string;
+ configProfileUUID?: string;
}
export const parseQueryValueToNumberOrUndefined = (
@@ -216,6 +218,8 @@ export const reconcileMutuallyExclusiveHostParams = ({
vulnerability,
diskEncryptionStatus,
bootstrapPackageStatus,
+ configProfileStatus,
+ configProfileUUID,
}: IMutuallyExclusiveHostParams): Record => {
if (label) {
// backend api now allows (label + low disk space) OR (label + mdm id) OR
@@ -270,6 +274,11 @@ export const reconcileMutuallyExclusiveHostParams = ({
return { [HOSTS_QUERY_PARAMS.DISK_ENCRYPTION]: diskEncryptionStatus };
case !!bootstrapPackageStatus:
return { bootstrap_package: bootstrapPackageStatus };
+ case !!configProfileUUID:
+ return {
+ profile_status: configProfileStatus,
+ profile_uuid: configProfileUUID,
+ };
default:
return {};
}