Implement functionality to delete domain (#59)

* Implement functionality to delete domain

* Remove redirectToId from frontend

---------

Co-authored-by: neeraj <neeraj.rtly@gmail.com>
This commit is contained in:
Nabarun Gogoi 2024-02-01 09:04:24 +05:30 committed by Ashwin Phatak
parent 3a7f16467e
commit 1d58beb2ec
11 changed files with 85 additions and 22 deletions

View File

@ -347,6 +347,28 @@ export class Database {
}
}
async deleteDomainById (domainId: string): Promise<boolean> {
const domainRepository = this.dataSource.getRepository(Domain);
const domainsRedirectedFrom = await domainRepository.find({
where: {
redirectToId: Number(domainId)
}
});
if (domainsRedirectedFrom.length > 0) {
throw new Error('Cannot delete domain since it has redirects from other domains');
}
const deleteResult = await domainRepository.softDelete({ id: Number(domainId) });
if (deleteResult.affected) {
return deleteResult.affected > 0;
} else {
return false;
}
}
async rollbackDeploymentById (projectId: string, deploymentId: string): Promise<boolean> {
const deploymentRepository = this.dataSource.getRepository(Deployment);

View File

@ -5,7 +5,8 @@ import {
CreateDateColumn,
UpdateDateColumn,
ManyToOne,
JoinColumn
JoinColumn,
DeleteDateColumn
} from 'typeorm';
import { Project } from './Project';
@ -52,4 +53,7 @@ export class Domain {
@UpdateDateColumn()
updatedAt!: Date;
@DeleteDateColumn()
deletedAt?: Date;
}

View File

@ -216,6 +216,16 @@ export const createResolvers = async (db: Database, app: OAuthApp): Promise<any>
}
},
deleteDomain: async (_: any, { domainId }: { domainId: string }) => {
try {
await db.deleteDomainById(domainId);
return true;
} catch (err) {
log(err);
return false;
}
},
rollbackDeployment: async (_: any, { projectId, deploymentId }: {deploymentId: string, projectId: string }) => {
try {
return db.rollbackDeploymentById(projectId, deploymentId);

View File

@ -141,6 +141,7 @@ type Mutation {
updateProject(projectId: String!, projectDetails: UpdateProjectInput): Boolean!
redeployToProd(deploymentId: String!): Boolean!
deleteProject(projectId: String!): Boolean!
deleteDomain(domainId: String!): Boolean!
rollbackDeployment(projectId: String!, deploymentId: String!): Boolean!
addDomain(projectId: String!, domainDetails: AddDomainInput!): Boolean!
updateDomain(domainId: String!, domainDetails: UpdateDomainInput!): Boolean!

View File

@ -5,7 +5,7 @@
"updatedAt": "2023-12-21T08:30:00",
"user": "bob",
"private": false,
"branch": ["main", "prod", "dev"]
"branch": ["main", "prod", "test"]
},
{
"id": 2,
@ -13,7 +13,7 @@
"updatedAt": "2023-12-21T08:30:00",
"user": "alice",
"private": true,
"branch": ["main", "prod", "dev"]
"branch": ["main", "prod", "test"]
},
{
"id": 3,
@ -21,7 +21,7 @@
"updatedAt": "2023-12-21T04:20:00",
"user": "charlie",
"private": false,
"branch": ["main", "prod", "dev"]
"branch": ["main", "prod", "test"]
},
{
"id": 4,
@ -29,7 +29,7 @@
"updatedAt": "2023-12-21T04:27:00",
"user": "alice",
"private": false,
"branch": ["main", "prod", "dev"]
"branch": ["main", "prod", "test"]
},
{
"id": 5,
@ -37,6 +37,6 @@
"updatedAt": "2023-12-21T04:41:00",
"user": "ivan",
"private": false,
"branch": ["main", "prod", "dev"]
"branch": ["main", "prod", "test"]
}
]

View File

@ -15,6 +15,7 @@ import {
import { ProjectDetails, RepositoryDetails } from '../../../../types/project';
import ConfirmDialog from '../../../shared/ConfirmDialog';
import EditDomainDialog from './EditDomainDialog';
import { useGQLClient } from '../../../../context/GQLClientContext';
enum RefreshStatus {
IDLE,
@ -51,6 +52,19 @@ const DomainCard = ({
const [deleteDialogOpen, setDeleteDialogOpen] = useState(false);
const [editDialogOpen, setEditDialogOpen] = useState(false);
const client = useGQLClient();
const deleteDomain = async () => {
const { deleteDomain } = await client.deleteDomain(domain.id);
if (deleteDomain) {
onUpdate();
toast.success(`Domain ${domain.name} deleted successfully`);
} else {
toast.error(`Error deleting domain ${domain.name}`);
}
};
return (
<>
<div className="flex justify-between py-3">
@ -109,8 +123,8 @@ const DomainCard = ({
open={deleteDialogOpen}
confirmButtonTitle="Yes, Delete domain"
handleConfirm={() => {
deleteDomain();
setDeleteDialogOpen((preVal) => !preVal);
toast.success(`Domain "${domain.name}" has been deleted`);
}}
color="red"
>

View File

@ -1,12 +1,13 @@
import React, { useEffect, useMemo, useState } from 'react';
import { useParams, Link, useOutletContext } from 'react-router-dom';
import { Domain } from 'gql-client';
import { Button, Typography } from '@material-tailwind/react';
import DomainCard from './DomainCard';
import { ProjectSearchOutletContext } from '../../../../types/project';
import { useGQLClient } from '../../../../context/GQLClientContext';
import { Domain } from 'gql-client';
import repositories from '../../../../assets/repositories.json';
const Domains = () => {
const { id } = useParams();
@ -22,16 +23,6 @@ const Domains = () => {
});
}, [id, projects]);
// TODO: Use github API for getting linked repository
const linkedRepo = {
id: 3,
title: 'project-103',
updatedAt: '2023-12-21T04:20:00',
user: 'charlie',
private: false,
branch: ['main', 'prod', 'test'],
};
const fetchDomains = async () => {
if (currentProject === undefined) {
return;
@ -62,7 +53,8 @@ const Domains = () => {
domains={domains}
domain={domain}
key={domain.id}
repo={linkedRepo!}
// TODO: Use github API for getting linked repository
repo={repositories[0]!}
project={currentProject!}
onUpdate={fetchDomains}
/>

View File

@ -63,7 +63,7 @@ const EditDomainDialog = ({
}, [domains, domain]);
const isDisableDropdown = useMemo(() => {
return domainRedirectedFrom?.redirectTo?.id !== undefined;
return domainRedirectedFrom !== undefined;
}, [domain, domains]);
const {

View File

@ -1,8 +1,8 @@
import { ApolloClient, DefaultOptions, InMemoryCache, NormalizedCacheObject } from '@apollo/client';
import { getUser, getOrganizations, getDeployments, getProjectMembers, searchProjects, getEnvironmentVariables, getProject, getDomains, getProjectsInOrganization } from './queries';
import { AddEnvironmentVariableInput, AddEnvironmentVariablesResponse, GetDeploymentsResponse, GetEnvironmentVariablesResponse, GetOrganizationsResponse, GetProjectMembersResponse, SearchProjectsResponse, GetUserResponse, UpdateDeploymentToProdResponse, GetProjectResponse, UpdateProjectResponse, UpdateProjectInput, RedeployToProdResponse, DeleteProjectResponse, GetProjectsInOrganizationResponse, RollbackDeploymentResponse, AddDomainInput, AddDomainResponse, GetDomainsResponse, UpdateDomainInput, UpdateDomainResponse, AuthenticateGitHubResponse, UnauthenticateGitHubResponse, UpdateEnvironmentVariableResponse, UpdateEnvironmentVariableInput, RemoveEnvironmentVariableResponse, UpdateProjectMemberInput, RemoveProjectMemberResponse, UpdateProjectMemberResponse } from './types';
import { removeProjectMember, addEnvironmentVariables, updateDeploymentToProd, updateProjectMutation, redeployToProd, deleteProject, addDomain, rollbackDeployment, updateDomainMutation, authenticateGitHub, unauthenticateGitHub, updateEnvironmentVariable, removeEnvironmentVariable, updateProjectMember } from './mutations';
import { AddEnvironmentVariableInput, AddEnvironmentVariablesResponse, GetDeploymentsResponse, GetEnvironmentVariablesResponse, GetOrganizationsResponse, GetProjectMembersResponse, SearchProjectsResponse, GetUserResponse, UpdateDeploymentToProdResponse, GetProjectResponse, UpdateProjectResponse, UpdateProjectInput, RedeployToProdResponse, DeleteProjectResponse, GetProjectsInOrganizationResponse, RollbackDeploymentResponse, AddDomainInput, AddDomainResponse, GetDomainsResponse, UpdateDomainInput, UpdateDomainResponse, AuthenticateGitHubResponse, UnauthenticateGitHubResponse, UpdateEnvironmentVariableResponse, UpdateEnvironmentVariableInput, RemoveEnvironmentVariableResponse, UpdateProjectMemberInput, RemoveProjectMemberResponse, UpdateProjectMemberResponse, DeleteDomainResponse } from './types';
import { removeProjectMember, addEnvironmentVariables, updateDeploymentToProd, updateProjectMutation, redeployToProd, deleteProject, addDomain, rollbackDeployment, updateDomainMutation, authenticateGitHub, unauthenticateGitHub, updateEnvironmentVariable, removeEnvironmentVariable, updateProjectMember, deleteDomain } from './mutations';
export interface GraphQLConfig {
gqlEndpoint: string;
@ -228,6 +228,17 @@ export class GQLClient {
return data;
}
async deleteDomain (domainId: string): Promise<DeleteDomainResponse> {
const { data } = await this.client.mutate({
mutation: deleteDomain,
variables: {
domainId
}
});
return data;
}
async rollbackDeployment (projectId: string, deploymentId: string): Promise<RollbackDeploymentResponse> {
const { data } = await this.client.mutate({
mutation: rollbackDeployment,

View File

@ -58,6 +58,11 @@ mutation ($projectId: String!) {
}
`;
export const deleteDomain = gql`
mutation ($domainId: String!) {
deleteDomain(domainId: $domainId)
}`;
export const rollbackDeployment = gql`
mutation ($projectId: String! ,$deploymentId: String!) {
rollbackDeployment(projectId: $projectId, deploymentId: $deploymentId)

View File

@ -218,6 +218,10 @@ export type DeleteProjectResponse = {
deleteProject: boolean;
}
export type DeleteDomainResponse = {
deleteDomain: boolean;
}
export type UpdateProjectInput = {
name: string
description: string