forked from cerc-io/snowballtools-base
Show public repo GitHub activity without authentication (#68)
* Handle request error while fetching Git activity * Use default Octokit instance if auth token is not available * Rename input arguments of mutation methods to data --------- Co-authored-by: neeraj <neeraj.rtly@gmail.com>
This commit is contained in:
parent
db3b9148b6
commit
9921dc5186
@ -236,9 +236,9 @@ export class Database {
|
||||
return savedEnvironmentVariables;
|
||||
}
|
||||
|
||||
async updateEnvironmentVariable (environmentVariableId: string, update: DeepPartial<EnvironmentVariable>): Promise<boolean> {
|
||||
async updateEnvironmentVariable (environmentVariableId: string, data: DeepPartial<EnvironmentVariable>): Promise<boolean> {
|
||||
const environmentVariableRepository = this.dataSource.getRepository(EnvironmentVariable);
|
||||
const updateResult = await environmentVariableRepository.update({ id: environmentVariableId }, update);
|
||||
const updateResult = await environmentVariableRepository.update({ id: environmentVariableId }, data);
|
||||
|
||||
return Boolean(updateResult.affected);
|
||||
}
|
||||
@ -293,18 +293,18 @@ export class Database {
|
||||
return projects;
|
||||
}
|
||||
|
||||
async updateDeploymentById (deploymentId: string, updates: DeepPartial<Deployment>): Promise<boolean> {
|
||||
async updateDeploymentById (deploymentId: string, data: DeepPartial<Deployment>): Promise<boolean> {
|
||||
const deploymentRepository = this.dataSource.getRepository(Deployment);
|
||||
const updateResult = await deploymentRepository.update({ id: deploymentId }, updates);
|
||||
const updateResult = await deploymentRepository.update({ id: deploymentId }, data);
|
||||
|
||||
return Boolean(updateResult.affected);
|
||||
}
|
||||
|
||||
async addProject (userId: string, organizationId: string, projectDetails: DeepPartial<Project>): Promise<Project> {
|
||||
async addProject (userId: string, organizationId: string, data: DeepPartial<Project>): Promise<Project> {
|
||||
const projectRepository = this.dataSource.getRepository(Project);
|
||||
|
||||
// TODO: Check if organization exists
|
||||
const newProject = projectRepository.create(projectDetails);
|
||||
const newProject = projectRepository.create(data);
|
||||
// TODO: Set default empty array for webhooks in TypeORM
|
||||
newProject.webhooks = [];
|
||||
// TODO: Set icon according to framework
|
||||
@ -323,9 +323,9 @@ export class Database {
|
||||
return projectRepository.save(newProject);
|
||||
}
|
||||
|
||||
async updateProjectById (projectId: string, updates: DeepPartial<Project>): Promise<boolean> {
|
||||
async updateProjectById (projectId: string, data: DeepPartial<Project>): Promise<boolean> {
|
||||
const projectRepository = this.dataSource.getRepository(Project);
|
||||
const updateResult = await projectRepository.update({ id: projectId }, updates);
|
||||
const updateResult = await projectRepository.update({ id: projectId }, data);
|
||||
|
||||
return Boolean(updateResult.affected);
|
||||
}
|
||||
@ -372,9 +372,9 @@ export class Database {
|
||||
return domain;
|
||||
}
|
||||
|
||||
async updateDomainById (domainId: string, updates: DeepPartial<Domain>): Promise<boolean> {
|
||||
async updateDomainById (domainId: string, data: DeepPartial<Domain>): Promise<boolean> {
|
||||
const domainRepository = this.dataSource.getRepository(Domain);
|
||||
const updateResult = await domainRepository.update({ id: domainId }, updates);
|
||||
const updateResult = await domainRepository.update({ id: domainId }, data);
|
||||
|
||||
return Boolean(updateResult.affected);
|
||||
}
|
||||
|
@ -135,9 +135,9 @@ export const createResolvers = async (service: Service): Promise<any> => {
|
||||
}
|
||||
},
|
||||
|
||||
updateProject: async (_: any, { projectId, projectDetails }: { projectId: string, projectDetails: DeepPartial<Project> }) => {
|
||||
updateProject: async (_: any, { projectId, data }: { projectId: string, data: DeepPartial<Project> }) => {
|
||||
try {
|
||||
return await service.updateProject(projectId, projectDetails);
|
||||
return await service.updateProject(projectId, data);
|
||||
} catch (err) {
|
||||
log(err);
|
||||
return false;
|
||||
@ -179,18 +179,18 @@ export const createResolvers = async (service: Service): Promise<any> => {
|
||||
}
|
||||
},
|
||||
|
||||
addDomain: async (_: any, { projectId, domainDetails }: { projectId: string, domainDetails: { name: string } }) => {
|
||||
addDomain: async (_: any, { projectId, data }: { projectId: string, data: { name: string } }) => {
|
||||
try {
|
||||
return Boolean(await service.addDomain(projectId, domainDetails));
|
||||
return Boolean(await service.addDomain(projectId, data));
|
||||
} catch (err) {
|
||||
log(err);
|
||||
return false;
|
||||
}
|
||||
},
|
||||
|
||||
updateDomain: async (_: any, { domainId, domainDetails }: { domainId: string, domainDetails: DeepPartial<Domain>}) => {
|
||||
updateDomain: async (_: any, { domainId, data }: { domainId: string, data: DeepPartial<Domain>}) => {
|
||||
try {
|
||||
return await service.updateDomain(domainId, domainDetails);
|
||||
return await service.updateDomain(domainId, data);
|
||||
} catch (err) {
|
||||
log(err);
|
||||
return false;
|
||||
|
@ -195,13 +195,13 @@ type Mutation {
|
||||
removeEnvironmentVariable(environmentVariableId: String!): Boolean!
|
||||
updateDeploymentToProd(deploymentId: String!): Boolean!
|
||||
addProject(organizationSlug: String!, data: AddProjectInput): Project!
|
||||
updateProject(projectId: String!, projectDetails: UpdateProjectInput): Boolean!
|
||||
updateProject(projectId: String!, data: 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!
|
||||
addDomain(projectId: String!, data: AddDomainInput!): Boolean!
|
||||
updateDomain(domainId: String!, data: UpdateDomainInput!): Boolean!
|
||||
authenticateGitHub(code: String!): AuthResult!
|
||||
unauthenticateGitHub: Boolean!
|
||||
}
|
||||
|
@ -405,7 +405,7 @@ export class Service {
|
||||
return newCurrentDeploymentUpdate && oldCurrentDeploymentUpdate;
|
||||
}
|
||||
|
||||
async addDomain (projectId: string, domainDetails: { name: string }): Promise<{
|
||||
async addDomain (projectId: string, data: { name: string }): Promise<{
|
||||
primaryDomain: Domain,
|
||||
redirectedDomain: Domain
|
||||
}> {
|
||||
@ -416,14 +416,14 @@ export class Service {
|
||||
}
|
||||
|
||||
const primaryDomainDetails = {
|
||||
...domainDetails,
|
||||
...data,
|
||||
branch: currentProject.prodBranch,
|
||||
project: currentProject
|
||||
};
|
||||
|
||||
const savedPrimaryDomain = await this.db.addDomain(primaryDomainDetails);
|
||||
|
||||
const domainArr = domainDetails.name.split('www.');
|
||||
const domainArr = data.name.split('www.');
|
||||
|
||||
const redirectedDomainDetails = {
|
||||
name: domainArr.length > 1 ? domainArr[1] : `www.${domainArr[0]}`,
|
||||
@ -437,7 +437,7 @@ export class Service {
|
||||
return { primaryDomain: savedPrimaryDomain, redirectedDomain: savedRedirectedDomain };
|
||||
}
|
||||
|
||||
async updateDomain (domainId: string, domainDetails: DeepPartial<Domain>): Promise<boolean> {
|
||||
async updateDomain (domainId: string, data: DeepPartial<Domain>): Promise<boolean> {
|
||||
const domain = await this.db.getDomain({
|
||||
where: {
|
||||
id: domainId
|
||||
@ -449,7 +449,7 @@ export class Service {
|
||||
}
|
||||
|
||||
const newDomain = {
|
||||
...domainDetails
|
||||
...data
|
||||
};
|
||||
|
||||
const domainsRedirectedFrom = await this.db.getDomains({
|
||||
@ -462,14 +462,14 @@ export class Service {
|
||||
});
|
||||
|
||||
// If there are domains redirecting to current domain, only branch of current domain can be updated
|
||||
if (domainsRedirectedFrom.length > 0 && domainDetails.branch === domain.branch) {
|
||||
if (domainsRedirectedFrom.length > 0 && data.branch === domain.branch) {
|
||||
throw new Error('Remove all redirects to this domain before updating');
|
||||
}
|
||||
|
||||
if (domainDetails.redirectToId) {
|
||||
if (data.redirectToId) {
|
||||
const redirectedDomain = await this.db.getDomain({
|
||||
where: {
|
||||
id: domainDetails.redirectToId
|
||||
id: data.redirectToId
|
||||
}
|
||||
});
|
||||
|
||||
|
@ -1,5 +1,3 @@
|
||||
export const ORGANIZATION_ID = '2379cf1f-a232-4ad2-ae14-4d881131cc26';
|
||||
|
||||
export const GIT_TEMPLATE_LINK =
|
||||
'https://git.vdb.to/cerc-io/test-progressive-web-app';
|
||||
|
||||
|
@ -15,16 +15,20 @@ const UNAUTHORIZED_ERROR_CODE = 401;
|
||||
|
||||
interface ContextValue {
|
||||
octokit: Octokit | null;
|
||||
isAuth: boolean;
|
||||
updateAuth: () => void;
|
||||
}
|
||||
|
||||
const OctokitContext = createContext<ContextValue>({
|
||||
octokit: null,
|
||||
isAuth: false,
|
||||
updateAuth: () => {},
|
||||
});
|
||||
|
||||
export const OctokitProvider = ({ children }: { children: ReactNode }) => {
|
||||
const [authToken, setAuthToken] = useState<string>('');
|
||||
const [isAuth, setIsAuth] = useState(false);
|
||||
|
||||
const client = useGQLClient();
|
||||
|
||||
const fetchUser = useCallback(async () => {
|
||||
@ -41,9 +45,11 @@ export const OctokitProvider = ({ children }: { children: ReactNode }) => {
|
||||
|
||||
const octokit = useMemo(() => {
|
||||
if (!authToken) {
|
||||
return null;
|
||||
setIsAuth(false);
|
||||
return new Octokit();
|
||||
}
|
||||
|
||||
setIsAuth(true);
|
||||
return new Octokit({ auth: authToken });
|
||||
}, [authToken]);
|
||||
|
||||
@ -52,10 +58,6 @@ export const OctokitProvider = ({ children }: { children: ReactNode }) => {
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
if (!octokit) {
|
||||
return;
|
||||
}
|
||||
|
||||
// TODO: Handle React component error
|
||||
const interceptor = async (error: RequestError | Error) => {
|
||||
if (
|
||||
@ -78,14 +80,14 @@ export const OctokitProvider = ({ children }: { children: ReactNode }) => {
|
||||
}, [octokit, client]);
|
||||
|
||||
return (
|
||||
<OctokitContext.Provider value={{ octokit, updateAuth }}>
|
||||
<OctokitContext.Provider value={{ octokit, updateAuth, isAuth }}>
|
||||
{children}
|
||||
</OctokitContext.Provider>
|
||||
);
|
||||
};
|
||||
|
||||
export const useOctokit = () => {
|
||||
const { octokit, updateAuth } = useContext(OctokitContext);
|
||||
const { octokit, updateAuth, isAuth } = useContext(OctokitContext);
|
||||
|
||||
return { octokit, updateAuth };
|
||||
return { octokit, updateAuth, isAuth };
|
||||
};
|
||||
|
@ -7,9 +7,9 @@ import ConnectAccount from '../../../../components/projects/create/ConnectAccoun
|
||||
import { useOctokit } from '../../../../context/OctokitContext';
|
||||
|
||||
const NewProject = () => {
|
||||
const { octokit, updateAuth } = useOctokit();
|
||||
const { octokit, updateAuth, isAuth } = useOctokit();
|
||||
|
||||
return Boolean(octokit) ? (
|
||||
return isAuth ? (
|
||||
<>
|
||||
<h5 className="mt-4 ml-4">Start with template</h5>
|
||||
<div className="grid grid-cols-3 p-4 gap-4">
|
||||
|
@ -1,6 +1,7 @@
|
||||
import React, { useEffect, useState } from 'react';
|
||||
import { Domain, DomainStatus } from 'gql-client';
|
||||
import { useOutletContext } from 'react-router-dom';
|
||||
import { useNavigate, useOutletContext } from 'react-router-dom';
|
||||
import { RequestError } from 'octokit';
|
||||
|
||||
import { Typography, Button, Chip, Avatar } from '@material-tailwind/react';
|
||||
|
||||
@ -14,6 +15,7 @@ const COMMITS_PER_PAGE = 4;
|
||||
|
||||
const OverviewTabPanel = () => {
|
||||
const { octokit } = useOctokit();
|
||||
const navigate = useNavigate();
|
||||
const [activities, setActivities] = useState<GitCommitDetails[]>([]);
|
||||
const [liveDomain, setLiveDomain] = useState<Domain>();
|
||||
|
||||
@ -29,47 +31,55 @@ const OverviewTabPanel = () => {
|
||||
// TODO: Save repo commits in DB and avoid using GitHub API in frontend
|
||||
// TODO: Figure out fetching latest commits for all branches
|
||||
const fetchRepoActivity = async () => {
|
||||
const [owner, repo] = project.repository.split('/');
|
||||
try {
|
||||
const [owner, repo] = project.repository.split('/');
|
||||
|
||||
if (!repo) {
|
||||
// Do not fetch branches if repo not available
|
||||
return;
|
||||
}
|
||||
if (!repo) {
|
||||
// Do not fetch branches if repo not available
|
||||
return;
|
||||
}
|
||||
|
||||
// Get all branches in project repo
|
||||
const result = await octokit.rest.repos.listBranches({
|
||||
owner,
|
||||
repo,
|
||||
});
|
||||
|
||||
// Get first 4 commits from repo branches
|
||||
const commitsByBranchPromises = result.data.map(async (branch) => {
|
||||
const result = await octokit.rest.repos.listCommits({
|
||||
// Get all branches in project repo
|
||||
const result = await octokit.rest.repos.listBranches({
|
||||
owner,
|
||||
repo,
|
||||
sha: branch.commit.sha,
|
||||
per_page: COMMITS_PER_PAGE,
|
||||
});
|
||||
|
||||
return result.data.map((data) => ({
|
||||
...data,
|
||||
branch,
|
||||
}));
|
||||
});
|
||||
// Get first 4 commits from repo branches
|
||||
const commitsByBranchPromises = result.data.map(async (branch) => {
|
||||
const result = await octokit.rest.repos.listCommits({
|
||||
owner,
|
||||
repo,
|
||||
sha: branch.commit.sha,
|
||||
per_page: COMMITS_PER_PAGE,
|
||||
});
|
||||
|
||||
const commitsByBranch = await Promise.all(commitsByBranchPromises);
|
||||
const commitsWithBranch = commitsByBranch.flat();
|
||||
return result.data.map((data) => ({
|
||||
...data,
|
||||
branch,
|
||||
}));
|
||||
});
|
||||
|
||||
// Order commits by date and set latest 4 commits in activity section
|
||||
const orderedCommits = commitsWithBranch
|
||||
.sort(
|
||||
(a, b) =>
|
||||
new Date(b.commit.author!.date!).getTime() -
|
||||
new Date(a.commit.author!.date!).getTime(),
|
||||
)
|
||||
.slice(0, COMMITS_PER_PAGE);
|
||||
const commitsByBranch = await Promise.all(commitsByBranchPromises);
|
||||
const commitsWithBranch = commitsByBranch.flat();
|
||||
|
||||
setActivities(orderedCommits);
|
||||
// Order commits by date and set latest 4 commits in activity section
|
||||
const orderedCommits = commitsWithBranch
|
||||
.sort(
|
||||
(a, b) =>
|
||||
new Date(b.commit.author!.date!).getTime() -
|
||||
new Date(a.commit.author!.date!).getTime(),
|
||||
)
|
||||
.slice(0, COMMITS_PER_PAGE);
|
||||
|
||||
setActivities(orderedCommits);
|
||||
} catch (err) {
|
||||
if (!(err instanceof RequestError)) {
|
||||
throw err;
|
||||
}
|
||||
|
||||
console.log(err.message);
|
||||
}
|
||||
};
|
||||
|
||||
fetchRepoActivity();
|
||||
@ -127,6 +137,9 @@ const OverviewTabPanel = () => {
|
||||
className="normal-case rounded-full"
|
||||
color="blue"
|
||||
size="sm"
|
||||
onClick={() => {
|
||||
navigate('settings/domains');
|
||||
}}
|
||||
>
|
||||
Setup
|
||||
</Button>
|
||||
|
@ -206,28 +206,28 @@ export class GQLClient {
|
||||
return result.data;
|
||||
}
|
||||
|
||||
async updateProject (projectId: string, projectDetails: types.UpdateProjectInput): Promise<types.UpdateProjectResponse> {
|
||||
const { data } = await this.client.mutate({
|
||||
async updateProject (projectId: string, data: types.UpdateProjectInput): Promise<types.UpdateProjectResponse> {
|
||||
const result = await this.client.mutate({
|
||||
mutation: mutations.updateProjectMutation,
|
||||
variables: {
|
||||
projectId,
|
||||
projectDetails
|
||||
data
|
||||
}
|
||||
});
|
||||
|
||||
return data;
|
||||
return result.data;
|
||||
}
|
||||
|
||||
async updateDomain (domainId: string, domainDetails: types.UpdateDomainInput): Promise<types.UpdateDomainResponse> {
|
||||
const { data } = await this.client.mutate({
|
||||
async updateDomain (domainId: string, data: types.UpdateDomainInput): Promise<types.UpdateDomainResponse> {
|
||||
const result = await this.client.mutate({
|
||||
mutation: mutations.updateDomainMutation,
|
||||
variables: {
|
||||
domainId,
|
||||
domainDetails
|
||||
data
|
||||
}
|
||||
});
|
||||
|
||||
return data;
|
||||
return result.data;
|
||||
}
|
||||
|
||||
async redeployToProd (deploymentId: string): Promise<types.RedeployToProdResponse> {
|
||||
@ -275,16 +275,16 @@ export class GQLClient {
|
||||
return data;
|
||||
}
|
||||
|
||||
async addDomain (projectId: string, domainDetails: types.AddDomainInput): Promise<types.AddDomainResponse> {
|
||||
const { data } = await this.client.mutate({
|
||||
async addDomain (projectId: string, data: types.AddDomainInput): Promise<types.AddDomainResponse> {
|
||||
const result = await this.client.mutate({
|
||||
mutation: mutations.addDomain,
|
||||
variables: {
|
||||
projectId,
|
||||
domainDetails
|
||||
data
|
||||
}
|
||||
});
|
||||
|
||||
return data;
|
||||
return result.data;
|
||||
}
|
||||
|
||||
async getDomains (projectId: string, filter?: types.FilterDomainInput): Promise<types.GetDomainsResponse> {
|
||||
|
@ -50,13 +50,13 @@ mutation ($organizationSlug: String!, $data: AddProjectInput) {
|
||||
}`;
|
||||
|
||||
export const updateProjectMutation = gql`
|
||||
mutation ($projectId: String!, $projectDetails: UpdateProjectInput) {
|
||||
updateProject(projectId: $projectId, projectDetails: $projectDetails)
|
||||
mutation ($projectId: String!, $data: UpdateProjectInput) {
|
||||
updateProject(projectId: $projectId, data: $data)
|
||||
}`;
|
||||
|
||||
export const updateDomainMutation = gql`
|
||||
mutation ($domainId: String!, $domainDetails: UpdateDomainInput!) {
|
||||
updateDomain(domainId: $domainId, domainDetails: $domainDetails)
|
||||
mutation ($domainId: String!, $data: UpdateDomainInput!) {
|
||||
updateDomain(domainId: $domainId, data: $data)
|
||||
}`;
|
||||
|
||||
export const redeployToProd = gql`
|
||||
@ -83,8 +83,8 @@ mutation ($projectId: String! ,$deploymentId: String!) {
|
||||
`;
|
||||
|
||||
export const addDomain = gql`
|
||||
mutation ($projectId: String!, $domainDetails: AddDomainInput!) {
|
||||
addDomain(projectId: $projectId, domainDetails: $domainDetails)
|
||||
mutation ($projectId: String!, $data: AddDomainInput!) {
|
||||
addDomain(projectId: $projectId, data: $data)
|
||||
}
|
||||
`;
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user