mirror of
https://github.com/elastic/kibana.git
synced 2025-04-25 02:09:32 -04:00
[i18n] Translate ML - annotations table (#28079)
* Translate annotations table * Fix test * Update snapshot * Fix id names
This commit is contained in:
parent
90bf43d958
commit
f05e8b6bd0
4 changed files with 111 additions and 33 deletions
|
@ -121,6 +121,12 @@ exports[`AnnotationsTable Minimal initialization without props. 1`] = `
|
||||||
color="primary"
|
color="primary"
|
||||||
iconType="iInCircle"
|
iconType="iInCircle"
|
||||||
size="m"
|
size="m"
|
||||||
title="No annotations created for this job"
|
title={
|
||||||
|
<FormattedMessage
|
||||||
|
defaultMessage="No annotations created for this job"
|
||||||
|
id="xpack.ml.annotationsTable.annotationsNotCreatedTitle"
|
||||||
|
values={Object {}}
|
||||||
|
/>
|
||||||
|
}
|
||||||
/>
|
/>
|
||||||
`;
|
`;
|
||||||
|
|
|
@ -44,13 +44,22 @@ import { mlTableService } from '../../services/table_service';
|
||||||
import { ANNOTATIONS_TABLE_DEFAULT_QUERY_SIZE } from '../../../common/constants/search';
|
import { ANNOTATIONS_TABLE_DEFAULT_QUERY_SIZE } from '../../../common/constants/search';
|
||||||
import { isTimeSeriesViewJob } from '../../../common/util/job_utils';
|
import { isTimeSeriesViewJob } from '../../../common/util/job_utils';
|
||||||
|
|
||||||
|
import { FormattedMessage, injectI18n } from '@kbn/i18n/react';
|
||||||
|
|
||||||
|
|
||||||
const TIME_FORMAT = 'YYYY-MM-DD HH:mm:ss';
|
const TIME_FORMAT = 'YYYY-MM-DD HH:mm:ss';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Table component for rendering the lists of annotations for an ML job.
|
* Table component for rendering the lists of annotations for an ML job.
|
||||||
*/
|
*/
|
||||||
class AnnotationsTable extends Component {
|
const AnnotationsTable = injectI18n(class AnnotationsTable extends Component {
|
||||||
|
static propTypes = {
|
||||||
|
annotations: PropTypes.array,
|
||||||
|
jobs: PropTypes.array,
|
||||||
|
isSingleMetricViewerLinkVisible: PropTypes.bool,
|
||||||
|
isNumberBadgeVisible: PropTypes.bool
|
||||||
|
};
|
||||||
|
|
||||||
constructor(props) {
|
constructor(props) {
|
||||||
super(props);
|
super(props);
|
||||||
this.state = {
|
this.state = {
|
||||||
|
@ -214,7 +223,8 @@ class AnnotationsTable extends Component {
|
||||||
render() {
|
render() {
|
||||||
const {
|
const {
|
||||||
isSingleMetricViewerLinkVisible = true,
|
isSingleMetricViewerLinkVisible = true,
|
||||||
isNumberBadgeVisible = false
|
isNumberBadgeVisible = false,
|
||||||
|
intl
|
||||||
} = this.props;
|
} = this.props;
|
||||||
|
|
||||||
if (this.props.annotations === undefined) {
|
if (this.props.annotations === undefined) {
|
||||||
|
@ -242,13 +252,28 @@ class AnnotationsTable extends Component {
|
||||||
if (annotations.length === 0) {
|
if (annotations.length === 0) {
|
||||||
return (
|
return (
|
||||||
<EuiCallOut
|
<EuiCallOut
|
||||||
title="No annotations created for this job"
|
title={<FormattedMessage
|
||||||
|
id="xpack.ml.annotationsTable.annotationsNotCreatedTitle"
|
||||||
|
defaultMessage="No annotations created for this job"
|
||||||
|
/>}
|
||||||
iconType="iInCircle"
|
iconType="iInCircle"
|
||||||
>
|
>
|
||||||
{this.state.jobId && isTimeSeriesViewJob(this.getJob(this.state.jobId)) &&
|
{this.state.jobId && isTimeSeriesViewJob(this.getJob(this.state.jobId)) &&
|
||||||
<p>
|
<p>
|
||||||
To create an annotation,
|
<FormattedMessage
|
||||||
open the <EuiLink onClick={() => this.openSingleMetricView()}>Single Metric Viewer</EuiLink>
|
id="xpack.ml.annotationsTable.howToCreateAnnotationDescription"
|
||||||
|
defaultMessage="To create an annotation, open the {linkToSingleMetricView}"
|
||||||
|
values={{
|
||||||
|
linkToSingleMetricView: (
|
||||||
|
<EuiLink onClick={() => this.openSingleMetricView()}>
|
||||||
|
<FormattedMessage
|
||||||
|
id="xpack.ml.annotationsTable.howToCreateAnnotationDescription.singleMetricViewerLinkText"
|
||||||
|
defaultMessage="Single Metric Viewer"
|
||||||
|
/>
|
||||||
|
</EuiLink>
|
||||||
|
)
|
||||||
|
}}
|
||||||
|
/>
|
||||||
</p>
|
</p>
|
||||||
}
|
}
|
||||||
</EuiCallOut>
|
</EuiCallOut>
|
||||||
|
@ -260,45 +285,66 @@ class AnnotationsTable extends Component {
|
||||||
const columns = [
|
const columns = [
|
||||||
{
|
{
|
||||||
field: 'annotation',
|
field: 'annotation',
|
||||||
name: 'Annotation',
|
name: intl.formatMessage({
|
||||||
|
id: 'xpack.ml.annotationsTable.annotationColumnName',
|
||||||
|
defaultMessage: 'Annotation',
|
||||||
|
}),
|
||||||
sortable: true
|
sortable: true
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
field: 'timestamp',
|
field: 'timestamp',
|
||||||
name: 'From',
|
name: intl.formatMessage({
|
||||||
|
id: 'xpack.ml.annotationsTable.fromColumnName',
|
||||||
|
defaultMessage: 'From',
|
||||||
|
}),
|
||||||
dataType: 'date',
|
dataType: 'date',
|
||||||
render: renderDate,
|
render: renderDate,
|
||||||
sortable: true,
|
sortable: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
field: 'end_timestamp',
|
field: 'end_timestamp',
|
||||||
name: 'To',
|
name: intl.formatMessage({
|
||||||
|
id: 'xpack.ml.annotationsTable.toColumnName',
|
||||||
|
defaultMessage: 'To',
|
||||||
|
}),
|
||||||
dataType: 'date',
|
dataType: 'date',
|
||||||
render: renderDate,
|
render: renderDate,
|
||||||
sortable: true,
|
sortable: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
field: 'create_time',
|
field: 'create_time',
|
||||||
name: 'Creation date',
|
name: intl.formatMessage({
|
||||||
|
id: 'xpack.ml.annotationsTable.creationDateColumnName',
|
||||||
|
defaultMessage: 'Creation date',
|
||||||
|
}),
|
||||||
dataType: 'date',
|
dataType: 'date',
|
||||||
render: renderDate,
|
render: renderDate,
|
||||||
sortable: true,
|
sortable: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
field: 'create_username',
|
field: 'create_username',
|
||||||
name: 'Created by',
|
name: intl.formatMessage({
|
||||||
|
id: 'xpack.ml.annotationsTable.createdByColumnName',
|
||||||
|
defaultMessage: 'Created by',
|
||||||
|
}),
|
||||||
sortable: true,
|
sortable: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
field: 'modified_time',
|
field: 'modified_time',
|
||||||
name: 'Last modified date',
|
name: intl.formatMessage({
|
||||||
|
id: 'xpack.ml.annotationsTable.lastModifiedDateColumnName',
|
||||||
|
defaultMessage: 'Last modified date',
|
||||||
|
}),
|
||||||
dataType: 'date',
|
dataType: 'date',
|
||||||
render: renderDate,
|
render: renderDate,
|
||||||
sortable: true,
|
sortable: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
field: 'modified_username',
|
field: 'modified_username',
|
||||||
name: 'Last modified by',
|
name: intl.formatMessage({
|
||||||
|
id: 'xpack.ml.annotationsTable.lastModifiedByColumnName',
|
||||||
|
defaultMessage: 'Last modified by',
|
||||||
|
}),
|
||||||
sortable: true,
|
sortable: true,
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
@ -307,7 +353,10 @@ class AnnotationsTable extends Component {
|
||||||
if (jobIds.length > 1) {
|
if (jobIds.length > 1) {
|
||||||
columns.unshift({
|
columns.unshift({
|
||||||
field: 'job_id',
|
field: 'job_id',
|
||||||
name: 'job ID',
|
name: intl.formatMessage({
|
||||||
|
id: 'xpack.ml.annotationsTable.jobIdColumnName',
|
||||||
|
defaultMessage: 'job ID',
|
||||||
|
}),
|
||||||
sortable: true,
|
sortable: true,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -315,7 +364,10 @@ class AnnotationsTable extends Component {
|
||||||
if (isNumberBadgeVisible) {
|
if (isNumberBadgeVisible) {
|
||||||
columns.unshift({
|
columns.unshift({
|
||||||
field: 'key',
|
field: 'key',
|
||||||
name: 'Label',
|
name: intl.formatMessage({
|
||||||
|
id: 'xpack.ml.annotationsTable.labelColumnName',
|
||||||
|
defaultMessage: 'Label',
|
||||||
|
}),
|
||||||
sortable: true,
|
sortable: true,
|
||||||
width: '60px',
|
width: '60px',
|
||||||
render: (key) => {
|
render: (key) => {
|
||||||
|
@ -332,23 +384,45 @@ class AnnotationsTable extends Component {
|
||||||
columns.push({
|
columns.push({
|
||||||
align: RIGHT_ALIGNMENT,
|
align: RIGHT_ALIGNMENT,
|
||||||
width: '60px',
|
width: '60px',
|
||||||
name: 'View',
|
name: intl.formatMessage({
|
||||||
|
id: 'xpack.ml.annotationsTable.viewColumnName',
|
||||||
|
defaultMessage: 'View',
|
||||||
|
}),
|
||||||
render: (annotation) => {
|
render: (annotation) => {
|
||||||
const isDrillDownAvailable = isTimeSeriesViewJob(this.getJob(annotation.job_id));
|
const isDrillDownAvailable = isTimeSeriesViewJob(this.getJob(annotation.job_id));
|
||||||
const openInSingleMetricViewerText = isDrillDownAvailable
|
const openInSingleMetricViewerTooltipText = isDrillDownAvailable ? (
|
||||||
? 'Open in Single Metric Viewer'
|
<FormattedMessage
|
||||||
: 'Job configuration not supported in Single Metric Viewer';
|
id="xpack.ml.annotationsTable.openInSingleMetricViewerTooltip"
|
||||||
|
defaultMessage="Open in Single Metric Viewer"
|
||||||
|
/>
|
||||||
|
) : (
|
||||||
|
<FormattedMessage
|
||||||
|
id="xpack.ml.annotationsTable.jobConfigurationNotSupportedInSingleMetricViewerTooltip"
|
||||||
|
defaultMessage="Job configuration not supported in Single Metric Viewer"
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
const openInSingleMetricViewerAriaLabelText = isDrillDownAvailable ? (
|
||||||
|
<FormattedMessage
|
||||||
|
id="xpack.ml.annotationsTable.openInSingleMetricViewerAriaLabel"
|
||||||
|
defaultMessage="Open in Single Metric Viewer"
|
||||||
|
/>
|
||||||
|
) : (
|
||||||
|
<FormattedMessage
|
||||||
|
id="xpack.ml.annotationsTable.jobConfigurationNotSupportedInSingleMetricViewerAriaLabel"
|
||||||
|
defaultMessage="Job configuration not supported in Single Metric Viewer"
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<EuiToolTip
|
<EuiToolTip
|
||||||
position="bottom"
|
position="bottom"
|
||||||
content={openInSingleMetricViewerText}
|
content={openInSingleMetricViewerTooltipText}
|
||||||
>
|
>
|
||||||
<EuiButtonIcon
|
<EuiButtonIcon
|
||||||
onClick={() => this.openSingleMetricView(annotation)}
|
onClick={() => this.openSingleMetricView(annotation)}
|
||||||
disabled={!isDrillDownAvailable}
|
disabled={!isDrillDownAvailable}
|
||||||
iconType="stats"
|
iconType="stats"
|
||||||
aria-label={openInSingleMetricViewerText}
|
aria-label={openInSingleMetricViewerAriaLabelText}
|
||||||
/>
|
/>
|
||||||
</EuiToolTip>
|
</EuiToolTip>
|
||||||
);
|
);
|
||||||
|
@ -381,12 +455,6 @@ class AnnotationsTable extends Component {
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
});
|
||||||
AnnotationsTable.propTypes = {
|
|
||||||
annotations: PropTypes.array,
|
|
||||||
jobs: PropTypes.array,
|
|
||||||
isSingleMetricViewerLinkVisible: PropTypes.bool,
|
|
||||||
isNumberBadgeVisible: PropTypes.bool
|
|
||||||
};
|
|
||||||
|
|
||||||
export { AnnotationsTable };
|
export { AnnotationsTable };
|
||||||
|
|
|
@ -7,7 +7,7 @@
|
||||||
import jobConfig from '../../../common/types/__mocks__/job_config_farequote';
|
import jobConfig from '../../../common/types/__mocks__/job_config_farequote';
|
||||||
import mockAnnotations from './__mocks__/mock_annotations.json';
|
import mockAnnotations from './__mocks__/mock_annotations.json';
|
||||||
|
|
||||||
import { shallow } from 'enzyme';
|
import { shallowWithIntl } from 'test_utils/enzyme_helpers';
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
|
|
||||||
import { AnnotationsTable } from './annotations_table';
|
import { AnnotationsTable } from './annotations_table';
|
||||||
|
@ -33,17 +33,17 @@ jest.mock('../../services/ml_api_service', () => ({
|
||||||
|
|
||||||
describe('AnnotationsTable', () => {
|
describe('AnnotationsTable', () => {
|
||||||
test('Minimal initialization without props.', () => {
|
test('Minimal initialization without props.', () => {
|
||||||
const wrapper = shallow(<AnnotationsTable />);
|
const wrapper = shallowWithIntl(<AnnotationsTable.WrappedComponent />);
|
||||||
expect(wrapper).toMatchSnapshot();
|
expect(wrapper).toMatchSnapshot();
|
||||||
});
|
});
|
||||||
|
|
||||||
test('Initialization with job config prop.', () => {
|
test('Initialization with job config prop.', () => {
|
||||||
const wrapper = shallow(<AnnotationsTable jobs={[jobConfig]} />);
|
const wrapper = shallowWithIntl(<AnnotationsTable.WrappedComponent jobs={[jobConfig]} />);
|
||||||
expect(wrapper).toMatchSnapshot();
|
expect(wrapper).toMatchSnapshot();
|
||||||
});
|
});
|
||||||
|
|
||||||
test('Initialization with annotations prop.', () => {
|
test('Initialization with annotations prop.', () => {
|
||||||
const wrapper = shallow(<AnnotationsTable annotations={mockAnnotations} />);
|
const wrapper = shallowWithIntl(<AnnotationsTable.WrappedComponent annotations={mockAnnotations} />);
|
||||||
expect(wrapper).toMatchSnapshot();
|
expect(wrapper).toMatchSnapshot();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -23,6 +23,8 @@ const module = uiModules.get('apps/ml');
|
||||||
import chrome from 'ui/chrome';
|
import chrome from 'ui/chrome';
|
||||||
const mlAnnotationsEnabled = chrome.getInjected('mlAnnotationsEnabled', false);
|
const mlAnnotationsEnabled = chrome.getInjected('mlAnnotationsEnabled', false);
|
||||||
|
|
||||||
|
import { I18nProvider } from '@kbn/i18n/react';
|
||||||
|
|
||||||
module.directive('mlAnnotationTable', function () {
|
module.directive('mlAnnotationTable', function () {
|
||||||
|
|
||||||
function link(scope, element) {
|
function link(scope, element) {
|
||||||
|
@ -39,7 +41,9 @@ module.directive('mlAnnotationTable', function () {
|
||||||
};
|
};
|
||||||
|
|
||||||
ReactDOM.render(
|
ReactDOM.render(
|
||||||
React.createElement(AnnotationsTable, props),
|
<I18nProvider>
|
||||||
|
{React.createElement(AnnotationsTable, props)}
|
||||||
|
</I18nProvider>,
|
||||||
element[0]
|
element[0]
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue