Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@
"@tanstack/react-form": "^1.33.0",
"@tanstack/react-query": "^5.101.2",
"@tanstack/react-router": "^1.170.17",
"@tanstack/react-table": "^8.21.3",
"@tanstack/react-table": "^9.1.1",
"axios": "^1.18.1",
"class-variance-authority": "^0.7.1",
"clsx": "^2.1.1",
Expand Down
324 changes: 42 additions & 282 deletions pnpm-lock.yaml

Large diffs are not rendered by default.

4 changes: 4 additions & 0 deletions pnpm-workspace.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -6,3 +6,7 @@ trustLockfile: true
allowBuilds:
msgpackr-extract: false
msw: false

minimumReleaseAgeExclude:
- '@tanstack/react-table@9.1.1'
- '@tanstack/table-core@9.1.1'
69 changes: 47 additions & 22 deletions src/components/ui/data-table.tsx
Original file line number Diff line number Diff line change
@@ -1,13 +1,20 @@
import {
type CellData,
type ColumnDef,
type Row,
type RowData,
type SortingState,
type TableFeatures,
type TableMeta,
createSortedRowModel,
flexRender,
getCoreRowModel,
getSortedRowModel,
useReactTable,
rowSortingFeature,
sortFn_alphanumeric,
sortFn_basic,
sortFn_datetime,
sortFn_text,
tableFeatures,
useTable,
} from "@tanstack/react-table";
import { memo, useState } from "react";

Expand All @@ -20,24 +27,48 @@ import {
TableRow,
} from "@/components/ui/table";


interface DataTableProps<TData extends RowData> {
columns: ColumnDef<typeof dataTableFeatures, TData>[];
data: TData[];
meta?: TableMeta<typeof dataTableFeatures, TData>;
}

declare module "@tanstack/react-table" {
interface ColumnMeta<TData extends RowData, TValue> {
interface ColumnMeta<
TFeatures extends TableFeatures,
TData extends RowData,
TValue extends CellData = CellData,
> {
className?: string;
}
}

interface DataTableProps<TData, TValue> {
columns: ColumnDef<TData, TValue>[];
data: TData[];
meta?: TableMeta<TData>;
}
export const dataTableFeatures = tableFeatures({
rowSortingFeature,
sortedRowModel: createSortedRowModel(),
sortFns: {
alphanumeric: sortFn_alphanumeric,
basic: sortFn_basic,
datetime: sortFn_datetime,
text: sortFn_text,
},
});

const DataTableRow = memo(
DataTableRowImpl,
(prev, next) => prev.row.original === next.row.original && prev.meta === next.meta,
) as typeof DataTableRowImpl;

function DataTableRowImpl<TData>({
function DataTableRowImpl<TData extends RowData>({
row,
}: Readonly<{ meta: TableMeta<TData> | undefined ; row: Row<TData> }>) {
}: Readonly<{
meta: TableMeta<typeof dataTableFeatures, TData> | undefined;
row: Row<typeof dataTableFeatures, TData>;
}>) {
return (
<TableRow>
{row.getVisibleCells().map((cell) => (
{row.getAllCells().map((cell) => (
<TableCell key={cell.id} className={cell.column.columnDef.meta?.className}>
{flexRender(cell.column.columnDef.cell, cell.getContext())}
</TableCell>
Expand All @@ -46,24 +77,18 @@ function DataTableRowImpl<TData>({
);
}

const DataTableRow = memo(
DataTableRowImpl,
(prev, next) => prev.row.original === next.row.original && prev.meta === next.meta,
) as typeof DataTableRowImpl;

export function DataTable<TData, TValue>({
export function DataTable<TData extends RowData>({
columns,
data,
meta,
}: Readonly<DataTableProps<TData, TValue>>) {
}: Readonly<DataTableProps<TData>>) {
const [sorting, setSorting] = useState<SortingState>([]);

const table = useReactTable({
const table = useTable({
features: dataTableFeatures,
data,
columns,
meta,
getCoreRowModel: getCoreRowModel(),
getSortedRowModel: getSortedRowModel(),
onSortingChange: setSorting,
state: { sorting },
});
Expand Down
15 changes: 10 additions & 5 deletions src/routes/dashboard/admin/members.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,11 @@
import { queryOptions, useMutation, useQuery, useQueryClient } from "@tanstack/react-query";
import { createFileRoute } from "@tanstack/react-router";
import { type ColumnDef, type RowData, type TableMeta } from "@tanstack/react-table";
import {
type ColumnDef,
type RowData,
type TableFeatures,
type TableMeta,
} from "@tanstack/react-table";
import axios from "axios";
import {
type LucideIcon,
Expand All @@ -27,7 +32,7 @@ import {
import { Avatar, AvatarFallback } from "@/components/ui/avatar";
import { Badge } from "@/components/ui/badge";
import { Button } from "@/components/ui/button";
import { DataTable } from "@/components/ui/data-table";
import { type dataTableFeatures, DataTable } from "@/components/ui/data-table";
import {
Dialog,
DialogContent,
Expand Down Expand Up @@ -110,7 +115,7 @@ interface RoleModifyVars {
}

declare module "@tanstack/react-table" {
interface TableMeta<TData extends RowData> {
interface TableMeta<TFeatures extends TableFeatures, TData extends RowData> {
members?: MembersMeta;
}
}
Expand Down Expand Up @@ -172,7 +177,7 @@ const EMPTY_ROLES: Role[] = [];
const ACTIONS_TRIGGER = <Button variant="ghost" size="icon-sm" className="text-brand-text-sub" />;
const REGISTERED_FMT = new Intl.DateTimeFormat("en-US", { month: "short", year: "numeric" });

const MEMBER_COLUMNS: ColumnDef<AdminMember>[] = [
const MEMBER_COLUMNS: ColumnDef<typeof dataTableFeatures, AdminMember>[] = [
{
id: "member",
header: "Member",
Expand Down Expand Up @@ -479,7 +484,7 @@ function MembersPage() {
[rows, page],
);

const tableMeta = useMemo<TableMeta<AdminMember>>(
const tableMeta = useMemo<TableMeta<typeof dataTableFeatures, AdminMember>>(
() => ({ members: { meId, onManage: openManage, onAskDelete: askDelete } }),
[meId, openManage, askDelete],
);
Expand Down
15 changes: 10 additions & 5 deletions src/routes/dashboard/admin/tags.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,12 @@
import { useForm } from "@tanstack/react-form";
import { queryOptions, useMutation, useQuery, useQueryClient } from "@tanstack/react-query";
import { createFileRoute } from "@tanstack/react-router";
import { type ColumnDef, type RowData, type TableMeta } from "@tanstack/react-table";
import {
type ColumnDef,
type RowData,
type TableFeatures,
type TableMeta,
} from "@tanstack/react-table";
import axios from "axios";
import {
AlertTriangle,
Expand All @@ -28,7 +33,7 @@ import {
} from "@/components/app/sudo-dialog";
import { Badge } from "@/components/ui/badge";
import { Button } from "@/components/ui/button";
import { DataTable } from "@/components/ui/data-table";
import { type dataTableFeatures, DataTable } from "@/components/ui/data-table";
import {
Dialog,
DialogContent,
Expand Down Expand Up @@ -107,7 +112,7 @@ interface EditVars extends TagVars {
}

declare module "@tanstack/react-table" {
interface TableMeta<TData extends RowData> {
interface TableMeta<TFeatures extends TableFeatures, TData extends RowData> {
tags?: TagsMeta;
}
}
Expand All @@ -124,7 +129,7 @@ const EMPTY_TAGS: FullTags[] = [];
const ACTIONS_TRIGGER = <Button variant="ghost" size="icon-sm" className="text-brand-text-sub" />;
const DESCRIPTION_MAX = 128;

const TAG_COLUMNS: ColumnDef<FullTags>[] = [
const TAG_COLUMNS: ColumnDef<typeof dataTableFeatures, FullTags>[] = [
{
id: "tag",
header: "Tag",
Expand Down Expand Up @@ -476,7 +481,7 @@ function TagsPage() {
() => filtered.slice((page - 1) * TABLE_PAGE_SIZE, page * TABLE_PAGE_SIZE),
[filtered, page],
);
const tableMeta = useMemo<TableMeta<FullTags>>(
const tableMeta = useMemo<TableMeta<typeof dataTableFeatures, FullTags>>(
() => ({ tags: { onEdit: openEdit, onDelete: removeTag } }),
[openEdit, removeTag],
);
Expand Down
15 changes: 10 additions & 5 deletions src/routes/dashboard/manage/events.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,12 @@ import {
useQueryClient,
} from "@tanstack/react-query";
import { createFileRoute } from "@tanstack/react-router";
import { type ColumnDef, type RowData, type TableMeta } from "@tanstack/react-table";
import {
type ColumnDef,
type RowData,
type TableFeatures,
type TableMeta,
} from "@tanstack/react-table";
import axios from "axios";
import { blake3 } from "hash-wasm";
import {
Expand All @@ -34,7 +39,7 @@ import { EmptyState } from "@/components/app/dashboard-events";
import { DataPagination } from "@/components/app/data-pagination";
import { ThumbnailDropzone } from "@/components/app/thumbnail-dropzone";
import { Button } from "@/components/ui/button";
import { DataTable } from "@/components/ui/data-table";
import { type dataTableFeatures, DataTable } from "@/components/ui/data-table";
import { DatePicker } from "@/components/ui/date-picker";
import {
Dialog,
Expand Down Expand Up @@ -136,7 +141,7 @@ interface UndoVars {
}

declare module "@tanstack/react-table" {
interface TableMeta<TData extends RowData> {
interface TableMeta<TFeatures extends TableFeatures, TData extends RowData> {
events?: ManageEventsMeta;
}
}
Expand All @@ -162,7 +167,7 @@ const EMPTY_ATTENDANCE_SUMMARY: AttendanceSummary = { planned: 0, attended: 0 };
/// Constants — Table Columns

const ACTIONS_TRIGGER = <Button variant="ghost" size="icon-sm" className="text-brand-text-sub" />;
const EVENT_COLUMNS: ColumnDef<FullEvent>[] = [
const EVENT_COLUMNS: ColumnDef<typeof dataTableFeatures, FullEvent>[] = [
{
id: "event",
header: "Event",
Expand Down Expand Up @@ -771,7 +776,7 @@ function ManageEventsPage() {
},
});

const tableMeta = useMemo<TableMeta<FullEvent>>(
const tableMeta = useMemo<TableMeta<typeof dataTableFeatures, FullEvent>>(
() => ({
events: {
now,
Expand Down
15 changes: 10 additions & 5 deletions src/routes/dashboard/manage/projects.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,12 @@ import {
useQueryClient,
} from "@tanstack/react-query";
import { createFileRoute, useNavigate } from "@tanstack/react-router";
import { type ColumnDef, type RowData, type TableMeta } from "@tanstack/react-table";
import {
type ColumnDef,
type RowData,
type TableFeatures,
type TableMeta,
} from "@tanstack/react-table";
import axios from "axios";
import { blake3 } from "hash-wasm";
import {
Expand Down Expand Up @@ -40,7 +45,7 @@ import { ThumbnailDropzone } from "@/components/app/thumbnail-dropzone";
import { Avatar, AvatarFallback } from "@/components/ui/avatar";
import { Badge } from "@/components/ui/badge";
import { Button } from "@/components/ui/button";
import { DataTable } from "@/components/ui/data-table";
import { type dataTableFeatures, DataTable } from "@/components/ui/data-table";
import {
Dialog,
DialogContent,
Expand Down Expand Up @@ -143,7 +148,7 @@ interface Editor {
}

declare module "@tanstack/react-table" {
interface TableMeta<TData extends RowData> {
interface TableMeta<TFeatures extends TableFeatures, TData extends RowData> {
manage?: ManageProjectsMeta;
}
}
Expand Down Expand Up @@ -216,7 +221,7 @@ const JOIN_POLICIES = Object.keys(JOIN_POLICY_META) as JoinPolicy[];
const ACTIONS_TRIGGER = (
<Button variant="ghost" size="icon-sm" className="relative text-brand-text-sub" />
);
const PROJECT_COLUMNS: ColumnDef<FullProject>[] = [
const PROJECT_COLUMNS: ColumnDef<typeof dataTableFeatures, FullProject>[] = [
{
id: "project",
header: "Project",
Expand Down Expand Up @@ -910,7 +915,7 @@ function ManageProjectsPage() {
[form],
);

const tableMeta = useMemo<TableMeta<FullProject>>(
const tableMeta = useMemo<TableMeta<typeof dataTableFeatures, FullProject>>(
() => ({
manage: {
invites,
Expand Down