mirror of https://github.com/grafana/grafana
Dynamic dashboards: Copy paste rows tabs and auto grid items (#103237)
* copy paste tab row works * refactor to hook * add buttons to canvas * make i18n * remove paste from add pane and refactor * pasting auto grid panel works * add paste for default grid * set height/width and postion for auto grid items moving to default grid * clean uppull/102879/head
parent
332f041c91
commit
6ff3af7e83
@ -0,0 +1,116 @@ |
|||||||
|
import { |
||||||
|
AutoGridLayoutItemKind, |
||||||
|
DashboardV2Spec, |
||||||
|
GridLayoutItemKind, |
||||||
|
RowsLayoutRowKind, |
||||||
|
TabsLayoutTabKind, |
||||||
|
} from '@grafana/schema/dist/esm/schema/dashboard/v2alpha0'; |
||||||
|
import { LS_PANEL_COPY_KEY, LS_ROW_COPY_KEY, LS_TAB_COPY_KEY } from 'app/core/constants'; |
||||||
|
import store from 'app/core/store'; |
||||||
|
|
||||||
|
import { deserializeGridItem } from '../../serialization/layoutSerializers/DefaultGridLayoutSerializer'; |
||||||
|
import { deserializeAutoGridItem } from '../../serialization/layoutSerializers/ResponsiveGridLayoutSerializer'; |
||||||
|
import { deserializeRow } from '../../serialization/layoutSerializers/RowsLayoutSerializer'; |
||||||
|
import { deserializeTab } from '../../serialization/layoutSerializers/TabsLayoutSerializer'; |
||||||
|
import { dashboardSceneGraph } from '../../utils/dashboardSceneGraph'; |
||||||
|
import { DashboardScene } from '../DashboardScene'; |
||||||
|
import { DashboardGridItem } from '../layout-default/DashboardGridItem'; |
||||||
|
import { GridCell } from '../layout-default/findSpaceForNewPanel'; |
||||||
|
import { AutoGridItem } from '../layout-responsive-grid/ResponsiveGridItem'; |
||||||
|
import { RowItem } from '../layout-rows/RowItem'; |
||||||
|
import { TabItem } from '../layout-tabs/TabItem'; |
||||||
|
|
||||||
|
export function clearClipboard() { |
||||||
|
store.delete(LS_PANEL_COPY_KEY); |
||||||
|
store.delete(LS_ROW_COPY_KEY); |
||||||
|
store.delete(LS_TAB_COPY_KEY); |
||||||
|
} |
||||||
|
|
||||||
|
export interface RowStore { |
||||||
|
elements: DashboardV2Spec['elements']; |
||||||
|
row: RowsLayoutRowKind; |
||||||
|
} |
||||||
|
|
||||||
|
export interface TabStore { |
||||||
|
elements: DashboardV2Spec['elements']; |
||||||
|
tab: TabsLayoutTabKind; |
||||||
|
} |
||||||
|
|
||||||
|
export interface PanelStore { |
||||||
|
elements: DashboardV2Spec['elements']; |
||||||
|
gridItem: GridLayoutItemKind | AutoGridLayoutItemKind; |
||||||
|
} |
||||||
|
|
||||||
|
export function getRowFromClipboard(scene: DashboardScene): RowItem { |
||||||
|
const jsonData = store.get(LS_ROW_COPY_KEY); |
||||||
|
|
||||||
|
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions
|
||||||
|
const jsonObj: RowStore = JSON.parse(jsonData) as RowStore; |
||||||
|
clearClipboard(); |
||||||
|
const panelIdGenerator = getPanelIdGenerator(dashboardSceneGraph.getNextPanelId(scene)); |
||||||
|
|
||||||
|
let row; |
||||||
|
// We don't control the local storage content, so if it's out of sync with the code all bets are off.
|
||||||
|
try { |
||||||
|
row = deserializeRow(jsonObj.row, jsonObj.elements, false, panelIdGenerator); |
||||||
|
} catch (error) { |
||||||
|
throw new Error('Error pasting row from clipboard, please try to copy again'); |
||||||
|
} |
||||||
|
|
||||||
|
return row; |
||||||
|
} |
||||||
|
|
||||||
|
export function getTabFromClipboard(scene: DashboardScene): TabItem { |
||||||
|
const jsonData = store.get(LS_TAB_COPY_KEY); |
||||||
|
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions
|
||||||
|
const jsonObj: TabStore = JSON.parse(jsonData) as TabStore; |
||||||
|
clearClipboard(); |
||||||
|
const panelIdGenerator = getPanelIdGenerator(dashboardSceneGraph.getNextPanelId(scene)); |
||||||
|
let tab; |
||||||
|
try { |
||||||
|
tab = deserializeTab(jsonObj.tab, jsonObj.elements, false, panelIdGenerator); |
||||||
|
} catch (error) { |
||||||
|
throw new Error('Error pasting tab from clipboard, please try to copy again'); |
||||||
|
} |
||||||
|
|
||||||
|
return tab; |
||||||
|
} |
||||||
|
|
||||||
|
export function getPanelFromClipboard(scene: DashboardScene): DashboardGridItem | AutoGridItem { |
||||||
|
const jsonData = store.get(LS_PANEL_COPY_KEY); |
||||||
|
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions
|
||||||
|
const { elements, gridItem }: PanelStore = JSON.parse(jsonData) as PanelStore; |
||||||
|
|
||||||
|
if (gridItem.kind === 'GridLayoutItem') { |
||||||
|
return deserializeGridItem(gridItem, elements, getPanelIdGenerator(dashboardSceneGraph.getNextPanelId(scene))); |
||||||
|
} |
||||||
|
return deserializeAutoGridItem(gridItem, elements, getPanelIdGenerator(dashboardSceneGraph.getNextPanelId(scene))); |
||||||
|
} |
||||||
|
|
||||||
|
export function getAutoGridItemFromClipboard(scene: DashboardScene): AutoGridItem { |
||||||
|
const panel = getPanelFromClipboard(scene); |
||||||
|
if (panel instanceof AutoGridItem) { |
||||||
|
return panel; |
||||||
|
} |
||||||
|
// Convert to AutoGridItem
|
||||||
|
return new AutoGridItem({ body: panel.state.body, key: panel.state.key, variableName: panel.state.variableName }); |
||||||
|
} |
||||||
|
|
||||||
|
export function getDashboardGridItemFromClipboard(scene: DashboardScene, gridCell: GridCell | null): DashboardGridItem { |
||||||
|
const panel = getPanelFromClipboard(scene); |
||||||
|
if (panel instanceof DashboardGridItem) { |
||||||
|
return panel; |
||||||
|
} |
||||||
|
// Convert to DashboardGridItem
|
||||||
|
return new DashboardGridItem({ |
||||||
|
...gridCell, |
||||||
|
body: panel.state.body, |
||||||
|
key: panel.state.key, |
||||||
|
variableName: panel.state.variableName, |
||||||
|
}); |
||||||
|
} |
||||||
|
|
||||||
|
function getPanelIdGenerator(start: number) { |
||||||
|
let id = start; |
||||||
|
return () => id++; |
||||||
|
} |
@ -0,0 +1,36 @@ |
|||||||
|
import { useEffect, useState } from 'react'; |
||||||
|
|
||||||
|
import { LS_PANEL_COPY_KEY, LS_ROW_COPY_KEY, LS_TAB_COPY_KEY } from 'app/core/constants'; |
||||||
|
import store from 'app/core/store'; |
||||||
|
|
||||||
|
export function useClipboardState() { |
||||||
|
const [hasCopiedPanel, setHasCopiedPanel] = useState(store.exists(LS_PANEL_COPY_KEY)); |
||||||
|
const [hasCopiedRow, setHasCopiedRow] = useState(store.exists(LS_ROW_COPY_KEY)); |
||||||
|
const [hasCopiedTab, setHasCopiedTab] = useState(store.exists(LS_TAB_COPY_KEY)); |
||||||
|
|
||||||
|
useEffect(() => { |
||||||
|
const unsubscribe = store.subscribe(LS_PANEL_COPY_KEY, () => { |
||||||
|
setHasCopiedPanel(store.exists(LS_PANEL_COPY_KEY)); |
||||||
|
}); |
||||||
|
|
||||||
|
const unsubscribeRow = store.subscribe(LS_ROW_COPY_KEY, () => { |
||||||
|
setHasCopiedRow(store.exists(LS_ROW_COPY_KEY)); |
||||||
|
}); |
||||||
|
|
||||||
|
const unsubscribeTab = store.subscribe(LS_TAB_COPY_KEY, () => { |
||||||
|
setHasCopiedTab(store.exists(LS_TAB_COPY_KEY)); |
||||||
|
}); |
||||||
|
|
||||||
|
return () => { |
||||||
|
unsubscribe(); |
||||||
|
unsubscribeRow(); |
||||||
|
unsubscribeTab(); |
||||||
|
}; |
||||||
|
}, []); |
||||||
|
|
||||||
|
return { |
||||||
|
hasCopiedPanel, |
||||||
|
hasCopiedRow, |
||||||
|
hasCopiedTab, |
||||||
|
}; |
||||||
|
} |
Loading…
Reference in new issue