feat(files): allow image uploads in workspace files (#4419)

* feat(files): allow image uploads in workspace files

* fix(files): include images in workspace type filter

* fix(files): match all image mime types in image filter
This commit is contained in:
Waleed
2026-05-03 02:50:00 -07:00
committed by GitHub
parent f76a10ca55
commit 14c93f6305
2 changed files with 40 additions and 6 deletions
@@ -43,6 +43,7 @@ import {
SUPPORTED_AUDIO_EXTENSIONS,
SUPPORTED_CODE_EXTENSIONS,
SUPPORTED_DOCUMENT_EXTENSIONS,
SUPPORTED_IMAGE_EXTENSIONS,
SUPPORTED_VIDEO_EXTENSIONS,
} from '@/lib/uploads/utils/validation'
import type {
@@ -89,6 +90,7 @@ const SUPPORTED_EXTENSIONS = [
...SUPPORTED_CODE_EXTENSIONS,
...SUPPORTED_AUDIO_EXTENSIONS,
...SUPPORTED_VIDEO_EXTENSIONS,
...SUPPORTED_IMAGE_EXTENSIONS,
] as const
const ACCEPT_ATTR = SUPPORTED_EXTENSIONS.map((ext) => `.${ext}`).join(',')
@@ -125,6 +127,7 @@ function formatFileType(mimeType: string | null, filename: string): string {
if (mimeType?.startsWith('audio/')) return 'Audio'
if (mimeType?.startsWith('video/')) return 'Video'
if (mimeType?.startsWith('image/')) return 'Image'
const ext = getFileExtension(filename)
if (ext) return ext.toUpperCase()
@@ -246,6 +249,7 @@ export function Files() {
if (typeFilter.includes('document') && isSupportedExtension(ext)) return true
if (typeFilter.includes('audio') && isAudioFileType(f.type)) return true
if (typeFilter.includes('video') && isVideoFileType(f.type)) return true
if (typeFilter.includes('image') && f.type?.startsWith('image/')) return true
return false
})
}
@@ -926,9 +930,14 @@ export function Files() {
typeFilter.length === 0
? 'All'
: typeFilter.length === 1
? (({ document: 'Documents', audio: 'Audio', video: 'Video' } as Record<string, string>)[
typeFilter[0]
] ?? typeFilter[0])
? ((
{
document: 'Documents',
image: 'Images',
audio: 'Audio',
video: 'Video',
} as Record<string, string>
)[typeFilter[0]] ?? typeFilter[0])
: `${typeFilter.length} selected`
const sizeDisplayLabel =
@@ -954,6 +963,7 @@ export function Files() {
<Combobox
options={[
{ value: 'document', label: 'Documents' },
{ value: 'image', label: 'Images' },
{ value: 'audio', label: 'Audio' },
{ value: 'video', label: 'Video' },
]}
@@ -1036,6 +1046,7 @@ export function Files() {
if (typeFilter.length > 0) {
const typeLabels: Record<string, string> = {
document: 'Documents',
image: 'Images',
audio: 'Audio',
video: 'Video',
}
+26 -3
View File
@@ -95,13 +95,31 @@ export const SUPPORTED_AUDIO_EXTENSIONS = [
export const SUPPORTED_VIDEO_EXTENSIONS = ['mp4', 'mov', 'avi', 'mkv', 'webm'] as const
export const SUPPORTED_IMAGE_EXTENSIONS = [
'png',
'jpg',
'jpeg',
'gif',
'webp',
'svg',
'bmp',
'tif',
'tiff',
'heic',
'heif',
'avif',
'ico',
] as const
export type SupportedDocumentExtension = (typeof SUPPORTED_DOCUMENT_EXTENSIONS)[number]
export type SupportedAudioExtension = (typeof SUPPORTED_AUDIO_EXTENSIONS)[number]
export type SupportedVideoExtension = (typeof SUPPORTED_VIDEO_EXTENSIONS)[number]
export type SupportedImageExtension = (typeof SUPPORTED_IMAGE_EXTENSIONS)[number]
export type SupportedMediaExtension =
| SupportedDocumentExtension
| SupportedAudioExtension
| SupportedVideoExtension
| SupportedImageExtension
export const SUPPORTED_MIME_TYPES: Record<SupportedDocumentExtension, string[]> = {
pdf: ['application/pdf', 'application/x-pdf'],
@@ -180,14 +198,19 @@ const SUPPORTED_IMAGE_MIME_TYPES = [
'image/gif',
'image/webp',
'image/svg+xml',
'image/bmp',
'image/tiff',
'image/heic',
'image/heif',
'image/avif',
'image/x-icon',
'image/vnd.microsoft.icon',
]
const SUPPORTED_IMAGE_EXTENSIONS = ['.jpg', '.jpeg', '.png', '.gif', '.webp', '.svg']
export const CHAT_ACCEPT_ATTRIBUTE = [
ACCEPT_ATTRIBUTE,
...SUPPORTED_IMAGE_MIME_TYPES,
...SUPPORTED_IMAGE_EXTENSIONS,
...SUPPORTED_IMAGE_EXTENSIONS.map((ext) => `.${ext}`),
].join(',')
export interface FileValidationError {