Merge pull request #13302 from AllForNothing/rep-rule

Add page size options to datagrid
This commit is contained in:
Will Sun 2020-10-21 11:14:44 +08:00 committed by GitHub
commit 1e421748bc
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
55 changed files with 460 additions and 474 deletions

View File

@ -5,7 +5,7 @@
"angular-cli": {},
"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",
"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_fix": "tslint --fix \"src/**/*.ts\"",
"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>
</clr-dg-row>
<clr-dg-footer>
<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 [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}}
</clr-dg-pagination>
</clr-dg-footer>
</clr-datagrid>
</div>

View File

@ -4,7 +4,7 @@
{{ 'SIDE_NAV.DISTRIBUTIONS.INSTANCES' | translate }}
</h2>
<div>
<clr-datagrid (clrDgRefresh)="loadData()" [clrDgLoading]="inProgress" [(clrDgSelected)]="selectedRow">
<clr-datagrid (clrDgRefresh)="loadData($event)" [clrDgLoading]="inProgress" [(clrDgSelected)]="selectedRow">
<clr-dg-action-bar>
<div class="clr-row">
<div class="clr-col-7">
@ -110,6 +110,7 @@
</clr-dg-row>
<clr-dg-footer>
<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>{{ totalCount }} {{ 'HELM_CHART.ITEMS' | translate }}</span>
</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 { Metadata } from '../../../../ng-swagger-gen/models/metadata';
import { FrontInstance, HEALTHY, UNHEALTHY } from '../distribution-interface';
import { ClrDatagridStateInterface } from '@clr/angular';
interface MultiOperateData {
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 = [];
const queryParam: PreheatService.ListInstancesParams = {
page: this.currentPage,

View File

@ -30,7 +30,7 @@
</div>
</div>
<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.RESOURCE' | 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-row>
<clr-dg-footer>
<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 #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}}
</clr-dg-pagination>
</clr-dg-footer>
</clr-datagrid>
</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 { Project } from "../project/project";
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' };
@ -72,7 +74,7 @@ export class AuditLogComponent implements OnInit {
];
pageOffset = 1;
pageSize = 15;
pageSize = DEFAULT_PAGE_SIZE;
totalRecordCount = 0;
currentPage = 1;
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[] = [];
if (this.queryUsername) {
arr.push(`username=~${this.queryUsername}`);

View File

@ -100,6 +100,7 @@
</clr-dg-row>
<clr-dg-footer>
<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">
{{pagination.firstItem + 1}} - {{pagination.lastItem + 1}} {{'HELM_CHART.OF' | translate}}
</span>

View File

@ -21,7 +21,7 @@
</div>
<div class="row">
<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>
<button type="button" id="helm-chart-upload" class="btn btn-secondary"
[disabled]="!hasUploadHelmChartsPermission" (click)="onChartUpload()">
@ -41,7 +41,7 @@
<clr-dg-column>{{'HELM_CHART.CHARTVERSIONS' | 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-row *ngFor="let chart of charts" [clrDgItem]="chart">
<clr-dg-row *clrDgItems="let chart of charts" [clrDgItem]="chart">
<clr-dg-cell>
<span class="list-img">
<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-footer>
<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">
{{pagination.firstItem + 1}} - {{pagination.lastItem + 1}} {{'HELM_CHART.OF' | translate}}
</span>

View File

@ -25,8 +25,10 @@
<clr-dg-cell>{{p.creation_time | date: 'short'}}</clr-dg-cell>
</clr-dg-row>
<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
}} {{'PROJECT.ITEMS' | translate}}
<clr-dg-pagination #pagination [clrDgPageSize]="pageSize" [(clrDgPage)]="currentPage" [clrDgTotalItems]="totalCount"></clr-dg-pagination>
</clr-dg-pagination>
</clr-dg-footer>
</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 { errorHandler } from "../../../lib/utils/shared/shared.utils";
import {HttpErrorResponse} from "@angular/common/http";
import { ClrDatagridStateInterface } from '@clr/angular';
@Component({
selector: "list-project",
@ -135,10 +136,11 @@ export class ListProjectComponent implements OnDestroy {
this.router.navigate(linkUrl);
}
clrLoad(state: State) {
clrLoad(state: ClrDatagridStateInterface) {
if (!state || !state.page) {
return;
}
this.pageSize = state.page.size;
this.selectedRow = [];
// Keep state for future filtering and sorting

View File

@ -46,9 +46,11 @@
</clr-dg-cell>
</clr-dg-row>
<clr-dg-footer>
<span *ngIf="members?.length">{{pagination.firstItem + 1}} - {{pagination.lastItem +1 }} {{'MEMBER.OF' | translate}} </span>
{{members?.length }} {{'MEMBER.ITEMS' | translate}}
<clr-dg-pagination #pagination [clrDgPageSize]="15"></clr-dg-pagination>
<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>
{{members?.length }} {{'MEMBER.ITEMS' | translate}}
</clr-dg-pagination>
</clr-dg-footer>
</clr-datagrid>
</div>

View File

@ -144,15 +144,17 @@
<clr-dg-cell>{{p.description}}</clr-dg-cell>
</clr-dg-row>
<clr-dg-footer>
<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 [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}}
</clr-dg-pagination>
</clr-dg-footer>
</clr-datagrid>
</div>
<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>
<clr-datagrid [(clrDgSingleSelected)]="selectedExecutionRow" [clrDgLoading]="jobsLoading"
(clrDgRefresh)="clrLoadJobs(null,true)">
(clrDgRefresh)="clrLoadJobs(null,true, $event)">
<clr-dg-action-bar>
<div class="clr-row">
<div class="clr-col-7">
@ -202,11 +204,14 @@
<clr-dg-cell>{{execution.vendor_type}}</clr-dg-cell>
</clr-dg-row>
<clr-dg-footer>
<span *ngIf="totalExecutionCount">{{pagination.firstItem + 1}}
- {{pagination.lastItem + 1}} {{'REPLICATION.OF' | translate}}</span>
{{totalExecutionCount}} {{'REPLICATION.ITEMS' | translate}}
<clr-dg-pagination #pagination [(clrDgPage)]="currentExecutionPage" [clrDgPageSize]="pageSize"
[clrDgTotalItems]="totalExecutionCount"></clr-dg-pagination>
[clrDgTotalItems]="totalExecutionCount">
<clr-dg-page-size [clrPageSizeOptions]="[15,25,50]">{{"PAGINATION.PAGE_SIZE" | translate}}</clr-dg-page-size>
<span *ngIf="totalExecutionCount">{{pagination.firstItem + 1}}
- {{pagination.lastItem + 1}} {{'REPLICATION.OF' | translate}}</span>
{{totalExecutionCount}} {{'REPLICATION.ITEMS' | translate}}
</clr-dg-pagination>
</clr-dg-footer>
</clr-datagrid>
</div>

View File

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

View File

@ -76,7 +76,7 @@
<div class="tasks-detail">
<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>
<div class="row flex-end">
<div class="select filter-tag clr-select-wrapper" [hidden]="!isOpenFilterTag">
@ -133,11 +133,13 @@
</clr-dg-cell>
</clr-dg-row>
<clr-dg-footer>
<span *ngIf="totalCount">{{pagination.firstItem + 1}}
- {{pagination.lastItem + 1}} {{'REPLICATION.OF' | translate}}</span>
{{totalCount}} {{'REPLICATION.ITEMS' | translate}}
<clr-dg-pagination #pagination [(clrDgPage)]="currentPage" [clrDgPageSize]="pageSize"
[clrDgTotalItems]="totalCount"></clr-dg-pagination>
[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}} {{'REPLICATION.OF' | translate}}</span>
{{totalCount}} {{'REPLICATION.ITEMS' | translate}}
</clr-dg-pagination>
</clr-dg-footer>
</clr-datagrid>
</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 { EXECUTION_STATUS, P2pProviderService, TIME_OUT } from '../p2p-provider.service';
import { forkJoin, Observable, Subject, Subscription } from 'rxjs';
import { ClrLoadingState } from '@clr/angular';
import {ClrDatagridStateInterface, ClrLoadingState} from '@clr/angular';
@Component({
selector: 'task-list',
@ -220,10 +220,13 @@ export class TaskListComponent implements OnInit, OnDestroy {
return this.preheatService.rootUrl
+ `/projects/${this.projectName}/preheat/policies/${this.preheatPolicyName}/executions/${this.executionId}/tasks/${taskId}/logs`;
}
clrLoadTasks(withLoading): void {
if (withLoading) {
this.loading = true;
}
clrLoadTasks(withLoading, state?: ClrDatagridStateInterface): void {
if (withLoading) {
this.loading = true;
}
if (state && state.page) {
this.pageSize = state.page.size;
}
let params: string;
if (this.searchString) {
params = encodeURIComponent(`${this.filterKey}=~${this.searchString}`);

View File

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

View File

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

View File

@ -73,8 +73,10 @@
</clr-dg-row>
<clr-dg-footer>
<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 #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}}
</clr-dg-pagination>
</clr-dg-footer>
</clr-datagrid>
</div>

View File

@ -71,9 +71,11 @@
</clr-dg-row>
<clr-dg-footer>
<span *ngIf="totalCount">{{pagination.firstItem + 1}} - {{pagination.lastItem + 1}}
{{'TAG.OF' | translate}} {{totalCount}} {{'TAG.ITEMS' | translate}}</span>
<clr-dg-pagination #pagination [clrDgTotalItems]="totalCount" [(clrDgPage)]="currentPage" [clrDgPageSize]="pageSize"></clr-dg-pagination>
<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}}
{{'TAG.OF' | translate}} {{totalCount}} {{'TAG.ITEMS' | translate}}</span>
</clr-dg-pagination>
</clr-dg-footer>
</clr-datagrid>

View File

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

View File

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

View File

@ -357,6 +357,7 @@ export class RepositoryGridviewComponent implements OnChanges, OnInit, OnDestroy
if (!state || !state.page) {
return;
}
this.pageSize = state.page.size;
this.selectedRow = [];
// Keep it for future filtering and sorting
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-row>
<clr-dg-footer>
<span *ngIf="robots?.length">{{pagination.firstItem + 1}}
-
{{pagination.lastItem +1 }} {{'ROBOT_ACCOUNT.OF' |
translate}} </span>
{{robots?.length}} {{'ROBOT_ACCOUNT.ITEMS' | translate}}
<clr-dg-pagination #pagination [clrDgPageSize]="15"></clr-dg-pagination>
<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}}
-
{{pagination.lastItem +1 }} {{'ROBOT_ACCOUNT.OF' |
translate}} </span>
{{robots?.length}} {{'ROBOT_ACCOUNT.ITEMS' | translate}}
</clr-dg-pagination>
</clr-dg-footer>
</clr-datagrid>
</div>

View File

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

View File

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

View File

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

View File

@ -101,8 +101,10 @@
</clr-dg-row-detail>
</clr-dg-row>
<clr-dg-footer>
<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 [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}}
</clr-dg-pagination>
</clr-dg-footer>
</clr-datagrid>
</div>

View File

@ -39,9 +39,10 @@
<clr-dg-cell>{{user.creation_time | date: 'short'}}</clr-dg-cell>
</clr-dg-row>
<clr-dg-footer>
<span *ngIf="totalCount>0">{{pagination.firstItem + 1}} - {{pagination.lastItem + 1}} {{'USER.OF' | translate }}</span>
{{totalCount}} {{'USER.ITEMS' | translate }}
<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>
{{totalCount}} {{'USER.ITEMS' | translate }}
</clr-dg-pagination>
</clr-dg-footer>
</clr-datagrid>

View File

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

View File

@ -1584,5 +1584,8 @@
"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.",
"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.",
"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"
},
"PAGINATION": {
"PAGE_SIZE": "Page size"
}
}

View File

@ -1552,5 +1552,8 @@
"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.",
"NEED_HELP": "Please ask your system admin to add a provider first"
},
"PAGINATION": {
"PAGE_SIZE": "Page size"
}
}

View File

@ -1580,6 +1580,9 @@
"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.",
"NEED_HELP": "Please ask your system admin to add a provider first"
},
"PAGINATION": {
"PAGE_SIZE": "Page size"
}
}

View File

@ -1584,5 +1584,8 @@
"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.",
"NEED_HELP": "Please ask your system admin to add a provider first"
},
"PAGINATION": {
"PAGE_SIZE": "Page size"
}
}

View File

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

View File

@ -1568,5 +1568,8 @@
"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.",
"NEED_HELP": "Please ask your system admin to add a provider first"
},
"PAGINATION": {
"PAGE_SIZE": "Page size"
}
}

View File

@ -2,7 +2,7 @@
<span class="refresh-btn" (click)="getJobs()">
<clr-icon shape="refresh"></clr-icon>
</span>
<clr-datagrid [clrDgLoading]="loading">
<clr-datagrid [clrDgLoading]="loading">
<clr-dg-column>{{'GC.JOB_ID' | translate}}</clr-dg-column>
<clr-dg-column>{{'GC.TRIGGER_TYPE' | translate}}</clr-dg-column>
<clr-dg-column>{{'TAG_RETENTION.DRY_RUN' | translate}}</clr-dg-column>
@ -10,7 +10,7 @@
<clr-dg-column>{{'CREATION_TIME' | translate}}</clr-dg-column>
<clr-dg-column>{{'UPDATE_TIME' | 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.type ? 'SCHEDULE.'+ job.type.toUpperCase() : '') | 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>
</clr-dg-cell>
</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>

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 { GcRepoService } from "../gc.service";
import { of } from 'rxjs';
@ -86,12 +93,9 @@ describe('GcHistoryComponent', () => {
it('should create', () => {
expect(component).toBeTruthy();
});
it('should retry getting jobs', fakeAsync(() => {
const spy = spyOn(fakeGcRepoService, 'getJobs').and.callThrough();
tick(11000);
it('should retry getting jobs', waitForAsync(() => {
fixture.detectChanges();
fixture.whenStable().then(() => {
expect(spy.calls.count()).toEqual(2);
expect(component.jobs[1].status).toEqual('finished');
});
}));

View File

@ -58,11 +58,13 @@
</clr-dg-cell>
</clr-dg-row>
<clr-dg-footer>
<span *ngIf="totalCount">{{pagination.firstItem + 1}} - {{pagination.lastItem + 1}}
<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}}
{{'DESTINATION.OF' | translate}}</span>
{{totalCount}} {{'SUMMARY.QUOTAS' | translate}}
<clr-dg-pagination #pagination [clrDgPageSize]="pageSize" [(clrDgPage)]="currentPage"
[clrDgTotalItems]="totalCount"></clr-dg-pagination>
</clr-dg-pagination>
</clr-dg-footer>
</clr-datagrid>
</div>

View File

@ -18,6 +18,7 @@ import { forkJoin } from 'rxjs';
import { QuotaService } from "../../../services/quota.service";
import { Router } from '@angular/router';
import { finalize } from 'rxjs/operators';
import { ClrDatagridStateInterface } from '@clr/angular';
const quotaSort = {
storage: "used.storage",
sortType: 'string'
@ -170,10 +171,11 @@ export class ProjectQuotasComponent implements OnChanges {
const storageUnit = this.getIntegerAndUnit(storageNumberAndUnit, 0).partCharacterHard;
this.quotaHardLimitValue = { storageLimit, storageUnit };
}
getQuotaList(state: State) {
getQuotaList(state: ClrDatagridStateInterface) {
if (!state || !state.page) {
return;
}
this.pageSize = state.page.size;
// Keep state for future filtering and sorting
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 { DebugElement } from "@angular/core";
import { NoopAnimationsModule } from "@angular/platform-browser/animations";
import { SharedModule } from "../../utils/shared/shared.module";
import { ConfirmationDialogComponent } from "../confirmation-dialog/confirmation-dialog.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 { CreateEditRuleComponent } from "./create-edit-rule.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 {
ReplicationService,
ReplicationDefaultService,
JobLogService,
JobLogDefaultService
} from "../../services";
@ -40,6 +36,8 @@ import {LabelPieceComponent} from "../label-piece/label-piece.component";
import { RouterTestingModule } from '@angular/router/testing';
import { of } from "rxjs";
import { CURRENT_BASE_HREF } from "../../utils/utils";
import {HttpHeaders, HttpResponse} from "@angular/common/http";
import {delay} from "rxjs/operators";
describe("CreateEditRuleComponent (inline template)", () => {
let mockRules: ReplicationRule[] = [
@ -203,35 +201,47 @@ describe("CreateEditRuleComponent (inline template)", () => {
"event_based"
]
};
let fixture: ComponentFixture<ReplicationComponent>;
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 fixture: ComponentFixture<CreateEditRuleComponent>;
let comp: CreateEditRuleComponent;
let config: IServiceConfig = {
replicationBaseEndpoint: CURRENT_BASE_HREF + "/replication/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(() => {
TestBed.configureTestingModule({
imports: [SharedModule, NoopAnimationsModule, RouterTestingModule],
declarations: [
ReplicationComponent,
ListReplicationRuleComponent,
CreateEditRuleComponent,
CronTooltipComponent,
ConfirmationDialogComponent,
@ -242,75 +252,40 @@ describe("CreateEditRuleComponent (inline template)", () => {
LabelPieceComponent
],
providers: [
ErrorHandler,
{ provide: ErrorHandler, useValue: fakedErrorHandler },
{ provide: SERVICE_CONFIG, useValue: config },
{ provide: ReplicationService, useClass: ReplicationDefaultService },
{ provide: EndpointService, useClass: EndpointDefaultService },
{ provide: JobLogService, useClass: JobLogDefaultService },
{ provide: OperationService },
{ provide: LabelService }
{ provide: ReplicationService, useValue: fakedReplicationService },
{ provide: EndpointService, useValue: fakedEndpointService },
]
});
}));
beforeEach(() => {
fixture = TestBed.createComponent(ReplicationComponent);
fixtureCreate = TestBed.createComponent(CreateEditRuleComponent);
fixture = TestBed.createComponent(CreateEditRuleComponent);
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();
});
it("Should open creation modal and load endpoints", waitForAsync(() => {
it("Should open creation modal and load endpoints", async () => {
fixture.detectChanges();
compCreate.openCreateEditRule();
fixture.whenStable().then(() => {
fixture.detectChanges();
let de: DebugElement = fixture.debugElement.query(By.css("input"));
expect(de).toBeTruthy();
let deSelect: DebugElement = fixture.debugElement.query(By.css("select"));
expect(deSelect).toBeTruthy();
let elSelect: HTMLElement = de.nativeElement;
expect(elSelect).toBeTruthy();
expect(elSelect.childNodes.item(0).textContent).toEqual("target_01");
});
}));
await fixture.whenStable();
comp.openCreateEditRule();
fixture.detectChanges();
await fixture.whenStable();
const modal = fixture.nativeElement.querySelector("clr-modal");
expect(modal).toBeTruthy();
const selectionOptions = fixture.nativeElement.querySelectorAll("#dest_registry>option");
expect(selectionOptions).toBeTruthy();
expect(selectionOptions.length).toEqual(5);
});
it("Should open modal to edit replication rule", waitForAsync(() => {
it("Should open modal to edit replication rule", fakeAsync( () => {
fixture.detectChanges();
compCreate.openCreateEditRule(mockRule.id);
fixture.whenStable().then(() => {
fixture.detectChanges();
let de: DebugElement = fixture.debugElement.query(By.css("input"));
expect(de).toBeTruthy();
fixture.detectChanges();
let el: HTMLElement = de.nativeElement;
expect(el).toBeTruthy();
expect(el.textContent.trim()).toEqual("sync_01");
});
comp.openCreateEditRule(mockRule.id);
fixture.detectChanges();
tick(5000);
const ruleNameInput: HTMLInputElement = fixture.nativeElement.querySelector("#ruleName");
expect(ruleNameInput).toBeTruthy();
expect(ruleNameInput.value.trim()).toEqual("sync_01");
}));
});

View File

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

View File

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

View File

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

View File

@ -1,5 +1,5 @@
<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>
<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>
@ -49,7 +49,7 @@
<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-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 class="status-width">
<div [ngSwitch]="p.enabled">
@ -83,8 +83,10 @@
</clr-dg-cell>
</clr-dg-row>
<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 [clrDgPageSize]="5"></clr-dg-pagination>
<clr-dg-pagination #pagination [(clrDgPage)]="page" [clrDgPageSize]="pageSize" [clrDgTotalItems]="totalCount">
<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-datagrid>
<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 { CURRENT_BASE_HREF } from "../../utils/utils";
import { delay } from "rxjs/operators";
import {HttpHeaders, HttpResponse} from "@angular/common/http";
describe('ListReplicationRuleComponent (inline template)', () => {
@ -52,20 +53,23 @@ describe('ListReplicationRuleComponent (inline template)', () => {
let fixture: ComponentFixture<ListReplicationRuleComponent>;
let comp: ListReplicationRuleComponent;
let replicationService: ReplicationService;
let spyRules: jasmine.Spy;
let config: IServiceConfig = {
replicationRuleEndpoint: CURRENT_BASE_HREF + '/policies/replication/testing'
};
const fakedReplicationService = {
getReplicationRules() {
return of(mockRules).pipe(delay(0));
},
updateReplicationRule() {
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 = {
@ -101,54 +105,59 @@ describe('ListReplicationRuleComponent (inline template)', () => {
beforeEach(() => {
fixture = TestBed.createComponent(ListReplicationRuleComponent);
comp = fixture.componentInstance;
replicationService = fixture.debugElement.injector.get(ReplicationService);
spyRules = spyOn(replicationService, 'getReplicationRules').and.returnValues(of(mockRules));
fixture.detectChanges();
});
it('Should load and render data', waitForAsync(() => {
it('Should load and render data', async () => {
fixture.detectChanges();
fixture.whenStable().then(() => {
fixture.detectChanges();
let de: DebugElement = fixture.debugElement.query(By.css('datagrid-cell'));
expect(de).toBeTruthy();
fixture.detectChanges();
let el: HTMLElement = de.nativeElement;
expect(el.textContent.trim()).toEqual('sync_01');
});
}));
it('should disable rule', () => {
await fixture.whenStable();
fixture.detectChanges();
const el = fixture.nativeElement.querySelector("clr-dg-cell");
expect(el).toBeTruthy();
fixture.detectChanges();
expect(el.textContent.trim()).toEqual('sync_01');
});
it('should disable rule', async () => {
fixture.detectChanges();
await fixture.whenStable();
comp.selectedRow = comp.rules[0];
comp.selectedRow.enabled = true;
fixture.detectChanges();
await fixture.whenStable();
const action: HTMLElement = fixture.nativeElement.querySelector("#rule-action");
action.click();
fixture.detectChanges();
await fixture.whenStable();
const disable: HTMLElement = fixture.nativeElement.querySelector("#rule-disable");
disable.click();
fixture.detectChanges();
await fixture.whenStable();
const button: HTMLElement = fixture.nativeElement.querySelector("#dialog-action-disable");
button.click();
fixture.detectChanges();
await fixture.whenStable();
const body: HTMLElement = fixture.nativeElement.querySelector(".modal-body");
expect(body).toBeFalsy();
});
it('should enable rule', () => {
it('should enable rule', async () => {
fixture.detectChanges();
await fixture.whenStable();
comp.selectedRow = comp.rules[0];
comp.selectedRow.enabled = false;
fixture.detectChanges();
await fixture.whenStable();
const action: HTMLElement = fixture.nativeElement.querySelector("#rule-action");
action.click();
fixture.detectChanges();
await fixture.whenStable();
const enable: HTMLElement = fixture.nativeElement.querySelector("#rule-enable");
enable.click();
fixture.detectChanges();
await fixture.whenStable();
const button: HTMLElement = fixture.nativeElement.querySelector("#dialog-action-enable");
button.click();
fixture.detectChanges();
await fixture.whenStable();
const body: HTMLElement = fixture.nativeElement.querySelector(".modal-body");
expect(body).toBeFalsy();
});

View File

@ -15,18 +15,11 @@ import {
Component,
Input,
Output,
OnInit,
EventEmitter,
ViewChild,
ChangeDetectionStrategy,
ChangeDetectorRef,
OnChanges,
SimpleChange,
SimpleChanges
} from "@angular/core";
import { Comparator } from "../../services";
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 { ReplicationService } from "../../services";
import {
@ -41,33 +34,23 @@ import {
ConfirmationButtons
} from "../../entities/shared.const";
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 { OperationService } from "../operation/operation.service";
import { errorHandler as errorHandFn} from "../../utils/shared/shared.utils";
const jobstatus = "InProgress";
import { ClrDatagridStateInterface } from '@clr/angular';
@Component({
selector: "hbr-list-replication-rule",
templateUrl: "./list-replication-rule.component.html",
styleUrls: ["./list-replication-rule.component.scss"],
changeDetection: ChangeDetectionStrategy.OnPush
})
export class ListReplicationRuleComponent implements OnInit, OnChanges {
nullTime = "0001-01-01T00:00:00Z";
@Input() projectId: number;
export class ListReplicationRuleComponent {
@Input() selectedId: number | string;
@Input() withReplicationJob: boolean;
@Input() loading = false;
@Input() hasCreateReplicationPermission: boolean;
@Input() hasUpdateReplicationPermission: boolean;
@Input() hasDeleteReplicationPermission: boolean;
@Input() hasExecuteReplicationPermission: boolean;
@Output() reload = new EventEmitter<boolean>();
@Output() selectOne = new EventEmitter<ReplicationRule>();
@Output() editOne = new EventEmitter<ReplicationRule>();
@Output() toggleOne = new EventEmitter<ReplicationRule>();
@ -75,30 +58,22 @@ export class ListReplicationRuleComponent implements OnInit, OnChanges {
@Output() redirect = new EventEmitter<ReplicationRule>();
@Output() openNewRule = new EventEmitter<any>();
@Output() replicateManual = new EventEmitter<ReplicationRule>();
projectScope = false;
rules: ReplicationRule[];
changedRules: ReplicationRule[];
ruleName: string;
rules: ReplicationRule[] = [];
selectedRow: ReplicationRule;
@ViewChild("toggleConfirmDialog")
toggleConfirmDialog: ConfirmationDialogComponent;
@ViewChild("deletionConfirmDialog")
deletionConfirmDialog: ConfirmationDialogComponent;
startTimeComparator: Comparator<ReplicationRule> = new CustomComparator<ReplicationRule>("start_time", "date");
enabledComparator: Comparator<ReplicationRule> = new CustomComparator<ReplicationRule>("enabled", "number");
page: number = 1;
pageSize: number = 5;
totalCount: number = 0;
ruleName: string = "";
loading: boolean = true;
constructor(private replicationService: ReplicationService,
private translateService: TranslateService,
private errorHandler: ErrorHandler,
private operationService: OperationService,
private ref: ChangeDetectorRef) {
setInterval(() => ref.markForCheck(), 500);
private operationService: OperationService) {
}
trancatedDescription(desc: string): string {
@ -108,47 +83,9 @@ export class ListReplicationRuleComponent implements OnInit, OnChanges {
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 {
this.replicateManual.emit(rule);
}
deletionConfirm(message: ConfirmationAcknowledgement) {
if (
message &&
@ -174,7 +111,7 @@ export class ListReplicationRuleComponent implements OnInit, OnChanges {
.subscribe(msg => {
operateChanges(opeMessage, OperationState.success);
this.errorHandler.info(msg);
this.retrieveRules('');
this.refreshRule();
});
}, error => {
const errMessage = errorHandFn(error);
@ -228,9 +165,7 @@ export class ListReplicationRuleComponent implements OnInit, OnChanges {
forkJoin(...observableLists).subscribe(item => {
this.selectedRow = null;
this.reload.emit(true);
let hnd = setInterval(() => this.ref.markForCheck(), 200);
setTimeout(() => clearInterval(hnd), 2000);
this.refreshRule();
}, error => {
this.errorHandler.error(error);
});
@ -290,4 +225,36 @@ export class ListReplicationRuleComponent implements OnInit, OnChanges {
);
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>
<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.RESOURCE' | translate}}</clr-dg-column>
<clr-dg-column>{{'AUDIT_LOG.RESOURCE_TYPE' | translate}}</clr-dg-column>
@ -35,10 +35,12 @@
<clr-dg-cell>{{l.op_time | date: 'short'}}</clr-dg-cell>
</clr-dg-row>
<clr-dg-footer>
<span *ngIf="totalCount">{{pagination.firstItem + 1}} - {{pagination.lastItem + 1}} {{'AUDIT_LOG.OF' | translate}} {{totalCount}} {{'AUDIT_LOG.ITEMS'
<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'
| translate}}</span>
<clr-dg-pagination #pagination [(clrDgPage)]="currentPage" [clrDgPageSize]="pageSize" [clrDgTotalItems]="totalCount"></clr-dg-pagination>
</clr-dg-pagination>
</clr-dg-footer>
</clr-datagrid>
</div>
</div>
</div>

View File

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

View File

@ -118,8 +118,10 @@
</clr-dg-cell>
</clr-dg-row>
<clr-dg-footer>
<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 #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}}
</clr-dg-pagination>
</clr-dg-footer>
</clr-datagrid>
</div>

View File

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

View File

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

View File

@ -1,32 +1,23 @@
import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing';
import { By } from '@angular/platform-browser';
import { DebugElement, CUSTOM_ELEMENTS_SCHEMA } from '@angular/core';
import {ComponentFixture, TestBed, waitForAsync} from '@angular/core/testing';
import {DebugElement, CUSTOM_ELEMENTS_SCHEMA, NO_ERRORS_SCHEMA} from '@angular/core';
import { NoopAnimationsModule } from "@angular/platform-browser/animations";
import { SharedModule } from '../../utils/shared/shared.module';
import { ConfirmationDialogComponent } from '../confirmation-dialog/confirmation-dialog.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 { 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 { CronTooltipComponent } from "../cron-schedule/cron-tooltip/cron-tooltip.component";
import { ErrorHandler } from '../../utils/error-handler/error-handler';
import { SERVICE_CONFIG, IServiceConfig } from '../../entities/service.config';
import { ReplicationService, ReplicationDefaultService } from '../../services/replication.service';
import { EndpointService, EndpointDefaultService } from '../../services/endpoint.service';
import { JobLogService, JobLogDefaultService, ReplicationJobItem } from '../../services';
import {ProjectDefaultService, ProjectService} from "../../services/project.service";
import { ReplicationService } from '../../services/replication.service';
import { ReplicationJobItem } from '../../services';
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 { of } from 'rxjs';
import {of, Subscription} from 'rxjs';
import { CURRENT_BASE_HREF } from "../../utils/utils";
import {HttpHeaders, HttpResponse} from "@angular/common/http";
import {delay} from "rxjs/operators";
describe('Replication Component (inline template)', () => {
@ -129,33 +120,37 @@ describe('Replication Component (inline template)', () => {
metadata: {xTotalCount: 3},
data: mockJobs
};
let fixture: ComponentFixture<ReplicationComponent>;
let fixtureCreate: ComponentFixture<CreateEditRuleComponent>;
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 elRule: HTMLElement;
let elJob: HTMLElement;
let config: IServiceConfig = {
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(() => {
TestBed.configureTestingModule({
schemas: [ CUSTOM_ELEMENTS_SCHEMA ],
schemas: [ CUSTOM_ELEMENTS_SCHEMA ,
NO_ERRORS_SCHEMA],
imports: [
SharedModule,
NoopAnimationsModule,
@ -163,131 +158,37 @@ describe('Replication Component (inline template)', () => {
],
declarations: [
ReplicationComponent,
ListReplicationRuleComponent,
CreateEditRuleComponent,
CronTooltipComponent,
CronScheduleComponent,
ConfirmationDialogComponent,
DatePickerComponent,
FilterComponent,
InlineAlertComponent,
FilterLabelComponent,
LabelPieceComponent
],
providers: [
ErrorHandler,
{ provide: ErrorHandler, useValue: fakedErrorHandler },
{ provide: SERVICE_CONFIG, useValue: config },
{ provide: ReplicationService, useClass: ReplicationDefaultService },
{ provide: EndpointService, useClass: EndpointDefaultService },
{ provide: ProjectService, useClass: ProjectDefaultService },
{ provide: JobLogService, useClass: JobLogDefaultService },
{ provide: ReplicationService, useValue: fakedReplicationService },
{ provide: OperationService }
]
});
}));
beforeEach(() => {
fixture = TestBed.createComponent(ReplicationComponent);
fixtureCreate = TestBed.createComponent(CreateEditRuleComponent);
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));
spyJobs = spyOn(replicationService, 'getExecutions').and.returnValues(of(mockJob));
spyEndpoints = spyOn(endpointService, 'getEndpoints').and.returnValues(of(mockEndpoints));
comp.withReplicationJob = true;
comp.hiddenJobList = false;
comp.searchSub = new Subscription();
spyOn(comp, "clrLoadJobs").and.returnValue(undefined);
comp.jobs = mockJobs;
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 rules', waitForAsync(() => {
it('Should load replication jobs', async () => {
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');
});
}));
await fixture.whenStable();
const rows = fixture.nativeElement.querySelectorAll("clr-dg-row");
expect(rows).toBeTruthy();
expect(rows.length).toEqual(3);
});
it('function "getDuration" should work', () => {
// ms level
const item: ReplicationJobItem = {

View File

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

View File

@ -17,6 +17,7 @@ import {
import { RequestQueryParams } from "./RequestQueryParams";
import { map, catchError } from "rxjs/operators";
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.
*
@ -45,6 +46,12 @@ export abstract class ReplicationService {
queryParams?: RequestQueryParams
):
| Observable<ReplicationRule[]>;
abstract getReplicationRulesResponse(
ruleName?: string,
page?: number ,
pageSize?: number,
queryParams?: RequestQueryParams
): Observable<HttpResponse<ReplicationRule[]>>;
/**
* Get the specified replication rule.
@ -256,7 +263,7 @@ export class ReplicationDefaultService extends ReplicationService {
):
| Observable<ReplicationRule[]> {
if (!queryParams) {
queryParams = queryParams = new RequestQueryParams();
queryParams = new RequestQueryParams();
}
if (projectId) {
@ -266,12 +273,33 @@ export class ReplicationDefaultService extends ReplicationService {
if (ruleName) {
queryParams = queryParams.set("name", ruleName);
}
return this.http
.get(this._ruleBaseUrl, buildHttpRequestOptions(queryParams))
.pipe(map(response => response as ReplicationRule[])
, 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(
ruleId: number | string