Skip to content

Commit

Permalink
Add Stand alone Conversation Page
Browse files Browse the repository at this point in the history
  • Loading branch information
chidozieononiwu committed Sep 17, 2024
1 parent b33617d commit 181c49e
Show file tree
Hide file tree
Showing 17 changed files with 200 additions and 69 deletions.
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<app-review-page-layout
[review]="review"
[sideMenu]="sideMenu">
<div class="conversation-panel border rounded p-3">
<div class="conversation-panel overflow-auto border rounded py-3">
<app-conversations
[apiRevisions]="apiRevisions"
[comments]="comments"
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { Component } from '@angular/core';
import { ActivatedRoute } from '@angular/router';
import { ActivatedRoute, Router } from '@angular/router';
import { MenuItem } from 'primeng/api';
import { Subject, takeUntil } from 'rxjs';
import { REVIEW_ID_ROUTE_PARAM } from 'src/app/_helpers/common-helpers';
Expand Down Expand Up @@ -30,11 +30,15 @@ export class ConversationPageComponent {
private destroy$ = new Subject<void>();

constructor(private route: ActivatedRoute, private reviewsService: ReviewsService, private userProfileService: UserProfileService,
private apiRevisionsService: RevisionsService, private commentsService: CommentsService
private apiRevisionsService: RevisionsService, private commentsService: CommentsService, private router: Router
) {}

ngOnInit() {
this.userProfileService.getUserProfile().subscribe();
this.userProfileService.getUserProfile().subscribe(
(userProfile : any) => {
this.userProfile = userProfile;
}
);
this.reviewId = this.route.snapshot.paramMap.get(REVIEW_ID_ROUTE_PARAM);
this.createSideMenu();
this.loadReview(this.reviewId!);
Expand All @@ -47,12 +51,12 @@ export class ConversationPageComponent {
{
icon: 'bi bi-braces',
tooltip: 'API',
//command: () => { this.conversationSidePanel = !this.conversationSidePanel; }
command: () => this.openLatestAPIReivisonForReview()
},
{
icon: 'bi bi-clock-history',
tooltip: 'Revisions',
//command: () => { this.revisionSidePanel = !this.revisionSidePanel; }
command: () => this.router.navigate([`/revision/${this.reviewId}`])
}
];
}
Expand All @@ -73,7 +77,7 @@ export class ConversationPageComponent {
next: (response: any) => {
this.apiRevisions = response.result;
}
});
});
}

loadComments() {
Expand All @@ -82,6 +86,11 @@ export class ConversationPageComponent {
next: (comments: CommentItemModel[]) => {
this.comments = comments;
}
});
});
}

openLatestAPIReivisonForReview() {
const apiRevision = this.apiRevisions.find(x => x.apiRevisionType === "Automatic") ?? this.apiRevisions[0];
this.apiRevisionsService.openAPIRevisionPage(apiRevision, this.router.url);
}
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
<p *ngIf="commentThreads.size === 0">This Review has no comments</p>
<p-timeline [value]="getAPIRevisionWithComments()">
<div *ngIf="isLoading" class="spinner-border m-3" role="status">
<span class="visually-hidden">Loading...</span>
</div>
<p *ngIf="!isLoading && (getAPIRevisionWithComments()).length == 0" class="ms-4">This Review has no comments</p>
<p-timeline *ngIf="!isLoading" [value]="getAPIRevisionWithComments()">
<ng-template pTemplate="marker" let-apiRevision>
<i class="bi bi-clock-history"></i>
</ng-template>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,10 @@ export class ConversationsComponent implements OnChanges {
commentThreads: Map<string, CodePanelRowData[]> = new Map<string, CodePanelRowData[]>();
numberOfActiveThreads: number = 0;

apiRevisionsLoaded = false;
commentsLoaded = false;
isLoading: boolean = true;

destroy$ = new Subject<void>();

constructor(private commentsService: CommentsService, private signalRService: SignalRService) { }
Expand All @@ -37,62 +41,76 @@ export class ConversationsComponent implements OnChanges {
}

ngOnChanges(changes: SimpleChanges) {
if (changes['apiRevisions'] || changes['comments']) {
if (this.apiRevisions.length > 0 && this.comments.length > 0) {
this.createCommentThreads();
}
if (changes['apiRevisions']) {
this.apiRevisionsLoaded = true;
}

if (changes['comments']) {
this.commentsLoaded = true;
}

if (this.apiRevisionsLoaded && this.commentsLoaded) {
this.createCommentThreads();
}
}

createCommentThreads() {
this.commentThreads = new Map<string, CodePanelRowData[]>();
this.numberOfActiveThreads = 0;
const apiRevisionInOrder = this.apiRevisions.sort((a, b) => (new Date(b.createdOn) as any) - (new Date(a.createdOn) as any));
const groupedComments = this.comments
.reduce((acc: { [key: string]: CommentItemModel[] }, comment) => {
const key = comment.elementId;
if (!acc[key]) {
acc[key] = [];
}
acc[key].push(comment);
return acc;
}, {});
if (this.apiRevisions.length > 0 && this.comments.length > 0) {
this.commentThreads = new Map<string, CodePanelRowData[]>();
this.numberOfActiveThreads = 0;
const apiRevisionInOrder = this.apiRevisions.sort((a, b) => (new Date(b.createdOn) as any) - (new Date(a.createdOn) as any));
const groupedComments = this.comments
.reduce((acc: { [key: string]: CommentItemModel[] }, comment) => {
const key = comment.elementId;
if (!acc[key]) {
acc[key] = [];
}
acc[key].push(comment);
return acc;
}, {});

for (const elementId in groupedComments) {
if (groupedComments.hasOwnProperty(elementId)) {
const comments = groupedComments[elementId];
const apiRevisionIds = comments.map(c => c.apiRevisionId);
for (const elementId in groupedComments) {
if (groupedComments.hasOwnProperty(elementId)) {
const comments = groupedComments[elementId];
const apiRevisionIds = comments.map(c => c.apiRevisionId);

let apiRevisionPostion = Number.MAX_SAFE_INTEGER;
let apiRevisionPostion = Number.MAX_SAFE_INTEGER;

for (const apiRevisionId of apiRevisionIds) {
const apiRevisionIdPosition = apiRevisionInOrder.findIndex(apiRevision => apiRevision.id === apiRevisionId);
if (apiRevisionIdPosition >= 0 && apiRevisionIdPosition < apiRevisionPostion) {
apiRevisionPostion = apiRevisionIdPosition;
for (const apiRevisionId of apiRevisionIds) {
const apiRevisionIdPosition = apiRevisionInOrder.findIndex(apiRevision => apiRevision.id === apiRevisionId);
if (apiRevisionIdPosition >= 0 && apiRevisionIdPosition < apiRevisionPostion) {
apiRevisionPostion = apiRevisionIdPosition;
}
}
}

if (apiRevisionPostion >= 0 && apiRevisionPostion < apiRevisionInOrder.length) {
const apiRevisionIdForThread = apiRevisionInOrder[apiRevisionPostion].id;
const codePanelRowData = new CodePanelRowData();
codePanelRowData.type = CodePanelRowDatatype.CommentThread;
codePanelRowData.comments = comments;
codePanelRowData.isResolvedCommentThread = comments.some(c => c.isResolved);
if (apiRevisionPostion >= 0 && apiRevisionPostion < apiRevisionInOrder.length) {
const apiRevisionIdForThread = apiRevisionInOrder[apiRevisionPostion].id;
const codePanelRowData = new CodePanelRowData();
codePanelRowData.type = CodePanelRowDatatype.CommentThread;
codePanelRowData.comments = comments;
codePanelRowData.isResolvedCommentThread = comments.some(c => c.isResolved);

if (!codePanelRowData.isResolvedCommentThread) {
this.numberOfActiveThreads++;
}
if (!codePanelRowData.isResolvedCommentThread) {
this.numberOfActiveThreads++;
}

if (this.commentThreads.has(apiRevisionIdForThread)) {
this.commentThreads.get(apiRevisionIdForThread)?.push(codePanelRowData);
}
else {
this.commentThreads.set(apiRevisionIdForThread, [codePanelRowData]);
if (this.commentThreads.has(apiRevisionIdForThread)) {
this.commentThreads.get(apiRevisionIdForThread)?.push(codePanelRowData);
}
else {
this.commentThreads.set(apiRevisionIdForThread, [codePanelRowData]);
}
}
}
}
this.numberOfActiveThreadsEmitter.emit(this.numberOfActiveThreads);
this.isLoading = false;
}
else if (this.apiRevisions.length > 0 && this.comments.length === 0) {
setTimeout(() => {
this.isLoading = false;
}, 1000);
}
this.numberOfActiveThreadsEmitter.emit(this.numberOfActiveThreads);
}

getAPIRevisionWithComments() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -64,19 +64,24 @@
</ng-template>
</p-splitter>
</app-review-page-layout>
<p-sidebar [(visible)]="revisionSidePanel!" position="right" [modal]="true" styleClass="revisions-sidebar">
<p-sidebar [(visible)]="revisionSidePanel!" position="right" [modal]="true" [showCloseIcon]="false" styleClass="revisions-sidebar">
<app-revisions-list
[review]="review"
[revisionSidePanel]="revisionSidePanel!"></app-revisions-list>
[revisionSidePanel]="revisionSidePanel!">
</app-revisions-list>
</p-sidebar>
<p-sidebar [(visible)]="conversationSidePanel!" position="right" [modal]="true" styleClass="conversation-sidebar">
<h4>Conversations</h4>
<p-divider />
<p-sidebar [(visible)]="conversationSidePanel!" position="right" [modal]="true" [showCloseIcon]="false" styleClass="conversation-sidebar">
<ng-template pTemplate="header">
<div class="flex align-items-center gap-2">
<a [routerLink]="['/conversation', this.reviewId]" class="h4">Conversations</a>
</div>
</ng-template>
<app-conversations
[apiRevisions]="apiRevisions"
[comments]="comments"
[review]="review"
[activeApiRevisionId]="activeApiRevisionId"
(scrollToNodeEmitter)="handleScrollToNodeEmitter($event)"
(numberOfActiveThreadsEmitter)="handleNumberOfActiveThreadsEmitter($event)"></app-conversations >
(numberOfActiveThreadsEmitter)="handleNumberOfActiveThreadsEmitter($event)">
</app-conversations >
</p-sidebar>
Original file line number Diff line number Diff line change
Expand Up @@ -498,8 +498,8 @@ export class ReviewPageComponent implements OnInit {
break;
}
}
}

}
ngOnDestroy() {
this.workerService.terminateWorker();
this.destroy$.next();
Expand Down
Original file line number Diff line number Diff line change
@@ -1 +1,10 @@

<app-review-page-layout
[review]="review"
[sideMenu]="sideMenu">
<div class="revisions-panel overflow-auto border rounded">
<app-revisions-list
[review]="review"
(apiRevisionsEmitter)="handleApiRevisionsEmitter($event)">
</app-revisions-list>
</div>
</app-review-page-layout>
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
:host ::ng-deep {
.revision-panel{
height: calc(100vh - 130px);
background-color: var(--base-fg-color);
}
}
Original file line number Diff line number Diff line change
@@ -1,10 +1,64 @@
import { Component } from '@angular/core';
import { ActivatedRoute, Router } from '@angular/router';
import { MenuItem } from 'primeng/api';
import { Subject, takeUntil } from 'rxjs';
import { REVIEW_ID_ROUTE_PARAM } from 'src/app/_helpers/common-helpers';
import { Review } from 'src/app/_models/review';
import { APIRevision } from 'src/app/_models/revision';
import { ReviewsService } from 'src/app/_services/reviews/reviews.service';
import { RevisionsService } from 'src/app/_services/revisions/revisions.service';

@Component({
selector: 'app-revision-page',
templateUrl: './revision-page.component.html',
styleUrls: ['./revision-page.component.scss']
})
export class RevisionPageComponent {
reviewId : string | null = null;
review : Review | undefined = undefined;
sideMenu: MenuItem[] | undefined;
apiRevisions: APIRevision[] = [];

private destroy$ = new Subject<void>();

constructor(private route: ActivatedRoute, private reviewsService: ReviewsService, private apiRevisionsService: RevisionsService, private router: Router) {}

ngOnInit() {
this.reviewId = this.route.snapshot.paramMap.get(REVIEW_ID_ROUTE_PARAM);
this.createSideMenu();
this.loadReview(this.reviewId!);
}

createSideMenu() {
this.sideMenu = [
{
icon: 'bi bi-braces',
tooltip: 'API',
command: () => this.openLatestAPIReivisonForReview()
},
{
icon: 'bi bi-chat-left-dots',
tooltip: 'Conversations',
command: () => this.router.navigate([`/conversation/${this.reviewId}`])
}
];
}

loadReview(reviewId: string) {
this.reviewsService.getReview(reviewId)
.pipe(takeUntil(this.destroy$)).subscribe({
next: (review: Review) => {
this.review = review;
}
});
}

openLatestAPIReivisonForReview() {
const apiRevision = this.apiRevisions.find(x => x.apiRevisionType === "Automatic") ?? this.apiRevisions[0];
this.apiRevisionsService.openAPIRevisionPage(apiRevision, this.router.url);
}

handleApiRevisionsEmitter(apiRevisions: APIRevision[]) {
this.apiRevisions = apiRevisions as APIRevision[];
}
}
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { Component, Input, OnChanges, OnInit, SimpleChanges, ViewChild } from '@angular/core';
import { Component, EventEmitter, Input, OnChanges, OnInit, Output, SimpleChanges, ViewChild } from '@angular/core';
import { FormBuilder, FormGroup, Validators } from '@angular/forms';
import { Router } from '@angular/router';
import { MenuItem, MessageService, SortEvent } from 'primeng/api';
Expand All @@ -23,6 +23,8 @@ export class RevisionsListComponent implements OnInit, OnChanges {
@Input() review : Review | undefined = undefined;
@Input() revisionSidePanel : boolean = false;

@Output() apiRevisionsEmitter : EventEmitter<APIRevision[]> = new EventEmitter<APIRevision[]>();

@ViewChild("revisionCreationFileUpload") revisionCreationFileUpload!: FileUpload;

assetsPath : string = environment.assetsPath;
Expand Down Expand Up @@ -152,7 +154,7 @@ export class RevisionsListComponent implements OnInit, OnChanges {
this.pagination = response.pagination;
this.totalNumberOfRevisions = this.pagination?.totalCount!;
}

this.apiRevisionsEmitter.emit(this.revisions);
this.setCreateRevisionLanguageBasedOnReview();
}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
import { ActivatedRoute } from "@angular/router";
import { SCROLL_TO_NODE_QUERY_PARAM } from "./common-helpers";

export const REVIEW_PAGE_ROUTE_REGEX = "\/[a-z]+?\/[a-zA-Z0-9]+";

export function getQueryParams(route: ActivatedRoute, excludedKeys: string[] = [SCROLL_TO_NODE_QUERY_PARAM]) {
return route.snapshot.queryParamMap.keys.reduce((params: { [key: string]: any; }, key) => {
if (!excludedKeys.includes(key)) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ import { NgModule } from '@angular/core';
import { RouterModule, Routes } from '@angular/router';
import { ConversationPageComponent } from 'src/app/_components/conversation-page/conversation-page.component';
import { ReviewPageLayoutModule } from './shared/review-page-layout.module';
import { SharedAppModule } from './shared/shared-app.module';
import { CommonModule } from '@angular/common';

const routes: Routes = [
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@ import { UiScrollModule } from 'ngx-ui-scroll' ;
import { PageOptionsSectionComponent } from 'src/app/_components/shared/page-options-section/page-options-section.component';
import { ReviewPageOptionsComponent } from 'src/app/_components/review-page-options/review-page-options.component';
import { InputSwitchModule } from 'primeng/inputswitch';
import { SharedAppModule } from './shared/shared-app.module';
import { ReviewPageLayoutModule } from './shared/review-page-layout.module';

const routes: Routes = [
Expand Down
Loading

0 comments on commit 181c49e

Please sign in to comment.