diff --git a/cli/src/api/open-api/api.ts b/cli/src/api/open-api/api.ts index 05cac4bcf..3c2980ef8 100644 --- a/cli/src/api/open-api/api.ts +++ b/cli/src/api/open-api/api.ts @@ -3007,6 +3007,12 @@ export interface SearchResponseDto { * @interface ServerConfigDto */ export interface ServerConfigDto { + /** + * + * @type {string} + * @memberof ServerConfigDto + */ + 'externalDomain': string; /** * * @type {boolean} @@ -3590,6 +3596,12 @@ export interface SystemConfigDto { * @memberof SystemConfigDto */ 'reverseGeocoding': SystemConfigReverseGeocodingDto; + /** + * + * @type {SystemConfigServerDto} + * @memberof SystemConfigDto + */ + 'server': SystemConfigServerDto; /** * * @type {SystemConfigStorageTemplateDto} @@ -4014,6 +4026,19 @@ export interface SystemConfigReverseGeocodingDto { */ 'enabled': boolean; } +/** + * + * @export + * @interface SystemConfigServerDto + */ +export interface SystemConfigServerDto { + /** + * + * @type {string} + * @memberof SystemConfigServerDto + */ + 'externalDomain': string; +} /** * * @export diff --git a/mobile/lib/modules/shared_link/ui/shared_link_item.dart b/mobile/lib/modules/shared_link/ui/shared_link_item.dart index f41dec639..b147ea3c5 100644 --- a/mobile/lib/modules/shared_link/ui/shared_link_item.dart +++ b/mobile/lib/modules/shared_link/ui/shared_link_item.dart @@ -9,6 +9,7 @@ import 'package:immich_mobile/modules/search/ui/thumbnail_with_info.dart'; import 'package:immich_mobile/modules/shared_link/models/shared_link.dart'; import 'package:immich_mobile/modules/shared_link/providers/shared_link.provider.dart'; import 'package:immich_mobile/routing/router.dart'; +import 'package:immich_mobile/shared/providers/server_info.provider.dart'; import 'package:immich_mobile/shared/ui/confirm_dialog.dart'; import 'package:immich_mobile/shared/ui/immich_toast.dart'; import 'package:immich_mobile/utils/image_url_builder.dart'; @@ -71,7 +72,11 @@ class SharedLinkItem extends ConsumerWidget { final imageSize = math.min(context.width / 4, 100.0); void copyShareLinkToClipboard() { - final serverUrl = getServerUrl(); + final externalDomain = ref.read( + serverInfoProvider.select((s) => s.serverConfig.externalDomain), + ); + final serverUrl = + externalDomain.isNotEmpty ? externalDomain : getServerUrl(); if (serverUrl == null) { ImmichToast.show( context: context, diff --git a/mobile/lib/modules/shared_link/views/shared_link_edit_page.dart b/mobile/lib/modules/shared_link/views/shared_link_edit_page.dart index a2d7bfde2..e96fff56a 100644 --- a/mobile/lib/modules/shared_link/views/shared_link_edit_page.dart +++ b/mobile/lib/modules/shared_link/views/shared_link_edit_page.dart @@ -8,6 +8,7 @@ import 'package:immich_mobile/extensions/build_context_extensions.dart'; import 'package:immich_mobile/modules/shared_link/models/shared_link.dart'; import 'package:immich_mobile/modules/shared_link/providers/shared_link.provider.dart'; import 'package:immich_mobile/modules/shared_link/services/shared_link.service.dart'; +import 'package:immich_mobile/shared/providers/server_info.provider.dart'; import 'package:immich_mobile/shared/ui/immich_toast.dart'; import 'package:immich_mobile/utils/url_helper.dart'; @@ -353,7 +354,11 @@ class SharedLinkEditPage extends HookConsumerWidget { expiresAt: expiryAfter.value == 0 ? null : calculateExpiry(), ); ref.invalidate(sharedLinksStateProvider); - final serverUrl = getServerUrl(); + final externalDomain = ref.read( + serverInfoProvider.select((s) => s.serverConfig.externalDomain), + ); + final serverUrl = + externalDomain.isNotEmpty ? externalDomain : getServerUrl(); if (newLink != null && serverUrl != null) { newShareLink.value = "$serverUrl/share/${newLink.key}"; copyLinkToClipboard(); diff --git a/mobile/lib/shared/models/server_info/server_config.model.dart b/mobile/lib/shared/models/server_info/server_config.model.dart index cdb99987e..7833301cc 100644 --- a/mobile/lib/shared/models/server_info/server_config.model.dart +++ b/mobile/lib/shared/models/server_info/server_config.model.dart @@ -2,35 +2,40 @@ import 'package:openapi/api.dart'; class ServerConfig { final int trashDays; + final String externalDomain; const ServerConfig({ required this.trashDays, + required this.externalDomain, }); ServerConfig copyWith({ int? trashDays, + String? externalDomain, }) { return ServerConfig( trashDays: trashDays ?? this.trashDays, + externalDomain: externalDomain ?? this.externalDomain, ); } @override - String toString() { - return 'ServerConfig(trashDays: $trashDays)'; - } + String toString() => + 'ServerConfig(trashDays: $trashDays, externalDomain: $externalDomain)'; - ServerConfig.fromDto(ServerConfigDto dto) : trashDays = dto.trashDays; + ServerConfig.fromDto(ServerConfigDto dto) + : trashDays = dto.trashDays, + externalDomain = dto.externalDomain; @override bool operator ==(Object other) { if (identical(this, other)) return true; - return other is ServerConfig && other.trashDays == trashDays; + return other is ServerConfig && + other.trashDays == trashDays && + other.externalDomain == externalDomain; } @override - int get hashCode { - return trashDays.hashCode; - } + int get hashCode => trashDays.hashCode ^ externalDomain.hashCode; } diff --git a/mobile/lib/shared/providers/server_info.provider.dart b/mobile/lib/shared/providers/server_info.provider.dart index b7389824b..0f2d9d1c4 100644 --- a/mobile/lib/shared/providers/server_info.provider.dart +++ b/mobile/lib/shared/providers/server_info.provider.dart @@ -29,6 +29,7 @@ class ServerInfoNotifier extends StateNotifier { ), serverConfig: const ServerConfig( trashDays: 30, + externalDomain: '', ), serverDiskInfo: const ServerDiskInfo( diskAvailable: "0", @@ -74,7 +75,8 @@ class ServerInfoNotifier extends StateNotifier { if (appVersion["major"]! > serverVersion.major) { state = state.copyWith( isVersionMismatch: true, - versionMismatchErrorMessage: "profile_drawer_server_out_of_date_major".tr(), + versionMismatchErrorMessage: + "profile_drawer_server_out_of_date_major".tr(), ); return; } @@ -82,7 +84,8 @@ class ServerInfoNotifier extends StateNotifier { if (appVersion["major"]! < serverVersion.major) { state = state.copyWith( isVersionMismatch: true, - versionMismatchErrorMessage: "profile_drawer_client_out_of_date_major".tr(), + versionMismatchErrorMessage: + "profile_drawer_client_out_of_date_major".tr(), ); return; } @@ -90,7 +93,8 @@ class ServerInfoNotifier extends StateNotifier { if (appVersion["minor"]! > serverVersion.minor) { state = state.copyWith( isVersionMismatch: true, - versionMismatchErrorMessage: "profile_drawer_server_out_of_date_minor".tr(), + versionMismatchErrorMessage: + "profile_drawer_server_out_of_date_minor".tr(), ); return; } @@ -98,7 +102,8 @@ class ServerInfoNotifier extends StateNotifier { if (appVersion["minor"]! < serverVersion.minor) { state = state.copyWith( isVersionMismatch: true, - versionMismatchErrorMessage: "profile_drawer_client_out_of_date_minor".tr(), + versionMismatchErrorMessage: + "profile_drawer_client_out_of_date_minor".tr(), ); return; } diff --git a/mobile/openapi/.openapi-generator/FILES b/mobile/openapi/.openapi-generator/FILES index b8aef8e3d..2eaa4a5bb 100644 --- a/mobile/openapi/.openapi-generator/FILES +++ b/mobile/openapi/.openapi-generator/FILES @@ -149,6 +149,7 @@ doc/SystemConfigNewVersionCheckDto.md doc/SystemConfigOAuthDto.md doc/SystemConfigPasswordLoginDto.md doc/SystemConfigReverseGeocodingDto.md +doc/SystemConfigServerDto.md doc/SystemConfigStorageTemplateDto.md doc/SystemConfigTemplateStorageOptionDto.md doc/SystemConfigThemeDto.md @@ -335,6 +336,7 @@ lib/model/system_config_new_version_check_dto.dart lib/model/system_config_o_auth_dto.dart lib/model/system_config_password_login_dto.dart lib/model/system_config_reverse_geocoding_dto.dart +lib/model/system_config_server_dto.dart lib/model/system_config_storage_template_dto.dart lib/model/system_config_template_storage_option_dto.dart lib/model/system_config_theme_dto.dart @@ -508,6 +510,7 @@ test/system_config_new_version_check_dto_test.dart test/system_config_o_auth_dto_test.dart test/system_config_password_login_dto_test.dart test/system_config_reverse_geocoding_dto_test.dart +test/system_config_server_dto_test.dart test/system_config_storage_template_dto_test.dart test/system_config_template_storage_option_dto_test.dart test/system_config_theme_dto_test.dart diff --git a/mobile/openapi/README.md b/mobile/openapi/README.md index 9b4e57c9b..068aa8aa2 100644 Binary files a/mobile/openapi/README.md and b/mobile/openapi/README.md differ diff --git a/mobile/openapi/doc/ServerConfigDto.md b/mobile/openapi/doc/ServerConfigDto.md index fd543257b..b2406daf7 100644 Binary files a/mobile/openapi/doc/ServerConfigDto.md and b/mobile/openapi/doc/ServerConfigDto.md differ diff --git a/mobile/openapi/doc/SystemConfigDto.md b/mobile/openapi/doc/SystemConfigDto.md index 403260659..51bf203ff 100644 Binary files a/mobile/openapi/doc/SystemConfigDto.md and b/mobile/openapi/doc/SystemConfigDto.md differ diff --git a/mobile/openapi/doc/SystemConfigServerDto.md b/mobile/openapi/doc/SystemConfigServerDto.md new file mode 100644 index 000000000..f749fb587 Binary files /dev/null and b/mobile/openapi/doc/SystemConfigServerDto.md differ diff --git a/mobile/openapi/lib/api.dart b/mobile/openapi/lib/api.dart index 32c60889d..2bc825f45 100644 Binary files a/mobile/openapi/lib/api.dart and b/mobile/openapi/lib/api.dart differ diff --git a/mobile/openapi/lib/api_client.dart b/mobile/openapi/lib/api_client.dart index b9dfe3505..ec8f84bae 100644 Binary files a/mobile/openapi/lib/api_client.dart and b/mobile/openapi/lib/api_client.dart differ diff --git a/mobile/openapi/lib/model/server_config_dto.dart b/mobile/openapi/lib/model/server_config_dto.dart index ffe5b2af3..abe598396 100644 Binary files a/mobile/openapi/lib/model/server_config_dto.dart and b/mobile/openapi/lib/model/server_config_dto.dart differ diff --git a/mobile/openapi/lib/model/system_config_dto.dart b/mobile/openapi/lib/model/system_config_dto.dart index e7214c201..0d64d6bc3 100644 Binary files a/mobile/openapi/lib/model/system_config_dto.dart and b/mobile/openapi/lib/model/system_config_dto.dart differ diff --git a/mobile/openapi/lib/model/system_config_server_dto.dart b/mobile/openapi/lib/model/system_config_server_dto.dart new file mode 100644 index 000000000..ffd0ac69c Binary files /dev/null and b/mobile/openapi/lib/model/system_config_server_dto.dart differ diff --git a/mobile/openapi/test/server_config_dto_test.dart b/mobile/openapi/test/server_config_dto_test.dart index d43e47823..ffd373bf2 100644 Binary files a/mobile/openapi/test/server_config_dto_test.dart and b/mobile/openapi/test/server_config_dto_test.dart differ diff --git a/mobile/openapi/test/system_config_dto_test.dart b/mobile/openapi/test/system_config_dto_test.dart index 5398f7760..5f4154987 100644 Binary files a/mobile/openapi/test/system_config_dto_test.dart and b/mobile/openapi/test/system_config_dto_test.dart differ diff --git a/mobile/openapi/test/system_config_server_dto_test.dart b/mobile/openapi/test/system_config_server_dto_test.dart new file mode 100644 index 000000000..4d5dcae2b Binary files /dev/null and b/mobile/openapi/test/system_config_server_dto_test.dart differ diff --git a/server/immich-openapi-specs.json b/server/immich-openapi-specs.json index 9d23c8e55..4b2d620ea 100644 --- a/server/immich-openapi-specs.json +++ b/server/immich-openapi-specs.json @@ -8593,6 +8593,9 @@ }, "ServerConfigDto": { "properties": { + "externalDomain": { + "type": "string" + }, "isInitialized": { "type": "boolean" }, @@ -8610,7 +8613,8 @@ "trashDays", "oauthButtonText", "loginPageMessage", - "isInitialized" + "isInitialized", + "externalDomain" ], "type": "object" }, @@ -9039,6 +9043,9 @@ "reverseGeocoding": { "$ref": "#/components/schemas/SystemConfigReverseGeocodingDto" }, + "server": { + "$ref": "#/components/schemas/SystemConfigServerDto" + }, "storageTemplate": { "$ref": "#/components/schemas/SystemConfigStorageTemplateDto" }, @@ -9066,7 +9073,8 @@ "thumbnail", "trash", "theme", - "library" + "library", + "server" ], "type": "object" }, @@ -9359,6 +9367,17 @@ ], "type": "object" }, + "SystemConfigServerDto": { + "properties": { + "externalDomain": { + "type": "string" + } + }, + "required": [ + "externalDomain" + ], + "type": "object" + }, "SystemConfigStorageTemplateDto": { "properties": { "enabled": { diff --git a/server/src/domain/server-info/server-info.dto.ts b/server/src/domain/server-info/server-info.dto.ts index e8c68d559..32ac51aa4 100644 --- a/server/src/domain/server-info/server-info.dto.ts +++ b/server/src/domain/server-info/server-info.dto.ts @@ -86,6 +86,7 @@ export class ServerConfigDto { @ApiProperty({ type: 'integer' }) trashDays!: number; isInitialized!: boolean; + externalDomain!: string; } export class ServerFeaturesDto implements FeatureFlags { diff --git a/server/src/domain/server-info/server-info.service.spec.ts b/server/src/domain/server-info/server-info.service.spec.ts index f40c16e82..d093399c7 100644 --- a/server/src/domain/server-info/server-info.service.spec.ts +++ b/server/src/domain/server-info/server-info.service.spec.ts @@ -184,6 +184,7 @@ describe(ServerInfoService.name, () => { loginPageMessage: '', oauthButtonText: 'Login with OAuth', trashDays: 30, + externalDomain: '', }); expect(configMock.load).toHaveBeenCalled(); }); diff --git a/server/src/domain/server-info/server-info.service.ts b/server/src/domain/server-info/server-info.service.ts index 5a1bed567..b13e3c9fa 100644 --- a/server/src/domain/server-info/server-info.service.ts +++ b/server/src/domain/server-info/server-info.service.ts @@ -89,6 +89,7 @@ export class ServerInfoService { trashDays: config.trash.days, oauthButtonText: config.oauth.buttonText, isInitialized, + externalDomain: config.server.externalDomain, }; } diff --git a/server/src/domain/system-config/dto/system-config-server.dto.ts b/server/src/domain/system-config/dto/system-config-server.dto.ts new file mode 100644 index 000000000..0b5cb3550 --- /dev/null +++ b/server/src/domain/system-config/dto/system-config-server.dto.ts @@ -0,0 +1,6 @@ +import { IsString } from 'class-validator'; + +export class SystemConfigServerDto { + @IsString() + externalDomain!: string; +} diff --git a/server/src/domain/system-config/dto/system-config.dto.ts b/server/src/domain/system-config/dto/system-config.dto.ts index 6fbfeced2..122d78ca6 100644 --- a/server/src/domain/system-config/dto/system-config.dto.ts +++ b/server/src/domain/system-config/dto/system-config.dto.ts @@ -11,6 +11,7 @@ import { SystemConfigNewVersionCheckDto } from './system-config-new-version-chec import { SystemConfigOAuthDto } from './system-config-oauth.dto'; import { SystemConfigPasswordLoginDto } from './system-config-password-login.dto'; import { SystemConfigReverseGeocodingDto } from './system-config-reverse-geocoding.dto'; +import { SystemConfigServerDto } from './system-config-server.dto'; import { SystemConfigStorageTemplateDto } from './system-config-storage-template.dto'; import { SystemConfigThemeDto } from './system-config-theme.dto'; import { SystemConfigThumbnailDto } from './system-config-thumbnail.dto'; @@ -86,6 +87,11 @@ export class SystemConfigDto implements SystemConfig { @ValidateNested() @IsObject() library!: SystemConfigLibraryDto; + + @Type(() => SystemConfigServerDto) + @ValidateNested() + @IsObject() + server!: SystemConfigServerDto; } export function mapConfig(config: SystemConfig): SystemConfigDto { diff --git a/server/src/domain/system-config/system-config.core.ts b/server/src/domain/system-config/system-config.core.ts index 5717e0308..8aaab1c9e 100644 --- a/server/src/domain/system-config/system-config.core.ts +++ b/server/src/domain/system-config/system-config.core.ts @@ -127,6 +127,9 @@ export const defaults = Object.freeze({ cronExpression: CronExpression.EVERY_DAY_AT_MIDNIGHT, }, }, + server: { + externalDomain: '', + }, }); export enum FeatureFlag { diff --git a/server/src/domain/system-config/system-config.service.spec.ts b/server/src/domain/system-config/system-config.service.spec.ts index 986247786..1f71a0beb 100644 --- a/server/src/domain/system-config/system-config.service.spec.ts +++ b/server/src/domain/system-config/system-config.service.spec.ts @@ -100,6 +100,9 @@ const updatedConfig = Object.freeze({ passwordLogin: { enabled: true, }, + server: { + externalDomain: '', + }, storageTemplate: { enabled: false, hashVerificationEnabled: true, diff --git a/server/src/infra/entities/system-config.entity.ts b/server/src/infra/entities/system-config.entity.ts index 5c10c027f..9033ec387 100644 --- a/server/src/infra/entities/system-config.entity.ts +++ b/server/src/infra/entities/system-config.entity.ts @@ -84,6 +84,8 @@ export enum SystemConfigKey { PASSWORD_LOGIN_ENABLED = 'passwordLogin.enabled', + SERVER_EXTERNAL_DOMAIN = 'server.externalDomain', + STORAGE_TEMPLATE_ENABLED = 'storageTemplate.enabled', STORAGE_TEMPLATE_HASH_VERIFICATION_ENABLED = 'storageTemplate.hashVerificationEnabled', STORAGE_TEMPLATE = 'storageTemplate.template', @@ -244,4 +246,7 @@ export interface SystemConfig { cronExpression: string; }; }; + server: { + externalDomain: string; + }; } diff --git a/server/test/e2e/server-info.e2e-spec.ts b/server/test/e2e/server-info.e2e-spec.ts index f2839aa50..d2d54d079 100644 --- a/server/test/e2e/server-info.e2e-spec.ts +++ b/server/test/e2e/server-info.e2e-spec.ts @@ -97,6 +97,7 @@ describe(`${ServerInfoController.name} (e2e)`, () => { oauthButtonText: 'Login with OAuth', trashDays: 30, isInitialized: true, + externalDomain: '', }); }); }); diff --git a/web/src/api/open-api/api.ts b/web/src/api/open-api/api.ts index 05cac4bcf..3c2980ef8 100644 --- a/web/src/api/open-api/api.ts +++ b/web/src/api/open-api/api.ts @@ -3007,6 +3007,12 @@ export interface SearchResponseDto { * @interface ServerConfigDto */ export interface ServerConfigDto { + /** + * + * @type {string} + * @memberof ServerConfigDto + */ + 'externalDomain': string; /** * * @type {boolean} @@ -3590,6 +3596,12 @@ export interface SystemConfigDto { * @memberof SystemConfigDto */ 'reverseGeocoding': SystemConfigReverseGeocodingDto; + /** + * + * @type {SystemConfigServerDto} + * @memberof SystemConfigDto + */ + 'server': SystemConfigServerDto; /** * * @type {SystemConfigStorageTemplateDto} @@ -4014,6 +4026,19 @@ export interface SystemConfigReverseGeocodingDto { */ 'enabled': boolean; } +/** + * + * @export + * @interface SystemConfigServerDto + */ +export interface SystemConfigServerDto { + /** + * + * @type {string} + * @memberof SystemConfigServerDto + */ + 'externalDomain': string; +} /** * * @export diff --git a/web/src/api/utils.ts b/web/src/api/utils.ts index 8dd0fb4ca..f2f8f50cc 100644 --- a/web/src/api/utils.ts +++ b/web/src/api/utils.ts @@ -19,6 +19,10 @@ export const copyToClipboard = async (secret: string) => { } }; +export const makeSharedLinkUrl = (externalDomain: string, key: string) => { + return `${externalDomain || window.location.origin}/share/${key}`; +}; + export const oauth = { isCallback: (location: Location) => { const search = location.search; diff --git a/web/src/lib/components/admin-page/settings/server/server-settings.svelte b/web/src/lib/components/admin-page/settings/server/server-settings.svelte new file mode 100644 index 000000000..16c1eabfc --- /dev/null +++ b/web/src/lib/components/admin-page/settings/server/server-settings.svelte @@ -0,0 +1,107 @@ + + +
+ {#await getConfigs() then} +
+
+
+ +
+ handleReset(detail)} + on:save={saveSetting} + showResetToDefault={!isEqual(savedConfig, defaultConfig)} + {disabled} + /> +
+
+
+
+ {/await} +
diff --git a/web/src/lib/components/shared-components/create-share-link-modal/create-shared-link-modal.svelte b/web/src/lib/components/shared-components/create-share-link-modal/create-shared-link-modal.svelte index cec2686c7..483ed9bd2 100644 --- a/web/src/lib/components/shared-components/create-share-link-modal/create-shared-link-modal.svelte +++ b/web/src/lib/components/shared-components/create-share-link-modal/create-shared-link-modal.svelte @@ -5,7 +5,7 @@ import SettingSwitch from '$lib/components/admin-page/settings/setting-switch.svelte'; import Button from '$lib/components/elements/buttons/button.svelte'; import { handleError } from '$lib/utils/handle-error'; - import { api, copyToClipboard, SharedLinkResponseDto, SharedLinkType } from '@api'; + import { api, copyToClipboard, makeSharedLinkUrl, SharedLinkResponseDto, SharedLinkType } from '@api'; import { createEventDispatcher, onMount } from 'svelte'; import Icon from '$lib/components/elements/icon.svelte'; import BaseModal from '../base-modal.svelte'; @@ -13,6 +13,7 @@ import DropdownButton from '../dropdown-button.svelte'; import { notificationController, NotificationType } from '../notification/notification'; import { mdiLink } from '@mdi/js'; + import { serverConfig } from '$lib/stores/server-config.store'; export let albumId: string | undefined = undefined; export let assetIds: string[] = []; @@ -82,7 +83,7 @@ showMetadata, }, }); - sharedLink = `${window.location.origin}/share/${data.key}`; + sharedLink = makeSharedLinkUrl($serverConfig.externalDomain, data.key); } catch (e) { handleError(e, 'Failed to create shared link'); } @@ -182,7 +183,7 @@ {:else}
Individual shared | {editingLink.description}{editingLink.description || ''}
{/if} diff --git a/web/src/lib/stores/server-config.store.ts b/web/src/lib/stores/server-config.store.ts index 8843aaee2..73798631a 100644 --- a/web/src/lib/stores/server-config.store.ts +++ b/web/src/lib/stores/server-config.store.ts @@ -26,6 +26,7 @@ export const serverConfig = writable({ loginPageMessage: '', trashDays: 30, isInitialized: false, + externalDomain: '', }); export const loadConfig = async () => { diff --git a/web/src/routes/(user)/sharing/sharedlinks/+page.svelte b/web/src/routes/(user)/sharing/sharedlinks/+page.svelte index 6fd9a7afa..cb7b0d5fa 100644 --- a/web/src/routes/(user)/sharing/sharedlinks/+page.svelte +++ b/web/src/routes/(user)/sharing/sharedlinks/+page.svelte @@ -1,6 +1,6 @@ diff --git a/web/src/routes/admin/system-settings/+page.svelte b/web/src/routes/admin/system-settings/+page.svelte index 2a6fce5ae..cabe88183 100644 --- a/web/src/routes/admin/system-settings/+page.svelte +++ b/web/src/routes/admin/system-settings/+page.svelte @@ -9,6 +9,7 @@ import SettingAccordion from '$lib/components/admin-page/settings/setting-accordion.svelte'; import StorageTemplateSettings from '$lib/components/admin-page/settings/storage-template/storage-template-settings.svelte'; import ThumbnailSettings from '$lib/components/admin-page/settings/thumbnail/thumbnail-settings.svelte'; + import ServerSettings from '$lib/components/admin-page/settings/server/server-settings.svelte'; import TrashSettings from '$lib/components/admin-page/settings/trash-settings/trash-settings.svelte'; import ThemeSettings from '$lib/components/admin-page/settings/theme/theme-settings.svelte'; import LinkButton from '$lib/components/elements/buttons/link-button.svelte'; @@ -95,6 +96,10 @@ + + + +