LibraryPanels: Load library panels in the frontend rather than the backend (#50560)

Co-authored-by: Torkel Ödegaard <torkel@grafana.com>
This commit is contained in:
Ryan McKinley
2022-10-26 15:38:20 -07:00
committed by GitHub
parent 0db946977b
commit 7346280316
21 changed files with 191 additions and 952 deletions

View File

@@ -27,7 +27,7 @@ export const AddLibraryPanelContents = ({ panel, initialFolderId, onDismiss }: A
const { saveLibraryPanel } = usePanelSave();
const onCreate = useCallback(() => {
panel.libraryPanel = { uid: undefined, name: panelName };
panel.libraryPanel = { uid: '', name: panelName };
saveLibraryPanel(panel, folderId!).then((res) => {
if (!(res instanceof Error)) {
onDismiss();

View File

@@ -4,7 +4,6 @@ import React from 'react';
import { DateTimeInput, GrafanaTheme } from '@grafana/data';
import { useStyles } from '@grafana/ui';
import { isPanelModelLibraryPanel } from '../../guard';
import { PanelModelWithLibraryPanel } from '../../types';
interface Props {
@@ -15,28 +14,29 @@ interface Props {
export const LibraryPanelInformation = ({ panel, formatDate }: Props) => {
const styles = useStyles(getStyles);
if (!isPanelModelLibraryPanel(panel)) {
const meta = panel.libraryPanel?.meta;
if (!meta) {
return null;
}
return (
<div className={styles.info}>
<div className={styles.libraryPanelInfo}>
{`Used on ${panel.libraryPanel.meta.connectedDashboards} `}
{panel.libraryPanel.meta.connectedDashboards === 1 ? 'dashboard' : 'dashboards'}
{`Used on ${meta.connectedDashboards} `}
{meta.connectedDashboards === 1 ? 'dashboard' : 'dashboards'}
</div>
<div className={styles.libraryPanelInfo}>
Last edited on {formatDate?.(panel.libraryPanel.meta.updated, 'L') ?? panel.libraryPanel.meta.updated} by
{panel.libraryPanel.meta.updatedBy.avatarUrl && (
Last edited on {formatDate?.(meta.updated, 'L') ?? meta.updated} by
{meta.updatedBy.avatarUrl && (
<img
width="22"
height="22"
className={styles.userAvatar}
src={panel.libraryPanel.meta.updatedBy.avatarUrl}
alt={`Avatar for ${panel.libraryPanel.meta.updatedBy.name}`}
src={meta.updatedBy.avatarUrl}
alt={`Avatar for ${meta.updatedBy.name}`}
/>
)}
{panel.libraryPanel.meta.updatedBy.name}
{meta.updatedBy.name}
</div>
</div>
);

View File

@@ -1,5 +1,7 @@
import { lastValueFrom } from 'rxjs';
import { DashboardModel } from 'app/features/dashboard/state';
import { getBackendSrv } from '../../../core/services/backend_srv';
import { DashboardSearchItem } from '../../search/types';
import {
@@ -54,7 +56,18 @@ export async function getLibraryPanel(uid: string, isHandled = false): Promise<L
showErrorAlert: !isHandled,
})
);
return response.data.result;
// kinda heavy weight migration process!!!
const { result } = response.data;
const dash = new DashboardModel({
schemaVersion: 35, // should be saved in the library panel
panels: [result.model],
});
const model = dash.panels[0].getSaveModel(); // migrated panel
dash.destroy(); // kill event listeners
return {
...result,
model,
};
}
export async function getLibraryPanelByName(name: string): Promise<LibraryElementDTO[]> {
@@ -76,9 +89,9 @@ export async function addLibraryPanel(
}
export async function updateLibraryPanel(panelSaveModel: PanelModelWithLibraryPanel): Promise<LibraryElementDTO> {
const { uid, name, version } = panelSaveModel.libraryPanel;
const { libraryPanel, ...model } = panelSaveModel;
const { uid, name, version } = libraryPanel;
const kind = LibraryElementKind.Panel;
const model = panelSaveModel;
const { result } = await getBackendSrv().patch(`/api/library-elements/${uid}`, {
name,
model,

View File

@@ -59,10 +59,13 @@ export interface LibraryElementDTOMetaUser {
avatarUrl: string;
}
export type PanelModelLibraryPanel = Pick<LibraryElementDTO, 'uid' | 'name' | 'meta' | 'version'>;
export interface LibraryPanelRef {
name: string;
uid: string;
}
export interface PanelModelWithLibraryPanel extends PanelModel {
libraryPanel: PanelModelLibraryPanel;
libraryPanel: LibraryElementDTO;
}
export type DispatchResult = (dispatch: Dispatch<AnyAction>) => void;

View File

@@ -3,7 +3,7 @@ import { AppNotification } from '../../types';
import { PanelModel } from '../dashboard/state';
import { addLibraryPanel, updateLibraryPanel } from './state/api';
import { LibraryElementDTO, PanelModelLibraryPanel } from './types';
import { LibraryElementDTO } from './types';
export function createPanelLibraryErrorNotification(message: string): AppNotification {
return createErrorNotification(message);
@@ -13,11 +13,6 @@ export function createPanelLibrarySuccessNotification(message: string): AppNotif
return createSuccessNotification(message);
}
export function toPanelModelLibraryPanel(libraryPanelDto: LibraryElementDTO): PanelModelLibraryPanel {
const { uid, name, meta, version } = libraryPanelDto;
return { uid, name, meta, version };
}
export async function saveAndRefreshLibraryPanel(panel: PanelModel, folderId: number): Promise<LibraryElementDTO> {
const panelSaveModel = toPanelSaveModel(panel);
const savedPanel = await saveOrUpdateLibraryPanel(panelSaveModel, folderId);
@@ -42,7 +37,7 @@ function updatePanelModelWithUpdate(panel: PanelModel, updated: LibraryElementDT
panel.restoreModel({
...updated.model,
configRev: 0, // reset config rev, since changes have been saved
libraryPanel: toPanelModelLibraryPanel(updated),
libraryPanel: updated,
title: panel.title,
});
panel.hasSavedPanelEditChange = true;
@@ -54,7 +49,7 @@ function saveOrUpdateLibraryPanel(panel: any, folderId: number): Promise<Library
return Promise.reject();
}
if (panel.libraryPanel && panel.libraryPanel.uid === undefined) {
if (panel.libraryPanel && panel.libraryPanel.uid === '') {
return addLibraryPanel(panel, folderId!);
}