diff --git a/packages/frontend/package.json b/packages/frontend/package.json index 0f741c0c..0ae20f9b 100644 --- a/packages/frontend/package.json +++ b/packages/frontend/package.json @@ -102,4 +102,4 @@ "typescript": "^5.3.3", "vite": "^5.2.0" } -} \ No newline at end of file +} diff --git a/packages/frontend/src/components/projects/project/settings/AddEnvironmentVariableRow.tsx b/packages/frontend/src/components/projects/project/settings/AddEnvironmentVariableRow.tsx index b29b4aa4..016e852b 100644 --- a/packages/frontend/src/components/projects/project/settings/AddEnvironmentVariableRow.tsx +++ b/packages/frontend/src/components/projects/project/settings/AddEnvironmentVariableRow.tsx @@ -19,7 +19,7 @@ const AddEnvironmentVariableRow = ({ isDeleteDisabled, }: AddEnvironmentVariableRowProps) => { return ( -
+
-
- -
+
); }; diff --git a/packages/frontend/src/components/projects/project/settings/DeleteProjectDialog.tsx b/packages/frontend/src/components/projects/project/settings/DeleteProjectDialog.tsx index 552216ea..b3285e82 100644 --- a/packages/frontend/src/components/projects/project/settings/DeleteProjectDialog.tsx +++ b/packages/frontend/src/components/projects/project/settings/DeleteProjectDialog.tsx @@ -1,20 +1,13 @@ import { useCallback } from 'react'; import { useNavigate, useParams } from 'react-router-dom'; import { useForm } from 'react-hook-form'; -import { Project } from 'gql-client'; -import { - Button, - Dialog, - DialogHeader, - DialogBody, - DialogFooter, - Input, - Typography, -} from '@snowballtools/material-tailwind-react-fork'; - -import { useGQLClient } from '../../../../context/GQLClientContext'; +import { useGQLClient } from 'context/GQLClientContext'; import { useToast } from 'components/shared/Toast'; +import { Modal } from 'components/shared/Modal'; +import { Button } from 'components/shared/Button'; +import { Input } from 'components/shared/Input'; +import { Project } from 'gql-client'; interface DeleteProjectDialogProp { open: boolean; @@ -60,51 +53,36 @@ const DeleteProjectDialog = ({ }, [client, project, handleOpen]); return ( - - -
Delete project?
- -
-
- - - Deleting your project is irreversible. Enter your project’s - name  - ({project.name}) -  below to confirm you want to permanently delete it: - - value === project.name, - })} - /> - - ^ Deleting your project is irreversible. - - - - - - -
-
+ + + Delete project? +
+ + value === project.name, + })} + helperText="Deleting your project is irreversible." + /> + + + + + +
+
+
); }; diff --git a/packages/frontend/src/components/projects/project/settings/EditEnvironmentVariableRow.tsx b/packages/frontend/src/components/projects/project/settings/EditEnvironmentVariableRow.tsx index 95661806..7f7a519e 100644 --- a/packages/frontend/src/components/projects/project/settings/EditEnvironmentVariableRow.tsx +++ b/packages/frontend/src/components/projects/project/settings/EditEnvironmentVariableRow.tsx @@ -1,16 +1,20 @@ import { useCallback, useEffect, useState } from 'react'; import { useForm } from 'react-hook-form'; -import toast from 'react-hot-toast'; -import { EnvironmentVariable } from 'gql-client'; - -import { - IconButton, - 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'; +import { Button } from 'components/shared/Button'; +import { + CheckRoundFilledIcon, + CrossIcon, + EditBigIcon, + HideEyeOffIcon, + ShowEyeIcon, + TrashIcon, +} from 'components/shared/CustomIcon'; +import { EnvironmentVariable } from 'gql-client'; +import { useToast } from 'components/shared/Toast'; const ShowPasswordIcon = ({ handler, @@ -26,19 +30,24 @@ const ShowPasswordIcon = ({ }} className="cursor-pointer" > - {isVisible ? '-' : '+'} + {isVisible ? : } ); }; +export interface EditEnvironmentVariableRowProps { + variable: EnvironmentVariable; + onUpdate: () => Promise; + isFirstVariable?: boolean; +} + const EditEnvironmentVariableRow = ({ variable, onUpdate, -}: { - variable: EnvironmentVariable; - onUpdate: () => Promise; -}) => { + isFirstVariable = false, +}: EditEnvironmentVariableRowProps) => { const client = useGQLClient(); + const { toast, dismiss } = useToast(); const { handleSubmit, register, reset } = useForm({ defaultValues: { @@ -58,9 +67,19 @@ const EditEnvironmentVariableRow = ({ if (isEnvironmentVariableRemoved) { await onUpdate(); setDeleteDialogOpen((preVal) => !preVal); - toast.success('Variable deleted'); + toast({ + id: 'variable_deleted', + title: 'Variable deleted', + variant: 'success', + onDismiss: dismiss, + }); } else { - toast.error('Variable not deleted'); + toast({ + id: 'variable_not_deleted', + title: 'Variable not deleted', + variant: 'error', + onDismiss: dismiss, + }); } }, [variable, onUpdate]); @@ -71,10 +90,21 @@ const EditEnvironmentVariableRow = ({ if (isEnvironmentVariableUpdated) { await onUpdate(); - toast.success('Variable edited'); + toast({ + id: 'variable_updated', + title: 'Variable edited', + variant: 'success', + onDismiss: dismiss, + }); + setEdit((preVal) => !preVal); } else { - toast.error('Variable not edited'); + toast({ + id: 'variable_not_updated', + title: 'Variable not edited', + variant: 'error', + onDismiss: dismiss, + }); } }, [variable, onUpdate], @@ -86,71 +116,55 @@ const EditEnvironmentVariableRow = ({ return ( <> -
-
- Key - -
-
- Value - { - setShowPassword((prevShowPassword) => !prevShowPassword); - }} - isVisible={showPassword} - /> +
+ + { + setShowPassword((prevShowPassword) => !prevShowPassword); + }} + isVisible={showPassword || edit} + /> + } + {...register(`value`)} + /> + +
- {edit ? ( - <> -
- - {'S'} - -
-
- { - reset(); - setEdit((preVal) => !preVal); - }} - > - {'C'} - -
- - ) : ( - <> -
- { - setEdit((preVal) => !preVal); - }} - > - {'E'} - -
-
- setDeleteDialogOpen((preVal) => !preVal)} - > - {'D'} - -
- - )} + }} + > + {edit ? : } +
setDeleteDialogOpen((preVal) => !preVal)} diff --git a/packages/frontend/src/components/projects/project/settings/MemberCard.tsx b/packages/frontend/src/components/projects/project/settings/MemberCard.tsx index d31d47f6..bf6e598f 100644 --- a/packages/frontend/src/components/projects/project/settings/MemberCard.tsx +++ b/packages/frontend/src/components/projects/project/settings/MemberCard.tsx @@ -80,7 +80,7 @@ const MemberCard = ({ return (
{member.name && ( diff --git a/packages/frontend/src/components/shared/Calendar/Calendar.css b/packages/frontend/src/components/shared/Calendar/Calendar.css index 85ce4182..49bf10d3 100644 --- a/packages/frontend/src/components/shared/Calendar/Calendar.css +++ b/packages/frontend/src/components/shared/Calendar/Calendar.css @@ -30,7 +30,7 @@ abbr[title] { @apply !text-elements-disabled !bg-transparent; } -.react-calendar__month-view__days__day--neighboringMonth { +.react-calendar__month-view__days__day--neighboringMonth:focus-visible { @apply !text-elements-disabled !bg-transparent; } diff --git a/packages/frontend/src/components/shared/CustomIcon/EditBigIcon.tsx b/packages/frontend/src/components/shared/CustomIcon/EditBigIcon.tsx new file mode 100644 index 00000000..0e69acef --- /dev/null +++ b/packages/frontend/src/components/shared/CustomIcon/EditBigIcon.tsx @@ -0,0 +1,26 @@ +import { CustomIcon, CustomIconProps } from './CustomIcon'; + +export const EditBigIcon: React.FC = (props) => { + return ( + + + + + + + ); +}; diff --git a/packages/frontend/src/components/shared/CustomIcon/HideEyeOffIcon.tsx b/packages/frontend/src/components/shared/CustomIcon/HideEyeOffIcon.tsx new file mode 100644 index 00000000..dd95373f --- /dev/null +++ b/packages/frontend/src/components/shared/CustomIcon/HideEyeOffIcon.tsx @@ -0,0 +1,18 @@ +import { CustomIcon, CustomIconProps } from './CustomIcon'; + +export const HideEyeOffIcon: React.FC = (props) => { + return ( + + + + ); +}; diff --git a/packages/frontend/src/components/shared/CustomIcon/ShowEyeIcon.tsx b/packages/frontend/src/components/shared/CustomIcon/ShowEyeIcon.tsx new file mode 100644 index 00000000..17aa1744 --- /dev/null +++ b/packages/frontend/src/components/shared/CustomIcon/ShowEyeIcon.tsx @@ -0,0 +1,18 @@ +import { CustomIcon, CustomIconProps } from './CustomIcon'; + +export const ShowEyeIcon: React.FC = (props) => { + return ( + + + + ); +}; diff --git a/packages/frontend/src/components/shared/CustomIcon/index.ts b/packages/frontend/src/components/shared/CustomIcon/index.ts index cfa0f2dc..2a7feddf 100644 --- a/packages/frontend/src/components/shared/CustomIcon/index.ts +++ b/packages/frontend/src/components/shared/CustomIcon/index.ts @@ -73,6 +73,9 @@ export * from './SwitchIcon'; export * from './CollaboratorsIcon'; export * from './ChevronUpSmallIcon'; export * from './ChevronDownSmallIcon'; +export * from './EditBigIcon'; +export * from './ShowEyeIcon'; +export * from './HideEyeOffIcon'; // Templates export * from './templates'; diff --git a/packages/frontend/src/pages/org-slug/projects/id/settings/General.tsx b/packages/frontend/src/pages/org-slug/projects/id/settings/General.tsx index 25302ae8..92f6d708 100644 --- a/packages/frontend/src/pages/org-slug/projects/id/settings/General.tsx +++ b/packages/frontend/src/pages/org-slug/projects/id/settings/General.tsx @@ -166,7 +166,7 @@ const GeneralTabPanel = () => { setSelectedTransferOrganization(org.org); setOpenTransferDialog(!openTransferDialog); })} - className="self-stretch space-y-3 px-2" + className="self-stretch space-y-3" > Transfer project @@ -197,7 +197,7 @@ const GeneralTabPanel = () => { from={project.organization.name} to={selectedUserOrgName} /> -
+
Delete project diff --git a/packages/frontend/src/stories/Components/Icons/EditBigIcon.stories.tsx b/packages/frontend/src/stories/Components/Icons/EditBigIcon.stories.tsx new file mode 100644 index 00000000..d91df2b9 --- /dev/null +++ b/packages/frontend/src/stories/Components/Icons/EditBigIcon.stories.tsx @@ -0,0 +1,29 @@ +import { Meta, StoryObj } from '@storybook/react'; + +import { EditBigIcon } from 'components/shared/CustomIcon'; + +const meta: Meta = { + title: 'Icons/EditBigIcon', + component: EditBigIcon, + tags: ['autodocs'], + argTypes: { + size: { + control: 'text', + }, + name: { + control: 'text', + }, + }, +}; + +export default meta; + +type Story = StoryObj; + +export const Default: Story = { + render: ({ size, name }) => , + args: { + size: '24px', + name: 'plus', + }, +}; diff --git a/packages/frontend/src/stories/Components/Icons/HideEyeOffIcon.stories.tsx b/packages/frontend/src/stories/Components/Icons/HideEyeOffIcon.stories.tsx new file mode 100644 index 00000000..ba8e2817 --- /dev/null +++ b/packages/frontend/src/stories/Components/Icons/HideEyeOffIcon.stories.tsx @@ -0,0 +1,29 @@ +import { Meta, StoryObj } from '@storybook/react'; + +import { HideEyeOffIcon } from 'components/shared/CustomIcon'; + +const meta: Meta = { + title: 'Icons/HideEyeOffIcon', + component: HideEyeOffIcon, + tags: ['autodocs'], + argTypes: { + size: { + control: 'text', + }, + name: { + control: 'text', + }, + }, +}; + +export default meta; + +type Story = StoryObj; + +export const Default: Story = { + render: ({ size, name }) => , + args: { + size: '24px', + name: 'plus', + }, +}; diff --git a/packages/frontend/src/stories/Components/Icons/ShowEyeIcon.stories.tsx b/packages/frontend/src/stories/Components/Icons/ShowEyeIcon.stories.tsx new file mode 100644 index 00000000..dbe81967 --- /dev/null +++ b/packages/frontend/src/stories/Components/Icons/ShowEyeIcon.stories.tsx @@ -0,0 +1,29 @@ +import { Meta, StoryObj } from '@storybook/react'; + +import { ShowEyeIcon } from 'components/shared/CustomIcon'; + +const meta: Meta = { + title: 'Icons/ShowEyeIcon', + component: ShowEyeIcon, + tags: ['autodocs'], + argTypes: { + size: { + control: 'text', + }, + name: { + control: 'text', + }, + }, +}; + +export default meta; + +type Story = StoryObj; + +export const Default: Story = { + render: ({ size, name }) => , + args: { + size: '24px', + name: 'plus', + }, +}; diff --git a/packages/frontend/src/stories/MockStoriesData.ts b/packages/frontend/src/stories/MockStoriesData.ts new file mode 100644 index 00000000..c3e3ac25 --- /dev/null +++ b/packages/frontend/src/stories/MockStoriesData.ts @@ -0,0 +1,114 @@ +import { + User, + Project, + Organization, + Role, + OrganizationMember, + ProjectMember, + EnvironmentVariable, + Deployment, + DeploymentStatus, + DomainStatus, + Domain, + Environment, +} from 'gql-client'; + +export const user: User = { + id: '1', + email: 'helloworld@helloworld.com', + isVerified: true, + createdAt: '2021-08-01T00:00:00.000Z', + name: 'Hello World', + updatedAt: '2021-08-01T00:00:00.000Z', + gitHubToken: 'GitHub Token', +}; + +export const organizationMember: OrganizationMember = { + id: '1', + member: user, + role: Role.Owner, + createdAt: '2021-08-01T00:00:00.000Z', + updatedAt: '2021-08-01T00:00:00.000Z', +}; + +export const organization: Organization = { + id: '1', + name: 'Organization', + slug: 'organization', + createdAt: '2021-08-01T00:00:00.000Z', + updatedAt: '2021-08-01T00:00:00.000Z', + members: [organizationMember], + projects: [], +}; + +export const member: ProjectMember = { + id: '1', + member: user, + permissions: [], + isPending: false, + createdAt: '2021-08-01T00:00:00.000Z', + updatedAt: '2021-08-01T00:00:00.000Z', +}; + +export const environmentVariable0: EnvironmentVariable = { + id: '1', + key: 'API_KEY', + value: '123456', + environment: Environment.Development, + createdAt: '2021-08-01T00:00:00.000Z', + updatedAt: '2021-08-01T00:00:00.000Z', +}; + +export const environmentVariable1: EnvironmentVariable = { + id: '2', + key: 'API_KEY_2', + value: '123456', + environment: Environment.Development, + createdAt: '2021-08-01T00:00:00.000Z', + updatedAt: '2021-08-01T00:00:00.000Z', +}; + +export const domain0: Domain = { + id: '1', + name: 'Domain', + createdAt: '2021-08-01T00:00:00.000Z', + updatedAt: '2021-08-01T00:00:00.000Z', + branch: 'Branch', + status: DomainStatus.Live, + redirectTo: null, +}; + +export const deployment0: Deployment = { + id: '1', + url: 'https://deployment.com', + status: DeploymentStatus.Ready, + createdAt: '2021-08-01T00:00:00.000Z', + updatedAt: '2021-08-01T00:00:00.000Z', + branch: 'Branch', + environment: Environment.Development, + isCurrent: true, + commitHash: 'Commit Hash', + domain: domain0, + commitMessage: 'Commit Message', + createdBy: user, +}; + +export const project: Project = { + id: '1', + name: 'GithubUsername-ProjectName', + owner: user, + deployments: [deployment0], + repository: 'Repository', + prodBranch: 'Prod Branch', + description: 'Description', + createdAt: '2021-08-01T00:00:00.000Z', + updatedAt: '2021-08-01T00:00:00.000Z', + framework: 'NextJS', + environmentVariables: [environmentVariable0, environmentVariable1], + organization: organization, + template: 'Template', + members: [member], + webhooks: ['beepboop'], + icon: 'Icon', + subDomain: 'SubDomain', +}; diff --git a/packages/frontend/src/stories/Project/Settings/General.stories.tsx b/packages/frontend/src/stories/Project/Settings/AddEnvironmentVariableRow.stories.tsx similarity index 63% rename from packages/frontend/src/stories/Project/Settings/General.stories.tsx rename to packages/frontend/src/stories/Project/Settings/AddEnvironmentVariableRow.stories.tsx index 9851e20b..458bfa70 100644 --- a/packages/frontend/src/stories/Project/Settings/General.stories.tsx +++ b/packages/frontend/src/stories/Project/Settings/AddEnvironmentVariableRow.stories.tsx @@ -21,10 +21,45 @@ const meta: Meta = { }, }), }, -} as Meta; + argTypes: { + onDelete: { + action: 'delete', + }, + register: { + action: 'register', + }, + index: { + type: 'number', + }, + isDeleteDisabled: { + type: 'boolean', + }, + }, + args: { + isDeleteDisabled: false, + }, +}; export default meta; type Story = StoryObj; export const Default: Story = {}; + +export const DisabledDelete: Story = { + args: { + isDeleteDisabled: true, + }, +}; + +export const First: Story = { + args: { + index: 0, + }, +}; + +export const Second: Story = { + args: { + index: 1, + }, +}; diff --git a/packages/frontend/src/stories/Project/Settings/AddMemberDialog.stories.tsx b/packages/frontend/src/stories/Project/Settings/AddMemberDialog.stories.tsx new file mode 100644 index 00000000..8c7a55c8 --- /dev/null +++ b/packages/frontend/src/stories/Project/Settings/AddMemberDialog.stories.tsx @@ -0,0 +1,31 @@ +import { Meta, StoryObj } from '@storybook/react'; + +import AddMemberDialog from 'components/projects/project/settings/AddMemberDialog'; + +const meta: Meta = { + title: 'Project/Settings/AddMemberDialog', + component: AddMemberDialog, + tags: ['autodocs'], + argTypes: { + open: { + control: { + type: 'boolean', + }, + }, + handleOpen: { + action: 'open', + }, + handleAddMember: { + action: 'addMember', + }, + }, + args: { + open: true, + }, +}; + +export default meta; + +type Story = StoryObj; + +export const Default: Story = {}; diff --git a/packages/frontend/src/stories/Project/Settings/DeleteProjectDialog.stories.tsx b/packages/frontend/src/stories/Project/Settings/DeleteProjectDialog.stories.tsx new file mode 100644 index 00000000..e3fe7f7e --- /dev/null +++ b/packages/frontend/src/stories/Project/Settings/DeleteProjectDialog.stories.tsx @@ -0,0 +1,50 @@ +import { Meta, StoryObj } from '@storybook/react'; +import { + reactRouterParameters, + withRouter, +} from 'storybook-addon-remix-react-router'; + +import DeleteProjectDialog from 'components/projects/project/settings/DeleteProjectDialog'; +import { project } from '../../MockStoriesData'; + +const meta: Meta = { + title: 'Project/Settings/DeleteProjectDialog', + component: DeleteProjectDialog, + tags: ['autodocs'], + decorators: [withRouter], + parameters: { + reactRouter: reactRouterParameters({ + location: { + pathParams: { userId: 'me' }, + }, + routing: { + path: '/snowball-tools-1/projects/6bb3bec2-d71b-4fc0-9e32-4767f68668f4/settings', + }, + }), + }, + argTypes: { + open: { + control: { + type: 'boolean', + }, + }, + handleOpen: { + action: 'open', + }, + project: { + control: { + type: 'object', + }, + }, + }, + args: { + open: true, + project: project, + }, +}; + +export default meta; + +type Story = StoryObj; + +export const Default: Story = {}; diff --git a/packages/frontend/src/stories/Project/Settings/DisplayEnvironmentVariables.stories.tsx b/packages/frontend/src/stories/Project/Settings/DisplayEnvironmentVariables.stories.tsx new file mode 100644 index 00000000..a3ccc0a8 --- /dev/null +++ b/packages/frontend/src/stories/Project/Settings/DisplayEnvironmentVariables.stories.tsx @@ -0,0 +1,38 @@ +import { Meta, StoryObj } from '@storybook/react'; + +import DisplayEnvironmentVariables from 'components/projects/project/settings/DisplayEnvironmentVariables'; +import { + environmentVariable0, + environmentVariable1, +} from '../../MockStoriesData'; +import { Environment } from 'gql-client'; + +const meta: Meta = { + title: 'Project/Settings/DisplayEnvironmentVariables', + component: DisplayEnvironmentVariables, + argTypes: { + environment: { + control: { + type: 'object', + }, + }, + variables: { + control: { + type: 'object', + }, + }, + onUpdate: { + action: 'update', + }, + }, + args: { + environment: Environment.Development, + variables: [environmentVariable0, environmentVariable1], + }, +}; + +export default meta; + +type Story = StoryObj; + +export const Default: Story = {}; diff --git a/packages/frontend/src/stories/Project/Settings/EditEnvironmentVariableRow.stories.tsx b/packages/frontend/src/stories/Project/Settings/EditEnvironmentVariableRow.stories.tsx new file mode 100644 index 00000000..811b0ea4 --- /dev/null +++ b/packages/frontend/src/stories/Project/Settings/EditEnvironmentVariableRow.stories.tsx @@ -0,0 +1,28 @@ +import { Meta, StoryObj } from '@storybook/react'; + +import EditEnvironmentVariableRow from 'components/projects/project/settings/EditEnvironmentVariableRow'; +import { environmentVariable0 } from '../../MockStoriesData'; + +const meta: Meta = { + title: 'Project/Settings/EditEnvironmentVariableRow', + component: EditEnvironmentVariableRow, + argTypes: { + variable: { + control: { + type: 'object', + }, + }, + onUpdate: { + action: 'update', + }, + }, + args: { + variable: environmentVariable0, + }, +}; + +export default meta; + +type Story = StoryObj; + +export const Default: Story = {}; diff --git a/packages/frontend/src/stories/Project/Settings/SetupDomains.stories.tsx b/packages/frontend/src/stories/Project/Settings/SetupDomains.stories.tsx index 560dbe74..7c416099 100644 --- a/packages/frontend/src/stories/Project/Settings/SetupDomains.stories.tsx +++ b/packages/frontend/src/stories/Project/Settings/SetupDomains.stories.tsx @@ -17,7 +17,7 @@ const meta: Meta = { pathParams: { userId: 'me' }, }, routing: { - path: '/snowball-tools-1/projects/6bb3bec2-d71b-4fc0-9e32-4767f68668f4/settings/domains/add', + path: '/snowball-tools-1/projects/6bb3bec2-d71b-4fc0-9e32-4767f68668f4/settings/domains', }, }), }, diff --git a/packages/frontend/tailwind.config.js b/packages/frontend/tailwind.config.js index 7ad42dca..f561b2c6 100644 --- a/packages/frontend/tailwind.config.js +++ b/packages/frontend/tailwind.config.js @@ -14,9 +14,6 @@ export default withMT({ xxs: '400px', xs: '480px', }, - zIndex: { - tooltip: '52', - }, letterSpacing: { tight: '-0.084px', }, @@ -178,6 +175,7 @@ export default withMT({ 4.5: '1.125rem', }, zIndex: { + tooltip: '52', toast: '9999', }, animation: { diff --git a/packages/frontend/vite.config.ts b/packages/frontend/vite.config.ts index d9bb608b..e40bea3b 100644 --- a/packages/frontend/vite.config.ts +++ b/packages/frontend/vite.config.ts @@ -1,9 +1,9 @@ -import { defineConfig } from 'vite'; +import { defineConfig, PluginOption } from 'vite'; import react from '@vitejs/plugin-react'; // https://vitejs.dev/config/ export default defineConfig({ - plugins: [react()], + plugins: [react()] as PluginOption[], resolve: { alias: { utils: '/src/utils',