diff --git a/packages/backend/src/database.ts b/packages/backend/src/database.ts index b471e867..2da2f6d4 100644 --- a/packages/backend/src/database.ts +++ b/packages/backend/src/database.ts @@ -365,4 +365,16 @@ export class Database { return domains; } + + async updateDomainById (domainId: string, updates: DeepPartial): Promise { + const domainRepository = this.dataSource.getRepository(Domain); + + const updateResult = await domainRepository.update({ id: Number(domainId) }, updates); + + if (updateResult.affected) { + return updateResult.affected > 0; + } else { + return false; + } + } } diff --git a/packages/backend/src/resolvers.ts b/packages/backend/src/resolvers.ts index a2e9f318..da186f25 100644 --- a/packages/backend/src/resolvers.ts +++ b/packages/backend/src/resolvers.ts @@ -153,9 +153,9 @@ export const createResolvers = async (db: Database): Promise => { } }, - updateProject: async (_: any, { projectId, updateProject }: { projectId: string, updateProject: { name: string, description: string } }) => { + updateProject: async (_: any, { projectId, projectDetails }: { projectId: string, projectDetails: { name: string, description: string } }) => { try { - return db.updateProjectById(projectId, updateProject); + return db.updateProjectById(projectId, projectDetails); } catch (err) { log(err); return false; @@ -198,6 +198,16 @@ export const createResolvers = async (db: Database): Promise => { log(err); return false; } + }, + + updateDomain: async (_: any, { domainId, domainDetails }: { domainId: string, domainDetails: {name?: string, isRedirected?: boolean, branch?: string }}) => { + try { + await db.updateDomainById(domainId, domainDetails); + return true; + } catch (err) { + log(err); + return false; + } } } }; diff --git a/packages/backend/src/schema.gql b/packages/backend/src/schema.gql index c8c27b20..74a74baa 100644 --- a/packages/backend/src/schema.gql +++ b/packages/backend/src/schema.gql @@ -129,11 +129,12 @@ type Mutation { removeMember(memberId: String!): Boolean! addEnvironmentVariables(projectId: String!, environmentVariables: [AddEnvironmentVariableInput!]): Boolean! updateDeploymentToProd(deploymentId: String!): Boolean! - updateProject(projectId: String!, updateProject: UpdateProjectInput): Boolean! + updateProject(projectId: String!, projectDetails: UpdateProjectInput): Boolean! redeployToProd(deploymentId: String!): Boolean! deleteProject(projectId: String!): Boolean! rollbackDeployment(projectId: String!, deploymentId: String!): Boolean! addDomain(projectId: String!, domainDetails: AddDomainInput!): Boolean! + updateDomain(domainId: String!, domainDetails: UpdateDomainInput!): Boolean! } input AddEnvironmentVariableInput { @@ -150,3 +151,9 @@ input UpdateProjectInput { input AddDomainInput { name: String! } + +input UpdateDomainInput { + name: String + isRedirected: Boolean + branch: String +} diff --git a/packages/frontend/src/components/projects/project/settings/DomainCard.tsx b/packages/frontend/src/components/projects/project/settings/DomainCard.tsx index 02cfe568..a3a61f8c 100644 --- a/packages/frontend/src/components/projects/project/settings/DomainCard.tsx +++ b/packages/frontend/src/components/projects/project/settings/DomainCard.tsx @@ -24,9 +24,11 @@ enum RefreshStatus { } interface DomainCardProps { + domains: Domain[]; domain: Domain; repo: RepositoryDetails; project: ProjectDetails; + onUpdate: () => Promise; } const CHECK_FAIL_TIMEOUT = 5000; // In milliseconds @@ -38,7 +40,13 @@ const DOMAIN_RECORD = { value: '56.49.19.21', }; -const DomainCard = ({ domain, repo, project }: DomainCardProps) => { +const DomainCard = ({ + domains, + domain, + repo, + project, + onUpdate, +}: DomainCardProps) => { const [refreshStatus, SetRefreshStatus] = useState(RefreshStatus.IDLE); const [deleteDialogOpen, setDeleteDialogOpen] = useState(false); const [editDialogOpen, setEditDialogOpen] = useState(false); @@ -163,10 +171,11 @@ const DomainCard = ({ domain, repo, project }: DomainCardProps) => { handleOpen={() => { setEditDialogOpen((preVal) => !preVal); }} + domains={domains} open={editDialogOpen} domain={domain} repo={repo} - project={project} + onUpdate={onUpdate} /> ); diff --git a/packages/frontend/src/components/projects/project/settings/Domains.tsx b/packages/frontend/src/components/projects/project/settings/Domains.tsx index 3ceb88dd..e7f69a2a 100644 --- a/packages/frontend/src/components/projects/project/settings/Domains.tsx +++ b/packages/frontend/src/components/projects/project/settings/Domains.tsx @@ -55,10 +55,12 @@ const Domains = () => { {domains.map((domain) => { return ( ); })} diff --git a/packages/frontend/src/components/projects/project/settings/EditDomainDialog.tsx b/packages/frontend/src/components/projects/project/settings/EditDomainDialog.tsx index f1eae60a..3bd694aa 100644 --- a/packages/frontend/src/components/projects/project/settings/EditDomainDialog.tsx +++ b/packages/frontend/src/components/projects/project/settings/EditDomainDialog.tsx @@ -1,4 +1,4 @@ -import React, { useMemo } from 'react'; +import React, { useCallback, useMemo } from 'react'; import { Controller, useForm } from 'react-hook-form'; import toast from 'react-hot-toast'; import { Domain } from 'gql-client'; @@ -15,25 +15,30 @@ import { Option, } from '@material-tailwind/react'; -import { ProjectDetails, RepositoryDetails } from '../../../../types/project'; +import { RepositoryDetails } from '../../../../types/project'; +import { useGQLClient } from '../../../../context/GQLClientContext'; const DEFAULT_REDIRECT_OPTIONS = ['none']; interface EditDomainDialogProp { + domains: Domain[]; open: boolean; handleOpen: () => void; domain: Domain; repo: RepositoryDetails; - project: ProjectDetails; + onUpdate: () => Promise; } const EditDomainDialog = ({ + domains, open, handleOpen, domain, repo, - project, + onUpdate, }: EditDomainDialogProp) => { + const client = useGQLClient(); + const getRedirectUrl = (domain: Domain) => { const domainArr = domain.name.split('www.'); let redirectUrl = ''; @@ -45,12 +50,6 @@ const EditDomainDialog = ({ return redirectUrl; }; - const domains = project.deployments - .filter((deployment: any) => { - return deployment.domain != null; - }) - .map((deployment: any) => deployment.domain); - const redirectOptions = useMemo(() => { const redirectUrl = getRedirectUrl(domain); return [...DEFAULT_REDIRECT_OPTIONS, redirectUrl]; @@ -63,9 +62,31 @@ const EditDomainDialog = ({ (domain) => domain.name === redirectUrl, ); - return domainRedirected?.isRedirectedto; + return domainRedirected?.isRedirected; }, [domain]); + const onSubmit = useCallback( + async (data: any) => { + const updates = { + name: data.name, + branch: data.branch, + isRedirected: data.redirectedTo !== 'none', + }; + + const { updateDomain } = await client.updateDomain(domain.id, updates); + + if (updateDomain) { + await onUpdate(); + toast.success(`Domain ${domain.name} has been updated`); + } else { + toast.error(`Error updating domain ${domain.name}`); + } + + handleOpen(); + }, + [client], + ); + const { handleSubmit, register, @@ -94,12 +115,7 @@ const EditDomainDialog = ({ X -
{ - handleOpen(); - toast.success(`Domain ${domain.name} has been updated`); - })} - > + Domain name diff --git a/packages/gql-client/src/client.ts b/packages/gql-client/src/client.ts index ade2cab2..f061bafb 100644 --- a/packages/gql-client/src/client.ts +++ b/packages/gql-client/src/client.ts @@ -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, RemoveMemberResponse, UpdateDeploymentToProdResponse, GetProjectResponse, UpdateProjectResponse, UpdateProjectInput, RedeployToProdResponse, DeleteProjectResponse, GetProjectsInOrganizationResponse, RollbackDeploymentResponse, AddDomainInput, AddDomainResponse, GetDomainsResponse } from './types'; -import { removeMember, addEnvironmentVariables, updateDeploymentToProd, updateProjectMutation, redeployToProd, deleteProject, addDomain, rollbackDeployment } from './mutations'; +import { AddEnvironmentVariableInput, AddEnvironmentVariablesResponse, GetDeploymentsResponse, GetEnvironmentVariablesResponse, GetOrganizationsResponse, GetProjectMembersResponse, SearchProjectsResponse, GetUserResponse, RemoveMemberResponse, UpdateDeploymentToProdResponse, GetProjectResponse, UpdateProjectResponse, UpdateProjectInput, RedeployToProdResponse, DeleteProjectResponse, GetProjectsInOrganizationResponse, RollbackDeploymentResponse, AddDomainInput, AddDomainResponse, GetDomainsResponse, UpdateDomainInput, UpdateDomainResponse } from './types'; +import { removeMember, addEnvironmentVariables, updateDeploymentToProd, updateProjectMutation, redeployToProd, deleteProject, addDomain, rollbackDeployment, updateDomainMutation } from './mutations'; export interface GraphQLConfig { gqlEndpoint: string; @@ -147,12 +147,24 @@ export class GQLClient { return data; } - async updateProject (projectId: string, updateProject: UpdateProjectInput): Promise { + async updateProject (projectId: string, projectDetails: UpdateProjectInput): Promise { const { data } = await this.client.mutate({ mutation: updateProjectMutation, variables: { projectId, - updateProject + projectDetails + } + }); + + return data; + } + + async updateDomain (domainId: string, domainDetails: UpdateDomainInput): Promise { + const { data } = await this.client.mutate({ + mutation: updateDomainMutation, + variables: { + domainId, + domainDetails } }); diff --git a/packages/gql-client/src/mutations.ts b/packages/gql-client/src/mutations.ts index f151d306..aec887d7 100644 --- a/packages/gql-client/src/mutations.ts +++ b/packages/gql-client/src/mutations.ts @@ -19,8 +19,13 @@ mutation ($deploymentId: String!) { `; export const updateProjectMutation = gql` -mutation ($projectId: String!, $updateProject: UpdateProjectInput) { - updateProject(projectId: $projectId, updateProject: $updateProject) +mutation ($projectId: String!, $projectDetails: UpdateProjectInput) { + updateProject(projectId: $projectId, projectDetails: $projectDetails) +}`; + +export const updateDomainMutation = gql` +mutation ($domainId: String!, $domainDetails: UpdateDomainInput!) { + updateDomain(domainId: $domainId, domainDetails: $domainDetails) }`; export const redeployToProd = gql` diff --git a/packages/gql-client/src/types.ts b/packages/gql-client/src/types.ts index a2033b1e..9bf85462 100644 --- a/packages/gql-client/src/types.ts +++ b/packages/gql-client/src/types.ts @@ -187,6 +187,10 @@ export type UpdateProjectResponse = { updateProject: boolean; } +export type UpdateDomainResponse = { + updateDomain: boolean; +} + export type DeleteProjectResponse = { deleteProject: boolean; } @@ -196,6 +200,12 @@ export type UpdateProjectInput = { description: string } +export type UpdateDomainInput = { + name?: string; + isRedirected?: boolean; + branch?: string; +} + export type RedeployToProdResponse = { redeployToProd: boolean }