Files
jacobshandlingandJacob Shandling 9ab0eb2acd UI: Update conditional access on a per-policy basis (#28658)
## For #28049 , #28610

- **Implement front end ability to enable or disable conditional access
on a per-policy basis**
- **Update policy status UI to include new "action required" state,
representing a failed policy on a host with conditional access enabled**
- Additional improvements

<img width="1624" alt="Screenshot 2025-04-29 at 1 32 33 PM"
src="https://github.com/user-attachments/assets/960b3348-b0e2-48b8-bcff-28f91f64fd01"
/>

<img width="1624" alt="Screenshot 2025-04-29 at 12 15 39 PM"
src="https://github.com/user-attachments/assets/b0e0cf1f-a693-4e0b-b18a-a44ee258975f"
/>

<img width="1624" alt="Screenshot 2025-04-29 at 12 15 49 PM"
src="https://github.com/user-attachments/assets/15f7bea1-7338-4997-93bf-8baeb308e3f0"
/>

<img width="1400" alt="updated policies table headers"
src="https://github.com/user-attachments/assets/164fd84a-a9ee-4dfe-8d73-b4e82e27edbc"
/>

- [x] Changes file added for user-visible changes in `changes/`
- [ ] Added/updated automated tests
- [x] A detailed QA plan exists on the associated ticket (if it isn't
there, work with the product group's QA engineer to add it)
- [x] Manual QA for all new/changed functionality

---------

Co-authored-by: Jacob Shandling <jacob@fleetdm.com>
2025-05-01 11:43:38 -07:00

82 lines
1.6 KiB
TypeScript

const booleanAsc = (a: unknown, b: unknown): number => {
if (!a && !!b) {
return -1;
}
if (!!a && !b) {
return 1;
}
return 0;
};
const caseInsensitiveAsc = (a: any, b: any): number => {
a = typeof a === "string" ? a.toLowerCase() : a;
b = typeof b === "string" ? b.toLowerCase() : b;
if (a < b) {
return -1;
}
if (a > b) {
return 1;
}
return 0;
};
// Parses string representations of dates (e.g., "2021-02-21") and sorts in ascending order (i.e. "2021-02-01"
// appears before "2021-03-01").
// Values that are not parsable as dates return NaN and are sorted to appear before date-parsable values.
const dateStringsAsc = (a: string, b: string): number => {
const parsedA = Date.parse(a);
const parsedB = Date.parse(b);
if (isNaN(parsedA) && isNaN(parsedB)) {
return 0;
}
if (isNaN(parsedA)) {
return -1;
}
if (isNaN(parsedB)) {
return 1;
}
if (parsedA < parsedB) {
return -1;
}
if (parsedA > parsedB) {
return 1;
}
return 0;
};
const hasLength = (a: unknown[], b: unknown[]): number => {
if (!a?.length && b?.length) {
return -1;
}
if (a?.length && !b?.length) {
return 1;
}
return 0;
};
const POLICY_STATUS_PRECEDENCE = ["actionRequired", "fail", "pass"];
const hostPolicyStatus = (a: unknown, b: unknown): number => {
const [aI, bI] = [
POLICY_STATUS_PRECEDENCE.indexOf(a as string),
POLICY_STATUS_PRECEDENCE.indexOf(b as string),
];
if (aI > bI) {
return 1;
}
if (aI === bI) {
return 0;
}
return -1;
};
export default {
booleanAsc,
caseInsensitiveAsc,
dateStringsAsc,
hasLength,
hostPolicyStatus,
};