Skip to content

Commit

Permalink
feat(explorer): add save as variable overlay
Browse files Browse the repository at this point in the history
  • Loading branch information
AlirieGray committed Mar 11, 2019
1 parent 33e1f51 commit bf6824d
Show file tree
Hide file tree
Showing 6 changed files with 220 additions and 110 deletions.
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@

### Features

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,
Expand All @@ -19,6 +20,7 @@ import 'src/dataExplorer/components/SaveAsButton.scss'
enum SaveAsOption {
Dashboard = 'dashboard',
Task = 'task',
Variable = 'variable',
}

interface Props {}
Expand Down Expand Up @@ -71,6 +73,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 @@ -88,6 +98,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)
125 changes: 16 additions & 109 deletions ui/src/organizations/components/CreateVariableOverlay.tsx
Original file line number Diff line number Diff line change
@@ -1,132 +1,39 @@
// Libraries
import React, {PureComponent, ChangeEvent} from 'react'
import React, {PureComponent} from 'react'

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

// Components
import {
Form,
OverlayBody,
OverlayHeading,
OverlayContainer,
Input,
OverlayFooter,
} from 'src/clockface'
import {Button} from '@influxdata/clockface'
import FluxEditor from 'src/shared/components/FluxEditor'
import {OverlayBody, OverlayHeading, OverlayContainer} 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 (
<OverlayContainer maxWidth={1000}>
<OverlayHeading
title="Create Variable"
onDismiss={this.props.onCloseModal}
/>

<Form onSubmit={this.handleSubmit}>
<OverlayBody>
<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>

<OverlayFooter>
<Button
text="Cancel"
color={ComponentColor.Danger}
onClick={onCloseModal}
/>
<Button
text="Create"
type={ButtonType.Submit}
color={ComponentColor.Primary}
/>
</OverlayFooter>
</OverlayBody>
</Form>
<OverlayHeading title="Create Variable" onDismiss={onHideOverlay} />
<OverlayBody>
<VariableForm
onCreateVariable={onCreateVariable}
onHideOverlay={onHideOverlay}
orgID={orgID}
initialScript={initialScript}
/>
</OverlayBody>
</OverlayContainer>
)
}

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})
}
}
2 changes: 1 addition & 1 deletion ui/src/organizations/components/Variables.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -109,7 +109,7 @@ class Variables extends PureComponent<Props, State> {
<OverlayTechnology visible={createOverlayState === OverlayState.Open}>
<CreateVariableOverlay
onCreateVariable={this.handleCreateVariable}
onCloseModal={this.handleCloseCreateOverlay}
onHideOverlay={this.handleCloseCreateOverlay}
orgID={org.id}
/>
</OverlayTechnology>
Expand Down

0 comments on commit bf6824d

Please sign in to comment.