mirror of
https://github.com/siteboon/claudecodeui.git
synced 2026-05-01 18:28:38 +00:00
Create command palette and add new features for search and actions (#728)
* refactor(ui): replace in-repo Command primitive with cmdk wrapper * feat(command-palette): add global Cmd+K palette with v1 actions * feat(command-palette): add session, file, and commit search sources * refactor: add provider names to model constants * feat(command-palette): add settings, navigation, message search, and ⌘K hints * feat(command-palette): add git fetch/pull/push and branch switch actions * refactor(command-palette): consolidate fetch source hooks behind useApiSource * refactor(command-palette): extract useCommandKey and SETTINGS_MAIN_TABS metadata * refactor(command-palette): extract groups into declarative registry * refactor(command-palette): wire openFile through PaletteOpsContext * refactor: migrate openSettings and refreshProjects from window.* to PaletteOpsContext * refactor(command-palette): inline groups and delete registry indirection * refactor(command-palette): return items array directly from source hooks * refactor(palette-ops): flatten Handle wrapper into ref-based registry * refactor: inline useCommandKey as MOD_KEY constant in two call sites * feat: introduce pages and fix bug on branch switching * fix: small labels * fix: coderabbit issues * fix: coderabbit comments * Update src/components/chat/view/subcomponents/ProviderSelectionEmptyState.tsx Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> --------- Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
This commit is contained in:
@@ -1,5 +1,6 @@
|
||||
import { useEffect, useRef } from 'react';
|
||||
import type { Dispatch, MutableRefObject, SetStateAction } from 'react';
|
||||
import { usePaletteOps } from '../../../contexts/PaletteOpsContext';
|
||||
import type { PendingPermissionRequest } from '../types/types';
|
||||
import type { Project, ProjectSession, LLMProvider } from '../../../types/app';
|
||||
import type { SessionStore, NormalizedMessage } from '../../../stores/useSessionStore';
|
||||
@@ -99,6 +100,7 @@ export function useChatRealtimeHandlers({
|
||||
onWebSocketReconnect,
|
||||
sessionStore,
|
||||
}: UseChatRealtimeHandlersArgs) {
|
||||
const paletteOps = usePaletteOps();
|
||||
const lastProcessedMessageRef = useRef<LatestChatMessage | null>(null);
|
||||
|
||||
useEffect(() => {
|
||||
@@ -280,9 +282,7 @@ export function useChatRealtimeHandlers({
|
||||
onNavigateToSession?.(actualId);
|
||||
}
|
||||
sessionStorage.removeItem('pendingSessionId');
|
||||
if (window.refreshProjects) {
|
||||
setTimeout(() => window.refreshProjects?.(), 500);
|
||||
}
|
||||
setTimeout(() => { void paletteOps.refreshProjects(); }, 500);
|
||||
}
|
||||
break;
|
||||
}
|
||||
@@ -365,5 +365,6 @@ export function useChatRealtimeHandlers({
|
||||
onNavigateToSession,
|
||||
onWebSocketReconnect,
|
||||
sessionStore,
|
||||
paletteOps,
|
||||
]);
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import React, { useCallback, useEffect, useMemo, useState } from "react";
|
||||
import { Check, ChevronDown } from "lucide-react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { Trans, useTranslation } from "react-i18next";
|
||||
|
||||
import { useServerPlatform } from "../../../../hooks/useServerPlatform";
|
||||
import SessionProviderLogo from "../../../llm-logo-provider/SessionProviderLogo";
|
||||
@@ -9,6 +9,7 @@ import {
|
||||
CURSOR_MODELS,
|
||||
CODEX_MODELS,
|
||||
GEMINI_MODELS,
|
||||
PROVIDERS,
|
||||
} from "../../../../../shared/modelConstants";
|
||||
import type { ProjectSession, LLMProvider } from "../../../../types/app";
|
||||
import { NextTaskBanner } from "../../../task-master";
|
||||
@@ -26,6 +27,9 @@ import {
|
||||
Card,
|
||||
} from "../../../../shared/view/ui";
|
||||
|
||||
const MOD_KEY =
|
||||
typeof navigator !== "undefined" && /Mac|iPhone|iPad/.test(navigator.platform) ? "⌘" : "Ctrl";
|
||||
|
||||
type ProviderSelectionEmptyStateProps = {
|
||||
selectedSession: ProjectSession | null;
|
||||
currentSessionId: string | null;
|
||||
@@ -52,12 +56,11 @@ type ProviderGroup = {
|
||||
models: { value: string; label: string }[];
|
||||
};
|
||||
|
||||
const PROVIDER_GROUPS: ProviderGroup[] = [
|
||||
{ id: "claude", name: "Anthropic", models: CLAUDE_MODELS.OPTIONS },
|
||||
{ id: "cursor", name: "Cursor", models: CURSOR_MODELS.OPTIONS },
|
||||
{ id: "codex", name: "OpenAI", models: CODEX_MODELS.OPTIONS },
|
||||
{ id: "gemini", name: "Google", models: GEMINI_MODELS.OPTIONS },
|
||||
];
|
||||
const PROVIDER_GROUPS: ProviderGroup[] = PROVIDERS.map((p) => ({
|
||||
id: p.id as LLMProvider,
|
||||
name: p.name,
|
||||
models: p.models.OPTIONS,
|
||||
}));
|
||||
|
||||
function getModelConfig(p: LLMProvider) {
|
||||
if (p === "claude") return CLAUDE_MODELS;
|
||||
@@ -231,9 +234,14 @@ export default function ProviderSelectionEmptyState({
|
||||
defaultValue: "No models found.",
|
||||
})}
|
||||
</CommandEmpty>
|
||||
{visibleProviderGroups.map((group) => (
|
||||
{visibleProviderGroups.map((group, idx) => (
|
||||
<CommandGroup
|
||||
key={group.id}
|
||||
className={
|
||||
idx > 0
|
||||
? "border-t border-border/40 [&_[cmdk-group-heading]]:mt-1 [&_[cmdk-group-heading]]:uppercase [&_[cmdk-group-heading]]:tracking-wider"
|
||||
: "[&_[cmdk-group-heading]]:uppercase [&_[cmdk-group-heading]]:tracking-wider"
|
||||
}
|
||||
heading={
|
||||
<span className="flex items-center gap-1.5">
|
||||
<SessionProviderLogo provider={group.id} className="h-3.5 w-3.5 shrink-0" />
|
||||
@@ -248,6 +256,7 @@ export default function ProviderSelectionEmptyState({
|
||||
key={`${group.id}-${model.value}`}
|
||||
value={`${group.name} ${model.label}`}
|
||||
onSelect={() => handleModelSelect(group.id, model.value)}
|
||||
className="ml-4 border-l border-border/40 pl-4"
|
||||
>
|
||||
<span className="flex-1 truncate">{model.label}</span>
|
||||
{isSelected && (
|
||||
@@ -282,6 +291,18 @@ export default function ProviderSelectionEmptyState({
|
||||
}
|
||||
</p>
|
||||
|
||||
<p className="mt-3 flex items-center justify-center gap-1.5 text-center text-xs text-muted-foreground/60">
|
||||
<Trans
|
||||
i18nKey="providerSelection.pressToSearch"
|
||||
values={{ shortcut: MOD_KEY === "⌘" ? "⌘K" : "Ctrl+K" }}
|
||||
components={{
|
||||
kbd: (
|
||||
<kbd className="inline-flex items-center gap-0.5 rounded border border-border/60 bg-muted/40 px-1.5 py-0.5 font-mono text-[10px]" />
|
||||
),
|
||||
}}
|
||||
/>
|
||||
</p>
|
||||
|
||||
{provider && tasksEnabled && isTaskMasterInstalled && (
|
||||
<div className="mt-5">
|
||||
<NextTaskBanner
|
||||
|
||||
Reference in New Issue
Block a user