Skip to content

Commit

Permalink
Merge pull request #12523 from influxdata/explorer/save-as-variable
Browse files Browse the repository at this point in the history
feat(explorer): add save as variable overlay
  • Loading branch information
AlirieGray authored Mar 13, 2019
2 parents 8121380 + 4646291 commit f2f9d4f
Show file tree
Hide file tree
Showing 7 changed files with 231 additions and 103 deletions.
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@
1. [12524](https://github.com/influxdata/influxdb/pull/12524): Add ability to import a dashboard from org view
1. [12531](https://github.com/influxdata/influxdb/pull/12531): Add ability to export a dashboard and a task

1. [12523](https://github.com/influxdata/influxdb/pull/12523): Add ability to save a query as a variable from the Data Explorer.

### Bug Fixes

### UI Improvements
Expand Down
12 changes: 12 additions & 0 deletions ui/src/dataExplorer/components/SaveAsButton.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import React, {PureComponent} from 'react'
// Components
import SaveAsCellForm from 'src/dataExplorer/components/SaveAsCellForm'
import SaveAsTaskForm from 'src/dataExplorer/components/SaveAsTaskForm'
import SaveAsVariable from 'src/dataExplorer/components/SaveAsVariable'
import {IconFont, Button, ComponentColor} from '@influxdata/clockface'
import {Radio, Overlay} from 'src/clockface'

Expand All @@ -13,6 +14,7 @@ import 'src/dataExplorer/components/SaveAsButton.scss'
enum SaveAsOption {
Dashboard = 'dashboard',
Task = 'task',
Variable = 'variable',
}

interface Props {}
Expand Down Expand Up @@ -65,6 +67,14 @@ class SaveAsButton extends PureComponent<Props, State> {
>
Task
</Radio.Button>
<Radio.Button
active={saveAsOption === SaveAsOption.Variable}
value={SaveAsOption.Variable}
onClick={this.handleSetSaveAsOption}
data-testid="variable-radio-button"
>
Variable
</Radio.Button>
</Radio>
</div>
{this.saveAsForm}
Expand All @@ -82,6 +92,8 @@ class SaveAsButton extends PureComponent<Props, State> {
return <SaveAsCellForm dismiss={this.handleHideOverlay} />
} else if (saveAsOption === SaveAsOption.Task) {
return <SaveAsTaskForm dismiss={this.handleHideOverlay} />
} else if (saveAsOption === SaveAsOption.Variable) {
return <SaveAsVariable onHideOverlay={this.handleHideOverlay} />
}
}

Expand Down
64 changes: 64 additions & 0 deletions ui/src/dataExplorer/components/SaveAsVariable.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
// Libraries
import React, {PureComponent} from 'react'
import {connect} from 'react-redux'

// Components
import VariableForm from 'src/organizations/components/VariableForm'

// Utils
import {getActiveOrg} from 'src/organizations/selectors'
import {createVariable} from 'src/variables/actions'

// Types
import {AppState} from 'src/types/v2'
import {Variable} from '@influxdata/influx'
import {getActiveQuery} from 'src/timeMachine/selectors'

interface OwnProps {
onHideOverlay: () => void
}

interface DispatchProps {
onCreateVariable: (variable: Variable) => void
}

interface StateProps {
initialScript?: string
orgID: string
}

type Props = StateProps & DispatchProps & OwnProps

class SaveAsVariable extends PureComponent<Props> {
render() {
const {orgID, onHideOverlay, onCreateVariable, initialScript} = this.props

return (
<VariableForm
orgID={orgID}
onHideOverlay={onHideOverlay}
onCreateVariable={onCreateVariable}
initialScript={initialScript}
/>
)
}
}

const mstp = (state: AppState): StateProps => {
const activeQuery = getActiveQuery(state)
const activeOrgID = getActiveOrg(state).id

return {
orgID: activeOrgID,
initialScript: activeQuery.text,
}
}

const mdtp = {
onCreateVariable: createVariable,
}

export default connect<StateProps, DispatchProps, OwnProps>(
mstp,
mdtp
)(SaveAsVariable)
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,17 @@ exports[`SaveAsButton rendering renders 1`] = `
>
Task
</RadioButton>
<RadioButton
active={false}
data-testid="variable-radio-button"
disabled={false}
disabledTitleText="This option is disabled"
onClick={[Function]}
testID="radio-button"
value="variable"
>
Variable
</RadioButton>
</Radio>
</div>
<Connect(SaveAsCellForm)
Expand Down
118 changes: 16 additions & 102 deletions ui/src/organizations/components/CreateVariableOverlay.tsx
Original file line number Diff line number Diff line change
@@ -1,125 +1,39 @@
// Libraries
import React, {PureComponent, ChangeEvent} from 'react'
import React, {PureComponent} from 'react'

// Styles
import 'src/organizations/components/CreateVariableOverlay.scss'

// Components
import {Form, Input, Overlay} from 'src/clockface'
import {Button} from '@influxdata/clockface'
import FluxEditor from 'src/shared/components/FluxEditor'
import {Overlay} from 'src/clockface'
import VariableForm from 'src/organizations/components/VariableForm'

// Types
import {Variable} from '@influxdata/influx'
import {
ComponentColor,
ComponentStatus,
ButtonType,
} from '@influxdata/clockface'

interface Props {
onCreateVariable: (variable: Variable) => void
onCloseModal: () => void
onHideOverlay: () => void
orgID: string
initialScript?: string
}

interface State {
name: string
script: string
nameInputStatus: ComponentStatus
errorMessage: string
}

export default class CreateOrgOverlay extends PureComponent<Props, State> {
constructor(props) {
super(props)
this.state = {
name: '',
script: '',
nameInputStatus: ComponentStatus.Default,
errorMessage: '',
}
}

export default class CreateVariableOverlay extends PureComponent<Props> {
public render() {
const {onCloseModal} = this.props
const {nameInputStatus, name, script} = this.state
const {onHideOverlay, onCreateVariable, orgID, initialScript} = this.props

return (
<Overlay.Container maxWidth={1000}>
<Overlay.Heading
title="Create Variable"
onDismiss={this.props.onCloseModal}
/>

<Form onSubmit={this.handleSubmit}>
<Overlay.Body>
<div className="overlay-flux-editor--spacing">
<Form.Element label="Name">
<Input
placeholder="Give your variable a name"
name="name"
autoFocus={true}
value={name}
onChange={this.handleChangeInput}
status={nameInputStatus}
/>
</Form.Element>
</div>

<Form.Element label="Value">
<div className="overlay-flux-editor">
<FluxEditor
script={script}
onChangeScript={this.handleChangeScript}
visibility="visible"
suggestions={[]}
/>
</div>
</Form.Element>

<Overlay.Footer>
<Button
text="Cancel"
color={ComponentColor.Danger}
onClick={onCloseModal}
/>
<Button
text="Create"
type={ButtonType.Submit}
color={ComponentColor.Primary}
/>
</Overlay.Footer>
</Overlay.Body>
</Form>
<Overlay.Heading title="Create Variable" onDismiss={onHideOverlay} />
<Overlay.Body>
<VariableForm
onCreateVariable={onCreateVariable}
onHideOverlay={onHideOverlay}
orgID={orgID}
initialScript={initialScript}
/>
</Overlay.Body>
</Overlay.Container>
)
}

private handleSubmit = (): void => {
const {onCreateVariable, orgID, onCloseModal} = this.props

onCreateVariable({
name: this.state.name,
orgID,
arguments: {
type: 'query',
values: {query: this.state.script, language: 'flux'},
},
})

onCloseModal()
}

private handleChangeInput = (e: ChangeEvent<HTMLInputElement>) => {
const {value, name} = e.target

const newState = {...this.state}
newState[name] = value
this.setState(newState)
}

private handleChangeScript = (script: string): void => {
this.setState({script})
}
}
125 changes: 125 additions & 0 deletions ui/src/organizations/components/VariableForm.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,125 @@
// Libraries
import React, {PureComponent, ChangeEvent} from 'react'

// Styles
import 'src/organizations/components/CreateVariableOverlay.scss'

// Components
import {Form, Input, Grid} from 'src/clockface'
import {Button} from '@influxdata/clockface'
import FluxEditor from 'src/shared/components/FluxEditor'

// Types
import {Variable} from '@influxdata/influx'
import {
ComponentColor,
ComponentStatus,
ButtonType,
} from '@influxdata/clockface'

interface Props {
onCreateVariable: (variable: Variable) => void
onHideOverlay?: () => void
orgID: string
initialScript?: string
}

interface State {
name: string
script: string
nameInputStatus: ComponentStatus
errorMessage: string
}

export default class CreateOrgOverlay extends PureComponent<Props, State> {
constructor(props) {
super(props)
this.state = {
name: '',
script: this.props.initialScript || '',
nameInputStatus: ComponentStatus.Default,
errorMessage: '',
}
}

public render() {
const {onHideOverlay} = this.props
const {nameInputStatus, name, script} = this.state

return (
<Form onSubmit={this.handleSubmit}>
<Grid>
<Grid.Row>
<Grid.Column>
<div className="overlay-flux-editor--spacing">
<Form.Element label="Name">
<Input
placeholder="Give your variable a name"
name="name"
autoFocus={true}
value={name}
onChange={this.handleChangeInput}
status={nameInputStatus}
/>
</Form.Element>
</div>
</Grid.Column>
<Grid.Column>
<Form.Element label="Value">
<div className="overlay-flux-editor">
<FluxEditor
script={script}
onChangeScript={this.handleChangeScript}
visibility="visible"
suggestions={[]}
/>
</div>
</Form.Element>
</Grid.Column>
<Grid.Column>
<Form.Footer>
<Button
text="Cancel"
color={ComponentColor.Danger}
onClick={onHideOverlay}
/>
<Button
text="Create"
type={ButtonType.Submit}
color={ComponentColor.Primary}
/>
</Form.Footer>
</Grid.Column>
</Grid.Row>
</Grid>
</Form>
)
}

private handleSubmit = (): void => {
const {onCreateVariable, orgID, onHideOverlay} = this.props

onCreateVariable({
name: this.state.name,
orgID,
arguments: {
type: 'query',
values: {query: this.state.script, language: 'flux'},
},
})

onHideOverlay()
}

private handleChangeInput = (e: ChangeEvent<HTMLInputElement>) => {
const {value, name} = e.target

const newState = {...this.state}
newState[name] = value
this.setState(newState)
}

private handleChangeScript = (script: string): void => {
this.setState({script})
}
}
Loading

0 comments on commit f2f9d4f

Please sign in to comment.