diff --git a/.env.example b/.env.example index dc82ea23a..b05d685b1 100644 --- a/.env.example +++ b/.env.example @@ -20,8 +20,6 @@ DB_URL='FULL_PATH_TO_YOUR_SQLITE_DB_FILE' # DB_PASSWORD='password' # DB_NAME='name-of-database' -# @see https://next-auth.js.org/configuration/options#nextauth_url -AUTH_URL='http://localhost:3000' # You can generate the secret via 'openssl rand -base64 32' on Unix # @see https://next-auth.js.org/configuration/options#secret diff --git a/.github/renovate.json5 b/.github/renovate.json5 index 8978459cf..377002605 100644 --- a/.github/renovate.json5 +++ b/.github/renovate.json5 @@ -1,31 +1,19 @@ { - "$schema": "https://docs.renovatebot.com/renovate-schema.json", - "extends": [ - "config:recommended" - ], - "packageRules": [ + $schema: "https://docs.renovatebot.com/renovate-schema.json", + extends: ["config:recommended"], + packageRules: [ { - "matchPackagePatterns": [ - "^@homarr/", - "tsx" // Disabled for now as version 0.14.4 did not work with the current version of homarr. It resulted in a ERR_MODULE_NOT_FOUND error - ], - "enabled": false + matchPackagePatterns: ["^@homarr/"], + enabled: false, }, { - "matchUpdateTypes": [ - "minor", - "patch", - "pin", - "digest" - ], - "automerge": true - } + matchUpdateTypes: ["minor", "patch", "pin", "digest"], + automerge: true, + }, ], - "updateInternalDeps": true, - "rangeStrategy": "bump", - "automerge": false, - "baseBranches": [ - "dev" - ], - "dependencyDashboard": false -} \ No newline at end of file + updateInternalDeps: true, + rangeStrategy: "bump", + automerge: false, + baseBranches: ["dev"], + dependencyDashboard: false, +} diff --git a/Dockerfile b/Dockerfile index 7ae43e72f..7a2eca66e 100644 --- a/Dockerfile +++ b/Dockerfile @@ -30,6 +30,9 @@ COPY --from=builder /app/cli-out/json/ . COPY --from=builder /app/next-out/json/ . COPY --from=builder /app/pnpm-lock.yaml ./pnpm-lock.yaml +# Is used for postinstall of docs definitions +COPY --from=builder /app/packages/definitions/src/docs ./packages/definitions/src/docs + # Uses the lockfile to install the dependencies RUN corepack enable pnpm && pnpm install --recursive --frozen-lockfile diff --git a/apps/nextjs/package.json b/apps/nextjs/package.json index 5f410d270..22ae92ba7 100644 --- a/apps/nextjs/package.json +++ b/apps/nextjs/package.json @@ -37,17 +37,17 @@ "@homarr/ui": "workspace:^0.1.0", "@homarr/validation": "workspace:^0.1.0", "@homarr/widgets": "workspace:^0.1.0", - "@mantine/colors-generator": "^7.13.2", - "@mantine/core": "^7.13.2", - "@mantine/hooks": "^7.13.2", - "@mantine/modals": "^7.13.2", - "@mantine/tiptap": "^7.13.2", - "@million/lint": "1.0.9", + "@mantine/colors-generator": "^7.13.4", + "@mantine/core": "^7.13.4", + "@mantine/hooks": "^7.13.4", + "@mantine/modals": "^7.13.4", + "@mantine/tiptap": "^7.13.4", + "@million/lint": "1.0.11", "@t3-oss/env-nextjs": "^0.11.1", - "@tabler/icons-react": "^3.19.0", - "@tanstack/react-query": "^5.59.9", - "@tanstack/react-query-devtools": "^5.59.9", - "@tanstack/react-query-next-experimental": "5.59.9", + "@tabler/icons-react": "^3.20.0", + "@tanstack/react-query": "^5.59.16", + "@tanstack/react-query-devtools": "^5.59.16", + "@tanstack/react-query-next-experimental": "5.59.16", "@trpc/client": "next", "@trpc/next": "next", "@trpc/react-query": "next", @@ -55,22 +55,22 @@ "@xterm/addon-canvas": "^0.7.0", "@xterm/addon-fit": "0.10.0", "@xterm/xterm": "^5.5.0", - "chroma-js": "^3.1.1", + "chroma-js": "^3.1.2", "clsx": "^2.1.1", "dayjs": "^1.11.13", "dotenv": "^16.4.5", "flag-icons": "^7.2.3", "glob": "^11.0.0", - "jotai": "^2.10.0", - "mantine-react-table": "2.0.0-beta.6", - "next": "^14.2.15", + "jotai": "^2.10.1", + "mantine-react-table": "2.0.0-beta.7", + "next": "^14.2.16", "postcss-preset-mantine": "^1.17.0", "prismjs": "^1.29.0", "react": "^18.3.1", "react-dom": "^18.3.1", - "react-error-boundary": "^4.0.13", + "react-error-boundary": "^4.1.2", "react-simple-code-editor": "^0.14.1", - "sass": "^1.79.5", + "sass": "^1.80.4", "superjson": "2.2.1", "swagger-ui-react": "^5.17.14", "use-deep-compare-effect": "^1.8.1" @@ -80,13 +80,13 @@ "@homarr/prettier-config": "workspace:^0.1.0", "@homarr/tsconfig": "workspace:^0.1.0", "@types/chroma-js": "2.4.4", - "@types/node": "^20.16.11", - "@types/prismjs": "^1.26.4", - "@types/react": "^18.3.11", + "@types/node": "^20.17.1", + "@types/prismjs": "^1.26.5", + "@types/react": "^18.3.12", "@types/react-dom": "^18.3.1", "@types/swagger-ui-react": "^4.18.3", "concurrently": "^9.0.1", - "eslint": "^9.12.0", + "eslint": "^9.13.0", "node-loader": "^2.0.0", "prettier": "^3.3.3", "typescript": "^5.6.3" diff --git a/apps/nextjs/public/images/pwa/192.maskable.png b/apps/nextjs/public/images/pwa/192.maskable.png new file mode 100644 index 000000000..0783e1c6e Binary files /dev/null and b/apps/nextjs/public/images/pwa/192.maskable.png differ diff --git a/apps/nextjs/public/images/pwa/512.maskable.png b/apps/nextjs/public/images/pwa/512.maskable.png new file mode 100644 index 000000000..d6366700a Binary files /dev/null and b/apps/nextjs/public/images/pwa/512.maskable.png differ diff --git a/apps/nextjs/src/app/[locale]/_client-providers/mantine.tsx b/apps/nextjs/src/app/[locale]/_client-providers/mantine.tsx index e5e867815..867ecfd94 100644 --- a/apps/nextjs/src/app/[locale]/_client-providers/mantine.tsx +++ b/apps/nextjs/src/app/[locale]/_client-providers/mantine.tsx @@ -1,9 +1,8 @@ "use client"; import type { PropsWithChildren } from "react"; -import { useState } from "react"; import type { MantineColorScheme, MantineColorSchemeManager } from "@mantine/core"; -import { createTheme, DirectionProvider, isMantineColorScheme, MantineProvider } from "@mantine/core"; +import { createTheme, DirectionProvider, MantineProvider } from "@mantine/core"; import dayjs from "dayjs"; import { clientApi } from "@homarr/api/client"; @@ -16,7 +15,7 @@ export const CustomMantineProvider = ({ children }: PropsWithChildren) => { return ( { function useColorSchemeManager(): MantineColorSchemeManager { const key = "homarr-color-scheme"; const { data: session } = useSession(); - const [sessionColorScheme, setSessionColorScheme] = useState( - session?.user.colorScheme, - ); + + const updateCookieValue = (value: Exclude) => { + setClientCookie(key, value, { expires: dayjs().add(1, "year").toDate(), path: "/" }); + }; + const { mutate: mutateColorScheme } = clientApi.user.changeColorScheme.useMutation({ onSuccess: (_, variables) => { - setSessionColorScheme(variables.colorScheme); + updateCookieValue(variables.colorScheme); }, }); - let handleStorageEvent: (event: StorageEvent) => void; - return { get: (defaultValue) => { if (typeof window === "undefined") { return defaultValue; } - if (sessionColorScheme) { - return sessionColorScheme; - } - try { const cookies = parseCookies(document.cookie); return (cookies[key] as MantineColorScheme | undefined) ?? defaultValue; @@ -62,34 +57,18 @@ function useColorSchemeManager(): MantineColorSchemeManager { }, set: (value) => { + if (value === "auto") return; try { if (session) { mutateColorScheme({ colorScheme: value }); } - setClientCookie(key, value, { expires: dayjs().add(1, "year").toDate() }); - window.localStorage.setItem(key, value); + updateCookieValue(value); } catch (error) { - console.warn("[@mantine/core] Local storage color scheme manager was unable to save color scheme.", error); + console.warn("[@mantine/core] Color scheme manager was unable to save color scheme.", error); } }, - - subscribe: (onUpdate) => { - handleStorageEvent = (event) => { - if (session) return; // Ignore updates when session is available as we are using session color scheme - if (event.storageArea === window.localStorage && event.key === key && isMantineColorScheme(event.newValue)) { - onUpdate(event.newValue); - } - }; - - window.addEventListener("storage", handleStorageEvent); - }, - - unsubscribe: () => { - window.removeEventListener("storage", handleStorageEvent); - }, - - clear: () => { - window.localStorage.removeItem(key); - }, + subscribe: () => undefined, + unsubscribe: () => undefined, + clear: () => undefined, }; } diff --git a/apps/nextjs/src/app/[locale]/_client-providers/trpc.tsx b/apps/nextjs/src/app/[locale]/_client-providers/trpc.tsx index c08542590..90df364f2 100644 --- a/apps/nextjs/src/app/[locale]/_client-providers/trpc.tsx +++ b/apps/nextjs/src/app/[locale]/_client-providers/trpc.tsx @@ -19,11 +19,23 @@ import superjson from "superjson"; import type { AppRouter } from "@homarr/api"; import { clientApi } from "@homarr/api/client"; +import { env } from "~/env.mjs"; + +const constructWebsocketUrl = () => { + const fallback = "ws://localhost:3001/websockets"; + if (typeof window === "undefined") { + return fallback; + } + + if (env.NODE_ENV === "development") { + return fallback; + } + + return `ws://${window.location.hostname}:${window.location.port}/websockets`; +}; + const wsClient = createWSClient({ - url: - typeof window === "undefined" - ? "ws://localhost:3001/websockets" - : `ws://${window.location.hostname}:${window.location.port}/websockets`, + url: constructWebsocketUrl(), }); export function TRPCReactProvider(props: PropsWithChildren) { diff --git a/apps/nextjs/src/app/[locale]/boards/(content)/_context.tsx b/apps/nextjs/src/app/[locale]/boards/(content)/_context.tsx index 346baff75..808759af1 100644 --- a/apps/nextjs/src/app/[locale]/boards/(content)/_context.tsx +++ b/apps/nextjs/src/app/[locale]/boards/(content)/_context.tsx @@ -49,6 +49,7 @@ export const BoardProvider = ({ useEffect(() => { setReadySections((previous) => previous.filter((id) => data.sections.some((section) => section.id === id))); + // eslint-disable-next-line react-hooks/exhaustive-deps }, [data.sections.length, setReadySections]); const markAsReady = useCallback((id: string) => { diff --git a/apps/nextjs/src/app/[locale]/boards/(content)/_creator.tsx b/apps/nextjs/src/app/[locale]/boards/(content)/_creator.tsx index 6a6be9b42..4827a3b1d 100644 --- a/apps/nextjs/src/app/[locale]/boards/(content)/_creator.tsx +++ b/apps/nextjs/src/app/[locale]/boards/(content)/_creator.tsx @@ -28,7 +28,6 @@ export const createBoardContentPage = >( layout: createBoardLayout({ headerActions: , getInitialBoardAsync: getInitialBoard, - isBoardContentPage: true, }), // eslint-disable-next-line no-restricted-syntax page: async () => { @@ -50,6 +49,10 @@ export const createBoardContentPage = >( title: board.metaTitle ?? createMetaTitle(t("board.content.metaTitle", { boardName: board.name })), icons: { icon: board.faviconImageUrl ? board.faviconImageUrl : undefined, + apple: board.faviconImageUrl ? board.faviconImageUrl : undefined, + }, + appleWebApp: { + startupImage: { url: board.faviconImageUrl ? board.faviconImageUrl : "/logo/logo.png" }, }, }; } catch (error) { diff --git a/apps/nextjs/src/app/[locale]/boards/[name]/layout.tsx b/apps/nextjs/src/app/[locale]/boards/[name]/layout.tsx index 42107bf2d..1f129e4c1 100644 --- a/apps/nextjs/src/app/[locale]/boards/[name]/layout.tsx +++ b/apps/nextjs/src/app/[locale]/boards/[name]/layout.tsx @@ -8,5 +8,4 @@ export default createBoardLayout<{ locale: string; name: string }>({ async getInitialBoardAsync({ name }) { return await api.board.getBoardByName({ name }); }, - isBoardContentPage: false, }); diff --git a/apps/nextjs/src/app/[locale]/boards/_layout-creator.tsx b/apps/nextjs/src/app/[locale]/boards/_layout-creator.tsx index 56dabdd88..4e8edd149 100644 --- a/apps/nextjs/src/app/[locale]/boards/_layout-creator.tsx +++ b/apps/nextjs/src/app/[locale]/boards/_layout-creator.tsx @@ -4,7 +4,6 @@ import { AppShellMain } from "@mantine/core"; import { TRPCError } from "@trpc/server"; import { logger } from "@homarr/log"; -import { GlobalItemServerDataRunner } from "@homarr/widgets"; import { MainHeader } from "~/components/layout/header"; import { BoardLogoWithTitle } from "~/components/layout/logo/board-logo"; @@ -18,13 +17,11 @@ import { BoardMantineProvider } from "./(content)/_theme"; interface CreateBoardLayoutProps { headerActions: JSX.Element; getInitialBoardAsync: (params: TParams) => Promise; - isBoardContentPage: boolean; } export const createBoardLayout = ({ headerActions, getInitialBoardAsync: getInitialBoard, - isBoardContentPage, }: CreateBoardLayoutProps) => { const Layout = async ({ params, @@ -42,21 +39,19 @@ export const createBoardLayout = ({ }); return ( - - - - - - } - actions={headerActions} - hasNavigation={false} - /> - {children} - - - - + + + + + } + actions={headerActions} + hasNavigation={false} + /> + {children} + + + ); }; diff --git a/apps/nextjs/src/app/[locale]/layout.tsx b/apps/nextjs/src/app/[locale]/layout.tsx index 6adc5aaef..22888ea0b 100644 --- a/apps/nextjs/src/app/[locale]/layout.tsx +++ b/apps/nextjs/src/app/[locale]/layout.tsx @@ -28,8 +28,7 @@ const fontSans = Inter({ variable: "--font-sans", }); -export const metadata: Metadata = { - metadataBase: new URL("http://localhost:3000"), +export const generateMetadata = (): Metadata => ({ title: "Homarr", description: "Simplify the management of your server with Homarr - a sleek, modern dashboard that puts all of your apps and services at your fingertips.", @@ -40,12 +39,17 @@ export const metadata: Metadata = { url: "https://homarr.dev", siteName: "Homarr Documentation", }, - twitter: { - card: "summary_large_image", - site: "@jullerino", - creator: "@jullerino", + icons: { + icon: "/logo/logo.png", + apple: "/logo/logo.png", }, -}; + appleWebApp: { + title: "Homarr", + capable: true, + startupImage: { url: "/logo/logo.png" }, + statusBarStyle: getColorScheme() === "dark" ? "black-translucent" : "default", + }, +}); export const viewport: Viewport = { themeColor: [ @@ -56,7 +60,7 @@ export const viewport: Viewport = { export default async function Layout(props: { children: React.ReactNode; params: { locale: string } }) { const session = await auth(); - const colorScheme = cookies().get("homarr-color-scheme")?.value ?? "light"; + const colorScheme = getColorScheme(); const tCommon = await getScopedI18n("common"); const direction = tCommon("direction"); @@ -73,7 +77,15 @@ export default async function Layout(props: { children: React.ReactNode; params: return ( // Instead of ColorSchemScript we use data-mantine-color-scheme to prevent flickering - + @@ -87,3 +99,7 @@ export default async function Layout(props: { children: React.ReactNode; params: ); } + +const getColorScheme = () => { + return cookies().get("homarr-color-scheme")?.value ?? "dark"; +}; diff --git a/apps/nextjs/src/app/[locale]/manage/integrations/new/_integration-new-form.tsx b/apps/nextjs/src/app/[locale]/manage/integrations/new/_integration-new-form.tsx index 25eacf9b9..791be2938 100644 --- a/apps/nextjs/src/app/[locale]/manage/integrations/new/_integration-new-form.tsx +++ b/apps/nextjs/src/app/[locale]/manage/integrations/new/_integration-new-form.tsx @@ -9,7 +9,7 @@ import { IconInfoCircle } from "@tabler/icons-react"; import { clientApi } from "@homarr/api/client"; import { revalidatePathActionAsync } from "@homarr/common/client"; import type { IntegrationKind, IntegrationSecretKind } from "@homarr/definitions"; -import { getAllSecretKindOptions } from "@homarr/definitions"; +import { getAllSecretKindOptions, getIntegrationName } from "@homarr/definitions"; import type { UseFormReturnType } from "@homarr/form"; import { useZodForm } from "@homarr/form"; import { convertIntegrationTestConnectionError } from "@homarr/integrations/client"; @@ -32,7 +32,7 @@ export const NewIntegrationForm = ({ searchParams }: NewIntegrationFormProps) => const router = useRouter(); const form = useZodForm(validation.integration.create.omit({ kind: true }), { initialValues: { - name: searchParams.name ?? "", + name: searchParams.name ?? getIntegrationName(searchParams.kind), url: searchParams.url ?? "", secrets: secretKinds[0].map((kind) => ({ kind, @@ -81,7 +81,7 @@ export const NewIntegrationForm = ({ searchParams }: NewIntegrationFormProps) => return (
void handleSubmitAsync(value))}> - + diff --git a/apps/nextjs/src/app/[locale]/manage/integrations/page.tsx b/apps/nextjs/src/app/[locale]/manage/integrations/page.tsx index ad03dc244..fafc49fc8 100644 --- a/apps/nextjs/src/app/[locale]/manage/integrations/page.tsx +++ b/apps/nextjs/src/app/[locale]/manage/integrations/page.tsx @@ -161,21 +161,20 @@ const IntegrationList = async ({ integrations, activeTab }: IntegrationListProps - {hasFullAccess || - (integration.permissions.hasFullAccess && ( - - - - - - - ))} + {(hasFullAccess || integration.permissions.hasFullAccess) && ( + + + + + + + )} diff --git a/apps/nextjs/src/app/[locale]/manage/layout.tsx b/apps/nextjs/src/app/[locale]/manage/layout.tsx index e0bd9fcb5..43e11f3a3 100644 --- a/apps/nextjs/src/app/[locale]/manage/layout.tsx +++ b/apps/nextjs/src/app/[locale]/manage/layout.tsx @@ -25,6 +25,7 @@ import { import { auth } from "@homarr/auth/next"; import { isProviderEnabled } from "@homarr/auth/server"; +import { createDocumentationLink } from "@homarr/definitions"; import { getScopedI18n } from "@homarr/translation/server"; import { MainHeader } from "~/components/layout/header"; @@ -124,7 +125,7 @@ export default async function ManageLayout({ children }: PropsWithChildren) { { label: t("items.help.items.documentation"), icon: IconBook2, - href: "https://homarr.dev/docs/getting-started/", + href: createDocumentationLink("/docs/getting-started"), external: true, }, { diff --git a/apps/nextjs/src/app/[locale]/manage/tools/api/components/api-keys.tsx b/apps/nextjs/src/app/[locale]/manage/tools/api/components/api-keys.tsx index 86503427c..71a0efb1b 100644 --- a/apps/nextjs/src/app/[locale]/manage/tools/api/components/api-keys.tsx +++ b/apps/nextjs/src/app/[locale]/manage/tools/api/components/api-keys.tsx @@ -47,7 +47,7 @@ export const ApiKeysManagement = ({ apiKeys }: ApiKeysManagementProps) => { ), }, ], - [], + [t], ); const table = useMantineReactTable({ diff --git a/apps/nextjs/src/app/[locale]/manage/users/[userId]/general/_components/_ping-icons-enabled.tsx b/apps/nextjs/src/app/[locale]/manage/users/[userId]/general/_components/_ping-icons-enabled.tsx new file mode 100644 index 000000000..1631189dc --- /dev/null +++ b/apps/nextjs/src/app/[locale]/manage/users/[userId]/general/_components/_ping-icons-enabled.tsx @@ -0,0 +1,66 @@ +"use client"; + +import { Button, Group, Stack, Switch } from "@mantine/core"; + +import type { RouterOutputs } from "@homarr/api"; +import { clientApi } from "@homarr/api/client"; +import { revalidatePathActionAsync } from "@homarr/common/client"; +import { useZodForm } from "@homarr/form"; +import { showErrorNotification, showSuccessNotification } from "@homarr/notifications"; +import { useI18n } from "@homarr/translation/client"; +import type { z } from "@homarr/validation"; +import { validation } from "@homarr/validation"; + +interface PingIconsEnabledProps { + user: RouterOutputs["user"]["getById"]; +} + +export const PingIconsEnabled = ({ user }: PingIconsEnabledProps) => { + const t = useI18n(); + const { mutate, isPending } = clientApi.user.changePingIconsEnabled.useMutation({ + async onSettled() { + await revalidatePathActionAsync(`/manage/users/${user.id}`); + }, + onSuccess(_, variables) { + form.setInitialValues({ + pingIconsEnabled: variables.pingIconsEnabled, + }); + showSuccessNotification({ + message: t("user.action.changePingIconsEnabled.notification.success.message"), + }); + }, + onError() { + showErrorNotification({ + message: t("user.action.changePingIconsEnabled.notification.error.message"), + }); + }, + }); + const form = useZodForm(validation.user.pingIconsEnabled, { + initialValues: { + pingIconsEnabled: user.pingIconsEnabled, + }, + }); + + const handleSubmit = (values: FormType) => { + mutate({ + id: user.id, + ...values, + }); + }; + + return ( + + + + + + + + + + ); +}; + +type FormType = z.infer; diff --git a/apps/nextjs/src/app/[locale]/manage/users/[userId]/general/_components/_profile-form.tsx b/apps/nextjs/src/app/[locale]/manage/users/[userId]/general/_components/_profile-form.tsx index 0099dcbd8..b2d5ab87e 100644 --- a/apps/nextjs/src/app/[locale]/manage/users/[userId]/general/_components/_profile-form.tsx +++ b/apps/nextjs/src/app/[locale]/manage/users/[userId]/general/_components/_profile-form.tsx @@ -61,7 +61,7 @@ export const UserProfileForm = ({ user }: UserProfileFormProps) => { id: user.id, }); }, - [user.id, mutate], + [isProviderCredentials, mutate, user.id], ); return ( diff --git a/apps/nextjs/src/app/[locale]/manage/users/[userId]/general/page.tsx b/apps/nextjs/src/app/[locale]/manage/users/[userId]/general/page.tsx index e29a140f3..fa26d7bd1 100644 --- a/apps/nextjs/src/app/[locale]/manage/users/[userId]/general/page.tsx +++ b/apps/nextjs/src/app/[locale]/manage/users/[userId]/general/page.tsx @@ -14,6 +14,7 @@ import { canAccessUserEditPage } from "../access"; import { ChangeHomeBoardForm } from "./_components/_change-home-board"; import { DeleteUserButton } from "./_components/_delete-user-button"; import { FirstDayOfWeek } from "./_components/_first-day-of-week"; +import { PingIconsEnabled } from "./_components/_ping-icons-enabled"; import { UserProfileAvatarForm } from "./_components/_profile-avatar-form"; import { UserProfileForm } from "./_components/_profile-form"; @@ -99,6 +100,11 @@ export default async function EditUserPage({ params }: Props) {
+ + {tGeneral("item.accessibility")} + + + {isCredentialsUser && ( { +export const RenameGroupForm = ({ group, disabled }: RenameGroupFormProps) => { const t = useI18n(); const { mutate, isPending } = clientApi.group.updateGroup.useMutation(); const form = useZodForm(validation.group.update.pick({ name: true }), { @@ -28,6 +29,9 @@ export const RenameGroupForm = ({ group }: RenameGroupFormProps) => { const handleSubmit = useCallback( (values: FormType) => { + if (disabled) { + return; + } mutate( { ...values, @@ -60,13 +64,15 @@ export const RenameGroupForm = ({ group }: RenameGroupFormProps) => { return (
- + - - - + {!disabled && ( + + + + )}
); diff --git a/apps/nextjs/src/app/[locale]/manage/users/groups/[id]/_reserved-group-alert.tsx b/apps/nextjs/src/app/[locale]/manage/users/groups/[id]/_reserved-group-alert.tsx new file mode 100644 index 000000000..bd6920792 --- /dev/null +++ b/apps/nextjs/src/app/[locale]/manage/users/groups/[id]/_reserved-group-alert.tsx @@ -0,0 +1,27 @@ +import Link from "next/link"; +import { Alert, Anchor } from "@mantine/core"; +import { IconExclamationCircle } from "@tabler/icons-react"; + +import { createDocumentationLink } from "@homarr/definitions"; +import { getI18n } from "@homarr/translation/server"; + +export const ReservedGroupAlert = async () => { + const t = await getI18n(); + + return ( + }> + {t("group.reservedNotice.message", { + checkoutDocs: ( + + {t("common.action.checkoutDocs")} + + ), + })} + + ); +}; diff --git a/apps/nextjs/src/app/[locale]/manage/users/groups/[id]/members/page.tsx b/apps/nextjs/src/app/[locale]/manage/users/groups/[id]/members/page.tsx index 972b62d99..d20f285a8 100644 --- a/apps/nextjs/src/app/[locale]/manage/users/groups/[id]/members/page.tsx +++ b/apps/nextjs/src/app/[locale]/manage/users/groups/[id]/members/page.tsx @@ -6,9 +6,11 @@ import type { RouterOutputs } from "@homarr/api"; import { api } from "@homarr/api/server"; import { env } from "@homarr/auth/env.mjs"; import { isProviderEnabled } from "@homarr/auth/server"; +import { everyoneGroup } from "@homarr/definitions"; import { getI18n, getScopedI18n } from "@homarr/translation/server"; import { SearchInput, UserAvatar } from "@homarr/ui"; +import { ReservedGroupAlert } from "../_reserved-group-alert"; import { AddGroupMember } from "./_add-group-member"; import { RemoveGroupMember } from "./_remove-group-member"; @@ -25,6 +27,7 @@ export default async function GroupsDetailPage({ params, searchParams }: GroupsD const t = await getI18n(); const tMembers = await getScopedI18n("management.page.group.setting.members"); const group = await api.group.getById({ id: params.id }); + const isReserved = group.name === everyoneGroup; const filteredMembers = searchParams.search ? // eslint-disable-next-line @typescript-eslint/no-non-null-assertion @@ -41,15 +44,19 @@ export default async function GroupsDetailPage({ params, searchParams }: GroupsD {tMembers("title")} - {providerTypes !== "credentials" && ( - }> - {t(`group.memberNotice.${providerTypes}`)} - + {isReserved ? ( + + ) : ( + providerTypes !== "credentials" && ( + }> + {t(`group.memberNotice.${providerTypes}`)} + + ) )} - {isProviderEnabled("credentials") && ( + {isProviderEnabled("credentials") && !isReserved && ( member.id)} /> )} @@ -63,7 +70,7 @@ export default async function GroupsDetailPage({ params, searchParams }: GroupsD {filteredMembers.map((member) => ( - + ))}
@@ -74,9 +81,10 @@ export default async function GroupsDetailPage({ params, searchParams }: GroupsD interface RowProps { member: RouterOutputs["group"]["getById"]["members"][number]; groupId: string; + disabled?: boolean; } -const Row = ({ member, groupId }: RowProps) => { +const Row = ({ member, groupId, disabled }: RowProps) => { return ( @@ -88,7 +96,7 @@ const Row = ({ member, groupId }: RowProps) => { - {member.provider === "credentials" && } + {member.provider === "credentials" && !disabled && } ); diff --git a/apps/nextjs/src/app/[locale]/manage/users/groups/[id]/page.tsx b/apps/nextjs/src/app/[locale]/manage/users/groups/[id]/page.tsx index cc3496520..455a835e0 100644 --- a/apps/nextjs/src/app/[locale]/manage/users/groups/[id]/page.tsx +++ b/apps/nextjs/src/app/[locale]/manage/users/groups/[id]/page.tsx @@ -1,11 +1,13 @@ import { Stack, Title } from "@mantine/core"; import { api } from "@homarr/api/server"; +import { everyoneGroup } from "@homarr/definitions"; import { getScopedI18n } from "@homarr/translation/server"; import { DangerZoneItem, DangerZoneRoot } from "~/components/manage/danger-zone"; import { DeleteGroup } from "./_delete-group"; import { RenameGroupForm } from "./_rename-group-form"; +import { ReservedGroupAlert } from "./_reserved-group-alert"; import { TransferGroupOwnership } from "./_transfer-group-ownership"; interface GroupsDetailPageProps { @@ -18,26 +20,31 @@ export default async function GroupsDetailPage({ params }: GroupsDetailPageProps const group = await api.group.getById({ id: params.id }); const tGeneral = await getScopedI18n("management.page.group.setting.general"); const tGroupAction = await getScopedI18n("group.action"); + const isReserved = group.name === everyoneGroup; return ( {tGeneral("title")} - + {isReserved && } - - } - /> + - } - /> - + {!isReserved && ( + + } + /> + + } + /> + + )} ); } diff --git a/apps/nextjs/src/app/manifest.ts b/apps/nextjs/src/app/manifest.ts new file mode 100644 index 000000000..21c17f3df --- /dev/null +++ b/apps/nextjs/src/app/manifest.ts @@ -0,0 +1,39 @@ +import type { MetadataRoute } from "next"; + +export default function manifest(): MetadataRoute.Manifest { + return { + name: "Homarr", + short_name: "Homarr", + description: "Your dashboard for managing your server.", + start_url: "/", + display: "standalone", + background_color: "#fff", + theme_color: "#fff", + icons: [ + { + src: "/images/pwa/192.maskable.png", + sizes: "192x192", + type: "image/png", + purpose: "any", + }, + { + src: "/images/pwa/192.maskable.png", + sizes: "192x192", + type: "image/png", + purpose: "maskable", + }, + { + src: "/images/pwa/512.maskable.png", + sizes: "512x512", + type: "image/png", + purpose: "any", + }, + { + src: "/images/pwa/512.maskable.png", + sizes: "512x512", + type: "image/png", + purpose: "maskable", + }, + ], + }; +} diff --git a/apps/nextjs/src/components/board/items/item-content.tsx b/apps/nextjs/src/components/board/items/item-content.tsx index 2af6b3154..930cde473 100644 --- a/apps/nextjs/src/components/board/items/item-content.tsx +++ b/apps/nextjs/src/components/board/items/item-content.tsx @@ -4,7 +4,7 @@ import { QueryErrorResetBoundary } from "@tanstack/react-query"; import combineClasses from "clsx"; import { ErrorBoundary } from "react-error-boundary"; -import { loadWidgetDynamic, reduceWidgetOptionsWithDefaultValues, useServerDataFor } from "@homarr/widgets"; +import { loadWidgetDynamic, reduceWidgetOptionsWithDefaultValues } from "@homarr/widgets"; import { WidgetError } from "@homarr/widgets/errors"; import type { Item } from "~/app/[locale]/boards/_types"; @@ -53,7 +53,6 @@ interface InnerContentProps { const InnerContent = ({ item, ...dimensions }: InnerContentProps) => { const board = useRequiredBoard(); const [isEditMode] = useEditMode(); - const serverData = useServerDataFor(item.id); const Comp = loadWidgetDynamic(item.kind); const options = reduceWidgetOptionsWithDefaultValues(item.kind, item.options); const newItem = { ...item, options }; @@ -61,8 +60,6 @@ const InnerContent = ({ item, ...dimensions }: InnerContentProps) => { const updateOptions = ({ newOptions }: { newOptions: Record }) => updateItemOptions({ itemId: item.id, newOptions }); - if (!serverData?.isReady) return null; - return ( {({ reset }) => ( @@ -79,8 +76,6 @@ const InnerContent = ({ item, ...dimensions }: InnerContentProps) => { (({ actions, innerProps }) = const t = useI18n(); // Keep track of the maximum width based on the x offset const maxWidthRef = useRef(innerProps.columnCount - innerProps.item.xOffset); - const { moveAndResizeItem } = useItemActions(); const form = useZodForm( z.object({ xOffset: z @@ -62,7 +60,7 @@ export const ItemMoveModal = createModal(({ actions, innerProps }) = }); actions.closeModal(); }, - [moveAndResizeItem], + [actions, innerProps.gridStack, innerProps.item.id], ); return ( diff --git a/apps/nextjs/src/components/board/sections/gridstack/gridstack-item.tsx b/apps/nextjs/src/components/board/sections/gridstack/gridstack-item.tsx index 554a376fa..beff12f66 100644 --- a/apps/nextjs/src/components/board/sections/gridstack/gridstack-item.tsx +++ b/apps/nextjs/src/components/board/sections/gridstack/gridstack-item.tsx @@ -39,7 +39,7 @@ export const GridStackItem = ({ if (type !== "section") return; innerRef.current.gridstackNode.minW = minWidth; innerRef.current.gridstackNode.minH = minHeight; - }, [minWidth, minHeight, innerRef]); + }, [minWidth, minHeight, innerRef, type]); return ( , itemIds: string[]) } // Only run this effect when the section items change + // eslint-disable-next-line react-hooks/exhaustive-deps }, [itemIds.length, columnCount]); /** diff --git a/apps/nextjs/src/components/user-avatar-menu.tsx b/apps/nextjs/src/components/user-avatar-menu.tsx index 9a03b4200..1dafdce25 100644 --- a/apps/nextjs/src/components/user-avatar-menu.tsx +++ b/apps/nextjs/src/components/user-avatar-menu.tsx @@ -58,7 +58,7 @@ export const UserAvatarMenu = ({ children }: UserAvatarMenuProps) => { router.refresh(); }, }); - }, [openModal, router]); + }, [logoutUrl, openModal, router]); return ( diff --git a/apps/tasks/package.json b/apps/tasks/package.json index ac21b2feb..669d2c988 100644 --- a/apps/tasks/package.json +++ b/apps/tasks/package.json @@ -38,17 +38,17 @@ "dayjs": "^1.11.13", "dotenv": "^16.4.5", "superjson": "2.2.1", - "undici": "6.20.0" + "undici": "6.20.1" }, "devDependencies": { "@homarr/eslint-config": "workspace:^0.2.0", "@homarr/prettier-config": "workspace:^0.1.0", "@homarr/tsconfig": "workspace:^0.1.0", - "@types/node": "^20.16.11", + "@types/node": "^20.17.1", "dotenv-cli": "^7.4.2", - "eslint": "^9.12.0", + "eslint": "^9.13.0", "prettier": "^3.3.3", - "tsx": "4.13.3", + "tsx": "4.19.1", "typescript": "^5.6.3" } } diff --git a/apps/tasks/src/main.ts b/apps/tasks/src/main.ts index 4ae066828..2cb395ad2 100644 --- a/apps/tasks/src/main.ts +++ b/apps/tasks/src/main.ts @@ -4,10 +4,7 @@ import "./undici-log-agent-override"; import { registerCronJobRunner } from "@homarr/cron-job-runner"; import { jobGroup } from "@homarr/cron-jobs"; -import { seedServerSettingsAsync } from "./seed-server-settings"; - void (async () => { registerCronJobRunner(); await jobGroup.startAllAsync(); - await seedServerSettingsAsync(); })(); diff --git a/apps/tasks/src/seed-server-settings.ts b/apps/tasks/src/seed-server-settings.ts deleted file mode 100644 index 885d4e64c..000000000 --- a/apps/tasks/src/seed-server-settings.ts +++ /dev/null @@ -1,28 +0,0 @@ -import SuperJSON from "superjson"; - -import { db } from "@homarr/db"; -import { serverSettings } from "@homarr/db/schema/sqlite"; -import { logger } from "@homarr/log"; - -import { defaultServerSettings, defaultServerSettingsKeys } from "../../../packages/server-settings"; - -export const seedServerSettingsAsync = async () => { - const serverSettingsData = await db.query.serverSettings.findMany(); - let insertedSettingsCount = 0; - - for (const settingsKey of defaultServerSettingsKeys) { - if (serverSettingsData.some((setting) => setting.settingKey === settingsKey)) { - return; - } - - await db.insert(serverSettings).values({ - settingKey: settingsKey, - value: SuperJSON.stringify(defaultServerSettings[settingsKey]), - }); - insertedSettingsCount++; - } - - if (insertedSettingsCount > 0) { - logger.info(`Inserted ${insertedSettingsCount} missing settings`); - } -}; diff --git a/apps/websocket/package.json b/apps/websocket/package.json index 10f974e45..bf522cfdf 100644 --- a/apps/websocket/package.json +++ b/apps/websocket/package.json @@ -26,7 +26,7 @@ "@homarr/redis": "workspace:^0.1.0", "@homarr/validation": "workspace:^0.1.0", "dotenv": "^16.4.5", - "tsx": "4.13.3", + "tsx": "4.19.1", "ws": "^8.18.0" }, "devDependencies": { @@ -34,7 +34,7 @@ "@homarr/prettier-config": "workspace:^0.1.0", "@homarr/tsconfig": "workspace:^0.1.0", "@types/ws": "^8.5.12", - "eslint": "^9.12.0", + "eslint": "^9.13.0", "prettier": "^3.3.3", "typescript": "^5.6.3" } diff --git a/package.json b/package.json index 0827b1d81..9410bd747 100644 --- a/package.json +++ b/package.json @@ -2,7 +2,7 @@ "name": "homarr", "private": true, "scripts": { - "build": "turbo build", + "build": "cross-env CI=true turbo build", "clean": "git clean -xdf node_modules", "clean:workspaces": "turbo clean", "cli": "pnpm with-env tsx packages/cli/index.ts", @@ -27,20 +27,20 @@ "prettier": "@homarr/prettier-config", "devDependencies": { "@homarr/prettier-config": "workspace:^0.1.0", - "@turbo/gen": "^2.1.3", - "@vitejs/plugin-react": "^4.3.2", - "@vitest/coverage-v8": "^2.1.2", - "@vitest/ui": "^2.1.2", + "@turbo/gen": "^2.2.3", + "@vitejs/plugin-react": "^4.3.3", + "@vitest/coverage-v8": "^2.1.3", + "@vitest/ui": "^2.1.3", "cross-env": "^7.0.3", "jsdom": "^25.0.1", "prettier": "^3.3.3", "testcontainers": "^10.13.2", - "turbo": "^2.1.3", + "turbo": "^2.2.3", "typescript": "^5.6.3", "vite-tsconfig-paths": "^5.0.1", - "vitest": "^2.1.2" + "vitest": "^2.1.3" }, - "packageManager": "pnpm@9.12.1", + "packageManager": "pnpm@9.12.2", "engines": { "node": ">=20.18.0" }, diff --git a/packages/analytics/package.json b/packages/analytics/package.json index 64bb1adc9..0e8523d9b 100644 --- a/packages/analytics/package.json +++ b/packages/analytics/package.json @@ -32,7 +32,7 @@ "@homarr/eslint-config": "workspace:^0.2.0", "@homarr/prettier-config": "workspace:^0.1.0", "@homarr/tsconfig": "workspace:^0.1.0", - "eslint": "^9.12.0", + "eslint": "^9.13.0", "typescript": "^5.6.3" } } diff --git a/packages/api/package.json b/packages/api/package.json index be3235d98..578a1314d 100644 --- a/packages/api/package.json +++ b/packages/api/package.json @@ -39,7 +39,7 @@ "@trpc/react-query": "next", "@trpc/server": "next", "dockerode": "^4.0.2", - "next": "^14.2.15", + "next": "^14.2.16", "react": "^18.3.1", "superjson": "2.2.1", "trpc-swagger": "^1.2.6" @@ -49,7 +49,7 @@ "@homarr/prettier-config": "workspace:^0.1.0", "@homarr/tsconfig": "workspace:^0.1.0", "@types/dockerode": "^3.3.31", - "eslint": "^9.12.0", + "eslint": "^9.13.0", "prettier": "^3.3.3", "typescript": "^5.6.3" } diff --git a/packages/api/src/router/group.ts b/packages/api/src/router/group.ts index d14083995..8726d9fd7 100644 --- a/packages/api/src/router/group.ts +++ b/packages/api/src/router/group.ts @@ -3,6 +3,7 @@ import { TRPCError } from "@trpc/server"; import type { Database } from "@homarr/db"; import { and, createId, eq, like, not, sql } from "@homarr/db"; import { groupMembers, groupPermissions, groups } from "@homarr/db/schema/sqlite"; +import { everyoneGroup } from "@homarr/definitions"; import { validation, z } from "@homarr/validation"; import { createTRPCRouter, permissionRequiredProcedure, protectedProcedure } from "../trpc"; @@ -121,13 +122,12 @@ export const groupRouter = createTRPCRouter({ .requiresPermission("admin") .input(validation.group.create) .mutation(async ({ input, ctx }) => { - const normalizedName = normalizeName(input.name); - await checkSimilarNameAndThrowAsync(ctx.db, normalizedName); + await checkSimilarNameAndThrowAsync(ctx.db, input.name); const id = createId(); await ctx.db.insert(groups).values({ id, - name: normalizedName, + name: input.name, ownerId: ctx.session.user.id, }); @@ -138,14 +138,14 @@ export const groupRouter = createTRPCRouter({ .input(validation.group.update) .mutation(async ({ input, ctx }) => { await throwIfGroupNotFoundAsync(ctx.db, input.id); + await throwIfGroupNameIsReservedAsync(ctx.db, input.id); - const normalizedName = normalizeName(input.name); - await checkSimilarNameAndThrowAsync(ctx.db, normalizedName, input.id); + await checkSimilarNameAndThrowAsync(ctx.db, input.name, input.id); await ctx.db .update(groups) .set({ - name: normalizedName, + name: input.name, }) .where(eq(groups.id, input.id)); }), @@ -169,6 +169,7 @@ export const groupRouter = createTRPCRouter({ .input(validation.group.groupUser) .mutation(async ({ input, ctx }) => { await throwIfGroupNotFoundAsync(ctx.db, input.groupId); + await throwIfGroupNameIsReservedAsync(ctx.db, input.groupId); await ctx.db .update(groups) @@ -182,6 +183,7 @@ export const groupRouter = createTRPCRouter({ .input(validation.common.byId) .mutation(async ({ input, ctx }) => { await throwIfGroupNotFoundAsync(ctx.db, input.id); + await throwIfGroupNameIsReservedAsync(ctx.db, input.id); await ctx.db.delete(groups).where(eq(groups.id, input.id)); }), @@ -190,6 +192,7 @@ export const groupRouter = createTRPCRouter({ .input(validation.group.groupUser) .mutation(async ({ input, ctx }) => { await throwIfGroupNotFoundAsync(ctx.db, input.groupId); + await throwIfGroupNameIsReservedAsync(ctx.db, input.groupId); throwIfCredentialsDisabled(); const user = await ctx.db.query.users.findFirst({ @@ -213,6 +216,7 @@ export const groupRouter = createTRPCRouter({ .input(validation.group.groupUser) .mutation(async ({ input, ctx }) => { await throwIfGroupNotFoundAsync(ctx.db, input.groupId); + await throwIfGroupNameIsReservedAsync(ctx.db, input.groupId); throwIfCredentialsDisabled(); await ctx.db @@ -221,8 +225,6 @@ export const groupRouter = createTRPCRouter({ }), }); -const normalizeName = (name: string) => name.trim(); - const checkSimilarNameAndThrowAsync = async (db: Database, name: string, ignoreId?: string) => { const similar = await db.query.groups.findFirst({ where: and(like(groups.name, `${name}`), not(eq(groups.id, ignoreId ?? ""))), @@ -236,6 +238,17 @@ const checkSimilarNameAndThrowAsync = async (db: Database, name: string, ignoreI } }; +const throwIfGroupNameIsReservedAsync = async (db: Database, id: string) => { + const count = await db.$count(groups, and(eq(groups.id, id), eq(groups.name, everyoneGroup))); + + if (count > 0) { + throw new TRPCError({ + code: "FORBIDDEN", + message: "Action is forbidden for reserved group names", + }); + } +}; + const throwIfGroupNotFoundAsync = async (db: Database, id: string) => { const group = await db.query.groups.findFirst({ where: eq(groups.id, id), diff --git a/packages/api/src/router/test/user.spec.ts b/packages/api/src/router/test/user.spec.ts index f19502bd5..1d51afe9f 100644 --- a/packages/api/src/router/test/user.spec.ts +++ b/packages/api/src/router/test/user.spec.ts @@ -248,18 +248,11 @@ describe("editProfile shoud update user", () => { const user = await db.select().from(schema.users).where(eq(schema.users.id, defaultOwnerId)); expect(user).toHaveLength(1); - expect(user[0]).toStrictEqual({ + expect(user[0]).containSubset({ id: defaultOwnerId, name: "ABC", email: "abc@gmail.com", emailVerified, - salt: null, - password: null, - image: null, - homeBoardId: null, - provider: "credentials", - colorScheme: "auto", - firstDayOfWeek: 1, }); }); @@ -289,18 +282,11 @@ describe("editProfile shoud update user", () => { const user = await db.select().from(schema.users).where(eq(schema.users.id, defaultOwnerId)); expect(user).toHaveLength(1); - expect(user[0]).toStrictEqual({ + expect(user[0]).containSubset({ id: defaultOwnerId, name: "ABC", email: "myNewEmail@gmail.com", emailVerified: null, - salt: null, - password: null, - image: null, - homeBoardId: null, - provider: "credentials", - colorScheme: "auto", - firstDayOfWeek: 1, }); }); }); @@ -317,40 +303,14 @@ describe("delete should delete user", () => { { id: createId(), name: "User 1", - email: null, - emailVerified: null, - image: null, - password: null, - salt: null, - homeBoardId: null, - provider: "ldap" as const, - colorScheme: "auto" as const, - firstDayOfWeek: 1 as const, }, { id: defaultOwnerId, name: "User 2", - email: null, - emailVerified: null, - image: null, - password: null, - salt: null, - homeBoardId: null, - colorScheme: "auto" as const, - firstDayOfWeek: 1 as const, }, { id: createId(), name: "User 3", - email: null, - emailVerified: null, - image: null, - password: null, - salt: null, - homeBoardId: null, - provider: "oidc" as const, - colorScheme: "auto" as const, - firstDayOfWeek: 1 as const, }, ]; @@ -359,6 +319,8 @@ describe("delete should delete user", () => { await caller.delete(defaultOwnerId); const usersInDb = await db.select().from(schema.users); - expect(usersInDb).toStrictEqual([initialUsers[0], initialUsers[2]]); + expect(usersInDb).toHaveLength(2); + expect(usersInDb[0]).containSubset(initialUsers[0]); + expect(usersInDb[1]).containSubset(initialUsers[2]); }); }); diff --git a/packages/api/src/router/user.ts b/packages/api/src/router/user.ts index d1a9719f3..805140540 100644 --- a/packages/api/src/router/user.ts +++ b/packages/api/src/router/user.ts @@ -209,6 +209,7 @@ export const userRouter = createTRPCRouter({ provider: true, homeBoardId: true, firstDayOfWeek: true, + pingIconsEnabled: true, }, where: eq(users.id, input.userId), }); @@ -376,6 +377,39 @@ export const userRouter = createTRPCRouter({ }) .where(eq(users.id, ctx.session.user.id)); }), + getPingIconsEnabledOrDefault: publicProcedure.query(async ({ ctx }) => { + if (!ctx.session?.user) { + return false; + } + + const user = await ctx.db.query.users.findFirst({ + columns: { + id: true, + pingIconsEnabled: true, + }, + where: eq(users.id, ctx.session.user.id), + }); + + return user?.pingIconsEnabled ?? false; + }), + changePingIconsEnabled: protectedProcedure + .input(validation.user.pingIconsEnabled.and(validation.common.byId)) + .mutation(async ({ input, ctx }) => { + // Only admins can change other users ping icons enabled + if (!ctx.session.user.permissions.includes("admin") && ctx.session.user.id !== input.id) { + throw new TRPCError({ + code: "NOT_FOUND", + message: "User not found", + }); + } + + await ctx.db + .update(users) + .set({ + pingIconsEnabled: input.pingIconsEnabled, + }) + .where(eq(users.id, ctx.session.user.id)); + }), getFirstDayOfWeekForUserOrDefault: publicProcedure.query(async ({ ctx }) => { if (!ctx.session?.user) { return 1 as const; @@ -394,7 +428,7 @@ export const userRouter = createTRPCRouter({ changeFirstDayOfWeek: protectedProcedure .input(validation.user.firstDayOfWeek.and(validation.common.byId)) .mutation(async ({ input, ctx }) => { - // Only admins can change other users' passwords + // Only admins can change other users first day of week if (!ctx.session.user.permissions.includes("admin") && ctx.session.user.id !== input.id) { throw new TRPCError({ code: "NOT_FOUND", diff --git a/packages/api/src/router/widgets/calendar.ts b/packages/api/src/router/widgets/calendar.ts index 606ec04b7..7713db4f7 100644 --- a/packages/api/src/router/widgets/calendar.ts +++ b/packages/api/src/router/widgets/calendar.ts @@ -9,11 +9,12 @@ export const calendarRouter = createTRPCRouter({ findAllEvents: publicProcedure .unstable_concat(createManyIntegrationOfOneItemMiddleware("query", ...getIntegrationKindsByCategory("calendar"))) .query(async ({ ctx }) => { - return await Promise.all( + const result = await Promise.all( ctx.integrations.flatMap(async (integration) => { const cache = createItemAndIntegrationChannel("calendar", integration.id); return await cache.getAsync(); }), ); + return result.filter((item) => item !== null).flatMap((item) => item.data); }), }); diff --git a/packages/api/src/router/widgets/health-monitoring.ts b/packages/api/src/router/widgets/health-monitoring.ts index bd3d3bf27..28e0b9b6a 100644 --- a/packages/api/src/router/widgets/health-monitoring.ts +++ b/packages/api/src/router/widgets/health-monitoring.ts @@ -13,15 +13,13 @@ export const healthMonitoringRouter = createTRPCRouter({ return await Promise.all( ctx.integrations.map(async (integration) => { const channel = createItemAndIntegrationChannel("healthMonitoring", integration.id); - const data = await channel.getAsync(); - if (!data) { - return null; - } + const { data: healthInfo, timestamp } = (await channel.getAsync()) ?? { data: null, timestamp: new Date(0) }; return { integrationId: integration.id, integrationName: integration.name, - healthInfo: data.data, + healthInfo, + timestamp, }; }), ); @@ -30,7 +28,7 @@ export const healthMonitoringRouter = createTRPCRouter({ subscribeHealthStatus: publicProcedure .unstable_concat(createManyIntegrationMiddleware("query", "openmediavault")) .subscription(({ ctx }) => { - return observable<{ integrationId: string; healthInfo: HealthMonitoring }>((emit) => { + return observable<{ integrationId: string; healthInfo: HealthMonitoring; timestamp: Date }>((emit) => { const unsubscribes: (() => void)[] = []; for (const integration of ctx.integrations) { const channel = createItemAndIntegrationChannel("healthMonitoring", integration.id); @@ -38,6 +36,7 @@ export const healthMonitoringRouter = createTRPCRouter({ emit.next({ integrationId: integration.id, healthInfo, + timestamp: new Date(), }); }); unsubscribes.push(unsubscribe); diff --git a/packages/auth/callbacks.ts b/packages/auth/callbacks.ts index 6a381f57a..d5fac0b7a 100644 --- a/packages/auth/callbacks.ts +++ b/packages/auth/callbacks.ts @@ -36,7 +36,7 @@ export const createSessionAsync = async ( ...user, email: user.email ?? "", permissions: await getCurrentUserPermissionsAsync(db, user.id), - colorScheme: "auto", + colorScheme: "dark", }, } as Session; }; diff --git a/packages/auth/configuration.ts b/packages/auth/configuration.ts index 3a3fee360..65d67d4b4 100644 --- a/packages/auth/configuration.ts +++ b/packages/auth/configuration.ts @@ -15,11 +15,12 @@ import { EmptyNextAuthProvider } from "./providers/empty/empty-provider"; import { filterProviders } from "./providers/filter-providers"; import { OidcProvider } from "./providers/oidc/oidc-provider"; import { createRedirectUri } from "./redirect"; -import { generateSessionToken, sessionTokenCookieName } from "./session"; +import { expireDateAfter, generateSessionToken, sessionTokenCookieName } from "./session"; // See why it's unknown in the [...nextauth]/route.ts file -export const createConfiguration = (provider: SupportedAuthProvider | "unknown", headers: ReadonlyHeaders | null) => - NextAuth({ +export const createConfiguration = (provider: SupportedAuthProvider | "unknown", headers: ReadonlyHeaders | null) => { + const adapter = createAdapter(db, provider); + return NextAuth({ logger: { error: (code, ...message) => { // Remove the big error message for failed login attempts @@ -33,7 +34,18 @@ export const createConfiguration = (provider: SupportedAuthProvider | "unknown", }, }, trustHost: true, - adapter: createAdapter(db, provider), + cookies: { + sessionToken: { + name: sessionTokenCookieName, + options: { + httpOnly: true, + sameSite: "lax", + path: "/", + secure: true, + }, + }, + }, + adapter, providers: filterProviders([ Credentials(createCredentialsConfiguration(db)), Credentials(createLdapConfiguration(db)), @@ -42,6 +54,38 @@ export const createConfiguration = (provider: SupportedAuthProvider | "unknown", ]), callbacks: { session: createSessionCallback(db), + // eslint-disable-next-line no-restricted-syntax + signIn: async ({ user }) => { + /** + * For credentials provider only jwt is supported by default + * so we have to create the session and set the cookie manually. + */ + if (provider !== "credentials" && provider !== "ldap") { + return true; + } + + if (!adapter.createSession || !user.id) { + return false; + } + + const expires = expireDateAfter(env.AUTH_SESSION_EXPIRY_TIME); + const sessionToken = generateSessionToken(); + await adapter.createSession({ + sessionToken, + expires, + userId: user.id, + }); + + cookies().set(sessionTokenCookieName, sessionToken, { + path: "/", + expires: expires, + httpOnly: true, + sameSite: "lax", + secure: true, + }); + + return true; + }, }, events: { signIn: createSignInEventHandler(db), @@ -68,3 +112,4 @@ export const createConfiguration = (provider: SupportedAuthProvider | "unknown", }, }, }); +}; diff --git a/packages/auth/events.ts b/packages/auth/events.ts index f4cd1eeac..292204de0 100644 --- a/packages/auth/events.ts +++ b/packages/auth/events.ts @@ -5,6 +5,7 @@ import type { NextAuthConfig } from "next-auth"; import { and, eq, inArray } from "@homarr/db"; import type { Database } from "@homarr/db"; import { groupMembers, groups, users } from "@homarr/db/schema/sqlite"; +import { everyoneGroup } from "@homarr/definitions"; import { logger } from "@homarr/log"; import { env } from "./env.mjs"; @@ -33,6 +34,7 @@ export const createSignInEventHandler = (db: Database): Exclude { + const dbEveryoneGroup = await db.query.groups.findFirst({ + where: eq(groups.name, everyoneGroup), + with: { + members: { + where: eq(groupMembers.userId, userId), + }, + }, + }); + + if (dbEveryoneGroup?.members.length === 0) { + await db.insert(groupMembers).values({ + userId, + groupId: dbEveryoneGroup.id, + }); + logger.info(`Added user to everyone group. user=${userId}`); + } +}; + const synchronizeGroupsWithExternalForUserAsync = async (db: Database, userId: string, externalGroups: string[]) => { + const ignoredGroups = [everyoneGroup]; const dbGroupMembers = await db.query.groupMembers.findMany({ where: eq(groupMembers.userId, userId), with: { @@ -102,11 +124,11 @@ const synchronizeGroupsWithExternalForUserAsync = async (db: Database, userId: s } /** - * The below groups are those groups the user is part of in Homarr, but not in the external system. + * The below groups are those groups the user is part of in Homarr, but not in the external system and not ignored. * So he has to be removed from those groups. */ const groupsUserIsNoLongerMemberOfExternally = dbGroupMembers.filter( - ({ group }) => !externalGroups.includes(group.name), + ({ group }) => !externalGroups.concat(ignoredGroups).includes(group.name), ); if (groupsUserIsNoLongerMemberOfExternally.length > 0) { diff --git a/packages/auth/package.json b/packages/auth/package.json index 56c14c80f..71d51e18f 100644 --- a/packages/auth/package.json +++ b/packages/auth/package.json @@ -23,8 +23,8 @@ }, "prettier": "@homarr/prettier-config", "dependencies": { - "@auth/core": "^0.37.0", - "@auth/drizzle-adapter": "^1.7.0", + "@auth/core": "^0.37.2", + "@auth/drizzle-adapter": "^1.7.2", "@homarr/common": "workspace:^0.1.0", "@homarr/db": "workspace:^0.1.0", "@homarr/definitions": "workspace:^0.1.0", @@ -34,8 +34,8 @@ "bcrypt": "^5.1.1", "cookies": "^0.9.1", "ldapts": "7.2.1", - "next": "^14.2.15", - "next-auth": "5.0.0-beta.22", + "next": "^14.2.16", + "next-auth": "5.0.0-beta.25", "react": "^18.3.1", "react-dom": "^18.3.1" }, @@ -45,7 +45,7 @@ "@homarr/tsconfig": "workspace:^0.1.0", "@types/bcrypt": "5.0.2", "@types/cookies": "0.9.0", - "eslint": "^9.12.0", + "eslint": "^9.13.0", "prettier": "^3.3.3", "typescript": "^5.6.3" } diff --git a/packages/auth/test/events.spec.ts b/packages/auth/test/events.spec.ts index 02f44abd3..325d1d949 100644 --- a/packages/auth/test/events.spec.ts +++ b/packages/auth/test/events.spec.ts @@ -7,6 +7,7 @@ import { eq } from "@homarr/db"; import type { Database } from "@homarr/db"; import { groupMembers, groups, users } from "@homarr/db/schema/sqlite"; import { createDb } from "@homarr/db/test"; +import { everyoneGroup } from "@homarr/definitions"; import { createSignInEventHandler } from "../events"; @@ -34,6 +35,29 @@ vi.mock("next/headers", async (importOriginal) => { }); describe("createSignInEventHandler should create signInEventHandler", () => { + describe("signInEventHandler should add users to everyone group", () => { + test("should add user to everyone group if he isn't already", async () => { + // Arrange + const db = createDb(); + await createUserAsync(db); + await createGroupAsync(db, everyoneGroup); + const eventHandler = createSignInEventHandler(db); + + // Act + await eventHandler?.({ + user: { id: "1", name: "test" }, + profile: undefined, + account: null, + }); + + // Assert + const dbGroupMembers = await db.query.groupMembers.findFirst({ + where: eq(groupMembers.userId, "1"), + }); + expect(dbGroupMembers?.groupId).toBe("1"); + }); + }); + describe("signInEventHandler should synchronize ldap groups", () => { test("should add missing group membership", async () => { // Arrange @@ -79,6 +103,30 @@ describe("createSignInEventHandler should create signInEventHandler", () => { }); expect(dbGroupMembers).toBeUndefined(); }); + test("should not remove group membership for everyone group", async () => { + // Arrange + const db = createDb(); + await createUserAsync(db); + await createGroupAsync(db, everyoneGroup); + await db.insert(groupMembers).values({ + userId: "1", + groupId: "1", + }); + const eventHandler = createSignInEventHandler(db); + + // Act + await eventHandler?.({ + user: { id: "1", name: "test", groups: [] } as never, + profile: undefined, + account: null, + }); + + // Assert + const dbGroupMembers = await db.query.groupMembers.findFirst({ + where: eq(groupMembers.userId, "1"), + }); + expect(dbGroupMembers?.groupId).toBe("1"); + }); }); describe("signInEventHandler should synchronize oidc groups", () => { test("should add missing group membership", async () => { @@ -125,6 +173,30 @@ describe("createSignInEventHandler should create signInEventHandler", () => { }); expect(dbGroupMembers).toBeUndefined(); }); + test("should not remove group membership for everyone group", async () => { + // Arrange + const db = createDb(); + await createUserAsync(db); + await createGroupAsync(db, everyoneGroup); + await db.insert(groupMembers).values({ + userId: "1", + groupId: "1", + }); + const eventHandler = createSignInEventHandler(db); + + // Act + await eventHandler?.({ + user: { id: "1", name: "test" }, + profile: { preferred_username: "test", someRandomGroupsKey: [] }, + account: null, + }); + + // Assert + const dbGroupMembers = await db.query.groupMembers.findFirst({ + where: eq(groupMembers.userId, "1"), + }); + expect(dbGroupMembers?.groupId).toBe("1"); + }); }); test.each([ ["ldap" as const, { name: "test-new" }, undefined], @@ -183,8 +255,8 @@ const createUserAsync = async (db: Database) => colorScheme: "dark", }); -const createGroupAsync = async (db: Database) => +const createGroupAsync = async (db: Database, name = "test") => await db.insert(groups).values({ id: "1", - name: "test", + name, }); diff --git a/packages/cli/package.json b/packages/cli/package.json index d7766ea3a..bba9ee6b4 100644 --- a/packages/cli/package.json +++ b/packages/cli/package.json @@ -33,7 +33,7 @@ "@homarr/eslint-config": "workspace:^0.2.0", "@homarr/prettier-config": "workspace:^0.1.0", "@homarr/tsconfig": "workspace:^0.1.0", - "eslint": "^9.12.0", + "eslint": "^9.13.0", "typescript": "^5.6.3" } } diff --git a/packages/common/package.json b/packages/common/package.json index a7c915305..5259cb506 100644 --- a/packages/common/package.json +++ b/packages/common/package.json @@ -27,15 +27,15 @@ "dependencies": { "@homarr/log": "workspace:^0.1.0", "dayjs": "^1.11.13", - "next": "^14.2.15", + "next": "^14.2.16", "react": "^18.3.1", - "tldts": "^6.1.50" + "tldts": "^6.1.56" }, "devDependencies": { "@homarr/eslint-config": "workspace:^0.2.0", "@homarr/prettier-config": "workspace:^0.1.0", "@homarr/tsconfig": "workspace:^0.1.0", - "eslint": "^9.12.0", + "eslint": "^9.13.0", "typescript": "^5.6.3" } } diff --git a/packages/cron-job-runner/package.json b/packages/cron-job-runner/package.json index ef29c3968..47ee1632f 100644 --- a/packages/cron-job-runner/package.json +++ b/packages/cron-job-runner/package.json @@ -30,7 +30,7 @@ "@homarr/eslint-config": "workspace:^0.2.0", "@homarr/prettier-config": "workspace:^0.1.0", "@homarr/tsconfig": "workspace:^0.1.0", - "eslint": "^9.12.0", + "eslint": "^9.13.0", "typescript": "^5.6.3" } } diff --git a/packages/cron-job-status/package.json b/packages/cron-job-status/package.json index a5f88277b..3ecf3fdd4 100644 --- a/packages/cron-job-status/package.json +++ b/packages/cron-job-status/package.json @@ -29,7 +29,7 @@ "@homarr/eslint-config": "workspace:^0.2.0", "@homarr/prettier-config": "workspace:^0.1.0", "@homarr/tsconfig": "workspace:^0.1.0", - "eslint": "^9.12.0", + "eslint": "^9.13.0", "typescript": "^5.6.3" } } diff --git a/packages/cron-jobs-core/package.json b/packages/cron-jobs-core/package.json index 976e940f4..2fee72109 100644 --- a/packages/cron-jobs-core/package.json +++ b/packages/cron-jobs-core/package.json @@ -32,7 +32,7 @@ "@homarr/prettier-config": "workspace:^0.1.0", "@homarr/tsconfig": "workspace:^0.1.0", "@types/node-cron": "^3.0.11", - "eslint": "^9.12.0", + "eslint": "^9.13.0", "typescript": "^5.6.3" } } diff --git a/packages/cron-jobs/package.json b/packages/cron-jobs/package.json index 44617bc18..404d7c40d 100644 --- a/packages/cron-jobs/package.json +++ b/packages/cron-jobs/package.json @@ -41,7 +41,7 @@ "@homarr/eslint-config": "workspace:^0.2.0", "@homarr/prettier-config": "workspace:^0.1.0", "@homarr/tsconfig": "workspace:^0.1.0", - "eslint": "^9.12.0", + "eslint": "^9.13.0", "typescript": "^5.6.3" } } diff --git a/packages/db/migrations/mysql/0011_freezing_banshee.sql b/packages/db/migrations/mysql/0011_freezing_banshee.sql new file mode 100644 index 000000000..f088e6b9d --- /dev/null +++ b/packages/db/migrations/mysql/0011_freezing_banshee.sql @@ -0,0 +1 @@ +ALTER TABLE `user` ADD `pingIconsEnabled` boolean DEFAULT false NOT NULL; \ No newline at end of file diff --git a/packages/db/migrations/mysql/0012_abnormal_wendell_vaughn.sql b/packages/db/migrations/mysql/0012_abnormal_wendell_vaughn.sql new file mode 100644 index 000000000..2c126b3fc --- /dev/null +++ b/packages/db/migrations/mysql/0012_abnormal_wendell_vaughn.sql @@ -0,0 +1 @@ +ALTER TABLE `user` MODIFY COLUMN `colorScheme` varchar(5) NOT NULL DEFAULT 'dark'; \ No newline at end of file diff --git a/packages/db/migrations/mysql/0013_youthful_vulture.sql b/packages/db/migrations/mysql/0013_youthful_vulture.sql new file mode 100644 index 000000000..0ca6ea7b9 --- /dev/null +++ b/packages/db/migrations/mysql/0013_youthful_vulture.sql @@ -0,0 +1 @@ +ALTER TABLE `group` ADD CONSTRAINT `group_name_unique` UNIQUE(`name`); \ No newline at end of file diff --git a/packages/db/migrations/mysql/meta/0011_snapshot.json b/packages/db/migrations/mysql/meta/0011_snapshot.json new file mode 100644 index 000000000..afa00d67d --- /dev/null +++ b/packages/db/migrations/mysql/meta/0011_snapshot.json @@ -0,0 +1,1497 @@ +{ + "version": "5", + "dialect": "mysql", + "id": "c2595909-0d92-4b2f-b934-6792271f52c0", + "prevId": "ea24896b-e311-49b3-855b-e50b224e7719", + "tables": { + "account": { + "name": "account", + "columns": { + "userId": { + "name": "userId", + "type": "varchar(64)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "type": { + "name": "type", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "provider": { + "name": "provider", + "type": "varchar(64)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "providerAccountId": { + "name": "providerAccountId", + "type": "varchar(64)", + "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": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "scope": { + "name": "scope", + "type": "text", + "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": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + } + }, + "indexes": { + "userId_idx": { + "name": "userId_idx", + "columns": ["userId"], + "isUnique": false + } + }, + "foreignKeys": { + "account_userId_user_id_fk": { + "name": "account_userId_user_id_fk", + "tableFrom": "account", + "tableTo": "user", + "columnsFrom": ["userId"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": { + "account_provider_providerAccountId_pk": { + "name": "account_provider_providerAccountId_pk", + "columns": ["provider", "providerAccountId"] + } + }, + "uniqueConstraints": {} + }, + "apiKey": { + "name": "apiKey", + "columns": { + "id": { + "name": "id", + "type": "varchar(64)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "apiKey": { + "name": "apiKey", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "salt": { + "name": "salt", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "userId": { + "name": "userId", + "type": "varchar(64)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": { + "apiKey_userId_user_id_fk": { + "name": "apiKey_userId_user_id_fk", + "tableFrom": "apiKey", + "tableTo": "user", + "columnsFrom": ["userId"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": { + "apiKey_id": { + "name": "apiKey_id", + "columns": ["id"] + } + }, + "uniqueConstraints": {} + }, + "app": { + "name": "app", + "columns": { + "id": { + "name": "id", + "type": "varchar(64)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "icon_url": { + "name": "icon_url", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "href": { + "name": "href", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": { + "app_id": { + "name": "app_id", + "columns": ["id"] + } + }, + "uniqueConstraints": {} + }, + "boardGroupPermission": { + "name": "boardGroupPermission", + "columns": { + "board_id": { + "name": "board_id", + "type": "varchar(64)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "group_id": { + "name": "group_id", + "type": "varchar(64)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "permission": { + "name": "permission", + "type": "varchar(128)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": { + "boardGroupPermission_board_id_board_id_fk": { + "name": "boardGroupPermission_board_id_board_id_fk", + "tableFrom": "boardGroupPermission", + "tableTo": "board", + "columnsFrom": ["board_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "boardGroupPermission_group_id_group_id_fk": { + "name": "boardGroupPermission_group_id_group_id_fk", + "tableFrom": "boardGroupPermission", + "tableTo": "group", + "columnsFrom": ["group_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": { + "boardGroupPermission_board_id_group_id_permission_pk": { + "name": "boardGroupPermission_board_id_group_id_permission_pk", + "columns": ["board_id", "group_id", "permission"] + } + }, + "uniqueConstraints": {} + }, + "boardUserPermission": { + "name": "boardUserPermission", + "columns": { + "board_id": { + "name": "board_id", + "type": "varchar(64)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "user_id": { + "name": "user_id", + "type": "varchar(64)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "permission": { + "name": "permission", + "type": "varchar(128)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": { + "boardUserPermission_board_id_board_id_fk": { + "name": "boardUserPermission_board_id_board_id_fk", + "tableFrom": "boardUserPermission", + "tableTo": "board", + "columnsFrom": ["board_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "boardUserPermission_user_id_user_id_fk": { + "name": "boardUserPermission_user_id_user_id_fk", + "tableFrom": "boardUserPermission", + "tableTo": "user", + "columnsFrom": ["user_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": { + "boardUserPermission_board_id_user_id_permission_pk": { + "name": "boardUserPermission_board_id_user_id_permission_pk", + "columns": ["board_id", "user_id", "permission"] + } + }, + "uniqueConstraints": {} + }, + "board": { + "name": "board", + "columns": { + "id": { + "name": "id", + "type": "varchar(64)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "name": { + "name": "name", + "type": "varchar(256)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "is_public": { + "name": "is_public", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": false + }, + "creator_id": { + "name": "creator_id", + "type": "varchar(64)", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "page_title": { + "name": "page_title", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "meta_title": { + "name": "meta_title", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "logo_image_url": { + "name": "logo_image_url", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "favicon_image_url": { + "name": "favicon_image_url", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "background_image_url": { + "name": "background_image_url", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "background_image_attachment": { + "name": "background_image_attachment", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "('fixed')" + }, + "background_image_repeat": { + "name": "background_image_repeat", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "('no-repeat')" + }, + "background_image_size": { + "name": "background_image_size", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "('cover')" + }, + "primary_color": { + "name": "primary_color", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "('#fa5252')" + }, + "secondary_color": { + "name": "secondary_color", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "('#fd7e14')" + }, + "opacity": { + "name": "opacity", + "type": "int", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": 100 + }, + "custom_css": { + "name": "custom_css", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "column_count": { + "name": "column_count", + "type": "int", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": 10 + } + }, + "indexes": {}, + "foreignKeys": { + "board_creator_id_user_id_fk": { + "name": "board_creator_id_user_id_fk", + "tableFrom": "board", + "tableTo": "user", + "columnsFrom": ["creator_id"], + "columnsTo": ["id"], + "onDelete": "set null", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": { + "board_id": { + "name": "board_id", + "columns": ["id"] + } + }, + "uniqueConstraints": { + "board_name_unique": { + "name": "board_name_unique", + "columns": ["name"] + } + } + }, + "groupMember": { + "name": "groupMember", + "columns": { + "groupId": { + "name": "groupId", + "type": "varchar(64)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "userId": { + "name": "userId", + "type": "varchar(64)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": { + "groupMember_groupId_group_id_fk": { + "name": "groupMember_groupId_group_id_fk", + "tableFrom": "groupMember", + "tableTo": "group", + "columnsFrom": ["groupId"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "groupMember_userId_user_id_fk": { + "name": "groupMember_userId_user_id_fk", + "tableFrom": "groupMember", + "tableTo": "user", + "columnsFrom": ["userId"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": { + "groupMember_groupId_userId_pk": { + "name": "groupMember_groupId_userId_pk", + "columns": ["groupId", "userId"] + } + }, + "uniqueConstraints": {} + }, + "groupPermission": { + "name": "groupPermission", + "columns": { + "groupId": { + "name": "groupId", + "type": "varchar(64)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "permission": { + "name": "permission", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": { + "groupPermission_groupId_group_id_fk": { + "name": "groupPermission_groupId_group_id_fk", + "tableFrom": "groupPermission", + "tableTo": "group", + "columnsFrom": ["groupId"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {} + }, + "group": { + "name": "group", + "columns": { + "id": { + "name": "id", + "type": "varchar(64)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "name": { + "name": "name", + "type": "varchar(64)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "owner_id": { + "name": "owner_id", + "type": "varchar(64)", + "primaryKey": false, + "notNull": false, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": { + "group_owner_id_user_id_fk": { + "name": "group_owner_id_user_id_fk", + "tableFrom": "group", + "tableTo": "user", + "columnsFrom": ["owner_id"], + "columnsTo": ["id"], + "onDelete": "set null", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": { + "group_id": { + "name": "group_id", + "columns": ["id"] + } + }, + "uniqueConstraints": {} + }, + "iconRepository": { + "name": "iconRepository", + "columns": { + "iconRepository_id": { + "name": "iconRepository_id", + "type": "varchar(64)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "iconRepository_slug": { + "name": "iconRepository_slug", + "type": "varchar(150)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": { + "iconRepository_iconRepository_id": { + "name": "iconRepository_iconRepository_id", + "columns": ["iconRepository_id"] + } + }, + "uniqueConstraints": {} + }, + "icon": { + "name": "icon", + "columns": { + "icon_id": { + "name": "icon_id", + "type": "varchar(64)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "icon_name": { + "name": "icon_name", + "type": "varchar(250)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "icon_url": { + "name": "icon_url", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "icon_checksum": { + "name": "icon_checksum", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "iconRepository_id": { + "name": "iconRepository_id", + "type": "varchar(64)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": { + "icon_iconRepository_id_iconRepository_iconRepository_id_fk": { + "name": "icon_iconRepository_id_iconRepository_iconRepository_id_fk", + "tableFrom": "icon", + "tableTo": "iconRepository", + "columnsFrom": ["iconRepository_id"], + "columnsTo": ["iconRepository_id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": { + "icon_icon_id": { + "name": "icon_icon_id", + "columns": ["icon_id"] + } + }, + "uniqueConstraints": {} + }, + "integrationGroupPermissions": { + "name": "integrationGroupPermissions", + "columns": { + "integration_id": { + "name": "integration_id", + "type": "varchar(64)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "group_id": { + "name": "group_id", + "type": "varchar(64)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "permission": { + "name": "permission", + "type": "varchar(128)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": { + "integrationGroupPermissions_integration_id_integration_id_fk": { + "name": "integrationGroupPermissions_integration_id_integration_id_fk", + "tableFrom": "integrationGroupPermissions", + "tableTo": "integration", + "columnsFrom": ["integration_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "integrationGroupPermissions_group_id_group_id_fk": { + "name": "integrationGroupPermissions_group_id_group_id_fk", + "tableFrom": "integrationGroupPermissions", + "tableTo": "group", + "columnsFrom": ["group_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": { + "integration_group_permission__pk": { + "name": "integration_group_permission__pk", + "columns": ["integration_id", "group_id", "permission"] + } + }, + "uniqueConstraints": {} + }, + "integration_item": { + "name": "integration_item", + "columns": { + "item_id": { + "name": "item_id", + "type": "varchar(64)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "integration_id": { + "name": "integration_id", + "type": "varchar(64)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": { + "integration_item_item_id_item_id_fk": { + "name": "integration_item_item_id_item_id_fk", + "tableFrom": "integration_item", + "tableTo": "item", + "columnsFrom": ["item_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "integration_item_integration_id_integration_id_fk": { + "name": "integration_item_integration_id_integration_id_fk", + "tableFrom": "integration_item", + "tableTo": "integration", + "columnsFrom": ["integration_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": { + "integration_item_item_id_integration_id_pk": { + "name": "integration_item_item_id_integration_id_pk", + "columns": ["item_id", "integration_id"] + } + }, + "uniqueConstraints": {} + }, + "integrationSecret": { + "name": "integrationSecret", + "columns": { + "kind": { + "name": "kind", + "type": "varchar(16)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "value": { + "name": "value", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "integration_id": { + "name": "integration_id", + "type": "varchar(64)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": { + "integration_secret__kind_idx": { + "name": "integration_secret__kind_idx", + "columns": ["kind"], + "isUnique": false + }, + "integration_secret__updated_at_idx": { + "name": "integration_secret__updated_at_idx", + "columns": ["updated_at"], + "isUnique": false + } + }, + "foreignKeys": { + "integrationSecret_integration_id_integration_id_fk": { + "name": "integrationSecret_integration_id_integration_id_fk", + "tableFrom": "integrationSecret", + "tableTo": "integration", + "columnsFrom": ["integration_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": { + "integrationSecret_integration_id_kind_pk": { + "name": "integrationSecret_integration_id_kind_pk", + "columns": ["integration_id", "kind"] + } + }, + "uniqueConstraints": {} + }, + "integrationUserPermission": { + "name": "integrationUserPermission", + "columns": { + "integration_id": { + "name": "integration_id", + "type": "varchar(64)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "user_id": { + "name": "user_id", + "type": "varchar(64)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "permission": { + "name": "permission", + "type": "varchar(128)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": { + "integrationUserPermission_integration_id_integration_id_fk": { + "name": "integrationUserPermission_integration_id_integration_id_fk", + "tableFrom": "integrationUserPermission", + "tableTo": "integration", + "columnsFrom": ["integration_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "integrationUserPermission_user_id_user_id_fk": { + "name": "integrationUserPermission_user_id_user_id_fk", + "tableFrom": "integrationUserPermission", + "tableTo": "user", + "columnsFrom": ["user_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": { + "integrationUserPermission_integration_id_user_id_permission_pk": { + "name": "integrationUserPermission_integration_id_user_id_permission_pk", + "columns": ["integration_id", "user_id", "permission"] + } + }, + "uniqueConstraints": {} + }, + "integration": { + "name": "integration", + "columns": { + "id": { + "name": "id", + "type": "varchar(64)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "url": { + "name": "url", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "kind": { + "name": "kind", + "type": "varchar(128)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": { + "integration__kind_idx": { + "name": "integration__kind_idx", + "columns": ["kind"], + "isUnique": false + } + }, + "foreignKeys": {}, + "compositePrimaryKeys": { + "integration_id": { + "name": "integration_id", + "columns": ["id"] + } + }, + "uniqueConstraints": {} + }, + "invite": { + "name": "invite", + "columns": { + "id": { + "name": "id", + "type": "varchar(64)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "token": { + "name": "token", + "type": "varchar(512)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "expiration_date": { + "name": "expiration_date", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "creator_id": { + "name": "creator_id", + "type": "varchar(64)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": { + "invite_creator_id_user_id_fk": { + "name": "invite_creator_id_user_id_fk", + "tableFrom": "invite", + "tableTo": "user", + "columnsFrom": ["creator_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": { + "invite_id": { + "name": "invite_id", + "columns": ["id"] + } + }, + "uniqueConstraints": { + "invite_token_unique": { + "name": "invite_token_unique", + "columns": ["token"] + } + } + }, + "item": { + "name": "item", + "columns": { + "id": { + "name": "id", + "type": "varchar(64)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "section_id": { + "name": "section_id", + "type": "varchar(64)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "kind": { + "name": "kind", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "x_offset": { + "name": "x_offset", + "type": "int", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "y_offset": { + "name": "y_offset", + "type": "int", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "width": { + "name": "width", + "type": "int", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "height": { + "name": "height", + "type": "int", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "options": { + "name": "options", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "('{\"json\": {}}')" + }, + "advanced_options": { + "name": "advanced_options", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "('{\"json\": {}}')" + } + }, + "indexes": {}, + "foreignKeys": { + "item_section_id_section_id_fk": { + "name": "item_section_id_section_id_fk", + "tableFrom": "item", + "tableTo": "section", + "columnsFrom": ["section_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": { + "item_id": { + "name": "item_id", + "columns": ["id"] + } + }, + "uniqueConstraints": {} + }, + "search_engine": { + "name": "search_engine", + "columns": { + "id": { + "name": "id", + "type": "varchar(64)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "icon_url": { + "name": "icon_url", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "name": { + "name": "name", + "type": "varchar(64)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "short": { + "name": "short", + "type": "varchar(8)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "url_template": { + "name": "url_template", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": { + "search_engine_id": { + "name": "search_engine_id", + "columns": ["id"] + } + }, + "uniqueConstraints": {} + }, + "section": { + "name": "section", + "columns": { + "id": { + "name": "id", + "type": "varchar(64)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "board_id": { + "name": "board_id", + "type": "varchar(64)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "kind": { + "name": "kind", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "x_offset": { + "name": "x_offset", + "type": "int", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "y_offset": { + "name": "y_offset", + "type": "int", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "width": { + "name": "width", + "type": "int", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "height": { + "name": "height", + "type": "int", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "parent_section_id": { + "name": "parent_section_id", + "type": "varchar(64)", + "primaryKey": false, + "notNull": false, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": { + "section_board_id_board_id_fk": { + "name": "section_board_id_board_id_fk", + "tableFrom": "section", + "tableTo": "board", + "columnsFrom": ["board_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "section_parent_section_id_section_id_fk": { + "name": "section_parent_section_id_section_id_fk", + "tableFrom": "section", + "tableTo": "section", + "columnsFrom": ["parent_section_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": { + "section_id": { + "name": "section_id", + "columns": ["id"] + } + }, + "uniqueConstraints": {} + }, + "serverSetting": { + "name": "serverSetting", + "columns": { + "key": { + "name": "key", + "type": "varchar(64)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "value": { + "name": "value", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "('{\"json\": {}}')" + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": { + "serverSetting_key": { + "name": "serverSetting_key", + "columns": ["key"] + } + }, + "uniqueConstraints": { + "serverSetting_key_unique": { + "name": "serverSetting_key_unique", + "columns": ["key"] + } + } + }, + "session": { + "name": "session", + "columns": { + "sessionToken": { + "name": "sessionToken", + "type": "varchar(512)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "userId": { + "name": "userId", + "type": "varchar(64)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "expires": { + "name": "expires", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": { + "user_id_idx": { + "name": "user_id_idx", + "columns": ["userId"], + "isUnique": false + } + }, + "foreignKeys": { + "session_userId_user_id_fk": { + "name": "session_userId_user_id_fk", + "tableFrom": "session", + "tableTo": "user", + "columnsFrom": ["userId"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": { + "session_sessionToken": { + "name": "session_sessionToken", + "columns": ["sessionToken"] + } + }, + "uniqueConstraints": {} + }, + "user": { + "name": "user", + "columns": { + "id": { + "name": "id", + "type": "varchar(64)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "email": { + "name": "email", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "emailVerified": { + "name": "emailVerified", + "type": "timestamp", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "image": { + "name": "image", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "password": { + "name": "password", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "salt": { + "name": "salt", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "provider": { + "name": "provider", + "type": "varchar(64)", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "'credentials'" + }, + "homeBoardId": { + "name": "homeBoardId", + "type": "varchar(64)", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "colorScheme": { + "name": "colorScheme", + "type": "varchar(5)", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "'auto'" + }, + "firstDayOfWeek": { + "name": "firstDayOfWeek", + "type": "tinyint", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": 1 + }, + "pingIconsEnabled": { + "name": "pingIconsEnabled", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": false + } + }, + "indexes": {}, + "foreignKeys": { + "user_homeBoardId_board_id_fk": { + "name": "user_homeBoardId_board_id_fk", + "tableFrom": "user", + "tableTo": "board", + "columnsFrom": ["homeBoardId"], + "columnsTo": ["id"], + "onDelete": "set null", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": { + "user_id": { + "name": "user_id", + "columns": ["id"] + } + }, + "uniqueConstraints": {} + }, + "verificationToken": { + "name": "verificationToken", + "columns": { + "identifier": { + "name": "identifier", + "type": "varchar(64)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "token": { + "name": "token", + "type": "varchar(512)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "expires": { + "name": "expires", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": { + "verificationToken_identifier_token_pk": { + "name": "verificationToken_identifier_token_pk", + "columns": ["identifier", "token"] + } + }, + "uniqueConstraints": {} + } + }, + "_meta": { + "schemas": {}, + "tables": {}, + "columns": {} + }, + "internal": { + "tables": {}, + "indexes": {} + } +} diff --git a/packages/db/migrations/mysql/meta/0012_snapshot.json b/packages/db/migrations/mysql/meta/0012_snapshot.json new file mode 100644 index 000000000..784b0f9d3 --- /dev/null +++ b/packages/db/migrations/mysql/meta/0012_snapshot.json @@ -0,0 +1,1522 @@ +{ + "version": "5", + "dialect": "mysql", + "id": "ae1da11f-d73a-427c-8581-3ea6aabdd6d2", + "prevId": "c2595909-0d92-4b2f-b934-6792271f52c0", + "tables": { + "account": { + "name": "account", + "columns": { + "userId": { + "name": "userId", + "type": "varchar(64)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "type": { + "name": "type", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "provider": { + "name": "provider", + "type": "varchar(64)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "providerAccountId": { + "name": "providerAccountId", + "type": "varchar(64)", + "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": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "scope": { + "name": "scope", + "type": "text", + "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": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + } + }, + "indexes": { + "userId_idx": { + "name": "userId_idx", + "columns": ["userId"], + "isUnique": false + } + }, + "foreignKeys": { + "account_userId_user_id_fk": { + "name": "account_userId_user_id_fk", + "tableFrom": "account", + "tableTo": "user", + "columnsFrom": ["userId"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": { + "account_provider_providerAccountId_pk": { + "name": "account_provider_providerAccountId_pk", + "columns": ["provider", "providerAccountId"] + } + }, + "uniqueConstraints": {}, + "checkConstraint": {} + }, + "apiKey": { + "name": "apiKey", + "columns": { + "id": { + "name": "id", + "type": "varchar(64)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "apiKey": { + "name": "apiKey", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "salt": { + "name": "salt", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "userId": { + "name": "userId", + "type": "varchar(64)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": { + "apiKey_userId_user_id_fk": { + "name": "apiKey_userId_user_id_fk", + "tableFrom": "apiKey", + "tableTo": "user", + "columnsFrom": ["userId"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": { + "apiKey_id": { + "name": "apiKey_id", + "columns": ["id"] + } + }, + "uniqueConstraints": {}, + "checkConstraint": {} + }, + "app": { + "name": "app", + "columns": { + "id": { + "name": "id", + "type": "varchar(64)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "icon_url": { + "name": "icon_url", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "href": { + "name": "href", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": { + "app_id": { + "name": "app_id", + "columns": ["id"] + } + }, + "uniqueConstraints": {}, + "checkConstraint": {} + }, + "boardGroupPermission": { + "name": "boardGroupPermission", + "columns": { + "board_id": { + "name": "board_id", + "type": "varchar(64)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "group_id": { + "name": "group_id", + "type": "varchar(64)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "permission": { + "name": "permission", + "type": "varchar(128)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": { + "boardGroupPermission_board_id_board_id_fk": { + "name": "boardGroupPermission_board_id_board_id_fk", + "tableFrom": "boardGroupPermission", + "tableTo": "board", + "columnsFrom": ["board_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "boardGroupPermission_group_id_group_id_fk": { + "name": "boardGroupPermission_group_id_group_id_fk", + "tableFrom": "boardGroupPermission", + "tableTo": "group", + "columnsFrom": ["group_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": { + "boardGroupPermission_board_id_group_id_permission_pk": { + "name": "boardGroupPermission_board_id_group_id_permission_pk", + "columns": ["board_id", "group_id", "permission"] + } + }, + "uniqueConstraints": {}, + "checkConstraint": {} + }, + "boardUserPermission": { + "name": "boardUserPermission", + "columns": { + "board_id": { + "name": "board_id", + "type": "varchar(64)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "user_id": { + "name": "user_id", + "type": "varchar(64)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "permission": { + "name": "permission", + "type": "varchar(128)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": { + "boardUserPermission_board_id_board_id_fk": { + "name": "boardUserPermission_board_id_board_id_fk", + "tableFrom": "boardUserPermission", + "tableTo": "board", + "columnsFrom": ["board_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "boardUserPermission_user_id_user_id_fk": { + "name": "boardUserPermission_user_id_user_id_fk", + "tableFrom": "boardUserPermission", + "tableTo": "user", + "columnsFrom": ["user_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": { + "boardUserPermission_board_id_user_id_permission_pk": { + "name": "boardUserPermission_board_id_user_id_permission_pk", + "columns": ["board_id", "user_id", "permission"] + } + }, + "uniqueConstraints": {}, + "checkConstraint": {} + }, + "board": { + "name": "board", + "columns": { + "id": { + "name": "id", + "type": "varchar(64)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "name": { + "name": "name", + "type": "varchar(256)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "is_public": { + "name": "is_public", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": false + }, + "creator_id": { + "name": "creator_id", + "type": "varchar(64)", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "page_title": { + "name": "page_title", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "meta_title": { + "name": "meta_title", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "logo_image_url": { + "name": "logo_image_url", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "favicon_image_url": { + "name": "favicon_image_url", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "background_image_url": { + "name": "background_image_url", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "background_image_attachment": { + "name": "background_image_attachment", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "('fixed')" + }, + "background_image_repeat": { + "name": "background_image_repeat", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "('no-repeat')" + }, + "background_image_size": { + "name": "background_image_size", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "('cover')" + }, + "primary_color": { + "name": "primary_color", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "('#fa5252')" + }, + "secondary_color": { + "name": "secondary_color", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "('#fd7e14')" + }, + "opacity": { + "name": "opacity", + "type": "int", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": 100 + }, + "custom_css": { + "name": "custom_css", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "column_count": { + "name": "column_count", + "type": "int", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": 10 + } + }, + "indexes": {}, + "foreignKeys": { + "board_creator_id_user_id_fk": { + "name": "board_creator_id_user_id_fk", + "tableFrom": "board", + "tableTo": "user", + "columnsFrom": ["creator_id"], + "columnsTo": ["id"], + "onDelete": "set null", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": { + "board_id": { + "name": "board_id", + "columns": ["id"] + } + }, + "uniqueConstraints": { + "board_name_unique": { + "name": "board_name_unique", + "columns": ["name"] + } + }, + "checkConstraint": {} + }, + "groupMember": { + "name": "groupMember", + "columns": { + "groupId": { + "name": "groupId", + "type": "varchar(64)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "userId": { + "name": "userId", + "type": "varchar(64)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": { + "groupMember_groupId_group_id_fk": { + "name": "groupMember_groupId_group_id_fk", + "tableFrom": "groupMember", + "tableTo": "group", + "columnsFrom": ["groupId"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "groupMember_userId_user_id_fk": { + "name": "groupMember_userId_user_id_fk", + "tableFrom": "groupMember", + "tableTo": "user", + "columnsFrom": ["userId"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": { + "groupMember_groupId_userId_pk": { + "name": "groupMember_groupId_userId_pk", + "columns": ["groupId", "userId"] + } + }, + "uniqueConstraints": {}, + "checkConstraint": {} + }, + "groupPermission": { + "name": "groupPermission", + "columns": { + "groupId": { + "name": "groupId", + "type": "varchar(64)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "permission": { + "name": "permission", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": { + "groupPermission_groupId_group_id_fk": { + "name": "groupPermission_groupId_group_id_fk", + "tableFrom": "groupPermission", + "tableTo": "group", + "columnsFrom": ["groupId"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraint": {} + }, + "group": { + "name": "group", + "columns": { + "id": { + "name": "id", + "type": "varchar(64)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "name": { + "name": "name", + "type": "varchar(64)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "owner_id": { + "name": "owner_id", + "type": "varchar(64)", + "primaryKey": false, + "notNull": false, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": { + "group_owner_id_user_id_fk": { + "name": "group_owner_id_user_id_fk", + "tableFrom": "group", + "tableTo": "user", + "columnsFrom": ["owner_id"], + "columnsTo": ["id"], + "onDelete": "set null", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": { + "group_id": { + "name": "group_id", + "columns": ["id"] + } + }, + "uniqueConstraints": {}, + "checkConstraint": {} + }, + "iconRepository": { + "name": "iconRepository", + "columns": { + "iconRepository_id": { + "name": "iconRepository_id", + "type": "varchar(64)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "iconRepository_slug": { + "name": "iconRepository_slug", + "type": "varchar(150)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": { + "iconRepository_iconRepository_id": { + "name": "iconRepository_iconRepository_id", + "columns": ["iconRepository_id"] + } + }, + "uniqueConstraints": {}, + "checkConstraint": {} + }, + "icon": { + "name": "icon", + "columns": { + "icon_id": { + "name": "icon_id", + "type": "varchar(64)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "icon_name": { + "name": "icon_name", + "type": "varchar(250)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "icon_url": { + "name": "icon_url", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "icon_checksum": { + "name": "icon_checksum", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "iconRepository_id": { + "name": "iconRepository_id", + "type": "varchar(64)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": { + "icon_iconRepository_id_iconRepository_iconRepository_id_fk": { + "name": "icon_iconRepository_id_iconRepository_iconRepository_id_fk", + "tableFrom": "icon", + "tableTo": "iconRepository", + "columnsFrom": ["iconRepository_id"], + "columnsTo": ["iconRepository_id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": { + "icon_icon_id": { + "name": "icon_icon_id", + "columns": ["icon_id"] + } + }, + "uniqueConstraints": {}, + "checkConstraint": {} + }, + "integrationGroupPermissions": { + "name": "integrationGroupPermissions", + "columns": { + "integration_id": { + "name": "integration_id", + "type": "varchar(64)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "group_id": { + "name": "group_id", + "type": "varchar(64)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "permission": { + "name": "permission", + "type": "varchar(128)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": { + "integrationGroupPermissions_integration_id_integration_id_fk": { + "name": "integrationGroupPermissions_integration_id_integration_id_fk", + "tableFrom": "integrationGroupPermissions", + "tableTo": "integration", + "columnsFrom": ["integration_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "integrationGroupPermissions_group_id_group_id_fk": { + "name": "integrationGroupPermissions_group_id_group_id_fk", + "tableFrom": "integrationGroupPermissions", + "tableTo": "group", + "columnsFrom": ["group_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": { + "integration_group_permission__pk": { + "name": "integration_group_permission__pk", + "columns": ["integration_id", "group_id", "permission"] + } + }, + "uniqueConstraints": {}, + "checkConstraint": {} + }, + "integration_item": { + "name": "integration_item", + "columns": { + "item_id": { + "name": "item_id", + "type": "varchar(64)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "integration_id": { + "name": "integration_id", + "type": "varchar(64)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": { + "integration_item_item_id_item_id_fk": { + "name": "integration_item_item_id_item_id_fk", + "tableFrom": "integration_item", + "tableTo": "item", + "columnsFrom": ["item_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "integration_item_integration_id_integration_id_fk": { + "name": "integration_item_integration_id_integration_id_fk", + "tableFrom": "integration_item", + "tableTo": "integration", + "columnsFrom": ["integration_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": { + "integration_item_item_id_integration_id_pk": { + "name": "integration_item_item_id_integration_id_pk", + "columns": ["item_id", "integration_id"] + } + }, + "uniqueConstraints": {}, + "checkConstraint": {} + }, + "integrationSecret": { + "name": "integrationSecret", + "columns": { + "kind": { + "name": "kind", + "type": "varchar(16)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "value": { + "name": "value", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "integration_id": { + "name": "integration_id", + "type": "varchar(64)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": { + "integration_secret__kind_idx": { + "name": "integration_secret__kind_idx", + "columns": ["kind"], + "isUnique": false + }, + "integration_secret__updated_at_idx": { + "name": "integration_secret__updated_at_idx", + "columns": ["updated_at"], + "isUnique": false + } + }, + "foreignKeys": { + "integrationSecret_integration_id_integration_id_fk": { + "name": "integrationSecret_integration_id_integration_id_fk", + "tableFrom": "integrationSecret", + "tableTo": "integration", + "columnsFrom": ["integration_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": { + "integrationSecret_integration_id_kind_pk": { + "name": "integrationSecret_integration_id_kind_pk", + "columns": ["integration_id", "kind"] + } + }, + "uniqueConstraints": {}, + "checkConstraint": {} + }, + "integrationUserPermission": { + "name": "integrationUserPermission", + "columns": { + "integration_id": { + "name": "integration_id", + "type": "varchar(64)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "user_id": { + "name": "user_id", + "type": "varchar(64)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "permission": { + "name": "permission", + "type": "varchar(128)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": { + "integrationUserPermission_integration_id_integration_id_fk": { + "name": "integrationUserPermission_integration_id_integration_id_fk", + "tableFrom": "integrationUserPermission", + "tableTo": "integration", + "columnsFrom": ["integration_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "integrationUserPermission_user_id_user_id_fk": { + "name": "integrationUserPermission_user_id_user_id_fk", + "tableFrom": "integrationUserPermission", + "tableTo": "user", + "columnsFrom": ["user_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": { + "integrationUserPermission_integration_id_user_id_permission_pk": { + "name": "integrationUserPermission_integration_id_user_id_permission_pk", + "columns": ["integration_id", "user_id", "permission"] + } + }, + "uniqueConstraints": {}, + "checkConstraint": {} + }, + "integration": { + "name": "integration", + "columns": { + "id": { + "name": "id", + "type": "varchar(64)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "url": { + "name": "url", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "kind": { + "name": "kind", + "type": "varchar(128)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": { + "integration__kind_idx": { + "name": "integration__kind_idx", + "columns": ["kind"], + "isUnique": false + } + }, + "foreignKeys": {}, + "compositePrimaryKeys": { + "integration_id": { + "name": "integration_id", + "columns": ["id"] + } + }, + "uniqueConstraints": {}, + "checkConstraint": {} + }, + "invite": { + "name": "invite", + "columns": { + "id": { + "name": "id", + "type": "varchar(64)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "token": { + "name": "token", + "type": "varchar(512)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "expiration_date": { + "name": "expiration_date", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "creator_id": { + "name": "creator_id", + "type": "varchar(64)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": { + "invite_creator_id_user_id_fk": { + "name": "invite_creator_id_user_id_fk", + "tableFrom": "invite", + "tableTo": "user", + "columnsFrom": ["creator_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": { + "invite_id": { + "name": "invite_id", + "columns": ["id"] + } + }, + "uniqueConstraints": { + "invite_token_unique": { + "name": "invite_token_unique", + "columns": ["token"] + } + }, + "checkConstraint": {} + }, + "item": { + "name": "item", + "columns": { + "id": { + "name": "id", + "type": "varchar(64)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "section_id": { + "name": "section_id", + "type": "varchar(64)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "kind": { + "name": "kind", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "x_offset": { + "name": "x_offset", + "type": "int", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "y_offset": { + "name": "y_offset", + "type": "int", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "width": { + "name": "width", + "type": "int", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "height": { + "name": "height", + "type": "int", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "options": { + "name": "options", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "('{\"json\": {}}')" + }, + "advanced_options": { + "name": "advanced_options", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "('{\"json\": {}}')" + } + }, + "indexes": {}, + "foreignKeys": { + "item_section_id_section_id_fk": { + "name": "item_section_id_section_id_fk", + "tableFrom": "item", + "tableTo": "section", + "columnsFrom": ["section_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": { + "item_id": { + "name": "item_id", + "columns": ["id"] + } + }, + "uniqueConstraints": {}, + "checkConstraint": {} + }, + "search_engine": { + "name": "search_engine", + "columns": { + "id": { + "name": "id", + "type": "varchar(64)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "icon_url": { + "name": "icon_url", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "name": { + "name": "name", + "type": "varchar(64)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "short": { + "name": "short", + "type": "varchar(8)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "url_template": { + "name": "url_template", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": { + "search_engine_id": { + "name": "search_engine_id", + "columns": ["id"] + } + }, + "uniqueConstraints": {}, + "checkConstraint": {} + }, + "section": { + "name": "section", + "columns": { + "id": { + "name": "id", + "type": "varchar(64)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "board_id": { + "name": "board_id", + "type": "varchar(64)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "kind": { + "name": "kind", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "x_offset": { + "name": "x_offset", + "type": "int", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "y_offset": { + "name": "y_offset", + "type": "int", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "width": { + "name": "width", + "type": "int", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "height": { + "name": "height", + "type": "int", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "parent_section_id": { + "name": "parent_section_id", + "type": "varchar(64)", + "primaryKey": false, + "notNull": false, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": { + "section_board_id_board_id_fk": { + "name": "section_board_id_board_id_fk", + "tableFrom": "section", + "tableTo": "board", + "columnsFrom": ["board_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "section_parent_section_id_section_id_fk": { + "name": "section_parent_section_id_section_id_fk", + "tableFrom": "section", + "tableTo": "section", + "columnsFrom": ["parent_section_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": { + "section_id": { + "name": "section_id", + "columns": ["id"] + } + }, + "uniqueConstraints": {}, + "checkConstraint": {} + }, + "serverSetting": { + "name": "serverSetting", + "columns": { + "key": { + "name": "key", + "type": "varchar(64)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "value": { + "name": "value", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "('{\"json\": {}}')" + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": { + "serverSetting_key": { + "name": "serverSetting_key", + "columns": ["key"] + } + }, + "uniqueConstraints": { + "serverSetting_key_unique": { + "name": "serverSetting_key_unique", + "columns": ["key"] + } + }, + "checkConstraint": {} + }, + "session": { + "name": "session", + "columns": { + "sessionToken": { + "name": "sessionToken", + "type": "varchar(512)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "userId": { + "name": "userId", + "type": "varchar(64)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "expires": { + "name": "expires", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": { + "user_id_idx": { + "name": "user_id_idx", + "columns": ["userId"], + "isUnique": false + } + }, + "foreignKeys": { + "session_userId_user_id_fk": { + "name": "session_userId_user_id_fk", + "tableFrom": "session", + "tableTo": "user", + "columnsFrom": ["userId"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": { + "session_sessionToken": { + "name": "session_sessionToken", + "columns": ["sessionToken"] + } + }, + "uniqueConstraints": {}, + "checkConstraint": {} + }, + "user": { + "name": "user", + "columns": { + "id": { + "name": "id", + "type": "varchar(64)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "email": { + "name": "email", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "emailVerified": { + "name": "emailVerified", + "type": "timestamp", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "image": { + "name": "image", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "password": { + "name": "password", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "salt": { + "name": "salt", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "provider": { + "name": "provider", + "type": "varchar(64)", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "'credentials'" + }, + "homeBoardId": { + "name": "homeBoardId", + "type": "varchar(64)", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "colorScheme": { + "name": "colorScheme", + "type": "varchar(5)", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "'dark'" + }, + "firstDayOfWeek": { + "name": "firstDayOfWeek", + "type": "tinyint", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": 1 + }, + "pingIconsEnabled": { + "name": "pingIconsEnabled", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": false + } + }, + "indexes": {}, + "foreignKeys": { + "user_homeBoardId_board_id_fk": { + "name": "user_homeBoardId_board_id_fk", + "tableFrom": "user", + "tableTo": "board", + "columnsFrom": ["homeBoardId"], + "columnsTo": ["id"], + "onDelete": "set null", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": { + "user_id": { + "name": "user_id", + "columns": ["id"] + } + }, + "uniqueConstraints": {}, + "checkConstraint": {} + }, + "verificationToken": { + "name": "verificationToken", + "columns": { + "identifier": { + "name": "identifier", + "type": "varchar(64)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "token": { + "name": "token", + "type": "varchar(512)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "expires": { + "name": "expires", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": { + "verificationToken_identifier_token_pk": { + "name": "verificationToken_identifier_token_pk", + "columns": ["identifier", "token"] + } + }, + "uniqueConstraints": {}, + "checkConstraint": {} + } + }, + "views": {}, + "_meta": { + "schemas": {}, + "tables": {}, + "columns": {} + }, + "internal": { + "tables": {}, + "indexes": {} + } +} diff --git a/packages/db/migrations/mysql/meta/0013_snapshot.json b/packages/db/migrations/mysql/meta/0013_snapshot.json new file mode 100644 index 000000000..69a7e253f --- /dev/null +++ b/packages/db/migrations/mysql/meta/0013_snapshot.json @@ -0,0 +1,1527 @@ +{ + "version": "5", + "dialect": "mysql", + "id": "aa507e60-8e16-4546-b7a5-86304be877ab", + "prevId": "ae1da11f-d73a-427c-8581-3ea6aabdd6d2", + "tables": { + "account": { + "name": "account", + "columns": { + "userId": { + "name": "userId", + "type": "varchar(64)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "type": { + "name": "type", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "provider": { + "name": "provider", + "type": "varchar(64)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "providerAccountId": { + "name": "providerAccountId", + "type": "varchar(64)", + "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": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "scope": { + "name": "scope", + "type": "text", + "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": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + } + }, + "indexes": { + "userId_idx": { + "name": "userId_idx", + "columns": ["userId"], + "isUnique": false + } + }, + "foreignKeys": { + "account_userId_user_id_fk": { + "name": "account_userId_user_id_fk", + "tableFrom": "account", + "tableTo": "user", + "columnsFrom": ["userId"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": { + "account_provider_providerAccountId_pk": { + "name": "account_provider_providerAccountId_pk", + "columns": ["provider", "providerAccountId"] + } + }, + "uniqueConstraints": {}, + "checkConstraint": {} + }, + "apiKey": { + "name": "apiKey", + "columns": { + "id": { + "name": "id", + "type": "varchar(64)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "apiKey": { + "name": "apiKey", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "salt": { + "name": "salt", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "userId": { + "name": "userId", + "type": "varchar(64)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": { + "apiKey_userId_user_id_fk": { + "name": "apiKey_userId_user_id_fk", + "tableFrom": "apiKey", + "tableTo": "user", + "columnsFrom": ["userId"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": { + "apiKey_id": { + "name": "apiKey_id", + "columns": ["id"] + } + }, + "uniqueConstraints": {}, + "checkConstraint": {} + }, + "app": { + "name": "app", + "columns": { + "id": { + "name": "id", + "type": "varchar(64)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "icon_url": { + "name": "icon_url", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "href": { + "name": "href", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": { + "app_id": { + "name": "app_id", + "columns": ["id"] + } + }, + "uniqueConstraints": {}, + "checkConstraint": {} + }, + "boardGroupPermission": { + "name": "boardGroupPermission", + "columns": { + "board_id": { + "name": "board_id", + "type": "varchar(64)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "group_id": { + "name": "group_id", + "type": "varchar(64)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "permission": { + "name": "permission", + "type": "varchar(128)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": { + "boardGroupPermission_board_id_board_id_fk": { + "name": "boardGroupPermission_board_id_board_id_fk", + "tableFrom": "boardGroupPermission", + "tableTo": "board", + "columnsFrom": ["board_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "boardGroupPermission_group_id_group_id_fk": { + "name": "boardGroupPermission_group_id_group_id_fk", + "tableFrom": "boardGroupPermission", + "tableTo": "group", + "columnsFrom": ["group_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": { + "boardGroupPermission_board_id_group_id_permission_pk": { + "name": "boardGroupPermission_board_id_group_id_permission_pk", + "columns": ["board_id", "group_id", "permission"] + } + }, + "uniqueConstraints": {}, + "checkConstraint": {} + }, + "boardUserPermission": { + "name": "boardUserPermission", + "columns": { + "board_id": { + "name": "board_id", + "type": "varchar(64)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "user_id": { + "name": "user_id", + "type": "varchar(64)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "permission": { + "name": "permission", + "type": "varchar(128)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": { + "boardUserPermission_board_id_board_id_fk": { + "name": "boardUserPermission_board_id_board_id_fk", + "tableFrom": "boardUserPermission", + "tableTo": "board", + "columnsFrom": ["board_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "boardUserPermission_user_id_user_id_fk": { + "name": "boardUserPermission_user_id_user_id_fk", + "tableFrom": "boardUserPermission", + "tableTo": "user", + "columnsFrom": ["user_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": { + "boardUserPermission_board_id_user_id_permission_pk": { + "name": "boardUserPermission_board_id_user_id_permission_pk", + "columns": ["board_id", "user_id", "permission"] + } + }, + "uniqueConstraints": {}, + "checkConstraint": {} + }, + "board": { + "name": "board", + "columns": { + "id": { + "name": "id", + "type": "varchar(64)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "name": { + "name": "name", + "type": "varchar(256)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "is_public": { + "name": "is_public", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": false + }, + "creator_id": { + "name": "creator_id", + "type": "varchar(64)", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "page_title": { + "name": "page_title", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "meta_title": { + "name": "meta_title", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "logo_image_url": { + "name": "logo_image_url", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "favicon_image_url": { + "name": "favicon_image_url", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "background_image_url": { + "name": "background_image_url", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "background_image_attachment": { + "name": "background_image_attachment", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "('fixed')" + }, + "background_image_repeat": { + "name": "background_image_repeat", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "('no-repeat')" + }, + "background_image_size": { + "name": "background_image_size", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "('cover')" + }, + "primary_color": { + "name": "primary_color", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "('#fa5252')" + }, + "secondary_color": { + "name": "secondary_color", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "('#fd7e14')" + }, + "opacity": { + "name": "opacity", + "type": "int", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": 100 + }, + "custom_css": { + "name": "custom_css", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "column_count": { + "name": "column_count", + "type": "int", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": 10 + } + }, + "indexes": {}, + "foreignKeys": { + "board_creator_id_user_id_fk": { + "name": "board_creator_id_user_id_fk", + "tableFrom": "board", + "tableTo": "user", + "columnsFrom": ["creator_id"], + "columnsTo": ["id"], + "onDelete": "set null", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": { + "board_id": { + "name": "board_id", + "columns": ["id"] + } + }, + "uniqueConstraints": { + "board_name_unique": { + "name": "board_name_unique", + "columns": ["name"] + } + }, + "checkConstraint": {} + }, + "groupMember": { + "name": "groupMember", + "columns": { + "groupId": { + "name": "groupId", + "type": "varchar(64)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "userId": { + "name": "userId", + "type": "varchar(64)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": { + "groupMember_groupId_group_id_fk": { + "name": "groupMember_groupId_group_id_fk", + "tableFrom": "groupMember", + "tableTo": "group", + "columnsFrom": ["groupId"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "groupMember_userId_user_id_fk": { + "name": "groupMember_userId_user_id_fk", + "tableFrom": "groupMember", + "tableTo": "user", + "columnsFrom": ["userId"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": { + "groupMember_groupId_userId_pk": { + "name": "groupMember_groupId_userId_pk", + "columns": ["groupId", "userId"] + } + }, + "uniqueConstraints": {}, + "checkConstraint": {} + }, + "groupPermission": { + "name": "groupPermission", + "columns": { + "groupId": { + "name": "groupId", + "type": "varchar(64)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "permission": { + "name": "permission", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": { + "groupPermission_groupId_group_id_fk": { + "name": "groupPermission_groupId_group_id_fk", + "tableFrom": "groupPermission", + "tableTo": "group", + "columnsFrom": ["groupId"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraint": {} + }, + "group": { + "name": "group", + "columns": { + "id": { + "name": "id", + "type": "varchar(64)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "name": { + "name": "name", + "type": "varchar(64)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "owner_id": { + "name": "owner_id", + "type": "varchar(64)", + "primaryKey": false, + "notNull": false, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": { + "group_owner_id_user_id_fk": { + "name": "group_owner_id_user_id_fk", + "tableFrom": "group", + "tableTo": "user", + "columnsFrom": ["owner_id"], + "columnsTo": ["id"], + "onDelete": "set null", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": { + "group_id": { + "name": "group_id", + "columns": ["id"] + } + }, + "uniqueConstraints": { + "group_name_unique": { + "name": "group_name_unique", + "columns": ["name"] + } + }, + "checkConstraint": {} + }, + "iconRepository": { + "name": "iconRepository", + "columns": { + "iconRepository_id": { + "name": "iconRepository_id", + "type": "varchar(64)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "iconRepository_slug": { + "name": "iconRepository_slug", + "type": "varchar(150)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": { + "iconRepository_iconRepository_id": { + "name": "iconRepository_iconRepository_id", + "columns": ["iconRepository_id"] + } + }, + "uniqueConstraints": {}, + "checkConstraint": {} + }, + "icon": { + "name": "icon", + "columns": { + "icon_id": { + "name": "icon_id", + "type": "varchar(64)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "icon_name": { + "name": "icon_name", + "type": "varchar(250)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "icon_url": { + "name": "icon_url", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "icon_checksum": { + "name": "icon_checksum", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "iconRepository_id": { + "name": "iconRepository_id", + "type": "varchar(64)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": { + "icon_iconRepository_id_iconRepository_iconRepository_id_fk": { + "name": "icon_iconRepository_id_iconRepository_iconRepository_id_fk", + "tableFrom": "icon", + "tableTo": "iconRepository", + "columnsFrom": ["iconRepository_id"], + "columnsTo": ["iconRepository_id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": { + "icon_icon_id": { + "name": "icon_icon_id", + "columns": ["icon_id"] + } + }, + "uniqueConstraints": {}, + "checkConstraint": {} + }, + "integrationGroupPermissions": { + "name": "integrationGroupPermissions", + "columns": { + "integration_id": { + "name": "integration_id", + "type": "varchar(64)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "group_id": { + "name": "group_id", + "type": "varchar(64)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "permission": { + "name": "permission", + "type": "varchar(128)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": { + "integrationGroupPermissions_integration_id_integration_id_fk": { + "name": "integrationGroupPermissions_integration_id_integration_id_fk", + "tableFrom": "integrationGroupPermissions", + "tableTo": "integration", + "columnsFrom": ["integration_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "integrationGroupPermissions_group_id_group_id_fk": { + "name": "integrationGroupPermissions_group_id_group_id_fk", + "tableFrom": "integrationGroupPermissions", + "tableTo": "group", + "columnsFrom": ["group_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": { + "integration_group_permission__pk": { + "name": "integration_group_permission__pk", + "columns": ["integration_id", "group_id", "permission"] + } + }, + "uniqueConstraints": {}, + "checkConstraint": {} + }, + "integration_item": { + "name": "integration_item", + "columns": { + "item_id": { + "name": "item_id", + "type": "varchar(64)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "integration_id": { + "name": "integration_id", + "type": "varchar(64)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": { + "integration_item_item_id_item_id_fk": { + "name": "integration_item_item_id_item_id_fk", + "tableFrom": "integration_item", + "tableTo": "item", + "columnsFrom": ["item_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "integration_item_integration_id_integration_id_fk": { + "name": "integration_item_integration_id_integration_id_fk", + "tableFrom": "integration_item", + "tableTo": "integration", + "columnsFrom": ["integration_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": { + "integration_item_item_id_integration_id_pk": { + "name": "integration_item_item_id_integration_id_pk", + "columns": ["item_id", "integration_id"] + } + }, + "uniqueConstraints": {}, + "checkConstraint": {} + }, + "integrationSecret": { + "name": "integrationSecret", + "columns": { + "kind": { + "name": "kind", + "type": "varchar(16)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "value": { + "name": "value", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "integration_id": { + "name": "integration_id", + "type": "varchar(64)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": { + "integration_secret__kind_idx": { + "name": "integration_secret__kind_idx", + "columns": ["kind"], + "isUnique": false + }, + "integration_secret__updated_at_idx": { + "name": "integration_secret__updated_at_idx", + "columns": ["updated_at"], + "isUnique": false + } + }, + "foreignKeys": { + "integrationSecret_integration_id_integration_id_fk": { + "name": "integrationSecret_integration_id_integration_id_fk", + "tableFrom": "integrationSecret", + "tableTo": "integration", + "columnsFrom": ["integration_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": { + "integrationSecret_integration_id_kind_pk": { + "name": "integrationSecret_integration_id_kind_pk", + "columns": ["integration_id", "kind"] + } + }, + "uniqueConstraints": {}, + "checkConstraint": {} + }, + "integrationUserPermission": { + "name": "integrationUserPermission", + "columns": { + "integration_id": { + "name": "integration_id", + "type": "varchar(64)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "user_id": { + "name": "user_id", + "type": "varchar(64)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "permission": { + "name": "permission", + "type": "varchar(128)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": { + "integrationUserPermission_integration_id_integration_id_fk": { + "name": "integrationUserPermission_integration_id_integration_id_fk", + "tableFrom": "integrationUserPermission", + "tableTo": "integration", + "columnsFrom": ["integration_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "integrationUserPermission_user_id_user_id_fk": { + "name": "integrationUserPermission_user_id_user_id_fk", + "tableFrom": "integrationUserPermission", + "tableTo": "user", + "columnsFrom": ["user_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": { + "integrationUserPermission_integration_id_user_id_permission_pk": { + "name": "integrationUserPermission_integration_id_user_id_permission_pk", + "columns": ["integration_id", "user_id", "permission"] + } + }, + "uniqueConstraints": {}, + "checkConstraint": {} + }, + "integration": { + "name": "integration", + "columns": { + "id": { + "name": "id", + "type": "varchar(64)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "url": { + "name": "url", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "kind": { + "name": "kind", + "type": "varchar(128)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": { + "integration__kind_idx": { + "name": "integration__kind_idx", + "columns": ["kind"], + "isUnique": false + } + }, + "foreignKeys": {}, + "compositePrimaryKeys": { + "integration_id": { + "name": "integration_id", + "columns": ["id"] + } + }, + "uniqueConstraints": {}, + "checkConstraint": {} + }, + "invite": { + "name": "invite", + "columns": { + "id": { + "name": "id", + "type": "varchar(64)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "token": { + "name": "token", + "type": "varchar(512)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "expiration_date": { + "name": "expiration_date", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "creator_id": { + "name": "creator_id", + "type": "varchar(64)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": { + "invite_creator_id_user_id_fk": { + "name": "invite_creator_id_user_id_fk", + "tableFrom": "invite", + "tableTo": "user", + "columnsFrom": ["creator_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": { + "invite_id": { + "name": "invite_id", + "columns": ["id"] + } + }, + "uniqueConstraints": { + "invite_token_unique": { + "name": "invite_token_unique", + "columns": ["token"] + } + }, + "checkConstraint": {} + }, + "item": { + "name": "item", + "columns": { + "id": { + "name": "id", + "type": "varchar(64)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "section_id": { + "name": "section_id", + "type": "varchar(64)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "kind": { + "name": "kind", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "x_offset": { + "name": "x_offset", + "type": "int", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "y_offset": { + "name": "y_offset", + "type": "int", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "width": { + "name": "width", + "type": "int", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "height": { + "name": "height", + "type": "int", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "options": { + "name": "options", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "('{\"json\": {}}')" + }, + "advanced_options": { + "name": "advanced_options", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "('{\"json\": {}}')" + } + }, + "indexes": {}, + "foreignKeys": { + "item_section_id_section_id_fk": { + "name": "item_section_id_section_id_fk", + "tableFrom": "item", + "tableTo": "section", + "columnsFrom": ["section_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": { + "item_id": { + "name": "item_id", + "columns": ["id"] + } + }, + "uniqueConstraints": {}, + "checkConstraint": {} + }, + "search_engine": { + "name": "search_engine", + "columns": { + "id": { + "name": "id", + "type": "varchar(64)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "icon_url": { + "name": "icon_url", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "name": { + "name": "name", + "type": "varchar(64)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "short": { + "name": "short", + "type": "varchar(8)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "url_template": { + "name": "url_template", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": { + "search_engine_id": { + "name": "search_engine_id", + "columns": ["id"] + } + }, + "uniqueConstraints": {}, + "checkConstraint": {} + }, + "section": { + "name": "section", + "columns": { + "id": { + "name": "id", + "type": "varchar(64)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "board_id": { + "name": "board_id", + "type": "varchar(64)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "kind": { + "name": "kind", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "x_offset": { + "name": "x_offset", + "type": "int", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "y_offset": { + "name": "y_offset", + "type": "int", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "width": { + "name": "width", + "type": "int", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "height": { + "name": "height", + "type": "int", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "parent_section_id": { + "name": "parent_section_id", + "type": "varchar(64)", + "primaryKey": false, + "notNull": false, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": { + "section_board_id_board_id_fk": { + "name": "section_board_id_board_id_fk", + "tableFrom": "section", + "tableTo": "board", + "columnsFrom": ["board_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "section_parent_section_id_section_id_fk": { + "name": "section_parent_section_id_section_id_fk", + "tableFrom": "section", + "tableTo": "section", + "columnsFrom": ["parent_section_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": { + "section_id": { + "name": "section_id", + "columns": ["id"] + } + }, + "uniqueConstraints": {}, + "checkConstraint": {} + }, + "serverSetting": { + "name": "serverSetting", + "columns": { + "key": { + "name": "key", + "type": "varchar(64)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "value": { + "name": "value", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "('{\"json\": {}}')" + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": { + "serverSetting_key": { + "name": "serverSetting_key", + "columns": ["key"] + } + }, + "uniqueConstraints": { + "serverSetting_key_unique": { + "name": "serverSetting_key_unique", + "columns": ["key"] + } + }, + "checkConstraint": {} + }, + "session": { + "name": "session", + "columns": { + "sessionToken": { + "name": "sessionToken", + "type": "varchar(512)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "userId": { + "name": "userId", + "type": "varchar(64)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "expires": { + "name": "expires", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": { + "user_id_idx": { + "name": "user_id_idx", + "columns": ["userId"], + "isUnique": false + } + }, + "foreignKeys": { + "session_userId_user_id_fk": { + "name": "session_userId_user_id_fk", + "tableFrom": "session", + "tableTo": "user", + "columnsFrom": ["userId"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": { + "session_sessionToken": { + "name": "session_sessionToken", + "columns": ["sessionToken"] + } + }, + "uniqueConstraints": {}, + "checkConstraint": {} + }, + "user": { + "name": "user", + "columns": { + "id": { + "name": "id", + "type": "varchar(64)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "email": { + "name": "email", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "emailVerified": { + "name": "emailVerified", + "type": "timestamp", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "image": { + "name": "image", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "password": { + "name": "password", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "salt": { + "name": "salt", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "provider": { + "name": "provider", + "type": "varchar(64)", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "'credentials'" + }, + "homeBoardId": { + "name": "homeBoardId", + "type": "varchar(64)", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "colorScheme": { + "name": "colorScheme", + "type": "varchar(5)", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "'dark'" + }, + "firstDayOfWeek": { + "name": "firstDayOfWeek", + "type": "tinyint", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": 1 + }, + "pingIconsEnabled": { + "name": "pingIconsEnabled", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": false + } + }, + "indexes": {}, + "foreignKeys": { + "user_homeBoardId_board_id_fk": { + "name": "user_homeBoardId_board_id_fk", + "tableFrom": "user", + "tableTo": "board", + "columnsFrom": ["homeBoardId"], + "columnsTo": ["id"], + "onDelete": "set null", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": { + "user_id": { + "name": "user_id", + "columns": ["id"] + } + }, + "uniqueConstraints": {}, + "checkConstraint": {} + }, + "verificationToken": { + "name": "verificationToken", + "columns": { + "identifier": { + "name": "identifier", + "type": "varchar(64)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "token": { + "name": "token", + "type": "varchar(512)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "expires": { + "name": "expires", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": { + "verificationToken_identifier_token_pk": { + "name": "verificationToken_identifier_token_pk", + "columns": ["identifier", "token"] + } + }, + "uniqueConstraints": {}, + "checkConstraint": {} + } + }, + "views": {}, + "_meta": { + "schemas": {}, + "tables": {}, + "columns": {} + }, + "internal": { + "tables": {}, + "indexes": {} + } +} diff --git a/packages/db/migrations/mysql/meta/_journal.json b/packages/db/migrations/mysql/meta/_journal.json index dacc6be5a..7ac6a43d8 100644 --- a/packages/db/migrations/mysql/meta/_journal.json +++ b/packages/db/migrations/mysql/meta/_journal.json @@ -78,6 +78,27 @@ "when": 1728142597094, "tag": "0010_melted_pestilence", "breakpoints": true + }, + { + "idx": 11, + "version": "5", + "when": 1728490046896, + "tag": "0011_freezing_banshee", + "breakpoints": true + }, + { + "idx": 12, + "version": "5", + "when": 1729348221072, + "tag": "0012_abnormal_wendell_vaughn", + "breakpoints": true + }, + { + "idx": 13, + "version": "5", + "when": 1729369383739, + "tag": "0013_youthful_vulture", + "breakpoints": true } ] } diff --git a/packages/db/migrations/mysql/migrate.ts b/packages/db/migrations/mysql/migrate.ts index 50d495d00..7cb343ceb 100644 --- a/packages/db/migrations/mysql/migrate.ts +++ b/packages/db/migrations/mysql/migrate.ts @@ -3,25 +3,35 @@ import { drizzle } from "drizzle-orm/mysql2"; import { migrate } from "drizzle-orm/mysql2/migrator"; import mysql from "mysql2"; +import type { Database } from "../.."; +import * as mysqlSchema from "../../schema/mysql"; +import { seedDataAsync } from "../seed"; + const migrationsFolder = process.argv[2] ?? "."; -const mysql2 = mysql.createConnection( - process.env.DB_HOST - ? { - host: process.env.DB_HOST, - database: process.env.DB_NAME!, - port: Number(process.env.DB_PORT), - user: process.env.DB_USER, - password: process.env.DB_PASSWORD, - } - : { uri: process.env.DB_URL }, -); +const migrateAsync = async () => { + const mysql2 = mysql.createConnection( + process.env.DB_HOST + ? { + host: process.env.DB_HOST, + database: process.env.DB_NAME!, + port: Number(process.env.DB_PORT), + user: process.env.DB_USER, + password: process.env.DB_PASSWORD, + } + : { uri: process.env.DB_URL }, + ); -const db = drizzle(mysql2, { - mode: "default", -}); + const db = drizzle(mysql2, { + mode: "default", + schema: mysqlSchema, + }); -migrate(db, { migrationsFolder }) + await migrate(db, { migrationsFolder }); + await seedDataAsync(db as unknown as Database); +}; + +migrateAsync() .then(() => { console.log("Migration complete"); process.exit(0); diff --git a/packages/db/migrations/run-seed.ts b/packages/db/migrations/run-seed.ts new file mode 100644 index 000000000..7a0e346bc --- /dev/null +++ b/packages/db/migrations/run-seed.ts @@ -0,0 +1,12 @@ +import { database } from "../driver"; +import { seedDataAsync } from "./seed"; + +seedDataAsync(database) + .then(() => { + console.log("Seed complete"); + process.exit(0); + }) + .catch((err) => { + console.log("Seed failed\n\t", err); + process.exit(1); + }); diff --git a/packages/db/migrations/seed.ts b/packages/db/migrations/seed.ts new file mode 100644 index 000000000..ab4a865e7 --- /dev/null +++ b/packages/db/migrations/seed.ts @@ -0,0 +1,52 @@ +import SuperJSON from "superjson"; + +import { everyoneGroup } from "@homarr/definitions"; +import { defaultServerSettings, defaultServerSettingsKeys } from "@homarr/server-settings"; + +import { createId, eq } from ".."; +import type { Database } from ".."; +import { groups } from "../schema/mysql"; +import { serverSettings } from "../schema/sqlite"; + +export const seedDataAsync = async (db: Database) => { + await seedEveryoneGroupAsync(db); + await seedServerSettingsAsync(db); +}; + +const seedEveryoneGroupAsync = async (db: Database) => { + const group = await db.query.groups.findFirst({ + where: eq(groups.name, everyoneGroup), + }); + + if (group) { + console.log("Skipping seeding of group 'everyone' as it already exists"); + return; + } + + await db.insert(groups).values({ + id: createId(), + name: everyoneGroup, + }); + console.log("Created group 'everyone' through seed"); +}; + +const seedServerSettingsAsync = async (db: Database) => { + const serverSettingsData = await db.query.serverSettings.findMany(); + let insertedSettingsCount = 0; + + for (const settingsKey of defaultServerSettingsKeys) { + if (serverSettingsData.some((setting) => setting.settingKey === settingsKey)) { + return; + } + + await db.insert(serverSettings).values({ + settingKey: settingsKey, + value: SuperJSON.stringify(defaultServerSettings[settingsKey]), + }); + insertedSettingsCount++; + } + + if (insertedSettingsCount > 0) { + console.info(`Inserted ${insertedSettingsCount} missing settings`); + } +}; diff --git a/packages/db/migrations/sqlite/0011_classy_angel.sql b/packages/db/migrations/sqlite/0011_classy_angel.sql new file mode 100644 index 000000000..10f3d6bf5 --- /dev/null +++ b/packages/db/migrations/sqlite/0011_classy_angel.sql @@ -0,0 +1 @@ +ALTER TABLE `user` ADD `pingIconsEnabled` integer DEFAULT false NOT NULL; \ No newline at end of file diff --git a/packages/db/migrations/sqlite/0012_ambiguous_black_panther.sql b/packages/db/migrations/sqlite/0012_ambiguous_black_panther.sql new file mode 100644 index 000000000..edcfca536 --- /dev/null +++ b/packages/db/migrations/sqlite/0012_ambiguous_black_panther.sql @@ -0,0 +1,21 @@ +PRAGMA foreign_keys=OFF;--> statement-breakpoint +CREATE TABLE `__new_user` ( + `id` text PRIMARY KEY NOT NULL, + `name` text, + `email` text, + `emailVerified` integer, + `image` text, + `password` text, + `salt` text, + `provider` text DEFAULT 'credentials' NOT NULL, + `homeBoardId` text, + `colorScheme` text DEFAULT 'dark' NOT NULL, + `firstDayOfWeek` integer DEFAULT 1 NOT NULL, + `pingIconsEnabled` integer DEFAULT false NOT NULL, + FOREIGN KEY (`homeBoardId`) REFERENCES `board`(`id`) ON UPDATE no action ON DELETE set null +); +--> statement-breakpoint +INSERT INTO `__new_user`("id", "name", "email", "emailVerified", "image", "password", "salt", "provider", "homeBoardId", "colorScheme", "firstDayOfWeek", "pingIconsEnabled") SELECT "id", "name", "email", "emailVerified", "image", "password", "salt", "provider", "homeBoardId", "colorScheme", "firstDayOfWeek", "pingIconsEnabled" FROM `user`;--> statement-breakpoint +DROP TABLE `user`;--> statement-breakpoint +ALTER TABLE `__new_user` RENAME TO `user`;--> statement-breakpoint +PRAGMA foreign_keys=ON; \ No newline at end of file diff --git a/packages/db/migrations/sqlite/0013_faithful_hex.sql b/packages/db/migrations/sqlite/0013_faithful_hex.sql new file mode 100644 index 000000000..d2632a0dd --- /dev/null +++ b/packages/db/migrations/sqlite/0013_faithful_hex.sql @@ -0,0 +1 @@ +CREATE UNIQUE INDEX `group_name_unique` ON `group` (`name`); \ No newline at end of file diff --git a/packages/db/migrations/sqlite/meta/0011_snapshot.json b/packages/db/migrations/sqlite/meta/0011_snapshot.json new file mode 100644 index 000000000..b3bf026e0 --- /dev/null +++ b/packages/db/migrations/sqlite/meta/0011_snapshot.json @@ -0,0 +1,1430 @@ +{ + "version": "6", + "dialect": "sqlite", + "id": "7c2e4a9e-350a-4551-90d9-bdfa90db58ee", + "prevId": "52be1539-1b06-4581-8347-ce2102e782c7", + "tables": { + "account": { + "name": "account", + "columns": { + "userId": { + "name": "userId", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "type": { + "name": "type", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "provider": { + "name": "provider", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "providerAccountId": { + "name": "providerAccountId", + "type": "text", + "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": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "token_type": { + "name": "token_type", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "scope": { + "name": "scope", + "type": "text", + "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": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + } + }, + "indexes": { + "userId_idx": { + "name": "userId_idx", + "columns": ["userId"], + "isUnique": false + } + }, + "foreignKeys": { + "account_userId_user_id_fk": { + "name": "account_userId_user_id_fk", + "tableFrom": "account", + "tableTo": "user", + "columnsFrom": ["userId"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": { + "account_provider_providerAccountId_pk": { + "columns": ["provider", "providerAccountId"], + "name": "account_provider_providerAccountId_pk" + } + }, + "uniqueConstraints": {} + }, + "apiKey": { + "name": "apiKey", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "apiKey": { + "name": "apiKey", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "salt": { + "name": "salt", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "userId": { + "name": "userId", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": { + "apiKey_userId_user_id_fk": { + "name": "apiKey_userId_user_id_fk", + "tableFrom": "apiKey", + "tableTo": "user", + "columnsFrom": ["userId"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {} + }, + "app": { + "name": "app", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "icon_url": { + "name": "icon_url", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "href": { + "name": "href", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {} + }, + "boardGroupPermission": { + "name": "boardGroupPermission", + "columns": { + "board_id": { + "name": "board_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "group_id": { + "name": "group_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "permission": { + "name": "permission", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": { + "boardGroupPermission_board_id_board_id_fk": { + "name": "boardGroupPermission_board_id_board_id_fk", + "tableFrom": "boardGroupPermission", + "tableTo": "board", + "columnsFrom": ["board_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "boardGroupPermission_group_id_group_id_fk": { + "name": "boardGroupPermission_group_id_group_id_fk", + "tableFrom": "boardGroupPermission", + "tableTo": "group", + "columnsFrom": ["group_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": { + "boardGroupPermission_board_id_group_id_permission_pk": { + "columns": ["board_id", "group_id", "permission"], + "name": "boardGroupPermission_board_id_group_id_permission_pk" + } + }, + "uniqueConstraints": {} + }, + "boardUserPermission": { + "name": "boardUserPermission", + "columns": { + "board_id": { + "name": "board_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "permission": { + "name": "permission", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": { + "boardUserPermission_board_id_board_id_fk": { + "name": "boardUserPermission_board_id_board_id_fk", + "tableFrom": "boardUserPermission", + "tableTo": "board", + "columnsFrom": ["board_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "boardUserPermission_user_id_user_id_fk": { + "name": "boardUserPermission_user_id_user_id_fk", + "tableFrom": "boardUserPermission", + "tableTo": "user", + "columnsFrom": ["user_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": { + "boardUserPermission_board_id_user_id_permission_pk": { + "columns": ["board_id", "user_id", "permission"], + "name": "boardUserPermission_board_id_user_id_permission_pk" + } + }, + "uniqueConstraints": {} + }, + "board": { + "name": "board", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "is_public": { + "name": "is_public", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": false + }, + "creator_id": { + "name": "creator_id", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "page_title": { + "name": "page_title", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "meta_title": { + "name": "meta_title", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "logo_image_url": { + "name": "logo_image_url", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "favicon_image_url": { + "name": "favicon_image_url", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "background_image_url": { + "name": "background_image_url", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "background_image_attachment": { + "name": "background_image_attachment", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "'fixed'" + }, + "background_image_repeat": { + "name": "background_image_repeat", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "'no-repeat'" + }, + "background_image_size": { + "name": "background_image_size", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "'cover'" + }, + "primary_color": { + "name": "primary_color", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "'#fa5252'" + }, + "secondary_color": { + "name": "secondary_color", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "'#fd7e14'" + }, + "opacity": { + "name": "opacity", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": 100 + }, + "custom_css": { + "name": "custom_css", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "column_count": { + "name": "column_count", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": 10 + } + }, + "indexes": { + "board_name_unique": { + "name": "board_name_unique", + "columns": ["name"], + "isUnique": true + } + }, + "foreignKeys": { + "board_creator_id_user_id_fk": { + "name": "board_creator_id_user_id_fk", + "tableFrom": "board", + "tableTo": "user", + "columnsFrom": ["creator_id"], + "columnsTo": ["id"], + "onDelete": "set null", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {} + }, + "groupMember": { + "name": "groupMember", + "columns": { + "groupId": { + "name": "groupId", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "userId": { + "name": "userId", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": { + "groupMember_groupId_group_id_fk": { + "name": "groupMember_groupId_group_id_fk", + "tableFrom": "groupMember", + "tableTo": "group", + "columnsFrom": ["groupId"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "groupMember_userId_user_id_fk": { + "name": "groupMember_userId_user_id_fk", + "tableFrom": "groupMember", + "tableTo": "user", + "columnsFrom": ["userId"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": { + "groupMember_groupId_userId_pk": { + "columns": ["groupId", "userId"], + "name": "groupMember_groupId_userId_pk" + } + }, + "uniqueConstraints": {} + }, + "groupPermission": { + "name": "groupPermission", + "columns": { + "groupId": { + "name": "groupId", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "permission": { + "name": "permission", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": { + "groupPermission_groupId_group_id_fk": { + "name": "groupPermission_groupId_group_id_fk", + "tableFrom": "groupPermission", + "tableTo": "group", + "columnsFrom": ["groupId"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {} + }, + "group": { + "name": "group", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "owner_id": { + "name": "owner_id", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": { + "group_owner_id_user_id_fk": { + "name": "group_owner_id_user_id_fk", + "tableFrom": "group", + "tableTo": "user", + "columnsFrom": ["owner_id"], + "columnsTo": ["id"], + "onDelete": "set null", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {} + }, + "iconRepository": { + "name": "iconRepository", + "columns": { + "iconRepository_id": { + "name": "iconRepository_id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "iconRepository_slug": { + "name": "iconRepository_slug", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {} + }, + "icon": { + "name": "icon", + "columns": { + "icon_id": { + "name": "icon_id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "icon_name": { + "name": "icon_name", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "icon_url": { + "name": "icon_url", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "icon_checksum": { + "name": "icon_checksum", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "iconRepository_id": { + "name": "iconRepository_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": { + "icon_iconRepository_id_iconRepository_iconRepository_id_fk": { + "name": "icon_iconRepository_id_iconRepository_iconRepository_id_fk", + "tableFrom": "icon", + "tableTo": "iconRepository", + "columnsFrom": ["iconRepository_id"], + "columnsTo": ["iconRepository_id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {} + }, + "integrationGroupPermissions": { + "name": "integrationGroupPermissions", + "columns": { + "integration_id": { + "name": "integration_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "group_id": { + "name": "group_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "permission": { + "name": "permission", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": { + "integrationGroupPermissions_integration_id_integration_id_fk": { + "name": "integrationGroupPermissions_integration_id_integration_id_fk", + "tableFrom": "integrationGroupPermissions", + "tableTo": "integration", + "columnsFrom": ["integration_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "integrationGroupPermissions_group_id_group_id_fk": { + "name": "integrationGroupPermissions_group_id_group_id_fk", + "tableFrom": "integrationGroupPermissions", + "tableTo": "group", + "columnsFrom": ["group_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": { + "integrationGroupPermissions_integration_id_group_id_permission_pk": { + "columns": ["integration_id", "group_id", "permission"], + "name": "integrationGroupPermissions_integration_id_group_id_permission_pk" + } + }, + "uniqueConstraints": {} + }, + "integration_item": { + "name": "integration_item", + "columns": { + "item_id": { + "name": "item_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "integration_id": { + "name": "integration_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": { + "integration_item_item_id_item_id_fk": { + "name": "integration_item_item_id_item_id_fk", + "tableFrom": "integration_item", + "tableTo": "item", + "columnsFrom": ["item_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "integration_item_integration_id_integration_id_fk": { + "name": "integration_item_integration_id_integration_id_fk", + "tableFrom": "integration_item", + "tableTo": "integration", + "columnsFrom": ["integration_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": { + "integration_item_item_id_integration_id_pk": { + "columns": ["item_id", "integration_id"], + "name": "integration_item_item_id_integration_id_pk" + } + }, + "uniqueConstraints": {} + }, + "integrationSecret": { + "name": "integrationSecret", + "columns": { + "kind": { + "name": "kind", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "value": { + "name": "value", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "updated_at": { + "name": "updated_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "integration_id": { + "name": "integration_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": { + "integration_secret__kind_idx": { + "name": "integration_secret__kind_idx", + "columns": ["kind"], + "isUnique": false + }, + "integration_secret__updated_at_idx": { + "name": "integration_secret__updated_at_idx", + "columns": ["updated_at"], + "isUnique": false + } + }, + "foreignKeys": { + "integrationSecret_integration_id_integration_id_fk": { + "name": "integrationSecret_integration_id_integration_id_fk", + "tableFrom": "integrationSecret", + "tableTo": "integration", + "columnsFrom": ["integration_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": { + "integrationSecret_integration_id_kind_pk": { + "columns": ["integration_id", "kind"], + "name": "integrationSecret_integration_id_kind_pk" + } + }, + "uniqueConstraints": {} + }, + "integrationUserPermission": { + "name": "integrationUserPermission", + "columns": { + "integration_id": { + "name": "integration_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "permission": { + "name": "permission", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": { + "integrationUserPermission_integration_id_integration_id_fk": { + "name": "integrationUserPermission_integration_id_integration_id_fk", + "tableFrom": "integrationUserPermission", + "tableTo": "integration", + "columnsFrom": ["integration_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "integrationUserPermission_user_id_user_id_fk": { + "name": "integrationUserPermission_user_id_user_id_fk", + "tableFrom": "integrationUserPermission", + "tableTo": "user", + "columnsFrom": ["user_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": { + "integrationUserPermission_integration_id_user_id_permission_pk": { + "columns": ["integration_id", "user_id", "permission"], + "name": "integrationUserPermission_integration_id_user_id_permission_pk" + } + }, + "uniqueConstraints": {} + }, + "integration": { + "name": "integration", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "url": { + "name": "url", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "kind": { + "name": "kind", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": { + "integration__kind_idx": { + "name": "integration__kind_idx", + "columns": ["kind"], + "isUnique": false + } + }, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {} + }, + "invite": { + "name": "invite", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "token": { + "name": "token", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "expiration_date": { + "name": "expiration_date", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "creator_id": { + "name": "creator_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": { + "invite_token_unique": { + "name": "invite_token_unique", + "columns": ["token"], + "isUnique": true + } + }, + "foreignKeys": { + "invite_creator_id_user_id_fk": { + "name": "invite_creator_id_user_id_fk", + "tableFrom": "invite", + "tableTo": "user", + "columnsFrom": ["creator_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {} + }, + "item": { + "name": "item", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "section_id": { + "name": "section_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "kind": { + "name": "kind", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "x_offset": { + "name": "x_offset", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "y_offset": { + "name": "y_offset", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "width": { + "name": "width", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "height": { + "name": "height", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "options": { + "name": "options", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "'{\"json\": {}}'" + }, + "advanced_options": { + "name": "advanced_options", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "'{\"json\": {}}'" + } + }, + "indexes": {}, + "foreignKeys": { + "item_section_id_section_id_fk": { + "name": "item_section_id_section_id_fk", + "tableFrom": "item", + "tableTo": "section", + "columnsFrom": ["section_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {} + }, + "search_engine": { + "name": "search_engine", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "icon_url": { + "name": "icon_url", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "short": { + "name": "short", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "url_template": { + "name": "url_template", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {} + }, + "section": { + "name": "section", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "board_id": { + "name": "board_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "kind": { + "name": "kind", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "x_offset": { + "name": "x_offset", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "y_offset": { + "name": "y_offset", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "width": { + "name": "width", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "height": { + "name": "height", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "parent_section_id": { + "name": "parent_section_id", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": { + "section_board_id_board_id_fk": { + "name": "section_board_id_board_id_fk", + "tableFrom": "section", + "tableTo": "board", + "columnsFrom": ["board_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "section_parent_section_id_section_id_fk": { + "name": "section_parent_section_id_section_id_fk", + "tableFrom": "section", + "tableTo": "section", + "columnsFrom": ["parent_section_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {} + }, + "serverSetting": { + "name": "serverSetting", + "columns": { + "key": { + "name": "key", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "value": { + "name": "value", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "'{\"json\": {}}'" + } + }, + "indexes": { + "serverSetting_key_unique": { + "name": "serverSetting_key_unique", + "columns": ["key"], + "isUnique": true + } + }, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {} + }, + "session": { + "name": "session", + "columns": { + "sessionToken": { + "name": "sessionToken", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "userId": { + "name": "userId", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "expires": { + "name": "expires", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": { + "user_id_idx": { + "name": "user_id_idx", + "columns": ["userId"], + "isUnique": false + } + }, + "foreignKeys": { + "session_userId_user_id_fk": { + "name": "session_userId_user_id_fk", + "tableFrom": "session", + "tableTo": "user", + "columnsFrom": ["userId"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {} + }, + "user": { + "name": "user", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "email": { + "name": "email", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "emailVerified": { + "name": "emailVerified", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "image": { + "name": "image", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "password": { + "name": "password", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "salt": { + "name": "salt", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "provider": { + "name": "provider", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "'credentials'" + }, + "homeBoardId": { + "name": "homeBoardId", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "colorScheme": { + "name": "colorScheme", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "'auto'" + }, + "firstDayOfWeek": { + "name": "firstDayOfWeek", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": 1 + }, + "pingIconsEnabled": { + "name": "pingIconsEnabled", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": false + } + }, + "indexes": {}, + "foreignKeys": { + "user_homeBoardId_board_id_fk": { + "name": "user_homeBoardId_board_id_fk", + "tableFrom": "user", + "tableTo": "board", + "columnsFrom": ["homeBoardId"], + "columnsTo": ["id"], + "onDelete": "set null", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {} + }, + "verificationToken": { + "name": "verificationToken", + "columns": { + "identifier": { + "name": "identifier", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "token": { + "name": "token", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "expires": { + "name": "expires", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": { + "verificationToken_identifier_token_pk": { + "columns": ["identifier", "token"], + "name": "verificationToken_identifier_token_pk" + } + }, + "uniqueConstraints": {} + } + }, + "enums": {}, + "_meta": { + "schemas": {}, + "tables": {}, + "columns": {} + }, + "internal": { + "indexes": {} + } +} diff --git a/packages/db/migrations/sqlite/meta/0012_snapshot.json b/packages/db/migrations/sqlite/meta/0012_snapshot.json new file mode 100644 index 000000000..6efb386a6 --- /dev/null +++ b/packages/db/migrations/sqlite/meta/0012_snapshot.json @@ -0,0 +1,1455 @@ +{ + "version": "6", + "dialect": "sqlite", + "id": "20b3ebeb-a111-4576-b530-a2634d154132", + "prevId": "7c2e4a9e-350a-4551-90d9-bdfa90db58ee", + "tables": { + "account": { + "name": "account", + "columns": { + "userId": { + "name": "userId", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "type": { + "name": "type", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "provider": { + "name": "provider", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "providerAccountId": { + "name": "providerAccountId", + "type": "text", + "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": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "token_type": { + "name": "token_type", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "scope": { + "name": "scope", + "type": "text", + "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": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + } + }, + "indexes": { + "userId_idx": { + "name": "userId_idx", + "columns": ["userId"], + "isUnique": false + } + }, + "foreignKeys": { + "account_userId_user_id_fk": { + "name": "account_userId_user_id_fk", + "tableFrom": "account", + "tableTo": "user", + "columnsFrom": ["userId"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": { + "account_provider_providerAccountId_pk": { + "columns": ["provider", "providerAccountId"], + "name": "account_provider_providerAccountId_pk" + } + }, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "apiKey": { + "name": "apiKey", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "apiKey": { + "name": "apiKey", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "salt": { + "name": "salt", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "userId": { + "name": "userId", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": { + "apiKey_userId_user_id_fk": { + "name": "apiKey_userId_user_id_fk", + "tableFrom": "apiKey", + "tableTo": "user", + "columnsFrom": ["userId"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "app": { + "name": "app", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "icon_url": { + "name": "icon_url", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "href": { + "name": "href", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "boardGroupPermission": { + "name": "boardGroupPermission", + "columns": { + "board_id": { + "name": "board_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "group_id": { + "name": "group_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "permission": { + "name": "permission", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": { + "boardGroupPermission_board_id_board_id_fk": { + "name": "boardGroupPermission_board_id_board_id_fk", + "tableFrom": "boardGroupPermission", + "tableTo": "board", + "columnsFrom": ["board_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "boardGroupPermission_group_id_group_id_fk": { + "name": "boardGroupPermission_group_id_group_id_fk", + "tableFrom": "boardGroupPermission", + "tableTo": "group", + "columnsFrom": ["group_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": { + "boardGroupPermission_board_id_group_id_permission_pk": { + "columns": ["board_id", "group_id", "permission"], + "name": "boardGroupPermission_board_id_group_id_permission_pk" + } + }, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "boardUserPermission": { + "name": "boardUserPermission", + "columns": { + "board_id": { + "name": "board_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "permission": { + "name": "permission", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": { + "boardUserPermission_board_id_board_id_fk": { + "name": "boardUserPermission_board_id_board_id_fk", + "tableFrom": "boardUserPermission", + "tableTo": "board", + "columnsFrom": ["board_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "boardUserPermission_user_id_user_id_fk": { + "name": "boardUserPermission_user_id_user_id_fk", + "tableFrom": "boardUserPermission", + "tableTo": "user", + "columnsFrom": ["user_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": { + "boardUserPermission_board_id_user_id_permission_pk": { + "columns": ["board_id", "user_id", "permission"], + "name": "boardUserPermission_board_id_user_id_permission_pk" + } + }, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "board": { + "name": "board", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "is_public": { + "name": "is_public", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": false + }, + "creator_id": { + "name": "creator_id", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "page_title": { + "name": "page_title", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "meta_title": { + "name": "meta_title", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "logo_image_url": { + "name": "logo_image_url", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "favicon_image_url": { + "name": "favicon_image_url", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "background_image_url": { + "name": "background_image_url", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "background_image_attachment": { + "name": "background_image_attachment", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "'fixed'" + }, + "background_image_repeat": { + "name": "background_image_repeat", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "'no-repeat'" + }, + "background_image_size": { + "name": "background_image_size", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "'cover'" + }, + "primary_color": { + "name": "primary_color", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "'#fa5252'" + }, + "secondary_color": { + "name": "secondary_color", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "'#fd7e14'" + }, + "opacity": { + "name": "opacity", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": 100 + }, + "custom_css": { + "name": "custom_css", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "column_count": { + "name": "column_count", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": 10 + } + }, + "indexes": { + "board_name_unique": { + "name": "board_name_unique", + "columns": ["name"], + "isUnique": true + } + }, + "foreignKeys": { + "board_creator_id_user_id_fk": { + "name": "board_creator_id_user_id_fk", + "tableFrom": "board", + "tableTo": "user", + "columnsFrom": ["creator_id"], + "columnsTo": ["id"], + "onDelete": "set null", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "groupMember": { + "name": "groupMember", + "columns": { + "groupId": { + "name": "groupId", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "userId": { + "name": "userId", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": { + "groupMember_groupId_group_id_fk": { + "name": "groupMember_groupId_group_id_fk", + "tableFrom": "groupMember", + "tableTo": "group", + "columnsFrom": ["groupId"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "groupMember_userId_user_id_fk": { + "name": "groupMember_userId_user_id_fk", + "tableFrom": "groupMember", + "tableTo": "user", + "columnsFrom": ["userId"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": { + "groupMember_groupId_userId_pk": { + "columns": ["groupId", "userId"], + "name": "groupMember_groupId_userId_pk" + } + }, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "groupPermission": { + "name": "groupPermission", + "columns": { + "groupId": { + "name": "groupId", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "permission": { + "name": "permission", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": { + "groupPermission_groupId_group_id_fk": { + "name": "groupPermission_groupId_group_id_fk", + "tableFrom": "groupPermission", + "tableTo": "group", + "columnsFrom": ["groupId"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "group": { + "name": "group", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "owner_id": { + "name": "owner_id", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": { + "group_owner_id_user_id_fk": { + "name": "group_owner_id_user_id_fk", + "tableFrom": "group", + "tableTo": "user", + "columnsFrom": ["owner_id"], + "columnsTo": ["id"], + "onDelete": "set null", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "iconRepository": { + "name": "iconRepository", + "columns": { + "iconRepository_id": { + "name": "iconRepository_id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "iconRepository_slug": { + "name": "iconRepository_slug", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "icon": { + "name": "icon", + "columns": { + "icon_id": { + "name": "icon_id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "icon_name": { + "name": "icon_name", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "icon_url": { + "name": "icon_url", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "icon_checksum": { + "name": "icon_checksum", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "iconRepository_id": { + "name": "iconRepository_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": { + "icon_iconRepository_id_iconRepository_iconRepository_id_fk": { + "name": "icon_iconRepository_id_iconRepository_iconRepository_id_fk", + "tableFrom": "icon", + "tableTo": "iconRepository", + "columnsFrom": ["iconRepository_id"], + "columnsTo": ["iconRepository_id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "integrationGroupPermissions": { + "name": "integrationGroupPermissions", + "columns": { + "integration_id": { + "name": "integration_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "group_id": { + "name": "group_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "permission": { + "name": "permission", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": { + "integrationGroupPermissions_integration_id_integration_id_fk": { + "name": "integrationGroupPermissions_integration_id_integration_id_fk", + "tableFrom": "integrationGroupPermissions", + "tableTo": "integration", + "columnsFrom": ["integration_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "integrationGroupPermissions_group_id_group_id_fk": { + "name": "integrationGroupPermissions_group_id_group_id_fk", + "tableFrom": "integrationGroupPermissions", + "tableTo": "group", + "columnsFrom": ["group_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": { + "integrationGroupPermissions_integration_id_group_id_permission_pk": { + "columns": ["integration_id", "group_id", "permission"], + "name": "integrationGroupPermissions_integration_id_group_id_permission_pk" + } + }, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "integration_item": { + "name": "integration_item", + "columns": { + "item_id": { + "name": "item_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "integration_id": { + "name": "integration_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": { + "integration_item_item_id_item_id_fk": { + "name": "integration_item_item_id_item_id_fk", + "tableFrom": "integration_item", + "tableTo": "item", + "columnsFrom": ["item_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "integration_item_integration_id_integration_id_fk": { + "name": "integration_item_integration_id_integration_id_fk", + "tableFrom": "integration_item", + "tableTo": "integration", + "columnsFrom": ["integration_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": { + "integration_item_item_id_integration_id_pk": { + "columns": ["item_id", "integration_id"], + "name": "integration_item_item_id_integration_id_pk" + } + }, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "integrationSecret": { + "name": "integrationSecret", + "columns": { + "kind": { + "name": "kind", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "value": { + "name": "value", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "updated_at": { + "name": "updated_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "integration_id": { + "name": "integration_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": { + "integration_secret__kind_idx": { + "name": "integration_secret__kind_idx", + "columns": ["kind"], + "isUnique": false + }, + "integration_secret__updated_at_idx": { + "name": "integration_secret__updated_at_idx", + "columns": ["updated_at"], + "isUnique": false + } + }, + "foreignKeys": { + "integrationSecret_integration_id_integration_id_fk": { + "name": "integrationSecret_integration_id_integration_id_fk", + "tableFrom": "integrationSecret", + "tableTo": "integration", + "columnsFrom": ["integration_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": { + "integrationSecret_integration_id_kind_pk": { + "columns": ["integration_id", "kind"], + "name": "integrationSecret_integration_id_kind_pk" + } + }, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "integrationUserPermission": { + "name": "integrationUserPermission", + "columns": { + "integration_id": { + "name": "integration_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "permission": { + "name": "permission", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": { + "integrationUserPermission_integration_id_integration_id_fk": { + "name": "integrationUserPermission_integration_id_integration_id_fk", + "tableFrom": "integrationUserPermission", + "tableTo": "integration", + "columnsFrom": ["integration_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "integrationUserPermission_user_id_user_id_fk": { + "name": "integrationUserPermission_user_id_user_id_fk", + "tableFrom": "integrationUserPermission", + "tableTo": "user", + "columnsFrom": ["user_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": { + "integrationUserPermission_integration_id_user_id_permission_pk": { + "columns": ["integration_id", "user_id", "permission"], + "name": "integrationUserPermission_integration_id_user_id_permission_pk" + } + }, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "integration": { + "name": "integration", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "url": { + "name": "url", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "kind": { + "name": "kind", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": { + "integration__kind_idx": { + "name": "integration__kind_idx", + "columns": ["kind"], + "isUnique": false + } + }, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "invite": { + "name": "invite", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "token": { + "name": "token", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "expiration_date": { + "name": "expiration_date", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "creator_id": { + "name": "creator_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": { + "invite_token_unique": { + "name": "invite_token_unique", + "columns": ["token"], + "isUnique": true + } + }, + "foreignKeys": { + "invite_creator_id_user_id_fk": { + "name": "invite_creator_id_user_id_fk", + "tableFrom": "invite", + "tableTo": "user", + "columnsFrom": ["creator_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "item": { + "name": "item", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "section_id": { + "name": "section_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "kind": { + "name": "kind", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "x_offset": { + "name": "x_offset", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "y_offset": { + "name": "y_offset", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "width": { + "name": "width", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "height": { + "name": "height", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "options": { + "name": "options", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "'{\"json\": {}}'" + }, + "advanced_options": { + "name": "advanced_options", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "'{\"json\": {}}'" + } + }, + "indexes": {}, + "foreignKeys": { + "item_section_id_section_id_fk": { + "name": "item_section_id_section_id_fk", + "tableFrom": "item", + "tableTo": "section", + "columnsFrom": ["section_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "search_engine": { + "name": "search_engine", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "icon_url": { + "name": "icon_url", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "short": { + "name": "short", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "url_template": { + "name": "url_template", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "section": { + "name": "section", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "board_id": { + "name": "board_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "kind": { + "name": "kind", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "x_offset": { + "name": "x_offset", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "y_offset": { + "name": "y_offset", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "width": { + "name": "width", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "height": { + "name": "height", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "parent_section_id": { + "name": "parent_section_id", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": { + "section_board_id_board_id_fk": { + "name": "section_board_id_board_id_fk", + "tableFrom": "section", + "tableTo": "board", + "columnsFrom": ["board_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "section_parent_section_id_section_id_fk": { + "name": "section_parent_section_id_section_id_fk", + "tableFrom": "section", + "tableTo": "section", + "columnsFrom": ["parent_section_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "serverSetting": { + "name": "serverSetting", + "columns": { + "key": { + "name": "key", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "value": { + "name": "value", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "'{\"json\": {}}'" + } + }, + "indexes": { + "serverSetting_key_unique": { + "name": "serverSetting_key_unique", + "columns": ["key"], + "isUnique": true + } + }, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "session": { + "name": "session", + "columns": { + "sessionToken": { + "name": "sessionToken", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "userId": { + "name": "userId", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "expires": { + "name": "expires", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": { + "user_id_idx": { + "name": "user_id_idx", + "columns": ["userId"], + "isUnique": false + } + }, + "foreignKeys": { + "session_userId_user_id_fk": { + "name": "session_userId_user_id_fk", + "tableFrom": "session", + "tableTo": "user", + "columnsFrom": ["userId"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "user": { + "name": "user", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "email": { + "name": "email", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "emailVerified": { + "name": "emailVerified", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "image": { + "name": "image", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "password": { + "name": "password", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "salt": { + "name": "salt", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "provider": { + "name": "provider", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "'credentials'" + }, + "homeBoardId": { + "name": "homeBoardId", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "colorScheme": { + "name": "colorScheme", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "'dark'" + }, + "firstDayOfWeek": { + "name": "firstDayOfWeek", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": 1 + }, + "pingIconsEnabled": { + "name": "pingIconsEnabled", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": false + } + }, + "indexes": {}, + "foreignKeys": { + "user_homeBoardId_board_id_fk": { + "name": "user_homeBoardId_board_id_fk", + "tableFrom": "user", + "tableTo": "board", + "columnsFrom": ["homeBoardId"], + "columnsTo": ["id"], + "onDelete": "set null", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "verificationToken": { + "name": "verificationToken", + "columns": { + "identifier": { + "name": "identifier", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "token": { + "name": "token", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "expires": { + "name": "expires", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": { + "verificationToken_identifier_token_pk": { + "columns": ["identifier", "token"], + "name": "verificationToken_identifier_token_pk" + } + }, + "uniqueConstraints": {}, + "checkConstraints": {} + } + }, + "views": {}, + "enums": {}, + "_meta": { + "schemas": {}, + "tables": {}, + "columns": {} + }, + "internal": { + "indexes": {} + } +} diff --git a/packages/db/migrations/sqlite/meta/0013_snapshot.json b/packages/db/migrations/sqlite/meta/0013_snapshot.json new file mode 100644 index 000000000..1dd77999c --- /dev/null +++ b/packages/db/migrations/sqlite/meta/0013_snapshot.json @@ -0,0 +1,1461 @@ +{ + "version": "6", + "dialect": "sqlite", + "id": "767f5db4-59ab-46c7-a154-4fcd9474c358", + "prevId": "20b3ebeb-a111-4576-b530-a2634d154132", + "tables": { + "account": { + "name": "account", + "columns": { + "userId": { + "name": "userId", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "type": { + "name": "type", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "provider": { + "name": "provider", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "providerAccountId": { + "name": "providerAccountId", + "type": "text", + "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": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "token_type": { + "name": "token_type", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "scope": { + "name": "scope", + "type": "text", + "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": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + } + }, + "indexes": { + "userId_idx": { + "name": "userId_idx", + "columns": ["userId"], + "isUnique": false + } + }, + "foreignKeys": { + "account_userId_user_id_fk": { + "name": "account_userId_user_id_fk", + "tableFrom": "account", + "tableTo": "user", + "columnsFrom": ["userId"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": { + "account_provider_providerAccountId_pk": { + "columns": ["provider", "providerAccountId"], + "name": "account_provider_providerAccountId_pk" + } + }, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "apiKey": { + "name": "apiKey", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "apiKey": { + "name": "apiKey", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "salt": { + "name": "salt", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "userId": { + "name": "userId", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": { + "apiKey_userId_user_id_fk": { + "name": "apiKey_userId_user_id_fk", + "tableFrom": "apiKey", + "tableTo": "user", + "columnsFrom": ["userId"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "app": { + "name": "app", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "icon_url": { + "name": "icon_url", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "href": { + "name": "href", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "boardGroupPermission": { + "name": "boardGroupPermission", + "columns": { + "board_id": { + "name": "board_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "group_id": { + "name": "group_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "permission": { + "name": "permission", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": { + "boardGroupPermission_board_id_board_id_fk": { + "name": "boardGroupPermission_board_id_board_id_fk", + "tableFrom": "boardGroupPermission", + "tableTo": "board", + "columnsFrom": ["board_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "boardGroupPermission_group_id_group_id_fk": { + "name": "boardGroupPermission_group_id_group_id_fk", + "tableFrom": "boardGroupPermission", + "tableTo": "group", + "columnsFrom": ["group_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": { + "boardGroupPermission_board_id_group_id_permission_pk": { + "columns": ["board_id", "group_id", "permission"], + "name": "boardGroupPermission_board_id_group_id_permission_pk" + } + }, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "boardUserPermission": { + "name": "boardUserPermission", + "columns": { + "board_id": { + "name": "board_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "permission": { + "name": "permission", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": { + "boardUserPermission_board_id_board_id_fk": { + "name": "boardUserPermission_board_id_board_id_fk", + "tableFrom": "boardUserPermission", + "tableTo": "board", + "columnsFrom": ["board_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "boardUserPermission_user_id_user_id_fk": { + "name": "boardUserPermission_user_id_user_id_fk", + "tableFrom": "boardUserPermission", + "tableTo": "user", + "columnsFrom": ["user_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": { + "boardUserPermission_board_id_user_id_permission_pk": { + "columns": ["board_id", "user_id", "permission"], + "name": "boardUserPermission_board_id_user_id_permission_pk" + } + }, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "board": { + "name": "board", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "is_public": { + "name": "is_public", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": false + }, + "creator_id": { + "name": "creator_id", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "page_title": { + "name": "page_title", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "meta_title": { + "name": "meta_title", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "logo_image_url": { + "name": "logo_image_url", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "favicon_image_url": { + "name": "favicon_image_url", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "background_image_url": { + "name": "background_image_url", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "background_image_attachment": { + "name": "background_image_attachment", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "'fixed'" + }, + "background_image_repeat": { + "name": "background_image_repeat", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "'no-repeat'" + }, + "background_image_size": { + "name": "background_image_size", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "'cover'" + }, + "primary_color": { + "name": "primary_color", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "'#fa5252'" + }, + "secondary_color": { + "name": "secondary_color", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "'#fd7e14'" + }, + "opacity": { + "name": "opacity", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": 100 + }, + "custom_css": { + "name": "custom_css", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "column_count": { + "name": "column_count", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": 10 + } + }, + "indexes": { + "board_name_unique": { + "name": "board_name_unique", + "columns": ["name"], + "isUnique": true + } + }, + "foreignKeys": { + "board_creator_id_user_id_fk": { + "name": "board_creator_id_user_id_fk", + "tableFrom": "board", + "tableTo": "user", + "columnsFrom": ["creator_id"], + "columnsTo": ["id"], + "onDelete": "set null", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "groupMember": { + "name": "groupMember", + "columns": { + "groupId": { + "name": "groupId", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "userId": { + "name": "userId", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": { + "groupMember_groupId_group_id_fk": { + "name": "groupMember_groupId_group_id_fk", + "tableFrom": "groupMember", + "tableTo": "group", + "columnsFrom": ["groupId"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "groupMember_userId_user_id_fk": { + "name": "groupMember_userId_user_id_fk", + "tableFrom": "groupMember", + "tableTo": "user", + "columnsFrom": ["userId"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": { + "groupMember_groupId_userId_pk": { + "columns": ["groupId", "userId"], + "name": "groupMember_groupId_userId_pk" + } + }, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "groupPermission": { + "name": "groupPermission", + "columns": { + "groupId": { + "name": "groupId", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "permission": { + "name": "permission", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": { + "groupPermission_groupId_group_id_fk": { + "name": "groupPermission_groupId_group_id_fk", + "tableFrom": "groupPermission", + "tableTo": "group", + "columnsFrom": ["groupId"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "group": { + "name": "group", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "owner_id": { + "name": "owner_id", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + } + }, + "indexes": { + "group_name_unique": { + "name": "group_name_unique", + "columns": ["name"], + "isUnique": true + } + }, + "foreignKeys": { + "group_owner_id_user_id_fk": { + "name": "group_owner_id_user_id_fk", + "tableFrom": "group", + "tableTo": "user", + "columnsFrom": ["owner_id"], + "columnsTo": ["id"], + "onDelete": "set null", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "iconRepository": { + "name": "iconRepository", + "columns": { + "iconRepository_id": { + "name": "iconRepository_id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "iconRepository_slug": { + "name": "iconRepository_slug", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "icon": { + "name": "icon", + "columns": { + "icon_id": { + "name": "icon_id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "icon_name": { + "name": "icon_name", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "icon_url": { + "name": "icon_url", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "icon_checksum": { + "name": "icon_checksum", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "iconRepository_id": { + "name": "iconRepository_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": { + "icon_iconRepository_id_iconRepository_iconRepository_id_fk": { + "name": "icon_iconRepository_id_iconRepository_iconRepository_id_fk", + "tableFrom": "icon", + "tableTo": "iconRepository", + "columnsFrom": ["iconRepository_id"], + "columnsTo": ["iconRepository_id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "integrationGroupPermissions": { + "name": "integrationGroupPermissions", + "columns": { + "integration_id": { + "name": "integration_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "group_id": { + "name": "group_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "permission": { + "name": "permission", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": { + "integrationGroupPermissions_integration_id_integration_id_fk": { + "name": "integrationGroupPermissions_integration_id_integration_id_fk", + "tableFrom": "integrationGroupPermissions", + "tableTo": "integration", + "columnsFrom": ["integration_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "integrationGroupPermissions_group_id_group_id_fk": { + "name": "integrationGroupPermissions_group_id_group_id_fk", + "tableFrom": "integrationGroupPermissions", + "tableTo": "group", + "columnsFrom": ["group_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": { + "integrationGroupPermissions_integration_id_group_id_permission_pk": { + "columns": ["integration_id", "group_id", "permission"], + "name": "integrationGroupPermissions_integration_id_group_id_permission_pk" + } + }, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "integration_item": { + "name": "integration_item", + "columns": { + "item_id": { + "name": "item_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "integration_id": { + "name": "integration_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": { + "integration_item_item_id_item_id_fk": { + "name": "integration_item_item_id_item_id_fk", + "tableFrom": "integration_item", + "tableTo": "item", + "columnsFrom": ["item_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "integration_item_integration_id_integration_id_fk": { + "name": "integration_item_integration_id_integration_id_fk", + "tableFrom": "integration_item", + "tableTo": "integration", + "columnsFrom": ["integration_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": { + "integration_item_item_id_integration_id_pk": { + "columns": ["item_id", "integration_id"], + "name": "integration_item_item_id_integration_id_pk" + } + }, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "integrationSecret": { + "name": "integrationSecret", + "columns": { + "kind": { + "name": "kind", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "value": { + "name": "value", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "updated_at": { + "name": "updated_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "integration_id": { + "name": "integration_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": { + "integration_secret__kind_idx": { + "name": "integration_secret__kind_idx", + "columns": ["kind"], + "isUnique": false + }, + "integration_secret__updated_at_idx": { + "name": "integration_secret__updated_at_idx", + "columns": ["updated_at"], + "isUnique": false + } + }, + "foreignKeys": { + "integrationSecret_integration_id_integration_id_fk": { + "name": "integrationSecret_integration_id_integration_id_fk", + "tableFrom": "integrationSecret", + "tableTo": "integration", + "columnsFrom": ["integration_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": { + "integrationSecret_integration_id_kind_pk": { + "columns": ["integration_id", "kind"], + "name": "integrationSecret_integration_id_kind_pk" + } + }, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "integrationUserPermission": { + "name": "integrationUserPermission", + "columns": { + "integration_id": { + "name": "integration_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "permission": { + "name": "permission", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": { + "integrationUserPermission_integration_id_integration_id_fk": { + "name": "integrationUserPermission_integration_id_integration_id_fk", + "tableFrom": "integrationUserPermission", + "tableTo": "integration", + "columnsFrom": ["integration_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "integrationUserPermission_user_id_user_id_fk": { + "name": "integrationUserPermission_user_id_user_id_fk", + "tableFrom": "integrationUserPermission", + "tableTo": "user", + "columnsFrom": ["user_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": { + "integrationUserPermission_integration_id_user_id_permission_pk": { + "columns": ["integration_id", "user_id", "permission"], + "name": "integrationUserPermission_integration_id_user_id_permission_pk" + } + }, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "integration": { + "name": "integration", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "url": { + "name": "url", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "kind": { + "name": "kind", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": { + "integration__kind_idx": { + "name": "integration__kind_idx", + "columns": ["kind"], + "isUnique": false + } + }, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "invite": { + "name": "invite", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "token": { + "name": "token", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "expiration_date": { + "name": "expiration_date", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "creator_id": { + "name": "creator_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": { + "invite_token_unique": { + "name": "invite_token_unique", + "columns": ["token"], + "isUnique": true + } + }, + "foreignKeys": { + "invite_creator_id_user_id_fk": { + "name": "invite_creator_id_user_id_fk", + "tableFrom": "invite", + "tableTo": "user", + "columnsFrom": ["creator_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "item": { + "name": "item", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "section_id": { + "name": "section_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "kind": { + "name": "kind", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "x_offset": { + "name": "x_offset", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "y_offset": { + "name": "y_offset", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "width": { + "name": "width", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "height": { + "name": "height", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "options": { + "name": "options", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "'{\"json\": {}}'" + }, + "advanced_options": { + "name": "advanced_options", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "'{\"json\": {}}'" + } + }, + "indexes": {}, + "foreignKeys": { + "item_section_id_section_id_fk": { + "name": "item_section_id_section_id_fk", + "tableFrom": "item", + "tableTo": "section", + "columnsFrom": ["section_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "search_engine": { + "name": "search_engine", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "icon_url": { + "name": "icon_url", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "short": { + "name": "short", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "url_template": { + "name": "url_template", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "section": { + "name": "section", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "board_id": { + "name": "board_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "kind": { + "name": "kind", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "x_offset": { + "name": "x_offset", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "y_offset": { + "name": "y_offset", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "width": { + "name": "width", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "height": { + "name": "height", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "parent_section_id": { + "name": "parent_section_id", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": { + "section_board_id_board_id_fk": { + "name": "section_board_id_board_id_fk", + "tableFrom": "section", + "tableTo": "board", + "columnsFrom": ["board_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "section_parent_section_id_section_id_fk": { + "name": "section_parent_section_id_section_id_fk", + "tableFrom": "section", + "tableTo": "section", + "columnsFrom": ["parent_section_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "serverSetting": { + "name": "serverSetting", + "columns": { + "key": { + "name": "key", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "value": { + "name": "value", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "'{\"json\": {}}'" + } + }, + "indexes": { + "serverSetting_key_unique": { + "name": "serverSetting_key_unique", + "columns": ["key"], + "isUnique": true + } + }, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "session": { + "name": "session", + "columns": { + "sessionToken": { + "name": "sessionToken", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "userId": { + "name": "userId", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "expires": { + "name": "expires", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": { + "user_id_idx": { + "name": "user_id_idx", + "columns": ["userId"], + "isUnique": false + } + }, + "foreignKeys": { + "session_userId_user_id_fk": { + "name": "session_userId_user_id_fk", + "tableFrom": "session", + "tableTo": "user", + "columnsFrom": ["userId"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "user": { + "name": "user", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "email": { + "name": "email", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "emailVerified": { + "name": "emailVerified", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "image": { + "name": "image", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "password": { + "name": "password", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "salt": { + "name": "salt", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "provider": { + "name": "provider", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "'credentials'" + }, + "homeBoardId": { + "name": "homeBoardId", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "colorScheme": { + "name": "colorScheme", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "'dark'" + }, + "firstDayOfWeek": { + "name": "firstDayOfWeek", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": 1 + }, + "pingIconsEnabled": { + "name": "pingIconsEnabled", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": false + } + }, + "indexes": {}, + "foreignKeys": { + "user_homeBoardId_board_id_fk": { + "name": "user_homeBoardId_board_id_fk", + "tableFrom": "user", + "tableTo": "board", + "columnsFrom": ["homeBoardId"], + "columnsTo": ["id"], + "onDelete": "set null", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "verificationToken": { + "name": "verificationToken", + "columns": { + "identifier": { + "name": "identifier", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "token": { + "name": "token", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "expires": { + "name": "expires", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": { + "verificationToken_identifier_token_pk": { + "columns": ["identifier", "token"], + "name": "verificationToken_identifier_token_pk" + } + }, + "uniqueConstraints": {}, + "checkConstraints": {} + } + }, + "views": {}, + "enums": {}, + "_meta": { + "schemas": {}, + "tables": {}, + "columns": {} + }, + "internal": { + "indexes": {} + } +} diff --git a/packages/db/migrations/sqlite/meta/_journal.json b/packages/db/migrations/sqlite/meta/_journal.json index 40d9bf4d0..e88a243de 100644 --- a/packages/db/migrations/sqlite/meta/_journal.json +++ b/packages/db/migrations/sqlite/meta/_journal.json @@ -78,6 +78,27 @@ "when": 1728142590232, "tag": "0010_gorgeous_stingray", "breakpoints": true + }, + { + "idx": 11, + "version": "6", + "when": 1728490026154, + "tag": "0011_classy_angel", + "breakpoints": true + }, + { + "idx": 12, + "version": "6", + "when": 1729348200091, + "tag": "0012_ambiguous_black_panther", + "breakpoints": true + }, + { + "idx": 13, + "version": "6", + "when": 1729369389386, + "tag": "0013_faithful_hex", + "breakpoints": true } ] } diff --git a/packages/db/migrations/sqlite/migrate.ts b/packages/db/migrations/sqlite/migrate.ts index abef5ea9d..47a901745 100644 --- a/packages/db/migrations/sqlite/migrate.ts +++ b/packages/db/migrations/sqlite/migrate.ts @@ -2,10 +2,27 @@ import Database from "better-sqlite3"; import { drizzle } from "drizzle-orm/better-sqlite3"; import { migrate } from "drizzle-orm/better-sqlite3/migrator"; +import { schema } from "../.."; +import { seedDataAsync } from "../seed"; + const migrationsFolder = process.argv[2] ?? "."; -const sqlite = new Database(process.env.DB_URL?.replace("file:", "")); +const migrateAsync = async () => { + const sqlite = new Database(process.env.DB_URL?.replace("file:", "")); -const db = drizzle(sqlite); + const db = drizzle(sqlite, { schema }); -migrate(db, { migrationsFolder }); + migrate(db, { migrationsFolder }); + + await seedDataAsync(db); +}; + +migrateAsync() + .then(() => { + console.log("Migration complete"); + process.exit(0); + }) + .catch((err) => { + console.log("Migration failed", err); + process.exit(1); + }); diff --git a/packages/db/package.json b/packages/db/package.json index 67ffa31ba..122226edc 100644 --- a/packages/db/package.json +++ b/packages/db/package.json @@ -21,26 +21,31 @@ "format": "prettier --check . --ignore-path ../../.gitignore", "lint": "eslint", "migration:mysql:generate": "drizzle-kit generate --config ./configs/mysql.config.ts", - "migration:mysql:run": "drizzle-kit migrate --config ./configs/mysql.config.ts", + "migration:mysql:run": "drizzle-kit migrate --config ./configs/mysql.config.ts && pnpm run seed", + "migration:mysql:drop": "drizzle-kit drop --config ./configs/mysql.config.ts", "migration:sqlite:generate": "drizzle-kit generate --config ./configs/sqlite.config.ts", - "migration:sqlite:run": "drizzle-kit migrate --config ./configs/sqlite.config.ts", + "migration:sqlite:run": "drizzle-kit migrate --config ./configs/sqlite.config.ts && pnpm run seed", + "migration:sqlite:drop": "drizzle-kit drop --config ./configs/sqlite.config.ts", "push:mysql": "drizzle-kit push --config ./configs/mysql.config.ts", "push:sqlite": "drizzle-kit push --config ./configs/sqlite.config.ts", + "seed": "pnpm with-env tsx ./migrations/run-seed.ts", "studio": "drizzle-kit studio --config ./configs/sqlite.config.ts", - "typecheck": "tsc --noEmit" + "typecheck": "tsc --noEmit", + "with-env": "dotenv -e ../../.env --" }, "prettier": "@homarr/prettier-config", "dependencies": { - "@auth/core": "^0.37.0", + "@auth/core": "^0.37.2", "@homarr/common": "workspace:^0.1.0", "@homarr/definitions": "workspace:^0.1.0", "@homarr/log": "workspace:^0.1.0", + "@homarr/server-settings": "workspace:^0.1.0", "@paralleldrive/cuid2": "^2.2.2", "@testcontainers/mysql": "^10.13.2", - "better-sqlite3": "^11.3.0", + "better-sqlite3": "^11.5.0", "dotenv": "^16.4.5", - "drizzle-kit": "^0.25.0", - "drizzle-orm": "^0.34.1", + "drizzle-kit": "^0.26.2", + "drizzle-orm": "^0.35.3", "mysql2": "3.11.3" }, "devDependencies": { @@ -49,8 +54,9 @@ "@homarr/tsconfig": "workspace:^0.1.0", "@types/better-sqlite3": "7.6.11", "dotenv-cli": "^7.4.2", - "eslint": "^9.12.0", + "eslint": "^9.13.0", "prettier": "^3.3.3", + "tsx": "4.19.1", "typescript": "^5.6.3" } } diff --git a/packages/db/schema/mysql.ts b/packages/db/schema/mysql.ts index 383ac2e5a..e5b2b050f 100644 --- a/packages/db/schema/mysql.ts +++ b/packages/db/schema/mysql.ts @@ -43,8 +43,9 @@ export const users = mysqlTable("user", { homeBoardId: varchar("homeBoardId", { length: 64 }).references((): AnyMySqlColumn => boards.id, { onDelete: "set null", }), - colorScheme: varchar("colorScheme", { length: 5 }).$type().default("auto").notNull(), + colorScheme: varchar("colorScheme", { length: 5 }).$type().default("dark").notNull(), firstDayOfWeek: tinyint("firstDayOfWeek").$type().default(1).notNull(), // Defaults to Monday + pingIconsEnabled: boolean("pingIconsEnabled").default(false).notNull(), }); export const accounts = mysqlTable( @@ -119,7 +120,7 @@ export const groupMembers = mysqlTable( export const groups = mysqlTable("group", { id: varchar("id", { length: 64 }).notNull().primaryKey(), - name: varchar("name", { length: 64 }).notNull(), + name: varchar("name", { length: 64 }).unique().notNull(), ownerId: varchar("owner_id", { length: 64 }).references(() => users.id, { onDelete: "set null", }), diff --git a/packages/db/schema/sqlite.ts b/packages/db/schema/sqlite.ts index cec5844c1..08a8b8c44 100644 --- a/packages/db/schema/sqlite.ts +++ b/packages/db/schema/sqlite.ts @@ -44,8 +44,9 @@ export const users = sqliteTable("user", { homeBoardId: text("homeBoardId").references((): AnySQLiteColumn => boards.id, { onDelete: "set null", }), - colorScheme: text("colorScheme").$type().default("auto").notNull(), + colorScheme: text("colorScheme").$type().default("dark").notNull(), firstDayOfWeek: int("firstDayOfWeek").$type().default(1).notNull(), // Defaults to Monday + pingIconsEnabled: int("pingIconsEnabled", { mode: "boolean" }).default(false).notNull(), }); export const accounts = sqliteTable( @@ -120,7 +121,7 @@ export const groupMembers = sqliteTable( export const groups = sqliteTable("group", { id: text("id").notNull().primaryKey(), - name: text("name").notNull(), + name: text("name").unique().notNull(), ownerId: text("owner_id").references(() => users.id, { onDelete: "set null", }), diff --git a/packages/definitions/package.json b/packages/definitions/package.json index 7585d0718..e58e30125 100644 --- a/packages/definitions/package.json +++ b/packages/definitions/package.json @@ -18,7 +18,8 @@ "clean": "rm -rf .turbo node_modules", "format": "prettier --check . --ignore-path ../../.gitignore", "lint": "eslint", - "typecheck": "tsc --noEmit" + "typecheck": "tsc --noEmit", + "postinstall": "tsx ./src/docs/codegen.ts" }, "prettier": "@homarr/prettier-config", "dependencies": { @@ -28,7 +29,7 @@ "@homarr/eslint-config": "workspace:^0.2.0", "@homarr/prettier-config": "workspace:^0.1.0", "@homarr/tsconfig": "workspace:^0.1.0", - "eslint": "^9.12.0", + "eslint": "^9.13.0", "typescript": "^5.6.3" } } diff --git a/packages/definitions/src/docs/codegen.ts b/packages/definitions/src/docs/codegen.ts new file mode 100644 index 000000000..9f35a3af3 --- /dev/null +++ b/packages/definitions/src/docs/codegen.ts @@ -0,0 +1,75 @@ +import fs from "fs/promises"; +import path, { dirname } from "path"; +import { fileURLToPath } from "url"; +import { XMLParser } from "fast-xml-parser"; +import { z } from "zod"; + +import { createDocumentationLink } from "./index"; + +const __filename = fileURLToPath(import.meta.url); +const __dirname = dirname(__filename); + +const removeCommonUrl = (url: string) => { + return url.replace("https://homarr.dev", ""); +}; + +const sitemapSchema = z.object({ + urlset: z.object({ + url: z.array( + z.object({ + loc: z.string(), + }), + ), + }), +}); + +const fetchSitemapAsync = async () => { + const response = await fetch(createDocumentationLink("/sitemap.xml")); + return await response.text(); +}; + +const parseXml = (sitemapXml: string) => { + const parser = new XMLParser(); + const data: unknown = parser.parse(sitemapXml); + const result = sitemapSchema.safeParse(data); + if (!result.success) { + throw new Error("Invalid sitemap schema"); + } + + return result.data; +}; + +const mapSitemapXmlToPaths = (sitemapData: z.infer) => { + return sitemapData.urlset.url.map((url) => removeCommonUrl(url.loc)); +}; + +const createSitemapPathType = (paths: string[]) => { + return "export type HomarrDocumentationPath =\n" + paths.map((path) => ` | "${path.replace(/\/$/, "")}"`).join("\n"); +}; + +const updateSitemapTypeFileAsync = async (sitemapPathType: string) => { + const content = + "// This file is auto-generated by the codegen script\n" + + "// it uses the sitemap.xml to generate the HomarrDocumentationPath type\n" + + sitemapPathType + + ";\n"; + + await fs.writeFile(path.join(__dirname, "homarr-docs-sitemap.ts"), content); +}; + +/** + * This script fetches the sitemap.xml and generates the HomarrDocumentationPath type + * which is used for typesafe documentation links + */ +// eslint-disable-next-line no-restricted-syntax +const main = async () => { + const sitemapXml = await fetchSitemapAsync(); + const sitemapData = parseXml(sitemapXml); + const paths = mapSitemapXmlToPaths(sitemapData); + // Adding sitemap as it's not in the sitemap.xml and we need it for this file + paths.push("/sitemap.xml"); + const sitemapPathType = createSitemapPathType(paths); + await updateSitemapTypeFileAsync(sitemapPathType); +}; + +void main(); diff --git a/packages/definitions/src/docs/homarr-docs-sitemap.ts b/packages/definitions/src/docs/homarr-docs-sitemap.ts new file mode 100644 index 000000000..0e4ffbd96 --- /dev/null +++ b/packages/definitions/src/docs/homarr-docs-sitemap.ts @@ -0,0 +1,191 @@ +// This file is auto-generated by the codegen script +// it uses the sitemap.xml to generate the HomarrDocumentationPath type +export type HomarrDocumentationPath = + | "/about-us" + | "/blog" + | "/blog/2023/01/11/version0.11" + | "/blog/2023/04/16/version0.12-more-widgets" + | "/blog/2023/11/10/authentication" + | "/blog/2023/12/22/updated-documentation" + | "/blog/2024/09/23/version-1.0" + | "/blog/archive" + | "/blog/authors" + | "/blog/authors/ajnart" + | "/blog/authors/manuel-rw" + | "/blog/authors/meierschlumpf" + | "/blog/authors/tagashi" + | "/blog/authors/walkx" + | "/blog/documentation-migration" + | "/blog/tags" + | "/blog/tags/authentication" + | "/blog/tags/breaking-changes" + | "/blog/tags/contributions" + | "/blog/tags/design" + | "/blog/tags/dnd" + | "/blog/tags/docs" + | "/blog/tags/documentation" + | "/blog/tags/gridstack" + | "/blog/tags/homarr" + | "/blog/tags/migration" + | "/blog/tags/notepad" + | "/blog/tags/security" + | "/blog/tags/translations" + | "/blog/tags/update" + | "/blog/tags/version" + | "/blog/translations" + | "/docs/tags" + | "/docs/tags/active-directory" + | "/docs/tags/ad-guard" + | "/docs/tags/ad-guard-home" + | "/docs/tags/administration" + | "/docs/tags/advanced" + | "/docs/tags/analytics" + | "/docs/tags/api" + | "/docs/tags/banner" + | "/docs/tags/blocking" + | "/docs/tags/board" + | "/docs/tags/boards" + | "/docs/tags/bookmark" + | "/docs/tags/caddy" + | "/docs/tags/checklist" + | "/docs/tags/code" + | "/docs/tags/community" + | "/docs/tags/configuration" + | "/docs/tags/connections" + | "/docs/tags/customization" + | "/docs/tags/data-sources" + | "/docs/tags/developer" + | "/docs/tags/development" + | "/docs/tags/dns" + | "/docs/tags/docker" + | "/docs/tags/edit-mode" + | "/docs/tags/env" + | "/docs/tags/environment-variables" + | "/docs/tags/feeds" + | "/docs/tags/getting-started" + | "/docs/tags/google" + | "/docs/tags/grafana" + | "/docs/tags/groups" + | "/docs/tags/hardware" + | "/docs/tags/health" + | "/docs/tags/help" + | "/docs/tags/icons" + | "/docs/tags/iframe" + | "/docs/tags/images" + | "/docs/tags/installation" + | "/docs/tags/integrade" + | "/docs/tags/integration" + | "/docs/tags/integrations" + | "/docs/tags/interface" + | "/docs/tags/jellyserr" + | "/docs/tags/ldap" + | "/docs/tags/links" + | "/docs/tags/lists" + | "/docs/tags/management" + | "/docs/tags/monitoring" + | "/docs/tags/news" + | "/docs/tags/notebook" + | "/docs/tags/notes" + | "/docs/tags/oidc" + | "/docs/tags/open-media-vault" + | "/docs/tags/overseerr" + | "/docs/tags/permissions" + | "/docs/tags/pi-hole" + | "/docs/tags/preferences" + | "/docs/tags/programming" + | "/docs/tags/proxmox" + | "/docs/tags/proxy" + | "/docs/tags/roles" + | "/docs/tags/rss" + | "/docs/tags/search" + | "/docs/tags/search-engines" + | "/docs/tags/security" + | "/docs/tags/seo" + | "/docs/tags/server" + | "/docs/tags/settings" + | "/docs/tags/sinkhole" + | "/docs/tags/sso" + | "/docs/tags/system" + | "/docs/tags/table" + | "/docs/tags/technical-documentation" + | "/docs/tags/text" + | "/docs/tags/theming" + | "/docs/tags/traefik" + | "/docs/tags/translations" + | "/docs/tags/unraid" + | "/docs/tags/user" + | "/docs/tags/users" + | "/docs/tags/variables" + | "/docs/tags/widgets" + | "/docs/advanced/command-line" + | "/docs/advanced/command-line/password-recovery" + | "/docs/advanced/configuration/environment-variables" + | "/docs/advanced/configuration/keyboard-shortcuts" + | "/docs/advanced/configuration/proxies-and-certificates" + | "/docs/advanced/customizations/board-customization" + | "/docs/advanced/customizations/dark-mode" + | "/docs/advanced/customizations/icons" + | "/docs/advanced/customizations/user-preferences" + | "/docs/advanced/sso" + | "/docs/category/advanced" + | "/docs/category/getting-started" + | "/docs/category/installation" + | "/docs/category/installation-1" + | "/docs/category/integrations" + | "/docs/category/management" + | "/docs/category/more" + | "/docs/category/widgets" + | "/docs/community/developer-guides" + | "/docs/community/donate" + | "/docs/community/faq" + | "/docs/community/get-in-touch" + | "/docs/community/license" + | "/docs/community/translations" + | "/docs/getting-started" + | "/docs/getting-started/after-the-installation" + | "/docs/getting-started/glossary" + | "/docs/getting-started/installation/docker" + | "/docs/getting-started/installation/easy-panel" + | "/docs/getting-started/installation/home-assistant" + | "/docs/getting-started/installation/kubernetes" + | "/docs/getting-started/installation/portainer" + | "/docs/getting-started/installation/qnap" + | "/docs/getting-started/installation/saltbox" + | "/docs/getting-started/installation/source" + | "/docs/getting-started/installation/synology" + | "/docs/getting-started/installation/truenas" + | "/docs/getting-started/installation/unraid" + | "/docs/integrations/containers" + | "/docs/integrations/dns" + | "/docs/integrations/hardware" + | "/docs/integrations/media-requester" + | "/docs/integrations/media-server" + | "/docs/integrations/servarr" + | "/docs/integrations/torrent" + | "/docs/integrations/usenet" + | "/docs/management/api" + | "/docs/management/boards" + | "/docs/management/integrations" + | "/docs/management/search-engines" + | "/docs/management/settings" + | "/docs/management/users" + | "/docs/widgets/bookmarks" + | "/docs/widgets/calendar-widget" + | "/docs/widgets/clock-widget" + | "/docs/widgets/dashdot-widget" + | "/docs/widgets/dns-hole" + | "/docs/widgets/download-speed-widget" + | "/docs/widgets/health-monitoring" + | "/docs/widgets/home-assistant" + | "/docs/widgets/iframe" + | "/docs/widgets/indexer-manager" + | "/docs/widgets/media-requests" + | "/docs/widgets/media-server" + | "/docs/widgets/notebook" + | "/docs/widgets/rss-widget" + | "/docs/widgets/torrent-widget" + | "/docs/widgets/usenet-widget" + | "/docs/widgets/video" + | "/docs/widgets/weather-widget" + | "" + | "/sitemap.xml"; diff --git a/packages/definitions/src/docs/index.ts b/packages/definitions/src/docs/index.ts new file mode 100644 index 000000000..cc6c0f515 --- /dev/null +++ b/packages/definitions/src/docs/index.ts @@ -0,0 +1,7 @@ +import type { HomarrDocumentationPath } from "./homarr-docs-sitemap"; + +const documentationBaseUrl = "https://deploy-preview-113--homarr-docs.netlify.app"; + +// Please use the method so the path can be checked! +export const createDocumentationLink = (path: HomarrDocumentationPath, hashTag?: `#${string}`) => + `${documentationBaseUrl}${path}${hashTag ?? ""}`; diff --git a/packages/definitions/src/group.ts b/packages/definitions/src/group.ts new file mode 100644 index 000000000..ebac0daa1 --- /dev/null +++ b/packages/definitions/src/group.ts @@ -0,0 +1 @@ +export const everyoneGroup = "everyone"; diff --git a/packages/definitions/src/index.ts b/packages/definitions/src/index.ts index d2dcd8e0a..20919b208 100644 --- a/packages/definitions/src/index.ts +++ b/packages/definitions/src/index.ts @@ -6,3 +6,5 @@ export * from "./permissions"; export * from "./docker"; export * from "./auth"; export * from "./user"; +export * from "./group"; +export * from "./docs"; diff --git a/packages/definitions/src/user.ts b/packages/definitions/src/user.ts index 28f24ae7b..77d8d4138 100644 --- a/packages/definitions/src/user.ts +++ b/packages/definitions/src/user.ts @@ -1,2 +1,2 @@ -export const colorSchemes = ["light", "dark", "auto"] as const; +export const colorSchemes = ["light", "dark"] as const; export type ColorScheme = (typeof colorSchemes)[number]; diff --git a/packages/form/package.json b/packages/form/package.json index 1871c1cfe..6ef96da0c 100644 --- a/packages/form/package.json +++ b/packages/form/package.json @@ -24,13 +24,13 @@ "dependencies": { "@homarr/translation": "workspace:^0.1.0", "@homarr/validation": "workspace:^0.1.0", - "@mantine/form": "^7.13.2" + "@mantine/form": "^7.13.4" }, "devDependencies": { "@homarr/eslint-config": "workspace:^0.2.0", "@homarr/prettier-config": "workspace:^0.1.0", "@homarr/tsconfig": "workspace:^0.1.0", - "eslint": "^9.12.0", + "eslint": "^9.13.0", "typescript": "^5.6.3" } } diff --git a/packages/icons/package.json b/packages/icons/package.json index 406684bfe..b219f01d0 100644 --- a/packages/icons/package.json +++ b/packages/icons/package.json @@ -29,7 +29,7 @@ "@homarr/eslint-config": "workspace:^0.2.0", "@homarr/prettier-config": "workspace:^0.1.0", "@homarr/tsconfig": "workspace:^0.1.0", - "eslint": "^9.12.0", + "eslint": "^9.13.0", "typescript": "^5.6.3" } } diff --git a/packages/integrations/package.json b/packages/integrations/package.json index de9f5dbda..a3d944fa8 100644 --- a/packages/integrations/package.json +++ b/packages/integrations/package.json @@ -33,13 +33,15 @@ "@homarr/log": "workspace:^0.1.0", "@homarr/translation": "workspace:^0.1.0", "@homarr/validation": "workspace:^0.1.0", - "@jellyfin/sdk": "^0.10.0" + "@jellyfin/sdk": "^0.10.0", + "xml2js": "^0.6.2" }, "devDependencies": { "@homarr/eslint-config": "workspace:^0.2.0", "@homarr/prettier-config": "workspace:^0.1.0", "@homarr/tsconfig": "workspace:^0.1.0", - "eslint": "^9.12.0", + "@types/xml2js": "^0.4.14", + "eslint": "^9.13.0", "typescript": "^5.6.3" } } diff --git a/packages/integrations/src/base/creator.ts b/packages/integrations/src/base/creator.ts index beaf6d1a3..5894aea9e 100644 --- a/packages/integrations/src/base/creator.ts +++ b/packages/integrations/src/base/creator.ts @@ -17,6 +17,7 @@ import { SonarrIntegration } from "../media-organizer/sonarr/sonarr-integration" import { OpenMediaVaultIntegration } from "../openmediavault/openmediavault-integration"; import { OverseerrIntegration } from "../overseerr/overseerr-integration"; import { PiHoleIntegration } from "../pi-hole/pi-hole-integration"; +import { PlexIntegration } from "../plex/plex-integration"; import { ProwlarrIntegration } from "../prowlarr/prowlarr-integration"; import type { Integration, IntegrationInput } from "./integration"; @@ -51,6 +52,7 @@ export const integrationCreators = { adGuardHome: AdGuardHomeIntegration, homeAssistant: HomeAssistantIntegration, jellyfin: JellyfinIntegration, + plex: PlexIntegration, sonarr: SonarrIntegration, radarr: RadarrIntegration, sabNzbd: SabnzbdIntegration, diff --git a/packages/integrations/src/calendar-types.ts b/packages/integrations/src/calendar-types.ts index f9b97b431..95399c4b1 100644 --- a/packages/integrations/src/calendar-types.ts +++ b/packages/integrations/src/calendar-types.ts @@ -1,7 +1,11 @@ +export const radarrReleaseTypes = ["inCinemas", "digitalRelease", "physicalRelease"] as const; +type ReleaseType = (typeof radarrReleaseTypes)[number]; + export interface CalendarEvent { name: string; subName: string; date: Date; + dates?: { type: ReleaseType; date: Date }[]; description?: string; thumbnail?: string; mediaInformation?: { diff --git a/packages/integrations/src/index.ts b/packages/integrations/src/index.ts index 0c650a0e3..8a0556c6b 100644 --- a/packages/integrations/src/index.ts +++ b/packages/integrations/src/index.ts @@ -1,30 +1,31 @@ // General integrations export { AdGuardHomeIntegration } from "./adguard-home/adguard-home-integration"; +export { DelugeIntegration } from "./download-client/deluge/deluge-integration"; +export { NzbGetIntegration } from "./download-client/nzbget/nzbget-integration"; +export { QBitTorrentIntegration } from "./download-client/qbittorrent/qbittorrent-integration"; +export { SabnzbdIntegration } from "./download-client/sabnzbd/sabnzbd-integration"; +export { TransmissionIntegration } from "./download-client/transmission/transmission-integration"; export { HomeAssistantIntegration } from "./homeassistant/homeassistant-integration"; -export { JellyfinIntegration } from "./jellyfin/jellyfin-integration"; export { DownloadClientIntegration } from "./interfaces/downloads/download-client-integration"; +export { JellyfinIntegration } from "./jellyfin/jellyfin-integration"; export { JellyseerrIntegration } from "./jellyseerr/jellyseerr-integration"; export { RadarrIntegration } from "./media-organizer/radarr/radarr-integration"; export { SonarrIntegration } from "./media-organizer/sonarr/sonarr-integration"; export { OpenMediaVaultIntegration } from "./openmediavault/openmediavault-integration"; export { OverseerrIntegration } from "./overseerr/overseerr-integration"; export { PiHoleIntegration } from "./pi-hole/pi-hole-integration"; +export { PlexIntegration } from "./plex/plex-integration"; export { ProwlarrIntegration } from "./prowlarr/prowlarr-integration"; -export { SabnzbdIntegration } from "./download-client/sabnzbd/sabnzbd-integration"; -export { NzbGetIntegration } from "./download-client/nzbget/nzbget-integration"; -export { QBitTorrentIntegration } from "./download-client/qbittorrent/qbittorrent-integration"; -export { DelugeIntegration } from "./download-client/deluge/deluge-integration"; -export { TransmissionIntegration } from "./download-client/transmission/transmission-integration"; // Types +export type { IntegrationInput } from "./base/integration"; +export type { DownloadClientJobsAndStatus } from "./interfaces/downloads/download-client-data"; +export type { ExtendedDownloadClientItem } from "./interfaces/downloads/download-client-items"; +export type { ExtendedClientStatus } from "./interfaces/downloads/download-client-status"; export type { HealthMonitoring } from "./interfaces/health-monitoring/healt-monitoring"; export { MediaRequestStatus } from "./interfaces/media-requests/media-request"; export type { MediaRequestList, MediaRequestStats } from "./interfaces/media-requests/media-request"; export type { StreamSession } from "./interfaces/media-server/session"; -export type { ExtendedClientStatus } from "./interfaces/downloads/download-client-status"; -export type { ExtendedDownloadClientItem } from "./interfaces/downloads/download-client-items"; -export type { DownloadClientJobsAndStatus } from "./interfaces/downloads/download-client-data"; -export type { IntegrationInput } from "./base/integration"; // Schemas export { downloadClientItemSchema } from "./interfaces/downloads/download-client-items"; diff --git a/packages/integrations/src/media-organizer/radarr/radarr-integration.ts b/packages/integrations/src/media-organizer/radarr/radarr-integration.ts index 1ef79bf78..a562ce2d0 100644 --- a/packages/integrations/src/media-organizer/radarr/radarr-integration.ts +++ b/packages/integrations/src/media-organizer/radarr/radarr-integration.ts @@ -1,8 +1,10 @@ +import type { AtLeastOneOf } from "@homarr/common/types"; import { logger } from "@homarr/log"; import { z } from "@homarr/validation"; import { Integration } from "../../base/integration"; import type { CalendarEvent } from "../../calendar-types"; +import { radarrReleaseTypes } from "../../calendar-types"; export class RadarrIntegration extends Integration { /** @@ -37,19 +39,23 @@ export class RadarrIntegration extends Integration { }); const radarrCalendarEvents = await z.array(radarrCalendarEventSchema).parseAsync(await response.json()); - return radarrCalendarEvents.map( - (radarrCalendarEvent): CalendarEvent => ({ + return radarrCalendarEvents.map((radarrCalendarEvent): CalendarEvent => { + const dates = radarrReleaseTypes + .map((type) => (radarrCalendarEvent[type] ? { type, date: radarrCalendarEvent[type] } : undefined)) + .filter((date) => date) as AtLeastOneOf[number]>; + return { name: radarrCalendarEvent.title, subName: radarrCalendarEvent.originalTitle, description: radarrCalendarEvent.overview, thumbnail: this.chooseBestImageAsURL(radarrCalendarEvent), - date: radarrCalendarEvent.inCinemas, + date: dates[0].date, + dates, mediaInformation: { type: "movie", }, links: this.getLinksForRadarrCalendarEvent(radarrCalendarEvent), - }), - ); + }; + }); } private getLinksForRadarrCalendarEvent = (event: z.infer) => { @@ -118,7 +124,18 @@ const radarrCalendarEventImageSchema = z.array( const radarrCalendarEventSchema = z.object({ title: z.string(), originalTitle: z.string(), - inCinemas: z.string().transform((value) => new Date(value)), + inCinemas: z + .string() + .transform((value) => new Date(value)) + .optional(), + physicalRelease: z + .string() + .transform((value) => new Date(value)) + .optional(), + digitalRelease: z + .string() + .transform((value) => new Date(value)) + .optional(), overview: z.string().optional(), titleSlug: z.string(), images: radarrCalendarEventImageSchema, diff --git a/packages/integrations/src/plex/interface.ts b/packages/integrations/src/plex/interface.ts new file mode 100644 index 000000000..ca7ce3e67 --- /dev/null +++ b/packages/integrations/src/plex/interface.ts @@ -0,0 +1,37 @@ +interface MediaContainer { + Video?: Session[]; + Track?: Session[]; +} + +interface Session { + User?: { + $: { + id: string; + title: string; + thumb?: string; + }; + }[]; + Player?: { + $: { + product: string; + title: string; + }; + }[]; + Session?: { + $: { + id: string; + }; + }[]; + $: { + grandparentTitle?: string; + parentTitle?: string; + title?: string; + index?: number; + type: string; + live?: string; + }; +} + +export interface PlexResponse { + MediaContainer: MediaContainer; +} diff --git a/packages/integrations/src/plex/plex-integration.ts b/packages/integrations/src/plex/plex-integration.ts new file mode 100644 index 000000000..cdbad1d41 --- /dev/null +++ b/packages/integrations/src/plex/plex-integration.ts @@ -0,0 +1,103 @@ +import { parseStringPromise } from "xml2js"; + +import { logger } from "@homarr/log"; + +import { Integration } from "../base/integration"; +import { IntegrationTestConnectionError } from "../base/test-connection-error"; +import type { StreamSession } from "../interfaces/media-server/session"; +import type { PlexResponse } from "./interface"; + +export class PlexIntegration extends Integration { + public async getCurrentSessionsAsync(): Promise { + const token = super.getSecretValue("apiKey"); + + const response = await fetch(`${this.integration.url}/status/sessions`, { + headers: { + "X-Plex-Token": token, + }, + }); + const body = await response.text(); + // convert xml response to objects, as there is no JSON api + const data = await PlexIntegration.parseXml(body); + const mediaContainer = data.MediaContainer; + const mediaElements = [mediaContainer.Video ?? [], mediaContainer.Track ?? []].flat(); + + // no sessions are open or available + if (mediaElements.length === 0) { + logger.info("No active video sessions found in MediaContainer"); + return []; + } + + const medias = mediaElements + .map((mediaElement): StreamSession | undefined => { + const userElement = mediaElement.User ? mediaElement.User[0] : undefined; + const playerElement = mediaElement.Player ? mediaElement.Player[0] : undefined; + const sessionElement = mediaElement.Session ? mediaElement.Session[0] : undefined; + + if (!playerElement) { + return undefined; + } + + return { + sessionId: sessionElement?.$.id ?? "unknown", + sessionName: `${playerElement.$.product} (${playerElement.$.title})`, + user: { + userId: userElement?.$.id ?? "Anonymous", + username: userElement?.$.title ?? "Anonymous", + profilePictureUrl: userElement?.$.thumb ?? null, + }, + currentlyPlaying: { + type: mediaElement.$.live === "1" ? "tv" : PlexIntegration.getCurrentlyPlayingType(mediaElement.$.type), + name: mediaElement.$.grandparentTitle ?? mediaElement.$.title ?? "Unknown", + seasonName: mediaElement.$.parentTitle, + episodeName: mediaElement.$.title ?? null, + albumName: mediaElement.$.type === "track" ? (mediaElement.$.parentTitle ?? null) : null, + episodeCount: mediaElement.$.index ?? null, + }, + }; + }) + .filter((session): session is StreamSession => session !== undefined); + + return medias; + } + + public async testConnectionAsync(): Promise { + const token = super.getSecretValue("apiKey"); + + await super.handleTestConnectionResponseAsync({ + queryFunctionAsync: async () => { + return await fetch(this.integration.url, { + headers: { + "X-Plex-Token": token, + }, + }); + }, + handleResponseAsync: async (response) => { + try { + const result = await response.text(); + await PlexIntegration.parseXml(result); + return; + } catch { + throw new IntegrationTestConnectionError("invalidCredentials"); + } + }, + }); + } + + static parseXml(xml: string): Promise { + return parseStringPromise(xml) as Promise; + } + + static getCurrentlyPlayingType(type: string): NonNullable["type"] { + switch (type) { + case "movie": + return "movie"; + case "episode": + return "video"; + case "track": + return "audio"; + default: + return "video"; + } + } +} diff --git a/packages/log/package.json b/packages/log/package.json index e87d4f31a..3ad22495d 100644 --- a/packages/log/package.json +++ b/packages/log/package.json @@ -34,7 +34,7 @@ "@homarr/eslint-config": "workspace:^0.2.0", "@homarr/prettier-config": "workspace:^0.1.0", "@homarr/tsconfig": "workspace:^0.1.0", - "eslint": "^9.12.0", + "eslint": "^9.13.0", "typescript": "^5.6.3" } } diff --git a/packages/modals-collection/package.json b/packages/modals-collection/package.json index 72d2def67..c18486717 100644 --- a/packages/modals-collection/package.json +++ b/packages/modals-collection/package.json @@ -30,17 +30,17 @@ "@homarr/translation": "workspace:^0.1.0", "@homarr/ui": "workspace:^0.1.0", "@homarr/validation": "workspace:^0.1.0", - "@mantine/core": "^7.13.2", - "@tabler/icons-react": "^3.19.0", + "@mantine/core": "^7.13.4", + "@tabler/icons-react": "^3.20.0", "dayjs": "^1.11.13", - "next": "^14.2.15", + "next": "^14.2.16", "react": "^18.3.1" }, "devDependencies": { "@homarr/eslint-config": "workspace:^0.2.0", "@homarr/prettier-config": "workspace:^0.1.0", "@homarr/tsconfig": "workspace:^0.1.0", - "eslint": "^9.12.0", + "eslint": "^9.13.0", "typescript": "^5.6.3" }, "prettier": "@homarr/prettier-config" diff --git a/packages/modals/package.json b/packages/modals/package.json index 2e714ecc3..9a7aff6f7 100644 --- a/packages/modals/package.json +++ b/packages/modals/package.json @@ -24,15 +24,15 @@ "dependencies": { "@homarr/translation": "workspace:^0.1.0", "@homarr/ui": "workspace:^0.1.0", - "@mantine/core": "^7.13.2", - "@mantine/hooks": "^7.13.2", + "@mantine/core": "^7.13.4", + "@mantine/hooks": "^7.13.4", "react": "^18.3.1" }, "devDependencies": { "@homarr/eslint-config": "workspace:^0.2.0", "@homarr/prettier-config": "workspace:^0.1.0", "@homarr/tsconfig": "workspace:^0.1.0", - "eslint": "^9.12.0", + "eslint": "^9.13.0", "typescript": "^5.6.3" } } diff --git a/packages/modals/src/confirm-modal.tsx b/packages/modals/src/confirm-modal.tsx index 752506cb8..9f3f2b4ac 100644 --- a/packages/modals/src/confirm-modal.tsx +++ b/packages/modals/src/confirm-modal.tsx @@ -53,7 +53,7 @@ export const ConfirmModal = createModal>(({ act actions.closeModal(); } }, - [cancelProps?.onClick, onCancel, actions.closeModal], + [cancelProps, onCancel, closeOnCancel, actions], ); const handleConfirm = useCallback( @@ -73,7 +73,7 @@ export const ConfirmModal = createModal>(({ act } setLoading(false); }, - [confirmProps?.onClick, onConfirm, actions.closeModal], + [confirmProps, onConfirm, closeOnConfirm, actions], ); return ( diff --git a/packages/modals/src/index.tsx b/packages/modals/src/index.tsx index f3c9e1386..02bc4cff4 100644 --- a/packages/modals/src/index.tsx +++ b/packages/modals/src/index.tsx @@ -38,7 +38,7 @@ export const ModalProvider = ({ children }: PropsWithChildren) => { (id: string, canceled?: boolean) => { dispatch({ type: "CLOSE", modalId: id, canceled }); }, - [stateRef, dispatch], + [dispatch], ); const openModalInner: ModalContextProps["openModalInner"] = useCallback( @@ -63,10 +63,7 @@ export const ModalProvider = ({ children }: PropsWithChildren) => { [dispatch], ); - const handleCloseModal = useCallback( - () => state.current && closeModal(state.current.id), - [closeModal, state.current?.id], - ); + const handleCloseModal = useCallback(() => state.current && closeModal(state.current.id), [closeModal, state]); const activeModals = state.modals.filter((modal) => modal.id === state.current?.id || modal.props.keepMounted); diff --git a/packages/notifications/package.json b/packages/notifications/package.json index 4384d745b..985ef3853 100644 --- a/packages/notifications/package.json +++ b/packages/notifications/package.json @@ -24,14 +24,14 @@ "prettier": "@homarr/prettier-config", "dependencies": { "@homarr/ui": "workspace:^0.1.0", - "@mantine/notifications": "^7.13.2", - "@tabler/icons-react": "^3.19.0" + "@mantine/notifications": "^7.13.4", + "@tabler/icons-react": "^3.20.0" }, "devDependencies": { "@homarr/eslint-config": "workspace:^0.2.0", "@homarr/prettier-config": "workspace:^0.1.0", "@homarr/tsconfig": "workspace:^0.1.0", - "eslint": "^9.12.0", + "eslint": "^9.13.0", "typescript": "^5.6.3" } } diff --git a/packages/old-import/package.json b/packages/old-import/package.json index 34f8b2545..2684dab49 100644 --- a/packages/old-import/package.json +++ b/packages/old-import/package.json @@ -33,7 +33,7 @@ "@homarr/eslint-config": "workspace:^0.2.0", "@homarr/prettier-config": "workspace:^0.1.0", "@homarr/tsconfig": "workspace:^0.1.0", - "eslint": "^9.12.0", + "eslint": "^9.13.0", "typescript": "^5.6.3" }, "prettier": "@homarr/prettier-config" diff --git a/packages/old-import/src/widgets/definitions/rss.ts b/packages/old-import/src/widgets/definitions/rss.ts index 095b6c2fc..1dbf9d560 100644 --- a/packages/old-import/src/widgets/definitions/rss.ts +++ b/packages/old-import/src/widgets/definitions/rss.ts @@ -4,6 +4,7 @@ export type OldmarrRssDefinition = CommonOldmarrWidgetDefinition< "rss", { rssFeedUrl: string[]; + enableRtl: boolean; refreshInterval: number; dangerousAllowSanitizedItemContent: boolean; textLinesClamp: number; diff --git a/packages/old-import/src/widgets/options.ts b/packages/old-import/src/widgets/options.ts index cb95a7629..badf31981 100644 --- a/packages/old-import/src/widgets/options.ts +++ b/packages/old-import/src/widgets/options.ts @@ -23,6 +23,7 @@ const optionMapping: OptionMapping = { }, "mediaRequests-requestStats": {}, calendar: { + releaseType: (oldOptions) => [oldOptions.radarrReleaseType], filterFutureMonths: () => undefined, filterPastMonths: () => undefined, }, @@ -81,6 +82,7 @@ const optionMapping: OptionMapping = { }, rssFeed: { feedUrls: (oldOptions) => oldOptions.rssFeedUrl, + enableRtl: (oldOptions) => oldOptions.enableRtl, maximumAmountPosts: (oldOptions) => oldOptions.maximumAmountOfPosts, textLinesClamp: (oldOptions) => oldOptions.textLinesClamp, }, diff --git a/packages/old-schema/package.json b/packages/old-schema/package.json index e721b6e98..a69c5f546 100644 --- a/packages/old-schema/package.json +++ b/packages/old-schema/package.json @@ -27,7 +27,7 @@ "@homarr/eslint-config": "workspace:^0.2.0", "@homarr/prettier-config": "workspace:^0.1.0", "@homarr/tsconfig": "workspace:^0.1.0", - "eslint": "^9.12.0", + "eslint": "^9.13.0", "typescript": "^5.6.3" }, "prettier": "@homarr/prettier-config" diff --git a/packages/ping/package.json b/packages/ping/package.json index da7bf402a..2a0c18258 100644 --- a/packages/ping/package.json +++ b/packages/ping/package.json @@ -29,7 +29,7 @@ "@homarr/eslint-config": "workspace:^0.2.0", "@homarr/prettier-config": "workspace:^0.1.0", "@homarr/tsconfig": "workspace:^0.1.0", - "eslint": "^9.12.0", + "eslint": "^9.13.0", "typescript": "^5.6.3" } } diff --git a/packages/redis/package.json b/packages/redis/package.json index faa399085..1c56d6c79 100644 --- a/packages/redis/package.json +++ b/packages/redis/package.json @@ -33,7 +33,7 @@ "@homarr/eslint-config": "workspace:^0.2.0", "@homarr/prettier-config": "workspace:^0.1.0", "@homarr/tsconfig": "workspace:^0.1.0", - "eslint": "^9.12.0", + "eslint": "^9.13.0", "typescript": "^5.6.3" } } diff --git a/packages/server-settings/package.json b/packages/server-settings/package.json index a852efca1..d2dab7755 100644 --- a/packages/server-settings/package.json +++ b/packages/server-settings/package.json @@ -25,7 +25,7 @@ "@homarr/eslint-config": "workspace:^0.2.0", "@homarr/prettier-config": "workspace:^0.1.0", "@homarr/tsconfig": "workspace:^0.1.0", - "eslint": "^9.12.0", + "eslint": "^9.13.0", "typescript": "^5.6.3" } } diff --git a/packages/spotlight/package.json b/packages/spotlight/package.json index b23509a1b..22e4fa28e 100644 --- a/packages/spotlight/package.json +++ b/packages/spotlight/package.json @@ -30,12 +30,12 @@ "@homarr/modals-collection": "workspace:^0.1.0", "@homarr/translation": "workspace:^0.1.0", "@homarr/ui": "workspace:^0.1.0", - "@mantine/core": "^7.13.2", - "@mantine/hooks": "^7.13.2", - "@mantine/spotlight": "^7.13.2", - "@tabler/icons-react": "^3.19.0", - "jotai": "^2.10.0", - "next": "^14.2.15", + "@mantine/core": "^7.13.4", + "@mantine/hooks": "^7.13.4", + "@mantine/spotlight": "^7.13.4", + "@tabler/icons-react": "^3.20.0", + "jotai": "^2.10.1", + "next": "^14.2.16", "react": "^18.3.1", "use-deep-compare-effect": "^1.8.1" }, @@ -43,7 +43,7 @@ "@homarr/eslint-config": "workspace:^0.2.0", "@homarr/prettier-config": "workspace:^0.1.0", "@homarr/tsconfig": "workspace:^0.1.0", - "eslint": "^9.12.0", + "eslint": "^9.13.0", "typescript": "^5.6.3" }, "prettier": "@homarr/prettier-config" diff --git a/packages/spotlight/src/components/actions/items/children-action-item.tsx b/packages/spotlight/src/components/actions/items/children-action-item.tsx index c36fb3c65..0b070b147 100644 --- a/packages/spotlight/src/components/actions/items/children-action-item.tsx +++ b/packages/spotlight/src/components/actions/items/children-action-item.tsx @@ -24,7 +24,7 @@ export const ChildrenActionItem = ({ childrenOptions, action, query }: ChildrenA return ( - + ); }; diff --git a/packages/spotlight/src/components/actions/items/group-action-item.tsx b/packages/spotlight/src/components/actions/items/group-action-item.tsx index 1b2ebe1c5..6dd70c5ff 100644 --- a/packages/spotlight/src/components/actions/items/group-action-item.tsx +++ b/packages/spotlight/src/components/actions/items/group-action-item.tsx @@ -48,7 +48,7 @@ export const SpotlightGroupActionItem = closeSpotlightOnTrigger={interaction.type !== "mode" && interaction.type !== "children"} className={classes.spotlightAction} > - + ); }; diff --git a/packages/spotlight/src/components/spotlight.tsx b/packages/spotlight/src/components/spotlight.tsx index f84af4add..2de76db8c 100644 --- a/packages/spotlight/src/components/spotlight.tsx +++ b/packages/spotlight/src/components/spotlight.tsx @@ -92,7 +92,7 @@ export const Spotlight = () => { {childrenOptions ? ( - + ) : null} diff --git a/packages/spotlight/src/lib/children.ts b/packages/spotlight/src/lib/children.ts index 1a792a2b6..69b3c00b1 100644 --- a/packages/spotlight/src/lib/children.ts +++ b/packages/spotlight/src/lib/children.ts @@ -3,13 +3,13 @@ import type { ReactNode } from "react"; import type { inferSearchInteractionDefinition } from "./interaction"; export interface CreateChildrenOptionsProps> { - detailComponent: ({ options }: { options: TParentOptions }) => ReactNode; + DetailComponent: ({ options }: { options: TParentOptions }) => ReactNode; useActions: (options: TParentOptions, query: string) => ChildrenAction[]; } export interface ChildrenAction> { key: string; - component: (option: TParentOptions) => JSX.Element; + Component: (option: TParentOptions) => JSX.Element; useInteraction: (option: TParentOptions, query: string) => inferSearchInteractionDefinition<"link" | "javaScript">; hide?: boolean | ((option: TParentOptions) => boolean); } diff --git a/packages/spotlight/src/lib/group.ts b/packages/spotlight/src/lib/group.ts index dda1fa7a8..900990e4a 100644 --- a/packages/spotlight/src/lib/group.ts +++ b/packages/spotlight/src/lib/group.ts @@ -8,7 +8,7 @@ type CommonSearchGroup, TOptionProps ext // key path is used to define the path to a unique key in the option object keyPath: keyof TOption; title: stringOrTranslation; - component: (option: TOption) => JSX.Element; + Component: (option: TOption) => JSX.Element; useInteraction: (option: TOption, query: string) => inferSearchInteractionDefinition; onKeyDown?: ( event: KeyboardEvent, diff --git a/packages/spotlight/src/lib/interaction.ts b/packages/spotlight/src/lib/interaction.ts index 1528a39ca..b917b3bcd 100644 --- a/packages/spotlight/src/lib/interaction.ts +++ b/packages/spotlight/src/lib/interaction.ts @@ -16,7 +16,7 @@ const searchInteractions = [ // eslint-disable-next-line @typescript-eslint/no-explicit-any useActions: CreateChildrenOptionsProps["useActions"]; // eslint-disable-next-line @typescript-eslint/no-explicit-any - detailComponent: CreateChildrenOptionsProps["detailComponent"]; + DetailComponent: CreateChildrenOptionsProps["DetailComponent"]; // eslint-disable-next-line @typescript-eslint/no-explicit-any option: any; }>(), diff --git a/packages/spotlight/src/modes/app-integration-board/apps-search-group.tsx b/packages/spotlight/src/modes/app-integration-board/apps-search-group.tsx index 5d2dc98a6..477842ac2 100644 --- a/packages/spotlight/src/modes/app-integration-board/apps-search-group.tsx +++ b/packages/spotlight/src/modes/app-integration-board/apps-search-group.tsx @@ -16,7 +16,7 @@ const appChildrenOptions = createChildrenOptions({ useActions: () => [ { key: "open", - component: () => { + Component: () => { const t = useI18n(); return ( @@ -34,7 +34,7 @@ const appChildrenOptions = createChildrenOptions({ }, { key: "edit", - component: () => { + Component: () => { const t = useI18n(); return ( @@ -47,7 +47,7 @@ const appChildrenOptions = createChildrenOptions({ useInteraction: interaction.link(({ id }) => ({ href: `/manage/apps/edit/${id}` })), }, ], - detailComponent: ({ options }) => { + DetailComponent: ({ options }) => { const t = useI18n(); return ( @@ -75,7 +75,7 @@ const appChildrenOptions = createChildrenOptions({ export const appsSearchGroup = createGroup({ keyPath: "id", title: (t) => t("search.mode.appIntegrationBoard.group.app.title"), - component: (app) => ( + Component: (app) => ( ({ const actions: (ChildrenAction & { hidden?: boolean })[] = [ { key: "open", - component: () => { + Component: () => { const t = useI18n(); return ( @@ -37,7 +37,7 @@ const boardChildrenOptions = createChildrenOptions({ }, { key: "homeBoard", - component: () => { + Component: () => { const t = useI18n(); return ( @@ -61,7 +61,7 @@ const boardChildrenOptions = createChildrenOptions({ }, { key: "settings", - component: () => { + Component: () => { const t = useI18n(); return ( @@ -78,7 +78,7 @@ const boardChildrenOptions = createChildrenOptions({ return actions; }, - detailComponent: ({ options: board }) => { + DetailComponent: ({ options: board }) => { const t = useI18n(); return ( @@ -102,7 +102,7 @@ const boardChildrenOptions = createChildrenOptions({ export const boardsSearchGroup = createGroup({ keyPath: "id", title: "Boards", - component: (board) => ( + Component: (board) => ( {board.logoImageUrl ? ( {board.name} diff --git a/packages/spotlight/src/modes/app-integration-board/integrations-search-group.tsx b/packages/spotlight/src/modes/app-integration-board/integrations-search-group.tsx index 55fd14eca..28926a165 100644 --- a/packages/spotlight/src/modes/app-integration-board/integrations-search-group.tsx +++ b/packages/spotlight/src/modes/app-integration-board/integrations-search-group.tsx @@ -10,7 +10,7 @@ import { interaction } from "../../lib/interaction"; export const integrationsSearchGroup = createGroup<{ id: string; kind: IntegrationKind; name: string }>({ keyPath: "id", title: (t) => t("search.mode.appIntegrationBoard.group.integration.title"), - component: (integration) => ( + Component: (integration) => ( diff --git a/packages/spotlight/src/modes/command/children/language.tsx b/packages/spotlight/src/modes/command/children/language.tsx index 7a248275a..848139b68 100644 --- a/packages/spotlight/src/modes/command/children/language.tsx +++ b/packages/spotlight/src/modes/command/children/language.tsx @@ -30,7 +30,7 @@ export const languageChildrenOptions = createChildrenOptions ({ key: localeKey, - component() { + Component() { return ( @@ -53,7 +53,7 @@ export const languageChildrenOptions = createChildrenOptions { + DetailComponent: () => { const t = useI18n(); return ( diff --git a/packages/spotlight/src/modes/command/children/new-integration.tsx b/packages/spotlight/src/modes/command/children/new-integration.tsx index d70a719f3..aebb6ede1 100644 --- a/packages/spotlight/src/modes/command/children/new-integration.tsx +++ b/packages/spotlight/src/modes/command/children/new-integration.tsx @@ -20,7 +20,7 @@ export const newIntegrationChildrenOptions = createChildrenOptions ({ key: kind, - component() { + Component() { return ( @@ -31,7 +31,7 @@ export const newIntegrationChildrenOptions = createChildrenOptions ({ href: `/manage/integrations/new?kind=${kind}` })), })); }, - detailComponent() { + DetailComponent() { const t = useI18n(); return ( diff --git a/packages/spotlight/src/modes/command/index.tsx b/packages/spotlight/src/modes/command/index.tsx index 240fd13b5..88f208104 100644 --- a/packages/spotlight/src/modes/command/index.tsx +++ b/packages/spotlight/src/modes/command/index.tsx @@ -44,7 +44,7 @@ export const commandMode = { keyPath: "commandKey", title: "Global commands", useInteraction: (option, query) => option.useInteraction(option, query), - component: ({ icon: Icon, name }) => ( + Component: ({ icon: Icon, name }) => ( {name} diff --git a/packages/spotlight/src/modes/external/search-engines-search-group.tsx b/packages/spotlight/src/modes/external/search-engines-search-group.tsx index 4c76532e9..fd7563207 100644 --- a/packages/spotlight/src/modes/external/search-engines-search-group.tsx +++ b/packages/spotlight/src/modes/external/search-engines-search-group.tsx @@ -15,7 +15,7 @@ export const searchEnginesChildrenOptions = createChildrenOptions( useActions: () => [ { key: "search", - component: ({ name }) => { + Component: ({ name }) => { const tChildren = useScopedI18n("search.mode.external.group.searchEngine.children"); return ( @@ -30,7 +30,7 @@ export const searchEnginesChildrenOptions = createChildrenOptions( })), }, ], - detailComponent({ options }) { + DetailComponent({ options }) { const tChildren = useScopedI18n("search.mode.external.group.searchEngine.children"); return ( @@ -47,7 +47,7 @@ export const searchEnginesChildrenOptions = createChildrenOptions( export const searchEnginesSearchGroups = createGroup({ keyPath: "short", title: (t) => t("search.mode.external.group.searchEngine.title"), - component: ({ iconUrl, name, short, description }) => { + Component: ({ iconUrl, name, short, description }) => { return ( diff --git a/packages/spotlight/src/modes/index.tsx b/packages/spotlight/src/modes/index.tsx index 077e8fa11..eb286a1cd 100644 --- a/packages/spotlight/src/modes/index.tsx +++ b/packages/spotlight/src/modes/index.tsx @@ -1,6 +1,7 @@ import { Group, Kbd, Text } from "@mantine/core"; import { IconBook2, IconBrandDiscord, IconBrandGithub } from "@tabler/icons-react"; +import { createDocumentationLink } from "@homarr/definitions"; import { useScopedI18n } from "@homarr/translation/client"; import { createGroup } from "../lib/group"; @@ -22,7 +23,7 @@ const helpMode = { keyPath: "character", title: (t) => t("search.mode.help.group.mode.title"), options: searchModesWithoutHelp.map(({ character, modeKey }) => ({ character, modeKey })), - component: ({ modeKey, character }) => { + Component: ({ modeKey, character }) => { const t = useScopedI18n(`search.mode.${modeKey}`); return ( @@ -45,7 +46,7 @@ const helpMode = { { label: t("documentation.label"), icon: IconBook2, - href: "https://homarr.dev/docs/getting-started/", + href: createDocumentationLink("/docs/getting-started"), }, { label: t("submitIssue.label"), @@ -59,7 +60,7 @@ const helpMode = { }, ]; }, - component: (props) => ( + Component: (props) => ( {props.label} diff --git a/packages/spotlight/src/modes/page/pages-search-group.tsx b/packages/spotlight/src/modes/page/pages-search-group.tsx index e0b268a12..698f6166c 100644 --- a/packages/spotlight/src/modes/page/pages-search-group.tsx +++ b/packages/spotlight/src/modes/page/pages-search-group.tsx @@ -29,7 +29,7 @@ export const pagesSearchGroup = createGroup<{ }>({ keyPath: "path", title: (t) => t("search.mode.page.group.page.title"), - component: ({ name, icon: Icon }) => ( + Component: ({ name, icon: Icon }) => ( {name} diff --git a/packages/spotlight/src/modes/user-group/groups-search-group.tsx b/packages/spotlight/src/modes/user-group/groups-search-group.tsx index 507c7cb80..8ffb2a6e2 100644 --- a/packages/spotlight/src/modes/user-group/groups-search-group.tsx +++ b/packages/spotlight/src/modes/user-group/groups-search-group.tsx @@ -16,7 +16,7 @@ const groupChildrenOptions = createChildrenOptions({ useActions: () => [ { key: "detail", - component: () => { + Component: () => { const t = useI18n(); return ( @@ -29,7 +29,7 @@ const groupChildrenOptions = createChildrenOptions({ }, { key: "manageMember", - component: () => { + Component: () => { const t = useI18n(); return ( @@ -42,7 +42,7 @@ const groupChildrenOptions = createChildrenOptions({ }, { key: "managePermission", - component: () => { + Component: () => { const t = useI18n(); return ( @@ -54,7 +54,7 @@ const groupChildrenOptions = createChildrenOptions({ useInteraction: interaction.link(({ id }) => ({ href: `/manage/users/groups/${id}/permissions` })), }, ], - detailComponent: ({ options }) => { + DetailComponent: ({ options }) => { const t = useI18n(); return ( @@ -71,7 +71,7 @@ const groupChildrenOptions = createChildrenOptions({ export const groupsSearchGroup = createGroup({ keyPath: "id", title: "Groups", - component: ({ name }) => ( + Component: ({ name }) => ( {name} diff --git a/packages/spotlight/src/modes/user-group/users-search-group.tsx b/packages/spotlight/src/modes/user-group/users-search-group.tsx index ec750f182..b27dfbc37 100644 --- a/packages/spotlight/src/modes/user-group/users-search-group.tsx +++ b/packages/spotlight/src/modes/user-group/users-search-group.tsx @@ -17,7 +17,7 @@ const userChildrenOptions = createChildrenOptions({ useActions: () => [ { key: "detail", - component: () => { + Component: () => { const t = useI18n(); return ( @@ -30,7 +30,7 @@ const userChildrenOptions = createChildrenOptions({ useInteraction: interaction.link(({ id }) => ({ href: `/manage/users/${id}/general` })), }, ], - detailComponent: ({ options }) => { + DetailComponent: ({ options }) => { const t = useI18n(); return ( @@ -49,7 +49,7 @@ const userChildrenOptions = createChildrenOptions({ export const usersSearchGroup = createGroup({ keyPath: "id", title: (t) => t("search.mode.userGroup.group.user.title"), - component: (user) => ( + Component: (user) => ( {user.name} diff --git a/packages/translation/package.json b/packages/translation/package.json index aeec42149..0f4f728d3 100644 --- a/packages/translation/package.json +++ b/packages/translation/package.json @@ -26,14 +26,14 @@ "prettier": "@homarr/prettier-config", "dependencies": { "dayjs": "^1.11.13", - "mantine-react-table": "2.0.0-beta.6", + "mantine-react-table": "2.0.0-beta.7", "next-international": "^1.2.4" }, "devDependencies": { "@homarr/eslint-config": "workspace:^0.2.0", "@homarr/prettier-config": "workspace:^0.1.0", "@homarr/tsconfig": "workspace:^0.1.0", - "eslint": "^9.12.0", + "eslint": "^9.13.0", "typescript": "^5.6.3" } } diff --git a/packages/translation/src/lang/en.ts b/packages/translation/src/lang/en.ts index f61c5da64..670be6712 100644 --- a/packages/translation/src/lang/en.ts +++ b/packages/translation/src/lang/en.ts @@ -48,6 +48,9 @@ export default { homeBoard: { label: "Home board", }, + pingIconsEnabled: { + label: "Use icons for pings", + }, }, error: { usernameTaken: "Username already taken", @@ -116,6 +119,16 @@ export default { }, }, }, + changePingIconsEnabled: { + notification: { + success: { + message: "Ping icons toggled successfully", + }, + error: { + message: "Unable to toggle ping icons", + }, + }, + }, manageAvatar: { changeImage: { label: "Change image", @@ -236,6 +249,9 @@ export default { mixed: "Some members are from external providers and cannot be managed here", external: "All members are from external providers and cannot be managed here", }, + reservedNotice: { + message: "This group is reserved for system use and restricts some actions. {checkoutDocs}", + }, action: { create: { label: "New group", @@ -563,6 +579,7 @@ export default { tryAgain: "Try again", loading: "Loading", }, + here: "here", iconPicker: { label: "Icon URL", header: "Type name or objects to filter for icons... Homarr will search through {countIcons} icons for you.", @@ -570,6 +587,9 @@ export default { information: { min: "Min", max: "Max", + days: "Days", + hours: "Hours", + minutes: "Minutes", }, notification: { create: { @@ -1018,6 +1038,14 @@ export default { name: "Calendar", description: "Display events from your integrations in a calendar view within a certain relative time period", option: { + releaseType: { + label: "Radarr release type", + options: { + inCinemas: "In cinemas", + digitalRelease: "Digital release", + physicalRelease: "Physical release", + }, + }, filterPastMonths: { label: "Start from", }, @@ -1097,16 +1125,17 @@ export default { }, popover: { information: "Information", - processor: "Processor:", - memory: "Memory:", - version: "Version:", - uptime: "Uptime: {days} days, {hours} hours", + processor: "Processor: {cpuModelName}", + memory: "Memory: {memory}GiB", + memoryAvailable: "Available: {memoryAvailable}GiB ({percent}%)", + version: "Version: {version}", + uptime: "Uptime: {days} Days, {hours} Hours, {minutes} Minutes", loadAverage: "Load average:", - minute: "1 minute:", - minutes: "{count} minutes:", + minute: "1 minute", + minutes: "{count} minutes", used: "Used", - diskAvailable: "Available", - memAvailable: "Available:", + available: "Available", + lastSeen: "Last status update: {lastSeen}", }, memory: {}, error: { @@ -1136,6 +1165,14 @@ export default { }, }, }, + integration: { + noData: "No integration found", + description: "Click {here} to create a new integration", + }, + app: { + noData: "No app found", + description: "Click {here} to create a new app", + }, error: { action: { logs: "Check logs for more details", @@ -1317,6 +1354,9 @@ export default { feedUrls: { label: "Feed URLs", }, + enableRtl: { + label: "Enable RTL", + }, textLinesClamp: { label: "Description line clamp", }, @@ -1703,6 +1743,7 @@ export default { language: "Language & Region", board: "Home board", firstDayOfWeek: "First day of the week", + accessibility: "Accessibility", }, }, security: { diff --git a/packages/ui/package.json b/packages/ui/package.json index 2b8e9d069..e7c275d94 100644 --- a/packages/ui/package.json +++ b/packages/ui/package.json @@ -28,12 +28,12 @@ "@homarr/log": "workspace:^0.1.0", "@homarr/translation": "workspace:^0.1.0", "@homarr/validation": "workspace:^0.1.0", - "@mantine/core": "^7.13.2", - "@mantine/dates": "^7.13.2", - "@mantine/hooks": "^7.13.2", - "@tabler/icons-react": "^3.19.0", - "mantine-react-table": "2.0.0-beta.6", - "next": "^14.2.15", + "@mantine/core": "^7.13.4", + "@mantine/dates": "^7.13.4", + "@mantine/hooks": "^7.13.4", + "@tabler/icons-react": "^3.20.0", + "mantine-react-table": "2.0.0-beta.7", + "next": "^14.2.16", "react": "^18.3.1" }, "devDependencies": { @@ -41,7 +41,7 @@ "@homarr/prettier-config": "workspace:^0.1.0", "@homarr/tsconfig": "workspace:^0.1.0", "@types/css-modules": "^1.0.5", - "eslint": "^9.12.0", + "eslint": "^9.13.0", "typescript": "^5.6.3" }, "prettier": "@homarr/prettier-config" diff --git a/packages/ui/src/components/table-pagination.tsx b/packages/ui/src/components/table-pagination.tsx index 83420ba54..e2380f821 100644 --- a/packages/ui/src/components/table-pagination.tsx +++ b/packages/ui/src/components/table-pagination.tsx @@ -34,7 +34,7 @@ export const TablePagination = ({ total }: TablePaginationProps) => { (control: ControlType) => { return getItemProps(calculatePageFor(control, current, total)); }, - [current], + [current, getItemProps, total], ); const handleChange = useCallback( @@ -43,7 +43,7 @@ export const TablePagination = ({ total }: TablePaginationProps) => { params.set("page", page.toString()); replace(`${pathName}?${params.toString()}`); }, - [pathName, searchParams], + [pathName, replace, searchParams], ); return ( diff --git a/packages/validation/package.json b/packages/validation/package.json index 1acbd4457..9a9b6cb7c 100644 --- a/packages/validation/package.json +++ b/packages/validation/package.json @@ -33,7 +33,7 @@ "@homarr/eslint-config": "workspace:^0.2.0", "@homarr/prettier-config": "workspace:^0.1.0", "@homarr/tsconfig": "workspace:^0.1.0", - "eslint": "^9.12.0", + "eslint": "^9.13.0", "typescript": "^5.6.3" } } diff --git a/packages/validation/src/group.ts b/packages/validation/src/group.ts index cd476c5df..a48642caf 100644 --- a/packages/validation/src/group.ts +++ b/packages/validation/src/group.ts @@ -1,12 +1,19 @@ import { z } from "zod"; -import { groupPermissionKeys } from "@homarr/definitions"; +import { everyoneGroup, groupPermissionKeys } from "@homarr/definitions"; import { byIdSchema } from "./common"; import { zodEnumFromArray } from "./enums"; const createSchema = z.object({ - name: z.string().trim().min(1).max(64), + name: z + .string() + .trim() + .min(1) + .max(64) + .refine((value) => value !== everyoneGroup, { + message: "'everyone' is a reserved group name", + }), }); const updateSchema = createSchema.merge(byIdSchema); diff --git a/packages/validation/src/user.ts b/packages/validation/src/user.ts index e44395e67..566e43363 100644 --- a/packages/validation/src/user.ts +++ b/packages/validation/src/user.ts @@ -108,6 +108,10 @@ const firstDayOfWeekSchema = z.object({ firstDayOfWeek: z.custom((value) => z.number().min(0).max(6).safeParse(value).success), }); +const pingIconsEnabledSchema = z.object({ + pingIconsEnabled: z.boolean(), +}); + export const userSchemas = { signIn: signInSchema, registration: registrationSchema, @@ -121,4 +125,5 @@ export const userSchemas = { changePasswordApi: changePasswordApiSchema, changeColorScheme: changeColorSchemeSchema, firstDayOfWeek: firstDayOfWeekSchema, + pingIconsEnabled: pingIconsEnabledSchema, }; diff --git a/packages/widgets/package.json b/packages/widgets/package.json index 74ee3276a..4716fc5e5 100644 --- a/packages/widgets/package.json +++ b/packages/widgets/package.json @@ -38,37 +38,37 @@ "@homarr/translation": "workspace:^0.1.0", "@homarr/ui": "workspace:^0.1.0", "@homarr/validation": "workspace:^0.1.0", - "@mantine/core": "^7.13.2", - "@mantine/hooks": "^7.13.2", - "@tabler/icons-react": "^3.19.0", - "@tiptap/extension-color": "2.8.0", - "@tiptap/extension-highlight": "2.8.0", - "@tiptap/extension-image": "2.8.0", - "@tiptap/extension-link": "^2.8.0", - "@tiptap/extension-table": "2.8.0", - "@tiptap/extension-table-cell": "2.8.0", - "@tiptap/extension-table-header": "2.8.0", - "@tiptap/extension-table-row": "2.8.0", - "@tiptap/extension-task-item": "2.8.0", - "@tiptap/extension-task-list": "2.8.0", - "@tiptap/extension-text-align": "2.8.0", - "@tiptap/extension-text-style": "2.8.0", - "@tiptap/extension-underline": "2.8.0", - "@tiptap/react": "^2.8.0", - "@tiptap/starter-kit": "^2.8.0", + "@mantine/core": "^7.13.4", + "@mantine/hooks": "^7.13.4", + "@tabler/icons-react": "^3.20.0", + "@tiptap/extension-color": "2.9.1", + "@tiptap/extension-highlight": "2.9.1", + "@tiptap/extension-image": "2.9.1", + "@tiptap/extension-link": "^2.9.1", + "@tiptap/extension-table": "2.9.1", + "@tiptap/extension-table-cell": "2.9.1", + "@tiptap/extension-table-header": "2.9.1", + "@tiptap/extension-table-row": "2.9.1", + "@tiptap/extension-task-item": "2.9.1", + "@tiptap/extension-task-list": "2.9.1", + "@tiptap/extension-text-align": "2.9.1", + "@tiptap/extension-text-style": "2.9.1", + "@tiptap/extension-underline": "2.9.1", + "@tiptap/react": "^2.9.1", + "@tiptap/starter-kit": "^2.9.1", "clsx": "^2.1.1", "dayjs": "^1.11.13", - "mantine-react-table": "2.0.0-beta.6", - "next": "^14.2.15", + "mantine-react-table": "2.0.0-beta.7", + "next": "^14.2.16", "react": "^18.3.1", - "video.js": "^8.18.1" + "video.js": "^8.19.1" }, "devDependencies": { "@homarr/eslint-config": "workspace:^0.2.0", "@homarr/prettier-config": "workspace:^0.1.0", "@homarr/tsconfig": "workspace:^0.1.0", "@types/video.js": "^7.3.58", - "eslint": "^9.12.0", + "eslint": "^9.13.0", "typescript": "^5.6.3" } } diff --git a/packages/widgets/src/_inputs/widget-app-input.tsx b/packages/widgets/src/_inputs/widget-app-input.tsx index 04a85d468..ee22b08da 100644 --- a/packages/widgets/src/_inputs/widget-app-input.tsx +++ b/packages/widgets/src/_inputs/widget-app-input.tsx @@ -1,19 +1,22 @@ "use client"; import { memo, useMemo } from "react"; +import Link from "next/link"; import type { SelectProps } from "@mantine/core"; -import { Group, Loader, Select } from "@mantine/core"; +import { Anchor, Group, Loader, Select, Text } from "@mantine/core"; import { IconCheck } from "@tabler/icons-react"; import type { RouterOutputs } from "@homarr/api"; import { clientApi } from "@homarr/api/client"; +import { useI18n } from "@homarr/translation/client"; import type { CommonWidgetInputProps } from "./common"; import { useWidgetInputTranslation } from "./common"; import { useFormContext } from "./form"; -export const WidgetAppInput = ({ property, kind, options }: CommonWidgetInputProps<"app">) => { - const t = useWidgetInputTranslation(kind, property); +export const WidgetAppInput = ({ property, kind }: CommonWidgetInputProps<"app">) => { + const t = useI18n(); + const tInput = useWidgetInputTranslation(kind, property); const form = useFormContext(); const { data: apps, isPending } = clientApi.app.selectable.useQuery(); @@ -24,10 +27,11 @@ export const WidgetAppInput = ({ property, kind, options }: CommonWidgetInputPro return (