diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 8ec52296db..2780cfbdf2 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -20,6 +20,7 @@ Have questions about this document or anything not covered here? Feel free to re * [Typechecking with PropTypes](#typechecking-with-proptypes) * [Naming Functions](#naming-functions) * [Default State Initialization](#default-state-initialization) +* [Internationalization](#internationalization) ## Things to know prior to submitting code @@ -214,3 +215,30 @@ mountWithContexts(< { } }); ``` + +## Internationalization + +Internationalization leans on the [lingui](https://github.com/lingui/js-lingui) project. [Official documentation here](https://lingui.js.org/). We use this libary to mark our strings for translation. If you want to see this in action you'll need to take the following steps: + +### Marking strings for translation and replacement in the UI + +The lingui library provides various React helpers for dealing with both marking strings for translation, and replacing strings that have been traslated. For consistency and ease of use, we have consolidated on one pattern for the codebase. To set strings to be translated in the UI: + +- import the withI18n function and wrap the export of your component in it (i.e. `export default withI18n()(Foo)`) +- doing the above gives you access to the i18n object on props. Make sure to put it in the scope of the function that contains strings needed to be translated (i.e. `const { i18n } = this.props;`) +- import the t template tag function from the @lingui/macro package. +- wrap your string using the following format: ```i18n._(t`String to be translated`)``` + +**Note:** Variables that are put inside the t-marked template tag will not be translated. If you have a variable string with text that needs translating, you must wrap it in ```i18n._(t``)``` where it is defined. + +**Note:** We do not use the `I18n` consumer, `i18nMark` function, or `` component lingui gives us access to in this repo. i18nMark does not actually replace the string in the UI (leading to the potential for untranslated bugs), and the other helpers are redundant. Settling on a consistent, single pattern helps us ease the mental overhead of the need to understand the ins and outs of the lingui API. + +You can learn more about the ways lingui and its React helpers at [this link](https://lingui.js.org/tutorials/react-patterns.html). + +### Setting up .po files to give to translation team + +1) `npm run add-locale` to add the language that you want to translate to (we should only have to do this once and the commit to repo afaik). Example: `npm run add-locale en es fr` # Add English, Spanish and French locale +2) `npm run extract-strings` to create .po files for each language specified. The .po files will be placed in src/locales but this is configurable. +3) Open up the .po file for the language you want to test and add some translations. In production we would pass this .po file off to the translation team. +4) Once you've edited your .po file (or we've gotten a .po file back from the translation team) run `npm run compile-strings`. This command takes the .po files and turns them into a minified JSON object and can be seen in the `messages.js` file in each locale directory. These files get loaded at the App root level (see: App.jsx). +5) Change the language in your browser and reload the page. You should see your specified translations in place of English strings. diff --git a/README.md b/README.md index de22f94b42..3b192e3fcb 100644 --- a/README.md +++ b/README.md @@ -27,13 +27,3 @@ To run a single test (in this case the login page test): * `npm test -- __tests__/pages/Login.jsx` **note:** Once the test watcher is up and running you can hit `a` to run all the tests - -## Internationalization - -Internationalization leans on the [lingui](https://github.com/lingui/js-lingui) project. [Official documentation here](https://lingui.js.org/). We use this libary to mark our strings for translation. For common React use cases see [this link](https://lingui.js.org/tutorials/react-patterns.html). If you want to see this in action you'll need to take the following steps: - -1) `npm run add-locale` to add the language that you want to translate to (we should only have to do this once and the commit to repo afaik). Example: `npm run add-locale en es fr` # Add English, Spanish and French locale -2) `npm run extract-strings` to create .po files for each language specified. The .po files will be placed in src/locales but this is configurable. -3) Open up the .po file for the language you want to test and add some translations. In production we would pass this .po file off to the translation team. -4) Once you've edited your .po file (or we've gotten a .po file back from the translation team) run `npm run compile-strings`. This command takes the .po files and turns them into a minified JSON object and can be seen in the `messages.js` file in each locale directory. These files get loaded at the App root level (see: App.jsx). -5) Change the language in your browser and reload the page. You should see your specified translations in place of English strings. diff --git a/__tests__/__snapshots__/enzymeHelpers.test.jsx.snap b/__tests__/__snapshots__/enzymeHelpers.test.jsx.snap index 892684faf0..50ac85a193 100644 --- a/__tests__/__snapshots__/enzymeHelpers.test.jsx.snap +++ b/__tests__/__snapshots__/enzymeHelpers.test.jsx.snap @@ -21,29 +21,28 @@ exports[`mountWithContexts injected ConfigProvider should mount and render with exports[`mountWithContexts injected I18nProvider should mount and render 1`] = `
- - - Text content - - + + Text content +
`; exports[`mountWithContexts injected I18nProvider should mount and render deeply nested consumer 1`] = ` - + -
- Text content -
+ +
+ Text content +
+
-
+
`; diff --git a/__tests__/components/AddResourceRole.test.jsx b/__tests__/components/AddResourceRole.test.jsx index edd8dcf1c2..3a3b4a2241 100644 --- a/__tests__/components/AddResourceRole.test.jsx +++ b/__tests__/components/AddResourceRole.test.jsx @@ -1,9 +1,9 @@ import React from 'react'; import { shallow } from 'enzyme'; import { mountWithContexts } from '../enzymeHelpers'; -import AddResourceRole from '../../src/components/AddRole/AddResourceRole'; +import AddResourceRole, { _AddResourceRole } from '../../src/components/AddRole/AddResourceRole'; -describe('', () => { +describe('<_AddResourceRole />', () => { const readUsers = jest.fn().mockResolvedValue({ data: { count: 2, @@ -31,21 +31,23 @@ describe('', () => { }; test('initially renders without crashing', () => { shallow( - {}} onSave={() => {}} roles={roles} + i18n={{ _: val => val.toString() }} /> ); }); test('handleRoleCheckboxClick properly updates state', () => { const wrapper = shallow( - {}} onSave={() => {}} roles={roles} + i18n={{ _: val => val.toString() }} /> ); wrapper.setState({ @@ -76,11 +78,12 @@ describe('', () => { }); test('handleResourceCheckboxClick properly updates state', () => { const wrapper = shallow( - {}} onSave={() => {}} roles={roles} + i18n={{ _: val => val.toString() }} /> ); wrapper.setState({ @@ -106,14 +109,13 @@ describe('', () => { }]); }); test('clicking user/team cards updates state', () => { - const spy = jest.spyOn(AddResourceRole.prototype, 'handleResourceSelect'); + const spy = jest.spyOn(_AddResourceRole.prototype, 'handleResourceSelect'); const wrapper = mountWithContexts( {}} onSave={() => {}} - api={api} roles={roles} - /> + />, { context: { network: { api, handleHttpError: () => {} } } } ).find('AddResourceRole'); const selectableCardWrapper = wrapper.find('SelectableCard'); expect(selectableCardWrapper.length).toBe(2); @@ -126,11 +128,12 @@ describe('', () => { }); test('readUsers and readTeams call out to corresponding api functions', () => { const wrapper = shallow( - {}} onSave={() => {}} roles={roles} + i18n={{ _: val => val.toString() }} /> ); wrapper.instance().readUsers({ @@ -150,11 +153,12 @@ describe('', () => { test('handleResourceSelect clears out selected lists and sets selectedResource', () => { const wrapper = shallow( - {}} onSave={() => {}} roles={roles} + i18n={{ _: val => val.toString() }} /> ); wrapper.setState({ @@ -193,11 +197,10 @@ describe('', () => { const handleSave = jest.fn(); const wrapper = mountWithContexts( {}} onSave={handleSave} roles={roles} - /> + />, { context: { network: { api, handleHttpError: () => {} } } } ).find('AddResourceRole'); wrapper.setState({ selectedResource: 'users', diff --git a/__tests__/components/AnsibleSelect.test.jsx b/__tests__/components/AnsibleSelect.test.jsx index cd308f2cfc..08d64ef811 100644 --- a/__tests__/components/AnsibleSelect.test.jsx +++ b/__tests__/components/AnsibleSelect.test.jsx @@ -1,6 +1,7 @@ import React from 'react'; import { mountWithContexts } from '../enzymeHelpers'; import AnsibleSelect from '../../src/components/AnsibleSelect'; +import { _AnsibleSelect } from '../../src/components/AnsibleSelect/AnsibleSelect'; const label = 'test select'; const mockData = ['/venv/baz/', '/venv/ansible/']; @@ -18,7 +19,7 @@ describe('', () => { }); test('calls "onSelectChange" on dropdown select change', () => { - const spy = jest.spyOn(AnsibleSelect.prototype, 'onSelectChange'); + const spy = jest.spyOn(_AnsibleSelect.prototype, 'onSelectChange'); const wrapper = mountWithContexts( ', () => { getItems={getItems} handleHttpError={() => {}} location={{ history }} + i18n={{ _: val => val.toString() }} /> ); diff --git a/__tests__/components/NotifyAndRedirect.test.jsx b/__tests__/components/NotifyAndRedirect.test.jsx index 910174db28..df4845359f 100644 --- a/__tests__/components/NotifyAndRedirect.test.jsx +++ b/__tests__/components/NotifyAndRedirect.test.jsx @@ -11,6 +11,7 @@ describe('', () => { to="foo" setRootDialogMessage={setRootDialogMessage} location={{ pathname: 'foo' }} + i18n={{ _: val => val.toString() }} /> ); expect(setRootDialogMessage).toHaveBeenCalled(); diff --git a/__tests__/components/PaginatedDataList/__snapshots__/DeleteToolbarButton.test.jsx.snap b/__tests__/components/PaginatedDataList/__snapshots__/DeleteToolbarButton.test.jsx.snap index 3315e9feb0..f230c0abbe 100644 --- a/__tests__/components/PaginatedDataList/__snapshots__/DeleteToolbarButton.test.jsx.snap +++ b/__tests__/components/PaginatedDataList/__snapshots__/DeleteToolbarButton.test.jsx.snap @@ -2,202 +2,202 @@ exports[` should render button 1`] = ` - - + + + Select a row to delete + + + } + delay={ + Array [ + 500, + 500, + ] + } + distance={15} + flip={true} + lazy={true} maxWidth="18.75rem" - position="left" + onCreate={[Function]} + performance={true} + placement="left" + popperOptions={ + Object { + "modifiers": Object { + "hide": Object { + "enabled": true, + }, + "preventOverflow": Object { + "enabled": true, + }, + }, + } + } + theme="pf-tippy" trigger="mouseenter focus" zIndex={9999} > - - - - Select a row to delete - - - } - delay={ - Array [ - 500, - 500, - ] - } - distance={15} - flip={true} - lazy={true} - maxWidth="18.75rem" - onCreate={[Function]} - performance={true} - placement="left" - popperOptions={ - Object { - "modifiers": Object { - "hide": Object { - "enabled": true, - }, - "preventOverflow": Object { - "enabled": true, - }, - }, - } - } - theme="pf-tippy" - trigger="mouseenter focus" - zIndex={9999} + - svg{color:#d2d2d2;}}}&:hover{background-color:#d9534f;> svg{color:white;}}", + ], + }, + "displayName": "ToolbarDeleteButton__Button", + "foldedComponentIds": Array [], + "render": [Function], + "styledComponentId": "ToolbarDeleteButton__Button-sc-1e3r0eg-0", + "target": [Function], + "toString": [Function], + "warnTooManyClasses": [Function], + "withComponent": [Function], + } + } + forwardedRef={null} isDisabled={true} onClick={[Function]} variant="plain" > - svg{color:#d2d2d2;}}}&:hover{background-color:#d9534f;> svg{color:white;}}", - ], - }, - "displayName": "ToolbarDeleteButton__Button", - "foldedComponentIds": Array [], - "render": [Function], - "styledComponentId": "ToolbarDeleteButton__Button-sc-1e3r0eg-0", - "target": [Function], - "toString": [Function], - "warnTooManyClasses": [Function], - "withComponent": [Function], - } - } - forwardedRef={null} + className="awx-ToolBarBtn ToolbarDeleteButton__Button-sc-1e3r0eg-0 iyjqWq" + component="button" + isActive={false} + isBlock={false} isDisabled={true} + isFocus={false} + isHover={false} onClick={[Function]} + type="button" variant="plain" > - - - - - - - } - > -
- + + + + + + + + - - - - + } + > +
+ +
+ + +
+ Select a row to delete +
+
+
+ + + `; diff --git a/__tests__/components/SelectResourceStep.test.jsx b/__tests__/components/SelectResourceStep.test.jsx index 6188fdf217..12912de606 100644 --- a/__tests__/components/SelectResourceStep.test.jsx +++ b/__tests__/components/SelectResourceStep.test.jsx @@ -3,7 +3,7 @@ import { createMemoryHistory } from 'history'; import { shallow } from 'enzyme'; import { mountWithContexts } from '../enzymeHelpers'; import { sleep } from '../testUtils'; -import SelectResourceStep, { _SelectResourceStep } from '../../src/components/AddRole/SelectResourceStep'; +import SelectResourceStep from '../../src/components/AddRole/SelectResourceStep'; describe('', () => { const columns = [ @@ -67,15 +67,14 @@ describe('', () => { initialEntries: ['/organizations/1/access?resource.page=1&resource.order_by=-username'], }); const wrapper = await mountWithContexts( - <_SelectResourceStep + {}} onSearch={handleSearch} selectedResourceRows={selectedResourceRows} sortedColumnKey="username" - location={history.location} - /> + />, { context: { router: { history, route: { location: history.location } } } } ).find('SelectResourceStep'); await wrapper.instance().readResourceList(); expect(handleSearch).toHaveBeenCalledWith({ diff --git a/__tests__/components/SelectRoleStep.test.jsx b/__tests__/components/SelectRoleStep.test.jsx index 6e323e2936..221014e18f 100644 --- a/__tests__/components/SelectRoleStep.test.jsx +++ b/__tests__/components/SelectRoleStep.test.jsx @@ -1,5 +1,6 @@ import React from 'react'; -import { mount, shallow } from 'enzyme'; +import { shallow } from 'enzyme'; +import { mountWithContexts } from '../enzymeHelpers'; import SelectRoleStep from '../../src/components/AddRole/SelectRoleStep'; describe('', () => { @@ -42,7 +43,7 @@ describe('', () => { }); test('clicking role fires onRolesClick callback', () => { const onRolesClick = jest.fn(); - wrapper = mount( + wrapper = mountWithContexts( initially renders succe canToggleNotifications={true} detailUrl="/foo" errorTurnedOn={false} + i18n={"/i18n/"} notification={ Object { "id": 9000, @@ -15,446 +16,526 @@ exports[` initially renders succe successTurnedOn={false} toggleNotification={[MockFunction]} > - - -
  • - -
    - - - - Foo - - - - slack - - , + - - - , - ] - } - key=".0" - rowid="items-list-item-9000" - > -
    - - - -
    + + + slack + + , + + + + , + ] + } + key=".0" + rowid="items-list-item-9000" + > +
    + + + +
    + - - - - - - Foo - - - - - - + + + + + + - - - - slack - - - - -
    -
    -
    -
    - + + + +
    + + + + + - - -
    - - - - - - - - + + + + + + + - - - - - - -
    -
    -
    -
    -
    - -
    - -
  • -
    -
    + Failure + + + + + + +
    + + + +
    + + + + + + + + + + + + `; diff --git a/__tests__/enzymeHelpers.test.jsx b/__tests__/enzymeHelpers.test.jsx index 3248cdbaf1..5ee423800a 100644 --- a/__tests__/enzymeHelpers.test.jsx +++ b/__tests__/enzymeHelpers.test.jsx @@ -1,7 +1,6 @@ import React from 'react'; import { Link } from 'react-router-dom'; -// import { mount } from 'enzyme'; -import { I18n } from '@lingui/react'; +import { withI18n } from '@lingui/react'; import { t } from '@lingui/macro'; import { mountWithContexts } from './enzymeHelpers'; import { Config } from '../src/contexts/Config'; @@ -11,26 +10,19 @@ import { withRootDialog } from '../src/contexts/RootDialog'; describe('mountWithContexts', () => { describe('injected I18nProvider', () => { test('should mount and render', () => { - const wrapper = mountWithContexts( + const Child = withI18n()(({ i18n }) => (
    - - {({ i18n }) => ( - {i18n._(t`Text content`)} - )} - + {i18n._(t`Text content`)}
    - ); + )); + const wrapper = mountWithContexts(); expect(wrapper.find('div')).toMatchSnapshot(); }); test('should mount and render deeply nested consumer', () => { - const Child = () => ( - - {({ i18n }) => ( -
    {i18n._(t`Text content`)}
    - )} -
    - ); + const Child = withI18n()(({ i18n }) => ( +
    {i18n._(t`Text content`)}
    + )); const Parent = () => (); const wrapper = mountWithContexts(); expect(wrapper.find('Parent')).toMatchSnapshot(); diff --git a/__tests__/pages/Applications.test.jsx b/__tests__/pages/Applications.test.jsx index f86759b04f..a8afd7cd43 100644 --- a/__tests__/pages/Applications.test.jsx +++ b/__tests__/pages/Applications.test.jsx @@ -1,5 +1,5 @@ import React from 'react'; -import { mount } from 'enzyme'; +import { mountWithContexts } from '../enzymeHelpers'; import Applications from '../../src/pages/Applications'; describe('', () => { @@ -8,7 +8,7 @@ describe('', () => { let title; beforeEach(() => { - pageWrapper = mount(); + pageWrapper = mountWithContexts(); pageSections = pageWrapper.find('PageSection'); title = pageWrapper.find('Title'); }); diff --git a/__tests__/pages/AuthSettings.test.jsx b/__tests__/pages/AuthSettings.test.jsx index afd11eeca5..18cc15903c 100644 --- a/__tests__/pages/AuthSettings.test.jsx +++ b/__tests__/pages/AuthSettings.test.jsx @@ -1,5 +1,5 @@ import React from 'react'; -import { mount } from 'enzyme'; +import { mountWithContexts } from '../enzymeHelpers'; import AuthSettings from '../../src/pages/AuthSettings'; describe('', () => { @@ -8,7 +8,7 @@ describe('', () => { let title; beforeEach(() => { - pageWrapper = mount(); + pageWrapper = mountWithContexts(); pageSections = pageWrapper.find('PageSection'); title = pageWrapper.find('Title'); }); diff --git a/__tests__/pages/CredentialTypes.test.jsx b/__tests__/pages/CredentialTypes.test.jsx index 9d5f9ea3d7..7b233aeaeb 100644 --- a/__tests__/pages/CredentialTypes.test.jsx +++ b/__tests__/pages/CredentialTypes.test.jsx @@ -1,5 +1,5 @@ import React from 'react'; -import { mount } from 'enzyme'; +import { mountWithContexts } from '../enzymeHelpers'; import CredentialTypes from '../../src/pages/CredentialTypes'; describe('', () => { @@ -8,7 +8,7 @@ describe('', () => { let title; beforeEach(() => { - pageWrapper = mount(); + pageWrapper = mountWithContexts(); pageSections = pageWrapper.find('PageSection'); title = pageWrapper.find('Title'); }); diff --git a/__tests__/pages/Credentials.test.jsx b/__tests__/pages/Credentials.test.jsx index 6acf0d4dc3..7f4f66022e 100644 --- a/__tests__/pages/Credentials.test.jsx +++ b/__tests__/pages/Credentials.test.jsx @@ -1,5 +1,5 @@ import React from 'react'; -import { mount } from 'enzyme'; +import { mountWithContexts } from '../enzymeHelpers'; import Credentials from '../../src/pages/Credentials'; describe('', () => { @@ -8,7 +8,7 @@ describe('', () => { let title; beforeEach(() => { - pageWrapper = mount(); + pageWrapper = mountWithContexts(); pageSections = pageWrapper.find('PageSection'); title = pageWrapper.find('Title'); }); diff --git a/__tests__/pages/Dashboard.test.jsx b/__tests__/pages/Dashboard.test.jsx index b5e9b9049a..43ff67f5f4 100644 --- a/__tests__/pages/Dashboard.test.jsx +++ b/__tests__/pages/Dashboard.test.jsx @@ -1,5 +1,5 @@ import React from 'react'; -import { mount } from 'enzyme'; +import { mountWithContexts } from '../enzymeHelpers'; import Dashboard from '../../src/pages/Dashboard'; describe('', () => { @@ -8,7 +8,7 @@ describe('', () => { let title; beforeEach(() => { - pageWrapper = mount(); + pageWrapper = mountWithContexts(); pageSections = pageWrapper.find('PageSection'); title = pageWrapper.find('Title'); }); diff --git a/__tests__/pages/InstanceGroups.test.jsx b/__tests__/pages/InstanceGroups.test.jsx index a78c2ff9c2..7cfbdf5397 100644 --- a/__tests__/pages/InstanceGroups.test.jsx +++ b/__tests__/pages/InstanceGroups.test.jsx @@ -1,5 +1,5 @@ import React from 'react'; -import { mount } from 'enzyme'; +import { mountWithContexts } from '../enzymeHelpers'; import InstanceGroups from '../../src/pages/InstanceGroups'; describe('', () => { @@ -8,7 +8,7 @@ describe('', () => { let title; beforeEach(() => { - pageWrapper = mount(); + pageWrapper = mountWithContexts(); pageSections = pageWrapper.find('PageSection'); title = pageWrapper.find('Title'); }); diff --git a/__tests__/pages/Inventories.test.jsx b/__tests__/pages/Inventories.test.jsx index 2296fc165c..8c98c52486 100644 --- a/__tests__/pages/Inventories.test.jsx +++ b/__tests__/pages/Inventories.test.jsx @@ -1,5 +1,5 @@ import React from 'react'; -import { mount } from 'enzyme'; +import { mountWithContexts } from '../enzymeHelpers'; import Inventories from '../../src/pages/Inventories'; describe('', () => { @@ -8,7 +8,7 @@ describe('', () => { let title; beforeEach(() => { - pageWrapper = mount(); + pageWrapper = mountWithContexts(); pageSections = pageWrapper.find('PageSection'); title = pageWrapper.find('Title'); }); diff --git a/__tests__/pages/InventoryScripts.test.jsx b/__tests__/pages/InventoryScripts.test.jsx index 253f7da7e4..e7f3e94687 100644 --- a/__tests__/pages/InventoryScripts.test.jsx +++ b/__tests__/pages/InventoryScripts.test.jsx @@ -1,5 +1,5 @@ import React from 'react'; -import { mount } from 'enzyme'; +import { mountWithContexts } from '../enzymeHelpers'; import InventoryScripts from '../../src/pages/InventoryScripts'; describe('', () => { @@ -8,7 +8,7 @@ describe('', () => { let title; beforeEach(() => { - pageWrapper = mount(); + pageWrapper = mountWithContexts(); pageSections = pageWrapper.find('PageSection'); title = pageWrapper.find('Title'); }); diff --git a/__tests__/pages/Jobs.test.jsx b/__tests__/pages/Jobs.test.jsx index 7529c3a831..82fbe1867e 100644 --- a/__tests__/pages/Jobs.test.jsx +++ b/__tests__/pages/Jobs.test.jsx @@ -1,5 +1,5 @@ import React from 'react'; -import { mount } from 'enzyme'; +import { mountWithContexts } from '../enzymeHelpers'; import Jobs from '../../src/pages/Jobs'; describe('', () => { @@ -8,7 +8,7 @@ describe('', () => { let title; beforeEach(() => { - pageWrapper = mount(); + pageWrapper = mountWithContexts(); pageSections = pageWrapper.find('PageSection'); title = pageWrapper.find('Title'); }); diff --git a/__tests__/pages/JobsSettings.test.jsx b/__tests__/pages/JobsSettings.test.jsx index 136e3a2d9f..af36ebb3a7 100644 --- a/__tests__/pages/JobsSettings.test.jsx +++ b/__tests__/pages/JobsSettings.test.jsx @@ -1,5 +1,5 @@ import React from 'react'; -import { mount } from 'enzyme'; +import { mountWithContexts } from '../enzymeHelpers'; import JobsSettings from '../../src/pages/JobsSettings'; describe('', () => { @@ -8,7 +8,7 @@ describe('', () => { let title; beforeEach(() => { - pageWrapper = mount(); + pageWrapper = mountWithContexts(); pageSections = pageWrapper.find('PageSection'); title = pageWrapper.find('Title'); }); diff --git a/__tests__/pages/License.test.jsx b/__tests__/pages/License.test.jsx index 3b637dd5c3..7a614c0410 100644 --- a/__tests__/pages/License.test.jsx +++ b/__tests__/pages/License.test.jsx @@ -1,5 +1,5 @@ import React from 'react'; -import { mount } from 'enzyme'; +import { mountWithContexts } from '../enzymeHelpers'; import License from '../../src/pages/License'; describe('', () => { @@ -8,7 +8,7 @@ describe('', () => { let title; beforeEach(() => { - pageWrapper = mount(); + pageWrapper = mountWithContexts(); pageSections = pageWrapper.find('PageSection'); title = pageWrapper.find('Title'); }); diff --git a/__tests__/pages/Login.test.jsx b/__tests__/pages/Login.test.jsx index 29a707fd59..57d4be3634 100644 --- a/__tests__/pages/Login.test.jsx +++ b/__tests__/pages/Login.test.jsx @@ -1,9 +1,7 @@ import React from 'react'; -import { MemoryRouter } from 'react-router-dom'; -import { mount } from 'enzyme'; -import { I18nProvider } from '@lingui/react'; +import { mountWithContexts } from '../enzymeHelpers'; import { asyncFlush } from '../../jest.setup'; -import { _AWXLogin } from '../../src/pages/Login'; +import AWXLogin from '../../src/pages/Login'; import APIClient from '../../src/api'; describe('', () => { @@ -18,6 +16,12 @@ describe('', () => { const api = new APIClient({}); + const mountLogin = () => { + loginWrapper = mountWithContexts(, { context: { network: { + api, handleHttpError: () => {} + } } }); + }; + const findChildren = () => { awxLogin = loginWrapper.find('AWXLogin'); loginPage = loginWrapper.find('LoginPage'); @@ -28,22 +32,13 @@ describe('', () => { loginHeaderLogo = loginPage.find('img'); }; - beforeEach(() => { - loginWrapper = mount( - - - <_AWXLogin api={api} clearRootDialogMessage={() => {}} handleHttpError={() => {}} /> - - - ); - findChildren(); - }); - afterEach(() => { loginWrapper.unmount(); }); test('initially renders without crashing', () => { + mountLogin(); + findChildren(); expect(loginWrapper.length).toBe(1); expect(loginPage.length).toBe(1); expect(loginForm.length).toBe(1); @@ -58,13 +53,7 @@ describe('', () => { }); test('custom logo renders Brand component with correct src and alt', () => { - loginWrapper = mount( - - - <_AWXLogin api={api} logo="images/foo.jpg" alt="Foo Application" /> - - - ); + loginWrapper = mountWithContexts(); findChildren(); expect(loginHeaderLogo.length).toBe(1); expect(loginHeaderLogo.props().src).toBe('data:image/jpeg;images/foo.jpg'); @@ -72,13 +61,7 @@ describe('', () => { }); test('default logo renders Brand component with correct src and alt', () => { - loginWrapper = mount( - - - <_AWXLogin api={api} /> - - - ); + mountLogin(); findChildren(); expect(loginHeaderLogo.length).toBe(1); expect(loginHeaderLogo.props().src).toBe('tower-logo-header.svg'); @@ -86,6 +69,8 @@ describe('', () => { }); test('state maps to un/pw input value props', () => { + mountLogin(); + findChildren(); awxLogin.setState({ username: 'un', password: 'pw' }); expect(awxLogin.state().username).toBe('un'); expect(awxLogin.state().password).toBe('pw'); @@ -95,6 +80,8 @@ describe('', () => { }); test('updating un/pw clears out error', () => { + mountLogin(); + findChildren(); awxLogin.setState({ isInputValid: false }); expect(loginWrapper.find('.pf-c-form__helper-text.pf-m-error').length).toBe(1); usernameInput.instance().value = 'uname'; @@ -113,6 +100,8 @@ describe('', () => { test('api.login not called when loading', () => { api.login = jest.fn().mockImplementation(() => Promise.resolve({})); + mountLogin(); + findChildren(); expect(awxLogin.state().isLoading).toBe(false); awxLogin.setState({ isLoading: true }); submitButton.simulate('click'); @@ -121,6 +110,8 @@ describe('', () => { test('submit calls api.login successfully', async () => { api.login = jest.fn().mockImplementation(() => Promise.resolve({})); + mountLogin(); + findChildren(); expect(awxLogin.state().isLoading).toBe(false); awxLogin.setState({ username: 'unamee', password: 'pwordd' }); submitButton.simulate('click'); @@ -137,6 +128,8 @@ describe('', () => { err.response = { status: 401, message: 'problem' }; return Promise.reject(err); }); + mountLogin(); + findChildren(); expect(awxLogin.state().isLoading).toBe(false); expect(awxLogin.state().isInputValid).toBe(true); awxLogin.setState({ username: 'unamee', password: 'pwordd' }); @@ -155,6 +148,8 @@ describe('', () => { err.response = { status: 500, message: 'problem' }; return Promise.reject(err); }); + mountLogin(); + findChildren(); expect(awxLogin.state().isLoading).toBe(false); awxLogin.setState({ username: 'unamee', password: 'pwordd' }); submitButton.simulate('click'); @@ -166,6 +161,8 @@ describe('', () => { }); test('render Redirect to / when already authenticated', () => { + mountLogin(); + findChildren(); awxLogin.setState({ isAuthenticated: true }); const redirectElem = loginWrapper.find('Redirect'); expect(redirectElem.length).toBe(1); diff --git a/__tests__/pages/ManagementJobs.test.jsx b/__tests__/pages/ManagementJobs.test.jsx index 0f26614b94..b2f2dbdc61 100644 --- a/__tests__/pages/ManagementJobs.test.jsx +++ b/__tests__/pages/ManagementJobs.test.jsx @@ -1,5 +1,5 @@ import React from 'react'; -import { mount } from 'enzyme'; +import { mountWithContexts } from '../enzymeHelpers'; import ManagementJobs from '../../src/pages/ManagementJobs'; describe('', () => { @@ -8,7 +8,7 @@ describe('', () => { let title; beforeEach(() => { - pageWrapper = mount(); + pageWrapper = mountWithContexts(); pageSections = pageWrapper.find('PageSection'); title = pageWrapper.find('Title'); }); diff --git a/__tests__/pages/NotifcationTemplates.test.jsx b/__tests__/pages/NotifcationTemplates.test.jsx index 4603c8c85e..9039d5475f 100644 --- a/__tests__/pages/NotifcationTemplates.test.jsx +++ b/__tests__/pages/NotifcationTemplates.test.jsx @@ -1,5 +1,5 @@ import React from 'react'; -import { mount } from 'enzyme'; +import { mountWithContexts } from '../enzymeHelpers'; import NotificationTemplates from '../../src/pages/NotificationTemplates'; describe('', () => { @@ -8,7 +8,7 @@ describe('', () => { let title; beforeEach(() => { - pageWrapper = mount(); + pageWrapper = mountWithContexts(); pageSections = pageWrapper.find('PageSection'); title = pageWrapper.find('Title'); }); diff --git a/__tests__/pages/Organizations/components/__snapshots__/DeleteRoleConfirmationModal.test.jsx.snap b/__tests__/pages/Organizations/components/__snapshots__/DeleteRoleConfirmationModal.test.jsx.snap index 57b9ffa547..015774b1c2 100644 --- a/__tests__/pages/Organizations/components/__snapshots__/DeleteRoleConfirmationModal.test.jsx.snap +++ b/__tests__/pages/Organizations/components/__snapshots__/DeleteRoleConfirmationModal.test.jsx.snap @@ -2,6 +2,7 @@ exports[` should render initially 1`] = ` should render initially 1`] = ` } username="jane" > - + Delete + , + , + ] + } + isOpen={true} + onClose={[Function]} + title="Remove {0} Access" + variant="danger" > - <_default + should render initially 1`] = ` , ] } + ariaDescribedById="" + className="awx-c-modal at-c-alertModal at-c-alertModal--danger" + hideTitle={false} + isLarge={false} isOpen={true} + isSmall={false} onClose={[Function]} - title="Remove Team Access" - variant="danger" + title="Remove {0} Access" + width={null} > - +
    - Delete - , - , - ] - } - ariaDescribedById="" - className="awx-c-modal at-c-alertModal at-c-alertModal--danger" - hideTitle={false} - isLarge={false} - isOpen={true} - isSmall={false} - onClose={[Function]} - title="Remove Team Access" - width={null} - > -
    - } - > - - Delete - , - , - ] - } - ariaDescribedById="" - className="awx-c-modal at-c-alertModal at-c-alertModal--danger" - hideTitle={false} - id="pf-modal-0" - isLarge={false} - isOpen={true} - isSmall={false} - onClose={[Function]} - title="Remove Team Access" - width={null} - > - -
    + } + > + - , + , + ] + } + ariaDescribedById="" + className="awx-c-modal at-c-alertModal at-c-alertModal--danger" + hideTitle={false} + id="pf-modal-0" + isLarge={false} + isOpen={true} + isSmall={false} + onClose={[Function]} + title="Remove {0} Access" + width={null} + > + +
    + +
    -
    - +
    -
    - -
    - - - - - - - <h3 - className="pf-c-title pf-m-2xl" - > - - Remove Team Access - - </h3> - - - -
    - , - , -
    , -
    , - , - , - ] - } - id="Are you sure you want to remove<0> {0} access from<1> {1}? Doing so affects all members of the team.<2/><3/>If you<4><5> only want to remove access for this particular user, please remove them from the team." - values={ - Object { - "0": "Member", - "1": "The Team", - } - } - > - - , - , -
    , -
    , - , - , - ] - } - i18n={"/i18n/"} - id="Are you sure you want to remove<0> {0} access from<1> {1}? Doing so affects all members of the team.<2/><3/>If you<4><5> only want to remove access for this particular user, please remove them from the team." - values={ - Object { - "0": "Member", - "1": "The Team", - } - } - > - -
    -
    -
    - should render initially 1`] = ` should render initially 1`] = ` "verticalAlign": "-0.125em", } } - viewBox="0 0 512 512" + viewBox="0 0 352 512" width="1em" > - -
    -
    - + + + + + - <div - className="pf-c-modal-box__footer" + <h3 + className="pf-c-title pf-m-2xl" > - <Button - aria-label="Confirm delete" - className="" - component="button" - isActive={false} - isBlock={false} - isDisabled={false} - isFocus={false} - isHover={false} - key="delete" - onClick={[Function]} - type="button" - variant="danger" - > - <button - aria-disabled={null} - aria-label="Confirm delete" - className="pf-c-button pf-m-danger" - disabled={false} - onClick={[Function]} - tabIndex={null} - type="button" - > - Delete - </button> - </Button> - <Button - aria-label={null} - className="" - component="button" - isActive={false} - isBlock={false} - isDisabled={false} - isFocus={false} - isHover={false} - key="cancel" - onClick={[Function]} - type="button" - variant="secondary" - > - <button - aria-disabled={null} - aria-label={null} - className="pf-c-button pf-m-secondary" - disabled={false} - onClick={[Function]} - tabIndex={null} - type="button" - > - Cancel - </button> - </Button> + Remove {0} Access - </div> - </ModalBoxFooter> - </div> - </ModalBox> - </div> - </FocusTrap> - </div> - </Bullseye> - </div> - </Backdrop> - </ModalContent> - </Portal> - </Modal> - </_default> - </I18n> + </h3> + + + +
    + Are you sure you want to remove {0} access from {1}? Doing so affects all members of the team. +
    +
    + If you {0} want to remove access for this particular user, please remove them from the team. + + + + + +
    +
    + +
    + + + + + + +
    +
    +
    +
    +
    + +
    + +
    + + + + + `; diff --git a/__tests__/pages/Organizations/components/__snapshots__/OrganizationAccessItem.test.jsx.snap b/__tests__/pages/Organizations/components/__snapshots__/OrganizationAccessItem.test.jsx.snap index 38ae63010b..d8a646bade 100644 --- a/__tests__/pages/Organizations/components/__snapshots__/OrganizationAccessItem.test.jsx.snap +++ b/__tests__/pages/Organizations/components/__snapshots__/OrganizationAccessItem.test.jsx.snap @@ -29,43 +29,146 @@ exports[` initially renders succesfully 1`] = ` "username": "jane", } } + i18n={"/i18n/"} onRoleDelete={[Function]} > - - -
  • - -
    - + - + + jane + + + + + , + +
      + + Team Roles + + + Member + +
    +
    , + ] + } + key=".0" + rowid="access-list-item" + > +
    + +
    + +
    initially renders succesfully 1`] = ` } } > - - jane - - - - - , - -
      - - Team Roles - - - Member - -
    -
    , - ] - } - key=".0" - rowid="access-list-item" - > -
    - -
    - - - - - -
    initially renders succesfully 1`] = ` } } > - Name + jane - -

    - jane brown -

    -
    -
    -
    -
    -
    -
    - -
    + +
    + + -
      - -
      initially renders succesfully 1`] = ` } } > - Team Roles -
      -
      - - -
    • - - Member - - + + +

      + jane brown +

      +
      +
    + +
    +
    + + +
    +
      + +
      + Team Roles +
      +
      + + +
    • + + Member + + + - - -
    • -
      -
      -
    -
    -
    -
    - -
    - -
  • -
    -
    + } + viewBox="0 0 512 512" + width="1em" + > + + + + + + + + + + +
    + +
    + +
    + + + `; diff --git a/__tests__/pages/Organizations/screens/Organization/__snapshots__/OrganizationAccess.test.jsx.snap b/__tests__/pages/Organizations/screens/Organization/__snapshots__/OrganizationAccess.test.jsx.snap index d9faca0720..e03c838e8d 100644 --- a/__tests__/pages/Organizations/screens/Organization/__snapshots__/OrganizationAccess.test.jsx.snap +++ b/__tests__/pages/Organizations/screens/Organization/__snapshots__/OrganizationAccess.test.jsx.snap @@ -5,6 +5,7 @@ exports[` initially renders succesfully 1`] = ` api={"/api/"} handleHttpError={[Function]} history={"/history/"} + i18n={"/i18n/"} location={ Object { "hash": "", diff --git a/__tests__/pages/Organizations/screens/Organization/__snapshots__/OrganizationNotifications.test.jsx.snap b/__tests__/pages/Organizations/screens/Organization/__snapshots__/OrganizationNotifications.test.jsx.snap index 0f2db3c9df..093b1885d8 100644 --- a/__tests__/pages/Organizations/screens/Organization/__snapshots__/OrganizationNotifications.test.jsx.snap +++ b/__tests__/pages/Organizations/screens/Organization/__snapshots__/OrganizationNotifications.test.jsx.snap @@ -57,7 +57,7 @@ exports[` initially renders succesfully 1`] = ` } } > - initially renders succesfully 1`] = ` ] } > - - + initially renders succesfully 1`] = ` }, ] } - location={ - Object { - "hash": "", - "pathname": "", - "search": "", - "state": "", - } - } - match={ - Object { - "isExact": false, - "params": Object {}, - "path": "", - "url": "", - } - } - onSelectAll={null} - paginationStyling={null} qsConfig={ Object { "defaultParams": Object { @@ -171,8 +152,6 @@ exports[` initially renders succesfully 1`] = ` } } renderItem={[Function]} - showPageSizeOptions={true} - showSelectAll={false} toolbarColumns={ Array [ Object { @@ -195,13 +174,68 @@ exports[` initially renders succesfully 1`] = ` ] } > - - + initially renders succesfully 1`] = ` }, ] } - isAllSelected={false} - isCompact={false} - noLeftMargin={false} - onCompact={null} - onExpand={null} - onSearch={[Function]} - onSelectAll={null} - onSort={[Function]} - showSelectAll={false} - sortOrder="ascending" - sortedColumnKey="name" > - - - + -
    - - + +
    - -
    - - +
    -
    - - + +
    + + + +
    + + + +
    + + Modified + , + + Created + , + ] + } + isOpen={false} + onSelect={[Function]} + onToggle={[Function]} + toggle={ + + Name + + } + > + + Modified + , + + Created + , + ] + } + forwardedComponent={ + Object { + "$$typeof": Symbol(react.forward_ref), + "attrs": Array [], + "componentStyle": ComponentStyle { + "componentId": "Search__Dropdown-sc-1dwuww3-2", + "isStatic": true, + "lastClassName": "kcnywV", + "rules": Array [ + "&&&{> button{min-height:30px;min-width:70px;height:30px;padding:0 10px;margin:0px;> span{width:auto;}> svg{margin:0px;padding-top:3px;padding-left:3px;}}}", + ], + }, + "displayName": "Search__Dropdown", + "foldedComponentIds": Array [], + "render": [Function], + "styledComponentId": "Search__Dropdown-sc-1dwuww3-2", + "target": [Function], + "toString": [Function], + "warnTooManyClasses": [Function], + "withComponent": [Function], + } + } + forwardedRef={null} + isOpen={false} + onSelect={[Function]} + onToggle={[Function]} + toggle={ + + Name + + } + > + + Modified + , + + Created + , + ] + } + isOpen={false} + isPlain={false} + onSelect={[Function]} + onToggle={[Function]} + position="left" + toggle={ + + Name + + } + > +
    + + +
    + } + > + + +
    + } + > + + + +
    + +
    + + + + + + + + + + + + + + +
    + + + +
    + + + + +
    + +
    +
    +
    +
    +
    + + +
    - initially renders succesfully 1`] = ` }, ] } - onSearch={[Function]} + onSort={[Function]} + sortOrder="ascending" sortedColumnKey="name" > -
    - initially renders succesfully 1`] = ` isOpen={false} onSelect={[Function]} onToggle={[Function]} + style={ + Object { + "marginRight": "20px", + } + } toggle={ initially renders succesfully 1`] = ` "$$typeof": Symbol(react.forward_ref), "attrs": Array [], "componentStyle": ComponentStyle { - "componentId": "Search__Dropdown-sc-1dwuww3-2", + "componentId": "Sort__Dropdown-sc-21g5aw-0", "isStatic": true, - "lastClassName": "kcnywV", + "lastClassName": "kdSQuN", "rules": Array [ "&&&{> button{min-height:30px;min-width:70px;height:30px;padding:0 10px;margin:0px;> span{width:auto;}> svg{margin:0px;padding-top:3px;padding-left:3px;}}}", ], }, - "displayName": "Search__Dropdown", + "displayName": "Sort__Dropdown", "foldedComponentIds": Array [], "render": [Function], - "styledComponentId": "Search__Dropdown-sc-1dwuww3-2", + "styledComponentId": "Sort__Dropdown-sc-21g5aw-0", "target": [Function], "toString": [Function], "warnTooManyClasses": [Function], @@ -491,11 +1204,16 @@ exports[` initially renders succesfully 1`] = ` isOpen={false} onSelect={[Function]} onToggle={[Function]} + style={ + Object { + "marginRight": "20px", + } + } toggle={ initially renders succesfully 1`] = ` } > initially renders succesfully 1`] = ` onSelect={[Function]} onToggle={[Function]} position="left" + style={ + Object { + "marginRight": "20px", + } + } toggle={ initially renders succesfully 1`] = ` } >
    initially renders succesfully 1`] = ` onToggle={[Function]} parentRef={
    - - - - - - - - - + initially renders succesfully 1`] = ` } forwardedRef={null} onClick={[Function]} - variant="tertiary" + variant="plain" > - -
    + + - +
    - - - -
    - + +
    + + +
    +
    + +
    + + + +
    + + + + + + +
      + + + + +
    • + +
      + + + + Notification one + + + + email + + , + + -
      - -
    -
    - - - + , + ] } - forwardedRef={null} + key=".0" + rowid="items-list-item-1" >
    - -
    - - - - Modified - , - - Created - , - ] - } - isOpen={false} - onSelect={[Function]} - onToggle={[Function]} - style={ - Object { - "marginRight": "20px", - } - } - toggle={ - - Name - - } - > - - Modified - , - - Created - , - ] - } - forwardedComponent={ - Object { - "$$typeof": Symbol(react.forward_ref), - "attrs": Array [], - "componentStyle": ComponentStyle { - "componentId": "Sort__Dropdown-sc-21g5aw-0", - "isStatic": true, - "lastClassName": "kdSQuN", - "rules": Array [ - "&&&{> button{min-height:30px;min-width:70px;height:30px;padding:0 10px;margin:0px;> span{width:auto;}> svg{margin:0px;padding-top:3px;padding-left:3px;}}}", - ], - }, - "displayName": "Sort__Dropdown", - "foldedComponentIds": Array [], - "render": [Function], - "styledComponentId": "Sort__Dropdown-sc-21g5aw-0", - "target": [Function], - "toString": [Function], - "warnTooManyClasses": [Function], - "withComponent": [Function], - } - } - forwardedRef={null} - isOpen={false} - onSelect={[Function]} - onToggle={[Function]} - style={ - Object { - "marginRight": "20px", - } - } - toggle={ - - Name - - } - > - - Modified - , - - Created - , - ] - } - isOpen={false} - isPlain={false} - onSelect={[Function]} - onToggle={[Function]} - position="left" - style={ - Object { - "marginRight": "20px", - } - } - toggle={ - - Name - - } - > -
    - - -
    - } - > - - -
    - } - > - - - -
    - -
    - - - - - - - - - -
    - - initially renders succesfully 1`] = ` } forwardedRef={null} > -
    - - -
    -
    - -
    - -
    -
    -
    -
    -
    -
    -
    - -
      - - - -
    • - -
      - - - - Notification one - - - - email - - , - - - - , - ] - } - key=".0" - rowid="items-list-item-1" - > -
      - - - -
      - - - - - - Notification one - - - - - - - - + + Notification one + + + + + + - - email - - - - -
      -
      -
      -
      - - - + + email + + + + +
      + + + + -
      - - - - - - - - - - + + + + + + + + + - - - - -
      - - -
      -
      - -
    - - - -
    - - - - -
  • - -
    - - - - Notification two - - - - email - - , - - - - , - ] - } - key=".0" - rowid="items-list-item-2" - > -
    - + + + + + + + + +
    + + + +
    + + initially renders succesfully 1`] = ` } } forwardedRef={null} + id="notification-1-error-toggle" + isChecked={false} + isDisabled={false} + label="Failure" + onChange={[Function]} + rowid="items-list-item-1" > - -
    - + + + + + + + +
    +
    +
  • +
    +
    +
    + + + + + +
  • + +
    + + - - + + + email + + , + + + + , + ] + } + key=".0" + rowid="items-list-item-2" + > +
    + + + +
    + - - - Notification two - - - - - - - - + + Notification two + + + + + + - - email - - - - -
    -
    -
    -
    - + + email + + + + +
    + + + + + + +
    + + + + + + + + + + + + + + +
    +
    +
    +
    +
    + + initially renders succesfully 1`] = ` } } forwardedRef={null} - righthalf="true" + id="notification-2-error-toggle" + isChecked={true} + isDisabled={false} + label="Failure" + onChange={[Function]} + rowid="items-list-item-2" > - -
    - - - - - - - - + + -
    -
    + Failure + + + +
    - +
    - - -
    -
  • -
    -
    - - - - - + + + + +
    + + + -
    -
    - - - - - - - - - 50 - , - - 25 - , - - 10 - , - ] - } - isOpen={false} - isPlain={false} - onSelect={[Function]} - onToggle={[Function]} - position="left" - toggle={ - - 5 - - } +
    - + 50 + , + + 25 + , + + 10 + , + ] + } isOpen={false} isPlain={false} - key=".0" - onEnter={[Function]} + onSelect={[Function]} onToggle={[Function]} - parentRef={ -
    - -
    + 5 +
    } > - + + +
    + } + > + + +
    + } > -
    - } - > - - - + + +
    + - - -
    -
    - - - - - - - + Items {itemMin} – {itemMax} of {count} +
    +
    - - - - - - - - + + +
    + + + + + diff --git a/__tests__/pages/Portal.test.jsx b/__tests__/pages/Portal.test.jsx index ba411fdac1..892034ba76 100644 --- a/__tests__/pages/Portal.test.jsx +++ b/__tests__/pages/Portal.test.jsx @@ -1,5 +1,5 @@ import React from 'react'; -import { mount } from 'enzyme'; +import { mountWithContexts } from '../enzymeHelpers'; import Portal from '../../src/pages/Portal'; describe('', () => { @@ -8,7 +8,7 @@ describe('', () => { let title; beforeEach(() => { - pageWrapper = mount(); + pageWrapper = mountWithContexts(); pageSections = pageWrapper.find('PageSection'); title = pageWrapper.find('Title'); }); diff --git a/__tests__/pages/Projects.test.jsx b/__tests__/pages/Projects.test.jsx index 8ec7510325..9e7ec2c623 100644 --- a/__tests__/pages/Projects.test.jsx +++ b/__tests__/pages/Projects.test.jsx @@ -1,5 +1,5 @@ import React from 'react'; -import { mount } from 'enzyme'; +import { mountWithContexts } from '../enzymeHelpers'; import Projects from '../../src/pages/Projects'; describe('', () => { @@ -8,7 +8,7 @@ describe('', () => { let title; beforeEach(() => { - pageWrapper = mount(); + pageWrapper = mountWithContexts(); pageSections = pageWrapper.find('PageSection'); title = pageWrapper.find('Title'); }); diff --git a/__tests__/pages/Schedules.test.jsx b/__tests__/pages/Schedules.test.jsx index a144c5e985..b2255f9fc1 100644 --- a/__tests__/pages/Schedules.test.jsx +++ b/__tests__/pages/Schedules.test.jsx @@ -1,5 +1,5 @@ import React from 'react'; -import { mount } from 'enzyme'; +import { mountWithContexts } from '../enzymeHelpers'; import Schedules from '../../src/pages/Schedules'; describe('', () => { @@ -8,7 +8,7 @@ describe('', () => { let title; beforeEach(() => { - pageWrapper = mount(); + pageWrapper = mountWithContexts(); pageSections = pageWrapper.find('PageSection'); title = pageWrapper.find('Title'); }); diff --git a/__tests__/pages/SystemSettings.test.jsx b/__tests__/pages/SystemSettings.test.jsx index cc86976a52..9fa1f751c7 100644 --- a/__tests__/pages/SystemSettings.test.jsx +++ b/__tests__/pages/SystemSettings.test.jsx @@ -1,5 +1,5 @@ import React from 'react'; -import { mount } from 'enzyme'; +import { mountWithContexts } from '../enzymeHelpers'; import SystemSettings from '../../src/pages/SystemSettings'; describe('', () => { @@ -8,7 +8,7 @@ describe('', () => { let title; beforeEach(() => { - pageWrapper = mount(); + pageWrapper = mountWithContexts(); pageSections = pageWrapper.find('PageSection'); title = pageWrapper.find('Title'); }); diff --git a/__tests__/pages/Teams.test.jsx b/__tests__/pages/Teams.test.jsx index 80f52cbc69..9d10331dcf 100644 --- a/__tests__/pages/Teams.test.jsx +++ b/__tests__/pages/Teams.test.jsx @@ -1,5 +1,5 @@ import React from 'react'; -import { mount } from 'enzyme'; +import { mountWithContexts } from '../enzymeHelpers'; import Teams from '../../src/pages/Teams'; describe('', () => { @@ -8,7 +8,7 @@ describe('', () => { let title; beforeEach(() => { - pageWrapper = mount(); + pageWrapper = mountWithContexts(); pageSections = pageWrapper.find('PageSection'); title = pageWrapper.find('Title'); }); diff --git a/__tests__/pages/Templates.test.jsx b/__tests__/pages/Templates.test.jsx index 2a3f4ef869..433c1648b2 100644 --- a/__tests__/pages/Templates.test.jsx +++ b/__tests__/pages/Templates.test.jsx @@ -1,5 +1,5 @@ import React from 'react'; -import { mount } from 'enzyme'; +import { mountWithContexts } from '../enzymeHelpers'; import Templates from '../../src/pages/Templates'; describe('', () => { @@ -8,7 +8,7 @@ describe('', () => { let title; beforeEach(() => { - pageWrapper = mount(); + pageWrapper = mountWithContexts(); pageSections = pageWrapper.find('PageSection'); title = pageWrapper.find('Title'); }); diff --git a/__tests__/pages/UISettings.test.jsx b/__tests__/pages/UISettings.test.jsx index 3d6c6c88d2..3ecab146bf 100644 --- a/__tests__/pages/UISettings.test.jsx +++ b/__tests__/pages/UISettings.test.jsx @@ -1,5 +1,5 @@ import React from 'react'; -import { mount } from 'enzyme'; +import { mountWithContexts } from '../enzymeHelpers'; import UISettings from '../../src/pages/UISettings'; describe('', () => { @@ -8,7 +8,7 @@ describe('', () => { let title; beforeEach(() => { - pageWrapper = mount(); + pageWrapper = mountWithContexts(); pageSections = pageWrapper.find('PageSection'); title = pageWrapper.find('Title'); }); diff --git a/__tests__/pages/Users.test.jsx b/__tests__/pages/Users.test.jsx index 48199690a9..bdacf86be1 100644 --- a/__tests__/pages/Users.test.jsx +++ b/__tests__/pages/Users.test.jsx @@ -1,5 +1,5 @@ import React from 'react'; -import { mount } from 'enzyme'; +import { mountWithContexts } from '../enzymeHelpers'; import Users from '../../src/pages/Users'; describe('', () => { @@ -8,7 +8,7 @@ describe('', () => { let title; beforeEach(() => { - pageWrapper = mount(); + pageWrapper = mountWithContexts(); pageSections = pageWrapper.find('PageSection'); title = pageWrapper.find('Title'); }); diff --git a/__tests__/util/validators.test.js b/__tests__/util/validators.test.js index d197c61a21..3021f804cb 100644 --- a/__tests__/util/validators.test.js +++ b/__tests__/util/validators.test.js @@ -1,34 +1,36 @@ import { required, maxLength } from '../../src/util/validators'; +const i18n = { _: val => val }; + describe('validators', () => { test('required returns undefined if value given', () => { - expect(required()('some value')).toBeUndefined(); - expect(required('oops')('some value')).toBeUndefined(); + expect(required(null, i18n)('some value')).toBeUndefined(); + expect(required('oops', i18n)('some value')).toBeUndefined(); }); test('required returns default message if value missing', () => { - expect(required()('')).toEqual('This field must not be blank'); + expect(required(null, i18n)('')).toEqual({ id: 'This field must not be blank' }); }); test('required returns custom message if value missing', () => { - expect(required('oops')('')).toEqual('oops'); + expect(required('oops', i18n)('')).toEqual('oops'); }); test('required interprets white space as empty value', () => { - expect(required()(' ')).toEqual('This field must not be blank'); - expect(required()('\t')).toEqual('This field must not be blank'); + expect(required(null, i18n)(' ')).toEqual({ id: 'This field must not be blank' }); + expect(required(null, i18n)('\t')).toEqual({ id: 'This field must not be blank' }); }); test('maxLength accepts value below max', () => { - expect(maxLength(10)('snazzy')).toBeUndefined(); + expect(maxLength(10, i18n)('snazzy')).toBeUndefined(); }); test('maxLength accepts value equal to max', () => { - expect(maxLength(10)('abracadbra')).toBeUndefined(); + expect(maxLength(10, i18n)('abracadbra')).toBeUndefined(); }); test('maxLength rejects value above max', () => { - expect(maxLength(8)('abracadbra')) - .toEqual('This field must not exceed 8 characters'); + expect(maxLength(8, i18n)('abracadbra')) + .toEqual({ id: 'This field must not exceed {max} characters', values: { max: 8 } }); }); }); diff --git a/build/locales/en/messages.po b/build/locales/en/messages.po index 028b852868..070d3b5067 100644 --- a/build/locales/en/messages.po +++ b/build/locales/en/messages.po @@ -13,6 +13,10 @@ msgstr "" "Language-Team: \n" "Plural-Forms: \n" +#: src/contexts/Network.jsx:56 +msgid "404" +msgstr "" + #: src/pages/Organizations/components/OrganizationBreadcrumb.jsx:60 #~ msgid "> add" #~ msgstr "" @@ -25,20 +29,34 @@ msgstr "" msgid "About" msgstr "" -#: src/components/About.jsx:60 +#: src/components/About.jsx:59 msgid "AboutModal Logo" msgstr "" -#: src/index.jsx:175 +#: src/index.jsx:140 +#: src/pages/Organizations/Organizations.jsx:43 +#: src/pages/Organizations/screens/Organization/Organization.jsx:131 msgid "Access" msgstr "" -#: src/components/DataListToolbar/DataListToolbar.jsx:266 -#: src/pages/Organizations/components/OrganizationBreadcrumb.jsx:68 +#: src/components/PaginatedDataList/ToolbarAddButton.jsx:33 +#: src/components/PaginatedDataList/ToolbarAddButton.jsx:44 msgid "Add" msgstr "" -#: src/index.jsx:196 +#: src/components/AddRole/AddResourceRole.jsx:153 +msgid "Add Roles" +msgstr "" + +#: src/components/AddRole/AddResourceRole.jsx:150 +msgid "Add Team Roles" +msgstr "" + +#: src/components/AddRole/AddResourceRole.jsx:147 +msgid "Add User Roles" +msgstr "" + +#: src/index.jsx:161 msgid "Administration" msgstr "" @@ -46,67 +64,154 @@ msgstr "" #~ msgid "Admins" #~ msgstr "" -#: src/components/About.jsx:77 +#: src/pages/Organizations/components/OrganizationForm.jsx:123 +#: src/pages/Organizations/components/OrganizationForm.jsx:128 +#: src/pages/Organizations/screens/Organization/OrganizationDetail.jsx:142 +msgid "Ansible Environment" +msgstr "" + +#: src/components/About.jsx:75 msgid "Ansible Version" msgstr "" -#: src/pages/Applications.jsx:17 +#: src/pages/Applications.jsx:19 msgid "Applications" msgstr "" -#: src/index.jsx:231 +#: src/components/AddRole/AddResourceRole.jsx:209 +msgid "Apply roles" +msgstr "" + +#: src/components/PaginatedDataList/ToolbarDeleteButton.jsx:165 +msgid "Are you sure you want to delete:" +msgstr "" + +#: src/pages/Organizations/components/DeleteRoleConfirmationModal.jsx:51 +msgid "Are you sure you want to remove {0} access from {1}? Doing so affects all members of the team." +msgstr "" + +#: src/pages/Organizations/components/DeleteRoleConfirmationModal.jsx:58 +msgid "Are you sure you want to remove {0} access from {username}?" +msgstr "" + +#: src/index.jsx:196 msgid "Authentication" msgstr "" -#: src/pages/AuthSettings.jsx:17 +#: src/pages/AuthSettings.jsx:19 msgid "Authentication Settings" msgstr "" -#: src/components/About.jsx:58 +#: src/components/About.jsx:57 msgid "Brand Image" msgstr "" -#: src/components/DataListToolbar/DataListToolbar.jsx:241 +#: src/components/FormActionGroup/FormActionGroup.jsx:30 +#: src/components/FormActionGroup/FormActionGroup.jsx:30 +#: src/components/Lookup/Lookup.jsx:169 +#: src/components/PaginatedDataList/ToolbarDeleteButton.jsx:161 +#: src/pages/Organizations/components/DeleteRoleConfirmationModal.jsx:45 +msgid "Cancel" +msgstr "" + +#: src/pages/Organizations/Organizations.jsx:77 +msgid "Cannot find organization with ID" +msgstr "" + +#: src/contexts/Network.jsx:57 +msgid "Cannot find resource." +msgstr "" + +#: src/components/NotifyAndRedirect.jsx:23 +msgid "Cannot find route {0}." +msgstr "" + +#: src/App.jsx:94 +#: src/components/CardCloseButton.jsx:14 +#: src/components/CardCloseButton.jsx:15 +#: src/components/CardCloseButton.jsx:27 +#: src/components/Lookup/Lookup.jsx:169 +#: src/pages/Organizations/screens/OrganizationAdd.jsx:67 +msgid "Close" +msgstr "" + +#: src/components/ExpandCollapse/ExpandCollapse.jsx:34 msgid "Collapse" msgstr "" -#: src/components/About.jsx:56 +#: src/components/About.jsx:55 msgid "Copyright 2018 Red Hat, Inc." msgstr "" -#: src/pages/Organizations/views/Organizations.list.jsx:29 +#: src/pages/Organizations/Organizations.jsx:39 +#: src/pages/Organizations/Organizations.jsx:25 +msgid "Create New Organization" +msgstr "" + +#: src/pages/Organizations/components/InstanceGroupsLookup.jsx:58 +#: src/pages/Organizations/screens/Organization/OrganizationDetail.jsx:146 +#: src/pages/Organizations/screens/OrganizationsList.jsx:164 msgid "Created" msgstr "" -#: src/index.jsx:200 -#: src/pages/CredentialTypes.jsx:17 +#: src/index.jsx:165 +#: src/pages/CredentialTypes.jsx:19 msgid "Credential Types" msgstr "" -#: src/index.jsx:153 -#: src/pages/Credentials.jsx:17 +#: src/index.jsx:118 +#: src/pages/Credentials.jsx:19 msgid "Credentials" msgstr "" -#: src/index.jsx:122 -#: src/pages/Dashboard.jsx:17 +#: src/index.jsx:87 +#: src/pages/Dashboard.jsx:19 msgid "Dashboard" msgstr "" -#: src/components/DataListToolbar/DataListToolbar.jsx:252 -#: src/components/DataListToolbar/DataListToolbar.jsx:257 +#: src/components/PaginatedDataList/ToolbarDeleteButton.jsx:109 +#: src/components/PaginatedDataList/ToolbarDeleteButton.jsx:130 +#: src/components/PaginatedDataList/ToolbarDeleteButton.jsx:153 +#: src/pages/Organizations/components/DeleteRoleConfirmationModal.jsx:42 msgid "Delete" msgstr "" -#: src/pages/Organizations/components/OrganizationBreadcrumb.jsx:59 +#: src/components/PaginatedDataList/ToolbarDeleteButton.jsx:142 +msgid "Delete {0}" +msgstr "" + +#: src/components/PaginatedDataList/ToolbarDeleteButton.jsx:141 +msgid "Delete {itemName}" +msgstr "" + +#: src/pages/Organizations/components/OrganizationForm.jsx:113 +#: src/pages/Organizations/screens/Organization/OrganizationDetail.jsx:138 +msgid "Description" +msgstr "" + +#: src/pages/Organizations/Organizations.jsx:42 +#: src/pages/Organizations/screens/Organization/Organization.jsx:130 +msgid "Details" +msgstr "" + +#: src/pages/Organizations/screens/Organization/OrganizationDetail.jsx:171 msgid "Edit" msgstr "" -#: src/components/DataListToolbar/DataListToolbar.jsx:233 +#: src/pages/Organizations/Organizations.jsx:41 +msgid "Edit Details" +msgstr "" + +#: src/components/ExpandCollapse/ExpandCollapse.jsx:44 msgid "Expand" msgstr "" -#: src/components/Pagination/Pagination.jsx:169 +#: src/components/NotificationsList/NotificationListItem.jsx:82 +#: src/components/NotificationsList/NotificationListItem.jsx:97 +msgid "Failure" +msgstr "" + +#: src/components/Pagination/Pagination.jsx:170 msgid "First" msgstr "" @@ -114,260 +219,436 @@ msgstr "" msgid "Help" msgstr "" -#: src/index.jsx:215 -#: src/pages/InstanceGroups.jsx:17 +#: src/pages/Organizations/components/DeleteRoleConfirmationModal.jsx:54 +msgid "If you {0} want to remove access for this particular user, please remove them from the team." +msgstr "" + +#: src/components/PageHeaderToolbar.jsx:66 +msgid "Info" +msgstr "" + +#: src/index.jsx:180 +#: src/pages/InstanceGroups.jsx:19 +#: src/pages/Organizations/components/InstanceGroupsLookup.jsx:32 +#: src/pages/Organizations/components/InstanceGroupsLookup.jsx:50 +#: src/pages/Organizations/screens/Organization/OrganizationDetail.jsx:159 msgid "Instance Groups" msgstr "" -#: src/index.jsx:220 +#: src/index.jsx:185 msgid "Integrations" msgstr "" -#: src/pages/Login.jsx:80 +#: src/pages/Login.jsx:84 msgid "Invalid username or password. Please try again." msgstr "" -#: src/index.jsx:163 -#: src/pages/Inventories.jsx:17 +#: src/index.jsx:128 +#: src/pages/Inventories.jsx:19 msgid "Inventories" msgstr "" -#: src/index.jsx:168 -#: src/pages/InventoryScripts.jsx:17 +#: src/index.jsx:133 +#: src/pages/InventoryScripts.jsx:19 msgid "Inventory Scripts" msgstr "" -#: src/index.jsx:127 -#: src/index.jsx:236 -#: src/pages/Jobs.jsx:17 +#: src/components/Pagination/Pagination.jsx:142 +msgid "Items Per Page" +msgstr "" + +#: src/components/Pagination/Pagination.jsx:162 +msgid "Items {itemMin} – {itemMax} of {count}" +msgstr "" + +#: src/index.jsx:92 +#: src/index.jsx:201 +#: src/pages/Jobs.jsx:19 msgid "Jobs" msgstr "" -#: src/pages/JobsSettings.jsx:17 +#: src/pages/JobsSettings.jsx:19 msgid "Jobs Settings" msgstr "" -#: src/components/Pagination/Pagination.jsx:221 +#: src/components/Pagination/Pagination.jsx:213 msgid "Last" msgstr "" -#: src/index.jsx:251 -#: src/pages/License.jsx:17 +#: src/pages/Organizations/screens/Organization/OrganizationDetail.jsx:150 +msgid "Last Modified" +msgstr "" + +#: src/pages/Organizations/screens/Organization/OrganizationAccess.jsx:173 +msgid "Last Name" +msgstr "" + +#: src/index.jsx:216 +#: src/pages/License.jsx:19 msgid "License" msgstr "" -#: src/components/PageHeaderToolbar.jsx:116 +#: src/components/AddRole/SelectResourceStep.jsx:96 +msgid "Loading..." +msgstr "" + +#: src/components/PageHeaderToolbar.jsx:120 msgid "Logout" msgstr "" -#: src/index.jsx:210 -#: src/pages/ManagementJobs.jsx:17 +#: src/index.jsx:175 +#: src/pages/ManagementJobs.jsx:19 msgid "Management Jobs" msgstr "" -#: src/pages/Organizations/views/Organizations.list.jsx:28 +#: src/pages/Organizations/components/OrganizationListItem.jsx:91 +msgid "Members" +msgstr "" + +#: src/pages/Organizations/components/InstanceGroupsLookup.jsx:57 +#: src/pages/Organizations/screens/OrganizationsList.jsx:163 msgid "Modified" msgstr "" -#: src/index.jsx:137 -#: src/pages/Portal.jsx:17 +#: src/index.jsx:102 +#: src/pages/Portal.jsx:19 msgid "My View" msgstr "" -#: src/pages/Organizations/views/Organizations.list.jsx:27 +#: src/components/AddRole/AddResourceRole.jsx:140 +#: src/components/PaginatedDataList/PaginatedDataList.jsx:116 +#: src/pages/Organizations/components/InstanceGroupsLookup.jsx:56 +#: src/pages/Organizations/components/OrganizationAccessItem.jsx:109 +#: src/pages/Organizations/components/OrganizationForm.jsx:105 +#: src/pages/Organizations/screens/Organization/OrganizationAccess.jsx:171 +#: src/pages/Organizations/screens/Organization/OrganizationDetail.jsx:134 +#: src/pages/Organizations/screens/OrganizationsList.jsx:162 msgid "Name" msgstr "" -#: src/components/Pagination/Pagination.jsx:212 +#: src/components/Pagination/Pagination.jsx:204 msgid "Next" msgstr "" -#: src/pages/NotificationTemplates.jsx:17 +#: src/components/PaginatedDataList/PaginatedDataList.jsx:133 +#: src/components/PaginatedDataList/PaginatedDataList.jsx:196 +msgid "No {0} Found" +msgstr "" + +#: src/pages/NotificationTemplates.jsx:19 msgid "Notification Templates" msgstr "" -#: src/index.jsx:205 +#: src/index.jsx:170 +#: src/pages/Organizations/Organizations.jsx:45 +#: src/pages/Organizations/screens/Organization/Organization.jsx:137 msgid "Notifications" msgstr "" #: src/pages/Organizations/views/Organization.add.jsx:79 -msgid "Organization Add" -msgstr "" +#~ msgid "Organization Add" +#~ msgstr "" -#: src/pages/Organizations/components/OrganizationDetail.jsx:72 +#: src/pages/Organizations/screens/Organization/Organization.jsx:153 msgid "Organization detail tabs" msgstr "" -#: src/index.jsx:179 -#: src/pages/Organizations/views/Organization.view.jsx:63 -#: src/pages/Organizations/views/Organizations.list.jsx:196 -#: src/pages/Organizations/views/Organizations.list.jsx:202 +#: src/index.jsx:144 +#: src/pages/Organizations/Organizations.jsx:38 +#: src/pages/Organizations/Organizations.jsx:24 msgid "Organizations" msgstr "" #: src/pages/Organizations/views/Organizations.list.jsx:218 -msgid "Organizations List" +#~ msgid "Organizations List" +#~ msgstr "" + +#: src/components/Pagination/Pagination.jsx:190 +msgid "Page" msgstr "" #: src/components/Pagination/Pagination.jsx:189 -msgid "Page <0/> of {pageCount}" -msgstr "" +#~ msgid "Page <0/> of {pageCount}" +#~ msgstr "" -#: src/components/Pagination/Pagination.jsx:192 +#: src/components/Pagination/Pagination.jsx:193 msgid "Page Number" msgstr "" -#: src/pages/Login.jsx:79 +#: src/pages/Login.jsx:82 msgid "Password" msgstr "" #: src/components/Pagination/Pagination.jsx:158 -msgid "Per Page" +#~ msgid "Per Page" +#~ msgstr "" + +#: src/components/PaginatedDataList/PaginatedDataList.jsx:136 +#: src/components/PaginatedDataList/PaginatedDataList.jsx:199 +msgid "Please add {0} {itemName} to populate this list" msgstr "" #: src/App.jsx:203 #~ msgid "Portal Mode" #~ msgstr "" -#: src/components/Pagination/Pagination.jsx:178 +#: src/components/Pagination/Pagination.jsx:179 msgid "Previous" msgstr "" -#: src/index.jsx:115 +#: src/index.jsx:80 msgid "Primary Navigation" msgstr "" -#: src/index.jsx:158 -#: src/pages/Projects.jsx:17 +#: src/index.jsx:123 +#: src/pages/Projects.jsx:19 msgid "Projects" msgstr "" -#: src/index.jsx:144 +#: src/pages/Organizations/components/DeleteRoleConfirmationModal.jsx:28 +msgid "Remove {0} Access" +msgstr "" + +#: src/index.jsx:109 msgid "Resources" msgstr "" -#: src/index.jsx:132 -#: src/pages/Schedules.jsx:17 +#: src/components/AddRole/AddResourceRole.jsx:220 +#: src/components/FormActionGroup/FormActionGroup.jsx:27 +#: src/components/FormActionGroup/FormActionGroup.jsx:27 +#: src/components/Lookup/Lookup.jsx:168 +msgid "Save" +msgstr "" + +#: src/index.jsx:97 +#: src/pages/Schedules.jsx:19 msgid "Schedules" msgstr "" -#: src/components/DataListToolbar/DataListToolbar.jsx:191 +#: src/components/Search/Search.jsx:138 msgid "Search" msgstr "" -#: src/components/DataListToolbar/DataListToolbar.jsx:185 +#: src/components/Search/Search.jsx:131 msgid "Search text input" msgstr "" -#: src/components/DataListToolbar/DataListToolbar.jsx:160 +#: src/components/AnsibleSelect/AnsibleSelect.jsx:28 +msgid "Select Input" +msgstr "" + +#: src/components/AddRole/AddResourceRole.jsx:159 +msgid "Select Users Or Teams" +msgstr "" + +#: src/components/PaginatedDataList/ToolbarDeleteButton.jsx:111 +msgid "Select a row to delete" +msgstr "" + +#: src/components/DataListToolbar/DataListToolbar.jsx:102 msgid "Select all" msgstr "" -#: src/index.jsx:227 +#: src/components/AddRole/AddResourceRole.jsx:178 +msgid "Select items from list" +msgstr "" + +#: src/pages/Organizations/components/OrganizationForm.jsx:141 +msgid "Select the Instance Groups for this Organization to run on." +msgstr "" + +#: src/components/Lookup/Lookup.jsx:164 +msgid "Select {header}" +msgstr "" + +#: src/components/AddRole/AddResourceRole.jsx:187 +#: src/components/AddRole/AddResourceRole.jsx:198 +#: src/components/AddRole/AddResourceRole.jsx:215 +#: src/components/AddRole/SelectRoleStep.jsx:29 +#: src/components/Lookup/Lookup.jsx:193 +msgid "Selected" +msgstr "" + +#: src/index.jsx:192 msgid "Settings" msgstr "" -#: src/components/DataListToolbar/DataListToolbar.jsx:222 +#: src/components/Sort/Sort.jsx:135 msgid "Sort" msgstr "" -#: src/index.jsx:241 +#: src/components/NotificationsList/NotificationListItem.jsx:70 +msgid "Successful" +msgstr "" + +#: src/index.jsx:206 msgid "System" msgstr "" -#: src/pages/SystemSettings.jsx:17 +#: src/pages/SystemSettings.jsx:19 msgid "System Settings" msgstr "" -#: src/index.jsx:189 -#: src/pages/Organizations/components/OrganizationListItem.jsx:57 -#: src/pages/Teams.jsx:17 +#: src/pages/Organizations/components/DeleteRoleConfirmationModal.jsx:28 +msgid "Team" +msgstr "" + +#: src/pages/Organizations/components/OrganizationAccessItem.jsx:144 +msgid "Team Roles" +msgstr "" + +#: src/components/AddRole/AddResourceRole.jsx:169 +#: src/index.jsx:154 +#: src/pages/Organizations/Organizations.jsx:44 +#: src/pages/Organizations/components/OrganizationListItem.jsx:99 +#: src/pages/Organizations/screens/Organization/Organization.jsx:132 +#: src/pages/Teams.jsx:19 msgid "Teams" msgstr "" -#: src/index.jsx:148 -#: src/pages/Templates.jsx:17 +#: src/index.jsx:113 +#: src/pages/Templates.jsx:19 msgid "Templates" msgstr "" +#: src/util/validators.jsx:6 +msgid "This field must not be blank" +msgstr "" + +#: src/util/validators.jsx:16 +msgid "This field must not exceed {max} characters" +msgstr "" + +#: src/components/NotificationsList/NotificationListItem.jsx:90 +#: src/components/NotificationsList/NotificationListItem.jsx:105 +msgid "Toggle notification failure" +msgstr "" + +#: src/components/NotificationsList/NotificationListItem.jsx:78 +msgid "Toggle notification success" +msgstr "" + #: src/components/TowerLogo/TowerLogo.jsx:48 msgid "Tower Brand Image" msgstr "" -#: src/components/PageHeaderToolbar.jsx:108 +#: src/components/AnsibleSelect/AnsibleSelect.jsx:35 +msgid "Use Default {label}" +msgstr "" + +#: src/pages/Organizations/components/DeleteRoleConfirmationModal.jsx:28 +msgid "User" +msgstr "" + +#: src/components/PageHeaderToolbar.jsx:113 msgid "User Details" msgstr "" -#: src/index.jsx:246 +#: src/index.jsx:211 msgid "User Interface" msgstr "" -#: src/pages/UISettings.jsx:17 +#: src/pages/UISettings.jsx:19 msgid "User Interface Settings" msgstr "" -#: src/pages/Login.jsx:78 +#: src/pages/Organizations/components/OrganizationAccessItem.jsx:122 +msgid "User Roles" +msgstr "" + +#: src/components/AddRole/AddResourceRole.jsx:136 +#: src/pages/Login.jsx:81 +#: src/pages/Organizations/screens/Organization/OrganizationAccess.jsx:172 msgid "Username" msgstr "" -#: src/index.jsx:184 -#: src/pages/Organizations/components/OrganizationListItem.jsx:49 -#: src/pages/Users.jsx:17 +#: src/components/AddRole/AddResourceRole.jsx:164 +#: src/index.jsx:149 +#: src/pages/Users.jsx:19 msgid "Users" msgstr "" -#: src/index.jsx:118 +#: src/index.jsx:83 msgid "Views" msgstr "" -#: src/pages/Login.jsx:74 +#: src/pages/Login.jsx:76 msgid "Welcome to Ansible Tower! Please Sign In." msgstr "" -#: src/pages/Organizations/components/OrganizationDetail.jsx:56 -msgid "add {currentTab}" +#: src/components/PaginatedDataList/ToolbarDeleteButton.jsx:104 +msgid "You do not have permission to delete the following {0}: {itemsUnableToDelete}" msgstr "" +#: src/contexts/Network.jsx:44 +msgid "You have been logged out." +msgstr "" + +#: src/pages/Organizations/components/OrganizationDetail.jsx:56 +#~ msgid "add {currentTab}" +#~ msgstr "" + #: src/pages/Organizations/components/OrganizationDetail.jsx:45 -msgid "adding {currentTab}" +#~ msgid "adding {currentTab}" +#~ msgstr "" + +#: src/components/PaginatedDataList/ToolbarDeleteButton.jsx:158 +msgid "cancel delete" +msgstr "" + +#: src/components/PaginatedDataList/ToolbarDeleteButton.jsx:150 +msgid "confirm delete" msgstr "" #: src/pages/Organizations/components/OrganizationDetail.jsx:38 -msgid "confirm removal of {currentTab}/cancel and go back to {currentTab} view." -msgstr "" +#~ msgid "confirm removal of {currentTab}/cancel and go back to {currentTab} view." +#~ msgstr "" #: src/pages/Organizations/components/OrganizationDetail.jsx:60 -msgid "delete {currentTab}" -msgstr "" +#~ msgid "delete {currentTab}" +#~ msgstr "" #: src/pages/Organizations/components/OrganizationDetail.jsx:36 -msgid "deleting {currentTab} association with orgs" -msgstr "" +#~ msgid "deleting {currentTab} association with orgs" +#~ msgstr "" #: src/pages/Organizations/components/OrganizationEdit.jsx:20 -msgid "edit view" +#~ msgid "edit view" +#~ msgstr "" + +#: src/components/Lookup/Lookup.jsx:135 +msgid "items" +msgstr "" + +#: src/components/Pagination/Pagination.jsx:198 +msgid "of {pageCount}" msgstr "" #: src/pages/Organizations/components/OrganizationEdit.jsx:22 -msgid "save/cancel and go back to view" -msgstr "" +#~ msgid "save/cancel and go back to view" +#~ msgstr "" #: src/pages/Organizations/components/OrganizationDetail.jsx:47 -msgid "save/cancel and go back to {currentTab} view" -msgstr "" +#~ msgid "save/cancel and go back to {currentTab} view" +#~ msgstr "" #: src/pages/Organizations/components/OrganizationListItem.jsx:29 -msgid "select organization {itemId}" -msgstr "" +#~ msgid "select organization {itemId}" +#~ msgstr "" #: src/pages/Organizations/components/OrganizationDetail.jsx:82 -msgid "{0}" +#~ msgid "{0}" +#~ msgstr "" + +#: src/components/PaginatedDataList/PaginatedDataList.jsx:153 +#: src/components/PaginatedDataList/PaginatedDataList.jsx:215 +msgid "{0} List" msgstr "" #: src/pages/Organizations/components/OrganizationDetail.jsx:54 -msgid "{currentTab} detail view" -msgstr "" +#~ msgid "{currentTab} detail view" +#~ msgstr "" #: src/components/Pagination/Pagination.jsx:163 -msgid "{itemMin} - {itemMax} of {count}" -msgstr "" +#~ msgid "{itemMin} - {itemMax} of {count}" +#~ msgstr "" diff --git a/build/locales/ja/messages.po b/build/locales/ja/messages.po index 281199eef1..741d9e4070 100644 --- a/build/locales/ja/messages.po +++ b/build/locales/ja/messages.po @@ -13,6 +13,10 @@ msgstr "" "Language-Team: \n" "Plural-Forms: \n" +#: src/contexts/Network.jsx:56 +msgid "404" +msgstr "" + #: src/pages/Organizations/components/OrganizationBreadcrumb.jsx:60 #~ msgid "> add" #~ msgstr "" @@ -25,20 +29,34 @@ msgstr "" msgid "About" msgstr "" -#: src/components/About.jsx:60 +#: src/components/About.jsx:59 msgid "AboutModal Logo" msgstr "" -#: src/index.jsx:175 +#: src/index.jsx:140 +#: src/pages/Organizations/Organizations.jsx:43 +#: src/pages/Organizations/screens/Organization/Organization.jsx:131 msgid "Access" msgstr "" -#: src/components/DataListToolbar/DataListToolbar.jsx:266 -#: src/pages/Organizations/components/OrganizationBreadcrumb.jsx:68 +#: src/components/PaginatedDataList/ToolbarAddButton.jsx:33 +#: src/components/PaginatedDataList/ToolbarAddButton.jsx:44 msgid "Add" msgstr "" -#: src/index.jsx:196 +#: src/components/AddRole/AddResourceRole.jsx:153 +msgid "Add Roles" +msgstr "" + +#: src/components/AddRole/AddResourceRole.jsx:150 +msgid "Add Team Roles" +msgstr "" + +#: src/components/AddRole/AddResourceRole.jsx:147 +msgid "Add User Roles" +msgstr "" + +#: src/index.jsx:161 msgid "Administration" msgstr "" @@ -46,67 +64,154 @@ msgstr "" #~ msgid "Admins" #~ msgstr "" -#: src/components/About.jsx:77 +#: src/pages/Organizations/components/OrganizationForm.jsx:123 +#: src/pages/Organizations/components/OrganizationForm.jsx:128 +#: src/pages/Organizations/screens/Organization/OrganizationDetail.jsx:142 +msgid "Ansible Environment" +msgstr "" + +#: src/components/About.jsx:75 msgid "Ansible Version" msgstr "" -#: src/pages/Applications.jsx:17 +#: src/pages/Applications.jsx:19 msgid "Applications" msgstr "" -#: src/index.jsx:231 +#: src/components/AddRole/AddResourceRole.jsx:209 +msgid "Apply roles" +msgstr "" + +#: src/components/PaginatedDataList/ToolbarDeleteButton.jsx:165 +msgid "Are you sure you want to delete:" +msgstr "" + +#: src/pages/Organizations/components/DeleteRoleConfirmationModal.jsx:51 +msgid "Are you sure you want to remove {0} access from {1}? Doing so affects all members of the team." +msgstr "" + +#: src/pages/Organizations/components/DeleteRoleConfirmationModal.jsx:58 +msgid "Are you sure you want to remove {0} access from {username}?" +msgstr "" + +#: src/index.jsx:196 msgid "Authentication" msgstr "" -#: src/pages/AuthSettings.jsx:17 +#: src/pages/AuthSettings.jsx:19 msgid "Authentication Settings" msgstr "" -#: src/components/About.jsx:58 +#: src/components/About.jsx:57 msgid "Brand Image" msgstr "" -#: src/components/DataListToolbar/DataListToolbar.jsx:241 +#: src/components/FormActionGroup/FormActionGroup.jsx:30 +#: src/components/FormActionGroup/FormActionGroup.jsx:30 +#: src/components/Lookup/Lookup.jsx:169 +#: src/components/PaginatedDataList/ToolbarDeleteButton.jsx:161 +#: src/pages/Organizations/components/DeleteRoleConfirmationModal.jsx:45 +msgid "Cancel" +msgstr "" + +#: src/pages/Organizations/Organizations.jsx:77 +msgid "Cannot find organization with ID" +msgstr "" + +#: src/contexts/Network.jsx:57 +msgid "Cannot find resource." +msgstr "" + +#: src/components/NotifyAndRedirect.jsx:23 +msgid "Cannot find route {0}." +msgstr "" + +#: src/App.jsx:94 +#: src/components/CardCloseButton.jsx:14 +#: src/components/CardCloseButton.jsx:15 +#: src/components/CardCloseButton.jsx:27 +#: src/components/Lookup/Lookup.jsx:169 +#: src/pages/Organizations/screens/OrganizationAdd.jsx:67 +msgid "Close" +msgstr "" + +#: src/components/ExpandCollapse/ExpandCollapse.jsx:34 msgid "Collapse" msgstr "" -#: src/components/About.jsx:56 +#: src/components/About.jsx:55 msgid "Copyright 2018 Red Hat, Inc." msgstr "" -#: src/pages/Organizations/views/Organizations.list.jsx:29 +#: src/pages/Organizations/Organizations.jsx:39 +#: src/pages/Organizations/Organizations.jsx:25 +msgid "Create New Organization" +msgstr "" + +#: src/pages/Organizations/components/InstanceGroupsLookup.jsx:58 +#: src/pages/Organizations/screens/Organization/OrganizationDetail.jsx:146 +#: src/pages/Organizations/screens/OrganizationsList.jsx:164 msgid "Created" msgstr "" -#: src/index.jsx:200 -#: src/pages/CredentialTypes.jsx:17 +#: src/index.jsx:165 +#: src/pages/CredentialTypes.jsx:19 msgid "Credential Types" msgstr "" -#: src/index.jsx:153 -#: src/pages/Credentials.jsx:17 +#: src/index.jsx:118 +#: src/pages/Credentials.jsx:19 msgid "Credentials" msgstr "" -#: src/index.jsx:122 -#: src/pages/Dashboard.jsx:17 +#: src/index.jsx:87 +#: src/pages/Dashboard.jsx:19 msgid "Dashboard" msgstr "" -#: src/components/DataListToolbar/DataListToolbar.jsx:252 -#: src/components/DataListToolbar/DataListToolbar.jsx:257 +#: src/components/PaginatedDataList/ToolbarDeleteButton.jsx:109 +#: src/components/PaginatedDataList/ToolbarDeleteButton.jsx:130 +#: src/components/PaginatedDataList/ToolbarDeleteButton.jsx:153 +#: src/pages/Organizations/components/DeleteRoleConfirmationModal.jsx:42 msgid "Delete" msgstr "" -#: src/pages/Organizations/components/OrganizationBreadcrumb.jsx:59 +#: src/components/PaginatedDataList/ToolbarDeleteButton.jsx:142 +msgid "Delete {0}" +msgstr "" + +#: src/components/PaginatedDataList/ToolbarDeleteButton.jsx:141 +msgid "Delete {itemName}" +msgstr "" + +#: src/pages/Organizations/components/OrganizationForm.jsx:113 +#: src/pages/Organizations/screens/Organization/OrganizationDetail.jsx:138 +msgid "Description" +msgstr "" + +#: src/pages/Organizations/Organizations.jsx:42 +#: src/pages/Organizations/screens/Organization/Organization.jsx:130 +msgid "Details" +msgstr "" + +#: src/pages/Organizations/screens/Organization/OrganizationDetail.jsx:171 msgid "Edit" msgstr "" -#: src/components/DataListToolbar/DataListToolbar.jsx:233 +#: src/pages/Organizations/Organizations.jsx:41 +msgid "Edit Details" +msgstr "" + +#: src/components/ExpandCollapse/ExpandCollapse.jsx:44 msgid "Expand" msgstr "" -#: src/components/Pagination/Pagination.jsx:169 +#: src/components/NotificationsList/NotificationListItem.jsx:82 +#: src/components/NotificationsList/NotificationListItem.jsx:97 +msgid "Failure" +msgstr "" + +#: src/components/Pagination/Pagination.jsx:170 msgid "First" msgstr "" @@ -114,260 +219,436 @@ msgstr "" msgid "Help" msgstr "" -#: src/index.jsx:215 -#: src/pages/InstanceGroups.jsx:17 +#: src/pages/Organizations/components/DeleteRoleConfirmationModal.jsx:54 +msgid "If you {0} want to remove access for this particular user, please remove them from the team." +msgstr "" + +#: src/components/PageHeaderToolbar.jsx:66 +msgid "Info" +msgstr "" + +#: src/index.jsx:180 +#: src/pages/InstanceGroups.jsx:19 +#: src/pages/Organizations/components/InstanceGroupsLookup.jsx:32 +#: src/pages/Organizations/components/InstanceGroupsLookup.jsx:50 +#: src/pages/Organizations/screens/Organization/OrganizationDetail.jsx:159 msgid "Instance Groups" msgstr "" -#: src/index.jsx:220 +#: src/index.jsx:185 msgid "Integrations" msgstr "" -#: src/pages/Login.jsx:80 +#: src/pages/Login.jsx:84 msgid "Invalid username or password. Please try again." msgstr "" -#: src/index.jsx:163 -#: src/pages/Inventories.jsx:17 +#: src/index.jsx:128 +#: src/pages/Inventories.jsx:19 msgid "Inventories" msgstr "" -#: src/index.jsx:168 -#: src/pages/InventoryScripts.jsx:17 +#: src/index.jsx:133 +#: src/pages/InventoryScripts.jsx:19 msgid "Inventory Scripts" msgstr "" -#: src/index.jsx:127 -#: src/index.jsx:236 -#: src/pages/Jobs.jsx:17 +#: src/components/Pagination/Pagination.jsx:142 +msgid "Items Per Page" +msgstr "" + +#: src/components/Pagination/Pagination.jsx:162 +msgid "Items {itemMin} – {itemMax} of {count}" +msgstr "" + +#: src/index.jsx:92 +#: src/index.jsx:201 +#: src/pages/Jobs.jsx:19 msgid "Jobs" msgstr "" -#: src/pages/JobsSettings.jsx:17 +#: src/pages/JobsSettings.jsx:19 msgid "Jobs Settings" msgstr "" -#: src/components/Pagination/Pagination.jsx:221 +#: src/components/Pagination/Pagination.jsx:213 msgid "Last" msgstr "" -#: src/index.jsx:251 -#: src/pages/License.jsx:17 +#: src/pages/Organizations/screens/Organization/OrganizationDetail.jsx:150 +msgid "Last Modified" +msgstr "" + +#: src/pages/Organizations/screens/Organization/OrganizationAccess.jsx:173 +msgid "Last Name" +msgstr "" + +#: src/index.jsx:216 +#: src/pages/License.jsx:19 msgid "License" msgstr "" -#: src/components/PageHeaderToolbar.jsx:116 +#: src/components/AddRole/SelectResourceStep.jsx:96 +msgid "Loading..." +msgstr "" + +#: src/components/PageHeaderToolbar.jsx:120 msgid "Logout" msgstr "" -#: src/index.jsx:210 -#: src/pages/ManagementJobs.jsx:17 +#: src/index.jsx:175 +#: src/pages/ManagementJobs.jsx:19 msgid "Management Jobs" msgstr "" -#: src/pages/Organizations/views/Organizations.list.jsx:28 +#: src/pages/Organizations/components/OrganizationListItem.jsx:91 +msgid "Members" +msgstr "" + +#: src/pages/Organizations/components/InstanceGroupsLookup.jsx:57 +#: src/pages/Organizations/screens/OrganizationsList.jsx:163 msgid "Modified" msgstr "" -#: src/index.jsx:137 -#: src/pages/Portal.jsx:17 +#: src/index.jsx:102 +#: src/pages/Portal.jsx:19 msgid "My View" msgstr "" -#: src/pages/Organizations/views/Organizations.list.jsx:27 +#: src/components/AddRole/AddResourceRole.jsx:140 +#: src/components/PaginatedDataList/PaginatedDataList.jsx:116 +#: src/pages/Organizations/components/InstanceGroupsLookup.jsx:56 +#: src/pages/Organizations/components/OrganizationAccessItem.jsx:109 +#: src/pages/Organizations/components/OrganizationForm.jsx:105 +#: src/pages/Organizations/screens/Organization/OrganizationAccess.jsx:171 +#: src/pages/Organizations/screens/Organization/OrganizationDetail.jsx:134 +#: src/pages/Organizations/screens/OrganizationsList.jsx:162 msgid "Name" msgstr "" -#: src/components/Pagination/Pagination.jsx:212 +#: src/components/Pagination/Pagination.jsx:204 msgid "Next" msgstr "" -#: src/pages/NotificationTemplates.jsx:17 +#: src/components/PaginatedDataList/PaginatedDataList.jsx:133 +#: src/components/PaginatedDataList/PaginatedDataList.jsx:196 +msgid "No {0} Found" +msgstr "" + +#: src/pages/NotificationTemplates.jsx:19 msgid "Notification Templates" msgstr "" -#: src/index.jsx:205 +#: src/index.jsx:170 +#: src/pages/Organizations/Organizations.jsx:45 +#: src/pages/Organizations/screens/Organization/Organization.jsx:137 msgid "Notifications" msgstr "" #: src/pages/Organizations/views/Organization.add.jsx:79 -msgid "Organization Add" -msgstr "" +#~ msgid "Organization Add" +#~ msgstr "" -#: src/pages/Organizations/components/OrganizationDetail.jsx:72 +#: src/pages/Organizations/screens/Organization/Organization.jsx:153 msgid "Organization detail tabs" msgstr "" -#: src/index.jsx:179 -#: src/pages/Organizations/views/Organization.view.jsx:63 -#: src/pages/Organizations/views/Organizations.list.jsx:196 -#: src/pages/Organizations/views/Organizations.list.jsx:202 +#: src/index.jsx:144 +#: src/pages/Organizations/Organizations.jsx:38 +#: src/pages/Organizations/Organizations.jsx:24 msgid "Organizations" msgstr "" #: src/pages/Organizations/views/Organizations.list.jsx:218 -msgid "Organizations List" +#~ msgid "Organizations List" +#~ msgstr "" + +#: src/components/Pagination/Pagination.jsx:190 +msgid "Page" msgstr "" #: src/components/Pagination/Pagination.jsx:189 -msgid "Page <0/> of {pageCount}" -msgstr "" +#~ msgid "Page <0/> of {pageCount}" +#~ msgstr "" -#: src/components/Pagination/Pagination.jsx:192 +#: src/components/Pagination/Pagination.jsx:193 msgid "Page Number" msgstr "" -#: src/pages/Login.jsx:79 +#: src/pages/Login.jsx:82 msgid "Password" msgstr "" #: src/components/Pagination/Pagination.jsx:158 -msgid "Per Page" +#~ msgid "Per Page" +#~ msgstr "" + +#: src/components/PaginatedDataList/PaginatedDataList.jsx:136 +#: src/components/PaginatedDataList/PaginatedDataList.jsx:199 +msgid "Please add {0} {itemName} to populate this list" msgstr "" #: src/App.jsx:203 #~ msgid "Portal Mode" #~ msgstr "" -#: src/components/Pagination/Pagination.jsx:178 +#: src/components/Pagination/Pagination.jsx:179 msgid "Previous" msgstr "" -#: src/index.jsx:115 +#: src/index.jsx:80 msgid "Primary Navigation" msgstr "" -#: src/index.jsx:158 -#: src/pages/Projects.jsx:17 +#: src/index.jsx:123 +#: src/pages/Projects.jsx:19 msgid "Projects" msgstr "" -#: src/index.jsx:144 +#: src/pages/Organizations/components/DeleteRoleConfirmationModal.jsx:28 +msgid "Remove {0} Access" +msgstr "" + +#: src/index.jsx:109 msgid "Resources" msgstr "" -#: src/index.jsx:132 -#: src/pages/Schedules.jsx:17 +#: src/components/AddRole/AddResourceRole.jsx:220 +#: src/components/FormActionGroup/FormActionGroup.jsx:27 +#: src/components/FormActionGroup/FormActionGroup.jsx:27 +#: src/components/Lookup/Lookup.jsx:168 +msgid "Save" +msgstr "" + +#: src/index.jsx:97 +#: src/pages/Schedules.jsx:19 msgid "Schedules" msgstr "" -#: src/components/DataListToolbar/DataListToolbar.jsx:191 +#: src/components/Search/Search.jsx:138 msgid "Search" msgstr "" -#: src/components/DataListToolbar/DataListToolbar.jsx:185 +#: src/components/Search/Search.jsx:131 msgid "Search text input" msgstr "" -#: src/components/DataListToolbar/DataListToolbar.jsx:160 +#: src/components/AnsibleSelect/AnsibleSelect.jsx:28 +msgid "Select Input" +msgstr "" + +#: src/components/AddRole/AddResourceRole.jsx:159 +msgid "Select Users Or Teams" +msgstr "" + +#: src/components/PaginatedDataList/ToolbarDeleteButton.jsx:111 +msgid "Select a row to delete" +msgstr "" + +#: src/components/DataListToolbar/DataListToolbar.jsx:102 msgid "Select all" msgstr "" -#: src/index.jsx:227 +#: src/components/AddRole/AddResourceRole.jsx:178 +msgid "Select items from list" +msgstr "" + +#: src/pages/Organizations/components/OrganizationForm.jsx:141 +msgid "Select the Instance Groups for this Organization to run on." +msgstr "" + +#: src/components/Lookup/Lookup.jsx:164 +msgid "Select {header}" +msgstr "" + +#: src/components/AddRole/AddResourceRole.jsx:187 +#: src/components/AddRole/AddResourceRole.jsx:198 +#: src/components/AddRole/AddResourceRole.jsx:215 +#: src/components/AddRole/SelectRoleStep.jsx:29 +#: src/components/Lookup/Lookup.jsx:193 +msgid "Selected" +msgstr "" + +#: src/index.jsx:192 msgid "Settings" msgstr "" -#: src/components/DataListToolbar/DataListToolbar.jsx:222 +#: src/components/Sort/Sort.jsx:135 msgid "Sort" msgstr "" -#: src/index.jsx:241 +#: src/components/NotificationsList/NotificationListItem.jsx:70 +msgid "Successful" +msgstr "" + +#: src/index.jsx:206 msgid "System" msgstr "" -#: src/pages/SystemSettings.jsx:17 +#: src/pages/SystemSettings.jsx:19 msgid "System Settings" msgstr "" -#: src/index.jsx:189 -#: src/pages/Organizations/components/OrganizationListItem.jsx:57 -#: src/pages/Teams.jsx:17 +#: src/pages/Organizations/components/DeleteRoleConfirmationModal.jsx:28 +msgid "Team" +msgstr "" + +#: src/pages/Organizations/components/OrganizationAccessItem.jsx:144 +msgid "Team Roles" +msgstr "" + +#: src/components/AddRole/AddResourceRole.jsx:169 +#: src/index.jsx:154 +#: src/pages/Organizations/Organizations.jsx:44 +#: src/pages/Organizations/components/OrganizationListItem.jsx:99 +#: src/pages/Organizations/screens/Organization/Organization.jsx:132 +#: src/pages/Teams.jsx:19 msgid "Teams" msgstr "" -#: src/index.jsx:148 -#: src/pages/Templates.jsx:17 +#: src/index.jsx:113 +#: src/pages/Templates.jsx:19 msgid "Templates" msgstr "" +#: src/util/validators.jsx:6 +msgid "This field must not be blank" +msgstr "" + +#: src/util/validators.jsx:16 +msgid "This field must not exceed {max} characters" +msgstr "" + +#: src/components/NotificationsList/NotificationListItem.jsx:90 +#: src/components/NotificationsList/NotificationListItem.jsx:105 +msgid "Toggle notification failure" +msgstr "" + +#: src/components/NotificationsList/NotificationListItem.jsx:78 +msgid "Toggle notification success" +msgstr "" + #: src/components/TowerLogo/TowerLogo.jsx:48 msgid "Tower Brand Image" msgstr "" -#: src/components/PageHeaderToolbar.jsx:108 +#: src/components/AnsibleSelect/AnsibleSelect.jsx:35 +msgid "Use Default {label}" +msgstr "" + +#: src/pages/Organizations/components/DeleteRoleConfirmationModal.jsx:28 +msgid "User" +msgstr "" + +#: src/components/PageHeaderToolbar.jsx:113 msgid "User Details" msgstr "" -#: src/index.jsx:246 +#: src/index.jsx:211 msgid "User Interface" msgstr "" -#: src/pages/UISettings.jsx:17 +#: src/pages/UISettings.jsx:19 msgid "User Interface Settings" msgstr "" -#: src/pages/Login.jsx:78 +#: src/pages/Organizations/components/OrganizationAccessItem.jsx:122 +msgid "User Roles" +msgstr "" + +#: src/components/AddRole/AddResourceRole.jsx:136 +#: src/pages/Login.jsx:81 +#: src/pages/Organizations/screens/Organization/OrganizationAccess.jsx:172 msgid "Username" msgstr "" -#: src/index.jsx:184 -#: src/pages/Organizations/components/OrganizationListItem.jsx:49 -#: src/pages/Users.jsx:17 +#: src/components/AddRole/AddResourceRole.jsx:164 +#: src/index.jsx:149 +#: src/pages/Users.jsx:19 msgid "Users" msgstr "" -#: src/index.jsx:118 +#: src/index.jsx:83 msgid "Views" msgstr "" -#: src/pages/Login.jsx:74 +#: src/pages/Login.jsx:76 msgid "Welcome to Ansible Tower! Please Sign In." msgstr "" -#: src/pages/Organizations/components/OrganizationDetail.jsx:56 -msgid "add {currentTab}" +#: src/components/PaginatedDataList/ToolbarDeleteButton.jsx:104 +msgid "You do not have permission to delete the following {0}: {itemsUnableToDelete}" msgstr "" +#: src/contexts/Network.jsx:44 +msgid "You have been logged out." +msgstr "" + +#: src/pages/Organizations/components/OrganizationDetail.jsx:56 +#~ msgid "add {currentTab}" +#~ msgstr "" + #: src/pages/Organizations/components/OrganizationDetail.jsx:45 -msgid "adding {currentTab}" +#~ msgid "adding {currentTab}" +#~ msgstr "" + +#: src/components/PaginatedDataList/ToolbarDeleteButton.jsx:158 +msgid "cancel delete" +msgstr "" + +#: src/components/PaginatedDataList/ToolbarDeleteButton.jsx:150 +msgid "confirm delete" msgstr "" #: src/pages/Organizations/components/OrganizationDetail.jsx:38 -msgid "confirm removal of {currentTab}/cancel and go back to {currentTab} view." -msgstr "" +#~ msgid "confirm removal of {currentTab}/cancel and go back to {currentTab} view." +#~ msgstr "" #: src/pages/Organizations/components/OrganizationDetail.jsx:60 -msgid "delete {currentTab}" -msgstr "" +#~ msgid "delete {currentTab}" +#~ msgstr "" #: src/pages/Organizations/components/OrganizationDetail.jsx:36 -msgid "deleting {currentTab} association with orgs" -msgstr "" +#~ msgid "deleting {currentTab} association with orgs" +#~ msgstr "" #: src/pages/Organizations/components/OrganizationEdit.jsx:20 -msgid "edit view" +#~ msgid "edit view" +#~ msgstr "" + +#: src/components/Lookup/Lookup.jsx:135 +msgid "items" +msgstr "" + +#: src/components/Pagination/Pagination.jsx:198 +msgid "of {pageCount}" msgstr "" #: src/pages/Organizations/components/OrganizationEdit.jsx:22 -msgid "save/cancel and go back to view" -msgstr "" +#~ msgid "save/cancel and go back to view" +#~ msgstr "" #: src/pages/Organizations/components/OrganizationDetail.jsx:47 -msgid "save/cancel and go back to {currentTab} view" -msgstr "" +#~ msgid "save/cancel and go back to {currentTab} view" +#~ msgstr "" #: src/pages/Organizations/components/OrganizationListItem.jsx:29 -msgid "select organization {itemId}" -msgstr "" +#~ msgid "select organization {itemId}" +#~ msgstr "" #: src/pages/Organizations/components/OrganizationDetail.jsx:82 -msgid "{0}" +#~ msgid "{0}" +#~ msgstr "" + +#: src/components/PaginatedDataList/PaginatedDataList.jsx:153 +#: src/components/PaginatedDataList/PaginatedDataList.jsx:215 +msgid "{0} List" msgstr "" #: src/pages/Organizations/components/OrganizationDetail.jsx:54 -msgid "{currentTab} detail view" -msgstr "" +#~ msgid "{currentTab} detail view" +#~ msgstr "" #: src/components/Pagination/Pagination.jsx:163 -msgid "{itemMin} - {itemMax} of {count}" -msgstr "" +#~ msgid "{itemMin} - {itemMax} of {count}" +#~ msgstr "" diff --git a/src/App.jsx b/src/App.jsx index 436a841621..d47c545e3a 100644 --- a/src/App.jsx +++ b/src/App.jsx @@ -9,7 +9,7 @@ import { Button } from '@patternfly/react-core'; -import { I18n } from '@lingui/react'; +import { withI18n } from '@lingui/react'; import { t } from '@lingui/macro'; import { RootDialog } from './contexts/RootDialog'; @@ -66,92 +66,88 @@ class App extends Component { render () { const { isAboutModalOpen, isNavOpen } = this.state; - const { render, routeGroups = [], navLabel = '' } = this.props; + const { render, routeGroups = [], navLabel = '', i18n } = this.props; return ( {({ ansible_version, version, me }) => ( - - {({ i18n }) => ( - - {({ - title, - bodyText, - variant = 'info', - clearRootDialogMessage - }) => ( - - {(title || bodyText) && ( - - {i18n._(t`Close`)} - - ]} + + {({ + title, + bodyText, + variant = 'info', + clearRootDialogMessage + }) => ( + + {(title || bodyText) && ( + - {bodyText} - - )} - } - toolbar={( - - )} - /> - )} - sidebar={( - - - {routeGroups.map( - ({ groupId, groupTitle, routes }) => ( - - ) - )} - - - )} - /> - )} - > - {render && render({ routeGroups })} - - - + {i18n._(t`Close`)} + + ]} + > + {bodyText} + )} - + } + toolbar={( + + )} + /> + )} + sidebar={( + + + {routeGroups.map( + ({ groupId, groupTitle, routes }) => ( + + ) + )} + + + )} + /> + )} + > + {render && render({ routeGroups })} + + + )} - + )} ); @@ -159,4 +155,4 @@ class App extends Component { } export { App as _App }; -export default withNetwork(App); +export default withI18n()(withNetwork(App)); diff --git a/src/components/About.jsx b/src/components/About.jsx index 9d8b8abb7c..aceb91074e 100644 --- a/src/components/About.jsx +++ b/src/components/About.jsx @@ -1,7 +1,7 @@ import React from 'react'; import PropTypes from 'prop-types'; -import { I18n } from '@lingui/react'; -import { Trans, t } from '@lingui/macro'; +import { withI18n } from '@lingui/react'; +import { t } from '@lingui/macro'; import { AboutModal, TextContent, @@ -41,46 +41,43 @@ class About extends React.Component { ansible_version, version, isOpen, - onClose + onClose, + i18n } = this.props; const speechBubble = this.createSpeechBubble(version); return ( - - {({ i18n }) => ( - -
    -              { speechBubble }
    -              {`
    -              \\
    -              \\   ^__^
    -                  (oo)\\_______
    -                  (__)      A )\\
    -                      ||----w |
    -                      ||     ||
    -                        `}
    -            
    - - - - Ansible Version - - { ansible_version } - - -
    - )} -
    + +
    +          { speechBubble }
    +          {`
    +          \\
    +          \\   ^__^
    +              (oo)\\_______
    +              (__)      A )\\
    +                  ||----w |
    +                  ||     ||
    +                    `}
    +        
    + + + + {i18n._(t`Ansible Version`)} + + { ansible_version } + + +
    ); } } @@ -98,4 +95,4 @@ About.defaultProps = { version: null, }; -export default About; +export default withI18n()(About); diff --git a/src/components/AddRole/AddResourceRole.jsx b/src/components/AddRole/AddResourceRole.jsx index e01aaff669..13039bde15 100644 --- a/src/components/AddRole/AddResourceRole.jsx +++ b/src/components/AddRole/AddResourceRole.jsx @@ -1,8 +1,9 @@ import React, { Fragment } from 'react'; import PropTypes from 'prop-types'; -import { I18n, i18nMark } from '@lingui/react'; +import { withI18n } from '@lingui/react'; import { t } from '@lingui/macro'; import { Wizard } from '@patternfly/react-core'; +import { withNetwork } from '../../contexts/Network'; import SelectResourceStep from './SelectResourceStep'; import SelectRoleStep from './SelectRoleStep'; import SelectableCard from './SelectableCard'; @@ -127,113 +128,103 @@ class AddResourceRole extends React.Component { } = this.state; const { onClose, - roles + roles, + i18n } = this.props; const userColumns = [ - { name: i18nMark('Username'), key: 'username', isSortable: true } + { name: i18n._(t`Username`), key: 'username', isSortable: true } ]; const teamColumns = [ - { name: i18nMark('Name'), key: 'name', isSortable: true } + { name: i18n._(t`Name`), key: 'name', isSortable: true } ]; let wizardTitle = ''; switch (selectedResource) { case 'users': - wizardTitle = i18nMark('Add User Roles'); + wizardTitle = i18n._(t`Add User Roles`); break; case 'teams': - wizardTitle = i18nMark('Add Team Roles'); + wizardTitle = i18n._(t`Add Team Roles`); break; default: - wizardTitle = i18nMark('Add Roles'); + wizardTitle = i18n._(t`Add Roles`); } const steps = [ { id: 1, - name: i18nMark('Select Users Or Teams'), + name: i18n._(t`Select Users Or Teams`), component: ( - - {({ i18n }) => ( -
    - this.handleResourceSelect('users')} - /> - this.handleResourceSelect('teams')} - /> -
    - )} -
    +
    + this.handleResourceSelect('users')} + /> + this.handleResourceSelect('teams')} + /> +
    ), enableNext: selectedResource !== null }, { id: 2, - name: i18nMark('Select items from list'), + name: i18n._(t`Select items from list`), component: ( - - {({ i18n }) => ( - - {selectedResource === 'users' && ( - - )} - {selectedResource === 'teams' && ( - - )} - + + {selectedResource === 'users' && ( + )} - + {selectedResource === 'teams' && ( + + )} + ), enableNext: selectedResourceRows.length > 0 }, { id: 3, - name: i18nMark('Apply roles'), + name: i18n._(t`Apply roles`), component: ( - - {({ i18n }) => ( - - )} - + ), - nextButtonText: i18nMark('Save'), + nextButtonText: i18n._(t`Save`), enableNext: selectedRoleRows.length > 0 } ]; const currentStep = steps.find(step => step.id === currentStepId); + // TODO: somehow internationalize steps and currentStep.nextButtonText return ( - {isLoading && (
    Loading...
    )} + {isLoading && (
    {i18n._(t`Loading...`)}
    )} {isInitialized && ( {selectedResourceRows.length > 0 && ( @@ -146,11 +148,11 @@ SelectResourceStep.propTypes = { SelectResourceStep.defaultProps = { displayKey: 'name', onRowClick: () => {}, - selectedLabel: i18nMark('Selected Items'), + selectedLabel: null, selectedResourceRows: [], sortedColumnKey: 'name', itemName: 'item', }; export { SelectResourceStep as _SelectResourceStep }; -export default withRouter(SelectResourceStep); +export default withI18n()(withRouter(SelectResourceStep)); diff --git a/src/components/AddRole/SelectRoleStep.jsx b/src/components/AddRole/SelectRoleStep.jsx index e0d052d76a..98caad4728 100644 --- a/src/components/AddRole/SelectRoleStep.jsx +++ b/src/components/AddRole/SelectRoleStep.jsx @@ -1,7 +1,8 @@ import React, { Fragment } from 'react'; import PropTypes from 'prop-types'; -import { i18nMark } from '@lingui/react'; +import { withI18n } from '@lingui/react'; +import { t } from '@lingui/macro'; import CheckboxCard from './CheckboxCard'; import SelectedList from '../SelectedList'; @@ -14,7 +15,8 @@ class RolesStep extends React.Component { selectedListKey, selectedListLabel, selectedResourceRows, - selectedRoleRows + selectedRoleRows, + i18n } = this.props; return ( @@ -24,7 +26,7 @@ class RolesStep extends React.Component { @@ -61,9 +63,9 @@ RolesStep.propTypes = { RolesStep.defaultProps = { onRolesClick: () => {}, selectedListKey: 'name', - selectedListLabel: i18nMark('Selected'), + selectedListLabel: null, selectedResourceRows: [], selectedRoleRows: [] }; -export default RolesStep; +export default withI18n()(RolesStep); diff --git a/src/components/AnsibleSelect/AnsibleSelect.jsx b/src/components/AnsibleSelect/AnsibleSelect.jsx index c4de1c51e7..fe6e352811 100644 --- a/src/components/AnsibleSelect/AnsibleSelect.jsx +++ b/src/components/AnsibleSelect/AnsibleSelect.jsx @@ -1,6 +1,6 @@ import React from 'react'; import PropTypes from 'prop-types'; -import { I18n } from '@lingui/react'; +import { withI18n } from '@lingui/react'; import { t } from '@lingui/macro'; import { FormSelect, @@ -20,29 +20,25 @@ class AnsibleSelect extends React.Component { } render () { - const { label, value, data, defaultSelected } = this.props; + const { label, value, data, defaultSelected, i18n } = this.props; return ( - - {({ i18n }) => ( - - {data.map((datum) => ( - datum === defaultSelected ? ( - - ) : ( - - ) - ))} - - )} - + + {data.map((datum) => ( + datum === defaultSelected ? ( + + ) : ( + + ) + ))} + ); } } @@ -62,4 +58,5 @@ AnsibleSelect.propTypes = { value: PropTypes.string.isRequired, }; -export default AnsibleSelect; +export { AnsibleSelect as _AnsibleSelect }; +export default withI18n()(AnsibleSelect); diff --git a/src/components/CardCloseButton.jsx b/src/components/CardCloseButton.jsx index 9b8dffe41c..c26cb76b84 100644 --- a/src/components/CardCloseButton.jsx +++ b/src/components/CardCloseButton.jsx @@ -3,40 +3,32 @@ import { string } from 'prop-types'; import { Link } from 'react-router-dom'; import { Button } from '@patternfly/react-core'; import { TimesIcon } from '@patternfly/react-icons'; -import { I18n } from '@lingui/react'; +import { withI18n } from '@lingui/react'; import { t } from '@lingui/macro'; -function CardCloseButton ({ linkTo, ...props }) { +function CardCloseButton ({ linkTo, i18n, i18nHash, ...props }) { if (linkTo) { return ( - - {({ i18n }) => ( - - - - )} - + + + ); } return ( - - {({ i18n }) => ( - - )} - + ); } CardCloseButton.propTypes = { @@ -46,4 +38,4 @@ CardCloseButton.defaultProps = { linkTo: null, }; -export default CardCloseButton; +export default withI18n()(CardCloseButton); diff --git a/src/components/DataListToolbar/DataListToolbar.jsx b/src/components/DataListToolbar/DataListToolbar.jsx index e73745ff44..599362d0ef 100644 --- a/src/components/DataListToolbar/DataListToolbar.jsx +++ b/src/components/DataListToolbar/DataListToolbar.jsx @@ -1,6 +1,6 @@ import React, { Fragment } from 'react'; import PropTypes from 'prop-types'; -import { I18n } from '@lingui/react'; +import { withI18n } from '@lingui/react'; import { t } from '@lingui/macro'; import { Checkbox, @@ -85,70 +85,66 @@ class DataListToolbar extends React.Component { sortOrder, sortedColumnKey, additionalControls, + i18n } = this.props; const showExpandCollapse = (onCompact && onExpand); return ( - - {({ i18n }) => ( - - - - { showSelectAll && ( - - - - - - - )} - - + + + { showSelectAll && ( + + + - - - - + )} + + + + + + + + + + {showExpandCollapse && ( + + + + - - {showExpandCollapse && ( - - - - - - { additionalControls && ( - - )} - + + { additionalControls && ( + )} - - {additionalControls} - - - - - - )} - + + )} + + {additionalControls} + + + + ); } } @@ -184,4 +180,4 @@ DataListToolbar.defaultProps = { additionalControls: [], }; -export default DataListToolbar; +export default withI18n()(DataListToolbar); diff --git a/src/components/ExpandCollapse/ExpandCollapse.jsx b/src/components/ExpandCollapse/ExpandCollapse.jsx index dfd0402c3c..cabc7f2f3b 100644 --- a/src/components/ExpandCollapse/ExpandCollapse.jsx +++ b/src/components/ExpandCollapse/ExpandCollapse.jsx @@ -1,6 +1,6 @@ import React, { Fragment } from 'react'; import PropTypes from 'prop-types'; -import { I18n } from '@lingui/react'; +import { withI18n } from '@lingui/react'; import { t } from '@lingui/macro'; import { Button, @@ -22,36 +22,33 @@ class ExpandCollapse extends React.Component { const { onCompact, onExpand, - isCompact + isCompact, + i18n } = this.props; return ( - - {({ i18n }) => ( - - - - - - - - - )} - + + + + + + + + ); } } @@ -64,4 +61,4 @@ ExpandCollapse.propTypes = { ExpandCollapse.defaultProps = {}; -export default ExpandCollapse; +export default withI18n()(ExpandCollapse); diff --git a/src/components/FormActionGroup/FormActionGroup.jsx b/src/components/FormActionGroup/FormActionGroup.jsx index 99db0621a4..ee92ac0169 100644 --- a/src/components/FormActionGroup/FormActionGroup.jsx +++ b/src/components/FormActionGroup/FormActionGroup.jsx @@ -1,6 +1,6 @@ import React from 'react'; import PropTypes from 'prop-types'; -import { I18n } from '@lingui/react'; +import { withI18n } from '@lingui/react'; import { t } from '@lingui/macro'; import { ActionGroup, @@ -20,21 +20,17 @@ const buttonGroupStyle = { marginRight: '20px' }; -const FormActionGroup = ({ onSubmit, submitDisabled, onCancel }) => ( - - {({ i18n }) => ( - - - - - - - - - - - )} - +const FormActionGroup = ({ onSubmit, submitDisabled, onCancel, i18n }) => ( + + + + + + + + + + ); FormActionGroup.propTypes = { @@ -47,4 +43,4 @@ FormActionGroup.defaultProps = { submitDisabled: false, }; -export default FormActionGroup; +export default withI18n()(FormActionGroup); diff --git a/src/components/Lookup/Lookup.jsx b/src/components/Lookup/Lookup.jsx index e007ed2af5..4b147e552b 100644 --- a/src/components/Lookup/Lookup.jsx +++ b/src/components/Lookup/Lookup.jsx @@ -9,7 +9,7 @@ import { InputGroup, Modal, } from '@patternfly/react-core'; -import { I18n } from '@lingui/react'; +import { withI18n } from '@lingui/react'; import { t } from '@lingui/macro'; import { withNetwork } from '../../contexts/Network'; @@ -130,7 +130,9 @@ class Lookup extends React.Component { results, count, } = this.state; - const { id, lookupHeader = 'items', value, columns } = this.props; + const { id, lookupHeader, value, columns, i18n } = this.props; + + const header = lookupHeader || i18n._(t`items`); const chips = value ? (
    @@ -143,64 +145,60 @@ class Lookup extends React.Component { ) : null; return ( - - {({ i18n }) => ( - - - -
    - {chips} -
    -
    - {i18n._(t`Save`)}, - - ]} - > - ( - i.id === item.id)} - onSelect={() => this.toggleSelected(item)} - /> - )} - alignToolbarLeft - showPageSizeOptions={false} - paginationStyling={paginationStyling} + + + +
    + {chips} +
    +
    + {i18n._(t`Save`)}, + + ]} + > + ( + i.id === item.id)} + onSelect={() => this.toggleSelected(item)} /> - {lookupSelectedItems.length > 0 && ( - - )} - { error ?
    error
    : '' } -
    -
    - )} -
    + )} + alignToolbarLeft + showPageSizeOptions={false} + paginationStyling={paginationStyling} + /> + {lookupSelectedItems.length > 0 && ( + + )} + { error ?
    error
    : '' } + + ); } } @@ -217,9 +215,9 @@ Lookup.propTypes = { Lookup.defaultProps = { id: 'lookup-search', - lookupHeader: 'items', + lookupHeader: null, name: null, }; export { Lookup as _Lookup }; -export default withNetwork(withRouter(Lookup)); +export default withI18n()(withNetwork(withRouter(Lookup))); diff --git a/src/components/NotificationsList/NotificationListItem.jsx b/src/components/NotificationsList/NotificationListItem.jsx index 5493982145..1d3122ce1a 100644 --- a/src/components/NotificationsList/NotificationListItem.jsx +++ b/src/components/NotificationsList/NotificationListItem.jsx @@ -1,6 +1,6 @@ import React from 'react'; import { shape, number, string, bool, func } from 'prop-types'; -import { I18n } from '@lingui/react'; +import { withI18n } from '@lingui/react'; import { t } from '@lingui/macro'; import { Link } from 'react-router-dom'; import { @@ -37,66 +37,63 @@ function NotificationListItem (props) { detailUrl, successTurnedOn, errorTurnedOn, - toggleNotification + toggleNotification, + i18n } = props; return ( - - {({ i18n }) => ( - - - - - {notification.name} - - - {notification.notification_type} - - , - - toggleNotification( - notification.id, - successTurnedOn, - 'success' - )} - aria-label={i18n._(t`Toggle notification success`)} - /> - toggleNotification( - notification.id, - errorTurnedOn, - 'error' - )} - aria-label={i18n._(t`Toggle notification failure`)} - /> - - ]} + + + + + {notification.name} + + + {notification.notification_type} + + , + + toggleNotification( + notification.id, + successTurnedOn, + 'success' + )} + aria-label={i18n._(t`Toggle notification success`)} /> - - - )} - + toggleNotification( + notification.id, + errorTurnedOn, + 'error' + )} + aria-label={i18n._(t`Toggle notification failure`)} + /> + + ]} + /> + + ); } @@ -118,4 +115,4 @@ NotificationListItem.defaultProps = { successTurnedOn: false, }; -export default NotificationListItem; +export default withI18n()(NotificationListItem); diff --git a/src/components/NotifyAndRedirect.jsx b/src/components/NotifyAndRedirect.jsx index 0bb030440a..19a18ea62c 100644 --- a/src/components/NotifyAndRedirect.jsx +++ b/src/components/NotifyAndRedirect.jsx @@ -1,8 +1,8 @@ -import React from 'react'; +import React, { Fragment } from 'react'; import { Redirect, withRouter } from 'react-router-dom'; - -import { Trans } from '@lingui/macro'; +import { withI18n } from '@lingui/react'; +import { t } from '@lingui/macro'; import { withRootDialog } from '../contexts/RootDialog'; @@ -14,16 +14,13 @@ const NotifyAndRedirect = ({ strict, sensitive, setRootDialogMessage, - location + location, + i18n }) => { setRootDialogMessage({ title: '404', bodyText: ( - - Cannot find route - {` ${location.pathname}`} - . - + {i18n._(t`Cannot find route ${({location.pathname})}.`)} ), variant: 'warning' }); @@ -41,4 +38,4 @@ const NotifyAndRedirect = ({ }; export { NotifyAndRedirect as _NotifyAndRedirect }; -export default withRootDialog(withRouter(NotifyAndRedirect)); +export default withI18n()(withRootDialog(withRouter(NotifyAndRedirect))); diff --git a/src/components/PageHeaderToolbar.jsx b/src/components/PageHeaderToolbar.jsx index b6cdebf3d2..f0f948b91f 100644 --- a/src/components/PageHeaderToolbar.jsx +++ b/src/components/PageHeaderToolbar.jsx @@ -1,8 +1,7 @@ import React, { Component } from 'react'; import PropTypes from 'prop-types'; - +import { withI18n } from '@lingui/react'; import { t } from '@lingui/macro'; -import { I18n } from '@lingui/react'; import { Dropdown, DropdownItem, @@ -57,78 +56,75 @@ class PageHeaderToolbar extends Component { isAboutDisabled, onAboutClick, onLogoutClick, - loggedInUser + loggedInUser, + i18n } = this.props; return ( - - {({ i18n }) => ( - - - {i18n._(t`Info`)}
    }> - - - - + + + {i18n._(t`Info`)}}> + + + + + )} + dropdownItems={[ + + {i18n._(t`Help`)} + , + + {i18n._(t`About`)} + + ]} + /> + + + User}> + + + + {loggedInUser && ( + + {loggedInUser.username} + )} - dropdownItems={[ - - {i18n._(t`Help`)} - , - - {i18n._(t`About`)} - - ]} - /> - - - User}> - - - - {loggedInUser && ( - - {loggedInUser.username} - - )} - - )} - dropdownItems={[ - - {i18n._(t`User Details`)} - , - - {i18n._(t`Logout`)} - - ]} - /> - - - - - )} - + + )} + dropdownItems={[ + + {i18n._(t`User Details`)} + , + + {i18n._(t`Logout`)} + + ]} + /> + + + + ); } } @@ -143,4 +139,4 @@ PageHeaderToolbar.defaultProps = { isAboutDisabled: false }; -export default PageHeaderToolbar; +export default withI18n()(PageHeaderToolbar); diff --git a/src/components/PaginatedDataList/PaginatedDataList.jsx b/src/components/PaginatedDataList/PaginatedDataList.jsx index f4d1b8c067..267b0caad8 100644 --- a/src/components/PaginatedDataList/PaginatedDataList.jsx +++ b/src/components/PaginatedDataList/PaginatedDataList.jsx @@ -14,8 +14,8 @@ import { EmptyStateBody, } from '@patternfly/react-core'; import { CubesIcon } from '@patternfly/react-icons'; -import { I18n, i18nMark } from '@lingui/react'; -import { Trans, t } from '@lingui/macro'; +import { withI18n } from '@lingui/react'; +import { t } from '@lingui/macro'; import { withRouter, Link } from 'react-router-dom'; import Pagination from '../Pagination'; @@ -108,13 +108,15 @@ class PaginatedDataList extends React.Component { showPageSizeOptions, paginationStyling, location, + i18n } = this.props; const { error } = this.state; const [orderBy, sortOrder] = this.getSortOrder(); const queryParams = parseNamespacedQueryString(qsConfig, location.search); + const columns = toolbarColumns.length ? toolbarColumns : [{ name: i18n._(t`Name`), key: 'name', isSortable: true }]; return ( - - {({ i18n }) => ( + + {error && ( {error && ( @@ -128,24 +130,10 @@ class PaginatedDataList extends React.Component { - <Trans> - No - {' '} - {ucFirst(itemNamePlural || pluralize(itemName))} - {' '} - Found - </Trans> + {i18n._(t`No ${ucFirst(itemNamePlural || pluralize(itemName))} Found`)} - - Please add - {' '} - {getArticle(itemName)} - {' '} - {itemName} - {' '} - to populate this list - + {i18n._(t`Please add ${getArticle(itemName)} ${itemName} to populate this list`)} ) : ( @@ -153,7 +141,7 @@ class PaginatedDataList extends React.Component { { }} onSort={this.handleSort} showSelectAll={showSelectAll} @@ -199,9 +187,67 @@ class PaginatedDataList extends React.Component { /> )} + // TODO: replace with proper error handling + )} + {items.length === 0 ? ( + + + + {i18n._(t`No ${ucFirst(itemNamePlural || pluralize(itemName))} Found`)} + + + {i18n._(t`Please add ${getArticle(itemName)} ${itemName} to populate this list`)} + + + ) : ( + + { }} + onSort={this.handleSort} + showSelectAll={showSelectAll} + isAllSelected={isAllSelected} + onSelectAll={onSelectAll} + additionalControls={additionalControls} + /> + + {items.map(item => (renderItem ? renderItem(item) : ( + + + + + + + {item.name} + + + + + ]} + /> + + + )))} + + )} - + ); } } @@ -235,9 +281,7 @@ PaginatedDataList.propTypes = { PaginatedDataList.defaultProps = { renderItem: null, - toolbarColumns: [ - { name: i18nMark('Name'), key: 'name', isSortable: true }, - ], + toolbarColumns: [], additionalControls: [], itemName: 'item', itemNamePlural: '', @@ -250,4 +294,4 @@ PaginatedDataList.defaultProps = { }; export { PaginatedDataList as _PaginatedDataList }; -export default withRouter(PaginatedDataList); +export default withI18n()(withRouter(PaginatedDataList)); diff --git a/src/components/PaginatedDataList/ToolbarAddButton.jsx b/src/components/PaginatedDataList/ToolbarAddButton.jsx index ae6b7e0c74..ea2f2f183f 100644 --- a/src/components/PaginatedDataList/ToolbarAddButton.jsx +++ b/src/components/PaginatedDataList/ToolbarAddButton.jsx @@ -3,7 +3,7 @@ import { string, func } from 'prop-types'; import { Link } from 'react-router-dom'; import { Button as PFButton } from '@patternfly/react-core'; import { PlusIcon } from '@patternfly/react-icons'; -import { I18n } from '@lingui/react'; +import { withI18n } from '@lingui/react'; import { t } from '@lingui/macro'; import styled from 'styled-components'; @@ -20,39 +20,32 @@ const Button = styled(PFButton)` } `; -function ToolbarAddButton ({ linkTo, onClick }) { +function ToolbarAddButton ({ linkTo, onClick, i18n }) { if (!linkTo && !onClick) { throw new Error('ToolbarAddButton requires either `linkTo` or `onClick` prop'); } if (linkTo) { // TODO: This should only be a (no - - )} - - ); - } - return ( - - {({ i18n }) => ( + - )} - + + ); + } + + return ( + ); } ToolbarAddButton.propTypes = { @@ -64,4 +57,4 @@ ToolbarAddButton.defaultProps = { onClick: null }; -export default ToolbarAddButton; +export default withI18n()(ToolbarAddButton); diff --git a/src/components/PaginatedDataList/ToolbarDeleteButton.jsx b/src/components/PaginatedDataList/ToolbarDeleteButton.jsx index d9ff520ee2..1b54e4539d 100644 --- a/src/components/PaginatedDataList/ToolbarDeleteButton.jsx +++ b/src/components/PaginatedDataList/ToolbarDeleteButton.jsx @@ -2,9 +2,9 @@ import React, { Fragment } from 'react'; import { func, bool, number, string, arrayOf, shape } from 'prop-types'; import { Button as PFButton, Tooltip } from '@patternfly/react-core'; import { TrashAltIcon } from '@patternfly/react-icons'; -import { I18n, i18nMark } from '@lingui/react'; -import { Trans, t } from '@lingui/macro'; import styled from 'styled-components'; +import { withI18n } from '@lingui/react'; +import { t } from '@lingui/macro'; import AlertModal from '../AlertModal'; import { pluralize } from '../../util/strings'; @@ -89,103 +89,95 @@ class ToolbarDeleteButton extends React.Component { } renderTooltip () { - const { itemsToDelete, itemName } = this.props; + const { itemsToDelete, itemName, i18n } = this.props; + + const itemsUnableToDelete = itemsToDelete + .filter(cannotDelete) + .map(item => ( +
    + {item.name} +
    + )); if (itemsToDelete.some(cannotDelete)) { return (
    - - You dont have permission to delete the following - {' '} - {pluralize(itemName)} - : - - {itemsToDelete - .filter(cannotDelete) - .map(item => ( -
    - {item.name} -
    - )) - } + {i18n._(t`You do not have permission to delete the following ${pluralize(itemName)}: ${itemsUnableToDelete}`)}
    ); } if (itemsToDelete.length) { - return i18nMark('Delete'); + return i18n._(t`Delete`); } - return i18nMark('Select a row to delete'); + return i18n._(t`Select a row to delete`); } render () { - const { itemsToDelete, itemName } = this.props; + const { itemsToDelete, itemName, i18n } = this.props; const { isModalOpen } = this.state; const isDisabled = itemsToDelete.length === 0 || itemsToDelete.some(cannotDelete); return ( - - {({ i18n }) => ( - - + + + + + { isModalOpen && ( + - - - - { isModalOpen && ( - - {i18n._(t`Delete`)} - , - - ]} + aria-label={i18n._(t`confirm delete`)} + onClick={this.handleDelete} > - {i18n._(t`Are you sure you want to delete:`)} + {i18n._(t`Delete`)} + , + + ]} + > + {i18n._(t`Are you sure you want to delete:`)} +
    + {itemsToDelete.map((item) => ( + + + {item.name} +
    - {itemsToDelete.map((item) => ( - - - {item.name} - -
    -
    - ))} -
    -
    - )} -
    + + ))} +
    + )} -
    + ); } } -export default ToolbarDeleteButton; +export default withI18n()(ToolbarDeleteButton); diff --git a/src/components/Pagination/Pagination.jsx b/src/components/Pagination/Pagination.jsx index 8c6762705b..9058648177 100644 --- a/src/components/Pagination/Pagination.jsx +++ b/src/components/Pagination/Pagination.jsx @@ -1,7 +1,7 @@ import React, { Component } from 'react'; import PropTypes from 'prop-types'; -import { I18n } from '@lingui/react'; -import { Trans, t } from '@lingui/macro'; +import { withI18n } from '@lingui/react'; +import { t } from '@lingui/macro'; import { Button, Dropdown, @@ -106,7 +106,8 @@ class Pagination extends Component { page_size, pageSizeOptions, showPageSizeOptions, - style + style, + i18n } = this.props; const { value, isOpen } = this.state; let opts = []; @@ -135,98 +136,91 @@ class Pagination extends Component { )); return ( - - {({ i18n }) => ( -
    - {showPageSizeOptions && ( -
    - Items Per Page - + {showPageSizeOptions && ( +
    + {i18n._(t`Items Per Page`)} + - {page_size} - - )} - dropdownItems={dropdownItems} - /> -
    - )} -
    -
    - {`Items ${itemMin} – ${itemMax} of ${count}`} -
    - {pageCount !== 1 && ( -
    -
    - - -
    -
    - - {'Page '} - - {' of '} - {pageCount} - -
    -
    - - -
    -
    + > + {page_size} + )} -
    + dropdownItems={dropdownItems} + />
    )} - +
    +
    + {i18n._(t`Items ${itemMin} – ${itemMax} of ${count}`)} +
    + {pageCount !== 1 && ( +
    +
    + + +
    +
    + {i18n._(t`Page `)} + + {i18n._(t` of ${pageCount}`)} + +
    + + +
    +
    + )} +
    +
    ); } } @@ -248,4 +242,4 @@ Pagination.defaultProps = { showPageSizeOptions: true }; -export default Pagination; +export default withI18n()(Pagination); diff --git a/src/components/Search/Search.jsx b/src/components/Search/Search.jsx index c43c156785..3ffb4aab8a 100644 --- a/src/components/Search/Search.jsx +++ b/src/components/Search/Search.jsx @@ -1,6 +1,6 @@ import React from 'react'; import PropTypes from 'prop-types'; -import { I18n } from '@lingui/react'; +import { withI18n } from '@lingui/react'; import { t } from '@lingui/macro'; import { Button as PFButton, @@ -90,7 +90,8 @@ class Search extends React.Component { render () { const { up } = DropdownPosition; const { - columns + columns, + i18n } = this.props; const { isSearchDropdownOpen, @@ -109,41 +110,37 @@ class Search extends React.Component { )); return ( - - {({ i18n }) => ( -
    - + - {searchColumnName} - - )} - dropdownItems={searchDropdownItems} - /> - - -
    - )} -
    + {searchColumnName} + + )} + dropdownItems={searchDropdownItems} + /> + + + ); } } @@ -159,4 +156,4 @@ Search.defaultProps = { sortedColumnKey: 'name' }; -export default Search; +export default withI18n()(Search); diff --git a/src/components/Sort/Sort.jsx b/src/components/Sort/Sort.jsx index 966f1b8d2a..2e8b06d2de 100644 --- a/src/components/Sort/Sort.jsx +++ b/src/components/Sort/Sort.jsx @@ -1,6 +1,6 @@ import React from 'react'; import PropTypes from 'prop-types'; -import { I18n } from '@lingui/react'; +import { withI18n } from '@lingui/react'; import { t } from '@lingui/macro'; import { Button, @@ -85,7 +85,8 @@ class Sort extends React.Component { const { columns, sortedColumnKey, - sortOrder + sortOrder, + i18n } = this.props; const { isSortDropdownOpen @@ -109,40 +110,36 @@ class Sort extends React.Component { } return ( - - {({ i18n }) => ( - - { sortDropdownItems.length > 1 && ( - + { sortDropdownItems.length > 1 && ( + - {sortedColumnName} - - )} - dropdownItems={sortDropdownItems} - /> + > + {sortedColumnName} + )} - - + dropdownItems={sortDropdownItems} + /> )} - + + ); } } @@ -160,4 +157,4 @@ Sort.defaultProps = { sortedColumnKey: 'name' }; -export default Sort; +export default withI18n()(Sort); diff --git a/src/components/TowerLogo/TowerLogo.jsx b/src/components/TowerLogo/TowerLogo.jsx index 74d278a69c..2b9d8ab808 100644 --- a/src/components/TowerLogo/TowerLogo.jsx +++ b/src/components/TowerLogo/TowerLogo.jsx @@ -1,7 +1,7 @@ import React, { Component } from 'react'; import PropTypes from 'prop-types'; import { withRouter } from 'react-router-dom'; -import { I18n } from '@lingui/react'; +import { withI18n } from '@lingui/react'; import { t } from '@lingui/macro'; import { Brand } from '@patternfly/react-core'; @@ -34,6 +34,7 @@ class TowerLogo extends Component { render () { const { hover } = this.state; + const { i18n } = this.props; let src = TowerLogoHeader; @@ -42,19 +43,15 @@ class TowerLogo extends Component { } return ( - - {({ i18n }) => ( - - )} - + ); } } @@ -67,4 +64,4 @@ TowerLogo.defaultProps = { linkTo: null, }; -export default withRouter(TowerLogo); +export default withI18n()(withRouter(TowerLogo)); diff --git a/src/contexts/Network.jsx b/src/contexts/Network.jsx index 5407346c45..0ee2106bf7 100644 --- a/src/contexts/Network.jsx +++ b/src/contexts/Network.jsx @@ -4,7 +4,8 @@ import React, { Component } from 'react'; import { withRouter } from 'react-router-dom'; -import { i18nMark } from '@lingui/react'; +import { withI18n } from '@lingui/react'; +import { t } from '@lingui/macro'; import { withRootDialog } from './RootDialog'; @@ -33,27 +34,27 @@ class Provider extends Component { } handle401 () { - const { handle401, history, setRootDialogMessage } = this.props; + const { handle401, history, setRootDialogMessage, i18n } = this.props; if (handle401) { handle401(); return; } history.replace('/login'); setRootDialogMessage({ - bodyText: i18nMark('You have been logged out.') + bodyText: i18n._(t`You have been logged out.`) }); } handle404 () { - const { handle404, history, setRootDialogMessage } = this.props; + const { handle404, history, setRootDialogMessage, i18n } = this.props; if (handle404) { handle404(); return; } history.replace('/home'); setRootDialogMessage({ - title: i18nMark('404'), - bodyText: i18nMark('Cannot find resource.'), + title: i18n._(t`404`), + bodyText: i18n._(t`Cannot find resource.`), variant: 'warning' }); } @@ -72,7 +73,7 @@ class Provider extends Component { } export { Provider as _NetworkProvider }; -export const NetworkProvider = withRootDialog(withRouter(Provider)); +export const NetworkProvider = withI18n()(withRootDialog(withRouter(Provider))); export function withNetwork (Child) { return (props) => ( diff --git a/src/pages/Applications.jsx b/src/pages/Applications.jsx index 4eeb1a9b85..8d6bf4eba5 100644 --- a/src/pages/Applications.jsx +++ b/src/pages/Applications.jsx @@ -1,5 +1,6 @@ import React, { Component, Fragment } from 'react'; -import { Trans } from '@lingui/macro'; +import { withI18n } from '@lingui/react'; +import { t } from '@lingui/macro'; import { PageSection, PageSectionVariants, @@ -8,13 +9,14 @@ import { class Applications extends Component { render () { + const { i18n } = this.props; const { light, medium } = PageSectionVariants; return ( - <Trans>Applications</Trans> + {i18n._(t`Applications`)} @@ -23,4 +25,4 @@ class Applications extends Component { } } -export default Applications; +export default withI18n()(Applications); diff --git a/src/pages/AuthSettings.jsx b/src/pages/AuthSettings.jsx index ad2f1e60e3..c2c45e1d17 100644 --- a/src/pages/AuthSettings.jsx +++ b/src/pages/AuthSettings.jsx @@ -1,5 +1,6 @@ import React, { Component, Fragment } from 'react'; -import { Trans } from '@lingui/macro'; +import { withI18n } from '@lingui/react'; +import { t } from '@lingui/macro'; import { PageSection, PageSectionVariants, @@ -8,13 +9,14 @@ import { class AuthSettings extends Component { render () { + const { i18n } = this.props; const { light, medium } = PageSectionVariants; return ( - <Trans>Authentication Settings</Trans> + {i18n._(t`Authentication Settings`)} @@ -23,4 +25,4 @@ class AuthSettings extends Component { } } -export default AuthSettings; +export default withI18n()(AuthSettings); diff --git a/src/pages/CredentialTypes.jsx b/src/pages/CredentialTypes.jsx index 3ea22eaa09..b711560509 100644 --- a/src/pages/CredentialTypes.jsx +++ b/src/pages/CredentialTypes.jsx @@ -1,5 +1,6 @@ import React, { Component, Fragment } from 'react'; -import { Trans } from '@lingui/macro'; +import { withI18n } from '@lingui/react'; +import { t } from '@lingui/macro'; import { PageSection, PageSectionVariants, @@ -8,13 +9,14 @@ import { class CredentialTypes extends Component { render () { + const { i18n } = this.props; const { light, medium } = PageSectionVariants; return ( - <Trans>Credential Types</Trans> + {i18n._(t`Credential Types`)} @@ -23,4 +25,4 @@ class CredentialTypes extends Component { } } -export default CredentialTypes; +export default withI18n()(CredentialTypes); diff --git a/src/pages/Credentials.jsx b/src/pages/Credentials.jsx index 5893d125b0..c3384a40b1 100644 --- a/src/pages/Credentials.jsx +++ b/src/pages/Credentials.jsx @@ -1,5 +1,6 @@ import React, { Component, Fragment } from 'react'; -import { Trans } from '@lingui/macro'; +import { withI18n } from '@lingui/react'; +import { t } from '@lingui/macro'; import { PageSection, PageSectionVariants, @@ -8,13 +9,14 @@ import { class Credentials extends Component { render () { + const { i18n } = this.props; const { light, medium } = PageSectionVariants; return ( - <Trans>Credentials</Trans> + {i18n._(t`Credentials`)} @@ -23,4 +25,4 @@ class Credentials extends Component { } } -export default Credentials; +export default withI18n()(Credentials); diff --git a/src/pages/Dashboard.jsx b/src/pages/Dashboard.jsx index 76d655dd80..1c0ae88339 100644 --- a/src/pages/Dashboard.jsx +++ b/src/pages/Dashboard.jsx @@ -1,5 +1,6 @@ import React, { Component, Fragment } from 'react'; -import { Trans } from '@lingui/macro'; +import { withI18n } from '@lingui/react'; +import { t } from '@lingui/macro'; import { PageSection, PageSectionVariants, @@ -8,13 +9,14 @@ import { class Dashboard extends Component { render () { + const { i18n } = this.props; const { light, medium } = PageSectionVariants; return ( - <Trans>Dashboard</Trans> + {i18n._(t`Dashboard`)} @@ -23,4 +25,4 @@ class Dashboard extends Component { } } -export default Dashboard; +export default withI18n()(Dashboard); diff --git a/src/pages/InstanceGroups.jsx b/src/pages/InstanceGroups.jsx index 12ed22d376..7e05873691 100644 --- a/src/pages/InstanceGroups.jsx +++ b/src/pages/InstanceGroups.jsx @@ -1,5 +1,6 @@ import React, { Component, Fragment } from 'react'; -import { Trans } from '@lingui/macro'; +import { withI18n } from '@lingui/react'; +import { t } from '@lingui/macro'; import { PageSection, PageSectionVariants, @@ -8,13 +9,14 @@ import { class InstanceGroups extends Component { render () { + const { i18n } = this.props; const { light, medium } = PageSectionVariants; return ( - <Trans>Instance Groups</Trans> + {i18n._(t`Instance Groups`)} @@ -23,4 +25,4 @@ class InstanceGroups extends Component { } } -export default InstanceGroups; +export default withI18n()(InstanceGroups); diff --git a/src/pages/Inventories.jsx b/src/pages/Inventories.jsx index 3f7f40d200..d0457dd00a 100644 --- a/src/pages/Inventories.jsx +++ b/src/pages/Inventories.jsx @@ -1,5 +1,6 @@ import React, { Component, Fragment } from 'react'; -import { Trans } from '@lingui/macro'; +import { withI18n } from '@lingui/react'; +import { t } from '@lingui/macro'; import { PageSection, PageSectionVariants, @@ -8,13 +9,14 @@ import { class Inventories extends Component { render () { + const { i18n } = this.props; const { light, medium } = PageSectionVariants; return ( - <Trans>Inventories</Trans> + {i18n._(t`Inventories`)} @@ -23,4 +25,4 @@ class Inventories extends Component { } } -export default Inventories; +export default withI18n()(Inventories); diff --git a/src/pages/InventoryScripts.jsx b/src/pages/InventoryScripts.jsx index ff23dd3fdf..aab83da691 100644 --- a/src/pages/InventoryScripts.jsx +++ b/src/pages/InventoryScripts.jsx @@ -1,5 +1,6 @@ import React, { Component, Fragment } from 'react'; -import { Trans } from '@lingui/macro'; +import { withI18n } from '@lingui/react'; +import { t } from '@lingui/macro'; import { PageSection, PageSectionVariants, @@ -8,13 +9,14 @@ import { class InventoryScripts extends Component { render () { + const { i18n } = this.props; const { light, medium } = PageSectionVariants; return ( - <Trans>Inventory Scripts</Trans> + {i18n._(t`Inventory Scripts`)} @@ -23,4 +25,4 @@ class InventoryScripts extends Component { } } -export default InventoryScripts; +export default withI18n()(InventoryScripts); diff --git a/src/pages/Jobs.jsx b/src/pages/Jobs.jsx index 1ff7f4436b..e78e62cfbd 100644 --- a/src/pages/Jobs.jsx +++ b/src/pages/Jobs.jsx @@ -1,5 +1,6 @@ import React, { Component, Fragment } from 'react'; -import { Trans } from '@lingui/macro'; +import { withI18n } from '@lingui/react'; +import { t } from '@lingui/macro'; import { PageSection, PageSectionVariants, @@ -8,13 +9,14 @@ import { class Jobs extends Component { render () { + const { i18n } = this.props; const { light, medium } = PageSectionVariants; return ( - <Trans>Jobs</Trans> + {i18n._(t`Jobs`)} @@ -23,4 +25,4 @@ class Jobs extends Component { } } -export default Jobs; +export default withI18n()(Jobs); diff --git a/src/pages/JobsSettings.jsx b/src/pages/JobsSettings.jsx index 3fbba9334c..5327f74d48 100644 --- a/src/pages/JobsSettings.jsx +++ b/src/pages/JobsSettings.jsx @@ -1,5 +1,6 @@ import React, { Component, Fragment } from 'react'; -import { Trans } from '@lingui/macro'; +import { withI18n } from '@lingui/react'; +import { t } from '@lingui/macro'; import { PageSection, PageSectionVariants, @@ -8,13 +9,14 @@ import { class JobsSettings extends Component { render () { + const { i18n } = this.props; const { light, medium } = PageSectionVariants; return ( - <Trans>Jobs Settings</Trans> + {i18n._(t`Jobs Settings`)} @@ -23,4 +25,4 @@ class JobsSettings extends Component { } } -export default JobsSettings; +export default withI18n()(JobsSettings); diff --git a/src/pages/License.jsx b/src/pages/License.jsx index bb1ab2cd88..db74e17fb0 100644 --- a/src/pages/License.jsx +++ b/src/pages/License.jsx @@ -1,5 +1,6 @@ import React, { Component, Fragment } from 'react'; -import { Trans } from '@lingui/macro'; +import { withI18n } from '@lingui/react'; +import { t } from '@lingui/macro'; import { PageSection, PageSectionVariants, @@ -8,13 +9,14 @@ import { class License extends Component { render () { + const { i18n } = this.props; const { light, medium } = PageSectionVariants; return ( - <Trans>License</Trans> + {i18n._(t`License`)} @@ -23,4 +25,4 @@ class License extends Component { } } -export default License; +export default withI18n()(License); diff --git a/src/pages/Login.jsx b/src/pages/Login.jsx index 27ca4cfb5f..50b58765ae 100644 --- a/src/pages/Login.jsx +++ b/src/pages/Login.jsx @@ -1,6 +1,6 @@ import React, { Component } from 'react'; import { Redirect, withRouter } from 'react-router-dom'; -import { I18n } from '@lingui/react'; +import { withI18n } from '@lingui/react'; import { t } from '@lingui/macro'; import { LoginForm, @@ -62,7 +62,7 @@ class AWXLogin extends Component { render () { const { username, password, isInputValid, isAuthenticated } = this.state; - const { alt, loginInfo, logo, bodyText: errorMessage } = this.props; + const { alt, loginInfo, logo, bodyText: errorMessage, i18n } = this.props; const logoSrc = logo ? `data:image/jpeg;${logo}` : towerLogo; if (isAuthenticated) { @@ -70,34 +70,30 @@ class AWXLogin extends Component { } return ( - - {({ i18n }) => ( - - - - )} - + + + ); } } export { AWXLogin as _AWXLogin }; -export default withNetwork(withRootDialog(withRouter(AWXLogin))); +export default withI18n()(withNetwork(withRootDialog(withRouter(AWXLogin)))); diff --git a/src/pages/ManagementJobs.jsx b/src/pages/ManagementJobs.jsx index 8aa347acc6..c74b484314 100644 --- a/src/pages/ManagementJobs.jsx +++ b/src/pages/ManagementJobs.jsx @@ -1,5 +1,6 @@ import React, { Component, Fragment } from 'react'; -import { Trans } from '@lingui/macro'; +import { withI18n } from '@lingui/react'; +import { t } from '@lingui/macro'; import { PageSection, PageSectionVariants, @@ -8,13 +9,14 @@ import { class ManagementJobs extends Component { render () { + const { i18n } = this.props; const { light, medium } = PageSectionVariants; return ( - <Trans>Management Jobs</Trans> + {i18n._(t`Management Jobs`)} @@ -23,4 +25,4 @@ class ManagementJobs extends Component { } } -export default ManagementJobs; +export default withI18n()(ManagementJobs); diff --git a/src/pages/NotificationTemplates.jsx b/src/pages/NotificationTemplates.jsx index 8c824340b5..9b28ecb9af 100644 --- a/src/pages/NotificationTemplates.jsx +++ b/src/pages/NotificationTemplates.jsx @@ -1,5 +1,6 @@ import React, { Component, Fragment } from 'react'; -import { Trans } from '@lingui/macro'; +import { withI18n } from '@lingui/react'; +import { t } from '@lingui/macro'; import { PageSection, PageSectionVariants, @@ -8,13 +9,14 @@ import { class NotificationTemplates extends Component { render () { + const { i18n } = this.props; const { light, medium } = PageSectionVariants; return ( - <Trans>Notification Templates</Trans> + {i18n._(t`Notification Templates`)} @@ -23,4 +25,4 @@ class NotificationTemplates extends Component { } } -export default NotificationTemplates; +export default withI18n()(NotificationTemplates); diff --git a/src/pages/Organizations/Organizations.jsx b/src/pages/Organizations/Organizations.jsx index e9ba60d059..00962dd43a 100644 --- a/src/pages/Organizations/Organizations.jsx +++ b/src/pages/Organizations/Organizations.jsx @@ -1,7 +1,7 @@ import React, { Component, Fragment } from 'react'; import { Route, withRouter, Switch } from 'react-router-dom'; -import { i18nMark } from '@lingui/react'; -import { Trans } from '@lingui/macro'; +import { withI18n } from '@lingui/react'; +import { t } from '@lingui/macro'; import { Config } from '../../contexts/Config'; import { NetworkProvider } from '../../contexts/Network'; @@ -14,34 +14,42 @@ import OrganizationAdd from './screens/OrganizationAdd'; import Organization from './screens/Organization/Organization'; class Organizations extends Component { - state = { - breadcrumbConfig: { - '/organizations': i18nMark('Organizations'), - '/organizations/add': i18nMark('Create New Organization') - } - }; + constructor (props) { + super(props); + + const { i18n } = props; + + this.state = { + breadcrumbConfig: { + '/organizations': i18n._(t`Organizations`), + '/organizations/add': i18n._(t`Create New Organization`) + } + }; + } setBreadcrumbConfig = (organization) => { + const { i18n } = this.props; + if (!organization) { return; } const breadcrumbConfig = { - '/organizations': i18nMark('Organizations'), - '/organizations/add': i18nMark('Create New Organization'), + '/organizations': i18n._(t`Organizations`), + '/organizations/add': i18n._(t`Create New Organization`), [`/organizations/${organization.id}`]: `${organization.name}`, - [`/organizations/${organization.id}/edit`]: i18nMark('Edit Details'), - [`/organizations/${organization.id}/details`]: i18nMark('Details'), - [`/organizations/${organization.id}/access`]: i18nMark('Access'), - [`/organizations/${organization.id}/teams`]: i18nMark('Teams'), - [`/organizations/${organization.id}/notifications`]: i18nMark('Notifications'), + [`/organizations/${organization.id}/edit`]: i18n._(t`Edit Details`), + [`/organizations/${organization.id}/details`]: i18n._(t`Details`), + [`/organizations/${organization.id}/access`]: i18n._(t`Access`), + [`/organizations/${organization.id}/teams`]: i18n._(t`Teams`), + [`/organizations/${organization.id}/notifications`]: i18n._(t`Notifications`), }; this.setState({ breadcrumbConfig }); } render () { - const { match, history, location, setRootDialogMessage } = this.props; + const { match, history, location, setRootDialogMessage, i18n } = this.props; const { breadcrumbConfig } = this.state; return ( @@ -65,11 +73,11 @@ class Organizations extends Component { setRootDialogMessage({ title: '404', bodyText: ( - - Cannot find organization with ID + + {i18n._(t`Cannot find organization with ID`)} {` ${newRouteMatch.params.id}`} . - + ), variant: 'warning' }); @@ -101,4 +109,4 @@ class Organizations extends Component { } export { Organizations as _Organizations }; -export default withRootDialog(withRouter(Organizations)); +export default withI18n()(withRootDialog(withRouter(Organizations))); diff --git a/src/pages/Organizations/components/DeleteRoleConfirmationModal.jsx b/src/pages/Organizations/components/DeleteRoleConfirmationModal.jsx index 4f4760b864..c06b377ac7 100644 --- a/src/pages/Organizations/components/DeleteRoleConfirmationModal.jsx +++ b/src/pages/Organizations/components/DeleteRoleConfirmationModal.jsx @@ -1,8 +1,8 @@ -import React from 'react'; +import React, { Fragment } from 'react'; import { func, string } from 'prop-types'; import { Button } from '@patternfly/react-core'; -import { I18n, i18nMark } from '@lingui/react'; -import { t, Trans } from '@lingui/macro'; +import { withI18n } from '@lingui/react'; +import { t } from '@lingui/macro'; import AlertModal from '../../../components/AlertModal'; import { Role } from '../../../types'; @@ -24,57 +24,43 @@ class DeleteRoleConfirmationModal extends React.Component { } render () { - const { role, username, onCancel, onConfirm } = this.props; - const title = `Remove ${this.isTeamRole() ? 'Team' : 'User'} Access`; + const { role, username, onCancel, onConfirm, i18n } = this.props; + const title = i18n._(t`Remove ${this.isTeamRole() ? i18n._(t`Team`) : i18n._(t`User`)} Access`); return ( - - {({ i18n }) => ( - - {i18n._(t`Delete`)} - , - - ]} + aria-label="Confirm delete" + onClick={onConfirm} > - {this.isTeamRole() ? ( - - Are you sure you want to remove - {` ${role.name} `} - access from - {` ${role.team_name}`} - ? Doing so affects all members of the team. -
    -
    - If you - only - want to remove access for this particular user, please remove them from the team. -
    - ) : ( - - Are you sure you want to remove - {` ${role.name} `} - access from - {` ${username}`} - ? - - )} -
    + {i18n._(t`Delete`)} + , + + ]} + > + {this.isTeamRole() ? ( + + {i18n._(t`Are you sure you want to remove ${role.name} access from ${role.team_name}? Doing so affects all members of the team.`)} +
    +
    + {i18n._(t`If you ${(only)} want to remove access for this particular user, please remove them from the team.`)} +
    + ) : ( + + {i18n._(t`Are you sure you want to remove ${role.name} access from ${username}?`)} + )} -
    + ); } } -export default DeleteRoleConfirmationModal; +export default withI18n()(DeleteRoleConfirmationModal); diff --git a/src/pages/Organizations/components/InstanceGroupsLookup.jsx b/src/pages/Organizations/components/InstanceGroupsLookup.jsx index 703fd2420c..e93f93ebf5 100644 --- a/src/pages/Organizations/components/InstanceGroupsLookup.jsx +++ b/src/pages/Organizations/components/InstanceGroupsLookup.jsx @@ -1,20 +1,14 @@ import React, { Fragment } from 'react'; import PropTypes from 'prop-types'; -import { I18n, i18nMark } from '@lingui/react'; +import { withI18n } from '@lingui/react'; +import { t } from '@lingui/macro'; import { FormGroup, Tooltip } from '@patternfly/react-core'; import { QuestionCircleIcon } from '@patternfly/react-icons'; -import { t } from '@lingui/macro'; import Lookup from '../../../components/Lookup'; import { withNetwork } from '../../../contexts/Network'; -const INSTANCE_GROUPS_LOOKUP_COLUMNS = [ - { name: i18nMark('Name'), key: 'name', isSortable: true }, - { name: i18nMark('Modified'), key: 'modified', isSortable: false, isNumeric: true }, - { name: i18nMark('Created'), key: 'created', isSortable: false, isNumeric: true } -]; - class InstanceGroupsLookup extends React.Component { constructor (props) { super(props); @@ -29,43 +23,43 @@ class InstanceGroupsLookup extends React.Component { } render () { - const { value, tooltip, onChange } = this.props; + const { value, tooltip, onChange, i18n } = this.props; return ( - - {({ i18n }) => ( - - {i18n._(t`Instance Groups`)} - {' '} - { - tooltip && ( - - - - ) - } -
    - )} - fieldId="org-instance-groups" - > - - + + {i18n._(t`Instance Groups`)} + {' '} + { + tooltip && ( + + + + ) + } +
    )} -
    + fieldId="org-instance-groups" + > + + ); } } @@ -80,4 +74,4 @@ InstanceGroupsLookup.defaultProps = { tooltip: '', }; -export default withNetwork(InstanceGroupsLookup); +export default withI18n()(withNetwork(InstanceGroupsLookup)); diff --git a/src/pages/Organizations/components/OrganizationAccessItem.jsx b/src/pages/Organizations/components/OrganizationAccessItem.jsx index 71ac7a94f4..f6caf4a499 100644 --- a/src/pages/Organizations/components/OrganizationAccessItem.jsx +++ b/src/pages/Organizations/components/OrganizationAccessItem.jsx @@ -1,6 +1,6 @@ import React from 'react'; import { func } from 'prop-types'; -import { I18n } from '@lingui/react'; +import { withI18n } from '@lingui/react'; import { t } from '@lingui/macro'; import { DataListItem, @@ -81,96 +81,92 @@ class OrganizationAccessItem extends React.Component { } render () { - const { accessRecord, onRoleDelete } = this.props; + const { accessRecord, onRoleDelete, i18n } = this.props; const [teamRoles, userRoles] = this.getRoleLists(); return ( - - {({ i18n }) => ( - - - - {accessRecord.username && ( - - {accessRecord.url ? ( - - - {accessRecord.username} - - - ) : ( - - {accessRecord.username} - - )} - - )} - {accessRecord.first_name || accessRecord.last_name ? ( - + + + + {accessRecord.username && ( + + {accessRecord.url ? ( + + + {accessRecord.username} + + ) : ( - null + + {accessRecord.username} + )} - , - - {userRoles.length > 0 && ( -
      - - {i18n._(t`User Roles`)} - - {userRoles.map(role => ( - role.user_capabilities.unattach ? ( - { onRoleDelete(role, accessRecord); }} - > - {role.name} - - ) : ( - - {role.name} - - ) - ))} -
    - )} - {teamRoles.length > 0 && ( -
      - - {i18n._(t`Team Roles`)} - - {teamRoles.map(role => ( - role.user_capabilities.unattach ? ( - { onRoleDelete(role, accessRecord); }} - > - {role.name} - - ) : ( - - {role.name} - - ) - ))} -
    - )} -
    - ]} - /> -
    -
    - )} -
    + + )} + {accessRecord.first_name || accessRecord.last_name ? ( + + ) : ( + null + )} + , + + {userRoles.length > 0 && ( +
      + + {i18n._(t`User Roles`)} + + {userRoles.map(role => ( + role.user_capabilities.unattach ? ( + { onRoleDelete(role, accessRecord); }} + > + {role.name} + + ) : ( + + {role.name} + + ) + ))} +
    + )} + {teamRoles.length > 0 && ( +
      + + {i18n._(t`Team Roles`)} + + {teamRoles.map(role => ( + role.user_capabilities.unattach ? ( + { onRoleDelete(role, accessRecord); }} + > + {role.name} + + ) : ( + + {role.name} + + ) + ))} +
    + )} +
    + ]} + /> + + ); } } -export default OrganizationAccessItem; +export default withI18n()(OrganizationAccessItem); diff --git a/src/pages/Organizations/components/OrganizationForm.jsx b/src/pages/Organizations/components/OrganizationForm.jsx index d956bb8c47..c8364239e8 100644 --- a/src/pages/Organizations/components/OrganizationForm.jsx +++ b/src/pages/Organizations/components/OrganizationForm.jsx @@ -2,7 +2,7 @@ import React, { Component } from 'react'; import PropTypes from 'prop-types'; import { withRouter } from 'react-router-dom'; import { Formik, Field } from 'formik'; -import { I18n } from '@lingui/react'; +import { withI18n } from '@lingui/react'; import { t } from '@lingui/macro'; import { Form, @@ -83,76 +83,72 @@ class OrganizationForm extends Component { } render () { - const { organization, handleCancel } = this.props; + const { organization, handleCancel, i18n } = this.props; const { instanceGroups, formIsValid, error } = this.state; const defaultVenv = '/venv/ansible/'; return ( - - {({ i18n }) => ( - ( -
    - - - - - {({ custom_virtualenvs }) => ( - custom_virtualenvs && custom_virtualenvs.length > 1 && ( - ( - - - - )} - /> - ) - )} - - - - - {error ?
    error
    : null} - - )} - /> + ( +
    + + + + + {({ custom_virtualenvs }) => ( + custom_virtualenvs && custom_virtualenvs.length > 1 && ( + ( + + + + )} + /> + ) + )} + + + + + {error ?
    error
    : null} + )} -
    + /> ); } } @@ -176,4 +172,4 @@ OrganizationForm.contextTypes = { }; export { OrganizationForm as _OrganizationForm }; -export default withNetwork(withRouter(OrganizationForm)); +export default withI18n()(withNetwork(withRouter(OrganizationForm))); diff --git a/src/pages/Organizations/components/OrganizationListItem.jsx b/src/pages/Organizations/components/OrganizationListItem.jsx index 865fa4e3c0..804708c544 100644 --- a/src/pages/Organizations/components/OrganizationListItem.jsx +++ b/src/pages/Organizations/components/OrganizationListItem.jsx @@ -1,6 +1,7 @@ import React from 'react'; import { string, bool, func } from 'prop-types'; -import { Trans } from '@lingui/macro'; +import { withI18n } from '@lingui/react'; +import { t } from '@lingui/macro'; import { Badge as PFBadge, DataListItem, @@ -62,6 +63,7 @@ class OrganizationListItem extends React.Component { isSelected, onSelect, detailUrl, + i18n } = this.props; const labelId = `check-action-${organization.id}`; return ( @@ -86,13 +88,15 @@ class OrganizationListItem extends React.Component { , - Members + {i18n._(t`Members`)} {organization.summary_fields.related_field_counts.users} + , + - Teams + {i18n._(t`Teams`)} {organization.summary_fields.related_field_counts.teams} @@ -105,4 +109,4 @@ class OrganizationListItem extends React.Component { ); } } -export default OrganizationListItem; +export default withI18n()(OrganizationListItem); diff --git a/src/pages/Organizations/screens/Organization/Organization.jsx b/src/pages/Organizations/screens/Organization/Organization.jsx index ec65d866a6..aaf6be1940 100644 --- a/src/pages/Organizations/screens/Organization/Organization.jsx +++ b/src/pages/Organizations/screens/Organization/Organization.jsx @@ -1,5 +1,5 @@ import React, { Component } from 'react'; -import { I18n, i18nMark } from '@lingui/react'; +import { withI18n } from '@lingui/react'; import { t } from '@lingui/macro'; import { Switch, Route, withRouter, Redirect } from 'react-router-dom'; import { Card, CardHeader, PageSection } from '@patternfly/react-core'; @@ -100,7 +100,8 @@ class Organization extends Component { location, match, me, - history + history, + i18n } = this.props; const { @@ -126,14 +127,14 @@ class Organization extends Component { ); const tabsArray = [ - { name: i18nMark('Details'), link: `${match.url}/details`, id: 0 }, - { name: i18nMark('Access'), link: `${match.url}/access`, id: 1 }, - { name: i18nMark('Teams'), link: `${match.url}/teams`, id: 2 } + { name: i18n._(t`Details`), link: `${match.url}/details`, id: 0 }, + { name: i18n._(t`Access`), link: `${match.url}/access`, id: 1 }, + { name: i18n._(t`Teams`), link: `${match.url}/teams`, id: 2 } ]; if (canSeeNotificationsTab) { tabsArray.push({ - name: i18nMark('Notifications'), + name: i18n._(t`Notifications`), link: `${match.url}/notifications`, id: 3 }); @@ -145,24 +146,18 @@ class Organization extends Component { - - {({ i18n }) => ( - -
    - - -
    -
    - - )} - +
    + + +
    +
    )); if (!match) { @@ -245,5 +240,5 @@ class Organization extends Component { ); } } -export default withNetwork(withRouter(Organization)); +export default withI18n()(withNetwork(withRouter(Organization))); export { Organization as _Organization }; diff --git a/src/pages/Organizations/screens/Organization/OrganizationAccess.jsx b/src/pages/Organizations/screens/Organization/OrganizationAccess.jsx index ad2fc69d7e..2d974e5424 100644 --- a/src/pages/Organizations/screens/Organization/OrganizationAccess.jsx +++ b/src/pages/Organizations/screens/Organization/OrganizationAccess.jsx @@ -1,6 +1,7 @@ import React, { Fragment } from 'react'; import { withRouter } from 'react-router-dom'; -import { i18nMark } from '@lingui/react'; +import { withI18n } from '@lingui/react'; +import { t } from '@lingui/macro'; import PaginatedDataList, { ToolbarAddButton } from '../../../../components/PaginatedDataList'; import OrganizationAccessItem from '../../components/OrganizationAccessItem'; import DeleteRoleConfirmationModal from '../../components/DeleteRoleConfirmationModal'; @@ -130,7 +131,7 @@ class OrganizationAccess extends React.Component { } render () { - const { api, organization } = this.props; + const { organization, i18n } = this.props; const { isLoading, isInitialized, @@ -167,9 +168,9 @@ class OrganizationAccess extends React.Component { itemName="role" qsConfig={QS_CONFIG} toolbarColumns={[ - { name: i18nMark('Name'), key: 'first_name', isSortable: true }, - { name: i18nMark('Username'), key: 'username', isSortable: true }, - { name: i18nMark('Last Name'), key: 'last_name', isSortable: true }, + { name: i18n._(t`Name`), key: 'first_name', isSortable: true }, + { name: i18n._(t`Username`), key: 'username', isSortable: true }, + { name: i18n._(t`Last Name`), key: 'last_name', isSortable: true }, ]} additionalControls={canEdit ? [ @@ -187,7 +188,6 @@ class OrganizationAccess extends React.Component { )} @@ -197,4 +197,4 @@ class OrganizationAccess extends React.Component { } export { OrganizationAccess as _OrganizationAccess }; -export default withNetwork(withRouter(OrganizationAccess)); +export default withI18n()(withNetwork(withRouter(OrganizationAccess))); diff --git a/src/pages/Organizations/screens/Organization/OrganizationDetail.jsx b/src/pages/Organizations/screens/Organization/OrganizationDetail.jsx index c992f66e6d..1c6a69b6d5 100644 --- a/src/pages/Organizations/screens/Organization/OrganizationDetail.jsx +++ b/src/pages/Organizations/screens/Organization/OrganizationDetail.jsx @@ -1,7 +1,7 @@ import React, { Component } from 'react'; import { Link, withRouter } from 'react-router-dom'; -import { I18n } from '@lingui/react'; -import { Trans, t } from '@lingui/macro'; +import { withI18n } from '@lingui/react'; +import { t } from '@lingui/macro'; import { CardBody, @@ -103,7 +103,8 @@ class OrganizationDetail extends Component { modified, summary_fields }, - match + match, + i18n } = this.props; const showOverflowChipAfter = 5; @@ -127,58 +128,54 @@ class OrganizationDetail extends Component { ) : null; return ( - - {({ i18n }) => ( - -
    - - - - - - {(instanceGroups && instanceGroups.length > 0) && ( - - - Instance Groups - -
    - {instanceGroupChips} - {overflowChip} -
    -
    - )} -
    - {summary_fields.user_capabilities.edit && ( -
    - - - + +
    + + + + + + {(instanceGroups && instanceGroups.length > 0) && ( + + + {i18n._(t`Instance Groups`)} + +
    + {instanceGroupChips} + {overflowChip}
    - )} - {error ? 'error!' : ''} - +
    + )} +
    + {summary_fields.user_capabilities.edit && ( +
    + + + +
    )} - + {error ? 'error!' : ''} +
    ); } } -export default withRouter(withNetwork(OrganizationDetail)); +export default withI18n()(withRouter(withNetwork(OrganizationDetail))); diff --git a/src/pages/Organizations/screens/OrganizationAdd.jsx b/src/pages/Organizations/screens/OrganizationAdd.jsx index c975ea6bac..abd652d66d 100644 --- a/src/pages/Organizations/screens/OrganizationAdd.jsx +++ b/src/pages/Organizations/screens/OrganizationAdd.jsx @@ -1,7 +1,7 @@ import React from 'react'; import PropTypes from 'prop-types'; import { withRouter } from 'react-router-dom'; -import { I18n } from '@lingui/react'; +import { withI18n } from '@lingui/react'; import { t } from '@lingui/macro'; import { PageSection, @@ -57,30 +57,27 @@ class OrganizationAdd extends React.Component { render () { const { error } = this.state; + const { i18n } = this.props; return ( - - {({ i18n }) => ( - - - - - - - - - {error ?
    error
    : ''} -
    -
    - )} -
    + + + + + + + + + {error ?
    error
    : ''} +
    +
    ); } @@ -95,4 +92,4 @@ OrganizationAdd.contextTypes = { }; export { OrganizationAdd as _OrganizationAdd }; -export default withNetwork(withRouter(OrganizationAdd)); +export default withI18n()(withNetwork(withRouter(OrganizationAdd))); diff --git a/src/pages/Organizations/screens/OrganizationsList.jsx b/src/pages/Organizations/screens/OrganizationsList.jsx index 6465017fd0..393a10d365 100644 --- a/src/pages/Organizations/screens/OrganizationsList.jsx +++ b/src/pages/Organizations/screens/OrganizationsList.jsx @@ -1,6 +1,7 @@ import React, { Component } from 'react'; import { withRouter } from 'react-router-dom'; -import { i18nMark } from '@lingui/react'; +import { withI18n } from '@lingui/react'; +import { t } from '@lingui/macro'; import { Card, PageSection, @@ -15,12 +16,6 @@ import PaginatedDataList, { import OrganizationListItem from '../components/OrganizationListItem'; import { getQSConfig, parseNamespacedQueryString } from '../../../util/qs'; -const COLUMNS = [ - { name: i18nMark('Name'), key: 'name', isSortable: true }, - { name: i18nMark('Modified'), key: 'modified', isSortable: true, isNumeric: true }, - { name: i18nMark('Created'), key: 'created', isSortable: true, isNumeric: true }, -]; - const QS_CONFIG = getQSConfig('organization', { page: 1, page_size: 5, @@ -36,7 +31,7 @@ class OrganizationsList extends Component { isLoading: true, isInitialized: false, organizations: [], - selected: [], + selected: [] }; this.handleSelectAll = this.handleSelectAll.bind(this); @@ -148,9 +143,9 @@ class OrganizationsList extends Component { isLoading, isInitialized, selected, - organizations, + organizations } = this.state; - const { match } = this.props; + const { match, i18n } = this.props; const isAllSelected = selected.length === organizations.length; @@ -163,7 +158,11 @@ class OrganizationsList extends Component { itemCount={itemCount} itemName="organization" qsConfig={QS_CONFIG} - toolbarColumns={COLUMNS} + toolbarColumns={[ + { name: i18n._(t`Name`), key: 'name', isSortable: true }, + { name: i18n._(t`Modified`), key: 'modified', isSortable: true, isNumeric: true }, + { name: i18n._(t`Created`), key: 'created', isSortable: true, isNumeric: true }, + ]} showSelectAll isAllSelected={isAllSelected} onSelectAll={this.handleSelectAll} @@ -198,4 +197,4 @@ class OrganizationsList extends Component { } export { OrganizationsList as _OrganizationsList }; -export default withNetwork(withRouter(OrganizationsList)); +export default withI18n()(withNetwork(withRouter(OrganizationsList))); diff --git a/src/pages/Portal.jsx b/src/pages/Portal.jsx index 999d895893..2073ebc33a 100644 --- a/src/pages/Portal.jsx +++ b/src/pages/Portal.jsx @@ -1,5 +1,6 @@ import React, { Component, Fragment } from 'react'; -import { Trans } from '@lingui/macro'; +import { withI18n } from '@lingui/react'; +import { t } from '@lingui/macro'; import { PageSection, PageSectionVariants, @@ -8,13 +9,14 @@ import { class Portal extends Component { render () { + const { i18n } = this.props; const { light, medium } = PageSectionVariants; return ( - <Trans>My View</Trans> + {i18n._(t`My View`)} @@ -23,4 +25,4 @@ class Portal extends Component { } } -export default Portal; +export default withI18n()(Portal); diff --git a/src/pages/Projects.jsx b/src/pages/Projects.jsx index 3646c73756..079cb7fe36 100644 --- a/src/pages/Projects.jsx +++ b/src/pages/Projects.jsx @@ -1,5 +1,6 @@ import React, { Component, Fragment } from 'react'; -import { Trans } from '@lingui/macro'; +import { withI18n } from '@lingui/react'; +import { t } from '@lingui/macro'; import { PageSection, PageSectionVariants, @@ -8,13 +9,14 @@ import { class Projects extends Component { render () { + const { i18n } = this.props; const { light, medium } = PageSectionVariants; return ( - <Trans>Projects</Trans> + {i18n._(t`Projects`)} @@ -23,4 +25,4 @@ class Projects extends Component { } } -export default Projects; +export default withI18n()(Projects); diff --git a/src/pages/Schedules.jsx b/src/pages/Schedules.jsx index fbada872d5..2d8951685a 100644 --- a/src/pages/Schedules.jsx +++ b/src/pages/Schedules.jsx @@ -1,5 +1,6 @@ import React, { Component, Fragment } from 'react'; -import { Trans } from '@lingui/macro'; +import { withI18n } from '@lingui/react'; +import { t } from '@lingui/macro'; import { PageSection, PageSectionVariants, @@ -8,13 +9,14 @@ import { class Schedules extends Component { render () { + const { i18n } = this.props; const { light, medium } = PageSectionVariants; return ( - <Trans>Schedules</Trans> + {i18n._(t`Schedules`)} @@ -23,4 +25,4 @@ class Schedules extends Component { } } -export default Schedules; +export default withI18n()(Schedules); diff --git a/src/pages/SystemSettings.jsx b/src/pages/SystemSettings.jsx index 2cc19192a9..ac33293756 100644 --- a/src/pages/SystemSettings.jsx +++ b/src/pages/SystemSettings.jsx @@ -1,5 +1,6 @@ import React, { Component, Fragment } from 'react'; -import { Trans } from '@lingui/macro'; +import { withI18n } from '@lingui/react'; +import { t } from '@lingui/macro'; import { PageSection, PageSectionVariants, @@ -8,13 +9,14 @@ import { class SystemSettings extends Component { render () { + const { i18n } = this.props; const { light, medium } = PageSectionVariants; return ( - <Trans>System Settings</Trans> + {i18n._(t`System Settings`)} @@ -23,4 +25,4 @@ class SystemSettings extends Component { } } -export default SystemSettings; +export default withI18n()(SystemSettings); diff --git a/src/pages/Teams.jsx b/src/pages/Teams.jsx index e8eb36c2d5..e49bfca702 100644 --- a/src/pages/Teams.jsx +++ b/src/pages/Teams.jsx @@ -1,5 +1,6 @@ import React, { Component, Fragment } from 'react'; -import { Trans } from '@lingui/macro'; +import { withI18n } from '@lingui/react'; +import { t } from '@lingui/macro'; import { PageSection, PageSectionVariants, @@ -8,13 +9,14 @@ import { class Teams extends Component { render () { + const { i18n } = this.props; const { light, medium } = PageSectionVariants; return ( - <Trans>Teams</Trans> + {i18n._(t`Teams`)} @@ -23,4 +25,4 @@ class Teams extends Component { } } -export default Teams; +export default withI18n()(Teams); diff --git a/src/pages/Templates.jsx b/src/pages/Templates.jsx index 59ed691f8e..f8a5a99a16 100644 --- a/src/pages/Templates.jsx +++ b/src/pages/Templates.jsx @@ -1,5 +1,6 @@ import React, { Component, Fragment } from 'react'; -import { Trans } from '@lingui/macro'; +import { withI18n } from '@lingui/react'; +import { t } from '@lingui/macro'; import { PageSection, PageSectionVariants, @@ -8,13 +9,14 @@ import { class Templates extends Component { render () { + const { i18n } = this.props; const { light, medium } = PageSectionVariants; return ( - <Trans>Templates</Trans> + {i18n._(t`Templates`)} @@ -23,4 +25,4 @@ class Templates extends Component { } } -export default Templates; +export default withI18n()(Templates); diff --git a/src/pages/UISettings.jsx b/src/pages/UISettings.jsx index c581f6633f..c51d5d0e84 100644 --- a/src/pages/UISettings.jsx +++ b/src/pages/UISettings.jsx @@ -1,5 +1,6 @@ import React, { Component, Fragment } from 'react'; -import { Trans } from '@lingui/macro'; +import { withI18n } from '@lingui/react'; +import { t } from '@lingui/macro'; import { PageSection, PageSectionVariants, @@ -8,13 +9,14 @@ import { class UISettings extends Component { render () { + const { i18n } = this.props; const { light, medium } = PageSectionVariants; return ( - <Trans>User Interface Settings</Trans> + {i18n._(t`User Interface Settings`)} @@ -23,4 +25,4 @@ class UISettings extends Component { } } -export default UISettings; +export default withI18n()(UISettings); diff --git a/src/pages/Users.jsx b/src/pages/Users.jsx index 5f6f6b2d34..ca2dd09ebd 100644 --- a/src/pages/Users.jsx +++ b/src/pages/Users.jsx @@ -1,5 +1,6 @@ import React, { Component, Fragment } from 'react'; -import { Trans } from '@lingui/macro'; +import { withI18n } from '@lingui/react'; +import { t } from '@lingui/macro'; import { PageSection, PageSectionVariants, @@ -8,13 +9,14 @@ import { class Users extends Component { render () { + const { i18n } = this.props; const { light, medium } = PageSectionVariants; return ( - <Trans>Users</Trans> + {i18n._(t`Users`)} @@ -23,4 +25,4 @@ class Users extends Component { } } -export default Users; +export default withI18n()(Users); diff --git a/src/util/validators.js b/src/util/validators.js deleted file mode 100644 index 939bb1bdec..0000000000 --- a/src/util/validators.js +++ /dev/null @@ -1,20 +0,0 @@ -import { i18nMark } from '@lingui/react'; - -export function required (message) { - return value => { - if (!value.trim()) { - return message || i18nMark('This field must not be blank'); - } - return undefined; - }; -} - -export function maxLength (max) { - return value => { - if (value.trim().length - > max) { - return i18nMark(`This field must not exceed ${max} characters`); - } - return undefined; - }; -} diff --git a/src/util/validators.jsx b/src/util/validators.jsx new file mode 100644 index 0000000000..7de0a0a423 --- /dev/null +++ b/src/util/validators.jsx @@ -0,0 +1,20 @@ +import { t } from '@lingui/macro'; + +export function required (message, i18n) { + return value => { + if (!value.trim()) { + return message || i18n._(t`This field must not be blank`); + } + return undefined; + }; +} + +export function maxLength (max, i18n) { + return value => { + if (value.trim().length + > max) { + return i18n._(t`This field must not exceed ${max} characters`); + } + return undefined; + }; +}