Merge pull request #2469 from influxdata/multitenancy_ui_polish

Multitenancy UI Polish
pull/2484/head
Alex Paxton 2017-12-04 16:40:18 -08:00 committed by GitHub
commit 83e3ef8e2e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
17 changed files with 177 additions and 36 deletions

View File

@ -28,7 +28,7 @@ const AdminTabs = ({
{
requiredRole: SUPERADMIN_ROLE,
type: ORGANIZATIONS_TAB_NAME,
component: <OrganizationsPage />,
component: <OrganizationsPage currentOrganization={organization} />,
},
{
requiredRole: ADMIN_ROLE,

View File

@ -38,6 +38,7 @@ class OrganizationsTable extends Component {
onRenameOrg,
onChooseDefaultRole,
onTogglePublic,
currentOrganization,
} = this.props
const {isCreatingOrganization} = this.state
@ -62,7 +63,7 @@ class OrganizationsTable extends Component {
</div>
<div className="panel-body">
<div className="orgs-table--org-labels">
<div className="orgs-table--id">ID</div>
<div className="orgs-table--active" />
<div className="orgs-table--name">Name</div>
<div className="orgs-table--public">
Public{' '}
@ -85,6 +86,7 @@ class OrganizationsTable extends Component {
onDelete={onDeleteOrg}
onRename={onRenameOrg}
onChooseDefaultRole={onChooseDefaultRole}
currentOrganization={currentOrganization}
/>
)}
</div>
@ -102,6 +104,10 @@ OrganizationsTable.propTypes = {
name: string.isRequired,
})
).isRequired,
currentOrganization: shape({
name: string.isRequired,
id: string.isRequired,
}),
onCreateOrg: func.isRequired,
onDeleteOrg: func.isRequired,
onRenameOrg: func.isRequired,

View File

@ -1,9 +1,14 @@
import React, {Component, PropTypes} from 'react'
import {connect} from 'react-redux'
import {bindActionCreators} from 'redux'
import {withRouter} from 'react-router'
import SlideToggle from 'shared/components/SlideToggle'
import ConfirmButtons from 'shared/components/ConfirmButtons'
import Dropdown from 'shared/components/Dropdown'
import {meChangeOrganizationAsync} from 'shared/actions/auth'
import {DEFAULT_ORG_ID} from 'src/admin/constants/chronografAdmin'
import {USER_ROLES} from 'src/admin/constants/chronografAdmin'
@ -33,6 +38,13 @@ class OrganizationsTableRow extends Component {
}
}
handleChangeCurrentOrganization = async () => {
const {router, links, meChangeOrganization, organization} = this.props
await meChangeOrganization(links.me, {organization: organization.id})
router.push('')
}
handleNameClick = () => {
this.setState({isEditing: true})
}
@ -106,7 +118,7 @@ class OrganizationsTableRow extends Component {
render() {
const {workingName, isEditing, isDeleting} = this.state
const {organization} = this.props
const {organization, currentOrganization} = this.props
const dropdownRolesItems = USER_ROLES.map(role => ({
...role,
@ -119,8 +131,17 @@ class OrganizationsTableRow extends Component {
return (
<div className="orgs-table--org">
<div className="orgs-table--id">
{organization.id}
<div className="orgs-table--active">
{organization.id === currentOrganization.id
? <button className="btn btn-sm btn-success">
<span className="icon checkmark" /> Current
</button>
: <button
className="btn btn-sm btn-default"
onClick={this.handleChangeCurrentOrganization}
>
<span className="icon shuffle" /> Switch to
</button>}
</div>
{isEditing
? <input
@ -173,7 +194,7 @@ class OrganizationsTableRow extends Component {
}
}
const {func, shape, string} = PropTypes
const {arrayOf, func, shape, string} = PropTypes
OrganizationsTableRow.propTypes = {
organization: shape({
@ -185,6 +206,25 @@ OrganizationsTableRow.propTypes = {
onRename: func.isRequired,
onTogglePublic: func.isRequired,
onChooseDefaultRole: func.isRequired,
currentOrganization: shape({
name: string.isRequired,
id: string.isRequired,
}),
router: shape({
push: func.isRequired,
}).isRequired,
links: shape({
me: string,
external: shape({
custom: arrayOf(
shape({
name: string.isRequired,
url: string.isRequired,
})
),
}),
}),
meChangeOrganization: func.isRequired,
}
OrganizationsTableRowDeleteButton.propTypes = {
@ -196,4 +236,14 @@ OrganizationsTableRowDeleteButton.propTypes = {
onClickDelete: func.isRequired,
}
export default OrganizationsTableRow
const mapDispatchToProps = dispatch => ({
meChangeOrganization: bindActionCreators(meChangeOrganizationAsync, dispatch),
})
const mapStateToProps = ({links}) => ({
links,
})
export default connect(mapStateToProps, mapDispatchToProps)(
withRouter(OrganizationsTableRow)
)

View File

@ -59,7 +59,7 @@ class OrganizationsTableRowNew extends Component {
return (
<div className="orgs-table--org orgs-table--new-org">
<div className="orgs-table--id">&mdash;</div>
<div className="orgs-table--active">&mdash;</div>
<input
type="text"
className="form-control input-sm orgs-table--input"

View File

@ -27,12 +27,19 @@ const UsersTableRow = ({
role => role.organization === organization.id
)
const userIsMe = user.id === meID
return (
<tr className={'chronograf-admin-table--user'}>
<td>
<strong>
{user.name}
</strong>
{userIsMe
? <strong className="chronograf-user--me">
<span className="icon user" />
{user.name}
</strong>
: <strong>
{user.name}
</strong>}
</td>
<td style={{width: colRole}}>
<span className="chronograf-user--role">
@ -66,7 +73,7 @@ const UsersTableRow = ({
onDelete={onDelete}
item={user}
buttonSize="btn-xs"
disabled={user.id === meID}
disabled={userIsMe}
/>
</tr>
)

View File

@ -111,6 +111,10 @@ AdminChronografPage.propTypes = {
name: string.isRequired,
}).isRequired,
meRole: string.isRequired,
me: shape({
name: string.isRequired,
id: string.isRequired,
}).isRequired,
meID: string.isRequired,
actions: shape({
loadUsersAsync: func.isRequired,
@ -125,6 +129,7 @@ const mapStateToProps = ({
links,
adminChronograf: {users},
auth: {
me,
me: {currentOrganization: meCurrentOrganization, role: meRole, id: meID},
},
}) => ({
@ -132,6 +137,7 @@ const mapStateToProps = ({
users,
meCurrentOrganization,
meRole,
me,
meID,
})

View File

@ -52,7 +52,7 @@ class OrganizationsPage extends Component {
}
render() {
const {organizations} = this.props
const {organizations, currentOrganization} = this.props
return (
<OrganizationsTable
@ -62,6 +62,7 @@ class OrganizationsPage extends Component {
onRenameOrg={this.handleRenameOrganization}
onTogglePublic={this.handleTogglePublic}
onChooseDefaultRole={this.handleChooseDefaultRole}
currentOrganization={currentOrganization}
/>
)
}
@ -87,6 +88,10 @@ OrganizationsPage.propTypes = {
deleteOrganizationAsync: func.isRequired,
}),
getMe: func.isRequired,
currentOrganization: shape({
name: string.isRequired,
id: string.isRequired,
}),
}
const mapStateToProps = ({links, adminChronograf: {organizations}}) => ({

View File

@ -87,16 +87,14 @@ class UserNavBlock extends Component {
})}
</FancyScrollbar>
<div className="sidebar-menu--section">Account</div>
<div className="sidebar-menu--provider">
<div>
{me.scheme} / {me.provider}
</div>
</div>
<a className="sidebar-menu--item" href={logoutLink}>
Logout
</a>
{isSuperAdmin
? <div className="sidebar-menu--superadmin">
<div>
<span className="icon crown2" /> You are a SuperAdmin
</div>
</div>
: null}
<div className="sidebar-menu--heading sidebar--no-hover">
{me.name}
</div>
@ -107,13 +105,11 @@ class UserNavBlock extends Component {
{me.name}
</div>
<div className="sidebar-menu--section">Account</div>
{isSuperAdmin
? <div className="sidebar-menu--superadmin">
<div>
<span className="icon crown2" /> You are a SuperAdmin
</div>
</div>
: null}
<div className="sidebar-menu--provider">
<div>
{me.scheme} / {me.provider}
</div>
</div>
<a className="sidebar-menu--item" href={logoutLink}>
Logout
</a>

View File

@ -24,6 +24,15 @@
color: $g13-mist;
font-weight: 500;
}
.orgs-table--active {
padding: 0 4px 0 0;
width: 102px;
height: 30px;
button.btn {
width: 100%;
}
}
.orgs-table--name,
.orgs-table--name-disabled,
input[type="text"].form-control.orgs-table--input {
@ -76,7 +85,7 @@ input[type="text"].form-control.orgs-table--input {
height: 30px;
margin-right: 4px;
text-align: center;
width: 104px;
width: 88px;
background-color: $g4-onyx;
border-radius: 4px;
line-height: 30px;
@ -97,7 +106,7 @@ input[type="text"].form-control.orgs-table--input {
.orgs-table--default-role,
.orgs-table--default-role-disabled {
width: 130px;
width: 100px;
height: 30px;
margin-right: 4px;
}
@ -130,7 +139,8 @@ input[type="text"].form-control.orgs-table--input {
> .orgs-table--name,
> .orgs-table--name:hover,
> .orgs-table--public {
> .orgs-table--public,
> .orgs-table--active {
transition: none;
background-color: transparent;
border-color: transparent;
@ -140,12 +150,14 @@ input[type="text"].form-control.orgs-table--input {
> .orgs-table--name,
> .orgs-table--name:hover,
> .orgs-table--default-role,
> .orgs-table--public {
> .orgs-table--public,
> .orgs-table--active {
color: $g17-whisper;
font-weight: 500;
}
> .orgs-table--default-role,
> .orgs-table--public {
> .orgs-table--public,
> .orgs-table--active {
line-height: 30px;
font-size: 13px;
padding: 0 11px;

Binary file not shown.

View File

@ -87,6 +87,7 @@
<glyph unicode="&#xe94b;" glyph-name="crown2" d="M882.4-64.4l135.2 523.4c2.2 8.4-7 15.2-14.4 10.4l-262.4-168.2c-10.4-6.6-24.2-3.8-31.2 6.4l-189.8 276.4c-3.8 5.6-12 5.6-15.8 0l-189.6-276.6c-7-10.2-20.8-13-31.2-6.4l-262.4 168.2c-7.4 4.6-16.6-2-14.4-10.4l135.2-523.4c2.8-11 12.8-18.8 24.2-18.8h692.6c11.2 0.2 21.2 8 24 19z" />
<glyph unicode="&#xe94c;" glyph-name="server2" d="M992.4 729.2h-960.8c-10.2 0-20.4-10.2-20.4-20.4v-203.8c0-10.2 10.2-20.4 20.4-20.4h960.6c10.2 0 20.4 10.2 20.4 20.4v203.8c0.2 10.2-10 20.4-20.2 20.4zM241.6 556.4c0-7.4-6-13.6-13.6-13.6h-101c-7.4 0-13.6 6-13.6 13.6v101c0 7.4 6 13.6 13.6 13.6h101c7.4 0 13.6-6 13.6-13.6v-101zM992.4 378.4h-960.8c-10.2 0-20.4-10.2-20.4-20.4v-204c0-10.2 10.2-20.4 20.4-20.4h960.6c10.2 0 20.4 10.2 20.4 20.4v204c0.2 10.2-10 20.4-20.2 20.4zM241.6 205.6c0-7.4-6-13.6-13.6-13.6h-101c-7.4 0-13.6 6-13.6 13.6v100.8c0 7.4 6 13.6 13.6 13.6h101c7.4 0 13.6-6 13.6-13.6v-100.8zM992.4 47.6h-960.8c-10.2 0-20.4-10.2-20.4-20.4v-203.8c0-10.2 10.2-20.4 20.4-20.4h960.6c10.2 0 20.4 10.2 20.4 20.4v203.8c0.2 10.2-10 20.4-20.2 20.4zM241.6-125.2c0-7.4-6-13.6-13.6-13.6h-101c-7.4 0-13.6 6-13.6 13.6v101c0 7.4 6 13.6 13.6 13.6h101c7.4 0 13.6-6 13.6-13.6v-101z" />
<glyph unicode="&#xe94d;" glyph-name="user" d="M744.96 483.84c0-128.66-104.3-232.96-232.96-232.96s-232.96 104.3-232.96 232.96c0 128.66 104.3 232.96 232.96 232.96s232.96-104.3 232.96-232.96zM637.44 199.68h-25.6c-10.24 0-17.92-2.56-23.040-10.24l-76.8-99.84-76.8 99.84c-5.12 7.68-15.36 10.24-23.040 10.24h-25.6c-130.56 0-235.52-107.52-235.52-235.52v-143.36c0-12.8 10.24-25.6 25.6-25.6h673.28c12.8 0 25.6 10.24 25.6 25.6v143.36c-2.56 128-107.52 235.52-238.080 235.52z" />
<glyph unicode="&#xe94e;" glyph-name="shuffle" d="M330.24 145.92c-51.2-81.92-99.84-133.12-168.96-133.12h-97.28c-35.84 0-64-28.16-64-64s28.16-64 64-64h94.72c104.96 0 179.2 56.32 238.080 133.12-23.040 43.52-46.080 87.040-66.56 128zM832 107.52c-17.92 15.36-48.64 2.56-48.64-23.040v-74.24h-23.040c-102.4 0-163.84 107.52-243.2 271.36-79.36 161.28-168.96 343.040-358.4 343.040h-94.72c-35.84 2.56-64-25.6-64-61.44s28.16-64 64-64h94.72c102.4 0 163.84-107.52 243.2-271.36 79.36-161.28 168.96-343.040 358.4-343.040h23.040v-74.24c0-25.6 28.16-38.4 48.64-23.040l192 161.28-192 158.72zM832 721.92c-17.92 15.36-48.64 2.56-48.64-23.040v-74.24h-23.040c-104.96 0-179.2-56.32-238.080-133.12 25.6-40.96 48.64-84.48 69.12-125.44 51.2 81.92 99.84 133.12 168.96 133.12h23.040v-74.24c0-25.6 28.16-38.4 48.64-23.040l192 161.28-192 158.72z" />
<glyph unicode="&#xea88;" glyph-name="google" d="M522.2 329.2v-175.6h290.4c-11.8-75.4-87.8-220.8-290.4-220.8-174.8 0-317.4 144.8-317.4 323.2s142.6 323.2 317.4 323.2c99.4 0 166-42.4 204-79l139 133.8c-89.2 83.6-204.8 134-343 134-283 0-512-229-512-512s229-512 512-512c295.4 0 491.6 207.8 491.6 500.2 0 33.6-3.6 59.2-8 84.8l-483.6 0.2z" />
<glyph unicode="&#xea8a;" glyph-name="google3" d="M512 768c-282.8 0-512-229.2-512-512s229.2-512 512-512 512 229.2 512 512-229.2 512-512 512zM519.6-128c-212.2 0-384 171.8-384 384s171.8 384 384 384c103.6 0 190.4-37.8 257.2-100.4l-104.2-100.4c-28.6 27.4-78.4 59.2-153 59.2-131.2 0-238-108.6-238-242.4s107-242.4 238-242.4c152 0 209 109.2 217.8 165.6h-217.8v131.6h362.6c3.2-19.2 6-38.4 6-63.6 0.2-219.4-146.8-375.2-368.6-375.2z" />
<glyph unicode="&#xea8b;" glyph-name="google-plus" d="M325.8 310.6v-111.8h184.8c-7.4-48-55.8-140.6-184.8-140.6-111.2 0-202 92.2-202 205.8s90.8 205.8 202 205.8c63.4 0 105.6-27 129.8-50.2l88.4 85.2c-56.8 53-130.4 85.2-218.2 85.2-180.2-0.2-325.8-145.8-325.8-326s145.6-325.8 325.8-325.8c188 0 312.8 132.2 312.8 318.4 0 21.4-2.4 37.8-5.2 54h-307.6zM1024 320h-96v96h-96v-96h-96v-96h96v-96h96v96h96z" />

Before

Width:  |  Height:  |  Size: 73 KiB

After

Width:  |  Height:  |  Size: 74 KiB

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -263,10 +263,6 @@ span.icon.sidebar--icon.sidebar--icon__superadmin {
@include no-user-select();
> div {
display: flex;
padding: 4px 8px;
align-items: center;
border-radius: 3px;
@include gradient-h($c-pineapple,$c-tiger);
color: $c-sapphire;
}
@ -280,6 +276,36 @@ span.icon.sidebar--icon.sidebar--icon__superadmin {
cursor: default;
}
}
.sidebar-menu--provider {
padding: 4px $sidebar-menu--gutter;
font-size: 15px;
font-weight: 500;
@include no-user-select();
> div {
@include gradient-h($c-rainforest,$c-pool);
color: $g20-white;
}
span.icon {
display: inline-block;
margin-right: 6px;
position: relative;
top: -2px;
}
&:hover {
cursor: default;
}
}
.sidebar-menu--superadmin > div,
.sidebar-menu--provider > div {
display: flex;
padding: 4px 8px;
align-items: center;
border-radius: 3px;
white-space: nowrap;
}
.fancy-scroll--container.sidebar-menu--scrollbar {
.fancy-scroll--thumb-h {display: none !important;}
.fancy-scroll--thumb-v { @include gradient-v($g20-white,$c-neutrino); }

View File

@ -110,3 +110,13 @@ table.table.chronograf-admin-table tbody tr.chronograf-admin-table--new-user {
padding-bottom: 8px;
}
}
/* Highlight "Me" in the users table */
.chronograf-user--me {
color: $c-rainforest;
> span.icon {
display: inline-block;
margin-right: 4px;
}
}

View File

@ -358,6 +358,9 @@ span.text-color-danger {
.icon.heroku-simple:before {
content: "\e948";
}
.icon.shuffle:before {
content: "\e94e";
}
.icon.alert-triangle:before {
content: "\f02d";
}
@ -5721,6 +5724,25 @@ input.form-control.form-astronaut::-moz-selection,
textarea.form-control.form-astronaut::-moz-selection {
background-color: #9394ff;
}
input.form-control.form-volcano,
textarea.form-control.form-volcano {
color: #ff8564;
}
input.form-control.form-volcano:focus,
textarea.form-control.form-volcano:focus {
color: #fff7f4;
background-color: #2f1f29;
border-color: #ff8564;
box-shadow: 0 0 8px #f95f53;
}
input.form-control.form-volcano::selection,
textarea.form-control.form-volcano::selection {
background-color: #f95f53;
}
input.form-control.form-volcano::-moz-selection,
textarea.form-control.form-volcano::-moz-selection {
background-color: #f95f53;
}
.form-control.monotype {
font-family: "Roboto Mono", monospace;
}