## 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>
82 lines
1.6 KiB
TypeScript
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,
|
|
};
|