mirror of
https://github.com/portainer/portainer.git
synced 2025-08-03 04:45:21 +02:00
refactor(ui/datatables): migrate views to use datatable component [EE-4064] (#7609)
This commit is contained in:
parent
0f0513c684
commit
fe8e834dbf
90 changed files with 1714 additions and 2717 deletions
|
@ -1,28 +1,10 @@
|
|||
import { Fragment, useEffect } from 'react';
|
||||
import {
|
||||
useFilters,
|
||||
useGlobalFilter,
|
||||
usePagination,
|
||||
useSortBy,
|
||||
useTable,
|
||||
} from 'react-table';
|
||||
import { useStore } from 'zustand';
|
||||
|
||||
import { NomadEvent } from '@/react/nomad/types';
|
||||
import { useDebouncedValue } from '@/react/hooks/useDebouncedValue';
|
||||
|
||||
import { PaginationControls } from '@@/PaginationControls';
|
||||
import {
|
||||
Table,
|
||||
TableContainer,
|
||||
TableHeaderRow,
|
||||
TableRow,
|
||||
TableTitle,
|
||||
} from '@@/datatables';
|
||||
import { multiple } from '@@/datatables/filter-types';
|
||||
import { useTableSettings } from '@@/datatables/useTableSettings';
|
||||
import { SearchBar, useSearchBarState } from '@@/datatables/SearchBar';
|
||||
import { TableFooter } from '@@/datatables/TableFooter';
|
||||
import { TableContent } from '@@/datatables/TableContent';
|
||||
import { Datatable } from '@@/datatables';
|
||||
import { useSearchBarState } from '@@/datatables/SearchBar';
|
||||
import { createPersistedStore } from '@@/datatables/types';
|
||||
|
||||
import { useColumns } from './columns';
|
||||
|
||||
|
@ -31,133 +13,31 @@ export interface EventsDatatableProps {
|
|||
isLoading: boolean;
|
||||
}
|
||||
|
||||
export interface EventsTableSettings {
|
||||
autoRefreshRate: number;
|
||||
pageSize: number;
|
||||
sortBy: { id: string; desc: boolean };
|
||||
}
|
||||
const storageKey = 'events';
|
||||
|
||||
const settingsStore = createPersistedStore(storageKey, 'Date');
|
||||
|
||||
export function EventsDatatable({ data, isLoading }: EventsDatatableProps) {
|
||||
const { settings, setTableSettings } =
|
||||
useTableSettings<EventsTableSettings>();
|
||||
const [searchBarValue, setSearchBarValue] = useSearchBarState('events');
|
||||
const columns = useColumns();
|
||||
const debouncedSearchValue = useDebouncedValue(searchBarValue);
|
||||
|
||||
const {
|
||||
getTableProps,
|
||||
getTableBodyProps,
|
||||
headerGroups,
|
||||
page,
|
||||
prepareRow,
|
||||
gotoPage,
|
||||
setPageSize,
|
||||
setGlobalFilter,
|
||||
state: { pageIndex, pageSize },
|
||||
} = useTable<NomadEvent>(
|
||||
{
|
||||
defaultCanFilter: false,
|
||||
columns,
|
||||
data,
|
||||
filterTypes: { multiple },
|
||||
initialState: {
|
||||
pageSize: settings.pageSize || 10,
|
||||
sortBy: [settings.sortBy],
|
||||
globalFilter: searchBarValue,
|
||||
},
|
||||
},
|
||||
useFilters,
|
||||
useGlobalFilter,
|
||||
useSortBy,
|
||||
usePagination
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
setGlobalFilter(debouncedSearchValue);
|
||||
}, [debouncedSearchValue, setGlobalFilter]);
|
||||
|
||||
const tableProps = getTableProps();
|
||||
const tbodyProps = getTableBodyProps();
|
||||
const settings = useStore(settingsStore);
|
||||
const [search, setSearch] = useSearchBarState(storageKey);
|
||||
|
||||
return (
|
||||
<TableContainer>
|
||||
<TableTitle icon="fa-history" label="Events" />
|
||||
|
||||
<SearchBar value={searchBarValue} onChange={handleSearchBarChange} />
|
||||
|
||||
<Table
|
||||
className={tableProps.className}
|
||||
role={tableProps.role}
|
||||
style={tableProps.style}
|
||||
>
|
||||
<thead>
|
||||
{headerGroups.map((headerGroup) => {
|
||||
const { key, className, role, style } =
|
||||
headerGroup.getHeaderGroupProps();
|
||||
|
||||
return (
|
||||
<TableHeaderRow<NomadEvent>
|
||||
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
|
||||
rows={page}
|
||||
prepareRow={prepareRow}
|
||||
isLoading={isLoading}
|
||||
emptyContent="No events found"
|
||||
renderRow={(row, { key, className, role, style }) => (
|
||||
<Fragment key={key}>
|
||||
<TableRow<NomadEvent>
|
||||
cells={row.cells}
|
||||
key={key}
|
||||
className={className}
|
||||
role={role}
|
||||
style={style}
|
||||
/>
|
||||
</Fragment>
|
||||
)}
|
||||
/>
|
||||
</tbody>
|
||||
</Table>
|
||||
|
||||
<TableFooter>
|
||||
<PaginationControls
|
||||
showAll
|
||||
pageLimit={pageSize}
|
||||
page={pageIndex + 1}
|
||||
onPageChange={(p) => gotoPage(p - 1)}
|
||||
totalCount={data.length}
|
||||
onPageLimitChange={handlePageSizeChange}
|
||||
/>
|
||||
</TableFooter>
|
||||
</TableContainer>
|
||||
<Datatable
|
||||
isLoading={isLoading}
|
||||
columns={columns}
|
||||
dataset={data}
|
||||
initialPageSize={settings.pageSize}
|
||||
onPageSizeChange={settings.setPageSize}
|
||||
initialSortBy={settings.sortBy}
|
||||
onSortByChange={settings.setSortBy}
|
||||
searchValue={search}
|
||||
onSearchChange={setSearch}
|
||||
titleIcon="fa-history"
|
||||
title="Events"
|
||||
totalCount={data.length}
|
||||
getRowId={(row) => `${row.Date}-${row.Message}-${row.Type}`}
|
||||
disableSelect
|
||||
/>
|
||||
);
|
||||
|
||||
function handlePageSizeChange(pageSize: number) {
|
||||
setPageSize(pageSize);
|
||||
setTableSettings((settings) => ({ ...settings, pageSize }));
|
||||
}
|
||||
|
||||
function handleSearchBarChange(value: string) {
|
||||
setSearchBarValue(value);
|
||||
}
|
||||
|
||||
function handleSortChange(id: string, desc: boolean) {
|
||||
setTableSettings((settings) => ({
|
||||
...settings,
|
||||
sortBy: { id, desc },
|
||||
}));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,9 +1,7 @@
|
|||
import { useCurrentStateAndParams } from '@uirouter/react';
|
||||
|
||||
import { useEnvironmentId } from '@/react/hooks/useEnvironmentId';
|
||||
import { NomadEventsList } from '@/react/nomad/types';
|
||||
|
||||
import { TableSettingsProvider } from '@@/datatables/useTableSettings';
|
||||
import { PageHeader } from '@@/PageHeader';
|
||||
|
||||
import { EventsDatatable } from './EventsDatatable';
|
||||
|
@ -27,14 +25,8 @@ export function EventsView() {
|
|||
{ label: 'Events' },
|
||||
];
|
||||
|
||||
const defaultSettings = {
|
||||
pageSize: 10,
|
||||
sortBy: {},
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
{/* header */}
|
||||
<PageHeader
|
||||
title="Event list"
|
||||
breadcrumbs={breadcrumbs}
|
||||
|
@ -43,20 +35,7 @@ export function EventsView() {
|
|||
onReload={invalidateQuery}
|
||||
/>
|
||||
|
||||
<div className="row">
|
||||
<div className="col-sm-12">
|
||||
<TableSettingsProvider
|
||||
defaults={defaultSettings}
|
||||
storageKey="nomad-events"
|
||||
>
|
||||
{/* events table */}
|
||||
<EventsDatatable
|
||||
data={(query.data || []) as NomadEventsList}
|
||||
isLoading={query.isLoading}
|
||||
/>
|
||||
</TableSettingsProvider>
|
||||
</div>
|
||||
</div>
|
||||
<EventsDatatable data={query.data || []} isLoading={query.isLoading} />
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
|
|
@ -1,40 +1,16 @@
|
|||
import { Fragment, useEffect } from 'react';
|
||||
import {
|
||||
useExpanded,
|
||||
useFilters,
|
||||
useGlobalFilter,
|
||||
usePagination,
|
||||
useSortBy,
|
||||
useTable,
|
||||
} from 'react-table';
|
||||
import { useRowSelectColumn } from '@lineup-lite/hooks';
|
||||
import { useStore } from 'zustand';
|
||||
import { Clock } from 'react-feather';
|
||||
|
||||
import { Job } from '@/react/nomad/types';
|
||||
import { useDebouncedValue } from '@/react/hooks/useDebouncedValue';
|
||||
|
||||
import { PaginationControls } from '@@/PaginationControls';
|
||||
import {
|
||||
Table,
|
||||
TableActions,
|
||||
TableContainer,
|
||||
TableHeaderRow,
|
||||
TableRow,
|
||||
TableTitle,
|
||||
TableSettingsMenu,
|
||||
TableTitleActions,
|
||||
} from '@@/datatables';
|
||||
import { multiple } from '@@/datatables/filter-types';
|
||||
import { useTableSettings } from '@@/datatables/useTableSettings';
|
||||
import { SearchBar, useSearchBarState } from '@@/datatables/SearchBar';
|
||||
import { useRowSelect } from '@@/datatables/useRowSelect';
|
||||
import { TableFooter } from '@@/datatables/TableFooter';
|
||||
import { SelectedRowsCount } from '@@/datatables/SelectedRowsCount';
|
||||
import { TableContent } from '@@/datatables/TableContent';
|
||||
import { useRepeater } from '@@/datatables/useRepeater';
|
||||
import { ExpandableDatatable } from '@@/datatables/ExpandableDatatable';
|
||||
import { TableSettingsMenu } from '@@/datatables';
|
||||
import { useSearchBarState } from '@@/datatables/SearchBar';
|
||||
|
||||
import { JobsTableSettings } from './types';
|
||||
import { TasksDatatable } from './TasksDatatable';
|
||||
import { useColumns } from './columns';
|
||||
import { columns } from './columns';
|
||||
import { createStore } from './datatable-store';
|
||||
import { JobsDatatableSettings } from './JobsDatatableSettings';
|
||||
|
||||
export interface JobsDatatableProps {
|
||||
|
@ -43,162 +19,39 @@ export interface JobsDatatableProps {
|
|||
isLoading?: boolean;
|
||||
}
|
||||
|
||||
const storageKey = 'jobs';
|
||||
const settingsStore = createStore(storageKey);
|
||||
|
||||
export function JobsDatatable({
|
||||
jobs,
|
||||
refreshData,
|
||||
isLoading,
|
||||
}: JobsDatatableProps) {
|
||||
const { settings, setTableSettings } = useTableSettings<JobsTableSettings>();
|
||||
const [searchBarValue, setSearchBarValue] = useSearchBarState('jobs');
|
||||
const columns = useColumns();
|
||||
const debouncedSearchValue = useDebouncedValue(searchBarValue);
|
||||
const [search, setSearch] = useSearchBarState(storageKey);
|
||||
const settings = useStore(settingsStore);
|
||||
useRepeater(settings.autoRefreshRate, refreshData);
|
||||
|
||||
const {
|
||||
getTableProps,
|
||||
getTableBodyProps,
|
||||
headerGroups,
|
||||
page,
|
||||
prepareRow,
|
||||
selectedFlatRows,
|
||||
gotoPage,
|
||||
setPageSize,
|
||||
setGlobalFilter,
|
||||
state: { pageIndex, pageSize },
|
||||
} = useTable<Job>(
|
||||
{
|
||||
defaultCanFilter: false,
|
||||
columns,
|
||||
data: jobs,
|
||||
filterTypes: { multiple },
|
||||
initialState: {
|
||||
pageSize: settings.pageSize || 10,
|
||||
sortBy: [settings.sortBy],
|
||||
globalFilter: searchBarValue,
|
||||
},
|
||||
isRowSelectable() {
|
||||
return false;
|
||||
},
|
||||
autoResetExpanded: false,
|
||||
autoResetSelectedRows: false,
|
||||
selectColumnWidth: 5,
|
||||
getRowId(job, relativeIndex) {
|
||||
return `${job.ID}-${relativeIndex}`;
|
||||
},
|
||||
},
|
||||
useFilters,
|
||||
useGlobalFilter,
|
||||
useSortBy,
|
||||
useExpanded,
|
||||
usePagination,
|
||||
useRowSelect,
|
||||
useRowSelectColumn
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
setGlobalFilter(debouncedSearchValue);
|
||||
}, [debouncedSearchValue, setGlobalFilter]);
|
||||
|
||||
const tableProps = getTableProps();
|
||||
const tbodyProps = getTableBodyProps();
|
||||
|
||||
return (
|
||||
<TableContainer>
|
||||
<TableTitle icon="fa-cubes" label="Nomad Jobs">
|
||||
<TableTitleActions>
|
||||
<TableSettingsMenu>
|
||||
<JobsDatatableSettings />
|
||||
</TableSettingsMenu>
|
||||
</TableTitleActions>
|
||||
</TableTitle>
|
||||
|
||||
<TableActions />
|
||||
|
||||
<SearchBar value={searchBarValue} onChange={handleSearchBarChange} />
|
||||
|
||||
<Table
|
||||
className={tableProps.className}
|
||||
role={tableProps.role}
|
||||
style={tableProps.style}
|
||||
>
|
||||
<thead>
|
||||
{headerGroups.map((headerGroup) => {
|
||||
const { key, className, role, style } =
|
||||
headerGroup.getHeaderGroupProps();
|
||||
|
||||
return (
|
||||
<TableHeaderRow<Job>
|
||||
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
|
||||
rows={page}
|
||||
prepareRow={prepareRow}
|
||||
isLoading={isLoading}
|
||||
emptyContent="No jobs found"
|
||||
renderRow={(row, { key, className, role, style }) => (
|
||||
<Fragment key={key}>
|
||||
<TableRow<Job>
|
||||
cells={row.cells}
|
||||
key={key}
|
||||
className={className}
|
||||
role={role}
|
||||
style={style}
|
||||
/>
|
||||
|
||||
{row.isExpanded && (
|
||||
<tr>
|
||||
<td />
|
||||
<td colSpan={row.cells.length - 1}>
|
||||
<TasksDatatable data={row.original.Tasks} />
|
||||
</td>
|
||||
</tr>
|
||||
)}
|
||||
</Fragment>
|
||||
)}
|
||||
/>
|
||||
</tbody>
|
||||
</Table>
|
||||
|
||||
<TableFooter>
|
||||
<SelectedRowsCount value={selectedFlatRows.length} />
|
||||
<PaginationControls
|
||||
showAll
|
||||
pageLimit={pageSize}
|
||||
page={pageIndex + 1}
|
||||
onPageChange={(p) => gotoPage(p - 1)}
|
||||
totalCount={jobs.length}
|
||||
onPageLimitChange={handlePageSizeChange}
|
||||
/>
|
||||
</TableFooter>
|
||||
</TableContainer>
|
||||
<ExpandableDatatable<Job>
|
||||
dataset={jobs}
|
||||
columns={columns}
|
||||
initialPageSize={settings.pageSize}
|
||||
onPageSizeChange={settings.setPageSize}
|
||||
initialSortBy={settings.sortBy}
|
||||
onSortByChange={settings.setSortBy}
|
||||
searchValue={search}
|
||||
onSearchChange={setSearch}
|
||||
title="Nomad Jobs"
|
||||
titleIcon={Clock}
|
||||
disableSelect
|
||||
emptyContentLabel="No jobs found"
|
||||
renderSubRow={(row) => <TasksDatatable data={row.original.Tasks} />}
|
||||
isLoading={isLoading}
|
||||
renderTableSettings={() => (
|
||||
<TableSettingsMenu>
|
||||
<JobsDatatableSettings settings={settings} />
|
||||
</TableSettingsMenu>
|
||||
)}
|
||||
/>
|
||||
);
|
||||
|
||||
function handlePageSizeChange(pageSize: number) {
|
||||
setPageSize(pageSize);
|
||||
setTableSettings((settings) => ({ ...settings, pageSize }));
|
||||
}
|
||||
|
||||
function handleSearchBarChange(value: string) {
|
||||
setSearchBarValue(value);
|
||||
}
|
||||
|
||||
function handleSortChange(id: string, desc: boolean) {
|
||||
setTableSettings((settings) => ({
|
||||
...settings,
|
||||
sortBy: { id, desc },
|
||||
}));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,11 +1,12 @@
|
|||
import { TableSettingsMenuAutoRefresh } from '@@/datatables/TableSettingsMenuAutoRefresh';
|
||||
import { useTableSettings } from '@@/datatables/useTableSettings';
|
||||
|
||||
import { JobsTableSettings } from './types';
|
||||
import { TableSettings } from './types';
|
||||
|
||||
export function JobsDatatableSettings() {
|
||||
const { settings, setTableSettings } = useTableSettings<JobsTableSettings>();
|
||||
interface Props {
|
||||
settings: TableSettings;
|
||||
}
|
||||
|
||||
export function JobsDatatableSettings({ settings }: Props) {
|
||||
return (
|
||||
<TableSettingsMenuAutoRefresh
|
||||
value={settings.autoRefreshRate}
|
||||
|
@ -14,6 +15,6 @@ export function JobsDatatableSettings() {
|
|||
);
|
||||
|
||||
function handleRefreshRateChange(autoRefreshRate: number) {
|
||||
setTableSettings({ autoRefreshRate });
|
||||
settings.setAutoRefreshRate(autoRefreshRate);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,97 +1,21 @@
|
|||
import { useFilters, usePagination, useSortBy, useTable } from 'react-table';
|
||||
import { useState } from 'react';
|
||||
|
||||
import { Task } from '@/react/nomad/types';
|
||||
|
||||
import { Table, TableContainer, TableHeaderRow, TableRow } from '@@/datatables';
|
||||
import { InnerDatatable } from '@@/datatables/InnerDatatable';
|
||||
import { NestedDatatable } from '@@/datatables/NestedDatatable';
|
||||
|
||||
import { useColumns } from './columns';
|
||||
|
||||
export interface TasksTableProps {
|
||||
export interface Props {
|
||||
data: Task[];
|
||||
}
|
||||
|
||||
export function TasksDatatable({ data }: TasksTableProps) {
|
||||
export function TasksDatatable({ data }: Props) {
|
||||
const columns = useColumns();
|
||||
const [sortBy, setSortBy] = useState({ id: 'taskName', desc: false });
|
||||
|
||||
const { getTableProps, getTableBodyProps, headerGroups, page, prepareRow } =
|
||||
useTable<Task>(
|
||||
{
|
||||
columns,
|
||||
data,
|
||||
initialState: {
|
||||
sortBy: [sortBy],
|
||||
},
|
||||
},
|
||||
useFilters,
|
||||
useSortBy,
|
||||
usePagination
|
||||
);
|
||||
|
||||
const tableProps = getTableProps();
|
||||
const tbodyProps = getTableBodyProps();
|
||||
|
||||
return (
|
||||
<InnerDatatable>
|
||||
<TableContainer>
|
||||
<Table
|
||||
className={tableProps.className}
|
||||
role={tableProps.role}
|
||||
style={tableProps.style}
|
||||
>
|
||||
<thead>
|
||||
{headerGroups.map((headerGroup) => {
|
||||
const { key, className, role, style } =
|
||||
headerGroup.getHeaderGroupProps();
|
||||
|
||||
return (
|
||||
<TableHeaderRow<Task>
|
||||
key={key}
|
||||
className={className}
|
||||
role={role}
|
||||
style={style}
|
||||
headers={headerGroup.headers}
|
||||
onSortChange={handleSortChange}
|
||||
/>
|
||||
);
|
||||
})}
|
||||
</thead>
|
||||
<tbody
|
||||
className={tbodyProps.className}
|
||||
role={tbodyProps.role}
|
||||
style={tbodyProps.style}
|
||||
>
|
||||
{data.length > 0 ? (
|
||||
page.map((row) => {
|
||||
prepareRow(row);
|
||||
const { key, className, role, style } = row.getRowProps();
|
||||
|
||||
return (
|
||||
<TableRow<Task>
|
||||
key={key}
|
||||
cells={row.cells}
|
||||
className={className}
|
||||
role={role}
|
||||
style={style}
|
||||
/>
|
||||
);
|
||||
})
|
||||
) : (
|
||||
<tr>
|
||||
<td colSpan={5} className="text-center text-muted">
|
||||
no tasks
|
||||
</td>
|
||||
</tr>
|
||||
)}
|
||||
</tbody>
|
||||
</Table>
|
||||
</TableContainer>
|
||||
</InnerDatatable>
|
||||
<NestedDatatable
|
||||
columns={columns}
|
||||
dataset={data}
|
||||
defaultSortBy="taskName"
|
||||
/>
|
||||
);
|
||||
|
||||
function handleSortChange(id: string, desc: boolean) {
|
||||
setSortBy({ id, desc });
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,6 +3,7 @@ import { CellProps, Column } from 'react-table';
|
|||
import { Task } from '@/react/nomad/types';
|
||||
|
||||
import { Link } from '@@/Link';
|
||||
import { Icon } from '@@/Icon';
|
||||
|
||||
export const actions: Column<Task> = {
|
||||
Header: 'Task Actions',
|
||||
|
@ -25,7 +26,7 @@ export function ActionsCell({ row }: CellProps<Task>) {
|
|||
};
|
||||
|
||||
return (
|
||||
<div className="text-center">
|
||||
<div className="text-center vertical-center">
|
||||
{/* events */}
|
||||
<Link
|
||||
to="nomad.events"
|
||||
|
@ -33,12 +34,12 @@ export function ActionsCell({ row }: CellProps<Task>) {
|
|||
title="Events"
|
||||
className="space-right"
|
||||
>
|
||||
<i className="fa fa-history space-right" aria-hidden="true" />
|
||||
<Icon icon="clock" feather className="space-right icon" />
|
||||
</Link>
|
||||
|
||||
{/* logs */}
|
||||
<Link to="nomad.logs" params={params} title="Logs">
|
||||
<i className="fa fa-file-alt space-right" aria-hidden="true" />
|
||||
<Icon icon="file-text" feather className="space-right icon" />
|
||||
</Link>
|
||||
</div>
|
||||
);
|
||||
|
|
|
@ -1,8 +1,7 @@
|
|||
import * as notifications from '@/portainer/services/notifications';
|
||||
import { EnvironmentId } from '@/react/portainer/environments/types';
|
||||
import { Job } from '@/react/nomad/types';
|
||||
|
||||
import { deleteJob } from '../../../jobs.service';
|
||||
import { deleteJob } from '@/react/nomad/jobs/jobs.service';
|
||||
|
||||
export async function deleteJobs(environmentID: EnvironmentId, jobs: Job[]) {
|
||||
return Promise.all(
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
import { CellProps, Column } from 'react-table';
|
||||
import { Clock } from 'react-feather';
|
||||
|
||||
import { Job } from '@/react/nomad/types';
|
||||
|
||||
|
@ -18,7 +19,7 @@ export function ActionsCell({ row }: CellProps<Job>) {
|
|||
return (
|
||||
// eslint-disable-next-line react/jsx-props-no-spreading
|
||||
<div className="text-center" {...row.getToggleRowExpandedProps()}>
|
||||
<i className="fa fa-history space-right" aria-hidden="true" />
|
||||
<Clock className="feather" />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
|
|
@ -1,11 +1,7 @@
|
|||
import { useMemo } from 'react';
|
||||
|
||||
import { name } from './name';
|
||||
import { status } from './status';
|
||||
import { created } from './created';
|
||||
import { actions } from './actions';
|
||||
import { namespace } from './namespace';
|
||||
|
||||
export function useColumns() {
|
||||
return useMemo(() => [name, status, namespace, actions, created], []);
|
||||
}
|
||||
export const columns = [name, status, namespace, actions, created];
|
||||
|
|
|
@ -0,0 +1,13 @@
|
|||
import { refreshableSettings, createPersistedStore } from '@@/datatables/types';
|
||||
|
||||
import { TableSettings } from './types';
|
||||
|
||||
export function createStore(storageKey: string) {
|
||||
return createPersistedStore<TableSettings>(
|
||||
storageKey,
|
||||
'SubmitTime',
|
||||
(set) => ({
|
||||
...refreshableSettings(set),
|
||||
})
|
||||
);
|
||||
}
|
|
@ -1,5 +1,8 @@
|
|||
export interface JobsTableSettings {
|
||||
autoRefreshRate: number;
|
||||
pageSize: number;
|
||||
sortBy: { id: string; desc: boolean };
|
||||
}
|
||||
import {
|
||||
BasicTableSettings,
|
||||
RefreshableTableSettings,
|
||||
} from '@@/datatables/types';
|
||||
|
||||
export interface TableSettings
|
||||
extends BasicTableSettings,
|
||||
RefreshableTableSettings {}
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
import { useEnvironmentId } from '@/react/hooks/useEnvironmentId';
|
||||
|
||||
import { PageHeader } from '@@/PageHeader';
|
||||
import { TableSettingsProvider } from '@@/datatables/useTableSettings';
|
||||
|
||||
import { useJobs } from './useJobs';
|
||||
import { JobsDatatable } from './JobsDatatable';
|
||||
|
@ -10,12 +9,6 @@ export function JobsView() {
|
|||
const environmentId = useEnvironmentId();
|
||||
const jobsQuery = useJobs(environmentId);
|
||||
|
||||
const defaultSettings = {
|
||||
autoRefreshRate: 10,
|
||||
pageSize: 10,
|
||||
sortBy: { id: 'name', desc: false },
|
||||
};
|
||||
|
||||
async function reloadData() {
|
||||
await jobsQuery.refetch();
|
||||
}
|
||||
|
@ -30,17 +23,11 @@ export function JobsView() {
|
|||
onReload={reloadData}
|
||||
/>
|
||||
|
||||
<div className="row">
|
||||
<div className="col-sm-12">
|
||||
<TableSettingsProvider defaults={defaultSettings} storageKey="jobs">
|
||||
<JobsDatatable
|
||||
jobs={jobsQuery.data || []}
|
||||
refreshData={reloadData}
|
||||
isLoading={jobsQuery.isLoading}
|
||||
/>
|
||||
</TableSettingsProvider>
|
||||
</div>
|
||||
</div>
|
||||
<JobsDatatable
|
||||
jobs={jobsQuery.data || []}
|
||||
refreshData={reloadData}
|
||||
isLoading={jobsQuery.isLoading}
|
||||
/>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue