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:
Michael Abashian
2019-06-07 15:48:09 -04:00
committed by GitHub
parent a8c51670af
commit 2ae93261d1
51 changed files with 839 additions and 727 deletions

View File

@@ -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 });

View File

@@ -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 },

View File

@@ -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;
}

View File

@@ -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) {

View File

@@ -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,

View File

@@ -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]
});

View File

@@ -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 });
}

View File

@@ -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,

View File

@@ -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,

View File

@@ -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)
};

View File

@@ -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 = {