diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index 2780cfbdf2..b2eebf71a0 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -12,6 +12,7 @@ Have questions about this document or anything not covered here? Feel free to re
* [Node and npm](#node-and-npm)
* [Build the user interface](#build-the-user-interface)
* [Accessing the AWX web interface](#accessing-the-awx-web-interface)
+* [AWX REST API Interaction](#awx-rest-api-interaction)
* [Working with React](#working-with-react)
* [App structure](#app-structure)
* [Naming files](#naming-files)
@@ -58,6 +59,57 @@ Run the following to build the AWX UI:
You can now log into the AWX web interface at [https://127.0.0.1:3001](https://127.0.0.1:3001).
+## AWX REST API Interaction
+
+This interface is built on top of the AWX REST API. If a component needs to interact with the API then the model that corresponds to that base endpoint will need to be imported from the api module.
+
+Example:
+
+`import { OrganizationsAPI, UsersAPI } from '../../../api';`
+
+All models extend a `Base` class which provides an interface to the standard HTTP methods (GET, POST, PUT etc). Methods that are specific to that endpoint should be added directly to model's class.
+
+**Mixins** - For related endpoints that apply to several different models a mixin should be used. Mixins are classes with a number of methods and can be used to avoid adding the same methods to a number of different models. A good example of this is the Notifications mixin. This mixin provides generic methods for reading notification templates and toggling them on and off.
+Note that mixins can be chained. See the example below.
+
+Example of a model using multiple mixins:
+
+```
+import NotificationsMixin from '../mixins/Notifications.mixin';
+import InstanceGroupsMixin from '../mixins/InstanceGroups.mixin';
+
+class Organizations extends InstanceGroupsMixin(NotificationsMixin(Base)) {
+ ...
+}
+
+export default Organizations;
+```
+
+**Testing** - The easiest way to mock the api module in tests is to use jest's [automatic mock](https://jestjs.io/docs/en/es6-class-mocks#automatic-mock). This syntax will replace the class with a mock constructor and mock out all methods to return undefined by default. If necessary, you can still override these mocks for specific tests. See the example below.
+
+Example of mocking a specific method for every test in a suite:
+
+```
+import { OrganizationsAPI } from '../../../../src/api';
+
+// Mocks out all available methods. Comparable to:
+// OrganizationsAPI.readAccessList = jest.fn();
+// but for every available method
+jest.mock('../../../../src/api');
+
+// Return a specific mock value for the readAccessList method
+beforeEach(() => {
+ OrganizationsAPI.readAccessList.mockReturnValue({ foo: 'bar' });
+});
+
+// Reset mocks
+afterEach(() => {
+ jest.clearAllMocks();
+});
+
+...
+```
+
## Working with React
### App structure
@@ -191,20 +243,19 @@ this.state = {
We have several React contexts that wrap much of the app, including those from react-router, lingui, and some of our own. When testing a component that depends on one or more of these, you can use the `mountWithContexts()` helper function found in `__tests__/enzymeHelpers.jsx`. This can be used just like Enzyme's `mount()` function, except it will wrap the component tree with the necessary context providers and basic stub data.
-If you want to stub the value of a context, or assert actions taken on it, you can customize a contexts value by passing a second parameter to `mountWithContexts`. For example, this provides a custom value for the `Network` context:
+If you want to stub the value of a context, or assert actions taken on it, you can customize a contexts value by passing a second parameter to `mountWithContexts`. For example, this provides a custom value for the `Config` context:
```
-const network = {
- api: {
- getOrganizationInstanceGroups: jest.fn(),
- }
+const config = {
+ custom_virtualenvs: ['foo', 'bar'],
};
mountWithContexts( , {
- context: { network },
+ context: { config },
});
```
-In this test, when the `OrganizationForm` calls `api.getOrganizationInstanceGroups` from the network context, it will invoke the provided stub. You can assert that this stub is invoked when you expect or to provide stubbed data.
+Now that these custom virtual environments are available in this `OrganizationForm` test we can assert that the component that displays
+them is rendering properly.
The object containing context values looks for five known contexts, identified by the keys `linguiPublisher`, `router`, `config`, `network`, and `dialog` — the latter three each referring to the contexts defined in `src/contexts`. You can pass `false` for any of these values, and the corresponding context will be omitted from your test. For example, this will mount your component without the dialog context:
diff --git a/__tests__/App.test.jsx b/__tests__/App.test.jsx
index 663cf231a8..bf3393aa31 100644
--- a/__tests__/App.test.jsx
+++ b/__tests__/App.test.jsx
@@ -6,6 +6,10 @@ import { asyncFlush } from '../jest.setup';
import App from '../src/App';
+import { RootAPI } from '../src/api';
+
+jest.mock('../src/api');
+
describe(' ', () => {
test('expected content is rendered', () => {
const appWrapper = mountWithContexts(
@@ -89,15 +93,13 @@ describe(' ', () => {
});
test('onLogout makes expected call to api client', async (done) => {
- const logout = jest.fn(() => Promise.resolve());
-
const appWrapper = mountWithContexts( , {
- context: { network: { api: { logout }, handleHttpError: () => {} } }
+ context: { network: { handleHttpError: () => {} } }
}).find('App');
appWrapper.instance().onLogout();
await asyncFlush();
- expect(logout).toHaveBeenCalledTimes(1);
+ expect(RootAPI.logout).toHaveBeenCalledTimes(1);
done();
});
diff --git a/__tests__/__snapshots__/enzymeHelpers.test.jsx.snap b/__tests__/__snapshots__/enzymeHelpers.test.jsx.snap
index 50ac85a193..a1f251ed2d 100644
--- a/__tests__/__snapshots__/enzymeHelpers.test.jsx.snap
+++ b/__tests__/__snapshots__/enzymeHelpers.test.jsx.snap
@@ -46,17 +46,6 @@ exports[`mountWithContexts injected I18nProvider should mount and render deeply
`;
-exports[`mountWithContexts injected Network should mount and render 1`] = `
-
-
- test
-
-
-`;
-
exports[`mountWithContexts injected Router should mount and render 1`] = `
{
- test('isAuthenticated returns false when cookie is invalid', () => {
- APIClient.getCookie = jest.fn(() => invalidCookie);
-
- const api = new APIClient();
- expect(api.isAuthenticated()).toBe(false);
- });
-
- test('isAuthenticated returns false when cookie is unauthenticated', () => {
- APIClient.getCookie = jest.fn(() => validLoggedOutCookie);
-
- const api = new APIClient();
- expect(api.isAuthenticated()).toBe(false);
- });
-
- test('isAuthenticated returns true when cookie is valid and authenticated', () => {
- APIClient.getCookie = jest.fn(() => validLoggedInCookie);
-
- const api = new APIClient();
- expect(api.isAuthenticated()).toBe(true);
- });
-
- test('login calls get and post with expected content headers', async (done) => {
- const headers = { 'Content-Type': 'application/x-www-form-urlencoded' };
-
- const createPromise = () => Promise.resolve();
- const mockHttp = ({ get: jest.fn(createPromise), post: jest.fn(createPromise) });
-
- const api = new APIClient(mockHttp);
- await api.login('username', 'password');
-
- expect(mockHttp.get).toHaveBeenCalledTimes(1);
- expect(mockHttp.get.mock.calls[0]).toContainEqual({ headers });
-
- expect(mockHttp.post).toHaveBeenCalledTimes(1);
- expect(mockHttp.post.mock.calls[0]).toContainEqual({ headers });
-
- done();
- });
-
- test('login sends expected data', async (done) => {
- const createPromise = () => Promise.resolve();
- const mockHttp = ({ get: jest.fn(createPromise), post: jest.fn(createPromise) });
-
- const api = new APIClient(mockHttp);
- await api.login('foo', 'bar');
- await api.login('foo', 'bar', 'baz');
-
- expect(mockHttp.post).toHaveBeenCalledTimes(2);
- expect(mockHttp.post.mock.calls[0]).toContainEqual('username=foo&password=bar&next=%2Fapi%2Fv2%2Fconfig%2F');
- expect(mockHttp.post.mock.calls[1]).toContainEqual('username=foo&password=bar&next=baz');
-
- done();
- });
-
- test('logout calls expected http method', async (done) => {
- const createPromise = () => Promise.resolve();
- const mockHttp = ({ get: jest.fn(createPromise) });
-
- const api = new APIClient(mockHttp);
- await api.logout();
-
- expect(mockHttp.get).toHaveBeenCalledTimes(1);
-
- done();
- });
-
- test('getConfig calls expected http method', async (done) => {
- const createPromise = () => Promise.resolve();
- const mockHttp = ({ get: jest.fn(createPromise) });
-
- const api = new APIClient(mockHttp);
- await api.getConfig();
-
- expect(mockHttp.get).toHaveBeenCalledTimes(1);
-
- done();
- });
-
- test('getOrganizations calls http method with expected data', async (done) => {
- const createPromise = () => Promise.resolve();
- const mockHttp = ({ get: jest.fn(createPromise) });
- const api = new APIClient(mockHttp);
-
- const defaultParams = {};
- const testParams = { foo: 'bar' };
-
- await api.getOrganizations(testParams);
- await api.getOrganizations();
-
- expect(mockHttp.get).toHaveBeenCalledTimes(2);
- expect(mockHttp.get.mock.calls[0][1]).toEqual({ params: testParams });
- expect(mockHttp.get.mock.calls[1][1]).toEqual({ params: defaultParams });
- done();
- });
-
- test('createOrganization calls http method with expected data', async (done) => {
- const createPromise = () => Promise.resolve();
- const mockHttp = ({ post: jest.fn(createPromise) });
-
- const api = new APIClient(mockHttp);
- const data = { name: 'test ' };
- await api.createOrganization(data);
-
- expect(mockHttp.post).toHaveBeenCalledTimes(1);
- expect(mockHttp.post.mock.calls[0][1]).toEqual(data);
-
- done();
- });
-
- test('getOrganizationDetails calls http method with expected data', async (done) => {
- const createPromise = () => Promise.resolve();
- const mockHttp = ({ get: jest.fn(createPromise) });
-
- const api = new APIClient(mockHttp);
- await api.getOrganizationDetails(99);
-
- expect(mockHttp.get).toHaveBeenCalledTimes(1);
- expect(mockHttp.get.mock.calls[0][0]).toContain('99');
-
- done();
- });
-
- test('getInstanceGroups calls expected http method', async (done) => {
- const createPromise = () => Promise.resolve();
- const mockHttp = ({ get: jest.fn(createPromise) });
-
- const api = new APIClient(mockHttp);
- await api.getInstanceGroups();
-
- expect(mockHttp.get).toHaveBeenCalledTimes(1);
-
- done();
- });
-
- test('associateInstanceGroup calls expected http method with expected data', async (done) => {
- const createPromise = () => Promise.resolve();
- const mockHttp = ({ post: jest.fn(createPromise) });
-
- const api = new APIClient(mockHttp);
- const url = 'foo/bar/';
- const id = 1;
- await api.associateInstanceGroup(url, id);
-
- expect(mockHttp.post).toHaveBeenCalledTimes(1);
- expect(mockHttp.post.mock.calls[0][0]).toEqual(url);
- expect(mockHttp.post.mock.calls[0][1]).toEqual({ id });
-
- done();
- });
-
- test('disassociate calls expected http method with expected data', async (done) => {
- const createPromise = () => Promise.resolve();
- const mockHttp = ({ post: jest.fn(createPromise) });
-
- const api = new APIClient(mockHttp);
- const url = 'foo/bar/';
- const id = 1;
- await api.disassociate(url, id);
-
- expect(mockHttp.post).toHaveBeenCalledTimes(1);
- expect(mockHttp.post.mock.calls[0][0]).toEqual(url);
- expect(mockHttp.post.mock.calls[0][1]).toEqual({ id, disassociate: true });
-
- done();
- });
-});
diff --git a/__tests__/api/base.test.jsx b/__tests__/api/base.test.jsx
new file mode 100644
index 0000000000..e7b79fe5b2
--- /dev/null
+++ b/__tests__/api/base.test.jsx
@@ -0,0 +1,97 @@
+import Base from '../../src/api/Base';
+
+describe('Base', () => {
+ const createPromise = () => Promise.resolve();
+ const mockBaseURL = '/api/v2/organizations/';
+ const mockHttp = ({
+ delete: jest.fn(createPromise),
+ get: jest.fn(createPromise),
+ options: jest.fn(createPromise),
+ patch: jest.fn(createPromise),
+ post: jest.fn(createPromise),
+ put: jest.fn(createPromise)
+ });
+
+ const BaseAPI = new Base(mockHttp, mockBaseURL);
+
+ afterEach(() => {
+ jest.clearAllMocks();
+ });
+
+ test('create calls http method with expected data', async (done) => {
+ const data = { name: 'test ' };
+ await BaseAPI.create(data);
+
+ expect(mockHttp.post).toHaveBeenCalledTimes(1);
+ expect(mockHttp.post.mock.calls[0][1]).toEqual(data);
+
+ done();
+ });
+
+ test('destroy calls http method with expected data', async (done) => {
+ const resourceId = 1;
+ await BaseAPI.destroy(resourceId);
+
+ expect(mockHttp.delete).toHaveBeenCalledTimes(1);
+ expect(mockHttp.delete.mock.calls[0][0]).toEqual(`${mockBaseURL}${resourceId}/`);
+
+ done();
+ });
+
+ test('read calls http method with expected data', async (done) => {
+ const defaultParams = {};
+ const testParams = { foo: 'bar' };
+
+ await BaseAPI.read(testParams);
+ await BaseAPI.read();
+
+ expect(mockHttp.get).toHaveBeenCalledTimes(2);
+ expect(mockHttp.get.mock.calls[0][1]).toEqual({ params: testParams });
+ expect(mockHttp.get.mock.calls[1][1]).toEqual({ params: defaultParams });
+ done();
+ });
+
+ test('readDetail calls http method with expected data', async (done) => {
+ const resourceId = 1;
+
+ await BaseAPI.readDetail(resourceId);
+
+ expect(mockHttp.get).toHaveBeenCalledTimes(1);
+ expect(mockHttp.get.mock.calls[0][0]).toEqual(`${mockBaseURL}${resourceId}/`);
+ done();
+ });
+
+ test('readOptions calls http method with expected data', async (done) => {
+ await BaseAPI.readOptions();
+
+ expect(mockHttp.options).toHaveBeenCalledTimes(1);
+ expect(mockHttp.options.mock.calls[0][0]).toEqual(`${mockBaseURL}`);
+ done();
+ });
+
+ test('replace calls http method with expected data', async (done) => {
+ const resourceId = 1;
+ const data = { name: 'test ' };
+
+ await BaseAPI.replace(resourceId, data);
+
+ expect(mockHttp.put).toHaveBeenCalledTimes(1);
+ expect(mockHttp.put.mock.calls[0][0]).toEqual(`${mockBaseURL}${resourceId}/`);
+ expect(mockHttp.put.mock.calls[0][1]).toEqual(data);
+
+ done();
+ });
+
+ test('update calls http method with expected data', async (done) => {
+ const resourceId = 1;
+ const data = { name: 'test ' };
+
+ await BaseAPI.update(resourceId, data);
+
+ expect(mockHttp.patch).toHaveBeenCalledTimes(1);
+ expect(mockHttp.patch.mock.calls[0][0]).toEqual(`${mockBaseURL}${resourceId}/`);
+ expect(mockHttp.patch.mock.calls[0][1]).toEqual(data);
+
+ done();
+ });
+});
diff --git a/__tests__/api/organizations.test.jsx b/__tests__/api/organizations.test.jsx
new file mode 100644
index 0000000000..249661c634
--- /dev/null
+++ b/__tests__/api/organizations.test.jsx
@@ -0,0 +1,36 @@
+import Organizations from '../../src/api/models/Organizations';
+
+describe('OrganizationsAPI', () => {
+ const orgId = 1;
+ const searchParams = { foo: 'bar' };
+ const createPromise = () => Promise.resolve();
+ const mockHttp = ({ get: jest.fn(createPromise) });
+
+ const OrganizationsAPI = new Organizations(mockHttp);
+
+ afterEach(() => {
+ jest.clearAllMocks();
+ });
+
+ test('read access list calls get with expected params', async (done) => {
+ await OrganizationsAPI.readAccessList(orgId);
+ await OrganizationsAPI.readAccessList(orgId, searchParams);
+
+ expect(mockHttp.get).toHaveBeenCalledTimes(2);
+ expect(mockHttp.get.mock.calls[0]).toContainEqual(`/api/v2/organizations/${orgId}/access_list/`, { params: {} });
+ expect(mockHttp.get.mock.calls[1]).toContainEqual(`/api/v2/organizations/${orgId}/access_list/`, { params: searchParams });
+
+ done();
+ });
+
+ test('read teams calls get with expected params', async (done) => {
+ await OrganizationsAPI.readTeams(orgId);
+ await OrganizationsAPI.readTeams(orgId, searchParams);
+
+ expect(mockHttp.get).toHaveBeenCalledTimes(2);
+ expect(mockHttp.get.mock.calls[0]).toContainEqual(`/api/v2/organizations/${orgId}/teams/`, { params: {} });
+ expect(mockHttp.get.mock.calls[1]).toContainEqual(`/api/v2/organizations/${orgId}/teams/`, { params: searchParams });
+
+ done();
+ });
+});
diff --git a/__tests__/api/root.test.jsx b/__tests__/api/root.test.jsx
new file mode 100644
index 0000000000..8ef84a1f1b
--- /dev/null
+++ b/__tests__/api/root.test.jsx
@@ -0,0 +1,45 @@
+import Root from '../../src/api/models/Root';
+
+describe('RootAPI', () => {
+ const createPromise = () => Promise.resolve();
+ const mockHttp = ({ get: jest.fn(createPromise), post: jest.fn(createPromise) });
+
+ const RootAPI = new Root(mockHttp);
+
+ afterEach(() => {
+ jest.clearAllMocks();
+ });
+
+ test('login calls get and post with expected content headers', async (done) => {
+ const headers = { 'Content-Type': 'application/x-www-form-urlencoded' };
+
+ await RootAPI.login('username', 'password');
+
+ expect(mockHttp.get).toHaveBeenCalledTimes(1);
+ expect(mockHttp.get.mock.calls[0]).toContainEqual({ headers });
+
+ expect(mockHttp.post).toHaveBeenCalledTimes(1);
+ expect(mockHttp.post.mock.calls[0]).toContainEqual({ headers });
+
+ done();
+ });
+
+ test('login sends expected data', async (done) => {
+ await RootAPI.login('foo', 'bar');
+ await RootAPI.login('foo', 'bar', 'baz');
+
+ expect(mockHttp.post).toHaveBeenCalledTimes(2);
+ expect(mockHttp.post.mock.calls[0]).toContainEqual('username=foo&password=bar&next=%2Fapi%2Fv2%2Fconfig%2F');
+ expect(mockHttp.post.mock.calls[1]).toContainEqual('username=foo&password=bar&next=baz');
+
+ done();
+ });
+
+ test('logout calls expected http method', async (done) => {
+ await RootAPI.logout();
+
+ expect(mockHttp.get).toHaveBeenCalledTimes(1);
+
+ done();
+ });
+});
diff --git a/__tests__/api/teams.test.jsx b/__tests__/api/teams.test.jsx
new file mode 100644
index 0000000000..0df8153c08
--- /dev/null
+++ b/__tests__/api/teams.test.jsx
@@ -0,0 +1,35 @@
+import Teams from '../../src/api/models/Teams';
+
+describe('TeamsAPI', () => {
+ const teamId = 1;
+ const roleId = 7;
+ const createPromise = () => Promise.resolve();
+ const mockHttp = ({ post: jest.fn(createPromise) });
+
+ const TeamsAPI = new Teams(mockHttp);
+
+ afterEach(() => {
+ jest.clearAllMocks();
+ });
+
+ test('associate role calls post with expected params', async (done) => {
+ await TeamsAPI.associateRole(teamId, roleId);
+
+ expect(mockHttp.post).toHaveBeenCalledTimes(1);
+ expect(mockHttp.post.mock.calls[0]).toContainEqual(`/api/v2/teams/${teamId}/roles/`, { id: roleId });
+
+ done();
+ });
+
+ test('read teams calls post with expected params', async (done) => {
+ await TeamsAPI.disassociateRole(teamId, roleId);
+
+ expect(mockHttp.post).toHaveBeenCalledTimes(1);
+ expect(mockHttp.post.mock.calls[0]).toContainEqual(`/api/v2/teams/${teamId}/roles/`, {
+ id: roleId,
+ disassociate: true
+ });
+
+ done();
+ });
+});
diff --git a/__tests__/api/users.test.jsx b/__tests__/api/users.test.jsx
new file mode 100644
index 0000000000..3d72ce4a2d
--- /dev/null
+++ b/__tests__/api/users.test.jsx
@@ -0,0 +1,35 @@
+import Users from '../../src/api/models/Users';
+
+describe('UsersAPI', () => {
+ const userId = 1;
+ const roleId = 7;
+ const createPromise = () => Promise.resolve();
+ const mockHttp = ({ post: jest.fn(createPromise) });
+
+ const UsersAPI = new Users(mockHttp);
+
+ afterEach(() => {
+ jest.clearAllMocks();
+ });
+
+ test('associate role calls post with expected params', async (done) => {
+ await UsersAPI.associateRole(userId, roleId);
+
+ expect(mockHttp.post).toHaveBeenCalledTimes(1);
+ expect(mockHttp.post.mock.calls[0]).toContainEqual(`/api/v2/users/${userId}/roles/`, { id: roleId });
+
+ done();
+ });
+
+ test('read users calls post with expected params', async (done) => {
+ await UsersAPI.disassociateRole(userId, roleId);
+
+ expect(mockHttp.post).toHaveBeenCalledTimes(1);
+ expect(mockHttp.post.mock.calls[0]).toContainEqual(`/api/v2/users/${userId}/roles/`, {
+ id: roleId,
+ disassociate: true
+ });
+
+ done();
+ });
+});
diff --git a/__tests__/components/AddResourceRole.test.jsx b/__tests__/components/AddResourceRole.test.jsx
index 3a3b4a2241..0b0acb307e 100644
--- a/__tests__/components/AddResourceRole.test.jsx
+++ b/__tests__/components/AddResourceRole.test.jsx
@@ -2,9 +2,12 @@ import React from 'react';
import { shallow } from 'enzyme';
import { mountWithContexts } from '../enzymeHelpers';
import AddResourceRole, { _AddResourceRole } from '../../src/components/AddRole/AddResourceRole';
+import { TeamsAPI, UsersAPI } from '../../src/api';
+
+jest.mock('../../src/api');
describe('<_AddResourceRole />', () => {
- const readUsers = jest.fn().mockResolvedValue({
+ UsersAPI.read.mockResolvedValue({
data: {
count: 2,
results: [
@@ -13,10 +16,6 @@ describe('<_AddResourceRole />', () => {
]
}
});
- const readTeams = jest.fn();
- const createUserRole = jest.fn();
- const createTeamRole = jest.fn();
- const api = { readUsers, readTeams, createUserRole, createTeamRole };
const roles = {
admin_role: {
description: 'Can manage all aspects of the organization',
@@ -32,7 +31,6 @@ describe('<_AddResourceRole />', () => {
test('initially renders without crashing', () => {
shallow(
<_AddResourceRole
- api={api}
onClose={() => {}}
onSave={() => {}}
roles={roles}
@@ -43,7 +41,6 @@ describe('<_AddResourceRole />', () => {
test('handleRoleCheckboxClick properly updates state', () => {
const wrapper = shallow(
<_AddResourceRole
- api={api}
onClose={() => {}}
onSave={() => {}}
roles={roles}
@@ -79,7 +76,6 @@ describe('<_AddResourceRole />', () => {
test('handleResourceCheckboxClick properly updates state', () => {
const wrapper = shallow(
<_AddResourceRole
- api={api}
onClose={() => {}}
onSave={() => {}}
roles={roles}
@@ -115,7 +111,7 @@ describe('<_AddResourceRole />', () => {
onClose={() => {}}
onSave={() => {}}
roles={roles}
- />, { context: { network: { api, handleHttpError: () => {} } } }
+ />, { context: { network: { handleHttpError: () => {} } } }
).find('AddResourceRole');
const selectableCardWrapper = wrapper.find('SelectableCard');
expect(selectableCardWrapper.length).toBe(2);
@@ -126,35 +122,9 @@ describe('<_AddResourceRole />', () => {
expect(spy).toHaveBeenCalledWith('teams');
expect(wrapper.state('selectedResource')).toBe('teams');
});
- test('readUsers and readTeams call out to corresponding api functions', () => {
- const wrapper = shallow(
- <_AddResourceRole
- api={api}
- onClose={() => {}}
- onSave={() => {}}
- roles={roles}
- i18n={{ _: val => val.toString() }}
- />
- );
- wrapper.instance().readUsers({
- foo: 'bar'
- });
- expect(readUsers).toHaveBeenCalledWith({
- foo: 'bar',
- is_superuser: false
- });
- wrapper.instance().readTeams({
- foo: 'bar'
- });
- expect(readTeams).toHaveBeenCalledWith({
- foo: 'bar'
- });
- });
-
test('handleResourceSelect clears out selected lists and sets selectedResource', () => {
const wrapper = shallow(
<_AddResourceRole
- api={api}
onClose={() => {}}
onSave={() => {}}
roles={roles}
@@ -192,7 +162,6 @@ describe('<_AddResourceRole />', () => {
currentStepId: 1
});
});
-
test('handleWizardSave makes correct api calls, calls onSave when done', async () => {
const handleSave = jest.fn();
const wrapper = mountWithContexts(
@@ -200,7 +169,7 @@ describe('<_AddResourceRole />', () => {
onClose={() => {}}
onSave={handleSave}
roles={roles}
- />, { context: { network: { api, handleHttpError: () => {} } } }
+ />, { context: { network: { handleHttpError: () => {} } } }
).find('AddResourceRole');
wrapper.setState({
selectedResource: 'users',
@@ -224,7 +193,7 @@ describe('<_AddResourceRole />', () => {
]
});
await wrapper.instance().handleWizardSave();
- expect(createUserRole).toHaveBeenCalledTimes(2);
+ expect(UsersAPI.associateRole).toHaveBeenCalledTimes(2);
expect(handleSave).toHaveBeenCalled();
wrapper.setState({
selectedResource: 'teams',
@@ -248,7 +217,7 @@ describe('<_AddResourceRole />', () => {
]
});
await wrapper.instance().handleWizardSave();
- expect(createTeamRole).toHaveBeenCalledTimes(2);
+ expect(TeamsAPI.associateRole).toHaveBeenCalledTimes(2);
expect(handleSave).toHaveBeenCalled();
});
});
diff --git a/__tests__/enzymeHelpers.jsx b/__tests__/enzymeHelpers.jsx
index d8a5de7e4e..b7114e9cdf 100644
--- a/__tests__/enzymeHelpers.jsx
+++ b/__tests__/enzymeHelpers.jsx
@@ -70,10 +70,6 @@ const defaultContexts = {
toJSON: () => '/router/',
},
network: {
- api: {
- getConfig: () => {},
- toJSON: () => '/api/',
- },
handleHttpError: () => {},
},
dialog: {}
@@ -146,7 +142,6 @@ export function mountWithContexts (node, options = {}) {
history: shape({}).isRequired,
}),
network: shape({
- api: shape({}).isRequired,
handleHttpError: func.isRequired,
}),
dialog: shape({
diff --git a/__tests__/enzymeHelpers.test.jsx b/__tests__/enzymeHelpers.test.jsx
index 8a92fe0ab9..6c8c16a99a 100644
--- a/__tests__/enzymeHelpers.test.jsx
+++ b/__tests__/enzymeHelpers.test.jsx
@@ -4,7 +4,6 @@ import { withI18n } from '@lingui/react';
import { t } from '@lingui/macro';
import { mountWithContexts, waitForElement } from './enzymeHelpers';
import { Config } from '../src/contexts/Config';
-import { withNetwork } from '../src/contexts/Network';
import { withRootDialog } from '../src/contexts/RootDialog';
describe('mountWithContexts', () => {
@@ -111,32 +110,6 @@ describe('mountWithContexts', () => {
});
});
- describe('injected Network', () => {
- it('should mount and render', () => {
- const Foo = () => (
-
test
- );
- const Bar = withNetwork(Foo);
- const wrapper = mountWithContexts(
);
- expect(wrapper.find('Foo')).toMatchSnapshot();
- });
-
- it('should mount and render with stubbed api', () => {
- const network = {
- api: {
- getFoo: jest.fn().mockReturnValue('foo value'),
- },
- };
- const Foo = ({ api }) => (
-
{api.getFoo()}
- );
- const Bar = withNetwork(Foo);
- const wrapper = mountWithContexts(
, { context: { network } });
- expect(network.api.getFoo).toHaveBeenCalledTimes(1);
- expect(wrapper.find('div').text()).toEqual('foo value');
- });
- });
-
describe('injected root dialog', () => {
it('should mount and render', () => {
const Foo = ({ title, setRootDialogMessage }) => (
diff --git a/__tests__/pages/Login.test.jsx b/__tests__/pages/Login.test.jsx
index 57d4be3634..51b79e742f 100644
--- a/__tests__/pages/Login.test.jsx
+++ b/__tests__/pages/Login.test.jsx
@@ -2,7 +2,9 @@ import React from 'react';
import { mountWithContexts } from '../enzymeHelpers';
import { asyncFlush } from '../../jest.setup';
import AWXLogin from '../../src/pages/Login';
-import APIClient from '../../src/api';
+import { RootAPI } from '../../src/api';
+
+jest.mock('../../src/api');
describe('
', () => {
let loginWrapper;
@@ -14,12 +16,8 @@ describe('
', () => {
let submitButton;
let loginHeaderLogo;
- const api = new APIClient({});
-
const mountLogin = () => {
- loginWrapper = mountWithContexts(
, { context: { network: {
- api, handleHttpError: () => {}
- } } });
+ loginWrapper = mountWithContexts(
, { context: { network: {} } });
};
const findChildren = () => {
@@ -33,6 +31,7 @@ describe('
', () => {
};
afterEach(() => {
+ jest.clearAllMocks();
loginWrapper.unmount();
});
@@ -98,32 +97,31 @@ describe('
', () => {
expect(loginWrapper.find('.pf-c-form__helper-text.pf-m-error').length).toBe(0);
});
- test('api.login not called when loading', () => {
- api.login = jest.fn().mockImplementation(() => Promise.resolve({}));
+ test('login API not called when loading', () => {
mountLogin();
findChildren();
expect(awxLogin.state().isLoading).toBe(false);
awxLogin.setState({ isLoading: true });
submitButton.simulate('click');
- expect(api.login).toHaveBeenCalledTimes(0);
+ expect(RootAPI.login).toHaveBeenCalledTimes(0);
});
- test('submit calls api.login successfully', async () => {
- api.login = jest.fn().mockImplementation(() => Promise.resolve({}));
+ test('submit calls login API successfully', async () => {
+ RootAPI.login = jest.fn().mockImplementation(() => Promise.resolve({}));
mountLogin();
findChildren();
expect(awxLogin.state().isLoading).toBe(false);
awxLogin.setState({ username: 'unamee', password: 'pwordd' });
submitButton.simulate('click');
- expect(api.login).toHaveBeenCalledTimes(1);
- expect(api.login).toHaveBeenCalledWith('unamee', 'pwordd');
+ expect(RootAPI.login).toHaveBeenCalledTimes(1);
+ expect(RootAPI.login).toHaveBeenCalledWith('unamee', 'pwordd');
expect(awxLogin.state().isLoading).toBe(true);
await asyncFlush();
expect(awxLogin.state().isLoading).toBe(false);
});
- test('submit calls api.login handles 401 error', async () => {
- api.login = jest.fn().mockImplementation(() => {
+ test('submit calls login API and handles 401 error', async () => {
+ RootAPI.login = jest.fn().mockImplementation(() => {
const err = new Error('401 error');
err.response = { status: 401, message: 'problem' };
return Promise.reject(err);
@@ -134,16 +132,16 @@ describe('
', () => {
expect(awxLogin.state().isInputValid).toBe(true);
awxLogin.setState({ username: 'unamee', password: 'pwordd' });
submitButton.simulate('click');
- expect(api.login).toHaveBeenCalledTimes(1);
- expect(api.login).toHaveBeenCalledWith('unamee', 'pwordd');
+ expect(RootAPI.login).toHaveBeenCalledTimes(1);
+ expect(RootAPI.login).toHaveBeenCalledWith('unamee', 'pwordd');
expect(awxLogin.state().isLoading).toBe(true);
await asyncFlush();
expect(awxLogin.state().isInputValid).toBe(false);
expect(awxLogin.state().isLoading).toBe(false);
});
- test('submit calls api.login handles non-401 error', async () => {
- api.login = jest.fn().mockImplementation(() => {
+ test('submit calls login API and handles non-401 error', async () => {
+ RootAPI.login = jest.fn().mockImplementation(() => {
const err = new Error('500 error');
err.response = { status: 500, message: 'problem' };
return Promise.reject(err);
@@ -153,8 +151,8 @@ describe('
', () => {
expect(awxLogin.state().isLoading).toBe(false);
awxLogin.setState({ username: 'unamee', password: 'pwordd' });
submitButton.simulate('click');
- expect(api.login).toHaveBeenCalledTimes(1);
- expect(api.login).toHaveBeenCalledWith('unamee', 'pwordd');
+ expect(RootAPI.login).toHaveBeenCalledTimes(1);
+ expect(RootAPI.login).toHaveBeenCalledWith('unamee', 'pwordd');
expect(awxLogin.state().isLoading).toBe(true);
await asyncFlush();
expect(awxLogin.state().isLoading).toBe(false);
diff --git a/__tests__/pages/Organizations/components/OrganizationForm.test.jsx b/__tests__/pages/Organizations/components/OrganizationForm.test.jsx
index 2a2c98a19b..e1a4e84048 100644
--- a/__tests__/pages/Organizations/components/OrganizationForm.test.jsx
+++ b/__tests__/pages/Organizations/components/OrganizationForm.test.jsx
@@ -2,9 +2,12 @@ import React from 'react';
import { mountWithContexts } from '../../../enzymeHelpers';
import { sleep } from '../../../testUtils';
import OrganizationForm from '../../../../src/pages/Organizations/components/OrganizationForm';
+import { OrganizationsAPI } from '../../../../src/api';
+
+jest.mock('../../../../src/api');
describe('
', () => {
- let network;
+ const network = {};
const mockData = {
id: 1,
@@ -16,24 +19,11 @@ describe('
', () => {
}
};
- beforeEach(() => {
- network = {};
- });
-
afterEach(() => {
jest.clearAllMocks();
});
test('should request related instance groups from api', () => {
- const mockInstanceGroups = [
- { name: 'One', id: 1 },
- { name: 'Two', id: 2 }
- ];
- network.api = {
- getOrganizationInstanceGroups: jest.fn(() => (
- Promise.resolve({ data: { results: mockInstanceGroups } })
- ))
- };
mountWithContexts(
(
', () => {
}
);
- expect(network.api.getOrganizationInstanceGroups).toHaveBeenCalledTimes(1);
+ expect(OrganizationsAPI.readInstanceGroups).toHaveBeenCalledTimes(1);
});
test('componentDidMount should set instanceGroups to state', async () => {
@@ -54,11 +44,11 @@ describe('
', () => {
{ name: 'One', id: 1 },
{ name: 'Two', id: 2 }
];
- network.api = {
- getOrganizationInstanceGroups: jest.fn(() => (
- Promise.resolve({ data: { results: mockInstanceGroups } })
- ))
- };
+ OrganizationsAPI.readInstanceGroups.mockReturnValue({
+ data: {
+ results: mockInstanceGroups
+ }
+ });
const wrapper = mountWithContexts(
(
', () => {
);
await sleep(0);
- expect(network.api.getOrganizationInstanceGroups).toHaveBeenCalled();
+ expect(OrganizationsAPI.readInstanceGroups).toHaveBeenCalled();
expect(wrapper.find('OrganizationForm').state().instanceGroups).toEqual(mockInstanceGroups);
});
@@ -165,20 +155,20 @@ describe('
', () => {
{ name: 'One', id: 1 },
{ name: 'Two', id: 2 }
];
- network.api = {
- getOrganizationInstanceGroups: jest.fn(() => (
- Promise.resolve({ data: { results: mockInstanceGroups } })
- ))
- };
+ OrganizationsAPI.readInstanceGroups.mockReturnValue({
+ data: {
+ results: mockInstanceGroups
+ }
+ });
const mockDataForm = {
name: 'Foo',
description: 'Bar',
custom_virtualenv: 'Fizz',
};
const handleSubmit = jest.fn();
- network.api.updateOrganizationDetails = jest.fn().mockResolvedValue(1, mockDataForm);
- network.api.associateInstanceGroup = jest.fn().mockResolvedValue('done');
- network.api.disassociate = jest.fn().mockResolvedValue('done');
+ OrganizationsAPI.update.mockResolvedValue(1, mockDataForm);
+ OrganizationsAPI.associateInstanceGroup.mockResolvedValue('done');
+ OrganizationsAPI.disassociateInstanceGroup.mockResolvedValue('done');
const wrapper = mountWithContexts(
(
', () => {
const me = {
@@ -12,8 +17,41 @@ describe.only('
', () => {
mountWithContexts(
);
});
- test('notifications tab shown/hidden based on permissions', () => {
- const wrapper = mountWithContexts(
);
+ test('notifications tab shown/hidden based on permissions', async () => {
+ OrganizationsAPI.readDetail.mockResolvedValue({
+ data: {
+ id: 1,
+ name: 'foo'
+ }
+ });
+ OrganizationsAPI.read.mockResolvedValue({
+ data: {
+ results: []
+ }
+ });
+ const history = createMemoryHistory({
+ initialEntries: ['/organizations/1/details'],
+ });
+ const match = { path: '/organizations/:id', url: '/organizations/1' };
+ const wrapper = mountWithContexts(
+
{}}
+ />,
+ {
+ context: {
+ router: {
+ history,
+ route: {
+ location: history.location,
+ match
+ }
+ }
+ }
+ }
+ );
+ await sleep(0);
+ wrapper.update();
expect(wrapper.find('.pf-c-tabs__item').length).toBe(3);
expect(wrapper.find('.pf-c-tabs__button[children="Notifications"]').length).toBe(0);
wrapper.find('Organization').setState({
diff --git a/__tests__/pages/Organizations/screens/Organization/OrganizationAccess.test.jsx b/__tests__/pages/Organizations/screens/Organization/OrganizationAccess.test.jsx
index 9733a88287..64b358c78f 100644
--- a/__tests__/pages/Organizations/screens/Organization/OrganizationAccess.test.jsx
+++ b/__tests__/pages/Organizations/screens/Organization/OrganizationAccess.test.jsx
@@ -3,8 +3,12 @@ import { mountWithContexts } from '../../../../enzymeHelpers';
import OrganizationAccess from '../../../../../src/pages/Organizations/screens/Organization/OrganizationAccess';
import { sleep } from '../../../../testUtils';
+import { OrganizationsAPI, TeamsAPI, UsersAPI } from '../../../../../src/api';
+
+jest.mock('../../../../../src/api');
+
describe(' ', () => {
- let network;
+ const network = {};
const organization = {
id: 1,
name: 'Default',
@@ -60,15 +64,11 @@ describe(' ', () => {
};
beforeEach(() => {
- network = {
- api: {
- getOrganizationAccessList: jest.fn()
- .mockReturnValue(Promise.resolve({ data })),
- disassociateTeamRole: jest.fn(),
- disassociateUserRole: jest.fn(),
- toJSON: () => '/api/',
- },
- };
+ OrganizationsAPI.readAccessList.mockReturnValue({ data });
+ });
+
+ afterEach(() => {
+ jest.clearAllMocks();
});
test('initially renders succesfully', () => {
@@ -86,7 +86,7 @@ describe(' ', () => {
);
await sleep(0);
wrapper.update();
- expect(network.api.getOrganizationAccessList).toHaveBeenCalled();
+ expect(OrganizationsAPI.readAccessList).toHaveBeenCalled();
expect(wrapper.find('OrganizationAccess').state('isInitialized')).toBe(true);
expect(wrapper.find('PaginatedDataList').prop('items')).toEqual(data.results);
expect(wrapper.find('OrganizationAccessItem')).toHaveLength(2);
@@ -127,8 +127,8 @@ describe(' ', () => {
const component = wrapper.find('OrganizationAccess');
expect(component.state('roleToDelete')).toBeNull();
expect(component.state('roleToDeleteAccessRecord')).toBeNull();
- expect(network.api.disassociateTeamRole).not.toHaveBeenCalled();
- expect(network.api.disassociateUserRole).not.toHaveBeenCalled();
+ expect(TeamsAPI.disassociateRole).not.toHaveBeenCalled();
+ expect(UsersAPI.disassociateRole).not.toHaveBeenCalled();
});
it('should delete user role', async () => {
@@ -149,9 +149,9 @@ describe(' ', () => {
const component = wrapper.find('OrganizationAccess');
expect(component.state('roleToDelete')).toBeNull();
expect(component.state('roleToDeleteAccessRecord')).toBeNull();
- expect(network.api.disassociateTeamRole).not.toHaveBeenCalled();
- expect(network.api.disassociateUserRole).toHaveBeenCalledWith(1, 1);
- expect(network.api.getOrganizationAccessList).toHaveBeenCalledTimes(2);
+ expect(TeamsAPI.disassociateRole).not.toHaveBeenCalled();
+ expect(UsersAPI.disassociateRole).toHaveBeenCalledWith(1, 1);
+ expect(OrganizationsAPI.readAccessList).toHaveBeenCalledTimes(2);
});
it('should delete team role', async () => {
@@ -172,8 +172,8 @@ describe(' ', () => {
const component = wrapper.find('OrganizationAccess');
expect(component.state('roleToDelete')).toBeNull();
expect(component.state('roleToDeleteAccessRecord')).toBeNull();
- expect(network.api.disassociateTeamRole).toHaveBeenCalledWith(5, 3);
- expect(network.api.disassociateUserRole).not.toHaveBeenCalled();
- expect(network.api.getOrganizationAccessList).toHaveBeenCalledTimes(2);
+ expect(TeamsAPI.disassociateRole).toHaveBeenCalledWith(5, 3);
+ expect(UsersAPI.disassociateRole).not.toHaveBeenCalled();
+ expect(OrganizationsAPI.readAccessList).toHaveBeenCalledTimes(2);
});
});
diff --git a/__tests__/pages/Organizations/screens/Organization/OrganizationDetail.test.jsx b/__tests__/pages/Organizations/screens/Organization/OrganizationDetail.test.jsx
index b9739a8aa6..a4f70f11da 100644
--- a/__tests__/pages/Organizations/screens/Organization/OrganizationDetail.test.jsx
+++ b/__tests__/pages/Organizations/screens/Organization/OrganizationDetail.test.jsx
@@ -1,6 +1,9 @@
import React from 'react';
import { mountWithContexts } from '../../../../enzymeHelpers';
import OrganizationDetail from '../../../../../src/pages/Organizations/screens/Organization/OrganizationDetail';
+import { OrganizationsAPI } from '../../../../../src/api';
+
+jest.mock('../../../../../src/api');
describe(' ', () => {
const mockDetails = {
@@ -16,6 +19,10 @@ describe(' ', () => {
}
};
+ afterEach(() => {
+ jest.clearAllMocks();
+ });
+
test('initially renders succesfully', () => {
mountWithContexts(
', () => {
});
test('should request instance groups from api', () => {
- const getOrganizationInstanceGroups = jest.fn();
mountWithContexts(
, { context: {
- network: { api: { getOrganizationInstanceGroups }, handleHttpError: () => {} }
+ network: { handleHttpError: () => {} }
} }
).find('OrganizationDetail');
- expect(getOrganizationInstanceGroups).toHaveBeenCalledTimes(1);
+ expect(OrganizationsAPI.readInstanceGroups).toHaveBeenCalledTimes(1);
});
test('should handle setting instance groups to state', async () => {
@@ -42,18 +48,18 @@ describe(' ', () => {
{ name: 'One', id: 1 },
{ name: 'Two', id: 2 }
];
- const getOrganizationInstanceGroups = jest.fn(() => (
- Promise.resolve({ data: { results: mockInstanceGroups } })
- ));
+ OrganizationsAPI.readInstanceGroups.mockResolvedValue({
+ data: { results: mockInstanceGroups }
+ });
const wrapper = mountWithContexts(
, { context: {
- network: { api: { getOrganizationInstanceGroups }, handleHttpError: () => {} }
+ network: { handleHttpError: () => {} }
} }
).find('OrganizationDetail');
- await getOrganizationInstanceGroups();
+ await OrganizationsAPI.readInstanceGroups();
expect(wrapper.state().instanceGroups).toEqual(mockInstanceGroups);
});
diff --git a/__tests__/pages/Organizations/screens/Organization/OrganizationEdit.test.jsx b/__tests__/pages/Organizations/screens/Organization/OrganizationEdit.test.jsx
index edd8296156..2b2d2eeea8 100644
--- a/__tests__/pages/Organizations/screens/Organization/OrganizationEdit.test.jsx
+++ b/__tests__/pages/Organizations/screens/Organization/OrganizationEdit.test.jsx
@@ -3,6 +3,10 @@ import { mountWithContexts } from '../../../../enzymeHelpers';
import OrganizationEdit from '../../../../../src/pages/Organizations/screens/Organization/OrganizationEdit';
+import { OrganizationsAPI } from '../../../../../src/api';
+
+jest.mock('../../../../../src/api');
+
const sleep = (ms) => new Promise(resolve => setTimeout(resolve, ms));
describe(' ', () => {
@@ -44,10 +48,7 @@ describe(' ', () => {
};
wrapper.find('OrganizationForm').prop('handleSubmit')(updatedOrgData, [], []);
- expect(api.updateOrganizationDetails).toHaveBeenCalledWith(
- 1,
- updatedOrgData
- );
+ expect(OrganizationsAPI.update).toHaveBeenCalledWith(1, updatedOrgData);
});
test('handleSubmit associates and disassociates instance groups', async () => {
@@ -68,18 +69,9 @@ describe(' ', () => {
wrapper.find('OrganizationForm').prop('handleSubmit')(updatedOrgData, [3, 4], [2]);
await sleep(1);
- expect(api.associateInstanceGroup).toHaveBeenCalledWith(
- '/api/v2/organizations/1/instance_groups',
- 3
- );
- expect(api.associateInstanceGroup).toHaveBeenCalledWith(
- '/api/v2/organizations/1/instance_groups',
- 4
- );
- expect(api.disassociate).toHaveBeenCalledWith(
- '/api/v2/organizations/1/instance_groups',
- 2
- );
+ expect(OrganizationsAPI.associateInstanceGroup).toHaveBeenCalledWith(1, 3);
+ expect(OrganizationsAPI.associateInstanceGroup).toHaveBeenCalledWith(1, 4);
+ expect(OrganizationsAPI.disassociateInstanceGroup).toHaveBeenCalledWith(1, 2);
});
test('should navigate to organization detail when cancel is clicked', () => {
diff --git a/__tests__/pages/Organizations/screens/Organization/OrganizationNotifications.test.jsx b/__tests__/pages/Organizations/screens/Organization/OrganizationNotifications.test.jsx
index 766f6c2b6e..bda435749e 100644
--- a/__tests__/pages/Organizations/screens/Organization/OrganizationNotifications.test.jsx
+++ b/__tests__/pages/Organizations/screens/Organization/OrganizationNotifications.test.jsx
@@ -2,10 +2,13 @@ import React from 'react';
import { mountWithContexts } from '../../../../enzymeHelpers';
import OrganizationNotifications from '../../../../../src/pages/Organizations/screens/Organization/OrganizationNotifications';
import { sleep } from '../../../../testUtils';
+import { OrganizationsAPI } from '../../../../../src/api';
+
+jest.mock('../../../../../src/api');
describe(' ', () => {
let data;
- let network;
+ const network = {};
beforeEach(() => {
data = {
@@ -22,23 +25,13 @@ describe(' ', () => {
notification_type: 'email',
}]
};
- network = {
- api: {
- getOrganizationNotifications: jest.fn()
- .mockReturnValue(Promise.resolve({ data })),
- getOrganizationNotificationSuccess: jest.fn()
- .mockReturnValue(Promise.resolve({
- data: { results: [{ id: 1 }] },
- })),
- getOrganizationNotificationError: jest.fn()
- .mockReturnValue(Promise.resolve({
- data: { results: [{ id: 2 }] },
- })),
- createOrganizationNotificationSuccess: jest.fn(),
- createOrganizationNotificationError: jest.fn(),
- toJSON: () => '/api/',
- }
- };
+ OrganizationsAPI.readNotificationTemplates.mockReturnValue({ data });
+ OrganizationsAPI.readNotificationTemplatesSuccess.mockReturnValue({
+ data: { results: [{ id: 1 }] },
+ });
+ OrganizationsAPI.readNotificationTemplatesError.mockReturnValue({
+ data: { results: [{ id: 2 }] },
+ });
});
afterEach(() => {
@@ -65,7 +58,7 @@ describe(' ', () => {
await sleep(0);
wrapper.update();
- expect(network.api.getOrganizationNotifications).toHaveBeenCalled();
+ expect(OrganizationsAPI.readNotificationTemplates).toHaveBeenCalled();
expect(wrapper.find('OrganizationNotifications').state('notifications'))
.toEqual(data.results);
const items = wrapper.find('NotificationListItem');
@@ -91,7 +84,7 @@ describe(' ', () => {
).toEqual([1]);
const items = wrapper.find('NotificationListItem');
items.at(1).find('Switch').at(0).prop('onChange')();
- expect(network.api.createOrganizationNotificationSuccess).toHaveBeenCalled();
+ expect(OrganizationsAPI.associateNotificationTemplatesSuccess).toHaveBeenCalled();
await sleep(0);
wrapper.update();
expect(
@@ -114,7 +107,7 @@ describe(' ', () => {
).toEqual([2]);
const items = wrapper.find('NotificationListItem');
items.at(0).find('Switch').at(1).prop('onChange')();
- expect(network.api.createOrganizationNotificationError).toHaveBeenCalled();
+ expect(OrganizationsAPI.associateNotificationTemplatesError).toHaveBeenCalled();
await sleep(0);
wrapper.update();
expect(
@@ -137,7 +130,7 @@ describe(' ', () => {
).toEqual([1]);
const items = wrapper.find('NotificationListItem');
items.at(0).find('Switch').at(0).prop('onChange')();
- expect(network.api.createOrganizationNotificationSuccess).toHaveBeenCalled();
+ expect(OrganizationsAPI.disassociateNotificationTemplatesSuccess).toHaveBeenCalled();
await sleep(0);
wrapper.update();
expect(
@@ -160,7 +153,7 @@ describe(' ', () => {
).toEqual([2]);
const items = wrapper.find('NotificationListItem');
items.at(1).find('Switch').at(1).prop('onChange')();
- expect(network.api.createOrganizationNotificationError).toHaveBeenCalled();
+ expect(OrganizationsAPI.disassociateNotificationTemplatesError).toHaveBeenCalled();
await sleep(0);
wrapper.update();
expect(
diff --git a/__tests__/pages/Organizations/screens/Organization/OrganizationTeams.test.jsx b/__tests__/pages/Organizations/screens/Organization/OrganizationTeams.test.jsx
index 7c07d21096..3f4321009d 100644
--- a/__tests__/pages/Organizations/screens/Organization/OrganizationTeams.test.jsx
+++ b/__tests__/pages/Organizations/screens/Organization/OrganizationTeams.test.jsx
@@ -3,6 +3,9 @@ import { shallow } from 'enzyme';
import { mountWithContexts } from '../../../../enzymeHelpers';
import { sleep } from '../../../../testUtils';
import OrganizationTeams, { _OrganizationTeams } from '../../../../../src/pages/Organizations/screens/Organization/OrganizationTeams';
+import { OrganizationsAPI } from '../../../../../src/api';
+
+jest.mock('../../../../../src/api');
const listData = {
data: {
@@ -17,6 +20,14 @@ const listData = {
}
};
+beforeEach(() => {
+ OrganizationsAPI.readTeams.mockResolvedValue(listData);
+});
+
+afterEach(() => {
+ jest.clearAllMocks();
+});
+
describe(' ', () => {
test('renders succesfully', () => {
shallow(
@@ -24,25 +35,21 @@ describe(' ', () => {
id={1}
searchString=""
location={{ search: '', pathname: '/organizations/1/teams' }}
- api={{
- readOrganizationTeamsList: jest.fn(),
- }}
handleHttpError={() => {}}
/>
);
});
test('should load teams on mount', () => {
- const readOrganizationTeamsList = jest.fn(() => Promise.resolve(listData));
mountWithContexts(
, { context: {
- network: { api: { readOrganizationTeamsList }, handleHttpError: () => {} } }
+ network: {} }
}
).find('OrganizationTeams');
- expect(readOrganizationTeamsList).toHaveBeenCalledWith(1, {
+ expect(OrganizationsAPI.readTeams).toHaveBeenCalledWith(1, {
page: 1,
page_size: 5,
order_by: 'name',
@@ -50,13 +57,12 @@ describe(' ', () => {
});
test('should pass fetched teams to PaginatedDatalist', async () => {
- const readOrganizationTeamsList = jest.fn(() => Promise.resolve(listData));
const wrapper = mountWithContexts(
, { context: {
- network: { api: { readOrganizationTeamsList }, handleHttpError: () => {} } }
+ network: { handleHttpError: () => {} } }
}
);
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 e03c838e8d..f520ba2c1e 100644
--- a/__tests__/pages/Organizations/screens/Organization/__snapshots__/OrganizationAccess.test.jsx.snap
+++ b/__tests__/pages/Organizations/screens/Organization/__snapshots__/OrganizationAccess.test.jsx.snap
@@ -2,7 +2,6 @@
exports[` initially renders succesfully 1`] = `
initially renders succesfully 1`] = `
initially renders succesfully 1`] = `
value={"/config/"}
>
initially renders succesfully 1`] = `
id={1}
>
new Promise(resolve => setTimeout(resolve, ms));
describe(' ', () => {
- let api;
let networkProviderValue;
beforeEach(() => {
- api = {
- getInstanceGroups: jest.fn(),
- createOrganization: jest.fn(),
- associateInstanceGroup: jest.fn(),
- disassociate: jest.fn(),
- };
-
networkProviderValue = {
- api,
handleHttpError: () => {}
};
});
@@ -34,7 +28,7 @@ describe(' ', () => {
custom_virtualenv: 'Buzz',
};
wrapper.find('OrganizationForm').prop('handleSubmit')(updatedOrgData, [], []);
- expect(api.createOrganization).toHaveBeenCalledWith(updatedOrgData);
+ expect(OrganizationsAPI.create).toHaveBeenCalledWith(updatedOrgData);
});
test('should navigate to organizations list when cancel is clicked', () => {
@@ -70,7 +64,7 @@ describe(' ', () => {
description: 'new description',
custom_virtualenv: 'Buzz',
};
- api.createOrganization.mockReturnValueOnce({
+ OrganizationsAPI.create.mockReturnValueOnce({
data: {
id: 5,
related: {
@@ -96,7 +90,7 @@ describe(' ', () => {
description: 'new description',
custom_virtualenv: 'Buzz',
};
- api.createOrganization.mockReturnValueOnce({
+ OrganizationsAPI.create.mockReturnValueOnce({
data: {
id: 5,
related: {
@@ -107,8 +101,8 @@ describe(' ', () => {
});
wrapper.find('OrganizationForm').prop('handleSubmit')(orgData, [3], []);
await sleep(0);
- expect(api.associateInstanceGroup)
- .toHaveBeenCalledWith('/api/v2/organizations/5/instance_groups', 3);
+ expect(OrganizationsAPI.associateInstanceGroup)
+ .toHaveBeenCalledWith(5, 3);
});
test('AnsibleSelect component renders if there are virtual environments', () => {
diff --git a/__tests__/pages/Organizations/screens/OrganizationsList.test.jsx b/__tests__/pages/Organizations/screens/OrganizationsList.test.jsx
index cd59efb01a..c3e38f3a30 100644
--- a/__tests__/pages/Organizations/screens/OrganizationsList.test.jsx
+++ b/__tests__/pages/Organizations/screens/OrganizationsList.test.jsx
@@ -2,6 +2,9 @@ import React from 'react';
import { createMemoryHistory } from 'history';
import { mountWithContexts } from '../../../enzymeHelpers';
import OrganizationsList, { _OrganizationsList } from '../../../../src/pages/Organizations/screens/OrganizationsList';
+import { OrganizationsAPI } from '../../../../src/api';
+
+jest.mock('../../../../src/api');
const mockAPIOrgsList = {
data: {
@@ -124,7 +127,7 @@ describe(' ', () => {
selected: mockAPIOrgsList.data.results
});
wrapper.find('ToolbarDeleteButton').prop('onDelete')();
- expect(api.destroyOrganization).toHaveBeenCalledTimes(component.state('selected').length);
+ expect(OrganizationsAPI.destroy).toHaveBeenCalledTimes(component.state('selected').length);
});
test('call fetchOrganizations after org(s) have been deleted', () => {
diff --git a/src/App.jsx b/src/App.jsx
index 60d1e7900f..0d63d35ad0 100644
--- a/src/App.jsx
+++ b/src/App.jsx
@@ -15,6 +15,7 @@ import styled from 'styled-components';
import { RootDialog } from './contexts/RootDialog';
import { withNetwork } from './contexts/Network';
import { Config } from './contexts/Config';
+import { RootAPI } from './api';
import AlertModal from './components/AlertModal';
import About from './components/About';
@@ -56,9 +57,9 @@ class App extends Component {
}
async onLogout () {
- const { api, handleHttpError } = this.props;
+ const { handleHttpError } = this.props;
try {
- await api.logout();
+ await RootAPI.logout();
window.location.replace('/#/login');
} catch (err) {
handleHttpError(err);
diff --git a/src/api.js b/src/api.js
deleted file mode 100644
index ac8af86208..0000000000
--- a/src/api.js
+++ /dev/null
@@ -1,182 +0,0 @@
-const API_ROOT = '/api/';
-const API_LOGIN = `${API_ROOT}login/`;
-const API_LOGOUT = `${API_ROOT}logout/`;
-const API_V2 = `${API_ROOT}v2/`;
-const API_CONFIG = `${API_V2}config/`;
-const API_ME = `${API_V2}me/`;
-const API_ORGANIZATIONS = `${API_V2}organizations/`;
-const API_INSTANCE_GROUPS = `${API_V2}instance_groups/`;
-const API_USERS = `${API_V2}users/`;
-const API_TEAMS = `${API_V2}teams/`;
-
-const LOGIN_CONTENT_TYPE = 'application/x-www-form-urlencoded';
-
-class APIClient {
- static getCookie () {
- return document.cookie;
- }
-
- constructor (httpAdapter) {
- this.http = httpAdapter;
- }
-
- isAuthenticated () {
- const cookie = this.constructor.getCookie();
- const parsed = (`; ${cookie}`).split('; userLoggedIn=');
-
- let authenticated = false;
-
- if (parsed.length === 2) {
- authenticated = parsed.pop().split(';').shift() === 'true';
- }
-
- return authenticated;
- }
-
- async login (username, password, redirect = API_CONFIG) {
- const un = encodeURIComponent(username);
- const pw = encodeURIComponent(password);
- const next = encodeURIComponent(redirect);
-
- const data = `username=${un}&password=${pw}&next=${next}`;
- const headers = { 'Content-Type': LOGIN_CONTENT_TYPE };
-
- await this.http.get(API_LOGIN, { headers });
- const response = await this.http.post(API_LOGIN, data, { headers });
-
- return response;
- }
-
- logout () {
- return this.http.get(API_LOGOUT);
- }
-
- getRoot () {
- return this.http.get(API_ROOT);
- }
-
- getConfig () {
- return this.http.get(API_CONFIG);
- }
-
- getMe () {
- return this.http.get(API_ME);
- }
-
- destroyOrganization (id) {
- const endpoint = `${API_ORGANIZATIONS}${id}/`;
- return (this.http.delete(endpoint));
- }
-
- getOrganizations (params = {}) {
- return this.http.get(API_ORGANIZATIONS, { params });
- }
-
- createOrganization (data) {
- return this.http.post(API_ORGANIZATIONS, data);
- }
-
- optionsOrganizations () {
- return this.http.options(API_ORGANIZATIONS);
- }
-
- getOrganizationAccessList (id, params = {}) {
- const endpoint = `${API_ORGANIZATIONS}${id}/access_list/`;
-
- return this.http.get(endpoint, { params });
- }
-
- readOrganizationTeamsList (id, params = {}) {
- const endpoint = `${API_ORGANIZATIONS}${id}/teams/`;
-
- return this.http.get(endpoint, { params });
- }
-
- getOrganizationDetails (id) {
- const endpoint = `${API_ORGANIZATIONS}${id}/`;
-
- return this.http.get(endpoint);
- }
-
- updateOrganizationDetails (id, data) {
- const endpoint = `${API_ORGANIZATIONS}${id}/`;
-
- return this.http.patch(endpoint, data);
- }
-
- getOrganizationInstanceGroups (id, params = {}) {
- const endpoint = `${API_ORGANIZATIONS}${id}/instance_groups/`;
-
- return this.http.get(endpoint, { params });
- }
-
- getOrganizationNotifications (id, params = {}) {
- const endpoint = `${API_ORGANIZATIONS}${id}/notification_templates/`;
-
- return this.http.get(endpoint, { params });
- }
-
- getOrganizationNotificationSuccess (id, params = {}) {
- const endpoint = `${API_ORGANIZATIONS}${id}/notification_templates_success/`;
-
- return this.http.get(endpoint, { params });
- }
-
- getOrganizationNotificationError (id, params = {}) {
- const endpoint = `${API_ORGANIZATIONS}${id}/notification_templates_error/`;
-
- return this.http.get(endpoint, { params });
- }
-
- createOrganizationNotificationSuccess (id, data) {
- const endpoint = `${API_ORGANIZATIONS}${id}/notification_templates_success/`;
-
- return this.http.post(endpoint, data);
- }
-
- createOrganizationNotificationError (id, data) {
- const endpoint = `${API_ORGANIZATIONS}${id}/notification_templates_error/`;
-
- return this.http.post(endpoint, data);
- }
-
- getInstanceGroups (params) {
- return this.http.get(API_INSTANCE_GROUPS, { params });
- }
-
- associateInstanceGroup (url, id) {
- return this.http.post(url, { id });
- }
-
- disassociateTeamRole (teamId, roleId) {
- const url = `/api/v2/teams/${teamId}/roles/`;
- return this.disassociate(url, roleId);
- }
-
- disassociateUserRole (accessRecordId, roleId) {
- const url = `/api/v2/users/${accessRecordId}/roles/`;
- return this.disassociate(url, roleId);
- }
-
- disassociate (url, id) {
- return this.http.post(url, { id, disassociate: true });
- }
-
- readUsers (params) {
- return this.http.get(API_USERS, { params });
- }
-
- readTeams (params) {
- return this.http.get(API_TEAMS, { params });
- }
-
- createUserRole (userId, roleId) {
- return this.http.post(`${API_USERS}${userId}/roles/`, { id: roleId });
- }
-
- createTeamRole (teamId, roleId) {
- return this.http.post(`${API_TEAMS}${teamId}/roles/`, { id: roleId });
- }
-}
-
-export default APIClient;
diff --git a/src/api/Base.js b/src/api/Base.js
new file mode 100644
index 0000000000..bc26bc0657
--- /dev/null
+++ b/src/api/Base.js
@@ -0,0 +1,43 @@
+import axios from 'axios';
+
+const defaultHttp = axios.create({
+ xsrfCookieName: 'csrftoken',
+ xsrfHeaderName: 'X-CSRFToken'
+});
+
+class Base {
+ constructor (http = defaultHttp, baseURL) {
+ this.http = http;
+ this.baseUrl = baseURL;
+ }
+
+ create (data) {
+ return this.http.post(this.baseUrl, data);
+ }
+
+ destroy (id) {
+ return this.http.delete(`${this.baseUrl}${id}/`);
+ }
+
+ read (params = {}) {
+ return this.http.get(this.baseUrl, { params });
+ }
+
+ readDetail (id) {
+ return this.http.get(`${this.baseUrl}${id}/`);
+ }
+
+ readOptions () {
+ return this.http.options(this.baseUrl);
+ }
+
+ replace (id, data) {
+ return this.http.put(`${this.baseUrl}${id}/`, data);
+ }
+
+ update (id, data) {
+ return this.http.patch(`${this.baseUrl}${id}/`, data);
+ }
+}
+
+export default Base;
diff --git a/src/api/index.js b/src/api/index.js
new file mode 100644
index 0000000000..b908cf17d7
--- /dev/null
+++ b/src/api/index.js
@@ -0,0 +1,25 @@
+import Config from './models/Config';
+import InstanceGroups from './models/InstanceGroups';
+import Me from './models/Me';
+import Organizations from './models/Organizations';
+import Root from './models/Root';
+import Teams from './models/Teams';
+import Users from './models/Users';
+
+const ConfigAPI = new Config();
+const InstanceGroupsAPI = new InstanceGroups();
+const MeAPI = new Me();
+const OrganizationsAPI = new Organizations();
+const RootAPI = new Root();
+const TeamsAPI = new Teams();
+const UsersAPI = new Users();
+
+export {
+ ConfigAPI,
+ InstanceGroupsAPI,
+ MeAPI,
+ OrganizationsAPI,
+ RootAPI,
+ TeamsAPI,
+ UsersAPI
+};
diff --git a/src/api/mixins/InstanceGroups.mixin.js b/src/api/mixins/InstanceGroups.mixin.js
new file mode 100644
index 0000000000..2317fb9270
--- /dev/null
+++ b/src/api/mixins/InstanceGroups.mixin.js
@@ -0,0 +1,15 @@
+const InstanceGroupsMixin = (parent) => class extends parent {
+ readInstanceGroups (resourceId, params = {}) {
+ return this.http.get(`${this.baseUrl}${resourceId}/instance_groups/`, { params });
+ }
+
+ associateInstanceGroup (resourceId, instanceGroupId) {
+ return this.http.post(`${this.baseUrl}${resourceId}/instance_groups/`, { id: instanceGroupId });
+ }
+
+ disassociateInstanceGroup (resourceId, instanceGroupId) {
+ return this.http.post(`${this.baseUrl}${resourceId}/instance_groups/`, { id: instanceGroupId, disassociate: true });
+ }
+};
+
+export default InstanceGroupsMixin;
diff --git a/src/api/mixins/Notifications.mixin.js b/src/api/mixins/Notifications.mixin.js
new file mode 100644
index 0000000000..4672b9989b
--- /dev/null
+++ b/src/api/mixins/Notifications.mixin.js
@@ -0,0 +1,31 @@
+const NotificationsMixin = (parent) => class extends parent {
+ readNotificationTemplates (id, params = {}) {
+ return this.http.get(`${this.baseUrl}${id}/notification_templates/`, { params });
+ }
+
+ readNotificationTemplatesSuccess (id, params = {}) {
+ return this.http.get(`${this.baseUrl}${id}/notification_templates_success/`, { params });
+ }
+
+ readNotificationTemplatesError (id, params = {}) {
+ return this.http.get(`${this.baseUrl}${id}/notification_templates_error/`, { params });
+ }
+
+ associateNotificationTemplatesSuccess (resourceId, notificationId) {
+ return this.http.post(`${this.baseUrl}${resourceId}/notification_templates_success/`, { id: notificationId });
+ }
+
+ disassociateNotificationTemplatesSuccess (resourceId, notificationId) {
+ return this.http.post(`${this.baseUrl}${resourceId}/notification_templates_success/`, { id: notificationId, disassociate: true });
+ }
+
+ associateNotificationTemplatesError (resourceId, notificationId) {
+ return this.http.post(`${this.baseUrl}${resourceId}/notification_templates_error/`, { id: notificationId });
+ }
+
+ disassociateNotificationTemplatesError (resourceId, notificationId) {
+ return this.http.post(`${this.baseUrl}${resourceId}/notification_templates_error/`, { id: notificationId, disassociate: true });
+ }
+};
+
+export default NotificationsMixin;
diff --git a/src/api/models/Config.js b/src/api/models/Config.js
new file mode 100644
index 0000000000..a944f4b994
--- /dev/null
+++ b/src/api/models/Config.js
@@ -0,0 +1,10 @@
+import Base from '../Base';
+
+class Config extends Base {
+ constructor (http) {
+ super(http);
+ this.baseUrl = '/api/v2/config/';
+ }
+}
+
+export default Config;
diff --git a/src/api/models/InstanceGroups.js b/src/api/models/InstanceGroups.js
new file mode 100644
index 0000000000..7eaad069e3
--- /dev/null
+++ b/src/api/models/InstanceGroups.js
@@ -0,0 +1,10 @@
+import Base from '../Base';
+
+class InstanceGroups extends Base {
+ constructor (http) {
+ super(http);
+ this.baseUrl = '/api/v2/instance_groups/';
+ }
+}
+
+export default InstanceGroups;
diff --git a/src/api/models/Me.js b/src/api/models/Me.js
new file mode 100644
index 0000000000..ca0b336e26
--- /dev/null
+++ b/src/api/models/Me.js
@@ -0,0 +1,10 @@
+import Base from '../Base';
+
+class Me extends Base {
+ constructor (http) {
+ super(http);
+ this.baseUrl = '/api/v2/me/';
+ }
+}
+
+export default Me;
diff --git a/src/api/models/Organizations.js b/src/api/models/Organizations.js
new file mode 100644
index 0000000000..77970ad00c
--- /dev/null
+++ b/src/api/models/Organizations.js
@@ -0,0 +1,20 @@
+import Base from '../Base';
+import NotificationsMixin from '../mixins/Notifications.mixin';
+import InstanceGroupsMixin from '../mixins/InstanceGroups.mixin';
+
+class Organizations extends InstanceGroupsMixin(NotificationsMixin(Base)) {
+ constructor (http) {
+ super(http);
+ this.baseUrl = '/api/v2/organizations/';
+ }
+
+ readAccessList (id, params = {}) {
+ return this.http.get(`${this.baseUrl}${id}/access_list/`, { params });
+ }
+
+ readTeams (id, params = {}) {
+ return this.http.get(`${this.baseUrl}${id}/teams/`, { params });
+ }
+}
+
+export default Organizations;
diff --git a/src/api/models/Root.js b/src/api/models/Root.js
new file mode 100644
index 0000000000..6e2bd0cfd9
--- /dev/null
+++ b/src/api/models/Root.js
@@ -0,0 +1,30 @@
+import Base from '../Base';
+
+class Root extends Base {
+ constructor (http) {
+ super(http);
+ this.baseUrl = '/api/';
+ this.redirectURL = '/api/v2/config/';
+ }
+
+ async login (username, password, redirect = this.redirectURL) {
+ const loginUrl = `${this.baseUrl}login/`;
+ const un = encodeURIComponent(username);
+ const pw = encodeURIComponent(password);
+ const next = encodeURIComponent(redirect);
+
+ const data = `username=${un}&password=${pw}&next=${next}`;
+ const headers = { 'Content-Type': 'application/x-www-form-urlencoded' };
+
+ await this.http.get(loginUrl, { headers });
+ const response = await this.http.post(loginUrl, data, { headers });
+
+ return response;
+ }
+
+ logout () {
+ return this.http.get(`${this.baseUrl}logout/`);
+ }
+}
+
+export default Root;
diff --git a/src/api/models/Teams.js b/src/api/models/Teams.js
new file mode 100644
index 0000000000..fb373bb3bc
--- /dev/null
+++ b/src/api/models/Teams.js
@@ -0,0 +1,18 @@
+import Base from '../Base';
+
+class Teams extends Base {
+ constructor (http) {
+ super(http);
+ this.baseUrl = '/api/v2/teams/';
+ }
+
+ associateRole (teamId, roleId) {
+ return this.http.post(`${this.baseUrl}${teamId}/roles/`, { id: roleId });
+ }
+
+ disassociateRole (teamId, roleId) {
+ return this.http.post(`${this.baseUrl}${teamId}/roles/`, { id: roleId, disassociate: true });
+ }
+}
+
+export default Teams;
diff --git a/src/api/models/Users.js b/src/api/models/Users.js
new file mode 100644
index 0000000000..d386e2333c
--- /dev/null
+++ b/src/api/models/Users.js
@@ -0,0 +1,18 @@
+import Base from '../Base';
+
+class Users extends Base {
+ constructor (http) {
+ super(http);
+ this.baseUrl = '/api/v2/users/';
+ }
+
+ associateRole (userId, roleId) {
+ return this.http.post(`${this.baseUrl}${userId}/roles/`, { id: roleId });
+ }
+
+ disassociateRole (userId, roleId) {
+ return this.http.post(`${this.baseUrl}${userId}/roles/`, { id: roleId, disassociate: true });
+ }
+}
+
+export default Users;
diff --git a/src/components/AddRole/AddResourceRole.jsx b/src/components/AddRole/AddResourceRole.jsx
index 13039bde15..a282521750 100644
--- a/src/components/AddRole/AddResourceRole.jsx
+++ b/src/components/AddRole/AddResourceRole.jsx
@@ -7,6 +7,13 @@ import { withNetwork } from '../../contexts/Network';
import SelectResourceStep from './SelectResourceStep';
import SelectRoleStep from './SelectRoleStep';
import SelectableCard from './SelectableCard';
+import { TeamsAPI, UsersAPI } from '../../api';
+
+const readUsers = async (queryParams) => UsersAPI.read(
+ Object.assign(queryParams, { is_superuser: false })
+);
+
+const readTeams = async (queryParams) => TeamsAPI.read(queryParams);
class AddResourceRole extends React.Component {
constructor (props) {
@@ -24,8 +31,6 @@ class AddResourceRole extends React.Component {
this.handleRoleCheckboxClick = this.handleRoleCheckboxClick.bind(this);
this.handleWizardNext = this.handleWizardNext.bind(this);
this.handleWizardSave = this.handleWizardSave.bind(this);
- this.readTeams = this.readTeams.bind(this);
- this.readUsers = this.readUsers.bind(this);
}
handleResourceCheckboxClick (user) {
@@ -76,8 +81,7 @@ class AddResourceRole extends React.Component {
async handleWizardSave () {
const {
- onSave,
- api
+ onSave
} = this.props;
const {
selectedResourceRows,
@@ -92,11 +96,11 @@ class AddResourceRole extends React.Component {
for (let j = 0; j < selectedRoleRows.length; j++) {
if (selectedResource === 'users') {
roleRequests.push(
- api.createUserRole(selectedResourceRows[i].id, selectedRoleRows[j].id)
+ UsersAPI.associateRole(selectedResourceRows[i].id, selectedRoleRows[j].id)
);
} else if (selectedResource === 'teams') {
roleRequests.push(
- api.createTeamRole(selectedResourceRows[i].id, selectedRoleRows[j].id)
+ TeamsAPI.associateRole(selectedResourceRows[i].id, selectedRoleRows[j].id)
);
}
}
@@ -109,16 +113,6 @@ class AddResourceRole extends React.Component {
}
}
- async readUsers (queryParams) {
- const { api } = this.props;
- return api.readUsers(Object.assign(queryParams, { is_superuser: false }));
- }
-
- async readTeams (queryParams) {
- const { api } = this.props;
- return api.readTeams(queryParams);
- }
-
render () {
const {
selectedResource,
@@ -183,7 +177,7 @@ class AddResourceRole extends React.Component {
columns={userColumns}
displayKey="username"
onRowClick={this.handleResourceCheckboxClick}
- onSearch={this.readUsers}
+ onSearch={readUsers}
selectedLabel={i18n._(t`Selected`)}
selectedResourceRows={selectedResourceRows}
sortedColumnKey="username"
@@ -194,7 +188,7 @@ class AddResourceRole extends React.Component {
({
value: {
...prevState.value,
@@ -75,13 +77,13 @@ class Provider extends Component {
}
async fetchConfig () {
- const { api, handleHttpError } = this.props;
+ const { handleHttpError } = this.props;
try {
const [configRes, rootRes, meRes] = await Promise.all([
- api.getConfig(),
- api.getRoot(),
- api.getMe()
+ ConfigAPI.read(),
+ RootAPI.read(),
+ MeAPI.read()
]);
this.setState({
value: {
diff --git a/src/contexts/Network.jsx b/src/contexts/Network.jsx
index 0ee2106bf7..84628aba5e 100644
--- a/src/contexts/Network.jsx
+++ b/src/contexts/Network.jsx
@@ -1,5 +1,4 @@
-import axios from 'axios';
import React, { Component } from 'react';
import { withRouter } from 'react-router-dom';
@@ -9,8 +8,6 @@ import { t } from '@lingui/macro';
import { withRootDialog } from './RootDialog';
-import APIClient from '../api';
-
const NetworkContext = React.createContext({});
class Provider extends Component {
@@ -19,7 +16,6 @@ class Provider extends Component {
this.state = {
value: {
- api: new APIClient(axios.create({ xsrfCookieName: 'csrftoken', xsrfHeaderName: 'X-CSRFToken' })),
handleHttpError: err => {
if (err.response.status === 401) {
this.handle401();
diff --git a/src/pages/Login.jsx b/src/pages/Login.jsx
index 50b58765ae..b2c5f0bc57 100644
--- a/src/pages/Login.jsx
+++ b/src/pages/Login.jsx
@@ -9,6 +9,7 @@ import {
import { withRootDialog } from '../contexts/RootDialog';
import { withNetwork } from '../contexts/Network';
+import { RootAPI } from '../api';
import towerLogo from '../../images/tower-logo-header.svg';
@@ -39,7 +40,7 @@ class AWXLogin extends Component {
async onLoginButtonClick (event) {
const { username, password, isLoading } = this.state;
- const { api, handleHttpError, clearRootDialogMessage, fetchMe, updateConfig } = this.props;
+ const { handleHttpError, clearRootDialogMessage, fetchMe, updateConfig } = this.props;
event.preventDefault();
@@ -51,7 +52,7 @@ class AWXLogin extends Component {
this.setState({ isLoading: true });
try {
- const { data } = await api.login(username, password);
+ const { data } = await RootAPI.login(username, password);
updateConfig(data);
await fetchMe();
this.setState({ isAuthenticated: true, isLoading: false });
diff --git a/src/pages/Organizations/components/InstanceGroupsLookup.jsx b/src/pages/Organizations/components/InstanceGroupsLookup.jsx
index e93f93ebf5..89a8f82fc7 100644
--- a/src/pages/Organizations/components/InstanceGroupsLookup.jsx
+++ b/src/pages/Organizations/components/InstanceGroupsLookup.jsx
@@ -9,19 +9,11 @@ import Lookup from '../../../components/Lookup';
import { withNetwork } from '../../../contexts/Network';
+import { InstanceGroupsAPI } from '../../../api';
+
+const getInstanceGroups = async (params) => InstanceGroupsAPI.read(params);
+
class InstanceGroupsLookup extends React.Component {
- constructor (props) {
- super(props);
-
- this.getInstanceGroups = this.getInstanceGroups.bind(this);
- }
-
- async getInstanceGroups (params) {
- const { api } = this.props;
- const data = await api.getInstanceGroups(params);
- return data;
- }
-
render () {
const { value, tooltip, onChange, i18n } = this.props;
@@ -51,7 +43,7 @@ class InstanceGroupsLookup extends React.Component {
name="instanceGroups"
value={value}
onLookupSave={onChange}
- getItems={this.getInstanceGroups}
+ getItems={getInstanceGroups}
columns={[
{ name: i18n._(t`Name`), key: 'name', isSortable: true },
{ name: i18n._(t`Modified`), key: 'modified', isSortable: false, isNumeric: true },
diff --git a/src/pages/Organizations/components/OrganizationForm.jsx b/src/pages/Organizations/components/OrganizationForm.jsx
index fcf0ec8809..c848b34e61 100644
--- a/src/pages/Organizations/components/OrganizationForm.jsx
+++ b/src/pages/Organizations/components/OrganizationForm.jsx
@@ -17,6 +17,7 @@ import FormActionGroup from '../../../components/FormActionGroup/FormActionGroup
import AnsibleSelect from '../../../components/AnsibleSelect';
import InstanceGroupsLookup from './InstanceGroupsLookup';
import { required } from '../../../util/validators';
+import { OrganizationsAPI } from '../../../api';
class OrganizationForm extends Component {
constructor (props) {
@@ -52,10 +53,9 @@ class OrganizationForm extends Component {
async getRelatedInstanceGroups () {
const {
- api,
organization: { id }
} = this.props;
- const { data } = await api.getOrganizationInstanceGroups(id);
+ const { data } = await OrganizationsAPI.readInstanceGroups(id);
return data.results;
}
diff --git a/src/pages/Organizations/screens/Organization/Organization.jsx b/src/pages/Organizations/screens/Organization/Organization.jsx
index 2fd96b673d..931736b3d5 100644
--- a/src/pages/Organizations/screens/Organization/Organization.jsx
+++ b/src/pages/Organizations/screens/Organization/Organization.jsx
@@ -12,6 +12,7 @@ import OrganizationEdit from './OrganizationEdit';
import OrganizationNotifications from './OrganizationNotifications';
import OrganizationTeams from './OrganizationTeams';
import RoutedTabs from '../../../../components/Tabs/RoutedTabs';
+import { OrganizationsAPI } from '../../../../api';
class Organization extends Component {
constructor (props) {
@@ -45,22 +46,21 @@ class Organization extends Component {
const {
match,
setBreadcrumb,
- api,
handleHttpError
} = this.props;
try {
const [{ data }, notifAdminRest, auditorRes, adminRes] = await Promise.all([
- api.getOrganizationDetails(parseInt(match.params.id, 10)),
- api.getOrganizations({
+ OrganizationsAPI.readDetail(parseInt(match.params.id, 10)),
+ OrganizationsAPI.read({
role_level: 'notification_admin_role',
page_size: 1
}),
- api.getOrganizations({
+ OrganizationsAPI.read({
role_level: 'auditor_role',
id: parseInt(match.params.id, 10)
}),
- api.getOrganizations({
+ OrganizationsAPI.read({
role_level: 'admin_role',
id: parseInt(match.params.id, 10)
})
@@ -82,12 +82,11 @@ class Organization extends Component {
const {
match,
setBreadcrumb,
- api,
handleHttpError
} = this.props;
try {
- const { data } = await api.getOrganizationDetails(parseInt(match.params.id, 10));
+ const { data } = await OrganizationsAPI.readDetail(parseInt(match.params.id, 10));
setBreadcrumb(data);
this.setState({ organization: data, loading: false });
} catch (error) {
diff --git a/src/pages/Organizations/screens/Organization/OrganizationAccess.jsx b/src/pages/Organizations/screens/Organization/OrganizationAccess.jsx
index d4465b3a99..2e654d347f 100644
--- a/src/pages/Organizations/screens/Organization/OrganizationAccess.jsx
+++ b/src/pages/Organizations/screens/Organization/OrganizationAccess.jsx
@@ -10,6 +10,7 @@ import AddResourceRole from '../../../../components/AddRole/AddResourceRole';
import { withNetwork } from '../../../../contexts/Network';
import { getQSConfig, parseNamespacedQueryString } from '../../../../util/qs';
import { Organization } from '../../../../types';
+import { OrganizationsAPI, TeamsAPI, UsersAPI } from '../../../../api';
const QS_CONFIG = getQSConfig('access', {
page: 1,
@@ -56,10 +57,10 @@ class OrganizationAccess extends React.Component {
}
async readOrgAccessList () {
- const { organization, api, handleHttpError, location } = this.props;
+ const { organization, handleHttpError, location } = this.props;
this.setState({ isLoading: true });
try {
- const { data } = await api.getOrganizationAccessList(
+ const { data } = await OrganizationsAPI.readAccessList(
organization.id,
parseNamespacedQueryString(QS_CONFIG, location.search)
);
@@ -92,7 +93,7 @@ class OrganizationAccess extends React.Component {
}
async removeRole () {
- const { api, handleHttpError } = this.props;
+ const { handleHttpError } = this.props;
const { roleToDelete: role, roleToDeleteAccessRecord: accessRecord } = this.state;
if (!role || !accessRecord) {
return;
@@ -101,9 +102,9 @@ class OrganizationAccess extends React.Component {
this.setState({ isLoading: true });
try {
if (type === 'teams') {
- await api.disassociateTeamRole(role.team_id, role.id);
+ await TeamsAPI.disassociateRole(role.team_id, role.id);
} else {
- await api.disassociateUserRole(accessRecord.id, role.id);
+ await UsersAPI.disassociateRole(accessRecord.id, role.id);
}
this.setState({
isLoading: false,
diff --git a/src/pages/Organizations/screens/Organization/OrganizationDetail.jsx b/src/pages/Organizations/screens/Organization/OrganizationDetail.jsx
index 811317df80..a0c7b21ba1 100644
--- a/src/pages/Organizations/screens/Organization/OrganizationDetail.jsx
+++ b/src/pages/Organizations/screens/Organization/OrganizationDetail.jsx
@@ -7,6 +7,7 @@ import styled from 'styled-components';
import { DetailList, Detail } from '../../../../components/DetailList';
import { withNetwork } from '../../../../contexts/Network';
import { ChipGroup, Chip } from '../../../../components/Chip';
+import { OrganizationsAPI } from '../../../../api';
const CardBody = styled(PFCardBody)`
padding-top: 20px;
@@ -29,14 +30,13 @@ class OrganizationDetail extends Component {
async loadInstanceGroups () {
const {
- api,
handleHttpError,
match
} = this.props;
try {
const {
data
- } = await api.getOrganizationInstanceGroups(match.params.id);
+ } = await OrganizationsAPI.readInstanceGroups(match.params.id);
this.setState({
instanceGroups: [...data.results]
});
diff --git a/src/pages/Organizations/screens/Organization/OrganizationEdit.jsx b/src/pages/Organizations/screens/Organization/OrganizationEdit.jsx
index 2b5fe68ca1..d4931b8125 100644
--- a/src/pages/Organizations/screens/Organization/OrganizationEdit.jsx
+++ b/src/pages/Organizations/screens/Organization/OrganizationEdit.jsx
@@ -4,6 +4,7 @@ import { withRouter } from 'react-router-dom';
import { CardBody } from '@patternfly/react-core';
import OrganizationForm from '../../components/OrganizationForm';
import { withNetwork } from '../../../../contexts/Network';
+import { OrganizationsAPI } from '../../../../api';
class OrganizationEdit extends Component {
constructor (props) {
@@ -20,9 +21,9 @@ class OrganizationEdit extends Component {
}
async handleSubmit (values, groupsToAssociate, groupsToDisassociate) {
- const { api, organization, handleHttpError } = this.props;
+ const { organization, handleHttpError } = this.props;
try {
- await api.updateOrganizationDetails(organization.id, values);
+ await OrganizationsAPI.update(organization.id, values);
await this.submitInstanceGroups(groupsToAssociate, groupsToDisassociate);
this.handleSuccess();
} catch (err) {
@@ -41,12 +42,17 @@ class OrganizationEdit extends Component {
}
async submitInstanceGroups (groupsToAssociate, groupsToDisassociate) {
- const { api, organization, handleHttpError } = this.props;
- const url = organization.related.instance_groups;
+ const { organization, handleHttpError } = this.props;
try {
- await Promise.all(groupsToAssociate.map(id => api.associateInstanceGroup(url, id)));
- await Promise.all(groupsToDisassociate.map(id => api.disassociate(url, id)));
+ await Promise.all(
+ groupsToAssociate.map(id => OrganizationsAPI.associateInstanceGroup(organization.id, id))
+ );
+ await Promise.all(
+ groupsToDisassociate.map(
+ id => OrganizationsAPI.disassociateInstanceGroup(organization.id, id)
+ )
+ );
} catch (err) {
handleHttpError(err) || this.setState({ error: err });
}
diff --git a/src/pages/Organizations/screens/Organization/OrganizationNotifications.jsx b/src/pages/Organizations/screens/Organization/OrganizationNotifications.jsx
index 59e5b43eb9..6fd667f0d5 100644
--- a/src/pages/Organizations/screens/Organization/OrganizationNotifications.jsx
+++ b/src/pages/Organizations/screens/Organization/OrganizationNotifications.jsx
@@ -5,6 +5,7 @@ import { withNetwork } from '../../../../contexts/Network';
import PaginatedDataList from '../../../../components/PaginatedDataList';
import NotificationListItem from '../../../../components/NotificationsList/NotificationListItem';
import { getQSConfig, parseNamespacedQueryString } from '../../../../util/qs';
+import { OrganizationsAPI } from '../../../../api';
const QS_CONFIG = getQSConfig('notification', {
page: 1,
@@ -49,11 +50,11 @@ class OrganizationNotifications extends Component {
}
async readNotifications () {
- const { id, api, handleHttpError, location } = this.props;
+ const { id, handleHttpError, location } = this.props;
const params = parseNamespacedQueryString(QS_CONFIG, location.search);
this.setState({ isLoading: true });
try {
- const { data } = await api.getOrganizationNotifications(id, params);
+ const { data } = await OrganizationsAPI.readNotificationTemplates(id, params);
this.setState(
{
itemCount: data.count || 0,
@@ -72,21 +73,22 @@ class OrganizationNotifications extends Component {
}
async readSuccessesAndErrors () {
- const { api, handleHttpError, id } = this.props;
+ const { handleHttpError, id } = this.props;
const { notifications } = this.state;
if (!notifications.length) {
return;
}
const ids = notifications.map(n => n.id).join(',');
try {
- const successTemplatesPromise = api.getOrganizationNotificationSuccess(
+ const successTemplatesPromise = OrganizationsAPI.readNotificationTemplatesSuccess(
id,
{ id__in: ids }
);
- const errorTemplatesPromise = api.getOrganizationNotificationError(
+ const errorTemplatesPromise = OrganizationsAPI.readNotificationTemplatesError(
id,
{ id__in: ids }
);
+
const { data: successTemplates } = await successTemplatesPromise;
const { data: errorTemplates } = await errorTemplatesPromise;
@@ -104,53 +106,65 @@ class OrganizationNotifications extends Component {
toggleNotification = (notificationId, isCurrentlyOn, status) => {
if (status === 'success') {
- this.createSuccess(notificationId, isCurrentlyOn);
+ if (isCurrentlyOn) {
+ this.disassociateSuccess(notificationId);
+ } else {
+ this.associateSuccess(notificationId);
+ }
} else if (status === 'error') {
- this.createError(notificationId, isCurrentlyOn);
+ if (isCurrentlyOn) {
+ this.disassociateError(notificationId);
+ } else {
+ this.associateError(notificationId);
+ }
}
};
- async createSuccess (notificationId, isCurrentlyOn) {
- const { id, api, handleHttpError } = this.props;
- const postParams = { id: notificationId };
- if (isCurrentlyOn) {
- postParams.disassociate = true;
- }
+ async associateSuccess (notificationId) {
+ const { id, handleHttpError } = this.props;
try {
- await api.createOrganizationNotificationSuccess(id, postParams);
- if (isCurrentlyOn) {
- this.setState((prevState) => ({
- successTemplateIds: prevState.successTemplateIds
- .filter((templateId) => templateId !== notificationId)
- }));
- } else {
- this.setState(prevState => ({
- successTemplateIds: [...prevState.successTemplateIds, notificationId]
- }));
- }
+ await OrganizationsAPI.associateNotificationTemplatesSuccess(id, notificationId);
+ this.setState(prevState => ({
+ successTemplateIds: [...prevState.successTemplateIds, notificationId]
+ }));
} catch (err) {
handleHttpError(err) || this.setState({ error: true });
}
}
- async createError (notificationId, isCurrentlyOn) {
- const { id, api, handleHttpError } = this.props;
- const postParams = { id: notificationId };
- if (isCurrentlyOn) {
- postParams.disassociate = true;
- }
+ async disassociateSuccess (notificationId) {
+ const { id, handleHttpError } = this.props;
try {
- await api.createOrganizationNotificationError(id, postParams);
- if (isCurrentlyOn) {
- this.setState((prevState) => ({
- errorTemplateIds: prevState.errorTemplateIds
- .filter((templateId) => templateId !== notificationId)
- }));
- } else {
- this.setState(prevState => ({
- errorTemplateIds: [...prevState.errorTemplateIds, notificationId]
- }));
- }
+ await OrganizationsAPI.disassociateNotificationTemplatesSuccess(id, notificationId);
+ this.setState((prevState) => ({
+ successTemplateIds: prevState.successTemplateIds
+ .filter((templateId) => templateId !== notificationId)
+ }));
+ } catch (err) {
+ handleHttpError(err) || this.setState({ error: true });
+ }
+ }
+
+ async associateError (notificationId) {
+ const { id, handleHttpError } = this.props;
+ try {
+ await OrganizationsAPI.associateNotificationTemplatesError(id, notificationId);
+ this.setState(prevState => ({
+ errorTemplateIds: [...prevState.errorTemplateIds, notificationId]
+ }));
+ } catch (err) {
+ handleHttpError(err) || this.setState({ error: true });
+ }
+ }
+
+ async disassociateError (notificationId) {
+ const { id, handleHttpError } = this.props;
+ try {
+ await OrganizationsAPI.disassociateNotificationTemplatesError(id, notificationId);
+ this.setState((prevState) => ({
+ errorTemplateIds: prevState.errorTemplateIds
+ .filter((templateId) => templateId !== notificationId)
+ }));
} catch (err) {
handleHttpError(err) || this.setState({ error: true });
}
@@ -205,13 +219,6 @@ OrganizationNotifications.propTypes = {
id: number.isRequired,
canToggleNotifications: bool.isRequired,
handleHttpError: func.isRequired,
- api: shape({
- getOrganizationNotifications: func.isRequired,
- getOrganizationNotificationSuccess: func.isRequired,
- getOrganizationNotificationError: func.isRequired,
- createOrganizationNotificationSuccess: func.isRequired,
- createOrganizationNotificationError: func.isRequired,
- }).isRequired,
location: shape({
search: string.isRequired,
}).isRequired,
diff --git a/src/pages/Organizations/screens/Organization/OrganizationTeams.jsx b/src/pages/Organizations/screens/Organization/OrganizationTeams.jsx
index e54081b935..5f0cd85e8d 100644
--- a/src/pages/Organizations/screens/Organization/OrganizationTeams.jsx
+++ b/src/pages/Organizations/screens/Organization/OrganizationTeams.jsx
@@ -4,6 +4,7 @@ import { withRouter } from 'react-router-dom';
import PaginatedDataList from '../../../../components/PaginatedDataList';
import { getQSConfig, parseNamespacedQueryString } from '../../../../util/qs';
import { withNetwork } from '../../../../contexts/Network';
+import { OrganizationsAPI } from '../../../../api';
const QS_CONFIG = getQSConfig('team', {
page: 1,
@@ -38,13 +39,13 @@ class OrganizationTeams extends React.Component {
}
async readOrganizationTeamsList () {
- const { id, api, handleHttpError, location } = this.props;
+ const { id, handleHttpError, location } = this.props;
const params = parseNamespacedQueryString(QS_CONFIG, location.search);
this.setState({ isLoading: true, error: null });
try {
const {
data: { count = 0, results = [] },
- } = await api.readOrganizationTeamsList(id, params);
+ } = await OrganizationsAPI.readTeams(id, params);
this.setState({
itemCount: count,
teams: results,
diff --git a/src/pages/Organizations/screens/OrganizationAdd.jsx b/src/pages/Organizations/screens/OrganizationAdd.jsx
index abd652d66d..1b5fd2d355 100644
--- a/src/pages/Organizations/screens/OrganizationAdd.jsx
+++ b/src/pages/Organizations/screens/OrganizationAdd.jsx
@@ -14,6 +14,7 @@ import {
import { withNetwork } from '../../../contexts/Network';
import CardCloseButton from '../../../components/CardCloseButton';
import OrganizationForm from '../components/OrganizationForm';
+import { OrganizationsAPI } from '../../../api';
class OrganizationAdd extends React.Component {
constructor (props) {
@@ -29,13 +30,12 @@ class OrganizationAdd extends React.Component {
}
async handleSubmit (values, groupsToAssociate) {
- const { api, handleHttpError } = this.props;
+ const { handleHttpError } = this.props;
try {
- const { data: response } = await api.createOrganization(values);
- const instanceGroupsUrl = response.related.instance_groups;
+ const { data: response } = await OrganizationsAPI.create(values);
try {
- await Promise.all(groupsToAssociate.map(id => api
- .associateInstanceGroup(instanceGroupsUrl, id)));
+ await Promise.all(groupsToAssociate.map(id => OrganizationsAPI
+ .associateInstanceGroup(response.id, id)));
this.handleSuccess(response.id);
} catch (err) {
handleHttpError(err) || this.setState({ error: err });
@@ -83,10 +83,6 @@ class OrganizationAdd extends React.Component {
}
}
-OrganizationAdd.propTypes = {
- api: PropTypes.shape().isRequired,
-};
-
OrganizationAdd.contextTypes = {
custom_virtualenvs: PropTypes.arrayOf(PropTypes.string)
};
diff --git a/src/pages/Organizations/screens/OrganizationsList.jsx b/src/pages/Organizations/screens/OrganizationsList.jsx
index cbe00f9b51..c8bd1350c1 100644
--- a/src/pages/Organizations/screens/OrganizationsList.jsx
+++ b/src/pages/Organizations/screens/OrganizationsList.jsx
@@ -16,6 +16,7 @@ import PaginatedDataList, {
import DataListToolbar from '../../../components/DataListToolbar';
import OrganizationListItem from '../components/OrganizationListItem';
import { getQSConfig, parseNamespacedQueryString } from '../../../util/qs';
+import { OrganizationsAPI } from '../../../api';
const QS_CONFIG = getQSConfig('organization', {
page: 1,
@@ -73,11 +74,11 @@ class OrganizationsList extends Component {
async handleOrgDelete () {
const { selected } = this.state;
- const { api, handleHttpError } = this.props;
+ const { handleHttpError } = this.props;
let errorHandled;
try {
- await Promise.all(selected.map((org) => api.destroyOrganization(org.id)));
+ await Promise.all(selected.map((org) => OrganizationsAPI.destroy(org.id)));
this.setState({
selected: []
});
@@ -91,13 +92,13 @@ class OrganizationsList extends Component {
}
async fetchOrganizations () {
- const { api, handleHttpError, location } = this.props;
+ const { handleHttpError, location } = this.props;
const params = parseNamespacedQueryString(QS_CONFIG, location.search);
this.setState({ error: false, isLoading: true });
try {
- const { data } = await api.getOrganizations(params);
+ const { data } = await OrganizationsAPI.read(params);
const { count, results } = data;
const stateToUpdate = {
@@ -115,10 +116,8 @@ class OrganizationsList extends Component {
}
async fetchOptionsOrganizations () {
- const { api } = this.props;
-
try {
- const { data } = await api.optionsOrganizations();
+ const { data } = await OrganizationsAPI.readOptions();
const { actions } = data;
const stateToUpdate = {