diff --git a/changes/issue-2380-host-details-failing-policies b/changes/issue-2380-host-details-failing-policies new file mode 100644 index 0000000000..aaa44f4aa6 --- /dev/null +++ b/changes/issue-2380-host-details-failing-policies @@ -0,0 +1 @@ +* Host details page renders total issues if present and policies modal with query description and resolution \ No newline at end of file diff --git a/frontend/interfaces/host_policy.ts b/frontend/interfaces/host_policy.ts index 57ddebbad8..d29b3f7a2a 100644 --- a/frontend/interfaces/host_policy.ts +++ b/frontend/interfaces/host_policy.ts @@ -1,15 +1,19 @@ import PropTypes from "prop-types"; export default PropTypes.shape({ - id: PropTypes.number, + id: PropTypes.number.isRequired, query_id: PropTypes.number, - query_name: PropTypes.string, + query_name: PropTypes.string.isRequired, + query_description: PropTypes.string, response: PropTypes.string, + resolution: PropTypes.string, }); export interface IHostPolicy { id: number; query_id: number; query_name: string; + query_description?: string; response: string; + resolution?: string; } diff --git a/frontend/pages/hosts/HostDetailsPage/HostDetailsPage.tsx b/frontend/pages/hosts/HostDetailsPage/HostDetailsPage.tsx index 83ee4c33de..edbe3145b1 100644 --- a/frontend/pages/hosts/HostDetailsPage/HostDetailsPage.tsx +++ b/frontend/pages/hosts/HostDetailsPage/HostDetailsPage.tsx @@ -65,6 +65,7 @@ import BackChevron from "../../../../assets/images/icon-chevron-down-9x6@2x.png" import DeleteIcon from "../../../../assets/images/icon-action-delete-14x14@2x.png"; import TransferIcon from "../../../../assets/images/icon-action-transfer-16x16@2x.png"; import QueryIcon from "../../../../assets/images/icon-action-query-16x16@2x.png"; +import IssueIcon from "../../../../assets/images/icon-issue-fleet-black-50-16x16@2x.png"; const baseClass = "host-details"; @@ -107,11 +108,25 @@ const HostDetailsPage = ({ false ); const [showQueryHostModal, setShowQueryHostModal] = useState(false); - const [showPolicyDetailsModal, setPolicyDetailsModal] = useState(false); + const [showPolicyDetailsModal, setPolicyDetailsModal] = useState( + false + ); + const [selectedPolicy, setSelectedPolicy] = useState( + null + ); - const togglePolicyDetailsModal = useCallback(() => { + const togglePolicyDetailsModal = useCallback( + (policy: IHostPolicy) => { + setPolicyDetailsModal(!showPolicyDetailsModal); + setSelectedPolicy(policy); + }, + [showPolicyDetailsModal, setPolicyDetailsModal, setSelectedPolicy] + ); + + const onCancelPolicyDetailsModal = useCallback(() => { setPolicyDetailsModal(!showPolicyDetailsModal); - }, [showPolicyDetailsModal, setPolicyDetailsModal]); + setSelectedPolicy(null); + }, [showPolicyDetailsModal, setPolicyDetailsModal, setSelectedPolicy]); const [refetchStartTime, setRefetchStartTime] = useState(null); const [ @@ -276,6 +291,7 @@ const HostDetailsPage = ({ const titleData = normalizeEmptyValues( pick(host, [ "status", + "issues", "memory", "cpu_type", "os_version", @@ -741,6 +757,37 @@ const HostDetailsPage = ({ ); }; + const renderIssues = () => ( +
+ Issues + + + host issue + + + + Failing policies ({host?.issues.failing_policies_count}) + + + + {host?.issues.total_issues_count} + + +
+ ); + const renderHostTeam = () => (
Team @@ -879,6 +926,7 @@ const HostDetailsPage = ({ {titleData.status}
+ {titleData.issues.total_issues_count > 0 && renderIssues()} {isPremiumTier && renderHostTeam()} {renderDeviceUser()}
@@ -987,7 +1035,10 @@ const HostDetailsPage = ({ /> )} {!!host && showPolicyDetailsModal && ( - + )}
); diff --git a/frontend/pages/hosts/HostDetailsPage/HostPoliciesTable/HostPoliciesTableConfig.tsx b/frontend/pages/hosts/HostDetailsPage/HostPoliciesTable/HostPoliciesTableConfig.tsx index 25463555d1..b8f07bf6de 100644 --- a/frontend/pages/hosts/HostDetailsPage/HostPoliciesTable/HostPoliciesTableConfig.tsx +++ b/frontend/pages/hosts/HostDetailsPage/HostPoliciesTable/HostPoliciesTableConfig.tsx @@ -52,7 +52,7 @@ const getPolicyStatus = (policy: IHostPolicy): string => { // NOTE: cellProps come from react-table // more info here https://react-table.tanstack.com/docs/api/useTable#cell-properties const generatePolicyTableHeaders = ( - togglePolicyDetails: () => void + togglePolicyDetails: (policy: IHostPolicy) => void ): IDataColumn[] => { return [ { @@ -64,7 +64,12 @@ const generatePolicyTableHeaders = ( const { query_name } = cellProps.row.original; return ( <> - diff --git a/frontend/pages/hosts/HostDetailsPage/HostPoliciesTable/PolicyDetailsModal/_styles.scss b/frontend/pages/hosts/HostDetailsPage/HostPoliciesTable/PolicyDetailsModal/_styles.scss index 480f21b1a8..8b028d5f82 100644 --- a/frontend/pages/hosts/HostDetailsPage/HostPoliciesTable/PolicyDetailsModal/_styles.scss +++ b/frontend/pages/hosts/HostDetailsPage/HostPoliciesTable/PolicyDetailsModal/_styles.scss @@ -1,8 +1,18 @@ .policy-details-modal { + &__resolution { + p { + margin-top: $pad-xsmall; + } + } + + &__resolve-header { + font-weight: $bold; + } + &__btn-wrap { display: flex; flex-direction: row-reverse; - margin-top: $pad-xxlarge; + margin-top: $pad-large; } &__btn { diff --git a/frontend/pages/hosts/HostDetailsPage/_styles.scss b/frontend/pages/hosts/HostDetailsPage/_styles.scss index 75537ce8e9..efa18b39be 100644 --- a/frontend/pages/hosts/HostDetailsPage/_styles.scss +++ b/frontend/pages/hosts/HostDetailsPage/_styles.scss @@ -42,10 +42,20 @@ &--title { margin-right: $pad-xxlarge; - .info__data { + .info-flex__data { white-space: nowrap; overflow: hidden; text-overflow: ellipsis; + + img { + width: 16px; + height: 16px; + vertical-align: sub; + } + + .total-issues-count { + margin-left: $pad-small; + } } } }