diff --git a/changes/42568-host-policy-empty-state b/changes/42568-host-policy-empty-state new file mode 100644 index 0000000000..263c17e975 --- /dev/null +++ b/changes/42568-host-policy-empty-state @@ -0,0 +1 @@ +* Fleet UI: Improve host policy empty state \ No newline at end of file diff --git a/frontend/pages/hosts/details/DeviceUserPage/DeviceUserPage.tsx b/frontend/pages/hosts/details/DeviceUserPage/DeviceUserPage.tsx index 78abefa8f9..fc1b244a8e 100644 --- a/frontend/pages/hosts/details/DeviceUserPage/DeviceUserPage.tsx +++ b/frontend/pages/hosts/details/DeviceUserPage/DeviceUserPage.tsx @@ -850,6 +850,7 @@ const DeviceUserPage = ({ = {} +): IHostPolicy => ({ + id: 1, + name: "Test policy", + query: "SELECT 1;", + description: "", + author_id: 1, + author_name: "Admin", + author_email: "admin@fleet.co", + resolution: "", + platform: "", + team_id: null, + created_at: "2024-01-01T00:00:00Z", + updated_at: "2024-01-01T00:00:00Z", + critical: false, + calendar_events_enabled: false, + conditional_access_enabled: false, + type: "policy", + response: "fail", + ...overrides, +}); + +describe("PolicyDetailsModal", () => { + it("renders policy name, description, and resolution", () => { + renderWithSetup( + + ); + + expect(screen.getByText("Disk encryption enabled")).toBeInTheDocument(); + expect( + screen.getByText("Checks that FileVault is enabled.") + ).toBeInTheDocument(); + expect(screen.getByText("Resolve:")).toBeInTheDocument(); + expect( + screen.getByText("Enable FileVault in System Settings.") + ).toBeInTheDocument(); + expect(screen.queryByText(/missing description/)).not.toBeInTheDocument(); + }); + + it("renders only description or resolution without showing empty state", () => { + const { unmount } = renderWithSetup( + + ); + + expect(screen.getByText("Some description")).toBeInTheDocument(); + expect(screen.queryByText("Resolve:")).not.toBeInTheDocument(); + expect(screen.queryByText(/missing description/)).not.toBeInTheDocument(); + + unmount(); + + renderWithSetup( + + ); + + expect(screen.getByText("Resolve:")).toBeInTheDocument(); + expect(screen.getByText("Some resolution")).toBeInTheDocument(); + expect(screen.queryByText(/missing description/)).not.toBeInTheDocument(); + }); + + it("renders empty state when no description or resolution", () => { + renderWithSetup( + + ); + + expect( + screen.getByText( + "This policy is missing description and resolution instructions." + ) + ).toBeInTheDocument(); + expect(screen.queryByText("Resolve:")).not.toBeInTheDocument(); + expect( + screen.queryByText(/Please contact your IT admin/) + ).not.toBeInTheDocument(); + }); + + it("renders device user empty state with IT admin message", () => { + renderWithSetup( + + ); + + expect( + screen.getByText( + /missing description and resolution instructions.*Please contact your IT admin/ + ) + ).toBeInTheDocument(); + }); + + it("renders 'Resolve later' button only for failing conditional access policies", () => { + const { unmount } = renderWithSetup( + + ); + + expect(screen.getByText("Resolve later")).toBeInTheDocument(); + + unmount(); + + renderWithSetup( + + ); + + expect(screen.queryByText("Resolve later")).not.toBeInTheDocument(); + }); +}); diff --git a/frontend/pages/hosts/details/cards/Policies/HostPoliciesTable/PolicyDetailsModal/PolicyDetailsModal.tsx b/frontend/pages/hosts/details/cards/Policies/HostPoliciesTable/PolicyDetailsModal/PolicyDetailsModal.tsx index 7a146f9122..34f47e4809 100644 --- a/frontend/pages/hosts/details/cards/Policies/HostPoliciesTable/PolicyDetailsModal/PolicyDetailsModal.tsx +++ b/frontend/pages/hosts/details/cards/Policies/HostPoliciesTable/PolicyDetailsModal/PolicyDetailsModal.tsx @@ -9,6 +9,7 @@ interface IPolicyDetailsProps { onCancel: () => void; policy: IHostPolicy | null; onResolveLater?: () => void; + isDeviceUser?: boolean; } const baseClass = "policy-details-modal"; @@ -17,7 +18,11 @@ const PolicyDetailsModal = ({ onCancel, policy, onResolveLater, + isDeviceUser = false, }: IPolicyDetailsProps): JSX.Element => { + const hasNoDescriptionOrResolution = + !policy?.description && !policy?.resolution; + return (
- - {policy?.description} - - {policy?.resolution && ( -
- Resolve: - {policy?.resolution && } -
+ {hasNoDescriptionOrResolution ? ( + + This policy is missing description and resolution instructions. + {isDeviceUser ? " Please contact your IT admin." : ""} + + ) : ( + <> + {policy?.description && ( + + {policy.description} + + )} + {policy?.resolution && ( +
+ + Resolve: + + +
+ )} + )}
diff --git a/frontend/pages/hosts/details/cards/Policies/HostPoliciesTable/PolicyDetailsModal/_styles.scss b/frontend/pages/hosts/details/cards/Policies/HostPoliciesTable/PolicyDetailsModal/_styles.scss index 835644f9bb..3957743e9a 100644 --- a/frontend/pages/hosts/details/cards/Policies/HostPoliciesTable/PolicyDetailsModal/_styles.scss +++ b/frontend/pages/hosts/details/cards/Policies/HostPoliciesTable/PolicyDetailsModal/_styles.scss @@ -1,9 +1,10 @@ .policy-details-modal { &__body { + @include vertical-modal-layout; + white-space: pre-wrap; } &__resolution { - margin-top: $pad-small; overflow: hidden; }