Fix beta build: image check accepts Blob attachments (#131)
Unit Tests / test (push) Successful in 12s
Deploy Beta / unit-tests (push) Successful in 37s
Deploy Beta / deploy-beta (push) Failing after 3m49s

## Summary
- Closes #130.
- [Deploy Beta run 929](https://git.aimloperations.com/ai_ml_operations/chat_web_app/actions/runs/929) failed `npm run build:beta` with `TS2345`: `isImageFile` took a `File`, but the composer file is a `Blob`.
- The helper now accepts `Blob`. `URL.createObjectURL` already does. The `as File` casts are gone.
- Jest stayed green on that run because it does not typecheck this call. `tsc --noEmit` is clean on this branch.

## Test plan
- [ ] `npx tsc --noEmit` in `llm-fe`
- [ ] `npm run build:beta` (or the next Deploy Beta) compiles
- [ ] Image attach still shows a thumbnail and sends
- [ ] Document attach still shows the filename

Reviewed-on: #131
This commit was merged in pull request #131.
This commit is contained in:
westfarn committed 2026-10-20 08:07:39 -07:00
1 parent 89228719b5
commit ac165a2db4
3 files changed
+8 -7

No files matched your search

@@ -335,15 +335,15 @@ const AlwaysScrollToBottom = ({ trigger }: { trigger: string | number }): JSX.El
return <div ref={elementRef} />; return <div ref={elementRef} />;
}; };
const AttachmentPreview = ({ file }: { file: File | null }): JSX.Element | null => { const AttachmentPreview = ({ file }: { file: Blob | null }): JSX.Element | null => {
const theme = useContext(ThemeContext); const theme = useContext(ThemeContext);
const [url, setUrl] = useState<string | null>(null); const [url, setUrl] = useState<string | null>(null);
useEffect(() => { useEffect(() => {
if (!isImageFile(file)) { if (!file || !isImageFile(file)) {
setUrl(null); setUrl(null);
return; return;
} }
const next = URL.createObjectURL(file as File); const next = URL.createObjectURL(file);
setUrl(next); setUrl(next);
return () => URL.revokeObjectURL(next); return () => URL.revokeObjectURL(next);
}, [file]); }, [file]);
@@ -370,7 +370,7 @@ const AttachmentPreview = ({ file }: { file: File | null }): JSX.Element | null
color: theme?.darkMode ? "rgba(255,255,255,0.6)" : "rgba(0,0,0,0.6)", color: theme?.darkMode ? "rgba(255,255,255,0.6)" : "rgba(0,0,0,0.6)",
textAlign: "center", textAlign: "center",
}}> }}>
Attached: {file.name} Attached: {file instanceof File ? file.name : "attachment"}
</div> </div>
); );
}; };
@@ -473,7 +473,7 @@ const AsyncDashboardInner = (): JSX.Element => {
} }
try { try {
clearActivity(); clearActivity();
const attachedImage = isImageFile(file) ? URL.createObjectURL(file as File) : null; const attachedImage = file && isImageFile(file) ? URL.createObjectURL(file) : null;
const tempConversations: ConversationPrompt[] = [ const tempConversations: ConversationPrompt[] = [
...conversationDetails, ...conversationDetails,
new ConversationPrompt({ new ConversationPrompt({
@@ -753,7 +753,7 @@ const AsyncDashboardInner = (): JSX.Element => {
</span> </span>
</Tooltip> </Tooltip>
</StyledInputContainer> </StyledInputContainer>
<AttachmentPreview file={formik.values.file as File | null} /> <AttachmentPreview file={formik.values.file} />
</Form> </Form>
)} )}
</Formik> </Formik>
@@ -16,6 +16,7 @@ describe('visionAttachment', () => {
it('detects image files', () => { it('detects image files', () => {
expect(isImageFile(new File(['x'], 'a.png', { type: 'image/png' }))).toBe(true); expect(isImageFile(new File(['x'], 'a.png', { type: 'image/png' }))).toBe(true);
expect(isImageFile(new File(['x'], 'a.pdf', { type: 'application/pdf' }))).toBe(false); expect(isImageFile(new File(['x'], 'a.pdf', { type: 'application/pdf' }))).toBe(false);
expect(isImageFile(new Blob(['x'], { type: 'image/png' }))).toBe(true);
expect(isImageFile(null)).toBe(false); expect(isImageFile(null)).toBe(false);
}); });
}); });
+1 -1
View File
@@ -1,7 +1,7 @@
export const CHAT_FILE_ACCEPT = export const CHAT_FILE_ACCEPT =
'.csv,.xlsx,.txt,.pdf,.PDF,image/png,image/jpeg,image/webp,image/gif'; '.csv,.xlsx,.txt,.pdf,.PDF,image/png,image/jpeg,image/webp,image/gif';
export function isImageFile(file: File | null | undefined): boolean { export function isImageFile(file: Blob | null | undefined): boolean {
return Boolean(file && file.type.startsWith('image/')); return Boolean(file && file.type.startsWith('image/'));
} }