Merge remote-tracking branch 'origin/master' into feature/custom_user_links-1550
commit
f064342440
15
CHANGELOG.md
15
CHANGELOG.md
|
@ -1,11 +1,26 @@
|
||||||
## v1.3.4.0 [unreleased]
|
## v1.3.4.0 [unreleased]
|
||||||
### Bug Fixes
|
### Bug Fixes
|
||||||
|
1. [#1612](https://github.com/influxdata/chronograf/pull/1612): Prevent users from being able to write to internal system databases
|
||||||
|
1. [#1655](https://github.com/influxdata/chronograf/pull/1655): Add more than one color to Line+Stat graphs
|
||||||
|
|
||||||
### Features
|
### Features
|
||||||
1. [#1645](https://github.com/influxdata/chronograf/pull/1645): Add Auth0 as a supported OAuth2 provider
|
1. [#1645](https://github.com/influxdata/chronograf/pull/1645): Add Auth0 as a supported OAuth2 provider
|
||||||
1. [#1660](https://github.com/influxdata/chronograf/pull/1660): Add ability to add custom links to User menu via server CLI or ENV vars
|
1. [#1660](https://github.com/influxdata/chronograf/pull/1660): Add ability to add custom links to User menu via server CLI or ENV vars
|
||||||
|
|
||||||
### UI Improvements
|
### UI Improvements
|
||||||
|
1. [#1644](https://github.com/influxdata/chronograf/pull/1644): Redesign Alerts History table to have sticky headers
|
||||||
1. [#1581](https://github.com/influxdata/chronograf/pull/1581): Refresh template variable values on dashboard page load
|
1. [#1581](https://github.com/influxdata/chronograf/pull/1581): Refresh template variable values on dashboard page load
|
||||||
|
1. [#1612](https://github.com/influxdata/chronograf/pull/1612): Prevent users from being able to write to internal system databases
|
||||||
|
1. [#1655](https://github.com/influxdata/chronograf/pull/1655): Add version number item to the navbar
|
||||||
|
1. [#1655](https://github.com/influxdata/chronograf/pull/1655): Redesign dashboards table and sort alphabetically by name
|
||||||
|
1. [#1655](https://github.com/influxdata/chronograf/pull/1655): Redesign navbar to be consistent with navbar in Branding Documentation
|
||||||
|
|
||||||
|
## v1.3.3.3 [2017-06-21]
|
||||||
|
### Bug Fixes
|
||||||
|
1. [1651](https://github.com/influxdata/chronograf/pull/1651): Add back in x and y axes and revert some style changes on Line + Single Stat graphs
|
||||||
|
|
||||||
|
## v1.3.3.2 [2017-06-21]
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
## v1.3.3.3 [2017-06-21]
|
## v1.3.3.3 [2017-06-21]
|
||||||
### Bug Fixes
|
### Bug Fixes
|
||||||
|
|
|
@ -2,6 +2,10 @@ import React, {Component, PropTypes} from 'react'
|
||||||
import _ from 'lodash'
|
import _ from 'lodash'
|
||||||
import {Link} from 'react-router'
|
import {Link} from 'react-router'
|
||||||
|
|
||||||
|
import FancyScrollbar from 'shared/components/FancyScrollbar'
|
||||||
|
|
||||||
|
import {ALERTS_TABLE} from 'src/alerts/constants/tableSizing'
|
||||||
|
|
||||||
class AlertsTable extends Component {
|
class AlertsTable extends Component {
|
||||||
constructor(props) {
|
constructor(props) {
|
||||||
super(props)
|
super(props)
|
||||||
|
@ -55,11 +59,11 @@ class AlertsTable extends Component {
|
||||||
sortableClasses(key) {
|
sortableClasses(key) {
|
||||||
if (this.state.sortKey === key) {
|
if (this.state.sortKey === key) {
|
||||||
if (this.state.sortDirection === 'asc') {
|
if (this.state.sortDirection === 'asc') {
|
||||||
return 'sortable-header sorting-ascending'
|
return 'alert-history-table--th sortable-header sorting-ascending'
|
||||||
}
|
}
|
||||||
return 'sortable-header sorting-descending'
|
return 'alert-history-table--th sortable-header sorting-descending'
|
||||||
}
|
}
|
||||||
return 'sortable-header'
|
return 'alert-history-table--th sortable-header'
|
||||||
}
|
}
|
||||||
|
|
||||||
sort(alerts, key, direction) {
|
sort(alerts, key, direction) {
|
||||||
|
@ -80,64 +84,93 @@ class AlertsTable extends Component {
|
||||||
this.state.sortKey,
|
this.state.sortKey,
|
||||||
this.state.sortDirection
|
this.state.sortDirection
|
||||||
)
|
)
|
||||||
|
const {colName, colLevel, colTime, colHost, colValue} = ALERTS_TABLE
|
||||||
return this.props.alerts.length
|
return this.props.alerts.length
|
||||||
? <table className="table v-center table-highlight">
|
? <div className="alert-history-table">
|
||||||
<thead>
|
<div className="alert-history-table--thead">
|
||||||
<tr>
|
<div
|
||||||
<th
|
|
||||||
onClick={() => this.changeSort('name')}
|
onClick={() => this.changeSort('name')}
|
||||||
className={this.sortableClasses('name')}
|
className={this.sortableClasses('name')}
|
||||||
|
style={{width: colName}}
|
||||||
>
|
>
|
||||||
Name
|
Name
|
||||||
</th>
|
</div>
|
||||||
<th
|
<div
|
||||||
onClick={() => this.changeSort('level')}
|
onClick={() => this.changeSort('level')}
|
||||||
className={this.sortableClasses('level')}
|
className={this.sortableClasses('level')}
|
||||||
|
style={{width: colLevel}}
|
||||||
>
|
>
|
||||||
Level
|
Level
|
||||||
</th>
|
</div>
|
||||||
<th
|
<div
|
||||||
onClick={() => this.changeSort('time')}
|
onClick={() => this.changeSort('time')}
|
||||||
className={this.sortableClasses('time')}
|
className={this.sortableClasses('time')}
|
||||||
|
style={{width: colTime}}
|
||||||
>
|
>
|
||||||
Time
|
Time
|
||||||
</th>
|
</div>
|
||||||
<th
|
<div
|
||||||
onClick={() => this.changeSort('host')}
|
onClick={() => this.changeSort('host')}
|
||||||
className={this.sortableClasses('host')}
|
className={this.sortableClasses('host')}
|
||||||
|
style={{width: colHost}}
|
||||||
>
|
>
|
||||||
Host
|
Host
|
||||||
</th>
|
</div>
|
||||||
<th
|
<div
|
||||||
onClick={() => this.changeSort('value')}
|
onClick={() => this.changeSort('value')}
|
||||||
className={this.sortableClasses('value')}
|
className={this.sortableClasses('value')}
|
||||||
|
style={{width: colValue}}
|
||||||
>
|
>
|
||||||
Value
|
Value
|
||||||
</th>
|
</div>
|
||||||
</tr>
|
</div>
|
||||||
</thead>
|
<FancyScrollbar
|
||||||
<tbody>
|
className="alert-history-table--tbody"
|
||||||
|
autoHide={false}
|
||||||
|
>
|
||||||
{alerts.map(({name, level, time, host, value}) => {
|
{alerts.map(({name, level, time, host, value}) => {
|
||||||
return (
|
return (
|
||||||
<tr key={`${name}-${level}-${time}-${host}-${value}`}>
|
<div
|
||||||
<td className="monotype">{name}</td>
|
className="alert-history-table--tr"
|
||||||
<td className={`monotype alert-level-${level.toLowerCase()}`}>
|
key={`${name}-${level}-${time}-${host}-${value}`}
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
className="alert-history-table--td"
|
||||||
|
style={{width: colName}}
|
||||||
|
>
|
||||||
|
{name}
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
className={`alert-history-table--td alert-level-${level.toLowerCase()}`}
|
||||||
|
style={{width: colLevel}}
|
||||||
|
>
|
||||||
{level}
|
{level}
|
||||||
</td>
|
</div>
|
||||||
<td className="monotype">
|
<div
|
||||||
|
className="alert-history-table--td"
|
||||||
|
style={{width: colTime}}
|
||||||
|
>
|
||||||
{new Date(Number(time)).toISOString()}
|
{new Date(Number(time)).toISOString()}
|
||||||
</td>
|
</div>
|
||||||
<td className="monotype">
|
<div
|
||||||
|
className="alert-history-table--td"
|
||||||
|
style={{width: colHost}}
|
||||||
|
>
|
||||||
<Link to={`/sources/${id}/hosts/${host}`}>
|
<Link to={`/sources/${id}/hosts/${host}`}>
|
||||||
{host}
|
{host}
|
||||||
</Link>
|
</Link>
|
||||||
</td>
|
</div>
|
||||||
<td className="monotype">{value}</td>
|
<div
|
||||||
</tr>
|
className="alert-history-table--td"
|
||||||
|
style={{width: colValue}}
|
||||||
|
>
|
||||||
|
{value}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
)
|
)
|
||||||
})}
|
})}
|
||||||
</tbody>
|
</FancyScrollbar>
|
||||||
</table>
|
</div>
|
||||||
: this.renderTableEmpty()
|
: this.renderTableEmpty()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -239,7 +272,7 @@ class SearchBar extends Component {
|
||||||
<input
|
<input
|
||||||
type="text"
|
type="text"
|
||||||
className="form-control"
|
className="form-control"
|
||||||
placeholder="Filter Alerts by Name..."
|
placeholder="Filter Alerts..."
|
||||||
onChange={this.handleChange}
|
onChange={this.handleChange}
|
||||||
value={this.state.searchTerm}
|
value={this.state.searchTerm}
|
||||||
/>
|
/>
|
||||||
|
|
|
@ -0,0 +1,7 @@
|
||||||
|
export const ALERTS_TABLE = {
|
||||||
|
colName: '15%',
|
||||||
|
colLevel: '10%',
|
||||||
|
colTime: '25%',
|
||||||
|
colHost: '25%',
|
||||||
|
colValue: '25%',
|
||||||
|
}
|
|
@ -4,7 +4,6 @@ import SourceIndicator from 'shared/components/SourceIndicator'
|
||||||
import AlertsTable from 'src/alerts/components/AlertsTable'
|
import AlertsTable from 'src/alerts/components/AlertsTable'
|
||||||
import NoKapacitorError from 'shared/components/NoKapacitorError'
|
import NoKapacitorError from 'shared/components/NoKapacitorError'
|
||||||
import CustomTimeRangeDropdown from 'shared/components/CustomTimeRangeDropdown'
|
import CustomTimeRangeDropdown from 'shared/components/CustomTimeRangeDropdown'
|
||||||
import FancyScrollbar from 'shared/components/FancyScrollbar'
|
|
||||||
|
|
||||||
import {getAlerts} from 'src/alerts/apis'
|
import {getAlerts} from 'src/alerts/apis'
|
||||||
import AJAX from 'utils/ajax'
|
import AJAX from 'utils/ajax'
|
||||||
|
@ -160,10 +159,8 @@ class AlertsApp extends Component {
|
||||||
}
|
}
|
||||||
|
|
||||||
return isWidget
|
return isWidget
|
||||||
? <FancyScrollbar autoHide={false}>
|
? this.renderSubComponents()
|
||||||
{this.renderSubComponents()}
|
: <div className="page alert-history-page">
|
||||||
</FancyScrollbar>
|
|
||||||
: <div className="page">
|
|
||||||
<div className="page-header">
|
<div className="page-header">
|
||||||
<div className="page-header__container">
|
<div className="page-header__container">
|
||||||
<div className="page-header__left">
|
<div className="page-header__left">
|
||||||
|
@ -183,7 +180,7 @@ class AlertsApp extends Component {
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<FancyScrollbar className="page-contents">
|
<div className="page-contents">
|
||||||
<div className="container-fluid">
|
<div className="container-fluid">
|
||||||
<div className="row">
|
<div className="row">
|
||||||
<div className="col-md-12">
|
<div className="col-md-12">
|
||||||
|
@ -191,7 +188,7 @@ class AlertsApp extends Component {
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</FancyScrollbar>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,28 @@
|
||||||
|
import React, {PropTypes} from 'react'
|
||||||
|
|
||||||
|
import SourceIndicator from 'shared/components/SourceIndicator'
|
||||||
|
|
||||||
|
const DashboardsHeader = ({sourceName}) => {
|
||||||
|
return (
|
||||||
|
<div className="page-header">
|
||||||
|
<div className="page-header__container">
|
||||||
|
<div className="page-header__left">
|
||||||
|
<h1 className="page-header__title">
|
||||||
|
Dashboards
|
||||||
|
</h1>
|
||||||
|
</div>
|
||||||
|
<div className="page-header__right">
|
||||||
|
<SourceIndicator sourceName={sourceName} />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
const {string} = PropTypes
|
||||||
|
|
||||||
|
DashboardsHeader.propTypes = {
|
||||||
|
sourceName: string.isRequired,
|
||||||
|
}
|
||||||
|
|
||||||
|
export default DashboardsHeader
|
|
@ -0,0 +1,61 @@
|
||||||
|
import React, {PropTypes} from 'react'
|
||||||
|
|
||||||
|
import DashboardsTable from 'src/dashboards/components/DashboardsTable'
|
||||||
|
import FancyScrollbar from 'shared/components/FancyScrollbar'
|
||||||
|
|
||||||
|
const DashboardsPageContents = ({
|
||||||
|
dashboards,
|
||||||
|
onDeleteDashboard,
|
||||||
|
onCreateDashboard,
|
||||||
|
dashboardLink,
|
||||||
|
}) => {
|
||||||
|
let tableHeader
|
||||||
|
if (dashboards === null) {
|
||||||
|
tableHeader = 'Loading Dashboards...'
|
||||||
|
} else if (dashboards.length === 1) {
|
||||||
|
tableHeader = '1 Dashboard'
|
||||||
|
} else {
|
||||||
|
tableHeader = `${dashboards.length} Dashboards`
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<FancyScrollbar className="page-contents">
|
||||||
|
<div className="container-fluid">
|
||||||
|
<div className="row">
|
||||||
|
<div className="col-md-12">
|
||||||
|
<div className="panel panel-minimal">
|
||||||
|
<div className="panel-heading u-flex u-ai-center u-jc-space-between">
|
||||||
|
<h2 className="panel-title">{tableHeader}</h2>
|
||||||
|
<button
|
||||||
|
className="btn btn-sm btn-primary"
|
||||||
|
onClick={onCreateDashboard}
|
||||||
|
>
|
||||||
|
Create Dashboard
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
<div className="panel-body">
|
||||||
|
<DashboardsTable
|
||||||
|
dashboards={dashboards}
|
||||||
|
onDeleteDashboard={onDeleteDashboard}
|
||||||
|
onCreateDashboard={onCreateDashboard}
|
||||||
|
dashboardLink={dashboardLink}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</FancyScrollbar>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
const {arrayOf, func, shape, string} = PropTypes
|
||||||
|
|
||||||
|
DashboardsPageContents.propTypes = {
|
||||||
|
dashboards: arrayOf(shape()),
|
||||||
|
onDeleteDashboard: func.isRequired,
|
||||||
|
onCreateDashboard: func.isRequired,
|
||||||
|
dashboardLink: string.isRequired,
|
||||||
|
}
|
||||||
|
|
||||||
|
export default DashboardsPageContents
|
|
@ -0,0 +1,73 @@
|
||||||
|
import React, {PropTypes} from 'react'
|
||||||
|
import {Link} from 'react-router'
|
||||||
|
import _ from 'lodash'
|
||||||
|
|
||||||
|
import DeleteConfirmTableCell from 'shared/components/DeleteConfirmTableCell'
|
||||||
|
|
||||||
|
const DashboardsTable = ({
|
||||||
|
dashboards,
|
||||||
|
onDeleteDashboard,
|
||||||
|
onCreateDashboard,
|
||||||
|
dashboardLink,
|
||||||
|
}) => {
|
||||||
|
return dashboards && dashboards.length
|
||||||
|
? <table className="table v-center admin-table table-highlight">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th>Name</th>
|
||||||
|
<th>Template Variables</th>
|
||||||
|
<th />
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
{_.sortBy(dashboards, d => d.name.toLowerCase()).map(dashboard =>
|
||||||
|
<tr key={dashboard.id}>
|
||||||
|
<td>
|
||||||
|
<Link to={`${dashboardLink}/dashboards/${dashboard.id}`}>
|
||||||
|
{dashboard.name}
|
||||||
|
</Link>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
{dashboard.templates.length
|
||||||
|
? dashboard.templates.map(tv =>
|
||||||
|
<code className="table--temp-var" key={tv.id}>
|
||||||
|
{tv.tempVar}
|
||||||
|
</code>
|
||||||
|
)
|
||||||
|
: <span className="empty-string">
|
||||||
|
None
|
||||||
|
</span>}
|
||||||
|
</td>
|
||||||
|
<DeleteConfirmTableCell
|
||||||
|
onDelete={onDeleteDashboard}
|
||||||
|
item={dashboard}
|
||||||
|
buttonSize="btn-xs"
|
||||||
|
/>
|
||||||
|
</tr>
|
||||||
|
)}
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
: <div className="generic-empty-state">
|
||||||
|
<h4 style={{marginTop: '90px'}}>
|
||||||
|
Looks like you dont have any dashboards
|
||||||
|
</h4>
|
||||||
|
<button
|
||||||
|
className="btn btn-sm btn-primary"
|
||||||
|
onClick={onCreateDashboard}
|
||||||
|
style={{marginBottom: '90px'}}
|
||||||
|
>
|
||||||
|
Create Dashboard
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
|
||||||
|
const {arrayOf, func, shape, string} = PropTypes
|
||||||
|
|
||||||
|
DashboardsTable.propTypes = {
|
||||||
|
dashboards: arrayOf(shape()),
|
||||||
|
onDeleteDashboard: func.isRequired,
|
||||||
|
onCreateDashboard: func.isRequired,
|
||||||
|
dashboardLink: string.isRequired,
|
||||||
|
}
|
||||||
|
|
||||||
|
export default DashboardsTable
|
|
@ -1,11 +1,10 @@
|
||||||
import React, {PropTypes} from 'react'
|
import React, {PropTypes} from 'react'
|
||||||
import {Link, withRouter} from 'react-router'
|
import {withRouter} from 'react-router'
|
||||||
import {connect} from 'react-redux'
|
import {connect} from 'react-redux'
|
||||||
import {bindActionCreators} from 'redux'
|
import {bindActionCreators} from 'redux'
|
||||||
|
|
||||||
import SourceIndicator from 'shared/components/SourceIndicator'
|
import DashboardsHeader from 'src/dashboards/components/DashboardsHeader'
|
||||||
import DeleteConfirmTableCell from 'shared/components/DeleteConfirmTableCell'
|
import DashboardsContents from 'src/dashboards/components/DashboardsPageContents'
|
||||||
import FancyScrollbar from 'shared/components/FancyScrollbar'
|
|
||||||
|
|
||||||
import {createDashboard} from 'src/dashboards/apis'
|
import {createDashboard} from 'src/dashboards/apis'
|
||||||
import {getDashboardsAsync, deleteDashboardAsync} from 'src/dashboards/actions'
|
import {getDashboardsAsync, deleteDashboardAsync} from 'src/dashboards/actions'
|
||||||
|
@ -50,89 +49,16 @@ const DashboardsPage = React.createClass({
|
||||||
render() {
|
render() {
|
||||||
const {dashboards} = this.props
|
const {dashboards} = this.props
|
||||||
const dashboardLink = `/sources/${this.props.source.id}`
|
const dashboardLink = `/sources/${this.props.source.id}`
|
||||||
let tableHeader
|
|
||||||
if (dashboards === null) {
|
|
||||||
tableHeader = 'Loading Dashboards...'
|
|
||||||
} else if (dashboards.length === 1) {
|
|
||||||
tableHeader = '1 Dashboard'
|
|
||||||
} else {
|
|
||||||
tableHeader = `${dashboards.length} Dashboards`
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="page">
|
<div className="page">
|
||||||
<div className="page-header">
|
<DashboardsHeader sourceName={this.props.source.name} />
|
||||||
<div className="page-header__container">
|
<DashboardsContents
|
||||||
<div className="page-header__left">
|
dashboardLink={dashboardLink}
|
||||||
<h1 className="page-header__title">
|
dashboards={dashboards}
|
||||||
Dashboards
|
onDeleteDashboard={this.handleDeleteDashboard}
|
||||||
</h1>
|
onCreateDashboard={this.handleCreateDashbord}
|
||||||
</div>
|
|
||||||
<div className="page-header__right">
|
|
||||||
<SourceIndicator sourceName={this.props.source.name} />
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<FancyScrollbar className="page-contents">
|
|
||||||
<div className="container-fluid">
|
|
||||||
<div className="row">
|
|
||||||
<div className="col-md-12">
|
|
||||||
<div className="panel panel-minimal">
|
|
||||||
<div className="panel-heading u-flex u-ai-center u-jc-space-between">
|
|
||||||
<h2 className="panel-title">{tableHeader}</h2>
|
|
||||||
<button
|
|
||||||
className="btn btn-sm btn-primary"
|
|
||||||
onClick={this.handleCreateDashbord}
|
|
||||||
>
|
|
||||||
Create Dashboard
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
<div className="panel-body">
|
|
||||||
{dashboards && dashboards.length
|
|
||||||
? <table className="table v-center admin-table table-highlight">
|
|
||||||
<thead>
|
|
||||||
<tr>
|
|
||||||
<th>Name</th>
|
|
||||||
<th />
|
|
||||||
</tr>
|
|
||||||
</thead>
|
|
||||||
<tbody>
|
|
||||||
{dashboards.map(dashboard =>
|
|
||||||
<tr key={dashboard.id} className="">
|
|
||||||
<td>
|
|
||||||
<Link
|
|
||||||
to={`${dashboardLink}/dashboards/${dashboard.id}`}
|
|
||||||
>
|
|
||||||
{dashboard.name}
|
|
||||||
</Link>
|
|
||||||
</td>
|
|
||||||
<DeleteConfirmTableCell
|
|
||||||
onDelete={this.handleDeleteDashboard}
|
|
||||||
item={dashboard}
|
|
||||||
buttonSize="btn-xs"
|
|
||||||
/>
|
/>
|
||||||
</tr>
|
|
||||||
)}
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
: <div className="generic-empty-state">
|
|
||||||
<h4 style={{marginTop: '90px'}}>
|
|
||||||
Looks like you dont have any dashboards
|
|
||||||
</h4>
|
|
||||||
<button
|
|
||||||
className="btn btn-sm btn-primary"
|
|
||||||
onClick={this.handleCreateDashbord}
|
|
||||||
style={{marginBottom: '90px'}}
|
|
||||||
>
|
|
||||||
Create Dashboard
|
|
||||||
</button>
|
|
||||||
</div>}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</FancyScrollbar>
|
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
|
|
|
@ -43,12 +43,17 @@ class DatabaseDropdown extends Component {
|
||||||
const proxy = source.links.proxy
|
const proxy = source.links.proxy
|
||||||
try {
|
try {
|
||||||
const {data} = await showDatabases(proxy)
|
const {data} = await showDatabases(proxy)
|
||||||
const {databases} = showDatabasesParser(data)
|
const {databases, errors} = showDatabasesParser(data)
|
||||||
|
if (errors.length > 0) {
|
||||||
|
throw errors[0] // only one error can come back from this, but it's returned as an array
|
||||||
|
}
|
||||||
|
|
||||||
this.setState({databases})
|
const nonSystemDatabases = databases.filter(name => name !== '_internal')
|
||||||
const selectedDatabaseText = databases.includes(database)
|
|
||||||
|
this.setState({databases: nonSystemDatabases})
|
||||||
|
const selectedDatabaseText = nonSystemDatabases.includes(database)
|
||||||
? database
|
? database
|
||||||
: databases[0] || 'No databases'
|
: nonSystemDatabases[0] || 'No databases'
|
||||||
onSelectDatabase({text: selectedDatabaseText})
|
onSelectDatabase({text: selectedDatabaseText})
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error(error)
|
console.error(error)
|
||||||
|
|
|
@ -33,6 +33,7 @@ class FancyScrollbar extends Component {
|
||||||
<div {...props} className="fancy-scroll--thumb-h" />}
|
<div {...props} className="fancy-scroll--thumb-h" />}
|
||||||
renderThumbVertical={props =>
|
renderThumbVertical={props =>
|
||||||
<div {...props} className="fancy-scroll--thumb-v" />}
|
<div {...props} className="fancy-scroll--thumb-v" />}
|
||||||
|
renderView={props => <div {...props} className="fancy-scroll--view" />}
|
||||||
>
|
>
|
||||||
{children}
|
{children}
|
||||||
</Scrollbars>
|
</Scrollbars>
|
||||||
|
|
|
@ -131,7 +131,17 @@ export default React.createClass({
|
||||||
strokeWidth: 1.5,
|
strokeWidth: 1.5,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
const singleStatLineColor = ['#7A65F2']
|
const singleStatLineColors = [
|
||||||
|
'#7A65F2',
|
||||||
|
'#FFD255',
|
||||||
|
'#7CE490',
|
||||||
|
'#F95F53',
|
||||||
|
'#4591ED',
|
||||||
|
'#B1B6FF',
|
||||||
|
'#FFF6B8',
|
||||||
|
'#C6FFD0',
|
||||||
|
'#6BDFFF',
|
||||||
|
]
|
||||||
|
|
||||||
let roundedValue
|
let roundedValue
|
||||||
if (showSingleStat) {
|
if (showSingleStat) {
|
||||||
|
@ -152,7 +162,7 @@ export default React.createClass({
|
||||||
<Dygraph
|
<Dygraph
|
||||||
containerStyle={{width: '100%', height: '100%'}}
|
containerStyle={{width: '100%', height: '100%'}}
|
||||||
overrideLineColors={
|
overrideLineColors={
|
||||||
showSingleStat ? singleStatLineColor : overrideLineColors
|
showSingleStat ? singleStatLineColors : overrideLineColors
|
||||||
}
|
}
|
||||||
isGraphFilled={showSingleStat ? false : isGraphFilled}
|
isGraphFilled={showSingleStat ? false : isGraphFilled}
|
||||||
isBarGraph={isBarGraph}
|
isBarGraph={isBarGraph}
|
||||||
|
|
|
@ -19,14 +19,14 @@ const NavListItem = React.createClass({
|
||||||
|
|
||||||
return useAnchor
|
return useAnchor
|
||||||
? <a
|
? <a
|
||||||
className={classnames('sidebar__menu-item', {active: isActive})}
|
className={classnames('sidebar-menu--item', {active: isActive})}
|
||||||
href={link}
|
href={link}
|
||||||
target={isExternal ? '_blank' : '_self'}
|
target={isExternal ? '_blank' : '_self'}
|
||||||
>
|
>
|
||||||
{children}
|
{children}
|
||||||
</a>
|
</a>
|
||||||
: <Link
|
: <Link
|
||||||
className={classnames('sidebar__menu-item', {active: isActive})}
|
className={classnames('sidebar-menu--item', {active: isActive})}
|
||||||
to={link}
|
to={link}
|
||||||
>
|
>
|
||||||
{children}
|
{children}
|
||||||
|
@ -46,11 +46,11 @@ const NavHeader = React.createClass({
|
||||||
// Some nav items, such as Logout, need to hit an external link rather
|
// Some nav items, such as Logout, need to hit an external link rather
|
||||||
// than simply route to an internal page. Anchor tags serve that purpose.
|
// than simply route to an internal page. Anchor tags serve that purpose.
|
||||||
return useAnchor
|
return useAnchor
|
||||||
? <a className="sidebar__menu-route" href={link}>
|
? <a className="sidebar-menu--heading" href={link}>
|
||||||
<h3 className="sidebar__menu-heading">{title}</h3>
|
{title}
|
||||||
</a>
|
</a>
|
||||||
: <Link className="sidebar__menu-route" to={link}>
|
: <Link className="sidebar-menu--heading" to={link}>
|
||||||
<h3 className="sidebar__menu-heading">{title}</h3>
|
{title}
|
||||||
</Link>
|
</Link>
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
@ -62,11 +62,10 @@ const NavBlock = React.createClass({
|
||||||
icon: string.isRequired,
|
icon: string.isRequired,
|
||||||
location: string,
|
location: string,
|
||||||
className: string,
|
className: string,
|
||||||
wrapperClassName: string,
|
|
||||||
},
|
},
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const {location, className, wrapperClassName} = this.props
|
const {location, className} = this.props
|
||||||
|
|
||||||
const isActive = React.Children.toArray(this.props.children).find(child => {
|
const isActive = React.Children.toArray(this.props.children).find(child => {
|
||||||
return location.startsWith(child.props.link)
|
return location.startsWith(child.props.link)
|
||||||
|
@ -82,34 +81,30 @@ const NavBlock = React.createClass({
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
className={classnames('sidebar__square', className, {active: isActive})}
|
className={classnames('sidebar--item', className, {active: isActive})}
|
||||||
>
|
>
|
||||||
{this.renderLink()}
|
{this.renderSquare()}
|
||||||
<div className={wrapperClassName || 'sidebar__menu-wrapper'}>
|
<div className="sidebar-menu">
|
||||||
<div className="sidebar__menu">
|
|
||||||
{children}
|
{children}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
|
|
||||||
renderLink() {
|
renderSquare() {
|
||||||
const {link, icon} = this.props
|
const {link, icon} = this.props
|
||||||
|
|
||||||
if (!link) {
|
if (!link) {
|
||||||
return (
|
return (
|
||||||
<div className="sidebar__icon">
|
<div className="sidebar--square">
|
||||||
<span className={`icon ${icon}`} />
|
<div className={`sidebar--icon icon ${icon}`} />
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Link className="sidebar__menu-route" to={link}>
|
<Link className="sidebar--square" to={link}>
|
||||||
<div className="sidebar__icon">
|
<div className={`sidebar--icon icon ${icon}`} />
|
||||||
<span className={`icon ${icon}`} />
|
|
||||||
</div>
|
|
||||||
</Link>
|
</Link>
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
|
@ -131,7 +126,7 @@ const NavBar = React.createClass({
|
||||||
|
|
||||||
return child
|
return child
|
||||||
})
|
})
|
||||||
return <aside className="sidebar">{children}</aside>
|
return <nav className="sidebar">{children}</nav>
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
|
@ -13,6 +13,8 @@ import {DEFAULT_HOME_PAGE} from 'shared/constants'
|
||||||
|
|
||||||
const {arrayOf, bool, shape, string} = PropTypes
|
const {arrayOf, bool, shape, string} = PropTypes
|
||||||
|
|
||||||
|
const V_NUMBER = VERSION // eslint-disable-line no-undef
|
||||||
|
|
||||||
const SideNav = React.createClass({
|
const SideNav = React.createClass({
|
||||||
propTypes: {
|
propTypes: {
|
||||||
params: shape({
|
params: shape({
|
||||||
|
@ -45,7 +47,11 @@ const SideNav = React.createClass({
|
||||||
</NavListItem>
|
</NavListItem>
|
||||||
)
|
)
|
||||||
.concat(
|
.concat(
|
||||||
<NavListItem useAnchor={true} link={logoutLink}>
|
<NavListItem
|
||||||
|
key={customLinks.length + 1}
|
||||||
|
useAnchor={true}
|
||||||
|
link={logoutLink}
|
||||||
|
>
|
||||||
Logout
|
Logout
|
||||||
</NavListItem>
|
</NavListItem>
|
||||||
)
|
)
|
||||||
|
@ -68,12 +74,14 @@ const SideNav = React.createClass({
|
||||||
return isHidden
|
return isHidden
|
||||||
? null
|
? null
|
||||||
: <NavBar location={location}>
|
: <NavBar location={location}>
|
||||||
|
<div className="sidebar--item">
|
||||||
<Link
|
<Link
|
||||||
to={`${sourcePrefix}/${DEFAULT_HOME_PAGE}`}
|
to={`${sourcePrefix}/${DEFAULT_HOME_PAGE}`}
|
||||||
className="sidebar__logo"
|
className="sidebar--square sidebar--logo"
|
||||||
>
|
>
|
||||||
<span className="icon cubo-uniform" />
|
<span className="sidebar--icon icon cubo-uniform" />
|
||||||
</Link>
|
</Link>
|
||||||
|
</div>
|
||||||
<NavBlock icon="cubo-node" link={`${sourcePrefix}/hosts`}>
|
<NavBlock icon="cubo-node" link={`${sourcePrefix}/hosts`}>
|
||||||
<NavHeader link={`${sourcePrefix}/hosts`} title="Host List" />
|
<NavHeader link={`${sourcePrefix}/hosts`} title="Host List" />
|
||||||
</NavBlock>
|
</NavBlock>
|
||||||
|
@ -108,8 +116,20 @@ const SideNav = React.createClass({
|
||||||
title="Configuration"
|
title="Configuration"
|
||||||
/>
|
/>
|
||||||
</NavBlock>
|
</NavBlock>
|
||||||
|
<div className="sidebar--bottom">
|
||||||
|
<div className="sidebar--item">
|
||||||
|
<div className="sidebar--square">
|
||||||
|
<span className="sidebar--icon icon zap" />
|
||||||
|
</div>
|
||||||
|
<div className="sidebar-menu">
|
||||||
|
<div className="sidebar-menu--heading">
|
||||||
|
Version: {V_NUMBER}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
{isUsingAuth
|
{isUsingAuth
|
||||||
? <NavBlock icon="user" className="sidebar__square-last">
|
? <NavBlock icon="user" className="sidebar--item-last">
|
||||||
{customLinks
|
{customLinks
|
||||||
? this.renderUserMenuBlockWithCustomLinks(
|
? this.renderUserMenuBlockWithCustomLinks(
|
||||||
customLinks,
|
customLinks,
|
||||||
|
|
|
@ -55,7 +55,11 @@ ul.dropdown-menu {
|
||||||
.fancy-scroll--thumb-v { @include gradient-v($c-neutrino,$c-laser); }
|
.fancy-scroll--thumb-v { @include gradient-v($c-neutrino,$c-laser); }
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Hacky Fix to make this work in Safari */
|
/* Hacky fix to hide strange white lines in chrome */
|
||||||
|
.fancy-scroll--view {
|
||||||
|
margin-right: -16px !important
|
||||||
|
}
|
||||||
|
/* Hacky Fix to make fancy scrollbars work in Safari */
|
||||||
.query-builder--list {
|
.query-builder--list {
|
||||||
position: relative;
|
position: relative;
|
||||||
|
|
||||||
|
|
|
@ -12,7 +12,7 @@
|
||||||
}
|
}
|
||||||
.chronograf-root > .page-spinner {
|
.chronograf-root > .page-spinner {
|
||||||
// Center the spinner based on the main content window, not the entire screen
|
// Center the spinner based on the main content window, not the entire screen
|
||||||
left: calc(50% + #{$sidebar-width});
|
left: calc(50% + #{$sidebar--width});
|
||||||
}
|
}
|
||||||
|
|
||||||
@keyframes pageSpinner {
|
@keyframes pageSpinner {
|
||||||
|
|
|
@ -36,7 +36,6 @@ $breakpoint-c: 2100px;
|
||||||
.query-builder--heading {
|
.query-builder--heading {
|
||||||
font-size: 17px;
|
font-size: 17px;
|
||||||
font-weight: 400;
|
font-weight: 400;
|
||||||
text-transform: uppercase;
|
|
||||||
}
|
}
|
||||||
.query-maker .multi-select-dropdown .dropdown-toggle {
|
.query-maker .multi-select-dropdown .dropdown-toggle {
|
||||||
width: 140px;
|
width: 140px;
|
||||||
|
|
|
@ -50,7 +50,8 @@
|
||||||
Sortable Tables
|
Sortable Tables
|
||||||
----------------------------------------------
|
----------------------------------------------
|
||||||
*/
|
*/
|
||||||
table.table thead th.sortable-header {
|
table.table thead th.sortable-header,
|
||||||
|
.alert-history-table--th.sortable-header {
|
||||||
transition:
|
transition:
|
||||||
color 0.25s ease,
|
color 0.25s ease,
|
||||||
background-color 0.25s ease;
|
background-color 0.25s ease;
|
||||||
|
@ -172,15 +173,84 @@ $table-tab-scrollbar-height: 6px;
|
||||||
.table.table-highlight > tbody > tr.highlight {
|
.table.table-highlight > tbody > tr.highlight {
|
||||||
background-color: $g4-onyx;
|
background-color: $g4-onyx;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Responsive Tables
|
Alert History "Page"
|
||||||
|
----------------------------------------------
|
||||||
|
*/
|
||||||
|
.alert-history-page {
|
||||||
|
.page-contents > .container-fluid,
|
||||||
|
.page-contents > .container-fluid > .row,
|
||||||
|
.page-contents > .container-fluid > .row > .col-md-12,
|
||||||
|
.page-contents > .container-fluid > .row > .col-md-12 > .panel {
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.col-md-12 > .panel {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: stretch;
|
||||||
|
|
||||||
|
> .panel-body {flex: 1 0 0;}
|
||||||
|
.generic-empty-state {height: 100%;}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
Misc
|
||||||
|
----------------------------------------------
|
||||||
|
*/
|
||||||
|
.table .empty-string {
|
||||||
|
font-weight: 500;
|
||||||
|
color: $g8-storm;
|
||||||
|
font-style: italic;
|
||||||
|
}
|
||||||
|
.table .table--temp-var {
|
||||||
|
color: $c-comet;
|
||||||
|
font-weight: 600;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
Alert History "Table"
|
||||||
----------------------------------------------
|
----------------------------------------------
|
||||||
*/
|
*/
|
||||||
|
|
||||||
@media screen and (max-width: 767px) {
|
.alert-history-table {
|
||||||
.table-responsive {
|
height: 100%;
|
||||||
border-radius: 3px;
|
display: flex;
|
||||||
border-color: $g5-pepper;
|
flex-direction: column;
|
||||||
@include custom-scrollbar($g5-pepper, $c-pool);
|
align-items: stretch;
|
||||||
|
}
|
||||||
|
.alert-history-table--thead {
|
||||||
|
display: flex;
|
||||||
|
width: 100%;
|
||||||
|
border-bottom: 2px solid $g5-pepper;
|
||||||
|
}
|
||||||
|
.alert-history-table--th {
|
||||||
|
@include no-user-select();
|
||||||
|
padding: 8px;
|
||||||
|
font-size: 13px;
|
||||||
|
font-weight: 500;
|
||||||
|
color: $g17-whisper;
|
||||||
|
}
|
||||||
|
.alert-history-table--tbody {
|
||||||
|
flex: 1 0 0;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
.alert-history-table--tr {
|
||||||
|
display: flex;
|
||||||
|
width: 100%;
|
||||||
|
&:hover {
|
||||||
|
background-color: $g4-onyx;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
.alert-history-table--td {
|
||||||
|
font-size: 12px;
|
||||||
|
font-family: $code-font;
|
||||||
|
font-weight: 500;
|
||||||
|
padding: 4px 8px;
|
||||||
|
line-height: 1.42857143em;
|
||||||
|
color: $g13-mist;
|
||||||
|
white-space: pre-wrap;
|
||||||
|
word-break: break-all;
|
||||||
|
}
|
||||||
|
|
|
@ -19,5 +19,5 @@
|
||||||
|
|
||||||
// Make Overlay Technology full screen
|
// Make Overlay Technology full screen
|
||||||
.overlay-technology {
|
.overlay-technology {
|
||||||
left: -($sidebar-width) !important;
|
left: -($sidebar--width) !important;
|
||||||
}
|
}
|
|
@ -3,293 +3,177 @@
|
||||||
----------------------------------------------
|
----------------------------------------------
|
||||||
*/
|
*/
|
||||||
|
|
||||||
$sidebar-width: 60px;
|
$sidebar--width: 60px;
|
||||||
$sidebar-menu-gutter: 30px;
|
|
||||||
$sidebar-menu-indent: 13px;
|
|
||||||
|
|
||||||
$sidebar-hover: $g8-storm;
|
$sidebar--gradient-start: $g7-graphite;
|
||||||
$sidebar-item-hover: $g7-graphite;
|
$sidebar--gradient-end: $g4-onyx;
|
||||||
$sidebar-lighter: $g8-storm;
|
|
||||||
$sidebar-light: $g7-graphite;
|
$sidebar--logo-bg: $g19-ghost;
|
||||||
$sidebar-dark: $g4-onyx;
|
$sidebar--logo-color: $c-pool;
|
||||||
$sidebar-icon: $g11-sidewalk;
|
$sidebar--logo-bg-hover: $g20-white;
|
||||||
$sidebar-text: $g13-mist;
|
$sidebar--logo-color-hover: $c-laser;
|
||||||
$sidebar-icon-hover: $g20-white;
|
|
||||||
$sidebar-icon-active: $g20-white;
|
$sidebar--item-bg: transparent;
|
||||||
$sidebar-active-bg: $c-pool;
|
$sidebar--item-bg-hover: $c-pool;
|
||||||
$sidebar-active-accent: $c-laser;
|
$sidebar--item-bg-active: $g4-onyx;
|
||||||
$sidebar-logo-bg: $g17-whisper;
|
$sidebar--icon: $g11-sidewalk;
|
||||||
$sidebar-logo-color: $g8-storm;
|
$sidebar--icon-hover: $g20-white;
|
||||||
|
$sidebar--icon-active: $g20-white;
|
||||||
|
|
||||||
|
$sidebar-menu--bg: $c-pool;
|
||||||
|
$sidebar-menu--bg-accent: $c-comet;
|
||||||
|
$sidebar-menu--item-bg: $c-ocean;
|
||||||
|
$sidebar-menu--item-bg-accent: $c-star;
|
||||||
|
$sidebar-menu--item-bg-hover: $c-laser;
|
||||||
|
$sidebar-menu--item-bg-hover-accent: $c-potassium;
|
||||||
|
$sidebar-menu--item-text: $c-neutrino;
|
||||||
|
$sidebar-menu--item-text-hover: $g20-white;
|
||||||
|
$sidebar-menu--item-text-active: $g20-white;
|
||||||
|
$sidebar-menu--gutter: 18px;
|
||||||
|
|
||||||
// Sidebar styles
|
|
||||||
.sidebar {
|
.sidebar {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
width: $sidebar-width;
|
width: $sidebar--width;
|
||||||
@include gradient-v($sidebar-light,$sidebar-dark);
|
@include gradient-v($sidebar--gradient-start,$sidebar--gradient-end);
|
||||||
|
}
|
||||||
&__logo {
|
.sidebar--bottom {
|
||||||
width: $sidebar-width;
|
|
||||||
height: $sidebar-width;
|
|
||||||
background-color: $sidebar-logo-bg;
|
|
||||||
position: relative;
|
|
||||||
color: $sidebar-logo-color;
|
|
||||||
|
|
||||||
span.icon {
|
|
||||||
position: absolute;
|
|
||||||
top: 50%;
|
|
||||||
left: 50%;
|
|
||||||
transform: translate(-50%,-50%);
|
|
||||||
font-size: $sidebar-width * 0.4222;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
&__icon {
|
|
||||||
position: absolute;
|
|
||||||
top: 0;
|
|
||||||
left: 0;
|
|
||||||
width: 100%;
|
|
||||||
height: 100%;
|
|
||||||
transition:
|
|
||||||
background-color 0.25s ease,
|
|
||||||
color 0.25s ease;
|
|
||||||
color: $sidebar-icon;
|
|
||||||
|
|
||||||
span.icon {
|
|
||||||
position: absolute;
|
|
||||||
top: 50%;
|
|
||||||
left: 50%;
|
|
||||||
transform: translate(-50%,-50%);
|
|
||||||
font-size: $sidebar-width * 0.4222;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
&__square {
|
|
||||||
z-index: 999;
|
|
||||||
width: $sidebar-width;
|
|
||||||
height: $sidebar-width;
|
|
||||||
background-color: transparent;
|
|
||||||
position: relative;
|
|
||||||
color: $sidebar-icon;
|
|
||||||
|
|
||||||
/* Here for specificity issues */
|
|
||||||
.sidebar__icon {
|
|
||||||
&:link,
|
|
||||||
&:active,
|
|
||||||
&:visited {
|
|
||||||
transition:
|
|
||||||
background-color 0.25s ease,
|
|
||||||
color 0.25s ease;
|
|
||||||
color: $sidebar-icon;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
&:hover {
|
|
||||||
cursor: pointer;
|
|
||||||
|
|
||||||
.sidebar__icon {
|
|
||||||
color: $sidebar-icon-hover;
|
|
||||||
background-color: $sidebar-hover;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Show menu on hover */
|
|
||||||
.sidebar__menu-wrapper,
|
|
||||||
.sidebar__menu-wrapper-bottom {
|
|
||||||
visibility: visible;
|
|
||||||
}
|
|
||||||
.sidebar__menu {
|
|
||||||
opacity: 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Active Indicator */
|
|
||||||
&:after {
|
|
||||||
content: '';
|
|
||||||
position: absolute;
|
|
||||||
top: 50%;
|
|
||||||
left: 0;
|
|
||||||
width: 4px;
|
|
||||||
height: 100%;
|
|
||||||
transform: translateY(-50%) scale(1,0);
|
|
||||||
background-color: $c-pool;
|
|
||||||
z-index: 999;
|
|
||||||
backface-visibility: hidden;
|
|
||||||
transition:
|
|
||||||
transform 0.4s ease;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Active State Styles */
|
|
||||||
&.active {
|
|
||||||
&:after {
|
|
||||||
transform: translateY(-50%) scale(1,1);
|
|
||||||
transition:
|
|
||||||
transform 0.31s cubic-bezier(0.175, 0.885, 0.32, 1.275);
|
|
||||||
}
|
|
||||||
|
|
||||||
.sidebar__icon {
|
|
||||||
color: $sidebar-icon-active;
|
|
||||||
|
|
||||||
&:link,
|
|
||||||
&:active,
|
|
||||||
&:visited,
|
|
||||||
&:hover {
|
|
||||||
color: $sidebar-icon-active;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
&-last {
|
|
||||||
position: absolute;
|
position: absolute;
|
||||||
bottom: 0;
|
bottom: 0;
|
||||||
|
left: 0;
|
||||||
.sidebar__menu-wrapper {
|
|
||||||
bottom: 0;
|
|
||||||
top: initial;
|
|
||||||
}
|
|
||||||
.sidebar__menu-route {
|
|
||||||
order: 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
&__menu {
|
|
||||||
border-radius: 0 $radius $radius 0;
|
|
||||||
background: $sidebar-hover;
|
|
||||||
opacity: 0;
|
|
||||||
transition: opacity 0.25s ease;
|
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
list-style: none;
|
justify-content: flex-end;
|
||||||
|
width: $sidebar--width;
|
||||||
|
}
|
||||||
|
|
||||||
&-wrapper {
|
/*
|
||||||
|
Sidebar Items
|
||||||
|
----------------------------------------------
|
||||||
|
*/
|
||||||
|
.sidebar--item {
|
||||||
|
width: $sidebar--width;
|
||||||
|
height: $sidebar--width;
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
.sidebar--square {
|
||||||
|
display: block;
|
||||||
|
position: relative;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
background-color: $sidebar--item-bg;
|
||||||
|
transition: none;
|
||||||
|
}
|
||||||
|
.sidebar--icon {
|
||||||
|
position: absolute;
|
||||||
|
color: $sidebar--icon;
|
||||||
|
top: 50%;
|
||||||
|
left: 50%;
|
||||||
|
transform: translate(-50%,-50%);
|
||||||
|
font-size: $sidebar--width * 0.4222;
|
||||||
|
transition:
|
||||||
|
text-shadow 0.4s ease;
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
Sidebar Item Active State
|
||||||
|
*/
|
||||||
|
.sidebar--item.active {
|
||||||
|
.sidebar--square {background-color: $sidebar--item-bg-active;}
|
||||||
|
.sidebar--icon {
|
||||||
|
color: $sidebar--icon-active;
|
||||||
|
text-shadow:
|
||||||
|
0 0 9px $c-laser,
|
||||||
|
0 0 15px $c-ocean,
|
||||||
|
0 0 20px $c-amethyst;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
Sidebar Item Hover State
|
||||||
|
*/
|
||||||
|
.sidebar--item:hover {
|
||||||
|
cursor: pointer;
|
||||||
|
|
||||||
|
.sidebar--square {background-color: $sidebar--item-bg-hover;}
|
||||||
|
.sidebar--icon {color: $sidebar--icon-hover;}
|
||||||
|
.sidebar-menu {display: flex;}
|
||||||
|
}
|
||||||
|
.sidebar--item.active:hover .sidebar--icon {
|
||||||
|
text-shadow:
|
||||||
|
0 0 9px $c-yeti,
|
||||||
|
0 0 15px $c-hydrogen,
|
||||||
|
0 0 20px $c-laser;
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
Sidebar Logo Square
|
||||||
|
*/
|
||||||
|
.sidebar--square.sidebar--logo {
|
||||||
|
background-color: $sidebar--logo-bg;
|
||||||
|
.sidebar--icon {color: $sidebar--logo-color;}
|
||||||
|
}
|
||||||
|
.sidebar--item:hover .sidebar--square.sidebar--logo {
|
||||||
|
background-color: $sidebar--logo-bg-hover;
|
||||||
|
.sidebar--icon {color: $sidebar--logo-color-hover;}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
Sidebar Sub Menus
|
||||||
|
----------------------------------------------
|
||||||
|
*/
|
||||||
|
.sidebar-menu {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
top: 0;
|
top: 0;
|
||||||
left: 100%;
|
left: 100%;
|
||||||
z-index: 999;
|
border-radius: 0 $radius $radius 0;
|
||||||
visibility: hidden;
|
@include gradient-h($sidebar-menu--bg,$sidebar-menu--bg-accent);
|
||||||
display: flex;
|
transition: opacity 0.25s ease;
|
||||||
transition: all 0.25s ease;
|
display: none;
|
||||||
}
|
flex-direction: column;
|
||||||
&-wrapper-bottom {
|
}
|
||||||
position: absolute;
|
.sidebar-menu--heading,
|
||||||
bottom: 0;
|
.sidebar-menu--item {
|
||||||
left: 100%;
|
|
||||||
z-index: 999;
|
|
||||||
visibility: hidden;
|
|
||||||
display: flex;
|
|
||||||
transition: all 0.25s ease;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
&__menu-heading,
|
|
||||||
&__menu-item {
|
|
||||||
width: 100%;
|
width: 100%;
|
||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
margin: 0;
|
|
||||||
display: block;
|
display: block;
|
||||||
@include no-user-select();
|
@include no-user-select();
|
||||||
&:hover {
|
&:hover {
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
.sidebar-menu--item:link,
|
||||||
&__menu-item {
|
.sidebar-menu--item:active,
|
||||||
color: $sidebar-text;
|
.sidebar-menu--item:visited {
|
||||||
|
color: $sidebar-menu--item-text;
|
||||||
font-size: 15px;
|
font-size: 15px;
|
||||||
line-height: 22px;
|
line-height: 22px;
|
||||||
font-weight: 500;
|
font-weight: 500;
|
||||||
position: relative;
|
position: relative;
|
||||||
padding: 4px $sidebar-menu-gutter;
|
padding: 4px $sidebar-menu--gutter;
|
||||||
transition:
|
transition: none;
|
||||||
color 0.25s ease,
|
|
||||||
background-color 0.25s ease;
|
|
||||||
|
|
||||||
// Overriding link styles
|
|
||||||
&:link,
|
|
||||||
&:active,
|
|
||||||
&:visited {
|
|
||||||
color: $sidebar-text;
|
|
||||||
font-weight: 500;
|
|
||||||
transition:
|
|
||||||
color 0.25s ease,
|
|
||||||
background-color 0.25s ease;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Rounding top outside corner to match container
|
|
||||||
&:first-child {
|
|
||||||
border-top-right-radius: $radius;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Rounding bottom outside corner of match container
|
// Rounding bottom outside corner of match container
|
||||||
&:last-child {
|
&:last-child {border-bottom-right-radius: $radius;}
|
||||||
border-bottom-right-radius: $radius;
|
}
|
||||||
}
|
.sidebar-menu--item.active:link,
|
||||||
|
.sidebar-menu--item.active:active,
|
||||||
// Used for sub-navigation
|
.sidebar-menu--item.active:visited {
|
||||||
small {
|
@include gradient-h($sidebar-menu--item-bg,$sidebar-menu--item-bg-accent);
|
||||||
font-size: 13px;
|
color: $sidebar-menu--item-text-active;
|
||||||
border-left: 2px solid $sidebar-icon;
|
}
|
||||||
padding-left: $sidebar-menu-indent;
|
.sidebar-menu--item:hover,
|
||||||
display: inline-block;
|
.sidebar-menu--item.active:hover {
|
||||||
transition: border-color 0.25s ease;
|
@include gradient-h($sidebar-menu--item-bg-hover,$sidebar-menu--item-bg-hover-accent);
|
||||||
}
|
color: $sidebar-menu--item-text-hover;
|
||||||
// Invisible until item is active, indicates active item
|
}
|
||||||
&:after {
|
.sidebar-menu--heading,
|
||||||
position: absolute;
|
.sidebar-menu--heading:link,
|
||||||
top: 50%;
|
.sidebar-menu--heading:visited,
|
||||||
left: $sidebar-menu-gutter /2;
|
.sidebar-menu--heading:active,
|
||||||
content: '';
|
.sidebar-menu--heading:hover, {
|
||||||
width: 8px;
|
color: $g20-white;
|
||||||
height: 8px;
|
height: $sidebar--width;
|
||||||
border-radius: 50%;
|
line-height: $sidebar--width;
|
||||||
background-color: transparent;
|
font-size: 19px;
|
||||||
transform: translate(-50%,-50%);
|
font-weight: 400;
|
||||||
}
|
padding: 0px $sidebar-menu--gutter;
|
||||||
&:hover {
|
|
||||||
background-color: $sidebar-item-hover;
|
|
||||||
color: $sidebar-icon-hover;
|
|
||||||
|
|
||||||
small {
|
|
||||||
border-color: $sidebar-icon-hover;
|
|
||||||
}
|
|
||||||
// Emphasize rename icon on hover
|
|
||||||
.js-open-rename-cluster-modal {
|
|
||||||
opacity: 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
&.active {
|
|
||||||
@include gradient-h($sidebar-active-bg,$sidebar-active-accent);
|
|
||||||
color: $sidebar-icon-hover;
|
|
||||||
|
|
||||||
&:link,
|
|
||||||
&:active,
|
|
||||||
&:visited {
|
|
||||||
color: $sidebar-icon-hover;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Show indicator
|
|
||||||
&:after {
|
|
||||||
background-color: $sidebar-icon-active;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Show rename icon when active
|
|
||||||
.js-open-rename-cluster-modal {
|
|
||||||
background-color: $c-laser;
|
|
||||||
opacity: 1;
|
|
||||||
|
|
||||||
&:hover {
|
|
||||||
background-color: $c-hydrogen;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
&__menu-heading {
|
|
||||||
color: $g20-white;
|
|
||||||
height: $sidebar-width;
|
|
||||||
line-height: $sidebar-width;
|
|
||||||
font-size: 17px;
|
|
||||||
text-transform: uppercase;
|
|
||||||
font-weight: 400;
|
|
||||||
padding: 0px $sidebar-menu-gutter;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,7 +11,7 @@
|
||||||
overflow: auto;
|
overflow: auto;
|
||||||
@include custom-scrollbar($g3-castle, $c-pool);
|
@include custom-scrollbar($g3-castle, $c-pool);
|
||||||
@include gradient-v($g3-castle, $g0-obsidian);
|
@include gradient-v($g3-castle, $g0-obsidian);
|
||||||
padding: $sidebar-width;
|
padding: $sidebar--width;
|
||||||
}
|
}
|
||||||
.auth-image {
|
.auth-image {
|
||||||
background-image: url(assets/images/auth-bg.svg);
|
background-image: url(assets/images/auth-bg.svg);
|
||||||
|
@ -47,8 +47,8 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
.btn {
|
.btn {
|
||||||
margin-top: ($sidebar-width / 2);
|
margin-top: ($sidebar--width / 2);
|
||||||
margin-bottom: $sidebar-width;
|
margin-bottom: $sidebar--width;
|
||||||
|
|
||||||
> .icon {
|
> .icon {
|
||||||
font-size: 20px;
|
font-size: 20px;
|
||||||
|
@ -67,7 +67,7 @@
|
||||||
.auth-credits {
|
.auth-credits {
|
||||||
z-index: 90;
|
z-index: 90;
|
||||||
position: absolute;
|
position: absolute;
|
||||||
bottom: ($sidebar-width / 4);
|
bottom: ($sidebar--width / 4);
|
||||||
left: 50%;
|
left: 50%;
|
||||||
transform: translateX(-50%);
|
transform: translateX(-50%);
|
||||||
font-size: 12px;
|
font-size: 12px;
|
||||||
|
|
|
@ -192,3 +192,15 @@ br {
|
||||||
|
|
||||||
p {font-size: 13px;}
|
p {font-size: 13px;}
|
||||||
}
|
}
|
||||||
|
.alerts-widget {
|
||||||
|
height: 100%;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: stretch;
|
||||||
|
|
||||||
|
> .btn {margin: 20px 0;}
|
||||||
|
|
||||||
|
.alert-history-table {
|
||||||
|
flex: 1 0 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue