Files
grafana/public/app/features/dashboard-scene/sharing/ShareExportTab.tsx
Dominik Prokop bfde6f2c8a Dashboard interactions reporting refactor, DashboardScene interactions handling (#79078)
* Refactor dashboard interactions tracking

* Local scenes tmp

* Use latest scenes

* Review refactor

* Fix enterprise tests

* Reporting parity for panel description
2023-12-06 07:24:15 -08:00

187 lines
6.0 KiB
TypeScript

import saveAs from 'file-saver';
import React from 'react';
import { useAsync } from 'react-use';
import AutoSizer from 'react-virtualized-auto-sizer';
import { SceneComponentProps, SceneObjectBase, SceneObjectRef } from '@grafana/scenes';
import { Button, ClipboardButton, CodeEditor, Field, Modal, Switch, VerticalGroup } from '@grafana/ui';
import { t, Trans } from 'app/core/internationalization';
import { DashboardExporter } from 'app/features/dashboard/components/DashExportModal';
import { shareDashboardType } from 'app/features/dashboard/components/ShareModal/utils';
import { DashboardModel } from 'app/features/dashboard/state';
import { DashboardScene } from '../scene/DashboardScene';
import { transformSceneToSaveModel } from '../serialization/transformSceneToSaveModel';
import { DashboardInteractions } from '../utils/interactions';
import { SceneShareTabState } from './types';
const exportExternallyTranslation = t('share-modal.export.share-externally-label', `Export for sharing externally`);
interface ShareExportTabState extends SceneShareTabState {
dashboardRef: SceneObjectRef<DashboardScene>;
isSharingExternally?: boolean;
isViewingJSON?: boolean;
}
export class ShareExportTab extends SceneObjectBase<ShareExportTabState> {
public tabId = shareDashboardType.export;
static Component = ShareExportTabRenderer;
private _exporter = new DashboardExporter();
constructor(state: Omit<ShareExportTabState, 'panelRef'>) {
super({
isSharingExternally: false,
isViewingJSON: false,
...state,
});
}
public getTabLabel() {
return t('share-modal.tab-title.export', 'Export');
}
public onShareExternallyChange = () => {
this.setState({
isSharingExternally: !this.state.isSharingExternally,
});
};
public onViewJSON = () => {
this.setState({
isViewingJSON: !this.state.isViewingJSON,
});
};
public getClipboardText() {
return;
}
public async getExportableDashboardJson() {
const { dashboardRef, isSharingExternally } = this.state;
const saveModel = transformSceneToSaveModel(dashboardRef.resolve());
const exportable = isSharingExternally
? await this._exporter.makeExportable(new DashboardModel(saveModel))
: saveModel;
return exportable;
}
public async onSaveAsFile() {
const dashboardJson = await this.getExportableDashboardJson();
const dashboardJsonPretty = JSON.stringify(dashboardJson, null, 2);
const { isSharingExternally } = this.state;
const blob = new Blob([dashboardJsonPretty], {
type: 'application/json;charset=utf-8',
});
const time = new Date().getTime();
let title = 'dashboard';
if ('title' in dashboardJson && dashboardJson.title) {
title = dashboardJson.title;
}
saveAs(blob, `${title}-${time}.json`);
DashboardInteractions.exportDownloadJsonClicked({
externally: isSharingExternally,
});
}
}
function ShareExportTabRenderer({ model }: SceneComponentProps<ShareExportTab>) {
const { isSharingExternally, isViewingJSON, modalRef } = model.useState();
const dashboardJson = useAsync(async () => {
if (isViewingJSON) {
const json = await model.getExportableDashboardJson();
return JSON.stringify(json, null, 2);
}
return '';
}, [isViewingJSON]);
return (
<>
{!isViewingJSON && (
<>
<p className="share-modal-info-text">
<Trans i18nKey="share-modal.export.info-text">Export this dashboard.</Trans>
</p>
<VerticalGroup spacing="md">
<Field label={exportExternallyTranslation}>
<Switch
id="share-externally-toggle"
value={isSharingExternally}
onChange={model.onShareExternallyChange}
/>
</Field>
</VerticalGroup>
<Modal.ButtonRow>
<Button
variant="secondary"
onClick={() => {
modalRef?.resolve().onDismiss();
}}
fill="outline"
>
<Trans i18nKey="share-modal.export.cancel-button">Cancel</Trans>
</Button>
<Button variant="secondary" icon="brackets-curly" onClick={model.onViewJSON}>
<Trans i18nKey="share-modal.export.view-button">View JSON</Trans>
</Button>
<Button variant="primary" icon="save" onClick={() => model.onSaveAsFile()}>
<Trans i18nKey="share-modal.export.save-button">Save to file</Trans>
</Button>
</Modal.ButtonRow>
</>
)}
{isViewingJSON && (
<>
<AutoSizer disableHeight>
{({ width }) => {
if (dashboardJson.value) {
return (
<CodeEditor
value={dashboardJson.value ?? ''}
language="json"
showMiniMap={false}
height="500px"
width={width}
/>
);
}
if (dashboardJson.loading) {
return <div>Loading...</div>;
}
return null;
}}
</AutoSizer>
<Modal.ButtonRow>
<Button variant="secondary" fill="outline" onClick={model.onViewJSON} icon="arrow-left">
<Trans i18nKey="share-modal.export.back-button">Back to export config</Trans>
</Button>
<ClipboardButton
variant="secondary"
icon="copy"
disabled={dashboardJson.loading}
getText={() => dashboardJson.value ?? ''}
>
<Trans i18nKey="share-modal.view-json.copy-button">Copy to Clipboard</Trans>
</ClipboardButton>
<Button variant="primary" icon="save" disabled={dashboardJson.loading} onClick={() => model.onSaveAsFile()}>
<Trans i18nKey="share-modal.export.save-button">Save to file</Trans>
</Button>
</Modal.ButtonRow>
</>
)}
</>
);
}