UNPKG

passbolt-styleguide

Version:

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

331 lines (310 loc) 12.7 kB
/** * Passbolt ~ Open source password manager for teams * Copyright (c) 2020 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) 2020 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 DisplayUsers from "../DisplayUsers/DisplayUsers"; import { withUserWorkspace } from "../../../contexts/UserWorkspaceContext"; import { Route, withRouter } from "react-router-dom"; import PropTypes from "prop-types"; import DisplayUserDetails from "../../UserDetails/DisplayUserDetails/DisplayUserDetails"; import DisplayUserWorkspaceActions from "../DisplayUserWorkspaceActions/DisplayUserWorkspaceActions"; import DisplayUserBadgeMenu from "../DisplayUserBadgeMenu/DisplayUserBadgeMenu"; import { withAppContext } from "../../../../shared/context/AppContext/AppContext"; import DisplayGroups from "../FilterUsersByGroups/FilterUsersByGroup"; import FilterUsersByShortcut from "../FilterUsersByShortcut/FilterUsersByShortcut"; import FilterUsersByText from "../FilterUsersByText/FilterUsersByText"; import DisplayUserGroupDetails from "../../UserGroup/DisplayUserGroupDetails/DisplayUserGroupDetails"; import DisplayUserWorkspaceMainActions from "../DisplayUserWorkspaceMainActions/DisplayUserWorkspaceMainActions"; import FilterUsersByBreadcrumb from "../FilterUsersByBreadcrumb/FilterUsersByBreadcrumb"; import HandleReviewAccountRecoveryRequestRoute from "../HandleReviewAccountRecoveryRequestRoute/HandleReviewAccountRecoveryRequestRoute"; import DisplayHttpError from "../../Common/Error/DisplayHttpError/DisplayHttpError"; import ArrowLeftSVG from "../../../../img/svg/arrow_left.svg"; import InfoSVG from "../../../../img/svg/info.svg"; import { Trans, withTranslation } from "react-i18next"; import DisplayUserWorkspaceEmptyDetails from "../DisplayUserWorkspaceEmptyDetails/DisplayUserWorkspaceEmptyDetails"; import Footer from "../../Common/Footer/Footer"; import DisplayUsersWorkspaceFilterBar from "../DisplayUsersWorkspaceFilterBar/DisplayUsersWorkspaceFilterBar"; import debounce from "debounce-promise"; import { withNavigationContext } from "../../../contexts/NavigationContext"; import WorkspaceSwitcher, { WORKSPACE_ENUM } from "../../Common/Navigation/WorkspaceSwitcher/WorkspaceSwitcher"; import RoleEntity from "../../../../shared/models/entity/role/roleEntity"; import { uiActions } from "../../../../shared/services/rbacs/uiActionEnumeration"; import { withRbac } from "../../../../shared/context/Rbac/RbacContext"; import ResizableSidebar from "../../ResizableSidebar/ResizableSidebar"; import { withResizableSidebar } from "../../../contexts/ResizeSidebar/ResizeSidebarContext"; import ManageAnnouncements from "../../Announcement/ManageAnnouncements/ManageAnnouncements"; const GAP_AND_PADDING_BUTTONS = 22; /** * This component is a container for all the user workspace features */ class DisplayUserWorkspace extends React.Component { /** * Constructor * @param {Object} props */ constructor(props) { super(props); this.bindCallbacks(); this.createRefs(); window.addEventListener("resize", this.handleWindowResizeEventDebounced); } /** * Bind callbacks methods */ bindCallbacks() { this.handleGoBack = this.handleGoBack.bind(this); this.handleDetailsLockedEvent = this.handleDetailsLockedEvent.bind(this); this.handleWindowResizeEventDebounced = debounce(this.handleWindowResizeEvent.bind(this), 50); } /** * Create DOM nodes or React elements references in order to be able to access them programmatically. */ createRefs() { this.actionsBar = React.createRef(); this.actionsFilter = React.createRef(); this.actionsButton = React.createRef(); this.actionsSecondary = React.createRef(); } /** * ComponentDidMount */ componentDidMount() { this.displayOnlyButtonIconsIfButtonsOverlay(); } /** * ComponentDidUpdate */ componentDidUpdate() { this.displayOnlyButtonIconsIfButtonsOverlay(); } /** * Handle window resize event */ handleWindowResizeEvent() { this.displayOnlyButtonIconsIfButtonsOverlay(); } /** * calculate the width pf buttons, * if overlay the container, add classname to display only icons, else do nothing */ displayOnlyButtonIconsIfButtonsOverlay() { // Remove the class name to calculate with default width (text) this.actionsBar.current?.classList.remove("icon-only"); // Get elements width const offsetWidthActionBar = this.actionsBar.current?.offsetWidth; const offsetActionsButton = this.actionsFilter.current ? this.actionsFilter.current.offsetWidth : this.actionsButton.current?.offsetWidth; const offsetActionsSecondary = this.actionsSecondary.current?.offsetWidth; // Check if the default width overlay the container to show only icons if (offsetActionsButton + offsetActionsSecondary + GAP_AND_PADDING_BUTTONS > offsetWidthActionBar) { this.actionsBar.current.classList.add("icon-only"); } } /** * Returns true if the user details must be displayed * @returns {boolean} */ get shouldDisplayUserDetails() { const { details } = this.props.userWorkspaceContext; return details.user; } /** * Returns true if the group details must be displayed * @returns {boolean} */ get shouldDisplayGroupDetails() { const { details } = this.props.userWorkspaceContext; return details.group; } /** * Returns true if current user is allowed to access the user workspace * @returns {boolean} */ get isAccessAllowed() { return this.props.userWorkspaceContext.isAccessAllowed(); } /** * Handle go back to resource workspace */ handleGoBack() { this.props.navigationContext.onGoToPasswordsRequested(); } /** * Returns true if there is currently if nothing is selected in the workspace. * @returns {boolean} */ get shouldDisplayEmptyDetails() { const { details } = this.props.userWorkspaceContext; return !details.user && !details.group; } /** * Returns true if the current user is an admin. * @returns {boolean} */ get isUserAdmin() { const loggedInUser = this.props.context.loggedInUser; return ( loggedInUser?.role?.name === RoleEntity.ROLE_ADMIN && this.props.rbacContext.canIUseAction(uiActions.ADMINSTRATION_VIEW_WORKSPACE) ); } /** * Has lock for the detail display * @returns {boolean} */ hasDetailsLocked() { return this.props.userWorkspaceContext.details.locked; } /** * Handle view detail click event */ handleDetailsLockedEvent() { // lock or unlock the detail resource or folder this.props.userWorkspaceContext.onDetailsLocked(); } /** * Render the component * @return {JSX} */ render() { const { right, containerRef } = this.props.sidebarContext || {}; const containerWidth = containerRef?.current?.offsetWidth || 1; const rightHeaderWidth = (right?.width / containerWidth) * 100 < 25 ? `25%` : `${(right?.width / containerWidth) * 100}%`; // set width of right header return ( <> {this.props.context.users && ( <Route path="/app/account-recovery/requests/review/:accountRecoveryRequestId" component={HandleReviewAccountRecoveryRequestRoute} /> )} <ManageAnnouncements /> <div className="panel main"> {this.isAccessAllowed ? ( <> <ResizableSidebar resizable gutterLeft={false} minWidth={"18%"} maxWidth={"24%"} classNames={"users-workspace left-side-bar"} > <div className="panel left"> <div className="sidebar-content"> <div className="top-bar-left-navigation"> <div className="navigation"> {/* Add onclick action */} <button type="button" className="button-transparent back" onClick={this.handleGoBack}> <ArrowLeftSVG /> </button> <span className="title users"> <Trans>Users & Groups</Trans> </span> </div> </div> <DisplayUserWorkspaceMainActions /> <div className="sidebar-content-left"> <FilterUsersByShortcut /> <DisplayGroups /> </div> </div> </div> </ResizableSidebar> <div className="panel middle"> <div className="header"> <div className="header-left"> <FilterUsersByText /> </div> <div className="header-right" style={{ width: rightHeaderWidth }}> <WorkspaceSwitcher isUserAdmin={this.isUserAdmin} isUserWorkspaceVisible={true} currentWorkspace={WORKSPACE_ENUM.USER_AND_GROUPS} /> <DisplayUserBadgeMenu baseUrl={this.props.context.userSettings.getTrustedDomain()} user={this.props.context.loggedInUser} /> </div> </div> <div className="middle-right"> <div className="breadcrumbs-and-grid"> <div className="top-bar"> <FilterUsersByBreadcrumb /> <div className="action-bar" ref={this.actionsBar}> {this.props.userWorkspaceContext.selectedUsers?.length > 0 ? ( <DisplayUserWorkspaceActions actionsButtonRef={this.actionsButton} /> ) : ( <DisplayUsersWorkspaceFilterBar actionsFilterRef={this.actionsFilter} /> )} <div className="actions-secondary" ref={this.actionsSecondary}> <button type="button" className={`button-toggle button-action button-action-icon info ${this.hasDetailsLocked() ? "active" : ""}`} onClick={this.handleDetailsLockedEvent} > <InfoSVG /> <span className="visuallyhidden"> <Trans>View detail</Trans> </span> </button> </div> </div> </div> <DisplayUsers /> </div> {this.hasDetailsLocked() && ( <ResizableSidebar resizable gutterLeft={true} minWidth={"25%"} maxWidth={"35%"} classNames={"users-workspace right-side-bar"} > <div className="panel aside"> {this.shouldDisplayEmptyDetails && <DisplayUserWorkspaceEmptyDetails />} {this.shouldDisplayUserDetails && <DisplayUserDetails />} {this.shouldDisplayGroupDetails && <DisplayUserGroupDetails />} <Footer /> </div> </ResizableSidebar> )} </div> </div> </> ) : ( <DisplayHttpError errorCode={403} /> )} </div> </> ); } } DisplayUserWorkspace.propTypes = { context: PropTypes.any, // The application context userWorkspaceContext: PropTypes.any, history: PropTypes.any, rbacContext: PropTypes.any, // The role based access control context navigationContext: PropTypes.any, // The application navigation context t: PropTypes.func, // The translation function sidebarContext: PropTypes.any, }; export default withRouter( withAppContext( withRbac( withNavigationContext(withUserWorkspace(withResizableSidebar(withTranslation("common")(DisplayUserWorkspace)))), ), ), );