From 7f77a13b0c79c2c7c6def813b94d190f26e33c6f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=98=AD?= <81747598+lan-yonghui@users.noreply.github.com> Date: Tue, 2 Jul 2024 17:27:24 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E6=96=87=E4=BB=B6=E7=AE=A1=E7=90=86?= =?UTF-8?q?=E6=96=87=E6=9C=AC=E7=BC=96=E8=BE=91=E5=90=8E=E9=80=80=E5=87=BA?= =?UTF-8?q?=E5=89=8D=E4=BF=9D=E5=AD=98=E6=8F=90=E7=A4=BA=20(#5636)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit #### What this PR does / why we need it? Refs #5356 #### Summary of your change 检测文本是否编辑,退出/切换文件作出提示,可以重置当前修改! #### Please indicate you've done the following: - [ ] Made sure tests are passing and test coverage is added if needed. - [ ] Made sure commit message follow the rule of [Conventional Commits specification](https://www.conventionalcommits.org/). - [ ] Considered the docs impact and opened a new docs issue or PR with docs changes if needed. --- frontend/src/lang/modules/en.ts | 8 +- frontend/src/lang/modules/tw.ts | 6 + frontend/src/lang/modules/zh.ts | 6 + .../file-management/code-editor/index.vue | 106 ++++++++++++++---- 4 files changed, 101 insertions(+), 25 deletions(-) diff --git a/frontend/src/lang/modules/en.ts b/frontend/src/lang/modules/en.ts index 9935c3924..644dd6a9f 100644 --- a/frontend/src/lang/modules/en.ts +++ b/frontend/src/lang/modules/en.ts @@ -64,6 +64,8 @@ const message = { agree: 'Agree', notAgree: 'Not Agree', preview: 'Preview', + open: 'Open', + notSave: 'Not Save', }, search: { timeStart: 'Time start', @@ -143,6 +145,7 @@ const message = { recoverHelper: 'Restoring from {0} file. This operation is irreversible. Do you want to continue?', refreshSuccess: 'Refresh successful', rootInfoErr: "It's already the root directory", + resetSuccess: 'Reset successful', }, login: { username: 'UserName', @@ -1240,9 +1243,12 @@ const message = { back: 'Back', top: 'Go Back', refresh: 'Refresh', + up: 'Go back', openWithVscode: 'Open with VS Code', vscodeHelper: 'Please make sure that VS Code is installed locally and the SSH Remote plugin is configured', - up: 'Go back', + saveContentAndClose: 'The file has been modified, do you want to save and close it?', + saveAndOpenNewFile: 'The file has been modified, do you want to save and open the new file?', + noEdit: 'The file has not been modified, no need to do this!', }, ssh: { autoStart: 'Auto Start', diff --git a/frontend/src/lang/modules/tw.ts b/frontend/src/lang/modules/tw.ts index b3d359829..2a60042fc 100644 --- a/frontend/src/lang/modules/tw.ts +++ b/frontend/src/lang/modules/tw.ts @@ -63,6 +63,8 @@ const message = { agree: '同意', notAgree: '不同意', preview: '預覽', + open: '打開', + notSave: '不保存', }, search: { timeStart: '開始時間', @@ -143,6 +145,7 @@ const message = { recoverHelper: '將從 {0} 文件進行恢復,該操作不可回滾,是否繼續?', refreshSuccess: '重繪成功', rootInfoErr: '已經是根目錄了', + resetSuccess: '重置成功', }, login: { username: '用戶名', @@ -1180,6 +1183,9 @@ const message = { up: '上一層', openWithVscode: 'VS Code 打開', vscodeHelper: '請確保本地已安裝 VS Code 並配置了 SSH Remote 插件', + saveContentAndClose: '檔案已被修改,是否保存並關閉?', + saveAndOpenNewFile: '檔案已被修改,是否保存並打開新檔案?', + noEdit: '檔案未修改,無需此操作!', }, ssh: { autoStart: '開機自啟', diff --git a/frontend/src/lang/modules/zh.ts b/frontend/src/lang/modules/zh.ts index 8604a1764..9be6be6da 100644 --- a/frontend/src/lang/modules/zh.ts +++ b/frontend/src/lang/modules/zh.ts @@ -63,6 +63,8 @@ const message = { agree: '同意', notAgree: '不同意', preview: '预览', + open: '打开', + notSave: '不保存', }, search: { timeStart: '开始时间', @@ -143,6 +145,7 @@ const message = { recoverHelper: '将从 {0} 文件进行恢复,该操作不可回滚,是否继续?', refreshSuccess: '刷新成功', rootInfoErr: '已经是根目录了', + resetSuccess: '重置成功', }, login: { username: '用户名', @@ -1181,6 +1184,9 @@ const message = { up: '上一级', openWithVscode: 'VS Code 打开', vscodeHelper: '请确保本地已安装 VS Code 并配置了 SSH Remote 插件', + saveContentAndClose: '文件已被修改,是否保存并关闭?', + saveAndOpenNewFile: '文件已被修改,是否保存并打开新文件?', + noEdit: '文件未修改,无需此操作!', }, ssh: { autoStart: '开机自启', diff --git a/frontend/src/views/host/file-management/code-editor/index.vue b/frontend/src/views/host/file-management/code-editor/index.vue index 8301962ca..d2c94b780 100644 --- a/frontend/src/views/host/file-management/code-editor/index.vue +++ b/frontend/src/views/host/file-management/code-editor/index.vue @@ -131,8 +131,8 @@ @@ -151,7 +151,7 @@ import htmlWorker from 'monaco-editor/esm/vs/language/html/html.worker?worker'; import tsWorker from 'monaco-editor/esm/vs/language/typescript/ts.worker?worker'; import EditorWorker from 'monaco-editor/esm/vs/editor/editor.worker?worker'; -import { ElTreeV2 } from 'element-plus'; +import { ElMessageBox, ElTreeV2 } from 'element-plus'; import { ResultData } from '@/api/interface'; import { File } from '@/api/interface/file'; import { getIcon } from '@/utils/util'; @@ -221,6 +221,8 @@ const treeHeight = ref(0); const codeHeight = ref('55vh'); const codeReq = reactive({ path: '', expand: false, page: 1, pageSize: 100 }); const isShow = ref(true); +const isEdit = ref(false); +const oldFileContent = ref(''); const toggleShow = () => { isShow.value = !isShow.value; @@ -271,11 +273,43 @@ let form = ref({ const em = defineEmits(['close']); const handleClose = () => { - open.value = false; - if (editor) { - editor.dispose(); + const closeEditor = () => { + open.value = false; + if (editor) { + editor.dispose(); + } + em('close', open.value); + }; + + if (isEdit.value) { + ElMessageBox.confirm(i18n.global.t('file.saveContentAndClose'), { + confirmButtonText: i18n.global.t('commons.button.save'), + cancelButtonText: i18n.global.t('commons.button.notSave'), + type: 'info', + distinguishCancelAndClose: true, + }) + .then(() => { + saveContent(); + }) + .finally(() => { + closeEditor(); + }); + } else { + closeEditor(); + } +}; + +const handleReset = () => { + if (isEdit.value) { + loading.value = true; + form.value.content = oldFileContent.value; + editor.setValue(oldFileContent.value); + isEdit.value = false; + MsgSuccess(i18n.global.t('commons.msg.resetSuccess')); + loading.value = false; + } else { + MsgInfo(i18n.global.t('file.noEdit')); } - em('close', open.value); }; const loadTooltip = () => { @@ -347,6 +381,7 @@ const initEditor = () => { editor.onDidChangeModelContent(() => { if (editor) { form.value.content = editor.getValue(); + isEdit.value = true; } }); @@ -358,27 +393,30 @@ const initEditor = () => { }; const quickSave = () => { - saveContent(false); + saveContent(); }; -const saveContent = (closePage: boolean) => { - loading.value = true; - SaveFileContent(form.value) - .then(() => { - loading.value = false; - open.value = !closePage; - MsgSuccess(i18n.global.t('commons.msg.updateSuccess')); - if (closePage) { - handleClose(); - } - }) - .catch(() => { - loading.value = false; - }); +const saveContent = () => { + if (isEdit.value) { + loading.value = true; + SaveFileContent(form.value) + .then(() => { + loading.value = false; + isEdit.value = false; + oldFileContent.value = form.value.content; + MsgSuccess(i18n.global.t('commons.msg.updateSuccess')); + }) + .catch(() => { + loading.value = false; + }); + } else { + MsgInfo(i18n.global.t('file.noEdit')); + } }; const acceptParams = (props: EditProps) => { form.value.content = props.content; + oldFileContent.value = props.content; form.value.path = props.path; directoryPath.value = getDirectoryPath(props.path); fileExtension.value = props.extension; @@ -447,11 +485,15 @@ const getRefresh = (path: string) => { }; const getContent = (path: string, extension: string) => { - if (form.value.path !== path) { + if (form.value.path === path) { + return; + } + + const fetchFileContent = () => { codeReq.path = path; codeReq.expand = true; - if (extension != '') { + if (extension !== '') { Languages.forEach((language) => { const ext = extension.substring(1); if (language.value.indexOf(ext) > -1) { @@ -463,12 +505,28 @@ const getContent = (path: string, extension: string) => { GetFileContent(codeReq) .then((res) => { form.value.content = res.data.content; + oldFileContent.value = res.data.content; form.value.path = res.data.path; fileExtension.value = res.data.extension; fileName.value = res.data.name; initEditor(); }) .catch(() => {}); + }; + + if (isEdit.value) { + ElMessageBox.confirm(i18n.global.t('file.saveAndOpenNewFile'), { + confirmButtonText: i18n.global.t('commons.button.open'), + cancelButtonText: i18n.global.t('commons.button.cancel'), + type: 'info', + }) + .then(() => { + saveContent(); + fetchFileContent(); + }) + .finally(() => {}); + } else { + fetchFileContent(); } };