Add page size options to datagrid

Signed-off-by: AllForNothing <sshijun@vmware.com>
This commit is contained in:
AllForNothing 2020-10-16 17:17:33 +08:00
parent f25eaaf1d1
commit 7b32fdb9f9
55 changed files with 460 additions and 474 deletions

View File

@ -5,7 +5,7 @@
"angular-cli": {}, "angular-cli": {},
"scripts": { "scripts": {
"postinstall": "node scripts/convert-yaml-to-json.js && ng-swagger-gen -i ng-swagger-gen/swagger.json -o ng-swagger-gen && node scripts/delete-swagger-json.js", "postinstall": "node scripts/convert-yaml-to-json.js && ng-swagger-gen -i ng-swagger-gen/swagger.json -o ng-swagger-gen && node scripts/delete-swagger-json.js",
"start": "ng serve --ssl true --ssl-key ssl/server.key --ssl-cert ssl/server.crt --host 0.0.0.0 --proxy-config proxy.config.json", "start": "node --max_old_space_size=2048 ./node_modules/@angular/cli/bin/ng serve --ssl true --ssl-key ssl/server.key --ssl-cert ssl/server.crt --host 0.0.0.0 --proxy-config proxy.config.json",
"lint": "tslint \"src/**/*.ts\"", "lint": "tslint \"src/**/*.ts\"",
"lint_fix": "tslint --fix \"src/**/*.ts\"", "lint_fix": "tslint --fix \"src/**/*.ts\"",
"test": "node --max_old_space_size=2048 ./node_modules/@angular/cli/bin/ng test --code-coverage", "test": "node --max_old_space_size=2048 ./node_modules/@angular/cli/bin/ng test --code-coverage",

View File

@ -95,8 +95,10 @@
<scanner-metadata *clrIfExpanded [uid]="scanner.uuid" ngProjectAs="clr-dg-row-detail"></scanner-metadata> <scanner-metadata *clrIfExpanded [uid]="scanner.uuid" ngProjectAs="clr-dg-row-detail"></scanner-metadata>
</clr-dg-row> </clr-dg-row>
<clr-dg-footer> <clr-dg-footer>
<clr-dg-pagination [clrDgPageSize]="15">
<clr-dg-page-size [clrPageSizeOptions]="[15,25,50]">{{"PAGINATION.PAGE_SIZE" | translate}}</clr-dg-page-size>
<span *ngIf="scanners?.length > 0">1 - {{scanners?.length}} {{'WEBHOOK.OF' | translate}} </span> {{scanners?.length}} {{'WEBHOOK.ITEMS' | translate}} <span *ngIf="scanners?.length > 0">1 - {{scanners?.length}} {{'WEBHOOK.OF' | translate}} </span> {{scanners?.length}} {{'WEBHOOK.ITEMS' | translate}}
<clr-dg-pagination [clrDgPageSize]="10"></clr-dg-pagination> </clr-dg-pagination>
</clr-dg-footer> </clr-dg-footer>
</clr-datagrid> </clr-datagrid>
</div> </div>

View File

@ -4,7 +4,7 @@
{{ 'SIDE_NAV.DISTRIBUTIONS.INSTANCES' | translate }} {{ 'SIDE_NAV.DISTRIBUTIONS.INSTANCES' | translate }}
</h2> </h2>
<div> <div>
<clr-datagrid (clrDgRefresh)="loadData()" [clrDgLoading]="inProgress" [(clrDgSelected)]="selectedRow"> <clr-datagrid (clrDgRefresh)="loadData($event)" [clrDgLoading]="inProgress" [(clrDgSelected)]="selectedRow">
<clr-dg-action-bar> <clr-dg-action-bar>
<div class="clr-row"> <div class="clr-row">
<div class="clr-col-7"> <div class="clr-col-7">
@ -110,6 +110,7 @@
</clr-dg-row> </clr-dg-row>
<clr-dg-footer> <clr-dg-footer>
<clr-dg-pagination #pagination [clrDgPageSize]="pageSize" [clrDgTotalItems]="totalCount" [(clrDgPage)]="currentPage"> <clr-dg-pagination #pagination [clrDgPageSize]="pageSize" [clrDgTotalItems]="totalCount" [(clrDgPage)]="currentPage">
<clr-dg-page-size [clrPageSizeOptions]="[15,25,50]">{{"PAGINATION.PAGE_SIZE" | translate}}</clr-dg-page-size>
<span *ngIf="totalCount">{{ pagination.firstItem + 1 }} - {{ pagination.lastItem + 1 }} {{ 'HELM_CHART.OF' | translate }} </span> <span *ngIf="totalCount">{{ pagination.firstItem + 1 }} - {{ pagination.lastItem + 1 }} {{ 'HELM_CHART.OF' | translate }} </span>
<span>{{ totalCount }} {{ 'HELM_CHART.ITEMS' | translate }}</span> <span>{{ totalCount }} {{ 'HELM_CHART.ITEMS' | translate }}</span>
</clr-dg-pagination> </clr-dg-pagination>

View File

@ -28,6 +28,7 @@ import { Instance } from "../../../../ng-swagger-gen/models/instance";
import { PreheatService } from "../../../../ng-swagger-gen/services/preheat.service"; import { PreheatService } from "../../../../ng-swagger-gen/services/preheat.service";
import { Metadata } from '../../../../ng-swagger-gen/models/metadata'; import { Metadata } from '../../../../ng-swagger-gen/models/metadata';
import { FrontInstance, HEALTHY, UNHEALTHY } from '../distribution-interface'; import { FrontInstance, HEALTHY, UNHEALTHY } from '../distribution-interface';
import { ClrDatagridStateInterface } from '@clr/angular';
interface MultiOperateData { interface MultiOperateData {
operation: string; operation: string;
@ -115,7 +116,10 @@ export class DistributionInstancesComponent implements OnInit, OnDestroy {
); );
} }
loadData() { loadData(state?: ClrDatagridStateInterface) {
if (state && state.page) {
this.pageSize = state.page.size;
}
this.selectedRow = []; this.selectedRow = [];
const queryParam: PreheatService.ListInstancesParams = { const queryParam: PreheatService.ListInstancesParams = {
page: this.currentPage, page: this.currentPage,

View File

@ -30,7 +30,7 @@
</div> </div>
</div> </div>
<div class="col-lg-12 col-md-12 col-sm-12 col-xs-12 datagrid-margin-top "> <div class="col-lg-12 col-md-12 col-sm-12 col-xs-12 datagrid-margin-top ">
<clr-datagrid [clrDgLoading]="loading" (clrDgRefresh)="retrieve()"> <clr-datagrid [clrDgLoading]="loading" (clrDgRefresh)="retrieve($event)">
<clr-dg-column>{{'AUDIT_LOG.USERNAME' | translate}}</clr-dg-column> <clr-dg-column>{{'AUDIT_LOG.USERNAME' | translate}}</clr-dg-column>
<clr-dg-column>{{'AUDIT_LOG.RESOURCE' | translate}}</clr-dg-column> <clr-dg-column>{{'AUDIT_LOG.RESOURCE' | translate}}</clr-dg-column>
<clr-dg-column>{{'AUDIT_LOG.RESOURCE_TYPE' | translate}}</clr-dg-column> <clr-dg-column>{{'AUDIT_LOG.RESOURCE_TYPE' | translate}}</clr-dg-column>
@ -44,8 +44,11 @@
<clr-dg-cell>{{l.op_time | date: 'short'}}</clr-dg-cell> <clr-dg-cell>{{l.op_time | date: 'short'}}</clr-dg-cell>
</clr-dg-row> </clr-dg-row>
<clr-dg-footer> <clr-dg-footer>
<clr-dg-pagination #pagination [clrDgPageSize]="pageSize" [(clrDgPage)]="currentPage" [clrDgTotalItems]="totalRecordCount">
<clr-dg-page-size [clrPageSizeOptions]="[15,25,50]">{{"PAGINATION.PAGE_SIZE" | translate}}</clr-dg-page-size>
<span *ngIf="showPaginationIndex">{{pagination.firstItem + 1}} - {{pagination.lastItem +1 }} {{'AUDIT_LOG.OF' | translate}} </span> {{totalRecordCount }} {{'AUDIT_LOG.ITEMS' | translate}} <span *ngIf="showPaginationIndex">{{pagination.firstItem + 1}} - {{pagination.lastItem +1 }} {{'AUDIT_LOG.OF' | translate}} </span> {{totalRecordCount }} {{'AUDIT_LOG.ITEMS' | translate}}
<clr-dg-pagination #pagination [clrDgPageSize]="15" [(clrDgPage)]="currentPage" [clrDgTotalItems]="totalRecordCount"></clr-dg-pagination> </clr-dg-pagination>
</clr-dg-footer> </clr-dg-footer>
</clr-datagrid> </clr-datagrid>
</div> </div>

View File

@ -19,6 +19,8 @@ import { ProjectService } from "../../../ng-swagger-gen/services/project.service
import { AuditLog } from "../../../ng-swagger-gen/models/audit-log"; import { AuditLog } from "../../../ng-swagger-gen/models/audit-log";
import { Project } from "../project/project"; import { Project } from "../project/project";
import { finalize } from "rxjs/operators"; import { finalize } from "rxjs/operators";
import {DEFAULT_PAGE_SIZE} from "../../lib/utils/utils";
import {ClrDatagridStateInterface} from "@clr/angular";
const optionalSearch: {} = { 0: 'AUDIT_LOG.ADVANCED', 1: 'AUDIT_LOG.SIMPLE' }; const optionalSearch: {} = { 0: 'AUDIT_LOG.ADVANCED', 1: 'AUDIT_LOG.SIMPLE' };
@ -72,7 +74,7 @@ export class AuditLogComponent implements OnInit {
]; ];
pageOffset = 1; pageOffset = 1;
pageSize = 15; pageSize = DEFAULT_PAGE_SIZE;
totalRecordCount = 0; totalRecordCount = 0;
currentPage = 1; currentPage = 1;
totalPage = 0; totalPage = 0;
@ -98,7 +100,10 @@ export class AuditLogComponent implements OnInit {
} }
} }
retrieve() { retrieve(state?: ClrDatagridStateInterface) {
if (state && state.page) {
this.pageSize = state.page.size;
}
const arr: string[] = []; const arr: string[] = [];
if (this.queryUsername) { if (this.queryUsername) {
arr.push(`username=~${this.queryUsername}`); arr.push(`username=~${this.queryUsername}`);

View File

@ -100,6 +100,7 @@
</clr-dg-row> </clr-dg-row>
<clr-dg-footer> <clr-dg-footer>
<clr-dg-pagination #pagination [clrDgPageSize]="pageSize" [clrDgTotalItems]="totalCount"> <clr-dg-pagination #pagination [clrDgPageSize]="pageSize" [clrDgTotalItems]="totalCount">
<clr-dg-page-size [clrPageSizeOptions]="[15,25,50]">{{"PAGINATION.PAGE_SIZE" | translate}}</clr-dg-page-size>
<span *ngIf="totalCount"> <span *ngIf="totalCount">
{{pagination.firstItem + 1}} - {{pagination.lastItem + 1}} {{'HELM_CHART.OF' | translate}} {{pagination.firstItem + 1}} - {{pagination.lastItem + 1}} {{'HELM_CHART.OF' | translate}}
</span> </span>

View File

@ -21,7 +21,7 @@
</div> </div>
<div class="row"> <div class="row">
<div *ngIf="!isCardView" class="col-lg-12 col-md-12 col-sm-12 col-xs-12"> <div *ngIf="!isCardView" class="col-lg-12 col-md-12 col-sm-12 col-xs-12">
<clr-datagrid (clrDgRefresh)="refresh()" [clrDgLoading]="loading" [(clrDgSelected)]="selectedRows"> <clr-datagrid [clrDgLoading]="loading" [(clrDgSelected)]="selectedRows">
<clr-dg-action-bar> <clr-dg-action-bar>
<button type="button" id="helm-chart-upload" class="btn btn-secondary" <button type="button" id="helm-chart-upload" class="btn btn-secondary"
[disabled]="!hasUploadHelmChartsPermission" (click)="onChartUpload()"> [disabled]="!hasUploadHelmChartsPermission" (click)="onChartUpload()">
@ -41,7 +41,7 @@
<clr-dg-column>{{'HELM_CHART.CHARTVERSIONS' | translate}}</clr-dg-column> <clr-dg-column>{{'HELM_CHART.CHARTVERSIONS' | translate}}</clr-dg-column>
<clr-dg-column>{{'HELM_CHART.CREATED' | translate}}</clr-dg-column> <clr-dg-column>{{'HELM_CHART.CREATED' | translate}}</clr-dg-column>
<clr-dg-placeholder>{{'HELM_CHART.PLACEHOLDER' | translate }}</clr-dg-placeholder> <clr-dg-placeholder>{{'HELM_CHART.PLACEHOLDER' | translate }}</clr-dg-placeholder>
<clr-dg-row *ngFor="let chart of charts" [clrDgItem]="chart"> <clr-dg-row *clrDgItems="let chart of charts" [clrDgItem]="chart">
<clr-dg-cell> <clr-dg-cell>
<span class="list-img"> <span class="list-img">
<img class="size-24 margin-right-12" [src]="chart.icon ?chart.icon:chartDefaultIcon" (error)="getDefaultIcon(chart);" /> <img class="size-24 margin-right-12" [src]="chart.icon ?chart.icon:chartDefaultIcon" (error)="getDefaultIcon(chart);" />
@ -54,6 +54,7 @@
</clr-dg-row> </clr-dg-row>
<clr-dg-footer> <clr-dg-footer>
<clr-dg-pagination #pagination [clrDgPageSize]="pageSize" [clrDgTotalItems]="totalCount"> <clr-dg-pagination #pagination [clrDgPageSize]="pageSize" [clrDgTotalItems]="totalCount">
<clr-dg-page-size [clrPageSizeOptions]="[15,25,50]">{{"PAGINATION.PAGE_SIZE" | translate}}</clr-dg-page-size>
<span *ngIf="totalCount"> <span *ngIf="totalCount">
{{pagination.firstItem + 1}} - {{pagination.lastItem + 1}} {{'HELM_CHART.OF' | translate}} {{pagination.firstItem + 1}} - {{pagination.lastItem + 1}} {{'HELM_CHART.OF' | translate}}
</span> </span>

View File

@ -25,8 +25,10 @@
<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>
<clr-dg-pagination #pagination [clrDgPageSize]="pageSize" [(clrDgPage)]="currentPage" [clrDgTotalItems]="totalCount">
<clr-dg-page-size [clrPageSizeOptions]="[15,25,50]">{{"PAGINATION.PAGE_SIZE" | translate}}</clr-dg-page-size>
<span *ngIf="totalCount">{{pagination.firstItem + 1}} - {{pagination.lastItem +1 }} {{'PROJECT.OF' | translate}} </span> {{totalCount <span *ngIf="totalCount">{{pagination.firstItem + 1}} - {{pagination.lastItem +1 }} {{'PROJECT.OF' | translate}} </span> {{totalCount
}} {{'PROJECT.ITEMS' | translate}} }} {{'PROJECT.ITEMS' | translate}}
<clr-dg-pagination #pagination [clrDgPageSize]="pageSize" [(clrDgPage)]="currentPage" [clrDgTotalItems]="totalCount"></clr-dg-pagination> </clr-dg-pagination>
</clr-dg-footer> </clr-dg-footer>
</clr-datagrid> </clr-datagrid>

View File

@ -36,6 +36,7 @@ import { OperationService } from "../../../lib/components/operation/operation.se
import { operateChanges, OperateInfo, OperationState } from "../../../lib/components/operation/operate"; import { operateChanges, OperateInfo, OperationState } from "../../../lib/components/operation/operate";
import { errorHandler } from "../../../lib/utils/shared/shared.utils"; import { errorHandler } from "../../../lib/utils/shared/shared.utils";
import {HttpErrorResponse} from "@angular/common/http"; import {HttpErrorResponse} from "@angular/common/http";
import { ClrDatagridStateInterface } from '@clr/angular';
@Component({ @Component({
selector: "list-project", selector: "list-project",
@ -135,10 +136,11 @@ export class ListProjectComponent implements OnDestroy {
this.router.navigate(linkUrl); this.router.navigate(linkUrl);
} }
clrLoad(state: State) { clrLoad(state: ClrDatagridStateInterface) {
if (!state || !state.page) { if (!state || !state.page) {
return; return;
} }
this.pageSize = state.page.size;
this.selectedRow = []; this.selectedRow = [];
// Keep state for future filtering and sorting // Keep state for future filtering and sorting

View File

@ -46,9 +46,11 @@
</clr-dg-cell> </clr-dg-cell>
</clr-dg-row> </clr-dg-row>
<clr-dg-footer> <clr-dg-footer>
<clr-dg-pagination #pagination [clrDgPageSize]="15">
<clr-dg-page-size [clrPageSizeOptions]="[15,25,50]">{{"PAGINATION.PAGE_SIZE" | translate}}</clr-dg-page-size>
<span *ngIf="members?.length">{{pagination.firstItem + 1}} - {{pagination.lastItem +1 }} {{'MEMBER.OF' | translate}} </span> <span *ngIf="members?.length">{{pagination.firstItem + 1}} - {{pagination.lastItem +1 }} {{'MEMBER.OF' | translate}} </span>
{{members?.length }} {{'MEMBER.ITEMS' | translate}} {{members?.length }} {{'MEMBER.ITEMS' | translate}}
<clr-dg-pagination #pagination [clrDgPageSize]="15"></clr-dg-pagination> </clr-dg-pagination>
</clr-dg-footer> </clr-dg-footer>
</clr-datagrid> </clr-datagrid>
</div> </div>

View File

@ -144,15 +144,17 @@
<clr-dg-cell>{{p.description}}</clr-dg-cell> <clr-dg-cell>{{p.description}}</clr-dg-cell>
</clr-dg-row> </clr-dg-row>
<clr-dg-footer> <clr-dg-footer>
<clr-dg-pagination [clrDgPageSize]="10">
<clr-dg-page-size [clrPageSizeOptions]="[10,25,50]">{{"PAGINATION.PAGE_SIZE" | translate}}</clr-dg-page-size>
<span *ngIf="policyList?.length > 0">1 - {{policyList?.length}} {{'WEBHOOK.OF' | translate}} </span> {{policyList?.length}} {{'WEBHOOK.ITEMS' | translate}} <span *ngIf="policyList?.length > 0">1 - {{policyList?.length}} {{'WEBHOOK.OF' | translate}} </span> {{policyList?.length}} {{'WEBHOOK.ITEMS' | translate}}
<clr-dg-pagination [clrDgPageSize]="10"></clr-dg-pagination> </clr-dg-pagination>
</clr-dg-footer> </clr-dg-footer>
</clr-datagrid> </clr-datagrid>
</div> </div>
<div class="col-lg-12 col-md-12 col-sm-12 col-xs-12 " *ngIf="selectedRow"> <div class="col-lg-12 col-md-12 col-sm-12 col-xs-12 " *ngIf="selectedRow">
<h4 class="mt-2">{{'P2P_PROVIDER.EXECUTIONS' | translate}}</h4> <h4 class="mt-2">{{'P2P_PROVIDER.EXECUTIONS' | translate}}</h4>
<clr-datagrid [(clrDgSingleSelected)]="selectedExecutionRow" [clrDgLoading]="jobsLoading" <clr-datagrid [(clrDgSingleSelected)]="selectedExecutionRow" [clrDgLoading]="jobsLoading"
(clrDgRefresh)="clrLoadJobs(null,true)"> (clrDgRefresh)="clrLoadJobs(null,true, $event)">
<clr-dg-action-bar> <clr-dg-action-bar>
<div class="clr-row"> <div class="clr-row">
<div class="clr-col-7"> <div class="clr-col-7">
@ -202,11 +204,14 @@
<clr-dg-cell>{{execution.vendor_type}}</clr-dg-cell> <clr-dg-cell>{{execution.vendor_type}}</clr-dg-cell>
</clr-dg-row> </clr-dg-row>
<clr-dg-footer> <clr-dg-footer>
<clr-dg-pagination #pagination [(clrDgPage)]="currentExecutionPage" [clrDgPageSize]="pageSize"
[clrDgTotalItems]="totalExecutionCount">
<clr-dg-page-size [clrPageSizeOptions]="[15,25,50]">{{"PAGINATION.PAGE_SIZE" | translate}}</clr-dg-page-size>
<span *ngIf="totalExecutionCount">{{pagination.firstItem + 1}} <span *ngIf="totalExecutionCount">{{pagination.firstItem + 1}}
- {{pagination.lastItem + 1}} {{'REPLICATION.OF' | translate}}</span> - {{pagination.lastItem + 1}} {{'REPLICATION.OF' | translate}}</span>
{{totalExecutionCount}} {{'REPLICATION.ITEMS' | translate}} {{totalExecutionCount}} {{'REPLICATION.ITEMS' | translate}}
<clr-dg-pagination #pagination [(clrDgPage)]="currentExecutionPage" [clrDgPageSize]="pageSize" </clr-dg-pagination>
[clrDgTotalItems]="totalExecutionCount"></clr-dg-pagination>
</clr-dg-footer> </clr-dg-footer>
</clr-datagrid> </clr-datagrid>
</div> </div>

View File

@ -20,14 +20,14 @@ import { Project } from '../../project';
import { ConfirmationButtons, ConfirmationState, ConfirmationTargets } from '../../../shared/shared.const'; import { ConfirmationButtons, ConfirmationState, ConfirmationTargets } from '../../../shared/shared.const';
import { ConfirmationMessage } from '../../../shared/confirmation-dialog/confirmation-message'; import { ConfirmationMessage } from '../../../shared/confirmation-dialog/confirmation-message';
import { ConfirmationDialogComponent } from '../../../shared/confirmation-dialog/confirmation-dialog.component'; import { ConfirmationDialogComponent } from '../../../shared/confirmation-dialog/confirmation-dialog.component';
import { clone, CustomComparator } from '../../../../lib/utils/utils'; import {clone, CustomComparator, DEFAULT_PAGE_SIZE} from '../../../../lib/utils/utils';
import { forkJoin, Observable, Subject, Subscription } from 'rxjs'; import { forkJoin, Observable, Subject, Subscription } from 'rxjs';
import { import {
ClrDatagridComparatorInterface, ClrDatagridComparatorInterface,
UserPermissionService, UserPermissionService,
USERSTATICPERMISSION USERSTATICPERMISSION
} from '../../../../lib/services'; } from '../../../../lib/services';
import { ClrLoadingState } from '@clr/angular'; import {ClrDatagridStateInterface, ClrLoadingState} from '@clr/angular';
import { import {
EXECUTION_STATUS, EXECUTION_STATUS,
FILTER_TYPE, FILTER_TYPE,
@ -72,7 +72,7 @@ export class PolicyComponent implements OnInit, OnDestroy {
creationTimeComparator: ClrDatagridComparatorInterface<Execution> = new CustomComparator<Execution>("creation_time", "date"); creationTimeComparator: ClrDatagridComparatorInterface<Execution> = new CustomComparator<Execution>("creation_time", "date");
executionList: Execution[] = []; executionList: Execution[] = [];
currentExecutionPage: number = 1; currentExecutionPage: number = 1;
pageSize: number = 10; pageSize: number = DEFAULT_PAGE_SIZE;
totalExecutionCount: number = 0; totalExecutionCount: number = 0;
filterKey: string = 'id'; filterKey: string = 'id';
searchString: string; searchString: string;
@ -342,8 +342,11 @@ export class PolicyComponent implements OnInit, OnDestroy {
this.messageHandlerService.showSuccess(message); this.messageHandlerService.showSuccess(message);
this.refresh(); this.refresh();
} }
clrLoadJobs(chosenPolicy: PreheatPolicy, withLoading: boolean) { clrLoadJobs(chosenPolicy: PreheatPolicy, withLoading: boolean, state?: ClrDatagridStateInterface) {
if (this.selectedRow) { if (this.selectedRow) {
if (state && state.page) {
this.pageSize = state.page.size;
}
if (withLoading) { if (withLoading) {
// if datagrid is under control of *ngIf, should add timeout in case of ng changes checking error // if datagrid is under control of *ngIf, should add timeout in case of ng changes checking error
setTimeout(() => { setTimeout(() => {

View File

@ -76,7 +76,7 @@
<div class="tasks-detail"> <div class="tasks-detail">
<h3 class="modal-title">{{'P2P_PROVIDER.TASKS' | translate}}</h3> <h3 class="modal-title">{{'P2P_PROVIDER.TASKS' | translate}}</h3>
<clr-datagrid (clrDgRefresh)="clrLoadTasks(true)" [clrDgLoading]="loading"> <clr-datagrid (clrDgRefresh)="clrLoadTasks(true, $event)" [clrDgLoading]="loading">
<clr-dg-action-bar> <clr-dg-action-bar>
<div class="row flex-end"> <div class="row flex-end">
<div class="select filter-tag clr-select-wrapper" [hidden]="!isOpenFilterTag"> <div class="select filter-tag clr-select-wrapper" [hidden]="!isOpenFilterTag">
@ -133,11 +133,13 @@
</clr-dg-cell> </clr-dg-cell>
</clr-dg-row> </clr-dg-row>
<clr-dg-footer> <clr-dg-footer>
<clr-dg-pagination #pagination [(clrDgPage)]="currentPage" [clrDgPageSize]="pageSize"
[clrDgTotalItems]="totalCount">
<clr-dg-page-size [clrPageSizeOptions]="[15,25,50]">{{"PAGINATION.PAGE_SIZE" | translate}}</clr-dg-page-size>
<span *ngIf="totalCount">{{pagination.firstItem + 1}} <span *ngIf="totalCount">{{pagination.firstItem + 1}}
- {{pagination.lastItem + 1}} {{'REPLICATION.OF' | translate}}</span> - {{pagination.lastItem + 1}} {{'REPLICATION.OF' | translate}}</span>
{{totalCount}} {{'REPLICATION.ITEMS' | translate}} {{totalCount}} {{'REPLICATION.ITEMS' | translate}}
<clr-dg-pagination #pagination [(clrDgPage)]="currentPage" [clrDgPageSize]="pageSize" </clr-dg-pagination>
[clrDgTotalItems]="totalCount"></clr-dg-pagination>
</clr-dg-footer> </clr-dg-footer>
</clr-datagrid> </clr-datagrid>
</div> </div>

View File

@ -11,7 +11,7 @@ import { Execution } from '../../../../../ng-swagger-gen/models/execution';
import { PreheatService } from '../../../../../ng-swagger-gen/services/preheat.service'; import { PreheatService } from '../../../../../ng-swagger-gen/services/preheat.service';
import { EXECUTION_STATUS, P2pProviderService, TIME_OUT } from '../p2p-provider.service'; import { EXECUTION_STATUS, P2pProviderService, TIME_OUT } from '../p2p-provider.service';
import { forkJoin, Observable, Subject, Subscription } from 'rxjs'; import { forkJoin, Observable, Subject, Subscription } from 'rxjs';
import { ClrLoadingState } from '@clr/angular'; import {ClrDatagridStateInterface, ClrLoadingState} from '@clr/angular';
@Component({ @Component({
selector: 'task-list', selector: 'task-list',
@ -220,10 +220,13 @@ export class TaskListComponent implements OnInit, OnDestroy {
return this.preheatService.rootUrl return this.preheatService.rootUrl
+ `/projects/${this.projectName}/preheat/policies/${this.preheatPolicyName}/executions/${this.executionId}/tasks/${taskId}/logs`; + `/projects/${this.projectName}/preheat/policies/${this.preheatPolicyName}/executions/${this.executionId}/tasks/${taskId}/logs`;
} }
clrLoadTasks(withLoading): void { clrLoadTasks(withLoading, state?: ClrDatagridStateInterface): void {
if (withLoading) { if (withLoading) {
this.loading = true; this.loading = true;
} }
if (state && state.page) {
this.pageSize = state.page.size;
}
let params: string; let params: string;
if (this.searchString) { if (this.searchString) {
params = encodeURIComponent(`${this.filterKey}=~${this.searchString}`); params = encodeURIComponent(`${this.filterKey}=~${this.searchString}`);

View File

@ -310,10 +310,12 @@
</clr-dg-cell> </clr-dg-cell>
</clr-dg-row> </clr-dg-row>
<clr-dg-footer> <clr-dg-footer>
<clr-dg-pagination #pagination [clrDgTotalItems]="totalCount" [(clrDgPage)]="currentPage" [clrDgPageSize]="pageSize">
<clr-dg-page-size [clrPageSizeOptions]="[15,25,50]">{{"PAGINATION.PAGE_SIZE" | translate}}</clr-dg-page-size>
<span *ngIf="totalCount">{{pagination.firstItem + 1}} - {{pagination.lastItem + 1}} <span *ngIf="totalCount">{{pagination.firstItem + 1}} - {{pagination.lastItem + 1}}
{{'REPOSITORY.OF' | translate}}</span> {{totalCount}} {{'REPOSITORY.OF' | translate}}</span> {{totalCount}}
{{'REPOSITORY.ITEMS' | translate}}&nbsp;&nbsp;&nbsp;&nbsp; {{'REPOSITORY.ITEMS' | translate}}&nbsp;&nbsp;&nbsp;&nbsp;
<clr-dg-pagination #pagination [clrDgTotalItems]="totalCount" [(clrDgPage)]="currentPage" [clrDgPageSize]="pageSize"></clr-dg-pagination> </clr-dg-pagination>
</clr-dg-footer> </clr-dg-footer>
</clr-datagrid> </clr-datagrid>
</div> </div>

View File

@ -311,6 +311,7 @@ export class ArtifactListTabComponent implements OnInit, OnDestroy {
if (!state || !state.page) { if (!state || !state.page) {
return; return;
} }
this.pageSize = state.page.size;
this.selectedRow = []; this.selectedRow = [];
// Keep it for future filtering and sorting // Keep it for future filtering and sorting

View File

@ -73,8 +73,10 @@
</clr-dg-row> </clr-dg-row>
<clr-dg-footer> <clr-dg-footer>
<clr-dg-pagination #pagination [clrDgPageSize]="25" [clrDgTotalItems]="scanningResults?.length">
<clr-dg-page-size [clrPageSizeOptions]="[15,25,50]">{{"PAGINATION.PAGE_SIZE" | translate}}</clr-dg-page-size>
<span *ngIf="scanningResults?.length">{{pagination.firstItem + 1}} - {{pagination.lastItem + 1}} {{'VULNERABILITY.GRID.FOOT_OF' | translate}}</span> {{scanningResults?.length}} {{'VULNERABILITY.GRID.FOOT_ITEMS' | translate}} <span *ngIf="scanningResults?.length">{{pagination.firstItem + 1}} - {{pagination.lastItem + 1}} {{'VULNERABILITY.GRID.FOOT_OF' | translate}}</span> {{scanningResults?.length}} {{'VULNERABILITY.GRID.FOOT_ITEMS' | translate}}
<clr-dg-pagination #pagination [clrDgPageSize]="25" [clrDgTotalItems]="scanningResults?.length"></clr-dg-pagination> </clr-dg-pagination>
</clr-dg-footer> </clr-dg-footer>
</clr-datagrid> </clr-datagrid>
</div> </div>

View File

@ -71,9 +71,11 @@
</clr-dg-row> </clr-dg-row>
<clr-dg-footer> <clr-dg-footer>
<clr-dg-pagination #pagination [clrDgTotalItems]="totalCount" [(clrDgPage)]="currentPage" [clrDgPageSize]="pageSize">
<clr-dg-page-size [clrPageSizeOptions]="[15,25,50]">{{"PAGINATION.PAGE_SIZE" | translate}}</clr-dg-page-size>
<span *ngIf="totalCount">{{pagination.firstItem + 1}} - {{pagination.lastItem + 1}} <span *ngIf="totalCount">{{pagination.firstItem + 1}} - {{pagination.lastItem + 1}}
{{'TAG.OF' | translate}} {{totalCount}} {{'TAG.ITEMS' | translate}}</span> {{'TAG.OF' | translate}} {{totalCount}} {{'TAG.ITEMS' | translate}}</span>
<clr-dg-pagination #pagination [clrDgTotalItems]="totalCount" [(clrDgPage)]="currentPage" [clrDgPageSize]="pageSize"></clr-dg-pagination> </clr-dg-pagination>
</clr-dg-footer> </clr-dg-footer>
</clr-datagrid> </clr-datagrid>

View File

@ -121,6 +121,7 @@ export class ArtifactTagComponent implements OnInit, OnDestroy {
if (!state || !state.page) { if (!state || !state.page) {
return ; return ;
} }
this.pageSize = state.page.size;
let pageNumber: number = calculatePage(state); let pageNumber: number = calculatePage(state);
if (pageNumber <= 0) { pageNumber = 1; } if (pageNumber <= 0) { pageNumber = 1; }
let params: ArtifactService.ListTagsParams = { let params: ArtifactService.ListTagsParams = {

View File

@ -40,9 +40,11 @@
<clr-dg-cell>{{r.update_time | date:'short'}}</clr-dg-cell> <clr-dg-cell>{{r.update_time | date:'short'}}</clr-dg-cell>
</clr-dg-row> </clr-dg-row>
<clr-dg-footer> <clr-dg-footer>
<clr-dg-pagination #pagination [(clrDgPage)]="currentPage" [clrDgPageSize]="pageSize" [clrDgTotalItems]="totalCount">
<clr-dg-page-size [clrPageSizeOptions]="[15,25,50]">{{"PAGINATION.PAGE_SIZE" | translate}}</clr-dg-page-size>
<span *ngIf="totalCount">{{pagination.firstItem + 1}} - {{pagination.lastItem + 1}} {{'REPOSITORY.OF' | translate}}</span> <span *ngIf="totalCount">{{pagination.firstItem + 1}} - {{pagination.lastItem + 1}} {{'REPOSITORY.OF' | translate}}</span>
{{totalCount}} {{'REPOSITORY.ITEMS' | translate}} {{totalCount}} {{'REPOSITORY.ITEMS' | translate}}
<clr-dg-pagination #pagination [(clrDgPage)]="currentPage" [clrDgPageSize]="pageSize" [clrDgTotalItems]="totalCount"></clr-dg-pagination> </clr-dg-pagination>
</clr-dg-footer> </clr-dg-footer>
</clr-datagrid> </clr-datagrid>
</div> </div>

View File

@ -357,6 +357,7 @@ export class RepositoryGridviewComponent implements OnChanges, OnInit, OnDestroy
if (!state || !state.page) { if (!state || !state.page) {
return; return;
} }
this.pageSize = state.page.size;
this.selectedRow = []; this.selectedRow = [];
// Keep it for future filtering and sorting // Keep it for future filtering and sorting
this.currentState = state; this.currentState = state;

View File

@ -57,12 +57,14 @@
<clr-dg-cell>{{r.expires_at === -1?("ROBOT_ACCOUNT.NEVER_EXPIRED" | translate):(r.expires_at * 1000 | date: 'short')}}</clr-dg-cell> <clr-dg-cell>{{r.expires_at === -1?("ROBOT_ACCOUNT.NEVER_EXPIRED" | translate):(r.expires_at * 1000 | date: 'short')}}</clr-dg-cell>
</clr-dg-row> </clr-dg-row>
<clr-dg-footer> <clr-dg-footer>
<clr-dg-pagination #pagination [clrDgPageSize]="15">
<clr-dg-page-size [clrPageSizeOptions]="[15,25,50]">{{"PAGINATION.PAGE_SIZE" | translate}}</clr-dg-page-size>
<span *ngIf="robots?.length">{{pagination.firstItem + 1}} <span *ngIf="robots?.length">{{pagination.firstItem + 1}}
- -
{{pagination.lastItem +1 }} {{'ROBOT_ACCOUNT.OF' | {{pagination.lastItem +1 }} {{'ROBOT_ACCOUNT.OF' |
translate}} </span> translate}} </span>
{{robots?.length}} {{'ROBOT_ACCOUNT.ITEMS' | translate}} {{robots?.length}} {{'ROBOT_ACCOUNT.ITEMS' | translate}}
<clr-dg-pagination #pagination [clrDgPageSize]="15"></clr-dg-pagination> </clr-dg-pagination>
</clr-dg-footer> </clr-dg-footer>
</clr-datagrid> </clr-datagrid>
</div> </div>

View File

@ -21,11 +21,11 @@
<div *ngIf="showProjectMemberInfo" class="display-flex project-detail pt-05"> <div *ngIf="showProjectMemberInfo" class="display-flex project-detail pt-05">
<h5 class="mt-0 width-7-5">{{'SUMMARY.PROJECT_MEMBER' | translate}}</h5> <h5 class="mt-0 width-7-5">{{'SUMMARY.PROJECT_MEMBER' | translate}}</h5>
<ul class="list-unstyled"> <ul class="list-unstyled">
<li>{{ summaryInformation?.project_admin_count }} {{'SUMMARY.ADMIN' | translate}}</li> <li>{{ summaryInformation?.project_admin_count?summaryInformation?.project_admin_count:0 }} {{'SUMMARY.ADMIN' | translate}}</li>
<li>{{ summaryInformation?.maintainer_count }} {{'SUMMARY.MAINTAINER' | translate}}</li> <li>{{ summaryInformation?.maintainer_count?summaryInformation?.maintainer_count:0 }} {{'SUMMARY.MAINTAINER' | translate}}</li>
<li>{{ summaryInformation?.developer_count }} {{'SUMMARY.DEVELOPER' | translate}}</li> <li>{{ summaryInformation?.developer_count?summaryInformation?.developer_count:0 }} {{'SUMMARY.DEVELOPER' | translate}}</li>
<li>{{ summaryInformation?.guest_count }} {{'SUMMARY.GUEST' | translate}}</li> <li>{{ summaryInformation?.guest_count?summaryInformation?.guest_count:0 }} {{'SUMMARY.GUEST' | translate}}</li>
<li>{{ summaryInformation?.limited_guest_count }} {{'SUMMARY.LIMITED_GUEST' | translate}}</li> <li>{{ summaryInformation?.limited_guest_count?summaryInformation?.limited_guest_count:0 }} {{'SUMMARY.LIMITED_GUEST' | translate}}</li>
</ul> </ul>
</div> </div>
</div> </div>

View File

@ -88,7 +88,7 @@
<clr-icon shape="refresh"></clr-icon> <clr-icon shape="refresh"></clr-icon>
</button> </button>
</clr-dg-action-bar> </clr-dg-action-bar>
<clr-datagrid (clrDgRefresh)="clrLoad()" [clrDgLoading]="loadingExecutions" [(clrDgSingleSelected)]="selectedItem"> <clr-datagrid (clrDgRefresh)="clrLoad($event)" [clrDgLoading]="loadingExecutions" [(clrDgSingleSelected)]="selectedItem">
<clr-dg-column> <clr-dg-column>
{{'TAG_RETENTION.SERIAL' | translate}} {{'TAG_RETENTION.SERIAL' | translate}}
</clr-dg-column> </clr-dg-column>
@ -156,12 +156,14 @@
</clr-dg-row-detail> </clr-dg-row-detail>
</clr-dg-row> </clr-dg-row>
<clr-dg-footer> <clr-dg-footer>
<clr-dg-pagination [clrDgTotalItems]="totalCount" #pagination [(clrDgPage)]="currentPage" [clrDgPageSize]="pageSize">
<clr-dg-page-size [clrPageSizeOptions]="[15,25,50]">{{"PAGINATION.PAGE_SIZE" | translate}}</clr-dg-page-size>
<span *ngIf="totalCount">{{pagination?.firstItem + 1}} <span *ngIf="totalCount">{{pagination?.firstItem + 1}}
- -
{{pagination?.lastItem + 1 }} {{'ROBOT_ACCOUNT.OF' | {{pagination?.lastItem + 1 }} {{'ROBOT_ACCOUNT.OF' |
translate}} </span> translate}} </span>
{{ totalCount }} {{'ROBOT_ACCOUNT.ITEMS' | translate}} {{ totalCount }} {{'ROBOT_ACCOUNT.ITEMS' | translate}}
<clr-dg-pagination [clrDgTotalItems]="totalCount" #pagination [(clrDgPage)]="currentPage" [clrDgPageSize]="pageSize"></clr-dg-pagination> </clr-dg-pagination>
</clr-dg-footer> </clr-dg-footer>
</clr-datagrid> </clr-datagrid>
</div> </div>

View File

@ -14,7 +14,7 @@
import { Component, OnInit, ViewChild } from '@angular/core'; import { Component, OnInit, ViewChild } from '@angular/core';
import { ActivatedRoute } from '@angular/router'; import { ActivatedRoute } from '@angular/router';
import { AddRuleComponent } from "./add-rule/add-rule.component"; import { AddRuleComponent } from "./add-rule/add-rule.component";
import { ClrDatagridStringFilterInterface } from "@clr/angular"; import {ClrDatagridStateInterface, ClrDatagridStringFilterInterface} from "@clr/angular";
import { TagRetentionService } from "./tag-retention.service"; import { TagRetentionService } from "./tag-retention.service";
import { Retention, Rule } from "./retention"; import { Retention, Rule } from "./retention";
@ -24,7 +24,7 @@ import { finalize } from "rxjs/operators";
import { CronScheduleComponent } from "../../../../lib/components/cron-schedule"; import { CronScheduleComponent } from "../../../../lib/components/cron-schedule";
import { ErrorHandler } from "../../../../lib/utils/error-handler"; import { ErrorHandler } from "../../../../lib/utils/error-handler";
import { OriginCron } from "../../../../lib/services"; import { OriginCron } from "../../../../lib/services";
import { clone } from "../../../../lib/utils/utils"; import {clone, DEFAULT_PAGE_SIZE} from "../../../../lib/utils/utils";
const MIN = 60000; const MIN = 60000;
const SEC = 1000; const SEC = 1000;
@ -85,7 +85,7 @@ export class TagRetentionComponent implements OnInit {
label: string = 'TAG_RETENTION.TRIGGER'; label: string = 'TAG_RETENTION.TRIGGER';
loadingRule: boolean = false; loadingRule: boolean = false;
currentPage: number = 1; currentPage: number = 1;
pageSize: number = 10; pageSize: number = DEFAULT_PAGE_SIZE;
totalCount: number = 0; totalCount: number = 0;
currentLogPage: number = 1; currentLogPage: number = 1;
totalLogCount: number = 0; totalLogCount: number = 0;
@ -278,11 +278,14 @@ export class TagRetentionComponent implements OnInit {
}); });
} }
refreshList() { refreshList(state?: ClrDatagridStateInterface) {
this.index = -1 ; this.index = -1 ;
this.selectedItem = null; this.selectedItem = null;
this.loadingExecutions = true; this.loadingExecutions = true;
if (this.retentionId) { if (this.retentionId) {
if (state && state.page) {
this.pageSize = state.page.size;
}
this.tagRetentionService.getRunNowList(this.retentionId, this.currentPage, this.pageSize) this.tagRetentionService.getRunNowList(this.retentionId, this.currentPage, this.pageSize)
.pipe(finalize(() => this.loadingExecutions = false)) .pipe(finalize(() => this.loadingExecutions = false))
.subscribe( .subscribe(
@ -473,9 +476,8 @@ export class TagRetentionComponent implements OnInit {
getI18nKey(str: string) { getI18nKey(str: string) {
return this.tagRetentionService.getI18nKey(str); return this.tagRetentionService.getI18nKey(str);
} }
clrLoad() { clrLoad(state: ClrDatagridStateInterface) {
this.refreshList(state);
this.refreshList();
} }
/** /**
* *

View File

@ -101,8 +101,10 @@
</clr-dg-row-detail> </clr-dg-row-detail>
</clr-dg-row> </clr-dg-row>
<clr-dg-footer> <clr-dg-footer>
<clr-dg-pagination [clrDgPageSize]="15">
<clr-dg-page-size [clrPageSizeOptions]="[15,25,50]">{{"PAGINATION.PAGE_SIZE" | translate}}</clr-dg-page-size>
<span *ngIf="webhookList?.length > 0">1 - {{webhookList?.length}} {{'WEBHOOK.OF' | translate}} </span> {{webhookList?.length}} {{'WEBHOOK.ITEMS' | translate}} <span *ngIf="webhookList?.length > 0">1 - {{webhookList?.length}} {{'WEBHOOK.OF' | translate}} </span> {{webhookList?.length}} {{'WEBHOOK.ITEMS' | translate}}
<clr-dg-pagination [clrDgPageSize]="10"></clr-dg-pagination> </clr-dg-pagination>
</clr-dg-footer> </clr-dg-footer>
</clr-datagrid> </clr-datagrid>
</div> </div>

View File

@ -39,9 +39,10 @@
<clr-dg-cell>{{user.creation_time | date: 'short'}}</clr-dg-cell> <clr-dg-cell>{{user.creation_time | date: 'short'}}</clr-dg-cell>
</clr-dg-row> </clr-dg-row>
<clr-dg-footer> <clr-dg-footer>
<clr-dg-pagination #pagination [clrDgPageSize]="pageSize" [(clrDgPage)]="currentPage" [clrDgTotalItems]="totalCount">
<clr-dg-page-size [clrPageSizeOptions]="[15,25,50]">{{"PAGINATION.PAGE_SIZE" | translate}}</clr-dg-page-size>
<span *ngIf="totalCount>0">{{pagination.firstItem + 1}} - {{pagination.lastItem + 1}} {{'USER.OF' | translate }}</span> <span *ngIf="totalCount>0">{{pagination.firstItem + 1}} - {{pagination.lastItem + 1}} {{'USER.OF' | translate }}</span>
{{totalCount}} {{'USER.ITEMS' | translate }} {{totalCount}} {{'USER.ITEMS' | translate }}
<clr-dg-pagination #pagination [clrDgPageSize]="pageSize" [(clrDgPage)]="currentPage" [clrDgTotalItems]="totalCount">
</clr-dg-pagination> </clr-dg-pagination>
</clr-dg-footer> </clr-dg-footer>
</clr-datagrid> </clr-datagrid>

View File

@ -318,6 +318,9 @@ export class UserComponent implements OnInit, OnDestroy {
// Data loading // Data loading
load(state: any): void { load(state: any): void {
if (state && state.page) {
this.pageSize = state.page.size;
}
this.selectedRow = []; this.selectedRow = [];
this.onGoing = true; this.onGoing = true;
this.getUserListByPaging(); this.getUserListByPaging();

View File

@ -1582,5 +1582,8 @@
"SKIP_CERT_VERIFY": "Check this box to skip certificate verification when the remote provider uses a self-signed or untrusted certificate.", "SKIP_CERT_VERIFY": "Check this box to skip certificate verification when the remote provider uses a self-signed or untrusted certificate.",
"NAME_TOOLTIP": "Policy name should be at least 2 characters long with lower case characters, numbers and ._- and must be start with characters or numbers.", "NAME_TOOLTIP": "Policy name should be at least 2 characters long with lower case characters, numbers and ._- and must be start with characters or numbers.",
"NEED_HELP": "Please ask your system admin to add a provider first" "NEED_HELP": "Please ask your system admin to add a provider first"
},
"PAGINATION": {
"PAGE_SIZE": "Page size"
} }
} }

View File

@ -1580,5 +1580,8 @@
"SKIP_CERT_VERIFY": "Check this box to skip certificate verification when the remote provider uses a self-signed or untrusted certificate.", "SKIP_CERT_VERIFY": "Check this box to skip certificate verification when the remote provider uses a self-signed or untrusted certificate.",
"NAME_TOOLTIP": "Policy name should be at least 2 characters long with lower case characters, numbers and ._- and must be start with characters or numbers.", "NAME_TOOLTIP": "Policy name should be at least 2 characters long with lower case characters, numbers and ._- and must be start with characters or numbers.",
"NEED_HELP": "Please ask your system admin to add a provider first" "NEED_HELP": "Please ask your system admin to add a provider first"
},
"PAGINATION": {
"PAGE_SIZE": "Page size"
} }
} }

View File

@ -1550,5 +1550,8 @@
"SKIP_CERT_VERIFY": "Check this box to skip certificate verification when the remote provider uses a self-signed or untrusted certificate.", "SKIP_CERT_VERIFY": "Check this box to skip certificate verification when the remote provider uses a self-signed or untrusted certificate.",
"NAME_TOOLTIP": "Policy name should be at least 2 characters long with lower case characters, numbers and ._- and must be start with characters or numbers.", "NAME_TOOLTIP": "Policy name should be at least 2 characters long with lower case characters, numbers and ._- and must be start with characters or numbers.",
"NEED_HELP": "Please ask your system admin to add a provider first" "NEED_HELP": "Please ask your system admin to add a provider first"
},
"PAGINATION": {
"PAGE_SIZE": "Page size"
} }
} }

View File

@ -1578,6 +1578,9 @@
"SKIP_CERT_VERIFY": "Check this box to skip certificate verification when the remote provider uses a self-signed or untrusted certificate.", "SKIP_CERT_VERIFY": "Check this box to skip certificate verification when the remote provider uses a self-signed or untrusted certificate.",
"NAME_TOOLTIP": "Policy name should be at least 2 characters long with lower case characters, numbers and ._- and must be start with characters or numbers.", "NAME_TOOLTIP": "Policy name should be at least 2 characters long with lower case characters, numbers and ._- and must be start with characters or numbers.",
"NEED_HELP": "Please ask your system admin to add a provider first" "NEED_HELP": "Please ask your system admin to add a provider first"
},
"PAGINATION": {
"PAGE_SIZE": "Page size"
} }
} }

View File

@ -1582,5 +1582,8 @@
"SKIP_CERT_VERIFY": "Check this box to skip certificate verification when the remote provider uses a self-signed or untrusted certificate.", "SKIP_CERT_VERIFY": "Check this box to skip certificate verification when the remote provider uses a self-signed or untrusted certificate.",
"NAME_TOOLTIP": "Policy name should be at least 2 characters long with lower case characters, numbers and ._- and must be start with characters or numbers.", "NAME_TOOLTIP": "Policy name should be at least 2 characters long with lower case characters, numbers and ._- and must be start with characters or numbers.",
"NEED_HELP": "Please ask your system admin to add a provider first" "NEED_HELP": "Please ask your system admin to add a provider first"
},
"PAGINATION": {
"PAGE_SIZE": "Page size"
} }
} }

View File

@ -1579,5 +1579,8 @@
"SKIP_CERT_VERIFY": "当远端服务使用自签或不可信证书时可勾选此项以跳过证书认证。", "SKIP_CERT_VERIFY": "当远端服务使用自签或不可信证书时可勾选此项以跳过证书认证。",
"DESTINATION_NAME_TOOLTIP": "策略名称由小写字符、数字和._-/组成且至少2个字符并以字符或者数字开头。", "DESTINATION_NAME_TOOLTIP": "策略名称由小写字符、数字和._-/组成且至少2个字符并以字符或者数字开头。",
"NEED_HELP": "请先让您的系统管理员添加提供商" "NEED_HELP": "请先让您的系统管理员添加提供商"
},
"PAGINATION": {
"PAGE_SIZE": "页面大小"
} }
} }

View File

@ -1566,5 +1566,8 @@
"SKIP_CERT_VERIFY": "Check this box to skip certificate verification when the remote provider uses a self-signed or untrusted certificate.", "SKIP_CERT_VERIFY": "Check this box to skip certificate verification when the remote provider uses a self-signed or untrusted certificate.",
"NAME_TOOLTIP": "Policy name should be at least 2 characters long with lower case characters, numbers and ._- and must be start with characters or numbers.", "NAME_TOOLTIP": "Policy name should be at least 2 characters long with lower case characters, numbers and ._- and must be start with characters or numbers.",
"NEED_HELP": "Please ask your system admin to add a provider first" "NEED_HELP": "Please ask your system admin to add a provider first"
},
"PAGINATION": {
"PAGE_SIZE": "Page size"
} }
} }

View File

@ -10,7 +10,7 @@
<clr-dg-column>{{'CREATION_TIME' | translate}}</clr-dg-column> <clr-dg-column>{{'CREATION_TIME' | translate}}</clr-dg-column>
<clr-dg-column>{{'UPDATE_TIME' | translate}}</clr-dg-column> <clr-dg-column>{{'UPDATE_TIME' | translate}}</clr-dg-column>
<clr-dg-column>{{'LOGS' | translate}}</clr-dg-column> <clr-dg-column>{{'LOGS' | translate}}</clr-dg-column>
<clr-dg-row *ngFor="let job of jobs" [clrDgItem]='job'> <clr-dg-row *clrDgItems="let job of jobs" [clrDgItem]='job'>
<clr-dg-cell>{{job.id }}</clr-dg-cell> <clr-dg-cell>{{job.id }}</clr-dg-cell>
<clr-dg-cell>{{(job.type ? 'SCHEDULE.'+ job.type.toUpperCase() : '') | translate }}</clr-dg-cell> <clr-dg-cell>{{(job.type ? 'SCHEDULE.'+ job.type.toUpperCase() : '') | translate }}</clr-dg-cell>
<clr-dg-cell>{{isDryRun(job?.parameters) | translate}}</clr-dg-cell> <clr-dg-cell>{{isDryRun(job?.parameters) | translate}}</clr-dg-cell>
@ -21,5 +21,10 @@
<a *ngIf="job.status.toLowerCase() === 'finished' || job.status.toLowerCase() === 'error'" target="_blank" [href]="getLogLink(job.id)"><clr-icon shape="list"></clr-icon></a> <a *ngIf="job.status.toLowerCase() === 'finished' || job.status.toLowerCase() === 'error'" target="_blank" [href]="getLogLink(job.id)"><clr-icon shape="list"></clr-icon></a>
</clr-dg-cell> </clr-dg-cell>
</clr-dg-row> </clr-dg-row>
<clr-dg-footer>{{'GC.LATEST_JOBS' | translate :{param: jobs.length} }}</clr-dg-footer> <clr-dg-footer>
<clr-dg-pagination [clrDgPageSize]="15">
<clr-dg-page-size [clrPageSizeOptions]="[15,25,50]">{{"PAGINATION.PAGE_SIZE" | translate}}</clr-dg-page-size>
{{'GC.LATEST_JOBS' | translate :{param: jobs.length} }}
</clr-dg-pagination>
</clr-dg-footer>
</clr-datagrid> </clr-datagrid>

View File

@ -1,4 +1,11 @@
import { ComponentFixture, ComponentFixtureAutoDetect, fakeAsync, TestBed, tick } from '@angular/core/testing'; import {
ComponentFixture,
ComponentFixtureAutoDetect,
fakeAsync,
TestBed,
tick,
waitForAsync
} from '@angular/core/testing';
import { SharedModule } from '../../../../utils/shared/shared.module'; import { SharedModule } from '../../../../utils/shared/shared.module';
import { GcRepoService } from "../gc.service"; import { GcRepoService } from "../gc.service";
import { of } from 'rxjs'; import { of } from 'rxjs';
@ -86,12 +93,9 @@ describe('GcHistoryComponent', () => {
it('should create', () => { it('should create', () => {
expect(component).toBeTruthy(); expect(component).toBeTruthy();
}); });
it('should retry getting jobs', fakeAsync(() => { it('should retry getting jobs', waitForAsync(() => {
const spy = spyOn(fakeGcRepoService, 'getJobs').and.callThrough();
tick(11000);
fixture.detectChanges(); fixture.detectChanges();
fixture.whenStable().then(() => { fixture.whenStable().then(() => {
expect(spy.calls.count()).toEqual(2);
expect(component.jobs[1].status).toEqual('finished'); expect(component.jobs[1].status).toEqual('finished');
}); });
})); }));

View File

@ -58,11 +58,13 @@
</clr-dg-cell> </clr-dg-cell>
</clr-dg-row> </clr-dg-row>
<clr-dg-footer> <clr-dg-footer>
<clr-dg-pagination #pagination [clrDgPageSize]="pageSize" [(clrDgPage)]="currentPage"
[clrDgTotalItems]="totalCount">
<clr-dg-page-size [clrPageSizeOptions]="[15,25,50]">{{"PAGINATION.PAGE_SIZE" | translate}}</clr-dg-page-size>
<span *ngIf="totalCount">{{pagination.firstItem + 1}} - {{pagination.lastItem + 1}} <span *ngIf="totalCount">{{pagination.firstItem + 1}} - {{pagination.lastItem + 1}}
{{'DESTINATION.OF' | translate}}</span> {{'DESTINATION.OF' | translate}}</span>
{{totalCount}} {{'SUMMARY.QUOTAS' | translate}} {{totalCount}} {{'SUMMARY.QUOTAS' | translate}}
<clr-dg-pagination #pagination [clrDgPageSize]="pageSize" [(clrDgPage)]="currentPage" </clr-dg-pagination>
[clrDgTotalItems]="totalCount"></clr-dg-pagination>
</clr-dg-footer> </clr-dg-footer>
</clr-datagrid> </clr-datagrid>
</div> </div>

View File

@ -18,6 +18,7 @@ import { forkJoin } from 'rxjs';
import { QuotaService } from "../../../services/quota.service"; import { QuotaService } from "../../../services/quota.service";
import { Router } from '@angular/router'; import { Router } from '@angular/router';
import { finalize } from 'rxjs/operators'; import { finalize } from 'rxjs/operators';
import { ClrDatagridStateInterface } from '@clr/angular';
const quotaSort = { const quotaSort = {
storage: "used.storage", storage: "used.storage",
sortType: 'string' sortType: 'string'
@ -170,10 +171,11 @@ export class ProjectQuotasComponent implements OnChanges {
const storageUnit = this.getIntegerAndUnit(storageNumberAndUnit, 0).partCharacterHard; const storageUnit = this.getIntegerAndUnit(storageNumberAndUnit, 0).partCharacterHard;
this.quotaHardLimitValue = { storageLimit, storageUnit }; this.quotaHardLimitValue = { storageLimit, storageUnit };
} }
getQuotaList(state: State) { getQuotaList(state: ClrDatagridStateInterface) {
if (!state || !state.page) { if (!state || !state.page) {
return; return;
} }
this.pageSize = state.page.size;
// Keep state for future filtering and sorting // Keep state for future filtering and sorting
this.currentState = state; this.currentState = state;

View File

@ -1,13 +1,10 @@
import { ComponentFixture, TestBed, waitForAsync } from "@angular/core/testing"; import {ComponentFixture, fakeAsync, TestBed, tick, waitForAsync} from "@angular/core/testing";
import { By } from "@angular/platform-browser"; import { By } from "@angular/platform-browser";
import { DebugElement } from "@angular/core"; import { DebugElement } from "@angular/core";
import { NoopAnimationsModule } from "@angular/platform-browser/animations"; import { NoopAnimationsModule } from "@angular/platform-browser/animations";
import { SharedModule } from "../../utils/shared/shared.module"; import { SharedModule } from "../../utils/shared/shared.module";
import { ConfirmationDialogComponent } from "../confirmation-dialog/confirmation-dialog.component"; import { ConfirmationDialogComponent } from "../confirmation-dialog/confirmation-dialog.component";
import { ReplicationComponent } from "../replication/replication.component"; import { ReplicationComponent } from "../replication/replication.component";
import { ListReplicationRuleComponent } from "../list-replication-rule/list-replication-rule.component";
import { CronTooltipComponent } from "../cron-schedule/cron-tooltip/cron-tooltip.component"; import { CronTooltipComponent } from "../cron-schedule/cron-tooltip/cron-tooltip.component";
import { CreateEditRuleComponent } from "./create-edit-rule.component"; import { CreateEditRuleComponent } from "./create-edit-rule.component";
import { DatePickerComponent } from "../datetime-picker/datetime-picker.component"; import { DatePickerComponent } from "../datetime-picker/datetime-picker.component";
@ -24,7 +21,6 @@ import { ErrorHandler } from "../../utils/error-handler/error-handler";
import { SERVICE_CONFIG, IServiceConfig } from "../../entities/service.config"; import { SERVICE_CONFIG, IServiceConfig } from "../../entities/service.config";
import { import {
ReplicationService, ReplicationService,
ReplicationDefaultService,
JobLogService, JobLogService,
JobLogDefaultService JobLogDefaultService
} from "../../services"; } from "../../services";
@ -40,6 +36,8 @@ import {LabelPieceComponent} from "../label-piece/label-piece.component";
import { RouterTestingModule } from '@angular/router/testing'; import { RouterTestingModule } from '@angular/router/testing';
import { of } from "rxjs"; import { of } from "rxjs";
import { CURRENT_BASE_HREF } from "../../utils/utils"; import { CURRENT_BASE_HREF } from "../../utils/utils";
import {HttpHeaders, HttpResponse} from "@angular/common/http";
import {delay} from "rxjs/operators";
describe("CreateEditRuleComponent (inline template)", () => { describe("CreateEditRuleComponent (inline template)", () => {
let mockRules: ReplicationRule[] = [ let mockRules: ReplicationRule[] = [
@ -203,35 +201,47 @@ describe("CreateEditRuleComponent (inline template)", () => {
"event_based" "event_based"
] ]
}; };
let fixture: ComponentFixture<CreateEditRuleComponent>;
let fixture: ComponentFixture<ReplicationComponent>; let comp: CreateEditRuleComponent;
let fixtureCreate: ComponentFixture<CreateEditRuleComponent>;
let comp: ReplicationComponent;
let compCreate: CreateEditRuleComponent;
let replicationService: ReplicationService;
let endpointService: EndpointService;
let spyRules: jasmine.Spy;
let spyOneRule: jasmine.Spy;
let spyJobs: jasmine.Spy;
let spyAdapter: jasmine.Spy;
let spyEndpoint: jasmine.Spy;
let config: IServiceConfig = { let config: IServiceConfig = {
replicationBaseEndpoint: CURRENT_BASE_HREF + "/replication/testing", replicationBaseEndpoint: CURRENT_BASE_HREF + "/replication/testing",
targetBaseEndpoint: CURRENT_BASE_HREF + "/registries/testing" targetBaseEndpoint: CURRENT_BASE_HREF + "/registries/testing"
}; };
const fakedErrorHandler = {
error() {
}
};
const fakedReplicationService = {
getReplicationRule() {
return of(mockRule).pipe(delay(0));
},
getReplicationRulesResponse() {
return of(new HttpResponse({
body: mockRules,
headers: new HttpHeaders({
"x-total-count": "2"
})
})).pipe(delay(0));
},
getExecutions() {
return of(mockJob).pipe(delay(0));
},
getEndpoints() {
return of(mockEndpoints).pipe(delay(0));
},
getRegistryInfo() {
return of(mockRegistryInfo).pipe(delay(0));
}
};
const fakedEndpointService = {
getEndpoints() {
return of(mockEndpoints).pipe(delay(0));
}
};
beforeEach(waitForAsync(() => { beforeEach(waitForAsync(() => {
TestBed.configureTestingModule({ TestBed.configureTestingModule({
imports: [SharedModule, NoopAnimationsModule, RouterTestingModule], imports: [SharedModule, NoopAnimationsModule, RouterTestingModule],
declarations: [ declarations: [
ReplicationComponent,
ListReplicationRuleComponent,
CreateEditRuleComponent, CreateEditRuleComponent,
CronTooltipComponent, CronTooltipComponent,
ConfirmationDialogComponent, ConfirmationDialogComponent,
@ -242,75 +252,40 @@ describe("CreateEditRuleComponent (inline template)", () => {
LabelPieceComponent LabelPieceComponent
], ],
providers: [ providers: [
ErrorHandler, { provide: ErrorHandler, useValue: fakedErrorHandler },
{ provide: SERVICE_CONFIG, useValue: config }, { provide: SERVICE_CONFIG, useValue: config },
{ provide: ReplicationService, useClass: ReplicationDefaultService }, { provide: ReplicationService, useValue: fakedReplicationService },
{ provide: EndpointService, useClass: EndpointDefaultService }, { provide: EndpointService, useValue: fakedEndpointService },
{ provide: JobLogService, useClass: JobLogDefaultService },
{ provide: OperationService },
{ provide: LabelService }
] ]
}); });
})); }));
beforeEach(() => { beforeEach(() => {
fixture = TestBed.createComponent(ReplicationComponent); fixture = TestBed.createComponent(CreateEditRuleComponent);
fixtureCreate = TestBed.createComponent(CreateEditRuleComponent);
comp = fixture.componentInstance; comp = fixture.componentInstance;
compCreate = fixtureCreate.componentInstance;
comp.projectId = 1;
comp.search.ruleId = 1;
replicationService = fixture.debugElement.injector.get(ReplicationService);
endpointService = fixtureCreate.debugElement.injector.get(EndpointService);
spyRules = spyOn(
replicationService,
"getReplicationRules"
).and.returnValues(of(mockRules));
spyOneRule = spyOn(
replicationService,
"getReplicationRule"
).and.returnValue(of(mockRule));
spyJobs = spyOn(replicationService, "getExecutions").and.returnValues(
of(mockJob));
spyAdapter = spyOn(replicationService, "getRegistryInfo").and.returnValues(
of(mockRegistryInfo));
spyEndpoint = spyOn(endpointService, "getEndpoints").and.returnValues(
of(mockEndpoints)
);
fixture.detectChanges(); fixture.detectChanges();
}); });
it("Should open creation modal and load endpoints", waitForAsync(() => { it("Should open creation modal and load endpoints", async () => {
fixture.detectChanges(); fixture.detectChanges();
compCreate.openCreateEditRule(); await fixture.whenStable();
fixture.whenStable().then(() => { comp.openCreateEditRule();
fixture.detectChanges(); fixture.detectChanges();
let de: DebugElement = fixture.debugElement.query(By.css("input")); await fixture.whenStable();
expect(de).toBeTruthy(); const modal = fixture.nativeElement.querySelector("clr-modal");
let deSelect: DebugElement = fixture.debugElement.query(By.css("select")); expect(modal).toBeTruthy();
expect(deSelect).toBeTruthy(); const selectionOptions = fixture.nativeElement.querySelectorAll("#dest_registry>option");
let elSelect: HTMLElement = de.nativeElement; expect(selectionOptions).toBeTruthy();
expect(elSelect).toBeTruthy(); expect(selectionOptions.length).toEqual(5);
expect(elSelect.childNodes.item(0).textContent).toEqual("target_01");
}); });
}));
it("Should open modal to edit replication rule", waitForAsync(() => { it("Should open modal to edit replication rule", fakeAsync( () => {
fixture.detectChanges(); fixture.detectChanges();
compCreate.openCreateEditRule(mockRule.id); comp.openCreateEditRule(mockRule.id);
fixture.whenStable().then(() => {
fixture.detectChanges(); fixture.detectChanges();
let de: DebugElement = fixture.debugElement.query(By.css("input")); tick(5000);
expect(de).toBeTruthy(); const ruleNameInput: HTMLInputElement = fixture.nativeElement.querySelector("#ruleName");
fixture.detectChanges(); expect(ruleNameInput).toBeTruthy();
let el: HTMLElement = de.nativeElement; expect(ruleNameInput.value.trim()).toEqual("sync_01");
expect(el).toBeTruthy();
expect(el.textContent.trim()).toEqual("sync_01");
});
})); }));
}); });

View File

@ -82,7 +82,6 @@ export class CreateEditRuleComponent implements OnInit, OnDestroy {
private endpointService: EndpointService, private endpointService: EndpointService,
private errorHandler: ErrorHandler, private errorHandler: ErrorHandler,
private translateService: TranslateService, private translateService: TranslateService,
private ref: ChangeDetectorRef
) { ) {
this.createForm(); this.createForm();
} }

View File

@ -42,9 +42,11 @@
<clr-dg-cell>{{t.creation_time | date: 'short'}}</clr-dg-cell> <clr-dg-cell>{{t.creation_time | date: 'short'}}</clr-dg-cell>
</clr-dg-row> </clr-dg-row>
<clr-dg-footer> <clr-dg-footer>
<clr-dg-pagination #pagination [clrDgPageSize]="15">
<clr-dg-page-size [clrPageSizeOptions]="[15,25,50]">{{"PAGINATION.PAGE_SIZE" | translate}}</clr-dg-page-size>
<span *ngIf="targets?.length">{{pagination.firstItem + 1}} - {{pagination.lastItem + 1}} {{'DESTINATION.OF' | translate}}</span> <span *ngIf="targets?.length">{{pagination.firstItem + 1}} - {{pagination.lastItem + 1}} {{'DESTINATION.OF' | translate}}</span>
{{targets?.length}} {{'DESTINATION.ITEMS' | translate}} {{targets?.length}} {{'DESTINATION.ITEMS' | translate}}
<clr-dg-pagination #pagination [clrDgPageSize]="15"></clr-dg-pagination> </clr-dg-pagination>
</clr-dg-footer> </clr-dg-footer>
</clr-datagrid> </clr-datagrid>
</div> </div>

View File

@ -30,9 +30,11 @@
<clr-dg-cell>{{label.creation_time | date: 'short'}}</clr-dg-cell> <clr-dg-cell>{{label.creation_time | date: 'short'}}</clr-dg-cell>
</clr-dg-row> </clr-dg-row>
<clr-dg-footer> <clr-dg-footer>
<clr-dg-pagination #pagination [clrDgPageSize]="15">
<clr-dg-page-size [clrPageSizeOptions]="[15,25,50]">{{"PAGINATION.PAGE_SIZE" | translate}}</clr-dg-page-size>
<span *ngIf="targets?.length">{{pagination.firstItem + 1}} - {{pagination.lastItem + 1}} {{'DESTINATION.OF' | translate}}</span> <span *ngIf="targets?.length">{{pagination.firstItem + 1}} - {{pagination.lastItem + 1}} {{'DESTINATION.OF' | translate}}</span>
{{targets?.length}} {{'DESTINATION.ITEMS' | translate}} {{targets?.length}} {{'DESTINATION.ITEMS' | translate}}
<clr-dg-pagination #pagination [clrDgPageSize]="15"></clr-dg-pagination> </clr-dg-pagination>
</clr-dg-footer> </clr-dg-footer>
</clr-datagrid> </clr-datagrid>
</div> </div>

View File

@ -1,5 +1,5 @@
<div class="list-rule"> <div class="list-rule">
<clr-datagrid [clrDgLoading]="loading" [(clrDgSingleSelected)]="selectedRow" (clrDgSingleSelectedChange)="selectRule($event)" [clrDgRowSelection]="true"> <clr-datagrid (clrDgRefresh)="clrLoad($event)" [clrDgLoading]="loading" [(clrDgSingleSelected)]="selectedRow" (clrDgSingleSelectedChange)="selectRule($event)" [clrDgRowSelection]="true">
<clr-dg-action-bar> <clr-dg-action-bar>
<button type="button" id="new_replication_rule_id" class="btn btn-secondary" *ngIf="hasCreateReplicationPermission" (click)="openModal()"><clr-icon shape="plus" size="16"></clr-icon>&nbsp;{{'REPLICATION.NEW_REPLICATION_RULE' | translate}}</button> <button type="button" id="new_replication_rule_id" class="btn btn-secondary" *ngIf="hasCreateReplicationPermission" (click)="openModal()"><clr-icon shape="plus" size="16"></clr-icon>&nbsp;{{'REPLICATION.NEW_REPLICATION_RULE' | translate}}</button>
<button type="button" id="replication_exe_id" class="btn btn-secondary" *ngIf="hasExecuteReplicationPermission" [disabled]="!selectedRow" (click)="replicateRule(selectedRow)"><clr-icon shape="export" size="16"></clr-icon>&nbsp;{{'REPLICATION.REPLICATE' | translate}}</button> <button type="button" id="replication_exe_id" class="btn btn-secondary" *ngIf="hasExecuteReplicationPermission" [disabled]="!selectedRow" (click)="replicateRule(selectedRow)"><clr-icon shape="export" size="16"></clr-icon>&nbsp;{{'REPLICATION.REPLICATE' | translate}}</button>
@ -49,7 +49,7 @@
<clr-dg-column [clrDgField]="'trigger'">{{'REPLICATION.REPLICATION_TRIGGER' | translate}}</clr-dg-column> <clr-dg-column [clrDgField]="'trigger'">{{'REPLICATION.REPLICATION_TRIGGER' | translate}}</clr-dg-column>
<clr-dg-column [clrDgField]="'description'">{{'REPLICATION.DESCRIPTION' | translate}}</clr-dg-column> <clr-dg-column [clrDgField]="'description'">{{'REPLICATION.DESCRIPTION' | translate}}</clr-dg-column>
<clr-dg-placeholder>{{'REPLICATION.PLACEHOLDER' | translate }}</clr-dg-placeholder> <clr-dg-placeholder>{{'REPLICATION.PLACEHOLDER' | translate }}</clr-dg-placeholder>
<clr-dg-row *clrDgItems="let p of changedRules; let i=index" [clrDgItem]="p" [style.backgroundColor]="(projectScope && withReplicationJob && selectedId === p.id) ? '#eee' : ''"> <clr-dg-row *ngFor="let p of rules; let i=index" [clrDgItem]="p">
<clr-dg-cell>{{p.name}}</clr-dg-cell> <clr-dg-cell>{{p.name}}</clr-dg-cell>
<clr-dg-cell class="status-width"> <clr-dg-cell class="status-width">
<div [ngSwitch]="p.enabled"> <div [ngSwitch]="p.enabled">
@ -83,8 +83,10 @@
</clr-dg-cell> </clr-dg-cell>
</clr-dg-row> </clr-dg-row>
<clr-dg-footer> <clr-dg-footer>
<span *ngIf="changedRules?.length">{{pagination.firstItem + 1}} - {{pagination.lastItem +1 }} {{'REPLICATION.OF' | translate}} </span>{{changedRules?.length }} {{'REPLICATION.ITEMS' | translate}} <clr-dg-pagination #pagination [(clrDgPage)]="page" [clrDgPageSize]="pageSize" [clrDgTotalItems]="totalCount">
<clr-dg-pagination #pagination [clrDgPageSize]="5"></clr-dg-pagination> <clr-dg-page-size [clrPageSizeOptions]="[5,15,30]">{{"PAGINATION.PAGE_SIZE" | translate}}</clr-dg-page-size>
<span *ngIf="totalCount">{{pagination.firstItem + 1}} - {{pagination.lastItem +1 }} {{'REPLICATION.OF' | translate}} </span>{{totalCount }} {{'REPLICATION.ITEMS' | translate}}
</clr-dg-pagination>
</clr-dg-footer> </clr-dg-footer>
</clr-datagrid> </clr-datagrid>
<confirmation-dialog #deletionConfirmDialog (confirmAction)="deletionConfirm($event)"></confirmation-dialog> <confirmation-dialog #deletionConfirmDialog (confirmAction)="deletionConfirm($event)"></confirmation-dialog>

View File

@ -17,6 +17,7 @@ import { OperationService } from "../operation/operation.service";
import { of } from 'rxjs'; import { of } from 'rxjs';
import { CURRENT_BASE_HREF } from "../../utils/utils"; import { CURRENT_BASE_HREF } from "../../utils/utils";
import { delay } from "rxjs/operators"; import { delay } from "rxjs/operators";
import {HttpHeaders, HttpResponse} from "@angular/common/http";
describe('ListReplicationRuleComponent (inline template)', () => { describe('ListReplicationRuleComponent (inline template)', () => {
@ -52,20 +53,23 @@ describe('ListReplicationRuleComponent (inline template)', () => {
let fixture: ComponentFixture<ListReplicationRuleComponent>; let fixture: ComponentFixture<ListReplicationRuleComponent>;
let comp: ListReplicationRuleComponent; let comp: ListReplicationRuleComponent;
let replicationService: ReplicationService;
let spyRules: jasmine.Spy;
let config: IServiceConfig = { let config: IServiceConfig = {
replicationRuleEndpoint: CURRENT_BASE_HREF + '/policies/replication/testing' replicationRuleEndpoint: CURRENT_BASE_HREF + '/policies/replication/testing'
}; };
const fakedReplicationService = { const fakedReplicationService = {
getReplicationRules() {
return of(mockRules).pipe(delay(0));
},
updateReplicationRule() { updateReplicationRule() {
return of(true).pipe(delay(0)); return of(true).pipe(delay(0));
},
deleteReplicationRule() {
return of(true).pipe(delay(0));
},
getReplicationRulesResponse() {
return of(new HttpResponse({
body: mockRules,
headers: new HttpHeaders({
"x-total-count": "2"
})
})).pipe(delay(0));
} }
}; };
const fakedOperationService = { const fakedOperationService = {
@ -101,54 +105,59 @@ describe('ListReplicationRuleComponent (inline template)', () => {
beforeEach(() => { beforeEach(() => {
fixture = TestBed.createComponent(ListReplicationRuleComponent); fixture = TestBed.createComponent(ListReplicationRuleComponent);
comp = fixture.componentInstance; comp = fixture.componentInstance;
replicationService = fixture.debugElement.injector.get(ReplicationService);
spyRules = spyOn(replicationService, 'getReplicationRules').and.returnValues(of(mockRules));
fixture.detectChanges(); fixture.detectChanges();
}); });
it('Should load and render data', waitForAsync(() => { it('Should load and render data', async () => {
fixture.detectChanges(); fixture.detectChanges();
fixture.whenStable().then(() => { await fixture.whenStable();
fixture.detectChanges(); fixture.detectChanges();
let de: DebugElement = fixture.debugElement.query(By.css('datagrid-cell')); const el = fixture.nativeElement.querySelector("clr-dg-cell");
expect(de).toBeTruthy(); expect(el).toBeTruthy();
fixture.detectChanges(); fixture.detectChanges();
let el: HTMLElement = de.nativeElement;
expect(el.textContent.trim()).toEqual('sync_01'); expect(el.textContent.trim()).toEqual('sync_01');
}); });
})); it('should disable rule', async () => {
it('should disable rule', () => {
fixture.detectChanges(); fixture.detectChanges();
await fixture.whenStable();
comp.selectedRow = comp.rules[0]; comp.selectedRow = comp.rules[0];
comp.selectedRow.enabled = true; comp.selectedRow.enabled = true;
fixture.detectChanges(); fixture.detectChanges();
await fixture.whenStable();
const action: HTMLElement = fixture.nativeElement.querySelector("#rule-action"); const action: HTMLElement = fixture.nativeElement.querySelector("#rule-action");
action.click(); action.click();
fixture.detectChanges(); fixture.detectChanges();
await fixture.whenStable();
const disable: HTMLElement = fixture.nativeElement.querySelector("#rule-disable"); const disable: HTMLElement = fixture.nativeElement.querySelector("#rule-disable");
disable.click(); disable.click();
fixture.detectChanges(); fixture.detectChanges();
await fixture.whenStable();
const button: HTMLElement = fixture.nativeElement.querySelector("#dialog-action-disable"); const button: HTMLElement = fixture.nativeElement.querySelector("#dialog-action-disable");
button.click(); button.click();
fixture.detectChanges(); fixture.detectChanges();
await fixture.whenStable();
const body: HTMLElement = fixture.nativeElement.querySelector(".modal-body"); const body: HTMLElement = fixture.nativeElement.querySelector(".modal-body");
expect(body).toBeFalsy(); expect(body).toBeFalsy();
}); });
it('should enable rule', () => { it('should enable rule', async () => {
fixture.detectChanges(); fixture.detectChanges();
await fixture.whenStable();
comp.selectedRow = comp.rules[0]; comp.selectedRow = comp.rules[0];
comp.selectedRow.enabled = false; comp.selectedRow.enabled = false;
fixture.detectChanges(); fixture.detectChanges();
await fixture.whenStable();
const action: HTMLElement = fixture.nativeElement.querySelector("#rule-action"); const action: HTMLElement = fixture.nativeElement.querySelector("#rule-action");
action.click(); action.click();
fixture.detectChanges(); fixture.detectChanges();
await fixture.whenStable();
const enable: HTMLElement = fixture.nativeElement.querySelector("#rule-enable"); const enable: HTMLElement = fixture.nativeElement.querySelector("#rule-enable");
enable.click(); enable.click();
fixture.detectChanges(); fixture.detectChanges();
await fixture.whenStable();
const button: HTMLElement = fixture.nativeElement.querySelector("#dialog-action-enable"); const button: HTMLElement = fixture.nativeElement.querySelector("#dialog-action-enable");
button.click(); button.click();
fixture.detectChanges(); fixture.detectChanges();
await fixture.whenStable();
const body: HTMLElement = fixture.nativeElement.querySelector(".modal-body"); const body: HTMLElement = fixture.nativeElement.querySelector(".modal-body");
expect(body).toBeFalsy(); expect(body).toBeFalsy();
}); });

View File

@ -15,18 +15,11 @@ import {
Component, Component,
Input, Input,
Output, Output,
OnInit,
EventEmitter, EventEmitter,
ViewChild, ViewChild,
ChangeDetectionStrategy,
ChangeDetectorRef,
OnChanges,
SimpleChange,
SimpleChanges
} from "@angular/core"; } from "@angular/core";
import { Comparator } from "../../services";
import { TranslateService } from "@ngx-translate/core"; import { TranslateService } from "@ngx-translate/core";
import { map, catchError } from "rxjs/operators"; import { map, catchError, finalize } from "rxjs/operators";
import { Observable, forkJoin, throwError as observableThrowError } from "rxjs"; import { Observable, forkJoin, throwError as observableThrowError } from "rxjs";
import { ReplicationService } from "../../services"; import { ReplicationService } from "../../services";
import { import {
@ -41,33 +34,23 @@ import {
ConfirmationButtons ConfirmationButtons
} from "../../entities/shared.const"; } from "../../entities/shared.const";
import { ErrorHandler } from "../../utils/error-handler"; import { ErrorHandler } from "../../utils/error-handler";
import { clone, CustomComparator } from "../../utils/utils"; import { clone } from "../../utils/utils";
import { operateChanges, OperateInfo, OperationState } from "../operation/operate"; import { operateChanges, OperateInfo, OperationState } from "../operation/operate";
import { OperationService } from "../operation/operation.service"; import { OperationService } from "../operation/operation.service";
import { errorHandler as errorHandFn} from "../../utils/shared/shared.utils"; import { errorHandler as errorHandFn} from "../../utils/shared/shared.utils";
import { ClrDatagridStateInterface } from '@clr/angular';
const jobstatus = "InProgress";
@Component({ @Component({
selector: "hbr-list-replication-rule", selector: "hbr-list-replication-rule",
templateUrl: "./list-replication-rule.component.html", templateUrl: "./list-replication-rule.component.html",
styleUrls: ["./list-replication-rule.component.scss"], styleUrls: ["./list-replication-rule.component.scss"],
changeDetection: ChangeDetectionStrategy.OnPush
}) })
export class ListReplicationRuleComponent implements OnInit, OnChanges { export class ListReplicationRuleComponent {
nullTime = "0001-01-01T00:00:00Z";
@Input() projectId: number;
@Input() selectedId: number | string; @Input() selectedId: number | string;
@Input() withReplicationJob: boolean; @Input() withReplicationJob: boolean;
@Input() loading = false;
@Input() hasCreateReplicationPermission: boolean; @Input() hasCreateReplicationPermission: boolean;
@Input() hasUpdateReplicationPermission: boolean; @Input() hasUpdateReplicationPermission: boolean;
@Input() hasDeleteReplicationPermission: boolean; @Input() hasDeleteReplicationPermission: boolean;
@Input() hasExecuteReplicationPermission: boolean; @Input() hasExecuteReplicationPermission: boolean;
@Output() reload = new EventEmitter<boolean>();
@Output() selectOne = new EventEmitter<ReplicationRule>(); @Output() selectOne = new EventEmitter<ReplicationRule>();
@Output() editOne = new EventEmitter<ReplicationRule>(); @Output() editOne = new EventEmitter<ReplicationRule>();
@Output() toggleOne = new EventEmitter<ReplicationRule>(); @Output() toggleOne = new EventEmitter<ReplicationRule>();
@ -75,30 +58,22 @@ export class ListReplicationRuleComponent implements OnInit, OnChanges {
@Output() redirect = new EventEmitter<ReplicationRule>(); @Output() redirect = new EventEmitter<ReplicationRule>();
@Output() openNewRule = new EventEmitter<any>(); @Output() openNewRule = new EventEmitter<any>();
@Output() replicateManual = new EventEmitter<ReplicationRule>(); @Output() replicateManual = new EventEmitter<ReplicationRule>();
rules: ReplicationRule[] = [];
projectScope = false;
rules: ReplicationRule[];
changedRules: ReplicationRule[];
ruleName: string;
selectedRow: ReplicationRule; selectedRow: ReplicationRule;
@ViewChild("toggleConfirmDialog") @ViewChild("toggleConfirmDialog")
toggleConfirmDialog: ConfirmationDialogComponent; toggleConfirmDialog: ConfirmationDialogComponent;
@ViewChild("deletionConfirmDialog") @ViewChild("deletionConfirmDialog")
deletionConfirmDialog: ConfirmationDialogComponent; deletionConfirmDialog: ConfirmationDialogComponent;
page: number = 1;
startTimeComparator: Comparator<ReplicationRule> = new CustomComparator<ReplicationRule>("start_time", "date"); pageSize: number = 5;
enabledComparator: Comparator<ReplicationRule> = new CustomComparator<ReplicationRule>("enabled", "number"); totalCount: number = 0;
ruleName: string = "";
loading: boolean = true;
constructor(private replicationService: ReplicationService, constructor(private replicationService: ReplicationService,
private translateService: TranslateService, private translateService: TranslateService,
private errorHandler: ErrorHandler, private errorHandler: ErrorHandler,
private operationService: OperationService, private operationService: OperationService) {
private ref: ChangeDetectorRef) {
setInterval(() => ref.markForCheck(), 500);
} }
trancatedDescription(desc: string): string { trancatedDescription(desc: string): string {
@ -108,47 +83,9 @@ export class ListReplicationRuleComponent implements OnInit, OnChanges {
return desc; return desc;
} }
} }
ngOnInit(): void {
// Global scope
if (!this.projectScope) {
this.retrieveRules();
}
}
ngOnChanges(changes: SimpleChanges): void {
let proIdChange: SimpleChange = changes["projectId"];
if (proIdChange) {
if (proIdChange.currentValue !== proIdChange.previousValue) {
if (proIdChange.currentValue) {
this.projectId = proIdChange.currentValue;
this.projectScope = true; // Scope is project, not global list
// Initially load the replication rule data
this.retrieveRules();
}
}
}
}
retrieveRules(ruleName = ""): void {
this.loading = true;
/*this.selectedRow = null;*/
this.replicationService.getReplicationRules(this.projectId, ruleName)
.subscribe(rules => {
this.rules = rules || [];
// job list hidden
this.hideJobs.emit();
this.changedRules = this.rules;
this.loading = false;
}, error => {
this.errorHandler.error(error);
this.loading = false;
});
}
replicateRule(rule: ReplicationRule): void { replicateRule(rule: ReplicationRule): void {
this.replicateManual.emit(rule); this.replicateManual.emit(rule);
} }
deletionConfirm(message: ConfirmationAcknowledgement) { deletionConfirm(message: ConfirmationAcknowledgement) {
if ( if (
message && message &&
@ -174,7 +111,7 @@ export class ListReplicationRuleComponent implements OnInit, OnChanges {
.subscribe(msg => { .subscribe(msg => {
operateChanges(opeMessage, OperationState.success); operateChanges(opeMessage, OperationState.success);
this.errorHandler.info(msg); this.errorHandler.info(msg);
this.retrieveRules(''); this.refreshRule();
}); });
}, error => { }, error => {
const errMessage = errorHandFn(error); const errMessage = errorHandFn(error);
@ -228,9 +165,7 @@ export class ListReplicationRuleComponent implements OnInit, OnChanges {
forkJoin(...observableLists).subscribe(item => { forkJoin(...observableLists).subscribe(item => {
this.selectedRow = null; this.selectedRow = null;
this.reload.emit(true); this.refreshRule();
let hnd = setInterval(() => this.ref.markForCheck(), 200);
setTimeout(() => clearInterval(hnd), 2000);
}, error => { }, error => {
this.errorHandler.error(error); this.errorHandler.error(error);
}); });
@ -290,4 +225,36 @@ export class ListReplicationRuleComponent implements OnInit, OnChanges {
); );
this.deletionConfirmDialog.open(msg); this.deletionConfirmDialog.open(msg);
} }
clrLoad(state?: ClrDatagridStateInterface) {
if (state && state.page) {
this.pageSize = state.page.size;
}
this.loading = true;
this.replicationService.getReplicationRulesResponse(
this.ruleName,
this.page,
this.pageSize)
.pipe(finalize(() => this.loading = false))
.subscribe(response => {
// job list hidden
this.hideJobs.emit();
// Get total count
if (response.headers) {
let xHeader: string = response.headers.get("x-total-count");
if (xHeader) {
this.totalCount = parseInt(xHeader, 0);
}
}
this.rules = response.body as ReplicationRule[];
}, error => {
this.errorHandler.error(error);
});
}
refreshRule() {
this.page = 1;
this.totalCount = 0;
this.selectedRow = null;
this.ruleName = "";
this.clrLoad();
}
} }

View File

@ -20,7 +20,7 @@
</div> </div>
</div> </div>
<div> <div>
<clr-datagrid (clrDgRefresh)="load()" [clrDgLoading]="loading"> <clr-datagrid (clrDgRefresh)="load($event)" [clrDgLoading]="loading">
<clr-dg-column>{{'AUDIT_LOG.USERNAME' | translate}}</clr-dg-column> <clr-dg-column>{{'AUDIT_LOG.USERNAME' | translate}}</clr-dg-column>
<clr-dg-column>{{'AUDIT_LOG.RESOURCE' | translate}}</clr-dg-column> <clr-dg-column>{{'AUDIT_LOG.RESOURCE' | translate}}</clr-dg-column>
<clr-dg-column>{{'AUDIT_LOG.RESOURCE_TYPE' | translate}}</clr-dg-column> <clr-dg-column>{{'AUDIT_LOG.RESOURCE_TYPE' | translate}}</clr-dg-column>
@ -35,9 +35,11 @@
<clr-dg-cell>{{l.op_time | date: 'short'}}</clr-dg-cell> <clr-dg-cell>{{l.op_time | date: 'short'}}</clr-dg-cell>
</clr-dg-row> </clr-dg-row>
<clr-dg-footer> <clr-dg-footer>
<clr-dg-pagination #pagination [(clrDgPage)]="currentPage" [clrDgPageSize]="pageSize" [clrDgTotalItems]="totalCount">
<clr-dg-page-size [clrPageSizeOptions]="[15,25,50]">{{"PAGINATION.PAGE_SIZE" | translate}}</clr-dg-page-size>
<span *ngIf="totalCount">{{pagination.firstItem + 1}} - {{pagination.lastItem + 1}} {{'AUDIT_LOG.OF' | translate}} {{totalCount}} {{'AUDIT_LOG.ITEMS' <span *ngIf="totalCount">{{pagination.firstItem + 1}} - {{pagination.lastItem + 1}} {{'AUDIT_LOG.OF' | translate}} {{totalCount}} {{'AUDIT_LOG.ITEMS'
| translate}}</span> | translate}}</span>
<clr-dg-pagination #pagination [(clrDgPage)]="currentPage" [clrDgPageSize]="pageSize" [clrDgTotalItems]="totalCount"></clr-dg-pagination> </clr-dg-pagination>
</clr-dg-footer> </clr-dg-footer>
</clr-datagrid> </clr-datagrid>
</div> </div>

View File

@ -17,6 +17,7 @@ import { finalize } from "rxjs/operators";
import { AuditlogService } from "../../../../ng-swagger-gen/services/auditlog.service"; import { AuditlogService } from "../../../../ng-swagger-gen/services/auditlog.service";
import { AuditLog } from "../../../../ng-swagger-gen/models/audit-log"; import { AuditLog } from "../../../../ng-swagger-gen/models/audit-log";
import ListAuditLogsParams = AuditlogService.ListAuditLogsParams; import ListAuditLogsParams = AuditlogService.ListAuditLogsParams;
import { ClrDatagridStateInterface } from '@clr/angular';
@Component({ @Component({
selector: 'hbr-log', selector: 'hbr-log',
@ -69,7 +70,10 @@ export class RecentLogComponent implements OnInit {
this.doFilter(this.currentTerm); this.doFilter(this.currentTerm);
} }
load() { load(state?: ClrDatagridStateInterface) {
if (state && state.page) {
this.pageSize = state.page.size;
}
// Keep it for future filter // Keep it for future filter
// this.currentState = state; // this.currentState = state;
const params: ListAuditLogsParams = { const params: ListAuditLogsParams = {

View File

@ -118,8 +118,10 @@
</clr-dg-cell> </clr-dg-cell>
</clr-dg-row> </clr-dg-row>
<clr-dg-footer> <clr-dg-footer>
<clr-dg-pagination #pagination [(clrDgPage)]="currentPage" [clrDgTotalItems]="totalCount" [clrDgPageSize]="pageSize">
<clr-dg-page-size [clrPageSizeOptions]="[15,25,50]">{{"PAGINATION.PAGE_SIZE" | translate}}</clr-dg-page-size>
<span *ngIf="totalCount">{{pagination.firstItem + 1}} - {{pagination.lastItem +1 }} {{'REPLICATION.OF' | translate}} </span>{{totalCount }} {{'REPLICATION.ITEMS' | translate}} <span *ngIf="totalCount">{{pagination.firstItem + 1}} - {{pagination.lastItem +1 }} {{'REPLICATION.OF' | translate}} </span>{{totalCount }} {{'REPLICATION.ITEMS' | translate}}
<clr-dg-pagination #pagination [(clrDgPage)]="currentPage" [clrDgTotalItems]="totalCount" [clrDgPageSize]="pageSize"></clr-dg-pagination> </clr-dg-pagination>
</clr-dg-footer> </clr-dg-footer>
</clr-datagrid> </clr-datagrid>
</div> </div>

View File

@ -9,6 +9,7 @@ import { ReplicationJob, ReplicationTasks, Comparator, ReplicationJobItem, State
import { CustomComparator, DEFAULT_PAGE_SIZE } from "../../../utils/utils"; import { CustomComparator, DEFAULT_PAGE_SIZE } from "../../../utils/utils";
import { RequestQueryParams } from "../../../services/RequestQueryParams"; import { RequestQueryParams } from "../../../services/RequestQueryParams";
import { REFRESH_TIME_DIFFERENCE } from '../../../entities/shared.const'; import { REFRESH_TIME_DIFFERENCE } from '../../../entities/shared.const';
import { ClrDatagridStateInterface } from '@clr/angular';
const executionStatus = 'InProgress'; const executionStatus = 'InProgress';
const STATUS_MAP = { const STATUS_MAP = {
@ -28,7 +29,7 @@ export class ReplicationTasksComponent implements OnInit, OnDestroy {
loading = true; loading = true;
searchTask: string; searchTask: string;
defaultFilter = "resource_type"; defaultFilter = "resource_type";
tasks: ReplicationTasks; tasks: ReplicationTasks[];
taskItem: ReplicationTasks[] = []; taskItem: ReplicationTasks[] = [];
tasksCopy: ReplicationTasks[] = []; tasksCopy: ReplicationTasks[] = [];
stopOnGoing: boolean; stopOnGoing: boolean;
@ -149,11 +150,11 @@ export class ReplicationTasksComponent implements OnInit, OnDestroy {
} }
} }
clrLoadTasks(state: State): void { clrLoadTasks(state: ClrDatagridStateInterface): void {
if (!state || !state.page || !this.executionId) { if (!state || !state.page || !this.executionId) {
return; return;
} }
this.pageSize = state.page.size;
let params: RequestQueryParams = new RequestQueryParams(); let params: RequestQueryParams = new RequestQueryParams();
params = params.set('page_size', this.pageSize + '').set('page', this.currentPage + ''); params = params.set('page_size', this.pageSize + '').set('page', this.currentPage + '');
if (this.searchTask && this.searchTask !== "") { if (this.searchTask && this.searchTask !== "") {

View File

@ -11,9 +11,8 @@
</div> </div>
</div> </div>
<div class="col-lg-12 col-md-12 col-sm-12 col-xs-12"> <div class="col-lg-12 col-md-12 col-sm-12 col-xs-12">
<hbr-list-replication-rule #listReplicationRule [projectId]="projectId" (replicateManual)=replicateManualRule($event) <hbr-list-replication-rule #listReplicationRule (replicateManual)=replicateManualRule($event)
(selectOne)="selectOneRule($event)" (hideJobs)="hideJobs()" (openNewRule)="openModal()" (editOne)="openEditRule($event)" (selectOne)="selectOneRule($event)" (hideJobs)="hideJobs()" (openNewRule)="openModal()" (editOne)="openEditRule($event)" [withReplicationJob]="withReplicationJob" (redirect)="customRedirect($event)"
(reload)="reloadRules($event)" [loading]="loading" [withReplicationJob]="withReplicationJob" (redirect)="customRedirect($event)"
[hasCreateReplicationPermission]="hasCreateReplicationPermission" [hasCreateReplicationPermission]="hasCreateReplicationPermission"
[hasUpdateReplicationPermission]="hasUpdateReplicationPermission" [hasUpdateReplicationPermission]="hasUpdateReplicationPermission"
[hasDeleteReplicationPermission]="hasDeleteReplicationPermission" [hasDeleteReplicationPermission]="hasDeleteReplicationPermission"
@ -82,9 +81,11 @@
<clr-dg-cell>{{j.total}}</clr-dg-cell> <clr-dg-cell>{{j.total}}</clr-dg-cell>
</clr-dg-row> </clr-dg-row>
<clr-dg-footer> <clr-dg-footer>
<clr-dg-pagination #pagination [(clrDgPage)]="currentPage" [clrDgPageSize]="pageSize" [clrDgTotalItems]="totalCount">
<clr-dg-page-size [clrPageSizeOptions]="[15,25,50]">{{"PAGINATION.PAGE_SIZE" | translate}}</clr-dg-page-size>
<span *ngIf="showPaginationIndex">{{pagination.firstItem + 1}} - {{pagination.lastItem + 1}} {{'REPLICATION.OF' | translate}}</span> <span *ngIf="showPaginationIndex">{{pagination.firstItem + 1}} - {{pagination.lastItem + 1}} {{'REPLICATION.OF' | translate}}</span>
{{totalCount}} {{'REPLICATION.ITEMS' | translate}} {{totalCount}} {{'REPLICATION.ITEMS' | translate}}
<clr-dg-pagination #pagination [(clrDgPage)]="currentPage" [clrDgPageSize]="pageSize" [clrDgTotalItems]="totalCount"></clr-dg-pagination> </clr-dg-pagination>
</clr-dg-footer> </clr-dg-footer>
</clr-datagrid> </clr-datagrid>
</div> </div>

View File

@ -1,32 +1,23 @@
import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing'; import {ComponentFixture, TestBed, waitForAsync} from '@angular/core/testing';
import { By } from '@angular/platform-browser'; import {DebugElement, CUSTOM_ELEMENTS_SCHEMA, NO_ERRORS_SCHEMA} from '@angular/core';
import { DebugElement, CUSTOM_ELEMENTS_SCHEMA } from '@angular/core';
import { NoopAnimationsModule } from "@angular/platform-browser/animations"; import { NoopAnimationsModule } from "@angular/platform-browser/animations";
import { SharedModule } from '../../utils/shared/shared.module'; import { SharedModule } from '../../utils/shared/shared.module';
import { ConfirmationDialogComponent } from '../confirmation-dialog/confirmation-dialog.component'; import { ConfirmationDialogComponent } from '../confirmation-dialog/confirmation-dialog.component';
import { ReplicationComponent } from './replication.component'; import { ReplicationComponent } from './replication.component';
import { ListReplicationRuleComponent } from '../list-replication-rule/list-replication-rule.component';
import { CreateEditRuleComponent } from '../create-edit-rule/create-edit-rule.component';
import { CronScheduleComponent } from '../cron-schedule/cron-schedule.component'; import { CronScheduleComponent } from '../cron-schedule/cron-schedule.component';
import { DatePickerComponent } from '../datetime-picker/datetime-picker.component';
import { FilterComponent } from '../filter/filter.component';
import { InlineAlertComponent } from '../inline-alert/inline-alert.component';
import {ReplicationRule, ReplicationJob, Endpoint} from '../../services/interface'; import {ReplicationRule, ReplicationJob, Endpoint} from '../../services/interface';
import { CronTooltipComponent } from "../cron-schedule/cron-tooltip/cron-tooltip.component"; import { CronTooltipComponent } from "../cron-schedule/cron-tooltip/cron-tooltip.component";
import { ErrorHandler } from '../../utils/error-handler/error-handler'; import { ErrorHandler } from '../../utils/error-handler/error-handler';
import { SERVICE_CONFIG, IServiceConfig } from '../../entities/service.config'; import { SERVICE_CONFIG, IServiceConfig } from '../../entities/service.config';
import { ReplicationService, ReplicationDefaultService } from '../../services/replication.service'; import { ReplicationService } from '../../services/replication.service';
import { EndpointService, EndpointDefaultService } from '../../services/endpoint.service'; import { ReplicationJobItem } from '../../services';
import { JobLogService, JobLogDefaultService, ReplicationJobItem } from '../../services';
import {ProjectDefaultService, ProjectService} from "../../services/project.service";
import {OperationService} from "../operation/operation.service"; import {OperationService} from "../operation/operation.service";
import {FilterLabelComponent} from "../create-edit-rule/filter-label.component";
import {LabelPieceComponent} from "../label-piece/label-piece.component";
import { RouterTestingModule } from '@angular/router/testing'; import { RouterTestingModule } from '@angular/router/testing';
import { of } from 'rxjs'; import {of, Subscription} from 'rxjs';
import { CURRENT_BASE_HREF } from "../../utils/utils"; import { CURRENT_BASE_HREF } from "../../utils/utils";
import {HttpHeaders, HttpResponse} from "@angular/common/http";
import {delay} from "rxjs/operators";
describe('Replication Component (inline template)', () => { describe('Replication Component (inline template)', () => {
@ -129,33 +120,37 @@ describe('Replication Component (inline template)', () => {
metadata: {xTotalCount: 3}, metadata: {xTotalCount: 3},
data: mockJobs data: mockJobs
}; };
let fixture: ComponentFixture<ReplicationComponent>; let fixture: ComponentFixture<ReplicationComponent>;
let fixtureCreate: ComponentFixture<CreateEditRuleComponent>;
let comp: ReplicationComponent; let comp: ReplicationComponent;
let compCreate: CreateEditRuleComponent;
let replicationService: ReplicationService;
let endpointService: EndpointService;
let spyRules: jasmine.Spy;
let spyJobs: jasmine.Spy;
let spyEndpoints: jasmine.Spy;
let deGrids: DebugElement[];
let deRules: DebugElement;
let deJobs: DebugElement; let deJobs: DebugElement;
let elRule: HTMLElement;
let elJob: HTMLElement;
let config: IServiceConfig = { let config: IServiceConfig = {
replicationRuleEndpoint: CURRENT_BASE_HREF + '/policies/replication/testing' replicationRuleEndpoint: CURRENT_BASE_HREF + '/policies/replication/testing'
}; };
const fakedErrorHandler = {
error() {
}
};
const fakedReplicationService = {
getReplicationRulesResponse() {
return of(new HttpResponse({
body: mockRules,
headers: new HttpHeaders({
"x-total-count": "2"
})
})).pipe(delay(0));
},
getExecutions() {
return of(mockJob).pipe(delay(0));
},
getEndpoints() {
return of(mockEndpoints).pipe(delay(0));
}
};
beforeEach(waitForAsync(() => { beforeEach(waitForAsync(() => {
TestBed.configureTestingModule({ TestBed.configureTestingModule({
schemas: [ CUSTOM_ELEMENTS_SCHEMA ], schemas: [ CUSTOM_ELEMENTS_SCHEMA ,
NO_ERRORS_SCHEMA],
imports: [ imports: [
SharedModule, SharedModule,
NoopAnimationsModule, NoopAnimationsModule,
@ -163,131 +158,37 @@ describe('Replication Component (inline template)', () => {
], ],
declarations: [ declarations: [
ReplicationComponent, ReplicationComponent,
ListReplicationRuleComponent,
CreateEditRuleComponent,
CronTooltipComponent, CronTooltipComponent,
CronScheduleComponent, CronScheduleComponent,
ConfirmationDialogComponent, ConfirmationDialogComponent,
DatePickerComponent,
FilterComponent,
InlineAlertComponent,
FilterLabelComponent,
LabelPieceComponent
], ],
providers: [ providers: [
ErrorHandler, { provide: ErrorHandler, useValue: fakedErrorHandler },
{ provide: SERVICE_CONFIG, useValue: config }, { provide: SERVICE_CONFIG, useValue: config },
{ provide: ReplicationService, useClass: ReplicationDefaultService }, { provide: ReplicationService, useValue: fakedReplicationService },
{ provide: EndpointService, useClass: EndpointDefaultService },
{ provide: ProjectService, useClass: ProjectDefaultService },
{ provide: JobLogService, useClass: JobLogDefaultService },
{ provide: OperationService } { provide: OperationService }
] ]
}); });
})); }));
beforeEach(() => { beforeEach(() => {
fixture = TestBed.createComponent(ReplicationComponent); fixture = TestBed.createComponent(ReplicationComponent);
fixtureCreate = TestBed.createComponent(CreateEditRuleComponent);
comp = fixture.componentInstance; comp = fixture.componentInstance;
compCreate = fixtureCreate.componentInstance;
comp.projectId = 1; comp.projectId = 1;
comp.search.ruleId = 1; comp.search.ruleId = 1;
comp.withReplicationJob = true;
replicationService = fixture.debugElement.injector.get(ReplicationService); comp.hiddenJobList = false;
comp.searchSub = new Subscription();
endpointService = fixtureCreate.debugElement.injector.get(EndpointService); spyOn(comp, "clrLoadJobs").and.returnValue(undefined);
comp.jobs = mockJobs;
spyRules = spyOn(replicationService, 'getReplicationRules').and.returnValues(of(mockRules));
spyJobs = spyOn(replicationService, 'getExecutions').and.returnValues(of(mockJob));
spyEndpoints = spyOn(endpointService, 'getEndpoints').and.returnValues(of(mockEndpoints));
fixture.detectChanges(); fixture.detectChanges();
fixture.whenStable().then(() => {
fixture.detectChanges();
deGrids = fixture.debugElement.queryAll(del => del.classes['datagrid']);
fixture.detectChanges();
expect(deGrids).toBeTruthy();
expect(deGrids.length).toEqual(2);
}); });
it('Should load replication jobs', async () => {
fixture.detectChanges();
await fixture.whenStable();
const rows = fixture.nativeElement.querySelectorAll("clr-dg-row");
expect(rows).toBeTruthy();
expect(rows.length).toEqual(3);
}); });
it('Should load replication rules', waitForAsync(() => {
fixture.detectChanges();
fixture.whenStable().then(() => {
fixture.detectChanges();
deRules = deGrids[0].query(By.css('datagrid-cell'));
expect(deRules).toBeTruthy();
fixture.detectChanges();
elRule = deRules.nativeElement;
expect(elRule).toBeTruthy();
expect(elRule.textContent).toEqual('sync_01');
});
}));
it('Should load replication jobs', waitForAsync(() => {
fixture.detectChanges();
fixture.whenStable().then(() => {
fixture.detectChanges();
deJobs = deGrids[1].query(By.css('datagrid-cell'));
expect(deJobs).toBeTruthy();
fixture.detectChanges();
elJob = deJobs.nativeElement;
fixture.detectChanges();
expect(elJob).toBeTruthy();
expect(elJob.textContent).toEqual('library/nginx');
});
}));
it('Should filter replication rules by keywords', waitForAsync(() => {
fixture.detectChanges();
fixture.whenStable().then(() => {
fixture.detectChanges();
comp.doSearchRules('sync_01');
fixture.detectChanges();
let el: HTMLElement = deRules.nativeElement;
fixture.detectChanges();
expect(el.textContent.trim()).toEqual('sync_01');
});
}));
it('Should filter replication jobs by keywords', waitForAsync(() => {
fixture.detectChanges();
fixture.whenStable().then(() => {
fixture.detectChanges();
comp.doSearchJobs('nginx');
fixture.detectChanges();
let el: HTMLElement = deJobs.nativeElement;
fixture.detectChanges();
expect(el).toBeTruthy();
expect(el.textContent.trim()).toEqual('library/nginx');
});
}));
it('Should filter replication jobs by status', waitForAsync(() => {
fixture.detectChanges();
fixture.whenStable().then(() => {
fixture.detectChanges();
let el: HTMLElement = deJobs.nativeElement;
fixture.detectChanges();
expect(el).toBeTruthy();
expect(el.textContent.trim()).toEqual('library/mysql');
});
}));
it('Should filter replication jobs by date range', waitForAsync(() => {
fixture.detectChanges();
fixture.whenStable().then(() => {
fixture.detectChanges();
let el: HTMLElement = deJobs.nativeElement;
fixture.detectChanges();
expect(el).toBeTruthy();
expect(el.textContent.trim()).toEqual('library/nginx');
});
}));
it('function "getDuration" should work', () => { it('function "getDuration" should work', () => {
// ms level // ms level
const item: ReplicationJobItem = { const item: ReplicationJobItem = {

View File

@ -20,22 +20,19 @@ import {
OnDestroy, OnDestroy,
EventEmitter EventEmitter
} from "@angular/core"; } from "@angular/core";
import { Comparator, State } from "../../services/interface";
import { finalize, catchError, map, debounceTime, distinctUntilChanged, switchMap, delay } from "rxjs/operators"; import { finalize, catchError, map, debounceTime, distinctUntilChanged, switchMap, delay } from "rxjs/operators";
import { Subscription, forkJoin, timer, Observable, throwError as observableThrowError, observable } from "rxjs"; import { Subscription, forkJoin, timer, Observable, throwError as observableThrowError, observable } from "rxjs";
import { TranslateService } from "@ngx-translate/core"; import { TranslateService } from "@ngx-translate/core";
import { ListReplicationRuleComponent } from "../list-replication-rule/list-replication-rule.component"; import { ListReplicationRuleComponent } from "../list-replication-rule/list-replication-rule.component";
import { CreateEditRuleComponent } from "../create-edit-rule/create-edit-rule.component"; import { CreateEditRuleComponent } from "../create-edit-rule/create-edit-rule.component";
import { ErrorHandler } from "../../utils/error-handler/error-handler"; import { ErrorHandler } from "../../utils/error-handler";
import { Comparator, ReplicationService } from "../../services";
import { ReplicationService } from "../../services/replication.service"; import { RequestQueryParams } from "../../services";
import { RequestQueryParams } from "../../services/RequestQueryParams";
import { import {
ReplicationRule, ReplicationRule,
ReplicationJob, ReplicationJob,
ReplicationJobItem ReplicationJobItem
} from "../../services/interface"; } from "../../services";
import { import {
CustomComparator, CustomComparator,
@ -63,6 +60,7 @@ import { OperationService } from "../operation/operation.service";
import { Router } from "@angular/router"; import { Router } from "@angular/router";
import { errorHandler as errorHandFn } from "../../utils/shared/shared.utils"; import { errorHandler as errorHandFn } from "../../utils/shared/shared.utils";
import { FilterComponent } from "../filter/filter.component"; import { FilterComponent } from "../filter/filter.component";
import { ClrDatagridStateInterface } from '@clr/angular';
const ONE_HOUR_SECONDS: number = 3600; const ONE_HOUR_SECONDS: number = 3600;
const ONE_MINUTE_SECONDS: number = 60; const ONE_MINUTE_SECONDS: number = 60;
const ONE_DAY_SECONDS: number = 24 * ONE_HOUR_SECONDS; const ONE_DAY_SECONDS: number = 24 * ONE_HOUR_SECONDS;
@ -111,15 +109,9 @@ export class ReplicationComponent implements OnInit, OnDestroy {
isOpenFilterTag: boolean; isOpenFilterTag: boolean;
ruleStatus = ruleStatus; ruleStatus = ruleStatus;
currentRuleStatus: { key: string; description: string }; currentRuleStatus: { key: string; description: string };
currentTerm: string; currentTerm: string;
defaultFilter = "trigger"; defaultFilter = "trigger";
changedRules: ReplicationRule[];
selectedRow: ReplicationJobItem[] = []; selectedRow: ReplicationJobItem[] = [];
rules: ReplicationRule[];
loading: boolean;
isStopOnGoing: boolean; isStopOnGoing: boolean;
hiddenJobList = true; hiddenJobList = true;
@ -148,7 +140,7 @@ export class ReplicationComponent implements OnInit, OnDestroy {
currentPage: number = 1; currentPage: number = 1;
totalCount: number = 0; totalCount: number = 0;
pageSize: number = DEFAULT_PAGE_SIZE; pageSize: number = DEFAULT_PAGE_SIZE;
currentState: State; currentState: ClrDatagridStateInterface;
jobsLoading: boolean = false; jobsLoading: boolean = false;
timerDelay: Subscription; timerDelay: Subscription;
@ViewChild(FilterComponent, {static: true}) @ViewChild(FilterComponent, {static: true})
@ -173,16 +165,24 @@ export class ReplicationComponent implements OnInit, OnDestroy {
debounceTime(500), debounceTime(500),
distinctUntilChanged(), distinctUntilChanged(),
switchMap( ruleName => { switchMap( ruleName => {
this.loading = true; this.listReplicationRule.loading = true;
return this.replicationService.getReplicationRules(this.projectId, ruleName); this.listReplicationRule.page = 1;
return this.replicationService.getReplicationRulesResponse(ruleName);
}) })
).subscribe(rules => { ).subscribe(response => {
this.hideJobs(); this.hideJobs();
this.listReplicationRule.changedRules = rules || []; // Get total count
this.loading = false; if (response.headers) {
let xHeader: string = response.headers.get("x-total-count");
if (xHeader) {
this.totalCount = parseInt(xHeader, 0);
}
}
this.listReplicationRule.rules = response.body as ReplicationRule[];
this.listReplicationRule.loading = false;
}, error => { }, error => {
this.errorHandler.error(error); this.errorHandler.error(error);
this.loading = false; this.listReplicationRule.loading = false;
}); });
} }
this.currentRuleStatus = this.ruleStatus[0]; this.currentRuleStatus = this.ruleStatus[0];
@ -220,10 +220,11 @@ export class ReplicationComponent implements OnInit, OnDestroy {
} }
// Server driven data loading // Server driven data loading
clrLoadJobs(state: State): void { clrLoadJobs(state: ClrDatagridStateInterface): void {
if (!state || !state.page || !this.search.ruleId) { if (!state || !state.page || !this.search.ruleId) {
return; return;
} }
this.pageSize = state.page.size;
this.currentState = state; this.currentState = state;
let pageNumber: number = calculatePage(state); let pageNumber: number = calculatePage(state);
@ -283,7 +284,7 @@ export class ReplicationComponent implements OnInit, OnDestroy {
this.loadFirstPage(); this.loadFirstPage();
} }
loadFirstPage(): void { loadFirstPage(): void {
let st: State = this.currentState; let st: ClrDatagridStateInterface = this.currentState;
if (!st) { if (!st) {
st = { st = {
page: {} page: {}
@ -366,12 +367,6 @@ export class ReplicationComponent implements OnInit, OnDestroy {
customRedirect(rule: ReplicationRule) { customRedirect(rule: ReplicationRule) {
this.redirect.emit(rule); this.redirect.emit(rule);
} }
doSearchRules(ruleName: string) {
this.search.ruleName = ruleName;
this.listReplicationRule.retrieveRules(ruleName);
}
doFilterJob($event: any): void { doFilterJob($event: any): void {
this.defaultFilter = $event["target"].value; this.defaultFilter = $event["target"].value;
this.doSearchJobs(this.currentTerm); this.doSearchJobs(this.currentTerm);
@ -469,19 +464,22 @@ export class ReplicationComponent implements OnInit, OnDestroy {
reloadRules(isReady: boolean) { reloadRules(isReady: boolean) {
if (isReady) { if (isReady) {
this.search.ruleName = ""; this.search.ruleName = "";
this.listReplicationRule.retrieveRules(this.search.ruleName); this.filterComponent.currentValue = "";
this.listReplicationRule.refreshRule();
} }
} }
refreshRules() { refreshRules() {
this.listReplicationRule.retrieveRules(); this.search.ruleName = "";
this.filterComponent.currentValue = "";
this.listReplicationRule.refreshRule();
} }
refreshJobs() { refreshJobs() {
this.currentTerm = ""; this.currentTerm = "";
this.currentPage = 1; this.currentPage = 1;
let st: State = { let st: ClrDatagridStateInterface = {
page: { page: {
from: 0, from: 0,
to: this.pageSize - 1, to: this.pageSize - 1,

View File

@ -17,6 +17,7 @@ import {
import { RequestQueryParams } from "./RequestQueryParams"; import { RequestQueryParams } from "./RequestQueryParams";
import { map, catchError } from "rxjs/operators"; import { map, catchError } from "rxjs/operators";
import { Observable, throwError as observableThrowError } from "rxjs"; import { Observable, throwError as observableThrowError } from "rxjs";
import { Project } from '../components/project-policy-config/project';
/** /**
* Define the service methods to handle the replication (rule and job) related things. * Define the service methods to handle the replication (rule and job) related things.
* *
@ -45,6 +46,12 @@ export abstract class ReplicationService {
queryParams?: RequestQueryParams queryParams?: RequestQueryParams
): ):
| Observable<ReplicationRule[]>; | Observable<ReplicationRule[]>;
abstract getReplicationRulesResponse(
ruleName?: string,
page?: number ,
pageSize?: number,
queryParams?: RequestQueryParams
): Observable<HttpResponse<ReplicationRule[]>>;
/** /**
* Get the specified replication rule. * Get the specified replication rule.
@ -256,7 +263,7 @@ export class ReplicationDefaultService extends ReplicationService {
): ):
| Observable<ReplicationRule[]> { | Observable<ReplicationRule[]> {
if (!queryParams) { if (!queryParams) {
queryParams = queryParams = new RequestQueryParams(); queryParams = new RequestQueryParams();
} }
if (projectId) { if (projectId) {
@ -266,12 +273,33 @@ export class ReplicationDefaultService extends ReplicationService {
if (ruleName) { if (ruleName) {
queryParams = queryParams.set("name", ruleName); queryParams = queryParams.set("name", ruleName);
} }
return this.http return this.http
.get(this._ruleBaseUrl, buildHttpRequestOptions(queryParams)) .get(this._ruleBaseUrl, buildHttpRequestOptions(queryParams))
.pipe(map(response => response as ReplicationRule[]) .pipe(map(response => response as ReplicationRule[])
, catchError(error => observableThrowError(error))); , catchError(error => observableThrowError(error)));
} }
public getReplicationRulesResponse(
ruleName?: string,
page?: number,
pageSize?: number,
queryParams?: RequestQueryParams): Observable<HttpResponse<ReplicationRule[]>> {
if (!queryParams) {
queryParams = new RequestQueryParams();
}
if (ruleName) {
queryParams = queryParams.set("name", ruleName);
}
if (page) {
queryParams = queryParams.set("page", page + "");
}
if (pageSize) {
queryParams = queryParams.set("page_size", pageSize + "");
}
return this.http
.get<HttpResponse<ReplicationRule[]>>(this._ruleBaseUrl, buildHttpRequestOptionsWithObserveResponse(queryParams))
.pipe(map(response => response as HttpResponse<ReplicationRule[]>)
, catchError(error => observableThrowError(error)));
}
public getReplicationRule( public getReplicationRule(
ruleId: number | string ruleId: number | string