mirror of
https://github.com/ansible/awx.git
synced 2026-05-08 01:47:35 -02:30
improves isLoading state and removes unnecessary RBAC
This commit is contained in:
@@ -6,15 +6,10 @@ class InventorySources extends LaunchUpdateMixin(Base) {
|
|||||||
super(http);
|
super(http);
|
||||||
this.baseUrl = '/api/v2/inventory_sources/';
|
this.baseUrl = '/api/v2/inventory_sources/';
|
||||||
|
|
||||||
this.allowSyncStart = this.allowSyncStart.bind(this);
|
this.createSyncStart = this.createSyncStart.bind(this);
|
||||||
this.startSyncSource = this.startSyncSource.bind(this);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
allowSyncStart(sourceId) {
|
createSyncStart(sourceId, extraVars) {
|
||||||
return this.http.get(`${this.baseUrl}${sourceId}/update/`);
|
|
||||||
}
|
|
||||||
|
|
||||||
startSyncSource(sourceId, extraVars) {
|
|
||||||
return this.http.post(`${this.baseUrl}${sourceId}/update/`, {
|
return this.http.post(`${this.baseUrl}${sourceId}/update/`, {
|
||||||
extra_vars: extraVars,
|
extra_vars: extraVars,
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -5,15 +5,10 @@ class InventoryUpdates extends LaunchUpdateMixin(Base) {
|
|||||||
constructor(http) {
|
constructor(http) {
|
||||||
super(http);
|
super(http);
|
||||||
this.baseUrl = '/api/v2/inventory_updates/';
|
this.baseUrl = '/api/v2/inventory_updates/';
|
||||||
this.allowSyncCancel = this.allowSyncCancel.bind(this);
|
this.createSyncCancel = this.createSyncCancel.bind(this);
|
||||||
this.cancelSyncSource = this.cancelSyncSource.bind(this);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
allowSyncCancel(sourceId) {
|
createSyncCancel(sourceId) {
|
||||||
return this.http.get(`${this.baseUrl}${sourceId}/cancel/`);
|
|
||||||
}
|
|
||||||
|
|
||||||
cancelSyncSource(sourceId) {
|
|
||||||
return this.http.post(`${this.baseUrl}${sourceId}/cancel/`);
|
return this.http.post(`${this.baseUrl}${sourceId}/cancel/`);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -25,10 +25,7 @@ function InventorySourceListItem({
|
|||||||
detailUrl,
|
detailUrl,
|
||||||
label,
|
label,
|
||||||
}) {
|
}) {
|
||||||
const [isCancelSyncLoading, setIsCancelSyncLoading] = useState(false);
|
const [isSyncLoading, setIsSyncLoading] = useState(false);
|
||||||
const [isStartSyncLoading, setIsStartSyncLoading] = useState(false);
|
|
||||||
|
|
||||||
const isDisabled = isCancelSyncLoading || isStartSyncLoading;
|
|
||||||
|
|
||||||
const generateLastJobTooltip = job => {
|
const generateLastJobTooltip = job => {
|
||||||
return (
|
return (
|
||||||
@@ -53,7 +50,7 @@ function InventorySourceListItem({
|
|||||||
<DataListItem aria-labelledby={`check-action-${source.id}`}>
|
<DataListItem aria-labelledby={`check-action-${source.id}`}>
|
||||||
<DataListItemRow>
|
<DataListItemRow>
|
||||||
<DataListCheck
|
<DataListCheck
|
||||||
isDisabled={isDisabled}
|
isDisabled={isSyncLoading}
|
||||||
id={`select-source-${source.id}`}
|
id={`select-source-${source.id}`}
|
||||||
checked={isSelected}
|
checked={isSelected}
|
||||||
onChange={onSelect}
|
onChange={onSelect}
|
||||||
@@ -99,12 +96,9 @@ function InventorySourceListItem({
|
|||||||
>
|
>
|
||||||
{source.summary_fields.user_capabilities.start && (
|
{source.summary_fields.user_capabilities.start && (
|
||||||
<InventorySourceSyncButton
|
<InventorySourceSyncButton
|
||||||
onCancelSyncLoading={isLoading =>
|
onSyncLoading={isLoading => {
|
||||||
setIsCancelSyncLoading(isLoading)
|
setIsSyncLoading(isLoading);
|
||||||
}
|
}}
|
||||||
onStartSyncLoading={isLoading =>
|
|
||||||
setIsStartSyncLoading(isLoading)
|
|
||||||
}
|
|
||||||
source={source}
|
source={source}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
@@ -113,7 +107,7 @@ function InventorySourceListItem({
|
|||||||
aria-label={i18n._(t`Edit Source`)}
|
aria-label={i18n._(t`Edit Source`)}
|
||||||
variant="plain"
|
variant="plain"
|
||||||
component={Link}
|
component={Link}
|
||||||
isDisabled={isDisabled}
|
isDisabled={isSyncLoading}
|
||||||
to={`${detailUrl}/edit`}
|
to={`${detailUrl}/edit`}
|
||||||
>
|
>
|
||||||
<PencilAltIcon />
|
<PencilAltIcon />
|
||||||
|
|||||||
@@ -106,6 +106,7 @@ describe('<InventorySourceListItem />', () => {
|
|||||||
);
|
);
|
||||||
expect(wrapper.find('StatusIcon').length).toBe(0);
|
expect(wrapper.find('StatusIcon').length).toBe(0);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('should not render sync buttons', async () => {
|
test('should not render sync buttons', async () => {
|
||||||
const onSelect = jest.fn();
|
const onSelect = jest.fn();
|
||||||
wrapper = mountWithContexts(
|
wrapper = mountWithContexts(
|
||||||
|
|||||||
@@ -9,12 +9,7 @@ import AlertModal from '@components/AlertModal/AlertModal';
|
|||||||
import ErrorDetail from '@components/ErrorDetail/ErrorDetail';
|
import ErrorDetail from '@components/ErrorDetail/ErrorDetail';
|
||||||
import { InventoryUpdatesAPI, InventorySourcesAPI } from '@api';
|
import { InventoryUpdatesAPI, InventorySourcesAPI } from '@api';
|
||||||
|
|
||||||
function InventorySourceSyncButton({
|
function InventorySourceSyncButton({ onSyncLoading, source, i18n }) {
|
||||||
onCancelSyncLoading,
|
|
||||||
onStartSyncLoading,
|
|
||||||
source,
|
|
||||||
i18n,
|
|
||||||
}) {
|
|
||||||
const [updateStatus, setUpdateStatus] = useState(source.status);
|
const [updateStatus, setUpdateStatus] = useState(source.status);
|
||||||
|
|
||||||
const {
|
const {
|
||||||
@@ -23,25 +18,14 @@ function InventorySourceSyncButton({
|
|||||||
request: startSyncProcess,
|
request: startSyncProcess,
|
||||||
} = useRequest(
|
} = useRequest(
|
||||||
useCallback(async () => {
|
useCallback(async () => {
|
||||||
let syncStatus;
|
|
||||||
|
|
||||||
const {
|
const {
|
||||||
data: { can_update },
|
data: { status },
|
||||||
} = await InventorySourcesAPI.allowSyncStart(source.id);
|
} = await InventorySourcesAPI.createSyncStart(source.id);
|
||||||
if (can_update) {
|
|
||||||
syncStatus = await InventorySourcesAPI.startSyncSource(source.id);
|
|
||||||
} else {
|
|
||||||
throw new Error(
|
|
||||||
i18n._(
|
|
||||||
t`You do not have permission to start this inventory source sync`
|
|
||||||
)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
setUpdateStatus(syncStatus.data.status);
|
setUpdateStatus(status);
|
||||||
|
|
||||||
return syncStatus.data.status;
|
return status;
|
||||||
}, [source.id, i18n]),
|
}, [source.id]),
|
||||||
{}
|
{}
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -58,29 +42,15 @@ function InventorySourceSyncButton({
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
} = await InventorySourcesAPI.readDetail(source.id);
|
} = await InventorySourcesAPI.readDetail(source.id);
|
||||||
const {
|
|
||||||
data: { can_cancel },
|
await InventoryUpdatesAPI.createSyncCancel(id);
|
||||||
} = await InventoryUpdatesAPI.allowSyncCancel(id);
|
setUpdateStatus(null);
|
||||||
if (can_cancel) {
|
}, [source.id])
|
||||||
await InventoryUpdatesAPI.cancelSyncSource(id);
|
|
||||||
setUpdateStatus(null);
|
|
||||||
} else {
|
|
||||||
throw new Error(
|
|
||||||
i18n._(
|
|
||||||
t`You do not have permission to cancel this inventory source sync`
|
|
||||||
)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}, [source.id, i18n])
|
|
||||||
);
|
);
|
||||||
|
|
||||||
useEffect(() => onStartSyncLoading(startSyncLoading), [
|
useEffect(() => onSyncLoading(startSyncLoading || cancelSyncLoading), [
|
||||||
onStartSyncLoading,
|
onSyncLoading,
|
||||||
startSyncLoading,
|
startSyncLoading,
|
||||||
]);
|
|
||||||
|
|
||||||
useEffect(() => onCancelSyncLoading(cancelSyncLoading), [
|
|
||||||
onCancelSyncLoading,
|
|
||||||
cancelSyncLoading,
|
cancelSyncLoading,
|
||||||
]);
|
]);
|
||||||
|
|
||||||
@@ -131,8 +101,7 @@ function InventorySourceSyncButton({
|
|||||||
}
|
}
|
||||||
|
|
||||||
InventorySourceSyncButton.propTypes = {
|
InventorySourceSyncButton.propTypes = {
|
||||||
onCancelSyncLoading: PropTypes.func.isRequired,
|
onSyncLoading: PropTypes.func.isRequired,
|
||||||
onStartSyncLoading: PropTypes.func.isRequired,
|
|
||||||
source: PropTypes.shape({}),
|
source: PropTypes.shape({}),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -8,8 +8,7 @@ jest.mock('@api/models/InventoryUpdates');
|
|||||||
jest.mock('@api/models/InventorySources');
|
jest.mock('@api/models/InventorySources');
|
||||||
|
|
||||||
const source = { id: 1, name: 'Foo', source: 'Source Bar' };
|
const source = { id: 1, name: 'Foo', source: 'Source Bar' };
|
||||||
const onCancelSyncLoading = jest.fn();
|
const onSyncLoading = jest.fn();
|
||||||
const onStartSyncLoading = jest.fn();
|
|
||||||
|
|
||||||
describe('<InventorySourceSyncButton />', () => {
|
describe('<InventorySourceSyncButton />', () => {
|
||||||
let wrapper;
|
let wrapper;
|
||||||
@@ -17,8 +16,7 @@ describe('<InventorySourceSyncButton />', () => {
|
|||||||
wrapper = mountWithContexts(
|
wrapper = mountWithContexts(
|
||||||
<InventorySourceSyncButton
|
<InventorySourceSyncButton
|
||||||
source={source}
|
source={source}
|
||||||
onCancelSyncLoading={onCancelSyncLoading}
|
onSyncLoading={onSyncLoading}
|
||||||
onStartSyncLoading={onStartSyncLoading}
|
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
@@ -41,26 +39,21 @@ describe('<InventorySourceSyncButton />', () => {
|
|||||||
wrapper = mountWithContexts(
|
wrapper = mountWithContexts(
|
||||||
<InventorySourceSyncButton
|
<InventorySourceSyncButton
|
||||||
source={{ status: 'pending', ...source }}
|
source={{ status: 'pending', ...source }}
|
||||||
onCancelSyncLoading={onCancelSyncLoading}
|
onSyncLoading={onSyncLoading}
|
||||||
onStartSyncLoading={onStartSyncLoading}
|
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
expect(wrapper.find('MinusCircleIcon').length).toBe(1);
|
expect(wrapper.find('MinusCircleIcon').length).toBe(1);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('should start sync properly', async () => {
|
test('should start sync properly', async () => {
|
||||||
InventorySourcesAPI.allowSyncStart.mockResolvedValue({
|
InventorySourcesAPI.createSyncStart.mockResolvedValue({
|
||||||
data: { can_update: true },
|
|
||||||
});
|
|
||||||
InventorySourcesAPI.startSyncSource.mockResolvedValue({
|
|
||||||
data: { status: 'pending' },
|
data: { status: 'pending' },
|
||||||
});
|
});
|
||||||
|
|
||||||
await act(async () =>
|
await act(async () =>
|
||||||
wrapper.find('Button[aria-label="Start sync source"]').simulate('click')
|
wrapper.find('Button[aria-label="Start sync source"]').simulate('click')
|
||||||
);
|
);
|
||||||
expect(InventorySourcesAPI.allowSyncStart).toBeCalledWith(1);
|
expect(InventorySourcesAPI.createSyncStart).toBeCalledWith(1);
|
||||||
expect(InventorySourcesAPI.startSyncSource).toBeCalledWith(1);
|
|
||||||
wrapper.update();
|
wrapper.update();
|
||||||
expect(wrapper.find('Button[aria-label="Cancel sync source"]').length).toBe(
|
expect(wrapper.find('Button[aria-label="Cancel sync source"]').length).toBe(
|
||||||
1
|
1
|
||||||
@@ -70,18 +63,14 @@ describe('<InventorySourceSyncButton />', () => {
|
|||||||
InventorySourcesAPI.readDetail.mockResolvedValue({
|
InventorySourcesAPI.readDetail.mockResolvedValue({
|
||||||
data: { summary_fields: { current_update: { id: 120 } } },
|
data: { summary_fields: { current_update: { id: 120 } } },
|
||||||
});
|
});
|
||||||
InventoryUpdatesAPI.allowSyncCancel.mockResolvedValue({
|
InventoryUpdatesAPI.createSyncCancel.mockResolvedValue({
|
||||||
data: { can_cancel: true },
|
|
||||||
});
|
|
||||||
InventoryUpdatesAPI.cancelSyncSource.mockResolvedValue({
|
|
||||||
data: { status: '' },
|
data: { status: '' },
|
||||||
});
|
});
|
||||||
|
|
||||||
wrapper = mountWithContexts(
|
wrapper = mountWithContexts(
|
||||||
<InventorySourceSyncButton
|
<InventorySourceSyncButton
|
||||||
source={{ status: 'pending', ...source }}
|
source={{ status: 'pending', ...source }}
|
||||||
onCancelSyncLoading={onCancelSyncLoading}
|
onSyncLoading={onSyncLoading}
|
||||||
onStartSyncLoading={onStartSyncLoading}
|
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
expect(wrapper.find('Button[aria-label="Cancel sync source"]').length).toBe(
|
expect(wrapper.find('Button[aria-label="Cancel sync source"]').length).toBe(
|
||||||
@@ -93,8 +82,7 @@ describe('<InventorySourceSyncButton />', () => {
|
|||||||
);
|
);
|
||||||
|
|
||||||
expect(InventorySourcesAPI.readDetail).toBeCalledWith(1);
|
expect(InventorySourcesAPI.readDetail).toBeCalledWith(1);
|
||||||
expect(InventoryUpdatesAPI.allowSyncCancel).toBeCalledWith(120);
|
expect(InventoryUpdatesAPI.createSyncCancel).toBeCalledWith(120);
|
||||||
expect(InventoryUpdatesAPI.cancelSyncSource).toBeCalledWith(120);
|
|
||||||
|
|
||||||
wrapper.update();
|
wrapper.update();
|
||||||
|
|
||||||
@@ -102,59 +90,4 @@ describe('<InventorySourceSyncButton />', () => {
|
|||||||
1
|
1
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
test('Should prevent user from starting sync', async () => {
|
|
||||||
InventorySourcesAPI.allowSyncStart.mockResolvedValue({
|
|
||||||
data: { can_update: false },
|
|
||||||
});
|
|
||||||
InventorySourcesAPI.startSyncSource.mockResolvedValue({
|
|
||||||
data: { status: 'pending' },
|
|
||||||
});
|
|
||||||
|
|
||||||
await act(async () =>
|
|
||||||
wrapper.find('Button[aria-label="Start sync source"]').simulate('click')
|
|
||||||
);
|
|
||||||
expect(InventorySourcesAPI.allowSyncStart).toBeCalledWith(1);
|
|
||||||
expect(InventorySourcesAPI.startSyncSource).not.toBeCalledWith();
|
|
||||||
wrapper.update();
|
|
||||||
expect(wrapper.find('AlertModal').length).toBe(1);
|
|
||||||
expect(wrapper.find('Button[aria-label="Start sync source"]').length).toBe(
|
|
||||||
1
|
|
||||||
);
|
|
||||||
});
|
|
||||||
test('should prevent user from canceling sync', async () => {
|
|
||||||
InventorySourcesAPI.readDetail.mockResolvedValue({
|
|
||||||
data: { summary_fields: { current_update: { id: 120 } } },
|
|
||||||
});
|
|
||||||
InventoryUpdatesAPI.allowSyncCancel.mockResolvedValue({
|
|
||||||
data: { can_cancel: false },
|
|
||||||
});
|
|
||||||
InventoryUpdatesAPI.cancelSyncSource.mockResolvedValue({
|
|
||||||
data: { status: '' },
|
|
||||||
});
|
|
||||||
|
|
||||||
wrapper = mountWithContexts(
|
|
||||||
<InventorySourceSyncButton
|
|
||||||
source={{ status: 'pending', ...source }}
|
|
||||||
onCancelSyncLoading={onCancelSyncLoading}
|
|
||||||
onStartSyncLoading={onStartSyncLoading}
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
expect(wrapper.find('Button[aria-label="Cancel sync source"]').length).toBe(
|
|
||||||
1
|
|
||||||
);
|
|
||||||
|
|
||||||
await act(async () =>
|
|
||||||
wrapper.find('Button[aria-label="Cancel sync source"]').simulate('click')
|
|
||||||
);
|
|
||||||
|
|
||||||
expect(InventorySourcesAPI.readDetail).toBeCalledWith(1);
|
|
||||||
expect(InventoryUpdatesAPI.allowSyncCancel).toBeCalledWith(120);
|
|
||||||
expect(InventoryUpdatesAPI.cancelSyncSource).not.toBeCalledWith(120);
|
|
||||||
|
|
||||||
wrapper.update();
|
|
||||||
expect(wrapper.find('AlertModal').length).toBe(1);
|
|
||||||
expect(wrapper.find('Button[aria-label="Cancel sync source"]').length).toBe(
|
|
||||||
1
|
|
||||||
);
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
|
|||||||
Reference in New Issue
Block a user