Skip to content

Commit

Permalink
Logic to search codeLines
Browse files Browse the repository at this point in the history
  • Loading branch information
chidozieononiwu committed Jan 8, 2025
1 parent e5bc165 commit 01b6637
Show file tree
Hide file tree
Showing 10 changed files with 190 additions and 38 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
/*----Shadows and Glows------------------------------------------*/
--outer-glow: #{tint-color($primary, 80%)};
--shadow-color: rgba(#{$black}, .15);
--shadow-color-primary: 0 0 0 0.15rem #{rgba($primary, 0.5)};
--box-shadow: 0 .5rem 1rem #{rgba($black, .15)};
--box-shadow-sm: 0 .125rem .25rem #{rgba($black, .075)};
--box-shadow-lg: 0 1rem 3rem #{rgba($black, .175)};
Expand Down Expand Up @@ -120,6 +121,7 @@
/*----Shadows and Glows------------------------------------------*/
--outer-glow: #{tint-color($primary-color, 80%)};
--shadow-color: rgba(#{$white}, .15);
--shadow-color-primary: 0 0 0 0.15rem #{rgba($primary-color, 0.5)};
--box-shadow: 0 .5rem 1rem #{rgba($white, .15)};
--box-shadow-sm: 0 .125rem .25rem #{rgba($white, .075)};
--box-shadow-lg: 0 1rem 3rem #{rgba($white, .175)};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
<div *ngIf="isLoading" class="spinner-border m-3" role="status">
<span class="visually-hidden">Loading...</span>
</div>
<div *ngIf="codePanelRowSource;" class="viewport {{languageSafeName!}}" (click)="onCodePanelItemClick($event)">
<div *ngIf="codePanelRowSource;" id="viewport" class="{{languageSafeName!}}" (click)="onCodePanelItemClick($event)">
<p-messages class="sticky-top" *ngIf="showNoDiffInContentMessage()" [(value)]="noDiffInContentMessage" [closable]="false" />
<div *uiScroll="let item of codePanelRowSource; let index = index" class="code-line" [attr.data-node-id]="item.nodeIdHashed"
[attr.data-row-position-in-group]="item.rowPositionInGroup" [attr.data-row-type]="item.type" [ngClass]="getRowClassObject(item)">
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
line-height: 1.5;
display: block;

.viewport {
#viewport {
overflow: auto;
height: calc(100vh - 132px);
will-change: scroll-position, contents;
Expand Down Expand Up @@ -219,6 +219,12 @@
text-decoration: line-through;
}

.codeline-search-match-highlight {
background-color: var(--primary-color);
color: var(--primary-btn-color);
padding: 0px;
margin: 0px;
}

.java {
.javadoc {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
import { ChangeDetectorRef, Component, EventEmitter, Input, OnChanges, Output, SimpleChanges } from '@angular/core';
import { ChangeDetectorRef, Component, ElementRef, EventEmitter, Input, OnChanges, Output, SimpleChanges } from '@angular/core';
import { take, takeUntil } from 'rxjs/operators';
import { Datasource, IDatasource, SizeStrategy } from 'ngx-ui-scroll';
import { CommentsService } from 'src/app/_services/comments/comments.service';
import { getQueryParams } from 'src/app/_helpers/router-helpers';
import { ActivatedRoute, Router } from '@angular/router';
import { CodeLineRowNavigationDirection, isDiffRow } from 'src/app/_helpers/common-helpers';
import { CodeLineRowNavigationDirection, convertRowOfTokensToString, isDiffRow } from 'src/app/_helpers/common-helpers';
import { SCROLL_TO_NODE_QUERY_PARAM } from 'src/app/_helpers/router-helpers';
import { CodePanelData, CodePanelRowData, CodePanelRowDatatype } from 'src/app/_models/codePanelModels';
import { StructuredToken } from 'src/app/_models/structuredToken';
Expand All @@ -15,6 +15,7 @@ import { MessageService } from 'primeng/api';
import { SignalRService } from 'src/app/_services/signal-r/signal-r.service';
import { Subject } from 'rxjs';
import { CommentThreadUpdateAction, CommentUpdatesDto } from 'src/app/_dtos/commentThreadUpdateDto';
import { CodeLineSearchInfo } from 'src/app/_models/codeLineSearchInfo';

@Component({
selector: 'app-code-panel',
Expand All @@ -34,10 +35,11 @@ export class CodePanelComponent implements OnChanges{
@Input() userProfile : UserProfile | undefined;
@Input() showLineNumbers: boolean = true;
@Input() loadFailed : boolean = false;
@Input() reviewSearchText: string | undefined;
@Input() codeLineSearchText: string | undefined;
@Input() codeLineNavigationDirection: number | undefined;

@Output() hasActiveConversationEmitter : EventEmitter<boolean> = new EventEmitter<boolean>();

@Output() codeLineSearchInfoEmitter : EventEmitter<CodeLineSearchInfo> = new EventEmitter<CodeLineSearchInfo>();

noDiffInContentMessage : Message[] = [{ severity: 'info', icon:'bi bi-info-circle', detail: 'There is no difference between the two API revisions.' }];

Expand All @@ -48,13 +50,16 @@ export class CodePanelComponent implements OnChanges{
codePanelRowSource: IDatasource<CodePanelRowData> | undefined;
CodePanelRowDatatype = CodePanelRowDatatype;

searchMatchedRowInfo: Map<string, RegExpMatchArray[]> = new Map<string, RegExpMatchArray[]>();

destroy$ = new Subject<void>();

commentThreadNavaigationPointer: number | undefined = undefined;
diffNodeNavaigationPointer: number | undefined = undefined;

constructor(private changeDetectorRef: ChangeDetectorRef, private commentsService: CommentsService,
private signalRService: SignalRService, private route: ActivatedRoute, private router: Router, private messageService: MessageService) { }
private signalRService: SignalRService, private route: ActivatedRoute, private router: Router,
private messageService: MessageService, private elementRef: ElementRef<HTMLElement>) { }

ngOnInit() {
this.codeWindowHeight = `${window.innerHeight - 80}`;
Expand All @@ -80,8 +85,15 @@ export class CodePanelComponent implements OnChanges{
this.isLoading = false;
}

if (changes['reviewSearchText']) {
this.searchCodePanelRowData(this.reviewSearchText!);
if (changes['codeLineSearchText']) {
this.searchCodePanelRowData(this.codeLineSearchText!);
}

if (changes['codeLineNavigationDirection']) {
this.navigateToCodeLineWithSearchMatch(
changes['codeLineNavigationDirection'].previousValue,
changes['codeLineNavigationDirection'].currentValue
);
}
}

Expand Down Expand Up @@ -625,16 +637,94 @@ export class CodePanelComponent implements OnChanges{
}

private searchCodePanelRowData(searchText: string) {
this.searchMatchedRowInfo.clear();
if (!searchText || searchText.length === 0) {
this.clearSearchMatchHighlights();
return;
}

let totalMatches = 0;
let matchedNodeIds = new Set<string>();
this.codePanelRowData.forEach((row) => {
//if (row.rowOfTokens && row.rowOfTokens.length > 0) {
// let codeLineText = convertRowOfTokensToString(row.rowOfTokens);
// if (row.indent && row.indent > 0) {
// codeLineText = '\t'.repeat(row.indent - 1) + codeLineText;
// }
// reviewText.push(codeLineText);
//}
if (row.rowOfTokens && row.rowOfTokens.length > 0) {
let codeLineInfo = convertRowOfTokensToString(row.rowOfTokens);
const regex = new RegExp(searchText, "gi");
const matches = [...codeLineInfo.matchAll(regex)];
if (matches.length > 0) {
totalMatches += matches.length;
matchedNodeIds.add(row.nodeIdHashed!);
this.searchMatchedRowInfo.set(row.nodeIdHashed!, matches);
}
}
});
this.highlightSearchMatches();
this.codeLineSearchInfoEmitter.emit({
current: 0,
total: totalMatches,
matchedNodeIds: matchedNodeIds
});
}

private highlightSearchMatches() {
this.clearSearchMatchHighlights();
const codeLines = this.elementRef.nativeElement.querySelectorAll('.code-line');

codeLines.forEach((codeLine) => {
const nodeIdhashed = codeLine.getAttribute('data-node-id');
if (nodeIdhashed && this.searchMatchedRowInfo.has(nodeIdhashed)) {
const tokens = codeLine.querySelectorAll('.code-line-content > span');
const matches = this.searchMatchedRowInfo.get(nodeIdhashed)!;

matches.forEach((match) => {
const matchStartIndex = match.index!;
const matchEndIndex = matchStartIndex + match[0].length;

let currentOffset = 0;
tokens.forEach((token) => {
const tokenText = token.textContent || '';
const tokenLength = tokenText.length;

const tokenStart = currentOffset;
const tokenEnd = currentOffset + tokenLength;

if (matchStartIndex < tokenEnd && matchEndIndex > tokenStart) {
const highlightStart = Math.max(0, matchStartIndex - tokenStart);
const highlightEnd = Math.min(tokenLength, matchEndIndex - tokenStart);

const beforeMatch = tokenText.slice(0, highlightStart);
const matchText = tokenText.slice(highlightStart, highlightEnd);
const afterMatch = tokenText.slice(highlightEnd);

token.innerHTML = `${beforeMatch}<mark class="codeline-search-match-highlight">${matchText}</mark>${afterMatch}`;
}

currentOffset += tokenLength;
});
});
}
});
}

/**
* Navigates to the next or previous code line that contains a search match but is outside the viewport
*/
private navigateToCodeLineWithSearchMatch(previousPosition: number, newPosition: number) {
if (newPosition > previousPosition) {
// Find the next code line that contains a search match but is below the visible viewport
return;
} else if (newPosition < previousPosition) {
// Find the previous code line that contains a search match but is above the visible viewport
return;
}
}

private clearSearchMatchHighlights() {
this.elementRef.nativeElement.querySelectorAll('.codeline-search-match-highlight').forEach((element) => {
const parent = element.parentNode as HTMLElement;
if (parent) {
parent.innerHTML = parent.textContent || '';
}
});
console.log('searchText', searchText);
}

private findNextCommentThread (index: number) : CodePanelRowData | undefined {
Expand Down Expand Up @@ -706,15 +796,22 @@ export class CodePanelComponent implements OnChanges{
this.hasActiveConversationEmitter.emit(hasActiveConversation);
}

private loadCodePanelViewPort() {
private loadCodePanelViewPort() {
this.setMaxLineNumberWidth();
this.initializeDataSource().then(() => {
this.codePanelRowSource?.adapter?.init$.pipe(take(1)).subscribe(() => {
this.isLoading = false;
setTimeout(() => {
this.scrollToNode(undefined, this.scrollToNodeId);
const viewport = this.elementRef.nativeElement.ownerDocument.getElementById('viewport');
if (viewport) {
viewport.addEventListener('scroll', (event) => {
if (this.codeLineSearchText && this.codeLineSearchText.length > 0) {
this.highlightSearchMatches();
}
});
}
}, 500);

});
}).catch((error) => {
console.error(error);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -72,13 +72,13 @@
<li class="list-group-item">
<p-iconField iconPosition="left" class="w-full">
<p-inputIcon styleClass="pi pi-search" />
<input type="text" [formControl]="reviewSearchText" pInputText placeholder="Search Review" style="width: 100%; box-sizing: border-box;"/>
<input type="text" [formControl]="codeLineSearchText" pInputText placeholder="Search Review" style="width: 100%; box-sizing: border-box;"/>
</p-iconField>
<div *ngIf="reviewSearchText.value.length > 0" class="d-flex justify-content-between">
<small class="review-search-info">{{ reviewSearchInfoCurrent }} of {{ reviewSearchInfoTotal }}</small>
<div *ngIf="codeLineSearchText.value.length > 0" class="d-flex justify-content-between">
<small class="review-search-info">{{ codeLineSearchInfo.current }} of {{ codeLineSearchInfo.total }}</small>
<span class="mt-2">
<i class="bi bi-arrow-up-short border rounded-start review-search-icon"></i>
<i class="bi bi-arrow-down-short border review-search-icon"></i>
<i class="bi bi-arrow-up-short border rounded-start review-search-icon" (click)="navigateSearch(-1)"></i>
<i class="bi bi-arrow-down-short border review-search-icon" (click)="navigateSearch(1)"></i>
<i class="bi bi-x border rounded-end review-search-icon" (click)="clearReviewSearch()"></i>
</span>
</div>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import { UserProfile } from 'src/app/_models/userProfile';
import { PullRequestsService } from 'src/app/_services/pull-requests/pull-requests.service';
import { PullRequestModel } from 'src/app/_models/pullRequestModel';
import { FormControl } from '@angular/forms';
import { CodeLineSearchInfo } from 'src/app/_models/codeLineSearchInfo';

@Component({
selector: 'app-review-page-options',
Expand All @@ -31,7 +32,8 @@ export class ReviewPageOptionsComponent implements OnInit, OnChanges{
@Input() hasActiveConversation : boolean = false;
@Input() hasHiddenAPIs : boolean = false;
@Input() hasHiddenAPIThatIsDiff : boolean = false;

@Input() codeLineSearchInfo : CodeLineSearchInfo = new CodeLineSearchInfo();

@Output() diffStyleEmitter : EventEmitter<string> = new EventEmitter<string>();
@Output() showCommentsEmitter : EventEmitter<boolean> = new EventEmitter<boolean>();
@Output() showSystemCommentsEmitter : EventEmitter<boolean> = new EventEmitter<boolean>();
Expand All @@ -46,7 +48,8 @@ export class ReviewPageOptionsComponent implements OnInit, OnChanges{
@Output() reviewApprovalEmitter : EventEmitter<boolean> = new EventEmitter<boolean>();
@Output() commentThreadNavaigationEmitter : EventEmitter<CodeLineRowNavigationDirection> = new EventEmitter<CodeLineRowNavigationDirection>();
@Output() diffNavaigationEmitter : EventEmitter<CodeLineRowNavigationDirection> = new EventEmitter<CodeLineRowNavigationDirection>();
@Output() reviewSearchTextEmitter : EventEmitter<string> = new EventEmitter<string>();
@Output() codeLineSearchTextEmitter : EventEmitter<string> = new EventEmitter<string>();
@Output() codeLineSearchNaviationEmmiter : EventEmitter<number> = new EventEmitter<number>();

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

Expand Down Expand Up @@ -76,14 +79,14 @@ export class ReviewPageOptionsComponent implements OnInit, OnChanges{
reviewIsApproved: boolean | undefined = undefined;
reviewApprover: string = 'azure-sdk';

reviewSearchText: FormControl = new FormControl('');
reviewSearchInfoCurrent: number = 0;
reviewSearchInfoTotal: number = 0;
codeLineSearchText: FormControl = new FormControl('');

associatedPullRequests : PullRequestModel[] = [];
pullRequestsOfAssociatedAPIRevisions : PullRequestModel[] = [];
CodeLineRowNavigationDirection = CodeLineRowNavigationDirection;

codeLineSearchNavigationPosition : number = 0;

//Approvers Options
selectedApprovers: string[] = [];

Expand Down Expand Up @@ -116,12 +119,12 @@ export class ReviewPageOptionsComponent implements OnInit, OnChanges{
this.setAPIRevisionApprovalStates();
this.setReviewApprovalStatus();

this.reviewSearchText.valueChanges.pipe(
this.codeLineSearchText.valueChanges.pipe(
debounceTime(500),
distinctUntilChanged(),
takeUntil(this.destroy$)
).subscribe((searchText: string) => {
this.reviewSearchTextEmitter.emit(searchText);
this.codeLineSearchTextEmitter.emit(searchText);
});
}

Expand Down Expand Up @@ -333,7 +336,20 @@ export class ReviewPageOptionsComponent implements OnInit, OnChanges{
}

clearReviewSearch() {
this.reviewSearchText.setValue('');
this.codeLineSearchText.setValue('');
}

navigateCommentThread(direction: CodeLineRowNavigationDirection) {
this.commentThreadNavaigationEmitter.emit(direction);
}

/**
* Use positive number to navigate to the next search result and negative number to navigate to the previous search result
* @param number
*/
navigateSearch(number: number) {
this.codeLineSearchNavigationPosition += number;
this.codeLineSearchNaviationEmmiter.emit(this.codeLineSearchNavigationPosition);
}

handleAPIRevisionApprovalAction() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,8 +29,10 @@
[loadFailed]="loadFailed"
[showLineNumbers]="showLineNumbers" [scrollToNodeIdHashed]="scrollToNodeIdHashed"
[scrollToNodeId]="scrollToNodeId"
[reviewSearchText]="reviewSearchText"
(hasActiveConversationEmitter)="handleHasActiveConversationEmitter($event)"></app-code-panel>
[codeLineSearchText]="codeLineSearchText"
[codeLineNavigationDirection]="codeLineNavigationDirection"
(hasActiveConversationEmitter)="handleHasActiveConversationEmitter($event)"
(codeLineSearchInfoEmitter)="handleCodeLineSearchInfoEmitter($event)"></app-code-panel>
</div>
</ng-template>
<ng-template pTemplate>
Expand All @@ -47,6 +49,7 @@
[hasFatalDiagnostics]="hasFatalDiagnostics"
[hasActiveConversation]="hasActiveConversation"
[hasHiddenAPIs]="hasHiddenAPIs"
[codeLineSearchInfo]="codeLineSearchInfo"
(showSystemCommentsEmitter)="handleShowSystemCommentsEmitter($event)"
(showDocumentationEmitter)="handleShowDocumentationEmitter($event)"
(showCommentsEmitter)="handleShowCommentsEmitter($event)"
Expand All @@ -61,7 +64,8 @@
(disableCodeLinesLazyLoadingEmitter)="handleDisableCodeLinesLazyLoadingEmitter($event)"
(commentThreadNavaigationEmitter)="handleCommentThreadNavaigationEmitter($event)"
(diffNavaigationEmitter)="handleDiffNavaigationEmitter($event)"
(reviewSearchTextEmitter)="handleReviewSearchTextEmitter($event)"></app-review-page-options>
(codeLineSearchTextEmitter)="handleCodeLineSearchTextEmitter($event)"
(codeLineSearchNaviationEmmiter)="handleCodeLineSearchNaviationEmmiter($event)"></app-review-page-options>
</div>
</ng-template>
</p-splitter>
Expand Down
Loading

0 comments on commit 01b6637

Please sign in to comment.