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