From f96478a62f8d80e411196e124558b5fe5bb856c7 Mon Sep 17 00:00:00 2001 From: MariaAga Date: Tue, 21 Jul 2026 15:44:59 +0100 Subject: [PATCH] Fixes #39522 - Fix failing new lint rules --- .../JobInvocationActions.js | 3 ++- .../JobInvocationConstants.js | 7 +++++++ .../JobInvocationDetail.scss | 8 ++++--- .../JobInvocationSystemStatusChart.js | 7 +++++-- .../JobInvocationDetail/TemplateInvocation.js | 11 ++++++++-- .../OutputCodeBlock.js | 5 ++++- .../TemplateInvocationComponents/index.scss | 1 - webpack/JobWizard/JobWizard.js | 6 +++++- webpack/JobWizard/JobWizard.scss | 21 +++++++++++++++++++ webpack/JobWizard/JobWizardConstants.js | 9 ++++++++ .../JobWizard/steps/Schedule/RepeatHour.js | 8 +++++-- .../JobWizard/steps/Schedule/RepeatWeek.js | 5 +++-- .../steps/Schedule/ScheduleRecurring.js | 4 ++-- .../JobWizard/steps/Schedule/ScheduleType.js | 5 ++++- .../JobWizard/steps/form/DateTimePicker.js | 18 ++++++++++------ webpack/JobWizard/steps/form/FormHelpers.js | 9 ++++---- .../components/FeaturesDropdown/index.scss | 2 ++ .../TargetingHosts/TargetingHostsConsts.js | 1 + .../TargetingHostsLabelsRow.scss | 8 +++++-- .../components/TargetingHosts/index.js | 7 +++++-- .../redux/actions/jobInvocations/index.js | 3 ++- webpack/react_app/redux/consts.js | 1 + 22 files changed, 116 insertions(+), 33 deletions(-) diff --git a/webpack/JobInvocationDetail/JobInvocationActions.js b/webpack/JobInvocationDetail/JobInvocationActions.js index 131696068..e89bdeeb0 100644 --- a/webpack/JobInvocationDetail/JobInvocationActions.js +++ b/webpack/JobInvocationDetail/JobInvocationActions.js @@ -12,6 +12,7 @@ import { CHANGE_ENABLED_RECURRING_LOGIC, GET_TASK, JOB_INVOCATION_KEY, + POLLING_INTERVAL_MS, UPDATE_JOB, } from './JobInvocationConstants'; @@ -32,7 +33,7 @@ export const getJobInvocation = url => dispatch => { response?.data?.error?.message || 'Error', }), - 1000 + POLLING_INTERVAL_MS ); dispatch(fetchData); diff --git a/webpack/JobInvocationDetail/JobInvocationConstants.js b/webpack/JobInvocationDetail/JobInvocationConstants.js index 12d6deb11..79352913c 100644 --- a/webpack/JobInvocationDetail/JobInvocationConstants.js +++ b/webpack/JobInvocationDetail/JobInvocationConstants.js @@ -20,6 +20,13 @@ export const DIRECT_OPEN_HOST_LIMIT = 3; export const ALL_JOB_HOSTS = 'ALL_JOB_HOSTS'; export const AWAITING_STATUS_FILTER = '(job_invocation.result = N/A)'; +export const POLLING_INTERVAL_MS = 1000; +export const AUTO_REFRESH_INTERVAL_MS = 5000; +export const UNIX_TO_JS_TIMESTAMP_FACTOR = 1000; +export const DEFAULT_CHART_LEGEND_WIDTH = 270; +export const CLIPBOARD_COPIED_EXIT_DELAY_MS = 1500; +export const CLIPBOARD_DEFAULT_EXIT_DELAY_MS = 600; + export const showTemplateInvocationUrl = (hostID, jobID) => `/show_template_invocation_by_host/${hostID}/job_invocation/${jobID}`; export const LIST_TEMPLATE_INVOCATIONS = 'LIST_TEMPLATE_INVOCATIONS'; diff --git a/webpack/JobInvocationDetail/JobInvocationDetail.scss b/webpack/JobInvocationDetail/JobInvocationDetail.scss index 34e0d7e24..2742f0bc3 100644 --- a/webpack/JobInvocationDetail/JobInvocationDetail.scss +++ b/webpack/JobInvocationDetail/JobInvocationDetail.scss @@ -1,5 +1,6 @@ .job-invocation-detail-flex { $chart_size: 105px; + padding-top: 0px; padding-left: 10px; display: flex; @@ -92,16 +93,17 @@ section.job-additional-info { max-height: 25em; } } + div.invocation-output { display: block; padding: 9.5px; margin: 0 0 10px; font-size: 12px; word-break: break-all; - word-wrap: break-word; + overflow-wrap: break-word; color: rgba(255, 255, 255, 1); background-color: rgba(47, 47, 47, 1); - border: 1px solid #000000; + border: 1px solid #000; border-radius: 0px; font-family: Menlo, Monaco, Consolas, monospace; @@ -127,7 +129,7 @@ section.job-additional-info { } a { - color: #ffffff; + color: #fff; } a.scroll-link{ diff --git a/webpack/JobInvocationDetail/JobInvocationSystemStatusChart.js b/webpack/JobInvocationDetail/JobInvocationSystemStatusChart.js index f44f9b707..77a46e3c7 100644 --- a/webpack/JobInvocationDetail/JobInvocationSystemStatusChart.js +++ b/webpack/JobInvocationDetail/JobInvocationSystemStatusChart.js @@ -23,7 +23,10 @@ import { global_palette_blue_300 as inProgressColor, global_palette_green_500 as successedColor, } from '@patternfly/react-tokens'; -import { STATUS_TITLES } from './JobInvocationConstants'; +import { + STATUS_TITLES, + DEFAULT_CHART_LEGEND_WIDTH, +} from './JobInvocationConstants'; import './JobInvocationDetail.scss'; const JobInvocationSystemStatusChart = ({ @@ -52,7 +55,7 @@ const JobInvocationSystemStatusChart = ({ return '0'; }; const chartSize = 105; - const [legendWidth, setLegendWidth] = useState(270); + const [legendWidth, setLegendWidth] = useState(DEFAULT_CHART_LEGEND_WIDTH); // Calculates chart legend width based on its content useEffect(() => { diff --git a/webpack/JobInvocationDetail/TemplateInvocation.js b/webpack/JobInvocationDetail/TemplateInvocation.js index 9045be218..faad034f8 100644 --- a/webpack/JobInvocationDetail/TemplateInvocation.js +++ b/webpack/JobInvocationDetail/TemplateInvocation.js @@ -11,6 +11,9 @@ import { showTemplateInvocationUrl, templateInvocationPageUrl, GET_TEMPLATE_INVOCATION, + CLIPBOARD_COPIED_EXIT_DELAY_MS, + CLIPBOARD_DEFAULT_EXIT_DELAY_MS, + AUTO_REFRESH_INTERVAL_MS, } from './JobInvocationConstants'; import { selectTemplateInvocationStatus, @@ -41,7 +44,11 @@ const CopyToClipboard = ({ fullOutput }) => { textId="code-content" aria-label="Copy to clipboard" onClick={e => onClick(e, fullOutput)} - exitDelay={copied ? 1500 : 600} + exitDelay={ + copied + ? CLIPBOARD_COPIED_EXIT_DELAY_MS + : CLIPBOARD_DEFAULT_EXIT_DELAY_MS + } maxWidth="110px" variant="plain" onTooltipHidden={() => setCopied(false)} @@ -111,7 +118,7 @@ export const TemplateInvocation = ({ } else if (intervalRef.current) { clearInterval(intervalRef.current); } - }, 5000); + }, AUTO_REFRESH_INTERVAL_MS); } return () => { diff --git a/webpack/JobInvocationDetail/TemplateInvocationComponents/OutputCodeBlock.js b/webpack/JobInvocationDetail/TemplateInvocationComponents/OutputCodeBlock.js index 759b7b280..3a4a57644 100644 --- a/webpack/JobInvocationDetail/TemplateInvocationComponents/OutputCodeBlock.js +++ b/webpack/JobInvocationDetail/TemplateInvocationComponents/OutputCodeBlock.js @@ -7,6 +7,7 @@ import React, { import PropTypes from 'prop-types'; import { Button } from '@patternfly/react-core'; import { translate as __ } from 'foremanReact/common/I18n'; +import { UNIX_TO_JS_TIMESTAMP_FACTOR } from '../JobInvocationConstants'; export const OutputCodeBlock = ({ code, showOutputType, scrollElement }) => { let lineCounter = 0; @@ -122,7 +123,9 @@ export const OutputCodeBlock = ({ code, showOutputType, scrollElement }) => {
{lineCounter.toString().padStart(4, '\u00A0')}:{' '} diff --git a/webpack/JobInvocationDetail/TemplateInvocationComponents/index.scss b/webpack/JobInvocationDetail/TemplateInvocationComponents/index.scss index 893d701c3..550247e59 100644 --- a/webpack/JobInvocationDetail/TemplateInvocationComponents/index.scss +++ b/webpack/JobInvocationDetail/TemplateInvocationComponents/index.scss @@ -1,5 +1,4 @@ .jobs-table-action-item a { - color: inherit; text-decoration: none; diff --git a/webpack/JobWizard/JobWizard.js b/webpack/JobWizard/JobWizard.js index 68f2a820c..8e244c628 100644 --- a/webpack/JobWizard/JobWizard.js +++ b/webpack/JobWizard/JobWizard.js @@ -18,6 +18,7 @@ import { WIZARD_TITLES, SCHEDULE_TYPES, initialScheduleState, + STARTS_ERROR_CHECK_INTERVAL_MS, } from './JobWizardConstants'; import { selectTemplateError, @@ -237,7 +238,10 @@ export const JobWizard = ({ rerunData }) => { } }; updateStartsError(); - const interval = setInterval(updateStartsError, 5000); + const interval = setInterval( + updateStartsError, + STARTS_ERROR_CHECK_INTERVAL_MS + ); return () => { interval && clearInterval(interval); diff --git a/webpack/JobWizard/JobWizard.scss b/webpack/JobWizard/JobWizard.scss index 08e3afb0b..d8e638138 100644 --- a/webpack/JobWizard/JobWizard.scss +++ b/webpack/JobWizard/JobWizard.scss @@ -1,5 +1,6 @@ .job-wizard { font-size: var(--pf-v5-global--FontSize--md); + .wizard-title { margin-bottom: 25px; } @@ -15,6 +16,7 @@ var(--pf-v5-cwizard__toggle--ZIndex) + 1 ); // So the select box can be shown above the wizard footer and navigation toggle } + .pf-v5-c-wizard__main-body { @media (max-width: 600px) { max-width: 100%; @@ -41,6 +43,7 @@ .pf-v5-c-chip-group.pf-m-category { margin-bottom: 10px; } + .pf-v5-c-select__toggle-typeahead { border: 0px; } @@ -50,62 +53,76 @@ flex-wrap: nowrap; } } + .foreman-search-field { width: 100%; } } + input[type='radio'], input[type='checkbox'] { margin: 0; } + .schedule-tab { #repeat-on-weekly { display: grid; grid-template-columns: repeat(7, 1fr); } + .pf-v5-l-grid { gap: var(--pf-v5-cform--GridGap); } + #repeat-on-hourly { max-height: 300px; overflow: scroll; } + .schedule-radio label { width: 100%; } + .schedule-radio input { align-self: center; } + .schedule-radio-repeat-text { width: 100px; display: inline-block; margin-right: 5px; align-self: center; } + .schedule-radio-title { width: 80px; display: inline-block; align-self: center; } + .schedule-radio-occurences { display: inline-block; align-self: center; } + .schedule-radio-wrapper { display: flex; } } + .future-schedule-tab { .clear-datetime-button { margin-left: 10px; align-self: center; font-size: var(--pf-v5-global--FontSize--md); } + .pf-v5-c-form__group-control { display: flex; flex-wrap: wrap; } } + .pf-v5-c-date-picker { vertical-align: top; } @@ -119,10 +136,12 @@ // overwriting bootstrap/_forms.scss margin: 4px 0 0; margin: 0; } + textarea { min-height: 40px; min-width: 100px; } + .pf-v5-c-modal-box { width: auto; } @@ -132,9 +151,11 @@ margin-left: 10px; } } + .pf-v5-c-radio__body { font-size: var(--pf-v5-cradio__label--FontSize); } + .reset-default { padding-bottom: 0; } diff --git a/webpack/JobWizard/JobWizardConstants.js b/webpack/JobWizard/JobWizardConstants.js index ca1bfcdc0..a1db56bca 100644 --- a/webpack/JobWizard/JobWizardConstants.js +++ b/webpack/JobWizard/JobWizardConstants.js @@ -78,3 +78,12 @@ export const HOST_IDS = 'HOST_IDS'; export const REX_FEATURE = 'REX_FEATURE'; export const JOB_API_KEY = 'JOB_API_KEY'; + +export const MINUTES_IN_HOUR = 60; +export const DAYS_IN_WEEK = 7; +export const SUNDAY_BASE_YEAR = 2017; +export const DEFAULT_MINUTE_OPTIONS = [0, 15, 30, 45]; +export const MS_PER_MINUTE = 60000; +export const STARTS_ERROR_CHECK_INTERVAL_MS = 5000; +export const DATE_PADDING_SLICE = -2; +export const DEBOUNCE_INPUT_MS = 1000; diff --git a/webpack/JobWizard/steps/Schedule/RepeatHour.js b/webpack/JobWizard/steps/Schedule/RepeatHour.js index 28e8f588e..90a7ff0a6 100644 --- a/webpack/JobWizard/steps/Schedule/RepeatHour.js +++ b/webpack/JobWizard/steps/Schedule/RepeatHour.js @@ -13,12 +13,16 @@ import { } from '@patternfly/react-core/deprecated'; import { translate as __ } from 'foremanReact/common/I18n'; import { helpLabel } from '../form/FormHelpers'; +import { + MINUTES_IN_HOUR, + DEFAULT_MINUTE_OPTIONS, +} from '../../JobWizardConstants'; export const RepeatHour = ({ repeatData, setRepeatData }) => { const isValidMinute = newMinute => Number.isInteger(parseInt(newMinute, 10)) && newMinute >= 0 && - newMinute < 60; + newMinute < MINUTES_IN_HOUR; const { minute } = repeatData; useEffect(() => { @@ -27,7 +31,7 @@ export const RepeatHour = ({ repeatData, setRepeatData }) => { } }, [minute, setRepeatData]); const [minuteOpen, setMinuteOpen] = useState(false); - const [options, setOptions] = useState([0, 15, 30, 45]); + const [options, setOptions] = useState(DEFAULT_MINUTE_OPTIONS); const [isAlertOpen, setIsAlertOpen] = useState(false); return ( { const locale = documentLocale().replace(/-/g, '_'); - const baseDate = new Date(Date.UTC(2017, 0, 1)); // just a Sunday + const baseDate = new Date(Date.UTC(SUNDAY_BASE_YEAR, 0, 1)); // just a Sunday const weekDays = []; const formatOptions = { weekday: 'short', timeZone: 'UTC' }; - for (let i = 0; i < 7; i++) { + for (let i = 0; i < DAYS_IN_WEEK; i++) { try { weekDays.push(baseDate.toLocaleDateString(locale, formatOptions)); } catch { diff --git a/webpack/JobWizard/steps/Schedule/ScheduleRecurring.js b/webpack/JobWizard/steps/Schedule/ScheduleRecurring.js index 6668a9924..d2427b896 100644 --- a/webpack/JobWizard/steps/Schedule/ScheduleRecurring.js +++ b/webpack/JobWizard/steps/Schedule/ScheduleRecurring.js @@ -13,7 +13,7 @@ import { import { ExclamationCircleIcon } from '@patternfly/react-icons'; import { translate as __ } from 'foremanReact/common/I18n'; import { RepeatOn } from './RepeatOn'; -import { SCHEDULE_TYPES } from '../../JobWizardConstants'; +import { SCHEDULE_TYPES, MS_PER_MINUTE } from '../../JobWizardConstants'; import { PurposeField } from './PurposeField'; import { DateTimePicker } from '../form/DateTimePicker'; import { WizardTitle } from '../form/WizardTitle'; @@ -114,7 +114,7 @@ export const ScheduleRecurring = ({ setScheduleValue(current => ({ ...current, startsAt: new Date( - new Date().getTime() + 60000 + new Date().getTime() + MS_PER_MINUTE ).toISOString(), // 1 minute in the future isFuture: true, })) diff --git a/webpack/JobWizard/steps/Schedule/ScheduleType.js b/webpack/JobWizard/steps/Schedule/ScheduleType.js index 77862c1f4..07857fa40 100644 --- a/webpack/JobWizard/steps/Schedule/ScheduleType.js +++ b/webpack/JobWizard/steps/Schedule/ScheduleType.js @@ -6,6 +6,7 @@ import { WIZARD_TITLES, SCHEDULE_TYPES, repeatTypes, + MS_PER_MINUTE, } from '../../JobWizardConstants'; import { WizardTitle } from '../form/WizardTitle'; import { QueryType } from './QueryType'; @@ -49,7 +50,9 @@ export const ScheduleType = ({ onChange={() => { setScheduleValue(current => ({ ...current, - startsAt: new Date(new Date().getTime() + 60000).toISOString(), // 1 minute in the future + startsAt: new Date( + new Date().getTime() + MS_PER_MINUTE + ).toISOString(), // 1 minute in the future scheduleType: SCHEDULE_TYPES.FUTURE, repeatType: repeatTypes.noRepeat, })); diff --git a/webpack/JobWizard/steps/form/DateTimePicker.js b/webpack/JobWizard/steps/form/DateTimePicker.js index 4c12012b6..2917d968e 100644 --- a/webpack/JobWizard/steps/form/DateTimePicker.js +++ b/webpack/JobWizard/steps/form/DateTimePicker.js @@ -7,13 +7,19 @@ import { } from '@patternfly/react-core'; import { debounce } from 'lodash'; import { translate as __, documentLocale } from 'foremanReact/common/I18n'; +import { + DATE_PADDING_SLICE, + DEBOUNCE_INPUT_MS, +} from '../../JobWizardConstants'; const formatDateTime = d => `${d.getFullYear()}-${`0${d.getMonth() + 1}`.slice( - -2 - )}-${`0${d.getDate()}`.slice(-2)} ${`0${d.getHours()}`.slice( - -2 - )}:${`0${d.getMinutes()}`.slice(-2)}:${`0${d.getSeconds()}`.slice(-2)}`; + DATE_PADDING_SLICE + )}-${`0${d.getDate()}`.slice(DATE_PADDING_SLICE)} ${`0${d.getHours()}`.slice( + DATE_PADDING_SLICE + )}:${`0${d.getMinutes()}`.slice( + DATE_PADDING_SLICE + )}:${`0${d.getSeconds()}`.slice(DATE_PADDING_SLICE)}`; export const DateTimePicker = ({ dateTime, @@ -103,7 +109,7 @@ export const DateTimePicker = ({ aria-label={`${ariaLabel} datepicker`} value={formattedDate} placeholder="yyyy/mm/dd" - onChange={debounce(onDateChange, 1000, { + onChange={debounce(onDateChange, DEBOUNCE_INPUT_MS, { leading: false, trailing: true, })} @@ -123,7 +129,7 @@ export const DateTimePicker = ({ time={dateTime ? dateObject.toString() : ''} inputProps={dateTime ? {} : { value: '' }} placeholder={includeSeconds ? 'hh:mm:ss' : 'hh:mm'} - onChange={debounce(onTimeChange, 1000, { + onChange={debounce(onTimeChange, DEBOUNCE_INPUT_MS, { leading: false, trailing: true, })} diff --git a/webpack/JobWizard/steps/form/FormHelpers.js b/webpack/JobWizard/steps/form/FormHelpers.js index 29d0fb324..2209342c2 100644 --- a/webpack/JobWizard/steps/form/FormHelpers.js +++ b/webpack/JobWizard/steps/form/FormHelpers.js @@ -8,16 +8,17 @@ export const helpLabel = (text, id) => { if (!text) return null; return ( - + ); }; diff --git a/webpack/react_app/components/FeaturesDropdown/index.scss b/webpack/react_app/components/FeaturesDropdown/index.scss index e7e90c486..8f36f5465 100644 --- a/webpack/react_app/components/FeaturesDropdown/index.scss +++ b/webpack/react_app/components/FeaturesDropdown/index.scss @@ -1,7 +1,9 @@ #schedule-a-job-dropdown ul.pf-v5-c-dropdown__menu { padding-left: 0; + li { display: unset; + a { font-size: 16px; color: var(--pf-v5-cdropdown__menu-item--Color); diff --git a/webpack/react_app/components/TargetingHosts/TargetingHostsConsts.js b/webpack/react_app/components/TargetingHosts/TargetingHostsConsts.js index 5fd27d8c8..3642c0393 100644 --- a/webpack/react_app/components/TargetingHosts/TargetingHostsConsts.js +++ b/webpack/react_app/components/TargetingHosts/TargetingHostsConsts.js @@ -1,2 +1,3 @@ export const TARGETING_HOSTS = 'TARGETING_HOSTS'; export const TARGETING_HOSTS_AUTOCOMPLETE = 'targeting_hosts_search'; +export const TARGETING_HOSTS_POLLING_INTERVAL_MS = 1000; diff --git a/webpack/react_app/components/TargetingHosts/TargetingHostsLabelsRow.scss b/webpack/react_app/components/TargetingHosts/TargetingHostsLabelsRow.scss index a2c5713a0..b4b1139f8 100644 --- a/webpack/react_app/components/TargetingHosts/TargetingHostsLabelsRow.scss +++ b/webpack/react_app/components/TargetingHosts/TargetingHostsLabelsRow.scss @@ -3,24 +3,28 @@ .tasks-labels-row { margin: 0; padding: 10px; + .title { font-weight: 600; font-size: 13px; } + .label { font-size: 100%; - margin-left: 5px; margin-right: 5px; + a { padding-left: 10px; } } + .pficon-close { color: $color-pf-white; } + .compound-label-pf { - margin-left: 0; margin: 10px; + margin-left: 0; } } diff --git a/webpack/react_app/components/TargetingHosts/index.js b/webpack/react_app/components/TargetingHosts/index.js index 76f1ec728..415fb660b 100644 --- a/webpack/react_app/components/TargetingHosts/index.js +++ b/webpack/react_app/components/TargetingHosts/index.js @@ -17,7 +17,10 @@ import { selectStatusFilter, } from './TargetingHostsSelectors'; import { getApiUrl } from './TargetingHostsHelpers'; -import { TARGETING_HOSTS } from './TargetingHostsConsts'; +import { + TARGETING_HOSTS, + TARGETING_HOSTS_POLLING_INTERVAL_MS, +} from './TargetingHostsConsts'; import TargetingHostsPage from './TargetingHostsPage'; import { chartFilter } from '../../redux/actions/jobInvocations'; @@ -100,7 +103,7 @@ const WrappedTargetingHosts = () => { dispatch(stopInterval(TARGETING_HOSTS)); }, }), - 1000 + TARGETING_HOSTS_POLLING_INTERVAL_MS ), [dispatch] ); diff --git a/webpack/react_app/redux/actions/jobInvocations/index.js b/webpack/react_app/redux/actions/jobInvocations/index.js index 968d83923..885712656 100644 --- a/webpack/react_app/redux/actions/jobInvocations/index.js +++ b/webpack/react_app/redux/actions/jobInvocations/index.js @@ -5,6 +5,7 @@ import { JOB_INVOCATIONS_GET_JOB_INVOCATIONS, JOB_INVOCATIONS_POLLING_STARTED, JOB_INVOCATIONS_JOB_FINISHED, + HTTP_UNAUTHORIZED, } from '../../consts'; const defaultJobInvocationsPollingInterval = 1000; @@ -32,7 +33,7 @@ const getJobInvocations = url => async (dispatch, getState) => { } function onGetJobInvocationsFailed(error) { - if (error.response.status === 401) { + if (error.response.status === HTTP_UNAUTHORIZED) { window.location.replace('/users/login'); } } diff --git a/webpack/react_app/redux/consts.js b/webpack/react_app/redux/consts.js index 02c09fc35..1cdc74474 100644 --- a/webpack/react_app/redux/consts.js +++ b/webpack/react_app/redux/consts.js @@ -3,3 +3,4 @@ export const JOB_INVOCATIONS_POLLING_STARTED = export const JOB_INVOCATIONS_GET_JOB_INVOCATIONS = 'JOB_INVOCATIONS_GET_JOB_INVOCATIONS'; export const JOB_INVOCATIONS_JOB_FINISHED = 'JOB_INVOCATIONS_JOB_FINISHED'; +export const HTTP_UNAUTHORIZED = 401;