Skip to content

Commit 22b3921

Browse files
committed
refactor: drop react-hook-form and use props-based env variable components
Replace react-hook-form integration in EnvironmentVariable components with the props-based approach consistent with the rest of the codebase. The shared component now accepts the upstream's full props interface (envVariables, setEnvVariables, hideAddButton, keyFieldsDisabled, isValueSecret, title, description) while retaining the Import button and EnvBulkImportModal. The add-new-agent component is updated to match, using formData/setFormData props. Removed react-hook-form and @hookform/resolvers from add-new-agent dependencies.
1 parent fa78555 commit 22b3921

File tree

2 files changed

+122
-85
lines changed

2 files changed

+122
-85
lines changed

console/workspaces/pages/add-new-agent/package.json

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -51,9 +51,6 @@
5151
"@agent-management-platform/types": "workspace:*",
5252
"@agent-management-platform/shared-component": "workspace:*",
5353
"dayjs": "1.11.18",
54-
"yup": "1.4.0",
55-
"react-hook-form": "7.53.0",
56-
"@hookform/resolvers": "3.9.0",
5754
"lodash": "4.17.21"
5855
},
5956
"devDependencies": {

console/workspaces/pages/add-new-agent/src/components/EnvironmentVariable.tsx

Lines changed: 122 additions & 82 deletions
Original file line numberDiff line numberDiff line change
@@ -16,102 +16,142 @@
1616
* under the License.
1717
*/
1818

19-
import { useState, useCallback, useMemo } from "react";
19+
import { useState, useCallback } from "react";
2020
import { Box, Button, Card, CardContent, Typography } from "@wso2/oxygen-ui";
2121
import { Plus as Add, FileText } from "@wso2/oxygen-ui-icons-react";
22-
import { useFieldArray, useFormContext, useWatch } from "react-hook-form";
2322
import { EnvVariableEditor } from "@agent-management-platform/views";
2423
import { EnvBulkImportModal, EnvVariable } from "@agent-management-platform/shared-component";
24+
import { CreateAgentFormValues } from "../form/schema";
2525

26-
export const EnvironmentVariable = () => {
27-
const { control, formState: { errors }, register, getValues } = useFormContext();
28-
const { fields, append, remove, replace } = useFieldArray({ control, name: 'env' });
29-
const watchedEnvValues = useWatch({ control, name: 'env' });
30-
const [importModalOpen, setImportModalOpen] = useState(false);
26+
interface EnvironmentVariableProps {
27+
formData: CreateAgentFormValues;
28+
setFormData: React.Dispatch<React.SetStateAction<CreateAgentFormValues>>;
29+
}
3130

32-
// Memoize envValues to stabilize dependency for useCallback
33-
const envValues = useMemo(
34-
() => (watchedEnvValues || []) as EnvVariable[],
35-
[watchedEnvValues]
36-
);
31+
export const EnvironmentVariable = ({
32+
formData,
33+
setFormData,
34+
}: EnvironmentVariableProps) => {
35+
const [importModalOpen, setImportModalOpen] = useState(false);
36+
const envVariables = formData.env || [];
37+
const isOneEmpty = envVariables.some((e) => !e?.key || !e?.value);
3738

38-
const isOneEmpty = envValues.some((e) => !e?.key || !e?.value);
39+
const handleAdd = () => {
40+
setFormData((prev) => ({
41+
...prev,
42+
env: [...(prev.env || []), { key: '', value: '' }],
43+
}));
44+
};
3945

40-
// Handle bulk import - merge imported vars with existing ones, remove empty rows
41-
const handleImport = useCallback((importedVars: EnvVariable[]) => {
42-
// Get current values directly from form to avoid stale closure
43-
const currentEnv = (getValues('env') || []) as EnvVariable[];
46+
const handleRemove = (index: number) => {
47+
setFormData((prev) => ({
48+
...prev,
49+
env: prev.env?.filter((_, i) => i !== index) || [],
50+
}));
51+
};
4452

45-
// Filter out rows with no key (value may be intentionally empty)
46-
const nonEmptyExisting = currentEnv.filter((env) => env?.key);
53+
const handleChange = (index: number, field: 'key' | 'value', value: string) => {
54+
setFormData((prev) => ({
55+
...prev,
56+
env: prev.env?.map((item, i) =>
57+
i === index ? { ...item, [field]: value } : item
58+
) || [],
59+
}));
60+
};
4761

48-
// Map existing keys to their values for merging
49-
const existingMap = new Map<string, string>();
50-
nonEmptyExisting.forEach((env) => {
51-
existingMap.set(env.key, env.value);
52-
});
62+
const handleInitialEdit = (field: 'key' | 'value', value: string) => {
63+
setFormData((prev) => {
64+
const envList = prev.env || [];
65+
if (envList.length > 0) {
66+
return {
67+
...prev,
68+
env: envList.map((item, i) =>
69+
i === 0 ? { ...item, [field]: value } : item
70+
),
71+
};
72+
}
73+
return {
74+
...prev,
75+
env: [{ key: field === 'key' ? value : '', value: field === 'value' ? value : '' }],
76+
};
77+
});
78+
};
5379

54-
// Merge: imported vars override existing ones with same key
55-
importedVars.forEach((imported) => {
56-
existingMap.set(imported.key, imported.value);
57-
});
80+
const handleImport = useCallback((importedVars: EnvVariable[]) => {
81+
setFormData((prev) => {
82+
// Filter out rows with no key (value may be intentionally empty)
83+
const nonEmpty = (prev.env || []).filter((env) => env?.key);
5884

59-
// Convert map back to array
60-
const mergedEnv = Array.from(existingMap.entries()).map(([key, value]) => ({ key, value }));
85+
// Build map from existing vars; imported vars override on same key
86+
const existingMap = new Map<string, string>(nonEmpty.map((env) => [env.key, env.value]));
87+
importedVars.forEach((v) => existingMap.set(v.key, v.value));
6188

62-
// Replace all fields with merged result
63-
replace(mergedEnv);
64-
}, [getValues, replace]);
89+
return {
90+
...prev,
91+
env: Array.from(existingMap.entries()).map(([key, value]) => ({ key, value })),
92+
};
93+
});
94+
}, [setFormData]);
6595

66-
const handleModalClose = useCallback(() => setImportModalOpen(false), []);
96+
const handleModalClose = useCallback(() => setImportModalOpen(false), []);
6797

68-
return (
69-
<Card variant="outlined">
70-
<CardContent>
71-
<Box display="flex" flexDirection="row" alignItems="center" gap={1}>
72-
<Typography variant="h5">
73-
Environment Variables (Optional)
74-
</Typography>
75-
</Box>
76-
<Box display="flex" flexDirection="column" py={2} gap={2}>
77-
{fields.map((field, index) => (
78-
<EnvVariableEditor
79-
key={field.id}
80-
fieldName="env"
81-
index={index}
82-
fieldId={field.id}
83-
register={register}
84-
errors={errors}
85-
onRemove={() => remove(index)}
86-
/>
87-
))}
88-
</Box>
89-
<Box display="flex" gap={1}>
90-
<Button
91-
startIcon={<Add fontSize="small" />}
92-
disabled={isOneEmpty}
93-
variant="outlined"
94-
color="primary"
95-
onClick={() => append({ key: '', value: '' })}
96-
>
97-
Add
98-
</Button>
99-
<Button
100-
startIcon={<FileText fontSize="small" />}
101-
variant="outlined"
102-
color="primary"
103-
onClick={() => setImportModalOpen(true)}
104-
>
105-
Import
106-
</Button>
107-
</Box>
98+
return (
99+
<Card variant="outlined">
100+
<CardContent>
101+
<Box display="flex" flexDirection="row" alignItems="center" gap={1}>
102+
<Typography variant="h5">
103+
Environment Variables (Optional)
104+
</Typography>
105+
</Box>
106+
<Box display="flex" flexDirection="column" py={2} gap={2}>
107+
{envVariables.length ? envVariables.map((item, index) => (
108+
<EnvVariableEditor
109+
key={`env-${index}`}
110+
index={index}
111+
keyValue={item.key || ''}
112+
valueValue={item.value || ''}
113+
onKeyChange={(value) => handleChange(index, 'key', value)}
114+
onValueChange={(value) => handleChange(index, 'value', value)}
115+
onRemove={() => handleRemove(index)}
116+
/>
117+
)) : (
118+
<EnvVariableEditor
119+
key="env-0"
120+
index={0}
121+
keyValue={envVariables?.[0]?.key || ''}
122+
valueValue={envVariables?.[0]?.value || ''}
123+
onKeyChange={(value) => handleInitialEdit('key', value)}
124+
onValueChange={(value) => handleInitialEdit('value', value)}
125+
onRemove={() => handleRemove(0)}
126+
/>
127+
)}
128+
</Box>
129+
<Box display="flex" gap={1}>
130+
<Button
131+
startIcon={<Add fontSize="small" />}
132+
disabled={isOneEmpty}
133+
variant="outlined"
134+
color="primary"
135+
onClick={handleAdd}
136+
>
137+
Add
138+
</Button>
139+
<Button
140+
startIcon={<FileText fontSize="small" />}
141+
variant="outlined"
142+
color="primary"
143+
onClick={() => setImportModalOpen(true)}
144+
>
145+
Import
146+
</Button>
147+
</Box>
108148

109-
<EnvBulkImportModal
110-
open={importModalOpen}
111-
onClose={handleModalClose}
112-
onImport={handleImport}
113-
/>
114-
</CardContent>
115-
</Card>
116-
);
149+
<EnvBulkImportModal
150+
open={importModalOpen}
151+
onClose={handleModalClose}
152+
onImport={handleImport}
153+
/>
154+
</CardContent>
155+
</Card>
156+
);
117157
};

0 commit comments

Comments
 (0)