Merge remote-tracking branch 'origin/master' into feature/generic-oauth
commit
e235292107
|
@ -34,6 +34,7 @@
|
|||
1. [#1095](https://github.com/influxdata/chronograf/pull/1095): Add new auth duration CLI option; add client heartbeat
|
||||
1. [#1168](https://github.com/influxdata/chronograf/issue/1168): Expand support for --basepath on some load balancers
|
||||
1. [#1207](https://github.com/influxdata/chronograf/pull/1207): Add support for custom OAuth2 providers
|
||||
1. [#1212](https://github.com/influxdata/chronograf/issue/1212): Add query templates and loading animation to the RawQueryEditor
|
||||
1. [#1221](https://github.com/influxdata/chronograf/issue/1221): More sensical Cell and Dashboard defaults
|
||||
|
||||
### UI Improvements
|
||||
|
@ -46,6 +47,7 @@
|
|||
1. [#1187](https://github.com/influxdata/chronograf/pull/1187): Replace Kill Query confirmation modal with ConfirmButtons
|
||||
1. [#1185](https://github.com/influxdata/chronograf/pull/1185): Alphabetically sort Admin Database Page
|
||||
1. [#1199](https://github.com/influxdata/chronograf/pull/1199): Move Rename Cell functionality to ContextMenu dropdown
|
||||
1. [#1222](https://github.com/influxdata/chronograf/pull/1222): Isolate cell repositioning to just those affected by adding a new cell
|
||||
|
||||
## v1.2.0-beta7 [2017-03-28]
|
||||
### Bug Fixes
|
||||
|
|
|
@ -380,7 +380,7 @@ type Dashboard struct {
|
|||
|
||||
// DashboardCell holds visual and query information for a cell
|
||||
type DashboardCell struct {
|
||||
ID string `json:"-"`
|
||||
ID string `json:"i"`
|
||||
X int32 `json:"x"`
|
||||
Y int32 `json:"y"`
|
||||
W int32 `json:"w"`
|
||||
|
|
|
@ -117,21 +117,23 @@ class CellEditorOverlay extends Component {
|
|||
cellName={cellWorkingName}
|
||||
/>
|
||||
<ResizeBottom>
|
||||
<OverlayControls
|
||||
selectedGraphType={cellWorkingType}
|
||||
onSelectGraphType={this.handleSelectGraphType}
|
||||
onCancel={onCancel}
|
||||
onSave={this.handleSaveCell}
|
||||
/>
|
||||
<QueryBuilder
|
||||
queries={queriesWorkingDraft}
|
||||
actions={queryActions}
|
||||
autoRefresh={autoRefresh}
|
||||
timeRange={timeRange}
|
||||
setActiveQueryIndex={this.handleSetActiveQueryIndex}
|
||||
onDeleteQuery={this.handleDeleteQuery}
|
||||
activeQueryIndex={activeQueryIndex}
|
||||
/>
|
||||
<div>
|
||||
<OverlayControls
|
||||
selectedGraphType={cellWorkingType}
|
||||
onSelectGraphType={this.handleSelectGraphType}
|
||||
onCancel={onCancel}
|
||||
onSave={this.handleSaveCell}
|
||||
/>
|
||||
<QueryBuilder
|
||||
queries={queriesWorkingDraft}
|
||||
actions={queryActions}
|
||||
autoRefresh={autoRefresh}
|
||||
timeRange={timeRange}
|
||||
setActiveQueryIndex={this.handleSetActiveQueryIndex}
|
||||
onDeleteQuery={this.handleDeleteQuery}
|
||||
activeQueryIndex={activeQueryIndex}
|
||||
/>
|
||||
</div>
|
||||
</ResizeBottom>
|
||||
</ResizeContainer>
|
||||
</div>
|
||||
|
|
|
@ -31,9 +31,8 @@ const Dashboard = ({
|
|||
}
|
||||
|
||||
Dashboard.renderDashboard = (dashboard, autoRefresh, timeRange, source, onPositionChange, onEditCell, onRenameCell, onUpdateCell, onDeleteCell, onSummonOverlayTechnologies) => {
|
||||
const cells = dashboard.cells.map((cell, i) => {
|
||||
i = `${i}`
|
||||
const dashboardCell = {...cell, i}
|
||||
const cells = dashboard.cells.map((cell) => {
|
||||
const dashboardCell = {...cell}
|
||||
dashboardCell.queries = dashboardCell.queries.map(({label, query, queryConfig, db}) =>
|
||||
({
|
||||
label,
|
||||
|
|
|
@ -142,7 +142,7 @@ const DashboardPage = React.createClass({
|
|||
|
||||
handleUpdateDashboardCell(newCell) {
|
||||
return () => {
|
||||
this.props.dashboardActions.editDashboardCell(newCell.x, newCell.y, false)
|
||||
this.props.dashboardActions.editDashboardCell(this.getActiveDashboard(), newCell.x, newCell.y, false)
|
||||
this.props.dashboardActions.putDashboard(this.getActiveDashboard())
|
||||
}
|
||||
},
|
||||
|
|
|
@ -35,13 +35,6 @@ const QueryEditor = React.createClass({
|
|||
}).isRequired,
|
||||
},
|
||||
|
||||
getInitialState() {
|
||||
return {
|
||||
database: null,
|
||||
measurement: null,
|
||||
}
|
||||
},
|
||||
|
||||
handleChooseNamespace(namespace) {
|
||||
this.props.actions.chooseNamespace(this.props.query.id, namespace)
|
||||
},
|
||||
|
|
|
@ -1,5 +1,8 @@
|
|||
import React, {PropTypes} from 'react'
|
||||
import classNames from 'classnames'
|
||||
import Dropdown from 'src/shared/components/Dropdown'
|
||||
import LoadingDots from 'src/shared/components/LoadingDots'
|
||||
import {QUERY_TEMPLATES} from 'src/data_explorer/constants'
|
||||
|
||||
const ENTER = 13
|
||||
const ESCAPE = 27
|
||||
|
@ -45,6 +48,10 @@ const RawQueryEditor = React.createClass({
|
|||
this.props.onUpdate(this.state.value)
|
||||
},
|
||||
|
||||
handleChooseTemplate(template) {
|
||||
this.setState({value: template.query})
|
||||
},
|
||||
|
||||
render() {
|
||||
const {query: {rawStatus}} = this.props
|
||||
const {value} = this.state
|
||||
|
@ -63,6 +70,7 @@ const RawQueryEditor = React.createClass({
|
|||
spellCheck="false"
|
||||
/>
|
||||
{this.renderStatus(rawStatus)}
|
||||
<Dropdown items={QUERY_TEMPLATES} selected={'Query Templates'} onChoose={this.handleChooseTemplate} className="query-template"/>
|
||||
</div>
|
||||
)
|
||||
},
|
||||
|
@ -74,6 +82,14 @@ const RawQueryEditor = React.createClass({
|
|||
)
|
||||
}
|
||||
|
||||
if (rawStatus.loading) {
|
||||
return (
|
||||
<div className="raw-text--status">
|
||||
<LoadingDots />
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
return (
|
||||
<div className={classNames("raw-text--status", {"raw-text--error": rawStatus.error, "raw-text--success": rawStatus.success, "raw-text--warning": rawStatus.warn})}>
|
||||
<span className={classNames("icon", {stop: rawStatus.error, checkmark: rawStatus.success, "alert-triangle": rawStatus.warn})}></span>
|
||||
|
|
|
@ -82,12 +82,15 @@ const ChronoTable = React.createClass({
|
|||
return
|
||||
}
|
||||
|
||||
this.setState({isLoading: true})
|
||||
const {onEditRawStatus} = this.props
|
||||
|
||||
onEditRawStatus(query.id, {loading: true})
|
||||
this.setState({isLoading: true})
|
||||
// second param is db, we want to leave this blank
|
||||
try {
|
||||
const {data} = await fetchTimeSeries(query.host, undefined, query.text)
|
||||
this.setState({isLoading: false})
|
||||
onEditRawStatus(query.id, {loading: false})
|
||||
|
||||
const results = _.get(data, ['results', '0'], false)
|
||||
if (!results) {
|
||||
|
|
|
@ -35,7 +35,7 @@ const Visualization = React.createClass({
|
|||
activeQueryIndex: number,
|
||||
height: string,
|
||||
heightPixels: number,
|
||||
onEditRawStatus: func.isRequired,
|
||||
onEditRawStatus: func,
|
||||
},
|
||||
|
||||
contextTypes: {
|
||||
|
@ -112,7 +112,7 @@ const Visualization = React.createClass({
|
|||
|
||||
renderTable(query, heightPixels, onEditRawStatus) {
|
||||
if (!query) {
|
||||
return <div className="generic-empty-state">Enter your query below</div>
|
||||
return <div className="generic-empty-state">Enter your query above</div>
|
||||
}
|
||||
|
||||
return <Table query={query} height={heightPixels} onEditRawStatus={onEditRawStatus} />
|
||||
|
|
|
@ -10,3 +10,23 @@ export const INFLUXQL_FUNCTIONS = [
|
|||
'spread',
|
||||
'stddev',
|
||||
]
|
||||
|
||||
export const QUERY_TEMPLATES = [
|
||||
{text: 'Show Databases', query: 'SHOW DATABASES'},
|
||||
{text: 'Create Database', query: 'CREATE DATABASE "db_name"'},
|
||||
{text: 'Drop Database', query: 'DROP DATABASE "db_name"'},
|
||||
{text: 'Show Measurements', query: 'SHOW MEASUREMENTS ON "db_name"'},
|
||||
{text: 'Show Tag Keys', query: 'SHOW TAG KEYS ON "db_name" FROM "measurement_name"'},
|
||||
{text: 'Show Tag Values', query: 'SHOW TAG VALUES ON "db_name" FROM "measurement_name" WITH KEY = "tag_key"'},
|
||||
{text: 'Show Retention Policies', query: 'SHOW RETENTION POLICIES on "db_name"'},
|
||||
{text: 'Create Retention Policy', query: 'CREATE RETENTION POLICY "rp_name" ON "db_name" DURATION 30d REPLICATION 1 DEFAULT'},
|
||||
{text: 'Drop Retention Policy', query: 'DROP RETENTION POLICY "rp_name" ON "db_name"'},
|
||||
{text: 'Create Continuous Query', query: 'CREATE CONTINUOUS QUERY "cq_name" ON "db_name" BEGIN SELECT min("field") INTO "target_measurement" FROM "current_measurement" GROUP BY time(30m) END'},
|
||||
{text: 'Drop Continuous Query', query: 'DROP CONTINUOUS QUERY "cq_name" ON "db_name"'},
|
||||
{text: 'Show Users', query: 'SHOW USERS'},
|
||||
{text: 'Create User', query: `CREATE USER "username" WITH PASSWORD 'password'`},
|
||||
{text: 'Create Admin User', query: `CREATE USER "username" WITH PASSWORD 'password' WITH ALL PRIVILEGES`},
|
||||
{text: 'Drop User', query: 'DROP USER "username"'},
|
||||
{text: 'Show Stats', query: 'SHOW STATS'},
|
||||
{text: 'Show Diagnostics', query: 'SHOW DIAGNOSTICS'},
|
||||
]
|
||||
|
|
|
@ -83,22 +83,22 @@ const DataExplorer = React.createClass({
|
|||
timeRange={timeRange}
|
||||
/>
|
||||
<ResizeContainer>
|
||||
<Visualization
|
||||
<QueryBuilder
|
||||
queries={queryConfigs}
|
||||
actions={queryConfigActions}
|
||||
autoRefresh={autoRefresh}
|
||||
timeRange={timeRange}
|
||||
queryConfigs={queryConfigs}
|
||||
setActiveQueryIndex={this.handleSetActiveQueryIndex}
|
||||
onDeleteQuery={this.handleDeleteQuery}
|
||||
activeQueryIndex={activeQueryIndex}
|
||||
onEditRawStatus={queryConfigActions.editRawQueryStatus}
|
||||
/>
|
||||
<ResizeBottom>
|
||||
<QueryBuilder
|
||||
queries={queryConfigs}
|
||||
actions={queryConfigActions}
|
||||
<Visualization
|
||||
autoRefresh={autoRefresh}
|
||||
timeRange={timeRange}
|
||||
setActiveQueryIndex={this.handleSetActiveQueryIndex}
|
||||
onDeleteQuery={this.handleDeleteQuery}
|
||||
queryConfigs={queryConfigs}
|
||||
activeQueryIndex={activeQueryIndex}
|
||||
onEditRawStatus={queryConfigActions.editRawQueryStatus}
|
||||
/>
|
||||
</ResizeBottom>
|
||||
</ResizeContainer>
|
||||
|
|
|
@ -48,6 +48,7 @@ export default React.createClass({
|
|||
value: string,
|
||||
rangeValue: string,
|
||||
}),
|
||||
legendOnBottom: bool,
|
||||
},
|
||||
|
||||
getDefaultProps() {
|
||||
|
@ -55,6 +56,7 @@ export default React.createClass({
|
|||
containerStyle: {},
|
||||
isGraphFilled: true,
|
||||
overrideLineColors: null,
|
||||
legendOnBottom: false,
|
||||
}
|
||||
},
|
||||
|
||||
|
@ -67,7 +69,7 @@ export default React.createClass({
|
|||
componentDidMount() {
|
||||
const timeSeries = this.getTimeSeries()
|
||||
// dygraphSeries is a legend label and its corresponding y-axis e.g. {legendLabel1: 'y', legendLabel2: 'y2'};
|
||||
const {ranges, dygraphSeries, ruleValues} = this.props
|
||||
const {ranges, dygraphSeries, ruleValues, legendOnBottom} = this.props
|
||||
|
||||
const refs = this.refs
|
||||
const graphContainerNode = refs.graphContainer
|
||||
|
@ -122,7 +124,12 @@ export default React.createClass({
|
|||
}
|
||||
|
||||
legendContainerNode.style.left = `${legendLeft}px`
|
||||
legendContainerNode.style.top = `${legendTop}px`
|
||||
if (legendOnBottom) {
|
||||
legendContainerNode.style.bottom = `4px`
|
||||
} else {
|
||||
legendContainerNode.style.top = `${legendTop}px`
|
||||
}
|
||||
|
||||
setMarker(points)
|
||||
},
|
||||
unhighlightCallback() {
|
||||
|
|
|
@ -67,7 +67,7 @@ export default React.createClass({
|
|||
},
|
||||
|
||||
render() {
|
||||
const {data, ranges, isFetchingInitially, isRefreshing, isGraphFilled, overrideLineColors, title, underlayCallback, queries, showSingleStat, displayOptions, ruleValues} = this.props
|
||||
const {data, ranges, isFetchingInitially, isRefreshing, isGraphFilled, overrideLineColors, title, underlayCallback, queries, showSingleStat, displayOptions, ruleValues, isInDataExplorer} = this.props
|
||||
const {labels, timeSeries, dygraphSeries} = this._timeSeries
|
||||
|
||||
// If data for this graph is being fetched for the first time, show a graph-wide spinner.
|
||||
|
@ -119,6 +119,7 @@ export default React.createClass({
|
|||
dygraphSeries={dygraphSeries}
|
||||
ranges={ranges || this.getRanges()}
|
||||
ruleValues={ruleValues}
|
||||
legendOnBottom={isInDataExplorer}
|
||||
/>
|
||||
{showSingleStat ? <div className="graph-single-stat single-stat">{roundedValue}</div> : null}
|
||||
</div>
|
||||
|
|
|
@ -0,0 +1,19 @@
|
|||
import React, {PropTypes} from 'react'
|
||||
|
||||
const LoadingDots = ({className}) => (
|
||||
<div className={`loading-dots ${className}`}>
|
||||
<div></div>
|
||||
<div></div>
|
||||
<div></div>
|
||||
</div>
|
||||
)
|
||||
|
||||
const {
|
||||
string,
|
||||
} = PropTypes
|
||||
|
||||
LoadingDots.propTypes = {
|
||||
className: string,
|
||||
}
|
||||
|
||||
export default LoadingDots
|
|
@ -59,7 +59,12 @@ const ResizeContainer = React.createClass({
|
|||
return
|
||||
}
|
||||
|
||||
this.setState({topHeight: `${(newTopPanelPercent)}%`, bottomHeight: `${(newBottomPanelPercent)}%`, topHeightPixels})
|
||||
this.setState({
|
||||
topHeight: `${(newTopPanelPercent)}%`,
|
||||
bottomHeight: `${(newBottomPanelPercent)}%`,
|
||||
topHeightPixels,
|
||||
bottomHeightPixels,
|
||||
})
|
||||
},
|
||||
|
||||
renderHandle() {
|
||||
|
@ -70,9 +75,13 @@ const ResizeContainer = React.createClass({
|
|||
},
|
||||
|
||||
render() {
|
||||
const {topHeight, topHeightPixels, bottomHeight} = this.state
|
||||
const {
|
||||
topHeight,
|
||||
topHeightPixels,
|
||||
bottomHeightPixels,
|
||||
} = this.state
|
||||
const top = React.cloneElement(this.props.children[0], {height: topHeight, heightPixels: topHeightPixels})
|
||||
const bottom = React.cloneElement(this.props.children[1], {height: bottomHeight})
|
||||
const bottom = React.cloneElement(this.props.children[1], {height: `${bottomHeightPixels}px`})
|
||||
return (
|
||||
<div className="resize-container page-contents" onMouseLeave={this.handleMouseLeave} onMouseUp={this.handleStopDrag} onMouseMove={this.handleDrag} ref="resizeContainer" >
|
||||
{top}
|
||||
|
@ -83,17 +92,21 @@ const ResizeContainer = React.createClass({
|
|||
},
|
||||
})
|
||||
|
||||
const ResizeBottom = (props) => (
|
||||
<div className="resize-bottom" style={{height: props.height}}>
|
||||
{props.children}
|
||||
</div>
|
||||
)
|
||||
export const ResizeBottom = ({
|
||||
height,
|
||||
children,
|
||||
}) => {
|
||||
const child = React.cloneElement(children, {height})
|
||||
return (
|
||||
<div className="resize-bottom" style={{height}}>
|
||||
{child}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
ResizeBottom.propTypes = {
|
||||
children: node.isRequired,
|
||||
height: string,
|
||||
}
|
||||
|
||||
export {ResizeBottom}
|
||||
|
||||
export default ResizeContainer
|
||||
|
|
|
@ -19,7 +19,7 @@ $resizer-color-active: $c-pool;
|
|||
z-index: 2;
|
||||
user-select: none;
|
||||
-webkit-user-select: none;
|
||||
position: relative;
|
||||
position: absolute;
|
||||
|
||||
// Psuedo element for handle
|
||||
&:before {
|
||||
|
|
|
@ -57,7 +57,6 @@ $dash-graph-options-arrow: 8px;
|
|||
left: 0;
|
||||
}
|
||||
.dash-graph--container {
|
||||
z-index: 0;
|
||||
user-select: none !important;
|
||||
-o-user-select: none !important;
|
||||
-moz-user-select: none !important;
|
||||
|
@ -89,7 +88,6 @@ $dash-graph-options-arrow: 8px;
|
|||
}
|
||||
}
|
||||
.dash-graph--heading {
|
||||
z-index: 0;
|
||||
user-select: none !important;
|
||||
-o-user-select: none !important;
|
||||
-moz-user-select: none !important;
|
||||
|
@ -370,11 +368,6 @@ $overlay-bg: rgba($c-pool, 0.7);
|
|||
border: 0;
|
||||
border-radius: $radius;
|
||||
@include gradient-h($g3-castle,$overlay-controls-bg);
|
||||
|
||||
/* Hack for making the adjacent query builder have less margin on top */
|
||||
& + .query-builder {
|
||||
margin-top: 2px;
|
||||
}
|
||||
}
|
||||
.overlay-controls--right {
|
||||
display: flex;
|
||||
|
@ -444,3 +437,13 @@ $overlay-bg: rgba($c-pool, 0.7);
|
|||
height: calc(100% - #{$dash-graph-heading});
|
||||
top: $dash-graph-heading;
|
||||
}
|
||||
.overlay-technology .query-builder {
|
||||
flex: 1 0 0;
|
||||
margin-bottom: 16px;
|
||||
margin-top: 2px;
|
||||
}
|
||||
.overlay-technology .query-builder--tabs,
|
||||
.overlay-technology .query-builder--tab-contents,
|
||||
.overlay-technology .qeditor--empty {
|
||||
margin: 0;
|
||||
}
|
||||
|
|
|
@ -26,6 +26,9 @@ $breakpoint-c: 2100px;
|
|||
.query-builder--tabs {
|
||||
width: 320px;
|
||||
}
|
||||
.query-builder--tab-label {
|
||||
width: (320px - 8px - 16px - 16px);
|
||||
}
|
||||
.qeditor--list-item,
|
||||
.query-builder--tab-label {
|
||||
font-size: 15px;
|
||||
|
@ -89,6 +92,7 @@ $breakpoint-c: 2100px;
|
|||
letter-spacing: 0.3px;
|
||||
}
|
||||
.query-builder--tab-label {
|
||||
width: (373px - 8px - 16px - 16px);
|
||||
font-size: 16px;
|
||||
}
|
||||
.query-builder--tab {
|
||||
|
|
|
@ -1,7 +1,9 @@
|
|||
/* Variables */
|
||||
$query-builder-tabs-width: 210px;
|
||||
|
||||
|
||||
.query-builder {
|
||||
position: relative;
|
||||
flex: 1 0 0;
|
||||
margin: 16px 0;
|
||||
width: calc(100% - #{($explorer-page-padding * 2)});
|
||||
left: $explorer-page-padding;
|
||||
border: 0;
|
||||
|
@ -12,11 +14,12 @@
|
|||
|
||||
// Tabs
|
||||
.query-builder--tabs {
|
||||
margin: 16px 0;
|
||||
display: flex;
|
||||
width: 250px;
|
||||
width: $query-builder-tabs-width;
|
||||
flex-direction: column;
|
||||
align-items: stretch;
|
||||
@include gradient-v($g3-castle,$g1-raven);
|
||||
background-color: $g3-castle;
|
||||
border-radius: $radius 0 0 $radius;
|
||||
}
|
||||
.query-builder--tabs-heading {
|
||||
|
@ -132,7 +135,7 @@
|
|||
font-weight: 600;
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
width: 90%;
|
||||
width: ($query-builder-tabs-width - 8px - 16px - 16px);
|
||||
text-overflow: ellipsis;
|
||||
@include no-user-select();
|
||||
}
|
||||
|
@ -145,7 +148,8 @@ $query-builder--preview-height: 60px;
|
|||
$query-builder--column-heading-height: 50px;
|
||||
|
||||
.query-builder--tab-contents {
|
||||
width: 100%;
|
||||
flex: 1 0 0;
|
||||
margin: 16px 0;
|
||||
background-color: $g4-onyx;
|
||||
border-radius: 0 $radius $radius 0;
|
||||
overflow: hidden;
|
||||
|
@ -219,6 +223,7 @@ $query-builder--column-heading-height: 50px;
|
|||
background-color: $g4-onyx;
|
||||
}
|
||||
.qeditor--empty {
|
||||
width: 100%;
|
||||
margin-top: 0;
|
||||
height: calc(100% - #{$query-builder--column-heading-height});
|
||||
position: absolute;
|
||||
|
|
|
@ -163,7 +163,8 @@
|
|||
.qeditor--empty {
|
||||
text-align: center;
|
||||
color: $g10-wolf;
|
||||
width: 100%;
|
||||
flex: 1 0 0;
|
||||
margin: 16px 0;
|
||||
padding: 0;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
|
|
|
@ -26,7 +26,7 @@
|
|||
}
|
||||
|
||||
$raw-text-color: $c-pool;
|
||||
$raw-text-height: 38px;
|
||||
$raw-text-height: 42px;
|
||||
|
||||
.raw-text--field {
|
||||
@include custom-scrollbar($g2-kevlar, $raw-text-color);
|
||||
|
@ -72,7 +72,7 @@ $raw-text-height: 38px;
|
|||
}
|
||||
.raw-text--status {
|
||||
width: 100%;
|
||||
height: ($query-builder--preview-height - 2px - $raw-text-height);
|
||||
height: ($query-builder--preview-height - $raw-text-height);
|
||||
line-height: 12px;
|
||||
font-size: 12px;
|
||||
background-color: $g2-kevlar;
|
||||
|
@ -108,4 +108,13 @@ $raw-text-height: 38px;
|
|||
&.raw-text--success {
|
||||
color: $c-rainforest;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.dropdown.query-template {
|
||||
position: absolute;
|
||||
top: 8px;
|
||||
right: 7px;
|
||||
.dropdown-toggle {
|
||||
width: 135px;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,6 +4,10 @@
|
|||
width: calc(100% - #{($explorer-page-padding * 2)});
|
||||
left: $explorer-page-padding;
|
||||
}
|
||||
/* Special rule for when the graph is in the bottom of resizer */
|
||||
.resize-bottom .graph {
|
||||
height: 100%;
|
||||
}
|
||||
.graph-heading {
|
||||
position: relative;
|
||||
top: $de-vertical-margin;
|
||||
|
|
|
@ -90,3 +90,31 @@
|
|||
margin-bottom: 11px;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
Loading Dots
|
||||
----------------------------------------------
|
||||
*/
|
||||
|
||||
.loading-dots {
|
||||
position: absolute;
|
||||
transform: translate(0,0);
|
||||
transform: translateX(50%);
|
||||
width: 16px;
|
||||
height: 18px;
|
||||
|
||||
div {
|
||||
width: 4px;
|
||||
height: 4px;
|
||||
background-color: $g6-smoke;
|
||||
border-radius: 50%;
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
transform: translate(-50%,-50%);
|
||||
}
|
||||
|
||||
div:nth-child(1) {left: 0; animation: refreshingSpinnerA 0.8s cubic-bezier(0.645, 0.045, 0.355, 1) infinite;}
|
||||
div:nth-child(2) {left: 50%; animation: refreshingSpinnerB 0.8s cubic-bezier(0.645, 0.045, 0.355, 1) infinite;}
|
||||
div:nth-child(3) {left: 100%; animation: refreshingSpinnerC 0.8s cubic-bezier(0.645, 0.045, 0.355, 1) infinite;}
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue