2020-11-25 04:24:06 -06:00
|
|
|
import React, { PureComponent } from 'react';
|
2020-12-15 05:18:40 -06:00
|
|
|
import { connect, ConnectedProps } from 'react-redux';
|
2020-10-27 05:18:37 -05:00
|
|
|
import AutoSizer from 'react-virtualized-auto-sizer';
|
|
|
|
import { css, cx } from 'emotion';
|
2020-11-26 08:14:57 -06:00
|
|
|
import { Subscription } from 'rxjs';
|
2020-10-27 05:18:37 -05:00
|
|
|
|
2020-12-15 05:18:40 -06:00
|
|
|
import { FieldConfigSource, GrafanaTheme } from '@grafana/data';
|
2020-10-27 05:18:37 -05:00
|
|
|
import { selectors } from '@grafana/e2e-selectors';
|
2021-02-25 04:26:28 -06:00
|
|
|
import {
|
|
|
|
HorizontalGroup,
|
|
|
|
ModalsController,
|
|
|
|
PageToolbar,
|
|
|
|
RadioButtonGroup,
|
|
|
|
stylesFactory,
|
|
|
|
ToolbarButton,
|
|
|
|
} from '@grafana/ui';
|
2019-12-16 02:18:48 -06:00
|
|
|
|
2020-10-27 05:18:37 -05:00
|
|
|
import config from 'app/core/config';
|
|
|
|
import { appEvents } from 'app/core/core';
|
|
|
|
import { calculatePanelSize } from './utils';
|
2020-02-09 08:39:46 -06:00
|
|
|
|
|
|
|
import { PanelEditorTabs } from './PanelEditorTabs';
|
2020-02-09 11:48:14 -06:00
|
|
|
import { DashNavTimeControls } from '../DashNav/DashNavTimeControls';
|
2020-03-20 09:15:04 -05:00
|
|
|
import { OptionsPaneContent } from './OptionsPaneContent';
|
2020-04-02 06:56:20 -05:00
|
|
|
import { SubMenuItems } from 'app/features/dashboard/components/SubMenu/SubMenuItems';
|
2020-11-26 06:27:50 -06:00
|
|
|
import { SplitPaneWrapper } from 'app/core/components/SplitPaneWrapper/SplitPaneWrapper';
|
2020-04-18 11:00:54 -05:00
|
|
|
import { SaveDashboardModalProxy } from '../SaveDashboard/SaveDashboardModalProxy';
|
2020-10-27 05:18:37 -05:00
|
|
|
import { DashboardPanel } from '../../dashgrid/DashboardPanel';
|
|
|
|
|
2021-02-25 04:26:28 -06:00
|
|
|
import {
|
|
|
|
exitPanelEditor,
|
|
|
|
initPanelEditor,
|
|
|
|
panelEditorCleanUp,
|
|
|
|
updatePanelEditorUIState,
|
2021-03-02 09:37:36 -06:00
|
|
|
updateSourcePanel,
|
2021-02-25 04:26:28 -06:00
|
|
|
} from './state/actions';
|
2020-10-27 05:18:37 -05:00
|
|
|
|
|
|
|
import { updateTimeZoneForSession } from 'app/features/profile/state/reducers';
|
|
|
|
import { updateLocation } from 'app/core/reducers/location';
|
2020-12-15 05:18:40 -06:00
|
|
|
import { setDiscardChanges } from './state/reducers';
|
2020-10-27 05:18:37 -05:00
|
|
|
|
|
|
|
import { getPanelEditorTabs } from './state/selectors';
|
|
|
|
import { getPanelStateById } from '../../state/selectors';
|
|
|
|
import { getVariables } from 'app/features/variables/state/selectors';
|
|
|
|
|
2020-12-15 05:18:40 -06:00
|
|
|
import { CoreEvents, StoreState } from 'app/types';
|
2020-10-27 05:18:37 -05:00
|
|
|
import { DisplayMode, displayModes, PanelEditorTab } from './types';
|
|
|
|
import { DashboardModel, PanelModel } from '../../state';
|
2020-11-26 08:14:57 -06:00
|
|
|
import { PanelOptionsChangedEvent } from 'app/types/events';
|
2021-02-25 04:26:28 -06:00
|
|
|
import { UnlinkModal } from '../../../library-panels/components/UnlinkModal/UnlinkModal';
|
|
|
|
import { SaveLibraryPanelModal } from 'app/features/library-panels/components/SaveLibraryPanelModal/SaveLibraryPanelModal';
|
2021-03-02 09:37:36 -06:00
|
|
|
import { isPanelModelLibraryPanel } from '../../../library-panels/guard';
|
|
|
|
import { getLibraryPanelConnectedDashboards } from '../../../library-panels/state/api';
|
|
|
|
import {
|
|
|
|
createPanelLibraryErrorNotification,
|
|
|
|
createPanelLibrarySuccessNotification,
|
|
|
|
saveAndRefreshLibraryPanel,
|
|
|
|
} from '../../../library-panels/utils';
|
|
|
|
import { notifyApp } from '../../../../core/actions';
|
2019-12-16 02:18:48 -06:00
|
|
|
|
2020-02-11 07:57:16 -06:00
|
|
|
interface OwnProps {
|
2019-12-16 02:18:48 -06:00
|
|
|
dashboard: DashboardModel;
|
2020-02-08 11:29:09 -06:00
|
|
|
sourcePanel: PanelModel;
|
2019-12-16 02:18:48 -06:00
|
|
|
}
|
|
|
|
|
2020-12-15 05:18:40 -06:00
|
|
|
const mapStateToProps = (state: StoreState) => {
|
|
|
|
const panel = state.panelEditor.getPanel();
|
|
|
|
const { plugin } = getPanelStateById(state.dashboard, panel.id);
|
2019-12-16 02:18:48 -06:00
|
|
|
|
2020-12-15 05:18:40 -06:00
|
|
|
return {
|
|
|
|
location: state.location,
|
|
|
|
plugin: plugin,
|
|
|
|
panel,
|
|
|
|
initDone: state.panelEditor.initDone,
|
|
|
|
tabs: getPanelEditorTabs(state.location, plugin),
|
|
|
|
uiState: state.panelEditor.ui,
|
|
|
|
variables: getVariables(state),
|
|
|
|
};
|
|
|
|
};
|
|
|
|
|
|
|
|
const mapDispatchToProps = {
|
|
|
|
updateLocation,
|
|
|
|
initPanelEditor,
|
2021-02-25 04:26:28 -06:00
|
|
|
exitPanelEditor,
|
|
|
|
updateSourcePanel,
|
2020-12-15 05:18:40 -06:00
|
|
|
panelEditorCleanUp,
|
|
|
|
setDiscardChanges,
|
|
|
|
updatePanelEditorUIState,
|
|
|
|
updateTimeZoneForSession,
|
2021-03-02 09:37:36 -06:00
|
|
|
notifyApp,
|
2020-12-15 05:18:40 -06:00
|
|
|
};
|
|
|
|
|
|
|
|
const connector = connect(mapStateToProps, mapDispatchToProps);
|
2020-02-08 11:29:09 -06:00
|
|
|
|
2020-12-15 05:18:40 -06:00
|
|
|
type Props = OwnProps & ConnectedProps<typeof connector>;
|
2020-02-09 11:48:14 -06:00
|
|
|
|
2020-02-11 07:57:16 -06:00
|
|
|
export class PanelEditorUnconnected extends PureComponent<Props> {
|
2020-11-26 08:14:57 -06:00
|
|
|
private eventSubs?: Subscription;
|
2020-02-09 11:48:14 -06:00
|
|
|
|
2020-02-11 07:57:16 -06:00
|
|
|
componentDidMount() {
|
|
|
|
this.props.initPanelEditor(this.props.sourcePanel, this.props.dashboard);
|
2020-02-08 06:23:16 -06:00
|
|
|
}
|
2020-11-26 08:14:57 -06:00
|
|
|
|
|
|
|
componentDidUpdate() {
|
|
|
|
const { panel, initDone } = this.props;
|
|
|
|
|
|
|
|
if (initDone && !this.eventSubs) {
|
|
|
|
this.eventSubs = new Subscription();
|
|
|
|
this.eventSubs.add(panel.events.subscribe(PanelOptionsChangedEvent, this.triggerForceUpdate));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-02-08 06:23:16 -06:00
|
|
|
componentWillUnmount() {
|
2020-02-11 07:57:16 -06:00
|
|
|
this.props.panelEditorCleanUp();
|
2020-11-26 08:14:57 -06:00
|
|
|
this.eventSubs?.unsubscribe();
|
2020-02-07 07:59:04 -06:00
|
|
|
}
|
2019-12-16 02:18:48 -06:00
|
|
|
|
2020-11-26 08:14:57 -06:00
|
|
|
triggerForceUpdate = () => {
|
|
|
|
this.forceUpdate();
|
|
|
|
};
|
|
|
|
|
2020-02-07 07:59:04 -06:00
|
|
|
onDiscard = () => {
|
2020-02-11 07:57:16 -06:00
|
|
|
this.props.setDiscardChanges(true);
|
2020-02-07 07:59:04 -06:00
|
|
|
this.props.updateLocation({
|
2020-04-04 08:44:55 -05:00
|
|
|
query: { editPanel: null, tab: null },
|
2020-02-07 07:59:04 -06:00
|
|
|
partial: true,
|
|
|
|
});
|
|
|
|
};
|
2019-12-16 02:18:48 -06:00
|
|
|
|
2020-04-18 11:00:54 -05:00
|
|
|
onOpenDashboardSettings = () => {
|
|
|
|
this.props.updateLocation({ query: { editview: 'settings' }, partial: true });
|
|
|
|
};
|
|
|
|
|
|
|
|
onSaveDashboard = () => {
|
|
|
|
appEvents.emit(CoreEvents.showModalReact, {
|
|
|
|
component: SaveDashboardModalProxy,
|
|
|
|
props: { dashboard: this.props.dashboard },
|
|
|
|
});
|
|
|
|
};
|
|
|
|
|
2021-03-02 09:37:36 -06:00
|
|
|
onSaveLibraryPanel = async () => {
|
|
|
|
if (!isPanelModelLibraryPanel(this.props.panel)) {
|
2021-02-25 04:26:28 -06:00
|
|
|
// New library panel, no need to display modal
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2021-03-02 09:37:36 -06:00
|
|
|
if (this.props.panel.libraryPanel.meta.connectedDashboards === 0) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
const connectedDashboards = await getLibraryPanelConnectedDashboards(this.props.panel.libraryPanel.uid);
|
|
|
|
if (connectedDashboards.length === 1 && connectedDashboards.indexOf(this.props.dashboard.id) !== -1) {
|
|
|
|
try {
|
|
|
|
await saveAndRefreshLibraryPanel(this.props.panel, this.props.dashboard.meta.folderId!);
|
|
|
|
this.props.updateSourcePanel(this.props.panel);
|
|
|
|
this.props.notifyApp(createPanelLibrarySuccessNotification('Library panel saved'));
|
|
|
|
} catch (err) {
|
|
|
|
this.props.notifyApp(createPanelLibraryErrorNotification(`Error saving library panel: "${err.statusText}"`));
|
|
|
|
}
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2021-02-25 04:26:28 -06:00
|
|
|
appEvents.emit(CoreEvents.showModalReact, {
|
|
|
|
component: SaveLibraryPanelModal,
|
|
|
|
props: {
|
|
|
|
panel: this.props.panel,
|
|
|
|
folderId: this.props.dashboard.meta.folderId,
|
|
|
|
isOpen: true,
|
|
|
|
onConfirm: () => {
|
|
|
|
// need to update the source panel here so that when
|
|
|
|
// the user exits the panel editor they aren't prompted to save again
|
|
|
|
this.props.updateSourcePanel(this.props.panel);
|
|
|
|
},
|
|
|
|
},
|
|
|
|
});
|
|
|
|
};
|
|
|
|
|
2020-02-12 03:42:57 -06:00
|
|
|
onChangeTab = (tab: PanelEditorTab) => {
|
|
|
|
this.props.updateLocation({ query: { tab: tab.id }, partial: true });
|
|
|
|
};
|
|
|
|
|
2020-03-19 05:50:31 -05:00
|
|
|
onFieldConfigChange = (config: FieldConfigSource) => {
|
2020-12-17 06:30:55 -06:00
|
|
|
// we do not need to trigger force update here as the function call below
|
|
|
|
// fires PanelOptionsChangedEvent which we subscribe to above
|
|
|
|
this.props.panel.updateFieldConfig({
|
2020-03-19 05:50:31 -05:00
|
|
|
...config,
|
2020-02-08 11:29:09 -06:00
|
|
|
});
|
|
|
|
};
|
|
|
|
|
|
|
|
onPanelOptionsChanged = (options: any) => {
|
2020-11-26 08:14:57 -06:00
|
|
|
// we do not need to trigger force update here as the function call below
|
|
|
|
// fires PanelOptionsChangedEvent which we subscribe to above
|
2020-02-11 07:57:16 -06:00
|
|
|
this.props.panel.updateOptions(options);
|
2020-02-08 11:29:09 -06:00
|
|
|
};
|
|
|
|
|
2021-02-25 04:26:28 -06:00
|
|
|
onPanelConfigChanged = (configKey: keyof PanelModel, value: any) => {
|
2020-03-20 09:15:04 -05:00
|
|
|
// @ts-ignore
|
|
|
|
this.props.panel[configKey] = value;
|
|
|
|
this.props.panel.render();
|
|
|
|
this.forceUpdate();
|
|
|
|
};
|
2020-02-08 11:29:09 -06:00
|
|
|
|
2021-02-25 04:26:28 -06:00
|
|
|
onDisplayModeChange = (mode?: DisplayMode) => {
|
2020-02-15 13:31:11 -06:00
|
|
|
const { updatePanelEditorUIState } = this.props;
|
|
|
|
updatePanelEditorUIState({
|
2020-04-04 07:25:06 -05:00
|
|
|
mode: mode,
|
2020-02-15 13:31:11 -06:00
|
|
|
});
|
2020-02-09 08:39:46 -06:00
|
|
|
};
|
|
|
|
|
|
|
|
onTogglePanelOptions = () => {
|
2020-02-15 13:31:11 -06:00
|
|
|
const { uiState, updatePanelEditorUIState } = this.props;
|
|
|
|
updatePanelEditorUIState({ isPanelOptionsVisible: !uiState.isPanelOptionsVisible });
|
2020-02-09 08:39:46 -06:00
|
|
|
};
|
|
|
|
|
2020-04-23 13:36:42 -05:00
|
|
|
renderPanel = (styles: EditorStyles) => {
|
|
|
|
const { dashboard, panel, tabs, uiState } = this.props;
|
|
|
|
return (
|
2020-11-25 04:24:06 -06:00
|
|
|
<div className={cx(styles.mainPaneWrapper, tabs.length === 0 && styles.mainPaneWrapperNoTabs)} key="panel">
|
2020-04-23 13:36:42 -05:00
|
|
|
{this.renderPanelToolbar(styles)}
|
|
|
|
<div className={styles.panelWrapper}>
|
|
|
|
<AutoSizer>
|
|
|
|
{({ width, height }) => {
|
|
|
|
if (width < 3 || height < 3) {
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
return (
|
|
|
|
<div className={styles.centeringContainer} style={{ width, height }}>
|
|
|
|
<div style={calculatePanelSize(uiState.mode, width, height, panel)}>
|
|
|
|
<DashboardPanel
|
|
|
|
dashboard={dashboard}
|
|
|
|
panel={panel}
|
|
|
|
isEditing={true}
|
|
|
|
isViewing={false}
|
|
|
|
isInView={true}
|
|
|
|
/>
|
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
);
|
|
|
|
}}
|
|
|
|
</AutoSizer>
|
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
);
|
|
|
|
};
|
2020-09-28 02:06:46 -05:00
|
|
|
|
2020-11-25 04:24:06 -06:00
|
|
|
renderPanelAndEditor(styles: EditorStyles) {
|
|
|
|
const { panel, dashboard, tabs } = this.props;
|
|
|
|
|
|
|
|
if (tabs.length > 0) {
|
|
|
|
return [
|
|
|
|
this.renderPanel(styles),
|
|
|
|
<div
|
|
|
|
className={styles.tabsWrapper}
|
|
|
|
aria-label={selectors.components.PanelEditor.DataPane.content}
|
|
|
|
key="panel-editor-tabs"
|
|
|
|
>
|
2020-05-25 07:05:43 -05:00
|
|
|
<PanelEditorTabs panel={panel} dashboard={dashboard} tabs={tabs} onChangeTab={this.onChangeTab} />
|
2020-11-25 04:24:06 -06:00
|
|
|
</div>,
|
|
|
|
];
|
|
|
|
}
|
|
|
|
return this.renderPanel(styles);
|
2020-02-09 03:50:58 -06:00
|
|
|
}
|
|
|
|
|
2020-04-02 06:56:20 -05:00
|
|
|
renderTemplateVariables(styles: EditorStyles) {
|
|
|
|
const { variables } = this.props;
|
|
|
|
|
|
|
|
if (!variables.length) {
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
|
|
|
|
return (
|
|
|
|
<div className={styles.variablesWrapper}>
|
|
|
|
<SubMenuItems variables={variables} />
|
|
|
|
</div>
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
2020-04-04 07:25:06 -05:00
|
|
|
renderPanelToolbar(styles: EditorStyles) {
|
2020-06-26 02:08:15 -05:00
|
|
|
const { dashboard, location, uiState, variables, updateTimeZoneForSession } = this.props;
|
2020-02-25 10:58:20 -06:00
|
|
|
return (
|
2020-04-04 07:25:06 -05:00
|
|
|
<div className={styles.panelToolbar}>
|
2020-04-25 00:55:42 -05:00
|
|
|
<HorizontalGroup justify={variables.length > 0 ? 'space-between' : 'flex-end'} align="flex-start">
|
|
|
|
{this.renderTemplateVariables(styles)}
|
|
|
|
|
|
|
|
<HorizontalGroup>
|
2020-09-28 02:06:46 -05:00
|
|
|
<RadioButtonGroup value={uiState.mode} options={displayModes} onChange={this.onDisplayModeChange} />
|
2020-06-26 02:08:15 -05:00
|
|
|
<DashNavTimeControls
|
|
|
|
dashboard={dashboard}
|
|
|
|
location={location}
|
|
|
|
onChangeTimeZone={updateTimeZoneForSession}
|
|
|
|
/>
|
2020-04-25 00:55:42 -05:00
|
|
|
{!uiState.isPanelOptionsVisible && (
|
2021-01-27 13:10:03 -06:00
|
|
|
<ToolbarButton onClick={this.onTogglePanelOptions} tooltip="Open options pane" icon="angle-left">
|
|
|
|
Show options
|
|
|
|
</ToolbarButton>
|
2020-04-25 00:55:42 -05:00
|
|
|
)}
|
|
|
|
</HorizontalGroup>
|
|
|
|
</HorizontalGroup>
|
2020-04-04 07:25:06 -05:00
|
|
|
</div>
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
2020-12-11 07:49:14 -06:00
|
|
|
renderEditorActions() {
|
2021-02-25 04:26:28 -06:00
|
|
|
let editorActions = [
|
2021-01-27 09:46:01 -06:00
|
|
|
<ToolbarButton
|
2020-12-11 07:49:14 -06:00
|
|
|
icon="cog"
|
|
|
|
onClick={this.onOpenDashboardSettings}
|
|
|
|
title="Open dashboard settings"
|
|
|
|
key="settings"
|
|
|
|
/>,
|
2021-01-27 09:46:01 -06:00
|
|
|
<ToolbarButton onClick={this.onDiscard} title="Undo all changes" key="discard">
|
2020-12-11 07:49:14 -06:00
|
|
|
Discard
|
2021-01-27 09:46:01 -06:00
|
|
|
</ToolbarButton>,
|
2021-02-25 04:26:28 -06:00
|
|
|
this.props.panel.libraryPanel ? (
|
|
|
|
<ToolbarButton
|
2021-03-02 09:37:36 -06:00
|
|
|
onClick={this.onSaveLibraryPanel}
|
2021-02-25 04:26:28 -06:00
|
|
|
variant="primary"
|
|
|
|
title="Apply changes and save library panel"
|
|
|
|
key="save-panel"
|
|
|
|
>
|
|
|
|
Save library panel
|
|
|
|
</ToolbarButton>
|
|
|
|
) : (
|
|
|
|
<ToolbarButton onClick={this.onSaveDashboard} title="Apply changes and save dashboard" key="save">
|
|
|
|
Save
|
|
|
|
</ToolbarButton>
|
|
|
|
),
|
2021-01-27 09:46:01 -06:00
|
|
|
<ToolbarButton
|
2021-02-25 04:26:28 -06:00
|
|
|
onClick={this.props.exitPanelEditor}
|
2021-01-27 09:46:01 -06:00
|
|
|
variant="primary"
|
|
|
|
title="Apply changes and go back to dashboard"
|
|
|
|
key="apply"
|
|
|
|
>
|
2020-12-11 07:49:14 -06:00
|
|
|
Apply
|
2021-01-27 09:46:01 -06:00
|
|
|
</ToolbarButton>,
|
2020-12-11 07:49:14 -06:00
|
|
|
];
|
2021-02-25 04:26:28 -06:00
|
|
|
|
|
|
|
if (this.props.panel.libraryPanel) {
|
|
|
|
editorActions.splice(
|
|
|
|
1,
|
|
|
|
0,
|
|
|
|
<ModalsController key="unlink-controller">
|
|
|
|
{({ showModal, hideModal }) => {
|
|
|
|
return (
|
|
|
|
<ToolbarButton
|
|
|
|
onClick={() => {
|
|
|
|
showModal(UnlinkModal, {
|
|
|
|
onConfirm: () => {
|
|
|
|
delete this.props.panel.libraryPanel;
|
|
|
|
this.props.panel.render();
|
|
|
|
this.forceUpdate();
|
|
|
|
},
|
|
|
|
onDismiss: hideModal,
|
|
|
|
isOpen: true,
|
|
|
|
});
|
|
|
|
}}
|
|
|
|
title="Disconnects this panel from the reusable panel so that you can edit it regularly."
|
|
|
|
key="unlink"
|
|
|
|
>
|
|
|
|
Unlink
|
|
|
|
</ToolbarButton>
|
|
|
|
);
|
|
|
|
}}
|
|
|
|
</ModalsController>
|
|
|
|
);
|
|
|
|
|
|
|
|
// Remove "Apply" button
|
|
|
|
editorActions.pop();
|
|
|
|
}
|
|
|
|
|
|
|
|
return editorActions;
|
2020-02-25 10:58:20 -06:00
|
|
|
}
|
|
|
|
|
2020-11-25 04:24:06 -06:00
|
|
|
renderOptionsPane() {
|
|
|
|
const { plugin, dashboard, panel, uiState } = this.props;
|
|
|
|
|
|
|
|
const rightPaneSize =
|
|
|
|
uiState.rightPaneSize <= 1
|
|
|
|
? (uiState.rightPaneSize as number) * window.innerWidth
|
|
|
|
: (uiState.rightPaneSize as number);
|
2020-03-20 09:15:04 -05:00
|
|
|
|
|
|
|
if (!plugin) {
|
2020-03-28 17:11:50 -05:00
|
|
|
return <div />;
|
2020-03-20 09:15:04 -05:00
|
|
|
}
|
2020-02-28 04:04:40 -06:00
|
|
|
|
2020-02-25 10:58:20 -06:00
|
|
|
return (
|
2020-03-20 09:15:04 -05:00
|
|
|
<OptionsPaneContent
|
|
|
|
plugin={plugin}
|
|
|
|
dashboard={dashboard}
|
|
|
|
panel={panel}
|
2020-11-25 04:24:06 -06:00
|
|
|
width={rightPaneSize}
|
2020-03-30 07:39:18 -05:00
|
|
|
onClose={this.onTogglePanelOptions}
|
2020-03-20 09:15:04 -05:00
|
|
|
onFieldConfigsChange={this.onFieldConfigChange}
|
|
|
|
onPanelOptionsChanged={this.onPanelOptionsChanged}
|
|
|
|
onPanelConfigChange={this.onPanelConfigChanged}
|
|
|
|
/>
|
2020-02-25 10:58:20 -06:00
|
|
|
);
|
|
|
|
}
|
|
|
|
|
2019-12-16 02:18:48 -06:00
|
|
|
render() {
|
2020-12-11 07:49:14 -06:00
|
|
|
const { dashboard, initDone, updatePanelEditorUIState, uiState } = this.props;
|
2020-03-30 07:39:18 -05:00
|
|
|
const styles = getStyles(config.theme, this.props);
|
2019-12-16 02:18:48 -06:00
|
|
|
|
2020-02-11 07:57:16 -06:00
|
|
|
if (!initDone) {
|
2019-12-16 02:18:48 -06:00
|
|
|
return null;
|
|
|
|
}
|
|
|
|
|
|
|
|
return (
|
2020-04-27 02:09:05 -05:00
|
|
|
<div className={styles.wrapper} aria-label={selectors.components.PanelEditor.General.content}>
|
2021-02-25 04:26:28 -06:00
|
|
|
<PageToolbar title={`${dashboard.title} / Edit Panel`} onGoBack={this.props.exitPanelEditor}>
|
2021-01-27 09:46:01 -06:00
|
|
|
{this.renderEditorActions()}
|
|
|
|
</PageToolbar>
|
2020-04-17 11:04:57 -05:00
|
|
|
<div className={styles.verticalSplitPanesWrapper}>
|
2020-11-25 04:24:06 -06:00
|
|
|
<SplitPaneWrapper
|
|
|
|
leftPaneComponents={this.renderPanelAndEditor(styles)}
|
|
|
|
rightPaneComponents={this.renderOptionsPane()}
|
|
|
|
uiState={uiState}
|
|
|
|
updateUiState={updatePanelEditorUIState}
|
|
|
|
rightPaneVisible={uiState.isPanelOptionsVisible}
|
|
|
|
/>
|
2020-02-08 12:31:17 -06:00
|
|
|
</div>
|
2020-04-17 11:04:57 -05:00
|
|
|
</div>
|
2019-12-16 02:18:48 -06:00
|
|
|
);
|
|
|
|
}
|
|
|
|
}
|
2020-02-07 07:59:04 -06:00
|
|
|
|
2020-12-15 05:18:40 -06:00
|
|
|
export const PanelEditor = connector(PanelEditorUnconnected);
|
2020-02-11 07:57:16 -06:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Styles
|
|
|
|
*/
|
2020-04-18 11:00:54 -05:00
|
|
|
export const getStyles = stylesFactory((theme: GrafanaTheme, props: Props) => {
|
2020-03-30 07:39:18 -05:00
|
|
|
const { uiState } = props;
|
2020-04-23 13:36:42 -05:00
|
|
|
const paneSpacing = theme.spacing.md;
|
2020-02-11 07:57:16 -06:00
|
|
|
|
|
|
|
return {
|
|
|
|
wrapper: css`
|
|
|
|
width: 100%;
|
|
|
|
height: 100%;
|
|
|
|
position: fixed;
|
2020-04-18 11:00:54 -05:00
|
|
|
z-index: ${theme.zIndex.sidemenu};
|
2020-02-11 07:57:16 -06:00
|
|
|
top: 0;
|
|
|
|
left: 0;
|
|
|
|
right: 0;
|
|
|
|
bottom: 0;
|
2020-04-12 08:05:49 -05:00
|
|
|
background: ${theme.colors.dashboardBg};
|
2020-02-25 10:58:20 -06:00
|
|
|
display: flex;
|
|
|
|
flex-direction: column;
|
|
|
|
`,
|
2020-04-04 07:25:06 -05:00
|
|
|
verticalSplitPanesWrapper: css`
|
|
|
|
display: flex;
|
|
|
|
flex-direction: column;
|
|
|
|
height: 100%;
|
|
|
|
width: 100%;
|
|
|
|
position: relative;
|
|
|
|
`,
|
2020-03-30 07:39:18 -05:00
|
|
|
mainPaneWrapper: css`
|
|
|
|
display: flex;
|
|
|
|
flex-direction: column;
|
|
|
|
height: 100%;
|
2020-02-25 10:58:20 -06:00
|
|
|
width: 100%;
|
2020-04-23 13:36:42 -05:00
|
|
|
padding-right: ${uiState.isPanelOptionsVisible ? 0 : paneSpacing};
|
|
|
|
`,
|
|
|
|
mainPaneWrapperNoTabs: css`
|
|
|
|
padding-bottom: ${paneSpacing};
|
2020-02-11 07:57:16 -06:00
|
|
|
`,
|
2020-04-02 06:56:20 -05:00
|
|
|
variablesWrapper: css`
|
2020-04-25 00:55:42 -05:00
|
|
|
label: variablesWrapper;
|
2020-04-04 07:25:06 -05:00
|
|
|
display: flex;
|
2020-04-25 00:55:42 -05:00
|
|
|
flex-grow: 1;
|
|
|
|
flex-wrap: wrap;
|
2020-04-02 06:56:20 -05:00
|
|
|
`,
|
2020-02-11 07:57:16 -06:00
|
|
|
panelWrapper: css`
|
2020-03-30 07:39:18 -05:00
|
|
|
flex: 1 1 0;
|
|
|
|
min-height: 0;
|
2020-02-11 07:57:16 -06:00
|
|
|
width: 100%;
|
2020-04-23 13:36:42 -05:00
|
|
|
padding-left: ${paneSpacing};
|
2020-02-11 07:57:16 -06:00
|
|
|
`,
|
2020-02-25 10:58:20 -06:00
|
|
|
tabsWrapper: css`
|
2020-02-11 07:57:16 -06:00
|
|
|
height: 100%;
|
|
|
|
width: 100%;
|
2020-02-12 03:42:57 -06:00
|
|
|
`,
|
2020-04-04 07:25:06 -05:00
|
|
|
panelToolbar: css`
|
|
|
|
display: flex;
|
2020-04-23 13:36:42 -05:00
|
|
|
padding: ${paneSpacing} 0 ${paneSpacing} ${paneSpacing};
|
2020-02-11 07:57:16 -06:00
|
|
|
justify-content: space-between;
|
2020-04-04 07:25:06 -05:00
|
|
|
flex-wrap: wrap;
|
2020-02-11 07:57:16 -06:00
|
|
|
`,
|
|
|
|
toolbarLeft: css`
|
2020-02-17 00:28:00 -06:00
|
|
|
padding-left: ${theme.spacing.sm};
|
2020-02-12 03:42:57 -06:00
|
|
|
`,
|
2020-02-11 07:57:16 -06:00
|
|
|
centeringContainer: css`
|
|
|
|
display: flex;
|
|
|
|
justify-content: center;
|
|
|
|
align-items: center;
|
|
|
|
`,
|
|
|
|
};
|
|
|
|
});
|
2020-04-02 06:56:20 -05:00
|
|
|
|
|
|
|
type EditorStyles = ReturnType<typeof getStyles>;
|