diff --git a/src/core_plugins/kibana/public/dashboard/components/__snapshots__/exit_full_screen_button.test.js.snap b/src/core_plugins/kibana/public/dashboard/components/__snapshots__/exit_full_screen_button.test.js.snap
index e41e0bf21420..2fe29dd29a59 100644
--- a/src/core_plugins/kibana/public/dashboard/components/__snapshots__/exit_full_screen_button.test.js.snap
+++ b/src/core_plugins/kibana/public/dashboard/components/__snapshots__/exit_full_screen_button.test.js.snap
@@ -28,7 +28,7 @@ exports[`is rendered 1`] = `
class="dshExitFullScreenButton__text"
data-test-subj="exitFullScreenModeText"
>
- Exit full screen
+ Exit full screen
diff --git a/src/core_plugins/kibana/public/dashboard/components/exit_full_screen_button.js b/src/core_plugins/kibana/public/dashboard/components/exit_full_screen_button.js
index 1d95ff0d09aa..d24d3a81017a 100644
--- a/src/core_plugins/kibana/public/dashboard/components/exit_full_screen_button.js
+++ b/src/core_plugins/kibana/public/dashboard/components/exit_full_screen_button.js
@@ -20,6 +20,7 @@
import React, { PureComponent } from 'react';
import PropTypes from 'prop-types';
import chrome from 'ui/chrome';
+import { injectI18n, FormattedMessage } from '@kbn/i18n/react';
import {
KuiButton,
@@ -30,7 +31,7 @@ import {
EuiScreenReaderOnly,
} from '@elastic/eui';
-export class ExitFullScreenButton extends PureComponent {
+class ExitFullScreenButtonUi extends PureComponent {
onKeyDown = (e) => {
if (e.keyCode === keyCodes.ESCAPE) {
@@ -49,11 +50,16 @@ export class ExitFullScreenButton extends PureComponent {
}
render() {
+ const { intl } = this.props;
+
return (
- In full screen mode, press ESC to exit.
+
- Exit full screen
+
+
@@ -76,6 +89,8 @@ export class ExitFullScreenButton extends PureComponent {
}
}
-ExitFullScreenButton.propTypes = {
+ExitFullScreenButtonUi.propTypes = {
onExitFullScreenMode: PropTypes.func.isRequired,
};
+
+export const ExitFullScreenButton = injectI18n(ExitFullScreenButtonUi);
diff --git a/src/core_plugins/kibana/public/dashboard/components/exit_full_screen_button.test.js b/src/core_plugins/kibana/public/dashboard/components/exit_full_screen_button.test.js
index 0fb74f1a29ff..80a52584cf9b 100644
--- a/src/core_plugins/kibana/public/dashboard/components/exit_full_screen_button.test.js
+++ b/src/core_plugins/kibana/public/dashboard/components/exit_full_screen_button.test.js
@@ -24,7 +24,7 @@ jest.mock('ui/chrome',
}), { virtual: true });
import React from 'react';
-import { render, mount } from 'enzyme';
+import { mountWithIntl, renderWithIntl } from 'test_utils/enzyme_helpers';
import sinon from 'sinon';
import chrome from 'ui/chrome';
@@ -36,8 +36,8 @@ import { keyCodes } from '@elastic/eui';
test('is rendered', () => {
- const component = render(
-
{}}/>
+ const component = renderWithIntl(
+ {}}/>
);
expect(component)
@@ -48,8 +48,8 @@ describe('onExitFullScreenMode', () => {
test('is called when the button is pressed', () => {
const onExitHandler = sinon.stub();
- const component = mount(
-
+ const component = mountWithIntl(
+
);
component.find('button').simulate('click');
@@ -60,7 +60,7 @@ describe('onExitFullScreenMode', () => {
test('is called when the ESC key is pressed', () => {
const onExitHandler = sinon.stub();
- mount();
+ mountWithIntl();
const escapeKeyEvent = new KeyboardEvent('keydown', { keyCode: keyCodes.ESCAPE });
document.dispatchEvent(escapeKeyEvent);
@@ -73,8 +73,8 @@ describe('chrome.setVisible', () => {
test('is called with false when the component is rendered', () => {
chrome.setVisible = sinon.stub();
- const component = mount(
- {}} />
+ const component = mountWithIntl(
+ {}} />
);
component.find('button').simulate('click');
@@ -84,8 +84,8 @@ describe('chrome.setVisible', () => {
});
test('is called with true the component is unmounted', () => {
- const component = mount(
- {}} />
+ const component = mountWithIntl(
+ {}} />
);
chrome.setVisible = sinon.stub();
diff --git a/src/core_plugins/kibana/public/dashboard/dashboard_app.html b/src/core_plugins/kibana/public/dashboard/dashboard_app.html
index cc020f33e3db..18c40bda026f 100644
--- a/src/core_plugins/kibana/public/dashboard/dashboard_app.html
+++ b/src/core_plugins/kibana/public/dashboard/dashboard_app.html
@@ -15,7 +15,12 @@
aria-level="1"
ng-if="showPluginBreadcrumbs">
{{ getDashTitle() }}
@@ -46,22 +51,64 @@
ng-show="getShouldShowEditHelp()"
class="dshStartScreen"
>
-
- This dashboard is empty. Let’s fill it up!
+
-
- Click the Add button in the menu bar above to add a visualization to the dashboard.
If you haven't set up any visualizations yet, visit the Visualize app to create your first visualization.
+
+
+
+
-
- This dashboard is empty. Let’s fill it up!
+
- Click the Edit button in the menu bar above to start working on your new dashboard.
+
+
+
diff --git a/src/core_plugins/kibana/public/dashboard/dashboard_app.js b/src/core_plugins/kibana/public/dashboard/dashboard_app.js
index 13f6c1006c95..3a1fd54a24de 100644
--- a/src/core_plugins/kibana/public/dashboard/dashboard_app.js
+++ b/src/core_plugins/kibana/public/dashboard/dashboard_app.js
@@ -56,7 +56,6 @@ import { timefilter } from 'ui/timefilter';
import { getUnhashableStatesProvider } from 'ui/state_management/state_hashing';
import { DashboardViewportProvider } from './viewport/dashboard_viewport_provider';
-import { i18n } from '@kbn/i18n';
const app = uiModules.get('app/dashboard', [
'elasticsearch',
@@ -90,7 +89,8 @@ app.directive('dashboardApp', function ($injector) {
getAppState,
dashboardConfig,
localStorage,
- breadcrumbState
+ breadcrumbState,
+ i18n,
) {
const filterManager = Private(FilterManagerProvider);
const filterBar = Private(FilterBarQueryFilterProvider);
@@ -184,7 +184,7 @@ app.directive('dashboardApp', function ($injector) {
const updateBreadcrumbs = () => {
breadcrumbState.set([
{
- text: i18n.translate('kbn.dashboard.dashboardAppBreadcrumbsTitle', {
+ text: i18n('kbn.dashboard.dashboardAppBreadcrumbsTitle', {
defaultMessage: 'Dashboard',
}),
href: $scope.landingPageUrl()
@@ -273,14 +273,22 @@ app.directive('dashboardApp', function ($injector) {
}
confirmModal(
- `Once you discard your changes, there's no getting them back.`,
+ i18n('kbn.dashboard.changeViewModeConfirmModal.discardChangesDescription',
+ { defaultMessage: `Once you discard your changes, there's no getting them back.` }
+ ),
{
onConfirm: revertChangesAndExitEditMode,
onCancel: _.noop,
- confirmButtonText: 'Discard changes',
- cancelButtonText: 'Continue editing',
+ confirmButtonText: i18n('kbn.dashboard.changeViewModeConfirmModal.confirmButtonLabel',
+ { defaultMessage: 'Discard changes' }
+ ),
+ cancelButtonText: i18n('kbn.dashboard.changeViewModeConfirmModal.cancelButtonLabel',
+ { defaultMessage: 'Continue editing' }
+ ),
defaultFocusedButton: ConfirmationButtonTypes.CANCEL,
- title: 'Discard changes to dashboard?'
+ title: i18n('kbn.dashboard.changeViewModeConfirmModal.discardChangesTitle',
+ { defaultMessage: 'Discard changes to dashboard?' }
+ )
}
);
};
@@ -302,7 +310,12 @@ app.directive('dashboardApp', function ($injector) {
.then(function (id) {
if (id) {
toastNotifications.addSuccess({
- title: `Dashboard '${dash.title}' was saved`,
+ title: i18n('kbn.dashboard.dashboardWasSavedSuccessMessage',
+ {
+ defaultMessage: `Dashboard '{dashTitle}' was saved`,
+ values: { dashTitle: dash.title },
+ },
+ ),
'data-test-subj': 'saveDashboardSuccess',
});
@@ -316,7 +329,15 @@ app.directive('dashboardApp', function ($injector) {
return { id };
}).catch((error) => {
toastNotifications.addDanger({
- title: `Dashboard '${dash.title}' was not saved. Error: ${error.message}`,
+ title: i18n('kbn.dashboard.dashboardWasNotSavedDangerMessage',
+ {
+ defaultMessage: `Dashboard '{dashTitle}' was not saved. Error: {errorMessage}`,
+ values: {
+ dashTitle: dash.title,
+ errorMessage: error.message,
+ },
+ },
+ ),
'data-test-subj': 'saveDashboardFailure',
});
return { error };
diff --git a/src/core_plugins/kibana/public/dashboard/dashboard_state_manager.js b/src/core_plugins/kibana/public/dashboard/dashboard_state_manager.js
index a9a937231859..aea6ba3b9642 100644
--- a/src/core_plugins/kibana/public/dashboard/dashboard_state_manager.js
+++ b/src/core_plugins/kibana/public/dashboard/dashboard_state_manager.js
@@ -17,6 +17,7 @@
* under the License.
*/
+import { i18n } from '@kbn/i18n';
import _ from 'lodash';
import moment from 'moment';
@@ -550,7 +551,9 @@ export class DashboardStateManager {
*/
syncTimefilterWithDashboard(timeFilter, quickTimeRanges) {
if (!this.getIsTimeSavedWithDashboard()) {
- throw new Error('The time is not saved with this dashboard so should not be synced.');
+ throw new Error(i18n.translate('kbn.dashboard.stateManager.timeNotSavedWithDashboardErrorMessage', {
+ defaultMessage: 'The time is not saved with this dashboard so should not be synced.',
+ }));
}
let mode;
diff --git a/src/core_plugins/kibana/public/dashboard/dashboard_strings.js b/src/core_plugins/kibana/public/dashboard/dashboard_strings.js
index 7dffc94c9e97..a0d2af3e9c00 100644
--- a/src/core_plugins/kibana/public/dashboard/dashboard_strings.js
+++ b/src/core_plugins/kibana/public/dashboard/dashboard_strings.js
@@ -17,6 +17,7 @@
* under the License.
*/
+import { i18n } from '@kbn/i18n';
import { DashboardViewMode } from './dashboard_view_mode';
/**
@@ -28,10 +29,21 @@ import { DashboardViewMode } from './dashboard_view_mode';
*/
export function getDashboardTitle(title, viewMode, isDirty) {
const isEditMode = viewMode === DashboardViewMode.EDIT;
- const unsavedSuffix = isEditMode && isDirty
- ? ' (unsaved)'
- : '';
+ let displayTitle;
- const displayTitle = `${title}${unsavedSuffix}`;
- return isEditMode ? 'Editing ' + displayTitle : displayTitle;
+ if (isEditMode && isDirty) {
+ displayTitle = i18n.translate('kbn.dashboard.strings.dashboardUnsavedEditTitle', {
+ defaultMessage: 'Editing {title} (unsaved)',
+ values: { title },
+ });
+ } else if (isEditMode) {
+ displayTitle = i18n.translate('kbn.dashboard.strings.dashboardEditTitle', {
+ defaultMessage: 'Editing {title}',
+ values: { title },
+ });
+ } else {
+ displayTitle = title;
+ }
+
+ return displayTitle;
}
diff --git a/src/core_plugins/kibana/public/dashboard/grid/__snapshots__/dashboard_grid.test.js.snap b/src/core_plugins/kibana/public/dashboard/grid/__snapshots__/dashboard_grid.test.js.snap
index a098c22af236..806e11c557a0 100644
--- a/src/core_plugins/kibana/public/dashboard/grid/__snapshots__/dashboard_grid.test.js.snap
+++ b/src/core_plugins/kibana/public/dashboard/grid/__snapshots__/dashboard_grid.test.js.snap
@@ -33,7 +33,7 @@ exports[`renders DashboardGrid 1`] = `
}
}
>
-
- {
});
test('renders DashboardGrid', () => {
- const component = shallow();
+ const component = shallowWithIntl();
expect(component).toMatchSnapshot();
- const panelElements = component.find('Connect(DashboardPanel)');
+ const panelElements = component.find('Connect(InjectIntl(DashboardPanelUi))');
expect(panelElements.length).toBe(2);
});
test('renders DashboardGrid with no visualizations', () => {
- const component = shallow();
+ const component = shallowWithIntl();
expect(component).toMatchSnapshot();
});
test('adjusts z-index of focused panel to be higher than siblings', () => {
- const component = shallow();
- const panelElements = component.find('Connect(DashboardPanel)');
+ const component = shallowWithIntl();
+ const panelElements = component.find('Connect(InjectIntl(DashboardPanelUi))');
panelElements.first().prop('onPanelFocused')('1');
const [gridItem1, gridItem2] = component.update().findWhere(el => el.key() === '1' || el.key() === '2');
expect(gridItem1.props.style.zIndex).toEqual('2');
diff --git a/src/core_plugins/kibana/public/dashboard/grid/dashboard_grid_container.test.js b/src/core_plugins/kibana/public/dashboard/grid/dashboard_grid_container.test.js
index 1a7e3db04868..12d5d42c811f 100644
--- a/src/core_plugins/kibana/public/dashboard/grid/dashboard_grid_container.test.js
+++ b/src/core_plugins/kibana/public/dashboard/grid/dashboard_grid_container.test.js
@@ -18,7 +18,7 @@
*/
import React from 'react';
-import { mount } from 'enzyme';
+import { mountWithIntl } from 'test_utils/enzyme_helpers';
import { Provider } from 'react-redux';
import _ from 'lodash';
import sizeMe from 'react-sizeme';
@@ -94,7 +94,7 @@ test('loads old panel data in the right order', () => {
store.dispatch(updatePanels(panelData));
store.dispatch(updateUseMargins(false));
- const grid = mount();
+ const grid = mountWithIntl();
const panels = store.getState().dashboard.panels;
expect(Object.keys(panels).length).toBe(16);
@@ -130,7 +130,7 @@ test('loads old panel data in the right order with margins', () => {
store.dispatch(updatePanels(panelData));
store.dispatch(updateUseMargins(true));
- const grid = mount();
+ const grid = mountWithIntl();
const panels = store.getState().dashboard.panels;
expect(Object.keys(panels).length).toBe(16);
diff --git a/src/core_plugins/kibana/public/dashboard/index.js b/src/core_plugins/kibana/public/dashboard/index.js
index 3c302ec41bb6..a2965219d68b 100644
--- a/src/core_plugins/kibana/public/dashboard/index.js
+++ b/src/core_plugins/kibana/public/dashboard/index.js
@@ -17,6 +17,7 @@
* under the License.
*/
+import { injectI18nProvider } from '@kbn/i18n/react';
import './dashboard_app';
import './saved_dashboard/saved_dashboards';
import './dashboard_config';
@@ -34,7 +35,6 @@ import { recentlyAccessed } from 'ui/persisted_log';
import { SavedObjectRegistryProvider } from 'ui/saved_objects/saved_object_registry';
import { DashboardListing, EMPTY_FILTER } from './listing/dashboard_listing';
import { uiModules } from 'ui/modules';
-import { i18n } from '@kbn/i18n';
const app = uiModules.get('app/dashboard', [
'ngRoute',
@@ -42,16 +42,22 @@ const app = uiModules.get('app/dashboard', [
]);
app.directive('dashboardListing', function (reactDirective) {
- return reactDirective(DashboardListing);
+ return reactDirective(injectI18nProvider(DashboardListing));
});
+function createNewDashboardCtrl($scope, i18n) {
+ $scope.visitVisualizeAppLinkText = i18n('kbn.dashboard.visitVisualizeAppLinkText', {
+ defaultMessage: 'visit the Visualize app',
+ });
+}
+
uiRoutes
.defaults(/dashboard/, {
requireDefaultIndex: true
})
.when(DashboardConstants.LANDING_PAGE_PATH, {
template: dashboardListingTemplate,
- controller($injector, $location, $scope, Private, config, breadcrumbState) {
+ controller($injector, $location, $scope, Private, config, breadcrumbState, i18n) {
const services = Private(SavedObjectRegistryProvider).byLoaderPropertiesName;
const dashboardConfig = $injector.get('dashboardConfig');
@@ -65,7 +71,7 @@ uiRoutes
$scope.hideWriteControls = dashboardConfig.getHideWriteControls();
$scope.initialFilter = ($location.search()).filter || EMPTY_FILTER;
breadcrumbState.set([{
- text: i18n.translate('kbn.dashboard.dashboardBreadcrumbsTitle', {
+ text: i18n('kbn.dashboard.dashboardBreadcrumbsTitle', {
defaultMessage: 'Dashboards',
}),
}]);
@@ -98,6 +104,7 @@ uiRoutes
})
.when(DashboardConstants.CREATE_NEW_DASHBOARD_URL, {
template: dashboardTemplate,
+ controller: createNewDashboardCtrl,
resolve: {
dash: function (savedDashboards, redirectWhenMissing) {
return savedDashboards.get()
@@ -109,8 +116,9 @@ uiRoutes
})
.when(createDashboardEditUrl(':id'), {
template: dashboardTemplate,
+ controller: createNewDashboardCtrl,
resolve: {
- dash: function (savedDashboards, Notifier, $route, $location, redirectWhenMissing, kbnUrl, AppState) {
+ dash: function (savedDashboards, Notifier, $route, $location, redirectWhenMissing, kbnUrl, AppState, i18n) {
const id = $route.current.params.id;
return savedDashboards.get(id)
@@ -131,7 +139,9 @@ uiRoutes
if (error instanceof SavedObjectNotFound && id === 'create') {
// Note "new AppState" is necessary so the state in the url is preserved through the redirect.
kbnUrl.redirect(DashboardConstants.CREATE_NEW_DASHBOARD_URL, {}, new AppState());
- toastNotifications.addWarning('The url "dashboard/create" was removed in 6.0. Please update your bookmarks.');
+ toastNotifications.addWarning(i18n('kbn.dashboard.urlWasRemovedInSixZeroWarningMessage',
+ { defaultMessage: 'The url "dashboard/create" was removed in 6.0. Please update your bookmarks.' }
+ ));
} else {
throw error;
}
@@ -143,11 +153,15 @@ uiRoutes
}
});
-FeatureCatalogueRegistryProvider.register(() => {
+FeatureCatalogueRegistryProvider.register((i18n) => {
return {
id: 'dashboard',
- title: 'Dashboard',
- description: 'Display and share a collection of visualizations and saved searches.',
+ title: i18n('kbn.dashboard.featureCatalogue.dashboardTitle', {
+ defaultMessage: 'Dashboard',
+ }),
+ description: i18n('kbn.dashboard.featureCatalogue.dashboardDescription', {
+ defaultMessage: 'Display and share a collection of visualizations and saved searches.',
+ }),
icon: 'dashboardApp',
path: `/app/kibana#${DashboardConstants.LANDING_PAGE_PATH}`,
showOnHomePage: true,
diff --git a/src/core_plugins/kibana/public/dashboard/listing/__snapshots__/dashboard_listing.test.js.snap b/src/core_plugins/kibana/public/dashboard/listing/__snapshots__/dashboard_listing.test.js.snap
index cd45b2ae64b1..e350b43c4028 100644
--- a/src/core_plugins/kibana/public/dashboard/listing/__snapshots__/dashboard_listing.test.js.snap
+++ b/src/core_plugins/kibana/public/dashboard/listing/__snapshots__/dashboard_listing.test.js.snap
@@ -22,7 +22,11 @@ exports[`after fetch hideWriteControls 1`] = `
color="subdued"
component="span"
>
- Looks like you don't have any dashboards.
+
@@ -64,7 +68,11 @@ exports[`after fetch initialFilter 1`] = `
textTransform="none"
>
- Dashboards
+
@@ -80,7 +88,11 @@ exports[`after fetch initialFilter 1`] = `
iconSide="left"
type="button"
>
- Create new dashboard
+
@@ -108,7 +120,7 @@ exports[`after fetch initialFilter 1`] = `
incremental={false}
isLoading={false}
onChange={[Function]}
- placeholder="Search..."
+ placeholder="Search…"
value="my dashboard"
/>
@@ -157,7 +169,13 @@ exports[`after fetch initialFilter 1`] = `
]
}
loading={false}
- noItemsMessage="No dashboards matched your search."
+ noItemsMessage={
+
+ }
onChange={[Function]}
pagination={
Object {
@@ -210,24 +228,42 @@ exports[`after fetch renders call to action when no dashboards exist 1`] = `
iconType="plusInCircle"
type="button"
>
- Create new dashboard
+
}
body={
- You can combine data views from any Kibana app into one dashboard and see everything in one place.
+
- New to Kibana?
-
- Install some sample data
-
- to take a test drive.
+
+
+ ,
+ }
+ }
+ />
}
@@ -235,7 +271,11 @@ exports[`after fetch renders call to action when no dashboards exist 1`] = `
iconType="dashboardApp"
title={
- Create your first dashboard
+
}
/>
@@ -278,7 +318,11 @@ exports[`after fetch renders table rows 1`] = `
textTransform="none"
>
- Dashboards
+
@@ -294,7 +338,11 @@ exports[`after fetch renders table rows 1`] = `
iconSide="left"
type="button"
>
- Create new dashboard
+
@@ -322,7 +370,7 @@ exports[`after fetch renders table rows 1`] = `
incremental={false}
isLoading={false}
onChange={[Function]}
- placeholder="Search..."
+ placeholder="Search…"
value=""
/>
@@ -371,7 +419,13 @@ exports[`after fetch renders table rows 1`] = `
]
}
loading={false}
- noItemsMessage="No dashboards matched your search."
+ noItemsMessage={
+
+ }
onChange={[Function]}
pagination={
Object {
@@ -432,7 +486,11 @@ exports[`after fetch renders warning when listingLimit is exceeded 1`] = `
textTransform="none"
>
- Dashboards
+
@@ -448,7 +506,11 @@ exports[`after fetch renders warning when listingLimit is exceeded 1`] = `
iconSide="left"
type="button"
>
- Create new dashboard
+
@@ -460,26 +522,39 @@ exports[`after fetch renders warning when listingLimit is exceeded 1`] = `
color="warning"
iconType="help"
size="m"
- title="Listing limit exceeded"
+ title={
+
+ }
>
- You have
- 2
- dashboards, but your
-
- listingLimit
-
- setting prevents the table below from displaying more than
- 1
- . You can change this setting under
-
- Advanced Settings
-
- .
+
+
+ ,
+ "listingLimitText":
+ listingLimit
+ ,
+ "listingLimitValue": 1,
+ "totalDashboards": 2,
+ }
+ }
+ />
@@ -556,7 +631,13 @@ exports[`after fetch renders warning when listingLimit is exceeded 1`] = `
]
}
loading={false}
- noItemsMessage="No dashboards matched your search."
+ noItemsMessage={
+
+ }
onChange={[Function]}
pagination={
Object {
diff --git a/src/core_plugins/kibana/public/dashboard/listing/dashboard_listing.js b/src/core_plugins/kibana/public/dashboard/listing/dashboard_listing.js
index 2a2aef320880..b7af6a616ba2 100644
--- a/src/core_plugins/kibana/public/dashboard/listing/dashboard_listing.js
+++ b/src/core_plugins/kibana/public/dashboard/listing/dashboard_listing.js
@@ -19,6 +19,7 @@
import React, { Fragment } from 'react';
import PropTypes from 'prop-types';
+import { injectI18n, FormattedMessage } from '@kbn/i18n/react';
import _ from 'lodash';
import { toastNotifications } from 'ui/notify';
import {
@@ -49,7 +50,7 @@ export const EMPTY_FILTER = '';
// and not supporting server-side paging.
// This component does not try to tackle these problems (yet) and is just feature matching the legacy component
// TODO support server side sorting/paging once title and description are sortable on the server.
-export class DashboardListing extends React.Component {
+class DashboardListingUi extends React.Component {
constructor(props) {
super(props);
@@ -111,7 +112,12 @@ export class DashboardListing extends React.Component {
await this.props.delete(this.state.selectedIds);
} catch (error) {
toastNotifications.addDanger({
- title: `Unable to delete dashboard(s)`,
+ title: (
+
+ ),
text: `${error}`,
});
}
@@ -194,14 +200,34 @@ export class DashboardListing extends React.Component {
return (
+ }
onCancel={this.closeDeleteModal}
onConfirm={this.deleteSelectedItems}
- cancelButtonText="Cancel"
- confirmButtonText="Delete"
+ cancelButtonText={
+
+ }
+ confirmButtonText={
+
+ }
defaultFocusedButton="cancel"
>
- {`You can't recover deleted dashboards.`}
+
+
+
);
@@ -212,14 +238,38 @@ export class DashboardListing extends React.Component {
return (
+ }
color="warning"
iconType="help"
>
- You have {this.state.totalDashboards} dashboards,
- but your listingLimit setting prevents the table below from displaying more than {this.props.listingLimit}.
- You can change this setting under Advanced Settings.
+
+ listingLimit
+
+ ),
+ advancedSettingsLink: (
+
+
+
+ )
+ }}
+ />
@@ -233,7 +283,12 @@ export class DashboardListing extends React.Component {
return '';
}
- return 'No dashboards matched your search.';
+ return (
+
+ );
}
renderNoItemsMessage() {
@@ -243,7 +298,10 @@ export class DashboardListing extends React.Component {
- {`Looks like you don't have any dashboards.`}
+
@@ -254,14 +312,37 @@ export class DashboardListing extends React.Component {
Create your first dashboard}
+ title={
+
+
+
+ }
body={
- You can combine data views from any Kibana app into one dashboard and see everything in one place.
+
- New to Kibana? Install some sample data to take a test drive.
+
+
+
+ ),
+ }}
+ />
}
@@ -272,7 +353,10 @@ export class DashboardListing extends React.Component {
iconType="plusInCircle"
data-test-subj="createDashboardPromptButton"
>
- Create new dashboard
+
}
/>
@@ -282,6 +366,7 @@ export class DashboardListing extends React.Component {
}
renderSearchBar() {
+ const { intl } = this.props;
let deleteBtn;
if (this.state.selectedIds.length > 0) {
deleteBtn = (
@@ -292,7 +377,10 @@ export class DashboardListing extends React.Component {
data-test-subj="deleteSelectedDashboards"
key="delete"
>
- Delete selected
+
);
@@ -303,8 +391,14 @@ export class DashboardListing extends React.Component {
{deleteBtn}
{
@@ -320,10 +414,14 @@ export class DashboardListing extends React.Component {
}
renderTable() {
+ const { intl } = this.props;
const tableColumns = [
{
field: 'title',
- name: 'Title',
+ name: intl.formatMessage({
+ id: 'kbn.dashboard.listing.table.titleColumnName',
+ defaultMessage: 'Title',
+ }),
sortable: true,
render: (field, record) => (
{
@@ -351,7 +455,10 @@ export class DashboardListing extends React.Component {
- Edit
+
);
}
@@ -413,7 +520,10 @@ export class DashboardListing extends React.Component {
href={`#${DashboardConstants.CREATE_NEW_DASHBOARD_URL}`}
data-test-subj="newDashboardLink"
>
- Create new dashboard
+
);
@@ -426,7 +536,10 @@ export class DashboardListing extends React.Component {
- Dashboards
+
@@ -471,7 +584,7 @@ export class DashboardListing extends React.Component {
}
}
-DashboardListing.propTypes = {
+DashboardListingUi.propTypes = {
find: PropTypes.func.isRequired,
delete: PropTypes.func.isRequired,
listingLimit: PropTypes.number.isRequired,
@@ -479,6 +592,8 @@ DashboardListing.propTypes = {
initialFilter: PropTypes.string,
};
-DashboardListing.defaultProps = {
+DashboardListingUi.defaultProps = {
initialFilter: EMPTY_FILTER,
};
+
+export const DashboardListing = injectI18n(DashboardListingUi);
diff --git a/src/core_plugins/kibana/public/dashboard/listing/dashboard_listing.test.js b/src/core_plugins/kibana/public/dashboard/listing/dashboard_listing.test.js
index e1a95b65982a..9fcb0c6bab90 100644
--- a/src/core_plugins/kibana/public/dashboard/listing/dashboard_listing.test.js
+++ b/src/core_plugins/kibana/public/dashboard/listing/dashboard_listing.test.js
@@ -36,7 +36,7 @@ jest.mock('lodash',
}), { virtual: true });
import React from 'react';
-import { shallow } from 'enzyme';
+import { shallowWithIntl } from 'test_utils/enzyme_helpers';
import {
DashboardListing,
@@ -58,7 +58,7 @@ const find = (num) => {
};
test('renders empty page in before initial fetch to avoid flickering', () => {
- const component = shallow( {}}
listingLimit={1000}
@@ -69,7 +69,7 @@ test('renders empty page in before initial fetch to avoid flickering', () => {
describe('after fetch', () => {
test('initialFilter', async () => {
- const component = shallow( {}}
listingLimit={1000}
@@ -86,7 +86,7 @@ describe('after fetch', () => {
});
test('renders table rows', async () => {
- const component = shallow( {}}
listingLimit={1000}
@@ -102,7 +102,7 @@ describe('after fetch', () => {
});
test('renders call to action when no dashboards exist', async () => {
- const component = shallow( {}}
listingLimit={1}
@@ -118,7 +118,7 @@ describe('after fetch', () => {
});
test('hideWriteControls', async () => {
- const component = shallow( {}}
listingLimit={1}
@@ -134,7 +134,7 @@ describe('after fetch', () => {
});
test('renders warning when listingLimit is exceeded', async () => {
- const component = shallow( {}}
listingLimit={1}
diff --git a/src/core_plugins/kibana/public/dashboard/panel/dashboard_panel.js b/src/core_plugins/kibana/public/dashboard/panel/dashboard_panel.js
index 684fe6c54a22..1ec58d197154 100644
--- a/src/core_plugins/kibana/public/dashboard/panel/dashboard_panel.js
+++ b/src/core_plugins/kibana/public/dashboard/panel/dashboard_panel.js
@@ -19,6 +19,7 @@
import React from 'react';
import PropTypes from 'prop-types';
+import { injectI18n, FormattedMessage } from '@kbn/i18n/react';
import classNames from 'classnames';
import _ from 'lodash';
@@ -29,11 +30,14 @@ import {
EuiPanel,
} from '@elastic/eui';
-export class DashboardPanel extends React.Component {
+class DashboardPanelUi extends React.Component {
constructor(props) {
super(props);
this.state = {
- error: props.embeddableFactory ? null : `No factory found for embeddable`,
+ error: props.embeddableFactory ? null : props.intl.formatMessage({
+ id: 'kbn.dashboard.panel.noEmbeddableFactoryErrorMessage',
+ defaultMessage: 'No factory found for embeddable',
+ }),
};
this.mounted = false;
@@ -100,7 +104,10 @@ export class DashboardPanel extends React.Component {
className="panel-content"
ref={panelElement => this.panelElement = panelElement}
>
- {!this.props.initialized && 'loading...'}
+ {!this.props.initialized && }
);
}
@@ -151,7 +158,7 @@ export class DashboardPanel extends React.Component {
}
}
-DashboardPanel.propTypes = {
+DashboardPanelUi.propTypes = {
viewOnlyMode: PropTypes.bool.isRequired,
onPanelFocused: PropTypes.func,
onPanelBlurred: PropTypes.func,
@@ -179,3 +186,5 @@ DashboardPanel.propTypes = {
panelIndex: PropTypes.string,
}).isRequired,
};
+
+export const DashboardPanel = injectI18n(DashboardPanelUi);
diff --git a/src/core_plugins/kibana/public/dashboard/panel/dashboard_panel.test.js b/src/core_plugins/kibana/public/dashboard/panel/dashboard_panel.test.js
index 5f142a8b1e33..eb8258f43833 100644
--- a/src/core_plugins/kibana/public/dashboard/panel/dashboard_panel.test.js
+++ b/src/core_plugins/kibana/public/dashboard/panel/dashboard_panel.test.js
@@ -19,7 +19,7 @@
import React from 'react';
import _ from 'lodash';
-import { mount } from 'enzyme';
+import { mountWithIntl } from 'test_utils/enzyme_helpers';
import { DashboardPanel } from './dashboard_panel';
import { DashboardViewMode } from '../dashboard_view_mode';
import { PanelError } from '../panel/panel_error';
@@ -62,7 +62,7 @@ beforeAll(() => {
});
test('DashboardPanel matches snapshot', () => {
- const component = mount();
+ const component = mountWithIntl();
expect(takeMountedSnapshot(component)).toMatchSnapshot();
});
@@ -71,7 +71,7 @@ test('renders an error when error prop is passed', () => {
error: 'Simulated error'
});
- const component = mount();
+ const component = mountWithIntl();
const panelError = component.find(PanelError);
expect(panelError.length).toBe(1);
});
diff --git a/src/core_plugins/kibana/public/dashboard/panel/dashboard_panel_container.js b/src/core_plugins/kibana/public/dashboard/panel/dashboard_panel_container.js
index 1b62a93f2cfb..556c81d32f8d 100644
--- a/src/core_plugins/kibana/public/dashboard/panel/dashboard_panel_container.js
+++ b/src/core_plugins/kibana/public/dashboard/panel/dashboard_panel_container.js
@@ -19,6 +19,7 @@
import { connect } from 'react-redux';
import PropTypes from 'prop-types';
+import { i18n } from '@kbn/i18n';
import { DashboardPanel } from './dashboard_panel';
import { DashboardViewMode } from '../dashboard_view_mode';
@@ -40,7 +41,10 @@ const mapStateToProps = ({ dashboard }, { embeddableFactory, panelId }) => {
let error = null;
if (!embeddableFactory) {
const panelType = getPanelType(dashboard, panelId);
- error = `No embeddable factory found for panel type ${panelType}`;
+ error = i18n.translate('kbn.dashboard.panel.noFoundEmbeddableFactoryErrorMessage', {
+ defaultMessage: 'No embeddable factory found for panel type {panelType}',
+ values: { panelType },
+ });
} else {
error = (embeddable && getEmbeddableError(dashboard, panelId)) || '';
}
diff --git a/src/core_plugins/kibana/public/dashboard/panel/dashboard_panel_container.test.js b/src/core_plugins/kibana/public/dashboard/panel/dashboard_panel_container.test.js
index 2af88510b715..cb532f1a48e3 100644
--- a/src/core_plugins/kibana/public/dashboard/panel/dashboard_panel_container.test.js
+++ b/src/core_plugins/kibana/public/dashboard/panel/dashboard_panel_container.test.js
@@ -19,7 +19,7 @@
import React from 'react';
import _ from 'lodash';
-import { mount } from 'enzyme';
+import { mountWithIntl } from 'test_utils/enzyme_helpers';
import { DashboardPanelContainer } from './dashboard_panel_container';
import { DashboardViewMode } from '../dashboard_view_mode';
import { PanelError } from '../panel/panel_error';
@@ -52,7 +52,7 @@ test('renders an error when embeddableFactory.create throws an error', (done) =>
throw new Error('simulated error');
});
};
- const component = mount();
+ const component = mountWithIntl();
setTimeout(() => {
component.update();
const panelError = component.find(PanelError);
diff --git a/src/core_plugins/kibana/public/dashboard/panel/panel_header/panel_actions/get_customize_panel_action.tsx b/src/core_plugins/kibana/public/dashboard/panel/panel_header/panel_actions/get_customize_panel_action.tsx
index f7cd97666b5c..dd059c47475c 100644
--- a/src/core_plugins/kibana/public/dashboard/panel/panel_header/panel_actions/get_customize_panel_action.tsx
+++ b/src/core_plugins/kibana/public/dashboard/panel/panel_header/panel_actions/get_customize_panel_action.tsx
@@ -18,6 +18,7 @@
*/
import { EuiIcon } from '@elastic/eui';
+import { i18n } from '@kbn/i18n';
import React from 'react';
import { ContextMenuAction, ContextMenuPanel } from 'ui/embeddable';
import { DashboardViewMode } from '../../../dashboard_view_mode';
@@ -36,7 +37,9 @@ export function getCustomizePanelAction({
}): ContextMenuAction {
return new ContextMenuAction(
{
- displayName: 'Customize panel',
+ displayName: i18n.translate('kbn.dashboard.panel.customizePanel.displayName', {
+ defaultMessage: 'Customize panel',
+ }),
id: 'customizePanel',
parentPanelId: 'mainMenu',
},
@@ -44,7 +47,9 @@ export function getCustomizePanelAction({
childContextMenuPanel: new ContextMenuPanel(
{
id: 'panelSubOptionsMenu',
- title: 'Customize panel',
+ title: i18n.translate('kbn.dashboard.panel.customizePanelTitle', {
+ defaultMessage: 'Customize panel',
+ }),
},
{
getContent: () => (
diff --git a/src/core_plugins/kibana/public/dashboard/panel/panel_header/panel_actions/get_edit_panel_action.tsx b/src/core_plugins/kibana/public/dashboard/panel/panel_header/panel_actions/get_edit_panel_action.tsx
index 88bc0001a9ac..f4413fc5539e 100644
--- a/src/core_plugins/kibana/public/dashboard/panel/panel_header/panel_actions/get_edit_panel_action.tsx
+++ b/src/core_plugins/kibana/public/dashboard/panel/panel_header/panel_actions/get_edit_panel_action.tsx
@@ -20,6 +20,7 @@
import React from 'react';
import { EuiIcon } from '@elastic/eui';
+import { i18n } from '@kbn/i18n';
import { ContextMenuAction } from 'ui/embeddable';
import { DashboardViewMode } from '../../../dashboard_view_mode';
@@ -31,7 +32,9 @@ import { DashboardViewMode } from '../../../dashboard_view_mode';
export function getEditPanelAction() {
return new ContextMenuAction(
{
- displayName: 'Edit visualization',
+ displayName: i18n.translate('kbn.dashboard.panel.editPanel.displayName', {
+ defaultMessage: 'Edit visualization',
+ }),
id: 'editPanel',
parentPanelId: 'mainMenu',
},
diff --git a/src/core_plugins/kibana/public/dashboard/panel/panel_header/panel_actions/get_inspector_panel_action.tsx b/src/core_plugins/kibana/public/dashboard/panel/panel_header/panel_actions/get_inspector_panel_action.tsx
index 2739e2859a42..01f6da642110 100644
--- a/src/core_plugins/kibana/public/dashboard/panel/panel_header/panel_actions/get_inspector_panel_action.tsx
+++ b/src/core_plugins/kibana/public/dashboard/panel/panel_header/panel_actions/get_inspector_panel_action.tsx
@@ -20,6 +20,7 @@
import React from 'react';
import { EuiIcon } from '@elastic/eui';
+import { i18n } from '@kbn/i18n';
import { ContextMenuAction } from 'ui/embeddable';
import { Inspector } from 'ui/inspector';
@@ -41,7 +42,9 @@ export function getInspectorPanelAction({
return new ContextMenuAction(
{
id: 'openInspector',
- displayName: 'Inspect',
+ displayName: i18n.translate('kbn.dashboard.panel.inspectorPanel.displayName', {
+ defaultMessage: 'Inspect',
+ }),
parentPanelId: 'mainMenu',
},
{
diff --git a/src/core_plugins/kibana/public/dashboard/panel/panel_header/panel_actions/get_remove_panel_action.tsx b/src/core_plugins/kibana/public/dashboard/panel/panel_header/panel_actions/get_remove_panel_action.tsx
index fce94f24b16c..47718a5f21b3 100644
--- a/src/core_plugins/kibana/public/dashboard/panel/panel_header/panel_actions/get_remove_panel_action.tsx
+++ b/src/core_plugins/kibana/public/dashboard/panel/panel_header/panel_actions/get_remove_panel_action.tsx
@@ -18,6 +18,7 @@
*/
import { EuiIcon } from '@elastic/eui';
+import { i18n } from '@kbn/i18n';
import React from 'react';
import { ContextMenuAction } from 'ui/embeddable';
@@ -31,7 +32,9 @@ import { DashboardViewMode } from '../../../dashboard_view_mode';
export function getRemovePanelAction(onDeletePanel: () => void) {
return new ContextMenuAction(
{
- displayName: 'Delete from dashboard',
+ displayName: i18n.translate('kbn.dashboard.panel.removePanel.displayName', {
+ defaultMessage: 'Delete from dashboard',
+ }),
id: 'deletePanel',
parentPanelId: 'mainMenu',
},
diff --git a/src/core_plugins/kibana/public/dashboard/panel/panel_header/panel_actions/get_toggle_expand_panel_action.tsx b/src/core_plugins/kibana/public/dashboard/panel/panel_header/panel_actions/get_toggle_expand_panel_action.tsx
index 27dca29c01ba..80d43347b308 100644
--- a/src/core_plugins/kibana/public/dashboard/panel/panel_header/panel_actions/get_toggle_expand_panel_action.tsx
+++ b/src/core_plugins/kibana/public/dashboard/panel/panel_header/panel_actions/get_toggle_expand_panel_action.tsx
@@ -18,6 +18,7 @@
*/
import { EuiIcon } from '@elastic/eui';
+import { i18n } from '@kbn/i18n';
import React from 'react';
import { ContextMenuAction } from 'ui/embeddable';
@@ -37,7 +38,13 @@ export function getToggleExpandPanelAction({
}) {
return new ContextMenuAction(
{
- displayName: isExpanded ? 'Minimize' : 'Full screen',
+ displayName: isExpanded
+ ? i18n.translate('kbn.dashboard.panel.toggleExpandPanel.expandedDisplayName', {
+ defaultMessage: 'Minimize',
+ })
+ : i18n.translate('kbn.dashboard.panel.toggleExpandPanel.notExpandedDisplayName', {
+ defaultMessage: 'Full screen',
+ }),
id: 'togglePanel',
parentPanelId: 'mainMenu',
},
diff --git a/src/core_plugins/kibana/public/dashboard/panel/panel_header/panel_header.tsx b/src/core_plugins/kibana/public/dashboard/panel/panel_header/panel_header.tsx
index c0acd5a672a6..9e9e59d79aa9 100644
--- a/src/core_plugins/kibana/public/dashboard/panel/panel_header/panel_header.tsx
+++ b/src/core_plugins/kibana/public/dashboard/panel/panel_header/panel_header.tsx
@@ -17,6 +17,7 @@
* under the License.
*/
+import { InjectedIntl, injectI18n } from '@kbn/i18n/react';
import React from 'react';
import { Embeddable } from 'ui/embeddable';
import { PanelId } from '../../selectors';
@@ -30,13 +31,18 @@ export interface PanelHeaderProps {
hidePanelTitles: boolean;
}
-export function PanelHeader({
+interface PanelHeaderUiProps extends PanelHeaderProps {
+ intl: InjectedIntl;
+}
+
+function PanelHeaderUi({
title,
panelId,
embeddable,
isViewOnlyMode,
hidePanelTitles,
-}: PanelHeaderProps) {
+ intl,
+}: PanelHeaderUiProps) {
if (isViewOnlyMode && (!title || hidePanelTitles)) {
return (
@@ -56,7 +62,15 @@ export function PanelHeader({
data-test-subj="dashboardPanelTitle"
className="dshPanel__title"
title={title}
- aria-label={`Dashboard panel: ${title}`}
+ aria-label={intl.formatMessage(
+ {
+ id: 'kbn.dashboard.panel.dashboardPanelAriaLabel',
+ defaultMessage: 'Dashboard panel: {title}',
+ },
+ {
+ title,
+ }
+ )}
>
{hidePanelTitles ? '' : title}
@@ -67,3 +81,5 @@ export function PanelHeader({
);
}
+
+export const PanelHeader = injectI18n(PanelHeaderUi);
diff --git a/src/core_plugins/kibana/public/dashboard/panel/panel_header/panel_header_container.test.tsx b/src/core_plugins/kibana/public/dashboard/panel/panel_header/panel_header_container.test.tsx
index 998c1f6dc3ff..f395b17207be 100644
--- a/src/core_plugins/kibana/public/dashboard/panel/panel_header/panel_header_container.test.tsx
+++ b/src/core_plugins/kibana/public/dashboard/panel/panel_header/panel_header_container.test.tsx
@@ -17,10 +17,11 @@
* under the License.
*/
-import { mount, ReactWrapper } from 'enzyme';
+import { ReactWrapper } from 'enzyme';
import _ from 'lodash';
import React from 'react';
import { Provider } from 'react-redux';
+import { mountWithIntl } from 'test_utils/enzyme_helpers';
// TODO: remove this when EUI supports types for this.
// @ts-ignore: implicit any for JS file
@@ -77,7 +78,7 @@ afterAll(() => {
});
test('Panel header shows embeddable title when nothing is set on the panel', () => {
- component = mount(
+ component = mountWithIntl(
diff --git a/src/core_plugins/kibana/public/dashboard/panel/panel_header/panel_options_menu.tsx b/src/core_plugins/kibana/public/dashboard/panel/panel_header/panel_options_menu.tsx
index 983a235a719f..25efd58d059e 100644
--- a/src/core_plugins/kibana/public/dashboard/panel/panel_header/panel_options_menu.tsx
+++ b/src/core_plugins/kibana/public/dashboard/panel/panel_header/panel_options_menu.tsx
@@ -17,6 +17,7 @@
* under the License.
*/
+import { InjectedIntl, injectI18n } from '@kbn/i18n/react';
import React from 'react';
import {
@@ -34,19 +35,27 @@ export interface PanelOptionsMenuProps {
isViewMode: boolean;
}
-export function PanelOptionsMenu({
+interface PanelOptionsMenuUiProps extends PanelOptionsMenuProps {
+ intl: InjectedIntl;
+}
+
+function PanelOptionsMenuUi({
toggleContextMenu,
isPopoverOpen,
closeContextMenu,
panels,
isViewMode,
-}: PanelOptionsMenuProps) {
+ intl,
+}: PanelOptionsMenuUiProps) {
const button = (
@@ -70,3 +79,5 @@ export function PanelOptionsMenu({
);
}
+
+export const PanelOptionsMenu = injectI18n(PanelOptionsMenuUi);
diff --git a/src/core_plugins/kibana/public/dashboard/panel/panel_header/panel_options_menu_container.ts b/src/core_plugins/kibana/public/dashboard/panel/panel_header/panel_options_menu_container.ts
index 294a7dd2661c..478c59847fe3 100644
--- a/src/core_plugins/kibana/public/dashboard/panel/panel_header/panel_options_menu_container.ts
+++ b/src/core_plugins/kibana/public/dashboard/panel/panel_header/panel_options_menu_container.ts
@@ -18,6 +18,7 @@
*/
import { EuiContextMenuPanelDescriptor } from '@elastic/eui';
+import { i18n } from '@kbn/i18n';
import { connect } from 'react-redux';
import {
buildEuiContextMenuPanels,
@@ -167,7 +168,9 @@ const mergeProps = (
// every panel, every time any state changes.
if (isPopoverOpen) {
const contextMenuPanel = new ContextMenuPanel({
- title: 'Options',
+ title: i18n.translate('kbn.dashboard.panel.optionsMenu.optionsContextMenuTitle', {
+ defaultMessage: 'Options',
+ }),
id: 'mainMenu',
});
diff --git a/src/core_plugins/kibana/public/dashboard/panel/panel_header/panel_options_menu_form.tsx b/src/core_plugins/kibana/public/dashboard/panel/panel_header/panel_options_menu_form.tsx
index 4b7b4a3a1341..c80ab00a46b7 100644
--- a/src/core_plugins/kibana/public/dashboard/panel/panel_header/panel_options_menu_form.tsx
+++ b/src/core_plugins/kibana/public/dashboard/panel/panel_header/panel_options_menu_form.tsx
@@ -20,6 +20,7 @@
import React, { ChangeEvent, KeyboardEvent } from 'react';
import { EuiButtonEmpty, EuiFieldText, EuiFormRow, keyCodes } from '@elastic/eui';
+import { FormattedMessage, InjectedIntl, injectI18n } from '@kbn/i18n/react';
export interface PanelOptionsMenuFormProps {
title?: string;
@@ -28,12 +29,17 @@ export interface PanelOptionsMenuFormProps {
onClose: () => void;
}
-export function PanelOptionsMenuForm({
+interface PanelOptionsMenuFormUiProps extends PanelOptionsMenuFormProps {
+ intl: InjectedIntl;
+}
+
+function PanelOptionsMenuFormUi({
title,
onReset,
onUpdatePanelTitle,
onClose,
-}: PanelOptionsMenuFormProps) {
+ intl,
+}: PanelOptionsMenuFormUiProps) {
function onInputChange(event: ChangeEvent) {
onUpdatePanelTitle(event.target.value);
}
@@ -46,7 +52,12 @@ export function PanelOptionsMenuForm({
return (
-
+
- Reset title
+
);
}
+
+export const PanelOptionsMenuForm = injectI18n(PanelOptionsMenuFormUi);
diff --git a/src/core_plugins/kibana/public/dashboard/panel/panel_utils.js b/src/core_plugins/kibana/public/dashboard/panel/panel_utils.js
index c5b60f1018bb..aec24998f17b 100644
--- a/src/core_plugins/kibana/public/dashboard/panel/panel_utils.js
+++ b/src/core_plugins/kibana/public/dashboard/panel/panel_utils.js
@@ -18,6 +18,7 @@
*/
import _ from 'lodash';
+import { i18n } from '@kbn/i18n';
import { DEFAULT_PANEL_WIDTH, DEFAULT_PANEL_HEIGHT } from '../dashboard_constants';
import chrome from 'ui/chrome';
@@ -31,7 +32,10 @@ export class PanelUtils {
static convertPanelDataPre_6_1(panel) { // eslint-disable-line camelcase
['col', 'row'].forEach(key => {
if (!_.has(panel, key)) {
- throw new Error(`Unable to migrate panel data for "6.1.0" backwards compatibility, panel does not contain expected field: ${key}`);
+ throw new Error(i18n.translate('kbn.dashboard.panel.unableToMigratePanelDataForSixOneZeroErrorMessage', {
+ defaultMessage: 'Unable to migrate panel data for "6.1.0" backwards compatibility, panel does not contain expected field: {key}',
+ values: { key },
+ }));
}
});
@@ -59,7 +63,10 @@ export class PanelUtils {
static convertPanelDataPre_6_3(panel, useMargins) { // eslint-disable-line camelcase
['w', 'x', 'h', 'y'].forEach(key => {
if (!_.has(panel.gridData, key)) {
- throw new Error(`Unable to migrate panel data for "6.3.0" backwards compatibility, panel does not contain expected field: ${key}`);
+ throw new Error(i18n.translate('kbn.dashboard.panel.unableToMigratePanelDataForSixThreeZeroErrorMessage', {
+ defaultMessage: 'Unable to migrate panel data for "6.3.0" backwards compatibility, panel does not contain expected field: {key}',
+ values: { key },
+ }));
}
});
@@ -78,7 +85,13 @@ export class PanelUtils {
static parseVersion(version = '6.0.0') {
const versionSplit = version.split('.');
if (versionSplit.length < 3) {
- throw new Error(`Invalid version, ${version}, expected ..`);
+ throw new Error(i18n.translate('kbn.dashboard.panel.invalidVersionErrorMessage', {
+ defaultMessage: 'Invalid version, {version}, expected {semver}',
+ values: {
+ version,
+ semver: '..',
+ },
+ }));
}
return {
major: parseInt(versionSplit[0], 10),
diff --git a/src/core_plugins/kibana/public/dashboard/saved_dashboard/saved_dashboard.js b/src/core_plugins/kibana/public/dashboard/saved_dashboard/saved_dashboard.js
index cf82b8274b63..04773be6e428 100644
--- a/src/core_plugins/kibana/public/dashboard/saved_dashboard/saved_dashboard.js
+++ b/src/core_plugins/kibana/public/dashboard/saved_dashboard/saved_dashboard.js
@@ -26,7 +26,7 @@ import { SavedObjectProvider } from 'ui/courier';
const module = uiModules.get('app/dashboard');
// Used only by the savedDashboards service, usually no reason to change this
-module.factory('SavedDashboard', function (Private, config) {
+module.factory('SavedDashboard', function (Private, config, i18n) {
// SavedDashboard constructor. Usually you'd interact with an instance of this.
// ID is option, without it one will be generated on save.
const SavedObject = Private(SavedObjectProvider);
@@ -43,7 +43,7 @@ module.factory('SavedDashboard', function (Private, config) {
// default values that will get assigned if the doc is new
defaults: {
- title: 'New Dashboard',
+ title: i18n('kbn.dashboard.savedDashboard.newDashboardTitle', { defaultMessage: 'New Dashboard' }),
hits: 0,
description: '',
panelsJSON: '[]',
diff --git a/src/core_plugins/kibana/public/dashboard/saved_dashboard/saved_dashboards.js b/src/core_plugins/kibana/public/dashboard/saved_dashboard/saved_dashboards.js
index a4563b71a26f..c4ab8b9a96e3 100644
--- a/src/core_plugins/kibana/public/dashboard/saved_dashboard/saved_dashboards.js
+++ b/src/core_plugins/kibana/public/dashboard/saved_dashboard/saved_dashboards.js
@@ -17,6 +17,7 @@
* under the License.
*/
+import { i18n } from '@kbn/i18n';
import './saved_dashboard';
import { uiModules } from 'ui/modules';
import { SavedObjectLoader } from 'ui/courier/saved_object/saved_object_loader';
@@ -29,7 +30,9 @@ const module = uiModules.get('app/dashboard');
// edited by the object editor.
savedObjectManagementRegistry.register({
service: 'savedDashboards',
- title: 'dashboards'
+ title: i18n.translate('kbn.dashboard.savedDashboardsTitle', {
+ defaultMessage: 'dashboards',
+ }),
});
// This is the only thing that gets injected into controllers
diff --git a/src/core_plugins/kibana/public/dashboard/top_nav/__snapshots__/add_panel.test.js.snap b/src/core_plugins/kibana/public/dashboard/top_nav/__snapshots__/add_panel.test.js.snap
index d976372dd2bf..4f96414b427c 100644
--- a/src/core_plugins/kibana/public/dashboard/top_nav/__snapshots__/add_panel.test.js.snap
+++ b/src/core_plugins/kibana/public/dashboard/top_nav/__snapshots__/add_panel.test.js.snap
@@ -16,7 +16,11 @@ exports[`render 1`] = `
textTransform="none"
>
- Add Panels
+
- Add new Visualization
+
}
key="visSavedObjectFinder"
diff --git a/src/core_plugins/kibana/public/dashboard/top_nav/__snapshots__/clone_modal.test.js.snap b/src/core_plugins/kibana/public/dashboard/top_nav/__snapshots__/clone_modal.test.js.snap
index 80fb7a7ed275..92e8f07ea0da 100644
--- a/src/core_plugins/kibana/public/dashboard/top_nav/__snapshots__/clone_modal.test.js.snap
+++ b/src/core_plugins/kibana/public/dashboard/top_nav/__snapshots__/clone_modal.test.js.snap
@@ -10,7 +10,11 @@ exports[`renders DashboardCloneModal 1`] = `
>
- Clone Dashboard
+
@@ -19,7 +23,11 @@ exports[`renders DashboardCloneModal 1`] = `
size="m"
>
- Please enter a new name for your dashboard.
+
- Cancel
+
- Confirm Clone
+
diff --git a/src/core_plugins/kibana/public/dashboard/top_nav/__snapshots__/save_modal.test.js.snap b/src/core_plugins/kibana/public/dashboard/top_nav/__snapshots__/save_modal.test.js.snap
index 2112aee0763c..aae42c0b98ce 100644
--- a/src/core_plugins/kibana/public/dashboard/top_nav/__snapshots__/save_modal.test.js.snap
+++ b/src/core_plugins/kibana/public/dashboard/top_nav/__snapshots__/save_modal.test.js.snap
@@ -11,7 +11,13 @@ exports[`renders DashboardSaveModal 1`] = `
describedByIds={Array []}
fullWidth={false}
hasEmptyLabelSpace={false}
- label="Description"
+ label={
+
+ }
>
+ }
+ label={
+
+ }
>
- Add new Visualization
+
);
const tabs = [{
id: VIS_TAB_ID,
- name: 'Visualization',
+ name: props.intl.formatMessage({
+ id: 'kbn.dashboard.topNav.addPanel.visualizationTabName',
+ defaultMessage: 'Visualization',
+ }),
dataTestSubj: 'addVisualizationTab',
toastDataTestSubj: 'addVisualizationToDashboardSuccess',
savedObjectFinder: (
@@ -59,20 +66,29 @@ export class DashboardAddPanel extends React.Component {
callToActionButton={addNewVisBtn}
onChoose={this.onAddPanel}
visTypes={this.props.visTypes}
- noItemsMessage="No matching visualizations found."
+ noItemsMessage={props.intl.formatMessage({
+ id: 'kbn.dashboard.topNav.addPanel.visSavedObjectFinder.noMatchingVisualizationsMessage',
+ defaultMessage: 'No matching visualizations found.',
+ })}
savedObjectType="visualization"
/>
)
}, {
id: SAVED_SEARCH_TAB_ID,
- name: 'Saved Search',
+ name: props.intl.formatMessage({
+ id: 'kbn.dashboard.topNav.addPanel.savedSearchTabName',
+ defaultMessage: 'Saved Search',
+ }),
dataTestSubj: 'addSavedSearchTab',
toastDataTestSubj: 'addSavedSearchToDashboardSuccess',
savedObjectFinder: (
)
@@ -115,7 +131,12 @@ export class DashboardAddPanel extends React.Component {
}
this.lastToast = toastNotifications.addSuccess({
- title: `${this.state.selectedTab.name} was added to your dashboard`,
+ title: this.props.intl.formatMessage({
+ id: 'kbn.dashboard.topNav.addPanel.selectedTabAddedToDashboardSuccessMessageTitle',
+ defaultMessage: '{selectedTabName} was added to your dashboard',
+ }, {
+ selectedTabName: this.state.selectedTab.name,
+ }),
'data-test-subj': this.state.selectedTab.toastDataTestSubj,
});
}
@@ -131,7 +152,12 @@ export class DashboardAddPanel extends React.Component {
- Add Panels
+
+
+
@@ -148,9 +174,11 @@ export class DashboardAddPanel extends React.Component {
}
}
-DashboardAddPanel.propTypes = {
+DashboardAddPanelUi.propTypes = {
onClose: PropTypes.func.isRequired,
visTypes: PropTypes.object.isRequired,
addNewPanel: PropTypes.func.isRequired,
addNewVis: PropTypes.func.isRequired,
};
+
+export const DashboardAddPanel = injectI18n(DashboardAddPanelUi);
diff --git a/src/core_plugins/kibana/public/dashboard/top_nav/add_panel.test.js b/src/core_plugins/kibana/public/dashboard/top_nav/add_panel.test.js
index 9c17980f7b9c..3f233eed6b10 100644
--- a/src/core_plugins/kibana/public/dashboard/top_nav/add_panel.test.js
+++ b/src/core_plugins/kibana/public/dashboard/top_nav/add_panel.test.js
@@ -19,7 +19,7 @@
import React from 'react';
import sinon from 'sinon';
-import { shallow } from 'enzyme';
+import { shallowWithIntl } from 'test_utils/enzyme_helpers';
import {
DashboardAddPanel,
@@ -38,7 +38,7 @@ beforeEach(() => {
});
test('render', () => {
- const component = shallow( {}}
diff --git a/src/core_plugins/kibana/public/dashboard/top_nav/clone_modal.js b/src/core_plugins/kibana/public/dashboard/top_nav/clone_modal.js
index 5bab97387a14..507eb2b6db34 100644
--- a/src/core_plugins/kibana/public/dashboard/top_nav/clone_modal.js
+++ b/src/core_plugins/kibana/public/dashboard/top_nav/clone_modal.js
@@ -19,6 +19,7 @@
import React, { Fragment } from 'react';
import PropTypes from 'prop-types';
+import { injectI18n, FormattedMessage } from '@kbn/i18n/react';
import {
EuiButton,
@@ -34,7 +35,7 @@ import {
EuiCallOut,
} from '@elastic/eui';
-export class DashboardCloneModal extends React.Component {
+class DashboardCloneModalUi extends React.Component {
constructor(props) {
super(props);
@@ -90,12 +91,30 @@ export class DashboardCloneModal extends React.Component {
return (
- Click Confirm Clone to clone the dashboard with the duplicate title.
+
+
+
+ ),
+ }}
+ />
@@ -113,14 +132,20 @@ export class DashboardCloneModal extends React.Component {
>
- Clone Dashboard
+
- Please enter a new name for your dashboard.
+
@@ -143,7 +168,10 @@ export class DashboardCloneModal extends React.Component {
data-test-subj="cloneCancelButton"
onClick={this.props.onClose}
>
- Cancel
+
- Confirm Clone
+
@@ -161,8 +192,10 @@ export class DashboardCloneModal extends React.Component {
}
}
-DashboardCloneModal.propTypes = {
+DashboardCloneModalUi.propTypes = {
onClone: PropTypes.func,
onClose: PropTypes.func,
title: PropTypes.string
};
+
+export const DashboardCloneModal = injectI18n(DashboardCloneModalUi);
diff --git a/src/core_plugins/kibana/public/dashboard/top_nav/clone_modal.test.js b/src/core_plugins/kibana/public/dashboard/top_nav/clone_modal.test.js
index c8154fe3bdd6..3dfaa26b7982 100644
--- a/src/core_plugins/kibana/public/dashboard/top_nav/clone_modal.test.js
+++ b/src/core_plugins/kibana/public/dashboard/top_nav/clone_modal.test.js
@@ -19,7 +19,7 @@
import React from 'react';
import sinon from 'sinon';
-import { mount, shallow } from 'enzyme';
+import { mountWithIntl, shallowWithIntl } from 'test_utils/enzyme_helpers';
import {
findTestSubject,
} from '@elastic/eui/lib/test';
@@ -37,9 +37,9 @@ beforeEach(() => {
onClose = sinon.spy();
});
-function createComponent(creationMethod = mount) {
+function createComponent(creationMethod = mountWithIntl) {
component = creationMethod(
- {
- createComponent(shallow);
+ createComponent(shallowWithIntl);
expect(component).toMatchSnapshot(); // eslint-disable-line
});
diff --git a/src/core_plugins/kibana/public/dashboard/top_nav/get_top_nav_config.js b/src/core_plugins/kibana/public/dashboard/top_nav/get_top_nav_config.js
index c0ac1cb2702b..969ff3f631de 100644
--- a/src/core_plugins/kibana/public/dashboard/top_nav/get_top_nav_config.js
+++ b/src/core_plugins/kibana/public/dashboard/top_nav/get_top_nav_config.js
@@ -17,6 +17,7 @@
* under the License.
*/
+import { i18n } from '@kbn/i18n';
import { DashboardViewMode } from '../dashboard_view_mode';
import { TopNavIds } from './top_nav_ids';
@@ -57,8 +58,12 @@ export function getTopNavConfig(dashboardMode, actions, hideWriteControls) {
function getFullScreenConfig(action) {
return {
- key: 'full screen',
- description: 'Full Screen Mode',
+ key: i18n.translate('kbn.dashboard.topNave.fullScreenButtonAriaLabel', {
+ defaultMessage: 'full screen',
+ }),
+ description: i18n.translate('kbn.dashboard.topNave.fullScreenConfigDescription', {
+ defaultMessage: 'Full Screen Mode',
+ }),
testId: 'dashboardFullScreenMode',
run: action
};
@@ -69,8 +74,12 @@ function getFullScreenConfig(action) {
*/
function getEditConfig(action) {
return {
- key: 'edit',
- description: 'Switch to edit mode',
+ key: i18n.translate('kbn.dashboard.topNave.editButtonAriaLabel', {
+ defaultMessage: 'edit',
+ }),
+ description: i18n.translate('kbn.dashboard.topNave.editConfigDescription', {
+ defaultMessage: 'Switch to edit mode',
+ }),
testId: 'dashboardEditMode',
run: action
};
@@ -81,8 +90,12 @@ function getEditConfig(action) {
*/
function getSaveConfig(action) {
return {
- key: TopNavIds.SAVE,
- description: 'Save your dashboard',
+ key: i18n.translate('kbn.dashboard.topNave.saveButtonAriaLabel', {
+ defaultMessage: 'save',
+ }),
+ description: i18n.translate('kbn.dashboard.topNave.saveConfigDescription', {
+ defaultMessage: 'Save your dashboard',
+ }),
testId: 'dashboardSaveMenuItem',
run: action
};
@@ -93,8 +106,12 @@ function getSaveConfig(action) {
*/
function getViewConfig(action) {
return {
- key: 'cancel',
- description: 'Cancel editing and switch to view-only mode',
+ key: i18n.translate('kbn.dashboard.topNave.cancelButtonAriaLabel', {
+ defaultMessage: 'cancel',
+ }),
+ description: i18n.translate('kbn.dashboard.topNave.viewConfigDescription', {
+ defaultMessage: 'Cancel editing and switch to view-only mode',
+ }),
testId: 'dashboardViewOnlyMode',
run: action
};
@@ -105,8 +122,12 @@ function getViewConfig(action) {
*/
function getCloneConfig(action) {
return {
- key: TopNavIds.CLONE,
- description: 'Create a copy of your dashboard',
+ key: i18n.translate('kbn.dashboard.topNave.cloneButtonAriaLabel', {
+ defaultMessage: 'clone',
+ }),
+ description: i18n.translate('kbn.dashboard.topNave.cloneConfigDescription', {
+ defaultMessage: 'Create a copy of your dashboard',
+ }),
testId: 'dashboardClone',
run: action
};
@@ -117,8 +138,12 @@ function getCloneConfig(action) {
*/
function getAddConfig(action) {
return {
- key: TopNavIds.ADD,
- description: 'Add a panel to the dashboard',
+ key: i18n.translate('kbn.dashboard.topNave.addButtonAriaLabel', {
+ defaultMessage: 'add',
+ }),
+ description: i18n.translate('kbn.dashboard.topNave.addConfigDescription', {
+ defaultMessage: 'Add a panel to the dashboard',
+ }),
testId: 'dashboardAddPanelButton',
run: action
};
@@ -129,8 +154,12 @@ function getAddConfig(action) {
*/
function getShareConfig(action) {
return {
- key: TopNavIds.SHARE,
- description: 'Share Dashboard',
+ key: i18n.translate('kbn.dashboard.topNave.shareButtonAriaLabel', {
+ defaultMessage: 'share',
+ }),
+ description: i18n.translate('kbn.dashboard.topNave.shareConfigDescription', {
+ defaultMessage: 'Share Dashboard',
+ }),
testId: 'shareTopNavButton',
run: action,
};
@@ -141,8 +170,12 @@ function getShareConfig(action) {
*/
function getOptionsConfig(action) {
return {
- key: TopNavIds.OPTIONS,
- description: 'Options',
+ key: i18n.translate('kbn.dashboard.topNave.optionsButtonAriaLabel', {
+ defaultMessage: 'options',
+ }),
+ description: i18n.translate('kbn.dashboard.topNave.optionsConfigDescription', {
+ defaultMessage: 'Options',
+ }),
testId: 'dashboardOptionsButton',
run: action,
};
diff --git a/src/core_plugins/kibana/public/dashboard/top_nav/options.js b/src/core_plugins/kibana/public/dashboard/top_nav/options.js
index 6c42c2d26a25..62c3b65374db 100644
--- a/src/core_plugins/kibana/public/dashboard/top_nav/options.js
+++ b/src/core_plugins/kibana/public/dashboard/top_nav/options.js
@@ -19,6 +19,7 @@
import React, { Component } from 'react';
import PropTypes from 'prop-types';
+import { injectI18n } from '@kbn/i18n/react';
import {
EuiForm,
@@ -26,7 +27,7 @@ import {
EuiSwitch,
} from '@elastic/eui';
-export class OptionsMenu extends Component {
+class OptionsMenuUi extends Component {
state = {
darkTheme: this.props.darkTheme,
@@ -60,7 +61,10 @@ export class OptionsMenu extends Component {
}
>
}
+ helpText={}
>
{
- const component = shallow( {}}
onClose={() => {}}
title="dash title"
diff --git a/src/core_plugins/kibana/public/dashboard/top_nav/show_add_panel.js b/src/core_plugins/kibana/public/dashboard/top_nav/show_add_panel.js
index 00719a850aca..d4d8b1a0e404 100644
--- a/src/core_plugins/kibana/public/dashboard/top_nav/show_add_panel.js
+++ b/src/core_plugins/kibana/public/dashboard/top_nav/show_add_panel.js
@@ -17,6 +17,7 @@
* under the License.
*/
+import { I18nProvider } from '@kbn/i18n/react';
import { DashboardAddPanel } from './add_panel';
import React from 'react';
import ReactDOM from 'react-dom';
@@ -43,12 +44,14 @@ export function showAddPanel(addNewPanel, addNewVis, visTypes) {
document.body.appendChild(container);
const element = (
-
+
+
+
);
ReactDOM.render(element, container);
}
diff --git a/src/core_plugins/kibana/public/dashboard/top_nav/show_clone_modal.js b/src/core_plugins/kibana/public/dashboard/top_nav/show_clone_modal.js
index d75c3da660e9..08163a9a3595 100644
--- a/src/core_plugins/kibana/public/dashboard/top_nav/show_clone_modal.js
+++ b/src/core_plugins/kibana/public/dashboard/top_nav/show_clone_modal.js
@@ -17,9 +17,11 @@
* under the License.
*/
+import { I18nProvider } from '@kbn/i18n/react';
import { DashboardCloneModal } from './clone_modal';
import React from 'react';
import ReactDOM from 'react-dom';
+import { i18n } from '@kbn/i18n';
export function showCloneModal(onClone, title) {
const container = document.createElement('div');
@@ -37,7 +39,16 @@ export function showCloneModal(onClone, title) {
};
document.body.appendChild(container);
const element = (
-
+
+
+
);
ReactDOM.render(element, container);
}
diff --git a/src/core_plugins/kibana/public/dashboard/top_nav/show_options_popover.js b/src/core_plugins/kibana/public/dashboard/top_nav/show_options_popover.js
index 2d2dd83b4c34..cf6fba6316e7 100644
--- a/src/core_plugins/kibana/public/dashboard/top_nav/show_options_popover.js
+++ b/src/core_plugins/kibana/public/dashboard/top_nav/show_options_popover.js
@@ -19,6 +19,7 @@
import React from 'react';
import ReactDOM from 'react-dom';
+import { I18nProvider } from '@kbn/i18n/react';
import { OptionsMenu } from './options';
@@ -53,22 +54,24 @@ export function showOptionsPopover({
document.body.appendChild(container);
const element = (
-
-
-
+
+
+
+
+
);
ReactDOM.render(element, container);
}
diff --git a/src/core_plugins/kibana/public/dashboard/viewport/dashboard_viewport_provider.js b/src/core_plugins/kibana/public/dashboard/viewport/dashboard_viewport_provider.js
index a219f763dac2..95b66cc1c4c5 100644
--- a/src/core_plugins/kibana/public/dashboard/viewport/dashboard_viewport_provider.js
+++ b/src/core_plugins/kibana/public/dashboard/viewport/dashboard_viewport_provider.js
@@ -19,6 +19,7 @@
import React from 'react';
import PropTypes from 'prop-types';
+import { I18nProvider } from '@kbn/i18n/react';
import { store } from '../../store';
import { Provider } from 'react-redux';
import { DashboardViewportContainer } from './dashboard_viewport_container';
@@ -26,7 +27,9 @@ import { DashboardViewportContainer } from './dashboard_viewport_container';
export function DashboardViewportProvider(props) {
return (
-
+
+
+
);
}
diff --git a/src/ui/public/saved_objects/show_saved_object_save_modal.js b/src/ui/public/saved_objects/show_saved_object_save_modal.js
index f53f819c697f..5cb1681c0828 100644
--- a/src/ui/public/saved_objects/show_saved_object_save_modal.js
+++ b/src/ui/public/saved_objects/show_saved_object_save_modal.js
@@ -19,6 +19,7 @@
import React from 'react';
import ReactDOM from 'react-dom';
+import { I18nProvider } from '@kbn/i18n/react';
export function showSaveModal(saveModal) {
const container = document.createElement('div');
@@ -44,5 +45,6 @@ export function showSaveModal(saveModal) {
onClose: closeModal
}
);
- ReactDOM.render(element, container);
+
+ ReactDOM.render({element}, container);
}
diff --git a/tsconfig.json b/tsconfig.json
index 0ca1bef98f43..6eedfa53b261 100644
--- a/tsconfig.json
+++ b/tsconfig.json
@@ -4,6 +4,9 @@
"paths": {
"ui/*": [
"src/ui/public/*"
+ ],
+ "test_utils/*": [
+ "src/test_utils/public/*"
]
},
// Support .tsx files and transform JSX into calls to React.createElement
@@ -54,4 +57,4 @@
// the tsconfig.json file for public files correctly.
// "src/**/public/**/*"
]
-}
\ No newline at end of file
+}