Migrate CEO to typescript
parent
ada654cbe6
commit
d34ea10d98
|
@ -0,0 +1,11 @@
|
||||||
|
import React, {ReactNode, SFC} from 'react'
|
||||||
|
|
||||||
|
interface Props {
|
||||||
|
children: ReactNode
|
||||||
|
}
|
||||||
|
|
||||||
|
const CEOBottom: SFC<Props> = ({children}) => (
|
||||||
|
<div className="overlay-technology--editor">{children}</div>
|
||||||
|
)
|
||||||
|
|
||||||
|
export default CEOBottom
|
|
@ -1,5 +1,4 @@
|
||||||
import React, {Component} from 'react'
|
import React, {Component} from 'react'
|
||||||
import PropTypes from 'prop-types'
|
|
||||||
|
|
||||||
import _ from 'lodash'
|
import _ from 'lodash'
|
||||||
import uuid from 'uuid'
|
import uuid from 'uuid'
|
||||||
|
@ -9,13 +8,16 @@ import QueryMaker from 'src/dashboards/components/QueryMaker'
|
||||||
import Visualization from 'src/dashboards/components/Visualization'
|
import Visualization from 'src/dashboards/components/Visualization'
|
||||||
import OverlayControls from 'src/dashboards/components/OverlayControls'
|
import OverlayControls from 'src/dashboards/components/OverlayControls'
|
||||||
import DisplayOptions from 'src/dashboards/components/DisplayOptions'
|
import DisplayOptions from 'src/dashboards/components/DisplayOptions'
|
||||||
|
import CEOBottom from 'src/dashboards/components/CEOBottom'
|
||||||
|
|
||||||
import * as queryModifiers from 'src/utils/queryTransitions'
|
import * as queryModifiers from 'src/utils/queryTransitions'
|
||||||
|
|
||||||
import defaultQueryConfig from 'src/utils/defaultQueryConfig'
|
import defaultQueryConfig from 'src/utils/defaultQueryConfig'
|
||||||
import {buildQuery} from 'utils/influxql'
|
import {buildQuery} from 'src/utils/influxql'
|
||||||
import {getQueryConfig} from 'shared/apis'
|
import {getQueryConfig} from 'src/shared/apis'
|
||||||
import {IS_STATIC_LEGEND} from 'src/shared/constants'
|
import {IS_STATIC_LEGEND} from 'src/shared/constants'
|
||||||
|
import {ColorString, ColorNumber} from 'src/types/colors'
|
||||||
|
import {nextSource} from 'src/dashboards/utils/sources'
|
||||||
|
|
||||||
import {
|
import {
|
||||||
removeUnselectedTemplateValues,
|
removeUnselectedTemplateValues,
|
||||||
|
@ -25,98 +27,237 @@ import {OVERLAY_TECHNOLOGY} from 'src/shared/constants/classNames'
|
||||||
import {MINIMUM_HEIGHTS, INITIAL_HEIGHTS} from 'src/data_explorer/constants'
|
import {MINIMUM_HEIGHTS, INITIAL_HEIGHTS} from 'src/data_explorer/constants'
|
||||||
import {AUTO_GROUP_BY} from 'src/shared/constants'
|
import {AUTO_GROUP_BY} from 'src/shared/constants'
|
||||||
import {getCellTypeColors} from 'src/dashboards/constants/cellEditor'
|
import {getCellTypeColors} from 'src/dashboards/constants/cellEditor'
|
||||||
import {colorsStringSchema, colorsNumberSchema} from 'shared/schemas'
|
import {TimeRange, Source, Query} from 'src/types'
|
||||||
|
import {Status} from 'src/types/query'
|
||||||
|
import {Cell, CellQuery, Legend} from 'src/types/dashboard'
|
||||||
|
|
||||||
|
const staticLegend: Legend = {
|
||||||
|
type: 'static',
|
||||||
|
orientation: 'bottom',
|
||||||
|
}
|
||||||
|
|
||||||
|
interface Template {
|
||||||
|
tempVar: string
|
||||||
|
}
|
||||||
|
|
||||||
|
interface QueryStatus {
|
||||||
|
queryID: string
|
||||||
|
status: Status
|
||||||
|
}
|
||||||
|
|
||||||
|
interface Props {
|
||||||
|
sources: Source[]
|
||||||
|
editQueryStatus: () => void
|
||||||
|
onCancel: () => void
|
||||||
|
onSave: (cell: Cell) => void
|
||||||
|
source: Source
|
||||||
|
dashboardID: string
|
||||||
|
queryStatus: QueryStatus
|
||||||
|
autoRefresh: number
|
||||||
|
templates: Template[]
|
||||||
|
timeRange: TimeRange
|
||||||
|
thresholdsListType: string
|
||||||
|
thresholdsListColors: ColorNumber[]
|
||||||
|
gaugeColors: ColorNumber[]
|
||||||
|
lineColors: ColorString[]
|
||||||
|
cell: Cell
|
||||||
|
}
|
||||||
|
|
||||||
|
interface State {
|
||||||
|
queriesWorkingDraft: Query[]
|
||||||
|
activeQueryIndex: number
|
||||||
|
isDisplayOptionsTabActive: boolean
|
||||||
|
isStaticLegend: boolean
|
||||||
|
}
|
||||||
|
|
||||||
|
const createWorkingDraft = (source: string, query: CellQuery): Query => {
|
||||||
|
const {queryConfig} = query
|
||||||
|
const draft: Query = {
|
||||||
|
...queryConfig,
|
||||||
|
id: uuid.v4(),
|
||||||
|
source,
|
||||||
|
}
|
||||||
|
|
||||||
|
return draft
|
||||||
|
}
|
||||||
|
|
||||||
|
const createWorkingDrafts = (source: string, queries: CellQuery[]): Query[] =>
|
||||||
|
_.cloneDeep(
|
||||||
|
queries.map((query: CellQuery) => createWorkingDraft(source, query))
|
||||||
|
)
|
||||||
|
|
||||||
|
class CellEditorOverlay extends Component<Props, State> {
|
||||||
|
private overlayRef: HTMLDivElement
|
||||||
|
private formattedSources = this.props.sources.map(s => ({
|
||||||
|
...s,
|
||||||
|
text: `${s.name} @ ${s.url}`,
|
||||||
|
}))
|
||||||
|
|
||||||
class CellEditorOverlay extends Component {
|
|
||||||
constructor(props) {
|
constructor(props) {
|
||||||
super(props)
|
super(props)
|
||||||
|
|
||||||
const {cell: {queries, legend}, sources} = props
|
const {cell: {queries, legend}} = props
|
||||||
|
const queriesWorkingDraft = createWorkingDrafts(this.sourceLink, queries)
|
||||||
let source = _.get(queries, ['0', 'source'], null)
|
|
||||||
source = sources.find(s => s.links.self === source) || props.source
|
|
||||||
|
|
||||||
const queriesWorkingDraft = _.cloneDeep(
|
|
||||||
queries.map(({queryConfig}) => ({
|
|
||||||
...queryConfig,
|
|
||||||
id: uuid.v4(),
|
|
||||||
source,
|
|
||||||
}))
|
|
||||||
)
|
|
||||||
|
|
||||||
this.state = {
|
this.state = {
|
||||||
queriesWorkingDraft,
|
queriesWorkingDraft,
|
||||||
activeQueryIndex: 0,
|
activeQueryIndex: 0,
|
||||||
isDisplayOptionsTabActive: false,
|
isDisplayOptionsTabActive: false,
|
||||||
staticLegend: IS_STATIC_LEGEND(legend),
|
isStaticLegend: IS_STATIC_LEGEND(legend),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
componentWillReceiveProps(nextProps) {
|
public componentWillReceiveProps(nextProps: Props) {
|
||||||
const {status, queryID} = this.props.queryStatus
|
const {status, queryID} = this.props.queryStatus
|
||||||
const nextStatus = nextProps.queryStatus
|
const {queriesWorkingDraft} = this.state
|
||||||
if (nextStatus.status && nextStatus.queryID) {
|
const {queryStatus} = nextProps
|
||||||
if (nextStatus.queryID !== queryID || nextStatus.status !== status) {
|
|
||||||
const nextQueries = this.state.queriesWorkingDraft.map(
|
if (
|
||||||
q => (q.id === queryID ? {...q, status: nextStatus.status} : q)
|
queryStatus.status &&
|
||||||
)
|
queryStatus.queryID &&
|
||||||
this.setState({queriesWorkingDraft: nextQueries})
|
(queryStatus.queryID !== queryID || queryStatus.status !== status)
|
||||||
}
|
) {
|
||||||
|
const nextQueries = queriesWorkingDraft.map(
|
||||||
|
q => (q.id === queryID ? {...q, status: queryStatus.status} : q)
|
||||||
|
)
|
||||||
|
this.setState({queriesWorkingDraft: nextQueries})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
componentDidMount = () => {
|
public componentDidMount() {
|
||||||
this.overlayRef.focus()
|
this.overlayRef.focus()
|
||||||
}
|
}
|
||||||
|
|
||||||
queryStateReducer = queryModifier => (queryID, ...payload) => {
|
public render() {
|
||||||
|
const {
|
||||||
|
onCancel,
|
||||||
|
templates,
|
||||||
|
timeRange,
|
||||||
|
autoRefresh,
|
||||||
|
editQueryStatus,
|
||||||
|
} = this.props
|
||||||
|
|
||||||
|
const {
|
||||||
|
activeQueryIndex,
|
||||||
|
isDisplayOptionsTabActive,
|
||||||
|
queriesWorkingDraft,
|
||||||
|
isStaticLegend,
|
||||||
|
} = this.state
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div
|
||||||
|
className={OVERLAY_TECHNOLOGY}
|
||||||
|
onKeyDown={this.handleKeyDown}
|
||||||
|
tabIndex={0}
|
||||||
|
ref={this.onRef}
|
||||||
|
>
|
||||||
|
<ResizeContainer
|
||||||
|
containerClass="resizer--full-size"
|
||||||
|
minTopHeight={MINIMUM_HEIGHTS.visualization}
|
||||||
|
minBottomHeight={MINIMUM_HEIGHTS.queryMaker}
|
||||||
|
initialTopHeight={INITIAL_HEIGHTS.visualization}
|
||||||
|
initialBottomHeight={INITIAL_HEIGHTS.queryMaker}
|
||||||
|
>
|
||||||
|
<Visualization
|
||||||
|
timeRange={timeRange}
|
||||||
|
templates={templates}
|
||||||
|
autoRefresh={autoRefresh}
|
||||||
|
queryConfigs={queriesWorkingDraft}
|
||||||
|
editQueryStatus={editQueryStatus}
|
||||||
|
staticLegend={isStaticLegend}
|
||||||
|
/>
|
||||||
|
<CEOBottom>
|
||||||
|
<OverlayControls
|
||||||
|
onCancel={onCancel}
|
||||||
|
queries={queriesWorkingDraft}
|
||||||
|
sources={this.formattedSources}
|
||||||
|
onSave={this.handleSaveCell}
|
||||||
|
selected={this.findSelectedSource()}
|
||||||
|
onSetQuerySource={this.handleSetQuerySource}
|
||||||
|
isSavable={this.isSaveable}
|
||||||
|
isDisplayOptionsTabActive={isDisplayOptionsTabActive}
|
||||||
|
onClickDisplayOptions={this.handleClickDisplayOptionsTab}
|
||||||
|
/>
|
||||||
|
{isDisplayOptionsTabActive ? (
|
||||||
|
<DisplayOptions
|
||||||
|
queryConfigs={queriesWorkingDraft}
|
||||||
|
onToggleStaticLegend={this.handleToggleStaticLegend}
|
||||||
|
staticLegend={isStaticLegend}
|
||||||
|
onResetFocus={this.handleResetFocus}
|
||||||
|
/>
|
||||||
|
) : (
|
||||||
|
<QueryMaker
|
||||||
|
source={this.source}
|
||||||
|
templates={templates}
|
||||||
|
queries={queriesWorkingDraft}
|
||||||
|
actions={this.queryActions}
|
||||||
|
timeRange={timeRange}
|
||||||
|
onDeleteQuery={this.handleDeleteQuery}
|
||||||
|
onAddQuery={this.handleAddQuery}
|
||||||
|
activeQueryIndex={activeQueryIndex}
|
||||||
|
activeQuery={this.getActiveQuery()}
|
||||||
|
setActiveQueryIndex={this.handleSetActiveQueryIndex}
|
||||||
|
initialGroupByTime={AUTO_GROUP_BY}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
</CEOBottom>
|
||||||
|
</ResizeContainer>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
private onRef = (r: HTMLDivElement) => {
|
||||||
|
this.overlayRef = r
|
||||||
|
}
|
||||||
|
|
||||||
|
private queryStateReducer = queryModifier => (queryID, ...payload) => {
|
||||||
const {queriesWorkingDraft} = this.state
|
const {queriesWorkingDraft} = this.state
|
||||||
const query = queriesWorkingDraft.find(q => q.id === queryID)
|
const query = queriesWorkingDraft.find(q => q.id === queryID)
|
||||||
|
|
||||||
const nextQuery = queryModifier(query, ...payload)
|
const nextQuery = queryModifier(query, ...payload)
|
||||||
|
|
||||||
const nextQueries = queriesWorkingDraft.map(
|
const nextQueries = queriesWorkingDraft.map(q => {
|
||||||
q =>
|
if (q.id === query.id) {
|
||||||
q.id === query.id
|
return {...nextQuery, source: nextSource(q, nextQuery)}
|
||||||
? {...nextQuery, source: this.nextSource(q, nextQuery)}
|
}
|
||||||
: q
|
|
||||||
)
|
return q
|
||||||
|
})
|
||||||
|
|
||||||
this.setState({queriesWorkingDraft: nextQueries})
|
this.setState({queriesWorkingDraft: nextQueries})
|
||||||
}
|
}
|
||||||
|
|
||||||
handleAddQuery = () => {
|
private handleAddQuery = () => {
|
||||||
const {queriesWorkingDraft} = this.state
|
const {queriesWorkingDraft} = this.state
|
||||||
const newIndex = queriesWorkingDraft.length
|
const newIndex = queriesWorkingDraft.length
|
||||||
|
|
||||||
this.setState({
|
this.setState({
|
||||||
queriesWorkingDraft: [
|
queriesWorkingDraft: [
|
||||||
...queriesWorkingDraft,
|
...queriesWorkingDraft,
|
||||||
defaultQueryConfig({id: uuid.v4()}),
|
{...defaultQueryConfig({id: uuid.v4()}), source: null},
|
||||||
],
|
],
|
||||||
})
|
})
|
||||||
this.handleSetActiveQueryIndex(newIndex)
|
this.handleSetActiveQueryIndex(newIndex)
|
||||||
}
|
}
|
||||||
|
|
||||||
handleDeleteQuery = index => {
|
private handleDeleteQuery = index => {
|
||||||
const nextQueries = this.state.queriesWorkingDraft.filter(
|
const {queriesWorkingDraft} = this.state
|
||||||
(__, i) => i !== index
|
const nextQueries = queriesWorkingDraft.filter((__, i) => i !== index)
|
||||||
)
|
|
||||||
this.setState({queriesWorkingDraft: nextQueries})
|
this.setState({queriesWorkingDraft: nextQueries})
|
||||||
}
|
}
|
||||||
|
|
||||||
handleSaveCell = () => {
|
private handleSaveCell = () => {
|
||||||
const {queriesWorkingDraft, staticLegend} = this.state
|
const {queriesWorkingDraft, isStaticLegend} = this.state
|
||||||
const {cell, thresholdsListColors, gaugeColors, lineColors} = this.props
|
const {cell, thresholdsListColors, gaugeColors, lineColors} = this.props
|
||||||
|
|
||||||
const queries = queriesWorkingDraft.map(q => {
|
const queries = queriesWorkingDraft.map(q => {
|
||||||
const timeRange = q.range || {upper: null, lower: ':dashboardTime:'}
|
const timeRange = q.range || {upper: null, lower: ':dashboardTime:'}
|
||||||
const query = q.rawText || buildQuery(TYPE_QUERY_CONFIG, timeRange, q)
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
queryConfig: q,
|
queryConfig: q,
|
||||||
query,
|
query: q.rawText || buildQuery(TYPE_QUERY_CONFIG, timeRange, q),
|
||||||
source: _.get(q, ['source', 'links', 'self'], null),
|
source: q.source,
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
@ -131,28 +272,23 @@ class CellEditorOverlay extends Component {
|
||||||
...cell,
|
...cell,
|
||||||
queries,
|
queries,
|
||||||
colors,
|
colors,
|
||||||
legend: staticLegend
|
legend: isStaticLegend ? staticLegend : {},
|
||||||
? {
|
|
||||||
type: 'static',
|
|
||||||
orientation: 'bottom',
|
|
||||||
}
|
|
||||||
: {},
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
handleClickDisplayOptionsTab = isDisplayOptionsTabActive => () => {
|
private handleClickDisplayOptionsTab = isDisplayOptionsTabActive => () => {
|
||||||
this.setState({isDisplayOptionsTabActive})
|
this.setState({isDisplayOptionsTabActive})
|
||||||
}
|
}
|
||||||
|
|
||||||
handleSetActiveQueryIndex = activeQueryIndex => {
|
private handleSetActiveQueryIndex = activeQueryIndex => {
|
||||||
this.setState({activeQueryIndex})
|
this.setState({activeQueryIndex})
|
||||||
}
|
}
|
||||||
|
|
||||||
handleToggleStaticLegend = staticLegend => () => {
|
private handleToggleStaticLegend = isStaticLegend => () => {
|
||||||
this.setState({staticLegend})
|
this.setState({isStaticLegend})
|
||||||
}
|
}
|
||||||
|
|
||||||
handleSetQuerySource = source => {
|
private handleSetQuerySource = source => {
|
||||||
const queriesWorkingDraft = this.state.queriesWorkingDraft.map(q => ({
|
const queriesWorkingDraft = this.state.queriesWorkingDraft.map(q => ({
|
||||||
..._.cloneDeep(q),
|
..._.cloneDeep(q),
|
||||||
source,
|
source,
|
||||||
|
@ -161,15 +297,13 @@ class CellEditorOverlay extends Component {
|
||||||
this.setState({queriesWorkingDraft})
|
this.setState({queriesWorkingDraft})
|
||||||
}
|
}
|
||||||
|
|
||||||
getActiveQuery = () => {
|
private getActiveQuery = () => {
|
||||||
const {queriesWorkingDraft, activeQueryIndex} = this.state
|
const {queriesWorkingDraft, activeQueryIndex} = this.state
|
||||||
const activeQuery = queriesWorkingDraft[activeQueryIndex]
|
|
||||||
const defaultQuery = queriesWorkingDraft[0]
|
|
||||||
|
|
||||||
return activeQuery || defaultQuery
|
return _.get(queriesWorkingDraft, activeQueryIndex, queriesWorkingDraft[0])
|
||||||
}
|
}
|
||||||
|
|
||||||
handleEditRawText = async (url, id, text) => {
|
private handleEditRawText = async (url, id, text) => {
|
||||||
const templates = removeUnselectedTemplateValues(this.props.templates)
|
const templates = removeUnselectedTemplateValues(this.props.templates)
|
||||||
|
|
||||||
// use this as the handler passed into fetchTimeSeries to update a query status
|
// use this as the handler passed into fetchTimeSeries to update a query status
|
||||||
|
@ -185,203 +319,86 @@ class CellEditorOverlay extends Component {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
formatSources = this.props.sources.map(s => ({
|
private findSelectedSource = () => {
|
||||||
...s,
|
|
||||||
text: `${s.name} @ ${s.url}`,
|
|
||||||
}))
|
|
||||||
|
|
||||||
findSelectedSource = () => {
|
|
||||||
const {source} = this.props
|
const {source} = this.props
|
||||||
const sources = this.formatSources
|
const sources = this.formattedSources
|
||||||
const query = _.get(this.state.queriesWorkingDraft, 0, false)
|
const currentSource = _.get(this.state.queriesWorkingDraft, '0.source')
|
||||||
|
|
||||||
if (!query || !query.source) {
|
if (!currentSource) {
|
||||||
const defaultSource = sources.find(s => s.id === source.id)
|
const defaultSource = sources.find(s => s.id === source.id)
|
||||||
return (defaultSource && defaultSource.text) || 'No sources'
|
return (defaultSource && defaultSource.text) || 'No sources'
|
||||||
}
|
}
|
||||||
|
|
||||||
const selected = sources.find(s => s.id === query.source.id)
|
const selected = sources.find(s => s.links.self === currentSource)
|
||||||
return (selected && selected.text) || 'No sources'
|
return (selected && selected.text) || 'No sources'
|
||||||
}
|
}
|
||||||
|
|
||||||
getSource = () => {
|
private handleKeyDown = e => {
|
||||||
const {source, sources} = this.props
|
switch (e.key) {
|
||||||
const query = _.get(this.state.queriesWorkingDraft, 0, false)
|
case 'Enter':
|
||||||
|
if (!e.metaKey) {
|
||||||
|
return
|
||||||
|
} else if (e.target === this.overlayRef) {
|
||||||
|
this.handleSaveCell()
|
||||||
|
} else {
|
||||||
|
e.target.blur()
|
||||||
|
setTimeout(this.handleSaveCell, 50)
|
||||||
|
}
|
||||||
|
break
|
||||||
|
case 'Escape':
|
||||||
|
if (e.target === this.overlayRef) {
|
||||||
|
this.props.onCancel()
|
||||||
|
} else {
|
||||||
|
const targetIsDropdown = e.target.classList[0] === 'dropdown'
|
||||||
|
const targetIsButton = e.target.tagName === 'BUTTON'
|
||||||
|
|
||||||
if (!query || !query.source) {
|
if (targetIsDropdown || targetIsButton) {
|
||||||
return source
|
return this.props.onCancel()
|
||||||
}
|
}
|
||||||
|
|
||||||
const querySource = sources.find(s => s.id === query.source.id)
|
e.target.blur()
|
||||||
return querySource || source
|
this.overlayRef.focus()
|
||||||
}
|
}
|
||||||
|
break
|
||||||
nextSource = (prevQuery, nextQuery) => {
|
|
||||||
if (nextQuery.source) {
|
|
||||||
return nextQuery.source
|
|
||||||
}
|
|
||||||
|
|
||||||
return prevQuery.source
|
|
||||||
}
|
|
||||||
|
|
||||||
handleKeyDown = e => {
|
|
||||||
if (e.key === 'Enter' && e.metaKey && e.target === this.overlayRef) {
|
|
||||||
this.handleSaveCell()
|
|
||||||
}
|
|
||||||
if (e.key === 'Enter' && e.metaKey && e.target !== this.overlayRef) {
|
|
||||||
e.target.blur()
|
|
||||||
setTimeout(this.handleSaveCell, 50)
|
|
||||||
}
|
|
||||||
if (e.key === 'Escape' && e.target === this.overlayRef) {
|
|
||||||
this.props.onCancel()
|
|
||||||
}
|
|
||||||
if (e.key === 'Escape' && e.target !== this.overlayRef) {
|
|
||||||
const targetIsDropdown = e.target.classList[0] === 'dropdown'
|
|
||||||
const targetIsButton = e.target.tagName === 'BUTTON'
|
|
||||||
|
|
||||||
if (targetIsDropdown || targetIsButton) {
|
|
||||||
return this.props.onCancel()
|
|
||||||
}
|
|
||||||
|
|
||||||
e.target.blur()
|
|
||||||
this.overlayRef.focus()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
handleResetFocus = () => {
|
private handleResetFocus = () => {
|
||||||
this.overlayRef.focus()
|
this.overlayRef.focus()
|
||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
private get isSaveable(): boolean {
|
||||||
const {
|
const {queriesWorkingDraft} = this.state
|
||||||
onCancel,
|
|
||||||
templates,
|
|
||||||
timeRange,
|
|
||||||
autoRefresh,
|
|
||||||
editQueryStatus,
|
|
||||||
} = this.props
|
|
||||||
|
|
||||||
const {
|
return queriesWorkingDraft.every(
|
||||||
activeQueryIndex,
|
(query: Query) =>
|
||||||
isDisplayOptionsTabActive,
|
(!!query.measurement && !!query.database && !!query.fields.length) ||
|
||||||
queriesWorkingDraft,
|
!!query.rawText
|
||||||
staticLegend,
|
)
|
||||||
} = this.state
|
}
|
||||||
|
|
||||||
const queryActions = {
|
private get queryActions() {
|
||||||
|
return {
|
||||||
editRawTextAsync: this.handleEditRawText,
|
editRawTextAsync: this.handleEditRawText,
|
||||||
..._.mapValues(queryModifiers, qm => this.queryStateReducer(qm)),
|
..._.mapValues(queryModifiers, this.queryStateReducer),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private get sourceLink(): string {
|
||||||
|
const {cell: {queries}, source: {links}} = this.props
|
||||||
|
return _.get(queries, '0.source.links.self', links.self)
|
||||||
|
}
|
||||||
|
|
||||||
|
private get source() {
|
||||||
|
const {source, sources} = this.props
|
||||||
|
const query = _.get(this.state.queriesWorkingDraft, 0, {source: null})
|
||||||
|
|
||||||
|
if (!query.source) {
|
||||||
|
return source
|
||||||
}
|
}
|
||||||
|
|
||||||
const isQuerySavable = query =>
|
return sources.find(s => s.links.self === query.source) || source
|
||||||
(!!query.measurement && !!query.database && !!query.fields.length) ||
|
|
||||||
!!query.rawText
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div
|
|
||||||
className={OVERLAY_TECHNOLOGY}
|
|
||||||
onKeyDown={this.handleKeyDown}
|
|
||||||
tabIndex="0"
|
|
||||||
ref={r => (this.overlayRef = r)}
|
|
||||||
>
|
|
||||||
<ResizeContainer
|
|
||||||
containerClass="resizer--full-size"
|
|
||||||
minTopHeight={MINIMUM_HEIGHTS.visualization}
|
|
||||||
minBottomHeight={MINIMUM_HEIGHTS.queryMaker}
|
|
||||||
initialTopHeight={INITIAL_HEIGHTS.visualization}
|
|
||||||
initialBottomHeight={INITIAL_HEIGHTS.queryMaker}
|
|
||||||
>
|
|
||||||
<Visualization
|
|
||||||
timeRange={timeRange}
|
|
||||||
templates={templates}
|
|
||||||
autoRefresh={autoRefresh}
|
|
||||||
queryConfigs={queriesWorkingDraft}
|
|
||||||
editQueryStatus={editQueryStatus}
|
|
||||||
staticLegend={staticLegend}
|
|
||||||
/>
|
|
||||||
<CEOBottom>
|
|
||||||
<OverlayControls
|
|
||||||
onCancel={onCancel}
|
|
||||||
queries={queriesWorkingDraft}
|
|
||||||
sources={this.formatSources}
|
|
||||||
onSave={this.handleSaveCell}
|
|
||||||
selected={this.findSelectedSource()}
|
|
||||||
onSetQuerySource={this.handleSetQuerySource}
|
|
||||||
isSavable={queriesWorkingDraft.every(isQuerySavable)}
|
|
||||||
isDisplayOptionsTabActive={isDisplayOptionsTabActive}
|
|
||||||
onClickDisplayOptions={this.handleClickDisplayOptionsTab}
|
|
||||||
/>
|
|
||||||
{isDisplayOptionsTabActive ? (
|
|
||||||
<DisplayOptions
|
|
||||||
queryConfigs={queriesWorkingDraft}
|
|
||||||
onToggleStaticLegend={this.handleToggleStaticLegend}
|
|
||||||
staticLegend={staticLegend}
|
|
||||||
onResetFocus={this.handleResetFocus}
|
|
||||||
/>
|
|
||||||
) : (
|
|
||||||
<QueryMaker
|
|
||||||
source={this.getSource()}
|
|
||||||
templates={templates}
|
|
||||||
queries={queriesWorkingDraft}
|
|
||||||
actions={queryActions}
|
|
||||||
autoRefresh={autoRefresh}
|
|
||||||
timeRange={timeRange}
|
|
||||||
onDeleteQuery={this.handleDeleteQuery}
|
|
||||||
onAddQuery={this.handleAddQuery}
|
|
||||||
activeQueryIndex={activeQueryIndex}
|
|
||||||
activeQuery={this.getActiveQuery()}
|
|
||||||
setActiveQueryIndex={this.handleSetActiveQueryIndex}
|
|
||||||
initialGroupByTime={AUTO_GROUP_BY}
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
</CEOBottom>
|
|
||||||
</ResizeContainer>
|
|
||||||
</div>
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const CEOBottom = ({children}) => (
|
|
||||||
<div className="overlay-technology--editor">{children}</div>
|
|
||||||
)
|
|
||||||
|
|
||||||
const {arrayOf, func, node, number, shape, string} = PropTypes
|
|
||||||
|
|
||||||
CellEditorOverlay.propTypes = {
|
|
||||||
onCancel: func.isRequired,
|
|
||||||
onSave: func.isRequired,
|
|
||||||
cell: shape({}).isRequired,
|
|
||||||
templates: arrayOf(
|
|
||||||
shape({
|
|
||||||
tempVar: string.isRequired,
|
|
||||||
})
|
|
||||||
).isRequired,
|
|
||||||
timeRange: shape({
|
|
||||||
upper: string,
|
|
||||||
lower: string,
|
|
||||||
}).isRequired,
|
|
||||||
autoRefresh: number.isRequired,
|
|
||||||
source: shape({
|
|
||||||
links: shape({
|
|
||||||
proxy: string.isRequired,
|
|
||||||
queries: string.isRequired,
|
|
||||||
}).isRequired,
|
|
||||||
}).isRequired,
|
|
||||||
editQueryStatus: func.isRequired,
|
|
||||||
queryStatus: shape({
|
|
||||||
queryID: string,
|
|
||||||
status: shape({}),
|
|
||||||
}).isRequired,
|
|
||||||
dashboardID: string.isRequired,
|
|
||||||
sources: arrayOf(shape()),
|
|
||||||
thresholdsListType: string.isRequired,
|
|
||||||
thresholdsListColors: colorsNumberSchema.isRequired,
|
|
||||||
gaugeColors: colorsNumberSchema.isRequired,
|
|
||||||
lineColors: colorsStringSchema.isRequired,
|
|
||||||
}
|
|
||||||
|
|
||||||
CEOBottom.propTypes = {
|
|
||||||
children: node,
|
|
||||||
}
|
|
||||||
|
|
||||||
export default CellEditorOverlay
|
export default CellEditorOverlay
|
|
@ -0,0 +1,7 @@
|
||||||
|
export const nextSource = (prevQuery, nextQuery) => {
|
||||||
|
if (nextQuery.source) {
|
||||||
|
return nextQuery.source
|
||||||
|
}
|
||||||
|
|
||||||
|
return prevQuery.source
|
||||||
|
}
|
|
@ -0,0 +1,9 @@
|
||||||
|
interface ColorBase {
|
||||||
|
type: string
|
||||||
|
hex: string
|
||||||
|
id: string
|
||||||
|
name: string
|
||||||
|
}
|
||||||
|
|
||||||
|
export type ColorString = ColorBase & {value: string}
|
||||||
|
export type ColorNumber = ColorBase & {value: number}
|
|
@ -0,0 +1,60 @@
|
||||||
|
import {Query} from 'src/types'
|
||||||
|
import {ColorString} from 'src/types/colors'
|
||||||
|
interface Axis {
|
||||||
|
bounds: [string, string]
|
||||||
|
label: string
|
||||||
|
prefix: string
|
||||||
|
suffix: string
|
||||||
|
base: string
|
||||||
|
scale: string
|
||||||
|
}
|
||||||
|
|
||||||
|
interface Axes {
|
||||||
|
x: Axis
|
||||||
|
y: Axis
|
||||||
|
}
|
||||||
|
|
||||||
|
interface FieldName {
|
||||||
|
internalName: string
|
||||||
|
displayName: string
|
||||||
|
visible: boolean
|
||||||
|
}
|
||||||
|
|
||||||
|
interface TableOptions {
|
||||||
|
timeFormat: string
|
||||||
|
verticalTimeAxis: boolean
|
||||||
|
sortBy: FieldName
|
||||||
|
wrapping: string
|
||||||
|
fixFirstColumn: boolean
|
||||||
|
fieldNames: FieldName[]
|
||||||
|
}
|
||||||
|
|
||||||
|
interface CellLinks {
|
||||||
|
self: string
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface CellQuery {
|
||||||
|
query: string
|
||||||
|
queryConfig: Query
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface Legend {
|
||||||
|
type?: string
|
||||||
|
orientation?: string
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface Cell {
|
||||||
|
id: string
|
||||||
|
x: number
|
||||||
|
y: number
|
||||||
|
w: number
|
||||||
|
h: number
|
||||||
|
name: string
|
||||||
|
queries: CellQuery[]
|
||||||
|
type: string
|
||||||
|
axes: Axes
|
||||||
|
colors: ColorString[]
|
||||||
|
tableOptions: TableOptions
|
||||||
|
links: CellLinks
|
||||||
|
legend: Legend
|
||||||
|
}
|
|
@ -64,7 +64,7 @@ export interface DurationRange {
|
||||||
upper?: string
|
upper?: string
|
||||||
}
|
}
|
||||||
|
|
||||||
interface TimeShift {
|
export interface TimeShift {
|
||||||
label: string
|
label: string
|
||||||
unit: string
|
unit: string
|
||||||
quantity: string
|
quantity: string
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
import _ from 'lodash'
|
||||||
import {buildQuery} from 'utils/influxql'
|
import {buildQuery} from 'utils/influxql'
|
||||||
import {TYPE_QUERY_CONFIG, TYPE_SHIFTED} from 'src/dashboards/constants'
|
import {TYPE_QUERY_CONFIG, TYPE_SHIFTED} from 'src/dashboards/constants'
|
||||||
|
|
||||||
|
@ -26,10 +27,7 @@ const buildQueries = (proxy, queryConfigs, tR) => {
|
||||||
const queries = statements
|
const queries = statements
|
||||||
.filter(s => s.text !== null)
|
.filter(s => s.text !== null)
|
||||||
.map(({queryConfig, text, id}) => {
|
.map(({queryConfig, text, id}) => {
|
||||||
let queryProxy = ''
|
const queryProxy = _.get(queryConfig, 'source.links.proxy', '')
|
||||||
if (queryConfig.source) {
|
|
||||||
queryProxy = `${queryConfig.source.links.proxy}`
|
|
||||||
}
|
|
||||||
|
|
||||||
const host = [queryProxy || proxy]
|
const host = [queryProxy || proxy]
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue