From 092acec2954b52d093eab2e73c6b4347325ac58d Mon Sep 17 00:00:00 2001 From: Alexander Zobnin Date: Wed, 27 May 2020 12:19:32 +0300 Subject: [PATCH] Exec script dialog --- .../ExecScriptButton/ExecScriptButton.tsx | 13 + src/components/index.ts | 1 + .../components/ExecScriptModal.tsx | 233 ++++++++++++++++++ .../components/Problems/ProblemDetails.tsx | 24 +- .../components/Problems/Problems.tsx | 3 + src/panel-triggers/triggers_panel_ctrl.ts | 10 + 6 files changed, 283 insertions(+), 1 deletion(-) create mode 100644 src/components/ExecScriptButton/ExecScriptButton.tsx create mode 100644 src/panel-triggers/components/ExecScriptModal.tsx diff --git a/src/components/ExecScriptButton/ExecScriptButton.tsx b/src/components/ExecScriptButton/ExecScriptButton.tsx new file mode 100644 index 0000000..9a54f76 --- /dev/null +++ b/src/components/ExecScriptButton/ExecScriptButton.tsx @@ -0,0 +1,13 @@ +import React, { FC } from 'react'; +import { ActionButton } from '../ActionButton/ActionButton'; + +interface Props { + className?: string; + onClick(): void; +} + +export const ExecScriptButton: FC = ({ className, onClick }) => { + return ( + + ); +}; diff --git a/src/components/index.ts b/src/components/index.ts index 767e5b0..c342b30 100644 --- a/src/components/index.ts +++ b/src/components/index.ts @@ -2,5 +2,6 @@ export { GFHeartIcon } from './GFHeartIcon/GFHeartIcon'; export { FAIcon } from './FAIcon/FAIcon'; export { AckButton } from './AckButton/AckButton'; export { ExploreButton } from './ExploreButton/ExploreButton'; +export { ExecScriptButton } from './ExecScriptButton/ExecScriptButton'; export { Tooltip } from './Tooltip/Tooltip'; export { ModalController } from './Modal/ModalController'; diff --git a/src/panel-triggers/components/ExecScriptModal.tsx b/src/panel-triggers/components/ExecScriptModal.tsx new file mode 100644 index 0000000..fa1752c --- /dev/null +++ b/src/panel-triggers/components/ExecScriptModal.tsx @@ -0,0 +1,233 @@ +import React, { PureComponent } from 'react'; +import { cx, css } from 'emotion'; +import { ZBX_ACK_ACTION_ADD_MESSAGE, ZBX_ACK_ACTION_ACK, ZBX_ACK_ACTION_CHANGE_SEVERITY, ZBX_ACK_ACTION_CLOSE } from '../../datasource-zabbix/constants'; +import { APIScriptGetResponse, ZBXScript } from '../../datasource-zabbix/zabbix/connectors/zabbix_api/types'; +import { Button, VerticalGroup, Spinner, Modal, Select, Forms, stylesFactory, withTheme, Themeable } from '@grafana/ui'; +import { FAIcon } from '../../components'; + +import * as grafanaUi from '@grafana/ui'; +import { GrafanaTheme, SelectableValue } from '@grafana/data'; +const Checkbox: any = Forms?.Checkbox || (grafanaUi as any).Checkbox; +const RadioButtonGroup: any = Forms?.RadioButtonGroup || (grafanaUi as any).RadioButtonGroup; + +const KEYBOARD_ENTER_KEY = 13; +const KEYBOARD_ESCAPE_KEY = 27; + +interface Props extends Themeable { + getScripts(): Promise; + onSubmit(data?: AckProblemData): Promise | any; + onDismiss?(): void; +} + +interface State { + selectedScript: SelectableValue; + scriptOptions: Array>; + script: ZBXScript; + error: boolean; + errorMessage: string; + selectError: string; + result: string; + loading: boolean; +} + +export interface AckProblemData { + message: string; + closeProblem?: boolean; + action?: number; + severity?: number; +} + +export class ExecScriptModalUnthemed extends PureComponent { + scripts: ZBXScript[]; + + constructor(props) { + super(props); + this.state = { + error: false, + errorMessage: '', + selectError: '', + selectedScript: null, + result: '', + loading: false, + scriptOptions: [], + script: null, + }; + } + + async componentDidMount() { + const scripts = await this.props.getScripts(); + this.scripts = scripts; + const scriptOptions: Array> = scripts.map(s => { + return { + value: s.scriptid, + label: s.name, + description: s.description || s.command, + }; + }); + + const selectedScript = scriptOptions?.length ? scriptOptions[0] : null; + const script = scripts.find(s => selectedScript.value === s.scriptid); + + this.setState({ scriptOptions, selectedScript, script }); + } + + handleKeyUp = (event: React.KeyboardEvent) => { + if (event.which === KEYBOARD_ENTER_KEY || event.key === 'Enter') { + this.submit(); + } else if (event.which === KEYBOARD_ESCAPE_KEY || event.key === 'Escape') { + this.dismiss(); + } + } + + handleBackdropClick = () => { + this.dismiss(); + } + + onChangeSelectedScript = (v: SelectableValue) => { + const script = this.scripts.find(s => v.value === s.scriptid); + this.setState({ selectedScript: v, script }); + }; + + dismiss = () => { + this.setState({ selectedScript: null, error: false, errorMessage: '', selectError: '', loading: false }); + this.props.onDismiss(); + } + + submit = () => { + // const { acknowledge, changeSeverity, closeProblem } = this.state; + + // const actionSelected = acknowledge || changeSeverity || closeProblem; + // if (!this.state.value && !actionSelected) { + // return this.setState({ + // error: true, + // errorMessage: 'Enter message text or select an action' + // }); + // } + + // this.setState({ ackError: '', loading: true }); + + // const ackData: AckProblemData = { + // message: this.state.value, + // }; + + // let action = ZBX_ACK_ACTION_ADD_MESSAGE; + // if (this.state.acknowledge) { + // action += ZBX_ACK_ACTION_ACK; + // } + // if (this.state.changeSeverity) { + // action += ZBX_ACK_ACTION_CHANGE_SEVERITY; + // ackData.severity = this.state.selectedSeverity; + // } + // if (this.state.closeProblem) { + // action += ZBX_ACK_ACTION_CLOSE; + // } + // ackData.action = action; + + // this.props.onSubmit(ackData).then(() => { + // this.dismiss(); + // }).catch(err => { + // this.setState({ + // ackError: err.message || err.data, + // loading: false, + // }); + // }); + } + + render() { + const { theme } = this.props; + const { scriptOptions, selectedScript, script, selectError, errorMessage } = this.state; + + const styles = getStyles(theme); + const modalClass = cx(styles.modal); + const modalTitleClass = cx(styles.modalHeaderTitle); + const inputGroupClass = cx('gf-form', styles.inputGroup); + const inputHintClass = cx('gf-form-hint-text', styles.inputHint); + const inputErrorClass = cx('gf-form-hint-text', styles.inputError); + const scriptCommandClass = cx('gf-form-hint-text', styles.scriptCommand); + + return ( + + {this.state.loading ? : } + Execute script + + } + > +
+