Add confirm dialogs for deployment menu (#24)

* Add dialogs for deployment menu items

* Populate deployment dialogs with dummy json

* Pass production deployment as prop to deployment card

---------

Co-authored-by: neeraj <neeraj.rtly@gmail.com>
This commit is contained in:
Nabarun Gogoi 2023-12-26 11:53:28 +05:30 committed by GitHub
parent ef72a0351e
commit fc2bdefe17
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 206 additions and 34 deletions

View File

@ -1,8 +1,9 @@
[
{
"id": 1,
"title": "nextjs-boilerplate-9t44zbky4dg-bygideon-projects",
"status": "Building",
"environment": "Production",
"isProduction": true,
"branch": "prod",
"commit": {
"hash": "9haif19",
@ -12,9 +13,10 @@
"updatedAt": "2023-12-11T04:20:00"
},
{
"id": 2,
"title": "nextjs-boilerplate-9232dwky4dg-bygideon-projects",
"status": "Ready",
"environment": "Preview",
"isProduction": false,
"branch": "prod",
"commit": {
"hash": "43de569",
@ -24,9 +26,10 @@
"updatedAt": "2023-12-11T04:20:00"
},
{
"id": 3,
"title": "nextjs-boilerplate-9saa22y4dg-bygideon-projects",
"status": "Error",
"environment": "Production",
"isProduction": false,
"branch": "main",
"commit": {
"hash": "4hdsf19",

View File

@ -3,13 +3,12 @@ import React, { useCallback, useMemo, useState } from 'react';
import { Button, Typography } from '@material-tailwind/react';
import deploymentData from '../../../assets/deployments.json';
import DeployDetailsCard, {
DeploymentDetails,
} from './deployments/DeploymentDetailsCard';
import DeploymentDetailsCard from './deployments/DeploymentDetailsCard';
import FilterForm, {
FilterValue,
StatusOptions,
} from './deployments/FilterForm';
import { DeploymentDetails } from '../../../types/project';
const DEFAULT_FILTER_VALUE: FilterValue = {
searchedBranch: '',
@ -19,6 +18,12 @@ const DEFAULT_FILTER_VALUE: FilterValue = {
const DeploymentsTabPanel = () => {
const [filterValue, setFilterValue] = useState(DEFAULT_FILTER_VALUE);
const productionDeployment = useMemo(() => {
return deploymentData.find((deployment) => {
return deployment.isProduction === true;
}) as DeploymentDetails;
}, []);
const filteredDeployments = useMemo<DeploymentDetails[]>(() => {
return deploymentData.filter((deployment) => {
// Searched branch filter
@ -55,7 +60,13 @@ const DeploymentsTabPanel = () => {
<div className="mt-2">
{Boolean(filteredDeployments.length) ? (
filteredDeployments.map((deployment, key) => {
return <DeployDetailsCard deployment={deployment} key={key} />;
return (
<DeploymentDetailsCard
deployment={deployment}
key={key}
productionDeployment={productionDeployment}
/>
);
})
) : (
<div className="h-[50vh] bg-gray-100 flex rounded items-center justify-center">

View File

@ -1,4 +1,4 @@
import React from 'react';
import React, { useState } from 'react';
import {
Menu,
@ -11,28 +11,13 @@ import {
} from '@material-tailwind/react';
import { relativeTime } from '../../../../utils/time';
export enum Status {
BUILDING = 'Building',
READY = 'Ready',
ERROR = 'Error',
}
export interface DeploymentDetails {
title: string;
status: Status;
environment: string;
branch: string;
commit: {
hash: string;
message: string;
};
author: string;
updatedAt: string;
}
import ConfirmDialog from '../../../shared/ConfirmDialog';
import DeploymentDialogBodyCard from './DeploymentDialogBodyCard';
import { DeploymentDetails, Status } from '../../../../types/project';
interface DeployDetailsCardProps {
deployment: DeploymentDetails;
productionDeployment: DeploymentDetails;
}
const STATUS_COLORS: { [key in Status]: ChipProps['color'] } = {
@ -41,7 +26,14 @@ const STATUS_COLORS: { [key in Status]: ChipProps['color'] } = {
[Status.ERROR]: 'red',
};
const DeployDetailsCard = ({ deployment }: DeployDetailsCardProps) => {
const DeploymentDetailsCard = ({
deployment,
productionDeployment,
}: DeployDetailsCardProps) => {
const [changeToProduction, setChangeToProduction] = useState(false);
const [redeployToProduction, setRedeployToProduction] = useState(false);
const [rollbackDeployment, setRollbackDeployment] = useState(false);
return (
<div className="grid grid-cols-4 gap-2 border-b border-gray-300 p-3 my-2">
<div className="col-span-2">
@ -54,7 +46,9 @@ const DeployDetailsCard = ({ deployment }: DeployDetailsCardProps) => {
icon={<i>^</i>}
/>
</div>
<Typography color="gray">{deployment.environment}</Typography>
<Typography color="gray">
{deployment.isProduction ? 'Production (Current)' : 'Preview'}
</Typography>
</div>
<div className="col-span-1">
<Typography color="gray">^ {deployment.branch}</Typography>
@ -73,15 +67,116 @@ const DeployDetailsCard = ({ deployment }: DeployDetailsCardProps) => {
<MenuList>
<MenuItem>^ Visit</MenuItem>
<MenuItem>^ Assign domain</MenuItem>
<MenuItem>^ Change to production</MenuItem>
{!deployment.isProduction && (
<MenuItem
onClick={() => setChangeToProduction(!changeToProduction)}
>
^ Change to production
</MenuItem>
)}
<hr className="my-3" />
<MenuItem>^ Redeploy</MenuItem>
<MenuItem>^ Rollback to this version</MenuItem>
<MenuItem
onClick={() => setRedeployToProduction(!redeployToProduction)}
>
^ Redeploy to production
</MenuItem>
{!deployment.isProduction && (
<MenuItem
onClick={() => setRollbackDeployment(!rollbackDeployment)}
>
^ Rollback to this version
</MenuItem>
)}
</MenuList>
</Menu>
</div>
<ConfirmDialog
dialogTitle="Change to production?"
handleOpen={() => setChangeToProduction(!changeToProduction)}
open={changeToProduction}
confirmButtonTitle="Change"
color="blue"
>
<div className="flex flex-col gap-2">
<Typography variant="small">
Upon confirmation, this deployment will be changed to production.
</Typography>
<DeploymentDialogBodyCard deployment={deployment} />
<Typography variant="small">
The new deployment will be associated with these domains:
</Typography>
<Typography variant="small" color="blue">
^ saugatt.com
</Typography>
<Typography variant="small" color="blue">
^ www.saugatt.com
</Typography>
</div>
</ConfirmDialog>
<ConfirmDialog
dialogTitle="Redeploy to production?"
handleOpen={() => setRedeployToProduction(!redeployToProduction)}
open={redeployToProduction}
confirmButtonTitle="Redeploy"
color="blue"
>
<div className="flex flex-col gap-2">
<Typography variant="small">
Upon confirmation, new deployment will be created with the same
source code as current deployment.
</Typography>
<DeploymentDialogBodyCard deployment={deployment} />
<Typography variant="small">
These domains will point to your new deployment:
</Typography>
<Typography variant="small" color="blue">
^ saugatt.com
</Typography>
<Typography variant="small" color="blue">
^ www.saugatt.com
</Typography>
</div>
</ConfirmDialog>
<ConfirmDialog
dialogTitle="Rollback to this deployment?"
handleOpen={() => setRollbackDeployment(!rollbackDeployment)}
open={rollbackDeployment}
confirmButtonTitle="Rollback"
color="blue"
>
<div className="flex flex-col gap-2">
<Typography variant="small">
Upon confirmation, this deployment will replace your current
deployment
</Typography>
<DeploymentDialogBodyCard
deployment={productionDeployment}
chip={{
value: 'Live Deployment',
color: 'green',
}}
/>
<DeploymentDialogBodyCard
deployment={deployment}
chip={{
value: 'New Deployment',
color: 'orange',
}}
/>
<Typography variant="small">
These domains will point to your new deployment:
</Typography>
<Typography variant="small" color="blue">
^ saugatt.com
</Typography>
<Typography variant="small" color="blue">
^ www.saugatt.com
</Typography>
</div>
</ConfirmDialog>
</div>
);
};
export default DeployDetailsCard;
export default DeploymentDetailsCard;

View File

@ -0,0 +1,44 @@
import React from 'react';
import { Typography, Chip, Card } from '@material-tailwind/react';
import { color } from '@material-tailwind/react/types/components/chip';
import { DeploymentDetails } from '../../../../types/project';
import { relativeTime } from '../../../../utils/time';
interface DeploymentDialogBodyCardProps {
deployment: DeploymentDetails;
chip?: {
value: string;
color?: color;
};
}
const DeploymentDialogBodyCard = ({
chip,
deployment,
}: DeploymentDialogBodyCardProps) => {
return (
<Card className="p-2 shadow-none">
{chip && (
<Chip
className={`w-fit normal-case font-normal`}
size="sm"
value={chip.value}
color={chip.color}
/>
)}
<Typography variant="small" className="text-black">
deployment title
</Typography>
<Typography variant="small">
^ {deployment.branch} ^ {deployment.commit.hash}{' '}
{deployment.commit.message}
</Typography>
<Typography variant="small">
^ {relativeTime(deployment.updatedAt)} ^ {deployment.author}
</Typography>
</Card>
);
};
export default DeploymentDialogBodyCard;

View File

@ -16,7 +16,7 @@ type ConfirmDialogProp = {
open: boolean;
handleOpen: () => void;
confirmButtonTitle: string;
handleConfirm: () => void;
handleConfirm?: () => void;
color: color;
};

View File

@ -16,3 +16,22 @@ export interface ProjectDetails {
branch: string;
};
}
export interface DeploymentDetails {
title: string;
isProduction: boolean;
status: Status;
branch: string;
commit: {
hash: string;
message: string;
};
author: string;
updatedAt: string;
}
export enum Status {
BUILDING = 'Building',
READY = 'Ready',
ERROR = 'Error',
}