Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
85 changes: 65 additions & 20 deletions apps/web/src/components/settings/SettingsPanels.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -387,7 +387,9 @@ function AboutVersionSection() {
);
}

export function useSettingsRestore(onRestored?: () => void) {
export type SettingsOwnership = "client" | "environment";

export function useSettingsRestore(ownership: SettingsOwnership, onRestored?: () => void) {
const { theme, setTheme } = useTheme();
const settings = usePrimarySettings();
const updateSettings = useUpdatePrimarySettings();
Expand All @@ -397,8 +399,8 @@ export function useSettingsRestore(onRestored?: () => void) {
DEFAULT_UNIFIED_SETTINGS.textGenerationModelSelection ?? null,
);

const changedSettingLabels = useMemo(
() => [
const changedSettingLabels = useMemo(() => {
const clientSettingLabels = [
...(theme !== "system" ? ["Theme"] : []),
...(settings.glassOpacity !== DEFAULT_UNIFIED_SETTINGS.glassOpacity ? ["Glass opacity"] : []),
...(settings.timestampFormat !== DEFAULT_UNIFIED_SETTINGS.timestampFormat
Expand All @@ -418,6 +420,14 @@ export function useSettingsRestore(onRestored?: () => void) {
...(settings.autoOpenPlanSidebar !== DEFAULT_UNIFIED_SETTINGS.autoOpenPlanSidebar
? ["Auto-open task panel"]
: []),
...(settings.confirmThreadArchive !== DEFAULT_UNIFIED_SETTINGS.confirmThreadArchive
? ["Archive confirmation"]
: []),
...(settings.confirmThreadDelete !== DEFAULT_UNIFIED_SETTINGS.confirmThreadDelete
? ["Delete confirmation"]
: []),
];
const environmentSettingLabels = [
...(settings.enableAssistantStreaming !== DEFAULT_UNIFIED_SETTINGS.enableAssistantStreaming
? ["Assistant output"]
: []),
Expand All @@ -439,16 +449,12 @@ export function useSettingsRestore(onRestored?: () => void) {
...(settings.addProjectBaseDirectory !== DEFAULT_UNIFIED_SETTINGS.addProjectBaseDirectory
? ["Add project base directory"]
: []),
...(settings.confirmThreadArchive !== DEFAULT_UNIFIED_SETTINGS.confirmThreadArchive
? ["Archive confirmation"]
: []),
...(settings.confirmThreadDelete !== DEFAULT_UNIFIED_SETTINGS.confirmThreadDelete
? ["Delete confirmation"]
: []),
...(isGitWritingModelDirty ? ["Git writing model"] : []),
],
[
];
return ownership === "client" ? clientSettingLabels : environmentSettingLabels;
}, [
isGitWritingModelDirty,
ownership,
settings.autoOpenPlanSidebar,
settings.confirmThreadArchive,
settings.confirmThreadDelete,
Expand All @@ -465,8 +471,7 @@ export function useSettingsRestore(onRestored?: () => void) {
settings.timestampFormat,
settings.wordWrap,
theme,
],
);
]);

const restoreDefaults = useCallback(async () => {
if (changedSettingLabels.length === 0) return;
Expand All @@ -478,6 +483,7 @@ export function useSettingsRestore(onRestored?: () => void) {
);
if (!confirmed) return;

if (ownership === "client") {
setTheme("system");
updateSettings({
timestampFormat: DEFAULT_UNIFIED_SETTINGS.timestampFormat,
Expand All @@ -487,26 +493,30 @@ export function useSettingsRestore(onRestored?: () => void) {
sidebarThreadPreviewCount: DEFAULT_UNIFIED_SETTINGS.sidebarThreadPreviewCount,
sidebarProjectGroupingMode: DEFAULT_UNIFIED_SETTINGS.sidebarProjectGroupingMode,
autoOpenPlanSidebar: DEFAULT_UNIFIED_SETTINGS.autoOpenPlanSidebar,
confirmThreadArchive: DEFAULT_UNIFIED_SETTINGS.confirmThreadArchive,
confirmThreadDelete: DEFAULT_UNIFIED_SETTINGS.confirmThreadDelete,
});
} else {
updateSettings({
enableAssistantStreaming: DEFAULT_UNIFIED_SETTINGS.enableAssistantStreaming,
enableProviderUpdateChecks: DEFAULT_UNIFIED_SETTINGS.enableProviderUpdateChecks,
automaticGitFetchInterval: DEFAULT_UNIFIED_SETTINGS.automaticGitFetchInterval,
defaultThreadEnvMode: DEFAULT_UNIFIED_SETTINGS.defaultThreadEnvMode,
newWorktreesStartFromOrigin: DEFAULT_UNIFIED_SETTINGS.newWorktreesStartFromOrigin,
addProjectBaseDirectory: DEFAULT_UNIFIED_SETTINGS.addProjectBaseDirectory,
confirmThreadArchive: DEFAULT_UNIFIED_SETTINGS.confirmThreadArchive,
confirmThreadDelete: DEFAULT_UNIFIED_SETTINGS.confirmThreadDelete,
textGenerationModelSelection: DEFAULT_UNIFIED_SETTINGS.textGenerationModelSelection,
});
}
onRestored?.();
}, [changedSettingLabels, onRestored, setTheme, updateSettings]);
}, [changedSettingLabels, onRestored, ownership, setTheme, updateSettings]);

return {
changedSettingLabels,
restoreDefaults,
};
}

export function GeneralSettingsPanel() {
function OwnershipSettingsPanel({ ownership }: { ownership: SettingsOwnership }) {
const { theme, setTheme } = useTheme();
const settings = usePrimarySettings();
const updateSettings = useUpdatePrimarySettings();
Expand Down Expand Up @@ -554,7 +564,9 @@ export function GeneralSettingsPanel() {

return (
<SettingsPageContainer>
<SettingsSection title="General">
<SettingsSection title={ownership === "client" ? "Client" : "Environment"}>
{ownership === "client" ? (
<>
<SettingsRow
title="Theme"
description="Choose how T3 Code looks across the app."
Expand Down Expand Up @@ -644,7 +656,8 @@ export function GeneralSettingsPanel() {
label="project grouping"
onClick={() =>
updateSettings({
sidebarProjectGroupingMode: DEFAULT_UNIFIED_SETTINGS.sidebarProjectGroupingMode,
sidebarProjectGroupingMode:
DEFAULT_UNIFIED_SETTINGS.sidebarProjectGroupingMode,
})
}
/>
Expand Down Expand Up @@ -761,7 +774,11 @@ export function GeneralSettingsPanel() {
/>
}
/>
</>
) : null}

{ownership === "environment" ? (
<>
<SettingsRow
title="Assistant output"
description="Show token-by-token output while a response is in progress."
Expand Down Expand Up @@ -799,7 +816,8 @@ export function GeneralSettingsPanel() {
label="provider update checks"
onClick={() =>
updateSettings({
enableProviderUpdateChecks: DEFAULT_UNIFIED_SETTINGS.enableProviderUpdateChecks,
enableProviderUpdateChecks:
DEFAULT_UNIFIED_SETTINGS.enableProviderUpdateChecks,
})
}
/>
Expand All @@ -815,7 +833,10 @@ export function GeneralSettingsPanel() {
/>
}
/>
</>
) : null}

{ownership === "client" ? (
<SettingsRow
title="Auto-open task panel"
description="Open the right-side plan and task panel automatically when steps appear."
Expand All @@ -841,7 +862,10 @@ export function GeneralSettingsPanel() {
/>
}
/>
) : null}

{ownership === "environment" ? (
<>
<SettingsRow
title="New threads"
description="Pick the default workspace mode for newly created draft threads."
Expand Down Expand Up @@ -945,7 +969,11 @@ export function GeneralSettingsPanel() {
/>
}
/>
</>
) : null}

{ownership === "client" ? (
<>
<SettingsRow
title="Archive confirmation"
description="Require a second click on the inline archive action before a thread is archived."
Expand Down Expand Up @@ -997,7 +1025,10 @@ export function GeneralSettingsPanel() {
/>
}
/>
</>
) : null}

{ownership === "environment" ? (
<SettingsRow
title="Text generation model"
description="Configure the model used for generated commit messages, PR titles, and similar Git text."
Expand Down Expand Up @@ -1071,8 +1102,10 @@ export function GeneralSettingsPanel() {
</div>
}
/>
) : null}
</SettingsSection>

{ownership === "client" ? (
<SettingsSection title="About">
{isElectron || HOSTED_APP_CHANNEL ? (
<AboutVersionSection />
Expand All @@ -1082,6 +1115,9 @@ export function GeneralSettingsPanel() {
description="Current version of the application."
/>
)}
</SettingsSection>
) : (
<SettingsSection title="Diagnostics">
<SettingsRow
title="Diagnostics"
description={diagnosticsDescription}
Expand All @@ -1092,10 +1128,19 @@ export function GeneralSettingsPanel() {
}
/>
</SettingsSection>
)}
</SettingsPageContainer>
);
}

export function GeneralSettingsPanel() {
return <OwnershipSettingsPanel ownership="client" />;
}

export function EnvironmentSettingsPanel() {
return <OwnershipSettingsPanel ownership="environment" />;
}

export function ProviderSettingsPanel() {
const settings = usePrimarySettings();
const updateSettings = useUpdatePrimarySettings();
Expand Down
33 changes: 33 additions & 0 deletions apps/web/src/components/settings/SettingsSidebarNav.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import { describe, expect, it } from "@effect/vitest";

import { SETTINGS_NAV_GROUPS } from "./SettingsSidebarNav";

describe("settings navigation ownership", () => {
it("separates client-owned pages from environment-owned pages", () => {
expect(
SETTINGS_NAV_GROUPS.map((group) => ({
label: group.label,
routes: group.items.map((item) => item.to),
})),
).toEqual([
{
label: "Client",
routes: [
"/settings/general",
"/settings/connections",
"/settings/beta",
"/settings/archived",
],
},
{
label: "Environment",
routes: [
"/settings/environment",
"/settings/keybindings",
"/settings/providers",
"/settings/source-control",
],
},
]);
});
});
Loading
Loading