mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
chore: Reduce code duplication by letting the page component adding the header and taking care of the page title
This commit is contained in:
@@ -1,6 +1,8 @@
|
||||
// Libraries
|
||||
import React, { Component } from 'react';
|
||||
import config from 'app/core/config';
|
||||
import { NavModel } from 'app/types';
|
||||
import { getTitleFromNavModel } from 'app/core/selectors/navModel';
|
||||
|
||||
// Components
|
||||
import PageHeader from '../PageHeader/PageHeader';
|
||||
@@ -11,6 +13,7 @@ import { CustomScrollbar } from '@grafana/ui';
|
||||
interface Props {
|
||||
title?: string;
|
||||
children: JSX.Element[] | JSX.Element;
|
||||
navModel: NavModel;
|
||||
}
|
||||
|
||||
class Page extends Component<Props> {
|
||||
@@ -35,26 +38,36 @@ class Page extends Component<Props> {
|
||||
}
|
||||
|
||||
updateTitle = () => {
|
||||
const { title } = this.props;
|
||||
const title = this.getPageTitle;
|
||||
document.title = title ? title + ' - Grafana' : 'Grafana';
|
||||
}
|
||||
|
||||
get getPageTitle () {
|
||||
const { navModel } = this.props;
|
||||
if (navModel) {
|
||||
return getTitleFromNavModel(navModel) || undefined;
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
|
||||
render() {
|
||||
const { navModel } = this.props;
|
||||
const { buildInfo } = config;
|
||||
return (
|
||||
<div className="page-scrollbar-wrapper">
|
||||
<CustomScrollbar autoHeightMin={'100%'}>
|
||||
<div className="page-scrollbar-content">
|
||||
{this.props.children}
|
||||
<Footer
|
||||
appName="Grafana"
|
||||
buildCommit={buildInfo.commit}
|
||||
buildVersion={buildInfo.version}
|
||||
newGrafanaVersion={buildInfo.latestVersion}
|
||||
newGrafanaVersionExists={buildInfo.hasUpdate} />
|
||||
</div>
|
||||
</CustomScrollbar>
|
||||
</div>
|
||||
<div className="page-scrollbar-wrapper">
|
||||
<CustomScrollbar autoHeightMin={'100%'}>
|
||||
<div className="page-scrollbar-content">
|
||||
<PageHeader model={navModel} />
|
||||
{this.props.children}
|
||||
<Footer
|
||||
appName="Grafana"
|
||||
buildCommit={buildInfo.commit}
|
||||
buildVersion={buildInfo.version}
|
||||
newGrafanaVersion={buildInfo.latestVersion}
|
||||
newGrafanaVersionExists={buildInfo.hasUpdate} />
|
||||
</div>
|
||||
</CustomScrollbar>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,7 +3,7 @@ import ReactDOMServer from 'react-dom/server';
|
||||
import { connect } from 'react-redux';
|
||||
import { hot } from 'react-hot-loader';
|
||||
import { NavModel, ApiKey, NewApiKey, OrgRole } from 'app/types';
|
||||
import { getNavModel, getTitleFromNavModel } from 'app/core/selectors/navModel';
|
||||
import { getNavModel } from 'app/core/selectors/navModel';
|
||||
import { getApiKeys, getApiKeysCount } from './state/selectors';
|
||||
import { loadApiKeys, deleteApiKey, setSearchQuery, addApiKey } from './state/actions';
|
||||
import Page from 'app/core/components/Page/Page';
|
||||
@@ -239,8 +239,7 @@ export class ApiKeysPage extends PureComponent<Props, any> {
|
||||
const { hasFetched, navModel, apiKeysCount } = this.props;
|
||||
|
||||
return (
|
||||
<Page title={getTitleFromNavModel(navModel)}>
|
||||
<Page.Header model={navModel} />
|
||||
<Page navModel={navModel}>
|
||||
<Page.Contents isLoading={!hasFetched}>
|
||||
{hasFetched && (
|
||||
apiKeysCount > 0 ? (
|
||||
|
||||
@@ -2,20 +2,17 @@
|
||||
|
||||
exports[`Render should render API keys table if there are any keys 1`] = `
|
||||
<Page
|
||||
title="Configuration: Api Keys"
|
||||
>
|
||||
<PageHeader
|
||||
model={
|
||||
Object {
|
||||
"main": Object {
|
||||
"text": "Configuration",
|
||||
},
|
||||
"node": Object {
|
||||
"text": "Api Keys",
|
||||
},
|
||||
}
|
||||
navModel={
|
||||
Object {
|
||||
"main": Object {
|
||||
"text": "Configuration",
|
||||
},
|
||||
"node": Object {
|
||||
"text": "Api Keys",
|
||||
},
|
||||
}
|
||||
/>
|
||||
}
|
||||
>
|
||||
<PageContents
|
||||
isLoading={true}
|
||||
/>
|
||||
@@ -24,20 +21,17 @@ exports[`Render should render API keys table if there are any keys 1`] = `
|
||||
|
||||
exports[`Render should render CTA if there are no API keys 1`] = `
|
||||
<Page
|
||||
title="Configuration: Api Keys"
|
||||
>
|
||||
<PageHeader
|
||||
model={
|
||||
Object {
|
||||
"main": Object {
|
||||
"text": "Configuration",
|
||||
},
|
||||
"node": Object {
|
||||
"text": "Api Keys",
|
||||
},
|
||||
}
|
||||
navModel={
|
||||
Object {
|
||||
"main": Object {
|
||||
"text": "Configuration",
|
||||
},
|
||||
"node": Object {
|
||||
"text": "Api Keys",
|
||||
},
|
||||
}
|
||||
/>
|
||||
}
|
||||
>
|
||||
<PageContents
|
||||
isLoading={false}
|
||||
>
|
||||
|
||||
@@ -8,7 +8,7 @@ import DataSourcesList from './DataSourcesList';
|
||||
import { DataSource, NavModel, StoreState } from 'app/types';
|
||||
import { LayoutMode } from 'app/core/components/LayoutSelector/LayoutSelector';
|
||||
import { loadDataSources, setDataSourcesLayoutMode, setDataSourcesSearchQuery } from './state/actions';
|
||||
import { getNavModel, getTitleFromNavModel } from 'app/core/selectors/navModel';
|
||||
import { getNavModel } from 'app/core/selectors/navModel';
|
||||
|
||||
import {
|
||||
getDataSources,
|
||||
@@ -67,8 +67,7 @@ export class DataSourcesListPage extends PureComponent<Props> {
|
||||
};
|
||||
|
||||
return (
|
||||
<Page title={getTitleFromNavModel(navModel)}>
|
||||
<Page.Header model={navModel} />
|
||||
<Page navModel={navModel}>
|
||||
<Page.Contents isLoading={!hasFetched}>
|
||||
<>
|
||||
{hasFetched && dataSourcesCount === 0 && <EmptyListCTA model={emptyListModel} />}
|
||||
|
||||
@@ -2,20 +2,17 @@
|
||||
|
||||
exports[`Render should render action bar and datasources 1`] = `
|
||||
<Page
|
||||
title="Configuration: Data Sources"
|
||||
>
|
||||
<PageHeader
|
||||
model={
|
||||
Object {
|
||||
"main": Object {
|
||||
"text": "Configuration",
|
||||
},
|
||||
"node": Object {
|
||||
"text": "Data Sources",
|
||||
},
|
||||
}
|
||||
navModel={
|
||||
Object {
|
||||
"main": Object {
|
||||
"text": "Configuration",
|
||||
},
|
||||
"node": Object {
|
||||
"text": "Data Sources",
|
||||
},
|
||||
}
|
||||
/>
|
||||
}
|
||||
>
|
||||
<PageContents
|
||||
isLoading={false}
|
||||
>
|
||||
@@ -160,20 +157,17 @@ exports[`Render should render action bar and datasources 1`] = `
|
||||
|
||||
exports[`Render should render component 1`] = `
|
||||
<Page
|
||||
title="Configuration: Data Sources"
|
||||
>
|
||||
<PageHeader
|
||||
model={
|
||||
Object {
|
||||
"main": Object {
|
||||
"text": "Configuration",
|
||||
},
|
||||
"node": Object {
|
||||
"text": "Data Sources",
|
||||
},
|
||||
}
|
||||
navModel={
|
||||
Object {
|
||||
"main": Object {
|
||||
"text": "Configuration",
|
||||
},
|
||||
"node": Object {
|
||||
"text": "Data Sources",
|
||||
},
|
||||
}
|
||||
/>
|
||||
}
|
||||
>
|
||||
<PageContents
|
||||
isLoading={true}
|
||||
/>
|
||||
|
||||
@@ -6,7 +6,7 @@ import OrgProfile from './OrgProfile';
|
||||
import SharedPreferences from 'app/core/components/SharedPreferences/SharedPreferences';
|
||||
import { loadOrganization, setOrganizationName, updateOrganization } from './state/actions';
|
||||
import { NavModel, Organization, StoreState } from 'app/types';
|
||||
import { getNavModel, getTitleFromNavModel } from 'app/core/selectors/navModel';
|
||||
import { getNavModel } from 'app/core/selectors/navModel';
|
||||
|
||||
export interface Props {
|
||||
navModel: NavModel;
|
||||
@@ -34,8 +34,7 @@ export class OrgDetailsPage extends PureComponent<Props> {
|
||||
const isLoading = Object.keys(organization).length === 0;
|
||||
|
||||
return (
|
||||
<Page title={getTitleFromNavModel(navModel)}>
|
||||
<Page.Header model={navModel} />
|
||||
<Page navModel={navModel}>
|
||||
<Page.Contents isLoading={isLoading}>
|
||||
<div className="page-container page-body">
|
||||
{!isLoading && (
|
||||
|
||||
@@ -2,20 +2,17 @@
|
||||
|
||||
exports[`Render should render component 1`] = `
|
||||
<Page
|
||||
title="Configuration: Org details"
|
||||
>
|
||||
<PageHeader
|
||||
model={
|
||||
Object {
|
||||
"main": Object {
|
||||
"text": "Configuration",
|
||||
},
|
||||
"node": Object {
|
||||
"text": "Org details",
|
||||
},
|
||||
}
|
||||
navModel={
|
||||
Object {
|
||||
"main": Object {
|
||||
"text": "Configuration",
|
||||
},
|
||||
"node": Object {
|
||||
"text": "Org details",
|
||||
},
|
||||
}
|
||||
/>
|
||||
}
|
||||
>
|
||||
<PageContents
|
||||
isLoading={true}
|
||||
>
|
||||
@@ -28,20 +25,17 @@ exports[`Render should render component 1`] = `
|
||||
|
||||
exports[`Render should render organization and preferences 1`] = `
|
||||
<Page
|
||||
title="Configuration: Org details"
|
||||
>
|
||||
<PageHeader
|
||||
model={
|
||||
Object {
|
||||
"main": Object {
|
||||
"text": "Configuration",
|
||||
},
|
||||
"node": Object {
|
||||
"text": "Org details",
|
||||
},
|
||||
}
|
||||
navModel={
|
||||
Object {
|
||||
"main": Object {
|
||||
"text": "Configuration",
|
||||
},
|
||||
"node": Object {
|
||||
"text": "Org details",
|
||||
},
|
||||
}
|
||||
/>
|
||||
}
|
||||
>
|
||||
<PageContents
|
||||
isLoading={false}
|
||||
>
|
||||
|
||||
@@ -6,7 +6,7 @@ import OrgActionBar from 'app/core/components/OrgActionBar/OrgActionBar';
|
||||
import PluginList from './PluginList';
|
||||
import { NavModel, Plugin } from 'app/types';
|
||||
import { loadPlugins, setPluginsLayoutMode, setPluginsSearchQuery } from './state/actions';
|
||||
import { getNavModel, getTitleFromNavModel } from 'app/core/selectors/navModel';
|
||||
import { getNavModel } from 'app/core/selectors/navModel';
|
||||
import { getLayoutMode, getPlugins, getPluginsSearchQuery } from './state/selectors';
|
||||
import { LayoutMode } from 'app/core/components/LayoutSelector/LayoutSelector';
|
||||
|
||||
@@ -47,8 +47,7 @@ export class PluginListPage extends PureComponent<Props> {
|
||||
};
|
||||
|
||||
return (
|
||||
<Page title={getTitleFromNavModel(navModel)}>
|
||||
<Page.Header model={navModel} />
|
||||
<Page navModel={navModel}>
|
||||
<Page.Contents isLoading={!hasFetched}>
|
||||
<>
|
||||
<OrgActionBar
|
||||
|
||||
@@ -2,20 +2,17 @@
|
||||
|
||||
exports[`Render should render component 1`] = `
|
||||
<Page
|
||||
title="Configuration: Plugins"
|
||||
>
|
||||
<PageHeader
|
||||
model={
|
||||
Object {
|
||||
"main": Object {
|
||||
"text": "Configuration",
|
||||
},
|
||||
"node": Object {
|
||||
"text": "Plugins",
|
||||
},
|
||||
}
|
||||
navModel={
|
||||
Object {
|
||||
"main": Object {
|
||||
"text": "Configuration",
|
||||
},
|
||||
"node": Object {
|
||||
"text": "Plugins",
|
||||
},
|
||||
}
|
||||
/>
|
||||
}
|
||||
>
|
||||
<PageContents
|
||||
isLoading={true}
|
||||
>
|
||||
@@ -37,20 +34,17 @@ exports[`Render should render component 1`] = `
|
||||
|
||||
exports[`Render should render list 1`] = `
|
||||
<Page
|
||||
title="Configuration: Plugins"
|
||||
>
|
||||
<PageHeader
|
||||
model={
|
||||
Object {
|
||||
"main": Object {
|
||||
"text": "Configuration",
|
||||
},
|
||||
"node": Object {
|
||||
"text": "Plugins",
|
||||
},
|
||||
}
|
||||
navModel={
|
||||
Object {
|
||||
"main": Object {
|
||||
"text": "Configuration",
|
||||
},
|
||||
"node": Object {
|
||||
"text": "Plugins",
|
||||
},
|
||||
}
|
||||
/>
|
||||
}
|
||||
>
|
||||
<PageContents
|
||||
isLoading={false}
|
||||
>
|
||||
|
||||
@@ -7,7 +7,7 @@ import EmptyListCTA from 'app/core/components/EmptyListCTA/EmptyListCTA';
|
||||
import { NavModel, Team } from 'app/types';
|
||||
import { loadTeams, deleteTeam, setSearchQuery } from './state/actions';
|
||||
import { getSearchQuery, getTeams, getTeamsCount } from './state/selectors';
|
||||
import { getNavModel, getTitleFromNavModel } from 'app/core/selectors/navModel';
|
||||
import { getNavModel } from 'app/core/selectors/navModel';
|
||||
|
||||
export interface Props {
|
||||
navModel: NavModel;
|
||||
@@ -140,8 +140,7 @@ export class TeamList extends PureComponent<Props, any> {
|
||||
const { hasFetched, navModel } = this.props;
|
||||
|
||||
return (
|
||||
<Page title={getTitleFromNavModel(navModel)}>
|
||||
<Page.Header model={navModel} />
|
||||
<Page navModel={navModel}>
|
||||
<Page.Contents isLoading={!hasFetched}>
|
||||
{hasFetched && this.renderList()}
|
||||
</Page.Contents>
|
||||
|
||||
@@ -2,20 +2,17 @@
|
||||
|
||||
exports[`Render should render component 1`] = `
|
||||
<Page
|
||||
title="Configuration: Team List"
|
||||
>
|
||||
<PageHeader
|
||||
model={
|
||||
Object {
|
||||
"main": Object {
|
||||
"text": "Configuration",
|
||||
},
|
||||
"node": Object {
|
||||
"text": "Team List",
|
||||
},
|
||||
}
|
||||
navModel={
|
||||
Object {
|
||||
"main": Object {
|
||||
"text": "Configuration",
|
||||
},
|
||||
"node": Object {
|
||||
"text": "Team List",
|
||||
},
|
||||
}
|
||||
/>
|
||||
}
|
||||
>
|
||||
<PageContents
|
||||
isLoading={true}
|
||||
/>
|
||||
@@ -24,20 +21,17 @@ exports[`Render should render component 1`] = `
|
||||
|
||||
exports[`Render should render teams table 1`] = `
|
||||
<Page
|
||||
title="Configuration: Team List"
|
||||
>
|
||||
<PageHeader
|
||||
model={
|
||||
Object {
|
||||
"main": Object {
|
||||
"text": "Configuration",
|
||||
},
|
||||
"node": Object {
|
||||
"text": "Team List",
|
||||
},
|
||||
}
|
||||
navModel={
|
||||
Object {
|
||||
"main": Object {
|
||||
"text": "Configuration",
|
||||
},
|
||||
"node": Object {
|
||||
"text": "Team List",
|
||||
},
|
||||
}
|
||||
/>
|
||||
}
|
||||
>
|
||||
<PageContents
|
||||
isLoading={false}
|
||||
>
|
||||
|
||||
@@ -9,7 +9,7 @@ import InviteesTable from './InviteesTable';
|
||||
import { Invitee, NavModel, OrgUser } from 'app/types';
|
||||
import appEvents from 'app/core/app_events';
|
||||
import { loadUsers, loadInvitees, setUsersSearchQuery, updateUser, removeUser } from './state/actions';
|
||||
import { getNavModel, getTitleFromNavModel } from 'app/core/selectors/navModel';
|
||||
import { getNavModel } from 'app/core/selectors/navModel';
|
||||
import { getInvitees, getUsers, getUsersSearchQuery } from './state/selectors';
|
||||
|
||||
export interface Props {
|
||||
@@ -104,8 +104,7 @@ export class UsersListPage extends PureComponent<Props, State> {
|
||||
const externalUserMngInfoHtml = this.externalUserMngInfoHtml;
|
||||
|
||||
return (
|
||||
<Page title={getTitleFromNavModel(navModel)}>
|
||||
<Page.Header model={navModel} />
|
||||
<Page navModel={navModel}>
|
||||
<Page.Contents isLoading={!hasFetched}>
|
||||
<>
|
||||
<UsersActionBar onShowInvites={this.onShowInvites} showInvites={this.state.showInvites} />
|
||||
|
||||
@@ -2,20 +2,17 @@
|
||||
|
||||
exports[`Render should render List page 1`] = `
|
||||
<Page
|
||||
title="Configuration: Users"
|
||||
>
|
||||
<PageHeader
|
||||
model={
|
||||
Object {
|
||||
"main": Object {
|
||||
"text": "Configuration",
|
||||
},
|
||||
"node": Object {
|
||||
"text": "Users",
|
||||
},
|
||||
}
|
||||
navModel={
|
||||
Object {
|
||||
"main": Object {
|
||||
"text": "Configuration",
|
||||
},
|
||||
"node": Object {
|
||||
"text": "Users",
|
||||
},
|
||||
}
|
||||
/>
|
||||
}
|
||||
>
|
||||
<PageContents
|
||||
isLoading={false}
|
||||
>
|
||||
@@ -34,20 +31,17 @@ exports[`Render should render List page 1`] = `
|
||||
|
||||
exports[`Render should render component 1`] = `
|
||||
<Page
|
||||
title="Configuration: Users"
|
||||
>
|
||||
<PageHeader
|
||||
model={
|
||||
Object {
|
||||
"main": Object {
|
||||
"text": "Configuration",
|
||||
},
|
||||
"node": Object {
|
||||
"text": "Users",
|
||||
},
|
||||
}
|
||||
navModel={
|
||||
Object {
|
||||
"main": Object {
|
||||
"text": "Configuration",
|
||||
},
|
||||
"node": Object {
|
||||
"text": "Users",
|
||||
},
|
||||
}
|
||||
/>
|
||||
}
|
||||
>
|
||||
<PageContents
|
||||
isLoading={true}
|
||||
>
|
||||
|
||||
Reference in New Issue
Block a user