mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
NavBar: app chrome state wrongly overwritten when ds modal is opened (#67952)
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
import React, { Component } from 'react';
|
||||
|
||||
interface ModalsContextState {
|
||||
export interface ModalsContextState {
|
||||
component: React.ComponentType<any> | null;
|
||||
props: any;
|
||||
showModal: <T>(component: React.ComponentType<T>, props: T) => void;
|
||||
|
||||
@@ -4,7 +4,10 @@ import React from 'react';
|
||||
import { GrafanaTheme2 } from '@grafana/data/src';
|
||||
import { selectors as e2eSelectors } from '@grafana/e2e-selectors/src';
|
||||
import { Button, LoadingPlaceholder, Modal, ModalsController, useStyles2 } from '@grafana/ui/src';
|
||||
import { generatePublicDashboardUrl } from 'app/features/dashboard/components/ShareModal/SharePublicDashboard/SharePublicDashboardUtils';
|
||||
import {
|
||||
generatePublicDashboardConfigUrl,
|
||||
generatePublicDashboardUrl,
|
||||
} from 'app/features/dashboard/components/ShareModal/SharePublicDashboard/SharePublicDashboardUtils';
|
||||
|
||||
import { useGetActiveUserDashboardsQuery } from '../../dashboard/api/publicDashboardApi';
|
||||
|
||||
@@ -37,7 +40,7 @@ export const DashboardsListModal = ({ email, onDismiss }: { email: string; onDis
|
||||
<span className={styles.urlsDivider}>•</span>
|
||||
<a
|
||||
className={cx('external-link', styles.url)}
|
||||
href={`/d/${dash.dashboardUid}?shareView=share`}
|
||||
href={generatePublicDashboardConfigUrl(dash.dashboardUid)}
|
||||
onClick={onDismiss}
|
||||
>
|
||||
Public dashboard settings
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { css } from '@emotion/css';
|
||||
import React, { FC, ReactNode, useContext, useEffect } from 'react';
|
||||
import React, { FC, ReactNode } from 'react';
|
||||
import { connect, ConnectedProps } from 'react-redux';
|
||||
import { useLocation } from 'react-router-dom';
|
||||
|
||||
@@ -13,7 +13,6 @@ import {
|
||||
useForceUpdate,
|
||||
Tag,
|
||||
ToolbarButtonRow,
|
||||
ModalsContext,
|
||||
ConfirmModal,
|
||||
} from '@grafana/ui';
|
||||
import { AppChromeUpdate } from 'app/core/components/AppChrome/AppChromeUpdate';
|
||||
@@ -26,7 +25,6 @@ import { t, Trans } from 'app/core/internationalization';
|
||||
import { setStarred } from 'app/core/reducers/navBarTree';
|
||||
import { AddPanelButton } from 'app/features/dashboard/components/AddPanelButton/AddPanelButton';
|
||||
import { SaveDashboardDrawer } from 'app/features/dashboard/components/SaveDashboard/SaveDashboardDrawer';
|
||||
import { ShareModal } from 'app/features/dashboard/components/ShareModal';
|
||||
import { getDashboardSrv } from 'app/features/dashboard/services/DashboardSrv';
|
||||
import { DashboardModel } from 'app/features/dashboard/state';
|
||||
import { playlistSrv } from 'app/features/playlist/PlaylistSrv';
|
||||
@@ -36,6 +34,7 @@ import { DashboardMetaChangedEvent, ShowModalReactEvent } from 'app/types/events
|
||||
|
||||
import { DashNavButton } from './DashNavButton';
|
||||
import { DashNavTimeControls } from './DashNavTimeControls';
|
||||
import { ShareButton } from './ShareButton';
|
||||
|
||||
const mapDispatchToProps = {
|
||||
setStarred,
|
||||
@@ -53,7 +52,6 @@ export interface OwnProps {
|
||||
hideTimePicker: boolean;
|
||||
folderTitle?: string;
|
||||
title: string;
|
||||
shareModalActiveTab?: string;
|
||||
onAddPanel: () => void;
|
||||
}
|
||||
|
||||
@@ -80,7 +78,6 @@ export const DashNav = React.memo<Props>((props) => {
|
||||
// this ensures the component rerenders when the location changes
|
||||
useLocation();
|
||||
const forceUpdate = useForceUpdate();
|
||||
const { showModal, hideModal } = useContext(ModalsContext);
|
||||
|
||||
// We don't really care about the event payload here only that it triggeres a re-render of this component
|
||||
useBusEvent(props.dashboard.events, DashboardMetaChangedEvent);
|
||||
@@ -164,25 +161,6 @@ export const DashNav = React.memo<Props>((props) => {
|
||||
return playlistSrv.isPlaying;
|
||||
};
|
||||
|
||||
// Open/Close
|
||||
useEffect(() => {
|
||||
const dashboard = props.dashboard;
|
||||
const shareModalActiveTab = props.shareModalActiveTab;
|
||||
const { canShare } = dashboard.meta;
|
||||
|
||||
if (canShare && shareModalActiveTab) {
|
||||
// automagically open modal
|
||||
showModal(ShareModal, {
|
||||
dashboard,
|
||||
onDismiss: hideModal,
|
||||
activeTab: shareModalActiveTab,
|
||||
});
|
||||
}
|
||||
return () => {
|
||||
hideModal();
|
||||
};
|
||||
}, [showModal, hideModal, props.dashboard, props.shareModalActiveTab]);
|
||||
|
||||
const renderLeftActions = () => {
|
||||
const { dashboard, kioskMode } = props;
|
||||
const { canStar, canShare, isStarred } = dashboard.meta;
|
||||
@@ -209,23 +187,7 @@ export const DashNav = React.memo<Props>((props) => {
|
||||
}
|
||||
|
||||
if (canShare) {
|
||||
buttons.push(
|
||||
<ModalsController key="button-share">
|
||||
{({ showModal, hideModal }) => (
|
||||
<DashNavButton
|
||||
tooltip={t('dashboard.toolbar.share', 'Share dashboard or panel')}
|
||||
icon="share-alt"
|
||||
iconSize="lg"
|
||||
onClick={() => {
|
||||
showModal(ShareModal, {
|
||||
dashboard,
|
||||
onDismiss: hideModal,
|
||||
});
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
</ModalsController>
|
||||
);
|
||||
buttons.push(<ShareButton key="button-share" dashboard={dashboard} />);
|
||||
}
|
||||
|
||||
if (dashboard.meta.publicDashboardEnabled) {
|
||||
|
||||
@@ -0,0 +1,42 @@
|
||||
import React, { useContext, useEffect } from 'react';
|
||||
|
||||
import { ModalsContext } from '@grafana/ui';
|
||||
import { useQueryParams } from 'app/core/hooks/useQueryParams';
|
||||
import { t } from 'app/core/internationalization';
|
||||
import { DashboardModel } from 'app/features/dashboard/state';
|
||||
|
||||
import { ShareModal } from '../ShareModal';
|
||||
|
||||
import { DashNavButton } from './DashNavButton';
|
||||
|
||||
export const ShareButton = ({ dashboard }: { dashboard: DashboardModel }) => {
|
||||
const [queryParams] = useQueryParams();
|
||||
const { showModal, hideModal } = useContext(ModalsContext);
|
||||
|
||||
useEffect(() => {
|
||||
if (!!queryParams.shareView) {
|
||||
showModal(ShareModal, {
|
||||
dashboard,
|
||||
onDismiss: hideModal,
|
||||
activeTab: String(queryParams.shareView),
|
||||
});
|
||||
}
|
||||
return () => {
|
||||
hideModal();
|
||||
};
|
||||
}, [showModal, hideModal, dashboard, queryParams.shareView]);
|
||||
|
||||
return (
|
||||
<DashNavButton
|
||||
tooltip={t('dashboard.toolbar.share', 'Share dashboard or panel')}
|
||||
icon="share-alt"
|
||||
iconSize="lg"
|
||||
onClick={() => {
|
||||
showModal(ShareModal, {
|
||||
dashboard,
|
||||
onDismiss: hideModal,
|
||||
});
|
||||
}}
|
||||
/>
|
||||
);
|
||||
};
|
||||
@@ -1,6 +1,6 @@
|
||||
import React from 'react';
|
||||
|
||||
import { reportInteraction } from '@grafana/runtime/src';
|
||||
import { locationService, reportInteraction } from '@grafana/runtime/src';
|
||||
import { Modal, ModalTabsHeader, TabContent } from '@grafana/ui';
|
||||
import { config } from 'app/core/config';
|
||||
import { contextSrv } from 'app/core/core';
|
||||
@@ -52,7 +52,7 @@ function getTabs(panel?: PanelModel, activeTab?: string) {
|
||||
}
|
||||
|
||||
if (Boolean(config.featureToggles['publicDashboards'])) {
|
||||
tabs.push({ label: 'Public dashboard', value: 'share', component: SharePublicDashboard });
|
||||
tabs.push({ label: 'Public dashboard', value: 'public-dashboard', component: SharePublicDashboard });
|
||||
}
|
||||
|
||||
const at = tabs.find((t) => t.value === activeTab);
|
||||
@@ -95,6 +95,10 @@ export class ShareModal extends React.Component<Props, State> {
|
||||
reportInteraction('grafana_dashboards_share_modal_viewed');
|
||||
}
|
||||
|
||||
componentWillUnmount() {
|
||||
locationService.partial({ shareView: null });
|
||||
}
|
||||
|
||||
onSelectTab: React.ComponentProps<typeof ModalTabsHeader>['onChangeTab'] = (t) => {
|
||||
this.setState((prevState) => ({ ...prevState, activeTab: t.value }));
|
||||
};
|
||||
|
||||
@@ -76,4 +76,8 @@ export const generatePublicDashboardUrl = (accessToken: string): string => {
|
||||
return `${getConfig().appUrl}public-dashboards/${accessToken}`;
|
||||
};
|
||||
|
||||
export const generatePublicDashboardConfigUrl = (dashboardUid: string): string => {
|
||||
return `/d/${dashboardUid}?shareView=public-dashboard`;
|
||||
};
|
||||
|
||||
export const validEmailRegex = /^[A-Z\d._%+-]+@[A-Z\d.-]+\.[A-Z]{2,}$/i;
|
||||
|
||||
@@ -64,7 +64,6 @@ export type DashboardPageRouteSearchParams = {
|
||||
editPanel?: string;
|
||||
viewPanel?: string;
|
||||
editview?: string;
|
||||
shareView?: string;
|
||||
panelType?: string;
|
||||
inspect?: string;
|
||||
from?: string;
|
||||
@@ -454,7 +453,6 @@ export class UnthemedDashboardPage extends PureComponent<Props, State> {
|
||||
onAddPanel={this.onAddPanel}
|
||||
kioskMode={kioskMode}
|
||||
hideTimePicker={dashboard.timepicker.hidden}
|
||||
shareModalActiveTab={this.props.queryParams.shareView}
|
||||
/>
|
||||
</header>
|
||||
)}
|
||||
|
||||
@@ -155,6 +155,7 @@ export function DataSourceModal({
|
||||
item: INTERACTION_ITEM.CONFIG_NEW_DS,
|
||||
src: analyticsInteractionSrc,
|
||||
});
|
||||
onDismiss();
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
|
||||
@@ -8,7 +8,10 @@ import { Link, ButtonGroup, LinkButton, Icon, Tag, useStyles2, Tooltip, useTheme
|
||||
import { Page } from 'app/core/components/Page/Page';
|
||||
import { contextSrv } from 'app/core/services/context_srv';
|
||||
import { useListPublicDashboardsQuery } from 'app/features/dashboard/api/publicDashboardApi';
|
||||
import { generatePublicDashboardUrl } from 'app/features/dashboard/components/ShareModal/SharePublicDashboard/SharePublicDashboardUtils';
|
||||
import {
|
||||
generatePublicDashboardConfigUrl,
|
||||
generatePublicDashboardUrl,
|
||||
} from 'app/features/dashboard/components/ShareModal/SharePublicDashboard/SharePublicDashboardUtils';
|
||||
import { isOrgAdmin } from 'app/features/plugins/admin/permissions';
|
||||
import { AccessControlAction } from 'app/types';
|
||||
|
||||
@@ -82,7 +85,7 @@ export const PublicDashboardListTable = () => {
|
||||
<LinkButton
|
||||
fill="text"
|
||||
size={responsiveSize}
|
||||
href={`/d/${pd.dashboardUid}?shareView=share`}
|
||||
href={generatePublicDashboardConfigUrl(pd.dashboardUid)}
|
||||
title="Configure public dashboard"
|
||||
disabled={isOrphaned}
|
||||
data-testid={selectors.ListItem.configButton}
|
||||
|
||||
Reference in New Issue
Block a user