diff --git a/.github/workflows/deployment-docker-image.yml b/.github/workflows/deployment-docker-image.yml index 63592aff5..3611ae31e 100644 --- a/.github/workflows/deployment-docker-image.yml +++ b/.github/workflows/deployment-docker-image.yml @@ -11,6 +11,11 @@ on: required: false default: true description: Send notifications + push-image: + type: boolean + required: false + default: true + description: Push Docker Image permissions: contents: write @@ -93,9 +98,9 @@ jobs: id: buildPushAction uses: docker/build-push-action@v6 with: - platforms: linux/amd64 # we currently do't build for linux/arm64 as it's really slow and we'll move to a self hosted runner for that or use the official github runner, once it's available + platforms: linux/amd64,linux/arm64 context: . - push: true + push: ${{ github.events.inputs.push-image && 'true' || 'false' }} tags: ${{ steps.meta.outputs.tags }} labels: ${{ steps.meta.outputs.labels }} network: host diff --git a/Dockerfile b/Dockerfile index d1379e26e..a0e2c5949 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,4 +1,4 @@ -FROM node:20.17.0-alpine AS base +FROM --platform=linux/amd64 node:20.17.0-alpine AS base FROM base AS builder RUN apk add --no-cache libc6-compat diff --git a/apps/nextjs/package.json b/apps/nextjs/package.json index 69a399841..82be0f98d 100644 --- a/apps/nextjs/package.json +++ b/apps/nextjs/package.json @@ -7,12 +7,13 @@ "build": "pnpm with-env next build", "clean": "git clean -xdf .next .turbo node_modules", "dev": "pnpm with-env next dev", - "lint": "eslint", "format": "prettier --check . --ignore-path ../../.gitignore", + "lint": "eslint", "start": "pnpm with-env next start", "typecheck": "tsc --noEmit", "with-env": "dotenv -e ../../.env --" }, + "prettier": "@homarr/prettier-config", "dependencies": { "@homarr/analytics": "workspace:^0.1.0", "@homarr/api": "workspace:^0.1.0", @@ -40,10 +41,10 @@ "@mantine/tiptap": "^7.12.2", "@million/lint": "1.0.0-rc.84", "@t3-oss/env-nextjs": "^0.11.1", - "@tanstack/react-query": "^5.53.1", - "@tanstack/react-query-devtools": "^5.53.1", - "@tanstack/react-query-next-experimental": "5.53.1", "@tabler/icons-react": "^3.14.0", + "@tanstack/react-query": "^5.55.0", + "@tanstack/react-query-devtools": "^5.55.0", + "@tanstack/react-query-next-experimental": "5.55.0", "@trpc/client": "next", "@trpc/next": "next", "@trpc/react-query": "next", @@ -59,14 +60,14 @@ "glob": "^11.0.0", "jotai": "^2.9.3", "mantine-react-table": "2.0.0-beta.6", - "next": "^14.2.7", + "next": "^14.2.8", "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-simple-code-editor": "^0.14.1", - "sass": "^1.77.8", + "sass": "^1.78.0", "superjson": "2.2.1", "swagger-ui-react": "^5.17.14", "use-deep-compare-effect": "^1.8.1" @@ -76,7 +77,7 @@ "@homarr/prettier-config": "workspace:^0.1.0", "@homarr/tsconfig": "workspace:^0.1.0", "@types/chroma-js": "2.4.4", - "@types/node": "^20.16.2", + "@types/node": "^20.16.5", "@types/prismjs": "^1.26.4", "@types/react": "^18.3.5", "@types/react-dom": "^18.3.0", @@ -86,6 +87,5 @@ "node-loader": "^2.0.0", "prettier": "^3.3.3", "typescript": "^5.5.4" - }, - "prettier": "@homarr/prettier-config" + } } diff --git a/apps/nextjs/src/app/[locale]/_client-providers/mantine.tsx b/apps/nextjs/src/app/[locale]/_client-providers/mantine.tsx new file mode 100644 index 000000000..9a2f3aecb --- /dev/null +++ b/apps/nextjs/src/app/[locale]/_client-providers/mantine.tsx @@ -0,0 +1,89 @@ +"use client"; + +import { useState } from "react"; +import type { PropsWithChildren } from "react"; +import type { MantineColorScheme, MantineColorSchemeManager } from "@mantine/core"; +import { createTheme, isMantineColorScheme, MantineProvider } from "@mantine/core"; + +import { clientApi } from "@homarr/api/client"; +import { useSession } from "@homarr/auth/client"; + +export const CustomMantineProvider = ({ children }: PropsWithChildren) => { + const manager = useColorSchemeManager(); + + return ( + + {children} + + ); +}; + +function useColorSchemeManager(): MantineColorSchemeManager { + const key = "homarr-color-scheme"; + const { data: session } = useSession(); + const [sessionColorScheme, setSessionColorScheme] = useState( + session?.user.colorScheme, + ); + const { mutate: mutateColorScheme } = clientApi.user.changeColorScheme.useMutation({ + onSuccess: (_, variables) => { + setSessionColorScheme(variables.colorScheme); + }, + }); + + let handleStorageEvent: (event: StorageEvent) => void; + + return { + get: (defaultValue) => { + if (typeof window === "undefined") { + return defaultValue; + } + + if (sessionColorScheme) { + return sessionColorScheme; + } + + try { + return (window.localStorage.getItem(key) as MantineColorScheme | undefined) ?? defaultValue; + } catch { + return defaultValue; + } + }, + + set: (value) => { + try { + if (session) { + mutateColorScheme({ colorScheme: value }); + } + window.localStorage.setItem(key, value); + } catch (error) { + console.warn("[@mantine/core] Local storage 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); + }, + }; +} diff --git a/apps/nextjs/src/app/[locale]/_client-providers/trpc.tsx b/apps/nextjs/src/app/[locale]/_client-providers/trpc.tsx index db34ced95..ff3078ae6 100644 --- a/apps/nextjs/src/app/[locale]/_client-providers/trpc.tsx +++ b/apps/nextjs/src/app/[locale]/_client-providers/trpc.tsx @@ -12,7 +12,7 @@ import type { AppRouter } from "@homarr/api"; import { clientApi } from "@homarr/api/client"; const wsClient = createWSClient({ - url: "ws://localhost:3001", + url: typeof window === "undefined" ? "ws://localhost:3001" : `ws://${window.location.hostname}:3001`, }); export function TRPCReactProvider(props: PropsWithChildren) { diff --git a/apps/nextjs/src/app/[locale]/layout.tsx b/apps/nextjs/src/app/[locale]/layout.tsx index 223ebf9be..ae7c4600c 100644 --- a/apps/nextjs/src/app/[locale]/layout.tsx +++ b/apps/nextjs/src/app/[locale]/layout.tsx @@ -1,13 +1,11 @@ import type { Metadata, Viewport } from "next"; import { Inter } from "next/font/google"; -import "@homarr/ui/styles.css"; import "@homarr/notifications/styles.css"; import "@homarr/spotlight/styles.css"; +import "@homarr/ui/styles.css"; import "~/styles/scroll-area.scss"; -import { ColorSchemeScript, createTheme, MantineProvider } from "@mantine/core"; - import { env } from "@homarr/auth/env.mjs"; import { auth } from "@homarr/auth/next"; import { ModalProvider } from "@homarr/modals"; @@ -15,6 +13,7 @@ import { Notifications } from "@homarr/notifications"; import { Analytics } from "~/components/layout/analytics"; import { JotaiProvider } from "./_client-providers/jotai"; +import { CustomMantineProvider } from "./_client-providers/mantine"; import { NextInternationalProvider } from "./_client-providers/next-international"; import { AuthProvider } from "./_client-providers/session"; import { TRPCReactProvider } from "./_client-providers/trpc"; @@ -51,34 +50,25 @@ export const viewport: Viewport = { ], }; -export default function Layout(props: { children: React.ReactNode; params: { locale: string } }) { - const colorScheme = "dark"; +export default async function Layout(props: { children: React.ReactNode; params: { locale: string } }) { + const session = await auth(); + const colorScheme = session?.user.colorScheme; const StackedProvider = composeWrappers([ - async (innerProps) => { - const session = await auth(); + (innerProps) => { return ; }, (innerProps) => , (innerProps) => , (innerProps) => , - (innerProps) => ( - - ), + (innerProps) => , (innerProps) => , ]); return ( - + // Instead of ColorSchemScript we use data-mantine-color-scheme to prevent flickering + - diff --git a/apps/nextjs/src/app/[locale]/manage/tools/logs/client.tsx b/apps/nextjs/src/app/[locale]/manage/tools/logs/client.tsx new file mode 100644 index 000000000..304505d63 --- /dev/null +++ b/apps/nextjs/src/app/[locale]/manage/tools/logs/client.tsx @@ -0,0 +1,10 @@ +"use client"; + +import dynamic from "next/dynamic"; + +export const ClientSideTerminalComponent = dynamic( + () => import("./terminal").then(({ TerminalComponent }) => TerminalComponent), + { + ssr: false, + }, +); diff --git a/apps/nextjs/src/app/[locale]/manage/tools/logs/page.tsx b/apps/nextjs/src/app/[locale]/manage/tools/logs/page.tsx index 7822da49c..da45b84bb 100644 --- a/apps/nextjs/src/app/[locale]/manage/tools/logs/page.tsx +++ b/apps/nextjs/src/app/[locale]/manage/tools/logs/page.tsx @@ -4,11 +4,10 @@ import { getScopedI18n } from "@homarr/translation/server"; import "@xterm/xterm/css/xterm.css"; -import dynamic from "next/dynamic"; - import { DynamicBreadcrumb } from "~/components/navigation/dynamic-breadcrumb"; import { fullHeightWithoutHeaderAndFooter } from "~/constants"; import { createMetaTitle } from "~/metadata"; +import { ClientSideTerminalComponent } from "./client"; export async function generateMetadata() { const t = await getScopedI18n("management"); @@ -18,10 +17,6 @@ export async function generateMetadata() { }; } -const ClientSideTerminalComponent = dynamic(() => import("./terminal"), { - ssr: false, -}); - export default function LogsManagementPage() { return ( <> diff --git a/apps/nextjs/src/app/[locale]/manage/tools/logs/terminal.tsx b/apps/nextjs/src/app/[locale]/manage/tools/logs/terminal.tsx index 428f1f300..b989e8e58 100644 --- a/apps/nextjs/src/app/[locale]/manage/tools/logs/terminal.tsx +++ b/apps/nextjs/src/app/[locale]/manage/tools/logs/terminal.tsx @@ -10,7 +10,7 @@ import { clientApi } from "@homarr/api/client"; import classes from "./terminal.module.css"; -export default function TerminalComponent() { +export const TerminalComponent = () => { const ref = useRef(null); const terminalRef = useRef(); @@ -54,4 +54,4 @@ export default function TerminalComponent() { }; }, []); return ; -} +}; diff --git a/apps/tasks/package.json b/apps/tasks/package.json index eda472148..200b05db9 100644 --- a/apps/tasks/package.json +++ b/apps/tasks/package.json @@ -2,25 +2,29 @@ "name": "@homarr/tasks", "version": "0.1.0", "private": true, + "license": "MIT", + "type": "module", "exports": { ".": "./src/index.ts" }, "main": "./src/main.ts", "types": "./src/main.ts", - "license": "MIT", - "type": "module", "scripts": { - "dev": "pnpm with-env tsx ./src/main.ts", "build": "esbuild src/main.ts --bundle --platform=node --outfile=tasks.cjs", "clean": "rm -rf .turbo node_modules", - "lint": "eslint", + "dev": "pnpm with-env tsx ./src/main.ts", "format": "prettier --check . --ignore-path ../../.gitignore", + "lint": "eslint", "typecheck": "tsc --noEmit", "with-env": "dotenv -e ../../.env --" }, + "prettier": "@homarr/prettier-config", "dependencies": { "@homarr/analytics": "workspace:^0.1.0", "@homarr/common": "workspace:^0.1.0", + "@homarr/cron-job-runner": "workspace:^0.1.0", + "@homarr/cron-jobs": "workspace:^0.1.0", + "@homarr/cron-jobs-core": "workspace:^0.1.0", "@homarr/db": "workspace:^0.1.0", "@homarr/definitions": "workspace:^0.1.0", "@homarr/icons": "workspace:^0.1.0", @@ -30,11 +34,8 @@ "@homarr/redis": "workspace:^0.1.0", "@homarr/server-settings": "workspace:^0.1.0", "@homarr/validation": "workspace:^0.1.0", - "@homarr/cron-jobs-core": "workspace:^0.1.0", "@homarr/widgets": "workspace:^0.1.0", "dayjs": "^1.11.13", - "@homarr/cron-jobs": "workspace:^0.1.0", - "@homarr/cron-job-runner": "workspace:^0.1.0", "dotenv": "^16.4.5", "superjson": "2.2.1", "undici": "6.19.8" @@ -43,12 +44,11 @@ "@homarr/eslint-config": "workspace:^0.2.0", "@homarr/prettier-config": "workspace:^0.1.0", "@homarr/tsconfig": "workspace:^0.1.0", - "@types/node": "^20.16.2", + "@types/node": "^20.16.5", "dotenv-cli": "^7.4.2", "eslint": "^9.9.1", "prettier": "^3.3.3", "tsx": "4.13.3", "typescript": "^5.5.4" - }, - "prettier": "@homarr/prettier-config" + } } diff --git a/apps/websocket/package.json b/apps/websocket/package.json index 6e660dab3..b651380e7 100644 --- a/apps/websocket/package.json +++ b/apps/websocket/package.json @@ -2,19 +2,20 @@ "name": "@homarr/websocket", "version": "0.1.0", "private": true, - "main": "./src/main.ts", - "types": "./src/main.ts", "license": "MIT", "type": "module", + "main": "./src/main.ts", + "types": "./src/main.ts", "scripts": { - "dev": "pnpm with-env tsx ./src/main.ts", "build": "esbuild src/main.ts --bundle --platform=node --outfile=wssServer.cjs --external:bcrypt --external:cpu-features --loader:.html=text --loader:.node=text", "clean": "rm -rf .turbo node_modules", - "lint": "eslint", + "dev": "pnpm with-env tsx ./src/main.ts", "format": "prettier --check . --ignore-path ../../.gitignore", + "lint": "eslint", "typecheck": "tsc --noEmit", "with-env": "dotenv -e ../../.env --" }, + "prettier": "@homarr/prettier-config", "dependencies": { "@homarr/api": "workspace:^0.1.0", "@homarr/auth": "workspace:^0.1.0", @@ -24,9 +25,9 @@ "@homarr/log": "workspace:^", "@homarr/redis": "workspace:^0.1.0", "@homarr/validation": "workspace:^0.1.0", + "dotenv": "^16.4.5", "tsx": "4.13.3", - "ws": "^8.18.0", - "dotenv": "^16.4.5" + "ws": "^8.18.0" }, "devDependencies": { "@homarr/eslint-config": "workspace:^0.2.0", @@ -36,6 +37,5 @@ "eslint": "^9.9.1", "prettier": "^3.3.3", "typescript": "^5.5.4" - }, - "prettier": "@homarr/prettier-config" + } } diff --git a/package.json b/package.json index b780e2ba5..7e1dd0384 100644 --- a/package.json +++ b/package.json @@ -1,22 +1,17 @@ { "name": "homarr", "private": true, - "engines": { - "node": ">=20.17.0" - }, - "packageManager": "pnpm@9.9.0", "scripts": { "build": "turbo build", "clean": "git clean -xdf node_modules", "clean:workspaces": "turbo clean", - "db:push": "pnpm -F db push:sqlite", - "db:studio": "pnpm -F db studio", - "db:migration:sqlite:generate": "pnpm -F db migration:sqlite:generate", + "cli": "pnpm with-env tsx packages/cli/index.ts", "db:migration:mysql:generate": "pnpm -F db migration:mysql:generate", - "db:migration:sqlite:run": "pnpm -F db migration:sqlite:run", "db:migration:mysql:run": "pnpm -F db migration:mysql:run", - "cli": "pnpm with-env tsx packages/cli/index.ts", - "with-env": "dotenv -e .env --", + "db:migration:sqlite:generate": "pnpm -F db migration:sqlite:generate", + "db:migration:sqlite:run": "pnpm -F db migration:sqlite:run", + "db:push": "pnpm -F db push:sqlite", + "db:studio": "pnpm -F db studio", "dev": "turbo dev --parallel", "docker:dev": "docker compose -f ./development/development.docker-compose.yml up", "format": "turbo format --continue -- --cache --cache-location node_modules/.cache/.prettiercache", @@ -26,24 +21,29 @@ "lint:ws": "pnpm dlx sherif@latest", "test": "cross-env NODE_ENV=development vitest run --coverage.enabled", "test:ui": "cross-env NODE_ENV=development vitest --ui --coverage.enabled", - "typecheck": "turbo typecheck" + "typecheck": "turbo typecheck", + "with-env": "dotenv -e .env --" }, + "prettier": "@homarr/prettier-config", "devDependencies": { "@homarr/prettier-config": "workspace:^0.1.0", - "@turbo/gen": "^2.1.0", + "@turbo/gen": "^2.1.1", "@vitejs/plugin-react": "^4.3.1", "@vitest/coverage-v8": "^2.0.5", "@vitest/ui": "^2.0.5", "cross-env": "^7.0.3", "jsdom": "^25.0.0", "prettier": "^3.3.3", - "testcontainers": "^10.12.0", - "turbo": "^2.1.0", + "testcontainers": "^10.13.0", + "turbo": "^2.1.1", "typescript": "^5.5.4", "vite-tsconfig-paths": "^5.0.1", "vitest": "^2.0.5" }, - "prettier": "@homarr/prettier-config", + "packageManager": "pnpm@9.9.0", + "engines": { + "node": ">=20.17.0" + }, "pnpm": { "patchedDependencies": { "trpc-swagger@1.2.6": "patches/trpc-swagger@1.2.6.patch" diff --git a/packages/analytics/package.json b/packages/analytics/package.json index 1c7422249..4870fdb28 100644 --- a/packages/analytics/package.json +++ b/packages/analytics/package.json @@ -1,7 +1,8 @@ { "name": "@homarr/analytics", - "private": true, "version": "0.1.0", + "private": true, + "license": "MIT", "type": "module", "exports": { ".": "./index.ts" @@ -13,19 +14,19 @@ ] } }, - "license": "MIT", "scripts": { "clean": "rm -rf .turbo node_modules", - "lint": "eslint", "format": "prettier --check . --ignore-path ../../.gitignore", + "lint": "eslint", "typecheck": "tsc --noEmit" }, + "prettier": "@homarr/prettier-config", "dependencies": { - "@umami/node": "^0.4.0", - "superjson": "2.2.1", "@homarr/db": "workspace:^0.1.0", "@homarr/log": "workspace:^0.1.0", - "@homarr/server-settings": "workspace:^0.1.0" + "@homarr/server-settings": "workspace:^0.1.0", + "@umami/node": "^0.4.0", + "superjson": "2.2.1" }, "devDependencies": { "@homarr/eslint-config": "workspace:^0.2.0", @@ -33,6 +34,5 @@ "@homarr/tsconfig": "workspace:^0.1.0", "eslint": "^9.9.1", "typescript": "^5.5.4" - }, - "prettier": "@homarr/prettier-config" + } } diff --git a/packages/api/package.json b/packages/api/package.json index 0c23cd94d..e8399f5ff 100644 --- a/packages/api/package.json +++ b/packages/api/package.json @@ -1,45 +1,46 @@ { "name": "@homarr/api", "version": "0.1.0", + "private": true, + "license": "MIT", + "type": "module", "exports": { ".": "./src/index.ts", "./client": "./src/client.ts", "./server": "./src/server.ts", "./websocket": "./src/websocket.ts" }, - "private": true, "main": "./index.ts", "types": "./index.ts", - "license": "MIT", - "type": "module", "scripts": { "clean": "rm -rf .turbo node_modules", - "lint": "eslint", "format": "prettier --check . --ignore-path ../../.gitignore", + "lint": "eslint", "typecheck": "tsc --noEmit" }, + "prettier": "@homarr/prettier-config", "dependencies": { "@homarr/auth": "workspace:^0.1.0", "@homarr/common": "workspace:^0.1.0", - "@homarr/cron-jobs": "workspace:^0.1.0", "@homarr/cron-job-runner": "workspace:^0.1.0", "@homarr/cron-job-status": "workspace:^0.1.0", + "@homarr/cron-jobs": "workspace:^0.1.0", "@homarr/db": "workspace:^0.1.0", "@homarr/definitions": "workspace:^0.1.0", "@homarr/integrations": "workspace:^0.1.0", "@homarr/log": "workspace:^", "@homarr/ping": "workspace:^0.1.0", "@homarr/redis": "workspace:^0.1.0", - "@homarr/validation": "workspace:^0.1.0", "@homarr/server-settings": "workspace:^0.1.0", - "@trpc/react-query": "next", + "@homarr/validation": "workspace:^0.1.0", "@trpc/client": "next", + "@trpc/react-query": "next", "@trpc/server": "next", "dockerode": "^4.0.2", + "next": "^14.2.8", + "react": "^18.3.1", "superjson": "2.2.1", - "trpc-swagger": "^1.2.6", - "next": "^14.2.7", - "react": "^18.3.1" + "trpc-swagger": "^1.2.6" }, "devDependencies": { "@homarr/eslint-config": "workspace:^0.2.0", @@ -49,6 +50,5 @@ "eslint": "^9.9.1", "prettier": "^3.3.3", "typescript": "^5.5.4" - }, - "prettier": "@homarr/prettier-config" + } } diff --git a/packages/api/src/router/test/board.spec.ts b/packages/api/src/router/test/board.spec.ts index c1d0f45bb..b95f6279c 100644 --- a/packages/api/src/router/test/board.spec.ts +++ b/packages/api/src/router/test/board.spec.ts @@ -30,6 +30,7 @@ const defaultSession = { user: { id: defaultCreatorId, permissions: [], + colorScheme: "light", }, expires: new Date().toISOString(), } satisfies Session; @@ -87,6 +88,7 @@ describe("getAllBoards should return all boards accessable to the current user", user: { id: defaultCreatorId, permissions: ["board-view-all"], + colorScheme: "light", }, expires: new Date().toISOString(), }, diff --git a/packages/api/src/router/test/docker/docker-router.spec.ts b/packages/api/src/router/test/docker/docker-router.spec.ts index c92a0bbfc..f81313fe2 100644 --- a/packages/api/src/router/test/docker/docker-router.spec.ts +++ b/packages/api/src/router/test/docker/docker-router.spec.ts @@ -29,6 +29,7 @@ const createSessionWithPermissions = (...permissions: GroupPermissionKey[]) => user: { id: "1", permissions, + colorScheme: "light", }, expires: new Date().toISOString(), }) satisfies Session; diff --git a/packages/api/src/router/test/group.spec.ts b/packages/api/src/router/test/group.spec.ts index 51c11e70e..5e3ca35a4 100644 --- a/packages/api/src/router/test/group.spec.ts +++ b/packages/api/src/router/test/group.spec.ts @@ -12,6 +12,7 @@ const defaultSession = { user: { id: defaultOwnerId, permissions: [], + colorScheme: "light", }, expires: new Date().toISOString(), } satisfies Session; diff --git a/packages/api/src/router/test/integration/integration-router.spec.ts b/packages/api/src/router/test/integration/integration-router.spec.ts index 2f21e666b..dde896352 100644 --- a/packages/api/src/router/test/integration/integration-router.spec.ts +++ b/packages/api/src/router/test/integration/integration-router.spec.ts @@ -17,6 +17,7 @@ const defaultSessionWithPermissions = (permissions: GroupPermissionKey[] = []) = user: { id: defaultUserId, permissions, + colorScheme: "light", }, expires: new Date().toISOString(), }) satisfies Session; diff --git a/packages/api/src/router/test/invite.spec.ts b/packages/api/src/router/test/invite.spec.ts index 9c39d5bb2..6be30f7a9 100644 --- a/packages/api/src/router/test/invite.spec.ts +++ b/packages/api/src/router/test/invite.spec.ts @@ -12,6 +12,7 @@ const defaultSession = { user: { id: createId(), permissions: [], + colorScheme: "light", }, expires: new Date().toISOString(), } satisfies Session; diff --git a/packages/api/src/router/test/serverSettings.spec.ts b/packages/api/src/router/test/serverSettings.spec.ts index 331631229..dffa42e35 100644 --- a/packages/api/src/router/test/serverSettings.spec.ts +++ b/packages/api/src/router/test/serverSettings.spec.ts @@ -16,6 +16,7 @@ const defaultSession = { user: { id: createId(), permissions: [], + colorScheme: "light", }, expires: new Date().toISOString(), } satisfies Session; diff --git a/packages/api/src/router/test/user.spec.ts b/packages/api/src/router/test/user.spec.ts index 9a4696969..e27074426 100644 --- a/packages/api/src/router/test/user.spec.ts +++ b/packages/api/src/router/test/user.spec.ts @@ -246,6 +246,7 @@ describe("editProfile shoud update user", () => { image: null, homeBoardId: null, provider: "credentials", + colorScheme: "auto", }); }); @@ -287,6 +288,7 @@ describe("editProfile shoud update user", () => { image: null, homeBoardId: null, provider: "credentials", + colorScheme: "auto", }); }); }); @@ -312,6 +314,7 @@ describe("delete should delete user", () => { salt: null, homeBoardId: null, provider: "ldap" as const, + colorScheme: "auto" as const, }, { id: userToDelete, @@ -322,6 +325,7 @@ describe("delete should delete user", () => { password: null, salt: null, homeBoardId: null, + colorScheme: "auto" as const, }, { id: createId(), @@ -333,6 +337,7 @@ describe("delete should delete user", () => { salt: null, homeBoardId: null, provider: "oidc" as const, + colorScheme: "auto" as const, }, ]; diff --git a/packages/api/src/router/user.ts b/packages/api/src/router/user.ts index 4ede622cf..362b3b7d7 100644 --- a/packages/api/src/router/user.ts +++ b/packages/api/src/router/user.ts @@ -317,6 +317,14 @@ export const userRouter = createTRPCRouter({ }) .where(eq(users.id, input.userId)); }), + changeColorScheme: protectedProcedure.input(validation.user.changeColorScheme).mutation(async ({ input, ctx }) => { + await ctx.db + .update(users) + .set({ + colorScheme: input.colorScheme, + }) + .where(eq(users.id, ctx.session.user.id)); + }), }); const createUserAsync = async (db: Database, input: z.infer) => { diff --git a/packages/auth/callbacks.ts b/packages/auth/callbacks.ts index 90242b836..3665a674f 100644 --- a/packages/auth/callbacks.ts +++ b/packages/auth/callbacks.ts @@ -4,7 +4,7 @@ import type { NextAuthConfig } from "next-auth"; import type { Database } from "@homarr/db"; import { eq, inArray } from "@homarr/db"; -import { groupMembers, groupPermissions } from "@homarr/db/schema/sqlite"; +import { groupMembers, groupPermissions, users } from "@homarr/db/schema/sqlite"; import { getPermissionsWithChildren } from "@homarr/definitions"; import { env } from "./env.mjs"; @@ -31,10 +31,18 @@ export const getCurrentUserPermissionsAsync = async (db: Database, userId: strin export const createSessionCallback = (db: Database): NextAuthCallbackOf<"session"> => { return async ({ session, user }) => { + const additionalProperties = await db.query.users.findFirst({ + where: eq(users.id, user.id), + columns: { + colorScheme: true, + }, + }); + return { ...session, user: { ...session.user, + ...additionalProperties, id: user.id, name: user.name, permissions: await getCurrentUserPermissionsAsync(db, user.id), diff --git a/packages/auth/index.ts b/packages/auth/index.ts index 78c3e7e88..1cb226fa2 100644 --- a/packages/auth/index.ts +++ b/packages/auth/index.ts @@ -1,7 +1,7 @@ import { headers } from "next/headers"; import type { DefaultSession } from "@auth/core/types"; -import type { GroupPermissionKey } from "@homarr/definitions"; +import type { ColorScheme, GroupPermissionKey } from "@homarr/definitions"; import { createConfiguration } from "./configuration"; @@ -12,6 +12,7 @@ declare module "next-auth" { user: { id: string; permissions: GroupPermissionKey[]; + colorScheme: ColorScheme; } & DefaultSession["user"]; } } diff --git a/packages/auth/package.json b/packages/auth/package.json index 78f7ca546..6f4ea6af2 100644 --- a/packages/auth/package.json +++ b/packages/auth/package.json @@ -1,6 +1,8 @@ { "name": "@homarr/auth", "version": "0.1.0", + "private": true, + "license": "MIT", "type": "module", "exports": { ".": "./index.ts", @@ -11,29 +13,28 @@ "./shared": "./shared.ts", "./env.mjs": "./env.mjs" }, - "private": true, "main": "./index.ts", "types": "./index.ts", - "license": "MIT", "scripts": { "clean": "rm -rf .turbo node_modules", - "lint": "eslint", "format": "prettier --check . --ignore-path ../../.gitignore", + "lint": "eslint", "typecheck": "tsc --noEmit" }, + "prettier": "@homarr/prettier-config", "dependencies": { - "@homarr/db": "workspace:^0.1.0", + "@auth/core": "^0.34.2", + "@auth/drizzle-adapter": "^1.4.2", "@homarr/common": "workspace:^0.1.0", + "@homarr/db": "workspace:^0.1.0", "@homarr/definitions": "workspace:^0.1.0", "@homarr/log": "workspace:^0.1.0", "@homarr/validation": "workspace:^0.1.0", - "@auth/core": "^0.34.2", - "@auth/drizzle-adapter": "^1.4.2", "@t3-oss/env-nextjs": "^0.11.1", "bcrypt": "^5.1.1", "cookies": "^0.9.1", "ldapts": "7.1.1", - "next": "^14.2.7", + "next": "^14.2.8", "next-auth": "5.0.0-beta.20", "react": "^18.3.1", "react-dom": "^18.3.1" @@ -47,6 +48,5 @@ "eslint": "^9.9.1", "prettier": "^3.3.3", "typescript": "^5.5.4" - }, - "prettier": "@homarr/prettier-config" + } } diff --git a/packages/auth/permissions/test/board-permissions.spec.ts b/packages/auth/permissions/test/board-permissions.spec.ts index 3e02e6be6..f897491ae 100644 --- a/packages/auth/permissions/test/board-permissions.spec.ts +++ b/packages/auth/permissions/test/board-permissions.spec.ts @@ -20,6 +20,7 @@ describe("constructBoardPermissions", () => { user: { id: "1", permissions: [], + colorScheme: "light", }, expires: new Date().toISOString(), } satisfies Session; @@ -47,6 +48,7 @@ describe("constructBoardPermissions", () => { user: { id: "2", permissions: getPermissionsWithChildren(["board-full-all"]), + colorScheme: "light", }, expires: new Date().toISOString(), } satisfies Session; @@ -74,6 +76,7 @@ describe("constructBoardPermissions", () => { user: { id: "2", permissions: getPermissionsWithChildren(["board-modify-all"]), + colorScheme: "light", }, expires: new Date().toISOString(), } satisfies Session; @@ -102,6 +105,7 @@ describe("constructBoardPermissions", () => { user: { id: "2", permissions: [], + colorScheme: "light", }, expires: new Date().toISOString(), } satisfies Session; @@ -129,6 +133,7 @@ describe("constructBoardPermissions", () => { user: { id: "2", permissions: [], + colorScheme: "light", }, expires: new Date().toISOString(), } satisfies Session; @@ -156,6 +161,7 @@ describe("constructBoardPermissions", () => { user: { id: "2", permissions: getPermissionsWithChildren(["board-view-all"]), + colorScheme: "light", }, expires: new Date().toISOString(), } satisfies Session; @@ -183,6 +189,7 @@ describe("constructBoardPermissions", () => { user: { id: "2", permissions: [], + colorScheme: "light", }, expires: new Date().toISOString(), } satisfies Session; @@ -210,6 +217,7 @@ describe("constructBoardPermissions", () => { user: { id: "2", permissions: [], + colorScheme: "light", }, expires: new Date().toISOString(), } satisfies Session; @@ -237,6 +245,7 @@ describe("constructBoardPermissions", () => { user: { id: "2", permissions: [], + colorScheme: "light", }, expires: new Date().toISOString(), } satisfies Session; @@ -264,6 +273,7 @@ describe("constructBoardPermissions", () => { user: { id: "2", permissions: [], + colorScheme: "light", }, expires: new Date().toISOString(), } satisfies Session; diff --git a/packages/auth/permissions/test/integration-permissions.spec.ts b/packages/auth/permissions/test/integration-permissions.spec.ts index 01c9ba818..b84041ae6 100644 --- a/packages/auth/permissions/test/integration-permissions.spec.ts +++ b/packages/auth/permissions/test/integration-permissions.spec.ts @@ -16,6 +16,7 @@ describe("constructIntegrationPermissions", () => { user: { id: "2", permissions: getPermissionsWithChildren(["integration-full-all"]), + colorScheme: "light", }, expires: new Date().toISOString(), } satisfies Session; @@ -39,6 +40,7 @@ describe("constructIntegrationPermissions", () => { user: { id: "2", permissions: getPermissionsWithChildren(["integration-interact-all"]), + colorScheme: "light", }, expires: new Date().toISOString(), } satisfies Session; @@ -62,6 +64,7 @@ describe("constructIntegrationPermissions", () => { user: { id: "2", permissions: [], + colorScheme: "light", }, expires: new Date().toISOString(), } satisfies Session; @@ -85,6 +88,7 @@ describe("constructIntegrationPermissions", () => { user: { id: "2", permissions: [], + colorScheme: "light", }, expires: new Date().toISOString(), } satisfies Session; @@ -108,6 +112,7 @@ describe("constructIntegrationPermissions", () => { user: { id: "2", permissions: getPermissionsWithChildren(["integration-use-all"]), + colorScheme: "light", }, expires: new Date().toISOString(), } satisfies Session; @@ -131,6 +136,7 @@ describe("constructIntegrationPermissions", () => { user: { id: "2", permissions: [], + colorScheme: "light", }, expires: new Date().toISOString(), } satisfies Session; @@ -154,6 +160,7 @@ describe("constructIntegrationPermissions", () => { user: { id: "2", permissions: [], + colorScheme: "light", }, expires: new Date().toISOString(), } satisfies Session; @@ -177,6 +184,7 @@ describe("constructIntegrationPermissions", () => { user: { id: "2", permissions: [], + colorScheme: "light", }, expires: new Date().toISOString(), } satisfies Session; @@ -190,40 +198,3 @@ describe("constructIntegrationPermissions", () => { expect(result.hasUseAccess).toBe(false); }); }); -/* - - - - - - - - - test("should return hasViewAccess as true when board is public", () => { - // Arrange - const board = { - creator: { - id: "1", - }, - userPermissions: [], - groupPermissions: [], - isPublic: true, - }; - const session = { - user: { - id: "2", - permissions: [], - }, - expires: new Date().toISOString(), - } satisfies Session; - - // Act - const result = constructBoardPermissions(board, session); - - // Assert - expect(result.hasFullAccess).toBe(false); - expect(result.hasChangeAccess).toBe(false); - expect(result.hasViewAccess).toBe(true); - }); -}); -*/ diff --git a/packages/auth/permissions/test/integration-query-permissions.spec.ts b/packages/auth/permissions/test/integration-query-permissions.spec.ts index c0185c177..faf527d92 100644 --- a/packages/auth/permissions/test/integration-query-permissions.spec.ts +++ b/packages/auth/permissions/test/integration-query-permissions.spec.ts @@ -20,6 +20,7 @@ const createSession = (user: Partial): Session => ({ user: { id: "1", permissions: [], + colorScheme: "light", ...user, }, expires: new Date().toISOString(), diff --git a/packages/auth/session.ts b/packages/auth/session.ts index 48701ef0b..5510ca89b 100644 --- a/packages/auth/session.ts +++ b/packages/auth/session.ts @@ -32,6 +32,7 @@ export const getSessionFromTokenAsync = async (db: Database, token: string | und name: true, email: true, image: true, + colorScheme: true, }, }, }, diff --git a/packages/auth/test/callbacks.spec.ts b/packages/auth/test/callbacks.spec.ts index 755b56fe8..e793c6749 100644 --- a/packages/auth/test/callbacks.spec.ts +++ b/packages/auth/test/callbacks.spec.ts @@ -101,6 +101,7 @@ describe("session callback", () => { email: "no-email", emailVerified: new Date("2023-01-13"), permissions: [], + colorScheme: "dark", }, expires: "2023-01-13" as Date & string, sessionToken: "token", diff --git a/packages/cli/package.json b/packages/cli/package.json index b352cb868..6376fb9b9 100644 --- a/packages/cli/package.json +++ b/packages/cli/package.json @@ -1,7 +1,8 @@ { "name": "@homarr/cli", - "private": true, "version": "0.1.0", + "private": true, + "license": "MIT", "type": "module", "exports": { ".": "./index.ts" @@ -13,19 +14,19 @@ ] } }, - "license": "MIT", "scripts": { - "clean": "rm -rf .turbo node_modules", - "lint": "eslint", "build": "esbuild src/index.ts --bundle --platform=node --outfile=cli.cjs --external:bcrypt --external:cpu-features --loader:.html=text --loader:.node=text", + "clean": "rm -rf .turbo node_modules", "format": "prettier --check . --ignore-path ../../.gitignore", + "lint": "eslint", "typecheck": "tsc --noEmit" }, + "prettier": "@homarr/prettier-config", "dependencies": { "@drizzle-team/brocli": "^0.10.1", - "@homarr/db": "workspace:^0.1.0", - "@homarr/common": "workspace:^0.1.0", "@homarr/auth": "workspace:^0.1.0", + "@homarr/common": "workspace:^0.1.0", + "@homarr/db": "workspace:^0.1.0", "dotenv": "^16.4.5" }, "devDependencies": { @@ -34,6 +35,5 @@ "@homarr/tsconfig": "workspace:^0.1.0", "eslint": "^9.9.1", "typescript": "^5.5.4" - }, - "prettier": "@homarr/prettier-config" + } } diff --git a/packages/common/package.json b/packages/common/package.json index 343532534..dde0170e7 100644 --- a/packages/common/package.json +++ b/packages/common/package.json @@ -1,7 +1,8 @@ { "name": "@homarr/common", - "private": true, "version": "0.1.0", + "private": true, + "license": "MIT", "type": "module", "exports": { ".": "./index.ts", @@ -16,18 +17,18 @@ ] } }, - "license": "MIT", "scripts": { "clean": "rm -rf .turbo node_modules", - "lint": "eslint", "format": "prettier --check . --ignore-path ../../.gitignore", + "lint": "eslint", "typecheck": "tsc --noEmit" }, + "prettier": "@homarr/prettier-config", "dependencies": { "dayjs": "^1.11.13", - "next": "^14.2.7", + "next": "^14.2.8", "react": "^18.3.1", - "tldts": "^6.1.41" + "tldts": "^6.1.42" }, "devDependencies": { "@homarr/eslint-config": "workspace:^0.2.0", @@ -35,6 +36,5 @@ "@homarr/tsconfig": "workspace:^0.1.0", "eslint": "^9.9.1", "typescript": "^5.5.4" - }, - "prettier": "@homarr/prettier-config" + } } diff --git a/packages/cron-job-runner/package.json b/packages/cron-job-runner/package.json index 8fc5270fb..d4a18e976 100644 --- a/packages/cron-job-runner/package.json +++ b/packages/cron-job-runner/package.json @@ -1,7 +1,8 @@ { "name": "@homarr/cron-job-runner", - "private": true, "version": "0.1.0", + "private": true, + "license": "MIT", "type": "module", "exports": { ".": "./index.ts" @@ -13,13 +14,13 @@ ] } }, - "license": "MIT", "scripts": { "clean": "rm -rf .turbo node_modules", - "lint": "eslint", "format": "prettier --check . --ignore-path ../../.gitignore", + "lint": "eslint", "typecheck": "tsc --noEmit" }, + "prettier": "@homarr/prettier-config", "dependencies": { "@homarr/cron-jobs": "workspace:^0.1.0", "@homarr/log": "workspace:^0.1.0", @@ -31,6 +32,5 @@ "@homarr/tsconfig": "workspace:^0.1.0", "eslint": "^9.9.1", "typescript": "^5.5.4" - }, - "prettier": "@homarr/prettier-config" + } } diff --git a/packages/cron-job-status/package.json b/packages/cron-job-status/package.json index 484f270fb..d4e8b63c4 100644 --- a/packages/cron-job-status/package.json +++ b/packages/cron-job-status/package.json @@ -1,7 +1,8 @@ { "name": "@homarr/cron-job-status", - "private": true, "version": "0.1.0", + "private": true, + "license": "MIT", "type": "module", "exports": { ".": "./index.ts", @@ -14,13 +15,13 @@ ] } }, - "license": "MIT", "scripts": { "clean": "rm -rf .turbo node_modules", - "lint": "eslint", "format": "prettier --check . --ignore-path ../../.gitignore", + "lint": "eslint", "typecheck": "tsc --noEmit" }, + "prettier": "@homarr/prettier-config", "dependencies": { "@homarr/redis": "workspace:^0.1.0" }, @@ -30,6 +31,5 @@ "@homarr/tsconfig": "workspace:^0.1.0", "eslint": "^9.9.1", "typescript": "^5.5.4" - }, - "prettier": "@homarr/prettier-config" + } } diff --git a/packages/cron-jobs-core/package.json b/packages/cron-jobs-core/package.json index 4bdf5a97d..5b78de5fa 100644 --- a/packages/cron-jobs-core/package.json +++ b/packages/cron-jobs-core/package.json @@ -1,7 +1,8 @@ { "name": "@homarr/cron-jobs-core", - "private": true, "version": "0.1.0", + "private": true, + "license": "MIT", "type": "module", "exports": { ".": "./index.ts", @@ -15,16 +16,16 @@ ] } }, - "license": "MIT", "scripts": { "clean": "rm -rf .turbo node_modules", - "lint": "eslint", "format": "prettier --check . --ignore-path ../../.gitignore", + "lint": "eslint", "typecheck": "tsc --noEmit" }, + "prettier": "@homarr/prettier-config", "dependencies": { - "node-cron": "^3.0.3", - "@homarr/common": "workspace:^0.1.0" + "@homarr/common": "workspace:^0.1.0", + "node-cron": "^3.0.3" }, "devDependencies": { "@homarr/eslint-config": "workspace:^0.2.0", @@ -33,6 +34,5 @@ "@types/node-cron": "^3.0.11", "eslint": "^9.9.1", "typescript": "^5.5.4" - }, - "prettier": "@homarr/prettier-config" + } } diff --git a/packages/cron-jobs/package.json b/packages/cron-jobs/package.json index caf1eb442..3578badcd 100644 --- a/packages/cron-jobs/package.json +++ b/packages/cron-jobs/package.json @@ -1,7 +1,8 @@ { "name": "@homarr/cron-jobs", - "private": true, "version": "0.1.0", + "private": true, + "license": "MIT", "type": "module", "exports": { ".": "./index.ts" @@ -13,13 +14,13 @@ ] } }, - "license": "MIT", "scripts": { "clean": "rm -rf .turbo node_modules", - "lint": "eslint", "format": "prettier --check . --ignore-path ../../.gitignore", + "lint": "eslint", "typecheck": "tsc --noEmit" }, + "prettier": "@homarr/prettier-config", "dependencies": { "@extractus/feed-extractor": "^7.1.3", "@homarr/analytics": "workspace:^0.1.0", @@ -42,6 +43,5 @@ "@homarr/tsconfig": "workspace:^0.1.0", "eslint": "^9.9.1", "typescript": "^5.5.4" - }, - "prettier": "@homarr/prettier-config" + } } diff --git a/packages/db/migrations/mysql/0007_boring_nocturne.sql b/packages/db/migrations/mysql/0007_boring_nocturne.sql new file mode 100644 index 000000000..b041b6918 --- /dev/null +++ b/packages/db/migrations/mysql/0007_boring_nocturne.sql @@ -0,0 +1 @@ +ALTER TABLE `user` ADD `colorScheme` varchar(5) DEFAULT 'auto' NOT NULL; \ No newline at end of file diff --git a/packages/db/migrations/mysql/meta/0007_snapshot.json b/packages/db/migrations/mysql/meta/0007_snapshot.json new file mode 100644 index 000000000..b1b162698 --- /dev/null +++ b/packages/db/migrations/mysql/meta/0007_snapshot.json @@ -0,0 +1,1373 @@ +{ + "version": "5", + "dialect": "mysql", + "id": "b7264307-fc31-48c0-973f-0e0dd91f5f90", + "prevId": "67352107-06b7-4f5d-a4e0-4ba27327f588", + "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": {} + }, + "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": "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": { + "name": "integrationGroupPermissions_integration_id_group_id_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": "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": { + "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": {} + }, + "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": "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": { + "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'" + } + }, + "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/_journal.json b/packages/db/migrations/mysql/meta/_journal.json index 1a45a04c0..8917665c6 100644 --- a/packages/db/migrations/mysql/meta/_journal.json +++ b/packages/db/migrations/mysql/meta/_journal.json @@ -50,6 +50,13 @@ "when": 1722517058725, "tag": "0006_young_micromax", "breakpoints": true + }, + { + "idx": 7, + "version": "5", + "when": 1723749320706, + "tag": "0007_boring_nocturne", + "breakpoints": true } ] } diff --git a/packages/db/migrations/sqlite/0007_known_ultragirl.sql b/packages/db/migrations/sqlite/0007_known_ultragirl.sql new file mode 100644 index 000000000..7a4040a01 --- /dev/null +++ b/packages/db/migrations/sqlite/0007_known_ultragirl.sql @@ -0,0 +1 @@ +ALTER TABLE `user` ADD `colorScheme` text DEFAULT 'auto' NOT NULL; diff --git a/packages/db/migrations/sqlite/meta/0007_snapshot.json b/packages/db/migrations/sqlite/meta/0007_snapshot.json new file mode 100644 index 000000000..85bccfaea --- /dev/null +++ b/packages/db/migrations/sqlite/meta/0007_snapshot.json @@ -0,0 +1,1316 @@ +{ + "version": "6", + "dialect": "sqlite", + "id": "11d3d936-3e3a-43b7-84b8-f0a1020b3b82", + "prevId": "589ffaa4-4b95-4c6e-84b0-5b0d7959750b", + "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": {} + }, + "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": {} + }, + "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'" + } + }, + "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/_journal.json b/packages/db/migrations/sqlite/meta/_journal.json index 99839fc25..e2e4864d9 100644 --- a/packages/db/migrations/sqlite/meta/_journal.json +++ b/packages/db/migrations/sqlite/meta/_journal.json @@ -50,6 +50,13 @@ "when": 1722517033483, "tag": "0006_windy_doctor_faustus", "breakpoints": true + }, + { + "idx": 7, + "version": "6", + "when": 1723746828385, + "tag": "0007_known_ultragirl", + "breakpoints": true } ] } diff --git a/packages/db/package.json b/packages/db/package.json index 0769bcbdd..43497e5b3 100644 --- a/packages/db/package.json +++ b/packages/db/package.json @@ -1,6 +1,8 @@ { "name": "@homarr/db", "version": "0.1.0", + "private": true, + "license": "MIT", "type": "module", "exports": { ".": "./index.ts", @@ -9,37 +11,36 @@ "./test": "./test/index.ts", "./queries": "./queries/index.ts" }, - "private": true, "main": "./index.ts", "types": "./index.ts", - "license": "MIT", "scripts": { "build": "pnpm run build:sqlite && pnpm run build:mysql", - "build:sqlite": "esbuild migrations/sqlite/migrate.ts --bundle --platform=node --outfile=migrations/sqlite/migrate.cjs", "build:mysql": "esbuild migrations/mysql/migrate.ts --bundle --platform=node --outfile=migrations/mysql/migrate.cjs", + "build:sqlite": "esbuild migrations/sqlite/migrate.ts --bundle --platform=node --outfile=migrations/sqlite/migrate.cjs", "clean": "rm -rf .turbo node_modules", - "lint": "eslint", "format": "prettier --check . --ignore-path ../../.gitignore", - "migration:sqlite:generate": "drizzle-kit generate --config ./configs/sqlite.config.ts", - "migration:sqlite:run": "drizzle-kit migrate --config ./configs/sqlite.config.ts", + "lint": "eslint", "migration:mysql:generate": "drizzle-kit generate --config ./configs/mysql.config.ts", "migration:mysql:run": "drizzle-kit migrate --config ./configs/mysql.config.ts", - "push:sqlite": "drizzle-kit push --config ./configs/sqlite.config.ts", + "migration:sqlite:generate": "drizzle-kit generate --config ./configs/sqlite.config.ts", + "migration:sqlite:run": "drizzle-kit migrate --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", "studio": "drizzle-kit studio --config ./configs/sqlite.config.ts", "typecheck": "tsc --noEmit" }, + "prettier": "@homarr/prettier-config", "dependencies": { + "@auth/core": "^0.34.2", "@homarr/common": "workspace:^0.1.0", "@homarr/definitions": "workspace:^0.1.0", "@homarr/log": "workspace:^0.1.0", "@paralleldrive/cuid2": "^2.2.2", - "@auth/core": "^0.34.2", "better-sqlite3": "^11.2.1", - "drizzle-orm": "^0.33.0", "dotenv": "^16.4.5", - "mysql2": "3.11.0", - "drizzle-kit": "^0.24.2" + "drizzle-kit": "^0.24.2", + "drizzle-orm": "^0.33.0", + "mysql2": "3.11.0" }, "devDependencies": { "@homarr/eslint-config": "workspace:^0.2.0", @@ -50,6 +51,5 @@ "eslint": "^9.9.1", "prettier": "^3.3.3", "typescript": "^5.5.4" - }, - "prettier": "@homarr/prettier-config" + } } diff --git a/packages/db/schema/mysql.ts b/packages/db/schema/mysql.ts index e45186ac0..32cabdbe5 100644 --- a/packages/db/schema/mysql.ts +++ b/packages/db/schema/mysql.ts @@ -8,6 +8,7 @@ import type { BackgroundImageRepeat, BackgroundImageSize, BoardPermission, + ColorScheme, GroupPermissionKey, IntegrationKind, IntegrationPermission, @@ -30,6 +31,7 @@ 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(), }); export const accounts = mysqlTable( diff --git a/packages/db/schema/sqlite.ts b/packages/db/schema/sqlite.ts index 197dd9c8e..268c19c75 100644 --- a/packages/db/schema/sqlite.ts +++ b/packages/db/schema/sqlite.ts @@ -10,6 +10,7 @@ import type { BackgroundImageRepeat, BackgroundImageSize, BoardPermission, + ColorScheme, GroupPermissionKey, IntegrationKind, IntegrationPermission, @@ -31,6 +32,7 @@ export const users = sqliteTable("user", { homeBoardId: text("homeBoardId").references((): AnySQLiteColumn => boards.id, { onDelete: "set null", }), + colorScheme: text("colorScheme").$type().default("auto").notNull(), }); export const accounts = sqliteTable( diff --git a/packages/definitions/package.json b/packages/definitions/package.json index ce7a906d2..7b025b25f 100644 --- a/packages/definitions/package.json +++ b/packages/definitions/package.json @@ -1,7 +1,8 @@ { "name": "@homarr/definitions", - "private": true, "version": "0.1.0", + "private": true, + "license": "MIT", "type": "module", "exports": { ".": "./index.ts" @@ -13,13 +14,13 @@ ] } }, - "license": "MIT", "scripts": { "clean": "rm -rf .turbo node_modules", - "lint": "eslint", "format": "prettier --check . --ignore-path ../../.gitignore", + "lint": "eslint", "typecheck": "tsc --noEmit" }, + "prettier": "@homarr/prettier-config", "dependencies": { "@homarr/common": "workspace:^0.1.0" }, @@ -29,6 +30,5 @@ "@homarr/tsconfig": "workspace:^0.1.0", "eslint": "^9.9.1", "typescript": "^5.5.4" - }, - "prettier": "@homarr/prettier-config" + } } diff --git a/packages/definitions/src/index.ts b/packages/definitions/src/index.ts index 140b2d924..d2dcd8e0a 100644 --- a/packages/definitions/src/index.ts +++ b/packages/definitions/src/index.ts @@ -5,3 +5,4 @@ export * from "./widget"; export * from "./permissions"; export * from "./docker"; export * from "./auth"; +export * from "./user"; diff --git a/packages/definitions/src/integration.ts b/packages/definitions/src/integration.ts index 7564a6ae8..fbe355d6f 100644 --- a/packages/definitions/src/integration.ts +++ b/packages/definitions/src/integration.ts @@ -63,6 +63,12 @@ export const integrationDefs = { iconUrl: "https://cdn.jsdelivr.net/gh/walkxcode/dashboard-icons@master/png/readarr.png", category: ["calendar"], }, + prowlarr: { + name: "Prowlarr", + secretKinds: [["apiKey"]], + iconUrl: "https://cdn.jsdelivr.net/gh/walkxcode/dashboard-icons@master/png/prowlarr.png", + category: ["indexerManager"], + }, jellyfin: { name: "Jellyfin", secretKinds: [["username", "password"], ["apiKey"]], @@ -103,7 +109,7 @@ export const integrationDefs = { name: "Home Assistant", secretKinds: [["apiKey"]], iconUrl: "https://cdn.jsdelivr.net/gh/walkxcode/dashboard-icons@master/png/home-assistant.png", - category: [], + category: ["smartHomeServer"], }, } satisfies Record< string, @@ -138,4 +144,5 @@ export type IntegrationCategory = | "mediaRequest" | "downloadClient" | "useNetClient" - | "smartHomeServer"; + | "smartHomeServer" + | "indexerManager"; diff --git a/packages/definitions/src/user.ts b/packages/definitions/src/user.ts new file mode 100644 index 000000000..28f24ae7b --- /dev/null +++ b/packages/definitions/src/user.ts @@ -0,0 +1,2 @@ +export const colorSchemes = ["light", "dark", "auto"] as const; +export type ColorScheme = (typeof colorSchemes)[number]; diff --git a/packages/form/package.json b/packages/form/package.json index b61baaeb7..9c150c670 100644 --- a/packages/form/package.json +++ b/packages/form/package.json @@ -1,7 +1,8 @@ { "name": "@homarr/form", - "private": true, "version": "0.1.0", + "private": true, + "license": "MIT", "type": "module", "exports": { ".": "./index.ts" @@ -13,17 +14,17 @@ ] } }, - "license": "MIT", "scripts": { "clean": "rm -rf .turbo node_modules", - "lint": "eslint", "format": "prettier --check . --ignore-path ../../.gitignore", + "lint": "eslint", "typecheck": "tsc --noEmit" }, + "prettier": "@homarr/prettier-config", "dependencies": { - "@mantine/form": "^7.12.2", + "@homarr/translation": "workspace:^0.1.0", "@homarr/validation": "workspace:^0.1.0", - "@homarr/translation": "workspace:^0.1.0" + "@mantine/form": "^7.12.2" }, "devDependencies": { "@homarr/eslint-config": "workspace:^0.2.0", @@ -31,6 +32,5 @@ "@homarr/tsconfig": "workspace:^0.1.0", "eslint": "^9.9.1", "typescript": "^5.5.4" - }, - "prettier": "@homarr/prettier-config" + } } diff --git a/packages/icons/package.json b/packages/icons/package.json index c5801f318..3926129c9 100644 --- a/packages/icons/package.json +++ b/packages/icons/package.json @@ -1,7 +1,8 @@ { "name": "@homarr/icons", - "private": true, "version": "0.1.0", + "private": true, + "license": "MIT", "type": "module", "exports": { ".": "./index.ts" @@ -13,16 +14,16 @@ ] } }, - "license": "MIT", "scripts": { "clean": "rm -rf .turbo node_modules", - "lint": "eslint", "format": "prettier --check . --ignore-path ../../.gitignore", + "lint": "eslint", "typecheck": "tsc --noEmit" }, + "prettier": "@homarr/prettier-config", "dependencies": { - "@homarr/log": "workspace:^0.1.0", - "@homarr/common": "workspace:^0.1.0" + "@homarr/common": "workspace:^0.1.0", + "@homarr/log": "workspace:^0.1.0" }, "devDependencies": { "@homarr/eslint-config": "workspace:^0.2.0", @@ -30,6 +31,5 @@ "@homarr/tsconfig": "workspace:^0.1.0", "eslint": "^9.9.1", "typescript": "^5.5.4" - }, - "prettier": "@homarr/prettier-config" + } } diff --git a/packages/integrations/package.json b/packages/integrations/package.json index 1a42bc3b3..eef4cd8d2 100644 --- a/packages/integrations/package.json +++ b/packages/integrations/package.json @@ -1,7 +1,9 @@ { "name": "@homarr/integrations", - "private": true, "version": "0.1.0", + "private": true, + "license": "MIT", + "type": "module", "exports": { ".": "./index.ts", "./client": "./src/client.ts", @@ -14,21 +16,20 @@ ] } }, - "license": "MIT", - "type": "module", "scripts": { "clean": "rm -rf .turbo node_modules", - "lint": "eslint", "format": "prettier --check . --ignore-path ../../.gitignore", + "lint": "eslint", "typecheck": "tsc --noEmit" }, + "prettier": "@homarr/prettier-config", "dependencies": { "@homarr/common": "workspace:^0.1.0", "@homarr/definitions": "workspace:^0.1.0", "@homarr/log": "workspace:^0.1.0", + "@homarr/translation": "workspace:^0.1.0", "@homarr/validation": "workspace:^0.1.0", - "@jellyfin/sdk": "^0.10.0", - "@homarr/translation": "workspace:^0.1.0" + "@jellyfin/sdk": "^0.10.0" }, "devDependencies": { "@homarr/eslint-config": "workspace:^0.2.0", @@ -36,6 +37,5 @@ "@homarr/tsconfig": "workspace:^0.1.0", "eslint": "^9.9.1", "typescript": "^5.5.4" - }, - "prettier": "@homarr/prettier-config" + } } diff --git a/packages/integrations/src/base/creator.ts b/packages/integrations/src/base/creator.ts index 94f23b70f..27c289ef2 100644 --- a/packages/integrations/src/base/creator.ts +++ b/packages/integrations/src/base/creator.ts @@ -7,6 +7,7 @@ import { JellyseerrIntegration } from "../jellyseerr/jellyseerr-integration"; import { SonarrIntegration } from "../media-organizer/sonarr/sonarr-integration"; import { OverseerrIntegration } from "../overseerr/overseerr-integration"; import { PiHoleIntegration } from "../pi-hole/pi-hole-integration"; +import { ProwlarrIntegration } from "../prowlarr/prowlarr-integration"; import type { Integration, IntegrationInput } from "./integration"; export const integrationCreatorByKind = ( @@ -28,4 +29,5 @@ export const integrationCreators = { sonarr: SonarrIntegration, jellyseerr: JellyseerrIntegration, overseerr: OverseerrIntegration, + prowlarr: ProwlarrIntegration, } satisfies Partial Integration>>; diff --git a/packages/integrations/src/interfaces/indexer-manager/indexer.ts b/packages/integrations/src/interfaces/indexer-manager/indexer.ts new file mode 100644 index 000000000..81393d9e7 --- /dev/null +++ b/packages/integrations/src/interfaces/indexer-manager/indexer.ts @@ -0,0 +1,12 @@ +export interface Indexer { + id: number; + name: string; + url: string; + /** + * Enabled: when the user enable / disable the indexer. + * Status: when there is an error with the indexer site. + * If one of the options are false the indexer is off. + */ + enabled: boolean; + status: boolean; +} diff --git a/packages/integrations/src/prowlarr/prowlarr-integration.ts b/packages/integrations/src/prowlarr/prowlarr-integration.ts new file mode 100644 index 000000000..e023e21a5 --- /dev/null +++ b/packages/integrations/src/prowlarr/prowlarr-integration.ts @@ -0,0 +1,99 @@ +import { Integration } from "../base/integration"; +import { IntegrationTestConnectionError } from "../base/test-connection-error"; +import type { Indexer } from "../interfaces/indexer-manager/indexer"; +import { indexerResponseSchema, statusResponseSchema } from "./prowlarr-types"; + +export class ProwlarrIntegration extends Integration { + public async getIndexersAsync(): Promise { + const apiKey = super.getSecretValue("apiKey"); + + const indexerResponse = await fetch(`${this.integration.url}/api/v1/indexer`, { + headers: { + "X-Api-Key": apiKey, + }, + }); + if (!indexerResponse.ok) { + throw new Error( + `Failed to fetch indexers for ${this.integration.name} (${this.integration.id}): ${indexerResponse.statusText}`, + ); + } + + const statusResponse = await fetch(`${this.integration.url}/api/v1/indexerstatus`, { + headers: { + "X-Api-Key": apiKey, + }, + }); + if (!statusResponse.ok) { + throw new Error( + `Failed to fetch status for ${this.integration.name} (${this.integration.id}): ${statusResponse.statusText}`, + ); + } + + const indexersResult = indexerResponseSchema.array().safeParse(await indexerResponse.json()); + const statusResult = statusResponseSchema.safeParse(await statusResponse.json()); + + const errorMessages: string[] = []; + if (!indexersResult.success) { + errorMessages.push(`Indexers parsing error: ${indexersResult.error.message}`); + } + if (!statusResult.success) { + errorMessages.push(`Status parsing error: ${statusResult.error.message}`); + } + if (!indexersResult.success || !statusResult.success) { + throw new Error( + `Failed to parse indexers for ${this.integration.name} (${this.integration.id}), most likely your api key is wrong:\n${errorMessages.join("\n")}`, + ); + } + + const inactiveIndexerIds = new Set(statusResult.data.map((status: { id: number }) => status.id)); + + const indexers: Indexer[] = indexersResult.data.map((indexer) => ({ + id: indexer.id, + name: indexer.name, + url: indexer.indexerUrls[0] ?? "", + enabled: indexer.enable, + status: inactiveIndexerIds.has(indexer.id), + })); + + return indexers; + } + + public async testAllAsync(): Promise { + const apiKey = super.getSecretValue("apiKey"); + const response = await fetch(`${this.integration.url}/api/v1/indexer/testall`, { + headers: { + "X-Api-Key": apiKey, + }, + }); + + if (!response.ok) { + throw new Error( + `Failed to test all indexers for ${this.integration.name} (${this.integration.id}): ${response.statusText}`, + ); + } + } + + public async testConnectionAsync(): Promise { + const apiKey = super.getSecretValue("apiKey"); + + await super.handleTestConnectionResponseAsync({ + queryFunctionAsync: async () => { + return await fetch(`${this.integration.url}/api`, { + headers: { + "X-Api-Key": apiKey, + }, + }); + }, + handleResponseAsync: async (response) => { + try { + const result = (await response.json()) as unknown; + if (typeof result === "object" && result !== null) return; + } catch { + throw new IntegrationTestConnectionError("invalidJson"); + } + + throw new IntegrationTestConnectionError("invalidCredentials"); + }, + }); + } +} diff --git a/packages/integrations/src/prowlarr/prowlarr-types.ts b/packages/integrations/src/prowlarr/prowlarr-types.ts new file mode 100644 index 000000000..9b61f74f0 --- /dev/null +++ b/packages/integrations/src/prowlarr/prowlarr-types.ts @@ -0,0 +1,14 @@ +import { z } from "@homarr/validation"; + +export const indexerResponseSchema = z.object({ + id: z.number(), + indexerUrls: z.array(z.string()), + name: z.string(), + enable: z.boolean(), +}); + +export const statusResponseSchema = z.array( + z.object({ + id: z.number(), + }), +); diff --git a/packages/log/package.json b/packages/log/package.json index 6ab1677e8..b5830fbee 100644 --- a/packages/log/package.json +++ b/packages/log/package.json @@ -1,7 +1,8 @@ { "name": "@homarr/log", - "private": true, "version": "0.1.0", + "private": true, + "license": "MIT", "type": "module", "exports": { ".": { @@ -17,13 +18,13 @@ ] } }, - "license": "MIT", "scripts": { "clean": "rm -rf .turbo node_modules", - "lint": "eslint", "format": "prettier --check . --ignore-path ../../.gitignore", + "lint": "eslint", "typecheck": "tsc --noEmit" }, + "prettier": "@homarr/prettier-config", "dependencies": { "ioredis": "5.4.1", "superjson": "2.2.1", @@ -35,6 +36,5 @@ "@homarr/tsconfig": "workspace:^0.1.0", "eslint": "^9.9.1", "typescript": "^5.5.4" - }, - "prettier": "@homarr/prettier-config" + } } diff --git a/packages/modals/package.json b/packages/modals/package.json index 52cc86a17..d0065baa4 100644 --- a/packages/modals/package.json +++ b/packages/modals/package.json @@ -1,7 +1,8 @@ { "name": "@homarr/modals", - "private": true, "version": "0.1.0", + "private": true, + "license": "MIT", "type": "module", "exports": { ".": "./index.ts" @@ -13,19 +14,19 @@ ] } }, - "license": "MIT", "scripts": { "clean": "rm -rf .turbo node_modules", - "lint": "eslint", "format": "prettier --check . --ignore-path ../../.gitignore", + "lint": "eslint", "typecheck": "tsc --noEmit" }, + "prettier": "@homarr/prettier-config", "dependencies": { - "@homarr/ui": "workspace:^0.1.0", "@homarr/translation": "workspace:^0.1.0", - "react": "^18.3.1", + "@homarr/ui": "workspace:^0.1.0", "@mantine/core": "^7.12.2", - "@mantine/hooks": "^7.12.2" + "@mantine/hooks": "^7.12.2", + "react": "^18.3.1" }, "devDependencies": { "@homarr/eslint-config": "workspace:^0.2.0", @@ -33,6 +34,5 @@ "@homarr/tsconfig": "workspace:^0.1.0", "eslint": "^9.9.1", "typescript": "^5.5.4" - }, - "prettier": "@homarr/prettier-config" + } } diff --git a/packages/notifications/package.json b/packages/notifications/package.json index b8598aefa..499a5a89c 100644 --- a/packages/notifications/package.json +++ b/packages/notifications/package.json @@ -1,7 +1,8 @@ { "name": "@homarr/notifications", - "private": true, "version": "0.1.0", + "private": true, + "license": "MIT", "type": "module", "exports": { ".": "./index.ts", @@ -14,16 +15,16 @@ ] } }, - "license": "MIT", "scripts": { "clean": "rm -rf .turbo node_modules", - "lint": "eslint", "format": "prettier --check . --ignore-path ../../.gitignore", + "lint": "eslint", "typecheck": "tsc --noEmit" }, + "prettier": "@homarr/prettier-config", "dependencies": { - "@mantine/notifications": "^7.12.2", "@homarr/ui": "workspace:^0.1.0", + "@mantine/notifications": "^7.12.2", "@tabler/icons-react": "^3.14.0" }, "devDependencies": { @@ -32,6 +33,5 @@ "@homarr/tsconfig": "workspace:^0.1.0", "eslint": "^9.9.1", "typescript": "^5.5.4" - }, - "prettier": "@homarr/prettier-config" + } } diff --git a/packages/ping/package.json b/packages/ping/package.json index 3e3249610..741a63917 100644 --- a/packages/ping/package.json +++ b/packages/ping/package.json @@ -1,7 +1,9 @@ { "name": "@homarr/ping", - "private": true, "version": "0.1.0", + "private": true, + "license": "MIT", + "type": "module", "exports": { ".": "./index.ts" }, @@ -12,14 +14,13 @@ ] } }, - "license": "MIT", - "type": "module", "scripts": { "clean": "rm -rf .turbo node_modules", - "lint": "eslint", "format": "prettier --check . --ignore-path ../../.gitignore", + "lint": "eslint", "typecheck": "tsc --noEmit" }, + "prettier": "@homarr/prettier-config", "dependencies": { "@homarr/common": "workspace:^0.1.0", "@homarr/log": "workspace:^0.1.0" @@ -30,6 +31,5 @@ "@homarr/tsconfig": "workspace:^0.1.0", "eslint": "^9.9.1", "typescript": "^5.5.4" - }, - "prettier": "@homarr/prettier-config" + } } diff --git a/packages/redis/package.json b/packages/redis/package.json index 55f22c3a9..d6de9128d 100644 --- a/packages/redis/package.json +++ b/packages/redis/package.json @@ -1,7 +1,9 @@ { "name": "@homarr/redis", - "private": true, "version": "0.1.0", + "private": true, + "license": "MIT", + "type": "module", "exports": { ".": "./index.ts" }, @@ -12,21 +14,20 @@ ] } }, - "license": "MIT", - "type": "module", "scripts": { "clean": "rm -rf .turbo node_modules", - "lint": "eslint", "format": "prettier --check . --ignore-path ../../.gitignore", + "lint": "eslint", "typecheck": "tsc --noEmit" }, + "prettier": "@homarr/prettier-config", "dependencies": { - "ioredis": "5.4.1", - "superjson": "2.2.1", - "@homarr/log": "workspace:^", - "@homarr/db": "workspace:^", "@homarr/common": "workspace:^", - "@homarr/definitions": "workspace:^" + "@homarr/db": "workspace:^", + "@homarr/definitions": "workspace:^", + "@homarr/log": "workspace:^", + "ioredis": "5.4.1", + "superjson": "2.2.1" }, "devDependencies": { "@homarr/eslint-config": "workspace:^0.2.0", @@ -34,6 +35,5 @@ "@homarr/tsconfig": "workspace:^0.1.0", "eslint": "^9.9.1", "typescript": "^5.5.4" - }, - "prettier": "@homarr/prettier-config" + } } diff --git a/packages/server-settings/package.json b/packages/server-settings/package.json index 95d5e7272..b513928b9 100644 --- a/packages/server-settings/package.json +++ b/packages/server-settings/package.json @@ -1,7 +1,9 @@ { "name": "@homarr/server-settings", - "private": true, "version": "0.1.0", + "private": true, + "license": "MIT", + "type": "module", "exports": { ".": "./index.ts" }, @@ -12,20 +14,18 @@ ] } }, - "type": "module", - "license": "MIT", "scripts": { "clean": "rm -rf .turbo node_modules", - "lint": "eslint", "format": "prettier --check . --ignore-path ../../.gitignore", + "lint": "eslint", "typecheck": "tsc --noEmit" }, + "prettier": "@homarr/prettier-config", "devDependencies": { "@homarr/eslint-config": "workspace:^0.2.0", "@homarr/prettier-config": "workspace:^0.1.0", "@homarr/tsconfig": "workspace:^0.1.0", "eslint": "^9.9.1", "typescript": "^5.5.4" - }, - "prettier": "@homarr/prettier-config" + } } diff --git a/packages/spotlight/package.json b/packages/spotlight/package.json index 9453fce54..cd58026f6 100644 --- a/packages/spotlight/package.json +++ b/packages/spotlight/package.json @@ -1,7 +1,8 @@ { "name": "@homarr/spotlight", - "private": true, "version": "0.1.0", + "private": true, + "license": "MIT", "type": "module", "exports": { ".": "./index.ts", @@ -14,22 +15,22 @@ ] } }, - "license": "MIT", "scripts": { "clean": "rm -rf .turbo node_modules", - "lint": "eslint", "format": "prettier --check . --ignore-path ../../.gitignore", + "lint": "eslint", "typecheck": "tsc --noEmit" }, + "prettier": "@homarr/prettier-config", "dependencies": { - "@homarr/ui": "workspace:^0.1.0", "@homarr/translation": "workspace:^0.1.0", + "@homarr/ui": "workspace:^0.1.0", "@mantine/core": "^7.12.2", "@mantine/hooks": "^7.12.2", "@mantine/spotlight": "^7.12.2", "@tabler/icons-react": "^3.14.0", "jotai": "^2.9.3", - "next": "^14.2.7", + "next": "^14.2.8", "react": "^18.3.1", "use-deep-compare-effect": "^1.8.1" }, @@ -39,6 +40,5 @@ "@homarr/tsconfig": "workspace:^0.1.0", "eslint": "^9.9.1", "typescript": "^5.5.4" - }, - "prettier": "@homarr/prettier-config" + } } diff --git a/packages/translation/package.json b/packages/translation/package.json index 22418ea26..1afd60b4f 100644 --- a/packages/translation/package.json +++ b/packages/translation/package.json @@ -1,7 +1,8 @@ { "name": "@homarr/translation", - "private": true, "version": "0.1.0", + "private": true, + "license": "MIT", "type": "module", "exports": { ".": "./index.ts", @@ -16,13 +17,13 @@ ] } }, - "license": "MIT", "scripts": { "clean": "rm -rf .turbo node_modules", - "lint": "eslint", "format": "prettier --check . --ignore-path ../../.gitignore", + "lint": "eslint", "typecheck": "tsc --noEmit" }, + "prettier": "@homarr/prettier-config", "dependencies": { "dayjs": "^1.11.13", "mantine-react-table": "2.0.0-beta.6", @@ -34,6 +35,5 @@ "@homarr/tsconfig": "workspace:^0.1.0", "eslint": "^9.9.1", "typescript": "^5.5.4" - }, - "prettier": "@homarr/prettier-config" + } } diff --git a/packages/ui/package.json b/packages/ui/package.json index 7e954c306..4777dfd96 100644 --- a/packages/ui/package.json +++ b/packages/ui/package.json @@ -1,7 +1,8 @@ { "name": "@homarr/ui", - "private": true, "version": "0.1.0", + "private": true, + "license": "MIT", "type": "module", "exports": { ".": "./index.ts", @@ -15,24 +16,24 @@ ] } }, - "license": "MIT", "scripts": { "clean": "rm -rf .turbo node_modules", - "lint": "eslint", "format": "prettier --check . --ignore-path ../../.gitignore", + "lint": "eslint", "typecheck": "tsc --noEmit" }, + "prettier": "@homarr/prettier-config", "dependencies": { - "@homarr/log": "workspace:^0.1.0", - "@homarr/validation": "workspace:^0.1.0", "@homarr/common": "workspace:^0.1.0", + "@homarr/log": "workspace:^0.1.0", "@homarr/translation": "workspace:^0.1.0", + "@homarr/validation": "workspace:^0.1.0", "@mantine/core": "^7.12.2", "@mantine/dates": "^7.12.2", "@mantine/hooks": "^7.12.2", "@tabler/icons-react": "^3.14.0", "mantine-react-table": "2.0.0-beta.6", - "next": "^14.2.7", + "next": "^14.2.8", "react": "^18.3.1" }, "devDependencies": { @@ -42,6 +43,5 @@ "@types/css-modules": "^1.0.5", "eslint": "^9.9.1", "typescript": "^5.5.4" - }, - "prettier": "@homarr/prettier-config" + } } diff --git a/packages/validation/package.json b/packages/validation/package.json index b50247501..4e716b625 100644 --- a/packages/validation/package.json +++ b/packages/validation/package.json @@ -1,7 +1,8 @@ { "name": "@homarr/validation", - "private": true, "version": "0.1.0", + "private": true, + "license": "MIT", "type": "module", "exports": { ".": "./index.ts", @@ -14,17 +15,17 @@ ] } }, - "license": "MIT", "scripts": { "clean": "rm -rf .turbo node_modules", - "lint": "eslint", "format": "prettier --check . --ignore-path ../../.gitignore", + "lint": "eslint", "typecheck": "tsc --noEmit" }, + "prettier": "@homarr/prettier-config", "dependencies": { - "zod": "^3.23.8", "@homarr/definitions": "workspace:^0.1.0", - "@homarr/translation": "workspace:^0.1.0" + "@homarr/translation": "workspace:^0.1.0", + "zod": "^3.23.8" }, "devDependencies": { "@homarr/eslint-config": "workspace:^0.2.0", @@ -32,6 +33,5 @@ "@homarr/tsconfig": "workspace:^0.1.0", "eslint": "^9.9.1", "typescript": "^5.5.4" - }, - "prettier": "@homarr/prettier-config" + } } diff --git a/packages/validation/src/user.ts b/packages/validation/src/user.ts index 5d26be3d3..1057265cd 100644 --- a/packages/validation/src/user.ts +++ b/packages/validation/src/user.ts @@ -1,7 +1,9 @@ import { z } from "zod"; +import { colorSchemes } from "@homarr/definitions"; import type { TranslationObject } from "@homarr/translation"; +import { zodEnumFromArray } from "./enums"; import { createCustomErrorParams } from "./form/i18n"; const usernameSchema = z.string().min(3).max(255); @@ -98,6 +100,10 @@ const changeHomeBoardSchema = z.object({ homeBoardId: z.string().min(1), }); +const changeColorSchemeSchema = z.object({ + colorScheme: zodEnumFromArray(colorSchemes), +}); + export const userSchemas = { signIn: signInSchema, registration: registrationSchema, @@ -109,4 +115,5 @@ export const userSchemas = { changePassword: changePasswordSchema, changeHomeBoard: changeHomeBoardSchema, changePasswordApi: changePasswordApiSchema, + changeColorScheme: changeColorSchemeSchema, }; diff --git a/packages/widgets/package.json b/packages/widgets/package.json index 3b44765b7..9243dfcb9 100644 --- a/packages/widgets/package.json +++ b/packages/widgets/package.json @@ -1,7 +1,8 @@ { "name": "@homarr/widgets", - "private": true, "version": "0.1.0", + "private": true, + "license": "MIT", "type": "module", "exports": { ".": "./index.ts", @@ -14,13 +15,13 @@ ] } }, - "license": "MIT", "scripts": { "clean": "rm -rf .turbo node_modules", - "lint": "eslint", "format": "prettier --check . --ignore-path ../../.gitignore", + "lint": "eslint", "typecheck": "tsc --noEmit" }, + "prettier": "@homarr/prettier-config", "dependencies": { "@extractus/feed-extractor": "^7.1.3", "@homarr/api": "workspace:^0.1.0", @@ -35,8 +36,8 @@ "@homarr/translation": "workspace:^0.1.0", "@homarr/ui": "workspace:^0.1.0", "@homarr/validation": "workspace:^0.1.0", - "@mantine/hooks": "^7.12.2", "@mantine/core": "^7.12.2", + "@mantine/hooks": "^7.12.2", "@tabler/icons-react": "^3.14.0", "@tiptap/extension-color": "2.6.6", "@tiptap/extension-highlight": "2.6.6", @@ -55,8 +56,8 @@ "@tiptap/starter-kit": "^2.6.6", "clsx": "^2.1.1", "dayjs": "^1.11.13", - "next": "^14.2.7", "mantine-react-table": "2.0.0-beta.6", + "next": "^14.2.8", "react": "^18.3.1", "video.js": "^8.17.3" }, @@ -67,6 +68,5 @@ "@types/video.js": "^7.3.58", "eslint": "^9.9.1", "typescript": "^5.5.4" - }, - "prettier": "@homarr/prettier-config" + } } diff --git a/packages/widgets/src/dns-hole/controls/component.tsx b/packages/widgets/src/dns-hole/controls/component.tsx index 0859dc728..dd13969c3 100644 --- a/packages/widgets/src/dns-hole/controls/component.tsx +++ b/packages/widgets/src/dns-hole/controls/component.tsx @@ -1,7 +1,7 @@ "use client"; import { useEffect, useState } from "react"; -import { ActionIcon, Badge, Box, Button, Card, Flex, Image, Stack, Text, Tooltip, UnstyledButton } from "@mantine/core"; +import { ActionIcon, Badge, Button, Card, Flex, Image, Stack, Text, Tooltip, UnstyledButton } from "@mantine/core"; import { useDisclosure } from "@mantine/hooks"; import { IconClockPause, IconPlayerPlay, IconPlayerStop } from "@tabler/icons-react"; @@ -76,7 +76,7 @@ export default function DnsHoleControlsWidget({ options, integrationIds }: Widge return ( {options.showToggleAllButtons && ( - +