Files
hermes-web/packages/client/src/components/hermes/files/FileRenameModal.vue
T
toor 4baccd5d88 Phase 005: vendor ArkScope, land the Arco style baseline, and fix bridge interpreter resolution
- Vendor ArkScope decorative layers (ScrambleTitle / IsometricWave) with provenance notes; decorative-only per AGENTS.md red lines
- Migrate theme tokens to Arco, register the Arco theme, and add hook adapter composables (useMessage / useDialog / useNotification) with matching signatures
- Sample pages: LoginView and AppSidebar on the new baseline; docs/arco-mapping.md and docs/ui-baseline.md land
- agent-bridge: prefer the PM-selected venv from facts.json over legacy in-tree venvs (legacy lacks the mcp extra, so every MCP server showed 0 tools / not connected)
- agent-bridge python (vendored, deliberate deviation): MCP discovery import fallback and pyyaml -> hermes_yaml so plugins and MCP work under the PM env; install the mcp extra via `hermes pm install --extra mcp`
- Chat-chain fragment: docs/chat-chain-changes/2026-10-17-phase005-arkscope-baseline.md

Verified: harness:check, test (2020 passed), test:e2e (30 passed), build all green; manual: plugins 100/0 warnings, MCP 6/6 servers connected with 104 tools.
2026-10-17 09:45:30 +08:00

101 lines
2.7 KiB
Vue

<script setup lang="ts">
import { ref, watch, computed } from 'vue'
import { NModal, NInput, NButton, NSpace } from 'naive-ui'
import { useMessage } from '@/composables/useMessage'
import { useI18n } from 'vue-i18n'
import { useFilesStore } from '@/stores/hermes/files'
import type { FileEntry } from '@/api/hermes/files'
const { t } = useI18n()
const message = useMessage()
const filesStore = useFilesStore()
const props = defineProps<{
show: boolean
mode: 'newFile' | 'newFolder' | 'rename'
entry?: FileEntry | null
targetPath?: string | null
}>()
const emit = defineEmits<{
(e: 'update:show', value: boolean): void
}>()
const inputValue = ref('')
const submitting = ref(false)
watch(() => props.show, (val) => {
if (val) {
if (props.mode === 'rename' && props.entry) {
inputValue.value = props.entry.name
} else {
inputValue.value = ''
}
}
})
const title = computed(() => {
switch (props.mode) {
case 'newFile': return t('files.newFile')
case 'newFolder': return t('files.newFolder')
case 'rename': return t('files.rename')
}
})
const placeholder = computed(() => {
switch (props.mode) {
case 'newFile': return t('files.newFileName')
case 'newFolder': return t('files.newFolderName')
case 'rename': return t('files.renameTo')
}
})
async function handleSubmit() {
if (!inputValue.value.trim()) return
submitting.value = true
try {
switch (props.mode) {
case 'newFile':
await filesStore.createFile(inputValue.value.trim())
message.success(t('files.created'))
break
case 'newFolder':
await filesStore.createDir(inputValue.value.trim(), props.targetPath || undefined)
message.success(t('files.created'))
break
case 'rename':
if (props.entry) {
await filesStore.renameEntry(props.entry, inputValue.value.trim())
message.success(t('files.renamed'))
}
break
}
emit('update:show', false)
} catch (err: any) {
const msg = props.mode === 'rename' ? t('files.renameFailed') : t('files.createFailed')
message.error(err.message || msg)
} finally {
submitting.value = false
}
}
</script>
<template>
<NModal :show="props.show" preset="dialog" :title="title" @update:show="emit('update:show', false)" style="width: 400px;">
<NInput
v-model:value="inputValue"
:placeholder="placeholder"
@keydown.enter="handleSubmit"
autofocus
/>
<template #action>
<NSpace>
<NButton @click="emit('update:show', false)">{{ t('common.cancel') }}</NButton>
<NButton type="primary" :loading="submitting" :disabled="!inputValue.trim()" @click="handleSubmit">
{{ t('common.ok') }}
</NButton>
</NSpace>
</template>
</NModal>
</template>