List latest commits from project repo in overview tab (#55)

This commit is contained in:
Nabarun Gogoi 2024-02-05 17:57:08 +05:30 committed by GitHub
parent 1c9597739b
commit 7e522aa45d
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
6 changed files with 87 additions and 24 deletions

View File

@ -188,7 +188,7 @@ type Mutation {
updateEnvironmentVariable(environmentVariableId: String!, data: UpdateEnvironmentVariableInput!): Boolean! updateEnvironmentVariable(environmentVariableId: String!, data: UpdateEnvironmentVariableInput!): Boolean!
removeEnvironmentVariable(environmentVariableId: String!): Boolean! removeEnvironmentVariable(environmentVariableId: String!): Boolean!
updateDeploymentToProd(deploymentId: String!): Boolean! updateDeploymentToProd(deploymentId: String!): Boolean!
addProject(projectDetails: AddProjectInput): Boolean! addProject(data: AddProjectInput): Boolean!
updateProject(projectId: String!, projectDetails: UpdateProjectInput): Boolean! updateProject(projectId: String!, projectDetails: UpdateProjectInput): Boolean!
redeployToProd(deploymentId: String!): Boolean! redeployToProd(deploymentId: String!): Boolean!
deleteProject(projectId: String!): Boolean! deleteProject(projectId: String!): Boolean!

View File

@ -3,31 +3,24 @@ import React from 'react';
import { Typography, IconButton } from '@material-tailwind/react'; import { Typography, IconButton } from '@material-tailwind/react';
import { relativeTime } from '../../../utils/time'; import { relativeTime } from '../../../utils/time';
import { GitCommitDetails } from '../../../types/project';
interface ActivityDetails {
author: string;
authorAvatar: string;
createdAt: string;
branch: string;
message: string;
}
interface ActivityCardProps { interface ActivityCardProps {
activity: ActivityDetails; activity: GitCommitDetails;
} }
const ActivityCard = ({ activity }: ActivityCardProps) => { const ActivityCard = ({ activity }: ActivityCardProps) => {
return ( return (
<div className="group flex hover:bg-gray-200 rounded mt-1"> <div className="group flex hover:bg-gray-200 rounded mt-1">
<div className="w-4">{activity.authorAvatar}</div> <div className="w-4">^</div>
<div className="grow"> <div className="grow">
<Typography>{activity.author}</Typography> <Typography>{activity.commit.author?.name}</Typography>
<Typography variant="small" color="gray"> <Typography variant="small" color="gray">
{relativeTime(activity.createdAt)} ^ {activity.branch} {relativeTime(activity.commit.author!.date!)} ^ {activity.branch.name}
</Typography> </Typography>
<Typography variant="small" color="gray"> <Typography variant="small" color="gray">
{activity.message} {activity.commit.message}
</Typography> </Typography>
</div> </div>
<div className="mr-2 self-center hidden group-hover:block"> <div className="mr-2 self-center hidden group-hover:block">

View File

@ -1,11 +1,14 @@
import React from 'react'; import React, { useEffect, useState } from 'react';
import { Project } from 'gql-client'; import { Project } from 'gql-client';
import { Typography, Button, Chip } from '@material-tailwind/react'; import { Typography, Button, Chip } from '@material-tailwind/react';
import ActivityCard from './ActivityCard'; import ActivityCard from './ActivityCard';
import activityDetails from '../../../assets/activities.json';
import { relativeTimeMs } from '../../../utils/time'; import { relativeTimeMs } from '../../../utils/time';
import { useOctokit } from '../../../context/OctokitContext';
import { GitCommitDetails } from '../../../types/project';
const COMMITS_PER_PAGE = 4;
interface OverviewProps { interface OverviewProps {
project: Project; project: Project;
@ -15,6 +18,58 @@ interface OverviewProps {
const IS_DOMAIN_SETUP = false; const IS_DOMAIN_SETUP = false;
const OverviewTabPanel = ({ project }: OverviewProps) => { const OverviewTabPanel = ({ project }: OverviewProps) => {
const { octokit } = useOctokit();
const [activities, setActivities] = useState<GitCommitDetails[]>([]);
useEffect(() => {
if (!octokit) {
return;
}
// 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('/');
// 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({
owner,
repo,
sha: branch.commit.sha,
per_page: COMMITS_PER_PAGE,
});
return result.data.map((data) => ({
...data,
branch,
}));
});
const commitsByBranch = await Promise.all(commitsByBranchPromises);
const commitsWithBranch = commitsByBranch.flat();
// 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);
};
fetchRepoActivity();
}, [octokit, project]);
return ( return (
<div className="grid grid-cols-5"> <div className="grid grid-cols-5">
<div className="col-span-3 p-2"> <div className="col-span-3 p-2">
@ -86,8 +141,8 @@ const OverviewTabPanel = ({ project }: OverviewProps) => {
</button> </button>
</div> </div>
<div className="p-2"> <div className="p-2">
{activityDetails.map((activity, key) => { {activities.map((activity, index) => {
return <ActivityCard activity={activity} key={key} />; return <ActivityCard activity={activity} key={index} />;
})} })}
</div> </div>
</div> </div>

View File

@ -44,6 +44,21 @@ export interface GitRepositoryDetails {
default_branch?: string; default_branch?: string;
} }
export interface GitBranchDetails {
name: string;
}
export interface GitCommitDetails {
branch: GitBranchDetails;
commit: {
author: {
name?: string;
date?: string;
} | null;
message: string;
};
}
export enum GitSelect { export enum GitSelect {
GITHUB = 'github', GITHUB = 'github',
GITEA = 'gitea', GITEA = 'gitea',

View File

@ -194,15 +194,15 @@ export class GQLClient {
return data; return data;
} }
async addProject (projectDetails: AddProjectInput): Promise<AddProjectResponse> { async addProject (data: AddProjectInput): Promise<AddProjectResponse> {
const { data } = await this.client.mutate({ const result = await this.client.mutate({
mutation: addProject, mutation: addProject,
variables: { variables: {
projectDetails data
} }
}); });
return data; return result.data;
} }
async updateProject (projectId: string, projectDetails: UpdateProjectInput): Promise<UpdateProjectResponse> { async updateProject (projectId: string, projectDetails: UpdateProjectInput): Promise<UpdateProjectResponse> {

View File

@ -43,8 +43,8 @@ mutation ($deploymentId: String!) {
`; `;
export const addProject = gql` export const addProject = gql`
mutation ($projectDetails: AddProjectInput) { mutation ($data: AddProjectInput) {
addProject(projectDetails: $projectDetails) addProject(data: $data)
}`; }`;
export const updateProjectMutation = gql` export const updateProjectMutation = gql`