Newer
Older
import { Component, OnDestroy, OnInit } from '@angular/core';
import { Subject, Subscription } from 'rxjs';
import { LoginModalService } from 'app/core/login/login-modal.service';
import { AccountService } from 'app/core/auth/account.service';
import { Account } from 'app/core/user/account.model';
import { HttpResponse } from '@angular/common/http';
import { ActivatedRoute, Router } from '@angular/router';
import { QueryParam, QueryParamBuilder, QueryParamGroup } from '@ngqp/core';
import { takeUntil } from 'rxjs/operators';
import { IFrequency } from 'app/shared/model/frequency.model';
import { IGitFilesPageDetails, GitFilesPageDetails } from 'app/shared/model/git-files-page-details.model';
import { IGitFilesAggregation } from 'app/shared/model/git-files-aggregation';
import { IGitFiles } from 'app/shared/model/git-files.model';
import { SearchInput } from 'app/shared/model/search-input.model';
import { SearchResultService } from 'app/search/search/search-result.service';
import { MetadataMessageService } from 'app/search/metadata/metadata-message.service';
import { IMetadataSelection } from 'app/search/metadata/metadata-selection.component';
@Component({
selector: 'jhi-search',
templateUrl: './search.component.html',
styleUrls: ['search.scss'],
})
export class SearchComponent implements OnInit, OnDestroy {
private static DEBOUNCE_TIME = 200;
public pageSize = 4;
account: Account | null = null;
authSubscription?: Subscription;
// Stores all search results for the current query.
// Used to locally apply filters for e.g. repository and file format.
// When local filters change, the results are recalculated from this variable.
gitFilesPageDetails?: IGitFilesPageDetails;
gitFilesAggregation?: IGitFilesAggregation;
private filterSelectionSubscription: Subscription = new Subscription();
private selectedRepositories = new Set<string>();
private selectedUniversities = new Set<string>();
private selectedFileFormats = new Set<string>();
public paramGroup: QueryParamGroup;
private componentDestroyed$ = new Subject<void>();
public searchInput: SearchInput;
constructor(
protected searchResultService: SearchResultService,
private accountService: AccountService,
private loginModalService: LoginModalService,
protected activatedRoute: ActivatedRoute,
private router: Router,
private filterSelectionService: MetadataMessageService
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
this.paramGroup = qpb.group({
searchText: qpb.stringParam('q', {
debounceTime: SearchComponent.DEBOUNCE_TIME,
emptyOn: '',
}),
page: qpb.numberParam('page', {
emptyOn: 1,
}),
programmingLanguage: qpb.stringParam('pl', {
debounceTime: SearchComponent.DEBOUNCE_TIME,
emptyOn: '',
}),
keywords: qpb.stringParam('kw', {
debounceTime: SearchComponent.DEBOUNCE_TIME,
emptyOn: '',
}),
author: qpb.stringParam('a', {
debounceTime: SearchComponent.DEBOUNCE_TIME,
emptyOn: '',
}),
license: qpb.stringParam('l', {
debounceTime: SearchComponent.DEBOUNCE_TIME,
emptyOn: '',
}),
});
this.paramGroup.valueChanges.pipe(takeUntil(this.componentDestroyed$)).subscribe(value => {
this.searchInput.setValues(value);
this.search();
});
}
filter(): void {
if (!this.gitFilesPageDetails?.hitCount || this.gitFilesPageDetails.hitCount <= 0) {
return;
}
this.loadPageDetails();
}
search(): void {
if (this.searchInput.fulltextQuery === '') {
this.gitFilesAggregation = undefined;
this.gitFilesPageDetails = undefined;
return;
}
this.loadAggregation();
this.loadPageDetails();
}
ngOnInit(): void {
this.loadAggregation();
this.loadPageDetails();
this.authSubscription = this.accountService.getAuthenticationState().subscribe(account => (this.account = account));
this.filterSelectionSubscription.add(
this.filterSelectionService.filterSelection$.subscribe(selection => this.updateSearchInfoFilter(selection))
}
loadAggregation(): void {
if (this.searchInput.fulltextQuery) {
this.searchResultService
.searchAggregation({
query: this.searchInput.fulltextQuery,
})
.subscribe((res: HttpResponse<IGitFilesAggregation>) => {
this.gitFilesAggregation = res.body || undefined;
});
}
}
loadPageDetails(): void {
if (this.searchInput.fulltextQuery) {
this.searchResultService.searchPageDetails(this.searchInput, this.pageSize).subscribe((res: HttpResponse<IGitFilesPageDetails>) => {
if (res.body === null) {
this.queryResult = new GitFilesPageDetails(res.body.gitFiles, res.body.gitFiles.length);
// Applies local filters to search results
// and sets this.gitFilesPageDetails accordingly.
if (this.queryResult !== undefined) {
const matchingResults = this.queryResult.gitFiles.filter(element => this.matchesSelection(element));
if (matchingResults.length > 0) {
this.gitFilesPageDetails = new GitFilesPageDetails(matchingResults, matchingResults.length);
} else {
this.gitFilesPageDetails = undefined;
}
}
}
// When the user updates the metadata filter selection
// this function is called.
// It updates the local filters.
// Currently, for any category (at the moment repository and file format)
// there is a set of allowed values.
// If the selected item is not in the corresponding set it is added.
// Otherwise it is removed.
// If a set is empty the corresponding filter is not applied.
// For non-empty sets, the results which will be displayed must match one of the set's elements.
// (e.g. if the selectedRepositories set contains "foo" and "bar",
// only results from these two repos will be shown.)
public updateSearchInfoFilter(selection: IMetadataSelection): void {
switch (selection.category) {
case 'repository': {
if (this.selectedRepositories.has(selection.value)) {
this.selectedRepositories.delete(selection.value);
// University seems to be a derived attribute.
// Currently not implemented.
alert('Filtering by university is not supported at the moment. Cause: University is not in the interface IGitFiles.');
/* if (this.selectedUniversities.has(selection.value)) {
this.selectedUniversities.delete(selection.value);
} */
break;
}
case 'fileFormat': {
if (this.selectedFileFormats.has(selection.value)) {
this.selectedFileFormats.delete(selection.value);
// Checks if a given file matches the local filters.
matchesSelection(file: IGitFiles): boolean {
if (this.selectedRepositories.size > 0 && !this.selectedRepositories.has(file.repository)) {
/* if (this.selectedUniversities.size > 0 && !this.selectedUniversities.has(file.university)) {
return false;
} */
if (this.selectedFileFormats.size > 0 && !this.selectedFileFormats.has(file.fileFormat)) {
isAuthenticated(): boolean {
return this.accountService.isAuthenticated();
}
login(): void {
this.loginModalService.open();
}
ngOnDestroy(): void {
if (this.authSubscription) {
this.authSubscription.unsubscribe();
}
if (this.filterSelectionSubscription) {
this.filterSelectionSubscription.unsubscribe();
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
this.componentDestroyed$.next();
this.componentDestroyed$.complete();
}
onClickMe(gitFiles: IGitFiles): void {
window.location.href = gitFiles.gitUrl;
}
public get gitFiles(): IGitFiles[] {
return this.gitFilesPageDetails?.gitFiles || [];
}
public get repos(): IFrequency<string>[] {
return this.gitFilesAggregation?.repositories || [];
}
public get university(): IFrequency<string>[] {
return this.gitFilesAggregation?.university || [];
}
public get fileFormat(): IFrequency<string>[] {
return this.gitFilesAggregation?.fileFormat || [];
}
public get pageParam(): QueryParam<number> {
return this.paramGroup.get('page') as QueryParam<number>;
}
public onPageChange(page: number): void {
this.pageParam.setValue(page);
}
public get hitCount(): number {
const hits = this.gitFilesPageDetails?.hitCount;
return hits ? hits : 0;
}
}