From 3a6a22bb458783fcfd32f3b35f5fe6afc5414e25 Mon Sep 17 00:00:00 2001 From: Aaron Liu Date: Tue, 15 Jul 2025 11:23:19 +0800 Subject: [PATCH] fix(file apps): "open in new tab" option now applies to all app types (cloudreve/cloudreve#2647) --- .../ViewerSetting/FileViewerEditDialog.tsx | 48 +++++++++---------- src/hooks/useNavigation.tsx | 9 +++- src/redux/thunks/filemanager.ts | 36 +++++++++++++- src/redux/thunks/viewer.ts | 20 +++++++- 4 files changed, 84 insertions(+), 29 deletions(-) diff --git a/src/component/Admin/FileSystem/ViewerSetting/FileViewerEditDialog.tsx b/src/component/Admin/FileSystem/ViewerSetting/FileViewerEditDialog.tsx index 3da8acd..d6f30e2 100644 --- a/src/component/Admin/FileSystem/ViewerSetting/FileViewerEditDialog.tsx +++ b/src/component/Admin/FileSystem/ViewerSetting/FileViewerEditDialog.tsx @@ -17,6 +17,8 @@ import FormControl from "@mui/material/FormControl"; import Grid from "@mui/material/Grid2"; import { useSnackbar } from "notistack"; import React, { lazy, Suspense, useCallback, useEffect, useMemo, useState } from "react"; +import { DndProvider, useDrag, useDrop } from "react-dnd"; +import { HTML5Backend } from "react-dnd-html5-backend"; import { Trans, useTranslation } from "react-i18next"; import { Viewer, ViewerPlatform, ViewerType } from "../../../../api/explorer.ts"; import { builtInViewers } from "../../../../redux/thunks/viewer.ts"; @@ -35,13 +37,11 @@ import DraggableDialog from "../../../Dialogs/DraggableDialog.tsx"; import { SquareMenuItem } from "../../../FileManager/ContextMenu/ContextMenu.tsx"; import { ViewerIDWithDefaultIcons } from "../../../FileManager/Dialogs/OpenWith.tsx"; import Add from "../../../Icons/Add.tsx"; +import ArrowDown from "../../../Icons/ArrowDown.tsx"; import Dismiss from "../../../Icons/Dismiss.tsx"; import SettingForm from "../../../Pages/Setting/SettingForm.tsx"; import MagicVarDialog, { MagicVar } from "../../Common/MagicVarDialog.tsx"; import { NoMarginHelperText } from "../../Settings/Settings.tsx"; -import ArrowDown from "../../../Icons/ArrowDown.tsx"; -import { DndProvider, useDrag, useDrop } from "react-dnd"; -import { HTML5Backend } from "react-dnd-html5-backend"; const MonacoEditor = lazy(() => import("../../../Viewers/CodeViewer/MonacoEditor.tsx")); @@ -396,28 +396,26 @@ const FileViewerEditDialog = ({ viewer, onChange, open, onClose }: FileViewerEdi {t("settings.viewerPlatformDes")} - {viewer.type == ViewerType.custom && ( - - - setViewerShadowed((v) => ({ - ...(v as Viewer), - props: { - ...(v?.props ?? {}), - openInNew: e.target.checked.toString(), - }, - })) - } - /> - } - label={t("settings.openInNew")} - /> - {t("settings.openInNewDes")} - - )} + + + setViewerShadowed((v) => ({ + ...(v as Viewer), + props: { + ...(v?.props ?? {}), + openInNew: e.target.checked.toString(), + }, + })) + } + /> + } + label={t("settings.openInNew")} + /> + {t("settings.openInNewDes")} + {viewer.id == builtInViewers.drawio && ( { if (path) { dispatch(navigateReconcile(index)).then(() => { dispatch(checkReadMeEnabled(index)); + dispatch(checkOpenViewerQuery(index)); }); dispatch(beforePathChange(index)); } diff --git a/src/redux/thunks/filemanager.ts b/src/redux/thunks/filemanager.ts index 940f0af..b7f55be 100644 --- a/src/redux/thunks/filemanager.ts +++ b/src/redux/thunks/filemanager.ts @@ -49,10 +49,11 @@ import { setShareReadmeDetect, setUploadFromClipboardDialog, } from "../globalStateSlice.ts"; -import { Viewers } from "../siteConfigSlice.ts"; +import { Viewers, ViewersByID } from "../siteConfigSlice.ts"; import { AppThunk } from "../store.ts"; import { deleteFile, openFileContextMenu } from "./file.ts"; import { queueLoadShareInfo } from "./share.ts"; +import { openViewer } from "./viewer.ts"; export function setTargetPath(index: number, path: string): AppThunk { return async (dispatch, _getState) => { @@ -128,6 +129,39 @@ export function checkReadMeEnabled(index: number): AppThunk { }; } +export function checkOpenViewerQuery(index: number): AppThunk { + return async (dispatch, getState) => { + const currentUrl = new URL(window.location.href); + const viewer = currentUrl.searchParams.get("viewer"); + const fileId = currentUrl.searchParams.get("open"); + const version = currentUrl.searchParams.get("version"); + const size = currentUrl.searchParams.get("size"); + + // Clear viewer-related query parameters + currentUrl.searchParams.delete("viewer"); + currentUrl.searchParams.delete("open"); + currentUrl.searchParams.delete("version"); + currentUrl.searchParams.delete("size"); + window.history.replaceState({}, "", currentUrl.toString()); + + if (!fileId || !viewer || !ViewersByID[viewer]) { + return; + } + + const { files: list, pagination } = getState().fileManager[index]?.list ?? {}; + if (list) { + // Find readme file from highest to lowest priority + const found = list.find((file) => file.id === fileId); + if (found) { + dispatch(openViewer(found, ViewersByID[viewer], parseInt(size ?? "0"), version ?? undefined, true)); + return; + } + } + + alert("openViewer"); + }; +} + export function navigateReconcile(index: number, opt?: NavigateReconcileOptions): AppThunk> { return async (dispatch, getState) => { const timeNow = dayjs().valueOf(); diff --git a/src/redux/thunks/viewer.ts b/src/redux/thunks/viewer.ts index 6cac49c..07288a3 100644 --- a/src/redux/thunks/viewer.ts +++ b/src/redux/thunks/viewer.ts @@ -9,6 +9,7 @@ import { FileManagerIndex } from "../../component/FileManager/FileManager.tsx"; import SessionManager, { UserSettings } from "../../session"; import { isTrueVal } from "../../session/utils.ts"; import { dataUrlToBytes, fileExtension, fileNameNoExt, getFileLinkedUri, sizeToString } from "../../util"; +import { base64Encode } from "../../util/base64.ts"; import CrUri from "../../util/uri.ts"; import { closeContextMenu, ContextMenuTypes, fileUpdated } from "../fileManagerSlice.ts"; import { @@ -34,7 +35,6 @@ import { Viewers, ViewersByID } from "../siteConfigSlice.ts"; import { AppThunk } from "../store.ts"; import { askSaveAs, askStaleVersionAction } from "./dialog.ts"; import { longRunningTaskWithSnackbar, refreshSingleFileSymbolicLinks } from "./file.ts"; -import { base64Encode } from "../../util/base64.ts"; export interface ExpandedViewerSetting { [key: string]: Viewer[]; @@ -98,8 +98,24 @@ export function openViewers( }; } -export function openViewer(file: FileResponse, viewer: Viewer, size: number, preferredVersion?: string): AppThunk { +export function openViewer( + file: FileResponse, + viewer: Viewer, + size: number, + preferredVersion?: string, + forceNotOpenInNew?: boolean, +): AppThunk { return async (dispatch, getState) => { + if (!forceNotOpenInNew && viewer.type != ViewerType.custom && isTrueVal(viewer.props?.openInNew ?? "")) { + const currentUrl = new URL(window.location.href); + currentUrl.searchParams.set("viewer", viewer.id ?? ""); + currentUrl.searchParams.set("version", preferredVersion ?? ""); + currentUrl.searchParams.set("open", file.id ?? ""); + currentUrl.searchParams.set("size", size.toString()); + window.open(currentUrl.toString(), "_blank"); + return; + } + // Warning for large file if (viewer.max_size && size > viewer.max_size) { enqueueSnackbar({