diff --git a/e2e/src/ui/mock-network/base-network.ts b/e2e/src/ui/mock-network/base-network.ts index 0b361bd72..3c761ba37 100644 --- a/e2e/src/ui/mock-network/base-network.ts +++ b/e2e/src/ui/mock-network/base-network.ts @@ -1,5 +1,6 @@ import { BrowserContext } from '@playwright/test'; import { playwrightHost } from 'src/../playwright.config.js'; +import { adminConfig, publicConfig, userConfig } from 'src/ui/mock-network/config-fixtures.js'; export const setupBaseMockApiRoutes = async (context: BrowserContext, adminUserId: string) => { await context.addCookies([ @@ -113,6 +114,27 @@ export const setupBaseMockApiRoutes = async (context: BrowserContext, adminUserI }, }); }); + await context.route('**/api/public/config', async (route) => { + return route.fulfill({ + status: 200, + contentType: 'application/json', + json: publicConfig, + }); + }); + await context.route('**/api/config', async (route) => { + return route.fulfill({ + status: 200, + contentType: 'application/json', + json: userConfig, + }); + }); + await context.route('**/api/admin/config', async (route) => { + return route.fulfill({ + status: 200, + contentType: 'application/json', + json: adminConfig, + }); + }); await context.route('**/api/server/features', async (route) => { return route.fulfill({ status: 200, diff --git a/e2e/src/ui/mock-network/config-fixtures.ts b/e2e/src/ui/mock-network/config-fixtures.ts new file mode 100644 index 000000000..a9b2a42b5 --- /dev/null +++ b/e2e/src/ui/mock-network/config-fixtures.ts @@ -0,0 +1,171 @@ +export const publicConfig = { + ffmpeg: { realtime: { enabled: false } }, + map: { + enabled: true, + lightStyle: 'https://tiles.immich.cloud/v1/style/light.json', + darkStyle: 'https://tiles.immich.cloud/v1/style/dark.json', + }, + oauth: { autoLaunch: false, buttonText: 'Login with OAuth', enabled: false }, + passkey: { enabled: true }, + passwordLogin: { enabled: true }, + server: { loginPageMessage: '' }, +}; + +export const userConfig = { + ffmpeg: { realtime: { enabled: false, videoCodecs: ['h264', 'hevc'], resolutions: [480, 720, 1080] } }, + machineLearning: { + enabled: false, + clip: { enabled: true }, + duplicateDetection: { enabled: true }, + facialRecognition: { enabled: true, minFaces: 3 }, + ocr: { enabled: true }, + }, + map: { + enabled: true, + lightStyle: 'https://tiles.immich.cloud/v1/style/light.json', + darkStyle: 'https://tiles.immich.cloud/v1/style/dark.json', + }, + reverseGeocoding: { enabled: true }, + oauth: { autoLaunch: false, buttonText: 'Login with OAuth', enabled: false, accountManagementUrl: '' }, + passkey: { enabled: true }, + passwordLogin: { enabled: true }, + image: { thumbnail: { size: 250 }, preview: { size: 1440 }, fullsize: { enabled: false } }, + trash: { enabled: true, days: 30 }, + notifications: { smtp: { enabled: false } }, + server: { externalDomain: '', loginPageMessage: '', publicUsers: true }, + user: { deleteDelay: 7 }, +}; + +export const adminConfig = { + backup: { database: { enabled: true, cronExpression: '0 02 * * *', keepLastAmount: 14 } }, + ffmpeg: { + crf: 23, + threads: 0, + preset: 'ultrafast', + targetVideoCodec: 'h264', + acceptedVideoCodecs: ['h264'], + targetAudioCodec: 'aac', + acceptedAudioCodecs: ['aac', 'mp3', 'opus'], + acceptedContainers: ['mov', 'ogg', 'webm'], + targetResolution: '720', + maxBitrate: '0', + bframes: -1, + refs: 0, + gopSize: 0, + temporalAQ: false, + cqMode: 'auto', + twoPass: false, + preferredHwDevice: 'auto', + transcode: 'required', + tonemap: 'hable', + accel: 'disabled', + accelDecode: true, + realtime: { enabled: false, videoCodecs: ['h264', 'hevc'], resolutions: [480, 720, 1080] }, + }, + integrityChecks: { + missingFiles: { enabled: true, cronExpression: '0 03 * * *' }, + untrackedFiles: { enabled: true, cronExpression: '0 03 * * *' }, + checksumFiles: { enabled: true, cronExpression: '0 03 * * *', timeLimit: 3_600_000, percentageLimit: 1 }, + }, + job: { + thumbnailGeneration: { concurrency: 3 }, + metadataExtraction: { concurrency: 5 }, + videoConversion: { concurrency: 1 }, + faceDetection: { concurrency: 2 }, + smartSearch: { concurrency: 2 }, + backgroundTask: { concurrency: 5 }, + migration: { concurrency: 5 }, + search: { concurrency: 5 }, + sidecar: { concurrency: 5 }, + library: { concurrency: 5 }, + notifications: { concurrency: 5 }, + ocr: { concurrency: 1 }, + workflow: { concurrency: 5 }, + editor: { concurrency: 2 }, + integrityCheck: { concurrency: 1 }, + }, + logging: { enabled: true, level: 'log' }, + machineLearning: { + enabled: false, + urls: ['http://immich-machine-learning:3003'], + availabilityChecks: { enabled: true, timeout: 2000, interval: 30_000 }, + clip: { enabled: true, modelName: 'ViT-B-32__openai' }, + duplicateDetection: { enabled: true, maxDistance: 0.01 }, + facialRecognition: { enabled: true, modelName: 'buffalo_l', minScore: 0.7, maxDistance: 0.5, minFaces: 3 }, + ocr: { + enabled: true, + modelName: 'PP-OCRv5_mobile', + minDetectionScore: 0.5, + minRecognitionScore: 0.8, + maxResolution: 736, + }, + }, + map: { + enabled: true, + lightStyle: 'https://tiles.immich.cloud/v1/style/light.json', + darkStyle: 'https://tiles.immich.cloud/v1/style/dark.json', + }, + reverseGeocoding: { enabled: true }, + metadata: { faces: { import: false } }, + oauth: { + autoLaunch: false, + autoRegister: true, + buttonText: 'Login with OAuth', + clientId: '', + clientSecret: '', + defaultStorageQuota: null, + enabled: false, + issuerUrl: '', + accountManagementUrl: '', + endSessionEndpoint: '', + mobileOverrideEnabled: false, + mobileRedirectUri: '', + prompt: '', + scope: 'openid email profile', + signingAlgorithm: 'RS256', + profileSigningAlgorithm: 'none', + storageLabelClaim: 'preferred_username', + storageQuotaClaim: 'immich_quota', + roleClaim: 'immich_role', + tokenEndpointAuthMethod: 'client_secret_post', + timeout: 30_000, + allowInsecureRequests: false, + }, + passkey: { enabled: true, domain: null, additionalDomains: [] }, + passwordLogin: { enabled: true }, + storageTemplate: { + enabled: false, + hashVerificationEnabled: true, + template: '{{y}}/{{y}}-{{MM}}-{{dd}}/{{filename}}', + }, + image: { + thumbnail: { format: 'webp', size: 250, quality: 80, progressive: false }, + preview: { format: 'jpeg', size: 1440, quality: 80, progressive: false }, + colorspace: 'p3', + extractEmbedded: false, + fullsize: { enabled: false, format: 'jpeg', quality: 80, progressive: false }, + }, + newVersionCheck: { enabled: true, channel: 'stable' }, + nightlyTasks: { + startTime: '00:00', + databaseCleanup: true, + generateMemories: true, + syncQuotaUsage: true, + missingThumbnails: true, + clusterNewFaces: true, + }, + trash: { enabled: true, days: 30 }, + theme: { customCss: '' }, + library: { scan: { enabled: true, cronExpression: '0 0 * * *' }, watch: { enabled: false } }, + server: { externalDomain: '', loginPageMessage: '', publicUsers: true }, + notifications: { + smtp: { + enabled: false, + from: '', + replyTo: '', + transport: { ignoreCert: false, host: '', port: 587, secure: false, username: '', password: '' }, + }, + }, + templates: { email: { welcomeTemplate: '', albumInviteTemplate: '', albumUpdateTemplate: '' } }, + user: { deleteDelay: 7 }, +}; diff --git a/web/src/lib/commands.ts b/web/src/lib/commands.ts index 3945674e0..4001db81d 100644 --- a/web/src/lib/commands.ts +++ b/web/src/lib/commands.ts @@ -31,7 +31,8 @@ import type { MessageFormatter } from 'svelte-i18n'; import { goto } from '$app/navigation'; import { page } from '$app/state'; import { authManager } from '$lib/managers/auth-manager.svelte'; -import { featureFlagsManager } from '$lib/managers/feature-flags-manager.svelte'; +import { readPreloadedQuery } from '$lib/queries/client'; +import { getUserConfigQuery } from '$lib/queries/config-user.query'; import { Route } from '$lib/route'; import { copyToClipboard } from '$lib/utils'; @@ -92,7 +93,7 @@ export const getPagesProvider = ($t: MessageFormatter) => { title: $t('map'), icon: mdiMapOutline, onAction: () => goto(Route.map()), - $if: () => authManager.authenticated && featureFlagsManager.value.map, + $if: () => authManager.authenticated && readPreloadedQuery(getUserConfigQuery()).map.enabled, }, { title: $t('people'), @@ -173,7 +174,7 @@ export const getPagesProvider = ($t: MessageFormatter) => { title: $t('trash'), icon: mdiTrashCanOutline, onAction: () => goto(Route.trash()), - $if: () => authManager.authenticated && featureFlagsManager.value.trash, + $if: () => authManager.authenticated && readPreloadedQuery(getUserConfigQuery()).trash.enabled, }, { title: $t('admin.user_settings'), diff --git a/web/src/lib/components/admin-settings/StorageTemplateSettings.svelte b/web/src/lib/components/admin-settings/StorageTemplateSettings.svelte index 05657654c..98832ac25 100644 --- a/web/src/lib/components/admin-settings/StorageTemplateSettings.svelte +++ b/web/src/lib/components/admin-settings/StorageTemplateSettings.svelte @@ -7,7 +7,7 @@ import { authManager } from '$lib/managers/auth-manager.svelte'; import { featureFlagsManager } from '$lib/managers/feature-flags-manager.svelte'; import { createPreloadedQuery, executeMutation } from '$lib/queries/client'; - import { getConfigQuery, updateConfigMutation } from '$lib/queries/system-config.query'; + import { getAdminConfigQuery, updateAdminConfigMutation } from '$lib/queries/config-admin.query'; import StorageTemplateVariablesModal from '$lib/modals/StorageTemplateVariablesModal.svelte'; import { Route } from '$lib/route'; import { getStorageTemplateOptions, type SystemConfigTemplateStorageOptionDto } from '@immich/sdk'; @@ -40,7 +40,7 @@ type StorageTemplateOption = (typeof StorageTemplateOption)[keyof typeof StorageTemplateOption]; const disabled = $derived(featureFlagsManager.value.configFile); - const query = createPreloadedQuery(getConfigQuery); + const query = createPreloadedQuery(getAdminConfigQuery); const config = $derived(query.data); let configToEdit = $state(cloneDeep(config)); @@ -155,7 +155,7 @@ onDestroy(() => { if (saveOnClose) { - void executeMutation(updateConfigMutation, { storageTemplate: configToEdit.storageTemplate }); + void executeMutation(updateAdminConfigMutation, { storageTemplate: configToEdit.storageTemplate }); } }); diff --git a/web/src/lib/components/album-page/AlbumViewer.svelte b/web/src/lib/components/album-page/AlbumViewer.svelte index 2f1b43aee..056854b5e 100644 --- a/web/src/lib/components/album-page/AlbumViewer.svelte +++ b/web/src/lib/components/album-page/AlbumViewer.svelte @@ -7,7 +7,6 @@ import Timeline from '$lib/components/timeline/Timeline.svelte'; import { assetMultiSelectManager } from '$lib/managers/asset-multi-select-manager.svelte'; import { assetViewerManager } from '$lib/managers/asset-viewer-manager.svelte'; - import { featureFlagsManager } from '$lib/managers/feature-flags-manager.svelte'; import { TimelineManager } from '$lib/managers/timeline-manager/timeline-manager.svelte'; import { handleDownloadAlbum } from '$lib/services/album.service'; import { getGlobalActions } from '$lib/services/app.service'; @@ -23,6 +22,11 @@ import ControlAppBar from '../shared-components/ControlAppBar.svelte'; import ThemeButton from '../shared-components/ThemeButton.svelte'; import AlbumSummary from './AlbumSummary.svelte'; + import { createPreloadedQuery } from '$lib/queries/client'; + import { getPublicConfigQuery } from '$lib/queries/config-public.query'; + + const query = createPreloadedQuery(getPublicConfigQuery); + const publicConfig = $derived(query.data); interface Props { sharedLink: SharedLinkResponseDto; @@ -144,7 +148,7 @@ icon={mdiDownload} /> {/if} - {#if sharedLink.showMetadata && featureFlagsManager.value.map} + {#if sharedLink.showMetadata && publicConfig.map.enabled} {/if} diff --git a/web/src/lib/components/asset-viewer/AssetViewerNavBar.spec.ts b/web/src/lib/components/asset-viewer/AssetViewerNavBar.spec.ts index 2c118f347..3d89971ab 100644 --- a/web/src/lib/components/asset-viewer/AssetViewerNavBar.spec.ts +++ b/web/src/lib/components/asset-viewer/AssetViewerNavBar.spec.ts @@ -1,6 +1,9 @@ +import type { UserConfigDto } from '@immich/sdk'; import '@testing-library/jest-dom'; import { getResizeObserverMock } from '$lib/__mocks__/resize-observer.mock'; import { authManager } from '$lib/managers/auth-manager.svelte'; +import { queryClient } from '$lib/queries/client'; +import { getUserConfigQuery } from '$lib/queries/config-user.query'; import { renderWithTooltips } from '$tests/helpers'; import { assetFactory } from '@test-data/factories/asset-factory'; import { preferencesFactory } from '@test-data/factories/preferences-factory'; @@ -60,6 +63,16 @@ describe('AssetViewerNavBar component', () => { const user = userAdminFactory.build({ id: ownerId }); const asset = assetFactory.build({ ownerId, isTrashed: false }); authManager.setUser(user); + queryClient.setQueryData(getUserConfigQuery().queryKey, { + machineLearning: { + enabled: true, + clip: { enabled: true }, + duplicateDetection: { enabled: true }, + facialRecognition: { enabled: true }, + ocr: { enabled: true }, + }, + trash: { enabled: true, days: 30 }, + } as UserConfigDto); const preferences = preferencesFactory.build({ cast: { gCastEnabled: false } }); authManager.setPreferences(preferences); diff --git a/web/src/lib/components/asset-viewer/DetailPanel.svelte b/web/src/lib/components/asset-viewer/DetailPanel.svelte index 47791a94a..9f210419a 100644 --- a/web/src/lib/components/asset-viewer/DetailPanel.svelte +++ b/web/src/lib/components/asset-viewer/DetailPanel.svelte @@ -8,7 +8,6 @@ import { timeToLoadTheMap } from '$lib/constants'; import { assetViewerManager } from '$lib/managers/asset-viewer-manager.svelte'; import { authManager } from '$lib/managers/auth-manager.svelte'; - import { featureFlagsManager } from '$lib/managers/feature-flags-manager.svelte'; import { Route } from '$lib/route'; import { locale } from '$lib/stores/preferences.store'; import { getAssetMediaUrl } from '$lib/utils'; @@ -34,6 +33,11 @@ import AlbumListItemDetails from './AlbumListItemDetails.svelte'; import DetailPanelPeople from '$lib/components/asset-viewer/DetailPanelPeople.svelte'; import { faceManager } from '$lib/stores/face.svelte'; + import { createPreloadedQuery } from '$lib/queries/client'; + import { getPublicConfigQuery } from '$lib/queries/config-public.query'; + + const query = createPreloadedQuery(getPublicConfigQuery); + const publicConfig = $derived(query.data); interface Props { asset: AssetResponseDto; @@ -278,7 +282,7 @@ - {#if latlng && featureFlagsManager.value.map} + {#if latlng && publicConfig.map.enabled}
{#await import('$lib/components/shared-components/map/Map.svelte')} {#await delay(timeToLoadTheMap) then} diff --git a/web/src/lib/components/asset-viewer/VideoNativeViewer.svelte b/web/src/lib/components/asset-viewer/VideoNativeViewer.svelte index ce7486bc1..ad82ff6f0 100644 --- a/web/src/lib/components/asset-viewer/VideoNativeViewer.svelte +++ b/web/src/lib/components/asset-viewer/VideoNativeViewer.svelte @@ -4,7 +4,6 @@ import { assetViewerFadeDuration } from '$lib/constants'; import { assetViewerManager } from '$lib/managers/asset-viewer-manager.svelte'; import { castManager } from '$lib/managers/cast-manager.svelte'; - import { featureFlagsManager } from '$lib/managers/feature-flags-manager.svelte'; import { authManager } from '$lib/managers/auth-manager.svelte'; import { mediaCapabilitiesManager } from '$lib/managers/media-capabilities-manager.svelte'; import { autoPlayVideo, lang, loopVideo as loopVideoPreference } from '$lib/stores/preferences.store'; @@ -45,6 +44,11 @@ import { t } from 'svelte-i18n'; import { fade } from 'svelte/transition'; import './immich-time-range'; + import { createPreloadedQuery } from '$lib/queries/client'; + import { getPublicConfigQuery } from '$lib/queries/config-public.query'; + + const query = createPreloadedQuery(getPublicConfigQuery); + const publicConfig = $derived(query.data); interface Props { asset: AssetResponseDto; @@ -78,7 +82,7 @@ let isLoading = $state(true); let hasLoadedMetadata = $state(false); let assetFileUrl = $derived.by(() => { - if (featureFlagsManager.value.realtimeTranscoding) { + if (publicConfig.ffmpeg.realtime.enabled) { return getAssetHlsUrl(assetId); } @@ -376,7 +380,7 @@ style:aspect-ratio={aspectRatio} defaultduration={asset.duration! / 1000} > - {#if featureFlagsManager.value.realtimeTranscoding} + {#if publicConfig.ffmpeg.realtime.enabled} {$t('media_chrome.playback_rate')} - {#if featureFlagsManager.value.realtimeTranscoding} + {#if publicConfig.ffmpeg.realtime.enabled} {$t('video_quality')} diff --git a/web/src/lib/components/shared-components/map/Map.svelte b/web/src/lib/components/shared-components/map/Map.svelte index a3fda214c..dc69366f8 100644 --- a/web/src/lib/components/shared-components/map/Map.svelte +++ b/web/src/lib/components/shared-components/map/Map.svelte @@ -12,7 +12,6 @@ import { afterNavigate } from '$app/navigation'; import OnEvents from '$lib/components/OnEvents.svelte'; import { assetViewerManager } from '$lib/managers/asset-viewer-manager.svelte'; - import { serverConfigManager } from '$lib/managers/server-config-manager.svelte'; import MapSettingsModal from '$lib/modals/MapSettingsModal.svelte'; import { mapSettings } from '$lib/stores/preferences.store'; import { getAssetMediaUrl, handlePromiseError } from '$lib/utils'; @@ -48,6 +47,11 @@ ScaleControl, } from 'svelte-maplibre'; import type { SelectionBBox } from './types'; + import { createPreloadedQuery } from '$lib/queries/client'; + import { getPublicConfigQuery } from '$lib/queries/config-public.query'; + + const query = createPreloadedQuery(getPublicConfigQuery); + const publicConfig = $derived(query.data); interface Props { mapMarkers?: MapMarkerResponseDto[]; @@ -111,9 +115,7 @@ let abortController: AbortController; const mapTheme = $derived($mapSettings.allowDarkMode ? themeManager.value : Theme.Light); - const styleUrl = $derived( - mapTheme === Theme.Dark ? serverConfigManager.value.mapDarkStyleUrl : serverConfigManager.value.mapLightStyleUrl, - ); + const styleUrl = $derived(mapTheme === Theme.Dark ? publicConfig.map.darkStyle : publicConfig.map.lightStyle); export function addClipMapMarker(lng: number, lat: number) { if (!map) { diff --git a/web/src/lib/components/shared-components/search-bar/SearchTextSection.svelte b/web/src/lib/components/shared-components/search-bar/SearchTextSection.svelte index 22c87d9a3..8166f4a4b 100644 --- a/web/src/lib/components/shared-components/search-bar/SearchTextSection.svelte +++ b/web/src/lib/components/shared-components/search-bar/SearchTextSection.svelte @@ -1,10 +1,14 @@ @@ -44,7 +48,7 @@ - {#if featureFlagsManager.value.map} + {#if config.map.enabled} {/if} @@ -111,7 +115,7 @@ - {#if featureFlagsManager.value.trash} + {#if config.trash.enabled} {/if} diff --git a/web/src/lib/managers/auth-manager.svelte.ts b/web/src/lib/managers/auth-manager.svelte.ts index 5e10d8b11..e53d5d909 100644 --- a/web/src/lib/managers/auth-manager.svelte.ts +++ b/web/src/lib/managers/auth-manager.svelte.ts @@ -10,6 +10,8 @@ import { goto } from '$app/navigation'; import { page } from '$app/state'; import { eventManager } from '$lib/managers/event-manager.svelte'; import { queryClient } from '$lib/queries/client'; +import { getAdminConfigQuery } from '$lib/queries/config-admin.query'; +import { getUserConfigQuery } from '$lib/queries/config-user.query'; import { getAboutInfoQuery } from '$lib/queries/server.query'; import { Route } from '$lib/route'; import { isSharedLinkRoute } from '$lib/utils/navigation'; @@ -62,7 +64,14 @@ class AuthManager { async refresh() { try { - const [user, preferences] = await Promise.all([getMyUser(), getMyPreferences()]); + const [user, preferences] = await Promise.all([ + getMyUser(), + getMyPreferences(), + queryClient.query(getUserConfigQuery()), + ]); + if (user.isAdmin) { + await queryClient.query(getAdminConfigQuery()); + } this.#preferences = preferences; this.#user = user; diff --git a/web/src/lib/managers/server-config-manager.svelte.ts b/web/src/lib/managers/server-config-manager.svelte.ts deleted file mode 100644 index 45f54122e..000000000 --- a/web/src/lib/managers/server-config-manager.svelte.ts +++ /dev/null @@ -1,30 +0,0 @@ -import { getServerConfig, type ServerConfigDto } from '@immich/sdk'; -import { eventManager } from '$lib/managers/event-manager.svelte'; - -class ServerConfigManager { - #value?: ServerConfigDto = $state(); - - constructor() { - eventManager.on({ - SystemConfigUpdate: () => this.loadServerConfig(), - }); - } - - async init() { - await this.loadServerConfig(); - } - - get value() { - if (!this.#value) { - throw new Error('Server config manager must be initialized first'); - } - - return this.#value; - } - - async loadServerConfig() { - this.#value = await getServerConfig(); - } -} - -export const serverConfigManager = new ServerConfigManager(); diff --git a/web/src/lib/modals/PinCodeResetModal.svelte b/web/src/lib/modals/PinCodeResetModal.svelte index a51e0c358..6ea7b98f2 100644 --- a/web/src/lib/modals/PinCodeResetModal.svelte +++ b/web/src/lib/modals/PinCodeResetModal.svelte @@ -1,9 +1,13 @@ -{#if featureFlagsManager.value.passwordLogin} +{#if config.passwordLogin.enabled}
{$t('reset_pin_code_description')}
diff --git a/web/src/lib/modals/UserDeleteConfirmModal.svelte b/web/src/lib/modals/UserDeleteConfirmModal.svelte index 03818b550..fe7cd6255 100644 --- a/web/src/lib/modals/UserDeleteConfirmModal.svelte +++ b/web/src/lib/modals/UserDeleteConfirmModal.svelte @@ -1,12 +1,15 @@ -{#if featureFlagsManager.value.map} +{#if config.map.enabled}
; let searchQuery = $derived(page.url.searchParams.get(QueryParameter.QUERY)); - let smartSearchEnabled = $derived(featureFlagsManager.value.smartSearch); let terms = $derived(searchQuery ? JSON.parse(searchQuery) : {}); let searchTermKeys = $derived(getObjectKeys(terms)); @@ -139,7 +142,7 @@ try { const { albums, assets } = - ('query' in searchDto || 'queryAssetId' in searchDto) && smartSearchEnabled + ('query' in searchDto || 'queryAssetId' in searchDto) && config.machineLearning.clip.enabled ? await searchSmart({ smartSearchDto: { visibility: AssetVisibility.Timeline, ...searchDto, language: $lang }, }) diff --git a/web/src/routes/(user)/trash/[[photos=photos]]/[[assetId=id]]/+page.svelte b/web/src/routes/(user)/trash/[[photos=photos]]/[[assetId=id]]/+page.svelte index 46e8b46be..95bed86a3 100644 --- a/web/src/routes/(user)/trash/[[photos=photos]]/[[assetId=id]]/+page.svelte +++ b/web/src/routes/(user)/trash/[[photos=photos]]/[[assetId=id]]/+page.svelte @@ -9,14 +9,17 @@ import AssetSelectControlBar from '$lib/components/timeline/AssetSelectControlBar.svelte'; import Timeline from '$lib/components/timeline/Timeline.svelte'; import { assetMultiSelectManager } from '$lib/managers/asset-multi-select-manager.svelte'; - import { featureFlagsManager } from '$lib/managers/feature-flags-manager.svelte'; - import { serverConfigManager } from '$lib/managers/server-config-manager.svelte'; import { TimelineManager } from '$lib/managers/timeline-manager/timeline-manager.svelte'; import { Route } from '$lib/route'; import { getTrashActions } from '$lib/services/trash.service'; import { handlePromiseError } from '$lib/utils'; import { t } from 'svelte-i18n'; import type { PageData } from './$types'; + import { createPreloadedQuery } from '$lib/queries/client'; + import { getUserConfigQuery } from '$lib/queries/config-user.query'; + + const query = createPreloadedQuery(getUserConfigQuery); + const config = $derived(query.data); type Props = { data: PageData; @@ -27,7 +30,7 @@ let timelineManager = $state() as TimelineManager; const options = { isTrashed: true }; - if (!featureFlagsManager.value.trash) { + if (!config.trash.enabled) { handlePromiseError(goto(Route.photos())); } @@ -43,7 +46,7 @@ const { Empty, RestoreAll } = $derived(getTrashActions($t, timelineManager?.assetCount ?? 0)); -{#if featureFlagsManager.value.trash} +{#if config.trash.enabled}

{$t('trashed_items_will_be_permanently_deleted_after', { - values: { days: serverConfigManager.value.trashDays }, + values: { days: config.trash.days }, })}

{#snippet empty()} diff --git a/web/src/routes/(user)/user-settings/FeatureSettings.svelte b/web/src/routes/(user)/user-settings/FeatureSettings.svelte index 640a2425a..133066cdf 100644 --- a/web/src/routes/(user)/user-settings/FeatureSettings.svelte +++ b/web/src/routes/(user)/user-settings/FeatureSettings.svelte @@ -1,5 +1,4 @@ diff --git a/web/src/routes/admin/system-settings/+page.ts b/web/src/routes/admin/system-settings/+page.ts index 32d7f4298..a2d62e66e 100644 --- a/web/src/routes/admin/system-settings/+page.ts +++ b/web/src/routes/admin/system-settings/+page.ts @@ -1,12 +1,12 @@ import { queryClient } from '$lib/queries/client'; -import { getConfigDefaultsQuery, getConfigQuery } from '$lib/queries/system-config.query'; +import { getAdminConfigDefaultsQuery } from '$lib/queries/config-admin.query'; import { authenticate } from '$lib/utils/auth'; import { getFormatter } from '$lib/utils/i18n'; import type { PageLoad } from './$types'; export const load = (async ({ url }) => { await authenticate(url, { admin: true }); - await Promise.all([queryClient.query(getConfigQuery()), queryClient.query(getConfigDefaultsQuery())]); + await queryClient.query(getAdminConfigDefaultsQuery()); const $t = await getFormatter(); return { diff --git a/web/src/routes/admin/system-settings/AuthSettings.svelte b/web/src/routes/admin/system-settings/AuthSettings.svelte index 086b96747..2a9b34424 100644 --- a/web/src/routes/admin/system-settings/AuthSettings.svelte +++ b/web/src/routes/admin/system-settings/AuthSettings.svelte @@ -8,7 +8,7 @@ import { featureFlagsManager } from '$lib/managers/feature-flags-manager.svelte'; import AuthDisableLoginConfirmModal from '$lib/modals/AuthDisableLoginConfirmModal.svelte'; import { createPreloadedQuery } from '$lib/queries/client'; - import { getConfigQuery } from '$lib/queries/system-config.query'; + import { getAdminConfigQuery } from '$lib/queries/config-admin.query'; import { handleError } from '$lib/utils/handle-error'; import { OAuthTokenEndpointAuthMethod, unlinkAllOAuthAccountsAdmin } from '@immich/sdk'; import { Button, IconButton, Link, modalManager, Text, toastManager } from '@immich/ui'; @@ -18,7 +18,7 @@ import { fade } from 'svelte/transition'; import SettingSelect from './SettingSelect.svelte'; - const query = createPreloadedQuery(getConfigQuery); + const query = createPreloadedQuery(getAdminConfigQuery); const config = $derived(query.data); const disabled = $derived(featureFlagsManager.value.configFile); diff --git a/web/src/routes/admin/system-settings/BackupSettings.svelte b/web/src/routes/admin/system-settings/BackupSettings.svelte index b9da87d6d..6dcb1c2ae 100644 --- a/web/src/routes/admin/system-settings/BackupSettings.svelte +++ b/web/src/routes/admin/system-settings/BackupSettings.svelte @@ -1,6 +1,6 @@
diff --git a/web/src/routes/auth/onboarding/OnboardingHello.svelte b/web/src/routes/auth/onboarding/OnboardingHello.svelte index 1b5b0d2e8..deadf8bc0 100644 --- a/web/src/routes/auth/onboarding/OnboardingHello.svelte +++ b/web/src/routes/auth/onboarding/OnboardingHello.svelte @@ -1,12 +1,16 @@ diff --git a/web/src/routes/auth/onboarding/OnboardingServerPrivacy.svelte b/web/src/routes/auth/onboarding/OnboardingServerPrivacy.svelte index 46be0b922..e96b1c8f3 100644 --- a/web/src/routes/auth/onboarding/OnboardingServerPrivacy.svelte +++ b/web/src/routes/auth/onboarding/OnboardingServerPrivacy.svelte @@ -1,16 +1,16 @@