refactor(app): introduce attachment storage layer and draft lifecycle management
Replace inline data-URL image handling with a persistent attachment storage service, add draft lifecycle states (active/abandoned/sent) with generation tracking, and update fetchAgent to return project placement alongside agent snapshots.
This commit is contained in:
@@ -28,14 +28,13 @@ import {
|
||||
collectImageFilesFromClipboardData,
|
||||
filesToImageAttachments,
|
||||
} from '@/utils/image-attachments-from-files'
|
||||
import type { AttachmentMetadata } from '@/attachments/types'
|
||||
import { useAttachmentPreviewUrl } from '@/attachments/use-attachment-preview-url'
|
||||
import { Tooltip, TooltipContent, TooltipTrigger } from '@/components/ui/tooltip'
|
||||
import { Shortcut } from '@/components/ui/shortcut'
|
||||
import type { MessageInputKeyboardActionKind } from '@/keyboard/actions'
|
||||
|
||||
export interface ImageAttachment {
|
||||
uri: string
|
||||
mimeType: string
|
||||
}
|
||||
export type ImageAttachment = AttachmentMetadata
|
||||
|
||||
export interface MessagePayload {
|
||||
text: string
|
||||
@@ -111,6 +110,14 @@ type TextAreaHandle = {
|
||||
} & Record<string, unknown>
|
||||
}
|
||||
|
||||
function ImageAttachmentThumbnail({ image }: { image: ImageAttachment }) {
|
||||
const uri = useAttachmentPreviewUrl(image)
|
||||
if (!uri) {
|
||||
return <View style={styles.imageThumbnailPlaceholder} />
|
||||
}
|
||||
return <Image source={{ uri }} style={styles.imageThumbnail} />
|
||||
}
|
||||
|
||||
export const MessageInput = forwardRef<MessageInputRef, MessageInputProps>(function MessageInput(
|
||||
{
|
||||
value,
|
||||
@@ -636,14 +643,14 @@ export const MessageInput = forwardRef<MessageInputRef, MessageInputProps>(funct
|
||||
<View style={styles.imagePreviewContainer} testID="message-input-image-preview">
|
||||
{images.map((image, index) => (
|
||||
<Pressable
|
||||
key={`${image.uri}-${index}`}
|
||||
key={`${image.id}-${index}`}
|
||||
testID="message-input-image-pill"
|
||||
style={styles.imagePill}
|
||||
onPress={onRemoveImage ? () => onRemoveImage(index) : undefined}
|
||||
>
|
||||
{({ hovered }) => (
|
||||
<>
|
||||
<Image source={{ uri: image.uri }} style={styles.imageThumbnail} />
|
||||
<ImageAttachmentThumbnail image={image} />
|
||||
{onRemoveImage && (
|
||||
<View
|
||||
style={[
|
||||
@@ -894,6 +901,11 @@ const styles = StyleSheet.create(((theme: any) => ({
|
||||
width: 48,
|
||||
height: 48,
|
||||
},
|
||||
imageThumbnailPlaceholder: {
|
||||
width: 48,
|
||||
height: 48,
|
||||
backgroundColor: theme.colors.surface2,
|
||||
},
|
||||
removeImageButton: {
|
||||
position: 'absolute',
|
||||
top: 0,
|
||||
|
||||
Reference in New Issue
Block a user