[7/n][project settings ui] AddEnvironmentVariableRowProps Input (#29)

This commit is contained in:
Vivian Phung 2024-05-14 16:00:30 -04:00 committed by GitHub
commit abbda18fc7
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
15 changed files with 176 additions and 76 deletions

View File

@ -1,10 +1,9 @@
import { UseFormRegister } from 'react-hook-form';
import { Input } from 'components/shared/Input';
import { EnvironmentVariablesFormValues } from '../../../../types';
import { Button } from 'components/shared/Button';
import { TrashIcon } from 'components/shared/CustomIcon';
import { Input } from 'components/shared/Input';
interface AddEnvironmentVariableRowProps {
onDelete: () => void;
@ -20,28 +19,24 @@ const AddEnvironmentVariableRow = ({
isDeleteDisabled,
}: AddEnvironmentVariableRowProps) => {
return (
<div className="flex gap-1 p-2">
<div>
<div className="flex gap-1 py-4 self-stretch">
<Input
label="key"
size="sm"
size="md"
{...register(`variables.${index}.key`, {
required: 'Key field cannot be empty',
})}
label={index === 0 ? 'Key' : undefined}
/>
</div>
<div>
<Input
size="sm"
label="value"
size="md"
label={index === 0 ? 'Value' : undefined}
{...register(`variables.${index}.value`, {
required: 'Value field cannot be empty',
})}
/>
</div>
<div className="self-end">
<Button
size="sm"
size="md"
iconOnly
onClick={() => onDelete()}
disabled={isDeleteDisabled}

View File

@ -1,7 +1,6 @@
import { useCallback } from 'react';
import { useNavigate, useParams } from 'react-router-dom';
import { useForm } from 'react-hook-form';
import toast from 'react-hot-toast';
import { Project } from 'gql-client';
import {
@ -13,7 +12,9 @@ import {
Input,
Typography,
} from '@snowballtools/material-tailwind-react-fork';
import { useGQLClient } from '../../../../context/GQLClientContext';
import { useToast } from 'components/shared/Toast';
interface DeleteProjectDialogProp {
open: boolean;
@ -26,6 +27,7 @@ const DeleteProjectDialog = ({
handleOpen,
project,
}: DeleteProjectDialogProp) => {
const { toast, dismiss } = useToast();
const { orgSlug } = useParams();
const navigate = useNavigate();
const client = useGQLClient();
@ -46,7 +48,12 @@ const DeleteProjectDialog = ({
if (deleteProject) {
navigate(`/${orgSlug}`);
} else {
toast.error('Project not deleted');
toast({
id: 'project_not_deleted',
title: 'Project not deleted',
variant: 'error',
onDismiss: dismiss,
});
}
handleOpen();

View File

@ -1,12 +1,12 @@
import { useState } from 'react';
import {
Card,
Collapse,
Typography,
} from '@snowballtools/material-tailwind-react-fork';
import { Collapse } from '@snowballtools/material-tailwind-react-fork';
import EditEnvironmentVariableRow from './EditEnvironmentVariableRow';
import { Environment, EnvironmentVariable } from 'gql-client';
import {
ChevronDownSmallIcon,
ChevronUpSmallIcon,
} from 'components/shared/CustomIcon';
interface DisplayEnvironmentVariablesProps {
environment: Environment;
@ -27,20 +27,16 @@ const DisplayEnvironmentVariables = ({
className="flex gap-4 p-2"
onClick={() => setOpenCollapse((cur) => !cur)}
>
<div>^</div>
{openCollapse ? <ChevronUpSmallIcon /> : <ChevronDownSmallIcon />}
<div className="grow capitalize">{environment}</div>
<div>{variables.length} variables</div>
</div>
<Collapse open={openCollapse}>
{variables.length === 0 ? (
<Card className="bg-gray-300 flex items-center p-4">
<Typography variant="small" className="text-black">
No environment variables added yet.
</Typography>
<Typography variant="small">
Once you add them, theyll show up here.
</Typography>
</Card>
<div className="bg-slate-100 rounded-xl flex-col p-4">
No environment variables added yet. Once you add them, they'll show
up here.
</div>
) : (
variables.map((variable: EnvironmentVariable) => {
return (

View File

@ -1,5 +1,4 @@
import { useState } from 'react';
import toast from 'react-hot-toast';
import { Domain, DomainStatus, Project } from 'gql-client';
import {
@ -15,6 +14,7 @@ import {
import EditDomainDialog from './EditDomainDialog';
import { useGQLClient } from 'context/GQLClientContext';
import { DeleteDomainDialog } from 'components/projects/Dialog/DeleteDomainDialog';
import { useToast } from 'components/shared/Toast';
enum RefreshStatus {
IDLE,
@ -47,6 +47,7 @@ const DomainCard = ({
project,
onUpdate,
}: DomainCardProps) => {
const { toast, dismiss } = useToast();
const [refreshStatus, SetRefreshStatus] = useState(RefreshStatus.IDLE);
const [deleteDialogOpen, setDeleteDialogOpen] = useState(false);
const [editDialogOpen, setEditDialogOpen] = useState(false);
@ -58,9 +59,19 @@ const DomainCard = ({
if (deleteDomain) {
onUpdate();
toast.success(`Domain ${domain.name} deleted successfully`);
toast({
id: 'domain_deleted_success',
title: 'Domain deleted',
variant: 'success',
onDismiss: dismiss,
});
} else {
toast.error(`Error deleting domain ${domain.name}`);
toast({
id: 'domain_deleted_error',
title: `Error deleting domain ${domain.name}`,
variant: 'error',
onDismiss: dismiss,
});
}
};

View File

@ -5,12 +5,12 @@ import { EnvironmentVariable } from 'gql-client';
import {
IconButton,
Input,
Typography,
} from '@snowballtools/material-tailwind-react-fork';
import { useGQLClient } from 'context/GQLClientContext';
import { DeleteVariableDialog } from 'components/projects/Dialog/DeleteVariableDialog';
import { Input } from 'components/shared/Input';
const ShowPasswordIcon = ({
handler,
@ -96,7 +96,7 @@ const EditEnvironmentVariableRow = ({
<Input
disabled={!edit}
type={showPassword ? 'text' : 'password'}
icon={
leftIcon={
<ShowPasswordIcon
handler={() => {
setShowPassword((prevShowPassword) => !prevShowPassword);

View File

@ -1,4 +1,4 @@
import { GitSelect } from '../../../../types/types';
import { GitSelect } from '../../../../types';
const GitSelectionSection = ({
gitSelectionHandler,

View File

@ -5,12 +5,12 @@ import {
Select,
Option,
Chip,
IconButton,
Tooltip,
} from '@snowballtools/material-tailwind-react-fork';
import { formatAddress } from 'utils/format';
import { RemoveMemberDialog } from 'components/projects/Dialog/RemoveMemberDialog';
import { Tooltip } from 'components/shared/Tooltip';
import { Button } from 'components/shared/Button';
const PERMISSION_OPTIONS = [
{
@ -125,15 +125,15 @@ const MemberCard = ({
/>
</div>
<div>
<IconButton
<Button
size="sm"
className="rounded-full"
iconOnly
onClick={() => {
setRemoveMemberDialogOpen((prevVal) => !prevVal);
}}
>
D
</IconButton>
</Button>
</div>
</div>
)}

View File

@ -1,9 +1,8 @@
import { useState } from 'react';
import toast from 'react-hot-toast';
import { Button } from '@snowballtools/material-tailwind-react-fork';
import { DeleteWebhookDialog } from 'components/projects/Dialog/DeleteWebhookDialog';
import { Button } from 'components/shared/Button';
interface WebhookCardProps {
webhookUrl: string;
@ -26,8 +25,8 @@ const WebhookCard = ({ webhookUrl, onDelete }: WebhookCardProps) => {
C
</Button>
<Button
color="red"
size="sm"
variant="danger"
onClick={() => {
setDeleteDialogOpen(true);
}}

View File

@ -0,0 +1,20 @@
import { CustomIcon, CustomIconProps } from './CustomIcon';
export const ChevronDownSmallIcon = (props: CustomIconProps) => {
return (
<CustomIcon
width="24"
height="24"
viewBox="0 0 24 24"
fill="none"
{...props}
>
<path
fill-rule="evenodd"
clip-rule="evenodd"
d="M11.4697 14.5303C11.7626 14.8232 12.2374 14.8232 12.5303 14.5303L16.5303 10.5303C16.8232 10.2374 16.8232 9.76256 16.5303 9.46967C16.2374 9.17678 15.7626 9.17678 15.4697 9.46967L12 12.9393L8.53033 9.46967C8.23744 9.17678 7.76256 9.17678 7.46967 9.46967C7.17678 9.76256 7.17678 10.2374 7.46967 10.5303L11.4697 14.5303Z"
fill="currentColor"
/>
</CustomIcon>
);
};

View File

@ -0,0 +1,20 @@
import { CustomIcon, CustomIconProps } from './CustomIcon';
export const ChevronUpSmallIcon = (props: CustomIconProps) => {
return (
<CustomIcon
width="24"
height="24"
viewBox="0 0 24 24"
fill="none"
{...props}
>
<path
fill-rule="evenodd"
clip-rule="evenodd"
d="M11.4697 9.46967C11.7626 9.17678 12.2374 9.17678 12.5303 9.46967L16.5303 13.4697C16.8232 13.7626 16.8232 14.2374 16.5303 14.5303C16.2374 14.8232 15.7626 14.8232 15.4697 14.5303L12 11.0607L8.53033 14.5303C8.23744 14.8232 7.76256 14.8232 7.46967 14.5303C7.17678 14.2374 7.17678 13.7626 7.46967 13.4697L11.4697 9.46967Z"
fill="currentColor"
/>
</CustomIcon>
);
};

View File

@ -71,6 +71,8 @@ export * from './TrashIcon';
export * from './CopyUnfilledIcon';
export * from './SwitchIcon';
export * from './CollaboratorsIcon';
export * from './ChevronUpSmallIcon';
export * from './ChevronDownSmallIcon';
// Templates
export * from './templates';

View File

@ -4,20 +4,18 @@ import toast from 'react-hot-toast';
import { useParams } from 'react-router-dom';
import { Environment, EnvironmentVariable } from 'gql-client';
import {
Collapse,
Card,
Chip,
} from '@snowballtools/material-tailwind-react-fork';
import { Collapse } from '@snowballtools/material-tailwind-react-fork';
import { useGQLClient } from '../../../../../context/GQLClientContext';
import { EnvironmentVariablesFormValues } from '../../../../../types';
import AddEnvironmentVariableRow from 'components/projects/project/settings/AddEnvironmentVariableRow';
import DisplayEnvironmentVariables from 'components/projects/project/settings/DisplayEnvironmentVariables';
import { useGQLClient } from '../../../../../context/GQLClientContext';
import { EnvironmentVariablesFormValues } from '../../../../../types';
import HorizontalLine from 'components/HorizontalLine';
import { Heading } from 'components/shared/Heading';
import { Button } from 'components/shared/Button';
import { Checkbox } from 'components/shared/Checkbox';
import { PlusIcon } from 'components/shared/CustomIcon';
import { InlineNotification } from 'components/shared/InlineNotification';
export const EnvironmentVariablesTabPanel = () => {
const { id } = useParams();
@ -139,15 +137,18 @@ export const EnvironmentVariablesTabPanel = () => {
<p className="text-slate-600 text-sm font-normal leading-tight">
A new deployment is required for your changes to take effect.
</p>
<div className="bg-gray-300 rounded-lg p-2">
<div
className="text-black"
<div className="bg-slate-100 rounded-xl flex-col">
<Heading
onClick={() => setCreateNewVariable((cur) => !cur)}
className="p-4"
>
+ Create new variable
<div className="flex gap-2 items-center">
<PlusIcon />
<span>Create new variable</span>
</div>
</Heading>
<Collapse open={createNewVariable}>
<Card className="bg-white p-2">
<div className="p-4 bg-slate-100">
<form onSubmit={handleSubmit(createEnvironmentVariablesHandler)}>
{fields.map((field, index) => {
return (
@ -162,7 +163,7 @@ export const EnvironmentVariablesTabPanel = () => {
})}
<div className="flex gap-1 p-2">
<Button
size="sm"
size="md"
onClick={() =>
append({
key: '',
@ -173,19 +174,18 @@ export const EnvironmentVariablesTabPanel = () => {
+ Add variable
</Button>
{/* TODO: Implement import environment varible functionality */}
<Button size="sm" disabled>
<Button size="md" disabled>
Import .env
</Button>
</div>
{isFieldEmpty && (
<Chip
value="^ Please ensure no fields are empty before saving."
variant="outlined"
color="red"
size="sm"
<InlineNotification
title="Please ensure no fields are empty before saving."
variant="danger"
size="md"
/>
)}
<div>
<div className="flex gap-2 p-2">
<Checkbox
label="Production"
{...register(`environment.production`)}
@ -208,7 +208,7 @@ export const EnvironmentVariablesTabPanel = () => {
</Button>
</div>
</form>
</Card>
</div>
</Collapse>
</div>
<div className="p-2">

View File

@ -0,0 +1,25 @@
import { Meta, StoryObj } from '@storybook/react';
import { ChevronDownSmallIcon } from 'components/shared/CustomIcon';
const meta: Meta<typeof ChevronDownSmallIcon> = {
title: 'Icons/ChevronDownSmallIcon',
component: ChevronDownSmallIcon,
tags: ['autodocs'],
args: {
size: 'string | number' as unknown as any,
name: 'string',
},
};
export default meta;
type Story = StoryObj<typeof ChevronDownSmallIcon>;
export const Default: Story = {
render: ({ size, name }) => <ChevronDownSmallIcon size={size} name={name} />,
args: {
size: '24px',
name: 'plus',
},
};

View File

@ -1,6 +1,6 @@
import { Meta, StoryObj } from '@storybook/react';
import { ChevronUpDown } from 'components/shared/CustomIcon/ChevronUpDown';
import { ChevronUpDown } from 'components/shared/CustomIcon';
const meta: Meta<typeof ChevronUpDown> = {
title: 'Icons/ChevronUpDown',

View File

@ -0,0 +1,25 @@
import { Meta, StoryObj } from '@storybook/react';
import { ChevronUpSmallIcon } from 'components/shared/CustomIcon';
const meta: Meta<typeof ChevronUpSmallIcon> = {
title: 'Components/ChevronUpSmallIcon',
component: ChevronUpSmallIcon,
tags: ['autodocs'],
args: {
size: 'string | number' as unknown as any,
name: 'string',
},
};
export default meta;
type Story = StoryObj<typeof ChevronUpSmallIcon>;
export const Default: Story = {
render: ({ size, name }) => <ChevronUpSmallIcon size={size} name={name} />,
args: {
size: '24px',
name: 'chevron-up',
},
};