2020-03-10 02:53:41 -05:00
|
|
|
import React, { ChangeEvent, FormEvent, PureComponent } from 'react';
|
|
|
|
import isEqual from 'lodash/isEqual';
|
2020-10-02 00:02:06 -05:00
|
|
|
import { AppEvents, LoadingState, VariableType } from '@grafana/data';
|
|
|
|
import { Icon, InlineFormLabel } from '@grafana/ui';
|
2020-04-27 02:09:05 -05:00
|
|
|
import { selectors } from '@grafana/e2e-selectors';
|
|
|
|
|
2020-03-10 02:53:41 -05:00
|
|
|
import { variableAdapters } from '../adapters';
|
2020-10-02 00:02:06 -05:00
|
|
|
import { NEW_VARIABLE_ID, toVariableIdentifier, toVariablePayload, VariableIdentifier } from '../state/types';
|
2020-06-04 06:44:48 -05:00
|
|
|
import { VariableHide, VariableModel } from '../types';
|
2020-03-10 02:53:41 -05:00
|
|
|
import { appEvents } from '../../../core/core';
|
|
|
|
import { VariableValuesPreview } from './VariableValuesPreview';
|
|
|
|
import { changeVariableName, onEditorAdd, onEditorUpdate, variableEditorMount, variableEditorUnMount } from './actions';
|
|
|
|
import { MapDispatchToProps, MapStateToProps } from 'react-redux';
|
|
|
|
import { StoreState } from '../../../types';
|
|
|
|
import { VariableEditorState } from './reducer';
|
|
|
|
import { getVariable } from '../state/selectors';
|
|
|
|
import { connectWithStore } from '../../../core/utils/connectWithReduxStore';
|
|
|
|
import { OnPropChangeArguments } from './types';
|
|
|
|
import { changeVariableProp, changeVariableType } from '../state/sharedReducer';
|
2020-10-02 00:02:06 -05:00
|
|
|
import { updateOptions } from '../state/actions';
|
2020-03-10 02:53:41 -05:00
|
|
|
|
|
|
|
export interface OwnProps {
|
|
|
|
identifier: VariableIdentifier;
|
|
|
|
}
|
|
|
|
|
|
|
|
interface ConnectedProps {
|
|
|
|
editor: VariableEditorState;
|
|
|
|
variable: VariableModel;
|
|
|
|
}
|
|
|
|
|
|
|
|
interface DispatchProps {
|
|
|
|
variableEditorMount: typeof variableEditorMount;
|
|
|
|
variableEditorUnMount: typeof variableEditorUnMount;
|
|
|
|
changeVariableName: typeof changeVariableName;
|
|
|
|
changeVariableProp: typeof changeVariableProp;
|
|
|
|
onEditorUpdate: typeof onEditorUpdate;
|
|
|
|
onEditorAdd: typeof onEditorAdd;
|
|
|
|
changeVariableType: typeof changeVariableType;
|
2020-10-02 00:02:06 -05:00
|
|
|
updateOptions: typeof updateOptions;
|
2020-03-10 02:53:41 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
type Props = OwnProps & ConnectedProps & DispatchProps;
|
|
|
|
|
|
|
|
export class VariableEditorEditorUnConnected extends PureComponent<Props> {
|
|
|
|
componentDidMount(): void {
|
|
|
|
this.props.variableEditorMount(this.props.identifier);
|
|
|
|
}
|
|
|
|
|
|
|
|
componentDidUpdate(prevProps: Readonly<Props>, prevState: Readonly<{}>, snapshot?: any): void {
|
|
|
|
if (!isEqual(prevProps.editor.errors, this.props.editor.errors)) {
|
|
|
|
Object.values(this.props.editor.errors).forEach(error => {
|
|
|
|
appEvents.emit(AppEvents.alertWarning, ['Validation', error]);
|
|
|
|
});
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
componentWillUnmount(): void {
|
|
|
|
this.props.variableEditorUnMount(this.props.identifier);
|
|
|
|
}
|
|
|
|
|
|
|
|
onNameChange = (event: ChangeEvent<HTMLInputElement>) => {
|
|
|
|
event.preventDefault();
|
|
|
|
this.props.changeVariableName(this.props.identifier, event.target.value);
|
|
|
|
};
|
|
|
|
|
|
|
|
onTypeChange = (event: ChangeEvent<HTMLSelectElement>) => {
|
|
|
|
event.preventDefault();
|
|
|
|
this.props.changeVariableType(
|
|
|
|
toVariablePayload(this.props.identifier, { newType: event.target.value as VariableType })
|
|
|
|
);
|
|
|
|
};
|
|
|
|
|
|
|
|
onLabelChange = (event: ChangeEvent<HTMLInputElement>) => {
|
|
|
|
event.preventDefault();
|
|
|
|
this.props.changeVariableProp(
|
|
|
|
toVariablePayload(this.props.identifier, { propName: 'label', propValue: event.target.value })
|
|
|
|
);
|
|
|
|
};
|
|
|
|
|
|
|
|
onHideChange = (event: ChangeEvent<HTMLSelectElement>) => {
|
|
|
|
event.preventDefault();
|
|
|
|
this.props.changeVariableProp(
|
|
|
|
toVariablePayload(this.props.identifier, {
|
|
|
|
propName: 'hide',
|
|
|
|
propValue: parseInt(event.target.value, 10) as VariableHide,
|
|
|
|
})
|
|
|
|
);
|
|
|
|
};
|
|
|
|
|
|
|
|
onPropChanged = async ({ propName, propValue, updateOptions = false }: OnPropChangeArguments) => {
|
|
|
|
this.props.changeVariableProp(toVariablePayload(this.props.identifier, { propName, propValue }));
|
|
|
|
if (updateOptions) {
|
2020-10-02 00:02:06 -05:00
|
|
|
await this.props.updateOptions(toVariableIdentifier(this.props.variable));
|
2020-03-10 02:53:41 -05:00
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
onHandleSubmit = async (event: FormEvent<HTMLFormElement>) => {
|
|
|
|
event.preventDefault();
|
|
|
|
if (!this.props.editor.isValid) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2020-03-23 07:45:08 -05:00
|
|
|
if (this.props.variable.id !== NEW_VARIABLE_ID) {
|
2020-03-10 02:53:41 -05:00
|
|
|
await this.props.onEditorUpdate(this.props.identifier);
|
|
|
|
}
|
|
|
|
|
2020-03-23 07:45:08 -05:00
|
|
|
if (this.props.variable.id === NEW_VARIABLE_ID) {
|
2020-03-10 02:53:41 -05:00
|
|
|
await this.props.onEditorAdd(this.props.identifier);
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
render() {
|
2020-10-02 00:02:06 -05:00
|
|
|
const { variable } = this.props;
|
2020-03-10 02:53:41 -05:00
|
|
|
const EditorToRender = variableAdapters.get(this.props.variable.type).editor;
|
|
|
|
if (!EditorToRender) {
|
|
|
|
return null;
|
|
|
|
}
|
2020-03-23 07:45:08 -05:00
|
|
|
const newVariable = this.props.variable.id && this.props.variable.id === NEW_VARIABLE_ID;
|
2020-10-02 00:02:06 -05:00
|
|
|
const loading = variable.state === LoadingState.Loading;
|
2020-03-10 02:53:41 -05:00
|
|
|
|
|
|
|
return (
|
|
|
|
<div>
|
|
|
|
<form aria-label="Variable editor Form" onSubmit={this.onHandleSubmit}>
|
|
|
|
<h5 className="section-heading">General</h5>
|
|
|
|
<div className="gf-form-group">
|
|
|
|
<div className="gf-form-inline">
|
|
|
|
<div className="gf-form max-width-19">
|
|
|
|
<span className="gf-form-label width-6">Name</span>
|
|
|
|
<input
|
|
|
|
type="text"
|
|
|
|
className="gf-form-input"
|
|
|
|
name="name"
|
|
|
|
placeholder="name"
|
|
|
|
required
|
|
|
|
value={this.props.editor.name}
|
|
|
|
onChange={this.onNameChange}
|
2020-04-27 02:09:05 -05:00
|
|
|
aria-label={selectors.pages.Dashboard.Settings.Variables.Edit.General.generalNameInput}
|
2020-03-10 02:53:41 -05:00
|
|
|
/>
|
|
|
|
</div>
|
|
|
|
<div className="gf-form max-width-19">
|
2020-04-21 04:42:21 -05:00
|
|
|
<InlineFormLabel width={6} tooltip={variableAdapters.get(this.props.variable.type).description}>
|
2020-03-10 02:53:41 -05:00
|
|
|
Type
|
2020-04-21 04:42:21 -05:00
|
|
|
</InlineFormLabel>
|
2020-03-10 02:53:41 -05:00
|
|
|
<div className="gf-form-select-wrapper max-width-17">
|
|
|
|
<select
|
|
|
|
className="gf-form-input"
|
|
|
|
value={this.props.variable.type}
|
|
|
|
onChange={this.onTypeChange}
|
2020-04-27 02:09:05 -05:00
|
|
|
aria-label={selectors.pages.Dashboard.Settings.Variables.Edit.General.generalTypeSelect}
|
2020-03-10 02:53:41 -05:00
|
|
|
>
|
2020-03-23 09:33:17 -05:00
|
|
|
{variableAdapters.list().map(({ id, name }) => (
|
|
|
|
<option key={id} label={name} value={id}>
|
|
|
|
{name}
|
2020-03-10 02:53:41 -05:00
|
|
|
</option>
|
|
|
|
))}
|
|
|
|
</select>
|
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
|
|
|
|
{this.props.editor.errors.name && (
|
|
|
|
<div className="gf-form">
|
|
|
|
<span className="gf-form-label gf-form-label--error">{this.props.editor.errors.name}</span>
|
|
|
|
</div>
|
|
|
|
)}
|
|
|
|
|
|
|
|
<div className="gf-form-inline">
|
|
|
|
<div className="gf-form max-width-19">
|
|
|
|
<span className="gf-form-label width-6">Label</span>
|
|
|
|
<input
|
|
|
|
type="text"
|
|
|
|
className="gf-form-input"
|
|
|
|
value={this.props.variable.label ?? ''}
|
|
|
|
onChange={this.onLabelChange}
|
|
|
|
placeholder="optional display name"
|
2020-04-27 02:09:05 -05:00
|
|
|
aria-label={selectors.pages.Dashboard.Settings.Variables.Edit.General.generalLabelInput}
|
2020-03-10 02:53:41 -05:00
|
|
|
/>
|
|
|
|
</div>
|
|
|
|
<div className="gf-form max-width-19">
|
|
|
|
<span className="gf-form-label width-6">Hide</span>
|
|
|
|
<div className="gf-form-select-wrapper max-width-15">
|
|
|
|
<select
|
|
|
|
className="gf-form-input"
|
|
|
|
value={this.props.variable.hide}
|
|
|
|
onChange={this.onHideChange}
|
2020-04-27 02:09:05 -05:00
|
|
|
aria-label={selectors.pages.Dashboard.Settings.Variables.Edit.General.generalHideSelect}
|
2020-03-10 02:53:41 -05:00
|
|
|
>
|
|
|
|
<option label="" value={VariableHide.dontHide}>
|
|
|
|
{''}
|
|
|
|
</option>
|
2020-08-09 23:11:24 -05:00
|
|
|
<option label="Label" value={VariableHide.hideLabel}>
|
2020-03-10 02:53:41 -05:00
|
|
|
Label
|
|
|
|
</option>
|
2020-08-09 23:11:24 -05:00
|
|
|
<option label="Variable" value={VariableHide.hideVariable}>
|
2020-03-10 02:53:41 -05:00
|
|
|
Variable
|
|
|
|
</option>
|
|
|
|
</select>
|
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
|
|
|
|
{EditorToRender && <EditorToRender variable={this.props.variable} onPropChange={this.onPropChanged} />}
|
|
|
|
|
|
|
|
<VariableValuesPreview variable={this.props.variable} />
|
|
|
|
|
|
|
|
<div className="gf-form-button-row p-y-0">
|
2020-10-02 00:02:06 -05:00
|
|
|
<button
|
|
|
|
type="submit"
|
|
|
|
className="btn btn-primary"
|
|
|
|
aria-label={selectors.pages.Dashboard.Settings.Variables.Edit.General.submitButton}
|
|
|
|
disabled={loading}
|
|
|
|
>
|
|
|
|
{newVariable ? 'Add' : 'Update'}
|
|
|
|
{loading ? <Icon className="spin-clockwise" name="sync" size="sm" style={{ marginLeft: '2px' }} /> : null}
|
|
|
|
</button>
|
2020-03-10 02:53:41 -05:00
|
|
|
</div>
|
|
|
|
</form>
|
|
|
|
</div>
|
|
|
|
);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
const mapStateToProps: MapStateToProps<ConnectedProps, OwnProps, StoreState> = (state, ownProps) => ({
|
|
|
|
editor: state.templating.editor,
|
2020-03-23 07:45:08 -05:00
|
|
|
variable: getVariable(ownProps.identifier.id, state, false), // we could be renaming a variable and we don't want this to throw
|
2020-03-10 02:53:41 -05:00
|
|
|
});
|
|
|
|
|
|
|
|
const mapDispatchToProps: MapDispatchToProps<DispatchProps, OwnProps> = {
|
|
|
|
variableEditorMount,
|
|
|
|
variableEditorUnMount,
|
|
|
|
changeVariableName,
|
|
|
|
changeVariableProp,
|
|
|
|
onEditorUpdate,
|
|
|
|
onEditorAdd,
|
|
|
|
changeVariableType,
|
2020-10-02 00:02:06 -05:00
|
|
|
updateOptions,
|
2020-03-10 02:53:41 -05:00
|
|
|
};
|
|
|
|
|
|
|
|
export const VariableEditorEditor = connectWithStore(
|
|
|
|
VariableEditorEditorUnConnected,
|
|
|
|
mapStateToProps,
|
|
|
|
mapDispatchToProps
|
|
|
|
);
|