From 832d10e133f7cf83e2d5321740f757c14601b2d4 Mon Sep 17 00:00:00 2001 From: webdevcody Date: Sat, 17 Jan 2026 17:58:16 -0500 Subject: [PATCH 1/3] refactor: replace Loader2 with Spinner component across the application This update standardizes the loading indicators by replacing all instances of Loader2 with the new Spinner component. The Spinner component provides a consistent look and feel for loading states throughout the UI, enhancing the user experience. Changes include: - Updated loading indicators in various components such as popovers, modals, and views. - Ensured that the Spinner component is used with appropriate sizes for different contexts. No functional changes were made; this is purely a visual and structural improvement. --- .../src/components/claude-usage-popover.tsx | 3 +- .../ui/src/components/codex-usage-popover.tsx | 3 +- .../dialogs/board-background-modal.tsx | 7 ++-- .../components/dialogs/new-project-modal.tsx | 14 ++----- .../dialogs/workspace-picker-modal.tsx | 5 ++- .../sidebar/components/sidebar-navigation.tsx | 7 ++-- apps/ui/src/components/session-manager.tsx | 4 +- apps/ui/src/components/ui/button.tsx | 4 +- .../ui/description-image-dropzone.tsx | 5 ++- .../components/ui/feature-image-upload.tsx | 5 ++- apps/ui/src/components/ui/git-diff-panel.tsx | 4 +- apps/ui/src/components/ui/image-drop-zone.tsx | 5 ++- apps/ui/src/components/ui/loading-state.tsx | 10 ++--- apps/ui/src/components/ui/log-viewer.tsx | 4 +- apps/ui/src/components/ui/spinner.tsx | 32 +++++++++++++++ .../src/components/ui/task-progress-panel.tsx | 5 ++- apps/ui/src/components/usage-popover.tsx | 5 ++- .../src/components/views/agent-tools-view.tsx | 8 ++-- .../components/thinking-indicator.tsx | 16 +------- .../ui/src/components/views/analysis-view.tsx | 10 ++--- apps/ui/src/components/views/board-view.tsx | 4 +- .../views/board-view/board-search-bar.tsx | 5 ++- .../kanban-card/agent-info-panel.tsx | 14 ++----- .../components/kanban-card/card-header.tsx | 6 +-- .../board-view/dialogs/agent-output-modal.tsx | 9 +++-- .../dialogs/backlog-plan-dialog.tsx | 19 +++------ .../dialogs/commit-worktree-dialog.tsx | 5 ++- .../dialogs/create-branch-dialog.tsx | 5 ++- .../board-view/dialogs/create-pr-dialog.tsx | 5 ++- .../dialogs/create-worktree-dialog.tsx | 5 ++- .../dialogs/delete-worktree-dialog.tsx | 5 ++- .../dialogs/merge-worktree-dialog.tsx | 5 ++- .../dialogs/plan-approval-dialog.tsx | 7 ++-- .../board-view/init-script-indicator.tsx | 5 ++- .../views/board-view/mobile-usage-bar.tsx | 9 +++-- .../board-view/shared/model-selector.tsx | 4 +- .../shared/planning-mode-selector.tsx | 4 +- .../components/branch-switch-dropdown.tsx | 5 ++- .../components/dev-server-logs-panel.tsx | 8 ++-- .../components/worktree-mobile-dropdown.tsx | 7 ++-- .../components/worktree-tab.tsx | 11 ++--- .../worktree-panel/worktree-panel.tsx | 5 ++- apps/ui/src/components/views/code-view.tsx | 5 ++- apps/ui/src/components/views/context-view.tsx | 11 +++-- .../src/components/views/dashboard-view.tsx | 4 +- .../components/issue-detail-panel.tsx | 10 ++--- .../components/issue-row.tsx | 4 +- .../components/issues-list-header.tsx | 3 +- .../src/components/views/github-prs-view.tsx | 7 ++-- .../src/components/views/graph-view-page.tsx | 4 +- .../components/ideation-dashboard.tsx | 11 ++--- .../components/prompt-category-grid.tsx | 4 +- .../ideation-view/components/prompt-list.tsx | 7 ++-- .../components/views/ideation-view/index.tsx | 9 ++--- .../src/components/views/interview-view.tsx | 7 ++-- apps/ui/src/components/views/login-view.tsx | 9 +++-- apps/ui/src/components/views/memory-view.tsx | 3 +- .../components/views/notifications-view.tsx | 5 ++- .../worktree-preferences-section.tsx | 16 ++------ .../components/views/running-agents-view.tsx | 11 +++-- .../settings-view/account/account-section.tsx | 3 +- .../settings-view/api-keys/api-key-field.tsx | 5 ++- .../api-keys/api-keys-section.tsx | 7 ++-- .../api-keys/claude-usage-section.tsx | 3 +- .../cli-status/claude-cli-status.tsx | 3 +- .../cli-status/cli-status-card.tsx | 3 +- .../cli-status/codex-cli-status.tsx | 3 +- .../cli-status/cursor-cli-status.tsx | 3 +- .../cli-status/opencode-cli-status.tsx | 3 +- .../codex/codex-usage-section.tsx | 3 +- .../event-hooks/event-history-view.tsx | 7 +++- .../components/mcp-server-card.tsx | 5 ++- .../components/mcp-server-header.tsx | 3 +- .../views/settings-view/mcp-servers/utils.tsx | 5 ++- .../claude-settings-tab/subagents-section.tsx | 18 ++------- .../providers/cursor-permissions-section.tsx | 3 +- .../opencode-model-configuration.tsx | 5 ++- .../components/cli-installation-card.tsx | 5 ++- .../setup-view/components/status-badge.tsx | 5 ++- .../setup-view/steps/claude-setup-step.tsx | 22 +++++----- .../views/setup-view/steps/cli-setup-step.tsx | 22 +++++----- .../setup-view/steps/cursor-setup-step.tsx | 8 ++-- .../setup-view/steps/github-setup-step.tsx | 6 +-- .../setup-view/steps/opencode-setup-step.tsx | 8 ++-- .../setup-view/steps/providers-setup-step.tsx | 40 +++++++++---------- apps/ui/src/components/views/spec-view.tsx | 4 +- .../spec-view/components/spec-empty-state.tsx | 7 ++-- .../spec-view/components/spec-header.tsx | 9 +++-- .../spec-view/dialogs/create-spec-dialog.tsx | 5 ++- .../dialogs/regenerate-spec-dialog.tsx | 5 ++- .../ui/src/components/views/terminal-view.tsx | 6 +-- .../views/terminal-view/terminal-panel.tsx | 6 +-- apps/ui/src/components/views/welcome-view.tsx | 6 +-- 93 files changed, 351 insertions(+), 333 deletions(-) create mode 100644 apps/ui/src/components/ui/spinner.tsx diff --git a/apps/ui/src/components/claude-usage-popover.tsx b/apps/ui/src/components/claude-usage-popover.tsx index d51e316c..fa3d5c94 100644 --- a/apps/ui/src/components/claude-usage-popover.tsx +++ b/apps/ui/src/components/claude-usage-popover.tsx @@ -2,6 +2,7 @@ import { useState, useEffect, useMemo, useCallback } from 'react'; import { Popover, PopoverContent, PopoverTrigger } from '@/components/ui/popover'; import { Button } from '@/components/ui/button'; import { RefreshCw, AlertTriangle, CheckCircle, XCircle, Clock, ExternalLink } from 'lucide-react'; +import { Spinner } from '@/components/ui/spinner'; import { cn } from '@/lib/utils'; import { getElectronAPI } from '@/lib/electron'; import { useAppStore } from '@/store/app-store'; @@ -279,7 +280,7 @@ export function ClaudeUsagePopover() { ) : !claudeUsage ? ( // Loading state
- +

Loading usage data...

) : ( diff --git a/apps/ui/src/components/codex-usage-popover.tsx b/apps/ui/src/components/codex-usage-popover.tsx index f6005b6a..0fee4226 100644 --- a/apps/ui/src/components/codex-usage-popover.tsx +++ b/apps/ui/src/components/codex-usage-popover.tsx @@ -2,6 +2,7 @@ import { useState, useEffect, useMemo, useCallback } from 'react'; import { Popover, PopoverContent, PopoverTrigger } from '@/components/ui/popover'; import { Button } from '@/components/ui/button'; import { RefreshCw, AlertTriangle, CheckCircle, XCircle, Clock, ExternalLink } from 'lucide-react'; +import { Spinner } from '@/components/ui/spinner'; import { cn } from '@/lib/utils'; import { getElectronAPI } from '@/lib/electron'; import { useAppStore } from '@/store/app-store'; @@ -333,7 +334,7 @@ export function CodexUsagePopover() { ) : !codexUsage ? ( // Loading state
- +

Loading usage data...

) : codexUsage.rateLimits ? ( diff --git a/apps/ui/src/components/dialogs/board-background-modal.tsx b/apps/ui/src/components/dialogs/board-background-modal.tsx index 89ab44da..e381c366 100644 --- a/apps/ui/src/components/dialogs/board-background-modal.tsx +++ b/apps/ui/src/components/dialogs/board-background-modal.tsx @@ -1,6 +1,7 @@ import { useState, useRef, useCallback, useEffect } from 'react'; import { createLogger } from '@automaker/utils/logger'; -import { ImageIcon, Upload, Loader2, Trash2 } from 'lucide-react'; +import { ImageIcon, Upload, Trash2 } from 'lucide-react'; +import { Spinner } from '@/components/ui/spinner'; const logger = createLogger('BoardBackgroundModal'); import { @@ -313,7 +314,7 @@ export function BoardBackgroundModal({ open, onOpenChange }: BoardBackgroundModa /> {isProcessing && (
- +
)} @@ -353,7 +354,7 @@ export function BoardBackgroundModal({ open, onOpenChange }: BoardBackgroundModa )} > {isProcessing ? ( - + ) : ( )} diff --git a/apps/ui/src/components/dialogs/new-project-modal.tsx b/apps/ui/src/components/dialogs/new-project-modal.tsx index dd114bf9..55df0a1c 100644 --- a/apps/ui/src/components/dialogs/new-project-modal.tsx +++ b/apps/ui/src/components/dialogs/new-project-modal.tsx @@ -14,16 +14,8 @@ import { Input } from '@/components/ui/input'; import { Label } from '@/components/ui/label'; import { Tabs, TabsContent, TabsList, TabsTrigger } from '@/components/ui/tabs'; import { Badge } from '@/components/ui/badge'; -import { - FolderPlus, - FolderOpen, - Rocket, - ExternalLink, - Check, - Loader2, - Link, - Folder, -} from 'lucide-react'; +import { FolderPlus, FolderOpen, Rocket, ExternalLink, Check, Link, Folder } from 'lucide-react'; +import { Spinner } from '@/components/ui/spinner'; import { starterTemplates, type StarterTemplate } from '@/lib/templates'; import { getElectronAPI } from '@/lib/electron'; import { cn } from '@/lib/utils'; @@ -451,7 +443,7 @@ export function NewProjectModal({ > {isCreating ? ( <> - + {activeTab === 'template' ? 'Cloning...' : 'Creating...'} ) : ( diff --git a/apps/ui/src/components/dialogs/workspace-picker-modal.tsx b/apps/ui/src/components/dialogs/workspace-picker-modal.tsx index 4f287465..84e723fc 100644 --- a/apps/ui/src/components/dialogs/workspace-picker-modal.tsx +++ b/apps/ui/src/components/dialogs/workspace-picker-modal.tsx @@ -8,7 +8,8 @@ import { DialogTitle, } from '@/components/ui/dialog'; import { Button } from '@/components/ui/button'; -import { Folder, Loader2, FolderOpen, AlertCircle } from 'lucide-react'; +import { Folder, FolderOpen, AlertCircle } from 'lucide-react'; +import { Spinner } from '@/components/ui/spinner'; import { getHttpApiClient } from '@/lib/http-api-client'; interface WorkspaceDirectory { @@ -74,7 +75,7 @@ export function WorkspacePickerModal({ open, onOpenChange, onSelect }: Workspace
{isLoading && (
- +

Loading projects...

)} diff --git a/apps/ui/src/components/layout/sidebar/components/sidebar-navigation.tsx b/apps/ui/src/components/layout/sidebar/components/sidebar-navigation.tsx index 3cda8229..c4956159 100644 --- a/apps/ui/src/components/layout/sidebar/components/sidebar-navigation.tsx +++ b/apps/ui/src/components/layout/sidebar/components/sidebar-navigation.tsx @@ -1,9 +1,9 @@ import type { NavigateOptions } from '@tanstack/react-router'; -import { Loader2 } from 'lucide-react'; import { cn } from '@/lib/utils'; import { formatShortcut } from '@/store/app-store'; import type { NavSection } from '../types'; import type { Project } from '@/lib/electron'; +import { Spinner } from '@/components/ui/spinner'; interface SidebarNavigationProps { currentProject: Project | null; @@ -93,9 +93,10 @@ export function SidebarNavigation({ >
{item.isLoading ? ( - diff --git a/apps/ui/src/components/session-manager.tsx b/apps/ui/src/components/session-manager.tsx index 88c31acc..f0fa9a45 100644 --- a/apps/ui/src/components/session-manager.tsx +++ b/apps/ui/src/components/session-manager.tsx @@ -16,8 +16,8 @@ import { Check, X, ArchiveRestore, - Loader2, } from 'lucide-react'; +import { Spinner } from '@/components/ui/spinner'; import { cn } from '@/lib/utils'; import type { SessionListItem } from '@/types/electron'; import { useKeyboardShortcutsConfig } from '@/hooks/use-keyboard-shortcuts'; @@ -466,7 +466,7 @@ export function SessionManager({ {/* Show loading indicator if this session is running (either current session thinking or any session in runningSessions) */} {(currentSessionId === session.id && isCurrentSessionThinking) || runningSessions.has(session.id) ? ( - + ) : ( )} diff --git a/apps/ui/src/components/ui/button.tsx b/apps/ui/src/components/ui/button.tsx index fa970a52..a7163ed3 100644 --- a/apps/ui/src/components/ui/button.tsx +++ b/apps/ui/src/components/ui/button.tsx @@ -1,9 +1,9 @@ import * as React from 'react'; import { Slot } from '@radix-ui/react-slot'; import { cva, type VariantProps } from 'class-variance-authority'; -import { Loader2 } from 'lucide-react'; import { cn } from '@/lib/utils'; +import { Spinner } from '@/components/ui/spinner'; const buttonVariants = cva( "inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-md text-sm font-medium transition-all duration-200 cursor-pointer disabled:pointer-events-none disabled:opacity-50 disabled:cursor-not-allowed [&_svg]:pointer-events-none [&_svg:not([class*='size-'])]:size-4 shrink-0 [&_svg]:shrink-0 outline-none focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:ring-[3px] aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive active:scale-[0.98]", @@ -39,7 +39,7 @@ const buttonVariants = cva( // Loading spinner component function ButtonSpinner({ className }: { className?: string }) { - return
) : !claudeUsage ? (
- +

Loading usage data...

) : ( @@ -568,7 +569,7 @@ export function UsagePopover() {
) : !codexUsage ? (
- +

Loading usage data...

) : codexUsage.rateLimits ? ( diff --git a/apps/ui/src/components/views/agent-tools-view.tsx b/apps/ui/src/components/views/agent-tools-view.tsx index 4485f165..48c3f92d 100644 --- a/apps/ui/src/components/views/agent-tools-view.tsx +++ b/apps/ui/src/components/views/agent-tools-view.tsx @@ -11,12 +11,12 @@ import { Terminal, CheckCircle, XCircle, - Loader2, Play, File, Pencil, Wrench, } from 'lucide-react'; +import { Spinner } from '@/components/ui/spinner'; import { cn } from '@/lib/utils'; import { getElectronAPI } from '@/lib/electron'; @@ -236,7 +236,7 @@ export function AgentToolsView() { > {isReadingFile ? ( <> - + Reading... ) : ( @@ -315,7 +315,7 @@ export function AgentToolsView() { > {isWritingFile ? ( <> - + Writing... ) : ( @@ -383,7 +383,7 @@ export function AgentToolsView() { > {isRunningCommand ? ( <> - + Running... ) : ( diff --git a/apps/ui/src/components/views/agent-view/components/thinking-indicator.tsx b/apps/ui/src/components/views/agent-view/components/thinking-indicator.tsx index facd4fc5..ff2965d5 100644 --- a/apps/ui/src/components/views/agent-view/components/thinking-indicator.tsx +++ b/apps/ui/src/components/views/agent-view/components/thinking-indicator.tsx @@ -1,4 +1,5 @@ import { Bot } from 'lucide-react'; +import { Spinner } from '@/components/ui/spinner'; export function ThinkingIndicator() { return ( @@ -8,20 +9,7 @@ export function ThinkingIndicator() {
-
- - - -
+ Thinking...
diff --git a/apps/ui/src/components/views/analysis-view.tsx b/apps/ui/src/components/views/analysis-view.tsx index e235a9e9..2143d390 100644 --- a/apps/ui/src/components/views/analysis-view.tsx +++ b/apps/ui/src/components/views/analysis-view.tsx @@ -14,12 +14,12 @@ import { RefreshCw, BarChart3, FileCode, - Loader2, FileText, CheckCircle, AlertCircle, ListChecks, } from 'lucide-react'; +import { Spinner } from '@/components/ui/spinner'; import { cn, generateUUID } from '@/lib/utils'; const logger = createLogger('AnalysisView'); @@ -742,7 +742,7 @@ ${Object.entries(projectAnalysis.filesByExtension)
{children}
diff --git a/apps/ui/src/components/views/board-view/shared/model-selector.tsx b/apps/ui/src/components/views/board-view/shared/model-selector.tsx index 957fccc0..fb6deeae 100644 --- a/apps/ui/src/components/views/board-view/shared/model-selector.tsx +++ b/apps/ui/src/components/views/board-view/shared/model-selector.tsx @@ -11,7 +11,7 @@ import { getModelProvider, PROVIDER_PREFIXES, stripProviderPrefix } from '@autom import type { ModelProvider } from '@automaker/types'; import { CLAUDE_MODELS, CURSOR_MODELS, ModelOption } from './model-constants'; import { useEffect } from 'react'; -import { RefreshCw } from 'lucide-react'; +import { Spinner } from '@/components/ui/spinner'; interface ModelSelectorProps { selectedModel: string; // Can be ModelAlias or "cursor-{id}" @@ -294,7 +294,7 @@ export function ModelSelector({ {/* Loading state */} {codexModelsLoading && dynamicCodexModels.length === 0 && (
- + Loading models...
)} diff --git a/apps/ui/src/components/views/board-view/shared/planning-mode-selector.tsx b/apps/ui/src/components/views/board-view/shared/planning-mode-selector.tsx index 66af8d13..5c9bb5db 100644 --- a/apps/ui/src/components/views/board-view/shared/planning-mode-selector.tsx +++ b/apps/ui/src/components/views/board-view/shared/planning-mode-selector.tsx @@ -6,12 +6,12 @@ import { ClipboardList, FileText, ScrollText, - Loader2, Check, Eye, RefreshCw, Sparkles, } from 'lucide-react'; +import { Spinner } from '@/components/ui/spinner'; import { Label } from '@/components/ui/label'; import { Button } from '@/components/ui/button'; import { Checkbox } from '@/components/ui/checkbox'; @@ -236,7 +236,7 @@ export function PlanningModeSelector({
{isGenerating ? ( <> - + Generating {mode === 'full' ? 'comprehensive spec' : 'spec'}... diff --git a/apps/ui/src/components/views/board-view/worktree-panel/components/branch-switch-dropdown.tsx b/apps/ui/src/components/views/board-view/worktree-panel/components/branch-switch-dropdown.tsx index c7e7b7ef..0f6d2af3 100644 --- a/apps/ui/src/components/views/board-view/worktree-panel/components/branch-switch-dropdown.tsx +++ b/apps/ui/src/components/views/board-view/worktree-panel/components/branch-switch-dropdown.tsx @@ -8,7 +8,8 @@ import { DropdownMenuTrigger, DropdownMenuLabel, } from '@/components/ui/dropdown-menu'; -import { GitBranch, RefreshCw, GitBranchPlus, Check, Search } from 'lucide-react'; +import { GitBranch, GitBranchPlus, Check, Search } from 'lucide-react'; +import { Spinner } from '@/components/ui/spinner'; import { cn } from '@/lib/utils'; import type { WorktreeInfo, BranchInfo } from '../types'; @@ -81,7 +82,7 @@ export function BranchSwitchDropdown({
{isLoadingBranches ? ( - + Loading branches... ) : filteredBranches.length === 0 ? ( diff --git a/apps/ui/src/components/views/board-view/worktree-panel/components/dev-server-logs-panel.tsx b/apps/ui/src/components/views/board-view/worktree-panel/components/dev-server-logs-panel.tsx index 859ad34c..8405fbca 100644 --- a/apps/ui/src/components/views/board-view/worktree-panel/components/dev-server-logs-panel.tsx +++ b/apps/ui/src/components/views/board-view/worktree-panel/components/dev-server-logs-panel.tsx @@ -2,7 +2,6 @@ import { useEffect, useRef, useCallback, useState } from 'react'; import { Dialog, DialogContent, DialogHeader, DialogTitle } from '@/components/ui/dialog'; import { Button } from '@/components/ui/button'; import { - Loader2, Terminal, ArrowDown, ExternalLink, @@ -12,6 +11,7 @@ import { Clock, GitBranch, } from 'lucide-react'; +import { Spinner } from '@/components/ui/spinner'; import { cn } from '@/lib/utils'; import { XtermLogViewer, type XtermLogViewerRef } from '@/components/ui/xterm-log-viewer'; import { useDevServerLogs } from '../hooks/use-dev-server-logs'; @@ -183,7 +183,7 @@ export function DevServerLogsPanel({ onClick={() => fetchLogs()} title="Refresh logs" > - + {isLoading ? : }
@@ -234,7 +234,7 @@ export function DevServerLogsPanel({ > {isLoading && !logs ? (
- + Loading logs...
) : !logs && !isRunning ? ( @@ -245,7 +245,7 @@ export function DevServerLogsPanel({ ) : !logs ? (
-
+

Waiting for output...

Logs will appear as the server generates output diff --git a/apps/ui/src/components/views/board-view/worktree-panel/components/worktree-mobile-dropdown.tsx b/apps/ui/src/components/views/board-view/worktree-panel/components/worktree-mobile-dropdown.tsx index 52a07c96..079c9b11 100644 --- a/apps/ui/src/components/views/board-view/worktree-panel/components/worktree-mobile-dropdown.tsx +++ b/apps/ui/src/components/views/board-view/worktree-panel/components/worktree-mobile-dropdown.tsx @@ -7,7 +7,8 @@ import { DropdownMenuSeparator, DropdownMenuTrigger, } from '@/components/ui/dropdown-menu'; -import { GitBranch, ChevronDown, Loader2, CircleDot, Check } from 'lucide-react'; +import { GitBranch, ChevronDown, CircleDot, Check } from 'lucide-react'; +import { Spinner } from '@/components/ui/spinner'; import { cn } from '@/lib/utils'; import type { WorktreeInfo } from '../types'; @@ -44,7 +45,7 @@ export function WorktreeMobileDropdown({ {displayBranch} {isActivating ? ( - + ) : ( )} @@ -74,7 +75,7 @@ export function WorktreeMobileDropdown({ ) : (

)} - {isRunning && } + {isRunning && } {worktree.branch} diff --git a/apps/ui/src/components/views/board-view/worktree-panel/components/worktree-tab.tsx b/apps/ui/src/components/views/board-view/worktree-panel/components/worktree-tab.tsx index 5cb379d3..212e6d89 100644 --- a/apps/ui/src/components/views/board-view/worktree-panel/components/worktree-tab.tsx +++ b/apps/ui/src/components/views/board-view/worktree-panel/components/worktree-tab.tsx @@ -1,6 +1,7 @@ import type { JSX } from 'react'; import { Button } from '@/components/ui/button'; -import { RefreshCw, Globe, Loader2, CircleDot, GitPullRequest } from 'lucide-react'; +import { Globe, CircleDot, GitPullRequest } from 'lucide-react'; +import { Spinner } from '@/components/ui/spinner'; import { cn } from '@/lib/utils'; import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from '@/components/ui/tooltip'; import type { WorktreeInfo, BranchInfo, DevServerInfo, PRInfo, GitRepoStatus } from '../types'; @@ -197,8 +198,8 @@ export function WorktreeTab({ aria-label={worktree.branch} data-testid={`worktree-branch-${worktree.branch}`} > - {isRunning && } - {isActivating && !isRunning && } + {isRunning && } + {isActivating && !isRunning && } {worktree.branch} {cardCount !== undefined && cardCount > 0 && ( @@ -264,8 +265,8 @@ export function WorktreeTab({ : 'Click to switch to this branch' } > - {isRunning && } - {isActivating && !isRunning && } + {isRunning && } + {isActivating && !isRunning && } {worktree.branch} {cardCount !== undefined && cardCount > 0 && ( diff --git a/apps/ui/src/components/views/board-view/worktree-panel/worktree-panel.tsx b/apps/ui/src/components/views/board-view/worktree-panel/worktree-panel.tsx index 2cc844f4..fbd54d73 100644 --- a/apps/ui/src/components/views/board-view/worktree-panel/worktree-panel.tsx +++ b/apps/ui/src/components/views/board-view/worktree-panel/worktree-panel.tsx @@ -1,6 +1,7 @@ import { useEffect, useRef, useCallback, useState } from 'react'; import { Button } from '@/components/ui/button'; import { GitBranch, Plus, RefreshCw } from 'lucide-react'; +import { Spinner } from '@/components/ui/spinner'; import { cn, pathsEqual } from '@/lib/utils'; import { toast } from 'sonner'; import { getHttpApiClient } from '@/lib/http-api-client'; @@ -285,7 +286,7 @@ export function WorktreePanel({ disabled={isLoading} title="Refresh worktrees" > - + {isLoading ? : } )} @@ -429,7 +430,7 @@ export function WorktreePanel({ disabled={isLoading} title="Refresh worktrees" > - + {isLoading ? : }
diff --git a/apps/ui/src/components/views/code-view.tsx b/apps/ui/src/components/views/code-view.tsx index 581a298b..ce80bc23 100644 --- a/apps/ui/src/components/views/code-view.tsx +++ b/apps/ui/src/components/views/code-view.tsx @@ -4,7 +4,8 @@ import { useAppStore } from '@/store/app-store'; import { getElectronAPI } from '@/lib/electron'; import { Card, CardContent } from '@/components/ui/card'; import { Button } from '@/components/ui/button'; -import { File, Folder, FolderOpen, ChevronRight, ChevronDown, RefreshCw, Code } from 'lucide-react'; +import { File, Folder, FolderOpen, ChevronRight, ChevronDown, Code } from 'lucide-react'; +import { Spinner } from '@/components/ui/spinner'; import { cn } from '@/lib/utils'; const logger = createLogger('CodeView'); @@ -206,7 +207,7 @@ export function CodeView() { if (isLoading) { return (
- +
); } diff --git a/apps/ui/src/components/views/context-view.tsx b/apps/ui/src/components/views/context-view.tsx index 024ee392..b186e0c1 100644 --- a/apps/ui/src/components/views/context-view.tsx +++ b/apps/ui/src/components/views/context-view.tsx @@ -12,7 +12,6 @@ import { HeaderActionsPanelTrigger, } from '@/components/ui/header-actions-panel'; import { - RefreshCw, FileText, Image as ImageIcon, Trash2, @@ -24,9 +23,9 @@ import { Pencil, FilePlus, FileUp, - Loader2, MoreVertical, } from 'lucide-react'; +import { Spinner } from '@/components/ui/spinner'; import { useKeyboardShortcuts, useKeyboardShortcutsConfig, @@ -670,7 +669,7 @@ export function ContextView() { if (isLoading) { return (
- +
); } @@ -790,7 +789,7 @@ export function ContextView() { {isUploading && (
- + Uploading {uploadingFileName}...
@@ -838,7 +837,7 @@ export function ContextView() { {file.name} {isGenerating ? ( - + Generating description... ) : file.description ? ( @@ -955,7 +954,7 @@ export function ContextView() { {generatingDescriptions.has(selectedFile.name) ? (
- + Generating description with AI...
) : selectedFile.description ? ( diff --git a/apps/ui/src/components/views/dashboard-view.tsx b/apps/ui/src/components/views/dashboard-view.tsx index 7e657c80..f9582d00 100644 --- a/apps/ui/src/components/views/dashboard-view.tsx +++ b/apps/ui/src/components/views/dashboard-view.tsx @@ -18,7 +18,6 @@ import { Folder, Star, Clock, - Loader2, ChevronDown, MessageSquare, MoreVertical, @@ -28,6 +27,7 @@ import { type LucideIcon, } from 'lucide-react'; import * as LucideIcons from 'lucide-react'; +import { Spinner } from '@/components/ui/spinner'; import { Input } from '@/components/ui/input'; import { getAuthenticatedImageUrl } from '@/lib/api-fetch'; import { @@ -992,7 +992,7 @@ export function DashboardView() { data-testid="project-opening-overlay" >
- +

Opening project...

diff --git a/apps/ui/src/components/views/github-issues-view/components/issue-detail-panel.tsx b/apps/ui/src/components/views/github-issues-view/components/issue-detail-panel.tsx index 3ff836dc..cc62a7fe 100644 --- a/apps/ui/src/components/views/github-issues-view/components/issue-detail-panel.tsx +++ b/apps/ui/src/components/views/github-issues-view/components/issue-detail-panel.tsx @@ -4,7 +4,6 @@ import { X, Wand2, ExternalLink, - Loader2, CheckCircle, Clock, GitPullRequest, @@ -14,6 +13,7 @@ import { ChevronDown, ChevronUp, } from 'lucide-react'; +import { Spinner } from '@/components/ui/spinner'; import { useState } from 'react'; import { Button } from '@/components/ui/button'; import { Checkbox } from '@/components/ui/checkbox'; @@ -87,7 +87,7 @@ export function IssueDetailPanel({ if (isValidating) { return ( ); @@ -297,9 +297,7 @@ export function IssueDetailPanel({ Comments {totalCount > 0 && `(${totalCount})`} - {commentsLoading && ( - - )} + {commentsLoading && } {commentsExpanded ? ( ) : ( @@ -340,7 +338,7 @@ export function IssueDetailPanel({ > {loadingMore ? ( <> - + Loading... ) : ( diff --git a/apps/ui/src/components/views/github-issues-view/components/issue-row.tsx b/apps/ui/src/components/views/github-issues-view/components/issue-row.tsx index bf6496f1..01bf8316 100644 --- a/apps/ui/src/components/views/github-issues-view/components/issue-row.tsx +++ b/apps/ui/src/components/views/github-issues-view/components/issue-row.tsx @@ -2,12 +2,12 @@ import { Circle, CheckCircle2, ExternalLink, - Loader2, CheckCircle, Sparkles, GitPullRequest, User, } from 'lucide-react'; +import { Spinner } from '@/components/ui/spinner'; import { Button } from '@/components/ui/button'; import { cn } from '@/lib/utils'; import type { IssueRowProps } from '../types'; @@ -97,7 +97,7 @@ export function IssueRow({ {/* Validating indicator */} {isValidating && ( - + Analyzing... )} diff --git a/apps/ui/src/components/views/github-issues-view/components/issues-list-header.tsx b/apps/ui/src/components/views/github-issues-view/components/issues-list-header.tsx index 1c58bbe4..5b599c4e 100644 --- a/apps/ui/src/components/views/github-issues-view/components/issues-list-header.tsx +++ b/apps/ui/src/components/views/github-issues-view/components/issues-list-header.tsx @@ -1,5 +1,6 @@ import { CircleDot, RefreshCw } from 'lucide-react'; import { Button } from '@/components/ui/button'; +import { Spinner } from '@/components/ui/spinner'; import { cn } from '@/lib/utils'; import type { IssuesStateFilter } from '../types'; import { IssuesFilterControls } from './issues-filter-controls'; @@ -77,7 +78,7 @@ export function IssuesListHeader({
diff --git a/apps/ui/src/components/views/github-prs-view.tsx b/apps/ui/src/components/views/github-prs-view.tsx index 855d136c..fbbcb9eb 100644 --- a/apps/ui/src/components/views/github-prs-view.tsx +++ b/apps/ui/src/components/views/github-prs-view.tsx @@ -1,6 +1,7 @@ import { useState, useEffect, useCallback } from 'react'; import { createLogger } from '@automaker/utils/logger'; -import { GitPullRequest, Loader2, RefreshCw, ExternalLink, GitMerge, X } from 'lucide-react'; +import { GitPullRequest, RefreshCw, ExternalLink, GitMerge, X } from 'lucide-react'; +import { Spinner } from '@/components/ui/spinner'; import { getElectronAPI, GitHubPR } from '@/lib/electron'; import { useAppStore } from '@/store/app-store'; import { Button } from '@/components/ui/button'; @@ -86,7 +87,7 @@ export function GitHubPRsView() { if (loading) { return (
- +
); } @@ -134,7 +135,7 @@ export function GitHubPRsView() { diff --git a/apps/ui/src/components/views/graph-view-page.tsx b/apps/ui/src/components/views/graph-view-page.tsx index f8e9ba0a..47acf313 100644 --- a/apps/ui/src/components/views/graph-view-page.tsx +++ b/apps/ui/src/components/views/graph-view-page.tsx @@ -17,7 +17,7 @@ import { import { useWorktrees } from './board-view/worktree-panel/hooks'; import { useAutoMode } from '@/hooks/use-auto-mode'; import { pathsEqual } from '@/lib/utils'; -import { RefreshCw } from 'lucide-react'; +import { Spinner } from '@/components/ui/spinner'; import { getElectronAPI } from '@/lib/electron'; import { createLogger } from '@automaker/utils/logger'; import { toast } from 'sonner'; @@ -330,7 +330,7 @@ export function GraphViewPage() { if (isLoading) { return (
- +
); } diff --git a/apps/ui/src/components/views/ideation-view/components/ideation-dashboard.tsx b/apps/ui/src/components/views/ideation-view/components/ideation-dashboard.tsx index 41d12a34..8bf6d7bb 100644 --- a/apps/ui/src/components/views/ideation-view/components/ideation-dashboard.tsx +++ b/apps/ui/src/components/views/ideation-view/components/ideation-dashboard.tsx @@ -4,7 +4,8 @@ */ import { useState, useMemo, useEffect, useCallback } from 'react'; -import { Loader2, AlertCircle, Plus, X, Sparkles, Lightbulb, Trash2 } from 'lucide-react'; +import { AlertCircle, Plus, X, Sparkles, Lightbulb, Trash2 } from 'lucide-react'; +import { Spinner } from '@/components/ui/spinner'; import { Card, CardContent } from '@/components/ui/card'; import { Button } from '@/components/ui/button'; import { Badge } from '@/components/ui/badge'; @@ -109,7 +110,7 @@ function SuggestionCard({ )} > {isAdding ? ( - + ) : ( <> @@ -153,11 +154,7 @@ function GeneratingCard({ job }: { job: GenerationJob }) { isError ? 'bg-destructive/10 text-destructive' : 'bg-blue-500/10 text-blue-500' )} > - {isError ? ( - - ) : ( - - )} + {isError ? : }

{job.prompt.title}

diff --git a/apps/ui/src/components/views/ideation-view/components/prompt-category-grid.tsx b/apps/ui/src/components/views/ideation-view/components/prompt-category-grid.tsx index a4d3d505..c09548b0 100644 --- a/apps/ui/src/components/views/ideation-view/components/prompt-category-grid.tsx +++ b/apps/ui/src/components/views/ideation-view/components/prompt-category-grid.tsx @@ -13,8 +13,8 @@ import { Gauge, Accessibility, BarChart3, - Loader2, } from 'lucide-react'; +import { Spinner } from '@/components/ui/spinner'; import { Card, CardContent } from '@/components/ui/card'; import { useGuidedPrompts } from '@/hooks/use-guided-prompts'; import type { IdeaCategory } from '@automaker/types'; @@ -53,7 +53,7 @@ export function PromptCategoryGrid({ onSelect, onBack }: PromptCategoryGridProps {isLoading && (
- + Loading categories...
)} diff --git a/apps/ui/src/components/views/ideation-view/components/prompt-list.tsx b/apps/ui/src/components/views/ideation-view/components/prompt-list.tsx index a7e3fc8b..af52030b 100644 --- a/apps/ui/src/components/views/ideation-view/components/prompt-list.tsx +++ b/apps/ui/src/components/views/ideation-view/components/prompt-list.tsx @@ -3,7 +3,8 @@ */ import { useState, useMemo } from 'react'; -import { ArrowLeft, Lightbulb, Loader2, CheckCircle2 } from 'lucide-react'; +import { ArrowLeft, Lightbulb, CheckCircle2 } from 'lucide-react'; +import { Spinner } from '@/components/ui/spinner'; import { Card, CardContent } from '@/components/ui/card'; import { useGuidedPrompts } from '@/hooks/use-guided-prompts'; import { useIdeationStore } from '@/store/ideation-store'; @@ -121,7 +122,7 @@ export function PromptList({ category, onBack }: PromptListProps) {
{isLoadingPrompts && (
- + Loading prompts...
)} @@ -162,7 +163,7 @@ export function PromptList({ category, onBack }: PromptListProps) { }`} > {isLoading || isGenerating ? ( - + ) : isStarted ? ( ) : ( diff --git a/apps/ui/src/components/views/ideation-view/index.tsx b/apps/ui/src/components/views/ideation-view/index.tsx index 0662c6ed..50cbd8d3 100644 --- a/apps/ui/src/components/views/ideation-view/index.tsx +++ b/apps/ui/src/components/views/ideation-view/index.tsx @@ -11,7 +11,8 @@ import { PromptList } from './components/prompt-list'; import { IdeationDashboard } from './components/ideation-dashboard'; import { useGuidedPrompts } from '@/hooks/use-guided-prompts'; import { Button } from '@/components/ui/button'; -import { ArrowLeft, ChevronRight, Lightbulb, CheckCheck, Loader2, Trash2 } from 'lucide-react'; +import { ArrowLeft, ChevronRight, Lightbulb, CheckCheck, Trash2 } from 'lucide-react'; +import { Spinner } from '@/components/ui/spinner'; import type { IdeaCategory } from '@automaker/types'; import type { IdeationMode } from '@/store/ideation-store'; @@ -152,11 +153,7 @@ function IdeationHeader({ className="gap-2" disabled={isAcceptingAll} > - {isAcceptingAll ? ( - - ) : ( - - )} + {isAcceptingAll ? : } Accept All ({acceptAllCount}) )} diff --git a/apps/ui/src/components/views/interview-view.tsx b/apps/ui/src/components/views/interview-view.tsx index b9b9997e..b56971c1 100644 --- a/apps/ui/src/components/views/interview-view.tsx +++ b/apps/ui/src/components/views/interview-view.tsx @@ -5,7 +5,8 @@ import { useAppStore, Feature } from '@/store/app-store'; import { Card, CardContent } from '@/components/ui/card'; import { Button } from '@/components/ui/button'; import { Input } from '@/components/ui/input'; -import { Bot, Send, User, Loader2, Sparkles, FileText, ArrowLeft, CheckCircle } from 'lucide-react'; +import { Bot, Send, User, Sparkles, FileText, ArrowLeft, CheckCircle } from 'lucide-react'; +import { Spinner } from '@/components/ui/spinner'; import { cn, generateUUID } from '@/lib/utils'; import { getElectronAPI } from '@/lib/electron'; import { Markdown } from '@/components/ui/markdown'; @@ -491,7 +492,7 @@ export function InterviewView() {
- + Generating specification...
@@ -571,7 +572,7 @@ export function InterviewView() { > {isGenerating ? ( <> - + Creating... ) : ( diff --git a/apps/ui/src/components/views/login-view.tsx b/apps/ui/src/components/views/login-view.tsx index faca109c..0ed259bf 100644 --- a/apps/ui/src/components/views/login-view.tsx +++ b/apps/ui/src/components/views/login-view.tsx @@ -24,7 +24,8 @@ import { } from '@/lib/http-api-client'; import { Button } from '@/components/ui/button'; import { Input } from '@/components/ui/input'; -import { KeyRound, AlertCircle, Loader2, RefreshCw, ServerCrash } from 'lucide-react'; +import { KeyRound, AlertCircle, RefreshCw, ServerCrash } from 'lucide-react'; +import { Spinner } from '@/components/ui/spinner'; import { useAuthStore } from '@/store/auth-store'; import { useSetupStore } from '@/store/setup-store'; @@ -349,7 +350,7 @@ export function LoginView() { return (
- +

Connecting to server {state.attempt > 1 ? ` (attempt ${state.attempt}/${MAX_RETRIES})` : '...'} @@ -385,7 +386,7 @@ export function LoginView() { return (

- +

{state.phase === 'checking_setup' ? 'Loading settings...' : 'Redirecting...'}

@@ -447,7 +448,7 @@ export function LoginView() { > {isLoggingIn ? ( <> - + Authenticating... ) : ( diff --git a/apps/ui/src/components/views/memory-view.tsx b/apps/ui/src/components/views/memory-view.tsx index 66533413..b6331602 100644 --- a/apps/ui/src/components/views/memory-view.tsx +++ b/apps/ui/src/components/views/memory-view.tsx @@ -19,6 +19,7 @@ import { FilePlus, MoreVertical, } from 'lucide-react'; +import { Spinner } from '@/components/ui/spinner'; import { Dialog, DialogContent, @@ -299,7 +300,7 @@ export function MemoryView() { if (isLoading) { return (
- +
); } diff --git a/apps/ui/src/components/views/notifications-view.tsx b/apps/ui/src/components/views/notifications-view.tsx index aaffb011..08386c55 100644 --- a/apps/ui/src/components/views/notifications-view.tsx +++ b/apps/ui/src/components/views/notifications-view.tsx @@ -9,7 +9,8 @@ import { useLoadNotifications, useNotificationEvents } from '@/hooks/use-notific import { getHttpApiClient } from '@/lib/http-api-client'; import { Button } from '@/components/ui/button'; import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/components/ui/card'; -import { Bell, Check, CheckCheck, Trash2, ExternalLink, Loader2 } from 'lucide-react'; +import { Bell, Check, CheckCheck, Trash2, ExternalLink } from 'lucide-react'; +import { Spinner } from '@/components/ui/spinner'; import { useNavigate } from '@tanstack/react-router'; import type { Notification } from '@automaker/types'; @@ -146,7 +147,7 @@ export function NotificationsView() { if (isLoading) { return (
- +

Loading notifications...

); diff --git a/apps/ui/src/components/views/project-settings-view/worktree-preferences-section.tsx b/apps/ui/src/components/views/project-settings-view/worktree-preferences-section.tsx index c289d382..d6d0c247 100644 --- a/apps/ui/src/components/views/project-settings-view/worktree-preferences-section.tsx +++ b/apps/ui/src/components/views/project-settings-view/worktree-preferences-section.tsx @@ -10,9 +10,9 @@ import { Save, RotateCcw, Trash2, - Loader2, PanelBottomClose, } from 'lucide-react'; +import { Spinner } from '@/components/ui/spinner'; import { cn } from '@/lib/utils'; import { apiGet, apiPut, apiDelete } from '@/lib/api-fetch'; import { toast } from 'sonner'; @@ -409,7 +409,7 @@ export function WorktreePreferencesSection({ project }: WorktreePreferencesSecti {isLoading ? (
- +
) : ( <> @@ -448,11 +448,7 @@ npm install disabled={!scriptExists || isSaving || isDeleting} className="gap-1.5 text-destructive hover:text-destructive hover:bg-destructive/10" > - {isDeleting ? ( - - ) : ( - - )} + {isDeleting ? : } Delete
diff --git a/apps/ui/src/components/views/running-agents-view.tsx b/apps/ui/src/components/views/running-agents-view.tsx index d46729c1..b77518d0 100644 --- a/apps/ui/src/components/views/running-agents-view.tsx +++ b/apps/ui/src/components/views/running-agents-view.tsx @@ -1,6 +1,7 @@ import { useState, useEffect, useCallback } from 'react'; import { createLogger } from '@automaker/utils/logger'; -import { Bot, Folder, Loader2, RefreshCw, Square, Activity, FileText } from 'lucide-react'; +import { Bot, Folder, RefreshCw, Square, Activity, FileText } from 'lucide-react'; +import { Spinner } from '@/components/ui/spinner'; import { getElectronAPI, RunningAgent } from '@/lib/electron'; import { useAppStore } from '@/store/app-store'; import { Button } from '@/components/ui/button'; @@ -146,7 +147,7 @@ export function RunningAgentsView() { if (loading) { return (
- +
); } @@ -169,7 +170,11 @@ export function RunningAgentsView() {
diff --git a/apps/ui/src/components/views/settings-view/account/account-section.tsx b/apps/ui/src/components/views/settings-view/account/account-section.tsx index 901e5040..d10049fc 100644 --- a/apps/ui/src/components/views/settings-view/account/account-section.tsx +++ b/apps/ui/src/components/views/settings-view/account/account-section.tsx @@ -11,6 +11,7 @@ import { import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from '@/components/ui/tooltip'; import { toast } from 'sonner'; import { LogOut, User, Code2, RefreshCw } from 'lucide-react'; +import { Spinner } from '@/components/ui/spinner'; import { cn } from '@/lib/utils'; import { logout } from '@/lib/http-api-client'; import { useAuthStore } from '@/store/auth-store'; @@ -143,7 +144,7 @@ export function AccountSection() { disabled={isRefreshing || isLoadingEditors} className="shrink-0 h-9 w-9" > - + {isRefreshing ? : } diff --git a/apps/ui/src/components/views/settings-view/api-keys/api-key-field.tsx b/apps/ui/src/components/views/settings-view/api-keys/api-key-field.tsx index 6d044f6c..61b49a1c 100644 --- a/apps/ui/src/components/views/settings-view/api-keys/api-key-field.tsx +++ b/apps/ui/src/components/views/settings-view/api-keys/api-key-field.tsx @@ -1,7 +1,8 @@ import { Button } from '@/components/ui/button'; import { Input } from '@/components/ui/input'; import { Label } from '@/components/ui/label'; -import { AlertCircle, CheckCircle2, Eye, EyeOff, Loader2, Zap } from 'lucide-react'; +import { AlertCircle, CheckCircle2, Eye, EyeOff, Zap } from 'lucide-react'; +import { Spinner } from '@/components/ui/spinner'; import type { ProviderConfig } from '@/config/api-providers'; interface ApiKeyFieldProps { @@ -70,7 +71,7 @@ export function ApiKeyField({ config }: ApiKeyFieldProps) { > {testButton.loading ? ( <> - + Testing... ) : ( diff --git a/apps/ui/src/components/views/settings-view/api-keys/api-keys-section.tsx b/apps/ui/src/components/views/settings-view/api-keys/api-keys-section.tsx index 088f3ddf..840c8e63 100644 --- a/apps/ui/src/components/views/settings-view/api-keys/api-keys-section.tsx +++ b/apps/ui/src/components/views/settings-view/api-keys/api-keys-section.tsx @@ -1,7 +1,8 @@ import { useAppStore } from '@/store/app-store'; import { useSetupStore } from '@/store/setup-store'; import { Button } from '@/components/ui/button'; -import { Key, CheckCircle2, Trash2, Loader2 } from 'lucide-react'; +import { Key, CheckCircle2, Trash2 } from 'lucide-react'; +import { Spinner } from '@/components/ui/spinner'; import { ApiKeyField } from './api-key-field'; import { buildProviderConfigs } from '@/config/api-providers'; import { SecurityNotice } from './security-notice'; @@ -142,7 +143,7 @@ export function ApiKeysSection() { data-testid="delete-anthropic-key" > {isDeletingAnthropicKey ? ( - + ) : ( )} @@ -159,7 +160,7 @@ export function ApiKeysSection() { data-testid="delete-openai-key" > {isDeletingOpenaiKey ? ( - + ) : ( )} diff --git a/apps/ui/src/components/views/settings-view/api-keys/claude-usage-section.tsx b/apps/ui/src/components/views/settings-view/api-keys/claude-usage-section.tsx index 11912ec4..2aa1ff3c 100644 --- a/apps/ui/src/components/views/settings-view/api-keys/claude-usage-section.tsx +++ b/apps/ui/src/components/views/settings-view/api-keys/claude-usage-section.tsx @@ -4,6 +4,7 @@ import { getElectronAPI } from '@/lib/electron'; import { useSetupStore } from '@/store/setup-store'; import { useAppStore } from '@/store/app-store'; import { Button } from '@/components/ui/button'; +import { Spinner } from '@/components/ui/spinner'; import { RefreshCw, AlertCircle } from 'lucide-react'; const ERROR_NO_API = 'Claude usage API not available'; @@ -178,7 +179,7 @@ export function ClaudeUsageSection() { data-testid="refresh-claude-usage" title={CLAUDE_REFRESH_LABEL} > - + {isLoading ? : }

{CLAUDE_USAGE_SUBTITLE}

diff --git a/apps/ui/src/components/views/settings-view/cli-status/claude-cli-status.tsx b/apps/ui/src/components/views/settings-view/cli-status/claude-cli-status.tsx index 2457969b..a6474a7a 100644 --- a/apps/ui/src/components/views/settings-view/cli-status/claude-cli-status.tsx +++ b/apps/ui/src/components/views/settings-view/cli-status/claude-cli-status.tsx @@ -1,5 +1,6 @@ import { useState, useCallback } from 'react'; import { Button } from '@/components/ui/button'; +import { Spinner } from '@/components/ui/spinner'; import { CheckCircle2, AlertCircle, RefreshCw, XCircle } from 'lucide-react'; import { cn } from '@/lib/utils'; import type { CliStatus } from '../shared/types'; @@ -172,7 +173,7 @@ export function ClaudeCliStatus({ status, authStatus, isChecking, onRefresh }: C 'transition-all duration-200' )} > - + {isChecking ? : }

diff --git a/apps/ui/src/components/views/settings-view/cli-status/cli-status-card.tsx b/apps/ui/src/components/views/settings-view/cli-status/cli-status-card.tsx index dd194c1f..6e577787 100644 --- a/apps/ui/src/components/views/settings-view/cli-status/cli-status-card.tsx +++ b/apps/ui/src/components/views/settings-view/cli-status/cli-status-card.tsx @@ -1,5 +1,6 @@ import { Button } from '@/components/ui/button'; import { CheckCircle2, AlertCircle, RefreshCw } from 'lucide-react'; +import { Spinner } from '@/components/ui/spinner'; import { cn } from '@/lib/utils'; import type { CliStatus } from '../shared/types'; @@ -56,7 +57,7 @@ export function CliStatusCard({ 'transition-all duration-200' )} > - + {isChecking ? : }

{description}

diff --git a/apps/ui/src/components/views/settings-view/cli-status/codex-cli-status.tsx b/apps/ui/src/components/views/settings-view/cli-status/codex-cli-status.tsx index 86635264..3e0d8b53 100644 --- a/apps/ui/src/components/views/settings-view/cli-status/codex-cli-status.tsx +++ b/apps/ui/src/components/views/settings-view/cli-status/codex-cli-status.tsx @@ -1,5 +1,6 @@ import { useState, useCallback } from 'react'; import { Button } from '@/components/ui/button'; +import { Spinner } from '@/components/ui/spinner'; import { CheckCircle2, AlertCircle, RefreshCw, XCircle } from 'lucide-react'; import { cn } from '@/lib/utils'; import type { CliStatus } from '../shared/types'; @@ -165,7 +166,7 @@ export function CodexCliStatus({ status, authStatus, isChecking, onRefresh }: Cl 'transition-all duration-200' )} > - + {isChecking ? : }

diff --git a/apps/ui/src/components/views/settings-view/cli-status/cursor-cli-status.tsx b/apps/ui/src/components/views/settings-view/cli-status/cursor-cli-status.tsx index bc49270c..68c052fb 100644 --- a/apps/ui/src/components/views/settings-view/cli-status/cursor-cli-status.tsx +++ b/apps/ui/src/components/views/settings-view/cli-status/cursor-cli-status.tsx @@ -1,5 +1,6 @@ import { useState, useCallback } from 'react'; import { Button } from '@/components/ui/button'; +import { Spinner } from '@/components/ui/spinner'; import { CheckCircle2, AlertCircle, RefreshCw, XCircle } from 'lucide-react'; import { cn } from '@/lib/utils'; import { CursorIcon } from '@/components/ui/provider-icon'; @@ -290,7 +291,7 @@ export function CursorCliStatus({ status, isChecking, onRefresh }: CursorCliStat 'transition-all duration-200' )} > - + {isChecking ? : }

diff --git a/apps/ui/src/components/views/settings-view/cli-status/opencode-cli-status.tsx b/apps/ui/src/components/views/settings-view/cli-status/opencode-cli-status.tsx index bfd9efe6..7d7577c5 100644 --- a/apps/ui/src/components/views/settings-view/cli-status/opencode-cli-status.tsx +++ b/apps/ui/src/components/views/settings-view/cli-status/opencode-cli-status.tsx @@ -1,5 +1,6 @@ import { Button } from '@/components/ui/button'; import { Badge } from '@/components/ui/badge'; +import { Spinner } from '@/components/ui/spinner'; import { CheckCircle2, AlertCircle, RefreshCw, Bot, Cloud } from 'lucide-react'; import { cn } from '@/lib/utils'; import type { CliStatus } from '../shared/types'; @@ -221,7 +222,7 @@ export function OpencodeCliStatus({ 'transition-all duration-200' )} > - + {isChecking ? : }

diff --git a/apps/ui/src/components/views/settings-view/codex/codex-usage-section.tsx b/apps/ui/src/components/views/settings-view/codex/codex-usage-section.tsx index b879df4a..9012047d 100644 --- a/apps/ui/src/components/views/settings-view/codex/codex-usage-section.tsx +++ b/apps/ui/src/components/views/settings-view/codex/codex-usage-section.tsx @@ -1,6 +1,7 @@ // @ts-nocheck import { useCallback, useEffect, useState } from 'react'; import { Button } from '@/components/ui/button'; +import { Spinner } from '@/components/ui/spinner'; import { RefreshCw, AlertCircle } from 'lucide-react'; import { OpenAIIcon } from '@/components/ui/provider-icon'; import { cn } from '@/lib/utils'; @@ -168,7 +169,7 @@ export function CodexUsageSection() { data-testid="refresh-codex-usage" title={CODEX_REFRESH_LABEL} > - + {isLoading ? : }

{CODEX_USAGE_SUBTITLE}

diff --git a/apps/ui/src/components/views/settings-view/event-hooks/event-history-view.tsx b/apps/ui/src/components/views/settings-view/event-hooks/event-history-view.tsx index 780f5f98..e9c5a071 100644 --- a/apps/ui/src/components/views/settings-view/event-hooks/event-history-view.tsx +++ b/apps/ui/src/components/views/settings-view/event-hooks/event-history-view.tsx @@ -1,5 +1,6 @@ import { useState, useEffect, useCallback } from 'react'; import { Button } from '@/components/ui/button'; +import { Spinner } from '@/components/ui/spinner'; import { cn } from '@/lib/utils'; import { History, @@ -184,7 +185,11 @@ export function EventHistoryView() {

{events.length > 0 && ( diff --git a/apps/ui/src/components/views/settings-view/mcp-servers/components/mcp-server-card.tsx b/apps/ui/src/components/views/settings-view/mcp-servers/components/mcp-server-card.tsx index babf4bda..752b06e7 100644 --- a/apps/ui/src/components/views/settings-view/mcp-servers/components/mcp-server-card.tsx +++ b/apps/ui/src/components/views/settings-view/mcp-servers/components/mcp-server-card.tsx @@ -1,4 +1,5 @@ -import { ChevronDown, ChevronRight, Code, Pencil, Trash2, PlayCircle, Loader2 } from 'lucide-react'; +import { ChevronDown, ChevronRight, Code, Pencil, Trash2, PlayCircle } from 'lucide-react'; +import { Spinner } from '@/components/ui/spinner'; import { Button } from '@/components/ui/button'; import { Switch } from '@/components/ui/switch'; import { Collapsible, CollapsibleContent, CollapsibleTrigger } from '@/components/ui/collapsible'; @@ -111,7 +112,7 @@ export function MCPServerCard({ className="h-8 px-2" > {testState?.status === 'testing' ? ( - + ) : ( )} diff --git a/apps/ui/src/components/views/settings-view/mcp-servers/components/mcp-server-header.tsx b/apps/ui/src/components/views/settings-view/mcp-servers/components/mcp-server-header.tsx index a85fc305..8caf3bca 100644 --- a/apps/ui/src/components/views/settings-view/mcp-servers/components/mcp-server-header.tsx +++ b/apps/ui/src/components/views/settings-view/mcp-servers/components/mcp-server-header.tsx @@ -1,5 +1,6 @@ import { Plug, RefreshCw, Download, Code, FileJson, Plus } from 'lucide-react'; import { Button } from '@/components/ui/button'; +import { Spinner } from '@/components/ui/spinner'; import { cn } from '@/lib/utils'; interface MCPServerHeaderProps { @@ -43,7 +44,7 @@ export function MCPServerHeader({ disabled={isRefreshing} data-testid="refresh-mcp-servers-button" > - + {isRefreshing ? : } {hasServers && ( <> diff --git a/apps/ui/src/components/views/settings-view/mcp-servers/utils.tsx b/apps/ui/src/components/views/settings-view/mcp-servers/utils.tsx index 25102025..83687556 100644 --- a/apps/ui/src/components/views/settings-view/mcp-servers/utils.tsx +++ b/apps/ui/src/components/views/settings-view/mcp-servers/utils.tsx @@ -1,4 +1,5 @@ -import { Terminal, Globe, Loader2, CheckCircle2, XCircle } from 'lucide-react'; +import { Terminal, Globe, CheckCircle2, XCircle } from 'lucide-react'; +import { Spinner } from '@/components/ui/spinner'; import type { ServerType, ServerTestState } from './types'; import { SENSITIVE_PARAM_PATTERNS } from './constants'; @@ -40,7 +41,7 @@ export function getServerIcon(type: ServerType = 'stdio') { export function getTestStatusIcon(status: ServerTestState['status']) { switch (status) { case 'testing': - return ; + return ; case 'success': return ; case 'error': diff --git a/apps/ui/src/components/views/settings-view/providers/claude-settings-tab/subagents-section.tsx b/apps/ui/src/components/views/settings-view/providers/claude-settings-tab/subagents-section.tsx index 08800331..d1f1bf76 100644 --- a/apps/ui/src/components/views/settings-view/providers/claude-settings-tab/subagents-section.tsx +++ b/apps/ui/src/components/views/settings-view/providers/claude-settings-tab/subagents-section.tsx @@ -14,16 +14,8 @@ import { Label } from '@/components/ui/label'; import { Switch } from '@/components/ui/switch'; import { Checkbox } from '@/components/ui/checkbox'; import { cn } from '@/lib/utils'; -import { - Bot, - RefreshCw, - Loader2, - Users, - ExternalLink, - Globe, - FolderOpen, - Sparkles, -} from 'lucide-react'; +import { Bot, RefreshCw, Users, ExternalLink, Globe, FolderOpen, Sparkles } from 'lucide-react'; +import { Spinner } from '@/components/ui/spinner'; import { useSubagents } from './hooks/use-subagents'; import { useSubagentsSettings } from './hooks/use-subagents-settings'; import { SubagentCard } from './subagent-card'; @@ -178,11 +170,7 @@ export function SubagentsSection() { title="Refresh agents from disk" className="gap-1.5 h-7 px-2 text-xs" > - {isLoadingAgents ? ( - - ) : ( - - )} + {isLoadingAgents ? : } Refresh
diff --git a/apps/ui/src/components/views/settings-view/providers/cursor-permissions-section.tsx b/apps/ui/src/components/views/settings-view/providers/cursor-permissions-section.tsx index 29be25b3..133913b9 100644 --- a/apps/ui/src/components/views/settings-view/providers/cursor-permissions-section.tsx +++ b/apps/ui/src/components/views/settings-view/providers/cursor-permissions-section.tsx @@ -4,6 +4,7 @@ import { Badge } from '@/components/ui/badge'; import { Button } from '@/components/ui/button'; import { Collapsible, CollapsibleContent, CollapsibleTrigger } from '@/components/ui/collapsible'; import { Shield, ShieldCheck, ShieldAlert, ChevronDown, Copy, Check } from 'lucide-react'; +import { Spinner } from '@/components/ui/spinner'; import { cn } from '@/lib/utils'; import type { CursorStatus } from '../hooks/use-cursor-status'; import type { PermissionsData } from '../hooks/use-cursor-permissions'; @@ -118,7 +119,7 @@ export function CursorPermissionsSection({ {isLoadingPermissions ? (
-
+
) : ( <> diff --git a/apps/ui/src/components/views/settings-view/providers/opencode-model-configuration.tsx b/apps/ui/src/components/views/settings-view/providers/opencode-model-configuration.tsx index 3d2d0fb6..6ecce79c 100644 --- a/apps/ui/src/components/views/settings-view/providers/opencode-model-configuration.tsx +++ b/apps/ui/src/components/views/settings-view/providers/opencode-model-configuration.tsx @@ -9,7 +9,8 @@ import { SelectTrigger, SelectValue, } from '@/components/ui/select'; -import { Terminal, Cloud, Cpu, Brain, Github, Loader2, KeyRound, ShieldCheck } from 'lucide-react'; +import { Terminal, Cloud, Cpu, Brain, Github, KeyRound, ShieldCheck } from 'lucide-react'; +import { Spinner } from '@/components/ui/spinner'; import { cn } from '@/lib/utils'; import { Input } from '@/components/ui/input'; import type { @@ -500,7 +501,7 @@ export function OpencodeModelConfiguration({

{isLoadingDynamicModels && (
- + Discovering...
)} diff --git a/apps/ui/src/components/views/setup-view/components/cli-installation-card.tsx b/apps/ui/src/components/views/setup-view/components/cli-installation-card.tsx index ee32f231..4932ef29 100644 --- a/apps/ui/src/components/views/setup-view/components/cli-installation-card.tsx +++ b/apps/ui/src/components/views/setup-view/components/cli-installation-card.tsx @@ -1,6 +1,7 @@ import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/components/ui/card'; import { Button } from '@/components/ui/button'; -import { Download, Loader2, AlertCircle } from 'lucide-react'; +import { Download, AlertCircle } from 'lucide-react'; +import { Spinner } from '@/components/ui/spinner'; import { CopyableCommandField } from './copyable-command-field'; import { TerminalOutput } from './terminal-output'; @@ -59,7 +60,7 @@ export function CliInstallationCard({ > {isInstalling ? ( <> - + Installing... ) : ( diff --git a/apps/ui/src/components/views/setup-view/components/status-badge.tsx b/apps/ui/src/components/views/setup-view/components/status-badge.tsx index 38692a0b..53869d07 100644 --- a/apps/ui/src/components/views/setup-view/components/status-badge.tsx +++ b/apps/ui/src/components/views/setup-view/components/status-badge.tsx @@ -1,4 +1,5 @@ -import { CheckCircle2, XCircle, Loader2, AlertCircle } from 'lucide-react'; +import { CheckCircle2, XCircle, AlertCircle } from 'lucide-react'; +import { Spinner } from '@/components/ui/spinner'; interface StatusBadgeProps { status: @@ -34,7 +35,7 @@ export function StatusBadge({ status, label }: StatusBadgeProps) { }; case 'checking': return { - icon: , + icon: , className: 'bg-yellow-500/10 text-yellow-500 border-yellow-500/20', }; case 'unverified': diff --git a/apps/ui/src/components/views/setup-view/steps/claude-setup-step.tsx b/apps/ui/src/components/views/setup-view/steps/claude-setup-step.tsx index 8b56f49c..87bf6f77 100644 --- a/apps/ui/src/components/views/setup-view/steps/claude-setup-step.tsx +++ b/apps/ui/src/components/views/setup-view/steps/claude-setup-step.tsx @@ -14,7 +14,6 @@ import { useAppStore } from '@/store/app-store'; import { getElectronAPI } from '@/lib/electron'; import { CheckCircle2, - Loader2, Key, ArrowRight, ArrowLeft, @@ -27,6 +26,7 @@ import { XCircle, Trash2, } from 'lucide-react'; +import { Spinner } from '@/components/ui/spinner'; import { toast } from 'sonner'; import { StatusBadge, TerminalOutput } from '../components'; import { useCliStatus, useCliInstallation, useTokenSave } from '../hooks'; @@ -330,7 +330,7 @@ export function ClaudeSetupStep({ onNext, onBack, onSkip }: ClaudeSetupStepProps Authentication Methods
@@ -412,7 +412,7 @@ export function ClaudeSetupStep({ onNext, onBack, onSkip }: ClaudeSetupStepProps > {isInstalling ? ( <> - + Installing... ) : ( @@ -435,7 +435,7 @@ export function ClaudeSetupStep({ onNext, onBack, onSkip }: ClaudeSetupStepProps {/* CLI Verification Status */} {cliVerificationStatus === 'verifying' && (
- +

Verifying CLI authentication...

Running a test query

@@ -494,7 +494,7 @@ export function ClaudeSetupStep({ onNext, onBack, onSkip }: ClaudeSetupStepProps > {cliVerificationStatus === 'verifying' ? ( <> - + Verifying... ) : cliVerificationStatus === 'error' ? ( @@ -574,7 +574,7 @@ export function ClaudeSetupStep({ onNext, onBack, onSkip }: ClaudeSetupStepProps > {isSavingApiKey ? ( <> - + Saving... ) : ( @@ -589,11 +589,7 @@ export function ClaudeSetupStep({ onNext, onBack, onSkip }: ClaudeSetupStepProps className="border-red-500/50 text-red-500 hover:bg-red-500/10 hover:text-red-400" data-testid="delete-anthropic-key-button" > - {isDeletingApiKey ? ( - - ) : ( - - )} + {isDeletingApiKey ? : } )}
@@ -602,7 +598,7 @@ export function ClaudeSetupStep({ onNext, onBack, onSkip }: ClaudeSetupStepProps {/* API Key Verification Status */} {apiKeyVerificationStatus === 'verifying' && (
- +

Verifying API key...

Running a test query

@@ -642,7 +638,7 @@ export function ClaudeSetupStep({ onNext, onBack, onSkip }: ClaudeSetupStepProps > {apiKeyVerificationStatus === 'verifying' ? ( <> - + Verifying... ) : apiKeyVerificationStatus === 'error' ? ( diff --git a/apps/ui/src/components/views/setup-view/steps/cli-setup-step.tsx b/apps/ui/src/components/views/setup-view/steps/cli-setup-step.tsx index cf581f8c..031d6815 100644 --- a/apps/ui/src/components/views/setup-view/steps/cli-setup-step.tsx +++ b/apps/ui/src/components/views/setup-view/steps/cli-setup-step.tsx @@ -14,7 +14,6 @@ import { useAppStore } from '@/store/app-store'; import { getElectronAPI } from '@/lib/electron'; import { CheckCircle2, - Loader2, Key, ArrowRight, ArrowLeft, @@ -27,6 +26,7 @@ import { XCircle, Trash2, } from 'lucide-react'; +import { Spinner } from '@/components/ui/spinner'; import { toast } from 'sonner'; import { StatusBadge, TerminalOutput } from '../components'; import { useCliStatus, useCliInstallation, useTokenSave } from '../hooks'; @@ -332,7 +332,7 @@ export function CliSetupStep({ config, state, onNext, onBack, onSkip }: CliSetup Authentication Methods
Choose one of the following methods to authenticate: @@ -408,7 +408,7 @@ export function CliSetupStep({ config, state, onNext, onBack, onSkip }: CliSetup > {isInstalling ? ( <> - + Installing... ) : ( @@ -427,7 +427,7 @@ export function CliSetupStep({ config, state, onNext, onBack, onSkip }: CliSetup {cliVerificationStatus === 'verifying' && (
- +

Verifying CLI authentication...

Running a test query

@@ -605,7 +605,7 @@ export function CliSetupStep({ config, state, onNext, onBack, onSkip }: CliSetup > {cliVerificationStatus === 'verifying' ? ( <> - + Verifying... ) : cliVerificationStatus === 'error' ? ( @@ -681,7 +681,7 @@ export function CliSetupStep({ config, state, onNext, onBack, onSkip }: CliSetup > {isSavingApiKey ? ( <> - + Saving... ) : ( @@ -696,11 +696,7 @@ export function CliSetupStep({ config, state, onNext, onBack, onSkip }: CliSetup className="border-red-500/50 text-red-500 hover:bg-red-500/10 hover:text-red-400" data-testid={config.testIds.deleteApiKeyButton} > - {isDeletingApiKey ? ( - - ) : ( - - )} + {isDeletingApiKey ? : } )}
@@ -708,7 +704,7 @@ export function CliSetupStep({ config, state, onNext, onBack, onSkip }: CliSetup {apiKeyVerificationStatus === 'verifying' && (
- +

Verifying API key...

Running a test query

@@ -767,7 +763,7 @@ export function CliSetupStep({ config, state, onNext, onBack, onSkip }: CliSetup > {apiKeyVerificationStatus === 'verifying' ? ( <> - + Verifying... ) : apiKeyVerificationStatus === 'error' ? ( diff --git a/apps/ui/src/components/views/setup-view/steps/cursor-setup-step.tsx b/apps/ui/src/components/views/setup-view/steps/cursor-setup-step.tsx index ff591f1a..e48057c4 100644 --- a/apps/ui/src/components/views/setup-view/steps/cursor-setup-step.tsx +++ b/apps/ui/src/components/views/setup-view/steps/cursor-setup-step.tsx @@ -7,7 +7,6 @@ import { useSetupStore } from '@/store/setup-store'; import { getElectronAPI } from '@/lib/electron'; import { CheckCircle2, - Loader2, ArrowRight, ArrowLeft, ExternalLink, @@ -16,6 +15,7 @@ import { AlertTriangle, XCircle, } from 'lucide-react'; +import { Spinner } from '@/components/ui/spinner'; import { toast } from 'sonner'; import { StatusBadge } from '../components'; import { CursorIcon } from '@/components/ui/provider-icon'; @@ -204,7 +204,7 @@ export function CursorSetupStep({ onNext, onBack, onSkip }: CursorSetupStepProps
{getStatusBadge()}
@@ -318,7 +318,7 @@ export function CursorSetupStep({ onNext, onBack, onSkip }: CursorSetupStepProps > {isLoggingIn ? ( <> - + Waiting for login... ) : ( @@ -332,7 +332,7 @@ export function CursorSetupStep({ onNext, onBack, onSkip }: CursorSetupStepProps {/* Loading State */} {isChecking && (
- +

Checking Cursor CLI status...

diff --git a/apps/ui/src/components/views/setup-view/steps/github-setup-step.tsx b/apps/ui/src/components/views/setup-view/steps/github-setup-step.tsx index fcccb618..3a20ee24 100644 --- a/apps/ui/src/components/views/setup-view/steps/github-setup-step.tsx +++ b/apps/ui/src/components/views/setup-view/steps/github-setup-step.tsx @@ -6,7 +6,6 @@ import { useSetupStore } from '@/store/setup-store'; import { getElectronAPI } from '@/lib/electron'; import { CheckCircle2, - Loader2, ArrowRight, ArrowLeft, ExternalLink, @@ -16,6 +15,7 @@ import { Github, XCircle, } from 'lucide-react'; +import { Spinner } from '@/components/ui/spinner'; import { toast } from 'sonner'; import { StatusBadge } from '../components'; @@ -116,7 +116,7 @@ export function GitHubSetupStep({ onNext, onBack, onSkip }: GitHubSetupStepProps
{getStatusBadge()}
@@ -252,7 +252,7 @@ export function GitHubSetupStep({ onNext, onBack, onSkip }: GitHubSetupStepProps {/* Loading State */} {isChecking && (
- +

Checking GitHub CLI status...

diff --git a/apps/ui/src/components/views/setup-view/steps/opencode-setup-step.tsx b/apps/ui/src/components/views/setup-view/steps/opencode-setup-step.tsx index 5e7e29c0..58337851 100644 --- a/apps/ui/src/components/views/setup-view/steps/opencode-setup-step.tsx +++ b/apps/ui/src/components/views/setup-view/steps/opencode-setup-step.tsx @@ -7,7 +7,6 @@ import { useSetupStore } from '@/store/setup-store'; import { getElectronAPI } from '@/lib/electron'; import { CheckCircle2, - Loader2, ArrowRight, ArrowLeft, ExternalLink, @@ -17,6 +16,7 @@ import { XCircle, Terminal, } from 'lucide-react'; +import { Spinner } from '@/components/ui/spinner'; import { toast } from 'sonner'; import { StatusBadge } from '../components'; @@ -204,7 +204,7 @@ export function OpencodeSetupStep({ onNext, onBack, onSkip }: OpencodeSetupStepP
{getStatusBadge()}
@@ -316,7 +316,7 @@ export function OpencodeSetupStep({ onNext, onBack, onSkip }: OpencodeSetupStepP > {isLoggingIn ? ( <> - + Waiting for login... ) : ( @@ -330,7 +330,7 @@ export function OpencodeSetupStep({ onNext, onBack, onSkip }: OpencodeSetupStepP {/* Loading State */} {isChecking && (
- +

Checking OpenCode CLI status...

diff --git a/apps/ui/src/components/views/setup-view/steps/providers-setup-step.tsx b/apps/ui/src/components/views/setup-view/steps/providers-setup-step.tsx index b9ad3263..53b3ca0b 100644 --- a/apps/ui/src/components/views/setup-view/steps/providers-setup-step.tsx +++ b/apps/ui/src/components/views/setup-view/steps/providers-setup-step.tsx @@ -17,7 +17,6 @@ import { ArrowRight, ArrowLeft, CheckCircle2, - Loader2, Key, ExternalLink, Copy, @@ -29,6 +28,7 @@ import { Terminal, AlertCircle, } from 'lucide-react'; +import { Spinner } from '@/components/ui/spinner'; import { toast } from 'sonner'; import { cn } from '@/lib/utils'; import { AnthropicIcon, CursorIcon, OpenAIIcon, OpenCodeIcon } from '@/components/ui/provider-icon'; @@ -240,7 +240,7 @@ function ClaudeContent() { onClick={checkStatus} disabled={isChecking || isVerifying} > - + {isChecking || isVerifying ? : }
@@ -278,7 +278,7 @@ function ClaudeContent() { {/* Checking/Verifying State */} {(isChecking || isVerifying) && (
- +

{isChecking ? 'Checking Claude CLI status...' : 'Verifying authentication...'}

@@ -322,7 +322,7 @@ function ClaudeContent() { > {isInstalling ? ( <> - + Installing... ) : ( @@ -417,11 +417,7 @@ function ClaudeContent() { disabled={isSavingApiKey || !apiKey.trim()} className="flex-1 bg-brand-500 hover:bg-brand-600 text-white" > - {isSavingApiKey ? ( - - ) : ( - 'Save API Key' - )} + {isSavingApiKey ? : 'Save API Key'} {hasApiKey && (
@@ -658,7 +654,7 @@ function CursorContent() { > {isLoggingIn ? ( <> - + Waiting for login... ) : ( @@ -671,7 +667,7 @@ function CursorContent() { {isChecking && (
- +

Checking Cursor CLI status...

)} @@ -807,7 +803,7 @@ function CodexContent() { Codex CLI Status
@@ -915,7 +911,7 @@ function CodexContent() { > {isLoggingIn ? ( <> - + Waiting for login... ) : ( @@ -958,7 +954,7 @@ function CodexContent() { disabled={isSaving || !apiKey.trim()} className="w-full bg-brand-500 hover:bg-brand-600 text-white" > - {isSaving ? : 'Save API Key'} + {isSaving ? : 'Save API Key'} @@ -968,7 +964,7 @@ function CodexContent() { {isChecking && (
- +

Checking Codex CLI status...

)} @@ -1082,7 +1078,7 @@ function OpencodeContent() { OpenCode CLI Status
@@ -1191,7 +1187,7 @@ function OpencodeContent() { > {isLoggingIn ? ( <> - + Waiting for login... ) : ( @@ -1204,7 +1200,7 @@ function OpencodeContent() { {isChecking && (
- +

Checking OpenCode CLI status...

)} @@ -1416,7 +1412,7 @@ export function ProvidersSetupStep({ onNext, onBack }: ProvidersSetupStepProps) ); case 'verifying': return ( - + ); case 'installed_not_auth': return ( @@ -1436,7 +1432,7 @@ export function ProvidersSetupStep({ onNext, onBack }: ProvidersSetupStepProps) {isInitialChecking && (
- +

Checking provider status...

)} diff --git a/apps/ui/src/components/views/spec-view.tsx b/apps/ui/src/components/views/spec-view.tsx index 616dc4dd..88fec94b 100644 --- a/apps/ui/src/components/views/spec-view.tsx +++ b/apps/ui/src/components/views/spec-view.tsx @@ -1,6 +1,6 @@ import { useState } from 'react'; -import { RefreshCw } from 'lucide-react'; import { useAppStore } from '@/store/app-store'; +import { Spinner } from '@/components/ui/spinner'; // Extracted hooks import { useSpecLoading, useSpecSave, useSpecGeneration } from './spec-view/hooks'; @@ -86,7 +86,7 @@ export function SpecView() { if (isLoading) { return (
- +
); } diff --git a/apps/ui/src/components/views/spec-view/components/spec-empty-state.tsx b/apps/ui/src/components/views/spec-view/components/spec-empty-state.tsx index fa1792b1..ce7c1667 100644 --- a/apps/ui/src/components/views/spec-view/components/spec-empty-state.tsx +++ b/apps/ui/src/components/views/spec-view/components/spec-empty-state.tsx @@ -1,5 +1,6 @@ import { Button } from '@/components/ui/button'; -import { FileText, FilePlus2, Loader2 } from 'lucide-react'; +import { FileText, FilePlus2 } from 'lucide-react'; +import { Spinner } from '@/components/ui/spinner'; import { PHASE_LABELS } from '../constants'; interface SpecEmptyStateProps { @@ -36,7 +37,7 @@ export function SpecEmptyState({ {isProcessing && (
- +
@@ -64,7 +65,7 @@ export function SpecEmptyState({
{isCreating ? ( - + ) : ( )} diff --git a/apps/ui/src/components/views/spec-view/components/spec-header.tsx b/apps/ui/src/components/views/spec-view/components/spec-header.tsx index b38a6579..72d879dd 100644 --- a/apps/ui/src/components/views/spec-view/components/spec-header.tsx +++ b/apps/ui/src/components/views/spec-view/components/spec-header.tsx @@ -3,7 +3,8 @@ import { HeaderActionsPanel, HeaderActionsPanelTrigger, } from '@/components/ui/header-actions-panel'; -import { Save, Sparkles, Loader2, FileText, AlertCircle, ListPlus, RefreshCcw } from 'lucide-react'; +import { Save, Sparkles, FileText, AlertCircle, ListPlus, RefreshCcw } from 'lucide-react'; +import { Spinner } from '@/components/ui/spinner'; import { PHASE_LABELS } from '../constants'; interface SpecHeaderProps { @@ -59,7 +60,7 @@ export function SpecHeader({ {isProcessing && (
- +
@@ -83,7 +84,7 @@ export function SpecHeader({ {/* Mobile processing indicator */} {isProcessing && (
- + Processing...
)} @@ -157,7 +158,7 @@ export function SpecHeader({ {/* Status messages in panel */} {isProcessing && (
- +
{isSyncing diff --git a/apps/ui/src/components/views/spec-view/dialogs/create-spec-dialog.tsx b/apps/ui/src/components/views/spec-view/dialogs/create-spec-dialog.tsx index 73389f78..f77b08ca 100644 --- a/apps/ui/src/components/views/spec-view/dialogs/create-spec-dialog.tsx +++ b/apps/ui/src/components/views/spec-view/dialogs/create-spec-dialog.tsx @@ -1,4 +1,5 @@ -import { Sparkles, Clock, Loader2 } from 'lucide-react'; +import { Sparkles, Clock } from 'lucide-react'; +import { Spinner } from '@/components/ui/spinner'; import { Dialog, DialogContent, @@ -163,7 +164,7 @@ export function CreateSpecDialog({ > {isCreatingSpec ? ( <> - + Generating... ) : ( diff --git a/apps/ui/src/components/views/spec-view/dialogs/regenerate-spec-dialog.tsx b/apps/ui/src/components/views/spec-view/dialogs/regenerate-spec-dialog.tsx index fd534a58..c911fc94 100644 --- a/apps/ui/src/components/views/spec-view/dialogs/regenerate-spec-dialog.tsx +++ b/apps/ui/src/components/views/spec-view/dialogs/regenerate-spec-dialog.tsx @@ -1,4 +1,5 @@ -import { Sparkles, Clock, Loader2 } from 'lucide-react'; +import { Sparkles, Clock } from 'lucide-react'; +import { Spinner } from '@/components/ui/spinner'; import { Dialog, DialogContent, @@ -158,7 +159,7 @@ export function RegenerateSpecDialog({ > {isRegenerating ? ( <> - + Regenerating... ) : ( diff --git a/apps/ui/src/components/views/terminal-view.tsx b/apps/ui/src/components/views/terminal-view.tsx index 328afc21..0287ca68 100644 --- a/apps/ui/src/components/views/terminal-view.tsx +++ b/apps/ui/src/components/views/terminal-view.tsx @@ -7,13 +7,13 @@ import { Unlock, SplitSquareHorizontal, SplitSquareVertical, - Loader2, AlertCircle, RefreshCw, X, SquarePlus, Settings, } from 'lucide-react'; +import { Spinner } from '@/components/ui/spinner'; import { getServerUrlSync } from '@/lib/http-api-client'; import { useAppStore, @@ -1279,7 +1279,7 @@ export function TerminalView() { if (loading) { return (
- +
); } @@ -1342,7 +1342,7 @@ export function TerminalView() { {authError &&

{authError}

}