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:
parent
0268656d2f
commit
9b224f218a
@ -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>
|
||||||
|
@ -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 ? (
|
||||||
|
@ -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)}
|
||||||
|
Loading…
Reference in New Issue
Block a user