fleet/frontend/pages/labels/ManageLabelsPage/LabelsTable/LabelsTableConfig.tsx
Ian Littman 8e4e89f4e9
API + auth + UI changes for team labels (#37208)
Covers #36760, #36758.

# Checklist for submitter

If some of the following don't apply, delete the relevant line.

- [x] 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/guides/committing-changes.md#changes-files)
for more information.

- [x] Input data is properly validated, `SELECT *` is avoided, SQL
injection is prevented (using placeholders for values in statements)

## Testing

- [x] Added/updated automated tests
- [x] Where appropriate, [automated tests simulate multiple hosts and
test for host
isolation](https://github.com/fleetdm/fleet/blob/main/docs/Contributing/reference/patterns-backend.md#unit-testing)
(updates to one hosts's records do not affect another)

- [ ] QA'd all new/changed functionality manually
2025-12-29 21:28:45 -06:00

177 lines
4.4 KiB
TypeScript

import React from "react";
import { ILabel, LabelMembershipTypeToDisplayCopy } from "interfaces/label";
import { IDropdownOption } from "interfaces/dropdownOption";
import TextCell from "components/TableContainer/DataTable/TextCell";
import {
isGlobalAdmin,
isGlobalMaintainer,
isAnyTeamMaintainerOrTeamAdmin,
isTeamAdmin,
isTeamMaintainer,
} from "utilities/permissions/permissions";
import { IUser } from "interfaces/user";
import HeaderCell from "components/TableContainer/DataTable/HeaderCell";
import ViewAllHostsLink from "components/ViewAllHostsLink";
import TooltipTruncatedTextCell from "components/TableContainer/DataTable/TooltipTruncatedTextCell";
interface IHeaderProps {
column: {
title: string;
isSortedDesc: boolean;
};
}
interface IRowProps {
row: {
original: ILabel;
};
}
interface ICellProps extends IRowProps {
cell: {
value: string;
};
}
interface IDropdownCellProps extends IRowProps {
cell: {
value: IDropdownOption[];
};
}
interface IDataColumn {
title: string;
Header: ((props: IHeaderProps) => JSX.Element) | string;
accessor: string;
Cell:
| ((props: ICellProps) => JSX.Element)
| ((props: IDropdownCellProps) => JSX.Element);
disableHidden?: boolean;
disableSortBy?: boolean;
sortType?: string;
}
const hasEditPermission = (currentUser: IUser, label: ILabel): boolean => {
return (
// global permissions
isGlobalAdmin(currentUser) ||
isGlobalMaintainer(currentUser) ||
// author permission
(label.author_id === currentUser.id &&
isAnyTeamMaintainerOrTeamAdmin(currentUser)) ||
// team permission
(label.team_id != null &&
(isTeamAdmin(currentUser, label.team_id) ||
isTeamMaintainer(currentUser, label.team_id)))
);
};
const generateActionDropdownOptions = (
currentUser: IUser,
label: ILabel
): IDropdownOption[] => {
const options: IDropdownOption[] = [
{
label: "View all hosts",
disabled: false,
value: "view_hosts",
},
];
if (hasEditPermission(currentUser, label)) {
if (label.label_membership_type !== "host_vitals") {
options.push({
label: "Edit",
disabled: false,
value: "edit",
});
}
options.push({
label: "Delete",
disabled: false,
value: "delete",
});
}
return options;
};
const generateTableHeaders = (
currentUser: IUser,
onClickAction: (action: string, label: ILabel) => void
): IDataColumn[] => {
return [
{
title: "Name",
Header: (cellProps) => (
<HeaderCell
value={cellProps.column.title}
isSortedDesc={cellProps.column.isSortedDesc}
/>
),
accessor: "name",
disableSortBy: false,
Cell: (cellProps: ICellProps) => (
<TooltipTruncatedTextCell value={cellProps.cell.value} />
),
},
{
title: "Description",
Header: (cellProps) => (
<HeaderCell
value={cellProps.column.title}
isSortedDesc={cellProps.column.isSortedDesc}
/>
),
accessor: "description",
Cell: (cellProps: ICellProps) => (
<TooltipTruncatedTextCell value={cellProps.cell.value || ""} />
),
},
{
title: "Type",
Header: (cellProps) => (
<HeaderCell
value={cellProps.column.title}
isSortedDesc={cellProps.column.isSortedDesc}
/>
),
accessor: "label_membership_type",
Cell: (cellProps: ICellProps) => {
const type = cellProps.row.original.label_membership_type;
return <TextCell value={LabelMembershipTypeToDisplayCopy[type]} />;
},
},
{
title: "Actions",
Header: "",
disableSortBy: true,
accessor: "actions",
Cell: (cellProps: IDropdownCellProps) => {
const label = cellProps.row.original;
const dropdownOptions = generateActionDropdownOptions(
currentUser,
label
);
return (
<ViewAllHostsLink
rowHover
noLink
excludeChevron
dropdown={{
options: dropdownOptions,
onChange: (value: string) => onClickAction(value, label),
}}
/>
);
},
},
];
};
const generateDataSet = (labels: ILabel[]) =>
labels.filter((label) => label.label_type !== "builtin");
export { generateTableHeaders, generateDataSet, hasEditPermission };