mirror of
https://github.com/grafana/grafana.git
synced 2025-02-16 18:34:52 -06:00
* Apply field overrides in PanelChrome * Move applyFieldOverrides to panel query runner * Review updates * Make sure overrides are applied back on souce panel when exiting the new edit mode * TS ignores in est * Make field display work in viz repeater * Review updates * Review and test updates * Change the way overrides and trransformations are retrieved in PQR * Add fieldConfig property to PanelModel * Dashboard migration v1 * Use field config when exiting new panel edit mode * Gauge - use fieldConfig from panel model * FieldDisplayOptions - don's extend FieldConfigSource * Fix fieldDisplay ts * StatPanel updated * Stat panel defaults applied * Table2 panel options update * React graph updates * BarGauge updated * PieChart, Gauge, BarGauge and Stat updates * PieChart - remove field config defaults from options * FieldDisplayEditor - remove unused methos * PanelModel - remove debugger * Remove fieldConfig from field options when migrating dashboard * Update data links migrations * Update fieldDisaplay tests to respect new fieldConfig * Update dashboard schema version in snapshots * Fix BarGaugePanel test * Rebase fixes * Add onFieldConfigChange to PanelProps type * Update shared single stat migration * Pass PanelModel instead of options only for panel type change handler [breaking] * Renames * Don't mutate panel options * Migrations update * Remove obsolete snap * Minor updates after review * Fix null checks * Temporarily (until we decide to switch to new pane edit) bring back old aditors * Temporarily rename ValueMappingEditor and MappingRow to Legacy* * Migrations update * Updae setFieldConfigDefaults API * Update the way field config defaults are applied * Use standard field config for gauge, bar gauge and stat panels * refactoring * Revert dashboard fieldOptions migrations as those are handled by single stat migrator * Fix ts in tests * Strict null fix and some minor fixes Co-authored-by: Torkel Ödegaard <torkel@grafana.com>
233 lines
6.2 KiB
TypeScript
233 lines
6.2 KiB
TypeScript
// Libraries
|
|
import React, { PureComponent } from 'react';
|
|
// Utils & Services
|
|
import { connect } from 'react-redux';
|
|
import { StoreState } from 'app/types';
|
|
import { updateLocation } from 'app/core/actions';
|
|
// Components
|
|
import { EditorTabBody, EditorToolbarView } from './EditorTabBody';
|
|
import { VizTypePicker } from './VizTypePicker';
|
|
import { PluginHelp } from 'app/core/components/PluginHelp/PluginHelp';
|
|
import { FadeIn } from 'app/core/components/Animations/FadeIn';
|
|
import { AngularPanelOptions } from './AngularPanelOptions';
|
|
// Types
|
|
import { PanelModel, DashboardModel } from '../state';
|
|
import { VizPickerSearch } from './VizPickerSearch';
|
|
import PluginStateinfo from 'app/features/plugins/PluginStateInfo';
|
|
import { Unsubscribable } from 'rxjs';
|
|
import {
|
|
PanelPlugin,
|
|
PanelPluginMeta,
|
|
PanelData,
|
|
LoadingState,
|
|
DefaultTimeRange,
|
|
FieldConfigSource,
|
|
} from '@grafana/data';
|
|
|
|
interface Props {
|
|
panel: PanelModel;
|
|
dashboard: DashboardModel;
|
|
plugin: PanelPlugin;
|
|
onPluginTypeChange: (newType: PanelPluginMeta) => void;
|
|
updateLocation: typeof updateLocation;
|
|
urlOpenVizPicker: boolean;
|
|
}
|
|
|
|
interface State {
|
|
isVizPickerOpen: boolean;
|
|
searchQuery: string;
|
|
scrollTop: number;
|
|
hasBeenFocused: boolean;
|
|
data: PanelData;
|
|
}
|
|
|
|
export class VisualizationTab extends PureComponent<Props, State> {
|
|
element: HTMLElement;
|
|
querySubscription: Unsubscribable;
|
|
|
|
constructor(props: Props) {
|
|
super(props);
|
|
|
|
this.state = {
|
|
isVizPickerOpen: this.props.urlOpenVizPicker,
|
|
hasBeenFocused: false,
|
|
searchQuery: '',
|
|
scrollTop: 0,
|
|
data: {
|
|
state: LoadingState.NotStarted,
|
|
series: [],
|
|
timeRange: DefaultTimeRange,
|
|
},
|
|
};
|
|
}
|
|
|
|
getReactPanelOptions = () => {
|
|
const { panel } = this.props;
|
|
return panel.getOptions();
|
|
};
|
|
|
|
getReactPanelFieldConfig = () => {
|
|
const { panel } = this.props;
|
|
return panel.getFieldConfig();
|
|
};
|
|
|
|
renderPanelOptions() {
|
|
const { plugin, dashboard, panel } = this.props;
|
|
|
|
if (plugin.angularPanelCtrl) {
|
|
return <AngularPanelOptions plugin={plugin} dashboard={dashboard} panel={panel} />;
|
|
}
|
|
|
|
if (plugin.editor) {
|
|
return (
|
|
<plugin.editor
|
|
data={this.state.data}
|
|
options={this.getReactPanelOptions()}
|
|
onOptionsChange={this.onPanelOptionsChanged}
|
|
// TODO[FieldConfig]: Remove when we switch old editor to new
|
|
fieldConfig={this.getReactPanelFieldConfig()}
|
|
// TODO[FieldConfig]: Remove when we switch old editor to new
|
|
onFieldConfigChange={this.onPanelFieldConfigChange}
|
|
/>
|
|
);
|
|
}
|
|
|
|
return <p>Visualization has no options</p>;
|
|
}
|
|
|
|
componentDidMount() {
|
|
const { panel } = this.props;
|
|
const queryRunner = panel.getQueryRunner();
|
|
|
|
this.querySubscription = queryRunner.getData().subscribe({
|
|
next: (data: PanelData) => this.setState({ data }),
|
|
});
|
|
}
|
|
|
|
componentWillUnmount() {
|
|
if (this.querySubscription) {
|
|
this.querySubscription.unsubscribe();
|
|
}
|
|
}
|
|
|
|
clearQuery = () => {
|
|
this.setState({ searchQuery: '' });
|
|
};
|
|
|
|
onPanelOptionsChanged = (options: any, callback?: () => void) => {
|
|
this.props.panel.updateOptions(options);
|
|
this.forceUpdate(callback);
|
|
};
|
|
|
|
// TODO[FieldConfig]: Remove when we switch old editor to new
|
|
onPanelFieldConfigChange = (config: FieldConfigSource, callback?: () => void) => {
|
|
this.props.panel.updateFieldConfig(config);
|
|
this.forceUpdate(callback);
|
|
};
|
|
|
|
onOpenVizPicker = () => {
|
|
this.setState({ isVizPickerOpen: true, scrollTop: 0 });
|
|
};
|
|
|
|
onCloseVizPicker = () => {
|
|
if (this.props.urlOpenVizPicker) {
|
|
this.props.updateLocation({ query: { openVizPicker: null }, partial: true });
|
|
}
|
|
|
|
this.setState({ isVizPickerOpen: false, hasBeenFocused: false });
|
|
};
|
|
|
|
onSearchQueryChange = (value: string) => {
|
|
this.setState({
|
|
searchQuery: value,
|
|
});
|
|
};
|
|
|
|
renderToolbar = (): JSX.Element => {
|
|
const { plugin } = this.props;
|
|
const { isVizPickerOpen, searchQuery } = this.state;
|
|
const { meta } = plugin;
|
|
|
|
if (isVizPickerOpen) {
|
|
return (
|
|
<VizPickerSearch
|
|
plugin={meta}
|
|
searchQuery={searchQuery}
|
|
onChange={this.onSearchQueryChange}
|
|
onClose={this.onCloseVizPicker}
|
|
/>
|
|
);
|
|
} else {
|
|
return (
|
|
<>
|
|
<div className="toolbar__main" onClick={this.onOpenVizPicker}>
|
|
<img className="toolbar__main-image" src={meta.info.logos.small} />
|
|
<div className="toolbar__main-name">{meta.name}</div>
|
|
<i className="fa fa-caret-down" />
|
|
</div>
|
|
<PluginStateinfo state={meta.state} />
|
|
</>
|
|
);
|
|
}
|
|
};
|
|
|
|
onPluginTypeChange = (plugin: PanelPluginMeta) => {
|
|
if (plugin.id === this.props.plugin.meta.id) {
|
|
this.setState({ isVizPickerOpen: false });
|
|
} else {
|
|
this.props.onPluginTypeChange(plugin);
|
|
}
|
|
};
|
|
|
|
renderHelp = () => <PluginHelp plugin={this.props.plugin.meta} type="help" />;
|
|
|
|
setScrollTop = (event: React.MouseEvent<HTMLElement>) => {
|
|
const target = event.target as HTMLElement;
|
|
this.setState({ scrollTop: target.scrollTop });
|
|
};
|
|
|
|
render() {
|
|
const { plugin } = this.props;
|
|
const { isVizPickerOpen, searchQuery, scrollTop } = this.state;
|
|
const { meta } = plugin;
|
|
|
|
const pluginHelp: EditorToolbarView = {
|
|
heading: 'Help',
|
|
icon: 'fa fa-question',
|
|
render: this.renderHelp,
|
|
};
|
|
|
|
return (
|
|
<EditorTabBody
|
|
heading="Visualization"
|
|
renderToolbar={this.renderToolbar}
|
|
toolbarItems={[pluginHelp]}
|
|
scrollTop={scrollTop}
|
|
setScrollTop={this.setScrollTop}
|
|
>
|
|
<>
|
|
<FadeIn in={isVizPickerOpen} duration={200} unmountOnExit={true} onExited={this.clearQuery}>
|
|
<VizTypePicker
|
|
current={meta}
|
|
onTypeChange={this.onPluginTypeChange}
|
|
searchQuery={searchQuery}
|
|
onClose={this.onCloseVizPicker}
|
|
/>
|
|
</FadeIn>
|
|
{this.renderPanelOptions()}
|
|
</>
|
|
</EditorTabBody>
|
|
);
|
|
}
|
|
}
|
|
|
|
const mapStateToProps = (state: StoreState) => ({
|
|
urlOpenVizPicker: !!state.location.query.openVizPicker,
|
|
});
|
|
|
|
const mapDispatchToProps = {
|
|
updateLocation,
|
|
};
|
|
|
|
export default connect(mapStateToProps, mapDispatchToProps)(VisualizationTab);
|