Merge pull request #1743 from grafana/gareth/legacy-forms

legacy form migration
This commit is contained in:
Gareth Dawson
2023-11-20 10:07:39 +00:00
committed by GitHub
6 changed files with 129 additions and 116 deletions

View File

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

View File

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

View File

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

View File

@@ -5,7 +5,7 @@ import { GrafanaTheme2 } from '@grafana/data';
import { isRegex, variableRegex } from '../utils'; import { isRegex, variableRegex } from '../utils';
import * as grafanaUi from '@grafana/ui'; 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}`); const variablePattern = RegExp(`^${variableRegex.source}`);

View File

@@ -1,5 +1,5 @@
import React, { PureComponent } from 'react'; import React, { PureComponent } from 'react';
import { cx, css } from '@emotion/css'; import { css } from '@emotion/css';
import { import {
ZBX_ACK_ACTION_ADD_MESSAGE, ZBX_ACK_ACTION_ADD_MESSAGE,
ZBX_ACK_ACTION_ACK, ZBX_ACK_ACTION_ACK,
@@ -17,6 +17,7 @@ import {
withTheme, withTheme,
Themeable, Themeable,
TextArea, TextArea,
ButtonGroup,
} from '@grafana/ui'; } from '@grafana/ui';
import { FAIcon } from '../../components'; import { FAIcon } from '../../components';
import { GrafanaTheme } from '@grafana/data'; import { GrafanaTheme } from '@grafana/data';
@@ -200,63 +201,49 @@ export class AckModalUnthemed extends PureComponent<Props, State> {
render() { render() {
const { theme } = this.props; const { theme } = this.props;
const styles = getStyles(theme); 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 ( return (
<Modal <Modal
isOpen={true} isOpen={true}
onDismiss={this.dismiss} onDismiss={this.dismiss}
className={modalClass} className={styles.modal}
title={ title={
<div className={modalTitleClass}> <div className={styles.modalHeaderTitle}>
{this.state.loading ? <Spinner size={18} /> : <FAIcon icon="reply-all" />} {this.state.loading ? <Spinner size={18} /> : <FAIcon icon="reply-all" />}
<span className="p-l-1">Acknowledge Problem</span> Acknowledge Problem
</div> </div>
} }
> >
<div className={inputGroupClass}> <div className={styles.inputGroup}>
<label className="gf-form-hint"> <TextArea
<TextArea className={this.state.error && styles.input}
className={inputClass} type="text"
type="text" name="message"
name="message" placeholder="Message"
placeholder="Message" autoComplete="off"
autoComplete="off" autoFocus={true}
autoFocus={true} value={this.state.value}
value={this.state.value} onChange={this.handleChange}
onChange={this.handleChange} onKeyDown={this.handleKeyPress}
onKeyDown={this.handleKeyPress} />
></TextArea> <small className={styles.inputHint}>Press Enter to submit</small>
<small className={inputHintClass}>Press Enter to submit</small> {this.state.error && <small className={styles.inputError}>{this.state.errorMessage}</small>}
{this.state.error && <small className={inputErrorClass}>{this.state.errorMessage}</small>}
</label>
</div> </div>
<div className="gf-form"> <VerticalGroup>{this.renderActions()}</VerticalGroup>
<VerticalGroup>{this.renderActions()}</VerticalGroup>
</div>
{this.state.ackError && ( {this.state.ackError && <span className={styles.ackError}>{this.state.ackError}</span>}
<div className="gf-form ack-request-error">
<span className={styles.ackError}>{this.state.ackError}</span>
</div>
)}
<div className="gf-form-button-row text-center"> <ButtonGroup className={styles.buttonGroup}>
<Button variant="primary" onClick={this.submit}> <Button variant="primary" onClick={this.submit}>
Update Update
</Button> </Button>
<Button variant="secondary" onClick={this.dismiss}> <Button variant="secondary" onClick={this.dismiss}>
Cancel Cancel
</Button> </Button>
</div> </ButtonGroup>
</Modal> </Modal>
); );
} }
@@ -297,6 +284,11 @@ const getStyles = stylesFactory((theme: GrafanaTheme) => {
ackError: css` ackError: css`
color: ${red}; 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 React, { PureComponent } from 'react';
import { cx, css } from '@emotion/css'; import { css } from '@emotion/css';
import { GrafanaTheme, SelectableValue } from '@grafana/data'; 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 { ZBXScript, APIExecuteScriptResponse } from '../../datasource/zabbix/connectors/zabbix_api/types';
import { FAIcon } from '../../components'; 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 { scriptOptions, selectedScript, script, result, selectError, errorMessage, error } = this.state;
const styles = getStyles(theme); 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 ( return (
<Modal <Modal
isOpen={true} isOpen={true}
onDismiss={this.dismiss} onDismiss={this.dismiss}
className={modalClass} className={styles.modal}
title={ title={
<div className={modalTitleClass}> <div className={styles.modalHeaderTitle}>
{this.state.loading ? <Spinner size={18} /> : <FAIcon icon="terminal" />} {this.state.loading ? <Spinner size={18} /> : <FAIcon icon="terminal" />}
<span className="p-l-1">Execute script</span> Execute script
</div> </div>
} }
> >
<div className="gf-form"> <Select options={scriptOptions} value={selectedScript} onChange={this.onChangeSelectedScript} />
<label className="gf-form-hint"> {selectError && <small className={styles.inputError}>{selectError}</small>}
<Select options={scriptOptions} value={selectedScript} onChange={this.onChangeSelectedScript} />
{selectError && <small className={selectErrorClass}>{selectError}</small>} <div className={styles.scriptCommandContainer}>
</label> {script && <small className={styles.scriptCommand}>{script.command}</small>}
</div>
<div className={scriptCommandContainerClass}>
{script && <small className={scriptCommandClass}>{script.command}</small>}
</div> </div>
<div className={styles.resultContainer}> <div className={styles.resultContainer}>
@@ -151,14 +143,15 @@ export class ExecScriptModalUnthemed extends PureComponent<Props, State> {
{error && <span className={styles.execError}>{errorMessage}</span>} {error && <span className={styles.execError}>{errorMessage}</span>}
</div> </div>
<div className="gf-form-button-row text-center"> <ButtonGroup className={styles.buttonGroup}>
<Button variant="primary" onClick={this.submit}> <Button variant="primary" onClick={this.submit}>
Execute Execute
</Button> </Button>
<Button variant="secondary" onClick={this.dismiss}> <Button variant="secondary" onClick={this.dismiss}>
Cancel Cancel
</Button> </Button>
</div> </ButtonGroup>
</Modal> </Modal>
); );
} }
@@ -214,6 +207,11 @@ const getStyles = stylesFactory((theme: GrafanaTheme) => {
execError: css` execError: css`
color: ${red}; color: ${red};
`, `,
buttonGroup: css`
justify-content: center;
gap: ${theme.spacing.sm};
margin-top: ${theme.spacing.md};
`,
}; };
}); });