From d9264cdff1f5ecb2d61ff0285e8c83470e4f3d20 Mon Sep 17 00:00:00 2001 From: jbolor21 <86250273+jbolor21@users.noreply.github.com> Date: Mon, 11 May 2026 08:40:32 -0700 Subject: [PATCH 1/2] add changes to files --- .../components/Chat/ChatInputArea.styles.ts | 18 +++ .../components/Chat/ChatInputArea.test.tsx | 50 +++++++- .../src/components/Chat/ChatInputArea.tsx | 60 ++++++++- frontend/src/components/Chat/ChatWindow.tsx | 67 ++++++++-- .../components/Chat/ConverterPanel.test.tsx | 27 ++-- .../ConverterPanel/ConverterPanel.styles.ts | 35 ++++++ .../Chat/ConverterPanel/ConverterPanel.tsx | 23 +++- .../ConverterPanel/ConverterPreview.test.tsx | 56 +++++++-- .../Chat/ConverterPanel/ConverterPreview.tsx | 115 +++++++++++++----- .../src/components/Chat/MessageList.styles.ts | 27 ++++ .../src/components/Chat/MessageList.test.tsx | 30 +++++ frontend/src/components/Chat/MessageList.tsx | 18 ++- .../src/components/Chat/converterTypes.ts | 61 ++++++++++ frontend/src/services/api.ts | 2 +- 14 files changed, 513 insertions(+), 76 deletions(-) diff --git a/frontend/src/components/Chat/ChatInputArea.styles.ts b/frontend/src/components/Chat/ChatInputArea.styles.ts index b53e720e58..0599837cab 100644 --- a/frontend/src/components/Chat/ChatInputArea.styles.ts +++ b/frontend/src/components/Chat/ChatInputArea.styles.ts @@ -228,6 +228,24 @@ export const useChatInputAreaStyles = makeStyles({ fontSize: tokens.fontSizeBase200, color: tokens.colorNeutralForeground2, }, + openLink: { + display: 'inline-flex', + alignItems: 'center', + gap: tokens.spacingHorizontalXXS, + padding: `0 ${tokens.spacingHorizontalS}`, + borderRadius: tokens.borderRadiusSmall, + backgroundColor: tokens.colorBrandBackground, + color: tokens.colorNeutralForegroundOnBrand, + fontSize: tokens.fontSizeBase200, + fontWeight: tokens.fontWeightSemibold as unknown as string, + textDecoration: 'none', + flexShrink: 0, + height: '20px', + ':hover': { + backgroundColor: tokens.colorBrandBackgroundHover, + color: tokens.colorNeutralForegroundOnBrand, + }, + }, originalBadge: { display: 'inline-block', padding: `0 ${tokens.spacingHorizontalXS}`, diff --git a/frontend/src/components/Chat/ChatInputArea.test.tsx b/frontend/src/components/Chat/ChatInputArea.test.tsx index 570fb93039..82f1e47b56 100644 --- a/frontend/src/components/Chat/ChatInputArea.test.tsx +++ b/frontend/src/components/Chat/ChatInputArea.test.tsx @@ -543,7 +543,7 @@ describe("ChatInputArea", () => { ); @@ -571,7 +571,7 @@ describe("ChatInputArea", () => { @@ -647,4 +647,50 @@ describe("ChatInputArea", () => { expect(onSend).toHaveBeenCalledWith("hello", "convertedHello", []); expect(onClearConversion).toHaveBeenCalled(); }); + + it("should render converted file chip with Open link for text→file conversion", async () => { + render( + + + + ); + + expect(screen.getByTestId("original-banner")).toBeInTheDocument(); + const chip = screen.getByTestId("converted-file-chip"); + expect(chip).toHaveTextContent("result.pdf"); + const openLink = screen.getByTestId("converted-file-open"); + expect(openLink).toHaveAttribute("href", "/api/media?path=%2Ftmp%2Fresult.pdf"); + expect(openLink).toHaveAttribute("target", "_blank"); + }); + + it("should call onClearConvertedFileChip when chip dismiss is clicked", async () => { + const onClearConvertedFileChip = jest.fn(); + const user = userEvent.setup(); + + render( + + + + ); + + await user.click(screen.getByTestId("clear-converted-file-chip")); + expect(onClearConvertedFileChip).toHaveBeenCalledTimes(1); + }); }); diff --git a/frontend/src/components/Chat/ChatInputArea.tsx b/frontend/src/components/Chat/ChatInputArea.tsx index 615244d0e9..b818402908 100644 --- a/frontend/src/components/Chat/ChatInputArea.tsx +++ b/frontend/src/components/Chat/ChatInputArea.tsx @@ -6,7 +6,7 @@ import { Text, tokens, } from '@fluentui/react-components' -import { SendRegular, AttachRegular, DismissRegular, InfoRegular, AddRegular, CopyRegular, WarningRegular, SettingsRegular, ArrowShuffleRegular } from '@fluentui/react-icons' +import { SendRegular, AttachRegular, DismissRegular, InfoRegular, AddRegular, CopyRegular, WarningRegular, SettingsRegular, ArrowShuffleRegular, OpenRegular } from '@fluentui/react-icons' import { MessageAttachment, TargetInstance } from '../../types' import { useChatInputAreaStyles } from './ChatInputArea.styles' @@ -14,6 +14,12 @@ import { useChatInputAreaStyles } from './ChatInputArea.styles' // Reusable status banner // --------------------------------------------------------------------------- +export interface ConvertedFileChip { + name: string + url: string + iconKind: 'image' | 'audio' | 'video' | 'file' +} + interface StatusBannerProps { icon: React.ReactElement text: string @@ -53,7 +59,7 @@ function StatusBanner({ icon, text, buttonText, buttonIcon, onButtonClick, testI interface AttachmentListProps { attachments: MessageAttachment[] - mediaConversions: Array<{ pieceType: string; convertedValue: string }> + mediaConversions: Array<{ pieceType: string; convertedValue: string; convertedDataType: string }> onRemove: (index: number) => void onClearMediaConversion: (pieceType: string) => void formatFileSize: (bytes: number) => string @@ -118,20 +124,23 @@ function AttachmentList({ attachments, mediaConversions, onRemove, onClearMediaC interface TextInputRowsProps { input: string convertedValue?: string | null + convertedFileChip?: ConvertedFileChip | null disabled: boolean textareaRef: Ref onInput: (e: React.ChangeEvent) => void onKeyDown: (e: KeyboardEvent) => void onConvertedValueChange: (value: string) => void onClearConversion: () => void + onClearConvertedFileChip?: () => void styles: ReturnType } -function TextInputRows({ input, convertedValue, disabled, textareaRef, onInput, onKeyDown, onConvertedValueChange, onClearConversion, styles }: TextInputRowsProps) { +function TextInputRows({ input, convertedValue, convertedFileChip, disabled, textareaRef, onInput, onKeyDown, onConvertedValueChange, onClearConversion, onClearConvertedFileChip, styles }: TextInputRowsProps) { + const hasConversion = Boolean(convertedValue) || Boolean(convertedFileChip) return ( <>
- {convertedValue && ( + {hasConversion && ( Original )}