mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
public dashboards: insert default public dashboard config into database on save (#49131)
This PR adds endpoints for saving and retrieving a public dashboard configuration and and api endpoint to retrieve the public dashboard. All of this is highly experimental and APIs will change. Notably, we will be removing isPublic from the dashboard model and moving it over to the public dashboard table in the next release. Further context can be found here: https://github.com/grafana/grafana/pull/49131#issuecomment-1145456952
This commit is contained in:
@@ -1,10 +1,27 @@
|
||||
import { fireEvent, render, screen, waitFor } from '@testing-library/react';
|
||||
import React from 'react';
|
||||
|
||||
import { BackendSrv } from '@grafana/runtime';
|
||||
import config from 'app/core/config';
|
||||
import { DashboardModel, PanelModel } from 'app/features/dashboard/state';
|
||||
|
||||
import { ShareModal } from './ShareModal';
|
||||
import { PublicDashboardConfig } from './SharePublicDashboardUtils';
|
||||
|
||||
// Mock api request
|
||||
const publicDashboardconfigResp: PublicDashboardConfig = {
|
||||
isPublic: true,
|
||||
publicDashboard: { uid: '', dashboardUid: '' },
|
||||
};
|
||||
|
||||
const backendSrv = {
|
||||
get: () => publicDashboardconfigResp,
|
||||
} as unknown as BackendSrv;
|
||||
|
||||
jest.mock('@grafana/runtime', () => ({
|
||||
...(jest.requireActual('@grafana/runtime') as unknown as object),
|
||||
getBackendSrv: () => backendSrv,
|
||||
}));
|
||||
|
||||
jest.mock('app/core/core', () => {
|
||||
return {
|
||||
|
||||
@@ -1,12 +1,13 @@
|
||||
import React, { useState, useEffect } from 'react';
|
||||
|
||||
import { Button, Field, Switch } from '@grafana/ui';
|
||||
import { Button, Field, Switch, Alert } from '@grafana/ui';
|
||||
import { notifyApp } from 'app/core/actions';
|
||||
import { createErrorNotification, createSuccessNotification } from 'app/core/copy/appNotification';
|
||||
import { createErrorNotification } from 'app/core/copy/appNotification';
|
||||
import { VariableModel } from 'app/features/variables/types';
|
||||
import { dispatch } from 'app/store/store';
|
||||
|
||||
import {
|
||||
dashboardCanBePublic,
|
||||
dashboardHasTemplateVariables,
|
||||
getPublicDashboardConfig,
|
||||
savePublicDashboardConfig,
|
||||
PublicDashboardConfig,
|
||||
@@ -15,46 +16,45 @@ import { ShareModalTabProps } from './types';
|
||||
|
||||
interface Props extends ShareModalTabProps {}
|
||||
|
||||
// 1. write test for dashboardCanBePublic
|
||||
// 2. figure out how to disable the switch
|
||||
|
||||
export const SharePublicDashboard = (props: Props) => {
|
||||
const [publicDashboardConfig, setPublicDashboardConfig] = useState<PublicDashboardConfig>({ isPublic: false });
|
||||
const dashboardUid = props.dashboard.uid;
|
||||
const [publicDashboardConfig, setPublicDashboardConfig] = useState<PublicDashboardConfig>({
|
||||
isPublic: false,
|
||||
publicDashboard: { uid: '', dashboardUid },
|
||||
});
|
||||
|
||||
const [dashboardVariables, setDashboardVariables] = useState<VariableModel[]>([]);
|
||||
|
||||
useEffect(() => {
|
||||
getPublicDashboardConfig(dashboardUid)
|
||||
.then((pdc: PublicDashboardConfig) => {
|
||||
setPublicDashboardConfig(pdc);
|
||||
})
|
||||
.catch(() => {
|
||||
dispatch(notifyApp(createErrorNotification('Failed to retrieve public dashboard config')));
|
||||
});
|
||||
}, [dashboardUid]);
|
||||
setDashboardVariables(props.dashboard.getVariables());
|
||||
getPublicDashboardConfig(dashboardUid, setPublicDashboardConfig).catch();
|
||||
}, [props, dashboardUid]);
|
||||
|
||||
const onSavePublicConfig = () => {
|
||||
// verify dashboard can be public
|
||||
if (!dashboardCanBePublic(props.dashboard)) {
|
||||
dispatch(notifyApp(createErrorNotification('This dashboard cannot be made public')));
|
||||
if (dashboardHasTemplateVariables(dashboardVariables)) {
|
||||
dispatch(
|
||||
notifyApp(createErrorNotification('This dashboard cannot be made public because it has template variables'))
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
savePublicDashboardConfig(props.dashboard.uid, publicDashboardConfig);
|
||||
dispatch(notifyApp(createSuccessNotification('Dashboard sharing configuration saved')));
|
||||
} catch (err) {
|
||||
console.error('Error while making dashboard public', err);
|
||||
dispatch(notifyApp(createErrorNotification('Error making dashboard public')));
|
||||
}
|
||||
savePublicDashboardConfig(props.dashboard.uid, publicDashboardConfig, setPublicDashboardConfig).catch();
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
{dashboardHasTemplateVariables(dashboardVariables) && (
|
||||
<Alert severity="warning" title="dashboard cannot be public">
|
||||
This dashboard cannot be made public because it has template variables
|
||||
</Alert>
|
||||
)}
|
||||
|
||||
<p className="share-modal-info-text">Public Dashboard Configuration</p>
|
||||
|
||||
<Field label="Enabled" description="Configures whether current dashboard can be available publicly">
|
||||
<Switch
|
||||
id="share-current-time-range"
|
||||
disabled={!dashboardCanBePublic(props.dashboard)}
|
||||
disabled={dashboardHasTemplateVariables(dashboardVariables)}
|
||||
value={publicDashboardConfig?.isPublic}
|
||||
onChange={() =>
|
||||
setPublicDashboardConfig((state) => {
|
||||
|
||||
@@ -1,17 +1,16 @@
|
||||
import { DashboardModel } from 'app/features/dashboard/state';
|
||||
import { VariableModel } from 'app/features/variables/types';
|
||||
|
||||
import { dashboardCanBePublic } from './SharePublicDashboardUtils';
|
||||
import { dashboardHasTemplateVariables } from './SharePublicDashboardUtils';
|
||||
|
||||
describe('dashboardCanBePublic', () => {
|
||||
it('can be public with no template variables', () => {
|
||||
//@ts-ignore
|
||||
const dashboard: DashboardModel = { templating: { list: [] } };
|
||||
expect(dashboardCanBePublic(dashboard)).toBe(true);
|
||||
describe('dashboardHasTemplateVariables', () => {
|
||||
it('false', () => {
|
||||
let variables: VariableModel[] = [];
|
||||
expect(dashboardHasTemplateVariables(variables)).toBe(false);
|
||||
});
|
||||
|
||||
it('cannot be public with template variables', () => {
|
||||
it('true', () => {
|
||||
//@ts-ignore
|
||||
const dashboard: DashboardModel = { templating: { list: [{}] } };
|
||||
expect(dashboardCanBePublic(dashboard)).toBe(false);
|
||||
let variables: VariableModel[] = ['a'];
|
||||
expect(dashboardHasTemplateVariables(variables)).toBe(true);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1,21 +1,43 @@
|
||||
import { getBackendSrv } from '@grafana/runtime';
|
||||
import { DashboardModel } from 'app/features/dashboard/state';
|
||||
import { notifyApp } from 'app/core/actions';
|
||||
import { createSuccessNotification } from 'app/core/copy/appNotification';
|
||||
import { VariableModel } from 'app/features/variables/types';
|
||||
import { dispatch } from 'app/store/store';
|
||||
import { DashboardDataDTO, DashboardMeta } from 'app/types/dashboard';
|
||||
|
||||
export interface PublicDashboardConfig {
|
||||
isPublic: boolean;
|
||||
publicDashboard: {
|
||||
uid: string;
|
||||
dashboardUid: string;
|
||||
timeSettings?: object;
|
||||
};
|
||||
}
|
||||
export interface DashboardResponse {
|
||||
dashboard: DashboardDataDTO;
|
||||
meta: DashboardMeta;
|
||||
}
|
||||
|
||||
export const dashboardCanBePublic = (dashboard: DashboardModel): boolean => {
|
||||
return dashboard?.templating?.list.length === 0;
|
||||
export const dashboardHasTemplateVariables = (variables: VariableModel[]): boolean => {
|
||||
return variables.length > 0;
|
||||
};
|
||||
|
||||
export const getPublicDashboardConfig = async (dashboardUid: string) => {
|
||||
export const getPublicDashboardConfig = async (
|
||||
dashboardUid: string,
|
||||
setPublicDashboardConfig: React.Dispatch<React.SetStateAction<PublicDashboardConfig>>
|
||||
) => {
|
||||
const url = `/api/dashboards/uid/${dashboardUid}/public-config`;
|
||||
return getBackendSrv().get(url);
|
||||
const pdResp: PublicDashboardConfig = await getBackendSrv().get(url);
|
||||
setPublicDashboardConfig(pdResp);
|
||||
};
|
||||
|
||||
export const savePublicDashboardConfig = async (dashboardUid: string, conf: PublicDashboardConfig) => {
|
||||
const payload = { isPublic: conf.isPublic };
|
||||
export const savePublicDashboardConfig = async (
|
||||
dashboardUid: string,
|
||||
publicDashboardConfig: PublicDashboardConfig,
|
||||
setPublicDashboardConfig: Function
|
||||
) => {
|
||||
const url = `/api/dashboards/uid/${dashboardUid}/public-config`;
|
||||
return getBackendSrv().post(url, payload);
|
||||
const pdResp: PublicDashboardConfig = await getBackendSrv().post(url, publicDashboardConfig);
|
||||
dispatch(notifyApp(createSuccessNotification('Dashboard sharing configuration saved')));
|
||||
setPublicDashboardConfig(pdResp);
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user