UNPKG

passbolt-styleguide

Version:

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

331 lines (308 loc) 11.1 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 2.13.0 */ import React from "react"; import PropTypes from "prop-types"; import {withAppContext} from "../../../contexts/AppContext"; import {withDialog} from "../../../contexts/DialogContext"; import ContextualMenuWrapper from "../../Common/ContextualMenu/ContextualMenuWrapper"; import EditResource from "../EditResource/EditResource"; import ShareDialog from "../../Share/ShareDialog"; import {withActionFeedback} from "../../../contexts/ActionFeedbackContext"; import DeleteResource from "../DeleteResource/DeleteResource"; import { resourceLinkAuthorizedProtocols, withResourceWorkspace } from "../../../contexts/ResourceWorkspaceContext"; import sanitizeUrl, {urlProtocols} from "../../../lib/Sanitize/sanitizeUrl"; import {Trans, withTranslation} from "react-i18next"; import ClipBoard from '../../../../shared/lib/Browser/clipBoard'; class DisplayResourcesListContextualMenu extends React.Component { /** * Constructor * Initialize state and bind methods */ constructor(props) { super(props); this.bindCallbacks(); } /** * Bind callbacks methods */ bindCallbacks() { this.handleEditClickEvent = this.handleEditClickEvent.bind(this); this.handleShareClickEvent = this.handleShareClickEvent.bind(this); this.handleUsernameClickEvent = this.handleUsernameClickEvent.bind(this); this.handleUriClickEvent = this.handleUriClickEvent.bind(this); this.handlePermalinkClickEvent = this.handlePermalinkClickEvent.bind(this); this.handlePasswordClickEvent = this.handlePasswordClickEvent.bind(this); this.handleDeleteClickEvent = this.handleDeleteClickEvent.bind(this); this.handleGoToResourceUriClick = this.handleGoToResourceUriClick.bind(this); } /** * handle edit resource */ handleEditClickEvent() { const passwordEditDialogProps = { id: this.resource.id }; this.props.context.setContext({passwordEditDialogProps}); this.props.dialogContext.open(EditResource); this.props.hide(); } /** * handle share resource */ handleShareClickEvent() { const resourcesIds = [this.resource.id]; this.props.context.setContext({shareDialogProps: {resourcesIds}}); this.props.dialogContext.open(ShareDialog); this.props.hide(); } /** * handle username resource */ async handleUsernameClickEvent() { await ClipBoard.copy(this.resource.username, this.props.context.port); this.props.actionFeedbackContext.displaySuccess(this.translate("The username has been copied to clipboard")); this.props.hide(); } /** * handle uri resource */ async handleUriClickEvent() { await ClipBoard.copy(this.resource.uri, this.props.context.port); this.props.actionFeedbackContext.displaySuccess(this.translate("The uri has been copied to clipboard")); this.props.hide(); } /** * handle permalink resource */ async handlePermalinkClickEvent() { const baseUrl = this.props.context.userSettings.getTrustedDomain(); const permalink = `${baseUrl}/app/passwords/view/${this.resource.id}`; await ClipBoard.copy(permalink, this.props.context.port); this.props.actionFeedbackContext.displaySuccess(this.translate("The permalink has been copied to clipboard")); this.props.hide(); } /** * Copy password from dto to clipboard * Support original password (a simple string) and composed objects) * * @param {string|object} plaintextDto * @returns {Promise<void>} */ async copyPasswordToClipboard(plaintextDto) { if (!plaintextDto) { throw new TypeError(this.translate("The password is empty.")); } if (typeof plaintextDto === 'string') { await ClipBoard.copy(plaintextDto, this.props.context.port); this.props.resourceWorkspaceContext.onResourceCopied(); } else { if (Object.prototype.hasOwnProperty.call(plaintextDto, 'password')) { await ClipBoard.copy(plaintextDto.password, this.props.context.port); this.props.resourceWorkspaceContext.onResourceCopied(); } else { throw new TypeError(this.translate("The password field is not defined.")); } } } /** * handle password resource */ async handlePasswordClickEvent() { this.props.hide(); try { const plaintextDto = await this.props.context.port.request("passbolt.secret.decrypt", this.resource.id, {showProgress: true}); await this.copyPasswordToClipboard(plaintextDto); this.props.actionFeedbackContext.displaySuccess(this.translate("The secret has been copied to clipboard")); } catch (error) { if (error.name !== "UserAbortsOperationError") { this.props.actionFeedbackContext.displayError(error.message); } } } /** * handle delete resource */ handleDeleteClickEvent() { const resources = [this.resource]; this.props.context.setContext({passwordDeleteDialogProps: {resources}}); this.props.dialogContext.open(DeleteResource); this.props.hide(); } /** * handle open the uri in a new tab */ handleGoToResourceUriClick() { this.props.resourceWorkspaceContext.onGoToResourceUriRequested(this.resource); } /** * the resource selected * @returns {*} */ get resource() { return this.props.resource; } /** * the resource safe uri * @return {string|bool} Return safe uri or false if not safe */ get safeUri() { return sanitizeUrl( this.resource.uri, { whiteListedProtocols: resourceLinkAuthorizedProtocols, defaultProtocol: urlProtocols.HTTPS }); } /** * Can update the resource */ canUpdate() { return this.resource.permission.type >= 7; } /** * Can share the resource */ canShare() { return this.resource.permission.type === 15; } /** * Can copy username * @returns {boolean} */ canCopyUsername() { return this.resource.username !== ""; } /** * Can copy uri * @returns {boolean} */ canCopyUri() { return this.resource.uri !== ""; } /** * Get the translate function * @returns {function(...[*]=)} */ get translate() { return this.props.t; } /** * Render the component. * @returns {JSX} */ render() { return ( <ContextualMenuWrapper hide={this.props.hide} left={this.props.left} top={this.props.top}> <li key="option-username-resource" className="ready"> <div className="row"> <div className="main-cell-wrapper"> <div className="main-cell"> <a id="username" className={`${this.canCopyUsername() ? "" : "disabled"}`} onClick={this.handleUsernameClickEvent}><span><Trans>Copy username</Trans></span></a> </div> </div> </div> </li> <li key="option-copy-password-resource" className="ready"> <div className="row"> <div className="main-cell-wrapper"> <div className="main-cell"> <a id="password" onClick={this.handlePasswordClickEvent}><span><Trans>Copy password</Trans></span></a> </div> </div> </div> </li> <li key="option-copy-uri-resource" className="ready"> <div className="row"> <div className="main-cell-wrapper"> <div className="main-cell"> <a id="username" className={`${this.canCopyUri() ? "" : "disabled"}`} onClick={this.handleUriClickEvent}><span><Trans>Copy URI</Trans></span></a> </div> </div> </div> </li> <li key="option-permalink-resource" className="ready"> <div className="row"> <div className="main-cell-wrapper"> <div className="main-cell"> <a id="permalink" onClick={this.handlePermalinkClickEvent}><span><Trans>Copy permalink</Trans></span></a> </div> </div> </div> </li> <li key="option-open-uri-resource" className="ready separator-after"> <div className="row"> <div className="main-cell-wrapper"> <div className="main-cell"> <a id="permalink" className={`${this.safeUri ? "" : "disabled"}`} onClick={this.handleGoToResourceUriClick}><span><Trans>Open URI in a new Tab</Trans></span></a> </div> </div> </div> </li> <li key="option-edit-resource" className="ready"> <div className="row"> <div className="main-cell-wrapper"> <div className="main-cell"> <a id="edit" className={`${this.canUpdate() ? "" : "disabled"}`} onClick={this.handleEditClickEvent}><span><Trans>Edit</Trans></span></a> </div> </div> </div> </li> <li key="option-share-resource" className="ready"> <div className="row"> <div className="main-cell-wrapper"> <div className="main-cell"> <a id="share" className={`${this.canShare() ? "" : "disabled"}`} onClick={this.handleShareClickEvent}><span><Trans>Share</Trans></span></a> </div> </div> </div> </li> <li key="option-delete-resource" className="ready"> <div className="row"> <div className="main-cell-wrapper"> <div className="main-cell"> <a id="delete" className={`${this.canUpdate() ? "" : "disabled"}`} onClick={this.handleDeleteClickEvent}><span><Trans>Delete</Trans></span></a> </div> </div> </div> </li> </ContextualMenuWrapper> ); } } DisplayResourcesListContextualMenu.propTypes = { context: PropTypes.any, // The application context hide: PropTypes.func, // Hide the contextual menu left: PropTypes.number, // left position in px of the page top: PropTypes.number, // top position in px of the page resourceWorkspaceContext: PropTypes.any, // Resource workspace context dialogContext: PropTypes.any, // the dialog context resource: PropTypes.object, // resource selected actionFeedbackContext: PropTypes.any, // The action feedback context t: PropTypes.func, // The translation function }; export default withAppContext(withResourceWorkspace(withDialog(withActionFeedback(withTranslation('common')(DisplayResourcesListContextualMenu)))));