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
179 changes: 2 additions & 177 deletions apps/web/src/components/Sidebar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,9 @@ import {
FolderIcon,
GitPullRequestIcon,
PlusIcon,
RocketIcon,
SettingsIcon,
SquarePenIcon,
TerminalIcon,
TriangleAlertIcon,
} from "lucide-react";
import { useCallback, useEffect, useMemo, useRef, useState, type MouseEvent } from "react";
import {
Expand All @@ -28,7 +26,6 @@ import { restrictToParentElement, restrictToVerticalAxis } from "@dnd-kit/modifi
import { CSS } from "@dnd-kit/utilities";
import {
DEFAULT_MODEL_BY_PROVIDER,
type DesktopUpdateState,
ProjectId,
ThreadId,
type GitStatusResult,
Expand All @@ -50,19 +47,6 @@ import { useComposerDraftStore } from "../composerDraftStore";
import { useHandleNewThread } from "../hooks/useHandleNewThread";
import { selectThreadTerminalState, useTerminalStateStore } from "../terminalStateStore";
import { toastManager } from "./ui/toast";
import {
getArm64IntelBuildWarningDescription,
getDesktopUpdateActionError,
getDesktopUpdateButtonTooltip,
isDesktopUpdateButtonDisabled,
resolveDesktopUpdateButtonAction,
shouldShowArm64IntelBuildWarning,
shouldHighlightDesktopUpdateError,
shouldShowDesktopUpdateButton,
shouldToastDesktopUpdateActionResult,
} from "./desktopUpdate.logic";
import { Alert, AlertAction, AlertDescription, AlertTitle } from "./ui/alert";
import { Button } from "./ui/button";
import { Collapsible, CollapsibleContent } from "./ui/collapsible";
import { Tooltip, TooltipPopup, TooltipTrigger } from "./ui/tooltip";
import {
Expand All @@ -89,6 +73,7 @@ import {
resolveThreadStatusPill,
shouldClearThreadSelectionOnMouseDown,
} from "./Sidebar.logic";
import { SidebarUpdatePill } from "./sidebar/SidebarUpdatePill";
import { useCopyToClipboard } from "~/hooks/useCopyToClipboard";

const EMPTY_KEYBINDINGS: ResolvedKeybindingsConfig = [];
Expand Down Expand Up @@ -298,7 +283,6 @@ export default function Sidebar() {
const renamingInputRef = useRef<HTMLInputElement | null>(null);
const dragInProgressRef = useRef(false);
const suppressProjectClickAfterDragRef = useRef(false);
const [desktopUpdateState, setDesktopUpdateState] = useState<DesktopUpdateState | null>(null);
const selectedThreadIds = useThreadSelectionStore((s) => s.selectedThreadIds);
const toggleThreadSelection = useThreadSelectionStore((s) => s.toggleThread);
const rangeSelectTo = useThreadSelectionStore((s) => s.rangeSelectTo);
Expand Down Expand Up @@ -963,131 +947,13 @@ export default function Sidebar() {
};
}, [clearSelection, selectedThreadIds.size]);

useEffect(() => {
if (!isElectron) return;
const bridge = window.desktopBridge;
if (
!bridge ||
typeof bridge.getUpdateState !== "function" ||
typeof bridge.onUpdateState !== "function"
) {
return;
}

let disposed = false;
let receivedSubscriptionUpdate = false;
const unsubscribe = bridge.onUpdateState((nextState) => {
if (disposed) return;
receivedSubscriptionUpdate = true;
setDesktopUpdateState(nextState);
});

void bridge
.getUpdateState()
.then((nextState) => {
if (disposed || receivedSubscriptionUpdate) return;
setDesktopUpdateState(nextState);
})
.catch(() => undefined);

return () => {
disposed = true;
unsubscribe();
};
}, []);

const showDesktopUpdateButton = isElectron && shouldShowDesktopUpdateButton(desktopUpdateState);

const desktopUpdateTooltip = desktopUpdateState
? getDesktopUpdateButtonTooltip(desktopUpdateState)
: "Update available";

const desktopUpdateButtonDisabled = isDesktopUpdateButtonDisabled(desktopUpdateState);
const desktopUpdateButtonAction = desktopUpdateState
? resolveDesktopUpdateButtonAction(desktopUpdateState)
: "none";
const showArm64IntelBuildWarning =
isElectron && shouldShowArm64IntelBuildWarning(desktopUpdateState);
const arm64IntelBuildWarningDescription =
desktopUpdateState && showArm64IntelBuildWarning
? getArm64IntelBuildWarningDescription(desktopUpdateState)
: null;
const desktopUpdateButtonInteractivityClasses = desktopUpdateButtonDisabled
? "cursor-not-allowed opacity-60"
: "hover:bg-accent hover:text-foreground";
const desktopUpdateButtonClasses =
desktopUpdateState?.status === "downloaded"
? "text-emerald-500"
: desktopUpdateState?.status === "downloading"
? "text-sky-400"
: shouldHighlightDesktopUpdateError(desktopUpdateState)
? "text-rose-500 animate-pulse"
: "text-amber-500 animate-pulse";
const newThreadShortcutLabel = useMemo(
() =>
shortcutLabelForCommand(keybindings, "chat.newLocal") ??
shortcutLabelForCommand(keybindings, "chat.new"),
[keybindings],
);

const handleDesktopUpdateButtonClick = useCallback(() => {
const bridge = window.desktopBridge;
if (!bridge || !desktopUpdateState) return;
if (desktopUpdateButtonDisabled || desktopUpdateButtonAction === "none") return;

if (desktopUpdateButtonAction === "download") {
void bridge
.downloadUpdate()
.then((result) => {
if (result.completed) {
toastManager.add({
type: "success",
title: "Update downloaded",
description: "Restart the app from the update button to install it.",
});
}
if (!shouldToastDesktopUpdateActionResult(result)) return;
const actionError = getDesktopUpdateActionError(result);
if (!actionError) return;
toastManager.add({
type: "error",
title: "Could not download update",
description: actionError,
});
})
.catch((error) => {
toastManager.add({
type: "error",
title: "Could not start update download",
description: error instanceof Error ? error.message : "An unexpected error occurred.",
});
});
return;
}

if (desktopUpdateButtonAction === "install") {
void bridge
.installUpdate()
.then((result) => {
if (!shouldToastDesktopUpdateActionResult(result)) return;
const actionError = getDesktopUpdateActionError(result);
if (!actionError) return;
toastManager.add({
type: "error",
title: "Could not install update",
description: actionError,
});
})
.catch((error) => {
toastManager.add({
type: "error",
title: "Could not install update",
description: error instanceof Error ? error.message : "An unexpected error occurred.",
});
});
}
}, [desktopUpdateButtonAction, desktopUpdateButtonDisabled, desktopUpdateState]);

const expandThreadListForProject = useCallback((projectId: ProjectId) => {
setExpandedThreadListsByProject((current) => {
if (current.has(projectId)) return current;
Expand Down Expand Up @@ -1136,25 +1002,6 @@ export default function Sidebar() {
<>
<SidebarHeader className="drag-region h-[52px] flex-row items-center gap-2 px-4 py-0 pl-[90px]">
{wordmark}
{showDesktopUpdateButton && (
<Tooltip>
<TooltipTrigger
render={
<button
type="button"
aria-label={desktopUpdateTooltip}
aria-disabled={desktopUpdateButtonDisabled || undefined}
disabled={desktopUpdateButtonDisabled}
className={`inline-flex size-7 ml-auto mt-1.5 items-center justify-center rounded-md text-muted-foreground transition-colors ${desktopUpdateButtonInteractivityClasses} ${desktopUpdateButtonClasses}`}
onClick={handleDesktopUpdateButtonClick}
>
<RocketIcon className="size-3.5" />
</button>
}
/>
<TooltipPopup side="bottom">{desktopUpdateTooltip}</TooltipPopup>
</Tooltip>
)}
</SidebarHeader>
</>
) : (
Expand All @@ -1164,29 +1011,6 @@ export default function Sidebar() {
)}

<SidebarContent className="gap-0">
{showArm64IntelBuildWarning && arm64IntelBuildWarningDescription ? (
<SidebarGroup className="px-2 pt-2 pb-0">
<Alert variant="warning" className="rounded-2xl border-warning/40 bg-warning/8">
<TriangleAlertIcon />
<AlertTitle>Intel build on Apple Silicon</AlertTitle>
<AlertDescription>{arm64IntelBuildWarningDescription}</AlertDescription>
{desktopUpdateButtonAction !== "none" ? (
<AlertAction>
<Button
size="xs"
variant="outline"
disabled={desktopUpdateButtonDisabled}
onClick={handleDesktopUpdateButtonClick}
>
{desktopUpdateButtonAction === "download"
? "Download ARM build"
: "Install ARM build"}
</Button>
</AlertAction>
) : null}
</Alert>
</SidebarGroup>
) : null}
<SidebarGroup className="px-2 py-2">
<div className="mb-1 flex items-center justify-between px-2">
<span className="text-[10px] font-medium uppercase tracking-wider text-muted-foreground/60">
Expand Down Expand Up @@ -1610,6 +1434,7 @@ export default function Sidebar() {

<SidebarSeparator />
<SidebarFooter className="p-2">
<SidebarUpdatePill />
<SidebarMenu>
<SidebarMenuItem>
{isOnSettings ? (
Expand Down
Loading