Merge pull request #566 from ONLYOFFICE/bugfix/restore-data-import

bugfix/restore-data-import
This commit is contained in:
Alexey Safronov 2024-08-01 16:38:56 +04:00 committed by GitHub
commit e4fb34c058
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
34 changed files with 265 additions and 271 deletions

View File

@ -51,11 +51,7 @@ const GoogleWorkspace = (props: WorkspaceProps) => {
"Common, SMTPSettings, Settings",
]);
const StepsData = getStepsData(
t,
filteredUsers.length === 0,
t("Common:OrganizationName"),
);
const StepsData = getStepsData(t, filteredUsers.length === 0);
useLayoutEffect(() => {
if (migratingWorkspace === "GoogleWorkspace" && !isMigrationInit) {
@ -68,6 +64,7 @@ const GoogleWorkspace = (props: WorkspaceProps) => {
}
setIsMigrationInit(true);
}
// eslint-disable-next-line react-hooks/exhaustive-deps
}, []);
if (!ready) return <SelectFileLoader />;
@ -81,7 +78,6 @@ const GoogleWorkspace = (props: WorkspaceProps) => {
title={StepsData[step - 1].title}
description={StepsData[step - 1].description}
component={StepsData[step - 1].component}
organizationName={t("Common:OrganizationName")}
/>
);
};

View File

@ -64,6 +64,7 @@ const NextcloudWorkspace = (props: WorkspaceProps) => {
}
setIsMigrationInit(true);
}
// eslint-disable-next-line react-hooks/exhaustive-deps
}, []);
if (!ready) return <SelectFileLoader />;

View File

@ -64,6 +64,7 @@ const OnlyofficeWorkspace = (props: WorkspaceProps) => {
}
setIsMigrationInit(true);
}
// eslint-disable-next-line react-hooks/exhaustive-deps
}, []);
if (!ready) return <SelectFileLoader />;

View File

@ -24,7 +24,7 @@
// 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 styled, { css } from "styled-components";
import styled from "styled-components";
import { tablet, mobile } from "@docspace/shared/utils/device";
import { TableContainer } from "@docspace/shared/components/table";

View File

@ -29,15 +29,25 @@ import { inject, observer } from "mobx-react";
import { tablet } from "@docspace/shared/utils/device";
import styled from "styled-components";
import { EmptyScreenContainer } from "@docspace/shared/components/empty-screen-container";
import { IconButton } from "@docspace/shared/components/icon-button";
import { Link, LinkType } from "@docspace/shared/components/link";
import { Box } from "@docspace/shared/components/box";
import { RowContainer } from "@docspace/shared/components/row-container";
import { Row } from "@docspace/shared/components/row";
import { Text } from "@docspace/shared/components/text";
import EmptyScreenUserReactSvgUrl from "PUBLIC_DIR/images/empty_screen_user.react.svg?url";
import ClearEmptyFilterSvgUrl from "PUBLIC_DIR/images/clear.empty.filter.svg?url";
import { TEnhancedMigrationUser } from "@docspace/shared/api/settings/types";
import UsersRow from "./UsersRow";
import { AddEmailRowProps, RowViewProps } from "../../../../types";
const StyledRowContainer = styled(RowContainer)`
margin: 0 0 20px;
.clear-icon {
margin-inline-end: 8px;
}
`;
const StyledRow = styled(Row)`
@ -71,6 +81,7 @@ const RowView = (props: RowViewProps) => {
toggleAccount,
toggleAllAccounts,
isAccountChecked,
setSearchValue,
} = props as AddEmailRowProps;
const [openedEmailKey, setOpenedEmailKey] = useState("");
@ -85,6 +96,8 @@ const RowView = (props: RowViewProps) => {
const handleToggle = (user: TEnhancedMigrationUser) =>
toggleAccount(user, checkedAccountType);
const onClearFilter = () => setSearchValue("");
const isIndeterminate =
checkedUsers.withoutEmail.length > 0 &&
checkedUsers.withoutEmail.length !== usersWithFilledEmails.length;
@ -95,26 +108,56 @@ const RowView = (props: RowViewProps) => {
return (
<StyledRowContainer useReactWindow={false}>
<StyledRow
checked={isChecked}
onSelect={toggleAll}
indeterminate={isIndeterminate}
isDisabled={usersWithFilledEmails.length === 0}
>
<Text className="row-header-title">{t("Common:Name")}</Text>
</StyledRow>
{accountsData.map((data) => (
<UsersRow
t={t}
key={data.key}
data={data}
sectionWidth={sectionWidth}
toggleAccount={() => handleToggle(data)}
isChecked={isAccountChecked(data.key, checkedAccountType)}
isEmailOpen={openedEmailKey === data.key}
setOpenedEmailKey={setOpenedEmailKey}
{accountsData.length > 0 ? (
<>
<StyledRow
checked={isChecked}
onSelect={toggleAll}
indeterminate={isIndeterminate}
isDisabled={usersWithFilledEmails.length === 0}
>
<Text className="row-header-title">{t("Common:Name")}</Text>
</StyledRow>
{accountsData.map((data) => (
<UsersRow
t={t}
key={data.key}
data={data}
sectionWidth={sectionWidth}
toggleAccount={() => handleToggle(data)}
isChecked={isAccountChecked(data.key, checkedAccountType)}
isEmailOpen={openedEmailKey === data.key}
setOpenedEmailKey={setOpenedEmailKey}
/>
))}
</>
) : (
<EmptyScreenContainer
imageSrc={EmptyScreenUserReactSvgUrl}
imageAlt="Empty Screen user image"
headerText={t("Common:NotFoundUsers")}
descriptionText={t("Common:NotFoundUsersDescription")}
buttons={
<Box displayProp="flex" alignItems="center">
<IconButton
className="clear-icon"
isFill
size={12}
onClick={onClearFilter}
iconName={ClearEmptyFilterSvgUrl}
/>
<Link
type={LinkType.action}
isHovered
fontWeight="600"
onClick={onClearFilter}
>
{t("Common:ClearFilter")}
</Link>
</Box>
}
/>
))}
)}
</StyledRowContainer>
);
};
@ -126,6 +169,7 @@ export default inject<TStore>(({ importAccountsStore }) => {
toggleAccount,
toggleAllAccounts,
isAccountChecked,
setSearchValue,
} = importAccountsStore;
return {
@ -134,5 +178,6 @@ export default inject<TStore>(({ importAccountsStore }) => {
toggleAccount,
toggleAllAccounts,
isAccountChecked,
setSearchValue,
};
})(observer(RowView));

View File

@ -27,7 +27,13 @@
import { useState, useRef } from "react";
import { inject, observer } from "mobx-react";
import { EmptyScreenContainer } from "@docspace/shared/components/empty-screen-container";
import { IconButton } from "@docspace/shared/components/icon-button";
import { Link, LinkType } from "@docspace/shared/components/link";
import { Box } from "@docspace/shared/components/box";
import { TableBody } from "@docspace/shared/components/table";
import EmptyScreenUserReactSvgUrl from "PUBLIC_DIR/images/empty_screen_user.react.svg?url";
import ClearEmptyFilterSvgUrl from "PUBLIC_DIR/images/clear.empty.filter.svg?url";
import UsersTableHeader from "./UsersTableHeader";
import UsersTableRow from "./UsersTableRow";
import { StyledTableContainer } from "../../../../StyledDataImport";
@ -45,13 +51,13 @@ const TableView = (props: TableViewProps) => {
t,
sectionWidth,
accountsData,
userId,
checkedUsers,
toggleAccount,
toggleAllAccounts,
isAccountChecked,
users,
setSearchValue,
} = props as AddEmailTableProps;
const [openedEmailKey, setOpenedEmailKey] = useState<string>("");
const tableRef = useRef(null);
@ -67,6 +73,10 @@ const TableView = (props: TableViewProps) => {
checkedAccountType,
);
const onClearFilter = () => {
setSearchValue("");
};
const columnStorageName = `${COLUMNS_SIZE}=${userId}`;
const columnInfoPanelStorageName = `${INFO_PANEL_COLUMNS_SIZE}=${userId}`;
@ -76,44 +86,74 @@ const TableView = (props: TableViewProps) => {
return (
<StyledTableContainer forwardedRef={tableRef} useReactWindow>
<UsersTableHeader
t={t}
sectionWidth={sectionWidth}
tableRef={tableRef}
columnStorageName={columnStorageName}
columnInfoPanelStorageName={columnInfoPanelStorageName}
isIndeterminate={isIndeterminate}
isChecked={
usersWithFilledEmails.length > 0 &&
checkedUsers.withoutEmail.length === usersWithFilledEmails.length
}
toggleAll={toggleAll}
/>
<TableBody
itemHeight={49}
useReactWindow
infoPanelVisible={false}
columnStorageName={columnStorageName}
columnInfoPanelStorageName={columnInfoPanelStorageName}
filesLength={accountsData.length}
hasMoreFiles={false}
itemCount={accountsData.length}
fetchMoreFiles={() => {}}
>
{accountsData.map((data) => (
<UsersTableRow
{accountsData.length > 0 ? (
<>
<UsersTableHeader
t={t}
key={data.key}
id={data.key}
email={data.email || ""}
displayName={data.displayName}
isChecked={isAccountChecked(data.key, checkedAccountType)}
toggleAccount={() => toggleAccount(data, checkedAccountType)}
isEmailOpen={openedEmailKey === data.key}
setOpenedEmailKey={setOpenedEmailKey}
sectionWidth={sectionWidth}
tableRef={tableRef}
columnStorageName={columnStorageName}
columnInfoPanelStorageName={columnInfoPanelStorageName}
isIndeterminate={isIndeterminate}
isChecked={
usersWithFilledEmails.length > 0 &&
checkedUsers.withoutEmail.length === usersWithFilledEmails.length
}
toggleAll={toggleAll}
/>
))}
</TableBody>
<TableBody
itemHeight={49}
useReactWindow
infoPanelVisible={false}
columnStorageName={columnStorageName}
columnInfoPanelStorageName={columnInfoPanelStorageName}
filesLength={accountsData.length}
hasMoreFiles={false}
itemCount={accountsData.length}
fetchMoreFiles={() => {}}
>
{accountsData.map((data) => (
<UsersTableRow
t={t}
key={data.key}
id={data.key}
email={data.email || ""}
displayName={data.displayName}
isChecked={isAccountChecked(data.key, checkedAccountType)}
toggleAccount={() => toggleAccount(data, checkedAccountType)}
isEmailOpen={openedEmailKey === data.key}
setOpenedEmailKey={setOpenedEmailKey}
/>
))}
</TableBody>
</>
) : (
<EmptyScreenContainer
imageSrc={EmptyScreenUserReactSvgUrl}
imageAlt="Empty Screen user image"
headerText={t("Common:NotFoundUsers")}
descriptionText={t("Common:NotFoundUsersDescription")}
buttons={
<Box displayProp="flex" alignItems="center">
<IconButton
className="clear-icon"
isFill
size={12}
onClick={onClearFilter}
iconName={ClearEmptyFilterSvgUrl}
/>
<Link
type={LinkType.action}
isHovered
fontWeight="600"
onClick={onClearFilter}
>
{t("Common:ClearFilter")}
</Link>
</Box>
}
/>
)}
</StyledTableContainer>
);
};
@ -126,6 +166,7 @@ export default inject<TStore>(({ userStore, importAccountsStore }) => {
toggleAccount,
toggleAllAccounts,
isAccountChecked,
setSearchValue,
} = importAccountsStore;
return {
@ -135,5 +176,6 @@ export default inject<TStore>(({ userStore, importAccountsStore }) => {
toggleAccount,
toggleAllAccounts,
isAccountChecked,
setSearchValue,
};
})(observer(TableView));

View File

@ -51,7 +51,6 @@ const REFRESH_TIMEOUT = 100;
const AddEmailsStep = (props: AddEmailsStepProps) => {
const {
t,
incrementStep,
decrementStep,
users,
@ -67,10 +66,8 @@ const AddEmailsStep = (props: AddEmailsStepProps) => {
setWorkspace,
setMigratingWorkspace,
setMigrationPhase,
cancelUploadDialogVisible,
setCancelUploadDialogVisible,
quotaCharacteristics,
} = props as InjectedAddEmailsStepProps;
@ -97,8 +94,8 @@ const AddEmailsStep = (props: AddEmailsStepProps) => {
const filteredAccounts = dataPortion.filter(
(data) =>
data.firstName?.toLowerCase().startsWith(searchValue.toLowerCase()) ||
data.displayName.toLowerCase().startsWith(searchValue.toLowerCase()) ||
data.email.toLowerCase().startsWith(searchValue.toLowerCase()),
data.displayName?.toLowerCase().startsWith(searchValue.toLowerCase()) ||
data.email?.toLowerCase().startsWith(searchValue.toLowerCase()),
);
const handleStepIncrement = () => {
@ -190,12 +187,15 @@ const AddEmailsStep = (props: AddEmailsStepProps) => {
)}
</>
) : (
<Text fontWeight={600} lineHeight="20px" className="mb-17">
{t("Settings:WithoutEmailHint")}
</Text>
<>
<Text fontWeight={600} lineHeight="20px" className="mb-17">
{t("Settings:WithoutEmailHint")}
</Text>
{Buttons}
</>
)}
{Buttons}
{filteredAccounts.length > 0 && Buttons}
{cancelUploadDialogVisible && (
<CancelUploadDialog

View File

@ -42,7 +42,6 @@ const ImportProcessingStep = (props: ImportProcessingStepProps) => {
const {
t,
migratorName,
incrementStep,
setIsLoading,
proceedFileMigration,
@ -50,8 +49,7 @@ const ImportProcessingStep = (props: ImportProcessingStepProps) => {
} = props as InjectedImportProcessingStepProps;
const [percent, setPercent] = useState(0);
const [isVisible, setIsVisible] = useState(false);
const [isVisibleProgress, setIsVisibleProgress] = useState(false);
const [failTries, setFailTries] = useState(FAIL_TRIES);
const uploadInterval = useRef<number>();
@ -59,7 +57,7 @@ const ImportProcessingStep = (props: ImportProcessingStepProps) => {
const handleFileMigration = async () => {
setIsLoading(true);
setPercent(0);
setIsVisible(true);
setIsVisibleProgress(true);
try {
await proceedFileMigration(migratorName);
@ -78,17 +76,12 @@ const ImportProcessingStep = (props: ImportProcessingStepProps) => {
}
setPercent(res.progress);
if (res.progress > 10) {
setIsVisible(false);
} else {
setIsVisible(true);
}
setIsVisibleProgress(res.progress <= 10);
if (res.isCompleted || res.progress === 100) {
clearInterval(uploadInterval.current);
setIsLoading(false);
setIsVisible(false);
setIsVisibleProgress(false);
setPercent(100);
setTimeout(() => {
incrementStep();
@ -111,7 +104,7 @@ const ImportProcessingStep = (props: ImportProcessingStepProps) => {
<Wrapper>
<ProgressBar
percent={percent}
isInfiniteProgress={isVisible}
isInfiniteProgress={isVisibleProgress}
className="data-import-progress-bar"
/>
</Wrapper>

View File

@ -180,6 +180,7 @@ const ImportStep = (props: ImportStepProps) => {
workspace: t("Common:ProductName"),
sectionIcon: RoomsIcon,
}}
isDisabled={false}
/>
<ImportSection
isChecked={importOptions.importCommonFiles}

View File

@ -86,20 +86,22 @@ const Wrapper = styled.div`
const FileUploadContainer = styled.div`
max-width: 350px;
.cancel-btn {
@media ${mobile} {
height: 40px;
}
}
.cancelUploadButton {
@media ${mobile} {
margin-bottom: 0;
width: auto;
position: fixed;
inset-inline: 0px;
bottom: 0px;
padding: 16px;
background: white;
background: ${(props) =>
props.theme.client.settings.migration.workspaceBackground};
gap: 0;
}
}
@ -133,19 +135,15 @@ const FAIL_TRIES = 2;
const SelectFileStep = (props: SelectFileStepProps) => {
const {
t,
isMultipleUpload,
migratorName,
acceptedExtensions,
t,
incrementStep,
setWorkspace,
cancelUploadDialogVisible,
setCancelUploadDialogVisible,
initMigrationName,
singleFileUploading,
initMigrations,
getMigrationStatus,
setUsers,
cancelMigration,
@ -153,9 +151,9 @@ const SelectFileStep = (props: SelectFileStepProps) => {
setLoadingStatus,
files,
setFiles,
multipleFileUploading,
migratingWorkspace,
setMigratingWorkspace,
uploadFiles,
} = props as InjectedSelectFileStepProps;
const [isSaveDisabled, setIsSaveDisabled] = useState(
@ -174,9 +172,18 @@ const SelectFileStep = (props: SelectFileStepProps) => {
const [chunkSize, setChunkSize] = useState(0);
const [failTries, setFailTries] = useState(FAIL_TRIES);
const uploadInterval = useRef<number>();
const handleError = useCallback(
(message?: string) => {
toastr.error(message || t("Common:SomethingWentWrong"));
setIsFileError(true);
setLoadingStatus("none");
clearInterval(uploadInterval.current);
},
[t, setLoadingStatus],
);
const poolStatus = useCallback(async () => {
try {
const res = await getMigrationStatus();
@ -187,29 +194,24 @@ const SelectFileStep = (props: SelectFileStepProps) => {
}
if (!res) {
toastr.error(t("Common:SomethingWentWrong"));
setLoadingStatus("none");
clearInterval(uploadInterval.current);
handleError();
return;
}
if (res.parseResult.failedArchives.length > 0 || res.error) {
toastr.error(res.error);
setIsFileError(true);
setLoadingStatus("none");
clearInterval(uploadInterval.current);
handleError(res.error);
return;
}
if (res.isCompleted || res.progress === 100) {
clearInterval(uploadInterval.current);
if (
const totalUsers =
res.parseResult.users.length +
res.parseResult.existUsers.length +
res.parseResult.withoutEmailUsers.length >
0
) {
setUsers(res.parseResult);
res.parseResult.existUsers.length +
res.parseResult.withoutEmailUsers.length;
if (totalUsers > 0) {
setIsBackupEmpty(false);
setLoadingStatus("done");
setUsers(res.parseResult);
@ -228,15 +230,8 @@ const SelectFileStep = (props: SelectFileStepProps) => {
setIsInfiniteProgress(false);
}
} catch (error) {
if (error instanceof Error) {
if (error.message === "Network Error") {
setIsNetworkError(true);
}
toastr.error(error || t("Common:SomethingWentWrong"));
setIsFileError(true);
setLoadingStatus("none");
clearInterval(uploadInterval.current);
}
handleError(error as string);
setIsNetworkError(true);
}
}, [
failTries,
@ -244,49 +239,31 @@ const SelectFileStep = (props: SelectFileStepProps) => {
isInfiniteProgress,
setLoadingStatus,
setUsers,
t,
handleError,
]);
const onUploadFile = async (file: File | File[]) => {
try {
if (file instanceof Array) {
setFiles(file.map((item) => item.name));
await multipleFileUploading(
file,
setProgress,
isAbort,
setChunk,
startChunk,
setChunkSize,
chunkSize,
);
} else {
setFiles([file.name]);
await singleFileUploading(
file,
setProgress,
isAbort,
setChunk,
startChunk,
setChunkSize,
chunkSize,
);
}
const filesData = Array.isArray(file) ? file : [file];
setFiles(filesData.map((item) => item.name));
await uploadFiles(
filesData,
setProgress,
isAbort,
setChunk,
startChunk,
setChunkSize,
chunkSize,
);
if (isAbort.current) return;
await initMigrationName(migratorName);
await initMigrations(migratorName);
setLoadingStatus("proceed");
} catch (error) {
if (error instanceof Error) {
if (error.message === "Network Error") {
setIsNetworkError(true);
}
toastr.error(error || t("Common:SomethingWentWrong"));
setIsFileError(true);
setLoadingStatus("none");
}
handleError(error as string);
setIsNetworkError(true);
} finally {
isAbort.current = false;
}
@ -300,6 +277,7 @@ const SelectFileStep = (props: SelectFileStepProps) => {
setProgress(0);
setIsFileError(false);
setIsBackupEmpty(false);
setIsSaveDisabled(true);
setLoadingStatus("upload");
setFailTries(FAIL_TRIES);
@ -405,6 +383,7 @@ const SelectFileStep = (props: SelectFileStepProps) => {
}
accept={acceptedExtensions}
size={InputSize.base}
isMultiple={migratorName === "GoogleWorkspace"}
/>
</FileUploadContainer>
{fileLoadingStatus === "upload" || fileLoadingStatus === "proceed" ? (
@ -418,6 +397,7 @@ const SelectFileStep = (props: SelectFileStepProps) => {
<div className="cancelUploadButton">
<Button
size={isTablet() ? ButtonSize.medium : ButtonSize.small}
className="cancel-btn"
label={t("Common:CancelButton")}
onClick={onCancel}
scale={isMobile()}
@ -503,8 +483,7 @@ const SelectFileStep = (props: SelectFileStepProps) => {
export default inject<TStore>(({ dialogsStore, importAccountsStore }) => {
const {
initMigrationName,
singleFileUploading,
initMigrations,
getMigrationStatus,
setUsers,
fileLoadingStatus,
@ -514,16 +493,15 @@ export default inject<TStore>(({ dialogsStore, importAccountsStore }) => {
incrementStep,
files,
setFiles,
multipleFileUploading,
migratingWorkspace,
setMigratingWorkspace,
uploadFiles,
} = importAccountsStore;
const { cancelUploadDialogVisible, setCancelUploadDialogVisible } =
dialogsStore;
return {
initMigrationName,
singleFileUploading,
initMigrations,
getMigrationStatus,
setUsers,
fileLoadingStatus,
@ -535,8 +513,8 @@ export default inject<TStore>(({ dialogsStore, importAccountsStore }) => {
incrementStep,
files,
setFiles,
multipleFileUploading,
migratingWorkspace,
setMigratingWorkspace,
uploadFiles,
};
})(observer(SelectFileStep));

View File

@ -24,7 +24,7 @@
// 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 styled, { css } from "styled-components";
import styled from "styled-components";
import { Text } from "@docspace/shared/components/text";
import { Box } from "@docspace/shared/components/box";
import { RowContent } from "@docspace/shared/components/row-content";

View File

@ -26,7 +26,7 @@
import { inject, observer } from "mobx-react";
import { tablet } from "@docspace/shared/utils/device";
import styled, { css } from "styled-components";
import styled from "styled-components";
import { EmptyScreenContainer } from "@docspace/shared/components/empty-screen-container";
import { IconButton } from "@docspace/shared/components/icon-button";
@ -91,7 +91,6 @@ const RowView = (props: RowViewProps) => {
t,
sectionWidth,
accountsData,
checkedUsers,
withEmailUsers,
toggleAccount,

View File

@ -196,9 +196,12 @@ const SelectUsersStep = (props: SelectUsersStepProps) => {
)}
</>
) : (
<Text fontWeight={600} lineHeight="20px" className="mb-17">
{t("Settings:AddEmailsWarning")}
</Text>
<>
<Text fontWeight={600} lineHeight="20px" className="mb-17">
{t("Settings:AddEmailsWarning")}
</Text>
{Buttons}
</>
)}
{filteredAccounts.length > 0 && Buttons}

View File

@ -26,7 +26,7 @@
import { inject, observer } from "mobx-react";
import { tablet } from "@docspace/shared/utils/device";
import styled, { css } from "styled-components";
import styled from "styled-components";
import { EmptyScreenContainer } from "@docspace/shared/components/empty-screen-container";
import { IconButton } from "@docspace/shared/components/icon-button";
@ -55,7 +55,7 @@ const StyledRowContainer = styled(RowContainer)`
margin-inline-start: -16px;
width: 100%;
margin-top: -31.5px;
margin-top: -32.5px;
top: 53px;
margin-bottom: -29.5px;

View File

@ -27,7 +27,7 @@
import { useRef } from "react";
import { inject, observer } from "mobx-react";
import { Base } from "@docspace/shared/themes";
import styled, { css } from "styled-components";
import styled from "styled-components";
import { EmptyScreenContainer } from "@docspace/shared/components/empty-screen-container";
import { IconButton } from "@docspace/shared/components/icon-button";
@ -97,7 +97,6 @@ const TableView = (props: TypeSelectTableViewProps) => {
sectionWidth,
accountsData,
typeOptions,
userId,
checkedUsers,
toggleAccount,

View File

@ -27,9 +27,9 @@
import { useEffect, useCallback } from "react";
import { inject, observer } from "mobx-react";
import { useTranslation } from "react-i18next";
import useViewEffect from "SRC_DIR/Hooks/useViewEffect";
import { setDocumentTitle } from "SRC_DIR/helpers/utils";
import { toastr } from "@docspace/shared/components/toast";
import { setDocumentTitle } from "SRC_DIR/helpers/utils";
import useViewEffect from "SRC_DIR/Hooks/useViewEffect";
import { DataImportProps, InjectedDataImportProps } from "./types";
@ -43,7 +43,6 @@ const DataImport = (props: DataImportProps) => {
viewAs,
setViewAs,
currentDeviceType,
getMigrationStatus,
isMigrationInit,
setUsers,
@ -74,15 +73,14 @@ const DataImport = (props: DataImportProps) => {
const { parseResult, error, isCompleted } = response;
if (
error ||
parseResult.failedArchives.length > 0 ||
const isErrorOrFailedParse = error || parseResult.failedArchives.length > 0;
const isNoUsersParsed =
parseResult.users.length +
parseResult.existUsers.length +
parseResult.withoutEmailUsers.length ===
0
)
return;
0;
if (isErrorOrFailedParse || isNoUsersParsed) return;
if (parseResult.operation === "parse") {
setWorkspace(parseResult.migratorName);
@ -140,7 +138,7 @@ const DataImport = (props: DataImportProps) => {
};
export default inject<TStore>(
({ authStore, settingsStore, setup, importAccountsStore }) => {
({ settingsStore, setup, importAccountsStore }) => {
const {
getMigrationStatus,
isMigrationInit,
@ -160,7 +158,6 @@ export default inject<TStore>(
viewAs,
setViewAs,
currentDeviceType,
getMigrationStatus,
isMigrationInit,
setUsers,

View File

@ -59,8 +59,7 @@ export interface InjectedSelectFileStepProps extends SelectFileStepProps {
setWorkspace: TStore["importAccountsStore"]["setWorkspace"];
cancelUploadDialogVisible: TStore["dialogsStore"]["cancelUploadDialogVisible"];
setCancelUploadDialogVisible: TStore["dialogsStore"]["setCancelUploadDialogVisible"];
initMigrationName: TStore["importAccountsStore"]["initMigrationName"];
singleFileUploading: TStore["importAccountsStore"]["singleFileUploading"];
initMigrations: TStore["importAccountsStore"]["initMigrations"];
getMigrationStatus: TStore["importAccountsStore"]["getMigrationStatus"];
setUsers: TStore["importAccountsStore"]["setUsers"];
fileLoadingStatus: TStore["importAccountsStore"]["fileLoadingStatus"];
@ -68,15 +67,14 @@ export interface InjectedSelectFileStepProps extends SelectFileStepProps {
cancelMigration: TStore["importAccountsStore"]["cancelMigration"];
files: TStore["importAccountsStore"]["files"];
setFiles: TStore["importAccountsStore"]["setFiles"];
multipleFileUploading: TStore["importAccountsStore"]["multipleFileUploading"];
migratingWorkspace: TStore["importAccountsStore"]["migratingWorkspace"];
setMigratingWorkspace: TStore["importAccountsStore"]["setMigratingWorkspace"];
uploadFiles: TStore["importAccountsStore"]["uploadFiles"];
}
export interface DataImportProps {}
export interface InjectedDataImportProps extends DataImportProps {
setDocumentTitle: TStore["authStore"]["setDocumentTitle"];
getMigrationStatus: TStore["importAccountsStore"]["getMigrationStatus"];
viewAs: TStore["setup"]["viewAs"];
setViewAs: TStore["setup"]["setViewAs"];
@ -102,8 +100,6 @@ export interface InjectedWorkspaceProps extends WorkspaceProps {
migrationPhase: TStore["importAccountsStore"]["migrationPhase"];
isMigrationInit: TStore["importAccountsStore"]["isMigrationInit"];
setIsMigrationInit: TStore["importAccountsStore"]["setIsMigrationInit"];
setDocumentTitle: TStore["authStore"]["setDocumentTitle"];
}
export interface LayoutProps {
@ -172,6 +168,7 @@ export interface InjectedTableViewProps extends TableViewProps {
export interface AddEmailTableProps extends InjectedTableViewProps {
users: TStore["importAccountsStore"]["users"];
setSearchValue: TStore["importAccountsStore"]["setSearchValue"];
}
export interface SelectUserTableProps extends InjectedTableViewProps {
@ -223,6 +220,7 @@ export interface AddEmailRowProps extends RowViewProps {
toggleAccount: TStore["importAccountsStore"]["toggleAccount"];
toggleAllAccounts: TStore["importAccountsStore"]["toggleAllAccounts"];
isAccountChecked: TStore["importAccountsStore"]["isAccountChecked"];
setSearchValue: TStore["importAccountsStore"]["setSearchValue"];
}
export interface UsersRowProps {

View File

@ -27,6 +27,7 @@
import axios from "axios";
import { uploadFile } from "@docspace/shared/api/files";
import { combineUrl } from "@docspace/shared/utils/combineUrl";
import { toastr } from "@docspace/shared/components/toast";
import { makeAutoObservable, runInAction } from "mobx";
import {
migrationList,
@ -328,8 +329,8 @@ class ImportAccountsStore {
};
};
multipleFileUploading = async (
files: File[],
uploadFiles = async (
filesData: File | File[],
setProgress: (progress: number) => void,
isAbort: React.MutableRefObject<boolean>,
setChunk: React.Dispatch<React.SetStateAction<number>>,
@ -338,29 +339,34 @@ class ImportAccountsStore {
chunkSize: number,
) => {
let chunk = 0;
const location = combineUrl(
window.location.origin,
"migrationFileUpload.ashx",
);
try {
const location = combineUrl(
window.location.origin,
"migrationFileUpload.ashx",
);
const requestsDataArray: { formData: FormData; fileName: string }[] = [];
let chunkUploadSize = chunkSize;
let chunkUploadSize = 0;
if (!chunkSize) {
const res = await axios.post<{
Success: boolean;
ChunkSize: number;
Message: string;
}>(`${location}?Init=${startChunk === 0}`);
if (chunkSize) {
chunkUploadSize = chunkSize;
} else {
const res: { data: { ChunkSize: number } } = await axios.post(
`${location}?Init=${startChunk === 0}`,
);
if (!res.data.Success) {
toastr.error(res.data.Message);
throw new Error(res.data.Message);
}
chunkUploadSize = res.data.ChunkSize;
setChunkSize(chunkUploadSize);
}
if (!chunkUploadSize) return;
if (!chunkUploadSize || isAbort.current) return;
if (isAbort.current) return;
const requestsDataArray: { formData: FormData; fileName: string }[] = [];
const files = Array.isArray(filesData) ? filesData : [filesData];
const chunksNumber = files
.map((file) => Math.ceil(file.size / chunkUploadSize))
@ -396,74 +402,9 @@ class ImportAccountsStore {
setProgress(Math.ceil(progress));
chunk += 1;
}
} catch (e) {
setChunk(chunk);
}
};
singleFileUploading = async (
file: File,
setProgress: (progress: number) => void,
isAbort: React.MutableRefObject<boolean>,
setChunk: React.Dispatch<React.SetStateAction<number>>,
startChunk: number,
setChunkSize: React.Dispatch<React.SetStateAction<number>>,
chunkSize: number,
) => {
let chunk = 0;
try {
const location = combineUrl(
window.location.origin,
"migrationFileUpload.ashx",
);
let chunkUploadSize = 0;
if (chunkSize) {
chunkUploadSize = chunkSize;
} else {
const res: { data: { ChunkSize: number } } = await axios.post(
`${location}?Init=${startChunk === 0}`,
);
chunkUploadSize = res.data.ChunkSize;
setChunkSize(chunkUploadSize);
}
if (!chunkUploadSize) return;
const requestsDataArray = [];
const chunks = Math.ceil(file.size / chunkUploadSize);
if (isAbort.current) return;
while (chunk < chunks) {
const offset = chunk * chunkUploadSize;
const formData = new FormData();
formData.append("file", file.slice(offset, offset + chunkUploadSize));
requestsDataArray.push(formData);
chunk += 1;
}
chunk = startChunk || 0;
while (
chunk < chunks &&
(this.fileLoadingStatus === "upload" ||
this.fileLoadingStatus === "proceed")
) {
if (isAbort.current) return;
// eslint-disable-next-line no-await-in-loop
await uploadFile(
`${location}?Name=${file.name}`,
requestsDataArray[chunk],
);
const progress = (chunk / chunks) * 100;
setProgress(Math.ceil(progress));
chunk += 1;
}
} catch (e) {
} catch (error) {
setChunk(chunk);
throw new Error(error as string);
}
};
@ -481,7 +422,7 @@ class ImportAccountsStore {
};
// eslint-disable-next-line class-methods-use-this
initMigrationName = (name: TWorkspaceService) => {
initMigrations = (name: TWorkspaceService) => {
return initMigration(name);
};