PageLayouts: Updates dashboard section routes with navId (#52175)

* First stab at new page layouts behind feature toggle

* Simplifying PageHeader

* Progress on a new model that can more easily support new and old page layouts

* Progress

* rename folder

* Progress

* Minor change

* fixes

* Fixing tests

* Make breadcrumbs work

* Add tests for old Page component

* Adding tests for new Page component and behavior

* fixing page header test

* Fixed test

* Moving user profile routes to navId

* PageLayouts: Updates dashboards routes with navId

* added missing navId

* AppChrome outside route

* Renaming folder

* Minor fix

* Updated

* Fixing StoragePage

* Updated

* Updating translation ids

* Updated snapshot

* update nav translation ids (yes this is confusing)

Co-authored-by: Ashley Harrison <ashley.harrison@grafana.com>
Co-authored-by: joshhunt <josh@trtr.co>
This commit is contained in:
Torkel Ödegaard
2022-07-20 17:26:52 +02:00
committed by GitHub
parent 320262c3db
commit 77f7e8dafc
23 changed files with 80 additions and 218 deletions

View File

@@ -27,10 +27,6 @@ async function getTestContext({ name, interval, items, uid }: Partial<Playlist>
const match: any = { params: { uid: 'foo' } };
const location: any = {};
const history: any = {};
const navModel: any = {
node: {},
main: {},
};
const getMock = jest.spyOn(backendSrv, 'get');
const putMock = jest.spyOn(backendSrv, 'put');
getMock.mockResolvedValue({
@@ -40,14 +36,7 @@ async function getTestContext({ name, interval, items, uid }: Partial<Playlist>
uid: 'foo',
});
const { rerender } = render(
<PlaylistEditPage
queryParams={queryParams}
route={route}
match={match}
location={location}
history={history}
navModel={navModel}
/>
<PlaylistEditPage queryParams={queryParams} route={route} match={match} location={location} history={history} />
);
await waitFor(() => expect(getMock).toHaveBeenCalledTimes(1));

View File

@@ -1,12 +1,8 @@
import React, { FC } from 'react';
import { connect, MapStateToProps } from 'react-redux';
import { NavModel } from '@grafana/data';
import { locationService } from '@grafana/runtime';
import { useStyles2 } from '@grafana/ui';
import { Page } from 'app/core/components/Page/Page';
import { getNavModel } from 'app/core/selectors/navModel';
import { StoreState } from 'app/types';
import { GrafanaRouteComponentProps } from '../../core/navigation/types';
@@ -16,17 +12,13 @@ import { getPlaylistStyles } from './styles';
import { Playlist } from './types';
import { usePlaylist } from './usePlaylist';
interface ConnectedProps {
navModel: NavModel;
}
export interface RouteParams {
uid: string;
}
interface Props extends ConnectedProps, GrafanaRouteComponentProps<RouteParams> {}
interface Props extends GrafanaRouteComponentProps<RouteParams> {}
export const PlaylistEditPage: FC<Props> = ({ navModel, match }) => {
export const PlaylistEditPage: FC<Props> = ({ match }) => {
const styles = useStyles2(getPlaylistStyles);
const { playlist, loading } = usePlaylist(match.params.uid);
const onSubmit = async (playlist: Playlist) => {
@@ -35,7 +27,7 @@ export const PlaylistEditPage: FC<Props> = ({ navModel, match }) => {
};
return (
<Page navModel={navModel}>
<Page navId="dashboards/playlists">
<Page.Contents isLoading={loading}>
<h3 className={styles.subHeading}>Edit playlist</h3>
@@ -50,8 +42,4 @@ export const PlaylistEditPage: FC<Props> = ({ navModel, match }) => {
);
};
const mapStateToProps: MapStateToProps<ConnectedProps, {}, StoreState> = (state: StoreState) => ({
navModel: getNavModel(state.navIndex, 'playlists'),
});
export default connect(mapStateToProps)(PlaylistEditPage);
export default PlaylistEditPage;

View File

@@ -23,7 +23,7 @@ export const PlaylistForm: FC<PlaylistFormProps> = ({ onSubmit, playlist }) => {
const { name, interval, items: propItems } = playlist;
const { items, addById, addByTag, deleteItem, moveDown, moveUp } = usePlaylistItems(propItems);
return (
<>
<div>
<Form onSubmit={(list: Playlist) => onSubmit({ ...list, items })} validateOn={'onBlur'}>
{({ register, errors }) => {
const isDisabled = items.length === 0 || Object.keys(errors).length > 0;
@@ -81,6 +81,6 @@ export const PlaylistForm: FC<PlaylistFormProps> = ({ onSubmit, playlist }) => {
);
}}
</Form>
</>
</div>
);
};

View File

@@ -30,26 +30,9 @@ jest.mock('../../core/components/TagFilter/TagFilter', () => ({
function getTestContext({ name, interval, items }: Partial<Playlist> = {}) {
jest.clearAllMocks();
const playlist = { name, items, interval } as unknown as Playlist;
const queryParams = {};
const route: any = {};
const match: any = {};
const location: any = {};
const history: any = {};
const navModel: any = {
node: {},
main: {},
};
const backendSrvMock = jest.spyOn(backendSrv, 'post');
const { rerender } = render(
<PlaylistNewPage
queryParams={queryParams}
route={route}
match={match}
location={location}
history={history}
navModel={navModel}
/>
);
const { rerender } = render(<PlaylistNewPage />);
return { playlist, rerender, backendSrvMock };
}

View File

@@ -1,14 +1,8 @@
import React, { FC } from 'react';
import { connect, MapStateToProps } from 'react-redux';
import React from 'react';
import { NavModel } from '@grafana/data';
import { locationService } from '@grafana/runtime';
import { useStyles2 } from '@grafana/ui';
import { Page } from 'app/core/components/Page/Page';
import { getNavModel } from 'app/core/selectors/navModel';
import { StoreState } from 'app/types';
import { GrafanaRouteComponentProps } from '../../core/navigation/types';
import { PlaylistForm } from './PlaylistForm';
import { createPlaylist } from './api';
@@ -16,13 +10,7 @@ import { getPlaylistStyles } from './styles';
import { Playlist } from './types';
import { usePlaylist } from './usePlaylist';
interface ConnectedProps {
navModel: NavModel;
}
interface Props extends ConnectedProps, GrafanaRouteComponentProps {}
export const PlaylistNewPage: FC<Props> = ({ navModel }) => {
export const PlaylistNewPage = () => {
const styles = useStyles2(getPlaylistStyles);
const { playlist, loading } = usePlaylist();
const onSubmit = async (playlist: Playlist) => {
@@ -31,7 +19,7 @@ export const PlaylistNewPage: FC<Props> = ({ navModel }) => {
};
return (
<Page navModel={navModel}>
<Page navId="dashboards/playlists">
<Page.Contents isLoading={loading}>
<h3 className={styles.subHeading}>New Playlist</h3>
@@ -46,8 +34,4 @@ export const PlaylistNewPage: FC<Props> = ({ navModel }) => {
);
};
const mapStateToProps: MapStateToProps<ConnectedProps, {}, StoreState> = (state: StoreState) => ({
navModel: getNavModel(state.navIndex, 'playlists'),
});
export default connect(mapStateToProps)(PlaylistNewPage);
export default PlaylistNewPage;

View File

@@ -3,9 +3,7 @@ import React from 'react';
import { contextSrv } from 'app/core/services/context_srv';
import { locationService } from '../../../../packages/grafana-runtime/src';
import { PlaylistPage, PlaylistPageProps } from './PlaylistPage';
import { PlaylistPage } from './PlaylistPage';
const fnMock = jest.fn();
@@ -22,29 +20,8 @@ jest.mock('app/core/services/context_srv', () => ({
},
}));
function getTestContext(propOverrides?: object) {
const props: PlaylistPageProps = {
navModel: {
main: {
text: 'Playlist',
},
node: {
text: 'playlist',
},
},
route: {
path: '/playlists',
component: jest.fn(),
},
queryParams: { state: 'ok' },
match: { params: { name: 'playlist', sourceName: 'test playlist' }, isExact: false, url: 'asdf', path: '' },
history: locationService.getHistory(),
location: { pathname: '', hash: '', search: '', state: '' },
};
Object.assign(props, propOverrides);
return render(<PlaylistPage {...props} />);
function getTestContext() {
return render(<PlaylistPage />);
}
describe('PlaylistPage', () => {

View File

@@ -1,17 +1,12 @@
import React, { FC, useState } from 'react';
import { connect, MapStateToProps } from 'react-redux';
import React, { useState } from 'react';
import { useDebounce } from 'react-use';
import { NavModel } from '@grafana/data';
import { ConfirmModal } from '@grafana/ui';
import { Page } from 'app/core/components/Page/Page';
import PageActionBar from 'app/core/components/PageActionBar/PageActionBar';
import { getNavModel } from 'app/core/selectors/navModel';
import { contextSrv } from 'app/core/services/context_srv';
import { StoreState } from 'app/types';
import EmptyListCTA from '../../core/components/EmptyListCTA/EmptyListCTA';
import { GrafanaRouteComponentProps } from '../../core/navigation/types';
import { EmptyQueryListBanner } from './EmptyQueryListBanner';
import { PlaylistPageList } from './PlaylistPageList';
@@ -19,12 +14,7 @@ import { StartModal } from './StartModal';
import { deletePlaylist, getAllPlaylist } from './api';
import { PlaylistDTO } from './types';
interface ConnectedProps {
navModel: NavModel;
}
export interface PlaylistPageProps extends ConnectedProps, GrafanaRouteComponentProps {}
export const PlaylistPage: FC<PlaylistPageProps> = ({ navModel }) => {
export const PlaylistPage = () => {
const [searchQuery, setSearchQuery] = useState('');
const [debouncedSearchQuery, setDebouncedSearchQuery] = useState(searchQuery);
const [hasFetched, setHasFetched] = useState(false);
@@ -76,7 +66,7 @@ export const PlaylistPage: FC<PlaylistPageProps> = ({ navModel }) => {
const showSearch = playlists.length > 0 || searchQuery.length > 0 || debouncedSearchQuery.length > 0;
return (
<Page navModel={navModel}>
<Page navId="dashboards/playlists">
<Page.Contents isLoading={!hasFetched}>
{showSearch && (
<PageActionBar
@@ -112,8 +102,4 @@ export const PlaylistPage: FC<PlaylistPageProps> = ({ navModel }) => {
);
};
const mapStateToProps: MapStateToProps<ConnectedProps, {}, StoreState> = (state: StoreState) => ({
navModel: getNavModel(state.navIndex, 'playlists'),
});
export default connect(mapStateToProps)(PlaylistPage);
export default PlaylistPage;