* feat: workspace start of week column * feat(l10n): add workspace setting for the first day of the week Fixes #361 * feat: add Saturday as option * chore: fix migration order * chore: fix merge --------- Co-authored-by: Henry <henry_ball@hotmail.co.uk>
This commit is contained in:
@@ -17,9 +17,14 @@ import { twMerge } from "tailwind-merge";
|
|||||||
interface DateSelectorProps {
|
interface DateSelectorProps {
|
||||||
selectedDate?: Date | null;
|
selectedDate?: Date | null;
|
||||||
onDateSelect?: (date: Date | undefined) => void;
|
onDateSelect?: (date: Date | undefined) => void;
|
||||||
|
weekStartsOn?: 0 | 1 | 6;
|
||||||
}
|
}
|
||||||
|
|
||||||
const DateSelector = ({ selectedDate, onDateSelect }: DateSelectorProps) => {
|
const DateSelector = ({
|
||||||
|
selectedDate,
|
||||||
|
onDateSelect,
|
||||||
|
weekStartsOn = 1,
|
||||||
|
}: DateSelectorProps) => {
|
||||||
const [currentMonth, setCurrentMonth] = useState(() => {
|
const [currentMonth, setCurrentMonth] = useState(() => {
|
||||||
return selectedDate ? startOfMonth(selectedDate) : startOfMonth(new Date());
|
return selectedDate ? startOfMonth(selectedDate) : startOfMonth(new Date());
|
||||||
});
|
});
|
||||||
@@ -28,18 +33,18 @@ const DateSelector = ({ selectedDate, onDateSelect }: DateSelectorProps) => {
|
|||||||
const year = format(currentMonth, "yyyy");
|
const year = format(currentMonth, "yyyy");
|
||||||
|
|
||||||
const dayHeaders = useMemo(() => {
|
const dayHeaders = useMemo(() => {
|
||||||
const weekStart = startOfWeek(new Date(), { weekStartsOn: 1 }); // Monday
|
const weekStart = startOfWeek(new Date(), { weekStartsOn });
|
||||||
return eachDayOfInterval({
|
return eachDayOfInterval({
|
||||||
start: weekStart,
|
start: weekStart,
|
||||||
end: new Date(weekStart.getTime() + 6 * 24 * 60 * 60 * 1000),
|
end: new Date(weekStart.getTime() + 6 * 24 * 60 * 60 * 1000),
|
||||||
}).map((date) => format(date, "EEEEEE")); // Shortest localized day name
|
}).map((date) => format(date, "EEEEEE")); // Shortest localized day name
|
||||||
}, []);
|
}, [weekStartsOn]);
|
||||||
|
|
||||||
const days = useMemo(() => {
|
const days = useMemo(() => {
|
||||||
const monthStart = startOfMonth(currentMonth);
|
const monthStart = startOfMonth(currentMonth);
|
||||||
const monthEnd = endOfMonth(currentMonth);
|
const monthEnd = endOfMonth(currentMonth);
|
||||||
const calendarStart = startOfWeek(monthStart, { weekStartsOn: 1 }); // Monday
|
const calendarStart = startOfWeek(monthStart, { weekStartsOn });
|
||||||
const calendarEnd = endOfWeek(monthEnd, { weekStartsOn: 1 }); // Monday
|
const calendarEnd = endOfWeek(monthEnd, { weekStartsOn });
|
||||||
|
|
||||||
return eachDayOfInterval({ start: calendarStart, end: calendarEnd }).map(
|
return eachDayOfInterval({ start: calendarStart, end: calendarEnd }).map(
|
||||||
(date) => {
|
(date) => {
|
||||||
@@ -53,7 +58,7 @@ const DateSelector = ({ selectedDate, onDateSelect }: DateSelectorProps) => {
|
|||||||
};
|
};
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
}, [currentMonth, selectedDate]);
|
}, [currentMonth, selectedDate, weekStartsOn]);
|
||||||
|
|
||||||
const handlePreviousMonth = () => {
|
const handlePreviousMonth = () => {
|
||||||
setCurrentMonth(subMonths(currentMonth, 1));
|
setCurrentMonth(subMonths(currentMonth, 1));
|
||||||
|
|||||||
@@ -111,6 +111,7 @@ export function NewWorkspaceForm() {
|
|||||||
slug: values.slug,
|
slug: values.slug,
|
||||||
plan: values.plan,
|
plan: values.plan,
|
||||||
role: "admin",
|
role: "admin",
|
||||||
|
weekStartDay: 1,
|
||||||
});
|
});
|
||||||
|
|
||||||
// If in cloud and Pro toggle is enabled, create checkout session for pro
|
// If in cloud and Pro toggle is enabled, create checkout session for pro
|
||||||
|
|||||||
@@ -19,6 +19,7 @@ interface Workspace {
|
|||||||
slug: string | undefined;
|
slug: string | undefined;
|
||||||
plan: "free" | "pro" | "enterprise" | undefined;
|
plan: "free" | "pro" | "enterprise" | undefined;
|
||||||
role: "admin" | "member" | "guest";
|
role: "admin" | "member" | "guest";
|
||||||
|
weekStartDay: 0 | 1 | 6;
|
||||||
}
|
}
|
||||||
|
|
||||||
const initialWorkspace: Workspace = {
|
const initialWorkspace: Workspace = {
|
||||||
@@ -28,13 +29,14 @@ const initialWorkspace: Workspace = {
|
|||||||
slug: "",
|
slug: "",
|
||||||
plan: "free",
|
plan: "free",
|
||||||
role: "member",
|
role: "member",
|
||||||
|
weekStartDay: 1,
|
||||||
};
|
};
|
||||||
|
|
||||||
const initialAvailableWorkspaces: Workspace[] = [];
|
const initialAvailableWorkspaces: Workspace[] = [];
|
||||||
|
|
||||||
export const WorkspaceContext = createContext<WorkspaceContextProps | undefined>(
|
export const WorkspaceContext = createContext<
|
||||||
undefined,
|
WorkspaceContextProps | undefined
|
||||||
);
|
>(undefined);
|
||||||
|
|
||||||
export const WorkspaceProvider: React.FC<{ children: ReactNode }> = ({
|
export const WorkspaceProvider: React.FC<{ children: ReactNode }> = ({
|
||||||
children,
|
children,
|
||||||
@@ -79,6 +81,7 @@ export const WorkspaceProvider: React.FC<{ children: ReactNode }> = ({
|
|||||||
slug: workspace.slug,
|
slug: workspace.slug,
|
||||||
description: workspace.description,
|
description: workspace.description,
|
||||||
plan: workspace.plan,
|
plan: workspace.plan,
|
||||||
|
weekStartDay: workspace.weekStartDay,
|
||||||
hasLoaded: true,
|
hasLoaded: true,
|
||||||
})) as Workspace[];
|
})) as Workspace[];
|
||||||
|
|
||||||
@@ -100,6 +103,7 @@ export const WorkspaceProvider: React.FC<{ children: ReactNode }> = ({
|
|||||||
plan: selectedWorkspace.workspace.plan,
|
plan: selectedWorkspace.workspace.plan,
|
||||||
description: selectedWorkspace.workspace.description,
|
description: selectedWorkspace.workspace.description,
|
||||||
role: selectedWorkspace.role,
|
role: selectedWorkspace.role,
|
||||||
|
weekStartDay: selectedWorkspace.workspace.weekStartDay as 0 | 1 | 6,
|
||||||
});
|
});
|
||||||
|
|
||||||
if (workspacePublicId) {
|
if (workspacePublicId) {
|
||||||
@@ -119,6 +123,7 @@ export const WorkspaceProvider: React.FC<{ children: ReactNode }> = ({
|
|||||||
plan: primaryWorkspace.plan,
|
plan: primaryWorkspace.plan,
|
||||||
description: primaryWorkspace.description,
|
description: primaryWorkspace.description,
|
||||||
role: primaryWorkspaceRole,
|
role: primaryWorkspaceRole,
|
||||||
|
weekStartDay: primaryWorkspace.weekStartDay as 0 | 1 | 6,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}, [data, isLoading, workspacePublicId, router]);
|
}, [data, isLoading, workspacePublicId, router]);
|
||||||
|
|||||||
@@ -24,6 +24,7 @@ import Toggle from "~/components/Toggle";
|
|||||||
import { useModalFormState } from "~/hooks/useModalFormState";
|
import { useModalFormState } from "~/hooks/useModalFormState";
|
||||||
import { useModal } from "~/providers/modal";
|
import { useModal } from "~/providers/modal";
|
||||||
import { usePopup } from "~/providers/popup";
|
import { usePopup } from "~/providers/popup";
|
||||||
|
import { useWorkspace } from "~/providers/workspace";
|
||||||
import { api } from "~/utils/api";
|
import { api } from "~/utils/api";
|
||||||
import { formatMemberDisplayName, getAvatarUrl } from "~/utils/helpers";
|
import { formatMemberDisplayName, getAvatarUrl } from "~/utils/helpers";
|
||||||
|
|
||||||
@@ -53,6 +54,7 @@ export function NewCardForm({
|
|||||||
queryParams,
|
queryParams,
|
||||||
}: NewCardFormProps) {
|
}: NewCardFormProps) {
|
||||||
const { showPopup } = usePopup();
|
const { showPopup } = usePopup();
|
||||||
|
const { workspace } = useWorkspace();
|
||||||
const { closeModal, openModal, modalStates, clearModalState } = useModal();
|
const { closeModal, openModal, modalStates, clearModalState } = useModal();
|
||||||
|
|
||||||
const utils = api.useUtils();
|
const utils = api.useUtils();
|
||||||
@@ -491,6 +493,7 @@ export function NewCardForm({
|
|||||||
setValue("dueDate", date ?? null);
|
setValue("dueDate", date ?? null);
|
||||||
setIsDateSelectorOpen(false);
|
setIsDateSelectorOpen(false);
|
||||||
}}
|
}}
|
||||||
|
weekStartsOn={workspace.weekStartDay}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</>
|
</>
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ import { HiMiniPlus } from "react-icons/hi2";
|
|||||||
|
|
||||||
import DateSelector from "~/components/DateSelector";
|
import DateSelector from "~/components/DateSelector";
|
||||||
import { usePopup } from "~/providers/popup";
|
import { usePopup } from "~/providers/popup";
|
||||||
|
import { useWorkspace } from "~/providers/workspace";
|
||||||
import { api } from "~/utils/api";
|
import { api } from "~/utils/api";
|
||||||
import { invalidateCard } from "~/utils/cardInvalidation";
|
import { invalidateCard } from "~/utils/cardInvalidation";
|
||||||
|
|
||||||
@@ -22,6 +23,7 @@ export function DueDateSelector({
|
|||||||
disabled = false,
|
disabled = false,
|
||||||
}: DueDateSelectorProps) {
|
}: DueDateSelectorProps) {
|
||||||
const { showPopup } = usePopup();
|
const { showPopup } = usePopup();
|
||||||
|
const { workspace } = useWorkspace();
|
||||||
const utils = api.useUtils();
|
const utils = api.useUtils();
|
||||||
const [isOpen, setIsOpen] = useState(false);
|
const [isOpen, setIsOpen] = useState(false);
|
||||||
const [pendingDate, setPendingDate] = useState<Date | null | undefined>(
|
const [pendingDate, setPendingDate] = useState<Date | null | undefined>(
|
||||||
@@ -135,6 +137,7 @@ export function DueDateSelector({
|
|||||||
<DateSelector
|
<DateSelector
|
||||||
selectedDate={pendingDate ?? undefined}
|
selectedDate={pendingDate ?? undefined}
|
||||||
onDateSelect={handleDateSelect}
|
onDateSelect={handleDateSelect}
|
||||||
|
weekStartsOn={workspace.weekStartDay}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</>
|
</>
|
||||||
|
|||||||
@@ -21,6 +21,7 @@ import UpdateWorkspaceDescriptionForm from "./components/UpdateWorkspaceDescript
|
|||||||
import UpdateWorkspaceEmailVisibilityForm from "./components/UpdateWorkspaceEmailVisibilityForm";
|
import UpdateWorkspaceEmailVisibilityForm from "./components/UpdateWorkspaceEmailVisibilityForm";
|
||||||
import UpdateWorkspaceNameForm from "./components/UpdateWorkspaceNameForm";
|
import UpdateWorkspaceNameForm from "./components/UpdateWorkspaceNameForm";
|
||||||
import UpdateWorkspaceUrlForm from "./components/UpdateWorkspaceUrlForm";
|
import UpdateWorkspaceUrlForm from "./components/UpdateWorkspaceUrlForm";
|
||||||
|
import UpdateWeekStartDayForm from "./components/UpdateWeekStartDayForm";
|
||||||
import { UpgradeToProConfirmation } from "./components/UpgradeToProConfirmation";
|
import { UpgradeToProConfirmation } from "./components/UpgradeToProConfirmation";
|
||||||
|
|
||||||
export default function WorkspaceSettings() {
|
export default function WorkspaceSettings() {
|
||||||
@@ -86,6 +87,15 @@ export default function WorkspaceSettings() {
|
|||||||
disabled={!canEditWorkspace}
|
disabled={!canEditWorkspace}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
|
<h2 className="mb-4 mt-8 text-[14px] font-bold text-neutral-900 dark:text-dark-1000">
|
||||||
|
{t`Week start day`}
|
||||||
|
</h2>
|
||||||
|
<UpdateWeekStartDayForm
|
||||||
|
workspacePublicId={workspace.publicId}
|
||||||
|
weekStartDay={workspaceData?.weekStartDay ?? 1}
|
||||||
|
disabled={!canEditWorkspace}
|
||||||
|
/>
|
||||||
|
|
||||||
<h2 className="mb-4 mt-8 text-[14px] font-bold text-neutral-900 dark:text-dark-1000">
|
<h2 className="mb-4 mt-8 text-[14px] font-bold text-neutral-900 dark:text-dark-1000">
|
||||||
{t`Email visibility`}
|
{t`Email visibility`}
|
||||||
</h2>
|
</h2>
|
||||||
|
|||||||
@@ -0,0 +1,59 @@
|
|||||||
|
import { t } from "@lingui/core/macro";
|
||||||
|
import { useEffect, useState } from "react";
|
||||||
|
|
||||||
|
import { api } from "~/utils/api";
|
||||||
|
|
||||||
|
export default function UpdateWeekStartDayForm({
|
||||||
|
workspacePublicId,
|
||||||
|
weekStartDay,
|
||||||
|
disabled = false,
|
||||||
|
}: {
|
||||||
|
workspacePublicId: string;
|
||||||
|
weekStartDay: number;
|
||||||
|
disabled?: boolean;
|
||||||
|
}) {
|
||||||
|
const utils = api.useUtils();
|
||||||
|
const [value, setValue] = useState(weekStartDay);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
setValue(weekStartDay);
|
||||||
|
}, [weekStartDay]);
|
||||||
|
|
||||||
|
const updateWorkspace = api.workspace.update.useMutation({
|
||||||
|
onSuccess: () => {
|
||||||
|
if (workspacePublicId && workspacePublicId.length >= 12) {
|
||||||
|
void utils.workspace.byId.invalidate({
|
||||||
|
workspacePublicId,
|
||||||
|
});
|
||||||
|
void utils.workspace.all.invalidate();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
const handleChange = (e: React.ChangeEvent<HTMLSelectElement>) => {
|
||||||
|
if (disabled) return;
|
||||||
|
const newValue = Number(e.target.value);
|
||||||
|
setValue(newValue);
|
||||||
|
updateWorkspace.mutate({
|
||||||
|
workspacePublicId,
|
||||||
|
weekStartDay: newValue,
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="flex gap-2">
|
||||||
|
<div className="mb-4 flex w-full max-w-[325px] items-center gap-2">
|
||||||
|
<select
|
||||||
|
value={value}
|
||||||
|
onChange={handleChange}
|
||||||
|
disabled={disabled || updateWorkspace.isPending}
|
||||||
|
className="block w-full rounded-md border-0 bg-dark-300 bg-white/5 py-1.5 text-sm shadow-sm ring-1 ring-inset ring-light-600 placeholder:text-dark-800 focus:ring-2 focus:ring-inset focus:ring-light-700 dark:text-dark-1000 dark:ring-dark-700 dark:focus:ring-dark-700 sm:leading-6"
|
||||||
|
>
|
||||||
|
<option value={0}>{t`Sunday`}</option>
|
||||||
|
<option value={1}>{t`Monday`}</option>
|
||||||
|
<option value={6}>{t`Saturday`}</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -4,11 +4,10 @@ import { z } from "zod";
|
|||||||
|
|
||||||
import * as workspaceRepo from "@kan/db/repository/workspace.repo";
|
import * as workspaceRepo from "@kan/db/repository/workspace.repo";
|
||||||
import * as workspaceSlugRepo from "@kan/db/repository/workspaceSlug.repo";
|
import * as workspaceSlugRepo from "@kan/db/repository/workspaceSlug.repo";
|
||||||
import { generateUID } from "@kan/shared/utils";
|
import { generateAvatarUrl, generateUID } from "@kan/shared/utils";
|
||||||
|
|
||||||
import { createTRPCRouter, protectedProcedure, publicProcedure } from "../trpc";
|
import { createTRPCRouter, protectedProcedure, publicProcedure } from "../trpc";
|
||||||
import { assertPermission } from "../utils/permissions";
|
import { assertPermission } from "../utils/permissions";
|
||||||
import { generateAvatarUrl } from "@kan/shared/utils";
|
|
||||||
|
|
||||||
export const workspaceRouter = createTRPCRouter({
|
export const workspaceRouter = createTRPCRouter({
|
||||||
all: protectedProcedure
|
all: protectedProcedure
|
||||||
@@ -84,8 +83,7 @@ export const workspaceRouter = createTRPCRouter({
|
|||||||
const isAdmin = userMember?.role === "admin";
|
const isAdmin = userMember?.role === "admin";
|
||||||
|
|
||||||
// Show emails if user is admin OR workspace setting allows it
|
// Show emails if user is admin OR workspace setting allows it
|
||||||
const shouldShowEmails =
|
const shouldShowEmails = isAdmin || result.showEmailsToMembers === true;
|
||||||
isAdmin || result.showEmailsToMembers === true;
|
|
||||||
|
|
||||||
// Generate presigned URLs for member avatars
|
// Generate presigned URLs for member avatars
|
||||||
const membersWithAvatarUrls = await Promise.all(
|
const membersWithAvatarUrls = await Promise.all(
|
||||||
@@ -295,6 +293,9 @@ export const workspaceRouter = createTRPCRouter({
|
|||||||
.optional(),
|
.optional(),
|
||||||
description: z.string().min(3).max(280).optional(),
|
description: z.string().min(3).max(280).optional(),
|
||||||
showEmailsToMembers: z.boolean().optional(),
|
showEmailsToMembers: z.boolean().optional(),
|
||||||
|
weekStartDay: z
|
||||||
|
.union([z.literal(0), z.literal(1), z.literal(6)])
|
||||||
|
.optional(),
|
||||||
}),
|
}),
|
||||||
)
|
)
|
||||||
.output(z.custom<Awaited<ReturnType<typeof workspaceRepo.update>>>())
|
.output(z.custom<Awaited<ReturnType<typeof workspaceRepo.update>>>())
|
||||||
@@ -356,6 +357,7 @@ export const workspaceRouter = createTRPCRouter({
|
|||||||
slug: input.slug,
|
slug: input.slug,
|
||||||
description: input.description,
|
description: input.description,
|
||||||
showEmailsToMembers: input.showEmailsToMembers,
|
showEmailsToMembers: input.showEmailsToMembers,
|
||||||
|
weekStartDay: input.weekStartDay,
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|||||||
@@ -190,7 +190,7 @@ export async function sendWebhooksForWorkspace(
|
|||||||
db,
|
db,
|
||||||
workspaceId,
|
workspaceId,
|
||||||
);
|
);
|
||||||
const webhooks = allWebhooks.filter((w) =>
|
const webhooksForEvent = allWebhooks.filter((w) =>
|
||||||
w.events.includes(payload.event),
|
w.events.includes(payload.event),
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|||||||
52
packages/db/migrations/20260311065722_AddWeekStartDay.sql
Normal file
52
packages/db/migrations/20260311065722_AddWeekStartDay.sql
Normal file
@@ -0,0 +1,52 @@
|
|||||||
|
-- Migrations and snapshots seem to have become out of sync (this should fix that)
|
||||||
|
DO $$
|
||||||
|
BEGIN
|
||||||
|
IF NOT EXISTS (
|
||||||
|
SELECT 1
|
||||||
|
FROM pg_enum e
|
||||||
|
JOIN pg_type t ON e.enumtypid = t.oid
|
||||||
|
WHERE t.typname = 'source'
|
||||||
|
AND e.enumlabel = 'github'
|
||||||
|
) THEN
|
||||||
|
ALTER TYPE "public"."source" ADD VALUE 'github';
|
||||||
|
END IF;
|
||||||
|
END $$;
|
||||||
|
--> statement-breakpoint
|
||||||
|
CREATE TABLE IF NOT EXISTS "workspace_webhooks" (
|
||||||
|
"id" bigserial PRIMARY KEY NOT NULL,
|
||||||
|
"publicId" varchar(12) NOT NULL,
|
||||||
|
"workspaceId" bigint NOT NULL,
|
||||||
|
"name" varchar(255) NOT NULL,
|
||||||
|
"url" varchar(2048) NOT NULL,
|
||||||
|
"secret" text,
|
||||||
|
"events" text NOT NULL,
|
||||||
|
"active" boolean DEFAULT true NOT NULL,
|
||||||
|
"createdBy" uuid NOT NULL,
|
||||||
|
"createdAt" timestamp DEFAULT now() NOT NULL,
|
||||||
|
"updatedAt" timestamp,
|
||||||
|
CONSTRAINT "workspace_webhooks_publicId_unique" UNIQUE("publicId")
|
||||||
|
);
|
||||||
|
--> statement-breakpoint
|
||||||
|
ALTER TABLE "workspace_webhooks" ENABLE ROW LEVEL SECURITY;--> statement-breakpoint
|
||||||
|
ALTER TABLE "integration" ALTER COLUMN "accessToken" SET DATA TYPE text;--> statement-breakpoint
|
||||||
|
ALTER TABLE "card_activity" ADD COLUMN IF NOT EXISTS "attachmentId" bigint;--> statement-breakpoint
|
||||||
|
--> statement-breakpoint
|
||||||
|
ALTER TABLE "workspace" ADD COLUMN IF NOT EXISTS "weekStartDay" integer DEFAULT 1 NOT NULL;--> statement-breakpoint
|
||||||
|
DO $$ BEGIN
|
||||||
|
ALTER TABLE "workspace_webhooks" ADD CONSTRAINT "workspace_webhooks_workspaceId_workspace_id_fk" FOREIGN KEY ("workspaceId") REFERENCES "public"."workspace"("id") ON DELETE cascade ON UPDATE no action;
|
||||||
|
EXCEPTION
|
||||||
|
WHEN duplicate_object THEN null;
|
||||||
|
END $$;
|
||||||
|
--> statement-breakpoint
|
||||||
|
DO $$ BEGIN
|
||||||
|
ALTER TABLE "workspace_webhooks" ADD CONSTRAINT "workspace_webhooks_createdBy_user_id_fk" FOREIGN KEY ("createdBy") REFERENCES "public"."user"("id") ON DELETE cascade ON UPDATE no action;
|
||||||
|
EXCEPTION
|
||||||
|
WHEN duplicate_object THEN null;
|
||||||
|
END $$;
|
||||||
|
--> statement-breakpoint
|
||||||
|
CREATE INDEX IF NOT EXISTS "workspace_webhooks_workspace_idx" ON "workspace_webhooks" USING btree ("workspaceId");--> statement-breakpoint
|
||||||
|
DO $$ BEGIN
|
||||||
|
ALTER TABLE "card_activity" ADD CONSTRAINT "card_activity_attachmentId_card_attachment_id_fk" FOREIGN KEY ("attachmentId") REFERENCES "public"."card_attachment"("id") ON DELETE cascade ON UPDATE no action;
|
||||||
|
EXCEPTION
|
||||||
|
WHEN duplicate_object THEN null;
|
||||||
|
END $$;
|
||||||
File diff suppressed because it is too large
Load Diff
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"id": "dc863226-583e-4985-8b6a-4c360a3b9fa1",
|
"id": "dc863226-583e-4985-8b6a-4c360a3b9fa1",
|
||||||
"prevId": "4e1ebb8b-bd52-48c5-87d6-8e6e5eb8bbde",
|
"prevId": "d0ce9209-d34a-4ae8-b93e-d73391bfec64",
|
||||||
"version": "7",
|
"version": "7",
|
||||||
"dialect": "postgresql",
|
"dialect": "postgresql",
|
||||||
"tables": {
|
"tables": {
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
3868
packages/db/migrations/meta/20260311065722_snapshot.json
Normal file
3868
packages/db/migrations/meta/20260311065722_snapshot.json
Normal file
File diff suppressed because it is too large
Load Diff
@@ -206,11 +206,18 @@
|
|||||||
"breakpoints": true
|
"breakpoints": true
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"idx": 28,
|
"idx": 29,
|
||||||
"version": "7",
|
"version": "7",
|
||||||
"when": 1771930355536,
|
"when": 1771930355536,
|
||||||
"tag": "20260224105235_AddGitHubIntegrationSupport",
|
"tag": "20260224105235_AddGitHubIntegrationSupport",
|
||||||
"breakpoints": true
|
"breakpoints": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"idx": 30,
|
||||||
|
"version": "7",
|
||||||
|
"when": 1773212242728,
|
||||||
|
"tag": "20260311065722_AddWeekStartDay",
|
||||||
|
"breakpoints": true
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
@@ -127,6 +127,7 @@ export const update = async (
|
|||||||
plan?: "free" | "pro" | "enterprise";
|
plan?: "free" | "pro" | "enterprise";
|
||||||
description?: string;
|
description?: string;
|
||||||
showEmailsToMembers?: boolean;
|
showEmailsToMembers?: boolean;
|
||||||
|
weekStartDay?: number;
|
||||||
},
|
},
|
||||||
) => {
|
) => {
|
||||||
const [result] = await db
|
const [result] = await db
|
||||||
@@ -137,6 +138,7 @@ export const update = async (
|
|||||||
plan: workspaceInput.plan,
|
plan: workspaceInput.plan,
|
||||||
description: workspaceInput.description,
|
description: workspaceInput.description,
|
||||||
showEmailsToMembers: workspaceInput.showEmailsToMembers,
|
showEmailsToMembers: workspaceInput.showEmailsToMembers,
|
||||||
|
weekStartDay: workspaceInput.weekStartDay,
|
||||||
})
|
})
|
||||||
.where(eq(workspaces.publicId, workspacePublicId))
|
.where(eq(workspaces.publicId, workspacePublicId))
|
||||||
.returning({
|
.returning({
|
||||||
@@ -147,6 +149,7 @@ export const update = async (
|
|||||||
description: workspaces.description,
|
description: workspaces.description,
|
||||||
plan: workspaces.plan,
|
plan: workspaces.plan,
|
||||||
showEmailsToMembers: workspaces.showEmailsToMembers,
|
showEmailsToMembers: workspaces.showEmailsToMembers,
|
||||||
|
weekStartDay: workspaces.weekStartDay,
|
||||||
});
|
});
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
@@ -189,6 +192,7 @@ export const getByPublicIdWithMembers = (
|
|||||||
name: true,
|
name: true,
|
||||||
slug: true,
|
slug: true,
|
||||||
showEmailsToMembers: true,
|
showEmailsToMembers: true,
|
||||||
|
weekStartDay: true,
|
||||||
},
|
},
|
||||||
with: {
|
with: {
|
||||||
members: {
|
members: {
|
||||||
@@ -274,6 +278,7 @@ export const getAllByUserId = async (db: dbClient, userId: string) => {
|
|||||||
description: true,
|
description: true,
|
||||||
slug: true,
|
slug: true,
|
||||||
plan: true,
|
plan: true,
|
||||||
|
weekStartDay: true,
|
||||||
deletedAt: true,
|
deletedAt: true,
|
||||||
},
|
},
|
||||||
// https://github.com/drizzle-team/drizzle-orm/issues/2903
|
// https://github.com/drizzle-team/drizzle-orm/issues/2903
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ import {
|
|||||||
bigint,
|
bigint,
|
||||||
bigserial,
|
bigserial,
|
||||||
boolean,
|
boolean,
|
||||||
|
integer,
|
||||||
pgEnum,
|
pgEnum,
|
||||||
pgTable,
|
pgTable,
|
||||||
text,
|
text,
|
||||||
@@ -45,6 +46,7 @@ export const workspaces = pgTable("workspace", {
|
|||||||
slug: varchar("slug", { length: 255 }).notNull().unique(),
|
slug: varchar("slug", { length: 255 }).notNull().unique(),
|
||||||
plan: workspacePlanEnum("plan").notNull().default("free"),
|
plan: workspacePlanEnum("plan").notNull().default("free"),
|
||||||
showEmailsToMembers: boolean("showEmailsToMembers").notNull().default(true),
|
showEmailsToMembers: boolean("showEmailsToMembers").notNull().default(true),
|
||||||
|
weekStartDay: integer("weekStartDay").notNull().default(1),
|
||||||
createdBy: uuid("createdBy").references(() => users.id, {
|
createdBy: uuid("createdBy").references(() => users.id, {
|
||||||
onDelete: "set null",
|
onDelete: "set null",
|
||||||
}),
|
}),
|
||||||
|
|||||||
Reference in New Issue
Block a user