Implement functionality to update production branch in project settings (#60)
* Add mutation to update prod branch for project * Implement frontend to update production branch * Handle review changes * Update README for Github creating OAuth app --------- Co-authored-by: neeraj <neeraj.rtly@gmail.com>
This commit is contained in:
parent
1d58beb2ec
commit
aa49bb0de2
@ -32,7 +32,10 @@
|
||||
|
||||
- Set `githubOauth.clientId` and `githubOauth.clientSecret` in backend [config file](packages/backend/environments/local.toml)
|
||||
- Client id and secret will be available after creating Github OAuth app
|
||||
- https://docs.github.com/en/apps/oauth-apps/building-oauth-apps/creating-an-oauth-app
|
||||
- https://docs.github.com/en/apps/oauth-apps/building-oauth-apps/creating-an-oauth-app
|
||||
- In "Homepage URL", type `http://localhost:3000`
|
||||
- In "Authorization callback URL", type `http://localhost:3000/projects/create`
|
||||
- Generate a new client secret after app is created
|
||||
|
||||
- Start the server
|
||||
|
||||
@ -40,7 +43,7 @@
|
||||
yarn start
|
||||
```
|
||||
|
||||
- Copy the graphQL endpoint from terminal and add the endpoint in the `.env` file present in `packages/frontend`
|
||||
- Copy the graphQL endpoint from terminal and add the endpoint in the [.env](packages/frontend/.env) file present in `packages/frontend`
|
||||
|
||||
```
|
||||
REACT_APP_GQL_SERVER_URL = 'http://localhost:8000/graphql'
|
||||
|
@ -273,6 +273,15 @@ export const createResolvers = async (db: Database, app: OAuthApp): Promise<any>
|
||||
log(err);
|
||||
return false;
|
||||
}
|
||||
},
|
||||
|
||||
updateProdBranch: async (_: any, { projectId, prodBranch }: {projectId: string, prodBranch: string }) => {
|
||||
try {
|
||||
return await db.updateProjectById(projectId, { prodBranch });
|
||||
} catch (err) {
|
||||
log(err);
|
||||
return (false);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
@ -139,6 +139,7 @@ type Mutation {
|
||||
updateEnvironmentVariable(environmentVariableId: String!, environmentVariable: UpdateEnvironmentVariableInput!): Boolean!
|
||||
updateDeploymentToProd(deploymentId: String!): Boolean!
|
||||
updateProject(projectId: String!, projectDetails: UpdateProjectInput): Boolean!
|
||||
updateProdBranch(projectId: String!, prodBranch: String!): Boolean!
|
||||
redeployToProd(deploymentId: String!): Boolean!
|
||||
deleteProject(projectId: String!): Boolean!
|
||||
deleteDomain(domainId: String!): Boolean!
|
||||
|
@ -1,32 +1,72 @@
|
||||
import React, { useEffect, useState } from 'react';
|
||||
import React, { useCallback, useEffect } from 'react';
|
||||
import { useForm } from 'react-hook-form';
|
||||
import toast from 'react-hot-toast';
|
||||
import { Project } from 'gql-client';
|
||||
|
||||
import { Button, Input, Switch, Typography } from '@material-tailwind/react';
|
||||
|
||||
import { GitRepositoryDetails } from '../../../../types/project';
|
||||
import WebhookCard from './WebhookCard';
|
||||
import { useGQLClient } from '../../../../context/GQLClientContext';
|
||||
|
||||
const GitTabPanel = () => {
|
||||
// TODO: Get linked repo from project
|
||||
const [linkedRepo] = useState<GitRepositoryDetails>();
|
||||
const [webhooksArray, setWebhooksArray] = useState<Array<string>>([]);
|
||||
const GitTabPanel = ({
|
||||
project,
|
||||
onUpdate,
|
||||
}: {
|
||||
project: Project;
|
||||
onUpdate: () => Promise<void>;
|
||||
}) => {
|
||||
const client = useGQLClient();
|
||||
|
||||
const {
|
||||
register,
|
||||
handleSubmit,
|
||||
reset,
|
||||
formState: { isSubmitSuccessful },
|
||||
} = useForm();
|
||||
} = useForm({
|
||||
defaultValues: {
|
||||
webhookUrl: project.webhooks,
|
||||
},
|
||||
});
|
||||
|
||||
const {
|
||||
register: registerProdBranch,
|
||||
handleSubmit: handleSubmitProdBranch,
|
||||
reset: resetProdBranch,
|
||||
} = useForm({
|
||||
defaultValues: {
|
||||
prodBranch: project.prodBranch,
|
||||
},
|
||||
});
|
||||
|
||||
const updateProdBranchHandler = useCallback(
|
||||
async (data: any) => {
|
||||
const { updateProdBranch } = await client.updateProdBranch(
|
||||
project.id,
|
||||
data.prodBranch,
|
||||
);
|
||||
|
||||
if (updateProdBranch) {
|
||||
await onUpdate();
|
||||
toast.success('Production branch upadated successfully');
|
||||
} else {
|
||||
toast.error('Error updating production branch');
|
||||
}
|
||||
},
|
||||
[project],
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
reset();
|
||||
}, [isSubmitSuccessful]);
|
||||
|
||||
const handleDelete = (index: number) => {
|
||||
const newArray = webhooksArray.filter((value, idx) => idx != index);
|
||||
setWebhooksArray(newArray);
|
||||
toast.success('Webhook deleted successfully');
|
||||
useEffect(() => {
|
||||
resetProdBranch({
|
||||
prodBranch: project.prodBranch,
|
||||
});
|
||||
}, [project]);
|
||||
|
||||
const handleDelete = () => {
|
||||
// TODO: Impletement functionality to delete webhooks
|
||||
};
|
||||
|
||||
return (
|
||||
@ -55,44 +95,30 @@ const GitTabPanel = () => {
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="mb-2 p-2">
|
||||
<Typography variant="h6" className="text-black">
|
||||
Production branch
|
||||
</Typography>
|
||||
<Typography variant="small">
|
||||
By default, each commit pushed to the{' '}
|
||||
<span className="font-bold">main</span> branch initiates a production
|
||||
deployment. You can opt for a different branch for deployment in the
|
||||
settings.
|
||||
</Typography>
|
||||
{!linkedRepo && (
|
||||
<div className="flex bg-blue-100 gap-4 rounded-lg p-2">
|
||||
<div>^</div>
|
||||
<div>
|
||||
<Typography variant="small">
|
||||
This project isn't currently linked to a Git repository. To
|
||||
establish a production branch, please linked to an existing Git
|
||||
repository in the 'Connected Git Repository' section
|
||||
above.
|
||||
</Typography>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
<Typography variant="small">Branch name</Typography>
|
||||
<Input
|
||||
crossOrigin={undefined}
|
||||
disabled={Boolean(!linkedRepo)}
|
||||
value="main"
|
||||
/>
|
||||
<Button size="sm" disabled className="mt-1">
|
||||
Save
|
||||
</Button>
|
||||
</div>
|
||||
<form onSubmit={handleSubmitProdBranch(updateProdBranchHandler)}>
|
||||
<div className="mb-2 p-2">
|
||||
<Typography variant="h6" className="text-black">
|
||||
Production branch
|
||||
</Typography>
|
||||
<Typography variant="small">
|
||||
By default, each commit pushed to the{' '}
|
||||
<span className="font-bold">{project.prodBranch}</span> branch
|
||||
initiates a production deployment. You can opt for a different
|
||||
branch for deployment in the settings.
|
||||
</Typography>
|
||||
<Typography variant="small">Branch name</Typography>
|
||||
<Input
|
||||
crossOrigin={undefined}
|
||||
{...registerProdBranch('prodBranch')}
|
||||
/>
|
||||
<Button size="sm" className="mt-1" type="submit">
|
||||
Save
|
||||
</Button>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
<form
|
||||
onSubmit={handleSubmit((data) => {
|
||||
setWebhooksArray((prevArray) => [...prevArray, data.webhookUrl]);
|
||||
|
||||
onSubmit={handleSubmit(() => {
|
||||
toast.success('Webhook added successfully.');
|
||||
})}
|
||||
>
|
||||
@ -118,12 +144,12 @@ const GitTabPanel = () => {
|
||||
</div>
|
||||
</form>
|
||||
<div className="mb-2 p-2">
|
||||
{webhooksArray?.map((webhookUrl, index) => {
|
||||
{project.webhooks.map((webhookUrl, index) => {
|
||||
return (
|
||||
<WebhookCard
|
||||
webhooksArray={webhooksArray}
|
||||
webhooksArray={project.webhooks}
|
||||
webhookUrl={webhookUrl}
|
||||
handleDelete={() => handleDelete(index)}
|
||||
handleDelete={() => handleDelete()}
|
||||
key={index}
|
||||
/>
|
||||
);
|
||||
|
@ -41,6 +41,7 @@ const NewProject = () => {
|
||||
return;
|
||||
}
|
||||
|
||||
// TODO: Handle React component error
|
||||
const interceptor = async (error: RequestError | Error) => {
|
||||
if (
|
||||
error instanceof RequestError &&
|
||||
|
@ -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, DeleteDomainResponse } from './types';
|
||||
import { removeProjectMember, addEnvironmentVariables, updateDeploymentToProd, updateProjectMutation, redeployToProd, deleteProject, addDomain, rollbackDeployment, updateDomainMutation, authenticateGitHub, unauthenticateGitHub, updateEnvironmentVariable, removeEnvironmentVariable, updateProjectMember, deleteDomain } 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, UpdateProdBranchResponse } from './types';
|
||||
import { removeProjectMember, addEnvironmentVariables, updateDeploymentToProd, updateProjectMutation, redeployToProd, deleteProject, addDomain, rollbackDeployment, updateDomainMutation, authenticateGitHub, unauthenticateGitHub, updateEnvironmentVariable, removeEnvironmentVariable, updateProjectMember, deleteDomain, updateProdBranch } from './mutations';
|
||||
|
||||
export interface GraphQLConfig {
|
||||
gqlEndpoint: string;
|
||||
@ -292,4 +292,16 @@ export class GQLClient {
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
async updateProdBranch (projectId: string, prodBranch: string): Promise<UpdateProdBranchResponse> {
|
||||
const { data } = await this.client.mutate({
|
||||
mutation: updateProdBranch,
|
||||
variables: {
|
||||
projectId,
|
||||
prodBranch
|
||||
}
|
||||
});
|
||||
|
||||
return data;
|
||||
}
|
||||
}
|
||||
|
@ -86,3 +86,9 @@ export const unauthenticateGitHub = gql`
|
||||
mutation {
|
||||
unauthenticateGitHub
|
||||
}`;
|
||||
|
||||
export const updateProdBranch = gql`
|
||||
mutation ($projectId: String!, $prodBranch: String!) {
|
||||
updateProdBranch(projectId: $projectId, prodBranch: $prodBranch)
|
||||
}
|
||||
`;
|
||||
|
@ -258,3 +258,7 @@ export type AuthenticateGitHubResponse = {
|
||||
export type UnauthenticateGitHubResponse = {
|
||||
unauthenticateGitHub: boolean
|
||||
}
|
||||
|
||||
export type UpdateProdBranchResponse = {
|
||||
updateProdBranch: boolean
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user