Update table component
This commit is contained in:
parent
d1c038ea6f
commit
2b0d4c44a6
9 changed files with 189 additions and 88 deletions
|
@ -31,7 +31,6 @@ export const AlbumArtistCell = ({ value, data }: ICellRendererParams) => {
|
|||
<React.Fragment key={`row-${item.id}-${data.uniqueId}`}>
|
||||
{index > 0 && (
|
||||
<Text
|
||||
$link
|
||||
$secondary
|
||||
size="sm"
|
||||
style={{ display: 'inline-block' }}
|
||||
|
|
|
@ -31,7 +31,6 @@ export const ArtistCell = ({ value, data }: ICellRendererParams) => {
|
|||
<React.Fragment key={`row-${item.id}-${data.uniqueId}`}>
|
||||
{index > 0 && (
|
||||
<Text
|
||||
$link
|
||||
$secondary
|
||||
size="sm"
|
||||
style={{ display: 'inline-block' }}
|
||||
|
|
|
@ -11,6 +11,7 @@ import { Text } from '/@/renderer/components/text';
|
|||
import { AppRoute } from '/@/renderer/router/routes';
|
||||
import { ServerType } from '/@/renderer/types';
|
||||
import { Skeleton } from '/@/renderer/components/skeleton';
|
||||
import { CELL_VARIANTS } from '/@/renderer/components/virtual-table/cells/generic-cell';
|
||||
|
||||
const CellContainer = styled(motion.div)<{ height: number }>`
|
||||
display: grid;
|
||||
|
|
|
@ -1,12 +1,20 @@
|
|||
import type { ICellRendererParams } from '@ag-grid-community/core';
|
||||
import { motion, Variants } from 'framer-motion';
|
||||
import { Link } from 'react-router-dom';
|
||||
import styled from 'styled-components';
|
||||
import { Skeleton } from '/@/renderer/components/skeleton';
|
||||
import { Text } from '/@/renderer/components/text';
|
||||
|
||||
export const CellContainer = styled.div<{
|
||||
position?: 'left' | 'center' | 'right';
|
||||
}>`
|
||||
export const CELL_VARIANTS: Variants = {
|
||||
animate: {
|
||||
opacity: 1,
|
||||
},
|
||||
initial: {
|
||||
opacity: 0,
|
||||
},
|
||||
};
|
||||
|
||||
export const CellContainer = styled(motion.div)<{ position?: 'left' | 'center' | 'right' }>`
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: ${(props) =>
|
||||
|
|
|
@ -17,7 +17,6 @@ export const GenreCell = ({ value, data }: ICellRendererParams) => {
|
|||
<React.Fragment key={`row-${item.id}-${data.uniqueId}`}>
|
||||
{index > 0 && (
|
||||
<Text
|
||||
$link
|
||||
$secondary
|
||||
size="sm"
|
||||
style={{ display: 'inline-block' }}
|
||||
|
|
|
@ -71,6 +71,26 @@ const tableColumns: { [key: string]: ColDef } = {
|
|||
valueFormatter: (params: ValueFormatterParams) => `${params.value} kbps`,
|
||||
valueGetter: (params: ValueGetterParams) => (params.data ? params.data.bitRate : undefined),
|
||||
},
|
||||
bpm: {
|
||||
cellRenderer: (params: ICellRendererParams) => GenericCell(params, { position: 'center' }),
|
||||
colId: TableColumn.BPM,
|
||||
headerComponent: (params: IHeaderParams) => GenericTableHeader(params, { position: 'center' }),
|
||||
headerName: 'BPM',
|
||||
valueGetter: (params: ValueGetterParams) => (params.data ? params.data.bpm : undefined),
|
||||
},
|
||||
channels: {
|
||||
cellRenderer: (params: ICellRendererParams) => GenericCell(params, { position: 'center' }),
|
||||
colId: TableColumn.CHANNELS,
|
||||
field: 'channels',
|
||||
headerComponent: (params: IHeaderParams) => GenericTableHeader(params, { position: 'center' }),
|
||||
valueGetter: (params: ValueGetterParams) => (params.data ? params.data.channels : undefined),
|
||||
},
|
||||
comment: {
|
||||
cellRenderer: GenericCell,
|
||||
colId: TableColumn.COMMENT,
|
||||
headerName: 'Note',
|
||||
valueGetter: (params: ValueGetterParams) => (params.data ? params.data.comment : undefined),
|
||||
},
|
||||
dateAdded: {
|
||||
cellRenderer: (params: ICellRendererParams) => GenericCell(params, { position: 'left' }),
|
||||
colId: TableColumn.DATE_ADDED,
|
||||
|
@ -106,6 +126,27 @@ const tableColumns: { [key: string]: ColDef } = {
|
|||
headerName: 'Genre',
|
||||
valueGetter: (params: ValueGetterParams) => (params.data ? params.data.genres : undefined),
|
||||
},
|
||||
lastPlayedAt: {
|
||||
cellRenderer: GenericCell,
|
||||
colId: TableColumn.LAST_PLAYED,
|
||||
headerName: 'Last Played',
|
||||
valueGetter: (params: ValueGetterParams) =>
|
||||
params.data ? params.data.lastPlayedAt : undefined,
|
||||
},
|
||||
path: {
|
||||
cellRenderer: GenericCell,
|
||||
colId: TableColumn.PATH,
|
||||
headerName: 'Path',
|
||||
valueGetter: (params: ValueGetterParams) => (params.data ? params.data.path : undefined),
|
||||
},
|
||||
playCount: {
|
||||
cellRenderer: (params: ICellRendererParams) => GenericCell(params, { position: 'center' }),
|
||||
colId: TableColumn.PLAY_COUNT,
|
||||
field: 'playCount',
|
||||
headerComponent: (params: IHeaderParams) => GenericTableHeader(params, { position: 'center' }),
|
||||
headerName: 'Plays',
|
||||
valueGetter: (params: ValueGetterParams) => (params.data ? params.data.playCount : undefined),
|
||||
},
|
||||
releaseDate: {
|
||||
cellRenderer: (params: ICellRendererParams) => GenericCell(params, { position: 'center' }),
|
||||
colId: TableColumn.RELEASE_DATE,
|
||||
|
|
|
@ -7,7 +7,7 @@ import { Text } from '/@/renderer/components/text';
|
|||
import { useSettingsStoreActions, useSettingsStore } from '/@/renderer/store/settings.store';
|
||||
import { TableColumn, TableType } from '/@/renderer/types';
|
||||
|
||||
export const tableColumns = [
|
||||
export const SONG_TABLE_COLUMNS = [
|
||||
{ label: 'Row Index', value: TableColumn.ROW_INDEX },
|
||||
{ label: 'Title', value: TableColumn.TITLE },
|
||||
{ label: 'Title (Combined)', value: TableColumn.TITLE_COMBINED },
|
||||
|
@ -21,13 +21,17 @@ export const tableColumns = [
|
|||
{ label: 'Disc Number', value: TableColumn.DISC_NUMBER },
|
||||
{ label: 'Track Number', value: TableColumn.TRACK_NUMBER },
|
||||
{ label: 'Bitrate', value: TableColumn.BIT_RATE },
|
||||
// { label: 'Size', value: TableColumn.SIZE },
|
||||
// { label: 'Skip', value: TableColumn.SKIP },
|
||||
// { label: 'Path', value: TableColumn.PATH },
|
||||
// { label: 'Play Count', value: TableColumn.PLAY_COUNT },
|
||||
{ label: 'Last Played', value: TableColumn.LAST_PLAYED },
|
||||
{ label: 'Note', value: TableColumn.COMMENT },
|
||||
{ label: 'Channels', value: TableColumn.CHANNELS },
|
||||
{ label: 'BPM', value: TableColumn.BPM },
|
||||
{ label: 'Date Added', value: TableColumn.DATE_ADDED },
|
||||
{ label: 'Path', value: TableColumn.PATH },
|
||||
{ label: 'Plays', value: TableColumn.PLAY_COUNT },
|
||||
// { label: 'Favorite', value: TableColumn.FAVORITE },
|
||||
// { label: 'Rating', value: TableColumn.RATING },
|
||||
{ label: 'Date Added', value: TableColumn.DATE_ADDED },
|
||||
// { label: 'Size', value: TableColumn.SIZE },
|
||||
// { label: 'Skip', value: TableColumn.SKIP },
|
||||
];
|
||||
|
||||
interface TableConfigDropdownProps {
|
||||
|
@ -130,7 +134,7 @@ export const TableConfigDropdown = ({ type }: TableConfigDropdownProps) => {
|
|||
<Text>Table Columns</Text>
|
||||
<MultiSelect
|
||||
clearable
|
||||
data={tableColumns}
|
||||
data={SONG_TABLE_COLUMNS}
|
||||
defaultValue={tableConfig[type]?.columns.map((column) => column.column)}
|
||||
dropdownPosition="top"
|
||||
width={300}
|
||||
|
|
|
@ -1,46 +1,87 @@
|
|||
import type { AgGridReact as AgGridReactType } from '@ag-grid-community/react/lib/agGridReact';
|
||||
import { Group } from '@mantine/core';
|
||||
import { useForm } from '@mantine/form';
|
||||
import { useDisclosure } from '@mantine/hooks';
|
||||
import { MutableRefObject } from 'react';
|
||||
import { RiHashtag } from 'react-icons/ri';
|
||||
import { Button } from '/@/renderer/components/button';
|
||||
import { MotionFlex } from '../motion';
|
||||
import { NumberInput } from '/@/renderer/components/input';
|
||||
import { Pagination } from '/@/renderer/components/pagination';
|
||||
import { Popover } from '/@/renderer/components/popover';
|
||||
import { Text } from '/@/renderer/components/text';
|
||||
import { useContainerQuery } from '/@/renderer/hooks';
|
||||
import { TablePagination as TablePaginationType } from '/@/renderer/types';
|
||||
|
||||
interface TablePaginationProps {
|
||||
containerQuery: ReturnType<typeof useContainerQuery>;
|
||||
pagination: {
|
||||
currentPage: number;
|
||||
itemsPerPage: number;
|
||||
totalPages: number;
|
||||
};
|
||||
tableRef: any;
|
||||
pagination: TablePaginationType;
|
||||
setPagination: (pagination: Partial<TablePaginationType>) => void;
|
||||
tableRef: MutableRefObject<AgGridReactType | null>;
|
||||
}
|
||||
|
||||
export const TablePagination = ({ tableRef, containerQuery, pagination }: TablePaginationProps) => {
|
||||
export const TablePagination = ({ tableRef, pagination, setPagination }: TablePaginationProps) => {
|
||||
const [isGoToPageOpen, handlers] = useDisclosure(false);
|
||||
const containerQuery = useContainerQuery();
|
||||
|
||||
const form = useForm({
|
||||
const goToForm = useForm({
|
||||
initialValues: {
|
||||
pageNumber: undefined,
|
||||
},
|
||||
});
|
||||
|
||||
const handlePagination = (index: number) => {
|
||||
tableRef.current?.api.paginationGoToPage(index - 1);
|
||||
const newPage = index - 1;
|
||||
tableRef.current?.api.paginationGoToPage(newPage);
|
||||
setPagination({ currentPage: newPage });
|
||||
};
|
||||
|
||||
const handleGoSubmit = form.onSubmit((values) => {
|
||||
const handleGoSubmit = goToForm.onSubmit((values) => {
|
||||
handlers.close();
|
||||
if (!values.pageNumber || values.pageNumber < 1 || values.pageNumber > pagination.totalPages) {
|
||||
return;
|
||||
}
|
||||
|
||||
tableRef.current?.api.paginationGoToPage(values.pageNumber - 1);
|
||||
const newPage = values.pageNumber - 1;
|
||||
tableRef.current?.api.paginationGoToPage(newPage);
|
||||
setPagination({ currentPage: newPage });
|
||||
});
|
||||
|
||||
const currentPageStartIndex = pagination.currentPage * pagination.itemsPerPage + 1;
|
||||
const currentPageStopIndex = (pagination.currentPage + 1) * pagination.itemsPerPage;
|
||||
|
||||
return (
|
||||
<MotionFlex
|
||||
ref={containerQuery.ref}
|
||||
layout
|
||||
align="center"
|
||||
animate={{ y: 0 }}
|
||||
exit={{ y: 50 }}
|
||||
initial={{ y: 50 }}
|
||||
justify="space-between"
|
||||
p="1rem"
|
||||
sx={{ borderTop: '1px solid var(--generic-border-color)' }}
|
||||
>
|
||||
<Text
|
||||
$secondary
|
||||
size="md"
|
||||
>
|
||||
{containerQuery.isMd ? (
|
||||
<>
|
||||
Showing <b>{currentPageStartIndex}</b> - <b>{currentPageStopIndex}</b> of{' '}
|
||||
<b>{pagination.totalItems}</b> items
|
||||
</>
|
||||
) : containerQuery.isSm ? (
|
||||
<>
|
||||
<b>{currentPageStartIndex}</b> - <b>{currentPageStopIndex}</b> of{' '}
|
||||
<b>{pagination.totalItems}</b> items
|
||||
</>
|
||||
) : (
|
||||
<>
|
||||
<b>{currentPageStartIndex}</b> - <b>{currentPageStopIndex}</b> of{' '}
|
||||
<b>{pagination.totalItems}</b>
|
||||
</>
|
||||
)}
|
||||
</Text>
|
||||
<Group
|
||||
ref={containerQuery.ref}
|
||||
noWrap
|
||||
|
@ -70,7 +111,7 @@ export const TablePagination = ({ tableRef, containerQuery, pagination }: TableP
|
|||
<form onSubmit={handleGoSubmit}>
|
||||
<Group>
|
||||
<NumberInput
|
||||
{...form.getInputProps('pageNumber')}
|
||||
{...goToForm.getInputProps('pageNumber')}
|
||||
hideControls={false}
|
||||
max={pagination.totalPages}
|
||||
min={1}
|
||||
|
@ -86,19 +127,18 @@ export const TablePagination = ({ tableRef, containerQuery, pagination }: TableP
|
|||
</form>
|
||||
</Popover.Dropdown>
|
||||
</Popover>
|
||||
|
||||
<Pagination
|
||||
noWrap
|
||||
$hideDividers={!containerQuery.isMd}
|
||||
boundaries={1}
|
||||
page={pagination.currentPage + 1}
|
||||
radius="sm"
|
||||
// siblings={containerQuery.isSm ? 1 : 0}
|
||||
siblings={1}
|
||||
total={pagination.totalPages - 1}
|
||||
withControls={containerQuery.isSm}
|
||||
onChange={handlePagination}
|
||||
/>
|
||||
</Group>
|
||||
</MotionFlex>
|
||||
);
|
||||
};
|
||||
|
|
|
@ -1,6 +1,13 @@
|
|||
import { Album, AlbumArtist, Artist } from '/@/renderer/api/types';
|
||||
import { AppRoute } from '/@/renderer/router/routes';
|
||||
|
||||
export type TablePagination = {
|
||||
currentPage: number;
|
||||
itemsPerPage: number;
|
||||
totalItems: number;
|
||||
totalPages: number;
|
||||
};
|
||||
|
||||
export type RouteSlug = {
|
||||
idProperty: string;
|
||||
slugProperty: string;
|
||||
|
@ -128,18 +135,21 @@ export enum TableColumn {
|
|||
ALBUM_ARTIST = 'albumArtist',
|
||||
ARTIST = 'artist',
|
||||
BIT_RATE = 'bitRate',
|
||||
BPM = 'bpm',
|
||||
CHANNELS = 'channels',
|
||||
COMMENT = 'comment',
|
||||
DATE_ADDED = 'dateAdded',
|
||||
DISC_NUMBER = 'discNumber',
|
||||
DURATION = 'duration',
|
||||
// FAVORITE = 'favorite',
|
||||
FAVORITE = 'favorite',
|
||||
GENRE = 'genre',
|
||||
// PATH = 'path',
|
||||
// PLAY_COUNT = 'playCount',
|
||||
// RATING = 'rating',
|
||||
LAST_PLAYED = 'lastPlayedAt',
|
||||
PATH = 'path',
|
||||
PLAY_COUNT = 'playCount',
|
||||
RATING = 'rating',
|
||||
RELEASE_DATE = 'releaseDate',
|
||||
ROW_INDEX = 'rowIndex',
|
||||
// SKIP = 'skip',
|
||||
// SIZE = 'size',
|
||||
TITLE = 'title',
|
||||
TITLE_COMBINED = 'titleCombined',
|
||||
TRACK_NUMBER = 'trackNumber',
|
||||
|
|
Reference in a new issue