grafana/public/app/features/dashboard/services/DashboardSrv.ts
Giordano Ricci 09f48173fe
Explore: allow users to save Explore state to a new panel in a new dashboard (#45148)
* Add Button & Form

* Save to new dashboard

* minor adjustements

* move modal to a separate component

* handle dashboard name related errors

* pick visualization based on query results

* lift state

* fix types

* Add Open & Close tests

* Add submit test

* add navigation tests

* add tests for API errors

* remove console log

* create wrapper component for AddToDashboardButton

* remove unused mapped prop

* add wrapper test

* rename isActive to isVisible

* invert control over save & redirect logic

* remove leftover commented code

* cleanup setup parameters

* reorganize code & improve tests

* Remove option to add to existing dashboard

* UI tweaks

* disable button if no queries

* Fix tests

* better accessible tests

* handle submission errors

* improve addToDashboard types

* use dashboardSrv' saveDashboard

* remove leftover test helper

* fix typo

Co-authored-by: Piotr Jamróz <pm.jamroz@gmail.com>

* Apply suggestions from code review

Co-authored-by: Kristina <kristina.durivage@grafana.com>

Co-authored-by: Piotr Jamróz <pm.jamroz@gmail.com>
Co-authored-by: Kristina <kristina.durivage@grafana.com>
2022-03-03 08:54:06 +00:00

130 lines
3.7 KiB
TypeScript

import { appEvents } from 'app/core/app_events';
import { DashboardModel } from '../state/DashboardModel';
import { removePanel } from '../utils/panel';
import { DashboardMeta } from 'app/types';
import { getBackendSrv } from 'app/core/services/backend_srv';
import { saveDashboard } from 'app/features/manage-dashboards/state/actions';
import { RemovePanelEvent } from '../../../types/events';
import { BackendSrvRequest } from '@grafana/runtime';
import { lastValueFrom } from 'rxjs';
export interface SaveDashboardOptions {
/** The complete dashboard model. If `dashboard.id` is not set a new dashboard will be created. */
dashboard: DashboardModel;
/** Set a commit message for the version history. */
message?: string;
/** The id of the folder to save the dashboard in. */
folderId?: number;
/** The UID of the folder to save the dashboard in. Overrides `folderId`. */
folderUid?: string;
/** Set to `true` if you want to overwrite existing dashboard with newer version,
* same dashboard title in folder or same dashboard uid. */
overwrite?: boolean;
/** Set the dashboard refresh interval.
* If this is lower than the minimum refresh interval, Grafana will ignore it and will enforce the minimum refresh interval. */
refresh?: string;
}
interface SaveDashboardResponse {
id: number;
slug: string;
status: string;
uid: string;
url: string;
version: number;
}
export class DashboardSrv {
dashboard?: DashboardModel;
constructor() {
appEvents.subscribe(RemovePanelEvent, (e) => this.onRemovePanel(e.payload));
}
create(dashboard: any, meta: DashboardMeta) {
return new DashboardModel(dashboard, meta);
}
setCurrent(dashboard: DashboardModel) {
this.dashboard = dashboard;
}
getCurrent(): DashboardModel | undefined {
if (!this.dashboard) {
console.warn('Calling getDashboardSrv().getCurrent() without calling getDashboardSrv().setCurrent() first.');
}
return this.dashboard;
}
onRemovePanel = (panelId: number) => {
const dashboard = this.getCurrent();
if (dashboard) {
removePanel(dashboard, dashboard.getPanelById(panelId)!, true);
}
};
saveJSONDashboard(json: string) {
const parsedJson = JSON.parse(json);
return saveDashboard({
dashboard: parsedJson,
folderId: this.dashboard?.meta.folderId || parsedJson.folderId,
});
}
saveDashboard(
data: SaveDashboardOptions,
requestOptions?: Pick<BackendSrvRequest, 'showErrorAlert' | 'showSuccessAlert'>
) {
return lastValueFrom(
getBackendSrv().fetch<SaveDashboardResponse>({
url: '/api/dashboards/db/',
method: 'POST',
data: {
...data,
dashboard: data.dashboard.getSaveModelClone(),
},
...requestOptions,
})
);
}
starDashboard(dashboardId: string, isStarred: any) {
const backendSrv = getBackendSrv();
let promise;
if (isStarred) {
promise = backendSrv.delete('/api/user/stars/dashboard/' + dashboardId).then(() => {
return false;
});
} else {
promise = backendSrv.post('/api/user/stars/dashboard/' + dashboardId).then(() => {
return true;
});
}
return promise.then((res: boolean) => {
if (this.dashboard && this.dashboard.id === dashboardId) {
this.dashboard.meta.isStarred = res;
}
return res;
});
}
}
//
// Code below is to export the service to React components
//
let singletonInstance: DashboardSrv;
export function setDashboardSrv(instance: DashboardSrv) {
singletonInstance = instance;
}
export function getDashboardSrv(): DashboardSrv {
if (!singletonInstance) {
singletonInstance = new DashboardSrv();
}
return singletonInstance;
}