Merge pull request #1212 from influxdata/feature/meta-query-builder
Feature/meta query builderpull/1207/head^2
commit
e2c0715745
|
@ -33,6 +33,7 @@
|
||||||
1. [#1113](https://github.com/influxdata/chronograf/issues/1113): Add Slack channel per Kapacitor alert.
|
1. [#1113](https://github.com/influxdata/chronograf/issues/1113): Add Slack channel per Kapacitor alert.
|
||||||
1. [#1095](https://github.com/influxdata/chronograf/pull/1095): Add new auth duration CLI option; add client heartbeat
|
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. [#1168](https://github.com/influxdata/chronograf/issue/1168): Expand support for --basepath on some load balancers
|
||||||
|
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
|
1. [#1221](https://github.com/influxdata/chronograf/issue/1221): More sensical Cell and Dashboard defaults
|
||||||
|
|
||||||
### UI Improvements
|
### UI Improvements
|
||||||
|
|
|
@ -35,13 +35,6 @@ const QueryEditor = React.createClass({
|
||||||
}).isRequired,
|
}).isRequired,
|
||||||
},
|
},
|
||||||
|
|
||||||
getInitialState() {
|
|
||||||
return {
|
|
||||||
database: null,
|
|
||||||
measurement: null,
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
handleChooseNamespace(namespace) {
|
handleChooseNamespace(namespace) {
|
||||||
this.props.actions.chooseNamespace(this.props.query.id, namespace)
|
this.props.actions.chooseNamespace(this.props.query.id, namespace)
|
||||||
},
|
},
|
||||||
|
|
|
@ -1,5 +1,8 @@
|
||||||
import React, {PropTypes} from 'react'
|
import React, {PropTypes} from 'react'
|
||||||
import classNames from 'classnames'
|
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 ENTER = 13
|
||||||
const ESCAPE = 27
|
const ESCAPE = 27
|
||||||
|
@ -45,6 +48,10 @@ const RawQueryEditor = React.createClass({
|
||||||
this.props.onUpdate(this.state.value)
|
this.props.onUpdate(this.state.value)
|
||||||
},
|
},
|
||||||
|
|
||||||
|
handleChooseTemplate(template) {
|
||||||
|
this.setState({value: template.query})
|
||||||
|
},
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const {query: {rawStatus}} = this.props
|
const {query: {rawStatus}} = this.props
|
||||||
const {value} = this.state
|
const {value} = this.state
|
||||||
|
@ -63,6 +70,7 @@ const RawQueryEditor = React.createClass({
|
||||||
spellCheck="false"
|
spellCheck="false"
|
||||||
/>
|
/>
|
||||||
{this.renderStatus(rawStatus)}
|
{this.renderStatus(rawStatus)}
|
||||||
|
<Dropdown items={QUERY_TEMPLATES} selected={'Query Templates'} onChoose={this.handleChooseTemplate} className="query-template"/>
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
|
@ -74,6 +82,14 @@ const RawQueryEditor = React.createClass({
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (rawStatus.loading) {
|
||||||
|
return (
|
||||||
|
<div className="raw-text--status">
|
||||||
|
<LoadingDots />
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={classNames("raw-text--status", {"raw-text--error": rawStatus.error, "raw-text--success": rawStatus.success, "raw-text--warning": rawStatus.warn})}>
|
<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>
|
<span className={classNames("icon", {stop: rawStatus.error, checkmark: rawStatus.success, "alert-triangle": rawStatus.warn})}></span>
|
||||||
|
|
|
@ -82,12 +82,15 @@ const ChronoTable = React.createClass({
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
this.setState({isLoading: true})
|
|
||||||
const {onEditRawStatus} = this.props
|
const {onEditRawStatus} = this.props
|
||||||
|
|
||||||
|
onEditRawStatus(query.id, {loading: true})
|
||||||
|
this.setState({isLoading: true})
|
||||||
// second param is db, we want to leave this blank
|
// second param is db, we want to leave this blank
|
||||||
try {
|
try {
|
||||||
const {data} = await fetchTimeSeries(query.host, undefined, query.text)
|
const {data} = await fetchTimeSeries(query.host, undefined, query.text)
|
||||||
this.setState({isLoading: false})
|
this.setState({isLoading: false})
|
||||||
|
onEditRawStatus(query.id, {loading: false})
|
||||||
|
|
||||||
const results = _.get(data, ['results', '0'], false)
|
const results = _.get(data, ['results', '0'], false)
|
||||||
if (!results) {
|
if (!results) {
|
||||||
|
|
|
@ -10,3 +10,23 @@ export const INFLUXQL_FUNCTIONS = [
|
||||||
'spread',
|
'spread',
|
||||||
'stddev',
|
'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'},
|
||||||
|
]
|
||||||
|
|
|
@ -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
|
|
@ -26,7 +26,7 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
$raw-text-color: $c-pool;
|
$raw-text-color: $c-pool;
|
||||||
$raw-text-height: 38px;
|
$raw-text-height: 42px;
|
||||||
|
|
||||||
.raw-text--field {
|
.raw-text--field {
|
||||||
@include custom-scrollbar($g2-kevlar, $raw-text-color);
|
@include custom-scrollbar($g2-kevlar, $raw-text-color);
|
||||||
|
@ -72,7 +72,7 @@ $raw-text-height: 38px;
|
||||||
}
|
}
|
||||||
.raw-text--status {
|
.raw-text--status {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
height: ($query-builder--preview-height - 2px - $raw-text-height);
|
height: ($query-builder--preview-height - $raw-text-height);
|
||||||
line-height: 12px;
|
line-height: 12px;
|
||||||
font-size: 12px;
|
font-size: 12px;
|
||||||
background-color: $g2-kevlar;
|
background-color: $g2-kevlar;
|
||||||
|
@ -108,4 +108,13 @@ $raw-text-height: 38px;
|
||||||
&.raw-text--success {
|
&.raw-text--success {
|
||||||
color: $c-rainforest;
|
color: $c-rainforest;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.dropdown.query-template {
|
||||||
|
position: absolute;
|
||||||
|
top: 8px;
|
||||||
|
right: 7px;
|
||||||
|
.dropdown-toggle {
|
||||||
|
width: 135px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -90,3 +90,31 @@
|
||||||
margin-bottom: 11px;
|
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