Move TimeMachine state to new state container
Co-authored-by: Iris Scholten <iris@influxdata.com> Co-authored-by: Chris Henn <chris@chrishenn.net>pull/4513/head
parent
cb3632af4c
commit
3d99060582
|
@ -139,6 +139,7 @@
|
|||
"redux-thunk": "^1.0.3",
|
||||
"reselect": "^3.0.1",
|
||||
"rome": "^2.1.22",
|
||||
"unstated": "^2.1.1",
|
||||
"uuid": "^3.2.1"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,17 +1,4 @@
|
|||
// Types
|
||||
import {ColorNumber, ColorString} from 'src/types/colors'
|
||||
import {
|
||||
DecimalPlaces,
|
||||
FieldOption,
|
||||
Axes,
|
||||
Cell,
|
||||
CellType,
|
||||
ThresholdType,
|
||||
TableOptions,
|
||||
CellQuery,
|
||||
NewDefaultCell,
|
||||
NoteVisibility,
|
||||
} from 'src/types/dashboards'
|
||||
import {TimeRange} from 'src/types'
|
||||
import {CEOInitialState} from 'src/dashboards/reducers/cellEditorOverlay'
|
||||
|
||||
|
@ -20,66 +7,21 @@ export interface State {
|
|||
}
|
||||
|
||||
export enum ActionType {
|
||||
LoadCEO = 'LOAD_CEO',
|
||||
ClearCEO = 'CLEAR_CEO',
|
||||
ChangeCellType = 'CHANGE_CELL_TYPE',
|
||||
RenameCell = 'RENAME_CELL',
|
||||
UpdateThresholdsListColors = 'UPDATE_THRESHOLDS_LIST_COLORS',
|
||||
UpdateThresholdsListType = 'UPDATE_THRESHOLDS_LIST_TYPE',
|
||||
UpdateGaugeColors = 'UPDATE_GAUGE_COLORS',
|
||||
UpdateAxes = 'UPDATE_AXES',
|
||||
UpdateTableOptions = 'UPDATE_TABLE_OPTIONS',
|
||||
UpdateLineColors = 'UPDATE_LINE_COLORS',
|
||||
ChangeTimeFormat = 'CHANGE_TIME_FORMAT',
|
||||
ChangeDecimalPlaces = 'CHANGE_DECIMAL_PLACES',
|
||||
UpdateFieldOptions = 'UPDATE_FIELD_OPTIONS',
|
||||
UpdateQueryDrafts = 'UPDATE_QUERY_DRAFTS',
|
||||
UpdateQueryDraft = 'UPDATE_QUERY_DRAFT',
|
||||
UpdateCellNote = 'UPDATE_CELL_NOTE',
|
||||
UpdateCellNoteVisibility = 'UPDATE_CELL_NOTE_VISIBILITY',
|
||||
UpdateEditorTimeRange = 'UPDATE_EDITOR_TIME_RANGE',
|
||||
UpdateScript = 'UPDATE_SCRIPT',
|
||||
UpdateFieldOptions = 'UPDATE_FIELD_OPTIONS',
|
||||
}
|
||||
|
||||
export type Action =
|
||||
| LoadCEOAction
|
||||
| ClearCEOAction
|
||||
| ChangeCellTypeAction
|
||||
| RenameCellAction
|
||||
| UpdateThresholdsListColorsAction
|
||||
| UpdateThresholdsListTypeAction
|
||||
| UpdateGaugeColorsAction
|
||||
| UpdateAxesAction
|
||||
| UpdateTableOptionsAction
|
||||
| UpdateLineColorsAction
|
||||
| ChangeTimeFormatAction
|
||||
| ChangeDecimalPlacesAction
|
||||
| UpdateFieldOptionsAction
|
||||
| UpdateQueryDraftsAction
|
||||
| UpdateCellNoteAction
|
||||
| UpdateCellNoteVisibilityAction
|
||||
| UpdateEditorTimeRangeAction
|
||||
| UpdateScriptAction
|
||||
|
||||
export interface LoadCEOAction {
|
||||
type: ActionType.LoadCEO
|
||||
payload: {
|
||||
cell: Cell | NewDefaultCell
|
||||
timeRange: TimeRange
|
||||
}
|
||||
}
|
||||
|
||||
export interface ClearCEOAction {
|
||||
type: ActionType.ClearCEO
|
||||
}
|
||||
|
||||
export interface ChangeCellTypeAction {
|
||||
type: ActionType.ChangeCellType
|
||||
payload: {
|
||||
cellType: CellType
|
||||
}
|
||||
}
|
||||
|
||||
export interface RenameCellAction {
|
||||
type: ActionType.RenameCell
|
||||
payload: {
|
||||
|
@ -87,97 +29,6 @@ export interface RenameCellAction {
|
|||
}
|
||||
}
|
||||
|
||||
export interface UpdateThresholdsListColorsAction {
|
||||
type: ActionType.UpdateThresholdsListColors
|
||||
payload: {
|
||||
thresholdsListColors: ColorNumber[]
|
||||
}
|
||||
}
|
||||
|
||||
export interface UpdateThresholdsListTypeAction {
|
||||
type: ActionType.UpdateThresholdsListType
|
||||
payload: {
|
||||
thresholdsListType: ThresholdType
|
||||
}
|
||||
}
|
||||
|
||||
export interface UpdateGaugeColorsAction {
|
||||
type: ActionType.UpdateGaugeColors
|
||||
payload: {
|
||||
gaugeColors: ColorNumber[]
|
||||
}
|
||||
}
|
||||
|
||||
export interface UpdateAxesAction {
|
||||
type: ActionType.UpdateAxes
|
||||
payload: {
|
||||
axes: Axes
|
||||
}
|
||||
}
|
||||
|
||||
export interface UpdateTableOptionsAction {
|
||||
type: ActionType.UpdateTableOptions
|
||||
payload: {
|
||||
tableOptions: TableOptions
|
||||
}
|
||||
}
|
||||
|
||||
export interface UpdateLineColorsAction {
|
||||
type: ActionType.UpdateLineColors
|
||||
payload: {
|
||||
lineColors: ColorString[]
|
||||
}
|
||||
}
|
||||
|
||||
export interface ChangeTimeFormatAction {
|
||||
type: ActionType.ChangeTimeFormat
|
||||
payload: {
|
||||
timeFormat: string
|
||||
}
|
||||
}
|
||||
|
||||
export interface ChangeDecimalPlacesAction {
|
||||
type: ActionType.ChangeDecimalPlaces
|
||||
payload: {
|
||||
decimalPlaces: DecimalPlaces
|
||||
}
|
||||
}
|
||||
|
||||
export interface UpdateFieldOptionsAction {
|
||||
type: ActionType.UpdateFieldOptions
|
||||
payload: {
|
||||
fieldOptions: FieldOption[]
|
||||
}
|
||||
}
|
||||
|
||||
export interface UpdateQueryDraftsAction {
|
||||
type: ActionType.UpdateQueryDrafts
|
||||
payload: {
|
||||
queryDrafts: CellQuery[]
|
||||
}
|
||||
}
|
||||
|
||||
export interface UpdateQueryDraftAction {
|
||||
type: ActionType.UpdateQueryDraft
|
||||
payload: {
|
||||
queryDraft: CellQuery
|
||||
}
|
||||
}
|
||||
|
||||
export interface UpdateCellNoteAction {
|
||||
type: ActionType.UpdateCellNote
|
||||
payload: {
|
||||
note: string
|
||||
}
|
||||
}
|
||||
|
||||
export interface UpdateCellNoteVisibilityAction {
|
||||
type: ActionType.UpdateCellNoteVisibility
|
||||
payload: {
|
||||
noteVisibility: NoteVisibility
|
||||
}
|
||||
}
|
||||
|
||||
export interface UpdateEditorTimeRangeAction {
|
||||
type: ActionType.UpdateEditorTimeRange
|
||||
payload: {
|
||||
|
@ -185,24 +36,6 @@ export interface UpdateEditorTimeRangeAction {
|
|||
}
|
||||
}
|
||||
|
||||
export interface UpdateScriptAction {
|
||||
type: ActionType.UpdateScript
|
||||
payload: {
|
||||
script: string
|
||||
}
|
||||
}
|
||||
|
||||
export const loadCEO = (
|
||||
cell: Cell | NewDefaultCell,
|
||||
timeRange: TimeRange
|
||||
): LoadCEOAction => ({
|
||||
type: ActionType.LoadCEO,
|
||||
payload: {
|
||||
cell,
|
||||
timeRange,
|
||||
},
|
||||
})
|
||||
|
||||
export const clearCEO = (): ClearCEOAction => ({
|
||||
type: ActionType.ClearCEO,
|
||||
})
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
// Libraries
|
||||
import React, {Component} from 'react'
|
||||
import _ from 'lodash'
|
||||
import {Provider} from 'unstated'
|
||||
|
||||
// Components
|
||||
import {ErrorHandling} from 'src/shared/decorators/errors'
|
||||
|
@ -11,15 +12,10 @@ import CEOHeader from 'src/dashboards/components/CEOHeader'
|
|||
import {getDeep} from 'src/utils/wrappers'
|
||||
import {buildQuery} from 'src/utils/influxql'
|
||||
import {getTimeRange} from 'src/dashboards/utils/cellGetters'
|
||||
import {TimeMachineContainer} from 'src/shared/utils/TimeMachineContainer'
|
||||
import {intialStateFromCell} from 'src/shared/utils/timeMachine'
|
||||
|
||||
// Actions
|
||||
import {
|
||||
QueryConfigActions,
|
||||
addQueryAsync,
|
||||
deleteQueryAsync,
|
||||
updateEditorTimeRange as updateEditorTimeRangeAction,
|
||||
updateScript,
|
||||
} from 'src/shared/actions/queries'
|
||||
import {editCellQueryStatus} from 'src/dashboards/actions'
|
||||
|
||||
// Constants
|
||||
|
@ -29,43 +25,34 @@ import {IS_STATIC_LEGEND} from 'src/shared/constants'
|
|||
import {STATIC_LEGEND} from 'src/dashboards/constants/cellEditor'
|
||||
|
||||
// Types
|
||||
import * as ColorsModels from 'src/types/colors'
|
||||
import * as DashboardsModels from 'src/types/dashboards'
|
||||
import * as QueriesModels from 'src/types/queries'
|
||||
import * as SourcesModels from 'src/types/sources'
|
||||
import {Service, NotificationAction} from 'src/types'
|
||||
import {Service, NotificationAction, TimeRange} from 'src/types'
|
||||
import {Template} from 'src/types/tempVars'
|
||||
import {NewDefaultCell, ThresholdType, QueryType} from 'src/types/dashboards'
|
||||
import {
|
||||
Cell,
|
||||
Legend,
|
||||
CellQuery,
|
||||
NewDefaultCell,
|
||||
QueryType,
|
||||
} from 'src/types/dashboards'
|
||||
import {Links, ScriptStatus} from 'src/types/flux'
|
||||
import {VisualizationOptions} from 'src/types/dataExplorer'
|
||||
|
||||
interface Props {
|
||||
fluxLinks: Links
|
||||
script: string
|
||||
sources: SourcesModels.Source[]
|
||||
services: Service[]
|
||||
notify: NotificationAction
|
||||
editQueryStatus: typeof editCellQueryStatus
|
||||
onCancel: () => void
|
||||
onSave: (cell: DashboardsModels.Cell | NewDefaultCell) => void
|
||||
onSave: (cell: Cell | NewDefaultCell) => void
|
||||
source: SourcesModels.Source
|
||||
dashboardID: number
|
||||
queryStatus: QueriesModels.QueryStatus
|
||||
templates: Template[]
|
||||
timeRange: QueriesModels.TimeRange
|
||||
thresholdsListType: ThresholdType
|
||||
thresholdsListColors: ColorsModels.ColorNumber[]
|
||||
gaugeColors: ColorsModels.ColorNumber[]
|
||||
lineColors: ColorsModels.ColorString[]
|
||||
cell: DashboardsModels.Cell | NewDefaultCell
|
||||
queryDrafts: DashboardsModels.CellQuery[]
|
||||
cell: Cell | NewDefaultCell
|
||||
renameCell: (name: string) => void
|
||||
updateQueryDrafts: (queryDrafts: DashboardsModels.CellQuery[]) => void
|
||||
queryConfigActions: QueryConfigActions
|
||||
addQuery: typeof addQueryAsync
|
||||
deleteQuery: typeof deleteQueryAsync
|
||||
updateScript: typeof updateScript
|
||||
updateEditorTimeRange: typeof updateEditorTimeRangeAction
|
||||
dashboardTimeRange: TimeRange
|
||||
}
|
||||
|
||||
interface State {
|
||||
|
@ -76,19 +63,21 @@ interface State {
|
|||
@ErrorHandling
|
||||
class CellEditorOverlay extends Component<Props, State> {
|
||||
private overlayRef: React.RefObject<HTMLDivElement> = React.createRef()
|
||||
private timeMachineContainer: TimeMachineContainer
|
||||
|
||||
public constructor(props: Props) {
|
||||
super(props)
|
||||
|
||||
const {cell} = props
|
||||
const legend = getDeep<DashboardsModels.Legend | null>(cell, 'legend', null)
|
||||
this.timeMachineContainer = new TimeMachineContainer({
|
||||
...intialStateFromCell(props.cell),
|
||||
timeRange: props.dashboardTimeRange,
|
||||
})
|
||||
|
||||
const legend = getDeep<Legend | null>(props, 'cell.legend', null)
|
||||
|
||||
this.state = {
|
||||
isStaticLegend: IS_STATIC_LEGEND(legend),
|
||||
status: {
|
||||
type: 'none',
|
||||
text: '',
|
||||
},
|
||||
status: {type: 'none', text: ''},
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -98,78 +87,63 @@ class CellEditorOverlay extends Component<Props, State> {
|
|||
|
||||
public render() {
|
||||
const {
|
||||
addQuery,
|
||||
cell,
|
||||
deleteQuery,
|
||||
editQueryStatus,
|
||||
fluxLinks,
|
||||
notify,
|
||||
onCancel,
|
||||
queryDrafts,
|
||||
renameCell,
|
||||
script,
|
||||
services,
|
||||
source,
|
||||
sources,
|
||||
templates,
|
||||
timeRange,
|
||||
updateEditorTimeRange,
|
||||
updateQueryDrafts,
|
||||
queryStatus,
|
||||
} = this.props
|
||||
|
||||
const {isStaticLegend} = this.state
|
||||
|
||||
return (
|
||||
<div
|
||||
className="deceo--overlay"
|
||||
onKeyDown={this.handleKeyDown}
|
||||
tabIndex={0}
|
||||
ref={this.overlayRef}
|
||||
>
|
||||
<TimeMachine
|
||||
fluxLinks={fluxLinks}
|
||||
notify={notify}
|
||||
script={script}
|
||||
queryDrafts={queryDrafts}
|
||||
updateScript={this.props.updateScript}
|
||||
editQueryStatus={editQueryStatus}
|
||||
templates={templates}
|
||||
timeRange={timeRange}
|
||||
source={source}
|
||||
onResetFocus={this.handleResetFocus}
|
||||
isInCEO={true}
|
||||
sources={sources}
|
||||
services={services}
|
||||
updateQueryDrafts={updateQueryDrafts}
|
||||
onToggleStaticLegend={this.handleToggleStaticLegend}
|
||||
isStaticLegend={isStaticLegend}
|
||||
queryConfigActions={this.props.queryConfigActions}
|
||||
addQuery={addQuery}
|
||||
deleteQuery={deleteQuery}
|
||||
updateEditorTimeRange={updateEditorTimeRange}
|
||||
visualizationOptions={this.visualizationOptions}
|
||||
queryStatus={queryStatus}
|
||||
updateScriptStatus={this.updateScriptStatus}
|
||||
<Provider inject={[this.timeMachineContainer]}>
|
||||
<div
|
||||
className="deceo--overlay"
|
||||
onKeyDown={this.handleKeyDown}
|
||||
tabIndex={0}
|
||||
ref={this.overlayRef}
|
||||
>
|
||||
{(activeEditorTab, onSetActiveEditorTab) => (
|
||||
<CEOHeader
|
||||
title={_.get(cell, 'name', '')}
|
||||
renameCell={renameCell}
|
||||
onSave={this.handleSaveCell}
|
||||
onCancel={onCancel}
|
||||
activeEditorTab={activeEditorTab}
|
||||
onSetActiveEditorTab={onSetActiveEditorTab}
|
||||
isSaveable={this.isSaveable}
|
||||
/>
|
||||
)}
|
||||
</TimeMachine>
|
||||
</div>
|
||||
<TimeMachine
|
||||
fluxLinks={fluxLinks}
|
||||
notify={notify}
|
||||
editQueryStatus={editQueryStatus}
|
||||
templates={templates}
|
||||
source={source}
|
||||
onResetFocus={this.handleResetFocus}
|
||||
isInCEO={true}
|
||||
sources={sources}
|
||||
services={services}
|
||||
onToggleStaticLegend={this.handleToggleStaticLegend}
|
||||
isStaticLegend={isStaticLegend}
|
||||
queryStatus={queryStatus}
|
||||
updateScriptStatus={this.updateScriptStatus}
|
||||
>
|
||||
{(activeEditorTab, onSetActiveEditorTab) => (
|
||||
<CEOHeader
|
||||
title={_.get(cell, 'name', '')}
|
||||
renameCell={renameCell}
|
||||
onSave={this.handleSaveCell}
|
||||
onCancel={onCancel}
|
||||
activeEditorTab={activeEditorTab}
|
||||
onSetActiveEditorTab={onSetActiveEditorTab}
|
||||
isSaveable={this.isSaveable}
|
||||
/>
|
||||
)}
|
||||
</TimeMachine>
|
||||
</div>
|
||||
</Provider>
|
||||
)
|
||||
}
|
||||
|
||||
private get isSaveable(): boolean {
|
||||
const {queryDrafts} = this.props
|
||||
const {queryDrafts} = this.timeMachineContainer.state
|
||||
const {status} = this.state
|
||||
|
||||
if (this.isFluxSource) {
|
||||
|
@ -192,44 +166,8 @@ class CellEditorOverlay extends Component<Props, State> {
|
|||
})
|
||||
}
|
||||
|
||||
private get visualizationOptions(): VisualizationOptions {
|
||||
const {
|
||||
cell,
|
||||
lineColors,
|
||||
gaugeColors,
|
||||
thresholdsListType,
|
||||
thresholdsListColors,
|
||||
} = this.props
|
||||
|
||||
const {
|
||||
type,
|
||||
tableOptions,
|
||||
fieldOptions,
|
||||
timeFormat,
|
||||
decimalPlaces,
|
||||
note,
|
||||
noteVisibility,
|
||||
} = cell
|
||||
const axes = _.get(cell, 'axes')
|
||||
|
||||
return {
|
||||
type,
|
||||
axes,
|
||||
tableOptions,
|
||||
fieldOptions,
|
||||
timeFormat,
|
||||
decimalPlaces,
|
||||
note,
|
||||
noteVisibility,
|
||||
thresholdsListColors,
|
||||
gaugeColors,
|
||||
lineColors,
|
||||
thresholdsListType,
|
||||
}
|
||||
}
|
||||
|
||||
private get isFluxSource(): boolean {
|
||||
const {queryDrafts} = this.props
|
||||
const {queryDrafts} = this.timeMachineContainer.state
|
||||
|
||||
if (getDeep<string>(queryDrafts, '0.type', '') === QueryType.Flux) {
|
||||
return true
|
||||
|
@ -241,18 +179,26 @@ class CellEditorOverlay extends Component<Props, State> {
|
|||
this.setState({status})
|
||||
}
|
||||
|
||||
private handleSaveCell = () => {
|
||||
private collectCell = (): Cell | NewDefaultCell => {
|
||||
const {cell} = this.props
|
||||
const {
|
||||
script,
|
||||
queryDrafts,
|
||||
type,
|
||||
axes,
|
||||
tableOptions,
|
||||
fieldOptions,
|
||||
timeFormat,
|
||||
decimalPlaces,
|
||||
note,
|
||||
noteVisibility,
|
||||
thresholdsListColors,
|
||||
gaugeColors,
|
||||
lineColors,
|
||||
cell,
|
||||
script,
|
||||
} = this.props
|
||||
} = this.timeMachineContainer.state
|
||||
const {isStaticLegend} = this.state
|
||||
|
||||
let queries: DashboardsModels.CellQuery[]
|
||||
let queries: CellQuery[]
|
||||
|
||||
if (this.isFluxSource) {
|
||||
queries = [
|
||||
|
@ -285,20 +231,35 @@ class CellEditorOverlay extends Component<Props, State> {
|
|||
}
|
||||
|
||||
const colors = getCellTypeColors({
|
||||
cellType: cell.type,
|
||||
cellType: type,
|
||||
gaugeColors,
|
||||
thresholdsListColors,
|
||||
lineColors,
|
||||
})
|
||||
|
||||
const newCell: DashboardsModels.Cell | NewDefaultCell = {
|
||||
const newCell = {
|
||||
...cell,
|
||||
queries,
|
||||
colors,
|
||||
axes,
|
||||
tableOptions,
|
||||
fieldOptions,
|
||||
timeFormat,
|
||||
decimalPlaces,
|
||||
note,
|
||||
noteVisibility,
|
||||
type,
|
||||
legend: isStaticLegend ? STATIC_LEGEND : {},
|
||||
}
|
||||
|
||||
this.props.onSave(newCell)
|
||||
return newCell
|
||||
}
|
||||
|
||||
private handleSaveCell = () => {
|
||||
const {onSave} = this.props
|
||||
const cell = this.collectCell()
|
||||
|
||||
onSave(cell)
|
||||
}
|
||||
|
||||
private handleKeyDown = e => {
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
// Libraries
|
||||
import React, {Component} from 'react'
|
||||
import {connect} from 'react-redux'
|
||||
import _ from 'lodash'
|
||||
import {Subscribe} from 'unstated'
|
||||
|
||||
// Components
|
||||
import GraphTypeSelector from 'src/dashboards/components/GraphTypeSelector'
|
||||
|
@ -13,21 +13,8 @@ import NoteOptions from 'src/dashboards/components/NoteOptions'
|
|||
import CellNoteEditor from 'src/shared/components/TimeMachine/CellNoteEditor'
|
||||
import Threesizer from 'src/shared/components/threesizer/Threesizer'
|
||||
|
||||
// Actions
|
||||
import {
|
||||
updateDecimalPlaces,
|
||||
updateGaugeColors,
|
||||
updateAxes,
|
||||
updateTableOptions,
|
||||
updateFieldOptions,
|
||||
updateTimeFormat,
|
||||
updateVisType,
|
||||
updateNote,
|
||||
updateNoteVisibility,
|
||||
updateThresholdsListColors,
|
||||
updateThresholdsListType,
|
||||
updateLineColors,
|
||||
} from 'src/shared/actions/visualizations'
|
||||
// Utils
|
||||
import {TimeMachineContainer} from 'src/shared/utils/TimeMachineContainer'
|
||||
|
||||
// Constants
|
||||
import {HANDLE_VERTICAL} from 'src/shared/constants'
|
||||
|
@ -35,42 +22,55 @@ import {QueryUpdateState} from 'src/shared/actions/queries'
|
|||
import {DEFAULT_AXES} from 'src/dashboards/constants/cellEditor'
|
||||
|
||||
// Types
|
||||
import {
|
||||
CellType,
|
||||
FieldOption,
|
||||
ThresholdType,
|
||||
DecimalPlaces,
|
||||
NewDefaultCell,
|
||||
NoteVisibility,
|
||||
TableOptions as TableOptionsInterface,
|
||||
} from 'src/types/dashboards'
|
||||
import {buildDefaultYLabel} from 'src/shared/presenters'
|
||||
import {ErrorHandling} from 'src/shared/decorators/errors'
|
||||
import {Axes, Cell, QueryConfig} from 'src/types'
|
||||
import {Axes, QueryConfig, CellType} from 'src/types'
|
||||
import {
|
||||
FieldOption,
|
||||
DecimalPlaces,
|
||||
NoteVisibility,
|
||||
ThresholdType,
|
||||
TableOptions as TableOptionsInterface,
|
||||
} from 'src/types/dashboards'
|
||||
import {ColorNumber, ColorString} from 'src/types/colors'
|
||||
import {VisualizationOptions} from 'src/types/dataExplorer'
|
||||
|
||||
interface Props extends VisualizationOptions {
|
||||
cell: Cell | NewDefaultCell
|
||||
interface ConnectedProps {
|
||||
type: CellType
|
||||
axes: Axes | null
|
||||
tableOptions: TableOptionsInterface
|
||||
fieldOptions: FieldOption[]
|
||||
timeFormat: string
|
||||
decimalPlaces: DecimalPlaces
|
||||
note: string
|
||||
noteVisibility: NoteVisibility
|
||||
thresholdsListColors: ColorNumber[]
|
||||
thresholdsListType: ThresholdType
|
||||
gaugeColors: ColorNumber[]
|
||||
lineColors: ColorString[]
|
||||
onUpdateDecimalPlaces: TimeMachineContainer['handleUpdateDecimalPlaces']
|
||||
onUpdateGaugeColors: TimeMachineContainer['handleUpdateGaugeColors']
|
||||
onUpdateAxes: TimeMachineContainer['handleUpdateAxes']
|
||||
onUpdateTableOptions: TimeMachineContainer['handleUpdateTableOptions']
|
||||
onUpdateFieldOptions: TimeMachineContainer['handleUpdateFieldOptions']
|
||||
onUpdateTimeFormat: TimeMachineContainer['handleUpdateTimeFormat']
|
||||
onUpdateType: TimeMachineContainer['handleUpdateType']
|
||||
onUpdateNote: TimeMachineContainer['handleUpdateNote']
|
||||
onUpdateLineColors: TimeMachineContainer['handleUpdateLineColors']
|
||||
onUpdateNoteVisibility: TimeMachineContainer['handleUpdateNoteVisibility']
|
||||
onUpdateThresholdsListColors: TimeMachineContainer['handleUpdateThresholdsListColors']
|
||||
onUpdateThresholdsListType: TimeMachineContainer['handleUpdateThresholdsListType']
|
||||
}
|
||||
|
||||
interface PassedProps {
|
||||
queryConfigs: QueryConfig[]
|
||||
staticLegend: boolean
|
||||
stateToUpdate: QueryUpdateState
|
||||
onResetFocus: () => void
|
||||
onToggleStaticLegend: (isStaticLegend: boolean) => void
|
||||
onUpdateDecimalPlaces: typeof updateDecimalPlaces
|
||||
onUpdateGaugeColors: typeof updateGaugeColors
|
||||
onUpdateAxes: typeof updateAxes
|
||||
onUpdateTableOptions: typeof updateTableOptions
|
||||
onUpdateFieldOptions: typeof updateFieldOptions
|
||||
onUpdateTimeFormat: typeof updateTimeFormat
|
||||
onUpdateVisType: typeof updateVisType
|
||||
onUpdateNote: typeof updateNote
|
||||
onUpdateLineColors: typeof updateLineColors
|
||||
onUpdateNoteVisibility: typeof updateNoteVisibility
|
||||
onUpdateThresholdsListColors: typeof updateThresholdsListColors
|
||||
onUpdateThresholdsListType: typeof updateThresholdsListType
|
||||
}
|
||||
|
||||
type Props = PassedProps & ConnectedProps
|
||||
|
||||
interface State {
|
||||
defaultYLabel: string
|
||||
}
|
||||
|
@ -103,17 +103,21 @@ class DisplayOptions extends Component<Props, State> {
|
|||
}
|
||||
|
||||
private get threesizerDivisions() {
|
||||
const {type, note, noteVisibility} = this.props
|
||||
const {
|
||||
type,
|
||||
note,
|
||||
noteVisibility,
|
||||
onUpdateType,
|
||||
onUpdateNote,
|
||||
onUpdateNoteVisibility,
|
||||
} = this.props
|
||||
return [
|
||||
{
|
||||
name: 'Visualization Type',
|
||||
headerButtons: [],
|
||||
menuOptions: [],
|
||||
render: () => (
|
||||
<GraphTypeSelector
|
||||
type={type}
|
||||
onUpdateVisType={this.handleUpdateVisType}
|
||||
/>
|
||||
<GraphTypeSelector type={type} onUpdateVisType={onUpdateType} />
|
||||
),
|
||||
headerOrientation: HANDLE_VERTICAL,
|
||||
},
|
||||
|
@ -132,8 +136,8 @@ class DisplayOptions extends Component<Props, State> {
|
|||
<CellNoteEditor
|
||||
note={note || ''}
|
||||
noteVisibility={noteVisibility}
|
||||
onUpdateNote={this.handleUpdateNote}
|
||||
onUpdateNoteVisibility={this.handleUpdateNoteVisibility}
|
||||
onUpdateNote={onUpdateNote}
|
||||
onUpdateNoteVisibility={onUpdateNoteVisibility}
|
||||
/>
|
||||
),
|
||||
headerOrientation: HANDLE_VERTICAL,
|
||||
|
@ -156,6 +160,15 @@ class DisplayOptions extends Component<Props, State> {
|
|||
timeFormat,
|
||||
tableOptions,
|
||||
fieldOptions,
|
||||
onUpdateAxes,
|
||||
onUpdateDecimalPlaces,
|
||||
onUpdateGaugeColors,
|
||||
onUpdateThresholdsListColors,
|
||||
onUpdateThresholdsListType,
|
||||
onUpdateFieldOptions,
|
||||
onUpdateLineColors,
|
||||
onUpdateTableOptions,
|
||||
onUpdateTimeFormat,
|
||||
} = this.props
|
||||
|
||||
const {defaultYLabel} = this.state
|
||||
|
@ -168,9 +181,9 @@ class DisplayOptions extends Component<Props, State> {
|
|||
axes={this.axes}
|
||||
decimalPlaces={decimalPlaces}
|
||||
gaugeColors={gaugeColors}
|
||||
onUpdateAxes={this.handleUpdateAxes}
|
||||
onUpdateDecimalPlaces={this.handleUpdateDecimalPlaces}
|
||||
onUpdateGaugeColors={this.handleUpdateGaugeColors}
|
||||
onUpdateAxes={onUpdateAxes}
|
||||
onUpdateDecimalPlaces={onUpdateDecimalPlaces}
|
||||
onUpdateGaugeColors={onUpdateGaugeColors}
|
||||
/>
|
||||
)
|
||||
case CellType.Note:
|
||||
|
@ -181,12 +194,12 @@ class DisplayOptions extends Component<Props, State> {
|
|||
onResetFocus={onResetFocus}
|
||||
axes={this.axes}
|
||||
decimalPlaces={decimalPlaces}
|
||||
onUpdateAxes={this.handleUpdateAxes}
|
||||
onUpdateAxes={onUpdateAxes}
|
||||
thresholdsListType={thresholdsListType}
|
||||
thresholdsListColors={thresholdsListColors}
|
||||
onUpdateDecimalPlaces={this.handleUpdateDecimalPlaces}
|
||||
onUpdateThresholdsListType={this.handleUpdateThresholdsListType}
|
||||
onUpdateThresholdsListColors={this.handleUpdateThresholdsListColors}
|
||||
onUpdateDecimalPlaces={onUpdateDecimalPlaces}
|
||||
onUpdateThresholdsListType={onUpdateThresholdsListType}
|
||||
onUpdateThresholdsListColors={onUpdateThresholdsListColors}
|
||||
/>
|
||||
)
|
||||
case CellType.Table:
|
||||
|
@ -200,12 +213,12 @@ class DisplayOptions extends Component<Props, State> {
|
|||
decimalPlaces={decimalPlaces}
|
||||
thresholdsListType={thresholdsListType}
|
||||
thresholdsListColors={thresholdsListColors}
|
||||
onUpdateDecimalPlaces={this.handleUpdateDecimalPlaces}
|
||||
onUpdateFieldOptions={this.handleUpdateFieldOptions}
|
||||
onUpdateTableOptions={this.handleUpdateTableOptions}
|
||||
onUpdateTimeFormat={this.handleUpdateTimeFormat}
|
||||
onUpdateThresholdsListColors={this.handleUpdateThresholdsListColors}
|
||||
onUpdateThresholdsListType={this.handleUpdateThresholdsListType}
|
||||
onUpdateDecimalPlaces={onUpdateDecimalPlaces}
|
||||
onUpdateFieldOptions={onUpdateFieldOptions}
|
||||
onUpdateTableOptions={onUpdateTableOptions}
|
||||
onUpdateTimeFormat={onUpdateTimeFormat}
|
||||
onUpdateThresholdsListColors={onUpdateThresholdsListColors}
|
||||
onUpdateThresholdsListType={onUpdateThresholdsListType}
|
||||
/>
|
||||
)
|
||||
default:
|
||||
|
@ -217,19 +230,15 @@ class DisplayOptions extends Component<Props, State> {
|
|||
staticLegend={staticLegend}
|
||||
defaultYLabel={defaultYLabel}
|
||||
decimalPlaces={decimalPlaces}
|
||||
onUpdateAxes={this.handleUpdateAxes}
|
||||
onUpdateAxes={onUpdateAxes}
|
||||
onToggleStaticLegend={onToggleStaticLegend}
|
||||
onUpdateLineColors={this.handleUpdateLineColors}
|
||||
onUpdateDecimalPlaces={this.handleUpdateDecimalPlaces}
|
||||
onUpdateLineColors={onUpdateLineColors}
|
||||
onUpdateDecimalPlaces={onUpdateDecimalPlaces}
|
||||
/>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private get stateToUpdate(): QueryUpdateState {
|
||||
return this.props.stateToUpdate
|
||||
}
|
||||
|
||||
private get axes(): Axes {
|
||||
return this.props.axes || DEFAULT_AXES
|
||||
}
|
||||
|
@ -242,95 +251,50 @@ class DisplayOptions extends Component<Props, State> {
|
|||
|
||||
return ''
|
||||
}
|
||||
|
||||
private handleUpdateAxes = (axes: Axes): void => {
|
||||
const {onUpdateAxes} = this.props
|
||||
|
||||
onUpdateAxes(axes, this.stateToUpdate)
|
||||
}
|
||||
|
||||
private handleUpdateDecimalPlaces = (decimalPlaces: DecimalPlaces): void => {
|
||||
const {onUpdateDecimalPlaces} = this.props
|
||||
|
||||
onUpdateDecimalPlaces(decimalPlaces, this.stateToUpdate)
|
||||
}
|
||||
|
||||
private handleUpdateGaugeColors = (gaugeColors: ColorNumber[]): void => {
|
||||
const {onUpdateGaugeColors} = this.props
|
||||
|
||||
onUpdateGaugeColors(gaugeColors, this.stateToUpdate)
|
||||
}
|
||||
|
||||
private handleUpdateTimeFormat = (timeFormat: string): void => {
|
||||
const {onUpdateTimeFormat} = this.props
|
||||
|
||||
onUpdateTimeFormat(timeFormat, this.stateToUpdate)
|
||||
}
|
||||
|
||||
private handleUpdateTableOptions = (
|
||||
tableOptions: TableOptionsInterface
|
||||
): void => {
|
||||
const {onUpdateTableOptions} = this.props
|
||||
|
||||
onUpdateTableOptions(tableOptions, this.stateToUpdate)
|
||||
}
|
||||
|
||||
private handleUpdateFieldOptions = (fieldOptions: FieldOption[]): void => {
|
||||
const {onUpdateFieldOptions} = this.props
|
||||
|
||||
onUpdateFieldOptions(fieldOptions, this.stateToUpdate)
|
||||
}
|
||||
|
||||
private handleUpdateVisType = (type: CellType): void => {
|
||||
const {onUpdateVisType} = this.props
|
||||
|
||||
onUpdateVisType(type, this.stateToUpdate)
|
||||
}
|
||||
|
||||
private handleUpdateNote = (note: string): void => {
|
||||
const {onUpdateNote} = this.props
|
||||
|
||||
onUpdateNote(note, this.stateToUpdate)
|
||||
}
|
||||
|
||||
private handleUpdateNoteVisibility = (visibility: NoteVisibility): void => {
|
||||
const {onUpdateNoteVisibility} = this.props
|
||||
|
||||
onUpdateNoteVisibility(visibility, this.stateToUpdate)
|
||||
}
|
||||
|
||||
private handleUpdateThresholdsListColors = (colors: ColorNumber[]): void => {
|
||||
const {onUpdateThresholdsListColors} = this.props
|
||||
|
||||
onUpdateThresholdsListColors(colors, this.stateToUpdate)
|
||||
}
|
||||
|
||||
private handleUpdateThresholdsListType = (type: ThresholdType): void => {
|
||||
const {onUpdateThresholdsListType} = this.props
|
||||
|
||||
onUpdateThresholdsListType(type, this.stateToUpdate)
|
||||
}
|
||||
|
||||
private handleUpdateLineColors = (colors: ColorString[]): void => {
|
||||
const {onUpdateLineColors} = this.props
|
||||
|
||||
onUpdateLineColors(colors, this.stateToUpdate)
|
||||
}
|
||||
}
|
||||
|
||||
const mdtp = {
|
||||
onUpdateGaugeColors: updateGaugeColors,
|
||||
onUpdateAxes: updateAxes,
|
||||
onUpdateDecimalPlaces: updateDecimalPlaces,
|
||||
onUpdateTableOptions: updateTableOptions,
|
||||
onUpdateFieldOptions: updateFieldOptions,
|
||||
onUpdateTimeFormat: updateTimeFormat,
|
||||
onUpdateVisType: updateVisType,
|
||||
onUpdateNote: updateNote,
|
||||
onUpdateNoteVisibility: updateNoteVisibility,
|
||||
onUpdateThresholdsListColors: updateThresholdsListColors,
|
||||
onUpdateThresholdsListType: updateThresholdsListType,
|
||||
onUpdateLineColors: updateLineColors,
|
||||
const ConnectedDisplayOptions = (props: PassedProps) => {
|
||||
// TODO: Have individual display option components subscribe directly to
|
||||
// relevant props, rather than passing them through here
|
||||
return (
|
||||
<Subscribe to={[TimeMachineContainer]}>
|
||||
{(timeMachineContainer: TimeMachineContainer) => (
|
||||
<DisplayOptions
|
||||
{...props}
|
||||
type={timeMachineContainer.state.type}
|
||||
axes={timeMachineContainer.state.axes}
|
||||
tableOptions={timeMachineContainer.state.tableOptions}
|
||||
fieldOptions={timeMachineContainer.state.fieldOptions}
|
||||
timeFormat={timeMachineContainer.state.timeFormat}
|
||||
decimalPlaces={timeMachineContainer.state.decimalPlaces}
|
||||
note={timeMachineContainer.state.note}
|
||||
noteVisibility={timeMachineContainer.state.noteVisibility}
|
||||
thresholdsListColors={timeMachineContainer.state.thresholdsListColors}
|
||||
thresholdsListType={timeMachineContainer.state.thresholdsListType}
|
||||
gaugeColors={timeMachineContainer.state.gaugeColors}
|
||||
lineColors={timeMachineContainer.state.lineColors}
|
||||
onUpdateType={timeMachineContainer.handleUpdateType}
|
||||
onUpdateAxes={timeMachineContainer.handleUpdateAxes}
|
||||
onUpdateTableOptions={timeMachineContainer.handleUpdateTableOptions}
|
||||
onUpdateFieldOptions={timeMachineContainer.handleUpdateFieldOptions}
|
||||
onUpdateTimeFormat={timeMachineContainer.handleUpdateTimeFormat}
|
||||
onUpdateDecimalPlaces={timeMachineContainer.handleUpdateDecimalPlaces}
|
||||
onUpdateNote={timeMachineContainer.handleUpdateNote}
|
||||
onUpdateNoteVisibility={
|
||||
timeMachineContainer.handleUpdateNoteVisibility
|
||||
}
|
||||
onUpdateThresholdsListColors={
|
||||
timeMachineContainer.handleUpdateThresholdsListColors
|
||||
}
|
||||
onUpdateThresholdsListType={
|
||||
timeMachineContainer.handleUpdateThresholdsListType
|
||||
}
|
||||
onUpdateGaugeColors={timeMachineContainer.handleUpdateGaugeColors}
|
||||
onUpdateLineColors={timeMachineContainer.handleUpdateLineColors}
|
||||
/>
|
||||
)}
|
||||
</Subscribe>
|
||||
)
|
||||
}
|
||||
|
||||
export default connect(null, mdtp)(DisplayOptions)
|
||||
export default ConnectedDisplayOptions
|
||||
|
|
|
@ -53,28 +53,25 @@ export const getCellTypeColors = ({
|
|||
thresholdsListColors,
|
||||
lineColors,
|
||||
}: Color): ColorString[] => {
|
||||
let colors: ColorString[] = []
|
||||
|
||||
switch (cellType) {
|
||||
case CellType.Gauge: {
|
||||
colors = stringifyColorValues(gaugeColors)
|
||||
break
|
||||
return stringifyColorValues(gaugeColors)
|
||||
}
|
||||
case CellType.SingleStat:
|
||||
case CellType.Table: {
|
||||
colors = stringifyColorValues(thresholdsListColors)
|
||||
break
|
||||
return stringifyColorValues(thresholdsListColors)
|
||||
}
|
||||
case CellType.Bar:
|
||||
case CellType.Line:
|
||||
case CellType.LinePlusSingleStat:
|
||||
case CellType.Stacked:
|
||||
case CellType.StepPlot: {
|
||||
colors = stringifyColorValues(lineColors)
|
||||
return stringifyColorValues(lineColors)
|
||||
}
|
||||
default: {
|
||||
return []
|
||||
}
|
||||
}
|
||||
|
||||
return colors
|
||||
}
|
||||
|
||||
export const STATIC_LEGEND: Legend = {
|
||||
|
|
|
@ -22,15 +22,6 @@ import {
|
|||
dismissEditingAnnotation,
|
||||
} from 'src/shared/actions/annotations'
|
||||
import * as cellEditorOverlayActions from 'src/dashboards/actions/cellEditorOverlay'
|
||||
import {
|
||||
queryConfigActions,
|
||||
QueryConfigActions,
|
||||
addQueryAsync,
|
||||
deleteQueryAsync,
|
||||
updateQueryDrafts as updateQueryDraftsAction,
|
||||
updateEditorTimeRange as updateEditorTimeRangeAction,
|
||||
updateScript,
|
||||
} from 'src/shared/actions/queries'
|
||||
|
||||
import * as appActions from 'src/shared/actions/app'
|
||||
import * as errorActions from 'src/shared/actions/errors'
|
||||
|
@ -68,7 +59,6 @@ import {ManualRefreshProps} from 'src/shared/components/ManualRefresh'
|
|||
import {Location} from 'history'
|
||||
import {InjectedRouter} from 'react-router'
|
||||
import * as AppActions from 'src/types/actions/app'
|
||||
import * as ColorsModels from 'src/types/colors'
|
||||
import * as DashboardsModels from 'src/types/dashboards'
|
||||
import * as ErrorsActions from 'src/types/actions/errors'
|
||||
import * as QueriesModels from 'src/types/queries'
|
||||
|
@ -81,8 +71,6 @@ import {Links} from 'src/types/flux'
|
|||
|
||||
interface Props extends ManualRefreshProps, WithRouterProps {
|
||||
fluxLinks: Links
|
||||
script: string
|
||||
updateScript: typeof updateScript
|
||||
source: SourcesModels.Source
|
||||
sources: SourcesModels.Source[]
|
||||
params: {
|
||||
|
@ -112,17 +100,9 @@ interface Props extends ManualRefreshProps, WithRouterProps {
|
|||
notify: NotificationAction
|
||||
annotationsDisplaySetting: AnnotationsDisplaySetting
|
||||
onGetAnnotationsAsync: typeof getAnnotationsAsync
|
||||
handleLoadCEO: typeof cellEditorOverlayActions.loadCEO
|
||||
handleClearCEO: typeof cellEditorOverlayActions.clearCEO
|
||||
handleDismissEditingAnnotation: typeof dismissEditingAnnotation
|
||||
selectedCell: DashboardsModels.Cell
|
||||
queryDrafts: DashboardsModels.CellQuery[]
|
||||
editorTimeRange: QueriesModels.TimeRange
|
||||
updateQueryDrafts: (queryDrafts: DashboardsModels.CellQuery[]) => void
|
||||
thresholdsListType: DashboardsModels.ThresholdType
|
||||
thresholdsListColors: ColorsModels.ColorNumber[]
|
||||
gaugeColors: ColorsModels.ColorNumber[]
|
||||
lineColors: ColorsModels.ColorString[]
|
||||
setDashTimeV1: typeof dashboardActions.setDashTimeV1
|
||||
setZoomedTimeRange: typeof dashboardActions.setZoomedTimeRange
|
||||
updateDashboard: typeof dashboardActions.updateDashboard
|
||||
|
@ -139,27 +119,12 @@ interface Props extends ManualRefreshProps, WithRouterProps {
|
|||
rehydrateTemplatesAsync: typeof dashboardActions.rehydrateTemplatesAsync
|
||||
updateTemplateQueryParams: typeof dashboardActions.updateTemplateQueryParams
|
||||
updateQueryParams: typeof dashboardActions.updateQueryParams
|
||||
addQuery: typeof addQueryAsync
|
||||
deleteQuery: typeof deleteQueryAsync
|
||||
fill: typeof queryConfigActions.fill
|
||||
timeShift: typeof queryConfigActions.timeShift
|
||||
chooseTag: typeof queryConfigActions.chooseTag
|
||||
groupByTag: typeof queryConfigActions.groupByTag
|
||||
groupByTime: typeof queryConfigActions.groupByTime
|
||||
toggleField: typeof queryConfigActions.toggleField
|
||||
removeFuncs: typeof queryConfigActions.removeFuncs
|
||||
addInitialField: typeof queryConfigActions.addInitialField
|
||||
chooseNamespace: typeof queryConfigActions.chooseNamespace
|
||||
chooseMeasurement: typeof queryConfigActions.chooseMeasurement
|
||||
applyFuncsToField: typeof queryConfigActions.applyFuncsToField
|
||||
toggleTagAcceptance: typeof queryConfigActions.toggleTagAcceptance
|
||||
updateEditorTimeRange: typeof updateEditorTimeRangeAction
|
||||
}
|
||||
|
||||
interface State {
|
||||
scrollTop: number
|
||||
windowHeight: number
|
||||
selectedCell: DashboardsModels.Cell | null
|
||||
selectedCell: DashboardsModels.Cell | DashboardsModels.NewDefaultCell | null
|
||||
dashboardLinks: DashboardsModels.DashboardSwitcherLinks
|
||||
servicesStatus: RemoteDataState
|
||||
showAnnotationControls: boolean
|
||||
|
@ -245,40 +210,28 @@ class DashboardPage extends Component<Props, State> {
|
|||
|
||||
public render() {
|
||||
const {
|
||||
script,
|
||||
notify,
|
||||
fluxLinks,
|
||||
isUsingAuth,
|
||||
meRole,
|
||||
source,
|
||||
sources,
|
||||
addQuery,
|
||||
deleteQuery,
|
||||
timeRange,
|
||||
timeRange: {lower, upper},
|
||||
editorTimeRange,
|
||||
renameCell,
|
||||
zoomedTimeRange,
|
||||
zoomedTimeRange: {lower: zoomedLower, upper: zoomedUpper},
|
||||
dashboard,
|
||||
dashboardID,
|
||||
lineColors,
|
||||
gaugeColors,
|
||||
autoRefresh,
|
||||
queryDrafts,
|
||||
selectedCell,
|
||||
manualRefresh,
|
||||
onManualRefresh,
|
||||
cellQueryStatus,
|
||||
updateQueryDrafts,
|
||||
thresholdsListType,
|
||||
thresholdsListColors,
|
||||
inPresentationMode,
|
||||
showTemplateVariableControlBar,
|
||||
handleChooseAutoRefresh,
|
||||
handleClickPresentationButton,
|
||||
toggleTemplateVariableControlBar,
|
||||
updateEditorTimeRange,
|
||||
} = this.props
|
||||
|
||||
const low = zoomedLower || lower
|
||||
|
@ -326,38 +279,31 @@ class DashboardPage extends Component<Props, State> {
|
|||
templatesIncludingDashTime = []
|
||||
}
|
||||
|
||||
const {dashboardLinks, showAnnotationControls} = this.state
|
||||
const {
|
||||
dashboardLinks,
|
||||
showAnnotationControls,
|
||||
selectedCell,
|
||||
showCellEditorOverlay,
|
||||
} = this.state
|
||||
|
||||
return (
|
||||
<Page>
|
||||
<OverlayTechnology visible={this.showCellEditorOverlay}>
|
||||
<OverlayTechnology visible={showCellEditorOverlay}>
|
||||
<CellEditorOverlay
|
||||
source={source}
|
||||
sources={sources}
|
||||
notify={notify}
|
||||
fluxLinks={fluxLinks}
|
||||
script={script}
|
||||
services={this.services}
|
||||
cell={selectedCell}
|
||||
queryDrafts={queryDrafts}
|
||||
timeRange={editorTimeRange}
|
||||
updateEditorTimeRange={updateEditorTimeRange}
|
||||
dashboardID={dashboardID}
|
||||
queryStatus={cellQueryStatus}
|
||||
onSave={this.handleSaveEditedCell}
|
||||
onCancel={this.handleHideCellEditorOverlay}
|
||||
templates={templatesIncludingDashTime}
|
||||
editQueryStatus={this.props.editCellQueryStatus}
|
||||
thresholdsListType={thresholdsListType}
|
||||
thresholdsListColors={thresholdsListColors}
|
||||
updateQueryDrafts={updateQueryDrafts}
|
||||
gaugeColors={gaugeColors}
|
||||
lineColors={lineColors}
|
||||
renameCell={renameCell}
|
||||
queryConfigActions={this.queryConfigActions}
|
||||
addQuery={addQuery}
|
||||
deleteQuery={deleteQuery}
|
||||
updateScript={this.props.updateScript}
|
||||
dashboardTimeRange={timeRange}
|
||||
/>
|
||||
</OverlayTechnology>
|
||||
<DashboardHeader
|
||||
|
@ -424,43 +370,6 @@ class DashboardPage extends Component<Props, State> {
|
|||
return getDeep(dashboard, 'templates', []).map(t => t.tempVar)
|
||||
}
|
||||
|
||||
private get queryConfigActions(): QueryConfigActions {
|
||||
const {
|
||||
fill,
|
||||
timeShift,
|
||||
chooseTag,
|
||||
groupByTag,
|
||||
groupByTime,
|
||||
toggleField,
|
||||
removeFuncs,
|
||||
addInitialField,
|
||||
chooseNamespace,
|
||||
chooseMeasurement,
|
||||
applyFuncsToField,
|
||||
toggleTagAcceptance,
|
||||
} = this.props
|
||||
return {
|
||||
fill,
|
||||
timeShift,
|
||||
chooseTag,
|
||||
groupByTag,
|
||||
groupByTime,
|
||||
toggleField,
|
||||
removeFuncs,
|
||||
addInitialField,
|
||||
chooseNamespace,
|
||||
chooseMeasurement,
|
||||
applyFuncsToField,
|
||||
toggleTagAcceptance,
|
||||
}
|
||||
}
|
||||
|
||||
private get showCellEditorOverlay(): boolean {
|
||||
const {selectedCell} = this.props
|
||||
const {showCellEditorOverlay} = this.state
|
||||
return !!selectedCell && showCellEditorOverlay
|
||||
}
|
||||
|
||||
private get showDashboard(): boolean {
|
||||
const {dashboard} = this.props
|
||||
const {servicesStatus} = this.state
|
||||
|
@ -552,12 +461,8 @@ class DashboardPage extends Component<Props, State> {
|
|||
this.handleHideCellEditorOverlay()
|
||||
}
|
||||
|
||||
private handleShowCellEditorOverlay = (
|
||||
cell: DashboardsModels.Cell | DashboardsModels.NewDefaultCell
|
||||
): void => {
|
||||
const {handleLoadCEO, timeRange} = this.props
|
||||
handleLoadCEO(cell, timeRange)
|
||||
this.setState({showCellEditorOverlay: true})
|
||||
private handleShowCellEditorOverlay = (cell: DashboardsModels.Cell): void => {
|
||||
this.setState({selectedCell: cell, showCellEditorOverlay: true})
|
||||
}
|
||||
|
||||
private handleHideCellEditorOverlay = () => {
|
||||
|
@ -599,7 +504,8 @@ class DashboardPage extends Component<Props, State> {
|
|||
private handleAddCell = (): void => {
|
||||
const {dashboard} = this.props
|
||||
const emptyCell = getNewDashboardCell(dashboard)
|
||||
this.handleShowCellEditorOverlay(emptyCell)
|
||||
|
||||
this.setState({selectedCell: emptyCell, showCellEditorOverlay: true})
|
||||
}
|
||||
|
||||
private handleCloneCell = (cell: DashboardsModels.Cell): void => {
|
||||
|
@ -703,16 +609,7 @@ const mstp = (state, {params: {dashboardID}}) => {
|
|||
sources,
|
||||
services,
|
||||
auth: {me, isUsingAuth},
|
||||
cellEditorOverlay: {
|
||||
cell,
|
||||
queryDrafts,
|
||||
thresholdsListType,
|
||||
thresholdsListColors,
|
||||
gaugeColors,
|
||||
lineColors,
|
||||
timeRange: editorTimeRange,
|
||||
script,
|
||||
},
|
||||
cellEditorOverlay: {cell, timeRange: editorTimeRange},
|
||||
} = state
|
||||
|
||||
const meRole = _.get(me, 'role', null)
|
||||
|
@ -726,7 +623,6 @@ const mstp = (state, {params: {dashboardID}}) => {
|
|||
const selectedCell = cell
|
||||
|
||||
return {
|
||||
script,
|
||||
sources,
|
||||
services,
|
||||
meRole,
|
||||
|
@ -740,19 +636,13 @@ const mstp = (state, {params: {dashboardID}}) => {
|
|||
cellQueryStatus,
|
||||
inPresentationMode,
|
||||
selectedCell,
|
||||
queryDrafts,
|
||||
editorTimeRange,
|
||||
thresholdsListType,
|
||||
thresholdsListColors,
|
||||
gaugeColors,
|
||||
lineColors,
|
||||
showTemplateVariableControlBar,
|
||||
annotationsDisplaySetting: displaySetting,
|
||||
}
|
||||
}
|
||||
|
||||
const mdtp = {
|
||||
updateScript,
|
||||
setDashTimeV1: dashboardActions.setDashTimeV1,
|
||||
setZoomedTimeRange: dashboardActions.setZoomedTimeRange,
|
||||
updateDashboard: dashboardActions.updateDashboard,
|
||||
|
@ -775,28 +665,11 @@ const mdtp = {
|
|||
handleClickPresentationButton: appActions.delayEnablePresentationMode,
|
||||
errorThrown: errorActions.errorThrown,
|
||||
notify: notifyActions.notify,
|
||||
handleLoadCEO: cellEditorOverlayActions.loadCEO,
|
||||
handleClearCEO: cellEditorOverlayActions.clearCEO,
|
||||
onGetAnnotationsAsync: getAnnotationsAsync,
|
||||
handleDismissEditingAnnotation: dismissEditingAnnotation,
|
||||
updateQueryDrafts: updateQueryDraftsAction,
|
||||
fetchServicesAsync: fetchAllFluxServicesAsync,
|
||||
renameCell: cellEditorOverlayActions.renameCell,
|
||||
addQuery: addQueryAsync,
|
||||
deleteQuery: deleteQueryAsync,
|
||||
fill: queryConfigActions.fill,
|
||||
timeShift: queryConfigActions.timeShift,
|
||||
chooseTag: queryConfigActions.chooseTag,
|
||||
groupByTag: queryConfigActions.groupByTag,
|
||||
groupByTime: queryConfigActions.groupByTime,
|
||||
toggleField: queryConfigActions.toggleField,
|
||||
removeFuncs: queryConfigActions.removeFuncs,
|
||||
addInitialField: queryConfigActions.addInitialField,
|
||||
chooseNamespace: queryConfigActions.chooseNamespace,
|
||||
chooseMeasurement: queryConfigActions.chooseMeasurement,
|
||||
applyFuncsToField: queryConfigActions.applyFuncsToField,
|
||||
toggleTagAcceptance: queryConfigActions.toggleTagAcceptance,
|
||||
updateEditorTimeRange: updateEditorTimeRangeAction,
|
||||
}
|
||||
|
||||
export default connect(mstp, mdtp)(
|
||||
|
|
|
@ -1,171 +1,32 @@
|
|||
// libraries
|
||||
import _ from 'lodash'
|
||||
import uuid from 'uuid'
|
||||
|
||||
// actions
|
||||
import {Action, ActionType} from 'src/dashboards/actions/cellEditorOverlay'
|
||||
|
||||
// utils
|
||||
import {getDeep} from 'src/utils/wrappers'
|
||||
import defaultQueryConfig from 'src/utils/defaultQueryConfig'
|
||||
|
||||
// constants
|
||||
import {
|
||||
DEFAULT_THRESHOLDS_LIST_COLORS,
|
||||
DEFAULT_GAUGE_COLORS,
|
||||
validateGaugeColors,
|
||||
validateThresholdsListColors,
|
||||
getThresholdsListType,
|
||||
} from 'src/shared/constants/thresholds'
|
||||
import {
|
||||
DEFAULT_LINE_COLORS,
|
||||
validateLineColors,
|
||||
} from 'src/shared/constants/graphColorPalettes'
|
||||
import {initializeOptions} from 'src/dashboards/constants/cellEditor'
|
||||
import {editor} from 'src/flux/constants'
|
||||
|
||||
// types
|
||||
import {CellType, Cell, TimeRange} from 'src/types'
|
||||
import {
|
||||
CellQuery,
|
||||
ThresholdType,
|
||||
TableOptions,
|
||||
QueryType,
|
||||
} from 'src/types/dashboards'
|
||||
import {ThresholdColor, GaugeColor, LineColor} from 'src/types/colors'
|
||||
import {Cell, TimeRange} from 'src/types'
|
||||
import {NewDefaultCell} from 'src/types/dashboards'
|
||||
|
||||
export interface CEOInitialState {
|
||||
cell: Cell | NewDefaultCell | null
|
||||
thresholdsListType: ThresholdType
|
||||
thresholdsListColors: ThresholdColor[]
|
||||
gaugeColors: GaugeColor[]
|
||||
lineColors: LineColor[]
|
||||
queryDrafts: CellQuery[]
|
||||
timeRange: TimeRange
|
||||
script: string
|
||||
}
|
||||
|
||||
export const initialState = {
|
||||
cell: null,
|
||||
thresholdsListType: ThresholdType.Text,
|
||||
thresholdsListColors: DEFAULT_THRESHOLDS_LIST_COLORS,
|
||||
gaugeColors: DEFAULT_GAUGE_COLORS,
|
||||
lineColors: DEFAULT_LINE_COLORS,
|
||||
queryDrafts: null,
|
||||
timeRange: null,
|
||||
script: editor.DEFAULT_SCRIPT,
|
||||
}
|
||||
|
||||
const getNewQueryDrafts = (type: string, sourceLink?: string): CellQuery[] => {
|
||||
const id = uuid.v4()
|
||||
const newQueryConfig = {
|
||||
...defaultQueryConfig({id}),
|
||||
}
|
||||
const newQueryDraft: CellQuery = {
|
||||
query: '',
|
||||
queryConfig: newQueryConfig,
|
||||
source: sourceLink || '',
|
||||
id,
|
||||
type,
|
||||
}
|
||||
return [newQueryDraft]
|
||||
}
|
||||
|
||||
export default (state = initialState, action: Action): CEOInitialState => {
|
||||
switch (action.type) {
|
||||
case ActionType.LoadCEO: {
|
||||
const {cell, timeRange} = action.payload
|
||||
|
||||
const tableOptions = getDeep<TableOptions>(
|
||||
cell,
|
||||
'tableOptions',
|
||||
initializeOptions(CellType.Table)
|
||||
)
|
||||
|
||||
// QueryDrafts corresponds to InfluxQL queries, script to Flux queries
|
||||
// When saved, either the InfluxQL query or the script is saved to cell.queries
|
||||
|
||||
let queryDrafts: CellQuery[]
|
||||
let script = editor.DEFAULT_SCRIPT
|
||||
const sourceLink = getDeep<string>(cell, 'queries.0.source', '')
|
||||
|
||||
if (getDeep<string>(cell, 'queries.0.type', '') === QueryType.Flux) {
|
||||
script = getDeep<string>(cell, 'queries.0.query', editor.DEFAULT_SCRIPT)
|
||||
|
||||
queryDrafts = getNewQueryDrafts(QueryType.Flux, sourceLink)
|
||||
} else {
|
||||
queryDrafts = cell.queries.map(q => {
|
||||
const id = uuid.v4()
|
||||
const queryConfig = {...q.queryConfig, id}
|
||||
|
||||
return {...q, queryConfig, id}
|
||||
})
|
||||
}
|
||||
if (_.isEmpty(queryDrafts)) {
|
||||
queryDrafts = getNewQueryDrafts(QueryType.InfluxQL)
|
||||
}
|
||||
|
||||
if ((cell as Cell).colors) {
|
||||
const colors = (cell as Cell).colors
|
||||
|
||||
const thresholdsListType = getThresholdsListType(colors)
|
||||
const thresholdsListColors = validateThresholdsListColors(
|
||||
colors,
|
||||
thresholdsListType
|
||||
)
|
||||
const gaugeColors = validateGaugeColors(colors)
|
||||
|
||||
const lineColors = validateLineColors(colors)
|
||||
|
||||
return {
|
||||
...state,
|
||||
cell: {...cell, tableOptions},
|
||||
thresholdsListType,
|
||||
thresholdsListColors,
|
||||
gaugeColors,
|
||||
lineColors,
|
||||
queryDrafts,
|
||||
timeRange,
|
||||
script,
|
||||
}
|
||||
}
|
||||
return {
|
||||
...state,
|
||||
cell: {...cell, tableOptions},
|
||||
queryDrafts,
|
||||
timeRange,
|
||||
script,
|
||||
}
|
||||
}
|
||||
|
||||
case ActionType.ClearCEO: {
|
||||
const cell = null
|
||||
const timeRange = null
|
||||
const script = editor.DEFAULT_SCRIPT
|
||||
|
||||
return {...state, cell, timeRange, script}
|
||||
}
|
||||
|
||||
case ActionType.ChangeCellType: {
|
||||
const {cellType} = action.payload
|
||||
const cell = {...state.cell, type: cellType}
|
||||
|
||||
return {...state, cell}
|
||||
}
|
||||
|
||||
case ActionType.UpdateCellNote: {
|
||||
const {note} = action.payload
|
||||
const cell = {...state.cell, note}
|
||||
|
||||
return {...state, cell}
|
||||
}
|
||||
|
||||
case ActionType.UpdateCellNoteVisibility: {
|
||||
const {noteVisibility} = action.payload
|
||||
const cell = {...state.cell, noteVisibility}
|
||||
|
||||
return {...state, cell}
|
||||
return {...state, cell, timeRange}
|
||||
}
|
||||
|
||||
case ActionType.RenameCell: {
|
||||
|
@ -175,87 +36,11 @@ export default (state = initialState, action: Action): CEOInitialState => {
|
|||
return {...state, cell}
|
||||
}
|
||||
|
||||
case ActionType.UpdateThresholdsListColors: {
|
||||
const {thresholdsListColors} = action.payload
|
||||
|
||||
return {...state, thresholdsListColors}
|
||||
}
|
||||
|
||||
case ActionType.UpdateThresholdsListType: {
|
||||
const {thresholdsListType} = action.payload
|
||||
|
||||
const thresholdsListColors = state.thresholdsListColors.map(color => ({
|
||||
...color,
|
||||
type: thresholdsListType,
|
||||
}))
|
||||
|
||||
return {...state, thresholdsListType, thresholdsListColors}
|
||||
}
|
||||
|
||||
case ActionType.UpdateGaugeColors: {
|
||||
const {gaugeColors} = action.payload
|
||||
|
||||
return {...state, gaugeColors}
|
||||
}
|
||||
|
||||
case ActionType.UpdateAxes: {
|
||||
const {axes} = action.payload
|
||||
const cell = {...state.cell, axes}
|
||||
|
||||
return {...state, cell}
|
||||
}
|
||||
|
||||
case ActionType.UpdateTableOptions: {
|
||||
const {tableOptions} = action.payload
|
||||
const cell = {...state.cell, tableOptions}
|
||||
|
||||
return {...state, cell}
|
||||
}
|
||||
|
||||
case ActionType.ChangeTimeFormat: {
|
||||
const {timeFormat} = action.payload
|
||||
const cell = {...state.cell, timeFormat}
|
||||
|
||||
return {...state, cell}
|
||||
}
|
||||
|
||||
case ActionType.ChangeDecimalPlaces: {
|
||||
const {decimalPlaces} = action.payload
|
||||
const cell = {...state.cell, decimalPlaces}
|
||||
|
||||
return {...state, cell}
|
||||
}
|
||||
|
||||
case ActionType.UpdateFieldOptions: {
|
||||
const {fieldOptions} = action.payload
|
||||
const cell = {...state.cell, fieldOptions}
|
||||
|
||||
return {...state, cell}
|
||||
}
|
||||
|
||||
case ActionType.UpdateLineColors: {
|
||||
const {lineColors} = action.payload
|
||||
|
||||
return {...state, lineColors}
|
||||
}
|
||||
|
||||
case ActionType.UpdateQueryDrafts: {
|
||||
const {queryDrafts} = action.payload
|
||||
|
||||
return {...state, queryDrafts}
|
||||
}
|
||||
|
||||
case ActionType.UpdateEditorTimeRange: {
|
||||
const {timeRange} = action.payload
|
||||
|
||||
return {...state, timeRange}
|
||||
}
|
||||
|
||||
case ActionType.UpdateScript: {
|
||||
const {script} = action.payload
|
||||
|
||||
return {...state, script}
|
||||
}
|
||||
}
|
||||
|
||||
return state
|
||||
|
|
|
@ -1,60 +1,17 @@
|
|||
// Types
|
||||
import {ColorNumber, ColorString} from 'src/types/colors'
|
||||
import {TimeRange, CellQuery, Status, CellType, Axes} from 'src/types'
|
||||
import {
|
||||
DecimalPlaces,
|
||||
FieldOption,
|
||||
ThresholdType,
|
||||
TableOptions,
|
||||
NoteVisibility,
|
||||
} from 'src/types/dashboards'
|
||||
import {DEState} from 'src/types/dataExplorer'
|
||||
import {Status} from 'src/types'
|
||||
|
||||
export interface State {
|
||||
dataExplorer: DEState
|
||||
}
|
||||
|
||||
export enum ActionType {
|
||||
LoadDE = 'LOAD_DE',
|
||||
UpdateQueryDrafts = 'DE_UPDATE_QUERY_DRAFTS',
|
||||
UpdateEditorTimeRange = 'DE_UPDATE_EDITOR_TIME_RANGE',
|
||||
UpdateQueryStatus = 'DE_UPDATE_QUERY_STATUS',
|
||||
UpdateScript = 'DE_UPDATE_SCRIPT',
|
||||
UpdateSourceLink = 'DE_UPDATE_SOURCE_LINK',
|
||||
ChangeVisualizationType = 'DE_CHANGE_Visualization_TYPE',
|
||||
UpdateThresholdsListColors = 'DE_UPDATE_THRESHOLDS_LIST_COLORS',
|
||||
UpdateThresholdsListType = 'DE_UPDATE_THRESHOLDS_LIST_TYPE',
|
||||
UpdateGaugeColors = 'DE_UPDATE_GAUGE_COLORS',
|
||||
UpdateAxes = 'DE_UPDATE_AXES',
|
||||
UpdateTableOptions = 'DE_UPDATE_TABLE_OPTIONS',
|
||||
UpdateLineColors = 'DE_UPDATE_LINE_COLORS',
|
||||
ChangeTimeFormat = 'DE_CHANGE_TIME_FORMAT',
|
||||
ChangeDecimalPlaces = 'DE_CHANGE_DECIMAL_PLACES',
|
||||
UpdateFieldOptions = 'DE_UPDATE_FIELD_OPTIONS',
|
||||
UpdateQueryDraft = 'DE_UPDATE_QUERY_DRAFT',
|
||||
UpdateNote = 'DE_UPDATE_NOTE',
|
||||
UpdateNoteVisibility = 'DE_UPDATE_NOTE_VISIBILITY',
|
||||
EditQueryStatus = 'EDIT_QUERY_STATUS',
|
||||
}
|
||||
|
||||
export type Action =
|
||||
| LoadDEAction
|
||||
| UpdateEditorTimeRangeAction
|
||||
| UpdateQueryDraftsAction
|
||||
| UpdateQueryStatusAction
|
||||
| UpdateScriptAction
|
||||
| UpdateSourceLinkAction
|
||||
| ChangeVisualizationTypeAction
|
||||
| UpdateThresholdsListColorsAction
|
||||
| UpdateThresholdsListTypeAction
|
||||
| UpdateGaugeColorsAction
|
||||
| UpdateAxesAction
|
||||
| UpdateTableOptionsAction
|
||||
| UpdateLineColorsAction
|
||||
| ChangeTimeFormatAction
|
||||
| ChangeDecimalPlacesAction
|
||||
| UpdateFieldOptionsAction
|
||||
| UpdateCellNoteAction
|
||||
| UpdateCellNoteVisibilityAction
|
||||
export type Action = UpdateSourceLinkAction | EditQueryStatusAction
|
||||
|
||||
export interface UpdateSourceLinkAction {
|
||||
type: ActionType.UpdateSourceLink
|
||||
|
@ -63,138 +20,6 @@ export interface UpdateSourceLinkAction {
|
|||
}
|
||||
}
|
||||
|
||||
export interface LoadDEAction {
|
||||
type: ActionType.LoadDE
|
||||
payload: {
|
||||
queries: CellQuery[]
|
||||
timeRange: TimeRange
|
||||
}
|
||||
}
|
||||
|
||||
export interface UpdateQueryDraftsAction {
|
||||
type: ActionType.UpdateQueryDrafts
|
||||
payload: {
|
||||
queryDrafts: CellQuery[]
|
||||
}
|
||||
}
|
||||
|
||||
export interface UpdateEditorTimeRangeAction {
|
||||
type: ActionType.UpdateEditorTimeRange
|
||||
payload: {
|
||||
timeRange: TimeRange
|
||||
}
|
||||
}
|
||||
|
||||
export interface UpdateQueryStatusAction {
|
||||
type: ActionType.UpdateQueryStatus
|
||||
payload: {
|
||||
queryID: string
|
||||
status: Status
|
||||
}
|
||||
}
|
||||
|
||||
export interface UpdateScriptAction {
|
||||
type: ActionType.UpdateScript
|
||||
payload: {
|
||||
script: string
|
||||
}
|
||||
}
|
||||
|
||||
export interface ChangeVisualizationTypeAction {
|
||||
type: ActionType.ChangeVisualizationType
|
||||
payload: {
|
||||
cellType: CellType
|
||||
}
|
||||
}
|
||||
|
||||
export interface UpdateThresholdsListColorsAction {
|
||||
type: ActionType.UpdateThresholdsListColors
|
||||
payload: {
|
||||
thresholdsListColors: ColorNumber[]
|
||||
}
|
||||
}
|
||||
|
||||
export interface UpdateThresholdsListTypeAction {
|
||||
type: ActionType.UpdateThresholdsListType
|
||||
payload: {
|
||||
thresholdsListType: ThresholdType
|
||||
}
|
||||
}
|
||||
|
||||
export interface UpdateGaugeColorsAction {
|
||||
type: ActionType.UpdateGaugeColors
|
||||
payload: {
|
||||
gaugeColors: ColorNumber[]
|
||||
}
|
||||
}
|
||||
|
||||
export interface UpdateAxesAction {
|
||||
type: ActionType.UpdateAxes
|
||||
payload: {
|
||||
axes: Axes
|
||||
}
|
||||
}
|
||||
|
||||
export interface UpdateTableOptionsAction {
|
||||
type: ActionType.UpdateTableOptions
|
||||
payload: {
|
||||
tableOptions: TableOptions
|
||||
}
|
||||
}
|
||||
|
||||
export interface UpdateLineColorsAction {
|
||||
type: ActionType.UpdateLineColors
|
||||
payload: {
|
||||
lineColors: ColorString[]
|
||||
}
|
||||
}
|
||||
|
||||
export interface ChangeTimeFormatAction {
|
||||
type: ActionType.ChangeTimeFormat
|
||||
payload: {
|
||||
timeFormat: string
|
||||
}
|
||||
}
|
||||
|
||||
export interface ChangeDecimalPlacesAction {
|
||||
type: ActionType.ChangeDecimalPlaces
|
||||
payload: {
|
||||
decimalPlaces: DecimalPlaces
|
||||
}
|
||||
}
|
||||
|
||||
export interface UpdateFieldOptionsAction {
|
||||
type: ActionType.UpdateFieldOptions
|
||||
payload: {
|
||||
fieldOptions: FieldOption[]
|
||||
}
|
||||
}
|
||||
|
||||
export interface UpdateCellNoteAction {
|
||||
type: ActionType.UpdateNote
|
||||
payload: {
|
||||
note: string
|
||||
}
|
||||
}
|
||||
|
||||
export interface UpdateCellNoteVisibilityAction {
|
||||
type: ActionType.UpdateNoteVisibility
|
||||
payload: {
|
||||
noteVisibility: NoteVisibility
|
||||
}
|
||||
}
|
||||
|
||||
export const loadDE = (
|
||||
queries: CellQuery[],
|
||||
timeRange: TimeRange
|
||||
): LoadDEAction => ({
|
||||
type: ActionType.LoadDE,
|
||||
payload: {
|
||||
queries,
|
||||
timeRange,
|
||||
},
|
||||
})
|
||||
|
||||
export const updateSourceLink = (
|
||||
sourceLink: string
|
||||
): UpdateSourceLinkAction => ({
|
||||
|
@ -203,3 +28,19 @@ export const updateSourceLink = (
|
|||
sourceLink,
|
||||
},
|
||||
})
|
||||
|
||||
interface EditQueryStatusAction {
|
||||
type: ActionType.EditQueryStatus
|
||||
payload: {
|
||||
queryID: string
|
||||
status: Status
|
||||
}
|
||||
}
|
||||
|
||||
export const editQueryStatus = (
|
||||
queryID: string,
|
||||
status: Status
|
||||
): EditQueryStatusAction => ({
|
||||
type: ActionType.EditQueryStatus,
|
||||
payload: {queryID, status},
|
||||
})
|
||||
|
|
|
@ -1,10 +1,12 @@
|
|||
// Libraries
|
||||
import React, {PureComponent} from 'react'
|
||||
import _ from 'lodash'
|
||||
import {Subscribe} from 'unstated'
|
||||
|
||||
// Utils
|
||||
import {getNewDashboardCell} from 'src/dashboards/utils/cellGetters'
|
||||
import {getCellTypeColors} from 'src/dashboards/constants/cellEditor'
|
||||
import {TimeMachineContainer} from 'src/shared/utils/TimeMachineContainer'
|
||||
|
||||
// Components
|
||||
import {
|
||||
|
@ -44,7 +46,7 @@ import {getDeep} from 'src/utils/wrappers'
|
|||
import {VisualizationOptions} from 'src/types/dataExplorer'
|
||||
import {ColorString} from 'src/types/colors'
|
||||
|
||||
interface Props {
|
||||
interface PassedProps {
|
||||
queryConfig: QueryConfig
|
||||
script: string
|
||||
dashboards: Dashboard[]
|
||||
|
@ -56,12 +58,17 @@ interface Props {
|
|||
dashboard: Dashboard,
|
||||
newCell: Partial<Cell>
|
||||
) => Promise<{success: boolean; dashboard: Dashboard}>
|
||||
visualizationOptions: VisualizationOptions
|
||||
isStaticLegend: boolean
|
||||
handleGetDashboards: () => Dashboard[]
|
||||
notify: (message: Notification) => void
|
||||
}
|
||||
|
||||
interface ConnectedProps {
|
||||
visualizationOptions: VisualizationOptions
|
||||
}
|
||||
|
||||
type Props = PassedProps & ConnectedProps
|
||||
|
||||
interface State {
|
||||
selectedIDs: string[]
|
||||
name: string
|
||||
|
@ -306,4 +313,49 @@ class SendToDashboardOverlay extends PureComponent<Props, State> {
|
|||
}
|
||||
}
|
||||
|
||||
export default SendToDashboardOverlay
|
||||
const ConnectedSendToDashboardOverlay = (props: PassedProps) => {
|
||||
return (
|
||||
<Subscribe to={[TimeMachineContainer]}>
|
||||
{(timeMachineContainer: TimeMachineContainer) => {
|
||||
const {
|
||||
type,
|
||||
tableOptions,
|
||||
fieldOptions,
|
||||
timeFormat,
|
||||
decimalPlaces,
|
||||
note,
|
||||
noteVisibility,
|
||||
axes,
|
||||
thresholdsListColors,
|
||||
thresholdsListType,
|
||||
gaugeColors,
|
||||
lineColors,
|
||||
} = timeMachineContainer.state
|
||||
|
||||
const visualizationOptions = {
|
||||
type,
|
||||
axes,
|
||||
tableOptions,
|
||||
fieldOptions,
|
||||
timeFormat,
|
||||
decimalPlaces,
|
||||
note,
|
||||
noteVisibility,
|
||||
thresholdsListColors,
|
||||
gaugeColors,
|
||||
lineColors,
|
||||
thresholdsListType,
|
||||
}
|
||||
|
||||
return (
|
||||
<SendToDashboardOverlay
|
||||
{...props}
|
||||
visualizationOptions={visualizationOptions}
|
||||
/>
|
||||
)
|
||||
}}
|
||||
</Subscribe>
|
||||
)
|
||||
}
|
||||
|
||||
export default ConnectedSendToDashboardOverlay
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
import {timeRanges} from 'src/shared/data/timeRanges'
|
||||
|
||||
export const INFLUXQL_FUNCTIONS: string[] = [
|
||||
'mean',
|
||||
'median',
|
||||
|
@ -210,3 +212,7 @@ export const METAQUERY_TEMPLATE_OPTIONS: Array<
|
|||
|
||||
export const WRITE_DATA_DOCS_LINK =
|
||||
'https://docs.influxdata.com/influxdb/latest/write_protocols/line_protocol_tutorial/'
|
||||
|
||||
export const DEFAULT_TIME_RANGE = timeRanges.find(
|
||||
tr => tr.lower === 'now() - 1h'
|
||||
)
|
||||
|
|
|
@ -2,20 +2,20 @@
|
|||
import React, {PureComponent} from 'react'
|
||||
import {connect} from 'react-redux'
|
||||
import {bindActionCreators} from 'redux'
|
||||
import {withRouter, InjectedRouter} from 'react-router'
|
||||
import {withRouter, InjectedRouter, WithRouterProps} from 'react-router'
|
||||
import {Location} from 'history'
|
||||
import qs from 'qs'
|
||||
import uuid from 'uuid'
|
||||
import _ from 'lodash'
|
||||
import {Subscribe} from 'unstated'
|
||||
|
||||
// Utils
|
||||
import {stripPrefix} from 'src/utils/basepath'
|
||||
import {GlobalAutoRefresher} from 'src/utils/AutoRefresher'
|
||||
import {getConfig} from 'src/dashboards/utils/cellGetters'
|
||||
import {buildRawText} from 'src/utils/influxql'
|
||||
|
||||
// Constants
|
||||
import {timeRanges} from 'src/shared/data/timeRanges'
|
||||
import {defaultQueryDraft} from 'src/shared/utils/timeMachine'
|
||||
import {TimeMachineContainer} from 'src/shared/utils/TimeMachineContainer'
|
||||
|
||||
// Components
|
||||
import WriteDataForm from 'src/data_explorer/components/WriteDataForm'
|
||||
|
@ -34,20 +34,8 @@ import {
|
|||
sendDashboardCellAsync,
|
||||
} from 'src/dashboards/actions'
|
||||
import {writeLineProtocolAsync} from 'src/data_explorer/actions/view/write'
|
||||
import {
|
||||
loadDE as loadDEAction,
|
||||
updateSourceLink as updateSourceLinkAction,
|
||||
} from 'src/data_explorer/actions/queries'
|
||||
import {
|
||||
queryConfigActions as queryConfigModifiers,
|
||||
updateQueryDrafts as updateQueryDraftsAction,
|
||||
updateQueryStatus as editQueryStatusAction,
|
||||
updateScript as updateScriptAction,
|
||||
addQueryAsync,
|
||||
deleteQueryAsync,
|
||||
updateEditorTimeRange,
|
||||
QueryUpdateState,
|
||||
} from 'src/shared/actions/queries'
|
||||
import {updateSourceLink as updateSourceLinkAction} from 'src/data_explorer/actions/queries'
|
||||
import {editQueryStatus as editQueryStatusAction} from 'src/data_explorer/actions/queries'
|
||||
import {fetchAllFluxServicesAsync} from 'src/shared/actions/services'
|
||||
import {notify as notifyAction} from 'src/shared/actions/notifications'
|
||||
|
||||
|
@ -62,45 +50,31 @@ import {
|
|||
import {
|
||||
Source,
|
||||
Service,
|
||||
TimeRange,
|
||||
Dashboard,
|
||||
CellQuery,
|
||||
QueryConfig,
|
||||
QueryStatus,
|
||||
Template,
|
||||
TemplateType,
|
||||
TemplateValueType,
|
||||
CellType,
|
||||
Axes,
|
||||
Notification,
|
||||
Cell,
|
||||
QueryType,
|
||||
CellQuery,
|
||||
TimeRange,
|
||||
} from 'src/types'
|
||||
import {ErrorHandling} from 'src/shared/decorators/errors'
|
||||
import {Links} from 'src/types/flux'
|
||||
import {ColorNumber, ColorString} from 'src/types/colors'
|
||||
import {
|
||||
DecimalPlaces,
|
||||
FieldOption,
|
||||
ThresholdType,
|
||||
TableOptions,
|
||||
NoteVisibility,
|
||||
QueryType,
|
||||
Cell,
|
||||
} from 'src/types/dashboards'
|
||||
import {VisualizationOptions} from 'src/types/dataExplorer'
|
||||
|
||||
interface Props {
|
||||
interface PassedProps {
|
||||
source: Source
|
||||
sources: Source[]
|
||||
services: Service[]
|
||||
queryConfigs: QueryConfig[]
|
||||
updateSourceLink: typeof updateSourceLinkAction
|
||||
queryConfigActions: typeof queryConfigModifiers
|
||||
autoRefresh: number
|
||||
handleChooseAutoRefresh: () => void
|
||||
router?: InjectedRouter
|
||||
location?: Location
|
||||
setTimeRange: (range: TimeRange) => void
|
||||
timeRange: TimeRange
|
||||
manualRefresh: number
|
||||
dashboards: Dashboard[]
|
||||
onManualRefresh: () => void
|
||||
|
@ -111,33 +85,24 @@ interface Props {
|
|||
dashboard: Dashboard,
|
||||
newCell: Partial<Cell>
|
||||
) => Promise<{success: boolean; dashboard: Dashboard}>
|
||||
updateQueryDrafts: typeof updateQueryDraftsAction
|
||||
loadDE: typeof loadDEAction
|
||||
addQuery: typeof addQueryAsync
|
||||
deleteQuery: typeof deleteQueryAsync
|
||||
queryDrafts: CellQuery[]
|
||||
editQueryStatus: typeof editQueryStatusAction
|
||||
queryStatus: QueryStatus
|
||||
fluxLinks: Links
|
||||
script: string
|
||||
updateScript: typeof updateScriptAction
|
||||
fetchServicesAsync: typeof fetchAllFluxServicesAsync
|
||||
notify: (message: Notification) => void
|
||||
sourceLink: string
|
||||
thresholdsListType: ThresholdType
|
||||
thresholdsListColors: ColorNumber[]
|
||||
gaugeColors: ColorNumber[]
|
||||
lineColors: ColorString[]
|
||||
visType: CellType
|
||||
axes: Axes
|
||||
tableOptions: TableOptions
|
||||
timeFormat: string
|
||||
decimalPlaces: DecimalPlaces
|
||||
fieldOptions: FieldOption[]
|
||||
note: string
|
||||
noteVisibility: NoteVisibility
|
||||
}
|
||||
|
||||
interface ConnectedProps {
|
||||
queryDrafts: CellQuery[]
|
||||
timeRange: TimeRange
|
||||
script: string
|
||||
onUpdateQueryDrafts: (queryDrafts: CellQuery[]) => void
|
||||
onChangeScript: TimeMachineContainer['handleChangeScript']
|
||||
}
|
||||
|
||||
type Props = PassedProps & ConnectedProps
|
||||
|
||||
interface State {
|
||||
isWriteFormVisible: boolean
|
||||
isSendToDashboardVisible: boolean
|
||||
|
@ -159,31 +124,10 @@ export class DataExplorer extends PureComponent<Props, State> {
|
|||
}
|
||||
|
||||
public async componentDidMount() {
|
||||
const {loadDE, timeRange, autoRefresh, queryDrafts} = this.props
|
||||
const {query, script} = this.queryString
|
||||
const isFlux = !!script
|
||||
const {autoRefresh} = this.props
|
||||
|
||||
await this.fetchFluxServices()
|
||||
|
||||
if (isFlux) {
|
||||
this.createNewQueryDraft()
|
||||
} else if (_.isEmpty(query)) {
|
||||
let drafts = []
|
||||
if (!_.isEmpty(queryDrafts)) {
|
||||
drafts = queryDrafts
|
||||
}
|
||||
loadDE(drafts, timeRange)
|
||||
} else if (!_.isEmpty(queryDrafts)) {
|
||||
const matchingQueryDraft = queryDrafts.find(q => q.query === query)
|
||||
|
||||
if (matchingQueryDraft) {
|
||||
loadDE(queryDrafts, timeRange)
|
||||
} else {
|
||||
await this.createNewQueryDraft()
|
||||
}
|
||||
} else {
|
||||
await this.createNewQueryDraft()
|
||||
}
|
||||
await this.resolveQueryParams()
|
||||
|
||||
GlobalAutoRefresher.poll(autoRefresh)
|
||||
this.setState({isComponentMounted: true})
|
||||
|
@ -191,11 +135,17 @@ export class DataExplorer extends PureComponent<Props, State> {
|
|||
|
||||
public componentDidUpdate(prevProps: Props) {
|
||||
const {autoRefresh} = this.props
|
||||
|
||||
if (autoRefresh !== prevProps.autoRefresh) {
|
||||
GlobalAutoRefresher.poll(autoRefresh)
|
||||
}
|
||||
|
||||
this.updateQueryStringQuery()
|
||||
if (
|
||||
prevProps.location === this.props.location &&
|
||||
this.state.isComponentMounted
|
||||
) {
|
||||
this.writeQueryParams()
|
||||
}
|
||||
}
|
||||
|
||||
public componentWillUnmount() {
|
||||
|
@ -207,18 +157,14 @@ export class DataExplorer extends PureComponent<Props, State> {
|
|||
source,
|
||||
sources,
|
||||
services,
|
||||
timeRange,
|
||||
manualRefresh,
|
||||
onManualRefresh,
|
||||
editQueryStatus,
|
||||
updateQueryDrafts,
|
||||
queryDrafts,
|
||||
addQuery,
|
||||
deleteQuery,
|
||||
queryStatus,
|
||||
fluxLinks,
|
||||
notify,
|
||||
updateSourceLink,
|
||||
timeRange,
|
||||
} = this.props
|
||||
const {isStaticLegend, isComponentMounted} = this.state
|
||||
|
||||
|
@ -234,29 +180,19 @@ export class DataExplorer extends PureComponent<Props, State> {
|
|||
<TimeMachine
|
||||
service={this.service}
|
||||
updateSourceLink={updateSourceLink}
|
||||
queryDrafts={queryDrafts}
|
||||
editQueryStatus={editQueryStatus}
|
||||
templates={this.templates}
|
||||
timeRange={timeRange}
|
||||
source={source}
|
||||
onResetFocus={this.handleResetFocus}
|
||||
isInCEO={false}
|
||||
sources={sources}
|
||||
services={services}
|
||||
updateQueryDrafts={updateQueryDrafts}
|
||||
onToggleStaticLegend={this.handleToggleStaticLegend}
|
||||
isStaticLegend={isStaticLegend}
|
||||
queryConfigActions={this.props.queryConfigActions}
|
||||
addQuery={addQuery}
|
||||
deleteQuery={deleteQuery}
|
||||
updateEditorTimeRange={this.handleChooseTimeRange}
|
||||
manualRefresh={manualRefresh}
|
||||
queryStatus={queryStatus}
|
||||
script={this.activeScript}
|
||||
updateScript={this.handleUpdateScript}
|
||||
fluxLinks={fluxLinks}
|
||||
notify={notify}
|
||||
visualizationOptions={this.visualizationOptions}
|
||||
>
|
||||
{(activeEditorTab, onSetActiveEditorTab) => (
|
||||
<DEHeader
|
||||
|
@ -274,42 +210,79 @@ export class DataExplorer extends PureComponent<Props, State> {
|
|||
)
|
||||
}
|
||||
|
||||
private get shouldUpdateQueryString(): boolean {
|
||||
const {queryDrafts} = this.props
|
||||
const query = _.get(queryDrafts, '0.query', '')
|
||||
const {query: existing} = this.queryString
|
||||
const isFlux = !!this.service
|
||||
private async resolveQueryParams() {
|
||||
const {
|
||||
source,
|
||||
sourceLink,
|
||||
queryDrafts,
|
||||
onUpdateQueryDrafts,
|
||||
onChangeScript,
|
||||
} = this.props
|
||||
const {query, script} = this.readQueryParams()
|
||||
|
||||
return !_.isEmpty(query) && query !== existing && !isFlux
|
||||
}
|
||||
if (script) {
|
||||
const queryDraft = {...defaultQueryDraft(QueryType.Flux), query: script}
|
||||
|
||||
private handleUpdateScript = (
|
||||
script: string,
|
||||
stateToUpdate: QueryUpdateState
|
||||
) => {
|
||||
const {router} = this.props
|
||||
const pathname = stripPrefix(location.pathname)
|
||||
const qsNew = qs.stringify({script})
|
||||
|
||||
router.push(`${pathname}?${qsNew}`)
|
||||
this.props.updateScript(script, stateToUpdate)
|
||||
}
|
||||
|
||||
private updateQueryStringQuery() {
|
||||
if (!this.shouldUpdateQueryString) {
|
||||
onUpdateQueryDrafts([queryDraft])
|
||||
onChangeScript(script)
|
||||
return
|
||||
}
|
||||
|
||||
const {queryDrafts, router} = this.props
|
||||
const query = _.get(queryDrafts, '0.query', '')
|
||||
const qsNew = qs.stringify({query})
|
||||
const pathname = stripPrefix(location.pathname)
|
||||
if (query) {
|
||||
if (queryDrafts.find(q => q.query === query)) {
|
||||
// Has matching query draft already loaded
|
||||
return
|
||||
}
|
||||
|
||||
router.push(`${pathname}?${qsNew}`)
|
||||
const queryConfig = await getConfig(
|
||||
source.links.queries,
|
||||
uuid.v4(),
|
||||
query,
|
||||
this.templates
|
||||
)
|
||||
|
||||
const queryDraft = {
|
||||
query,
|
||||
queryConfig,
|
||||
source: sourceLink,
|
||||
type: QueryType.InfluxQL,
|
||||
}
|
||||
|
||||
onUpdateQueryDrafts([queryDraft])
|
||||
return
|
||||
}
|
||||
|
||||
if (!queryDrafts.length) {
|
||||
const queryDraft = defaultQueryDraft(QueryType.InfluxQL)
|
||||
|
||||
onUpdateQueryDrafts([queryDraft])
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
private get queryString(): {query?: string; script?: string} {
|
||||
return qs.parse(location.search, {ignoreQueryPrefix: true})
|
||||
private readQueryParams(): {query?: string; script?: string} {
|
||||
const {query, script} = qs.parse(location.search, {ignoreQueryPrefix: true})
|
||||
|
||||
return {query, script}
|
||||
}
|
||||
|
||||
private writeQueryParams() {
|
||||
const {router, queryDrafts, script} = this.props
|
||||
const query = _.get(queryDrafts, '0.query')
|
||||
const isFlux = _.get(queryDrafts, '0.type') === QueryType.Flux
|
||||
|
||||
let queryParams
|
||||
|
||||
if (isFlux && script) {
|
||||
queryParams = {script}
|
||||
} else if (!isFlux && query) {
|
||||
queryParams = {query}
|
||||
}
|
||||
|
||||
const pathname = stripPrefix(location.pathname)
|
||||
const search = queryParams ? `?${qs.stringify(queryParams)}` : ''
|
||||
|
||||
router.push(pathname + search)
|
||||
}
|
||||
|
||||
private get service(): Service {
|
||||
|
@ -347,9 +320,9 @@ export class DataExplorer extends PureComponent<Props, State> {
|
|||
source,
|
||||
dashboards,
|
||||
sendDashboardCell,
|
||||
script,
|
||||
handleGetDashboards,
|
||||
notify,
|
||||
script,
|
||||
} = this.props
|
||||
|
||||
const {isSendToDashboardVisible, isStaticLegend} = this.state
|
||||
|
@ -367,7 +340,6 @@ export class DataExplorer extends PureComponent<Props, State> {
|
|||
dashboards={dashboards}
|
||||
handleGetDashboards={handleGetDashboards}
|
||||
sendDashboardCell={sendDashboardCell}
|
||||
visualizationOptions={this.visualizationOptions}
|
||||
isStaticLegend={isStaticLegend}
|
||||
/>
|
||||
</OverlayTechnology>
|
||||
|
@ -376,9 +348,7 @@ export class DataExplorer extends PureComponent<Props, State> {
|
|||
}
|
||||
|
||||
private get templates(): Template[] {
|
||||
const {lower, upper} = timeRanges.find(tr => tr.lower === 'now() - 1h')
|
||||
|
||||
const timeRange = this.props.timeRange || {lower, upper}
|
||||
const {timeRange} = this.props
|
||||
|
||||
const low = timeRange.lower
|
||||
const up = timeRange.upper
|
||||
|
@ -436,10 +406,6 @@ export class DataExplorer extends PureComponent<Props, State> {
|
|||
this.setState({isWriteFormVisible: true})
|
||||
}
|
||||
|
||||
private handleChooseTimeRange = (timeRange: TimeRange): void => {
|
||||
this.props.setTimeRange(timeRange)
|
||||
}
|
||||
|
||||
private async fetchFluxServices() {
|
||||
const {fetchServicesAsync, sources} = this.props
|
||||
if (!sources.length) {
|
||||
|
@ -455,49 +421,20 @@ export class DataExplorer extends PureComponent<Props, State> {
|
|||
|
||||
private get activeQueryConfig(): QueryConfig {
|
||||
const {queryDrafts} = this.props
|
||||
|
||||
return _.get(queryDrafts, '0.queryConfig')
|
||||
}
|
||||
|
||||
private get rawText(): string {
|
||||
const {timeRange} = this.props
|
||||
|
||||
if (this.activeQueryConfig) {
|
||||
return buildRawText(this.activeQueryConfig, timeRange)
|
||||
}
|
||||
|
||||
return ''
|
||||
}
|
||||
|
||||
private get visualizationOptions(): VisualizationOptions {
|
||||
const {
|
||||
visType,
|
||||
tableOptions,
|
||||
fieldOptions,
|
||||
timeFormat,
|
||||
decimalPlaces,
|
||||
note,
|
||||
noteVisibility,
|
||||
axes,
|
||||
thresholdsListColors,
|
||||
thresholdsListType,
|
||||
gaugeColors,
|
||||
lineColors,
|
||||
} = this.props
|
||||
|
||||
return {
|
||||
type: visType,
|
||||
axes,
|
||||
tableOptions,
|
||||
fieldOptions,
|
||||
timeFormat,
|
||||
decimalPlaces,
|
||||
note,
|
||||
noteVisibility,
|
||||
thresholdsListColors,
|
||||
gaugeColors,
|
||||
lineColors,
|
||||
thresholdsListType,
|
||||
}
|
||||
}
|
||||
|
||||
private toggleSendToDashboard = () => {
|
||||
this.setState({
|
||||
isSendToDashboardVisible: !this.state.isSendToDashboardVisible,
|
||||
|
@ -511,47 +448,23 @@ export class DataExplorer extends PureComponent<Props, State> {
|
|||
private handleResetFocus = () => {
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
private async createNewQueryDraft() {
|
||||
const {source, loadDE, timeRange, sourceLink} = this.props
|
||||
|
||||
const {query} = this.queryString
|
||||
const queryConfig = await getConfig(
|
||||
source.links.queries,
|
||||
uuid.v4(),
|
||||
query,
|
||||
this.templates
|
||||
)
|
||||
|
||||
const isFlux = !!this.service
|
||||
|
||||
if (isFlux) {
|
||||
const queryDraft = {
|
||||
query,
|
||||
queryConfig,
|
||||
source: sourceLink,
|
||||
type: QueryType.Flux,
|
||||
}
|
||||
loadDE([queryDraft], timeRange)
|
||||
} else {
|
||||
const queryDraft = {
|
||||
query,
|
||||
queryConfig,
|
||||
source: source.links.self,
|
||||
type: QueryType.InfluxQL,
|
||||
}
|
||||
loadDE([queryDraft], timeRange)
|
||||
}
|
||||
}
|
||||
|
||||
private get activeScript(): string {
|
||||
const {script} = this.queryString
|
||||
if (script) {
|
||||
return script
|
||||
}
|
||||
|
||||
return this.props.script
|
||||
}
|
||||
const ConnectedDataExplorer = (props: PassedProps & WithRouterProps) => {
|
||||
return (
|
||||
<Subscribe to={[TimeMachineContainer]}>
|
||||
{(timeMachineContainer: TimeMachineContainer) => (
|
||||
<DataExplorer
|
||||
{...props}
|
||||
queryDrafts={timeMachineContainer.state.queryDrafts}
|
||||
timeRange={timeMachineContainer.state.timeRange}
|
||||
script={timeMachineContainer.state.script}
|
||||
onChangeScript={timeMachineContainer.handleChangeScript}
|
||||
onUpdateQueryDrafts={timeMachineContainer.handleUpdateQueryDrafts}
|
||||
/>
|
||||
)}
|
||||
</Subscribe>
|
||||
)
|
||||
}
|
||||
|
||||
const mstp = state => {
|
||||
|
@ -559,25 +472,7 @@ const mstp = state => {
|
|||
app: {
|
||||
persisted: {autoRefresh},
|
||||
},
|
||||
dataExplorer: {
|
||||
queryDrafts,
|
||||
timeRange,
|
||||
queryStatus,
|
||||
script,
|
||||
sourceLink,
|
||||
visType,
|
||||
thresholdsListType,
|
||||
thresholdsListColors,
|
||||
gaugeColors,
|
||||
lineColors,
|
||||
axes,
|
||||
tableOptions,
|
||||
timeFormat,
|
||||
decimalPlaces,
|
||||
fieldOptions,
|
||||
note,
|
||||
noteVisibility,
|
||||
},
|
||||
dataExplorer: {timeRange, queryStatus, sourceLink},
|
||||
dashboardUI: {dashboards},
|
||||
sources,
|
||||
services,
|
||||
|
@ -587,26 +482,12 @@ const mstp = state => {
|
|||
return {
|
||||
fluxLinks: links.flux,
|
||||
autoRefresh,
|
||||
queryDrafts,
|
||||
timeRange,
|
||||
dashboards,
|
||||
sources,
|
||||
services,
|
||||
queryStatus,
|
||||
script,
|
||||
sourceLink,
|
||||
visType,
|
||||
thresholdsListType,
|
||||
thresholdsListColors,
|
||||
gaugeColors,
|
||||
lineColors,
|
||||
axes,
|
||||
tableOptions,
|
||||
timeFormat,
|
||||
decimalPlaces,
|
||||
fieldOptions,
|
||||
note,
|
||||
noteVisibility,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -614,21 +495,16 @@ const mdtp = dispatch => {
|
|||
return {
|
||||
handleChooseAutoRefresh: bindActionCreators(setAutoRefresh, dispatch),
|
||||
errorThrownAction: bindActionCreators(errorThrown, dispatch),
|
||||
setTimeRange: bindActionCreators(updateEditorTimeRange, dispatch),
|
||||
writeLineProtocol: bindActionCreators(writeLineProtocolAsync, dispatch),
|
||||
queryConfigActions: bindActionCreators(queryConfigModifiers, dispatch),
|
||||
handleGetDashboards: bindActionCreators(getDashboardsAsync, dispatch),
|
||||
sendDashboardCell: bindActionCreators(sendDashboardCellAsync, dispatch),
|
||||
loadDE: bindActionCreators(loadDEAction, dispatch),
|
||||
updateQueryDrafts: bindActionCreators(updateQueryDraftsAction, dispatch),
|
||||
addQuery: bindActionCreators(addQueryAsync, dispatch),
|
||||
deleteQuery: bindActionCreators(deleteQueryAsync, dispatch),
|
||||
editQueryStatus: bindActionCreators(editQueryStatusAction, dispatch),
|
||||
updateScript: bindActionCreators(updateScriptAction, dispatch),
|
||||
fetchServicesAsync: bindActionCreators(fetchAllFluxServicesAsync, dispatch),
|
||||
notify: bindActionCreators(notifyAction, dispatch),
|
||||
updateSourceLink: bindActionCreators(updateSourceLinkAction, dispatch),
|
||||
}
|
||||
}
|
||||
|
||||
export default connect(mstp, mdtp)(withRouter(ManualRefresh(DataExplorer)))
|
||||
export default connect(mstp, mdtp)(
|
||||
withRouter(ManualRefresh(ConnectedDataExplorer))
|
||||
)
|
||||
|
|
|
@ -1,19 +1,33 @@
|
|||
import React, {PureComponent} from 'react'
|
||||
import {Provider} from 'unstated'
|
||||
|
||||
import DataExplorer from './DataExplorer'
|
||||
|
||||
import {Source} from 'src/types'
|
||||
import {TimeMachineContainer} from 'src/shared/utils/TimeMachineContainer'
|
||||
import {ErrorHandling} from 'src/shared/decorators/errors'
|
||||
|
||||
import {Source} from 'src/types'
|
||||
|
||||
interface Props {
|
||||
source: Source
|
||||
}
|
||||
|
||||
@ErrorHandling
|
||||
class DataExplorerPage extends PureComponent<Props> {
|
||||
private timeMachineContainer: TimeMachineContainer
|
||||
|
||||
constructor(props: Props) {
|
||||
super(props)
|
||||
|
||||
this.timeMachineContainer = new TimeMachineContainer()
|
||||
}
|
||||
|
||||
public render() {
|
||||
return (
|
||||
<div className="page">
|
||||
<DataExplorer source={this.props.source} />
|
||||
<Provider inject={[this.timeMachineContainer]}>
|
||||
<DataExplorer source={this.props.source} />
|
||||
</Provider>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
|
|
@ -1,198 +1,29 @@
|
|||
// libraries
|
||||
// Libraries
|
||||
import _ from 'lodash'
|
||||
import uuid from 'uuid'
|
||||
|
||||
// actions
|
||||
// Actions
|
||||
import {Action, ActionType} from 'src/data_explorer/actions/queries'
|
||||
|
||||
// utils
|
||||
import defaultQueryConfig from 'src/utils/defaultQueryConfig'
|
||||
|
||||
// constants
|
||||
import {timeRanges} from 'src/shared/data/timeRanges'
|
||||
import {editor} from 'src/flux/constants'
|
||||
import {
|
||||
DEFAULT_THRESHOLDS_LIST_COLORS,
|
||||
DEFAULT_GAUGE_COLORS,
|
||||
} from 'src/shared/constants/thresholds'
|
||||
import {DEFAULT_LINE_COLORS} from 'src/shared/constants/graphColorPalettes'
|
||||
import {DEFAULT_AXES} from 'src/dashboards/constants/cellEditor'
|
||||
import {
|
||||
DEFAULT_TABLE_OPTIONS,
|
||||
DEFAULT_TIME_FORMAT,
|
||||
DEFAULT_DECIMAL_PLACES,
|
||||
DEFAULT_FIELD_OPTIONS,
|
||||
} from 'src/dashboards/constants'
|
||||
|
||||
// types
|
||||
import {CellType} from 'src/types'
|
||||
// Types
|
||||
import {DEState} from 'src/types/dataExplorer'
|
||||
import {
|
||||
CellQuery,
|
||||
ThresholdType,
|
||||
NoteVisibility,
|
||||
QueryType,
|
||||
} from 'src/types/dashboards'
|
||||
|
||||
const {lower, upper} = timeRanges.find(tr => tr.lower === 'now() - 1h')
|
||||
|
||||
export const initialState: DEState = {
|
||||
queryDrafts: [],
|
||||
timeRange: {lower, upper},
|
||||
queryStatus: {queryID: null, status: null},
|
||||
script: editor.DEFAULT_SCRIPT,
|
||||
sourceLink: '',
|
||||
visType: CellType.Line,
|
||||
thresholdsListType: ThresholdType.Text,
|
||||
thresholdsListColors: DEFAULT_THRESHOLDS_LIST_COLORS,
|
||||
gaugeColors: DEFAULT_GAUGE_COLORS,
|
||||
lineColors: DEFAULT_LINE_COLORS,
|
||||
axes: DEFAULT_AXES,
|
||||
tableOptions: DEFAULT_TABLE_OPTIONS,
|
||||
timeFormat: DEFAULT_TIME_FORMAT,
|
||||
decimalPlaces: DEFAULT_DECIMAL_PLACES,
|
||||
fieldOptions: DEFAULT_FIELD_OPTIONS,
|
||||
note: '',
|
||||
noteVisibility: NoteVisibility.Default,
|
||||
queryStatus: {queryID: null, status: null},
|
||||
}
|
||||
|
||||
export default (state = initialState, action: Action): DEState => {
|
||||
switch (action.type) {
|
||||
case ActionType.LoadDE: {
|
||||
const {timeRange, queries} = action.payload
|
||||
|
||||
let queryDrafts: CellQuery[] = queries.map(q => {
|
||||
const id = _.get(q, 'queryConfig.id')
|
||||
return {...q, id}
|
||||
})
|
||||
|
||||
if (_.isEmpty(queryDrafts)) {
|
||||
const id = uuid.v4()
|
||||
const newQueryConfig = {
|
||||
...defaultQueryConfig({id}),
|
||||
}
|
||||
const newQueryDraft: CellQuery = {
|
||||
query: '',
|
||||
queryConfig: newQueryConfig,
|
||||
source: '',
|
||||
id,
|
||||
type: QueryType.InfluxQL,
|
||||
}
|
||||
queryDrafts = [newQueryDraft]
|
||||
}
|
||||
|
||||
return {
|
||||
...state,
|
||||
queryDrafts,
|
||||
timeRange,
|
||||
}
|
||||
}
|
||||
|
||||
case ActionType.UpdateQueryDrafts: {
|
||||
const {queryDrafts} = action.payload
|
||||
|
||||
return {...state, queryDrafts}
|
||||
}
|
||||
|
||||
case ActionType.UpdateEditorTimeRange: {
|
||||
const {timeRange} = action.payload
|
||||
|
||||
return {...state, timeRange}
|
||||
}
|
||||
|
||||
case ActionType.UpdateQueryStatus: {
|
||||
const {queryID, status} = action.payload
|
||||
const queryStatus = {queryID, status}
|
||||
|
||||
return {...state, queryStatus}
|
||||
}
|
||||
|
||||
case ActionType.UpdateScript: {
|
||||
const {script} = action.payload
|
||||
|
||||
return {...state, script}
|
||||
}
|
||||
|
||||
case ActionType.UpdateSourceLink: {
|
||||
const {sourceLink} = action.payload
|
||||
|
||||
return {...state, sourceLink}
|
||||
}
|
||||
|
||||
case ActionType.ChangeVisualizationType: {
|
||||
const {cellType} = action.payload
|
||||
case ActionType.EditQueryStatus: {
|
||||
const {queryID, status} = action.payload
|
||||
|
||||
return {...state, visType: cellType}
|
||||
}
|
||||
|
||||
case ActionType.UpdateThresholdsListColors: {
|
||||
const {thresholdsListColors} = action.payload
|
||||
|
||||
return {...state, thresholdsListColors}
|
||||
}
|
||||
|
||||
case ActionType.UpdateThresholdsListType: {
|
||||
const {thresholdsListType} = action.payload
|
||||
|
||||
const thresholdsListColors = state.thresholdsListColors.map(color => {
|
||||
return {...color, type: thresholdsListType}
|
||||
})
|
||||
|
||||
return {...state, thresholdsListColors, thresholdsListType}
|
||||
}
|
||||
|
||||
case ActionType.UpdateGaugeColors: {
|
||||
const {gaugeColors} = action.payload
|
||||
|
||||
return {...state, gaugeColors}
|
||||
}
|
||||
|
||||
case ActionType.UpdateAxes: {
|
||||
const {axes} = action.payload
|
||||
|
||||
return {...state, axes}
|
||||
}
|
||||
|
||||
case ActionType.UpdateTableOptions: {
|
||||
const {tableOptions} = action.payload
|
||||
|
||||
return {...state, tableOptions}
|
||||
}
|
||||
|
||||
case ActionType.ChangeTimeFormat: {
|
||||
const {timeFormat} = action.payload
|
||||
|
||||
return {...state, timeFormat}
|
||||
}
|
||||
|
||||
case ActionType.ChangeDecimalPlaces: {
|
||||
const {decimalPlaces} = action.payload
|
||||
|
||||
return {...state, decimalPlaces}
|
||||
}
|
||||
|
||||
case ActionType.UpdateFieldOptions: {
|
||||
const {fieldOptions} = action.payload
|
||||
|
||||
return {...state, fieldOptions}
|
||||
}
|
||||
|
||||
case ActionType.UpdateLineColors: {
|
||||
const {lineColors} = action.payload
|
||||
|
||||
return {...state, lineColors}
|
||||
}
|
||||
|
||||
case ActionType.UpdateNote: {
|
||||
const {note} = action.payload
|
||||
|
||||
return {...state, note}
|
||||
}
|
||||
|
||||
case ActionType.UpdateNoteVisibility: {
|
||||
const {noteVisibility} = action.payload
|
||||
|
||||
return {...state, noteVisibility}
|
||||
return {...state, queryStatus: {queryID, status}}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,183 +0,0 @@
|
|||
import _ from 'lodash'
|
||||
|
||||
import defaultQueryConfig from 'src/utils/defaultQueryConfig'
|
||||
import {QueryConfig} from 'src/types'
|
||||
import {Action} from 'src/data_explorer/actions/view'
|
||||
|
||||
import {
|
||||
fill,
|
||||
timeShift,
|
||||
chooseTag,
|
||||
groupByTag,
|
||||
removeFuncs,
|
||||
groupByTime,
|
||||
toggleField,
|
||||
editRawText,
|
||||
updateRawQuery,
|
||||
chooseNamespace,
|
||||
chooseMeasurement,
|
||||
addInitialField,
|
||||
applyFuncsToField,
|
||||
toggleTagAcceptance,
|
||||
} from 'src/utils/queryTransitions'
|
||||
|
||||
interface State {
|
||||
[queryID: string]: Readonly<QueryConfig>
|
||||
}
|
||||
|
||||
const queryConfigs = (state: State = {}, action: Action): State => {
|
||||
switch (action.type) {
|
||||
case 'DE_CHOOSE_NAMESPACE': {
|
||||
const {queryID, database, retentionPolicy} = action.payload
|
||||
const nextQueryConfig = chooseNamespace(state[queryID], {
|
||||
database,
|
||||
retentionPolicy,
|
||||
})
|
||||
|
||||
return {...state, [queryID]: {...nextQueryConfig, rawText: null}}
|
||||
}
|
||||
|
||||
case 'DE_CHOOSE_MEASUREMENT': {
|
||||
const {queryID, measurement} = action.payload
|
||||
|
||||
const nextQueryConfig = chooseMeasurement(state[queryID], measurement)
|
||||
|
||||
return {
|
||||
...state,
|
||||
[queryID]: {
|
||||
...nextQueryConfig,
|
||||
rawText: state[queryID].rawText,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// there is an additional reducer for this same action in the ui reducer
|
||||
case 'DE_ADD_QUERY': {
|
||||
const {queryID} = action.payload
|
||||
|
||||
return {
|
||||
...state,
|
||||
[queryID]: defaultQueryConfig({id: queryID}),
|
||||
}
|
||||
}
|
||||
|
||||
// there is an additional reducer for this same action in the ui reducer
|
||||
case 'DE_DELETE_QUERY': {
|
||||
const {queryID} = action.payload
|
||||
return _.omit(state, queryID)
|
||||
}
|
||||
|
||||
case 'DE_UPDATE_QUERY_CONFIG': {
|
||||
const {config} = action.payload
|
||||
return {...state, [config.id]: config}
|
||||
}
|
||||
|
||||
case 'DE_EDIT_RAW_TEXT': {
|
||||
const {queryID, rawText} = action.payload
|
||||
const nextQueryConfig = editRawText(state[queryID], rawText)
|
||||
|
||||
return {
|
||||
...state,
|
||||
[queryID]: nextQueryConfig,
|
||||
}
|
||||
}
|
||||
|
||||
case 'DE_GROUP_BY_TIME': {
|
||||
const {queryID, time} = action.payload
|
||||
const nextQueryConfig = groupByTime(state[queryID], time)
|
||||
|
||||
return {...state, [queryID]: nextQueryConfig}
|
||||
}
|
||||
|
||||
case 'DE_TOGGLE_TAG_ACCEPTANCE': {
|
||||
const {queryID} = action.payload
|
||||
const nextQueryConfig = toggleTagAcceptance(state[queryID])
|
||||
|
||||
return {...state, [queryID]: nextQueryConfig}
|
||||
}
|
||||
|
||||
case 'DE_TOGGLE_FIELD': {
|
||||
const {queryID, fieldFunc} = action.payload
|
||||
const nextQueryConfig = toggleField(state[queryID], fieldFunc)
|
||||
|
||||
return {...state, [queryID]: {...nextQueryConfig, rawText: null}}
|
||||
}
|
||||
|
||||
case 'DE_APPLY_FUNCS_TO_FIELD': {
|
||||
const {queryID, fieldFunc, groupBy} = action.payload
|
||||
const nextQueryConfig = applyFuncsToField(
|
||||
state[queryID],
|
||||
fieldFunc,
|
||||
groupBy
|
||||
)
|
||||
|
||||
return {...state, [queryID]: nextQueryConfig}
|
||||
}
|
||||
|
||||
case 'DE_CHOOSE_TAG': {
|
||||
const {queryID, tag} = action.payload
|
||||
const nextQueryConfig = chooseTag(state[queryID], tag)
|
||||
|
||||
return {...state, [queryID]: nextQueryConfig}
|
||||
}
|
||||
|
||||
case 'DE_GROUP_BY_TAG': {
|
||||
const {queryID, tagKey} = action.payload
|
||||
const nextQueryConfig = groupByTag(state[queryID], tagKey)
|
||||
return {...state, [queryID]: nextQueryConfig}
|
||||
}
|
||||
|
||||
case 'DE_FILL': {
|
||||
const {queryID, value} = action.payload
|
||||
const nextQueryConfig = fill(state[queryID], value)
|
||||
|
||||
return {
|
||||
...state,
|
||||
[queryID]: nextQueryConfig,
|
||||
}
|
||||
}
|
||||
|
||||
case 'DE_UPDATE_RAW_QUERY': {
|
||||
const {queryID, text} = action.payload
|
||||
const nextQueryConfig = updateRawQuery(state[queryID], text)
|
||||
return Object.assign({}, state, {
|
||||
[queryID]: nextQueryConfig,
|
||||
})
|
||||
}
|
||||
|
||||
case 'DE_EDIT_QUERY_STATUS': {
|
||||
const {queryID, status} = action.payload
|
||||
const nextState = {
|
||||
[queryID]: {...state[queryID], status},
|
||||
}
|
||||
|
||||
return {...state, ...nextState}
|
||||
}
|
||||
|
||||
case 'DE_REMOVE_FUNCS': {
|
||||
const {queryID, fields} = action.payload
|
||||
const nextQuery = removeFuncs(state[queryID], fields)
|
||||
|
||||
// fields with no functions cannot have a group by time
|
||||
return {...state, [queryID]: nextQuery}
|
||||
}
|
||||
|
||||
// Adding the first feild applies a groupBy time
|
||||
case 'DE_ADD_INITIAL_FIELD': {
|
||||
const {queryID, field, groupBy} = action.payload
|
||||
const nextQuery = addInitialField(state[queryID], field, groupBy)
|
||||
|
||||
return {...state, [queryID]: nextQuery}
|
||||
}
|
||||
|
||||
case 'DE_TIME_SHIFT': {
|
||||
const {queryID, shift} = action.payload
|
||||
const nextQuery = timeShift(state[queryID], shift)
|
||||
|
||||
return {...state, [queryID]: nextQuery}
|
||||
}
|
||||
}
|
||||
return state
|
||||
}
|
||||
|
||||
export default queryConfigs
|
|
@ -61,7 +61,6 @@ class ExpressionNode extends PureComponent<Props, State> {
|
|||
service,
|
||||
data,
|
||||
scriptUpToYield,
|
||||
visualizationOptions,
|
||||
source,
|
||||
timeRange,
|
||||
queries,
|
||||
|
@ -140,7 +139,6 @@ class ExpressionNode extends PureComponent<Props, State> {
|
|||
queries={queries}
|
||||
timeRange={timeRange}
|
||||
declarationID={declarationID}
|
||||
visualizationOptions={visualizationOptions}
|
||||
/>
|
||||
</Fragment>
|
||||
)
|
||||
|
|
|
@ -27,6 +27,7 @@ interface Props {
|
|||
handleSetHoverTime?: (hovertime: string) => void
|
||||
colors: ColorString[]
|
||||
editorLocation?: QueryUpdateState
|
||||
onUpdateFieldOptions?: (fieldOptions: FieldOption[]) => void
|
||||
}
|
||||
|
||||
interface State {
|
||||
|
@ -77,7 +78,9 @@ class TimeMachineTables extends PureComponent<Props, State> {
|
|||
decimalPlaces,
|
||||
editorLocation,
|
||||
handleSetHoverTime,
|
||||
onUpdateFieldOptions,
|
||||
} = this.props
|
||||
|
||||
return (
|
||||
<div className="time-machine-tables">
|
||||
{this.showSidebar && (
|
||||
|
@ -98,6 +101,7 @@ class TimeMachineTables extends PureComponent<Props, State> {
|
|||
decimalPlaces={decimalPlaces}
|
||||
editorLocation={editorLocation}
|
||||
handleSetHoverTime={handleSetHoverTime}
|
||||
onUpdateFieldOptions={onUpdateFieldOptions}
|
||||
/>
|
||||
)}
|
||||
{!this.hasResults && <NoResults />}
|
||||
|
|
|
@ -1,15 +1,39 @@
|
|||
import React, {PureComponent} from 'react'
|
||||
import _ from 'lodash'
|
||||
import {Subscribe} from 'unstated'
|
||||
|
||||
import {ErrorHandling} from 'src/shared/decorators/errors'
|
||||
import YieldNodeVis from 'src/flux/components/YieldNodeVis'
|
||||
import TimeSeries from 'src/shared/components/time_series/TimeSeries'
|
||||
import {TimeMachineContainer} from 'src/shared/utils/TimeMachineContainer'
|
||||
|
||||
import {FluxTable, Service, Source, TimeRange, Query} from 'src/types'
|
||||
import {FluxTable, Service, Source, TimeRange, Query, Axes} from 'src/types'
|
||||
import {Func} from 'src/types/flux'
|
||||
import {VisualizationOptions} from 'src/types/dataExplorer'
|
||||
|
||||
interface Props {
|
||||
import {
|
||||
FieldOption,
|
||||
DecimalPlaces,
|
||||
NoteVisibility,
|
||||
ThresholdType,
|
||||
TableOptions as TableOptionsInterface,
|
||||
} from 'src/types/dashboards'
|
||||
import {ColorNumber, ColorString} from 'src/types/colors'
|
||||
|
||||
interface ConnectedProps {
|
||||
axes: Axes | null
|
||||
tableOptions: TableOptionsInterface
|
||||
fieldOptions: FieldOption[]
|
||||
timeFormat: string
|
||||
decimalPlaces: DecimalPlaces
|
||||
note: string
|
||||
noteVisibility: NoteVisibility
|
||||
thresholdsListColors: ColorNumber[]
|
||||
thresholdsListType: ThresholdType
|
||||
gaugeColors: ColorNumber[]
|
||||
lineColors: ColorString[]
|
||||
}
|
||||
|
||||
interface PassedProps {
|
||||
service: Service
|
||||
source: Source
|
||||
timeRange: TimeRange
|
||||
|
@ -20,9 +44,10 @@ interface Props {
|
|||
declarationID?: string
|
||||
script: string
|
||||
queries: Query[]
|
||||
visualizationOptions: VisualizationOptions
|
||||
}
|
||||
|
||||
type Props = ConnectedProps & PassedProps
|
||||
|
||||
interface State {
|
||||
data: FluxTable[]
|
||||
}
|
||||
|
@ -31,12 +56,12 @@ interface State {
|
|||
class YieldFuncNode extends PureComponent<Props, State> {
|
||||
private timeSeries: React.RefObject<TimeSeries> = React.createRef()
|
||||
|
||||
public componentDidUpdate(prevProps) {
|
||||
public componentDidUpdate(prevProps: Props) {
|
||||
if (!this.timeSeries.current) {
|
||||
return
|
||||
}
|
||||
|
||||
if (this.haveVisOptionsChanged(prevProps.visualizationOptions)) {
|
||||
if (this.haveVisOptionsChanged(prevProps)) {
|
||||
this.timeSeries.current.forceUpdate()
|
||||
}
|
||||
}
|
||||
|
@ -44,11 +69,18 @@ class YieldFuncNode extends PureComponent<Props, State> {
|
|||
public render() {
|
||||
const {
|
||||
func,
|
||||
visualizationOptions,
|
||||
source,
|
||||
service,
|
||||
timeRange,
|
||||
queries,
|
||||
axes,
|
||||
tableOptions,
|
||||
fieldOptions,
|
||||
timeFormat,
|
||||
decimalPlaces,
|
||||
thresholdsListColors,
|
||||
gaugeColors,
|
||||
lineColors,
|
||||
} = this.props
|
||||
|
||||
const yieldName = _.get(func, 'args.0.value', 'result')
|
||||
|
@ -66,7 +98,14 @@ class YieldFuncNode extends PureComponent<Props, State> {
|
|||
<YieldNodeVis
|
||||
data={timeSeriesFlux}
|
||||
yieldName={yieldName}
|
||||
visualizationOptions={visualizationOptions}
|
||||
axes={axes}
|
||||
tableOptions={tableOptions}
|
||||
fieldOptions={fieldOptions}
|
||||
timeFormat={timeFormat}
|
||||
decimalPlaces={decimalPlaces}
|
||||
thresholdsListColors={thresholdsListColors}
|
||||
gaugeColors={gaugeColors}
|
||||
lineColors={lineColors}
|
||||
/>
|
||||
)}
|
||||
</TimeSeries>
|
||||
|
@ -74,22 +113,46 @@ class YieldFuncNode extends PureComponent<Props, State> {
|
|||
)
|
||||
}
|
||||
|
||||
private haveVisOptionsChanged(
|
||||
visualizationOptions: VisualizationOptions
|
||||
): boolean {
|
||||
private haveVisOptionsChanged(prevProps: Props): boolean {
|
||||
const visProps: string[] = [
|
||||
'axes',
|
||||
'colors',
|
||||
'lineColors',
|
||||
'gaugeColors',
|
||||
'thresholdsListColors',
|
||||
'thresholdsListType',
|
||||
'tableOptions',
|
||||
'fieldOptions',
|
||||
'decimalPlaces',
|
||||
'timeFormat',
|
||||
]
|
||||
|
||||
const prevVisValues = _.pick(visualizationOptions, visProps)
|
||||
const curVisValues = _.pick(this.props.visualizationOptions, visProps)
|
||||
const prevVisValues = _.pick(prevProps, visProps)
|
||||
const curVisValues = _.pick(this.props, visProps)
|
||||
return !_.isEqual(prevVisValues, curVisValues)
|
||||
}
|
||||
}
|
||||
|
||||
export default YieldFuncNode
|
||||
const ConnectedYieldFuncNode = (props: PassedProps) => {
|
||||
return (
|
||||
<Subscribe to={[TimeMachineContainer]}>
|
||||
{(timeMachineContainer: TimeMachineContainer) => (
|
||||
<YieldFuncNode
|
||||
{...props}
|
||||
axes={timeMachineContainer.state.axes}
|
||||
tableOptions={timeMachineContainer.state.tableOptions}
|
||||
fieldOptions={timeMachineContainer.state.fieldOptions}
|
||||
timeFormat={timeMachineContainer.state.timeFormat}
|
||||
decimalPlaces={timeMachineContainer.state.decimalPlaces}
|
||||
note={timeMachineContainer.state.note}
|
||||
noteVisibility={timeMachineContainer.state.noteVisibility}
|
||||
thresholdsListColors={timeMachineContainer.state.thresholdsListColors}
|
||||
thresholdsListType={timeMachineContainer.state.thresholdsListType}
|
||||
gaugeColors={timeMachineContainer.state.gaugeColors}
|
||||
lineColors={timeMachineContainer.state.lineColors}
|
||||
/>
|
||||
)}
|
||||
</Subscribe>
|
||||
)
|
||||
}
|
||||
|
||||
export default ConnectedYieldFuncNode
|
||||
|
|
|
@ -7,15 +7,28 @@ import {Radio} from 'src/reusable_ui'
|
|||
import {ErrorHandling} from 'src/shared/decorators/errors'
|
||||
|
||||
import {FluxTable} from 'src/types'
|
||||
import {VisualizationOptions} from 'src/types/dataExplorer'
|
||||
import {DataType} from 'src/shared/constants'
|
||||
import {getCellTypeColors} from 'src/dashboards/constants/cellEditor'
|
||||
import {CellType} from 'src/types/dashboards'
|
||||
import {
|
||||
CellType,
|
||||
Axes,
|
||||
TableOptions,
|
||||
FieldOption,
|
||||
DecimalPlaces,
|
||||
} from 'src/types/dashboards'
|
||||
import {ColorNumber, ColorString} from 'src/types/colors'
|
||||
|
||||
interface Props {
|
||||
data: FluxTable[]
|
||||
yieldName: string
|
||||
visualizationOptions: VisualizationOptions
|
||||
axes: Axes | null
|
||||
tableOptions: TableOptions
|
||||
fieldOptions: FieldOption[]
|
||||
timeFormat: string
|
||||
decimalPlaces: DecimalPlaces
|
||||
thresholdsListColors: ColorNumber[]
|
||||
gaugeColors: ColorNumber[]
|
||||
lineColors: ColorString[]
|
||||
}
|
||||
|
||||
enum VisType {
|
||||
|
@ -71,9 +84,8 @@ class YieldNodeVis extends PureComponent<Props, State> {
|
|||
|
||||
private get vis(): JSX.Element {
|
||||
const {visType} = this.state
|
||||
const {data, visualizationOptions} = this.props
|
||||
|
||||
const {
|
||||
data,
|
||||
tableOptions,
|
||||
timeFormat,
|
||||
decimalPlaces,
|
||||
|
@ -81,7 +93,7 @@ class YieldNodeVis extends PureComponent<Props, State> {
|
|||
thresholdsListColors,
|
||||
gaugeColors,
|
||||
lineColors,
|
||||
} = visualizationOptions
|
||||
} = this.props
|
||||
|
||||
if (visType === VisType.Line) {
|
||||
return (
|
||||
|
|
|
@ -5,23 +5,8 @@ import {
|
|||
notifyLoadLocalSettingsFailed,
|
||||
} from 'src/shared/copy/notifications'
|
||||
|
||||
import {
|
||||
DEFAULT_THRESHOLDS_LIST_COLORS,
|
||||
DEFAULT_GAUGE_COLORS,
|
||||
} from 'src/shared/constants/thresholds'
|
||||
import {DEFAULT_LINE_COLORS} from 'src/shared/constants/graphColorPalettes'
|
||||
import {DEFAULT_AXES} from 'src/dashboards/constants/cellEditor'
|
||||
import {
|
||||
DEFAULT_TABLE_OPTIONS,
|
||||
DEFAULT_TIME_FORMAT,
|
||||
DEFAULT_DECIMAL_PLACES,
|
||||
DEFAULT_FIELD_OPTIONS,
|
||||
} from 'src/dashboards/constants'
|
||||
import {editor} from 'src/flux/constants'
|
||||
import {defaultTableData} from 'src/logs/constants'
|
||||
|
||||
import {CellType} from 'src/types'
|
||||
import {ThresholdType, NoteVisibility} from 'src/types/dashboards'
|
||||
import {LocalStorage} from 'src/types/localStorage'
|
||||
|
||||
const VERSION = process.env.npm_package_version
|
||||
|
@ -61,7 +46,6 @@ export const loadLocalStorage = (errorsQueue: any[]): LocalStorage | {} => {
|
|||
export const saveToLocalStorage = ({
|
||||
app: {persisted},
|
||||
timeRange,
|
||||
dataExplorer,
|
||||
dashTimeV1: {ranges},
|
||||
logs,
|
||||
script,
|
||||
|
@ -80,52 +64,25 @@ export const saveToLocalStorage = ({
|
|||
window.localStorage.setItem(
|
||||
'state',
|
||||
JSON.stringify(
|
||||
_.omit(
|
||||
{
|
||||
...appPersisted,
|
||||
VERSION,
|
||||
GIT_SHA,
|
||||
timeRange,
|
||||
dashTimeV1,
|
||||
dataExplorer: {
|
||||
...dataExplorer,
|
||||
queryDrafts: dataExplorer.queryDrafts || [],
|
||||
timeRange: dataExplorer.timeRange || {},
|
||||
sourceLink: dataExplorer.sourceLink || '',
|
||||
queryStatus: dataExplorer.queryStatus || {},
|
||||
script: dataExplorer.script || editor.DEFAULT_SCRIPT,
|
||||
visType: dataExplorer.visType || CellType.Line,
|
||||
thresholdsListType:
|
||||
dataExplorer.thresholdsListType || ThresholdType.Text,
|
||||
thresholdsListColors:
|
||||
dataExplorer.thresholdsListColors ||
|
||||
DEFAULT_THRESHOLDS_LIST_COLORS,
|
||||
gaugeColors: dataExplorer.gaugeColors || DEFAULT_GAUGE_COLORS,
|
||||
lineColors: dataExplorer.lineColors || DEFAULT_LINE_COLORS,
|
||||
axes: dataExplorer.axes || DEFAULT_AXES,
|
||||
tableOptions: dataExplorer.tableOptions || DEFAULT_TABLE_OPTIONS,
|
||||
timeFormat: dataExplorer.timeFormat || DEFAULT_TIME_FORMAT,
|
||||
decimalPlaces:
|
||||
dataExplorer.decimalPlaces || DEFAULT_DECIMAL_PLACES,
|
||||
fieldOptions: dataExplorer.fieldOptions || DEFAULT_FIELD_OPTIONS,
|
||||
noteVisibility:
|
||||
dataExplorer.noteVisibility || NoteVisibility.Default,
|
||||
},
|
||||
script,
|
||||
logs: {
|
||||
...minimalLogs,
|
||||
histogramData: [],
|
||||
tableData: {},
|
||||
queryCount: 0,
|
||||
tableInfiniteData: {
|
||||
forward: defaultTableData,
|
||||
backward: defaultTableData,
|
||||
},
|
||||
tableTime: minimalLogs.tableTime || {},
|
||||
_.omit({
|
||||
...appPersisted,
|
||||
VERSION,
|
||||
GIT_SHA,
|
||||
timeRange,
|
||||
dashTimeV1,
|
||||
script,
|
||||
logs: {
|
||||
...minimalLogs,
|
||||
histogramData: [],
|
||||
tableData: {},
|
||||
queryCount: 0,
|
||||
tableInfiniteData: {
|
||||
forward: defaultTableData,
|
||||
backward: defaultTableData,
|
||||
},
|
||||
tableTime: minimalLogs.tableTime || {},
|
||||
},
|
||||
'dataExplorerQueryConfigs'
|
||||
)
|
||||
})
|
||||
)
|
||||
)
|
||||
} catch (err) {
|
||||
|
|
|
@ -1,541 +1,4 @@
|
|||
// Libraries
|
||||
import uuid from 'uuid'
|
||||
|
||||
// Utils
|
||||
import {
|
||||
fill,
|
||||
timeShift,
|
||||
chooseTag,
|
||||
groupByTag,
|
||||
removeFuncs,
|
||||
groupByTime,
|
||||
toggleField,
|
||||
chooseNamespace,
|
||||
chooseMeasurement,
|
||||
addInitialField,
|
||||
applyFuncsToField,
|
||||
toggleTagAcceptance,
|
||||
} from 'src/utils/queryTransitions'
|
||||
import {getDeep} from 'src/utils/wrappers'
|
||||
import {getTimeRange} from 'src/dashboards/utils/cellGetters'
|
||||
import {buildQuery} from 'src/utils/influxql'
|
||||
import defaultQueryConfig from 'src/utils/defaultQueryConfig'
|
||||
|
||||
// Constants
|
||||
import {TYPE_QUERY_CONFIG} from 'src/dashboards/constants'
|
||||
|
||||
// Types
|
||||
import {
|
||||
Status,
|
||||
Field,
|
||||
GroupBy,
|
||||
Tag,
|
||||
TimeShift,
|
||||
ApplyFuncsToFieldArgs,
|
||||
CellQuery,
|
||||
TimeRange,
|
||||
QueryType,
|
||||
} from 'src/types'
|
||||
import {
|
||||
State as CEOState,
|
||||
ActionType as CEOActionType,
|
||||
} from 'src/dashboards/actions/cellEditorOverlay'
|
||||
import {ActionType as DashboardActionType} from 'src/dashboards/actions'
|
||||
import {
|
||||
State as DEState,
|
||||
ActionType as DEActionType,
|
||||
} from 'src/data_explorer/actions/queries'
|
||||
|
||||
type State = CEOState & DEState
|
||||
type GetState = () => State
|
||||
|
||||
export enum QueryUpdateState {
|
||||
CEO = 'cellEditorOverlay',
|
||||
DE = 'dataExplorer',
|
||||
}
|
||||
|
||||
interface UpdateQueryDraftsAction {
|
||||
type: CEOActionType.UpdateQueryDrafts | DEActionType.UpdateQueryDrafts
|
||||
payload: {queryDrafts: CellQuery[]}
|
||||
}
|
||||
|
||||
interface UpdateEditorTimeRangeAction {
|
||||
type: CEOActionType.UpdateEditorTimeRange | DEActionType.UpdateEditorTimeRange
|
||||
payload: {timeRange: TimeRange}
|
||||
}
|
||||
|
||||
interface UpdateQueryStatusAction {
|
||||
type: DashboardActionType.EditCellQueryStatus | DEActionType.UpdateQueryStatus
|
||||
payload: {queryID: string; status: Status}
|
||||
}
|
||||
|
||||
interface UpdateScriptAction {
|
||||
type: CEOActionType.UpdateScript | DEActionType.UpdateScript
|
||||
payload: {script: string}
|
||||
}
|
||||
|
||||
export const updateQueryDrafts = (
|
||||
queryDrafts: CellQuery[],
|
||||
stateToUpdate: QueryUpdateState
|
||||
): UpdateQueryDraftsAction => {
|
||||
const type =
|
||||
stateToUpdate === QueryUpdateState.CEO
|
||||
? CEOActionType.UpdateQueryDrafts
|
||||
: DEActionType.UpdateQueryDrafts
|
||||
return {
|
||||
type,
|
||||
payload: {
|
||||
queryDrafts,
|
||||
},
|
||||
} as UpdateQueryDraftsAction
|
||||
}
|
||||
|
||||
export const updateEditorTimeRange = (
|
||||
timeRange: TimeRange,
|
||||
stateToUpdate: QueryUpdateState
|
||||
) => {
|
||||
const type =
|
||||
stateToUpdate === QueryUpdateState.CEO
|
||||
? CEOActionType.UpdateEditorTimeRange
|
||||
: DEActionType.UpdateEditorTimeRange
|
||||
return {
|
||||
type,
|
||||
payload: {
|
||||
timeRange,
|
||||
},
|
||||
} as UpdateEditorTimeRangeAction
|
||||
}
|
||||
|
||||
export const updateQueryStatus = (
|
||||
queryID,
|
||||
status,
|
||||
stateToUpdate: QueryUpdateState
|
||||
) => {
|
||||
const type =
|
||||
stateToUpdate === QueryUpdateState.CEO
|
||||
? DashboardActionType.EditCellQueryStatus
|
||||
: DEActionType.UpdateQueryStatus
|
||||
|
||||
return {
|
||||
type,
|
||||
payload: {
|
||||
queryID,
|
||||
status,
|
||||
},
|
||||
} as UpdateQueryStatusAction
|
||||
}
|
||||
|
||||
export const updateScript = (
|
||||
script: string,
|
||||
stateToUpdate: QueryUpdateState
|
||||
) => {
|
||||
const type =
|
||||
stateToUpdate === QueryUpdateState.CEO
|
||||
? CEOActionType.UpdateScript
|
||||
: DEActionType.UpdateScript
|
||||
|
||||
return {
|
||||
type,
|
||||
payload: {
|
||||
script,
|
||||
},
|
||||
} as UpdateScriptAction
|
||||
}
|
||||
|
||||
export const toggleFieldAsync = (
|
||||
queryID: string,
|
||||
stateToUpdate: QueryUpdateState,
|
||||
fieldFunc: Field
|
||||
) => async (dispatch, getState: GetState) => {
|
||||
const queryDrafts = getDeep(getState(), `${stateToUpdate}.queryDrafts`, [])
|
||||
|
||||
const updatedQueryDrafts = queryDrafts.map(query => {
|
||||
if (query.id === queryID) {
|
||||
const nextQueryConfig = {
|
||||
...toggleField(query.queryConfig, fieldFunc),
|
||||
rawText: null,
|
||||
}
|
||||
|
||||
return {
|
||||
...query,
|
||||
query: buildQuery(
|
||||
TYPE_QUERY_CONFIG,
|
||||
getTimeRange(nextQueryConfig),
|
||||
nextQueryConfig
|
||||
),
|
||||
queryConfig: nextQueryConfig,
|
||||
}
|
||||
}
|
||||
return query
|
||||
})
|
||||
dispatch(updateQueryDrafts(updatedQueryDrafts, stateToUpdate))
|
||||
}
|
||||
|
||||
export const groupByTimeAsync = (
|
||||
queryID: string,
|
||||
stateToUpdate: QueryUpdateState,
|
||||
time: string
|
||||
) => (dispatch, getState: GetState) => {
|
||||
const queryDrafts = getDeep(getState(), `${stateToUpdate}.queryDrafts`, [])
|
||||
|
||||
const updatedQueryDrafts = queryDrafts.map(query => {
|
||||
if (query.id === queryID) {
|
||||
const nextQueryConfig = groupByTime(query.queryConfig, time)
|
||||
|
||||
return {
|
||||
...query,
|
||||
query: buildQuery(
|
||||
TYPE_QUERY_CONFIG,
|
||||
getTimeRange(nextQueryConfig),
|
||||
nextQueryConfig
|
||||
),
|
||||
queryConfig: nextQueryConfig,
|
||||
}
|
||||
}
|
||||
return query
|
||||
})
|
||||
dispatch(updateQueryDrafts(updatedQueryDrafts, stateToUpdate))
|
||||
}
|
||||
|
||||
export const fillAsync = (
|
||||
queryID: string,
|
||||
stateToUpdate: QueryUpdateState,
|
||||
value: string
|
||||
) => (dispatch, getState: GetState) => {
|
||||
const queryDrafts = getDeep(getState(), `${stateToUpdate}.queryDrafts`, [])
|
||||
|
||||
const updatedQueryDrafts = queryDrafts.map(query => {
|
||||
if (query.id === queryID) {
|
||||
const nextQueryConfig = fill(query.queryConfig, value)
|
||||
|
||||
return {
|
||||
...query,
|
||||
query: buildQuery(
|
||||
TYPE_QUERY_CONFIG,
|
||||
getTimeRange(nextQueryConfig),
|
||||
nextQueryConfig
|
||||
),
|
||||
queryConfig: nextQueryConfig,
|
||||
}
|
||||
}
|
||||
return query
|
||||
})
|
||||
dispatch(updateQueryDrafts(updatedQueryDrafts, stateToUpdate))
|
||||
}
|
||||
|
||||
export const removeFuncsAsync = (
|
||||
queryID: string,
|
||||
stateToUpdate: QueryUpdateState,
|
||||
fields: Field[]
|
||||
) => (dispatch, getState: GetState) => {
|
||||
const queryDrafts = getDeep(getState(), `${stateToUpdate}.queryDrafts`, [])
|
||||
|
||||
const updatedQueryDrafts = queryDrafts.map(query => {
|
||||
if (query.id === queryID) {
|
||||
const nextQueryConfig = removeFuncs(query.queryConfig, fields)
|
||||
|
||||
return {
|
||||
...query,
|
||||
query: buildQuery(
|
||||
TYPE_QUERY_CONFIG,
|
||||
getTimeRange(nextQueryConfig),
|
||||
nextQueryConfig
|
||||
),
|
||||
queryConfig: nextQueryConfig,
|
||||
}
|
||||
}
|
||||
return query
|
||||
})
|
||||
dispatch(updateQueryDrafts(updatedQueryDrafts, stateToUpdate))
|
||||
}
|
||||
|
||||
export const applyFuncsToFieldAsync = (
|
||||
queryID: string,
|
||||
stateToUpdate: QueryUpdateState,
|
||||
fieldFunc: ApplyFuncsToFieldArgs,
|
||||
groupBy?: GroupBy
|
||||
) => (dispatch, getState: GetState) => {
|
||||
const queryDrafts = getDeep(getState(), `${stateToUpdate}.queryDrafts`, [])
|
||||
|
||||
const updatedQueryDrafts = queryDrafts.map(query => {
|
||||
if (query.id === queryID) {
|
||||
const nextQueryConfig = applyFuncsToField(
|
||||
query.queryConfig,
|
||||
fieldFunc,
|
||||
groupBy
|
||||
)
|
||||
|
||||
return {
|
||||
...query,
|
||||
query: buildQuery(
|
||||
TYPE_QUERY_CONFIG,
|
||||
getTimeRange(nextQueryConfig),
|
||||
nextQueryConfig
|
||||
),
|
||||
queryConfig: nextQueryConfig,
|
||||
}
|
||||
}
|
||||
return query
|
||||
})
|
||||
dispatch(updateQueryDrafts(updatedQueryDrafts, stateToUpdate))
|
||||
}
|
||||
|
||||
export const chooseTagAsync = (
|
||||
queryID: string,
|
||||
stateToUpdate: QueryUpdateState,
|
||||
tag: Tag
|
||||
) => (dispatch, getState: GetState) => {
|
||||
const queryDrafts = getDeep(getState(), `${stateToUpdate}.queryDrafts`, [])
|
||||
|
||||
const updatedQueryDrafts = queryDrafts.map(query => {
|
||||
if (query.id === queryID) {
|
||||
const nextQueryConfig = chooseTag(query.queryConfig, tag)
|
||||
|
||||
return {
|
||||
...query,
|
||||
query: buildQuery(
|
||||
TYPE_QUERY_CONFIG,
|
||||
getTimeRange(nextQueryConfig),
|
||||
nextQueryConfig
|
||||
),
|
||||
queryConfig: nextQueryConfig,
|
||||
}
|
||||
}
|
||||
return query
|
||||
})
|
||||
dispatch(updateQueryDrafts(updatedQueryDrafts, stateToUpdate))
|
||||
}
|
||||
|
||||
interface DBRP {
|
||||
database: string
|
||||
retentionPolicy: string
|
||||
}
|
||||
|
||||
export const chooseNamespaceAsync = (
|
||||
queryID: string,
|
||||
stateToUpdate: QueryUpdateState,
|
||||
{database, retentionPolicy}: DBRP
|
||||
) => async (dispatch, getState: GetState) => {
|
||||
const queryDrafts = getDeep(getState(), `${stateToUpdate}.queryDrafts`, [])
|
||||
|
||||
const updatedQueryDrafts = queryDrafts.map(query => {
|
||||
if (query.id === queryID) {
|
||||
const nextQueryConfig = chooseNamespace(query.queryConfig, {
|
||||
database,
|
||||
retentionPolicy,
|
||||
})
|
||||
return {
|
||||
...query,
|
||||
query: buildQuery(
|
||||
TYPE_QUERY_CONFIG,
|
||||
getTimeRange(nextQueryConfig),
|
||||
nextQueryConfig
|
||||
),
|
||||
queryConfig: nextQueryConfig,
|
||||
}
|
||||
}
|
||||
return query
|
||||
})
|
||||
dispatch(updateQueryDrafts(updatedQueryDrafts, stateToUpdate))
|
||||
}
|
||||
|
||||
export const chooseMeasurementAsync = (
|
||||
queryID: string,
|
||||
stateToUpdate: QueryUpdateState,
|
||||
measurement: string
|
||||
) => async (dispatch, getState: GetState) => {
|
||||
const queryDrafts = getDeep(getState(), `${stateToUpdate}.queryDrafts`, [])
|
||||
|
||||
const updatedQueryDrafts = queryDrafts.map(query => {
|
||||
if (query.id === queryID) {
|
||||
const nextQueryConfig = {
|
||||
...chooseMeasurement(query.queryConfig, measurement),
|
||||
rawText: getDeep<string>(query, 'queryConfig.rawText', ''),
|
||||
}
|
||||
return {
|
||||
...query,
|
||||
query: buildQuery(
|
||||
TYPE_QUERY_CONFIG,
|
||||
getTimeRange(nextQueryConfig),
|
||||
nextQueryConfig
|
||||
),
|
||||
queryConfig: nextQueryConfig,
|
||||
}
|
||||
}
|
||||
return query
|
||||
})
|
||||
dispatch(updateQueryDrafts(updatedQueryDrafts, stateToUpdate))
|
||||
}
|
||||
|
||||
export const groupByTagAsync = (
|
||||
queryID: string,
|
||||
stateToUpdate: QueryUpdateState,
|
||||
tagKey: string
|
||||
) => async (dispatch, getState: GetState) => {
|
||||
const queryDrafts = getDeep(getState(), `${stateToUpdate}.queryDrafts`, [])
|
||||
|
||||
const updatedQueryDrafts = queryDrafts.map(query => {
|
||||
if (query.id === queryID) {
|
||||
const nextQueryConfig = groupByTag(query.queryConfig, tagKey)
|
||||
return {
|
||||
...query,
|
||||
query: buildQuery(
|
||||
TYPE_QUERY_CONFIG,
|
||||
getTimeRange(nextQueryConfig),
|
||||
nextQueryConfig
|
||||
),
|
||||
queryConfig: nextQueryConfig,
|
||||
}
|
||||
}
|
||||
return query
|
||||
})
|
||||
dispatch(updateQueryDrafts(updatedQueryDrafts, stateToUpdate))
|
||||
}
|
||||
|
||||
export const toggleTagAcceptanceAsync = (
|
||||
queryID: string,
|
||||
stateToUpdate: QueryUpdateState
|
||||
) => async (dispatch, getState: GetState) => {
|
||||
const queryDrafts = getDeep(getState(), `${stateToUpdate}.queryDrafts`, [])
|
||||
|
||||
const updatedQueryDrafts = queryDrafts.map(query => {
|
||||
if (query.id === queryID) {
|
||||
const nextQueryConfig = toggleTagAcceptance(query.queryConfig)
|
||||
return {
|
||||
...query,
|
||||
query: buildQuery(
|
||||
TYPE_QUERY_CONFIG,
|
||||
getTimeRange(nextQueryConfig),
|
||||
nextQueryConfig
|
||||
),
|
||||
queryConfig: nextQueryConfig,
|
||||
}
|
||||
}
|
||||
return query
|
||||
})
|
||||
dispatch(updateQueryDrafts(updatedQueryDrafts, stateToUpdate))
|
||||
}
|
||||
|
||||
export const addInitialFieldAsync = (
|
||||
queryID: string,
|
||||
stateToUpdate: QueryUpdateState,
|
||||
field: Field,
|
||||
groupBy: GroupBy
|
||||
) => async (dispatch, getState: GetState) => {
|
||||
const queryDrafts = getDeep(getState(), `${stateToUpdate}.queryDrafts`, [])
|
||||
|
||||
const updatedQueryDrafts = queryDrafts.map(query => {
|
||||
if (query.id === queryID) {
|
||||
const nextQueryConfig = addInitialField(query.queryConfig, field, groupBy)
|
||||
return {
|
||||
...query,
|
||||
query: buildQuery(
|
||||
TYPE_QUERY_CONFIG,
|
||||
getTimeRange(nextQueryConfig),
|
||||
nextQueryConfig
|
||||
),
|
||||
queryConfig: nextQueryConfig,
|
||||
}
|
||||
}
|
||||
return query
|
||||
})
|
||||
dispatch(updateQueryDrafts(updatedQueryDrafts, stateToUpdate))
|
||||
}
|
||||
|
||||
export const editQueryStatus = (
|
||||
queryID: string,
|
||||
stateToUpdate: QueryUpdateState,
|
||||
status: Status
|
||||
) => async (dispatch, getState: GetState) => {
|
||||
const queryDrafts = getDeep(getState(), `${stateToUpdate}.queryDrafts`, [])
|
||||
|
||||
const updatedQueryDrafts = queryDrafts.map(query => {
|
||||
if (query.id === queryID) {
|
||||
const nextQueryConfig = {...query.queryConfig, status}
|
||||
return {
|
||||
...query,
|
||||
query: buildQuery(
|
||||
TYPE_QUERY_CONFIG,
|
||||
getTimeRange(nextQueryConfig),
|
||||
nextQueryConfig
|
||||
),
|
||||
queryConfig: nextQueryConfig,
|
||||
}
|
||||
}
|
||||
return query
|
||||
})
|
||||
dispatch(updateQueryDrafts(updatedQueryDrafts, stateToUpdate))
|
||||
}
|
||||
|
||||
export const timeShiftAsync = (
|
||||
queryID: string,
|
||||
stateToUpdate: QueryUpdateState,
|
||||
shift: TimeShift
|
||||
) => async (dispatch, getState: GetState) => {
|
||||
const queryDrafts = getDeep(getState(), `${stateToUpdate}.queryDrafts`, [])
|
||||
|
||||
const updatedQueryDrafts = queryDrafts.map(query => {
|
||||
if (query.id === queryID) {
|
||||
const nextQueryConfig = timeShift(query.queryConfig, shift)
|
||||
return {
|
||||
...query,
|
||||
query: buildQuery(
|
||||
TYPE_QUERY_CONFIG,
|
||||
getTimeRange(nextQueryConfig),
|
||||
nextQueryConfig
|
||||
),
|
||||
queryConfig: nextQueryConfig,
|
||||
}
|
||||
}
|
||||
return query
|
||||
})
|
||||
dispatch(updateQueryDrafts(updatedQueryDrafts, stateToUpdate))
|
||||
}
|
||||
|
||||
export type QueryConfigActions = typeof queryConfigActions & {
|
||||
editRawTextAsync?: (text: string) => Promise<void>
|
||||
}
|
||||
|
||||
export const addQueryAsync = (stateToUpdate: QueryUpdateState) => async (
|
||||
dispatch,
|
||||
getState: GetState
|
||||
) => {
|
||||
const queryDrafts = getDeep(getState(), `${stateToUpdate}.queryDrafts`, [])
|
||||
|
||||
const queryID = uuid.v4()
|
||||
|
||||
const newQueryDraft: CellQuery = {
|
||||
query: '',
|
||||
queryConfig: defaultQueryConfig({id: queryID}),
|
||||
source: '',
|
||||
id: queryID,
|
||||
type: QueryType.InfluxQL,
|
||||
}
|
||||
const updatedQueryDrafts = [...queryDrafts, newQueryDraft]
|
||||
dispatch(updateQueryDrafts(updatedQueryDrafts, stateToUpdate))
|
||||
}
|
||||
|
||||
export const deleteQueryAsync = (
|
||||
queryID: string,
|
||||
stateToUpdate: QueryUpdateState
|
||||
) => async (dispatch, getState: GetState) => {
|
||||
const queryDrafts = getDeep(getState(), `${stateToUpdate}.queryDrafts`, [])
|
||||
|
||||
const updatedQueryDrafts = queryDrafts.filter(query => query.id !== queryID)
|
||||
dispatch(updateQueryDrafts(updatedQueryDrafts, stateToUpdate))
|
||||
}
|
||||
|
||||
export const queryConfigActions = {
|
||||
fill: fillAsync,
|
||||
timeShift: timeShiftAsync,
|
||||
chooseTag: chooseTagAsync,
|
||||
groupByTag: groupByTagAsync,
|
||||
groupByTime: groupByTimeAsync,
|
||||
toggleField: toggleFieldAsync,
|
||||
removeFuncs: removeFuncsAsync,
|
||||
addInitialField: addInitialFieldAsync,
|
||||
applyFuncsToField: applyFuncsToFieldAsync,
|
||||
toggleTagAcceptance: toggleTagAcceptanceAsync,
|
||||
chooseNamespace: chooseNamespaceAsync,
|
||||
chooseMeasurement: chooseMeasurementAsync,
|
||||
}
|
||||
|
|
|
@ -1,297 +1,18 @@
|
|||
// Constants
|
||||
import {QueryUpdateState} from 'src/shared/actions/queries'
|
||||
|
||||
// Types
|
||||
import {ActionType as CEOActionType} from 'src/dashboards/actions/cellEditorOverlay'
|
||||
import {ActionType as DEActionType} from 'src/data_explorer/actions/queries'
|
||||
|
||||
import {ColorNumber, ColorString} from 'src/types/colors'
|
||||
import {
|
||||
DecimalPlaces,
|
||||
FieldOption,
|
||||
Axes,
|
||||
CellType,
|
||||
ThresholdType,
|
||||
TableOptions,
|
||||
NoteVisibility,
|
||||
} from 'src/types/dashboards'
|
||||
|
||||
export interface ChangeVisualizationTypeAction {
|
||||
type: CEOActionType.ChangeCellType | DEActionType.ChangeVisualizationType
|
||||
payload: {
|
||||
cellType: CellType
|
||||
}
|
||||
}
|
||||
|
||||
export interface UpdateThresholdsListColorsAction {
|
||||
type:
|
||||
| CEOActionType.UpdateThresholdsListColors
|
||||
| DEActionType.UpdateThresholdsListColors
|
||||
payload: {
|
||||
thresholdsListColors: ColorNumber[]
|
||||
}
|
||||
}
|
||||
|
||||
export interface UpdateThresholdsListTypeAction {
|
||||
type:
|
||||
| CEOActionType.UpdateThresholdsListType
|
||||
| DEActionType.UpdateThresholdsListType
|
||||
payload: {
|
||||
thresholdsListType: ThresholdType
|
||||
}
|
||||
}
|
||||
|
||||
export interface UpdateGaugeColorsAction {
|
||||
type: CEOActionType.UpdateGaugeColors | DEActionType.UpdateGaugeColors
|
||||
payload: {
|
||||
gaugeColors: ColorNumber[]
|
||||
}
|
||||
}
|
||||
|
||||
export interface UpdateAxesAction {
|
||||
type: CEOActionType.UpdateAxes | DEActionType.UpdateAxes
|
||||
payload: {
|
||||
axes: Axes
|
||||
}
|
||||
}
|
||||
|
||||
export interface UpdateTableOptionsAction {
|
||||
type: CEOActionType.UpdateTableOptions | DEActionType.UpdateTableOptions
|
||||
payload: {
|
||||
tableOptions: TableOptions
|
||||
}
|
||||
}
|
||||
|
||||
export interface UpdateLineColorsAction {
|
||||
type: CEOActionType.UpdateLineColors | DEActionType.UpdateLineColors
|
||||
payload: {
|
||||
lineColors: ColorString[]
|
||||
}
|
||||
}
|
||||
|
||||
export interface ChangeTimeFormatAction {
|
||||
type: CEOActionType.ChangeTimeFormat | DEActionType.ChangeTimeFormat
|
||||
payload: {
|
||||
timeFormat: string
|
||||
}
|
||||
}
|
||||
|
||||
export interface ChangeDecimalPlacesAction {
|
||||
type: CEOActionType.ChangeDecimalPlaces | DEActionType.ChangeDecimalPlaces
|
||||
payload: {
|
||||
decimalPlaces: DecimalPlaces
|
||||
}
|
||||
}
|
||||
import {FieldOption} from 'src/types/dashboards'
|
||||
|
||||
export interface UpdateFieldOptionsAction {
|
||||
type: CEOActionType.UpdateFieldOptions | DEActionType.UpdateFieldOptions
|
||||
type: CEOActionType.UpdateFieldOptions
|
||||
payload: {
|
||||
fieldOptions: FieldOption[]
|
||||
}
|
||||
}
|
||||
|
||||
export interface UpdateNoteAction {
|
||||
type: CEOActionType.UpdateCellNote | DEActionType.UpdateNote
|
||||
payload: {
|
||||
note: string
|
||||
}
|
||||
}
|
||||
|
||||
export interface UpdateNoteVisibilityAction {
|
||||
type:
|
||||
| CEOActionType.UpdateCellNoteVisibility
|
||||
| DEActionType.UpdateNoteVisibility
|
||||
payload: {
|
||||
noteVisibility: NoteVisibility
|
||||
}
|
||||
}
|
||||
|
||||
export const updateVisType = (
|
||||
cellType: CellType,
|
||||
stateToUpdate: QueryUpdateState
|
||||
): ChangeVisualizationTypeAction => {
|
||||
const type =
|
||||
stateToUpdate === QueryUpdateState.CEO
|
||||
? CEOActionType.ChangeCellType
|
||||
: DEActionType.ChangeVisualizationType
|
||||
return {
|
||||
type,
|
||||
payload: {
|
||||
cellType,
|
||||
},
|
||||
} as ChangeVisualizationTypeAction
|
||||
}
|
||||
|
||||
export const updateNote = (
|
||||
note: string,
|
||||
stateToUpdate: QueryUpdateState
|
||||
): UpdateNoteAction => {
|
||||
const type =
|
||||
stateToUpdate === QueryUpdateState.CEO
|
||||
? CEOActionType.UpdateCellNote
|
||||
: DEActionType.UpdateNote
|
||||
return {
|
||||
type,
|
||||
payload: {
|
||||
note,
|
||||
},
|
||||
} as UpdateNoteAction
|
||||
}
|
||||
|
||||
export const updateNoteVisibility = (
|
||||
noteVisibility: NoteVisibility,
|
||||
stateToUpdate: QueryUpdateState
|
||||
): UpdateNoteVisibilityAction => {
|
||||
const type =
|
||||
stateToUpdate === QueryUpdateState.CEO
|
||||
? CEOActionType.UpdateCellNoteVisibility
|
||||
: DEActionType.UpdateNoteVisibility
|
||||
return {
|
||||
type,
|
||||
payload: {
|
||||
noteVisibility,
|
||||
},
|
||||
} as UpdateNoteVisibilityAction
|
||||
}
|
||||
|
||||
export const updateThresholdsListColors = (
|
||||
thresholdsListColors: ColorNumber[],
|
||||
stateToUpdate: QueryUpdateState
|
||||
): UpdateThresholdsListColorsAction => {
|
||||
const type =
|
||||
stateToUpdate === QueryUpdateState.CEO
|
||||
? CEOActionType.UpdateThresholdsListColors
|
||||
: DEActionType.UpdateThresholdsListColors
|
||||
return {
|
||||
type,
|
||||
payload: {
|
||||
thresholdsListColors,
|
||||
},
|
||||
} as UpdateThresholdsListColorsAction
|
||||
}
|
||||
|
||||
export const updateThresholdsListType = (
|
||||
thresholdsListType: ThresholdType,
|
||||
stateToUpdate: QueryUpdateState
|
||||
): UpdateThresholdsListTypeAction => {
|
||||
const type =
|
||||
stateToUpdate === QueryUpdateState.CEO
|
||||
? CEOActionType.UpdateThresholdsListType
|
||||
: DEActionType.UpdateThresholdsListType
|
||||
return {
|
||||
type,
|
||||
payload: {
|
||||
thresholdsListType,
|
||||
},
|
||||
} as UpdateThresholdsListTypeAction
|
||||
}
|
||||
|
||||
export const updateGaugeColors = (
|
||||
gaugeColors: ColorNumber[],
|
||||
stateToUpdate: QueryUpdateState
|
||||
): UpdateGaugeColorsAction => {
|
||||
const type =
|
||||
stateToUpdate === QueryUpdateState.CEO
|
||||
? CEOActionType.UpdateGaugeColors
|
||||
: DEActionType.UpdateGaugeColors
|
||||
return {
|
||||
type,
|
||||
payload: {
|
||||
gaugeColors,
|
||||
},
|
||||
} as UpdateGaugeColorsAction
|
||||
}
|
||||
|
||||
export const updateAxes = (
|
||||
axes: Axes,
|
||||
stateToUpdate: QueryUpdateState
|
||||
): UpdateAxesAction => {
|
||||
const type =
|
||||
stateToUpdate === QueryUpdateState.CEO
|
||||
? CEOActionType.UpdateAxes
|
||||
: DEActionType.UpdateAxes
|
||||
return {
|
||||
type,
|
||||
payload: {
|
||||
axes,
|
||||
},
|
||||
} as UpdateAxesAction
|
||||
}
|
||||
|
||||
export const updateTableOptions = (
|
||||
tableOptions: TableOptions,
|
||||
stateToUpdate: QueryUpdateState
|
||||
): UpdateTableOptionsAction => {
|
||||
const type =
|
||||
stateToUpdate === QueryUpdateState.CEO
|
||||
? CEOActionType.UpdateTableOptions
|
||||
: DEActionType.UpdateTableOptions
|
||||
return {
|
||||
type,
|
||||
payload: {
|
||||
tableOptions,
|
||||
},
|
||||
} as UpdateTableOptionsAction
|
||||
}
|
||||
|
||||
export const updateLineColors = (
|
||||
lineColors: ColorString[],
|
||||
stateToUpdate: QueryUpdateState
|
||||
): UpdateLineColorsAction => {
|
||||
const type =
|
||||
stateToUpdate === QueryUpdateState.CEO
|
||||
? CEOActionType.UpdateLineColors
|
||||
: DEActionType.UpdateLineColors
|
||||
return {
|
||||
type,
|
||||
payload: {
|
||||
lineColors,
|
||||
},
|
||||
} as UpdateLineColorsAction
|
||||
}
|
||||
|
||||
export const updateTimeFormat = (
|
||||
timeFormat: string,
|
||||
stateToUpdate: QueryUpdateState
|
||||
): ChangeTimeFormatAction => {
|
||||
const type =
|
||||
stateToUpdate === QueryUpdateState.CEO
|
||||
? CEOActionType.ChangeTimeFormat
|
||||
: DEActionType.ChangeTimeFormat
|
||||
return {
|
||||
type,
|
||||
payload: {
|
||||
timeFormat,
|
||||
},
|
||||
} as ChangeTimeFormatAction
|
||||
}
|
||||
|
||||
export const updateDecimalPlaces = (
|
||||
decimalPlaces: DecimalPlaces,
|
||||
stateToUpdate: QueryUpdateState
|
||||
): ChangeDecimalPlacesAction => {
|
||||
const type =
|
||||
stateToUpdate === QueryUpdateState.CEO
|
||||
? CEOActionType.ChangeDecimalPlaces
|
||||
: DEActionType.ChangeDecimalPlaces
|
||||
return {
|
||||
type,
|
||||
payload: {
|
||||
decimalPlaces,
|
||||
},
|
||||
} as ChangeDecimalPlacesAction
|
||||
}
|
||||
|
||||
export const updateFieldOptions = (
|
||||
fieldOptions: FieldOption[],
|
||||
stateToUpdate: QueryUpdateState
|
||||
fieldOptions: FieldOption[]
|
||||
): UpdateFieldOptionsAction => {
|
||||
const type =
|
||||
stateToUpdate === QueryUpdateState.CEO
|
||||
? CEOActionType.UpdateFieldOptions
|
||||
: DEActionType.UpdateFieldOptions
|
||||
return {
|
||||
type,
|
||||
type: CEOActionType.UpdateFieldOptions,
|
||||
payload: {
|
||||
fieldOptions,
|
||||
},
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import React, {Component, ComponentClass} from 'react'
|
||||
import React, {Component, ComponentClass, StatelessComponent} from 'react'
|
||||
|
||||
export interface ManualRefreshProps {
|
||||
manualRefresh: number
|
||||
|
@ -10,7 +10,9 @@ interface ManualRefreshState {
|
|||
}
|
||||
|
||||
function ManualRefresh<P>(
|
||||
WrappedComponent: ComponentClass<P & ManualRefreshProps>
|
||||
WrappedComponent:
|
||||
| ComponentClass<P & ManualRefreshProps>
|
||||
| StatelessComponent<P & ManualRefreshProps>
|
||||
): ComponentClass<P> {
|
||||
return class extends Component<P & ManualRefreshProps, ManualRefreshState> {
|
||||
public constructor(props: P & ManualRefreshProps) {
|
||||
|
|
|
@ -88,6 +88,7 @@ interface Props {
|
|||
cellNoteVisibility: NoteVisibility
|
||||
editorLocation?: QueryUpdateState
|
||||
onUpdateCellColors?: (bgColor: string, textColor: string) => void
|
||||
onUpdateFieldOptions?: (fieldOptions: FieldOption[]) => void
|
||||
}
|
||||
|
||||
class RefreshingGraph extends PureComponent<Props> {
|
||||
|
@ -242,6 +243,7 @@ class RefreshingGraph extends PureComponent<Props> {
|
|||
manualRefresh,
|
||||
handleSetHoverTime,
|
||||
editorLocation,
|
||||
onUpdateFieldOptions,
|
||||
} = this.props
|
||||
|
||||
const {dataType, data} = this.getTypeAndData(influxQLData, fluxData)
|
||||
|
@ -258,6 +260,7 @@ class RefreshingGraph extends PureComponent<Props> {
|
|||
decimalPlaces={decimalPlaces}
|
||||
editorLocation={editorLocation}
|
||||
handleSetHoverTime={handleSetHoverTime}
|
||||
onUpdateFieldOptions={onUpdateFieldOptions}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
@ -274,6 +277,7 @@ class RefreshingGraph extends PureComponent<Props> {
|
|||
decimalPlaces={decimalPlaces}
|
||||
editorLocation={editorLocation}
|
||||
handleSetHoverTime={handleSetHoverTime}
|
||||
onUpdateFieldOptions={onUpdateFieldOptions}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
|
|
@ -6,43 +6,51 @@ import DatabaseList from 'src/shared/components/DatabaseList'
|
|||
import MeasurementList from 'src/shared/components/MeasurementList'
|
||||
import FieldList from 'src/shared/components/FieldList'
|
||||
|
||||
// Utiles
|
||||
import {TimeMachineContainer} from 'src/shared/utils/TimeMachineContainer'
|
||||
|
||||
// Types
|
||||
import {QueryConfig, Source} from 'src/types'
|
||||
import {QueryConfigActions, QueryUpdateState} from 'src/shared/actions/queries'
|
||||
|
||||
const actionBinder = (id, isInCEO, action) => (...args) => {
|
||||
const stateToUpdate = isInCEO ? QueryUpdateState.CEO : QueryUpdateState.DE
|
||||
return action(id, stateToUpdate, ...args)
|
||||
const actionBinder = (id, action) => (...args) => {
|
||||
return action(id, ...args)
|
||||
}
|
||||
|
||||
interface Props {
|
||||
isInCEO: boolean
|
||||
query: QueryConfig
|
||||
actions: QueryConfigActions
|
||||
source: Source
|
||||
initialGroupByTime: string
|
||||
isQuerySupportedByExplorer?: boolean
|
||||
onFill: TimeMachineContainer['handleFill']
|
||||
onTimeShift: TimeMachineContainer['handleTimeShift']
|
||||
onChooseTag: TimeMachineContainer['handleChooseTag']
|
||||
onGroupByTag: TimeMachineContainer['handleGroupByTag']
|
||||
onGroupByTime: TimeMachineContainer['handleGroupByTime']
|
||||
onToggleField: TimeMachineContainer['handleToggleField']
|
||||
onRemoveFuncs: TimeMachineContainer['handleRemoveFuncs']
|
||||
onAddInitialField: TimeMachineContainer['handleAddInitialField']
|
||||
onChooseNamespace: TimeMachineContainer['handleChooseNamespace']
|
||||
onChooseMeasurement: TimeMachineContainer['handleChooseMeasurement']
|
||||
onApplyFuncsToField: TimeMachineContainer['handleApplyFuncsToField']
|
||||
onToggleTagAcceptance: TimeMachineContainer['handleToggleTagAcceptance']
|
||||
}
|
||||
|
||||
const SchemaExplorer: SFC<Props> = ({
|
||||
isInCEO,
|
||||
query,
|
||||
source,
|
||||
initialGroupByTime,
|
||||
actions: {
|
||||
fill,
|
||||
timeShift,
|
||||
chooseTag,
|
||||
groupByTag,
|
||||
groupByTime,
|
||||
toggleField,
|
||||
removeFuncs,
|
||||
addInitialField,
|
||||
chooseNamespace,
|
||||
chooseMeasurement,
|
||||
applyFuncsToField,
|
||||
toggleTagAcceptance,
|
||||
},
|
||||
onFill,
|
||||
onTimeShift,
|
||||
onChooseTag,
|
||||
onGroupByTag,
|
||||
onGroupByTime,
|
||||
onToggleField,
|
||||
onRemoveFuncs,
|
||||
onAddInitialField,
|
||||
onChooseNamespace,
|
||||
onChooseMeasurement,
|
||||
onApplyFuncsToField,
|
||||
onToggleTagAcceptance,
|
||||
isQuerySupportedByExplorer = true,
|
||||
}) => {
|
||||
const {id} = query
|
||||
|
@ -52,29 +60,29 @@ const SchemaExplorer: SFC<Props> = ({
|
|||
<DatabaseList
|
||||
query={query}
|
||||
querySource={source}
|
||||
onChooseNamespace={actionBinder(id, isInCEO, chooseNamespace)}
|
||||
onChooseNamespace={actionBinder(id, onChooseNamespace)}
|
||||
/>
|
||||
<MeasurementList
|
||||
query={query}
|
||||
querySource={source}
|
||||
onChooseTag={actionBinder(id, isInCEO, chooseTag)}
|
||||
onGroupByTag={actionBinder(id, isInCEO, groupByTag)}
|
||||
onChooseMeasurement={actionBinder(id, isInCEO, chooseMeasurement)}
|
||||
onToggleTagAcceptance={actionBinder(id, isInCEO, toggleTagAcceptance)}
|
||||
onChooseTag={actionBinder(id, onChooseTag)}
|
||||
onGroupByTag={actionBinder(id, onGroupByTag)}
|
||||
onChooseMeasurement={actionBinder(id, onChooseMeasurement)}
|
||||
onToggleTagAcceptance={actionBinder(id, onToggleTagAcceptance)}
|
||||
isQuerySupportedByExplorer={isQuerySupportedByExplorer}
|
||||
/>
|
||||
<FieldList
|
||||
source={source}
|
||||
query={query}
|
||||
querySource={source}
|
||||
onFill={actionBinder(id, isInCEO, fill)}
|
||||
onFill={actionBinder(id, onFill)}
|
||||
initialGroupByTime={initialGroupByTime}
|
||||
onTimeShift={actionBinder(id, isInCEO, timeShift)}
|
||||
removeFuncs={actionBinder(id, isInCEO, removeFuncs)}
|
||||
onToggleField={actionBinder(id, isInCEO, toggleField)}
|
||||
onGroupByTime={actionBinder(id, isInCEO, groupByTime)}
|
||||
addInitialField={actionBinder(id, isInCEO, addInitialField)}
|
||||
applyFuncsToField={actionBinder(id, isInCEO, applyFuncsToField)}
|
||||
onTimeShift={actionBinder(id, onTimeShift)}
|
||||
removeFuncs={actionBinder(id, onRemoveFuncs)}
|
||||
onToggleField={actionBinder(id, onToggleField)}
|
||||
onGroupByTime={actionBinder(id, onGroupByTime)}
|
||||
addInitialField={actionBinder(id, onAddInitialField)}
|
||||
applyFuncsToField={actionBinder(id, onApplyFuncsToField)}
|
||||
isQuerySupportedByExplorer={isQuerySupportedByExplorer}
|
||||
/>
|
||||
</div>
|
||||
|
|
|
@ -7,14 +7,12 @@ import moment from 'moment'
|
|||
import {ColumnSizer, SizedColumnProps, AutoSizer} from 'react-virtualized'
|
||||
import {MultiGrid, PropsMultiGrid} from 'src/shared/components/MultiGrid'
|
||||
import InvalidData from 'src/shared/components/InvalidData'
|
||||
import {bindActionCreators} from 'redux'
|
||||
import {fastReduce} from 'src/utils/fast'
|
||||
import {timeSeriesToTableGraph} from 'src/utils/timeSeriesTransformers'
|
||||
import {
|
||||
computeFieldOptions,
|
||||
getDefaultTimeField,
|
||||
} from 'src/dashboards/utils/tableGraph'
|
||||
import {updateFieldOptions} from 'src/shared/actions/visualizations'
|
||||
import {QueryUpdateState} from 'src/shared/actions/queries'
|
||||
import {
|
||||
ASCENDING,
|
||||
|
@ -74,10 +72,10 @@ interface Props {
|
|||
decimalPlaces: DecimalPlaces
|
||||
fieldOptions: FieldOption[]
|
||||
hoverTime: string
|
||||
handleUpdateFieldOptions: typeof updateFieldOptions
|
||||
handleSetHoverTime?: (hovertime: string) => void
|
||||
colors: ColorString[]
|
||||
editorLocation?: QueryUpdateState
|
||||
onUpdateFieldOptions?: (fieldOptions: FieldOption[]) => void
|
||||
}
|
||||
|
||||
interface State {
|
||||
|
@ -508,9 +506,10 @@ class TableGraph extends PureComponent<Props, State> {
|
|||
}
|
||||
|
||||
private handleUpdateFieldOptions = (fieldOptions: FieldOption[]): void => {
|
||||
const {handleUpdateFieldOptions, editorLocation} = this.props
|
||||
if (editorLocation) {
|
||||
handleUpdateFieldOptions(fieldOptions, editorLocation)
|
||||
const {onUpdateFieldOptions} = this.props
|
||||
|
||||
if (onUpdateFieldOptions) {
|
||||
onUpdateFieldOptions(fieldOptions)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -833,8 +832,4 @@ const mstp = ({dashboardUI}) => ({
|
|||
hoverTime: dashboardUI.hoverTime,
|
||||
})
|
||||
|
||||
const mapDispatchToProps = dispatch => ({
|
||||
handleUpdateFieldOptions: bindActionCreators(updateFieldOptions, dispatch),
|
||||
})
|
||||
|
||||
export default connect(mstp, mapDispatchToProps)(TableGraph)
|
||||
export default connect(mstp)(TableGraph)
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
// Libraries
|
||||
import React, {SFC} from 'react'
|
||||
import _ from 'lodash'
|
||||
import {Subscribe} from 'unstated'
|
||||
|
||||
// Components
|
||||
import EmptyQuery from 'src/shared/components/EmptyQuery'
|
||||
|
@ -8,36 +9,52 @@ import QueryTabList from 'src/shared/components/QueryTabList'
|
|||
import InfluxQLEditor from 'src/dashboards/components/InfluxQLEditor'
|
||||
import SchemaExplorer from 'src/shared/components/SchemaExplorer'
|
||||
import FancyScrollbar from 'src/shared/components/FancyScrollbar'
|
||||
|
||||
// Utils
|
||||
import {TimeMachineContainer} from 'src/shared/utils/TimeMachineContainer'
|
||||
import {buildQuery} from 'src/utils/influxql'
|
||||
import {TYPE_QUERY_CONFIG} from 'src/dashboards/constants'
|
||||
import {TEMPLATE_RANGE} from 'src/tempVars/constants'
|
||||
import {AUTO_GROUP_BY} from 'src/shared/constants'
|
||||
|
||||
// Types
|
||||
import {QueryConfig, Source, TimeRange, Template} from 'src/types'
|
||||
import {QueryConfigActions} from 'src/shared/actions/queries'
|
||||
|
||||
const buildText = (q: QueryConfig): string =>
|
||||
q.rawText || buildQuery(TYPE_QUERY_CONFIG, q.range || TEMPLATE_RANGE, q) || ''
|
||||
|
||||
interface Props {
|
||||
interface ConnectedProps {
|
||||
timeRange: TimeRange
|
||||
onFill: TimeMachineContainer['handleFill']
|
||||
onTimeShift: TimeMachineContainer['handleTimeShift']
|
||||
onChooseTag: TimeMachineContainer['handleChooseTag']
|
||||
onGroupByTag: TimeMachineContainer['handleGroupByTag']
|
||||
onGroupByTime: TimeMachineContainer['handleGroupByTime']
|
||||
onToggleField: TimeMachineContainer['handleToggleField']
|
||||
onRemoveFuncs: TimeMachineContainer['handleRemoveFuncs']
|
||||
onAddInitialField: TimeMachineContainer['handleAddInitialField']
|
||||
onChooseNamespace: TimeMachineContainer['handleChooseNamespace']
|
||||
onChooseMeasurement: TimeMachineContainer['handleChooseMeasurement']
|
||||
onApplyFuncsToField: TimeMachineContainer['handleApplyFuncsToField']
|
||||
onToggleTagAcceptance: TimeMachineContainer['handleToggleTagAcceptance']
|
||||
}
|
||||
|
||||
interface PassedProps {
|
||||
source: Source
|
||||
queries: QueryConfig[]
|
||||
timeRange: TimeRange
|
||||
actions: QueryConfigActions
|
||||
setActiveQueryIndex: (index: number) => void
|
||||
onDeleteQuery: (index: number) => void
|
||||
activeQueryIndex: number
|
||||
activeQuery: QueryConfig
|
||||
onAddQuery: () => void
|
||||
templates: Template[]
|
||||
initialGroupByTime: string
|
||||
isInCEO: boolean
|
||||
onAddQuery: () => void
|
||||
onDeleteQuery: (index: number) => void
|
||||
onEditRawText: (text: string) => Promise<void>
|
||||
}
|
||||
|
||||
type Props = ConnectedProps & PassedProps
|
||||
|
||||
const QueryMaker: SFC<Props> = ({
|
||||
source,
|
||||
isInCEO,
|
||||
actions,
|
||||
queries,
|
||||
timeRange,
|
||||
templates,
|
||||
|
@ -45,8 +62,20 @@ const QueryMaker: SFC<Props> = ({
|
|||
activeQuery,
|
||||
onDeleteQuery,
|
||||
activeQueryIndex,
|
||||
initialGroupByTime,
|
||||
setActiveQueryIndex,
|
||||
onEditRawText,
|
||||
onFill,
|
||||
onTimeShift,
|
||||
onChooseTag,
|
||||
onGroupByTag,
|
||||
onGroupByTime,
|
||||
onToggleField,
|
||||
onRemoveFuncs,
|
||||
onAddInitialField,
|
||||
onChooseNamespace,
|
||||
onChooseMeasurement,
|
||||
onApplyFuncsToField,
|
||||
onToggleTagAcceptance,
|
||||
}) => {
|
||||
if (!activeQuery || !activeQuery.id) {
|
||||
return (
|
||||
|
@ -71,20 +100,30 @@ const QueryMaker: SFC<Props> = ({
|
|||
<InfluxQLEditor
|
||||
query={buildText(activeQuery)}
|
||||
config={activeQuery}
|
||||
onUpdate={actions.editRawTextAsync}
|
||||
onUpdate={onEditRawText}
|
||||
templates={templates}
|
||||
/>
|
||||
<SchemaExplorer
|
||||
source={source}
|
||||
actions={actions}
|
||||
query={activeQuery}
|
||||
initialGroupByTime={initialGroupByTime}
|
||||
initialGroupByTime={AUTO_GROUP_BY}
|
||||
isQuerySupportedByExplorer={_.get(
|
||||
activeQuery,
|
||||
'isQuerySupportedByExplorer',
|
||||
true
|
||||
)}
|
||||
isInCEO={isInCEO}
|
||||
onFill={onFill}
|
||||
onTimeShift={onTimeShift}
|
||||
onChooseTag={onChooseTag}
|
||||
onGroupByTag={onGroupByTag}
|
||||
onGroupByTime={onGroupByTime}
|
||||
onToggleField={onToggleField}
|
||||
onRemoveFuncs={onRemoveFuncs}
|
||||
onAddInitialField={onAddInitialField}
|
||||
onChooseNamespace={onChooseNamespace}
|
||||
onChooseMeasurement={onChooseMeasurement}
|
||||
onApplyFuncsToField={onApplyFuncsToField}
|
||||
onToggleTagAcceptance={onToggleTagAcceptance}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -92,4 +131,27 @@ const QueryMaker: SFC<Props> = ({
|
|||
)
|
||||
}
|
||||
|
||||
export default QueryMaker
|
||||
const ConnectedQueryMaker = (props: PassedProps) => (
|
||||
<Subscribe to={[TimeMachineContainer]}>
|
||||
{(container: TimeMachineContainer) => (
|
||||
<QueryMaker
|
||||
{...props}
|
||||
timeRange={container.state.timeRange}
|
||||
onFill={container.handleFill}
|
||||
onTimeShift={container.handleTimeShift}
|
||||
onChooseTag={container.handleChooseTag}
|
||||
onGroupByTag={container.handleGroupByTag}
|
||||
onGroupByTime={container.handleGroupByTime}
|
||||
onToggleField={container.handleToggleField}
|
||||
onRemoveFuncs={container.handleRemoveFuncs}
|
||||
onAddInitialField={container.handleAddInitialField}
|
||||
onChooseNamespace={container.handleChooseNamespace}
|
||||
onChooseMeasurement={container.handleChooseMeasurement}
|
||||
onApplyFuncsToField={container.handleApplyFuncsToField}
|
||||
onToggleTagAcceptance={container.handleToggleTagAcceptance}
|
||||
/>
|
||||
)}
|
||||
</Subscribe>
|
||||
)
|
||||
|
||||
export default ConnectedQueryMaker
|
||||
|
|
|
@ -1,14 +1,15 @@
|
|||
// Libraries
|
||||
import React, {PureComponent} from 'react'
|
||||
import _ from 'lodash'
|
||||
import {Subscribe} from 'unstated'
|
||||
|
||||
// Components
|
||||
import Threesizer from 'src/shared/components/threesizer/Threesizer'
|
||||
import RefreshingGraph from 'src/shared/components/RefreshingGraph'
|
||||
import InfluxQLQueryMaker from 'src/shared/components/TimeMachine/InfluxQLQueryMaker'
|
||||
import DisplayOptions from 'src/dashboards/components/DisplayOptions'
|
||||
import TimeMachineBottom from 'src/shared/components/TimeMachine/TimeMachineBottom'
|
||||
import TimeMachineControls from 'src/shared/components/TimeMachine/TimeMachineControls'
|
||||
import TimeMachineVisualization from 'src/shared/components/TimeMachine/TimeMachineVisualization'
|
||||
import FluxQueryBuilder from 'src/flux/components/FluxQueryBuilder'
|
||||
|
||||
// Utils
|
||||
|
@ -28,7 +29,7 @@ import {
|
|||
} from 'src/flux/helpers/scriptBuilder'
|
||||
import {AutoRefresher} from 'src/utils/AutoRefresher'
|
||||
import buildQueries from 'src/utils/buildQueriesForGraphs'
|
||||
import {getCellTypeColors} from 'src/dashboards/constants/cellEditor'
|
||||
import {TimeMachineContainer} from 'src/shared/utils/TimeMachineContainer'
|
||||
|
||||
// Actions
|
||||
import {validateSuccess} from 'src/shared/copy/notifications'
|
||||
|
@ -37,12 +38,12 @@ import {updateSourceLink as updateSourceLinkAction} from 'src/data_explorer/acti
|
|||
|
||||
// Constants
|
||||
import {HANDLE_HORIZONTAL} from 'src/shared/constants'
|
||||
import {AUTO_GROUP_BY, PREDEFINED_TEMP_VARS} from 'src/shared/constants'
|
||||
import {PREDEFINED_TEMP_VARS} from 'src/shared/constants'
|
||||
import {CEOTabs} from 'src/dashboards/constants'
|
||||
import {builder, emptyAST} from 'src/flux/constants'
|
||||
|
||||
// Types
|
||||
import {QueryConfigActions, QueryUpdateState} from 'src/shared/actions/queries'
|
||||
import {QueryUpdateState} from 'src/shared/actions/queries'
|
||||
import {
|
||||
TimeRange,
|
||||
QueryConfig,
|
||||
|
@ -67,47 +68,40 @@ import {
|
|||
DeleteFuncNodeArgs,
|
||||
ScriptStatus,
|
||||
} from 'src/types/flux'
|
||||
import {ColorString} from 'src/types/colors'
|
||||
import {VisualizationOptions} from 'src/types/dataExplorer'
|
||||
|
||||
interface Props {
|
||||
interface ConnectedProps {
|
||||
script: string
|
||||
queryDrafts: CellQuery[]
|
||||
onChangeScript: (script: string, stateToUpdate: QueryUpdateState) => void
|
||||
onUpdateQueryDrafts: TimeMachineContainer['handleUpdateQueryDrafts']
|
||||
onAddQuery: () => void
|
||||
onDeleteQuery: (queryID: string) => void
|
||||
timeRange: TimeRange
|
||||
onUpdateTimeRange: (timeRange: TimeRange) => void
|
||||
}
|
||||
|
||||
interface PassedProps {
|
||||
fluxLinks: Links
|
||||
source: Source
|
||||
service?: Service
|
||||
script: string
|
||||
sources: Source[]
|
||||
isInCEO: boolean
|
||||
services: Service[]
|
||||
timeRange: TimeRange
|
||||
templates: Template[]
|
||||
isStaticLegend: boolean
|
||||
queryDrafts: CellQuery[]
|
||||
onResetFocus: () => void
|
||||
updateSourceLink?: typeof updateSourceLinkAction
|
||||
updateScript: (script: string, stateToUpdate: QueryUpdateState) => void
|
||||
queryConfigActions: QueryConfigActions
|
||||
notify: NotificationAction
|
||||
editQueryStatus: (
|
||||
queryID: string,
|
||||
status: Status,
|
||||
stateToUpdate: QueryUpdateState
|
||||
) => void
|
||||
updateQueryDrafts: (
|
||||
queryDrafts: CellQuery[],
|
||||
stateToUpdate: QueryUpdateState
|
||||
) => void
|
||||
onToggleStaticLegend: (isStaticLegend: boolean) => void
|
||||
children: (
|
||||
activeEditorTab: CEOTabs,
|
||||
onSetActiveEditorTab: (activeEditorTab: CEOTabs) => void
|
||||
) => JSX.Element
|
||||
addQuery: (stateToUpdate: QueryUpdateState) => void
|
||||
deleteQuery: (queryID: string, stateToUpdate: QueryUpdateState) => void
|
||||
updateEditorTimeRange: (
|
||||
timeRange: TimeRange,
|
||||
stateToUpdate: QueryUpdateState
|
||||
) => void
|
||||
visualizationOptions: VisualizationOptions
|
||||
manualRefresh?: number
|
||||
queryStatus: QueryStatus
|
||||
updateScriptStatus?: (status: ScriptStatus) => void
|
||||
|
@ -138,6 +132,8 @@ type ScriptFunc = (script: string) => void
|
|||
|
||||
export const FluxContext = React.createContext(undefined)
|
||||
|
||||
type Props = PassedProps & ConnectedProps
|
||||
|
||||
class TimeMachine extends PureComponent<Props, State> {
|
||||
private debouncedASTResponse: ScriptFunc
|
||||
private validAST: boolean = true
|
||||
|
@ -207,7 +203,7 @@ class TimeMachine extends PureComponent<Props, State> {
|
|||
}
|
||||
|
||||
public render() {
|
||||
const {services, timeRange, templates, isInCEO, script} = this.props
|
||||
const {services, timeRange, templates, script} = this.props
|
||||
const {autoRefreshDuration, isViewingRawData} = this.state
|
||||
|
||||
const horizontalDivisions = [
|
||||
|
@ -254,7 +250,6 @@ class TimeMachine extends PureComponent<Props, State> {
|
|||
isDynamicSourceSelected={this.useDynamicSource}
|
||||
timeRange={timeRange}
|
||||
updateEditorTimeRange={this.handleUpdateEditorTimeRange}
|
||||
isInCEO={isInCEO}
|
||||
/>
|
||||
<div className="deceo--container">
|
||||
<Threesizer
|
||||
|
@ -267,70 +262,22 @@ class TimeMachine extends PureComponent<Props, State> {
|
|||
}
|
||||
|
||||
private renderVisualization = () => {
|
||||
const {
|
||||
timeRange,
|
||||
templates,
|
||||
isStaticLegend,
|
||||
manualRefresh,
|
||||
visualizationOptions: {
|
||||
type,
|
||||
axes,
|
||||
tableOptions,
|
||||
fieldOptions,
|
||||
timeFormat,
|
||||
decimalPlaces,
|
||||
note,
|
||||
noteVisibility,
|
||||
thresholdsListColors,
|
||||
thresholdsListType,
|
||||
gaugeColors,
|
||||
lineColors,
|
||||
},
|
||||
} = this.props
|
||||
const {templates, isStaticLegend, manualRefresh} = this.props
|
||||
const {autoRefresher, isViewingRawData} = this.state
|
||||
|
||||
const colors: ColorString[] = getCellTypeColors({
|
||||
cellType: type,
|
||||
gaugeColors,
|
||||
thresholdsListColors,
|
||||
lineColors,
|
||||
})
|
||||
|
||||
return (
|
||||
<div className="deceo--top">
|
||||
<div className="deceo--visualization">
|
||||
<div className="graph-container">
|
||||
<RefreshingGraph
|
||||
source={this.source}
|
||||
service={this.service}
|
||||
colors={colors}
|
||||
autoRefresher={autoRefresher}
|
||||
queries={this.queriesForVis}
|
||||
templates={templates}
|
||||
editQueryStatus={this.handleEditQueryStatus}
|
||||
staticLegend={isStaticLegend}
|
||||
timeRange={timeRange}
|
||||
manualRefresh={manualRefresh}
|
||||
editorLocation={this.stateToUpdate}
|
||||
showRawFluxData={isViewingRawData}
|
||||
type={type}
|
||||
axes={axes}
|
||||
tableOptions={tableOptions}
|
||||
fieldOptions={fieldOptions}
|
||||
timeFormat={timeFormat}
|
||||
decimalPlaces={decimalPlaces}
|
||||
note={note}
|
||||
noteVisibility={noteVisibility}
|
||||
thresholdsListColors={thresholdsListColors}
|
||||
thresholdsListType={thresholdsListType}
|
||||
gaugeColors={gaugeColors}
|
||||
lineColors={lineColors}
|
||||
cellNote={note}
|
||||
cellNoteVisibility={noteVisibility}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<TimeMachineVisualization
|
||||
source={this.source}
|
||||
service={this.service}
|
||||
autoRefresher={autoRefresher}
|
||||
queries={this.queriesForVis}
|
||||
templates={templates}
|
||||
onEditQueryStatus={this.handleEditQueryStatus}
|
||||
staticLegend={isStaticLegend}
|
||||
manualRefresh={manualRefresh}
|
||||
editorLocation={this.stateToUpdate}
|
||||
showRawFluxData={isViewingRawData}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
|
@ -339,18 +286,14 @@ class TimeMachine extends PureComponent<Props, State> {
|
|||
}
|
||||
|
||||
private get editorTab() {
|
||||
const {
|
||||
onResetFocus,
|
||||
isStaticLegend,
|
||||
onToggleStaticLegend,
|
||||
visualizationOptions,
|
||||
} = this.props
|
||||
const {onResetFocus, isStaticLegend, onToggleStaticLegend} = this.props
|
||||
const {activeEditorTab} = this.state
|
||||
|
||||
if (activeEditorTab === CEOTabs.Queries) {
|
||||
if (this.isFluxSource) {
|
||||
return this.fluxBuilder
|
||||
}
|
||||
|
||||
return this.influxQLBuilder
|
||||
}
|
||||
|
||||
|
@ -361,7 +304,6 @@ class TimeMachine extends PureComponent<Props, State> {
|
|||
staticLegend={isStaticLegend}
|
||||
onResetFocus={onResetFocus}
|
||||
stateToUpdate={this.stateToUpdate}
|
||||
{...visualizationOptions}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
@ -435,6 +377,7 @@ class TimeMachine extends PureComponent<Props, State> {
|
|||
if (!queryDrafts || !queryDrafts.length) {
|
||||
return []
|
||||
}
|
||||
|
||||
return queryDrafts.map(q => {
|
||||
if (queryStatus.queryID === q.id) {
|
||||
return {
|
||||
|
@ -506,23 +449,20 @@ class TimeMachine extends PureComponent<Props, State> {
|
|||
}
|
||||
|
||||
private get influxQLBuilder(): JSX.Element {
|
||||
const {isInCEO, templates, timeRange} = this.props
|
||||
const {templates} = this.props
|
||||
const {activeQueryIndex} = this.state
|
||||
|
||||
return (
|
||||
<InfluxQLQueryMaker
|
||||
isInCEO={isInCEO}
|
||||
source={this.source}
|
||||
templates={templates}
|
||||
queries={this.queriesWorkingDraft}
|
||||
actions={this.queryConfigActions}
|
||||
timeRange={timeRange}
|
||||
onDeleteQuery={this.handleDeleteQuery}
|
||||
onAddQuery={this.handleAddQuery}
|
||||
activeQueryIndex={activeQueryIndex}
|
||||
activeQuery={this.activeQuery}
|
||||
setActiveQueryIndex={this.handleSetActiveQueryIndex}
|
||||
initialGroupByTime={AUTO_GROUP_BY}
|
||||
onEditRawText={this.handleEditRawText}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
@ -536,6 +476,7 @@ class TimeMachine extends PureComponent<Props, State> {
|
|||
private get queriesForVis(): Query[] {
|
||||
const {script, timeRange, queryDrafts} = this.props
|
||||
const id = _.get(queryDrafts, 'id', '')
|
||||
|
||||
if (this.isFluxSource) {
|
||||
if (!this.validAST) {
|
||||
return []
|
||||
|
@ -575,9 +516,9 @@ class TimeMachine extends PureComponent<Props, State> {
|
|||
}
|
||||
|
||||
private handleUpdateEditorTimeRange = (timeRange: TimeRange) => {
|
||||
const {updateEditorTimeRange} = this.props
|
||||
const {onUpdateTimeRange} = this.props
|
||||
|
||||
updateEditorTimeRange(timeRange, this.stateToUpdate)
|
||||
onUpdateTimeRange(timeRange)
|
||||
}
|
||||
|
||||
private handleEditQueryStatus = (queryID: string, status: Status) => {
|
||||
|
@ -610,18 +551,12 @@ class TimeMachine extends PureComponent<Props, State> {
|
|||
return getDeep(queryDrafts, '0.source', '') === ''
|
||||
}
|
||||
|
||||
private get queryConfigActions() {
|
||||
const {queryConfigActions} = this.props
|
||||
|
||||
return {...queryConfigActions, editRawTextAsync: this.handleEditRawText}
|
||||
}
|
||||
|
||||
// The schema explorer is not built to handle user defined template variables
|
||||
// in the query in a clear manner. If they are being used, we indicate that in
|
||||
// the query config in order to disable the fields column down stream because
|
||||
// at this point the query string is disconnected from the schema explorer.
|
||||
private handleEditRawText = async (text: string): Promise<void> => {
|
||||
const {templates, updateQueryDrafts, queryDrafts} = this.props
|
||||
const {templates, onUpdateQueryDrafts, queryDrafts} = this.props
|
||||
|
||||
const id = this.activeQuery.id
|
||||
const url = getDeep<string>(this.source, 'links.queries', '')
|
||||
|
@ -675,7 +610,7 @@ class TimeMachine extends PureComponent<Props, State> {
|
|||
|
||||
return q
|
||||
})
|
||||
updateQueryDrafts(nextQueries, this.stateToUpdate)
|
||||
onUpdateQueryDrafts(nextQueries)
|
||||
} catch (error) {
|
||||
console.error(error)
|
||||
}
|
||||
|
@ -685,7 +620,7 @@ class TimeMachine extends PureComponent<Props, State> {
|
|||
selectedSource: Source | Service,
|
||||
type: string
|
||||
) {
|
||||
const {queryDrafts, updateQueryDrafts} = this.props
|
||||
const {queryDrafts, onUpdateQueryDrafts} = this.props
|
||||
|
||||
const queries: CellQuery[] = queryDrafts.map(q => {
|
||||
const queryConfig = _.get(q, 'queryConfig')
|
||||
|
@ -697,7 +632,7 @@ class TimeMachine extends PureComponent<Props, State> {
|
|||
}
|
||||
}) as CellQuery[]
|
||||
|
||||
updateQueryDrafts(queries, this.stateToUpdate)
|
||||
onUpdateQueryDrafts(queries)
|
||||
}
|
||||
|
||||
private handleChangeService = (
|
||||
|
@ -724,15 +659,15 @@ class TimeMachine extends PureComponent<Props, State> {
|
|||
}
|
||||
|
||||
private handleAddQuery = () => {
|
||||
const {queryDrafts, addQuery} = this.props
|
||||
const {queryDrafts, onAddQuery} = this.props
|
||||
const newIndex = queryDrafts.length
|
||||
|
||||
addQuery(this.stateToUpdate)
|
||||
onAddQuery()
|
||||
this.handleSetActiveQueryIndex(newIndex)
|
||||
}
|
||||
|
||||
private handleDeleteQuery = (index: number) => {
|
||||
const {queryDrafts, deleteQuery, isInCEO} = this.props
|
||||
const {queryDrafts, onDeleteQuery} = this.props
|
||||
const queryToDelete = queryDrafts.find((__, i) => i === index)
|
||||
const activeQueryId = this.activeQuery.id
|
||||
const activeQueryIndex = queryDrafts.findIndex(
|
||||
|
@ -755,8 +690,7 @@ class TimeMachine extends PureComponent<Props, State> {
|
|||
|
||||
this.handleSetActiveQueryIndex(newIndex)
|
||||
|
||||
const stateToUpdate = isInCEO ? QueryUpdateState.CEO : QueryUpdateState.DE
|
||||
deleteQuery(queryToDelete.id, stateToUpdate)
|
||||
onDeleteQuery(queryToDelete.id)
|
||||
}
|
||||
|
||||
private handleChangeAutoRefreshDuration = (autoRefreshDuration: number) => {
|
||||
|
@ -773,7 +707,7 @@ class TimeMachine extends PureComponent<Props, State> {
|
|||
|
||||
// --------------- FLUX ----------------
|
||||
private get getContext(): Context {
|
||||
const {timeRange, visualizationOptions} = this.props
|
||||
const {timeRange} = this.props
|
||||
return {
|
||||
onAddNode: this.handleAddNode,
|
||||
onChangeArg: this.handleChangeArg,
|
||||
|
@ -788,12 +722,11 @@ class TimeMachine extends PureComponent<Props, State> {
|
|||
source: this.source,
|
||||
queries: this.queriesForVis,
|
||||
timeRange,
|
||||
visualizationOptions,
|
||||
}
|
||||
}
|
||||
|
||||
private updateScript(script: string) {
|
||||
this.props.updateScript(script, this.stateToUpdate)
|
||||
this.props.onChangeScript(script, this.stateToUpdate)
|
||||
}
|
||||
|
||||
private getASTResponse = async (
|
||||
|
@ -987,4 +920,28 @@ class TimeMachine extends PureComponent<Props, State> {
|
|||
}
|
||||
}
|
||||
|
||||
export default TimeMachine
|
||||
const ConnectedTimeMachine = (props: PassedProps) => {
|
||||
return (
|
||||
<Subscribe to={[TimeMachineContainer]}>
|
||||
{(container: TimeMachineContainer) => {
|
||||
const {state} = container
|
||||
|
||||
return (
|
||||
<TimeMachine
|
||||
{...props}
|
||||
script={state.script}
|
||||
queryDrafts={state.queryDrafts}
|
||||
timeRange={state.timeRange}
|
||||
onUpdateTimeRange={container.handleUpdateTimeRange}
|
||||
onChangeScript={container.handleChangeScript}
|
||||
onUpdateQueryDrafts={container.handleUpdateQueryDrafts}
|
||||
onAddQuery={container.handleAddQuery}
|
||||
onDeleteQuery={container.handleDeleteQuery}
|
||||
/>
|
||||
)
|
||||
}}
|
||||
</Subscribe>
|
||||
)
|
||||
}
|
||||
|
||||
export default ConnectedTimeMachine
|
||||
|
|
|
@ -17,7 +17,6 @@ import * as SourcesModels from 'src/types/sources'
|
|||
import {Service, Template} from 'src/types'
|
||||
|
||||
interface Props {
|
||||
isInCEO: boolean
|
||||
isFluxSource: boolean
|
||||
source: SourcesModels.Source
|
||||
sources: SourcesModels.SourceOption[]
|
||||
|
@ -46,7 +45,6 @@ const TimeMachineControls: SFC<Props> = ({
|
|||
service,
|
||||
queries,
|
||||
templates,
|
||||
isInCEO,
|
||||
services,
|
||||
timeRange,
|
||||
toggleFlux,
|
||||
|
@ -61,8 +59,6 @@ const TimeMachineControls: SFC<Props> = ({
|
|||
isDynamicSourceSelected,
|
||||
updateEditorTimeRange,
|
||||
}) => {
|
||||
const timeRangePage = isInCEO ? null : 'DataExplorer'
|
||||
|
||||
return (
|
||||
<div className="deceo--controls">
|
||||
<SourceSelector
|
||||
|
@ -103,7 +99,6 @@ const TimeMachineControls: SFC<Props> = ({
|
|||
<TimeRangeDropdown
|
||||
onChooseTimeRange={updateEditorTimeRange}
|
||||
selected={timeRange}
|
||||
page={timeRangePage}
|
||||
/>
|
||||
</div>
|
||||
)
|
||||
|
|
|
@ -0,0 +1,135 @@
|
|||
import React, {SFC} from 'react'
|
||||
import {Subscribe} from 'unstated'
|
||||
|
||||
import RefreshingGraph from 'src/shared/components/RefreshingGraph'
|
||||
|
||||
import {TimeMachineContainer} from 'src/shared/utils/TimeMachineContainer'
|
||||
import {getCellTypeColors} from 'src/dashboards/constants/cellEditor'
|
||||
|
||||
import {
|
||||
CellType,
|
||||
Axes,
|
||||
TimeRange,
|
||||
Source,
|
||||
Service,
|
||||
Query,
|
||||
Template,
|
||||
Status,
|
||||
} from 'src/types'
|
||||
import {ColorString, ColorNumber} from 'src/types/colors'
|
||||
import {QueryUpdateState} from 'src/shared/actions/queries'
|
||||
import {
|
||||
TableOptions,
|
||||
FieldOption,
|
||||
DecimalPlaces,
|
||||
NoteVisibility,
|
||||
ThresholdType,
|
||||
} from 'src/types/dashboards'
|
||||
import {AutoRefresher} from 'src/utils/AutoRefresher'
|
||||
|
||||
interface ConnectedProps {
|
||||
timeRange: TimeRange
|
||||
onUpdateFieldOptions: TimeMachineContainer['handleUpdateFieldOptions']
|
||||
type: CellType
|
||||
axes: Axes | null
|
||||
tableOptions: TableOptions
|
||||
fieldOptions: FieldOption[]
|
||||
timeFormat: string
|
||||
decimalPlaces: DecimalPlaces
|
||||
note: string
|
||||
noteVisibility: NoteVisibility
|
||||
thresholdsListColors: ColorNumber[]
|
||||
thresholdsListType: ThresholdType
|
||||
gaugeColors: ColorNumber[]
|
||||
lineColors: ColorString[]
|
||||
}
|
||||
|
||||
interface PassedProps {
|
||||
source: Source
|
||||
service: Service
|
||||
autoRefresher: AutoRefresher
|
||||
queries: Query[]
|
||||
templates: Template[]
|
||||
onEditQueryStatus: (queryID: string, status: Status) => void
|
||||
staticLegend: boolean
|
||||
manualRefresh: number
|
||||
editorLocation?: QueryUpdateState
|
||||
showRawFluxData?: boolean
|
||||
}
|
||||
|
||||
type Props = PassedProps & ConnectedProps
|
||||
|
||||
const TimeMachineVisualization: SFC<Props> = props => {
|
||||
const colors: ColorString[] = getCellTypeColors({
|
||||
cellType: props.type,
|
||||
gaugeColors: props.gaugeColors,
|
||||
thresholdsListColors: props.thresholdsListColors,
|
||||
lineColors: props.lineColors,
|
||||
})
|
||||
|
||||
return (
|
||||
<div className="deceo--top">
|
||||
<div className="deceo--visualization">
|
||||
<div className="graph-container">
|
||||
<RefreshingGraph
|
||||
source={props.source}
|
||||
service={props.service}
|
||||
colors={colors}
|
||||
autoRefresher={props.autoRefresher}
|
||||
queries={props.queries}
|
||||
templates={props.templates}
|
||||
editQueryStatus={props.onEditQueryStatus}
|
||||
staticLegend={props.staticLegend}
|
||||
timeRange={props.timeRange}
|
||||
manualRefresh={props.manualRefresh}
|
||||
editorLocation={props.editorLocation}
|
||||
showRawFluxData={props.showRawFluxData}
|
||||
type={props.type}
|
||||
axes={props.axes}
|
||||
tableOptions={props.tableOptions}
|
||||
fieldOptions={props.fieldOptions}
|
||||
timeFormat={props.timeFormat}
|
||||
decimalPlaces={props.decimalPlaces}
|
||||
thresholdsListColors={props.thresholdsListColors}
|
||||
thresholdsListType={props.thresholdsListType}
|
||||
gaugeColors={props.gaugeColors}
|
||||
lineColors={props.lineColors}
|
||||
cellNote={props.note}
|
||||
cellNoteVisibility={props.noteVisibility}
|
||||
onUpdateFieldOptions={props.onUpdateFieldOptions}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
const ConnectedTimeMachineVisualization = (props: PassedProps) => (
|
||||
<Subscribe to={[TimeMachineContainer]}>
|
||||
{(container: TimeMachineContainer) => {
|
||||
const {state} = container
|
||||
|
||||
return (
|
||||
<TimeMachineVisualization
|
||||
{...props}
|
||||
timeRange={state.timeRange}
|
||||
type={state.type}
|
||||
axes={state.axes}
|
||||
tableOptions={state.tableOptions}
|
||||
fieldOptions={state.fieldOptions}
|
||||
timeFormat={state.timeFormat}
|
||||
decimalPlaces={state.decimalPlaces}
|
||||
thresholdsListColors={state.thresholdsListColors}
|
||||
thresholdsListType={state.thresholdsListType}
|
||||
gaugeColors={state.gaugeColors}
|
||||
lineColors={state.lineColors}
|
||||
note={state.note}
|
||||
noteVisibility={state.noteVisibility}
|
||||
onUpdateFieldOptions={container.handleUpdateFieldOptions}
|
||||
/>
|
||||
)
|
||||
}}
|
||||
</Subscribe>
|
||||
)
|
||||
|
||||
export default ConnectedTimeMachineVisualization
|
|
@ -208,7 +208,7 @@ export const LINE_COLOR_SCALES = [
|
|||
return {name, colors, id}
|
||||
})
|
||||
|
||||
export const validateLineColors = (
|
||||
export const getLineColors = (
|
||||
colors: LineColor[],
|
||||
numSeries = 0
|
||||
): LineColor[] => {
|
||||
|
@ -228,7 +228,7 @@ export const getLineColorsHexes = (
|
|||
colors: LineColor[],
|
||||
numSeries: number
|
||||
): string[] => {
|
||||
const validatedColors = validateLineColors(colors, numSeries) // ensures safe defaults
|
||||
const validatedColors = getLineColors(colors, numSeries) // ensures safe defaults
|
||||
const colorsHexArray = validatedColors.map(color => color.hex)
|
||||
|
||||
if (numSeries === 1 || numSeries === 0) {
|
||||
|
|
|
@ -119,7 +119,9 @@ export const DEFAULT_THRESHOLDS_LIST_COLORS = [
|
|||
},
|
||||
]
|
||||
|
||||
export const validateThresholdsListColors = (colors, type) => {
|
||||
export const getThresholdsListColors = colors => {
|
||||
const type = getThresholdsListType(colors)
|
||||
|
||||
if (!colors || colors.length === 0) {
|
||||
return DEFAULT_THRESHOLDS_LIST_COLORS
|
||||
}
|
||||
|
@ -159,19 +161,17 @@ export const validateThresholdsListColors = (colors, type) => {
|
|||
return containsBaseColor ? formattedColors : formattedColorsWithBase
|
||||
}
|
||||
|
||||
export const getThresholdsListType = colors => {
|
||||
const getThresholdsListType = colors => {
|
||||
const type = _.get(colors, ['0', 'type'], false)
|
||||
|
||||
if (type) {
|
||||
if (_.includes([THRESHOLD_TYPE_TEXT, THRESHOLD_TYPE_BG], type)) {
|
||||
return type
|
||||
}
|
||||
if (type && _.includes([THRESHOLD_TYPE_TEXT, THRESHOLD_TYPE_BG], type)) {
|
||||
return type
|
||||
}
|
||||
|
||||
return THRESHOLD_TYPE_TEXT
|
||||
}
|
||||
|
||||
export const validateGaugeColors = colors => {
|
||||
export const getGaugeColors = colors => {
|
||||
if (!colors || colors.length < MIN_THRESHOLDS) {
|
||||
return DEFAULT_GAUGE_COLORS
|
||||
}
|
||||
|
|
|
@ -0,0 +1,340 @@
|
|||
// Libraries
|
||||
import {Container} from 'unstated'
|
||||
import uuid from 'uuid'
|
||||
|
||||
// Utils
|
||||
import {
|
||||
fill,
|
||||
timeShift,
|
||||
chooseTag,
|
||||
groupByTag,
|
||||
removeFuncs,
|
||||
groupByTime,
|
||||
toggleField,
|
||||
chooseNamespace,
|
||||
chooseMeasurement,
|
||||
addInitialField,
|
||||
applyFuncsToField,
|
||||
toggleTagAcceptance,
|
||||
} from 'src/utils/queryTransitions'
|
||||
import {getTimeRange} from 'src/dashboards/utils/cellGetters'
|
||||
import {buildQuery} from 'src/utils/influxql'
|
||||
import defaultQueryConfig from 'src/utils/defaultQueryConfig'
|
||||
|
||||
// Constants
|
||||
import {TYPE_QUERY_CONFIG} from 'src/dashboards/constants'
|
||||
import {
|
||||
DEFAULT_THRESHOLDS_LIST_COLORS,
|
||||
DEFAULT_GAUGE_COLORS,
|
||||
} from 'src/shared/constants/thresholds'
|
||||
import {DEFAULT_LINE_COLORS} from 'src/shared/constants/graphColorPalettes'
|
||||
import {DEFAULT_AXES} from 'src/dashboards/constants/cellEditor'
|
||||
import {
|
||||
DEFAULT_TABLE_OPTIONS,
|
||||
DEFAULT_TIME_FORMAT,
|
||||
DEFAULT_DECIMAL_PLACES,
|
||||
DEFAULT_FIELD_OPTIONS,
|
||||
} from 'src/dashboards/constants'
|
||||
import {DEFAULT_TIME_RANGE} from 'src/data_explorer/constants'
|
||||
|
||||
// Types
|
||||
import {
|
||||
Status,
|
||||
Field,
|
||||
GroupBy,
|
||||
Tag,
|
||||
TimeShift,
|
||||
ApplyFuncsToFieldArgs,
|
||||
CellQuery,
|
||||
QueryType,
|
||||
TimeRange,
|
||||
CellType,
|
||||
QueryConfig,
|
||||
} from 'src/types'
|
||||
import {
|
||||
DecimalPlaces,
|
||||
FieldOption,
|
||||
ThresholdType,
|
||||
TableOptions,
|
||||
NoteVisibility,
|
||||
Axes,
|
||||
} from 'src/types/dashboards'
|
||||
import {ColorString, ColorNumber} from 'src/types/colors'
|
||||
|
||||
export interface TimeMachineState {
|
||||
script: string
|
||||
queryDrafts: CellQuery[]
|
||||
timeRange: TimeRange
|
||||
type: CellType
|
||||
axes: Axes | null
|
||||
tableOptions: TableOptions
|
||||
fieldOptions: FieldOption[]
|
||||
timeFormat: string
|
||||
decimalPlaces: DecimalPlaces
|
||||
note: string
|
||||
noteVisibility: NoteVisibility
|
||||
thresholdsListColors: ColorNumber[]
|
||||
thresholdsListType: ThresholdType
|
||||
gaugeColors: ColorNumber[]
|
||||
lineColors: ColorString[]
|
||||
}
|
||||
|
||||
export class TimeMachineContainer extends Container<TimeMachineState> {
|
||||
constructor(initialState: Partial<TimeMachineState> = {}) {
|
||||
super()
|
||||
|
||||
this.state = {
|
||||
script: '',
|
||||
queryDrafts: [],
|
||||
timeRange: DEFAULT_TIME_RANGE,
|
||||
type: CellType.Line,
|
||||
note: '',
|
||||
noteVisibility: NoteVisibility.Default,
|
||||
thresholdsListType: ThresholdType.Text,
|
||||
thresholdsListColors: DEFAULT_THRESHOLDS_LIST_COLORS,
|
||||
gaugeColors: DEFAULT_GAUGE_COLORS,
|
||||
lineColors: DEFAULT_LINE_COLORS,
|
||||
axes: DEFAULT_AXES,
|
||||
tableOptions: DEFAULT_TABLE_OPTIONS,
|
||||
timeFormat: DEFAULT_TIME_FORMAT,
|
||||
decimalPlaces: DEFAULT_DECIMAL_PLACES,
|
||||
fieldOptions: DEFAULT_FIELD_OPTIONS,
|
||||
...initialState,
|
||||
}
|
||||
}
|
||||
|
||||
public handleChangeScript = (script: string) => {
|
||||
this.setState({script})
|
||||
}
|
||||
|
||||
public handleUpdateTimeRange = (timeRange: TimeRange) => {
|
||||
this.setState({timeRange})
|
||||
}
|
||||
|
||||
public handleUpdateQueryDrafts = (queryDrafts: CellQuery[]) => {
|
||||
this.setState({queryDrafts})
|
||||
}
|
||||
|
||||
public handleToggleField = (queryID: string, fieldFunc: Field) => {
|
||||
const {queryDrafts} = this.state
|
||||
const updatedQueryDrafts = queryDrafts.map(query => {
|
||||
if (query.id === queryID) {
|
||||
const nextQueryConfig = {
|
||||
...toggleField(query.queryConfig, fieldFunc),
|
||||
rawText: null,
|
||||
}
|
||||
|
||||
return {
|
||||
...query,
|
||||
query: buildQuery(
|
||||
TYPE_QUERY_CONFIG,
|
||||
getTimeRange(nextQueryConfig),
|
||||
nextQueryConfig
|
||||
),
|
||||
queryConfig: nextQueryConfig,
|
||||
}
|
||||
}
|
||||
return query
|
||||
})
|
||||
|
||||
this.setState({queryDrafts: updatedQueryDrafts})
|
||||
}
|
||||
|
||||
public handleGroupByTime = (queryID: string, time: string) => {
|
||||
const {queryDrafts} = this.state
|
||||
const updatedQueryDrafts = queryDrafts.map(query => {
|
||||
if (query.id === queryID) {
|
||||
const nextQueryConfig = groupByTime(query.queryConfig, time)
|
||||
|
||||
return {
|
||||
...query,
|
||||
query: buildQuery(
|
||||
TYPE_QUERY_CONFIG,
|
||||
getTimeRange(nextQueryConfig),
|
||||
nextQueryConfig
|
||||
),
|
||||
queryConfig: nextQueryConfig,
|
||||
}
|
||||
}
|
||||
return query
|
||||
})
|
||||
|
||||
this.setState({queryDrafts: updatedQueryDrafts})
|
||||
}
|
||||
|
||||
public handleFill = (queryID: string, value: string) => {
|
||||
const {queryDrafts} = this.state
|
||||
const updatedQueryDrafts = queryDrafts.map(query => {
|
||||
if (query.id === queryID) {
|
||||
const nextQueryConfig = fill(query.queryConfig, value)
|
||||
|
||||
return {
|
||||
...query,
|
||||
query: buildQuery(
|
||||
TYPE_QUERY_CONFIG,
|
||||
getTimeRange(nextQueryConfig),
|
||||
nextQueryConfig
|
||||
),
|
||||
queryConfig: nextQueryConfig,
|
||||
}
|
||||
}
|
||||
return query
|
||||
})
|
||||
|
||||
this.setState({queryDrafts: updatedQueryDrafts})
|
||||
}
|
||||
|
||||
public handleRemoveFuncs = (queryID: string, fields: Field[]) => {
|
||||
this.updateQueryDrafts(queryID, q => removeFuncs(q, fields))
|
||||
}
|
||||
|
||||
public handleApplyFuncsToField = (
|
||||
queryID: string,
|
||||
fieldFunc: ApplyFuncsToFieldArgs,
|
||||
groupBy?: GroupBy
|
||||
) => {
|
||||
this.updateQueryDrafts(queryID, q =>
|
||||
applyFuncsToField(q, fieldFunc, groupBy)
|
||||
)
|
||||
}
|
||||
|
||||
public handleChooseTag = (queryID: string, tag: Tag) => {
|
||||
this.updateQueryDrafts(queryID, q => chooseTag(q, tag))
|
||||
}
|
||||
|
||||
public handleChooseNamespace = (
|
||||
queryID: string,
|
||||
options: {database: string; retentionPolicy: string}
|
||||
) => {
|
||||
this.updateQueryDrafts(queryID, q => chooseNamespace(q, options))
|
||||
}
|
||||
|
||||
public handleChooseMeasurement = (queryID: string, measurement: string) => {
|
||||
this.updateQueryDrafts(queryID, q => ({
|
||||
...chooseMeasurement(q, measurement),
|
||||
rawText: q.rawText || '',
|
||||
}))
|
||||
}
|
||||
|
||||
public handleGroupByTag = (queryID: string, tagKey: string) => {
|
||||
this.updateQueryDrafts(queryID, q => groupByTag(q, tagKey))
|
||||
}
|
||||
|
||||
public handleToggleTagAcceptance = (queryID: string) => {
|
||||
this.updateQueryDrafts(queryID, q => toggleTagAcceptance(q))
|
||||
}
|
||||
|
||||
public handleAddInitialField = (
|
||||
queryID: string,
|
||||
field: Field,
|
||||
groupBy: GroupBy
|
||||
) => {
|
||||
this.updateQueryDrafts(queryID, q => addInitialField(q, field, groupBy))
|
||||
}
|
||||
|
||||
public handleEditQueryStatus = (queryID: string, status: Status) => {
|
||||
this.updateQueryDrafts(queryID, q => ({...q, status}))
|
||||
}
|
||||
|
||||
public handleTimeShift = (queryID: string, shift: TimeShift) => {
|
||||
this.updateQueryDrafts(queryID, q => timeShift(q, shift))
|
||||
}
|
||||
|
||||
public handleAddQuery = () => {
|
||||
const {queryDrafts} = this.state
|
||||
const queryID = uuid.v4()
|
||||
const newQueryDraft: CellQuery = {
|
||||
query: '',
|
||||
queryConfig: defaultQueryConfig({id: queryID}),
|
||||
source: '',
|
||||
id: queryID,
|
||||
type: QueryType.InfluxQL,
|
||||
}
|
||||
|
||||
this.setState({queryDrafts: [...queryDrafts, newQueryDraft]})
|
||||
}
|
||||
|
||||
public handleDeleteQuery = (queryID: string) => {
|
||||
const {queryDrafts} = this.state
|
||||
const updatedQueryDrafts = queryDrafts.filter(query => query.id !== queryID)
|
||||
|
||||
this.setState({queryDrafts: updatedQueryDrafts})
|
||||
}
|
||||
|
||||
public handleUpdateType = (type: CellType) => {
|
||||
this.setState({type})
|
||||
}
|
||||
|
||||
public handleUpdateNote = (note: string) => {
|
||||
this.setState({note})
|
||||
}
|
||||
|
||||
public handleUpdateNoteVisibility = (noteVisibility: NoteVisibility) => {
|
||||
this.setState({noteVisibility})
|
||||
}
|
||||
|
||||
public handleUpdateThresholdsListColors = (
|
||||
thresholdsListColors: ColorNumber[]
|
||||
) => {
|
||||
this.setState({thresholdsListColors})
|
||||
}
|
||||
|
||||
public handleUpdateThresholdsListType = (
|
||||
thresholdsListType: ThresholdType
|
||||
) => {
|
||||
this.setState({thresholdsListType})
|
||||
}
|
||||
|
||||
public handleUpdateGaugeColors = (gaugeColors: ColorNumber[]) => {
|
||||
this.setState({gaugeColors})
|
||||
}
|
||||
|
||||
public handleUpdateAxes = (axes: Axes) => {
|
||||
this.setState({axes})
|
||||
}
|
||||
|
||||
public handleUpdateTableOptions = (tableOptions: TableOptions) => {
|
||||
this.setState({tableOptions})
|
||||
}
|
||||
|
||||
public handleUpdateLineColors = (lineColors: ColorString[]) => {
|
||||
this.setState({lineColors})
|
||||
}
|
||||
|
||||
public handleUpdateTimeFormat = (timeFormat: string) => {
|
||||
this.setState({timeFormat})
|
||||
}
|
||||
|
||||
public handleUpdateDecimalPlaces = (decimalPlaces: DecimalPlaces) => {
|
||||
this.setState({decimalPlaces})
|
||||
}
|
||||
|
||||
public handleUpdateFieldOptions = (fieldOptions: FieldOption[]) => {
|
||||
this.setState({fieldOptions})
|
||||
}
|
||||
|
||||
private updateQueryDrafts = (
|
||||
queryID: string,
|
||||
nextQueryConfigFn: ((q: QueryConfig) => QueryConfig)
|
||||
) => {
|
||||
const {queryDrafts} = this.state
|
||||
const updatedQueryDrafts = queryDrafts.map(query => {
|
||||
if (query.id === queryID) {
|
||||
const nextQueryConfig = nextQueryConfigFn(query.queryConfig)
|
||||
|
||||
return {
|
||||
...query,
|
||||
query: buildQuery(
|
||||
TYPE_QUERY_CONFIG,
|
||||
getTimeRange(nextQueryConfig),
|
||||
nextQueryConfig
|
||||
),
|
||||
queryConfig: nextQueryConfig,
|
||||
}
|
||||
}
|
||||
return query
|
||||
})
|
||||
|
||||
this.setState({queryDrafts: updatedQueryDrafts})
|
||||
}
|
||||
}
|
|
@ -0,0 +1,87 @@
|
|||
// Libraries
|
||||
import uuid from 'uuid'
|
||||
import {get} from 'lodash'
|
||||
|
||||
// Utils
|
||||
import defaultQueryConfig from 'src/utils/defaultQueryConfig'
|
||||
import {getLineColors} from 'src/shared/constants/graphColorPalettes'
|
||||
import {
|
||||
getThresholdsListColors,
|
||||
getGaugeColors,
|
||||
} from 'src/shared/constants/thresholds'
|
||||
|
||||
// Types
|
||||
import {Cell, NewDefaultCell, CellQuery, QueryType} from 'src/types'
|
||||
import {TimeMachineState} from 'src/shared/utils/TimeMachineContainer'
|
||||
|
||||
export function intialStateFromCell(
|
||||
cell: Cell | NewDefaultCell
|
||||
): Partial<TimeMachineState> {
|
||||
const initialState: Partial<TimeMachineState> = {
|
||||
queryDrafts: initialQueryDrafts(cell),
|
||||
type: cell.type,
|
||||
fieldOptions: cell.fieldOptions,
|
||||
timeFormat: cell.timeFormat,
|
||||
decimalPlaces: cell.decimalPlaces,
|
||||
note: cell.note,
|
||||
noteVisibility: cell.noteVisibility,
|
||||
}
|
||||
|
||||
if (get(cell, 'queries.0.type') === QueryType.Flux) {
|
||||
initialState.script = get(cell, 'queries.0.query', '')
|
||||
}
|
||||
|
||||
if (cell.tableOptions) {
|
||||
initialState.tableOptions = cell.tableOptions
|
||||
}
|
||||
|
||||
const axes = (cell as Cell).axes
|
||||
const colors = (cell as Cell).colors
|
||||
|
||||
if (axes) {
|
||||
initialState.axes = axes
|
||||
}
|
||||
|
||||
if (colors) {
|
||||
initialState.gaugeColors = getGaugeColors(colors)
|
||||
initialState.thresholdsListColors = getThresholdsListColors(colors)
|
||||
initialState.lineColors = getLineColors(colors)
|
||||
}
|
||||
|
||||
return initialState
|
||||
}
|
||||
|
||||
function initialQueryDrafts(cell: Cell | NewDefaultCell): CellQuery[] {
|
||||
const queries: CellQuery[] = get(cell, 'queries', [])
|
||||
|
||||
if (!cell.queries.length) {
|
||||
return [defaultQueryDraft(QueryType.InfluxQL)]
|
||||
}
|
||||
|
||||
if (cell.queries[0].type === QueryType.Flux) {
|
||||
return [defaultQueryDraft(QueryType.Flux, cell.queries[0].source)]
|
||||
}
|
||||
|
||||
return queries.map(q => {
|
||||
const id = uuid.v4()
|
||||
const queryConfig = {...q.queryConfig, id}
|
||||
|
||||
return {...q, queryConfig, id}
|
||||
})
|
||||
}
|
||||
|
||||
export function defaultQueryDraft(
|
||||
type: QueryType,
|
||||
source: string = ''
|
||||
): CellQuery {
|
||||
const id = uuid.v4()
|
||||
const defaultDraft: CellQuery = {
|
||||
id,
|
||||
type,
|
||||
source,
|
||||
query: '',
|
||||
queryConfig: defaultQueryConfig({id}),
|
||||
}
|
||||
|
||||
return defaultDraft
|
||||
}
|
|
@ -1,11 +1,5 @@
|
|||
import {
|
||||
ThresholdColor,
|
||||
GaugeColor,
|
||||
LineColor,
|
||||
ColorNumber,
|
||||
ColorString,
|
||||
} from 'src/types/colors'
|
||||
import {TimeRange, CellQuery, QueryStatus, CellType, Axes} from 'src/types'
|
||||
import {ColorNumber, ColorString} from 'src/types/colors'
|
||||
import {CellType, Axes, Status} from 'src/types'
|
||||
import {
|
||||
DecimalPlaces,
|
||||
FieldOption,
|
||||
|
@ -21,23 +15,11 @@ export enum WriteDataMode {
|
|||
}
|
||||
|
||||
export interface DEState {
|
||||
queryDrafts: CellQuery[]
|
||||
timeRange: TimeRange
|
||||
queryStatus: QueryStatus
|
||||
script: string
|
||||
sourceLink: string
|
||||
thresholdsListType: ThresholdType
|
||||
thresholdsListColors: ThresholdColor[]
|
||||
gaugeColors: GaugeColor[]
|
||||
lineColors: LineColor[]
|
||||
visType: CellType
|
||||
axes: Axes
|
||||
tableOptions: TableOptions
|
||||
timeFormat: string
|
||||
decimalPlaces: DecimalPlaces
|
||||
fieldOptions: FieldOption[]
|
||||
note: string
|
||||
noteVisibility: NoteVisibility
|
||||
queryStatus: {
|
||||
queryID: string | null
|
||||
status: Status
|
||||
}
|
||||
}
|
||||
|
||||
export interface VisualizationOptions {
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
import {Service, Source, TimeRange, Query} from 'src/types'
|
||||
import {VisualizationOptions} from 'src/types/dataExplorer'
|
||||
|
||||
// function definitions
|
||||
export type OnDeleteFuncNode = (ids: DeleteFuncNodeArgs) => void
|
||||
|
@ -44,7 +43,6 @@ export interface Context {
|
|||
source: Source
|
||||
timeRange: TimeRange
|
||||
queries: Query[]
|
||||
visualizationOptions: VisualizationOptions
|
||||
}
|
||||
|
||||
export interface DeleteFuncNodeArgs {
|
||||
|
|
|
@ -4,6 +4,7 @@ import {Links, Organization, Role, Permission, User, Me} from './auth'
|
|||
import {
|
||||
PBCell,
|
||||
Cell,
|
||||
NewDefaultCell,
|
||||
CellQuery,
|
||||
Legend,
|
||||
Axes,
|
||||
|
@ -81,6 +82,7 @@ export {
|
|||
TemplateQuery,
|
||||
TemplateValue,
|
||||
Cell,
|
||||
NewDefaultCell,
|
||||
CellQuery,
|
||||
CellType,
|
||||
PBCell,
|
||||
|
|
|
@ -1,13 +1,10 @@
|
|||
import {QueryConfig, TimeRange} from 'src/types'
|
||||
import {DEState} from 'src/types/dataExplorer'
|
||||
import {TimeRange} from 'src/types'
|
||||
import {LogsState} from 'src/types/logs'
|
||||
|
||||
export interface LocalStorage {
|
||||
VERSION: VERSION
|
||||
app: App
|
||||
dashTimeV1: DashTimeV1
|
||||
dataExplorer: DEState
|
||||
dataExplorerQueryConfigs: DataExplorerQueryConfigs
|
||||
timeRange: TimeRange
|
||||
script: string
|
||||
logs: LogsState
|
||||
|
@ -24,10 +21,6 @@ export interface DashTimeV1 {
|
|||
ranges: DashboardTimeRange[]
|
||||
}
|
||||
|
||||
export interface DataExplorerQueryConfigs {
|
||||
[id: string]: QueryConfig
|
||||
}
|
||||
|
||||
interface DashboardTimeRange {
|
||||
dashboardID: number
|
||||
defaultGroupBy: string
|
||||
|
|
|
@ -2,74 +2,16 @@
|
|||
import reducer, {initialState} from 'src/dashboards/reducers/cellEditorOverlay'
|
||||
|
||||
// Actions
|
||||
import {
|
||||
loadCEO,
|
||||
clearCEO,
|
||||
renameCell,
|
||||
Action,
|
||||
} from 'src/dashboards/actions/cellEditorOverlay'
|
||||
import {
|
||||
updateVisType,
|
||||
updateThresholdsListColors,
|
||||
updateThresholdsListType,
|
||||
updateGaugeColors,
|
||||
updateLineColors,
|
||||
updateAxes,
|
||||
} from 'src/shared/actions/visualizations'
|
||||
import {
|
||||
updateEditorTimeRange,
|
||||
updateQueryDrafts,
|
||||
QueryUpdateState,
|
||||
} from 'src/shared/actions/queries'
|
||||
|
||||
// Constants
|
||||
import {DEFAULT_TABLE_OPTIONS} from 'src/dashboards/constants'
|
||||
import {
|
||||
validateGaugeColors,
|
||||
validateThresholdsListColors,
|
||||
getThresholdsListType,
|
||||
} from 'src/shared/constants/thresholds'
|
||||
import {validateLineColors} from 'src/shared/constants/graphColorPalettes'
|
||||
import {clearCEO, renameCell} from 'src/dashboards/actions/cellEditorOverlay'
|
||||
|
||||
// Fixtures
|
||||
import {cell, axes, timeRange, query} from 'test/fixtures'
|
||||
|
||||
// Types
|
||||
import {Cell} from 'src/types/dashboards'
|
||||
import {cell} from 'test/fixtures'
|
||||
|
||||
const defaultCell = {
|
||||
...cell,
|
||||
}
|
||||
|
||||
const defaultThresholdsListType = getThresholdsListType(defaultCell.colors)
|
||||
const defaultThresholdsListColors = validateThresholdsListColors(
|
||||
defaultCell.colors,
|
||||
defaultThresholdsListType
|
||||
)
|
||||
const defaultGaugeColors = validateGaugeColors(defaultCell.colors)
|
||||
const defaultLineColors = validateLineColors(defaultCell.colors)
|
||||
|
||||
let state
|
||||
|
||||
describe('Dashboards.Reducers.cellEditorOverlay', () => {
|
||||
it('should show cell editor overlay', () => {
|
||||
const actual = reducer(initialState, loadCEO(defaultCell, timeRange))
|
||||
const expected = {
|
||||
cell: defaultCell,
|
||||
gaugeColors: defaultGaugeColors,
|
||||
thresholdsListColors: defaultThresholdsListColors,
|
||||
thresholdsListType: defaultThresholdsListType,
|
||||
tableOptions: DEFAULT_TABLE_OPTIONS,
|
||||
timeRange,
|
||||
}
|
||||
|
||||
expect(actual.cell).toEqual(expected.cell)
|
||||
expect(actual.gaugeColors).toBe(expected.gaugeColors)
|
||||
expect(actual.thresholdsListColors).toBe(expected.thresholdsListColors)
|
||||
expect(actual.thresholdsListType).toBe(expected.thresholdsListType)
|
||||
expect(actual.timeRange).toBe(expected.timeRange)
|
||||
})
|
||||
|
||||
it('should hide cell editor overlay', () => {
|
||||
const actual = reducer(initialState, clearCEO())
|
||||
const expected = null
|
||||
|
@ -78,94 +20,10 @@ describe('Dashboards.Reducers.cellEditorOverlay', () => {
|
|||
expect(actual.timeRange).toBe(expected)
|
||||
})
|
||||
|
||||
it('should change the cell editor visualization type', () => {
|
||||
const action = updateVisType(
|
||||
defaultCell.type,
|
||||
QueryUpdateState.CEO
|
||||
) as Action
|
||||
const actual = reducer(initialState, action)
|
||||
const expected = defaultCell.type
|
||||
|
||||
expect(actual.cell.type).toBe(expected)
|
||||
})
|
||||
|
||||
it('should change the name of the cell', () => {
|
||||
const actual = reducer(initialState, renameCell(defaultCell.name))
|
||||
const expected = defaultCell.name
|
||||
|
||||
expect(actual.cell.name).toBe(expected)
|
||||
})
|
||||
|
||||
it('should update the cell single stat colors', () => {
|
||||
const action = updateThresholdsListColors(
|
||||
defaultThresholdsListColors,
|
||||
QueryUpdateState.CEO
|
||||
) as Action
|
||||
const actual = reducer(initialState, action)
|
||||
const expected = defaultThresholdsListColors
|
||||
|
||||
expect(actual.thresholdsListColors).toBe(expected)
|
||||
})
|
||||
|
||||
it('should toggle the single stat type', () => {
|
||||
const action = updateThresholdsListType(
|
||||
defaultThresholdsListType,
|
||||
QueryUpdateState.CEO
|
||||
) as Action
|
||||
const actual = reducer(initialState, action)
|
||||
const expected = defaultThresholdsListType
|
||||
|
||||
expect(actual.thresholdsListType).toBe(expected)
|
||||
})
|
||||
|
||||
it('should update the cell gauge colors', () => {
|
||||
const action = updateGaugeColors(
|
||||
defaultGaugeColors,
|
||||
QueryUpdateState.CEO
|
||||
) as Action
|
||||
const actual = reducer(initialState, action)
|
||||
const expected = defaultGaugeColors
|
||||
|
||||
expect(actual.gaugeColors).toBe(expected)
|
||||
})
|
||||
|
||||
it('should update the cell axes', () => {
|
||||
const action = updateAxes(axes, QueryUpdateState.CEO) as Action
|
||||
const actual = reducer(initialState, action)
|
||||
const expected = axes
|
||||
const actualCell = actual.cell as Cell
|
||||
|
||||
expect(actualCell.axes).toBe(expected)
|
||||
})
|
||||
|
||||
it('should update the cell line graph colors', () => {
|
||||
const action = updateLineColors(
|
||||
defaultLineColors,
|
||||
QueryUpdateState.CEO
|
||||
) as Action
|
||||
const actual = reducer(initialState, action)
|
||||
const expected = defaultLineColors
|
||||
|
||||
expect(actual.lineColors).toBe(expected)
|
||||
})
|
||||
|
||||
it('it can update a query', () => {
|
||||
state = {queryDrafts: [query]}
|
||||
const updatedQuery = {...query, source: '/chronograf/v1/sources/12'}
|
||||
const queries = [updatedQuery]
|
||||
const action = updateQueryDrafts(queries, QueryUpdateState.CEO) as Action
|
||||
const actual = reducer(state, action)
|
||||
expect(actual.queryDrafts).toEqual([updatedQuery])
|
||||
})
|
||||
|
||||
it('it can update a timeRange', () => {
|
||||
state = {timeRange}
|
||||
const updatedTimeRange = {...timeRange, lower: 'now() - 15m'}
|
||||
const action = updateEditorTimeRange(
|
||||
updatedTimeRange,
|
||||
QueryUpdateState.CEO
|
||||
) as Action
|
||||
const actual = reducer(state, action)
|
||||
expect(actual.timeRange).toEqual(updatedTimeRange)
|
||||
})
|
||||
})
|
||||
|
|
|
@ -1,90 +0,0 @@
|
|||
import React from 'react'
|
||||
import {DataExplorer} from 'src/data_explorer/containers/DataExplorer'
|
||||
import {CellType} from 'src/types'
|
||||
import {shallow} from 'enzyme'
|
||||
import {source, query, timeRange} from 'test/resources'
|
||||
|
||||
const queryConfigActions = {
|
||||
chooseNamespace: jest.fn(),
|
||||
chooseMeasurement: jest.fn(),
|
||||
chooseTag: jest.fn(),
|
||||
groupByTag: jest.fn(),
|
||||
addQuery: jest.fn(),
|
||||
toggleField: jest.fn(),
|
||||
groupByTime: jest.fn(),
|
||||
toggleTagAcceptance: jest.fn(),
|
||||
applyFuncsToField: jest.fn(),
|
||||
editRawTextAsync: jest.fn(),
|
||||
addInitialField: jest.fn(),
|
||||
editQueryStatus: jest.fn(),
|
||||
deleteQuery: jest.fn(),
|
||||
fill: jest.fn(),
|
||||
removeFuncs: jest.fn(),
|
||||
editRawText: jest.fn(),
|
||||
setTimeRange: jest.fn(),
|
||||
updateRawQuery: jest.fn(),
|
||||
updateQueryConfig: jest.fn(),
|
||||
timeShift: jest.fn(),
|
||||
}
|
||||
|
||||
const setup = () => {
|
||||
const props = {
|
||||
source,
|
||||
sources: [source],
|
||||
services: [],
|
||||
queryConfigs: [query],
|
||||
queryConfigActions,
|
||||
autoRefresh: 1000,
|
||||
handleChooseAutoRefresh: () => {},
|
||||
setTimeRange: () => {},
|
||||
timeRange,
|
||||
manualRefresh: 0,
|
||||
dashboards: [],
|
||||
onManualRefresh: () => {},
|
||||
errorThrownAction: () => {},
|
||||
writeLineProtocol: () => {},
|
||||
handleGetDashboards: () => [],
|
||||
addDashboardCell: jest.fn(() => Promise.resolve()),
|
||||
updateQueryDrafts: jest.fn(() => Promise.resolve()),
|
||||
loadDE: jest.fn(() => Promise.resolve()),
|
||||
addQuery: jest.fn(() => Promise.resolve()),
|
||||
deleteQuery: jest.fn(() => Promise.resolve()),
|
||||
queryDrafts: [],
|
||||
editQueryStatus: jest.fn(() => Promise.resolve()),
|
||||
queryStatus: null,
|
||||
fluxLinks: null,
|
||||
script: '',
|
||||
updateScript: jest.fn(),
|
||||
fetchServicesAsync: jest.fn(),
|
||||
notify: jest.fn(),
|
||||
sourceLink: '',
|
||||
updateSourceLink: jest.fn(),
|
||||
thresholdsListType: null,
|
||||
thresholdsListColors: [],
|
||||
gaugeColors: [],
|
||||
lineColors: [],
|
||||
visType: CellType.Line,
|
||||
axes: null,
|
||||
tableOptions: null,
|
||||
timeFormat: '',
|
||||
decimalPlaces: null,
|
||||
fieldOptions: [],
|
||||
note: '',
|
||||
noteVisibility: null,
|
||||
sendDashboardCell: jest.fn(() => Promise.resolve()),
|
||||
}
|
||||
|
||||
const wrapper = shallow(<DataExplorer {...props} />)
|
||||
return {
|
||||
wrapper,
|
||||
}
|
||||
}
|
||||
|
||||
describe('DataExplorer.Containers.DataExplorer', () => {
|
||||
describe('rendering', () => {
|
||||
it('renders without errors', () => {
|
||||
const {wrapper} = setup()
|
||||
expect(wrapper.exists()).toBe(true)
|
||||
})
|
||||
})
|
||||
})
|
|
@ -1,40 +0,0 @@
|
|||
import reducer from 'src/data_explorer/reducers/queries'
|
||||
|
||||
import {
|
||||
updateQueryDrafts,
|
||||
updateEditorTimeRange,
|
||||
QueryUpdateState,
|
||||
} from 'src/shared/actions/queries'
|
||||
import {loadDE, Action} from 'src/data_explorer/actions/queries'
|
||||
|
||||
import {query, timeRange} from 'test/fixtures'
|
||||
|
||||
let state
|
||||
|
||||
describe('DataExplorer.Reducers.Queries', () => {
|
||||
it('loads the timeRange and queries', () => {
|
||||
const actual = reducer(state, loadDE([query], timeRange))
|
||||
expect(actual.queryDrafts).toEqual([query])
|
||||
expect(actual.timeRange).toEqual(timeRange)
|
||||
})
|
||||
|
||||
it('it can update a query', () => {
|
||||
state = {queryDrafts: [query]}
|
||||
const updatedQuery = {...query, source: '/chronograf/v1/sources/12'}
|
||||
const queries = [updatedQuery]
|
||||
const action = updateQueryDrafts(queries, QueryUpdateState.DE) as Action
|
||||
const actual = reducer(state, action)
|
||||
expect(actual.queryDrafts).toEqual([updatedQuery])
|
||||
})
|
||||
|
||||
it('it can update a timeRange', () => {
|
||||
state = {timeRange}
|
||||
const updatedTimeRange = {...timeRange, lower: 'now() - 15m'}
|
||||
const action = updateEditorTimeRange(
|
||||
updatedTimeRange,
|
||||
QueryUpdateState.DE
|
||||
) as Action
|
||||
const actual = reducer(state, action)
|
||||
expect(actual.timeRange).toEqual(updatedTimeRange)
|
||||
})
|
||||
})
|
|
@ -1,599 +0,0 @@
|
|||
import reducer from 'src/data_explorer/reducers/queryConfigs'
|
||||
|
||||
import defaultQueryConfig from 'src/utils/defaultQueryConfig'
|
||||
import {
|
||||
fill,
|
||||
timeShift,
|
||||
chooseTag,
|
||||
groupByTag,
|
||||
groupByTime,
|
||||
toggleField,
|
||||
removeFuncs,
|
||||
editRawText,
|
||||
updateRawQuery,
|
||||
editQueryStatus,
|
||||
chooseNamespace,
|
||||
chooseMeasurement,
|
||||
applyFuncsToField,
|
||||
addInitialField,
|
||||
updateQueryConfig,
|
||||
toggleTagAcceptance,
|
||||
ActionAddQuery,
|
||||
} from 'src/data_explorer/actions/view'
|
||||
|
||||
import {LINEAR, NULL_STRING} from 'src/shared/constants/queryFillOptions'
|
||||
|
||||
const fakeAddQueryAction = (queryID: string): ActionAddQuery => {
|
||||
return {
|
||||
type: 'DE_ADD_QUERY',
|
||||
payload: {
|
||||
queryID,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
function buildInitialState(queryID, params?) {
|
||||
return {
|
||||
...defaultQueryConfig({
|
||||
id: queryID,
|
||||
}),
|
||||
...params,
|
||||
}
|
||||
}
|
||||
|
||||
describe('Chronograf.Reducers.DataExplorer.queryConfigs', () => {
|
||||
const queryID = '123'
|
||||
|
||||
it('can add a query', () => {
|
||||
const state = reducer({}, fakeAddQueryAction(queryID))
|
||||
|
||||
const actual = state[queryID]
|
||||
const expected = defaultQueryConfig({
|
||||
id: queryID,
|
||||
})
|
||||
expect(actual).toEqual(expected)
|
||||
})
|
||||
|
||||
describe('choosing db, rp, and measurement', () => {
|
||||
let state
|
||||
beforeEach(() => {
|
||||
state = reducer({}, fakeAddQueryAction(queryID))
|
||||
})
|
||||
|
||||
it('sets the db and rp', () => {
|
||||
const newState = reducer(
|
||||
state,
|
||||
chooseNamespace(queryID, {
|
||||
database: 'telegraf',
|
||||
retentionPolicy: 'monitor',
|
||||
})
|
||||
)
|
||||
|
||||
expect(newState[queryID].database).toBe('telegraf')
|
||||
expect(newState[queryID].retentionPolicy).toBe('monitor')
|
||||
})
|
||||
|
||||
it('sets the measurement', () => {
|
||||
const newState = reducer(state, chooseMeasurement(queryID, 'mem'))
|
||||
|
||||
expect(newState[queryID].measurement).toBe('mem')
|
||||
})
|
||||
})
|
||||
|
||||
describe('a query has measurements and fields', () => {
|
||||
let state
|
||||
beforeEach(() => {
|
||||
const one = reducer({}, fakeAddQueryAction(queryID))
|
||||
const two = reducer(
|
||||
one,
|
||||
chooseNamespace(queryID, {
|
||||
database: '_internal',
|
||||
retentionPolicy: 'daily',
|
||||
})
|
||||
)
|
||||
const three = reducer(two, chooseMeasurement(queryID, 'disk'))
|
||||
const field = {
|
||||
value: 'a great field',
|
||||
type: 'field',
|
||||
}
|
||||
const groupBy = {}
|
||||
|
||||
state = reducer(three, addInitialField(queryID, field, groupBy))
|
||||
})
|
||||
|
||||
describe('choosing a new namespace', () => {
|
||||
it('clears out the old measurement and fields', () => {
|
||||
// what about tags?
|
||||
expect(state[queryID].measurement).toBe('disk')
|
||||
expect(state[queryID].fields.length).toBe(1)
|
||||
|
||||
const newState = reducer(
|
||||
state,
|
||||
chooseNamespace(queryID, {
|
||||
database: 'newdb',
|
||||
retentionPolicy: 'newrp',
|
||||
})
|
||||
)
|
||||
|
||||
expect(newState[queryID].measurement).toBe(null)
|
||||
expect(newState[queryID].fields.length).toBe(0)
|
||||
})
|
||||
})
|
||||
|
||||
describe('choosing a new measurement', () => {
|
||||
it('leaves the namespace and clears out the old fields', () => {
|
||||
// what about tags?
|
||||
expect(state[queryID].fields.length).toBe(1)
|
||||
|
||||
const newState = reducer(
|
||||
state,
|
||||
chooseMeasurement(queryID, 'newmeasurement')
|
||||
)
|
||||
|
||||
expect(state[queryID].database).toBe(newState[queryID].database)
|
||||
expect(state[queryID].retentionPolicy).toBe(
|
||||
newState[queryID].retentionPolicy
|
||||
)
|
||||
expect(newState[queryID].fields.length).toBe(0)
|
||||
})
|
||||
})
|
||||
|
||||
describe('DE_TOGGLE_FIELD', () => {
|
||||
it('can toggle multiple fields', () => {
|
||||
expect(state[queryID].fields.length).toBe(1)
|
||||
|
||||
const newState = reducer(
|
||||
state,
|
||||
toggleField(queryID, {
|
||||
value: 'f2',
|
||||
type: 'field',
|
||||
})
|
||||
)
|
||||
|
||||
expect(newState[queryID].fields.length).toBe(2)
|
||||
expect(newState[queryID].fields[1].alias).toEqual('mean_f2')
|
||||
expect(newState[queryID].fields[1].args).toEqual([
|
||||
{
|
||||
value: 'f2',
|
||||
type: 'field',
|
||||
},
|
||||
])
|
||||
expect(newState[queryID].fields[1].value).toEqual('mean')
|
||||
})
|
||||
|
||||
it('applies a func to newly selected fields', () => {
|
||||
expect(state[queryID].fields.length).toBe(1)
|
||||
expect(state[queryID].fields[0].type).toBe('func')
|
||||
expect(state[queryID].fields[0].value).toBe('mean')
|
||||
|
||||
const newState = reducer(
|
||||
state,
|
||||
toggleField(queryID, {
|
||||
value: 'f2',
|
||||
type: 'field',
|
||||
})
|
||||
)
|
||||
|
||||
expect(newState[queryID].fields[1].value).toBe('mean')
|
||||
expect(newState[queryID].fields[1].alias).toBe('mean_f2')
|
||||
expect(newState[queryID].fields[1].args).toEqual([
|
||||
{
|
||||
value: 'f2',
|
||||
type: 'field',
|
||||
},
|
||||
])
|
||||
expect(newState[queryID].fields[1].type).toBe('func')
|
||||
})
|
||||
|
||||
it('adds the field property to query config if not found', () => {
|
||||
delete state[queryID].fields
|
||||
expect(state[queryID].fields).toBe(undefined)
|
||||
|
||||
const newState = reducer(
|
||||
state,
|
||||
toggleField(queryID, {
|
||||
value: 'fk1',
|
||||
type: 'field',
|
||||
})
|
||||
)
|
||||
|
||||
expect(newState[queryID].fields.length).toBe(1)
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe('DE_APPLY_FUNCS_TO_FIELD', () => {
|
||||
it('applies new functions to a field', () => {
|
||||
const f1 = {
|
||||
value: 'f1',
|
||||
type: 'field',
|
||||
}
|
||||
const f2 = {
|
||||
value: 'f2',
|
||||
type: 'field',
|
||||
}
|
||||
|
||||
const initialState = {
|
||||
[queryID]: buildInitialState(queryID, {
|
||||
id: '123',
|
||||
database: 'db1',
|
||||
measurement: 'm1',
|
||||
fields: [
|
||||
{
|
||||
value: 'fn1',
|
||||
type: 'func',
|
||||
args: [f1],
|
||||
alias: `fn1_${f1.value}`,
|
||||
},
|
||||
{
|
||||
value: 'fn1',
|
||||
type: 'func',
|
||||
args: [f2],
|
||||
alias: `fn1_${f2.value}`,
|
||||
},
|
||||
{
|
||||
value: 'fn2',
|
||||
type: 'func',
|
||||
args: [f1],
|
||||
alias: `fn2_${f1.value}`,
|
||||
},
|
||||
],
|
||||
}),
|
||||
}
|
||||
|
||||
const action = applyFuncsToField(queryID, {
|
||||
field: {
|
||||
value: 'f1',
|
||||
type: 'field',
|
||||
},
|
||||
funcs: [
|
||||
{
|
||||
value: 'fn3',
|
||||
type: 'func',
|
||||
},
|
||||
{
|
||||
value: 'fn4',
|
||||
type: 'func',
|
||||
},
|
||||
],
|
||||
})
|
||||
|
||||
const nextState = reducer(initialState, action)
|
||||
|
||||
expect(nextState[queryID].fields).toEqual([
|
||||
{
|
||||
value: 'fn3',
|
||||
type: 'func',
|
||||
args: [f1],
|
||||
alias: `fn3_${f1.value}`,
|
||||
},
|
||||
{
|
||||
value: 'fn4',
|
||||
type: 'func',
|
||||
args: [f1],
|
||||
alias: `fn4_${f1.value}`,
|
||||
},
|
||||
{
|
||||
value: 'fn1',
|
||||
type: 'func',
|
||||
args: [f2],
|
||||
alias: `fn1_${f2.value}`,
|
||||
},
|
||||
])
|
||||
})
|
||||
})
|
||||
|
||||
describe('DE_REMOVE_FUNCS', () => {
|
||||
it('removes all functions and group by time when one field has no funcs applied', () => {
|
||||
const f1 = {
|
||||
value: 'f1',
|
||||
type: 'field',
|
||||
}
|
||||
const f2 = {
|
||||
value: 'f2',
|
||||
type: 'field',
|
||||
}
|
||||
const fields = [
|
||||
{
|
||||
value: 'fn1',
|
||||
type: 'func',
|
||||
args: [f1],
|
||||
alias: `fn1_${f1.value}`,
|
||||
},
|
||||
{
|
||||
value: 'fn1',
|
||||
type: 'func',
|
||||
args: [f2],
|
||||
alias: `fn1_${f2.value}`,
|
||||
},
|
||||
]
|
||||
const groupBy = {
|
||||
time: '1m',
|
||||
tags: [],
|
||||
}
|
||||
|
||||
const initialState = {
|
||||
[queryID]: buildInitialState(queryID, {
|
||||
id: '123',
|
||||
database: 'db1',
|
||||
measurement: 'm1',
|
||||
fields,
|
||||
groupBy,
|
||||
}),
|
||||
}
|
||||
|
||||
const action = removeFuncs(queryID, fields, groupBy)
|
||||
|
||||
const nextState = reducer(initialState, action)
|
||||
const actual = nextState[queryID].fields
|
||||
const expected = [f1, f2]
|
||||
|
||||
expect(actual).toEqual(expected)
|
||||
expect(nextState[queryID].groupBy.time).toBe(null)
|
||||
})
|
||||
})
|
||||
|
||||
describe('DE_CHOOSE_TAG', () => {
|
||||
it('adds a tag key/value to the query', () => {
|
||||
const initialState = {
|
||||
[queryID]: buildInitialState(queryID, {
|
||||
tags: {
|
||||
k1: ['v0'],
|
||||
k2: ['foo'],
|
||||
},
|
||||
}),
|
||||
}
|
||||
|
||||
const action = chooseTag(queryID, {
|
||||
key: 'k1',
|
||||
value: 'v1',
|
||||
})
|
||||
|
||||
const nextState = reducer(initialState, action)
|
||||
|
||||
expect(nextState[queryID].tags).toEqual({
|
||||
k1: ['v0', 'v1'],
|
||||
k2: ['foo'],
|
||||
})
|
||||
})
|
||||
|
||||
it("creates a new entry if it's the first key", () => {
|
||||
const initialState = {
|
||||
[queryID]: buildInitialState(queryID, {
|
||||
tags: {},
|
||||
}),
|
||||
}
|
||||
const action = chooseTag(queryID, {
|
||||
key: 'k1',
|
||||
value: 'v1',
|
||||
})
|
||||
|
||||
const nextState = reducer(initialState, action)
|
||||
|
||||
expect(nextState[queryID].tags).toEqual({
|
||||
k1: ['v1'],
|
||||
})
|
||||
})
|
||||
|
||||
it('removes a value that is already in the list', () => {
|
||||
const initialState = {
|
||||
[queryID]: buildInitialState(queryID, {
|
||||
tags: {
|
||||
k1: ['v1'],
|
||||
},
|
||||
}),
|
||||
}
|
||||
const action = chooseTag(queryID, {
|
||||
key: 'k1',
|
||||
value: 'v1',
|
||||
})
|
||||
|
||||
const nextState = reducer(initialState, action)
|
||||
|
||||
// TODO: this should probably remove the `k1` property entirely from the tags object
|
||||
expect(nextState[queryID].tags).toEqual({})
|
||||
})
|
||||
})
|
||||
|
||||
describe('DE_GROUP_BY_TAG', () => {
|
||||
it('adds a tag key/value to the query', () => {
|
||||
const initialState = {
|
||||
[queryID]: buildInitialState(queryID, {
|
||||
id: '123',
|
||||
database: 'db1',
|
||||
measurement: 'm1',
|
||||
fields: [],
|
||||
tags: {},
|
||||
groupBy: {
|
||||
tags: [],
|
||||
time: null,
|
||||
},
|
||||
}),
|
||||
}
|
||||
const action = groupByTag(queryID, 'k1')
|
||||
|
||||
const nextState = reducer(initialState, action)
|
||||
|
||||
expect(nextState[queryID].groupBy).toEqual({
|
||||
time: null,
|
||||
tags: ['k1'],
|
||||
})
|
||||
})
|
||||
|
||||
it('removes a tag if the given tag key is already in the GROUP BY list', () => {
|
||||
const query = {
|
||||
id: '123',
|
||||
database: 'db1',
|
||||
measurement: 'm1',
|
||||
fields: [],
|
||||
tags: {},
|
||||
groupBy: {
|
||||
tags: ['k1'],
|
||||
time: null,
|
||||
},
|
||||
}
|
||||
|
||||
const initialState = {
|
||||
[queryID]: buildInitialState(queryID, query),
|
||||
}
|
||||
const action = groupByTag(queryID, 'k1')
|
||||
|
||||
const nextState = reducer(initialState, action)
|
||||
|
||||
expect(nextState[queryID].groupBy).toEqual({
|
||||
time: null,
|
||||
tags: [],
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe('DE_TOGGLE_TAG_ACCEPTANCE', () => {
|
||||
it('it toggles areTagsAccepted', () => {
|
||||
const initialState = {
|
||||
[queryID]: buildInitialState(queryID),
|
||||
}
|
||||
const action = toggleTagAcceptance(queryID)
|
||||
|
||||
const nextState = reducer(initialState, action)
|
||||
|
||||
expect(nextState[queryID].areTagsAccepted).toBe(
|
||||
!initialState[queryID].areTagsAccepted
|
||||
)
|
||||
})
|
||||
})
|
||||
|
||||
describe('DE_GROUP_BY_TIME', () => {
|
||||
it('applys the appropriate group by time', () => {
|
||||
const time = '100y'
|
||||
const initialState = {
|
||||
[queryID]: buildInitialState(queryID),
|
||||
}
|
||||
|
||||
const action = groupByTime(queryID, time)
|
||||
|
||||
const nextState = reducer(initialState, action)
|
||||
|
||||
expect(nextState[queryID].groupBy.time).toBe(time)
|
||||
})
|
||||
})
|
||||
|
||||
it('updates entire config', () => {
|
||||
const initialState = {
|
||||
[queryID]: buildInitialState(queryID),
|
||||
}
|
||||
const id = {id: queryID}
|
||||
const expected = defaultQueryConfig(id)
|
||||
const action = updateQueryConfig(expected)
|
||||
|
||||
const nextState = reducer(initialState, action)
|
||||
|
||||
expect(nextState[queryID]).toEqual(expected)
|
||||
})
|
||||
|
||||
it("updates a query's raw text", () => {
|
||||
const initialState = {
|
||||
[queryID]: buildInitialState(queryID),
|
||||
}
|
||||
const text = 'foo'
|
||||
const action = updateRawQuery(queryID, text)
|
||||
|
||||
const nextState = reducer(initialState, action)
|
||||
|
||||
expect(nextState[queryID].rawText).toBe('foo')
|
||||
})
|
||||
|
||||
it("updates a query's raw status", () => {
|
||||
const initialState = {
|
||||
[queryID]: buildInitialState(queryID),
|
||||
}
|
||||
const status = {success: 'Your query was very nice'}
|
||||
const action = editQueryStatus(queryID, status)
|
||||
|
||||
const nextState = reducer(initialState, action)
|
||||
|
||||
expect(nextState[queryID].status).toEqual(status)
|
||||
})
|
||||
|
||||
describe('DE_FILL', () => {
|
||||
it('applies an explicit fill when group by time is used', () => {
|
||||
const initialState = {
|
||||
[queryID]: buildInitialState(queryID),
|
||||
}
|
||||
const time = '10s'
|
||||
const action = groupByTime(queryID, time)
|
||||
|
||||
const nextState = reducer(initialState, action)
|
||||
|
||||
expect(nextState[queryID].fill).toBe(NULL_STRING)
|
||||
})
|
||||
|
||||
it('updates fill to non-null-string non-number string value', () => {
|
||||
const initialState = {
|
||||
[queryID]: buildInitialState(queryID),
|
||||
}
|
||||
const action = fill(queryID, LINEAR)
|
||||
|
||||
const nextState = reducer(initialState, action)
|
||||
|
||||
expect(nextState[queryID].fill).toBe(LINEAR)
|
||||
})
|
||||
|
||||
it('updates fill to string integer value', () => {
|
||||
const initialState = {
|
||||
[queryID]: buildInitialState(queryID),
|
||||
}
|
||||
const INT_STRING = '1337'
|
||||
const action = fill(queryID, INT_STRING)
|
||||
|
||||
const nextState = reducer(initialState, action)
|
||||
|
||||
expect(nextState[queryID].fill).toBe(INT_STRING)
|
||||
})
|
||||
|
||||
it('updates fill to string float value', () => {
|
||||
const initialState = {
|
||||
[queryID]: buildInitialState(queryID),
|
||||
}
|
||||
const FLOAT_STRING = '1.337'
|
||||
const action = fill(queryID, FLOAT_STRING)
|
||||
|
||||
const nextState = reducer(initialState, action)
|
||||
|
||||
expect(nextState[queryID].fill).toBe(FLOAT_STRING)
|
||||
})
|
||||
})
|
||||
|
||||
describe('DE_TIME_SHIFT', () => {
|
||||
it('can shift the time', () => {
|
||||
const initialState = {
|
||||
[queryID]: buildInitialState(queryID),
|
||||
}
|
||||
|
||||
const shift = {
|
||||
quantity: '1',
|
||||
unit: 'd',
|
||||
duration: '1d',
|
||||
label: 'label',
|
||||
}
|
||||
|
||||
const action = timeShift(queryID, shift)
|
||||
const nextState = reducer(initialState, action)
|
||||
|
||||
expect(nextState[queryID].shifts).toEqual([shift])
|
||||
})
|
||||
})
|
||||
|
||||
describe('DE_EDIT_RAW_TEXT', () => {
|
||||
it('can edit the raw text', () => {
|
||||
const initialState = {
|
||||
[queryID]: buildInitialState(queryID),
|
||||
}
|
||||
|
||||
const rawText = 'im the raw text'
|
||||
const action = editRawText(queryID, rawText)
|
||||
const nextState = reducer(initialState, action)
|
||||
|
||||
expect(nextState[queryID].rawText).toEqual(rawText)
|
||||
})
|
||||
})
|
||||
})
|
10
ui/yarn.lock
10
ui/yarn.lock
|
@ -2126,6 +2126,10 @@ create-react-class@^15.5.1, create-react-class@^15.5.2, create-react-class@^15.5
|
|||
loose-envify "^1.3.1"
|
||||
object-assign "^4.1.1"
|
||||
|
||||
create-react-context@^0.1.5:
|
||||
version "0.1.6"
|
||||
resolved "https://registry.yarnpkg.com/create-react-context/-/create-react-context-0.1.6.tgz#0f425931d907741127acc6e31acb4f9015dd9fdc"
|
||||
|
||||
cross-spawn@^3.0.0:
|
||||
version "3.0.1"
|
||||
resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-3.0.1.tgz#1256037ecb9f0c5f79e3d6ef135e30770184b982"
|
||||
|
@ -8722,6 +8726,12 @@ unset-value@^1.0.0:
|
|||
has-value "^0.3.1"
|
||||
isobject "^3.0.0"
|
||||
|
||||
unstated@^2.1.1:
|
||||
version "2.1.1"
|
||||
resolved "https://registry.yarnpkg.com/unstated/-/unstated-2.1.1.tgz#36b124dfb2e7a12d39d0bb9c46dfb6e51276e3a2"
|
||||
dependencies:
|
||||
create-react-context "^0.1.5"
|
||||
|
||||
upath@^1.0.5:
|
||||
version "1.1.0"
|
||||
resolved "https://registry.yarnpkg.com/upath/-/upath-1.1.0.tgz#35256597e46a581db4793d0ce47fa9aebfc9fabd"
|
||||
|
|
Loading…
Reference in New Issue