diff --git a/site/src/pages/AgentsPage/AgentChatInput.stories.tsx b/site/src/pages/AgentsPage/AgentChatInput.stories.tsx
index 47245db2f6..1170ae7fb8 100644
--- a/site/src/pages/AgentsPage/AgentChatInput.stories.tsx
+++ b/site/src/pages/AgentsPage/AgentChatInput.stories.tsx
@@ -112,9 +112,13 @@ export const LoadingSpinner: Story = {
const canvas = within(canvasElement);
const sendButton = canvas.getByRole("button", { name: "Send" });
expect(sendButton).toBeDisabled();
- // The Loader2Icon renders with the animate-spin class when
- // isLoading is true.
- expect(sendButton.querySelector(".animate-spin")).toBeTruthy();
+ // The Spinner component renders an SVG with a "Loading spinner"
+ // title when isLoading is true.
+ const spinnerSvg = sendButton.querySelector("svg");
+ expect(spinnerSvg).toBeTruthy();
+ expect(spinnerSvg?.querySelector("title")?.textContent).toBe(
+ "Loading spinner",
+ );
},
};
diff --git a/site/src/pages/AgentsPage/AgentChatInput.tsx b/site/src/pages/AgentsPage/AgentChatInput.tsx
index 41ac54fa94..33f407634c 100644
--- a/site/src/pages/AgentsPage/AgentChatInput.tsx
+++ b/site/src/pages/AgentsPage/AgentChatInput.tsx
@@ -8,6 +8,7 @@ import {
ChatMessageInput,
type ChatMessageInputRef,
} from "components/ChatMessageInput/ChatMessageInput";
+import { Spinner } from "components/Spinner/Spinner";
import {
Tooltip,
TooltipContent,
@@ -17,7 +18,6 @@ import {
AlertTriangleIcon,
ArrowUpIcon,
ImageIcon,
- Loader2Icon,
Square,
XIcon,
} from "lucide-react";
@@ -274,7 +274,7 @@ export const AttachmentPreview = memo<{
)}
{uploadState?.status === "uploading" && (
-
+
)}
{uploadState?.status === "error" && (
@@ -565,9 +565,7 @@ export const AgentChatInput = memo(
{isEditingHistoryMessage && editingQueuedMessageID === null && (
- {isLoading && (
-
- )}
+ {isLoading && }
{isLoading ? "Saving edit..." : "Editing message"}
diff --git a/site/src/pages/AgentsPage/AgentsSidebar.tsx b/site/src/pages/AgentsPage/AgentsSidebar.tsx
index 53ce64fd3e..f00259e5ad 100644
--- a/site/src/pages/AgentsPage/AgentsSidebar.tsx
+++ b/site/src/pages/AgentsPage/AgentsSidebar.tsx
@@ -23,6 +23,7 @@ import { ExternalImage } from "components/ExternalImage/ExternalImage";
import { CoderIcon } from "components/Icons/CoderIcon";
import { ScrollArea } from "components/ScrollArea/ScrollArea";
import { Skeleton } from "components/Skeleton/Skeleton";
+import { Spinner } from "components/Spinner/Spinner";
import { useAuthenticated } from "hooks";
import {
AlertTriangleIcon,
@@ -445,7 +446,7 @@ const ChatTreeNode = memo(({ chat, isChildNode }) => {
{isArchivingThisChat ? (
-
+
) : (
<>
diff --git a/site/src/pages/AgentsPage/ChatModelAdminPanel/ChatModelAdminPanel.tsx b/site/src/pages/AgentsPage/ChatModelAdminPanel/ChatModelAdminPanel.tsx
index e25cbdba66..920ff3d5b6 100644
--- a/site/src/pages/AgentsPage/ChatModelAdminPanel/ChatModelAdminPanel.tsx
+++ b/site/src/pages/AgentsPage/ChatModelAdminPanel/ChatModelAdminPanel.tsx
@@ -12,7 +12,7 @@ import {
import type * as TypesGen from "api/typesGenerated";
import { Alert, AlertDescription, AlertTitle } from "components/Alert/Alert";
import { ErrorAlert } from "components/Alert/ErrorAlert";
-import { Loader2Icon } from "lucide-react";
+import { Spinner } from "components/Spinner/Spinner";
import { type FC, useMemo, useState } from "react";
import { useMutation, useQuery, useQueryClient } from "react-query";
import { cn } from "utils/cn";
@@ -301,7 +301,7 @@ export const ChatModelAdminPanel: FC = ({
{isLoading && (
-
+
Loading
)}
diff --git a/site/src/pages/AgentsPage/ChatModelAdminPanel/ModelForm.tsx b/site/src/pages/AgentsPage/ChatModelAdminPanel/ModelForm.tsx
index e1d3ae5bf8..0b86febfe2 100644
--- a/site/src/pages/AgentsPage/ChatModelAdminPanel/ModelForm.tsx
+++ b/site/src/pages/AgentsPage/ChatModelAdminPanel/ModelForm.tsx
@@ -9,12 +9,12 @@ import {
SelectTrigger,
SelectValue,
} from "components/Select/Select";
+import { Spinner } from "components/Spinner/Spinner";
import { useFormik } from "formik";
import {
ChevronDownIcon,
ChevronLeftIcon,
ChevronRightIcon,
- Loader2Icon,
} from "lucide-react";
import { type FC, useMemo, useState } from "react";
import { cn } from "utils/cn";
@@ -487,10 +487,8 @@ export const ModelForm: FC
= ({
disabled={isDeleting}
onClick={() => void onDeleteModel(editingModel.id)}
>
- {isDeleting && (
-
- )}
- Delete model
+ {isDeleting && }
+ Delete model{" "}
@@ -522,7 +520,7 @@ export const ModelForm: FC = ({
type="submit"
disabled={isSaving || !form.isValid || hasFieldErrors}
>
- {isSaving && }
+ {isSaving && }{" "}
{isEditing ? "Save" : "Add model"}{" "}
diff --git a/site/src/pages/AgentsPage/ChatModelAdminPanel/ProviderForm.tsx b/site/src/pages/AgentsPage/ChatModelAdminPanel/ProviderForm.tsx
index 3934022a6a..96c2cc86f5 100644
--- a/site/src/pages/AgentsPage/ChatModelAdminPanel/ProviderForm.tsx
+++ b/site/src/pages/AgentsPage/ChatModelAdminPanel/ProviderForm.tsx
@@ -2,12 +2,13 @@ import type * as TypesGen from "api/typesGenerated";
import { Alert, AlertDescription, AlertTitle } from "components/Alert/Alert";
import { Button } from "components/Button/Button";
import { Input } from "components/Input/Input";
+import { Spinner } from "components/Spinner/Spinner";
import {
Tooltip,
TooltipContent,
TooltipTrigger,
} from "components/Tooltip/Tooltip";
-import { ChevronLeftIcon, InfoIcon, Loader2Icon } from "lucide-react";
+import { ChevronLeftIcon, InfoIcon } from "lucide-react";
import { type FC, type FormEvent, useId, useState } from "react";
import { formatProviderLabel } from "../modelOptions";
import type { ProviderState } from "./ChatModelAdminPanel";
@@ -275,9 +276,9 @@ export const ProviderForm: FC = ({
onClick={() => void onDeleteProvider(providerConfig.id)}
>
{isProviderMutationPending && (
-
+
)}
- Delete provider
+ Delete provider{" "}
@@ -299,9 +300,11 @@ export const ProviderForm: FC = ({
)}
)}
diff --git a/site/src/pages/AgentsPage/QueuedMessagesList.tsx b/site/src/pages/AgentsPage/QueuedMessagesList.tsx
index 74f54b8c2b..3862c17fc9 100644
--- a/site/src/pages/AgentsPage/QueuedMessagesList.tsx
+++ b/site/src/pages/AgentsPage/QueuedMessagesList.tsx
@@ -1,5 +1,6 @@
import type { ChatQueuedMessage } from "api/typesGenerated";
import { Button } from "components/Button/Button";
+import { Spinner } from "components/Spinner/Spinner";
import {
Tooltip,
TooltipContent,
@@ -8,7 +9,6 @@ import {
import {
ArrowUpIcon,
CornerDownLeftIcon,
- Loader2Icon,
PencilIcon,
Trash2Icon,
} from "lucide-react";
@@ -288,7 +288,7 @@ export const QueuedMessagesList: FC = ({
className="size-6 rounded text-content-secondary hover:bg-surface-tertiary hover:text-content-primary"
>
{isItemBusy && busyItem.action === "promote" ? (
-
+
) : (
)}
@@ -307,7 +307,7 @@ export const QueuedMessagesList: FC = ({
className="size-6 rounded text-content-secondary hover:bg-surface-tertiary hover:text-content-destructive"
>
{isItemBusy && busyItem.action === "delete" ? (
-
+
) : (
)}
diff --git a/site/src/pages/AgentsPage/WebPushButton.tsx b/site/src/pages/AgentsPage/WebPushButton.tsx
index e425ae2c51..c482902b40 100644
--- a/site/src/pages/AgentsPage/WebPushButton.tsx
+++ b/site/src/pages/AgentsPage/WebPushButton.tsx
@@ -1,12 +1,13 @@
import { getErrorMessage } from "api/errors";
import { Button } from "components/Button/Button";
+import { Spinner } from "components/Spinner/Spinner";
import {
Tooltip,
TooltipContent,
TooltipTrigger,
} from "components/Tooltip/Tooltip";
import { useWebpushNotifications } from "contexts/useWebpushNotifications";
-import { BellIcon, BellOffIcon, Loader2Icon } from "lucide-react";
+import { BellIcon, BellOffIcon } from "lucide-react";
import type { FC } from "react";
import { toast } from "sonner";
@@ -51,7 +52,7 @@ export const WebPushButton: FC = () => {
className="h-7 w-7 text-content-secondary hover:text-content-primary"
>
{webPush.loading ? (
-
+
) : webPush.subscribed ? (
) : (