mirror of
https://github.com/grafana/grafana.git
synced 2024-12-28 18:01:40 -06:00
Canvas: Add tabs to inline editor (#57778)
This commit is contained in:
parent
3294918e9f
commit
a5c492b033
@ -7316,10 +7316,11 @@ exports[`better eslint`] = {
|
||||
"public/app/plugins/panel/canvas/InlineEditBody.tsx:5381": [
|
||||
[0, 0, 0, "Unexpected any. Specify a different type.", "0"],
|
||||
[0, 0, 0, "Unexpected any. Specify a different type.", "1"],
|
||||
[0, 0, 0, "Unexpected any. Specify a different type.", "2"],
|
||||
[0, 0, 0, "Do not use any type assertions.", "2"],
|
||||
[0, 0, 0, "Unexpected any. Specify a different type.", "3"],
|
||||
[0, 0, 0, "Do not use any type assertions.", "4"],
|
||||
[0, 0, 0, "Unexpected any. Specify a different type.", "5"]
|
||||
[0, 0, 0, "Unexpected any. Specify a different type.", "4"],
|
||||
[0, 0, 0, "Do not use any type assertions.", "5"],
|
||||
[0, 0, 0, "Unexpected any. Specify a different type.", "6"]
|
||||
],
|
||||
"public/app/plugins/panel/canvas/editor/APIEditor.tsx:5381": [
|
||||
[0, 0, 0, "Do not use any type assertions.", "0"],
|
||||
|
@ -1,24 +1,44 @@
|
||||
import { css } from '@emotion/css';
|
||||
import { get as lodashGet } from 'lodash';
|
||||
import React, { useMemo } from 'react';
|
||||
import React, { useMemo, useState } from 'react';
|
||||
import { useObservable } from 'react-use';
|
||||
|
||||
import { DataFrame, PanelOptionsEditorBuilder, StandardEditorContext } from '@grafana/data';
|
||||
import {
|
||||
DataFrame,
|
||||
GrafanaTheme2,
|
||||
PanelOptionsEditorBuilder,
|
||||
SelectableValue,
|
||||
StandardEditorContext,
|
||||
} from '@grafana/data';
|
||||
import { PanelOptionsSupplier } from '@grafana/data/src/panel/PanelPlugin';
|
||||
import { NestedValueAccess } from '@grafana/data/src/utils/OptionsUIBuilders';
|
||||
import { useStyles2 } from '@grafana/ui/src';
|
||||
import { AddLayerButton } from 'app/core/components/Layers/AddLayerButton';
|
||||
import { notFoundItem } from 'app/features/canvas/elements/notFound';
|
||||
import { ElementState } from 'app/features/canvas/runtime/element';
|
||||
import { FrameState } from 'app/features/canvas/runtime/frame';
|
||||
import { OptionsPaneCategory } from 'app/features/dashboard/components/PanelEditor/OptionsPaneCategory';
|
||||
import { OptionsPaneCategoryDescriptor } from 'app/features/dashboard/components/PanelEditor/OptionsPaneCategoryDescriptor';
|
||||
import { fillOptionsPaneItems } from 'app/features/dashboard/components/PanelEditor/getVisualizationOptions';
|
||||
import { setOptionImmutably } from 'app/features/dashboard/components/PanelEditor/utils';
|
||||
|
||||
import { CanvasElementOptions, canvasElementRegistry } from '../../../features/canvas';
|
||||
|
||||
import { activePanelSubject, InstanceState } from './CanvasPanel';
|
||||
import { TabsEditor } from './editor/TabsEditor';
|
||||
import { getElementEditor } from './editor/elementEditor';
|
||||
import { getLayerEditor } from './editor/layerEditor';
|
||||
import { addStandardCanvasEditorOptions } from './module';
|
||||
import { InlineEditTabs } from './types';
|
||||
import { getElementTypes } from './utils';
|
||||
|
||||
export function InlineEditBody() {
|
||||
const activePanel = useObservable(activePanelSubject);
|
||||
const instanceState = activePanel?.panel.context?.instanceState;
|
||||
const styles = useStyles2(getStyles);
|
||||
|
||||
const [activeTab, setActiveTab] = useState<string>(InlineEditTabs.SelectedElement);
|
||||
|
||||
const pane = useMemo(() => {
|
||||
const p = activePanel?.panel;
|
||||
const state: InstanceState = instanceState;
|
||||
@ -27,10 +47,12 @@ export function InlineEditBody() {
|
||||
}
|
||||
|
||||
const supplier = (builder: PanelOptionsEditorBuilder<any>, context: StandardEditorContext<any>) => {
|
||||
builder.addNestedOptions(getLayerEditor(instanceState));
|
||||
if (activeTab === InlineEditTabs.ElementManagement) {
|
||||
builder.addNestedOptions(getLayerEditor(instanceState));
|
||||
}
|
||||
|
||||
const selection = state.selected;
|
||||
if (selection?.length === 1) {
|
||||
if (selection?.length === 1 && activeTab === InlineEditTabs.SelectedElement) {
|
||||
const element = selection[0];
|
||||
if (element && !(element instanceof FrameState)) {
|
||||
builder.addNestedOptions(
|
||||
@ -54,17 +76,51 @@ export function InlineEditBody() {
|
||||
},
|
||||
supplier
|
||||
);
|
||||
}, [instanceState, activePanel]);
|
||||
}, [instanceState, activePanel, activeTab]);
|
||||
|
||||
const topLevelItemsContainerStyle = {
|
||||
marginLeft: 15,
|
||||
marginTop: 10,
|
||||
};
|
||||
|
||||
const onTabChange = (tab: string) => {
|
||||
setActiveTab(tab);
|
||||
};
|
||||
|
||||
const typeOptions = getElementTypes(instanceState?.scene.shouldShowAdvancedTypes).options;
|
||||
const rootLayer: FrameState | undefined = instanceState?.layer;
|
||||
|
||||
const onAddItem = (sel: SelectableValue<string>) => {
|
||||
const newItem = canvasElementRegistry.getIfExists(sel.value) ?? notFoundItem;
|
||||
const newElementOptions = newItem.getNewOptions() as CanvasElementOptions;
|
||||
newElementOptions.type = newItem.id;
|
||||
if (newItem.defaultSize) {
|
||||
newElementOptions.placement = { ...newElementOptions.placement, ...newItem.defaultSize };
|
||||
}
|
||||
if (rootLayer) {
|
||||
const newElement = new ElementState(newItem, newElementOptions, rootLayer);
|
||||
newElement.updateData(rootLayer.scene.context);
|
||||
rootLayer.elements.push(newElement);
|
||||
rootLayer.scene.save();
|
||||
|
||||
rootLayer.reinitializeMoveable();
|
||||
}
|
||||
};
|
||||
|
||||
const noElementSelected =
|
||||
instanceState && activeTab === InlineEditTabs.SelectedElement && instanceState.selected.length === 0;
|
||||
|
||||
return (
|
||||
<>
|
||||
{pane.categories.map((p) => renderOptionsPaneCategoryDescriptor(p))}
|
||||
<div style={topLevelItemsContainerStyle}>{pane.items.map((item) => item.render())}</div>
|
||||
<div style={topLevelItemsContainerStyle}>
|
||||
<AddLayerButton onChange={onAddItem} options={typeOptions} label={'Add item'} />
|
||||
</div>
|
||||
<div style={topLevelItemsContainerStyle}>
|
||||
<TabsEditor onTabChange={onTabChange} />
|
||||
{pane.categories.map((p) => renderOptionsPaneCategoryDescriptor(p))}
|
||||
{noElementSelected && <div className={styles.selectElement}>Please select an element</div>}
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
}
|
||||
@ -119,3 +175,10 @@ function getOptionsPaneCategoryDescriptor<T = any>(
|
||||
fillOptionsPaneItems(supplier, access, getOptionsPaneCategory, context);
|
||||
return root;
|
||||
}
|
||||
|
||||
const getStyles = (theme: GrafanaTheme2) => ({
|
||||
selectElement: css`
|
||||
color: ${theme.colors.text.secondary};
|
||||
padding: ${theme.spacing(2)};
|
||||
`,
|
||||
});
|
||||
|
38
public/app/plugins/panel/canvas/editor/TabsEditor.tsx
Normal file
38
public/app/plugins/panel/canvas/editor/TabsEditor.tsx
Normal file
@ -0,0 +1,38 @@
|
||||
import React, { useState } from 'react';
|
||||
|
||||
import { Tab, TabsBar } from '@grafana/ui/src';
|
||||
|
||||
import { InlineEditTabs } from '../types';
|
||||
|
||||
type Props = {
|
||||
onTabChange: (v: string) => void;
|
||||
};
|
||||
|
||||
export const TabsEditor = ({ onTabChange }: Props) => {
|
||||
const [activeTab, setActiveTab] = useState<string>(InlineEditTabs.SelectedElement);
|
||||
|
||||
const tabs = [
|
||||
{ label: 'Selected Element', value: InlineEditTabs.SelectedElement },
|
||||
{ label: 'Element Management', value: InlineEditTabs.ElementManagement },
|
||||
];
|
||||
|
||||
const onCurrentTabChange = (value: string) => {
|
||||
onTabChange(value);
|
||||
setActiveTab(value);
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
<TabsBar>
|
||||
{tabs.map((t, index) => (
|
||||
<Tab
|
||||
key={`${t.value}-${index}`}
|
||||
label={t.label}
|
||||
active={t.value === activeTab}
|
||||
onChangeTab={() => onCurrentTabChange(t.value!)}
|
||||
/>
|
||||
))}
|
||||
</TabsBar>
|
||||
</>
|
||||
);
|
||||
};
|
@ -15,3 +15,8 @@ export interface DragNode {
|
||||
export interface DropNode extends DragNode {
|
||||
pos: string;
|
||||
}
|
||||
|
||||
export enum InlineEditTabs {
|
||||
ElementManagement = 'element-management',
|
||||
SelectedElement = 'selected-element',
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user