grafana/public/app/features/dashboard-scene/sharing/ShareModal.tsx

142 lines
4.5 KiB
TypeScript

import { ComponentProps } from 'react';
import { t } from '@grafana/i18n';
import { config, locationService } from '@grafana/runtime';
import { SceneComponentProps, SceneObjectBase, SceneObjectRef, SceneObjectState, VizPanel } from '@grafana/scenes';
import { Modal, ModalTabsHeader, TabContent } from '@grafana/ui';
import { contextSrv } from 'app/core/core';
import { isPublicDashboardsEnabled } from 'app/features/dashboard/components/ShareModal/SharePublicDashboard/SharePublicDashboardUtils';
import { AccessControlAction } from 'app/types/accessControl';
import { getTrackingSource } from '../../dashboard/components/ShareModal/utils';
import { DashboardInteractions } from '../utils/interactions';
import { getDashboardSceneFor, isLibraryPanel } from '../utils/utils';
import { ShareExportTab } from './ShareExportTab';
import { ShareLibraryPanelTab } from './ShareLibraryPanelTab';
import { ShareLinkTab } from './ShareLinkTab';
import { SharePanelEmbedTab } from './SharePanelEmbedTab';
import { ShareSnapshotTab } from './ShareSnapshotTab';
import { SharePublicDashboardTab } from './public-dashboards/SharePublicDashboardTab';
import { ModalSceneObjectLike, SceneShareTab, SceneShareTabState } from './types';
interface ShareModalState extends SceneObjectState {
panelRef?: SceneObjectRef<VizPanel>;
tabs?: SceneShareTab[];
activeTab: string;
}
type customDashboardTabType = new (...args: SceneShareTabState[]) => SceneShareTab;
const customDashboardTabs: customDashboardTabType[] = [];
export function addDashboardShareTab(tab: customDashboardTabType) {
customDashboardTabs.push(tab);
}
/**
* Used for full dashboard share modal and the panel level share modal
*/
export class ShareModal extends SceneObjectBase<ShareModalState> implements ModalSceneObjectLike {
static Component = SharePanelModalRenderer;
constructor(state: Omit<ShareModalState, 'activeTab'> & { activeTab?: string }) {
super({
activeTab: 'link',
...state,
});
this.addActivationHandler(() => this.buildTabs(state.activeTab));
}
private buildTabs(activeTab?: string) {
const { panelRef } = this.state;
const modalRef = this.getRef();
const tabs: SceneShareTab[] = [new ShareLinkTab({ panelRef, modalRef })];
const dashboard = getDashboardSceneFor(this);
if (!panelRef) {
tabs.push(new ShareExportTab({ modalRef }));
}
if (
contextSrv.isSignedIn &&
config.snapshotEnabled &&
contextSrv.hasPermission(AccessControlAction.SnapshotsCreate)
) {
tabs.push(new ShareSnapshotTab({ panelRef, dashboardRef: dashboard.getRef(), modalRef }));
}
if (panelRef) {
tabs.push(new SharePanelEmbedTab({ panelRef }));
const panel = panelRef.resolve();
if (panel instanceof VizPanel) {
if (!isLibraryPanel(panel)) {
tabs.push(new ShareLibraryPanelTab({ panelRef, modalRef }));
}
}
}
if (!panelRef) {
tabs.push(...customDashboardTabs.map((Tab) => new Tab({ modalRef })));
if (isPublicDashboardsEnabled()) {
tabs.push(new SharePublicDashboardTab({ modalRef }));
}
}
const at = tabs.find((t) => t.tabId === activeTab);
this.setState({ activeTab: at?.tabId ?? tabs[0].tabId, tabs });
}
onDismiss = () => {
if (this.state.panelRef) {
const dashboard = getDashboardSceneFor(this);
dashboard.closeModal();
} else {
locationService.partial({ shareView: null });
}
};
onChangeTab: ComponentProps<typeof ModalTabsHeader>['onChangeTab'] = (tab) => {
DashboardInteractions.sharingCategoryClicked({
item: tab.value,
shareResource: getTrackingSource(this.state.panelRef),
});
this.setState({ activeTab: tab.value });
};
}
function SharePanelModalRenderer({ model }: SceneComponentProps<ShareModal>) {
const { panelRef, tabs, activeTab } = model.useState();
const title = panelRef ? t('share-modal.panel.title', 'Share Panel') : t('share-modal.dashboard.title', 'Share');
if (!tabs) {
return;
}
const modalTabs = tabs?.map((tab) => ({
label: tab.getTabLabel(),
value: tab.tabId,
}));
const header = (
<ModalTabsHeader
title={title}
icon="share-alt"
tabs={modalTabs}
activeTab={activeTab}
onChangeTab={model.onChangeTab}
/>
);
const currentTab = tabs.find((t) => t.tabId === activeTab);
return (
<Modal isOpen={true} title={header} onDismiss={model.onDismiss}>
<TabContent>{currentTab && <currentTab.Component model={currentTab} />}</TabContent>
</Modal>
);
}