From 27384c9263b5ff3c8f5de43c4f4e9106b95ffde6 Mon Sep 17 00:00:00 2001 From: Gabriel Hernandez Date: Tue, 11 Jun 2024 13:23:30 +0100 Subject: [PATCH 1/7] Add UI for uploading custom profiles with target of hosts that include all/exclude any selected labels (#19587) relates to #18848 This adds the UI that supports uploading a custom profile that applies to hosts that either: - have all selected labels - don't have any of the selected labels This includes UI updates for the Add Profile modal and the Custom Targets Modal, as well as code to support the new API. **include all on add profile modal:** ![image](https://github.com/fleetdm/fleet/assets/1153709/5eb8ffa2-95ce-4f43-ac38-0eac0d678614) **exclude any on add profile modal:** ![image](https://github.com/fleetdm/fleet/assets/1153709/ec62ad7b-c8bb-45d0-a57f-f078b857dd26) **dropdown options:** ![image](https://github.com/fleetdm/fleet/assets/1153709/015f268d-9f13-4643-8509-4543fb9a34d8) **include all custom target modal:** ![image](https://github.com/fleetdm/fleet/assets/1153709/e18b28e0-e20d-4ae1-ad13-15ee757b4818) **exclude any custom target modal:** ![image](https://github.com/fleetdm/fleet/assets/1153709/9009f584-d07d-4f49-9c74-59c2c36123a3) - [x] Changes file added for user-visible changes in `changes/`, `orbit/changes/` or `ee/fleetd-chrome/changes`. See [Changes files](https://fleetdm.com/docs/contributing/committing-changes#changes-files) for more information. - [ ] Added/updated tests - [x] Manual QA for all new/changed functionality --- ...848-include-all-exclude-any-custom-profile | 2 + frontend/interfaces/config.ts | 8 +- frontend/interfaces/dropdownOption.ts | 2 + frontend/interfaces/mdm.ts | 6 +- .../cards/CustomSettings/CustomSettings.tsx | 11 +- .../cards/CustomSettings/_styles.scss | 125 ----------- .../ProfileLabelsModal/ProfileLabelsModal.tsx | 56 +++-- .../ProfileListItem/ProfileListItem.tsx | 32 ++- .../{ => AddProfileModal}/AddProfileModal.tsx | 201 +++++++++++------- .../components/AddProfileModal/_styles.scss | 138 ++++++++++++ .../components/AddProfileModal/helpers.tsx | 54 +++++ .../components/AddProfileModal/index.ts | 1 + .../components/ProfileUploader/helpers.tsx | 72 ------- frontend/services/entities/mdm.ts | 51 ++++- 14 files changed, 443 insertions(+), 316 deletions(-) create mode 100644 changes/issue-18848-include-all-exclude-any-custom-profile rename frontend/pages/ManageControlsPage/OSSettings/cards/CustomSettings/components/ProfileUploader/components/{ => AddProfileModal}/AddProfileModal.tsx (71%) create mode 100644 frontend/pages/ManageControlsPage/OSSettings/cards/CustomSettings/components/ProfileUploader/components/AddProfileModal/_styles.scss create mode 100644 frontend/pages/ManageControlsPage/OSSettings/cards/CustomSettings/components/ProfileUploader/components/AddProfileModal/helpers.tsx create mode 100644 frontend/pages/ManageControlsPage/OSSettings/cards/CustomSettings/components/ProfileUploader/components/AddProfileModal/index.ts diff --git a/changes/issue-18848-include-all-exclude-any-custom-profile b/changes/issue-18848-include-all-exclude-any-custom-profile new file mode 100644 index 0000000000..ef065303f3 --- /dev/null +++ b/changes/issue-18848-include-all-exclude-any-custom-profile @@ -0,0 +1,2 @@ +- add UI for uploading custom profiles with a target of hosts that include all/exclude + any selected labels diff --git a/frontend/interfaces/config.ts b/frontend/interfaces/config.ts index ebb286630c..21ac95dbcd 100644 --- a/frontend/interfaces/config.ts +++ b/frontend/interfaces/config.ts @@ -29,6 +29,12 @@ export interface IMacOsMigrationSettings { webhook_url: string; } +interface ICustomSetting { + path: string; + labels_include_all?: string[]; + labels_exclude_any?: string[]; +} + export interface IMdmConfig { enable_disk_encryption: boolean; enabled_and_configured: boolean; @@ -42,7 +48,7 @@ export interface IMdmConfig { deadline: string | null; }; macos_settings: { - custom_settings: null; + custom_settings: null | ICustomSetting[]; enable_disk_encryption: boolean; }; macos_setup: { diff --git a/frontend/interfaces/dropdownOption.ts b/frontend/interfaces/dropdownOption.ts index a8895d48b9..67b1bacd4d 100644 --- a/frontend/interfaces/dropdownOption.ts +++ b/frontend/interfaces/dropdownOption.ts @@ -1,3 +1,4 @@ +import { ReactNode } from "react"; import PropTypes from "prop-types"; export default PropTypes.shape({ @@ -10,6 +11,7 @@ export interface IDropdownOption { disabled?: boolean; label: string | JSX.Element; value: string | number; + helpText?: ReactNode; premiumOnly?: boolean; tooltipContent?: string | JSX.Element; } diff --git a/frontend/interfaces/mdm.ts b/frontend/interfaces/mdm.ts index 4b3a8791e6..a911f0c9e7 100644 --- a/frontend/interfaces/mdm.ts +++ b/frontend/interfaces/mdm.ts @@ -71,7 +71,8 @@ export type ProfilePlatform = "darwin" | "windows"; export interface IProfileLabel { name: string; - broken: boolean; + id?: number; // id is only present when the label is not broken + broken?: boolean; } export interface IMdmProfile { @@ -83,7 +84,8 @@ export interface IMdmProfile { created_at: string; updated_at: string; checksum: string | null; // null for windows profiles - labels?: IProfileLabel[]; + labels_include_all?: IProfileLabel[]; + labels_exclude_any?: IProfileLabel[]; } export type MdmProfileStatus = "verified" | "verifying" | "pending" | "failed"; diff --git a/frontend/pages/ManageControlsPage/OSSettings/cards/CustomSettings/CustomSettings.tsx b/frontend/pages/ManageControlsPage/OSSettings/cards/CustomSettings/CustomSettings.tsx index 8298a10647..89887e9b83 100644 --- a/frontend/pages/ManageControlsPage/OSSettings/cards/CustomSettings/CustomSettings.tsx +++ b/frontend/pages/ManageControlsPage/OSSettings/cards/CustomSettings/CustomSettings.tsx @@ -20,7 +20,7 @@ import Pagination from "pages/ManageControlsPage/components/Pagination"; import UploadList from "../../../components/UploadList"; import AddProfileCard from "./components/ProfileUploader/components/AddProfileCard"; -import AddProfileModal from "./components/ProfileUploader/components/AddProfileModal"; +import AddProfileModal from "./components/ProfileUploader/components/AddProfileModal/AddProfileModal"; import DeleteProfileModal from "./components/DeleteProfileModal/DeleteProfileModal"; import ProfileLabelsModal from "./components/ProfileLabelsModal/ProfileLabelsModal"; import ProfileListItem from "./components/ProfileListItem"; @@ -101,7 +101,7 @@ const CustomSettings = ({ onMutation(); renderFlash("success", "Successfully deleted!"); } catch (e) { - renderFlash("error", "Couldn’t delete. Please try again."); + renderFlash("error", "Couldn't delete. Please try again."); } finally { selectedProfile.current = null; setShowDeleteProfileModal(false); @@ -169,6 +169,10 @@ const CustomSettings = ({ ); }; + const hasLabels = + !!profileLabelsModalData?.labels_include_all?.length || + !!profileLabelsModalData?.labels_exclude_any?.length; + return (
@@ -189,7 +193,6 @@ const CustomSettings = ({ )} {showAddProfileModal && ( )} - {!!isPremiumTier && !!profileLabelsModalData?.labels?.length && ( + {isPremiumTier && hasLabels && ( ( -
- {profileName} will only be applied to hosts that have all these - labels: -
-); + targetType, +}: IModalDescriptionProps) => { + const targetTypeText = + targetType === "includeAll" ? ( + <> + have all + + ) : ( + <> + don't have any + + ); + + return ( +
+ {profileName} profile only applies to hosts that {targetTypeText}{" "} + of these labels: +
+ ); +}; const BrokenLabelWarning = () => ( The configuration profile is{" "} broken @@ -67,7 +84,14 @@ const ProfileLabelsModal = ({ profile, setModalData, }: IProfileLabelsModalProps) => { - if (!profile?.labels?.length) { + if (!profile) { + return null; + } + + const { name, labels_include_all, labels_exclude_any } = profile; + const labels = labels_include_all || labels_exclude_any; + + if (!labels?.length) { // caller ensures this never happens return null; } @@ -75,9 +99,13 @@ const ProfileLabelsModal = ({ return ( setModalData(null)}>
- {profile.labels.some((label) => label.broken) && } - - + {labels.some((label) => label.broken) && } + +