mirror of
https://github.com/ansible/awx.git
synced 2026-02-15 18:20:00 -03:30
api.js refactor using classes (#250)
Refactor api.js into an api module where endpoint specific models can be imported and used in components.
This commit is contained in:
@@ -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);
|
||||
|
||||
182
src/api.js
182
src/api.js
@@ -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;
|
||||
43
src/api/Base.js
Normal file
43
src/api/Base.js
Normal file
@@ -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;
|
||||
25
src/api/index.js
Normal file
25
src/api/index.js
Normal file
@@ -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
|
||||
};
|
||||
15
src/api/mixins/InstanceGroups.mixin.js
Normal file
15
src/api/mixins/InstanceGroups.mixin.js
Normal file
@@ -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;
|
||||
31
src/api/mixins/Notifications.mixin.js
Normal file
31
src/api/mixins/Notifications.mixin.js
Normal file
@@ -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;
|
||||
10
src/api/models/Config.js
Normal file
10
src/api/models/Config.js
Normal file
@@ -0,0 +1,10 @@
|
||||
import Base from '../Base';
|
||||
|
||||
class Config extends Base {
|
||||
constructor (http) {
|
||||
super(http);
|
||||
this.baseUrl = '/api/v2/config/';
|
||||
}
|
||||
}
|
||||
|
||||
export default Config;
|
||||
10
src/api/models/InstanceGroups.js
Normal file
10
src/api/models/InstanceGroups.js
Normal file
@@ -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;
|
||||
10
src/api/models/Me.js
Normal file
10
src/api/models/Me.js
Normal file
@@ -0,0 +1,10 @@
|
||||
import Base from '../Base';
|
||||
|
||||
class Me extends Base {
|
||||
constructor (http) {
|
||||
super(http);
|
||||
this.baseUrl = '/api/v2/me/';
|
||||
}
|
||||
}
|
||||
|
||||
export default Me;
|
||||
20
src/api/models/Organizations.js
Normal file
20
src/api/models/Organizations.js
Normal file
@@ -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;
|
||||
30
src/api/models/Root.js
Normal file
30
src/api/models/Root.js
Normal file
@@ -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;
|
||||
18
src/api/models/Teams.js
Normal file
18
src/api/models/Teams.js
Normal file
@@ -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;
|
||||
18
src/api/models/Users.js
Normal file
18
src/api/models/Users.js
Normal file
@@ -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;
|
||||
@@ -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 {
|
||||
<SelectResourceStep
|
||||
columns={teamColumns}
|
||||
onRowClick={this.handleResourceCheckboxClick}
|
||||
onSearch={this.readTeams}
|
||||
onSearch={readTeams}
|
||||
selectedLabel={i18n._(t`Selected`)}
|
||||
selectedResourceRows={selectedResourceRows}
|
||||
itemName="team"
|
||||
|
||||
@@ -2,6 +2,8 @@ import React, { Component } from 'react';
|
||||
|
||||
import { withNetwork } from './Network';
|
||||
|
||||
import { ConfigAPI, MeAPI, RootAPI } from '../api';
|
||||
|
||||
const ConfigContext = React.createContext({});
|
||||
|
||||
class Provider extends Component {
|
||||
@@ -46,13 +48,13 @@ class Provider extends Component {
|
||||
};
|
||||
|
||||
async fetchMe () {
|
||||
const { api, handleHttpError } = this.props;
|
||||
const { handleHttpError } = this.props;
|
||||
try {
|
||||
const {
|
||||
data: {
|
||||
results: [me]
|
||||
}
|
||||
} = await api.getMe();
|
||||
} = await MeAPI.read();
|
||||
this.setState(prevState => ({
|
||||
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: {
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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 });
|
||||
|
||||
@@ -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 },
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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]
|
||||
});
|
||||
|
||||
@@ -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 });
|
||||
}
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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)
|
||||
};
|
||||
|
||||
@@ -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 = {
|
||||
|
||||
Reference in New Issue
Block a user