fix: terminal settings show while no terminal is available (#32981)

Settings > Interface showed the terminal file display, show files on terminal select and terminal preview settings to users who have no terminal to use, which is the default. They now show once the user can reach a terminal, either one the admin set up or one of their own, the same way the chat input decides whether to offer the terminal picker. In the admin default interface settings they show whenever the instance offers terminals.

Refs #32830
This commit is contained in:
Classic298 2026-10-24 23:52:48 +02:00 • committed by GitHub
parent 98f23b17a5
commit 11081b1567
No known key found for this signature in database
GPG key ID: B5690EEEBB952194

View file

@ -6,7 +6,7 @@
canUseWebSearch,
isSettingsAdmin
} from '$lib/utils/settings-access';
import { config, settings, user } from '$lib/stores';
import { config, settings, terminalServers, user } from '$lib/stores';
import { onMount, getContext } from 'svelte';
import { toast } from 'svelte-sonner';
import { updateUserInfo } from '$lib/apis/users';
@ -28,6 +28,18 @@
$: currentSettings = (settingsValue ?? $settings ?? {}) as Record<string, any>;
$: externalSettings = settingsValue !== null;
$: defaultSettings = ($config?.ui?.default_interface_settings ?? {}) as Record<string, any>;
$: hasDirectToolServerAccess =
$user?.role === 'admin' || ($user?.permissions?.features?.direct_tool_servers ?? true);
$: hasDirectTerminal =
($terminalServers ?? []).some((server) => !server.id) ||
(currentSettings?.terminalServers ?? []).some((server) => server.url);
// Defaults apply to every user, so they follow what the instance offers.
$: hasTerminal =
$config?.features?.enable_tool_servers &&
(($terminalServers ?? []).some((server) => server.id) ||
(externalSettings
? $config?.features?.enable_direct_integrations
: hasDirectToolServerAccess && hasDirectTerminal));
let backgroundImageUrl: string | null = null;
let inputFiles: FileList | null = null;
@ -1487,89 +1499,91 @@
</p>
</div>
<div>
<div class={settingRowClass}>
<label
id="terminal-file-display-label"
class={settingLabelClass}
for="terminal-file-display-label-control"
>
{$i18n.t('settings.personal.interface.terminalFileDisplay.label')}
</label>
{#if hasTerminal}
<div>
<div class={settingRowClass}>
<label
id="terminal-file-display-label"
class={settingLabelClass}
for="terminal-file-display-label-control"
>
{$i18n.t('settings.personal.interface.terminalFileDisplay.label')}
</label>
<button
id="terminal-file-display-label-control"
aria-labelledby="terminal-file-display-label terminal-file-display-state"
class={actionButtonClass}
on:click={() => {
terminalFileDisplay = terminalFileDisplay === 'inline' ? 'sidebar' : 'inline';
saveSettings({ terminalFileDisplay });
}}
type="button"
>
<span id="terminal-file-display-state">
{terminalFileDisplay === 'inline' ? $i18n.t('Inline') : $i18n.t('Sidebar')}
</span>
</button>
</div>
<p class={settingDescriptionClass}>
{$i18n.t('settings.personal.interface.terminalFileDisplay.description')}
</p>
</div>
<div>
<div class={settingRowClass}>
<label
id="show-files-on-terminal-select-label"
class={settingLabelClass}
for="show-files-on-terminal-select-label-control"
>
{$i18n.t('settings.personal.interface.showFilesOnTerminalSelect.label')}
</label>
<div class={settingControlClass}>
<Switch
ariaLabelledbyId="show-files-on-terminal-select-label"
tooltip={true}
bind:state={showFilesOnTerminalSelect}
inherited={isDefaultSetting('showFilesOnTerminalSelect')}
on:change={() => {
saveSettings({ showFilesOnTerminalSelect });
<button
id="terminal-file-display-label-control"
aria-labelledby="terminal-file-display-label terminal-file-display-state"
class={actionButtonClass}
on:click={() => {
terminalFileDisplay = terminalFileDisplay === 'inline' ? 'sidebar' : 'inline';
saveSettings({ terminalFileDisplay });
}}
/>
type="button"
>
<span id="terminal-file-display-state">
{terminalFileDisplay === 'inline' ? $i18n.t('Inline') : $i18n.t('Sidebar')}
</span>
</button>
</div>
<p class={settingDescriptionClass}>
{$i18n.t('settings.personal.interface.terminalFileDisplay.description')}
</p>
</div>
<p class={settingDescriptionClass}>
{$i18n.t('settings.personal.interface.showFilesOnTerminalSelect.description')}
</p>
</div>
<div>
<div class={settingRowClass}>
<label
id="terminal-preview-allow-same-origin-label"
class={settingLabelClass}
for="terminal-preview-allow-same-origin-label-control"
>
{$i18n.t('settings.personal.interface.terminalPreviewAllowSameOrigin.label')}
</label>
<div>
<div class={settingRowClass}>
<label
id="show-files-on-terminal-select-label"
class={settingLabelClass}
for="show-files-on-terminal-select-label-control"
>
{$i18n.t('settings.personal.interface.showFilesOnTerminalSelect.label')}
</label>
<div class={settingControlClass}>
<Switch
ariaLabelledbyId="terminal-preview-allow-same-origin-label"
tooltip={true}
bind:state={terminalPreviewAllowSameOrigin}
inherited={isDefaultSetting('terminalPreviewAllowSameOrigin')}
on:change={() => {
saveSettings({ terminalPreviewAllowSameOrigin });
}}
/>
<div class={settingControlClass}>
<Switch
ariaLabelledbyId="show-files-on-terminal-select-label"
tooltip={true}
bind:state={showFilesOnTerminalSelect}
inherited={isDefaultSetting('showFilesOnTerminalSelect')}
on:change={() => {
saveSettings({ showFilesOnTerminalSelect });
}}
/>
</div>
</div>
<p class={settingDescriptionClass}>
{$i18n.t('settings.personal.interface.showFilesOnTerminalSelect.description')}
</p>
</div>
<p class={settingDescriptionClass}>
{$i18n.t('settings.personal.interface.terminalPreviewAllowSameOrigin.description')}
</p>
</div>
<div>
<div class={settingRowClass}>
<label
id="terminal-preview-allow-same-origin-label"
class={settingLabelClass}
for="terminal-preview-allow-same-origin-label-control"
>
{$i18n.t('settings.personal.interface.terminalPreviewAllowSameOrigin.label')}
</label>
<div class={settingControlClass}>
<Switch
ariaLabelledbyId="terminal-preview-allow-same-origin-label"
tooltip={true}
bind:state={terminalPreviewAllowSameOrigin}
inherited={isDefaultSetting('terminalPreviewAllowSameOrigin')}
on:change={() => {
saveSettings({ terminalPreviewAllowSameOrigin });
}}
/>
</div>
</div>
<p class={settingDescriptionClass}>
{$i18n.t('settings.personal.interface.terminalPreviewAllowSameOrigin.description')}
</p>
</div>
{/if}
<div>
<div class={settingRowClass}>