PanelEditorTabs: Fixes theme and update issues when queries change from outside (#32204)

* PanelEditorTabs: Fixes theme and update issues when queries change from outside

* Remove unnessary arrow function

* Removed setState
This commit is contained in:
Torkel Ödegaard 2021-03-23 13:08:06 +01:00 committed by GitHub
parent 49a5b9f0cb
commit ca8295e298
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 71 additions and 80 deletions

View File

@ -5,6 +5,7 @@ export * from './dataLinks';
export * from './tags';
export * from './scrollbar';
export * from './measureText';
export * from './useForceUpdate';
export { default as ansicolor } from './ansicolor';
import * as DOMUtil from './dom'; // includes Element.closest polyfill

View File

@ -0,0 +1,7 @@
import { useState } from 'react';
/** @internal */
export function useForceUpdate() {
const [value, setValue] = useState(0); // integer state
return () => setValue(value + 1); // update the state to force render
}

View File

@ -3,23 +3,21 @@ import { QueryGroup } from 'app/features/query/components/QueryGroup';
import { PanelModel } from '../../state';
import { getLocationSrv } from '@grafana/runtime';
import { QueryGroupOptions } from 'app/types';
import { DataQuery } from '@grafana/data';
interface Props {
/** Current panel */
panel: PanelModel;
/** Added here to make component re-render when queries change from outside */
queries: DataQuery[];
}
interface State {
options: QueryGroupOptions;
}
export class PanelEditorQueries extends PureComponent<Props, State> {
export class PanelEditorQueries extends PureComponent<Props> {
constructor(props: Props) {
super(props);
this.state = { options: this.buildQueryOptions(props) };
}
buildQueryOptions({ panel }: Props): QueryGroupOptions {
buildQueryOptions(panel: PanelModel): QueryGroupOptions {
return {
dataSource: {
name: panel.datasource,
@ -51,20 +49,17 @@ export class PanelEditorQueries extends PureComponent<Props, State> {
const newDataSourceName = options.dataSource.default ? null : options.dataSource.name!;
const dataSourceChanged = newDataSourceName !== panel.datasource;
panel.updateQueries(options);
if (dataSourceChanged) {
// trigger queries when changing data source
setTimeout(this.onRunQueries, 10);
}
this.setState({ options: options });
};
render() {
const { panel } = this.props;
const { options } = this.state;
const options = this.buildQueryOptions(panel);
return (
<QueryGroup

View File

@ -1,7 +1,6 @@
import React, { PureComponent } from 'react';
import { config } from 'app/core/config';
import React, { FC, useEffect } from 'react';
import { css } from 'emotion';
import { IconName, stylesFactory, Tab, TabContent, TabsBar } from '@grafana/ui';
import { IconName, Tab, TabContent, TabsBar, useForceUpdate, useStyles } from '@grafana/ui';
import { AlertTab } from 'app/features/alerting/AlertTab';
import { TransformationsEditor } from '../TransformationsEditor/TransformationsEditor';
import { DashboardModel, PanelModel } from '../../state';
@ -9,6 +8,7 @@ import { PanelEditorTab, PanelEditorTabId } from './types';
import { Subscription } from 'rxjs';
import { PanelQueriesChangedEvent, PanelTransformationsChangedEvent } from 'app/types/events';
import { PanelEditorQueries } from './PanelEditorQueries';
import { GrafanaTheme } from '@grafana/data';
interface PanelEditorTabsProps {
panel: PanelModel;
@ -17,77 +17,65 @@ interface PanelEditorTabsProps {
onChangeTab: (tab: PanelEditorTab) => void;
}
export class PanelEditorTabs extends PureComponent<PanelEditorTabsProps> {
private eventSubs = new Subscription();
export const PanelEditorTabs: FC<PanelEditorTabsProps> = React.memo(({ panel, dashboard, tabs, onChangeTab }) => {
const forceUpdate = useForceUpdate();
const styles = useStyles(getStyles);
componentDidMount() {
const { events } = this.props.panel;
this.eventSubs.add(events.subscribe(PanelQueriesChangedEvent, this.triggerForceUpdate));
this.eventSubs.add(events.subscribe(PanelTransformationsChangedEvent, this.triggerForceUpdate));
}
useEffect(() => {
const eventSubs = new Subscription();
eventSubs.add(panel.events.subscribe(PanelQueriesChangedEvent, forceUpdate));
eventSubs.add(panel.events.subscribe(PanelTransformationsChangedEvent, forceUpdate));
return () => eventSubs.unsubscribe();
}, [panel, forceUpdate]);
componentWillUnmount() {
this.eventSubs.unsubscribe();
}
triggerForceUpdate = () => {
this.forceUpdate();
};
getCounter = (tab: PanelEditorTab) => {
const { panel } = this.props;
switch (tab.id) {
case PanelEditorTabId.Query:
return panel.targets.length;
case PanelEditorTabId.Alert:
return panel.alert ? 1 : 0;
case PanelEditorTabId.Transform:
const transformations = panel.getTransformations() ?? [];
return transformations.length;
}
const activeTab = tabs.find((item) => item.active)!;
if (tabs.length === 0) {
return null;
};
render() {
const { dashboard, onChangeTab, tabs, panel } = this.props;
const styles = getPanelEditorTabsStyles();
const activeTab = tabs.find((item) => item.active)!;
if (tabs.length === 0) {
return null;
}
return (
<div className={styles.wrapper}>
<TabsBar className={styles.tabBar}>
{tabs.map((tab) => {
return (
<Tab
key={tab.id}
label={tab.text}
active={tab.active}
onChangeTab={() => onChangeTab(tab)}
icon={tab.icon as IconName}
counter={this.getCounter(tab)}
/>
);
})}
</TabsBar>
<TabContent className={styles.tabContent}>
{activeTab.id === PanelEditorTabId.Query && <PanelEditorQueries panel={panel} />}
{activeTab.id === PanelEditorTabId.Alert && <AlertTab panel={panel} dashboard={dashboard} />}
{activeTab.id === PanelEditorTabId.Transform && <TransformationsEditor panel={panel} />}
</TabContent>
</div>
);
}
return (
<div className={styles.wrapper}>
<TabsBar className={styles.tabBar}>
{tabs.map((tab) => {
return (
<Tab
key={tab.id}
label={tab.text}
active={tab.active}
onChangeTab={() => onChangeTab(tab)}
icon={tab.icon as IconName}
counter={getCounter(panel, tab)}
/>
);
})}
</TabsBar>
<TabContent className={styles.tabContent}>
{activeTab.id === PanelEditorTabId.Query && <PanelEditorQueries panel={panel} queries={panel.targets} />}
{activeTab.id === PanelEditorTabId.Alert && <AlertTab panel={panel} dashboard={dashboard} />}
{activeTab.id === PanelEditorTabId.Transform && <TransformationsEditor panel={panel} />}
</TabContent>
</div>
);
});
PanelEditorTabs.displayName = 'PanelEditorTabs';
function getCounter(panel: PanelModel, tab: PanelEditorTab) {
switch (tab.id) {
case PanelEditorTabId.Query:
return panel.targets.length;
case PanelEditorTabId.Alert:
return panel.alert ? 1 : 0;
case PanelEditorTabId.Transform:
const transformations = panel.getTransformations() ?? [];
return transformations.length;
}
return null;
}
const getPanelEditorTabsStyles = stylesFactory(() => {
const { theme } = config;
const getStyles = (theme: GrafanaTheme) => {
return {
wrapper: css`
display: flex;
@ -111,4 +99,4 @@ const getPanelEditorTabsStyles = stylesFactory(() => {
}
`,
};
});
};