diff --git a/packages/client/src/pages/PortalSettings/categories/data-import/components/Providers.tsx b/packages/client/src/pages/PortalSettings/categories/data-import/components/Providers.tsx new file mode 100644 index 0000000000..38ddf481ae --- /dev/null +++ b/packages/client/src/pages/PortalSettings/categories/data-import/components/Providers.tsx @@ -0,0 +1,185 @@ +// (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 { useEffect, useMemo } from "react"; +import { inject, observer } from "mobx-react"; +import { useNavigate } from "react-router-dom"; +import { useTranslation } from "react-i18next"; +import { ReactSVG } from "react-svg"; + +import { Link } from "@docspace/shared/components/link"; +import { Box } from "@docspace/shared/components/box"; +import { Text } from "@docspace/shared/components/text"; + +import GoogleWorkspaceSvgUrl from "PUBLIC_DIR/images/workspace.google.react.svg?url"; +import NextcloudWorkspaceSvgUrl from "PUBLIC_DIR/images/workspace.nextcloud.react.svg?url"; +import OnlyofficeWorkspaceSvgUrl from "PUBLIC_DIR/images/workspace.onlyoffice.react.svg?url"; +import GoogleWorkspaceDarkSvgUrl from "PUBLIC_DIR/images/dark.workspace.google.react.svg?url"; +import NextcloudWorkspaceDarkSvgUrl from "PUBLIC_DIR/images/dark.workspace.nextcloud.react.svg?url"; +import OnlyofficeWorkspaceDarkSvgUrl from "PUBLIC_DIR/images/dark.workspace.onlyoffice.react.svg?url"; +import { TWorkspaceService } from "@docspace/shared/api/settings/types"; +import { LinkType } from "@docspace/shared/components/link/Link.enums"; +import DataImportLoader from "../sub-components/DataImportLoader"; +import { WorkspacesContainer } from "../StyledDataImport"; +import { ProvidersProps } from "../types"; + +const Providers = ({ + theme, + services, + setServices, + getMigrationList, + getMigrationStatus, + setDocumentTitle, + isMigrationInit, + setIsMigrationInit, +}: ProvidersProps) => { + const navigate = useNavigate(); + const { t } = useTranslation(["Settings"]); + + const workspacesMap = { + GoogleWorkspace: "google", + Nextcloud: "nextcloud", + Workspace: "onlyoffice", + }; + + const workspaces = useMemo(() => { + const logos = { + GoogleWorkspace: theme.isBase + ? GoogleWorkspaceSvgUrl + : GoogleWorkspaceDarkSvgUrl, + Nextcloud: theme.isBase + ? NextcloudWorkspaceSvgUrl + : NextcloudWorkspaceDarkSvgUrl, + Workspace: theme.isBase + ? OnlyofficeWorkspaceSvgUrl + : OnlyofficeWorkspaceDarkSvgUrl, + }; + + return services.map((service) => ({ + title: service, + logo: logos[service], + })); + }, [theme.isBase, services]); + + const handleMigrationCheck = async () => { + const migrationStatus = await getMigrationStatus(); + + if ( + migrationStatus && + migrationStatus.parseResult?.failedArchives && + migrationStatus.parseResult.failedArchives.length === 0 && + !migrationStatus.error + ) { + const migratorName = migrationStatus.parseResult.migratorName; + + navigate(`${workspacesMap[migratorName]}?service=${migratorName}`); + + return; + } + + const migrationList = await getMigrationList(); + setIsMigrationInit(true); + setServices(migrationList); + }; + + useEffect(() => { + setDocumentTitle(t("DataImport")); + handleMigrationCheck(); + // eslint-disable-next-line react-hooks/exhaustive-deps + }, []); + + const redirectToWorkspace = (title: TWorkspaceService) => { + switch (title) { + case "GoogleWorkspace": + navigate(`google?service=${title}`); + break; + case "Nextcloud": + navigate(`nextcloud?service=${title}`); + break; + case "Workspace": + navigate(`onlyoffice?service=${title}`); + break; + default: + break; + } + }; + + if (!isMigrationInit) return ; + return ( + + + {t("DataImportDescription")} + + {t("UploadBackupData")} + + + {workspaces.map((workspace) => ( + redirectToWorkspace(workspace.title)} + > + + + {t("Import")} + + + ))} + + + ); +}; +export default inject( + ({ authStore, settingsStore, importAccountsStore }) => { + const { + services, + setServices, + getMigrationList, + getMigrationStatus, + isMigrationInit, + setIsMigrationInit, + } = importAccountsStore; + + const { setDocumentTitle } = authStore; + + return { + services, + setServices, + getMigrationList, + getMigrationStatus, + theme: settingsStore.theme, + setDocumentTitle, + isMigrationInit, + setIsMigrationInit, + }; + }, +)(observer(Providers)); diff --git a/packages/client/src/pages/PortalSettings/categories/data-import/index.js b/packages/client/src/pages/PortalSettings/categories/data-import/index.js index e139e7b95f..3e1cfd98b8 100644 --- a/packages/client/src/pages/PortalSettings/categories/data-import/index.js +++ b/packages/client/src/pages/PortalSettings/categories/data-import/index.js @@ -24,161 +24,10 @@ // 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 { useEffect, useMemo } from "react"; -import { inject, observer } from "mobx-react"; -import { useNavigate } from "react-router-dom"; -import { withTranslation } from "react-i18next"; -import { ReactSVG } from "react-svg"; +import Providers from "./components/Providers"; -import { Link } from "@docspace/shared/components/link"; -import { Box } from "@docspace/shared/components/box"; -import { Text } from "@docspace/shared/components/text"; -import { WorkspacesContainer } from "./StyledDataImport"; - -import GoogleWorkspaceSvgUrl from "PUBLIC_DIR/images/workspace.google.react.svg?url"; -import NextcloudWorkspaceSvgUrl from "PUBLIC_DIR/images/workspace.nextcloud.react.svg?url"; -import OnlyofficeWorkspaceSvgUrl from "PUBLIC_DIR/images/workspace.onlyoffice.react.svg?url"; -import GoogleWorkspaceDarkSvgUrl from "PUBLIC_DIR/images/dark.workspace.google.react.svg?url"; -import NextcloudWorkspaceDarkSvgUrl from "PUBLIC_DIR/images/dark.workspace.nextcloud.react.svg?url"; -import OnlyofficeWorkspaceDarkSvgUrl from "PUBLIC_DIR/images/dark.workspace.onlyoffice.react.svg?url"; -import DataImportLoader from "./sub-components/DataImportLoader"; - -const DataImport = ({ - t, - theme, - services, - setServices, - getMigrationList, - getMigrationStatus, - setDocumentTitle, - isMigrationInit, - setIsMigrationInit, -}) => { - const navigate = useNavigate(); - - const google = theme.isBase - ? GoogleWorkspaceSvgUrl - : GoogleWorkspaceDarkSvgUrl; - - const nextcloud = theme.isBase - ? NextcloudWorkspaceSvgUrl - : NextcloudWorkspaceDarkSvgUrl; - - const onlyoffice = theme.isBase - ? OnlyofficeWorkspaceSvgUrl - : OnlyofficeWorkspaceDarkSvgUrl; - - const logos = { - GoogleWorkspace: google, - Nextcloud: nextcloud, - Workspace: onlyoffice, - }; - - const workspaces = useMemo(() => { - return services.map((service) => ({ - title: service, - logo: logos[service], - })); - }, [theme.isBase, services]); - - const handleMigrationCheck = async () => { - const migrationStatus = await getMigrationStatus(); - - if ( - migrationStatus && - migrationStatus.parseResult?.failedArchives && - migrationStatus.parseResult.failedArchives.length === 0 && - !migrationStatus.error - ) { - const workspacesEnum = { - GoogleWorkspace: "google", - Nextcloud: "nextcloud", - Workspace: "onlyoffice", - }; - const migratorName = migrationStatus.parseResult.migratorName; - - navigate(`${workspacesEnum[migratorName]}?service=${migratorName}`); - - return; - } - - const migrationList = await getMigrationList(); - setIsMigrationInit(true); - setServices(migrationList); - }; - - useEffect(() => { - setDocumentTitle(t("DataImport")); - handleMigrationCheck(); - }, []); - - const redirectToWorkspace = (title) => { - switch (title) { - case "GoogleWorkspace": - navigate(`google?service=${title}`); - break; - case "Nextcloud": - navigate(`nextcloud?service=${title}`); - break; - case "Workspace": - navigate(`onlyoffice?service=${title}`); - break; - default: - break; - } - }; - - if (!isMigrationInit) return ; - return ( - - - {t("DataImportDescription")} - - {t("UploadBackupData")} - - - {workspaces.map((workspace) => ( - redirectToWorkspace(workspace.title)} - > - - - {t("Import")} - - - ))} - - - ); +const DataImport = () => { + return ; }; -export default inject(({ authStore, settingsStore, importAccountsStore }) => { - const { - services, - setServices, - getMigrationList, - getMigrationStatus, - isMigrationInit, - setIsMigrationInit, - } = importAccountsStore; - const { setDocumentTitle } = authStore; - - return { - services, - setServices, - getMigrationList, - getMigrationStatus, - theme: settingsStore.theme, - setDocumentTitle, - isMigrationInit, - setIsMigrationInit, - }; -})(withTranslation(["Settings"])(observer(DataImport))); +export default DataImport; diff --git a/packages/client/src/pages/PortalSettings/categories/data-import/sub-components/DataImportLoader.js b/packages/client/src/pages/PortalSettings/categories/data-import/sub-components/DataImportLoader.tsx similarity index 100% rename from packages/client/src/pages/PortalSettings/categories/data-import/sub-components/DataImportLoader.js rename to packages/client/src/pages/PortalSettings/categories/data-import/sub-components/DataImportLoader.tsx diff --git a/packages/client/src/pages/PortalSettings/categories/data-import/types/index.ts b/packages/client/src/pages/PortalSettings/categories/data-import/types/index.ts new file mode 100644 index 0000000000..7b2cf455e8 --- /dev/null +++ b/packages/client/src/pages/PortalSettings/categories/data-import/types/index.ts @@ -0,0 +1,36 @@ +// (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 interface ProvidersProps { + theme: TStore["settingsStore"]["theme"]; + services: TStore["importAccountsStore"]["services"]; + setServices: TStore["importAccountsStore"]["setServices"]; + getMigrationList: TStore["importAccountsStore"]["getMigrationList"]; + getMigrationStatus: TStore["importAccountsStore"]["getMigrationStatus"]; + setDocumentTitle: TStore["authStore"]["setDocumentTitle"]; + isMigrationInit: TStore["importAccountsStore"]["isMigrationInit"]; + setIsMigrationInit: TStore["importAccountsStore"]["setIsMigrationInit"]; +} diff --git a/packages/client/src/store/ImportAccountsStore.ts b/packages/client/src/store/ImportAccountsStore.ts index 43ce7a04f0..3b6ced71fa 100644 --- a/packages/client/src/store/ImportAccountsStore.ts +++ b/packages/client/src/store/ImportAccountsStore.ts @@ -30,7 +30,7 @@ import { combineUrl } from "@docspace/shared/utils/combineUrl"; import { makeAutoObservable, runInAction } from "mobx"; import { migrationList, - migrationName, + initMigration, migrationStatus, migrationCancel, migrationFinish, @@ -38,64 +38,30 @@ import { migrateFile, migrationClear, } from "@docspace/shared/api/settings"; - -type TUser = { - key: string; - email: string; - displayName: string; - firstName: string; - userType: string; - migratingFiles: { - foldersCount: number; - filesCount: number; - bytesTotal: number; - }; - shouldImport: boolean; -}; +import { + TWorkspaceService, + TSendWelcomeEmailData, + TMigrationUser, + TMigrationStatusResult, +} from "@docspace/shared/api/settings/types"; type TUsers = { - new: TUser[]; - existing: TUser[]; - withoutEmail: TUser[]; - result: TUser[]; + new: TMigrationUser[]; + existing: TMigrationUser[]; + withoutEmail: TMigrationUser[]; + result: TMigrationUser[]; }; type TCheckedUsers = { - withEmail: TUser[]; - withoutEmail: TUser[]; - result: TUser[]; -}; - -type TGroup = { - groupName: string; - userUidList: string[]; - shouldImport: boolean; -}; - -type TResponseData = { - migratorName: string; - operation: string; - failedArchives: string[]; - users: TUser[]; - withoutEmailUsers: TUser[]; - existUsers: TUser[]; - groups: TGroup[]; - importPersonalFiles: boolean; - importSharedFiles: boolean; - importSharedFolders: boolean; - importCommonFiles: boolean; - importProjectFiles: boolean; - importGroups: boolean; - successedUsers: number; - failedUsers: number; - files: string[]; - errors: string[]; + withEmail: TMigrationUser[]; + withoutEmail: TMigrationUser[]; + result: TMigrationUser[]; }; type CheckedAccountTypes = "withEmail" | "withoutEmail" | "result"; class ImportAccountsStore { - services: string[] = []; + services: TWorkspaceService[] = []; users: TUsers = { new: [], @@ -186,7 +152,7 @@ class ImportAccountsStore { }); }; - setUsers = (data: TResponseData) => { + setUsers = (data: TMigrationStatusResult) => { runInAction(() => { this.users = { new: data.users, @@ -227,7 +193,10 @@ class ImportAccountsStore { }; }; - toggleAccount = (account: TUser, checkedAccountType: CheckedAccountTypes) => { + toggleAccount = ( + account: TMigrationUser, + checkedAccountType: CheckedAccountTypes, + ) => { this.checkedUsers = this.checkedUsers[checkedAccountType].some( (user) => user.key === account.key, ) @@ -248,7 +217,7 @@ class ImportAccountsStore { toggleAllAccounts = ( isChecked: boolean, - accounts: TUser[], + accounts: TMigrationUser[], checkedAccountType: CheckedAccountTypes, ) => { this.checkedUsers = isChecked @@ -305,10 +274,6 @@ class ImportAccountsStore { }; }; - // get numberOfCheckedAccounts() { - // return this.checkedAccounts.length; - // } - multipleFileUploading = async ( files: File[], setProgress: (progress: number) => void, @@ -418,7 +383,7 @@ class ImportAccountsStore { this.importOptions = { ...this.importOptions, ...value }; }; - setServices = (services: string[]) => { + setServices = (services: TWorkspaceService[]) => { this.services = services; }; @@ -428,11 +393,11 @@ class ImportAccountsStore { }; // eslint-disable-next-line class-methods-use-this - initMigrationName = (name: string) => { - return migrationName(name); + initMigrationName = (name: TWorkspaceService) => { + return initMigration(name); }; - proceedFileMigration = (migratorName: string) => { + proceedFileMigration = (migratorName: TWorkspaceService) => { const users = this.finalUsers.map((item) => Object.assign(item, { shouldImport: true }), ); @@ -461,19 +426,16 @@ class ImportAccountsStore { // eslint-disable-next-line class-methods-use-this getMigrationLog = () => { - return migrationLog() - .then((response) => { - if (!response || !response.data) return null; - return response.data; - }) - .catch((error) => { - console.log("Request Failed:", { error }); - return Promise.reject(error); - }); + try { + return migrationLog(); + } catch (error) { + console.log("Request Failed:", { error }); + return Promise.reject(error); + } }; // eslint-disable-next-line class-methods-use-this - sendWelcomeLetter = (data: { isSendWelcomeEmail: boolean }) => { + sendWelcomeLetter = (data: TSendWelcomeEmailData) => { return migrationFinish(data); }; } diff --git a/packages/shared/api/settings/index.ts b/packages/shared/api/settings/index.ts index efc69c4224..be89755e97 100644 --- a/packages/shared/api/settings/index.ts +++ b/packages/shared/api/settings/index.ts @@ -46,6 +46,10 @@ import { TThirdPartyProvider, TPaymentSettings, TGetSsoSettings, + TWorkspaceService, + TWorkspaceStatusResponse, + TMigrationData, + TSendWelcomeEmailData, } from "./types"; export async function getSettings(withPassword = false, headers = null) { @@ -1087,28 +1091,30 @@ export function getSendingTestMailStatus() { }); } -export function migrationList() { - return request({ +export async function migrationList() { + const res = (await request({ method: "get", url: `/migration/list`, - }); + })) as TWorkspaceService[]; + return res; } -export function migrationName(name) { +export function initMigration(name: TWorkspaceService) { return request({ method: "post", url: `/migration/init/${name}`, }); } -export function migrationStatus() { - return request({ +export async function migrationStatus() { + const res = (await request({ method: "get", url: `/migration/status`, - }); + })) as TWorkspaceStatusResponse; + return res; } -export function migrateFile(data) { +export function migrateFile(data: TMigrationData) { return request({ method: "post", url: `/migration/migrate`, @@ -1130,11 +1136,13 @@ export function migrationClear() { }); } -export function migrationLog() { - return axios.get("/api/2.0/migration/logs"); +export async function migrationLog() { + const response = await axios.get("/api/2.0/migration/logs"); + if (!response || !response.data) return null; + return response.data as string; } -export function migrationFinish(data) { +export function migrationFinish(data: TSendWelcomeEmailData) { return request({ method: "post", url: `/migration/finish`, diff --git a/packages/shared/api/settings/types.ts b/packages/shared/api/settings/types.ts index ddc65ff68d..1971def085 100644 --- a/packages/shared/api/settings/types.ts +++ b/packages/shared/api/settings/types.ts @@ -239,3 +239,64 @@ export type TPaymentSettings = { }; max: number; }; + +export type TWorkspaceService = "Workspace" | "GoogleWorkspace" | "Nextcloud"; + +export type TMigrationGroup = { + groupName: string; + userUidList: string[]; + shouldImport: boolean; +}; + +export type TImportOptions = { + importGroups: boolean; + importPersonalFiles: boolean; + importSharedFiles: boolean; + importSharedFolders: boolean; + importCommonFiles: boolean; + importProjectFiles: boolean; +}; + +export type TMigrationUser = { + key: string; + email: string; + displayName: string; + firstName: string; + userType: string; + migratingFiles: { + foldersCount: number; + filesCount: number; + bytesTotal: number; + }; + shouldImport: boolean; +}; + +export type TMigrationStatusResult = { + migratorName: TWorkspaceService; + operation: string; + failedArchives: string[]; + users: TMigrationUser[]; + withoutEmailUsers: TMigrationUser[]; + existUsers: TMigrationUser[]; + groups: TMigrationGroup[]; + successedUsers: number; + failedUsers: number; + files: string[]; + errors: string[]; +} & TImportOptions; + +export type TWorkspaceStatusResponse = + | { + error: string; + isCompleted: boolean; + progress: number; + parseResult: TMigrationStatusResult; + } + | undefined; + +export type TMigrationData = { + users: TMigrationUser[]; + migratorName: TWorkspaceService; +} & TImportOptions; + +export type TSendWelcomeEmailData = { isSendWelcomeEmail: boolean };