1
0
Fork 0
mirror of https://github.com/portainer/portainer.git synced 2025-08-02 20:35:25 +02:00

refactor(users): migrate users table to react [EE-4708] (#10759)

This commit is contained in:
Chaim Lev-Ari 2024-04-03 17:38:32 +03:00 committed by GitHub
parent 86f1b8df6e
commit a439695248
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
19 changed files with 159 additions and 192 deletions

View file

@ -26,7 +26,7 @@ export function WidgetTitle({
<div className="widget-icon">
<Icon icon={icon} className="space-right" />
</div>
<span>{title}</span>
<h2 className="text-base m-0">{title}</h2>
</span>
<span className={clsx('pull-right', className)}>{children}</span>
</div>

View file

@ -20,7 +20,7 @@ export function TableRow<D extends DefaultType = DefaultType>({
onClick={onClick}
>
{cells.map((cell) => (
<td key={cell.id}>
<td key={cell.id} className={cell.column.columnDef.meta?.className}>
{flexRender(cell.column.columnDef.cell, cell.getContext())}
</td>
))}

View file

@ -72,11 +72,11 @@ export interface OAuthSettings {
KubeSecretKey: string;
}
enum AuthenticationMethod {
export enum AuthenticationMethod {
/**
* Internal represents the internal authentication method (authentication against Portainer API)
*/
Internal,
Internal = 1,
/**
* LDAP represents the LDAP authentication method (authentication against a LDAP server)
*/

View file

@ -0,0 +1,40 @@
import { User as UserIcon } from 'lucide-react';
import { Datatable } from '@@/datatables';
import { useTableState } from '@@/datatables/useTableState';
import { createPersistedStore } from '@@/datatables/types';
import { DeleteButton } from '@@/buttons/DeleteButton';
import { columns } from './columns';
import { DecoratedUser } from './types';
const store = createPersistedStore('users');
export function UsersDatatable({
dataset,
onRemove,
}: {
dataset?: Array<DecoratedUser>;
onRemove: (selectedItems: Array<DecoratedUser>) => void;
}) {
const tableState = useTableState(store, 'users');
return (
<Datatable
columns={columns}
dataset={dataset || []}
isLoading={!dataset}
title="Users"
titleIcon={UserIcon}
settingsManager={tableState}
isRowSelectable={(row) => row.original.Id !== 1}
renderTableActions={(selectedItems) => (
<DeleteButton
disabled={selectedItems.length === 0}
confirmMessage="Do you want to remove the selected users? They will not be able to login into Portainer anymore."
onConfirmed={() => onRemove(selectedItems)}
/>
)}
/>
);
}

View file

@ -0,0 +1,5 @@
import { helper } from './helper';
export const authentication = helper.accessor('authMethod', {
header: 'Authentication',
});

View file

@ -0,0 +1,5 @@
import { createColumnHelper } from '@tanstack/react-table';
import { DecoratedUser } from '../types';
export const helper = createColumnHelper<DecoratedUser>();

View file

@ -0,0 +1,5 @@
import { authentication } from './authentication';
import { name } from './name';
import { role } from './role';
export const columns = [name, role, authentication];

View file

@ -0,0 +1,32 @@
import { CellContext } from '@tanstack/react-table';
import { useCurrentUser } from '@/react/hooks/useUser';
import { Link } from '@@/Link';
import { DecoratedUser } from '../types';
import { helper } from './helper';
export const name = helper.accessor('Username', {
header: 'Name',
cell: Cell,
});
function Cell({
getValue,
row: { original: item },
}: CellContext<DecoratedUser, 'string'>) {
const { isPureAdmin } = useCurrentUser();
const name = getValue();
if (!isPureAdmin) {
return <>{name}</>;
}
return (
<Link to=".user" params={{ id: item.Id }}>
{name}
</Link>
);
}

View file

@ -0,0 +1,29 @@
import { User, UserPlus } from 'lucide-react';
import { isEdgeAdmin } from '@/portainer/users/user.helpers';
import { RoleNames } from '@/portainer/users/types';
import { Icon } from '@@/Icon';
import { helper } from './helper';
export const role = helper.accessor(
(item) =>
`${RoleNames[item.Role]} ${
item.isTeamLeader ? ' - team leader' : ''
}`.trim(),
{
header: 'Role',
cell: ({ getValue, row: { original: item } }) => {
const icon =
isEdgeAdmin({ Role: item.Role }) || item.isTeamLeader ? User : UserPlus;
return (
<span className="vertical-center">
<Icon icon={icon} />
{getValue() || '-'}
</span>
);
},
}
);

View file

@ -0,0 +1,6 @@
import { type User } from '@/portainer/users/types';
export type DecoratedUser = User & {
isTeamLeader?: boolean;
authMethod: string;
};