import { Component, OnInit, OnDestroy } from '@angular/core'; import { HttpHeaders, HttpResponse } from '@angular/common/http'; import { ActivatedRoute } from '@angular/router'; import { Subscription } from 'rxjs'; import { JhiEventManager, JhiParseLinks } from 'ng-jhipster'; import { NgbModal } from '@ng-bootstrap/ng-bootstrap'; import { IUserWatchList } from 'app/shared/model/user-watch-list.model'; import { Exercise, searchResultToExercise } from 'app/shared/model/exercise.model'; import { ITEMS_PER_PAGE } from 'app/shared/constants/pagination.constants'; import { UserWatchListService } from 'app/entities/user-watch-list/user-watch-list.service'; import { BookmarksDeleteDialogComponent } from './bookmarks-delete-dialog.component'; import { SearchResultsDTO } from 'app/shared/model/search/search-results-dto.model'; import { SearchResultDTO, PluginActionInfo, equalPluginActionInfo } from 'app/shared/model/search/search-result-dto.model'; import { WatchlistManager } from 'app/shared/watchlist/watchlist-manager'; import { ShoppingBasketInfo, ShoppingBasketRedirectInfoDTO } from 'app/shared/model/basket/shopping-basket-info.model'; import { PluginService } from 'app/shared/service/plugin-service'; import * as lodash from 'lodash'; @Component({ selector: 'jhi-bookmarks', styleUrls: ['./bookmarks.component.scss'], templateUrl: './bookmarks.component.html', }) export class BookmarkComponent implements OnInit, OnDestroy { userWatchLists: IUserWatchList[]; selectedWatchList?: IUserWatchList; eventSubscriber?: Subscription; itemsPerPage: number; links: any; page: number; allLoaded = false; predicate: string; ascending: boolean; currentSearch: string; results: Exercise[] = []; selectedResult?: Exercise; hitCount = 0; constructor( protected userWatchListService: UserWatchListService, protected eventManager: JhiEventManager, protected modalService: NgbModal, protected parseLinks: JhiParseLinks, protected activatedRoute: ActivatedRoute, protected watchlistManager: WatchlistManager, protected pluginService: PluginService ) { this.userWatchLists = []; this.itemsPerPage = ITEMS_PER_PAGE; this.page = 0; this.allLoaded = false; this.links = { last: 0, }; this.predicate = 'id'; this.ascending = true; this.currentSearch = this.activatedRoute.snapshot && this.activatedRoute.snapshot.queryParams['search'] ? this.activatedRoute.snapshot.queryParams['search'] : ''; } loadAll(): void { if (this.currentSearch) { this.userWatchListService .searchForCurrentUser({ query: this.currentSearch, page: this.page, size: this.itemsPerPage, sort: this.sort(), }) .subscribe((res: HttpResponse<IUserWatchList[]>) => { this.paginateUserWatchLists(res.body, res.headers); }); return; } this.userWatchListService .findMyWatchlists({ page: this.page, size: this.itemsPerPage, sort: this.sort(), }) .subscribe((res: HttpResponse<IUserWatchList[]>) => { this.paginateUserWatchLists(res.body, res.headers); if (!this.loadCurrent()) { // should reset also current watchlist } }); } private loadCurrent(): boolean { let found = false; if (this.watchlistManager.getCurrentWatchList()) { this.userWatchLists.every(uwl => { if (this.isSelected(uwl)) { this.view(uwl); found = true; return false; } return true; }); } else { // currently no default yet selected if (this.userWatchLists && this.userWatchLists.length > 0) { this.watchlistManager.setCurrentWatchList(this.userWatchLists[0].name!); this.view(this.userWatchLists[0]); found = true; return false; } } return found; } reset(): void { this.page = 0; this.allLoaded = false; this.userWatchLists = []; this.loadAll(); } loadPage(page: number): void { this.page = page; this.loadAll(); } selectExercise(exercise: Exercise): void { this.selectedResult = exercise; } search(query: string): void { this.userWatchLists = []; this.links = { last: 0, }; this.page = 0; if (query) { this.predicate = '_score'; this.ascending = false; } else { this.predicate = 'id'; this.ascending = true; } this.currentSearch = query; this.loadAll(); } ngOnInit(): void { this.loadAll(); this.registerChangeInUserWatchLists(); } ngOnDestroy(): void { if (this.eventSubscriber) { this.eventManager.destroy(this.eventSubscriber); } } trackId(index: number, item: IUserWatchList): number { // eslint-disable-next-line @typescript-eslint/no-unnecessary-type-assertion return item.id!; } registerChangeInUserWatchLists(): void { this.eventSubscriber = this.eventManager.subscribe('userWatchListListModification', () => this.reset()); } private parseSearchResultsDTO(searchResultsDTO: SearchResultsDTO): Exercise[] { this.hitCount = searchResultsDTO.hitCount; // fix string to date conversion: unfortunatelly dates are not converted correctly :-() searchResultsDTO.searchResult.forEach(hit => { // eslint-disable-next-line @typescript-eslint/camelcase hit.project.last_activity_at = new Date(hit.project.last_activity_at); // eslint-disable-next-line @typescript-eslint/camelcase hit.file.indexing_date = new Date(hit.file.indexing_date); }); return searchResultsDTO.searchResult.map(searchResultToExercise); } delete(userWatchList: IUserWatchList): void { const modalRef = this.modalService.open(BookmarksDeleteDialogComponent, { size: 'lg', backdrop: 'static' }); modalRef.componentInstance.userWatchList = userWatchList; } sort(): string[] { const result = [this.predicate + ',' + (this.ascending ? 'asc' : 'desc')]; if (this.predicate !== 'id') { result.push('id'); } return result; } view(userWatchList: IUserWatchList): void { this.hitCount = 0; this.page = 0; this.allLoaded = false; this.results = []; this.selectedWatchList = userWatchList; this.watchlistManager.setCurrentWatchList(userWatchList.name!); this.onScroll(); } onScroll(): void { if (this.selectedWatchList) { if (!this.allLoaded) { this.userWatchListService.findExercises(this.selectedWatchList, this.page).subscribe( (data: SearchResultsDTO) => { const searchResults = this.parseSearchResultsDTO(data); if (data.pageStartIndex + searchResults.length < this.results.length) { // we are replacing already existing results inside the array for (let i = 0; i < searchResults.length; i++) { this.results[data.pageStartIndex + i] = searchResults[i]; } } else { const diff = data.pageStartIndex - this.results.length; if (diff > 0) { // overlap with current results, throw away current result this.results = this.results.slice(0, data.pageStartIndex - 1); } else if (diff < 0) { alert('reload of exercises failed!'); // fill up results for (let i = 0; i < -diff; i++) { // fill up array with empty content } } this.results = this.results.concat(searchResults); if (data.hitCount <= this.results.length) { this.allLoaded = true; } } ++this.page; // TODO this may result in a race condition, if requests are not returned in sequence :-() }, () => alert('Search failed') ); } } } isSelected(userWatchList: IUserWatchList) { return ( this.watchlistManager.getCurrentWatchList() && userWatchList.id === this.watchlistManager.getCurrentWatchList()!.userWatchList.id ); } protected paginateUserWatchLists(data: IUserWatchList[] | null, headers: HttpHeaders): void { const headersLink = headers.get('link'); this.links = this.parseLinks.parse(headersLink ? headersLink : ''); if (data) { for (let i = 0; i < data.length; i++) { this.userWatchLists.push(data[i]); } } } getCommonActions(): PluginActionInfo[] { const result = lodash .chain(this.results) .map(function (ex: Exercise) { return ex.originalResult.supportedActions; }) .flatten() .uniqWith(equalPluginActionInfo); return result.value(); } startAction(action: PluginActionInfo): void { const selectedExercises = lodash .chain(this.results) .map(function (ex: Exercise) { return ex.originalResult; }) .filter(function (sr: SearchResultDTO) { return sr.supportedActions.some(function (a: PluginActionInfo) { return equalPluginActionInfo(a, action); }); }); const basketInfo: ShoppingBasketInfo = { plugin: action.plugin, action: action.action, itemInfos: selectedExercises.value(), }; this.pluginService.getRedirectLink(basketInfo).subscribe( (redirectInfo: ShoppingBasketRedirectInfoDTO) => { // alert('redirecting to ' + redirectInfo.redirectURL); // location.href = redirectInfo.redirectURL; window.open(redirectInfo.redirectURL, action.action); }, () => alert('Search failed') ); } }