From 00d1f3e5e20d422123a0794b230201ca8d3c670c Mon Sep 17 00:00:00 2001 From: Alexandr Ogarkov Date: Tue, 9 Oct 2018 12:25:26 +0300 Subject: [PATCH] fix tests and update snapshots --- .../management/sections/objects/_objects.js | 51 ++--- .../management/sections/objects/_view.html | 87 +++++--- .../management/sections/objects/_view.js | 13 +- .../__snapshots__/objects_table.test.js.snap | 72 ++++++- .../__jest__/objects_table.test.js | 56 ++--- .../__snapshots__/flyout.test.js.snap | 108 ++++++++-- .../components/flyout/__jest__/flyout.test.js | 16 +- .../objects_table/components/flyout/flyout.js | 197 ++++++++++++++---- .../components/header/__jest__/header.test.js | 6 +- .../objects_table/components/header/header.js | 40 +++- .../__snapshots__/relationships.test.js.snap | 75 +++++-- .../__jest__/relationships.test.js | 22 +- .../components/relationships/relationships.js | 92 +++++--- .../__jest__/__snapshots__/table.test.js.snap | 12 +- .../components/table/__jest__/table.test.js | 6 +- .../objects_table/components/table/table.js | 48 +++-- .../components/objects_table/objects_table.js | 64 ++++-- .../management/sections/objects/index.js | 13 +- .../objects/lib/resolve_saved_objects.js | 12 +- 19 files changed, 723 insertions(+), 267 deletions(-) diff --git a/src/core_plugins/kibana/public/management/sections/objects/_objects.js b/src/core_plugins/kibana/public/management/sections/objects/_objects.js index 06110912601d9..f622a8cfd2e06 100644 --- a/src/core_plugins/kibana/public/management/sections/objects/_objects.js +++ b/src/core_plugins/kibana/public/management/sections/objects/_objects.js @@ -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( - { - 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; - } + + { + 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(); + }} + /> + , node, ); }); diff --git a/src/core_plugins/kibana/public/management/sections/objects/_view.html b/src/core_plugins/kibana/public/management/sections/objects/_view.html index 50c31e758691d..2f608f8c828ce 100644 --- a/src/core_plugins/kibana/public/management/sections/objects/_view.html +++ b/src/core_plugins/kibana/public/management/sections/objects/_view.html @@ -3,9 +3,12 @@
-

- Edit {{ title }} -

+

@@ -15,7 +18,11 @@

> - View {{ title }} + @@ -25,7 +32,11 @@

> - Delete {{ title }} +

@@ -39,36 +50,40 @@

- - There is a problem with this saved object - +
- The saved search associated with this object no longer exists. -
+ i18n-id="kbn.management.objects.view.savedSearchErrorMessage" + i18n-default-message="The saved search associated with this object no longer exists." + >
- The index pattern associated with this object no longer exists. -
+ i18n-id="kbn.management.objects.view.indexPatternErrorMessage" + i18n-default-message="The index pattern associated with this object no longer exists." + >
- A field associated with this object no longer exists in the index pattern. -
+ i18n-id="kbn.management.objects.view.indexPatternFieldErrorMessage" + i18n-default-message="A field associated with this object no longer exists in the index pattern.." + >

-
- If you know what this error means, go ahead and fix it — otherwise click the delete button above. -
+
@@ -78,14 +93,19 @@

- - Proceed with caution! - +
-
- 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’t be. +
@@ -143,20 +163,21 @@

+ i18n-id="kbn.management.objects.view.saveButtonLabel" + i18n-default-message="Save { title } Object" + i18n-values="{ title }" + > + i18n-id="kbn.management.objects.view.cancelButtonLabel" + i18n-default-message="Cancel" + >

diff --git a/src/core_plugins/kibana/public/management/sections/objects/_view.js b/src/core_plugins/kibana/public/management/sections/objects/_view.js index 9c42073983529..db79e63dca081 100644 --- a/src/core_plugins/kibana/public/management/sections/objects/_view.js +++ b/src/core_plugins/kibana/public/management/sections/objects/_view.js @@ -20,6 +20,7 @@ import _ from 'lodash'; import angular from 'angular'; import rison from 'rison-node'; +import { i18n } from '@kbn/i18n'; import { savedObjectManagementRegistry } from '../../saved_object_registry'; import objectViewHTML from './_view.html'; import uiRoutes from 'ui/routes'; @@ -199,11 +200,17 @@ uiModules.get('apps/management') } const confirmModalOptions = { onConfirm: doDelete, - confirmButtonText: 'Delete', - title: 'Delete saved Kibana object?' + confirmButtonText: i18n.translate('kbn.management.objects.confirmModalOptions.DeleteButtonLabel', { + defaultMessage: 'Delete', + }), + title: i18n.translate('kbn.management.objects.confirmModalOptions.DeleteButtonTitle', { + defaultMessage: 'Delete saved Kibana object?' + }), }; confirmModal( - `You can't recover deleted objects`, + i18n.translate('kbn.management.objects.confirmModalOptions.warningTextMessage', { + defaultMessage: 'You can\'t recover deleted objects', + }), confirmModalOptions ); }; diff --git a/src/core_plugins/kibana/public/management/sections/objects/components/objects_table/__jest__/__snapshots__/objects_table.test.js.snap b/src/core_plugins/kibana/public/management/sections/objects/components/objects_table/__jest__/__snapshots__/objects_table.test.js.snap index 36cfb413e146f..2d25d88fd6374 100644 --- a/src/core_plugins/kibana/public/management/sections/objects/components/objects_table/__jest__/__snapshots__/objects_table.test.js.snap +++ b/src/core_plugins/kibana/public/management/sections/objects/components/objects_table/__jest__/__snapshots__/objects_table.test.js.snap @@ -3,15 +3,37 @@ exports[`ObjectsTable delete should show a confirm modal 1`] = ` + } + confirmButtonText={ + + } defaultFocusedButton="confirm" onCancel={[Function]} onConfirm={[Function]} - title="Delete saved objects" + title={ + + } >

- This action will delete the following saved objects: +

+ } + confirmButtonText={ + + } defaultFocusedButton="confirm" onCancel={[Function]} onConfirm={[Function]} - title="Export 4 objects" + title={ + + } >

- Select which types to export. The number in parentheses indicates how many of this type are available to export. +

- ({ Header: () => 'Header', @@ -157,8 +159,8 @@ describe('ObjectsTable', () => { }); it('should render normally', async () => { - const component = shallow( - @@ -194,8 +196,8 @@ describe('ObjectsTable', () => { const { retrieveAndExportDocs } = require('../../../lib/retrieve_and_export_docs'); - const component = shallow( - @@ -216,8 +218,8 @@ describe('ObjectsTable', () => { }); it('should allow the user to choose when exporting all', async () => { - const component = shallow( - ); @@ -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( - ); @@ -259,8 +261,8 @@ describe('ObjectsTable', () => { describe('import', () => { it('should show the flyout', async () => { - const component = shallow( - ); @@ -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( - ); @@ -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( - ); @@ -315,8 +317,8 @@ describe('ObjectsTable', () => { }); it('should show the flyout', async () => { - const component = shallow( - ); @@ -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( - ); @@ -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( - ); @@ -403,8 +405,8 @@ describe('ObjectsTable', () => { delete: jest.fn(), }; - const component = shallow( - diff --git a/src/core_plugins/kibana/public/management/sections/objects/components/objects_table/components/flyout/__jest__/__snapshots__/flyout.test.js.snap b/src/core_plugins/kibana/public/management/sections/objects/components/objects_table/components/flyout/__jest__/__snapshots__/flyout.test.js.snap index 3464cbb2acba2..bf3b68bdf799e 100644 --- a/src/core_plugins/kibana/public/management/sections/objects/components/objects_table/components/flyout/__jest__/__snapshots__/flyout.test.js.snap +++ b/src/core_plugins/kibana/public/management/sections/objects/components/objects_table/components/flyout/__jest__/__snapshots__/flyout.test.js.snap @@ -16,7 +16,11 @@ exports[`Flyout conflicts should allow conflict resolution 1`] = ` size="m" >

- Import saved objects +

@@ -27,20 +31,36 @@ exports[`Flyout conflicts should allow conflict resolution 1`] = ` color="warning" iconType="help" size="m" - title="Index Pattern Conflicts" + title={ + + } >

- 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 - - - create a new index pattern - - - if necessary. + + + , + } + } + />

@@ -123,7 +143,11 @@ exports[`Flyout conflicts should allow conflict resolution 1`] = ` size="s" type="button" > - Cancel + - Confirm all changes + @@ -153,7 +181,13 @@ exports[`Flyout conflicts should handle errors 1`] = ` color="danger" iconType="cross" size="m" - title="Sorry, there was an error" + title={ + + } >

foobar @@ -177,7 +211,11 @@ exports[`Flyout should render import step 1`] = ` size="m" >

- Import saved objects +

@@ -187,11 +225,23 @@ exports[`Flyout should render import step 1`] = ` describedByIds={Array []} fullWidth={false} hasEmptyLabelSpace={false} - label="Please select a JSON file to import" + label={ + + } > + } onChange={[Function]} /> @@ -203,7 +253,13 @@ exports[`Flyout should render import step 1`] = ` + } name="overwriteAll" onChange={[Function]} /> @@ -231,7 +287,11 @@ exports[`Flyout should render import step 1`] = ` size="s" type="button" > - Cancel + - Import + diff --git a/src/core_plugins/kibana/public/management/sections/objects/components/objects_table/components/flyout/__jest__/flyout.test.js b/src/core_plugins/kibana/public/management/sections/objects/components/objects_table/components/flyout/__jest__/flyout.test.js index 68b7d46b18160..1866b499e712b 100644 --- a/src/core_plugins/kibana/public/management/sections/objects/components/objects_table/components/flyout/__jest__/flyout.test.js +++ b/src/core_plugins/kibana/public/management/sections/objects/components/objects_table/components/flyout/__jest__/flyout.test.js @@ -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(); + const component = shallowWithIntl(); // 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(); + const component = shallowWithIntl(); // 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(); + const component = shallowWithIntl(); // 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(); + const component = shallowWithIntl(); // 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(); + const component = shallowWithIntl(); // 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(); + const component = shallowWithIntl(); // 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(); + const component = shallowWithIntl(); // Ensure all promises resolve await new Promise(resolve => process.nextTick(resolve)); diff --git a/src/core_plugins/kibana/public/management/sections/objects/components/objects_table/components/flyout/flyout.js b/src/core_plugins/kibana/public/management/sections/objects/components/objects_table/components/flyout/flyout.js index f70177c341039..c254c9dc9f478 100644 --- a/src/core_plugins/kibana/public/management/sections/objects/components/objects_table/components/flyout/flyout.js +++ b/src/core_plugins/kibana/public/management/sections/objects/components/objects_table/components/flyout/flyout.js @@ -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.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.flyout.importFileTypeErrorMessage', + 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.flyout.confirmImport.resolvingConflictLoadingMessage', + 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.flyout.confirmImport.savingConflictLoadingMessage', + defaultMessage: 'Saving conflicts...', + }), + }); importCount += await saveObjects( conflictedSavedObjectsLinkedToSavedSearches, isOverwriteAllChecked ); this.setState({ - loadingMessage: 'Ensure saved searches are linked properly...', + loadingMessage: intl.formatMessage({ + id: 'kbn.management.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.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.flyout.renderConflicts.columnIdName', + defaultMessage: 'ID', + }), + description: intl.formatMessage({ + id: 'kbn.management.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.flyout.renderConflicts.columnCountName', + defaultMessage: 'Count', + }), + description: intl.formatMessage({ + id: 'kbn.management.flyout.renderConflicts.columnCountDescription', + defaultMessage: 'How many affected objects', + }), render: list => { return {list.length}; }, }, { field: 'list', - name: 'Sample of affected objects', - description: `Sample of affected objects`, + name: intl.formatMessage({ + id: 'kbn.management.flyout.renderConflicts.columnSampleOfAffectedObjectsName', + defaultMessage: 'Sample of affected objects', + }), + description: intl.formatMessage({ + id: 'kbn.management.flyout.renderConflicts.columnSampleOfAffectedObjectsDescription', + defaultMessage: 'Sample of affected objects', + }), render: list => { return (
    @@ -327,7 +369,10 @@ export class Flyout extends Component { }, { field: 'existingIndexPatternId', - name: 'New index pattern', + name: intl.formatMessage({ + id: 'kbn.management.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 ( + )} color="danger" iconType="cross" > @@ -412,12 +459,18 @@ export class Flyout extends Component { if (failedImports.length && !this.hasConflicts) { return ( + )} color="warning" iconType="help" >

    - Failed to import {failedImports.length} of {importCount + failedImports.length} objects. +

    {failedImports.map(({ error }) => getField(error, 'body.message', error.message || '')).join(' ')} @@ -431,7 +484,12 @@ export class Flyout extends Component { return ( + )} color="primary" /> ); @@ -440,11 +498,22 @@ export class Flyout extends Component { return ( + )} color="success" iconType="check" > -

    Successfully imported {importCount} objects.

    +

    + +

    ); } @@ -455,16 +524,33 @@ export class Flyout extends Component { return ( - + + )} + > + )} onChange={this.setImportFile} /> + )} data-test-subj="importSavedObjectsOverwriteToggle" checked={isOverwriteAllChecked} onChange={this.changeOverwriteAll} @@ -488,7 +574,10 @@ export class Flyout extends Component { fill data-test-subj="importSavedObjectsDoneBtn" > - Done + ); } else if (this.hasConflicts) { @@ -500,7 +589,10 @@ export class Flyout extends Component { isLoading={isLoading} data-test-subj="importSavedObjectsConfirmBtn" > - Confirm all changes + ); } else { @@ -512,7 +604,10 @@ export class Flyout extends Component { isLoading={isLoading} data-test-subj="importSavedObjectsImportBtn" > - Import + ); } @@ -521,7 +616,10 @@ export class Flyout extends Component { - Cancel + {confirmButton} @@ -542,20 +640,32 @@ export class Flyout extends Component { + )} color="warning" iconType="help" >

    - 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{' '} - { - - create a new index pattern - - }{' '} - if necessary. + + + + ) + }} + />

    @@ -569,7 +679,12 @@ export class Flyout extends Component { -

    Import saved objects

    +

    + +

    {this.renderSubheader()}
    @@ -584,3 +699,5 @@ export class Flyout extends Component { ); } } + +export const Flyout = injectI18n(FlyoutUI); diff --git a/src/core_plugins/kibana/public/management/sections/objects/components/objects_table/components/header/__jest__/header.test.js b/src/core_plugins/kibana/public/management/sections/objects/components/objects_table/components/header/__jest__/header.test.js index ee8db59273c46..848261cceb3a5 100644 --- a/src/core_plugins/kibana/public/management/sections/objects/components/objects_table/components/header/__jest__/header.test.js +++ b/src/core_plugins/kibana/public/management/sections/objects/components/objects_table/components/header/__jest__/header.test.js @@ -18,7 +18,7 @@ */ import React from 'react'; -import { shallow } from 'enzyme'; +import { shallowWithIntl } from 'test_utils/enzyme_helpers'; import { Header } from '../header'; @@ -32,8 +32,8 @@ describe('Header', () => { filteredCount: 2, }; - const component = shallow( -
    ); diff --git a/src/core_plugins/kibana/public/management/sections/objects/components/objects_table/components/header/header.js b/src/core_plugins/kibana/public/management/sections/objects/components/objects_table/components/header/header.js index 2ac10addbd4a2..c4c8ce8d8046d 100644 --- a/src/core_plugins/kibana/public/management/sections/objects/components/objects_table/components/header/header.js +++ b/src/core_plugins/kibana/public/management/sections/objects/components/objects_table/components/header/header.js @@ -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 = ({ -

    Saved Objects

    +

    + +

    @@ -53,7 +59,16 @@ export const Header = ({ data-test-subj="exportAllObjects" onClick={onExportAll} > - Export {filteredCount} {filteredCount === 1 ? 'object' : 'objects'} + @@ -63,7 +78,10 @@ export const Header = ({ data-test-subj="importObjects" onClick={onImport} > - Import + @@ -72,7 +90,10 @@ export const Header = ({ iconType="refresh" onClick={onRefresh} > - Refresh +
    @@ -82,10 +103,13 @@ export const Header = ({

    - 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. +

    diff --git a/src/core_plugins/kibana/public/management/sections/objects/components/objects_table/components/relationships/__jest__/__snapshots__/relationships.test.js.snap b/src/core_plugins/kibana/public/management/sections/objects/components/objects_table/components/relationships/__jest__/__snapshots__/relationships.test.js.snap index 961d5480a2e28..6a2e73b4f7119 100644 --- a/src/core_plugins/kibana/public/management/sections/objects/components/objects_table/components/relationships/__jest__/__snapshots__/relationships.test.js.snap +++ b/src/core_plugins/kibana/public/management/sections/objects/components/objects_table/components/relationships/__jest__/__snapshots__/relationships.test.js.snap @@ -52,12 +52,21 @@ exports[`Relationships should render dashboards normally 1`] = ` + } >

    - Here are some visualizations used on this dashboard. You can - safely delete this dashboard and the visualizations will still - work properly. +

    @@ -142,7 +151,13 @@ exports[`Relationships should render errors 1`] = ` + } > foo @@ -242,10 +257,20 @@ exports[`Relationships should render searches normally 1`] = ` + } >

    - Here is the index pattern tied to this saved search. +

    @@ -299,12 +324,22 @@ exports[`Relationships should render searches normally 1`] = ` + } >

    - Here are some visualizations that use this saved search. If - you delete this saved search, these visualizations will not - longer work properly. +

    @@ -402,12 +437,22 @@ exports[`Relationships should render visualizations normally 1`] = ` + } >

    - Here are some dashboards which contain this visualization. If - you delete this visualization, these dashboards will no longer - show them. +

    diff --git a/src/core_plugins/kibana/public/management/sections/objects/components/objects_table/components/relationships/__jest__/relationships.test.js b/src/core_plugins/kibana/public/management/sections/objects/components/objects_table/components/relationships/__jest__/relationships.test.js index 6e1e591fa9a9b..9eb269ea46440 100644 --- a/src/core_plugins/kibana/public/management/sections/objects/components/objects_table/components/relationships/__jest__/relationships.test.js +++ b/src/core_plugins/kibana/public/management/sections/objects/components/objects_table/components/relationships/__jest__/relationships.test.js @@ -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( - ); @@ -102,8 +102,8 @@ describe('Relationships', () => { close: jest.fn(), }; - const component = shallow( - ); @@ -140,8 +140,8 @@ describe('Relationships', () => { close: jest.fn(), }; - const component = shallow( - ); @@ -178,8 +178,8 @@ describe('Relationships', () => { close: jest.fn(), }; - const component = shallow( - ); @@ -209,8 +209,8 @@ describe('Relationships', () => { close: jest.fn(), }; - const component = shallow( - ); diff --git a/src/core_plugins/kibana/public/management/sections/objects/components/objects_table/components/relationships/relationships.js b/src/core_plugins/kibana/public/management/sections/objects/components/objects_table/components/relationships/relationships.js index 50b83de790c55..b40b0d8fc180a 100644 --- a/src/core_plugins/kibana/public/management/sections/objects/components/objects_table/components/relationships/relationships.js +++ b/src/core_plugins/kibana/public/management/sections/objects/components/objects_table/components/relationships/relationships.js @@ -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 ( - + + )} + color="danger" + > {error} ); } renderRelationships() { - const { getEditUrl, goInApp } = this.props; + const { getEditUrl, goInApp, intl } = this.props; const { relationships, isLoading, error } = this.state; if (error) { @@ -112,48 +118,72 @@ export class Relationships extends Component { if (list.length === 0) { items.push( - No {type} found. + ); } else { // let node; - let calloutTitle = 'Warning'; + let calloutTitle = (); 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 = (); + calloutText = (); 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 = (); } else { calloutColor = 'success'; - calloutTitle = 'Saved Search'; - calloutText = `Here is the index pattern tied to this saved search.`; + calloutTitle = (); + calloutText = (); } 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 = (); 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 = (); } 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 = (); } break; } @@ -184,7 +214,7 @@ export class Relationships extends Component { ), }, { - name: 'Title', + name: intl.formatMessage({ id: 'kbn.management.objects.relationships.columnTitleName', defaultMessage: 'Title' }), field: 'title', render: (title, item) => ( @@ -193,11 +223,17 @@ export class Relationships extends Component { ), }, { - name: 'Actions', + name: intl.formatMessage({ id: 'kbn.management.objects.relationships.columnActionsName', defaultMessage: 'Actions' }), actions: [ { - name: 'In app', - description: 'View this saved object within Kibana', + name: intl.formatMessage({ + id: 'kbn.management.objects.relationships.columnActions.inAppName', + defaultMessage: 'In app' + }), + description: intl.formatMessage({ + id: 'kbn.management.objects.relationships.columnActions.inAppDescription', + defaultMessage: 'View this saved object within Kibana' + }), icon: 'eye', onClick: object => goInApp(object.id, type), }, @@ -240,3 +276,5 @@ export class Relationships extends Component { ); } } + +export const Relationships = injectI18n(RelationshipsUI); \ No newline at end of file diff --git a/src/core_plugins/kibana/public/management/sections/objects/components/objects_table/components/table/__jest__/__snapshots__/table.test.js.snap b/src/core_plugins/kibana/public/management/sections/objects/components/objects_table/components/table/__jest__/__snapshots__/table.test.js.snap index abd8ee272608f..6b4ae5063694d 100644 --- a/src/core_plugins/kibana/public/management/sections/objects/components/objects_table/components/table/__jest__/__snapshots__/table.test.js.snap +++ b/src/core_plugins/kibana/public/management/sections/objects/components/objects_table/components/table/__jest__/__snapshots__/table.test.js.snap @@ -30,7 +30,11 @@ exports[`Table should render normally 1`] = ` onClick={[Function]} type="button" > - Delete + , - Export + , ] } diff --git a/src/core_plugins/kibana/public/management/sections/objects/components/objects_table/components/table/__jest__/table.test.js b/src/core_plugins/kibana/public/management/sections/objects/components/objects_table/components/table/__jest__/table.test.js index 7a6d9f8296586..41470722a1b3b 100644 --- a/src/core_plugins/kibana/public/management/sections/objects/components/objects_table/components/table/__jest__/table.test.js +++ b/src/core_plugins/kibana/public/management/sections/objects/components/objects_table/components/table/__jest__/table.test.js @@ -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( -
); diff --git a/src/core_plugins/kibana/public/management/sections/objects/components/objects_table/components/table/table.js b/src/core_plugins/kibana/public/management/sections/objects/components/objects_table/components/table/table.js index f9a5dab7fef9b..7589c5ce1561f 100644 --- a/src/core_plugins/kibana/public/management/sections/objects/components/objects_table/components/table/table.js +++ b/src/core_plugins/kibana/public/management/sections/objects/components/objects_table/components/table/table.js @@ -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.table.dropdownFilterByTypeName', defaultMessage: 'Type' }), multiSelect: 'or', options: filterOptions, }, @@ -108,10 +110,11 @@ export class Table extends PureComponent { const columns = [ { field: 'type', - name: 'Type', + name: intl.formatMessage({ id: 'kbn.management.objects.table.columnTypeName', defaultMessage: 'Type' }), width: '50px', align: 'center', - description: `Type of the saved object`, + description: + intl.formatMessage({ id: 'kbn.management.objects.table.columnTypeDescription', defaultMessage: 'Type of the saved object' }), sortable: false, render: type => { return ( @@ -130,8 +133,9 @@ export class Table extends PureComponent { }, { field: 'title', - name: 'Title', - description: `Title of the saved object`, + name: intl.formatMessage({ id: 'kbn.management.objects.table.columnTitleName', defaultMessage: 'Title' }), + description: + intl.formatMessage({ id: 'kbn.management.objects.table.columnTitleDescription', defaultMessage: 'Title of the saved object' }), dataType: 'string', sortable: false, render: (title, object) => ( @@ -139,20 +143,30 @@ export class Table extends PureComponent { ), }, { - name: 'Actions', + name: intl.formatMessage({ id: 'kbn.management.objects.table.columnActionsName', defaultMessage: 'Actions' }), actions: [ { - name: 'In app', + name: intl.formatMessage({ id: 'kbn.management.objects.table.columnActions.viewInAppName', defaultMessage: 'In app' }), description: - 'View this saved object within Kibana', + intl.formatMessage({ + id: 'kbn.management.objects.table.columnActions.viewInAppDescription', + 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.table.columnActions.viewRelationshipsName', + defaultMessage: 'Relationships' + }), description: - 'View the relationships this saved object has to other saved objects', + intl.formatMessage({ + id: 'kbn.management.objects.table.columnActions.viewRelationshipsDescription', + defaultMessage: 'View the relationships this saved object has to other saved objects' + }), type: 'icon', icon: 'kqlSelector', onClick: object => @@ -175,7 +189,10 @@ export class Table extends PureComponent { onClick={onDelete} isDisabled={selectedSavedObjects.length === 0} > - Delete + , - Export + , ]} /> @@ -203,3 +223,5 @@ export class Table extends PureComponent { ); } } + +export const Table = injectI18n(TableUI); diff --git a/src/core_plugins/kibana/public/management/sections/objects/components/objects_table/objects_table.js b/src/core_plugins/kibana/public/management/sections/objects/components/objects_table/objects_table.js index 27d77ca92028f..b589e947bf2d4 100644 --- a/src/core_plugins/kibana/public/management/sections/objects/components/objects_table/objects_table.js +++ b/src/core_plugins/kibana/public/management/sections/objects/components/objects_table/objects_table.js @@ -25,6 +25,7 @@ import { Flyout } from './components/flyout'; import { Relationships } from './components/relationships'; import { Table } from './components/table'; + import { EuiSpacer, Query, @@ -51,6 +52,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 +61,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 +385,7 @@ export class ObjectsTable extends Component { isDeleting, selectedSavedObjects, } = this.state; + const { intl } = this.props; if (!isShowingDeleteConfirmModal) { return null; @@ -406,20 +409,33 @@ export class ObjectsTable extends Component { modal = ( + } onCancel={onCancel} onConfirm={onConfirm} - cancelButtonText="Cancel" - confirmButtonText={isDeleting ? 'Deleting...' : 'Delete'} + cancelButtonText={( + + )} + confirmButtonText={ + isDeleting + ? () + : () + } defaultFocusedButton={EUI_MODAL_CONFIRM_BUTTON} > -

This action will delete the following saved objects:

+

+ +

( )} onCancel={() => this.setState({ isShowingExportAllOptionsModal: false }) } onConfirm={this.onExportAll} - cancelButtonText="Cancel" - confirmButtonText="Export All" + cancelButtonText={( + + )} + confirmButtonText={( + + )} defaultFocusedButton={EUI_MODAL_CONFIRM_BUTTON} >

- Select which types to export. The number in parentheses indicates - how many of this type are available to export. +

- + {this.renderFlyout()} {this.renderRelationships()} {this.renderDeleteConfirmModal()} @@ -560,3 +596,5 @@ export class ObjectsTable extends Component { ); } } + +export const ObjectsTable = injectI18n(ObjectsTableUI); diff --git a/src/core_plugins/kibana/public/management/sections/objects/index.js b/src/core_plugins/kibana/public/management/sections/objects/index.js index b5deddc00e316..6cb8ef88aae7d 100644 --- a/src/core_plugins/kibana/public/management/sections/objects/index.js +++ b/src/core_plugins/kibana/public/management/sections/objects/index.js @@ -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, diff --git a/src/core_plugins/kibana/public/management/sections/objects/lib/resolve_saved_objects.js b/src/core_plugins/kibana/public/management/sections/objects/lib/resolve_saved_objects.js index bf2e91625c26c..a771038128e6c 100644 --- a/src/core_plugins/kibana/public/management/sections/objects/lib/resolve_saved_objects.js +++ b/src/core_plugins/kibana/public/management/sections/objects/lib/resolve_saved_objects.js @@ -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.resolveSavedObjectsParsingErrorMessage', { + defaultMessage: 'Error encountered parsing {fieldName} for index pattern {indexName}: {errorMessage}', + values: { + fieldName, + indexName, + errorMessage: error.message, + } + }), + ); } } }