diff --git a/frontend/src/metabase/css/components/dropdown.css b/frontend/src/metabase/css/components/dropdown.css deleted file mode 100644 index 826aa5dd1498115c0d4c38d2e409e0ca9645515d..0000000000000000000000000000000000000000 --- a/frontend/src/metabase/css/components/dropdown.css +++ /dev/null @@ -1,65 +0,0 @@ -:root { - --dropdown-border-color: rgba(0, 0, 0, 0.064); -} - -.Dropdown { - position: relative; -} - -.Dropdown-content { - opacity: 0; /* start invisible */ - pointer-events: none; /* and without any clicks */ - z-index: 20; - position: absolute; - top: 40px; - min-width: 200px; - margin-top: 18px; - border: 1px solid var(--dropdown-border-color); - background-color: #fff; - border-radius: 4px; - box-shadow: 0 0 2px rgba(0, 0, 0, 0.12); - background-clip: padding-box; - padding-top: 1em; - padding-bottom: 1em; -} - -.Dropdown-content:before { - position: absolute; - top: -20px; - right: 0; - border-left: 5px solid transparent; - border-right: 5px solid transparent; - border-right: 5px solid red; - content: ""; - display: block; -} - -/* switching from home rolled to BS logic for dropdowns so we still have both classes */ -.Dropdown.open .Dropdown-content, -.Dropdown--showing.Dropdown-content { - opacity: 1; - pointer-events: all; - transition: opacity 0.3s linear, margin 0.2s linear; - margin-top: 0; -} - -.Dropdown-item { - padding-top: 1rem; - padding-bottom: 1rem; - padding-left: 2rem; - padding-right: 2rem; - line-height: 1; -} - -.Dropdown .Dropdown-item .link:hover { - text-decoration: none; -} - -.Dropdown-item:hover { - color: #fff; - background-color: var(--brand-color); -} - -.Dropdown .Dropdown-item:hover { - text-decoration: none; -} diff --git a/frontend/src/metabase/css/index.css b/frontend/src/metabase/css/index.css index f3cfe5e7ca6a542c19437509ed7b3e4153985c39..81c606efa54a99fb1338ef6f90488f4b2c8b28b2 100644 --- a/frontend/src/metabase/css/index.css +++ b/frontend/src/metabase/css/index.css @@ -3,7 +3,6 @@ @import "./core/index.css"; @import "./components/buttons.css"; -@import "./components/dropdown.css"; @import "./components/form.css"; @import "./components/header.css"; @import "./components/icons.css"; diff --git a/frontend/src/metabase/lib/urls.js b/frontend/src/metabase/lib/urls.js index bf64dfeabc7f0fff73983c480c036ce4195421b8..77245b8100bfa8d7e15291a627e577871b65b2e0 100644 --- a/frontend/src/metabase/lib/urls.js +++ b/frontend/src/metabase/lib/urls.js @@ -120,3 +120,7 @@ export function embedDashboard(token) { export function userCollection(userCollectionId) { return `/collection/${userCollectionId}/`; } + +export function accountSettings() { + return `/user/edit_current`; +} diff --git a/frontend/src/metabase/nav/components/ProfileLink.jsx b/frontend/src/metabase/nav/components/ProfileLink.jsx index 951875fab9a63c1ce4783b1d92fef0444f57db55..8979754f257bed8007f59447005325463677a9c4 100644 --- a/frontend/src/metabase/nav/components/ProfileLink.jsx +++ b/frontend/src/metabase/nav/components/ProfileLink.jsx @@ -1,20 +1,18 @@ import React, { Component } from "react"; import PropTypes from "prop-types"; -import { Link } from "react-router"; +import { Box } from "grid-styled"; -import OnClickOutsideWrapper from "metabase/components/OnClickOutsideWrapper"; import { t } from "c-3po"; -import cx from "classnames"; import _ from "underscore"; import { capitalize } from "metabase/lib/formatting"; import MetabaseSettings from "metabase/lib/settings"; -import Modal from "metabase/components/Modal.jsx"; -import Logs from "metabase/components/Logs.jsx"; +import * as Urls from "metabase/lib/urls"; +import Modal from "metabase/components/Modal"; +import Logs from "metabase/components/Logs"; -import UserAvatar from "metabase/components/UserAvatar.jsx"; -import Icon from "metabase/components/Icon.jsx"; -import LogoIcon from "metabase/components/LogoIcon.jsx"; +import LogoIcon from "metabase/components/LogoIcon"; +import EntityMenu from "metabase/components/EntityMenu"; export default class ProfileLink extends Component { constructor(props, context) { @@ -57,39 +55,99 @@ export default class ProfileLink extends Component { render() { const { user, context } = this.props; - const { modalOpen, dropdownOpen } = this.state; + const { modalOpen } = this.state; const { tag, date, ...versionExtra } = MetabaseSettings.get("version"); - - let dropDownClasses = cx({ - NavDropdown: true, - "inline-block": true, - "cursor-pointer": true, - open: dropdownOpen, - }); - + const isRoot = user.is_superuser; + const admin = context === "admin"; return ( - <div className={dropDownClasses}> - <a - data-metabase-event={"Navbar;Profile Dropdown;Toggle"} - className="NavDropdown-button NavItem flex align-center p2 transition-background" - onClick={this.toggleDropdown} - > - <div className="NavDropdown-button-layer"> - <div className="flex align-center"> - <UserAvatar user={user} /> - <Icon - name="chevrondown" - className="Dropdown-chevron ml1" - size={8} - /> + <Box> + <EntityMenu + items={[ + { + title: t`Account settings`, + icon: null, + link: Urls.accountSettings(), + }, + ...(!isRoot && { + title: admin ? t`Exit admin` : t`Admin`, + icon: null, + link: admin ? "/" : "/admin", + }), + ...(!isRoot && { + title: t`Logs`, + icon: null, + action: () => this.openModal("logs"), + }), + { + title: t`About metabase`, + icon: null, + action: () => this.openModal("about"), + }, + { + title: t`Sign out`, + icon: null, + link: "auth/logout", + }, + ]} + triggerIcon="person" + /> + {modalOpen === "about" ? ( + <Modal small onClose={this.closeModal}> + <div className="px4 pt4 pb2 text-centered relative"> + <div className="text-brand pb2"> + <LogoIcon width={48} height={48} /> + </div> + <h2 style={{ fontSize: "1.75em" }} className="text-dark"> + {t`Thanks for using`} Metabase! + </h2> + <div className="pt2"> + <h3 className="text-dark mb1"> + {t`You're on version`} {tag} + </h3> + <p className="text-grey-3 text-bold"> + {t`Built on`} {date} + </p> + {!/^v\d+\.\d+\.\d+$/.test(tag) && ( + <div> + {_.map(versionExtra, (value, key) => ( + <p key={key} className="text-grey-3 text-bold"> + {capitalize(key)}: {value} + </p> + ))} + </div> + )} + </div> </div> - </div> - </a> - - {dropdownOpen ? ( - <OnClickOutsideWrapper handleDismissal={this.closeDropdown}> - <div className="NavDropdown-content right"> - <ul className="NavDropdown-content-layer"> + <div + style={{ borderWidth: "2px" }} + className="p2 h5 text-centered text-grey-3 border-top" + > + <span className="block"> + <span className="text-bold">Metabase</span>{" "} + {t`is a Trademark of`} Metabase, Inc + </span> + <span>{t`and is built with care in San Francisco, CA`}</span> + </div> + </Modal> + ) : modalOpen === "logs" ? ( + <Modal wide onClose={this.closeModal}> + <Logs onClose={this.closeModal} /> + </Modal> + ) : null} + </Box> + /* + <PopoverWithTrigger + triggerElement={ + <a + data-metabase-event={"Navbar;Profile Dropdown;Toggle"} + className="flex align-center p2 transition-background" + onClick={this.toggleDropdown} + > + </a> + } + > + <div> + <ul> {!user.google_auth && !user.ldap_auth ? ( <li> <Link @@ -98,7 +156,7 @@ export default class ProfileLink extends Component { "Navbar;Profile Dropdown;Edit Profile" } onClick={this.closeDropdown} - className="Dropdown-item block text-white no-decoration" + className="Dropdown-item block no-decoration" > {t`Account Settings`} </Link> @@ -113,7 +171,7 @@ export default class ProfileLink extends Component { "Navbar;Profile Dropdown;Enter Admin" } onClick={this.closeDropdown} - className="Dropdown-item block text-white no-decoration" + className="Dropdown-item block no-decoration" > {t`Admin Panel`} </Link> @@ -126,7 +184,7 @@ export default class ProfileLink extends Component { to="/" data-metabase-event={"Navbar;Profile Dropdown;Exit Admin"} onClick={this.closeDropdown} - className="Dropdown-item block text-white no-decoration" + className="Dropdown-item block no-decoration" > {t`Exit Admin`} </Link> @@ -136,7 +194,7 @@ export default class ProfileLink extends Component { <li> <a data-metabase-event={"Navbar;Profile Dropdown;Help " + tag} - className="Dropdown-item block text-white no-decoration" + className="Dropdown-item block no-decoration" href={"http://www.metabase.com/docs/" + tag} target="_blank" > @@ -145,93 +203,31 @@ export default class ProfileLink extends Component { </li> {user.is_superuser && ( - <li> <a data-metabase-event={ "Navbar;Profile Dropdown;Debugging " + tag } onClick={this.openModal.bind(this, "logs")} - className="Dropdown-item block text-white no-decoration" + className="Dropdown-item block no-decoration" > {t`Logs`} </a> - </li> - )} - <li> <a data-metabase-event={"Navbar;Profile Dropdown;About " + tag} onClick={this.openModal.bind(this, "about")} - className="Dropdown-item block text-white no-decoration" + className="Dropdown-item block no-decoration" > {t`About Metabase`} </a> - </li> - <li className="border-top border-light"> <Link to="/auth/logout" data-metabase-event={"Navbar;Profile Dropdown;Logout"} - className="Dropdown-item block text-white no-decoration" > {t`Sign out`} </Link> - </li> - </ul> - </div> - </OnClickOutsideWrapper> - ) : null} - - {modalOpen === "about" ? ( - <Modal small onClose={this.closeModal}> - <div className="px4 pt4 pb2 text-centered relative"> - <span - className="absolute top right p4 text-normal text-grey-3 cursor-pointer" - onClick={this.closeModal} - > - <Icon name={"close"} size={16} /> - </span> - <div className="text-brand pb2"> - <LogoIcon width={48} height={48} /> - </div> - <h2 style={{ fontSize: "1.75em" }} className="text-dark"> - {t`Thanks for using`} Metabase! - </h2> - <div className="pt2"> - <h3 className="text-dark mb1"> - {t`You're on version`} {tag} - </h3> - <p className="text-grey-3 text-bold"> - {t`Built on`} {date} - </p> - {!/^v\d+\.\d+\.\d+$/.test(tag) && ( - <div> - {_.map(versionExtra, (value, key) => ( - <p key={key} className="text-grey-3 text-bold"> - {capitalize(key)}: {value} - </p> - ))} - </div> - )} - </div> - </div> - <div - style={{ borderWidth: "2px" }} - className="p2 h5 text-centered text-grey-3 border-top" - > - <span className="block"> - <span className="text-bold">Metabase</span>{" "} - {t`is a Trademark of`} Metabase, Inc - </span> - <span>{t`and is built with care in San Francisco, CA`}</span> - </div> - </Modal> - ) : modalOpen === "logs" ? ( - <Modal wide onClose={this.closeModal}> - <Logs onClose={this.closeModal} /> - </Modal> - ) : null} - </div> + */ ); } }