Skip to content

Commit b60512b

Browse files
committed
refactor(web): make settings an inline route instead of a modal
SettingsDialog fused four jobs into 1,571 lines: the modal shell, the tab nav, ten page bodies and their derived state. Because the shell was welded to the content, the pages could only ever render as an overlay. Split it. useSettingsNav owns the tab union, the groups, the active tab and the guarded lazy loads; SettingsNav renders the nav inside the real sidebar, and SettingsPane hosts one component per page in the content area. The sidebar keeps its header and New Session button in both modes and swaps only its body.
1 parent e9a4ef4 commit b60512b

21 files changed

Lines changed: 1928 additions & 2109 deletions

apps/pythinker-web/src/App.vue

Lines changed: 65 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ import type { AgentMember } from './types';
1414
import ModelPicker from './components/ModelPicker.vue';
1515
import ProviderManager from './components/ProviderManager.vue';
1616
import NewSessionDialog from './components/NewSessionDialog.vue';
17-
import SettingsDialog from './components/SettingsDialog.vue';
17+
import SettingsPane from './components/settings/SettingsPane.vue';
1818
import SessionsDialog from './components/SessionsDialog.vue';
1919
import AddWorkspaceDialog from './components/AddWorkspaceDialog.vue';
2020
import StatusPanel from './components/StatusPanel.vue';
@@ -30,6 +30,7 @@ import { isTraceEnabled } from './debug/trace';
3030
import { usePythinkerWebClient } from './composables/usePythinkerWebClient';
3131
import { useIsMobile } from './composables/useIsMobile';
3232
import { useIsDark } from './composables/useIsDark';
33+
import { useSettingsNav } from './composables/useSettingsNav';
3334
import type { AppConfig, ThinkingLevel } from './api/types';
3435
import type { FilePreviewRequest, ToolMedia } from './types';
3536
@@ -610,6 +611,31 @@ const showAddWorkspace = ref(false);
610611
const showStatusPanel = ref(false);
611612
const showSettings = ref(false);
612613
614+
const { activeTab: activeSettingsTab, setTab: selectSettingsTab } = useSettingsNav({
615+
counts: {
616+
connectors: () => client.connectors.value.length,
617+
plugins: () => client.plugins.value.length,
618+
subagents: () => client.subagents.value.length,
619+
},
620+
onLoadConnectors: () => { void client.loadConnectors(); },
621+
onLoadPlugins: () => { void client.loadPlugins(); },
622+
onLoadSubagents: () => { void client.loadSubagents(); },
623+
});
624+
625+
function toggleSettings(): void {
626+
showSettings.value = !showSettings.value;
627+
}
628+
629+
function loginFromSettings(): void {
630+
showSettings.value = false;
631+
openLogin();
632+
}
633+
634+
function openOnboardingFromSettings(): void {
635+
showSettings.value = false;
636+
openOnboarding();
637+
}
638+
613639
type SubmitPayload = {
614640
text: string;
615641
attachments: { fileId: string; kind: 'image' | 'video' }[];
@@ -918,6 +944,8 @@ function openPr(url: string): void {
918944
:attention-by-session="client.attentionBySession.value"
919945
:pending-by-session="client.pendingBySession.value"
920946
:unread-by-session="client.unreadBySession.value"
947+
:mode="showSettings ? 'settings' : 'sessions'"
948+
:active-settings-tab="activeSettingsTab"
921949
@select="client.selectSession($event)"
922950
@create="handleCreateSession"
923951
@create-in-workspace="handleCreateSessionInWorkspace($event)"
@@ -930,6 +958,8 @@ function openPr(url: string): void {
930958
@delete-workspace="(id) => client.deleteWorkspace(id)"
931959
@select-workspaces="handleSelectWorkspaces"
932960
@open-settings="showSettings = true"
961+
@close-settings="showSettings = false"
962+
@select-settings-tab="selectSettingsTab($event)"
933963
@collapse="toggleSidebarCollapse"
934964
/>
935965
<ResizeHandle
@@ -992,7 +1022,7 @@ function openPr(url: string): void {
9921022
class="rail-btn"
9931023
:title="t('settings.title')"
9941024
:aria-label="t('settings.title')"
995-
@click="showSettings = true"
1025+
@click="toggleSettings"
9961026
>
9971027
<svg viewBox="0 0 24 24" width="18" height="18" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true">
9981028
<circle cx="12" cy="12" r="3" />
@@ -1014,8 +1044,40 @@ function openPr(url: string): void {
10141044
@open-settings="showMobileSettings = true"
10151045
/>
10161046

1047+
<SettingsPane
1048+
v-if="showSettings && !isMobile"
1049+
:active-tab="activeSettingsTab"
1050+
:theme="client.theme.value"
1051+
:color-scheme="client.colorScheme.value"
1052+
:ui-font-size="client.uiFontSize.value"
1053+
:auth-ready="client.authReady.value"
1054+
:account-model="client.defaultModel.value"
1055+
:notify="client.notifyOnComplete.value"
1056+
:notify-permission="client.notifyPermission.value"
1057+
:beta-toc="client.betaToc.value"
1058+
:config="client.config.value"
1059+
:models="client.models.value"
1060+
:config-saving="configSaving"
1061+
:skills="client.skills.value"
1062+
:connectors="client.connectors.value"
1063+
:connectors-loading="client.connectorsLoading.value"
1064+
:sessions="client.sessionsWithUsage.value"
1065+
:plugins="client.plugins.value"
1066+
:subagents="client.subagents.value"
1067+
@set-plugin-enabled="client.setPluginEnabled($event.pluginId, $event.enabled)"
1068+
@restart-connector="client.restartConnector($event)"
1069+
@set-theme="client.setTheme($event)"
1070+
@set-color-scheme="client.setColorScheme($event)"
1071+
@set-ui-font-size="client.setUiFontSize($event)"
1072+
@set-notify="client.setNotifyOnComplete($event)"
1073+
@set-beta-toc="client.setBetaToc($event)"
1074+
@update-config="handleUpdateConfig($event)"
1075+
@login="loginFromSettings"
1076+
@open-onboarding="openOnboardingFromSettings"
1077+
/>
1078+
10171079
<ConversationPane
1018-
v-if="!hasMultiSelect"
1080+
v-else-if="!hasMultiSelect"
10191081
ref="conversationPaneRef"
10201082
:mobile="isMobile"
10211083
:modern="client.theme.value === 'modern' || client.theme.value === 'pythinker'"
@@ -1188,42 +1250,6 @@ function openPr(url: string): void {
11881250
@close="showModelPicker = false"
11891251
/>
11901252

1191-
<!-- Settings page (modal) -->
1192-
<SettingsDialog
1193-
v-if="showSettings"
1194-
:theme="client.theme.value"
1195-
:color-scheme="client.colorScheme.value"
1196-
:ui-font-size="client.uiFontSize.value"
1197-
:auth-ready="client.authReady.value"
1198-
:account-model="client.defaultModel.value"
1199-
:notify="client.notifyOnComplete.value"
1200-
:notify-permission="client.notifyPermission.value"
1201-
:beta-toc="client.betaToc.value"
1202-
:config="client.config.value"
1203-
:models="client.models.value"
1204-
:config-saving="configSaving"
1205-
:skills="client.skills.value"
1206-
:connectors="client.connectors.value"
1207-
:connectors-loading="client.connectorsLoading.value"
1208-
:sessions="client.sessionsWithUsage.value"
1209-
:plugins="client.plugins.value"
1210-
:subagents="client.subagents.value"
1211-
@load-plugins="client.loadPlugins()"
1212-
@set-plugin-enabled="client.setPluginEnabled($event.pluginId, $event.enabled)"
1213-
@load-subagents="client.loadSubagents()"
1214-
@load-connectors="client.loadConnectors()"
1215-
@restart-connector="client.restartConnector($event)"
1216-
@set-theme="client.setTheme($event)"
1217-
@set-color-scheme="client.setColorScheme($event)"
1218-
@set-ui-font-size="client.setUiFontSize($event)"
1219-
@set-notify="client.setNotifyOnComplete($event)"
1220-
@set-beta-toc="client.setBetaToc($event)"
1221-
@update-config="handleUpdateConfig($event)"
1222-
@login="() => { showSettings = false; openLogin(); }"
1223-
@open-onboarding="() => { showSettings = false; openOnboarding(); }"
1224-
@close="showSettings = false"
1225-
/>
1226-
12271253
<!-- Provider Manager overlay -->
12281254
<ProviderManager
12291255
v-if="showProviders"

0 commit comments

Comments
 (0)