mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
New panel editor (behind feature toggle) (#21097)
* WIP: initial 10min poc of new panel editor * added queries * PanelEditor: copy panel model when going into edit mode * Added option
This commit is contained in:
parent
664cb5f8f1
commit
16f0e75448
@ -15,6 +15,7 @@ interface FeatureToggles {
|
||||
transformations: boolean;
|
||||
inspect: boolean;
|
||||
expressions: boolean;
|
||||
newEdit: boolean;
|
||||
}
|
||||
export class GrafanaBootConfig {
|
||||
datasources: { [str: string]: DataSourceInstanceSettings } = {};
|
||||
@ -51,6 +52,7 @@ export class GrafanaBootConfig {
|
||||
transformations: false,
|
||||
inspect: false,
|
||||
expressions: false,
|
||||
newEdit: false,
|
||||
};
|
||||
|
||||
constructor(options: GrafanaBootConfig) {
|
||||
|
@ -123,6 +123,12 @@ export class KeybindingSrv {
|
||||
return;
|
||||
}
|
||||
|
||||
if (search.editPanel) {
|
||||
delete search.editPanel;
|
||||
this.$location.search(search);
|
||||
return;
|
||||
}
|
||||
|
||||
if (search.fullscreen) {
|
||||
appEvents.emit(PanelEvents.panelChangeView, { fullscreen: false, edit: false });
|
||||
return;
|
||||
|
@ -0,0 +1,96 @@
|
||||
import React, { PureComponent } from 'react';
|
||||
import { css } from 'emotion';
|
||||
import { GrafanaTheme } from '@grafana/data';
|
||||
import { stylesFactory } from '@grafana/ui';
|
||||
import config from 'app/core/config';
|
||||
|
||||
import { PanelModel } from '../../state/PanelModel';
|
||||
import { DashboardModel } from '../../state/DashboardModel';
|
||||
import { DashboardPanel } from '../../dashgrid/DashboardPanel';
|
||||
import { QueriesTab } from '../../panel_editor/QueriesTab';
|
||||
|
||||
const getStyles = stylesFactory((theme: GrafanaTheme) => ({
|
||||
wrapper: css`
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
position: fixed;
|
||||
z-index: ${theme.zIndex.modal};
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
background: ${theme.colors.pageBg};
|
||||
display: flex;
|
||||
padding: ${theme.spacing.md};
|
||||
flex-direction: row;
|
||||
`,
|
||||
leftPane: css`
|
||||
flex-grow: 1;
|
||||
height: 100%;
|
||||
`,
|
||||
rightPane: css`
|
||||
width: 450px;
|
||||
height: 100%;
|
||||
flex-grow: 0;
|
||||
`,
|
||||
leftPaneViz: css`
|
||||
width: 100%;
|
||||
height: 50%;
|
||||
`,
|
||||
leftPaneData: css`
|
||||
width: 100%;
|
||||
height: 50%;
|
||||
padding-top: ${theme.spacing.md};
|
||||
`,
|
||||
}));
|
||||
|
||||
interface Props {
|
||||
dashboard: DashboardModel;
|
||||
panel: PanelModel;
|
||||
}
|
||||
|
||||
interface State {
|
||||
dirtyPanel?: PanelModel;
|
||||
}
|
||||
|
||||
export class PanelEditor extends PureComponent<Props, State> {
|
||||
state: State = {};
|
||||
|
||||
componentDidMount() {
|
||||
const { panel } = this.props;
|
||||
const dirtyPanel = new PanelModel(panel.getSaveModel());
|
||||
|
||||
this.setState({ dirtyPanel });
|
||||
}
|
||||
|
||||
render() {
|
||||
const { dashboard } = this.props;
|
||||
const { dirtyPanel } = this.state;
|
||||
|
||||
const styles = getStyles(config.theme);
|
||||
|
||||
if (!dirtyPanel) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
<div className={styles.wrapper}>
|
||||
<div className={styles.leftPane}>
|
||||
<div className={styles.leftPaneViz}>
|
||||
<DashboardPanel
|
||||
dashboard={dashboard}
|
||||
panel={dirtyPanel}
|
||||
isEditing={false}
|
||||
isFullscreen={false}
|
||||
isInView={true}
|
||||
/>
|
||||
</div>
|
||||
<div className={styles.leftPaneData}>
|
||||
<QueriesTab panel={dirtyPanel} dashboard={dashboard} />;
|
||||
</div>
|
||||
</div>
|
||||
<div className={styles.rightPane}>Visualization settings</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
@ -0,0 +1 @@
|
||||
export { PanelEditor } from './PanelEditor';
|
@ -12,7 +12,9 @@ import { DashboardGrid } from '../dashgrid/DashboardGrid';
|
||||
import { DashNav } from '../components/DashNav';
|
||||
import { SubMenu } from '../components/SubMenu';
|
||||
import { DashboardSettings } from '../components/DashboardSettings';
|
||||
import { Alert, CustomScrollbar } from '@grafana/ui';
|
||||
import { PanelEditor } from '../components/PanelEditor';
|
||||
import { CustomScrollbar, Alert } from '@grafana/ui';
|
||||
|
||||
// Redux
|
||||
import { initDashboard } from '../state/initDashboard';
|
||||
import { cleanUpDashboard } from '../state/actions';
|
||||
@ -25,6 +27,7 @@ import {
|
||||
DashboardRouteInfo,
|
||||
StoreState,
|
||||
} from 'app/types';
|
||||
|
||||
import { DashboardModel, PanelModel } from 'app/features/dashboard/state';
|
||||
import { PanelInspector } from '../components/Inspector/PanelInspector';
|
||||
|
||||
@ -35,6 +38,7 @@ export interface Props {
|
||||
editview?: string;
|
||||
urlPanelId?: string;
|
||||
urlFolderId?: string;
|
||||
urlEditPanel?: string;
|
||||
inspectPanelId?: string;
|
||||
$scope: any;
|
||||
$injector: any;
|
||||
@ -248,7 +252,7 @@ export class DashboardPage extends PureComponent<Props, State> {
|
||||
}
|
||||
|
||||
render() {
|
||||
const { dashboard, editview, $injector, isInitSlow, initError, inspectPanelId } = this.props;
|
||||
const { dashboard, editview, $injector, isInitSlow, initError, inspectPanelId, urlEditPanel } = this.props;
|
||||
const { isSettingsOpening, isEditing, isFullscreen, scrollTop, updateScrollTop } = this.state;
|
||||
|
||||
if (!dashboard) {
|
||||
@ -270,6 +274,8 @@ export class DashboardPage extends PureComponent<Props, State> {
|
||||
|
||||
// Find the panel to inspect
|
||||
const inspectPanel = inspectPanelId ? dashboard.getPanelById(parseInt(inspectPanelId, 10)) : null;
|
||||
// find panel being edited
|
||||
const editPanel = urlEditPanel ? dashboard.getPanelById(parseInt(urlEditPanel, 10)) : null;
|
||||
|
||||
// Only trigger render when the scroll has moved by 25
|
||||
const approximateScrollTop = Math.round(scrollTop / 25) * 25;
|
||||
@ -309,6 +315,7 @@ export class DashboardPage extends PureComponent<Props, State> {
|
||||
</div>
|
||||
|
||||
{inspectPanel && <PanelInspector dashboard={dashboard} panel={inspectPanel} />}
|
||||
{editPanel && <PanelEditor dashboard={dashboard} panel={editPanel} />}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@ -320,6 +327,7 @@ export const mapStateToProps = (state: StoreState) => ({
|
||||
urlType: state.location.routeParams.type,
|
||||
editview: state.location.query.editview,
|
||||
urlPanelId: state.location.query.panelId,
|
||||
urlEditPanel: state.location.query.editPanel,
|
||||
urlFolderId: state.location.query.folderId,
|
||||
urlFullscreen: !!state.location.query.fullscreen,
|
||||
urlEdit: !!state.location.query.edit,
|
||||
|
@ -35,6 +35,7 @@ const notPersistedProperties: { [str: string]: boolean } = {
|
||||
fullscreen: true,
|
||||
isEditing: true,
|
||||
isInView: true,
|
||||
isNewEdit: true,
|
||||
hasRefreshed: true,
|
||||
cachedPluginOptions: true,
|
||||
plugin: true,
|
||||
@ -125,6 +126,7 @@ export class PanelModel {
|
||||
fullscreen: boolean;
|
||||
isEditing: boolean;
|
||||
isInView: boolean;
|
||||
isNewEdit: boolean;
|
||||
hasRefreshed: boolean;
|
||||
events: Emitter;
|
||||
cacheTimeout?: any;
|
||||
|
@ -41,6 +41,18 @@ export const getPanelMenu = (dashboard: DashboardModel, panel: PanelModel) => {
|
||||
);
|
||||
};
|
||||
|
||||
const onNewEditPanel = (event: React.MouseEvent<any>) => {
|
||||
event.preventDefault();
|
||||
store.dispatch(
|
||||
updateLocation({
|
||||
query: {
|
||||
editPanel: panel.id,
|
||||
},
|
||||
partial: true,
|
||||
})
|
||||
);
|
||||
};
|
||||
|
||||
const onSharePanel = (event: React.MouseEvent<any>) => {
|
||||
event.preventDefault();
|
||||
sharePanel(dashboard, panel);
|
||||
@ -119,6 +131,7 @@ export const getPanelMenu = (dashboard: DashboardModel, panel: PanelModel) => {
|
||||
onClick: onNavigateToExplore,
|
||||
});
|
||||
}
|
||||
|
||||
if (config.featureToggles.inspect) {
|
||||
menu.push({
|
||||
text: 'Inspect',
|
||||
@ -128,6 +141,15 @@ export const getPanelMenu = (dashboard: DashboardModel, panel: PanelModel) => {
|
||||
});
|
||||
}
|
||||
|
||||
if (config.featureToggles.newEdit) {
|
||||
menu.push({
|
||||
text: 'New edit',
|
||||
iconClassName: 'gicon gicon-editor',
|
||||
onClick: onNewEditPanel,
|
||||
shortcut: 'p i',
|
||||
});
|
||||
}
|
||||
|
||||
const subMenu: PanelMenuItem[] = [];
|
||||
|
||||
if (!panel.fullscreen && dashboard.meta.canEdit) {
|
||||
|
Loading…
Reference in New Issue
Block a user