Translations for Management -> Objects (#23905) (#24280)

* fix tests and update snapshots

* fix id names

* fix test and update snapshots

* Update unit test snapshots

* fix issues

* Update snapshots

* Fix issues
This commit is contained in:
Maryia Lapata 2018-10-19 22:45:38 +03:00 committed by GitHub
parent cf149f9d60
commit cd81a9e9d8
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
20 changed files with 769 additions and 273 deletions

View file

@ -4,6 +4,7 @@
"inputControl":"src/core_plugins/input_control_vis",
"kbn": "src/core_plugins/kibana",
"kbnVislibVisTypes": "src/core_plugins/kbn_vislib_vis_types",
"kbn.management.objects": "src/core_plugins/kibana/public/management",
"markdownVis": "src/core_plugins/markdown_vis",
"metricVis": "src/core_plugins/metric_vis",
"statusPage": "src/core_plugins/status_page",

View file

@ -28,6 +28,7 @@ import React from 'react';
import { render, unmountComponentAtNode } from 'react-dom';
import { ObjectsTable } from './components/objects_table';
import { getInAppUrl } from './lib/get_in_app_url';
import { I18nProvider } from '@kbn/i18n/react';
const REACT_OBJECTS_TABLE_DOM_ELEMENT_ID = 'reactSavedObjectsTable';
@ -52,31 +53,33 @@ function updateObjectsTable($scope, $injector) {
}
render(
<ObjectsTable
savedObjectsClient={savedObjectsClient}
services={services}
indexPatterns={indexPatterns}
$http={$http}
perPageConfig={config.get('savedObjects:perPage')}
basePath={chrome.getBasePath()}
newIndexPatternUrl={kbnUrl.eval('#/management/kibana/index')}
getEditUrl={(id, type) => {
if (type === 'index-pattern' || type === 'indexPatterns') {
return kbnUrl.eval(`#/management/kibana/indices/${id}`);
}
const serviceName = typeToServiceName(type);
if (!serviceName) {
toastNotifications.addWarning(`Unknown saved object type: ${type}`);
return null;
}
<I18nProvider>
<ObjectsTable
savedObjectsClient={savedObjectsClient}
services={services}
indexPatterns={indexPatterns}
$http={$http}
perPageConfig={config.get('savedObjects:perPage')}
basePath={chrome.getBasePath()}
newIndexPatternUrl={kbnUrl.eval('#/management/kibana/index')}
getEditUrl={(id, type) => {
if (type === 'index-pattern' || type === 'indexPatterns') {
return kbnUrl.eval(`#/management/kibana/indices/${id}`);
}
const serviceName = typeToServiceName(type);
if (!serviceName) {
toastNotifications.addWarning(`Unknown saved object type: ${type}`);
return null;
}
return kbnUrl.eval(`#/management/kibana/objects/${serviceName}/${id}`);
}}
goInApp={(id, type) => {
kbnUrl.change(getInAppUrl(id, type));
$scope.$apply();
}}
/>,
return kbnUrl.eval(`#/management/kibana/objects/${serviceName}/${id}`);
}}
goInApp={(id, type) => {
kbnUrl.change(getInAppUrl(id, type));
$scope.$apply();
}}
/>
</I18nProvider>,
node,
);
});

View file

@ -3,9 +3,12 @@
<!-- Header -->
<div class="kuiViewContentItem kuiBar kuiVerticalRhythm">
<div class="kuiBarSection">
<h1 class="kuiTitle">
Edit {{ title }}
</h1>
<h1
class="kuiTitle"
i18n-id="kbn.management.objects.view.editItemTitle"
i18n-default-message="Edit {title}"
i18n-values="{ title }"
></h1>
</div>
<div class="kuiBarSection">
@ -15,7 +18,11 @@
>
<span class="kuiButton__inner">
<span class="kuiButton__icon kuiIcon fa-eye"></span>
<span>View {{ title }}</span>
<span
i18n-id="kbn.management.objects.view.viewItemButtonLabel"
i18n-default-message="View {title}"
i18n-values="{ title }"
></span>
</span>
</a>
@ -25,7 +32,11 @@
>
<span class="kuiButton__inner">
<span class="kuiButton__icon kuiIcon fa-trash-o"></span>
<span>Delete {{ title }}</span>
<span
i18n-id="kbn.management.objects.view.deleteItemButtonLabel"
i18n-default-message="Delete {title}"
i18n-values="{ title }"
></span>
</span>
</button>
</div>
@ -39,36 +50,40 @@
<div class="kuiInfoPanel kuiInfoPanel--error">
<div class="kuiInfoPanelHeader">
<span class="kuiInfoPanelHeader__icon kuiIcon kuiIcon--error fa-warning"></span>
<span class="kuiInfoPanelHeader__title">
There is a problem with this saved object
</span>
<span
class="kuiInfoPanelHeader__title"
i18n-id="kbn.management.objects.view.savedObjectProblemErrorMessage"
i18n-default-message="There is a problem with this saved object"
></span>
</div>
<div class="kuiInfoPanelBody">
<div
class="kuiInfoPanelBody__message"
ng-if="notFound === 'search'"
>
The saved search associated with this object no longer exists.
</div>
i18n-id="kbn.management.objects.view.savedSearchDoesNotExistErrorMessage"
i18n-default-message="The saved search associated with this object no longer exists."
></div>
<div
class="kuiInfoPanelBody__message"
ng-if="notFound === 'index-pattern'"
>
The index pattern associated with this object no longer exists.
</div>
i18n-id="kbn.management.objects.view.indexPatternDoesNotExistErrorMessage"
i18n-default-message="The index pattern associated with this object no longer exists."
></div>
<div
class="kuiInfoPanelBody__message"
ng-if="notFound === 'index-pattern-field'"
>
A field associated with this object no longer exists in the index pattern.
</div>
i18n-id="kbn.management.objects.view.fieldDoesNotExistErrorMessage"
i18n-default-message="A field associated with this object no longer exists in the index pattern."
></div>
<div class="kuiInfoPanelBody__message">
If you know what this error means, go ahead and fix it &mdash; otherwise click the delete button above.
</div>
<div
class="kuiInfoPanelBody__message"
i18n-id="kbn.management.objects.view.howToFixErrorDescription"
i18n-default-message="If you know what this error means, go ahead and fix it &mdash; otherwise click the delete button above."
></div>
</div>
</div>
</div>
@ -78,14 +93,19 @@
<div class="kuiInfoPanel kuiInfoPanel--warning">
<div class="kuiInfoPanelHeader">
<span class="kuiInfoPanelHeader__icon kuiIcon kuiIcon--warning fa-bolt"></span>
<span class="kuiInfoPanelHeader__title">
Proceed with caution!
</span>
<span
class="kuiInfoPanelHeader__title"
i18n-id="kbn.management.objects.view.howToModifyObjectTitle"
i18n-default-message="Proceed with caution!"
></span>
</div>
<div class="kuiInfoPanelBody">
<div class="kuiInfoPanelBody__message">
Modifying objects is for advanced users only. Object properties are not validated and invalid objects could cause errors, data loss, or worse. Unless someone with intimate knowledge of the code told you to be in here, you probably shouldn&rsquo;t be.
<div
class="kuiInfoPanelBody__message"
i18n-id="kbn.management.objects.view.howToModifyObjectDescription"
i18n-default-message=" Modifying objects is for advanced users only. Object properties are not validated and invalid objects could cause errors, data loss, or worse. Unless someone with intimate knowledge of the code told you to be in here, you probably shouldn&rsquo;t be."
>
</div>
</div>
</div>
@ -143,20 +163,21 @@
<div class="kuiButtonGroup">
<button
class="kuiButton kuiButton--primary"
aria-label="Save {{ title }} Object"
aria-label="{{ 'kbn.management.objects.view.saveButtonAriaLabel' | i18n: { defaultMessage: 'Save { title } Object', values: { title } } }}"
ng-click="submit()"
ng-disabled="objectForm.$invalid || aceInvalidEditors.length !==0"
>
Save {{ title }} Object
</button>
i18n-id="kbn.management.objects.view.saveButtonLabel"
i18n-default-message="Save { title } Object"
i18n-values="{ title }"
></button>
<button
class="kuiButton kuiButton--basic"
aria-label="Cancel"
aria-label="{{ 'kbn.management.objects.view.cancelButtonAriaLabel' | i18n: { defaultMessage: 'Cancel'} }}"
ng-click="cancel()"
>
Cancel
</button>
i18n-id="kbn.management.objects.view.cancelButtonLabel"
i18n-default-message="Cancel"
></button>
</div>
</div>
</kbn-management-objects-view>

View file

@ -38,7 +38,7 @@ uiRoutes
});
uiModules.get('apps/management')
.directive('kbnManagementObjectsView', function (kbnIndex, confirmModal) {
.directive('kbnManagementObjectsView', function (kbnIndex, confirmModal, i18n) {
return {
restrict: 'E',
controller: function ($scope, $injector, $routeParams, $location, $window, $rootScope, Private) {
@ -199,11 +199,17 @@ uiModules.get('apps/management')
}
const confirmModalOptions = {
onConfirm: doDelete,
confirmButtonText: 'Delete',
title: 'Delete saved Kibana object?'
confirmButtonText: i18n('kbn.management.objects.confirmModalOptions.deleteButtonLabel', {
defaultMessage: 'Delete',
}),
title: i18n('kbn.management.objects.confirmModalOptions.modalTitle', {
defaultMessage: 'Delete saved Kibana object?'
}),
};
confirmModal(
`You can't recover deleted objects`,
i18n('kbn.management.objects.confirmModalOptions.modalDescription', {
defaultMessage: 'You can\'t recover deleted objects',
}),
confirmModalOptions
);
};

View file

@ -3,15 +3,37 @@
exports[`ObjectsTable delete should show a confirm modal 1`] = `
<EuiConfirmModal
buttonColor="primary"
cancelButtonText="Cancel"
confirmButtonText="Delete"
cancelButtonText={
<FormattedMessage
defaultMessage="Cancel"
id="kbn.management.objects.objectsTable.deleteSavedObjectsConfirmModal.cancelButtonLabel"
values={Object {}}
/>
}
confirmButtonText={
<FormattedMessage
defaultMessage="Delete"
id="kbn.management.objects.objectsTable.deleteSavedObjectsConfirmModal.deleteButtonLabel"
values={Object {}}
/>
}
defaultFocusedButton="confirm"
onCancel={[Function]}
onConfirm={[Function]}
title="Delete saved objects"
title={
<FormattedMessage
defaultMessage="Delete saved objects"
id="kbn.management.objects.objectsTable.deleteSavedObjectsConfirmModalTitle"
values={Object {}}
/>
}
>
<p>
This action will delete the following saved objects:
<FormattedMessage
defaultMessage="This action will delete the following saved objects:"
id="kbn.management.objects.deleteSavedObjectsConfirmModalDescription"
values={Object {}}
/>
</p>
<EuiInMemoryTable
columns={
@ -50,15 +72,41 @@ exports[`ObjectsTable delete should show a confirm modal 1`] = `
exports[`ObjectsTable export should allow the user to choose when exporting all 1`] = `
<EuiConfirmModal
buttonColor="primary"
cancelButtonText="Cancel"
confirmButtonText="Export All"
cancelButtonText={
<FormattedMessage
defaultMessage="Cancel"
id="kbn.management.objects.objectsTable.exportObjectsConfirmModal.cancelButtonLabel"
values={Object {}}
/>
}
confirmButtonText={
<FormattedMessage
defaultMessage="Export All"
id="kbn.management.objects.objectsTable.exportObjectsConfirmModal.exportAllButtonLabel"
values={Object {}}
/>
}
defaultFocusedButton="confirm"
onCancel={[Function]}
onConfirm={[Function]}
title="Export 4 objects"
title={
<FormattedMessage
defaultMessage="Export {filteredItemCount, plural, one{# object} other {# objects}}"
id="kbn.management.objects.objectsTable.exportObjectsConfirmModalTitle"
values={
Object {
"filteredItemCount": 4,
}
}
/>
}
>
<p>
Select which types to export. The number in parentheses indicates how many of this type are available to export.
<FormattedMessage
defaultMessage="Select which types to export. The number in parentheses indicates how many of this type are available to export."
id="kbn.management.objects.objectsTable.exportObjectsConfirmModalDescription"
values={Object {}}
/>
</p>
<EuiCheckboxGroup
idToSelectedMap={
@ -95,7 +143,7 @@ exports[`ObjectsTable export should allow the user to choose when exporting all
`;
exports[`ObjectsTable import should show the flyout 1`] = `
<Flyout
<InjectIntl(FlyoutUI)
close={[Function]}
done={[Function]}
indexPatterns={
@ -111,7 +159,7 @@ exports[`ObjectsTable import should show the flyout 1`] = `
`;
exports[`ObjectsTable relationships should show the flyout 1`] = `
<Relationships
<InjectIntl(RelationshipsUI)
close={[Function]}
getEditUrl={[Function]}
getRelationships={[Function]}
@ -150,7 +198,7 @@ exports[`ObjectsTable should render normally 1`] = `
<EuiSpacer
size="xs"
/>
<Table
<InjectIntl(TableUI)
filterOptions={
Array [
Object {

View file

@ -18,9 +18,11 @@
*/
import React from 'react';
import { shallow } from 'enzyme';
import { shallowWithIntl } from 'test_utils/enzyme_helpers';
import { ObjectsTable, INCLUDED_TYPES } from '../objects_table';
import { Flyout } from '../components/flyout/';
import { Relationships } from '../components/relationships/';
jest.mock('../components/header', () => ({
Header: () => 'Header',
@ -157,8 +159,8 @@ describe('ObjectsTable', () => {
});
it('should render normally', async () => {
const component = shallow(
<ObjectsTable
const component = shallowWithIntl(
<ObjectsTable.WrappedComponent
{...defaultProps}
perPageConfig={15}
/>
@ -194,8 +196,8 @@ describe('ObjectsTable', () => {
const { retrieveAndExportDocs } = require('../../../lib/retrieve_and_export_docs');
const component = shallow(
<ObjectsTable
const component = shallowWithIntl(
<ObjectsTable.WrappedComponent
{...defaultProps}
savedObjectsClient={mockSavedObjectsClient}
/>
@ -216,8 +218,8 @@ describe('ObjectsTable', () => {
});
it('should allow the user to choose when exporting all', async () => {
const component = shallow(
<ObjectsTable
const component = shallowWithIntl(
<ObjectsTable.WrappedComponent
{...defaultProps}
/>
);
@ -236,8 +238,8 @@ describe('ObjectsTable', () => {
it('should export all', async () => {
const { scanAllTypes } = require('../../../lib/scan_all_types');
const { saveToFile } = require('../../../lib/save_to_file');
const component = shallow(
<ObjectsTable
const component = shallowWithIntl(
<ObjectsTable.WrappedComponent
{...defaultProps}
/>
);
@ -259,8 +261,8 @@ describe('ObjectsTable', () => {
describe('import', () => {
it('should show the flyout', async () => {
const component = shallow(
<ObjectsTable
const component = shallowWithIntl(
<ObjectsTable.WrappedComponent
{...defaultProps}
/>
);
@ -273,12 +275,12 @@ describe('ObjectsTable', () => {
component.instance().showImportFlyout();
component.update();
expect(component.find('Flyout')).toMatchSnapshot();
expect(component.find(Flyout)).toMatchSnapshot();
});
it('should hide the flyout', async () => {
const component = shallow(
<ObjectsTable
const component = shallowWithIntl(
<ObjectsTable.WrappedComponent
{...defaultProps}
/>
);
@ -291,7 +293,7 @@ describe('ObjectsTable', () => {
component.instance().hideImportFlyout();
component.update();
expect(component.find('Flyout').length).toBe(0);
expect(component.find(Flyout).length).toBe(0);
});
});
@ -299,8 +301,8 @@ describe('ObjectsTable', () => {
it('should fetch relationships', async () => {
const { getRelationships } = require('../../../lib/get_relationships');
const component = shallow(
<ObjectsTable
const component = shallowWithIntl(
<ObjectsTable.WrappedComponent
{...defaultProps}
/>
);
@ -315,8 +317,8 @@ describe('ObjectsTable', () => {
});
it('should show the flyout', async () => {
const component = shallow(
<ObjectsTable
const component = shallowWithIntl(
<ObjectsTable.WrappedComponent
{...defaultProps}
/>
);
@ -329,15 +331,15 @@ describe('ObjectsTable', () => {
component.instance().onShowRelationships('1', 'search', 'MySearch');
component.update();
expect(component.find('Relationships')).toMatchSnapshot();
expect(component.find(Relationships)).toMatchSnapshot();
expect(component.state('relationshipId')).toBe('1');
expect(component.state('relationshipType')).toBe('search');
expect(component.state('relationshipTitle')).toBe('MySearch');
});
it('should hide the flyout', async () => {
const component = shallow(
<ObjectsTable
const component = shallowWithIntl(
<ObjectsTable.WrappedComponent
{...defaultProps}
/>
);
@ -350,7 +352,7 @@ describe('ObjectsTable', () => {
component.instance().onHideRelationships();
component.update();
expect(component.find('Relationships').length).toBe(0);
expect(component.find(Relationships).length).toBe(0);
expect(component.state('relationshipId')).toBe(undefined);
expect(component.state('relationshipType')).toBe(undefined);
expect(component.state('relationshipTitle')).toBe(undefined);
@ -359,8 +361,8 @@ describe('ObjectsTable', () => {
describe('delete', () => {
it('should show a confirm modal', async () => {
const component = shallow(
<ObjectsTable
const component = shallowWithIntl(
<ObjectsTable.WrappedComponent
{...defaultProps}
/>
);
@ -403,8 +405,8 @@ describe('ObjectsTable', () => {
delete: jest.fn(),
};
const component = shallow(
<ObjectsTable
const component = shallowWithIntl(
<ObjectsTable.WrappedComponent
{...defaultProps}
savedObjectsClient={mockSavedObjectsClient}
/>

View file

@ -16,7 +16,11 @@ exports[`Flyout conflicts should allow conflict resolution 1`] = `
size="m"
>
<h2>
Import saved objects
<FormattedMessage
defaultMessage="Import saved objects"
id="kbn.management.objects.objectsTable.flyout.importSavedObjectTitle"
values={Object {}}
/>
</h2>
</EuiTitle>
<React.Fragment>
@ -27,20 +31,34 @@ exports[`Flyout conflicts should allow conflict resolution 1`] = `
color="warning"
iconType="help"
size="m"
title="Index Pattern Conflicts"
title={
<FormattedMessage
defaultMessage="Index Pattern Conflicts"
id="kbn.management.objects.objectsTable.flyout.indexPatternConflictsTitle"
values={Object {}}
/>
}
>
<p>
The following saved objects use index patterns that do not exist. Please select the index patterns you'd like re-associated with them. You can
<EuiLink
color="primary"
href=""
type="button"
>
create a new index pattern
</EuiLink>
if necessary.
<FormattedMessage
defaultMessage="The following saved objects use index patterns that do not exist. Please select the index patterns you'd like re-associated with them. You can {indexPatternLink} if necessary."
id="kbn.management.objects.objectsTable.flyout.indexPatternConflictsDescription"
values={
Object {
"indexPatternLink": <EuiLink
color="primary"
href=""
type="button"
>
<FormattedMessage
defaultMessage="create a new index pattern"
id="kbn.management.objects.objectsTable.flyout.indexPatternConflictsCalloutLinkText"
values={Object {}}
/>
</EuiLink>,
}
}
/>
</p>
</EuiCallOut>
</React.Fragment>
@ -123,7 +141,11 @@ exports[`Flyout conflicts should allow conflict resolution 1`] = `
size="s"
type="button"
>
Cancel
<FormattedMessage
defaultMessage="Cancel"
id="kbn.management.objects.objectsTable.flyout.import.cancelButtonLabel"
values={Object {}}
/>
</EuiButtonEmpty>
</EuiFlexItem>
<EuiFlexItem
@ -140,7 +162,11 @@ exports[`Flyout conflicts should allow conflict resolution 1`] = `
size="s"
type="button"
>
Confirm all changes
<FormattedMessage
defaultMessage="Confirm all changes"
id="kbn.management.objects.objectsTable.flyout.importSuccessful.confirmAllChangesButtonLabel"
values={Object {}}
/>
</EuiButton>
</EuiFlexItem>
</EuiFlexGroup>
@ -153,7 +179,13 @@ exports[`Flyout conflicts should handle errors 1`] = `
color="danger"
iconType="cross"
size="m"
title="Sorry, there was an error"
title={
<FormattedMessage
defaultMessage="Sorry, there was an error"
id="kbn.management.objects.objectsTable.flyout.errorCalloutTitle"
values={Object {}}
/>
}
>
<p>
foobar
@ -177,7 +209,11 @@ exports[`Flyout should render import step 1`] = `
size="m"
>
<h2>
Import saved objects
<FormattedMessage
defaultMessage="Import saved objects"
id="kbn.management.objects.objectsTable.flyout.importSavedObjectTitle"
values={Object {}}
/>
</h2>
</EuiTitle>
</EuiFlyoutHeader>
@ -187,11 +223,23 @@ exports[`Flyout should render import step 1`] = `
describedByIds={Array []}
fullWidth={false}
hasEmptyLabelSpace={false}
label="Please select a JSON file to import"
label={
<FormattedMessage
defaultMessage="Please select a JSON file to import"
id="kbn.management.objects.objectsTable.flyout.selectFileToImportFormRowLabel"
values={Object {}}
/>
}
>
<EuiFilePicker
compressed={false}
initialPromptText="Import"
initialPromptText={
<FormattedMessage
defaultMessage="Import"
id="kbn.management.objects.objectsTable.flyout.importPromptText"
values={Object {}}
/>
}
onChange={[Function]}
/>
</EuiFormRow>
@ -203,7 +251,13 @@ exports[`Flyout should render import step 1`] = `
<EuiSwitch
checked={true}
data-test-subj="importSavedObjectsOverwriteToggle"
label="Automatically overwrite all saved objects?"
label={
<FormattedMessage
defaultMessage="Automatically overwrite all saved objects?"
id="kbn.management.objects.objectsTable.flyout.overwriteSavedObjectsLabel"
values={Object {}}
/>
}
name="overwriteAll"
onChange={[Function]}
/>
@ -231,7 +285,11 @@ exports[`Flyout should render import step 1`] = `
size="s"
type="button"
>
Cancel
<FormattedMessage
defaultMessage="Cancel"
id="kbn.management.objects.objectsTable.flyout.import.cancelButtonLabel"
values={Object {}}
/>
</EuiButtonEmpty>
</EuiFlexItem>
<EuiFlexItem
@ -248,7 +306,11 @@ exports[`Flyout should render import step 1`] = `
size="s"
type="button"
>
Import
<FormattedMessage
defaultMessage="Import"
id="kbn.management.objects.objectsTable.flyout.import.confirmButtonLabel"
values={Object {}}
/>
</EuiButton>
</EuiFlexItem>
</EuiFlexGroup>

View file

@ -18,7 +18,7 @@
*/
import React from 'react';
import { shallow } from 'enzyme';
import { shallowWithIntl } from 'test_utils/enzyme_helpers';
import { Flyout } from '../flyout';
@ -66,7 +66,7 @@ const mockFile = {
describe('Flyout', () => {
it('should render import step', async () => {
const component = shallow(<Flyout {...defaultProps} />);
const component = shallowWithIntl(<Flyout.WrappedComponent {...defaultProps} />);
// Ensure all promises resolve
await new Promise(resolve => process.nextTick(resolve));
@ -77,7 +77,7 @@ describe('Flyout', () => {
});
it('should toggle the overwrite all control', async () => {
const component = shallow(<Flyout {...defaultProps} />);
const component = shallowWithIntl(<Flyout.WrappedComponent {...defaultProps} />);
// Ensure all promises resolve
await new Promise(resolve => process.nextTick(resolve));
@ -90,7 +90,7 @@ describe('Flyout', () => {
});
it('should allow picking a file', async () => {
const component = shallow(<Flyout {...defaultProps} />);
const component = shallowWithIntl(<Flyout.WrappedComponent {...defaultProps} />);
// Ensure all promises resolve
await new Promise(resolve => process.nextTick(resolve));
@ -104,7 +104,7 @@ describe('Flyout', () => {
it('should handle invalid files', async () => {
const { importFile } = require('../../../../../lib/import_file');
const component = shallow(<Flyout {...defaultProps} />);
const component = shallowWithIntl(<Flyout.WrappedComponent {...defaultProps} />);
// Ensure all promises resolve
await new Promise(resolve => process.nextTick(resolve));
@ -183,7 +183,7 @@ describe('Flyout', () => {
});
it('should figure out conflicts', async () => {
const component = shallow(<Flyout {...defaultProps} />);
const component = shallowWithIntl(<Flyout.WrappedComponent {...defaultProps} />);
// Ensure all promises resolve
await new Promise(resolve => process.nextTick(resolve));
@ -226,7 +226,7 @@ describe('Flyout', () => {
});
it('should allow conflict resolution', async () => {
const component = shallow(<Flyout {...defaultProps} />);
const component = shallowWithIntl(<Flyout.WrappedComponent {...defaultProps} />);
// Ensure all promises resolve
await new Promise(resolve => process.nextTick(resolve));
@ -270,7 +270,7 @@ describe('Flyout', () => {
});
it('should handle errors', async () => {
const component = shallow(<Flyout {...defaultProps} />);
const component = shallowWithIntl(<Flyout.WrappedComponent {...defaultProps} />);
// Ensure all promises resolve
await new Promise(resolve => process.nextTick(resolve));

View file

@ -50,8 +50,9 @@ import {
saveObjects,
} from '../../../../lib/resolve_saved_objects';
import { INCLUDED_TYPES } from '../../objects_table';
import { FormattedMessage, injectI18n } from '@kbn/i18n/react';
export class Flyout extends Component {
class FlyoutUI extends Component {
static propTypes = {
close: PropTypes.func.isRequired,
done: PropTypes.func.isRequired,
@ -102,7 +103,7 @@ export class Flyout extends Component {
};
import = async () => {
const { services, indexPatterns } = this.props;
const { services, indexPatterns, intl } = this.props;
const { file, isOverwriteAllChecked } = this.state;
this.setState({ isLoading: true, error: undefined });
@ -114,7 +115,10 @@ export class Flyout extends Component {
} catch (e) {
this.setState({
isLoading: false,
error: 'The file could not be processed.',
error: intl.formatMessage({
id: 'kbn.management.objects.objectsTable.flyout.importFileErrorMessage',
defaultMessage: 'The file could not be processed.',
}),
});
return;
}
@ -122,7 +126,10 @@ export class Flyout extends Component {
if (!Array.isArray(contents)) {
this.setState({
isLoading: false,
error: 'Saved objects file format is invalid and cannot be imported.',
error: intl.formatMessage({
id: 'kbn.management.objects.objectsTable.flyout.invalidFormatOfImportedFileErrorMessage',
defaultMessage: 'Saved objects file format is invalid and cannot be imported.',
}),
});
return;
}
@ -211,7 +218,7 @@ export class Flyout extends Component {
failedImports
} = this.state;
const { services, indexPatterns } = this.props;
const { services, indexPatterns, intl } = this.props;
this.setState({
error: undefined,
@ -226,7 +233,12 @@ export class Flyout extends Component {
const resolutions = this.resolutions;
// Do not Promise.all these calls as the order matters
this.setState({ loadingMessage: 'Resolving conflicts...' });
this.setState({
loadingMessage: intl.formatMessage({
id: 'kbn.management.objects.objectsTable.flyout.confirmImport.resolvingConflictsLoadingMessage',
defaultMessage: 'Resolving conflicts…',
}),
});
if (resolutions.length) {
importCount += await resolveIndexPatternConflicts(
resolutions,
@ -234,13 +246,21 @@ export class Flyout extends Component {
isOverwriteAllChecked
);
}
this.setState({ loadingMessage: 'Saving conflicts...' });
this.setState({
loadingMessage: intl.formatMessage({
id: 'kbn.management.objects.objectsTable.flyout.confirmImport.savingConflictsLoadingMessage',
defaultMessage: 'Saving conflicts…',
}),
});
importCount += await saveObjects(
conflictedSavedObjectsLinkedToSavedSearches,
isOverwriteAllChecked
);
this.setState({
loadingMessage: 'Ensure saved searches are linked properly...',
loadingMessage: intl.formatMessage({
id: 'kbn.management.objects.objectsTable.flyout.confirmImport.savedSearchAreLinkedProperlyLoadingMessage',
defaultMessage: 'Ensure saved searches are linked properly…',
}),
});
importCount += await resolveSavedSearches(
conflictedSearchDocs,
@ -249,7 +269,10 @@ export class Flyout extends Component {
isOverwriteAllChecked
);
this.setState({
loadingMessage: 'Retrying failed objects...',
loadingMessage: intl.formatMessage({
id: 'kbn.management.objects.objectsTable.flyout.confirmImport.retryingFailedObjectsLoadingMessage',
defaultMessage: 'Retrying failed objects…',
}),
});
importCount += await saveObjects(
failedImports.map(({ obj }) => obj),
@ -293,6 +316,7 @@ export class Flyout extends Component {
renderConflicts() {
const { conflicts } = this.state;
const { intl } = this.props;
if (!conflicts) {
return null;
@ -301,22 +325,40 @@ export class Flyout extends Component {
const columns = [
{
field: 'existingIndexPatternId',
name: 'ID',
description: `ID of the index pattern`,
name: intl.formatMessage({
id: 'kbn.management.objects.objectsTable.flyout.renderConflicts.columnIdName',
defaultMessage: 'ID',
}),
description: intl.formatMessage({
id: 'kbn.management.objects.objectsTable.flyout.renderConflicts.columnIdDescription',
defaultMessage: 'ID of the index pattern',
}),
sortable: true,
},
{
field: 'list',
name: 'Count',
description: `How many affected objects`,
name: intl.formatMessage({
id: 'kbn.management.objects.objectsTable.flyout.renderConflicts.columnCountName',
defaultMessage: 'Count',
}),
description: intl.formatMessage({
id: 'kbn.management.objects.objectsTable.flyout.renderConflicts.columnCountDescription',
defaultMessage: 'How many affected objects',
}),
render: list => {
return <Fragment>{list.length}</Fragment>;
},
},
{
field: 'list',
name: 'Sample of affected objects',
description: `Sample of affected objects`,
name: intl.formatMessage({
id: 'kbn.management.objects.objectsTable.flyout.renderConflicts.columnSampleOfAffectedObjectsName',
defaultMessage: 'Sample of affected objects',
}),
description: intl.formatMessage({
id: 'kbn.management.objects.objectsTable.flyout.renderConflicts.columnSampleOfAffectedObjectsDescription',
defaultMessage: 'Sample of affected objects',
}),
render: list => {
return (
<ul style={{ listStyle: 'none' }}>
@ -327,7 +369,10 @@ export class Flyout extends Component {
},
{
field: 'existingIndexPatternId',
name: 'New index pattern',
name: intl.formatMessage({
id: 'kbn.management.objects.objectsTable.flyout.renderConflicts.columnNewIndexPatternName',
defaultMessage: 'New index pattern',
}),
render: id => {
const options = this.state.indexPatterns.map(indexPattern => ({
text: indexPattern.get('title'),
@ -374,7 +419,9 @@ export class Flyout extends Component {
return (
<Fragment>
<EuiCallOut
title="Sorry, there was an error"
title={(
<FormattedMessage id="kbn.management.objects.objectsTable.flyout.errorCalloutTitle" defaultMessage="Sorry, there was an error"/>
)}
color="danger"
iconType="cross"
>
@ -412,12 +459,18 @@ export class Flyout extends Component {
if (failedImports.length && !this.hasConflicts) {
return (
<EuiCallOut
title="Import failed"
title={(
<FormattedMessage id="kbn.management.objects.objectsTable.flyout.importFailedTitle" defaultMessage="Import failed"/>
)}
color="warning"
iconType="help"
>
<p>
Failed to import {failedImports.length} of {importCount + failedImports.length} objects.
<FormattedMessage
id="kbn.management.objects.objectsTable.flyout.importFailedDescription"
defaultMessage="Failed to import {failedImportCount} of {totalImportCount} objects.Import failed"
values={{ failedImportCount: failedImports.length, totalImportCount: importCount + failedImports.length, }}
/>
</p>
<p>
{failedImports.map(({ error }) => getField(error, 'body.message', error.message || '')).join(' ')}
@ -431,7 +484,12 @@ export class Flyout extends Component {
return (
<EuiCallOut
data-test-subj="importSavedObjectsSuccessNoneImported"
title="No objects imported"
title={(
<FormattedMessage
id="kbn.management.objects.objectsTable.flyout.importSuccessfulCallout.noObjectsImportedTitle"
defaultMessage="No objects imported"
/>
)}
color="primary"
/>
);
@ -440,11 +498,22 @@ export class Flyout extends Component {
return (
<EuiCallOut
data-test-subj="importSavedObjectsSuccess"
title="Import successful"
title={(
<FormattedMessage
id="kbn.management.objects.objectsTable.flyout.importSuccessfulTitle"
defaultMessage="Import successful"
/>
)}
color="success"
iconType="check"
>
<p>Successfully imported {importCount} objects.</p>
<p>
<FormattedMessage
id="kbn.management.objects.objectsTable.flyout.importSuccessfulDescription"
defaultMessage="Successfully imported {importCount} objects."
values={{ importCount }}
/>
</p>
</EuiCallOut>
);
}
@ -455,16 +524,33 @@ export class Flyout extends Component {
return (
<EuiForm>
<EuiFormRow label="Please select a JSON file to import">
<EuiFormRow
label={(
<FormattedMessage
id="kbn.management.objects.objectsTable.flyout.selectFileToImportFormRowLabel"
defaultMessage="Please select a JSON file to import"
/>
)}
>
<EuiFilePicker
initialPromptText="Import"
initialPromptText={(
<FormattedMessage
id="kbn.management.objects.objectsTable.flyout.importPromptText"
defaultMessage="Import"
/>
)}
onChange={this.setImportFile}
/>
</EuiFormRow>
<EuiFormRow>
<EuiSwitch
name="overwriteAll"
label="Automatically overwrite all saved objects?"
label={(
<FormattedMessage
id="kbn.management.objects.objectsTable.flyout.overwriteSavedObjectsLabel"
defaultMessage="Automatically overwrite all saved objects?"
/>
)}
data-test-subj="importSavedObjectsOverwriteToggle"
checked={isOverwriteAllChecked}
onChange={this.changeOverwriteAll}
@ -488,7 +574,10 @@ export class Flyout extends Component {
fill
data-test-subj="importSavedObjectsDoneBtn"
>
Done
<FormattedMessage
id="kbn.management.objects.objectsTable.flyout.importSuccessful.confirmButtonLabel"
defaultMessage="Done"
/>
</EuiButton>
);
} else if (this.hasConflicts) {
@ -500,7 +589,10 @@ export class Flyout extends Component {
isLoading={isLoading}
data-test-subj="importSavedObjectsConfirmBtn"
>
Confirm all changes
<FormattedMessage
id="kbn.management.objects.objectsTable.flyout.importSuccessful.confirmAllChangesButtonLabel"
defaultMessage="Confirm all changes"
/>
</EuiButton>
);
} else {
@ -512,7 +604,10 @@ export class Flyout extends Component {
isLoading={isLoading}
data-test-subj="importSavedObjectsImportBtn"
>
Import
<FormattedMessage
id="kbn.management.objects.objectsTable.flyout.import.confirmButtonLabel"
defaultMessage="Import"
/>
</EuiButton>
);
}
@ -521,7 +616,10 @@ export class Flyout extends Component {
<EuiFlexGroup justifyContent="spaceBetween">
<EuiFlexItem grow={false}>
<EuiButtonEmpty onClick={close} size="s">
Cancel
<FormattedMessage
id="kbn.management.objects.objectsTable.flyout.import.cancelButtonLabel"
defaultMessage="Cancel"
/>
</EuiButtonEmpty>
</EuiFlexItem>
<EuiFlexItem grow={false}>{confirmButton}</EuiFlexItem>
@ -542,20 +640,32 @@ export class Flyout extends Component {
<Fragment>
<EuiSpacer size="s" />
<EuiCallOut
title="Index Pattern Conflicts"
title={(
<FormattedMessage
id="kbn.management.objects.objectsTable.flyout.indexPatternConflictsTitle"
defaultMessage="Index Pattern Conflicts"
/>
)}
color="warning"
iconType="help"
>
<p>
The following saved objects use index patterns that do not exist.
Please select the index patterns you&apos;d like re-associated with
them. You can{' '}
{
<EuiLink href={this.props.newIndexPatternUrl}>
create a new index pattern
</EuiLink>
}{' '}
if necessary.
<FormattedMessage
id="kbn.management.objects.objectsTable.flyout.indexPatternConflictsDescription"
defaultMessage="The following saved objects use index patterns that do not exist.
Please select the index patterns you&apos;d like re-associated with
them. You can {indexPatternLink} if necessary."
values={{
indexPatternLink: (
<EuiLink href={this.props.newIndexPatternUrl}>
<FormattedMessage
id="kbn.management.objects.objectsTable.flyout.indexPatternConflictsCalloutLinkText"
defaultMessage="create a new index pattern"
/>
</EuiLink>
)
}}
/>
</p>
</EuiCallOut>
</Fragment>
@ -569,7 +679,12 @@ export class Flyout extends Component {
<EuiFlyout onClose={close} size="s">
<EuiFlyoutHeader>
<EuiTitle>
<h2>Import saved objects</h2>
<h2>
<FormattedMessage
id="kbn.management.objects.objectsTable.flyout.importSavedObjectTitle"
defaultMessage="Import saved objects"
/>
</h2>
</EuiTitle>
{this.renderSubheader()}
</EuiFlyoutHeader>
@ -584,3 +699,5 @@ export class Flyout extends Component {
);
}
}
export const Flyout = injectI18n(FlyoutUI);

View file

@ -19,7 +19,11 @@ exports[`Header should render normally 1`] = `
size="m"
>
<h1>
Saved Objects
<FormattedMessage
defaultMessage="Saved Objects"
id="kbn.management.objects.objectsTable.header.savedObjectsTitle"
values={Object {}}
/>
</h1>
</EuiTitle>
</EuiFlexItem>
@ -49,10 +53,15 @@ exports[`Header should render normally 1`] = `
size="s"
type="button"
>
Export
2
objects
<FormattedMessage
defaultMessage="Export {filteredCount, plural, one{# object} other {# objects}}"
id="kbn.management.objects.objectsTable.header.exportButtonLabel"
values={
Object {
"filteredCount": 2,
}
}
/>
</EuiButtonEmpty>
</EuiFlexItem>
<EuiFlexItem
@ -68,7 +77,11 @@ exports[`Header should render normally 1`] = `
size="s"
type="button"
>
Import
<FormattedMessage
defaultMessage="Import"
id="kbn.management.objects.objectsTable.header.importButtonLabel"
values={Object {}}
/>
</EuiButtonEmpty>
</EuiFlexItem>
<EuiFlexItem
@ -83,7 +96,11 @@ exports[`Header should render normally 1`] = `
size="s"
type="button"
>
Refresh
<FormattedMessage
defaultMessage="Refresh"
id="kbn.management.objects.objectsTable.header.refreshButtonLabel"
values={Object {}}
/>
</EuiButtonEmpty>
</EuiFlexItem>
</EuiFlexGroup>
@ -100,7 +117,11 @@ exports[`Header should render normally 1`] = `
color="subdued"
component="span"
>
From here you can delete saved objects, such as saved searches. You can also edit the raw data of saved objects. Typically objects are only modified via their associated application, which is probably what you should use instead of this screen.
<FormattedMessage
defaultMessage="From here you can delete saved objects, such as saved searches. You can also edit the raw data of saved objects. Typically objects are only modified via their associated application, which is probably what you should use instead of this screen."
id="kbn.management.objects.objectsTable.howToDeleteSavedObjectsDescription"
values={Object {}}
/>
</EuiTextColor>
</p>
</EuiText>

View file

@ -29,6 +29,7 @@ import {
EuiTextColor,
EuiButtonEmpty,
} from '@elastic/eui';
import { FormattedMessage } from '@kbn/i18n/react';
export const Header = ({
onExportAll,
@ -40,7 +41,12 @@ export const Header = ({
<EuiFlexGroup justifyContent="spaceBetween" alignItems="baseline">
<EuiFlexItem grow={false}>
<EuiTitle>
<h1>Saved Objects</h1>
<h1>
<FormattedMessage
id="kbn.management.objects.objectsTable.header.savedObjectsTitle"
defaultMessage="Saved Objects"
/>
</h1>
</EuiTitle>
</EuiFlexItem>
@ -53,7 +59,13 @@ export const Header = ({
data-test-subj="exportAllObjects"
onClick={onExportAll}
>
Export {filteredCount} {filteredCount === 1 ? 'object' : 'objects'}
<FormattedMessage
id="kbn.management.objects.objectsTable.header.exportButtonLabel"
defaultMessage="Export {filteredCount, plural, one{# object} other {# objects}}"
values={{
filteredCount
}}
/>
</EuiButtonEmpty>
</EuiFlexItem>
<EuiFlexItem grow={false}>
@ -63,7 +75,10 @@ export const Header = ({
data-test-subj="importObjects"
onClick={onImport}
>
Import
<FormattedMessage
id="kbn.management.objects.objectsTable.header.importButtonLabel"
defaultMessage="Import"
/>
</EuiButtonEmpty>
</EuiFlexItem>
<EuiFlexItem grow={false}>
@ -72,7 +87,10 @@ export const Header = ({
iconType="refresh"
onClick={onRefresh}
>
Refresh
<FormattedMessage
id="kbn.management.objects.objectsTable.header.refreshButtonLabel"
defaultMessage="Refresh"
/>
</EuiButtonEmpty>
</EuiFlexItem>
</EuiFlexGroup>
@ -82,10 +100,13 @@ export const Header = ({
<EuiText>
<p>
<EuiTextColor color="subdued">
From here you can delete saved objects, such as saved searches.
You can also edit the raw data of saved objects.
Typically objects are only modified via their associated application,
which is probably what you should use instead of this screen.
<FormattedMessage
id="kbn.management.objects.objectsTable.howToDeleteSavedObjectsDescription"
defaultMessage="From here you can delete saved objects, such as saved searches.
You can also edit the raw data of saved objects.
Typically objects are only modified via their associated application,
which is probably what you should use instead of this screen."
/>
</EuiTextColor>
</p>
</EuiText>

View file

@ -52,12 +52,20 @@ exports[`Relationships should render dashboards normally 1`] = `
<EuiCallOut
color="success"
size="m"
title="Dashboard"
title={
<FormattedMessage
defaultMessage="Dashboard"
id="kbn.management.objects.objectsTable.relationships.dashboard.calloutTitle"
values={Object {}}
/>
}
>
<p>
Here are some visualizations used on this dashboard. You can
safely delete this dashboard and the visualizations will still
work properly.
<FormattedMessage
defaultMessage="Here are some visualizations used on this dashboard. You can safely delete this dashboard and the visualizations will still work properly."
id="kbn.management.objects.objectsTable.relationships.dashboard.calloutText"
values={Object {}}
/>
</p>
</EuiCallOut>
</EuiDescriptionListTitle>
@ -142,7 +150,13 @@ exports[`Relationships should render errors 1`] = `
<EuiCallOut
color="danger"
size="m"
title="Error"
title={
<FormattedMessage
defaultMessage="Error"
id="kbn.management.objects.objectsTable.relationships.renderErrorMessage"
values={Object {}}
/>
}
>
foo
</EuiCallOut>
@ -242,10 +256,20 @@ exports[`Relationships should render searches normally 1`] = `
<EuiCallOut
color="success"
size="m"
title="Saved Search"
title={
<FormattedMessage
defaultMessage="Saved Search"
id="kbn.management.objects.objectsTable.relationships.search.calloutTitle"
values={Object {}}
/>
}
>
<p>
Here is the index pattern tied to this saved search.
<FormattedMessage
defaultMessage="Here is the index pattern tied to this saved search."
id="kbn.management.objects.objectsTable.relationships.search.calloutText"
values={Object {}}
/>
</p>
</EuiCallOut>
</EuiDescriptionListTitle>
@ -299,12 +323,20 @@ exports[`Relationships should render searches normally 1`] = `
<EuiCallOut
color="warning"
size="m"
title="Warning"
title={
<FormattedMessage
defaultMessage="Warning"
id="kbn.management.objects.objectsTable.relationships.warningTitle"
values={Object {}}
/>
}
>
<p>
Here are some visualizations that use this saved search. If
you delete this saved search, these visualizations will not
longer work properly.
<FormattedMessage
defaultMessage="Here are some visualizations that use this saved search. If you delete this saved search, these visualizations will not longer work properly."
id="kbn.management.objects.objectsTable.relationships.search.visualizations.calloutText"
values={Object {}}
/>
</p>
</EuiCallOut>
</EuiDescriptionListTitle>
@ -402,12 +434,20 @@ exports[`Relationships should render visualizations normally 1`] = `
<EuiCallOut
color="warning"
size="m"
title="Warning"
title={
<FormattedMessage
defaultMessage="Warning"
id="kbn.management.objects.objectsTable.relationships.warningTitle"
values={Object {}}
/>
}
>
<p>
Here are some dashboards which contain this visualization. If
you delete this visualization, these dashboards will no longer
show them.
<FormattedMessage
defaultMessage="Here are some dashboards which contain this visualization. If you delete this visualization, these dashboards will no longer show them."
id="kbn.management.objects.objectsTable.relationships.visualization.calloutText"
values={Object {}}
/>
</p>
</EuiCallOut>
</EuiDescriptionListTitle>

View file

@ -18,7 +18,7 @@
*/
import React from 'react';
import { shallow } from 'enzyme';
import { shallowWithIntl } from 'test_utils/enzyme_helpers';
jest.mock('ui/errors', () => ({
SavedObjectNotFound: class SavedObjectNotFound extends Error {
@ -62,8 +62,8 @@ describe('Relationships', () => {
close: jest.fn(),
};
const component = shallow(
<Relationships
const component = shallowWithIntl(
<Relationships.WrappedComponent
{...props}
/>
);
@ -102,8 +102,8 @@ describe('Relationships', () => {
close: jest.fn(),
};
const component = shallow(
<Relationships
const component = shallowWithIntl(
<Relationships.WrappedComponent
{...props}
/>
);
@ -140,8 +140,8 @@ describe('Relationships', () => {
close: jest.fn(),
};
const component = shallow(
<Relationships
const component = shallowWithIntl(
<Relationships.WrappedComponent
{...props}
/>
);
@ -178,8 +178,8 @@ describe('Relationships', () => {
close: jest.fn(),
};
const component = shallow(
<Relationships
const component = shallowWithIntl(
<Relationships.WrappedComponent
{...props}
/>
);
@ -209,8 +209,8 @@ describe('Relationships', () => {
close: jest.fn(),
};
const component = shallow(
<Relationships
const component = shallowWithIntl(
<Relationships.WrappedComponent
{...props}
/>
);

View file

@ -34,9 +34,10 @@ import {
EuiInMemoryTable,
EuiToolTip
} from '@elastic/eui';
import { FormattedMessage, injectI18n } from '@kbn/i18n/react';
import { getSavedObjectIcon, getSavedObjectLabel } from '../../../../lib';
export class Relationships extends Component {
class RelationshipsUI extends Component {
static propTypes = {
getRelationships: PropTypes.func.isRequired,
id: PropTypes.string.isRequired,
@ -88,14 +89,19 @@ export class Relationships extends Component {
}
return (
<EuiCallOut title="Error" color="danger">
<EuiCallOut
title={(
<FormattedMessage id="kbn.management.objects.objectsTable.relationships.renderErrorMessage" defaultMessage="Error"/>
)}
color="danger"
>
{error}
</EuiCallOut>
);
}
renderRelationships() {
const { getEditUrl, goInApp } = this.props;
const { getEditUrl, goInApp, intl } = this.props;
const { relationships, isLoading, error } = this.state;
if (error) {
@ -112,48 +118,78 @@ export class Relationships extends Component {
if (list.length === 0) {
items.push(
<EuiDescriptionListTitle key={`${type}_not_found`}>
No {type} found.
<FormattedMessage
id="kbn.management.objects.objectsTable.relationships.itemNotFoundText"
defaultMessage="No {type} found."
values={{ type }}
/>
</EuiDescriptionListTitle>
);
} else {
// let node;
let calloutTitle = 'Warning';
let calloutTitle = (<FormattedMessage
id="kbn.management.objects.objectsTable.relationships.warningTitle"
defaultMessage="Warning"
/>);
let calloutColor = 'warning';
let calloutText;
switch (this.props.type) {
case 'dashboard':
calloutColor = 'success';
calloutTitle = 'Dashboard';
calloutText = `Here are some visualizations used on this dashboard. You can
safely delete this dashboard and the visualizations will still
work properly.`;
calloutTitle = (<FormattedMessage
id="kbn.management.objects.objectsTable.relationships.dashboard.calloutTitle"
defaultMessage="Dashboard"
/>);
calloutText = (<FormattedMessage
id="kbn.management.objects.objectsTable.relationships.dashboard.calloutText"
defaultMessage="Here are some visualizations used on this dashboard.
You can safely delete this dashboard and the visualizations will still work properly."
/>);
break;
case 'search':
if (type === 'visualizations') {
calloutText = `Here are some visualizations that use this saved search. If
you delete this saved search, these visualizations will not
longer work properly.`;
calloutText = (<FormattedMessage
id="kbn.management.objects.objectsTable.relationships.search.visualizations.calloutText"
defaultMessage="Here are some visualizations that use this saved search. If
you delete this saved search, these visualizations will not
longer work properly."
/>);
} else {
calloutColor = 'success';
calloutTitle = 'Saved Search';
calloutText = `Here is the index pattern tied to this saved search.`;
calloutTitle = (<FormattedMessage
id="kbn.management.objects.objectsTable.relationships.search.calloutTitle"
defaultMessage="Saved Search"
/>);
calloutText = (<FormattedMessage
id="kbn.management.objects.objectsTable.relationships.search.calloutText"
defaultMessage="Here is the index pattern tied to this saved search."
/>);
}
break;
case 'visualization':
calloutText = `Here are some dashboards which contain this visualization. If
you delete this visualization, these dashboards will no longer
show them.`;
calloutText = (<FormattedMessage
id="kbn.management.objects.objectsTable.relationships.visualization.calloutText"
defaultMessage="Here are some dashboards which contain this visualization. If
you delete this visualization, these dashboards will no longer
show them."
/>);
break;
case 'index-pattern':
if (type === 'visualizations') {
calloutText = `Here are some visualizations that use this index pattern. If
you delete this index pattern, these visualizations will not
longer work properly.`;
calloutText = (<FormattedMessage
id="kbn.management.objects.objectsTable.relationships.indexPattern.visualizations.calloutText"
defaultMessage="Here are some visualizations that use this index pattern. If
you delete this index pattern, these visualizations will not
longer work properly."
/>);
} else if (type === 'searches') {
calloutText = `Here are some saved searches that use this index pattern. If
you delete this index pattern, these saved searches will not
longer work properly.`;
calloutText = (<FormattedMessage
id="kbn.management.objects.objectsTable.relationships.indexPattern.searches.calloutText"
defaultMessage="Here are some saved searches that use this index pattern. If
you delete this index pattern, these saved searches will not
longer work properly."
/>);
}
break;
}
@ -184,7 +220,9 @@ export class Relationships extends Component {
),
},
{
name: 'Title',
name: intl.formatMessage({
id: 'kbn.management.objects.objectsTable.relationships.columnTitleName', defaultMessage: 'Title'
}),
field: 'title',
render: (title, item) => (
<EuiLink href={`${getEditUrl(item.id, type)}`}>
@ -193,11 +231,19 @@ export class Relationships extends Component {
),
},
{
name: 'Actions',
name: intl.formatMessage({
id: 'kbn.management.objects.objectsTable.relationships.columnActionsName', defaultMessage: 'Actions'
}),
actions: [
{
name: 'In app',
description: 'View this saved object within Kibana',
name: intl.formatMessage({
id: 'kbn.management.objects.objectsTable.relationships.columnActions.inAppName',
defaultMessage: 'In app'
}),
description: intl.formatMessage({
id: 'kbn.management.objects.objectsTable.relationships.columnActions.inAppDescription',
defaultMessage: 'View this saved object within Kibana'
}),
icon: 'eye',
onClick: object => goInApp(object.id, type),
},
@ -240,3 +286,5 @@ export class Relationships extends Component {
);
}
}
export const Relationships = injectI18n(RelationshipsUI);

View file

@ -30,7 +30,11 @@ exports[`Table should render normally 1`] = `
onClick={[Function]}
type="button"
>
Delete
<FormattedMessage
defaultMessage="Delete"
id="kbn.management.objects.objectsTable.table.deleteButtonLabel"
values={Object {}}
/>
</EuiButton>,
<EuiButton
color="primary"
@ -41,7 +45,11 @@ exports[`Table should render normally 1`] = `
onClick={[Function]}
type="button"
>
Export
<FormattedMessage
defaultMessage="Export"
id="kbn.management.objects.objectsTable.table.exportButtonLabel"
values={Object {}}
/>
</EuiButton>,
]
}

View file

@ -18,7 +18,7 @@
*/
import React from 'react';
import { shallow } from 'enzyme';
import { shallowWithIntl } from 'test_utils/enzyme_helpers';
jest.mock('ui/errors', () => ({
SavedObjectNotFound: class SavedObjectNotFound extends Error {
@ -64,8 +64,8 @@ describe('Table', () => {
onShowRelationships: () => {},
};
const component = shallow(
<Table
const component = shallowWithIntl(
<Table.WrappedComponent
{...props}
/>
);

View file

@ -30,8 +30,9 @@ import {
EuiToolTip
} from '@elastic/eui';
import { getSavedObjectLabel, getSavedObjectIcon } from '../../../../lib';
import { FormattedMessage, injectI18n } from '@kbn/i18n/react';
export class Table extends PureComponent {
class TableUI extends PureComponent {
static propTypes = {
selectedSavedObjects: PropTypes.array.isRequired,
selectionConfig: PropTypes.shape({
@ -78,6 +79,7 @@ export class Table extends PureComponent {
goInApp,
getEditUrl,
onShowRelationships,
intl,
} = this.props;
const pagination = {
@ -91,7 +93,7 @@ export class Table extends PureComponent {
{
type: 'field_value_selection',
field: 'type',
name: 'Type',
name: intl.formatMessage({ id: 'kbn.management.objects.objectsTable.table.typeFilterName', defaultMessage: 'Type' }),
multiSelect: 'or',
options: filterOptions,
},
@ -108,10 +110,13 @@ export class Table extends PureComponent {
const columns = [
{
field: 'type',
name: 'Type',
name: intl.formatMessage({ id: 'kbn.management.objects.objectsTable.table.columnTypeName', defaultMessage: 'Type' }),
width: '50px',
align: 'center',
description: `Type of the saved object`,
description:
intl.formatMessage({
id: 'kbn.management.objects.objectsTable.table.columnTypeDescription', defaultMessage: 'Type of the saved object'
}),
sortable: false,
render: type => {
return (
@ -130,8 +135,11 @@ export class Table extends PureComponent {
},
{
field: 'title',
name: 'Title',
description: `Title of the saved object`,
name: intl.formatMessage({ id: 'kbn.management.objects.objectsTable.table.columnTitleName', defaultMessage: 'Title' }),
description:
intl.formatMessage({
id: 'kbn.management.objects.objectsTable.table.columnTitleDescription', defaultMessage: 'Title of the saved object'
}),
dataType: 'string',
sortable: false,
render: (title, object) => (
@ -139,20 +147,32 @@ export class Table extends PureComponent {
),
},
{
name: 'Actions',
name: intl.formatMessage({ id: 'kbn.management.objects.objectsTable.table.columnActionsName', defaultMessage: 'Actions' }),
actions: [
{
name: 'In app',
name: intl.formatMessage({
id: 'kbn.management.objects.objectsTable.table.columnActions.viewInAppActionName', defaultMessage: 'In app'
}),
description:
'View this saved object within Kibana',
intl.formatMessage({
id: 'kbn.management.objects.objectsTable.table.columnActions.viewInAppActionDescription',
defaultMessage: 'View this saved object within Kibana'
}),
type: 'icon',
icon: 'eye',
onClick: object => goInApp(object.id, object.type),
},
{
name: 'Relationships',
name:
intl.formatMessage({
id: 'kbn.management.objects.objectsTable.table.columnActions.viewRelationshipsActionName',
defaultMessage: 'Relationships'
}),
description:
'View the relationships this saved object has to other saved objects',
intl.formatMessage({
id: 'kbn.management.objects.objectsTable.table.columnActions.viewRelationshipsActionDescription',
defaultMessage: 'View the relationships this saved object has to other saved objects'
}),
type: 'icon',
icon: 'kqlSelector',
onClick: object =>
@ -175,7 +195,10 @@ export class Table extends PureComponent {
onClick={onDelete}
isDisabled={selectedSavedObjects.length === 0}
>
Delete
<FormattedMessage
id="kbn.management.objects.objectsTable.table.deleteButtonLabel"
defaultMessage="Delete"
/>
</EuiButton>,
<EuiButton
key="exportSO"
@ -183,7 +206,10 @@ export class Table extends PureComponent {
onClick={onExport}
isDisabled={selectedSavedObjects.length === 0}
>
Export
<FormattedMessage
id="kbn.management.objects.objectsTable.table.exportButtonLabel"
defaultMessage="Export"
/>
</EuiButton>,
]}
/>
@ -203,3 +229,5 @@ export class Table extends PureComponent {
);
}
}
export const Table = injectI18n(TableUI);

View file

@ -51,6 +51,7 @@ import {
getSavedObjectLabel,
} from '../../lib';
import { ensureMinimumTime } from '../../../indices/create_index_pattern_wizard/lib/ensure_minimum_time';
import { FormattedMessage, injectI18n } from '@kbn/i18n/react';
export const INCLUDED_TYPES = [
'index-pattern',
@ -59,7 +60,7 @@ export const INCLUDED_TYPES = [
'search',
];
export class ObjectsTable extends Component {
class ObjectsTableUI extends Component {
static propTypes = {
savedObjectsClient: PropTypes.object.isRequired,
indexPatterns: PropTypes.object.isRequired,
@ -383,6 +384,7 @@ export class ObjectsTable extends Component {
isDeleting,
selectedSavedObjects,
} = this.state;
const { intl } = this.props;
if (!isShowingDeleteConfirmModal) {
return null;
@ -406,20 +408,47 @@ export class ObjectsTable extends Component {
modal = (
<EuiConfirmModal
title="Delete saved objects"
title={
<FormattedMessage
id="kbn.management.objects.objectsTable.deleteSavedObjectsConfirmModalTitle"
defaultMessage="Delete saved objects"
/>
}
onCancel={onCancel}
onConfirm={onConfirm}
cancelButtonText="Cancel"
confirmButtonText={isDeleting ? 'Deleting...' : 'Delete'}
cancelButtonText={(
<FormattedMessage
id="kbn.management.objects.objectsTable.deleteSavedObjectsConfirmModal.cancelButtonLabel"
defaultMessage="Cancel"
/>
)}
confirmButtonText={
isDeleting
? (<FormattedMessage
id="kbn.management.objects.objectsTable.deleteSavedObjectsConfirmModal.deleteProcessButtonLabel"
defaultMessage="Deleting…"
/>)
: (<FormattedMessage
id="kbn.management.objects.objectsTable.deleteSavedObjectsConfirmModal.deleteButtonLabel"
defaultMessage="Delete"
/>)
}
defaultFocusedButton={EUI_MODAL_CONFIRM_BUTTON}
>
<p>This action will delete the following saved objects:</p>
<p>
<FormattedMessage
id="kbn.management.objects.deleteSavedObjectsConfirmModalDescription"
defaultMessage="This action will delete the following saved objects:"
/>
</p>
<EuiInMemoryTable
items={selectedSavedObjects}
columns={[
{
field: 'type',
name: 'Type',
name: intl.formatMessage({
id: 'kbn.management.objects.objectsTable.deleteSavedObjectsConfirmModal.typeColumnName', defaultMessage: 'Type'
}),
width: '50px',
render: type => (
<EuiToolTip
@ -432,7 +461,9 @@ export class ObjectsTable extends Component {
},
{
field: 'id',
name: 'Id/Name',
name: intl.formatMessage({
id: 'kbn.management.objects.objectsTable.deleteSavedObjectsConfirmModal.idColumnName', defaultMessage: 'Id/Name'
}),
},
]}
pagination={true}
@ -464,18 +495,34 @@ export class ObjectsTable extends Component {
return (
<EuiOverlayMask>
<EuiConfirmModal
title={`Export ${filteredItemCount} ${filteredItemCount === 1 ? 'object' : 'objects'}`}
title={(<FormattedMessage
id="kbn.management.objects.objectsTable.exportObjectsConfirmModalTitle"
defaultMessage="Export {filteredItemCount, plural, one{# object} other {# objects}}"
values={{
filteredItemCount
}}
/>)}
onCancel={() =>
this.setState({ isShowingExportAllOptionsModal: false })
}
onConfirm={this.onExportAll}
cancelButtonText="Cancel"
confirmButtonText="Export All"
cancelButtonText={(
<FormattedMessage id="kbn.management.objects.objectsTable.exportObjectsConfirmModal.cancelButtonLabel" defaultMessage="Cancel"/>
)}
confirmButtonText={(
<FormattedMessage
id="kbn.management.objects.objectsTable.exportObjectsConfirmModal.exportAllButtonLabel"
defaultMessage="Export All"
/>
)}
defaultFocusedButton={EUI_MODAL_CONFIRM_BUTTON}
>
<p>
Select which types to export. The number in parentheses indicates
how many of this type are available to export.
<FormattedMessage
id="kbn.management.objects.objectsTable.exportObjectsConfirmModalDescription"
defaultMessage="Select which types to export. The number in parentheses indicates
how many of this type are available to export."
/>
</p>
<EuiCheckboxGroup
options={exportAllOptions}
@ -522,7 +569,11 @@ export class ObjectsTable extends Component {
return (
<EuiPage>
<EuiPageBody>
<EuiPageContent verticalPosition="center" horizontalPosition="center" style={{ maxWidth: 1000, marginTop: 16, marginBottom: 16 }}>
<EuiPageContent
verticalPosition="center"
horizontalPosition="center"
style={{ maxWidth: 1000, marginTop: 16, marginBottom: 16 }}
>
{this.renderFlyout()}
{this.renderRelationships()}
{this.renderDeleteConfirmModal()}
@ -560,3 +611,5 @@ export class ObjectsTable extends Component {
);
}
}
export const ObjectsTable = injectI18n(ObjectsTableUI);

View file

@ -17,6 +17,7 @@
* under the License.
*/
import { i18n } from '@kbn/i18n';
import { management } from 'ui/management';
import './_view';
import './_objects';
@ -29,7 +30,9 @@ import { FeatureCatalogueRegistryProvider, FeatureCatalogueCategory } from 'ui/r
uiModules.get('apps/management');
management.getSection('kibana').register('objects', {
display: 'Saved Objects',
display: i18n.translate('kbn.management.objects.savedObjectsSectionLabel', {
defaultMessage: 'Saved Objects',
}),
order: 10,
url: '#/management/kibana/objects'
});
@ -37,8 +40,12 @@ management.getSection('kibana').register('objects', {
FeatureCatalogueRegistryProvider.register(() => {
return {
id: 'saved_objects',
title: 'Saved Objects',
description: 'Import, export, and manage your saved searches, visualizations, and dashboards.',
title: i18n.translate('kbn.management.objects.savedObjectsTitle', {
defaultMessage: 'Saved Objects',
}),
description: i18n.translate('kbn.management.objects.savedObjectsDescription', {
defaultMessage: 'Import, export, and manage your saved searches, visualizations, and dashboards.',
}),
icon: 'savedObjectsApp',
path: '/app/kibana#/management/kibana/objects',
showOnHomePage: true,

View file

@ -18,6 +18,7 @@
*/
import { SavedObjectNotFound } from 'ui/errors';
import { i18n } from '@kbn/i18n';
async function getSavedObject(doc, services) {
const service = services.find(service => service.type === doc._type);
@ -36,7 +37,16 @@ function addJsonFieldToIndexPattern(target, sourceString, fieldName, indexName)
try {
target[fieldName] = JSON.parse(sourceString);
} catch (error) {
throw new Error(`Error encountered parsing ${fieldName} for index pattern ${indexName}: ${error.message}`);
throw new Error(
i18n.translate('kbn.management.objects.parsingFieldErrorMessage', {
defaultMessage: 'Error encountered parsing {fieldName} for index pattern {indexName}: {errorMessage}',
values: {
fieldName,
indexName,
errorMessage: error.message,
}
}),
);
}
}
}