Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add pull requests component #92

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions server/application-server/openapi.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -289,6 +289,18 @@ components:
$ref: "#/components/schemas/PullRequestReview"
repository:
$ref: "#/components/schemas/Repository"
pullRequestLabels:
uniqueItems: true
type: array
items:
$ref: "#/components/schemas/PullRequestLabel"
PullRequestLabel:
type: object
properties:
name:
type: string
color:
type: string
PullRequestReview:
required:
- state
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,20 +4,14 @@
import java.util.HashSet;
import java.util.Set;

import jakarta.persistence.*;
import org.springframework.lang.NonNull;

import de.tum.in.www1.hephaestus.codereview.base.BaseGitServiceEntity;
import de.tum.in.www1.hephaestus.codereview.comment.IssueComment;
import de.tum.in.www1.hephaestus.codereview.pullrequest.review.PullRequestReview;
import de.tum.in.www1.hephaestus.codereview.repository.Repository;
import de.tum.in.www1.hephaestus.codereview.user.User;
import jakarta.persistence.Table;
import jakarta.persistence.CascadeType;
import jakarta.persistence.Entity;
import jakarta.persistence.FetchType;
import jakarta.persistence.JoinColumn;
import jakarta.persistence.ManyToOne;
import jakarta.persistence.OneToMany;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
Expand Down Expand Up @@ -74,6 +68,9 @@ public class PullRequest extends BaseGitServiceEntity {
@ToString.Exclude
private Repository repository;

@ElementCollection
private Set<PullRequestLabel> pullRequestLabels = new HashSet<>();

public void addComment(IssueComment comment) {
comments.add(comment);
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,11 @@
package de.tum.in.www1.hephaestus.codereview.pullrequest;

import java.io.IOException;
import java.util.Collection;
import java.util.HashSet;
import java.util.Set;

import org.kohsuke.github.GHLabel;
import org.kohsuke.github.GHPullRequest;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
Expand All @@ -24,6 +28,7 @@ public PullRequest convert(@NonNull GHPullRequest source) {
pullRequest.setTitle(source.getTitle());
pullRequest.setUrl(source.getHtmlUrl().toString());
pullRequest.setState(state);
pullRequest.setPullRequestLabels(convertLabels(source.getLabels()));
try {
pullRequest.setAdditions(source.getAdditions());
} catch (IOException e) {
Expand Down Expand Up @@ -65,4 +70,14 @@ private IssueState convertState(org.kohsuke.github.GHIssueState state) {
}
}

private Set<PullRequestLabel> convertLabels(Collection<GHLabel> labels) {
Set<PullRequestLabel> pullRequestLabels = new HashSet<>();
for (GHLabel label : labels) {
PullRequestLabel pullRequestLabel = new PullRequestLabel();
pullRequestLabel.setName(label.getName());
pullRequestLabel.setColor(label.getColor());
pullRequestLabels.add(pullRequestLabel);
}
return pullRequestLabels;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
package de.tum.in.www1.hephaestus.codereview.pullrequest;

import jakarta.persistence.Embeddable;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.NonNull;
import lombok.Setter;

@Embeddable
FelixTJDietrich marked this conversation as resolved.
Show resolved Hide resolved
@Getter
@Setter
@NoArgsConstructor
public class PullRequestLabel {
@NonNull
private String name;

@NonNull
private String color;
}
7 changes: 7 additions & 0 deletions webapp/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions webapp/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@
"autoprefixer": "10.4.20",
"class-variance-authority": "0.7.0",
"clsx": "2.1.1",
"dayjs": "^1.11.13",
"lucide-angular": "0.429.0",
"postcss": "8.4.41",
"rxjs": "7.8.1",
Expand Down
37 changes: 37 additions & 0 deletions webapp/src/app/core/IssueCard/issue-card.component.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
<div class="border border-border bg-card rounded-lg p-4 w-72">
<div class="flex justify-between items-center mb-2 text-xs text-gray-500">
<span class="font-bold flex justify-center items-center space-x-1">
@if (state() === 'OPEN') {
<ng-icon [svg]="octGitPullRequest" size="16" class="mr-1 text-github-success-foreground"></ng-icon>
} @else {
<ng-icon [svg]="octGitPullRequestClosed" size="16" class="mr-1 text-github-danger-foreground"></ng-icon>
}

{{ repositoryName() }} #{{ number() }} on {{ createdAt().format('MMM D') }}
</span>
<span class="flex items-center space-x-2">
<span class="text-github-success-foreground font-bold">+{{ additions() }}</span>
<span class="text-github-danger-foreground font-bold">-{{ deletions() }}</span>
</span>
</div>

<div class="flex justify-between font-bold text-sm mb-3 hover:text-github-accent-foreground cursor-pointer" (click)="openIssue()">
{{ title() }}
iam-flo marked this conversation as resolved.
Show resolved Hide resolved
@if (getMostRecentReview(); as review) {
@if (review.state === 'APPROVED') {
<ng-icon [svg]="octCheck" size="16" class="text-github-success-foreground"></ng-icon>
} @else if (review.state === 'DISMISSED') {
<ng-icon [svg]="octX" size="16" class="text-github-danger-foreground"></ng-icon>
} @else if (review.state === 'COMMENTED') {
<ng-icon [svg]="octComment" size="16" class="text-github-muted-foreground"></ng-icon>
} @else {
<ng-icon [svg]="octFileDiff" size="16" class="text-github-danger-foreground"></ng-icon>
}
}
</div>
<div class="flex gap-1 flex-wrap">
@for (label of pullRequestLabels(); track label.name) {
<span class="px-2 py-1 rounded-full text-xs mr-2 text-neutral-100/95" [style.background-color]="label.color">{{ label.name }}</span>
}
</div>
</div>
41 changes: 41 additions & 0 deletions webapp/src/app/core/IssueCard/issue-card.component.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
import { Component, input } from '@angular/core';
import { PullRequest, PullRequestLabel, PullRequestReview } from '@app/core/modules/openapi';
import { NgIcon } from '@ng-icons/core';
import { octCheck, octComment, octFileDiff, octGitPullRequest, octGitPullRequestClosed, octX } from '@ng-icons/octicons';
import { Dayjs } from 'dayjs';
import { NgStyle } from '@angular/common';

@Component({
selector: 'app-issue-card',
templateUrl: './issue-card.component.html',
imports: [NgIcon, NgStyle],
standalone: true
})
export class IssueCardComponent {
title = input.required<string>();
number = input.required<number>();
additions = input.required<number>();
deletions = input.required<number>();
url = input.required<string>();
repositoryName = input.required<string>();
reviews = input.required<Array<PullRequestReview>>();
createdAt = input.required<Dayjs>();
state = input.required<PullRequest.StateEnum>();
pullRequestLabels = input.required<Array<PullRequestLabel>>();
protected readonly octCheck = octCheck;
protected readonly octX = octX;
protected readonly octComment = octComment;
protected readonly octGitPullRequest = octGitPullRequest;
protected readonly octFileDiff = octFileDiff;
protected readonly octGitPullRequestClosed = octGitPullRequestClosed;

getMostRecentReview() {
return this.reviews().reduce((latest, review) => {
return new Date(review.updatedAt || 0) > new Date(latest.updatedAt || 0) ? review : latest;
});
}

openIssue() {
window.open(this.url());
}
}
40 changes: 40 additions & 0 deletions webapp/src/app/core/IssueCard/issue-card.stories.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
import { Meta, StoryObj } from '@storybook/angular';
import { IssueCardComponent } from './issue-card.component';
import dayjs from 'dayjs';

const meta: Meta<IssueCardComponent> = {
title: 'Components/Core/IssueCard',
component: IssueCardComponent,
tags: ['autodocs'] // Auto-generate docs if enabled
};

export default meta;

type Story = StoryObj<IssueCardComponent>;

export const Default: Story = {
args: {
title: 'Add feature X',
number: 12,
additions: 10,
deletions: 5,
url: 'http://example.com',
state: 'OPEN',
repositoryName: 'Artemis',
createdAt: dayjs('Jan 1'),
pullRequestLabels: [
{ name: 'bug', color: 'red' },
{ name: 'enhancement', color: 'green' }
],
reviews: [
{
state: 'APPROVED',
updatedAt: 'Jan 2'
},
{
state: 'CHANGES_REQUESTED',
updatedAt: 'Jan 4'
}
]
}
};
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ model/issue-comment.ts
model/leaderboard-entry.ts
model/models.ts
model/pull-request-dto.ts
model/pull-request-label.ts
model/pull-request-review-comment.ts
model/pull-request-review-dto.ts
model/pull-request-review.ts
Expand Down
1 change: 1 addition & 0 deletions webapp/src/app/core/modules/openapi/model/models.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ export * from './issue-comment-dto';
export * from './leaderboard-entry';
export * from './pull-request';
export * from './pull-request-dto';
export * from './pull-request-label';
export * from './pull-request-review';
export * from './pull-request-review-comment';
export * from './pull-request-review-dto';
Expand Down
18 changes: 18 additions & 0 deletions webapp/src/app/core/modules/openapi/model/pull-request-label.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
/**
* Hephaestus API
* API documentation for the Hephaestus application server.
*
* The version of the OpenAPI document: 0.0.1
* Contact: [email protected]
*
* NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech).
* https://openapi-generator.tech
* Do not edit the class manually.
*/


export interface PullRequestLabel {
name?: string;
FelixTJDietrich marked this conversation as resolved.
Show resolved Hide resolved
color?: string;
}

2 changes: 2 additions & 0 deletions webapp/src/app/core/modules/openapi/model/pull-request.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
* Do not edit the class manually.
*/
import { Repository } from './repository';
import { PullRequestLabel } from './pull-request-label';
import { PullRequestReview } from './pull-request-review';
import { User } from './user';
import { IssueComment } from './issue-comment';
Expand All @@ -35,6 +36,7 @@ export interface PullRequest {
comments?: Set<IssueComment>;
reviews?: Set<PullRequestReview>;
repository?: Repository;
pullRequestLabels?: Set<PullRequestLabel>;
}
export namespace PullRequest {
export type StateEnum = 'CLOSED' | 'OPEN';
Expand Down