diff --git a/libs/i18n/locales/en/translation.json b/libs/i18n/locales/en/translation.json index 8666dcdc3..a4bd783cb 100644 --- a/libs/i18n/locales/en/translation.json +++ b/libs/i18n/locales/en/translation.json @@ -969,12 +969,14 @@ "This device uses package-based OS management. System image configuration is not available for this device.": "This device uses package-based OS management. System image configuration is not available for this device.", "System image is managed by Software Catalog": "System image is managed by Software Catalog", "Must be a reference to a bootable container image (such as \"quay.io//my-rhel-with-fc-agent:\"). If you do not want to manage your OS from Edge management, leave this field empty.": "Must be a reference to a bootable container image (such as \"quay.io//my-rhel-with-fc-agent:\"). If you do not want to manage your OS from Edge management, leave this field empty.", - "Use basic configurations": "Use basic configurations", - "Advanced configurations": "Advanced configurations", - "Update policies": "Update policies", - "Update policies allow you to control when updates should be downloaded and applied.": "Update policies allow you to control when updates should be downloaded and applied.", - "Default update policy": "Default update policy", - "The device will download and apply updates as soon as they are available.": "The device will download and apply updates as soon as they are available.", + "Update behavior": "Update behavior", + "Immediate updates": "Immediate updates", + "Devices receive updates as soon as they are available.": "Devices receive updates as soon as they are available.", + "Customize update scheduling": "Customize update scheduling", + "Set maintenance windows to control when updates are downloaded and applied.": "Set maintenance windows to control when updates are downloaded and applied.", + "Customize updates": "Customize updates", + "Maintenance windows": "Maintenance windows", + "Maintenance windows control when devices may download and install updates.": "Maintenance windows control when devices may download and install updates.", "Device alias": "Device alias", "Device labels": "Device labels", "Unnamed": "Unnamed", @@ -1100,12 +1102,13 @@ "Device selector": "Device selector", "Rollout policy": "Rollout policy", "Disruption budget": "Disruption budget", - "Set rollout policies": "Set rollout policies", - "Rollout policies allow you to control the order of updates for the fleet devices.": "Rollout policies allow you to control the order of updates for the fleet devices.", + "Customize rollout and scheduling": "Customize rollout and scheduling", + "Set rollout order, disruption budget, or maintenance windows.": "Set rollout order, disruption budget, or maintenance windows.", + "Set rollout order": "Set rollout order", + "Rollout order controls which fleet devices are updated and in what sequence.": "Rollout order controls which fleet devices are updated and in what sequence.", "Set disruption budget": "Set disruption budget", "Disruption budget allows you to limit the number of similar devices that may be updating simultaneously.": "Disruption budget allows you to limit the number of similar devices that may be updating simultaneously.", - "Set update policies": "Set update policies", - "All the devices that are part of this fleet will receive updates as soon as they are available.": "All the devices that are part of this fleet will receive updates as soon as they are available.", + "Set maintenance windows": "Set maintenance windows", "Group devices by label keys": "Group devices by label keys", "The disruption budget will be applied to all group combinations independently.": "The disruption budget will be applied to all group combinations independently.", "Add label key": "Add label key", diff --git a/libs/ui-components/src/components/Device/EditDeviceWizard/EditDeviceWizard.tsx b/libs/ui-components/src/components/Device/EditDeviceWizard/EditDeviceWizard.tsx index 5bbe8fb99..c6f71cd26 100644 --- a/libs/ui-components/src/components/Device/EditDeviceWizard/EditDeviceWizard.tsx +++ b/libs/ui-components/src/components/Device/EditDeviceWizard/EditDeviceWizard.tsx @@ -115,7 +115,7 @@ const EditDeviceWizard = () => { ...updatePolicyValues, isAdvanced: true, }, - useBasicUpdateConfig: !updatePolicyValues.isAdvanced, + customizeUpdates: updatePolicyValues.isAdvanced, }} validationSchema={getValidationSchema(t)} validateOnMount diff --git a/libs/ui-components/src/components/Device/EditDeviceWizard/steps/DeviceUpdateStep.tsx b/libs/ui-components/src/components/Device/EditDeviceWizard/steps/DeviceUpdateStep.tsx index 359572feb..9ad1f7ea8 100644 --- a/libs/ui-components/src/components/Device/EditDeviceWizard/steps/DeviceUpdateStep.tsx +++ b/libs/ui-components/src/components/Device/EditDeviceWizard/steps/DeviceUpdateStep.tsx @@ -1,5 +1,5 @@ import * as React from 'react'; -import { Alert, Title } from '@patternfly/react-core'; +import { FormGroup, Stack, StackItem, Title } from '@patternfly/react-core'; import { type FormikErrors, useFormikContext } from 'formik'; import { useTranslation } from '../../../../hooks/useTranslation'; @@ -8,7 +8,7 @@ import UpdateStepUpdatePolicy from '../../../Fleet/CreateFleet/steps/UpdateStepU import FlightCtlForm from '../../../form/FlightCtlForm'; import { type DeviceSpecConfigFormValues } from '../../../../types/deviceSpec'; import { FormGroupWithHelperText } from '../../../common/WithHelperText'; -import CheckboxField from '../../../form/CheckboxField'; +import RadioField from '../../../form/RadioField'; export const deviceUpdatePolicyStepId = 'update-policy'; @@ -18,27 +18,46 @@ const UpdatePolicyStep = ({ isReadOnly }: { isReadOnly?: boolean }) => { const { t } = useTranslation(); const { - values: { useBasicUpdateConfig }, + values: { customizeUpdates }, } = useFormikContext(); return ( - - {!useBasicUpdateConfig ? ( - <> - {t('Advanced configurations')} - - - - - ) : ( - - {t('The device will download and apply updates as soon as they are available.')} - - )} + + + + + + + + + + {customizeUpdates && ( + + {t('Customize updates')} + + + + + )} + ); }; diff --git a/libs/ui-components/src/components/Device/EditDeviceWizard/utils.ts b/libs/ui-components/src/components/Device/EditDeviceWizard/utils.ts index 179cb15a3..cb1691207 100644 --- a/libs/ui-components/src/components/Device/EditDeviceWizard/utils.ts +++ b/libs/ui-components/src/components/Device/EditDeviceWizard/utils.ts @@ -31,7 +31,7 @@ export const getValidationSchema = (t: TFunction) => configTemplates: validConfigTemplatesSchema(t), applications: validApplicationsSchema(t), updatePolicy: - !values.useBasicUpdateConfig && values.updatePolicy.isAdvanced ? validUpdatePolicySchema(t) : Yup.object(), + values.customizeUpdates && values.updatePolicy.isAdvanced ? validUpdatePolicySchema(t) : Yup.object(), }), ); @@ -78,7 +78,7 @@ export const getDevicePatches = (currentDevice: Device, updatedDevice: EditDevic // Updates const updatesPatches = getUpdatePolicyPatches('/spec/updatePolicy', currentDevice.spec?.updatePolicy, { ...updatedDevice.updatePolicy, - isAdvanced: !updatedDevice.useBasicUpdateConfig, + isAdvanced: updatedDevice.customizeUpdates, } as Required); allPatches = allPatches.concat(updatesPatches); diff --git a/libs/ui-components/src/components/Fleet/CreateFleet/steps/ReviewStep.tsx b/libs/ui-components/src/components/Fleet/CreateFleet/steps/ReviewStep.tsx index 6ce5ec630..dfe9c83ce 100644 --- a/libs/ui-components/src/components/Fleet/CreateFleet/steps/ReviewStep.tsx +++ b/libs/ui-components/src/components/Fleet/CreateFleet/steps/ReviewStep.tsx @@ -88,7 +88,7 @@ const ReviewStep = ({ error }: { error?: unknown }) => { )} - {!values.useBasicUpdateConfig && ( + {values.customizeUpdates && ( <> {values.rolloutPolicy.isAdvanced && ( diff --git a/libs/ui-components/src/components/Fleet/CreateFleet/steps/UpdatePolicyStep.tsx b/libs/ui-components/src/components/Fleet/CreateFleet/steps/UpdatePolicyStep.tsx index 1fcef6faa..0f2cc34c7 100644 --- a/libs/ui-components/src/components/Fleet/CreateFleet/steps/UpdatePolicyStep.tsx +++ b/libs/ui-components/src/components/Fleet/CreateFleet/steps/UpdatePolicyStep.tsx @@ -1,5 +1,5 @@ import * as React from 'react'; -import { Alert, FormSection } from '@patternfly/react-core'; +import { FormGroup, FormSection, Stack, StackItem } from '@patternfly/react-core'; import { type FormikErrors, useFormikContext } from 'formik'; import { useTranslation } from '../../../../hooks/useTranslation'; @@ -11,6 +11,7 @@ import UpdateStepRolloutPolicy from './UpdateStepRolloutPolicy'; import UpdateStepDisruptionBudget from './UpdateStepDisruptionBudget'; import UpdateStepUpdatePolicy from './UpdateStepUpdatePolicy'; import CheckboxField from '../../../form/CheckboxField'; +import RadioField from '../../../form/RadioField'; import './UpdatePolicyStep.css'; @@ -23,60 +24,81 @@ const UpdatePolicyStep = ({ isReadOnly }: { isReadOnly: boolean }) => { const { t } = useTranslation(); const { - values: { useBasicUpdateConfig, rolloutPolicy, disruptionBudget, updatePolicy }, + values: { customizeUpdates, rolloutPolicy, disruptionBudget, updatePolicy }, } = useFormikContext(); return ( - - {!useBasicUpdateConfig ? ( - - {/* Rollout policies */} - + + + + + + + + + {customizeUpdates && ( + + + {/* Rollout order */} + + } + isDisabled={isReadOnly} + body={rolloutPolicy.isAdvanced && } /> - } - isDisabled={isReadOnly} - body={rolloutPolicy.isAdvanced && } - /> - {/* Disruption budget */} - + } + isDisabled={isReadOnly} + body={disruptionBudget.isAdvanced && } /> - } - isDisabled={isReadOnly} - body={disruptionBudget.isAdvanced && } - /> - {/* Update (and download) policies */} - + } + isDisabled={isReadOnly} + body={updatePolicy.isAdvanced && } /> - } - isDisabled={isReadOnly} - body={updatePolicy.isAdvanced && } - /> - - ) : ( - - {t('All the devices that are part of this fleet will receive updates as soon as they are available.')} - - )} + + + )} + ); }; diff --git a/libs/ui-components/src/components/Fleet/CreateFleet/utils.ts b/libs/ui-components/src/components/Fleet/CreateFleet/utils.ts index f98730f8f..bbc69b365 100644 --- a/libs/ui-components/src/components/Fleet/CreateFleet/utils.ts +++ b/libs/ui-components/src/components/Fleet/CreateFleet/utils.ts @@ -49,15 +49,13 @@ export const getValidationSchema = (t: TFunction) => { applications: validApplicationsSchema(t), systemdUnits: systemdUnitListValidationSchema(t), rolloutPolicy: - !values.useBasicUpdateConfig && values.rolloutPolicy?.isAdvanced - ? validFleetRolloutPolicySchema(t) - : Yup.object(), + values.customizeUpdates && values.rolloutPolicy?.isAdvanced ? validFleetRolloutPolicySchema(t) : Yup.object(), disruptionBudget: - !values.useBasicUpdateConfig && values.disruptionBudget?.isAdvanced + values.customizeUpdates && values.disruptionBudget?.isAdvanced ? validFleetDisruptionBudgetSchema(t) : Yup.object(), updatePolicy: - !values.useBasicUpdateConfig && values.updatePolicy?.isAdvanced ? validUpdatePolicySchema(t) : Yup.object(), + values.customizeUpdates && values.updatePolicy?.isAdvanced ? validUpdatePolicySchema(t) : Yup.object(), }), ); }; @@ -142,7 +140,7 @@ export const getFleetPatches = (currentFleet: Fleet, updatedFleet: FleetFormValu currentFleet.spec.template.spec.updatePolicy, { ...updatedFleet.updatePolicy, - isAdvanced: !updatedFleet.useBasicUpdateConfig && updatedFleet.updatePolicy.isAdvanced, + isAdvanced: updatedFleet.customizeUpdates && updatedFleet.updatePolicy.isAdvanced, } as Required, ); allPatches = allPatches.concat(updatePolicyPatches); @@ -190,7 +188,7 @@ export const getFleetResource = (values: FleetFormValues): Fleet => { if (values.registerMicroShift) { fleet.spec.template.spec.config?.push(ACMCrdConfig, ACMImportConfig, MicroshiftRegistrationHook); } - if (!values.useBasicUpdateConfig) { + if (values.customizeUpdates) { if (values.rolloutPolicy.isAdvanced || values.disruptionBudget.isAdvanced) { fleet.spec.rolloutPolicy = getRolloutPolicyData(values); } @@ -225,7 +223,7 @@ export const getInitialValues = (fleet?: Fleet): FleetFormValues => { rolloutPolicy, disruptionBudget, updatePolicy, - useBasicUpdateConfig: !rolloutPolicy.isAdvanced && !disruptionBudget.isAdvanced && !updatePolicy.isAdvanced, + customizeUpdates: rolloutPolicy.isAdvanced || disruptionBudget.isAdvanced || updatePolicy.isAdvanced, }; } @@ -241,6 +239,6 @@ export const getInitialValues = (fleet?: Fleet): FleetFormValues => { rolloutPolicy: getRolloutPolicyValues(undefined), disruptionBudget: getDisruptionBudgetValues(undefined), updatePolicy: getUpdatePolicyValues(undefined), - useBasicUpdateConfig: true, + customizeUpdates: false, }; }; diff --git a/libs/ui-components/src/components/form/RadioField.tsx b/libs/ui-components/src/components/form/RadioField.tsx index e304a1dd7..ba7c837f1 100644 --- a/libs/ui-components/src/components/form/RadioField.tsx +++ b/libs/ui-components/src/components/form/RadioField.tsx @@ -7,12 +7,14 @@ export interface RadioFieldProps extends Omit void; noDefaultOnChange?: boolean; } const RadioField = ({ helperText, + description, checkedValue, name, onChangeCustom, @@ -31,7 +33,7 @@ const RadioField = ({ if (noDefaultOnChange) { return; } - await setValue(checkedValue || true, true); + await setValue(checkedValue !== undefined ? checkedValue : true, true); await setTouched(true); } }; @@ -44,11 +46,12 @@ const RadioField = ({ {...field} {...props} id={fieldId} + description={description} onChange={onChange} - isChecked={checkedValue ? field.value === checkedValue : !!field.value} + isChecked={checkedValue !== undefined ? field.value === checkedValue : !!field.value} /> - + ); diff --git a/libs/ui-components/src/types/deviceSpec.ts b/libs/ui-components/src/types/deviceSpec.ts index cca40adba..66018a138 100644 --- a/libs/ui-components/src/types/deviceSpec.ts +++ b/libs/ui-components/src/types/deviceSpec.ts @@ -264,7 +264,7 @@ export type DeviceSpecConfigFormValues = { systemdUnits: SystemdUnitFormValue[]; updatePolicy: UpdatePolicyForm; registerMicroShift: boolean; - useBasicUpdateConfig: boolean; + customizeUpdates: boolean; }; export type EditDeviceFormValues = DeviceSpecConfigFormValues & { diff --git a/libs/ui-components/src/utils/patch.ts b/libs/ui-components/src/utils/patch.ts index d0bfcddbd..124a563aa 100644 --- a/libs/ui-components/src/utils/patch.ts +++ b/libs/ui-components/src/utils/patch.ts @@ -263,10 +263,10 @@ export const getRolloutPolicyPatches = ( const currentBatches = currentPolicy?.deviceSelection?.sequence || []; const currentDisruption = currentPolicy?.disruptionBudget; - const hadAdvancedSettings = currentBatches.length > 0 || !!currentDisruption; + const hadAdvancedSettings = + currentPolicy?.defaultUpdateTimeout !== undefined || currentBatches.length > 0 || !!currentDisruption; const wantsAdvancedSettings = - !fleetValues.useBasicUpdateConfig && - (fleetValues.rolloutPolicy.isAdvanced || fleetValues.disruptionBudget.isAdvanced); + fleetValues.customizeUpdates && (fleetValues.rolloutPolicy.isAdvanced || fleetValues.disruptionBudget.isAdvanced); const updatedPolicy = fleetValues.rolloutPolicy; if (hadAdvancedSettings !== wantsAdvancedSettings) {