Skip to content

Commit ea6b330

Browse files
Add provision to recipe parameters while enrolling applicaiton
https://issues.redhat.com/browse/DFBUGS-857 Signed-off-by: Timothy Asir Jeyasingh <[email protected]>
1 parent 837f2e0 commit ea6b330

File tree

5 files changed

+86
-3
lines changed

5 files changed

+86
-3
lines changed

locales/en/plugin__odf-console.json

+5-1
Original file line numberDiff line numberDiff line change
@@ -103,6 +103,10 @@
103103
"Select a recipe": "Select a recipe",
104104
"No recipe found": "No recipe found",
105105
"Required": "Required",
106+
"Recipe parameters": "Recipe parameters",
107+
"Set of rules and configurations that govern how data is selected, stored, and restored.": "Set of rules and configurations that govern how data is selected, stored, and restored.",
108+
"Add parameter": "Add parameter",
109+
"Value (optional)": "Value (optional)",
106110
"Label expressions": "Label expressions",
107111
"Protect all your Kubernetes objects matching the selected resource label value.": "Protect all your Kubernetes objects matching the selected resource label value.",
108112
"PVC label selectors": "PVC label selectors",
@@ -147,6 +151,7 @@
147151
"Type:": "Type:",
148152
"Recipe name:": "Recipe name:",
149153
"Recipe namespace:": "Recipe namespace:",
154+
"Recipe Parameters:": "Recipe Parameters:",
150155
"Label expressions:": "Label expressions:",
151156
"PVC label selectors:": "PVC label selectors:",
152157
"Replication": "Replication",
@@ -1304,7 +1309,6 @@
13041309
"Use different criteria for tagging your bucket.": "Use different criteria for tagging your bucket.",
13051310
"No tags are attached to this bucket.": "No tags are attached to this bucket.",
13061311
"Add tag": "Add tag",
1307-
"Value (optional)": "Value (optional)",
13081312
"Enter a valid rule name": "Enter a valid rule name",
13091313
"A rule name is required.": "A rule name is required.",
13101314
"A rule with this name already exists. Type a different name.": "A rule with this name already exists. Type a different name.",

packages/mco/components/discovered-application-wizard/utils/k8s-utils.ts

+11-2
Original file line numberDiff line numberDiff line change
@@ -31,10 +31,10 @@ export const getDRPCKindObj = (props: {
3131
k8sResourceReplicationInterval: string;
3232
recipeName?: string;
3333
recipeNamespace?: string;
34+
recipeParameters?: Record<string, string[]>;
3435
k8sResourceLabelExpressions?: MatchExpression[];
3536
pvcLabelExpressions?: MatchExpression[];
3637
placementName: string;
37-
recipeParameters?: Record<string, string[]>;
3838
labels?: ObjectMetadata['labels'];
3939
}): DRPlacementControlKind => ({
4040
apiVersion: getAPIVersionForModel(DRPlacementControlModel),
@@ -106,7 +106,7 @@ export const createPromise = (
106106
const { namespace, configuration, replication } = state;
107107
const { clusterName, namespaces, name } = namespace;
108108
const { protectionMethod, recipe, resourceLabels } = configuration;
109-
const { recipeName, recipeNamespace } = recipe;
109+
const { recipeName, recipeNamespace, recipeParameters } = recipe;
110110
const { k8sResourceLabelExpressions, pvcLabelExpressions } = resourceLabels;
111111
const { drPolicy, k8sResourceReplicationInterval } = replication;
112112
const namespaceList = namespaces.map(getName);
@@ -122,6 +122,14 @@ export const createPromise = (
122122
})
123123
);
124124

125+
const normalizedRecipeParameters: Record<string, string[]> =
126+
Object.fromEntries(
127+
Object.entries(recipeParameters || {}).map(([key, value]) => [
128+
key,
129+
[value],
130+
])
131+
);
132+
125133
promises.push(
126134
k8sCreate({
127135
model: DRPlacementControlModel,
@@ -132,6 +140,7 @@ export const createPromise = (
132140
protectionMethod,
133141
recipeName,
134142
recipeNamespace,
143+
recipeParameters: normalizedRecipeParameters,
135144
k8sResourceLabelExpressions,
136145
pvcLabelExpressions,
137146
drPolicyName: getName(drPolicy),

packages/mco/components/discovered-application-wizard/utils/reducer.ts

+20
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ export enum EnrollDiscoveredApplicationStateType {
1616
SET_NAMESPACES = 'NAMESPACE/SET_NAMESPACES',
1717
SET_PROTECTION_METHOD = 'CONFIGURATION/SET_PROTECTION_METHOD',
1818
SET_RECIPE_NAME_NAMESPACE = 'CONFIGURATION/RECIPE/SET_RECIPE_NAME_NAMESPACE',
19+
SET_RECIPE_PARAMETERS = 'SET_RECIPE_PARAMETERS',
1920
SET_K8S_RESOURCE_LABEL_EXPRESSIONS = 'CONFIGURATION/RESOURCE_LABEL/SET_K8S_RESOURCE_LABEL_EXPRESSIONS',
2021
SET_PVC_LABEL_EXPRESSIONS = 'CONFIGURATION/RESOURCE_LABEL/SET_PVC_LABEL_EXPRESSIONS',
2122
SET_POLICY = 'REPLICATION/SET_POLICY',
@@ -40,6 +41,7 @@ export type EnrollDiscoveredApplicationState = {
4041
recipeName: string;
4142
// recipe CR namespace
4243
recipeNamespace: string;
44+
recipeParameters: Record<string, string>;
4345
};
4446
resourceLabels: {
4547
k8sResourceLabelExpressions: MatchExpression[];
@@ -70,6 +72,7 @@ export const initialState: EnrollDiscoveredApplicationState = {
7072
recipe: {
7173
recipeName: '',
7274
recipeNamespace: '',
75+
recipeParameters: {},
7376
},
7477
resourceLabels: {
7578
k8sResourceLabelExpressions: [],
@@ -112,6 +115,10 @@ export type EnrollDiscoveredApplicationAction =
112115
type: EnrollDiscoveredApplicationStateType.SET_POLICY;
113116
payload: DRPolicyKind;
114117
}
118+
| {
119+
type: EnrollDiscoveredApplicationStateType.SET_RECIPE_PARAMETERS;
120+
payload: Record<string, string>;
121+
}
115122
| {
116123
type: EnrollDiscoveredApplicationStateType.SET_K8S_RESOURCE_REPLICATION_INTERVAL;
117124
payload: string;
@@ -159,6 +166,18 @@ export const reducer: EnrollReducer = (state, action) => {
159166
},
160167
};
161168
}
169+
case EnrollDiscoveredApplicationStateType.SET_RECIPE_PARAMETERS: {
170+
return {
171+
...state,
172+
configuration: {
173+
...state.configuration,
174+
recipe: {
175+
...state.configuration.recipe,
176+
recipeParameters: action.payload,
177+
},
178+
},
179+
};
180+
}
162181
case EnrollDiscoveredApplicationStateType.SET_RECIPE_NAME_NAMESPACE: {
163182
const [recipeName, recipeNamespace] = action.payload.split(
164183
NAME_NAMESPACE_SPLIT_CHAR
@@ -168,6 +187,7 @@ export const reducer: EnrollReducer = (state, action) => {
168187
configuration: {
169188
...state.configuration,
170189
recipe: {
190+
...state.configuration.recipe,
171191
recipeName,
172192
recipeNamespace,
173193
},

packages/mco/components/discovered-application-wizard/wizard-steps/configuration-step/recipe-selection.tsx

+43
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,13 @@ import * as React from 'react';
22
import { useACMSafeFetch } from '@odf/mco/hooks';
33
import { SearchResultItemType } from '@odf/mco/types';
44
import { queryRecipesFromCluster, getNameNamespace } from '@odf/mco/utils';
5+
import { FieldLevelHelp } from '@odf/shared';
56
import { SingleSelectDropdown } from '@odf/shared/dropdown';
67
import { StatusBox } from '@odf/shared/generic/status-box';
78
import { getName } from '@odf/shared/selectors';
89
import { useCustomTranslation } from '@odf/shared/useCustomTranslationHook';
910
import { getValidatedProp } from '@odf/shared/utils';
11+
import { LazyNameValueEditor } from '@odf/shared/utils/NameValueEditor';
1012
import { K8sResourceCommon } from '@openshift-console/dynamic-plugin-sdk';
1113
import { SelectOption } from '@patternfly/react-core/deprecated';
1214
import {
@@ -51,6 +53,9 @@ export const RecipeSelection: React.FC<RecipeSelectionProps> = ({
5153
dispatch,
5254
}) => {
5355
const { t } = useCustomTranslation();
56+
const [recipeParams, setRecipeParams] = React.useState<[string, string][]>([
57+
['', ''],
58+
]);
5459

5560
const searchQuery = React.useMemo(
5661
() => queryRecipesFromCluster(clusterName, namespaces.map(getName)),
@@ -81,6 +86,20 @@ export const RecipeSelection: React.FC<RecipeSelectionProps> = ({
8186
payload: nameNamespace,
8287
});
8388

89+
const updateRecipeParams = ({
90+
nameValuePairs,
91+
}: {
92+
nameValuePairs: [string, string][];
93+
}) => {
94+
// Filter valid key-value pairs and update global state
95+
setRecipeParams(nameValuePairs);
96+
const validPairs = nameValuePairs.filter(([key]) => key.trim());
97+
dispatch({
98+
type: EnrollDiscoveredApplicationStateType.SET_RECIPE_PARAMETERS,
99+
payload: Object.fromEntries(validPairs.map(([k, v]) => [k.trim(), v])),
100+
});
101+
};
102+
84103
return (
85104
<>
86105
{/* todo(bipuladh): Add form validation again */}
@@ -117,6 +136,30 @@ export const RecipeSelection: React.FC<RecipeSelectionProps> = ({
117136
) : (
118137
<StatusBox loaded={searchLoaded} loadError={searchError} />
119138
)}
139+
140+
{/* Key-Value Pair Input Fields */}
141+
{recipeNameNamespace && (
142+
<FormGroup
143+
label={t('Recipe parameters')}
144+
fieldId="recipe-parameters"
145+
labelIcon={
146+
<FieldLevelHelp>
147+
{t(
148+
'Set of rules and configurations that govern how data is selected, stored, and restored.'
149+
)}
150+
</FieldLevelHelp>
151+
}
152+
>
153+
<LazyNameValueEditor
154+
nameValuePairs={recipeParams}
155+
updateParentData={updateRecipeParams}
156+
addString={t('Add parameter')}
157+
valueString={t('Value (optional)')}
158+
nameMaxLength={128}
159+
valueMaxLength={256}
160+
/>
161+
</FormGroup>
162+
)}
120163
</>
121164
);
122165
};

packages/mco/components/discovered-application-wizard/wizard-steps/review-step/review-step.tsx

+7
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,13 @@ export const Review: React.FC<ReviewProps> = ({ state }) => {
6262
<ReviewAndCreationItem label={t('Recipe namespace:')}>
6363
{recipeNamespace}
6464
</ReviewAndCreationItem>
65+
{Object.keys(recipe.recipeParameters).length > 0 && (
66+
<ReviewAndCreationItem label={t('Recipe Parameters:')}>
67+
{Object.entries(recipe.recipeParameters)
68+
.map(([key, value]) => `${key}: ${value}`)
69+
.join(', ')}
70+
</ReviewAndCreationItem>
71+
)}
6572
</>
6673
)}
6774
{protectionMethod === ProtectionMethodType.RESOURCE_LABEL && (

0 commit comments

Comments
 (0)