mirror of
https://github.com/immich-app/immich.git
synced 2026-05-18 03:10:24 +03:00
refactor: server config and feature flags managers (#23894)
This commit is contained in:
+2
-2
@@ -30,6 +30,7 @@
|
||||
import Timeline from '$lib/components/timeline/Timeline.svelte';
|
||||
import { AlbumPageViewMode, AppRoute } from '$lib/constants';
|
||||
import { activityManager } from '$lib/managers/activity-manager.svelte';
|
||||
import { featureFlagsManager } from '$lib/managers/feature-flags-manager.svelte';
|
||||
import { TimelineManager } from '$lib/managers/timeline-manager/timeline-manager.svelte';
|
||||
import type { TimelineAsset } from '$lib/managers/timeline-manager/types';
|
||||
import AlbumOptionsModal from '$lib/modals/AlbumOptionsModal.svelte';
|
||||
@@ -40,7 +41,6 @@
|
||||
import { AssetInteraction } from '$lib/stores/asset-interaction.svelte';
|
||||
import { assetViewingStore } from '$lib/stores/asset-viewing.store';
|
||||
import { SlideshowNavigation, SlideshowState, slideshowStore } from '$lib/stores/slideshow.store';
|
||||
import { featureFlags } from '$lib/stores/system-config-manager.svelte';
|
||||
import { preferences, user } from '$lib/stores/user.store';
|
||||
import { handlePromiseError } from '$lib/utils';
|
||||
import { cancelMultiselect } from '$lib/utils/asset-utils';
|
||||
@@ -619,7 +619,7 @@
|
||||
/>
|
||||
{/if}
|
||||
|
||||
{#if $featureFlags.loaded && $featureFlags.map}
|
||||
{#if featureFlagsManager.value.map}
|
||||
<AlbumMap {album} />
|
||||
{/if}
|
||||
|
||||
|
||||
@@ -1,16 +1,14 @@
|
||||
<script lang="ts">
|
||||
import { goto } from '$app/navigation';
|
||||
import UserPageLayout from '$lib/components/layouts/user-page-layout.svelte';
|
||||
import { AppRoute, timeToLoadTheMap } from '$lib/constants';
|
||||
import { timeToLoadTheMap } from '$lib/constants';
|
||||
import Portal from '$lib/elements/Portal.svelte';
|
||||
import { featureFlagsManager } from '$lib/managers/feature-flags-manager.svelte';
|
||||
import { assetViewingStore } from '$lib/stores/asset-viewing.store';
|
||||
import { featureFlags } from '$lib/stores/system-config-manager.svelte';
|
||||
import { handlePromiseError } from '$lib/utils';
|
||||
import { delay } from '$lib/utils/asset-utils';
|
||||
import { navigate } from '$lib/utils/navigation';
|
||||
import { LoadingSpinner } from '@immich/ui';
|
||||
import { onDestroy } from 'svelte';
|
||||
import { run } from 'svelte/legacy';
|
||||
import type { PageData } from './$types';
|
||||
|
||||
interface Props {
|
||||
@@ -28,12 +26,6 @@
|
||||
assetViewingStore.showAssetViewer(false);
|
||||
});
|
||||
|
||||
run(() => {
|
||||
if (!$featureFlags.map) {
|
||||
handlePromiseError(goto(AppRoute.PHOTOS));
|
||||
}
|
||||
});
|
||||
|
||||
async function onViewAssets(assetIds: string[]) {
|
||||
viewingAssets = assetIds;
|
||||
viewingAssetCursor = 0;
|
||||
@@ -69,7 +61,7 @@
|
||||
}
|
||||
</script>
|
||||
|
||||
{#if $featureFlags.loaded && $featureFlags.map}
|
||||
{#if featureFlagsManager.value.map}
|
||||
<UserPageLayout title={data.meta.title}>
|
||||
<div class="isolate h-full w-full">
|
||||
{#await import('$lib/components/shared-components/map/map.svelte')}
|
||||
|
||||
@@ -1,3 +1,7 @@
|
||||
import { goto } from '$app/navigation';
|
||||
import { AppRoute } from '$lib/constants';
|
||||
import { featureFlagsManager } from '$lib/managers/feature-flags-manager.svelte';
|
||||
import { handlePromiseError } from '$lib/utils';
|
||||
import { authenticate } from '$lib/utils/auth';
|
||||
import { getFormatter } from '$lib/utils/i18n';
|
||||
import { getAssetInfoFromParam } from '$lib/utils/navigation';
|
||||
@@ -8,6 +12,10 @@ export const load = (async ({ params, url }) => {
|
||||
const asset = await getAssetInfoFromParam(params);
|
||||
const $t = await getFormatter();
|
||||
|
||||
if (!featureFlagsManager.value.map) {
|
||||
handlePromiseError(goto(AppRoute.PHOTOS));
|
||||
}
|
||||
|
||||
return {
|
||||
asset,
|
||||
meta: {
|
||||
|
||||
@@ -21,11 +21,11 @@
|
||||
import TagAction from '$lib/components/timeline/actions/TagAction.svelte';
|
||||
import AssetSelectControlBar from '$lib/components/timeline/AssetSelectControlBar.svelte';
|
||||
import { AppRoute, QueryParameter } from '$lib/constants';
|
||||
import { featureFlagsManager } from '$lib/managers/feature-flags-manager.svelte';
|
||||
import type { TimelineAsset, Viewport } from '$lib/managers/timeline-manager/types';
|
||||
import { AssetInteraction } from '$lib/stores/asset-interaction.svelte';
|
||||
import { assetViewingStore } from '$lib/stores/asset-viewing.store';
|
||||
import { lang, locale } from '$lib/stores/preferences.store';
|
||||
import { featureFlags } from '$lib/stores/system-config-manager.svelte';
|
||||
import { preferences } from '$lib/stores/user.store';
|
||||
import { handlePromiseError } from '$lib/utils';
|
||||
import { cancelMultiselect } from '$lib/utils/asset-utils';
|
||||
@@ -67,7 +67,7 @@
|
||||
|
||||
type SearchTerms = MetadataSearchDto & Pick<SmartSearchDto, 'query' | 'queryAssetId'>;
|
||||
let searchQuery = $derived(page.url.searchParams.get(QueryParameter.QUERY));
|
||||
let smartSearchEnabled = $derived($featureFlags.loaded && $featureFlags.smartSearch);
|
||||
let smartSearchEnabled = $derived(featureFlagsManager.value.smartSearch);
|
||||
let terms = $derived(searchQuery ? JSON.parse(searchQuery) : {});
|
||||
|
||||
$effect(() => {
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
<script lang="ts">
|
||||
import { goto } from '$app/navigation';
|
||||
import empty3Url from '$lib/assets/empty-3.svg';
|
||||
import UserPageLayout from '$lib/components/layouts/user-page-layout.svelte';
|
||||
import EmptyPlaceholder from '$lib/components/shared-components/empty-placeholder.svelte';
|
||||
@@ -8,11 +7,10 @@
|
||||
import SelectAllAssets from '$lib/components/timeline/actions/SelectAllAction.svelte';
|
||||
import AssetSelectControlBar from '$lib/components/timeline/AssetSelectControlBar.svelte';
|
||||
import Timeline from '$lib/components/timeline/Timeline.svelte';
|
||||
import { AppRoute } from '$lib/constants';
|
||||
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 { AssetInteraction } from '$lib/stores/asset-interaction.svelte';
|
||||
import { featureFlags, serverConfig } from '$lib/stores/system-config-manager.svelte';
|
||||
import { handlePromiseError } from '$lib/utils';
|
||||
import { handleError } from '$lib/utils/handle-error';
|
||||
import { emptyTrash, restoreTrash } from '@immich/sdk';
|
||||
import { Button, HStack, modalManager, Text, toastManager } from '@immich/ui';
|
||||
@@ -26,10 +24,6 @@
|
||||
|
||||
let { data }: Props = $props();
|
||||
|
||||
if (!$featureFlags.trash) {
|
||||
handlePromiseError(goto(AppRoute.PHOTOS));
|
||||
}
|
||||
|
||||
let timelineManager = $state<TimelineManager>() as TimelineManager;
|
||||
const options = { isTrashed: true };
|
||||
|
||||
@@ -76,7 +70,7 @@
|
||||
};
|
||||
</script>
|
||||
|
||||
{#if $featureFlags.loaded && $featureFlags.trash}
|
||||
{#if featureFlagsManager.value.trash}
|
||||
<UserPageLayout hideNavbar={assetInteraction.selectionActive} title={data.meta.title} scrollbar={false}>
|
||||
{#snippet buttons()}
|
||||
<HStack gap={0}>
|
||||
@@ -105,7 +99,9 @@
|
||||
|
||||
<Timeline enableRouting={true} bind:timelineManager {options} {assetInteraction} onEscape={handleEscape}>
|
||||
<p class="font-medium text-gray-500/60 dark:text-gray-300/60 p-4">
|
||||
{$t('trashed_items_will_be_permanently_deleted_after', { values: { days: $serverConfig.trashDays } })}
|
||||
{$t('trashed_items_will_be_permanently_deleted_after', {
|
||||
values: { days: serverConfigManager.value.trashDays },
|
||||
})}
|
||||
</p>
|
||||
{#snippet empty()}
|
||||
<EmptyPlaceholder text={$t('trash_no_results_message')} src={empty3Url} />
|
||||
|
||||
@@ -1,3 +1,7 @@
|
||||
import { goto } from '$app/navigation';
|
||||
import { AppRoute } from '$lib/constants';
|
||||
import { featureFlagsManager } from '$lib/managers/feature-flags-manager.svelte';
|
||||
import { handlePromiseError } from '$lib/utils';
|
||||
import { authenticate } from '$lib/utils/auth';
|
||||
import { getFormatter } from '$lib/utils/i18n';
|
||||
import { getAssetInfoFromParam } from '$lib/utils/navigation';
|
||||
@@ -8,6 +12,10 @@ export const load = (async ({ params, url }) => {
|
||||
const asset = await getAssetInfoFromParam(params);
|
||||
const $t = await getFormatter();
|
||||
|
||||
if (!featureFlagsManager.value.trash) {
|
||||
handlePromiseError(goto(AppRoute.PHOTOS));
|
||||
}
|
||||
|
||||
return {
|
||||
asset,
|
||||
meta: {
|
||||
|
||||
+7
-7
@@ -5,11 +5,11 @@
|
||||
import UserPageLayout from '$lib/components/layouts/user-page-layout.svelte';
|
||||
import DuplicatesCompareControl from '$lib/components/utilities-page/duplicates/duplicates-compare-control.svelte';
|
||||
import { AppRoute } from '$lib/constants';
|
||||
import { featureFlagsManager } from '$lib/managers/feature-flags-manager.svelte';
|
||||
import DuplicatesInformationModal from '$lib/modals/DuplicatesInformationModal.svelte';
|
||||
import ShortcutsModal from '$lib/modals/ShortcutsModal.svelte';
|
||||
import { assetViewingStore } from '$lib/stores/asset-viewing.store';
|
||||
import { locale } from '$lib/stores/preferences.store';
|
||||
import { featureFlags } from '$lib/stores/system-config-manager.svelte';
|
||||
import { stackAssets } from '$lib/utils/asset-utils';
|
||||
import { suggestDuplicate } from '$lib/utils/duplicate-utils';
|
||||
import { handleError } from '$lib/utils/handle-error';
|
||||
@@ -92,7 +92,7 @@
|
||||
return;
|
||||
}
|
||||
|
||||
const message = $featureFlags.trash
|
||||
const message = featureFlagsManager.value.trash
|
||||
? $t('assets_moved_to_trash_count', { values: { count: trashedCount } })
|
||||
: $t('permanently_deleted_assets_count', { values: { count: trashedCount } });
|
||||
toastManager.success(message);
|
||||
@@ -101,7 +101,7 @@
|
||||
const handleResolve = async (duplicateId: string, duplicateAssetIds: string[], trashIds: string[]) => {
|
||||
return withConfirmation(
|
||||
async () => {
|
||||
await deleteAssets({ assetBulkDeleteDto: { ids: trashIds, force: !$featureFlags.trash } });
|
||||
await deleteAssets({ assetBulkDeleteDto: { ids: trashIds, force: !featureFlagsManager.value.trash } });
|
||||
await updateAssets({ assetBulkUpdateDto: { ids: duplicateAssetIds, duplicateId: null } });
|
||||
|
||||
duplicates = duplicates.filter((duplicate) => duplicate.duplicateId !== duplicateId);
|
||||
@@ -109,8 +109,8 @@
|
||||
deletedNotification(trashIds.length);
|
||||
await correctDuplicatesIndexAndGo(duplicatesIndex);
|
||||
},
|
||||
trashIds.length > 0 && !$featureFlags.trash ? $t('delete_duplicates_confirmation') : undefined,
|
||||
trashIds.length > 0 && !$featureFlags.trash ? $t('permanently_delete') : undefined,
|
||||
trashIds.length > 0 && !featureFlagsManager.value.trash ? $t('delete_duplicates_confirmation') : undefined,
|
||||
trashIds.length > 0 && !featureFlagsManager.value.trash ? $t('permanently_delete') : undefined,
|
||||
);
|
||||
};
|
||||
|
||||
@@ -129,7 +129,7 @@
|
||||
);
|
||||
|
||||
let prompt, confirmText;
|
||||
if ($featureFlags.trash) {
|
||||
if (featureFlagsManager.value.trash) {
|
||||
prompt = $t('bulk_trash_duplicates_confirmation', { values: { count: idsToDelete.length } });
|
||||
confirmText = $t('confirm');
|
||||
} else {
|
||||
@@ -139,7 +139,7 @@
|
||||
|
||||
return withConfirmation(
|
||||
async () => {
|
||||
await deleteAssets({ assetBulkDeleteDto: { ids: idsToDelete, force: !$featureFlags.trash } });
|
||||
await deleteAssets({ assetBulkDeleteDto: { ids: idsToDelete, force: !featureFlagsManager.value.trash } });
|
||||
await updateAssets({
|
||||
assetBulkUpdateDto: {
|
||||
ids: [...idsToDelete, ...idsToKeep.filter((id): id is string => !!id)],
|
||||
|
||||
@@ -8,8 +8,8 @@
|
||||
import NavigationLoadingBar from '$lib/components/shared-components/navigation-loading-bar.svelte';
|
||||
import UploadPanel from '$lib/components/shared-components/upload-panel.svelte';
|
||||
import { eventManager } from '$lib/managers/event-manager.svelte';
|
||||
import { serverConfigManager } from '$lib/managers/server-config-manager.svelte';
|
||||
import VersionAnnouncementModal from '$lib/modals/VersionAnnouncementModal.svelte';
|
||||
import { serverConfig } from '$lib/stores/system-config-manager.svelte';
|
||||
import { user } from '$lib/stores/user.store';
|
||||
import {
|
||||
closeWebsocketConnection,
|
||||
@@ -120,7 +120,10 @@
|
||||
{#if page.data.meta.imageUrl}
|
||||
<meta
|
||||
property="og:image"
|
||||
content={new URL(page.data.meta.imageUrl, $serverConfig.externalDomain || globalThis.location.origin).href}
|
||||
content={new URL(
|
||||
page.data.meta.imageUrl,
|
||||
serverConfigManager.value.externalDomain || globalThis.location.origin,
|
||||
).href}
|
||||
/>
|
||||
{/if}
|
||||
|
||||
@@ -131,7 +134,10 @@
|
||||
{#if page.data.meta.imageUrl}
|
||||
<meta
|
||||
name="twitter:image"
|
||||
content={new URL(page.data.meta.imageUrl, $serverConfig.externalDomain || globalThis.location.origin).href}
|
||||
content={new URL(
|
||||
page.data.meta.imageUrl,
|
||||
serverConfigManager.value.externalDomain || globalThis.location.origin,
|
||||
).href}
|
||||
/>
|
||||
{/if}
|
||||
{/if}
|
||||
|
||||
@@ -1,10 +1,8 @@
|
||||
import { AppRoute } from '$lib/constants';
|
||||
import { serverConfig } from '$lib/stores/system-config-manager.svelte';
|
||||
import { serverConfigManager } from '$lib/managers/server-config-manager.svelte';
|
||||
import { getFormatter } from '$lib/utils/i18n';
|
||||
import { init } from '$lib/utils/server';
|
||||
|
||||
import { redirect } from '@sveltejs/kit';
|
||||
import { get } from 'svelte/store';
|
||||
import { loadUser } from '../lib/utils/auth';
|
||||
import type { PageLoad } from './$types';
|
||||
|
||||
@@ -19,8 +17,7 @@ export const load = (async ({ fetch }) => {
|
||||
redirect(302, AppRoute.PHOTOS);
|
||||
}
|
||||
|
||||
const { isInitialized } = get(serverConfig);
|
||||
if (isInitialized) {
|
||||
if (serverConfigManager.value.isInitialized) {
|
||||
// Redirect to login page if there exists an admin account (i.e. server is initialized)
|
||||
redirect(302, AppRoute.AUTH_LOGIN);
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { systemConfigManager } from '$lib/stores/system-config-manager.svelte';
|
||||
import { systemConfigManager } from '$lib/managers/system-config-manager.svelte';
|
||||
import type { LayoutLoad } from './$types';
|
||||
|
||||
export const load = (async () => {
|
||||
|
||||
@@ -23,8 +23,9 @@
|
||||
import SettingAccordion from '$lib/components/shared-components/settings/setting-accordion.svelte';
|
||||
import { QueryParameter } from '$lib/constants';
|
||||
import SearchBar from '$lib/elements/SearchBar.svelte';
|
||||
import { featureFlagsManager } from '$lib/managers/feature-flags-manager.svelte';
|
||||
import { systemConfigManager } from '$lib/managers/system-config-manager.svelte';
|
||||
import { getSystemConfigActions } from '$lib/services/system-config.service';
|
||||
import { featureFlags, systemConfigManager } from '$lib/stores/system-config-manager.svelte';
|
||||
import { Alert, HStack } from '@immich/ui';
|
||||
import {
|
||||
mdiAccountOutline,
|
||||
@@ -201,7 +202,7 @@
|
||||
);
|
||||
|
||||
const { CopyToClipboard, Upload, Download } = $derived(
|
||||
getSystemConfigActions($t, $featureFlags, systemConfigManager.value),
|
||||
getSystemConfigActions($t, featureFlagsManager.value, systemConfigManager.value),
|
||||
);
|
||||
</script>
|
||||
|
||||
@@ -219,7 +220,7 @@
|
||||
|
||||
<section id="setting-content" class="flex place-content-center sm:mx-4">
|
||||
<section class="w-full pb-28 sm:w-5/6 md:w-4xl">
|
||||
{#if $featureFlags.configFile}
|
||||
{#if featureFlagsManager.value.configFile}
|
||||
<Alert color="warning" class="text-dark my-4" title={$t('admin.config_set_by_file')} />
|
||||
{/if}
|
||||
<div class="block lg:hidden">
|
||||
|
||||
@@ -3,7 +3,8 @@
|
||||
import AuthPageLayout from '$lib/components/layouts/AuthPageLayout.svelte';
|
||||
import { AppRoute } from '$lib/constants';
|
||||
import { eventManager } from '$lib/managers/event-manager.svelte';
|
||||
import { featureFlags, serverConfig } from '$lib/stores/system-config-manager.svelte';
|
||||
import { featureFlagsManager } from '$lib/managers/feature-flags-manager.svelte';
|
||||
import { serverConfigManager } from '$lib/managers/server-config-manager.svelte';
|
||||
import { oauth } from '$lib/utils';
|
||||
import { getServerErrorMessage, handleError } from '$lib/utils/handle-error';
|
||||
import { login, type LoginResponseDto } from '@immich/sdk';
|
||||
@@ -25,6 +26,8 @@
|
||||
let loading = $state(false);
|
||||
let oauthLoading = $state(true);
|
||||
|
||||
const serverConfig = $derived(serverConfigManager.value);
|
||||
|
||||
const onSuccess = async (user: LoginResponseDto) => {
|
||||
await goto(data.continueUrl, { invalidateAll: true });
|
||||
eventManager.emit('AuthLogin', user);
|
||||
@@ -34,7 +37,7 @@
|
||||
const onOnboarding = () => goto(AppRoute.AUTH_ONBOARDING);
|
||||
|
||||
onMount(async () => {
|
||||
if (!$featureFlags.oauth) {
|
||||
if (!featureFlagsManager.value.oauth) {
|
||||
oauthLoading = false;
|
||||
return;
|
||||
}
|
||||
@@ -60,7 +63,7 @@
|
||||
|
||||
try {
|
||||
if (
|
||||
($featureFlags.oauthAutoLaunch && !oauth.isAutoLaunchDisabled(globalThis.location)) ||
|
||||
(featureFlagsManager.value.oauthAutoLaunch && !oauth.isAutoLaunchDisabled(globalThis.location)) ||
|
||||
oauth.isAutoLaunchEnabled(globalThis.location)
|
||||
) {
|
||||
await goto(`${AppRoute.AUTH_LOGIN}?autoLaunch=0`, { replaceState: true });
|
||||
@@ -80,7 +83,7 @@
|
||||
loading = true;
|
||||
const user = await login({ loginCredentialDto: { email, password } });
|
||||
|
||||
if (user.isAdmin && !$serverConfig.isOnboarded) {
|
||||
if (user.isAdmin && !serverConfig.isOnboarded) {
|
||||
await onOnboarding();
|
||||
return;
|
||||
}
|
||||
@@ -123,64 +126,62 @@
|
||||
};
|
||||
</script>
|
||||
|
||||
{#if $featureFlags.loaded}
|
||||
<AuthPageLayout title={data.meta.title}>
|
||||
<Stack gap={4}>
|
||||
{#if $serverConfig.loginPageMessage}
|
||||
<Alert color="primary" class="mb-6">
|
||||
<!-- eslint-disable-next-line svelte/no-at-html-tags -->
|
||||
{@html $serverConfig.loginPageMessage}
|
||||
</Alert>
|
||||
{/if}
|
||||
<AuthPageLayout title={data.meta.title}>
|
||||
<Stack gap={4}>
|
||||
{#if serverConfig.loginPageMessage}
|
||||
<Alert color="primary" class="mb-6">
|
||||
<!-- eslint-disable-next-line svelte/no-at-html-tags -->
|
||||
{@html serverConfig.loginPageMessage}
|
||||
</Alert>
|
||||
{/if}
|
||||
|
||||
{#if !oauthLoading && $featureFlags.passwordLogin}
|
||||
<form {onsubmit} class="flex flex-col gap-4">
|
||||
{#if errorMessage}
|
||||
<Alert color="danger" title={errorMessage} closable />
|
||||
{/if}
|
||||
|
||||
<Field label={$t('email')}>
|
||||
<Input id="email" name="email" type="email" autocomplete="email" bind:value={email} />
|
||||
</Field>
|
||||
|
||||
<Field label={$t('password')}>
|
||||
<PasswordInput id="password" bind:value={password} autocomplete="current-password" />
|
||||
</Field>
|
||||
|
||||
<Button type="submit" size="large" shape="round" fullWidth {loading} class="mt-6">{$t('to_login')}</Button>
|
||||
</form>
|
||||
{/if}
|
||||
|
||||
{#if $featureFlags.oauth}
|
||||
{#if $featureFlags.passwordLogin}
|
||||
<div class="inline-flex w-full items-center justify-center my-4">
|
||||
<hr class="my-4 h-px w-3/4 border-0 bg-gray-200 dark:bg-gray-600" />
|
||||
<span
|
||||
class="absolute start-1/2 -translate-x-1/2 bg-gray-50 px-3 font-medium text-gray-900 dark:bg-neutral-900 dark:text-white uppercase"
|
||||
>
|
||||
{$t('or')}
|
||||
</span>
|
||||
</div>
|
||||
{#if !oauthLoading && featureFlagsManager.value.passwordLogin}
|
||||
<form {onsubmit} class="flex flex-col gap-4">
|
||||
{#if errorMessage}
|
||||
<Alert color="danger" title={errorMessage} closable />
|
||||
{/if}
|
||||
{#if oauthError}
|
||||
<Alert color="danger" title={oauthError} closable />
|
||||
{/if}
|
||||
<Button
|
||||
shape="round"
|
||||
loading={loading || oauthLoading}
|
||||
disabled={loading || oauthLoading}
|
||||
size="large"
|
||||
fullWidth
|
||||
color={$featureFlags.passwordLogin ? 'secondary' : 'primary'}
|
||||
onclick={handleOAuthLogin}
|
||||
>
|
||||
{$serverConfig.oauthButtonText}
|
||||
</Button>
|
||||
{/if}
|
||||
|
||||
{#if !$featureFlags.passwordLogin && !$featureFlags.oauth}
|
||||
<Alert color="warning" title={$t('login_has_been_disabled')} />
|
||||
<Field label={$t('email')}>
|
||||
<Input id="email" name="email" type="email" autocomplete="email" bind:value={email} />
|
||||
</Field>
|
||||
|
||||
<Field label={$t('password')}>
|
||||
<PasswordInput id="password" bind:value={password} autocomplete="current-password" />
|
||||
</Field>
|
||||
|
||||
<Button type="submit" size="large" shape="round" fullWidth {loading} class="mt-6">{$t('to_login')}</Button>
|
||||
</form>
|
||||
{/if}
|
||||
|
||||
{#if featureFlagsManager.value.oauth}
|
||||
{#if featureFlagsManager.value.passwordLogin}
|
||||
<div class="inline-flex w-full items-center justify-center my-4">
|
||||
<hr class="my-4 h-px w-3/4 border-0 bg-gray-200 dark:bg-gray-600" />
|
||||
<span
|
||||
class="absolute start-1/2 -translate-x-1/2 bg-gray-50 px-3 font-medium text-gray-900 dark:bg-neutral-900 dark:text-white uppercase"
|
||||
>
|
||||
{$t('or')}
|
||||
</span>
|
||||
</div>
|
||||
{/if}
|
||||
</Stack>
|
||||
</AuthPageLayout>
|
||||
{/if}
|
||||
{#if oauthError}
|
||||
<Alert color="danger" title={oauthError} closable />
|
||||
{/if}
|
||||
<Button
|
||||
shape="round"
|
||||
loading={loading || oauthLoading}
|
||||
disabled={loading || oauthLoading}
|
||||
size="large"
|
||||
fullWidth
|
||||
color={featureFlagsManager.value.passwordLogin ? 'secondary' : 'primary'}
|
||||
onclick={handleOAuthLogin}
|
||||
>
|
||||
{serverConfig.oauthButtonText}
|
||||
</Button>
|
||||
{/if}
|
||||
|
||||
{#if !featureFlagsManager.value.passwordLogin && !featureFlagsManager.value.oauth}
|
||||
<Alert color="warning" title={$t('login_has_been_disabled')} />
|
||||
{/if}
|
||||
</Stack>
|
||||
</AuthPageLayout>
|
||||
|
||||
@@ -1,16 +1,13 @@
|
||||
import { AppRoute } from '$lib/constants';
|
||||
import { serverConfig } from '$lib/stores/system-config-manager.svelte';
|
||||
import { serverConfigManager } from '$lib/managers/server-config-manager.svelte';
|
||||
import { getFormatter } from '$lib/utils/i18n';
|
||||
|
||||
import { redirect } from '@sveltejs/kit';
|
||||
import { get } from 'svelte/store';
|
||||
import type { PageLoad } from './$types';
|
||||
|
||||
export const load = (async ({ parent, url }) => {
|
||||
await parent();
|
||||
const { isInitialized } = get(serverConfig);
|
||||
|
||||
if (!isInitialized) {
|
||||
if (!serverConfigManager.value.isInitialized) {
|
||||
// Admin not registered
|
||||
redirect(302, AppRoute.AUTH_REGISTER);
|
||||
}
|
||||
|
||||
@@ -11,8 +11,9 @@
|
||||
import OnboardingTheme from '$lib/components/onboarding-page/onboarding-theme.svelte';
|
||||
import OnboardingUserPrivacy from '$lib/components/onboarding-page/onboarding-user-privacy.svelte';
|
||||
import { AppRoute, QueryParameter } from '$lib/constants';
|
||||
import { serverConfigManager } from '$lib/managers/server-config-manager.svelte';
|
||||
import { systemConfigManager } from '$lib/managers/system-config-manager.svelte';
|
||||
import { OnboardingRole } from '$lib/models/onboarding-role';
|
||||
import { retrieveServerConfig, serverConfig, systemConfigManager } from '$lib/stores/system-config-manager.svelte';
|
||||
import { user } from '$lib/stores/user.store';
|
||||
import { setUserOnboarding, updateAdminOnboarding } from '@immich/sdk';
|
||||
import {
|
||||
@@ -95,7 +96,9 @@
|
||||
]);
|
||||
|
||||
let index = $state(0);
|
||||
let userRole = $derived($user.isAdmin && !$serverConfig.isOnboarded ? OnboardingRole.SERVER : OnboardingRole.USER);
|
||||
let userRole = $derived(
|
||||
$user.isAdmin && !serverConfigManager.value.isOnboarded ? OnboardingRole.SERVER : OnboardingRole.USER,
|
||||
);
|
||||
|
||||
let onboardingStepCount = $derived(onboardingSteps.filter((step) => shouldRunStep(step.role, userRole)).length);
|
||||
let onboardingProgress = $derived(
|
||||
@@ -105,7 +108,9 @@
|
||||
const shouldRunStep = (stepRole: OnboardingRole, userRole: OnboardingRole) => {
|
||||
return (
|
||||
stepRole === OnboardingRole.USER ||
|
||||
(stepRole === OnboardingRole.SERVER && userRole === OnboardingRole.SERVER && !$serverConfig.isOnboarded)
|
||||
(stepRole === OnboardingRole.SERVER &&
|
||||
userRole === OnboardingRole.SERVER &&
|
||||
!serverConfigManager.value.isOnboarded)
|
||||
);
|
||||
};
|
||||
|
||||
@@ -127,7 +132,7 @@
|
||||
if (nextStepIndex == -1) {
|
||||
if ($user.isAdmin) {
|
||||
await updateAdminOnboarding({ adminOnboardingUpdateDto: { isOnboarded: true } });
|
||||
await retrieveServerConfig();
|
||||
await serverConfigManager.loadServerConfig();
|
||||
}
|
||||
|
||||
await setUserOnboarding({
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
import { goto } from '$app/navigation';
|
||||
import AuthPageLayout from '$lib/components/layouts/AuthPageLayout.svelte';
|
||||
import { AppRoute } from '$lib/constants';
|
||||
import { retrieveServerConfig } from '$lib/stores/system-config-manager.svelte';
|
||||
import { serverConfigManager } from '$lib/managers/server-config-manager.svelte';
|
||||
import { handleError } from '$lib/utils/handle-error';
|
||||
import { signUpAdmin } from '@immich/sdk';
|
||||
import { Alert, Button, Field, Input, PasswordInput, Text } from '@immich/ui';
|
||||
@@ -37,7 +37,7 @@
|
||||
|
||||
try {
|
||||
await signUpAdmin({ signUpDto: { email, password, name } });
|
||||
await retrieveServerConfig();
|
||||
await serverConfigManager.loadServerConfig();
|
||||
await goto(AppRoute.AUTH_LOGIN);
|
||||
} catch (error) {
|
||||
handleError(error, $t('errors.unable_to_create_admin_account'));
|
||||
|
||||
@@ -1,14 +1,12 @@
|
||||
import { AppRoute } from '$lib/constants';
|
||||
import { serverConfig } from '$lib/stores/system-config-manager.svelte';
|
||||
import { serverConfigManager } from '$lib/managers/server-config-manager.svelte';
|
||||
import { getFormatter } from '$lib/utils/i18n';
|
||||
import { redirect } from '@sveltejs/kit';
|
||||
import { get } from 'svelte/store';
|
||||
import type { PageLoad } from './$types';
|
||||
|
||||
export const load = (async ({ parent }) => {
|
||||
await parent();
|
||||
const { isInitialized } = get(serverConfig);
|
||||
if (isInitialized) {
|
||||
if (serverConfigManager.value.isInitialized) {
|
||||
// Admin has been registered, redirect to login
|
||||
redirect(302, AppRoute.AUTH_LOGIN);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user