Show error messages and toasters in Environment variables settings tab (#29)

* Display error if fields are empty

* Show number of added variables in toast

* Show horizontal line between different environments

---------

Co-authored-by: neeraj <neeraj.rtly@gmail.com>
This commit is contained in:
Nabarun Gogoi 2023-12-27 17:02:34 +05:30 committed by GitHub
parent 0268656d2f
commit 9b224f218a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 78 additions and 20 deletions

View File

@ -9,12 +9,14 @@ interface AddEnvironmentVariableRowProps {
onDelete: () => void; onDelete: () => void;
register: UseFormRegister<EnvironmentVariablesFormValues>; register: UseFormRegister<EnvironmentVariablesFormValues>;
index: number; index: number;
isDeleteDisabled: boolean;
} }
const AddEnvironmentVariableRow = ({ const AddEnvironmentVariableRow = ({
onDelete, onDelete,
register, register,
index, index,
isDeleteDisabled,
}: AddEnvironmentVariableRowProps) => { }: AddEnvironmentVariableRowProps) => {
return ( return (
<div className="flex gap-1 p-2"> <div className="flex gap-1 p-2">
@ -22,18 +24,26 @@ const AddEnvironmentVariableRow = ({
<Typography variant="small">Key</Typography> <Typography variant="small">Key</Typography>
<Input <Input
crossOrigin={undefined} crossOrigin={undefined}
{...register(`variables.${index}.key`)} {...register(`variables.${index}.key`, {
required: 'Key field cannot be empty',
})}
/> />
</div> </div>
<div> <div>
<Typography variant="small">Value</Typography> <Typography variant="small">Value</Typography>
<Input <Input
crossOrigin={undefined} crossOrigin={undefined}
{...register(`variables.${index}.value`)} {...register(`variables.${index}.value`, {
required: 'Value field cannot be empty',
})}
/> />
</div> </div>
<div className="self-end"> <div className="self-end">
<IconButton size="sm" onClick={() => onDelete()}> <IconButton
size="sm"
onClick={() => onDelete()}
disabled={isDeleteDisabled}
>
{'>'} {'>'}
</IconButton> </IconButton>
</div> </div>

View File

@ -2,7 +2,6 @@ import React, { useState } from 'react';
import { Card, Collapse, Typography } from '@material-tailwind/react'; import { Card, Collapse, Typography } from '@material-tailwind/react';
import HorizontalLine from '../../../HorizontalLine';
import EditEnvironmentVariableRow from './EditEnvironmentVariableRow'; import EditEnvironmentVariableRow from './EditEnvironmentVariableRow';
import { Environments, EnvironmentVariable } from '../../../../types/project'; import { Environments, EnvironmentVariable } from '../../../../types/project';
@ -26,7 +25,6 @@ const DisplayEnvironmentVariables = ({
<div>^</div> <div>^</div>
<div className="grow capitalize">{environment}</div> <div className="grow capitalize">{environment}</div>
<div>{variables.length} variables</div> <div>{variables.length} variables</div>
<HorizontalLine />
</div> </div>
<Collapse open={openCollapse}> <Collapse open={openCollapse}>
{variables.length === 0 ? ( {variables.length === 0 ? (

View File

@ -1,6 +1,6 @@
import React, { useCallback, useState } from 'react'; import React, { useCallback, useEffect, useMemo, useState } from 'react';
import { useFieldArray, useForm } from 'react-hook-form'; import { useFieldArray, useForm } from 'react-hook-form';
import { Toaster } from 'react-hot-toast'; import toast, { Toaster } from 'react-hot-toast';
import { import {
Typography, Typography,
@ -8,12 +8,14 @@ import {
Card, Card,
Button, Button,
Checkbox, Checkbox,
Chip,
} from '@material-tailwind/react'; } from '@material-tailwind/react';
import AddEnvironmentVariableRow from './AddEnvironmentVariableRow'; import AddEnvironmentVariableRow from './AddEnvironmentVariableRow';
import DisplayEnvironmentVariables from './DisplayEnvironmentVariables'; import DisplayEnvironmentVariables from './DisplayEnvironmentVariables';
import environmentVariablesData from '../../../../assets/environment-variables.json'; import environmentVariablesData from '../../../../assets/environment-variables.json';
import { EnvironmentVariable, Environments } from '../../../../types/project'; import { EnvironmentVariable, Environments } from '../../../../types/project';
import HorizontalLine from '../../../HorizontalLine';
export type EnvironmentVariablesFormValues = { export type EnvironmentVariablesFormValues = {
variables: { variables: {
@ -28,8 +30,13 @@ export type EnvironmentVariablesFormValues = {
}; };
export const EnvironmentVariablesTabPanel = () => { export const EnvironmentVariablesTabPanel = () => {
const { handleSubmit, register, control } = const {
useForm<EnvironmentVariablesFormValues>({ handleSubmit,
register,
control,
reset,
formState: { isSubmitSuccessful, errors },
} = useForm<EnvironmentVariablesFormValues>({
defaultValues: { defaultValues: {
variables: [{ key: '', value: '' }], variables: [{ key: '', value: '' }],
environment: { environment: {
@ -39,20 +46,43 @@ export const EnvironmentVariablesTabPanel = () => {
}, },
}, },
}); });
const [createNewVariable, setCreateNewVariable] = useState(false); const [createNewVariable, setCreateNewVariable] = useState(false);
const { fields, append, remove } = useFieldArray({ const { fields, append, remove } = useFieldArray({
name: 'variables', name: 'variables',
control, control,
rules: {
required: 'Add at least 1 environment variables',
},
}); });
useEffect(() => {
if (isSubmitSuccessful) {
reset();
}
}, [isSubmitSuccessful, reset]);
const getEnvironmentVariable = useCallback((environment: Environments) => { const getEnvironmentVariable = useCallback((environment: Environments) => {
return (environmentVariablesData as EnvironmentVariable[]).filter((item) => return (environmentVariablesData as EnvironmentVariable[]).filter((item) =>
item.environments.includes(environment), item.environments.includes(environment),
); );
}, []); }, []);
const isFieldEmpty = useMemo(() => {
if (errors.variables) {
return fields.some((_, index) => {
if (
errors.variables![index]?.value?.type === 'required' ||
errors.variables![index]?.key?.type === 'required'
) {
return true;
}
});
}
return false;
}, [fields, errors.variables]);
return ( return (
<> <>
<Typography variant="h6">Environment variables</Typography> <Typography variant="h6">Environment variables</Typography>
@ -67,8 +97,17 @@ export const EnvironmentVariablesTabPanel = () => {
+ Create new variable + Create new variable
</div> </div>
<Collapse open={createNewVariable}> <Collapse open={createNewVariable}>
<Card className="bg-white"> <Card className="bg-white p-2">
<form onSubmit={handleSubmit(() => {})}> <form
onSubmit={handleSubmit((data) => {
toast.success(
data.variables.length > 1
? `${data.variables.length} variables added`
: `Variable added`,
);
reset();
})}
>
{fields.map((field, index) => { {fields.map((field, index) => {
return ( return (
<AddEnvironmentVariableRow <AddEnvironmentVariableRow
@ -76,6 +115,7 @@ export const EnvironmentVariablesTabPanel = () => {
index={index} index={index}
register={register} register={register}
onDelete={() => remove(index)} onDelete={() => remove(index)}
isDeleteDisabled={fields.length === 1}
/> />
); );
})} })}
@ -96,6 +136,14 @@ export const EnvironmentVariablesTabPanel = () => {
^ Import .env ^ Import .env
</Button> </Button>
</div> </div>
{isFieldEmpty && (
<Chip
value="^ Please ensure no fields are empty before saving."
variant="outlined"
color="red"
size="sm"
/>
)}
<div> <div>
<Checkbox <Checkbox
crossOrigin={undefined} crossOrigin={undefined}
@ -130,10 +178,12 @@ export const EnvironmentVariablesTabPanel = () => {
environment={Environments.PRODUCTION} environment={Environments.PRODUCTION}
variables={getEnvironmentVariable(Environments.PRODUCTION)} variables={getEnvironmentVariable(Environments.PRODUCTION)}
/> />
<HorizontalLine />
<DisplayEnvironmentVariables <DisplayEnvironmentVariables
environment={Environments.PREVIEW} environment={Environments.PREVIEW}
variables={getEnvironmentVariable(Environments.PREVIEW)} variables={getEnvironmentVariable(Environments.PREVIEW)}
/> />
<HorizontalLine />
<DisplayEnvironmentVariables <DisplayEnvironmentVariables
environment={Environments.DEVELOPMENT} environment={Environments.DEVELOPMENT}
variables={getEnvironmentVariable(Environments.DEVELOPMENT)} variables={getEnvironmentVariable(Environments.DEVELOPMENT)}