diff --git a/web/settings/account-settings.react.js b/web/settings/account-settings.react.js
index 27d1209bb..a6329fce4 100644
--- a/web/settings/account-settings.react.js
+++ b/web/settings/account-settings.react.js
@@ -1,188 +1,213 @@
// @flow
import * as React from 'react';
import { useLogOut, logOutActionTypes } from 'lib/actions/user-actions.js';
import { useModalContext } from 'lib/components/modal-provider.react.js';
import SWMansionIcon from 'lib/components/swmansion-icon.react.js';
import { useStringForUser } from 'lib/hooks/ens-cache.js';
import { accountHasPassword } from 'lib/shared/account-utils.js';
import { useTunnelbroker } from 'lib/tunnelbroker/tunnelbroker-context.js';
import { useDispatchActionPromise } from 'lib/utils/redux-promise-utils.js';
import css from './account-settings.css';
import AppearanceChangeModal from './appearance-change-modal.react.js';
+import BackupTestRestoreModal from './backup-test-restore-modal.react.js';
import PasswordChangeModal from './password-change-modal.js';
import BlockListModal from './relationship/block-list-modal.react.js';
import FriendListModal from './relationship/friend-list-modal.react.js';
import TunnelbrokerMessagesScreen from './tunnelbroker-message-list.react.js';
import TunnelbrokerTestScreen from './tunnelbroker-test.react.js';
import EditUserAvatar from '../avatars/edit-user-avatar.react.js';
import Button from '../components/button.react.js';
import { useSelector } from '../redux/redux-utils.js';
import { useStaffCanSee } from '../utils/staff-utils.js';
function AccountSettings(): React.Node {
const sendLogoutRequest = useLogOut();
const dispatchActionPromise = useDispatchActionPromise();
const logOutUser = React.useCallback(
() => dispatchActionPromise(logOutActionTypes, sendLogoutRequest()),
[dispatchActionPromise, sendLogoutRequest],
);
const { pushModal, popModal } = useModalContext();
const showPasswordChangeModal = React.useCallback(
() => pushModal(),
[pushModal],
);
const openFriendList = React.useCallback(
() => pushModal(),
[pushModal],
);
const openBlockList = React.useCallback(
() => pushModal(),
[pushModal],
);
const isAccountWithPassword = useSelector(state =>
accountHasPassword(state.currentUserInfo),
);
const currentUserInfo = useSelector(state => state.currentUserInfo);
const stringForUser = useStringForUser(currentUserInfo);
const staffCanSee = useStaffCanSee();
const { sendMessage, connected, addListener, removeListener } =
useTunnelbroker();
const openTunnelbrokerModal = React.useCallback(
() =>
pushModal(
,
),
[popModal, pushModal, sendMessage],
);
const openTunnelbrokerMessagesModal = React.useCallback(
() =>
pushModal(
,
),
[addListener, popModal, pushModal, removeListener],
);
+ const openBackupTestRestoreModal = React.useCallback(
+ () => pushModal(),
+ [popModal, pushModal],
+ );
+
const showAppearanceModal = React.useCallback(
() => pushModal(),
[pushModal],
);
if (!currentUserInfo || currentUserInfo.anonymous) {
return null;
}
let changePasswordSection;
if (isAccountWithPassword) {
changePasswordSection = (
Password
******
);
}
let preferences;
if (staffCanSee) {
preferences = (
);
}
let tunnelbroker;
if (staffCanSee) {
tunnelbroker = (
Tunnelbroker menu
-
Connected
{connected.toString()}
-
Send message to device
-
Trace received messages
);
}
+ let backup;
+ if (staffCanSee) {
+ backup = (
+
+
Backup menu
+
+
+ -
+ Test backup restore
+
+
+
+
+
+ );
+ }
return (
My Account
{preferences}
{tunnelbroker}
+ {backup}
);
}
export default AccountSettings;
diff --git a/web/settings/backup-test-restore-modal.css b/web/settings/backup-test-restore-modal.css
new file mode 100644
index 000000000..bfb878280
--- /dev/null
+++ b/web/settings/backup-test-restore-modal.css
@@ -0,0 +1,25 @@
+.modalBody {
+ padding: 24px 40px 32px;
+ color: var(--fg);
+}
+
+.content {
+ display: flex;
+ flex-direction: column;
+ gap: 10px;
+}
+
+.footer {
+ display: flex;
+ flex-direction: row-reverse;
+ justify-content: space-between;
+ padding-top: 8px;
+}
+
+.modalError {
+ font-size: var(--xs-font-12);
+ color: var(--error);
+ font-style: italic;
+ padding-left: 6px;
+ align-self: center;
+}
diff --git a/web/settings/backup-test-restore-modal.react.js b/web/settings/backup-test-restore-modal.react.js
new file mode 100644
index 000000000..bc77c5680
--- /dev/null
+++ b/web/settings/backup-test-restore-modal.react.js
@@ -0,0 +1,118 @@
+// @flow
+
+import invariant from 'invariant';
+import * as React from 'react';
+
+import { IdentityClientContext } from 'lib/shared/identity-client-context.js';
+
+import css from './backup-test-restore-modal.css';
+import Button from '../components/button.react.js';
+import { getDatabaseModule } from '../database/database-module-provider.js';
+import Input from '../modals/input.react.js';
+import Modal from '../modals/modal.react.js';
+import { workerRequestMessageTypes } from '../types/worker-types.js';
+
+type Props = {
+ +onClose: () => void,
+};
+
+function BackupTestRestoreModal(props: Props): React.Node {
+ const { onClose } = props;
+ const [backupID, setBackupID] = React.useState('');
+ const [backupDataKey, setBackupDataKey] = React.useState('');
+ const [backupLogDataKey, setBackupLogDataKey] = React.useState('');
+ const [inProgress, setInProgress] = React.useState(false);
+ const [errorMessage, setErrorMessage] = React.useState('');
+
+ const client = React.useContext(IdentityClientContext);
+
+ const onSubmit = React.useCallback(
+ async (event: SyntheticEvent) => {
+ event.preventDefault();
+
+ setInProgress(true);
+ void (async () => {
+ try {
+ if (!client) {
+ throw new Error('No identity client');
+ }
+
+ const authMetadata = await client.getAuthMetadata();
+
+ const databaseModule = await getDatabaseModule();
+ await databaseModule.schedule({
+ type: workerRequestMessageTypes.BACKUP_RESTORE,
+ authMetadata,
+ backupID,
+ backupDataKey,
+ backupLogDataKey,
+ });
+ } catch (e) {
+ setErrorMessage(e.message);
+ }
+ setInProgress(false);
+ })();
+ },
+ [backupDataKey, backupID, backupLogDataKey, client],
+ );
+
+ let errorMsg;
+ if (errorMessage) {
+ errorMsg = {errorMessage}
;
+ }
+
+ return (
+
+
+
+ );
+}
+
+export default BackupTestRestoreModal;