foreman_remote_execution 15.0.2 → 16.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (61) hide show
  1. checksums.yaml +4 -4
  2. data/app/controllers/api/v2/job_templates_controller.rb +3 -0
  3. data/app/views/api/v2/job_invocations/main.json.rabl +1 -1
  4. data/lib/foreman_remote_execution/engine.rb +1 -1
  5. data/lib/foreman_remote_execution/version.rb +1 -1
  6. data/locale/foreman_remote_execution.pot +138 -135
  7. data/package.json +8 -7
  8. data/webpack/JobInvocationDetail/JobAdditionInfo.js +4 -4
  9. data/webpack/JobInvocationDetail/JobInvocationDetail.scss +5 -5
  10. data/webpack/JobInvocationDetail/JobInvocationHostTable.js +7 -4
  11. data/webpack/JobInvocationDetail/JobInvocationHostTableToolbar.js +8 -3
  12. data/webpack/JobInvocationDetail/JobInvocationToolbarButtons.js +3 -5
  13. data/webpack/JobInvocationDetail/TemplateInvocationComponents/OutputToggleGroup.js +1 -1
  14. data/webpack/JobInvocationDetail/TemplateInvocationComponents/PreviewTemplate.js +3 -10
  15. data/webpack/JobInvocationDetail/TemplateInvocationComponents/TemplateActionButtons.js +5 -5
  16. data/webpack/JobInvocationDetail/TemplateInvocationComponents/index.scss +1 -1
  17. data/webpack/JobInvocationDetail/__tests__/MainInformation.test.js +6 -6
  18. data/webpack/JobInvocationDetail/__tests__/TemplateInvocation.test.js +1 -1
  19. data/webpack/JobInvocationDetail/__tests__/fixtures.js +1 -0
  20. data/webpack/JobInvocationDetail/index.js +14 -13
  21. data/webpack/JobWizard/Footer.js +2 -4
  22. data/webpack/JobWizard/JobWizard.js +1 -1
  23. data/webpack/JobWizard/JobWizard.scss +19 -19
  24. data/webpack/JobWizard/JobWizardPageRerun.js +22 -16
  25. data/webpack/JobWizard/PermissionDenied.js +15 -11
  26. data/webpack/JobWizard/__tests__/integration.test.js +10 -8
  27. data/webpack/JobWizard/steps/AdvancedFields/DescriptionField.js +26 -14
  28. data/webpack/JobWizard/steps/AdvancedFields/Fields.js +5 -5
  29. data/webpack/JobWizard/steps/AdvancedFields/__tests__/AdvancedFields.test.js +14 -12
  30. data/webpack/JobWizard/steps/HostsAndInputs/SelectAPI.js +1 -1
  31. data/webpack/JobWizard/steps/HostsAndInputs/SelectGQL.js +1 -1
  32. data/webpack/JobWizard/steps/HostsAndInputs/__tests__/HostsAndInputs.test.js +5 -5
  33. data/webpack/JobWizard/steps/HostsAndInputs/index.js +41 -36
  34. data/webpack/JobWizard/steps/ReviewDetails/ReviewDetails.test.js +3 -3
  35. data/webpack/JobWizard/steps/ReviewDetails/index.js +1 -1
  36. data/webpack/JobWizard/steps/Schedule/PurposeField.js +1 -1
  37. data/webpack/JobWizard/steps/Schedule/RepeatCron.js +1 -1
  38. data/webpack/JobWizard/steps/Schedule/RepeatDaily.js +1 -1
  39. data/webpack/JobWizard/steps/Schedule/RepeatHour.js +6 -4
  40. data/webpack/JobWizard/steps/Schedule/RepeatMonth.js +1 -1
  41. data/webpack/JobWizard/steps/Schedule/RepeatWeek.js +1 -1
  42. data/webpack/JobWizard/steps/Schedule/ScheduleFuture.js +10 -3
  43. data/webpack/JobWizard/steps/Schedule/ScheduleRecurring.js +29 -19
  44. data/webpack/JobWizard/steps/form/DateTimePicker.js +1 -1
  45. data/webpack/JobWizard/steps/form/FormHelpers.js +7 -4
  46. data/webpack/JobWizard/steps/form/Formatter.js +3 -1
  47. data/webpack/JobWizard/steps/form/GroupedSelectField.js +3 -3
  48. data/webpack/JobWizard/steps/form/NumberInput.js +17 -7
  49. data/webpack/JobWizard/steps/form/ResourceSelect.js +8 -4
  50. data/webpack/JobWizard/steps/form/SearchSelect.js +6 -2
  51. data/webpack/JobWizard/steps/form/SelectField.js +3 -2
  52. data/webpack/react_app/components/FeaturesDropdown/index.js +1 -1
  53. data/webpack/react_app/components/FeaturesDropdown/index.scss +2 -2
  54. data/webpack/react_app/components/HostKebab/KebabItems.js +1 -1
  55. data/webpack/react_app/components/RecentJobsCard/RecentJobsCard.js +2 -1
  56. data/webpack/react_app/components/RecentJobsCard/RecentJobsTable.js +3 -3
  57. data/webpack/react_app/components/RecentJobsCard/styles.scss +3 -3
  58. data/webpack/react_app/components/RegistrationExtension/RexInterface.js +5 -3
  59. data/webpack/react_app/components/RegistrationExtension/RexPull.js +1 -1
  60. data/webpack/react_app/components/RegistrationExtension/__tests__/__snapshots__/RexInterface.test.js.snap +6 -6
  61. metadata +2 -2
@@ -59,26 +59,28 @@ describe('Job wizard fill', () => {
59
59
  <JobWizard />
60
60
  </Provider>
61
61
  );
62
- expect(wrapper.find('.pf-c-wizard__nav-link.pf-m-disabled')).toHaveLength(
63
- 5
64
- );
62
+ expect(
63
+ wrapper.find('.pf-v5-c-wizard__nav-link.pf-m-disabled')
64
+ ).toHaveLength(5);
65
65
  selectors.selectJobCategoriesStatus.mockImplementation(() => 'RESOLVED');
66
66
  expect(store.getActions()).toMatchSnapshot('initial');
67
67
  selectors.selectJobTemplate.mockRestore();
68
68
  jest.spyOn(selectors, 'selectJobTemplate');
69
69
  selectors.selectJobTemplate.mockImplementation(() => jobTemplate);
70
- wrapper.find('.pf-c-button.pf-c-select__toggle-button').simulate('click');
70
+ wrapper
71
+ .find('.pf-v5-c-button.pf-v5-c-select__toggle-button')
72
+ .simulate('click');
71
73
  await act(async () => {
72
74
  await wrapper
73
- .find('.pf-c-select__menu-item')
75
+ .find('.pf-v5-c-select__menu-item')
74
76
  .first()
75
77
  .simulate('click');
76
78
  });
77
79
  expect(store.getActions().slice(-1)).toMatchSnapshot('select template');
78
80
  wrapper.update();
79
- expect(wrapper.find('.pf-c-wizard__nav-link.pf-m-disabled')).toHaveLength(
80
- 0
81
- );
81
+ expect(
82
+ wrapper.find('.pf-v5-c-wizard__nav-link.pf-m-disabled')
83
+ ).toHaveLength(0);
82
84
  });
83
85
 
84
86
  it('have all steps', async () => {
@@ -1,7 +1,15 @@
1
1
  import React, { useState, useEffect, useCallback } from 'react';
2
2
  import { useSelector } from 'react-redux';
3
3
  import PropTypes from 'prop-types';
4
- import { FormGroup, TextInput, Tooltip, Button } from '@patternfly/react-core';
4
+ import {
5
+ FormGroup,
6
+ TextInput,
7
+ Tooltip,
8
+ Button,
9
+ FormHelperText,
10
+ HelperText,
11
+ HelperTextItem,
12
+ } from '@patternfly/react-core';
5
13
  import { translate as __ } from 'foremanReact/common/I18n';
6
14
  import {
7
15
  selectTemplateInputs,
@@ -55,18 +63,6 @@ export const DescriptionField = ({
55
63
  <ResetDefault setValue={setValue} defaultValue={defaultValue} />
56
64
  }
57
65
  fieldId="description"
58
- helperText={
59
- <Button
60
- ouiaId="description-preview-button"
61
- variant="link"
62
- isInline
63
- onClick={togglePreview}
64
- >
65
- {isPreview
66
- ? __('Edit job description template')
67
- : __('Preview job description')}
68
- </Button>
69
- }
70
66
  >
71
67
  {isPreview ? (
72
68
  <Tooltip content={generatedDesc}>
@@ -89,9 +85,25 @@ export const DescriptionField = ({
89
85
  autoComplete="description"
90
86
  id="description"
91
87
  value={value}
92
- onChange={newValue => setValue(newValue)}
88
+ onChange={(_event, newValue) => setValue(newValue)}
93
89
  />
94
90
  )}
91
+ <FormHelperText>
92
+ <HelperText>
93
+ <HelperTextItem>
94
+ <Button
95
+ ouiaId="description-preview-button"
96
+ variant="link"
97
+ isInline
98
+ onClick={togglePreview}
99
+ >
100
+ {isPreview
101
+ ? __('Edit job description template')
102
+ : __('Preview job description')}
103
+ </Button>
104
+ </HelperTextItem>
105
+ </HelperText>
106
+ </FormHelperText>
95
107
  </FormGroup>
96
108
  );
97
109
  };
@@ -25,7 +25,7 @@ export const EffectiveUserField = ({ value, setValue, defaultValue }) => (
25
25
  id="effective-user"
26
26
  type="text"
27
27
  value={value}
28
- onChange={newValue => setValue(newValue)}
28
+ onChange={(_event, newValue) => setValue(newValue)}
29
29
  />
30
30
  </FormGroup>
31
31
  );
@@ -94,7 +94,7 @@ export const PasswordField = ({ value, setValue }) => (
94
94
  type="password"
95
95
  placeholder="*****"
96
96
  value={value}
97
- onChange={newValue => setValue(newValue)}
97
+ onChange={(_event, newValue) => setValue(newValue)}
98
98
  />
99
99
  </FormGroup>
100
100
  );
@@ -118,7 +118,7 @@ export const KeyPassphraseField = ({ value, setValue }) => (
118
118
  type="password"
119
119
  placeholder="*****"
120
120
  value={value}
121
- onChange={newValue => setValue(newValue)}
121
+ onChange={(_event, newValue) => setValue(newValue)}
122
122
  />
123
123
  </FormGroup>
124
124
  );
@@ -142,7 +142,7 @@ export const EffectiveUserPasswordField = ({ value, setValue }) => (
142
142
  type="password"
143
143
  placeholder="*****"
144
144
  value={value}
145
- onChange={newValue => setValue(newValue)}
145
+ onChange={(_event, newValue) => setValue(newValue)}
146
146
  />
147
147
  </FormGroup>
148
148
  );
@@ -228,7 +228,7 @@ export const SSHUserField = ({ value, setValue, defaultValue }) => (
228
228
  id="ssh-user"
229
229
  type="text"
230
230
  value={value}
231
- onChange={newValue => setValue(newValue)}
231
+ onChange={(_event, newValue) => setValue(newValue)}
232
232
  />
233
233
  </FormGroup>
234
234
  );
@@ -44,18 +44,20 @@ describe('AdvancedFields', () => {
44
44
  </MockedProvider>
45
45
  );
46
46
  // setup
47
- wrapper.find('.pf-c-button.pf-c-select__toggle-button').simulate('click');
48
47
  wrapper
49
- .find('.pf-c-select__menu-item')
48
+ .find('.pf-v5-c-button.pf-v5-c-select__toggle-button')
49
+ .simulate('click');
50
+ wrapper
51
+ .find('.pf-v5-c-select__menu-item')
50
52
  .first()
51
53
  .simulate('click');
52
54
 
53
55
  // test
54
- expect(wrapper.find('.pf-c-wizard__nav-link.pf-m-disabled')).toHaveLength(
55
- 0
56
- );
56
+ expect(
57
+ wrapper.find('.pf-v5-c-wizard__nav-link.pf-m-disabled')
58
+ ).toHaveLength(0);
57
59
  wrapper
58
- .find('.pf-c-wizard__nav-link')
60
+ .find('.pf-v5-c-wizard__nav-link')
59
61
  .at(2)
60
62
  .simulate('click'); // Advanced step
61
63
 
@@ -64,7 +66,7 @@ describe('AdvancedFields', () => {
64
66
  });
65
67
  const effectiveUserInput = () => wrapper.find('input#effective-user');
66
68
  const advancedTemplateInput = () =>
67
- wrapper.find('.pf-c-form__group-control textarea');
69
+ wrapper.find('.pf-v5-c-form__group-control textarea');
68
70
  const effectiveUesrValue = 'effective user new value';
69
71
  const advancedTemplateInputValue = 'advanced input new value';
70
72
  effectiveUserInput().getDOMNode().value = effectiveUesrValue;
@@ -79,15 +81,15 @@ describe('AdvancedFields', () => {
79
81
  );
80
82
 
81
83
  wrapper
82
- .find('.pf-c-wizard__nav-link')
84
+ .find('.pf-v5-c-wizard__nav-link')
83
85
  .at(1)
84
86
  .simulate('click');
85
87
 
86
- expect(wrapper.find('.pf-c-wizard__nav-link.pf-m-current').text()).toEqual(
87
- 'Target hosts and inputs'
88
- );
88
+ expect(
89
+ wrapper.find('.pf-v5-c-wizard__nav-link.pf-m-current').text()
90
+ ).toEqual('Target hosts and inputs');
89
91
  wrapper
90
- .find('.pf-c-wizard__nav-link')
92
+ .find('.pf-v5-c-wizard__nav-link')
91
93
  .at(2)
92
94
  .simulate('click'); // Advanced step
93
95
 
@@ -1,7 +1,7 @@
1
1
  import React from 'react';
2
2
  import { useSelector, useDispatch } from 'react-redux';
3
3
  import URI from 'urijs';
4
- import { SelectVariant } from '@patternfly/react-core';
4
+ import { SelectVariant } from '@patternfly/react-core/deprecated';
5
5
  import { get } from 'foremanReact/redux/API';
6
6
  import { selectResponse, selectIsLoading } from '../../JobWizardSelectors';
7
7
  import { SearchSelect } from '../form/SearchSelect';
@@ -1,6 +1,6 @@
1
1
  import React, { useState } from 'react';
2
2
  import { useQuery } from '@apollo/client';
3
- import { SelectVariant } from '@patternfly/react-core';
3
+ import { SelectVariant } from '@patternfly/react-core/deprecated';
4
4
  import {
5
5
  useForemanOrganization,
6
6
  useForemanLocation,
@@ -43,7 +43,7 @@ describe('Hosts', () => {
43
43
  await act(async () => {
44
44
  fireEvent.click(
45
45
  screen.getByText('host1', {
46
- selector: '.pf-c-select__menu-item',
46
+ selector: '.pf-v5-c-select__menu-item',
47
47
  })
48
48
  );
49
49
  fireEvent.blur(select('hosts'));
@@ -56,7 +56,7 @@ describe('Hosts', () => {
56
56
  fireEvent.click(screen.getByText('host2'));
57
57
  });
58
58
  fireEvent.click(
59
- screen.getByText('Hosts', { selector: '.pf-c-select__toggle-text' })
59
+ screen.getByText('Hosts', { selector: '.pf-v5-c-select__toggle-text' })
60
60
  );
61
61
  await act(async () => {
62
62
  fireEvent.click(screen.getByText('Host groups'));
@@ -71,7 +71,7 @@ describe('Hosts', () => {
71
71
  await act(async () => {
72
72
  fireEvent.click(
73
73
  screen.getByText('Host groups', {
74
- selector: '.pf-c-select__toggle-text',
74
+ selector: '.pf-v5-c-select__toggle-text',
75
75
  })
76
76
  );
77
77
  });
@@ -128,7 +128,7 @@ describe('Hosts', () => {
128
128
  expect(screen.queryAllByText('Hosts')).toHaveLength(1);
129
129
  await act(async () => {
130
130
  fireEvent.click(
131
- screen.getByText('Hosts', { selector: '.pf-c-select__toggle-text' })
131
+ screen.getByText('Hosts', { selector: '.pf-v5-c-select__toggle-text' })
132
132
  );
133
133
  });
134
134
  expect(screen.queryAllByText('Host groups')).toHaveLength(1);
@@ -138,7 +138,7 @@ describe('Hosts', () => {
138
138
  await act(async () => {
139
139
  fireEvent.click(
140
140
  // Close the select
141
- screen.getByText('Hosts', { selector: '.pf-c-select__toggle-text' })
141
+ screen.getByText('Hosts', { selector: '.pf-v5-c-select__toggle-text' })
142
142
  );
143
143
  });
144
144
  });
@@ -8,6 +8,9 @@ import {
8
8
  InputGroup,
9
9
  Text,
10
10
  Spinner,
11
+ InputGroupItem,
12
+ FormHelperText,
13
+ HelperText,
11
14
  } from '@patternfly/react-core';
12
15
  import PropTypes from 'prop-types';
13
16
  import { useSelector, useDispatch } from 'react-redux';
@@ -145,43 +148,40 @@ const HostsAndInputs = ({
145
148
  />
146
149
  )}
147
150
  <Form>
148
- <FormGroup
149
- fieldId="host_selection"
150
- id="host-selection"
151
- helperTextInvalid={errorText}
152
- validated={isError ? 'error' : 'default'}
153
- >
151
+ <FormGroup fieldId="host_selection" id="host-selection">
154
152
  <InputGroup onBlur={() => setWasFocus(true)}>
155
- <SelectField
156
- isRequired
157
- className="target-method-select"
158
- toggleIcon={<FilterIcon />}
159
- fieldId="host_methods"
160
- options={Object.values(hostMethods).filter(method => {
161
- if (method === hostMethods.hostCollections && !withKatello) {
162
- return false;
163
- }
164
- return true;
165
- })}
166
- setValue={val => {
167
- setHostMethod(val);
168
- if (val === hostMethods.searchQuery) {
169
- setErrorText(__('Please enter a search query'));
170
- }
171
- if (val === hostMethods.hosts) {
172
- setErrorText(__('Please select at least one host'));
173
- }
174
- if (val === hostMethods.hostCollections) {
175
- setErrorText(
176
- __('Please select at least one host collection')
177
- );
178
- }
179
- if (val === hostMethods.hostGroups) {
180
- setErrorText(__('Please select at least one host group'));
181
- }
182
- }}
183
- value={hostMethod}
184
- />
153
+ <InputGroupItem>
154
+ <SelectField
155
+ isRequired
156
+ className="target-method-select"
157
+ toggleIcon={<FilterIcon />}
158
+ fieldId="host_methods"
159
+ options={Object.values(hostMethods).filter(method => {
160
+ if (method === hostMethods.hostCollections && !withKatello) {
161
+ return false;
162
+ }
163
+ return true;
164
+ })}
165
+ setValue={val => {
166
+ setHostMethod(val);
167
+ if (val === hostMethods.searchQuery) {
168
+ setErrorText(__('Please enter a search query'));
169
+ }
170
+ if (val === hostMethods.hosts) {
171
+ setErrorText(__('Please select at least one host'));
172
+ }
173
+ if (val === hostMethods.hostCollections) {
174
+ setErrorText(
175
+ __('Please select at least one host collection')
176
+ );
177
+ }
178
+ if (val === hostMethods.hostGroups) {
179
+ setErrorText(__('Please select at least one host group'));
180
+ }
181
+ }}
182
+ value={hostMethod}
183
+ />
184
+ </InputGroupItem>
185
185
  {hostMethod === hostMethods.searchQuery && (
186
186
  <HostSearch
187
187
  setValue={setHostsSearchQuery}
@@ -220,6 +220,11 @@ const HostsAndInputs = ({
220
220
  />
221
221
  )}
222
222
  </InputGroup>
223
+ {isError && (
224
+ <FormHelperText>
225
+ <HelperText>{errorText}</HelperText>
226
+ </FormHelperText>
227
+ )}
223
228
  </FormGroup>
224
229
  <SelectedChips
225
230
  selectedHosts={selectedHosts}
@@ -76,7 +76,7 @@ describe('ReviewDetails', () => {
76
76
  expect(screen.getAllByText('Review details')).toHaveLength(3);
77
77
  fireEvent.click(
78
78
  screen.getByText('Job template', {
79
- selector: '.pf-c-button',
79
+ selector: '.pf-v5-c-button',
80
80
  })
81
81
  );
82
82
  expect(screen.getAllByText('Category and template')).toHaveLength(3);
@@ -88,7 +88,7 @@ describe('ReviewDetails', () => {
88
88
  act(() => {
89
89
  fireEvent.click(
90
90
  screen.getByText('Target hosts', {
91
- selector: '.pf-c-button',
91
+ selector: '.pf-v5-c-button',
92
92
  })
93
93
  );
94
94
  jest.advanceTimersByTime(1000); // to handle pf4 date picker popover useTimer
@@ -100,7 +100,7 @@ describe('ReviewDetails', () => {
100
100
  act(() => {
101
101
  fireEvent.click(
102
102
  screen.getByText('Advanced fields', {
103
- selector: '.pf-c-button',
103
+ selector: '.pf-v5-c-button',
104
104
  })
105
105
  );
106
106
  jest.advanceTimersByTime(1000);
@@ -6,8 +6,8 @@ import {
6
6
  DescriptionListTerm,
7
7
  DescriptionListGroup,
8
8
  DescriptionListDescription,
9
- WizardContextConsumer,
10
9
  } from '@patternfly/react-core';
10
+ import { WizardContextConsumer } from '@patternfly/react-core/deprecated';
11
11
  import PropTypes from 'prop-types';
12
12
  import { useDispatch, useSelector } from 'react-redux';
13
13
  import { get } from 'foremanReact/redux/API';
@@ -18,7 +18,7 @@ export const PurposeField = ({ purpose, setPurpose }) => (
18
18
  aria-label="purpose"
19
19
  type="text"
20
20
  value={purpose}
21
- onChange={newPurpose => {
21
+ onChange={(_event, newPurpose) => {
22
22
  setPurpose(newPurpose);
23
23
  }}
24
24
  />
@@ -72,7 +72,7 @@ export const RepeatCron = ({ repeatData, setRepeatData, setValid }) => {
72
72
  placeholder="* * * * *"
73
73
  type="text"
74
74
  value={cronline || ''}
75
- onChange={newTime => {
75
+ onChange={(_event, newTime) => {
76
76
  setRepeatData({ cronline: newTime });
77
77
  }}
78
78
  />
@@ -20,7 +20,7 @@ export const RepeatDaily = ({ repeatData, setRepeatData, setValid }) => {
20
20
  className="time-picker"
21
21
  time={repeatData.at}
22
22
  placeholder="hh:mm"
23
- onChange={newTime => {
23
+ onChange={(e, newTime) => {
24
24
  setRepeatData({ ...repeatData, at: newTime });
25
25
  }}
26
26
  is24Hour
@@ -2,13 +2,15 @@ import React, { useState, useEffect } from 'react';
2
2
  import PropTypes from 'prop-types';
3
3
  import {
4
4
  FormGroup,
5
- Select,
6
- SelectOption,
7
- SelectVariant,
8
5
  Alert,
9
6
  AlertActionCloseButton,
10
7
  ValidatedOptions,
11
8
  } from '@patternfly/react-core';
9
+ import {
10
+ Select,
11
+ SelectOption,
12
+ SelectVariant,
13
+ } from '@patternfly/react-core/deprecated';
12
14
  import { translate as __ } from 'foremanReact/common/I18n';
13
15
  import { helpLabel } from '../form/FormHelpers';
14
16
 
@@ -43,7 +45,7 @@ export const RepeatHour = ({ repeatData, setRepeatData }) => {
43
45
  setMinuteOpen(false);
44
46
  }}
45
47
  selections={`${minute}` || ''}
46
- onToggle={toggle => {
48
+ onToggle={(_event, toggle) => {
47
49
  setMinuteOpen(toggle);
48
50
  }}
49
51
  isOpen={minuteOpen}
@@ -26,7 +26,7 @@ export const RepeatMonth = ({ repeatData, setRepeatData, setValid }) => {
26
26
  placeholder="1,2..."
27
27
  type="text"
28
28
  value={repeatData.days || ''}
29
- onChange={newTime => {
29
+ onChange={(_event, newTime) => {
30
30
  setRepeatData({ ...repeatData, days: newTime });
31
31
  }}
32
32
  />
@@ -32,7 +32,7 @@ export const RepeatWeek = ({ repeatData, setRepeatData, setValid }) => {
32
32
  return () => setValid(true);
33
33
  }, [setValid, daysOfWeek, at]);
34
34
  const days = getWeekDays();
35
- const handleChangeDays = (checked, { target: { name } }) => {
35
+ const handleChangeDays = ({ target: { name } }, checked) => {
36
36
  setRepeatData({
37
37
  ...repeatData,
38
38
  daysOfWeek: { ...repeatData.daysOfWeek, [name]: checked },
@@ -4,7 +4,9 @@ import {
4
4
  FormGroup,
5
5
  Form,
6
6
  Button,
7
- ValidatedOptions,
7
+ FormHelperText,
8
+ HelperText,
9
+ HelperTextItem,
8
10
  } from '@patternfly/react-core';
9
11
  import { translate as __ } from 'foremanReact/common/I18n';
10
12
  import { DateTimePicker } from '../form/DateTimePicker';
@@ -85,8 +87,6 @@ export const ScheduleFuture = ({
85
87
  ),
86
88
  'start-before-date'
87
89
  )}
88
- validated={error ? ValidatedOptions.error : ValidatedOptions.noval}
89
- helperTextInvalid={error}
90
90
  >
91
91
  <DateTimePicker
92
92
  ariaLabel="starts before"
@@ -112,6 +112,13 @@ export const ScheduleFuture = ({
112
112
  >
113
113
  {__('Clear input')}
114
114
  </Button>
115
+ {error && (
116
+ <FormHelperText>
117
+ <HelperText>
118
+ <HelperTextItem variant="error">{error}</HelperTextItem>
119
+ </HelperText>
120
+ </FormHelperText>
121
+ )}
115
122
  </FormGroup>
116
123
  </Form>
117
124
  </>
@@ -5,8 +5,10 @@ import {
5
5
  FormGroup,
6
6
  Radio,
7
7
  TextInput,
8
- ValidatedOptions,
9
8
  Divider,
9
+ FormHelperText,
10
+ HelperText,
11
+ HelperTextItem,
10
12
  } from '@patternfly/react-core';
11
13
  import { ExclamationCircleIcon } from '@patternfly/react-icons';
12
14
  import { translate as __ } from 'foremanReact/common/I18n';
@@ -86,7 +88,7 @@ export const ScheduleRecurring = ({
86
88
  <WizardTitle title={SCHEDULE_TYPES.RECURRING} />
87
89
  <Form className="schedule-tab">
88
90
  <FormGroup label={__('Starts')} fieldId="schedule-starts">
89
- <div className="pf-c-form">
91
+ <div className="pf-v5-cform">
90
92
  <FormGroup fieldId="schedule-starts-now">
91
93
  <Radio
92
94
  ouiaId="schedule-start-now"
@@ -162,7 +164,7 @@ export const ScheduleRecurring = ({
162
164
  />
163
165
  <Divider component="div" />
164
166
  <FormGroup label={__('Ends')} fieldId="schedule-ends">
165
- <div className="pf-c-form">
167
+ <div className="pf-v5-cform">
166
168
  <FormGroup fieldId="schedule-ends-never">
167
169
  <Radio
168
170
  ouiaId="schedule-never-ends"
@@ -180,14 +182,7 @@ export const ScheduleRecurring = ({
180
182
  label={__('Never')}
181
183
  />
182
184
  </FormGroup>
183
- <FormGroup
184
- fieldId="ends-on-date"
185
- validated={
186
- validEnd ? ValidatedOptions.noval : ValidatedOptions.error
187
- }
188
- helperTextInvalid={__('End time needs to be after start time')}
189
- helperTextInvalidIcon={<ExclamationCircleIcon />}
190
- >
185
+ <FormGroup fieldId="ends-on-date">
191
186
  <Radio
192
187
  ouiaId="schedule-ends-on-date"
193
188
  isChecked={!!ends}
@@ -219,6 +214,18 @@ export const ScheduleRecurring = ({
219
214
  </div>
220
215
  }
221
216
  />
217
+ {!validEnd && (
218
+ <FormHelperText>
219
+ <HelperText>
220
+ <HelperTextItem
221
+ icon={<ExclamationCircleIcon />}
222
+ variant="error"
223
+ >
224
+ {__('End time needs to be after start time')}
225
+ </HelperTextItem>
226
+ </HelperText>
227
+ </FormHelperText>
228
+ )}
222
229
  </FormGroup>
223
230
  <FormGroup fieldId="ends-after">
224
231
  <Radio
@@ -238,21 +245,24 @@ export const ScheduleRecurring = ({
238
245
  label={
239
246
  <div className="schedule-radio-wrapper">
240
247
  <div className="schedule-radio-title">{__('After')}</div>
241
- <FormGroup
242
- helperTextInvalid={__(
243
- 'Repeat amount can only be a positive number'
244
- )}
245
- validated={repeatValidated}
246
- className="schedule-radio-repeat-text"
247
- >
248
+ <FormGroup className="schedule-radio-repeat-text">
248
249
  <TextInput
249
250
  ouiaId="repeat-amount"
250
251
  id="repeat-amount"
251
252
  value={repeatAmount || ''}
252
253
  type="number"
253
- onChange={handleRepeatInputChange}
254
+ onChange={(_event, newValue) =>
255
+ handleRepeatInputChange(newValue)
256
+ }
254
257
  isDisabled={!(repeatAmount === 0 || !!repeatAmount)}
255
258
  />
259
+ {repeatValidated === 'error' && (
260
+ <HelperText>
261
+ <HelperTextItem variant="error">
262
+ {__('Repeat amount can only be a positive number')}
263
+ </HelperTextItem>
264
+ </HelperText>
265
+ )}
256
266
  </FormGroup>
257
267
  <div className="schedule-radio-occurences">
258
268
  {__('occurences')}
@@ -75,7 +75,7 @@ export const DateTimePicker = ({
75
75
  }
76
76
  };
77
77
 
78
- const onTimeChange = newTime => {
78
+ const onTimeChange = (e, newTime) => {
79
79
  if (!newTime.length && allowEmpty) {
80
80
  const parsedNewTime = new Date(`${formattedDate} 00:00`);
81
81
  setDateTime(formatDateTime(parsedNewTime));
@@ -1,8 +1,9 @@
1
1
  import React from 'react';
2
2
  import PropTypes from 'prop-types';
3
- import { Popover, Button } from '@patternfly/react-core';
3
+ import { Popover, Button, Icon } from '@patternfly/react-core';
4
4
  import { HelpIcon } from '@patternfly/react-icons';
5
5
  import { translate as __ } from 'foremanReact/common/I18n';
6
+ import styles from '@patternfly/react-styles/css/components/Form/form';
6
7
 
7
8
  export const helpLabel = (text, id) => {
8
9
  if (!text) return null;
@@ -12,9 +13,11 @@ export const helpLabel = (text, id) => {
12
13
  type="button"
13
14
  aria-label={__('open-help-tooltip-button')}
14
15
  onClick={e => e.preventDefault()}
15
- className="pf-c-form__group-label-help"
16
+ className={styles.formGroupLabelHelp}
16
17
  >
17
- <HelpIcon noVerticalAlign />
18
+ <Icon isInline>
19
+ <HelpIcon />
20
+ </Icon>
18
21
  </button>
19
22
  </Popover>
20
23
  );
@@ -31,7 +34,7 @@ export const ResetDefault = ({ setValue, defaultValue }) =>
31
34
  className="reset-default"
32
35
  component="a"
33
36
  variant="link"
34
- isSmall
37
+ size="sm"
35
38
  onClick={() => setValue(defaultValue)}
36
39
  >
37
40
  {__('Reset to default')}