Save commit message in DB and show in deployments list (#67)

* Display commit message in projects and deployments

* Handle if current deployment not present

* Rename types file

---------

Co-authored-by: neeraj <neeraj.rtly@gmail.com>
This commit is contained in:
Nabarun Gogoi 2024-02-14 14:25:50 +05:30 committed by GitHub
parent adba64fd2b
commit db3b9148b6
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
29 changed files with 144 additions and 128 deletions

View File

@ -59,6 +59,9 @@ export class Deployment {
@Column('varchar')
commitHash!: string;
@Column('varchar')
commitMessage!: string;
@Column('varchar')
url!: string;

View File

@ -90,6 +90,7 @@ type Deployment {
domain: Domain
branch: String!
commitHash: String!
commitMessage: String!
url: String!
environment: Environment!
isCurrent: Boolean!

View File

@ -218,7 +218,8 @@ export class Service {
branch: oldDeployment.branch,
environment: Environment.Production,
domain: prodBranchDomains[0],
commitHash: oldDeployment.commitHash
commitHash: oldDeployment.commitHash,
commitMessage: oldDeployment.commitMessage
});
return newDeployement;
@ -252,6 +253,7 @@ export class Service {
project: data.project,
branch: data.branch,
commitHash: data.commitHash,
commitMessage: data.commitMessage,
environment: data.environment,
isCurrent: data.isCurrent,
status: DeploymentStatus.Building,
@ -300,7 +302,8 @@ export class Service {
branch: project.prodBranch,
environment: Environment.Production,
domain: null,
commitHash: latestCommit.sha
commitHash: latestCommit.sha,
commitMessage: latestCommit.commit.message
});
const { registryRecordId, registryRecordData } = await this.registry.createApplicationDeploymentRequest(
@ -370,7 +373,8 @@ export class Service {
isCurrent: true,
environment: Environment.Production,
domain: oldDeployment.domain,
commitHash: oldDeployment.commitHash
commitHash: oldDeployment.commitHash,
commitMessage: oldDeployment.commitMessage
});
return newDeployement;

View File

@ -11,6 +11,7 @@
"registryRecordData": {},
"branch": "main",
"commitHash": "d5dfd7b827226b0d09d897346d291c256e113e00",
"commitMessage": "subscription added",
"url": "testProject-ffhae3zq.snowball.xyz"
},
{
@ -25,6 +26,7 @@
"registryRecordData": {},
"branch": "test",
"commitHash": "d5dfd7b827226b0d09d897346d291c256e113e00",
"commitMessage": "subscription added",
"url": "testProject-vehagei8.snowball.xyz"
},
{
@ -39,6 +41,7 @@
"registryRecordData": {},
"branch": "test",
"commitHash": "d5dfd7b827226b0d09d897346d291c256e113e00",
"commitMessage": "subscription added",
"url": "testProject-qmgekyte.snowball.xyz"
},
{
@ -53,6 +56,7 @@
"registryRecordData": {},
"branch": "prod",
"commitHash": "d5dfd7b827226b0d09d897346d291c256e113e00",
"commitMessage": "subscription added",
"url": "testProject-f8wsyim6.snowball.xyz"
},
{
@ -67,6 +71,7 @@
"registryRecordData": {},
"branch": "main",
"commitHash": "d5dfd7b827226b0d09d897346d291c256e113e00",
"commitMessage": "subscription added",
"url": "testProject-2-eO8cckxk.snowball.xyz"
},
{
@ -81,6 +86,7 @@
"registryRecordData": {},
"branch": "test",
"commitHash": "d5dfd7b827226b0d09d897346d291c256e113e00",
"commitMessage": "subscription added",
"url": "testProject-2-yaq0t5yw.snowball.xyz"
},
{
@ -95,11 +101,12 @@
"registryRecordData": {},
"branch": "test",
"commitHash": "d5dfd7b827226b0d09d897346d291c256e113e00",
"commitMessage": "subscription added",
"url": "testProject-2-hwwr6sbx.snowball.xyz"
},
{
"projectIndex": 2,
"domainIndex":6,
"domainIndex":9,
"createdByIndex": 2,
"id":"ndxje48a",
"status": "Building",
@ -109,6 +116,7 @@
"registryRecordData": {},
"branch": "main",
"commitHash": "d5dfd7b827226b0d09d897346d291c256e113e00",
"commitMessage": "subscription added",
"url": "iglootools-ndxje48a.snowball.xyz"
},
{
@ -123,6 +131,7 @@
"registryRecordData": {},
"branch": "test",
"commitHash": "d5dfd7b827226b0d09d897346d291c256e113e00",
"commitMessage": "subscription added",
"url": "iglootools-gtgpgvei.snowball.xyz"
},
{
@ -137,6 +146,22 @@
"registryRecordData": {},
"branch": "test",
"commitHash": "d5dfd7b827226b0d09d897346d291c256e113e00",
"commitMessage": "subscription added",
"url": "iglootools-b4bpthjr.snowball.xyz"
},
{
"projectIndex": 3,
"domainIndex": 6,
"createdByIndex": 2,
"id":"b4bpthjr",
"status": "Building",
"environment": "Production",
"isCurrent": true,
"registryRecordId": "pbafyreihvzya6ovp4yfpkqnddkui2iw7t6hbhwq74lbqs7bhobvmfhrowo",
"registryRecordData": {},
"branch": "test",
"commitHash": "d5dfd7b827226b0d09d897346d291c256e113e00",
"commitMessage": "subscription added",
"url": "iglootools-b4bpthjr.snowball.xyz"
}
]

View File

@ -34,5 +34,11 @@
"name": "saugatt.com",
"status": "Pending",
"branch": "test"
},
{
"projectIndex": 3,
"name": "iglootools-2.com",
"status": "Pending",
"branch": "test"
}
]

View File

@ -1,5 +1,6 @@
import React from 'react';
import { Link } from 'react-router-dom';
import { Project } from 'gql-client';
import {
Menu,
@ -10,11 +11,10 @@ import {
Avatar,
} from '@material-tailwind/react';
import { relativeTimeISO } from '../../utils/time';
import { ProjectDetails } from '../../types/project';
import { relativeTimeMs } from '../../utils/time';
interface ProjectCardProps {
project: ProjectDetails;
project: Project;
}
const ProjectCard: React.FC<ProjectCardProps> = ({ project }) => {
@ -42,13 +42,21 @@ const ProjectCard: React.FC<ProjectCardProps> = ({ project }) => {
</Menu>
</div>
<div className="border-t-2 border-solid p-4 bg-gray-50">
<Typography variant="small" color="gray">
^ {project.latestCommit.message}
</Typography>
<Typography variant="small" color="gray">
{relativeTimeISO(project.latestCommit.createdAt)} on ^&nbsp;
{project.latestCommit.branch}
</Typography>
{project.deployments.length > 0 ? (
<>
<Typography variant="small" color="gray">
^ {project.deployments[0].commitMessage}
</Typography>
<Typography variant="small" color="gray">
{relativeTimeMs(project.deployments[0].createdAt)} on ^&nbsp;
{project.deployments[0].branch}
</Typography>
</>
) : (
<Typography variant="small" color="gray">
No Production deployment
</Typography>
)}
</div>
</div>
);

View File

@ -4,7 +4,7 @@ import { useNavigate, useParams } from 'react-router-dom';
import { Chip, IconButton } from '@material-tailwind/react';
import { relativeTimeISO } from '../../../utils/time';
import { GitRepositoryDetails } from '../../../types/project';
import { GitRepositoryDetails } from '../../../types';
import { useGQLClient } from '../../../context/GQLClientContext';
interface ProjectRepoCardProps {

View File

@ -7,7 +7,7 @@ import { Button, Typography, Option, Select } from '@material-tailwind/react';
import SearchBar from '../../SearchBar';
import ProjectRepoCard from './ProjectRepoCard';
import { GitOrgDetails, GitRepositoryDetails } from '../../../types/project';
import { GitOrgDetails, GitRepositoryDetails } from '../../../types';
const DEFAULT_SEARCHED_REPO = '';
const REPOS_PER_PAGE = 5;

View File

@ -3,7 +3,7 @@ import React from 'react';
import { Typography, IconButton } from '@material-tailwind/react';
import { relativeTimeISO } from '../../../utils/time';
import { GitCommitDetails } from '../../../types/project';
import { GitCommitDetails } from '../../../types';
interface ActivityCardProps {
activity: GitCommitDetails;

View File

@ -1,6 +1,12 @@
import React, { useState } from 'react';
import toast from 'react-hot-toast';
import { Environment, Project, Domain, DeploymentStatus } from 'gql-client';
import {
Environment,
Project,
Domain,
DeploymentStatus,
Deployment,
} from 'gql-client';
import {
Menu,
@ -16,13 +22,12 @@ import { relativeTimeMs } from '../../../../utils/time';
import ConfirmDialog from '../../../shared/ConfirmDialog';
import DeploymentDialogBodyCard from './DeploymentDialogBodyCard';
import AssignDomainDialog from './AssignDomainDialog';
import { DeploymentDetails } from '../../../../types/project';
import { useGQLClient } from '../../../../context/GQLClientContext';
import { SHORT_COMMIT_HASH_LENGTH } from '../../../../constants';
interface DeployDetailsCardProps {
deployment: DeploymentDetails;
currentDeployment: DeploymentDetails;
deployment: Deployment;
currentDeployment: Deployment;
onUpdate: () => Promise<void>;
project: Project;
prodBranchDomains: Domain[];
@ -103,7 +108,7 @@ const DeploymentDetailsCard = ({
<Typography color="gray">^ {deployment.branch}</Typography>
<Typography color="gray">
^ {deployment.commitHash.substring(0, SHORT_COMMIT_HASH_LENGTH)}{' '}
{deployment.commit.message}
{deployment.commitMessage}
</Typography>
</div>
<div className="col-span-1 flex items-center">
@ -149,7 +154,8 @@ const DeploymentDetailsCard = ({
onClick={() => setRollbackDeployment(!rollbackDeployment)}
disabled={
deployment.isCurrent ||
deployment.environment !== Environment.Production
deployment.environment !== Environment.Production ||
!Boolean(currentDeployment)
}
>
^ Rollback to this version
@ -213,44 +219,46 @@ const DeploymentDetailsCard = ({
)}
</div>
</ConfirmDialog>
<ConfirmDialog
dialogTitle="Rollback to this deployment?"
handleOpen={() => setRollbackDeployment((preVal) => !preVal)}
open={rollbackDeployment}
confirmButtonTitle="Rollback"
color="blue"
handleConfirm={async () => {
await rollbackDeploymentHandler();
setRollbackDeployment((preVal) => !preVal);
}}
>
<div className="flex flex-col gap-2">
<Typography variant="small">
Upon confirmation, this deployment will replace your current
deployment
</Typography>
<DeploymentDialogBodyCard
deployment={currentDeployment}
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">
^ {currentDeployment.domain?.name}
</Typography>
</div>
</ConfirmDialog>
{Boolean(currentDeployment) && (
<ConfirmDialog
dialogTitle="Rollback to this deployment?"
handleOpen={() => setRollbackDeployment((preVal) => !preVal)}
open={rollbackDeployment}
confirmButtonTitle="Rollback"
color="blue"
handleConfirm={async () => {
await rollbackDeploymentHandler();
setRollbackDeployment((preVal) => !preVal);
}}
>
<div className="flex flex-col gap-2">
<Typography variant="small">
Upon confirmation, this deployment will replace your current
deployment
</Typography>
<DeploymentDialogBodyCard
deployment={currentDeployment}
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">
^ {currentDeployment.domain?.name}
</Typography>
</div>
</ConfirmDialog>
)}
<AssignDomainDialog
open={assignDomainDialog}
handleOpen={() => setAssignDomainDialog(!assignDomainDialog)}

View File

@ -1,13 +1,13 @@
import React from 'react';
import { Deployment } from 'gql-client';
import { Typography, Chip, Card } from '@material-tailwind/react';
import { color } from '@material-tailwind/react/types/components/chip';
import { DeploymentDetails } from '../../../../types/project';
import { relativeTimeMs } from '../../../../utils/time';
import { SHORT_COMMIT_HASH_LENGTH } from '../../../../constants';
interface DeploymentDialogBodyCardProps {
deployment: DeploymentDetails;
deployment: Deployment;
chip?: {
value: string;
color?: color;
@ -34,7 +34,7 @@ const DeploymentDialogBodyCard = ({
<Typography variant="small">
^ {deployment.branch} ^{' '}
{deployment.commitHash.substring(0, SHORT_COMMIT_HASH_LENGTH)}{' '}
{deployment.commit.message}
{deployment.commitMessage}
</Typography>
<Typography variant="small">
^ {relativeTimeMs(deployment.createdAt)} ^ {deployment.createdBy.name}

View File

@ -3,7 +3,7 @@ import { UseFormRegister } from 'react-hook-form';
import { Typography, Input, IconButton } from '@material-tailwind/react';
import { EnvironmentVariablesFormValues } from '../../../../types/project';
import { EnvironmentVariablesFormValues } from '../../../../types';
interface AddEnvironmentVariableRowProps {
onDelete: () => void;

View File

@ -12,7 +12,7 @@ import {
Card,
} from '@material-tailwind/react';
import { RepositoryDetails } from '../../../../types/project';
import { RepositoryDetails } from '../../../../types';
import ConfirmDialog from '../../../shared/ConfirmDialog';
import EditDomainDialog from './EditDomainDialog';
import { useGQLClient } from '../../../../context/GQLClientContext';

View File

@ -15,7 +15,7 @@ import {
Option,
} from '@material-tailwind/react';
import { RepositoryDetails } from '../../../../types/project';
import { RepositoryDetails } from '../../../../types';
import { useGQLClient } from '../../../../context/GQLClientContext';
const DEFAULT_REDIRECT_OPTIONS = ['none'];

View File

@ -1,6 +1,6 @@
import React from 'react';
import { GitSelect } from '../../../../types/project';
import { GitSelect } from '../../../../types';
const GitSelectionSection = ({
gitSelectionHandler,

View File

@ -2,7 +2,7 @@ import React, { useState } from 'react';
import { Button, Typography } from '@material-tailwind/react';
import { GitRepositoryDetails } from '../../../../types/project';
import { GitRepositoryDetails } from '../../../../types';
import ConfirmDialog from '../../../shared/ConfirmDialog';
const RepoConnectedSection = ({

View File

@ -1,9 +1,3 @@
export const COMMIT_DETAILS = {
message: 'subscription added',
createdAt: '2023-12-11T04:20:00',
branch: 'main',
};
export const ORGANIZATION_ID = '2379cf1f-a232-4ad2-ae14-4d881131cc26';
export const GIT_TEMPLATE_LINK =

View File

@ -1,32 +1,22 @@
import React, { useCallback, useEffect, useState } from 'react';
import { Link, useParams } from 'react-router-dom';
import { Project } from 'gql-client';
import { Button, Typography, Chip } from '@material-tailwind/react';
import ProjectCard from '../../components/projects/ProjectCard';
import { useGQLClient } from '../../context/GQLClientContext';
import { ProjectDetails } from '../../types/project';
import { COMMIT_DETAILS } from '../../constants';
const Projects = () => {
const client = useGQLClient();
const { orgSlug } = useParams();
const [projects, setProjects] = useState<ProjectDetails[]>([]);
const [projects, setProjects] = useState<Project[]>([]);
const fetchProjects = useCallback(async () => {
const { projectsInOrganization } = await client.getProjectsInOrganization(
orgSlug!,
);
const updatedProjects = projectsInOrganization.map((project) => {
return {
...project,
// TODO: Populate from github API
latestCommit: COMMIT_DETAILS,
};
});
setProjects(updatedProjects);
setProjects(projectsInOrganization);
}, [orgSlug]);
useEffect(() => {

View File

@ -1,5 +1,5 @@
import React, { useCallback, useEffect, useMemo, useState } from 'react';
import { Domain } from 'gql-client';
import { Deployment, Domain } from 'gql-client';
import { useOutletContext } from 'react-router-dom';
import { Button, Typography } from '@material-tailwind/react';
@ -9,12 +9,8 @@ import FilterForm, {
FilterValue,
StatusOptions,
} from '../../../../components/projects/project/deployments/FilterForm';
import {
DeploymentDetails,
OutletContextType,
} from '../../../../types/project';
import { OutletContextType } from '../../../../types';
import { useGQLClient } from '../../../../context/GQLClientContext';
import { COMMIT_DETAILS } from '../../../../constants';
const DEFAULT_FILTER_VALUE: FilterValue = {
searchedBranch: '',
@ -27,19 +23,12 @@ const DeploymentsTabPanel = () => {
const { project } = useOutletContext<OutletContextType>();
const [filterValue, setFilterValue] = useState(DEFAULT_FILTER_VALUE);
const [deployments, setDeployments] = useState<DeploymentDetails[]>([]);
const [deployments, setDeployments] = useState<Deployment[]>([]);
const [prodBranchDomains, setProdBranchDomains] = useState<Domain[]>([]);
const fetchDeployments = async () => {
const { deployments } = await client.getDeployments(project.id);
const updatedDeployments = deployments.map((deployment) => {
return {
...deployment,
author: '',
commit: COMMIT_DETAILS,
};
});
setDeployments(updatedDeployments);
setDeployments(deployments);
};
const fetchProductionBranchDomains = useCallback(async () => {
@ -60,7 +49,7 @@ const DeploymentsTabPanel = () => {
});
}, [deployments]);
const filteredDeployments = useMemo<DeploymentDetails[]>(() => {
const filteredDeployments = useMemo<Deployment[]>(() => {
return deployments.filter((deployment) => {
// Searched branch filter
const branchMatch =
@ -81,7 +70,7 @@ const DeploymentsTabPanel = () => {
new Date(deployment.updatedAt) <= filterValue.updateAtRange!.to!);
return branchMatch && statusMatch && dateMatch;
}) as DeploymentDetails[];
});
}, [filterValue, deployments]);
const handleResetFilters = useCallback(() => {

View File

@ -7,7 +7,7 @@ import { Typography, Button, Chip, Avatar } from '@material-tailwind/react';
import ActivityCard from '../../../../components/projects/project/ActivityCard';
import { relativeTimeMs } from '../../../../utils/time';
import { useOctokit } from '../../../../context/OctokitContext';
import { GitCommitDetails, OutletContextType } from '../../../../types/project';
import { GitCommitDetails, OutletContextType } from '../../../../types';
import { useGQLClient } from '../../../../context/GQLClientContext';
const COMMITS_PER_PAGE = 4;

View File

@ -3,7 +3,7 @@ import { Link, Outlet, useLocation, useOutletContext } from 'react-router-dom';
import { Tabs, TabsHeader, TabsBody, Tab } from '@material-tailwind/react';
import { OutletContextType } from '../../../../types/project';
import { OutletContextType } from '../../../../types';
const tabsData = [
{

View File

@ -7,7 +7,7 @@ import { Button, Typography } from '@material-tailwind/react';
import DomainCard from '../../../../../components/projects/project/settings/DomainCard';
import { useGQLClient } from '../../../../../context/GQLClientContext';
import repositories from '../../../../../assets/repositories.json';
import { OutletContextType } from '../../../../../types/project';
import { OutletContextType } from '../../../../../types';
const Domains = () => {
const client = useGQLClient();

View File

@ -17,7 +17,7 @@ import AddEnvironmentVariableRow from '../../../../../components/projects/projec
import DisplayEnvironmentVariables from '../../../../../components/projects/project/settings/DisplayEnvironmentVariables';
import HorizontalLine from '../../../../../components/HorizontalLine';
import { useGQLClient } from '../../../../../context/GQLClientContext';
import { EnvironmentVariablesFormValues } from '../../../../../types/project';
import { EnvironmentVariablesFormValues } from '../../../../../types';
export const EnvironmentVariablesTabPanel = () => {
const { id } = useParams();

View File

@ -10,7 +10,7 @@ import DeleteProjectDialog from '../../../../../components/projects/project/sett
import ConfirmDialog from '../../../../../components/shared/ConfirmDialog';
import { useGQLClient } from '../../../../../context/GQLClientContext';
import AsyncSelect from '../../../../../components/shared/AsyncSelect';
import { OutletContextType } from '../../../../../types/project';
import { OutletContextType } from '../../../../../types';
const CopyIcon = ({ value }: { value: string }) => {
return (

View File

@ -7,7 +7,7 @@ import { Button, Input, Switch, Typography } from '@material-tailwind/react';
import WebhookCard from '../../../../../components/projects/project/settings/WebhookCard';
import { useGQLClient } from '../../../../../context/GQLClientContext';
import { OutletContextType } from '../../../../../types/project';
import { OutletContextType } from '../../../../../types';
type UpdateProdBranchValues = {
prodBranch: string;

View File

@ -8,7 +8,7 @@ import { Chip, Button, Typography } from '@material-tailwind/react';
import MemberCard from '../../../../../components/projects/project/settings/MemberCard';
import AddMemberDialog from '../../../../../components/projects/project/settings/AddMemberDialog';
import { useGQLClient } from '../../../../../context/GQLClientContext';
import { OutletContextType } from '../../../../../types/project';
import { OutletContextType } from '../../../../../types';
const FIRST_MEMBER_CARD = 0;

View File

@ -1,13 +1,4 @@
import { Project, Deployment } from 'gql-client';
export interface ProjectDetails extends Project {
latestCommit: Commit;
}
export interface DeploymentDetails extends Deployment {
commit: Commit;
author: string;
}
import { Project } from 'gql-client';
export interface GitOrgDetails {
id: number;
@ -55,12 +46,6 @@ export enum GitSelect {
NONE = 'none',
}
export interface Commit {
message: string;
createdAt: string;
branch: string;
}
export type OutletContextType = {
project: Project;
onUpdate: () => Promise<void>;

View File

@ -84,6 +84,7 @@ query ($organizationSlug: String!) {
status
updatedAt
commitHash
commitMessage
createdAt
environment
domain {
@ -125,6 +126,7 @@ query ($projectId: String!) {
}
branch
commitHash
commitMessage
url
environment
isCurrent

View File

@ -62,6 +62,7 @@ export type Deployment = {
domain: Domain
branch: string
commitHash: string
commitMessage: string
url: string
environment: Environment
isCurrent: boolean