mirror of
				https://github.com/immich-app/immich.git
				synced 2025-10-30 18:35:00 -04:00 
			
		
		
		
	feat(web): combine auth settings (#9427)
This commit is contained in:
		
							parent
							
								
									844f5a16a1
								
							
						
					
					
						commit
						a05c990718
					
				| @ -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…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user