Package updates and DataTable migration
Some checks failed
Deploy to production / build (push) Failing after 1m0s
Some checks failed
Deploy to production / build (push) Failing after 1m0s
This commit is contained in:
@@ -118,4 +118,11 @@ sudo pm2 start server.cjs
|
||||
- Mobile improvements
|
||||
- New Carosel on weather description
|
||||
- Updates to weather modal
|
||||
- Reivew Mantine v9 for changes
|
||||
- Add mantine-led for monitoring status (https://gfazioli.github.io/mantine-led)
|
||||
- Update Theme playlists
|
||||
- Include mantine-reflection (https://gfazioli.github.io/mantine-reflection#example-complex-components)
|
||||
- Include mantine-parallax (https://gfazioli.github.io/mantine-parallax#example-presentation)
|
||||
- Include mantine-depth-select (https://gfazioli.github.io/mantine-depth-select/)
|
||||
- Explore https://gfazioli.github.io/mantine-scene/
|
||||
- Explore https://gfazioli.github.io/mantine-window/
|
||||
- Upgrade spinners/loaders (https://gfazioli.github.io/mantine-spinner#example-random)
|
||||
1520
package-lock.json
generated
1520
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
49
package.json
49
package.json
@@ -10,39 +10,40 @@
|
||||
"preview": "vite preview"
|
||||
},
|
||||
"dependencies": {
|
||||
"@gfazioli/mantine-border-animate": "^2.0.9",
|
||||
"@gfazioli/mantine-text-animate": "^4.0.8",
|
||||
"@gfazioli/mantine-border-animate": "^3.0.2",
|
||||
"@gfazioli/mantine-text-animate": "^4.0.10",
|
||||
"@hello-pangea/dnd": "^18.0.1",
|
||||
"@mantine/core": "^9.5.0",
|
||||
"@mantine/dates": "^9.5.0",
|
||||
"@mantine/form": "^9.5.0",
|
||||
"@mantine/hooks": "^9.5.0",
|
||||
"@mantine/notifications": "^9.5.0",
|
||||
"@tanstack/react-query": "^5.101.4",
|
||||
"@tanstack/react-query-devtools": "^5.101.4",
|
||||
"@tanstack/react-query-persist-client": "^5.101.4",
|
||||
"@tanstack/react-table": "^8.21.3",
|
||||
"@mantine/core": "^9.6.2",
|
||||
"@mantine/dates": "^9.6.2",
|
||||
"@mantine/form": "^9.6.2",
|
||||
"@mantine/hooks": "^9.6.2",
|
||||
"@mantine/notifications": "^9.6.2",
|
||||
"@tanstack/react-query": "^5.103.2",
|
||||
"@tanstack/react-query-devtools": "^5.103.2",
|
||||
"@tanstack/react-query-persist-client": "^5.103.2",
|
||||
"@tanstack/react-table": "^9.2.4",
|
||||
"@tanstack/react-virtual": "^3.14.13",
|
||||
"idb-keyval": "^6.3.0",
|
||||
"jotai": "^2.20.2",
|
||||
"jotai": "^3.0.0",
|
||||
"openmeteo": "^1.2.3",
|
||||
"react": "^19.2.8",
|
||||
"react-dom": "^19.2.8",
|
||||
"react": "^19.3.0",
|
||||
"react-dom": "^19.3.0",
|
||||
"react-fontpicker-ts": "^1.3.0",
|
||||
"react-icons": "^5.7.0",
|
||||
"react-router-dom": "^7.18.2",
|
||||
"react-router-dom": "^7.18.4",
|
||||
"recharts": "^3.10.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/node": "^26.1.2",
|
||||
"@types/react": "^19.2.18",
|
||||
"@types/react-dom": "^19.2.4",
|
||||
"@vitejs/plugin-react": "^6.0.5",
|
||||
"@vitest/coverage-v8": "^4.1.10",
|
||||
"@vitest/ui": "^4.1.10",
|
||||
"@types/node": "^26.6.2",
|
||||
"@types/react": "^19.3.0",
|
||||
"@types/react-dom": "^19.3.0",
|
||||
"@vitejs/plugin-react": "^6.1.1",
|
||||
"@vitest/coverage-v8": "^5.0.2",
|
||||
"@vitest/ui": "^5.0.2",
|
||||
"typescript": "^7.0.2",
|
||||
"vite": "^8.2.0",
|
||||
"vite-plugin-dts": "~5.0.3",
|
||||
"vite": "^8.3.1",
|
||||
"vite-plugin-dts": "~5.1.1",
|
||||
"vite-tsconfig-paths": "^6.1.1",
|
||||
"vitest": "^4.1.10"
|
||||
"vitest": "^5.0.2"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,9 +1,20 @@
|
||||
import { ActionIcon, Box, Group, Text } from '@mantine/core';
|
||||
import { createColumnHelper } from '@tanstack/react-table';
|
||||
import {
|
||||
columnFilteringFeature,
|
||||
createColumnHelper,
|
||||
filterFn_includesString,
|
||||
rowSortingFeature,
|
||||
tableFeatures,
|
||||
} from '@tanstack/react-table';
|
||||
import { FaFilter, FaTrash } from 'react-icons/fa';
|
||||
import type { SearchHistoryItem } from 'types';
|
||||
|
||||
const columnHelper = createColumnHelper<SearchHistoryItem>();
|
||||
const features = tableFeatures({
|
||||
rowSortingFeature,
|
||||
columnFilteringFeature,
|
||||
filterFns: { includesString: filterFn_includesString },
|
||||
});
|
||||
const columnHelper = createColumnHelper<typeof features, SearchHistoryItem>();
|
||||
export const SearchHistoryColumns = (
|
||||
setSelectedItem: React.Dispatch<React.SetStateAction<SearchHistoryItem | undefined>>,
|
||||
deleteItemOpen: () => void,
|
||||
@@ -26,7 +37,7 @@ export const SearchHistoryColumns = (
|
||||
</Group>
|
||||
),
|
||||
header: () => (
|
||||
<Group gap={0} justify='center'>
|
||||
<Group gap={0} justify='center' align='center'>
|
||||
<Box
|
||||
w={'1.75rem'}
|
||||
h={'1.75rem'}
|
||||
@@ -48,9 +59,8 @@ export const SearchHistoryColumns = (
|
||||
),
|
||||
meta: {
|
||||
filterVariant: 'counter',
|
||||
width: '32px',
|
||||
},
|
||||
size: 32,
|
||||
maxSize: 32,
|
||||
enableSorting: false,
|
||||
}),
|
||||
columnHelper.accessor('prefix', {
|
||||
@@ -63,27 +73,28 @@ export const SearchHistoryColumns = (
|
||||
header: () => <Text fw={600}>Prefix</Text>,
|
||||
meta: {
|
||||
filterVariant: 'mantineSelect',
|
||||
width: '72px',
|
||||
},
|
||||
filterFn: (row, id, value) => {
|
||||
if (value === null) return true;
|
||||
return row.getValue(id) === value;
|
||||
},
|
||||
size: 32,
|
||||
maxSize: 32,
|
||||
}),
|
||||
columnHelper.accessor('provider', {
|
||||
id: 'provider',
|
||||
cell: ({ cell }: any) => (
|
||||
<Text mx={8} style={{ textAlign: 'center' }}>
|
||||
<Text
|
||||
mx={8}
|
||||
style={{ textAlign: 'center', overflow: 'ellipsis', whiteSpace: 'nowrap' }}
|
||||
>
|
||||
{cell.getValue()}
|
||||
</Text>
|
||||
),
|
||||
header: () => <Text fw={600}>Provider</Text>,
|
||||
meta: {
|
||||
filterVariant: 'mantineSelect',
|
||||
width: '128px',
|
||||
},
|
||||
size: 128,
|
||||
maxSize: 128,
|
||||
}),
|
||||
columnHelper.accessor('searchTerm', {
|
||||
id: 'searchTerm',
|
||||
@@ -93,9 +104,18 @@ export const SearchHistoryColumns = (
|
||||
overflow: 'hidden',
|
||||
whiteSpace: 'nowrap',
|
||||
textOverflow: 'ellipsis',
|
||||
display: 'block',
|
||||
}}
|
||||
>
|
||||
<Text w={'100%'} mx={8} style={{ justifySelf: 'center' }}>
|
||||
<Text
|
||||
mx={8}
|
||||
style={{
|
||||
justifySelf: 'center',
|
||||
overflow: 'hidden',
|
||||
whiteSpace: 'nowrap',
|
||||
textOverflow: 'ellipsis',
|
||||
}}
|
||||
>
|
||||
{cell.getValue()}
|
||||
</Text>
|
||||
</Group>
|
||||
@@ -103,8 +123,9 @@ export const SearchHistoryColumns = (
|
||||
header: () => <Text fw={600}>Search String</Text>,
|
||||
meta: {
|
||||
filterVariant: 'text',
|
||||
width: 'calc(100% - 375px)',
|
||||
},
|
||||
maxSize: 1920,
|
||||
filterFn: 'includesString',
|
||||
}),
|
||||
columnHelper.accessor('dateTimeStamp', {
|
||||
id: 'dateTimeStamp',
|
||||
@@ -126,6 +147,7 @@ export const SearchHistoryColumns = (
|
||||
header: () => <Text fw={600}>Time Stamp</Text>,
|
||||
meta: {
|
||||
filterVariant: 'range',
|
||||
width: '148px',
|
||||
},
|
||||
filterFn: (row, id, value) => {
|
||||
const startDate = new Date(value[0]);
|
||||
@@ -136,8 +158,5 @@ export const SearchHistoryColumns = (
|
||||
}
|
||||
return true;
|
||||
},
|
||||
size: 132,
|
||||
maxSize: 132,
|
||||
minSize: 132,
|
||||
}),
|
||||
];
|
||||
|
||||
@@ -1,40 +1,41 @@
|
||||
import { Button, Group, ScrollArea, Text } from '@mantine/core';
|
||||
import {
|
||||
type ColumnFiltersState,
|
||||
flexRender,
|
||||
getCoreRowModel,
|
||||
getExpandedRowModel,
|
||||
getFacetedMinMaxValues,
|
||||
getFilteredRowModel,
|
||||
getSortedRowModel,
|
||||
type SortingState,
|
||||
useReactTable,
|
||||
} from '@tanstack/react-table';
|
||||
import { type Dispatch, type SetStateAction, useEffect, useState } from 'react';
|
||||
import { scrollAreaClasses } from 'styles';
|
||||
import { Button, Group, Table, Text } from '@mantine/core';
|
||||
import { flexRender, type SortingState, useTable } from '@tanstack/react-table';
|
||||
import { useVirtualizer } from '@tanstack/react-virtual';
|
||||
import { type Dispatch, type SetStateAction, useState } from 'react';
|
||||
import { Filter } from './components';
|
||||
|
||||
export function DataTable({
|
||||
data,
|
||||
columns,
|
||||
features,
|
||||
sorting,
|
||||
setSorting,
|
||||
filtersEnabled,
|
||||
globalFilter,
|
||||
setGlobalFilter,
|
||||
isRefreshing,
|
||||
}: {
|
||||
data: any[];
|
||||
data: any;
|
||||
columns: any[];
|
||||
features: any;
|
||||
sorting: SortingState;
|
||||
setSorting: Dispatch<SetStateAction<SortingState>>;
|
||||
filtersEnabled: boolean;
|
||||
globalFilter: string | number;
|
||||
setGlobalFilter: Dispatch<SetStateAction<string | number>>;
|
||||
isRefreshing?: boolean;
|
||||
}) {
|
||||
const [columnFilters, setColumnFilters] = useState<ColumnFiltersState>([]);
|
||||
const table = useReactTable({
|
||||
const [scrollParent, setScrollParent] = useState<HTMLDivElement | null>(null);
|
||||
|
||||
const virtualizer = useVirtualizer({
|
||||
count: data.length,
|
||||
getScrollElement: () => scrollParent,
|
||||
estimateSize: () => 30,
|
||||
overscan: 5,
|
||||
});
|
||||
|
||||
const virtualItems = virtualizer.getVirtualItems();
|
||||
|
||||
const table = useTable({
|
||||
features,
|
||||
data: data,
|
||||
columns,
|
||||
initialState: {
|
||||
@@ -42,48 +43,24 @@ export function DataTable({
|
||||
},
|
||||
state: {
|
||||
sorting,
|
||||
columnFilters,
|
||||
globalFilter: globalFilter,
|
||||
},
|
||||
getCoreRowModel: getCoreRowModel(),
|
||||
getExpandedRowModel: getExpandedRowModel(),
|
||||
getFilteredRowModel: getFilteredRowModel(),
|
||||
getSortedRowModel: getSortedRowModel(),
|
||||
getFacetedRowModel: getFilteredRowModel(),
|
||||
getFacetedMinMaxValues: getFacetedMinMaxValues(),
|
||||
onColumnFiltersChange: setColumnFilters,
|
||||
enableSorting: true,
|
||||
enableFilters: true,
|
||||
enableGlobalFilter: true,
|
||||
globalFilterFn: 'includesString',
|
||||
onGlobalFilterChange: setGlobalFilter,
|
||||
});
|
||||
|
||||
useEffect(() => {
|
||||
if (!filtersEnabled) {
|
||||
setColumnFilters([]);
|
||||
}
|
||||
}, [filtersEnabled]);
|
||||
const { rows } = table.getRowModel();
|
||||
|
||||
return (
|
||||
<ScrollArea
|
||||
className={scrollAreaClasses.default}
|
||||
classNames={scrollAreaClasses}
|
||||
styles={{
|
||||
scrollbar: {
|
||||
paddingTop: '2.5rem',
|
||||
paddingBottom: '2rem',
|
||||
},
|
||||
}}
|
||||
<Table.ScrollContainer
|
||||
minWidth={'100%'}
|
||||
scrollAreaProps={{ viewportRef: setScrollParent }}
|
||||
>
|
||||
<table
|
||||
<Table
|
||||
style={{
|
||||
width: '100%',
|
||||
borderSpacing: '2px 0px',
|
||||
backgroundColor: 'var(--mantine-color-accent-0)',
|
||||
}}
|
||||
>
|
||||
<thead
|
||||
<Table.Thead
|
||||
style={{
|
||||
position: 'sticky',
|
||||
top: 0,
|
||||
@@ -92,133 +69,159 @@ export function DataTable({
|
||||
}}
|
||||
>
|
||||
{table.getHeaderGroups().map((headerGroup) => (
|
||||
<tr key={headerGroup.id}>
|
||||
{headerGroup.headers.map((header) => (
|
||||
<th
|
||||
key={header.id}
|
||||
style={{
|
||||
width: header.getSize(),
|
||||
padding: 0,
|
||||
}}
|
||||
>
|
||||
{header.isPlaceholder ? null : (
|
||||
<>
|
||||
<Button
|
||||
{...{
|
||||
style: {
|
||||
cursor: 'pointer',
|
||||
borderRadius: '0px',
|
||||
backgroundColor: 'transparent',
|
||||
},
|
||||
px: 0,
|
||||
onClick: () => {
|
||||
if (header.column.getCanSort()) {
|
||||
if (sorting[0].id === header.id) {
|
||||
setSorting([
|
||||
{
|
||||
id: header.id,
|
||||
desc: !sorting[0].desc,
|
||||
},
|
||||
]);
|
||||
} else {
|
||||
setSorting([
|
||||
{
|
||||
id: header.id,
|
||||
desc: false,
|
||||
},
|
||||
]);
|
||||
<Table.Tr key={headerGroup.id}>
|
||||
{headerGroup.headers.map((header: any) => {
|
||||
return (
|
||||
<Table.Th
|
||||
key={header.id}
|
||||
style={{
|
||||
padding: 0,
|
||||
}}
|
||||
w={`${header.column.columnDef.meta?.width}`}
|
||||
>
|
||||
{header.isPlaceholder ? null : (
|
||||
<>
|
||||
<Button
|
||||
{...{
|
||||
style: {
|
||||
cursor: 'pointer',
|
||||
borderRadius: '0px',
|
||||
backgroundColor: 'transparent',
|
||||
},
|
||||
px: 0,
|
||||
w: '100%',
|
||||
onClick: () => {
|
||||
if (header.column.getCanSort()) {
|
||||
if (sorting[0].id === header.id) {
|
||||
setSorting([
|
||||
{
|
||||
id: header.id,
|
||||
desc: !sorting[0].desc,
|
||||
},
|
||||
]);
|
||||
} else {
|
||||
setSorting([
|
||||
{
|
||||
id: header.id,
|
||||
desc: false,
|
||||
},
|
||||
]);
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
}}
|
||||
>
|
||||
<Group align='center' justify='center'>
|
||||
{flexRender(
|
||||
header.column.columnDef.header,
|
||||
header.getContext(),
|
||||
)}
|
||||
{{
|
||||
asc: (
|
||||
<Group gap={0}>
|
||||
<Text c={'var(--mantine-color-accent-0)'}>🠗</Text>
|
||||
<Text>🠕</Text>
|
||||
</Group>
|
||||
),
|
||||
desc: (
|
||||
<Group gap={0}>
|
||||
<Text>🠗</Text>
|
||||
<Text c={'var(--mantine-color-accent-0)'}>🠕</Text>
|
||||
</Group>
|
||||
),
|
||||
}[header.column.getIsSorted() as string] ?? null}
|
||||
</Group>
|
||||
</Button>
|
||||
{filtersEnabled ? (
|
||||
<Filter
|
||||
column={header.column}
|
||||
options={[...new Set(data.map((item: any) => item[header.id]))]}
|
||||
resultCount={table.getFilteredRowModel().rows.length}
|
||||
/>
|
||||
) : null}
|
||||
</>
|
||||
)}
|
||||
</th>
|
||||
))}
|
||||
</tr>
|
||||
},
|
||||
}}
|
||||
>
|
||||
<Group gap={4} align='center' justify='center'>
|
||||
{flexRender(
|
||||
header.column.columnDef.header,
|
||||
header.getContext(),
|
||||
)}
|
||||
{{
|
||||
asc: (
|
||||
<Group gap={0}>
|
||||
<Text c={'var(--mantine-color-accent-0)'}>🠗</Text>
|
||||
<Text>🠕</Text>
|
||||
</Group>
|
||||
),
|
||||
desc: (
|
||||
<Group gap={0}>
|
||||
<Text>🠗</Text>
|
||||
<Text c={'var(--mantine-color-accent-0)'}>🠕</Text>
|
||||
</Group>
|
||||
),
|
||||
}[header.column.getIsSorted() as string] ?? null}
|
||||
</Group>
|
||||
</Button>
|
||||
{filtersEnabled ? (
|
||||
<Filter
|
||||
column={header.column}
|
||||
options={[
|
||||
...new Set(data.map((item: any) => item[header.id])),
|
||||
]}
|
||||
resultCount={table.getFilteredRowModel().rows.length}
|
||||
/>
|
||||
) : null}
|
||||
</>
|
||||
)}
|
||||
</Table.Th>
|
||||
);
|
||||
})}
|
||||
</Table.Tr>
|
||||
))}
|
||||
</thead>
|
||||
<tbody>
|
||||
{table.getRowModel().rows.map((row, index) => (
|
||||
<tr
|
||||
key={row.id}
|
||||
style={{
|
||||
color: 'var(--mantine-color-primary-0)',
|
||||
backgroundColor:
|
||||
index % 2 === 0
|
||||
? 'color-mix(in srgb, var(--mantine-color-background-0), var(--mantine-color-primary-0) 10%)'
|
||||
: 'color-mix(in srgb, var(--mantine-color-background-0), var(--mantine-color-primary-0) 30%)',
|
||||
}}
|
||||
onClick={() => {
|
||||
row.toggleExpanded();
|
||||
}}
|
||||
>
|
||||
{row.getVisibleCells().map((cell) => (
|
||||
<td
|
||||
key={cell.id}
|
||||
style={{
|
||||
width: cell.column.getSize(),
|
||||
}}
|
||||
>
|
||||
{flexRender(cell.column.columnDef.cell, cell.getContext())}
|
||||
</td>
|
||||
))}
|
||||
</Table.Thead>
|
||||
<Table.Tbody>
|
||||
{virtualItems.length > 0 && (
|
||||
<tr aria-hidden>
|
||||
<td
|
||||
aria-hidden
|
||||
colSpan={5}
|
||||
style={{ height: virtualItems[0].start, padding: 0, border: 'none' }}
|
||||
/>
|
||||
</tr>
|
||||
))}
|
||||
</tbody>
|
||||
<tfoot
|
||||
)}
|
||||
{virtualItems.map((virtualItem) => {
|
||||
const row = rows[virtualItem.index];
|
||||
return (
|
||||
<Table.Tr
|
||||
key={row?.id}
|
||||
style={{
|
||||
color: 'var(--mantine-color-primary-0)',
|
||||
backgroundColor:
|
||||
virtualItem.index % 2 === 0
|
||||
? 'color-mix(in srgb, var(--mantine-color-background-0), var(--mantine-color-primary-0) 10%)'
|
||||
: 'color-mix(in srgb, var(--mantine-color-background-0), var(--mantine-color-primary-0) 30%)',
|
||||
}}
|
||||
onClick={() => {
|
||||
row?.toggleExpanded();
|
||||
}}
|
||||
>
|
||||
{row?.getAllCells().map((cell: any) => {
|
||||
return (
|
||||
<Table.Td
|
||||
key={cell.id}
|
||||
style={{
|
||||
maxWidth: `${cell.column.columnDef.meta?.width}`,
|
||||
overflow: 'hidden',
|
||||
textOverflow: 'ellipsis',
|
||||
whiteSpace: 'nowrap',
|
||||
}}
|
||||
>
|
||||
{flexRender(cell.column.columnDef.cell, cell.getContext())}
|
||||
</Table.Td>
|
||||
);
|
||||
})}
|
||||
</Table.Tr>
|
||||
);
|
||||
})}
|
||||
{virtualItems.length > 0 && (
|
||||
<tr aria-hidden>
|
||||
<td
|
||||
aria-hidden
|
||||
colSpan={5}
|
||||
style={{
|
||||
height:
|
||||
virtualizer.getTotalSize() -
|
||||
virtualItems[virtualItems.length - 1].end,
|
||||
padding: 0,
|
||||
border: 'none',
|
||||
}}
|
||||
/>
|
||||
</tr>
|
||||
)}
|
||||
</Table.Tbody>
|
||||
<Table.Tfoot
|
||||
style={{
|
||||
transition: 'all 1s ease',
|
||||
}}
|
||||
>
|
||||
{table.getFooterGroups().map((footerGroup) => (
|
||||
<tr key={footerGroup.id}>
|
||||
{footerGroup.headers.map((header) => (
|
||||
<th key={header.id}>
|
||||
{header.isPlaceholder
|
||||
? null
|
||||
: flexRender(header.column.columnDef.footer, header.getContext())}
|
||||
</th>
|
||||
))}
|
||||
</tr>
|
||||
))}
|
||||
<tr
|
||||
<Table.Tr
|
||||
style={{
|
||||
backgroundColor: 'var(--mantine-color-primary-0)',
|
||||
position: 'sticky',
|
||||
bottom: 0,
|
||||
}}
|
||||
>
|
||||
<td colSpan={5}>
|
||||
<Table.Td colSpan={5}>
|
||||
<Text
|
||||
style={{
|
||||
color: 'var(--mantine-color-background-0)',
|
||||
@@ -228,20 +231,24 @@ export function DataTable({
|
||||
>
|
||||
Total Entries: {table.getCoreRowModel().rows.length}
|
||||
</Text>
|
||||
</td>
|
||||
</tr>
|
||||
<tr
|
||||
</Table.Td>
|
||||
</Table.Tr>
|
||||
<Table.Tr
|
||||
style={{
|
||||
width: '100%',
|
||||
backgroundColor: 'var(--mantine-color-accent-0)',
|
||||
backgroundColor: isRefreshing
|
||||
? 'var(--mantine-color-accent-0)'
|
||||
: 'transparent',
|
||||
position: 'absolute',
|
||||
bottom: isRefreshing ? 0 : -30,
|
||||
bottom: isRefreshing ? 0 : -40,
|
||||
paddingBottom: 6,
|
||||
paddingTop: 6,
|
||||
transition: 'all 1.5s ease-in-out',
|
||||
placeContent: 'center',
|
||||
display: 'flex',
|
||||
}}
|
||||
>
|
||||
<td colSpan={5} width={'100%'} style={{}}>
|
||||
<Table.Td colSpan={5} width={'100%'} style={{}}>
|
||||
<Text
|
||||
style={{
|
||||
color: 'var(--mantine-color-background-0)',
|
||||
@@ -251,10 +258,10 @@ export function DataTable({
|
||||
>
|
||||
Updating
|
||||
</Text>
|
||||
</td>
|
||||
</tr>
|
||||
</tfoot>
|
||||
</table>
|
||||
</ScrollArea>
|
||||
</Table.Td>
|
||||
</Table.Tr>
|
||||
</Table.Tfoot>
|
||||
</Table>
|
||||
</Table.ScrollContainer>
|
||||
);
|
||||
}
|
||||
|
||||
55
src/components/DataTable/components/Features.ts
Normal file
55
src/components/DataTable/components/Features.ts
Normal file
@@ -0,0 +1,55 @@
|
||||
import {
|
||||
columnFacetingFeature,
|
||||
columnFilteringFeature,
|
||||
createExpandedRowModel,
|
||||
createFacetedMinMaxValues,
|
||||
createFacetedRowModel,
|
||||
createFilteredRowModel,
|
||||
createSortedRowModel,
|
||||
filterFn_equalsString,
|
||||
filterFn_includesString,
|
||||
filterFn_inDateRange,
|
||||
globalFilteringFeature,
|
||||
metaHelper,
|
||||
rowExpandingFeature,
|
||||
rowSortingFeature,
|
||||
sortFn_alphanumeric,
|
||||
sortFn_text,
|
||||
tableFeatures,
|
||||
} from '@tanstack/react-table';
|
||||
|
||||
interface ColumnMeta {
|
||||
width?: number | string;
|
||||
filterVariant?:
|
||||
| 'text'
|
||||
| 'range'
|
||||
| 'select'
|
||||
| 'mantineSelect'
|
||||
| 'multiSelect'
|
||||
| 'slider'
|
||||
| 'checkbox'
|
||||
| 'counter'
|
||||
| 'none';
|
||||
}
|
||||
|
||||
const features = tableFeatures({
|
||||
filterFns: {
|
||||
equalsString: filterFn_equalsString,
|
||||
includesString: filterFn_includesString,
|
||||
inDateRange: filterFn_inDateRange,
|
||||
},
|
||||
sortFns: { alphanumeric: sortFn_alphanumeric, text: sortFn_text },
|
||||
filteredRowModel: createFilteredRowModel(),
|
||||
expandedRowModel: createExpandedRowModel(),
|
||||
sortedRowModel: createSortedRowModel(),
|
||||
facetedRowModel: createFacetedRowModel(),
|
||||
facetedMinMaxValues: createFacetedMinMaxValues(),
|
||||
rowSortingFeature,
|
||||
rowExpandingFeature,
|
||||
columnFacetingFeature,
|
||||
columnFilteringFeature,
|
||||
globalFilteringFeature,
|
||||
columnMeta: metaHelper<ColumnMeta>(),
|
||||
});
|
||||
|
||||
export default features;
|
||||
@@ -11,32 +11,15 @@ import {
|
||||
Text,
|
||||
} from '@mantine/core';
|
||||
import { DatePickerInput } from '@mantine/dates';
|
||||
import type { Column, RowData } from '@tanstack/react-table';
|
||||
import { DebouncedInput } from 'components';
|
||||
import { datePickerInputClasses, selectClasses } from 'styles';
|
||||
|
||||
declare module '@tanstack/react-table' {
|
||||
//allows us to define custom properties for our columns
|
||||
interface ColumnMeta<_TData extends RowData, _TValue> {
|
||||
filterVariant?:
|
||||
| 'text'
|
||||
| 'range'
|
||||
| 'select'
|
||||
| 'mantineSelect'
|
||||
| 'multiSelect'
|
||||
| 'slider'
|
||||
| 'checkbox'
|
||||
| 'counter'
|
||||
| 'none';
|
||||
}
|
||||
}
|
||||
|
||||
export function Filter({
|
||||
column,
|
||||
options,
|
||||
resultCount,
|
||||
}: {
|
||||
column: Column<unknown>;
|
||||
column: any;
|
||||
options: any;
|
||||
resultCount?: number;
|
||||
}) {
|
||||
|
||||
@@ -61,7 +61,9 @@ export default function CurrentWeather({
|
||||
<Text>Humidity</Text>
|
||||
</Group>
|
||||
}
|
||||
rightSide={<Text>{current.current.relative_humidity_2m?.toFixed(0)}%</Text>}
|
||||
rightSide={
|
||||
<Text>{current.current.relative_humidity_2m?.toFixed(0)}%</Text>
|
||||
}
|
||||
highlight='right'
|
||||
/>
|
||||
<WeatherFeaturePill
|
||||
|
||||
@@ -10,6 +10,7 @@ import { useCommonHooks, useQueryAPI } from 'hooks';
|
||||
import { useEffect, useState } from 'react';
|
||||
import { textClasses } from 'styles';
|
||||
import type { SearchHistoryItem } from 'types';
|
||||
import features from '../../../../components/DataTable/components/Features';
|
||||
|
||||
export function SearchHistory() {
|
||||
const searchEndpoint = 'api/searchHistory';
|
||||
@@ -101,11 +102,11 @@ export function SearchHistory() {
|
||||
filtersEnabled,
|
||||
setFiltersEnabled,
|
||||
)}
|
||||
features={features}
|
||||
sorting={sorting}
|
||||
setSorting={setSorting}
|
||||
filtersEnabled={filtersEnabled}
|
||||
globalFilter={globalFilter}
|
||||
setGlobalFilter={setGlobalFilter}
|
||||
isRefreshing={historyDataIsFetching}
|
||||
/>
|
||||
</Stack>
|
||||
|
||||
Reference in New Issue
Block a user