Merge branch 'main' into set-header

This commit is contained in:
Ido Salomon
2025-04-12 03:37:18 +03:00
committed by GitHub
7 changed files with 45 additions and 37 deletions

View File

@@ -447,7 +447,13 @@ const Sidebar = ({
<div className="space-y-2"> <div className="space-y-2">
{connectionStatus === "connected" && ( {connectionStatus === "connected" && (
<div className="grid grid-cols-2 gap-4"> <div className="grid grid-cols-2 gap-4">
<Button data-testid="connect-button" onClick={onConnect}> <Button
data-testid="connect-button"
onClick={() => {
onDisconnect();
onConnect();
}}
>
<RotateCcw className="w-4 h-4 mr-2" /> <RotateCcw className="w-4 h-4 mr-2" />
{transportType === "stdio" ? "Restart" : "Reconnect"} {transportType === "stdio" ? "Restart" : "Reconnect"}
</Button> </Button>

View File

@@ -54,4 +54,4 @@ const Button = React.forwardRef<HTMLButtonElement, ButtonProps>(
); );
Button.displayName = "Button"; Button.displayName = "Button";
export { Button, buttonVariants }; export { Button };

View File

@@ -2,8 +2,7 @@ import * as React from "react";
import { cn } from "@/lib/utils"; import { cn } from "@/lib/utils";
export interface InputProps export type InputProps = React.InputHTMLAttributes<HTMLInputElement>;
extends React.InputHTMLAttributes<HTMLInputElement> {}
const Input = React.forwardRef<HTMLInputElement, InputProps>( const Input = React.forwardRef<HTMLInputElement, InputProps>(
({ className, type, ...props }, ref) => { ({ className, type, ...props }, ref) => {

View File

@@ -2,8 +2,7 @@ import * as React from "react";
import { cn } from "@/lib/utils"; import { cn } from "@/lib/utils";
export interface TextareaProps export type TextareaProps = React.TextareaHTMLAttributes<HTMLTextAreaElement>;
extends React.TextareaHTMLAttributes<HTMLTextAreaElement> {}
const Textarea = React.forwardRef<HTMLTextAreaElement, TextareaProps>( const Textarea = React.forwardRef<HTMLTextAreaElement, TextareaProps>(
({ className, ...props }, ref) => { ({ className, ...props }, ref) => {

View File

@@ -15,13 +15,6 @@ type ToasterToast = ToastProps & {
action?: ToastActionElement; action?: ToastActionElement;
}; };
const actionTypes = {
ADD_TOAST: "ADD_TOAST",
UPDATE_TOAST: "UPDATE_TOAST",
DISMISS_TOAST: "DISMISS_TOAST",
REMOVE_TOAST: "REMOVE_TOAST",
} as const;
let count = 0; let count = 0;
function genId() { function genId() {
@@ -29,23 +22,28 @@ function genId() {
return count.toString(); return count.toString();
} }
type ActionType = typeof actionTypes; const enum ActionType {
ADD_TOAST = "ADD_TOAST",
UPDATE_TOAST = "UPDATE_TOAST",
DISMISS_TOAST = "DISMISS_TOAST",
REMOVE_TOAST = "REMOVE_TOAST",
}
type Action = type Action =
| { | {
type: ActionType["ADD_TOAST"]; type: ActionType.ADD_TOAST;
toast: ToasterToast; toast: ToasterToast;
} }
| { | {
type: ActionType["UPDATE_TOAST"]; type: ActionType.UPDATE_TOAST;
toast: Partial<ToasterToast>; toast: Partial<ToasterToast>;
} }
| { | {
type: ActionType["DISMISS_TOAST"]; type: ActionType.DISMISS_TOAST;
toastId?: ToasterToast["id"]; toastId?: ToasterToast["id"];
} }
| { | {
type: ActionType["REMOVE_TOAST"]; type: ActionType.REMOVE_TOAST;
toastId?: ToasterToast["id"]; toastId?: ToasterToast["id"];
}; };
@@ -63,7 +61,7 @@ const addToRemoveQueue = (toastId: string) => {
const timeout = setTimeout(() => { const timeout = setTimeout(() => {
toastTimeouts.delete(toastId); toastTimeouts.delete(toastId);
dispatch({ dispatch({
type: "REMOVE_TOAST", type: ActionType.REMOVE_TOAST,
toastId: toastId, toastId: toastId,
}); });
}, TOAST_REMOVE_DELAY); }, TOAST_REMOVE_DELAY);
@@ -73,13 +71,13 @@ const addToRemoveQueue = (toastId: string) => {
export const reducer = (state: State, action: Action): State => { export const reducer = (state: State, action: Action): State => {
switch (action.type) { switch (action.type) {
case "ADD_TOAST": case ActionType.ADD_TOAST:
return { return {
...state, ...state,
toasts: [action.toast, ...state.toasts].slice(0, TOAST_LIMIT), toasts: [action.toast, ...state.toasts].slice(0, TOAST_LIMIT),
}; };
case "UPDATE_TOAST": case ActionType.UPDATE_TOAST:
return { return {
...state, ...state,
toasts: state.toasts.map((t) => toasts: state.toasts.map((t) =>
@@ -87,7 +85,7 @@ export const reducer = (state: State, action: Action): State => {
), ),
}; };
case "DISMISS_TOAST": { case ActionType.DISMISS_TOAST: {
const { toastId } = action; const { toastId } = action;
// ! Side effects ! - This could be extracted into a dismissToast() action, // ! Side effects ! - This could be extracted into a dismissToast() action,
@@ -112,7 +110,7 @@ export const reducer = (state: State, action: Action): State => {
), ),
}; };
} }
case "REMOVE_TOAST": case ActionType.REMOVE_TOAST:
if (action.toastId === undefined) { if (action.toastId === undefined) {
return { return {
...state, ...state,
@@ -144,13 +142,14 @@ function toast({ ...props }: Toast) {
const update = (props: ToasterToast) => const update = (props: ToasterToast) =>
dispatch({ dispatch({
type: "UPDATE_TOAST", type: ActionType.UPDATE_TOAST,
toast: { ...props, id }, toast: { ...props, id },
}); });
const dismiss = () => dispatch({ type: "DISMISS_TOAST", toastId: id }); const dismiss = () =>
dispatch({ type: ActionType.DISMISS_TOAST, toastId: id });
dispatch({ dispatch({
type: "ADD_TOAST", type: ActionType.ADD_TOAST,
toast: { toast: {
...props, ...props,
id, id,
@@ -184,7 +183,8 @@ function useToast() {
return { return {
...state, ...state,
toast, toast,
dismiss: (toastId?: string) => dispatch({ type: "DISMISS_TOAST", toastId }), dismiss: (toastId?: string) =>
dispatch({ type: ActionType.DISMISS_TOAST, toastId }),
}; };
} }

View File

@@ -1,4 +1,4 @@
import { useState, useCallback, useEffect, useRef } from "react"; import { useState, useCallback, useEffect, useRef, useMemo } from "react";
import { import {
ResourceReference, ResourceReference,
PromptReference, PromptReference,
@@ -15,9 +15,11 @@ function debounce<T extends (...args: any[]) => PromiseLike<void>>(
wait: number, wait: number,
): (...args: Parameters<T>) => void { ): (...args: Parameters<T>) => void {
let timeout: ReturnType<typeof setTimeout>; let timeout: ReturnType<typeof setTimeout>;
return function (...args: Parameters<T>) { return (...args: Parameters<T>) => {
clearTimeout(timeout); clearTimeout(timeout);
timeout = setTimeout(() => func(...args), wait); timeout = setTimeout(() => {
void func(...args);
}, wait);
}; };
} }
@@ -58,8 +60,8 @@ export function useCompletionState(
}); });
}, [cleanup]); }, [cleanup]);
const requestCompletions = useCallback( const requestCompletions = useMemo(() => {
debounce( return debounce(
async ( async (
ref: ResourceReference | PromptReference, ref: ResourceReference | PromptReference,
argName: string, argName: string,
@@ -94,7 +96,7 @@ export function useCompletionState(
loading: { ...prev.loading, [argName]: false }, loading: { ...prev.loading, [argName]: false },
})); }));
} }
} catch (err) { } catch {
if (!abortController.signal.aborted) { if (!abortController.signal.aborted) {
setState((prev) => ({ setState((prev) => ({
...prev, ...prev,
@@ -108,9 +110,8 @@ export function useCompletionState(
} }
}, },
debounceMs, debounceMs,
), );
[handleCompletion, completionsSupported, cleanup, debounceMs], }, [handleCompletion, completionsSupported, cleanup, debounceMs]);
);
// Clear completions when support status changes // Clear completions when support status changes
useEffect(() => { useEffect(() => {

View File

@@ -43,7 +43,10 @@ const useTheme = (): [Theme, (mode: Theme) => void] => {
document.documentElement.classList.toggle("dark", newTheme === "dark"); document.documentElement.classList.toggle("dark", newTheme === "dark");
} }
}, []); }, []);
return useMemo(() => [theme, setThemeWithSideEffect], [theme]); return useMemo(
() => [theme, setThemeWithSideEffect],
[theme, setThemeWithSideEffect],
);
}; };
export default useTheme; export default useTheme;