From a14161267b5ed1aee0647231a78797be89f0f17d Mon Sep 17 00:00:00 2001 From: Kar Rui Lau Date: Mon, 15 Jul 2024 15:51:24 +0800 Subject: [PATCH 01/15] feat: add Datatable app component --- apps/studio/package.json | 1 + .../src/components/Datatable/Datatable.tsx | 152 ++++++++++++++++ .../Datatable/DatatablePagination.tsx | 104 +++++++++++ .../Datatable/EmptyTablePlaceholder.tsx | 27 +++ .../src/components/Datatable/InfoCell.tsx | 39 ++++ .../src/components/Datatable/TableCell.tsx | 7 + .../src/components/Datatable/TableHeader.tsx | 11 ++ apps/studio/src/components/Datatable/index.ts | 4 + package-lock.json | 168 +++++++++++++++++- package.json | 1 - 10 files changed, 512 insertions(+), 2 deletions(-) create mode 100644 apps/studio/src/components/Datatable/Datatable.tsx create mode 100644 apps/studio/src/components/Datatable/DatatablePagination.tsx create mode 100644 apps/studio/src/components/Datatable/EmptyTablePlaceholder.tsx create mode 100644 apps/studio/src/components/Datatable/InfoCell.tsx create mode 100644 apps/studio/src/components/Datatable/TableCell.tsx create mode 100644 apps/studio/src/components/Datatable/TableHeader.tsx create mode 100644 apps/studio/src/components/Datatable/index.ts diff --git a/apps/studio/package.json b/apps/studio/package.json index b4f7a96b3..3215bb85b 100644 --- a/apps/studio/package.json +++ b/apps/studio/package.json @@ -61,6 +61,7 @@ "@tanstack/match-sorter-utils": "^8.15.1", "@tanstack/react-query": "^4.36.1", "@tanstack/react-query-devtools": "^4.36.1", + "@tanstack/react-table": "^8.19.3", "@tiptap/extension-blockquote": "^2.4.0", "@tiptap/extension-bold": "^2.4.0", "@tiptap/extension-bullet-list": "^2.4.0", diff --git a/apps/studio/src/components/Datatable/Datatable.tsx b/apps/studio/src/components/Datatable/Datatable.tsx new file mode 100644 index 000000000..0e6d8db53 --- /dev/null +++ b/apps/studio/src/components/Datatable/Datatable.tsx @@ -0,0 +1,152 @@ +import type { LayoutProps, TableCellProps, TableProps } from "@chakra-ui/react" +import type { Table as ReactTable } from "@tanstack/react-table" +import { + Box, + Flex, + Spinner, + Table, + Tbody, + Td, + Th, + Thead, + Tr, +} from "@chakra-ui/react" +import { flexRender } from "@tanstack/react-table" + +import { DatatablePagination } from "./DatatablePagination" + +export interface DatatableProps extends TableProps { + instance: ReactTable + /** + * If provided, this number will be used for pagination instead of retrieving + * from react-table's filtered row count. + */ + totalRowCount?: number + pagination?: boolean + isFetching?: boolean + tablePropOverrides?: Record + emptyPlaceholder?: React.ReactElement + overflow?: LayoutProps["overflow"] +} + +export function createAccessor(props: (keyof T)[]) { + return (row: T): string => { + return props.map((prop) => String(row[prop])).join(" ") + } +} + +export const Datatable = ({ + instance, + isFetching, + pagination, + totalRowCount, + tablePropOverrides, + emptyPlaceholder, + overflow = "auto", + ...tableProps +}: DatatableProps): JSX.Element => { + const { rows } = instance.getRowModel() + + return ( + + {isFetching && ( + <> + + + + + + + + )} + + + + {instance.getHeaderGroups().map((headerGroup) => ( + + {headerGroup.headers.map((header) => ( + + ))} + + ))} + + + {rows.length === 0 && emptyPlaceholder} + {rows.map((row) => { + return ( + + {row.getVisibleCells().map((cell) => { + return ( + + ) + })} + + ) + })} + +
+ + {flexRender( + header.column.columnDef.header, + header.getContext(), + )} + +
+ {flexRender( + cell.column.columnDef.cell, + cell.getContext(), + )} +
+
+ {pagination && ( + + + + )} +
+ ) +} diff --git a/apps/studio/src/components/Datatable/DatatablePagination.tsx b/apps/studio/src/components/Datatable/DatatablePagination.tsx new file mode 100644 index 000000000..03fcaf71d --- /dev/null +++ b/apps/studio/src/components/Datatable/DatatablePagination.tsx @@ -0,0 +1,104 @@ +import { useMemo } from "react" +import { ButtonGroup, HStack, Select, Text } from "@chakra-ui/react" +import { IconButton } from "@opengovsg/design-system-react" +import { type Table } from "@tanstack/react-table" +import { + BiChevronLeft, + BiChevronRight, + BiFirstPage, + BiLastPage, +} from "react-icons/bi" + +export interface DataTablePaginationProps { + instance: Table + /** + * Defaults to [10, 25, 50] + */ + pageSizeOptions?: number[] + totalRowCount?: number +} + +export const DatatablePagination = ({ + instance, + totalRowCount: totalRowCountProp, + pageSizeOptions = [10, 25, 50, 100], +}: DataTablePaginationProps): JSX.Element => { + const paginationState = instance.getState().pagination + const pageRowCount = instance.getRowModel().rows.length + const totalRowCount = + totalRowCountProp ?? instance.getFilteredRowModel().rows.length + + // Get page row details depending on current page index and page size. + const pageRowDetails = useMemo(() => { + const { pageIndex, pageSize } = paginationState + const startRow = pageIndex * pageSize + const endRow = Math.min(startRow + pageSize, startRow + pageRowCount) + return { + startRow: totalRowCount === 0 ? 0 : startRow + 1, + endRow, + } + }, [paginationState, pageRowCount, totalRowCount]) + + return ( + + Rows per page + + + {pageRowDetails.startRow}-{pageRowDetails.endRow} of {totalRowCount} + + + } + isDisabled={!instance.getCanPreviousPage()} + variant="clear" + onClick={() => instance.setPageIndex(0)} + /> + } + isDisabled={!instance.getCanPreviousPage()} + variant="clear" + onClick={() => instance.previousPage()} + /> + } + isDisabled={!instance.getCanNextPage()} + variant="clear" + onClick={() => instance.nextPage()} + /> + } + isDisabled={!instance.getCanNextPage()} + variant="clear" + onClick={() => instance.setPageIndex(instance.getPageCount() - 1)} + /> + + + ) +} diff --git a/apps/studio/src/components/Datatable/EmptyTablePlaceholder.tsx b/apps/studio/src/components/Datatable/EmptyTablePlaceholder.tsx new file mode 100644 index 000000000..7e336c126 --- /dev/null +++ b/apps/studio/src/components/Datatable/EmptyTablePlaceholder.tsx @@ -0,0 +1,27 @@ +import { Flex, Stack, Td, Text, Tr } from "@chakra-ui/react" + +export const EmptyTablePlaceholder = ({ + entityName, + hasSearchTerm, +}: { + entityName: string + hasSearchTerm: boolean +}) => { + return ( + + + + + + No {entityName} + {hasSearchTerm ? " found" : ""} + + {hasSearchTerm && ( + Try different search terms + )} + + + + + ) +} diff --git a/apps/studio/src/components/Datatable/InfoCell.tsx b/apps/studio/src/components/Datatable/InfoCell.tsx new file mode 100644 index 000000000..0a0ad4168 --- /dev/null +++ b/apps/studio/src/components/Datatable/InfoCell.tsx @@ -0,0 +1,39 @@ +import { memo } from "react" +import NextLink from "next/link" +import { Link, Text, VStack } from "@chakra-ui/react" + +export interface InfoCellProps { + caption?: string | null + subcaption?: string | null + href?: string +} + +export const InfoCell = memo( + ({ caption, subcaption, href }: InfoCellProps): JSX.Element => { + return ( + + {href ? ( + + {caption} + + ) : ( + {caption} + )} + {subcaption} + + ) + }, + (prevProps, nextProps) => { + return ( + prevProps.caption === nextProps.caption && + prevProps.subcaption === nextProps.subcaption + ) + }, +) + +InfoCell.displayName = "InfoCell" diff --git a/apps/studio/src/components/Datatable/TableCell.tsx b/apps/studio/src/components/Datatable/TableCell.tsx new file mode 100644 index 000000000..77d2c7453 --- /dev/null +++ b/apps/studio/src/components/Datatable/TableCell.tsx @@ -0,0 +1,7 @@ +import type { TextProps } from "@chakra-ui/react" +import React from "react" +import { Text } from "@chakra-ui/react" + +export const TableCell = ({ children, ...props }: TextProps) => { + return {children} +} diff --git a/apps/studio/src/components/Datatable/TableHeader.tsx b/apps/studio/src/components/Datatable/TableHeader.tsx new file mode 100644 index 000000000..01dcc11cd --- /dev/null +++ b/apps/studio/src/components/Datatable/TableHeader.tsx @@ -0,0 +1,11 @@ +import type { BoxProps } from "@chakra-ui/react" +import React from "react" +import { Box } from "@chakra-ui/react" + +export const TableHeader = ({ children, ...props }: BoxProps) => { + return ( + + {children} + + ) +} diff --git a/apps/studio/src/components/Datatable/index.ts b/apps/studio/src/components/Datatable/index.ts new file mode 100644 index 000000000..320a1e964 --- /dev/null +++ b/apps/studio/src/components/Datatable/index.ts @@ -0,0 +1,4 @@ +export * from "./Datatable" +export * from "./TableCell" +export * from "./TableHeader" +export * from "./InfoCell" diff --git a/package-lock.json b/package-lock.json index a9b2092bd..8d292b054 100644 --- a/package-lock.json +++ b/package-lock.json @@ -10,7 +10,6 @@ "hasInstallScript": true, "license": "ISC", "workspaces": [ - "docs", "apps/*", "packages/*", "tooling/*" @@ -44,6 +43,7 @@ "@tanstack/match-sorter-utils": "^8.15.1", "@tanstack/react-query": "^4.36.1", "@tanstack/react-query-devtools": "^4.36.1", + "@tanstack/react-table": "^8.19.3", "@tiptap/extension-blockquote": "^2.4.0", "@tiptap/extension-bold": "^2.4.0", "@tiptap/extension-bullet-list": "^2.4.0", @@ -6966,6 +6966,141 @@ "glob": "10.3.10" } }, + "node_modules/@next/swc-darwin-arm64": { + "version": "14.2.5", + "resolved": "https://registry.npmjs.org/@next/swc-darwin-arm64/-/swc-darwin-arm64-14.2.5.tgz", + "integrity": "sha512-/9zVxJ+K9lrzSGli1///ujyRfon/ZneeZ+v4ptpiPoOU+GKZnm8Wj8ELWU1Pm7GHltYRBklmXMTUqM/DqQ99FQ==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@next/swc-darwin-x64": { + "version": "14.2.5", + "resolved": "https://registry.npmjs.org/@next/swc-darwin-x64/-/swc-darwin-x64-14.2.5.tgz", + "integrity": "sha512-vXHOPCwfDe9qLDuq7U1OYM2wUY+KQ4Ex6ozwsKxp26BlJ6XXbHleOUldenM67JRyBfVjv371oneEvYd3H2gNSA==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@next/swc-linux-arm64-gnu": { + "version": "14.2.5", + "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-gnu/-/swc-linux-arm64-gnu-14.2.5.tgz", + "integrity": "sha512-vlhB8wI+lj8q1ExFW8lbWutA4M2ZazQNvMWuEDqZcuJJc78iUnLdPPunBPX8rC4IgT6lIx/adB+Cwrl99MzNaA==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@next/swc-linux-arm64-musl": { + "version": "14.2.5", + "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-musl/-/swc-linux-arm64-musl-14.2.5.tgz", + "integrity": "sha512-NpDB9NUR2t0hXzJJwQSGu1IAOYybsfeB+LxpGsXrRIb7QOrYmidJz3shzY8cM6+rO4Aojuef0N/PEaX18pi9OA==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@next/swc-linux-x64-gnu": { + "version": "14.2.5", + "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-14.2.5.tgz", + "integrity": "sha512-8XFikMSxWleYNryWIjiCX+gU201YS+erTUidKdyOVYi5qUQo/gRxv/3N1oZFCgqpesN6FPeqGM72Zve+nReVXQ==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@next/swc-linux-x64-musl": { + "version": "14.2.5", + "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-musl/-/swc-linux-x64-musl-14.2.5.tgz", + "integrity": "sha512-6QLwi7RaYiQDcRDSU/os40r5o06b5ue7Jsk5JgdRBGGp8l37RZEh9JsLSM8QF0YDsgcosSeHjglgqi25+m04IQ==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@next/swc-win32-arm64-msvc": { + "version": "14.2.5", + "resolved": "https://registry.npmjs.org/@next/swc-win32-arm64-msvc/-/swc-win32-arm64-msvc-14.2.5.tgz", + "integrity": "sha512-1GpG2VhbspO+aYoMOQPQiqc/tG3LzmsdBH0LhnDS3JrtDx2QmzXe0B6mSZZiN3Bq7IOMXxv1nlsjzoS1+9mzZw==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@next/swc-win32-ia32-msvc": { + "version": "14.2.5", + "resolved": "https://registry.npmjs.org/@next/swc-win32-ia32-msvc/-/swc-win32-ia32-msvc-14.2.5.tgz", + "integrity": "sha512-Igh9ZlxwvCDsu6438FXlQTHlRno4gFpJzqPjSIBZooD22tKeI4fE/YMRoHVJHmrQ2P5YL1DoZ0qaOKkbeFWeMg==", + "cpu": [ + "ia32" + ], + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@next/swc-win32-x64-msvc": { + "version": "14.2.5", + "resolved": "https://registry.npmjs.org/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-14.2.5.tgz", + "integrity": "sha512-tEQ7oinq1/CjSG9uSTerca3v4AZ+dFa+4Yu6ihaG8Ud8ddqLQgFGcnwYls13H5X5CPDPZJdYxyeMui6muOLd4g==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10" + } + }, "node_modules/@noble/hashes": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.4.0.tgz", @@ -11821,6 +11956,25 @@ "node": ">=10" } }, + "node_modules/@tanstack/react-table": { + "version": "8.19.3", + "resolved": "https://registry.npmjs.org/@tanstack/react-table/-/react-table-8.19.3.tgz", + "integrity": "sha512-MtgPZc4y+cCRtU16y1vh1myuyZ2OdkWgMEBzyjYsoMWMicKZGZvcDnub3Zwb6XF2pj9iRMvm1SO1n57lS0vXLw==", + "dependencies": { + "@tanstack/table-core": "8.19.3" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/tannerlinsley" + }, + "peerDependencies": { + "react": ">=16.8", + "react-dom": ">=16.8" + } + }, "node_modules/@tanstack/react-virtual": { "version": "3.8.2", "resolved": "https://registry.npmjs.org/@tanstack/react-virtual/-/react-virtual-3.8.2.tgz", @@ -11837,6 +11991,18 @@ "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0" } }, + "node_modules/@tanstack/table-core": { + "version": "8.19.3", + "resolved": "https://registry.npmjs.org/@tanstack/table-core/-/table-core-8.19.3.tgz", + "integrity": "sha512-IqREj9ADoml9zCAouIG/5kCGoyIxPFdqdyoxis9FisXFi5vT+iYfEfLosq4xkU/iDbMcEuAj+X8dWRLvKYDNoQ==", + "engines": { + "node": ">=12" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/tannerlinsley" + } + }, "node_modules/@tanstack/virtual-core": { "version": "3.8.2", "resolved": "https://registry.npmjs.org/@tanstack/virtual-core/-/virtual-core-3.8.2.tgz", diff --git a/package.json b/package.json index ed85cc98e..8b4244097 100644 --- a/package.json +++ b/package.json @@ -22,7 +22,6 @@ "postinstall": "npm run lint:ws" }, "workspaces": [ - "docs", "apps/*", "packages/*", "tooling/*" From 3b345cacc83a3aa5ed89fe7bab05931a5f04c265 Mon Sep 17 00:00:00 2001 From: Kar Rui Lau Date: Mon, 15 Jul 2024 15:52:03 +0800 Subject: [PATCH 02/15] feat: return dummy table data from page.list route --- .../src/server/modules/page/page.router.ts | 50 +++++++++++++++++++ 1 file changed, 50 insertions(+) diff --git a/apps/studio/src/server/modules/page/page.router.ts b/apps/studio/src/server/modules/page/page.router.ts index 55a4ac745..dc29585ec 100644 --- a/apps/studio/src/server/modules/page/page.router.ts +++ b/apps/studio/src/server/modules/page/page.router.ts @@ -53,6 +53,56 @@ const validatedPageProcedure = protectedProcedure.use( ) export const pageRouter = router({ + list: protectedProcedure.query(() => { + const dummyChildData: { + id: string + name: string + permalink: string + type: "page" | "folder" + status: "folder" | "draft" | "published" + lastEditUser: string + lastEditDate: Date | "folder" + }[] = [ + { + id: "0001", + name: "Test Page 1", + permalink: "/", + type: "page", + status: "draft", + lastEditUser: "user1@test.com", + lastEditDate: new Date(), + }, + { + id: "0003", + name: "Test Folder 1", + permalink: "/testfolder1", + type: "folder", + status: "folder", + lastEditUser: "folder", + lastEditDate: "folder", + }, + { + id: "0002", + name: "Test Page 2", + permalink: "/testpage2", + type: "page", + status: "published", + lastEditUser: "user2@test.com", + lastEditDate: new Date(50000000000), + }, + { + id: "0004", + name: "Test Folder 2", + permalink: "/testfolder2", + type: "folder", + status: "folder", + lastEditUser: "folder", + lastEditDate: "folder", + }, + ] + // TODO: Implement actual data fetching + return dummyChildData + }), readPageAndBlob: protectedProcedure .input(getEditPageSchema) .query(async ({ input, ctx }) => { From 2e43e431e8e7342e12d7619afe291d95a400f211 Mon Sep 17 00:00:00 2001 From: Kar Rui Lau Date: Mon, 15 Jul 2024 17:13:31 +0800 Subject: [PATCH 03/15] feat: add initial ResourceTable component --- .../src/components/Datatable/Datatable.tsx | 4 +- .../src/features/dashboard/DashboardTable.tsx | 235 ------------------ .../components/ResourceTable/LastEditCell.tsx | 37 +++ .../ResourceTable/ResourceTable.tsx | 117 +++++++++ .../components/ResourceTable/StatusCell.tsx | 42 ++++ .../components/ResourceTable/TitleCell.tsx | 39 +++ .../components/ResourceTable/index.ts | 1 + .../components/ResourceTable/types.ts | 3 + .../studio/src/pages/sites/[siteId]/index.tsx | 4 +- apps/studio/src/theme/components/Table.ts | 86 +++++++ apps/studio/src/theme/components/index.ts | 2 + .../src/theme/foundations/textStyles.ts | 8 +- apps/studio/src/theme/generated/textStyles.ts | 215 ++++++++++++++++ 13 files changed, 554 insertions(+), 239 deletions(-) delete mode 100644 apps/studio/src/features/dashboard/DashboardTable.tsx create mode 100644 apps/studio/src/features/dashboard/components/ResourceTable/LastEditCell.tsx create mode 100644 apps/studio/src/features/dashboard/components/ResourceTable/ResourceTable.tsx create mode 100644 apps/studio/src/features/dashboard/components/ResourceTable/StatusCell.tsx create mode 100644 apps/studio/src/features/dashboard/components/ResourceTable/TitleCell.tsx create mode 100644 apps/studio/src/features/dashboard/components/ResourceTable/index.ts create mode 100644 apps/studio/src/features/dashboard/components/ResourceTable/types.ts create mode 100644 apps/studio/src/theme/components/Table.ts create mode 100644 apps/studio/src/theme/generated/textStyles.ts diff --git a/apps/studio/src/components/Datatable/Datatable.tsx b/apps/studio/src/components/Datatable/Datatable.tsx index 0e6d8db53..934942728 100644 --- a/apps/studio/src/components/Datatable/Datatable.tsx +++ b/apps/studio/src/components/Datatable/Datatable.tsx @@ -10,6 +10,7 @@ import { Th, Thead, Tr, + useMultiStyleConfig, } from "@chakra-ui/react" import { flexRender } from "@tanstack/react-table" @@ -46,6 +47,7 @@ export const Datatable = ({ ...tableProps }: DatatableProps): JSX.Element => { const { rows } = instance.getRowModel() + const styles = useMultiStyleConfig("Table", tableProps) return ( @@ -78,7 +80,7 @@ export const Datatable = ({ )} - + {instance.getHeaderGroups().map((headerGroup) => ( diff --git a/apps/studio/src/features/dashboard/DashboardTable.tsx b/apps/studio/src/features/dashboard/DashboardTable.tsx deleted file mode 100644 index 733b305d1..000000000 --- a/apps/studio/src/features/dashboard/DashboardTable.tsx +++ /dev/null @@ -1,235 +0,0 @@ -import { useState } from "react" -import { - Badge, - Box, - Checkbox, - HStack, - Icon, - IconButton, - Table, - TableContainer, - Tbody, - Td, - Text, - Th, - Thead, - Tr, - VStack, -} from "@chakra-ui/react" -import { Pagination } from "@opengovsg/design-system-react" -import { - BiDotsHorizontalRounded, - BiFileBlank, - BiFolder, - BiHome, - BiSolidCircle, -} from "react-icons/bi" -import { MdOutlineHorizontalRule } from "react-icons/md" - -export const DashboardTable = (): JSX.Element => { - const dummyChildData: { - id: string - name: string - permalink: string - type: "page" | "folder" - status: "folder" | "draft" | "published" - lastEditUser: string - lastEditDate: Date | "folder" - }[] = [ - { - id: "0001", - name: "Test Page 1", - permalink: "/", - type: "page", - status: "draft", - lastEditUser: "user1@test.com", - lastEditDate: new Date(), - }, - { - id: "0003", - name: "Test Folder 1", - permalink: "/testfolder1", - type: "folder", - status: "folder", - lastEditUser: "folder", - lastEditDate: "folder", - }, - { - id: "0002", - name: "Test Page 2", - permalink: "/testpage2", - type: "page", - status: "published", - lastEditUser: "user2@test.com", - lastEditDate: new Date(50000000000), - }, - { - id: "0004", - name: "Test Folder 2", - permalink: "/testfolder2", - type: "folder", - status: "folder", - lastEditUser: "folder", - lastEditDate: "folder", - }, - ] - - const [pageNumber, onPageChange] = useState(1) - const [dataToDisplay, setDataToDisplay] = useState(dummyChildData) - - const entriesPerPage = 6 - return ( - <> - -
- - - - - - - - - - {dataToDisplay - .slice( - (pageNumber - 1) * entriesPerPage, - pageNumber * entriesPerPage, - ) - .map((element, index) => { - return ( - - - - - - - - - - ) - })} - -
- {/* checkbox */} - - - - Title - - - - Status - - - - Last Edited - -
- - - - {element.type === "page" && - element.permalink === "/" && ( - - )} - {element.type === "page" && - element.permalink !== "/" && ( - - )} - {element.type === "folder" && ( - - )} - - - {element.name} - - {element.type === "page" && element.permalink} - {element.type === "folder" && "0 pages"} - - - - - {element.type === "page" && element.status == "draft" && ( - - - Draft - - )} - {element.type === "page" && - element.status == "published" && ( - - - Published - - )} - {element.type === "folder" && } - - - {element.type === "page" && ( - - - {element.lastEditUser} - - - {Math.floor( - (new Date().getTime() - - (element.lastEditDate as Date).getTime()) / - (1000 * 3600 * 24), - )}{" "} - Days Ago - - - )} - - {element.type === "folder" && ( - - )} - } - /> - -
- - - - - - ) -} diff --git a/apps/studio/src/features/dashboard/components/ResourceTable/LastEditCell.tsx b/apps/studio/src/features/dashboard/components/ResourceTable/LastEditCell.tsx new file mode 100644 index 000000000..59603c306 --- /dev/null +++ b/apps/studio/src/features/dashboard/components/ResourceTable/LastEditCell.tsx @@ -0,0 +1,37 @@ +import { Text, VStack } from "@chakra-ui/react" +import { formatDistance } from "date-fns" + +import type { ResourceTableData } from "./types" + +export interface LastEditCellProps { + date: ResourceTableData["lastEditDate"] + email: ResourceTableData["lastEditUser"] +} + +export const LastEditCell = ({ + date, + email, +}: LastEditCellProps): JSX.Element => { + if (date === "folder") { + return ( + + - + + ) + } + + return ( + + + {email} + + + {formatDistance(date, new Date(), { addSuffix: true })} + + + ) +} diff --git a/apps/studio/src/features/dashboard/components/ResourceTable/ResourceTable.tsx b/apps/studio/src/features/dashboard/components/ResourceTable/ResourceTable.tsx new file mode 100644 index 000000000..be933f734 --- /dev/null +++ b/apps/studio/src/features/dashboard/components/ResourceTable/ResourceTable.tsx @@ -0,0 +1,117 @@ +import type { PaginationState } from "@tanstack/react-table" +import { useState } from "react" +import { MenuButton, MenuItem, MenuList } from "@chakra-ui/react" +import { IconButton, Menu } from "@opengovsg/design-system-react" +import { + createColumnHelper, + getCoreRowModel, + getPaginationRowModel, + useReactTable, +} from "@tanstack/react-table" +import { BiDotsHorizontalRounded, BiEdit } from "react-icons/bi" + +import type { RouterOutput } from "~/utils/trpc" +import { TableHeader } from "~/components/Datatable" +import { createAccessor, Datatable } from "~/components/Datatable/Datatable" +import { EmptyTablePlaceholder } from "~/components/Datatable/EmptyTablePlaceholder" +import { trpc } from "~/utils/trpc" +import { LastEditCell } from "./LastEditCell" +import { StatusCell } from "./StatusCell" +import { TitleCell } from "./TitleCell" + +type ResourceTableData = RouterOutput["page"]["list"][number] + +const columnsHelper = createColumnHelper() + +export const ResourceTableMenu = ({ + resourceId: _resourceId, +}: { + resourceId: string +}) => { + return ( + + } + variant="clear" + /> + + {/* TODO: Open edit modal depending on resource */} + }>Edit + + + ) +} + +const columns = [ + columnsHelper.accessor("name", { + header: () => Title, + cell: ({ row }) => ( + + ), + }), + columnsHelper.accessor("status", { + header: () => Status, + cell: ({ row }) => , + }), + columnsHelper.accessor(createAccessor(["lastEditDate", "lastEditUser"]), { + id: "edit_details", + header: () => Last edited, + cell: ({ row }) => ( + + ), + }), + columnsHelper.display({ + id: "resource_menu", + header: () => Actions, + cell: ({ row }) => , + size: 2.25, + }), +] + +export const ResourceTable = (): JSX.Element => { + const { data: resources } = trpc.page.list.useQuery(undefined, { + keepPreviousData: true, // Required for table to show previous data while fetching next page + }) + + const [pagination, setPagination] = useState({ + pageIndex: 0, + pageSize: 25, + }) + + const tableInstance = useReactTable({ + columns, + data: resources ?? [], + getCoreRowModel: getCoreRowModel(), + manualFiltering: true, + autoResetPageIndex: false, + getPaginationRowModel: getPaginationRowModel(), + onPaginationChange: setPagination, + state: { + pagination, + }, + }) + + return ( + + } + instance={tableInstance} + sx={{ + tableLayout: "auto", + }} + totalRowCount={resources?.length ?? 0} + /> + ) +} diff --git a/apps/studio/src/features/dashboard/components/ResourceTable/StatusCell.tsx b/apps/studio/src/features/dashboard/components/ResourceTable/StatusCell.tsx new file mode 100644 index 000000000..af27599d9 --- /dev/null +++ b/apps/studio/src/features/dashboard/components/ResourceTable/StatusCell.tsx @@ -0,0 +1,42 @@ +import { Text } from "@chakra-ui/react" +import { Badge, BadgeLeftIcon } from "@opengovsg/design-system-react" +import { BiSolidCircle } from "react-icons/bi" + +import type { ResourceTableData } from "./types" + +export interface StatusCellProps { + status: ResourceTableData["status"] +} + +export const StatusCell = ({ status }: StatusCellProps): JSX.Element => { + switch (status) { + case "folder": + return ( + + - + + ) + case "published": + return ( + + + Published + + ) + case "draft": + return ( + + + Draft + + ) + } +} diff --git a/apps/studio/src/features/dashboard/components/ResourceTable/TitleCell.tsx b/apps/studio/src/features/dashboard/components/ResourceTable/TitleCell.tsx new file mode 100644 index 000000000..51609a616 --- /dev/null +++ b/apps/studio/src/features/dashboard/components/ResourceTable/TitleCell.tsx @@ -0,0 +1,39 @@ +import { HStack, Icon, Text, VStack } from "@chakra-ui/react" +import { BiFileBlank, BiFolder } from "react-icons/bi" + +import type { ResourceTableData } from "./types" + +export interface TitleCellProps { + title: ResourceTableData["name"] + permalink?: ResourceTableData["permalink"] + type: ResourceTableData["type"] +} + +export const TitleCell = ({ + title, + permalink, + type, +}: TitleCellProps): JSX.Element => { + return ( + + + + + {title} + + + {permalink} + + + + ) +} diff --git a/apps/studio/src/features/dashboard/components/ResourceTable/index.ts b/apps/studio/src/features/dashboard/components/ResourceTable/index.ts new file mode 100644 index 000000000..11e9b8529 --- /dev/null +++ b/apps/studio/src/features/dashboard/components/ResourceTable/index.ts @@ -0,0 +1 @@ +export * from "./ResourceTable" diff --git a/apps/studio/src/features/dashboard/components/ResourceTable/types.ts b/apps/studio/src/features/dashboard/components/ResourceTable/types.ts new file mode 100644 index 000000000..b51902e43 --- /dev/null +++ b/apps/studio/src/features/dashboard/components/ResourceTable/types.ts @@ -0,0 +1,3 @@ +import type { RouterOutput } from "~/utils/trpc" + +export type ResourceTableData = RouterOutput["page"]["list"][number] diff --git a/apps/studio/src/pages/sites/[siteId]/index.tsx b/apps/studio/src/pages/sites/[siteId]/index.tsx index 7b444473f..10baec986 100644 --- a/apps/studio/src/pages/sites/[siteId]/index.tsx +++ b/apps/studio/src/pages/sites/[siteId]/index.tsx @@ -1,7 +1,7 @@ import { HStack, Text, useDisclosure, VStack } from "@chakra-ui/react" import { Button } from "@opengovsg/design-system-react" -import { DashboardTable } from "~/features/dashboard/DashboardTable" +import { ResourceTable } from "~/features/dashboard/components/ResourceTable" import PageCreateModal from "~/features/editing-experience/components/PageCreateModal" import { type NextPageWithLayout } from "~/lib/types" import { AdminCmsSidebarLayout } from "~/templates/layouts/AdminCmsSidebarLayout" @@ -37,7 +37,7 @@ const SitePage: NextPageWithLayout = () => { Create a new page - + { + const baseStyles: SystemStyleObject = { + color: "base.content.medium", + textTransform: "initial", + } + + return { + color: "base.content.medium", + ...baseStyles, + } +} + +const variantSubtle = definePartsStyle(() => { + return { + container: { + bg: "white", + borderRadius: "8px", + border: "1px solid", + borderColor: "base.divider.medium", + }, + table: { + bg: "white", + }, + thead: { + opacity: 1, + zIndex: 1, + }, + th: getSubtleVariantThStyles(), + td: { + color: "base.content.default", + }, + } +}) + +const variants = { + subtle: variantSubtle, +} + +export const Table = defineMultiStyleConfig({ + baseStyle, + variants, + defaultProps: { + variant: "subtle", + size: "md", + colorScheme: "neutral", + }, + sizes, +}) diff --git a/apps/studio/src/theme/components/index.ts b/apps/studio/src/theme/components/index.ts index dc1d99793..56d1d90fb 100644 --- a/apps/studio/src/theme/components/index.ts +++ b/apps/studio/src/theme/components/index.ts @@ -1,5 +1,7 @@ import { Modal } from "./Modal" +import { Table } from "./Table" export const components = { Modal, + Table, } diff --git a/apps/studio/src/theme/foundations/textStyles.ts b/apps/studio/src/theme/foundations/textStyles.ts index 0202307d9..991856064 100644 --- a/apps/studio/src/theme/foundations/textStyles.ts +++ b/apps/studio/src/theme/foundations/textStyles.ts @@ -1,4 +1,8 @@ -export const textStyles = { +import merge from "lodash/merge" + +import { textStyles as generatedTextStyles } from "../generated/textStyles" + +const customTextStyles = { "h3-semibold": { fontWeight: 600, lineHeight: "2.25rem", @@ -7,3 +11,5 @@ export const textStyles = { fontFamily: "body", }, } + +export const textStyles = merge(customTextStyles, generatedTextStyles) diff --git a/apps/studio/src/theme/generated/textStyles.ts b/apps/studio/src/theme/generated/textStyles.ts new file mode 100644 index 000000000..487ec7703 --- /dev/null +++ b/apps/studio/src/theme/generated/textStyles.ts @@ -0,0 +1,215 @@ +/** + * Do not edit directly + * Generated on Thu, 28 Dec 2023 07:03:58 GMT + */ + +export const textStyles = { + "responsive-display": { + "heavy-1280": { + fontWeight: 700, + lineHeight: "4.5rem", + fontSize: "4rem", + letterSpacing: "-0.022em", + fontFamily: "body", + }, + "heavy-480": { + fontWeight: 700, + lineHeight: "4rem", + fontSize: "3.5rem", + letterSpacing: "-0.022em", + fontFamily: "body", + }, + heavy: { + fontWeight: 600, + lineHeight: "3rem", + fontSize: "2.5rem", + letterSpacing: "-0.022em", + fontFamily: "body", + }, + "light-1280": { + fontWeight: 300, + lineHeight: "4.5rem", + fontSize: "4rem", + letterSpacing: "-0.022em", + fontFamily: "body", + }, + "light-480": { + fontWeight: 300, + lineHeight: "4rem", + fontSize: "3.5rem", + letterSpacing: "-0.022em", + fontFamily: "body", + }, + light: { + fontWeight: 300, + lineHeight: "3rem", + fontSize: "2.5rem", + letterSpacing: "-0.022em", + fontFamily: "body", + }, + }, + "responsive-heading": { + "heavy-1280": { + fontWeight: 600, + lineHeight: "3.5rem", + fontSize: "3rem", + letterSpacing: "-0.022em", + fontFamily: "body", + }, + "heavy-480": { + fontWeight: 600, + lineHeight: "3rem", + fontSize: "2.5rem", + letterSpacing: "-0.022em", + fontFamily: "body", + }, + heavy: { + fontWeight: 600, + lineHeight: "2.5rem", + fontSize: "2rem", + letterSpacing: "-0.022em", + fontFamily: "body", + }, + "light-1280": { + fontWeight: 300, + lineHeight: "3.5rem", + fontSize: "3rem", + letterSpacing: "-0.022em", + fontFamily: "body", + }, + "light-480": { + fontWeight: 300, + lineHeight: "3rem", + fontSize: "2.5rem", + letterSpacing: "-0.022em", + fontFamily: "body", + }, + light: { + fontWeight: 300, + lineHeight: "2.5rem", + fontSize: "2rem", + letterSpacing: "-0.022em", + fontFamily: "body", + }, + }, + h1: { + fontWeight: 600, + lineHeight: "3rem", + fontSize: "2.5rem", + letterSpacing: "-0.022em", + fontFamily: "body", + }, + h2: { + fontWeight: 600, + lineHeight: "2.75rem", + fontSize: "2.25rem", + letterSpacing: "-0.022em", + fontFamily: "body", + }, + h3: { + fontWeight: 700, + lineHeight: "2.25rem", + fontSize: "1.75rem", + letterSpacing: "-0.019em", + fontFamily: "body", + }, + h4: { + fontWeight: 600, + lineHeight: "2rem", + fontSize: "1.5rem", + letterSpacing: "-0.019em", + fontFamily: "body", + }, + h5: { + fontWeight: 600, + lineHeight: "1.75rem", + fontSize: "1.25rem", + letterSpacing: "-0.014em", + fontFamily: "body", + }, + h6: { + fontWeight: 500, + lineHeight: "1.5rem", + fontSize: "1.125rem", + letterSpacing: "-0.014em", + fontFamily: "body", + }, + "subhead-1": { + fontWeight: 500, + lineHeight: "1.5rem", + fontSize: "1rem", + letterSpacing: "-0.006em", + fontFamily: "body", + }, + "subhead-2": { + fontWeight: 500, + lineHeight: "1.25rem", + fontSize: "0.875rem", + letterSpacing: 0, + fontFamily: "body", + }, + "subhead-3": { + fontWeight: 600, + lineHeight: "1.5rem", + fontSize: "0.875rem", + letterSpacing: "0.080em", + fontFamily: "body", + textTransform: "uppercase", + }, + "body-1": { + fontWeight: 400, + lineHeight: "1.5rem", + fontSize: "1rem", + letterSpacing: "-0.006em", + fontFamily: "body", + }, + "body-2": { + fontWeight: 400, + lineHeight: "1.25rem", + fontSize: "0.875rem", + letterSpacing: 0, + fontFamily: "body", + }, + "body-3": { + fontWeight: 400, + lineHeight: "1.75rem", + fontSize: "1rem", + letterSpacing: "-0.006em", + fontFamily: "body", + }, + "caption-1": { + fontWeight: 500, + lineHeight: "1rem", + fontSize: "0.75rem", + letterSpacing: 0, + fontFamily: "body", + }, + "caption-2": { + fontWeight: 400, + lineHeight: "1rem", + fontSize: "0.75rem", + letterSpacing: 0, + fontFamily: "body", + }, + "code-1": { + fontWeight: 400, + lineHeight: "1.25rem", + fontSize: "0.875rem", + letterSpacing: 0, + fontFamily: "code", + }, + "code-2": { + fontWeight: 400, + lineHeight: "1rem", + fontSize: "0.75rem", + letterSpacing: 0, + fontFamily: "code", + }, + legal: { + fontWeight: 400, + lineHeight: "0.75rem", + fontSize: "0.625rem", + letterSpacing: 0, + fontFamily: "body", + }, +} From 00f53957630f4ad8692ab8e589b899823032087e Mon Sep 17 00:00:00 2001 From: Kar Rui Lau Date: Mon, 15 Jul 2024 17:17:21 +0800 Subject: [PATCH 04/15] feat: update dummy data dates --- apps/studio/src/server/modules/page/page.router.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/studio/src/server/modules/page/page.router.ts b/apps/studio/src/server/modules/page/page.router.ts index dc29585ec..afc4abc98 100644 --- a/apps/studio/src/server/modules/page/page.router.ts +++ b/apps/studio/src/server/modules/page/page.router.ts @@ -70,7 +70,7 @@ export const pageRouter = router({ type: "page", status: "draft", lastEditUser: "user1@test.com", - lastEditDate: new Date(), + lastEditDate: new Date("2024-07-15T09:16:46.640Z"), }, { id: "0003", @@ -88,7 +88,7 @@ export const pageRouter = router({ type: "page", status: "published", lastEditUser: "user2@test.com", - lastEditDate: new Date(50000000000), + lastEditDate: new Date("2024-06-15T09:16:46.640Z"), }, { id: "0004", From a3f8c37cd2caa3bb4dfc3035bbfe862f8379d7d7 Mon Sep 17 00:00:00 2001 From: Kar Rui Lau Date: Mon, 15 Jul 2024 17:19:01 +0800 Subject: [PATCH 05/15] refactor: extract ResourceTableMenu component --- .../ResourceTable/ResourceTable.tsx | 26 +------------------ .../ResourceTable/ResourceTableMenu.tsx | 25 ++++++++++++++++++ 2 files changed, 26 insertions(+), 25 deletions(-) create mode 100644 apps/studio/src/features/dashboard/components/ResourceTable/ResourceTableMenu.tsx diff --git a/apps/studio/src/features/dashboard/components/ResourceTable/ResourceTable.tsx b/apps/studio/src/features/dashboard/components/ResourceTable/ResourceTable.tsx index be933f734..e32d653d3 100644 --- a/apps/studio/src/features/dashboard/components/ResourceTable/ResourceTable.tsx +++ b/apps/studio/src/features/dashboard/components/ResourceTable/ResourceTable.tsx @@ -1,14 +1,11 @@ import type { PaginationState } from "@tanstack/react-table" import { useState } from "react" -import { MenuButton, MenuItem, MenuList } from "@chakra-ui/react" -import { IconButton, Menu } from "@opengovsg/design-system-react" import { createColumnHelper, getCoreRowModel, getPaginationRowModel, useReactTable, } from "@tanstack/react-table" -import { BiDotsHorizontalRounded, BiEdit } from "react-icons/bi" import type { RouterOutput } from "~/utils/trpc" import { TableHeader } from "~/components/Datatable" @@ -16,6 +13,7 @@ import { createAccessor, Datatable } from "~/components/Datatable/Datatable" import { EmptyTablePlaceholder } from "~/components/Datatable/EmptyTablePlaceholder" import { trpc } from "~/utils/trpc" import { LastEditCell } from "./LastEditCell" +import { ResourceTableMenu } from "./ResourceTableMenu" import { StatusCell } from "./StatusCell" import { TitleCell } from "./TitleCell" @@ -23,28 +21,6 @@ type ResourceTableData = RouterOutput["page"]["list"][number] const columnsHelper = createColumnHelper() -export const ResourceTableMenu = ({ - resourceId: _resourceId, -}: { - resourceId: string -}) => { - return ( - - } - variant="clear" - /> - - {/* TODO: Open edit modal depending on resource */} - }>Edit - - - ) -} - const columns = [ columnsHelper.accessor("name", { header: () => Title, diff --git a/apps/studio/src/features/dashboard/components/ResourceTable/ResourceTableMenu.tsx b/apps/studio/src/features/dashboard/components/ResourceTable/ResourceTableMenu.tsx new file mode 100644 index 000000000..b133fa54b --- /dev/null +++ b/apps/studio/src/features/dashboard/components/ResourceTable/ResourceTableMenu.tsx @@ -0,0 +1,25 @@ +import { MenuButton, MenuItem, MenuList } from "@chakra-ui/react" +import { IconButton, Menu } from "@opengovsg/design-system-react" +import { BiDotsHorizontalRounded, BiEdit } from "react-icons/bi" + +export const ResourceTableMenu = ({ + resourceId: _resourceId, +}: { + resourceId: string +}) => { + return ( + + } + variant="clear" + /> + + {/* TODO: Open edit modal depending on resource */} + }>Edit + + + ) +} From ddf4dda63be3b4f94be3b85305bec6412bc88309 Mon Sep 17 00:00:00 2001 From: Kar Rui Lau Date: Mon, 15 Jul 2024 17:40:32 +0800 Subject: [PATCH 06/15] feat: update styling of table --- .../CmsSidebar/CmsSidebarContainer.tsx | 2 +- .../ResourceTable/ResourceTable.tsx | 7 ++- .../studio/src/pages/sites/[siteId]/index.tsx | 51 +++++++++---------- apps/studio/src/theme/components/Table.ts | 3 +- 4 files changed, 33 insertions(+), 30 deletions(-) diff --git a/apps/studio/src/components/CmsSidebar/CmsSidebarContainer.tsx b/apps/studio/src/components/CmsSidebar/CmsSidebarContainer.tsx index 5bb93ca53..351990fe4 100644 --- a/apps/studio/src/components/CmsSidebar/CmsSidebarContainer.tsx +++ b/apps/studio/src/components/CmsSidebar/CmsSidebarContainer.tsx @@ -39,7 +39,7 @@ export function CmsSidebarContainer({ {sidebar}
- + {children} diff --git a/apps/studio/src/features/dashboard/components/ResourceTable/ResourceTable.tsx b/apps/studio/src/features/dashboard/components/ResourceTable/ResourceTable.tsx index e32d653d3..5b732521c 100644 --- a/apps/studio/src/features/dashboard/components/ResourceTable/ResourceTable.tsx +++ b/apps/studio/src/features/dashboard/components/ResourceTable/ResourceTable.tsx @@ -23,6 +23,7 @@ const columnsHelper = createColumnHelper() const columns = [ columnsHelper.accessor("name", { + minSize: 300, header: () => Title, cell: ({ row }) => ( Status, cell: ({ row }) => , }), columnsHelper.accessor(createAccessor(["lastEditDate", "lastEditUser"]), { id: "edit_details", + size: 120, header: () => Last edited, cell: ({ row }) => ( Actions, cell: ({ row }) => , - size: 2.25, + size: 24, }), ] @@ -86,6 +89,8 @@ export const ResourceTable = (): JSX.Element => { instance={tableInstance} sx={{ tableLayout: "auto", + minWidth: "1000px", + overflowX: "auto", }} totalRowCount={resources?.length ?? 0} /> diff --git a/apps/studio/src/pages/sites/[siteId]/index.tsx b/apps/studio/src/pages/sites/[siteId]/index.tsx index 10baec986..aa2edafbb 100644 --- a/apps/studio/src/pages/sites/[siteId]/index.tsx +++ b/apps/studio/src/pages/sites/[siteId]/index.tsx @@ -1,4 +1,4 @@ -import { HStack, Text, useDisclosure, VStack } from "@chakra-ui/react" +import { Box, HStack, Text, useDisclosure, VStack } from "@chakra-ui/react" import { Button } from "@opengovsg/design-system-react" import { ResourceTable } from "~/features/dashboard/components/ResourceTable" @@ -13,36 +13,33 @@ const SitePage: NextPageWithLayout = () => { onClose: onpageCreateModalClose, } = useDisclosure() return ( - - - My Pages - - - - Double click a page to start editing. - - - - - + <> + + + + My Pages + + + + + + + + + + + + + - + ) } diff --git a/apps/studio/src/theme/components/Table.ts b/apps/studio/src/theme/components/Table.ts index 478801b4f..72a8d923b 100644 --- a/apps/studio/src/theme/components/Table.ts +++ b/apps/studio/src/theme/components/Table.ts @@ -31,7 +31,8 @@ const sizes = { ...textStyles["body-2"], }, td: { - p: "1rem", + py: "0.5rem", + px: "1rem", }, }), } From 6a6dacbfc12776f7f315879f03a318d98cc9ca2d Mon Sep 17 00:00:00 2001 From: Kar Rui Lau Date: Mon, 15 Jul 2024 18:21:36 +0800 Subject: [PATCH 07/15] feat: use pagination component as per design --- .../src/components/Datatable/Datatable.tsx | 29 ++++-- .../Datatable/DatatablePagination.tsx | 94 ++----------------- .../ResourceTable/ResourceTable.tsx | 5 +- 3 files changed, 34 insertions(+), 94 deletions(-) diff --git a/apps/studio/src/components/Datatable/Datatable.tsx b/apps/studio/src/components/Datatable/Datatable.tsx index 934942728..ee9f75daa 100644 --- a/apps/studio/src/components/Datatable/Datatable.tsx +++ b/apps/studio/src/components/Datatable/Datatable.tsx @@ -7,6 +7,7 @@ import { Table, Tbody, Td, + Text, Th, Thead, Tr, @@ -24,6 +25,10 @@ export interface DatatableProps extends TableProps { */ totalRowCount?: number pagination?: boolean + /** + * If provided, this string will be used to display the total row count. + */ + totalRowCountString?: string isFetching?: boolean tablePropOverrides?: Record emptyPlaceholder?: React.ReactElement @@ -41,6 +46,7 @@ export const Datatable = ({ isFetching, pagination, totalRowCount, + totalRowCountString, tablePropOverrides, emptyPlaceholder, overflow = "auto", @@ -141,14 +147,21 @@ export const Datatable = ({
- {pagination && ( - - - - )} + + {totalRowCountString && ( + + {totalRowCountString} + + )} + {pagination && ( + + + + )} +
) } diff --git a/apps/studio/src/components/Datatable/DatatablePagination.tsx b/apps/studio/src/components/Datatable/DatatablePagination.tsx index 03fcaf71d..fb17dbc64 100644 --- a/apps/studio/src/components/Datatable/DatatablePagination.tsx +++ b/apps/studio/src/components/Datatable/DatatablePagination.tsx @@ -1,19 +1,8 @@ -import { useMemo } from "react" -import { ButtonGroup, HStack, Select, Text } from "@chakra-ui/react" -import { IconButton } from "@opengovsg/design-system-react" +import { Pagination } from "@opengovsg/design-system-react" import { type Table } from "@tanstack/react-table" -import { - BiChevronLeft, - BiChevronRight, - BiFirstPage, - BiLastPage, -} from "react-icons/bi" export interface DataTablePaginationProps { instance: Table - /** - * Defaults to [10, 25, 50] - */ pageSizeOptions?: number[] totalRowCount?: number } @@ -21,84 +10,19 @@ export interface DataTablePaginationProps { export const DatatablePagination = ({ instance, totalRowCount: totalRowCountProp, - pageSizeOptions = [10, 25, 50, 100], }: DataTablePaginationProps): JSX.Element => { const paginationState = instance.getState().pagination - const pageRowCount = instance.getRowModel().rows.length const totalRowCount = totalRowCountProp ?? instance.getFilteredRowModel().rows.length - // Get page row details depending on current page index and page size. - const pageRowDetails = useMemo(() => { - const { pageIndex, pageSize } = paginationState - const startRow = pageIndex * pageSize - const endRow = Math.min(startRow + pageSize, startRow + pageRowCount) - return { - startRow: totalRowCount === 0 ? 0 : startRow + 1, - endRow, - } - }, [paginationState, pageRowCount, totalRowCount]) - return ( - - Rows per page - - - {pageRowDetails.startRow}-{pageRowDetails.endRow} of {totalRowCount} - - - } - isDisabled={!instance.getCanPreviousPage()} - variant="clear" - onClick={() => instance.setPageIndex(0)} - /> - } - isDisabled={!instance.getCanPreviousPage()} - variant="clear" - onClick={() => instance.previousPage()} - /> - } - isDisabled={!instance.getCanNextPage()} - variant="clear" - onClick={() => instance.nextPage()} - /> - } - isDisabled={!instance.getCanNextPage()} - variant="clear" - onClick={() => instance.setPageIndex(instance.getPageCount() - 1)} - /> - - + { + instance.setPageIndex(newPage - 1) + }} + pageSize={10} + totalCount={totalRowCount} + /> ) } diff --git a/apps/studio/src/features/dashboard/components/ResourceTable/ResourceTable.tsx b/apps/studio/src/features/dashboard/components/ResourceTable/ResourceTable.tsx index 5b732521c..554e6d344 100644 --- a/apps/studio/src/features/dashboard/components/ResourceTable/ResourceTable.tsx +++ b/apps/studio/src/features/dashboard/components/ResourceTable/ResourceTable.tsx @@ -62,6 +62,8 @@ export const ResourceTable = (): JSX.Element => { keepPreviousData: true, // Required for table to show previous data while fetching next page }) + const totalRowCount = resources?.length ?? 0 + const [pagination, setPagination] = useState({ pageIndex: 0, pageSize: 25, @@ -92,7 +94,8 @@ export const ResourceTable = (): JSX.Element => { minWidth: "1000px", overflowX: "auto", }} - totalRowCount={resources?.length ?? 0} + totalRowCount={totalRowCount} + totalRowCountString={`${totalRowCount} item${totalRowCount === 1 ? "" : "s"} in collection`} /> ) } From 182e6a0695d63f9950e7df432af679bf96e368d4 Mon Sep 17 00:00:00 2001 From: Kar Rui Lau Date: Mon, 15 Jul 2024 18:22:48 +0800 Subject: [PATCH 08/15] feat: increase mocked resource list --- .../src/server/modules/page/page.router.ts | 93 +++++++++++++++++-- 1 file changed, 87 insertions(+), 6 deletions(-) diff --git a/apps/studio/src/server/modules/page/page.router.ts b/apps/studio/src/server/modules/page/page.router.ts index afc4abc98..1f8f425e0 100644 --- a/apps/studio/src/server/modules/page/page.router.ts +++ b/apps/studio/src/server/modules/page/page.router.ts @@ -72,6 +72,15 @@ export const pageRouter = router({ lastEditUser: "user1@test.com", lastEditDate: new Date("2024-07-15T09:16:46.640Z"), }, + { + id: "0002", + name: "Test Page 2", + permalink: "/testpage2", + type: "page", + status: "published", + lastEditUser: "user2@test.com", + lastEditDate: new Date("2024-06-15T09:16:46.640Z"), + }, { id: "0003", name: "Test Folder 1", @@ -82,18 +91,90 @@ export const pageRouter = router({ lastEditDate: "folder", }, { - id: "0002", - name: "Test Page 2", - permalink: "/testpage2", + id: "0004", + name: "Test Folder 2", + permalink: "/testfolder2", + type: "folder", + status: "folder", + lastEditUser: "folder", + lastEditDate: "folder", + }, + { + id: "0005", + name: "Test Page 5", + permalink: "/", + type: "page", + status: "draft", + lastEditUser: "user1@test.com", + lastEditDate: new Date("2024-07-15T09:16:46.640Z"), + }, + { + id: "0006", + name: "Test Folder 6", + permalink: "/testfolder6", + type: "folder", + status: "folder", + lastEditUser: "folder", + lastEditDate: "folder", + }, + { + id: "0007", + name: "Test Page 7", + permalink: "/testpage7", + type: "page", + status: "published", + lastEditUser: "user7@test.com", + lastEditDate: new Date("2024-06-15T09:16:46.640Z"), + }, + { + id: "0008", + name: "Test Folder 8", + permalink: "/testfolder8", + type: "folder", + status: "folder", + lastEditUser: "folder", + lastEditDate: "folder", + }, + { + id: "0009", + name: "Test Folder 9", + permalink: "/testfolder9", + type: "folder", + status: "folder", + lastEditUser: "folder", + lastEditDate: "folder", + }, + { + id: "0010", + name: "Test Page 10", + permalink: "/testpage10", type: "page", status: "published", lastEditUser: "user2@test.com", lastEditDate: new Date("2024-06-15T09:16:46.640Z"), }, { - id: "0004", - name: "Test Folder 2", - permalink: "/testfolder2", + id: "0011", + name: "Test Folder 11", + permalink: "/testfolder11", + type: "folder", + status: "folder", + lastEditUser: "folder", + lastEditDate: "folder", + }, + { + id: "0012", + name: "Test Page 12", + permalink: "/testpage12", + type: "page", + status: "draft", + lastEditUser: "user1@test.com", + lastEditDate: new Date("2024-07-15T09:16:46.640Z"), + }, + { + id: "0013", + name: "Test Folder 13", + permalink: "/testfolder13", type: "folder", status: "folder", lastEditUser: "folder", From ea79c035b05f2ea98ec2b38f610cecfbf3b28315 Mon Sep 17 00:00:00 2001 From: Kar Rui Lau Date: Mon, 15 Jul 2024 18:45:42 +0800 Subject: [PATCH 09/15] feat: flesh out resource table menu options --- apps/studio/src/components/Menu/MenuItem.tsx | 47 +++++++++++++++++++ apps/studio/src/components/Menu/index.ts | 1 + .../ResourceTable/ResourceTableMenu.tsx | 23 +++++++-- 3 files changed, 67 insertions(+), 4 deletions(-) create mode 100644 apps/studio/src/components/Menu/MenuItem.tsx create mode 100644 apps/studio/src/components/Menu/index.ts diff --git a/apps/studio/src/components/Menu/MenuItem.tsx b/apps/studio/src/components/Menu/MenuItem.tsx new file mode 100644 index 000000000..31e9512b5 --- /dev/null +++ b/apps/studio/src/components/Menu/MenuItem.tsx @@ -0,0 +1,47 @@ +import type { MenuItemProps as ChakraMenuItemProps } from "@chakra-ui/react" +import { useMemo } from "react" +import { MenuItem as ChakraMenuItem, cssVar } from "@chakra-ui/react" + +const $bg = cssVar("menu-bg") + +export interface MenuItemProps extends ChakraMenuItemProps { + colorScheme?: "critical" +} + +export const MenuItem = ({ + colorScheme, + ...menuItemProps +}: MenuItemProps): JSX.Element => { + // Unable to use useMultiStyleConfig here because Menu parent still controls + // other styles such as size and placement + const extraStyles = useMemo(() => { + if (!colorScheme) return {} + switch (colorScheme) { + case "critical": { + return { + bg: $bg.reference, + color: "interaction.critical.default", + _hover: { + [$bg.variable]: `colors.interaction.muted.critical.hover`, + }, + _focus: { + [$bg.variable]: `colors.interaction.muted.critical.hover`, + _active: { + [$bg.variable]: `colors.interaction.muted.critical.active`, + }, + }, + _focusVisible: { + _active: { + [$bg.variable]: `colors.interaction.muted.critical.active`, + }, + }, + _active: { + [$bg.variable]: `colors.interaction.muted.critical.active`, + }, + } + } + } + }, [colorScheme]) + + return +} diff --git a/apps/studio/src/components/Menu/index.ts b/apps/studio/src/components/Menu/index.ts new file mode 100644 index 000000000..7829c6f2f --- /dev/null +++ b/apps/studio/src/components/Menu/index.ts @@ -0,0 +1 @@ +export { MenuItem } from "./MenuItem" diff --git a/apps/studio/src/features/dashboard/components/ResourceTable/ResourceTableMenu.tsx b/apps/studio/src/features/dashboard/components/ResourceTable/ResourceTableMenu.tsx index b133fa54b..6dcb9f9bb 100644 --- a/apps/studio/src/features/dashboard/components/ResourceTable/ResourceTableMenu.tsx +++ b/apps/studio/src/features/dashboard/components/ResourceTable/ResourceTableMenu.tsx @@ -1,6 +1,14 @@ -import { MenuButton, MenuItem, MenuList } from "@chakra-ui/react" +import { MenuButton, MenuList } from "@chakra-ui/react" import { IconButton, Menu } from "@opengovsg/design-system-react" -import { BiDotsHorizontalRounded, BiEdit } from "react-icons/bi" +import { + BiCog, + BiDotsHorizontalRounded, + BiDuplicate, + BiFolderOpen, + BiTrash, +} from "react-icons/bi" + +import { MenuItem } from "~/components/Menu" export const ResourceTableMenu = ({ resourceId: _resourceId, @@ -8,7 +16,7 @@ export const ResourceTableMenu = ({ resourceId: string }) => { return ( - + {/* TODO: Open edit modal depending on resource */} - }>Edit + }>Edit page settings + }> + Duplicate page + + }>Move to... + }> + Delete + ) From b161a11833fe7a64810fefd77f134e1ef1c036a6 Mon Sep 17 00:00:00 2001 From: Kar Rui Lau Date: Mon, 15 Jul 2024 18:54:14 +0800 Subject: [PATCH 10/15] fix: update decorator order so certain stories can render when getLayout uses loginstate hook it can fail to render if not in this order --- apps/studio/.storybook/preview.tsx | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/apps/studio/.storybook/preview.tsx b/apps/studio/.storybook/preview.tsx index 3a85c2e98..1ecf486cf 100644 --- a/apps/studio/.storybook/preview.tsx +++ b/apps/studio/.storybook/preview.tsx @@ -53,7 +53,7 @@ const StorybookEnvDecorator: Decorator = (story) => { return {story()} } -const SetupDecorator: Decorator = (story) => { +const SetupDecorator: Decorator = (Story) => { const [queryClient] = useState( new QueryClient({ defaultOptions: { @@ -76,7 +76,7 @@ const SetupDecorator: Decorator = (story) => { }> - {story()} + @@ -186,17 +186,17 @@ export const MockDateDecorator: Decorator = (story, { parameters }) => { const decorators: Decorator[] = [ WithLayoutDecorator, - StorybookEnvDecorator, + MockDateDecorator, MockFeatureFlagsDecorator, - LoginStateDecorator, SetupDecorator, + StorybookEnvDecorator, withThemeFromJSXProvider({ themes: { default: theme, }, Provider: ThemeProvider, }) as Decorator, // FIXME: Remove this cast when types are fixed - MockDateDecorator, + LoginStateDecorator, ] const preview: Preview = { From 1ebc22bdac83d5ed8bbb227b75017c3dc8647a49 Mon Sep 17 00:00:00 2001 From: Kar Rui Lau Date: Mon, 15 Jul 2024 18:55:48 +0800 Subject: [PATCH 11/15] feat: add page handler for listing resources --- .../src/stories/Page/SitePage.stories.tsx | 3 +- apps/studio/tests/msw/handlers/page.ts | 138 ++++++++++++++++++ 2 files changed, 140 insertions(+), 1 deletion(-) create mode 100644 apps/studio/tests/msw/handlers/page.ts diff --git a/apps/studio/src/stories/Page/SitePage.stories.tsx b/apps/studio/src/stories/Page/SitePage.stories.tsx index 7006661e4..eb143ac41 100644 --- a/apps/studio/src/stories/Page/SitePage.stories.tsx +++ b/apps/studio/src/stories/Page/SitePage.stories.tsx @@ -1,5 +1,6 @@ import type { Meta, StoryObj } from "@storybook/react" import { meHandlers } from "tests/msw/handlers/me" +import { pageHandlers } from "tests/msw/handlers/page" import SitePage from "~/pages/sites/[siteId]" @@ -9,7 +10,7 @@ const meta: Meta = { parameters: { getLayout: SitePage.getLayout, msw: { - handlers: [meHandlers.me()], + handlers: [meHandlers.me(), pageHandlers.list.default()], }, }, decorators: [], diff --git a/apps/studio/tests/msw/handlers/page.ts b/apps/studio/tests/msw/handlers/page.ts new file mode 100644 index 000000000..fdecd68ab --- /dev/null +++ b/apps/studio/tests/msw/handlers/page.ts @@ -0,0 +1,138 @@ +import type { DelayMode } from "msw" +import { delay } from "msw" + +import { trpcMsw } from "../mockTrpc" + +const pageListQuery = (wait?: DelayMode | number) => { + return trpcMsw.page.list.query(async () => { + if (wait !== undefined) { + await delay(wait) + } + return [ + { + id: "0001", + name: "Test Page 1", + permalink: "/", + type: "page", + status: "draft", + lastEditUser: "user1@test.com", + lastEditDate: new Date("2024-07-15T09:16:46.640Z"), + }, + { + id: "0002", + name: "Test Page 2", + permalink: "/testpage2", + type: "page", + status: "published", + lastEditUser: "user2@test.com", + lastEditDate: new Date("2024-06-15T09:16:46.640Z"), + }, + { + id: "0003", + name: "Test Folder 1", + permalink: "/testfolder1", + type: "folder", + status: "folder", + lastEditUser: "folder", + lastEditDate: "folder", + }, + { + id: "0004", + name: "Test Folder 2", + permalink: "/testfolder2", + type: "folder", + status: "folder", + lastEditUser: "folder", + lastEditDate: "folder", + }, + { + id: "0005", + name: "Test Page 5", + permalink: "/", + type: "page", + status: "draft", + lastEditUser: "user1@test.com", + lastEditDate: new Date("2024-07-15T09:16:46.640Z"), + }, + { + id: "0006", + name: "Test Folder 6", + permalink: "/testfolder6", + type: "folder", + status: "folder", + lastEditUser: "folder", + lastEditDate: "folder", + }, + { + id: "0007", + name: "Test Page 7", + permalink: "/testpage7", + type: "page", + status: "published", + lastEditUser: "user7@test.com", + lastEditDate: new Date("2024-06-15T09:16:46.640Z"), + }, + { + id: "0008", + name: "Test Folder 8", + permalink: "/testfolder8", + type: "folder", + status: "folder", + lastEditUser: "folder", + lastEditDate: "folder", + }, + { + id: "0009", + name: "Test Folder 9", + permalink: "/testfolder9", + type: "folder", + status: "folder", + lastEditUser: "folder", + lastEditDate: "folder", + }, + { + id: "0010", + name: "Test Page 10", + permalink: "/testpage10", + type: "page", + status: "published", + lastEditUser: "user2@test.com", + lastEditDate: new Date("2024-06-15T09:16:46.640Z"), + }, + { + id: "0011", + name: "Test Folder 11", + permalink: "/testfolder11", + type: "folder", + status: "folder", + lastEditUser: "folder", + lastEditDate: "folder", + }, + { + id: "0012", + name: "Test Page 12", + permalink: "/testpage12", + type: "page", + status: "draft", + lastEditUser: "user1@test.com", + lastEditDate: new Date("2024-07-15T09:16:46.640Z"), + }, + { + id: "0013", + name: "Test Folder 13", + permalink: "/testfolder13", + type: "folder", + status: "folder", + lastEditUser: "folder", + lastEditDate: "folder", + }, + ] + }) +} + +export const pageHandlers = { + list: { + default: pageListQuery, + loading: () => pageListQuery("infinite"), + }, +} From ab8d2123c4ef76655c91a5acfe2bd3a73a9d0335 Mon Sep 17 00:00:00 2001 From: Kar Rui Lau Date: Tue, 16 Jul 2024 11:22:31 +0800 Subject: [PATCH 12/15] feat: show different table menu depending on resource type --- .../ResourceTable/ResourceTable.tsx | 7 ++++- .../ResourceTable/ResourceTableMenu.tsx | 30 +++++++++++++------ 2 files changed, 27 insertions(+), 10 deletions(-) diff --git a/apps/studio/src/features/dashboard/components/ResourceTable/ResourceTable.tsx b/apps/studio/src/features/dashboard/components/ResourceTable/ResourceTable.tsx index 554e6d344..9c712a645 100644 --- a/apps/studio/src/features/dashboard/components/ResourceTable/ResourceTable.tsx +++ b/apps/studio/src/features/dashboard/components/ResourceTable/ResourceTable.tsx @@ -52,7 +52,12 @@ const columns = [ columnsHelper.display({ id: "resource_menu", header: () => Actions, - cell: ({ row }) => , + cell: ({ row }) => ( + + ), size: 24, }), ] diff --git a/apps/studio/src/features/dashboard/components/ResourceTable/ResourceTableMenu.tsx b/apps/studio/src/features/dashboard/components/ResourceTable/ResourceTableMenu.tsx index 6dcb9f9bb..d40520ebf 100644 --- a/apps/studio/src/features/dashboard/components/ResourceTable/ResourceTableMenu.tsx +++ b/apps/studio/src/features/dashboard/components/ResourceTable/ResourceTableMenu.tsx @@ -8,13 +8,15 @@ import { BiTrash, } from "react-icons/bi" +import type { ResourceTableData } from "./types" import { MenuItem } from "~/components/Menu" -export const ResourceTableMenu = ({ - resourceId: _resourceId, -}: { - resourceId: string -}) => { +interface ResourceTableMenuProps { + resourceId: ResourceTableData["id"] + type: ResourceTableData["type"] +} + +export const ResourceTableMenu = ({ type }: ResourceTableMenuProps) => { return ( {/* TODO: Open edit modal depending on resource */} - }>Edit page settings - }> - Duplicate page - + {type === "page" ? ( + <> + }> + Edit page settings + + }> + Duplicate page + + + ) : ( + }> + Edit folder settings + + )} }>Move to... }> Delete From d9592621c5256623384f9fe07adecb14b7d1c4e0 Mon Sep 17 00:00:00 2001 From: Kar Rui Lau Date: Tue, 16 Jul 2024 11:30:30 +0800 Subject: [PATCH 13/15] feat(sitepage): add stories for the different menu actions --- .../ResourceTable/ResourceTable.tsx | 1 + .../ResourceTable/ResourceTableMenu.tsx | 5 ++-- .../src/stories/Page/SitePage.stories.tsx | 25 +++++++++++++++++++ 3 files changed, 29 insertions(+), 2 deletions(-) diff --git a/apps/studio/src/features/dashboard/components/ResourceTable/ResourceTable.tsx b/apps/studio/src/features/dashboard/components/ResourceTable/ResourceTable.tsx index 9c712a645..b80101aa6 100644 --- a/apps/studio/src/features/dashboard/components/ResourceTable/ResourceTable.tsx +++ b/apps/studio/src/features/dashboard/components/ResourceTable/ResourceTable.tsx @@ -54,6 +54,7 @@ const columns = [ header: () => Actions, cell: ({ row }) => ( diff --git a/apps/studio/src/features/dashboard/components/ResourceTable/ResourceTableMenu.tsx b/apps/studio/src/features/dashboard/components/ResourceTable/ResourceTableMenu.tsx index d40520ebf..15132fd89 100644 --- a/apps/studio/src/features/dashboard/components/ResourceTable/ResourceTableMenu.tsx +++ b/apps/studio/src/features/dashboard/components/ResourceTable/ResourceTableMenu.tsx @@ -12,15 +12,16 @@ import type { ResourceTableData } from "./types" import { MenuItem } from "~/components/Menu" interface ResourceTableMenuProps { + title: ResourceTableData["name"] resourceId: ResourceTableData["id"] type: ResourceTableData["type"] } -export const ResourceTableMenu = ({ type }: ResourceTableMenuProps) => { +export const ResourceTableMenu = ({ title, type }: ResourceTableMenuProps) => { return ( } diff --git a/apps/studio/src/stories/Page/SitePage.stories.tsx b/apps/studio/src/stories/Page/SitePage.stories.tsx index eb143ac41..9146329c0 100644 --- a/apps/studio/src/stories/Page/SitePage.stories.tsx +++ b/apps/studio/src/stories/Page/SitePage.stories.tsx @@ -1,4 +1,5 @@ import type { Meta, StoryObj } from "@storybook/react" +import { userEvent, waitFor, within } from "@storybook/test" import { meHandlers } from "tests/msw/handlers/me" import { pageHandlers } from "tests/msw/handlers/page" @@ -22,3 +23,27 @@ type Story = StoryObj export const Default: Story = { args: {}, } + +export const PageResourceMenu: Story = { + play: async ({ canvasElement }) => { + await waitFor(async () => { + const screen = within(canvasElement) + const pageMenuButton = screen.getByRole("button", { + name: "Options for Test Page 1", + }) + await userEvent.click(pageMenuButton) + }) + }, +} + +export const FolderResourceMenu: Story = { + play: async ({ canvasElement }) => { + await waitFor(async () => { + const screen = within(canvasElement) + const folderMenuButton = screen.getByRole("button", { + name: "Options for Test Folder 1", + }) + await userEvent.click(folderMenuButton) + }) + }, +} From 39030cbc188ba5b55f8f274b3c9d7d7d73202e2a Mon Sep 17 00:00:00 2001 From: Kar Rui Lau Date: Wed, 17 Jul 2024 10:54:39 +0800 Subject: [PATCH 14/15] feat: remove unused width calculation and tablePropOverride prop --- .../src/components/Datatable/Datatable.tsx | 18 +++--------------- 1 file changed, 3 insertions(+), 15 deletions(-) diff --git a/apps/studio/src/components/Datatable/Datatable.tsx b/apps/studio/src/components/Datatable/Datatable.tsx index ee9f75daa..57863a8c9 100644 --- a/apps/studio/src/components/Datatable/Datatable.tsx +++ b/apps/studio/src/components/Datatable/Datatable.tsx @@ -1,4 +1,4 @@ -import type { LayoutProps, TableCellProps, TableProps } from "@chakra-ui/react" +import type { LayoutProps, TableProps } from "@chakra-ui/react" import type { Table as ReactTable } from "@tanstack/react-table" import { Box, @@ -30,7 +30,6 @@ export interface DatatableProps extends TableProps { */ totalRowCountString?: string isFetching?: boolean - tablePropOverrides?: Record emptyPlaceholder?: React.ReactElement overflow?: LayoutProps["overflow"] } @@ -47,7 +46,6 @@ export const Datatable = ({ pagination, totalRowCount, totalRowCountString, - tablePropOverrides, emptyPlaceholder, overflow = "auto", ...tableProps @@ -102,12 +100,7 @@ export const Datatable = ({ pos="relative" px={0} style={{ - width: - header.getSize() === Number.MAX_SAFE_INTEGER - ? "auto" - : header.getSize() === Number.MIN_SAFE_INTEGER - ? "fit-content" - : header.getSize(), + width: header.getSize(), }} > @@ -128,12 +121,7 @@ export const Datatable = ({ {row.getVisibleCells().map((cell) => { return ( - + {flexRender( cell.column.columnDef.cell, cell.getContext(), From 56b7c08a6ba982c5ab57b5908fa9b2b5fa083292 Mon Sep 17 00:00:00 2001 From: Kar Rui Lau Date: Wed, 17 Jul 2024 10:56:20 +0800 Subject: [PATCH 15/15] feat: remove unused prop --- apps/studio/src/components/Datatable/DatatablePagination.tsx | 1 - 1 file changed, 1 deletion(-) diff --git a/apps/studio/src/components/Datatable/DatatablePagination.tsx b/apps/studio/src/components/Datatable/DatatablePagination.tsx index fb17dbc64..ce22e16f9 100644 --- a/apps/studio/src/components/Datatable/DatatablePagination.tsx +++ b/apps/studio/src/components/Datatable/DatatablePagination.tsx @@ -3,7 +3,6 @@ import { type Table } from "@tanstack/react-table" export interface DataTablePaginationProps { instance: Table - pageSizeOptions?: number[] totalRowCount?: number }