Skip to content
Merged
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
5 changes: 2 additions & 3 deletions apps/mobile/src/state/entities.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,7 @@ import type {
import { Atom } from "effect/unstable/reactivity";

import { environmentProjects } from "./projects";
import { environmentServerConfigsAtom } from "./server";
import { environmentSession } from "./session";
import { environmentServerConfigsAtom, serverEnvironment } from "./server";
import { environmentThreadShells } from "./threads";

const EMPTY_PROJECT_ATOM = Atom.make<EnvironmentProject | null>(null).pipe(
Expand Down Expand Up @@ -50,7 +49,7 @@ export function useEnvironmentServerConfig(
return useAtomValue(
environmentId === null
? EMPTY_SERVER_CONFIG_ATOM
: environmentSession.configValueAtom(environmentId),
: serverEnvironment.configValueAtom(environmentId),
);
}

Expand Down
4 changes: 2 additions & 2 deletions apps/mobile/src/state/presentation.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,12 @@ import type { EnvironmentId } from "@t3tools/contracts";
import { Atom } from "effect/unstable/reactivity";

import { environmentCatalog } from "../connection/catalog";
import { environmentSession } from "./session";
import { serverEnvironment } from "./server";

export const environmentPresentations = createEnvironmentPresentationAtoms({
catalogValueAtom: environmentCatalog.catalogValueAtom,
stateAtom: environmentCatalog.stateAtom,
configValueAtom: environmentSession.configValueAtom,
serverConfigValueAtom: serverEnvironment.configValueAtom,
});

const EMPTY_ENVIRONMENT_PRESENTATION_ATOM = Atom.make<EnvironmentPresentation | null>(null).pipe(
Expand Down
4 changes: 2 additions & 2 deletions apps/mobile/src/state/server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,9 @@ import { connectionAtomRuntime } from "../connection/runtime";
import { environmentSession } from "./session";

export const serverEnvironment = createServerEnvironmentAtoms(connectionAtomRuntime, {
initialConfigValueAtom: environmentSession.configValueAtom,
initialConfigValueAtom: environmentSession.initialConfigValueAtom,
});
export const environmentServerConfigsAtom = createEnvironmentServerConfigsAtom({
catalogValueAtom: environmentCatalog.catalogValueAtom,
configValueAtom: serverEnvironment.configValueAtom,
serverConfigValueAtom: serverEnvironment.configValueAtom,
});
12 changes: 8 additions & 4 deletions apps/web/src/components/ChatView.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -138,7 +138,7 @@ import {
} from "~/projectScripts";
import { newDraftId, newMessageId, newThreadId } from "~/lib/utils";
import { getProviderModelCapabilities, resolveSelectableProvider } from "../providerModels";
import { useSettings } from "../hooks/useSettings";
import { useEnvironmentSettings } from "../hooks/useSettings";
import { resolveAppModelSelectionForInstance } from "../modelSelection";
import { getTerminalFocusOwner } from "../lib/terminalFocus";
import { resolveNewDraftStartFromOrigin } from "../lib/chatThreadActions";
Expand Down Expand Up @@ -1027,7 +1027,7 @@ function ChatViewContent(props: ChatViewProps) {
const activeThreadLastVisitedAt = useUiStateStore((store) =>
routeKind === "server" ? store.threadLastVisitedAtById[routeThreadKey] : undefined,
);
const settings = useSettings();
const settings = useEnvironmentSettings(environmentId);
const setStickyComposerModelSelection = useComposerDraftStore(
(store) => store.setStickyModelSelection,
);
Expand Down Expand Up @@ -1417,7 +1417,7 @@ function ChatViewContent(props: ChatViewProps) {
},
[retryEnvironment],
);
const projectGroupingSettings = useSettings(selectProjectGroupingSettings);
const projectGroupingSettings = selectProjectGroupingSettings(settings);
const logicalProjectEnvironments = useMemo(() => {
if (!activeProject) return [];
const logicalKey = deriveLogicalProjectKeyFromSettings(activeProject, projectGroupingSettings);
Expand Down Expand Up @@ -1586,7 +1586,11 @@ function ChatViewContent(props: ChatViewProps) {
selectedProvider: selectedProviderByThreadId,
threadProvider,
});
const serverConfig = activeEnvironment?.serverConfig ?? primaryEnvironment?.serverConfig ?? null;
// Once a thread selects an environment, never substitute the primary
// environment's config while the selected environment is still loading.
const serverConfig = activeThread
? (activeEnvironment?.serverConfig ?? null)
: (primaryEnvironment?.serverConfig ?? null);
const versionMismatch = resolveServerConfigVersionMismatch(serverConfig);
const versionMismatchDismissKey =
versionMismatch && activeThread
Expand Down
52 changes: 14 additions & 38 deletions apps/web/src/components/CommandPalette.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ import {
import { useAtomValue } from "@effect/atom-react";
import { OpenAddProjectCommandPaletteProvider } from "../commandPaletteContext";
import { useHandleNewThread } from "../hooks/useHandleNewThread";
import { useSettings } from "../hooks/useSettings";
import { useClientSettings } from "../hooks/useSettings";
import { readLocalApi } from "../localApi";
import { filesystemEnvironment } from "../state/filesystem";
import { projectEnvironment } from "../state/projects";
Expand Down Expand Up @@ -447,7 +447,7 @@ function OpenCommandPaletteDialog(props: {
const deferredQuery = useDeferredValue(query);
const isActionsOnly = deferredQuery.startsWith(">");
const [highlightedItemValue, setHighlightedItemValue] = useState<string | null>(null);
const settings = useSettings();
const clientSettings = useClientSettings();
const createProject = useAtomCommand(projectEnvironment.create, {
reportFailure: false,
});
Expand Down Expand Up @@ -524,16 +524,14 @@ function OpenCommandPaletteDialog(props: {
const environment = environments.find(
(candidate) => candidate.environmentId === environmentId,
);
const environmentSettings =
environment?.serverConfig?.settings ??
(environmentId === primaryEnvironmentId ? settings : null);
const environmentSettings = environment?.serverConfig?.settings ?? null;
const baseDirectory = environmentSettings?.addProjectBaseDirectory?.trim() ?? "";
if (baseDirectory.length === 0) {
return "~/";
}
return ensureBrowseDirectoryPath(baseDirectory);
},
[environments, primaryEnvironmentId, settings],
[environments],
);

const projectCwdById = useMemo(
Expand Down Expand Up @@ -589,7 +587,7 @@ function OpenCommandPaletteDialog(props: {
const latestThread = getLatestThreadForProject(
threads.filter((thread) => thread.environmentId === project.environmentId),
project.id,
settings.sidebarThreadSortOrder,
clientSettings.sidebarThreadSortOrder,
);
if (latestThread) {
await navigate({
Expand All @@ -601,17 +599,9 @@ function OpenCommandPaletteDialog(props: {
return;
}

await handleNewThread(scopeProjectRef(project.environmentId, project.id), {
envMode: settings.defaultThreadEnvMode,
});
await handleNewThread(scopeProjectRef(project.environmentId, project.id));
},
[
handleNewThread,
navigate,
settings.defaultThreadEnvMode,
settings.sidebarThreadSortOrder,
threads,
],
[handleNewThread, navigate, clientSettings.sidebarThreadSortOrder, threads],
);

const projectSearchItems = useMemo(
Expand Down Expand Up @@ -650,21 +640,13 @@ function OpenCommandPaletteDialog(props: {
activeDraftThread,
activeThread: activeThread ?? undefined,
defaultProjectRef,
defaultThreadEnvMode: settings.defaultThreadEnvMode,
handleNewThread,
},
scopeProjectRef(project.environmentId, project.id),
);
},
}),
[
activeDraftThread,
activeThread,
defaultProjectRef,
handleNewThread,
projects,
settings.defaultThreadEnvMode,
],
[activeDraftThread, activeThread, defaultProjectRef, handleNewThread, projects],
);

const allThreadItems = useMemo(
Expand All @@ -673,7 +655,7 @@ function OpenCommandPaletteDialog(props: {
threads,
...(activeThreadId ? { activeThreadId } : {}),
projectTitleById,
sortOrder: settings.sidebarThreadSortOrder,
sortOrder: clientSettings.sidebarThreadSortOrder,
icon: <MessageSquareIcon className={ITEM_ICON_CLASS} />,
renderLeadingContent: (thread) => <ThreadRowLeadingStatus thread={thread} />,
renderTrailingContent: (thread) => <ThreadRowTrailingStatus thread={thread} />,
Expand All @@ -684,7 +666,7 @@ function OpenCommandPaletteDialog(props: {
});
},
}),
[activeThreadId, navigate, projectTitleById, settings.sidebarThreadSortOrder, threads],
[activeThreadId, clientSettings.sidebarThreadSortOrder, navigate, projectTitleById, threads],
);
const recentThreadItems = allThreadItems.slice(0, RECENT_THREAD_LIMIT);

Expand Down Expand Up @@ -956,7 +938,6 @@ function OpenCommandPaletteDialog(props: {
activeDraftThread,
activeThread: activeThread ?? undefined,
defaultProjectRef,
defaultThreadEnvMode: settings.defaultThreadEnvMode,
handleNewThread,
});
},
Expand Down Expand Up @@ -1072,7 +1053,7 @@ function OpenCommandPaletteDialog(props: {
const latestThread = getLatestThreadForProject(
threads.filter((thread) => thread.environmentId === existing.environmentId),
existing.id,
settings.sidebarThreadSortOrder,
clientSettings.sidebarThreadSortOrder,
);
if (latestThread) {
await navigate({
Expand All @@ -1083,9 +1064,7 @@ function OpenCommandPaletteDialog(props: {
});
} else {
const navigationResult = await settlePromise(() =>
handleNewThread(scopeProjectRef(existing.environmentId, existing.id), {
envMode: settings.defaultThreadEnvMode,
}),
handleNewThread(scopeProjectRef(existing.environmentId, existing.id)),
);
if (navigationResult._tag === "Failure") {
const error = squashAtomCommandFailure(navigationResult);
Expand Down Expand Up @@ -1132,9 +1111,7 @@ function OpenCommandPaletteDialog(props: {
}

const navigationResult = await settlePromise(() =>
handleNewThread(scopeProjectRef(browseEnvironmentId, projectId), {
envMode: settings.defaultThreadEnvMode,
}),
handleNewThread(scopeProjectRef(browseEnvironmentId, projectId)),
);
if (navigationResult._tag === "Failure") {
const error = squashAtomCommandFailure(navigationResult);
Expand All @@ -1158,8 +1135,7 @@ function OpenCommandPaletteDialog(props: {
navigate,
projects,
setOpen,
settings.defaultThreadEnvMode,
settings.sidebarThreadSortOrder,
clientSettings.sidebarThreadSortOrder,
threads,
],
);
Expand Down
4 changes: 2 additions & 2 deletions apps/web/src/components/DiffPanel.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ import {
import { useTurnDiffSummaries } from "../hooks/useTurnDiffSummaries";
import { useProject, useThread } from "../state/entities";
import { resolveThreadRouteRef } from "../threadRoutes";
import { useSettings } from "../hooks/useSettings";
import { useClientSettings } from "../hooks/useSettings";
import { formatShortTimestamp } from "../timestampFormat";
import { DiffPanelLoadingState, DiffPanelShell, type DiffPanelMode } from "./DiffPanelShell";
import { AnnotatableCodeView, type AnnotatableCodeViewHandle } from "./diffs/AnnotatableFileDiff";
Expand Down Expand Up @@ -183,7 +183,7 @@ export { DiffWorkerPoolProvider } from "./DiffWorkerPoolProvider";

export default function DiffPanel({ mode = "inline", composerDraftTarget }: DiffPanelProps) {
const { resolvedTheme } = useTheme();
const settings = useSettings();
const settings = useClientSettings();
const [diffRenderMode, setDiffRenderMode] = useState<DiffRenderMode>("stacked");
const [diffWordWrap, setDiffWordWrap] = useState(settings.diffWordWrap);
const [diffIgnoreWhitespace, setDiffIgnoreWhitespace] = useState(settings.diffIgnoreWhitespace);
Expand Down
41 changes: 21 additions & 20 deletions apps/web/src/components/Sidebar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -41,11 +41,11 @@ import { restrictToFirstScrollableAncestor, restrictToVerticalAxis } from "@dnd-
import { CSS } from "@dnd-kit/utilities";
import {
type ContextMenuItem,
DEFAULT_SERVER_SETTINGS,
ProjectId,
type ScopedThreadRef,
type ResolvedKeybindingsConfig,
type SidebarProjectGroupingMode,
type ThreadEnvMode,
ThreadId,
} from "@t3tools/contracts";
import {
Expand Down Expand Up @@ -77,6 +77,7 @@ import {
readThreadShell,
useProject,
useProjects,
useServerConfigs,
useThreadShells,
useThreadShellsForProjectRefs,
} from "../state/entities";
Expand Down Expand Up @@ -199,7 +200,7 @@ import { SidebarUpdatePill } from "./sidebar/SidebarUpdatePill";
import { useCopyToClipboard } from "~/hooks/useCopyToClipboard";
import { useIsMobile } from "~/hooks/useMediaQuery";
import { CommandDialogTrigger } from "./ui/command";
import { useSettings, useUpdateSettings } from "~/hooks/useSettings";
import { useClientSettings, useUpdateClientSettings } from "~/hooks/useSettings";
import { primaryServerConfigAtom, primaryServerKeybindingsAtom } from "../state/server";
import {
derivePhysicalProjectKey,
Expand Down Expand Up @@ -1084,19 +1085,17 @@ const SidebarProjectItem = memo(function SidebarProjectItem(props: SidebarProjec
isManualProjectSorting,
dragHandleProps,
} = props;
const threadSortOrder = useSettings<SidebarThreadSortOrder>(
const threadSortOrder = useClientSettings<SidebarThreadSortOrder>(
(settings) => settings.sidebarThreadSortOrder,
);
const appSettingsConfirmThreadDelete = useSettings<boolean>(
const appSettingsConfirmThreadDelete = useClientSettings<boolean>(
(settings) => settings.confirmThreadDelete,
);
const appSettingsConfirmThreadArchive = useSettings<boolean>(
const appSettingsConfirmThreadArchive = useClientSettings<boolean>(
(settings) => settings.confirmThreadArchive,
);
const defaultThreadEnvMode = useSettings<ThreadEnvMode>(
(settings) => settings.defaultThreadEnvMode,
);
const projectGroupingSettings = useSettings(selectProjectGroupingSettings);
const projectGroupingSettings = useClientSettings(selectProjectGroupingSettings);
const serverConfigs = useServerConfigs();
const deleteProject = useAtomCommand(projectEnvironment.delete, {
reportFailure: false,
});
Expand All @@ -1106,8 +1105,8 @@ const SidebarProjectItem = memo(function SidebarProjectItem(props: SidebarProjec
const updateThreadMetadata = useAtomCommand(threadEnvironment.updateMetadata, {
reportFailure: false,
});
const updateSettings = useUpdateSettings();
const sidebarThreadPreviewCount = useSettings<SidebarThreadPreviewCount>(
const updateSettings = useUpdateClientSettings();
const sidebarThreadPreviewCount = useClientSettings<SidebarThreadPreviewCount>(
(settings) => settings.sidebarThreadPreviewCount,
);
const router = useRouter();
Expand Down Expand Up @@ -1840,7 +1839,9 @@ const SidebarProjectItem = memo(function SidebarProjectItem(props: SidebarProjec
const seedContext = resolveSidebarNewThreadSeedContext({
projectId: member.id,
defaultEnvMode: resolveSidebarNewThreadEnvMode({
defaultEnvMode: defaultThreadEnvMode,
defaultEnvMode:
serverConfigs.get(member.environmentId)?.settings.defaultThreadEnvMode ??
DEFAULT_SERVER_SETTINGS.defaultThreadEnvMode,
}),
activeThread:
currentActiveThread && currentActiveThread.projectId === member.id
Expand Down Expand Up @@ -1889,7 +1890,7 @@ const SidebarProjectItem = memo(function SidebarProjectItem(props: SidebarProjec
}
})();
},
[defaultThreadEnvMode, handleNewThread, isMobile, router, setOpenMobile],
[handleNewThread, isMobile, router, serverConfigs, setOpenMobile],
);

const handleCreateThreadClick = useCallback(
Expand Down Expand Up @@ -2745,7 +2746,7 @@ interface SidebarProjectsContentProps {
threadSortOrder: SidebarThreadSortOrder;
projectGroupingMode: SidebarProjectGroupingMode;
threadPreviewCount: SidebarThreadPreviewCount;
updateSettings: ReturnType<typeof useUpdateSettings>;
updateSettings: ReturnType<typeof useUpdateClientSettings>;
openAddProject: () => void;
isManualProjectSorting: boolean;
projectDnDSensors: ReturnType<typeof useSensors>;
Expand Down Expand Up @@ -3014,12 +3015,12 @@ export default function Sidebar() {
const navigate = useNavigate();
const pathname = useLocation({ select: (loc) => loc.pathname });
const isOnSettings = pathname.startsWith("/settings");
const sidebarThreadSortOrder = useSettings((s) => s.sidebarThreadSortOrder);
const sidebarProjectSortOrder = useSettings((s) => s.sidebarProjectSortOrder);
const sidebarProjectGroupingMode = useSettings((s) => s.sidebarProjectGroupingMode);
const projectGroupingSettings = useSettings(selectProjectGroupingSettings);
const sidebarThreadPreviewCount = useSettings((s) => s.sidebarThreadPreviewCount);
const updateSettings = useUpdateSettings();
const sidebarThreadSortOrder = useClientSettings((s) => s.sidebarThreadSortOrder);
const sidebarProjectSortOrder = useClientSettings((s) => s.sidebarProjectSortOrder);
const sidebarProjectGroupingMode = useClientSettings((s) => s.sidebarProjectGroupingMode);
const projectGroupingSettings = useClientSettings(selectProjectGroupingSettings);
const sidebarThreadPreviewCount = useClientSettings((s) => s.sidebarThreadPreviewCount);
const updateSettings = useUpdateClientSettings();
const handleNewThread = useNewThreadHandler();
const { archiveThread, deleteThread } = useThreadActions();
const { isMobile, setOpenMobile } = useSidebar();
Expand Down
Loading
Loading