From 5b9605037aff96d3dedd12c49d6d87e19b9f6674 Mon Sep 17 00:00:00 2001 From: DecDuck Date: Thu, 31 Jul 2025 18:10:34 +1000 Subject: [PATCH 1/5] fix: small merge fixes --- pages/news.vue | 1 - prisma/schema/content.prisma | 101 ----------------------------------- 2 files changed, 102 deletions(-) delete mode 100644 prisma/schema/content.prisma diff --git a/pages/news.vue b/pages/news.vue index a984018e..ee9fac4b 100644 --- a/pages/news.vue +++ b/pages/news.vue @@ -105,7 +105,6 @@ const news = useNews(); if (!news.value) { await fetchNews(); - console.log("fetched news"); } const { t } = useI18n(); diff --git a/prisma/schema/content.prisma b/prisma/schema/content.prisma deleted file mode 100644 index f64fdac5..00000000 --- a/prisma/schema/content.prisma +++ /dev/null @@ -1,101 +0,0 @@ -enum MetadataSource { - Manual - GiantBomb -} - -model Game { - id String @id @default(uuid()) - - metadataSource MetadataSource - metadataId String - created DateTime @default(now()) - - // Any field prefixed with m is filled in from metadata - // Acts as a cache so we can search and filter it - mName String // Name of game - mShortDescription String // Short description - mDescription String // Supports markdown - mDevelopers Developer[] - mPublishers Publisher[] - mReleased DateTime // When the game was released - - mReviewCount Int - mReviewRating Float // 0 to 1 - - mIconId String // linked to objects in s3 - mBannerId String // linked to objects in s3 - mCoverId String - mImageCarousel String[] // linked to below array - mImageLibrary String[] // linked to objects in s3 - - versions GameVersion[] - libraryBasePath String @unique // Base dir for all the game versions - - collections CollectionEntry[] - - @@unique([metadataSource, metadataId], name: "metadataKey") -} - -// A particular set of files that relate to the version -model GameVersion { - gameId String - game Game @relation(fields: [gameId], references: [id], onDelete: Cascade) - versionName String // Sub directory for the game files - - created DateTime @default(now()) - - platform Platform - - launchCommand String @default("") // Command to run to start. Platform-specific. Windows games on Linux will wrap this command in Proton/Wine - launchArgs String[] - setupCommand String @default("") // Command to setup game (dependencies and such) - setupArgs String[] - onlySetup Boolean @default(false) - - umuIdOverride String? - - dropletManifest Json // Results from droplet - - versionIndex Int - delta Boolean @default(false) - - @@id([gameId, versionName]) -} - -model Developer { - id String @id @default(uuid()) - - metadataSource MetadataSource - metadataId String - metadataOriginalQuery String - - mName String - mShortDescription String - mDescription String - mLogo String - mBanner String - mWebsite String - - games Game[] - - @@unique([metadataSource, metadataId, metadataOriginalQuery], name: "metadataKey") -} - -model Publisher { - id String @id @default(uuid()) - - metadataSource MetadataSource - metadataId String - metadataOriginalQuery String - - mName String - mShortDescription String - mDescription String - mLogo String - mBanner String - mWebsite String - - games Game[] - - @@unique([metadataSource, metadataId, metadataOriginalQuery], name: "metadataKey") -} From a0cab177d77f28b60d25c8560d133db0ceaee825 Mon Sep 17 00:00:00 2001 From: DecDuck Date: Thu, 31 Jul 2025 20:14:55 +1000 Subject: [PATCH 2/5] feat: initial setup wizard --- components/LanguageSelector.vue | 153 +------------ components/LanguageSelectorListbox.vue | 158 +++++++++++++ components/Setup/Account.vue | 161 +++++++++++++ components/Setup/Library.vue | 15 ++ composables/request.ts | 2 +- i18n/locales/en_au.json | 6 +- i18n/locales/en_us.json | 20 ++ pages/admin/library/sources/index.vue | 11 +- pages/auth/register.vue | 4 + pages/setup.vue | 215 ++++++++++++++++++ server/api/v1/admin/auth/index.get.ts | 2 +- .../v1/admin/auth/invitation/index.post.ts | 1 + server/api/v1/admin/index.get.ts | 7 + .../v1/admin/library/sources/index.delete.ts | 1 + .../api/v1/admin/library/sources/index.get.ts | 2 +- .../v1/admin/library/sources/index.patch.ts | 1 + .../v1/admin/library/sources/index.post.ts | 1 + server/api/v1/setup.post.ts | 20 ++ server/internal/acls/descriptions.ts | 3 + server/internal/acls/index.ts | 15 +- server/plugins/01.system-init.ts | 1 + server/plugins/02.setup-admin.ts | 32 ++- 22 files changed, 659 insertions(+), 172 deletions(-) create mode 100644 components/LanguageSelectorListbox.vue create mode 100644 components/Setup/Account.vue create mode 100644 components/Setup/Library.vue create mode 100644 pages/setup.vue create mode 100644 server/api/v1/admin/index.get.ts create mode 100644 server/api/v1/setup.post.ts diff --git a/components/LanguageSelector.vue b/components/LanguageSelector.vue index 496f8e13..9d873c1d 100644 --- a/components/LanguageSelector.vue +++ b/components/LanguageSelector.vue @@ -1,80 +1,6 @@ - - diff --git a/components/LanguageSelectorListbox.vue b/components/LanguageSelectorListbox.vue new file mode 100644 index 00000000..edb22e03 --- /dev/null +++ b/components/LanguageSelectorListbox.vue @@ -0,0 +1,158 @@ + + + diff --git a/components/Setup/Account.vue b/components/Setup/Account.vue new file mode 100644 index 00000000..5008af76 --- /dev/null +++ b/components/Setup/Account.vue @@ -0,0 +1,161 @@ + + + diff --git a/components/Setup/Library.vue b/components/Setup/Library.vue new file mode 100644 index 00000000..3d4b3f58 --- /dev/null +++ b/components/Setup/Library.vue @@ -0,0 +1,15 @@ + + + diff --git a/composables/request.ts b/composables/request.ts index 963de6d1..8396b8d2 100644 --- a/composables/request.ts +++ b/composables/request.ts @@ -67,7 +67,7 @@ export const $dropFetch: DropFetch = async (rawRequest, opts) => { try { const data = await $fetch(request, { ...opts, - headers: { ...opts?.headers, ...headers }, + headers: { ...headers, ...opts?.headers }, }); if (import.meta.server) state.value = data; return data; diff --git a/i18n/locales/en_au.json b/i18n/locales/en_au.json index 0967ef42..27d8b005 100644 --- a/i18n/locales/en_au.json +++ b/i18n/locales/en_au.json @@ -1 +1,5 @@ -{} +{ + "setup": { + "welcome": "G'day." + } +} diff --git a/i18n/locales/en_us.json b/i18n/locales/en_us.json index 67408f92..3c514b55 100644 --- a/i18n/locales/en_us.json +++ b/i18n/locales/en_us.json @@ -63,6 +63,26 @@ "signout": "Signout", "username": "Username" }, + "setup": { + "welcome": "Hey there.", + "welcomeDescription": "Welcome to Drop setup wizard. It will walk you through configuring Drop for the first time, and how it works.", + "auth": { + "title": "Authentication", + "description": "Authentication in Drop happens through multiple configured 'providers'. Each one can allow users to sign-in through their method. To get started, have at least one authentication provider enabled, and create an account through it.", + "docs": "Documentation {arrow}", + "enabled": "Enabled?", + "simple": { + "title": "Simple authentication", + "description": "Simple authentication uses username/password to authentication users. It is enabled by default if no other authentication provider is enabled.", + "register": "Register as admin {arrow}" + }, + "openid": { + "title": "OpenID Connect", + "description": "OpenID Connect (OIDC) is an OAuth2 extension commonly supported. Drop requires OIDC configuration to be done via environment variables.", + "skip": "I have a user with OIDC" + } + } + }, "cancel": "Cancel", "chars": { "arrow": "→", diff --git a/pages/admin/library/sources/index.vue b/pages/admin/library/sources/index.vue index 251da854..2fc3bbda 100644 --- a/pages/admin/library/sources/index.vue +++ b/pages/admin/library/sources/index.vue @@ -296,8 +296,15 @@ useHead({ const { t } = useI18n(); +// Optional token for setup wizard +const { token } = defineProps<{ token?: string }>(); + +const headers = token ? { Authorization: token } : undefined; + const sources = ref( - await $dropFetch("/api/v1/admin/library/sources"), + await $dropFetch("/api/v1/admin/library/sources", { + headers, + }), ); const editIndex = ref(undefined); @@ -345,6 +352,7 @@ async function performActionSource() { options: sourceConfig.value, }, method: createMode ? "POST" : "PATCH", + headers, }, ); if (createMode) { @@ -394,6 +402,7 @@ async function deleteSource(index: number) { await $dropFetch("/api/v1/admin/library/sources", { method: "DELETE", body: { id: source.id }, + headers, }); } catch (e) { createModal( diff --git a/pages/auth/register.vue b/pages/auth/register.vue index d2820ae5..0784eb13 100644 --- a/pages/auth/register.vue +++ b/pages/auth/register.vue @@ -264,6 +264,10 @@ function register_wrapper() { loading.value = true; register() .then(() => { + if (route.query.after == "close") { + window.close(); + return; + } router.push("/auth/signin"); }) .catch((response) => { diff --git a/pages/setup.vue b/pages/setup.vue new file mode 100644 index 00000000..c2c0e212 --- /dev/null +++ b/pages/setup.vue @@ -0,0 +1,215 @@ + + + + + diff --git a/server/api/v1/admin/auth/index.get.ts b/server/api/v1/admin/auth/index.get.ts index 6d975e94..4ea15237 100644 --- a/server/api/v1/admin/auth/index.get.ts +++ b/server/api/v1/admin/auth/index.get.ts @@ -3,7 +3,7 @@ import aclManager from "~/server/internal/acls"; import authManager from "~/server/internal/auth"; export default defineEventHandler(async (h3) => { - const allowed = await aclManager.allowSystemACL(h3, ["auth:read"]); + const allowed = await aclManager.allowSystemACL(h3, ["auth:read", "setup"]); if (!allowed) throw createError({ statusCode: 403 }); const enabledAuthManagers = authManager.getAuthProviders(); diff --git a/server/api/v1/admin/auth/invitation/index.post.ts b/server/api/v1/admin/auth/invitation/index.post.ts index 50696c2f..69d36497 100644 --- a/server/api/v1/admin/auth/invitation/index.post.ts +++ b/server/api/v1/admin/auth/invitation/index.post.ts @@ -14,6 +14,7 @@ const CreateInvite = SharedRegisterValidator.partial() export default defineEventHandler(async (h3) => { const allowed = await aclManager.allowSystemACL(h3, [ "auth:simple:invitation:new", + "setup", ]); if (!allowed) throw createError({ statusCode: 403 }); diff --git a/server/api/v1/admin/index.get.ts b/server/api/v1/admin/index.get.ts new file mode 100644 index 00000000..4a12b63f --- /dev/null +++ b/server/api/v1/admin/index.get.ts @@ -0,0 +1,7 @@ +import aclManager from "~/server/internal/acls" + +export default defineEventHandler(async (h3) => { + const allowed = await aclManager.allowSystemACL(h3, []); + if(!allowed) return false; + return true; +}) \ No newline at end of file diff --git a/server/api/v1/admin/library/sources/index.delete.ts b/server/api/v1/admin/library/sources/index.delete.ts index 8067f643..165a9b24 100644 --- a/server/api/v1/admin/library/sources/index.delete.ts +++ b/server/api/v1/admin/library/sources/index.delete.ts @@ -12,6 +12,7 @@ export default defineEventHandler<{ body: typeof DeleteLibrarySource.infer }>( async (h3) => { const allowed = await aclManager.allowSystemACL(h3, [ "library:sources:delete", + "setup", ]); if (!allowed) throw createError({ statusCode: 403 }); diff --git a/server/api/v1/admin/library/sources/index.get.ts b/server/api/v1/admin/library/sources/index.get.ts index 573be59b..b1d99aa8 100644 --- a/server/api/v1/admin/library/sources/index.get.ts +++ b/server/api/v1/admin/library/sources/index.get.ts @@ -5,7 +5,7 @@ import libraryManager from "~/server/internal/library"; export type WorkingLibrarySource = LibraryModel & { working: boolean }; export default defineEventHandler(async (h3) => { - const allowed = await aclManager.allowSystemACL(h3, ["library:sources:read"]); + const allowed = await aclManager.allowSystemACL(h3, ["library:sources:read", "setup"]); if (!allowed) throw createError({ statusCode: 403 }); const sources = await libraryManager.fetchLibraries(); diff --git a/server/api/v1/admin/library/sources/index.patch.ts b/server/api/v1/admin/library/sources/index.patch.ts index be0ccc7a..2972f0e9 100644 --- a/server/api/v1/admin/library/sources/index.patch.ts +++ b/server/api/v1/admin/library/sources/index.patch.ts @@ -16,6 +16,7 @@ export default defineEventHandler<{ body: typeof UpdateLibrarySource.infer }>( async (h3) => { const allowed = await aclManager.allowSystemACL(h3, [ "library:sources:update", + "setup" ]); if (!allowed) throw createError({ statusCode: 403 }); diff --git a/server/api/v1/admin/library/sources/index.post.ts b/server/api/v1/admin/library/sources/index.post.ts index 31a703ff..4ce6dc09 100644 --- a/server/api/v1/admin/library/sources/index.post.ts +++ b/server/api/v1/admin/library/sources/index.post.ts @@ -18,6 +18,7 @@ export default defineEventHandler<{ body: typeof CreateLibrarySource.infer }>( async (h3) => { const allowed = await aclManager.allowSystemACL(h3, [ "library:sources:new", + "setup" ]); if (!allowed) throw createError({ statusCode: 403 }); diff --git a/server/api/v1/setup.post.ts b/server/api/v1/setup.post.ts new file mode 100644 index 00000000..acd83f64 --- /dev/null +++ b/server/api/v1/setup.post.ts @@ -0,0 +1,20 @@ +import { APITokenMode } from "~/prisma/client/enums"; +import aclManager from "~/server/internal/acls"; +import prisma from "~/server/internal/db/database"; + +export default defineEventHandler(async (h3) => { + const allowed = await aclManager.allowSystemACL(h3, ["setup"]); + if (!allowed) + throw createError({ + statusCode: 403, + statusMessage: "Must use a setup token.", + }); + await prisma.aPIToken.deleteMany({ + where: { + mode: APITokenMode.System, + acls: { + hasSome: ["setup"], + }, + }, + }); +}); diff --git a/server/internal/acls/descriptions.ts b/server/internal/acls/descriptions.ts index 98b919da..ebb8d50a 100644 --- a/server/internal/acls/descriptions.ts +++ b/server/internal/acls/descriptions.ts @@ -44,6 +44,9 @@ export const userACLDescriptions: ObjectFromList = { }; export const systemACLDescriptions: ObjectFromList = { + setup: + "All permissions required to setup a new Drop instance (setup wizard).", + "auth:read": "Fetch the list of enabled authentication mechanisms configured.", "auth:simple:invitation:read": "Fetch simple auth invitations.", diff --git a/server/internal/acls/index.ts b/server/internal/acls/index.ts index 2c2f1c61..500105cb 100644 --- a/server/internal/acls/index.ts +++ b/server/internal/acls/index.ts @@ -2,6 +2,7 @@ import { APITokenMode } from "~/prisma/client/enums"; import prisma from "../db/database"; import sessionHandler from "../session"; import type { MinimumRequestObject } from "~/server/h3"; +import { logger } from "../logging"; export const userACLs = [ "read", @@ -41,6 +42,8 @@ const userACLPrefix = "user:"; export type UserACL = Array<(typeof userACLs)[number]>; export const systemACLs = [ + "setup", + "auth:read", "auth:simple:invitation:read", "auth:simple:invitation:new", @@ -167,9 +170,11 @@ class ACLManager { const user = await prisma.user.findUnique({ where: { id: userSession.userId }, }); - if (!user) return false; - if (user.admin) return true; - return false; + if (user) { + if (!user) return false; + if (user.admin) return true; + return false; + } } const authorizationToken = this.getAuthorizationToken(request); @@ -179,6 +184,10 @@ class ACLManager { }); if (!token) return false; if (token.mode != APITokenMode.System) return false; + + // If empty, we just want to check we are an admin *at all*, not specific ACLs + if(acls.length == 0) return true; + for (const acl of acls) { const tokenACLIndex = token.acls.findIndex((e) => e == acl); if (tokenACLIndex != -1) return true; diff --git a/server/plugins/01.system-init.ts b/server/plugins/01.system-init.ts index a28edbe7..9f56c608 100644 --- a/server/plugins/01.system-init.ts +++ b/server/plugins/01.system-init.ts @@ -1,3 +1,4 @@ +import { APITokenMode } from "~/prisma/client/enums"; import prisma from "~/server/internal/db/database"; export default defineNitroPlugin(async (_nitro) => { diff --git a/server/plugins/02.setup-admin.ts b/server/plugins/02.setup-admin.ts index 1d4a1283..25a87043 100644 --- a/server/plugins/02.setup-admin.ts +++ b/server/plugins/02.setup-admin.ts @@ -1,6 +1,18 @@ +import { APITokenMode } from "~/prisma/client/enums"; import prisma from "~/server/internal/db/database"; +import { systemConfig } from "../internal/config/sys-conf"; +import { logger } from "../internal/logging"; export default defineNitroPlugin(async (_nitro) => { + await prisma.aPIToken.deleteMany({ + where: { + acls: { + hasSome: ["setup"], + }, + mode: APITokenMode.System, + }, + }); + const userCount = await prisma.user.count({ where: { id: { not: "system" } }, }); @@ -10,18 +22,14 @@ export default defineNitroPlugin(async (_nitro) => { // but has not been configured // so it should be in-place - // Create admin invitation - await prisma.invitation.upsert({ - where: { - id: "admin", - }, - create: { - id: "admin", - isAdmin: true, - expires: new Date("4096-01-01"), - }, - update: { - isAdmin: true, + const token = await prisma.aPIToken.create({ + data: { + name: "Setup Wizard", + mode: APITokenMode.System, + acls: ["setup"], }, }); + + const setupUrl = `${systemConfig.getExternalUrl()}/setup?token=${token.token}`; + logger.info(`Open ${setupUrl} in a browser to get started with Drop.`); }); From b91fc9853a832dcf6172f1eb3fa17ca19da42728 Mon Sep 17 00:00:00 2001 From: DecDuck Date: Thu, 31 Jul 2025 20:28:01 +1000 Subject: [PATCH 3/5] fix: last few localization items --- i18n/locales/en_us.json | 10 ++++++++++ pages/setup.vue | 28 ++++++++++++++++++---------- 2 files changed, 28 insertions(+), 10 deletions(-) diff --git a/i18n/locales/en_us.json b/i18n/locales/en_us.json index 3c514b55..0f032544 100644 --- a/i18n/locales/en_us.json +++ b/i18n/locales/en_us.json @@ -81,6 +81,16 @@ "description": "OpenID Connect (OIDC) is an OAuth2 extension commonly supported. Drop requires OIDC configuration to be done via environment variables.", "skip": "I have a user with OIDC" } + }, + "stages": { + "account": { + "name": "Setup your admin account.", + "description": "You need at least one account to start using Drop." + }, + "library": { + "name": "Create a library.", + "description": "Add at least one library source to use Drop." + } } }, "cancel": "Cancel", diff --git a/pages/setup.vue b/pages/setup.vue index c2c0e212..13b89795 100644 --- a/pages/setup.vue +++ b/pages/setup.vue @@ -149,6 +149,12 @@ import { breakpointsTailwind, useBreakpoints } from "@vueuse/core"; const breakpoints = useBreakpoints(breakpointsTailwind); const useModal = computed(() => !breakpoints.lg.value); +const { t } = useI18n(); + +useHead({ + title: t("setup.welcome"), +}); + const route = useRoute(); const router = useRouter(); const token = route.query.token; @@ -171,21 +177,23 @@ if (!allowed) }); const currentAction = ref(-1); -const actions = ref>([ +const actions = ref< + Array<{ + name: string; + description: string; + icon: Component; + page: Component; + }> +>([ { - name: "Setup your admin account.", - description: "You need at least one account to start using Drop.", + name: t("setup.stages.account.name"), + description: t("setup.stages.account.description"), icon: UserCircleIcon, page: SetupAccount, }, { - name: "Create a library", - description: "Add at least one library source to use Drop.", + name: t("setup.stages.library.name"), + description: t("setup.stages.library.description"), icon: ServerStackIcon, page: SetupLibrary, }, From e0e9d3cc1bc4f51b4a3ad00be8a843ed1ef75caa Mon Sep 17 00:00:00 2001 From: DecDuck Date: Thu, 31 Jul 2025 20:38:06 +1000 Subject: [PATCH 4/5] fix: lint --- changelog.md | 8 ++-- components/LanguageSelectorListbox.vue | 5 +-- components/Setup/Account.vue | 2 - i18n/locales/en_us.json | 2 + pages/admin/library/sources/index.vue | 2 +- pages/setup.vue | 40 ++++++++++--------- server/api/v1/admin/index.get.ts | 10 ++--- .../api/v1/admin/library/sources/index.get.ts | 5 ++- .../v1/admin/library/sources/index.patch.ts | 2 +- .../v1/admin/library/sources/index.post.ts | 2 +- server/internal/acls/index.ts | 3 +- server/plugins/01.system-init.ts | 1 - 12 files changed, 42 insertions(+), 40 deletions(-) diff --git a/changelog.md b/changelog.md index 18266e71..ac147b22 100644 --- a/changelog.md +++ b/changelog.md @@ -193,6 +193,7 @@ _changelog generated by_ [go-conventional-commits](https://github.com/joselitofi ## Release 0.2.0-beta ### Fixes + - fix recursive dirs util #02d6346 - Fix username length requirement #0a5a649 - remove dynamic imports #0f10626 @@ -223,8 +224,8 @@ _changelog generated by_ [go-conventional-commits](https://github.com/joselitofi - fix FATAL: "root"... message #dbb315a - only show versions that are directories #ef8f3ae - ### Features + - update prisma & delete games #089c3e0 - manual handshake #12e3125 - fetch game endpoint #1f4d075 @@ -271,9 +272,9 @@ _changelog generated by_ [go-conventional-commits](https://github.com/joselitofi - add support for overriding UMU id #fd4a7d1 - add .sh for linux #fe9373a - ### Other Changes -- quexeky + +- quexeky - fixed manifest generation #03a37f7 - manual ci/cd #03b0b0c - ability to fetch client certs for p2p #0a715fe @@ -379,7 +380,6 @@ _changelog generated by_ [go-conventional-commits](https://github.com/joselitofi - better server side signin redirects #ef13b68 - patch signin #f3672f8 - _changelog generated by_ [go-conventional-commits](https://github.com/joselitofilho/go-conventional-commits) ## Release 0.1.0-beta diff --git a/components/LanguageSelectorListbox.vue b/components/LanguageSelectorListbox.vue index edb22e03..b86bf821 100644 --- a/components/LanguageSelectorListbox.vue +++ b/components/LanguageSelectorListbox.vue @@ -87,10 +87,7 @@ import { ListboxOptions, } from "@headlessui/vue"; import { ChevronUpDownIcon } from "@heroicons/vue/16/solid"; -import { - ArrowTopRightOnSquareIcon, - CheckIcon, -} from "@heroicons/vue/24/outline"; +import { CheckIcon } from "@heroicons/vue/24/outline"; import type { Locale } from "vue-i18n"; const { showText = true } = defineProps<{ showText?: boolean }>(); diff --git a/components/Setup/Account.vue b/components/Setup/Account.vue index 5008af76..017125be 100644 --- a/components/Setup/Account.vue +++ b/components/Setup/Account.vue @@ -133,12 +133,10 @@ import { DateTime } from "luxon"; const complete = defineModel({ required: true }); - const { token } = defineProps<{ token: string }>(); const invitationLoading = ref(false); - const enabledAuth = await $dropFetch("/api/v1/admin/auth", { headers: { Authorization: token }, }); diff --git a/i18n/locales/en_us.json b/i18n/locales/en_us.json index 0f032544..58e16c9a 100644 --- a/i18n/locales/en_us.json +++ b/i18n/locales/en_us.json @@ -66,6 +66,8 @@ "setup": { "welcome": "Hey there.", "welcomeDescription": "Welcome to Drop setup wizard. It will walk you through configuring Drop for the first time, and how it works.", + "finish": "Let's go {arrow}", + "noPage": "no page", "auth": { "title": "Authentication", "description": "Authentication in Drop happens through multiple configured 'providers'. Each one can allow users to sign-in through their method. To get started, have at least one authentication provider enabled, and create an account through it.", diff --git a/pages/admin/library/sources/index.vue b/pages/admin/library/sources/index.vue index 2fc3bbda..d7b6c14a 100644 --- a/pages/admin/library/sources/index.vue +++ b/pages/admin/library/sources/index.vue @@ -297,7 +297,7 @@ useHead({ const { t } = useI18n(); // Optional token for setup wizard -const { token } = defineProps<{ token?: string }>(); +const { token = undefined } = defineProps<{ token?: string }>(); const headers = token ? { Authorization: token } : undefined; diff --git a/pages/setup.vue b/pages/setup.vue index 13b89795..2bf06f83 100644 --- a/pages/setup.vue +++ b/pages/setup.vue @@ -29,8 +29,8 @@ class="flex size-10 flex-none items-center justify-center rounded-lg shadow-xs outline-1 outline-zinc-100/10" >