Skip to content

Commit 5ae61b5

Browse files
committed
refactor(frontend): decompose MainApp, sidebar, composer, and thread hooks
1 parent 785c356 commit 5ae61b5

57 files changed

Lines changed: 8460 additions & 6100 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

src/features/app/components/MainApp.tsx

Lines changed: 31 additions & 151 deletions
Original file line numberDiff line numberDiff line change
@@ -44,16 +44,18 @@ import { useMainAppDisplayNodes } from "@app/hooks/useMainAppDisplayNodes";
4444
import { useMainAppPromptActions } from "@app/hooks/useMainAppPromptActions";
4545
import { useMainAppShellProps } from "@app/hooks/useMainAppShellProps";
4646
import { useMainAppSidebarMenuOrchestration } from "@app/hooks/useMainAppSidebarMenuOrchestration";
47+
import { useMainAppSettingsActions } from "@app/hooks/useMainAppSettingsActions";
48+
import { useMainAppThreadCodexState } from "@app/hooks/useMainAppThreadCodexState";
4749
import { useMainAppWorktreeState } from "@app/hooks/useMainAppWorktreeState";
4850
import { useMainAppWorkspaceActions } from "@app/hooks/useMainAppWorkspaceActions";
4951
import { useMainAppWorkspaceLifecycle } from "@app/hooks/useMainAppWorkspaceLifecycle";
52+
import { useMainAppMobileThreadRefresh } from "@app/hooks/useMainAppMobileThreadRefresh";
5053
import { useHomeAccount } from "@app/hooks/useHomeAccount";
5154
import type {
5255
ComposerEditorSettings,
5356
ServiceTier,
5457
WorkspaceInfo,
5558
} from "@/types";
56-
import { OPEN_APP_STORAGE_KEY } from "@app/constants";
5759
import { useOpenAppIcons } from "@app/hooks/useOpenAppIcons";
5860
import { useAccountSwitching } from "@app/hooks/useAccountSwitching";
5961
import { useNewAgentDraft } from "@app/hooks/useNewAgentDraft";
@@ -76,14 +78,8 @@ import {
7678
useWorkspaceOrderingOrchestration,
7779
} from "@app/orchestration/useWorkspaceOrchestration";
7880
import { useAppShellOrchestration } from "@app/orchestration/useLayoutOrchestration";
79-
import { buildCodexArgsOptions } from "@threads/utils/codexArgsProfiles";
8081
import { normalizeCodexArgsInput } from "@/utils/codexArgsInput";
81-
import {
82-
resolveWorkspaceRuntimeCodexArgsBadgeLabel,
83-
resolveWorkspaceRuntimeCodexArgsOverride,
84-
} from "@threads/utils/threadCodexParamsSeed";
8582
import { subscribeTrayOpenThread } from "@services/events";
86-
import { setWorkspaceRuntimeCodexArgs } from "@services/tauri";
8783

8884
const SettingsView = lazy(() =>
8985
import("@settings/components/SettingsView").then((module) => ({
@@ -133,7 +129,6 @@ export default function MainApp() {
133129
const [activeTab, setActiveTab] = useState<
134130
"home" | "projects" | "codex" | "git" | "log"
135131
>("codex");
136-
const [mobileThreadRefreshLoading, setMobileThreadRefreshLoading] = useState(false);
137132
const tabletTab =
138133
activeTab === "projects" || activeTab === "home" ? "codex" : activeTab;
139134
const {
@@ -410,73 +405,17 @@ export default function MainApp() {
410405
const resolvedModel = selectedModel?.model ?? null;
411406
const resolvedEffort = reasoningSupported ? selectedEffort : null;
412407

413-
const handleThreadCodexMetadataDetected = useCallback(
414-
(
415-
workspaceId: string,
416-
threadId: string,
417-
metadata: { modelId: string | null; effort: string | null },
418-
) => {
419-
if (!workspaceId || !threadId) {
420-
return;
421-
}
422-
const modelId =
423-
typeof metadata.modelId === "string" && metadata.modelId.trim().length > 0
424-
? metadata.modelId.trim()
425-
: null;
426-
const effort =
427-
typeof metadata.effort === "string" && metadata.effort.trim().length > 0
428-
? metadata.effort.trim().toLowerCase()
429-
: null;
430-
if (!modelId && !effort) {
431-
return;
432-
}
433-
434-
const current = getThreadCodexParams(workspaceId, threadId);
435-
const patch: {
436-
modelId?: string | null;
437-
effort?: string | null;
438-
} = {};
439-
if (modelId && !current?.modelId) {
440-
patch.modelId = modelId;
441-
}
442-
if (effort && !current?.effort) {
443-
patch.effort = effort;
444-
}
445-
if (Object.keys(patch).length === 0) {
446-
return;
447-
}
448-
patchThreadCodexParams(workspaceId, threadId, patch);
449-
},
450-
[getThreadCodexParams, patchThreadCodexParams],
451-
);
452-
const codexArgsOptions = useMemo(
453-
() =>
454-
buildCodexArgsOptions({
455-
appCodexArgs: appSettings.codexArgs ?? null,
456-
additionalCodexArgs: [selectedCodexArgsOverride],
457-
}),
458-
[appSettings.codexArgs, selectedCodexArgsOverride],
459-
);
460-
const ensureWorkspaceRuntimeCodexArgs = useCallback(
461-
async (workspaceId: string, threadId: string | null) => {
462-
const sanitizedCodexArgsOverride = resolveWorkspaceRuntimeCodexArgsOverride({
463-
workspaceId,
464-
threadId,
465-
getThreadCodexParams,
466-
});
467-
await setWorkspaceRuntimeCodexArgs(workspaceId, sanitizedCodexArgsOverride);
468-
},
469-
[getThreadCodexParams],
470-
);
471-
const getThreadArgsBadge = useCallback(
472-
(workspaceId: string, threadId: string) =>
473-
resolveWorkspaceRuntimeCodexArgsBadgeLabel({
474-
workspaceId,
475-
threadId,
476-
getThreadCodexParams,
477-
}),
478-
[getThreadCodexParams],
479-
);
408+
const {
409+
handleThreadCodexMetadataDetected,
410+
codexArgsOptions,
411+
ensureWorkspaceRuntimeCodexArgs,
412+
getThreadArgsBadge,
413+
} = useMainAppThreadCodexState({
414+
appCodexArgs: appSettings.codexArgs,
415+
selectedCodexArgsOverride,
416+
getThreadCodexParams,
417+
patchThreadCodexParams,
418+
});
480419

481420
const { collaborationModePayload } = useCollaborationModeSelection({
482421
selectedCollaborationMode,
@@ -590,38 +529,14 @@ export default function MainApp() {
590529
reconnectWorkspace: connectWorkspace,
591530
});
592531

593-
const handleMobileThreadRefresh = useCallback(() => {
594-
if (mobileThreadRefreshLoading || !activeWorkspace) {
595-
return;
596-
}
597-
setMobileThreadRefreshLoading(true);
598-
void (async () => {
599-
let threadId = activeThreadId;
600-
if (!threadId) {
601-
threadId = await startThreadForWorkspace(activeWorkspace.id, {
602-
activate: true,
603-
});
604-
}
605-
if (!threadId) {
606-
return;
607-
}
608-
await refreshThread(activeWorkspace.id, threadId);
609-
await reconnectLive(activeWorkspace.id, threadId, { runResume: false });
610-
})()
611-
.catch(() => {
612-
// Errors are surfaced through debug entries/toasts in existing thread actions.
613-
})
614-
.finally(() => {
615-
setMobileThreadRefreshLoading(false);
616-
});
617-
}, [
618-
activeThreadId,
619-
activeWorkspace,
620-
mobileThreadRefreshLoading,
621-
refreshThread,
622-
reconnectLive,
623-
startThreadForWorkspace,
624-
]);
532+
const { mobileThreadRefreshLoading, handleMobileThreadRefresh } =
533+
useMainAppMobileThreadRefresh({
534+
activeWorkspace,
535+
activeThreadId,
536+
startThreadForWorkspace,
537+
refreshThread,
538+
reconnectLive,
539+
});
625540
const {
626541
updaterState,
627542
startUpdate,
@@ -995,53 +910,18 @@ export default function MainApp() {
995910
updateWorkspaceSettings,
996911
});
997912

998-
const handleSelectOpenAppId = useCallback(
999-
(id: string) => {
1000-
if (typeof window !== "undefined") {
1001-
window.localStorage.setItem(OPEN_APP_STORAGE_KEY, id);
1002-
}
1003-
setAppSettings((current) => {
1004-
if (current.selectedOpenAppId === id) {
1005-
return current;
1006-
}
1007-
const nextSettings = {
1008-
...current,
1009-
selectedOpenAppId: id,
1010-
};
1011-
void queueSaveSettings(nextSettings);
1012-
return nextSettings;
1013-
});
1014-
},
1015-
[queueSaveSettings, setAppSettings],
1016-
);
1017-
1018-
const handleToggleAutomaticAppUpdateChecks = useCallback(() => {
1019-
setAppSettings((current) => {
1020-
const nextSettings = {
1021-
...current,
1022-
automaticAppUpdateChecksEnabled:
1023-
!current.automaticAppUpdateChecksEnabled,
1024-
};
1025-
void queueSaveSettings(nextSettings);
1026-
return nextSettings;
1027-
});
1028-
}, [queueSaveSettings, setAppSettings]);
913+
const {
914+
handleSelectOpenAppId,
915+
handleToggleAutomaticAppUpdateChecks,
916+
persistProjectCopiesFolder,
917+
} = useMainAppSettingsActions({
918+
appSettings,
919+
setAppSettings,
920+
queueSaveSettings,
921+
});
1029922

1030923
const openAppIconById = useOpenAppIcons(appSettings.openAppTargets);
1031924

1032-
const persistProjectCopiesFolder = useCallback(
1033-
async (groupId: string, copiesFolder: string) => {
1034-
await queueSaveSettings({
1035-
...appSettings,
1036-
workspaceGroups: appSettings.workspaceGroups.map((entry) =>
1037-
entry.id === groupId ? { ...entry, copiesFolder } : entry,
1038-
),
1039-
});
1040-
},
1041-
[appSettings, queueSaveSettings],
1042-
);
1043-
1044-
1045925
const {
1046926
workspaceFromUrlPrompt,
1047927
openWorkspaceFromUrlPrompt,

0 commit comments

Comments
 (0)