diff --git a/frontend/pages/hosts/ManageHostsPage/ManageHostsPage.tsx b/frontend/pages/hosts/ManageHostsPage/ManageHostsPage.tsx index de90f3334c..079dafc640 100644 --- a/frontend/pages/hosts/ManageHostsPage/ManageHostsPage.tsx +++ b/frontend/pages/hosts/ManageHostsPage/ManageHostsPage.tsx @@ -282,7 +282,7 @@ const ManageHostsPage = ({ ? parseInt(queryParams?.mdm_id, 10) : undefined; const mdmEnrollmentStatus = queryParams?.mdm_enrollment_status; - const { os_id, os_name, os_version } = queryParams; + const { os_id: osId, os_name: osName, os_version: osVersion } = queryParams; const { active_label: activeLabel, label_id: labelID } = routeParams; // ===== filter matching @@ -549,9 +549,9 @@ const ManageHostsPage = ({ softwareId, mdmId, mdmEnrollmentStatus, - os_id, - os_name, - os_version, + osId, + osName, + osVersion, page: tableQueryData ? tableQueryData.pageIndex : 0, perPage: tableQueryData ? tableQueryData.pageSize : 100, device_mapping: true, @@ -863,15 +863,15 @@ const ManageHostsPage = ({ } if ( - (os_id || (os_name && os_version)) && + (osId || (osName && osVersion)) && !softwareId && !policyId && !mdmEnrollmentStatus && !mdmId ) { - newQueryParams.os_id = os_id; - newQueryParams.os_name = os_name; - newQueryParams.os_version = os_version; + newQueryParams.os_id = osId; + newQueryParams.os_name = osName; + newQueryParams.os_version = osVersion; } router.replace( getNextLocationPath({ @@ -893,9 +893,9 @@ const ManageHostsPage = ({ softwareId, mdmId, mdmEnrollmentStatus, - os_id, - os_name, - os_version, + osId, + osName, + osVersion, sortBy, ] ); @@ -1189,9 +1189,9 @@ const ManageHostsPage = ({ softwareId, mdmId, mdmEnrollmentStatus, - os_id, - os_name, - os_version, + osId, + osName, + osVersion, }); toggleTransferHostModal(); @@ -1243,9 +1243,9 @@ const ManageHostsPage = ({ softwareId, mdmId, mdmEnrollmentStatus, - os_id, - os_name, - os_version, + osId, + osName, + osVersion, }); refetchLabels(); @@ -1308,14 +1308,14 @@ const ManageHostsPage = ({ }; const renderOSFilterBlock = () => { - if (!os_id && !(os_name && os_version)) return null; + if (!osId && !(osName && osVersion)) return null; let os: IOperatingSystemVersion | undefined; - if (os_id) { - os = osVersions?.find((v) => v.os_id === os_id); - } else if (os_name && os_version) { - const name: string = os_name; - const vers: string = os_version; + if (osId) { + os = osVersions?.find((v) => v.os_id === osId); + } else if (osName && osVersion) { + const name: string = osName; + const vers: string = osVersion; os = osVersions?.find( ({ name_only, version }) => @@ -1621,9 +1621,9 @@ const ManageHostsPage = ({ softwareId, mdmId, mdmEnrollmentStatus, - os_id, - os_name, - os_version, + os_id: osId, + os_name: osName, + os_version: osVersion, visibleColumns, }; @@ -1697,8 +1697,8 @@ const ManageHostsPage = ({ showSelectedLabel || mdmId || mdmEnrollmentStatus || - os_id || - (os_name && os_version) + osId || + (osName && osVersion) ) { return (
@@ -1727,7 +1727,7 @@ const ManageHostsPage = ({ !mdmId && !showSelectedLabel && renderMDMEnrollmentFilterBlock()} - {(!!os_id || (!!os_name && !!os_version)) && + {(!!osId || (!!osName && !!osVersion)) && !policyId && !softwareId && !showSelectedLabel && @@ -1834,9 +1834,9 @@ const ManageHostsPage = ({ policy_id || mdm_id || mdm_enrollment_status || - os_id || - os_name || - os_version + osId || + osName || + osVersion ); return ( diff --git a/frontend/services/entities/host_count.ts b/frontend/services/entities/host_count.ts index 1b95207bb9..3d3ad5a46d 100644 --- a/frontend/services/entities/host_count.ts +++ b/frontend/services/entities/host_count.ts @@ -1,6 +1,12 @@ /* eslint-disable @typescript-eslint/explicit-module-boundary-types */ import sendRequest from "services"; import endpoints from "utilities/endpoints"; +import { + buildQueryStringFromParams, + getLabelParam, + reconcileMutuallyExclusiveHostParams, + getStatusParam, +} from "utilities/url"; export interface ISortOption { key: string; @@ -25,77 +31,35 @@ export interface IHostCountLoadOptions { } export default { - // hostCount.load share similar variables and parameters with hosts.loadAll load: (options: IHostCountLoadOptions | undefined) => { - const { HOSTS_COUNT } = endpoints; - const globalFilter = options?.globalFilter || ""; - const teamId = options?.teamId || null; - const policyId = options?.policyId || null; - const policyResponse = options?.policyResponse || null; const selectedLabels = options?.selectedLabels || []; - const softwareId = options?.softwareId || null; - const mdmId = options?.mdmId || null; - const mdmEnrollmentStatus = options?.mdmEnrollmentStatus || null; - const { os_id, os_name, os_version } = options || {}; + const policyId = options?.policyId; + const policyResponse = options?.policyResponse; + const globalFilter = options?.globalFilter || ""; + const teamId = options?.teamId; + const softwareId = options?.softwareId; + const mdmId = options?.mdmId; + const mdmEnrollmentStatus = options?.mdmEnrollmentStatus; + const label = getLabelParam(selectedLabels); - const labelPrefix = "labels/"; + const queryParams = { + query: globalFilter, + team_id: teamId, + ...reconcileMutuallyExclusiveHostParams( + label, + policyId, + policyResponse, + mdmId, + mdmEnrollmentStatus, + softwareId + ), + status: getStatusParam(selectedLabels), + label_id: label, + }; - // Handle multiple filters - const label = selectedLabels.find((f) => f.includes(labelPrefix)); - const status = selectedLabels.find((f) => !f.includes(labelPrefix)); - const isValidStatus = - status === "new" || status === "online" || status === "offline"; - let queryString = ""; - - if (globalFilter !== "") { - queryString += `&query=${globalFilter}`; - } - - if (status && isValidStatus) { - queryString += `&status=${status}`; - } - - if (label) { - queryString += `&label_id=${parseInt( - label.substr(labelPrefix.length), - 10 - )}`; - } - - if (teamId) { - queryString += `&team_id=${teamId}`; - } - - if (!label && policyId) { - queryString += `&policy_id=${policyId}`; - queryString += `&policy_response=${policyResponse || "passing"}`; // TODO confirm whether there should be a default if there is an id but no response specified - } - - // TODO: consider how to check for mutually exclusive scenarios with label, policy and software - if (!label && !policyId && softwareId) { - queryString += `&software_id=${softwareId}`; - } - - if (!label && !policyId && mdmId) { - queryString += `&mdm_id=${mdmId}`; - } - - if (!label && !policyId && mdmEnrollmentStatus) { - queryString += `&mdm_enrollment_status=${mdmEnrollmentStatus}`; - } - - if (!label && !policyId && !softwareId && !mdmId && !mdmEnrollmentStatus) { - if (os_id) { - queryString += `&os_id=${os_id}`; - } else if (os_name && os_version) { - queryString += `&os_name=${encodeURIComponent( - os_name - )}&os_version=${encodeURIComponent(os_version)}`; - } - } - - // Append query string to endpoint route after slicing off the leading ampersand - const path = `${HOSTS_COUNT}${queryString && `?${queryString.slice(1)}`}`; + const queryString = buildQueryStringFromParams(queryParams); + const endpoint = endpoints.HOSTS_COUNT; + const path = `${endpoint}?${queryString}`; return sendRequest("GET", path); }, diff --git a/frontend/services/entities/hosts.ts b/frontend/services/entities/hosts.ts index 9b6f67bf69..3b7571adba 100644 --- a/frontend/services/entities/hosts.ts +++ b/frontend/services/entities/hosts.ts @@ -2,7 +2,12 @@ import sendRequest from "services"; import endpoints from "utilities/endpoints"; import { IHost } from "interfaces/host"; -import { buildQueryStringFromParams } from "utilities/url"; +import { + buildQueryStringFromParams, + getLabelParam, + reconcileMutuallyExclusiveHostParams, + getStatusParam, +} from "utilities/url"; export interface ISortOption { key: string; @@ -21,9 +26,9 @@ export interface ILoadHostsOptions { softwareId?: number; mdmId?: number; mdmEnrollmentStatus?: string; - os_id?: number; - os_name?: string; - os_version?: string; + osId?: number; + osName?: string; + osVersion?: string; device_mapping?: boolean; columns?: string; visibleColumns?: string; @@ -41,9 +46,9 @@ export interface IExportHostsOptions { softwareId?: number; mdmId?: number; mdmEnrollmentStatus?: string; - os_id?: number; - os_name?: string; - os_version?: string; + osId?: number; + osName?: string; + osVersion?: string; device_mapping?: boolean; columns?: string; visibleColumns?: string; @@ -60,7 +65,7 @@ const getLabel = (selectedLabels?: string[]) => { const getHostEndpoint = (selectedLabels?: string[]) => { const { HOSTS, LABEL_HOSTS } = endpoints; - if (selectedLabels === undefined) return endpoints.HOSTS; + if (selectedLabels === undefined) return HOSTS; const label = getLabel(selectedLabels); if (label) { @@ -83,84 +88,6 @@ const getSortParams = (sortOptions?: ISortOption[]) => { }; }; -const getStatusParam = (selectedLabels?: string[]) => { - if (selectedLabels === undefined) return undefined; - - const status = selectedLabels.find((f) => !f.includes(LABEL_PREFIX)); - if (status === undefined) return undefined; - - const statusFilterList = ["new", "online", "offline"]; - return statusFilterList.includes(status) ? status : undefined; -}; - -const getPolicyParams = ( - label?: string, - policyId?: number, - policyResponse?: string -) => { - if (label !== undefined || policyId === undefined) return {}; - - return { - policy_id: policyId, - policy_response: policyResponse, - }; -}; - -const getSoftwareParam = ( - label?: string, - policyId?: number, - softwareId?: number, - mdmId?: number, - mdmEnrollmentStatus?: string -) => { - return !label && !policyId && !mdmId && !mdmEnrollmentStatus - ? softwareId - : undefined; -}; - -const getMDMSolutionParam = ( - label?: string, - policyId?: number, - softwareId?: number, - mdmId?: number, - mdmEnrollmentStatus?: string -) => { - return !label && !policyId && !softwareId && !mdmEnrollmentStatus - ? mdmId - : undefined; -}; - -const getMDMEnrollmentStatusParam = ( - label?: string, - policyId?: number, - softwareId?: number, - mdmId?: number, - mdmEnrollmentStatus?: string -) => { - return !label && !policyId && !softwareId && !mdmId - ? mdmEnrollmentStatus - : undefined; -}; - -const getOperatingSystemParams = ( - label?: string, - policyId?: number, - softwareId?: number, - mdmId?: number, - mdmEnrollmentStatus?: string, - os_id?: number, - os_name?: string, - os_version?: string -) => { - if (label || policyId || softwareId || mdmId || mdmEnrollmentStatus) { - return {}; - } - if (os_id) { - return { os_id }; - } - return os_name && os_version ? { os_name, os_version } : {}; -}; - export default { destroy: (host: IHost) => { const { HOSTS } = endpoints; @@ -190,85 +117,44 @@ export default { }); }, exportHosts: (options: IExportHostsOptions) => { - const { HOSTS_REPORT } = endpoints; const sortBy = options.sortBy; const selectedLabels = options?.selectedLabels || []; const globalFilter = options?.globalFilter || ""; - const teamId = options?.teamId || null; - const policyId = options?.policyId || null; + const teamId = options?.teamId; + const policyId = options?.policyId; const policyResponse = options?.policyResponse || "passing"; - const softwareId = options?.softwareId || null; - const mdmId = options?.mdmId || null; - const mdmEnrollmentStatus = options?.mdmEnrollmentStatus || null; - const visibleColumns = options?.visibleColumns || null; - const { os_id, os_name, os_version } = options; + const softwareId = options?.softwareId; + const mdmId = options?.mdmId; + const mdmEnrollmentStatus = options?.mdmEnrollmentStatus; + const visibleColumns = options?.visibleColumns; + const label = getLabelParam(selectedLabels); if (!sortBy.length) { throw Error("sortBy is a required field."); } - const orderKeyParam = `?order_key=${sortBy[0].key}`; - const orderDirection = `&order_direction=${sortBy[0].direction}`; + const queryParams = { + order_key: sortBy[0].key, + order_direction: sortBy[0].direction, + query: globalFilter, + team_id: teamId, + ...reconcileMutuallyExclusiveHostParams( + label, + policyId, + policyResponse, + mdmId, + mdmEnrollmentStatus, + softwareId + ), + status: getStatusParam(selectedLabels), + label_id: label, + columns: visibleColumns, + format: "csv", + }; - let path = `${HOSTS_REPORT}${orderKeyParam}${orderDirection}`; - - if (globalFilter !== "") { - path += `&query=${globalFilter}`; - } - const labelPrefix = "labels/"; - - // Handle multiple filters - const label = selectedLabels.find((f) => f.includes(labelPrefix)) || ""; - const status = selectedLabels.find((f) => !f.includes(labelPrefix)) || ""; - const statusFilterList = ["new", "online", "offline"]; - const isStatusFilter = statusFilterList.includes(status); - - if (isStatusFilter) { - path += `&status=${status}`; - } - - if (teamId) { - path += `&team_id=${teamId}`; - } - - // label OR policy_id OR software_id OR mdm_id OR mdm_enrollment_status are valid filters. - if (label) { - const lid = label.substr(labelPrefix.length); - path += `&label_id=${parseInt(lid, 10)}`; - } - - if (!label && policyId) { - path += `&policy_id=${policyId}`; - path += `&policy_response=${policyResponse}`; - } - - if (!label && !policyId && !mdmId && !mdmEnrollmentStatus && softwareId) { - path += `&software_id=${softwareId}`; - } - - if (!label && !policyId && !softwareId && !mdmEnrollmentStatus && mdmId) { - path += `&mdm_id=${mdmId}`; - } - - if (!label && !policyId && !softwareId && !mdmId && mdmEnrollmentStatus) { - path += `&mdm_enrollment_status=${mdmEnrollmentStatus}`; - } - - if (!label && !policyId && !softwareId && !mdmId && !mdmEnrollmentStatus) { - if (os_id) { - path += `&os_id=${os_id}`; - } else if (os_name && os_version) { - path += `&os_name=${encodeURIComponent( - os_name - )}&os_version=${encodeURIComponent(os_version)}`; - } - } - - if (visibleColumns) { - path += `&columns=${visibleColumns}`; - } - - path += "&format=csv"; + const queryString = buildQueryStringFromParams(queryParams); + const endpoint = endpoints.HOSTS_REPORT; + const path = `${endpoint}?${queryString}`; return sendRequest("GET", path); }, @@ -282,16 +168,15 @@ export default { softwareId, mdmId, mdmEnrollmentStatus, - os_id, - os_name, - os_version, + osId, + osName, + osVersion, device_mapping, selectedLabels, sortBy, }: ILoadHostsOptions) => { const label = getLabel(selectedLabels); const sortParams = getSortParams(sortBy); - const policyParams = getPolicyParams(label, policyId, policyResponse); const queryParams = { page, @@ -301,34 +186,17 @@ export default { device_mapping, order_key: sortParams.order_key, order_direction: sortParams.order_direction, - policy_id: policyParams.policy_id, - policy_response: policyParams.policy_response, - software_id: getSoftwareParam(label, policyId, softwareId), - mdm_id: getMDMSolutionParam( + ...reconcileMutuallyExclusiveHostParams( label, policyId, - softwareId, - mdmId, - mdmEnrollmentStatus - ), - mdm_enrollment_status: getMDMEnrollmentStatusParam( - label, - policyId, - softwareId, - mdmId, - mdmEnrollmentStatus - ), - ...getOperatingSystemParams( - label, - policyId, - softwareId, + policyResponse, mdmId, mdmEnrollmentStatus, - os_id, - os_name, - os_version + softwareId, + osId, + osName, + osVersion ), - status: getStatusParam(selectedLabels), }; diff --git a/frontend/utilities/url/index.ts b/frontend/utilities/url/index.ts index c6edfac76f..cbcfdd28b6 100644 --- a/frontend/utilities/url/index.ts +++ b/frontend/utilities/url/index.ts @@ -39,3 +39,54 @@ export const buildQueryStringFromParams = (queryParams: QueryParams) => { } return queryString; }; + +export const reconcileMutuallyExclusiveHostParams = ( + label?: string, + policyId?: number, + policyResponse?: string, + mdmId?: number, + mdmEnrollmentStatus?: string, + softwareId?: number, + osId?: number, + osName?: string, + osVersion?: string +): Record => { + if (label) { + return {}; + } + switch (true) { + case !!policyId: + return { policy_id: policyId, policy_response: policyResponse }; + case !!mdmId: + return { mdm_id: mdmId, mdm_status: mdmEnrollmentStatus }; + case !!softwareId: + return { software_id: softwareId }; + case !!osId: + return { os_id: osId }; + case !!osName && !!osVersion: + return { os_name: osName, os_version: osVersion }; + default: + return {}; + } +}; + +const LABEL_PREFIX = "labels/"; + +export const getStatusParam = (selectedLabels?: string[]) => { + if (selectedLabels === undefined) return undefined; + + const status = selectedLabels.find((f) => !f.includes(LABEL_PREFIX)); + if (status === undefined) return undefined; + + const statusFilterList = ["new", "online", "offline"]; + return statusFilterList.includes(status) ? status : undefined; +}; + +export const getLabelParam = (selectedLabels?: string[]) => { + if (selectedLabels === undefined) return undefined; + + const label = selectedLabels.find((f) => f.includes(LABEL_PREFIX)); + if (label === undefined) return undefined; + + return label.slice(7); +};