mirror of
https://github.com/vxcontrol/pentagi.git
synced 2026-08-25 12:36:30 +00:00
refactor(ui): adopt the Spinner primitive and drop redundant icon sizing
Two mechanical cleanups over the same files. <Loader2 className="size-4 animate-spin"> and <Loader2 className="animate-spin"> appeared 28 times across 20 files while Spinner variant="circle" — the same LoaderCircleIcon with animate-spin already baked in — was the idiom elsewhere. Loader2 spinners with a deliberate size (size-3/5/6/10/16) or a colour are left alone: Spinner sets no size of its own and would fall back to lucide's 24px. Separately, 51 icons carried className="size-4" inside a Button, DropdownMenuItem or AppHeaderAction, all of which already force [&_svg]:size-4 on descendants, so the class was a no-op. Only those 51 are stripped — the sites picked by walking each icon's real JSX ancestors through the TypeScript AST, because an indentation heuristic mistakes multi-line opening tags for the parent. The 40 icons with no forcing ancestor (Alert, TabsTrigger, AppHeaderTitle, a resize handle) keep their size-4: without it they would render at lucide's 24px. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 4.8
parent
5d15be2f4f
commit
d4dabc2783
@@ -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<ButtonProps, 'children'> {
|
||||
@@ -49,7 +48,7 @@ export function AppHeaderAction({
|
||||
size={size}
|
||||
{...props}
|
||||
>
|
||||
{loading ? <Loader2 className="size-4 animate-spin" /> : icon}
|
||||
{loading ? <Spinner variant="circle" /> : icon}
|
||||
<span className="hidden md:inline">{label}</span>
|
||||
{endIcon ? <span className="hidden md:inline-flex">{endIcon}</span> : null}
|
||||
</Button>
|
||||
|
||||
@@ -297,7 +297,7 @@ export function MainSidebar() {
|
||||
>
|
||||
<Avatar className="bg-background dark:bg-muted size-8 rounded-lg">
|
||||
<AvatarFallback className="flex size-8 items-center justify-center">
|
||||
<UserIcon className="size-4" />
|
||||
<UserIcon />
|
||||
</AvatarFallback>
|
||||
</Avatar>
|
||||
<div className="grid flex-1 text-left text-sm leading-tight">
|
||||
@@ -347,21 +347,21 @@ export function MainSidebar() {
|
||||
className="dark:data-[state=active]:bg-card h-6 px-2"
|
||||
value="system"
|
||||
>
|
||||
<Monitor className="size-4" />
|
||||
<Monitor />
|
||||
</TabsTrigger>
|
||||
<TabsTrigger
|
||||
aria-label="Light theme"
|
||||
className="dark:data-[state=active]:bg-card h-6 px-2"
|
||||
value="light"
|
||||
>
|
||||
<Sun className="size-4" />
|
||||
<Sun />
|
||||
</TabsTrigger>
|
||||
<TabsTrigger
|
||||
aria-label="Dark theme"
|
||||
className="dark:data-[state=active]:bg-card h-6 px-2"
|
||||
value="dark"
|
||||
>
|
||||
<Moon className="size-4" />
|
||||
<Moon />
|
||||
</TabsTrigger>
|
||||
</TabsList>
|
||||
</Tabs>
|
||||
|
||||
@@ -93,7 +93,7 @@ export function SettingsSidebar() {
|
||||
<SidebarFooter>
|
||||
<SidebarMenuButton asChild>
|
||||
<NavLink to={returnUrl}>
|
||||
<ArrowLeft className="size-4" />
|
||||
<ArrowLeft />
|
||||
Back to App
|
||||
</NavLink>
|
||||
</SidebarMenuButton>
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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<React.SVGProps<SVGSVGElement>>;
|
||||
@@ -127,7 +128,7 @@ function ConfirmationDialog({
|
||||
}}
|
||||
variant={confirmVariant}
|
||||
>
|
||||
{isProcessing ? <Loader2 className="size-4 animate-spin" /> : processIcon(confirmIcon)}
|
||||
{isProcessing ? <Spinner variant="circle" /> : processIcon(confirmIcon)}
|
||||
{confirmText}
|
||||
</Button>
|
||||
</DialogFooter>
|
||||
|
||||
@@ -184,7 +184,7 @@ export function FileManagerBulkActionsBar({
|
||||
handleActionClick(action);
|
||||
}}
|
||||
>
|
||||
{action.icon ? <action.icon className="size-4" /> : null}
|
||||
{action.icon ? <action.icon /> : null}
|
||||
{action.label}
|
||||
</DropdownMenuItem>
|
||||
))}
|
||||
|
||||
@@ -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 ? <Loader2 className="animate-spin" /> : <Check />}
|
||||
{busy ? <Spinner variant="circle" /> : <Check />}
|
||||
</InputGroupButton>
|
||||
<InputGroupButton
|
||||
aria-label="Cancel"
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
import type { ComponentType } from 'react';
|
||||
|
||||
import { Loader2, Replace } from 'lucide-react';
|
||||
import { Replace } from 'lucide-react';
|
||||
|
||||
import { Button } from '@/components/ui/button';
|
||||
import { Spinner } from '@/components/ui/spinner';
|
||||
|
||||
interface OverwriteButtonsProps {
|
||||
/**
|
||||
@@ -66,7 +67,7 @@ export function OverwriteButtons({
|
||||
onClick={primaryType === 'submit' ? undefined : onPrimary}
|
||||
type={primaryType}
|
||||
>
|
||||
{isProcessing ? <Loader2 className="animate-spin" /> : <PrimaryIcon />}
|
||||
{isProcessing ? <Spinner variant="circle" /> : <PrimaryIcon />}
|
||||
{primaryLabel}
|
||||
</Button>
|
||||
<Button
|
||||
|
||||
@@ -941,8 +941,8 @@ function DataTableColumnHeader<TData, TValue = unknown>({ column, title }: DataT
|
||||
variant="link"
|
||||
>
|
||||
{title}
|
||||
{sorted === 'asc' ? <ArrowDown className="size-4" /> : null}
|
||||
{sorted === 'desc' ? <ArrowUp className="size-4" /> : null}
|
||||
{sorted === 'asc' ? <ArrowDown /> : null}
|
||||
{sorted === 'desc' ? <ArrowUp /> : null}
|
||||
</Button>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -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<typeof Button> {
|
||||
/**
|
||||
@@ -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 ? <Loader2 className="size-4 animate-spin" /> : icon;
|
||||
const renderedIcon = isSubmitting ? <Spinner variant="circle" /> : icon;
|
||||
|
||||
return (
|
||||
<Button
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { ArrowDownToLine, ArrowUp, FolderOpen, Loader2, RefreshCw, TriangleAlert } from 'lucide-react';
|
||||
import { ArrowDownToLine, ArrowUp, FolderOpen, RefreshCw, TriangleAlert } from 'lucide-react';
|
||||
import { useCallback, useMemo, useState } from 'react';
|
||||
|
||||
import {
|
||||
@@ -28,6 +28,7 @@ import {
|
||||
} from '@/components/ui/dialog';
|
||||
import { Empty, EmptyDescription, EmptyHeader, EmptyMedia, EmptyTitle } from '@/components/ui/empty';
|
||||
import { Label } from '@/components/ui/label';
|
||||
import { Spinner } from '@/components/ui/spinner';
|
||||
import { Tooltip, TooltipContent, TooltipTrigger } from '@/components/ui/tooltip';
|
||||
|
||||
import { findPullConflicts } from './flow-files-conflicts';
|
||||
@@ -443,7 +444,7 @@ function FlowFilesPullDialogForm({ cachedFiles, flowId, onClose, onSuccess }: Fl
|
||||
type="button"
|
||||
variant="outline"
|
||||
>
|
||||
{isListingLoading ? <Loader2 className="animate-spin" /> : <RefreshCw />}
|
||||
{isListingLoading ? <Spinner variant="circle" /> : <RefreshCw />}
|
||||
</Button>
|
||||
</span>
|
||||
</TooltipTrigger>
|
||||
|
||||
@@ -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 ? <Loader2 className="animate-spin" /> : <Upload />}
|
||||
{upload.isUploading ? <Spinner variant="circle" /> : <Upload />}
|
||||
</Button>
|
||||
</span>
|
||||
</TooltipTrigger>
|
||||
|
||||
@@ -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) {
|
||||
<Empty>
|
||||
<EmptyHeader>
|
||||
<EmptyMedia variant="icon">
|
||||
<Loader2 className="animate-spin" />
|
||||
<Spinner variant="circle" />
|
||||
</EmptyMedia>
|
||||
<EmptyTitle>Creating assistant...</EmptyTitle>
|
||||
<EmptyDescription>Please wait while we set up your new assistant</EmptyDescription>
|
||||
|
||||
@@ -177,7 +177,7 @@ function FlowTerminal() {
|
||||
title="Previous match"
|
||||
type="button"
|
||||
>
|
||||
<ChevronUp className="size-4" />
|
||||
<ChevronUp />
|
||||
</InputGroupButton>
|
||||
<InputGroupButton
|
||||
onClick={handleFindNext}
|
||||
@@ -185,7 +185,7 @@ function FlowTerminal() {
|
||||
title="Next match"
|
||||
type="button"
|
||||
>
|
||||
<ChevronDown className="size-4" />
|
||||
<ChevronDown />
|
||||
</InputGroupButton>
|
||||
</>
|
||||
)}
|
||||
@@ -196,7 +196,7 @@ function FlowTerminal() {
|
||||
title="Clear search"
|
||||
type="button"
|
||||
>
|
||||
<X className="size-4" />
|
||||
<X />
|
||||
</InputGroupButton>
|
||||
)}
|
||||
</InputGroupAddon>
|
||||
|
||||
@@ -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 ? (
|
||||
<>
|
||||
<Loader2 className="size-4 animate-spin" />
|
||||
<Spinner variant="circle" />
|
||||
Anonymizing...
|
||||
</>
|
||||
) : (
|
||||
<>
|
||||
<HatGlasses className="size-4" />
|
||||
<HatGlasses />
|
||||
Anonymize
|
||||
</>
|
||||
)}
|
||||
@@ -254,7 +254,7 @@ export function KnowledgeHeader({
|
||||
className="cursor-default hover:bg-transparent focus:bg-transparent"
|
||||
onSelect={(event) => event.preventDefault()}
|
||||
>
|
||||
<LibraryBig className="size-4" />
|
||||
<LibraryBig />
|
||||
Knowledges
|
||||
<div className="-my-1.5 -mr-2 ml-auto flex items-center">
|
||||
<DetailNavigationButtons<Knowledge>
|
||||
@@ -302,12 +302,12 @@ export function KnowledgeHeader({
|
||||
>
|
||||
{isDeleting ? (
|
||||
<>
|
||||
<Loader2 className="size-4 animate-spin" />
|
||||
<Spinner variant="circle" />
|
||||
Deleting...
|
||||
</>
|
||||
) : (
|
||||
<>
|
||||
<Trash className="size-4" />
|
||||
<Trash />
|
||||
Delete
|
||||
</>
|
||||
)}
|
||||
|
||||
@@ -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()}
|
||||
>
|
||||
<GitFork className="size-4" />
|
||||
<GitFork />
|
||||
Flows
|
||||
<div className="-my-1.5 -mr-2 ml-auto flex items-center">
|
||||
<DetailNavigationButtons<FlowItem>
|
||||
@@ -331,7 +332,7 @@ function Flow() {
|
||||
>
|
||||
{isFinishing ? (
|
||||
<>
|
||||
<Loader2 className="animate-spin" />
|
||||
<Spinner variant="circle" />
|
||||
Finishing...
|
||||
</>
|
||||
) : (
|
||||
@@ -349,12 +350,12 @@ function Flow() {
|
||||
>
|
||||
{isDeleting ? (
|
||||
<>
|
||||
<Loader2 className="size-4 animate-spin" />
|
||||
<Spinner variant="circle" />
|
||||
Deleting...
|
||||
</>
|
||||
) : (
|
||||
<>
|
||||
<Trash className="size-4" />
|
||||
<Trash />
|
||||
Delete
|
||||
</>
|
||||
)}
|
||||
@@ -496,7 +497,7 @@ function FlowReportDropdown() {
|
||||
disabled={isReportDisabled}
|
||||
onClick={handleOpenWebView}
|
||||
>
|
||||
<ExternalLink className="size-4" />
|
||||
<ExternalLink />
|
||||
Open web view
|
||||
</DropdownMenuItem>
|
||||
<DropdownMenuItem
|
||||
@@ -504,7 +505,7 @@ function FlowReportDropdown() {
|
||||
disabled={isReportDisabled}
|
||||
onClick={handleCopyToClipboard}
|
||||
>
|
||||
<Copy className="size-4" />
|
||||
<Copy />
|
||||
Copy to clipboard
|
||||
</DropdownMenuItem>
|
||||
<DropdownMenuItem
|
||||
@@ -512,7 +513,7 @@ function FlowReportDropdown() {
|
||||
disabled={isReportDisabled}
|
||||
onClick={handleDownloadMD}
|
||||
>
|
||||
<Download className="size-4" />
|
||||
<Download />
|
||||
Download MD
|
||||
</DropdownMenuItem>
|
||||
<DropdownMenuItem
|
||||
@@ -520,7 +521,7 @@ function FlowReportDropdown() {
|
||||
disabled={isReportDisabled}
|
||||
onClick={handleDownloadPDF}
|
||||
>
|
||||
<Download className="size-4" />
|
||||
<Download />
|
||||
Download PDF
|
||||
</DropdownMenuItem>
|
||||
</DropdownMenuContent>
|
||||
|
||||
@@ -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"
|
||||
>
|
||||
<Star className="size-4" />
|
||||
<Star />
|
||||
</Toggle>
|
||||
<DropdownMenu>
|
||||
<DropdownMenuTrigger asChild>
|
||||
@@ -449,7 +450,7 @@ function Flows() {
|
||||
>
|
||||
{finishingFlowIds.has(flow.id) ? (
|
||||
<>
|
||||
<Loader2 className="animate-spin" />
|
||||
<Spinner variant="circle" />
|
||||
Finishing...
|
||||
</>
|
||||
) : (
|
||||
@@ -467,12 +468,12 @@ function Flows() {
|
||||
>
|
||||
{deletingFlowIds.has(flow.id) ? (
|
||||
<>
|
||||
<Loader2 className="size-4 animate-spin" />
|
||||
<Spinner variant="circle" />
|
||||
Deleting...
|
||||
</>
|
||||
) : (
|
||||
<>
|
||||
<Trash className="size-4" />
|
||||
<Trash />
|
||||
Delete
|
||||
</>
|
||||
)}
|
||||
|
||||
@@ -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) ? (
|
||||
<>
|
||||
<Loader2 className="size-4 animate-spin" />
|
||||
<Spinner variant="circle" />
|
||||
Deleting...
|
||||
</>
|
||||
) : (
|
||||
<>
|
||||
<Trash className="size-4" />
|
||||
<Trash />
|
||||
Delete
|
||||
</>
|
||||
)}
|
||||
|
||||
@@ -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() {
|
||||
<AppHeaderAction
|
||||
aria-label={upload.isUploading ? 'Uploading...' : 'Upload files'}
|
||||
disabled={upload.isUploading}
|
||||
icon={upload.isUploading ? <Loader2 className="animate-spin" /> : <Upload />}
|
||||
icon={upload.isUploading ? <Spinner variant="circle" /> : <Upload />}
|
||||
label={upload.isUploading ? 'Uploading...' : 'Upload files'}
|
||||
onClick={upload.openFilePicker}
|
||||
variant="secondary"
|
||||
|
||||
@@ -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 ? <Loader2 className="animate-spin" /> : <Check />}
|
||||
{isLoading ? <Spinner variant="circle" /> : <Check />}
|
||||
</Button>
|
||||
<Button
|
||||
aria-label="Cancel"
|
||||
@@ -226,7 +227,7 @@ function EditRowActions({
|
||||
size="icon-sm"
|
||||
variant="ghost"
|
||||
>
|
||||
{isLoading ? <Loader2 className="animate-spin" /> : <Check />}
|
||||
{isLoading ? <Spinner variant="circle" /> : <Check />}
|
||||
</Button>
|
||||
<Button
|
||||
aria-label="Cancel"
|
||||
@@ -738,7 +739,7 @@ function SettingsAPITokens() {
|
||||
>
|
||||
{isDeleteLoading && deletingToken?.tokenId === token.tokenId ? (
|
||||
<>
|
||||
<Loader2 className="animate-spin" />
|
||||
<Spinner variant="circle" />
|
||||
Deleting...
|
||||
</>
|
||||
) : (
|
||||
@@ -843,7 +844,7 @@ function SettingsAPITokens() {
|
||||
rel="noopener noreferrer"
|
||||
target="_blank"
|
||||
>
|
||||
<ExternalLink className="size-4" />
|
||||
<ExternalLink />
|
||||
GraphQL Playground
|
||||
</a>
|
||||
</DropdownMenuItem>
|
||||
@@ -853,7 +854,7 @@ function SettingsAPITokens() {
|
||||
rel="noopener noreferrer"
|
||||
target="_blank"
|
||||
>
|
||||
<ExternalLink className="size-4" />
|
||||
<ExternalLink />
|
||||
Swagger UI
|
||||
</a>
|
||||
</DropdownMenuItem>
|
||||
@@ -919,7 +920,7 @@ function SettingsAPITokens() {
|
||||
onClick={handleCreateNew}
|
||||
variant="secondary"
|
||||
>
|
||||
<Plus className="size-4" />
|
||||
<Plus />
|
||||
Create Token
|
||||
</Button>
|
||||
</EmptyContent>
|
||||
@@ -985,7 +986,7 @@ function SettingsAPITokens() {
|
||||
}}
|
||||
variant="secondary"
|
||||
>
|
||||
<Copy className="size-4" />
|
||||
<Copy />
|
||||
Copy Token
|
||||
</Button>
|
||||
<Button
|
||||
|
||||
@@ -72,6 +72,7 @@ import {
|
||||
import { Empty, EmptyDescription, EmptyHeader, EmptyMedia, EmptyTitle } from '@/components/ui/empty';
|
||||
import { Form, FormControl, FormItem, FormMessage } from '@/components/ui/form';
|
||||
import { Popover, PopoverContent, PopoverTrigger } from '@/components/ui/popover';
|
||||
import { Spinner } from '@/components/ui/spinner';
|
||||
import { Tabs, TabsContent, TabsList, TabsTrigger } from '@/components/ui/tabs';
|
||||
import {
|
||||
CreatePromptDocument,
|
||||
@@ -662,13 +663,7 @@ function SettingsPrompt() {
|
||||
<AppHeaderActions>
|
||||
<AppHeaderAction
|
||||
disabled={isLoading}
|
||||
icon={
|
||||
isValidateLoading ? (
|
||||
<Loader2 className="size-4 animate-spin" />
|
||||
) : (
|
||||
<CheckCircle className="size-4" />
|
||||
)
|
||||
}
|
||||
icon={isValidateLoading ? <Spinner variant="circle" /> : <CheckCircle />}
|
||||
label={isValidateLoading ? 'Validating...' : 'Validate'}
|
||||
onClick={handleValidate}
|
||||
type="button"
|
||||
@@ -676,7 +671,7 @@ function SettingsPrompt() {
|
||||
/>
|
||||
<AppHeaderAction
|
||||
form={activeFormId}
|
||||
icon={<Save className="size-4" />}
|
||||
icon={<Save />}
|
||||
label="Save"
|
||||
loading={isLoading}
|
||||
type="submit"
|
||||
@@ -699,18 +694,14 @@ function SettingsPrompt() {
|
||||
{hasOverride && (
|
||||
<>
|
||||
<DropdownMenuItem onClick={() => setIsDiffDialogOpen(true)}>
|
||||
<FileDiff className="size-4" />
|
||||
<FileDiff />
|
||||
Diff
|
||||
</DropdownMenuItem>
|
||||
<DropdownMenuItem
|
||||
disabled={isLoading}
|
||||
onClick={handleReset}
|
||||
>
|
||||
{isDeleteLoading ? (
|
||||
<Loader2 className="size-4 animate-spin" />
|
||||
) : (
|
||||
<RotateCcw className="size-4" />
|
||||
)}
|
||||
{isDeleteLoading ? <Spinner variant="circle" /> : <RotateCcw />}
|
||||
{isDeleteLoading ? 'Resetting...' : 'Reset'}
|
||||
</DropdownMenuItem>
|
||||
<DropdownMenuSeparator />
|
||||
@@ -1075,7 +1066,7 @@ function Variables({ currentTemplate, onVariableClick, variables }: VariablesPro
|
||||
size="sm"
|
||||
variant="secondary"
|
||||
>
|
||||
<Braces className="size-4" />
|
||||
<Braces />
|
||||
{VARIABLES_TITLE}
|
||||
<Badge
|
||||
className="ml-auto h-5 font-normal tabular-nums"
|
||||
|
||||
@@ -338,11 +338,7 @@ function SettingsPrompts() {
|
||||
variant="link"
|
||||
>
|
||||
Agent Name
|
||||
{sorted === 'asc' ? (
|
||||
<ArrowDown className="size-4" />
|
||||
) : sorted === 'desc' ? (
|
||||
<ArrowUp className="size-4" />
|
||||
) : null}
|
||||
{sorted === 'asc' ? <ArrowDown /> : sorted === 'desc' ? <ArrowUp /> : null}
|
||||
</Button>
|
||||
);
|
||||
},
|
||||
@@ -509,11 +505,7 @@ function SettingsPrompts() {
|
||||
variant="link"
|
||||
>
|
||||
Tool Name
|
||||
{sorted === 'asc' ? (
|
||||
<ArrowDown className="size-4" />
|
||||
) : sorted === 'desc' ? (
|
||||
<ArrowUp className="size-4" />
|
||||
) : null}
|
||||
{sorted === 'asc' ? <ArrowDown /> : sorted === 'desc' ? <ArrowUp /> : null}
|
||||
</Button>
|
||||
);
|
||||
},
|
||||
|
||||
@@ -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 ? (
|
||||
<Loader2 className="size-4 animate-spin" />
|
||||
<Spinner variant="circle" />
|
||||
) : (
|
||||
<Play className="size-4" />
|
||||
<Play />
|
||||
)}
|
||||
<span className="no-underline! hover:no-underline!">
|
||||
{isAgentTestLoading && currentAgentKey === agentKey ? 'Testing...' : 'Test'}
|
||||
@@ -1879,7 +1880,7 @@ function SettingsProvider() {
|
||||
<AppHeaderActions>
|
||||
<AppHeaderAction
|
||||
disabled={isLoading || isTestLoading || isAgentTestLoading}
|
||||
icon={isTestLoading ? <Loader2 className="size-4 animate-spin" /> : <Play className="size-4" />}
|
||||
icon={isTestLoading ? <Spinner variant="circle" /> : <Play />}
|
||||
label={isTestLoading ? 'Testing...' : 'Test'}
|
||||
onClick={() => handleTest()}
|
||||
type="button"
|
||||
@@ -1887,7 +1888,7 @@ function SettingsProvider() {
|
||||
/>
|
||||
<AppHeaderAction
|
||||
form="provider-form"
|
||||
icon={<Save className="size-4" />}
|
||||
icon={<Save />}
|
||||
label={isNew ? 'Create' : 'Save'}
|
||||
loading={isLoading}
|
||||
type="submit"
|
||||
@@ -1912,11 +1913,7 @@ function SettingsProvider() {
|
||||
disabled={isDeleteLoading}
|
||||
onClick={handleDelete}
|
||||
>
|
||||
{isDeleteLoading ? (
|
||||
<Loader2 className="size-4 animate-spin" />
|
||||
) : (
|
||||
<Trash2 className="size-4" />
|
||||
)}
|
||||
{isDeleteLoading ? <Spinner variant="circle" /> : <Trash2 />}
|
||||
{isDeleteLoading ? 'Deleting...' : 'Delete'}
|
||||
</DropdownMenuItem>
|
||||
</DropdownMenuContent>
|
||||
|
||||
@@ -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 className="size-4" />}
|
||||
{Icon && <Icon />}
|
||||
{label}
|
||||
</DropdownMenuItem>
|
||||
);
|
||||
@@ -264,7 +265,7 @@ function SettingsProviders() {
|
||||
Edit
|
||||
</DropdownMenuItem>
|
||||
<DropdownMenuItem onClick={() => handleProviderClone(provider.id)}>
|
||||
<Copy className="size-4" />
|
||||
<Copy />
|
||||
Clone
|
||||
</DropdownMenuItem>
|
||||
<DropdownMenuSeparator />
|
||||
@@ -274,12 +275,12 @@ function SettingsProviders() {
|
||||
>
|
||||
{isDeleteLoading && deletingProvider?.id === provider.id ? (
|
||||
<>
|
||||
<Loader2 className="size-4 animate-spin" />
|
||||
<Spinner variant="circle" />
|
||||
Deleting...
|
||||
</>
|
||||
) : (
|
||||
<>
|
||||
<Trash className="size-4" />
|
||||
<Trash />
|
||||
Delete
|
||||
</>
|
||||
)}
|
||||
@@ -459,7 +460,7 @@ function SettingsProviders() {
|
||||
onClick={() => navigate(routes.settings.newProvider())}
|
||||
variant="secondary"
|
||||
>
|
||||
<Plus className="size-4" />
|
||||
<Plus />
|
||||
Add Provider
|
||||
</Button>
|
||||
</EmptyContent>
|
||||
|
||||
@@ -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() {
|
||||
<AppHeaderAction
|
||||
disabled={!isNew && !hasUnsavedChanges}
|
||||
form="template-form"
|
||||
icon={<Save className="size-4" />}
|
||||
icon={<Save />}
|
||||
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()}
|
||||
>
|
||||
<FileText className="size-4" />
|
||||
<FileText />
|
||||
Templates
|
||||
<div className="-my-1.5 -mr-2 ml-auto flex items-center">
|
||||
<DetailNavigationButtons<Template>
|
||||
@@ -521,7 +511,7 @@ function Template() {
|
||||
</>
|
||||
)}
|
||||
<DropdownMenuItem onClick={handleTemplateRenameStart}>
|
||||
<Pencil className="size-4" />
|
||||
<Pencil />
|
||||
Rename
|
||||
</DropdownMenuItem>
|
||||
<DropdownMenuSeparator />
|
||||
@@ -548,12 +538,12 @@ function Template() {
|
||||
>
|
||||
{isDeleting ? (
|
||||
<>
|
||||
<Loader2 className="size-4 animate-spin" />
|
||||
<Spinner variant="circle" />
|
||||
Deleting...
|
||||
</>
|
||||
) : (
|
||||
<>
|
||||
<Trash className="size-4" />
|
||||
<Trash />
|
||||
Delete
|
||||
</>
|
||||
)}
|
||||
@@ -660,7 +650,7 @@ function Template() {
|
||||
size="sm"
|
||||
variant="secondary"
|
||||
>
|
||||
<LayoutTemplate className="size-4" />
|
||||
<LayoutTemplate />
|
||||
{PRESETS_TITLE}
|
||||
<Badge
|
||||
className="ml-auto h-5 font-normal tabular-nums"
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import type { ColumnDef } from '@tanstack/react-table';
|
||||
|
||||
import { Ellipsis, FileText, Loader2, Pencil, PencilLine, Plus, Trash } from 'lucide-react';
|
||||
import { Ellipsis, FileText, Pencil, PencilLine, Plus, Trash } from 'lucide-react';
|
||||
import { useCallback, useRef, useState } from 'react';
|
||||
import { useLocation, useNavigate } from 'react-router-dom';
|
||||
import { toast } from 'sonner';
|
||||
@@ -25,6 +25,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 { useTableState } from '@/hooks/use-table-state';
|
||||
import { routes } from '@/lib/routes';
|
||||
import { mergeHrefWithSearchParams } from '@/lib/url-params';
|
||||
@@ -203,12 +204,12 @@ function Templates() {
|
||||
>
|
||||
{deletingIds.has(template.id) ? (
|
||||
<>
|
||||
<Loader2 className="size-4 animate-spin" />
|
||||
<Spinner variant="circle" />
|
||||
Deleting...
|
||||
</>
|
||||
) : (
|
||||
<>
|
||||
<Trash className="size-4" />
|
||||
<Trash />
|
||||
Delete
|
||||
</>
|
||||
)}
|
||||
@@ -281,7 +282,7 @@ function Templates() {
|
||||
onClick={() => navigate(routes.newTemplate)}
|
||||
variant="secondary"
|
||||
>
|
||||
<Plus className="size-4" />
|
||||
<Plus />
|
||||
New Template
|
||||
</Button>
|
||||
</EmptyContent>
|
||||
|
||||
Reference in New Issue
Block a user