Web: Backup: Added direct third-party connection component.

This commit is contained in:
Tatiana Lopaeva 2022-07-26 12:03:35 +03:00
parent 5877abf2e1
commit 5dccd8f52c
7 changed files with 568 additions and 73 deletions

View File

@ -699,6 +699,32 @@ export function saveThirdParty(
return request({ method: "post", url: "files/thirdparty", data });
}
export function saveSettingsThirdParty(
url,
login,
password,
token,
isCorporate,
customerTitle,
providerKey,
providerId
) {
const data = {
url,
login,
password,
token,
isCorporate,
customerTitle,
providerKey,
providerId,
};
return request({ method: "post", url: "files/thirdparty/backup", data });
}
export function getSettingsThirdParty() {
return request({ method: "get", url: "files/thirdparty/backup" });
}
export function deleteThirdParty(providerId) {
return request({ method: "delete", url: `files/thirdparty/${providerId}` });
}

View File

@ -25,11 +25,9 @@ class SelectFolderInput extends React.PureComponent {
};
this._isMount = false;
}
async componentDidMount() {
this._isMount = true;
setBaseInfo = async () => {
const {
setFirstLoad,
treeFolders,
foldersType,
id,
@ -38,8 +36,6 @@ class SelectFolderInput extends React.PureComponent {
withoutBasicSelection,
} = this.props;
setFirstLoad(false);
let resultingFolderTree, resultingId;
try {
@ -68,11 +64,19 @@ class SelectFolderInput extends React.PureComponent {
resultingFolderTree,
baseId: resultingId,
});
};
componentDidMount() {
this._isMount = true;
const { setFirstLoad } = this.props;
setFirstLoad(false);
this.setBaseInfo();
}
componentDidUpdate(prevProps) {
const { isSuccessSave, isReset, id } = this.props;
const { newFolderPath, baseFolderPath } = this.state;
const { newFolderPath, baseFolderPath, foldersList } = this.state;
if (!isSuccessSave && isSuccessSave !== prevProps.isSuccessSave) {
newFolderPath &&
@ -90,6 +94,10 @@ class SelectFolderInput extends React.PureComponent {
newId: null,
});
}
if (foldersList !== prevProps.foldersList) {
this.setBaseInfo();
}
}
componentWillUnmount() {

View File

@ -4,7 +4,7 @@ import { inject, observer } from "mobx-react";
import { BackupStorageType } from "@appserver/common/constants";
import SelectFolderInput from "files/SelectFolderInput";
import ScheduleComponent from "./ScheduleComponent";
import DirectConnectionContainer from "../../common-container/DirectConnectionContainer";
import DirectThirdPartyConnection from "../../common-container/DirectThirdPartyConnection";
class ThirdPartyModule extends React.PureComponent {
constructor(props) {
@ -91,7 +91,7 @@ class ThirdPartyModule extends React.PureComponent {
t,
...rest
} = this.props;
console.log("passedId", passedId);
return (
<>
{!isDocSpace ? (
@ -113,27 +113,18 @@ class ThirdPartyModule extends React.PureComponent {
</div>
) : (
<div className="auto-backup_third-party-module">
<DirectConnectionContainer
accounts={this.accounts}
selectedAccount={selectedAccount}
onSelectAccount={this.onSelectAccount}
onConnect={this.onConnect}
<DirectThirdPartyConnection
t={t}
/>
<SelectFolderInput
onSelectFolder={this.onSelectFolder}
onClose={this.onClose}
onClickInput={this.onClickInput}
isDisabled={isLoadingData}
isPanelVisible={isPanelVisible}
withoutBasicSelection={isResourcesDefault ? false : true}
isError={isError}
foldersType="third-party"
isDisabled={isLoadingData || !isConnected}
id={passedId}
isReset={isResetProcess}
isSuccessSave={isSavingProcess}
foldersList={commonThirdPartyList}
withoutBasicSelection={isResourcesDefault ? false : true}
id={passedId}
/>
</div>
)}
@ -158,7 +149,7 @@ export default inject(({ backup }) => {
defaultStorageType === `${BackupStorageType.ResourcesModuleType}`;
const passedId = isResourcesDefault ? defaultFolderId : "";
const isDocSpace = false;
const isDocSpace = true;
return {
isResetProcess,
isSavingProcess,

View File

@ -0,0 +1,287 @@
import React, { useEffect, useState } from "react";
import Button from "@appserver/components/button";
import SelectFolderInput from "files/SelectFolderInput";
import {
getSettingsThirdParty,
getThirdPartyCapabilities,
saveSettingsThirdParty,
} from "@appserver/common/api/files";
import { StyledBackup } from "../StyledBackup";
import Text from "@appserver/components/text";
import ComboBox from "@appserver/components/combobox";
import toastr from "@appserver/components/toast/toastr";
import FormConnection from "./FormConnection";
import { inject, observer } from "mobx-react";
let accounts = [];
const DirectThirdPartyConnection = (props) => {
const {
openConnectWindow,
getOAuthToken,
t,
onSelectFolder,
onClose,
onClickInput,
onSetLoadingData,
isDisabled,
isPanelVisible,
withoutBasicSelection,
isError,
id,
isReset,
isSuccessSave,
} = props;
useEffect(() => {
updateAccountsInfo();
}, []);
const updateAccountsInfo = async () => {
try {
setIsLoading(true);
const connectedAccount = await getConnectedAccounts();
onSetThirdPartySettings(
connectedAccount?.providerKey,
connectedAccount?.providerId,
connectedAccount
);
} catch (e) {
setIsLoading(false);
if (!e) return;
toastr.error(e);
}
};
const onSetThirdPartySettings = async (providerKey, providerId, account) => {
try {
!isLoading && setIsLoading(true);
const capabilities = await getThirdPartyCapabilities();
accounts = [];
let connectedAccount = {};
for (let i = 0; i < capabilities.length; i++) {
const isConnected = capabilities[i][0] === providerKey;
if (capabilities[i][0] !== "WebDav") {
accounts.push({
key: i.toString(),
label: capabilities[i][0],
provider_key: capabilities[i][0],
...(capabilities[i][1] && { provider_link: capabilities[i][1] }),
connected: isConnected,
...(isConnected && {
provider_id: providerId,
}),
});
if (isConnected) {
connectedAccount = { ...accounts[i] };
}
} else {
const WebDavVariability = [
"Nextcloud",
"ownCloud",
"ConnextOtherAccount",
];
let index = 0;
for (let j = i; j < i + 3; j++) {
accounts.push({
key: j.toString(),
label: WebDavVariability[index],
provider_key: "WebDav",
connected: isConnected,
...(isConnected && {
provider_id: providerId,
}),
});
// if (isConnected) { //TODO: changed for WebDav
// connectedAccount = { ...accounts[j] };
// }
index++;
}
}
}
setSelectedAccount(
Object.keys(connectedAccount).length !== 0
? connectedAccount
: { ...accounts[0] }
);
setFolderList(account ? account : []);
} catch (e) {
if (!e) return;
toastr.error(e);
}
setIsLoading(false);
};
const [selectedAccount, setSelectedAccount] = useState({});
const [isLoading, setIsLoading] = useState(false);
const [isVisibleConnectionForm, setIsVisibleConnectionForm] = useState(false);
const [folderList, setFolderList] = useState([]);
const onConnect = () => {
const { label, provider_link } = selectedAccount;
const directConnection = provider_link;
if (directConnection) {
let authModal = window.open(
"",
"Authorization",
"height=600, width=1020"
);
openConnectWindow(label, authModal)
.then(getOAuthToken)
.then((token) => {
saveSettings(token);
authModal.close();
})
.catch((e) => {
if (!e) return;
toastr.error(e);
console.error(e);
});
} else {
setIsVisibleConnectionForm(true);
}
};
const getConnectedAccounts = async () => {
return await getSettingsThirdParty();
};
const saveSettings = async (
token = "",
urlValue = "",
loginValue = "",
passwordValue = ""
) => {
const { label, provider_key, provider_id } = selectedAccount;
try {
setIsLoading(true);
await saveSettingsThirdParty(
urlValue,
loginValue,
passwordValue,
token,
false,
label,
provider_key,
provider_id
);
updateAccountsInfo();
isVisibleConnectionForm && setIsVisibleConnectionForm(false);
} catch (e) {
setIsLoading(false);
if (!e) return;
toastr.error(e);
}
};
const onCloseConnectionForm = () => {
setIsVisibleConnectionForm(false);
};
const onSelectAccount = (options) => {
const key = options.key;
setSelectedAccount({ ...accounts[+key] });
};
const onReconnect = () => {
let authModal = window.open("", "Authorization", "height=600, width=1020");
openConnectWindow(selectedAccount.provider_key, authModal).then((modal) =>
getOAuthToken(modal).then((token) => {
authModal.close();
saveSettings(token);
})
);
};
return (
<StyledBackup>
<div className="backup_connection">
<ComboBox
className="backup_third-party-combo"
options={accounts}
selectedOption={{
key: 0,
label: selectedAccount?.label,
}}
onSelect={onSelectAccount}
noBorder={false}
scaledOptions
dropDownMaxHeight={300}
tabIndex={1}
isDisabled={isDisabled || isLoading || accounts.length === 0}
/>
{selectedAccount.connected ? (
<Button
label={t("Reconnect")}
onClick={onReconnect}
size={"small"}
isDisabled={isDisabled || isLoading || accounts.length === 0}
/>
) : (
<Button
isDisabled={isDisabled || isLoading || accounts.length === 0}
label={t("Common:Connect")}
onClick={onConnect}
size={"small"}
/>
)}
</div>
<Text className="backup_third-party-text" fontWeight={"600"}>
{"Folder name:"}
</Text>
<SelectFolderInput
id={id}
onSelectFolder={onSelectFolder}
name={"thirdParty"}
onClose={onClose}
onClickInput={onClickInput}
onSetLoadingData={onSetLoadingData}
isDisabled={
isLoading ||
accounts.length === 0 ||
folderList.length === 0 ||
isDisabled
}
isPanelVisible={isPanelVisible}
isError={isError}
foldersType="third-party"
foldersList={[folderList]}
withoutBasicSelection={withoutBasicSelection}
isReset={isReset}
isSuccessSave={isSuccessSave}
/>
{isVisibleConnectionForm && (
<FormConnection
saveSettings={saveSettings}
item={selectedAccount}
visible={isVisibleConnectionForm}
onClose={onCloseConnectionForm}
/>
)}
</StyledBackup>
);
};
export default inject(({ backup }) => {
const { commonThirdPartyList, openConnectWindow, getOAuthToken } = backup;
return {
commonThirdPartyList,
openConnectWindow,
getOAuthToken,
};
})(observer(DirectThirdPartyConnection));

View File

@ -0,0 +1,153 @@
import React, { useState, useEffect, useCallback } from "react";
import Button from "@appserver/components/button";
import ModalDialog from "@appserver/components/modal-dialog";
import TextInput from "@appserver/components/text-input";
import PasswordInput from "@appserver/components/password-input";
import FieldContainer from "@appserver/components/field-container";
const FormConnection = (props) => {
const { visible, t, tReady, item, saveSettings, onClose } = props;
const { provider_key, key } = item;
const [urlValue, setUrlValue] = useState("");
const [loginValue, setLoginValue] = useState("");
const [passwordValue, setPasswordValue] = useState("");
const [isUrlValid, setIsUrlValid] = useState(true);
const [isLoginValid, setIsLoginValid] = useState(true);
const [isPasswordValid, setIsPasswordValid] = useState(true);
const [isLoading, setIsLoading] = useState(false);
const showUrlField =
provider_key === "WebDav" ||
provider_key === "SharePoint" ||
key === "WebDav" ||
key === "SharePoint";
const onChangeUrl = (e) => {
setIsUrlValid(true);
setUrlValue(e.target.value);
};
const onChangeLogin = (e) => {
setIsLoginValid(true);
setLoginValue(e.target.value);
};
const onChangePassword = (e) => {
setIsPasswordValid(true);
setPasswordValue(e.target.value);
};
const onKeyUpHandler = useCallback(
(e) => {
if (e.keyCode === 13) onSave();
},
[urlValue, loginValue, passwordValue, showUrlField]
);
useEffect(() => {
window.addEventListener("keyup", onKeyUpHandler);
return () => window.removeEventListener("keyup", onKeyUpHandler);
}, [onKeyUpHandler]);
const onSave = useCallback(() => {
const urlValid = !!urlValue.trim();
const loginValid = !!loginValue.trim();
const passwordValid = !!passwordValue.trim();
if (!loginValid || !passwordValid || (showUrlField && !urlValid)) {
showUrlField && setIsUrlValid(urlValid);
setIsLoginValid(loginValid);
setIsPasswordValid(passwordValid);
return;
}
saveSettings(undefined, urlValue, loginValue, passwordValue);
}, [urlValue, loginValue, passwordValue, showUrlField]);
return (
<ModalDialog
isLoading={!tReady}
visible={visible}
zIndex={310}
displayType="modal"
onClose={onClose}
>
<ModalDialog.Header>
{t("Translations:ConnectingAccount")}
</ModalDialog.Header>
<ModalDialog.Body>
<>
{showUrlField && (
<FieldContainer
labelVisible
isRequired
labelText={t("ConnectionUrl")}
isVertical
hasError={!isUrlValid}
errorMessage={t("Common:RequiredField")}
>
<TextInput
isAutoFocussed={true}
hasError={!isUrlValid}
isDisabled={isLoading}
tabIndex={1}
scale
value={urlValue}
onChange={onChangeUrl}
/>
</FieldContainer>
)}
<FieldContainer
labelText={t("Login")}
isRequired
isVertical
hasError={!isLoginValid}
errorMessage={t("Common:RequiredField")}
>
<TextInput
isAutoFocussed={!showUrlField}
hasError={!isLoginValid}
isDisabled={isLoading}
tabIndex={2}
scale
value={loginValue}
onChange={onChangeLogin}
/>
</FieldContainer>
<FieldContainer
labelText={t("Common:Password")}
isRequired
isVertical
hasError={!isPasswordValid}
errorMessage={t("Common:RequiredField")}
>
<PasswordInput
hasError={!isPasswordValid}
isDisabled={isLoading}
tabIndex={3}
simpleView
passwordSettings={{ minLength: 0 }}
value={passwordValue}
onChange={onChangePassword}
/>
</FieldContainer>
</>
</ModalDialog.Body>
<ModalDialog.Footer>
<Button
tabIndex={4}
label={t("Common:SaveButton")}
size="normal"
primary
onClick={onSave}
isDisabled={isLoading}
isLoading={isLoading}
/>
</ModalDialog.Footer>
</ModalDialog>
);
};
export default FormConnection;

View File

@ -5,46 +5,22 @@ import SelectFolderInput from "files/SelectFolderInput";
import Button from "@appserver/components/button";
import { getFromSessionStorage } from "../../../../../utils";
import { BackupStorageType } from "@appserver/common/constants";
import DirectConnectionContainer from "../../common-container/DirectConnectionContainer";
import DirectThirdPartyConnection from "../../common-container/DirectThirdPartyConnection";
let folder = "";
class ThirdPartyModule extends React.Component {
constructor(props) {
super(props);
const { isDocSpace } = props;
folder = getFromSessionStorage("LocalCopyFolder");
if (isDocSpace) {
this.accounts = [
{
key: "0",
label: "Google Drive",
},
{
key: "1",
label: "OneDrive ",
},
{
key: "2",
label: "Dropbox ",
},
{
key: "3",
label: "Box.com",
},
];
}
this.state = {
isLoading: false,
isStartCopy: false,
isLoadingData: false,
selectedFolder: folder || "",
isPanelVisible: false,
isError: false,
...(isDocSpace && { selectedAccount: this.accounts[0] }),
isConnected: false,
};
}
@ -116,18 +92,12 @@ class ThirdPartyModule extends React.Component {
};
onSelectAccount = (options) => {
const key = options.key;
const label = options.label;
this.setState({
selectedAccount: { key, label },
selectedAccount: { ...this.accounts[+key] },
});
};
onConnect = () => {
const { isConnected } = this.state;
this.setState({ isConnected: !isConnected });
};
render() {
const {
isMaxProgress,
@ -141,8 +111,6 @@ class ThirdPartyModule extends React.Component {
isLoadingData,
isError,
isStartCopy,
selectedAccount,
isConnected,
selectedFolder,
} = this.state;
@ -185,26 +153,16 @@ class ThirdPartyModule extends React.Component {
</>
) : (
<div className="manual-backup_third-party-module">
<DirectConnectionContainer
accounts={this.accounts}
selectedAccount={selectedAccount}
onSelectAccount={this.onSelectAccount}
onConnect={this.onConnect}
<DirectThirdPartyConnection
t={t}
/>
<SelectFolderInput
onSelectFolder={this.onSelectFolder}
name={"thirdParty"}
onClose={this.onClose}
onClickInput={this.onClickInput}
onSetLoadingData={this.onSetLoadingData}
isDisabled={isModuleDisabled || !isConnected}
isDisabled={isModuleDisabled}
isPanelVisible={isPanelVisible}
withoutBasicSelection={true}
isError={isError}
foldersType="third-party"
foldersList={commonThirdPartyList}
withoutBasicSelection
/>
<Button
@ -218,11 +176,14 @@ class ThirdPartyModule extends React.Component {
);
}
}
export default inject(({ backup }) => {
const { commonThirdPartyList } = backup;
const isDocSpace = false;
export default inject(({ backup, settingsStore }) => {
const { commonThirdPartyList, openConnectWindow, getOAuthToken } = backup;
// const { openConnectWindow } = settingsStore.thirdPartyStore;
const isDocSpace = true;
return {
commonThirdPartyList,
isDocSpace,
openConnectWindow,
getOAuthToken,
};
})(withTranslation(["Settings", "Common"])(observer(ThirdPartyModule)));

View File

@ -6,6 +6,7 @@ import {
} from "../components/pages/Settings/utils";
import toastr from "../helpers/toastr";
import { AutoBackupPeriod } from "@appserver/common/constants";
import api from "@appserver/common/api";
const { EveryDayType, EveryWeekType } = AutoBackupPeriod;
@ -548,5 +549,73 @@ class BackupStore {
setResetProcess = (process) => {
if (process !== this.isResetProcess) this.isResetProcess = process;
};
convertServiceName = (serviceName) => {
//Docusign, OneDrive, Wordpress
switch (serviceName) {
case "GoogleDrive":
return "google";
case "Box":
return "box";
case "DropboxV2":
return "dropbox";
case "OneDrive":
return "onedrive";
default:
return "";
}
};
oAuthPopup = (url, modal) => {
let newWindow = modal;
if (modal) {
newWindow.location = url;
}
try {
let params =
"height=600,width=1020,resizable=0,status=0,toolbar=0,menubar=0,location=1";
newWindow = modal ? newWindow : window.open(url, "Authorization", params);
} catch (err) {
newWindow = modal ? newWindow : window.open(url, "Authorization");
}
return newWindow;
};
openConnectWindow = (serviceName, modal) => {
const service = this.convertServiceName(serviceName);
console.log("service", service);
return api.files.openConnectWindow(service).then((link) => {
console.log("link", link);
return this.oAuthPopup(link, modal);
});
};
getOAuthToken = (tokenGetterWin) => {
return new Promise((resolve, reject) => {
localStorage.removeItem("code");
let interval = null;
interval = setInterval(() => {
try {
const code = localStorage.getItem("code");
console.log("code", code);
if (code) {
localStorage.removeItem("code");
clearInterval(interval);
resolve(code);
console.log("code", code);
} else if (tokenGetterWin && tokenGetterWin.closed) {
clearInterval(interval);
reject();
}
} catch (e) {
clearInterval(interval);
reject(e);
console.log("code catch", code);
}
}, 500);
});
};
}
export default BackupStore;