mirror of
https://github.com/immich-app/immich.git
synced 2025-01-07 00:50:23 -05:00
feat(web): combine auth settings (#9427)
This commit is contained in:
parent
844f5a16a1
commit
a05c990718
5 changed files with 256 additions and 328 deletions
|
@ -0,0 +1,242 @@
|
||||||
|
<script lang="ts">
|
||||||
|
import ConfirmDialogue from '$lib/components/shared-components/confirm-dialogue.svelte';
|
||||||
|
import SettingAccordion from '$lib/components/shared-components/settings/setting-accordion.svelte';
|
||||||
|
import SettingButtonsRow from '$lib/components/shared-components/settings/setting-buttons-row.svelte';
|
||||||
|
import SettingInputField, {
|
||||||
|
SettingInputFieldType,
|
||||||
|
} from '$lib/components/shared-components/settings/setting-input-field.svelte';
|
||||||
|
import SettingSwitch from '$lib/components/shared-components/settings/setting-switch.svelte';
|
||||||
|
import { type SystemConfigDto } from '@immich/sdk';
|
||||||
|
import { isEqual } from 'lodash-es';
|
||||||
|
import { createEventDispatcher } from 'svelte';
|
||||||
|
import { fade } from 'svelte/transition';
|
||||||
|
import type { SettingsEventType } from '../admin-settings';
|
||||||
|
|
||||||
|
export let savedConfig: SystemConfigDto;
|
||||||
|
export let defaultConfig: SystemConfigDto;
|
||||||
|
export let config: SystemConfigDto; // this is the config that is being edited
|
||||||
|
export let disabled = false;
|
||||||
|
|
||||||
|
const dispatch = createEventDispatcher<SettingsEventType>();
|
||||||
|
|
||||||
|
let isConfirmOpen = false;
|
||||||
|
|
||||||
|
const handleToggleOverride = () => {
|
||||||
|
// click runs before bind
|
||||||
|
const previouslyEnabled = config.oauth.mobileOverrideEnabled;
|
||||||
|
if (!previouslyEnabled && !config.oauth.mobileRedirectUri) {
|
||||||
|
config.oauth.mobileRedirectUri = window.location.origin + '/api/oauth/mobile-redirect';
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleSave = (skipConfirm: boolean) => {
|
||||||
|
const allMethodsDisabled = !config.oauth.enabled && !config.passwordLogin.enabled;
|
||||||
|
if (allMethodsDisabled && !skipConfirm) {
|
||||||
|
isConfirmOpen = true;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
isConfirmOpen = false;
|
||||||
|
dispatch('save', { passwordLogin: config.passwordLogin, oauth: config.oauth });
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
{#if isConfirmOpen}
|
||||||
|
<ConfirmDialogue
|
||||||
|
id="disable-login-modal"
|
||||||
|
title="Disable login"
|
||||||
|
onClose={() => (isConfirmOpen = false)}
|
||||||
|
onConfirm={() => handleSave(true)}
|
||||||
|
>
|
||||||
|
<svelte:fragment slot="prompt">
|
||||||
|
<div class="flex flex-col gap-4">
|
||||||
|
<p>Are you sure you want to disable all login methods? Login will be completely disabled.</p>
|
||||||
|
<p>
|
||||||
|
To re-enable, use a
|
||||||
|
<a
|
||||||
|
href="https://immich.app/docs/administration/server-commands"
|
||||||
|
rel="noreferrer"
|
||||||
|
target="_blank"
|
||||||
|
class="underline"
|
||||||
|
>
|
||||||
|
Server Command</a
|
||||||
|
>.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</svelte:fragment>
|
||||||
|
</ConfirmDialogue>
|
||||||
|
{/if}
|
||||||
|
|
||||||
|
<div>
|
||||||
|
<div in:fade={{ duration: 500 }}>
|
||||||
|
<form autocomplete="off" on:submit|preventDefault>
|
||||||
|
<div class="ml-4 mt-4 flex flex-col gap-4">
|
||||||
|
<SettingAccordion key="oauth" title="OAuth" subtitle="Manage OAuth login settings">
|
||||||
|
<div class="ml-4 mt-4 flex flex-col gap-4">
|
||||||
|
<p class="text-sm dark:text-immich-dark-fg">
|
||||||
|
For more details about this feature, refer to the <a
|
||||||
|
href="https://immich.app/docs/administration/oauth"
|
||||||
|
class="underline"
|
||||||
|
target="_blank"
|
||||||
|
rel="noreferrer">docs</a
|
||||||
|
>.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<SettingSwitch
|
||||||
|
id="login-with-oauth"
|
||||||
|
{disabled}
|
||||||
|
title="ENABLE"
|
||||||
|
subtitle="Login with OAuth"
|
||||||
|
bind:checked={config.oauth.enabled}
|
||||||
|
/>
|
||||||
|
|
||||||
|
{#if config.oauth.enabled}
|
||||||
|
<hr />
|
||||||
|
<SettingInputField
|
||||||
|
inputType={SettingInputFieldType.TEXT}
|
||||||
|
label="ISSUER URL"
|
||||||
|
bind:value={config.oauth.issuerUrl}
|
||||||
|
required={true}
|
||||||
|
disabled={disabled || !config.oauth.enabled}
|
||||||
|
isEdited={!(config.oauth.issuerUrl == savedConfig.oauth.issuerUrl)}
|
||||||
|
/>
|
||||||
|
|
||||||
|
<SettingInputField
|
||||||
|
inputType={SettingInputFieldType.TEXT}
|
||||||
|
label="CLIENT ID"
|
||||||
|
bind:value={config.oauth.clientId}
|
||||||
|
required={true}
|
||||||
|
disabled={disabled || !config.oauth.enabled}
|
||||||
|
isEdited={!(config.oauth.clientId == savedConfig.oauth.clientId)}
|
||||||
|
/>
|
||||||
|
|
||||||
|
<SettingInputField
|
||||||
|
inputType={SettingInputFieldType.TEXT}
|
||||||
|
label="CLIENT SECRET"
|
||||||
|
bind:value={config.oauth.clientSecret}
|
||||||
|
required={true}
|
||||||
|
disabled={disabled || !config.oauth.enabled}
|
||||||
|
isEdited={!(config.oauth.clientSecret == savedConfig.oauth.clientSecret)}
|
||||||
|
/>
|
||||||
|
|
||||||
|
<SettingInputField
|
||||||
|
inputType={SettingInputFieldType.TEXT}
|
||||||
|
label="SCOPE"
|
||||||
|
bind:value={config.oauth.scope}
|
||||||
|
required={true}
|
||||||
|
disabled={disabled || !config.oauth.enabled}
|
||||||
|
isEdited={!(config.oauth.scope == savedConfig.oauth.scope)}
|
||||||
|
/>
|
||||||
|
|
||||||
|
<SettingInputField
|
||||||
|
inputType={SettingInputFieldType.TEXT}
|
||||||
|
label="SIGNING ALGORITHM"
|
||||||
|
bind:value={config.oauth.signingAlgorithm}
|
||||||
|
required={true}
|
||||||
|
disabled={disabled || !config.oauth.enabled}
|
||||||
|
isEdited={!(config.oauth.signingAlgorithm == savedConfig.oauth.signingAlgorithm)}
|
||||||
|
/>
|
||||||
|
|
||||||
|
<SettingInputField
|
||||||
|
inputType={SettingInputFieldType.TEXT}
|
||||||
|
label="STORAGE LABEL CLAIM"
|
||||||
|
desc="Automatically set the user's storage label to the value of this claim."
|
||||||
|
bind:value={config.oauth.storageLabelClaim}
|
||||||
|
required={true}
|
||||||
|
disabled={disabled || !config.oauth.enabled}
|
||||||
|
isEdited={!(config.oauth.storageLabelClaim == savedConfig.oauth.storageLabelClaim)}
|
||||||
|
/>
|
||||||
|
|
||||||
|
<SettingInputField
|
||||||
|
inputType={SettingInputFieldType.TEXT}
|
||||||
|
label="STORAGE QUOTA CLAIM"
|
||||||
|
desc="Automatically set the user's storage quota to the value of this claim."
|
||||||
|
bind:value={config.oauth.storageQuotaClaim}
|
||||||
|
required={true}
|
||||||
|
disabled={disabled || !config.oauth.enabled}
|
||||||
|
isEdited={!(config.oauth.storageQuotaClaim == savedConfig.oauth.storageQuotaClaim)}
|
||||||
|
/>
|
||||||
|
|
||||||
|
<SettingInputField
|
||||||
|
inputType={SettingInputFieldType.NUMBER}
|
||||||
|
label="DEFAULT STORAGE QUOTA (GiB)"
|
||||||
|
desc="Quota in GiB to be used when no claim is provided (Enter 0 for unlimited quota)."
|
||||||
|
bind:value={config.oauth.defaultStorageQuota}
|
||||||
|
required={true}
|
||||||
|
disabled={disabled || !config.oauth.enabled}
|
||||||
|
isEdited={!(config.oauth.defaultStorageQuota == savedConfig.oauth.defaultStorageQuota)}
|
||||||
|
/>
|
||||||
|
|
||||||
|
<SettingInputField
|
||||||
|
inputType={SettingInputFieldType.TEXT}
|
||||||
|
label="BUTTON TEXT"
|
||||||
|
bind:value={config.oauth.buttonText}
|
||||||
|
required={false}
|
||||||
|
disabled={disabled || !config.oauth.enabled}
|
||||||
|
isEdited={!(config.oauth.buttonText == savedConfig.oauth.buttonText)}
|
||||||
|
/>
|
||||||
|
|
||||||
|
<SettingSwitch
|
||||||
|
id="auto-register-new-users"
|
||||||
|
title="AUTO REGISTER"
|
||||||
|
subtitle="Automatically register new users after signing in with OAuth"
|
||||||
|
bind:checked={config.oauth.autoRegister}
|
||||||
|
disabled={disabled || !config.oauth.enabled}
|
||||||
|
/>
|
||||||
|
|
||||||
|
<SettingSwitch
|
||||||
|
id="auto-launch-oauth"
|
||||||
|
title="AUTO LAUNCH"
|
||||||
|
subtitle="Start the OAuth login flow automatically upon navigating to the login page"
|
||||||
|
disabled={disabled || !config.oauth.enabled}
|
||||||
|
bind:checked={config.oauth.autoLaunch}
|
||||||
|
/>
|
||||||
|
|
||||||
|
<SettingSwitch
|
||||||
|
id="mobile-redirect-uri-override"
|
||||||
|
title="MOBILE REDIRECT URI OVERRIDE"
|
||||||
|
subtitle="Enable when 'app.immich:/' is an invalid redirect URI."
|
||||||
|
disabled={disabled || !config.oauth.enabled}
|
||||||
|
on:click={() => handleToggleOverride()}
|
||||||
|
bind:checked={config.oauth.mobileOverrideEnabled}
|
||||||
|
/>
|
||||||
|
|
||||||
|
{#if config.oauth.mobileOverrideEnabled}
|
||||||
|
<SettingInputField
|
||||||
|
inputType={SettingInputFieldType.TEXT}
|
||||||
|
label="MOBILE REDIRECT URI"
|
||||||
|
bind:value={config.oauth.mobileRedirectUri}
|
||||||
|
required={true}
|
||||||
|
disabled={disabled || !config.oauth.enabled}
|
||||||
|
isEdited={!(config.oauth.mobileRedirectUri == savedConfig.oauth.mobileRedirectUri)}
|
||||||
|
/>
|
||||||
|
{/if}
|
||||||
|
{/if}
|
||||||
|
</div>
|
||||||
|
</SettingAccordion>
|
||||||
|
|
||||||
|
<SettingAccordion key="password" title="Password" subtitle="Manage password login settings">
|
||||||
|
<div class="ml-4 mt-4 flex flex-col gap-4">
|
||||||
|
<div class="ml-4 mt-4 flex flex-col">
|
||||||
|
<SettingSwitch
|
||||||
|
id="enable-password-login"
|
||||||
|
title="ENABLED"
|
||||||
|
{disabled}
|
||||||
|
subtitle="Login with email and password"
|
||||||
|
bind:checked={config.passwordLogin.enabled}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</SettingAccordion>
|
||||||
|
|
||||||
|
<SettingButtonsRow
|
||||||
|
showResetToDefault={!isEqual(savedConfig.passwordLogin, defaultConfig.passwordLogin) ||
|
||||||
|
!isEqual(savedConfig.oauth, defaultConfig.oauth)}
|
||||||
|
{disabled}
|
||||||
|
on:reset={({ detail }) => dispatch('reset', { ...detail, configKeys: ['passwordLogin', 'oauth'] })}
|
||||||
|
on:save={() => handleSave(false)}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</div>
|
|
@ -1,25 +0,0 @@
|
||||||
<script lang="ts">
|
|
||||||
import ConfirmDialogue from '$lib/components/shared-components/confirm-dialogue.svelte';
|
|
||||||
|
|
||||||
export let onCancel: () => void;
|
|
||||||
export let onConfirm: () => void;
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<ConfirmDialogue id="disable-login-modal" title="Disable login" onClose={onCancel} {onConfirm}>
|
|
||||||
<svelte:fragment slot="prompt">
|
|
||||||
<div class="flex flex-col gap-4">
|
|
||||||
<p>Are you sure you want to disable all login methods? Login will be completely disabled.</p>
|
|
||||||
<p>
|
|
||||||
To re-enable, use a
|
|
||||||
<a
|
|
||||||
href="https://immich.app/docs/administration/server-commands"
|
|
||||||
rel="noreferrer"
|
|
||||||
target="_blank"
|
|
||||||
class="underline"
|
|
||||||
>
|
|
||||||
Server Command</a
|
|
||||||
>.
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
</svelte:fragment>
|
|
||||||
</ConfirmDialogue>
|
|
|
@ -1,213 +0,0 @@
|
||||||
<script lang="ts">
|
|
||||||
import type { SystemConfigDto } from '@immich/sdk';
|
|
||||||
import { isEqual } from 'lodash-es';
|
|
||||||
import { createEventDispatcher } from 'svelte';
|
|
||||||
import { fade } from 'svelte/transition';
|
|
||||||
import type { SettingsEventType } from '../admin-settings';
|
|
||||||
import ConfirmDisableLogin from '../confirm-disable-login.svelte';
|
|
||||||
import SettingButtonsRow from '$lib/components/shared-components/settings/setting-buttons-row.svelte';
|
|
||||||
import SettingInputField, {
|
|
||||||
SettingInputFieldType,
|
|
||||||
} from '$lib/components/shared-components/settings/setting-input-field.svelte';
|
|
||||||
import SettingSwitch from '$lib/components/shared-components/settings/setting-switch.svelte';
|
|
||||||
|
|
||||||
export let savedConfig: SystemConfigDto;
|
|
||||||
export let defaultConfig: SystemConfigDto;
|
|
||||||
export let config: SystemConfigDto; // this is the config that is being edited
|
|
||||||
export let disabled = false;
|
|
||||||
|
|
||||||
const dispatch = createEventDispatcher<SettingsEventType>();
|
|
||||||
|
|
||||||
const handleToggleOverride = () => {
|
|
||||||
// click runs before bind
|
|
||||||
const previouslyEnabled = config.oauth.mobileOverrideEnabled;
|
|
||||||
if (!previouslyEnabled && !config.oauth.mobileRedirectUri) {
|
|
||||||
config.oauth.mobileRedirectUri = window.location.origin + '/api/oauth/mobile-redirect';
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
let isConfirmOpen = false;
|
|
||||||
let handleConfirm: (value: boolean) => void;
|
|
||||||
|
|
||||||
const openConfirmModal = () => {
|
|
||||||
return new Promise((resolve) => {
|
|
||||||
handleConfirm = (value: boolean) => {
|
|
||||||
isConfirmOpen = false;
|
|
||||||
resolve(value);
|
|
||||||
};
|
|
||||||
isConfirmOpen = true;
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleSave = async () => {
|
|
||||||
if (!savedConfig.passwordLogin.enabled && savedConfig.oauth.enabled && !config.oauth.enabled) {
|
|
||||||
const confirmed = await openConfirmModal();
|
|
||||||
if (!confirmed) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!config.oauth.mobileOverrideEnabled) {
|
|
||||||
config.oauth.mobileRedirectUri = '';
|
|
||||||
}
|
|
||||||
|
|
||||||
dispatch('save', { oauth: config.oauth });
|
|
||||||
};
|
|
||||||
</script>
|
|
||||||
|
|
||||||
{#if isConfirmOpen}
|
|
||||||
<ConfirmDisableLogin onCancel={() => handleConfirm(false)} onConfirm={() => handleConfirm(true)} />
|
|
||||||
{/if}
|
|
||||||
|
|
||||||
<div class="mt-2">
|
|
||||||
<div in:fade={{ duration: 500 }}>
|
|
||||||
<form autocomplete="off" on:submit|preventDefault class="mx-4 flex flex-col gap-4 py-4">
|
|
||||||
<p class="text-sm dark:text-immich-dark-fg">
|
|
||||||
For more details about this feature, refer to the <a
|
|
||||||
href="https://immich.app/docs/administration/oauth"
|
|
||||||
class="underline"
|
|
||||||
target="_blank"
|
|
||||||
rel="noreferrer">docs</a
|
|
||||||
>.
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<SettingSwitch
|
|
||||||
id="login-with-oauth"
|
|
||||||
{disabled}
|
|
||||||
title="ENABLE"
|
|
||||||
subtitle="Login with OAuth"
|
|
||||||
bind:checked={config.oauth.enabled}
|
|
||||||
/>
|
|
||||||
|
|
||||||
{#if config.oauth.enabled}
|
|
||||||
<hr />
|
|
||||||
<SettingInputField
|
|
||||||
inputType={SettingInputFieldType.TEXT}
|
|
||||||
label="ISSUER URL"
|
|
||||||
bind:value={config.oauth.issuerUrl}
|
|
||||||
required={true}
|
|
||||||
disabled={disabled || !config.oauth.enabled}
|
|
||||||
isEdited={!(config.oauth.issuerUrl == savedConfig.oauth.issuerUrl)}
|
|
||||||
/>
|
|
||||||
|
|
||||||
<SettingInputField
|
|
||||||
inputType={SettingInputFieldType.TEXT}
|
|
||||||
label="CLIENT ID"
|
|
||||||
bind:value={config.oauth.clientId}
|
|
||||||
required={true}
|
|
||||||
disabled={disabled || !config.oauth.enabled}
|
|
||||||
isEdited={!(config.oauth.clientId == savedConfig.oauth.clientId)}
|
|
||||||
/>
|
|
||||||
|
|
||||||
<SettingInputField
|
|
||||||
inputType={SettingInputFieldType.TEXT}
|
|
||||||
label="CLIENT SECRET"
|
|
||||||
bind:value={config.oauth.clientSecret}
|
|
||||||
required={true}
|
|
||||||
disabled={disabled || !config.oauth.enabled}
|
|
||||||
isEdited={!(config.oauth.clientSecret == savedConfig.oauth.clientSecret)}
|
|
||||||
/>
|
|
||||||
|
|
||||||
<SettingInputField
|
|
||||||
inputType={SettingInputFieldType.TEXT}
|
|
||||||
label="SCOPE"
|
|
||||||
bind:value={config.oauth.scope}
|
|
||||||
required={true}
|
|
||||||
disabled={disabled || !config.oauth.enabled}
|
|
||||||
isEdited={!(config.oauth.scope == savedConfig.oauth.scope)}
|
|
||||||
/>
|
|
||||||
|
|
||||||
<SettingInputField
|
|
||||||
inputType={SettingInputFieldType.TEXT}
|
|
||||||
label="SIGNING ALGORITHM"
|
|
||||||
bind:value={config.oauth.signingAlgorithm}
|
|
||||||
required={true}
|
|
||||||
disabled={disabled || !config.oauth.enabled}
|
|
||||||
isEdited={!(config.oauth.signingAlgorithm == savedConfig.oauth.signingAlgorithm)}
|
|
||||||
/>
|
|
||||||
|
|
||||||
<SettingInputField
|
|
||||||
inputType={SettingInputFieldType.TEXT}
|
|
||||||
label="STORAGE LABEL CLAIM"
|
|
||||||
desc="Automatically set the user's storage label to the value of this claim."
|
|
||||||
bind:value={config.oauth.storageLabelClaim}
|
|
||||||
required={true}
|
|
||||||
disabled={disabled || !config.oauth.enabled}
|
|
||||||
isEdited={!(config.oauth.storageLabelClaim == savedConfig.oauth.storageLabelClaim)}
|
|
||||||
/>
|
|
||||||
|
|
||||||
<SettingInputField
|
|
||||||
inputType={SettingInputFieldType.TEXT}
|
|
||||||
label="STORAGE QUOTA CLAIM"
|
|
||||||
desc="Automatically set the user's storage quota to the value of this claim."
|
|
||||||
bind:value={config.oauth.storageQuotaClaim}
|
|
||||||
required={true}
|
|
||||||
disabled={disabled || !config.oauth.enabled}
|
|
||||||
isEdited={!(config.oauth.storageQuotaClaim == savedConfig.oauth.storageQuotaClaim)}
|
|
||||||
/>
|
|
||||||
|
|
||||||
<SettingInputField
|
|
||||||
inputType={SettingInputFieldType.NUMBER}
|
|
||||||
label="DEFAULT STORAGE QUOTA (GiB)"
|
|
||||||
desc="Quota in GiB to be used when no claim is provided (Enter 0 for unlimited quota)."
|
|
||||||
bind:value={config.oauth.defaultStorageQuota}
|
|
||||||
required={true}
|
|
||||||
disabled={disabled || !config.oauth.enabled}
|
|
||||||
isEdited={!(config.oauth.defaultStorageQuota == savedConfig.oauth.defaultStorageQuota)}
|
|
||||||
/>
|
|
||||||
|
|
||||||
<SettingInputField
|
|
||||||
inputType={SettingInputFieldType.TEXT}
|
|
||||||
label="BUTTON TEXT"
|
|
||||||
bind:value={config.oauth.buttonText}
|
|
||||||
required={false}
|
|
||||||
disabled={disabled || !config.oauth.enabled}
|
|
||||||
isEdited={!(config.oauth.buttonText == savedConfig.oauth.buttonText)}
|
|
||||||
/>
|
|
||||||
|
|
||||||
<SettingSwitch
|
|
||||||
id="auto-register-new-users"
|
|
||||||
title="AUTO REGISTER"
|
|
||||||
subtitle="Automatically register new users after signing in with OAuth"
|
|
||||||
bind:checked={config.oauth.autoRegister}
|
|
||||||
disabled={disabled || !config.oauth.enabled}
|
|
||||||
/>
|
|
||||||
|
|
||||||
<SettingSwitch
|
|
||||||
id="auto-launch-oauth"
|
|
||||||
title="AUTO LAUNCH"
|
|
||||||
subtitle="Start the OAuth login flow automatically upon navigating to the login page"
|
|
||||||
disabled={disabled || !config.oauth.enabled}
|
|
||||||
bind:checked={config.oauth.autoLaunch}
|
|
||||||
/>
|
|
||||||
|
|
||||||
<SettingSwitch
|
|
||||||
id="mobile-redirect-uri-override"
|
|
||||||
title="MOBILE REDIRECT URI OVERRIDE"
|
|
||||||
subtitle="Enable when 'app.immich:/' is an invalid redirect URI."
|
|
||||||
disabled={disabled || !config.oauth.enabled}
|
|
||||||
on:click={() => handleToggleOverride()}
|
|
||||||
bind:checked={config.oauth.mobileOverrideEnabled}
|
|
||||||
/>
|
|
||||||
|
|
||||||
{#if config.oauth.mobileOverrideEnabled}
|
|
||||||
<SettingInputField
|
|
||||||
inputType={SettingInputFieldType.TEXT}
|
|
||||||
label="MOBILE REDIRECT URI"
|
|
||||||
bind:value={config.oauth.mobileRedirectUri}
|
|
||||||
required={true}
|
|
||||||
disabled={disabled || !config.oauth.enabled}
|
|
||||||
isEdited={!(config.oauth.mobileRedirectUri == savedConfig.oauth.mobileRedirectUri)}
|
|
||||||
/>
|
|
||||||
{/if}
|
|
||||||
{/if}
|
|
||||||
|
|
||||||
<SettingButtonsRow
|
|
||||||
on:reset={({ detail }) => dispatch('reset', { ...detail, configKeys: ['oauth'] })}
|
|
||||||
on:save={() => handleSave()}
|
|
||||||
showResetToDefault={!isEqual(savedConfig.oauth, defaultConfig.oauth)}
|
|
||||||
{disabled}
|
|
||||||
/>
|
|
||||||
</form>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
|
@ -1,68 +0,0 @@
|
||||||
<script lang="ts">
|
|
||||||
import type { SystemConfigDto } from '@immich/sdk';
|
|
||||||
import { isEqual } from 'lodash-es';
|
|
||||||
import { createEventDispatcher } from 'svelte';
|
|
||||||
import { fade } from 'svelte/transition';
|
|
||||||
import type { SettingsEventType } from '../admin-settings';
|
|
||||||
import ConfirmDisableLogin from '../confirm-disable-login.svelte';
|
|
||||||
import SettingButtonsRow from '$lib/components/shared-components/settings/setting-buttons-row.svelte';
|
|
||||||
import SettingSwitch from '$lib/components/shared-components/settings/setting-switch.svelte';
|
|
||||||
|
|
||||||
export let savedConfig: SystemConfigDto;
|
|
||||||
export let defaultConfig: SystemConfigDto;
|
|
||||||
export let config: SystemConfigDto; // this is the config that is being edited
|
|
||||||
export let disabled = false;
|
|
||||||
|
|
||||||
const dispatch = createEventDispatcher<SettingsEventType>();
|
|
||||||
|
|
||||||
let isConfirmOpen = false;
|
|
||||||
let handleConfirm: (value: boolean) => void;
|
|
||||||
|
|
||||||
const openConfirmModal = () => {
|
|
||||||
return new Promise((resolve) => {
|
|
||||||
handleConfirm = (value: boolean) => {
|
|
||||||
isConfirmOpen = false;
|
|
||||||
resolve(value);
|
|
||||||
};
|
|
||||||
isConfirmOpen = true;
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
async function handleSave() {
|
|
||||||
if (!savedConfig.oauth.enabled && savedConfig.passwordLogin.enabled && !config.passwordLogin.enabled) {
|
|
||||||
const confirmed = await openConfirmModal();
|
|
||||||
if (!confirmed) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
dispatch('save', { passwordLogin: config.passwordLogin });
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
|
|
||||||
{#if isConfirmOpen}
|
|
||||||
<ConfirmDisableLogin onCancel={() => handleConfirm(false)} onConfirm={() => handleConfirm(true)} />
|
|
||||||
{/if}
|
|
||||||
|
|
||||||
<div>
|
|
||||||
<div in:fade={{ duration: 500 }}>
|
|
||||||
<form autocomplete="off" on:submit|preventDefault>
|
|
||||||
<div class="ml-4 mt-4 flex flex-col">
|
|
||||||
<SettingSwitch
|
|
||||||
id="enable-password-login"
|
|
||||||
title="ENABLED"
|
|
||||||
{disabled}
|
|
||||||
subtitle="Login with email and password"
|
|
||||||
bind:checked={config.passwordLogin.enabled}
|
|
||||||
/>
|
|
||||||
|
|
||||||
<SettingButtonsRow
|
|
||||||
on:reset={({ detail }) => dispatch('reset', { ...detail, configKeys: ['passwordLogin'] })}
|
|
||||||
on:save={() => handleSave()}
|
|
||||||
showResetToDefault={!isEqual(savedConfig.passwordLogin, defaultConfig.passwordLogin)}
|
|
||||||
{disabled}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</form>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
|
@ -1,34 +1,33 @@
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import AdminSettings from '$lib/components/admin-page/settings/admin-settings.svelte';
|
import AdminSettings from '$lib/components/admin-page/settings/admin-settings.svelte';
|
||||||
|
import AuthSettings from '$lib/components/admin-page/settings/auth/auth-settings.svelte';
|
||||||
import FFmpegSettings from '$lib/components/admin-page/settings/ffmpeg/ffmpeg-settings.svelte';
|
import FFmpegSettings from '$lib/components/admin-page/settings/ffmpeg/ffmpeg-settings.svelte';
|
||||||
|
import ImageSettings from '$lib/components/admin-page/settings/image/image-settings.svelte';
|
||||||
import JobSettings from '$lib/components/admin-page/settings/job-settings/job-settings.svelte';
|
import JobSettings from '$lib/components/admin-page/settings/job-settings/job-settings.svelte';
|
||||||
import LibrarySettings from '$lib/components/admin-page/settings/library-settings/library-settings.svelte';
|
import LibrarySettings from '$lib/components/admin-page/settings/library-settings/library-settings.svelte';
|
||||||
import LoggingSettings from '$lib/components/admin-page/settings/logging-settings/logging-settings.svelte';
|
import LoggingSettings from '$lib/components/admin-page/settings/logging-settings/logging-settings.svelte';
|
||||||
import MachineLearningSettings from '$lib/components/admin-page/settings/machine-learning-settings/machine-learning-settings.svelte';
|
import MachineLearningSettings from '$lib/components/admin-page/settings/machine-learning-settings/machine-learning-settings.svelte';
|
||||||
import MapSettings from '$lib/components/admin-page/settings/map-settings/map-settings.svelte';
|
import MapSettings from '$lib/components/admin-page/settings/map-settings/map-settings.svelte';
|
||||||
import NewVersionCheckSettings from '$lib/components/admin-page/settings/new-version-check-settings/new-version-check-settings.svelte';
|
import NewVersionCheckSettings from '$lib/components/admin-page/settings/new-version-check-settings/new-version-check-settings.svelte';
|
||||||
import OAuthSettings from '$lib/components/admin-page/settings/oauth/oauth-settings.svelte';
|
|
||||||
import PasswordLoginSettings from '$lib/components/admin-page/settings/password-login/password-login-settings.svelte';
|
|
||||||
import ServerSettings from '$lib/components/admin-page/settings/server/server-settings.svelte';
|
|
||||||
import NotificationSettings from '$lib/components/admin-page/settings/notification-settings/notification-settings.svelte';
|
import NotificationSettings from '$lib/components/admin-page/settings/notification-settings/notification-settings.svelte';
|
||||||
import SettingAccordion from '$lib/components/shared-components/settings/setting-accordion.svelte';
|
import ServerSettings from '$lib/components/admin-page/settings/server/server-settings.svelte';
|
||||||
import StorageTemplateSettings from '$lib/components/admin-page/settings/storage-template/storage-template-settings.svelte';
|
import StorageTemplateSettings from '$lib/components/admin-page/settings/storage-template/storage-template-settings.svelte';
|
||||||
import ThemeSettings from '$lib/components/admin-page/settings/theme/theme-settings.svelte';
|
import ThemeSettings from '$lib/components/admin-page/settings/theme/theme-settings.svelte';
|
||||||
import ImageSettings from '$lib/components/admin-page/settings/image/image-settings.svelte';
|
|
||||||
import TrashSettings from '$lib/components/admin-page/settings/trash-settings/trash-settings.svelte';
|
import TrashSettings from '$lib/components/admin-page/settings/trash-settings/trash-settings.svelte';
|
||||||
import UserSettings from '$lib/components/admin-page/settings/user-settings/user-settings.svelte';
|
import UserSettings from '$lib/components/admin-page/settings/user-settings/user-settings.svelte';
|
||||||
import LinkButton from '$lib/components/elements/buttons/link-button.svelte';
|
import LinkButton from '$lib/components/elements/buttons/link-button.svelte';
|
||||||
import Icon from '$lib/components/elements/icon.svelte';
|
import Icon from '$lib/components/elements/icon.svelte';
|
||||||
import UserPageLayout from '$lib/components/layouts/user-page-layout.svelte';
|
import UserPageLayout from '$lib/components/layouts/user-page-layout.svelte';
|
||||||
|
import SettingAccordionState from '$lib/components/shared-components/settings/setting-accordion-state.svelte';
|
||||||
|
import SettingAccordion from '$lib/components/shared-components/settings/setting-accordion.svelte';
|
||||||
|
import { QueryParameter } from '$lib/constants';
|
||||||
import { downloadManager } from '$lib/stores/download';
|
import { downloadManager } from '$lib/stores/download';
|
||||||
import { featureFlags } from '$lib/stores/server-config.store';
|
import { featureFlags } from '$lib/stores/server-config.store';
|
||||||
import { copyToClipboard } from '$lib/utils';
|
import { copyToClipboard } from '$lib/utils';
|
||||||
import { downloadBlob } from '$lib/utils/asset-utils';
|
import { downloadBlob } from '$lib/utils/asset-utils';
|
||||||
|
import type { SystemConfigDto } from '@immich/sdk';
|
||||||
import { mdiAlert, mdiContentCopy, mdiDownload, mdiUpload } from '@mdi/js';
|
import { mdiAlert, mdiContentCopy, mdiDownload, mdiUpload } from '@mdi/js';
|
||||||
import type { PageData } from './$types';
|
import type { PageData } from './$types';
|
||||||
import SettingAccordionState from '$lib/components/shared-components/settings/setting-accordion-state.svelte';
|
|
||||||
import { QueryParameter } from '$lib/constants';
|
|
||||||
import type { SystemConfigDto } from '@immich/sdk';
|
|
||||||
|
|
||||||
export let data: PageData;
|
export let data: PageData;
|
||||||
|
|
||||||
|
@ -36,13 +35,12 @@
|
||||||
let handleSave: (update: Partial<SystemConfigDto>) => Promise<void>;
|
let handleSave: (update: Partial<SystemConfigDto>) => Promise<void>;
|
||||||
|
|
||||||
type Settings =
|
type Settings =
|
||||||
|
| typeof AuthSettings
|
||||||
| typeof JobSettings
|
| typeof JobSettings
|
||||||
| typeof LibrarySettings
|
| typeof LibrarySettings
|
||||||
| typeof LoggingSettings
|
| typeof LoggingSettings
|
||||||
| typeof MachineLearningSettings
|
| typeof MachineLearningSettings
|
||||||
| typeof MapSettings
|
| typeof MapSettings
|
||||||
| typeof OAuthSettings
|
|
||||||
| typeof PasswordLoginSettings
|
|
||||||
| typeof ServerSettings
|
| typeof ServerSettings
|
||||||
| typeof StorageTemplateSettings
|
| typeof StorageTemplateSettings
|
||||||
| typeof ThemeSettings
|
| typeof ThemeSettings
|
||||||
|
@ -82,6 +80,12 @@
|
||||||
subtitle: string;
|
subtitle: string;
|
||||||
key: string;
|
key: string;
|
||||||
}> = [
|
}> = [
|
||||||
|
{
|
||||||
|
item: AuthSettings,
|
||||||
|
title: 'Authentication Settings',
|
||||||
|
subtitle: 'Manage password, OAuth, and other authentication settings',
|
||||||
|
key: 'image',
|
||||||
|
},
|
||||||
{
|
{
|
||||||
item: ImageSettings,
|
item: ImageSettings,
|
||||||
title: 'Image Settings',
|
title: 'Image Settings',
|
||||||
|
@ -124,18 +128,6 @@
|
||||||
subtitle: 'Manage notification settings, including email',
|
subtitle: 'Manage notification settings, including email',
|
||||||
key: 'notifications',
|
key: 'notifications',
|
||||||
},
|
},
|
||||||
{
|
|
||||||
item: OAuthSettings,
|
|
||||||
title: 'OAuth Authentication',
|
|
||||||
subtitle: 'Manage the login with OAuth settings',
|
|
||||||
key: 'oauth',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
item: PasswordLoginSettings,
|
|
||||||
title: 'Password Authentication',
|
|
||||||
subtitle: 'Manage the login with password settings',
|
|
||||||
key: 'password',
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
item: ServerSettings,
|
item: ServerSettings,
|
||||||
title: 'Server Settings',
|
title: 'Server Settings',
|
||||||
|
|
Loading…
Reference in a new issue