Add relevant document titles to Infrastructure pages (#31136)
Add a DocumentTitle component Add DocumentTitle component to Nodes Overview / Metrics / Logs pages Stylistic / defensive changes Add I18n support
This commit is contained in:
parent
2b78c65d36
commit
036524f182
68
x-pack/plugins/infra/public/components/document_title.tsx
Normal file
68
x-pack/plugins/infra/public/components/document_title.tsx
Normal file
|
@ -0,0 +1,68 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License;
|
||||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
|
||||
import React from 'react';
|
||||
|
||||
type titleProp = string | ((previousTitle: string) => string);
|
||||
|
||||
interface DocumentTitleProps {
|
||||
title: titleProp;
|
||||
}
|
||||
|
||||
interface DocumentTitleState {
|
||||
index: number;
|
||||
}
|
||||
|
||||
const wrapWithSharedState = () => {
|
||||
const titles: string[] = [];
|
||||
const TITLE_SUFFIX = ' - Kibana';
|
||||
|
||||
return class extends React.Component<DocumentTitleProps, DocumentTitleState> {
|
||||
public readonly state = {
|
||||
index: titles.push('') - 1,
|
||||
};
|
||||
|
||||
public componentDidMount() {
|
||||
this.pushTitle(this.getTitle(this.props.title));
|
||||
this.updateDocumentTitle();
|
||||
}
|
||||
|
||||
public componentDidUpdate() {
|
||||
this.pushTitle(this.getTitle(this.props.title));
|
||||
this.updateDocumentTitle();
|
||||
}
|
||||
|
||||
public componentWillUnmount() {
|
||||
this.removeTitle();
|
||||
this.updateDocumentTitle();
|
||||
}
|
||||
|
||||
public render() {
|
||||
return null;
|
||||
}
|
||||
|
||||
private getTitle(title: titleProp) {
|
||||
return typeof title === 'function' ? title(titles[this.state.index - 1]) : title;
|
||||
}
|
||||
|
||||
private pushTitle(title: string) {
|
||||
titles[this.state.index] = title;
|
||||
}
|
||||
|
||||
private removeTitle() {
|
||||
titles.splice(this.state.index, 1);
|
||||
}
|
||||
|
||||
private updateDocumentTitle() {
|
||||
const title = (titles[titles.length - 1] || '') + TITLE_SUFFIX;
|
||||
if (title !== document.title) {
|
||||
document.title = title;
|
||||
}
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
export const DocumentTitle = wrapWithSharedState();
|
|
@ -11,6 +11,7 @@ import React from 'react';
|
|||
import { HomePageContent } from './page_content';
|
||||
import { HomeToolbar } from './toolbar';
|
||||
|
||||
import { DocumentTitle } from '../../components/document_title';
|
||||
import { NoIndices } from '../../components/empty_states/no_indices';
|
||||
import { Header } from '../../components/header';
|
||||
import { ColumnarPage } from '../../components/page';
|
||||
|
@ -36,6 +37,12 @@ export const HomePage = injectI18n(
|
|||
|
||||
return (
|
||||
<ColumnarPage>
|
||||
<DocumentTitle
|
||||
title={intl.formatMessage({
|
||||
id: 'xpack.infra.homePage.documentTitle',
|
||||
defaultMessage: 'Infrastructure',
|
||||
})}
|
||||
/>
|
||||
<Header
|
||||
breadcrumbs={[
|
||||
{
|
||||
|
|
|
@ -11,7 +11,9 @@ import React from 'react';
|
|||
import { LogsPageContent } from './page_content';
|
||||
import { LogsToolbar } from './toolbar';
|
||||
|
||||
import { DocumentTitle } from '../../components/document_title';
|
||||
import { NoIndices } from '../../components/empty_states/no_indices';
|
||||
|
||||
import { Header } from '../../components/header';
|
||||
import { LogFlyout } from '../../components/logging/log_flyout';
|
||||
import { ColumnarPage } from '../../components/page';
|
||||
|
@ -62,6 +64,12 @@ export const LogsPage = injectI18n(
|
|||
sourceId,
|
||||
}) => (
|
||||
<>
|
||||
<DocumentTitle
|
||||
title={intl.formatMessage({
|
||||
id: 'xpack.infra.logsPage.documentTitle',
|
||||
defaultMessage: 'Logs',
|
||||
})}
|
||||
/>
|
||||
<SourceConfigurationFlyout />
|
||||
{isLoading ? (
|
||||
<SourceLoadingPage />
|
||||
|
|
|
@ -20,6 +20,7 @@ import styled, { withTheme } from 'styled-components';
|
|||
|
||||
import { InfraMetricsErrorCodes } from '../../../common/errors';
|
||||
import { AutoSizer } from '../../components/auto_sizer';
|
||||
import { DocumentTitle } from '../../components/document_title';
|
||||
import { Header } from '../../components/header';
|
||||
import { Metrics } from '../../components/metrics';
|
||||
import { InvalidNodeError } from '../../components/metrics/invalid_node';
|
||||
|
@ -119,6 +120,17 @@ export const MetricDetail = withTheme(
|
|||
<Header breadcrumbs={breadcrumbs} />
|
||||
<SourceConfigurationFlyout />
|
||||
<WithMetricsTimeUrlState />
|
||||
<DocumentTitle
|
||||
title={intl.formatMessage(
|
||||
{
|
||||
id: 'xpack.infra.metricDetailPage.documentTitle',
|
||||
defaultMessage: 'Infrastructure | Metrics | {name}',
|
||||
},
|
||||
{
|
||||
name,
|
||||
}
|
||||
)}
|
||||
/>
|
||||
<DetailPageContent>
|
||||
<WithMetrics
|
||||
layouts={filteredLayouts}
|
||||
|
@ -134,11 +146,28 @@ export const MetricDetail = withTheme(
|
|||
err.code === InfraMetricsErrorCodes.invalid_node
|
||||
);
|
||||
|
||||
if (invalidNodeError) {
|
||||
return <InvalidNodeError nodeName={name} />;
|
||||
}
|
||||
|
||||
return <ErrorPageBody message={error.message} />;
|
||||
return (
|
||||
<>
|
||||
<DocumentTitle
|
||||
title={(previousTitle: string) =>
|
||||
intl.formatMessage(
|
||||
{
|
||||
id: 'xpack.infra.metricDetailPage.documentTitleError',
|
||||
defaultMessage: '{previousTitle} | Uh oh',
|
||||
},
|
||||
{
|
||||
previousTitle,
|
||||
}
|
||||
)
|
||||
}
|
||||
/>
|
||||
{invalidNodeError ? (
|
||||
<InvalidNodeError nodeName={name} />
|
||||
) : (
|
||||
<ErrorPageBody message={error.message} />
|
||||
)}
|
||||
</>
|
||||
);
|
||||
}
|
||||
return (
|
||||
<EuiPage style={{ flex: '1 0 auto' }}>
|
||||
|
|
Loading…
Reference in a new issue