]> source.dussan.org Git - archiva.git/blob
2e5123bb09a42f5ed9d222ff6d5255508e823ff5
[archiva.git] /
1 /*
2  * Licensed to the Apache Software Foundation (ASF) under one
3  * or more contributor license agreements.  See the NOTICE file
4  * distributed with this work for additional information
5  * regarding copyright ownership.  The ASF licenses this file
6  * to you under the Apache License, Version 2.0 (the
7  * "License"); you may not use this file except in compliance
8  * with the License.  You may obtain a copy of the License at
9  *
10  * http://www.apache.org/licenses/LICENSE-2.0
11  * Unless required by applicable law or agreed to in writing,
12  * software distributed under the License is distributed on an
13  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14  * KIND, either express or implied.  See the License for the
15  * specific language governing permissions and limitations
16  * under the License.
17  */
18
19 import {Component, OnInit, Input, Output, EventEmitter} from '@angular/core';
20 import {merge, Observable, Subject} from "rxjs";
21 import {UserInfo} from "../../../model/user-info";
22 import {TranslateService} from "@ngx-translate/core";
23 import {debounceTime, distinctUntilChanged, map, mergeMap, pluck, share, startWith} from "rxjs/operators";
24 import {EntityService} from "../../../model/entity-service";
25
26
27 /**
28  * This component has a search field and pagination section. Entering data in the search field, or
29  * a button click on the pagination triggers a call to a service method, that returns the entity data.
30  * The service must implement the {@link EntityService} interface.
31  *
32  * The content is displayed between the search input and the pagination section. To use the data, you should
33  * add an identifier and refer to the item$ variable:
34  * ```
35  * <app-paginated-entities #parent>
36  *   <table>
37  *       <tr ngFor="let entity in parent.item$ | async" >
38  *           <td>{{entity.id}}</td>
39  *       </tr>
40  *   </table>
41  * </app-paginated-entities>
42  * ```
43  *
44  * @typeparam T The type of the retrieved entity elements.
45  */
46 @Component({
47   selector: 'app-paginated-entities',
48   templateUrl: './paginated-entities.component.html',
49   styleUrls: ['./paginated-entities.component.scss']
50 })
51 export class PaginatedEntitiesComponent<T> implements OnInit {
52
53   /**
54    * This must be set, if you use the component. This service retrieves the entity data.
55    */
56   @Input() service : EntityService<T>;
57
58   /**
59    * The number of elements per page retrieved
60    */
61   @Input() pageSize = 10;
62
63   /**
64    * Pagination controls
65    */
66   @Input() pagination = {
67     maxSize:5,
68     rotate:true,
69     boundaryLinks:true,
70     ellipses:false
71   }
72
73   /**
74    * The current page that is selected
75    */
76   page = 1;
77   /**
78    * The current search term entered in the search field
79    */
80   searchTerm: string;
81
82   /**
83    * Event thrown, if the page value changes
84    */
85   @Output() pageEvent : EventEmitter<number> = new EventEmitter<number>();
86   /**
87    * Event thrown, if the search term changes
88    */
89   @Output() searchTermEvent: EventEmitter<string> = new EventEmitter<string>();
90
91   /**
92    * The total number of elements available for the given search term
93    */
94   total$: Observable<number>;
95   /**
96    * The entity items retrieved from the service
97    */
98   items$: Observable<T[]>;
99
100   private pageStream: Subject<number> = new Subject<number>();
101   private searchTermStream: Subject<string> = new Subject<string>();
102
103   constructor() { }
104
105   ngOnInit(): void {
106     // We combine the sources for the page and the search input field to a observable 'source'
107     const pageSource = this.pageStream.pipe(map(pageNumber => {
108       return {search: this.searchTerm, page: pageNumber}
109     }));
110     const searchSource = this.searchTermStream.pipe(
111         debounceTime(1000),
112         distinctUntilChanged(),
113         map(searchTerm => {
114           this.searchTerm = searchTerm;
115           return {search: searchTerm, page: 1}
116         }));
117     const source = merge(pageSource, searchSource).pipe(
118         startWith({search: this.searchTerm, page: this.page}),
119         mergeMap((params: { search: string, page: number }) => {
120           return this.service(params.search, (params.page - 1) * this.pageSize, this.pageSize, "", "asc");
121         }),share());
122     this.total$ = source.pipe(pluck('pagination','totalCount'));
123     this.items$ = source.pipe(pluck('data'));
124   }
125
126   search(terms: string) {
127     // console.log("Keystroke " + terms);
128     this.searchTermEvent.emit(terms);
129     this.searchTermStream.next(terms)
130   }
131
132   changePage(pageNumber : number) {
133     // console.log("Page change " +pageNumber);
134     this.pageEvent.emit(pageNumber);
135     this.pageStream.next(pageNumber);
136   }
137
138 }