legacy form migration

This commit is contained in:
Gareth Dawson
2023-11-14 15:41:36 +00:00
parent 17d71f6d9e
commit c9f515686c
6 changed files with 129 additions and 116 deletions

View File

@@ -1,6 +1,6 @@
import React, { useEffect } from 'react';
import { QueryEditorProps, SelectableValue } from '@grafana/data';
import { InlineField, InlineFieldRow, Select } from '@grafana/ui';
import { InlineField, Select } from '@grafana/ui';
import * as c from '../constants';
import { migrate, DS_QUERY_SCHEMA } from '../migrations';
import { ZabbixDatasource } from '../datasource';
@@ -14,6 +14,7 @@ import { ItemIdQueryEditor } from './QueryEditor/ItemIdQueryEditor';
import { ServicesQueryEditor } from './QueryEditor/ServicesQueryEditor';
import { TriggersQueryEditor } from './QueryEditor/TriggersQueryEditor';
import { UserMacrosQueryEditor } from './QueryEditor/UserMacrosQueryEditor';
import { QueryEditorRow } from './QueryEditor/QueryEditorRow';
const zabbixQueryTypeOptions: Array<SelectableValue<string>> = [
{
@@ -197,7 +198,7 @@ export const QueryEditor = ({ query, datasource, onChange, onRunQuery }: ZabbixQ
return (
<>
<InlineFieldRow>
<QueryEditorRow>
<InlineField label="Query type" labelWidth={12}>
<Select
isSearchable={false}
@@ -207,10 +208,7 @@ export const QueryEditor = ({ query, datasource, onChange, onRunQuery }: ZabbixQ
onChange={onPropChange('queryType')}
/>
</InlineField>
<div className="gf-form gf-form--grow">
<div className="gf-form-label gf-form-label--grow" />
</div>
</InlineFieldRow>
</QueryEditorRow>
{queryType === c.MODE_METRICS && renderMetricsEditor()}
{queryType === c.MODE_ITEMID && renderItemIdsEditor()}
{queryType === c.MODE_TEXT && renderTextMetricsEditor()}

View File

@@ -1,13 +1,24 @@
import React from 'react';
import { InlineFieldRow } from '@grafana/ui';
import { InlineFieldRow, InlineFormLabel } from '@grafana/ui';
import { css } from '@emotion/css';
export const QueryEditorRow = ({ children }: React.PropsWithChildren<{}>) => {
const styles = getStyles();
return (
<InlineFieldRow>
{children}
<div className="gf-form gf-form--grow">
<div className="gf-form-label gf-form-label--grow" />
</div>
<InlineFormLabel className={styles.rowTerminator}>
<></>
</InlineFormLabel>
</InlineFieldRow>
);
};
const getStyles = () => {
return {
rowTerminator: css({
flexGrow: 1,
}),
};
};

View File

@@ -3,7 +3,7 @@ import { parseLegacyVariableQuery } from '../utils';
import { SelectableValue } from '@grafana/data';
import { VariableQuery, VariableQueryData, VariableQueryProps, VariableQueryTypes } from '../types';
import { ZabbixInput } from './ZabbixInput';
import { InlineFormLabel, Input, Select } from '@grafana/ui';
import { InlineField, InlineFieldRow, InlineFormLabel, Input, Select } from '@grafana/ui';
export class ZabbixVariableQueryEditor extends PureComponent<VariableQueryProps, VariableQueryData> {
queryTypes: Array<SelectableValue<VariableQueryTypes>> = [
@@ -94,81 +94,95 @@ export class ZabbixVariableQueryEditor extends PureComponent<VariableQueryProps,
return (
<>
<div className="gf-form max-width-21">
<InlineFormLabel width={10}>Query Type</InlineFormLabel>
<InlineFieldRow>
<InlineField label="Query Type" labelWidth={16}>
<Select
width={11}
width={30}
value={selectedQueryType}
options={this.queryTypes}
onChange={this.handleQueryTypeChange}
/>
</div>
<div className="gf-form-inline">
<div className="gf-form max-width-30">
<InlineFormLabel width={10}>Group</InlineFormLabel>
</InlineField>
</InlineFieldRow>
<InlineFieldRow>
<InlineField label="Group" labelWidth={16}>
<ZabbixInput
width={30}
value={group}
onChange={(evt) => this.handleQueryUpdate(evt, 'group')}
onBlur={this.handleQueryChange}
/>
</div>
</InlineField>
</InlineFieldRow>
{selectedQueryType.value !== VariableQueryTypes.Group && (
<div className="gf-form max-width-30">
<InlineFormLabel width={10}>Host</InlineFormLabel>
<InlineFieldRow>
<InlineField label="Host" labelWidth={16}>
<ZabbixInput
width={30}
value={host}
onChange={(evt) => this.handleQueryUpdate(evt, 'host')}
onBlur={this.handleQueryChange}
/>
</div>
</InlineField>
</InlineFieldRow>
)}
</div>
{(selectedQueryType.value === VariableQueryTypes.Application ||
selectedQueryType.value === VariableQueryTypes.ItemTag ||
selectedQueryType.value === VariableQueryTypes.Item ||
selectedQueryType.value === VariableQueryTypes.ItemValues) && (
<div className="gf-form-inline">
<>
{supportsItemTags && (
<div className="gf-form max-width-30">
<InlineFormLabel width={10}>Item tag</InlineFormLabel>
<InlineFieldRow>
<InlineField label="Item Tag" labelWidth={16}>
<ZabbixInput
width={30}
value={itemTag}
onChange={(evt) => this.handleQueryUpdate(evt, 'itemTag')}
onBlur={this.handleQueryChange}
/>
</div>
</InlineField>
</InlineFieldRow>
)}
{!supportsItemTags && (
<div className="gf-form max-width-30">
<InlineFormLabel width={10}>Application</InlineFormLabel>
<InlineFieldRow>
<InlineField label="Application" labelWidth={16}>
<ZabbixInput
width={30}
value={application}
onChange={(evt) => this.handleQueryUpdate(evt, 'application')}
onBlur={this.handleQueryChange}
/>
</div>
</InlineField>
</InlineFieldRow>
)}
{(selectedQueryType.value === VariableQueryTypes.Item ||
selectedQueryType.value === VariableQueryTypes.ItemValues) && (
<div className="gf-form max-width-30">
<InlineFormLabel width={10}>Item</InlineFormLabel>
<InlineFieldRow>
<InlineField label="Item" labelWidth={16}>
<ZabbixInput
width={30}
value={item}
onChange={(evt) => this.handleQueryUpdate(evt, 'item')}
onBlur={this.handleQueryChange}
/>
</div>
</InlineField>
</InlineFieldRow>
)}
</div>
</>
)}
{legacyQuery && (
<div className="gf-form">
<>
<InlineFormLabel width={10} tooltip="Original query string, read-only">
Legacy Query
</InlineFormLabel>
<Input value={legacyQuery} readOnly={true} />
</div>
</>
)}
</>
);

View File

@@ -5,7 +5,7 @@ import { GrafanaTheme2 } from '@grafana/data';
import { isRegex, variableRegex } from '../utils';
import * as grafanaUi from '@grafana/ui';
const Input = (grafanaUi as any).LegacyForms?.Input || (grafanaUi as any).Input;
const Input = (grafanaUi as any).Input || (grafanaUi as any).LegacyForms?.Input;
const variablePattern = RegExp(`^${variableRegex.source}`);

View File

@@ -1,5 +1,5 @@
import React, { PureComponent } from 'react';
import { cx, css } from '@emotion/css';
import { css } from '@emotion/css';
import {
ZBX_ACK_ACTION_ADD_MESSAGE,
ZBX_ACK_ACTION_ACK,
@@ -17,6 +17,7 @@ import {
withTheme,
Themeable,
TextArea,
ButtonGroup,
} from '@grafana/ui';
import { FAIcon } from '../../components';
import { GrafanaTheme } from '@grafana/data';
@@ -200,31 +201,23 @@ export class AckModalUnthemed extends PureComponent<Props, State> {
render() {
const { theme } = this.props;
const styles = getStyles(theme);
const modalClass = cx(styles.modal);
const modalTitleClass = cx(styles.modalHeaderTitle);
const inputGroupClass = cx('gf-form', styles.inputGroup);
const inputClass = cx(this.state.error && styles.input);
const inputHintClass = cx('gf-form-hint-text', styles.inputHint);
const inputErrorClass = cx('gf-form-hint-text', styles.inputError);
return (
<Modal
isOpen={true}
onDismiss={this.dismiss}
className={modalClass}
className={styles.modal}
title={
<div className={modalTitleClass}>
<div className={styles.modalHeaderTitle}>
{this.state.loading ? <Spinner size={18} /> : <FAIcon icon="reply-all" />}
<span className="p-l-1">Acknowledge Problem</span>
Acknowledge Problem
</div>
}
>
<div className={inputGroupClass}>
<label className="gf-form-hint">
<div className={styles.inputGroup}>
<TextArea
className={inputClass}
className={this.state.error && styles.input}
type="text"
name="message"
placeholder="Message"
@@ -233,30 +226,24 @@ export class AckModalUnthemed extends PureComponent<Props, State> {
value={this.state.value}
onChange={this.handleChange}
onKeyDown={this.handleKeyPress}
></TextArea>
<small className={inputHintClass}>Press Enter to submit</small>
{this.state.error && <small className={inputErrorClass}>{this.state.errorMessage}</small>}
</label>
/>
<small className={styles.inputHint}>Press Enter to submit</small>
{this.state.error && <small className={styles.inputError}>{this.state.errorMessage}</small>}
</div>
<div className="gf-form">
<VerticalGroup>{this.renderActions()}</VerticalGroup>
</div>
{this.state.ackError && (
<div className="gf-form ack-request-error">
<span className={styles.ackError}>{this.state.ackError}</span>
</div>
)}
{this.state.ackError && <span className={styles.ackError}>{this.state.ackError}</span>}
<div className="gf-form-button-row text-center">
<ButtonGroup className={styles.buttonGroup}>
<Button variant="primary" onClick={this.submit}>
Update
</Button>
<Button variant="secondary" onClick={this.dismiss}>
Cancel
</Button>
</div>
</ButtonGroup>
</Modal>
);
}
@@ -297,6 +284,11 @@ const getStyles = stylesFactory((theme: GrafanaTheme) => {
ackError: css`
color: ${red};
`,
buttonGroup: css`
justify-content: center;
gap: ${theme.spacing.sm};
margin-top: ${theme.spacing.md};
`,
};
});

View File

@@ -1,7 +1,7 @@
import React, { PureComponent } from 'react';
import { cx, css } from '@emotion/css';
import { css } from '@emotion/css';
import { GrafanaTheme, SelectableValue } from '@grafana/data';
import { Button, Spinner, Modal, Select, stylesFactory, withTheme, Themeable } from '@grafana/ui';
import { Button, Spinner, Modal, Select, stylesFactory, withTheme, Themeable, ButtonGroup } from '@grafana/ui';
import { ZBXScript, APIExecuteScriptResponse } from '../../datasource/zabbix/connectors/zabbix_api/types';
import { FAIcon } from '../../components';
@@ -118,32 +118,24 @@ export class ExecScriptModalUnthemed extends PureComponent<Props, State> {
const { scriptOptions, selectedScript, script, result, selectError, errorMessage, error } = this.state;
const styles = getStyles(theme);
const modalClass = cx(styles.modal);
const modalTitleClass = cx(styles.modalHeaderTitle);
const selectErrorClass = cx('gf-form-hint-text', styles.inputError);
const scriptCommandContainerClass = cx('gf-form', styles.scriptCommandContainer);
const scriptCommandClass = cx('gf-form-hint-text', styles.scriptCommand);
return (
<Modal
isOpen={true}
onDismiss={this.dismiss}
className={modalClass}
className={styles.modal}
title={
<div className={modalTitleClass}>
<div className={styles.modalHeaderTitle}>
{this.state.loading ? <Spinner size={18} /> : <FAIcon icon="terminal" />}
<span className="p-l-1">Execute script</span>
Execute script
</div>
}
>
<div className="gf-form">
<label className="gf-form-hint">
<Select options={scriptOptions} value={selectedScript} onChange={this.onChangeSelectedScript} />
{selectError && <small className={selectErrorClass}>{selectError}</small>}
</label>
</div>
<div className={scriptCommandContainerClass}>
{script && <small className={scriptCommandClass}>{script.command}</small>}
{selectError && <small className={styles.inputError}>{selectError}</small>}
<div className={styles.scriptCommandContainer}>
{script && <small className={styles.scriptCommand}>{script.command}</small>}
</div>
<div className={styles.resultContainer}>
@@ -151,14 +143,15 @@ export class ExecScriptModalUnthemed extends PureComponent<Props, State> {
{error && <span className={styles.execError}>{errorMessage}</span>}
</div>
<div className="gf-form-button-row text-center">
<ButtonGroup className={styles.buttonGroup}>
<Button variant="primary" onClick={this.submit}>
Execute
</Button>
<Button variant="secondary" onClick={this.dismiss}>
Cancel
</Button>
</div>
</ButtonGroup>
</Modal>
);
}
@@ -214,6 +207,11 @@ const getStyles = stylesFactory((theme: GrafanaTheme) => {
execError: css`
color: ${red};
`,
buttonGroup: css`
justify-content: center;
gap: ${theme.spacing.sm};
margin-top: ${theme.spacing.md};
`,
};
});