diff --git a/frontend/src/lib/components/InstanceSettings.svelte b/frontend/src/lib/components/InstanceSettings.svelte index 76fc4bb67a..8b352d1e2b 100644 --- a/frontend/src/lib/components/InstanceSettings.svelte +++ b/frontend/src/lib/components/InstanceSettings.svelte @@ -615,17 +615,19 @@ reqPreexisting: boolean, opts: { normalize?: boolean; mask?: boolean } = {} ): string { - const obj: Record = {} - for (const key of Object.keys(vals).sort()) { - if (excludedKeys.has(key)) continue - if (opts.normalize && normalizeValue(vals[key], key) === undefined) continue - obj[key] = vals[key] - } + // Merge all settings (including oauths) into one object so they sort together + const merged: Record = { ...vals } if (oauthsObj && Object.keys(stripEmpty(oauthsObj)).length > 0) { - obj['oauths'] = oauthsObj + merged['oauths'] = oauthsObj } if (reqPreexisting) { - obj['require_preexisting_user_for_oauth'] = reqPreexisting + merged['require_preexisting_user_for_oauth'] = reqPreexisting + } + const obj: Record = {} + for (const key of Object.keys(merged).sort()) { + if (excludedKeys.has(key)) continue + if (opts.normalize && normalizeValue(merged[key], key) === undefined) continue + obj[key] = merged[key] } return YAML.stringify(opts.mask ? maskSensitive(obj) : obj) } diff --git a/frontend/src/routes/(root)/(logged)/user/(user)/instance_settings/+page.svelte b/frontend/src/routes/(root)/(logged)/user/(user)/instance_settings/+page.svelte index c90963b1a3..37d42ff03a 100644 --- a/frontend/src/routes/(root)/(logged)/user/(user)/instance_settings/+page.svelte +++ b/frontend/src/routes/(root)/(logged)/user/(user)/instance_settings/+page.svelte @@ -120,6 +120,7 @@ let fullTab = $state('general') let instanceSettingsCategory = $derived(tabToCategoryMap[fullTab] ?? 'Core') let authSubTab: 'sso' | 'oauth' | 'scim' = $derived(tabToAuthSubTab[fullTab] ?? 'sso') + let yamlMode = $state(false) // --- Unsaved changes detection (full mode) --- let pendingTab: string | undefined = $state(undefined) @@ -136,9 +137,18 @@ } } - /** Auto-save the current wizard step if dirty, then run the callback */ + + + /** Auto-save dirty settings, then run the callback */ async function saveAndProceed(callback: () => void) { - if (isSettingsStep(wizardStep)) { + if (yamlMode) { + // In YAML mode, sync editor → form, then bulk-save everything + if (!instanceSettings?.syncBeforeDiff()) return + await instanceSettings.saveSettings() + } else if (mode === 'full') { + // In full (advanced) mode, bulk-save all settings + await instanceSettings?.saveSettings() + } else if (isSettingsStep(wizardStep)) { const category = settingsSteps[wizardStep].id if (instanceSettings?.isDirty(category)) { await instanceSettings.saveCategorySettings(category) @@ -152,6 +162,7 @@ } function switchToWizardMode() { + yamlMode = false mode = 'wizard' } @@ -374,15 +385,26 @@ {/if} {:else} + +
+ +
+
-
- -
+ {#if !yamlMode} +
+ +
+ {/if}
{ const targetTab = categoryToTabMap[category] if (targetTab) { @@ -456,10 +479,11 @@ > Quick setup - + })}>Continue {/if}