Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 13 additions & 10 deletions libs/i18n/locales/en/translation.json
Original file line number Diff line number Diff line change
Expand Up @@ -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-org>/my-rhel-with-fc-agent:<version>\"). 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-org>/my-rhel-with-fc-agent:<version>\"). 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",
Expand Down Expand Up @@ -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",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -115,7 +115,7 @@ const EditDeviceWizard = () => {
...updatePolicyValues,
isAdvanced: true,
},
useBasicUpdateConfig: !updatePolicyValues.isAdvanced,
customizeUpdates: updatePolicyValues.isAdvanced,
}}
validationSchema={getValidationSchema(t)}
validateOnMount
Expand Down
Original file line number Diff line number Diff line change
@@ -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';
Expand All @@ -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';

Expand All @@ -18,27 +18,46 @@ const UpdatePolicyStep = ({ isReadOnly }: { isReadOnly?: boolean }) => {
const { t } = useTranslation();

const {
values: { useBasicUpdateConfig },
values: { customizeUpdates },
} = useFormikContext<DeviceSpecConfigFormValues>();

return (
<FlightCtlForm>
<CheckboxField name="useBasicUpdateConfig" label={t('Use basic configurations')} isDisabled={isReadOnly} />
{!useBasicUpdateConfig ? (
<>
<Title headingLevel="h3">{t('Advanced configurations')}</Title>
<FormGroupWithHelperText
label={t('Update policies')}
content={t('Update policies allow you to control when updates should be downloaded and applied.')}
>
<UpdateStepUpdatePolicy isReadOnly={isReadOnly} />
</FormGroupWithHelperText>
</>
) : (
<Alert isInline variant="info" title={t('Default update policy')}>
{t('The device will download and apply updates as soon as they are available.')}
</Alert>
)}
<Stack hasGutter>
<StackItem>
<FormGroup label={t('Update behavior')} role="radiogroup">
<Stack hasGutter>
<RadioField
id="device-update-immediate"
name="customizeUpdates"
label={t('Immediate updates')}
description={t('Devices receive updates as soon as they are available.')}
checkedValue={false}
isDisabled={isReadOnly}
/>
<RadioField
id="device-update-customize"
name="customizeUpdates"
label={t('Customize update scheduling')}
description={t('Set maintenance windows to control when updates are downloaded and applied.')}
checkedValue={true}
isDisabled={isReadOnly}
/>
</Stack>
</FormGroup>
</StackItem>
{customizeUpdates && (
<StackItem>
<Title headingLevel="h3">{t('Customize updates')}</Title>
<FormGroupWithHelperText
label={t('Maintenance windows')}
content={t('Maintenance windows control when devices may download and install updates.')}
>
<UpdateStepUpdatePolicy isReadOnly={isReadOnly} />
</FormGroupWithHelperText>
</StackItem>
)}
</Stack>
</FlightCtlForm>
);
};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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(),
}),
);

Expand Down Expand Up @@ -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<UpdatePolicyForm>);
allPatches = allPatches.concat(updatesPatches);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,7 @@ const ReviewStep = ({ error }: { error?: unknown }) => {
</DescriptionListDescription>
</DescriptionListGroup>
)}
{!values.useBasicUpdateConfig && (
{values.customizeUpdates && (
<>
{values.rolloutPolicy.isAdvanced && (
<DescriptionListGroup>
Expand Down
Original file line number Diff line number Diff line change
@@ -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';
Expand All @@ -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';

Expand All @@ -23,60 +24,81 @@ const UpdatePolicyStep = ({ isReadOnly }: { isReadOnly: boolean }) => {
const { t } = useTranslation();

const {
values: { useBasicUpdateConfig, rolloutPolicy, disruptionBudget, updatePolicy },
values: { customizeUpdates, rolloutPolicy, disruptionBudget, updatePolicy },
} = useFormikContext<FleetFormValues>();

return (
<FlightCtlForm>
<CheckboxField name="useBasicUpdateConfig" label={t('Use basic configurations')} isDisabled={isReadOnly} />
{!useBasicUpdateConfig ? (
<FormSection title={t('Advanced configurations')} titleElement="h1" className="fctl-update-policy--advanced">
{/* Rollout policies */}
<CheckboxField
name="rolloutPolicy.isAdvanced"
label={
<LabelWithHelperText
label={t('Set rollout policies')}
content={t('Rollout policies allow you to control the order of updates for the fleet devices.')}
<Stack hasGutter>
<StackItem>
<FormGroup label={t('Update behavior')} role="radiogroup">
<Stack hasGutter>
<RadioField
id="fleet-update-immediate"
name="customizeUpdates"
label={t('Immediate updates')}
description={t('Devices receive updates as soon as they are available.')}
checkedValue={false}
isDisabled={isReadOnly}
/>
<RadioField
id="fleet-update-customize"
name="customizeUpdates"
label={t('Customize rollout and scheduling')}
description={t('Set rollout order, disruption budget, or maintenance windows.')}
checkedValue={true}
isDisabled={isReadOnly}
/>
</Stack>
</FormGroup>
</StackItem>
{customizeUpdates && (
<StackItem>
<FormSection title={t('Customize updates')} titleElement="h1" className="fctl-update-policy--advanced">
{/* Rollout order */}
<CheckboxField
name="rolloutPolicy.isAdvanced"
label={
<LabelWithHelperText
label={t('Set rollout order')}
content={t('Rollout order controls which fleet devices are updated and in what sequence.')}
/>
}
isDisabled={isReadOnly}
body={rolloutPolicy.isAdvanced && <UpdateStepRolloutPolicy isReadOnly={isReadOnly} />}
/>
}
isDisabled={isReadOnly}
body={rolloutPolicy.isAdvanced && <UpdateStepRolloutPolicy isReadOnly={isReadOnly} />}
/>

{/* Disruption budget */}
<CheckboxField
name="disruptionBudget.isAdvanced"
label={
<LabelWithHelperText
label={t('Set disruption budget')}
content={t(
'Disruption budget allows you to limit the number of similar devices that may be updating simultaneously.',
)}
{/* Disruption budget */}
<CheckboxField
name="disruptionBudget.isAdvanced"
label={
<LabelWithHelperText
label={t('Set disruption budget')}
content={t(
'Disruption budget allows you to limit the number of similar devices that may be updating simultaneously.',
)}
/>
}
isDisabled={isReadOnly}
body={disruptionBudget.isAdvanced && <UpdateStepDisruptionBudget isReadOnly={isReadOnly} />}
/>
}
isDisabled={isReadOnly}
body={disruptionBudget.isAdvanced && <UpdateStepDisruptionBudget isReadOnly={isReadOnly} />}
/>

{/* Update (and download) policies */}
<CheckboxField
name="updatePolicy.isAdvanced"
label={
<LabelWithHelperText
label={t('Set update policies')}
content={t('Update policies allow you to control when updates should be downloaded and applied.')}
{/* Maintenance windows */}
<CheckboxField
name="updatePolicy.isAdvanced"
label={
<LabelWithHelperText
label={t('Set maintenance windows')}
content={t('Maintenance windows control when devices may download and install updates.')}
/>
}
isDisabled={isReadOnly}
body={updatePolicy.isAdvanced && <UpdateStepUpdatePolicy isReadOnly={isReadOnly} />}
/>
}
isDisabled={isReadOnly}
body={updatePolicy.isAdvanced && <UpdateStepUpdatePolicy isReadOnly={isReadOnly} />}
/>
</FormSection>
) : (
<Alert isInline variant="info" title={t('Default update policy')}>
{t('All the devices that are part of this fleet will receive updates as soon as they are available.')}
</Alert>
)}
</FormSection>
</StackItem>
)}
</Stack>
</FlightCtlForm>
);
};
Expand Down
16 changes: 7 additions & 9 deletions libs/ui-components/src/components/Fleet/CreateFleet/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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(),
}),
);
};
Expand Down Expand Up @@ -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<UpdatePolicyForm>,
);
allPatches = allPatches.concat(updatePolicyPatches);
Expand Down Expand Up @@ -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);
}
Expand Down Expand Up @@ -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,
};
}

Expand All @@ -241,6 +239,6 @@ export const getInitialValues = (fleet?: Fleet): FleetFormValues => {
rolloutPolicy: getRolloutPolicyValues(undefined),
disruptionBudget: getDisruptionBudgetValues(undefined),
updatePolicy: getUpdatePolicyValues(undefined),
useBasicUpdateConfig: true,
customizeUpdates: false,
};
};
9 changes: 6 additions & 3 deletions libs/ui-components/src/components/form/RadioField.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,14 @@ export interface RadioFieldProps extends Omit<RadioProps, 'onChange' | 'ref' | '
checkedValue?: unknown;
name: string;
helperText?: React.ReactNode;
description?: React.ReactNode;
onChangeCustom?: (checkedValue: unknown) => void;
noDefaultOnChange?: boolean;
}

const RadioField = ({
helperText,
description,
checkedValue,
name,
onChangeCustom,
Expand All @@ -31,7 +33,7 @@ const RadioField = ({
if (noDefaultOnChange) {
return;
}
await setValue(checkedValue || true, true);
await setValue(checkedValue !== undefined ? checkedValue : true, true);
await setTouched(true);
}
};
Expand All @@ -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}
/>

<DefaultHelperText helperText={helperText} />
<DefaultHelperText helperText={description ? undefined : helperText} />
<ErrorHelperText meta={meta} />
</FormGroup>
);
Expand Down
2 changes: 1 addition & 1 deletion libs/ui-components/src/types/deviceSpec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -264,7 +264,7 @@ export type DeviceSpecConfigFormValues = {
systemdUnits: SystemdUnitFormValue[];
updatePolicy: UpdatePolicyForm;
registerMicroShift: boolean;
useBasicUpdateConfig: boolean;
customizeUpdates: boolean;
};

export type EditDeviceFormValues = DeviceSpecConfigFormValues & {
Expand Down
Loading
Loading