Merge pull request #322 from ONLYOFFICE/bugfix/doceditor-optimization
Bugfix/doceditor optimization
This commit is contained in:
commit
14dbe3b022
@ -37,6 +37,8 @@ import SimulatePassword from "../../SimulatePassword";
|
||||
import StyledComponent from "./StyledConvertPasswordDialog";
|
||||
import config from "PACKAGE_FILE";
|
||||
|
||||
let _isMounted = false;
|
||||
|
||||
const ConvertPasswordDialogComponent = (props) => {
|
||||
const {
|
||||
t,
|
||||
|
Binary file not shown.
@ -11,7 +11,7 @@
|
||||
"deploy": "shx --silent mkdir -p ../../../publish/web/editor && shx --silent mkdir -p ../../../publish/web/editor/.next && shx --silent mkdir -p ../../../publish/web/editor/config && shx cp -r config/* ../../../publish/web/editor/config && shx --silent mkdir -p ../../../publish/web/editor/node_modules && shx --silent mkdir -p ../../../publish/web/editor/.next/static && shx cp -r .next/standalone/node_modules/* ../../../publish/web/editor/node_modules && shx cp -r .next/static/* ../../../publish/web/editor/.next/static && shx cp -r .next/standalone/packages/doceditor/.next/* ../../../publish/web/editor/.next && shx cp -f server.prod.js ../../../publish/web/editor/server.js"
|
||||
},
|
||||
"dependencies": {
|
||||
"@onlyoffice/document-editor-react": "file:./onlyoffice-document-editor-react-1.5.1.tgz",
|
||||
"@onlyoffice/document-editor-react": "^1.5.1",
|
||||
"i18next": "^20.6.1",
|
||||
"next": "14.0.4",
|
||||
"react": "^18.2.0",
|
||||
|
33
packages/doceditor/src/app/create/layout.tsx
Normal file
33
packages/doceditor/src/app/create/layout.tsx
Normal file
@ -0,0 +1,33 @@
|
||||
// (c) Copyright Ascensio System SIA 2009-2024
|
||||
//
|
||||
// This program is a free software product.
|
||||
// You can redistribute it and/or modify it under the terms
|
||||
// of the GNU Affero General Public License (AGPL) version 3 as published by the Free Software
|
||||
// Foundation. In accordance with Section 7(a) of the GNU AGPL its Section 15 shall be amended
|
||||
// to the effect that Ascensio System SIA expressly excludes the warranty of non-infringement of
|
||||
// any third-party rights.
|
||||
//
|
||||
// This program is distributed WITHOUT ANY WARRANTY, without even the implied warranty
|
||||
// of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. For details, see
|
||||
// the GNU AGPL at: http://www.gnu.org/licenses/agpl-3.0.html
|
||||
//
|
||||
// You can contact Ascensio System SIA at Lubanas st. 125a-25, Riga, Latvia, EU, LV-1021.
|
||||
//
|
||||
// The interactive user interfaces in modified source and object code versions of the Program must
|
||||
// display Appropriate Legal Notices, as required under Section 5 of the GNU AGPL version 3.
|
||||
//
|
||||
// Pursuant to Section 7(b) of the License you must retain the original Product logo when
|
||||
// distributing the program. Pursuant to Section 7(e) we decline to grant you any rights under
|
||||
// trademark law for use of our trademarks.
|
||||
//
|
||||
// All the Product's GUI elements, including illustrations and icon sets, as well as technical writing
|
||||
// content are licensed under the terms of the Creative Commons Attribution-ShareAlike 4.0
|
||||
// International. See the License terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode
|
||||
|
||||
export default function CreateLayout({
|
||||
children,
|
||||
}: {
|
||||
children: React.ReactNode;
|
||||
}) {
|
||||
return <>{children}</>;
|
||||
}
|
@ -24,23 +24,9 @@
|
||||
// content are licensed under the terms of the Creative Commons Attribution-ShareAlike 4.0
|
||||
// International. See the License terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode
|
||||
|
||||
import React from "react";
|
||||
import { i18n } from "i18next";
|
||||
import { I18nextProvider } from "react-i18next";
|
||||
import AppLoader from "@docspace/shared/components/app-loader";
|
||||
|
||||
import { ShareProps } from "./Share.types";
|
||||
import Share from ".";
|
||||
|
||||
const FilesSelectorWrapper = ({
|
||||
i18nProp,
|
||||
|
||||
...rest
|
||||
}: ShareProps & { i18nProp: i18n }) => {
|
||||
return (
|
||||
<I18nextProvider i18n={i18nProp}>
|
||||
<Share {...rest} />
|
||||
</I18nextProvider>
|
||||
);
|
||||
};
|
||||
|
||||
export default FilesSelectorWrapper;
|
||||
export default function Loading() {
|
||||
// You can add any UI inside Loading, including a Skeleton.
|
||||
return <AppLoader />;
|
||||
}
|
@ -24,11 +24,12 @@
|
||||
// content are licensed under the terms of the Creative Commons Attribution-ShareAlike 4.0
|
||||
// International. See the License terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode
|
||||
|
||||
import { redirect } from "next/navigation";
|
||||
import { permanentRedirect, redirect } from "next/navigation";
|
||||
|
||||
import { getBaseUrl } from "@docspace/shared/utils/next-ssr-helper";
|
||||
|
||||
import { createFile, fileCopyAs } from "@/utils/actions";
|
||||
import CreateFileError from "@/components/CreateFileError";
|
||||
import { getBaseUrl } from "@docspace/shared/utils/next-ssr-helper";
|
||||
|
||||
type TSearchParams = {
|
||||
parentId: string;
|
||||
@ -91,9 +92,8 @@ async function Page({ searchParams }: { searchParams: TSearchParams }) {
|
||||
if (file?.id) fileId = file.id;
|
||||
|
||||
if (fileId || !fileError) {
|
||||
const redirectURL = `${baseURL}/doceditor/?fileId=${fileId}`;
|
||||
|
||||
return redirect(redirectURL);
|
||||
const redirectURL = `${baseURL}/doceditor?fileId=${fileId}`;
|
||||
return permanentRedirect(redirectURL);
|
||||
}
|
||||
|
||||
return (
|
||||
@ -101,7 +101,6 @@ async function Page({ searchParams }: { searchParams: TSearchParams }) {
|
||||
error={fileError}
|
||||
fileInfo={fileInfo}
|
||||
fromFile={!!fromFile}
|
||||
fromTemplate={!!fromTemplate}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
@ -24,64 +24,32 @@
|
||||
// content are licensed under the terms of the Creative Commons Attribution-ShareAlike 4.0
|
||||
// International. See the License terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode
|
||||
|
||||
import "../styles/globals.scss";
|
||||
import Script from "next/script";
|
||||
import Scripts from "@/components/Scripts";
|
||||
import StyledComponentsRegistry from "@/utils/registry";
|
||||
|
||||
// import StyledComponentsRegistry from "@/utils/registry";
|
||||
import "../styles/globals.scss";
|
||||
import Providers from "@/providers";
|
||||
import { getSettings, getUser } from "@/utils/actions";
|
||||
|
||||
export default async function RootLayout({
|
||||
children,
|
||||
}: {
|
||||
children: React.ReactNode;
|
||||
}) {
|
||||
const [user, settings] = await Promise.all([getUser(), getSettings()]);
|
||||
|
||||
return (
|
||||
<html lang="en">
|
||||
<head>
|
||||
<link id="favicon" rel="shortcut icon" type="image/x-icon" />
|
||||
</head>
|
||||
<body>
|
||||
{children}
|
||||
<Script
|
||||
id="browser-detector"
|
||||
src="/static/scripts/browserDetector.js"
|
||||
/>
|
||||
<Script id="docspace-config">
|
||||
{`
|
||||
console.log("It's DocEditor INIT");
|
||||
fetch("/static/scripts/config.json")
|
||||
.then((response) => {
|
||||
if (!response.ok) {
|
||||
throw new Error("HTTP error " + response.status);
|
||||
}
|
||||
return response.json();
|
||||
})
|
||||
.then((config) => {
|
||||
window.DocSpaceConfig = {
|
||||
...config,
|
||||
};
|
||||
|
||||
if (
|
||||
window.navigator.userAgent.includes("ZoomWebKit") ||
|
||||
window.navigator.userAgent.includes("ZoomApps")
|
||||
) {
|
||||
window.DocSpaceConfig.editor = {
|
||||
openOnNewPage: false,
|
||||
requestClose: true,
|
||||
};
|
||||
}
|
||||
|
||||
//console.log({ DocSpaceConfig: window.DocSpaceConfig });
|
||||
})
|
||||
.catch((e) => {
|
||||
console.error(e);
|
||||
window.DocSpaceConfig = {
|
||||
errorOnLoad: e,
|
||||
};
|
||||
});
|
||||
`}
|
||||
</Script>
|
||||
<StyledComponentsRegistry>
|
||||
<Providers contextData={{ user, settings }}>{children}</Providers>
|
||||
</StyledComponentsRegistry>
|
||||
|
||||
<Scripts />
|
||||
</body>
|
||||
</html>
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -24,23 +24,9 @@
|
||||
// content are licensed under the terms of the Creative Commons Attribution-ShareAlike 4.0
|
||||
// International. See the License terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode
|
||||
|
||||
import React from "react";
|
||||
import { i18n } from "i18next";
|
||||
import { I18nextProvider } from "react-i18next";
|
||||
import AppLoader from "@docspace/shared/components/app-loader";
|
||||
|
||||
import { FilesSelectorProps } from "./FilesSelector.types";
|
||||
import FilesSelector from ".";
|
||||
|
||||
const FilesSelectorWrapper = ({
|
||||
i18nProp,
|
||||
|
||||
...rest
|
||||
}: FilesSelectorProps & { i18nProp: i18n }) => {
|
||||
return (
|
||||
<I18nextProvider i18n={i18nProp}>
|
||||
<FilesSelector {...rest} />
|
||||
</I18nextProvider>
|
||||
);
|
||||
};
|
||||
|
||||
export default FilesSelectorWrapper;
|
||||
export default function Loading() {
|
||||
// You can add any UI inside Loading, including a Skeleton.
|
||||
return <AppLoader />;
|
||||
}
|
@ -25,10 +25,16 @@
|
||||
// International. See the License terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode
|
||||
|
||||
import type { Metadata } from "next";
|
||||
import dynamic from "next/dynamic";
|
||||
|
||||
import AppLoader from "@docspace/shared/components/app-loader";
|
||||
|
||||
import { getData } from "@/utils/actions";
|
||||
|
||||
import Root from "@/components/Root";
|
||||
const Root = dynamic(() => import("@/components/Root"), {
|
||||
ssr: false,
|
||||
loading: () => <AppLoader />,
|
||||
});
|
||||
|
||||
export const metadata: Metadata = {
|
||||
title: "Onlyoffice DocEditor page",
|
||||
@ -41,26 +47,19 @@ async function Page({
|
||||
}: {
|
||||
searchParams?: { [key: string]: string };
|
||||
}) {
|
||||
const {
|
||||
fileId,
|
||||
fileid,
|
||||
fileVersion: version,
|
||||
doc,
|
||||
action,
|
||||
share,
|
||||
editorType,
|
||||
} = searchParams || {
|
||||
fileId: undefined,
|
||||
fileid: undefined,
|
||||
fileVersion: undefined,
|
||||
doc: undefined,
|
||||
action: undefined,
|
||||
share: undefined,
|
||||
editorType: undefined,
|
||||
};
|
||||
const { fileId, fileid, version, doc, action, share, editorType } =
|
||||
searchParams || {
|
||||
fileId: undefined,
|
||||
fileid: undefined,
|
||||
version: undefined,
|
||||
doc: undefined,
|
||||
action: undefined,
|
||||
share: undefined,
|
||||
editorType: undefined,
|
||||
};
|
||||
|
||||
const data = await getData(
|
||||
fileId ?? fileid,
|
||||
fileId ?? fileid ?? "",
|
||||
version,
|
||||
doc,
|
||||
action === "view",
|
||||
@ -72,4 +71,3 @@ async function Page({
|
||||
}
|
||||
|
||||
export default Page;
|
||||
|
||||
|
@ -27,55 +27,20 @@
|
||||
"use client";
|
||||
|
||||
import React from "react";
|
||||
import { toast } from "react-toastify";
|
||||
|
||||
import { Toast } from "@docspace/shared/components/toast";
|
||||
import { ThemeProvider } from "@docspace/shared/components/theme-provider";
|
||||
import { toastr } from "@docspace/shared/components/toast";
|
||||
import { Error520SSR } from "@docspace/shared/components/errors/Error520";
|
||||
import { TUser } from "@docspace/shared/api/people/types";
|
||||
import {
|
||||
TFirebaseSettings,
|
||||
TSettings,
|
||||
} from "@docspace/shared/api/settings/types";
|
||||
import FirebaseHelper from "@docspace/shared/utils/firebase";
|
||||
|
||||
import useDeviceType from "@/hooks/useDeviceType";
|
||||
import useWhiteLabel from "@/hooks/useWhiteLabel";
|
||||
import useI18N from "@/hooks/useI18N";
|
||||
import useTheme from "@/hooks/useTheme";
|
||||
|
||||
import pkg from "../../package.json";
|
||||
|
||||
type CreateFileErrorProps = {
|
||||
error: Error;
|
||||
fileInfo: object;
|
||||
fromTemplate: boolean;
|
||||
fromFile: boolean;
|
||||
settings?: TSettings;
|
||||
user?: TUser;
|
||||
};
|
||||
|
||||
const CreateFileError = ({
|
||||
error,
|
||||
fileInfo,
|
||||
fromFile,
|
||||
fromTemplate,
|
||||
settings,
|
||||
user,
|
||||
}: CreateFileErrorProps) => {
|
||||
const firebaseHelper = new FirebaseHelper({} as TFirebaseSettings);
|
||||
|
||||
const { i18n } = useI18N({ settings, user });
|
||||
const { currentDeviceType } = useDeviceType();
|
||||
const { logoUrls } = useWhiteLabel();
|
||||
const { theme } = useTheme({ user, i18n });
|
||||
|
||||
const t = i18n.t ? i18n.t.bind(i18n) : null;
|
||||
const message = error.message ?? error ?? "";
|
||||
|
||||
const showingToast = React.useRef(false);
|
||||
|
||||
React.useEffect(() => {
|
||||
if (fromFile && message.includes("password")) {
|
||||
const searchParams = new URLSearchParams();
|
||||
@ -85,30 +50,11 @@ const CreateFileError = ({
|
||||
`${window.location.origin}?${searchParams.toString()}`,
|
||||
);
|
||||
} else {
|
||||
if (!t || showingToast.current) return;
|
||||
showingToast.current = true;
|
||||
toastr.error(message, t?.("Common:Warning"));
|
||||
throw new Error(message);
|
||||
}
|
||||
}, [fileInfo, fromFile, message, t]);
|
||||
}, [fileInfo, fromFile, message]);
|
||||
|
||||
if (fromFile && message.includes("password")) return null;
|
||||
|
||||
return (
|
||||
<ThemeProvider theme={theme}>
|
||||
<Toast />
|
||||
{logoUrls && (
|
||||
<Error520SSR
|
||||
i18nProp={i18n}
|
||||
errorLog={error}
|
||||
user={user ?? ({} as TUser)}
|
||||
currentDeviceType={currentDeviceType}
|
||||
version={pkg.version}
|
||||
firebaseHelper={firebaseHelper}
|
||||
whiteLabelLogoUrls={logoUrls}
|
||||
/>
|
||||
)}
|
||||
</ThemeProvider>
|
||||
);
|
||||
return null;
|
||||
};
|
||||
|
||||
export default CreateFileError;
|
||||
|
@ -28,6 +28,7 @@
|
||||
|
||||
import React from "react";
|
||||
import { isMobile } from "react-device-detect";
|
||||
import { useTranslation } from "react-i18next";
|
||||
|
||||
import { DocumentEditor } from "@onlyoffice/document-editor-react";
|
||||
import IConfig from "@onlyoffice/document-editor-react/dist/esm/types/model/config";
|
||||
@ -53,13 +54,13 @@ const Editor = ({
|
||||
config,
|
||||
successAuth,
|
||||
user,
|
||||
view,
|
||||
|
||||
doc,
|
||||
documentserverUrl,
|
||||
fileInfo,
|
||||
isSharingAccess,
|
||||
errorMessage,
|
||||
t,
|
||||
|
||||
onSDKRequestSharingSettings,
|
||||
onSDKRequestSaveAs,
|
||||
onSDKRequestInsertImage,
|
||||
@ -67,6 +68,8 @@ const Editor = ({
|
||||
onSDKRequestSelectDocument,
|
||||
onSDKRequestReferenceSource,
|
||||
}: EditorProps) => {
|
||||
const { t } = useTranslation(["Common", "Editor", "DeepLink"]);
|
||||
|
||||
const {
|
||||
onDocumentReady,
|
||||
onSDKRequestOpen,
|
||||
|
@ -28,15 +28,10 @@
|
||||
|
||||
import React from "react";
|
||||
|
||||
import useI18N from "@/hooks/useI18N";
|
||||
|
||||
import { Error404Wrapper } from "@docspace/shared/components/errors/Error404";
|
||||
import Error404 from "@docspace/shared/components/errors/Error404";
|
||||
|
||||
const NotFoundError = ({}) => {
|
||||
const { i18n } = useI18N({});
|
||||
|
||||
return <Error404Wrapper i18nProp={i18n} />;
|
||||
return <Error404 />;
|
||||
};
|
||||
|
||||
export default NotFoundError;
|
||||
|
||||
|
@ -27,24 +27,16 @@
|
||||
"use client";
|
||||
|
||||
import React from "react";
|
||||
import { toast } from "react-toastify";
|
||||
import { I18nextProvider } from "react-i18next";
|
||||
import { useTranslation } from "react-i18next";
|
||||
|
||||
import { Toast } from "@docspace/shared/components/toast";
|
||||
import { TFile } from "@docspace/shared/api/files/types";
|
||||
import { ThemeProvider } from "@docspace/shared/components/theme-provider";
|
||||
import ErrorBoundary from "@docspace/shared/components/error-boundary/ErrorBoundary";
|
||||
import ErrorContainer from "@docspace/shared/components/error-container/ErrorContainer";
|
||||
import FirebaseHelper from "@docspace/shared/utils/firebase";
|
||||
import { TFirebaseSettings } from "@docspace/shared/api/settings/types";
|
||||
import { TUser } from "@docspace/shared/api/people/types";
|
||||
import AppLoader from "@docspace/shared/components/app-loader";
|
||||
import { Error520SSR } from "@docspace/shared/components/errors/Error520";
|
||||
|
||||
import { TResponse } from "@/types";
|
||||
import useError from "@/hooks/useError";
|
||||
import useI18N from "@/hooks/useI18N";
|
||||
import useTheme from "@/hooks/useTheme";
|
||||
|
||||
import useDeviceType from "@/hooks/useDeviceType";
|
||||
import useWhiteLabel from "@/hooks/useWhiteLabel";
|
||||
import useRootInit from "@/hooks/useRootInit";
|
||||
@ -55,17 +47,12 @@ import useSocketHelper from "@/hooks/useSocketHelper";
|
||||
import useShareDialog from "@/hooks/useShareDialog";
|
||||
import useFilesSettings from "@/hooks/useFilesSettings";
|
||||
import useUpdateSearchParamId from "@/hooks/useUpdateSearchParamId";
|
||||
import { IS_VIEW } from "@/utils/constants";
|
||||
import StyledComponentsRegistry from "@/utils/registry";
|
||||
|
||||
import pkgFile from "../../package.json";
|
||||
|
||||
import DeepLink from "./deep-link";
|
||||
import Editor from "./Editor";
|
||||
import SelectFileDialog from "./SelectFileDialog";
|
||||
import SelectFolderDialog from "./SelectFolderDialog";
|
||||
import SharingDialog from "./ShareDialog";
|
||||
import { EditorConfigErrorType } from "@docspace/shared/enums";
|
||||
|
||||
const Root = ({
|
||||
settings,
|
||||
@ -74,34 +61,32 @@ const Root = ({
|
||||
user,
|
||||
error,
|
||||
isSharingAccess,
|
||||
editorUrl,
|
||||
|
||||
doc,
|
||||
fileId,
|
||||
hash,
|
||||
}: TResponse) => {
|
||||
const documentserverUrl = editorUrl?.docServiceUrl;
|
||||
const documentserverUrl = config?.editorUrl ?? error?.editorUrl;
|
||||
const fileInfo = config?.file;
|
||||
const firebaseHelper = new FirebaseHelper(
|
||||
settings?.firebase ?? ({} as TFirebaseSettings),
|
||||
);
|
||||
|
||||
const instanceId = config?.document?.referenceData.instanceId;
|
||||
const isSkipError =
|
||||
error?.status === "not-found" ||
|
||||
error?.status === "access-denied" ||
|
||||
error?.status === "not-supported";
|
||||
|
||||
const { t } = useTranslation(["Editor", "Common"]);
|
||||
|
||||
useRootInit({
|
||||
documentType: config?.documentType,
|
||||
});
|
||||
const { i18n } = useI18N({ settings, user });
|
||||
|
||||
const t = i18n.t ? i18n.t.bind(i18n) : null;
|
||||
const { onError, getErrorMessage } = useError({
|
||||
const { getErrorMessage } = useError({
|
||||
error,
|
||||
editorUrl: documentserverUrl,
|
||||
t,
|
||||
});
|
||||
const { theme, currentColorTheme } = useTheme({ user, i18n });
|
||||
|
||||
const { currentDeviceType } = useDeviceType();
|
||||
const { logoUrls } = useWhiteLabel();
|
||||
const { isShowDeepLink, setIsShowDeepLink } = useDeepLink({
|
||||
@ -118,6 +103,7 @@ const Root = ({
|
||||
onCloseSelectFolderDialog,
|
||||
onSubmitSelectFolderDialog,
|
||||
getIsDisabledSelectFolderDialog,
|
||||
|
||||
isVisibleSelectFolderDialog,
|
||||
titleSelectorFolderDialog,
|
||||
extensionSelectorFolderDialog,
|
||||
@ -132,125 +118,99 @@ const Root = ({
|
||||
getIsDisabledSelectFileDialog,
|
||||
|
||||
selectFileDialogFileTypeDetection,
|
||||
|
||||
selectFileDialogVisible,
|
||||
} = useSelectFileDialog({ instanceId: instanceId ?? "" });
|
||||
const {
|
||||
isSharingDialogVisible,
|
||||
|
||||
onCloseSharingDialog,
|
||||
onSDKRequestSharingSettings,
|
||||
} = useShareDialog();
|
||||
|
||||
useUpdateSearchParamId(fileId, hash);
|
||||
|
||||
return (
|
||||
<I18nextProvider i18n={i18n}>
|
||||
<ThemeProvider theme={theme} currentColorScheme={currentColorTheme}>
|
||||
<ErrorBoundary
|
||||
user={user ?? ({} as TUser)}
|
||||
version={pkgFile.version}
|
||||
firebaseHelper={firebaseHelper}
|
||||
currentDeviceType={currentDeviceType}
|
||||
whiteLabelLogoUrls={logoUrls}
|
||||
isNextJS
|
||||
theme={theme}
|
||||
i18n={i18n}
|
||||
onError={onError}
|
||||
>
|
||||
{!fileId || false ? (
|
||||
<AppLoader />
|
||||
) : isShowDeepLink ? (
|
||||
<DeepLink
|
||||
fileInfo={fileInfo}
|
||||
logoUrls={logoUrls}
|
||||
userEmail={user?.email}
|
||||
theme={theme}
|
||||
currentDeviceType={currentDeviceType}
|
||||
deepLinkConfig={settings?.deepLink}
|
||||
setIsShowDeepLink={setIsShowDeepLink}
|
||||
/>
|
||||
) : error && error.message === "restore-backup" && !isSkipError ? (
|
||||
<StyledComponentsRegistry>
|
||||
<ErrorContainer
|
||||
headerText={t?.("Common:Error")}
|
||||
customizedBodyText={getErrorMessage()}
|
||||
isEditor
|
||||
/>
|
||||
</StyledComponentsRegistry>
|
||||
) : error && error.message !== "unauthorized" && !isSkipError ? (
|
||||
<Error520SSR
|
||||
i18nProp={i18n}
|
||||
errorLog={error as Error}
|
||||
version={pkgFile.version}
|
||||
user={user ?? ({} as TUser)}
|
||||
whiteLabelLogoUrls={logoUrls}
|
||||
firebaseHelper={firebaseHelper}
|
||||
currentDeviceType={currentDeviceType}
|
||||
/>
|
||||
) : isShowDeepLink ? null : (
|
||||
<div style={{ width: "100%", height: "100%" }}>
|
||||
{documentserverUrl && (
|
||||
<Editor
|
||||
config={config}
|
||||
user={user}
|
||||
view={IS_VIEW}
|
||||
successAuth={successAuth}
|
||||
doc={doc}
|
||||
isSharingAccess={isSharingAccess}
|
||||
t={t}
|
||||
documentserverUrl={documentserverUrl}
|
||||
fileInfo={fileInfo}
|
||||
errorMessage={error?.message}
|
||||
onSDKRequestSharingSettings={onSDKRequestSharingSettings}
|
||||
onSDKRequestSaveAs={onSDKRequestSaveAs}
|
||||
onSDKRequestInsertImage={onSDKRequestInsertImage}
|
||||
onSDKRequestReferenceSource={onSDKRequestReferenceSource}
|
||||
onSDKRequestSelectDocument={onSDKRequestSelectDocument}
|
||||
onSDKRequestSelectSpreadsheet={onSDKRequestSelectSpreadsheet}
|
||||
/>
|
||||
)}
|
||||
<Toast isSSR />
|
||||
{isVisibleSelectFolderDialog && !!socketHelper && (
|
||||
<SelectFolderDialog
|
||||
socketHelper={socketHelper}
|
||||
isVisible={isVisibleSelectFolderDialog}
|
||||
onSubmit={onSubmitSelectFolderDialog}
|
||||
onClose={onCloseSelectFolderDialog}
|
||||
titleSelectorFolder={titleSelectorFolderDialog}
|
||||
fileInfo={fileInfo ?? ({} as TFile)}
|
||||
getIsDisabled={getIsDisabledSelectFolderDialog}
|
||||
i18n={i18n}
|
||||
filesSettings={filesSettings}
|
||||
fileSaveAsExtension={extensionSelectorFolderDialog}
|
||||
/>
|
||||
)}
|
||||
{selectFileDialogVisible && !!socketHelper && (
|
||||
<SelectFileDialog
|
||||
socketHelper={socketHelper}
|
||||
isVisible={selectFileDialogVisible}
|
||||
onSubmit={onSubmitSelectFileDialog}
|
||||
onClose={onCloseSelectFileDialog}
|
||||
getIsDisabled={getIsDisabledSelectFileDialog}
|
||||
fileTypeDetection={selectFileDialogFileTypeDetection}
|
||||
fileInfo={fileInfo ?? ({} as TFile)}
|
||||
i18n={i18n}
|
||||
filesSettings={filesSettings}
|
||||
/>
|
||||
)}
|
||||
{isSharingDialogVisible && !!socketHelper && fileInfo && (
|
||||
<SharingDialog
|
||||
isVisible={isSharingDialogVisible}
|
||||
fileInfo={fileInfo}
|
||||
onCancel={onCloseSharingDialog}
|
||||
theme={theme}
|
||||
i18n={i18n}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
</ErrorBoundary>
|
||||
</ThemeProvider>
|
||||
</I18nextProvider>
|
||||
React.useEffect(() => {
|
||||
if (
|
||||
error &&
|
||||
error.message !== "restore-backup" &&
|
||||
error.message !== "unauthorized" &&
|
||||
!isSkipError
|
||||
) {
|
||||
throw new Error(error.message);
|
||||
}
|
||||
}, [error, isSkipError]);
|
||||
|
||||
return !fileId ? (
|
||||
<AppLoader />
|
||||
) : isShowDeepLink ? (
|
||||
<DeepLink
|
||||
fileInfo={fileInfo}
|
||||
logoUrls={logoUrls}
|
||||
userEmail={user?.email}
|
||||
currentDeviceType={currentDeviceType}
|
||||
deepLinkConfig={settings?.deepLink}
|
||||
setIsShowDeepLink={setIsShowDeepLink}
|
||||
/>
|
||||
) : error && error.message === "restore-backup" && !isSkipError ? (
|
||||
<ErrorContainer
|
||||
headerText={t("Common:Error")}
|
||||
customizedBodyText={getErrorMessage()}
|
||||
isEditor
|
||||
/>
|
||||
) : (
|
||||
<div style={{ width: "100%", height: "100%" }}>
|
||||
{documentserverUrl && (
|
||||
<Editor
|
||||
config={config}
|
||||
user={user}
|
||||
successAuth={successAuth}
|
||||
doc={doc}
|
||||
isSharingAccess={isSharingAccess}
|
||||
documentserverUrl={documentserverUrl}
|
||||
fileInfo={fileInfo}
|
||||
errorMessage={error?.message}
|
||||
onSDKRequestSharingSettings={onSDKRequestSharingSettings}
|
||||
onSDKRequestSaveAs={onSDKRequestSaveAs}
|
||||
onSDKRequestInsertImage={onSDKRequestInsertImage}
|
||||
onSDKRequestReferenceSource={onSDKRequestReferenceSource}
|
||||
onSDKRequestSelectDocument={onSDKRequestSelectDocument}
|
||||
onSDKRequestSelectSpreadsheet={onSDKRequestSelectSpreadsheet}
|
||||
/>
|
||||
)}
|
||||
|
||||
{isVisibleSelectFolderDialog && !!socketHelper && fileInfo && (
|
||||
<SelectFolderDialog
|
||||
socketHelper={socketHelper}
|
||||
isVisible={isVisibleSelectFolderDialog}
|
||||
onSubmit={onSubmitSelectFolderDialog}
|
||||
onClose={onCloseSelectFolderDialog}
|
||||
titleSelectorFolder={titleSelectorFolderDialog}
|
||||
fileInfo={fileInfo}
|
||||
getIsDisabled={getIsDisabledSelectFolderDialog}
|
||||
filesSettings={filesSettings}
|
||||
fileSaveAsExtension={extensionSelectorFolderDialog}
|
||||
/>
|
||||
)}
|
||||
{selectFileDialogVisible && !!socketHelper && fileInfo && (
|
||||
<SelectFileDialog
|
||||
socketHelper={socketHelper}
|
||||
filesSettings={filesSettings}
|
||||
isVisible={selectFileDialogVisible}
|
||||
onSubmit={onSubmitSelectFileDialog}
|
||||
onClose={onCloseSelectFileDialog}
|
||||
getIsDisabled={getIsDisabledSelectFileDialog}
|
||||
fileTypeDetection={selectFileDialogFileTypeDetection}
|
||||
fileInfo={fileInfo}
|
||||
/>
|
||||
)}
|
||||
{isSharingDialogVisible && !!socketHelper && fileInfo && (
|
||||
<SharingDialog
|
||||
isVisible={isSharingDialogVisible}
|
||||
fileInfo={fileInfo}
|
||||
onCancel={onCloseSharingDialog}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
|
72
packages/doceditor/src/components/Scripts.tsx
Normal file
72
packages/doceditor/src/components/Scripts.tsx
Normal file
@ -0,0 +1,72 @@
|
||||
// (c) Copyright Ascensio System SIA 2009-2024
|
||||
//
|
||||
// This program is a free software product.
|
||||
// You can redistribute it and/or modify it under the terms
|
||||
// of the GNU Affero General Public License (AGPL) version 3 as published by the Free Software
|
||||
// Foundation. In accordance with Section 7(a) of the GNU AGPL its Section 15 shall be amended
|
||||
// to the effect that Ascensio System SIA expressly excludes the warranty of non-infringement of
|
||||
// any third-party rights.
|
||||
//
|
||||
// This program is distributed WITHOUT ANY WARRANTY, without even the implied warranty
|
||||
// of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. For details, see
|
||||
// the GNU AGPL at: http://www.gnu.org/licenses/agpl-3.0.html
|
||||
//
|
||||
// You can contact Ascensio System SIA at Lubanas st. 125a-25, Riga, Latvia, EU, LV-1021.
|
||||
//
|
||||
// The interactive user interfaces in modified source and object code versions of the Program must
|
||||
// display Appropriate Legal Notices, as required under Section 5 of the GNU AGPL version 3.
|
||||
//
|
||||
// Pursuant to Section 7(b) of the License you must retain the original Product logo when
|
||||
// distributing the program. Pursuant to Section 7(e) we decline to grant you any rights under
|
||||
// trademark law for use of our trademarks.
|
||||
//
|
||||
// All the Product's GUI elements, including illustrations and icon sets, as well as technical writing
|
||||
// content are licensed under the terms of the Creative Commons Attribution-ShareAlike 4.0
|
||||
// International. See the License terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode
|
||||
|
||||
import Script from "next/script";
|
||||
|
||||
const Scripts = () => {
|
||||
return (
|
||||
<>
|
||||
<Script id="browser-detector" src="/static/scripts/browserDetector.js" />
|
||||
<Script id="docspace-config">
|
||||
{`
|
||||
console.log("It's DocEditor INIT");
|
||||
fetch("/static/scripts/config.json")
|
||||
.then((response) => {
|
||||
if (!response.ok) {
|
||||
throw new Error("HTTP error " + response.status);
|
||||
}
|
||||
return response.json();
|
||||
})
|
||||
.then((config) => {
|
||||
window.DocSpaceConfig = {
|
||||
...config,
|
||||
};
|
||||
|
||||
if (
|
||||
window.navigator.userAgent.includes("ZoomWebKit") ||
|
||||
window.navigator.userAgent.includes("ZoomApps")
|
||||
) {
|
||||
window.DocSpaceConfig.editor = {
|
||||
openOnNewPage: false,
|
||||
requestClose: true,
|
||||
};
|
||||
}
|
||||
|
||||
//console.log({ DocSpaceConfig: window.DocSpaceConfig });
|
||||
})
|
||||
.catch((e) => {
|
||||
console.error(e);
|
||||
window.DocSpaceConfig = {
|
||||
errorOnLoad: e,
|
||||
};
|
||||
});
|
||||
`}
|
||||
</Script>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default Scripts;
|
@ -27,7 +27,7 @@
|
||||
import React from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
|
||||
import FilesSelectorWrapper from "@docspace/shared/selectors/Files/FilesSelector.wrapper";
|
||||
import FilesSelectorWrapper from "@docspace/shared/selectors/Files";
|
||||
|
||||
import { DeviceType, FilesSelectorFilterTypes } from "@docspace/shared/enums";
|
||||
|
||||
@ -42,7 +42,6 @@ const SelectFileDialog = ({
|
||||
onSubmit,
|
||||
fileInfo,
|
||||
filesSettings,
|
||||
i18n,
|
||||
}: SelectFileDialogProps) => {
|
||||
const { t } = useTranslation();
|
||||
|
||||
@ -79,7 +78,6 @@ const SelectFileDialog = ({
|
||||
return (
|
||||
<FilesSelectorWrapper
|
||||
filesSettings={filesSettings}
|
||||
i18nProp={i18n}
|
||||
withoutBackButton
|
||||
withSearch
|
||||
withBreadCrumbs
|
||||
@ -117,4 +115,3 @@ const SelectFileDialog = ({
|
||||
};
|
||||
|
||||
export default SelectFileDialog;
|
||||
|
||||
|
@ -29,7 +29,7 @@
|
||||
import React from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
|
||||
import FilesSelectorWrapper from "@docspace/shared/selectors/Files/FilesSelector.wrapper";
|
||||
import FilesSelectorWrapper from "@docspace/shared/selectors/Files";
|
||||
import { DeviceType } from "@docspace/shared/enums";
|
||||
|
||||
import { SelectFolderDialogProps } from "@/types";
|
||||
@ -44,16 +44,16 @@ const SelectFolderDialog = ({
|
||||
fileInfo,
|
||||
getIsDisabled,
|
||||
filesSettings,
|
||||
i18n,
|
||||
|
||||
fileSaveAsExtension,
|
||||
}: SelectFolderDialogProps) => {
|
||||
const { t } = useTranslation();
|
||||
const { t } = useTranslation(["Common", "Editor"]);
|
||||
const sessionPath = sessionStorage.getItem("filesSelectorPath");
|
||||
|
||||
const cancelButtonProps: TSelectorCancelButton = {
|
||||
withCancelButton: true,
|
||||
onCancel: onClose,
|
||||
cancelButtonLabel: t?.("Common:CancelButton") ?? "",
|
||||
cancelButtonLabel: t("Common:CancelButton"),
|
||||
cancelButtonId: "select-file-modal-cancel",
|
||||
};
|
||||
|
||||
@ -62,7 +62,6 @@ const SelectFolderDialog = ({
|
||||
|
||||
return (
|
||||
<FilesSelectorWrapper
|
||||
i18nProp={i18n}
|
||||
filesSettings={filesSettings}
|
||||
{...cancelButtonProps}
|
||||
withHeader
|
||||
@ -70,16 +69,16 @@ const SelectFolderDialog = ({
|
||||
withSearch
|
||||
withoutBackButton
|
||||
withCancelButton
|
||||
headerLabel={i18n.t?.("Common:SaveButton") ?? ""}
|
||||
headerLabel={t("Common:SaveButton")}
|
||||
disabledItems={[]}
|
||||
onSubmit={onSubmit}
|
||||
submitButtonLabel={i18n.t?.("Common:SaveHereButton") ?? ""}
|
||||
submitButtonLabel={t("Common:SaveHereButton")}
|
||||
submitButtonId="select-file-modal-submit"
|
||||
socketHelper={socketHelper}
|
||||
socketSubscribers={socketHelper.socketSubscribers}
|
||||
footerInputHeader={i18n.t?.("Editor:FileName") ?? ""}
|
||||
footerInputHeader={t("Editor:FileName")}
|
||||
currentFooterInputValue={titleSelectorFolder}
|
||||
footerCheckboxLabel={i18n.t?.("Editor:OpenSavedDocument") ?? ""}
|
||||
footerCheckboxLabel={t("Editor:OpenSavedDocument")}
|
||||
isPanelVisible={isVisible}
|
||||
isRoomsOnly={false}
|
||||
isThirdParty={false}
|
||||
@ -98,4 +97,3 @@ const SelectFolderDialog = ({
|
||||
};
|
||||
|
||||
export default SelectFolderDialog;
|
||||
|
||||
|
@ -26,15 +26,14 @@
|
||||
|
||||
import React from "react";
|
||||
import styled from "styled-components";
|
||||
import { i18n } from "i18next";
|
||||
import { useTranslation } from "react-i18next";
|
||||
|
||||
import Share from "@docspace/shared/components/share/Share.wrapper";
|
||||
import Share from "@docspace/shared/components/share";
|
||||
import { Backdrop } from "@docspace/shared/components/backdrop";
|
||||
import { Aside } from "@docspace/shared/components/aside";
|
||||
import { Text } from "@docspace/shared/components/text";
|
||||
import { NoUserSelect } from "@docspace/shared/utils/commonStyles";
|
||||
import { Base, TTheme } from "@docspace/shared/themes";
|
||||
import { Base } from "@docspace/shared/themes";
|
||||
import { TFile } from "@docspace/shared/api/files/types";
|
||||
|
||||
const StyledWrapper = styled.div`
|
||||
@ -66,16 +65,12 @@ type SharingDialogProps = {
|
||||
fileInfo: TFile;
|
||||
onCancel: () => void;
|
||||
isVisible: boolean;
|
||||
theme: TTheme;
|
||||
i18n: i18n;
|
||||
};
|
||||
|
||||
const SharingDialog = ({
|
||||
fileInfo,
|
||||
onCancel,
|
||||
isVisible,
|
||||
theme,
|
||||
i18n,
|
||||
}: SharingDialogProps) => {
|
||||
const { t } = useTranslation(["Common"]);
|
||||
|
||||
@ -85,17 +80,17 @@ const SharingDialog = ({
|
||||
onClick={onCancel}
|
||||
visible={isVisible}
|
||||
zIndex={310}
|
||||
isAside={true}
|
||||
isAside
|
||||
withoutBackground={false}
|
||||
withoutBlur={false}
|
||||
/>
|
||||
<Aside visible={isVisible} onClose={onCancel} withoutBodyScroll>
|
||||
<StyledWrapper theme={theme}>
|
||||
<StyledWrapper>
|
||||
<div className="share-file_header">
|
||||
<Text className="share-file_heading">{t("Common:Share")}</Text>
|
||||
</div>
|
||||
<div className="share-file_body">
|
||||
<Share infoPanelSelection={fileInfo} i18nProp={i18n} />
|
||||
<Share infoPanelSelection={fileInfo} />
|
||||
</div>
|
||||
</StyledWrapper>
|
||||
</Aside>
|
||||
@ -104,4 +99,3 @@ const SharingDialog = ({
|
||||
};
|
||||
|
||||
export default SharingDialog;
|
||||
|
||||
|
@ -36,11 +36,8 @@ export interface DeepLinkProps {
|
||||
logoUrls: TWhiteLabel[];
|
||||
userEmail?: string;
|
||||
|
||||
theme: TTheme;
|
||||
|
||||
currentDeviceType: DeviceType;
|
||||
deepLinkConfig?: TDeepLinkConfig;
|
||||
|
||||
setIsShowDeepLink: (value: boolean) => void;
|
||||
}
|
||||
|
||||
|
@ -27,6 +27,7 @@
|
||||
/* eslint-disable @next/next/no-img-element */
|
||||
import React, { useState } from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { useTheme } from "styled-components";
|
||||
|
||||
import { Text } from "@docspace/shared/components/text";
|
||||
import { Checkbox } from "@docspace/shared/components/checkbox";
|
||||
@ -38,7 +39,6 @@ import { getLogoFromPath } from "@docspace/shared/utils";
|
||||
import { DeviceType } from "@docspace/shared/enums";
|
||||
|
||||
import { getDeepLink } from "./DeepLink.helper";
|
||||
|
||||
import {
|
||||
StyledSimpleNav,
|
||||
StyledDeepLink,
|
||||
@ -55,12 +55,13 @@ const DeepLink = ({
|
||||
fileInfo,
|
||||
userEmail,
|
||||
setIsShowDeepLink,
|
||||
theme,
|
||||
|
||||
logoUrls,
|
||||
currentDeviceType,
|
||||
deepLinkConfig,
|
||||
}: DeepLinkProps) => {
|
||||
const { t } = useTranslation(["DeepLink", "Common"]);
|
||||
const theme = useTheme();
|
||||
|
||||
const [isRemember, setIsRemember] = useState(false);
|
||||
const onChangeCheckbox = () => {
|
||||
@ -104,13 +105,13 @@ const DeepLink = ({
|
||||
|
||||
if (currentDeviceType === DeviceType.mobile) {
|
||||
return (
|
||||
<StyledSimpleNav theme={theme}>
|
||||
<StyledSimpleNav>
|
||||
<img src={logo} alt="" />
|
||||
</StyledSimpleNav>
|
||||
);
|
||||
} else {
|
||||
return (
|
||||
<LogoWrapper theme={theme}>
|
||||
<LogoWrapper>
|
||||
<img src={logo} alt="docspace-logo" />
|
||||
</LogoWrapper>
|
||||
);
|
||||
@ -128,7 +129,7 @@ const DeepLink = ({
|
||||
<StyledDeepLink>
|
||||
<StyledBodyWrapper>
|
||||
<Text className="title">{t("DeepLink:OpeningDocument")}</Text>
|
||||
<StyledFileTile theme={theme}>
|
||||
<StyledFileTile>
|
||||
<img src={getFileIcon()} alt="docspace-logo" />
|
||||
<Text fontSize="14px" fontWeight="600" truncate>
|
||||
{getFileTitle()}
|
||||
@ -168,4 +169,3 @@ const DeepLink = ({
|
||||
};
|
||||
|
||||
export default DeepLink;
|
||||
|
||||
|
@ -127,7 +127,7 @@ const useEditorEvents = ({
|
||||
winEditor?.close();
|
||||
docEditor?.showMessage?.(
|
||||
(e as { message?: string })?.message ??
|
||||
t?.("ErrorConnectionLost") ??
|
||||
t("ErrorConnectionLost") ??
|
||||
"",
|
||||
);
|
||||
}
|
||||
@ -232,17 +232,17 @@ const useEditorEvents = ({
|
||||
? "xlsx"
|
||||
: "docxf";
|
||||
|
||||
let fileName = t?.("Common:NewDocument");
|
||||
let fileName = t("Common:NewDocument");
|
||||
|
||||
switch (fileExt) {
|
||||
case "xlsx":
|
||||
fileName = t?.("Common:NewSpreadsheet");
|
||||
fileName = t("Common:NewSpreadsheet");
|
||||
break;
|
||||
case "pptx":
|
||||
fileName = t?.("Common:NewPresentation");
|
||||
fileName = t("Common:NewPresentation");
|
||||
break;
|
||||
case "docxf":
|
||||
fileName = t?.("Common:NewMasterForm");
|
||||
fileName = t("Common:NewMasterForm");
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
@ -464,8 +464,7 @@ const useEditorEvents = ({
|
||||
});
|
||||
} catch (e) {
|
||||
docEditor?.showMessage?.(
|
||||
((e as { message?: string })?.message ||
|
||||
t?.("ErrorConnectionLost")) ??
|
||||
((e as { message?: string })?.message || t("ErrorConnectionLost")) ??
|
||||
"",
|
||||
);
|
||||
}
|
||||
|
@ -28,14 +28,14 @@ import React from "react";
|
||||
|
||||
import { combineUrl } from "@docspace/shared/utils/combineUrl";
|
||||
import { frameCallCommand } from "@docspace/shared/utils/common";
|
||||
import { Nullable, TTranslation } from "@docspace/shared/types";
|
||||
import { TTranslation } from "@docspace/shared/types";
|
||||
|
||||
import { TError } from "@/types";
|
||||
|
||||
interface UseErrorProps {
|
||||
error?: TError;
|
||||
editorUrl?: string;
|
||||
t?: Nullable<TTranslation>;
|
||||
t: TTranslation;
|
||||
}
|
||||
|
||||
const useError = ({ error, editorUrl, t }: UseErrorProps) => {
|
||||
@ -69,23 +69,15 @@ const useError = ({ error, editorUrl, t }: UseErrorProps) => {
|
||||
}
|
||||
}, [editorUrl, error]);
|
||||
|
||||
const onError = React.useCallback(() => {
|
||||
// window.open(
|
||||
// combineUrl(window.DocSpaceConfig?.proxy?.url, "/login"),
|
||||
// "_self",
|
||||
// );
|
||||
}, []);
|
||||
|
||||
const getErrorMessage = React.useCallback(() => {
|
||||
if (typeof error !== "string") return error?.message;
|
||||
|
||||
if (error === "restore-backup") return t?.("Common:PreparationPortalTitle");
|
||||
if (error === "restore-backup") return t("Common:PreparationPortalTitle");
|
||||
|
||||
return error;
|
||||
}, [error, t]);
|
||||
|
||||
return { onError, getErrorMessage };
|
||||
return { getErrorMessage };
|
||||
};
|
||||
|
||||
export default useError;
|
||||
|
||||
|
@ -37,7 +37,10 @@ interface UseI18NProps {
|
||||
}
|
||||
|
||||
const useI18N = ({ settings, user }: UseI18NProps) => {
|
||||
const [i18n, setI18N] = React.useState<i18n>({} as i18n);
|
||||
const [i18n, setI18N] = React.useState<i18n>(
|
||||
getI18NInstance(user?.cultureName ?? "en", settings?.culture ?? "en") ??
|
||||
({} as i18n),
|
||||
);
|
||||
|
||||
const isInit = React.useRef(false);
|
||||
|
||||
@ -61,4 +64,3 @@ const useI18N = ({ settings, user }: UseI18NProps) => {
|
||||
};
|
||||
|
||||
export default useI18N;
|
||||
|
||||
|
@ -44,9 +44,16 @@ const useTheme = ({ user, i18n }: UseThemeProps) => {
|
||||
const [currentColorTheme, setCurrentColorTheme] =
|
||||
React.useState<TColorScheme>({} as TColorScheme);
|
||||
|
||||
const [theme, setTheme] = React.useState<TTheme>({
|
||||
...Base,
|
||||
currentColorScheme: currentColorTheme,
|
||||
const [theme, setTheme] = React.useState<TTheme>(() => {
|
||||
if (user?.theme === ThemeKeys.DarkStr)
|
||||
return {
|
||||
...Dark,
|
||||
currentColorScheme: currentColorTheme,
|
||||
};
|
||||
return {
|
||||
...Base,
|
||||
currentColorScheme: currentColorTheme,
|
||||
};
|
||||
});
|
||||
|
||||
const isRequestRunning = React.useRef(false);
|
||||
|
68
packages/doceditor/src/providers/ErrorProvider.tsx
Normal file
68
packages/doceditor/src/providers/ErrorProvider.tsx
Normal file
@ -0,0 +1,68 @@
|
||||
// (c) Copyright Ascensio System SIA 2009-2024
|
||||
//
|
||||
// This program is a free software product.
|
||||
// You can redistribute it and/or modify it under the terms
|
||||
// of the GNU Affero General Public License (AGPL) version 3 as published by the Free Software
|
||||
// Foundation. In accordance with Section 7(a) of the GNU AGPL its Section 15 shall be amended
|
||||
// to the effect that Ascensio System SIA expressly excludes the warranty of non-infringement of
|
||||
// any third-party rights.
|
||||
//
|
||||
// This program is distributed WITHOUT ANY WARRANTY, without even the implied warranty
|
||||
// of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. For details, see
|
||||
// the GNU AGPL at: http://www.gnu.org/licenses/agpl-3.0.html
|
||||
//
|
||||
// You can contact Ascensio System SIA at Lubanas st. 125a-25, Riga, Latvia, EU, LV-1021.
|
||||
//
|
||||
// The interactive user interfaces in modified source and object code versions of the Program must
|
||||
// display Appropriate Legal Notices, as required under Section 5 of the GNU AGPL version 3.
|
||||
//
|
||||
// Pursuant to Section 7(b) of the License you must retain the original Product logo when
|
||||
// distributing the program. Pursuant to Section 7(e) we decline to grant you any rights under
|
||||
// trademark law for use of our trademarks.
|
||||
//
|
||||
// All the Product's GUI elements, including illustrations and icon sets, as well as technical writing
|
||||
// content are licensed under the terms of the Creative Commons Attribution-ShareAlike 4.0
|
||||
// International. See the License terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode
|
||||
|
||||
"use client";
|
||||
|
||||
import React from "react";
|
||||
|
||||
import ErrorBoundary from "@docspace/shared/components/error-boundary/ErrorBoundary";
|
||||
import { TUser } from "@docspace/shared/api/people/types";
|
||||
import {
|
||||
TSettings,
|
||||
TFirebaseSettings,
|
||||
} from "@docspace/shared/api/settings/types";
|
||||
import FirebaseHelper from "@docspace/shared/utils/firebase";
|
||||
|
||||
import pkgFile from "../../package.json";
|
||||
import useDeviceType from "@/hooks/useDeviceType";
|
||||
import useWhiteLabel from "@/hooks/useWhiteLabel";
|
||||
|
||||
type TErrorProvider = {
|
||||
user: TUser | undefined;
|
||||
settings: TSettings | undefined;
|
||||
children: React.ReactNode;
|
||||
};
|
||||
|
||||
const ErrorProvider = ({ children, user, settings }: TErrorProvider) => {
|
||||
const firebaseHelper = new FirebaseHelper(
|
||||
settings?.firebase ?? ({} as TFirebaseSettings),
|
||||
);
|
||||
const { currentDeviceType } = useDeviceType();
|
||||
const { logoUrls } = useWhiteLabel();
|
||||
return (
|
||||
<ErrorBoundary
|
||||
user={user ?? ({} as TUser)}
|
||||
version={pkgFile.version}
|
||||
firebaseHelper={firebaseHelper}
|
||||
currentDeviceType={currentDeviceType}
|
||||
whiteLabelLogoUrls={logoUrls}
|
||||
>
|
||||
{children}
|
||||
</ErrorBoundary>
|
||||
);
|
||||
};
|
||||
|
||||
export default ErrorProvider;
|
@ -24,48 +24,36 @@
|
||||
// content are licensed under the terms of the Creative Commons Attribution-ShareAlike 4.0
|
||||
// International. See the License terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode
|
||||
|
||||
import CreateFileError from "@/components/CreateFileError";
|
||||
import { getErrorData } from "@/utils/actions";
|
||||
"use client";
|
||||
|
||||
type TSearchParams = {
|
||||
error?: string;
|
||||
fileInfo?: string;
|
||||
createFile?: string;
|
||||
fromFile?: string;
|
||||
fromTemplate?: string;
|
||||
import React from "react";
|
||||
|
||||
import { ThemeProvider as ComponentThemeProvider } from "@docspace/shared/components/theme-provider";
|
||||
import { TUser } from "@docspace/shared/api/people/types";
|
||||
import { TSettings } from "@docspace/shared/api/settings/types";
|
||||
|
||||
import useTheme from "@/hooks/useTheme";
|
||||
import useI18N from "@/hooks/useI18N";
|
||||
|
||||
type TThemeProvider = {
|
||||
children: React.ReactNode;
|
||||
settings: TSettings | undefined;
|
||||
user: TUser | undefined;
|
||||
};
|
||||
|
||||
async function Page({ searchParams }: { searchParams: TSearchParams }) {
|
||||
const error = searchParams.error ? JSON.parse(searchParams.error) : "";
|
||||
const fileInfo = searchParams.fileInfo
|
||||
? JSON.parse(searchParams.fileInfo)
|
||||
: "";
|
||||
const fromTemplate = searchParams.fromTemplate
|
||||
? JSON.parse(searchParams.fromTemplate)
|
||||
: "";
|
||||
const fromFile = searchParams.fromFile
|
||||
? JSON.parse(searchParams.fromFile)
|
||||
: "";
|
||||
const ThemeProvider = ({ children, user, settings }: TThemeProvider) => {
|
||||
const { i18n } = useI18N({ settings, user });
|
||||
|
||||
console.log("searchParams here", searchParams);
|
||||
const { theme, currentColorTheme } = useTheme({ user, i18n });
|
||||
|
||||
if (searchParams.createFile) {
|
||||
const { settings, user } = await getErrorData();
|
||||
|
||||
return (
|
||||
<CreateFileError
|
||||
error={error}
|
||||
fileInfo={fileInfo}
|
||||
fromFile={!!fromFile}
|
||||
fromTemplate={!!fromTemplate}
|
||||
settings={settings}
|
||||
user={user}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
return <div></div>;
|
||||
}
|
||||
|
||||
export default Page;
|
||||
return (
|
||||
<ComponentThemeProvider
|
||||
theme={theme}
|
||||
currentColorScheme={currentColorTheme}
|
||||
>
|
||||
{children}
|
||||
</ComponentThemeProvider>
|
||||
);
|
||||
};
|
||||
|
||||
export default ThemeProvider;
|
53
packages/doceditor/src/providers/TranslationProvider.tsx
Normal file
53
packages/doceditor/src/providers/TranslationProvider.tsx
Normal file
@ -0,0 +1,53 @@
|
||||
// (c) Copyright Ascensio System SIA 2009-2024
|
||||
//
|
||||
// This program is a free software product.
|
||||
// You can redistribute it and/or modify it under the terms
|
||||
// of the GNU Affero General Public License (AGPL) version 3 as published by the Free Software
|
||||
// Foundation. In accordance with Section 7(a) of the GNU AGPL its Section 15 shall be amended
|
||||
// to the effect that Ascensio System SIA expressly excludes the warranty of non-infringement of
|
||||
// any third-party rights.
|
||||
//
|
||||
// This program is distributed WITHOUT ANY WARRANTY, without even the implied warranty
|
||||
// of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. For details, see
|
||||
// the GNU AGPL at: http://www.gnu.org/licenses/agpl-3.0.html
|
||||
//
|
||||
// You can contact Ascensio System SIA at Lubanas st. 125a-25, Riga, Latvia, EU, LV-1021.
|
||||
//
|
||||
// The interactive user interfaces in modified source and object code versions of the Program must
|
||||
// display Appropriate Legal Notices, as required under Section 5 of the GNU AGPL version 3.
|
||||
//
|
||||
// Pursuant to Section 7(b) of the License you must retain the original Product logo when
|
||||
// distributing the program. Pursuant to Section 7(e) we decline to grant you any rights under
|
||||
// trademark law for use of our trademarks.
|
||||
//
|
||||
// All the Product's GUI elements, including illustrations and icon sets, as well as technical writing
|
||||
// content are licensed under the terms of the Creative Commons Attribution-ShareAlike 4.0
|
||||
// International. See the License terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode
|
||||
|
||||
"use client";
|
||||
|
||||
import React from "react";
|
||||
import { I18nextProvider } from "react-i18next";
|
||||
|
||||
import { TUser } from "@docspace/shared/api/people/types";
|
||||
import { TSettings } from "@docspace/shared/api/settings/types";
|
||||
|
||||
import useI18N from "@/hooks/useI18N";
|
||||
|
||||
type TTranslationProvider = {
|
||||
children: React.ReactNode;
|
||||
settings: TSettings | undefined;
|
||||
user: TUser | undefined;
|
||||
};
|
||||
|
||||
const TranslationProvider = ({
|
||||
children,
|
||||
settings,
|
||||
user,
|
||||
}: TTranslationProvider) => {
|
||||
const { i18n } = useI18N({ settings, user });
|
||||
|
||||
return <I18nextProvider i18n={i18n}>{children}</I18nextProvider>;
|
||||
};
|
||||
|
||||
export default TranslationProvider;
|
58
packages/doceditor/src/providers/index.tsx
Normal file
58
packages/doceditor/src/providers/index.tsx
Normal file
@ -0,0 +1,58 @@
|
||||
// (c) Copyright Ascensio System SIA 2009-2024
|
||||
//
|
||||
// This program is a free software product.
|
||||
// You can redistribute it and/or modify it under the terms
|
||||
// of the GNU Affero General Public License (AGPL) version 3 as published by the Free Software
|
||||
// Foundation. In accordance with Section 7(a) of the GNU AGPL its Section 15 shall be amended
|
||||
// to the effect that Ascensio System SIA expressly excludes the warranty of non-infringement of
|
||||
// any third-party rights.
|
||||
//
|
||||
// This program is distributed WITHOUT ANY WARRANTY, without even the implied warranty
|
||||
// of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. For details, see
|
||||
// the GNU AGPL at: http://www.gnu.org/licenses/agpl-3.0.html
|
||||
//
|
||||
// You can contact Ascensio System SIA at Lubanas st. 125a-25, Riga, Latvia, EU, LV-1021.
|
||||
//
|
||||
// The interactive user interfaces in modified source and object code versions of the Program must
|
||||
// display Appropriate Legal Notices, as required under Section 5 of the GNU AGPL version 3.
|
||||
//
|
||||
// Pursuant to Section 7(b) of the License you must retain the original Product logo when
|
||||
// distributing the program. Pursuant to Section 7(e) we decline to grant you any rights under
|
||||
// trademark law for use of our trademarks.
|
||||
//
|
||||
// All the Product's GUI elements, including illustrations and icon sets, as well as technical writing
|
||||
// content are licensed under the terms of the Creative Commons Attribution-ShareAlike 4.0
|
||||
// International. See the License terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode
|
||||
|
||||
import { TUser } from "@docspace/shared/api/people/types";
|
||||
import { TSettings } from "@docspace/shared/api/settings/types";
|
||||
import { Toast } from "@docspace/shared/components/toast/Toast";
|
||||
|
||||
import ThemeProvider from "./ThemeProvider";
|
||||
import TranslationProvider from "./TranslationProvider";
|
||||
import ErrorProvider from "./ErrorProvider";
|
||||
|
||||
export type TContextData = {
|
||||
user: TUser | undefined;
|
||||
settings: TSettings | undefined;
|
||||
};
|
||||
|
||||
export type TProviders = {
|
||||
children: React.ReactNode;
|
||||
contextData: TContextData;
|
||||
};
|
||||
|
||||
const Providers = ({ children, contextData }: TProviders) => {
|
||||
return (
|
||||
<TranslationProvider {...contextData}>
|
||||
<ThemeProvider {...contextData}>
|
||||
<ErrorProvider {...contextData}>
|
||||
{children}
|
||||
<Toast isSSR />
|
||||
</ErrorProvider>
|
||||
</ThemeProvider>
|
||||
</TranslationProvider>
|
||||
);
|
||||
};
|
||||
|
||||
export default Providers;
|
@ -56,4 +56,3 @@ body {
|
||||
body.loading * {
|
||||
cursor: wait !important;
|
||||
}
|
||||
|
||||
|
@ -42,8 +42,7 @@ import { TSelectedFileInfo } from "@docspace/shared/selectors/Files/FilesSelecto
|
||||
import SocketIOHelper from "@docspace/shared/utils/socket";
|
||||
import { FilesSelectorFilterTypes } from "@docspace/shared/enums";
|
||||
import { TRoomSecurity } from "@docspace/shared/api/rooms/types";
|
||||
import { Nullable, TTranslation } from "@docspace/shared/types";
|
||||
import { i18n } from "i18next";
|
||||
import { TTranslation } from "@docspace/shared/types";
|
||||
|
||||
export type TGoBack = {
|
||||
requestClose: boolean;
|
||||
@ -172,14 +171,15 @@ export type TError = {
|
||||
message: "unauthorized" | "restore-backup" | string;
|
||||
status?: "not-found" | "access-denied" | number | string;
|
||||
type?: string;
|
||||
editorUrl?: string;
|
||||
};
|
||||
|
||||
export type TResponse =
|
||||
| {
|
||||
config: IInitialConfig;
|
||||
editorUrl: TDocServiceLocation;
|
||||
user: TUser;
|
||||
settings: TSettings;
|
||||
|
||||
user?: TUser;
|
||||
settings?: TSettings;
|
||||
successAuth: boolean;
|
||||
isSharingAccess: boolean;
|
||||
error?: TError;
|
||||
@ -190,7 +190,7 @@ export type TResponse =
|
||||
| {
|
||||
error: TError;
|
||||
config?: undefined;
|
||||
editorUrl?: undefined;
|
||||
|
||||
user?: undefined;
|
||||
settings?: undefined;
|
||||
successAuth?: undefined;
|
||||
@ -204,13 +204,12 @@ export type EditorProps = {
|
||||
config?: IInitialConfig;
|
||||
successAuth?: boolean;
|
||||
user?: TUser;
|
||||
view?: boolean;
|
||||
doc?: string;
|
||||
documentserverUrl: string;
|
||||
fileInfo?: TFile;
|
||||
isSharingAccess?: boolean;
|
||||
errorMessage?: string;
|
||||
t: TTranslation | null;
|
||||
|
||||
onSDKRequestSharingSettings: () => void;
|
||||
onSDKRequestSaveAs: (event: object) => void;
|
||||
onSDKRequestInsertImage: (event: object) => void;
|
||||
@ -273,7 +272,6 @@ export interface SelectFolderDialogProps {
|
||||
) => Promise<void>;
|
||||
fileInfo: TFile;
|
||||
filesSettings: TFilesSettings;
|
||||
i18n: i18n;
|
||||
fileSaveAsExtension?: string;
|
||||
}
|
||||
|
||||
@ -310,7 +308,6 @@ export interface SelectFileDialogProps {
|
||||
) => Promise<void>;
|
||||
fileInfo: TFile;
|
||||
filesSettings: TFilesSettings;
|
||||
i18n: i18n;
|
||||
}
|
||||
|
||||
export interface UseSocketHelperProps {
|
||||
@ -324,7 +321,7 @@ export interface UseEventsProps {
|
||||
config?: IInitialConfig;
|
||||
doc?: string;
|
||||
errorMessage?: string;
|
||||
t?: Nullable<TTranslation>;
|
||||
t: TTranslation;
|
||||
}
|
||||
|
||||
export interface UseInitProps {
|
||||
@ -332,7 +329,7 @@ export interface UseInitProps {
|
||||
successAuth?: boolean;
|
||||
fileInfo?: TFile;
|
||||
user?: TUser;
|
||||
t: Nullable<TTranslation>;
|
||||
t: TTranslation;
|
||||
|
||||
setDocTitle: (value: string) => void;
|
||||
documentReady: boolean;
|
||||
|
@ -28,78 +28,35 @@
|
||||
|
||||
import { headers } from "next/headers";
|
||||
|
||||
import { TenantStatus, EditorConfigErrorType } from "@docspace/shared/enums";
|
||||
import {
|
||||
createRequest,
|
||||
getBaseUrl,
|
||||
} from "@docspace/shared/utils/next-ssr-helper";
|
||||
import type { TDocServiceLocation } from "@docspace/shared/api/files/types";
|
||||
import { TenantStatus, EditorConfigErrorType } from "@docspace/shared/enums";
|
||||
import type {
|
||||
TDocServiceLocation,
|
||||
TFile,
|
||||
} from "@docspace/shared/api/files/types";
|
||||
import { TUser } from "@docspace/shared/api/people/types";
|
||||
import { TSettings } from "@docspace/shared/api/settings/types";
|
||||
|
||||
import type { IInitialConfig, TCatchError, TError, TResponse } from "@/types";
|
||||
|
||||
import { REPLACED_URL_PATH } from "./constants";
|
||||
|
||||
import { isTemplateFile } from ".";
|
||||
|
||||
export async function getErrorData() {
|
||||
const hdrs = headers();
|
||||
const cookie = hdrs.get("cookie");
|
||||
|
||||
const [getSettings, getUser] = createRequest(
|
||||
[
|
||||
`/settings?withPassword=${cookie?.includes("asc_auth_key") ? "false" : "true"}`,
|
||||
`/people/@self`,
|
||||
],
|
||||
[["", ""]],
|
||||
"GET",
|
||||
);
|
||||
|
||||
const resActions = [];
|
||||
|
||||
resActions.push(fetch(getSettings));
|
||||
resActions.push(fetch(getUser));
|
||||
|
||||
const [settingsRes, userRes] = await Promise.all(resActions);
|
||||
|
||||
const actions = [];
|
||||
|
||||
actions.push(settingsRes.json());
|
||||
if (userRes.status !== 401) actions.push(userRes.json());
|
||||
|
||||
const [settings, user] = await Promise.all(actions);
|
||||
|
||||
return { settings: settings.response, user: user?.response };
|
||||
}
|
||||
|
||||
const processFillFormDraft = async (
|
||||
config: IInitialConfig,
|
||||
searchParams: URLSearchParams,
|
||||
editorSearchParams: URLSearchParams,
|
||||
|
||||
share?: string,
|
||||
): Promise<
|
||||
| [
|
||||
string,
|
||||
IInitialConfig,
|
||||
TDocServiceLocation | undefined,
|
||||
string | undefined,
|
||||
]
|
||||
| void
|
||||
> => {
|
||||
): Promise<[string, IInitialConfig | TError, string | undefined] | void> => {
|
||||
const templateFileId = config.file.id;
|
||||
|
||||
const [checkFillFormDraft] = createRequest(
|
||||
[`/files/masterform/${templateFileId}/checkfillformdraft`],
|
||||
[
|
||||
share ? ["Request-Token", share] : ["", ""],
|
||||
["Content-Type", "application/json;charset=utf-8"],
|
||||
],
|
||||
"POST",
|
||||
JSON.stringify({ fileId: templateFileId }),
|
||||
);
|
||||
const formUrl = await checkFillFromDraft(templateFileId, share);
|
||||
|
||||
const response = await fetch(checkFillFormDraft);
|
||||
|
||||
if (!response.ok) return;
|
||||
|
||||
const { response: formUrl } = await response.json();
|
||||
if (!formUrl) return;
|
||||
|
||||
const basePath = getBaseUrl();
|
||||
const url = new URL(basePath + formUrl);
|
||||
@ -116,45 +73,13 @@ const processFillFormDraft = async (
|
||||
...Object.fromEntries(url.searchParams),
|
||||
});
|
||||
|
||||
const editorVersion = editorSearchParams.get("version");
|
||||
|
||||
const queries = [
|
||||
`/files/file/${queryFileId}/openedit?${combinedSearchParams.toString()}`,
|
||||
const actions: [Promise<IInitialConfig | TError>] = [
|
||||
openEdit(queryFileId, combinedSearchParams.toString(), share),
|
||||
];
|
||||
|
||||
if (queryVersion && queryVersion !== editorVersion) {
|
||||
editorSearchParams.set("version", queryVersion);
|
||||
queries.push(`/files/docservice?${editorSearchParams.toString()}`);
|
||||
}
|
||||
const [newConfig] = await Promise.all(actions);
|
||||
|
||||
const [getConfig, getEditorUrl] = createRequest(
|
||||
queries,
|
||||
[share ? ["Request-Token", share] : ["", ""]],
|
||||
"GET",
|
||||
);
|
||||
|
||||
const resActions = [];
|
||||
|
||||
resActions.push(fetch(getConfig));
|
||||
getEditorUrl && resActions.push(fetch(getEditorUrl));
|
||||
|
||||
const [configRes, editorUrlRes] = await Promise.all(resActions);
|
||||
|
||||
if (!configRes.ok) return;
|
||||
|
||||
const actions = [];
|
||||
|
||||
actions.push(configRes.json());
|
||||
editorUrlRes && actions.push(editorUrlRes.json());
|
||||
|
||||
const [newConfig, newEditorUrl] = await Promise.all(actions);
|
||||
|
||||
return [
|
||||
queryFileId,
|
||||
newConfig.response,
|
||||
newEditorUrl?.response,
|
||||
url.hash ?? "",
|
||||
];
|
||||
return [queryFileId, newConfig, url.hash ?? ""];
|
||||
};
|
||||
|
||||
export async function fileCopyAs(
|
||||
@ -163,7 +88,13 @@ export async function fileCopyAs(
|
||||
destFolderId: string,
|
||||
enableExternalExt?: boolean,
|
||||
password?: string,
|
||||
) {
|
||||
): Promise<{
|
||||
file: TFile | undefined;
|
||||
error:
|
||||
| string
|
||||
| { message: string; status: number; type: string; stack: string }
|
||||
| undefined;
|
||||
}> {
|
||||
try {
|
||||
const [createFile] = createRequest(
|
||||
[`/files/file/${fileId}/copyas`],
|
||||
@ -216,7 +147,13 @@ export async function createFile(
|
||||
title: string,
|
||||
templateId?: string,
|
||||
formId?: string,
|
||||
) {
|
||||
): Promise<{
|
||||
file: TFile | undefined;
|
||||
error:
|
||||
| string
|
||||
| { message: string; status: number; type: string; stack: string }
|
||||
| undefined;
|
||||
}> {
|
||||
try {
|
||||
const [createFile] = createRequest(
|
||||
[`/files/${parentId}/file`],
|
||||
@ -258,7 +195,7 @@ export async function createFile(
|
||||
}
|
||||
|
||||
export async function getData(
|
||||
fileId?: string,
|
||||
fileId: string,
|
||||
version?: string,
|
||||
doc?: string,
|
||||
view?: boolean,
|
||||
@ -268,56 +205,28 @@ export async function getData(
|
||||
try {
|
||||
const hdrs = headers();
|
||||
|
||||
const cookie = hdrs.get("cookie");
|
||||
|
||||
const searchParams = new URLSearchParams();
|
||||
const editorSearchParams = new URLSearchParams();
|
||||
|
||||
if (view) searchParams.append("view", view ? "true" : "false");
|
||||
if (version) {
|
||||
searchParams.append("version", version);
|
||||
editorSearchParams.append("version", version);
|
||||
}
|
||||
if (doc) searchParams.append("doc", doc);
|
||||
if (share) searchParams.append("share", share);
|
||||
if (editorType) searchParams.append("editorType", editorType);
|
||||
|
||||
const [getConfig, getEditorUrl, getSettings, getUser] = createRequest(
|
||||
[
|
||||
`/files/file/${fileId}/openedit?${searchParams.toString()}`,
|
||||
`/files/docservice?${editorSearchParams.toString()}`,
|
||||
`/settings?withPassword=${cookie?.includes("asc_auth_key") ? "false" : "true"}`,
|
||||
`/people/@self`,
|
||||
],
|
||||
[share ? ["Request-Token", share] : ["", ""]],
|
||||
"GET",
|
||||
);
|
||||
const [config, user, settings] = await Promise.all([
|
||||
openEdit(fileId, searchParams.toString(), share),
|
||||
|
||||
const resActions = [];
|
||||
getUser(share),
|
||||
getSettings(share),
|
||||
]);
|
||||
|
||||
resActions.push(fetch(getConfig));
|
||||
resActions.push(fetch(getEditorUrl));
|
||||
resActions.push(fetch(getSettings));
|
||||
resActions.push(fetch(getUser));
|
||||
|
||||
const [configRes, editorUrlRes, settingsRes, userRes] =
|
||||
await Promise.all(resActions);
|
||||
|
||||
const actions = [];
|
||||
|
||||
actions.push(configRes.json());
|
||||
actions.push(editorUrlRes.json());
|
||||
actions.push(settingsRes.json());
|
||||
if (userRes.status !== 401) actions.push(userRes.json());
|
||||
|
||||
const [config, editorUrl, settings, user] = await Promise.all(actions);
|
||||
|
||||
if (configRes.ok) {
|
||||
if ("token" in config) {
|
||||
const response: TResponse = {
|
||||
config: config.response,
|
||||
editorUrl: editorUrl.response,
|
||||
user: user?.response,
|
||||
settings: settings.response,
|
||||
config,
|
||||
user,
|
||||
settings,
|
||||
successAuth: false,
|
||||
isSharingAccess: false,
|
||||
doc,
|
||||
@ -328,21 +237,20 @@ export async function getData(
|
||||
const result = await processFillFormDraft(
|
||||
response.config,
|
||||
searchParams,
|
||||
editorSearchParams,
|
||||
share,
|
||||
);
|
||||
|
||||
if (result) {
|
||||
const [newFileId, newConfig, newEditorUrl, hash] = result;
|
||||
const [newFileId, newConfig, hash] = result;
|
||||
|
||||
response.fileId = newFileId;
|
||||
response.config = newConfig;
|
||||
if (newEditorUrl) response.editorUrl = newEditorUrl;
|
||||
response.config = newConfig as IInitialConfig;
|
||||
|
||||
if (hash) response.hash = hash;
|
||||
}
|
||||
}
|
||||
|
||||
if (response.settings.tenantStatus === TenantStatus.PortalRestore) {
|
||||
if (response.settings?.tenantStatus === TenantStatus.PortalRestore) {
|
||||
response.error = { message: "restore-backup" };
|
||||
}
|
||||
|
||||
@ -364,38 +272,21 @@ export async function getData(
|
||||
return response;
|
||||
}
|
||||
|
||||
console.log("initDocEditor failed", config.error);
|
||||
|
||||
const status =
|
||||
config.error.type === EditorConfigErrorType.NotFoundScope
|
||||
? "not-found"
|
||||
: config.error.type === EditorConfigErrorType.AccessDeniedScope
|
||||
? "access-denied"
|
||||
: configRes.status === 415
|
||||
? "not-supported"
|
||||
: undefined;
|
||||
|
||||
const message = status ? config.error.message : undefined;
|
||||
console.log("initDocEditor failed", config);
|
||||
|
||||
const response: TResponse = {
|
||||
error:
|
||||
user || share
|
||||
? config.error.type === EditorConfigErrorType.LinkScope
|
||||
? { message: message ?? "unauthorized", status }
|
||||
: { ...config.error, status }
|
||||
: { message: message ?? "unauthorized", status },
|
||||
user: user?.response,
|
||||
settings: settings?.response,
|
||||
error: config,
|
||||
|
||||
fileId,
|
||||
editorUrl: editorUrl.response,
|
||||
};
|
||||
|
||||
return response;
|
||||
} catch (e) {
|
||||
console.log(e);
|
||||
const err = e as TCatchError;
|
||||
console.error("initDocEditor failed", err);
|
||||
|
||||
const editorUrl = (await getEditorUrl("", share)).docServiceUrl;
|
||||
|
||||
let message = "";
|
||||
if (typeof err === "string") message = err;
|
||||
else
|
||||
@ -414,7 +305,143 @@ export async function getData(
|
||||
const error: TError = {
|
||||
message,
|
||||
status,
|
||||
editorUrl,
|
||||
};
|
||||
return { error };
|
||||
}
|
||||
}
|
||||
|
||||
export async function getUser(share?: string) {
|
||||
const hdrs = headers();
|
||||
const cookie = hdrs.get("cookie");
|
||||
|
||||
const [getUser] = createRequest(
|
||||
[`/people/@self`],
|
||||
[share ? ["Request-Token", share] : ["", ""]],
|
||||
"GET",
|
||||
);
|
||||
|
||||
if (!cookie?.includes("asc_auth_key")) return undefined;
|
||||
const userRes = await fetch(getUser);
|
||||
|
||||
if (userRes.status === 401) return undefined;
|
||||
|
||||
const user = await userRes.json();
|
||||
|
||||
return user.response as TUser;
|
||||
}
|
||||
|
||||
export async function getSettings(share?: string) {
|
||||
const hdrs = headers();
|
||||
const cookie = hdrs.get("cookie");
|
||||
|
||||
const [getSettings] = createRequest(
|
||||
[
|
||||
`/settings?withPassword=${cookie?.includes("asc_auth_key") ? "false" : "true"}`,
|
||||
],
|
||||
[share ? ["Request-Token", share] : ["", ""]],
|
||||
"GET",
|
||||
);
|
||||
|
||||
const resActions = [];
|
||||
|
||||
resActions.push(fetch(getSettings));
|
||||
|
||||
const [settingsRes] = await Promise.all(resActions);
|
||||
|
||||
const actions = [];
|
||||
|
||||
actions.push(settingsRes.json());
|
||||
|
||||
const [settings] = await Promise.all(actions);
|
||||
|
||||
return settings.response as TSettings;
|
||||
}
|
||||
|
||||
export async function checkFillFromDraft(
|
||||
templateFileId: number,
|
||||
share?: string,
|
||||
) {
|
||||
const [checkFillFormDraft] = createRequest(
|
||||
[`/files/masterform/${templateFileId}/checkfillformdraft`],
|
||||
[
|
||||
share ? ["Request-Token", share] : ["", ""],
|
||||
["Content-Type", "application/json;charset=utf-8"],
|
||||
],
|
||||
"POST",
|
||||
JSON.stringify({ fileId: templateFileId }),
|
||||
);
|
||||
|
||||
const response = await fetch(checkFillFormDraft);
|
||||
|
||||
if (!response.ok) return null;
|
||||
|
||||
const { response: formUrl } = await response.json();
|
||||
|
||||
return formUrl as string;
|
||||
}
|
||||
|
||||
export async function openEdit(
|
||||
fileId: number | string,
|
||||
searchParams: string,
|
||||
share?: string,
|
||||
) {
|
||||
const hdrs = headers();
|
||||
const cookie = hdrs.get("cookie");
|
||||
|
||||
const [getConfig] = createRequest(
|
||||
[`/files/file/${fileId}/openedit?${searchParams}`],
|
||||
[share ? ["Request-Token", share] : ["", ""]],
|
||||
"GET",
|
||||
);
|
||||
|
||||
const res = await fetch(getConfig);
|
||||
|
||||
const config = await res.json();
|
||||
|
||||
if (res.ok) {
|
||||
config.response.editorUrl = (
|
||||
config.response as IInitialConfig
|
||||
).editorUrl.replace(REPLACED_URL_PATH, "");
|
||||
return config.response as IInitialConfig;
|
||||
}
|
||||
|
||||
const editorUrl = (await getEditorUrl("", share)).docServiceUrl;
|
||||
|
||||
const status =
|
||||
config.error.type === EditorConfigErrorType.NotFoundScope
|
||||
? "not-found"
|
||||
: config.error.type === EditorConfigErrorType.AccessDeniedScope
|
||||
? "access-denied"
|
||||
: res.status === 415
|
||||
? "not-supported"
|
||||
: undefined;
|
||||
|
||||
const message = status ? config.error.message : undefined;
|
||||
|
||||
const error =
|
||||
cookie?.includes("asc_auth_key") || share
|
||||
? config.error.type === EditorConfigErrorType.LinkScope
|
||||
? { message: message ?? "unauthorized", status, editorUrl }
|
||||
: { ...config.error, status, editorUrl }
|
||||
: { message: message ?? "unauthorized", status, editorUrl };
|
||||
|
||||
return error as TError;
|
||||
}
|
||||
|
||||
export async function getEditorUrl(
|
||||
editorSearchParams?: string,
|
||||
share?: string,
|
||||
) {
|
||||
const [request] = createRequest(
|
||||
[`/files/docservice?${editorSearchParams ? editorSearchParams : ""}`],
|
||||
[share ? ["Request-Token", share] : ["", ""]],
|
||||
"GET",
|
||||
);
|
||||
|
||||
const res = await fetch(request);
|
||||
|
||||
const editorUrl = await res.json();
|
||||
|
||||
return editorUrl.response as TDocServiceLocation;
|
||||
}
|
||||
|
@ -37,3 +37,4 @@ export const IS_VIEW =
|
||||
? window.location.search.indexOf("action=view") !== -1
|
||||
: false;
|
||||
|
||||
export const REPLACED_URL_PATH = "/web-apps/apps/api/documents/api.js";
|
||||
|
@ -24,19 +24,14 @@
|
||||
// content are licensed under the terms of the Creative Commons Attribution-ShareAlike 4.0
|
||||
// International. See the License terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode
|
||||
|
||||
import React from "react";
|
||||
import i18n from "i18next";
|
||||
import { initReactI18next } from "react-i18next";
|
||||
|
||||
import config from "../../../../../buildtools/config/appsettings.json";
|
||||
|
||||
import { translations } from "./autoGeneratedTranslations";
|
||||
|
||||
export const getI18NInstance = (lng: string, portalLng: string) => {
|
||||
if (typeof window === "undefined") return;
|
||||
|
||||
// const cultures = config.web.cultures.split(",");
|
||||
|
||||
i18n.use(initReactI18next).init({
|
||||
lng,
|
||||
fallbackLng: "en",
|
||||
|
@ -24,6 +24,8 @@
|
||||
// content are licensed under the terms of the Creative Commons Attribution-ShareAlike 4.0
|
||||
// International. See the License terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode
|
||||
|
||||
"use client";
|
||||
|
||||
import React from "react";
|
||||
import { Loader, LoaderTypes } from "../loader";
|
||||
|
||||
|
@ -26,8 +26,6 @@
|
||||
|
||||
import React, { ErrorInfo } from "react";
|
||||
|
||||
import { I18nextProvider } from "react-i18next";
|
||||
|
||||
import Error520 from "../errors/Error520";
|
||||
|
||||
import type {
|
||||
@ -68,32 +66,11 @@ class ErrorBoundary extends React.Component<
|
||||
currentDeviceType,
|
||||
whiteLabelLogoUrls,
|
||||
currentColorScheme,
|
||||
isNextJS,
|
||||
theme,
|
||||
i18n,
|
||||
} = this.props;
|
||||
|
||||
if (error) {
|
||||
// You can render any custom fallback UI
|
||||
|
||||
if (isNextJS && !i18n?.language) return null;
|
||||
|
||||
if (isNextJS && theme && i18n) {
|
||||
return (
|
||||
<I18nextProvider i18n={i18n}>
|
||||
<Error520
|
||||
user={user}
|
||||
errorLog={error}
|
||||
version={version}
|
||||
firebaseHelper={firebaseHelper}
|
||||
currentDeviceType={currentDeviceType}
|
||||
whiteLabelLogoUrls={whiteLabelLogoUrls}
|
||||
currentColorScheme={theme.currentColorScheme}
|
||||
/>
|
||||
</I18nextProvider>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<Error520
|
||||
user={user}
|
||||
|
@ -25,8 +25,8 @@
|
||||
// International. See the License terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode
|
||||
|
||||
import React from "react";
|
||||
import { i18n } from "i18next";
|
||||
import { I18nextProvider, useTranslation } from "react-i18next";
|
||||
|
||||
import { useTranslation } from "react-i18next";
|
||||
|
||||
import ErrorContainer from "../error-container/ErrorContainer";
|
||||
|
||||
@ -37,12 +37,3 @@ const Error404 = () => {
|
||||
};
|
||||
|
||||
export default Error404;
|
||||
|
||||
export const Error404Wrapper = ({ i18nProp }: { i18nProp: i18n }) => {
|
||||
if (!i18nProp.language) return null;
|
||||
return (
|
||||
<I18nextProvider i18n={i18nProp}>
|
||||
<Error404 />
|
||||
</I18nextProvider>
|
||||
);
|
||||
};
|
||||
|
@ -32,7 +32,7 @@ const GlobalStyle = createGlobalStyle<{ theme: TTheme }>`
|
||||
margin: 0;
|
||||
|
||||
background-color: ${(props) => props.theme.backgroundColor};
|
||||
|
||||
|
||||
color: ${(props) => props.theme.color};
|
||||
|
||||
font-family: ${(props) => props.theme.fontFamily};
|
||||
@ -42,7 +42,6 @@ const GlobalStyle = createGlobalStyle<{ theme: TTheme }>`
|
||||
}
|
||||
|
||||
body {
|
||||
|
||||
direction: ${(props) => props.theme.interfaceDirection};
|
||||
}
|
||||
`;
|
||||
|
@ -24,6 +24,8 @@
|
||||
// content are licensed under the terms of the Creative Commons Attribution-ShareAlike 4.0
|
||||
// International. See the License terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode
|
||||
|
||||
"use client";
|
||||
|
||||
import React, { useCallback, useEffect, useState } from "react";
|
||||
import { ToastClassName, cssTransition } from "react-toastify";
|
||||
import { isMobileOnly } from "react-device-detect";
|
||||
|
@ -25,6 +25,9 @@
|
||||
// International. See the License terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode
|
||||
|
||||
/* eslint-disable react-hooks/exhaustive-deps */
|
||||
|
||||
"use client";
|
||||
|
||||
import { useEffect } from "react";
|
||||
|
||||
export const useClickOutside = (
|
||||
|
@ -3163,7 +3163,7 @@ __metadata:
|
||||
version: 0.0.0-use.local
|
||||
resolution: "@docspace/doceditor@workspace:packages/doceditor"
|
||||
dependencies:
|
||||
"@onlyoffice/document-editor-react": "file:./onlyoffice-document-editor-react-1.5.1.tgz"
|
||||
"@onlyoffice/document-editor-react": "npm:^1.5.1"
|
||||
"@svgr/webpack": "npm:^8.1.0"
|
||||
"@types/node": "npm:^20"
|
||||
"@types/react": "npm:^18"
|
||||
@ -5224,15 +5224,15 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@onlyoffice/document-editor-react@file:./onlyoffice-document-editor-react-1.5.1.tgz::locator=%40docspace%2Fdoceditor%40workspace%3Apackages%2Fdoceditor":
|
||||
"@onlyoffice/document-editor-react@npm:^1.5.1":
|
||||
version: 1.5.1
|
||||
resolution: "@onlyoffice/document-editor-react@file:./onlyoffice-document-editor-react-1.5.1.tgz#./onlyoffice-document-editor-react-1.5.1.tgz::hash=0845a7&locator=%40docspace%2Fdoceditor%40workspace%3Apackages%2Fdoceditor"
|
||||
resolution: "@onlyoffice/document-editor-react@npm:1.5.1"
|
||||
dependencies:
|
||||
lodash: "npm:4.17.21"
|
||||
peerDependencies:
|
||||
react: ^16.9.0 || ^17 || ^18
|
||||
react-dom: ^16.9.0 || ^17 || ^18
|
||||
checksum: d7f1ac9ed3510484a8622da828d4a5edad127d4f8af66cd55990253557ad10dc0100b3fb8b39e696a00ee51e3ca9b64f7c031d50ad540f37cd3bdb7d8cb0f8e0
|
||||
checksum: f70f876afc7518a58a5fc0a8e1d644883e87471c6a5c0d035a73eb7c1911b059f751b14f123a83aaaaac64fcabfa76b984056f427778eaa62f12bcf2a1ace4b3
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user