mirror of
https://github.com/jxxghp/MoviePilot-Frontend.git
synced 2026-09-09 09:46:44 +08:00
feat(agent): support pasting clipboard images (#739)
This commit is contained in:
@@ -1721,10 +1721,8 @@ function openFilePicker() {
|
||||
fileInputRef.value?.click()
|
||||
}
|
||||
|
||||
// 处理文件选择并生成待发送附件预览。
|
||||
function handleFileSelection(event: Event) {
|
||||
const input = event.target as HTMLInputElement
|
||||
const files = Array.from(input.files || [])
|
||||
// 将文件加入待发送附件并生成图片预览。
|
||||
function addPendingAttachments(files: File[]) {
|
||||
const nextAttachments = files.map(file => {
|
||||
const kind = getFileKind(file)
|
||||
|
||||
@@ -1740,9 +1738,28 @@ function handleFileSelection(event: Event) {
|
||||
})
|
||||
|
||||
pendingAttachments.value.push(...nextAttachments)
|
||||
}
|
||||
|
||||
// 处理文件选择并生成待发送附件预览。
|
||||
function handleFileSelection(event: Event) {
|
||||
const input = event.target as HTMLInputElement
|
||||
addPendingAttachments(Array.from(input.files || []))
|
||||
input.value = ''
|
||||
}
|
||||
|
||||
// 将剪贴板中的截图或复制图片加入待发送附件。
|
||||
function handleInputPaste(event: ClipboardEvent) {
|
||||
if (isBusy.value || recording.value) return
|
||||
const images = Array.from(event.clipboardData?.items || [])
|
||||
.filter(item => item.kind === 'file' && item.type.startsWith('image/'))
|
||||
.map(item => item.getAsFile())
|
||||
.filter((file): file is File => Boolean(file))
|
||||
if (!images.length) return
|
||||
|
||||
event.preventDefault()
|
||||
addPendingAttachments(images)
|
||||
}
|
||||
|
||||
// 移除一条待发送附件。
|
||||
function removePendingAttachment(id: string) {
|
||||
const attachment = pendingAttachments.value.find(item => item.id === id)
|
||||
@@ -2798,6 +2815,7 @@ onScopeDispose(() => {
|
||||
:placeholder="inputPlaceholder"
|
||||
@input="handleInputChange"
|
||||
@keydown="handleInputKeydown"
|
||||
@paste="handleInputPaste"
|
||||
@compositionstart="handleCompositionStart"
|
||||
@compositionend="handleCompositionEnd"
|
||||
/>
|
||||
|
||||
@@ -519,6 +519,49 @@ describe('AgentAssistantPanel stream recovery', () => {
|
||||
wrapper.unmount()
|
||||
})
|
||||
|
||||
it('adds a pasted clipboard image to the pending attachments', async () => {
|
||||
vi.stubGlobal('fetch', vi.fn(async () => createAgentResponse([])))
|
||||
const createObjectURL = vi.fn(() => 'blob:pasted-image')
|
||||
Object.defineProperty(URL, 'createObjectURL', { configurable: true, value: createObjectURL })
|
||||
Object.defineProperty(URL, 'revokeObjectURL', { configurable: true, value: vi.fn() })
|
||||
const screenshot = new File(['screenshot'], 'image.png', { type: 'image/png' })
|
||||
const wrapper = shallowMount(AgentAssistantPanel, {
|
||||
props: { modelValue: true },
|
||||
global: {
|
||||
stubs: {
|
||||
AgentMarkdownContent: agentMarkdownContentStub,
|
||||
IconBtn: { template: '<button><slot /></button>' },
|
||||
PerfectScrollbar: { template: '<div><slot /></div>' },
|
||||
VIcon: true,
|
||||
},
|
||||
},
|
||||
})
|
||||
await flushPromises()
|
||||
|
||||
const pasteEvent = new Event('paste', { bubbles: true, cancelable: true })
|
||||
Object.defineProperty(pasteEvent, 'clipboardData', {
|
||||
value: {
|
||||
items: [
|
||||
{
|
||||
kind: 'file',
|
||||
type: 'image/png',
|
||||
getAsFile: () => screenshot,
|
||||
},
|
||||
],
|
||||
},
|
||||
})
|
||||
wrapper.get('textarea').element.dispatchEvent(pasteEvent)
|
||||
await flushPromises()
|
||||
|
||||
expect(pasteEvent.defaultPrevented).toBe(true)
|
||||
expect(createObjectURL).toHaveBeenCalledWith(screenshot)
|
||||
expect(wrapper.get('.agent-assistant-pending-file').text()).toContain('image.png')
|
||||
|
||||
wrapper.unmount()
|
||||
Reflect.deleteProperty(URL, 'createObjectURL')
|
||||
Reflect.deleteProperty(URL, 'revokeObjectURL')
|
||||
})
|
||||
|
||||
it('renders protected delivery only as transient literal text and advertises the stream capability', async () => {
|
||||
const protectedMarker = 'MP-PROTECTED-MARKER **not bold** <script>literal</script>'
|
||||
const fetchMock = vi.fn(async (input: RequestInfo | URL, init?: RequestInit) => {
|
||||
|
||||
Reference in New Issue
Block a user