feat(ui/variables/rename): add danger zone to rename (#13555)
parent
e5657ca62b
commit
cf8785dc76
|
@ -66,6 +66,9 @@ import AddMembersOverlay from 'src/members/components/AddMembersOverlay'
|
||||||
import OrgProfilePage from 'src/organizations/containers/OrgProfilePage'
|
import OrgProfilePage from 'src/organizations/containers/OrgProfilePage'
|
||||||
import RenameOrgOverlay from 'src/organizations/components/RenameOrgOverlay'
|
import RenameOrgOverlay from 'src/organizations/components/RenameOrgOverlay'
|
||||||
import UpdateBucketOverlay from 'src/buckets/components/UpdateBucketOverlay'
|
import UpdateBucketOverlay from 'src/buckets/components/UpdateBucketOverlay'
|
||||||
|
import RenameBucketOverlay from 'src/buckets/components/RenameBucketOverlay'
|
||||||
|
import RenameVariableOverlay from 'src/variables/components/RenameVariableOverlay'
|
||||||
|
import UpdateVariableOverlay from 'src/variables/components/UpdateVariableOverlay'
|
||||||
|
|
||||||
// Actions
|
// Actions
|
||||||
import {disablePresentationMode} from 'src/shared/actions/app'
|
import {disablePresentationMode} from 'src/shared/actions/app'
|
||||||
|
@ -73,7 +76,6 @@ import {disablePresentationMode} from 'src/shared/actions/app'
|
||||||
// Styles
|
// Styles
|
||||||
import 'src/style/chronograf.scss'
|
import 'src/style/chronograf.scss'
|
||||||
import '@influxdata/clockface/dist/index.css'
|
import '@influxdata/clockface/dist/index.css'
|
||||||
import RenameBucketOverlay from './buckets/components/RenameBucketOverlay'
|
|
||||||
|
|
||||||
const rootNode = getRootNode()
|
const rootNode = getRootNode()
|
||||||
const basepath = getBasepath()
|
const basepath = getBasepath()
|
||||||
|
@ -256,6 +258,14 @@ class Root extends PureComponent {
|
||||||
path="new"
|
path="new"
|
||||||
component={CreateVariableOverlay}
|
component={CreateVariableOverlay}
|
||||||
/>
|
/>
|
||||||
|
<Route
|
||||||
|
path=":id/rename"
|
||||||
|
component={RenameVariableOverlay}
|
||||||
|
/>
|
||||||
|
<Route
|
||||||
|
path=":id/edit"
|
||||||
|
component={UpdateVariableOverlay}
|
||||||
|
/>
|
||||||
</Route>
|
</Route>
|
||||||
<Route path="labels" component={LabelsIndex} />
|
<Route path="labels" component={LabelsIndex} />
|
||||||
<Route path="scrapers" component={ScrapersIndex}>
|
<Route path="scrapers" component={ScrapersIndex}>
|
||||||
|
|
|
@ -0,0 +1,159 @@
|
||||||
|
// Libraries
|
||||||
|
import React, {PureComponent, ChangeEvent, FormEvent} from 'react'
|
||||||
|
import _ from 'lodash'
|
||||||
|
import {connect} from 'react-redux'
|
||||||
|
import {withRouter, WithRouterProps} from 'react-router'
|
||||||
|
|
||||||
|
// Components
|
||||||
|
import {Form, Input, Button, Grid, Columns} from '@influxdata/clockface'
|
||||||
|
import {Overlay} from 'src/clockface'
|
||||||
|
|
||||||
|
// Utils
|
||||||
|
import {validateVariableName} from 'src/variables/utils/validation'
|
||||||
|
import {extractVariablesList} from 'src/variables/selectors'
|
||||||
|
|
||||||
|
// Actions
|
||||||
|
import {updateVariable} from 'src/variables/actions'
|
||||||
|
|
||||||
|
// Types
|
||||||
|
import {AppState} from 'src/types'
|
||||||
|
import {IVariable as Variable} from '@influxdata/influx'
|
||||||
|
import {
|
||||||
|
ButtonType,
|
||||||
|
ComponentColor,
|
||||||
|
ComponentStatus,
|
||||||
|
} from '@influxdata/clockface'
|
||||||
|
|
||||||
|
interface OwnProps {
|
||||||
|
onClose: () => void
|
||||||
|
}
|
||||||
|
|
||||||
|
interface State {
|
||||||
|
workingVariable: Variable
|
||||||
|
isNameValid: boolean
|
||||||
|
}
|
||||||
|
|
||||||
|
interface StateProps {
|
||||||
|
variables: Variable[]
|
||||||
|
startVariable: Variable
|
||||||
|
}
|
||||||
|
|
||||||
|
interface DispatchProps {
|
||||||
|
onUpdateVariable: typeof updateVariable
|
||||||
|
}
|
||||||
|
|
||||||
|
type Props = StateProps & OwnProps & DispatchProps & WithRouterProps
|
||||||
|
|
||||||
|
class RenameVariableOverlayForm extends PureComponent<Props, State> {
|
||||||
|
public state: State = {
|
||||||
|
workingVariable: this.props.startVariable,
|
||||||
|
isNameValid: true,
|
||||||
|
}
|
||||||
|
|
||||||
|
public render() {
|
||||||
|
const {onClose} = this.props
|
||||||
|
const {workingVariable, isNameValid} = this.state
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Overlay.Container maxWidth={1000}>
|
||||||
|
<Overlay.Heading title="Rename Variable" onDismiss={onClose} />
|
||||||
|
<Overlay.Body>
|
||||||
|
<Form onSubmit={this.handleSubmit}>
|
||||||
|
<Grid>
|
||||||
|
<Grid.Row>
|
||||||
|
<Grid.Column widthXS={Columns.Six}>
|
||||||
|
<div className="overlay-flux-editor--spacing">
|
||||||
|
<Form.ValidationElement
|
||||||
|
label="Name"
|
||||||
|
value={workingVariable.name}
|
||||||
|
required={true}
|
||||||
|
validationFunc={this.handleNameValidation}
|
||||||
|
>
|
||||||
|
{status => (
|
||||||
|
<Input
|
||||||
|
placeholder="Rename your variable"
|
||||||
|
name="name"
|
||||||
|
autoFocus={true}
|
||||||
|
value={workingVariable.name}
|
||||||
|
onChange={this.handleChangeInput}
|
||||||
|
status={status}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
</Form.ValidationElement>
|
||||||
|
</div>
|
||||||
|
</Grid.Column>
|
||||||
|
</Grid.Row>
|
||||||
|
<Grid.Row>
|
||||||
|
<Grid.Column>
|
||||||
|
<Form.Footer>
|
||||||
|
<Button
|
||||||
|
text="Cancel"
|
||||||
|
color={ComponentColor.Danger}
|
||||||
|
onClick={onClose}
|
||||||
|
/>
|
||||||
|
<Button
|
||||||
|
text="Submit"
|
||||||
|
type={ButtonType.Submit}
|
||||||
|
color={ComponentColor.Primary}
|
||||||
|
status={
|
||||||
|
isNameValid
|
||||||
|
? ComponentStatus.Default
|
||||||
|
: ComponentStatus.Disabled
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
</Form.Footer>
|
||||||
|
</Grid.Column>
|
||||||
|
</Grid.Row>
|
||||||
|
</Grid>
|
||||||
|
</Form>
|
||||||
|
</Overlay.Body>
|
||||||
|
</Overlay.Container>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
private handleSubmit = (e: FormEvent): void => {
|
||||||
|
const {workingVariable} = this.state
|
||||||
|
|
||||||
|
e.preventDefault()
|
||||||
|
|
||||||
|
this.props.onUpdateVariable(workingVariable.id, workingVariable)
|
||||||
|
this.props.onClose()
|
||||||
|
}
|
||||||
|
|
||||||
|
private handleNameValidation = (name: string) => {
|
||||||
|
const {variables} = this.props
|
||||||
|
const {error} = validateVariableName(name, variables)
|
||||||
|
|
||||||
|
this.setState({isNameValid: !error})
|
||||||
|
|
||||||
|
return error
|
||||||
|
}
|
||||||
|
|
||||||
|
private handleChangeInput = (e: ChangeEvent<HTMLInputElement>) => {
|
||||||
|
const name = e.target.value
|
||||||
|
|
||||||
|
const workingVariable = {...this.state.workingVariable, name}
|
||||||
|
|
||||||
|
this.setState({
|
||||||
|
workingVariable,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const mstp = (state: AppState, {params: {id}}: Props): StateProps => {
|
||||||
|
const variables = extractVariablesList(state)
|
||||||
|
const startVariable = variables.find(v => v.id === id)
|
||||||
|
|
||||||
|
return {variables, startVariable}
|
||||||
|
}
|
||||||
|
|
||||||
|
const mdtp: DispatchProps = {
|
||||||
|
onUpdateVariable: updateVariable,
|
||||||
|
}
|
||||||
|
|
||||||
|
export default withRouter<OwnProps>(
|
||||||
|
connect<StateProps, DispatchProps, OwnProps>(
|
||||||
|
mstp,
|
||||||
|
mdtp
|
||||||
|
)(RenameVariableOverlayForm)
|
||||||
|
)
|
|
@ -0,0 +1,48 @@
|
||||||
|
// Libraries
|
||||||
|
import React, {PureComponent} from 'react'
|
||||||
|
import {withRouter, WithRouterProps} from 'react-router'
|
||||||
|
|
||||||
|
import _ from 'lodash'
|
||||||
|
|
||||||
|
// Components
|
||||||
|
import DangerConfirmationOverlay from 'src/shared/components/dangerConfirmation/DangerConfirmationOverlay'
|
||||||
|
import RenameVariableForm from 'src/variables/components/RenameVariableForm'
|
||||||
|
|
||||||
|
// Decorators
|
||||||
|
import {ErrorHandling} from 'src/shared/decorators/errors'
|
||||||
|
|
||||||
|
@ErrorHandling
|
||||||
|
class RenameVariableOverlay extends PureComponent<WithRouterProps> {
|
||||||
|
public render() {
|
||||||
|
return (
|
||||||
|
<DangerConfirmationOverlay
|
||||||
|
title="Rename Variable"
|
||||||
|
message={this.message}
|
||||||
|
effectedItems={this.effectedItems}
|
||||||
|
onClose={this.handleClose}
|
||||||
|
confirmButtonText="I understand, let's rename my Variable"
|
||||||
|
>
|
||||||
|
<RenameVariableForm onClose={this.handleClose} />
|
||||||
|
</DangerConfirmationOverlay>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
private get message(): string {
|
||||||
|
return 'Updating the name of a Variable can have unintended consequences. Anything that references this Variable by name will stop working including:'
|
||||||
|
}
|
||||||
|
|
||||||
|
private get effectedItems(): string[] {
|
||||||
|
return ['Queries', 'Dashboards', 'Telegraf Configurations', 'Templates']
|
||||||
|
}
|
||||||
|
|
||||||
|
private handleClose = () => {
|
||||||
|
const {
|
||||||
|
router,
|
||||||
|
params: {orgID},
|
||||||
|
} = this.props
|
||||||
|
|
||||||
|
router.push(`/orgs/${orgID}/variables`)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default withRouter(RenameVariableOverlay)
|
|
@ -1,6 +1,8 @@
|
||||||
// Libraries
|
// Libraries
|
||||||
import React, {PureComponent, ChangeEvent, FormEvent} from 'react'
|
import React, {PureComponent, FormEvent} from 'react'
|
||||||
import _ from 'lodash'
|
import _ from 'lodash'
|
||||||
|
import {connect} from 'react-redux'
|
||||||
|
import {withRouter, WithRouterProps} from 'react-router'
|
||||||
|
|
||||||
// Components
|
// Components
|
||||||
import {
|
import {
|
||||||
|
@ -14,8 +16,11 @@ import {
|
||||||
import {Overlay} from 'src/clockface'
|
import {Overlay} from 'src/clockface'
|
||||||
import VariableArgumentsEditor from 'src/variables/components/VariableArgumentsEditor'
|
import VariableArgumentsEditor from 'src/variables/components/VariableArgumentsEditor'
|
||||||
|
|
||||||
|
// Actions
|
||||||
|
import {updateVariable} from 'src/variables/actions'
|
||||||
|
|
||||||
// Utils
|
// Utils
|
||||||
import {validateVariableName} from 'src/variables/utils/validation'
|
import {extractVariablesList} from 'src/variables/selectors'
|
||||||
|
|
||||||
// Constants
|
// Constants
|
||||||
import {variableItemTypes} from 'src/variables/constants'
|
import {variableItemTypes} from 'src/variables/constants'
|
||||||
|
@ -27,14 +32,7 @@ import {
|
||||||
ComponentColor,
|
ComponentColor,
|
||||||
ComponentStatus,
|
ComponentStatus,
|
||||||
} from '@influxdata/clockface'
|
} from '@influxdata/clockface'
|
||||||
import {VariableArguments} from 'src/types'
|
import {VariableArguments, AppState} from 'src/types'
|
||||||
|
|
||||||
interface Props {
|
|
||||||
variable: Variable
|
|
||||||
variables: Variable[]
|
|
||||||
onCloseOverlay: () => void
|
|
||||||
onUpdateVariable: (variable: Variable) => Promise<void>
|
|
||||||
}
|
|
||||||
|
|
||||||
interface State {
|
interface State {
|
||||||
workingVariable: Variable
|
workingVariable: Variable
|
||||||
|
@ -42,107 +40,109 @@ interface State {
|
||||||
hasValidArgs: boolean
|
hasValidArgs: boolean
|
||||||
}
|
}
|
||||||
|
|
||||||
export default class UpdateVariableOverlay extends PureComponent<Props, State> {
|
interface StateProps {
|
||||||
|
variables: Variable[]
|
||||||
|
startVariable: Variable
|
||||||
|
}
|
||||||
|
|
||||||
|
interface DispatchProps {
|
||||||
|
onUpdateVariable: typeof updateVariable
|
||||||
|
}
|
||||||
|
|
||||||
|
type Props = StateProps & DispatchProps & WithRouterProps
|
||||||
|
|
||||||
|
class UpdateVariableOverlay extends PureComponent<Props, State> {
|
||||||
public state: State = {
|
public state: State = {
|
||||||
workingVariable: this.props.variable,
|
workingVariable: this.props.startVariable,
|
||||||
isNameValid: true,
|
isNameValid: true,
|
||||||
hasValidArgs: true,
|
hasValidArgs: true,
|
||||||
}
|
}
|
||||||
|
|
||||||
public render() {
|
public render() {
|
||||||
const {onCloseOverlay} = this.props
|
const {workingVariable, hasValidArgs} = this.state
|
||||||
const {workingVariable} = this.state
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Overlay.Container maxWidth={1000}>
|
<Overlay visible={true}>
|
||||||
<Overlay.Heading
|
<Overlay.Container maxWidth={1000}>
|
||||||
title="Edit Variable"
|
<Overlay.Heading title="Edit Variable" onDismiss={this.handleClose} />
|
||||||
onDismiss={this.props.onCloseOverlay}
|
<Overlay.Body>
|
||||||
/>
|
<Form onSubmit={this.handleSubmit}>
|
||||||
<Overlay.Body>
|
<Grid>
|
||||||
<Form onSubmit={this.handleSubmit}>
|
<Grid.Row>
|
||||||
<Grid>
|
<Grid.Column widthXS={Columns.Six}>
|
||||||
<Grid.Row>
|
<div className="overlay-flux-editor--spacing">
|
||||||
<Grid.Column widthXS={Columns.Six}>
|
<Form.Element
|
||||||
<div className="overlay-flux-editor--spacing">
|
label="Name"
|
||||||
<Form.ValidationElement
|
helpText="To rename your variable use the rename button. Renaming is not allowed here."
|
||||||
label="Name"
|
>
|
||||||
value={workingVariable.name}
|
|
||||||
required={true}
|
|
||||||
validationFunc={this.handleNameValidation}
|
|
||||||
>
|
|
||||||
{status => (
|
|
||||||
<Input
|
<Input
|
||||||
placeholder="Give your variable a name"
|
placeholder="Give your variable a name"
|
||||||
name="name"
|
name="name"
|
||||||
autoFocus={true}
|
autoFocus={true}
|
||||||
value={workingVariable.name}
|
value={workingVariable.name}
|
||||||
onChange={this.handleChangeInput}
|
status={ComponentStatus.Disabled}
|
||||||
status={status}
|
|
||||||
/>
|
/>
|
||||||
)}
|
</Form.Element>
|
||||||
</Form.ValidationElement>
|
</div>
|
||||||
</div>
|
</Grid.Column>
|
||||||
</Grid.Column>
|
<Grid.Column widthXS={Columns.Six}>
|
||||||
<Grid.Column widthXS={Columns.Six}>
|
<Form.Element label="Type" required={true}>
|
||||||
<Form.Element label="Type" required={true}>
|
<Dropdown
|
||||||
<Dropdown
|
selectedID={workingVariable.arguments.type}
|
||||||
selectedID={workingVariable.arguments.type}
|
onChange={this.handleChangeType}
|
||||||
onChange={this.handleChangeType}
|
>
|
||||||
>
|
{variableItemTypes.map(v => (
|
||||||
{variableItemTypes.map(v => (
|
<Dropdown.Item
|
||||||
<Dropdown.Item key={v.type} id={v.type} value={v.type}>
|
key={v.type}
|
||||||
{v.label}
|
id={v.type}
|
||||||
</Dropdown.Item>
|
value={v.type}
|
||||||
))}
|
>
|
||||||
</Dropdown>
|
{v.label}
|
||||||
</Form.Element>
|
</Dropdown.Item>
|
||||||
</Grid.Column>
|
))}
|
||||||
</Grid.Row>
|
</Dropdown>
|
||||||
<Grid.Row>
|
</Form.Element>
|
||||||
<Grid.Column>
|
</Grid.Column>
|
||||||
<VariableArgumentsEditor
|
</Grid.Row>
|
||||||
onChange={this.handleChangeArgs}
|
<Grid.Row>
|
||||||
onSelectMapDefault={this.handleSelectMapDefault}
|
<Grid.Column>
|
||||||
selected={workingVariable.selected}
|
<VariableArgumentsEditor
|
||||||
args={workingVariable.arguments}
|
onChange={this.handleChangeArgs}
|
||||||
/>
|
onSelectMapDefault={this.handleSelectMapDefault}
|
||||||
</Grid.Column>
|
selected={workingVariable.selected}
|
||||||
</Grid.Row>
|
args={workingVariable.arguments}
|
||||||
<Grid.Row>
|
|
||||||
<Grid.Column>
|
|
||||||
<Form.Footer>
|
|
||||||
<Button
|
|
||||||
text="Cancel"
|
|
||||||
color={ComponentColor.Danger}
|
|
||||||
onClick={onCloseOverlay}
|
|
||||||
/>
|
/>
|
||||||
<Button
|
</Grid.Column>
|
||||||
text="Submit"
|
</Grid.Row>
|
||||||
type={ButtonType.Submit}
|
<Grid.Row>
|
||||||
color={ComponentColor.Primary}
|
<Grid.Column>
|
||||||
status={
|
<Form.Footer>
|
||||||
this.isFormValid
|
<Button
|
||||||
? ComponentStatus.Default
|
text="Cancel"
|
||||||
: ComponentStatus.Disabled
|
color={ComponentColor.Danger}
|
||||||
}
|
onClick={this.handleClose}
|
||||||
/>
|
/>
|
||||||
</Form.Footer>
|
<Button
|
||||||
</Grid.Column>
|
text="Submit"
|
||||||
</Grid.Row>
|
type={ButtonType.Submit}
|
||||||
</Grid>
|
color={ComponentColor.Primary}
|
||||||
</Form>
|
status={
|
||||||
</Overlay.Body>
|
hasValidArgs
|
||||||
</Overlay.Container>
|
? ComponentStatus.Default
|
||||||
|
: ComponentStatus.Disabled
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
</Form.Footer>
|
||||||
|
</Grid.Column>
|
||||||
|
</Grid.Row>
|
||||||
|
</Grid>
|
||||||
|
</Form>
|
||||||
|
</Overlay.Body>
|
||||||
|
</Overlay.Container>
|
||||||
|
</Overlay>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
private get isFormValid(): boolean {
|
|
||||||
const {hasValidArgs, isNameValid} = this.state
|
|
||||||
|
|
||||||
return hasValidArgs && isNameValid
|
|
||||||
}
|
|
||||||
|
|
||||||
private handleChangeType = (selectedType: string) => {
|
private handleChangeType = (selectedType: string) => {
|
||||||
const {isNameValid, workingVariable} = this.state
|
const {isNameValid, workingVariable} = this.state
|
||||||
const defaults = {hasValidArgs: false, isNameValid}
|
const defaults = {hasValidArgs: false, isNameValid}
|
||||||
|
@ -221,27 +221,36 @@ export default class UpdateVariableOverlay extends PureComponent<Props, State> {
|
||||||
|
|
||||||
private handleSubmit = (e: FormEvent): void => {
|
private handleSubmit = (e: FormEvent): void => {
|
||||||
e.preventDefault()
|
e.preventDefault()
|
||||||
|
const {workingVariable} = this.state
|
||||||
|
|
||||||
this.props.onUpdateVariable(this.state.workingVariable)
|
this.props.onUpdateVariable(workingVariable.id, workingVariable)
|
||||||
this.props.onCloseOverlay()
|
this.handleClose()
|
||||||
}
|
}
|
||||||
|
|
||||||
private handleNameValidation = (name: string) => {
|
private handleClose = () => {
|
||||||
const {variables} = this.props
|
const {
|
||||||
const {error} = validateVariableName(name, variables)
|
router,
|
||||||
|
params: {orgID},
|
||||||
|
} = this.props
|
||||||
|
|
||||||
this.setState({isNameValid: !error})
|
router.push(`/orgs/${orgID}/variables`)
|
||||||
|
|
||||||
return error
|
|
||||||
}
|
|
||||||
|
|
||||||
private handleChangeInput = (e: ChangeEvent<HTMLInputElement>) => {
|
|
||||||
const value = e.target.value
|
|
||||||
const key = e.target.name
|
|
||||||
const workingVariable = {...this.state.workingVariable, [key]: value}
|
|
||||||
|
|
||||||
this.setState({
|
|
||||||
workingVariable,
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const mstp = (state: AppState, {params: {id}}: Props): StateProps => {
|
||||||
|
const variables = extractVariablesList(state)
|
||||||
|
const startVariable = variables.find(v => v.id === id)
|
||||||
|
|
||||||
|
return {variables, startVariable}
|
||||||
|
}
|
||||||
|
|
||||||
|
const mdtp: DispatchProps = {
|
||||||
|
onUpdateVariable: updateVariable,
|
||||||
|
}
|
||||||
|
|
||||||
|
export default withRouter(
|
||||||
|
connect<StateProps, DispatchProps>(
|
||||||
|
mstp,
|
||||||
|
mdtp
|
||||||
|
)(UpdateVariableOverlay)
|
||||||
|
)
|
||||||
|
|
|
@ -3,9 +3,8 @@ import React, {PureComponent} from 'react'
|
||||||
import memoizeOne from 'memoize-one'
|
import memoizeOne from 'memoize-one'
|
||||||
|
|
||||||
// Components
|
// Components
|
||||||
import {IndexList, Overlay} from 'src/clockface'
|
import {IndexList} from 'src/clockface'
|
||||||
import VariableRow from 'src/variables/components/VariableRow'
|
import VariableRow from 'src/variables/components/VariableRow'
|
||||||
import UpdateVariableOverlay from 'src/variables/components/UpdateVariableOverlay'
|
|
||||||
|
|
||||||
// Types
|
// Types
|
||||||
import {IVariable as Variable} from '@influxdata/influx'
|
import {IVariable as Variable} from '@influxdata/influx'
|
||||||
|
@ -52,13 +51,7 @@ export default class VariableList extends PureComponent<Props, State> {
|
||||||
}
|
}
|
||||||
|
|
||||||
public render() {
|
public render() {
|
||||||
const {
|
const {emptyState, sortKey, sortDirection, onClickColumn} = this.props
|
||||||
emptyState,
|
|
||||||
variables,
|
|
||||||
sortKey,
|
|
||||||
sortDirection,
|
|
||||||
onClickColumn,
|
|
||||||
} = this.props
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
|
@ -77,14 +70,6 @@ export default class VariableList extends PureComponent<Props, State> {
|
||||||
{this.rows}
|
{this.rows}
|
||||||
</IndexList.Body>
|
</IndexList.Body>
|
||||||
</IndexList>
|
</IndexList>
|
||||||
<Overlay visible={this.isVariableOverlayVisible}>
|
|
||||||
<UpdateVariableOverlay
|
|
||||||
variable={this.variable}
|
|
||||||
variables={variables}
|
|
||||||
onCloseOverlay={this.handleCloseOverlay}
|
|
||||||
onUpdateVariable={this.handleUpdateVariable}
|
|
||||||
/>
|
|
||||||
</Overlay>
|
|
||||||
</>
|
</>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -122,26 +107,10 @@ export default class VariableList extends PureComponent<Props, State> {
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
|
|
||||||
private get variable(): Variable {
|
|
||||||
return this.props.variables.find(v => v.id === this.state.variableID)
|
|
||||||
}
|
|
||||||
|
|
||||||
private get isVariableOverlayVisible(): boolean {
|
|
||||||
return this.state.variableOverlayState === OverlayState.Open
|
|
||||||
}
|
|
||||||
|
|
||||||
private handleCloseOverlay = () => {
|
|
||||||
this.setState({variableOverlayState: OverlayState.Closed, variableID: null})
|
|
||||||
}
|
|
||||||
|
|
||||||
private handleStartEdit = (variable: Variable) => {
|
private handleStartEdit = (variable: Variable) => {
|
||||||
this.setState({
|
this.setState({
|
||||||
variableID: variable.id,
|
variableID: variable.id,
|
||||||
variableOverlayState: OverlayState.Open,
|
variableOverlayState: OverlayState.Open,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
private handleUpdateVariable = async (variable: Variable): Promise<void> => {
|
|
||||||
this.props.onUpdateVariable(variable)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
// Libraries
|
// Libraries
|
||||||
import React, {PureComponent} from 'react'
|
import React, {PureComponent} from 'react'
|
||||||
import {connect} from 'react-redux'
|
import {connect} from 'react-redux'
|
||||||
import {withRouter, WithRouterProps} from 'react-router'
|
import {withRouter, WithRouterProps, Link} from 'react-router'
|
||||||
|
|
||||||
// Components
|
// Components
|
||||||
import {IndexList, Alignment, Context, IconFont} from 'src/clockface'
|
import {IndexList, Alignment, Context, IconFont} from 'src/clockface'
|
||||||
|
@ -11,12 +11,12 @@ import {
|
||||||
FlexDirection,
|
FlexDirection,
|
||||||
AlignItems,
|
AlignItems,
|
||||||
ComponentSize,
|
ComponentSize,
|
||||||
|
Button,
|
||||||
} from '@influxdata/clockface'
|
} from '@influxdata/clockface'
|
||||||
import InlineLabels from 'src/shared/components/inlineLabels/InlineLabels'
|
import InlineLabels from 'src/shared/components/inlineLabels/InlineLabels'
|
||||||
|
|
||||||
// Types
|
// Types
|
||||||
import {IVariable as Variable, ILabel} from '@influxdata/influx'
|
import {IVariable as Variable, ILabel} from '@influxdata/influx'
|
||||||
import EditableName from 'src/shared/components/EditableName'
|
|
||||||
import {AppState} from 'src/types'
|
import {AppState} from 'src/types'
|
||||||
|
|
||||||
// Selectors
|
// Selectors
|
||||||
|
@ -62,18 +62,23 @@ class VariableRow extends PureComponent<Props & WithRouterProps> {
|
||||||
alignItems={AlignItems.FlexStart}
|
alignItems={AlignItems.FlexStart}
|
||||||
stretchToFitWidth={true}
|
stretchToFitWidth={true}
|
||||||
>
|
>
|
||||||
<EditableName
|
<div className="editable-name">
|
||||||
onUpdate={this.handleUpdateVariableName}
|
<Link to={this.editVariablePath}>
|
||||||
name={variable.name}
|
<span>{variable.name}</span>
|
||||||
noNameString="NAME THIS VARIABLE"
|
</Link>
|
||||||
onEditName={this.handleEditVariable}
|
</div>
|
||||||
>
|
|
||||||
{variable.name}
|
|
||||||
</EditableName>
|
|
||||||
{this.labels}
|
{this.labels}
|
||||||
</ComponentSpacer>
|
</ComponentSpacer>
|
||||||
</IndexList.Cell>
|
</IndexList.Cell>
|
||||||
<IndexList.Cell alignment={Alignment.Left}>Query</IndexList.Cell>
|
<IndexList.Cell alignment={Alignment.Left}>Query</IndexList.Cell>
|
||||||
|
<IndexList.Cell revealOnHover={true} alignment={Alignment.Right}>
|
||||||
|
<Button
|
||||||
|
text="Rename"
|
||||||
|
onClick={this.handleRenameVariable}
|
||||||
|
color={ComponentColor.Danger}
|
||||||
|
size={ComponentSize.ExtraSmall}
|
||||||
|
/>
|
||||||
|
</IndexList.Cell>
|
||||||
<IndexList.Cell revealOnHover={true} alignment={Alignment.Right}>
|
<IndexList.Cell revealOnHover={true} alignment={Alignment.Right}>
|
||||||
<Context>
|
<Context>
|
||||||
<Context.Menu icon={IconFont.CogThick}>
|
<Context.Menu icon={IconFont.CogThick}>
|
||||||
|
@ -97,6 +102,15 @@ class VariableRow extends PureComponent<Props & WithRouterProps> {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private get editVariablePath(): string {
|
||||||
|
const {
|
||||||
|
variable,
|
||||||
|
params: {orgID},
|
||||||
|
} = this.props
|
||||||
|
|
||||||
|
return `/orgs/${orgID}/variables/${variable.id}/edit`
|
||||||
|
}
|
||||||
|
|
||||||
private get labels(): JSX.Element {
|
private get labels(): JSX.Element {
|
||||||
const {variable, labels, onFilterChange} = this.props
|
const {variable, labels, onFilterChange} = this.props
|
||||||
const collectorLabels = viewableLabels(variable.labels)
|
const collectorLabels = viewableLabels(variable.labels)
|
||||||
|
@ -140,17 +154,17 @@ class VariableRow extends PureComponent<Props & WithRouterProps> {
|
||||||
variable,
|
variable,
|
||||||
params: {orgID},
|
params: {orgID},
|
||||||
} = this.props
|
} = this.props
|
||||||
router.push(`orgs/${orgID}/variables/${variable.id}/export`)
|
router.push(`/orgs/${orgID}/variables/${variable.id}/export`)
|
||||||
}
|
}
|
||||||
|
|
||||||
private handleUpdateVariableName = async (name: string) => {
|
private handleRenameVariable = async () => {
|
||||||
const {onUpdateVariableName, variable} = this.props
|
const {
|
||||||
|
router,
|
||||||
|
variable,
|
||||||
|
params: {orgID},
|
||||||
|
} = this.props
|
||||||
|
|
||||||
await onUpdateVariableName({id: variable.id, name})
|
router.push(`/orgs/${orgID}/variables/${variable.id}/rename`)
|
||||||
}
|
|
||||||
|
|
||||||
private handleEditVariable = (): void => {
|
|
||||||
this.props.onEditVariable(this.props.variable)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -41,28 +41,5 @@ exports[`VariableList rendering renders 1`] = `
|
||||||
/>
|
/>
|
||||||
</IndexListBody>
|
</IndexListBody>
|
||||||
</IndexList>
|
</IndexList>
|
||||||
<Overlay
|
|
||||||
visible={false}
|
|
||||||
>
|
|
||||||
<UpdateVariableOverlay
|
|
||||||
onCloseOverlay={[Function]}
|
|
||||||
onUpdateVariable={[Function]}
|
|
||||||
variables={
|
|
||||||
Array [
|
|
||||||
Object {
|
|
||||||
"arguments": Object {
|
|
||||||
"type": "query",
|
|
||||||
"values": Object {
|
|
||||||
"language": "flux",
|
|
||||||
"query": "1 + 1 ",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
"name": "a little variable",
|
|
||||||
"orgID": "0",
|
|
||||||
},
|
|
||||||
]
|
|
||||||
}
|
|
||||||
/>
|
|
||||||
</Overlay>
|
|
||||||
</Fragment>
|
</Fragment>
|
||||||
`;
|
`;
|
||||||
|
|
|
@ -1,4 +1,11 @@
|
||||||
import {Variable} from '@influxdata/influx'
|
import {Variable} from '@influxdata/influx'
|
||||||
|
import {
|
||||||
|
TIME_RANGE_START,
|
||||||
|
TIME_RANGE_STOP,
|
||||||
|
WINDOW_PERIOD,
|
||||||
|
} from 'src/variables/constants'
|
||||||
|
|
||||||
|
const reservedVarNames = [TIME_RANGE_START, TIME_RANGE_STOP, WINDOW_PERIOD]
|
||||||
|
|
||||||
export const validateVariableName = (
|
export const validateVariableName = (
|
||||||
varName: string,
|
varName: string,
|
||||||
|
@ -8,11 +15,23 @@ export const validateVariableName = (
|
||||||
return {error: 'Variable name cannot be empty'}
|
return {error: 'Variable name cannot be empty'}
|
||||||
}
|
}
|
||||||
|
|
||||||
const matchingName = variables.find(
|
const lowerName = varName.toLocaleLowerCase()
|
||||||
v => v.name.toLocaleLowerCase() === varName.toLocaleLowerCase()
|
|
||||||
|
const reservedMatch = reservedVarNames.find(
|
||||||
|
r => r.toLocaleLowerCase() === lowerName
|
||||||
)
|
)
|
||||||
|
|
||||||
if (matchingName) {
|
if (!!reservedMatch) {
|
||||||
|
return {
|
||||||
|
error: `Variable name is reserved: ${reservedMatch}`,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const matchingName = variables.find(
|
||||||
|
v => v.name.toLocaleLowerCase() === lowerName
|
||||||
|
)
|
||||||
|
|
||||||
|
if (!!matchingName) {
|
||||||
return {
|
return {
|
||||||
error: `Variable name must be unique`,
|
error: `Variable name must be unique`,
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue