forked from cerc-io/snowballtools-base
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:
parent
ef72a0351e
commit
fc2bdefe17
@ -1,8 +1,9 @@
|
|||||||
[
|
[
|
||||||
{
|
{
|
||||||
|
"id": 1,
|
||||||
"title": "nextjs-boilerplate-9t44zbky4dg-bygideon-projects",
|
"title": "nextjs-boilerplate-9t44zbky4dg-bygideon-projects",
|
||||||
"status": "Building",
|
"status": "Building",
|
||||||
"environment": "Production",
|
"isProduction": true,
|
||||||
"branch": "prod",
|
"branch": "prod",
|
||||||
"commit": {
|
"commit": {
|
||||||
"hash": "9haif19",
|
"hash": "9haif19",
|
||||||
@ -12,9 +13,10 @@
|
|||||||
"updatedAt": "2023-12-11T04:20:00"
|
"updatedAt": "2023-12-11T04:20:00"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
"id": 2,
|
||||||
"title": "nextjs-boilerplate-9232dwky4dg-bygideon-projects",
|
"title": "nextjs-boilerplate-9232dwky4dg-bygideon-projects",
|
||||||
"status": "Ready",
|
"status": "Ready",
|
||||||
"environment": "Preview",
|
"isProduction": false,
|
||||||
"branch": "prod",
|
"branch": "prod",
|
||||||
"commit": {
|
"commit": {
|
||||||
"hash": "43de569",
|
"hash": "43de569",
|
||||||
@ -24,9 +26,10 @@
|
|||||||
"updatedAt": "2023-12-11T04:20:00"
|
"updatedAt": "2023-12-11T04:20:00"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
"id": 3,
|
||||||
"title": "nextjs-boilerplate-9saa22y4dg-bygideon-projects",
|
"title": "nextjs-boilerplate-9saa22y4dg-bygideon-projects",
|
||||||
"status": "Error",
|
"status": "Error",
|
||||||
"environment": "Production",
|
"isProduction": false,
|
||||||
"branch": "main",
|
"branch": "main",
|
||||||
"commit": {
|
"commit": {
|
||||||
"hash": "4hdsf19",
|
"hash": "4hdsf19",
|
||||||
|
@ -3,13 +3,12 @@ import React, { useCallback, useMemo, useState } from 'react';
|
|||||||
import { Button, Typography } from '@material-tailwind/react';
|
import { Button, Typography } from '@material-tailwind/react';
|
||||||
|
|
||||||
import deploymentData from '../../../assets/deployments.json';
|
import deploymentData from '../../../assets/deployments.json';
|
||||||
import DeployDetailsCard, {
|
import DeploymentDetailsCard from './deployments/DeploymentDetailsCard';
|
||||||
DeploymentDetails,
|
|
||||||
} from './deployments/DeploymentDetailsCard';
|
|
||||||
import FilterForm, {
|
import FilterForm, {
|
||||||
FilterValue,
|
FilterValue,
|
||||||
StatusOptions,
|
StatusOptions,
|
||||||
} from './deployments/FilterForm';
|
} from './deployments/FilterForm';
|
||||||
|
import { DeploymentDetails } from '../../../types/project';
|
||||||
|
|
||||||
const DEFAULT_FILTER_VALUE: FilterValue = {
|
const DEFAULT_FILTER_VALUE: FilterValue = {
|
||||||
searchedBranch: '',
|
searchedBranch: '',
|
||||||
@ -19,6 +18,12 @@ const DEFAULT_FILTER_VALUE: FilterValue = {
|
|||||||
const DeploymentsTabPanel = () => {
|
const DeploymentsTabPanel = () => {
|
||||||
const [filterValue, setFilterValue] = useState(DEFAULT_FILTER_VALUE);
|
const [filterValue, setFilterValue] = useState(DEFAULT_FILTER_VALUE);
|
||||||
|
|
||||||
|
const productionDeployment = useMemo(() => {
|
||||||
|
return deploymentData.find((deployment) => {
|
||||||
|
return deployment.isProduction === true;
|
||||||
|
}) as DeploymentDetails;
|
||||||
|
}, []);
|
||||||
|
|
||||||
const filteredDeployments = useMemo<DeploymentDetails[]>(() => {
|
const filteredDeployments = useMemo<DeploymentDetails[]>(() => {
|
||||||
return deploymentData.filter((deployment) => {
|
return deploymentData.filter((deployment) => {
|
||||||
// Searched branch filter
|
// Searched branch filter
|
||||||
@ -55,7 +60,13 @@ const DeploymentsTabPanel = () => {
|
|||||||
<div className="mt-2">
|
<div className="mt-2">
|
||||||
{Boolean(filteredDeployments.length) ? (
|
{Boolean(filteredDeployments.length) ? (
|
||||||
filteredDeployments.map((deployment, key) => {
|
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">
|
<div className="h-[50vh] bg-gray-100 flex rounded items-center justify-center">
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import React from 'react';
|
import React, { useState } from 'react';
|
||||||
|
|
||||||
import {
|
import {
|
||||||
Menu,
|
Menu,
|
||||||
@ -11,28 +11,13 @@ import {
|
|||||||
} from '@material-tailwind/react';
|
} from '@material-tailwind/react';
|
||||||
|
|
||||||
import { relativeTime } from '../../../../utils/time';
|
import { relativeTime } from '../../../../utils/time';
|
||||||
|
import ConfirmDialog from '../../../shared/ConfirmDialog';
|
||||||
export enum Status {
|
import DeploymentDialogBodyCard from './DeploymentDialogBodyCard';
|
||||||
BUILDING = 'Building',
|
import { DeploymentDetails, Status } from '../../../../types/project';
|
||||||
READY = 'Ready',
|
|
||||||
ERROR = 'Error',
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface DeploymentDetails {
|
|
||||||
title: string;
|
|
||||||
status: Status;
|
|
||||||
environment: string;
|
|
||||||
branch: string;
|
|
||||||
commit: {
|
|
||||||
hash: string;
|
|
||||||
message: string;
|
|
||||||
};
|
|
||||||
author: string;
|
|
||||||
updatedAt: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
interface DeployDetailsCardProps {
|
interface DeployDetailsCardProps {
|
||||||
deployment: DeploymentDetails;
|
deployment: DeploymentDetails;
|
||||||
|
productionDeployment: DeploymentDetails;
|
||||||
}
|
}
|
||||||
|
|
||||||
const STATUS_COLORS: { [key in Status]: ChipProps['color'] } = {
|
const STATUS_COLORS: { [key in Status]: ChipProps['color'] } = {
|
||||||
@ -41,7 +26,14 @@ const STATUS_COLORS: { [key in Status]: ChipProps['color'] } = {
|
|||||||
[Status.ERROR]: 'red',
|
[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 (
|
return (
|
||||||
<div className="grid grid-cols-4 gap-2 border-b border-gray-300 p-3 my-2">
|
<div className="grid grid-cols-4 gap-2 border-b border-gray-300 p-3 my-2">
|
||||||
<div className="col-span-2">
|
<div className="col-span-2">
|
||||||
@ -54,7 +46,9 @@ const DeployDetailsCard = ({ deployment }: DeployDetailsCardProps) => {
|
|||||||
icon={<i>^</i>}
|
icon={<i>^</i>}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<Typography color="gray">{deployment.environment}</Typography>
|
<Typography color="gray">
|
||||||
|
{deployment.isProduction ? 'Production (Current)' : 'Preview'}
|
||||||
|
</Typography>
|
||||||
</div>
|
</div>
|
||||||
<div className="col-span-1">
|
<div className="col-span-1">
|
||||||
<Typography color="gray">^ {deployment.branch}</Typography>
|
<Typography color="gray">^ {deployment.branch}</Typography>
|
||||||
@ -73,15 +67,116 @@ const DeployDetailsCard = ({ deployment }: DeployDetailsCardProps) => {
|
|||||||
<MenuList>
|
<MenuList>
|
||||||
<MenuItem>^ Visit</MenuItem>
|
<MenuItem>^ Visit</MenuItem>
|
||||||
<MenuItem>^ Assign domain</MenuItem>
|
<MenuItem>^ Assign domain</MenuItem>
|
||||||
<MenuItem>^ Change to production</MenuItem>
|
{!deployment.isProduction && (
|
||||||
|
<MenuItem
|
||||||
|
onClick={() => setChangeToProduction(!changeToProduction)}
|
||||||
|
>
|
||||||
|
^ Change to production
|
||||||
|
</MenuItem>
|
||||||
|
)}
|
||||||
|
|
||||||
<hr className="my-3" />
|
<hr className="my-3" />
|
||||||
<MenuItem>^ Redeploy</MenuItem>
|
<MenuItem
|
||||||
<MenuItem>^ Rollback to this version</MenuItem>
|
onClick={() => setRedeployToProduction(!redeployToProduction)}
|
||||||
|
>
|
||||||
|
^ Redeploy to production
|
||||||
|
</MenuItem>
|
||||||
|
{!deployment.isProduction && (
|
||||||
|
<MenuItem
|
||||||
|
onClick={() => setRollbackDeployment(!rollbackDeployment)}
|
||||||
|
>
|
||||||
|
^ Rollback to this version
|
||||||
|
</MenuItem>
|
||||||
|
)}
|
||||||
</MenuList>
|
</MenuList>
|
||||||
</Menu>
|
</Menu>
|
||||||
</div>
|
</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>
|
</div>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
export default DeployDetailsCard;
|
export default DeploymentDetailsCard;
|
||||||
|
@ -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;
|
@ -16,7 +16,7 @@ type ConfirmDialogProp = {
|
|||||||
open: boolean;
|
open: boolean;
|
||||||
handleOpen: () => void;
|
handleOpen: () => void;
|
||||||
confirmButtonTitle: string;
|
confirmButtonTitle: string;
|
||||||
handleConfirm: () => void;
|
handleConfirm?: () => void;
|
||||||
color: color;
|
color: color;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -16,3 +16,22 @@ export interface ProjectDetails {
|
|||||||
branch: string;
|
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',
|
||||||
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user