This is the codeAbility Sharing Platform! Learn more about the codeAbility Sharing Platform.

Skip to content
Snippets Groups Projects
  • Daniel Rainer's avatar
    Update frontend to somewhat work with metadata v0.4 · 6652a5f8
    Daniel Rainer authored
    This accepts data from the updated backend
    (from the previous commit) but does not display
    any of the new metadata yet.
    
    This is not tested with search results, because I could
    not obtain search results locally. Suggestions on the
    home page work, but no results are shown in /search
    6652a5f8
bookmarks.component.ts 9.44 KiB
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')
    );
  }
}