NavBar: app chrome state wrongly overwritten when ds modal is opened (#67952)

This commit is contained in:
Juan Cabanas
2023-05-08 16:51:42 -03:00
committed by GitHub
parent da21473527
commit 24668137f8
9 changed files with 67 additions and 50 deletions

View File

@@ -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;

View File

@@ -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

View File

@@ -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) {

View File

@@ -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,
});
}}
/>
);
};

View File

@@ -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 }));
};

View File

@@ -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;

View File

@@ -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>
)}

View File

@@ -155,6 +155,7 @@ export function DataSourceModal({
item: INTERACTION_ITEM.CONFIG_NEW_DS,
src: analyticsInteractionSrc,
});
onDismiss();
}}
/>
</div>

View File

@@ -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}