passbolt-styleguide
Version:
Passbolt styleguide contains common styling assets used by the different sites, plugin, etc.
259 lines (244 loc) • 9.61 kB
JavaScript
/**
* Passbolt ~ Open source password manager for teams
* Copyright (c) 2022 Passbolt SA (https://www.passbolt.com)
*
* Licensed under GNU Affero General Public License version 3 of the or any later version.
* For full copyright and license information, please see the LICENSE.txt
* Redistributions of files must retain the above copyright notice.
*
* @copyright Copyright (c) 2022 Passbolt SA (https://www.passbolt.com)
* @license https://opensource.org/licenses/AGPL-3.0 AGPL License
* @link https://www.passbolt.com Passbolt(tm)
* @since 3.6.0
*/
import React, {Component, Fragment} from "react";
import PropTypes from "prop-types";
import {Trans, withTranslation} from "react-i18next";
import DialogWrapper from "../../Common/Dialog/DialogWrapper/DialogWrapper";
import FormSubmitButton from "../../Common/Inputs/FormSubmitButton/FormSubmitButton";
import {withAppContext} from "../../../contexts/AppContext";
import {DateTime} from "luxon";
import FormCancelButton from "../../Common/Inputs/FormSubmitButton/FormCancelButton";
class ConfirmSaveAccountRecoverySettings extends Component {
/**
* Constructor
* @param {Object} props
*/
constructor(props) {
super(props);
this.state = this.getDefaultState();
this.bindCallbacks();
}
/**
* Returns the default component state
*/
getDefaultState() {
return {
processing: false
};
}
/**
* Bind callbacks methods
*/
bindCallbacks() {
this.handleSubmit = this.handleSubmit.bind(this);
this.handleClose = this.handleClose.bind(this);
}
/**
* Handle close button click.
*/
handleClose() {
this.props.onClose();
}
/**
* Toggle the processing mode
*/
async toggleProcessing() {
await this.setState({processing: !this.state.processing});
}
/**
* Returns true if the component must be in a processing mode
*/
get isProcessing() {
return this.state.processing;
}
/**
* Go to the next process
* @param {Event} event A form submit event
*/
async handleSubmit(event) {
event.preventDefault();
await this.toggleProcessing();
try {
await this.props.onSubmit();
this.props.onClose();
} catch (error) {
await this.toggleProcessing();
if (error.name === "UserAbortsOperationError") {
// It can happen when the user has closed the passphrase entry dialog by instance. Do nothing.
} else {
// The component passing the onSubmit prop should take care of any unexpected errors, this code should not run.
console.error('Uncaught uncontrolled error');
throw error;
}
}
}
/**
* format fingerprint
* @param fingerprint
* @returns {JSX.Element}
*/
formatFingerprint(fingerprint) {
fingerprint = fingerprint || "";
const result = fingerprint.toUpperCase().replace(/.{4}/g, '$& ');
return <>{result.substr(0, 24)}<br/>{result.substr(25)}</>;
}
/**
* format user ids
* @param user_ids
* @returns {JSX.Element}
*/
formatUserIds(user_ids) {
user_ids = user_ids || [];
return user_ids.map((user, id) => <Fragment key={id}>{user.name}<{user.email}><br/></Fragment>);
}
/**
* Format date in time ago
* @param {string} date The date to format
* @return {string}
*/
formatDateTimeAgo(date) {
if (date === null) {
return "n/a";
}
if (date === 'Infinity') {
return this.translate("Never");
}
const dateTime = DateTime.fromISO(date);
const duration = dateTime.diffNow().toMillis();
return duration > -1000 && duration < 0 ? this.translate('Just now') : dateTime.toRelative({locale: this.props.context.locale});
}
/**
* Format date
* @param {string} date The date to format
* @return {string}
*/
formatDate(date) {
return DateTime.fromJSDate(new Date(date)).setLocale(this.props.context.locale).toLocaleString(DateTime.DATETIME_FULL);
}
/**
* Get the translate function
* @returns {function(...[*]=)}
*/
get translate() {
return this.props.t;
}
/**
* Render the component
* @returns {JSX}
*/
render() {
return (
<DialogWrapper
title={this.translate("Save Settings Summary")}
onClose={this.handleClose}
disabled={this.state.processing}
className="save-recovery-account-settings-dialog">
<form onSubmit={this.handleSubmit}>
<div className="form-content">
{this.props.policy &&
<>
<label><Trans>New Account Recovery Policy</Trans></label>
<div className="radiolist-alt">
<div className="input radio">
<label htmlFor="accountPolicy">
<span className="name">
{{
mandatory: <Trans>Mandatory</Trans>,
'opt-out': <Trans>Optional, Opt-out</Trans>,
'opt-in': <Trans>Optional, Opt-in</Trans>,
disabled: <Trans>Disable</Trans>
}[this.props.policy]}
</span>
<span className="info">
{{
mandatory: <><Trans>Every user is required to provide a copy of their private key and passphrase during setup.</Trans><br/><Trans>Warning: You should inform your users not to store personal passwords.</Trans></>,
'opt-out': <Trans>Every user will be prompted to provide a copy of their private key and passphrase by default during the setup, but they can opt out.</Trans>,
'opt-in': <Trans>Every user can decide to provide a copy of their private key and passphrase by default during the setup, but they can opt in.</Trans>,
disabled: <><Trans>Backup of the private key and passphrase will not be stored. This is the safest option.</Trans><br/><Trans>Warning: If users lose their private key and passphrase they will not be able to recover their account.</Trans></>
}[this.props.policy]}
</span>
</label>
</div>
</div>
</>
}
{this.props.keyInfo &&
<>
<label><Trans>New Organization Recovery Key</Trans></label>
<div className="recovery-key-details">
<table className="table-info recovery-key">
<tbody>
<tr className="user-ids">
<td className="label"><Trans>Uid</Trans></td>
<td className="value">{this.formatUserIds(this.props.keyInfo.user_ids)}</td>
</tr>
<tr className="fingerprint">
<td className="label"><Trans>Fingerprint</Trans></td>
<td className="value">{this.formatFingerprint(this.props.keyInfo.fingerprint)}</td>
</tr>
<tr className="algorithm">
<td className="label"><Trans>Algorithm</Trans></td>
<td className="value">{this.props.keyInfo.algorithm}</td>
</tr>
<tr className="key-length">
<td className="label"><Trans>Key length</Trans></td>
<td className="value">{this.props.keyInfo.length}</td>
</tr>
<tr className="created">
<td className="label"><Trans>Created</Trans></td>
<td className="value">{this.formatDate(this.props.keyInfo.created)}</td>
</tr>
<tr className="expires">
<td className="label"><Trans>Expires</Trans></td>
<td className="value">{this.formatDateTimeAgo(this.props.keyInfo.expires)}</td>
</tr>
</tbody>
</table>
</div>
</>
}
</div>
<div className="warning message">
<Trans>Please review carefully this configuration as it will not be trivial to change this later.</Trans>
</div>
<div className="submit-wrapper clearfix">
<a
target="_blank" rel="noopener noreferrer"
href="https://help.passbolt.com/configure/account-recovery"
className={`button button-left ${this.isProcessing ? "disabled" : ''}`}>
<Trans>Learn more</Trans>
</a>
<FormCancelButton
onClick={this.handleClose}
disabled={this.isProcessing}/>
<FormSubmitButton
value={this.translate("Save")}
disabled={this.isProcessing}
processing={this.isProcessing}
warning={true}/>
</div>
</form>
</DialogWrapper>
);
}
}
ConfirmSaveAccountRecoverySettings.propTypes = {
context: PropTypes.any, // The application context
onClose: PropTypes.func, // Callback when the dialog must be closed
onSubmit: PropTypes.func, // The submit callback
policy: PropTypes.string, // The account recovery policy if any change of policy
keyInfo: PropTypes.object, // The account recovery public key details if any change of key
t: PropTypes.func, // The translation function
};
export default withAppContext(withTranslation('common')(ConfirmSaveAccountRecoverySettings));