import React from "react"; import HeaderCell from "components/TableContainer/DataTable/HeaderCell/HeaderCell"; import StatusIndicator from "components/StatusIndicator"; import TextCell from "components/TableContainer/DataTable/TextCell/TextCell"; import TooltipTruncatedTextCell from "components/TableContainer/DataTable/TooltipTruncatedTextCell"; import TooltipWrapper from "components/TooltipWrapper"; import { IInvite } from "interfaces/invite"; import { IUser, UserRole } from "interfaces/user"; import { IDropdownOption } from "interfaces/dropdownOption"; import { generateRole, generateTeam, greyCell } from "utilities/helpers"; import { DEFAULT_EMPTY_CELL_VALUE } from "utilities/constants"; import { renderApiUserIndicator } from "pages/admin/TeamManagementPage/TeamDetailsWrapper/UsersPage/UsersPageTableConfig"; import ActionsDropdown from "../../../../../components/ActionsDropdown"; interface IHeaderProps { column: { title: string; isSortedDesc: boolean; }; } interface IRowProps { row: { original: IUser | IInvite; }; } interface ICellProps extends IRowProps { cell: { value: string; }; } interface IActionsDropdownProps extends IRowProps { cell: { value: IDropdownOption[]; }; } interface IDataColumn { title: string; Header: ((props: IHeaderProps) => JSX.Element) | string; accessor: string; Cell: | ((props: ICellProps) => JSX.Element) | ((props: IActionsDropdownProps) => JSX.Element); disableHidden?: boolean; disableSortBy?: boolean; } export interface IUserTableData { name: string; status: string; email: string; teams: string; role: UserRole; actions: IDropdownOption[]; id: number; type: string; api_only: boolean; } // NOTE: cellProps come from react-table // more info here https://react-table.tanstack.com/docs/api/useTable#cell-properties const generateTableHeaders = ( actionSelectHandler: (value: string, user: IUser | IInvite) => void, isPremiumTier: boolean | undefined ): IDataColumn[] => { const tableHeaders: IDataColumn[] = [ { title: "Name", Header: "Name", disableSortBy: true, accessor: "name", Cell: (cellProps: ICellProps) => { const apiOnlyUser = "api_only" in cellProps.row.original ? cellProps.row.original.api_only : false; return ( ); }, }, { title: "Role", Header: "Role", accessor: "role", disableSortBy: true, Cell: (cellProps: ICellProps) => { if (cellProps.cell.value === "GitOps") { return ( The GitOps role is only available on the command-line
when creating an API-only user. This user has no
access to the UI. } > GitOps
); } if (cellProps.cell.value === "Observer+") { return ( Users with the Observer+ role have access to all of
the same functions as an Observer, with the added
ability to run any live query against all hosts. } > {cellProps.cell.value}
); } const greyAndItalic = greyCell(cellProps.cell.value); return ( ); }, }, { title: "Status", Header: (cellProps) => ( ), accessor: "status", Cell: (cellProps: ICellProps) => ( ), }, { title: "Email", Header: "Email", disableSortBy: true, accessor: "email", Cell: (cellProps: ICellProps) => ( ), }, { title: "Actions", Header: "", disableSortBy: true, accessor: "actions", Cell: (cellProps: IActionsDropdownProps) => ( actionSelectHandler(value, cellProps.row.original) } placeholder="Actions" menuAlign="right" variant="small-button" /> ), }, ]; // Add Teams column for premium tier if (isPremiumTier) { tableHeaders.splice(2, 0, { title: "Teams", Header: "Teams", accessor: "teams", disableSortBy: true, Cell: (cellProps: ICellProps) => ( ), }); } return tableHeaders; }; const generateStatus = (type: string, data: IUser | IInvite): string => { const { teams, global_role } = data; if (global_role === null && teams.length === 0) { return "No access"; } return type === "invite" ? "Invite pending" : "Active"; }; const generateActionDropdownOptions = ( isCurrentUser: boolean, isInvitePending: boolean, isSsoEnabled: boolean ): IDropdownOption[] => { const disableDelete = isCurrentUser; let dropdownOptions = [ { label: "Edit", disabled: false, value: isCurrentUser ? "editMyAccount" : "edit", }, { label: "Require password reset", disabled: isInvitePending, value: "passwordReset", }, { label: "Reset sessions", disabled: isInvitePending, value: "resetSessions", }, { label: "Delete", disabled: disableDelete, value: "delete", tooltipContent: disableDelete ? ( <> There must be at least one Admin
user on the account. To delete this
user, add or set existing user with
role of "Admin". ) : undefined, }, ]; if (isCurrentUser) { // remove "Reset sessions" from dropdownOptions dropdownOptions = dropdownOptions.filter( (option) => option.label !== "Reset sessions" ); } if (isSsoEnabled) { // remove "Require password reset" from dropdownOptions dropdownOptions = dropdownOptions.filter( (option) => option.label !== "Require password reset" ); } return dropdownOptions; }; const enhanceUserData = ( users: IUser[], currentUserId: number ): IUserTableData[] => { return users.map((user) => { return { name: user.name || DEFAULT_EMPTY_CELL_VALUE, status: generateStatus("user", user), email: user.email, teams: generateTeam(user.teams, user.global_role), role: generateRole(user.teams, user.global_role), actions: generateActionDropdownOptions( user.id === currentUserId, false, user.sso_enabled ), id: user.id, type: "user", api_only: user.api_only, }; }); }; const enhanceInviteData = (invites: IInvite[]): IUserTableData[] => { return invites.map((invite) => { return { name: invite.name || DEFAULT_EMPTY_CELL_VALUE, status: generateStatus("invite", invite), email: invite.email, teams: generateTeam(invite.teams, invite.global_role), role: generateRole(invite.teams, invite.global_role), actions: generateActionDropdownOptions(false, true, invite.sso_enabled), id: invite.id, type: "invite", api_only: false, // api only users are created through fleetctl and not invites }; }); }; const combineDataSets = ( users: IUser[], invites: IInvite[], currentUserId: number ): IUserTableData[] => { return [ ...enhanceUserData(users, currentUserId), ...enhanceInviteData(invites), ]; }; export { generateTableHeaders, combineDataSets };