mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
Canvas: Position inline editor default via panel dimensions and add context menu option (#51471)
Co-authored-by: nmarrs <nathanielmarrs@gmail.com>
This commit is contained in:
parent
63366615bb
commit
dec3c3a5b1
@ -63,6 +63,8 @@ export class Scene {
|
|||||||
|
|
||||||
isPanelEditing = locationService.getSearchObject().editPanel !== undefined;
|
isPanelEditing = locationService.getSearchObject().editPanel !== undefined;
|
||||||
|
|
||||||
|
inlineEditingCallback?: () => void;
|
||||||
|
|
||||||
constructor(cfg: CanvasFrameOptions, enableEditing: boolean, public onSave: (cfg: CanvasFrameOptions) => void) {
|
constructor(cfg: CanvasFrameOptions, enableEditing: boolean, public onSave: (cfg: CanvasFrameOptions) => void) {
|
||||||
this.root = this.load(cfg, enableEditing);
|
this.root = this.load(cfg, enableEditing);
|
||||||
}
|
}
|
||||||
|
@ -1,11 +1,13 @@
|
|||||||
import { css } from '@emotion/css';
|
import { css } from '@emotion/css';
|
||||||
import React, { useCallback, useEffect, useState } from 'react';
|
import React, { useCallback, useEffect, useState } from 'react';
|
||||||
|
import { useObservable } from 'react-use';
|
||||||
import { first } from 'rxjs/operators';
|
import { first } from 'rxjs/operators';
|
||||||
|
|
||||||
import { ContextMenu, MenuItem } from '@grafana/ui';
|
import { ContextMenu, MenuItem } from '@grafana/ui';
|
||||||
|
|
||||||
import { Scene } from '../../../features/canvas/runtime/scene';
|
import { Scene } from '../../../features/canvas/runtime/scene';
|
||||||
|
|
||||||
|
import { activePanelSubject } from './CanvasPanel';
|
||||||
import { LayerActionID } from './types';
|
import { LayerActionID } from './types';
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
@ -18,6 +20,8 @@ type AnchorPoint = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
export const CanvasContextMenu = ({ scene }: Props) => {
|
export const CanvasContextMenu = ({ scene }: Props) => {
|
||||||
|
const activePanel = useObservable(activePanelSubject);
|
||||||
|
const inlineEditorOpen = activePanel?.panel.state.openInlineEdit;
|
||||||
const [isMenuVisible, setIsMenuVisible] = useState<boolean>(false);
|
const [isMenuVisible, setIsMenuVisible] = useState<boolean>(false);
|
||||||
const [anchorPoint, setAnchorPoint] = useState<AnchorPoint>({ x: 0, y: 0 });
|
const [anchorPoint, setAnchorPoint] = useState<AnchorPoint>({ x: 0, y: 0 });
|
||||||
|
|
||||||
@ -87,6 +91,20 @@ export const CanvasContextMenu = ({ scene }: Props) => {
|
|||||||
}}
|
}}
|
||||||
className={styles.menuItem}
|
className={styles.menuItem}
|
||||||
/>
|
/>
|
||||||
|
<MenuItem
|
||||||
|
label={inlineEditorOpen ? 'Close Editor' : 'Open Editor'}
|
||||||
|
onClick={() => {
|
||||||
|
if (scene.inlineEditingCallback) {
|
||||||
|
if (inlineEditorOpen) {
|
||||||
|
activePanel.panel.inlineEditButtonClose();
|
||||||
|
} else {
|
||||||
|
scene.inlineEditingCallback();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
closeContextMenu();
|
||||||
|
}}
|
||||||
|
className={styles.menuItem}
|
||||||
|
/>
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
@ -57,6 +57,7 @@ export class CanvasPanel extends Component<Props, State> {
|
|||||||
this.scene = new Scene(this.props.options.root, this.props.options.inlineEditing, this.onUpdateScene);
|
this.scene = new Scene(this.props.options.root, this.props.options.inlineEditing, this.onUpdateScene);
|
||||||
this.scene.updateSize(props.width, props.height);
|
this.scene.updateSize(props.width, props.height);
|
||||||
this.scene.updateData(props.data);
|
this.scene.updateData(props.data);
|
||||||
|
this.scene.inlineEditingCallback = this.inlineEditButtonClick;
|
||||||
|
|
||||||
this.subs.add(
|
this.subs.add(
|
||||||
this.props.eventBus.subscribe(PanelEditEnteredEvent, (evt) => {
|
this.props.eventBus.subscribe(PanelEditEnteredEvent, (evt) => {
|
||||||
@ -192,7 +193,9 @@ export class CanvasPanel extends Component<Props, State> {
|
|||||||
};
|
};
|
||||||
|
|
||||||
renderInlineEdit = () => {
|
renderInlineEdit = () => {
|
||||||
return <InlineEdit onClose={() => this.inlineEditButtonClose()} />;
|
return (
|
||||||
|
<InlineEdit onClose={() => this.inlineEditButtonClose()} id={this.props.id} scene={activeCanvasPanel!.scene} />
|
||||||
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
|
@ -1,29 +1,35 @@
|
|||||||
import { css } from '@emotion/css';
|
import { css } from '@emotion/css';
|
||||||
import React, { SyntheticEvent, useRef, useState } from 'react';
|
import React, { SyntheticEvent, useEffect, useRef, useState } from 'react';
|
||||||
import Draggable from 'react-draggable';
|
import Draggable from 'react-draggable';
|
||||||
import { Resizable, ResizeCallbackData } from 'react-resizable';
|
import { Resizable, ResizeCallbackData } from 'react-resizable';
|
||||||
|
|
||||||
import { Dimensions2D, GrafanaTheme2 } from '@grafana/data';
|
import { Dimensions2D, GrafanaTheme2 } from '@grafana/data';
|
||||||
import { IconButton, Portal, useStyles2 } from '@grafana/ui';
|
import { IconButton, Portal, useStyles2 } from '@grafana/ui';
|
||||||
import store from 'app/core/store';
|
import store from 'app/core/store';
|
||||||
|
import { Scene } from 'app/features/canvas/runtime/scene';
|
||||||
|
|
||||||
import { InlineEditBody } from './InlineEditBody';
|
import { InlineEditBody } from './InlineEditBody';
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
onClose?: () => void;
|
onClose?: () => void;
|
||||||
|
id: number;
|
||||||
|
scene: Scene;
|
||||||
};
|
};
|
||||||
|
|
||||||
const OFFSET_X = 70;
|
const OFFSET_X = 10;
|
||||||
|
const OFFSET_Y = 32;
|
||||||
|
|
||||||
export const InlineEdit = ({ onClose }: Props) => {
|
export const InlineEdit = ({ onClose, id, scene }: Props) => {
|
||||||
const btnInlineEdit = document.querySelector('[data-btninlineedit]')!.getBoundingClientRect();
|
const root = scene.root.div!.getBoundingClientRect();
|
||||||
|
const windowHeight = window.innerHeight;
|
||||||
|
const windowWidth = window.innerWidth;
|
||||||
const ref = useRef<HTMLDivElement>(null);
|
const ref = useRef<HTMLDivElement>(null);
|
||||||
const styles = useStyles2(getStyles);
|
const styles = useStyles2(getStyles);
|
||||||
const inlineEditKey = 'inlineEditPanel';
|
const inlineEditKey = 'inlineEditPanel' + id.toString();
|
||||||
|
|
||||||
const defaultMeasurements = { width: 350, height: 400 };
|
const defaultMeasurements = { width: 350, height: 400 };
|
||||||
const defaultX = btnInlineEdit.x + OFFSET_X;
|
const defaultX = root.x + root.width - defaultMeasurements.width - OFFSET_X;
|
||||||
const defaultY = btnInlineEdit.y - defaultMeasurements.height;
|
const defaultY = root.y + OFFSET_Y;
|
||||||
|
|
||||||
const savedPlacement = store.getObject(inlineEditKey, {
|
const savedPlacement = store.getObject(inlineEditKey, {
|
||||||
x: defaultX,
|
x: defaultX,
|
||||||
@ -34,6 +40,18 @@ export const InlineEdit = ({ onClose }: Props) => {
|
|||||||
const [measurements, setMeasurements] = useState<Dimensions2D>({ width: savedPlacement.w, height: savedPlacement.h });
|
const [measurements, setMeasurements] = useState<Dimensions2D>({ width: savedPlacement.w, height: savedPlacement.h });
|
||||||
const [placement, setPlacement] = useState({ x: savedPlacement.x, y: savedPlacement.y });
|
const [placement, setPlacement] = useState({ x: savedPlacement.x, y: savedPlacement.y });
|
||||||
|
|
||||||
|
// Checks that placement is within browser window
|
||||||
|
useEffect(() => {
|
||||||
|
const minX = windowWidth - measurements.width - OFFSET_X;
|
||||||
|
const minY = windowHeight - measurements.height - OFFSET_Y;
|
||||||
|
if (minX < placement.x && minX > 0) {
|
||||||
|
setPlacement({ ...placement, x: minX });
|
||||||
|
}
|
||||||
|
if (minY < placement.y && minY > 0) {
|
||||||
|
setPlacement({ ...placement, y: minY });
|
||||||
|
}
|
||||||
|
}, [windowHeight, windowWidth, placement, measurements]);
|
||||||
|
|
||||||
const onDragStop = (event: any, dragElement: any) => {
|
const onDragStop = (event: any, dragElement: any) => {
|
||||||
let x = dragElement.x < 0 ? 0 : dragElement.x;
|
let x = dragElement.x < 0 ? 0 : dragElement.x;
|
||||||
let y = dragElement.y < 0 ? 0 : dragElement.y;
|
let y = dragElement.y < 0 ? 0 : dragElement.y;
|
||||||
|
Loading…
Reference in New Issue
Block a user