mirror of
https://github.com/cloudreve/frontend.git
synced 2025-12-25 19:52:48 +00:00
feat(viewer): add unsaved change confirm dialog
This commit is contained in:
parent
0b388cc50a
commit
236ed936c7
|
|
@ -459,6 +459,7 @@
|
|||
"conflictDes2": "<0>Die Datei wurde nach dem Öffnen von anderer Stelle mit einer neuen Version aktualisiert.</0><1>Wenn Sie unter einem neuen Dateinamen oder an einem neuen Ort gespeichert haben, existiert möglicherweise bereits eine Datei mit demselben Namen.</1>",
|
||||
"saveAs": "Speichern unter",
|
||||
"versionConflict": "Versionskonflikt",
|
||||
"discardUnsavedConfirm": "Sie haben ungespeicherte Änderungen. Möchten Sie sie verwerfen?",
|
||||
"overwrite": "Überschreiben",
|
||||
"editShareLink": "Freigabe-Link bearbeiten",
|
||||
"clearPermissions": "Berechtigungseinstellungen löschen",
|
||||
|
|
|
|||
|
|
@ -424,6 +424,7 @@
|
|||
"conflictDes2": "<0>The file was updated to a new version from elsewhere after you opened it.</0><1>If you saved it with a new name or a new location, the file name already exists.</1>",
|
||||
"saveAs": "Save as",
|
||||
"versionConflict": "Version conflict",
|
||||
"discardUnsavedConfirm": "You have unsaved changes. Still discard?",
|
||||
"overwrite": "Overwrite",
|
||||
"editShareLink": "Edit share link",
|
||||
"clearPermissions": "Clear permission settings",
|
||||
|
|
|
|||
|
|
@ -459,6 +459,7 @@
|
|||
"conflictDes2": "<0>El archivo fue actualizado a una nueva versión desde otro lugar después de que lo abrieras.</0><1>Si lo guardaste con un nuevo nombre o nueva ubicación, el nombre de archivo ya existe.</1>",
|
||||
"saveAs": "Guardar como",
|
||||
"versionConflict": "Conflicto de versión",
|
||||
"discardUnsavedConfirm": "Tienes cambios sin guardar. ¿Deseas descartarlos?",
|
||||
"overwrite": "Sobrescribir",
|
||||
"editShareLink": "Editar enlace compartido",
|
||||
"clearPermissions": "Limpiar configuración de permisos",
|
||||
|
|
|
|||
|
|
@ -459,6 +459,7 @@
|
|||
"conflictDes2": "<0>Le fichier a été mis à jour vers une nouvelle version depuis ailleurs après que vous l'ayez ouvert.</0><1>Si vous l'avez enregistré avec un nouveau nom ou un nouvel emplacement, le nom de fichier existe déjà.</1>",
|
||||
"saveAs": "Enregistrer sous",
|
||||
"versionConflict": "Conflit de version",
|
||||
"discardUnsavedConfirm": "Vous avez des modifications non enregistrées. Les abandonner ?",
|
||||
"overwrite": "Écraser",
|
||||
"editShareLink": "Modifier le lien de partage",
|
||||
"clearPermissions": "Effacer les paramètres d'autorisation",
|
||||
|
|
|
|||
|
|
@ -459,6 +459,7 @@
|
|||
"conflictDes2": "<0>Il file è stato aggiornato a una nuova versione da altrove dopo che l'hai aperto.</0><1>Se l'hai salvato con un nuovo nome o in una nuova posizione, il nome del file esiste già.</1>",
|
||||
"saveAs": "Salva come",
|
||||
"versionConflict": "Conflitto di versione",
|
||||
"discardUnsavedConfirm": "Hai modifiche non salvate. Vuoi scartarle?",
|
||||
"overwrite": "Sovrascrivi",
|
||||
"editShareLink": "Modifica link di condivisione",
|
||||
"clearPermissions": "Pulisci impostazioni permessi",
|
||||
|
|
|
|||
|
|
@ -424,6 +424,7 @@
|
|||
"conflictDes2": "<0>ファイルを開いた後、別の場所から新しいバージョンで更新されました。</0><1>新しいファイル名または新しい場所に保存した場合、同名のファイルが既に存在する可能性があります。</1>",
|
||||
"saveAs": "名前を付けて保存",
|
||||
"versionConflict": "バージョン競合",
|
||||
"discardUnsavedConfirm": "保存されていない変更があります。破棄しますか?",
|
||||
"overwrite": "上書き",
|
||||
"editShareLink": "共有リンクの編集",
|
||||
"clearPermissions": "権限設定のクリア",
|
||||
|
|
|
|||
|
|
@ -459,6 +459,7 @@
|
|||
"conflictDes2": "<0>파일을 연 후 다른 곳에서 새 버전으로 업데이트되었습니다.</0><1>새 파일명이나 새 위치로 저장한 경우 동일한 이름의 파일이 이미 존재할 수 있습니다.</1>",
|
||||
"saveAs": "다른 이름으로 저장",
|
||||
"versionConflict": "버전 충돌",
|
||||
"discardUnsavedConfirm": "저장되지 않은 변경 사항이 있습니다. 삭제하시겠습니까?",
|
||||
"overwrite": "덮어쓰기",
|
||||
"editShareLink": "공유 링크 편집",
|
||||
"clearPermissions": "권한 설정 지우기",
|
||||
|
|
|
|||
|
|
@ -459,6 +459,7 @@
|
|||
"conflictDes2": "<0>O arquivo foi atualizado para uma nova versão de outro lugar depois que você o abriu.</0><1>Se você o salvou com um novo nome ou novo local, o nome do arquivo já existe.</1>",
|
||||
"saveAs": "Salvar como",
|
||||
"versionConflict": "Conflito de versão",
|
||||
"discardUnsavedConfirm": "Você tem alterações não salvas. Descartá-las?",
|
||||
"overwrite": "Sobrescrever",
|
||||
"editShareLink": "Editar link de compartilhamento",
|
||||
"clearPermissions": "Limpar configurações de permissão",
|
||||
|
|
|
|||
|
|
@ -459,6 +459,7 @@
|
|||
"conflictDes2": "<0>Файл был обновлён до новой версии из другого места после того, как вы его открыли.</0><1>Если вы сохранили его с новым именем или в новом месте, возможно, файл с таким именем уже существует.</1>",
|
||||
"saveAs": "Сохранить как",
|
||||
"versionConflict": "Конфликт версий",
|
||||
"discardUnsavedConfirm": "У вас есть несохранённые изменения. Отменить их?",
|
||||
"overwrite": "Перезаписать",
|
||||
"editShareLink": "Редактировать ссылку на публикацию",
|
||||
"clearPermissions": "Очистить настройки разрешений",
|
||||
|
|
|
|||
|
|
@ -424,6 +424,7 @@
|
|||
"conflictDes2": "<0>该文件在你打开后被从它处更新了新版本。</0><1>如果你另存为了新文件名或新位置,可能已有同名文件存在。</1>",
|
||||
"saveAs": "另存为",
|
||||
"versionConflict": "版本冲突",
|
||||
"discardUnsavedConfirm": "有未保存的更改,确定要关闭吗?",
|
||||
"overwrite": "覆盖",
|
||||
"editShareLink": "编辑分享链接",
|
||||
"clearPermissions": "清除权限设置",
|
||||
|
|
|
|||
|
|
@ -424,6 +424,7 @@
|
|||
"conflictDes2": "<0>該檔案在你開啟後被從它處更新了新版本。</0><1>如果你另存為了新檔名或新位置,可能已有同名檔案存在。</1>",
|
||||
"saveAs": "另存為",
|
||||
"versionConflict": "版本衝突",
|
||||
"discardUnsavedConfirm": "有未儲存的變更,確定要關閉嗎?",
|
||||
"overwrite": "覆蓋",
|
||||
"editShareLink": "編輯分享連結",
|
||||
"clearPermissions": "清除許可權設定",
|
||||
|
|
|
|||
|
|
@ -15,6 +15,7 @@ import CaretDown from "../../Icons/CaretDown.tsx";
|
|||
import Checkmark from "../../Icons/Checkmark.tsx";
|
||||
import Setting from "../../Icons/Setting.tsx";
|
||||
import ViewerDialog, { ViewerLoading } from "../ViewerDialog.tsx";
|
||||
import { confirmOperation } from "../../../redux/thunks/dialog.ts";
|
||||
|
||||
const MonacoEditor = lazy(() => import("./MonacoEditor.tsx"));
|
||||
|
||||
|
|
@ -109,6 +110,31 @@ const CodeViewer = () => {
|
|||
const [wordWrap, setWordWrap] = useState<"off" | "on" | "wordWrapColumn" | "bounded">("off");
|
||||
const saveFunction = useRef<() => void>(() => {});
|
||||
|
||||
const closeViewer = useCallback(() => {
|
||||
dispatch(closeCodeViewer());
|
||||
}, [dispatch]);
|
||||
|
||||
const handleDialogClose = useCallback(
|
||||
(_: React.SyntheticEvent | object, reason?: "backdropClick" | "escapeKeyDown") => {
|
||||
if (!saved && supportUpdate && (reason === "backdropClick" || reason === "escapeKeyDown")) {
|
||||
dispatch(
|
||||
confirmOperation(
|
||||
t("application:modals.discardUnsavedConfirm"),
|
||||
),
|
||||
)
|
||||
.then(() => {
|
||||
closeViewer();
|
||||
})
|
||||
.catch(() => {});
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
closeViewer();
|
||||
},
|
||||
[closeViewer, saved, supportUpdate, t, dispatch],
|
||||
);
|
||||
|
||||
const loadContent = useCallback(
|
||||
(charset?: string) => {
|
||||
if (!viewerState || !viewerState.open) {
|
||||
|
|
@ -123,10 +149,10 @@ const CodeViewer = () => {
|
|||
setLoaded(true);
|
||||
})
|
||||
.catch(() => {
|
||||
onClose();
|
||||
closeViewer();
|
||||
});
|
||||
},
|
||||
[viewerState],
|
||||
[viewerState, closeViewer],
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
|
|
@ -140,10 +166,6 @@ const CodeViewer = () => {
|
|||
loadContent();
|
||||
}, [viewerState?.open]);
|
||||
|
||||
const onClose = useCallback(() => {
|
||||
dispatch(closeCodeViewer());
|
||||
}, [dispatch]);
|
||||
|
||||
const openMore = useCallback(
|
||||
(e: React.MouseEvent<any>) => {
|
||||
setAnchorEl(e.currentTarget);
|
||||
|
|
@ -227,7 +249,7 @@ const CodeViewer = () => {
|
|||
fullScreenToggle
|
||||
dialogProps={{
|
||||
open: !!(viewerState && viewerState.open),
|
||||
onClose: onClose,
|
||||
onClose: handleDialogClose,
|
||||
fullWidth: true,
|
||||
maxWidth: "lg",
|
||||
}}
|
||||
|
|
|
|||
|
|
@ -11,6 +11,7 @@ import {
|
|||
saveMarkdown,
|
||||
uploadMarkdownImage,
|
||||
} from "../../../redux/thunks/viewer.ts";
|
||||
import { confirmOperation } from "../../../redux/thunks/dialog.ts";
|
||||
import { SquareMenuItem } from "../../FileManager/ContextMenu/ContextMenu.tsx";
|
||||
import useActionDisplayOpt, { canUpdate } from "../../FileManager/ContextMenu/useActionDisplayOpt.ts";
|
||||
import CaretDown from "../../Icons/CaretDown.tsx";
|
||||
|
|
@ -35,6 +36,31 @@ const MarkdownViewer = () => {
|
|||
const [optionAnchorEl, setOptionAnchorEl] = useState<null | HTMLElement>(null);
|
||||
const saveFunction = useRef(() => {});
|
||||
|
||||
const closeViewer = useCallback(() => {
|
||||
dispatch(closeMarkdownViewer());
|
||||
}, [dispatch]);
|
||||
|
||||
const handleDialogClose = useCallback(
|
||||
(_: React.SyntheticEvent | object, reason?: "backdropClick" | "escapeKeyDown") => {
|
||||
if (!saved && supportUpdate && (reason === "backdropClick" || reason === "escapeKeyDown")) {
|
||||
dispatch(
|
||||
confirmOperation(
|
||||
t("application:modals.discardUnsavedConfirm"),
|
||||
),
|
||||
)
|
||||
.then(() => {
|
||||
closeViewer();
|
||||
})
|
||||
.catch(() => {});
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
closeViewer();
|
||||
},
|
||||
[closeViewer, saved, supportUpdate, t, dispatch],
|
||||
);
|
||||
|
||||
const loadContent = useCallback(() => {
|
||||
if (!viewerState || !viewerState.open) {
|
||||
return;
|
||||
|
|
@ -50,9 +76,9 @@ const MarkdownViewer = () => {
|
|||
setLoaded(true);
|
||||
})
|
||||
.catch(() => {
|
||||
onClose();
|
||||
closeViewer();
|
||||
});
|
||||
}, [viewerState]);
|
||||
}, [viewerState, closeViewer]);
|
||||
|
||||
useEffect(() => {
|
||||
if (!viewerState || !viewerState.open) {
|
||||
|
|
@ -70,10 +96,6 @@ const MarkdownViewer = () => {
|
|||
return dispatch(markdownImageAutocompleteSuggestions());
|
||||
}, [viewerState?.open]);
|
||||
|
||||
const onClose = useCallback(() => {
|
||||
dispatch(closeMarkdownViewer());
|
||||
}, [dispatch]);
|
||||
|
||||
const openMore = useCallback(
|
||||
(e: React.MouseEvent<any>) => {
|
||||
setAnchorEl(e.currentTarget);
|
||||
|
|
@ -154,7 +176,7 @@ const MarkdownViewer = () => {
|
|||
fullScreenToggle
|
||||
dialogProps={{
|
||||
open: !!(viewerState && viewerState.open),
|
||||
onClose: onClose,
|
||||
onClose: handleDialogClose,
|
||||
fullWidth: true,
|
||||
maxWidth: "lg",
|
||||
}}
|
||||
|
|
|
|||
|
|
@ -44,7 +44,7 @@ const ViewerDialog = (props: ViewerDialogProps) => {
|
|||
const isMobile = useMediaQuery(theme.breakpoints.down("sm"));
|
||||
const [fullScreen, setFullScreen] = useState(props.fullScreen || isMobile);
|
||||
const onClose = useCallback(() => {
|
||||
props.dialogProps.onClose && props.dialogProps.onClose({}, "backdropClick");
|
||||
props.dialogProps.onClose && props.dialogProps.onClose({}, "closeButtonClick" as any);
|
||||
}, [props.dialogProps.onClose]);
|
||||
return (
|
||||
<Dialog
|
||||
|
|
|
|||
Loading…
Reference in New Issue