diff --git a/web/src/lib/components/server-statistics/ServerStatisticsCard.svelte b/web/src/lib/components/server-statistics/ServerStatisticsCard.svelte index a9fb831e8..b374a7696 100644 --- a/web/src/lib/components/server-statistics/ServerStatisticsCard.svelte +++ b/web/src/lib/components/server-statistics/ServerStatisticsCard.svelte @@ -1,6 +1,6 @@
{ - if (userInteraction.aboutInfo && userInteraction.versions && $serverVersion) { - info = userInteraction.aboutInfo; - versions = userInteraction.versions; - return; - } - await requestServerInfo(); - [info, versions] = await Promise.all([getAboutInfo(), getVersionHistory()]); - userInteraction.aboutInfo = info; - userInteraction.versions = versions; - }); + const aboutQuery = createQuery(() => getAboutInfoQuery()); + const info = $derived(aboutQuery.data); + const historyQuery = createQuery(() => getVersionHistoryQuery()); + const versions = $derived(historyQuery.data ?? []); let isMain = $derived(info?.sourceRef === 'main' && info.repository === 'immich-app/immich'); let version = $derived($serverVersion ? semverToName($serverVersion) : null); diff --git a/web/src/lib/components/shared-components/side-bar/StorageSpace.svelte b/web/src/lib/components/shared-components/side-bar/StorageSpace.svelte index 45c40f6c2..19a48e76a 100644 --- a/web/src/lib/components/shared-components/side-bar/StorageSpace.svelte +++ b/web/src/lib/components/shared-components/side-bar/StorageSpace.svelte @@ -1,36 +1,27 @@
- {#if userInteraction.serverInfo} + {#if serverInfo} {}); + const serverInfo = await queryClient.query(getAboutInfoQuery()).catch(() => {}); if (serverInfo?.licensed) { this.isPurchased = true; } diff --git a/web/src/lib/queries/library.query.ts b/web/src/lib/queries/library.query.ts new file mode 100644 index 000000000..920de891e --- /dev/null +++ b/web/src/lib/queries/library.query.ts @@ -0,0 +1,8 @@ +import { getLibraryStatistics } from '@immich/sdk'; +import { queryOptions } from '@tanstack/svelte-query'; + +export const getLibraryStatisticsQuery = (id: string) => + queryOptions({ + queryKey: ['libraries', id, 'statistics'], + queryFn: ({ signal }) => getLibraryStatistics({ id }, { signal }), + }); diff --git a/web/src/lib/queries/server.query.ts b/web/src/lib/queries/server.query.ts new file mode 100644 index 000000000..675658305 --- /dev/null +++ b/web/src/lib/queries/server.query.ts @@ -0,0 +1,29 @@ +import { getAboutInfo, getServerStatistics, getStorage, getVersionHistory } from '@immich/sdk'; +import { queryOptions } from '@tanstack/svelte-query'; + +export const getAboutInfoQuery = () => + queryOptions({ + queryKey: ['server', 'about'], + queryFn: ({ signal }) => getAboutInfo({ signal }), + staleTime: Infinity, + }); + +export const getVersionHistoryQuery = () => + queryOptions({ + queryKey: ['server', 'version-history'], + queryFn: ({ signal }) => getVersionHistory({ signal }), + staleTime: Infinity, + }); + +export const getStorageQuery = () => + queryOptions({ + queryKey: ['server', 'storage'], + queryFn: ({ signal }) => getStorage({ signal }), + staleTime: Infinity, + }); + +export const getServerStatisticsQuery = () => + queryOptions({ + queryKey: ['server', 'statistics'], + queryFn: ({ signal }) => getServerStatistics({ signal }), + }); diff --git a/web/src/lib/stores/user.svelte.ts b/web/src/lib/stores/user.svelte.ts index e5bb4dfa2..f1ae7f5a4 100644 --- a/web/src/lib/stores/user.svelte.ts +++ b/web/src/lib/stores/user.svelte.ts @@ -1,23 +1,12 @@ -import type { - AlbumResponseDto, - ServerAboutResponseDto, - ServerStorageResponseDto, - ServerVersionHistoryResponseDto, -} from '@immich/sdk'; +import type { AlbumResponseDto } from '@immich/sdk'; import { eventManager } from '$lib/managers/event-manager.svelte'; interface UserInteractions { recentAlbums?: AlbumResponseDto[]; - versions?: ServerVersionHistoryResponseDto[]; - aboutInfo?: ServerAboutResponseDto; - serverInfo?: ServerStorageResponseDto; } const defaultUserInteraction: UserInteractions = { recentAlbums: undefined, - versions: undefined, - aboutInfo: undefined, - serverInfo: undefined, }; export const userInteraction = $state(defaultUserInteraction); diff --git a/web/src/lib/stores/websocket.ts b/web/src/lib/stores/websocket.ts index 283038054..f9832f8c3 100644 --- a/web/src/lib/stores/websocket.ts +++ b/web/src/lib/stores/websocket.ts @@ -8,6 +8,7 @@ import { type SyncAssetEditV1, type SyncAssetV2, } from '@immich/sdk'; +import { isEqual } from 'lodash-es'; import { io, type Socket } from 'socket.io-client'; import { get, writable } from 'svelte/store'; import { page } from '$app/state'; @@ -69,7 +70,13 @@ websocket websocketStore.connected.set(true); }) .on('disconnect', () => websocketStore.connected.set(false)) - .on('on_server_version', (serverVersion) => websocketStore.serverVersion.set(serverVersion)) + .on('on_server_version', (serverVersion) => { + const previous = get(websocketStore.serverVersion); + websocketStore.serverVersion.set(serverVersion); + if (previous && !isEqual(previous, serverVersion)) { + void queryClient.invalidateQueries({ queryKey: ['server'] }); + } + }) .on( 'on_config_update', () => void queryClient.invalidateQueries({ queryKey: getConfigQuery().queryKey, exact: true }), diff --git a/web/src/lib/utils/auth.ts b/web/src/lib/utils/auth.ts index aa6ffccdb..85aaadbac 100644 --- a/web/src/lib/utils/auth.ts +++ b/web/src/lib/utils/auth.ts @@ -1,9 +1,7 @@ -import { getStorage } from '@immich/sdk'; import { redirect } from '@sveltejs/kit'; import { DateTime } from 'luxon'; import { authManager } from '$lib/managers/auth-manager.svelte'; import { Route } from '$lib/route'; -import { userInteraction } from '$lib/stores/user.svelte'; export interface AuthOptions { admin?: true; @@ -27,15 +25,6 @@ export const authenticate = async (url: URL, options?: AuthOptions) => { } }; -export const requestServerInfo = async () => { - if (!authManager.authenticated) { - return; - } - - const data = await getStorage(); - userInteraction.serverInfo = data; -}; - export const getAccountAge = (): number => { if (!authManager.authenticated) { return 0; diff --git a/web/src/lib/utils/license-utils.ts b/web/src/lib/utils/license-utils.ts index c53780ef8..45f47c9fe 100644 --- a/web/src/lib/utils/license-utils.ts +++ b/web/src/lib/utils/license-utils.ts @@ -3,6 +3,8 @@ import { PUBLIC_IMMICH_BUY_HOST, PUBLIC_IMMICH_PAY_HOST } from '$env/static/publ import type { ImmichProduct } from '$lib/constants'; import { authManager } from '$lib/managers/auth-manager.svelte'; import { serverConfigManager } from '$lib/managers/server-config-manager.svelte'; +import { queryClient } from '$lib/queries/client'; +import { getAboutInfoQuery } from '$lib/queries/server.query'; export const activateProduct = async (licenseKey: string, activationKey: string): Promise => { // TODO is this needed? @@ -11,7 +13,14 @@ export const activateProduct = async (licenseKey: string, activationKey: string) const isServerActivation = authManager.user.isAdmin && licenseKey.search('IMSV') !== -1; const licenseKeyDto = { licenseKey, activationKey }; // Send server key to user activation if user is not admin - return isServerActivation ? setServerLicense({ licenseKeyDto }) : setUserLicense({ licenseKeyDto }); + if (!isServerActivation) { + return setUserLicense({ licenseKeyDto }); + } + + const license = await setServerLicense({ licenseKeyDto }); + // contains license status + await queryClient.invalidateQueries({ queryKey: getAboutInfoQuery().queryKey }); + return license; }; export const getActivationKey = async (licenseKey: string): Promise => { diff --git a/web/src/routes/(user)/user-settings/UserPurchaseSettings.svelte b/web/src/routes/(user)/user-settings/UserPurchaseSettings.svelte index 747a7bc3a..07df2f9fe 100644 --- a/web/src/routes/(user)/user-settings/UserPurchaseSettings.svelte +++ b/web/src/routes/(user)/user-settings/UserPurchaseSettings.svelte @@ -5,13 +5,14 @@ import SettingSwitch from '$lib/components/shared-components/settings/SettingSwitch.svelte'; import { dateFormats } from '$lib/constants'; import { authManager } from '$lib/managers/auth-manager.svelte'; + import { getAboutInfoQuery } from '$lib/queries/server.query'; + import { queryClient } from '$lib/queries/client'; import { locale } from '$lib/stores/preferences.store'; import { handleError } from '$lib/utils/handle-error'; import { setSupportBadgeVisibility } from '$lib/utils/purchase-utils'; import { deleteUserLicense as deleteIndividualProductKey, deleteServerLicense as deleteServerProductKey, - getAboutInfo, getMyUser, getServerLicense, isHttpError, @@ -26,7 +27,7 @@ let serverPurchaseInfo: LicenseResponseDto | null = $state(null); const checkPurchaseInfo = async () => { - const serverInfo = await getAboutInfo(); + const serverInfo = await queryClient.query(getAboutInfoQuery()); isServerProduct = serverInfo.licensed; const response = await getMyUser(); @@ -90,6 +91,8 @@ } await deleteServerProductKey(); + // contains license status + await queryClient.invalidateQueries({ queryKey: getAboutInfoQuery().queryKey }); authManager.isPurchased = false; } catch (error) { handleError(error, $t('errors.failed_to_remove_product_key')); diff --git a/web/src/routes/admin/library-management/(list)/+layout.ts b/web/src/routes/admin/library-management/(list)/+layout.ts index 5c8442180..4721cf550 100644 --- a/web/src/routes/admin/library-management/(list)/+layout.ts +++ b/web/src/routes/admin/library-management/(list)/+layout.ts @@ -1,12 +1,11 @@ import { getAllLibraries, getLibraryStatistics, getUserAdmin, searchUsersAdmin } from '@immich/sdk'; -import { authenticate, requestServerInfo } from '$lib/utils/auth'; +import { authenticate } from '$lib/utils/auth'; import { getFormatter } from '$lib/utils/i18n'; import type { LayoutLoad } from './$types'; export const load = (async ({ url, depends }) => { depends('app:libraries'); await authenticate(url, { admin: true }); - await requestServerInfo(); const allUsers = await searchUsersAdmin({ withDeleted: false }); const $t = await getFormatter(); diff --git a/web/src/routes/admin/library-management/[id]/+layout.svelte b/web/src/routes/admin/library-management/[id]/+layout.svelte index d0a8700cc..32b412275 100644 --- a/web/src/routes/admin/library-management/[id]/+layout.svelte +++ b/web/src/routes/admin/library-management/[id]/+layout.svelte @@ -8,6 +8,8 @@ import EmptyPlaceholder from '$lib/components/shared-components/EmptyPlaceholder.svelte'; import TableButton from '$lib/components/TableButton.svelte'; import LibraryFolderAddModal from '$lib/modals/LibraryFolderAddModal.svelte'; + import { queryClient } from '$lib/queries/client'; + import { getLibraryStatisticsQuery } from '$lib/queries/library.query'; import { Route } from '$lib/route'; import { getLibraryActions, @@ -16,6 +18,7 @@ } from '$lib/services/library.service'; import { getBytesWithUnit } from '$lib/utils/byte-units'; import { Code, CommandPaletteDefaultProvider, Container, Heading, modalManager } from '@immich/ui'; + import { createQuery } from '@tanstack/svelte-query'; import { mdiCameraIris, mdiChartPie, mdiFilterMinusOutline, mdiFolderOutline, mdiPlayCircle } from '@mdi/js'; import type { Snippet } from 'svelte'; import { t } from 'svelte-i18n'; @@ -28,20 +31,25 @@ const { children, data }: Props = $props(); - const photosPromise = $derived(data.statisticsPromise.then((stats) => ({ value: stats.photos }))); - - const videosPromise = $derived(data.statisticsPromise.then((stats) => ({ value: stats.videos }))); - - const usagePromise = $derived( - data.statisticsPromise.then((stats) => { - const [value, unit] = getBytesWithUnit(stats.usage); - return { value, unit }; - }), - ); - const library = $derived(data.library); - const onLibraryUpdate = () => invalidate('app:library'); + const query = createQuery(() => getLibraryStatisticsQuery(library.id)); + const stats = $derived(query.data); + + const photos = $derived(stats && { value: stats.photos }); + const videos = $derived(stats && { value: stats.videos }); + const usage = $derived.by(() => { + if (!stats) { + return; + } + const [value, unit] = getBytesWithUnit(stats.usage); + return { value, unit }; + }); + + const onLibraryUpdate = async () => { + await invalidate('app:library'); + await queryClient.invalidateQueries({ queryKey: getLibraryStatisticsQuery(library.id).queryKey }); + }; const onLibraryDelete = async ({ id }: { id: string }) => { if (id === library.id) { @@ -64,9 +72,9 @@
{library.name}
- - - + + +
diff --git a/web/src/routes/admin/library-management/[id]/+layout.ts b/web/src/routes/admin/library-management/[id]/+layout.ts index 50b7e0791..9e2b44974 100644 --- a/web/src/routes/admin/library-management/[id]/+layout.ts +++ b/web/src/routes/admin/library-management/[id]/+layout.ts @@ -1,4 +1,4 @@ -import { getLibrary, getLibraryStatistics, type LibraryResponseDto } from '@immich/sdk'; +import { getLibrary, type LibraryResponseDto } from '@immich/sdk'; import { redirect } from '@sveltejs/kit'; import { Route } from '$lib/route'; import { authenticate } from '$lib/utils/auth'; @@ -17,12 +17,10 @@ export const load = (async ({ params: { id }, url, depends }) => { redirect(307, Route.libraries()); } - const statisticsPromise = getLibraryStatistics({ id }); const $t = await getFormatter(); return { library, - statisticsPromise, meta: { title: $t('admin.library_details'), }, diff --git a/web/src/routes/admin/maintenance/+page.svelte b/web/src/routes/admin/maintenance/+page.svelte index f7af961cb..a8163c439 100644 --- a/web/src/routes/admin/maintenance/+page.svelte +++ b/web/src/routes/admin/maintenance/+page.svelte @@ -143,7 +143,7 @@ {#snippet footer()} diff --git a/web/src/routes/admin/queues/[name]/+page.ts b/web/src/routes/admin/queues/[name]/+page.ts index b04667efb..446485e4f 100644 --- a/web/src/routes/admin/queues/[name]/+page.ts +++ b/web/src/routes/admin/queues/[name]/+page.ts @@ -1,13 +1,12 @@ import { getQueue, getQueueJobs, QueueJobStatus } from '@immich/sdk'; import { redirect } from '@sveltejs/kit'; import { fromQueueSlug, Route } from '$lib/route'; -import { authenticate, requestServerInfo } from '$lib/utils/auth'; +import { authenticate } from '$lib/utils/auth'; import { getFormatter } from '$lib/utils/i18n'; import type { PageLoad } from './$types'; export const load = (async ({ params, url }) => { await authenticate(url, { admin: true }); - await requestServerInfo(); const name = fromQueueSlug(params.name); if (!name) { diff --git a/web/src/routes/admin/server-status/+page.svelte b/web/src/routes/admin/server-status/+page.svelte index d8eb636cf..aacfeae60 100644 --- a/web/src/routes/admin/server-status/+page.svelte +++ b/web/src/routes/admin/server-status/+page.svelte @@ -1,9 +1,7 @@ - + diff --git a/web/src/routes/admin/server-status/+page.ts b/web/src/routes/admin/server-status/+page.ts index 91d478ae4..44a7861db 100644 --- a/web/src/routes/admin/server-status/+page.ts +++ b/web/src/routes/admin/server-status/+page.ts @@ -1,16 +1,18 @@ -import { getServerStatistics, searchUsersAdmin } from '@immich/sdk'; +import { searchUsersAdmin } from '@immich/sdk'; +import { noop } from 'lodash-es'; +import { queryClient } from '$lib/queries/client'; +import { getServerStatisticsQuery } from '$lib/queries/server.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 }); - const statsPromise = getServerStatistics(); + void queryClient.query(getServerStatisticsQuery()).catch(noop); const users = await searchUsersAdmin({ withDeleted: false }); const $t = await getFormatter(); return { - statsPromise, users, meta: { title: $t('server_stats'), diff --git a/web/src/routes/admin/server-status/ServerStatisticsPanel.svelte b/web/src/routes/admin/server-status/ServerStatisticsPanel.svelte index c24692ad7..3c93977d2 100644 --- a/web/src/routes/admin/server-status/ServerStatisticsPanel.svelte +++ b/web/src/routes/admin/server-status/ServerStatisticsPanel.svelte @@ -1,8 +1,9 @@ {#snippet placeholder()} @@ -66,9 +65,9 @@ {$t('total_usage')}
@@ -80,13 +79,11 @@
- {#await statsPromise} - {zeros(0)} - {:then stats} + {#if stats} {zeros(stats.photos)}{stats.photos} - {:catch} - {zeros(0)} - {/await} + {:else} + {zeros(0)} + {/if}
@@ -96,13 +93,11 @@
- {#await statsPromise} - {zeros(0)} - {:then stats} + {#if stats} {zeros(stats.videos)}{stats.videos} - {:catch} - {zeros(0)} - {/await} + {:else} + {zeros(0)} + {/if}
@@ -112,9 +107,7 @@
- {#await statsPromise} - {zeros(0)} - {:then stats} + {#if stats} {@const storageUsageWithUnit = getStorageUsageWithUnit(stats.usage)} {zeros(storageUsageWithUnit[0])}{storageUsageWithUnit[0]} {storageUsageWithUnit[1]}
- {:catch} - {zeros(0)} - {/await} + {:else} + {zeros(0)} + {/if}
@@ -145,42 +138,39 @@ {#each users as user (user.id)} {user.name} - {#await getUserStatsPromise(user.id)} - {@render placeholder()} - {:then userStats} - {#if userStats} - - {userStats.photos.toLocaleString($locale)} () - - {userStats.videos.toLocaleString($locale)} () - - - {#if userStats.quotaSizeInBytes !== null} - / + {@const userStats = getUserStats(user.id)} + {#if userStats} + + {userStats.photos.toLocaleString($locale)} () + + {userStats.videos.toLocaleString($locale)} () + + + {#if userStats.quotaSizeInBytes !== null} + / + {/if} + + {#if userStats.quotaSizeInBytes !== null && userStats.quotaSizeInBytes >= 0} + ({(userStats.quotaSizeInBytes === 0 + ? 1 + : userStats.usage / userStats.quotaSizeInBytes + ).toLocaleString($locale, { + style: 'percent', + maximumFractionDigits: 0, + })}) + {:else} + ({$t('unlimited')}) {/if} - - {#if userStats.quotaSizeInBytes !== null && userStats.quotaSizeInBytes >= 0} - ({(userStats.quotaSizeInBytes === 0 - ? 1 - : userStats.usage / userStats.quotaSizeInBytes - ).toLocaleString($locale, { - style: 'percent', - maximumFractionDigits: 0, - })}) - {:else} - ({$t('unlimited')}) - {/if} - - - {:else} - {@render placeholder()} - {/if} - {/await} + + + {:else} + {@render placeholder()} + {/if} {/each} diff --git a/web/src/routes/admin/system-settings/TemplateSettings.svelte b/web/src/routes/admin/system-settings/TemplateSettings.svelte index 33f9b4b14..de722843c 100644 --- a/web/src/routes/admin/system-settings/TemplateSettings.svelte +++ b/web/src/routes/admin/system-settings/TemplateSettings.svelte @@ -18,7 +18,7 @@ let { config = $bindable() }: Props = $props(); - const saved = createDefinedQuery(getConfigQuery()); + const query = createDefinedQuery(getConfigQuery()); let loadingPreview = $state(false); @@ -56,7 +56,7 @@ ]; const isEdited = (templateKey: keyof AdminConfigTemplateEmailsDto) => - config.templates.email[templateKey] !== saved.data.templates.email[templateKey]; + config.templates.email[templateKey] !== query.data.templates.email[templateKey]; const onsubmit = (event: Event) => { event.preventDefault(); diff --git a/web/src/routes/admin/users/(list)/+layout.ts b/web/src/routes/admin/users/(list)/+layout.ts index d7c66a722..a8941ad8a 100644 --- a/web/src/routes/admin/users/(list)/+layout.ts +++ b/web/src/routes/admin/users/(list)/+layout.ts @@ -1,11 +1,10 @@ import { searchUsersAdmin } from '@immich/sdk'; -import { authenticate, requestServerInfo } from '$lib/utils/auth'; +import { authenticate } from '$lib/utils/auth'; import { getFormatter } from '$lib/utils/i18n'; import type { LayoutLoad } from './$types'; export const load = (async ({ url }) => { await authenticate(url, { admin: true }); - await requestServerInfo(); const users = await searchUsersAdmin({ withDeleted: true }); const $t = await getFormatter(); diff --git a/web/src/routes/admin/users/(list)/new/+page.svelte b/web/src/routes/admin/users/(list)/new/+page.svelte index 7eaa1080b..20faf2c4e 100644 --- a/web/src/routes/admin/users/(list)/new/+page.svelte +++ b/web/src/routes/admin/users/(list)/new/+page.svelte @@ -3,11 +3,15 @@ import { featureFlagsManager } from '$lib/managers/feature-flags-manager.svelte'; import { Route } from '$lib/route'; import { handleCreateUserAdmin } from '$lib/services/user-admin.service'; - import { userInteraction } from '$lib/stores/user.svelte'; + import { getStorageQuery } from '$lib/queries/server.query'; import { ByteUnit, convertToBytes } from '$lib/utils/byte-units'; import { Field, FormModal, HelperText, Input, PasswordInput, Stack, Switch } from '@immich/ui'; + import { createQuery } from '@tanstack/svelte-query'; import { t } from 'svelte-i18n'; + const query = createQuery(() => getStorageQuery()); + const serverInfo = $derived(query.data); + let success = $state(false); let email = $state(''); @@ -22,9 +26,7 @@ let isCreatingUser = $state(false); let quotaSizeInBytes = $derived(quotaSize === null ? null : convertToBytes(Number(quotaSize), ByteUnit.GiB)); - let quotaSizeWarning = $derived( - quotaSizeInBytes && userInteraction.serverInfo && quotaSizeInBytes > userInteraction.serverInfo.diskSizeRaw, - ); + let quotaSizeWarning = $derived(quotaSizeInBytes && serverInfo && quotaSizeInBytes > serverInfo.diskSizeRaw); const passwordMismatch = $derived(password !== passwordConfirm && passwordConfirm.length > 0); const passwordMismatchMessage = $derived(passwordMismatch ? $t('password_does_not_match') : ''); diff --git a/web/src/routes/admin/users/[id]/+layout.svelte b/web/src/routes/admin/users/[id]/+layout.svelte index dc49e5f42..6726883cb 100644 --- a/web/src/routes/admin/users/[id]/+layout.svelte +++ b/web/src/routes/admin/users/[id]/+layout.svelte @@ -122,20 +122,12 @@
- - + +
diff --git a/web/src/routes/admin/users/[id]/+layout.ts b/web/src/routes/admin/users/[id]/+layout.ts index 56e3a470d..12546452c 100644 --- a/web/src/routes/admin/users/[id]/+layout.ts +++ b/web/src/routes/admin/users/[id]/+layout.ts @@ -2,13 +2,12 @@ import { getUserPreferencesAdmin, getUserSessionsAdmin, getUserStatisticsAdmin, import { redirect } from '@sveltejs/kit'; import { UUID_REGEX } from '$lib/constants'; import { Route } from '$lib/route'; -import { authenticate, requestServerInfo } from '$lib/utils/auth'; +import { authenticate } from '$lib/utils/auth'; import { getFormatter } from '$lib/utils/i18n'; import type { LayoutLoad } from './$types'; export const load = (async ({ params, url }) => { await authenticate(url, { admin: true }); - await requestServerInfo(); if (!UUID_REGEX.test(params.id)) { redirect(307, Route.users()); diff --git a/web/src/routes/admin/users/[id]/edit/+page.svelte b/web/src/routes/admin/users/[id]/edit/+page.svelte index 9c1262fa2..289ee93f6 100644 --- a/web/src/routes/admin/users/[id]/edit/+page.svelte +++ b/web/src/routes/admin/users/[id]/edit/+page.svelte @@ -3,9 +3,10 @@ import { authManager } from '$lib/managers/auth-manager.svelte'; import { Route } from '$lib/route'; import { handleUpdateUserAdmin } from '$lib/services/user-admin.service'; - import { userInteraction } from '$lib/stores/user.svelte'; + import { getStorageQuery } from '$lib/queries/server.query'; import { ByteUnit, convertFromBytes, convertToBytes } from '$lib/utils/byte-units'; import { Field, FormModal, Input, Link, NumberInput, Switch, Text } from '@immich/ui'; + import { createQuery } from '@tanstack/svelte-query'; import { mdiAccountEditOutline } from '@mdi/js'; import { t } from 'svelte-i18n'; import type { PageData } from './$types'; @@ -16,6 +17,9 @@ let { data }: Props = $props(); + const query = createQuery(() => getStorageQuery()); + const serverInfo = $derived(query.data); + const user = $derived(data.user); let { isAdmin, name, email } = $derived(user); let storageLabel = $derived(user.storageLabel || ''); @@ -28,10 +32,7 @@ const quotaSizeBytes = $derived(typeof quotaSize === 'number' ? convertToBytes(quotaSize, ByteUnit.GiB) : null); let quotaSizeWarning = $derived( - previousQuota !== quotaSizeBytes && - !!quotaSizeBytes && - userInteraction.serverInfo && - quotaSizeBytes > userInteraction.serverInfo.diskSizeRaw, + previousQuota !== quotaSizeBytes && !!quotaSizeBytes && serverInfo && quotaSizeBytes > serverInfo.diskSizeRaw, ); const onClose = async () => {