Add GQL mutation to delete project (#43)
* Implement delete project functionality * Use delete project client method in UI * Refetch projects information on deleting project * Use project's current deployment domain name for url * Handle review changes --------- Co-authored-by: neeraj <neeraj.rtly@gmail.com>
This commit is contained in:
parent
cfb4b4637c
commit
1ae1564878
@ -78,22 +78,39 @@ export class Database {
|
||||
return projects;
|
||||
}
|
||||
|
||||
async getProjectByProjectId (projectId: string): Promise<Project | null> {
|
||||
async getProjectById (projectId: string): Promise<Project | null> {
|
||||
const projectRepository = this.dataSource.getRepository(Project);
|
||||
|
||||
const project = await projectRepository.findOne({
|
||||
relations: {
|
||||
organization: true,
|
||||
owner: true
|
||||
},
|
||||
where: {
|
||||
id: projectId
|
||||
}
|
||||
});
|
||||
const project = await projectRepository
|
||||
.createQueryBuilder('project')
|
||||
.leftJoinAndSelect('project.deployments', 'deployments', 'deployments.isCurrent = true')
|
||||
.leftJoinAndSelect('deployments.domain', 'domain')
|
||||
.leftJoinAndSelect('project.owner', 'owner')
|
||||
.where('project.id = :projectId', {
|
||||
projectId
|
||||
})
|
||||
.getOne();
|
||||
|
||||
return project;
|
||||
}
|
||||
|
||||
async getProjectsInOrganization (userId: string, organizationId: string): Promise<Project[]> {
|
||||
const projectRepository = this.dataSource.getRepository(Project);
|
||||
|
||||
const projects = await projectRepository
|
||||
.createQueryBuilder('project')
|
||||
.leftJoinAndSelect('project.deployments', 'deployments', 'deployments.isCurrent = true')
|
||||
.leftJoinAndSelect('deployments.domain', 'domain')
|
||||
.leftJoin('project.projectMembers', 'projectMembers')
|
||||
.where('(project.ownerId = :userId OR projectMembers.userId = :userId) AND project.organizationId = :organizationId', {
|
||||
userId,
|
||||
organizationId
|
||||
})
|
||||
.getMany();
|
||||
|
||||
return projects;
|
||||
}
|
||||
|
||||
async getDeploymentsByProjectId (projectId: string): Promise<Deployment[]> {
|
||||
const deploymentRepository = this.dataSource.getRepository(Deployment);
|
||||
|
||||
@ -275,4 +292,15 @@ export class Database {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
async deleteProjectById (projectId: string): Promise<boolean> {
|
||||
const projectRepository = this.dataSource.getRepository(Project);
|
||||
const deleteResult = await projectRepository.softDelete({ id: projectId });
|
||||
|
||||
if (deleteResult.affected) {
|
||||
return deleteResult.affected > 0;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -6,12 +6,14 @@ import {
|
||||
UpdateDateColumn,
|
||||
ManyToOne,
|
||||
JoinColumn,
|
||||
OneToMany
|
||||
OneToMany,
|
||||
DeleteDateColumn
|
||||
} from 'typeorm';
|
||||
|
||||
import { User } from './User';
|
||||
import { Organization } from './Organization';
|
||||
import { ProjectMember } from './ProjectMember';
|
||||
import { Deployment } from './Deployment';
|
||||
|
||||
@Entity()
|
||||
export class Project {
|
||||
@ -49,12 +51,21 @@ export class Project {
|
||||
})
|
||||
webhooks!: string[];
|
||||
|
||||
@Column('varchar')
|
||||
icon!: string;
|
||||
|
||||
@CreateDateColumn()
|
||||
createdAt!: Date;
|
||||
|
||||
@UpdateDateColumn()
|
||||
updatedAt!: Date;
|
||||
|
||||
@DeleteDateColumn()
|
||||
deletedAt?: Date;
|
||||
|
||||
@OneToMany(() => ProjectMember, projectMember => projectMember.project)
|
||||
projectMembers!: ProjectMember[];
|
||||
|
||||
@OneToMany(() => Deployment, (deployment) => deployment.project)
|
||||
deployments!: Deployment[];
|
||||
}
|
||||
|
@ -50,9 +50,14 @@ export const createResolvers = async (db: Database): Promise<any> => {
|
||||
},
|
||||
|
||||
project: async (_: any, { projectId }: { projectId: string }) => {
|
||||
const dbProject = await db.getProjectByProjectId(projectId);
|
||||
const dbProject = await db.getProjectById(projectId);
|
||||
|
||||
return dbProject ? projectToGqlType(dbProject, [], []) : null;
|
||||
return dbProject || null;
|
||||
},
|
||||
|
||||
projectsInOrganization: async (_: any, { organizationId }: {organizationId: string }, context: any) => {
|
||||
const dbProject = await db.getProjectsInOrganization(context.userId, organizationId);
|
||||
return dbProject;
|
||||
},
|
||||
|
||||
deployments: async (_: any, { projectId }: { projectId: string }) => {
|
||||
@ -155,6 +160,15 @@ export const createResolvers = async (db: Database): Promise<any> => {
|
||||
log(err);
|
||||
return false;
|
||||
}
|
||||
},
|
||||
|
||||
deleteProject: async (_: any, { projectId }: { projectId: string }) => {
|
||||
try {
|
||||
return db.deleteProjectById(projectId);
|
||||
} catch (err) {
|
||||
log(err);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
@ -69,6 +69,7 @@ type Project {
|
||||
createdAt: String!
|
||||
updatedAt: String!
|
||||
organization: Organization!
|
||||
icon: String
|
||||
}
|
||||
|
||||
type ProjectMember {
|
||||
@ -115,6 +116,7 @@ type Query {
|
||||
user: User!
|
||||
organizations: [Organization!]
|
||||
projects: [Project!]
|
||||
projectsInOrganization(organizationId: String!): [Project!]
|
||||
project(projectId: String!): Project
|
||||
deployments(projectId: String!): [Deployment!]
|
||||
environmentVariables(projectId: String!): [EnvironmentVariable!]
|
||||
@ -128,6 +130,7 @@ type Mutation {
|
||||
updateDeploymentToProd(deploymentId: String!): Boolean!
|
||||
updateProject(projectId: String!, updateProject: UpdateProjectInput): Boolean!
|
||||
redeployToProd(deploymentId: String!): Boolean!
|
||||
deleteProject(projectId: String!): Boolean!
|
||||
}
|
||||
|
||||
input AddEnvironmentVariableInput {
|
||||
|
35
packages/backend/test/fixtures/projects.json
vendored
35
packages/backend/test/fixtures/projects.json
vendored
@ -1,57 +1,62 @@
|
||||
[
|
||||
{
|
||||
"ownerIndex":0,
|
||||
"organizationIndex":0,
|
||||
"ownerIndex": 0,
|
||||
"organizationIndex": 0,
|
||||
"name": "testProject",
|
||||
"repository": "test",
|
||||
"prodBranch": "main",
|
||||
"description": "test",
|
||||
"template": "test",
|
||||
"framework": "test",
|
||||
"webhooks": []
|
||||
"webhooks": [],
|
||||
"icon": ""
|
||||
},
|
||||
{
|
||||
"ownerIndex":1,
|
||||
"organizationIndex":0,
|
||||
"ownerIndex": 1,
|
||||
"organizationIndex": 0,
|
||||
"name": "testProject-2",
|
||||
"repository": "test-2",
|
||||
"prodBranch": "main",
|
||||
"description": "test-2",
|
||||
"template": "test-2",
|
||||
"framework": "test-2",
|
||||
"webhooks": []
|
||||
"webhooks": [],
|
||||
"icon": ""
|
||||
},
|
||||
{
|
||||
"ownerIndex":2,
|
||||
"organizationIndex":0,
|
||||
"ownerIndex": 2,
|
||||
"organizationIndex": 0,
|
||||
"name": "iglootools",
|
||||
"repository": "test-3",
|
||||
"prodBranch": "main",
|
||||
"description": "test-3",
|
||||
"template": "test-3",
|
||||
"framework": "test-3",
|
||||
"webhooks": []
|
||||
"webhooks": [],
|
||||
"icon": ""
|
||||
},
|
||||
{
|
||||
"ownerIndex":1,
|
||||
"organizationIndex":0,
|
||||
"ownerIndex": 1,
|
||||
"organizationIndex": 0,
|
||||
"name": "iglootools-2",
|
||||
"repository": "test-4",
|
||||
"prodBranch": "main",
|
||||
"description": "test-4",
|
||||
"template": "test-4",
|
||||
"framework": "test-4",
|
||||
"webhooks": []
|
||||
"webhooks": [],
|
||||
"icon": ""
|
||||
},
|
||||
{
|
||||
"ownerIndex":0,
|
||||
"organizationIndex":1,
|
||||
"ownerIndex": 0,
|
||||
"organizationIndex": 1,
|
||||
"name": "snowball-2",
|
||||
"repository": "test-5",
|
||||
"prodBranch": "main",
|
||||
"description": "test-5",
|
||||
"template": "test-5",
|
||||
"framework": "test-5",
|
||||
"webhooks": []
|
||||
"webhooks": [],
|
||||
"icon": ""
|
||||
}
|
||||
]
|
||||
|
@ -25,7 +25,9 @@ const ProjectCard: React.FC<ProjectCardProps> = ({ project }) => {
|
||||
<Link to={`projects/${project.id}`}>
|
||||
<Typography>{project.name}</Typography>
|
||||
<Typography color="gray" variant="small">
|
||||
{project.url}
|
||||
{project.deployments[0]?.domain.name
|
||||
? project.deployments[0]?.domain.name
|
||||
: ''}
|
||||
</Typography>
|
||||
</Link>
|
||||
</div>
|
||||
|
@ -31,7 +31,9 @@ const OverviewTabPanel = ({ project, organizationProject }: OverviewProps) => {
|
||||
<div className="grow">
|
||||
<Typography>{project.name}</Typography>
|
||||
<Typography variant="small" color="gray">
|
||||
{organizationProject.url}
|
||||
{project.deployments[0]?.domain.name
|
||||
? project.deployments[0]?.domain.name
|
||||
: ''}
|
||||
</Typography>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -1,6 +1,8 @@
|
||||
import React from 'react';
|
||||
import React, { useCallback } from 'react';
|
||||
import { useNavigate } from 'react-router-dom';
|
||||
import { useForm } from 'react-hook-form';
|
||||
import toast from 'react-hot-toast';
|
||||
import { Project } from 'gql-client';
|
||||
|
||||
import {
|
||||
Button,
|
||||
@ -11,13 +13,12 @@ import {
|
||||
Input,
|
||||
Typography,
|
||||
} from '@material-tailwind/react';
|
||||
|
||||
import { ProjectDetails } from '../../../../types/project';
|
||||
import { useGQLClient } from '../../../../context/GQLClientContext';
|
||||
|
||||
interface DeleteProjectDialogProp {
|
||||
open: boolean;
|
||||
handleOpen: () => void;
|
||||
project: Partial<ProjectDetails>;
|
||||
project: Project;
|
||||
}
|
||||
|
||||
const DeleteProjectDialog = ({
|
||||
@ -26,6 +27,7 @@ const DeleteProjectDialog = ({
|
||||
project,
|
||||
}: DeleteProjectDialogProp) => {
|
||||
const navigate = useNavigate();
|
||||
const client = useGQLClient();
|
||||
|
||||
const {
|
||||
handleSubmit,
|
||||
@ -37,6 +39,18 @@ const DeleteProjectDialog = ({
|
||||
},
|
||||
});
|
||||
|
||||
const deleteProjectHandler = useCallback(async () => {
|
||||
const { deleteProject } = await client.deleteProject(project.id);
|
||||
|
||||
if (deleteProject) {
|
||||
navigate('/');
|
||||
} else {
|
||||
toast.error('Project not deleted');
|
||||
}
|
||||
|
||||
handleOpen();
|
||||
}, [client, project, handleOpen]);
|
||||
|
||||
return (
|
||||
<Dialog open={open} handler={handleOpen}>
|
||||
<DialogHeader className="flex justify-between">
|
||||
@ -49,12 +63,7 @@ const DeleteProjectDialog = ({
|
||||
X
|
||||
</Button>
|
||||
</DialogHeader>
|
||||
<form
|
||||
onSubmit={handleSubmit(() => {
|
||||
handleOpen();
|
||||
navigate('/');
|
||||
})}
|
||||
>
|
||||
<form onSubmit={handleSubmit(deleteProjectHandler)}>
|
||||
<DialogBody className="flex flex-col gap-2">
|
||||
<Typography variant="paragraph">
|
||||
Deleting your project is irreversible. Enter your project’s
|
||||
|
@ -11,14 +11,10 @@ import {
|
||||
Card,
|
||||
} from '@material-tailwind/react';
|
||||
|
||||
import {
|
||||
DomainDetails,
|
||||
DomainStatus,
|
||||
ProjectDetails,
|
||||
RepositoryDetails,
|
||||
} from '../../../../types/project';
|
||||
import { ProjectDetails, RepositoryDetails } from '../../../../types/project';
|
||||
import ConfirmDialog from '../../../shared/ConfirmDialog';
|
||||
import EditDomainDialog from './EditDomainDialog';
|
||||
import { Domain, DomainStatus } from 'gql-client';
|
||||
|
||||
enum RefreshStatus {
|
||||
IDLE,
|
||||
@ -28,13 +24,20 @@ enum RefreshStatus {
|
||||
}
|
||||
|
||||
interface DomainCardProps {
|
||||
domain: DomainDetails;
|
||||
domain: Domain;
|
||||
repo: RepositoryDetails;
|
||||
project: ProjectDetails;
|
||||
}
|
||||
|
||||
const CHECK_FAIL_TIMEOUT = 5000; // In milliseconds
|
||||
|
||||
// TODO: Get domain record
|
||||
const DOMAIN_RECORD = {
|
||||
type: 'A',
|
||||
name: '@',
|
||||
value: '56.49.19.21',
|
||||
};
|
||||
|
||||
const DomainCard = ({ domain, repo, project }: DomainCardProps) => {
|
||||
const [refreshStatus, SetRefreshStatus] = useState(RefreshStatus.IDLE);
|
||||
const [deleteDialogOpen, setDeleteDialogOpen] = useState(false);
|
||||
@ -50,7 +53,7 @@ const DomainCard = ({ domain, repo, project }: DomainCardProps) => {
|
||||
<Chip
|
||||
className="w-fit capitalize"
|
||||
value={domain.status}
|
||||
color={domain.status === DomainStatus.LIVE ? 'green' : 'orange'}
|
||||
color={domain.status === DomainStatus.Live ? 'green' : 'orange'}
|
||||
variant="ghost"
|
||||
icon={<i>^</i>}
|
||||
/>
|
||||
@ -106,7 +109,7 @@ const DomainCard = ({ domain, repo, project }: DomainCardProps) => {
|
||||
<Typography variant="small">
|
||||
Once deleted, the project{' '}
|
||||
<span className="bg-blue-100 rounded-sm p-0.5 text-blue-700">
|
||||
{project.title}
|
||||
{project.name}
|
||||
</span>{' '}
|
||||
will not be accessible from the domain{' '}
|
||||
<span className="bg-blue-100 rounded-sm p-0.5 text-blue-700">
|
||||
@ -117,7 +120,7 @@ const DomainCard = ({ domain, repo, project }: DomainCardProps) => {
|
||||
</div>
|
||||
|
||||
<Typography variant="small">Production</Typography>
|
||||
{domain.status === DomainStatus.PENDING && (
|
||||
{domain.status === DomainStatus.Pending && (
|
||||
<Card className="bg-gray-200 p-4 text-sm">
|
||||
{refreshStatus === RefreshStatus.IDLE ? (
|
||||
<Typography variant="small">
|
||||
@ -147,9 +150,9 @@ const DomainCard = ({ domain, repo, project }: DomainCardProps) => {
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>{domain.record.type}</td>
|
||||
<td>{domain.record.name}</td>
|
||||
<td>{domain.record.value}</td>
|
||||
<td>{DOMAIN_RECORD.type}</td>
|
||||
<td>{DOMAIN_RECORD.name}</td>
|
||||
<td>{DOMAIN_RECORD.value}</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
@ -4,10 +4,7 @@ import { useParams, Link, useOutletContext } from 'react-router-dom';
|
||||
import { Button, Typography } from '@material-tailwind/react';
|
||||
|
||||
import DomainCard from './DomainCard';
|
||||
import {
|
||||
DomainDetails,
|
||||
ProjectSearchOutletContext,
|
||||
} from '../../../../types/project';
|
||||
import { ProjectSearchOutletContext } from '../../../../types/project';
|
||||
|
||||
const Domains = () => {
|
||||
const { id } = useParams();
|
||||
@ -21,7 +18,7 @@ const Domains = () => {
|
||||
}, [id, projects]);
|
||||
|
||||
const linkedRepo = useMemo(() => {
|
||||
return currentProject?.repositories.find(
|
||||
return currentProject?.repositories?.find(
|
||||
(repo: any) => repo.id === Number(currentProject?.repositoryId),
|
||||
);
|
||||
}, [currentProject]);
|
||||
@ -43,7 +40,7 @@ const Domains = () => {
|
||||
</Link>
|
||||
</div>
|
||||
|
||||
{(domains as DomainDetails[]).map((domain) => {
|
||||
{domains?.map((domain) => {
|
||||
return (
|
||||
<DomainCard
|
||||
domain={domain}
|
||||
|
@ -1,6 +1,7 @@
|
||||
import React, { useMemo } from 'react';
|
||||
import { Controller, useForm } from 'react-hook-form';
|
||||
import toast from 'react-hot-toast';
|
||||
import { Domain } from 'gql-client';
|
||||
|
||||
import {
|
||||
Button,
|
||||
@ -14,18 +15,14 @@ import {
|
||||
Option,
|
||||
} from '@material-tailwind/react';
|
||||
|
||||
import {
|
||||
DomainDetails,
|
||||
ProjectDetails,
|
||||
RepositoryDetails,
|
||||
} from '../../../../types/project';
|
||||
import { ProjectDetails, RepositoryDetails } from '../../../../types/project';
|
||||
|
||||
const DEFAULT_REDIRECT_OPTIONS = ['none'];
|
||||
|
||||
interface EditDomainDialogProp {
|
||||
open: boolean;
|
||||
handleOpen: () => void;
|
||||
domain: DomainDetails;
|
||||
domain: Domain;
|
||||
repo: RepositoryDetails;
|
||||
project: ProjectDetails;
|
||||
}
|
||||
@ -37,7 +34,7 @@ const EditDomainDialog = ({
|
||||
repo,
|
||||
project,
|
||||
}: EditDomainDialogProp) => {
|
||||
const getRedirectUrl = (domain: DomainDetails) => {
|
||||
const getRedirectUrl = (domain: Domain) => {
|
||||
const domainArr = domain.name.split('www.');
|
||||
let redirectUrl = '';
|
||||
if (domain.name.startsWith('www.')) {
|
||||
@ -79,7 +76,7 @@ const EditDomainDialog = ({
|
||||
defaultValues: {
|
||||
name: domain.name,
|
||||
branch: repo.branch[0],
|
||||
redirectedTo: !domain.isRedirectedto
|
||||
redirectedTo: !domain.isRedirected
|
||||
? redirectOptions[0]
|
||||
: redirectOptions[1],
|
||||
},
|
||||
|
@ -206,7 +206,7 @@ const GeneralTabPanel = ({
|
||||
<DeleteProjectDialog
|
||||
handleOpen={handleDeleteProjectDialog}
|
||||
open={openDeleteDialog}
|
||||
project={{ name: 'Iglootools' }}
|
||||
project={project}
|
||||
/>
|
||||
</div>
|
||||
</>
|
||||
|
@ -1,14 +1,41 @@
|
||||
import React from 'react';
|
||||
import { useOutletContext } from 'react-router-dom';
|
||||
import React, { useCallback, useEffect, useState } from 'react';
|
||||
import { Link } from 'react-router-dom';
|
||||
|
||||
import { Button, Typography, Chip } from '@material-tailwind/react';
|
||||
|
||||
import ProjectCard from '../components/projects/ProjectCard';
|
||||
import { ProjectSearchOutletContext } from '../types/project';
|
||||
import { useGQLClient } from '../context/GQLClientContext';
|
||||
import { ProjectDetails } from '../types/project';
|
||||
|
||||
// TODO: Implement organization switcher
|
||||
const USER_ORGANIZATION_ID = '1';
|
||||
|
||||
const Projects = () => {
|
||||
const { projects } = useOutletContext<ProjectSearchOutletContext>();
|
||||
const client = useGQLClient();
|
||||
const [projects, setProjects] = useState<ProjectDetails[]>([]);
|
||||
|
||||
const fetchProjects = useCallback(async () => {
|
||||
const { projectsInOrganization } =
|
||||
await client.getProjectsInOrganization(USER_ORGANIZATION_ID);
|
||||
|
||||
const updatedProjects = projectsInOrganization.map((project) => {
|
||||
return {
|
||||
...project,
|
||||
// TODO: Populate from github API
|
||||
latestCommit: {
|
||||
message: 'subscription added',
|
||||
createdAt: '2023-12-11T04:20:00',
|
||||
branch: 'main',
|
||||
},
|
||||
};
|
||||
});
|
||||
|
||||
setProjects(updatedProjects);
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
fetchProjects();
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<div>
|
||||
@ -33,7 +60,7 @@ const Projects = () => {
|
||||
</div>
|
||||
<div className="grid grid-cols-3 gap-5 p-5">
|
||||
{projects.length !== 0 &&
|
||||
projects.map((project: any, key: number) => {
|
||||
projects.map((project, key) => {
|
||||
return <ProjectCard project={project} key={key} />;
|
||||
})}
|
||||
</div>
|
||||
|
@ -1,29 +1,19 @@
|
||||
import { Environment, EnvironmentVariable } from 'gql-client';
|
||||
import { Environment, Project } from 'gql-client';
|
||||
|
||||
export interface ProjectDetails {
|
||||
icon: string;
|
||||
name: string;
|
||||
title: string;
|
||||
owner: Member;
|
||||
organization: string;
|
||||
description: string;
|
||||
url: string;
|
||||
domain: string | null;
|
||||
id: string;
|
||||
createdAt: string;
|
||||
createdBy: string;
|
||||
deployments: DeploymentDetails[];
|
||||
source: string;
|
||||
export interface ProjectDetails extends Project {
|
||||
// TODO: isDomain flag
|
||||
domain?: string | null;
|
||||
// TODO: Use deployment branch
|
||||
source?: string;
|
||||
latestCommit: {
|
||||
message: string;
|
||||
createdAt: string;
|
||||
branch: string;
|
||||
};
|
||||
repositoryId: number;
|
||||
repositories: RepositoryDetails[];
|
||||
members: ProjectMember[];
|
||||
ownerId: number;
|
||||
environmentVariables: EnvironmentVariable[];
|
||||
|
||||
// TODO: Move out of project
|
||||
repositories?: RepositoryDetails[];
|
||||
repositoryId?: number;
|
||||
}
|
||||
|
||||
export interface ProjectMember {
|
||||
|
@ -1,8 +1,8 @@
|
||||
import { ApolloClient, DefaultOptions, InMemoryCache, NormalizedCacheObject } from '@apollo/client';
|
||||
|
||||
import { getUser, getOrganizations, getDeployments, getProjectMembers, searchProjects, getEnvironmentVariables, getProject } from './queries';
|
||||
import { AddEnvironmentVariableInput, AddEnvironmentVariablesResponse, GetDeploymentsResponse, GetEnvironmentVariablesResponse, GetOrganizationsResponse, GetProjectMembersResponse, SearchProjectsResponse, GetUserResponse, RemoveMemberResponse, UpdateDeploymentToProdResponse, GetProjectResponse, UpdateProjectResponse, UpdateProjectInput, RedeployToProdResponse } from './types';
|
||||
import { removeMember, addEnvironmentVariables, updateDeploymentToProd, updateProjectMutation, redeployToProd } from './mutations';
|
||||
import { getUser, getOrganizations, getDeployments, getProjectMembers, searchProjects, getEnvironmentVariables, getProject, getProjectsInOrganization } from './queries';
|
||||
import { AddEnvironmentVariableInput, AddEnvironmentVariablesResponse, GetDeploymentsResponse, GetEnvironmentVariablesResponse, GetOrganizationsResponse, GetProjectMembersResponse, SearchProjectsResponse, GetUserResponse, RemoveMemberResponse, UpdateDeploymentToProdResponse, GetProjectResponse, UpdateProjectResponse, UpdateProjectInput, RedeployToProdResponse, DeleteProjectResponse, GetProjectsInOrganizationResponse } from './types';
|
||||
import { removeMember, addEnvironmentVariables, updateDeploymentToProd, updateProjectMutation, redeployToProd, deleteProject } from './mutations';
|
||||
|
||||
export interface GraphQLConfig {
|
||||
gqlEndpoint: string;
|
||||
@ -50,6 +50,17 @@ export class GQLClient {
|
||||
return data;
|
||||
}
|
||||
|
||||
async getProjectsInOrganization (organizationId: string) : Promise<GetProjectsInOrganizationResponse> {
|
||||
const { data } = await this.client.query({
|
||||
query: getProjectsInOrganization,
|
||||
variables: {
|
||||
organizationId
|
||||
}
|
||||
});
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
async getOrganizations () : Promise<GetOrganizationsResponse> {
|
||||
const { data } = await this.client.query({
|
||||
query: getOrganizations
|
||||
@ -158,4 +169,15 @@ export class GQLClient {
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
async deleteProject (projectId: string): Promise<DeleteProjectResponse> {
|
||||
const { data } = await this.client.mutate({
|
||||
mutation: deleteProject,
|
||||
variables: {
|
||||
projectId
|
||||
}
|
||||
});
|
||||
|
||||
return data;
|
||||
}
|
||||
}
|
||||
|
@ -28,3 +28,9 @@ mutation ($deploymentId: String!) {
|
||||
redeployToProd(deploymentId: $deploymentId)
|
||||
}
|
||||
`;
|
||||
|
||||
export const deleteProject = gql`
|
||||
mutation ($projectId: String!) {
|
||||
deleteProject(projectId: $projectId)
|
||||
}
|
||||
`;
|
||||
|
@ -25,11 +25,69 @@ query ($projectId: String!) {
|
||||
framework
|
||||
repository
|
||||
webhooks
|
||||
icon
|
||||
owner {
|
||||
id
|
||||
name
|
||||
email
|
||||
}
|
||||
deployments {
|
||||
id
|
||||
branch
|
||||
isCurrent
|
||||
status
|
||||
title
|
||||
updatedAt
|
||||
commitHash
|
||||
createdAt
|
||||
environment
|
||||
domain {
|
||||
status
|
||||
branch
|
||||
createdAt
|
||||
updatedAt
|
||||
id
|
||||
name
|
||||
isRedirected
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
export const getProjectsInOrganization = gql`
|
||||
query ($organizationId: String!) {
|
||||
projectsInOrganization(organizationId: $organizationId) {
|
||||
id
|
||||
name
|
||||
createdAt
|
||||
description
|
||||
framework
|
||||
prodBranch
|
||||
webhooks
|
||||
repository
|
||||
updatedAt
|
||||
icon
|
||||
deployments {
|
||||
id
|
||||
branch
|
||||
isCurrent
|
||||
status
|
||||
title
|
||||
updatedAt
|
||||
commitHash
|
||||
createdAt
|
||||
environment
|
||||
domain {
|
||||
status
|
||||
branch
|
||||
createdAt
|
||||
updatedAt
|
||||
id
|
||||
name
|
||||
isRedirected
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
@ -126,6 +126,7 @@ export type Project = {
|
||||
createdAt: string
|
||||
updatedAt: string
|
||||
organization: Organization
|
||||
icon: string
|
||||
}
|
||||
|
||||
export type GetProjectMembersResponse = {
|
||||
@ -156,6 +157,10 @@ export type GetProjectResponse = {
|
||||
project: Project | null
|
||||
}
|
||||
|
||||
export type GetProjectsInOrganizationResponse = {
|
||||
projectsInOrganization: Project[]
|
||||
}
|
||||
|
||||
export type SearchProjectsResponse = {
|
||||
searchProjects: Project[]
|
||||
}
|
||||
@ -178,6 +183,10 @@ export type UpdateProjectResponse = {
|
||||
updateProject: boolean;
|
||||
}
|
||||
|
||||
export type DeleteProjectResponse = {
|
||||
deleteProject: boolean;
|
||||
}
|
||||
|
||||
export type UpdateProjectInput = {
|
||||
name: string
|
||||
description: string
|
||||
|
Loading…
Reference in New Issue
Block a user