mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
ShareModal: able to extend tabs (#22537)
* ShareModal: use generic tab type * ShareModal: able to extend with custom tabs * ShareModal: able to extend dash/panel tabs separately * grafana-ui: ModalTabContent component
This commit is contained in:
parent
9731ea9b89
commit
fcaff011b1
28
packages/grafana-ui/src/components/Modal/ModalTabContent.tsx
Normal file
28
packages/grafana-ui/src/components/Modal/ModalTabContent.tsx
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import { IconType } from '../Icon/types';
|
||||||
|
import { Icon } from '../Icon/Icon';
|
||||||
|
|
||||||
|
interface Props {
|
||||||
|
icon?: IconType;
|
||||||
|
iconClass?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const ModalTabContent: React.FC<Props> = ({ icon, iconClass, children }) => {
|
||||||
|
let iconElem;
|
||||||
|
const showIcon = icon || iconClass;
|
||||||
|
if (iconClass) {
|
||||||
|
iconElem = <i className={iconClass}></i>;
|
||||||
|
}
|
||||||
|
if (icon) {
|
||||||
|
iconElem = <Icon name={icon} />;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="share-modal-body">
|
||||||
|
<div className="share-modal-header">
|
||||||
|
{showIcon && <div className="share-modal-big-icon">{iconElem}</div>}
|
||||||
|
<div className="share-modal-content">{children}</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
@ -48,6 +48,7 @@ export { QueryField } from './QueryField/QueryField';
|
|||||||
export { Modal } from './Modal/Modal';
|
export { Modal } from './Modal/Modal';
|
||||||
export { ModalHeader } from './Modal/ModalHeader';
|
export { ModalHeader } from './Modal/ModalHeader';
|
||||||
export { ModalTabsHeader } from './Modal/ModalTabsHeader';
|
export { ModalTabsHeader } from './Modal/ModalTabsHeader';
|
||||||
|
export { ModalTabContent } from './Modal/ModalTabContent';
|
||||||
export { ModalsProvider, ModalRoot, ModalsController } from './Modal/ModalsContext';
|
export { ModalsProvider, ModalRoot, ModalsController } from './Modal/ModalsContext';
|
||||||
|
|
||||||
// Renderless
|
// Renderless
|
||||||
|
@ -15,7 +15,7 @@ import { ILocationService, IRootScopeService, ITimeoutService } from 'angular';
|
|||||||
import { GrafanaRootScope } from 'app/routes/GrafanaCtrl';
|
import { GrafanaRootScope } from 'app/routes/GrafanaCtrl';
|
||||||
import { getLocationSrv } from '@grafana/runtime';
|
import { getLocationSrv } from '@grafana/runtime';
|
||||||
import { DashboardModel } from '../../features/dashboard/state';
|
import { DashboardModel } from '../../features/dashboard/state';
|
||||||
import { ShareModal } from 'app/features/dashboard/components/ShareModal/ShareModal';
|
import { ShareModal } from 'app/features/dashboard/components/ShareModal';
|
||||||
import { SaveDashboardModalProxy } from '../../features/dashboard/components/SaveDashboard/SaveDashboardModalProxy';
|
import { SaveDashboardModalProxy } from '../../features/dashboard/components/SaveDashboard/SaveDashboardModalProxy';
|
||||||
|
|
||||||
export class KeybindingSrv {
|
export class KeybindingSrv {
|
||||||
|
@ -15,7 +15,7 @@ import { updateLocation } from 'app/core/actions';
|
|||||||
// Types
|
// Types
|
||||||
import { DashboardModel } from '../../state';
|
import { DashboardModel } from '../../state';
|
||||||
import { CoreEvents, StoreState } from 'app/types';
|
import { CoreEvents, StoreState } from 'app/types';
|
||||||
import { ShareModal } from '../ShareModal/ShareModal';
|
import { ShareModal } from 'app/features/dashboard/components/ShareModal';
|
||||||
import { SaveDashboardModalProxy } from 'app/features/dashboard/components/SaveDashboard/SaveDashboardModalProxy';
|
import { SaveDashboardModalProxy } from 'app/features/dashboard/components/SaveDashboard/SaveDashboardModalProxy';
|
||||||
|
|
||||||
export interface OwnProps {
|
export interface OwnProps {
|
||||||
|
@ -13,7 +13,7 @@ const themeOptions: Array<SelectableValue<string>> = [
|
|||||||
];
|
];
|
||||||
|
|
||||||
export interface Props {
|
export interface Props {
|
||||||
dashboard?: DashboardModel;
|
dashboard: DashboardModel;
|
||||||
panel?: PanelModel;
|
panel?: PanelModel;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,18 +1,61 @@
|
|||||||
import React, { PureComponent } from 'react';
|
import React from 'react';
|
||||||
import { Modal, ModalTabsHeader, TabContent } from '@grafana/ui';
|
import { Modal, ModalTabsHeader, TabContent } from '@grafana/ui';
|
||||||
import { DashboardModel, PanelModel } from 'app/features/dashboard/state';
|
import { DashboardModel, PanelModel } from 'app/features/dashboard/state';
|
||||||
import { ShareLink } from './ShareLink';
|
import { ShareLink } from './ShareLink';
|
||||||
import { ShareSnapshot } from './ShareSnapshot';
|
import { ShareSnapshot } from './ShareSnapshot';
|
||||||
import { ShareExport } from './ShareExport';
|
import { ShareExport } from './ShareExport';
|
||||||
import { ShareEmbed } from './ShareEmbed';
|
import { ShareEmbed } from './ShareEmbed';
|
||||||
|
import { ShareModalTabModel } from './types';
|
||||||
|
|
||||||
const shareModalTabs = [
|
const shareCommonTabs: ShareModalTabModel[] = [
|
||||||
{ label: 'Link', value: 'link' },
|
{ label: 'Link', value: 'link', component: ShareLink },
|
||||||
{ label: 'Embed', value: 'embed' },
|
{ label: 'Snapshot', value: 'snapshot', component: ShareSnapshot },
|
||||||
{ label: 'Snapshot', value: 'snapshot' },
|
|
||||||
{ label: 'Export', value: 'export' },
|
|
||||||
];
|
];
|
||||||
|
|
||||||
|
// prettier-ignore
|
||||||
|
const shareDashboardTabs: ShareModalTabModel[] = [
|
||||||
|
{ label: 'Export', value: 'export', component: ShareExport },
|
||||||
|
];
|
||||||
|
|
||||||
|
// prettier-ignore
|
||||||
|
const sharePanelTabs: ShareModalTabModel[] = [
|
||||||
|
{ label: 'Embed', value: 'embed', component: ShareEmbed },
|
||||||
|
];
|
||||||
|
|
||||||
|
const customDashboardTabs: ShareModalTabModel[] = [];
|
||||||
|
const customPanelTabs: ShareModalTabModel[] = [];
|
||||||
|
|
||||||
|
export function addDashboardShareTab(tab: ShareModalTabModel) {
|
||||||
|
customDashboardTabs.push(tab);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function addPanelShareTab(tab: ShareModalTabModel) {
|
||||||
|
customPanelTabs.push(tab);
|
||||||
|
}
|
||||||
|
|
||||||
|
function getInitialState(props: Props): State {
|
||||||
|
const tabs = getTabs(props);
|
||||||
|
return {
|
||||||
|
tabs,
|
||||||
|
activeTab: tabs[0].value,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
function getTabs(props: Props) {
|
||||||
|
const { panel } = props;
|
||||||
|
const tabs = [...shareCommonTabs];
|
||||||
|
|
||||||
|
if (panel) {
|
||||||
|
tabs.push(...sharePanelTabs);
|
||||||
|
tabs.push(...customPanelTabs);
|
||||||
|
} else {
|
||||||
|
tabs.push(...shareDashboardTabs);
|
||||||
|
tabs.push(...customDashboardTabs);
|
||||||
|
}
|
||||||
|
|
||||||
|
return tabs;
|
||||||
|
}
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
dashboard: DashboardModel;
|
dashboard: DashboardModel;
|
||||||
panel?: PanelModel;
|
panel?: PanelModel;
|
||||||
@ -21,64 +64,60 @@ interface Props {
|
|||||||
}
|
}
|
||||||
|
|
||||||
interface State {
|
interface State {
|
||||||
tab: string;
|
tabs: ShareModalTabModel[];
|
||||||
|
activeTab: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
function getInitialState(): State {
|
export class ShareModal extends React.Component<Props, State> {
|
||||||
return {
|
|
||||||
tab: shareModalTabs[0].value,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export class ShareModal extends PureComponent<Props, State> {
|
|
||||||
constructor(props: Props) {
|
constructor(props: Props) {
|
||||||
super(props);
|
super(props);
|
||||||
this.state = getInitialState();
|
this.state = getInitialState(props);
|
||||||
}
|
}
|
||||||
|
|
||||||
onDismiss = () => {
|
onDismiss = () => {
|
||||||
this.setState(getInitialState());
|
this.setState(getInitialState(this.props));
|
||||||
this.props.onDismiss();
|
this.props.onDismiss();
|
||||||
};
|
};
|
||||||
|
|
||||||
onSelectTab = (t: any) => {
|
onSelectTab = (t: any) => {
|
||||||
this.setState({ tab: t.value });
|
this.setState({ activeTab: t.value });
|
||||||
};
|
};
|
||||||
|
|
||||||
getTabs() {
|
getTabs() {
|
||||||
const { panel } = this.props;
|
return getTabs(this.props);
|
||||||
|
}
|
||||||
|
|
||||||
// Filter tabs for dashboard/panel share modal
|
getActiveTab() {
|
||||||
return shareModalTabs.filter(t => {
|
const { tabs, activeTab } = this.state;
|
||||||
if (panel) {
|
return tabs.find(t => t.value === activeTab);
|
||||||
return t.value !== 'export';
|
|
||||||
}
|
|
||||||
return t.value !== 'embed';
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
renderTitle() {
|
renderTitle() {
|
||||||
const { panel } = this.props;
|
const { panel } = this.props;
|
||||||
const { tab } = this.state;
|
const { activeTab } = this.state;
|
||||||
const title = panel ? 'Share Panel' : 'Share';
|
const title = panel ? 'Share Panel' : 'Share';
|
||||||
const tabs = this.getTabs();
|
const tabs = this.getTabs();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<ModalTabsHeader title={title} icon="share-square-o" tabs={tabs} activeTab={tab} onChangeTab={this.onSelectTab} />
|
<ModalTabsHeader
|
||||||
|
title={title}
|
||||||
|
icon="share-square-o"
|
||||||
|
tabs={tabs}
|
||||||
|
activeTab={activeTab}
|
||||||
|
onChangeTab={this.onSelectTab}
|
||||||
|
/>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const { dashboard, panel } = this.props;
|
const { dashboard, panel } = this.props;
|
||||||
const { tab } = this.state;
|
const activeTabModel = this.getActiveTab();
|
||||||
|
const ActiveTab = activeTabModel?.component;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Modal isOpen={true} title={this.renderTitle()} onDismiss={this.onDismiss}>
|
<Modal isOpen={true} title={this.renderTitle()} onDismiss={this.onDismiss}>
|
||||||
<TabContent>
|
<TabContent>
|
||||||
{tab === 'link' && <ShareLink dashboard={dashboard} panel={panel} />}
|
<ActiveTab dashboard={dashboard} panel={panel} onDismiss={this.onDismiss} />
|
||||||
{tab === 'embed' && panel && <ShareEmbed dashboard={dashboard} panel={panel} />}
|
|
||||||
{tab === 'snapshot' && <ShareSnapshot dashboard={dashboard} panel={panel} onDismiss={this.onDismiss} />}
|
|
||||||
{tab === 'export' && !panel && <ShareExport dashboard={dashboard} panel={panel} onDismiss={this.onDismiss} />}
|
|
||||||
</TabContent>
|
</TabContent>
|
||||||
</Modal>
|
</Modal>
|
||||||
);
|
);
|
||||||
|
@ -0,0 +1,2 @@
|
|||||||
|
export { ShareModal, addDashboardShareTab, addPanelShareTab } from './ShareModal';
|
||||||
|
export * from './types';
|
17
public/app/features/dashboard/components/ShareModal/types.ts
Normal file
17
public/app/features/dashboard/components/ShareModal/types.ts
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import { PanelModel } from '@grafana/data';
|
||||||
|
import { DashboardModel } from 'app/features/dashboard/state';
|
||||||
|
|
||||||
|
export interface ShareModalTabProps {
|
||||||
|
dashboard: DashboardModel;
|
||||||
|
panel?: PanelModel;
|
||||||
|
onDismiss?(): void;
|
||||||
|
}
|
||||||
|
|
||||||
|
export type ShareModalTab = React.ComponentType<ShareModalTabProps>;
|
||||||
|
|
||||||
|
export interface ShareModalTabModel {
|
||||||
|
label: string;
|
||||||
|
value: string;
|
||||||
|
component: ShareModalTab;
|
||||||
|
}
|
@ -20,7 +20,7 @@ import templateSrv from 'app/features/templating/template_srv';
|
|||||||
import { LS_PANEL_COPY_KEY, PANEL_BORDER } from 'app/core/constants';
|
import { LS_PANEL_COPY_KEY, PANEL_BORDER } from 'app/core/constants';
|
||||||
import { CoreEvents } from 'app/types';
|
import { CoreEvents } from 'app/types';
|
||||||
|
|
||||||
import { ShareModal } from 'app/features/dashboard/components/ShareModal/ShareModal';
|
import { ShareModal } from 'app/features/dashboard/components/ShareModal';
|
||||||
|
|
||||||
export const removePanel = (dashboard: DashboardModel, panel: PanelModel, ask: boolean) => {
|
export const removePanel = (dashboard: DashboardModel, panel: PanelModel, ask: boolean) => {
|
||||||
// confirm deletion
|
// confirm deletion
|
||||||
|
Loading…
Reference in New Issue
Block a user