1
0
Fork 0
mirror of https://github.com/portainer/portainer.git synced 2025-08-09 15:55:23 +02:00

refactor(ui/datatables): migrate views to use datatable component [EE-4064] (#7609)

This commit is contained in:
Chaim Lev-Ari 2022-11-22 14:16:34 +02:00 committed by GitHub
parent 0f0513c684
commit fe8e834dbf
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
90 changed files with 1714 additions and 2717 deletions

View file

@ -175,159 +175,156 @@ export function EnvironmentList({ onClickItem, onRefresh }: Props) {
return (
<>
{totalAvailable === 0 && <NoEnvironmentsInfoPanel isAdmin={isAdmin} />}
<div className="row">
<div className="col-sm-12">
<TableContainer>
<TableTitle icon="hard-drive" featherIcon label="Environments" />
<TableActions className={styles.actionBar}>
<div className={styles.description}>
Click on an environment to manage
</div>
<div className={styles.actionButton}>
<div className={styles.refreshButton}>
{isAdmin && (
<Button
onClick={onRefresh}
data-cy="home-refreshEndpointsButton"
size="medium"
color="secondary"
className={clsx(
'vertical-center !ml-0',
styles.refreshEnvironmentsButton
)}
>
<RefreshCcw
className="feather icon-sm icon-white"
aria-hidden="true"
/>
Refresh
</Button>
<TableContainer>
<TableTitle icon="hard-drive" featherIcon label="Environments" />
<TableActions className={styles.actionBar}>
<div className={styles.description}>
Click on an environment to manage
</div>
<div className={styles.actionButton}>
<div className={styles.refreshButton}>
{isAdmin && (
<Button
onClick={onRefresh}
data-cy="home-refreshEndpointsButton"
size="medium"
color="secondary"
className={clsx(
'vertical-center !ml-0',
styles.refreshEnvironmentsButton
)}
</div>
<div className={styles.kubeconfigButton}>
<KubeconfigButton
environments={environments}
envQueryParams={{
...environmentsQueryParams,
sort: sortByFilter,
order: sortByDescending ? 'desc' : 'asc',
}}
>
<RefreshCcw
className="feather icon-sm icon-white"
aria-hidden="true"
/>
</div>
<div className={clsx(styles.filterSearchbar, 'ml-3')}>
<FilterSearchBar
value={searchBarValue}
onChange={setSearchBarValue}
placeholder="Search by name, group, tag, status, URL..."
data-cy="home-endpointsSearchInput"
/>
</div>
</div>
</TableActions>
<div className={styles.filterContainer}>
<div className={styles.filterLeft}>
<HomepageFilter
filterOptions={platformTypeOptions}
onChange={setPlatformTypes}
placeHolder="Platform"
value={platformTypes}
/>
</div>
<div className={styles.filterLeft}>
<HomepageFilter
filterOptions={connectionTypeOptions}
onChange={setConnectionTypes}
placeHolder="Connection Type"
value={connectionTypes}
/>
</div>
<div className={styles.filterLeft}>
<HomepageFilter
filterOptions={status}
onChange={statusOnChange}
placeHolder="Status"
value={statusState}
/>
</div>
<div className={styles.filterLeft}>
<HomepageFilter
filterOptions={uniqueTag}
onChange={tagOnChange}
placeHolder="Tags"
value={tagState}
/>
</div>
<div className={styles.filterLeft}>
<HomepageFilter
filterOptions={uniqueGroup}
onChange={groupOnChange}
placeHolder="Groups"
value={groupState}
/>
</div>
<div className={styles.filterLeft}>
<HomepageFilter<string>
filterOptions={
agentVersionsQuery.data?.map((v) => ({
label: v,
value: v,
})) || []
}
onChange={setAgentVersions}
placeHolder="Agent Version"
value={agentVersions}
/>
</div>
<button
type="button"
className={styles.clearButton}
onClick={clearFilter}
>
Clear all
</button>
<div className={styles.filterRight}>
<SortbySelector
filterOptions={sortByOptions}
onChange={sortOnchange}
onDescending={sortOnDescending}
placeHolder="Sort By"
sortByDescending={sortByDescending}
sortByButton={sortByButton}
value={sortByState}
/>
</div>
</div>
<div className="blocklist" data-cy="home-endpointList">
{renderItems(
isLoading,
totalCount,
environments.map((env) => (
<EnvironmentItem
key={env.Id}
environment={env}
groupName={
groupsQuery.data?.find((g) => g.Id === env.GroupId)?.Name
}
onClick={onClickItem}
/>
))
Refresh
</Button>
)}
</div>
<TableFooter>
<PaginationControls
showAll={totalCount <= 100}
pageLimit={pageLimit}
page={page}
onPageChange={setPage}
totalCount={totalCount}
onPageLimitChange={setPageLimit}
<div className={styles.kubeconfigButton}>
<KubeconfigButton
environments={environments}
envQueryParams={{
...environmentsQueryParams,
sort: sortByFilter,
order: sortByDescending ? 'desc' : 'asc',
}}
/>
</TableFooter>
</TableContainer>
</div>
<div className={clsx(styles.filterSearchbar, 'ml-3')}>
<FilterSearchBar
value={searchBarValue}
onChange={setSearchBarValue}
placeholder="Search by name, group, tag, status, URL..."
data-cy="home-endpointsSearchInput"
/>
</div>
</div>
</TableActions>
<div className={styles.filterContainer}>
<div className={styles.filterLeft}>
<HomepageFilter
filterOptions={platformTypeOptions}
onChange={setPlatformTypes}
placeHolder="Platform"
value={platformTypes}
/>
</div>
<div className={styles.filterLeft}>
<HomepageFilter
filterOptions={connectionTypeOptions}
onChange={setConnectionTypes}
placeHolder="Connection Type"
value={connectionTypes}
/>
</div>
<div className={styles.filterLeft}>
<HomepageFilter
filterOptions={status}
onChange={statusOnChange}
placeHolder="Status"
value={statusState}
/>
</div>
<div className={styles.filterLeft}>
<HomepageFilter
filterOptions={uniqueTag}
onChange={tagOnChange}
placeHolder="Tags"
value={tagState}
/>
</div>
<div className={styles.filterLeft}>
<HomepageFilter
filterOptions={uniqueGroup}
onChange={groupOnChange}
placeHolder="Groups"
value={groupState}
/>
</div>
<div className={styles.filterLeft}>
<HomepageFilter<string>
filterOptions={
agentVersionsQuery.data?.map((v) => ({
label: v,
value: v,
})) || []
}
onChange={setAgentVersions}
placeHolder="Agent Version"
value={agentVersions}
/>
</div>
<button
type="button"
className={styles.clearButton}
onClick={clearFilter}
>
Clear all
</button>
<div className={styles.filterRight}>
<SortbySelector
filterOptions={sortByOptions}
onChange={sortOnchange}
onDescending={sortOnDescending}
placeHolder="Sort By"
sortByDescending={sortByDescending}
sortByButton={sortByButton}
value={sortByState}
/>
</div>
</div>
</div>
<div className="blocklist" data-cy="home-endpointList">
{renderItems(
isLoading,
totalCount,
environments.map((env) => (
<EnvironmentItem
key={env.Id}
environment={env}
groupName={
groupsQuery.data?.find((g) => g.Id === env.GroupId)?.Name
}
onClick={onClickItem}
/>
))
)}
</div>
<TableFooter>
<PaginationControls
showAll={totalCount <= 100}
pageLimit={pageLimit}
page={page}
onPageChange={setPage}
totalCount={totalCount}
onPageLimitChange={setPageLimit}
/>
</TableFooter>
</TableContainer>
</>
);

View file

@ -46,39 +46,35 @@ export function AccessControlPanel({
(!isAdmin && !isPartOfRestrictedUsers && !isLeaderOfAnyRestrictedTeams);
return (
<div className="row">
<div className="col-sm-12">
<TableContainer>
<TableTitle label="Access control" icon="eye" featherIcon />
<AccessControlPanelDetails
resourceType={resourceType}
resourceControl={resourceControl}
/>
<TableContainer>
<TableTitle label="Access control" icon="eye" featherIcon />
<AccessControlPanelDetails
resourceType={resourceType}
resourceControl={resourceControl}
/>
{!isEditDisabled && !isEditMode && (
<div className="row">
<div>
<Button color="link" onClick={toggleEditMode}>
<Icon icon="edit" className="space-right" feather />
Change ownership
</Button>
</div>
</div>
)}
{!isEditDisabled && !isEditMode && (
<div className="row">
<div>
<Button color="link" onClick={toggleEditMode}>
<Icon icon="edit" className="space-right" feather />
Change ownership
</Button>
</div>
</div>
)}
{isEditMode && (
<AccessControlPanelForm
resourceControl={resourceControl}
onCancelClick={() => toggleEditMode()}
resourceId={resourceId}
resourceType={resourceType}
environmentId={environmentId}
onUpdateSuccess={handleUpdateSuccess}
/>
)}
</TableContainer>
</div>
</div>
{isEditMode && (
<AccessControlPanelForm
resourceControl={resourceControl}
onCancelClick={() => toggleEditMode()}
resourceId={resourceId}
resourceType={resourceType}
environmentId={environmentId}
onUpdateSuccess={handleUpdateSuccess}
/>
)}
</TableContainer>
);
async function handleUpdateSuccess() {

View file

@ -1,4 +1,5 @@
import { Clock, Trash2 } from 'react-feather';
import { useStore } from 'zustand';
import {
FeatureFlag,
@ -11,6 +12,7 @@ import { Datatable } from '@@/datatables';
import { PageHeader } from '@@/PageHeader';
import { Button } from '@@/buttons';
import { Link } from '@@/Link';
import { useSearchBarState } from '@@/datatables/SearchBar';
import { useList } from '../queries/list';
import { EdgeUpdateSchedule } from '../types';
@ -20,12 +22,15 @@ import { columns } from './columns';
import { createStore } from './datatable-store';
const storageKey = 'update-schedules-list';
const useStore = createStore(storageKey);
const settingsStore = createStore(storageKey);
export function ListView() {
useRedirectFeatureFlag(FeatureFlag.EdgeRemoteUpdate);
const settings = useStore(settingsStore);
const [search, setSearch] = useSearchBarState(storageKey);
const listQuery = useList();
const store = useStore();
if (!listQuery.data) {
return null;
@ -40,20 +45,22 @@ export function ListView() {
/>
<Datatable
columns={columns}
titleOptions={{
title: 'Update & rollback',
icon: Clock,
}}
dataset={listQuery.data}
settingsStore={store}
storageKey={storageKey}
columns={columns}
title="Update & rollback"
titleIcon={Clock}
emptyContentLabel="No schedules found"
isLoading={listQuery.isLoading}
totalCount={listQuery.data.length}
renderTableActions={(selectedRows) => (
<TableActions selectedRows={selectedRows} />
)}
initialPageSize={settings.pageSize}
onPageSizeChange={settings.setPageSize}
initialSortBy={settings.sortBy}
onSortByChange={settings.setSortBy}
searchValue={search}
onSearchChange={setSearch}
/>
</>
);

View file

@ -1,36 +1,25 @@
import create from 'zustand';
import { persist } from 'zustand/middleware';
import { keyBuilder } from '@/react/hooks/useLocalStorage';
import {
paginationSettings,
sortableSettings,
refreshableSettings,
hiddenColumnsSettings,
PaginationTableSettings,
RefreshableTableSettings,
SettableColumnsTableSettings,
SortableTableSettings,
createPersistedStore,
BasicTableSettings,
} from '@/react/components/datatables/types';
interface TableSettings
extends SortableTableSettings,
PaginationTableSettings,
extends BasicTableSettings,
SettableColumnsTableSettings,
RefreshableTableSettings {}
export function createStore(storageKey: string) {
return create<TableSettings>()(
persist(
(set) => ({
...sortableSettings(set),
...paginationSettings(set),
...hiddenColumnsSettings(set),
...refreshableSettings(set),
}),
{
name: keyBuilder(storageKey),
}
)
return createPersistedStore<TableSettings>(
storageKey,
'time',
(set) => ({
...hiddenColumnsSettings(set),
...refreshableSettings(set),
})
);
}

View file

@ -11,17 +11,20 @@ import { withReactQuery } from '@/react-tools/withReactQuery';
import { PageHeader } from '@@/PageHeader';
import { Datatable } from '@@/datatables';
import { Button } from '@@/buttons';
import { createPersistedStore } from '@@/datatables/types';
import { useSearchBarState } from '@@/datatables/SearchBar';
import { notificationsStore } from './notifications-store';
import { ToastNotification } from './types';
import { columns } from './columns';
import { createStore } from './datatable-store';
const storageKey = 'notifications-list';
const useSettingsStore = createStore(storageKey, 'time', true);
const settingsStore = createPersistedStore(storageKey, {
id: 'time',
desc: true,
});
export function NotificationsView() {
const settingsStore = useSettingsStore();
const { user } = useUser();
const userNotifications: ToastNotification[] =
@ -29,9 +32,11 @@ export function NotificationsView() {
[];
const breadcrumbs = 'Notifications';
const settings = useStore(settingsStore);
const [search, setSearch] = useSearchBarState(storageKey);
const {
params: { id },
params: { id: activeItemId },
} = useCurrentStateAndParams();
return (
@ -39,19 +44,22 @@ export function NotificationsView() {
<PageHeader title="Notifications" breadcrumbs={breadcrumbs} reload />
<Datatable
columns={columns}
titleOptions={{
title: 'Notifications',
icon: Bell,
}}
title="Notifications"
titleIcon={Bell}
dataset={userNotifications}
settingsStore={settingsStore}
storageKey="notifications"
emptyContentLabel="No notifications found"
totalCount={userNotifications.length}
renderTableActions={(selectedRows) => (
<TableActions selectedRows={selectedRows} />
)}
initialActiveItem={id}
initialPageSize={settings.pageSize}
onPageSizeChange={settings.setPageSize}
initialSortBy={settings.sortBy}
onSortByChange={settings.setSortBy}
searchValue={search}
onSearchChange={setSearch}
getRowId={(row) => row.id}
highlightedItemId={activeItemId}
/>
</>
);

View file

@ -1,40 +0,0 @@
import create from 'zustand';
import { persist } from 'zustand/middleware';
import { keyBuilder } from '@/react/hooks/useLocalStorage';
import {
paginationSettings,
sortableSettings,
refreshableSettings,
hiddenColumnsSettings,
PaginationTableSettings,
RefreshableTableSettings,
SettableColumnsTableSettings,
SortableTableSettings,
} from '@/react/components/datatables/types';
interface TableSettings
extends SortableTableSettings,
PaginationTableSettings,
SettableColumnsTableSettings,
RefreshableTableSettings {}
export function createStore(
storageKey: string,
initialSortBy?: string,
desc?: boolean
) {
return create<TableSettings>()(
persist(
(set) => ({
...sortableSettings(set, initialSortBy, desc),
...paginationSettings(set),
...hiddenColumnsSettings(set),
...refreshableSettings(set),
}),
{
name: keyBuilder(storageKey),
}
)
);
}

View file

@ -1,33 +1,17 @@
import { useTable, usePagination, useSortBy } from 'react-table';
import { useRowSelectColumn } from '@lineup-lite/hooks';
import { List } from 'react-feather';
import { useStore } from 'zustand';
import { Profile } from '@/portainer/hostmanagement/fdo/model';
import PortainerError from '@/portainer/error';
import { Datatable } from '@@/datatables';
import { createPersistedStore } from '@@/datatables/types';
import { useSearchBarState } from '@@/datatables/SearchBar';
import { PaginationControls } from '@@/PaginationControls';
import { SelectedRowsCount } from '@@/datatables/SelectedRowsCount';
import { TableFooter } from '@@/datatables/TableFooter';
import { useTableSettings } from '@@/datatables/useTableSettings';
import { useRowSelect } from '@@/datatables/useRowSelect';
import {
Table,
TableContainer,
TableHeaderRow,
TableRow,
TableTitle,
} from '@@/datatables';
import {
PaginationTableSettings,
SortableTableSettings,
} from '@@/datatables/types-old';
import { useFDOProfiles } from './useFDOProfiles';
import { useColumns } from './columns';
import { FDOProfilesDatatableActions } from './FDOProfilesDatatableActions';
import { useFDOProfiles } from './useFDOProfiles';
export interface FDOProfilesTableSettings
extends SortableTableSettings,
PaginationTableSettings {}
const storageKey = 'fdoProfiles';
const settingsStore = createPersistedStore(storageKey, 'name');
export interface FDOProfilesDatatableProps {
isFDOEnabled: boolean;
@ -36,132 +20,33 @@ export interface FDOProfilesDatatableProps {
export function FDOProfilesDatatable({
isFDOEnabled,
}: FDOProfilesDatatableProps) {
const { settings, setTableSettings } =
useTableSettings<FDOProfilesTableSettings>();
const columns = useColumns();
const { isLoading, profiles, error } = useFDOProfiles();
const {
getTableProps,
getTableBodyProps,
headerGroups,
page,
prepareRow,
selectedFlatRows,
gotoPage,
setPageSize,
state: { pageIndex, pageSize },
} = useTable<Profile>(
{
defaultCanFilter: false,
columns,
data: profiles,
initialState: {
pageSize: settings.pageSize || 10,
sortBy: [settings.sortBy],
},
isRowSelectable() {
return isFDOEnabled;
},
selectColumnWidth: 5,
},
useSortBy,
usePagination,
useRowSelect,
useRowSelectColumn
);
const tableProps = getTableProps();
const tbodyProps = getTableBodyProps();
const settings = useStore(settingsStore);
const [search, setSearch] = useSearchBarState(storageKey);
const { isLoading, profiles } = useFDOProfiles();
return (
<TableContainer>
<TableTitle icon="list" featherIcon label="Device Profiles">
<Datatable
columns={columns}
dataset={profiles}
initialPageSize={settings.pageSize}
onPageSizeChange={settings.setPageSize}
initialSortBy={settings.sortBy}
onSortByChange={settings.setSortBy}
searchValue={search}
onSearchChange={setSearch}
title="Device Profiles"
titleIcon={List}
disableSelect={!isFDOEnabled}
emptyContentLabel="No profiles found"
getRowId={(row) => row.id.toString()}
isLoading={isLoading}
renderTableActions={(selectedItems) => (
<FDOProfilesDatatableActions
isFDOEnabled={isFDOEnabled}
selectedItems={selectedFlatRows.map((row) => row.original)}
selectedItems={selectedItems}
/>
</TableTitle>
<Table
className={tableProps.className}
role={tableProps.role}
style={tableProps.style}
>
<thead>
{headerGroups.map((headerGroup) => {
const { key, className, role, style } =
headerGroup.getHeaderGroupProps();
return (
<TableHeaderRow<Profile>
key={key}
className={className}
role={role}
style={style}
headers={headerGroup.headers}
/>
);
})}
</thead>
<tbody
className={tbodyProps.className}
role={tbodyProps.role}
style={tbodyProps.style}
>
{!isLoading && profiles && profiles.length > 0 ? (
page.map((row) => {
prepareRow(row);
const { key, className, role, style } = row.getRowProps();
return (
<TableRow<Profile>
cells={row.cells}
key={key}
className={className}
role={role}
style={style}
/>
);
})
) : (
<tr>
<td colSpan={5} className="text-center text-muted">
{userMessage(isLoading, error)}
</td>
</tr>
)}
</tbody>
</Table>
<TableFooter>
<SelectedRowsCount value={selectedFlatRows.length} />
<PaginationControls
showAll
pageLimit={pageSize}
page={pageIndex + 1}
onPageChange={(p) => gotoPage(p - 1)}
totalCount={profiles ? profiles.length : 0}
onPageLimitChange={handlePageSizeChange}
/>
</TableFooter>
</TableContainer>
)}
/>
);
function handlePageSizeChange(pageSize: number) {
setPageSize(pageSize);
setTableSettings((settings) => ({ ...settings, pageSize }));
}
}
function userMessage(isLoading: boolean, error?: PortainerError) {
if (isLoading) {
return 'Loading...';
}
if (error) {
return error.message;
}
return 'No profiles found';
}

View file

@ -1,22 +0,0 @@
import { TableSettingsProvider } from '@@/datatables/useTableSettings';
import {
FDOProfilesDatatable,
FDOProfilesDatatableProps,
} from './FDOProfilesDatatable';
export function FDOProfilesDatatableContainer({
...props
}: FDOProfilesDatatableProps) {
const defaultSettings = {
pageSize: 10,
sortBy: { id: 'name', desc: false },
};
return (
<TableSettingsProvider defaults={defaultSettings} storageKey="fdoProfiles">
{/* eslint-disable-next-line react/jsx-props-no-spreading */}
<FDOProfilesDatatable {...props} />
</TableSettingsProvider>
);
}

View file

@ -0,0 +1 @@
export { FDOProfilesDatatable } from './FDOProfilesDatatable';

View file

@ -11,7 +11,7 @@ import { LoadingButton } from '@@/buttons/LoadingButton';
import { TextTip } from '@@/Tip/TextTip';
import { Input } from '@@/form-components/Input';
import { FDOProfilesDatatableContainer } from '../FDOProfilesDatatable/FDOProfilesDatatableContainer';
import { FDOProfilesDatatable } from '../FDOProfilesDatatable';
import styles from './SettingsFDO.module.css';
import { validationSchema } from './SettingsFDO.validation';
@ -165,7 +165,7 @@ export function SettingsFDO({ settings, onSubmit }: Props) {
Add, Edit and Manage the list of device profiles available
during FDO device setup
</TextTip>
<FDOProfilesDatatableContainer isFDOEnabled={initialFDOEnabled} />
<FDOProfilesDatatable isFDOEnabled={initialFDOEnabled} />
</div>
)}
</WidgetBody>

View file

@ -6,7 +6,7 @@ import { PageHeader } from '@@/PageHeader';
import { useTeams } from '../queries';
import { CreateTeamForm } from './CreateTeamForm';
import { TeamsDatatableContainer } from './TeamsDatatable/TeamsDatatable';
import { TeamsDatatable } from './TeamsDatatable';
export function ListView() {
const { isAdmin } = useUser();
@ -23,7 +23,7 @@ export function ListView() {
)}
{teamsQuery.data && (
<TeamsDatatableContainer teams={teamsQuery.data} isAdmin={isAdmin} />
<TeamsDatatable teams={teamsQuery.data} isAdmin={isAdmin} />
)}
</>
);

View file

@ -1,14 +1,7 @@
import { useRowSelectColumn } from '@lineup-lite/hooks';
import {
Column,
useGlobalFilter,
usePagination,
useRowSelect,
useSortBy,
useTable,
} from 'react-table';
import { Column } from 'react-table';
import { useMutation, useQueryClient } from 'react-query';
import { Trash2, Users } from 'react-feather';
import { useStore } from 'zustand';
import { notifySuccess } from '@/portainer/services/notifications';
import { promiseSequence } from '@/portainer/helpers/promise-utils';
@ -16,23 +9,13 @@ import { Team, TeamId } from '@/react/portainer/users/teams/types';
import { deleteTeam } from '@/react/portainer/users/teams/teams.service';
import { confirmDeletionAsync } from '@/portainer/services/modal.service/confirm';
import { PaginationControls } from '@@/PaginationControls';
import { Checkbox } from '@@/form-components/Checkbox';
import { Table } from '@@/datatables';
import { Datatable } from '@@/datatables';
import { Button } from '@@/buttons';
import { SearchBar, useSearchBarState } from '@@/datatables/SearchBar';
import { TableFooter } from '@@/datatables/TableFooter';
import { SelectedRowsCount } from '@@/datatables/SelectedRowsCount';
import {
TableSettingsProvider,
useTableSettings,
} from '@@/datatables/useTableSettings';
import { TableContent } from '@@/datatables/TableContent';
import { buildNameColumn } from '@@/datatables/NameCell';
import { createPersistedStore } from '@@/datatables/types';
import { useSearchBarState } from '@@/datatables/SearchBar';
import { TableSettings } from './types';
const tableKey = 'teams';
const storageKey = 'teams';
const columns: readonly Column<Team>[] = [
buildNameColumn('Name', 'Id', 'portainer.teams.team'),
@ -43,168 +26,47 @@ interface Props {
isAdmin: boolean;
}
const settingsStore = createPersistedStore(storageKey);
export function TeamsDatatable({ teams, isAdmin }: Props) {
const { handleRemove } = useRemoveMutation();
const [searchBarValue, setSearchBarValue] = useSearchBarState(tableKey);
const { settings, setTableSettings } = useTableSettings<TableSettings>();
const {
getTableProps,
getTableBodyProps,
headerGroups,
page,
prepareRow,
selectedFlatRows,
gotoPage,
setPageSize,
setGlobalFilter,
state: { pageIndex, pageSize },
} = useTable<Team>(
{
defaultCanFilter: false,
columns,
data: teams,
initialState: {
pageSize: settings.pageSize || 10,
sortBy: [settings.sortBy],
globalFilter: searchBarValue,
},
selectCheckboxComponent: Checkbox,
},
useGlobalFilter,
useSortBy,
usePagination,
useRowSelect,
isAdmin ? useRowSelectColumn : emptyPlugin
);
const tableProps = getTableProps();
const tbodyProps = getTableBodyProps();
const settings = useStore(settingsStore);
const [search, setSearch] = useSearchBarState(storageKey);
return (
<div className="row">
<div className="col-sm-12">
<Table.Container>
<Table.Title icon={Users} label="Teams">
<SearchBar
value={searchBarValue}
onChange={handleSearchBarChange}
/>
{isAdmin && (
<Table.Actions>
<Button
color="dangerlight"
onClick={handleRemoveClick}
disabled={selectedFlatRows.length === 0}
icon={Trash2}
>
Remove
</Button>
</Table.Actions>
)}
</Table.Title>
<Table
className={tableProps.className}
role={tableProps.role}
style={tableProps.style}
<Datatable
dataset={teams}
columns={columns}
initialPageSize={settings.pageSize}
onPageSizeChange={settings.setPageSize}
initialSortBy={settings.sortBy}
onSortByChange={settings.setSortBy}
searchValue={search}
onSearchChange={setSearch}
title="Teams"
titleIcon={Users}
renderTableActions={(selectedRows) =>
isAdmin && (
<Button
color="dangerlight"
onClick={() => handleRemoveClick(selectedRows)}
disabled={selectedRows.length === 0}
icon={Trash2}
>
<thead>
{headerGroups.map((headerGroup) => {
const { key, className, role, style } =
headerGroup.getHeaderGroupProps();
return (
<Table.HeaderRow<Team>
key={key}
className={className}
role={role}
style={style}
headers={headerGroup.headers}
onSortChange={handleSortChange}
/>
);
})}
</thead>
<tbody
className={tbodyProps.className}
role={tbodyProps.role}
style={tbodyProps.style}
>
<TableContent
prepareRow={prepareRow}
renderRow={(row, { key, className, role, style }) => (
<Table.Row<Team>
cells={row.cells}
key={key}
className={className}
role={role}
style={style}
/>
)}
rows={page}
emptyContent="No teams found"
/>
</tbody>
</Table>
<TableFooter>
<SelectedRowsCount value={selectedFlatRows.length} />
<PaginationControls
showAll
pageLimit={pageSize}
page={pageIndex + 1}
onPageChange={(p) => gotoPage(p - 1)}
totalCount={teams.length}
onPageLimitChange={handlePageSizeChange}
/>
</TableFooter>
</Table.Container>
</div>
</div>
Remove
</Button>
)
}
emptyContentLabel="No teams found"
/>
);
function handlePageSizeChange(pageSize: number) {
setPageSize(pageSize);
setTableSettings({ pageSize });
}
function handleSearchBarChange(value: string) {
setSearchBarValue(value);
setGlobalFilter(value);
}
function handleSortChange(id: string, desc: boolean) {
setTableSettings({ sortBy: { id, desc } });
}
function handleRemoveClick() {
const ids = selectedFlatRows.map((row) => row.original.Id);
function handleRemoveClick(selectedRows: Team[]) {
const ids = selectedRows.map((row) => row.Id);
handleRemove(ids);
}
}
const defaultSettings: TableSettings = {
pageSize: 10,
sortBy: { id: 'name', desc: false },
};
export function TeamsDatatableContainer(props: Props) {
return (
<TableSettingsProvider<TableSettings>
defaults={defaultSettings}
storageKey={tableKey}
>
{/* eslint-disable-next-line react/jsx-props-no-spreading */}
<TeamsDatatable {...props} />
</TableSettingsProvider>
);
}
function useRemoveMutation() {
const queryClient = useQueryClient();
@ -239,6 +101,3 @@ function useRemoveMutation() {
});
}
}
function emptyPlugin() {}
emptyPlugin.pluginName = 'emptyPlugin';

View file

@ -1,8 +0,0 @@
import {
PaginationTableSettings,
SortableTableSettings,
} from '@@/datatables/types-old';
export interface TableSettings
extends PaginationTableSettings,
SortableTableSettings {}