From d106454ca1261cba128c07c6ae16483248a84892 Mon Sep 17 00:00:00 2001 From: Bat-Zion Rotman Date: Tue, 26 Dec 2023 17:10:21 +0200 Subject: [PATCH] change default snr template to be determined according to label remediation.medik8s.io/default-template --- src/apis/useSNRTemplate.tsx | 28 +++++++--- src/components/editor/NodeHealthCheckForm.tsx | 55 +++++++++++++------ .../editor/NodeHealthCheckSyncedEditor.tsx | 27 +++++++-- .../remediatorField/RemediatorKindField.tsx | 17 +----- src/data/formValues.ts | 6 +- src/data/formViewValues.ts | 21 ++++--- 6 files changed, 99 insertions(+), 55 deletions(-) diff --git a/src/apis/useSNRTemplate.tsx b/src/apis/useSNRTemplate.tsx index 3442d85..0ca4c65 100644 --- a/src/apis/useSNRTemplate.tsx +++ b/src/apis/useSNRTemplate.tsx @@ -7,6 +7,8 @@ import { } from "data/types"; import * as React from "react"; +const DEFAULT_TEMPLATE_LABEL = "remediation.medik8s.io/default-template"; + const useSnrTemplate = (): SnrTemplateResult => { const [templates, loaded, error] = useK8sWatchResource< SelfNodeRemediationTemplate[] @@ -18,19 +20,29 @@ const useSnrTemplate = (): SnrTemplateResult => { if (error) { return undefined; } - const templateCR = templates.find( + + let defaultTemplate = templates.find( (template) => - template.spec?.template?.spec?.remediationStrategy === - "ResourceDeletion" + template.metadata?.labels?.[DEFAULT_TEMPLATE_LABEL] === "true" ); - if (!templateCR) { + + if (!defaultTemplate) { + // fallback to resource deletion for backward compatibility of versions without label + defaultTemplate = templates.find( + (template) => + template.spec?.template?.spec?.remediationStrategy === + "ResourceDeletion" + ); + } + + if (!defaultTemplate) { return undefined; } return { - apiVersion: templateCR.apiVersion, - kind: templateCR.kind, - namespace: templateCR.metadata?.namespace, - name: templateCR.metadata?.name, + apiVersion: defaultTemplate.apiVersion, + kind: defaultTemplate.kind, + namespace: defaultTemplate.metadata?.namespace, + name: defaultTemplate.metadata?.name, }; }, [templates, error]); diff --git a/src/components/editor/NodeHealthCheckForm.tsx b/src/components/editor/NodeHealthCheckForm.tsx index f3d3675..24f1110 100644 --- a/src/components/editor/NodeHealthCheckForm.tsx +++ b/src/components/editor/NodeHealthCheckForm.tsx @@ -17,6 +17,9 @@ import { getFormValues, getNodeHealthCheck } from "data/formValues"; import { LoadingInline } from "copiedFromConsole/utils/status-box"; import "./nhc-form.css"; import { useOpenShiftVersion } from "copiedFromConsole/hooks/useOpenShiftVersion"; +import useSnrTemplate from "../../apis/useSNRTemplate"; +import { range } from "lodash-es"; +import { Skeleton } from "@patternfly/react-core"; export interface NodeHealthCheckProps { title: string; name: string; @@ -24,6 +27,18 @@ export interface NodeHealthCheckProps { isCreateFlow: boolean; } +const FormLoading = () => ( + <> +
+ {range(0, 20).map((idx) => ( + <> + +
+ + ))} + +); + const LearnMoreLink: React.FC = () => { const { t } = useNodeHealthCheckTranslation(); const [version, loaded, error] = useOpenShiftVersion(); @@ -68,10 +83,13 @@ const NodeHealthCheckForm__: React.FC = ({ isCreateFlow, }) => { const { t } = useNodeHealthCheckTranslation(); - const initialValues = React.useMemo( - () => getFormValues(nodeHealthCheck, isCreateFlow), - [] - ); + const [snrTemplate, loaded] = useSnrTemplate(); + const initialValues = React.useMemo(() => { + if (!loaded) { + return undefined; + } + return getFormValues(nodeHealthCheck, isCreateFlow, snrTemplate); + }, [isCreateFlow, loaded, nodeHealthCheck, snrTemplate]); const navigation = useNodeHealthCheckNavigation(); @@ -109,18 +127,23 @@ const NodeHealthCheckForm__: React.FC = ({ return ( <> } /> - - navigation.goBack()} - /> - + {!loaded ? ( + + ) : ( + + navigation.goBack()} + snrTemplate={snrTemplate} + /> + + )} ); }; diff --git a/src/components/editor/NodeHealthCheckSyncedEditor.tsx b/src/components/editor/NodeHealthCheckSyncedEditor.tsx index 6870888..3ead11d 100644 --- a/src/components/editor/NodeHealthCheckSyncedEditor.tsx +++ b/src/components/editor/NodeHealthCheckSyncedEditor.tsx @@ -2,7 +2,11 @@ import * as React from "react"; import { useFormikContext } from "formik"; import { useNodeHealthCheckTranslation } from "localization/useNodeHealthCheckTranslation"; -import { NodeHealthCheck, NodeHealthCheckFormValues } from "../../data/types"; +import { + NodeHealthCheck, + NodeHealthCheckFormValues, + RemediationTemplate, +} from "../../data/types"; import { EditorType } from "../../copiedFromConsole/synced-editor/editor-toggle"; import { FlexForm, @@ -18,6 +22,7 @@ import { dump } from "js-yaml"; import { Alert, FormSection } from "@patternfly/react-core"; import { getFormValues } from "data/formValues"; import { isEmpty } from "lodash-es"; + const sanitizeToYaml = ( values: NodeHealthCheckFormValues, originalNodeHealthCheck: NodeHealthCheck @@ -40,11 +45,12 @@ const LAST_VIEWED_EDITOR_TYPE_USERSETTING_KEY = type NodeHealthCheckFormSyncedEditorProps = { handleCancel: () => void; originalNodeHealthCheck: NodeHealthCheck; + snrTemplate: RemediationTemplate; }; export const NodeHealthCheckSyncedEditor: React.FC< NodeHealthCheckFormSyncedEditorProps -> = ({ originalNodeHealthCheck, handleCancel }) => { +> = ({ originalNodeHealthCheck, handleCancel, snrTemplate }) => { const { values, status, @@ -96,7 +102,11 @@ export const NodeHealthCheckSyncedEditor: React.FC< const onReload = () => { const curEditorType = values.editorType; - const resetValues = getFormValues(originalNodeHealthCheck, false); + const resetValues = getFormValues( + originalNodeHealthCheck, + false, + snrTemplate + ); resetValues.editorType = curEditorType; resetValues.reloadCount++; resetForm({ values: resetValues }); @@ -105,6 +115,7 @@ export const NodeHealthCheckSyncedEditor: React.FC< React.useEffect(() => { setStatus({ submitError: null }); }, [setStatus, values.editorType]); + return ( <> @@ -115,11 +126,17 @@ export const NodeHealthCheckSyncedEditor: React.FC< editor: formEditor, sanitizeTo: (yamlNodeHealthCheck: NodeHealthCheck) => { try { - return formViewValues.getFormViewValues(yamlNodeHealthCheck); + return formViewValues.getFormViewValues( + yamlNodeHealthCheck, + snrTemplate + ); } catch (err) { //return a function so SyncedEditorField will handle the error properly return () => - formViewValues.getFormViewValues(originalNodeHealthCheck); + formViewValues.getFormViewValues( + originalNodeHealthCheck, + snrTemplate + ); } }, }} diff --git a/src/components/editor/formView/remediatorField/RemediatorKindField.tsx b/src/components/editor/formView/remediatorField/RemediatorKindField.tsx index 12ddc6d..cd3ce6b 100644 --- a/src/components/editor/formView/remediatorField/RemediatorKindField.tsx +++ b/src/components/editor/formView/remediatorField/RemediatorKindField.tsx @@ -17,21 +17,6 @@ import { RemediationTemplate, } from "../../../../data/types"; import { useNodeHealthCheckTranslation } from "../../../../localization/useNodeHealthCheckTranslation"; -import HelpIcon from "../../../shared/HelpIcon"; - -const SNRRadioButtonLabel: React.FC = () => { - const { t } = useNodeHealthCheckTranslation(); - return ( - <> - {getSNRLabel(t)} - - - ); -}; const RemediatorKindRadioGroup: React.FC<{ snrTemplatesExist: boolean; @@ -50,7 +35,7 @@ const RemediatorKindRadioGroup: React.FC<{ > } + label={getSNRLabel(t)} isDisabled={!snrTemplatesExist} aria-describedby={"SNR remediator kind"} name={fieldName} diff --git a/src/data/formValues.ts b/src/data/formValues.ts index f83d41a..2591637 100644 --- a/src/data/formValues.ts +++ b/src/data/formValues.ts @@ -4,6 +4,7 @@ import { FormViewValues, NodeHealthCheck, NodeHealthCheckFormValues, + RemediationTemplate, } from "./types"; import { dump } from "js-yaml"; import { isParseError } from "./parseErrors"; @@ -13,7 +14,8 @@ import * as yamlText from "./yamlText"; export const getFormValues = ( nodeHealthCheck: NodeHealthCheck, - isCreateFlow: boolean + isCreateFlow: boolean, + snrTemplate: RemediationTemplate | undefined ): NodeHealthCheckFormValues => { const yamlData = dump(nodeHealthCheck, { skipInvalid: true, @@ -22,7 +24,7 @@ export const getFormValues = ( let formData: FormViewValues | null = null; let editorType = EditorType.YAML; try { - formData = getFormViewValues(nodeHealthCheck); + formData = getFormViewValues(nodeHealthCheck, snrTemplate); editorType = EditorType.Form; } catch (err) { if (isParseError(err)) { diff --git a/src/data/formViewValues.ts b/src/data/formViewValues.ts index 59e25ac..b77528c 100644 --- a/src/data/formViewValues.ts +++ b/src/data/formViewValues.ts @@ -3,7 +3,6 @@ import { selectorToStringArray, } from "copiedFromConsole/module/selector"; import { defaultUnhealthyConditions, DEFAULT_MIN_HEALTHY } from "./defaults"; -import { snrTemplateKind } from "./model"; import { ParseErrorCode, throwParseError } from "./parseErrors"; import { getSortedRemediators } from "./remediator"; import { @@ -17,8 +16,10 @@ import { EscalatingRemediator, } from "./types"; import { MIN_HEALTHY_REGEX } from "./validationSchema"; +import { isEqual } from "lodash-es"; const getRemediationTemplateFormValues = ( + snrTemplate: RemediationTemplate | undefined, template?: RemediationTemplate, timeout?: string, order?: number @@ -26,10 +27,9 @@ const getRemediationTemplateFormValues = ( if (!template) { return undefined; } - const radioOption = - template.kind === snrTemplateKind.kind - ? RemediatorRadioOption.SNR - : RemediatorRadioOption.CUSTOM; + const radioOption = isEqual(snrTemplate, template) + ? RemediatorRadioOption.SNR + : RemediatorRadioOption.CUSTOM; return { radioOption, template, @@ -58,7 +58,8 @@ const getUnhealthyConditionsValue = ( }; const getescalatingRemediationsFormValues = ( - escalatingRemediations?: EscalatingRemediator[] + escalatingRemediations?: EscalatingRemediator[], + snrTemplate?: RemediationTemplate ): Remediator[] => { if (!escalatingRemediations) return []; const sortedescalatingRemediations = getSortedRemediators( @@ -66,6 +67,7 @@ const getescalatingRemediationsFormValues = ( ); return sortedescalatingRemediations.map((remediator) => { return getRemediationTemplateFormValues( + snrTemplate, remediator.remediationTemplate, remediator.timeout, remediator.order @@ -74,7 +76,8 @@ const getescalatingRemediationsFormValues = ( }; export const getFormViewValues = ( - nodeHealthCheck: NodeHealthCheck + nodeHealthCheck: NodeHealthCheck, + snrTemplate: RemediationTemplate | undefined ): FormViewValues => { const useEscalating = !!nodeHealthCheck.spec?.escalatingRemediations; return { @@ -86,11 +89,13 @@ export const getFormViewValues = ( unhealthyConditions: getUnhealthyConditionsValue(nodeHealthCheck), remediator: !useEscalating ? getRemediationTemplateFormValues( + snrTemplate, nodeHealthCheck?.spec?.remediationTemplate ) : undefined, escalatingRemediations: getescalatingRemediationsFormValues( - nodeHealthCheck.spec?.escalatingRemediations + nodeHealthCheck.spec?.escalatingRemediations, + snrTemplate ), useEscalating: !!nodeHealthCheck.spec?.escalatingRemediations, };