diff --git a/frontend/src/components/layouts/app/app-header.tsx b/frontend/src/components/layouts/app/app-header.tsx index 8d879061..73de02bf 100644 --- a/frontend/src/components/layouts/app/app-header.tsx +++ b/frontend/src/components/layouts/app/app-header.tsx @@ -1,11 +1,10 @@ import type { ReactNode } from 'react'; -import { Loader2 } from 'lucide-react'; - import { Breadcrumb, BreadcrumbItem, BreadcrumbList, BreadcrumbPage } from '@/components/ui/breadcrumb'; import { Button, type ButtonProps } from '@/components/ui/button'; import { Separator } from '@/components/ui/separator'; import { SidebarTrigger } from '@/components/ui/sidebar'; +import { Spinner } from '@/components/ui/spinner'; import { cn } from '@/lib/utils'; interface AppHeaderActionProps extends Omit { @@ -49,7 +48,7 @@ export function AppHeaderAction({ size={size} {...props} > - {loading ? : icon} + {loading ? : icon} {label} {endIcon ? {endIcon} : null} diff --git a/frontend/src/components/layouts/main/main-sidebar.tsx b/frontend/src/components/layouts/main/main-sidebar.tsx index d917965b..4c419a0c 100644 --- a/frontend/src/components/layouts/main/main-sidebar.tsx +++ b/frontend/src/components/layouts/main/main-sidebar.tsx @@ -297,7 +297,7 @@ export function MainSidebar() { > - +
@@ -347,21 +347,21 @@ export function MainSidebar() { className="dark:data-[state=active]:bg-card h-6 px-2" value="system" > - + - + - + diff --git a/frontend/src/components/layouts/settings/settings-sidebar.tsx b/frontend/src/components/layouts/settings/settings-sidebar.tsx index 584eb6f2..1ea570f2 100644 --- a/frontend/src/components/layouts/settings/settings-sidebar.tsx +++ b/frontend/src/components/layouts/settings/settings-sidebar.tsx @@ -93,7 +93,7 @@ export function SettingsSidebar() { - + Back to App diff --git a/frontend/src/components/shared/README.md b/frontend/src/components/shared/README.md index efd9334f..111f5cde 100644 --- a/frontend/src/components/shared/README.md +++ b/frontend/src/components/shared/README.md @@ -39,10 +39,10 @@ that every list reuses. ## Components -| File | Role | -| ---------------------------------------------------------- | ------------------------------------------------------------------------------------------------------- | -| [`detail-navigation/`](detail-navigation/) | Prev / Position / Next toolbar + listbox sheet for detail pages, and the navigation hooks that feed it. | -| [`inline-edit/`](inline-edit/) | Generic inline-edit input (Save/Cancel addons, Enter/Escape) plus the paired `useInlineEdit` state machine. | +| File | Role | +| ------------------------------------------ | ----------------------------------------------------------------------------------------------------------- | +| [`detail-navigation/`](detail-navigation/) | Prev / Position / Next toolbar + listbox sheet for detail pages, and the navigation hooks that feed it. | +| [`inline-edit/`](inline-edit/) | Generic inline-edit input (Save/Cancel addons, Enter/Escape) plus the paired `useInlineEdit` state machine. | ## Hooks diff --git a/frontend/src/components/shared/confirmation-dialog.tsx b/frontend/src/components/shared/confirmation-dialog.tsx index 6c87d0a3..bd173877 100644 --- a/frontend/src/components/shared/confirmation-dialog.tsx +++ b/frontend/src/components/shared/confirmation-dialog.tsx @@ -1,6 +1,6 @@ import type { ReactElement } from 'react'; -import { Loader2, Trash2 } from 'lucide-react'; +import { Trash2 } from 'lucide-react'; import { cloneElement, isValidElement, useState } from 'react'; import { Button } from '@/components/ui/button'; @@ -12,6 +12,7 @@ import { DialogHeader, DialogTitle, } from '@/components/ui/dialog'; +import { Spinner } from '@/components/ui/spinner'; import { cn } from '@/lib/utils'; type ConfirmationDialogIconProps = ReactElement>; @@ -127,7 +128,7 @@ function ConfirmationDialog({ }} variant={confirmVariant} > - {isProcessing ? : processIcon(confirmIcon)} + {isProcessing ? : processIcon(confirmIcon)} {confirmText} diff --git a/frontend/src/components/shared/file-manager/file-manager-bulk-actions-bar.tsx b/frontend/src/components/shared/file-manager/file-manager-bulk-actions-bar.tsx index 11d05af0..319e9b72 100644 --- a/frontend/src/components/shared/file-manager/file-manager-bulk-actions-bar.tsx +++ b/frontend/src/components/shared/file-manager/file-manager-bulk-actions-bar.tsx @@ -184,7 +184,7 @@ export function FileManagerBulkActionsBar({ handleActionClick(action); }} > - {action.icon ? : null} + {action.icon ? : null} {action.label} ))} diff --git a/frontend/src/components/shared/inline-edit/inline-edit-input.tsx b/frontend/src/components/shared/inline-edit/inline-edit-input.tsx index 656efbad..7655064f 100644 --- a/frontend/src/components/shared/inline-edit/inline-edit-input.tsx +++ b/frontend/src/components/shared/inline-edit/inline-edit-input.tsx @@ -1,7 +1,8 @@ -import { Check, Loader2, X } from 'lucide-react'; +import { Check, X } from 'lucide-react'; import { type KeyboardEvent, type Ref } from 'react'; import { InputGroup, InputGroupAddon, InputGroupButton, InputGroupInput } from '@/components/ui/input-group'; +import { Spinner } from '@/components/ui/spinner'; import { cn } from '@/lib/utils'; interface InlineEditInputProps { @@ -98,7 +99,7 @@ export function InlineEditInput({ disabled={busy} onClick={onSave} > - {busy ? : } + {busy ? : } - {isProcessing ? : } + {isProcessing ? : } {primaryLabel} ); } diff --git a/frontend/src/components/ui/form-submit-button.tsx b/frontend/src/components/ui/form-submit-button.tsx index 6d501db5..4f991fdf 100644 --- a/frontend/src/components/ui/form-submit-button.tsx +++ b/frontend/src/components/ui/form-submit-button.tsx @@ -1,7 +1,7 @@ -import { Loader2 } from 'lucide-react'; import { useFormContext } from 'react-hook-form'; import { Button } from '@/components/ui/button'; +import { Spinner } from '@/components/ui/spinner'; interface FormSubmitButtonProps extends React.ComponentProps { /** @@ -54,7 +54,7 @@ function FormSubmitButton({ children, icon, loading, requireValid = true, ...pro const isFormInvalid = !!formState && requireValid && formState.isSubmitted && !formState.isValid; const isDisabled = isSubmitting || isFormInvalid; - const renderedIcon = isSubmitting ? : icon; + const renderedIcon = isSubmitting ? : icon; return ( diff --git a/frontend/src/features/flows/files/flow-files.tsx b/frontend/src/features/flows/files/flow-files.tsx index de5e805f..eccb6eab 100644 --- a/frontend/src/features/flows/files/flow-files.tsx +++ b/frontend/src/features/flows/files/flow-files.tsx @@ -1,4 +1,4 @@ -import { ArrowDownToLine, FolderInput, FolderOutput, FolderUp, Loader2, Search, Upload, X } from 'lucide-react'; +import { ArrowDownToLine, FolderInput, FolderOutput, FolderUp, Search, Upload, X } from 'lucide-react'; import { useCallback, useMemo, useState } from 'react'; import { toast } from 'sonner'; @@ -20,6 +20,7 @@ import { Button } from '@/components/ui/button'; import { Empty, EmptyDescription, EmptyHeader, EmptyMedia, EmptyTitle } from '@/components/ui/empty'; import { Form, FormControl, FormField, FormItem } from '@/components/ui/form'; import { InputGroup, InputGroupAddon, InputGroupButton, InputGroupInput } from '@/components/ui/input-group'; +import { Spinner } from '@/components/ui/spinner'; import { Tooltip, TooltipContent, TooltipTrigger } from '@/components/ui/tooltip'; import { StatusType } from '@/graphql/types'; import { useFilesDragAndDrop } from '@/hooks/use-files-drag-and-drop'; @@ -255,7 +256,7 @@ function FlowFiles() { type="button" variant="outline" > - {upload.isUploading ? : } + {upload.isUploading ? : } diff --git a/frontend/src/features/flows/messages/flow-assistant-messages.tsx b/frontend/src/features/flows/messages/flow-assistant-messages.tsx index 71fbcc1d..9dfb5980 100644 --- a/frontend/src/features/flows/messages/flow-assistant-messages.tsx +++ b/frontend/src/features/flows/messages/flow-assistant-messages.tsx @@ -1,5 +1,5 @@ import { zodResolver } from '@hookform/resolvers/zod'; -import { Check, ChevronDown, ListFilter, Loader2, Plus, Search, Trash2, X } from 'lucide-react'; +import { Check, ChevronDown, ListFilter, Plus, Search, Trash2, X } from 'lucide-react'; import { useEffect, useMemo, useState } from 'react'; import { useForm } from 'react-hook-form'; import { useDebouncedCallback } from 'use-debounce'; @@ -16,6 +16,7 @@ import { Empty, EmptyContent, EmptyDescription, EmptyHeader, EmptyMedia, EmptyTi import { Form, FormControl, FormField } from '@/components/ui/form'; import { InputGroup, InputGroupAddon, InputGroupButton, InputGroupInput } from '@/components/ui/input-group'; import { Popover, PopoverContent, PopoverTrigger } from '@/components/ui/popover'; +import { Spinner } from '@/components/ui/spinner'; import { StatusType } from '@/graphql/types'; import { useAutoScroll } from '@/hooks/use-auto-scroll'; import { Log } from '@/lib/log'; @@ -549,7 +550,7 @@ function FlowAssistantMessages({ className }: FlowAssistantMessagesProps) { - + Creating assistant... Please wait while we set up your new assistant diff --git a/frontend/src/features/flows/terminal/flow-terminal.tsx b/frontend/src/features/flows/terminal/flow-terminal.tsx index 3cd0e2c0..a94b2a81 100644 --- a/frontend/src/features/flows/terminal/flow-terminal.tsx +++ b/frontend/src/features/flows/terminal/flow-terminal.tsx @@ -177,7 +177,7 @@ function FlowTerminal() { title="Previous match" type="button" > - + - + )} @@ -196,7 +196,7 @@ function FlowTerminal() { title="Clear search" type="button" > - + )} diff --git a/frontend/src/features/knowledges/knowledge-header.tsx b/frontend/src/features/knowledges/knowledge-header.tsx index ad27b3ed..07bb52e9 100644 --- a/frontend/src/features/knowledges/knowledge-header.tsx +++ b/frontend/src/features/knowledges/knowledge-header.tsx @@ -1,6 +1,6 @@ import type { ReactNode } from 'react'; -import { Ellipsis, HatGlasses, LibraryBig, Loader2, Pencil, Trash } from 'lucide-react'; +import { Ellipsis, HatGlasses, LibraryBig, Pencil, Trash } from 'lucide-react'; import { useCallback, useState } from 'react'; import { useNavigate } from 'react-router-dom'; import { toast } from 'sonner'; @@ -236,12 +236,12 @@ export function KnowledgeHeader({ > {isAnonymizing ? ( <> - + Anonymizing... ) : ( <> - + Anonymize )} @@ -254,7 +254,7 @@ export function KnowledgeHeader({ className="cursor-default hover:bg-transparent focus:bg-transparent" onSelect={(event) => event.preventDefault()} > - + Knowledges
@@ -302,12 +302,12 @@ export function KnowledgeHeader({ > {isDeleting ? ( <> - + Deleting... ) : ( <> - + Delete )} diff --git a/frontend/src/pages/flows/flow.tsx b/frontend/src/pages/flows/flow.tsx index a0a3137b..1a889b2f 100644 --- a/frontend/src/pages/flows/flow.tsx +++ b/frontend/src/pages/flows/flow.tsx @@ -41,6 +41,7 @@ import { DropdownMenuTrigger, } from '@/components/ui/dropdown-menu'; import { ResizableHandle, ResizablePanel, ResizablePanelGroup } from '@/components/ui/resizable'; +import { Spinner } from '@/components/ui/spinner'; import { Tooltip, TooltipContent, TooltipTrigger } from '@/components/ui/tooltip'; import FlowCentralTabs from '@/features/flows/flow-central-tabs'; import FlowTabs from '@/features/flows/flow-tabs'; @@ -295,7 +296,7 @@ function Flow() { className="cursor-default hover:bg-transparent focus:bg-transparent" onSelect={(event) => event.preventDefault()} > - + Flows
@@ -331,7 +332,7 @@ function Flow() { > {isFinishing ? ( <> - + Finishing... ) : ( @@ -349,12 +350,12 @@ function Flow() { > {isDeleting ? ( <> - + Deleting... ) : ( <> - + Delete )} @@ -496,7 +497,7 @@ function FlowReportDropdown() { disabled={isReportDisabled} onClick={handleOpenWebView} > - + Open web view - + Copy to clipboard - + Download MD - + Download PDF diff --git a/frontend/src/pages/flows/flows.tsx b/frontend/src/pages/flows/flows.tsx index 8c1cf8eb..ba00d0f7 100644 --- a/frontend/src/pages/flows/flows.tsx +++ b/frontend/src/pages/flows/flows.tsx @@ -30,6 +30,7 @@ import { DropdownMenuTrigger, } from '@/components/ui/dropdown-menu'; import { Empty, EmptyContent, EmptyDescription, EmptyHeader, EmptyMedia, EmptyTitle } from '@/components/ui/empty'; +import { Spinner } from '@/components/ui/spinner'; import { Toggle } from '@/components/ui/toggle'; import { Tooltip, TooltipContent, TooltipTrigger } from '@/components/ui/tooltip'; import { RenameFlowDocument, ResultType, StatusType, type TerminalFragmentFragment } from '@/graphql/types'; @@ -416,7 +417,7 @@ function Flows() { size="sm" variant="outline" > - + @@ -449,7 +450,7 @@ function Flows() { > {finishingFlowIds.has(flow.id) ? ( <> - + Finishing... ) : ( @@ -467,12 +468,12 @@ function Flows() { > {deletingFlowIds.has(flow.id) ? ( <> - + Deleting... ) : ( <> - + Delete )} diff --git a/frontend/src/pages/knowledges/knowledges.tsx b/frontend/src/pages/knowledges/knowledges.tsx index edcc7826..6e7d351e 100644 --- a/frontend/src/pages/knowledges/knowledges.tsx +++ b/frontend/src/pages/knowledges/knowledges.tsx @@ -29,6 +29,7 @@ import { } from '@/components/ui/dropdown-menu'; import { Empty, EmptyContent, EmptyDescription, EmptyHeader, EmptyMedia, EmptyTitle } from '@/components/ui/empty'; import { InputSearch } from '@/components/ui/input-search'; +import { Spinner } from '@/components/ui/spinner'; import { KnowledgeDocType } from '@/graphql/types'; import { useTableState } from '@/hooks/use-table-state'; import { routes } from '@/lib/routes'; @@ -328,12 +329,12 @@ function Knowledges() { > {deletingIds.has(k.id) ? ( <> - + Deleting... ) : ( <> - + Delete )} diff --git a/frontend/src/pages/resources/resources.tsx b/frontend/src/pages/resources/resources.tsx index 47c7a247..e7daeef4 100644 --- a/frontend/src/pages/resources/resources.tsx +++ b/frontend/src/pages/resources/resources.tsx @@ -1,15 +1,4 @@ -import { - ColumnsSettings, - Copy, - FileSymlink, - Folder, - FolderPlus, - FolderUp, - Loader2, - Search, - Upload, - X, -} from 'lucide-react'; +import { ColumnsSettings, Copy, FileSymlink, Folder, FolderPlus, FolderUp, Search, Upload, X } from 'lucide-react'; import { useCallback, useMemo, useState } from 'react'; import { toast } from 'sonner'; @@ -53,6 +42,7 @@ import { import { Empty, EmptyDescription, EmptyHeader, EmptyMedia, EmptyTitle } from '@/components/ui/empty'; import { FileDropZone } from '@/components/ui/file-drop-zone'; import { InputGroup, InputGroupAddon, InputGroupButton, InputGroupInput } from '@/components/ui/input-group'; +import { Spinner } from '@/components/ui/spinner'; import { ResourcesCopyDialog } from '@/features/resources/resources-copy-dialog'; import { ResourcesMkdirDialog } from '@/features/resources/resources-mkdir-dialog'; import { ResourcesMoveDialog } from '@/features/resources/resources-move-dialog'; @@ -405,7 +395,7 @@ function Resources() { : } + icon={upload.isUploading ? : } label={upload.isUploading ? 'Uploading...' : 'Upload files'} onClick={upload.openFilePicker} variant="secondary" diff --git a/frontend/src/pages/settings/settings-api-tokens.tsx b/frontend/src/pages/settings/settings-api-tokens.tsx index 853a6f33..db78cfe5 100644 --- a/frontend/src/pages/settings/settings-api-tokens.tsx +++ b/frontend/src/pages/settings/settings-api-tokens.tsx @@ -50,6 +50,7 @@ import { Empty, EmptyContent, EmptyDescription, EmptyHeader, EmptyMedia, EmptyTi import { Input } from '@/components/ui/input'; import { Popover, PopoverContent, PopoverTrigger } from '@/components/ui/popover'; import { Select, SelectContent, SelectGroup, SelectItem, SelectTrigger, SelectValue } from '@/components/ui/select'; +import { Spinner } from '@/components/ui/spinner'; import { ApiTokenCreatedDocument, ApiTokenDeletedDocument, @@ -188,7 +189,7 @@ function CreateRowActions({ size="icon-sm" variant="ghost" > - {isLoading ? : } + {isLoading ? : } @@ -985,7 +986,7 @@ function SettingsAPITokens() { }} variant="secondary" > - + Copy Token ); }, @@ -509,11 +505,7 @@ function SettingsPrompts() { variant="link" > Tool Name - {sorted === 'asc' ? ( - - ) : sorted === 'desc' ? ( - - ) : null} + {sorted === 'asc' ? : sorted === 'desc' ? : null} ); }, diff --git a/frontend/src/pages/settings/settings-provider.tsx b/frontend/src/pages/settings/settings-provider.tsx index 22321577..6ae2344f 100644 --- a/frontend/src/pages/settings/settings-provider.tsx +++ b/frontend/src/pages/settings/settings-provider.tsx @@ -57,6 +57,7 @@ import { Input } from '@/components/ui/input'; import { InputGroup, InputGroupAddon, InputGroupButton, InputGroupInput } from '@/components/ui/input-group'; import { Popover, PopoverContent, PopoverTrigger } from '@/components/ui/popover'; import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '@/components/ui/select'; +import { Spinner } from '@/components/ui/spinner'; import { AgentConfigType, CreateProviderDocument, @@ -1667,9 +1668,9 @@ function SettingsProvider() { }} > {isAgentTestLoading && currentAgentKey === agentKey ? ( - + ) : ( - + )} {isAgentTestLoading && currentAgentKey === agentKey ? 'Testing...' : 'Test'} @@ -1879,7 +1880,7 @@ function SettingsProvider() { : } + icon={isTestLoading ? : } label={isTestLoading ? 'Testing...' : 'Test'} onClick={() => handleTest()} type="button" @@ -1887,7 +1888,7 @@ function SettingsProvider() { /> } + icon={} label={isNew ? 'Create' : 'Save'} loading={isLoading} type="submit" @@ -1912,11 +1913,7 @@ function SettingsProvider() { disabled={isDeleteLoading} onClick={handleDelete} > - {isDeleteLoading ? ( - - ) : ( - - )} + {isDeleteLoading ? : } {isDeleteLoading ? 'Deleting...' : 'Delete'} diff --git a/frontend/src/pages/settings/settings-providers.tsx b/frontend/src/pages/settings/settings-providers.tsx index 13b67e32..10132f34 100644 --- a/frontend/src/pages/settings/settings-providers.tsx +++ b/frontend/src/pages/settings/settings-providers.tsx @@ -23,6 +23,7 @@ import { DropdownMenuTrigger, } from '@/components/ui/dropdown-menu'; import { Empty, EmptyContent, EmptyDescription, EmptyHeader, EmptyMedia, EmptyTitle } from '@/components/ui/empty'; +import { Spinner } from '@/components/ui/spinner'; import { DeleteProviderDocument, ProviderType, SettingsProvidersDocument } from '@/graphql/types'; import { useTableState } from '@/hooks/use-table-state'; import { routes } from '@/lib/routes'; @@ -90,7 +91,7 @@ export function SettingsProvidersHeader() { key={type} onClick={() => handleProviderCreate(type)} > - {Icon && } + {Icon && } {label} ); @@ -264,7 +265,7 @@ function SettingsProviders() { Edit handleProviderClone(provider.id)}> - + Clone @@ -274,12 +275,12 @@ function SettingsProviders() { > {isDeleteLoading && deletingProvider?.id === provider.id ? ( <> - + Deleting... ) : ( <> - + Delete )} @@ -459,7 +460,7 @@ function SettingsProviders() { onClick={() => navigate(routes.settings.newProvider())} variant="secondary" > - + Add Provider diff --git a/frontend/src/pages/templates/template.tsx b/frontend/src/pages/templates/template.tsx index 3c746166..01a6084b 100644 --- a/frontend/src/pages/templates/template.tsx +++ b/frontend/src/pages/templates/template.tsx @@ -1,17 +1,7 @@ import type { ReactNode } from 'react'; import { skipToken, useQuery } from '@apollo/client/react'; -import { - ChevronDown, - Ellipsis, - FileSymlink, - FileText, - LayoutTemplate, - Loader2, - Pencil, - Save, - Trash, -} from 'lucide-react'; +import { ChevronDown, Ellipsis, FileSymlink, FileText, LayoutTemplate, Pencil, Save, Trash } from 'lucide-react'; import { useCallback, useMemo, useState } from 'react'; import { useNavigate, useParams } from 'react-router-dom'; import { toast } from 'sonner'; @@ -478,7 +468,7 @@ function Template() { } + icon={} label={isNew ? 'Create' : 'Save'} loading={isSaving} type="submit" @@ -507,7 +497,7 @@ function Template() { className="cursor-default hover:bg-transparent focus:bg-transparent" onSelect={(event) => event.preventDefault()} > - + Templates
@@ -521,7 +511,7 @@ function Template() { )} - + Rename @@ -548,12 +538,12 @@ function Template() { > {isDeleting ? ( <> - + Deleting... ) : ( <> - + Delete )} @@ -660,7 +650,7 @@ function Template() { size="sm" variant="secondary" > - + {PRESETS_TITLE} {deletingIds.has(template.id) ? ( <> - + Deleting... ) : ( <> - + Delete )} @@ -281,7 +282,7 @@ function Templates() { onClick={() => navigate(routes.newTemplate)} variant="secondary" > - + New Template