From f3835e6d49283427a89edf4fca387113b5c282a9 Mon Sep 17 00:00:00 2001 From: Scott Gress Date: Wed, 19 Mar 2025 09:38:53 -0500 Subject: [PATCH] Allow team admins and team maintainers to manage labels (#27063) For #27037 # Checklist for submitter - [ ] Changes file added for user-visible changes in `changes/`, `orbit/changes/` or `ee/fleetd-chrome/changes`. See [Changes files](https://github.com/fleetdm/fleet/blob/main/docs/Contributing/Committing-Changes.md#changes-files) for more information. ## Details This PR updates the UI to allow team admins and maintainers to create labels, and to edit or delete labels that they created. They will not be able to edit or delete labels created by other team admins or maintainers, or by global admins. Global admins will still be able to edit or delete any label. ## Testing 1. Log in a global user and create a new label 1. Create a team admin user 1. Verify that the team admin user can create a label 2. Verify that the team admin user can edit their own label 2. Verify that the team admin user can delete their own label 2. Verify that the team admin user cannot edit or delete the label created by the global user 3. Create a team maintainer user 1. Verify that the team maintainer user can create a label 2. Verify that the team maintainer user can edit their own label 2. Verify that the team maintainer user can delete their own label 2. Verify that the team maintainer user cannot edit or delete the label created by the global user 2. Verify that the team maintainer user cannot edit or delete the label created by the team admin user 3. Verify that the team admin user cannot edit or delete the label created by the team maintainer user --- frontend/interfaces/label.ts | 1 + .../hosts/ManageHostsPage/ManageHostsPage.tsx | 4 ++- .../HostsFilterBlock/HostsFilterBlock.tsx | 27 +++++++++++-------- 3 files changed, 20 insertions(+), 12 deletions(-) diff --git a/frontend/interfaces/label.ts b/frontend/interfaces/label.ts index 7565fca881..19e80d3cd1 100644 --- a/frontend/interfaces/label.ts +++ b/frontend/interfaces/label.ts @@ -48,6 +48,7 @@ export interface ILabel extends ILabelSummary { slug?: string; // e.g., "labels/13" | "online" target_type?: string; // e.g., "labels" platform: string; + author_id?: number; } // corresponding to fleet>server>fleet>labels.go>LabelSpec diff --git a/frontend/pages/hosts/ManageHostsPage/ManageHostsPage.tsx b/frontend/pages/hosts/ManageHostsPage/ManageHostsPage.tsx index 2d35204b42..041d218ec9 100644 --- a/frontend/pages/hosts/ManageHostsPage/ManageHostsPage.tsx +++ b/frontend/pages/hosts/ManageHostsPage/ManageHostsPage.tsx @@ -294,7 +294,9 @@ const ManageHostsPage = ({ const canEnrollHosts = isGlobalAdmin || isGlobalMaintainer || isTeamAdmin || isTeamMaintainer; const canEnrollGlobalHosts = isGlobalAdmin || isGlobalMaintainer; - const canAddNewLabels = (isGlobalAdmin || isGlobalMaintainer) ?? false; + const canAddNewLabels = + (isGlobalAdmin || isGlobalMaintainer || isTeamAdmin || isTeamMaintainer) ?? + false; const { data: labels, refetch: refetchLabels } = useQuery< ILabelsResponse, diff --git a/frontend/pages/hosts/ManageHostsPage/components/HostsFilterBlock/HostsFilterBlock.tsx b/frontend/pages/hosts/ManageHostsPage/components/HostsFilterBlock/HostsFilterBlock.tsx index f3ea242e68..3eb8e6f5c4 100644 --- a/frontend/pages/hosts/ManageHostsPage/components/HostsFilterBlock/HostsFilterBlock.tsx +++ b/frontend/pages/hosts/ManageHostsPage/components/HostsFilterBlock/HostsFilterBlock.tsx @@ -1,6 +1,7 @@ -import React from "react"; +import React, { useContext } from "react"; import { invert } from "lodash"; +import { AppContext } from "context/app"; import { ILabel } from "interfaces/label"; import { formatOperatingSystemDisplayName, @@ -140,6 +141,8 @@ const HostsFilterBlock = ({ onClickEditLabel, onClickDeleteLabel, }: IHostsFilterBlockProps) => { + const { currentUser, isOnGlobalTeam } = useContext(AppContext); + const renderLabelFilterPill = () => { if (selectedLabel) { const { description, display_text, label_type } = selectedLabel; @@ -165,16 +168,18 @@ const HostsFilterBlock = ({ tooltipDescription={description} onClear={handleClearRouteParam} /> - {label_type !== "builtin" && !isOnlyObserver && ( - <> - - - - )} + {label_type !== "builtin" && + !isOnlyObserver && + (isOnGlobalTeam || currentUser?.id === selectedLabel.author_id) && ( + <> + + + + )} ); }