@@ -165,7 +151,7 @@ function InputToolbar(props: InputToolbarProps) {
{!props.toolbarOptions?.hideUseCodebase && !isInEditMode && (
@@ -235,7 +221,7 @@ function InputToolbar(props: InputToolbarProps) {
⏎
-
+
>
);
}
diff --git a/gui/src/components/mainInput/InputToolbar/bottom/PopoverTransition.tsx b/gui/src/components/mainInput/InputToolbar/bottom/PopoverTransition.tsx
deleted file mode 100644
index 24b64c27ba..0000000000
--- a/gui/src/components/mainInput/InputToolbar/bottom/PopoverTransition.tsx
+++ /dev/null
@@ -1,26 +0,0 @@
-import { Transition } from "@headlessui/react";
-
-export default function PopoverTransition({
- children,
- show,
- afterLeave,
-}: {
- children: React.ReactNode;
- show?: boolean;
- afterLeave?: () => void;
-}) {
- return (
-
- {children}
-
- );
-}
diff --git a/gui/src/components/mainInput/InputToolbar/bottom/ToolDropdownItem.tsx b/gui/src/components/mainInput/InputToolbar/bottom/ToolDropdownItem.tsx
index ca423764b8..7c838adf32 100644
--- a/gui/src/components/mainInput/InputToolbar/bottom/ToolDropdownItem.tsx
+++ b/gui/src/components/mainInput/InputToolbar/bottom/ToolDropdownItem.tsx
@@ -66,7 +66,7 @@ function ToolDropdownItem(props: ToolDropdownItemProps) {
>
) : null}
-
+
{props.tool.faviconUrl && (
-
+
{!isStreaming && (
)}
diff --git a/gui/src/components/mainInput/Lump/sections/docs/DocsDetailsDialog.tsx b/gui/src/components/mainInput/Lump/sections/docs/DocsDetailsDialog.tsx
index df07aafee8..3c91946b35 100644
--- a/gui/src/components/mainInput/Lump/sections/docs/DocsDetailsDialog.tsx
+++ b/gui/src/components/mainInput/Lump/sections/docs/DocsDetailsDialog.tsx
@@ -99,7 +99,7 @@ function DocsDetailsDialog({ startUrl }: DocsDetailsDialogProps) {
data-tooltip-id={contentToolTipId}
data-tooltip-delay-show={500}
>
-
+
{chunk.content}
diff --git a/gui/src/components/mainInput/Lump/sections/docs/DocsIndexingStatus.tsx b/gui/src/components/mainInput/Lump/sections/docs/DocsIndexingStatus.tsx
index 40b8c39cd4..6a4215c2ec 100644
--- a/gui/src/components/mainInput/Lump/sections/docs/DocsIndexingStatus.tsx
+++ b/gui/src/components/mainInput/Lump/sections/docs/DocsIndexingStatus.tsx
@@ -135,7 +135,7 @@ function DocsIndexingStatus({
style={{
fontSize: fontSize(-3),
}}
- className={`lines lines-1 m-0 p-0 text-left ${status?.url ? "cursor-pointer hover:underline" : ""}`}
+ className={`m-0 line-clamp-1 p-0 text-left ${status?.url ? "cursor-pointer hover:underline" : ""}`}
>
{docConfig.title ?? docConfig.startUrl}
diff --git a/gui/src/components/mainInput/tiptap/TipTapEditor.tsx b/gui/src/components/mainInput/tiptap/TipTapEditor.tsx
index 722cb007c9..cef58128e5 100644
--- a/gui/src/components/mainInput/tiptap/TipTapEditor.tsx
+++ b/gui/src/components/mainInput/tiptap/TipTapEditor.tsx
@@ -75,6 +75,9 @@ function TipTapEditor(props: TipTapEditorProps) {
}, [editor, props.placeholder, historyLength]);
useEffect(() => {
+ if (isInEditMode) {
+ setShouldHideToolbar(false);
+ }
if (props.isMainInput) {
editor?.commands.clearContent(true);
}
@@ -155,14 +158,19 @@ function TipTapEditor(props: TipTapEditorProps) {
const handleBlur = (e: React.FocusEvent) => {
// Check if the new focus target is within our InputBoxDiv
- const currentTarget = e.currentTarget;
- const relatedTarget = e.relatedTarget as Node | null;
+ queueMicrotask(() => {
+ if (isInEditMode) {
+ return;
+ }
+ const currentTarget = e.currentTarget;
+ const relatedTarget = e.relatedTarget as Node | null;
- if (relatedTarget && currentTarget.contains(relatedTarget)) {
- return;
- }
+ if (relatedTarget && currentTarget.contains(relatedTarget)) {
+ return;
+ }
- setShouldHideToolbar(true);
+ setShouldHideToolbar(true);
+ });
};
return (
diff --git a/gui/src/components/modelSelection/ModeSelect.tsx b/gui/src/components/modelSelection/ModeSelect.tsx
index efb670ae68..622c56838e 100644
--- a/gui/src/components/modelSelection/ModeSelect.tsx
+++ b/gui/src/components/modelSelection/ModeSelect.tsx
@@ -1,5 +1,4 @@
// A dropdown menu for selecting between Chat, Edit, and Agent modes with keyboard shortcuts
-import { Listbox } from "@headlessui/react";
import {
ChatBubbleLeftIcon,
CheckIcon,
@@ -11,7 +10,7 @@ import { MessageModes } from "core";
import { modelSupportsTools } from "core/llm/autodetect";
import { useEffect, useMemo } from "react";
import styled from "styled-components";
-import { defaultBorderRadius, lightGray, vscInputBackground } from "..";
+import { lightGray } from "..";
import { useAppDispatch, useAppSelector } from "../../redux/hooks";
import { selectDefaultModel } from "../../redux/slices/configSlice";
import {
@@ -19,57 +18,18 @@ import {
selectCurrentMode,
setMode,
} from "../../redux/slices/sessionSlice";
+import { exitEditMode } from "../../redux/thunks";
import {
- fontSize,
- getFontSize,
- getMetaKeyLabel,
- isJetBrains,
-} from "../../util";
-import Shortcut from "../gui/Shortcut";
-
-const StyledListboxButton = styled(Listbox.Button)`
- font-family: inherit;
- display: flex;
- align-items: center;
- gap: 2px;
- border: none;
- cursor: pointer;
- font-size: ${getFontSize() - 2}px;
- background: transparent;
- color: ${lightGray};
- &:focus {
- outline: none;
- }
-`;
-
-const StyledListboxOptions = styled(Listbox.Options)`
- margin-top: 4px;
- position: absolute;
- list-style: none;
- padding: 0px;
- min-width: 180px;
- cursor: default;
- display: flex;
- flex-direction: column;
- border-radius: ${defaultBorderRadius};
- border: 0.5px solid ${lightGray};
- background-color: ${vscInputBackground};
-`;
-
-const StyledListboxOption = styled(Listbox.Option)`
- border-radius: ${defaultBorderRadius};
- padding: 6px 12px;
- cursor: ${(props) => (props.disabled ? "not-allowed" : "pointer")};
- display: flex;
- align-items: center;
- gap: 8px;
- opacity: ${(props) => (props.disabled ? 0.5 : 1)};
-
- &:hover {
- background: ${(props) =>
- props.disabled ? "transparent" : `${lightGray}33`};
- }
-`;
+ loadLastSession,
+ saveCurrentSession,
+} from "../../redux/thunks/session";
+import { getFontSize, getMetaKeyLabel, isJetBrains } from "../../util";
+import {
+ Listbox,
+ ListboxButton,
+ ListboxOption,
+ ListboxOptions,
+} from "../ui/Listbox";
const ShortcutText = styled.span`
color: ${lightGray};
@@ -93,11 +53,11 @@ function ModeSelect() {
const getModeIcon = (mode: MessageModes) => {
switch (mode) {
case "agent":
- return ;
+ return ;
case "chat":
- return ;
+ return ;
case "edit":
- return ;
+ return ;
}
};
@@ -123,67 +83,79 @@ function ModeSelect() {
return (
{
+ onChange={async (newMode) => {
+ if (newMode === mode) {
+ return;
+ }
dispatch(setMode(newMode));
+ if (newMode === "edit") {
+ await dispatch(
+ saveCurrentSession({
+ generateTitle: false,
+ openNewSession: true,
+ }),
+ );
+ } else if (mode === "edit") {
+ await dispatch(
+ loadLastSession({
+ saveCurrentSession: false,
+ }),
+ );
+ dispatch(exitEditMode());
+ }
}}
>
-
-
- {getModeIcon(mode)}
-
- {mode.charAt(0).toUpperCase() + mode.slice(1)}
-
-
-
-
-
-
-
- Agent
- {/* */}
+ {getModeIcon(mode)}
+
+ {mode.charAt(0).toUpperCase() + mode.slice(1)}
+
+
+
+
+
+
+
+ Agent
+
{mode === "agent" && }
{!agentModeSupported && (Not supported)}
-
-
-
-
- Chat
- {metaKeyLabel}L
+
+
+
+
+
+ Chat
+ {getMetaKeyLabel()}L
+
{mode === "chat" && }
-
+
{!jetbrains && (
-
-
- Edit
- {metaKeyLabel}I
+
+
+
+
Edit
+
{getMetaKeyLabel()}I
+
{mode === "edit" && }
-
+
)}
- {metaKeyLabel}
- . for next mode
+ {metaKeyLabel}. for next mode
-
+
);
diff --git a/gui/src/components/modelSelection/ModelSelect.tsx b/gui/src/components/modelSelection/ModelSelect.tsx
index 437e2304ff..4c2e313878 100644
--- a/gui/src/components/modelSelection/ModelSelect.tsx
+++ b/gui/src/components/modelSelection/ModelSelect.tsx
@@ -1,4 +1,3 @@
-import { Listbox } from "@headlessui/react";
import {
CheckIcon,
ChevronDownIcon,
@@ -9,7 +8,7 @@ import {
import { useContext, useEffect, useRef, useState } from "react";
import { useDispatch } from "react-redux";
import styled from "styled-components";
-import { defaultBorderRadius, lightGray, vscInputBackground } from "..";
+import { defaultBorderRadius, lightGray } from "..";
import { useAuth } from "../../context/Auth";
import { IdeMessengerContext } from "../../context/IdeMessenger";
import AddModelForm from "../../forms/AddModelForm";
@@ -19,9 +18,8 @@ import {
setDefaultModel,
} from "../../redux/slices/configSlice";
import { setDialogMessage, setShowDialog } from "../../redux/slices/uiSlice";
-import { fontSize, isMetaEquivalentKeyPressed } from "../../util";
-import Shortcut from "../gui/Shortcut";
-import { Divider } from "./platform/shared";
+import { getMetaKeyLabel, isMetaEquivalentKeyPressed } from "../../util";
+import { Listbox, ListboxButton, ListboxOption, ListboxOptions } from "../ui";
interface ModelOptionProps {
option: Option;
@@ -36,68 +34,6 @@ interface Option {
apiKey?: string;
}
-const MAX_HEIGHT_PX = 300;
-
-const StyledListboxButton = styled(Listbox.Button)`
- font-family: inherit;
- display: flex;
- align-items: center;
- gap: 2px;
- border: none;
- cursor: pointer;
- font-size: ${fontSize(-3)};
- background: transparent;
- color: ${lightGray};
- &:focus {
- outline: none;
- }
-`;
-
-const StyledListboxOptions = styled(Listbox.Options)<{ $showabove: boolean }>`
- margin-top: 4px;
- position: absolute;
- list-style: none;
- padding: 0px;
- white-space: nowrap;
- cursor: default;
-
- display: flex;
- flex-direction: column;
-
- font-size: ${fontSize(-3)};
- border-radius: ${defaultBorderRadius};
- border: 0.5px solid ${lightGray};
- background-color: ${vscInputBackground};
-
- max-height: ${MAX_HEIGHT_PX}px;
- overflow-y: scroll;
-
- scrollbar-width: none;
-
- ${(props) => (props.$showabove ? "bottom: 100%;" : "top: 100%;")}
-`;
-
-const StyledListboxOption = styled(Listbox.Option)<{ isDisabled?: boolean }>`
- border-radius: ${defaultBorderRadius};
- padding: 4px 12px;
-
- ${({ isDisabled }) =>
- !isDisabled &&
- `
- cursor: pointer;
-
- &:hover {
- background: ${lightGray}33;
- }
- `}
-
- ${({ isDisabled }) =>
- isDisabled &&
- `
- opacity: 0.5;
- `}
-`;
-
const IconBase = styled.div<{ $hovered: boolean }>`
width: 1.2em;
height: 1.2em;
@@ -113,8 +49,6 @@ const IconBase = styled.div<{ $hovered: boolean }>`
}
`;
-const StyledCog6ToothIcon = styled(IconBase).attrs({ as: Cog6ToothIcon })``;
-
function modelSelectTitle(model: any): string {
if (model?.title) return model?.title;
if (model?.model !== undefined && model?.model.trim() !== "") {
@@ -151,19 +85,19 @@ function ModelOption({
}
return (
- setHovered(true)}
onMouseLeave={() => setHovered(false)}
onClick={handleOptionClick}
>
-
-
-
-
-
+
+
+
+
+
{option.title}
{showMissingApiKeyMsg && (
@@ -172,13 +106,18 @@ function ModelOption({
)}
-
-
- {isSelected &&
}
+
+ {isSelected && }
+ {hovered && (
+
+ )}
-
+
);
}
@@ -186,7 +125,6 @@ function ModelSelect() {
const dispatch = useDispatch();
const defaultModel = useAppSelector(selectDefaultModel);
const allModels = useAppSelector((state) => state.config.config.models);
- const [showAbove, setShowAbove] = useState(false);
const buttonRef = useRef
(null);
const [options, setOptions] = useState