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