Web: Client: Data Import: nextcloud select file step was translated into ts
This commit is contained in:
parent
515fc32865
commit
69b579521f
@ -52,7 +52,7 @@ export const getStepsData = (
|
||||
{
|
||||
title: t("Common:SelectFile"),
|
||||
description: t("Settings:SelectFileDescriptionNextcloud"),
|
||||
component: <SelectFileStep t={t} incrementStep={incrementStep} />,
|
||||
component: <SelectFileStep t={t} />,
|
||||
},
|
||||
{
|
||||
title: t("Settings:SelectUsersWithEmail"),
|
||||
|
@ -0,0 +1,404 @@
|
||||
// (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 { useState, useRef, useEffect, useCallback } from "react";
|
||||
import { inject, observer } from "mobx-react";
|
||||
import { CancelUploadDialog } from "SRC_DIR/components/dialogs";
|
||||
import { isTablet } from "@docspace/shared/utils/device";
|
||||
import styled from "styled-components";
|
||||
|
||||
import { Text } from "@docspace/shared/components/text";
|
||||
import { Button, ButtonSize } from "@docspace/shared/components/button";
|
||||
import { FileInput } from "@docspace/shared/components/file-input";
|
||||
import { ProgressBar } from "@docspace/shared/components/progress-bar";
|
||||
import { SaveCancelButtons } from "@docspace/shared/components/save-cancel-buttons";
|
||||
import { Box } from "@docspace/shared/components/box";
|
||||
import { Link, LinkType } from "@docspace/shared/components/link";
|
||||
import { toastr } from "@docspace/shared/components/toast";
|
||||
import { InputSize } from "@docspace/shared/components/text-input";
|
||||
import { InjectedSelectFileStepProps, SelectFileStepProps } from "../types";
|
||||
|
||||
const Wrapper = styled.div`
|
||||
max-width: 700px;
|
||||
margin-top: 16px;
|
||||
|
||||
.choose-backup-file {
|
||||
font-weight: 600;
|
||||
line-height: 20px;
|
||||
margin-bottom: 4px;
|
||||
}
|
||||
|
||||
.upload-backup-input {
|
||||
height: 32px;
|
||||
margin-bottom: 12px;
|
||||
|
||||
.icon-button_svg {
|
||||
svg {
|
||||
path {
|
||||
fill: ${(props) =>
|
||||
props.theme.client.settings.migration.fileInputIconColor};
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.upload-back-buttons {
|
||||
margin-top: 16px;
|
||||
}
|
||||
|
||||
.select-file-progress-text {
|
||||
margin: 12px 0;
|
||||
}
|
||||
|
||||
.select-file-progress-bar {
|
||||
margin: 12px 0 16px;
|
||||
}
|
||||
`;
|
||||
|
||||
const FileUploadContainer = styled.div`
|
||||
max-width: 350px;
|
||||
`;
|
||||
|
||||
const ErrorBlock = styled.div`
|
||||
max-width: 700px;
|
||||
|
||||
.complete-progress-bar {
|
||||
margin: 12px 0 16px;
|
||||
max-width: 350px;
|
||||
}
|
||||
|
||||
.error-text {
|
||||
font-size: 12px;
|
||||
margin-bottom: 10px;
|
||||
color: ${(props) => props.theme.client.settings.migration.errorTextColor};
|
||||
}
|
||||
|
||||
.save-cancel-buttons {
|
||||
margin-top: 16px;
|
||||
}
|
||||
`;
|
||||
|
||||
const FAIL_TRIES = 2;
|
||||
|
||||
const SelectFileStep = (props: SelectFileStepProps) => {
|
||||
const {
|
||||
t,
|
||||
incrementStep,
|
||||
setWorkspace,
|
||||
|
||||
cancelUploadDialogVisible,
|
||||
setCancelUploadDialogVisible,
|
||||
|
||||
initMigrationName,
|
||||
singleFileUploading,
|
||||
getMigrationStatus,
|
||||
setUsers,
|
||||
cancelMigration,
|
||||
fileLoadingStatus,
|
||||
setLoadingStatus,
|
||||
files,
|
||||
setFiles,
|
||||
} = props as InjectedSelectFileStepProps;
|
||||
|
||||
const [isSaveDisabled, setIsSaveDisabled] = useState(true);
|
||||
const [progress, setProgress] = useState(0);
|
||||
const [isInfiniteProgress, setIsInfiniteProgress] = useState(true);
|
||||
|
||||
const [isError, setIsError] = useState(false);
|
||||
const [isFileError, setIsFileError] = useState(false);
|
||||
const isAbort = useRef(false);
|
||||
|
||||
const [failTries, setFailTries] = useState(FAIL_TRIES);
|
||||
|
||||
const uploadInterval = useRef<number>();
|
||||
|
||||
const onUploadToServer = () => {
|
||||
console.log("handle internet abortion");
|
||||
};
|
||||
|
||||
const poolStatus = useCallback(async () => {
|
||||
try {
|
||||
const res = await getMigrationStatus();
|
||||
|
||||
if (!res && failTries) {
|
||||
setFailTries((prevTries) => prevTries - 1);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!res) {
|
||||
toastr.error(t("Common:SomethingWentWrong"));
|
||||
setLoadingStatus("none");
|
||||
clearInterval(uploadInterval.current);
|
||||
return;
|
||||
}
|
||||
|
||||
if (res.parseResult.failedArchives.length > 0 || res.error) {
|
||||
toastr.error(res.error);
|
||||
setIsFileError(true);
|
||||
setLoadingStatus("none");
|
||||
clearInterval(uploadInterval.current);
|
||||
return;
|
||||
}
|
||||
|
||||
if (res.isCompleted || res.progress === 100) {
|
||||
clearInterval(uploadInterval.current);
|
||||
setUsers(res.parseResult);
|
||||
|
||||
setLoadingStatus("done");
|
||||
setIsInfiniteProgress(false);
|
||||
setIsSaveDisabled(false);
|
||||
}
|
||||
|
||||
setProgress(res.progress);
|
||||
|
||||
if (isInfiniteProgress && res.progress > 10) {
|
||||
setIsInfiniteProgress(false);
|
||||
}
|
||||
} catch (error) {
|
||||
toastr.error(error || t("Common:SomethingWentWrong"));
|
||||
setIsFileError(true);
|
||||
setLoadingStatus("none");
|
||||
setIsError(true);
|
||||
clearInterval(uploadInterval.current);
|
||||
}
|
||||
}, [
|
||||
failTries,
|
||||
getMigrationStatus,
|
||||
isInfiniteProgress,
|
||||
setLoadingStatus,
|
||||
setUsers,
|
||||
t,
|
||||
]);
|
||||
|
||||
const onUploadFile = async (file: File) => {
|
||||
try {
|
||||
await singleFileUploading(file, setProgress, isAbort);
|
||||
|
||||
if (isAbort.current) return;
|
||||
|
||||
await initMigrationName("Nextcloud");
|
||||
setLoadingStatus("proceed");
|
||||
} catch (error) {
|
||||
toastr.error(error || t("Common:SomethingWentWrong"));
|
||||
setIsFileError(true);
|
||||
setLoadingStatus("none");
|
||||
} finally {
|
||||
isAbort.current = false;
|
||||
}
|
||||
};
|
||||
|
||||
const onSelectFile = (file: File | File[]) => {
|
||||
if (file instanceof Array) {
|
||||
toastr.error(t("Common:SomethingWentWrong"));
|
||||
return;
|
||||
}
|
||||
|
||||
setProgress(0);
|
||||
setIsFileError(false);
|
||||
setIsSaveDisabled(true);
|
||||
setLoadingStatus("upload");
|
||||
setFailTries(FAIL_TRIES);
|
||||
setIsInfiniteProgress(true);
|
||||
setFiles([file.name]);
|
||||
|
||||
onUploadFile(file);
|
||||
};
|
||||
|
||||
const onDownloadArchives = async () => {
|
||||
try {
|
||||
const res = await getMigrationStatus();
|
||||
|
||||
if (!res) {
|
||||
throw new Error();
|
||||
}
|
||||
|
||||
const blob = new Blob(res.parseResult.failedArchives, {
|
||||
type: "text/csv;charset=utf-8",
|
||||
});
|
||||
const a = document.createElement("a");
|
||||
const url = window.URL.createObjectURL(blob);
|
||||
a.href = url;
|
||||
a.download = "unsupported_files";
|
||||
a.click();
|
||||
window.URL.revokeObjectURL(url);
|
||||
} catch (error) {
|
||||
toastr.error(error || t("Common:SomethingWentWrong"));
|
||||
}
|
||||
};
|
||||
|
||||
const onCancel = () => {
|
||||
setCancelUploadDialogVisible(true);
|
||||
};
|
||||
|
||||
const handleCancelMigration = () => {
|
||||
isAbort.current = true;
|
||||
setProgress(0);
|
||||
setLoadingStatus("none");
|
||||
clearInterval(uploadInterval.current);
|
||||
cancelMigration();
|
||||
};
|
||||
|
||||
const hideCancelDialog = () => setCancelUploadDialogVisible(false);
|
||||
const returnToProviders = () => setWorkspace("");
|
||||
|
||||
useEffect(() => {
|
||||
if (fileLoadingStatus === "proceed") {
|
||||
uploadInterval.current = window.setInterval(poolStatus, 1000);
|
||||
} else if (fileLoadingStatus === "done") {
|
||||
setIsSaveDisabled(false);
|
||||
}
|
||||
|
||||
return () => clearInterval(uploadInterval.current);
|
||||
}, [fileLoadingStatus, poolStatus]);
|
||||
|
||||
return (
|
||||
<Wrapper>
|
||||
<FileUploadContainer>
|
||||
<Text className="choose-backup-file">
|
||||
{t("Settings:ChooseBackupFile")}
|
||||
</Text>
|
||||
<FileInput
|
||||
scale
|
||||
onInput={onSelectFile}
|
||||
className="upload-backup-input"
|
||||
placeholder={files.join(",") || t("Settings:BackupFile")}
|
||||
isDisabled={
|
||||
fileLoadingStatus === "upload" || fileLoadingStatus === "proceed"
|
||||
}
|
||||
accept={[".zip"]}
|
||||
size={InputSize.base}
|
||||
/>
|
||||
</FileUploadContainer>
|
||||
{fileLoadingStatus === "upload" || fileLoadingStatus === "proceed" ? (
|
||||
<FileUploadContainer>
|
||||
<ProgressBar
|
||||
percent={progress}
|
||||
isInfiniteProgress={isInfiniteProgress}
|
||||
className="select-file-progress-bar"
|
||||
label={t("Settings:BackupFileUploading")}
|
||||
/>
|
||||
<Button
|
||||
size={isTablet() ? ButtonSize.medium : ButtonSize.small}
|
||||
label={t("Common:CancelButton")}
|
||||
onClick={onCancel}
|
||||
/>
|
||||
</FileUploadContainer>
|
||||
) : (
|
||||
<ErrorBlock>
|
||||
{isFileError && (
|
||||
<Box>
|
||||
<ProgressBar
|
||||
percent={100}
|
||||
className="complete-progress-bar"
|
||||
label={t("Common:LoadingIsComplete")}
|
||||
/>
|
||||
<Text className="error-text">
|
||||
{t("Settings:UnsupportedFilesDescription")}
|
||||
</Text>
|
||||
<Link
|
||||
type={LinkType.action}
|
||||
isHovered
|
||||
fontWeight={600}
|
||||
onClick={onDownloadArchives}
|
||||
>
|
||||
{t("Settings:CheckUnsupportedFiles")}
|
||||
</Link>
|
||||
</Box>
|
||||
)}
|
||||
|
||||
{isError ? (
|
||||
<SaveCancelButtons
|
||||
className="save-cancel-buttons"
|
||||
onSaveClick={onUploadToServer}
|
||||
onCancelClick={returnToProviders}
|
||||
saveButtonLabel={t("Settings:UploadToServer")}
|
||||
cancelButtonLabel={t("Common:Back")}
|
||||
displaySettings
|
||||
saveButtonDisabled={isSaveDisabled}
|
||||
showReminder
|
||||
/>
|
||||
) : (
|
||||
<SaveCancelButtons
|
||||
className="save-cancel-buttons"
|
||||
onSaveClick={incrementStep}
|
||||
onCancelClick={returnToProviders}
|
||||
saveButtonLabel={t("Settings:NextStep")}
|
||||
cancelButtonLabel={t("Common:Back")}
|
||||
displaySettings
|
||||
saveButtonDisabled={isSaveDisabled}
|
||||
showReminder
|
||||
/>
|
||||
)}
|
||||
</ErrorBlock>
|
||||
)}
|
||||
|
||||
{cancelUploadDialogVisible && (
|
||||
<CancelUploadDialog
|
||||
visible={cancelUploadDialogVisible}
|
||||
onClose={hideCancelDialog}
|
||||
cancelMigration={handleCancelMigration}
|
||||
loading={false}
|
||||
isFifthStep={false}
|
||||
isSixthStep={false}
|
||||
/>
|
||||
)}
|
||||
</Wrapper>
|
||||
);
|
||||
};
|
||||
|
||||
export default inject<TStore>(({ dialogsStore, importAccountsStore }) => {
|
||||
const {
|
||||
initMigrationName,
|
||||
singleFileUploading,
|
||||
getMigrationStatus,
|
||||
setUsers,
|
||||
fileLoadingStatus,
|
||||
setLoadingStatus,
|
||||
cancelMigration,
|
||||
setWorkspace,
|
||||
incrementStep,
|
||||
files,
|
||||
setFiles,
|
||||
} = importAccountsStore;
|
||||
const { cancelUploadDialogVisible, setCancelUploadDialogVisible } =
|
||||
dialogsStore;
|
||||
|
||||
return {
|
||||
initMigrationName,
|
||||
singleFileUploading,
|
||||
getMigrationStatus,
|
||||
setUsers,
|
||||
fileLoadingStatus,
|
||||
setLoadingStatus,
|
||||
cancelMigration,
|
||||
cancelUploadDialogVisible,
|
||||
setCancelUploadDialogVisible,
|
||||
setWorkspace,
|
||||
incrementStep,
|
||||
files,
|
||||
setFiles,
|
||||
};
|
||||
})(observer(SelectFileStep));
|
@ -50,6 +50,7 @@ const DataImport = (props: DataImportProps) => {
|
||||
setWorkspace,
|
||||
setFiles,
|
||||
setIsMigrationInit,
|
||||
setLoadingStatus,
|
||||
} = props as InjectedDataImportProps;
|
||||
|
||||
const { t } = useTranslation(["Settings"]);
|
||||
@ -76,13 +77,15 @@ const DataImport = (props: DataImportProps) => {
|
||||
setWorkspace(parseResult.migratorName);
|
||||
setFiles(parseResult.files);
|
||||
setIsMigrationInit(true);
|
||||
setLoadingStatus("done");
|
||||
}
|
||||
}, [
|
||||
getMigrationStatus,
|
||||
setIsMigrationInit,
|
||||
setFiles,
|
||||
setUsers,
|
||||
setWorkspace,
|
||||
setFiles,
|
||||
setIsMigrationInit,
|
||||
setLoadingStatus,
|
||||
]);
|
||||
|
||||
useEffect(() => {
|
||||
@ -116,6 +119,7 @@ export default inject<TStore>(
|
||||
setWorkspace,
|
||||
setFiles,
|
||||
setIsMigrationInit,
|
||||
setLoadingStatus,
|
||||
} = importAccountsStore;
|
||||
|
||||
const { setDocumentTitle } = authStore;
|
||||
@ -135,6 +139,7 @@ export default inject<TStore>(
|
||||
setWorkspace,
|
||||
setFiles,
|
||||
setIsMigrationInit,
|
||||
setLoadingStatus,
|
||||
};
|
||||
},
|
||||
)(observer(DataImport));
|
||||
|
@ -44,16 +44,23 @@ export interface InjectedProvidersProps extends ProvidersProps {
|
||||
|
||||
export interface SelectFileStepProps {
|
||||
t: TFunciton;
|
||||
incrementStep: () => void;
|
||||
}
|
||||
|
||||
export interface InjectedSelectFileStepProps extends SelectFileStepProps {
|
||||
t: TFunciton;
|
||||
incrementStep: TStore["importAccountsStore"]["incrementStep"];
|
||||
setWorkspace: TStore["importAccountsStore"]["setWorkspace"];
|
||||
cancelUploadDialogVisible: TStore["dialogsStore"]["cancelUploadDialogVisible"];
|
||||
setCancelUploadDialogVisible: TStore["dialogsStore"]["setCancelUploadDialogVisible"];
|
||||
initMigrationName: TStore["importAccountsStore"]["initMigrationName"];
|
||||
singleFileUploading: TStore["importAccountsStore"]["singleFileUploading"];
|
||||
getMigrationStatus: TStore["importAccountsStore"]["getMigrationStatus"];
|
||||
setUsers: TStore["importAccountsStore"]["setUsers"];
|
||||
isFileLoading: TStore["importAccountsStore"]["isFileLoading"];
|
||||
setIsFileLoading: TStore["importAccountsStore"]["setIsFileLoading"];
|
||||
fileLoadingStatus: TStore["importAccountsStore"]["fileLoadingStatus"];
|
||||
setLoadingStatus: TStore["importAccountsStore"]["setLoadingStatus"];
|
||||
cancelMigration: TStore["importAccountsStore"]["cancelMigration"];
|
||||
files: TStore["importAccountsStore"]["files"];
|
||||
setFiles: TStore["importAccountsStore"]["setFiles"];
|
||||
}
|
||||
|
||||
export interface DataImportProps {}
|
||||
@ -70,6 +77,7 @@ export interface InjectedDataImportProps extends DataImportProps {
|
||||
setWorkspace: TStore["importAccountsStore"]["setWorkspace"];
|
||||
setFiles: TStore["importAccountsStore"]["setFiles"];
|
||||
setIsMigrationInit: TStore["importAccountsStore"]["setIsMigrationInit"];
|
||||
setLoadingStatus: TStore["importAccountsStore"]["setLoadingStatus"];
|
||||
}
|
||||
|
||||
export interface NextcloudProps {}
|
||||
|
@ -60,6 +60,8 @@ type TCheckedUsers = {
|
||||
|
||||
type CheckedAccountTypes = "withEmail" | "withoutEmail" | "result";
|
||||
|
||||
type LoadingState = "none" | "upload" | "proceed" | "done";
|
||||
|
||||
class ImportAccountsStore {
|
||||
services: TWorkspaceService[] = [];
|
||||
|
||||
@ -82,7 +84,7 @@ class ImportAccountsStore {
|
||||
User: "Collaborator",
|
||||
};
|
||||
|
||||
isFileLoading = false;
|
||||
fileLoadingStatus: LoadingState = "none";
|
||||
|
||||
isLoading = false;
|
||||
|
||||
@ -194,8 +196,8 @@ class ImportAccountsStore {
|
||||
});
|
||||
};
|
||||
|
||||
setIsFileLoading = (isLoading: boolean) => {
|
||||
this.isFileLoading = isLoading;
|
||||
setLoadingStatus = (status: LoadingState) => {
|
||||
this.fileLoadingStatus = status;
|
||||
};
|
||||
|
||||
setIsLoading = (isLoading: boolean) => {
|
||||
@ -339,7 +341,11 @@ class ImportAccountsStore {
|
||||
|
||||
let chunk = 0;
|
||||
|
||||
while (chunk < chunksNumber && this.isFileLoading) {
|
||||
while (
|
||||
chunk < chunksNumber &&
|
||||
(this.fileLoadingStatus === "upload" ||
|
||||
this.fileLoadingStatus === "proceed")
|
||||
) {
|
||||
if (isAbort.current) return;
|
||||
// eslint-disable-next-line no-await-in-loop
|
||||
await uploadFile(
|
||||
@ -387,7 +393,11 @@ class ImportAccountsStore {
|
||||
}
|
||||
|
||||
chunk = 0;
|
||||
while (chunk < chunks && this.isFileLoading) {
|
||||
while (
|
||||
chunk < chunks &&
|
||||
(this.fileLoadingStatus === "upload" ||
|
||||
this.fileLoadingStatus === "proceed")
|
||||
) {
|
||||
if (isAbort.current) return;
|
||||
// eslint-disable-next-line no-await-in-loop
|
||||
await uploadFile(
|
||||
@ -400,8 +410,6 @@ class ImportAccountsStore {
|
||||
}
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
} finally {
|
||||
isAbort.current = false;
|
||||
}
|
||||
};
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user