mirror of
https://github.com/1Panel-dev/1Panel.git
synced 2025-02-08 01:20:07 +08:00
feat: 文件管理文本编辑后退出前保存提示 (#5636)
#### 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.
This commit is contained in:
parent
f131aae344
commit
7f77a13b0c
@ -64,6 +64,8 @@ const message = {
|
|||||||
agree: 'Agree',
|
agree: 'Agree',
|
||||||
notAgree: 'Not Agree',
|
notAgree: 'Not Agree',
|
||||||
preview: 'Preview',
|
preview: 'Preview',
|
||||||
|
open: 'Open',
|
||||||
|
notSave: 'Not Save',
|
||||||
},
|
},
|
||||||
search: {
|
search: {
|
||||||
timeStart: 'Time start',
|
timeStart: 'Time start',
|
||||||
@ -143,6 +145,7 @@ const message = {
|
|||||||
recoverHelper: 'Restoring from {0} file. This operation is irreversible. Do you want to continue?',
|
recoverHelper: 'Restoring from {0} file. This operation is irreversible. Do you want to continue?',
|
||||||
refreshSuccess: 'Refresh successful',
|
refreshSuccess: 'Refresh successful',
|
||||||
rootInfoErr: "It's already the root directory",
|
rootInfoErr: "It's already the root directory",
|
||||||
|
resetSuccess: 'Reset successful',
|
||||||
},
|
},
|
||||||
login: {
|
login: {
|
||||||
username: 'UserName',
|
username: 'UserName',
|
||||||
@ -1240,9 +1243,12 @@ const message = {
|
|||||||
back: 'Back',
|
back: 'Back',
|
||||||
top: 'Go Back',
|
top: 'Go Back',
|
||||||
refresh: 'Refresh',
|
refresh: 'Refresh',
|
||||||
|
up: 'Go back',
|
||||||
openWithVscode: 'Open with VS Code',
|
openWithVscode: 'Open with VS Code',
|
||||||
vscodeHelper: 'Please make sure that VS Code is installed locally and the SSH Remote plugin is configured',
|
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: {
|
ssh: {
|
||||||
autoStart: 'Auto Start',
|
autoStart: 'Auto Start',
|
||||||
|
@ -63,6 +63,8 @@ const message = {
|
|||||||
agree: '同意',
|
agree: '同意',
|
||||||
notAgree: '不同意',
|
notAgree: '不同意',
|
||||||
preview: '預覽',
|
preview: '預覽',
|
||||||
|
open: '打開',
|
||||||
|
notSave: '不保存',
|
||||||
},
|
},
|
||||||
search: {
|
search: {
|
||||||
timeStart: '開始時間',
|
timeStart: '開始時間',
|
||||||
@ -143,6 +145,7 @@ const message = {
|
|||||||
recoverHelper: '將從 {0} 文件進行恢復,該操作不可回滾,是否繼續?',
|
recoverHelper: '將從 {0} 文件進行恢復,該操作不可回滾,是否繼續?',
|
||||||
refreshSuccess: '重繪成功',
|
refreshSuccess: '重繪成功',
|
||||||
rootInfoErr: '已經是根目錄了',
|
rootInfoErr: '已經是根目錄了',
|
||||||
|
resetSuccess: '重置成功',
|
||||||
},
|
},
|
||||||
login: {
|
login: {
|
||||||
username: '用戶名',
|
username: '用戶名',
|
||||||
@ -1180,6 +1183,9 @@ const message = {
|
|||||||
up: '上一層',
|
up: '上一層',
|
||||||
openWithVscode: 'VS Code 打開',
|
openWithVscode: 'VS Code 打開',
|
||||||
vscodeHelper: '請確保本地已安裝 VS Code 並配置了 SSH Remote 插件',
|
vscodeHelper: '請確保本地已安裝 VS Code 並配置了 SSH Remote 插件',
|
||||||
|
saveContentAndClose: '檔案已被修改,是否保存並關閉?',
|
||||||
|
saveAndOpenNewFile: '檔案已被修改,是否保存並打開新檔案?',
|
||||||
|
noEdit: '檔案未修改,無需此操作!',
|
||||||
},
|
},
|
||||||
ssh: {
|
ssh: {
|
||||||
autoStart: '開機自啟',
|
autoStart: '開機自啟',
|
||||||
|
@ -63,6 +63,8 @@ const message = {
|
|||||||
agree: '同意',
|
agree: '同意',
|
||||||
notAgree: '不同意',
|
notAgree: '不同意',
|
||||||
preview: '预览',
|
preview: '预览',
|
||||||
|
open: '打开',
|
||||||
|
notSave: '不保存',
|
||||||
},
|
},
|
||||||
search: {
|
search: {
|
||||||
timeStart: '开始时间',
|
timeStart: '开始时间',
|
||||||
@ -143,6 +145,7 @@ const message = {
|
|||||||
recoverHelper: '将从 {0} 文件进行恢复,该操作不可回滚,是否继续?',
|
recoverHelper: '将从 {0} 文件进行恢复,该操作不可回滚,是否继续?',
|
||||||
refreshSuccess: '刷新成功',
|
refreshSuccess: '刷新成功',
|
||||||
rootInfoErr: '已经是根目录了',
|
rootInfoErr: '已经是根目录了',
|
||||||
|
resetSuccess: '重置成功',
|
||||||
},
|
},
|
||||||
login: {
|
login: {
|
||||||
username: '用户名',
|
username: '用户名',
|
||||||
@ -1181,6 +1184,9 @@ const message = {
|
|||||||
up: '上一级',
|
up: '上一级',
|
||||||
openWithVscode: 'VS Code 打开',
|
openWithVscode: 'VS Code 打开',
|
||||||
vscodeHelper: '请确保本地已安装 VS Code 并配置了 SSH Remote 插件',
|
vscodeHelper: '请确保本地已安装 VS Code 并配置了 SSH Remote 插件',
|
||||||
|
saveContentAndClose: '文件已被修改,是否保存并关闭?',
|
||||||
|
saveAndOpenNewFile: '文件已被修改,是否保存并打开新文件?',
|
||||||
|
noEdit: '文件未修改,无需此操作!',
|
||||||
},
|
},
|
||||||
ssh: {
|
ssh: {
|
||||||
autoStart: '开机自启',
|
autoStart: '开机自启',
|
||||||
|
@ -131,8 +131,8 @@
|
|||||||
</div>
|
</div>
|
||||||
<template #footer>
|
<template #footer>
|
||||||
<span class="dialog-footer">
|
<span class="dialog-footer">
|
||||||
<el-button @click="handleClose">{{ $t('commons.button.cancel') }}</el-button>
|
<el-button @click="handleReset">{{ $t('commons.button.reset') }}</el-button>
|
||||||
<el-button type="primary" @click="saveContent(true)">{{ $t('commons.button.confirm') }}</el-button>
|
<el-button type="primary" @click="saveContent()">{{ $t('commons.button.confirm') }}</el-button>
|
||||||
</span>
|
</span>
|
||||||
</template>
|
</template>
|
||||||
</el-dialog>
|
</el-dialog>
|
||||||
@ -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 tsWorker from 'monaco-editor/esm/vs/language/typescript/ts.worker?worker';
|
||||||
import EditorWorker from 'monaco-editor/esm/vs/editor/editor.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 { ResultData } from '@/api/interface';
|
||||||
import { File } from '@/api/interface/file';
|
import { File } from '@/api/interface/file';
|
||||||
import { getIcon } from '@/utils/util';
|
import { getIcon } from '@/utils/util';
|
||||||
@ -221,6 +221,8 @@ const treeHeight = ref(0);
|
|||||||
const codeHeight = ref('55vh');
|
const codeHeight = ref('55vh');
|
||||||
const codeReq = reactive({ path: '', expand: false, page: 1, pageSize: 100 });
|
const codeReq = reactive({ path: '', expand: false, page: 1, pageSize: 100 });
|
||||||
const isShow = ref(true);
|
const isShow = ref(true);
|
||||||
|
const isEdit = ref(false);
|
||||||
|
const oldFileContent = ref('');
|
||||||
|
|
||||||
const toggleShow = () => {
|
const toggleShow = () => {
|
||||||
isShow.value = !isShow.value;
|
isShow.value = !isShow.value;
|
||||||
@ -271,6 +273,7 @@ let form = ref({
|
|||||||
const em = defineEmits(['close']);
|
const em = defineEmits(['close']);
|
||||||
|
|
||||||
const handleClose = () => {
|
const handleClose = () => {
|
||||||
|
const closeEditor = () => {
|
||||||
open.value = false;
|
open.value = false;
|
||||||
if (editor) {
|
if (editor) {
|
||||||
editor.dispose();
|
editor.dispose();
|
||||||
@ -278,6 +281,37 @@ const handleClose = () => {
|
|||||||
em('close', open.value);
|
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'));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
const loadTooltip = () => {
|
const loadTooltip = () => {
|
||||||
return i18n.global.t('commons.button.' + (isFullscreen.value ? 'quitFullscreen' : 'fullscreen'));
|
return i18n.global.t('commons.button.' + (isFullscreen.value ? 'quitFullscreen' : 'fullscreen'));
|
||||||
};
|
};
|
||||||
@ -347,6 +381,7 @@ const initEditor = () => {
|
|||||||
editor.onDidChangeModelContent(() => {
|
editor.onDidChangeModelContent(() => {
|
||||||
if (editor) {
|
if (editor) {
|
||||||
form.value.content = editor.getValue();
|
form.value.content = editor.getValue();
|
||||||
|
isEdit.value = true;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -358,27 +393,30 @@ const initEditor = () => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const quickSave = () => {
|
const quickSave = () => {
|
||||||
saveContent(false);
|
saveContent();
|
||||||
};
|
};
|
||||||
|
|
||||||
const saveContent = (closePage: boolean) => {
|
const saveContent = () => {
|
||||||
|
if (isEdit.value) {
|
||||||
loading.value = true;
|
loading.value = true;
|
||||||
SaveFileContent(form.value)
|
SaveFileContent(form.value)
|
||||||
.then(() => {
|
.then(() => {
|
||||||
loading.value = false;
|
loading.value = false;
|
||||||
open.value = !closePage;
|
isEdit.value = false;
|
||||||
|
oldFileContent.value = form.value.content;
|
||||||
MsgSuccess(i18n.global.t('commons.msg.updateSuccess'));
|
MsgSuccess(i18n.global.t('commons.msg.updateSuccess'));
|
||||||
if (closePage) {
|
|
||||||
handleClose();
|
|
||||||
}
|
|
||||||
})
|
})
|
||||||
.catch(() => {
|
.catch(() => {
|
||||||
loading.value = false;
|
loading.value = false;
|
||||||
});
|
});
|
||||||
|
} else {
|
||||||
|
MsgInfo(i18n.global.t('file.noEdit'));
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const acceptParams = (props: EditProps) => {
|
const acceptParams = (props: EditProps) => {
|
||||||
form.value.content = props.content;
|
form.value.content = props.content;
|
||||||
|
oldFileContent.value = props.content;
|
||||||
form.value.path = props.path;
|
form.value.path = props.path;
|
||||||
directoryPath.value = getDirectoryPath(props.path);
|
directoryPath.value = getDirectoryPath(props.path);
|
||||||
fileExtension.value = props.extension;
|
fileExtension.value = props.extension;
|
||||||
@ -447,11 +485,15 @@ const getRefresh = (path: string) => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const getContent = (path: string, extension: string) => {
|
const getContent = (path: string, extension: string) => {
|
||||||
if (form.value.path !== path) {
|
if (form.value.path === path) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const fetchFileContent = () => {
|
||||||
codeReq.path = path;
|
codeReq.path = path;
|
||||||
codeReq.expand = true;
|
codeReq.expand = true;
|
||||||
|
|
||||||
if (extension != '') {
|
if (extension !== '') {
|
||||||
Languages.forEach((language) => {
|
Languages.forEach((language) => {
|
||||||
const ext = extension.substring(1);
|
const ext = extension.substring(1);
|
||||||
if (language.value.indexOf(ext) > -1) {
|
if (language.value.indexOf(ext) > -1) {
|
||||||
@ -463,12 +505,28 @@ const getContent = (path: string, extension: string) => {
|
|||||||
GetFileContent(codeReq)
|
GetFileContent(codeReq)
|
||||||
.then((res) => {
|
.then((res) => {
|
||||||
form.value.content = res.data.content;
|
form.value.content = res.data.content;
|
||||||
|
oldFileContent.value = res.data.content;
|
||||||
form.value.path = res.data.path;
|
form.value.path = res.data.path;
|
||||||
fileExtension.value = res.data.extension;
|
fileExtension.value = res.data.extension;
|
||||||
fileName.value = res.data.name;
|
fileName.value = res.data.name;
|
||||||
initEditor();
|
initEditor();
|
||||||
})
|
})
|
||||||
.catch(() => {});
|
.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();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user