From 95cfc7d5aa22ef01581fa1f30e96bb4b613ef0aa Mon Sep 17 00:00:00 2001 From: Tim Raymond Date: Thu, 6 Oct 2016 11:25:31 -0400 Subject: [PATCH] Remove Overview page This removes the Overview page from the navigation as well as all associated JS that powered the Overview page. Styles for the Overview page have been left in place, since there doesn't appear to be a good option for performing CSS dead code elimination at this time. --- ui/spec/overview/components/NodeTableSpec.js | 44 ------ .../overview/containers/OverviewPageSpec.js | 109 --------------- ui/src/index.js | 2 - .../overview/components/ClusterStatsPanel.js | 64 --------- ui/src/overview/components/MiscStatsPanel.js | 81 ----------- ui/src/overview/components/NodeTable.js | 80 ----------- ui/src/overview/components/NodeTableRow.js | 76 ---------- ui/src/overview/constants/index.js | 2 - ui/src/overview/containers/OverviewPage.js | 77 ---------- ui/src/overview/index.js | 2 - ui/src/overview/reducers/hosts.js | 68 --------- ui/src/overview/reducers/index.js | 10 -- ui/src/overview/reducers/time.js | 26 ---- ui/src/overview/store/configureStore.js | 18 --- ui/src/side_nav/components/SideNav.js | 1 - ui/src/style/_OverviewPage.scss | 132 ------------------ 16 files changed, 792 deletions(-) delete mode 100644 ui/spec/overview/components/NodeTableSpec.js delete mode 100644 ui/spec/overview/containers/OverviewPageSpec.js delete mode 100644 ui/src/overview/components/ClusterStatsPanel.js delete mode 100644 ui/src/overview/components/MiscStatsPanel.js delete mode 100644 ui/src/overview/components/NodeTable.js delete mode 100644 ui/src/overview/components/NodeTableRow.js delete mode 100644 ui/src/overview/constants/index.js delete mode 100644 ui/src/overview/containers/OverviewPage.js delete mode 100644 ui/src/overview/index.js delete mode 100644 ui/src/overview/reducers/hosts.js delete mode 100644 ui/src/overview/reducers/index.js delete mode 100644 ui/src/overview/reducers/time.js delete mode 100644 ui/src/overview/store/configureStore.js delete mode 100644 ui/src/style/_OverviewPage.scss diff --git a/ui/spec/overview/components/NodeTableSpec.js b/ui/spec/overview/components/NodeTableSpec.js deleted file mode 100644 index 6d5d260a71..0000000000 --- a/ui/spec/overview/components/NodeTableSpec.js +++ /dev/null @@ -1,44 +0,0 @@ -import NodeTable from 'src/overview/components/NodeTable'; -import NodeTableRow from 'src/overview/components/NodeTableRow'; -import React from 'react'; -import TestUtils, {renderIntoDocument, scryRenderedComponentsWithType} from 'react-addons-test-utils'; -import {findDOMNode} from 'react-dom'; - -describe('Overview.Components.NodeTable', () => { - it('renders a NodeTableRow for each node (meta + data)', () => { - const cluster = { - "data": [ - { - "tcpAddr": "localhost:8088", - "httpAddr": "localhost:8086", - "id": 2, - "status": "joined" - }, - { - "tcpAddr": "localhost:8188", - "httpAddr": "localhost:8186", - "id": 6, - "status": "joined" - } - ], - "meta": [ - { - "addr": "localhost:8091" - } - ], - "id": "a cluster id" - }; - - const component = renderIntoDocument( - - ); - const nodeRows = scryRenderedComponentsWithType(component, NodeTableRow); - - expect(nodeRows.length).to.equal(3); - }); -}); diff --git a/ui/spec/overview/containers/OverviewPageSpec.js b/ui/spec/overview/containers/OverviewPageSpec.js deleted file mode 100644 index 009b347e28..0000000000 --- a/ui/spec/overview/containers/OverviewPageSpec.js +++ /dev/null @@ -1,109 +0,0 @@ -import React from 'react'; -import TestUtils, {renderIntoDocument, scryRenderedComponentsWithType} from 'react-addons-test-utils'; -import {findDOMNode} from 'react-dom'; -import {mount, shallow} from 'enzyme'; -import sinon from 'sinon'; -import * as api from 'src/shared/apis'; - -import {OverviewPage} from 'src/overview/containers/OverviewPage'; -import ClusterStatsPanel from 'src/overview/components/ClusterStatsPanel'; -import MiscStatsPanel from 'src/overview/components/MiscStatsPanel'; -import NodeTable from 'src/overview/components/NodeTable'; - -const clusterID = '1000'; -const showClustersResponse = { - data: [ - { - tcpAddr: 'localhost:8088', - httpAddr: 'localhost:8086', - id: 1, - status: 'joined' - }, - { - tcpAddr: 'localhost:8188', - httpAddr: 'localhost:8186', - id: 2, - status: 'joined' - } - ], - meta: [ - { - addr: 'localhost:8091' - } - ] -}; - -function setup(customProps = {}) { - const defaultProps = { - dataNodes: ['localhost:8086'], - params: {clusterID}, - addFlashMessage: function() {}, - }; - const props = Object.assign({}, defaultProps, customProps); - return mount(); -} - -xdescribe('Overview.Containers.OverviewPage', function() { - it('renders a spinner initially', function() { - const wrapper = shallow( {}} />); - - expect(wrapper.contains(
)).to.be.true; - }); - - describe('after being mounted', function() { - let stub; - beforeEach(function() { - stub = sinon.stub(api, 'showCluster').returns(Promise.resolve({ - data: showClustersResponse, - })); - }); - - afterEach(function() { - stub.restore(); - }); - - it('fetches cluster information after being mounted', function() { - setup(); - - expect(api.showCluster.calledWith(clusterID)).to.be.true; - }); - - it('hides the spinner', function(done) { - const wrapper = setup(); - - setTimeout(() => { - expect(wrapper.contains(
)).to.be.false; - done(); - }, 0); - }); - - it('fetches cluster information after being mounted', function() { - setup(); - - expect(api.showCluster.calledWith(clusterID)).to.be.true; - }); - - it('renders the correct panels', function(done) { - const wrapper = setup(); - - setTimeout(() => { - expect(wrapper.find(ClusterStatsPanel)).to.have.length(1); - expect(wrapper.find(MiscStatsPanel)).to.have.length(1); - expect(wrapper.find(NodeTable)).to.have.length(1); - done(); - }, 0); - }); - - it('passes the correct props to NodeTable', function(done) { - const wrapper = setup(); - - setTimeout(() => { - const table = wrapper.find(NodeTable); - expect(table.props().cluster).to.eql(showClustersResponse); - expect(table.props().dataNodes).to.eql(['localhost:8086']); - expect(table.props().clusterID).to.equal(clusterID); - done(); - }, 0); - }); - }); -}); diff --git a/ui/src/index.js b/ui/src/index.js index 3c25526c4e..4e12fabaf4 100644 --- a/ui/src/index.js +++ b/ui/src/index.js @@ -6,7 +6,6 @@ import {Router, Route, browserHistory} from 'react-router'; import App from 'src/App'; import CheckDataNodes from 'src/CheckDataNodes'; import {HostsPage, HostPage} from 'src/hosts'; -import OverviewPage from 'src/overview'; import QueriesPage from 'src/queries'; import TasksPage from 'src/tasks'; import RetentionPoliciesPage from 'src/retention_policies'; @@ -122,7 +121,6 @@ const Root = React.createClass({ - diff --git a/ui/src/overview/components/ClusterStatsPanel.js b/ui/src/overview/components/ClusterStatsPanel.js deleted file mode 100644 index 0d71022663..0000000000 --- a/ui/src/overview/components/ClusterStatsPanel.js +++ /dev/null @@ -1,64 +0,0 @@ -import React, {PropTypes} from 'react'; -import MiniGraph from 'shared/components/MiniGraph'; -import AutoRefresh from 'shared/components/AutoRefresh'; -const RefreshingMiniGraph = AutoRefresh(MiniGraph); -import {OVERVIEW_TIME_RANGE, OVERVIEW_INTERVAL} from '../constants'; - -const ClusterStatsPanel = React.createClass({ - propTypes: { - dataNodes: PropTypes.arrayOf(PropTypes.string.isRequired).isRequired, - clusterID: PropTypes.string.isRequired, - refreshIntervalMs: PropTypes.number.isRequired, - }, - render() { - const {dataNodes, refreshIntervalMs} = this.props; - - // For active writes/queries, we GROUP BY nodeID because we want to grab all of the - // values for each node and sum the results. - const queries = [ - { - queryDescription: "Active Queries", - host: dataNodes, - database: '_internal', - text: `SELECT NON_NEGATIVE_DERIVATIVE(MAX(queryReq)) FROM httpd WHERE time > now() - ${OVERVIEW_TIME_RANGE} AND clusterID='${this.props.clusterID}' GROUP by nodeID, time(${OVERVIEW_INTERVAL})`, - options: {combineSeries: true}, - }, - { - queryDescription: "Avg Query Latency (ms)", - host: dataNodes, - database: '_internal', - text: `SELECT mean(queryDurationNs)/100000000000 FROM queryExecutor WHERE time > now() - ${OVERVIEW_TIME_RANGE} AND clusterID='${this.props.clusterID}' GROUP BY time(${OVERVIEW_INTERVAL})`, - }, - { - queryDescription: "Active Writes", - host: dataNodes, - database: '_internal', - text: `SELECT NON_NEGATIVE_DERIVATIVE(MAX(req)) FROM "write" WHERE time > now() - ${OVERVIEW_TIME_RANGE} AND clusterID='${this.props.clusterID}' GROUP BY nodeID, time(${OVERVIEW_INTERVAL})`, - options: {combineSeries: true}, - }, - ]; - - return ( -
-
-
-

Cluster Speed

-
-
- { - queries.map(({options, host, database, text, queryDescription}, i) => { - return ( - -

Waiting for stats...

-
- ); - }) - } -
-
-
- ); - }, -}); - -export default ClusterStatsPanel; diff --git a/ui/src/overview/components/MiscStatsPanel.js b/ui/src/overview/components/MiscStatsPanel.js deleted file mode 100644 index 4253d43db4..0000000000 --- a/ui/src/overview/components/MiscStatsPanel.js +++ /dev/null @@ -1,81 +0,0 @@ -import React, {PropTypes} from 'react'; -import {formatBytes} from 'utils/formatting'; -import {diskBytesFromShard} from 'shared/parsing/diskBytes'; -import {clusterDiskUsage} from 'shared/apis/stats'; -import MiniGraph from 'shared/components/MiniGraph'; -import AutoRefresh from 'shared/components/AutoRefresh'; -const RefreshingMiniGraph = AutoRefresh(MiniGraph); -import {OVERVIEW_TIME_RANGE, OVERVIEW_INTERVAL} from '../constants'; - -const MiscStatsPanel = React.createClass({ - propTypes: { - dataNodes: PropTypes.arrayOf(PropTypes.string.isRequired).isRequired, - clusterID: PropTypes.string.isRequired, - refreshIntervalMs: PropTypes.number.isRequired, - }, - getInitialState() { - return { - diskUsed: 0, - influxVersion: null, - }; - }, - componentDidMount() { - clusterDiskUsage(this.props.dataNodes, this.props.clusterID).then((res) => { - this.setState({ - diskUsed: diskBytesFromShard(res.data).bytes, - influxVersion: res.headers['x-influxdb-version'], - }); - }); - }, - render() { - const {influxVersion, diskUsed} = this.state; - const {dataNodes, refreshIntervalMs} = this.props; - const queries = [ - { - queryDescription: 'Bytes Allocated', - host: dataNodes, - database: '_internal', - text: `select max(Alloc) AS bytes_allocated from runtime where time > now() - ${OVERVIEW_TIME_RANGE} AND clusterID='${this.props.clusterID}' group by time(${OVERVIEW_INTERVAL})`, - }, - { - queryDescription: 'Heap Bytes', - host: dataNodes, - database: '_internal', - text: `select max(HeapInUse) AS heap_bytes from runtime where time > now() - ${OVERVIEW_TIME_RANGE} AND clusterID='${this.props.clusterID}' group by time(${OVERVIEW_INTERVAL})`, - }, - ]; - - return ( -
-
-
-

Misc Stats

-
-
-
-
- Version:{influxVersion} -
-
- Disk Use:{formatBytes(diskUsed)} -
-
-
- { - queries.map(({host, database, text, queryDescription}, i) => { - return ( - -

Waiting for stats...

-
- ); - }) - } -
-
-
-
- ); - }, -}); - -export default MiscStatsPanel; diff --git a/ui/src/overview/components/NodeTable.js b/ui/src/overview/components/NodeTable.js deleted file mode 100644 index e8a4be8f21..0000000000 --- a/ui/src/overview/components/NodeTable.js +++ /dev/null @@ -1,80 +0,0 @@ -import React, {PropTypes} from 'react'; -import _ from 'lodash'; - -import NodeTableRow from './NodeTableRow'; - -const NodeTable = React.createClass({ - propTypes: { - refreshIntervalMs: PropTypes.number.isRequired, - dataNodes: PropTypes.arrayOf(PropTypes.string.isRequired).isRequired, - cluster: PropTypes.shape({ - data: PropTypes.arrayOf(PropTypes.shape({})).isRequired, - meta: PropTypes.arrayOf(PropTypes.shape({})).isRequired, - }), - clusterID: PropTypes.string.isRequired, - }, - - render() { - const {cluster, clusterID, dataNodes, refreshIntervalMs} = this.props; - const data = _.map(cluster.data, (node) => { - // The nodeID tag is for data nodes is currently the TCP address, but is fickle and - // possibly subject to change. - return {addr: node.httpAddr, type: 'data', nodeID: node.tcpAddr}; - }); - const meta = _.map(cluster.meta, (node) => { - return {addr: node.addr, type: 'meta'}; - }); - - return ( -
-
-
-
-

Data

-
-
-
- - - - - - - - - - - {data.map((n, i) => )} - -
NodeDisk UsedActive QueriesActive Writes
-
-
-
-
-
-
-
-

Meta

-
-
-
- - - - - - - - {meta.map((n, i) => )} - -
Node
-
-
-
-
-
- ); - }, -}); - -export default NodeTable; diff --git a/ui/src/overview/components/NodeTableRow.js b/ui/src/overview/components/NodeTableRow.js deleted file mode 100644 index a4e8fbbe32..0000000000 --- a/ui/src/overview/components/NodeTableRow.js +++ /dev/null @@ -1,76 +0,0 @@ -import React, {PropTypes} from 'react'; -import {formatBytes} from 'utils/formatting'; -import MiniGraph from 'shared/components/MiniGraph'; -import AutoRefresh from 'shared/components/AutoRefresh'; -import {nodeDiskUsage} from 'shared/apis/stats'; -import {diskBytesFromShard} from 'shared/parsing/diskBytes'; -const RefreshingMiniGraph = AutoRefresh(MiniGraph); -import {OVERVIEW_TIME_RANGE, OVERVIEW_INTERVAL} from '../constants'; - -const {string, shape, number} = PropTypes; -const NodeTableRow = React.createClass({ - propTypes: { - refreshIntervalMs: number.isRequired, - dataNodes: PropTypes.arrayOf(PropTypes.string.isRequired).isRequired, - clusterID: string.isRequired, - node: shape({ - addr: string.isRequired, - type: string.isRequired, - }), - }, - - getInitialState() { - return { - diskUsed: 0, - }; - }, - - componentDidMount() { - if (this.props.node.type !== 'data') { - return; - } - - const {node, dataNodes, clusterID} = this.props; - - nodeDiskUsage(dataNodes, clusterID, node.nodeID).then((resp) => { - this.setState({ - diskUsed: diskBytesFromShard(resp.data).bytes, - }); - }); - }, - - render() { - const {node, dataNodes, clusterID, refreshIntervalMs} = this.props; - const diskUsed = formatBytes(this.state.diskUsed); - - const activeQueries = `SELECT NON_NEGATIVE_DERIVATIVE(max(queryReq)) FROM httpd WHERE time > now() - ${OVERVIEW_TIME_RANGE} AND nodeID='${node.nodeID}' AND clusterID='${clusterID}' GROUP by time(${OVERVIEW_INTERVAL})`; - const activeWrites = `SELECT NON_NEGATIVE_DERIVATIVE(max(req)) FROM "write" WHERE time > now() - ${OVERVIEW_TIME_RANGE} AND nodeID='${node.nodeID}' AND clusterID='${clusterID}' GROUP BY time(${OVERVIEW_INTERVAL})`; - - if (node.type !== 'data') { - return ( - - {node.addr} - - ); - } - - return ( - - {node.addr} - {diskUsed} - - -

Waiting for stats...

-
- - - -

Waiting for stats..

-
- - - ); - }, -}); - -export default NodeTableRow; diff --git a/ui/src/overview/constants/index.js b/ui/src/overview/constants/index.js deleted file mode 100644 index 8fa00cba89..0000000000 --- a/ui/src/overview/constants/index.js +++ /dev/null @@ -1,2 +0,0 @@ -export const OVERVIEW_TIME_RANGE = '1h'; -export const OVERVIEW_INTERVAL = '30s'; diff --git a/ui/src/overview/containers/OverviewPage.js b/ui/src/overview/containers/OverviewPage.js deleted file mode 100644 index a47af9b9c7..0000000000 --- a/ui/src/overview/containers/OverviewPage.js +++ /dev/null @@ -1,77 +0,0 @@ -import React, {PropTypes} from 'react'; -import NodeTable from '../components/NodeTable'; -import MiscStatsPanel from '../components/MiscStatsPanel'; -import ClusterStatsPanel from '../components/ClusterStatsPanel'; -import FlashMessages from 'shared/components/FlashMessages'; -import {showCluster} from 'shared/apis'; - -export const OverviewPage = React.createClass({ - propTypes: { - params: PropTypes.shape({ - clusterID: PropTypes.string.isRequired, - }).isRequired, - dataNodes: PropTypes.arrayOf(PropTypes.string.isRequired).isRequired, - addFlashMessage: PropTypes.func.isRequired, // Injected by the `FlashMessages` wrapper - }, - - getInitialState() { - return { - isFetching: true, - // Raw output of plutonium's `/show-cluster` - includes both meta - // and data node information. - cluster: {}, - }; - }, - - componentDidMount() { - const {clusterID} = this.props.params; - showCluster(clusterID).then((resp) => { - this.setState({cluster: resp.data}); - }).catch(() => { - this.props.addFlashMessage({ - text: 'Something went wrong! Try refreshing your browser and email support@influxdata.com if the problem persists.', - type: 'error', - }); - }).then(() => { - this.setState({isFetching: false}); - }); - }, - - render() { - if (this.state.isFetching) { - return
; - } - - const {cluster} = this.state; - const {dataNodes, params: {clusterID}} = this.props; - const clusterPanelRefreshMs = 10000; - const nodeTableRefreshMs = 10000; - const miscPanelRefreshMs = 30000; - - return ( -
-
-
-
-

- Cluster Overiew -

-
-
-
-
-
- - -
{/* /row */} - -
- -
-
{/* /container */} -
- ); - }, -}); - -export default FlashMessages(OverviewPage); diff --git a/ui/src/overview/index.js b/ui/src/overview/index.js deleted file mode 100644 index 1ae42e78c2..0000000000 --- a/ui/src/overview/index.js +++ /dev/null @@ -1,2 +0,0 @@ -import OverviewPage from './containers/OverviewPage'; -export default OverviewPage; diff --git a/ui/src/overview/reducers/hosts.js b/ui/src/overview/reducers/hosts.js deleted file mode 100644 index a38a5cebb4..0000000000 --- a/ui/src/overview/reducers/hosts.js +++ /dev/null @@ -1,68 +0,0 @@ -import u from 'updeep'; - -export default function hosts(state = {}, action) { - switch (action.type) { - case 'ADD_HOST': { - const {url, params} = action.payload; - - const update = { - [url]: { - nickname: params.nickname, - host: params.host, - port: params.port, - ssl: params.ssl, - username: params.username, - password: params.password, - }, - }; - - return u(update, state); - } - case 'LOAD_HOST_DIAGNOSTICS': { - const allSeries = action.response.results[0].series; - - const networkSeries = allSeries.find((s) => s.name === 'network'); - const hostnameIndex = networkSeries.columns.indexOf('hostname'); - const hostname = networkSeries.values[0][hostnameIndex]; - - const systemSeries = allSeries.find((s) => s.name === 'system'); - const uptimeIndex = systemSeries.columns.indexOf('uptime'); - const uptime = systemSeries.values[0][uptimeIndex]; - - const buildSeries = allSeries.find((s) => s.name === 'build'); - const versionIndex = buildSeries.columns.indexOf('Version'); - const version = buildSeries.values[0][versionIndex]; - - const update = { - [action.url]: { - diagnostics: { - hostname, - uptime, - version, - }, - }, - }; - - return u(update, state); - } - case 'DELETE_HOST': { - const stateCopy = Object.assign({}, state); - delete stateCopy[action.payload.url]; - return stateCopy; - } - case 'LOAD_SERVERS_IN_CLUSTER': { - const {host, dataNodes, metaNodes} = action.payload; - - const update = { - [host]: { - dataNodes, - metaNodes, - }, - }; - - return u(update, state); - } - default: - return state; - } -} diff --git a/ui/src/overview/reducers/index.js b/ui/src/overview/reducers/index.js deleted file mode 100644 index 964d7b3a14..0000000000 --- a/ui/src/overview/reducers/index.js +++ /dev/null @@ -1,10 +0,0 @@ -import {combineReducers} from 'redux'; -import time from './time'; -import hosts from './hosts'; - -const rootReducer = combineReducers({ - hosts, - time, -}); - -export default rootReducer; diff --git a/ui/src/overview/reducers/time.js b/ui/src/overview/reducers/time.js deleted file mode 100644 index 9b1b05e447..0000000000 --- a/ui/src/overview/reducers/time.js +++ /dev/null @@ -1,26 +0,0 @@ -import u from 'updeep'; - -export default function time(state = {}, action) { - switch (action.type) { - case 'SET_TIME_BOUNDS': { - const update = { - bounds: action.payload.bounds, - groupByInterval: action.payload.groupByInterval || state.groupByInterval, - }; - - return u(update, state); - } - case 'SET_AUTO_REFRESH': { - const update = { - autoRefresh: action.payload.milliseconds, - }; - - return u(update, state); - } - case 'SET_GROUP_BY': { - return u({groupByInterval: action.payload.groupByInterval}, state); - } - default: - return state; - } -} diff --git a/ui/src/overview/store/configureStore.js b/ui/src/overview/store/configureStore.js deleted file mode 100644 index d495d8e864..0000000000 --- a/ui/src/overview/store/configureStore.js +++ /dev/null @@ -1,18 +0,0 @@ -import {createStore, applyMiddleware} from 'redux'; -import thunkMiddleware from 'redux-thunk'; -import rootReducer from '../reducers'; - -import makeAppStorage from 'shared/middleware/appStorage'; -import makeQueryExecuter from 'shared/middleware/queryExecuter'; - -export default function configureStore(effectiveWindow, initialState) { - return createStore( - rootReducer, - initialState, - applyMiddleware( - thunkMiddleware, - makeAppStorage(effectiveWindow.localStorage), - makeQueryExecuter() - ) - ); -} diff --git a/ui/src/side_nav/components/SideNav.js b/ui/src/side_nav/components/SideNav.js index 93593871b7..3d83299d0b 100644 --- a/ui/src/side_nav/components/SideNav.js +++ b/ui/src/side_nav/components/SideNav.js @@ -27,7 +27,6 @@ const SideNav = React.createClass({ - Overview Manage Sources Queries Tasks diff --git a/ui/src/style/_OverviewPage.scss b/ui/src/style/_OverviewPage.scss deleted file mode 100644 index 456a7174d0..0000000000 --- a/ui/src/style/_OverviewPage.scss +++ /dev/null @@ -1,132 +0,0 @@ -.cluster-stat-tiles { - display: flex; - justify-content: space-between; -} -.cluster-stat-tile { - line-height: 1.75; - width: 49%; -} -$cluster-stat-height: 44px; -$cluster-stat-padding: 2em; -@keyframes cluster-spinner { - 0% {transform: rotate(0deg);} - 100% {transform: rotate(360deg);} -} - -.cluster-stat { - display: flex !important; - justify-content: space-between; - padding: $cluster-stat-padding 0; - align-items: center; - height: $cluster-stat-height; - user-select: none; - -webkit-user-select: none; - -moz-user-select: none; - -ms-user-select: none; - - div { - div { - min-width: 150px; - max-width: 300px; - } - } - &-empty { - width: 100%; - background-color: $g19-ghost; - height: $cluster-stat-height; - margin: 0; - line-height: $cluster-stat-height; - text-align: center; - border-bottom: 2px solid $g18-cloud; - border-top: 2px solid $g20-white; - border-radius: 4px; - font-style: italic; - - .icon { - animation: cluster-spinner 3.8s infinite linear; - display: inline-block; - vertical-align: middle; - position: relative; - top: -1px; - } - } - &--label { - display: flex; - justify-content: space-between; - align-items: center; - width: 100%; - padding-left: 1.5em; - } - &-2x { - display: flex; - justify-content: space-between; - padding: $cluster-stat-padding 0; - align-items: center; - height: $cluster-stat-height; - margin: 0; - - &--label, - &--number { - vertical-align: middle; - display: inline-block; - line-height: 1em; - } - &--number { - // font-size: 18px; - font-weight: 600; - margin-left: 15px; - } - } -} -.influx-version, -.disk-util { - border: 2px solid $g18-cloud; - border-radius: 4px; - padding: 4px 10px; -} -.quarter-table-width { - width: 25%; -} -.js-node-table { - margin-bottom: 0; - tbody tr td { - height: $cluster-stat-height + 16px; - } - .cluster-stat { - padding: 0; - } -} -.btn.rebalance { - display: flex; - justify-content: space-between; - align-items: center; -} -div { - #rebalance { - margin-left: 5px; - font-size: 20px; - animation-name: spin; - animation-duration: 4000ms; - animation-iteration-count: infinite; - animation-timing-function: linear; - } -} -@keyframes spin { - from { - transform:rotate(0deg); - } - to { - transform:rotate(360deg); - } -} -.tasks__popover { - -webkit-box-shadow: 0 5px 10px rgba(0,0,0,.2); - box-shadow: 0 5px 10px rgba(0,0,0,.2); - position: absolute; - width: auto; - background: #FFFFFF; - right: 10px; - top: 53px; - z-index: 1; - border-radius: 5px; -}