diff --git a/changelog/8135-form-builder-thinking-spinner.yaml b/changelog/8135-form-builder-thinking-spinner.yaml new file mode 100644 index 0000000000..7d2766d5a7 --- /dev/null +++ b/changelog/8135-form-builder-thinking-spinner.yaml @@ -0,0 +1,4 @@ +type: Added +description: Loading spinner in the privacy center form builder chat while the LLM is streaming a response +pr: 8135 +labels: [] diff --git a/clients/admin-ui/src/features/properties/privacy-center-config/form-builder/ChatPane.tsx b/clients/admin-ui/src/features/properties/privacy-center-config/form-builder/ChatPane.tsx index f3e7ee64f0..7a3204347b 100644 --- a/clients/admin-ui/src/features/properties/privacy-center-config/form-builder/ChatPane.tsx +++ b/clients/admin-ui/src/features/properties/privacy-center-config/form-builder/ChatPane.tsx @@ -1,4 +1,4 @@ -import { Alert, Button, Input, SparkleIcon } from "fidesui"; +import { Alert, Button, Input, SparkleIcon, Spin } from "fidesui"; import { useEffect, useRef, useState } from "react"; import type { ChatMessage, Status } from "./useFormBuilder"; @@ -84,6 +84,21 @@ export const ChatPane = ({ {m.content} ))} + {isStreaming && ( +
+ +
+ )}
{ expect(screen.getByRole("textbox")).toBeDisabled(); }); + it("shows a thinking indicator while streaming", () => { + render( + , + ); + const status = screen.getByRole("status", { name: /thinking/i }); + expect(status).toBeInTheDocument(); + expect(status.querySelector('[aria-busy="true"]')).toBeInTheDocument(); + }); + + it("does not show a thinking indicator when idle", () => { + render( + , + ); + expect( + screen.queryByRole("status", { name: /thinking/i }), + ).not.toBeInTheDocument(); + }); + it("calls onSend with the typed text and clears input", async () => { const onSend = jest.fn(); render(