feat(files): POSIX paths, elevation, recursive chmod, access hints and docs

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
Your Name
2026-06-01 19:54:18 +08:00
parent 1cfac23c01
commit d93c518a14
79 changed files with 7784 additions and 394 deletions
+24 -1
View File
@@ -184,6 +184,17 @@
<v-text-field v-model="form.ssh_user" label="SSH 用户" variant="outlined" density="compact" class="mb-2" :rules="[required('用户名')]" />
<v-text-field v-model="form.ssh_port" label="SSH 端口" variant="outlined" density="compact" type="number" class="mb-2" />
<v-text-field v-model="form.password" label="密码" variant="outlined" density="compact" type="password" class="mb-2" />
<v-select
v-model="form.files_elevation"
:items="filesElevationItems"
item-title="title"
item-value="value"
label="文件管理提权"
variant="outlined"
density="compact"
hint="非 root SSH 用户需目标机配置免密 sudo;示例见 docs/deploy/nexus-files-sudoers.example"
persistent-hint
/>
</v-card-text>
<v-card-actions>
<v-spacer />
@@ -271,9 +282,16 @@ const deleting = ref(false)
const deletingServer = ref<ServerApiItem | null>(null)
const editingId = ref<number | null>(null)
const filesElevationItems = [
{ title: '自动(权限失败时 sudo', value: 'auto_sudo' },
{ title: '关闭 sudo', value: 'off' },
{ title: '始终 sudo(排障)', value: 'always_sudo' },
]
const form = ref({
name: '', address: '', category: '', platform_id: null as number | null,
ssh_user: '', ssh_port: 22, password: '',
files_elevation: 'auto_sudo' as 'off' | 'auto_sudo' | 'always_sudo',
})
// ── Batch selection (Vuetify returns IDs when item-value="id", objects when return-object) ──
@@ -463,6 +481,7 @@ function editServer(item: ServerApiItem) {
name: item.name, address: item.domain || '', category: item.category || '',
platform_id: item.platform_id, ssh_user: item.username || '',
ssh_port: item.port || 22, password: '',
files_elevation: item.files_elevation || 'auto_sudo',
}
showAdd.value = true
}
@@ -483,6 +502,7 @@ async function saveServer() {
category: form.value.category || undefined,
platform_id: form.value.platform_id || undefined,
password: form.value.password || undefined,
files_elevation: form.value.files_elevation,
}
if (editing.value && editingId.value) {
await http.put(`/servers/${editingId.value}`, payload)
@@ -520,7 +540,10 @@ async function doDelete() {
function resetForm() {
editing.value = false
editingId.value = null
form.value = { name: '', address: '', category: '', platform_id: null, ssh_user: '', ssh_port: 22, password: '' }
form.value = {
name: '', address: '', category: '', platform_id: null, ssh_user: '', ssh_port: 22,
password: '', files_elevation: 'auto_sudo',
}
}
// ── Init ──