updates several dependencies

This commit is contained in:
Alex Corey 2021-07-20 12:06:45 -04:00
parent e77d297a28
commit 3def23883e
660 changed files with 30212 additions and 5437 deletions

View File

@ -12,7 +12,6 @@
"extends": [
"airbnb",
"prettier",
"prettier/react",
"plugin:jsx-a11y/strict",
"plugin:i18next/recommended"
],
@ -22,7 +21,7 @@
},
"import/resolver": {
"node": {
paths: ["src"]
"paths": ["src"]
}
}
},
@ -134,6 +133,7 @@
"object-curly-newline": "off",
"no-trailing-spaces": ["error"],
"no-unused-expressions": ["error", { "allowShortCircuit": true }],
"react/jsx-props-no-spreading":["off"],
"react/prefer-stateless-function": "off",
"react/prop-types": "off",
"react/sort-comp": ["error", {}],

File diff suppressed because it is too large Load Diff

View File

@ -44,19 +44,19 @@
"enzyme": "^3.10.0",
"enzyme-adapter-react-16": "^1.14.0",
"enzyme-to-json": "^3.3.5",
"eslint": "^7.11.0",
"eslint-config-airbnb": "^17.1.0",
"eslint-config-prettier": "^5.0.0",
"eslint": "7.30.0",
"eslint-config-airbnb": "18.2.1",
"eslint-config-prettier": "8.3.0",
"eslint-import-resolver-webpack": "0.11.1",
"eslint-plugin-i18next": "^5.0.0",
"eslint-plugin-import": "^2.14.0",
"eslint-plugin-jsx-a11y": "^6.4.1",
"eslint-plugin-react": "^7.11.1",
"eslint-plugin-react-hooks": "^2.2.0",
"eslint-plugin-react-hooks": "4.2.0",
"http-proxy-middleware": "^1.0.3",
"jest-websocket-mock": "^2.0.2",
"mock-socket": "^9.0.3",
"prettier": "^1.18.2",
"prettier": "2.3.2",
"react-scripts": "^4.0.3"
},
"scripts": {

View File

@ -16,7 +16,7 @@ const defaultHttp = axios.create({
},
});
defaultHttp.interceptors.response.use(response => {
defaultHttp.interceptors.response.use((response) => {
const timeout = response?.headers['session-timeout'];
if (timeout) {
const timeoutDate = new Date().getTime() + timeout * 1000;

View File

@ -1,13 +1,11 @@
function isEqual(array1, array2) {
return (
array1.length === array2.length &&
array1.every((element, index) => {
return element.id === array2[index].id;
})
array1.every((element, index) => element.id === array2[index].id)
);
}
const InstanceGroupsMixin = parent =>
const InstanceGroupsMixin = (parent) =>
class extends parent {
readInstanceGroups(resourceId, params) {
return this.http.get(`${this.baseUrl}${resourceId}/instance_groups/`, {

View File

@ -1,4 +1,4 @@
const LaunchUpdateMixin = parent =>
const LaunchUpdateMixin = (parent) =>
class extends parent {
launchUpdate(id, data) {
return this.http.post(`${this.baseUrl}${id}/update/`, data);

View File

@ -1,4 +1,4 @@
const NotificationsMixin = parent =>
const NotificationsMixin = (parent) =>
class extends parent {
readOptionsNotificationTemplates(id) {
return this.http.options(`${this.baseUrl}${id}/notification_templates/`);

View File

@ -1,4 +1,4 @@
const Runnable = parent =>
const Runnable = (parent) =>
class extends parent {
jobEventSlug = '/events/';

View File

@ -1,4 +1,4 @@
const SchedulesMixin = parent =>
const SchedulesMixin = (parent) =>
class extends parent {
createSchedule(id, data) {
return this.http.post(`${this.baseUrl}${id}/schedules/`, data);

View File

@ -25,7 +25,7 @@ class CredentialTypes extends Base {
}
return results
.concat(nextResults)
.filter(type => acceptableKinds.includes(type.kind));
.filter((type) => acceptableKinds.includes(type.kind));
}
test(id, data) {

View File

@ -22,9 +22,10 @@ describe('TeamsAPI', () => {
await TeamsAPI.associateRole(teamId, roleId);
expect(mockHttp.post).toHaveBeenCalledTimes(1);
expect(
mockHttp.post.mock.calls[0]
).toContainEqual(`/api/v2/teams/${teamId}/roles/`, { id: roleId });
expect(mockHttp.post.mock.calls[0]).toContainEqual(
`/api/v2/teams/${teamId}/roles/`,
{ id: roleId }
);
});
test('read teams calls post with expected params', async () => {

View File

@ -19,9 +19,10 @@ describe('UsersAPI', () => {
await UsersAPI.associateRole(userId, roleId);
expect(mockHttp.post).toHaveBeenCalledTimes(1);
expect(
mockHttp.post.mock.calls[0]
).toContainEqual(`/api/v2/users/${userId}/roles/`, { id: roleId });
expect(mockHttp.post.mock.calls[0]).toContainEqual(
`/api/v2/users/${userId}/roles/`,
{ id: roleId }
);
});
test('read users calls post with expected params', async () => {

View File

@ -65,7 +65,7 @@ function AdHocCommands({
request: launchAdHocCommands,
} = useRequest(
useCallback(
async values => {
async (values) => {
const { data } = await InventoriesAPI.launchAdHocCommands(id, values);
history.push(`/jobs/command/${data.id}/output`);
},
@ -74,7 +74,11 @@ function AdHocCommands({
)
);
const handleSubmit = async values => {
const { error, dismissError } = useDismissableError(
launchError || fetchError
);
const handleSubmit = async (values) => {
const { credential, execution_environment, ...remainingValues } = values;
const newCredential = credential[0].id;
@ -85,13 +89,9 @@ function AdHocCommands({
};
await launchAdHocCommands(manipulatedValues);
};
useEffect(() => onLaunchLoading(isLaunchLoading), [
isLaunchLoading,
onLaunchLoading,
]);
const { error, dismissError } = useDismissableError(
launchError || fetchError
useEffect(
() => onLaunchLoading(isLaunchLoading),
[isLaunchLoading, onLaunchLoading]
);
if (error && isWizardOpen) {

View File

@ -109,7 +109,7 @@ describe('<AdHocCommands />', () => {
await waitForElement(
wrapper,
'button[aria-label="Run Command"]',
el => el.length === 1
(el) => el.length === 1
);
await act(async () =>
wrapper.find('button[aria-label="Run Command"]').prop('onClick')()
@ -164,7 +164,7 @@ describe('<AdHocCommands />', () => {
await waitForElement(
wrapper,
'button[aria-label="Run Command"]',
el => el.length === 1
(el) => el.length === 1
);
await act(async () =>
wrapper.find('button[aria-label="Run Command"]').prop('onClick')()
@ -190,15 +190,12 @@ describe('<AdHocCommands />', () => {
await act(async () =>
wrapper.find('Button[type="submit"]').prop('onClick')()
);
await waitForElement(wrapper, 'ContentEmpty', el => el.length === 0);
await waitForElement(wrapper, 'ContentEmpty', (el) => el.length === 0);
// second step of wizard
await act(async () => {
wrapper
.find('td#check-action-item-2')
.find('input')
.simulate('click');
wrapper.find('td#check-action-item-2').find('input').simulate('click');
});
wrapper.update();
@ -211,13 +208,10 @@ describe('<AdHocCommands />', () => {
wrapper.find('Button[type="submit"]').prop('onClick')()
);
// third step of wizard
await waitForElement(wrapper, 'ContentEmpty', el => el.length === 0);
await waitForElement(wrapper, 'ContentEmpty', (el) => el.length === 0);
await act(async () => {
wrapper
.find('td#check-action-item-4')
.find('input')
.simulate('click');
wrapper.find('td#check-action-item-4').find('input').simulate('click');
});
wrapper.update();
@ -322,7 +316,7 @@ describe('<AdHocCommands />', () => {
await waitForElement(
wrapper,
'button[aria-label="Run Command"]',
el => el.length === 1
(el) => el.length === 1
);
await act(async () =>
wrapper.find('button[aria-label="Run Command"]').prop('onClick')()
@ -353,15 +347,12 @@ describe('<AdHocCommands />', () => {
wrapper.find('Button[type="submit"]').prop('onClick')()
);
await waitForElement(wrapper, 'ContentEmpty', el => el.length === 0);
await waitForElement(wrapper, 'ContentEmpty', (el) => el.length === 0);
// second step of wizard
await act(async () => {
wrapper
.find('td#check-action-item-2')
.find('input')
.simulate('click');
wrapper.find('td#check-action-item-2').find('input').simulate('click');
});
wrapper.update();
@ -374,13 +365,10 @@ describe('<AdHocCommands />', () => {
wrapper.find('Button[type="submit"]').prop('onClick')()
);
// third step of wizard
await waitForElement(wrapper, 'ContentEmpty', el => el.length === 0);
await waitForElement(wrapper, 'ContentEmpty', (el) => el.length === 0);
await act(async () => {
wrapper
.find('td#check-action-item-4')
.find('input')
.simulate('click');
wrapper.find('td#check-action-item-4').find('input').simulate('click');
});
wrapper.update();
@ -399,7 +387,7 @@ describe('<AdHocCommands />', () => {
await act(async () =>
wrapper.find('Button[type="submit"]').prop('onClick')()
);
await waitForElement(wrapper, 'ErrorDetail', el => el.length > 0);
await waitForElement(wrapper, 'ErrorDetail', (el) => el.length > 0);
});
test('should disable run command button due to lack of list items', async () => {
@ -420,7 +408,7 @@ describe('<AdHocCommands />', () => {
/>
);
});
await waitForElement(wrapper, 'ContentLoading', el => el.length === 0);
await waitForElement(wrapper, 'ContentLoading', (el) => el.length === 0);
const runCommandsButton = wrapper.find('button[aria-label="Run Command"]');
expect(runCommandsButton.prop('disabled')).toBe(true);
});

View File

@ -58,7 +58,7 @@ function AdHocCommandsWizard({
const FormikApp = withFormik({
mapPropsToValues({ adHocItems, verbosityOptions }) {
const adHocItemStrings = adHocItems.map(item => item.name).join(', ');
const adHocItemStrings = adHocItems.map((item) => item.name).join(', ');
return {
limit: adHocItemStrings || 'all',
credential: [],

View File

@ -61,7 +61,7 @@ describe('<AdHocCommandsWizard/>', () => {
});
test('launch button should be disabled', async () => {
waitForElement(wrapper, 'WizardNavItem', el => el.length > 0);
waitForElement(wrapper, 'WizardNavItem', (el) => el.length > 0);
expect(wrapper.find('Button[type="submit"]').prop('isDisabled')).toBe(
false
@ -108,7 +108,7 @@ describe('<AdHocCommandsWizard/>', () => {
CredentialsAPI.readOptions.mockResolvedValue({
data: { actions: { GET: {} } },
});
await waitForElement(wrapper, 'WizardNavItem', el => el.length > 0);
await waitForElement(wrapper, 'WizardNavItem', (el) => el.length > 0);
await act(async () => {
wrapper.find('AnsibleSelect[name="module_name"]').prop('onChange')(
@ -132,17 +132,14 @@ describe('<AdHocCommandsWizard/>', () => {
// step 2
await waitForElement(wrapper, 'OptionsList', el => el.length > 0);
await waitForElement(wrapper, 'OptionsList', (el) => el.length > 0);
expect(wrapper.find('CheckboxListItem').length).toBe(2);
expect(wrapper.find('Button[type="submit"]').prop('isDisabled')).toBe(
false
);
await act(async () => {
wrapper
.find('td#check-action-item-1')
.find('input')
.simulate('click');
wrapper.find('td#check-action-item-1').find('input').simulate('click');
});
wrapper.update();
@ -161,14 +158,11 @@ describe('<AdHocCommandsWizard/>', () => {
wrapper.update();
// step 3
await waitForElement(wrapper, 'OptionsList', el => el.length > 0);
await waitForElement(wrapper, 'OptionsList', (el) => el.length > 0);
expect(wrapper.find('CheckboxListItem').length).toBe(2);
await act(async () => {
wrapper
.find('td#check-action-item-1')
.find('input')
.simulate('click');
wrapper.find('td#check-action-item-1').find('input').simulate('click');
});
wrapper.update();
@ -204,7 +198,7 @@ describe('<AdHocCommandsWizard/>', () => {
});
test('should show error in navigation bar', async () => {
await waitForElement(wrapper, 'WizardNavItem', el => el.length > 0);
await waitForElement(wrapper, 'WizardNavItem', (el) => el.length > 0);
await act(async () => {
wrapper.find('AnsibleSelect[name="module_name"]').prop('onChange')(
@ -215,7 +209,7 @@ describe('<AdHocCommandsWizard/>', () => {
target: { value: '', name: 'module_args' },
});
});
waitForElement(wrapper, 'ExclamationCircleIcon', el => el.length > 0);
waitForElement(wrapper, 'ExclamationCircleIcon', (el) => el.length > 0);
});
test('expect credential step to throw error', async () => {
@ -234,7 +228,7 @@ describe('<AdHocCommandsWizard/>', () => {
CredentialsAPI.readOptions.mockResolvedValue({
data: { actions: { GET: {} } },
});
await waitForElement(wrapper, 'WizardNavItem', el => el.length > 0);
await waitForElement(wrapper, 'WizardNavItem', (el) => el.length > 0);
await act(async () => {
wrapper.find('AnsibleSelect[name="module_name"]').prop('onChange')(

View File

@ -58,10 +58,10 @@ function AdHocCredentialStep({ credentialTypeId }) {
credentialCount: count,
relatedSearchableKeys: (
actionsResponse?.data?.related_search_fields || []
).map(val => val.slice(0, -8)),
).map((val) => val.slice(0, -8)),
searchableKeys: Object.keys(
actionsResponse.data.actions?.GET || {}
).filter(key => actionsResponse.data.actions?.GET[key].filterable),
).filter((key) => actionsResponse.data.actions?.GET[key].filterable),
};
}, [credentialTypeId, history.location.search]),
{
@ -135,7 +135,7 @@ function AdHocCredentialStep({ credentialTypeId }) {
},
]}
name="credential"
selectItem={value => {
selectItem={(value) => {
helpers.setValue([value]);
}}
deselectItem={() => {

View File

@ -42,11 +42,11 @@ describe('<AdHocCredentialStep />', () => {
});
test('should mount properly', async () => {
await waitForElement(wrapper, 'OptionsList', el => el.length > 0);
await waitForElement(wrapper, 'OptionsList', (el) => el.length > 0);
});
test('should call api', async () => {
await waitForElement(wrapper, 'OptionsList', el => el.length > 0);
await waitForElement(wrapper, 'OptionsList', (el) => el.length > 0);
expect(CredentialsAPI.read).toHaveBeenCalled();
expect(wrapper.find('CheckboxListItem').length).toBe(2);
});

View File

@ -30,9 +30,8 @@ function AdHocDetailsStep({ verbosityOptions, moduleOptions }) {
const [variablesField] = useField('extra_vars');
const [diffModeField, , diffModeHelpers] = useField('diff_mode');
const [becomeEnabledField, , becomeEnabledHelpers] = useField(
'become_enabled'
);
const [becomeEnabledField, , becomeEnabledHelpers] =
useField('become_enabled');
const [verbosityField, verbosityMeta, verbosityHelpers] = useField({
name: 'verbosity',
validate: required(null),
@ -82,7 +81,7 @@ function AdHocDetailsStep({ verbosityOptions, moduleOptions }) {
label: t`Choose a module`,
isDisabled: true,
},
...moduleOptions.map(value => ({
...moduleOptions.map((value) => ({
value: value[0],
label: value[0],
key: value[0],
@ -238,7 +237,7 @@ function AdHocDetailsStep({ verbosityOptions, moduleOptions }) {
}
id="become_enabled"
isChecked={becomeEnabledField.value}
onChange={checked => {
onChange={(checked) => {
becomeEnabledHelpers.setValue(checked);
}}
/>

View File

@ -39,11 +39,11 @@ describe('<AdHocExecutionEnvironmentStep />', () => {
});
test('should mount properly', async () => {
await waitForElement(wrapper, 'OptionsList', el => el.length > 0);
await waitForElement(wrapper, 'OptionsList', (el) => el.length > 0);
});
test('should call api', async () => {
await waitForElement(wrapper, 'OptionsList', el => el.length > 0);
await waitForElement(wrapper, 'OptionsList', (el) => el.length > 0);
expect(ExecutionEnvironmentsAPI.read).toHaveBeenCalled();
expect(wrapper.find('CheckboxListItem').length).toBe(2);
});

View File

@ -59,10 +59,10 @@ function AdHocExecutionEnvironmentStep({ organizationId }) {
executionEnvironmentsCount: count,
relatedSearchableKeys: (
actionsResponse?.data?.related_search_fields || []
).map(val => val.slice(0, -8)),
).map((val) => val.slice(0, -8)),
searchableKeys: Object.keys(
actionsResponse.data.actions?.GET || {}
).filter(key => actionsResponse.data.actions?.GET[key].filterable),
).filter((key) => actionsResponse.data.actions?.GET[key].filterable),
};
}, [history.location.search, organizationId]),
{
@ -127,7 +127,7 @@ function AdHocExecutionEnvironmentStep({ organizationId }) {
name="execution_environment"
searchableKeys={searchableKeys}
relatedSearchableKeys={relatedSearchableKeys}
selectItem={value => {
selectItem={(value) => {
executionEnvironmentHelpers.setValue([value]);
}}
deselectItem={() => {

View File

@ -34,7 +34,7 @@ export default function useAdHocExecutionEnvironmentStep(
helpers.setError('A credential must be selected');
}
},
setTouched: setFieldTouched => {
setTouched: (setFieldTouched) => {
setFieldTouched('credential', true, false);
},
};

View File

@ -62,7 +62,7 @@ export default function useAdHocDetailsStep(
}
}
},
setTouched: setFieldTouched => {
setTouched: (setFieldTouched) => {
setFieldTouched('module_name', true, false);
setFieldTouched('module_args', true, false);
},

View File

@ -17,32 +17,28 @@ export default function useAdHocLaunchSteps(
useAdHocCredentialStep(visited, credentialTypeId),
];
const hasErrors = steps.some(step => step.hasError);
const hasErrors = steps.some((step) => step.hasError);
steps.push(useAdHocPreviewStep(hasErrors));
return {
steps: steps.map(s => s.step).filter(s => s != null),
validateStep: stepId =>
steps
.find(s => {
return s?.step.id === stepId;
})
.validate(),
steps: steps.map((s) => s.step).filter((s) => s != null),
validateStep: (stepId) =>
steps.find((s) => s?.step.id === stepId).validate(),
visitStep: (prevStepId, setFieldTouched) => {
setVisited({
...visited,
[prevStepId]: true,
});
steps.find(s => s?.step?.id === prevStepId).setTouched(setFieldTouched);
steps.find((s) => s?.step?.id === prevStepId).setTouched(setFieldTouched);
},
visitAllSteps: setFieldTouched => {
visitAllSteps: (setFieldTouched) => {
setVisited({
details: true,
executionEnvironment: true,
credential: true,
preview: true,
});
steps.forEach(s => s.setTouched(setFieldTouched));
steps.forEach((s) => s.setTouched(setFieldTouched));
},
};
}

View File

@ -1,4 +1,4 @@
import React, { useState, useRef, useEffect, Fragment } from 'react';
import React, { useState, useRef, useEffect } from 'react';
import { t } from '@lingui/macro';
import PropTypes from 'prop-types';
import { Dropdown, DropdownPosition } from '@patternfly/react-core';
@ -11,7 +11,7 @@ function AddDropDownButton({ dropdownItems, ouiaId }) {
const element = useRef(null);
useEffect(() => {
const toggle = e => {
const toggle = (e) => {
if (!isKebabified && (!element || !element.current.contains(e.target))) {
setIsOpen(false);
}
@ -24,7 +24,7 @@ function AddDropDownButton({ dropdownItems, ouiaId }) {
}, [isKebabified]);
if (isKebabified) {
return <Fragment>{dropdownItems}</Fragment>;
return <>{dropdownItems}</>;
}
return (

View File

@ -1,4 +1,4 @@
import React, { Fragment, useState, useEffect } from 'react';
import React, { useState, useEffect } from 'react';
import PropTypes from 'prop-types';
import { useHistory } from 'react-router-dom';
import { t } from '@lingui/macro';
@ -8,12 +8,12 @@ import Wizard from '../Wizard';
import SelectResourceStep from './SelectResourceStep';
import SelectRoleStep from './SelectRoleStep';
const readUsers = async queryParams =>
const readUsers = async (queryParams) =>
UsersAPI.read(Object.assign(queryParams, { is_superuser: false }));
const readUsersOptions = async () => UsersAPI.readOptions();
const readTeams = async queryParams => TeamsAPI.read(queryParams);
const readTeams = async (queryParams) => TeamsAPI.read(queryParams);
const readTeamsOptions = async () => TeamsAPI.readOptions();
@ -77,9 +77,9 @@ function AddResourceRole({ onSave, onClose, roles, resource, onError }) {
const [currentStepId, setCurrentStepId] = useState(1);
const [maxEnabledStep, setMaxEnabledStep] = useState(1);
const handleResourceCheckboxClick = user => {
const handleResourceCheckboxClick = (user) => {
const selectedIndex = selectedResourceRows.findIndex(
selectedRow => selectedRow.id === user.id
(selectedRow) => selectedRow.id === user.id
);
if (selectedIndex > -1) {
selectedResourceRows.splice(selectedIndex, 1);
@ -98,9 +98,9 @@ function AddResourceRole({ onSave, onClose, roles, resource, onError }) {
}
}, [currentStepId, history, maxEnabledStep]);
const handleRoleCheckboxClick = role => {
const handleRoleCheckboxClick = (role) => {
const selectedIndex = selectedRoleRows.findIndex(
selectedRow => selectedRow.id === role.id
(selectedRow) => selectedRow.id === role.id
);
if (selectedIndex > -1) {
@ -112,18 +112,18 @@ function AddResourceRole({ onSave, onClose, roles, resource, onError }) {
}
};
const handleResourceSelect = resourceType => {
const handleResourceSelect = (resourceType) => {
setSelectedResource(resourceType);
setSelectedResourceRows([]);
setSelectedRoleRows([]);
};
const handleWizardNext = step => {
const handleWizardNext = (step) => {
setCurrentStepId(step.id);
setMaxEnabledStep(step.id);
};
const handleWizardGoToStep = step => {
const handleWizardGoToStep = (step) => {
setCurrentStepId(step.id);
};
@ -163,7 +163,7 @@ function AddResourceRole({ onSave, onClose, roles, resource, onError }) {
// showing role choices for team access
const selectableRoles = { ...roles };
if (selectedResource === 'teams') {
Object.keys(roles).forEach(key => {
Object.keys(roles).forEach((key) => {
if (selectableRoles[key].user_only) {
delete selectableRoles[key];
}
@ -219,7 +219,7 @@ function AddResourceRole({ onSave, onClose, roles, resource, onError }) {
id: 2,
name: t`Select Items from List`,
component: (
<Fragment>
<>
{selectedResource === 'users' && (
<SelectResourceStep
searchColumns={userSearchColumns}
@ -244,7 +244,7 @@ function AddResourceRole({ onSave, onClose, roles, resource, onError }) {
selectedResourceRows={selectedResourceRows}
/>
)}
</Fragment>
</>
),
enableNext: selectedResourceRows.length > 0,
nextButtonText: t`Next`,
@ -269,17 +269,17 @@ function AddResourceRole({ onSave, onClose, roles, resource, onError }) {
},
];
const currentStep = steps.find(step => step.id === currentStepId);
const currentStep = steps.find((step) => step.id === currentStepId);
return (
<Wizard
style={{ overflow: 'scroll' }}
isOpen
onNext={handleWizardNext}
onBack={step => setCurrentStepId(step.id)}
onBack={(step) => setCurrentStepId(step.id)}
onClose={onClose}
onSave={handleWizardSave}
onGoToStep={step => handleWizardGoToStep(step)}
onGoToStep={(step) => handleWizardGoToStep(step)}
steps={steps}
title={wizardTitle}
nextButtonText={currentStep.nextButtonText || undefined}

View File

@ -68,7 +68,7 @@ describe('<_AddResourceRole />', () => {
onClose={() => {}}
onSave={() => {}}
roles={roles}
i18n={{ _: val => val.toString() }}
i18n={{ _: (val) => val.toString() }}
/>
);
});
@ -93,7 +93,7 @@ describe('<_AddResourceRole />', () => {
wrapper.update();
// Step 2
await waitForElement(wrapper, 'EmptyStateBody', el => el.length === 0);
await waitForElement(wrapper, 'EmptyStateBody', (el) => el.length === 0);
expect(wrapper.find('Chip').length).toBe(0);
act(() =>
wrapper.find('CheckboxListItem[name="foo"]').invoke('onSelect')(true)
@ -161,7 +161,7 @@ describe('<_AddResourceRole />', () => {
wrapper.update();
// Step 2
await waitForElement(wrapper, 'EmptyStateBody', el => el.length === 0);
await waitForElement(wrapper, 'EmptyStateBody', (el) => el.length === 0);
act(() =>
wrapper.find('CheckboxListItem[name="foo"]').invoke('onSelect')(true)
);
@ -213,7 +213,7 @@ describe('<_AddResourceRole />', () => {
wrapper.update();
// Step 2
await waitForElement(wrapper, 'EmptyStateBody', el => el.length === 0);
await waitForElement(wrapper, 'EmptyStateBody', (el) => el.length === 0);
act(() =>
wrapper.find('CheckboxListItem[name="foo"]').invoke('onSelect')(true)
);
@ -246,7 +246,7 @@ describe('<_AddResourceRole />', () => {
await waitForElement(
wrapper,
'SelectableCard[label="Users"]',
el => el.prop('isSelected') === true
(el) => el.prop('isSelected') === true
);
act(() => wrapper.find('SelectableCard[label="Teams"]').prop('onClick')());
wrapper.update();
@ -254,7 +254,7 @@ describe('<_AddResourceRole />', () => {
await waitForElement(
wrapper,
'SelectableCard[label="Teams"]',
el => el.prop('isSelected') === true
(el) => el.prop('isSelected') === true
);
});
@ -279,7 +279,7 @@ describe('<_AddResourceRole />', () => {
wrapper.update();
// Step 2
await waitForElement(wrapper, 'EmptyStateBody', el => el.length === 0);
await waitForElement(wrapper, 'EmptyStateBody', (el) => el.length === 0);
act(() =>
wrapper.find('CheckboxListItem[name="foo"]').invoke('onSelect')(true)
);
@ -322,17 +322,17 @@ describe('<_AddResourceRole />', () => {
wrapper.update();
// Make sure no teams have been selected
await waitForElement(wrapper, 'EmptyStateBody', el => el.length === 0);
await waitForElement(wrapper, 'EmptyStateBody', (el) => el.length === 0);
wrapper
.find('DataListCheck')
.map(item => expect(item.prop('checked')).toBe(false));
.map((item) => expect(item.prop('checked')).toBe(false));
act(() => wrapper.find('Button[type="submit"]').prop('onClick')());
wrapper.update();
// Make sure that no roles have been selected
wrapper
.find('Checkbox')
.map(card => expect(card.prop('isChecked')).toBe(false));
.map((card) => expect(card.prop('isChecked')).toBe(false));
// Make sure the save button is disabled
expect(wrapper.find('Button[type="submit"]').prop('isDisabled')).toBe(true);
@ -379,7 +379,7 @@ describe('<_AddResourceRole />', () => {
wrapper.update();
// Step 2
await waitForElement(wrapper, 'EmptyStateBody', el => el.length === 0);
await waitForElement(wrapper, 'EmptyStateBody', (el) => el.length === 0);
expect(wrapper.find('Chip').length).toBe(0);
act(() =>
wrapper.find('CheckboxListItem[name="foo"]').invoke('onSelect')(true)

View File

@ -1,4 +1,4 @@
import React, { Component, Fragment } from 'react';
import React, { Component } from 'react';
import PropTypes from 'prop-types';
import { Checkbox as PFCheckbox } from '@patternfly/react-core';
import styled from 'styled-components';
@ -28,10 +28,10 @@ class CheckboxCard extends Component {
aria-label={name}
id={`checkbox-card-${itemId}`}
label={
<Fragment>
<>
<div style={{ fontWeight: 'bold' }}>{name}</div>
<div>{description}</div>
</Fragment>
</>
}
value={itemId}
/>

View File

@ -1,4 +1,4 @@
import React, { Fragment, useCallback, useEffect } from 'react';
import React, { useCallback, useEffect } from 'react';
import PropTypes from 'prop-types';
import { withRouter, useLocation } from 'react-router-dom';
import { t } from '@lingui/macro';
@ -10,15 +10,16 @@ import CheckboxListItem from '../CheckboxListItem';
import { SelectedList } from '../SelectedList';
import PaginatedTable, { HeaderCell, HeaderRow } from '../PaginatedTable';
const QS_Config = sortColumns => {
return getQSConfig('resource', {
const QS_Config = (sortColumns) =>
getQSConfig('resource', {
page: 1,
page_size: 5,
order_by: `${
sortColumns.filter(col => col.key === 'name').length ? 'name' : 'username'
sortColumns.filter((col) => col.key === 'name').length
? 'name'
: 'username'
}`,
});
};
function SelectResourceStep({
searchColumns,
sortColumns,
@ -54,10 +55,10 @@ function SelectResourceStep({
itemCount: count,
relatedSearchableKeys: (
actionsResponse?.data?.related_search_fields || []
).map(val => val.slice(0, -8)),
).map((val) => val.slice(0, -8)),
searchableKeys: Object.keys(
actionsResponse.data.actions?.GET || {}
).filter(key => actionsResponse.data.actions?.GET[key].filterable),
).filter((key) => actionsResponse.data.actions?.GET[key].filterable),
};
}, [location, fetchItems, fetchOptions, sortColumns]),
{
@ -73,7 +74,7 @@ function SelectResourceStep({
}, [readResourceList]);
return (
<Fragment>
<>
<div>
{t`Choose the resources that will be receiving new roles. You'll be able to select the roles to apply in the next step. Note that the resources chosen here will receive all roles chosen in the next step.`}
</div>
@ -108,7 +109,7 @@ function SelectResourceStep({
}
renderRow={(item, index) => (
<CheckboxListItem
isSelected={selectedResourceRows.some(i => i.id === item.id)}
isSelected={selectedResourceRows.some((i) => i.id === item.id)}
itemId={item.id}
item={item}
rowIndex={index}
@ -120,10 +121,10 @@ function SelectResourceStep({
onDeselect={() => onRowClick(item)}
/>
)}
renderToolbar={props => <DataListToolbar {...props} fillWidth />}
renderToolbar={(props) => <DataListToolbar {...props} fillWidth />}
showPageSizeOptions={false}
/>
</Fragment>
</>
);
}

View File

@ -79,7 +79,7 @@ describe('<SelectResourceStep />', () => {
page: 1,
page_size: 5,
});
waitForElement(wrapper, 'CheckBoxListItem', el => el.length === 2);
waitForElement(wrapper, 'CheckBoxListItem', (el) => el.length === 2);
});
test('clicking on row fires callback with correct params', async () => {

View File

@ -15,7 +15,7 @@ function RolesStep({
selectedRoleRows,
}) {
return (
<Fragment>
<>
<div>
{t`Choose roles to apply to the selected resources. Note that all selected roles will be applied to all selected resources.`}
</div>
@ -37,12 +37,12 @@ function RolesStep({
marginTop: '20px',
}}
>
{Object.keys(roles).map(role => (
{Object.keys(roles).map((role) => (
<CheckboxCard
description={roles[role].description}
itemId={roles[role].id}
isSelected={selectedRoleRows.some(
item => item.id === roles[role].id
(item) => item.id === roles[role].id
)}
key={roles[role].id}
name={roles[role].name}
@ -50,7 +50,7 @@ function RolesStep({
/>
))}
</div>
</Fragment>
</>
);
}

View File

@ -39,7 +39,7 @@ function AnsibleSelect({
className={className}
isDisabled={isDisabled}
>
{data.map(option => (
{data.map((option) => (
<FormSelectOption
key={option.key}
value={option.value}

View File

@ -166,7 +166,7 @@ describe('<AppContainer />', () => {
// open about modal
(
await waitForElement(wrapper, aboutButton, el => !el.props().disabled)
await waitForElement(wrapper, aboutButton, (el) => !el.props().disabled)
).simulate('click');
// check about modal content

View File

@ -47,21 +47,19 @@ function PageHeaderToolbar({
const [isUserOpen, setIsUserOpen] = useState(false);
const config = useConfig();
const {
request: fetchPendingApprovalCount,
result: pendingApprovals,
} = useRequest(
useCallback(async () => {
const {
data: { count },
} = await WorkflowApprovalsAPI.read({
status: 'pending',
page_size: 1,
});
return count;
}, []),
0
);
const { request: fetchPendingApprovalCount, result: pendingApprovals } =
useRequest(
useCallback(async () => {
const {
data: { count },
} = await WorkflowApprovalsAPI.read({
status: 'pending',
page_size: 1,
});
return count;
}, []),
0
);
const pendingApprovalsCount = useWsPendingApprovalCount(
pendingApprovals,

View File

@ -6,9 +6,8 @@ export default function useWsPendingApprovalCount(
initialCount,
fetchApprovalsCount
) {
const [pendingApprovalCount, setPendingApprovalCount] = useState(
initialCount
);
const [pendingApprovalCount, setPendingApprovalCount] =
useState(initialCount);
const [reloadCount, setReloadCount] = useState(false);
const throttledFetch = useThrottle(reloadCount, 1000);
const lastMessage = useWebsocket({
@ -20,27 +19,21 @@ export default function useWsPendingApprovalCount(
setPendingApprovalCount(initialCount);
}, [initialCount]);
useEffect(
function reloadTheCount() {
(async () => {
if (!throttledFetch) {
return;
}
setReloadCount(false);
fetchApprovalsCount();
})();
},
[throttledFetch, fetchApprovalsCount]
);
useEffect(
function processWsMessage() {
if (lastMessage?.type === 'workflow_approval') {
setReloadCount(true);
useEffect(() => {
(async () => {
if (!throttledFetch) {
return;
}
},
[lastMessage]
);
setReloadCount(false);
fetchApprovalsCount();
})();
}, [throttledFetch, fetchApprovalsCount]);
useEffect(() => {
if (lastMessage?.type === 'workflow_approval') {
setReloadCount(true);
}
}, [lastMessage]);
return pendingApprovalCount;
}

View File

@ -25,7 +25,7 @@ describe('useWsPendingApprovalCount hook', () => {
*/
jest.mock('../../hooks/useThrottle', () => ({
__esModule: true,
default: jest.fn(val => val),
default: jest.fn((val) => val),
}));
debug = global.console.debug; // eslint-disable-line prefer-destructuring
global.console.debug = () => {};

View File

@ -1,4 +1,4 @@
import React, { Fragment, useEffect, useCallback } from 'react';
import React, { useEffect, useCallback } from 'react';
import { useHistory } from 'react-router-dom';
import { t } from '@lingui/macro';
@ -8,13 +8,12 @@ import { getQSConfig, parseQueryString } from 'util/qs';
import useSelected from 'hooks/useSelected';
import OptionsList from '../OptionsList';
const QS_CONFIG = (order_by = 'name') => {
return getQSConfig('associate', {
const QS_CONFIG = (order_by = 'name') =>
getQSConfig('associate', {
page: 1,
page_size: 5,
order_by,
});
};
function AssociateModal({
header = t`Items`,
@ -53,10 +52,10 @@ function AssociateModal({
itemCount: count,
relatedSearchableKeys: (
actionsResponse?.data?.related_search_fields || []
).map(val => val.slice(0, -8)),
).map((val) => val.slice(0, -8)),
searchableKeys: Object.keys(
actionsResponse.data.actions?.GET || {}
).filter(key => actionsResponse.data.actions?.GET[key].filterable),
).filter((key) => actionsResponse.data.actions?.GET[key].filterable),
};
}, [fetchRequest, optionsRequest, history.location.search, displayKey]),
{
@ -75,7 +74,7 @@ function AssociateModal({
const parts = history.location.search.replace(/^\?/, '').split('&');
const { namespace } = QS_CONFIG(displayKey);
const otherParts = parts.filter(
param => !param.startsWith(`${namespace}.`)
(param) => !param.startsWith(`${namespace}.`)
);
history.replace(`${history.location.pathname}?${otherParts.join('&')}`);
};
@ -92,7 +91,7 @@ function AssociateModal({
};
return (
<Fragment>
<>
<Modal
ouiaId={ouiaId}
variant="large"
@ -160,7 +159,7 @@ function AssociateModal({
relatedSearchableKeys={relatedSearchableKeys}
/>
</Modal>
</Fragment>
</>
);
}

View File

@ -41,7 +41,7 @@ describe('<AssociateModal />', () => {
/>
);
});
await waitForElement(wrapper, 'ContentLoading', el => el.length === 0);
await waitForElement(wrapper, 'ContentLoading', (el) => el.length === 0);
});
afterEach(() => {
@ -61,10 +61,7 @@ describe('<AssociateModal />', () => {
test('should update selected list chips when items are selected', () => {
expect(wrapper.find('SelectedList Chip')).toHaveLength(0);
act(() => {
wrapper
.find('CheckboxListItem')
.first()
.invoke('onSelect')();
wrapper.find('CheckboxListItem').first().invoke('onSelect')();
});
wrapper.update();
expect(wrapper.find('SelectedList Chip')).toHaveLength(1);
@ -74,10 +71,7 @@ describe('<AssociateModal />', () => {
test('save button should call onAssociate', () => {
act(() => {
wrapper
.find('CheckboxListItem')
.first()
.invoke('onSelect')();
wrapper.find('CheckboxListItem').first().invoke('onSelect')();
});
wrapper.find('button[aria-label="Save"]').simulate('click');
expect(onAssociate).toHaveBeenCalledTimes(1);

View File

@ -3,8 +3,8 @@ import React, { Fragment } from 'react';
import { BackgroundImage } from '@patternfly/react-core';
export default ({ children }) => (
<Fragment>
<>
<BackgroundImage />
{children}
</Fragment>
</>
);

View File

@ -43,7 +43,7 @@ const CheckboxListItem = ({
/>
{columns?.length > 0 ? (
columns.map(col => (
columns.map((col) => (
<Td aria-label={col.name} dataLabel={col.key} key={col.key}>
{item[col.key]}
</Td>

View File

@ -7,11 +7,8 @@ describe('ChipGroup', () => {
const wrapper = mountWithContexts(
<ChipGroup numChips={5} totalChips={10} />
);
expect(
wrapper
.find('ChipGroup')
.at(1)
.props().collapsedText
).toEqual('5 more');
expect(wrapper.find('ChipGroup').at(1).props().collapsedText).toEqual(
'5 more'
);
});
});

View File

@ -47,7 +47,7 @@ const AceEditor = styled(ReactAce)`
display: none;
}
${props =>
${(props) =>
props.hasErrors &&
`
&& {
@ -59,7 +59,7 @@ const AceEditor = styled(ReactAce)`
border-bottom-width: var(--pf-c-form-control--invalid--BorderBottomWidth);
}`}
${props =>
${(props) =>
props.setOptions.readOnly &&
`
&& .ace_cursor {
@ -92,21 +92,18 @@ function CodeEditor({
const wrapper = useRef(null);
const editor = useRef(null);
useEffect(
function removeTextareaTabIndex() {
const editorInput = editor.current.refEditor?.querySelector('textarea');
if (!editorInput) {
return;
}
if (!readOnly) {
editorInput.tabIndex = -1;
}
editorInput.id = id;
},
[readOnly, id]
);
useEffect(() => {
const editorInput = editor.current.refEditor?.querySelector('textarea');
if (!editorInput) {
return;
}
if (!readOnly) {
editorInput.tabIndex = -1;
}
editorInput.id = id;
}, [readOnly, id]);
const listen = useCallback(event => {
const listen = useCallback((event) => {
if (wrapper.current === document.activeElement && event.key === 'Enter') {
const editorInput = editor.current.refEditor?.querySelector('textarea');
if (!editorInput) {
@ -118,7 +115,7 @@ function CodeEditor({
}
}, []);
useEffect(function addKeyEventListeners() {
useEffect(() => {
const wrapperEl = wrapper.current;
wrapperEl.addEventListener('keydown', listen);

View File

@ -22,7 +22,7 @@ describe('CodeEditor', () => {
});
it('should trigger onChange prop', () => {
debounce.mockImplementation(fn => fn);
debounce.mockImplementation((fn) => fn);
const onChange = jest.fn();
const wrapper = mountWithContexts(
<CodeEditor value="---" onChange={onChange} mode="yaml" />

View File

@ -43,7 +43,7 @@ function CodeEditorField({
id={id}
{...rest}
{...field}
onChange={value => {
onChange={(value) => {
helpers.setValue(value);
}}
mode={mode}

View File

@ -196,7 +196,7 @@ function ModeToggle({
[JSON_MODE, 'JSON'],
]}
value={mode}
onChange={newMode => {
onChange={(newMode) => {
setMode(newMode);
}}
name={name}

View File

@ -39,7 +39,7 @@ function VariablesField({
const [shouldValidate, setShouldValidate] = useState(false);
const [mode, setMode] = useState(initialMode || YAML_MODE);
const validate = useCallback(
value => {
(value) => {
if (!shouldValidate) {
return undefined;
}
@ -58,7 +58,7 @@ function VariablesField({
);
const [field, meta, helpers] = useField({ name, validate });
useEffect(function initializeJSON() {
useEffect(() => {
if (isJsonString(field.value)) {
// mode's useState above couldn't be initialized to JSON_MODE because
// the field value had to be defined below it
@ -69,7 +69,7 @@ function VariablesField({
}, []); // eslint-disable-line react-hooks/exhaustive-deps
useEffect(
function validateOnBlur() {
() => {
if (shouldValidate) {
helpers.setError(validate(field.value));
}
@ -82,7 +82,7 @@ function VariablesField({
const [isJsonEdited, setIsJsonEdited] = useState(false);
const [isExpanded, setIsExpanded] = useState(false);
const handleModeChange = newMode => {
const handleModeChange = (newMode) => {
if (newMode === YAML_MODE && !isJsonEdited && lastYamlValue !== null) {
helpers.setValue(lastYamlValue, false);
setMode(newMode);
@ -103,7 +103,7 @@ function VariablesField({
}
};
const handleChange = newVal => {
const handleChange = (newVal) => {
helpers.setValue(newVal);
if (mode === JSON_MODE) {
setIsJsonEdited(true);
@ -201,7 +201,7 @@ function VariablesFieldInternals({
}) {
const [field, meta, helpers] = useField(name);
useEffect(function formatJsonString() {
useEffect(() => {
if (mode === YAML_MODE) {
return;
}

View File

@ -140,10 +140,7 @@ describe('VariablesField', () => {
)}
</Formik>
);
wrapper
.find('Button')
.at(1)
.simulate('click');
wrapper.find('Button').at(1).simulate('click');
wrapper.update();
const field = wrapper.find('CodeEditor');
@ -173,7 +170,7 @@ describe('VariablesField', () => {
const handleSubmit = jest.fn();
const wrapper = mountWithContexts(
<Formik initialValues={{ variables: value }} onSubmit={handleSubmit}>
{formik => (
{(formik) => (
<form onSubmit={formik.handleSubmit}>
<VariablesField id="the-field" name="variables" label="Variables" />
<button type="submit" id="submit">
@ -200,7 +197,7 @@ describe('VariablesField', () => {
await act(async () => {
wrapper = mountWithContexts(
<Formik initialValues={{ variables: value }} onSubmit={jest.fn()}>
{formik => (
{(formik) => (
<form onSubmit={formik.handleSubmit}>
<VariablesField
id="the-field"
@ -224,7 +221,7 @@ describe('VariablesField', () => {
const value = '---';
const wrapper = mountWithContexts(
<Formik initialValues={{ variables: value }} onSubmit={jest.fn()}>
{formik => (
{(formik) => (
<form onSubmit={formik.handleSubmit}>
<VariablesField id="the-field" name="variables" label="Variables" />
<button type="submit" id="submit">
@ -249,7 +246,7 @@ describe('VariablesField', () => {
await act(async () => {
wrapper = mountWithContexts(
<Formik initialValues={{ variables: value }} onSubmit={jest.fn()}>
{formik => (
{(formik) => (
<form onSubmit={formik.handleSubmit}>
<VariablesField
id="the-field"

View File

@ -26,7 +26,7 @@ function VariablesInput(props) {
const isControlled = !!props.onChange;
/* eslint-enable react/destructuring-assignment */
const onChange = newValue => {
const onChange = (newValue) => {
if (isControlled) {
props.onChange(newValue);
}
@ -48,7 +48,7 @@ function VariablesInput(props) {
[JSON_MODE, 'JSON'],
]}
value={mode}
onChange={newMode => {
onChange={(newMode) => {
try {
if (mode === JSON_MODE) {
onChange(jsonToYaml(value));

View File

@ -26,7 +26,7 @@ function ContentError({ error, children, isNotFound }) {
isNotFound || (error && error.response && error.response.status === 404);
const is401 = error && error.response && error.response.status === 401;
return (
<Fragment>
<>
{is401 ? (
<Redirect to="/login" />
) : (
@ -44,7 +44,7 @@ function ContentError({ error, children, isNotFound }) {
{error && <ErrorDetail error={error} />}
</EmptyState>
)}
</Fragment>
</>
);
}
ContentError.propTypes = {

View File

@ -13,13 +13,11 @@ const EmptyState = styled(PFEmptyState)`
`;
// TODO: Better loading state - skeleton lines / spinner, etc.
const ContentLoading = ({ className }) => {
return (
<EmptyState variant="full" className={className}>
<EmptyStateIcon variant="container" component={Spinner} />
</EmptyState>
);
};
const ContentLoading = ({ className }) => (
<EmptyState variant="full" className={className}>
<EmptyStateIcon variant="container" component={Spinner} />
</EmptyState>
);
export { ContentLoading as _ContentLoading };
export default ContentLoading;

View File

@ -16,9 +16,11 @@ function CopyButton({
errorMessage,
ouiaId,
}) {
const { isLoading, error: copyError, request: copyItemToAPI } = useRequest(
copyItem
);
const {
isLoading,
error: copyError,
request: copyItemToAPI,
} = useRequest(copyItem);
useEffect(() => {
if (isLoading) {

View File

@ -66,7 +66,7 @@ function DataListToolbar({
const dropdownPosition =
viewportWidth >= 992 ? DropdownPosition.right : DropdownPosition.left;
const onShowAdvancedSearch = shown => {
const onShowAdvancedSearch = (shown) => {
setIsAdvancedSearchShown(shown);
setIsKebabOpen(false);
};
@ -165,7 +165,7 @@ function DataListToolbar({
toggle={
<KebabToggle
data-cy="actions-kebab-toogle"
onToggle={isOpen => {
onToggle={(isOpen) => {
if (!isKebabModalOpen) {
setIsKebabOpen(isOpen);
}
@ -182,7 +182,7 @@ function DataListToolbar({
)}
{!isAdvancedSearchShown && (
<ToolbarGroup>
{additionalControls.map(control => (
{additionalControls.map((control) => (
<ToolbarItem key={control.key}>{control}</ToolbarItem>
))}
</ToolbarGroup>

View File

@ -245,7 +245,7 @@ describe('<DataListToolbar />', () => {
const search = toolbar.find('Search');
expect(
search.prop('columns').filter(col => col.key === 'advanced').length
search.prop('columns').filter((col) => col.key === 'advanced').length
).toBe(1);
});

View File

@ -34,7 +34,7 @@ function DeleteButton({
const [deleteDetails, setDeleteDetails] = useState({});
const [isLoading, setIsLoading] = useState(false);
const toggleModal = async isModalOpen => {
const toggleModal = async (isModalOpen) => {
setIsLoading(true);
if (deleteDetailsRequests?.length && isModalOpen) {
const { results, error } = await getRelatedResourceDeleteCounts(

View File

@ -42,7 +42,7 @@ describe('<DeleteButton />', () => {
wrapper.find('button').prop('onClick')();
});
await waitForElement(wrapper, 'Modal', el => el.length > 0);
await waitForElement(wrapper, 'Modal', (el) => el.length > 0);
expect(wrapper.find('Modal')).toHaveLength(1);
expect(wrapper.find('div[aria-label="Delete this?"]')).toHaveLength(1);

View File

@ -24,7 +24,7 @@ function ArrayDetail({ label, value, dataCy }) {
{label}
</DetailName>
<Value component={TextListItemVariants.dd} data-cy={valueCy}>
{vals.map(v => (
{vals.map((v) => (
<div key={v}>{v}</div>
))}
</Value>

View File

@ -8,7 +8,7 @@ const DetailName = styled(({ fullWidth, ...props }) => (
<TextListItem {...props} />
))`
font-weight: var(--pf-global--FontWeight--bold);
${props =>
${(props) =>
props.fullWidth &&
`
grid-column: 1;
@ -21,12 +21,12 @@ const DetailValue = styled(
)
)`
word-break: break-all;
${props =>
${(props) =>
props.fullWidth &&
`
grid-column: 2 / -1;
`}
${props =>
${(props) =>
(props.isEncrypted || props.isNotConfigured) &&
`
color: var(--pf-global--Color--400);

View File

@ -12,7 +12,7 @@ export default styled(DetailList)`
display: grid;
grid-gap: 20px;
align-items: start;
${props =>
${(props) =>
props.stacked
? `
grid-template-columns: auto 1fr;

View File

@ -41,7 +41,7 @@ function DisassociateButton({
if (verifyCannotDisassociate) {
const itemsUnableToDisassociate = itemsToDisassociate
.filter(cannotDisassociate)
.map(item => item.name)
.map((item) => item.name)
.join(', ');
if (itemsToDisassociate.some(cannotDisassociate)) {
@ -130,7 +130,7 @@ function DisassociateButton({
<div>{t`This action will disassociate the following:`}</div>
{itemsToDisassociate.map(item => (
{itemsToDisassociate.map((item) => (
<span key={item.id}>
<strong>{item.hostname ? item.hostname : item.name}</strong>
<br />

View File

@ -1,4 +1,4 @@
import React, { useState, Fragment } from 'react';
import React, { useState } from 'react';
import PropTypes from 'prop-types';
import styled from 'styled-components';
@ -48,7 +48,7 @@ function ErrorDetail({ error }) {
const message = getErrorMessage(response);
return (
<Fragment>
<>
<CardBody>
{response?.config?.method.toUpperCase()} {response?.config?.url}{' '}
<strong>{response?.status}</strong>
@ -56,7 +56,7 @@ function ErrorDetail({ error }) {
<CardBody>
{Array.isArray(message) ? (
<ul>
{message.map(m =>
{message.map((m) =>
typeof m === 'string' ? <li key={m}>{m}</li> : null
)}
</ul>
@ -64,13 +64,11 @@ function ErrorDetail({ error }) {
message
)}
</CardBody>
</Fragment>
</>
);
};
const renderStack = () => {
return <CardBody>{error.stack}</CardBody>;
};
const renderStack = () => <CardBody>{error.stack}</CardBody>;
return (
<Expandable

View File

@ -14,7 +14,7 @@ const Button = styled(PFButton)`
margin: 0;
height: 30px;
width: 30px;
${props =>
${(props) =>
props.isActive
? `
background-color: #007bba;
@ -33,7 +33,7 @@ const ToolbarItem = styled(PFToolbarItem)`
// with ExpandingContainer
function ExpandCollapse({ isCompact, onCompact, onExpand }) {
return (
<Fragment>
<>
<ToolbarItem>
<Button
ouiaId="toolbar-collapse-button"
@ -56,7 +56,7 @@ function ExpandCollapse({ isCompact, onCompact, onExpand }) {
<EqualsIcon />
</Button>
</ToolbarItem>
</Fragment>
</>
);
}

View File

@ -5,33 +5,31 @@ import { t } from '@lingui/macro';
import { ActionGroup, Button } from '@patternfly/react-core';
import { FormFullWidthLayout } from '../FormLayout';
const FormActionGroup = ({ onCancel, onSubmit, submitDisabled }) => {
return (
<FormFullWidthLayout>
<ActionGroup>
<Button
ouiaId="form-save-button"
aria-label={t`Save`}
variant="primary"
type="button"
onClick={onSubmit}
isDisabled={submitDisabled}
>
{t`Save`}
</Button>
<Button
ouiaId="form-cancel-button"
aria-label={t`Cancel`}
variant="link"
type="button"
onClick={onCancel}
>
{t`Cancel`}
</Button>
</ActionGroup>
</FormFullWidthLayout>
);
};
const FormActionGroup = ({ onCancel, onSubmit, submitDisabled }) => (
<FormFullWidthLayout>
<ActionGroup>
<Button
ouiaId="form-save-button"
aria-label={t`Save`}
variant="primary"
type="button"
onClick={onSubmit}
isDisabled={submitDisabled}
>
{t`Save`}
</Button>
<Button
ouiaId="form-cancel-button"
aria-label={t`Cancel`}
variant="link"
type="button"
onClick={onCancel}
>
{t`Cancel`}
</Button>
</ActionGroup>
</FormFullWidthLayout>
);
FormActionGroup.propTypes = {
onCancel: PropTypes.func.isRequired,

View File

@ -40,8 +40,8 @@ function ArrayTextField(props) {
{...rest}
{...field}
value={value.join('\n')}
onChange={val => {
helpers.setValue(val.split('\n').map(v => v.trim()));
onChange={(val) => {
helpers.setValue(val.split('\n').map((v) => v.trim()));
}}
/>
</FormGroup>

View File

@ -29,7 +29,7 @@ function FormSubmitError({ error }) {
isInline
title={
Array.isArray(errorMessage)
? errorMessage.map(msg => <div key={msg}>{msg}</div>)
? errorMessage.map((msg) => <div key={msg}>{msg}</div>)
: errorMessage
}
/>

View File

@ -28,7 +28,7 @@ export default function sortErrorMessages(error, formValues = {}) {
function parseFieldErrors(obj, formValues) {
let fieldErrors = {};
let formErrors = [];
Object.keys(obj).forEach(key => {
Object.keys(obj).forEach((key) => {
const value = obj[key];
if (typeof value === 'string') {
if (typeof formValues[key] === 'undefined') {

View File

@ -13,12 +13,11 @@ import Popover from '../Popover';
const InventoryLookupField = ({ isDisabled }) => {
const { setFieldValue, setFieldTouched } = useFormikContext();
const [inventoryField, inventoryMeta, inventoryHelpers] = useField(
'inventory'
);
const [inventoryField, inventoryMeta, inventoryHelpers] =
useField('inventory');
const handleInventoryUpdate = useCallback(
value => {
(value) => {
setFieldValue('inventory', value);
setFieldTouched('inventory', true, false);
},
@ -76,55 +75,53 @@ const HostForm = ({
isInventoryVisible,
submitError,
disableInventoryLookup,
}) => {
return (
<Formik
initialValues={{
name: host.name,
description: host.description,
inventory: host.summary_fields?.inventory || null,
variables: host.variables,
}}
onSubmit={handleSubmit}
>
{formik => (
<Form autoComplete="off" onSubmit={formik.handleSubmit}>
<FormColumnLayout>
<FormField
id="host-name"
name="name"
type="text"
label={t`Name`}
validate={required(null)}
isRequired
}) => (
<Formik
initialValues={{
name: host.name,
description: host.description,
inventory: host.summary_fields?.inventory || null,
variables: host.variables,
}}
onSubmit={handleSubmit}
>
{(formik) => (
<Form autoComplete="off" onSubmit={formik.handleSubmit}>
<FormColumnLayout>
<FormField
id="host-name"
name="name"
type="text"
label={t`Name`}
validate={required(null)}
isRequired
/>
<FormField
id="host-description"
name="description"
type="text"
label={t`Description`}
/>
{isInventoryVisible && (
<InventoryLookupField isDisabled={disableInventoryLookup} />
)}
<FormFullWidthLayout>
<VariablesField
id="host-variables"
name="variables"
label={t`Variables`}
/>
<FormField
id="host-description"
name="description"
type="text"
label={t`Description`}
/>
{isInventoryVisible && (
<InventoryLookupField isDisabled={disableInventoryLookup} />
)}
<FormFullWidthLayout>
<VariablesField
id="host-variables"
name="variables"
label={t`Variables`}
/>
</FormFullWidthLayout>
{submitError && <FormSubmitError error={submitError} />}
<FormActionGroup
onCancel={handleCancel}
onSubmit={formik.handleSubmit}
/>
</FormColumnLayout>
</Form>
)}
</Formik>
);
};
</FormFullWidthLayout>
{submitError && <FormSubmitError error={submitError} />}
<FormActionGroup
onCancel={handleCancel}
onSubmit={formik.handleSubmit}
/>
</FormColumnLayout>
</Form>
)}
</Formik>
);
HostForm.propTypes = {
handleCancel: func.isRequired,

View File

@ -1,5 +1,5 @@
import 'styled-components/macro';
import React, { Fragment, useState, useEffect, useCallback } from 'react';
import React, { useState, useEffect, useCallback } from 'react';
import { t } from '@lingui/macro';
import { Switch, Tooltip } from '@patternfly/react-core';
@ -20,7 +20,12 @@ function HostToggle({
const [isEnabled, setIsEnabled] = useState(host.enabled);
const [showError, setShowError] = useState(false);
const { result, isLoading, error, request: toggleHost } = useRequest(
const {
result,
isLoading,
error,
request: toggleHost,
} = useRequest(
useCallback(async () => {
await HostsAPI.update(host.id, {
enabled: !isEnabled,
@ -46,7 +51,7 @@ function HostToggle({
}, [error]);
return (
<Fragment>
<>
<Tooltip content={tooltip} position="top">
<Switch
className={className}
@ -75,7 +80,7 @@ function HostToggle({
<ErrorDetail error={error} />
</AlertModal>
)}
</Fragment>
</>
);
}

View File

@ -13,7 +13,12 @@ function InstanceToggle({ className, fetchInstances, instance, onToggle }) {
const [isEnabled, setIsEnabled] = useState(instance.enabled);
const [showError, setShowError] = useState(false);
const { result, isLoading, error, request: toggleInstance } = useRequest(
const {
result,
isLoading,
error,
request: toggleInstance,
} = useRequest(
useCallback(async () => {
await InstancesAPI.update(instance.id, { enabled: !isEnabled });
await fetchInstances();

View File

@ -23,9 +23,8 @@ function JobCancelButton({
}, [job.id, job.type]),
{}
);
const { error, dismissError: dismissCancelError } = useDismissableError(
cancelError
);
const { error, dismissError: dismissCancelError } =
useDismissableError(cancelError);
const isAlreadyCancelled = cancelError?.response?.status === 405;

View File

@ -58,10 +58,10 @@ function JobList({ defaultParams, showTypeColumn = false }) {
count: response.data.count,
relatedSearchableKeys: (
actionsResponse?.data?.related_search_fields || []
).map(val => val.slice(0, -8)),
).map((val) => val.slice(0, -8)),
searchableKeys: Object.keys(
actionsResponse.data.actions?.GET || {}
).filter(key => actionsResponse.data.actions?.GET[key].filterable),
).filter((key) => actionsResponse.data.actions?.GET[key].filterable),
};
},
[location] // eslint-disable-line react-hooks/exhaustive-deps
@ -79,7 +79,7 @@ function JobList({ defaultParams, showTypeColumn = false }) {
// TODO: update QS_CONFIG to be safe for deps array
const fetchJobsById = useCallback(
async ids => {
async (ids) => {
const params = parseQueryString(qsConfig, location.search);
params.id__in = ids.join(',');
const { data } = await UnifiedJobsAPI.read(params);
@ -90,40 +90,34 @@ function JobList({ defaultParams, showTypeColumn = false }) {
const jobs = useWsJobs(results, fetchJobsById, qsConfig);
const {
selected,
isAllSelected,
handleSelect,
selectAll,
clearSelected,
} = useSelected(jobs);
const { selected, isAllSelected, handleSelect, selectAll, clearSelected } =
useSelected(jobs);
const { expanded, isAllExpanded, handleExpand, expandAll } = useExpanded(
jobs
);
const { expanded, isAllExpanded, handleExpand, expandAll } =
useExpanded(jobs);
const {
error: cancelJobsError,
isLoading: isCancelLoading,
request: cancelJobs,
} = useRequest(
useCallback(async () => {
return Promise.all(
selected.map(job => {
if (isJobRunning(job.status)) {
return getJobModel(job.type).cancel(job.id);
}
return Promise.resolve();
})
);
}, [selected]),
useCallback(
async () =>
Promise.all(
selected.map((job) => {
if (isJobRunning(job.status)) {
return getJobModel(job.type).cancel(job.id);
}
return Promise.resolve();
})
),
[selected]
),
{}
);
const {
error: cancelError,
dismissError: dismissCancelError,
} = useDismissableError(cancelJobsError);
const { error: cancelError, dismissError: dismissCancelError } =
useDismissableError(cancelJobsError);
const {
isLoading: isDeleteLoading,
@ -131,13 +125,13 @@ function JobList({ defaultParams, showTypeColumn = false }) {
deletionError,
clearDeletionError,
} = useDeleteItems(
useCallback(() => {
return Promise.all(
selected.map(({ type, id }) => {
return getJobModel(type).destroy(id);
})
);
}, [selected]),
useCallback(
() =>
Promise.all(
selected.map(({ type, id }) => getJobModel(type).destroy(id))
),
[selected]
),
{
qsConfig,
allItemsSelected: isAllSelected,
@ -155,7 +149,7 @@ function JobList({ defaultParams, showTypeColumn = false }) {
clearSelected();
};
const cannotDeleteItems = selected.filter(job => isJobRunning(job.status));
const cannotDeleteItems = selected.filter((job) => isJobRunning(job.status));
return (
<>
@ -229,7 +223,7 @@ function JobList({ defaultParams, showTypeColumn = false }) {
clearSelected={clearSelected}
toolbarSearchableKeys={searchableKeys}
toolbarRelatedSearchableKeys={relatedSearchableKeys}
renderToolbar={props => (
renderToolbar={(props) => (
<DatalistToolbar
{...props}
isAllExpanded={isAllExpanded}
@ -246,7 +240,7 @@ function JobList({ defaultParams, showTypeColumn = false }) {
return item;
})}
pluralizedItemName={t`Jobs`}
cannotDelete={item =>
cannotDelete={(item) =>
isJobRunning(item.status) ||
!item.summary_fields.user_capabilities.delete
}
@ -270,12 +264,12 @@ function JobList({ defaultParams, showTypeColumn = false }) {
<JobListItem
key={job.id}
job={job}
isExpanded={expanded.some(row => row.id === job.id)}
isExpanded={expanded.some((row) => row.id === job.id)}
onExpand={() => handleExpand(job)}
isSuperUser={me?.is_superuser}
showTypeColumn={showTypeColumn}
onSelect={() => handleSelect(job)}
isSelected={selected.some(row => row.id === job.id)}
isSelected={selected.some((row) => row.id === job.id)}
rowIndex={index}
/>
)}

View File

@ -120,7 +120,7 @@ function waitForLoaded(wrapper) {
return waitForElement(
wrapper,
'JobList',
el => el.find('ContentLoading').length === 0
(el) => el.find('ContentLoading').length === 0
);
}
@ -167,35 +167,23 @@ describe('<JobList />', () => {
await waitForLoaded(wrapper);
act(() => {
wrapper
.find('JobListItem')
.first()
.invoke('onSelect')(mockItem);
wrapper.find('JobListItem').first().invoke('onSelect')(mockItem);
});
wrapper.update();
expect(
wrapper
.find('JobListItem')
.first()
.prop('isSelected')
).toEqual(true);
expect(wrapper.find('JobListItem').first().prop('isSelected')).toEqual(
true
);
expect(
wrapper.find('ToolbarDeleteButton').prop('itemsToDelete')
).toHaveLength(1);
act(() => {
wrapper
.find('JobListItem')
.first()
.invoke('onSelect')(mockItem);
wrapper.find('JobListItem').first().invoke('onSelect')(mockItem);
});
wrapper.update();
expect(
wrapper
.find('JobListItem')
.first()
.prop('isSelected')
).toEqual(false);
expect(wrapper.find('JobListItem').first().prop('isSelected')).toEqual(
false
);
expect(
wrapper.find('ToolbarDeleteButton').prop('itemsToDelete')
).toHaveLength(0);
@ -344,10 +332,7 @@ describe('<JobList />', () => {
});
await waitForLoaded(wrapper);
await act(async () => {
wrapper
.find('JobListItem')
.at(1)
.invoke('onSelect')();
wrapper.find('JobListItem').at(1).invoke('onSelect')();
});
wrapper.update();
@ -358,7 +343,7 @@ describe('<JobList />', () => {
await waitForElement(
wrapper,
'Modal',
el => el.props().isOpen === true && el.props().title === 'Error!'
(el) => el.props().isOpen === true && el.props().title === 'Error!'
);
});
@ -411,10 +396,7 @@ describe('<JobList />', () => {
});
await waitForLoaded(wrapper);
await act(async () => {
wrapper
.find('JobListItem')
.at(1)
.invoke('onSelect')();
wrapper.find('JobListItem').at(1).invoke('onSelect')();
});
wrapper.update();
@ -425,7 +407,7 @@ describe('<JobList />', () => {
await waitForElement(
wrapper,
'Modal',
el => el.props().isOpen === true && el.props().title === 'Error!'
(el) => el.props().isOpen === true && el.props().title === 'Error!'
);
});
});

View File

@ -41,10 +41,10 @@ function JobListCancelButton({ jobsToCancel, onCancel }) {
const renderTooltip = () => {
const cannotCancelPermissions = jobsToCancel
.filter(cannotCancelBecausePermissions)
.map(job => job.name);
.map((job) => job.name);
const cannotCancelNotRunning = jobsToCancel
.filter(cannotCancelBecauseNotRunning)
.map(job => job.name);
.map((job) => job.name);
const numJobsUnableToCancel = cannotCancelPermissions.concat(
cannotCancelNotRunning
).length;
@ -170,7 +170,7 @@ function JobListCancelButton({ jobsToCancel, onCancel }) {
other="This action will cancel the following jobs:"
/>
</div>
{jobsToCancel.map(job => (
{jobsToCancel.map((job) => (
<span key={job.id}>
<strong>{job.name}</strong>
<br />

View File

@ -222,7 +222,7 @@ function JobListItem({
label={t`Credentials`}
value={
<ChipGroup numChips={5} totalChips={credentials.length}>
{credentials.map(c => (
{credentials.map((c) => (
<CredentialChip key={c.id} credential={c} isReadOnly />
))}
</ChipGroup>
@ -235,7 +235,7 @@ function JobListItem({
label={t`Labels`}
value={
<ChipGroup numChips={5} totalChips={labels.results.length}>
{labels.results.map(l => (
{labels.results.map((l) => (
<Chip key={l.id} isReadOnly>
{l.name}
</Chip>

View File

@ -20,9 +20,9 @@ export default function useWsJobs(initialJobs, fetchJobsById, qsConfig) {
setJobs(initialJobs);
}, [initialJobs]);
const enqueueJobId = id => {
const enqueueJobId = (id) => {
if (!jobsToFetch.includes(id)) {
setJobsToFetch(ids => ids.concat(id));
setJobsToFetch((ids) => ids.concat(id));
}
};
useEffect(() => {
@ -33,7 +33,7 @@ export default function useWsJobs(initialJobs, fetchJobsById, qsConfig) {
setJobsToFetch([]);
const newJobs = await fetchJobsById(throttledJobsToFetch);
const deduplicated = newJobs.filter(
job => !jobs.find(j => j.id === job.id)
(job) => !jobs.find((j) => j.id === job.id)
);
if (deduplicated.length) {
const params = parseQueryString(qsConfig, location.search);
@ -56,7 +56,7 @@ export default function useWsJobs(initialJobs, fetchJobsById, qsConfig) {
}
const jobId = lastMessage.unified_job_id;
const index = jobs.findIndex(j => j.id === jobId);
const index = jobs.findIndex((j) => j.id === jobId);
if (index > -1) {
setJobs(sortJobs(updateJob(jobs, index, lastMessage), params));
} else {

View File

@ -23,7 +23,7 @@ describe('useWsJobs hook', () => {
*/
jest.mock('../../hooks/useThrottle', () => ({
__esModule: true,
default: jest.fn(val => val),
default: jest.fn((val) => val),
}));
debug = global.console.debug; // eslint-disable-line prefer-destructuring
global.console.debug = () => {};

View File

@ -1,4 +1,4 @@
import React, { Fragment, useState } from 'react';
import React, { useState } from 'react';
import { withRouter } from 'react-router-dom';
import { number, shape } from 'prop-types';
@ -71,7 +71,7 @@ function LaunchButton({ resource, children, history }) {
}
};
const launchWithParams = async params => {
const launchWithParams = async (params) => {
try {
let jobPromise;
@ -94,7 +94,7 @@ function LaunchButton({ resource, children, history }) {
}
};
const handleRelaunch = async params => {
const handleRelaunch = async (params) => {
let readRelaunch;
let relaunch;
@ -148,7 +148,7 @@ function LaunchButton({ resource, children, history }) {
};
return (
<Fragment>
<>
{children({
handleLaunch,
handleRelaunch,
@ -174,7 +174,7 @@ function LaunchButton({ resource, children, history }) {
onCancel={() => setShowLaunchPrompt(false)}
/>
)}
</Fragment>
</>
);
}

View File

@ -21,7 +21,7 @@ function ReLaunchDropDown({
const [isOpen, setIsOpen] = useState(false);
const onToggle = () => {
setIsOpen(prev => !prev);
setIsOpen((prev) => !prev);
};
const dropdownItems = [

View File

@ -41,7 +41,7 @@ function PromptModalForm({
setValue('inventory_id', values.inventory?.id);
setValue(
'credentials',
values.credentials?.map(c => c.id)
values.credentials?.map((c) => c.id)
);
setValue('job_type', values.job_type);
setValue('limit', values.limit);
@ -78,7 +78,7 @@ function PromptModalForm({
isOpen
onClose={onCancel}
onSave={handleSubmit}
onBack={async nextStep => {
onBack={async (nextStep) => {
validateStep(nextStep.id);
}}
onNext={async (nextStep, prevStep) => {
@ -141,9 +141,9 @@ function LaunchPrompt({
resourceDefaultCredentials = [],
}) {
return (
<Formik initialValues={{}} onSubmit={values => onLaunch(values)}>
<Formik initialValues={{}} onSubmit={(values) => onLaunch(values)}>
<PromptModalForm
onSubmit={values => onLaunch(values)}
onSubmit={(values) => onLaunch(values)}
onCancel={onCancel}
launchConfig={launchConfig}
surveyConfig={surveyConfig}

View File

@ -19,7 +19,7 @@ function CredentialPasswordsStep({ launchConfig }) {
!launchConfig.ask_credential_on_launch &&
launchConfig.passwords_needed_to_start
) {
launchConfig.passwords_needed_to_start.forEach(password => {
launchConfig.passwords_needed_to_start.forEach((password) => {
if (password === 'ssh_password') {
showcredentialPasswordSsh = true;
} else if (password === 'become_password') {
@ -32,10 +32,10 @@ function CredentialPasswordsStep({ launchConfig }) {
}
});
} else if (credentials) {
credentials.forEach(credential => {
credentials.forEach((credential) => {
if (!credential.inputs) {
const launchConfigCredential = launchConfig.defaults.credentials.find(
defaultCred => defaultCred.id === credential.id
(defaultCred) => defaultCred.id === credential.id
);
if (launchConfigCredential?.passwords_needed.length > 0) {
@ -56,10 +56,10 @@ function CredentialPasswordsStep({ launchConfig }) {
}
const vaultPasswordIds = launchConfigCredential.passwords_needed
.filter(passwordNeeded =>
.filter((passwordNeeded) =>
passwordNeeded.startsWith('vault_password')
)
.map(vaultPassword => vaultPassword.split(/\.(.+)/)[1] || '');
.map((vaultPassword) => vaultPassword.split(/\.(.+)/)[1] || '');
vaultsThatPrompt.push(...vaultPasswordIds);
}
@ -85,7 +85,7 @@ function CredentialPasswordsStep({ launchConfig }) {
return (
<Form
onSubmit={e => {
onSubmit={(e) => {
e.preventDefault();
}}
>
@ -113,7 +113,7 @@ function CredentialPasswordsStep({ launchConfig }) {
isRequired
/>
)}
{vaultsThatPrompt.map(credId => (
{vaultsThatPrompt.map((credId) => (
<PasswordField
id={`launch-vault-password-${credId}`}
key={credId}

View File

@ -32,13 +32,12 @@ function CredentialsStep({
}) {
const [field, meta, helpers] = useField({
name: 'credentials',
validate: val => {
return credentialsValidator(
validate: (val) =>
credentialsValidator(
defaultCredentials,
allowCredentialsWithPasswords,
val
);
},
),
});
const [selectedType, setSelectedType] = useState(null);
const history = useHistory();
@ -53,7 +52,7 @@ function CredentialsStep({
const loadedTypes = await CredentialTypesAPI.loadAllTypes();
if (loadedTypes.length) {
const match =
loadedTypes.find(type => type.kind === 'ssh') || loadedTypes[0];
loadedTypes.find((type) => type.kind === 'ssh') || loadedTypes[0];
setSelectedType(match);
}
return loadedTypes;
@ -88,10 +87,10 @@ function CredentialsStep({
count: data.count,
relatedSearchableKeys: (
actionsResponse?.data?.related_search_fields || []
).map(val => val.slice(0, -8)),
).map((val) => val.slice(0, -8)),
searchableKeys: Object.keys(
actionsResponse.data.actions?.GET || {}
).filter(key => actionsResponse.data.actions?.GET[key].filterable),
).filter((key) => actionsResponse.data.actions?.GET[key].filterable),
};
}, [selectedType, history.location.search]),
{ credentials: [], count: 0, relatedSearchableKeys: [], searchableKeys: [] }
@ -122,17 +121,15 @@ function CredentialsStep({
const isVault = selectedType?.kind === 'vault';
const renderChip = ({ item, removeItem, canDelete }) => {
return (
<CredentialChip
id={`credential-chip-${item.id}`}
key={item.id}
onClick={() => removeItem(item)}
isReadOnly={!canDelete}
credential={item}
/>
);
};
const renderChip = ({ item, removeItem, canDelete }) => (
<CredentialChip
id={`credential-chip-${item.id}`}
key={item.id}
onClick={() => removeItem(item)}
isReadOnly={!canDelete}
credential={item}
/>
);
return (
<>
@ -148,7 +145,7 @@ function CredentialsStep({
css="flex: 1 1 75%;"
id="multiCredentialsLookUp-select"
label={t`Selected Category`}
data={types.map(type => ({
data={types.map((type) => ({
key: type.id,
value: type.id,
label: type.name,
@ -156,7 +153,7 @@ function CredentialsStep({
}))}
value={selectedType && selectedType.id}
onChange={(e, id) => {
setSelectedType(types.find(o => o.id === parseInt(id, 10)));
setSelectedType(types.find((o) => o.id === parseInt(id, 10)));
}}
/>
</ToolbarItem>
@ -194,20 +191,20 @@ function CredentialsStep({
name="credentials"
qsConfig={QS_CONFIG}
readOnly={false}
selectItem={item => {
const hasSameVaultID = val =>
selectItem={(item) => {
const hasSameVaultID = (val) =>
val?.inputs?.vault_id !== undefined &&
val?.inputs?.vault_id === item?.inputs?.vault_id;
const hasSameCredentialType = val =>
const hasSameCredentialType = (val) =>
val.credential_type === item.credential_type;
const newItems = field.value.filter(i =>
const newItems = field.value.filter((i) =>
isVault ? !hasSameVaultID(i) : !hasSameCredentialType(i)
);
newItems.push(item);
helpers.setValue(newItems);
}}
deselectItem={item => {
helpers.setValue(field.value.filter(i => i.id !== item.id));
deselectItem={(item) => {
helpers.setValue(field.value.filter((i) => i.id !== item.id));
}}
renderItemChip={renderChip}
/>

View File

@ -180,19 +180,11 @@ describe('CredentialsStep', () => {
wrapper.update();
expect(wrapper.find('Alert').length).toBe(0);
await act(async () => {
wrapper
.find('td#check-action-item-2')
.find('input')
.simulate('click');
wrapper.find('td#check-action-item-2').find('input').simulate('click');
});
wrapper.update();
expect(wrapper.find('Alert').length).toBe(1);
expect(
wrapper
.find('Alert')
.text()
.includes('Cred 2')
).toBe(true);
expect(wrapper.find('Alert').text().includes('Cred 2')).toBe(true);
});
test('error should be toggled when default machine credential is removed and then replaced', async () => {
@ -234,17 +226,9 @@ describe('CredentialsStep', () => {
});
wrapper.update();
expect(wrapper.find('Alert').length).toBe(1);
expect(
wrapper
.find('Alert')
.text()
.includes('Machine')
).toBe(true);
expect(wrapper.find('Alert').text().includes('Machine')).toBe(true);
await act(async () => {
wrapper
.find('td#check-action-item-5')
.find('input')
.simulate('click');
wrapper.find('td#check-action-item-5').find('input').simulate('click');
});
wrapper.update();
expect(wrapper.find('Alert').length).toBe(0);
@ -307,21 +291,13 @@ describe('CredentialsStep', () => {
wrapper.update();
expect(wrapper.find('CredentialChip').length).toBe(1);
expect(wrapper.find('Alert').length).toBe(1);
expect(
wrapper
.find('Alert')
.text()
.includes('Vault | foo')
).toBe(true);
expect(wrapper.find('Alert').text().includes('Vault | foo')).toBe(true);
await act(async () => {
wrapper.find('AnsibleSelect').invoke('onChange')({}, 3);
});
wrapper.update();
await act(async () => {
wrapper
.find('td#check-action-item-33')
.find('input')
.simulate('click');
wrapper.find('td#check-action-item-33').find('input').simulate('click');
});
wrapper.update();
expect(wrapper.find('Alert').length).toBe(0);

View File

@ -44,10 +44,10 @@ function InventoryStep({ warningMessage = null }) {
count: data.count,
relatedSearchableKeys: (
actionsResponse?.data?.related_search_fields || []
).map(val => val.slice(0, -8)),
).map((val) => val.slice(0, -8)),
searchableKeys: Object.keys(
actionsResponse.data.actions?.GET || {}
).filter(key => actionsResponse.data.actions?.GET[key].filterable),
).filter((key) => actionsResponse.data.actions?.GET[key].filterable),
};
}, [history.location]),
{

View File

@ -23,7 +23,7 @@ const FieldHeader = styled.div`
function OtherPromptsStep({ launchConfig, variablesMode, onVarModeChange }) {
return (
<Form
onSubmit={e => {
onSubmit={(e) => {
e.preventDefault();
}}
>

View File

@ -37,8 +37,8 @@ function PreviewStep({ resource, launchConfig, surveyConfig, formErrors }) {
launchConfig.ask_variables_on_launch && (overrides.extra_vars || '---');
if (surveyConfig?.spec) {
const passwordFields = surveyConfig.spec
.filter(q => q.type === 'password')
.map(q => q.variable);
.filter((q) => q.type === 'password')
.map((q) => q.variable);
const masked = maskPasswords(surveyValues, passwordFields);
overrides.extra_vars = yaml.safeDump(
mergeExtraVars(initialExtraVars, masked)
@ -54,7 +54,7 @@ function PreviewStep({ resource, launchConfig, surveyConfig, formErrors }) {
}
return (
<Fragment>
<>
{formErrors && (
<ErrorMessageWrapper>
{t`Some of the previous step(s) have errors`}
@ -72,7 +72,7 @@ function PreviewStep({ resource, launchConfig, surveyConfig, formErrors }) {
launchConfig={launchConfig}
overrides={overrides}
/>
</Fragment>
</>
);
}

View File

@ -32,11 +32,11 @@ function SurveyStep({ surveyConfig }) {
};
return (
<Form
onSubmit={e => {
onSubmit={(e) => {
e.preventDefault();
}}
>
{surveyConfig.spec.map(question => {
{surveyConfig.spec.map((question) => {
const Field = fieldTypes[question.type];
return <Field key={question.variable} question={question} />;
})}
@ -131,7 +131,7 @@ function MultipleChoiceField({ question }) {
helpers.setValue('');
}}
>
{options.map(opt => (
{options.map((opt) => (
<SelectOption key={opt} value={opt} />
))}
</Select>
@ -175,7 +175,7 @@ function MultiSelectField({ question }) {
onToggle={setIsOpen}
onSelect={(event, option) => {
if (field?.value?.includes(option)) {
helpers.setValue(field.value.filter(o => o !== option));
helpers.setValue(field.value.filter((o) => o !== option));
} else {
helpers.setValue(field.value.concat(option));
}
@ -188,7 +188,7 @@ function MultiSelectField({ question }) {
helpers.setValue([]);
}}
>
{options.map(opt => (
{options.map((opt) => (
<SelectOption key={opt} value={opt} />
))}
</Select>

View File

@ -1,6 +1,6 @@
import { t } from '@lingui/macro';
const credentialPromptsForPassword = credential =>
const credentialPromptsForPassword = (credential) =>
credential?.inputs?.password === 'ASK' ||
credential?.inputs?.ssh_key_unlock === 'ASK' ||
credential?.inputs?.become_password === 'ASK' ||
@ -13,10 +13,10 @@ export default function credentialsValidator(
) {
if (defaultCredentials.length > 0 && selectedCredentials) {
const missingCredentialTypes = [];
defaultCredentials.forEach(defaultCredential => {
defaultCredentials.forEach((defaultCredential) => {
if (
!selectedCredentials.find(selectedCredential => {
return (
!selectedCredentials.find(
(selectedCredential) =>
(selectedCredential?.credential_type ===
defaultCredential?.credential_type &&
!selectedCredential.inputs?.vault_id &&
@ -24,8 +24,7 @@ export default function credentialsValidator(
(defaultCredential.inputs?.vault_id &&
selectedCredential.inputs?.vault_id ===
defaultCredential.inputs?.vault_id)
);
})
)
) {
missingCredentialTypes.push(
defaultCredential.inputs?.vault_id
@ -44,7 +43,7 @@ export default function credentialsValidator(
if (!allowCredentialsWithPasswords && selectedCredentials) {
const credentialsThatPrompt = [];
selectedCredentials.forEach(selectedCredential => {
selectedCredentials.forEach((selectedCredential) => {
if (credentialPromptsForPassword(selectedCredential)) {
credentialsThatPrompt.push(selectedCredential.name);
}

View File

@ -6,9 +6,7 @@ import StepName from './StepName';
const STEP_ID = 'credentialPasswords';
const isValueMissing = val => {
return !val || val === '';
};
const isValueMissing = (val) => !val || val === '';
export default function useCredentialPasswordsStep(
launchConfig,
@ -38,8 +36,8 @@ export default function useCredentialPasswordsStep(
isReady: true,
contentError: null,
hasError,
setTouched: setFieldTouched => {
Object.keys(values.credential_passwords).forEach(credentialValueKey =>
setTouched: (setFieldTouched) => {
Object.keys(values.credential_passwords).forEach((credentialValueKey) =>
setFieldTouched(
`credential_passwords['${credentialValueKey}']`,
true,
@ -48,7 +46,7 @@ export default function useCredentialPasswordsStep(
);
},
validate: () => {
const setPasswordFieldError = fieldName => {
const setPasswordFieldError = (fieldName) => {
setFieldError(fieldName, t`This field may not be blank`);
};
@ -56,20 +54,21 @@ export default function useCredentialPasswordsStep(
!launchConfig.ask_credential_on_launch &&
launchConfig.passwords_needed_to_start
) {
launchConfig.passwords_needed_to_start.forEach(password => {
launchConfig.passwords_needed_to_start.forEach((password) => {
if (isValueMissing(values.credential_passwords[password])) {
setPasswordFieldError(`credential_passwords['${password}']`);
}
});
} else if (values.credentials) {
values.credentials.forEach(credential => {
values.credentials.forEach((credential) => {
if (!credential.inputs) {
const launchConfigCredential = launchConfig.defaults.credentials.find(
defaultCred => defaultCred.id === credential.id
);
const launchConfigCredential =
launchConfig.defaults.credentials.find(
(defaultCred) => defaultCred.id === credential.id
);
if (launchConfigCredential?.passwords_needed.length > 0) {
launchConfigCredential.passwords_needed.forEach(password => {
launchConfigCredential.passwords_needed.forEach((password) => {
if (isValueMissing(values.credential_passwords[password])) {
setPasswordFieldError(`credential_passwords['${password}']`);
}
@ -137,20 +136,20 @@ function getInitialValues(launchConfig, selectedCredentials = []) {
!launchConfig.ask_credential_on_launch &&
launchConfig.passwords_needed_to_start
) {
launchConfig.passwords_needed_to_start.forEach(password => {
launchConfig.passwords_needed_to_start.forEach((password) => {
initialValues.credential_passwords[password] = '';
});
return initialValues;
}
selectedCredentials.forEach(credential => {
selectedCredentials.forEach((credential) => {
if (!credential.inputs) {
const launchConfigCredential = launchConfig.defaults.credentials.find(
defaultCred => defaultCred.id === credential.id
(defaultCred) => defaultCred.id === credential.id
);
if (launchConfigCredential?.passwords_needed.length > 0) {
launchConfigCredential.passwords_needed.forEach(password => {
launchConfigCredential.passwords_needed.forEach((password) => {
initialValues.credential_passwords[password] = '';
});
}
@ -189,20 +188,20 @@ function checkForError(launchConfig, values) {
!launchConfig.ask_credential_on_launch &&
launchConfig.passwords_needed_to_start
) {
launchConfig.passwords_needed_to_start.forEach(password => {
launchConfig.passwords_needed_to_start.forEach((password) => {
if (isValueMissing(values.credential_passwords[password])) {
hasError = true;
}
});
} else if (values.credentials) {
values.credentials.forEach(credential => {
values.credentials.forEach((credential) => {
if (!credential.inputs) {
const launchConfigCredential = launchConfig.defaults.credentials.find(
defaultCred => defaultCred.id === credential.id
(defaultCred) => defaultCred.id === credential.id
);
if (launchConfigCredential?.passwords_needed.length > 0) {
launchConfigCredential.passwords_needed.forEach(password => {
launchConfigCredential.passwords_needed.forEach((password) => {
if (isValueMissing(values.credential_passwords[password])) {
hasError = true;
}

View File

@ -29,7 +29,7 @@ export default function useCredentialsStep(
isReady: true,
contentError: null,
hasError: launchConfig.ask_credential_on_launch && formError,
setTouched: setFieldTouched => {
setTouched: (setFieldTouched) => {
setFieldTouched('credentials', true, false);
},
validate: () => {

View File

@ -27,7 +27,7 @@ export default function useInventoryStep(launchConfig, resource, visitedSteps) {
isReady: true,
contentError: null,
hasError: launchConfig.ask_inventory_on_launch && formError,
setTouched: setFieldTouched => {
setTouched: (setFieldTouched) => {
setFieldTouched('inventory', true, false);
},
validate: () => {

View File

@ -9,7 +9,7 @@ const STEP_ID = 'other';
export const YAML_MODE = 'yaml';
export const JSON_MODE = 'javascript';
const getVariablesData = resource => {
const getVariablesData = (resource) => {
if (resource?.extra_data) {
return jsonToYaml(JSON.stringify(resource.extra_data));
}
@ -34,7 +34,7 @@ export default function useOtherPromptsStep(launchConfig, resource) {
const [variablesMode, setVariablesMode] = useState(null);
const [isTouched, setIsTouched] = useState(false);
const handleModeChange = mode => {
const handleModeChange = (mode) => {
setVariablesMode(mode);
};
@ -63,9 +63,11 @@ export default function useOtherPromptsStep(launchConfig, resource) {
isReady: true,
contentError: null,
hasError,
setTouched: setFieldTouched => {
setTouched: (setFieldTouched) => {
setIsTouched(true);
FIELD_NAMES.forEach(fieldName => setFieldTouched(fieldName, true, false));
FIELD_NAMES.forEach((fieldName) =>
setFieldTouched(fieldName, true, false)
);
},
validate: () => {},
};

View File

@ -35,17 +35,17 @@ export default function useSurveyStep(
isReady: true,
contentError: null,
hasError,
setTouched: setFieldTouched => {
setTouched: (setFieldTouched) => {
if (!surveyConfig?.spec) {
return;
}
surveyConfig.spec.forEach(question => {
surveyConfig.spec.forEach((question) => {
setFieldTouched(`survey_${question.variable}`, true, false);
});
},
validate: () => {
if (launchConfig.survey_enabled && surveyConfig.spec) {
surveyConfig.spec.forEach(question => {
surveyConfig.spec.forEach((question) => {
const errMessage = validateSurveyField(
question,
values[`survey_${question.variable}`]
@ -66,7 +66,7 @@ function getInitialValues(launchConfig, surveyConfig, resource) {
const values = {};
if (surveyConfig?.spec) {
surveyConfig.spec.forEach(question => {
surveyConfig.spec.forEach((question) => {
if (question.type === 'multiselect') {
values[`survey_${question.variable}`] = question.default
? question.default.split('\n')
@ -116,7 +116,7 @@ function validateSurveyField(question, value) {
function checkForError(launchConfig, surveyConfig, values) {
let hasError = false;
if (launchConfig.survey_enabled && surveyConfig.spec) {
surveyConfig.spec.forEach(question => {
surveyConfig.spec.forEach((question) => {
const value = values[`survey_${question.variable}`];
const isTextField = ['text', 'textarea'].includes(question.type);
const isNumeric = ['integer', 'float'].includes(question.type);

View File

@ -17,10 +17,10 @@ function showCredentialPasswordsStep(credentials = [], launchConfig) {
let credentialPasswordStepRequired = false;
credentials.forEach(credential => {
credentials.forEach((credential) => {
if (!credential.inputs) {
const launchConfigCredential = launchConfig.defaults.credentials.find(
defaultCred => defaultCred.id === credential.id
(defaultCred) => defaultCred.id === credential.id
);
if (launchConfigCredential?.passwords_needed.length > 0) {
@ -60,30 +60,31 @@ export default function useLaunchSteps(launchConfig, surveyConfig, resource) {
useSurveyStep(launchConfig, surveyConfig, resource, visited),
];
const { resetForm } = useFormikContext();
const hasErrors = steps.some(step => step.hasError);
const hasErrors = steps.some((step) => step.hasError);
steps.push(
usePreviewStep(launchConfig, resource, surveyConfig, hasErrors, true)
);
const pfSteps = steps.map(s => s.step).filter(s => s != null);
const stepsAreReady = !steps.some(s => !s.isReady);
const pfSteps = steps.map((s) => s.step).filter((s) => s != null);
const stepsAreReady = !steps.some((s) => !s.isReady);
useEffect(() => {
if (!stepsAreReady) {
return;
}
const initialValues = steps.reduce((acc, cur) => {
return {
const initialValues = steps.reduce(
(acc, cur) => ({
...acc,
...cur.initialValues,
};
}, {});
}),
{}
);
const newFormValues = { ...initialValues };
Object.keys(formikValues).forEach(formikValueKey => {
Object.keys(formikValues).forEach((formikValueKey) => {
if (
formikValueKey === 'credential_passwords' &&
Object.prototype.hasOwnProperty.call(
@ -93,7 +94,7 @@ export default function useLaunchSteps(launchConfig, surveyConfig, resource) {
) {
const formikCredentialPasswords = formikValues.credential_passwords;
Object.keys(formikCredentialPasswords).forEach(
credentialPasswordValueKey => {
(credentialPasswordValueKey) => {
if (
Object.prototype.hasOwnProperty.call(
newFormValues.credential_passwords,
@ -121,23 +122,23 @@ export default function useLaunchSteps(launchConfig, surveyConfig, resource) {
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [formikValues.credentials, stepsAreReady]);
const stepWithError = steps.find(s => s.contentError);
const stepWithError = steps.find((s) => s.contentError);
const contentError = stepWithError ? stepWithError.contentError : null;
return {
steps: pfSteps,
isReady,
validateStep: stepId => {
steps.find(s => s?.step?.id === stepId).validate();
validateStep: (stepId) => {
steps.find((s) => s?.step?.id === stepId).validate();
},
visitStep: (prevStepId, setFieldTouched) => {
setVisited({
...visited,
[prevStepId]: true,
});
steps.find(s => s?.step?.id === prevStepId).setTouched(setFieldTouched);
steps.find((s) => s?.step?.id === prevStepId).setTouched(setFieldTouched);
},
visitAllSteps: setFieldTouched => {
visitAllSteps: (setFieldTouched) => {
setVisited({
inventory: true,
credentials: true,
@ -146,7 +147,7 @@ export default function useLaunchSteps(launchConfig, surveyConfig, resource) {
survey: true,
preview: true,
});
steps.forEach(s => s.setTouched(setFieldTouched));
steps.forEach((s) => s.setTouched(setFieldTouched));
},
contentError,
};

View File

@ -66,7 +66,7 @@ class ListHeader extends React.Component {
handleRemoveAll() {
const { location, qsConfig } = this.props;
const oldParams = parseQueryString(qsConfig, location.search);
Object.keys(oldParams).forEach(key => {
Object.keys(oldParams).forEach((key) => {
oldParams[key] = null;
});
delete oldParams.page_size;
@ -106,7 +106,7 @@ class ListHeader extends React.Component {
const params = parseQueryString(qsConfig, location.search);
const isEmpty = itemCount === 0 && Object.keys(params).length === 0;
return (
<Fragment>
<>
{isEmpty ? (
<Toolbar
id={`${qsConfig.namespace}-list-toolbar`}
@ -120,7 +120,7 @@ class ListHeader extends React.Component {
</ToolbarContent>
</Toolbar>
) : (
<Fragment>
<>
{renderToolbar({
itemCount,
searchColumns,
@ -135,9 +135,9 @@ class ListHeader extends React.Component {
qsConfig,
pagination,
})}
</Fragment>
</>
)}
</Fragment>
</>
);
}
}
@ -153,7 +153,7 @@ ListHeader.propTypes = {
};
ListHeader.defaultProps = {
renderToolbar: props => <DataListToolbar {...props} />,
renderToolbar: (props) => <DataListToolbar {...props} />,
searchableKeys: [],
sortColumns: null,
relatedSearchableKeys: [],

View File

@ -41,10 +41,10 @@ function ApplicationLookup({ onChange, value, label, fieldName, validate }) {
itemCount: count,
relatedSearchableKeys: (
actionsResponse?.data?.related_search_fields || []
).map(val => val.slice(0, -8)),
).map((val) => val.slice(0, -8)),
searchableKeys: Object.keys(
actionsResponse?.data?.actions?.GET || {}
).filter(key => actionsResponse.data.actions?.GET[key].filterable),
).filter((key) => actionsResponse.data.actions?.GET[key].filterable),
};
}, [location]),
{
@ -56,7 +56,7 @@ function ApplicationLookup({ onChange, value, label, fieldName, validate }) {
);
const checkApplicationName = useCallback(
async name => {
async (name) => {
if (!name) {
onChange(null);
return;
@ -128,8 +128,8 @@ function ApplicationLookup({ onChange, value, label, fieldName, validate }) {
relatedSearchableKeys={relatedSearchableKeys}
readOnly={!canDelete}
name="application"
selectItem={item => dispatch({ type: 'SELECT_ITEM', item })}
deselectItem={item => dispatch({ type: 'DESELECT_ITEM', item })}
selectItem={(item) => dispatch({ type: 'SELECT_ITEM', item })}
deselectItem={(item) => dispatch({ type: 'DESELECT_ITEM', item })}
/>
)}
/>

View File

@ -84,7 +84,7 @@ function CredentialLookup({
const searchKeys = Object.keys(
actionsResponse.data.actions?.GET || {}
).filter(key => actionsResponse.data.actions?.GET[key].filterable);
).filter((key) => actionsResponse.data.actions?.GET[key].filterable);
const item = searchKeys.indexOf('type');
if (item) {
searchKeys[item] = 'credential_type__kind';
@ -95,7 +95,7 @@ function CredentialLookup({
credentials: data.results,
relatedSearchableKeys: (
actionsResponse?.data?.related_search_fields || []
).map(val => val.slice(0, -8)),
).map((val) => val.slice(0, -8)),
searchableKeys: searchKeys,
};
}, [
@ -115,7 +115,7 @@ function CredentialLookup({
);
const checkCredentialName = useCallback(
async name => {
async (name) => {
if (!name) {
onChange(null);
return;
@ -209,9 +209,9 @@ function CredentialLookup({
relatedSearchableKeys={relatedSearchableKeys}
readOnly={!canDelete}
name="credential"
selectItem={item => dispatch({ type: 'SELECT_ITEM', item })}
deselectItem={item => dispatch({ type: 'DESELECT_ITEM', item })}
sortSelectedItems={selectedItems =>
selectItem={(item) => dispatch({ type: 'SELECT_ITEM', item })}
deselectItem={(item) => dispatch({ type: 'DESELECT_ITEM', item })}
sortSelectedItems={(selectedItems) =>
dispatch({ type: 'SET_SELECTED_ITEMS', selectedItems })
}
multiple={multiple}

View File

@ -107,10 +107,10 @@ function ExecutionEnvironmentLookup({
count: data.count,
relatedSearchableKeys: (
actionsResponse?.data?.related_search_fields || []
).map(val => val.slice(0, -8)),
).map((val) => val.slice(0, -8)),
searchableKeys: Object.keys(
actionsResponse.data.actions?.GET || {}
).filter(key => actionsResponse.data.actions?.GET[key].filterable),
).filter((key) => actionsResponse.data.actions?.GET[key].filterable),
};
}, [
location,
@ -129,7 +129,7 @@ function ExecutionEnvironmentLookup({
);
const checkExecutionEnvironmentName = useCallback(
async name => {
async (name) => {
if (!name) {
onChange(null);
return;
@ -190,8 +190,8 @@ function ExecutionEnvironmentLookup({
name="executionEnvironments"
qsConfig={QS_CONFIG}
readOnly={!canDelete}
selectItem={item => dispatch({ type: 'SELECT_ITEM', item })}
deselectItem={item => dispatch({ type: 'DESELECT_ITEM', item })}
selectItem={(item) => dispatch({ type: 'SELECT_ITEM', item })}
deselectItem={(item) => dispatch({ type: 'DESELECT_ITEM', item })}
/>
)}
/>

View File

@ -129,7 +129,7 @@ function HostFilterLookup({
const { isModalOpen, toggleModal, closeModal } = useModal();
const searchColumns = buildSearchColumns();
const parseRelatedSearchFields = searchFields => {
const parseRelatedSearchFields = (searchFields) => {
if (searchFields.indexOf('__search') !== -1) {
return searchFields.slice(0, -8);
}
@ -143,7 +143,7 @@ function HostFilterLookup({
isLoading,
} = useRequest(
useCallback(
async orgId => {
async (orgId) => {
const params = parseQueryString(QS_CONFIG, location.search);
const [{ data }, { data: actions }] = await Promise.all([
HostsAPI.read(
@ -158,7 +158,7 @@ function HostFilterLookup({
parseRelatedSearchFields
),
searchableKeys: Object.keys(actions?.actions.GET || {}).filter(
key => actions.actions?.GET[key].filterable
(key) => actions.actions?.GET[key].filterable
),
};
},
@ -213,7 +213,7 @@ function HostFilterLookup({
const chipsArray = [];
if (Array.isArray(filter[param])) {
filter[param].forEach(val =>
filter[param].forEach((val) =>
chipsArray.push({
key: `${param}:${val}`,
node: `${val}`,
@ -274,7 +274,7 @@ function HostFilterLookup({
numChips={5}
totalChips={chips[key]?.chips?.length || 0}
>
{chips[key]?.chips?.map(chip => (
{chips[key]?.chips?.map((chip) => (
<Chip key={chip.key} isReadOnly>
{chip.node}
</Chip>
@ -284,18 +284,18 @@ function HostFilterLookup({
{/* Parse advanced search chips */}
{Object.keys(chips).length > 0 &&
Object.keys(chips)
.filter(val => chips[val].chips.length > 0)
.filter((val) => chips[val].chips.length > 0)
.filter(
val => searchColumns.map(val2 => val2.key).indexOf(val) === -1
(val) => searchColumns.map((val2) => val2.key).indexOf(val) === -1
)
.map(leftoverKey => (
.map((leftoverKey) => (
<ChipGroup
categoryName={chips[leftoverKey].key}
key={chips[leftoverKey].key}
numChips={5}
totalChips={chips[leftoverKey]?.chips?.length || 0}
>
{chips[leftoverKey]?.chips?.map(chip => (
{chips[leftoverKey]?.chips?.map((chip) => (
<Chip key={chip.key} isReadOnly>
{chip.node}
</Chip>
@ -372,8 +372,8 @@ function HostFilterLookup({
<HeaderCell>{t`Inventory`}</HeaderCell>
</HeaderRow>
}
renderRow={item => <HostListItem key={item.id} item={item} />}
renderToolbar={props => (
renderRow={(item) => <HostListItem key={item.id} item={item} />}
renderToolbar={(props) => (
<DataListToolbar
{...props}
fillWidth

View File

@ -23,17 +23,7 @@ describe('HostListItem', () => {
</table>
);
expect(wrapper.find('HostListItem').length).toBe(1);
expect(
wrapper
.find('Td')
.at(0)
.text()
).toBe('Foo');
expect(
wrapper
.find('Td')
.at(1)
.text()
).toBe('Bar');
expect(wrapper.find('Td').at(0).text()).toBe('Foo');
expect(wrapper.find('Td').at(1).text()).toBe('Bar');
});
});

View File

@ -46,10 +46,10 @@ function InstanceGroupsLookup({
count: data.count,
relatedSearchableKeys: (
actionsResponse?.data?.related_search_fields || []
).map(val => val.slice(0, -8)),
).map((val) => val.slice(0, -8)),
searchableKeys: Object.keys(
actionsResponse.data.actions?.GET || {}
).filter(key => actionsResponse.data.actions?.GET[key].filterable),
).filter((key) => actionsResponse.data.actions?.GET[key].filterable),
};
}, [history.location]),
{
@ -123,9 +123,9 @@ function InstanceGroupsLookup({
name="instanceGroups"
qsConfig={QS_CONFIG}
readOnly={!canDelete}
selectItem={item => dispatch({ type: 'SELECT_ITEM', item })}
deselectItem={item => dispatch({ type: 'DESELECT_ITEM', item })}
sortSelectedItems={selectedItems =>
selectItem={(item) => dispatch({ type: 'SELECT_ITEM', item })}
deselectItem={(item) => dispatch({ type: 'DESELECT_ITEM', item })}
sortSelectedItems={(selectedItems) =>
dispatch({ type: 'SET_SELECTED_ITEMS', selectedItems })
}
isSelectedDraggable

View File

@ -65,10 +65,10 @@ function InventoryLookup({
count: data.count,
relatedSearchableKeys: (
actionsResponse?.data?.related_search_fields || []
).map(val => val.slice(0, -8)),
).map((val) => val.slice(0, -8)),
searchableKeys: Object.keys(
actionsResponse.data.actions?.GET || {}
).filter(key => {
).filter((key) => {
if (['kind', 'host_filter'].includes(key) && hideSmartInventories) {
return false;
}
@ -89,7 +89,7 @@ function InventoryLookup({
);
const checkInventoryName = useCallback(
async name => {
async (name) => {
if (!name) {
onChange(null);
return;
@ -169,8 +169,8 @@ function InventoryLookup({
name="inventory"
qsConfig={QS_CONFIG}
readOnly={!canDelete}
selectItem={item => dispatch({ type: 'SELECT_ITEM', item })}
deselectItem={item => dispatch({ type: 'DESELECT_ITEM', item })}
selectItem={(item) => dispatch({ type: 'SELECT_ITEM', item })}
deselectItem={(item) => dispatch({ type: 'DESELECT_ITEM', item })}
/>
)}
/>
@ -225,8 +225,8 @@ function InventoryLookup({
name="inventory"
qsConfig={QS_CONFIG}
readOnly={!canDelete}
selectItem={item => dispatch({ type: 'SELECT_ITEM', item })}
deselectItem={item => dispatch({ type: 'DESELECT_ITEM', item })}
selectItem={(item) => dispatch({ type: 'SELECT_ITEM', item })}
deselectItem={(item) => dispatch({ type: 'DESELECT_ITEM', item })}
/>
)}
/>

Some files were not shown because too many files have changed in this diff Show More