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

Skip to content
Snippets Groups Projects

Compare revisions

Changes are shown as if the source revision was being merged into the target revision. Learn more about comparing revisions.

Source

Select target project
No results found

Target

Select target project
  • development/sharing/codeability-sharing-platform
1 result
Show changes
Showing
with 247 additions and 205 deletions
export const ASC = 'asc';
export const DESC = 'desc';
export const SORT = 'sort';
export const ITEM_DELETED_EVENT = 'deleted';
export const DEFAULT_SORT_DATA = 'defaultSort';
......@@ -30,10 +30,10 @@ export class DataUtils {
openFile(data: string, contentType: string | null | undefined): void {
contentType = contentType ?? '';
const byteCharacters = atob(data);
const byteCharacters = Buffer.from(data, 'base64');
const byteNumbers = new Array(byteCharacters.length);
for (let i = 0; i < byteCharacters.length; i++) {
byteNumbers[i] = byteCharacters.charCodeAt(i);
byteNumbers[i] = byteCharacters.at(i);
}
const byteArray = new Uint8Array(byteNumbers);
const blob = new Blob([byteArray], {
......
......@@ -24,16 +24,16 @@ export class MyRenderer extends MarkedRenderer {
if (href && href.startsWith('uploads')) {
const http = new HttpClient(new HttpXhrBackend({ build: () => new XMLHttpRequest() }));
const resp = this.getAttachmentURL(href, http);
resp.subscribe(
url => {
resp.subscribe({
next: url => {
const srcQuery = '[src="' + href + '"]';
const elem = window.document.querySelectorAll(srcQuery);
if (elem) elem.forEach(node => node.setAttribute('src', url));
},
e => {
error: e => {
alert(e);
}
);
},
});
const out = '<image src="' + href + '" alt="image"/>'; // warning: the output goes through a HTML
// Sanitizer, which eliminates
......
......@@ -68,15 +68,15 @@ export class PagesMarkDownViewerComponent implements OnInit, OnChanges, OnDestro
private reloadContent(): void {
const lang = this.translateService.currentLang;
if (this.path)
this.pagesService.getPage(lang + this.path).subscribe(
pageContent => {
this.pagesService.getPage(lang + this.path).subscribe({
next: pageContent => {
this.page = pageContent;
},
e => {
error: e => {
this.page.content = 'Die Seite ' + this.path + ' konnte nicht geladen werden.';
console.error(`Page ${this.path} not loaded: ${e.message as string}`);
}
);
},
});
}
/** helper function for special latex rendering with katex */
......@@ -115,7 +115,7 @@ export class PagesMarkDownViewerComponent implements OnInit, OnChanges, OnDestro
if (e.target && (e.target as any).tagName === 'A') {
const el = e.target as HTMLElement;
const linkURL = el.getAttribute && el.getAttribute('href');
if (linkURL && linkURL.startsWith('/pages')) {
if (linkURL?.startsWith('/pages')) {
e.preventDefault();
this.router.navigate([linkURL]);
}
......
......@@ -9,7 +9,7 @@ import { ReviewsComponent } from './reviews/reviews.component';
{
path: 'saved-searches',
data: { pageTitle: 'gitsearchApp.savedSearches.home.title' },
loadChildren: () => import('./saved-searches/saved-searches.module').then(m => m.GitsearchSavedSearchesModule),
loadChildren: () => import('./saved-searches/saved-searches.module').then(m => m.SavedSearchesModule),
},
{
path: 'statistics',
......
......@@ -65,10 +65,10 @@ export class LikesUpdateComponent implements OnInit {
}
protected subscribeToSaveResponse(result: Observable<HttpResponse<ILikes>>): void {
result.subscribe(
() => this.onSaveSuccess(),
() => this.onSaveError()
);
result.subscribe({
next: () => this.onSaveSuccess(),
error: () => this.onSaveError(),
});
}
protected onSaveSuccess(): void {
......
......@@ -2,7 +2,7 @@ import { Injectable } from '@angular/core';
import { HttpResponse } from '@angular/common/http';
import { Resolve, ActivatedRouteSnapshot, Routes, Router } from '@angular/router';
import { Observable, of, EMPTY } from 'rxjs';
import { flatMap } from 'rxjs/operators';
import { mergeMap } from 'rxjs/operators';
import { Authority } from 'app/app.constants';
import { UserRouteAccessService } from 'app/core/auth/user-route-access.service';
......@@ -20,7 +20,7 @@ export class LikesResolve implements Resolve<ILikes> {
const id = route.params['id'];
if (id) {
return this.service.find(id).pipe(
flatMap((likes: HttpResponse<Likes>) => {
mergeMap((likes: HttpResponse<Likes>) => {
if (likes.body) {
return of(likes.body);
} else {
......
......@@ -9,7 +9,6 @@ import { SearchService } from 'app/search/service/search-service';
@Component({
selector: 'jhi-review-ratings',
templateUrl: './review-ratings.component.html',
styleUrls: ['./review-ratings.component.scss'],
})
export class ReviewRatingsComponent implements OnInit {
reviewRatings: ReviewRating[] = [];
......
......@@ -9,22 +9,20 @@ import { User } from 'app/admin/user-management/user-management.model';
import { Account } from 'app/core/auth/account.model';
import { AccountService } from 'app/core/auth/account.service';
import { SearchService } from 'app/search/service/search-service';
import { Exercise, searchResultToExercise } from 'app/shared/model/exercise.model';
import { SearchResultDTO } from 'app/shared/model/search/search-result-dto.model';
@Component({
selector: 'jhi-reviews',
templateUrl: './reviews.component.html',
styleUrls: ['./reviews.component.scss'],
})
export class ReviewsComponent implements OnInit, OnChanges {
currentAccount: Account | null = null;
users: User[] | undefined;
results: Exercise[] = [];
results: SearchResultDTO[] = [];
selectedUsers: string[] | undefined;
selectedExercise: Exercise | undefined;
selectedExercise: SearchResultDTO | undefined;
reviews: Review[] = [];
selectedReview = new Review('', [''], [''], ['']);
selectedReview = new Review('', [''], [''], []);
constructor(
private userService: UserManagementService,
......@@ -50,15 +48,14 @@ export class ReviewsComponent implements OnInit, OnChanges {
this.userService.loadAll().subscribe(users => {
this.users = users;
});
this.searchService.getAllResources().subscribe(
(data: SearchResultDTO[]) => {
const searchResults = data.map(searchResultToExercise);
this.searchService.getAllResources().subscribe({
next: (data: SearchResultDTO[]) => {
this.results = this.results
.concat(searchResults)
.filter((value, index, self) => self.findIndex(t => t.title === value.title) === index);
.concat(data)
.filter((value, index, self) => self.findIndex(t => t.metadata.title === value.metadata.title) === index);
},
() => (this.results = [])
);
error: () => (this.results = []),
});
this.reviewManagementService.getAllWithStatistics().subscribe(reviews => {
this.reviews = reviews;
});
......@@ -67,43 +64,45 @@ export class ReviewsComponent implements OnInit, OnChanges {
shareCheckedUserList(users: string[]) {
this.selectedUsers = users;
}
shareExercise(exercise: Exercise) {
shareExercise(exercise: SearchResultDTO) {
this.selectedExercise = exercise;
}
submitReview() {
const res = this.selectedUsers!.filter(o => this.selectedExercise?.contributor?.some(x => x.email == o));
const res = this.selectedUsers!.filter(o => this.selectedExercise?.metadata.contributor?.some(x => x.email == o));
if (res.length > 0) {
alert('The selected users: ' + res.toString() + ' ,are already contributors of this exercise. Please select other users.');
return;
}
const res2 = this.selectedUsers!.filter(o => this.selectedExercise?.creator.some(x => x.email == o));
const res2 = this.selectedUsers!.filter(o => this.selectedExercise?.metadata.creator.some(x => x.email == o));
if (res2.length > 0) {
alert('The selected users: ' + res2.toString() + ' ,are already creators of this exercise. Please select other users.');
return;
}
const res3 = this.selectedUsers!.filter(o => this.selectedExercise?.publisher.some(x => x.email == o));
const res3 = this.selectedUsers!.filter(o => this.selectedExercise?.metadata.publisher.some(x => x.email == o));
if (res3.length > 0) {
alert('The selected users: ' + res3.toString() + ' ,are already publisher of this exercise. Please select other users.');
return;
}
if (this.reviews.filter(e => e.resource == this.selectedExercise?.title).length > 0) {
alert('The selected exercise: ' + this.selectedExercise!.title + ' ,is already in the database. Please select other exercise.');
if (this.reviews.filter(e => e.resource == this.selectedExercise?.metadata.title).length > 0) {
alert(
'The selected exercise: ' + this.selectedExercise!.metadata.title + ' ,is already in the database. Please select other exercise.'
);
return;
}
this.reviewManagementService
.create(
new ReviewRequest(
this.selectedExercise!.title,
this.selectedExercise!.originalResult.exerciseId,
this.selectedExercise!.metadata.title,
this.selectedExercise!.exerciseId,
this.selectedUsers!,
this.selectedExercise!.gitlabURL
this.selectedExercise!.project.url
)
)
.subscribe(() => {
......
......@@ -2,18 +2,17 @@
<div class="modal-header">
<h4 class="modal-title" data-cy="savedSearchesDeleteDialogHeading" jhiTranslate="entity.delete.title">Confirm delete operation</h4>
<button type="button" class="close" data-dismiss="modal" aria-hidden="true" (click)="cancel()">&times;</button>
<button type="button" class="btn-close" data-dismiss="modal" aria-hidden="true" (click)="cancel()">&times;</button>
</div>
<div class="modal-body">
<jhi-alert-error></jhi-alert-error>
<p
id="jhi-delete-savedSearches-heading"
jhiTranslate="gitsearchApp.savedSearches.delete.question"
[translateValues]="{ id: savedSearches.id }"
>
Are you sure you want to delete this Saved Searches?
Are you sure you want to delete Saved Searches {{ savedSearches.id }}?
</p>
</div>
......
......@@ -3,6 +3,7 @@ import { NgbActiveModal } from '@ng-bootstrap/ng-bootstrap';
import { ISavedSearches } from '../saved-searches.model';
import { SavedSearchesService } from '../service/saved-searches.service';
import { ITEM_DELETED_EVENT } from 'app/config/navigation.constants';
@Component({
templateUrl: './saved-searches-delete-dialog.component.html',
......@@ -18,7 +19,7 @@ export class SavedSearchesDeleteDialogComponent {
confirmDelete(id: number): void {
this.savedSearchesService.delete(id).subscribe(() => {
this.activeModal.close('deleted');
this.activeModal.close(ITEM_DELETED_EVENT);
});
}
}
<div class="row justify-content-center">
<div class="d-flex justify-content-center">
<div class="col-8">
<div *ngIf="savedSearches">
<h2 data-cy="savedSearchesDetailsHeading"><span jhiTranslate="gitsearchApp.savedSearches.detail.title">Saved Searches</span></h2>
......
......@@ -3,9 +3,9 @@
<span jhiTranslate="gitsearchApp.savedSearches.home.title">Saved Searches</span>
<div class="d-flex justify-content-end">
<button class="btn btn-info mr-2" (click)="reset()" [disabled]="isLoading">
<button class="btn btn-info me-2" (click)="load()" [disabled]="isLoading">
<fa-icon icon="sync" [spin]="isLoading"></fa-icon>
<span jhiTranslate="gitsearchApp.savedSearches.home.refreshListLabel">Refresh List</span>
<span jhiTranslate="gitsearchApp.savedSearches.home.refreshListLabel">Refresh list</span>
</button>
<button
......@@ -15,7 +15,7 @@
[routerLink]="['/saved-searches/new']"
>
<fa-icon icon="plus"></fa-icon>
<span class="hidden-sm-down" jhiTranslate="gitsearchApp.savedSearches.home.createLabel"> Create a new Saved Searches </span>
<span jhiTranslate="gitsearchApp.savedSearches.home.createLabel"> Create a new Saved Searches </span>
</button>
</div>
</h2>
......@@ -24,54 +24,47 @@
<jhi-alert></jhi-alert>
<div class="row">
<div class="col-sm-12">
<form name="searchForm" class="form-inline">
<div class="input-group w-100 mt-3">
<input
type="text"
class="form-control"
[(ngModel)]="currentSearch"
id="currentSearch"
name="currentSearch"
placeholder="{{ 'gitsearchApp.savedSearches.home.search' | translate }}"
/>
<button class="input-group-append btn btn-info" (click)="search(currentSearch)">
<fa-icon icon="search"></fa-icon>
</button>
<button class="input-group-append btn btn-danger" (click)="search('')" *ngIf="currentSearch">
<fa-icon icon="trash-alt"></fa-icon>
</button>
</div>
</form>
</div>
</div>
<div class="alert alert-warning" id="no-result" *ngIf="savedSearches?.length === 0">
<span jhiTranslate="gitsearchApp.savedSearches.home.notFound">No savedSearches found</span>
<span jhiTranslate="gitsearchApp.savedSearches.home.notFound">No Saved Searches found</span>
</div>
<div class="table-responsive" id="entities" *ngIf="savedSearches && savedSearches.length > 0">
<div class="table-responsive table-entities" id="entities" *ngIf="savedSearches && savedSearches.length > 0">
<table class="table table-striped" aria-describedby="page-heading">
<thead>
<tr jhiSort [(predicate)]="predicate" [(ascending)]="ascending" (sortChange)="reset()">
<th scope="col" jhiSortBy="id"><span jhiTranslate="global.field.id">ID</span> <fa-icon icon="sort"></fa-icon></th>
<tr jhiSort [(predicate)]="predicate" [(ascending)]="ascending" (sortChange)="navigateToWithComponentValues()">
<th scope="col" jhiSortBy="id">
<div class="d-flex">
<span jhiTranslate="global.field.id">ID</span>
<fa-icon class="p-1" icon="sort"></fa-icon>
</div>
</th>
<th scope="col" jhiSortBy="name">
<span jhiTranslate="gitsearchApp.savedSearches.name">Name</span> <fa-icon *ngIf="!currentSearch" icon="sort"></fa-icon>
<div class="d-flex">
<span jhiTranslate="gitsearchApp.savedSearches.name">Name</span>
<fa-icon class="p-1" icon="sort"></fa-icon>
</div>
</th>
<th scope="col" jhiSortBy="jsonQuery">
<span jhiTranslate="gitsearchApp.savedSearches.jsonQuery">Json Query</span>
<fa-icon *ngIf="!currentSearch" icon="sort"></fa-icon>
<div class="d-flex">
<span jhiTranslate="gitsearchApp.savedSearches.jsonQuery">Json Query</span>
<fa-icon class="p-1" icon="sort"></fa-icon>
</div>
</th>
<th scope="col" jhiSortBy="user.id">
<span jhiTranslate="gitsearchApp.savedSearches.user">User</span> <fa-icon icon="sort"></fa-icon>
<div class="d-flex">
<span jhiTranslate="gitsearchApp.savedSearches.user">User</span>
<fa-icon class="p-1" icon="sort"></fa-icon>
</div>
</th>
<th scope="col"></th>
</tr>
</thead>
<tbody infinite-scroll (scrolled)="loadPage(page + 1)" [infiniteScrollDisabled]="page >= links['last']" [infiniteScrollDistance]="0">
<tbody
infinite-scroll
(scrolled)="loadPage(page + 1)"
[infiniteScrollDisabled]="page - 1 >= links['last']"
[infiniteScrollDistance]="0"
>
<tr *ngFor="let savedSearches of savedSearches; trackBy: trackId" data-cy="entityTable">
<td>
<a [routerLink]="['/saved-searches', savedSearches.id, 'view']">{{ savedSearches.id }}</a>
......@@ -81,7 +74,7 @@
<td>
{{ savedSearches.user?.id }}
</td>
<td class="text-right">
<td class="text-end">
<div class="btn-group">
<button
type="submit"
......
......@@ -8,11 +8,13 @@ import { of } from 'rxjs';
import { SavedSearchesService } from '../service/saved-searches.service';
import { SavedSearchesComponent } from './saved-searches.component';
import SpyInstance = jest.SpyInstance;
describe('SavedSearches Management Component', () => {
let comp: SavedSearchesComponent;
let fixture: ComponentFixture<SavedSearchesComponent>;
let service: SavedSearchesService;
let routerNavigateSpy: SpyInstance<Promise<boolean>>;
beforeEach(() => {
TestBed.configureTestingModule({
......@@ -21,7 +23,20 @@ describe('SavedSearches Management Component', () => {
providers: [
{
provide: ActivatedRoute,
useValue: { snapshot: { queryParams: {} } },
useValue: {
data: of({
defaultSort: 'id,asc',
}),
queryParamMap: of(
jest.requireActual('@angular/router').convertToParamMap({
page: '1',
size: '1',
sort: 'id,desc',
'filter[someId.in]': 'dc4279ea-cfb9-11ec-9d64-0242ac120002',
})
),
snapshot: { queryParams: {} },
},
},
],
})
......@@ -31,6 +46,7 @@ describe('SavedSearches Management Component', () => {
fixture = TestBed.createComponent(SavedSearchesComponent);
comp = fixture.componentInstance;
service = TestBed.inject(SavedSearchesService);
routerNavigateSpy = jest.spyOn(comp.router, 'navigate');
const headers = new HttpHeaders();
jest.spyOn(service, 'query').mockReturnValue(
......@@ -49,16 +65,25 @@ describe('SavedSearches Management Component', () => {
// THEN
expect(service.query).toHaveBeenCalled();
expect(comp.savedSearches[0]).toEqual(expect.objectContaining({ id: 123 }));
expect(comp.savedSearches?.[0]).toEqual(expect.objectContaining({ id: 123 }));
});
describe('trackId', () => {
it('Should forward to savedSearchesService', () => {
const entity = { id: 123 };
jest.spyOn(service, 'getSavedSearchesIdentifier');
const id = comp.trackId(0, entity);
expect(service.getSavedSearchesIdentifier).toHaveBeenCalledWith(entity);
expect(id).toBe(entity.id);
});
});
it('should load a page', () => {
// WHEN
comp.loadPage(1);
comp.navigateToPage(1);
// THEN
expect(service.query).toHaveBeenCalled();
expect(comp.savedSearches[0]).toEqual(expect.objectContaining({ id: 123 }));
expect(routerNavigateSpy).toHaveBeenCalled();
});
it('should calculate the sort attribute for an id', () => {
......@@ -66,21 +91,25 @@ describe('SavedSearches Management Component', () => {
comp.ngOnInit();
// THEN
expect(service.query).toHaveBeenCalledWith(expect.objectContaining({ sort: ['id,asc'] }));
expect(service.query).toHaveBeenLastCalledWith(expect.objectContaining({ sort: ['id,desc'] }));
});
it('should calculate the sort attribute for a non-id attribute', () => {
// INIT
comp.ngOnInit();
// GIVEN
comp.predicate = 'name';
// WHEN
comp.loadPage(1);
comp.navigateToWithComponentValues();
// THEN
expect(service.query).toHaveBeenLastCalledWith(expect.objectContaining({ sort: ['name,asc', 'id'] }));
expect(routerNavigateSpy).toHaveBeenLastCalledWith(
expect.anything(),
expect.objectContaining({
queryParams: expect.objectContaining({
sort: ['name,asc'],
}),
})
);
});
it('should re-initialize the page', () => {
......@@ -89,8 +118,8 @@ describe('SavedSearches Management Component', () => {
comp.reset();
// THEN
expect(comp.page).toEqual(0);
expect(comp.page).toEqual(1);
expect(service.query).toHaveBeenCalledTimes(2);
expect(comp.savedSearches[0]).toEqual(expect.objectContaining({ id: 123 }));
expect(comp.savedSearches?.[0]).toEqual(expect.objectContaining({ id: 123 }));
});
});
import { Component, OnInit } from '@angular/core';
import { HttpHeaders, HttpResponse } from '@angular/common/http';
import { ActivatedRoute } from '@angular/router';
import { HttpHeaders } from '@angular/common/http';
import { ActivatedRoute, Data, ParamMap, Router } from '@angular/router';
import { combineLatest, filter, Observable, switchMap, tap } from 'rxjs';
import { NgbModal } from '@ng-bootstrap/ng-bootstrap';
import { ISavedSearches } from '../saved-searches.model';
import { ASC, DESC, ITEMS_PER_PAGE } from 'app/config/pagination.constants';
import { SavedSearchesService } from '../service/saved-searches.service';
import { ITEMS_PER_PAGE } from 'app/config/pagination.constants';
import { ASC, DESC, SORT, ITEM_DELETED_EVENT, DEFAULT_SORT_DATA } from 'app/config/navigation.constants';
import { EntityArrayResponseType, SavedSearchesService } from '../service/saved-searches.service';
import { SavedSearchesDeleteDialogComponent } from '../delete/saved-searches-delete-dialog.component';
import { ParseLinks } from 'app/core/util/parse-links.service';
......@@ -15,124 +17,107 @@ import { ParseLinks } from 'app/core/util/parse-links.service';
templateUrl: './saved-searches.component.html',
})
export class SavedSearchesComponent implements OnInit {
savedSearches: ISavedSearches[];
savedSearches?: ISavedSearches[];
isLoading = false;
itemsPerPage: number;
links: { [key: string]: number };
page: number;
predicate: string;
ascending: boolean;
currentSearch: string;
predicate = 'id';
ascending = true;
itemsPerPage = ITEMS_PER_PAGE;
links: { [key: string]: number } = {
last: 0,
};
page = 1;
constructor(
protected savedSearchesService: SavedSearchesService,
protected modalService: NgbModal,
protected activatedRoute: ActivatedRoute,
public router: Router,
protected parseLinks: ParseLinks,
protected activatedRoute: ActivatedRoute
) {
protected modalService: NgbModal
) {}
reset(): void {
this.page = 1;
this.savedSearches = [];
this.itemsPerPage = ITEMS_PER_PAGE;
this.page = 0;
this.links = {
last: 0,
};
this.predicate = 'id';
this.ascending = true;
this.currentSearch = this.activatedRoute.snapshot.queryParams['search'] ?? '';
this.load();
}
loadAll(): void {
this.isLoading = true;
if (this.currentSearch) {
this.savedSearchesService
.search({
query: this.currentSearch,
page: this.page,
size: this.itemsPerPage,
sort: this.sort(),
})
.subscribe({
next: (res: HttpResponse<ISavedSearches[]>) => {
this.isLoading = false;
this.paginateSavedSearches(res.body, res.headers);
},
error: () => {
this.isLoading = false;
},
});
return;
}
loadPage(page: number): void {
this.page = page;
this.load();
}
trackId = (_index: number, item: ISavedSearches): number => this.savedSearchesService.getSavedSearchesIdentifier(item);
ngOnInit(): void {
this.load();
}
this.savedSearchesService
.query({
page: this.page,
size: this.itemsPerPage,
sort: this.sort(),
})
delete(savedSearches: ISavedSearches): void {
const modalRef = this.modalService.open(SavedSearchesDeleteDialogComponent, { size: 'lg', backdrop: 'static' });
modalRef.componentInstance.savedSearches = savedSearches;
// unsubscribe not needed because closed completes on modal close
modalRef.closed
.pipe(
filter(reason => reason === ITEM_DELETED_EVENT),
switchMap(() => this.loadFromBackendWithRouteInformations())
)
.subscribe({
next: (res: HttpResponse<ISavedSearches[]>) => {
this.isLoading = false;
this.paginateSavedSearches(res.body, res.headers);
},
error: () => {
this.isLoading = false;
next: (res: EntityArrayResponseType) => {
this.onResponseSuccess(res);
},
});
}
reset(): void {
this.page = 0;
this.savedSearches = [];
this.loadAll();
load(): void {
this.loadFromBackendWithRouteInformations().subscribe({
next: (res: EntityArrayResponseType) => {
this.onResponseSuccess(res);
},
});
}
loadPage(page: number): void {
this.page = page;
this.loadAll();
navigateToWithComponentValues(): void {
this.handleNavigation(this.page, this.predicate, this.ascending);
}
search(query: string): void {
this.savedSearches = [];
this.links = {
last: 0,
};
this.page = 0;
if (query && ['name', 'jsonQuery'].includes(this.predicate)) {
this.predicate = 'id';
this.ascending = true;
}
this.currentSearch = query;
this.loadAll();
navigateToPage(page = this.page): void {
this.handleNavigation(page, this.predicate, this.ascending);
}
ngOnInit(): void {
this.loadAll();
protected loadFromBackendWithRouteInformations(): Observable<EntityArrayResponseType> {
return combineLatest([this.activatedRoute.queryParamMap, this.activatedRoute.data]).pipe(
tap(([params, data]) => this.fillComponentAttributeFromRoute(params, data)),
switchMap(() => this.queryBackend(this.page, this.predicate, this.ascending))
);
}
trackId(index: number, item: ISavedSearches): number {
return item.id!;
protected fillComponentAttributeFromRoute(params: ParamMap, data: Data): void {
const sort = (params.get(SORT) ?? data[DEFAULT_SORT_DATA]).split(',');
this.predicate = sort[0];
this.ascending = sort[1] === ASC;
}
delete(savedSearches: ISavedSearches): void {
const modalRef = this.modalService.open(SavedSearchesDeleteDialogComponent, { size: 'lg', backdrop: 'static' });
modalRef.componentInstance.savedSearches = savedSearches;
// unsubscribe not needed because closed completes on modal close
modalRef.closed.subscribe(reason => {
if (reason === 'deleted') {
this.reset();
}
});
protected onResponseSuccess(response: EntityArrayResponseType): void {
this.fillComponentAttributesFromResponseHeader(response.headers);
const dataFromBody = this.fillComponentAttributesFromResponseBody(response.body);
this.savedSearches = dataFromBody;
}
protected sort(): string[] {
const result = [this.predicate + ',' + (this.ascending ? ASC : DESC)];
if (this.predicate !== 'id') {
result.push('id');
protected fillComponentAttributesFromResponseBody(data: ISavedSearches[] | null): ISavedSearches[] {
const savedSearchesNew = this.savedSearches ?? [];
if (data) {
for (const d of data) {
if (savedSearchesNew.map(op => op.id).indexOf(d.id) === -1) {
savedSearchesNew.push(d);
}
}
}
return result;
return savedSearchesNew;
}
protected paginateSavedSearches(data: ISavedSearches[] | null, headers: HttpHeaders): void {
protected fillComponentAttributesFromResponseHeader(headers: HttpHeaders): void {
const linkHeader = headers.get('link');
if (linkHeader) {
this.links = this.parseLinks.parse(linkHeader);
......@@ -141,10 +126,38 @@ export class SavedSearchesComponent implements OnInit {
last: 0,
};
}
if (data) {
for (const d of data) {
this.savedSearches.push(d);
}
}
protected queryBackend(page?: number, predicate?: string, ascending?: boolean): Observable<EntityArrayResponseType> {
this.isLoading = true;
const pageToLoad: number = page ?? 1;
const queryObject = {
page: pageToLoad - 1,
size: this.itemsPerPage,
sort: this.getSortQueryParam(predicate, ascending),
};
return this.savedSearchesService.query(queryObject).pipe(tap(() => (this.isLoading = false)));
}
protected handleNavigation(page = this.page, predicate?: string, ascending?: boolean): void {
const queryParamsObj = {
page,
size: this.itemsPerPage,
sort: this.getSortQueryParam(predicate, ascending),
};
this.router.navigate(['./'], {
relativeTo: this.activatedRoute,
queryParams: queryParamsObj,
});
}
protected getSortQueryParam(predicate = this.predicate, ascending = this.ascending): string[] {
const ascendingQueryParam = ascending ? ASC : DESC;
if (predicate === '') {
return [];
} else {
return [predicate + ',' + ascendingQueryParam];
}
}
}
......@@ -5,7 +5,7 @@ import { ActivatedRouteSnapshot, ActivatedRoute, Router, convertToParamMap } fro
import { RouterTestingModule } from '@angular/router/testing';
import { of } from 'rxjs';
import { ISavedSearches, SavedSearches } from '../saved-searches.model';
import { ISavedSearches } from '../saved-searches.model';
import { SavedSearchesService } from '../service/saved-searches.service';
import { SavedSearchesRoutingResolveService } from './saved-searches-routing-resolve.service';
......@@ -15,7 +15,7 @@ describe('SavedSearches routing resolve service', () => {
let mockActivatedRouteSnapshot: ActivatedRouteSnapshot;
let routingResolveService: SavedSearchesRoutingResolveService;
let service: SavedSearchesService;
let resultSavedSearches: ISavedSearches | undefined;
let resultSavedSearches: ISavedSearches | null | undefined;
beforeEach(() => {
TestBed.configureTestingModule({
......@@ -55,7 +55,7 @@ describe('SavedSearches routing resolve service', () => {
expect(resultSavedSearches).toEqual({ id: 123 });
});
it('should return new ISavedSearches if id is not provided', () => {
it('should return null if id is not provided', () => {
// GIVEN
service.find = jest.fn();
mockActivatedRouteSnapshot.params = {};
......@@ -67,12 +67,12 @@ describe('SavedSearches routing resolve service', () => {
// THEN
expect(service.find).not.toBeCalled();
expect(resultSavedSearches).toEqual(new SavedSearches());
expect(resultSavedSearches).toEqual(null);
});
it('should route to 404 page if data not found in server', () => {
// GIVEN
jest.spyOn(service, 'find').mockReturnValue(of(new HttpResponse({ body: null as unknown as SavedSearches })));
jest.spyOn(service, 'find').mockReturnValue(of(new HttpResponse<ISavedSearches>({ body: null })));
mockActivatedRouteSnapshot.params = { id: 123 };
// WHEN
......
......@@ -4,18 +4,18 @@ import { Resolve, ActivatedRouteSnapshot, Router } from '@angular/router';
import { Observable, of, EMPTY } from 'rxjs';
import { mergeMap } from 'rxjs/operators';
import { ISavedSearches, SavedSearches } from '../saved-searches.model';
import { ISavedSearches } from '../saved-searches.model';
import { SavedSearchesService } from '../service/saved-searches.service';
@Injectable({ providedIn: 'root' })
export class SavedSearchesRoutingResolveService implements Resolve<ISavedSearches> {
export class SavedSearchesRoutingResolveService implements Resolve<ISavedSearches | null> {
constructor(protected service: SavedSearchesService, protected router: Router) {}
resolve(route: ActivatedRouteSnapshot): Observable<ISavedSearches> | Observable<never> {
resolve(route: ActivatedRouteSnapshot): Observable<ISavedSearches | null | never> {
const id = route.params['id'];
if (id) {
return this.service.find(id).pipe(
mergeMap((savedSearches: HttpResponse<SavedSearches>) => {
mergeMap((savedSearches: HttpResponse<ISavedSearches>) => {
if (savedSearches.body) {
return of(savedSearches.body);
} else {
......@@ -25,6 +25,6 @@ export class SavedSearchesRoutingResolveService implements Resolve<ISavedSearche
})
);
}
return of(new SavedSearches());
return of(null);
}
}
......@@ -6,11 +6,15 @@ import { SavedSearchesComponent } from '../list/saved-searches.component';
import { SavedSearchesDetailComponent } from '../detail/saved-searches-detail.component';
import { SavedSearchesUpdateComponent } from '../update/saved-searches-update.component';
import { SavedSearchesRoutingResolveService } from './saved-searches-routing-resolve.service';
import { ASC } from 'app/config/navigation.constants';
const savedSearchesRoute: Routes = [
{
path: '',
component: SavedSearchesComponent,
data: {
defaultSort: 'id,' + ASC,
},
canActivate: [UserRouteAccessService],
},
{
......