Add transfer and delete project in settings tab panel (#22)
* Add dialogs for transfer and delete project * Refactor confirm dialog * Handle form state of transfer and delete dialog * Handle default value of transfer dropdown * Add space in delete dialog body --------- Co-authored-by: neeraj <neeraj.rtly@gmail.com>
This commit is contained in:
parent
5dc079bc8f
commit
e93cca598a
@ -1,51 +0,0 @@
|
||||
import React from 'react';
|
||||
import { Link } from 'react-router-dom';
|
||||
|
||||
import {
|
||||
Button,
|
||||
Dialog,
|
||||
DialogHeader,
|
||||
DialogBody,
|
||||
DialogFooter,
|
||||
} from '@material-tailwind/react';
|
||||
|
||||
interface CancelDeploymentDialogProp {
|
||||
open: boolean;
|
||||
handleOpen: () => void;
|
||||
}
|
||||
|
||||
const CancelDeploymentDialog = ({
|
||||
open,
|
||||
handleOpen,
|
||||
}: CancelDeploymentDialogProp) => {
|
||||
return (
|
||||
<Dialog open={open} handler={handleOpen}>
|
||||
<DialogHeader className="flex justify-between">
|
||||
<div>Cancel deployment?</div>
|
||||
<Button
|
||||
variant="outlined"
|
||||
onClick={handleOpen}
|
||||
className="mr-1 rounded-3xl"
|
||||
>
|
||||
<span>X</span>
|
||||
</Button>
|
||||
</DialogHeader>
|
||||
<DialogBody>
|
||||
This will halt the deployment and you will have to start the process
|
||||
from scratch.
|
||||
</DialogBody>
|
||||
<DialogFooter className="flex justify-center">
|
||||
<Button variant="outlined" onClick={handleOpen} className="mr-1">
|
||||
<span>Cancel</span>
|
||||
</Button>
|
||||
<Link to="/projects/create/template">
|
||||
<Button variant="gradient" color="red" onClick={handleOpen}>
|
||||
<span>Yes, Cancel deployment</span>
|
||||
</Button>
|
||||
</Link>
|
||||
</DialogFooter>
|
||||
</Dialog>
|
||||
);
|
||||
};
|
||||
|
||||
export default CancelDeploymentDialog;
|
@ -52,9 +52,13 @@ const tabsData = [
|
||||
const SettingsTabPanel = () => {
|
||||
return (
|
||||
<>
|
||||
<Tabs value={'general'} orientation="vertical" className="my-6">
|
||||
<Tabs
|
||||
value={'general'}
|
||||
orientation="vertical"
|
||||
className="grid grid-cols-4"
|
||||
>
|
||||
<TabsHeader
|
||||
className="w-60 bg-transparent"
|
||||
className="bg-transparent col-span-1"
|
||||
indicatorProps={{
|
||||
className: 'bg-gray-900/10 shadow-none !text-gray-900',
|
||||
}}
|
||||
@ -68,7 +72,7 @@ const SettingsTabPanel = () => {
|
||||
</Tab>
|
||||
))}
|
||||
</TabsHeader>
|
||||
<TabsBody>
|
||||
<TabsBody className="col-span-2">
|
||||
{tabsData.map(({ value, component }) => (
|
||||
<TabPanel key={value} value={value} className="p-2">
|
||||
{createElement(component)}
|
||||
|
@ -0,0 +1,95 @@
|
||||
import React from 'react';
|
||||
import { useNavigate } from 'react-router-dom';
|
||||
import { useForm } from 'react-hook-form';
|
||||
|
||||
import {
|
||||
Button,
|
||||
Dialog,
|
||||
DialogHeader,
|
||||
DialogBody,
|
||||
DialogFooter,
|
||||
Input,
|
||||
Typography,
|
||||
} from '@material-tailwind/react';
|
||||
|
||||
import { ProjectDetails } from '../../../../types/project';
|
||||
|
||||
interface DeleteProjectDialogProp {
|
||||
open: boolean;
|
||||
handleOpen: () => void;
|
||||
project: Partial<ProjectDetails>;
|
||||
}
|
||||
|
||||
const DeleteProjectDialog = ({
|
||||
open,
|
||||
handleOpen,
|
||||
project,
|
||||
}: DeleteProjectDialogProp) => {
|
||||
const navigate = useNavigate();
|
||||
|
||||
const {
|
||||
handleSubmit,
|
||||
register,
|
||||
formState: { isValid },
|
||||
} = useForm({
|
||||
defaultValues: {
|
||||
projectName: '',
|
||||
},
|
||||
});
|
||||
|
||||
return (
|
||||
<Dialog open={open} handler={handleOpen}>
|
||||
<DialogHeader className="flex justify-between">
|
||||
<div>Delete project?</div>
|
||||
<Button
|
||||
variant="outlined"
|
||||
onClick={handleOpen}
|
||||
className="mr-1 rounded-3xl"
|
||||
>
|
||||
X
|
||||
</Button>
|
||||
</DialogHeader>
|
||||
<form
|
||||
onSubmit={handleSubmit(() => {
|
||||
handleOpen();
|
||||
navigate('/');
|
||||
})}
|
||||
>
|
||||
<DialogBody className="flex flex-col gap-2">
|
||||
<Typography variant="paragraph">
|
||||
Deleting your project is irreversible. Enter your project’s name
|
||||
|
||||
<span className="bg-blue-100 text-blue-700">({project.name})</span>
|
||||
below to confirm you want to permanently delete it:
|
||||
</Typography>
|
||||
<Input
|
||||
id="input"
|
||||
crossOrigin={undefined}
|
||||
{...register('projectName', {
|
||||
required: 'Project name is required',
|
||||
validate: (value) => value === project.name,
|
||||
})}
|
||||
/>
|
||||
<Typography variant="small" color="red">
|
||||
^ Deleting your project is irreversible.
|
||||
</Typography>
|
||||
</DialogBody>
|
||||
<DialogFooter className="flex justify-start">
|
||||
<Button variant="outlined" onClick={handleOpen} className="mr-1">
|
||||
Cancel
|
||||
</Button>
|
||||
<Button
|
||||
variant="gradient"
|
||||
color="red"
|
||||
type="submit"
|
||||
disabled={!isValid}
|
||||
>
|
||||
Yes, Delete project
|
||||
</Button>
|
||||
</DialogFooter>
|
||||
</form>
|
||||
</Dialog>
|
||||
);
|
||||
};
|
||||
|
||||
export default DeleteProjectDialog;
|
@ -1,10 +1,22 @@
|
||||
import React from 'react';
|
||||
import { useForm } from 'react-hook-form';
|
||||
import React, { useState } from 'react';
|
||||
import { Link } from 'react-router-dom';
|
||||
import { useForm, Controller } from 'react-hook-form';
|
||||
import toast, { Toaster } from 'react-hot-toast';
|
||||
|
||||
import { Button, Typography, Input } from '@material-tailwind/react';
|
||||
import {
|
||||
Button,
|
||||
Typography,
|
||||
Input,
|
||||
Select,
|
||||
Option,
|
||||
} from '@material-tailwind/react';
|
||||
|
||||
import DeleteProjectDialog from './DeleteProjectDialog';
|
||||
import ConfirmDialog from '../../../shared/ConfirmDialog';
|
||||
|
||||
const PROJECT_ID = '62f87575-7a2b-4951-8156-9f9821j380d';
|
||||
const TEAMS = ['Airfoil'];
|
||||
const DEFAULT_SELECT_TEAM = undefined;
|
||||
|
||||
const CopyIcon = ({ value }: { value: string }) => {
|
||||
return (
|
||||
@ -21,6 +33,24 @@ const CopyIcon = ({ value }: { value: string }) => {
|
||||
};
|
||||
|
||||
const GeneralTabPanel = () => {
|
||||
const {
|
||||
handleSubmit: handleTransfer,
|
||||
control,
|
||||
formState,
|
||||
} = useForm({
|
||||
defaultValues: {
|
||||
team: DEFAULT_SELECT_TEAM,
|
||||
},
|
||||
});
|
||||
|
||||
const [openTransferDialog, setOpenTransferDialog] = useState(false);
|
||||
const handleTransferProjectDialog = () =>
|
||||
setOpenTransferDialog(!openTransferDialog);
|
||||
|
||||
const [openDeleteDialog, setOpenDeleteDialog] = useState(false);
|
||||
const handleDeleteProjectDialog = () =>
|
||||
setOpenDeleteDialog(!openDeleteDialog);
|
||||
|
||||
const { handleSubmit, register } = useForm({
|
||||
defaultValues: {
|
||||
appName: 'iglootools',
|
||||
@ -29,17 +59,12 @@ const GeneralTabPanel = () => {
|
||||
});
|
||||
|
||||
return (
|
||||
<>
|
||||
<form onSubmit={handleSubmit(() => {})}>
|
||||
<div className="mb-4">
|
||||
<Typography variant="h6">Project info</Typography>
|
||||
</div>
|
||||
<div className="my-2 w-3/5">
|
||||
<label
|
||||
htmlFor="input"
|
||||
className="block text-sm font-medium text-gray-800"
|
||||
>
|
||||
<Typography variant="small" className="font-medium text-gray-800">
|
||||
App name
|
||||
</label>
|
||||
</Typography>
|
||||
<Input
|
||||
id="input"
|
||||
variant="outlined"
|
||||
@ -48,14 +73,9 @@ const GeneralTabPanel = () => {
|
||||
size="md"
|
||||
{...register('appName')}
|
||||
/>
|
||||
</div>
|
||||
<div className="my-2 w-3/5">
|
||||
<label
|
||||
htmlFor="input"
|
||||
className="block text-sm font-medium text-gray-800"
|
||||
>
|
||||
<Typography variant="small" className="font-medium text-gray-800">
|
||||
Description (Optional)
|
||||
</label>
|
||||
</Typography>
|
||||
<Input
|
||||
id="input"
|
||||
variant="outlined"
|
||||
@ -63,14 +83,9 @@ const GeneralTabPanel = () => {
|
||||
size="md"
|
||||
{...register('description')}
|
||||
/>
|
||||
</div>
|
||||
<div className="my-2 w-3/5">
|
||||
<label
|
||||
htmlFor="input"
|
||||
className="block text-sm font-medium text-gray-800"
|
||||
>
|
||||
<Typography variant="small" className="font-medium text-gray-800">
|
||||
Project ID
|
||||
</label>
|
||||
</Typography>
|
||||
<Input
|
||||
id="input"
|
||||
crossOrigin={undefined}
|
||||
@ -80,14 +95,91 @@ const GeneralTabPanel = () => {
|
||||
disabled
|
||||
icon={<CopyIcon value={PROJECT_ID} />}
|
||||
/>
|
||||
</div>
|
||||
<div>
|
||||
<Button type="submit" variant="gradient" size="sm">
|
||||
<Button type="submit" variant="gradient" size="sm" className="mt-1">
|
||||
Save
|
||||
</Button>
|
||||
</form>
|
||||
<div className="mb-1">
|
||||
<Typography variant="h6">Transfer project</Typography>
|
||||
<Typography variant="small">
|
||||
Transfer this app to your personal account or a team you are a member
|
||||
of.
|
||||
<Link to="" className="text-blue-500">
|
||||
Learn more
|
||||
</Link>
|
||||
</Typography>
|
||||
<form
|
||||
onSubmit={handleTransfer(() => {
|
||||
handleTransferProjectDialog();
|
||||
})}
|
||||
>
|
||||
<Typography variant="small" className="font-medium text-gray-800">
|
||||
Choose team
|
||||
</Typography>
|
||||
<Controller
|
||||
name="team"
|
||||
rules={{ required: 'This field is required' }}
|
||||
control={control}
|
||||
render={({ field }) => (
|
||||
<Select
|
||||
{...field}
|
||||
// TODO: Implement placeholder for select
|
||||
label={!field.value ? 'Select an account / team' : ''}
|
||||
>
|
||||
{TEAMS.map((team, key) => (
|
||||
<Option key={key} value={team}>
|
||||
^ {team}
|
||||
</Option>
|
||||
))}
|
||||
</Select>
|
||||
)}
|
||||
/>
|
||||
<Button
|
||||
variant="gradient"
|
||||
size="sm"
|
||||
className="mt-1"
|
||||
disabled={!formState.isValid}
|
||||
type="submit"
|
||||
>
|
||||
Transfer
|
||||
</Button>
|
||||
</form>
|
||||
<ConfirmDialog
|
||||
dialogTitle="Transfer project"
|
||||
handleOpen={handleTransferProjectDialog}
|
||||
open={openTransferDialog}
|
||||
confirmButtonTitle="Yes, Confirm transfer"
|
||||
handleConfirm={handleTransferProjectDialog}
|
||||
color="blue"
|
||||
>
|
||||
<Typography variant="small">
|
||||
Upon confirmation, your project nextjs-boilerplate will be
|
||||
transferred from saugat to Airfoil.
|
||||
</Typography>
|
||||
</ConfirmDialog>
|
||||
</div>
|
||||
<div className="mb-1">
|
||||
<Typography variant="h6">Delete project</Typography>
|
||||
<Typography variant="small">
|
||||
The project will be permanently deleted, including its deployments and
|
||||
domains. This action is irreversible and can not be undone.
|
||||
</Typography>
|
||||
<Button
|
||||
variant="gradient"
|
||||
size="sm"
|
||||
color="red"
|
||||
onClick={handleDeleteProjectDialog}
|
||||
>
|
||||
^ Delete project
|
||||
</Button>
|
||||
<DeleteProjectDialog
|
||||
handleOpen={handleDeleteProjectDialog}
|
||||
open={openDeleteDialog}
|
||||
project={{ name: 'Iglootools' }}
|
||||
/>
|
||||
</div>
|
||||
<Toaster />
|
||||
</form>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
|
57
packages/frontend/src/components/shared/ConfirmDialog.tsx
Normal file
57
packages/frontend/src/components/shared/ConfirmDialog.tsx
Normal file
@ -0,0 +1,57 @@
|
||||
import React from 'react';
|
||||
|
||||
import { color } from '@material-tailwind/react/types/components/button';
|
||||
import {
|
||||
Typography,
|
||||
Button,
|
||||
Dialog,
|
||||
DialogHeader,
|
||||
DialogBody,
|
||||
DialogFooter,
|
||||
} from '@material-tailwind/react';
|
||||
|
||||
type ConfirmDialogProp = {
|
||||
children: React.ReactNode;
|
||||
dialogTitle: string;
|
||||
open: boolean;
|
||||
handleOpen: () => void;
|
||||
confirmButtonTitle: string;
|
||||
handleConfirm: () => void;
|
||||
color: color;
|
||||
};
|
||||
|
||||
const ConfirmDialog = ({
|
||||
children,
|
||||
dialogTitle,
|
||||
open,
|
||||
handleOpen,
|
||||
confirmButtonTitle,
|
||||
handleConfirm,
|
||||
color,
|
||||
}: ConfirmDialogProp) => {
|
||||
return (
|
||||
<Dialog open={open} handler={handleOpen}>
|
||||
<DialogHeader className="flex justify-between">
|
||||
<Typography variant="h6">{dialogTitle} </Typography>
|
||||
<Button
|
||||
variant="outlined"
|
||||
onClick={handleOpen}
|
||||
className=" rounded-full"
|
||||
>
|
||||
X
|
||||
</Button>
|
||||
</DialogHeader>
|
||||
<DialogBody>{children}</DialogBody>
|
||||
<DialogFooter className="flex justify-start gap-2">
|
||||
<Button variant="outlined" onClick={handleOpen}>
|
||||
Cancel
|
||||
</Button>
|
||||
<Button variant="gradient" color={color} onClick={handleConfirm}>
|
||||
{confirmButtonTitle}
|
||||
</Button>
|
||||
</DialogFooter>
|
||||
</Dialog>
|
||||
);
|
||||
};
|
||||
|
||||
export default ConfirmDialog;
|
@ -1,6 +1,7 @@
|
||||
import React from 'react';
|
||||
import React, { useCallback } from 'react';
|
||||
import { useNavigate } from 'react-router-dom';
|
||||
|
||||
import { Button } from '@material-tailwind/react';
|
||||
import { Button, Typography } from '@material-tailwind/react';
|
||||
|
||||
import {
|
||||
DeployStep,
|
||||
@ -10,11 +11,16 @@ import {
|
||||
Stopwatch,
|
||||
setStopWatchOffset,
|
||||
} from '../../../../components/StopWatch';
|
||||
import CancelDeploymentDialog from '../../../../components/projects/create/template/deploy/CancelDeploymentDialog';
|
||||
import ConfirmDialog from '../../../../components/shared/ConfirmDialog';
|
||||
|
||||
const Deploy = () => {
|
||||
const [open, setOpen] = React.useState(false);
|
||||
const handleOpen = () => setOpen(!open);
|
||||
const navigate = useNavigate();
|
||||
|
||||
const handleCancel = useCallback(() => {
|
||||
navigate('/projects/create/template');
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<div>
|
||||
@ -33,7 +39,19 @@ const Deploy = () => {
|
||||
^ Cancel
|
||||
</Button>
|
||||
</div>
|
||||
<CancelDeploymentDialog handleOpen={handleOpen} open={open} />
|
||||
<ConfirmDialog
|
||||
dialogTitle="Cancel deployment?"
|
||||
handleOpen={handleOpen}
|
||||
open={open}
|
||||
confirmButtonTitle="Yes, Cancel deployment"
|
||||
handleConfirm={handleCancel}
|
||||
color="red"
|
||||
>
|
||||
<Typography variant="small">
|
||||
This will halt the deployment and you will have to start the process
|
||||
from scratch.
|
||||
</Typography>
|
||||
</ConfirmDialog>
|
||||
</div>
|
||||
<DeployStep
|
||||
title="Building"
|
||||
|
Loading…
Reference in New Issue
Block a user