diff --git a/frontend/src/components/complex-table/index.vue b/frontend/src/components/complex-table/index.vue index 32c26a5f4..3c56993d6 100644 --- a/frontend/src/components/complex-table/index.vue +++ b/frontend/src/components/complex-table/index.vue @@ -112,7 +112,7 @@ const rightClick = ref({ currentRow: null, }); const handleRightClick = (row, column, event) => { - tableRef.value.refElTable.clearSelection(); + clearSelects(); tableRef.value.refElTable.toggleRowSelection(row); if (!props.rightButtons) { return; @@ -128,7 +128,7 @@ const handleRightClick = (row, column, event) => { }; const closeRightClick = () => { rightClick.value.visible = false; - tableRef.value.refElTable.clearSelection(); + clearSelects(); document.removeEventListener('click', closeRightClick); }; const disabled = computed(() => { diff --git a/frontend/src/lang/modules/en.ts b/frontend/src/lang/modules/en.ts index e562042e5..a12b840e8 100644 --- a/frontend/src/lang/modules/en.ts +++ b/frontend/src/lang/modules/en.ts @@ -1509,6 +1509,7 @@ const message = { noShowHide: 'Don’t show hidden files', cancelUpload: 'Cancel Upload', cancelUploadHelper: 'Whether to cancel the upload, after cancellation the upload list will be cleared.', + keepOneTab: 'Keep at least one tab', }, ssh: { autoStart: 'Auto start', @@ -3660,7 +3661,7 @@ const message = { taskName: 'Task Name', cronJobType: 'Task Type', clamPath: 'Scan Directory', - cronjob: 'Cronjob', + cronjob: 'Cronjob execution {0} failed', app: 'Backup App', web: 'Backup Website', database: 'Backup Database', diff --git a/frontend/src/lang/modules/ja.ts b/frontend/src/lang/modules/ja.ts index 117fcabf2..ba5a57e9a 100644 --- a/frontend/src/lang/modules/ja.ts +++ b/frontend/src/lang/modules/ja.ts @@ -1453,6 +1453,7 @@ const message = { noShowHide: '隠しファイルを表示しない', cancelUpload: 'アップロードをキャンセル', cancelUploadHelper: 'アップロードをキャンセルするかどうか、キャンセル後、アップロードリストはクリアされます。', + keepOneTab: '少なくとも1つのタブを保持してください', }, ssh: { autoStart: 'オートスタート', @@ -3538,7 +3539,7 @@ const message = { taskName: 'タスク名', cronJobType: 'タスクタイプ', clamPath: 'スキャンディレクトリ', - cronjob: 'Cronジョブ', + cronjob: 'スケジュールタスクの実行{0}で異常が発生しました', app: 'アプリバックアップ', web: 'ウェブサイトバックアップ', database: 'データベースバックアップ', diff --git a/frontend/src/lang/modules/ko.ts b/frontend/src/lang/modules/ko.ts index f142f3ba9..34b1de9b7 100644 --- a/frontend/src/lang/modules/ko.ts +++ b/frontend/src/lang/modules/ko.ts @@ -1438,6 +1438,7 @@ const message = { noShowHide: '숨김 파일 숨기기', cancelUpload: '업로드 취소', cancelUploadHelper: '업로드를 취소할지 여부, 취소 후 업로드 목록이 비워집니다.', + keepOneTab: '최소한 하나의 탭을 유지하세요', }, ssh: { autoStart: '자동 시작', @@ -3476,7 +3477,7 @@ const message = { taskName: '작업 이름', cronJobType: '작업 유형', clamPath: '검사 디렉토리', - cronjob: '크론 작업', + cronjob: '예약 작업 실행 {0} 중 오류가 발생했습니다', app: '백업 애플리케이션', web: '백업 웹사이트', database: '백업 데이터베이스', diff --git a/frontend/src/lang/modules/ms.ts b/frontend/src/lang/modules/ms.ts index 3f013f126..bb07bbeb8 100644 --- a/frontend/src/lang/modules/ms.ts +++ b/frontend/src/lang/modules/ms.ts @@ -1496,6 +1496,7 @@ const message = { cancelUpload: 'Batalkan Muat Naik', cancelUploadHelper: 'Adakah hendak membatalkan muat naik, selepas pembatalan senarai muat naik akan dikosongkan.', + keepOneTab: 'Pastikan sekurang-kurangnya satu tab dikekalkan', }, ssh: { autoStart: 'Mula automatik', @@ -3624,7 +3625,7 @@ const message = { taskName: 'Nama Tugas', cronJobType: 'Jenis Tugas', clamPath: 'Direktori Imbasan', - cronjob: 'Cronjob', + cronjob: 'Pelaksanaan tugas berjadual {0} gagal', app: 'Sandaran Aplikasi', web: 'Sandaran Laman Web', database: 'Sandaran Pangkalan Data', diff --git a/frontend/src/lang/modules/pt-br.ts b/frontend/src/lang/modules/pt-br.ts index e949d340e..a0f8974ba 100644 --- a/frontend/src/lang/modules/pt-br.ts +++ b/frontend/src/lang/modules/pt-br.ts @@ -1483,6 +1483,7 @@ const message = { noShowHide: 'Não mostrar arquivos ocultos', cancelUpload: 'Cancelar Upload', cancelUploadHelper: 'Deseja cancelar o upload, após o cancelamento, a lista de upload será limpa.', + keepOneTab: 'Mantenha pelo menos uma aba', }, ssh: { autoStart: 'Início automático', @@ -3632,7 +3633,7 @@ const message = { taskName: 'Nome da Tarefa', cronJobType: 'Tipo de Tarefa', clamPath: 'Diretório de Varredura', - cronjob: 'Tarefa Cron', + cronjob: 'Tarefa Cron agendada {0} falhou', app: 'Backup do Aplicativo', web: 'Backup do Site', database: 'Backup do Banco de Dados', diff --git a/frontend/src/lang/modules/ru.ts b/frontend/src/lang/modules/ru.ts index 9eb891854..699299a43 100644 --- a/frontend/src/lang/modules/ru.ts +++ b/frontend/src/lang/modules/ru.ts @@ -1484,6 +1484,7 @@ const message = { noShowHide: 'Не показывать скрытые файлы', cancelUpload: 'Отменить загрузку', cancelUploadHelper: 'Отменить загрузку или нет, после отмены список загрузок будет очищен.', + keepOneTab: 'Необходимо оставить как минимум одну вкладку', }, ssh: { autoStart: 'Автозапуск', @@ -3618,7 +3619,7 @@ const message = { taskName: 'Имя задачи', cronJobType: 'Тип задачи', clamPath: 'Директория проверки', - cronjob: 'Задача Cron', + cronjob: 'Ошибка при выполнении Задача cron {0}', app: 'Резервное копирование приложения', web: 'Резервное копирование сайта', database: 'Резервное копирование базы данных', diff --git a/frontend/src/lang/modules/tr.ts b/frontend/src/lang/modules/tr.ts index 2fb0159ab..5dff21d2e 100644 --- a/frontend/src/lang/modules/tr.ts +++ b/frontend/src/lang/modules/tr.ts @@ -1526,6 +1526,7 @@ const message = { noShowHide: 'Gizli dosyaları gösterme', cancelUpload: 'Yüklemeyi İptal Et', cancelUploadHelper: 'Yüklemeyi iptal etmek ister misiniz, iptal sonrası yükleme listesi temizlenecektir.', + keepOneTab: 'En az bir sekme açık kalmalıdır', }, ssh: { autoStart: 'Otomatik başlat', @@ -3693,7 +3694,7 @@ const message = { success: 'Uyarı Başarılı', pushing: 'Gönderiliyor...', error: 'Uyarı Başarısız', - cleanLog: 'Günlükleri Temizle', + cleanLog: 'Zamanlanmış görev yürütmesi {0} hatası', cleanAlertLogs: 'Uyarı Günlüklerini Temizle', daily: 'Günlük Uyarı Sayısı: {0}', cumulative: 'Toplam Uyarı Sayısı: {0}', diff --git a/frontend/src/lang/modules/zh-Hant.ts b/frontend/src/lang/modules/zh-Hant.ts index 8e5be2107..9a20a4dc3 100644 --- a/frontend/src/lang/modules/zh-Hant.ts +++ b/frontend/src/lang/modules/zh-Hant.ts @@ -1438,6 +1438,7 @@ const message = { noShowHide: '不顯示隱藏檔案', cancelUpload: '取消上傳', cancelUploadHelper: '是否取消上傳,取消後將清空上傳列表', + keepOneTab: '至少保留一個標籤頁', }, ssh: { autoStart: '開機自啟', @@ -3405,7 +3406,7 @@ const message = { taskName: '任務名稱', cronJobType: '任務類型', clamPath: '掃描目錄', - cronjob: '計劃任務', + cronjob: '計劃任務執行{0}異常', app: '備份應用', web: '備份網站', database: '備份資料庫', diff --git a/frontend/src/lang/modules/zh.ts b/frontend/src/lang/modules/zh.ts index 6aa149d83..c76044e9d 100644 --- a/frontend/src/lang/modules/zh.ts +++ b/frontend/src/lang/modules/zh.ts @@ -1433,6 +1433,7 @@ const message = { noShowHide: '不显示隐藏文件', cancelUpload: '取消上传', cancelUploadHelper: '是否取消上传,取消后将清空上传列表', + keepOneTab: '至少保留一个标签页', }, ssh: { autoStart: '开机自启', diff --git a/frontend/src/views/host/file-management/index.vue b/frontend/src/views/host/file-management/index.vue index d898cd2b2..0b73efb7d 100644 --- a/frontend/src/views/host/file-management/index.vue +++ b/frontend/src/views/host/file-management/index.vue @@ -471,7 +471,8 @@ :autofocus="isEdit" class="table-link table-input" placeholder="file name" - @blur="handleRename(row)" + @keydown.enter="handleRename(row)" + @blur="onRenameBlur($event, row)" /> {{ row.name }} @@ -584,7 +585,7 @@ - + @@ -906,8 +907,8 @@ const updateButtons = async () => { const handlePath = () => { nextTick(function () { - let breadCrumbWidth = breadCrumbRef.value.offsetWidth; - let pathWidth = toolRef.value.offsetWidth; + let breadCrumbWidth = breadCrumbRef.value?.offsetWidth; + let pathWidth = toolRef.value?.offsetWidth; if (pathWidth - breadCrumbWidth < 50 && paths.value.length > 1) { const removed = paths.value.shift(); if (removed) hidePaths.value.push(removed); @@ -1281,6 +1282,20 @@ const openRename = (item: File.File) => { hideRightMenu(); }; +const onRenameBlur = (e: FocusEvent, row: File.File) => { + const related = e.relatedTarget as HTMLElement | null; + if ( + related && + (related.closest('.fu-table-more-button') || related.closest('.fu-table-more-button .el-dropdown__item')) + ) { + setTimeout(() => { + getCurrentRename()?.focus(); + }, 0); + return; + } + handleRename(row); +}; + const handleRename = async (row: File.File): Promise => { if (fileRename.newName === fileRename.oldName) { isEdit.value = false; @@ -1584,7 +1599,7 @@ onMounted(() => { req.path = globalStore.lastFilePath; getPaths(req.path); } - pathWidth.value = getCurrentPath().offsetWidth; + pathWidth.value = getCurrentPath()?.offsetWidth; paths.value = []; const segments = editableTabsValue.value.split('/').filter(Boolean); @@ -1670,6 +1685,9 @@ function updateTab(newPath?: string) { const addTab = () => { let tabIndex = editableTabs.value.length; + if (tabIndex >= 6) { + return; + } const newTabId = `${++tabIndex}`; editableTabs.value.push({ id: newTabId, @@ -1695,6 +1713,11 @@ const changeTab = (targetPath: TabPaneName) => { }; const removeTab = (targetPath: TabPaneName) => { + let tabIndex = editableTabs.value.length; + if (tabIndex === 1) { + MsgWarning(i18n.global.t('file.keepOneTab')); + return; + } editableTabsKey.value = targetPath.toString(); const tabs = editableTabs.value; let activeKey = editableTabsKey.value;