mirror of
https://github.com/grafana/grafana.git
synced 2026-07-30 00:08:10 -05:00
EmbeddedDashboard: Removes no longer used components (#77195)
This commit is contained in:
@@ -3309,9 +3309,6 @@ exports[`better eslint`] = {
|
||||
[0, 0, 0, "Unexpected any. Specify a different type.", "3"],
|
||||
[0, 0, 0, "Use data-testid for E2E selectors instead of aria-label", "4"]
|
||||
],
|
||||
"public/app/features/dashboard/containers/EmbeddedDashboardPage.tsx:5381": [
|
||||
[0, 0, 0, "Styles should be written using objects.", "0"]
|
||||
],
|
||||
"public/app/features/dashboard/dashgrid/DashboardGrid.tsx:5381": [
|
||||
[0, 0, 0, "Unexpected any. Specify a different type.", "0"]
|
||||
],
|
||||
|
||||
@@ -1,71 +0,0 @@
|
||||
import React, { useMemo, useState } from 'react';
|
||||
|
||||
import { config } from '@grafana/runtime';
|
||||
import { Dashboard } from '@grafana/schema';
|
||||
import { Drawer, Tab, TabsBar } from '@grafana/ui';
|
||||
|
||||
import { DashboardModel } from '../../state';
|
||||
import DashboardValidation from '../SaveDashboard/DashboardValidation';
|
||||
import { SaveDashboardDiff } from '../SaveDashboard/SaveDashboardDiff';
|
||||
import { SaveDashboardData } from '../SaveDashboard/types';
|
||||
import { jsonDiff } from '../VersionHistory/utils';
|
||||
|
||||
import { SaveDashboardForm } from './SaveDashboardForm';
|
||||
|
||||
type SaveDashboardDrawerProps = {
|
||||
dashboard: DashboardModel;
|
||||
onDismiss: () => void;
|
||||
dashboardJson: string;
|
||||
onSave: (clone: Dashboard) => Promise<unknown>;
|
||||
};
|
||||
|
||||
export const SaveDashboardDrawer = ({ dashboard, onDismiss, dashboardJson, onSave }: SaveDashboardDrawerProps) => {
|
||||
const data = useMemo<SaveDashboardData>(() => {
|
||||
const clone = dashboard.getSaveModelClone();
|
||||
|
||||
const diff = jsonDiff(JSON.parse(JSON.stringify(dashboardJson, null, 2)), clone);
|
||||
let diffCount = 0;
|
||||
for (const d of Object.values(diff)) {
|
||||
diffCount += d.length;
|
||||
}
|
||||
|
||||
return {
|
||||
clone,
|
||||
diff,
|
||||
diffCount,
|
||||
hasChanges: diffCount > 0,
|
||||
};
|
||||
}, [dashboard, dashboardJson]);
|
||||
|
||||
const [showDiff, setShowDiff] = useState(false);
|
||||
|
||||
return (
|
||||
<Drawer
|
||||
title={'Save dashboard'}
|
||||
onClose={onDismiss}
|
||||
subtitle={dashboard.title}
|
||||
tabs={
|
||||
<TabsBar>
|
||||
<Tab label={'Details'} active={!showDiff} onChangeTab={() => setShowDiff(false)} />
|
||||
{data.hasChanges && (
|
||||
<Tab label={'Changes'} active={showDiff} onChangeTab={() => setShowDiff(true)} counter={data.diffCount} />
|
||||
)}
|
||||
</TabsBar>
|
||||
}
|
||||
>
|
||||
{showDiff ? (
|
||||
<SaveDashboardDiff diff={data.diff} oldValue={dashboardJson} newValue={data.clone} />
|
||||
) : (
|
||||
<SaveDashboardForm
|
||||
dashboard={dashboard}
|
||||
saveModel={data}
|
||||
onCancel={onDismiss}
|
||||
onSuccess={onDismiss}
|
||||
onSubmit={onSave}
|
||||
/>
|
||||
)}
|
||||
|
||||
{config.featureToggles.showDashboardValidationWarnings && <DashboardValidation dashboard={dashboard} />}
|
||||
</Drawer>
|
||||
);
|
||||
};
|
||||
@@ -1,58 +0,0 @@
|
||||
import React, { useMemo, useState } from 'react';
|
||||
|
||||
import { Stack } from '@grafana/experimental';
|
||||
import { Dashboard } from '@grafana/schema';
|
||||
import { Button, Form } from '@grafana/ui';
|
||||
import { useAppNotification } from 'app/core/copy/appNotification';
|
||||
|
||||
import { DashboardModel } from '../../state';
|
||||
import { SaveDashboardData } from '../SaveDashboard/types';
|
||||
|
||||
interface SaveDashboardProps {
|
||||
dashboard: DashboardModel;
|
||||
onCancel: () => void;
|
||||
onSubmit?: (clone: Dashboard) => Promise<unknown>;
|
||||
onSuccess: () => void;
|
||||
saveModel: SaveDashboardData;
|
||||
}
|
||||
export const SaveDashboardForm = ({ dashboard, onCancel, onSubmit, onSuccess, saveModel }: SaveDashboardProps) => {
|
||||
const [saving, setSaving] = useState(false);
|
||||
const notifyApp = useAppNotification();
|
||||
const hasChanges = useMemo(() => dashboard.hasTimeChanged() || saveModel.hasChanges, [dashboard, saveModel]);
|
||||
|
||||
const onFormSubmit = async () => {
|
||||
if (!onSubmit) {
|
||||
return;
|
||||
}
|
||||
setSaving(true);
|
||||
onSubmit(saveModel.clone)
|
||||
.then(() => {
|
||||
notifyApp.success('Dashboard saved locally');
|
||||
onSuccess();
|
||||
})
|
||||
.catch((error) => {
|
||||
notifyApp.error(error.message || 'Error saving dashboard');
|
||||
})
|
||||
.finally(() => setSaving(false));
|
||||
};
|
||||
|
||||
return (
|
||||
<Form onSubmit={onFormSubmit}>
|
||||
{() => {
|
||||
return (
|
||||
<Stack gap={2}>
|
||||
<Stack alignItems="center">
|
||||
<Button variant="secondary" onClick={onCancel} fill="outline">
|
||||
Cancel
|
||||
</Button>
|
||||
<Button type="submit" disabled={!hasChanges} icon={saving ? 'spinner' : undefined}>
|
||||
Save
|
||||
</Button>
|
||||
{!hasChanges && <div>No changes to save</div>}
|
||||
</Stack>
|
||||
</Stack>
|
||||
);
|
||||
}}
|
||||
</Form>
|
||||
);
|
||||
};
|
||||
@@ -1,149 +0,0 @@
|
||||
import { css } from '@emotion/css';
|
||||
import React, { useEffect, useState } from 'react';
|
||||
|
||||
import { GrafanaTheme2, PageLayoutType } from '@grafana/data';
|
||||
import { getBackendSrv, locationService } from '@grafana/runtime';
|
||||
import { Dashboard, TimeZone } from '@grafana/schema';
|
||||
import { Button, ModalsController, PageToolbar, useStyles2 } from '@grafana/ui';
|
||||
import { Page } from 'app/core/components/Page/Page';
|
||||
import { useGrafana } from 'app/core/context/GrafanaContext';
|
||||
import { GrafanaRouteComponentProps } from 'app/core/navigation/types';
|
||||
import { useDispatch, useSelector } from 'app/types';
|
||||
|
||||
import { updateTimeZoneForSession } from '../../profile/state/reducers';
|
||||
import { DashNavTimeControls } from '../components/DashNav/DashNavTimeControls';
|
||||
import { DashboardFailed } from '../components/DashboardLoading/DashboardFailed';
|
||||
import { DashboardLoading } from '../components/DashboardLoading/DashboardLoading';
|
||||
import { SaveDashboardDrawer } from '../components/EmbeddedDashboard/SaveDashboardDrawer';
|
||||
import { DashboardGrid } from '../dashgrid/DashboardGrid';
|
||||
import { DashboardModel } from '../state';
|
||||
import { initDashboard } from '../state/initDashboard';
|
||||
|
||||
interface EmbeddedDashboardPageRouteParams {
|
||||
uid: string;
|
||||
}
|
||||
|
||||
interface EmbeddedDashboardPageRouteSearchParams {
|
||||
serverPort?: string;
|
||||
json?: string;
|
||||
accessToken?: string;
|
||||
}
|
||||
|
||||
export type Props = GrafanaRouteComponentProps<
|
||||
EmbeddedDashboardPageRouteParams,
|
||||
EmbeddedDashboardPageRouteSearchParams
|
||||
>;
|
||||
|
||||
export default function EmbeddedDashboardPage({ route, queryParams }: Props) {
|
||||
const dispatch = useDispatch();
|
||||
const context = useGrafana();
|
||||
const dashboardState = useSelector((store) => store.dashboard);
|
||||
const dashboard = dashboardState.getModel();
|
||||
const [dashboardJson, setDashboardJson] = useState('');
|
||||
|
||||
/**
|
||||
* Create dashboard model and initialize the dashboard from JSON
|
||||
*/
|
||||
useEffect(() => {
|
||||
const serverPort = queryParams.serverPort;
|
||||
|
||||
if (!serverPort) {
|
||||
throw new Error('No serverPort provided');
|
||||
}
|
||||
getBackendSrv()
|
||||
.get(`http://localhost:${serverPort}/load-dashboard`)
|
||||
.then((dashboardJson) => {
|
||||
setDashboardJson(dashboardJson);
|
||||
// Remove dashboard UID from JSON to prevent errors from external dashboards
|
||||
delete dashboardJson.uid;
|
||||
const dashboardModel = new DashboardModel(dashboardJson);
|
||||
|
||||
dispatch(
|
||||
initDashboard({
|
||||
routeName: route.routeName,
|
||||
fixUrl: false,
|
||||
keybindingSrv: context.keybindings,
|
||||
dashboardDto: { dashboard: dashboardModel, meta: { canEdit: true } },
|
||||
})
|
||||
);
|
||||
})
|
||||
.catch((err) => {
|
||||
console.log('Error getting dashboard JSON: ', err);
|
||||
});
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, []);
|
||||
|
||||
if (!dashboard) {
|
||||
return <DashboardLoading initPhase={dashboardState.initPhase} />;
|
||||
}
|
||||
|
||||
if (dashboard.meta.dashboardNotFound) {
|
||||
return <p>Not available</p>;
|
||||
}
|
||||
|
||||
return (
|
||||
<Page pageNav={{ text: dashboard.title }} layout={PageLayoutType.Custom}>
|
||||
<Toolbar dashboard={dashboard} dashboardJson={dashboardJson} />
|
||||
{dashboardState.initError && <DashboardFailed initError={dashboardState.initError} />}
|
||||
<div>
|
||||
<DashboardGrid dashboard={dashboard} isEditable viewPanel={null} editPanel={null} hidePanelMenus />
|
||||
</div>
|
||||
</Page>
|
||||
);
|
||||
}
|
||||
|
||||
interface ToolbarProps {
|
||||
dashboard: DashboardModel;
|
||||
dashboardJson: string;
|
||||
}
|
||||
|
||||
const Toolbar = ({ dashboard, dashboardJson }: ToolbarProps) => {
|
||||
const dispatch = useDispatch();
|
||||
const styles = useStyles2(getStyles);
|
||||
|
||||
const onChangeTimeZone = (timeZone: TimeZone) => {
|
||||
dispatch(updateTimeZoneForSession(timeZone));
|
||||
};
|
||||
|
||||
const saveDashboard = async (clone: Dashboard) => {
|
||||
const params = locationService.getSearch();
|
||||
const serverPort = params.get('serverPort');
|
||||
if (!clone || !serverPort) {
|
||||
return;
|
||||
}
|
||||
|
||||
return getBackendSrv().post(`http://localhost:${serverPort}/save-dashboard`, { dashboard: clone });
|
||||
};
|
||||
|
||||
return (
|
||||
<PageToolbar title={dashboard.title} buttonOverflowAlignment="right" className={styles.toolbar}>
|
||||
{!dashboard.timepicker.hidden && (
|
||||
<DashNavTimeControls dashboard={dashboard} onChangeTimeZone={onChangeTimeZone} />
|
||||
)}
|
||||
<ModalsController key="button-save">
|
||||
{({ showModal, hideModal }) => (
|
||||
<Button
|
||||
onClick={() => {
|
||||
showModal(SaveDashboardDrawer, {
|
||||
dashboard,
|
||||
dashboardJson,
|
||||
onDismiss: hideModal,
|
||||
onSave: saveDashboard,
|
||||
});
|
||||
}}
|
||||
>
|
||||
Save
|
||||
</Button>
|
||||
)}
|
||||
</ModalsController>
|
||||
</PageToolbar>
|
||||
);
|
||||
};
|
||||
|
||||
const getStyles = (theme: GrafanaTheme2) => {
|
||||
return {
|
||||
toolbar: css`
|
||||
padding: ${theme.spacing(3, 2)};
|
||||
`,
|
||||
};
|
||||
};
|
||||
@@ -33,23 +33,3 @@ export const getPublicDashboardRoutes = (): RouteDescriptor[] => {
|
||||
}
|
||||
return [];
|
||||
};
|
||||
|
||||
export const getEmbeddedDashboardRoutes = (): RouteDescriptor[] => {
|
||||
if (config.featureToggles.dashboardEmbed) {
|
||||
return [
|
||||
{
|
||||
path: '/d-embed',
|
||||
pageClass: 'dashboard-embed',
|
||||
routeName: DashboardRoutes.Embedded,
|
||||
component: SafeDynamicImport(
|
||||
() =>
|
||||
import(
|
||||
/* webpackChunkName: "EmbeddedDashboardPage" */ '../../features/dashboard/containers/EmbeddedDashboardPage'
|
||||
)
|
||||
),
|
||||
},
|
||||
];
|
||||
}
|
||||
|
||||
return [];
|
||||
};
|
||||
|
||||
@@ -22,7 +22,7 @@ import { AccessControlAction, DashboardRoutes } from 'app/types';
|
||||
|
||||
import { SafeDynamicImport } from '../core/components/DynamicImports/SafeDynamicImport';
|
||||
import { RouteDescriptor } from '../core/navigation/types';
|
||||
import { getEmbeddedDashboardRoutes, getPublicDashboardRoutes } from '../features/dashboard/routes';
|
||||
import { getPublicDashboardRoutes } from '../features/dashboard/routes';
|
||||
|
||||
export const extraRoutes: RouteDescriptor[] = [];
|
||||
|
||||
@@ -493,7 +493,6 @@ export function getAppRoutes(): RouteDescriptor[] {
|
||||
...extraRoutes,
|
||||
...getPublicDashboardRoutes(),
|
||||
...getDataConnectionsRoutes(),
|
||||
...getEmbeddedDashboardRoutes(),
|
||||
{
|
||||
path: '/*',
|
||||
component: PageNotFound,
|
||||
|
||||
Reference in New Issue
Block a user