mirror of
https://github.com/goharbor/harbor.git
synced 2024-10-01 06:47:33 +02:00
enable server end pagination for project list
This commit is contained in:
parent
d21795cf53
commit
9987d89705
@ -68,9 +68,9 @@ export class RepositoryStackviewComponent implements OnChanges, OnInit {
|
|||||||
@ViewChild('confirmationDialog')
|
@ViewChild('confirmationDialog')
|
||||||
confirmationDialog: ConfirmationDialogComponent;
|
confirmationDialog: ConfirmationDialogComponent;
|
||||||
|
|
||||||
pullCountComparator: Comparator<Repository> = new CustomComparator<Repository>('pull_count', 'number');
|
pullCountComparator: Comparator<RepositoryItem> = new CustomComparator<RepositoryItem>('pull_count', 'number');
|
||||||
|
|
||||||
tagsCountComparator: Comparator<Repository> = new CustomComparator<Repository>('tags_count', 'number');
|
tagsCountComparator: Comparator<RepositoryItem> = new CustomComparator<RepositoryItem>('tags_count', 'number');
|
||||||
|
|
||||||
pageSize: number = DEFAULT_PAGE_SIZE;
|
pageSize: number = DEFAULT_PAGE_SIZE;
|
||||||
currentPage: number = 1;
|
currentPage: number = 1;
|
||||||
@ -277,7 +277,7 @@ export class RepositoryStackviewComponent implements OnChanges, OnInit {
|
|||||||
let total: number = this.totalCount - 1;
|
let total: number = this.totalCount - 1;
|
||||||
if (total <= 0) { return null; }
|
if (total <= 0) { return null; }
|
||||||
|
|
||||||
let totalPages: number = Math.floor(total / this.pageSize);
|
let totalPages: number = Math.ceil(total / this.pageSize);
|
||||||
let targetPageNumber: number = this.currentPage;
|
let targetPageNumber: number = this.currentPage;
|
||||||
|
|
||||||
if (this.currentPage > totalPages) {
|
if (this.currentPage > totalPages) {
|
||||||
|
@ -1,10 +1,10 @@
|
|||||||
<clr-datagrid (clrDgRefresh)="refresh($event)" [clrDgLoading]="loading">
|
<clr-datagrid (clrDgRefresh)="clrLoad($event)" [clrDgLoading]="loading">
|
||||||
<clr-dg-column>{{'PROJECT.NAME' | translate}}</clr-dg-column>
|
<clr-dg-column [clrDgField]="'name'">{{'PROJECT.NAME' | translate}}</clr-dg-column>
|
||||||
<clr-dg-column>{{'PROJECT.ACCESS_LEVEL' | translate}}</clr-dg-column>
|
<clr-dg-column [clrDgSortBy]="accessLevelComparator">{{'PROJECT.ACCESS_LEVEL' | translate}}</clr-dg-column>
|
||||||
<clr-dg-column *ngIf="showRoleInfo">{{'PROJECT.ROLE' | translate}}</clr-dg-column>
|
<clr-dg-column *ngIf="showRoleInfo" [clrDgSortBy]="roleComparator">{{'PROJECT.ROLE' | translate}}</clr-dg-column>
|
||||||
<clr-dg-column>{{'PROJECT.REPO_COUNT'| translate}}</clr-dg-column>
|
<clr-dg-column [clrDgSortBy]="repoCountComparator">{{'PROJECT.REPO_COUNT'| translate}}</clr-dg-column>
|
||||||
<clr-dg-column>{{'PROJECT.CREATION_TIME' | translate}}</clr-dg-column>
|
<clr-dg-column [clrDgSortBy]="timeComparator">{{'PROJECT.CREATION_TIME' | translate}}</clr-dg-column>
|
||||||
<clr-dg-row *clrDgItems="let p of projects">
|
<clr-dg-row *ngFor="let p of projects">
|
||||||
<clr-dg-action-overflow [hidden]="!(p.current_user_role_id === 1 || isSystemAdmin)">
|
<clr-dg-action-overflow [hidden]="!(p.current_user_role_id === 1 || isSystemAdmin)">
|
||||||
<button class="action-item" (click)="newReplicationRule(p)" [hidden]="!isSystemAdmin">{{'PROJECT.REPLICATION_RULE' | translate}}</button>
|
<button class="action-item" (click)="newReplicationRule(p)" [hidden]="!isSystemAdmin">{{'PROJECT.REPLICATION_RULE' | translate}}</button>
|
||||||
<button class="action-item" (click)="toggleProject(p)">{{'PROJECT.MAKE' | translate}} {{(p.public === 0 ? 'PROJECT.PUBLIC' : 'PROJECT.PRIVATE') | translate}} </button>
|
<button class="action-item" (click)="toggleProject(p)">{{'PROJECT.MAKE' | translate}} {{(p.public === 0 ? 'PROJECT.PUBLIC' : 'PROJECT.PRIVATE') | translate}} </button>
|
||||||
@ -17,8 +17,7 @@
|
|||||||
<clr-dg-cell>{{p.creation_time | date: 'short'}}</clr-dg-cell>
|
<clr-dg-cell>{{p.creation_time | date: 'short'}}</clr-dg-cell>
|
||||||
</clr-dg-row>
|
</clr-dg-row>
|
||||||
<clr-dg-footer>
|
<clr-dg-footer>
|
||||||
<span *ngIf="pagination.totalItems">{{pagination.firstItem + 1}} - {{pagination.lastItem +1 }} {{'PROJECT.OF' | translate}} </span>
|
<span *ngIf="pagination.totalItems">{{pagination.firstItem + 1}} - {{pagination.lastItem +1 }} {{'PROJECT.OF' | translate}} </span> {{pagination.totalItems }} {{'PROJECT.ITEMS' | translate}}
|
||||||
{{pagination.totalItems }} {{'PROJECT.ITEMS' | translate}}
|
<clr-dg-pagination #pagination [clrDgPageSize]="pageSize" [(clrDgPage)]="currentPage" [clrDgTotalItems]="totalCount"></clr-dg-pagination>
|
||||||
<clr-dg-pagination #pagination [clrDgPageSize]="15"></clr-dg-pagination>
|
|
||||||
</clr-dg-footer>
|
</clr-dg-footer>
|
||||||
</clr-datagrid>
|
</clr-datagrid>
|
@ -11,7 +11,14 @@
|
|||||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
// See the License for the specific language governing permissions and
|
// See the License for the specific language governing permissions and
|
||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
import { Component, EventEmitter, Output, Input, ChangeDetectionStrategy, ChangeDetectorRef } from '@angular/core';
|
import {
|
||||||
|
Component,
|
||||||
|
Output,
|
||||||
|
Input,
|
||||||
|
ChangeDetectionStrategy,
|
||||||
|
ChangeDetectorRef,
|
||||||
|
OnDestroy
|
||||||
|
} from '@angular/core';
|
||||||
import { Router, NavigationExtras } from '@angular/router';
|
import { Router, NavigationExtras } from '@angular/router';
|
||||||
import { Project } from '../project';
|
import { Project } from '../project';
|
||||||
import { ProjectService } from '../project.service';
|
import { ProjectService } from '../project.service';
|
||||||
@ -19,46 +26,85 @@ import { ProjectService } from '../project.service';
|
|||||||
import { SessionService } from '../../shared/session.service';
|
import { SessionService } from '../../shared/session.service';
|
||||||
import { SearchTriggerService } from '../../base/global-search/search-trigger.service';
|
import { SearchTriggerService } from '../../base/global-search/search-trigger.service';
|
||||||
import { ProjectTypes, RoleInfo } from '../../shared/shared.const';
|
import { ProjectTypes, RoleInfo } from '../../shared/shared.const';
|
||||||
|
import { CustomComparator, doFiltering, doSorting, calculatePage } from '../../shared/shared.utils';
|
||||||
|
|
||||||
import { State } from 'clarity-angular';
|
import { Comparator, State } from 'clarity-angular';
|
||||||
|
import { MessageHandlerService } from '../../shared/message-handler/message-handler.service';
|
||||||
|
import { StatisticHandler } from '../../shared/statictics/statistic-handler.service';
|
||||||
|
import { Subscription } from 'rxjs/Subscription';
|
||||||
|
import { ConfirmationDialogService } from '../../shared/confirmation-dialog/confirmation-dialog.service';
|
||||||
|
import { ConfirmationMessage } from '../../shared/confirmation-dialog/confirmation-message';
|
||||||
|
import { ConfirmationTargets, ConfirmationState, ConfirmationButtons } from '../../shared/shared.const';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'list-project',
|
selector: 'list-project',
|
||||||
templateUrl: 'list-project.component.html',
|
templateUrl: 'list-project.component.html',
|
||||||
changeDetection: ChangeDetectionStrategy.OnPush
|
changeDetection: ChangeDetectionStrategy.OnPush
|
||||||
})
|
})
|
||||||
export class ListProjectComponent {
|
export class ListProjectComponent implements OnDestroy {
|
||||||
_filterType: string = ProjectTypes[0];
|
loading: boolean = true;
|
||||||
|
projects: Project[] = [];
|
||||||
@Input() loading: boolean = true;
|
filteredType: number = 0;//All projects
|
||||||
@Input() projects: Project[];
|
searchKeyword: string = "";
|
||||||
@Input()
|
|
||||||
get filteredType(): string {
|
|
||||||
return this._filterType;
|
|
||||||
}
|
|
||||||
set filteredType(value: string) {
|
|
||||||
if (value && value.trim() !== "") {
|
|
||||||
this._filterType = value;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Output() paginate = new EventEmitter<State>();
|
|
||||||
@Output() toggle = new EventEmitter<Project>();
|
|
||||||
@Output() delete = new EventEmitter<Project>();
|
|
||||||
|
|
||||||
roleInfo = RoleInfo;
|
roleInfo = RoleInfo;
|
||||||
|
repoCountComparator: Comparator<Project> = new CustomComparator<Project>("repo_count", "number");
|
||||||
|
timeComparator: Comparator<Project> = new CustomComparator<Project>("creation_time", "date");
|
||||||
|
accessLevelComparator: Comparator<Project> = new CustomComparator<Project>("public", "number");
|
||||||
|
roleComparator: Comparator<Project> = new CustomComparator<Project>("current_user_role_id", "number");
|
||||||
|
currentPage: number = 1;
|
||||||
|
totalCount: number = 0;
|
||||||
|
pageSize: number = 15;
|
||||||
|
currentState: State;
|
||||||
|
subscription: Subscription;
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
private session: SessionService,
|
private session: SessionService,
|
||||||
private router: Router,
|
private router: Router,
|
||||||
private searchTrigger: SearchTriggerService,
|
private searchTrigger: SearchTriggerService,
|
||||||
|
private proService: ProjectService,
|
||||||
|
private msgHandler: MessageHandlerService,
|
||||||
|
private statisticHandler: StatisticHandler,
|
||||||
|
private deletionDialogService: ConfirmationDialogService,
|
||||||
private ref: ChangeDetectorRef) {
|
private ref: ChangeDetectorRef) {
|
||||||
|
this.subscription = deletionDialogService.confirmationConfirm$.subscribe(message => {
|
||||||
|
if (message &&
|
||||||
|
message.state === ConfirmationState.CONFIRMED &&
|
||||||
|
message.source === ConfirmationTargets.PROJECT) {
|
||||||
|
let projectId = message.data;
|
||||||
|
this.proService
|
||||||
|
.deleteProject(projectId)
|
||||||
|
.subscribe(
|
||||||
|
response => {
|
||||||
|
this.msgHandler.showSuccess('PROJECT.DELETED_SUCCESS');
|
||||||
|
let st: State = this.getStateAfterDeletion();
|
||||||
|
if (!st) {
|
||||||
|
this.refresh();
|
||||||
|
} else {
|
||||||
|
this.clrLoad(st);
|
||||||
|
this.statisticHandler.refresh();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
error => {
|
||||||
|
if (error && error.status === 412) {
|
||||||
|
this.msgHandler.showError('PROJECT.FAILED_TO_DELETE_PROJECT', '');
|
||||||
|
} else {
|
||||||
|
this.msgHandler.handleError(error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
let hnd = setInterval(() => ref.markForCheck(), 100);
|
let hnd = setInterval(() => ref.markForCheck(), 100);
|
||||||
setTimeout(() => clearInterval(hnd), 1000);
|
setTimeout(() => clearInterval(hnd), 2000);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
let hnd = setInterval(() => ref.markForCheck(), 100);
|
||||||
|
setTimeout(() => clearInterval(hnd), 5000);
|
||||||
}
|
}
|
||||||
|
|
||||||
get showRoleInfo(): boolean {
|
get showRoleInfo(): boolean {
|
||||||
return this.filteredType !== ProjectTypes[2];
|
return this.filteredType !== 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
public get isSystemAdmin(): boolean {
|
public get isSystemAdmin(): boolean {
|
||||||
@ -66,6 +112,12 @@ export class ListProjectComponent {
|
|||||||
return account != null && account.has_admin_role > 0;
|
return account != null && account.has_admin_role > 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ngOnDestroy(): void {
|
||||||
|
if (this.subscription) {
|
||||||
|
this.subscription.unsubscribe();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
goToLink(proId: number): void {
|
goToLink(proId: number): void {
|
||||||
this.searchTrigger.closeSearch(true);
|
this.searchTrigger.closeSearch(true);
|
||||||
|
|
||||||
@ -73,8 +125,44 @@ export class ListProjectComponent {
|
|||||||
this.router.navigate(linkUrl);
|
this.router.navigate(linkUrl);
|
||||||
}
|
}
|
||||||
|
|
||||||
refresh(state: State) {
|
clrLoad(state: State) {
|
||||||
this.paginate.emit(state);
|
//Keep state for future filtering and sorting
|
||||||
|
this.currentState = state;
|
||||||
|
|
||||||
|
let pageNumber: number = calculatePage(state);
|
||||||
|
if (pageNumber <= 0) { pageNumber = 1; }
|
||||||
|
|
||||||
|
this.loading = true;
|
||||||
|
|
||||||
|
let passInFilteredType: number = undefined;
|
||||||
|
if (this.filteredType > 0) {
|
||||||
|
passInFilteredType = this.filteredType - 1;
|
||||||
|
}
|
||||||
|
this.proService.listProjects(this.searchKeyword, passInFilteredType, pageNumber, this.pageSize).toPromise()
|
||||||
|
.then(response => {
|
||||||
|
//Get total count
|
||||||
|
if (response.headers) {
|
||||||
|
let xHeader: string = response.headers.get("X-Total-Count");
|
||||||
|
if (xHeader) {
|
||||||
|
this.totalCount = parseInt(xHeader, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
this.projects = response.json() as Project[];
|
||||||
|
//Do customising filtering and sorting
|
||||||
|
this.projects = doFiltering<Project>(this.projects, state);
|
||||||
|
this.projects = doSorting<Project>(this.projects, state);
|
||||||
|
|
||||||
|
this.loading = false;
|
||||||
|
})
|
||||||
|
.catch(error => {
|
||||||
|
this.loading = false;
|
||||||
|
this.msgHandler.handleError(error);
|
||||||
|
});
|
||||||
|
|
||||||
|
//Force refresh view
|
||||||
|
let hnd = setInterval(() => this.ref.markForCheck(), 100);
|
||||||
|
setTimeout(() => clearInterval(hnd), 5000);
|
||||||
}
|
}
|
||||||
|
|
||||||
newReplicationRule(p: Project) {
|
newReplicationRule(p: Project) {
|
||||||
@ -84,11 +172,95 @@ export class ListProjectComponent {
|
|||||||
}
|
}
|
||||||
|
|
||||||
toggleProject(p: Project) {
|
toggleProject(p: Project) {
|
||||||
this.toggle.emit(p);
|
if (p) {
|
||||||
|
p.public === 0 ? p.public = 1 : p.public = 0;
|
||||||
|
this.proService
|
||||||
|
.toggleProjectPublic(p.project_id, p.public)
|
||||||
|
.subscribe(
|
||||||
|
response => {
|
||||||
|
this.msgHandler.showSuccess('PROJECT.TOGGLED_SUCCESS');
|
||||||
|
let pp: Project = this.projects.find((item: Project) => item.project_id === p.project_id);
|
||||||
|
if (pp) {
|
||||||
|
pp.public = p.public;
|
||||||
|
this.statisticHandler.refresh();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
error => this.msgHandler.handleError(error)
|
||||||
|
);
|
||||||
|
|
||||||
|
//Force refresh view
|
||||||
|
let hnd = setInterval(() => this.ref.markForCheck(), 100);
|
||||||
|
setTimeout(() => clearInterval(hnd), 2000);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
deleteProject(p: Project) {
|
deleteProject(p: Project) {
|
||||||
this.delete.emit(p);
|
let deletionMessage = new ConfirmationMessage(
|
||||||
|
'PROJECT.DELETION_TITLE',
|
||||||
|
'PROJECT.DELETION_SUMMARY',
|
||||||
|
p.name,
|
||||||
|
p.project_id,
|
||||||
|
ConfirmationTargets.PROJECT,
|
||||||
|
ConfirmationButtons.DELETE_CANCEL
|
||||||
|
);
|
||||||
|
this.deletionDialogService.openComfirmDialog(deletionMessage);
|
||||||
|
}
|
||||||
|
|
||||||
|
refresh(): void {
|
||||||
|
this.currentPage = 1;
|
||||||
|
this.filteredType = 0;
|
||||||
|
this.searchKeyword = "";
|
||||||
|
|
||||||
|
this.reload();
|
||||||
|
this.statisticHandler.refresh();
|
||||||
|
}
|
||||||
|
|
||||||
|
doFilterProject(filter: number): void {
|
||||||
|
this.currentPage = 1;
|
||||||
|
this.filteredType = filter;
|
||||||
|
this.reload();
|
||||||
|
}
|
||||||
|
|
||||||
|
doSearchProject(proName: string): void {
|
||||||
|
this.currentPage = 1;
|
||||||
|
this.searchKeyword = proName;
|
||||||
|
this.reload();
|
||||||
|
}
|
||||||
|
|
||||||
|
reload(): void {
|
||||||
|
let st: State = this.currentState;
|
||||||
|
if (!st) {
|
||||||
|
st = {
|
||||||
|
page: {}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
st.page.from = 0;
|
||||||
|
st.page.to = this.pageSize - 1;
|
||||||
|
st.page.size = this.pageSize;
|
||||||
|
|
||||||
|
this.clrLoad(st);
|
||||||
|
}
|
||||||
|
|
||||||
|
getStateAfterDeletion(): State {
|
||||||
|
let total: number = this.totalCount - 1;
|
||||||
|
if (total <= 0) { return null; }
|
||||||
|
|
||||||
|
let totalPages: number = Math.ceil(total / this.pageSize);
|
||||||
|
let targetPageNumber: number = this.currentPage;
|
||||||
|
|
||||||
|
if (this.currentPage > totalPages) {
|
||||||
|
targetPageNumber = totalPages;//Should == currentPage -1
|
||||||
|
}
|
||||||
|
|
||||||
|
let st: State = this.currentState;
|
||||||
|
if (!st) {
|
||||||
|
st = { page: {} };
|
||||||
|
}
|
||||||
|
st.page.size = this.pageSize;
|
||||||
|
st.page.from = (targetPageNumber - 1) * this.pageSize;
|
||||||
|
st.page.to = targetPageNumber * this.pageSize - 1;
|
||||||
|
|
||||||
|
return st;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
@ -13,7 +13,7 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="option-right">
|
<div class="option-right">
|
||||||
<div class="select" style="float: left; left:-6px; top:8px;">
|
<div class="select" style="float: left; left:-6px; top:8px;">
|
||||||
<select (change)="doFilterProjects($event)" [(ngModel)]="selecteType">
|
<select (change)="doFilterProjects()" [(ngModel)]="selecteType">
|
||||||
<option value="0" [selected]="currentFilteredType === 0">{{projectTypes[0] | translate}}</option>
|
<option value="0" [selected]="currentFilteredType === 0">{{projectTypes[0] | translate}}</option>
|
||||||
<option value="1">{{projectTypes[1] | translate}}</option>
|
<option value="1">{{projectTypes[1] | translate}}</option>
|
||||||
<option value="2">{{projectTypes[2] | translate}}</option>
|
<option value="2">{{projectTypes[2] | translate}}</option>
|
||||||
@ -25,6 +25,6 @@
|
|||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<list-project [projects]="changedProjects" [filteredType]="projectTypes[currentFilteredType]" (toggle)="toggleProject($event)" (delete)="deleteProject($event)" (paginate)="retrieve($event)" [loading]="loading"></list-project>
|
<list-project></list-project>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
@ -11,44 +11,21 @@
|
|||||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
// See the License for the specific language governing permissions and
|
// See the License for the specific language governing permissions and
|
||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
import {Component, OnInit, ViewChild, OnDestroy, ChangeDetectorRef, ChangeDetectionStrategy} from '@angular/core';
|
import { Component, OnInit, ViewChild, OnDestroy} from '@angular/core';
|
||||||
|
|
||||||
import { Router } from '@angular/router';
|
import { Router } from '@angular/router';
|
||||||
|
|
||||||
import { Project } from './project';
|
import { Project } from './project';
|
||||||
import { ProjectService } from './project.service';
|
|
||||||
|
|
||||||
import { CreateProjectComponent } from './create-project/create-project.component';
|
import { CreateProjectComponent } from './create-project/create-project.component';
|
||||||
|
|
||||||
import { ListProjectComponent } from './list-project/list-project.component';
|
import { ListProjectComponent } from './list-project/list-project.component';
|
||||||
|
|
||||||
import { MessageHandlerService } from '../shared/message-handler/message-handler.service';
|
|
||||||
import { Message } from '../global-message/message';
|
|
||||||
|
|
||||||
import { Response } from '@angular/http';
|
|
||||||
|
|
||||||
import { ConfirmationDialogService } from '../shared/confirmation-dialog/confirmation-dialog.service';
|
|
||||||
import { ConfirmationMessage } from '../shared/confirmation-dialog/confirmation-message';
|
|
||||||
import { ConfirmationTargets, ConfirmationState, ConfirmationButtons } from '../shared/shared.const';
|
|
||||||
|
|
||||||
import { Subscription } from 'rxjs/Subscription';
|
|
||||||
|
|
||||||
import { State } from 'clarity-angular';
|
|
||||||
|
|
||||||
import { AppConfigService } from '../app-config.service';
|
import { AppConfigService } from '../app-config.service';
|
||||||
import { SessionService } from '../shared/session.service';
|
import { SessionService } from '../shared/session.service';
|
||||||
import { ProjectTypes } from '../shared/shared.const';
|
import { ProjectTypes } from '../shared/shared.const';
|
||||||
import { StatisticHandler } from '../shared/statictics/statistic-handler.service';
|
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'project',
|
selector: 'project',
|
||||||
templateUrl: 'project.component.html',
|
templateUrl: 'project.component.html',
|
||||||
styleUrls: ['./project.component.css'],
|
styleUrls: ['./project.component.css']
|
||||||
changeDetection: ChangeDetectionStrategy.OnPush
|
|
||||||
})
|
})
|
||||||
export class ProjectComponent implements OnInit, OnDestroy {
|
export class ProjectComponent implements OnInit {
|
||||||
|
|
||||||
changedProjects: Project[];
|
|
||||||
projectTypes = ProjectTypes;
|
projectTypes = ProjectTypes;
|
||||||
|
|
||||||
@ViewChild(CreateProjectComponent)
|
@ViewChild(CreateProjectComponent)
|
||||||
@ -60,50 +37,21 @@ export class ProjectComponent implements OnInit, OnDestroy {
|
|||||||
currentFilteredType: number = 0;//all projects
|
currentFilteredType: number = 0;//all projects
|
||||||
projectName: string = "";
|
projectName: string = "";
|
||||||
|
|
||||||
subscription: Subscription;
|
|
||||||
loading: boolean = true;
|
loading: boolean = true;
|
||||||
|
|
||||||
get selecteType(): number {
|
get selecteType(): number {
|
||||||
return this.currentFilteredType;
|
return this.currentFilteredType;
|
||||||
}
|
}
|
||||||
set selecteType(_project: number) {
|
set selecteType(_project: number) {
|
||||||
|
this.currentFilteredType = _project;
|
||||||
if (window.sessionStorage) {
|
if (window.sessionStorage) {
|
||||||
window.sessionStorage['projectTypeValue'] = _project;
|
window.sessionStorage['projectTypeValue'] = _project;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
private projectService: ProjectService,
|
|
||||||
private messageHandlerService: MessageHandlerService,
|
|
||||||
private appConfigService: AppConfigService,
|
private appConfigService: AppConfigService,
|
||||||
private sessionService: SessionService,
|
private sessionService: SessionService) {
|
||||||
private deletionDialogService: ConfirmationDialogService,
|
|
||||||
private statisticHandler: StatisticHandler,
|
|
||||||
private ref: ChangeDetectorRef) {
|
|
||||||
this.subscription = deletionDialogService.confirmationConfirm$.subscribe(message => {
|
|
||||||
if (message &&
|
|
||||||
message.state === ConfirmationState.CONFIRMED &&
|
|
||||||
message.source === ConfirmationTargets.PROJECT) {
|
|
||||||
let projectId = message.data;
|
|
||||||
this.projectService
|
|
||||||
.deleteProject(projectId)
|
|
||||||
.subscribe(
|
|
||||||
response => {
|
|
||||||
this.messageHandlerService.showSuccess('PROJECT.DELETED_SUCCESS');
|
|
||||||
this.retrieve();
|
|
||||||
this.statisticHandler.refresh();
|
|
||||||
},
|
|
||||||
error => {
|
|
||||||
if (error && error.status === 412) {
|
|
||||||
this.messageHandlerService.showError('PROJECT.FAILED_TO_DELETE_PROJECT', '');
|
|
||||||
} else {
|
|
||||||
this.messageHandlerService.handleError(error);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ngOnInit(): void {
|
ngOnInit(): void {
|
||||||
@ -113,12 +61,6 @@ export class ProjectComponent implements OnInit, OnDestroy {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ngOnDestroy(): void {
|
|
||||||
if (this.subscription) {
|
|
||||||
this.subscription.unsubscribe();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
get projectCreationRestriction(): boolean {
|
get projectCreationRestriction(): boolean {
|
||||||
let account = this.sessionService.getCurrentUser();
|
let account = this.sessionService.getCurrentUser();
|
||||||
if (account) {
|
if (account) {
|
||||||
@ -132,105 +74,29 @@ export class ProjectComponent implements OnInit, OnDestroy {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
retrieve(state?: State): void {
|
|
||||||
this.projectName = "";
|
|
||||||
if (this.currentFilteredType !== 0) {
|
|
||||||
this.getProjects('', this.currentFilteredType - 1);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
this.getProjects();
|
|
||||||
}
|
|
||||||
|
|
||||||
getProjects(name?: string, isPublic?: number, page?: number, pageSize?: number): void {
|
|
||||||
this.loading = true;
|
|
||||||
this.projectService
|
|
||||||
.listProjects(name, isPublic, page, pageSize)
|
|
||||||
.subscribe(
|
|
||||||
response => {
|
|
||||||
this.changedProjects = response.json();
|
|
||||||
this.loading = false;
|
|
||||||
},
|
|
||||||
error => {
|
|
||||||
this.loading = false;
|
|
||||||
this.messageHandlerService.handleError(error);
|
|
||||||
}
|
|
||||||
);
|
|
||||||
let hnd = setInterval(()=>this.ref.markForCheck(), 100);
|
|
||||||
setTimeout(()=>clearInterval(hnd), 2000);
|
|
||||||
}
|
|
||||||
|
|
||||||
openModal(): void {
|
openModal(): void {
|
||||||
this.creationProject.newProject();
|
this.creationProject.newProject();
|
||||||
}
|
}
|
||||||
|
|
||||||
createProject(created: boolean) {
|
createProject(created: boolean) {
|
||||||
if (created) {
|
if (created) {
|
||||||
this.retrieve();
|
this.refresh();
|
||||||
this.statisticHandler.refresh();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
doSearchProjects(projectName: string): void {
|
doSearchProjects(projectName: string): void {
|
||||||
this.projectName = projectName;
|
this.projectName = projectName;
|
||||||
if (projectName === "") {
|
this.listProject.doSearchProject(this.projectName);
|
||||||
if (this.currentFilteredType === 0) {
|
|
||||||
this.getProjects();
|
|
||||||
} else {
|
|
||||||
this.getProjects(projectName, this.currentFilteredType - 1);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
this.getProjects(projectName);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
doFilterProjects($event: any): void {
|
doFilterProjects(): void {
|
||||||
if ($event && $event.target && $event.target["value"]) {
|
this.listProject.doFilterProject(this.selecteType);
|
||||||
this.projectName = "";
|
|
||||||
this.currentFilteredType = +$event.target["value"];
|
|
||||||
if (this.currentFilteredType === 0) {
|
|
||||||
this.getProjects();
|
|
||||||
} else {
|
|
||||||
this.getProjects("", this.currentFilteredType - 1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
toggleProject(p: Project) {
|
|
||||||
if (p) {
|
|
||||||
p.public === 0 ? p.public = 1 : p.public = 0;
|
|
||||||
this.projectService
|
|
||||||
.toggleProjectPublic(p.project_id, p.public)
|
|
||||||
.subscribe(
|
|
||||||
response => {
|
|
||||||
this.messageHandlerService.showSuccess('PROJECT.TOGGLED_SUCCESS');
|
|
||||||
this.statisticHandler.refresh();
|
|
||||||
if (this.currentFilteredType === 0) {
|
|
||||||
this.getProjects();
|
|
||||||
} else {
|
|
||||||
this.getProjects("", this.currentFilteredType - 1);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
error => this.messageHandlerService.handleError(error)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
deleteProject(p: Project) {
|
|
||||||
let deletionMessage = new ConfirmationMessage(
|
|
||||||
'PROJECT.DELETION_TITLE',
|
|
||||||
'PROJECT.DELETION_SUMMARY',
|
|
||||||
p.name,
|
|
||||||
p.project_id,
|
|
||||||
ConfirmationTargets.PROJECT,
|
|
||||||
ConfirmationButtons.DELETE_CANCEL
|
|
||||||
);
|
|
||||||
this.deletionDialogService.openComfirmDialog(deletionMessage);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
refresh(): void {
|
refresh(): void {
|
||||||
this.currentFilteredType = 0;
|
this.currentFilteredType = 0;
|
||||||
this.retrieve();
|
this.projectName = "";
|
||||||
this.statisticHandler.refresh();
|
this.listProject.refresh();
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
@ -14,6 +14,8 @@
|
|||||||
import { NgForm } from '@angular/forms';
|
import { NgForm } from '@angular/forms';
|
||||||
import { httpStatusCode, AlertType } from './shared.const';
|
import { httpStatusCode, AlertType } from './shared.const';
|
||||||
import { MessageService } from '../global-message/message.service';
|
import { MessageService } from '../global-message/message.service';
|
||||||
|
import { Comparator, State } from 'clarity-angular';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* To handle the error message body
|
* To handle the error message body
|
||||||
*
|
*
|
||||||
@ -107,3 +109,129 @@ export const maintainUrlQueryParmas = function (uri: string, key: string, value:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//Copy from ui library utils.ts
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Calculate page number by state
|
||||||
|
*/
|
||||||
|
export function calculatePage(state: State): number {
|
||||||
|
if (!state || !state.page) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return Math.ceil((state.page.to + 1) / state.page.size);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Comparator for fields with specific type.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
export class CustomComparator<T> implements Comparator<T> {
|
||||||
|
|
||||||
|
fieldName: string;
|
||||||
|
type: string;
|
||||||
|
|
||||||
|
constructor(fieldName: string, type: string) {
|
||||||
|
this.fieldName = fieldName;
|
||||||
|
this.type = type;
|
||||||
|
}
|
||||||
|
|
||||||
|
compare(a: { [key: string]: any | any[] }, b: { [key: string]: any | any[] }) {
|
||||||
|
let comp = 0;
|
||||||
|
if (a && b) {
|
||||||
|
let fieldA = a[this.fieldName];
|
||||||
|
let fieldB = b[this.fieldName];
|
||||||
|
switch (this.type) {
|
||||||
|
case "number":
|
||||||
|
comp = fieldB - fieldA;
|
||||||
|
break;
|
||||||
|
case "date":
|
||||||
|
comp = new Date(fieldB).getTime() - new Date(fieldA).getTime();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return comp;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Filter columns via RegExp
|
||||||
|
*
|
||||||
|
* @export
|
||||||
|
* @param {State} state
|
||||||
|
* @returns {void}
|
||||||
|
*/
|
||||||
|
export function doFiltering<T extends { [key: string]: any | any[] }>(items: T[], state: State): T[] {
|
||||||
|
if (!items || items.length === 0) {
|
||||||
|
return items;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!state || !state.filters || state.filters.length === 0) {
|
||||||
|
return items;
|
||||||
|
}
|
||||||
|
|
||||||
|
state.filters.forEach((filter: {
|
||||||
|
property: string;
|
||||||
|
value: string;
|
||||||
|
}) => {
|
||||||
|
items = items.filter(item => regexpFilter(filter["value"], item[filter["property"]]));
|
||||||
|
});
|
||||||
|
|
||||||
|
return items;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Match items via RegExp
|
||||||
|
*
|
||||||
|
* @export
|
||||||
|
* @param {string} terms
|
||||||
|
* @param {*} testedValue
|
||||||
|
* @returns {boolean}
|
||||||
|
*/
|
||||||
|
export function regexpFilter(terms: string, testedValue: any): boolean {
|
||||||
|
let reg = new RegExp('.*' + terms + '.*', 'i');
|
||||||
|
return reg.test(testedValue);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sorting the data by column
|
||||||
|
*
|
||||||
|
* @export
|
||||||
|
* @template T
|
||||||
|
* @param {T[]} items
|
||||||
|
* @param {State} state
|
||||||
|
* @returns {T[]}
|
||||||
|
*/
|
||||||
|
export function doSorting<T extends { [key: string]: any | any[] }>(items: T[], state: State): T[] {
|
||||||
|
if (!items || items.length === 0) {
|
||||||
|
return items;
|
||||||
|
}
|
||||||
|
if (!state || !state.sort) {
|
||||||
|
return items;
|
||||||
|
}
|
||||||
|
|
||||||
|
return items.sort((a: T, b: T) => {
|
||||||
|
let comp: number = 0;
|
||||||
|
if (typeof state.sort.by !== "string") {
|
||||||
|
comp = state.sort.by.compare(a, b);
|
||||||
|
} else {
|
||||||
|
let propA = a[state.sort.by.toString()], propB = b[state.sort.by.toString()];
|
||||||
|
if (typeof propA === "string") {
|
||||||
|
comp = propA.localeCompare(propB);
|
||||||
|
} else {
|
||||||
|
if (propA > propB) {
|
||||||
|
comp = 1;
|
||||||
|
} else if (propA < propB) {
|
||||||
|
comp = -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (state.sort.reverse) {
|
||||||
|
comp = -comp;
|
||||||
|
}
|
||||||
|
|
||||||
|
return comp;
|
||||||
|
});
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user