diff --git a/backend/internal/dto/app_config_dto.go b/backend/internal/dto/app_config_dto.go index 57cca2bd..646550be 100644 --- a/backend/internal/dto/app_config_dto.go +++ b/backend/internal/dto/app_config_dto.go @@ -14,6 +14,7 @@ type AppConfigVariableDto struct { type AppConfigUpdateDto struct { AppName string `json:"appName" binding:"required,min=1,max=30" unorm:"nfc"` SessionDuration string `json:"sessionDuration" binding:"required"` + HomePageURL string `json:"homePageUrl" binding:"required"` EmailsVerified string `json:"emailsVerified" binding:"required"` DisableAnimations string `json:"disableAnimations" binding:"required"` AllowOwnAccountEdit string `json:"allowOwnAccountEdit" binding:"required"` diff --git a/backend/internal/model/app_config.go b/backend/internal/model/app_config.go index 68c0f1c4..424a2c42 100644 --- a/backend/internal/model/app_config.go +++ b/backend/internal/model/app_config.go @@ -36,6 +36,7 @@ type AppConfig struct { // General AppName AppConfigVariable `key:"appName,public"` // Public SessionDuration AppConfigVariable `key:"sessionDuration"` + HomePageURL AppConfigVariable `key:"homePageUrl,public"` // Public EmailsVerified AppConfigVariable `key:"emailsVerified"` AccentColor AppConfigVariable `key:"accentColor,public"` // Public DisableAnimations AppConfigVariable `key:"disableAnimations,public"` // Public diff --git a/backend/internal/service/app_config_service.go b/backend/internal/service/app_config_service.go index 6e7889a4..1f8ea731 100644 --- a/backend/internal/service/app_config_service.go +++ b/backend/internal/service/app_config_service.go @@ -61,6 +61,7 @@ func (s *AppConfigService) getDefaultDbConfig() *model.AppConfig { // General AppName: model.AppConfigVariable{Value: "Pocket ID"}, SessionDuration: model.AppConfigVariable{Value: "60"}, + HomePageURL: model.AppConfigVariable{Value: "/settings/account"}, EmailsVerified: model.AppConfigVariable{Value: "false"}, DisableAnimations: model.AppConfigVariable{Value: "false"}, AllowOwnAccountEdit: model.AppConfigVariable{Value: "true"}, diff --git a/frontend/messages/en.json b/frontend/messages/en.json index 4833e334..39d0587c 100644 --- a/frontend/messages/en.json +++ b/frontend/messages/en.json @@ -505,5 +505,7 @@ "scopes": "Scopes", "issuer_url": "Issuer URL", "smtp_field_required_when_other_provided": "Required when any SMTP setting is provided", - "smtp_field_required_when_email_enabled": "Required when email notifications are enabled" + "smtp_field_required_when_email_enabled": "Required when email notifications are enabled", + "app_config_home_page": "Home Page", + "app_config_home_page_description": "The page users are redirected to after signing in." } diff --git a/frontend/src/lib/components/header/header.svelte b/frontend/src/lib/components/header/header.svelte index 82082ccc..0010f98a 100644 --- a/frontend/src/lib/components/header/header.svelte +++ b/frontend/src/lib/components/header/header.svelte @@ -28,7 +28,7 @@
{#if !isAuthPage} diff --git a/frontend/src/lib/services/app-config-service.ts b/frontend/src/lib/services/app-config-service.ts index 88386bf6..f73e7056 100644 --- a/frontend/src/lib/services/app-config-service.ts +++ b/frontend/src/lib/services/app-config-service.ts @@ -1,5 +1,5 @@ import userStore from '$lib/stores/user-store'; -import type { AllAppConfig, AppConfigRawResponse } from '$lib/types/application-configuration'; +import type { AllAppConfig, AppConfigRawResponse } from '$lib/types/application-configuration.type'; import { cachedApplicationLogo, cachedBackgroundImage, diff --git a/frontend/src/lib/stores/application-configuration-store.ts b/frontend/src/lib/stores/application-configuration-store.ts index ff278004..2f77be3d 100644 --- a/frontend/src/lib/stores/application-configuration-store.ts +++ b/frontend/src/lib/stores/application-configuration-store.ts @@ -1,5 +1,5 @@ import AppConfigService from '$lib/services/app-config-service'; -import type { AppConfig } from '$lib/types/application-configuration'; +import type { AppConfig } from '$lib/types/application-configuration.type'; import { applyAccentColor } from '$lib/utils/accent-color-util'; import { writable } from 'svelte/store'; diff --git a/frontend/src/lib/types/application-configuration.ts b/frontend/src/lib/types/application-configuration.type.ts similarity index 98% rename from frontend/src/lib/types/application-configuration.ts rename to frontend/src/lib/types/application-configuration.type.ts index 54bbb0a1..a45fd131 100644 --- a/frontend/src/lib/types/application-configuration.ts +++ b/frontend/src/lib/types/application-configuration.type.ts @@ -2,6 +2,7 @@ import type { CustomClaim } from './custom-claim.type'; export type AppConfig = { appName: string; + homePageUrl: string; allowOwnAccountEdit: boolean; allowUserSignups: 'disabled' | 'withToken' | 'open'; emailOneTimeAccessAsUnauthenticatedEnabled: boolean; diff --git a/frontend/src/routes/settings/+layout.ts b/frontend/src/routes/settings/+layout.ts index e4303823..74f0a776 100644 --- a/frontend/src/routes/settings/+layout.ts +++ b/frontend/src/routes/settings/+layout.ts @@ -1,5 +1,5 @@ import VersionService from '$lib/services/version-service'; -import type { AppVersionInformation } from '$lib/types/application-configuration'; +import type { AppVersionInformation } from '$lib/types/application-configuration.type'; import type { LayoutLoad } from './$types'; export const load: LayoutLoad = async () => { diff --git a/frontend/src/routes/settings/+page.ts b/frontend/src/routes/settings/+page.ts index 84a0ca1c..9669468f 100644 --- a/frontend/src/routes/settings/+page.ts +++ b/frontend/src/routes/settings/+page.ts @@ -1,6 +1,8 @@ import { redirect } from '@sveltejs/kit'; import type { PageLoad } from './$types'; +import appConfig from '$lib/stores/application-configuration-store'; +import { get } from 'svelte/store'; export const load: PageLoad = async () => { - throw redirect(307, '/settings/account'); + throw redirect(307, get(appConfig).homePageUrl); }; diff --git a/frontend/src/routes/settings/admin/application-configuration/+page.svelte b/frontend/src/routes/settings/admin/application-configuration/+page.svelte index fdecb945..a2244e70 100644 --- a/frontend/src/routes/settings/admin/application-configuration/+page.svelte +++ b/frontend/src/routes/settings/admin/application-configuration/+page.svelte @@ -4,7 +4,7 @@ import { m } from '$lib/paraglide/messages'; import AppConfigService from '$lib/services/app-config-service'; import appConfigStore from '$lib/stores/application-configuration-store'; - import type { AllAppConfig } from '$lib/types/application-configuration'; + import type { AllAppConfig } from '$lib/types/application-configuration.type'; import { axiosErrorToast } from '$lib/utils/error-util'; import { LucideImage, diff --git a/frontend/src/routes/settings/admin/application-configuration/forms/app-config-email-form.svelte b/frontend/src/routes/settings/admin/application-configuration/forms/app-config-email-form.svelte index 9c4dba71..2fcff24f 100644 --- a/frontend/src/routes/settings/admin/application-configuration/forms/app-config-email-form.svelte +++ b/frontend/src/routes/settings/admin/application-configuration/forms/app-config-email-form.svelte @@ -8,7 +8,7 @@ import { m } from '$lib/paraglide/messages'; import AppConfigService from '$lib/services/app-config-service'; import appConfigStore from '$lib/stores/application-configuration-store'; - import type { AllAppConfig } from '$lib/types/application-configuration'; + import type { AllAppConfig } from '$lib/types/application-configuration.type'; import { preventDefault } from '$lib/utils/event-util'; import { createForm } from '$lib/utils/form-util'; import { toast } from 'svelte-sonner'; diff --git a/frontend/src/routes/settings/admin/application-configuration/forms/app-config-general-form.svelte b/frontend/src/routes/settings/admin/application-configuration/forms/app-config-general-form.svelte index e2f53e42..975f58a3 100644 --- a/frontend/src/routes/settings/admin/application-configuration/forms/app-config-general-form.svelte +++ b/frontend/src/routes/settings/admin/application-configuration/forms/app-config-general-form.svelte @@ -3,9 +3,10 @@ import SwitchWithLabel from '$lib/components/form/switch-with-label.svelte'; import { Button } from '$lib/components/ui/button'; import * as Field from '$lib/components/ui/field'; + import * as Select from '$lib/components/ui/select'; import { m } from '$lib/paraglide/messages'; import appConfigStore from '$lib/stores/application-configuration-store'; - import type { AllAppConfig } from '$lib/types/application-configuration'; + import type { AllAppConfig } from '$lib/types/application-configuration.type'; import { preventDefault } from '$lib/utils/event-util'; import { createForm } from '$lib/utils/form-util'; import { toast } from 'svelte-sonner'; @@ -22,8 +23,14 @@ let isLoading = $state(false); + const homePageUrlOptions = [ + { label: m.my_account(), value: '/settings/account' }, + { label: m.my_apps(), value: '/settings/apps' } + ]; + const updatedAppConfig = { appName: appConfig.appName, + homePageUrl: appConfig.homePageUrl, sessionDuration: appConfig.sessionDuration, emailsVerified: appConfig.emailsVerified, allowOwnAccountEdit: appConfig.allowOwnAccountEdit, @@ -33,6 +40,7 @@ const formSchema = z.object({ appName: z.string().min(2).max(30), + homePageUrl: z.string(), sessionDuration: z.number().min(1).max(43200), emailsVerified: z.boolean(), allowOwnAccountEdit: z.boolean(), @@ -62,6 +70,32 @@ description={m.the_duration_of_a_session_in_minutes_before_the_user_has_to_sign_in_again()} bind:input={$inputs.sessionDuration} /> + + {m.app_config_home_page()} + + {m.app_config_home_page_description()} + + ($inputs.homePageUrl.value = v as string)} + > + + {homePageUrlOptions.find((option) => option.value === $inputs.homePageUrl.value) + ?.label ?? $inputs.homePageUrl.value} + + + {#each homePageUrlOptions as option} + + {option.label} + + {/each} + + + { test('Update general configuration', async ({ page }) => { await page.getByLabel('Application Name', { exact: true }).fill('Updated Name'); await page.getByLabel('Session Duration').fill('30'); + + await page.getByRole('button', { name: 'Home Page' }).click(); + await page.getByRole('option', { name: 'My Apps' }).click(); + await page.getByRole('button', { name: 'Save' }).first().click(); await expect(page.locator('[data-type="success"]')).toHaveText( @@ -20,6 +24,9 @@ test('Update general configuration', async ({ page }) => { await expect(page.getByLabel('Application Name', { exact: true })).toHaveValue('Updated Name'); await expect(page.getByLabel('Session Duration')).toHaveValue('30'); + + await page.getByRole('link', { name: 'Logo Updated Name' }).click(); + await page.waitForURL('/settings/apps'); }); test.describe('Update user creation configuration', () => { @@ -123,7 +130,9 @@ test.describe('Update application images', () => { test('should upload images', async ({ page }) => { await page.getByLabel('Favicon').setInputFiles('resources/images/w3-schools-favicon.ico'); - await page.getByLabel('Light Mode Logo').setInputFiles('resources/images/pingvin-share-logo.png'); + await page + .getByLabel('Light Mode Logo') + .setInputFiles('resources/images/pingvin-share-logo.png'); await page.getByLabel('Dark Mode Logo').setInputFiles('resources/images/cloud-logo.png'); await page.getByLabel('Email Logo').setInputFiles('resources/images/pingvin-share-logo.png'); await page