From 11d1e334868dc77d8fd48a964905ad4d1ac8eac0 Mon Sep 17 00:00:00 2001 From: Sianida26 Date: Fri, 26 Jan 2024 11:42:42 +0700 Subject: [PATCH] Added base for role table --- package.json | 2 +- pnpm-lock.yaml | 14 ++-- .../migration.sql | 66 +++++++++++++++++ .../migration.sql | 5 ++ prisma/schema.prisma | 34 +++++++-- .../roles/_tables/RolesTable/RolesTable.tsx | 71 +++++++++++++++++++ .../roles/_tables/RolesTable/columns.tsx | 38 ++++++++++ src/app/dashboard/(auth)/roles/page.tsx | 17 +++++ .../users/_tables/UsersTable/UsersTable.tsx | 2 + .../users/_tables/UsersTable/columns.tsx | 2 +- src/app/dashboard/(auth)/users/page.tsx | 2 + src/components/AppNavbar/_data/allMenu.ts | 2 +- 12 files changed, 239 insertions(+), 16 deletions(-) create mode 100644 prisma/migrations/20240125192659_added_role_and_permission_table/migration.sql create mode 100644 prisma/migrations/20240125193103_add_status_for_role_and_permission/migration.sql create mode 100644 src/app/dashboard/(auth)/roles/_tables/RolesTable/RolesTable.tsx create mode 100644 src/app/dashboard/(auth)/roles/_tables/RolesTable/columns.tsx create mode 100644 src/app/dashboard/(auth)/roles/page.tsx diff --git a/package.json b/package.json index 691e49c..afe1d90 100644 --- a/package.json +++ b/package.json @@ -14,7 +14,7 @@ "@mantine/form": "^7.4.2", "@mantine/hooks": "^7.4.2", "@mantine/notifications": "^7.4.2", - "@prisma/client": "5.7.1", + "@prisma/client": "5.8.1", "@tanstack/react-query": "^4.36.1", "@tanstack/react-query-devtools": "^4.36.1", "@tanstack/react-table": "^8.11.7", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 23749a4..b6bdce9 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -7,7 +7,7 @@ settings: dependencies: '@auth/prisma-adapter': specifier: ^1.0.16 - version: 1.0.16(@prisma/client@5.7.1) + version: 1.0.16(@prisma/client@5.8.1) '@mantine/core': specifier: ^7.4.2 version: 7.4.2(@mantine/hooks@7.4.2)(@types/react@18.2.48)(react-dom@18.2.0)(react@18.2.0) @@ -21,8 +21,8 @@ dependencies: specifier: ^7.4.2 version: 7.4.2(@mantine/core@7.4.2)(@mantine/hooks@7.4.2)(react-dom@18.2.0)(react@18.2.0) '@prisma/client': - specifier: 5.7.1 - version: 5.7.1(prisma@5.8.1) + specifier: 5.8.1 + version: 5.8.1(prisma@5.8.1) '@tanstack/react-query': specifier: ^4.36.1 version: 4.36.1(react-dom@18.2.0)(react@18.2.0) @@ -159,13 +159,13 @@ packages: preact-render-to-string: 5.2.3(preact@10.11.3) dev: false - /@auth/prisma-adapter@1.0.16(@prisma/client@5.7.1): + /@auth/prisma-adapter@1.0.16(@prisma/client@5.8.1): resolution: {integrity: sha512-i7+XCxrbv5n8Yp9r+FznvnOBG7BrjpfmXr4Fl7pL7LPgTGhDJPE10BokVf5tGTsR8SGnAp04qhBzgjTrTrmpPQ==} peerDependencies: '@prisma/client': '>=2.26.0 || >=3 || >=4 || >=5' dependencies: '@auth/core': 0.22.0 - '@prisma/client': 5.7.1(prisma@5.8.1) + '@prisma/client': 5.8.1(prisma@5.8.1) transitivePeerDependencies: - nodemailer dev: false @@ -509,8 +509,8 @@ packages: dev: true optional: true - /@prisma/client@5.7.1(prisma@5.8.1): - resolution: {integrity: sha512-TUSa4nUcC4nf/e7X3jyO1pEd6XcI/TLRCA0KjkA46RDIpxUaRsBYEOqITwXRW2c0bMFyKcCRXrH4f7h4q9oOlg==} + /@prisma/client@5.8.1(prisma@5.8.1): + resolution: {integrity: sha512-xQtMPfbIwLlbm0VVIVQY2yqQVOxPwRQhvIp7Z3m2900g1bu/zRHKhYZJQWELqmjl6d8YwBy0K2NvMqh47v1ubw==} engines: {node: '>=16.13'} requiresBuild: true peerDependencies: diff --git a/prisma/migrations/20240125192659_added_role_and_permission_table/migration.sql b/prisma/migrations/20240125192659_added_role_and_permission_table/migration.sql new file mode 100644 index 0000000..8df4a92 --- /dev/null +++ b/prisma/migrations/20240125192659_added_role_and_permission_table/migration.sql @@ -0,0 +1,66 @@ +-- CreateTable +CREATE TABLE `Role` ( + `id` VARCHAR(191) NOT NULL, + `code` VARCHAR(191) NOT NULL, + `name` VARCHAR(191) NOT NULL, + `description` VARCHAR(191) NOT NULL DEFAULT '', + + UNIQUE INDEX `Role_code_key`(`code`), + PRIMARY KEY (`id`) +) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci; + +-- CreateTable +CREATE TABLE `Permission` ( + `id` VARCHAR(191) NOT NULL, + `code` VARCHAR(191) NOT NULL, + `name` VARCHAR(191) NOT NULL, + `description` VARCHAR(191) NOT NULL DEFAULT '', + + UNIQUE INDEX `Permission_code_key`(`code`), + PRIMARY KEY (`id`) +) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci; + +-- CreateTable +CREATE TABLE `_RoleToUser` ( + `A` VARCHAR(191) NOT NULL, + `B` VARCHAR(191) NOT NULL, + + UNIQUE INDEX `_RoleToUser_AB_unique`(`A`, `B`), + INDEX `_RoleToUser_B_index`(`B`) +) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci; + +-- CreateTable +CREATE TABLE `_PermissionToRole` ( + `A` VARCHAR(191) NOT NULL, + `B` VARCHAR(191) NOT NULL, + + UNIQUE INDEX `_PermissionToRole_AB_unique`(`A`, `B`), + INDEX `_PermissionToRole_B_index`(`B`) +) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci; + +-- CreateTable +CREATE TABLE `_PermissionToUser` ( + `A` VARCHAR(191) NOT NULL, + `B` VARCHAR(191) NOT NULL, + + UNIQUE INDEX `_PermissionToUser_AB_unique`(`A`, `B`), + INDEX `_PermissionToUser_B_index`(`B`) +) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci; + +-- AddForeignKey +ALTER TABLE `_RoleToUser` ADD CONSTRAINT `_RoleToUser_A_fkey` FOREIGN KEY (`A`) REFERENCES `Role`(`id`) ON DELETE CASCADE ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE `_RoleToUser` ADD CONSTRAINT `_RoleToUser_B_fkey` FOREIGN KEY (`B`) REFERENCES `User`(`id`) ON DELETE CASCADE ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE `_PermissionToRole` ADD CONSTRAINT `_PermissionToRole_A_fkey` FOREIGN KEY (`A`) REFERENCES `Permission`(`id`) ON DELETE CASCADE ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE `_PermissionToRole` ADD CONSTRAINT `_PermissionToRole_B_fkey` FOREIGN KEY (`B`) REFERENCES `Role`(`id`) ON DELETE CASCADE ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE `_PermissionToUser` ADD CONSTRAINT `_PermissionToUser_A_fkey` FOREIGN KEY (`A`) REFERENCES `Permission`(`id`) ON DELETE CASCADE ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE `_PermissionToUser` ADD CONSTRAINT `_PermissionToUser_B_fkey` FOREIGN KEY (`B`) REFERENCES `User`(`id`) ON DELETE CASCADE ON UPDATE CASCADE; diff --git a/prisma/migrations/20240125193103_add_status_for_role_and_permission/migration.sql b/prisma/migrations/20240125193103_add_status_for_role_and_permission/migration.sql new file mode 100644 index 0000000..7a44158 --- /dev/null +++ b/prisma/migrations/20240125193103_add_status_for_role_and_permission/migration.sql @@ -0,0 +1,5 @@ +-- AlterTable +ALTER TABLE `Permission` ADD COLUMN `isActive` BOOLEAN NOT NULL DEFAULT false; + +-- AlterTable +ALTER TABLE `Role` ADD COLUMN `isActive` BOOLEAN NOT NULL DEFAULT false; diff --git a/prisma/schema.prisma b/prisma/schema.prisma index 18e5f62..fc0f2a2 100644 --- a/prisma/schema.prisma +++ b/prisma/schema.prisma @@ -11,12 +11,14 @@ datasource db { } model User { - id String @id @default(cuid()) - name String? - email String? @unique - emailVerified DateTime? - passwordHash String? - photoProfile UserPhotoProfiles? + id String @id @default(cuid()) + name String? + email String? @unique + emailVerified DateTime? + passwordHash String? + photoProfile UserPhotoProfiles? + roles Role[] + directPermissions Permission[] } model UserPhotoProfiles { @@ -24,4 +26,24 @@ model UserPhotoProfiles { userId String @unique path String user User @relation(fields: [userId], references: [id], onDelete: Cascade) +} + +model Role { + id String @id @default(cuid()) + code String @unique + name String + description String @default("") + isActive Boolean @default(false) + users User[] + permissions Permission[] +} + +model Permission { + id String @id @default(cuid()) + code String @unique + name String + description String @default("") + isActive Boolean @default(false) + roles Role[] + directUsers User[] } \ No newline at end of file diff --git a/src/app/dashboard/(auth)/roles/_tables/RolesTable/RolesTable.tsx b/src/app/dashboard/(auth)/roles/_tables/RolesTable/RolesTable.tsx new file mode 100644 index 0000000..abe9665 --- /dev/null +++ b/src/app/dashboard/(auth)/roles/_tables/RolesTable/RolesTable.tsx @@ -0,0 +1,71 @@ +"use client"; +import { Table, Text } from "@mantine/core"; +import { + flexRender, + getCoreRowModel, + useReactTable, +} from "@tanstack/react-table"; +import React from "react"; +import columns from "./columns"; + +export default function RolesTable() { + const table = useReactTable({ + data: [], + columns, + getCoreRowModel: getCoreRowModel(), + defaultColumn: { + cell: (props) => {props.getValue() as React.ReactNode}, + }, + }); + + // TODO: Add view when data is empty + + return ( + + {/* Thead */} + + {table.getHeaderGroups().map((headerGroup) => ( + + {headerGroup.headers.map((header) => ( + + {header.isPlaceholder + ? null + : flexRender( + header.column.columnDef.header, + header.getContext() + )} + + ))} + + ))} + + + {/* Tbody */} + + {table.getRowModel().rows.map((row) => ( + + {row.getVisibleCells().map((cell) => ( + + {flexRender( + cell.column.columnDef.cell, + cell.getContext() + )} + + ))} + + ))} + +
+ ); +} diff --git a/src/app/dashboard/(auth)/roles/_tables/RolesTable/columns.tsx b/src/app/dashboard/(auth)/roles/_tables/RolesTable/columns.tsx new file mode 100644 index 0000000..270ccf9 --- /dev/null +++ b/src/app/dashboard/(auth)/roles/_tables/RolesTable/columns.tsx @@ -0,0 +1,38 @@ +import { createColumnHelper } from "@tanstack/react-table"; +import { StringifyOptions } from "querystring"; + +export interface RoleRow { + id: string, + code: string, + name: string, + permissionCount: number, + userCount: number, +} + +const columnHelper = createColumnHelper() + +const columns = [ + columnHelper.accessor("id",{ + id: "sequence", + header: "#", + cell: props => props.row.index + 1, + }), + + columnHelper.accessor("code", { + header: 'Code', + }), + + columnHelper.accessor("name", { + header: "Name" + }), + + columnHelper.accessor("permissionCount", { + header: "Permissions" + }), + + columnHelper.accessor("userCount", { + header: "Users" + }), +] + +export default columns; diff --git a/src/app/dashboard/(auth)/roles/page.tsx b/src/app/dashboard/(auth)/roles/page.tsx new file mode 100644 index 0000000..187bcfa --- /dev/null +++ b/src/app/dashboard/(auth)/roles/page.tsx @@ -0,0 +1,17 @@ +import { Card, Stack, Title } from "@mantine/core"; +import { Metadata } from "next"; +import React from "react"; +import RolesTable from "./_tables/RolesTable/RolesTable"; + +export const metadata: Metadata = { + title: "Roles", +}; + +export default function RolesPage() { + return + Roles + + + + ; +} diff --git a/src/app/dashboard/(auth)/users/_tables/UsersTable/UsersTable.tsx b/src/app/dashboard/(auth)/users/_tables/UsersTable/UsersTable.tsx index 20b31ac..19e1624 100644 --- a/src/app/dashboard/(auth)/users/_tables/UsersTable/UsersTable.tsx +++ b/src/app/dashboard/(auth)/users/_tables/UsersTable/UsersTable.tsx @@ -24,6 +24,8 @@ export default function UsersTable({users}: Props) { } }); + // TODO: Add view when data is empty + return ( <> diff --git a/src/app/dashboard/(auth)/users/_tables/UsersTable/columns.tsx b/src/app/dashboard/(auth)/users/_tables/UsersTable/columns.tsx index b1b5986..4c5aaf7 100644 --- a/src/app/dashboard/(auth)/users/_tables/UsersTable/columns.tsx +++ b/src/app/dashboard/(auth)/users/_tables/UsersTable/columns.tsx @@ -15,7 +15,7 @@ const columnHelper = createColumnHelper() const columns = [ columnHelper.display({ - id: "seequence", + id: "sequence", header: "#", cell: props => props.row.index + 1, size: 1 diff --git a/src/app/dashboard/(auth)/users/page.tsx b/src/app/dashboard/(auth)/users/page.tsx index 606126a..583fd0e 100644 --- a/src/app/dashboard/(auth)/users/page.tsx +++ b/src/app/dashboard/(auth)/users/page.tsx @@ -46,6 +46,8 @@ export default async function UsersPage({searchParams}: Props) { return null; } + // TODO: Add functinoality for create new user + return ( Users diff --git a/src/components/AppNavbar/_data/allMenu.ts b/src/components/AppNavbar/_data/allMenu.ts index 035b898..bf4098d 100644 --- a/src/components/AppNavbar/_data/allMenu.ts +++ b/src/components/AppNavbar/_data/allMenu.ts @@ -29,7 +29,7 @@ const allMenu: MenuItem[] = [ color: "grape", children: [ { label: "Users", link: "/users" }, - { label: "Roles", link: "#" }, + { label: "Roles", link: "/roles" }, { label: "Permissions", link: "#" }, ], },