UNPKG

passbolt-styleguide

Version:

Passbolt styleguide contains common styling assets used by the different sites, plugin, etc.

289 lines (262 loc) 8.58 kB
/** * 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 from "react"; import {Trans, withTranslation} from "react-i18next"; import PropTypes from "prop-types"; import Icon from "../../../../shared/components/Icons/Icon"; import FormSubmitButton from "../../Common/Inputs/FormSubmitButton/FormSubmitButton"; import FormCancelButton from "../../Common/Inputs/FormSubmitButton/FormCancelButton"; import {withAppContext} from "../../../contexts/AppContext"; /** * This component allows to display the import organization key for the administration */ class ImportOrganizationKey extends React.Component { /** * Constructor * @param {Object} props */ constructor(props) { super(props); this.state = this.defaultState; this.bindCallbacks(); this.createInputRef(); } /** * Get default state * @returns {Object} */ get defaultState() { return { processing: false, // component is processing or not key: "", // The subscription key keyError: "", // The error subscription key hasAlreadyBeenValidated: false, // true if the form has already validated once, selectedFile: null, // the file to import }; } /** * Bind callbacks methods */ bindCallbacks() { this.handleSelectFile = this.handleSelectFile.bind(this); this.handleFormSubmit = this.handleFormSubmit.bind(this); this.handleInputChange = this.handleInputChange.bind(this); this.handleSelectOrganizationKeyFile = this.handleSelectOrganizationKeyFile.bind(this); } /** * Create DOM nodes or React elements references in order to be able to access them programmatically. */ createInputRef() { this.keyInputRef = React.createRef(); this.fileUploaderRef = React.createRef(); } /** * Whenever the user select a organization key file * @param event The file dom event */ async handleSelectOrganizationKeyFile(event) { const [organizationFile] = event.target.files; const organizationKey = await this.readOrganizationKeyFile(organizationFile); this.setState({key: organizationKey, selectedFile: organizationFile}); } /** * Read the selected file and returns its content in text form * @param organizationFile The given file * @return {Promise} */ readOrganizationKeyFile(organizationFile) { const reader = new FileReader(); return new Promise((resolve, reject) => { reader.onloadend = () => { try { resolve(reader.result); } catch (e) { reject(e); } }; reader.readAsText(organizationFile); }); } /** * Validate the key input. * @return {Promise} */ async validateKeyInput() { const key = this.state.key.trim(); if (key === "") { return Promise.reject(new Error(this.translate("The key can't be empty."))); } return await this.props.context.port.request('passbolt.account-recovery.validate-organization-key', key); } /** * Check if the form is valid. * @return {Promise<boolean>} */ async validate() { // Reset the form errors. this.setState({ keyError: "", }); return await this.validateKeyInput() .then(() => true) .catch(error => { this.setState({keyError: error.message}); return false; }); } /** * Handle form input change. * @params {ReactEvent} The react event. */ handleInputChange(event) { const target = event.target; this.setState({ [target.name]: target.value }); } /** * Handle the selection of a file by file explorer */ handleSelectFile() { this.fileUploaderRef.current.click(); } /** * Handle form submit event. * @params {ReactEvent} The react event * @return {Promise} */ async handleFormSubmit(event) { event.preventDefault(); if (!this.state.processing) { await this.save(); } } /** * Save the changes. */ async save() { await this.setState({hasAlreadyBeenValidated: true}); await this.toggleProcessing(); if (!await this.validate()) { this.handleValidateError(); await this.toggleProcessing(); return; } await this.props.onUpdateOrganizationKey(this.state.key.trim()); } /** * Handle validation error. */ handleValidateError() { this.focusFieldError(); } /** * Focus the field of the form which is in error state. */ focusFieldError() { if (this.state.keyError) { this.keyInputRef.current.focus(); } } /** * Toggle the processing mode */ async toggleProcessing() { await this.setState({processing: !this.state.processing}); } /** * Should input be disabled? True if state is processing * @returns {boolean} */ hasAllInputDisabled() { return this.state.processing; } /** * Get the translate function * @returns {function(...[*]=)} */ get translate() { return this.props.t; } /** * Returns the selected file's name */ get selectedFilename() { return this.state.selectedFile ? this.state.selectedFile.name : ""; } /** * Render the component * @returns {JSX} */ render() { return ( <form onSubmit={this.handleFormSubmit} noValidate> <div className="form-content import-organization-key"> <div className={`input textarea required ${this.state.keyError ? "error" : ""}`}> <label htmlFor="organization-recover-form-key"><Trans>Import an OpenPGP Public key</Trans></label> <textarea id="organization-recover-form-key" name="key" value={this.state.key} onKeyUp={this.handleKeyInputKeyUp} onChange={this.handleInputChange} disabled={this.hasAllInputDisabled()} ref={this.keyInputRef} className="required" placeholder={this.translate('Add Open PGP Public key')} required="required" autoComplete="off" autoFocus={true} /> </div> <div className="input file"> <input type="file" id="dialog-import-private-key" ref={this.fileUploaderRef} disabled={this.hasAllInputDisabled()} onChange={this.handleSelectOrganizationKeyFile} /> <label htmlFor="dialog-import-private-key"> <Trans>Select a file to import</Trans> </label> <div className="input-file-inline"> <input type="text" disabled={true} placeholder={this.translate("No file selected")} defaultValue={this.selectedFilename} /> <button className="button primary" type='button' disabled={this.hasAllInputDisabled()} onClick={this.handleSelectFile}> <span><Trans>Choose a file</Trans></span> </button> </div> {this.state.keyError && <div className="key error-message">{this.state.keyError}</div> } </div> </div> {!this.state.hasAlreadyBeenValidated && <div className="message notice"> <Icon baseline={true} name="info-circle" /> <strong><Trans>Pro tip</Trans>:</strong> <Trans>Learn how to <a href="https://help.passbolt.com/configure/account-recovery" target="_blank" rel="noopener noreferrer">generate a key separately.</a></Trans> </div> } <div className="submit-wrapper clearfix"> <FormCancelButton disabled={this.hasAllInputDisabled()} onClick={this.props.onClose} /> <FormSubmitButton disabled={this.hasAllInputDisabled()} processing={this.state.processing} value={this.translate("Apply")} /> </div> </form> ); } } ImportOrganizationKey.propTypes = { context: PropTypes.object, onUpdateOrganizationKey: PropTypes.func, onClose: PropTypes.func, t: PropTypes.func, // The translation function }; export default withAppContext(withTranslation('common')(ImportOrganizationKey));