mirror of
https://gitee.com/mateos/mateclaw.git
synced 2026-09-13 19:23:42 +08:00
chore: bump version to 1.0.101-SNAPSHOT with versioned docs
This commit is contained in:
parent
d7dcaab6f4
commit
eea622099d
@ -6,7 +6,7 @@
|
|||||||
|
|
||||||
<groupId>vip.mate</groupId>
|
<groupId>vip.mate</groupId>
|
||||||
<artifactId>mateclaw-server</artifactId>
|
<artifactId>mateclaw-server</artifactId>
|
||||||
<version>1.0.0-SNAPSHOT</version>
|
<version>1.0.101-SNAPSHOT</version>
|
||||||
<packaging>jar</packaging>
|
<packaging>jar</packaging>
|
||||||
|
|
||||||
<name>MateClaw Server</name>
|
<name>MateClaw Server</name>
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "mateclaw-ui",
|
"name": "mateclaw-ui",
|
||||||
"version": "1.0.0",
|
"version": "1.0.101-SNAPSHOT",
|
||||||
"private": true,
|
"private": true,
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"description": "MateClaw - Personal AI Assistant Web Console",
|
"description": "MateClaw - Personal AI Assistant Web Console",
|
||||||
|
|||||||
@ -12,22 +12,25 @@
|
|||||||
<div v-if="attachments.length" class="attachment-list">
|
<div v-if="attachments.length" class="attachment-list">
|
||||||
<div
|
<div
|
||||||
v-for="attachment in attachments"
|
v-for="attachment in attachments"
|
||||||
:key="attachment.storedName"
|
:key="attachment.storedName || attachment.path"
|
||||||
class="attachment-chip"
|
class="attachment-chip"
|
||||||
|
:class="{ 'attachment-chip--dir': attachment.contentType === 'inode/directory' }"
|
||||||
>
|
>
|
||||||
<a
|
<component
|
||||||
:href="attachment.url"
|
:is="attachment.url ? 'a' : 'span'"
|
||||||
|
:href="attachment.url || undefined"
|
||||||
target="_blank"
|
target="_blank"
|
||||||
rel="noreferrer"
|
rel="noreferrer"
|
||||||
class="attachment-chip__label"
|
class="attachment-chip__label"
|
||||||
>
|
>
|
||||||
<span>{{ attachment.name }}</span>
|
<span>{{ attachment.contentType === 'inode/directory' ? '📁 ' : '' }}{{ attachment.name }}</span>
|
||||||
<span>{{ formatFileSize(attachment.size) }}</span>
|
<span v-if="attachment.size">{{ formatFileSize(attachment.size) }}</span>
|
||||||
</a>
|
<span v-else-if="attachment.contentType === 'inode/directory'" class="attachment-chip__path">{{ attachment.path }}</span>
|
||||||
|
</component>
|
||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
class="attachment-chip__remove"
|
class="attachment-chip__remove"
|
||||||
@click="removeAttachment(attachment.storedName)"
|
@click="removeAttachment(attachment.storedName || attachment.path)"
|
||||||
>
|
>
|
||||||
×
|
×
|
||||||
</button>
|
</button>
|
||||||
@ -443,6 +446,19 @@ defineExpose({
|
|||||||
background: rgba(217, 119, 87, 0.24);
|
background: rgba(217, 119, 87, 0.24);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.attachment-chip--dir {
|
||||||
|
border-style: dashed;
|
||||||
|
}
|
||||||
|
|
||||||
|
.attachment-chip__path {
|
||||||
|
font-size: 11px;
|
||||||
|
color: var(--mc-text-tertiary, #94a3b8);
|
||||||
|
max-width: 200px;
|
||||||
|
overflow: hidden;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
|
|
||||||
/* 输入区域 */
|
/* 输入区域 */
|
||||||
.input-area {
|
.input-area {
|
||||||
display: flex;
|
display: flex;
|
||||||
|
|||||||
@ -106,7 +106,7 @@ export default {
|
|||||||
deleteConversationFailed: 'Failed to delete conversation',
|
deleteConversationFailed: 'Failed to delete conversation',
|
||||||
switchModelFailed: 'Failed to switch model',
|
switchModelFailed: 'Failed to switch model',
|
||||||
uploadFailed: 'File upload failed',
|
uploadFailed: 'File upload failed',
|
||||||
dropToUpload: 'Drop files here to upload',
|
dropToUpload: 'Drop files or folders here',
|
||||||
copyFailed: 'Copy failed',
|
copyFailed: 'Copy failed',
|
||||||
dateToday: 'Today',
|
dateToday: 'Today',
|
||||||
dateYesterday: 'Yesterday',
|
dateYesterday: 'Yesterday',
|
||||||
|
|||||||
@ -106,7 +106,7 @@ export default {
|
|||||||
deleteConversationFailed: '删除会话失败',
|
deleteConversationFailed: '删除会话失败',
|
||||||
switchModelFailed: '切换模型失败',
|
switchModelFailed: '切换模型失败',
|
||||||
uploadFailed: '文件上传失败',
|
uploadFailed: '文件上传失败',
|
||||||
dropToUpload: '拖放文件到此处上传',
|
dropToUpload: '拖放文件或文件夹到此处',
|
||||||
copyFailed: '复制失败',
|
copyFailed: '复制失败',
|
||||||
dateToday: '今天',
|
dateToday: '今天',
|
||||||
dateYesterday: '昨天',
|
dateYesterday: '昨天',
|
||||||
|
|||||||
@ -240,13 +240,94 @@ function onDragLeave() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function onDrop(e: DragEvent) {
|
async function onDrop(e: DragEvent) {
|
||||||
dragCounter = 0
|
dragCounter = 0
|
||||||
isDragging.value = false
|
isDragging.value = false
|
||||||
const files = Array.from(e.dataTransfer?.files || [])
|
|
||||||
if (files.length) {
|
const dtFiles = Array.from(e.dataTransfer?.files || [])
|
||||||
handleFileSelect(files)
|
const items = Array.from(e.dataTransfer?.items || [])
|
||||||
|
|
||||||
|
const electronDirs: File[] = []
|
||||||
|
const webDirEntries: FileSystemDirectoryEntry[] = []
|
||||||
|
const regularFiles: File[] = []
|
||||||
|
|
||||||
|
for (let i = 0; i < items.length; i++) {
|
||||||
|
const entry = items[i].webkitGetAsEntry?.()
|
||||||
|
const file = dtFiles[i]
|
||||||
|
if (entry?.isDirectory) {
|
||||||
|
if ((file as any)?.path) {
|
||||||
|
// Electron: has absolute path
|
||||||
|
electronDirs.push(file)
|
||||||
|
} else {
|
||||||
|
// Web: need to recursively collect files
|
||||||
|
webDirEntries.push(entry as FileSystemDirectoryEntry)
|
||||||
|
}
|
||||||
|
} else if (file) {
|
||||||
|
regularFiles.push(file)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Electron directories → record path reference
|
||||||
|
if (electronDirs.length) {
|
||||||
|
handleDirectoryAttach(electronDirs)
|
||||||
|
}
|
||||||
|
// Web directories → recursively collect files and upload
|
||||||
|
if (webDirEntries.length) {
|
||||||
|
const collected = await collectFilesFromEntries(webDirEntries)
|
||||||
|
if (collected.length) {
|
||||||
|
handleFileSelect(collected)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Regular files → normal upload
|
||||||
|
if (regularFiles.length) {
|
||||||
|
handleFileSelect(regularFiles)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function handleDirectoryAttach(dirFiles: File[]) {
|
||||||
|
if (!currentConversationId.value) {
|
||||||
|
newConversation()
|
||||||
|
}
|
||||||
|
for (const dir of dirFiles) {
|
||||||
|
const dirPath = (dir as any).path as string
|
||||||
|
pendingAttachments.value.push({
|
||||||
|
name: dirPath.split('/').pop() || dir.name,
|
||||||
|
size: 0,
|
||||||
|
url: '',
|
||||||
|
storedName: '',
|
||||||
|
path: dirPath,
|
||||||
|
contentType: 'inode/directory',
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async function collectFilesFromEntries(dirEntries: FileSystemDirectoryEntry[]): Promise<File[]> {
|
||||||
|
const files: File[] = []
|
||||||
|
|
||||||
|
async function readDir(dir: FileSystemDirectoryEntry) {
|
||||||
|
const reader = dir.createReader()
|
||||||
|
let batch: FileSystemEntry[]
|
||||||
|
do {
|
||||||
|
batch = await new Promise<FileSystemEntry[]>((resolve, reject) => {
|
||||||
|
reader.readEntries(resolve, reject)
|
||||||
|
})
|
||||||
|
for (const entry of batch) {
|
||||||
|
if (entry.isFile) {
|
||||||
|
const file = await new Promise<File>((resolve, reject) => {
|
||||||
|
(entry as FileSystemFileEntry).file(resolve, reject)
|
||||||
|
})
|
||||||
|
files.push(file)
|
||||||
|
} else if (entry.isDirectory) {
|
||||||
|
await readDir(entry as FileSystemDirectoryEntry)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} while (batch.length > 0) // readEntries returns empty when done
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const dir of dirEntries) {
|
||||||
|
await readDir(dir)
|
||||||
|
}
|
||||||
|
return files
|
||||||
}
|
}
|
||||||
|
|
||||||
const messageListRef = ref<InstanceType<typeof MessageList> | null>(null)
|
const messageListRef = ref<InstanceType<typeof MessageList> | null>(null)
|
||||||
@ -815,8 +896,10 @@ async function handleFileSelect(files: File[]) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function removeAttachment(storedName: string) {
|
function removeAttachment(key: string) {
|
||||||
pendingAttachments.value = pendingAttachments.value.filter(a => a.storedName !== storedName)
|
pendingAttachments.value = pendingAttachments.value.filter(
|
||||||
|
a => a.storedName !== key && a.path !== key
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
function buildOutgoingParts(text: string, attachments: ChatAttachment[]): MessageContentPart[] {
|
function buildOutgoingParts(text: string, attachments: ChatAttachment[]): MessageContentPart[] {
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user