forked from cerc-io/snowballtools-base
Set subdomain for project and set URL for each deployment (#52)
* Display current deployment info in overview tab * Add assign domain dialog box in deployments * Add empty link for project settings in assign domain dialog box * Use react router dom link * Add sub domain to project entity * Add deployment url with custom generated string * Set nano id to deployment id * Add sub domain while creating new project * Use same id as in url * Update readme steps for production build * Update README --------- Co-authored-by: neeraj <neeraj.rtly@gmail.com>
This commit is contained in:
@@ -1,4 +1,5 @@
|
||||
import React, { useCallback, useEffect, useMemo, useState } from 'react';
|
||||
import { Project } from 'gql-client';
|
||||
|
||||
import { Button, Typography } from '@material-tailwind/react';
|
||||
|
||||
@@ -16,14 +17,14 @@ const DEFAULT_FILTER_VALUE: FilterValue = {
|
||||
status: StatusOptions.ALL_STATUS,
|
||||
};
|
||||
|
||||
const DeploymentsTabPanel = ({ projectId }: { projectId: string }) => {
|
||||
const DeploymentsTabPanel = ({ project }: { project: Project }) => {
|
||||
const client = useGQLClient();
|
||||
|
||||
const [filterValue, setFilterValue] = useState(DEFAULT_FILTER_VALUE);
|
||||
const [deployments, setDeployments] = useState<DeploymentDetails[]>([]);
|
||||
|
||||
const fetchDeployments = async () => {
|
||||
const { deployments } = await client.getDeployments(projectId);
|
||||
const { deployments } = await client.getDeployments(project.id);
|
||||
const updatedDeployments = deployments.map((deployment) => {
|
||||
return {
|
||||
...deployment,
|
||||
@@ -91,7 +92,7 @@ const DeploymentsTabPanel = ({ projectId }: { projectId: string }) => {
|
||||
key={key}
|
||||
currentDeployment={currentDeployment!}
|
||||
onUpdate={onUpdateDeploymenToProd}
|
||||
projectId={projectId}
|
||||
project={project}
|
||||
/>
|
||||
);
|
||||
})
|
||||
|
||||
@@ -23,8 +23,7 @@ const OverviewTabPanel = ({ project }: OverviewProps) => {
|
||||
<div className="grow">
|
||||
<Typography>{project.name}</Typography>
|
||||
<Typography variant="small" color="gray">
|
||||
{project.deployments[0]?.domain?.name ??
|
||||
'No Production Deployment'}
|
||||
{project.subDomain}
|
||||
</Typography>
|
||||
</div>
|
||||
</div>
|
||||
@@ -55,22 +54,29 @@ const OverviewTabPanel = ({ project }: OverviewProps) => {
|
||||
</Button>
|
||||
)}
|
||||
</div>
|
||||
<div className="flex justify-between p-2 text-sm">
|
||||
<p>^ Source</p>
|
||||
<p>{project.deployments[0]?.branch}</p>
|
||||
</div>
|
||||
<div className="flex justify-between p-2 text-sm">
|
||||
<p>^ Deployment</p>
|
||||
<p className="text-blue-600">
|
||||
{project.deployments[0]?.domain?.name}
|
||||
</p>
|
||||
</div>
|
||||
<div className="flex justify-between p-2 text-sm">
|
||||
<p>^ Created</p>
|
||||
<p>
|
||||
{relativeTimeMs(project.createdAt)} by ^ {project.owner.name}
|
||||
</p>
|
||||
</div>
|
||||
{project.deployments.length !== 0 ? (
|
||||
<>
|
||||
<div className="flex justify-between p-2 text-sm">
|
||||
<p>^ Source</p>
|
||||
<p>{project.deployments[0]?.branch}</p>
|
||||
</div>
|
||||
<div className="flex justify-between p-2 text-sm">
|
||||
<p>^ Deployment</p>
|
||||
<p className="text-blue-600">
|
||||
{project.deployments[0]?.domain?.name}
|
||||
</p>
|
||||
</div>
|
||||
<div className="flex justify-between p-2 text-sm">
|
||||
<p>^ Created</p>
|
||||
<p>
|
||||
{relativeTimeMs(project.deployments[0].createdAt)} by ^{' '}
|
||||
{project.deployments[0].createdBy.name}
|
||||
</p>
|
||||
</div>
|
||||
</>
|
||||
) : (
|
||||
<div>No current deployment found</div>
|
||||
)}
|
||||
</div>
|
||||
<div className="col-span-2 p-2">
|
||||
<div className="flex justify-between">
|
||||
|
||||
@@ -47,7 +47,7 @@ const ProjectTabs = ({ project, onUpdate }: ProjectTabsProps) => {
|
||||
<OverviewTabPanel project={project} />
|
||||
</TabPanel>
|
||||
<TabPanel>
|
||||
<DeploymentsTabPanel projectId={project.id} />
|
||||
<DeploymentsTabPanel project={project} />
|
||||
</TabPanel>
|
||||
<TabPanel>
|
||||
<Database />
|
||||
|
||||
@@ -0,0 +1,52 @@
|
||||
import React from 'react';
|
||||
import { CopyBlock, atomOneLight } from 'react-code-blocks';
|
||||
import { Link } from 'react-router-dom';
|
||||
|
||||
import {
|
||||
Button,
|
||||
Dialog,
|
||||
DialogHeader,
|
||||
DialogBody,
|
||||
DialogFooter,
|
||||
} from '@material-tailwind/react';
|
||||
|
||||
interface AssignDomainProps {
|
||||
open: boolean;
|
||||
handleOpen: () => void;
|
||||
}
|
||||
|
||||
const AssignDomainDialog = ({ open, handleOpen }: AssignDomainProps) => {
|
||||
return (
|
||||
<Dialog open={open} handler={handleOpen}>
|
||||
<DialogHeader>Assign Domain</DialogHeader>
|
||||
<DialogBody>
|
||||
In order to assign a domain to your production deployments, configure it
|
||||
in the{' '}
|
||||
{/* TODO: Navigate to settings tab panel after clicking on project settings */}
|
||||
<Link to="" className="text-light-blue-800 inline">
|
||||
project settings{' '}
|
||||
</Link>
|
||||
(recommended). If you want to assign to this specific deployment,
|
||||
however, you can do so using our command-line interface:
|
||||
<CopyBlock
|
||||
text="snowball alias <deployment> <domain>"
|
||||
language=""
|
||||
showLineNumbers={false}
|
||||
theme={atomOneLight}
|
||||
/>
|
||||
</DialogBody>
|
||||
<DialogFooter className="flex justify-start">
|
||||
<Button
|
||||
className="rounded-3xl"
|
||||
variant="gradient"
|
||||
color="blue"
|
||||
onClick={handleOpen}
|
||||
>
|
||||
<span>Okay</span>
|
||||
</Button>
|
||||
</DialogFooter>
|
||||
</Dialog>
|
||||
);
|
||||
};
|
||||
|
||||
export default AssignDomainDialog;
|
||||
+16
-6
@@ -10,11 +10,12 @@ import {
|
||||
ChipProps,
|
||||
} from '@material-tailwind/react';
|
||||
import toast from 'react-hot-toast';
|
||||
import { Environment } from 'gql-client';
|
||||
import { Environment, Project } from 'gql-client';
|
||||
|
||||
import { relativeTimeMs } from '../../../../utils/time';
|
||||
import ConfirmDialog from '../../../shared/ConfirmDialog';
|
||||
import DeploymentDialogBodyCard from './DeploymentDialogBodyCard';
|
||||
import AssignDomainDialog from './AssignDomainDialog';
|
||||
import { DeploymentDetails, Status } from '../../../../types/project';
|
||||
import { useGQLClient } from '../../../../context/GQLClientContext';
|
||||
|
||||
@@ -22,7 +23,7 @@ interface DeployDetailsCardProps {
|
||||
deployment: DeploymentDetails;
|
||||
currentDeployment: DeploymentDetails;
|
||||
onUpdate: () => Promise<void>;
|
||||
projectId: string;
|
||||
project: Project;
|
||||
}
|
||||
|
||||
const STATUS_COLORS: { [key in Status]: ChipProps['color'] } = {
|
||||
@@ -35,13 +36,14 @@ const DeploymentDetailsCard = ({
|
||||
deployment,
|
||||
currentDeployment,
|
||||
onUpdate,
|
||||
projectId,
|
||||
project,
|
||||
}: DeployDetailsCardProps) => {
|
||||
const client = useGQLClient();
|
||||
|
||||
const [changeToProduction, setChangeToProduction] = useState(false);
|
||||
const [redeployToProduction, setRedeployToProduction] = useState(false);
|
||||
const [rollbackDeployment, setRollbackDeployment] = useState(false);
|
||||
const [assignDomainDialog, setAssignDomainDialog] = useState(false);
|
||||
|
||||
const updateDeployment = async () => {
|
||||
const isUpdated = await client.updateDeploymentToProd(deployment.id);
|
||||
@@ -65,7 +67,7 @@ const DeploymentDetailsCard = ({
|
||||
|
||||
const rollbackDeploymentHandler = async () => {
|
||||
const isRollbacked = await client.rollbackDeployment(
|
||||
projectId,
|
||||
project.id,
|
||||
deployment.id,
|
||||
);
|
||||
if (isRollbacked) {
|
||||
@@ -80,7 +82,7 @@ const DeploymentDetailsCard = ({
|
||||
<div className="grid grid-cols-4 gap-2 border-b border-gray-300 p-3 my-2">
|
||||
<div className="col-span-2">
|
||||
<div className="flex">
|
||||
<Typography className=" basis-3/4">{deployment.title}</Typography>
|
||||
<Typography className=" basis-3/4">{deployment.url}</Typography>
|
||||
<Chip
|
||||
value={deployment.status}
|
||||
color={STATUS_COLORS[deployment.status] ?? 'gray'}
|
||||
@@ -110,7 +112,11 @@ const DeploymentDetailsCard = ({
|
||||
</MenuHandler>
|
||||
<MenuList>
|
||||
<MenuItem>^ Visit</MenuItem>
|
||||
<MenuItem>^ Assign domain</MenuItem>
|
||||
<MenuItem
|
||||
onClick={() => setAssignDomainDialog(!assignDomainDialog)}
|
||||
>
|
||||
^ Assign domain
|
||||
</MenuItem>
|
||||
{!(deployment.environment === Environment.Production) && (
|
||||
<MenuItem
|
||||
onClick={() => setChangeToProduction(!changeToProduction)}
|
||||
@@ -235,6 +241,10 @@ const DeploymentDetailsCard = ({
|
||||
</Typography>
|
||||
</div>
|
||||
</ConfirmDialog>
|
||||
<AssignDomainDialog
|
||||
open={assignDomainDialog}
|
||||
handleOpen={() => setAssignDomainDialog(!assignDomainDialog)}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user