mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
Dashboard: remove usage of Legacyforms (#28707)
* refactor(dashboard): remove usage of legacyform components in sharemodal * refactor(dashboard): replace legacyform components * refactor(dashboard): remove ng-if and correct typo in content of sharesnapshot * feat(grafana-ui): set displayName prop for Switch component * refactor(dashboard): migrate TimePickerSettings legacyform components * refactor(queryoptions): migrate switch and input to nextgen components * refactor(sharesnapshot): prefer InlineFieldRow over gf-form-group * refactor(shareembed): styling fixes * refactor(timepickersettings): prefer double bang over nullish coalescing operator * fix(grafana-ui): switch uses id prop if passed in * feat: connect labels and switches with ids
This commit is contained in:
parent
f7a5150d54
commit
6d40206431
@ -70,20 +70,19 @@ export const getSwitchStyles = stylesFactory((theme: GrafanaTheme) => {
|
||||
transition: transform 0.2s cubic-bezier(0.19, 1, 0.22, 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
`,
|
||||
};
|
||||
});
|
||||
|
||||
export const Switch = React.forwardRef<HTMLInputElement, SwitchProps>(
|
||||
({ value, checked, disabled = false, onChange, ...inputProps }, ref) => {
|
||||
({ value, checked, disabled = false, onChange, id, ...inputProps }, ref) => {
|
||||
if (checked) {
|
||||
deprecationWarning('Switch', 'checked prop', 'value');
|
||||
}
|
||||
|
||||
const theme = useTheme();
|
||||
const styles = getSwitchStyles(theme);
|
||||
const switchIdRef = useRef(uniqueId('switch-'));
|
||||
const switchIdRef = useRef(id ? id : uniqueId('switch-'));
|
||||
|
||||
return (
|
||||
<div className={cx(styles.switch)}>
|
||||
@ -103,3 +102,5 @@ export const Switch = React.forwardRef<HTMLInputElement, SwitchProps>(
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
Switch.displayName = 'Switch';
|
||||
|
@ -1,5 +1,5 @@
|
||||
import React, { PureComponent } from 'react';
|
||||
import { Input, LegacyForms, TimeZonePicker, Tooltip } from '@grafana/ui';
|
||||
import { InlineField, Input, Switch, TimeZonePicker, Tooltip } from '@grafana/ui';
|
||||
import { rangeUtil, TimeZone } from '@grafana/data';
|
||||
import isEmpty from 'lodash/isEmpty';
|
||||
import { selectors } from '@grafana/e2e-selectors';
|
||||
@ -87,12 +87,9 @@ export class TimePickerSettings extends PureComponent<Props, State> {
|
||||
</div>
|
||||
|
||||
<div className="gf-form">
|
||||
<LegacyForms.Switch
|
||||
labelClass="width-7"
|
||||
label="Hide time picker"
|
||||
checked={this.props.timePickerHidden ?? false}
|
||||
onChange={this.onHideTimePickerChange}
|
||||
/>
|
||||
<InlineField labelWidth={14} label="Hide time picker">
|
||||
<Switch value={!!this.props.timePickerHidden} onChange={this.onHideTimePickerChange} />
|
||||
</InlineField>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -1,6 +1,5 @@
|
||||
import React, { PureComponent } from 'react';
|
||||
import { LegacyForms, Icon } from '@grafana/ui';
|
||||
const { Select, Switch } = LegacyForms;
|
||||
import { Select, Switch, Icon, InlineField } from '@grafana/ui';
|
||||
import { SelectableValue } from '@grafana/data';
|
||||
import { DashboardModel, PanelModel } from 'app/features/dashboard/state';
|
||||
import { buildIframeHtml } from './utils';
|
||||
@ -82,24 +81,24 @@ export class ShareEmbed extends PureComponent<Props, State> {
|
||||
<Icon name="link" className="share-modal-big-icon" size="xxl" />
|
||||
<div className="share-modal-content">
|
||||
<div className="gf-form-group">
|
||||
<Switch
|
||||
labelClass="width-12"
|
||||
label="Current time range"
|
||||
checked={useCurrentTimeRange}
|
||||
onChange={this.onUseCurrentTimeRangeChange}
|
||||
/>
|
||||
<Switch
|
||||
labelClass="width-12"
|
||||
label="Template variables"
|
||||
checked={includeTemplateVars}
|
||||
onChange={this.onIncludeTemplateVarsChange}
|
||||
/>
|
||||
<div className="gf-form">
|
||||
<label className="gf-form-label width-12">Theme</label>
|
||||
<Select width={10} options={themeOptions} value={selectedTheme} onChange={this.onThemeChange} />
|
||||
</div>
|
||||
<InlineField labelWidth={24} label="Current time range">
|
||||
<Switch
|
||||
id="share-current-time-range"
|
||||
value={useCurrentTimeRange}
|
||||
onChange={this.onUseCurrentTimeRangeChange}
|
||||
/>
|
||||
</InlineField>
|
||||
<InlineField labelWidth={24} label="Template variables">
|
||||
<Switch
|
||||
id="share-template-variables"
|
||||
value={includeTemplateVars}
|
||||
onChange={this.onIncludeTemplateVarsChange}
|
||||
/>
|
||||
</InlineField>
|
||||
<InlineField labelWidth={24} label="Theme">
|
||||
<Select width={20} options={themeOptions} value={selectedTheme} onChange={this.onThemeChange} />
|
||||
</InlineField>
|
||||
</div>
|
||||
|
||||
<p className="share-modal-info-text">
|
||||
The html code below can be pasted and included in another web page. Unless anonymous access is enabled,
|
||||
the user viewing that page need to be signed into grafana for the graph to load.
|
||||
|
@ -1,7 +1,6 @@
|
||||
import React, { PureComponent } from 'react';
|
||||
import { saveAs } from 'file-saver';
|
||||
import { Button, LegacyForms, Icon } from '@grafana/ui';
|
||||
const { Switch } = LegacyForms;
|
||||
import { Button, InlineField, Switch, Icon } from '@grafana/ui';
|
||||
import { DashboardModel, PanelModel } from 'app/features/dashboard/state';
|
||||
import { DashboardExporter } from 'app/features/dashboard/components/DashExportModal';
|
||||
import { appEvents } from 'app/core/core';
|
||||
@ -93,13 +92,9 @@ export class ShareExport extends PureComponent<Props, State> {
|
||||
<div className="share-modal-header">
|
||||
<Icon name="cloud-upload" size="xxl" className="share-modal-big-icon" />
|
||||
<div className="share-modal-content">
|
||||
<Switch
|
||||
labelClass="width-16"
|
||||
label="Export for sharing externally"
|
||||
checked={shareExternally}
|
||||
onChange={this.onShareExternallyChange}
|
||||
/>
|
||||
|
||||
<InlineField labelWidth={32} label="Export for sharing externally">
|
||||
<Switch value={shareExternally} onChange={this.onShareExternallyChange} />
|
||||
</InlineField>
|
||||
<div className="gf-form-button-row">
|
||||
<Button variant="primary" onClick={this.onSaveAsFile}>
|
||||
Save to file
|
||||
|
@ -1,7 +1,6 @@
|
||||
import React, { PureComponent } from 'react';
|
||||
import { selectors as e2eSelectors } from '@grafana/e2e-selectors';
|
||||
import { LegacyForms, ClipboardButton, Icon, InfoBox, Input } from '@grafana/ui';
|
||||
const { Select, Switch } = LegacyForms;
|
||||
import { InlineField, Select, Switch, ClipboardButton, Icon, InfoBox, Input } from '@grafana/ui';
|
||||
import { SelectableValue, PanelModel, AppEvents } from '@grafana/data';
|
||||
import { DashboardModel } from 'app/features/dashboard/state';
|
||||
import { buildImageUrl, buildShareUrl } from './utils';
|
||||
@ -111,23 +110,26 @@ export class ShareLink extends PureComponent<Props, State> {
|
||||
Create a direct link to this dashboard or panel, customized with the options below.
|
||||
</p>
|
||||
<div className="gf-form-group">
|
||||
<Switch
|
||||
labelClass="width-12"
|
||||
label="Current time range"
|
||||
checked={useCurrentTimeRange}
|
||||
onChange={this.onUseCurrentTimeRangeChange}
|
||||
/>
|
||||
<Switch
|
||||
labelClass="width-12"
|
||||
label="Template variables"
|
||||
checked={includeTemplateVars}
|
||||
onChange={this.onIncludeTemplateVarsChange}
|
||||
/>
|
||||
<div className="gf-form">
|
||||
<label className="gf-form-label width-12">Theme</label>
|
||||
<Select width={10} options={themeOptions} value={selectedTheme} onChange={this.onThemeChange} />
|
||||
</div>
|
||||
<Switch labelClass="width-12" label="Shorten URL" checked={useShortUrl} onChange={this.onUrlShorten} />
|
||||
<InlineField labelWidth={24} label="Current time range">
|
||||
<Switch
|
||||
id="share-current-time-range"
|
||||
value={useCurrentTimeRange}
|
||||
onChange={this.onUseCurrentTimeRangeChange}
|
||||
/>
|
||||
</InlineField>
|
||||
<InlineField labelWidth={24} label="Template variables">
|
||||
<Switch
|
||||
id="share-template-vars"
|
||||
value={includeTemplateVars}
|
||||
onChange={this.onIncludeTemplateVarsChange}
|
||||
/>
|
||||
</InlineField>
|
||||
<InlineField labelWidth={24} label="Theme">
|
||||
<Select width={20} options={themeOptions} value={selectedTheme} onChange={this.onThemeChange} />
|
||||
</InlineField>
|
||||
<InlineField labelWidth={24} label="Shorten URL">
|
||||
<Switch id="share-shorten-url" value={useShortUrl} onChange={this.onUrlShorten} />
|
||||
</InlineField>
|
||||
</div>
|
||||
<div>
|
||||
<div className="gf-form-group">
|
||||
|
@ -1,5 +1,15 @@
|
||||
import React, { PureComponent } from 'react';
|
||||
import { Button, ClipboardButton, Icon, Spinner, LegacyForms, LinkButton } from '@grafana/ui';
|
||||
import {
|
||||
Button,
|
||||
ClipboardButton,
|
||||
Icon,
|
||||
Spinner,
|
||||
Select,
|
||||
Input,
|
||||
LinkButton,
|
||||
InlineField,
|
||||
InlineFieldRow,
|
||||
} from '@grafana/ui';
|
||||
import { AppEvents, SelectableValue } from '@grafana/data';
|
||||
import { getBackendSrv } from '@grafana/runtime';
|
||||
import { DashboardModel, PanelModel } from 'app/features/dashboard/state';
|
||||
@ -7,8 +17,6 @@ import { getTimeSrv } from 'app/features/dashboard/services/TimeSrv';
|
||||
import { appEvents } from 'app/core/core';
|
||||
import { VariableRefresh } from '../../../variables/types';
|
||||
|
||||
const { Select, Input } = LegacyForms;
|
||||
|
||||
const snapshotApiUrl = '/api/snapshots';
|
||||
|
||||
const expireOptions: Array<SelectableValue<number>> = [
|
||||
@ -221,27 +229,24 @@ export class ShareSnapshot extends PureComponent<Props, State> {
|
||||
URL. Share wisely.
|
||||
</p>
|
||||
</div>
|
||||
<div className="gf-form-group share-modal-options">
|
||||
<div className="gf-form" ng-if="step === 1">
|
||||
<label className="gf-form-label width-12">Snapshot name</label>
|
||||
<Input width={15} value={snapshotName} onChange={this.onSnapshotNameChange} />
|
||||
</div>
|
||||
<div className="gf-form" ng-if="step === 1">
|
||||
<label className="gf-form-label width-12">Expire</label>
|
||||
<Select width={15} options={expireOptions} value={selectedExpireOption} onChange={this.onExpireChange} />
|
||||
</div>
|
||||
</div>
|
||||
<InlineFieldRow className="share-modal-options">
|
||||
<InlineField labelWidth={24} label="Snapshot name">
|
||||
<Input width={30} value={snapshotName} onChange={this.onSnapshotNameChange} />
|
||||
</InlineField>
|
||||
<InlineField labelWidth={24} label="Expire">
|
||||
<Select width={30} options={expireOptions} value={selectedExpireOption} onChange={this.onExpireChange} />
|
||||
</InlineField>
|
||||
</InlineFieldRow>
|
||||
|
||||
<p className="share-modal-info-text">
|
||||
You may need to configure the timeout value if it takes a long time to collect your dashboard's metrics.
|
||||
</p>
|
||||
|
||||
<div className="gf-form-group share-modal-options">
|
||||
<div className="gf-form">
|
||||
<span className="gf-form-label width-12">Timeout (seconds)</span>
|
||||
<Input type="number" width={15} value={timeoutSeconds} onChange={this.onTimeoutChange} />
|
||||
</div>
|
||||
</div>
|
||||
<InlineFieldRow className="share-modal-options">
|
||||
<InlineField labelWidth={24} label="Timeout (seconds)">
|
||||
<Input type="number" width={21} value={timeoutSeconds} onChange={this.onTimeoutChange} />
|
||||
</InlineField>
|
||||
</InlineFieldRow>
|
||||
|
||||
<div className="gf-form-button-row">
|
||||
<Button className="width-10" variant="primary" disabled={isLoading} onClick={this.createSnapshot()}>
|
||||
@ -277,7 +282,7 @@ export class ShareSnapshot extends PureComponent<Props, State> {
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="pull-right" ng-if="step === 2" style={{ padding: '5px' }}>
|
||||
<div className="pull-right" style={{ padding: '5px' }}>
|
||||
Did you make a mistake?{' '}
|
||||
<LinkButton variant="link" target="_blank" onClick={this.deleteSnapshot}>
|
||||
delete snapshot.
|
||||
@ -291,8 +296,8 @@ export class ShareSnapshot extends PureComponent<Props, State> {
|
||||
return (
|
||||
<div className="share-modal-header">
|
||||
<p className="share-modal-info-text">
|
||||
The snapshot has now been deleted. If it you have already accessed it once, It might take up to an hour before
|
||||
it is removed from browser caches or CDN caches.
|
||||
The snapshot has now been deleted. If you have already accessed it once, it might take up to an hour before it
|
||||
is removed from browser caches or CDN caches.
|
||||
</p>
|
||||
</div>
|
||||
);
|
||||
|
@ -5,15 +5,7 @@ import React, { PureComponent, ChangeEvent, FocusEvent } from 'react';
|
||||
import { rangeUtil, PanelData, DataSourceApi } from '@grafana/data';
|
||||
|
||||
// Components
|
||||
import {
|
||||
EventsWithValidation,
|
||||
LegacyInputStatus,
|
||||
LegacyForms,
|
||||
ValidationEvents,
|
||||
InlineFormLabel,
|
||||
stylesFactory,
|
||||
} from '@grafana/ui';
|
||||
const { Switch, Input } = LegacyForms;
|
||||
import { Switch, Input, InlineField, InlineFormLabel, stylesFactory } from '@grafana/ui';
|
||||
|
||||
// Types
|
||||
import { PanelModel } from '../state';
|
||||
@ -21,18 +13,11 @@ import { QueryOperationRow } from 'app/core/components/QueryOperationRow/QueryOp
|
||||
import { config } from 'app/core/config';
|
||||
import { css } from 'emotion';
|
||||
|
||||
const timeRangeValidationEvents: ValidationEvents = {
|
||||
[EventsWithValidation.onBlur]: [
|
||||
{
|
||||
rule: value => {
|
||||
if (!value) {
|
||||
return true;
|
||||
}
|
||||
return rangeUtil.isValidTimeSpan(value);
|
||||
},
|
||||
errorMessage: 'Not a valid timespan',
|
||||
},
|
||||
],
|
||||
const timeRangeValidation = (value: string) => {
|
||||
if (!value) {
|
||||
return true;
|
||||
}
|
||||
return rangeUtil.isValidTimeSpan(value);
|
||||
};
|
||||
|
||||
const emptyToNull = (value: string) => {
|
||||
@ -53,6 +38,8 @@ interface State {
|
||||
interval: string;
|
||||
hideTimeOverride: boolean;
|
||||
isOpen: boolean;
|
||||
relativeTimeIsValid: boolean;
|
||||
timeShiftIsValid: boolean;
|
||||
}
|
||||
|
||||
export class QueryOptions extends PureComponent<Props, State> {
|
||||
@ -67,6 +54,8 @@ export class QueryOptions extends PureComponent<Props, State> {
|
||||
interval: props.panel.interval || '',
|
||||
hideTimeOverride: props.panel.hideTimeOverride || false,
|
||||
isOpen: false,
|
||||
relativeTimeIsValid: true,
|
||||
timeShiftIsValid: true,
|
||||
};
|
||||
}
|
||||
|
||||
@ -82,26 +71,30 @@ export class QueryOptions extends PureComponent<Props, State> {
|
||||
});
|
||||
};
|
||||
|
||||
onOverrideTime = (event: FocusEvent<HTMLInputElement>, status: LegacyInputStatus) => {
|
||||
onOverrideTime = (event: FocusEvent<HTMLInputElement>) => {
|
||||
const { value } = event.target;
|
||||
const { panel } = this.props;
|
||||
const emptyToNullValue = emptyToNull(value);
|
||||
const isValid = timeRangeValidation(value);
|
||||
|
||||
if (status === LegacyInputStatus.Valid && panel.timeFrom !== emptyToNullValue) {
|
||||
if (isValid && panel.timeFrom !== emptyToNullValue) {
|
||||
panel.timeFrom = emptyToNullValue;
|
||||
panel.refresh();
|
||||
}
|
||||
this.setState({ relativeTimeIsValid: isValid });
|
||||
};
|
||||
|
||||
onTimeShift = (event: FocusEvent<HTMLInputElement>, status: LegacyInputStatus) => {
|
||||
onTimeShift = (event: FocusEvent<HTMLInputElement>) => {
|
||||
const { value } = event.target;
|
||||
const { panel } = this.props;
|
||||
const emptyToNullValue = emptyToNull(value);
|
||||
const isValid = timeRangeValidation(value);
|
||||
|
||||
if (status === LegacyInputStatus.Valid && panel.timeShift !== emptyToNullValue) {
|
||||
if (isValid && panel.timeShift !== emptyToNullValue) {
|
||||
panel.timeShift = emptyToNullValue;
|
||||
panel.refresh();
|
||||
}
|
||||
this.setState({ timeShiftIsValid: isValid });
|
||||
};
|
||||
|
||||
onToggleTimeOverride = () => {
|
||||
@ -301,7 +294,7 @@ export class QueryOptions extends PureComponent<Props, State> {
|
||||
}
|
||||
|
||||
render() {
|
||||
const { hideTimeOverride } = this.state;
|
||||
const { hideTimeOverride, relativeTimeIsValid, timeShiftIsValid } = this.state;
|
||||
const { relativeTime, timeShift, isOpen } = this.state;
|
||||
const styles = getStyles();
|
||||
|
||||
@ -327,8 +320,7 @@ export class QueryOptions extends PureComponent<Props, State> {
|
||||
placeholder="1h"
|
||||
onChange={this.onRelativeTimeChange}
|
||||
onBlur={this.onOverrideTime}
|
||||
validationEvents={timeRangeValidationEvents}
|
||||
hideErrorMessage={true}
|
||||
invalid={!relativeTimeIsValid}
|
||||
value={relativeTime}
|
||||
/>
|
||||
</div>
|
||||
@ -341,19 +333,15 @@ export class QueryOptions extends PureComponent<Props, State> {
|
||||
placeholder="1h"
|
||||
onChange={this.onTimeShiftChange}
|
||||
onBlur={this.onTimeShift}
|
||||
validationEvents={timeRangeValidationEvents}
|
||||
hideErrorMessage={true}
|
||||
invalid={!timeShiftIsValid}
|
||||
value={timeShift}
|
||||
/>
|
||||
</div>
|
||||
{(timeShift || relativeTime) && (
|
||||
<div className="gf-form-inline">
|
||||
<Switch
|
||||
label="Hide time info"
|
||||
labelClass="width-9"
|
||||
checked={hideTimeOverride}
|
||||
onChange={this.onToggleTimeOverride}
|
||||
/>
|
||||
<InlineField label="Hide time info" labelWidth={18}>
|
||||
<Switch value={hideTimeOverride} onChange={this.onToggleTimeOverride} />
|
||||
</InlineField>
|
||||
</div>
|
||||
)}
|
||||
</QueryOperationRow>
|
||||
|
Loading…
Reference in New Issue
Block a user