fix(files): close preview on navigation/delete/rename + backfill i18n (#150)

* i18n: backfill files/download translations for de, es, fr, ja, ko, pt

Add nav.files, files.* (39 keys), and download.* (9 keys) so the file
browser UI is fully localized in these six locales instead of falling
back to English.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* fix(files): close preview when navigating or affected file changes

Opening a preview and then navigating directories, deleting the
previewed file, or renaming it left the preview pane stuck on stale
content because previewFile was never cleared.

- stores/hermes/files.ts:
  - fetchEntries clears previewFile on path change (in-place refresh
    keeps the preview).
  - deleteEntry / renameEntry clear preview/editor state when the
    affected entry matches the previewed/edited file or its parent.
  - Add isAffected(target, changed, isDir) helper.
- components/hermes/files/FilePreview.vue: replace the misleading
  common.cancel close button with a dedicated files.closePreview key
  plus an X icon and quaternary style.
- i18n: add files.closePreview to all 8 locales.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

---------

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
This commit is contained in:
ww
2026-04-23 14:10:14 +08:00
committed by GitHub
parent 93719fb04b
commit a4bfd8edd3
10 changed files with 427 additions and 39 deletions
@@ -1,5 +1,6 @@
<script setup lang="ts">
import { NButton } from 'naive-ui'
import { h } from 'vue'
import { NButton, NIcon } from 'naive-ui'
import { useI18n } from 'vue-i18n'
import { useFilesStore } from '@/stores/hermes/files'
import { getFileDownloadUrl } from '@/api/hermes/files'
@@ -12,14 +13,24 @@ function getImageUrl(): string {
if (!filesStore.previewFile) return ''
return getFileDownloadUrl(filesStore.previewFile.path)
}
const CloseIcon = () =>
h(
'svg',
{ viewBox: '0 0 24 24', width: '14', height: '14', fill: 'currentColor' },
[h('path', { d: 'M19 6.41 17.59 5 12 10.59 6.41 5 5 6.41 10.59 12 5 17.59 6.41 19 12 13.41 17.59 19 19 17.59 13.41 12z' })],
)
</script>
<template>
<div class="file-preview" v-if="filesStore.previewFile">
<div class="preview-header">
<span class="preview-filename">{{ filesStore.previewFile.path }}</span>
<NButton size="small" @click="filesStore.closePreview()">
{{ t('common.cancel') }}
<NButton size="small" quaternary @click="filesStore.closePreview()">
<template #icon>
<NIcon><CloseIcon /></NIcon>
</template>
{{ t('files.closePreview') }}
</NButton>
</div>
<div class="preview-content">
+64 -6
View File
@@ -75,6 +75,7 @@ export default {
usage: 'Nutzung',
channels: 'Kanale',
terminal: 'Terminal',
files: 'Dateien',
settings: 'Einstellungen',
connected: 'Verbunden',
disconnected: 'Getrennt',
@@ -84,7 +85,6 @@ export default {
updateSuccess: 'Aktualisierung abgeschlossen, bitte Server neu starten',
updateFailed: 'Aktualisierung fehlgeschlagen',
logout: 'Abmelden',
nodeVersionWarning: 'Node.js v{version} erkannt. Version 23+ wird fur volle Funktionalitat benotigt (SQLite, node-pty).',
changelog: 'Anderungsprotokoll',
noChangelog: 'Kein Anderungsprotokoll verfugbar',
},
@@ -511,11 +511,6 @@ export default {
// Anderungsprotokoll
changelog: {
new_0_4_4_1: 'Dateibrowser mit Multi-Backend-Unterstutzung hinzugefugt (local/Docker/SSH/Singularity)',
new_0_4_4_2: 'Dateidownload aus Chat-Nachrichtenanhangen hinzugefugt',
new_0_4_4_3: 'Live-Badge auf aktiven Chat-Sitzungen hinzugefugt',
new_0_4_4_4: 'StepFun- und Nous-Portal-Provider-Unterstutzung hinzugefugt',
new_0_4_4_5: 'Spezialzeichen-Suche verursacht 500-Fehler behoben',
new_0_4_3_1: 'Benutzername/Passwort-Login neben Token-Authentifizierung hinzugefugt',
new_0_4_3_2: 'Kontoeinstellungen fur Anmeldeinformationen hinzugefugt',
new_0_4_3_3: 'Abmelden-Schaltflache in der Seitenleiste hinzugefugt',
@@ -527,4 +522,67 @@ export default {
new_0_4_2_5: 'Eingebaute Provider-Erkennung und Modellabgleich behoben',
new_0_4_1_1: 'Authentifizierungsumgehung und SPA-Bereitstellung behoben',
},
// Dateien
files: {
title: 'Dateien',
tree: 'Verzeichnisbaum',
list: 'Dateiliste',
breadcrumbRoot: 'Start',
newFile: 'Neue Datei',
newFolder: 'Neuer Ordner',
upload: 'Hochladen',
refresh: 'Aktualisieren',
open: 'Offnen',
edit: 'Bearbeiten',
preview: 'Vorschau',
download: 'Herunterladen',
copyPath: 'Pfad kopieren',
rename: 'Umbenennen',
delete: 'Loschen',
name: 'Name',
size: 'Grosse',
modified: 'Geandert',
actions: 'Aktionen',
emptyDir: 'Leeres Verzeichnis',
loading: 'Wird geladen...',
confirmDelete: 'Mochten Sie "{name}" wirklich loschen?',
confirmDeleteDir: 'Mochten Sie das Verzeichnis "{name}" und seinen gesamten Inhalt wirklich loschen?',
deleteFailed: 'Loschen fehlgeschlagen',
deleted: 'Geloscht',
renameTo: 'Umbenennen in',
newFileName: 'Dateiname',
newFolderName: 'Ordnername',
created: 'Erstellt',
createFailed: 'Erstellen fehlgeschlagen',
renamed: 'Umbenannt',
renameFailed: 'Umbenennen fehlgeschlagen',
uploadSuccess: '{count} Datei(en) hochgeladen',
uploadFailed: 'Hochladen fehlgeschlagen',
saveFailed: 'Speichern fehlgeschlagen',
saved: 'Gespeichert',
unsavedChanges: 'Sie haben ungespeicherte Anderungen. Verwerfen?',
pathCopied: 'Pfad kopiert',
fileTooLarge: 'Datei zu gross (max. 10 MB)',
permissionDenied: 'Geschutzte Datei kann nicht geandert werden',
notFound: 'Datei oder Verzeichnis nicht gefunden',
backendError: 'Dateioperation fehlgeschlagen',
dragDropHint: 'Dateien hierher ziehen, um sie hochzuladen',
closeEditor: 'Editor schliessen',
closePreview: 'Schliessen',
saveFile: 'Speichern',
},
// Download
download: {
downloading: 'Wird heruntergeladen...',
downloadFailed: 'Download fehlgeschlagen',
fileNotFound: 'Datei nicht gefunden oder geloscht',
fileTooLarge: 'Datei zu gross (Limit uberschritten)',
backendError: 'Lesen der Datei fehlgeschlagen, Remote-Umgebung moglicherweise nicht verfugbar',
backendTimeout: 'Zeituberschreitung beim Lesen der Datei',
unsupportedBackend: 'Aktuelles Terminal-Backend unterstutzt keine Datei-Downloads',
invalidPath: 'Ungultiger Dateipfad',
download: 'Herunterladen',
},
}
+1
View File
@@ -595,6 +595,7 @@ export default {
backendError: 'File operation failed',
dragDropHint: 'Drag files here to upload',
closeEditor: 'Close Editor',
closePreview: 'Close',
saveFile: 'Save',
},
// Download
+64 -6
View File
@@ -75,6 +75,7 @@ export default {
usage: 'Uso',
channels: 'Canales',
terminal: 'Terminal',
files: 'Archivos',
settings: 'Configuracion',
connected: 'Conectado',
disconnected: 'Desconectado',
@@ -84,7 +85,6 @@ export default {
updateSuccess: 'Actualizacion completa, por favor reinicia el servidor',
updateFailed: 'Error al actualizar',
logout: 'Cerrar sesion',
nodeVersionWarning: 'Node.js v{version} detectado. Se requiere la version 23+ para todas las funcionalidades (SQLite, node-pty).',
changelog: 'Registro de cambios',
noChangelog: 'No hay registro de cambios',
},
@@ -511,11 +511,6 @@ export default {
// Registro de cambios
changelog: {
new_0_4_4_1: 'Agregar explorador de archivos con soporte multi-backend (local/Docker/SSH/Singularity)',
new_0_4_4_2: 'Agregar descarga de archivos desde archivos adjuntos del chat',
new_0_4_4_3: 'Agregar indicador en vivo en sesiones de chat activas',
new_0_4_4_4: 'Agregar soporte para proveedores StepFun y Nous Portal',
new_0_4_4_5: 'Corregir error 500 al buscar con caracteres especiales',
new_0_4_3_1: 'Agregar inicio de sesion con usuario/contrasena junto a autenticacion por token',
new_0_4_3_2: 'Agregar configuracion de cuenta para gestionar credenciales',
new_0_4_3_3: 'Agregar boton de cerrar sesion en la barra lateral',
@@ -527,4 +522,67 @@ export default {
new_0_4_2_5: 'Corregir deteccion de proveedores integrados y coincidencia de modelos',
new_0_4_1_1: 'Corregir bypass de autenticacion y servicio de archivos SPA',
},
// Archivos
files: {
title: 'Archivos',
tree: 'Arbol de directorios',
list: 'Lista de archivos',
breadcrumbRoot: 'Inicio',
newFile: 'Nuevo archivo',
newFolder: 'Nueva carpeta',
upload: 'Subir',
refresh: 'Actualizar',
open: 'Abrir',
edit: 'Editar',
preview: 'Vista previa',
download: 'Descargar',
copyPath: 'Copiar ruta',
rename: 'Renombrar',
delete: 'Eliminar',
name: 'Nombre',
size: 'Tamano',
modified: 'Modificado',
actions: 'Acciones',
emptyDir: 'Directorio vacio',
loading: 'Cargando...',
confirmDelete: '?Seguro que quiere eliminar "{name}"?',
confirmDeleteDir: '?Seguro que quiere eliminar el directorio "{name}" y todo su contenido?',
deleteFailed: 'Error al eliminar',
deleted: 'Eliminado',
renameTo: 'Renombrar a',
newFileName: 'Nombre del archivo',
newFolderName: 'Nombre de la carpeta',
created: 'Creado',
createFailed: 'Error al crear',
renamed: 'Renombrado',
renameFailed: 'Error al renombrar',
uploadSuccess: '{count} archivo(s) subido(s)',
uploadFailed: 'Error al subir',
saveFailed: 'Error al guardar',
saved: 'Guardado',
unsavedChanges: 'Tiene cambios sin guardar. ?Descartar?',
pathCopied: 'Ruta copiada',
fileTooLarge: 'Archivo demasiado grande (max 10MB)',
permissionDenied: 'No se puede modificar un archivo protegido',
notFound: 'Archivo o directorio no encontrado',
backendError: 'Error en la operacion de archivo',
dragDropHint: 'Arrastra archivos aqui para subir',
closeEditor: 'Cerrar editor',
closePreview: 'Cerrar',
saveFile: 'Guardar',
},
// Descarga
download: {
downloading: 'Descargando...',
downloadFailed: 'Error en la descarga',
fileNotFound: 'Archivo no encontrado o eliminado',
fileTooLarge: 'Archivo demasiado grande (excede el limite)',
backendError: 'Error al leer el archivo, el entorno remoto puede no estar disponible',
backendTimeout: 'Tiempo de lectura del archivo agotado',
unsupportedBackend: 'El backend del terminal actual no admite la descarga de archivos',
invalidPath: 'Ruta de archivo invalida',
download: 'Descargar',
},
}
+64 -6
View File
@@ -75,6 +75,7 @@ export default {
usage: 'Utilisation',
channels: 'Canaux',
terminal: 'Terminal',
files: 'Fichiers',
settings: 'Parametres',
connected: 'Connecte',
disconnected: 'Deconnecte',
@@ -84,7 +85,6 @@ export default {
updateSuccess: 'Mise a jour terminee, veuillez redemarrer le serveur',
updateFailed: 'Echec de la mise a jour',
logout: 'Deconnexion',
nodeVersionWarning: 'Node.js v{version} detecte. La version 23+ est requise pour toutes les fonctionnalites (SQLite, node-pty).',
changelog: 'Journal des modifications',
noChangelog: 'Aucun journal disponible',
},
@@ -511,11 +511,6 @@ export default {
// Journal des modifications
changelog: {
new_0_4_4_1: 'Ajout du navigateur de fichiers avec support multi-backend (local/Docker/SSH/Singularity)',
new_0_4_4_2: 'Ajout du telechargement de fichiers depuis les pieces jointes',
new_0_4_4_3: 'Ajout du badge en direct sur les sessions actives',
new_0_4_4_4: 'Ajout du support des fournisseurs StepFun et Nous Portal',
new_0_4_4_5: 'Correction de l\'erreur 500 lors de la recherche avec caracteres speciaux',
new_0_4_3_1: 'Ajouter la connexion par nom d\'utilisateur/mot de passe en plus du token',
new_0_4_3_2: 'Ajouter les parametres de compte pour gerer les identifiants',
new_0_4_3_3: 'Ajouter le bouton de deconnexion dans la barre laterale',
@@ -527,4 +522,67 @@ export default {
new_0_4_2_5: 'Corriger la detection des fournisseurs integres et l\'appariement des modeles',
new_0_4_1_1: 'Corriger le contournement d\'authentification et le service de fichiers SPA',
},
// Fichiers
files: {
title: 'Fichiers',
tree: 'Arborescence',
list: 'Liste des fichiers',
breadcrumbRoot: 'Accueil',
newFile: 'Nouveau fichier',
newFolder: 'Nouveau dossier',
upload: 'Telecharger',
refresh: 'Actualiser',
open: 'Ouvrir',
edit: 'Modifier',
preview: 'Apercu',
download: 'Telecharger',
copyPath: 'Copier le chemin',
rename: 'Renommer',
delete: 'Supprimer',
name: 'Nom',
size: 'Taille',
modified: 'Modifie',
actions: 'Actions',
emptyDir: 'Dossier vide',
loading: 'Chargement...',
confirmDelete: 'Voulez-vous vraiment supprimer "{name}" ?',
confirmDeleteDir: 'Voulez-vous vraiment supprimer le dossier "{name}" et tout son contenu ?',
deleteFailed: 'Echec de la suppression',
deleted: 'Supprime',
renameTo: 'Renommer en',
newFileName: 'Nom du fichier',
newFolderName: 'Nom du dossier',
created: 'Cree',
createFailed: 'Echec de la creation',
renamed: 'Renomme',
renameFailed: 'Echec du renommage',
uploadSuccess: '{count} fichier(s) televerse(s)',
uploadFailed: 'Echec du televersement',
saveFailed: 'Echec de l\'enregistrement',
saved: 'Enregistre',
unsavedChanges: 'Vous avez des modifications non enregistrees. Annuler ?',
pathCopied: 'Chemin copie',
fileTooLarge: 'Fichier trop volumineux (max 10 Mo)',
permissionDenied: 'Impossible de modifier un fichier protege',
notFound: 'Fichier ou dossier introuvable',
backendError: 'Echec de l\'operation sur le fichier',
dragDropHint: 'Glissez des fichiers ici pour les televerser',
closeEditor: 'Fermer l\'editeur',
closePreview: 'Fermer',
saveFile: 'Enregistrer',
},
// Telechargement
download: {
downloading: 'Telechargement...',
downloadFailed: 'Echec du telechargement',
fileNotFound: 'Fichier introuvable ou supprime',
fileTooLarge: 'Fichier trop volumineux (limite depassee)',
backendError: 'Echec de la lecture du fichier, l\'environnement distant est peut-etre indisponible',
backendTimeout: 'Delai de lecture du fichier depasse',
unsupportedBackend: 'Le backend de terminal actuel ne prend pas en charge le telechargement de fichiers',
invalidPath: 'Chemin de fichier invalide',
download: 'Telecharger',
},
}
+64 -6
View File
@@ -75,6 +75,7 @@ export default {
usage: '使用量',
channels: 'チャンネル',
terminal: 'ターミナル',
files: 'ファイル',
settings: '設定',
connected: '接続済み',
disconnected: '未接続',
@@ -84,7 +85,6 @@ export default {
updateSuccess: '更新が完了しました。サーバーを再起動してください',
updateFailed: '更新に失敗しました',
logout: 'ログアウト',
nodeVersionWarning: 'Node.js v{version} が検出されました。全機能にはバージョン23+が必要です(SQLite、node-pty)。',
changelog: '更新履歴',
noChangelog: '更新履歴はありません',
},
@@ -511,11 +511,6 @@ export default {
// 更新履歴
changelog: {
new_0_4_4_1: 'ファイルブラウザを追加(local/Docker/SSH/Singularity対応)',
new_0_4_4_2: 'チャットメッセージの添付ファイルダウンロードを追加',
new_0_4_4_3: 'アクティブセッションにライブバッジを表示',
new_0_4_4_4: 'StepFunとNous Portalプロバイダーに対応',
new_0_4_4_5: '特殊文字検索で500エラーになる問題を修正',
new_0_4_3_1: 'トークン認証に加えてユーザー名/パスワードログインを追加',
new_0_4_3_2: '資格情報管理のためのアカウント設定を追加',
new_0_4_3_3: 'サイドバーにログアウトボタンを追加',
@@ -527,4 +522,67 @@ export default {
new_0_4_2_5: '組み込みプロバイダー検出とモデルマッチングを修正',
new_0_4_1_1: '認証バイパスとSPAファイル配信を修正',
},
// ファイル
files: {
title: 'ファイル',
tree: 'ディレクトリツリー',
list: 'ファイル一覧',
breadcrumbRoot: 'ホーム',
newFile: '新規ファイル',
newFolder: '新規フォルダ',
upload: 'アップロード',
refresh: '更新',
open: '開く',
edit: '編集',
preview: 'プレビュー',
download: 'ダウンロード',
copyPath: 'パスをコピー',
rename: '名前の変更',
delete: '削除',
name: '名前',
size: 'サイズ',
modified: '更新日時',
actions: '操作',
emptyDir: '空のディレクトリ',
loading: '読み込み中...',
confirmDelete: '「{name}」を削除してもよろしいですか?',
confirmDeleteDir: 'ディレクトリ「{name}」とそのすべての内容を削除してもよろしいですか?',
deleteFailed: '削除に失敗しました',
deleted: '削除しました',
renameTo: '名前を変更',
newFileName: 'ファイル名',
newFolderName: 'フォルダ名',
created: '作成しました',
createFailed: '作成に失敗しました',
renamed: '名前を変更しました',
renameFailed: '名前の変更に失敗しました',
uploadSuccess: '{count} 個のファイルをアップロードしました',
uploadFailed: 'アップロードに失敗しました',
saveFailed: '保存に失敗しました',
saved: '保存しました',
unsavedChanges: '未保存の変更があります。破棄しますか?',
pathCopied: 'パスをコピーしました',
fileTooLarge: 'ファイルが大きすぎます(最大10MB)',
permissionDenied: '保護されたファイルは変更できません',
notFound: 'ファイルまたはディレクトリが見つかりません',
backendError: 'ファイル操作に失敗しました',
dragDropHint: 'ここにファイルをドラッグしてアップロード',
closeEditor: 'エディタを閉じる',
closePreview: '閉じる',
saveFile: '保存',
},
// ダウンロード
download: {
downloading: 'ダウンロード中...',
downloadFailed: 'ダウンロードに失敗しました',
fileNotFound: 'ファイルが見つからないか削除されています',
fileTooLarge: 'ファイルが大きすぎます(制限超過)',
backendError: 'ファイルの読み取りに失敗しました。リモート環境が利用できない可能性があります',
backendTimeout: 'ファイルの読み取りがタイムアウトしました',
unsupportedBackend: '現在のターミナルバックエンドはファイルのダウンロードに対応していません',
invalidPath: '無効なファイルパス',
download: 'ダウンロード',
},
}
+64 -6
View File
@@ -75,6 +75,7 @@ export default {
usage: '사용량',
channels: '채널',
terminal: '터미널',
files: '파일',
settings: '설정',
connected: '연결됨',
disconnected: '연결 끊김',
@@ -84,7 +85,6 @@ export default {
updateSuccess: '업데이트 완료, 서버를 재시작해 주세요',
updateFailed: '업데이트 실패',
logout: '로그아웃',
nodeVersionWarning: 'Node.js v{version}이(가) 감지되었습니다. 전체 기능에는 버전 23+가 필요합니다(SQLite, node-pty).',
changelog: '변경 이력',
noChangelog: '변경 이력이 없습니다',
},
@@ -511,11 +511,6 @@ export default {
// 변경 이력
changelog: {
new_0_4_4_1: '파일 브라우저 추가 (local/Docker/SSH/Singularity 지원)',
new_0_4_4_2: '채팅 메시지 첨부 파일 다운로드 추가',
new_0_4_4_3: '활성 세션에 라이브 배지 표시',
new_0_4_4_4: 'StepFun 및 Nous Portal 프로바이더 지원 추가',
new_0_4_4_5: '특수문자 검색 시 500 에러 수정',
new_0_4_3_1: '토큰 인증과 함께 사용자 이름/비밀번호 로그인 추가',
new_0_4_3_2: '자격 증명 관리를 위한 계정 설정 추가',
new_0_4_3_3: '사이드바에 로그아웃 버튼 추가',
@@ -527,4 +522,67 @@ export default {
new_0_4_2_5: '내장 프로바이더 감지 및 모델 매칭 수정',
new_0_4_1_1: '인증 우회 및 SPA 파일 서비스 수정',
},
// 파일
files: {
title: '파일',
tree: '디렉터리 트리',
list: '파일 목록',
breadcrumbRoot: '홈',
newFile: '새 파일',
newFolder: '새 폴더',
upload: '업로드',
refresh: '새로고침',
open: '열기',
edit: '편집',
preview: '미리보기',
download: '다운로드',
copyPath: '경로 복사',
rename: '이름 변경',
delete: '삭제',
name: '이름',
size: '크기',
modified: '수정일',
actions: '작업',
emptyDir: '빈 디렉터리',
loading: '불러오는 중...',
confirmDelete: '"{name}"을(를) 삭제하시겠습니까?',
confirmDeleteDir: '디렉터리 "{name}"과 그 내부 항목을 모두 삭제하시겠습니까?',
deleteFailed: '삭제 실패',
deleted: '삭제됨',
renameTo: '새 이름',
newFileName: '파일 이름',
newFolderName: '폴더 이름',
created: '생성됨',
createFailed: '생성 실패',
renamed: '이름이 변경됨',
renameFailed: '이름 변경 실패',
uploadSuccess: '{count}개 파일이 업로드되었습니다',
uploadFailed: '업로드 실패',
saveFailed: '저장 실패',
saved: '저장됨',
unsavedChanges: '저장하지 않은 변경 사항이 있습니다. 취소하시겠습니까?',
pathCopied: '경로가 복사되었습니다',
fileTooLarge: '파일이 너무 큽니다 (최대 10MB)',
permissionDenied: '보호된 파일은 수정할 수 없습니다',
notFound: '파일 또는 디렉터리를 찾을 수 없습니다',
backendError: '파일 작업 실패',
dragDropHint: '여기로 파일을 드래그하여 업로드',
closeEditor: '편집기 닫기',
closePreview: '닫기',
saveFile: '저장',
},
// 다운로드
download: {
downloading: '다운로드 중...',
downloadFailed: '다운로드 실패',
fileNotFound: '파일을 찾을 수 없거나 삭제되었습니다',
fileTooLarge: '파일이 너무 큽니다 (제한 초과)',
backendError: '파일 읽기에 실패했습니다. 원격 환경이 사용 불가능할 수 있습니다',
backendTimeout: '파일 읽기 시간 초과',
unsupportedBackend: '현재 터미널 백엔드는 파일 다운로드를 지원하지 않습니다',
invalidPath: '잘못된 파일 경로',
download: '다운로드',
},
}
+64 -6
View File
@@ -75,6 +75,7 @@ export default {
usage: 'Uso',
channels: 'Canais',
terminal: 'Terminal',
files: 'Arquivos',
settings: 'Configuracoes',
connected: 'Conectado',
disconnected: 'Desconectado',
@@ -84,7 +85,6 @@ export default {
updateSuccess: 'Atualizacao concluida, por favor reinicie o servidor',
updateFailed: 'Falha na atualizacao',
logout: 'Sair',
nodeVersionWarning: 'Node.js v{version} detectado. A versao 23+ e necessaria para todas as funcionalidades (SQLite, node-pty).',
changelog: 'Registro de alteracoes',
noChangelog: 'Nenhum registro disponivel',
},
@@ -511,11 +511,6 @@ export default {
// Registro de alteracoes
changelog: {
new_0_4_4_1: 'Adicionar navegador de arquivos com suporte multi-backend (local/Docker/SSH/Singularity)',
new_0_4_4_2: 'Adicionar download de arquivos dos anexos de chat',
new_0_4_4_3: 'Adicionar indicador ao vivo nas sessoes de chat ativas',
new_0_4_4_4: 'Adicionar suporte para provedores StepFun e Nous Portal',
new_0_4_4_5: 'Corrigir erro 500 ao pesquisar com caracteres especiais',
new_0_4_3_1: 'Adicionar login por usuario/senha junto com autenticacao por token',
new_0_4_3_2: 'Adicionar configuracoes de conta para gerenciar credenciais',
new_0_4_3_3: 'Adicionar botao de sair na barra lateral',
@@ -527,4 +522,67 @@ export default {
new_0_4_2_5: 'Corrigir deteccao de provedores integrados e combinacao de modelos',
new_0_4_1_1: 'Corrigir bypass de autenticacao e servico de arquivos SPA',
},
// Arquivos
files: {
title: 'Arquivos',
tree: 'Arvore de diretorios',
list: 'Lista de arquivos',
breadcrumbRoot: 'Inicio',
newFile: 'Novo arquivo',
newFolder: 'Nova pasta',
upload: 'Enviar',
refresh: 'Atualizar',
open: 'Abrir',
edit: 'Editar',
preview: 'Visualizar',
download: 'Baixar',
copyPath: 'Copiar caminho',
rename: 'Renomear',
delete: 'Excluir',
name: 'Nome',
size: 'Tamanho',
modified: 'Modificado',
actions: 'Acoes',
emptyDir: 'Diretorio vazio',
loading: 'Carregando...',
confirmDelete: 'Tem certeza de que deseja excluir "{name}"?',
confirmDeleteDir: 'Tem certeza de que deseja excluir o diretorio "{name}" e todo o seu conteudo?',
deleteFailed: 'Falha ao excluir',
deleted: 'Excluido',
renameTo: 'Renomear para',
newFileName: 'Nome do arquivo',
newFolderName: 'Nome da pasta',
created: 'Criado',
createFailed: 'Falha ao criar',
renamed: 'Renomeado',
renameFailed: 'Falha ao renomear',
uploadSuccess: '{count} arquivo(s) enviado(s)',
uploadFailed: 'Falha ao enviar',
saveFailed: 'Falha ao salvar',
saved: 'Salvo',
unsavedChanges: 'Voce tem alteracoes nao salvas. Descartar?',
pathCopied: 'Caminho copiado',
fileTooLarge: 'Arquivo muito grande (max 10MB)',
permissionDenied: 'Nao e possivel modificar arquivo protegido',
notFound: 'Arquivo ou diretorio nao encontrado',
backendError: 'Falha na operacao de arquivo',
dragDropHint: 'Arraste arquivos aqui para enviar',
closeEditor: 'Fechar editor',
closePreview: 'Fechar',
saveFile: 'Salvar',
},
// Download
download: {
downloading: 'Baixando...',
downloadFailed: 'Falha no download',
fileNotFound: 'Arquivo nao encontrado ou excluido',
fileTooLarge: 'Arquivo muito grande (limite excedido)',
backendError: 'Falha ao ler o arquivo, o ambiente remoto pode estar indisponivel',
backendTimeout: 'Tempo esgotado para ler o arquivo',
unsupportedBackend: 'O backend de terminal atual nao suporta download de arquivos',
invalidPath: 'Caminho de arquivo invalido',
download: 'Baixar',
},
}
+1
View File
@@ -598,6 +598,7 @@ export default {
backendError: '文件操作失败',
dragDropHint: '拖拽文件到此处上传',
closeEditor: '关闭编辑器',
closePreview: '关闭',
saveFile: '保存',
},
// 下载
@@ -63,6 +63,15 @@ export function isTextFile(name: string): boolean {
return !binaryExts.has(getFileExt(name))
}
// Returns true if `targetPath` is the same as `changedPath` or lives inside it
// when `changedIsDir` is true. Used to invalidate preview/editor state when
// the underlying file is deleted or renamed.
function isAffected(targetPath: string, changedPath: string, changedIsDir: boolean): boolean {
if (targetPath === changedPath) return true
if (changedIsDir && targetPath.startsWith(changedPath + '/')) return true
return false
}
export const useFilesStore = defineStore('files', () => {
const currentPath = ref('')
const entries = ref<FileEntry[]>([])
@@ -104,6 +113,12 @@ export const useFilesStore = defineStore('files', () => {
})
async function fetchEntries(path?: string) {
if (path !== undefined && path !== currentPath.value) {
// Switching directory invalidates the current preview; close it so the
// file list becomes visible again. The editor has its own dirty-check
// (see hasUnsavedChanges), so we leave editingFile alone here.
previewFile.value = null
}
if (path !== undefined) currentPath.value = path
loading.value = true
try {
@@ -167,6 +182,12 @@ export const useFilesStore = defineStore('files', () => {
async function deleteEntry(entry: FileEntry) {
await filesApi.deleteFile(entry.path, entry.isDir)
if (previewFile.value && isAffected(previewFile.value.path, entry.path, entry.isDir)) {
previewFile.value = null
}
if (editingFile.value && isAffected(editingFile.value.path, entry.path, entry.isDir)) {
editingFile.value = null
}
await fetchEntries()
}
@@ -174,6 +195,12 @@ export const useFilesStore = defineStore('files', () => {
const parentPath = entry.path.includes('/') ? entry.path.slice(0, entry.path.lastIndexOf('/')) : ''
const newPath = parentPath ? `${parentPath}/${newName}` : newName
await filesApi.renameFile(entry.path, newPath)
if (previewFile.value && isAffected(previewFile.value.path, entry.path, entry.isDir)) {
previewFile.value = null
}
if (editingFile.value && isAffected(editingFile.value.path, entry.path, entry.isDir)) {
editingFile.value = null
}
await fetchEntries()
}