Problems: improve ack dialog (add ack options), closes #942
This commit is contained in:
@@ -69,8 +69,8 @@
|
|||||||
"ng-annotate-webpack-plugin": "^0.3.0",
|
"ng-annotate-webpack-plugin": "^0.3.0",
|
||||||
"node-sass": "^4.13.0",
|
"node-sass": "^4.13.0",
|
||||||
"prop-types": "^15.6.2",
|
"prop-types": "^15.6.2",
|
||||||
"react": "^16.13.1",
|
"react": "16.12.0",
|
||||||
"react-dom": "^16.13.1",
|
"react-dom": "16.12.0",
|
||||||
"react-popper": "^2.2.3",
|
"react-popper": "^2.2.3",
|
||||||
"react-table-6": "^6.8.6",
|
"react-table-6": "^6.8.6",
|
||||||
"react-test-renderer": "^16.7.0",
|
"react-test-renderer": "^16.7.0",
|
||||||
@@ -83,7 +83,7 @@
|
|||||||
"ts-jest": "^24.2.0",
|
"ts-jest": "^24.2.0",
|
||||||
"ts-loader": "^4.4.1",
|
"ts-loader": "^4.4.1",
|
||||||
"tslint": "5.20.1",
|
"tslint": "5.20.1",
|
||||||
"typescript": "3.7.2",
|
"typescript": "^3.9.2",
|
||||||
"webpack": "4.29.6",
|
"webpack": "4.29.6",
|
||||||
"webpack-cli": "3.2.3"
|
"webpack-cli": "3.2.3"
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -39,7 +39,6 @@ class FunctionEditor extends React.PureComponent<FunctionEditorProps, FunctionEd
|
|||||||
<div style={{ overflow: 'auto', maxHeight: '30rem', textAlign: 'left', fontWeight: 'normal' }}>
|
<div style={{ overflow: 'auto', maxHeight: '30rem', textAlign: 'left', fontWeight: 'normal' }}>
|
||||||
<h4 style={{ color: 'white' }}> {name} </h4>
|
<h4 style={{ color: 'white' }}> {name} </h4>
|
||||||
<div>{description}</div>
|
<div>{description}</div>
|
||||||
/>
|
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -28,8 +28,10 @@ export const SHOW_OK_EVENTS = 1;
|
|||||||
|
|
||||||
// Acknowledge
|
// Acknowledge
|
||||||
export const ZBX_ACK_ACTION_NONE = 0;
|
export const ZBX_ACK_ACTION_NONE = 0;
|
||||||
|
export const ZBX_ACK_ACTION_CLOSE = 1;
|
||||||
export const ZBX_ACK_ACTION_ACK = 2;
|
export const ZBX_ACK_ACTION_ACK = 2;
|
||||||
export const ZBX_ACK_ACTION_ADD_MESSAGE = 4;
|
export const ZBX_ACK_ACTION_ADD_MESSAGE = 4;
|
||||||
|
export const ZBX_ACK_ACTION_CHANGE_SEVERITY = 8;
|
||||||
|
|
||||||
export const TRIGGER_SEVERITY = [
|
export const TRIGGER_SEVERITY = [
|
||||||
{val: 0, text: 'Not classified'},
|
{val: 0, text: 'Not classified'},
|
||||||
|
|||||||
@@ -133,14 +133,21 @@ export class ZabbixAPIConnector {
|
|||||||
// Zabbix API method wrappers //
|
// Zabbix API method wrappers //
|
||||||
////////////////////////////////
|
////////////////////////////////
|
||||||
|
|
||||||
acknowledgeEvent(eventid, message) {
|
acknowledgeEvent(eventid: string, message: string, action?: number, severity?: number) {
|
||||||
const action = semver.gte(this.version, '4.0.0') ? ZBX_ACK_ACTION_ACK + ZBX_ACK_ACTION_ADD_MESSAGE : ZBX_ACK_ACTION_NONE;
|
if (!action) {
|
||||||
const params = {
|
action = semver.gte(this.version, '4.0.0') ? ZBX_ACK_ACTION_ADD_MESSAGE : ZBX_ACK_ACTION_NONE;
|
||||||
|
}
|
||||||
|
|
||||||
|
const params: any = {
|
||||||
eventids: eventid,
|
eventids: eventid,
|
||||||
message: message,
|
message: message,
|
||||||
action: action
|
action: action
|
||||||
};
|
};
|
||||||
|
|
||||||
|
if (severity) {
|
||||||
|
params.severity = severity;
|
||||||
|
}
|
||||||
|
|
||||||
return this.request('event.acknowledge', params);
|
return this.request('event.acknowledge', params);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
236
src/panel-triggers/components/AckModal.tsx
Normal file
236
src/panel-triggers/components/AckModal.tsx
Normal file
@@ -0,0 +1,236 @@
|
|||||||
|
import React, { PureComponent } from 'react';
|
||||||
|
import ReactDOM from 'react-dom';
|
||||||
|
import classNames from 'classnames';
|
||||||
|
import { ZBX_ACK_ACTION_ADD_MESSAGE, ZBX_ACK_ACTION_ACK, ZBX_ACK_ACTION_CHANGE_SEVERITY, ZBX_ACK_ACTION_CLOSE } from '../../datasource-zabbix/constants';
|
||||||
|
import { Button, Input, VerticalGroup, Spinner } from '@grafana/ui';
|
||||||
|
import { FAIcon } from './FAIcon';
|
||||||
|
|
||||||
|
import * as grafanaUi from '@grafana/ui';
|
||||||
|
const Checkbox: any = grafanaUi.Forms?.Checkbox || (grafanaUi as any).Checkbox;
|
||||||
|
const RadioButtonGroup: any = grafanaUi.Forms?.RadioButtonGroup || (grafanaUi as any).RadioButtonGroup;
|
||||||
|
|
||||||
|
const KEYBOARD_ENTER_KEY = 13;
|
||||||
|
const KEYBOARD_ESCAPE_KEY = 27;
|
||||||
|
|
||||||
|
interface Props {
|
||||||
|
canAck?: boolean;
|
||||||
|
canClose?: boolean;
|
||||||
|
isOpen?: boolean;
|
||||||
|
withBackdrop?: boolean;
|
||||||
|
onSubmit: (data?: AckProblemData) => Promise<any> | any;
|
||||||
|
onClose?: () => void;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface State {
|
||||||
|
value: string;
|
||||||
|
error: boolean;
|
||||||
|
errorMessage: string;
|
||||||
|
ackError: string;
|
||||||
|
acknowledge: boolean;
|
||||||
|
closeProblem: boolean;
|
||||||
|
changeSeverity: boolean;
|
||||||
|
selectedSeverity: number;
|
||||||
|
loading: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface AckProblemData {
|
||||||
|
message: string;
|
||||||
|
closeProblem?: boolean;
|
||||||
|
action?: number;
|
||||||
|
severity?: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
const severityOptions = [
|
||||||
|
{value: 0, label: 'Not classified'},
|
||||||
|
{value: 1, label: 'Information'},
|
||||||
|
{value: 2, label: 'Warning'},
|
||||||
|
{value: 3, label: 'Average'},
|
||||||
|
{value: 4, label: 'High'},
|
||||||
|
{value: 5, label: 'Disaster'}
|
||||||
|
];
|
||||||
|
|
||||||
|
export class AckModal extends PureComponent<Props, State> {
|
||||||
|
modalContainer: HTMLElement;
|
||||||
|
|
||||||
|
static defaultProps: Partial<Props> = {
|
||||||
|
withBackdrop: true,
|
||||||
|
};
|
||||||
|
|
||||||
|
constructor(props) {
|
||||||
|
super(props);
|
||||||
|
this.state = {
|
||||||
|
value: '',
|
||||||
|
error: false,
|
||||||
|
errorMessage: '',
|
||||||
|
ackError: '',
|
||||||
|
acknowledge: false,
|
||||||
|
closeProblem: false,
|
||||||
|
changeSeverity: false,
|
||||||
|
selectedSeverity: 0,
|
||||||
|
loading: false,
|
||||||
|
};
|
||||||
|
|
||||||
|
this.modalContainer = document.body;
|
||||||
|
}
|
||||||
|
|
||||||
|
handleChange = (event: React.ChangeEvent<HTMLInputElement>) => {
|
||||||
|
this.setState({ value: event.target.value, error: false });
|
||||||
|
}
|
||||||
|
|
||||||
|
handleKeyUp = (event: React.KeyboardEvent<HTMLInputElement>) => {
|
||||||
|
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();
|
||||||
|
}
|
||||||
|
|
||||||
|
onAcknowledgeToggle = () => {
|
||||||
|
this.setState({ acknowledge: !this.state.acknowledge, error: false });
|
||||||
|
}
|
||||||
|
|
||||||
|
onChangeSeverityToggle = () => {
|
||||||
|
this.setState({ changeSeverity: !this.state.changeSeverity, error: false });
|
||||||
|
}
|
||||||
|
|
||||||
|
onCloseProblemToggle = () => {
|
||||||
|
this.setState({ closeProblem: !this.state.closeProblem, error: false });
|
||||||
|
}
|
||||||
|
|
||||||
|
onChangeSelectedSeverity = v => {
|
||||||
|
this.setState({ selectedSeverity: v });
|
||||||
|
};
|
||||||
|
|
||||||
|
dismiss = () => {
|
||||||
|
this.setState({ value: '', error: false, errorMessage: '', ackError: '', loading: false });
|
||||||
|
this.props.onClose();
|
||||||
|
}
|
||||||
|
|
||||||
|
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((response) => {
|
||||||
|
this.dismiss();
|
||||||
|
}).catch(err => {
|
||||||
|
this.setState({
|
||||||
|
ackError: err.message || err.data,
|
||||||
|
loading: false,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
render() {
|
||||||
|
const { canClose, canAck } = this.props;
|
||||||
|
if (!this.props.isOpen || !this.modalContainer) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
const inputClass = classNames({ 'zbx-ack-error': this.state.error });
|
||||||
|
|
||||||
|
const modalNode = (
|
||||||
|
<div className="modal modal--narrow zbx-ack-modal" key="modal">
|
||||||
|
<div className="modal-body">
|
||||||
|
<div className="modal-header">
|
||||||
|
<h2 className="modal-header-title" style={{ display: 'flex' }}>
|
||||||
|
{this.state.loading ? <Spinner size={18} /> : <FAIcon icon="reply-all" />}
|
||||||
|
<span className="p-l-1">Acknowledge Problem</span>
|
||||||
|
</h2>
|
||||||
|
|
||||||
|
<a className="modal-header-close" onClick={this.dismiss}>
|
||||||
|
<FAIcon icon="remove" />
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
<div className="modal-content">
|
||||||
|
<div className="gf-form">
|
||||||
|
<label className="gf-form-hint">
|
||||||
|
<Input className={inputClass}
|
||||||
|
type="text"
|
||||||
|
name="message"
|
||||||
|
placeholder="Message"
|
||||||
|
maxLength={64}
|
||||||
|
autoComplete="off"
|
||||||
|
autoFocus={true}
|
||||||
|
value={this.state.value}
|
||||||
|
onChange={this.handleChange}
|
||||||
|
onKeyUp={this.handleKeyUp}>
|
||||||
|
</Input>
|
||||||
|
<small className="gf-form-hint-text muted">Press Enter to submit</small>
|
||||||
|
{this.state.error &&
|
||||||
|
<small className="gf-form-hint-text muted ack-error-message">{this.state.errorMessage}</small>
|
||||||
|
}
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="gf-form">
|
||||||
|
<VerticalGroup>
|
||||||
|
<Checkbox label="Acknowledge" value={this.state.acknowledge} onChange={this.onAcknowledgeToggle} />
|
||||||
|
<Checkbox label="Change severity" description="" value={this.state.changeSeverity} onChange={this.onChangeSeverityToggle} />
|
||||||
|
{this.state.changeSeverity &&
|
||||||
|
<RadioButtonGroup
|
||||||
|
size="sm"
|
||||||
|
options={severityOptions}
|
||||||
|
value={this.state.selectedSeverity}
|
||||||
|
onChange={this.onChangeSelectedSeverity}
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
{canClose &&
|
||||||
|
<Checkbox label="Close problem" disabled={!canClose} value={this.state.closeProblem} onChange={this.onCloseProblemToggle} />
|
||||||
|
}
|
||||||
|
</VerticalGroup>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{this.state.ackError &&
|
||||||
|
<div className="gf-form ack-request-error">
|
||||||
|
<span className="ack-error-message">{this.state.ackError}</span>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
|
||||||
|
<div className="gf-form-button-row text-center">
|
||||||
|
<Button variant="primary" onClick={this.submit}>Update</Button>
|
||||||
|
<Button variant="secondary" onClick={this.dismiss}>Cancel</Button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
|
||||||
|
const modalNodeWithBackdrop = [
|
||||||
|
modalNode,
|
||||||
|
<div className="modal-backdrop in" key="modal-backdrop" onClick={this.handleBackdropClick}></div>
|
||||||
|
];
|
||||||
|
|
||||||
|
const modal = this.props.withBackdrop ? modalNodeWithBackdrop : modalNode;
|
||||||
|
return ReactDOM.createPortal(modal, this.modalContainer);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -4,7 +4,7 @@ import _ from 'lodash';
|
|||||||
import moment from 'moment';
|
import moment from 'moment';
|
||||||
import { isNewProblem, formatLastChange } from '../../utils';
|
import { isNewProblem, formatLastChange } from '../../utils';
|
||||||
import { ProblemsPanelOptions, TriggerSeverity } from '../../types';
|
import { ProblemsPanelOptions, TriggerSeverity } from '../../types';
|
||||||
import { AckProblemData, Modal } from '.././Modal';
|
import { AckProblemData, AckModal } from '../AckModal';
|
||||||
import EventTag from '../EventTag';
|
import EventTag from '../EventTag';
|
||||||
import Tooltip from '.././Tooltip/Tooltip';
|
import Tooltip from '.././Tooltip/Tooltip';
|
||||||
import AlertAcknowledges from './AlertAcknowledges';
|
import AlertAcknowledges from './AlertAcknowledges';
|
||||||
@@ -165,7 +165,7 @@ export default class AlertCard extends PureComponent<AlertCardProps, AlertCardSt
|
|||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<Modal withBackdrop={true}
|
<AckModal
|
||||||
isOpen={this.state.showAckDialog}
|
isOpen={this.state.showAckDialog}
|
||||||
onSubmit={this.ackProblem}
|
onSubmit={this.ackProblem}
|
||||||
onClose={this.closeAckDialog} />
|
onClose={this.closeAckDialog} />
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import React, { PureComponent, CSSProperties } from 'react';
|
import React, { PureComponent, CSSProperties } from 'react';
|
||||||
import classNames from 'classnames';
|
import classNames from 'classnames';
|
||||||
import { ProblemsPanelOptions, GFTimeRange } from '../../types';
|
import { ProblemsPanelOptions, GFTimeRange } from '../../types';
|
||||||
import { AckProblemData } from '.././Modal';
|
import { AckProblemData } from '../AckModal';
|
||||||
import AlertCard from './AlertCard';
|
import AlertCard from './AlertCard';
|
||||||
import { ProblemDTO, ZBXTag } from '../../../datasource-zabbix/types';
|
import { ProblemDTO, ZBXTag } from '../../../datasource-zabbix/types';
|
||||||
|
|
||||||
|
|||||||
@@ -1,134 +0,0 @@
|
|||||||
import React, { PureComponent } from 'react';
|
|
||||||
import ReactDOM from 'react-dom';
|
|
||||||
import classNames from 'classnames';
|
|
||||||
|
|
||||||
const KEYBOARD_ENTER_KEY = 13;
|
|
||||||
const KEYBOARD_ESCAPE_KEY = 27;
|
|
||||||
|
|
||||||
interface ModalProps {
|
|
||||||
isOpen?: boolean;
|
|
||||||
withBackdrop?: boolean;
|
|
||||||
onSubmit: (data?: AckProblemData) => Promise<any> | any;
|
|
||||||
onClose?: () => void;
|
|
||||||
}
|
|
||||||
|
|
||||||
interface ModalState {
|
|
||||||
value: string;
|
|
||||||
error: boolean;
|
|
||||||
message: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface AckProblemData {
|
|
||||||
message: string;
|
|
||||||
closeProblem?: boolean;
|
|
||||||
action?: number;
|
|
||||||
}
|
|
||||||
|
|
||||||
export class Modal extends PureComponent<ModalProps, ModalState> {
|
|
||||||
modalContainer: HTMLElement;
|
|
||||||
|
|
||||||
constructor(props) {
|
|
||||||
super(props);
|
|
||||||
this.state = {
|
|
||||||
value: '',
|
|
||||||
error: false,
|
|
||||||
message: '',
|
|
||||||
};
|
|
||||||
|
|
||||||
this.modalContainer = document.body;
|
|
||||||
}
|
|
||||||
|
|
||||||
handleChange = (event: React.ChangeEvent<HTMLInputElement>) => {
|
|
||||||
this.setState({ value: event.target.value, error: false });
|
|
||||||
}
|
|
||||||
|
|
||||||
handleKeyUp = (event: React.KeyboardEvent<HTMLInputElement>) => {
|
|
||||||
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();
|
|
||||||
}
|
|
||||||
|
|
||||||
dismiss = () => {
|
|
||||||
this.setState({ value: '', error: false, message: '' });
|
|
||||||
this.props.onClose();
|
|
||||||
}
|
|
||||||
|
|
||||||
submit = () => {
|
|
||||||
if (!this.state.value) {
|
|
||||||
return this.setState({
|
|
||||||
error: true,
|
|
||||||
message: 'Enter message text'
|
|
||||||
});
|
|
||||||
}
|
|
||||||
this.props.onSubmit({
|
|
||||||
message: this.state.value
|
|
||||||
}).then(() => {
|
|
||||||
this.dismiss();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
render() {
|
|
||||||
if (!this.props.isOpen || !this.modalContainer) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
const inputClass = classNames('gf-form-input', { 'zbx-ack-error': this.state.error });
|
|
||||||
|
|
||||||
const modalNode = (
|
|
||||||
<div className="modal modal--narrow zbx-ack-modal" key="modal">
|
|
||||||
<div className="modal-body">
|
|
||||||
<div className="modal-header">
|
|
||||||
<h2 className="modal-header-title">
|
|
||||||
<i className="fa fa-reply-all"></i>
|
|
||||||
<span className="p-l-1">Acknowledge Problem</span>
|
|
||||||
</h2>
|
|
||||||
|
|
||||||
<a className="modal-header-close" onClick={this.dismiss}>
|
|
||||||
<i className="fa fa-remove"></i>
|
|
||||||
</a>
|
|
||||||
</div>
|
|
||||||
<div className="modal-content">
|
|
||||||
<div className="gf-form">
|
|
||||||
<label className="gf-form-hint">
|
|
||||||
<input className={inputClass}
|
|
||||||
type="text"
|
|
||||||
name="message"
|
|
||||||
placeholder="Message"
|
|
||||||
maxLength={64}
|
|
||||||
autoComplete="off"
|
|
||||||
autoFocus={true}
|
|
||||||
value={this.state.value}
|
|
||||||
onChange={this.handleChange}
|
|
||||||
onKeyUp={this.handleKeyUp}>
|
|
||||||
</input>
|
|
||||||
<small className="gf-form-hint-text muted">Press Enter to submit</small>
|
|
||||||
{this.state.error &&
|
|
||||||
<small className="gf-form-hint-text muted ack-error-message">{this.state.message}</small>
|
|
||||||
}
|
|
||||||
</label>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div className="gf-form-button-row text-center">
|
|
||||||
<button className="btn btn-success" onClick={this.submit}>Acknowledge</button>
|
|
||||||
<button className="btn btn-inverse" onClick={this.dismiss}>Cancel</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
|
|
||||||
const modalNodeWithBackdrop = [
|
|
||||||
modalNode,
|
|
||||||
<div className="modal-backdrop in" key="modal-backdrop" onClick={this.handleBackdropClick}></div>
|
|
||||||
];
|
|
||||||
|
|
||||||
const modal = this.props.withBackdrop ? modalNodeWithBackdrop : modalNode;
|
|
||||||
return ReactDOM.createPortal(modal, this.modalContainer);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -4,7 +4,7 @@ import * as utils from '../../../datasource-zabbix/utils';
|
|||||||
import { MODE_ITEMID, MODE_METRICS } from '../../../datasource-zabbix/constants';
|
import { MODE_ITEMID, MODE_METRICS } from '../../../datasource-zabbix/constants';
|
||||||
import { ProblemDTO, ZBXHost, ZBXGroup, ZBXEvent, ZBXTag, ZBXAlert } from '../../../datasource-zabbix/types';
|
import { ProblemDTO, ZBXHost, ZBXGroup, ZBXEvent, ZBXTag, ZBXAlert } from '../../../datasource-zabbix/types';
|
||||||
import { ZBXItem, ZBXAcknowledge, GFTimeRange, RTRow } from '../../types';
|
import { ZBXItem, ZBXAcknowledge, GFTimeRange, RTRow } from '../../types';
|
||||||
import { Modal, AckProblemData } from '../Modal';
|
import { AckModal, AckProblemData } from '../AckModal';
|
||||||
import EventTag from '../EventTag';
|
import EventTag from '../EventTag';
|
||||||
import Tooltip from '../Tooltip/Tooltip';
|
import Tooltip from '../Tooltip/Tooltip';
|
||||||
import ProblemStatusBar from './ProblemStatusBar';
|
import ProblemStatusBar from './ProblemStatusBar';
|
||||||
@@ -79,9 +79,6 @@ export default class ProblemDetails extends PureComponent<ProblemDetailsProps, P
|
|||||||
const problem = this.props.original as ProblemDTO;
|
const problem = this.props.original as ProblemDTO;
|
||||||
return this.props.onProblemAck(problem, data).then(result => {
|
return this.props.onProblemAck(problem, data).then(result => {
|
||||||
this.closeAckDialog();
|
this.closeAckDialog();
|
||||||
}).catch(err => {
|
|
||||||
console.log(err);
|
|
||||||
this.closeAckDialog();
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -211,7 +208,8 @@ export default class ProblemDetails extends PureComponent<ProblemDetailsProps, P
|
|||||||
{problem.groups && <ProblemGroups groups={problem.groups} className="problem-details-right-item" />}
|
{problem.groups && <ProblemGroups groups={problem.groups} className="problem-details-right-item" />}
|
||||||
{problem.hosts && <ProblemHosts hosts={problem.hosts} className="problem-details-right-item" />}
|
{problem.hosts && <ProblemHosts hosts={problem.hosts} className="problem-details-right-item" />}
|
||||||
</div>
|
</div>
|
||||||
<Modal withBackdrop={true}
|
<AckModal
|
||||||
|
canClose={problem.manual_close === '1'}
|
||||||
isOpen={this.state.showAckDialog}
|
isOpen={this.state.showAckDialog}
|
||||||
onSubmit={this.ackProblem}
|
onSubmit={this.ackProblem}
|
||||||
onClose={this.closeAckDialog} />
|
onClose={this.closeAckDialog} />
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ import * as utils from '../../../datasource-zabbix/utils';
|
|||||||
import { isNewProblem } from '../../utils';
|
import { isNewProblem } from '../../utils';
|
||||||
import EventTag from '../EventTag';
|
import EventTag from '../EventTag';
|
||||||
import ProblemDetails from './ProblemDetails';
|
import ProblemDetails from './ProblemDetails';
|
||||||
import { AckProblemData } from '../Modal';
|
import { AckProblemData } from '../AckModal';
|
||||||
import GFHeartIcon from '../GFHeartIcon';
|
import GFHeartIcon from '../GFHeartIcon';
|
||||||
import { ProblemsPanelOptions, GFTimeRange, RTCell, TriggerSeverity, RTResized } from '../../types';
|
import { ProblemsPanelOptions, GFTimeRange, RTCell, TriggerSeverity, RTResized } from '../../types';
|
||||||
import { ProblemDTO, ZBXEvent, ZBXTag, ZBXAlert } from '../../../datasource-zabbix/types';
|
import { ProblemDTO, ZBXEvent, ZBXTag, ZBXAlert } from '../../../datasource-zabbix/types';
|
||||||
|
|||||||
@@ -329,7 +329,7 @@ export class TriggerPanelCtrl extends MetricsPanelCtrl {
|
|||||||
this.render();
|
this.render();
|
||||||
}
|
}
|
||||||
|
|
||||||
acknowledgeProblem(problem: ProblemDTO, message) {
|
acknowledgeProblem(problem: ProblemDTO, message, action, severity) {
|
||||||
const eventid = problem.eventid;
|
const eventid = problem.eventid;
|
||||||
const grafana_user = this.contextSrv.user.name;
|
const grafana_user = this.contextSrv.user.name;
|
||||||
const ack_message = grafana_user + ' (Grafana): ' + message;
|
const ack_message = grafana_user + ' (Grafana): ' + message;
|
||||||
@@ -340,7 +340,7 @@ export class TriggerPanelCtrl extends MetricsPanelCtrl {
|
|||||||
return Promise.reject({message: 'You have no permissions to acknowledge events.'});
|
return Promise.reject({message: 'You have no permissions to acknowledge events.'});
|
||||||
}
|
}
|
||||||
if (eventid) {
|
if (eventid) {
|
||||||
return datasource.zabbix.acknowledgeEvent(eventid, ack_message);
|
return datasource.zabbix.acknowledgeEvent(eventid, ack_message, action, severity);
|
||||||
} else {
|
} else {
|
||||||
return Promise.reject({message: 'Trigger has no events. Nothing to acknowledge.'});
|
return Promise.reject({message: 'Trigger has no events. Nothing to acknowledge.'});
|
||||||
}
|
}
|
||||||
@@ -348,6 +348,7 @@ export class TriggerPanelCtrl extends MetricsPanelCtrl {
|
|||||||
.then(this.refresh.bind(this))
|
.then(this.refresh.bind(this))
|
||||||
.catch((err) => {
|
.catch((err) => {
|
||||||
this.setPanelError(err);
|
this.setPanelError(err);
|
||||||
|
return Promise.reject(err);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -401,8 +402,8 @@ export class TriggerPanelCtrl extends MetricsPanelCtrl {
|
|||||||
onPageSizeChange: ctrl.handlePageSizeChange.bind(ctrl),
|
onPageSizeChange: ctrl.handlePageSizeChange.bind(ctrl),
|
||||||
onColumnResize: ctrl.handleColumnResize.bind(ctrl),
|
onColumnResize: ctrl.handleColumnResize.bind(ctrl),
|
||||||
onProblemAck: (trigger, data) => {
|
onProblemAck: (trigger, data) => {
|
||||||
const message = data.message;
|
const { message, action, severity } = data;
|
||||||
return ctrl.acknowledgeProblem(trigger, message);
|
return ctrl.acknowledgeProblem(trigger, message, action, severity);
|
||||||
},
|
},
|
||||||
onTagClick: (tag, datasource, ctrlKey, shiftKey) => {
|
onTagClick: (tag, datasource, ctrlKey, shiftKey) => {
|
||||||
if (ctrlKey || shiftKey) {
|
if (ctrlKey || shiftKey) {
|
||||||
|
|||||||
@@ -598,9 +598,19 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.zbx-ack-modal {
|
.zbx-ack-modal {
|
||||||
.gf-form-input.zbx-ack-error {
|
.zbx-ack-error {
|
||||||
border-color: $btn-danger-bg;
|
border-color: $btn-danger-bg;
|
||||||
box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 5px $btn-danger-bg;
|
// box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 5px $btn-danger-bg;
|
||||||
|
outline-offset: 2px;
|
||||||
|
box-shadow: 0 0 0 2px #141619, 0 0 0px 4px $btn-danger-bg;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ack-request-error {
|
||||||
|
padding-top: 1.2rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ack-error-message {
|
||||||
|
color: $error-text-color;
|
||||||
}
|
}
|
||||||
|
|
||||||
.gf-form .gf-form-hint {
|
.gf-form .gf-form-hint {
|
||||||
@@ -610,7 +620,6 @@
|
|||||||
|
|
||||||
&.ack-error-message {
|
&.ack-error-message {
|
||||||
float: left;
|
float: left;
|
||||||
color: $error-text-color;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -18,6 +18,7 @@
|
|||||||
"noImplicitUseStrict": false,
|
"noImplicitUseStrict": false,
|
||||||
"noImplicitAny": false,
|
"noImplicitAny": false,
|
||||||
"noUnusedLocals": false,
|
"noUnusedLocals": false,
|
||||||
"baseUrl": "./src"
|
"baseUrl": "./src",
|
||||||
|
"strictFunctionTypes": false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
64
yarn.lock
64
yarn.lock
@@ -33,10 +33,10 @@
|
|||||||
dependencies:
|
dependencies:
|
||||||
"@antv/util" "~1.3.1"
|
"@antv/util" "~1.3.1"
|
||||||
|
|
||||||
"@antv/g2@3.5.13":
|
"@antv/g2@3.5.15":
|
||||||
version "3.5.13"
|
version "3.5.15"
|
||||||
resolved "https://registry.yarnpkg.com/@antv/g2/-/g2-3.5.13.tgz#2b0365406e89855e6af34cd374bcb307a0edad42"
|
resolved "https://registry.yarnpkg.com/@antv/g2/-/g2-3.5.15.tgz#5951808f88210f4a45ca1acb38fb25a743b4a578"
|
||||||
integrity sha512-Ok1hA4GyXWrYEAfDo54um4XCz2QNgwe4i45xNsVKHx+HXY0lwzkLp+LLa0QoFVW3gcxrBCrsGww3rp6GafEJGg==
|
integrity sha512-gWN28V/BRHrCe6O12WcJ7ji9UE8XETSQ146ur4zMu5I50ZO7kxc/3s038N0iyuJh3Em9nlrTjfhqjlysogrX7g==
|
||||||
dependencies:
|
dependencies:
|
||||||
"@antv/adjust" "~0.1.0"
|
"@antv/adjust" "~0.1.0"
|
||||||
"@antv/attr" "~0.1.2"
|
"@antv/attr" "~0.1.2"
|
||||||
@@ -2244,11 +2244,11 @@ bindings@^1.5.0:
|
|||||||
file-uri-to-path "1.0.0"
|
file-uri-to-path "1.0.0"
|
||||||
|
|
||||||
bizcharts@^3.5.5:
|
bizcharts@^3.5.5:
|
||||||
version "3.5.8"
|
version "3.5.9"
|
||||||
resolved "https://registry.yarnpkg.com/bizcharts/-/bizcharts-3.5.8.tgz#50abcb4960891aada6ca35318af791dd68d85825"
|
resolved "https://registry.yarnpkg.com/bizcharts/-/bizcharts-3.5.9.tgz#b4c56c8bc5e8567f65748aeb3916902c4e9c98c0"
|
||||||
integrity sha512-s/Nt66HLQXD8oyN8yE26inh5ZGkoIr1eFE+/2TBln6lpyATm51LrqCXJPOTgOSyEp3dSNVZ7rOFCKFMMVcdOwA==
|
integrity sha512-1GI1SWNHfU3xRYGh4b4Dn6gfHMaOZnl0EXewZGEL5V5/m97k2kBonedA0LvtdrOQZRAAM+sP1uwny/ttkNsnEQ==
|
||||||
dependencies:
|
dependencies:
|
||||||
"@antv/g2" "3.5.13"
|
"@antv/g2" "3.5.15"
|
||||||
"@babel/runtime" "^7.7.6"
|
"@babel/runtime" "^7.7.6"
|
||||||
invariant "^2.2.2"
|
invariant "^2.2.2"
|
||||||
lodash.debounce "^4.0.8"
|
lodash.debounce "^4.0.8"
|
||||||
@@ -7823,9 +7823,9 @@ rc-slider@8.7.1:
|
|||||||
warning "^4.0.3"
|
warning "^4.0.3"
|
||||||
|
|
||||||
rc-time-picker@^3.7.2:
|
rc-time-picker@^3.7.2:
|
||||||
version "3.7.2"
|
version "3.7.3"
|
||||||
resolved "https://registry.yarnpkg.com/rc-time-picker/-/rc-time-picker-3.7.2.tgz#fabe5501adf1374d31a2d3b47f1ba89fc2dc2467"
|
resolved "https://registry.yarnpkg.com/rc-time-picker/-/rc-time-picker-3.7.3.tgz#65a8de904093250ae9c82b02a4905e0f995e23e2"
|
||||||
integrity sha512-UVWO9HXGyZoM4I2THlJsEAFcZQz+tYwdcpoHXCEFZsRLz9L2+7vV4EMp9Wa3UrtzMFEt83qSAX/90dCJeKl9sg==
|
integrity sha512-Lv1Mvzp9fRXhXEnRLO4nW6GLNxUkfAZ3RsiIBsWjGjXXvMNjdr4BX/ayElHAFK0DoJqOhm7c5tjmIYpEOwcUXg==
|
||||||
dependencies:
|
dependencies:
|
||||||
classnames "2.x"
|
classnames "2.x"
|
||||||
moment "2.x"
|
moment "2.x"
|
||||||
@@ -7868,12 +7868,11 @@ rc-util@^4.0.4, rc-util@^4.4.0, rc-util@^4.8.0:
|
|||||||
shallowequal "^0.2.2"
|
shallowequal "^0.2.2"
|
||||||
|
|
||||||
rc-util@^4.11.2:
|
rc-util@^4.11.2:
|
||||||
version "4.20.1"
|
version "4.20.5"
|
||||||
resolved "https://registry.yarnpkg.com/rc-util/-/rc-util-4.20.1.tgz#a5976eabfc3198ed9b8e79ffb8c53c231db36e77"
|
resolved "https://registry.yarnpkg.com/rc-util/-/rc-util-4.20.5.tgz#f7c77569e971ae6a8ad56f899cadd22275398325"
|
||||||
integrity sha512-EGlDg9KPN0POzmAR2hk9ZyFc3DmJIrXwlC8NoDxJguX2LTINnVqwadLIVauLfYgYISMiFYFrSHiFW+cqUhZ5dA==
|
integrity sha512-f67s4Dt1quBYhrVPq5QMKmK3eS2hN1NNIAyhaiG0HmvqiGYAXMQ7SP2AlGqv750vnzhJs38JklbkWT1/wjhFPg==
|
||||||
dependencies:
|
dependencies:
|
||||||
add-dom-event-listener "^1.1.0"
|
add-dom-event-listener "^1.1.0"
|
||||||
babel-runtime "6.x"
|
|
||||||
prop-types "^15.5.10"
|
prop-types "^15.5.10"
|
||||||
react-is "^16.12.0"
|
react-is "^16.12.0"
|
||||||
react-lifecycles-compat "^3.0.4"
|
react-lifecycles-compat "^3.0.4"
|
||||||
@@ -7920,16 +7919,6 @@ react-dom@16.12.0:
|
|||||||
prop-types "^15.6.2"
|
prop-types "^15.6.2"
|
||||||
scheduler "^0.18.0"
|
scheduler "^0.18.0"
|
||||||
|
|
||||||
react-dom@^16.13.1:
|
|
||||||
version "16.13.1"
|
|
||||||
resolved "https://registry.yarnpkg.com/react-dom/-/react-dom-16.13.1.tgz#c1bd37331a0486c078ee54c4740720993b2e0e7f"
|
|
||||||
integrity sha512-81PIMmVLnCNLO/fFOQxdQkvEq/+Hfpv24XNJfpyZhTRfO0QcmQIF/PgCa1zCOj2w1hrn12MFLyaJ/G0+Mxtfag==
|
|
||||||
dependencies:
|
|
||||||
loose-envify "^1.1.0"
|
|
||||||
object-assign "^4.1.1"
|
|
||||||
prop-types "^15.6.2"
|
|
||||||
scheduler "^0.19.1"
|
|
||||||
|
|
||||||
react-fast-compare@^3.0.1:
|
react-fast-compare@^3.0.1:
|
||||||
version "3.0.1"
|
version "3.0.1"
|
||||||
resolved "https://registry.yarnpkg.com/react-fast-compare/-/react-fast-compare-3.0.1.tgz#884d339ce1341aad22392e7a88664c71da48600e"
|
resolved "https://registry.yarnpkg.com/react-fast-compare/-/react-fast-compare-3.0.1.tgz#884d339ce1341aad22392e7a88664c71da48600e"
|
||||||
@@ -8069,15 +8058,6 @@ react@16.12.0:
|
|||||||
object-assign "^4.1.1"
|
object-assign "^4.1.1"
|
||||||
prop-types "^15.6.2"
|
prop-types "^15.6.2"
|
||||||
|
|
||||||
react@^16.13.1:
|
|
||||||
version "16.13.1"
|
|
||||||
resolved "https://registry.yarnpkg.com/react/-/react-16.13.1.tgz#2e818822f1a9743122c063d6410d85c1e3afe48e"
|
|
||||||
integrity sha512-YMZQQq32xHLX0bz5Mnibv1/LHb3Sqzngu7xstSM+vrkE5Kzr9xE0yMByK5kMoTK30YVJE61WfbxIFFvfeDKT1w==
|
|
||||||
dependencies:
|
|
||||||
loose-envify "^1.1.0"
|
|
||||||
object-assign "^4.1.1"
|
|
||||||
prop-types "^15.6.2"
|
|
||||||
|
|
||||||
reactcss@^1.2.0:
|
reactcss@^1.2.0:
|
||||||
version "1.2.3"
|
version "1.2.3"
|
||||||
resolved "https://registry.yarnpkg.com/reactcss/-/reactcss-1.2.3.tgz#c00013875e557b1cf0dfd9a368a1c3dab3b548dd"
|
resolved "https://registry.yarnpkg.com/reactcss/-/reactcss-1.2.3.tgz#c00013875e557b1cf0dfd9a368a1c3dab3b548dd"
|
||||||
@@ -8608,14 +8588,6 @@ scheduler@^0.18.0:
|
|||||||
loose-envify "^1.1.0"
|
loose-envify "^1.1.0"
|
||||||
object-assign "^4.1.1"
|
object-assign "^4.1.1"
|
||||||
|
|
||||||
scheduler@^0.19.1:
|
|
||||||
version "0.19.1"
|
|
||||||
resolved "https://registry.yarnpkg.com/scheduler/-/scheduler-0.19.1.tgz#4f3e2ed2c1a7d65681f4c854fa8c5a1ccb40f196"
|
|
||||||
integrity sha512-n/zwRWRYSUj0/3g/otKDRPMh6qv2SYMWNq85IEa8iZyAv8od9zDYpGSnpBEjNgcMNq6Scbu5KfIPxNF72R/2EA==
|
|
||||||
dependencies:
|
|
||||||
loose-envify "^1.1.0"
|
|
||||||
object-assign "^4.1.1"
|
|
||||||
|
|
||||||
schema-utils@^0.4.5:
|
schema-utils@^0.4.5:
|
||||||
version "0.4.7"
|
version "0.4.7"
|
||||||
resolved "https://registry.yarnpkg.com/schema-utils/-/schema-utils-0.4.7.tgz#ba74f597d2be2ea880131746ee17d0a093c68187"
|
resolved "https://registry.yarnpkg.com/schema-utils/-/schema-utils-0.4.7.tgz#ba74f597d2be2ea880131746ee17d0a093c68187"
|
||||||
@@ -9684,10 +9656,10 @@ typedarray@^0.0.6:
|
|||||||
resolved "https://registry.yarnpkg.com/typedarray/-/typedarray-0.0.6.tgz#867ac74e3864187b1d3d47d996a78ec5c8830777"
|
resolved "https://registry.yarnpkg.com/typedarray/-/typedarray-0.0.6.tgz#867ac74e3864187b1d3d47d996a78ec5c8830777"
|
||||||
integrity sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c=
|
integrity sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c=
|
||||||
|
|
||||||
typescript@3.7.2:
|
typescript@^3.9.2:
|
||||||
version "3.7.2"
|
version "3.9.2"
|
||||||
resolved "https://registry.yarnpkg.com/typescript/-/typescript-3.7.2.tgz#27e489b95fa5909445e9fef5ee48d81697ad18fb"
|
resolved "https://registry.yarnpkg.com/typescript/-/typescript-3.9.2.tgz#64e9c8e9be6ea583c54607677dd4680a1cf35db9"
|
||||||
integrity sha512-ml7V7JfiN2Xwvcer+XAf2csGO1bPBdRbFCkYBczNZggrBZ9c7G3riSUeJmqEU5uOtXNPMhE3n+R4FA/3YOAWOQ==
|
integrity sha512-q2ktq4n/uLuNNShyayit+DTobV2ApPEo/6so68JaD5ojvc/6GClBipedB9zNWYxRSAlZXAe405Rlijzl6qDiSw==
|
||||||
|
|
||||||
typical@^2.6.1:
|
typical@^2.6.1:
|
||||||
version "2.6.1"
|
version "2.6.1"
|
||||||
|
|||||||
Reference in New Issue
Block a user