From 0116a1ae2c87140e446c25b2827b184e2a287232 Mon Sep 17 00:00:00 2001 From: Henry Date: Thu, 21 Dec 2023 17:43:40 +0000 Subject: [PATCH] feat: add card labels --- src/app/_components/modal.tsx | 4 +- src/app/boards/[...id]/page.tsx | 35 +- src/app/cards/[...id]/components/Dropdown.tsx | 2 +- .../[...id]/components/LabelSelector.tsx | 140 ++++ src/app/cards/[...id]/page.tsx | 86 ++- src/server/api/routers/board.ts | 17 + src/server/api/routers/card.ts | 63 +- .../db/migrations/0003_heavy_thanos.sql | 20 + .../db/migrations/0004_tidy_lord_hawal.sql | 1 + .../db/migrations/meta/0003_snapshot.json | 639 +++++++++++++++++ .../db/migrations/meta/0004_snapshot.json | 647 ++++++++++++++++++ src/server/db/migrations/meta/_journal.json | 14 + src/server/db/schema.ts | 54 +- 13 files changed, 1685 insertions(+), 37 deletions(-) create mode 100644 src/app/cards/[...id]/components/LabelSelector.tsx create mode 100644 src/server/db/migrations/0003_heavy_thanos.sql create mode 100644 src/server/db/migrations/0004_tidy_lord_hawal.sql create mode 100644 src/server/db/migrations/meta/0003_snapshot.json create mode 100644 src/server/db/migrations/meta/0004_snapshot.json diff --git a/src/app/_components/modal.tsx b/src/app/_components/modal.tsx index 170fbc23..a0d6f849 100644 --- a/src/app/_components/modal.tsx +++ b/src/app/_components/modal.tsx @@ -28,7 +28,7 @@ const Modal: React.FC = ({ children }) => {
-
+
= ({ children }) => { leaveFrom="opacity-100 translate-y-0 sm:scale-100" leaveTo="opacity-0 translate-y-4 sm:translate-y-0 sm:scale-95" > - + {children} diff --git a/src/app/boards/[...id]/page.tsx b/src/app/boards/[...id]/page.tsx index 14a9ba1e..929ebb1c 100644 --- a/src/app/boards/[...id]/page.tsx +++ b/src/app/boards/[...id]/page.tsx @@ -30,6 +30,17 @@ interface List { interface Card { publicId: string; title: string; + labels?: Label[]; +} + +interface Label { + label: LabelData; +} + +interface LabelData { + publicId: string; + name: string; + colourCode: string; } interface FormValues { @@ -226,12 +237,32 @@ export default function BoardPage() { - {card.title} +
{card.title}
+ {card.labels?.length ? ( +
+ {card.labels.map(({ label }) => ( + + +
{label.name}
+
+ ))} +
+ ) : null} )} diff --git a/src/app/cards/[...id]/components/Dropdown.tsx b/src/app/cards/[...id]/components/Dropdown.tsx index b3ac0e84..2e9c80fc 100644 --- a/src/app/cards/[...id]/components/Dropdown.tsx +++ b/src/app/cards/[...id]/components/Dropdown.tsx @@ -10,7 +10,7 @@ export default function Dropdown() {
- +
diff --git a/src/app/cards/[...id]/components/LabelSelector.tsx b/src/app/cards/[...id]/components/LabelSelector.tsx new file mode 100644 index 00000000..20cb5a39 --- /dev/null +++ b/src/app/cards/[...id]/components/LabelSelector.tsx @@ -0,0 +1,140 @@ +import { Fragment } from "react"; +import { api } from "~/trpc/react"; +import { Menu, Transition } from "@headlessui/react"; +import { HiMiniPlus } from "react-icons/hi2"; +import { useFormik } from "formik"; + +interface LabelSelectorProps { + cardPublicId: string; + labels: { + publicId: string; + name: string; + selected: boolean; + colourCode: string; + }[]; +} + +export default function LabelSelector({ + cardPublicId, + labels, +}: LabelSelectorProps) { + const utils = api.useUtils(); + + const refetchCard = () => utils.card.byId.refetch({ id: cardPublicId }); + + const addOrRemoveLabel = api.card.addOrRemoveLabel.useMutation({ + onSuccess: async () => { + await refetchCard(); + }, + }); + + const formik = useFormik({ + initialValues: { + ...Object.fromEntries( + labels?.map((label) => [label.publicId, label.selected]) ?? [], + ), + }, + onSubmit: (values) => { + console.log({ values }); + }, + enableReinitialize: true, + }); + + const selectedLabels = labels.filter((label) => label.selected); + + return ( + <> + + {selectedLabels.length ? ( + <> + {selectedLabels.map((label) => ( + + +
{label.name}
+
+ ))} + + + Add label + + + ) : ( + + + Add label + + )} + + + +
+
+ {labels?.map((label) => ( + + {() => ( +
{ + e.preventDefault(); + await formik.setFieldValue( + label.publicId, + !formik.values[label.publicId], + ); + + addOrRemoveLabel.mutate({ + cardPublicId, + labelPublicId: label.publicId, + }); + + await formik.submitForm(); + }} + > + event.stopPropagation()} + onChange={formik.handleChange} + checked={formik.values[label.publicId]} + /> + +
+ )} +
+ ))} +
+
+
+
+
+ + ); +} diff --git a/src/app/cards/[...id]/page.tsx b/src/app/cards/[...id]/page.tsx index 923af118..1e7f6a5d 100644 --- a/src/app/cards/[...id]/page.tsx +++ b/src/app/cards/[...id]/page.tsx @@ -6,11 +6,13 @@ import ContentEditable from "react-contenteditable"; import Dropdown from "./components/Dropdown"; import { DeleteCardConfirmation } from "./components/DeleteCardConfirmation"; +import LabelSelector from "./components/LabelSelector"; import Modal from "~/app/_components/modal"; import { useModal } from "~/app/providers/modal"; import { api } from "~/trpc/react"; + interface FormValues { cardId: string; title: string; @@ -26,6 +28,21 @@ export default function CardPage() { const { data } = api.card.byId.useQuery({ id: cardId ?? "" }); const boardId = data?.list?.board?.publicId; + const labels = data?.list?.board?.labels; + const selectedLabels = data?.labels; + + const formattedLabels = + labels?.map((label) => { + const isSelected = selectedLabels?.some( + (selectedLabel) => selectedLabel.label.publicId === label.publicId, + ); + + return { + ...label, + selected: isSelected ?? false, + colourCode: label.colourCode ?? "", + }; + }) ?? []; const updateCard = api.card.update.useMutation(); @@ -48,40 +65,49 @@ export default function CardPage() { if (!cardId) return <>; return ( -
-
-
-
- +
+
+
+ +
+ +
+ +
+
- -
- +
+
+
+
+ + formik.setFieldValue("description", e.target.value) + } + onBlur={formik.submitForm} + className="block w-full border-0 bg-transparent py-1.5 text-dark-1000 focus-visible:outline-none sm:text-sm sm:leading-6" + /> +
+
-
-
-
- - formik.setFieldValue("description", e.target.value) - } - onBlur={formik.submitForm} - className="block w-full border-0 bg-transparent py-1.5 text-dark-1000 focus-visible:outline-none sm:text-sm sm:leading-6" - /> -
-
+
+
+

Labels

+ +
+ {modalContentType === "DELETE_CARD" && ( { + const userId = ctx.session?.user.id; + + if (!userId) return; + + return ctx.db.transaction(async (tx) => { + const card = await tx.query.cards.findFirst({ + where: and(eq(cards.publicId, input.cardPublicId), isNull(cards.deletedAt)), + }); + + const label = await tx.query.labels.findFirst({ + where: eq(labels.publicId, input.labelPublicId), + }); + + if (!card || !label) return; + + const labelExists = await tx.query.cardsToLabels.findFirst({ + where: and(eq(cardsToLabels.cardId, card.id), eq(cardsToLabels.labelId, label.id)), + }); + + if (labelExists) { + return tx.delete(cardsToLabels).where(and(eq(cardsToLabels.cardId, card.id), eq(cardsToLabels.labelId, label.id)),); + } + + return tx.insert(cardsToLabels).values({ + cardId: card.id, + labelId: label.id, + }); + }) + }), byId: publicProcedure .input(z.object({ id: z.string().min(12) })) .query(({ ctx, input }) => ctx.db.query.cards.findFirst({ with: { + labels: { + columns: { + labelId: false, + cardId: false, + }, + with: { + label: { + columns: { + publicId: true, + name: true, + colourCode: true, + } + } + } + }, list: { columns: { publicId: true, @@ -63,6 +115,15 @@ export const cardRouter = createTRPCRouter({ columns: { publicId: true, }, + with: { + labels: { + columns: { + publicId: true, + colourCode: true, + name: true, + } + } + } } } }, diff --git a/src/server/db/migrations/0003_heavy_thanos.sql b/src/server/db/migrations/0003_heavy_thanos.sql new file mode 100644 index 00000000..260fdd2a --- /dev/null +++ b/src/server/db/migrations/0003_heavy_thanos.sql @@ -0,0 +1,20 @@ +CREATE TABLE `card_label` ( + `cardId` bigint NOT NULL, + `labelId` bigint NOT NULL +); +--> statement-breakpoint +CREATE TABLE `label` ( + `id` bigint AUTO_INCREMENT NOT NULL, + `publicId` varchar(12) NOT NULL, + `name` varchar(256) NOT NULL, + `colourCode` varchar(12), + `createdBy` varchar(256) NOT NULL, + `createdAt` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + `updatedAt` timestamp ON UPDATE CURRENT_TIMESTAMP, + `boardId` bigint NOT NULL, + CONSTRAINT `label_id` PRIMARY KEY(`id`), + CONSTRAINT `label_publicId_unique` UNIQUE(`publicId`) +); +--> statement-breakpoint +-- ALTER TABLE `card_label` ADD CONSTRAINT `card_label_cardId_card_id_fk` FOREIGN KEY (`cardId`) REFERENCES `card`(`id`) ON DELETE no action ON UPDATE no action;--> statement-breakpoint +-- ALTER TABLE `card_label` ADD CONSTRAINT `card_label_labelId_label_id_fk` FOREIGN KEY (`labelId`) REFERENCES `label`(`id`) ON DELETE no action ON UPDATE no action; \ No newline at end of file diff --git a/src/server/db/migrations/0004_tidy_lord_hawal.sql b/src/server/db/migrations/0004_tidy_lord_hawal.sql new file mode 100644 index 00000000..1f18ca12 --- /dev/null +++ b/src/server/db/migrations/0004_tidy_lord_hawal.sql @@ -0,0 +1 @@ +ALTER TABLE `card_label` ADD PRIMARY KEY(`cardId`,`labelId`); \ No newline at end of file diff --git a/src/server/db/migrations/meta/0003_snapshot.json b/src/server/db/migrations/meta/0003_snapshot.json new file mode 100644 index 00000000..4e5cf114 --- /dev/null +++ b/src/server/db/migrations/meta/0003_snapshot.json @@ -0,0 +1,639 @@ +{ + "version": "5", + "dialect": "mysql", + "id": "cb5d6d0a-3ad3-45b1-81a4-02844b130ebf", + "prevId": "a623c303-6c0b-416d-aa46-2c0a9e2328cd", + "tables": { + "account": { + "name": "account", + "columns": { + "userId": { + "name": "userId", + "type": "varchar(255)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "type": { + "name": "type", + "type": "varchar(255)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "provider": { + "name": "provider", + "type": "varchar(255)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "providerAccountId": { + "name": "providerAccountId", + "type": "varchar(255)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "refresh_token": { + "name": "refresh_token", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "access_token": { + "name": "access_token", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "expires_at": { + "name": "expires_at", + "type": "int", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "token_type": { + "name": "token_type", + "type": "varchar(255)", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "scope": { + "name": "scope", + "type": "varchar(255)", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "id_token": { + "name": "id_token", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "session_state": { + "name": "session_state", + "type": "varchar(255)", + "primaryKey": false, + "notNull": false, + "autoincrement": false + } + }, + "indexes": { + "userId_idx": { + "name": "userId_idx", + "columns": [ + "userId" + ], + "isUnique": false + } + }, + "foreignKeys": {}, + "compositePrimaryKeys": { + "account_provider_providerAccountId": { + "name": "account_provider_providerAccountId", + "columns": [ + "provider", + "providerAccountId" + ] + } + }, + "uniqueConstraints": {} + }, + "board": { + "name": "board", + "columns": { + "id": { + "name": "id", + "type": "bigint", + "primaryKey": false, + "notNull": true, + "autoincrement": true + }, + "publicId": { + "name": "publicId", + "type": "varchar(12)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "name": { + "name": "name", + "type": "varchar(255)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "createdBy": { + "name": "createdBy", + "type": "varchar(255)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "createdAt": { + "name": "createdAt", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "CURRENT_TIMESTAMP" + }, + "updatedAt": { + "name": "updatedAt", + "type": "timestamp", + "primaryKey": false, + "notNull": false, + "autoincrement": false, + "onUpdate": true + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": { + "board_id": { + "name": "board_id", + "columns": [ + "id" + ] + } + }, + "uniqueConstraints": { + "board_publicId_unique": { + "name": "board_publicId_unique", + "columns": [ + "publicId" + ] + } + } + }, + "card": { + "name": "card", + "columns": { + "id": { + "name": "id", + "type": "bigint", + "primaryKey": false, + "notNull": true, + "autoincrement": true + }, + "publicId": { + "name": "publicId", + "type": "varchar(12)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "title": { + "name": "title", + "type": "varchar(256)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "createdBy": { + "name": "createdBy", + "type": "varchar(256)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "createdAt": { + "name": "createdAt", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "CURRENT_TIMESTAMP" + }, + "updatedAt": { + "name": "updatedAt", + "type": "timestamp", + "primaryKey": false, + "notNull": false, + "autoincrement": false, + "onUpdate": true + }, + "listId": { + "name": "listId", + "type": "bigint", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "index": { + "name": "index", + "type": "int", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "deletedAt": { + "name": "deletedAt", + "type": "timestamp", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "deletedBy": { + "name": "deletedBy", + "type": "varchar(256)", + "primaryKey": false, + "notNull": false, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": { + "card_id": { + "name": "card_id", + "columns": [ + "id" + ] + } + }, + "uniqueConstraints": { + "card_publicId_unique": { + "name": "card_publicId_unique", + "columns": [ + "publicId" + ] + } + } + }, + "card_label": { + "name": "card_label", + "columns": { + "cardId": { + "name": "cardId", + "type": "bigint", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "labelId": { + "name": "labelId", + "type": "bigint", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": { + "card_label_cardId_card_id_fk": { + "name": "card_label_cardId_card_id_fk", + "tableFrom": "card_label", + "tableTo": "card", + "columnsFrom": [ + "cardId" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + }, + "card_label_labelId_label_id_fk": { + "name": "card_label_labelId_label_id_fk", + "tableFrom": "card_label", + "tableTo": "label", + "columnsFrom": [ + "labelId" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {} + }, + "label": { + "name": "label", + "columns": { + "id": { + "name": "id", + "type": "bigint", + "primaryKey": false, + "notNull": true, + "autoincrement": true + }, + "publicId": { + "name": "publicId", + "type": "varchar(12)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "name": { + "name": "name", + "type": "varchar(256)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "colourCode": { + "name": "colourCode", + "type": "varchar(12)", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "createdBy": { + "name": "createdBy", + "type": "varchar(256)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "createdAt": { + "name": "createdAt", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "CURRENT_TIMESTAMP" + }, + "updatedAt": { + "name": "updatedAt", + "type": "timestamp", + "primaryKey": false, + "notNull": false, + "autoincrement": false, + "onUpdate": true + }, + "boardId": { + "name": "boardId", + "type": "bigint", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": { + "label_id": { + "name": "label_id", + "columns": [ + "id" + ] + } + }, + "uniqueConstraints": { + "label_publicId_unique": { + "name": "label_publicId_unique", + "columns": [ + "publicId" + ] + } + } + }, + "list": { + "name": "list", + "columns": { + "id": { + "name": "id", + "type": "bigint", + "primaryKey": false, + "notNull": true, + "autoincrement": true + }, + "publicId": { + "name": "publicId", + "type": "varchar(12)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "name": { + "name": "name", + "type": "varchar(256)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "createdBy": { + "name": "createdBy", + "type": "varchar(256)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "createdAt": { + "name": "createdAt", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "CURRENT_TIMESTAMP" + }, + "updatedAt": { + "name": "updatedAt", + "type": "timestamp", + "primaryKey": false, + "notNull": false, + "autoincrement": false, + "onUpdate": true + }, + "boardId": { + "name": "boardId", + "type": "bigint", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "index": { + "name": "index", + "type": "int", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": { + "list_id": { + "name": "list_id", + "columns": [ + "id" + ] + } + }, + "uniqueConstraints": { + "list_publicId_unique": { + "name": "list_publicId_unique", + "columns": [ + "publicId" + ] + } + } + }, + "session": { + "name": "session", + "columns": { + "sessionToken": { + "name": "sessionToken", + "type": "varchar(255)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "userId": { + "name": "userId", + "type": "varchar(255)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "expires": { + "name": "expires", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": { + "userId_idx": { + "name": "userId_idx", + "columns": [ + "userId" + ], + "isUnique": false + } + }, + "foreignKeys": {}, + "compositePrimaryKeys": { + "session_sessionToken": { + "name": "session_sessionToken", + "columns": [ + "sessionToken" + ] + } + }, + "uniqueConstraints": {} + }, + "user": { + "name": "user", + "columns": { + "id": { + "name": "id", + "type": "varchar(255)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "name": { + "name": "name", + "type": "varchar(255)", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "email": { + "name": "email", + "type": "varchar(255)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "emailVerified": { + "name": "emailVerified", + "type": "timestamp(3)", + "primaryKey": false, + "notNull": false, + "autoincrement": false, + "default": "CURRENT_TIMESTAMP(3)" + }, + "image": { + "name": "image", + "type": "varchar(255)", + "primaryKey": false, + "notNull": false, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": { + "user_id": { + "name": "user_id", + "columns": [ + "id" + ] + } + }, + "uniqueConstraints": { + "user_email_unique": { + "name": "user_email_unique", + "columns": [ + "email" + ] + } + } + }, + "verificationToken": { + "name": "verificationToken", + "columns": { + "identifier": { + "name": "identifier", + "type": "varchar(255)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "token": { + "name": "token", + "type": "varchar(255)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "expires": { + "name": "expires", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": { + "verificationToken_identifier_token": { + "name": "verificationToken_identifier_token", + "columns": [ + "identifier", + "token" + ] + } + }, + "uniqueConstraints": {} + } + }, + "schemas": {}, + "_meta": { + "schemas": {}, + "tables": {}, + "columns": {} + } +} \ No newline at end of file diff --git a/src/server/db/migrations/meta/0004_snapshot.json b/src/server/db/migrations/meta/0004_snapshot.json new file mode 100644 index 00000000..c6bf79e8 --- /dev/null +++ b/src/server/db/migrations/meta/0004_snapshot.json @@ -0,0 +1,647 @@ +{ + "version": "5", + "dialect": "mysql", + "id": "52bf8e38-66ad-4bb6-9924-798177dbd1b5", + "prevId": "cb5d6d0a-3ad3-45b1-81a4-02844b130ebf", + "tables": { + "account": { + "name": "account", + "columns": { + "userId": { + "name": "userId", + "type": "varchar(255)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "type": { + "name": "type", + "type": "varchar(255)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "provider": { + "name": "provider", + "type": "varchar(255)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "providerAccountId": { + "name": "providerAccountId", + "type": "varchar(255)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "refresh_token": { + "name": "refresh_token", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "access_token": { + "name": "access_token", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "expires_at": { + "name": "expires_at", + "type": "int", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "token_type": { + "name": "token_type", + "type": "varchar(255)", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "scope": { + "name": "scope", + "type": "varchar(255)", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "id_token": { + "name": "id_token", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "session_state": { + "name": "session_state", + "type": "varchar(255)", + "primaryKey": false, + "notNull": false, + "autoincrement": false + } + }, + "indexes": { + "userId_idx": { + "name": "userId_idx", + "columns": [ + "userId" + ], + "isUnique": false + } + }, + "foreignKeys": {}, + "compositePrimaryKeys": { + "account_provider_providerAccountId": { + "name": "account_provider_providerAccountId", + "columns": [ + "provider", + "providerAccountId" + ] + } + }, + "uniqueConstraints": {} + }, + "board": { + "name": "board", + "columns": { + "id": { + "name": "id", + "type": "bigint", + "primaryKey": false, + "notNull": true, + "autoincrement": true + }, + "publicId": { + "name": "publicId", + "type": "varchar(12)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "name": { + "name": "name", + "type": "varchar(255)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "createdBy": { + "name": "createdBy", + "type": "varchar(255)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "createdAt": { + "name": "createdAt", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "CURRENT_TIMESTAMP" + }, + "updatedAt": { + "name": "updatedAt", + "type": "timestamp", + "primaryKey": false, + "notNull": false, + "autoincrement": false, + "onUpdate": true + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": { + "board_id": { + "name": "board_id", + "columns": [ + "id" + ] + } + }, + "uniqueConstraints": { + "board_publicId_unique": { + "name": "board_publicId_unique", + "columns": [ + "publicId" + ] + } + } + }, + "card": { + "name": "card", + "columns": { + "id": { + "name": "id", + "type": "bigint", + "primaryKey": false, + "notNull": true, + "autoincrement": true + }, + "publicId": { + "name": "publicId", + "type": "varchar(12)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "title": { + "name": "title", + "type": "varchar(256)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "createdBy": { + "name": "createdBy", + "type": "varchar(256)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "createdAt": { + "name": "createdAt", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "CURRENT_TIMESTAMP" + }, + "updatedAt": { + "name": "updatedAt", + "type": "timestamp", + "primaryKey": false, + "notNull": false, + "autoincrement": false, + "onUpdate": true + }, + "listId": { + "name": "listId", + "type": "bigint", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "index": { + "name": "index", + "type": "int", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "deletedAt": { + "name": "deletedAt", + "type": "timestamp", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "deletedBy": { + "name": "deletedBy", + "type": "varchar(256)", + "primaryKey": false, + "notNull": false, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": { + "card_id": { + "name": "card_id", + "columns": [ + "id" + ] + } + }, + "uniqueConstraints": { + "card_publicId_unique": { + "name": "card_publicId_unique", + "columns": [ + "publicId" + ] + } + } + }, + "card_label": { + "name": "card_label", + "columns": { + "cardId": { + "name": "cardId", + "type": "bigint", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "labelId": { + "name": "labelId", + "type": "bigint", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": { + "card_label_cardId_card_id_fk": { + "name": "card_label_cardId_card_id_fk", + "tableFrom": "card_label", + "tableTo": "card", + "columnsFrom": [ + "cardId" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + }, + "card_label_labelId_label_id_fk": { + "name": "card_label_labelId_label_id_fk", + "tableFrom": "card_label", + "tableTo": "label", + "columnsFrom": [ + "labelId" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": { + "card_label_cardId_labelId": { + "name": "card_label_cardId_labelId", + "columns": [ + "cardId", + "labelId" + ] + } + }, + "uniqueConstraints": {} + }, + "label": { + "name": "label", + "columns": { + "id": { + "name": "id", + "type": "bigint", + "primaryKey": false, + "notNull": true, + "autoincrement": true + }, + "publicId": { + "name": "publicId", + "type": "varchar(12)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "name": { + "name": "name", + "type": "varchar(256)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "colourCode": { + "name": "colourCode", + "type": "varchar(12)", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "createdBy": { + "name": "createdBy", + "type": "varchar(256)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "createdAt": { + "name": "createdAt", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "CURRENT_TIMESTAMP" + }, + "updatedAt": { + "name": "updatedAt", + "type": "timestamp", + "primaryKey": false, + "notNull": false, + "autoincrement": false, + "onUpdate": true + }, + "boardId": { + "name": "boardId", + "type": "bigint", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": { + "label_id": { + "name": "label_id", + "columns": [ + "id" + ] + } + }, + "uniqueConstraints": { + "label_publicId_unique": { + "name": "label_publicId_unique", + "columns": [ + "publicId" + ] + } + } + }, + "list": { + "name": "list", + "columns": { + "id": { + "name": "id", + "type": "bigint", + "primaryKey": false, + "notNull": true, + "autoincrement": true + }, + "publicId": { + "name": "publicId", + "type": "varchar(12)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "name": { + "name": "name", + "type": "varchar(256)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "createdBy": { + "name": "createdBy", + "type": "varchar(256)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "createdAt": { + "name": "createdAt", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "CURRENT_TIMESTAMP" + }, + "updatedAt": { + "name": "updatedAt", + "type": "timestamp", + "primaryKey": false, + "notNull": false, + "autoincrement": false, + "onUpdate": true + }, + "boardId": { + "name": "boardId", + "type": "bigint", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "index": { + "name": "index", + "type": "int", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": { + "list_id": { + "name": "list_id", + "columns": [ + "id" + ] + } + }, + "uniqueConstraints": { + "list_publicId_unique": { + "name": "list_publicId_unique", + "columns": [ + "publicId" + ] + } + } + }, + "session": { + "name": "session", + "columns": { + "sessionToken": { + "name": "sessionToken", + "type": "varchar(255)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "userId": { + "name": "userId", + "type": "varchar(255)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "expires": { + "name": "expires", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": { + "userId_idx": { + "name": "userId_idx", + "columns": [ + "userId" + ], + "isUnique": false + } + }, + "foreignKeys": {}, + "compositePrimaryKeys": { + "session_sessionToken": { + "name": "session_sessionToken", + "columns": [ + "sessionToken" + ] + } + }, + "uniqueConstraints": {} + }, + "user": { + "name": "user", + "columns": { + "id": { + "name": "id", + "type": "varchar(255)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "name": { + "name": "name", + "type": "varchar(255)", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "email": { + "name": "email", + "type": "varchar(255)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "emailVerified": { + "name": "emailVerified", + "type": "timestamp(3)", + "primaryKey": false, + "notNull": false, + "autoincrement": false, + "default": "CURRENT_TIMESTAMP(3)" + }, + "image": { + "name": "image", + "type": "varchar(255)", + "primaryKey": false, + "notNull": false, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": { + "user_id": { + "name": "user_id", + "columns": [ + "id" + ] + } + }, + "uniqueConstraints": { + "user_email_unique": { + "name": "user_email_unique", + "columns": [ + "email" + ] + } + } + }, + "verificationToken": { + "name": "verificationToken", + "columns": { + "identifier": { + "name": "identifier", + "type": "varchar(255)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "token": { + "name": "token", + "type": "varchar(255)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "expires": { + "name": "expires", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": { + "verificationToken_identifier_token": { + "name": "verificationToken_identifier_token", + "columns": [ + "identifier", + "token" + ] + } + }, + "uniqueConstraints": {} + } + }, + "schemas": {}, + "_meta": { + "schemas": {}, + "tables": {}, + "columns": {} + } +} \ No newline at end of file diff --git a/src/server/db/migrations/meta/_journal.json b/src/server/db/migrations/meta/_journal.json index a2c48fe3..82124e39 100644 --- a/src/server/db/migrations/meta/_journal.json +++ b/src/server/db/migrations/meta/_journal.json @@ -22,6 +22,20 @@ "when": 1702630369122, "tag": "0002_colossal_randall", "breakpoints": true + }, + { + "idx": 3, + "version": "5", + "when": 1702750430064, + "tag": "0003_heavy_thanos", + "breakpoints": true + }, + { + "idx": 4, + "version": "5", + "when": 1702924641678, + "tag": "0004_tidy_lord_hawal", + "breakpoints": true } ] } \ No newline at end of file diff --git a/src/server/db/schema.ts b/src/server/db/schema.ts index 2708c52c..72e43d06 100644 --- a/src/server/db/schema.ts +++ b/src/server/db/schema.ts @@ -39,6 +39,56 @@ export const boardsRelations = relations(boards, ({ one, many }) => ({ references: [users.id], }), lists: many(lists), + labels: many(labels) +})); + +export const labels = mySqlTable( + "label", + { + id: bigint("id", { mode: "number" }).primaryKey().autoincrement(), + publicId: varchar("publicId", { length: 12 }).notNull().unique(), + name: varchar("name", { length: 256 }).notNull(), + colourCode: varchar("colourCode", { length: 12 }), + createdBy: varchar("createdBy", { length: 256 }).notNull(), + createdAt: timestamp("createdAt") + .default(sql`CURRENT_TIMESTAMP`) + .notNull(), + updatedAt: timestamp("updatedAt").onUpdateNow(), + boardId: bigint("boardId", { mode: "number" }).notNull(), + } +); + +export const labelsRelations = relations(labels, ({ one, many }) => ({ + createdBy: one(users, { + fields: [labels.createdBy], + references: [users.id], + }), + board: one(boards, { + fields: [labels.boardId], + references: [boards.id], + }), + cards: many(cardsToLabels) +})); + +export const cardsToLabels = mySqlTable( + "card_label", + { + cardId: bigint("cardId", { mode: "number" }).notNull().references(() => cards.id), + labelId: bigint("labelId", { mode: "number" }).notNull().references(() => labels.id), + }, (t) => ({ + pk: primaryKey(t.cardId, t.labelId), + }), +); + +export const cardOnLabelsRelations = relations(cardsToLabels, ({ one }) => ({ + card: one(cards, { + fields: [cardsToLabels.cardId], + references: [cards.id], + }), + label: one(labels, { + fields: [cardsToLabels.labelId], + references: [labels.id], + }), })); export const lists = mySqlTable( @@ -88,7 +138,7 @@ export const cards = mySqlTable( } ); -export const cardsRelations = relations(cards, ({ one }) => ({ +export const cardsRelations = relations(cards, ({ one, many }) => ({ createdBy: one(users, { fields: [cards.createdBy], references: [users.id], @@ -101,6 +151,8 @@ export const cardsRelations = relations(cards, ({ one }) => ({ fields: [cards.deletedBy], references: [users.id], }), + + labels: many(cardsToLabels) })); export const users = mySqlTable("user", {