UNPKG

passbolt-styleguide

Version:

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

258 lines (242 loc) 9.24 kB
/** * Passbolt ~ Open source password manager for teams * Copyright (c) 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) Passbolt SA (https://www.passbolt.com) * @license https://opensource.org/licenses/AGPL-3.0 AGPL License * @link https://www.passbolt.com Passbolt(tm) * @since 4.6.1 */ import React from "react"; import PropTypes from "prop-types"; import { withRouter } from "react-router-dom"; import { Trans, withTranslation } from "react-i18next"; import SpinnerSVG from "../../../img/svg/spinner.svg"; import { withAppContext } from "../../../shared/context/AppContext/AppContext"; import { withPrepareResourceContext } from "../../contexts/PrepareResourceContext"; import { withPasswordExpiry } from "../../../react-extension/contexts/PasswordExpirySettingsContext"; import { withPasswordPolicies } from "../../../shared/context/PasswordPoliciesContext/PasswordPoliciesContext"; import { withResourceTypesLocalStorage } from "../../../shared/context/ResourceTypesLocalStorageContext/ResourceTypesLocalStorageContext"; import ResourceTypesCollection from "../../../shared/models/entity/resourceType/resourceTypesCollection"; import { RESOURCE_TYPE_PASSWORD_AND_DESCRIPTION_SLUG, RESOURCE_TYPE_V5_DEFAULT_SLUG, } from "../../../shared/models/entity/resourceType/resourceTypeSchemasDefinition"; import CaretLeftSVG from "../../../img/svg/caret_left.svg"; import CloseSVG from "../../../img/svg/close.svg"; import MetadataTypesSettingsEntity from "../../../shared/models/entity/metadata/metadataTypesSettingsEntity"; import { withMetadataTypesSettingsLocalStorage } from "../../../shared/context/MetadataTypesSettingsLocalStorageContext/MetadataTypesSettingsLocalStorageContext"; import ResourceMetadataEntity from "../../../shared/models/entity/resource/metadata/resourceMetadataEntity"; import { SECRET_DATA_OBJECT_TYPE } from "../../../shared/models/entity/secretData/secretDataEntity"; /** * The component display error variations. * @type {Object} */ export const ConfirmCreatePageRuleVariations = { IN_DICTIONARY: "In dictionary", MINIMUM_ENTROPY: "Minimum entropy", }; class ConfirmCreatePage extends React.PureComponent { constructor(props) { super(props); this.state = this.getDefaultState(); this.initEventHandlers(); } /** * Get the default state * @returns {object} */ getDefaultState() { return { error: "", processing: false, }; } /** * initialize event handlers * @returns {void} */ initEventHandlers() { this.handleGoBackClick = this.handleGoBackClick.bind(this); this.handleConfirmClick = this.handleConfirmClick.bind(this); } /** * Handles click on the `go back` button and cancel button * @param {React.Event} event */ handleGoBackClick(event) { event.preventDefault(); // Caution: Hack to notify the previous component that the resource is part of a dictionary, it does not handle previous page original state. const backPath = "/webAccessibleResources/quickaccess/resources/create"; const isPasswordInDictionary = this.props.location.state.rule === ConfirmCreatePageRuleVariations.IN_DICTIONARY; const additionalState = { passwordInDictionary: isPasswordInDictionary }; this.props.history.replace({ pathname: backPath, state: additionalState }); this.props.history.goBack(); } /** * Handles the click on the "x" button * @param {React.Event} event */ handleConfirmClick(event) { // Prevent submit default behavior. event.preventDefault(); this.save(); } /** * Save the resource * @returns {Promise<void>} */ async save() { const isV5 = this.props.metadataTypeSettings.isDefaultResourceTypeV5; const resourceTypeId = isV5 ? this.props.resourceTypes?.getFirstBySlug(RESOURCE_TYPE_V5_DEFAULT_SLUG)?.id : this.props.resourceTypes?.getFirstBySlug(RESOURCE_TYPE_PASSWORD_AND_DESCRIPTION_SLUG)?.id; const preparedResource = this.props.prepareResourceContext.consumePreparedResource(); const resourceDto = { resource_type_id: resourceTypeId, expired: this.props.passwordExpiryContext.getDefaultExpirationDate(), metadata: { name: preparedResource.name, username: preparedResource.username, uris: [preparedResource.uri], resource_type_id: resourceTypeId, }, }; const secretDto = { password: preparedResource.password, description: "", }; if (isV5) { resourceDto.metadata.object_type = ResourceMetadataEntity.METADATA_OBJECT_TYPE; secretDto.object_type = SECRET_DATA_OBJECT_TYPE; } this.setState({ processing: true }); try { const resource = await this.props.context.port.request("passbolt.resources.create", resourceDto, secretDto); /* * Remove the confirmation and create step from the history. * The user needs to be redirected to the home page and not the create page while clicking on go back * password details page. */ const goToComponentState = { goBackEntriesCount: -3, }; this.props.prepareResourceContext.resetSecretGeneratorSettings(); this.props.history.push(`/webAccessibleResources/quickaccess/resources/view/${resource.id}`, goToComponentState); } catch (error) { this.handleSubmitError(error); } } /** * Handles error during form submission * @param {Error} error */ handleSubmitError(error) { if (error.name === "UserAbortsOperationError") { this.setState({ processing: false }); } else { // An unexpected error occurred. this.setState({ error: error.message, processing: false, }); } } /** * Get the translate function * @returns {function(...[*]=)} */ get translate() { return this.props.t; } render() { return ( <div className="confirm-create"> <div className="back-link"> <a href="#" className="primary-action" onClick={this.handleGoBackClick} title={this.translate("Edit password")} > <CaretLeftSVG /> <span className="primary-action-title"> <Trans>Confirm password creation</Trans> </span> </a> <a href="#" className="secondary-action button-transparent button" onClick={this.handleGoBackClick} title={this.translate("Reject")} > <CloseSVG className="close" /> <span className="visually-hidden"> <Trans>Reject</Trans> </span> </a> </div> <div className="form-container"> <p> { { [ConfirmCreatePageRuleVariations.IN_DICTIONARY]: ( <Trans>The password is part of an exposed data breach.</Trans> ), [ConfirmCreatePageRuleVariations.MINIMUM_ENTROPY]: ( <Trans>The password is very weak and might be part of an exposed data breach.</Trans> ), }[this.props.location.state.rule] } </p> <p> <Trans> Are you sure you want to create the resource{" "} <strong>{{ resourceName: this.props.location.state.resourceName }}</strong>? </Trans> </p> </div> <div className="submit-wrapper input"> <button type="button" onClick={this.handleConfirmClick} className={`button primary attention big full-width ${this.state.processing ? "processing" : ""}`} role="button" disabled={this.state.processing} > <Trans>Proceed anyway</Trans> {this.state.processing && <SpinnerSVG />} </button> {this.state.error && <div className="error-message">{this.state.error}</div>} </div> </div> ); } } ConfirmCreatePage.propTypes = { context: PropTypes.any, // The application context prepareResourceContext: PropTypes.any, // The password generator context passwordExpiryContext: PropTypes.object, // The password expiry context resourceTypes: PropTypes.instanceOf(ResourceTypesCollection), // The resource types collection metadataTypeSettings: PropTypes.instanceOf(MetadataTypesSettingsEntity), // The metadata type settings // Match, location and history props are injected by the withRouter decoration call. match: PropTypes.object, location: PropTypes.object, history: PropTypes.object, t: PropTypes.func, // The translation function }; export default withAppContext( withRouter( withResourceTypesLocalStorage( withMetadataTypesSettingsLocalStorage( withPrepareResourceContext( withPasswordExpiry(withPasswordPolicies(withTranslation("common")(ConfirmCreatePage))), ), ), ), ), );