Refactor tag-retention page (#14749)

Signed-off-by: AllForNothing <sshijun@vmware.com>
This commit is contained in:
Will Sun 2021-04-26 14:27:44 +08:00 committed by GitHub
parent c946457eef
commit af12f9aa01
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 370 additions and 184 deletions

View File

@ -8,6 +8,7 @@ import { TagRetentionService } from './tag-retention/tag-retention.service';
import { ImmutableTagComponent } from "./immutable-tag/immutable-tag.component";
import { ImmutableTagService } from "./immutable-tag/immutable-tag.service";
import { AddImmutableRuleComponent } from "./immutable-tag/add-rule/add-immutable-rule.component";
import { TagRetentionTasksComponent } from './tag-retention/tag-retention-tasks/tag-retention-tasks/tag-retention-tasks.component';
const routes: Routes = [
@ -37,7 +38,8 @@ const routes: Routes = [
TagRetentionComponent,
AddRuleComponent,
ImmutableTagComponent,
AddImmutableRuleComponent
AddImmutableRuleComponent,
TagRetentionTasksComponent
],
providers: [
TagRetentionService,

View File

@ -155,3 +155,6 @@ export class RuleMetadate {
}
}
export const RUNNING: string = "Running";
export const PENDING: string = "pending";
export const TIMEOUT: number = 5000;

View File

@ -0,0 +1,6 @@
.hand {
cursor: pointer;
}
.color-79b {
color: #0079b8;
}

View File

@ -0,0 +1,29 @@
<clr-datagrid (clrDgRefresh)="loadLog()" [clrDgLoading]="loading" class="w-100">
<clr-dg-column>{{'TAG_RETENTION.REPOSITORY' | translate}}</clr-dg-column>
<clr-dg-column>{{'TAG_RETENTION.STATUS' | translate}}</clr-dg-column>
<clr-dg-column>{{'TAG_RETENTION.RETAINED' | translate}}/{{'TAG_RETENTION.TOTAL' | translate}}</clr-dg-column>
<clr-dg-column>{{'TAG_RETENTION.START_TIME' | translate}}</clr-dg-column>
<clr-dg-column>{{'TAG_RETENTION.DURATION' | translate}}</clr-dg-column>
<clr-dg-column>{{'TAG_RETENTION.LOG' | translate}}</clr-dg-column>
<clr-dg-placeholder>
{{'TAG_RETENTION.NO_HISTORY' | translate}}
</clr-dg-placeholder>
<clr-dg-row *ngFor="let task of tasks" [clrDgItem]="task">
<clr-dg-cell>{{task.repository}}</clr-dg-cell>
<clr-dg-cell>{{task.status}}</clr-dg-cell>
<clr-dg-cell>{{task?.retained?task?.retained:0}}/{{task?.total?task?.total:0}}</clr-dg-cell>
<clr-dg-cell>{{task.start_time| harborDatetime:'medium'}}</clr-dg-cell>
<clr-dg-cell>{{task.duration}}</clr-dg-cell>
<clr-dg-cell><span (click)="seeLog(task.execution_id,task.id)"
class="hand color-79b"><clr-icon shape="list"></clr-icon></span>
</clr-dg-cell>
</clr-dg-row>
<clr-dg-footer>
<span *ngIf="innerPagination">{{innerPagination.firstItem + 1}}
-
{{innerPagination.lastItem + 1 }} {{'ROBOT_ACCOUNT.OF' |
translate}} </span>
{{ total }} {{'ROBOT_ACCOUNT.ITEMS' | translate}}
<clr-dg-pagination [clrDgTotalItems]="tasksTimeout" [(clrDgPage)]="page" #innerPagination [clrDgPageSize]="pageSize"></clr-dg-pagination>
</clr-dg-footer>
</clr-datagrid>

View File

@ -0,0 +1,89 @@
import { ComponentFixture, fakeAsync, TestBed, tick } from '@angular/core/testing';
import { TagRetentionTasksComponent } from './tag-retention-tasks.component';
import { SharedTestingModule } from "../../../../../../shared/shared.module";
import { TagRetentionService } from "../../tag-retention.service";
import { HttpHeaders, HttpResponse } from "@angular/common/http";
import { Registry } from "../../../../../../../../ng-swagger-gen/models/registry";
import { of } from "rxjs";
import { delay } from "rxjs/operators";
import { TIMEOUT } from "../../retention";
describe('TagRetentionTasksComponent', () => {
let component: TagRetentionTasksComponent;
let fixture: ComponentFixture<TagRetentionTasksComponent>;
const mockedRunningTasks = [{
"end_time": "2021-04-26T04:32:21Z",
"execution_id": 57,
"id": 55,
"job_id": "85f5d7edab421456aae0159f",
"repository": "hello-world",
"retained": 1,
"start_time": "2021-04-26T04:32:18Z",
"status": "Running",
"status_code": 3,
"total": 1
}];
const mockedSuccessTasks = [{
"end_time": "2021-04-26T04:32:21Z",
"execution_id": 57,
"id": 55,
"job_id": "85f5d7edab421456aae0159f",
"repository": "hello-world",
"retained": 1,
"start_time": "2021-04-26T04:32:18Z",
"status": "Success",
"status_code": 3,
"total": 1
}];
const mockTagRetentionService = {
count: 0,
getExecutionHistory() {
if (this.count === 0) {
this.count += 1;
const response: HttpResponse<Array<Registry>> = new HttpResponse<Array<Registry>>({
headers: new HttpHeaders({'x-total-count': mockedRunningTasks.length.toString()}),
body: mockedRunningTasks
});
return of(response).pipe(delay(0));
} else {
this.count += 1;
const response: HttpResponse<Array<Registry>> = new HttpResponse<Array<Registry>>({
headers: new HttpHeaders({'x-total-count': mockedSuccessTasks.length.toString()}),
body: mockedSuccessTasks
});
return of(response).pipe(delay(0));
}
}
};
beforeEach(async () => {
await TestBed.configureTestingModule({
imports: [
SharedTestingModule
],
declarations: [TagRetentionTasksComponent],
providers: [
{provide: TagRetentionService, useValue: mockTagRetentionService},
]
})
.compileComponents();
});
beforeEach(() => {
fixture = TestBed.createComponent(TagRetentionTasksComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
it('should retry getting tasks', fakeAsync(() => {
tick(TIMEOUT);
fixture.detectChanges();
fixture.whenStable().then(() => {
expect(component.tasks[0].status).toEqual('Success');
});
}));
});

View File

@ -0,0 +1,82 @@
import { Component, Input, OnDestroy, OnInit } from '@angular/core';
import { finalize } from "rxjs/operators";
import { TagRetentionComponent } from "../../tag-retention.component";
import { TagRetentionService } from "../../tag-retention.service";
import { ErrorHandler } from "../../../../../../shared/units/error-handler";
import { PENDING, RUNNING, TIMEOUT } from "../../retention";
@Component({
selector: 'app-tag-retention-tasks',
templateUrl: './tag-retention-tasks.component.html',
styleUrls: ['./tag-retention-tasks.component.css']
})
export class TagRetentionTasksComponent implements OnInit, OnDestroy {
@Input()
retentionId;
@Input()
executionId;
loading: boolean = true;
page: number = 1;
pageSize: number = 5;
total: number = 0;
tasks = [];
tasksTimeout;
constructor(private tagRetentionService: TagRetentionService,
private errorHandler: ErrorHandler) { }
ngOnInit(): void {
}
ngOnDestroy() {
if (this.tasksTimeout) {
clearTimeout(this.tasksTimeout);
this.tasksTimeout = null;
}
}
loadLog() {
this.loading = true;
this.tagRetentionService.getExecutionHistory(this.retentionId, this.executionId, this.page, this.pageSize)
.pipe(finalize(() => this.loading = false))
.subscribe(
(response: any) => {
// Get total count
if (response.headers) {
let xHeader: string = response.headers.get("x-total-count");
if (xHeader) {
this.total = parseInt(xHeader, 0);
}
}
this.tasks = response.body as Array<any>;
TagRetentionComponent.calculateDuration(this.tasks);
this.loopGettingTasks();
}, error => {
this.errorHandler.error(error);
});
}
seeLog(executionId, taskId) {
this.tagRetentionService.seeLog(this.retentionId, executionId, taskId);
}
loopGettingTasks() {
if (this.tasks && this.tasks.length
&& this.tasks.some(item => {
return item.status === RUNNING || item.status === PENDING;
})) {
this.tasksTimeout = setTimeout(() => {
this.loading = true;
this.tagRetentionService.getExecutionHistory(this.retentionId, this.executionId, this.page, this.pageSize)
.pipe(finalize(() => this.loading = false))
.subscribe(res => {
// Get total count
if (res.headers) {
let xHeader: string = res.headers.get("x-total-count");
if (xHeader) {
this.total = parseInt(xHeader, 0);
}
}
this.tasks = res.body as Array<any>;
TagRetentionComponent.calculateDuration(this.tasks);
this.loopGettingTasks();
});
}, TIMEOUT);
}
}
}

View File

@ -110,50 +110,16 @@
<clr-dg-placeholder>
{{'TAG_RETENTION.NO_EXECUTION' | translate}}
</clr-dg-placeholder>
<clr-dg-row *ngFor="let execution of executionList;let i = index;" [clrDgItem]="execution">
<clr-dg-cell class="hand" (click)="openDetail(i,execution.id)">
<clr-icon shape="angle" [dir]="index===i?'down':'right'"></clr-icon>
<span class="ml-1">{{execution.id}}</span>
<clr-dg-row *ngFor="let execution of executionList;" [clrDgItem]="execution">
<clr-dg-cell>
<span>{{execution.id}}</span>
</clr-dg-cell>
<clr-dg-cell class="hand" (click)="openDetail(i,execution.id)">{{execution.status}}</clr-dg-cell>
<clr-dg-cell class="hand"
(click)="openDetail(i,execution.id)">{{(execution.dry_run ? 'TAG_RETENTION.YES' : 'TAG_RETENTION.NO') | translate}}</clr-dg-cell>
<clr-dg-cell class="hand"
(click)="openDetail(i,execution.id)">{{execution.trigger}}</clr-dg-cell>
<clr-dg-cell class="hand"
(click)="openDetail(i,execution.id)">{{execution.start_time| harborDatetime:'medium'}}</clr-dg-cell>
<clr-dg-cell class="hand" (click)="openDetail(i,execution.id)">{{execution.duration}}</clr-dg-cell>
<clr-dg-row-detail *ngIf="index===i">
<clr-datagrid (clrDgRefresh)="loadLog()" [clrDgLoading]="loadingHistories" class="w-100">
<clr-dg-column>{{'TAG_RETENTION.REPOSITORY' | translate}}</clr-dg-column>
<clr-dg-column>{{'TAG_RETENTION.STATUS' | translate}}</clr-dg-column>
<clr-dg-column>{{'TAG_RETENTION.RETAINED' | translate}}/{{'TAG_RETENTION.TOTAL' | translate}}</clr-dg-column>
<clr-dg-column>{{'TAG_RETENTION.START_TIME' | translate}}</clr-dg-column>
<clr-dg-column>{{'TAG_RETENTION.DURATION' | translate}}</clr-dg-column>
<clr-dg-column>{{'TAG_RETENTION.LOG' | translate}}</clr-dg-column>
<clr-dg-placeholder>
{{'TAG_RETENTION.NO_HISTORY' | translate}}
</clr-dg-placeholder>
<clr-dg-row *ngFor="let task of historyList" [clrDgItem]="task">
<clr-dg-cell>{{task.repository}}</clr-dg-cell>
<clr-dg-cell>{{task.status}}</clr-dg-cell>
<clr-dg-cell>{{task?.retained?task?.retained:0}}/{{task?.total?task?.total:0}}</clr-dg-cell>
<clr-dg-cell>{{task.start_time| harborDatetime:'medium'}}</clr-dg-cell>
<clr-dg-cell>{{task.duration}}</clr-dg-cell>
<clr-dg-cell><span (click)="seeLog(task.execution_id,task.id)"
class="hand color-79b">{{'TAG_RETENTION.LOG' | translate}}</span>
</clr-dg-cell>
</clr-dg-row>
<clr-dg-footer>
<span *ngIf="logPageSize">{{innerPagination.firstItem + 1}}
-
{{innerPagination.lastItem + 1 }} {{'ROBOT_ACCOUNT.OF' |
translate}} </span>
{{ totalLogCount }} {{'ROBOT_ACCOUNT.ITEMS' | translate}}
<clr-dg-pagination [clrDgTotalItems]="totalLogCount" [(clrDgPage)]="currentLogPage" #innerPagination [clrDgPageSize]="logPageSize"></clr-dg-pagination>
</clr-dg-footer>
</clr-datagrid>
</clr-dg-row-detail>
<clr-dg-cell>{{execution.status}}</clr-dg-cell>
<clr-dg-cell>{{(execution.dry_run ? 'TAG_RETENTION.YES' : 'TAG_RETENTION.NO') | translate}}</clr-dg-cell>
<clr-dg-cell>{{(execution?.trigger ? 'SCHEDULE.' + execution?.trigger.toUpperCase() : '') | translate }}</clr-dg-cell>
<clr-dg-cell>{{execution.start_time| harborDatetime:'medium'}}</clr-dg-cell>
<clr-dg-cell>{{execution.duration}}</clr-dg-cell>
<app-tag-retention-tasks *clrIfExpanded [executionId]="execution.id" [retentionId]="retentionId" ngProjectAs="clr-dg-row-detail"></app-tag-retention-tasks>
</clr-dg-row>
<clr-dg-footer>
<clr-dg-pagination [clrDgTotalItems]="totalCount" #pagination [(clrDgPage)]="currentPage" [clrDgPageSize]="pageSize">

View File

@ -1,91 +1,124 @@
import { waitForAsync, ComponentFixture, TestBed } from '@angular/core/testing';
import { TranslateService } from '@ngx-translate/core';
import { waitForAsync, ComponentFixture, TestBed, fakeAsync, tick } from '@angular/core/testing';
import { TagRetentionComponent } from './tag-retention.component';
import { CUSTOM_ELEMENTS_SCHEMA } from '@angular/core';
import { of } from 'rxjs';
import { ActivatedRoute } from '@angular/router';
import { AddRuleComponent } from "./add-rule/add-rule.component";
import { TagRetentionService } from "./tag-retention.service";
import { RuleMetadate, Retention } from './retention';
import { RuleMetadate, Retention, TIMEOUT } from './retention';
import { delay } from 'rxjs/operators';
import { ErrorHandler } from "../../../../shared/units/error-handler";
import { SharedTestingModule } from "../../../../shared/shared.module";
import { HttpHeaders, HttpResponse } from "@angular/common/http";
import { Registry } from "../../../../../../ng-swagger-gen/models/registry";
describe('TagRetentionComponent', () => {
let component: TagRetentionComponent;
let fixture: ComponentFixture<TagRetentionComponent>;
const mockTagRetentionService = {
createRetention: () => of(null).pipe(delay(0)),
updateRetention: () => of(null).pipe(delay(0)),
runNowTrigger: () => of(null).pipe(delay(0)),
whatIfRunTrigger: () => of(null).pipe(delay(0)),
AbortRun: () => of(null).pipe(delay(0)),
seeLog: () => of(null).pipe(delay(0)),
getExecutionHistory: () => of({
body: []
}).pipe(delay(0)),
getRunNowList: () => of({
body: []
}).pipe(delay(0)),
getProjectInfo: () => of({
metadata: {
retention_id: 1
}
}).pipe(delay(0)),
getRetentionMetadata: () => of(new RuleMetadate()).pipe(delay(0)),
getRetention: () => of(new Retention()).pipe(delay(0)),
};
const mockActivatedRoute = {
snapshot: {
parent: {
parent: {
parent: {
params: { id: 1 },
data: {
projectResolver: {
metadata: {
retention_id: 1
}
}
}
}
const mockedRunningExecutions = [{
"dry_run": true,
"end_time": "2021-04-26T04:32:21Z",
"id": 57,
"policy_id": 1,
"start_time": "2021-04-26T04:32:18.032419Z",
"status": "Running",
"trigger": "MANUAL"
}];
const mockedSuccessExecutions = [{
"dry_run": true,
"end_time": "2021-04-26T04:32:21Z",
"id": 57,
"policy_id": 1,
"start_time": "2021-04-26T04:32:18.032419Z",
"status": "Success",
"trigger": "MANUAL"
}];
let component: TagRetentionComponent;
let fixture: ComponentFixture<TagRetentionComponent>;
const mockTagRetentionService = {
createRetention: () => of(null).pipe(delay(0)),
updateRetention: () => of(null).pipe(delay(0)),
runNowTrigger: () => of(null).pipe(delay(0)),
whatIfRunTrigger: () => of(null).pipe(delay(0)),
AbortRun: () => of(null).pipe(delay(0)),
seeLog: () => of(null).pipe(delay(0)),
getExecutionHistory: () => of({
body: []
}).pipe(delay(0)),
count: 0,
getRunNowList() {
if (this.count === 0) {
this.count += 1;
const response: HttpResponse<Array<Registry>> = new HttpResponse<Array<Registry>>({
headers: new HttpHeaders({'x-total-count': mockedRunningExecutions.length.toString()}),
body: mockedRunningExecutions
});
return of(response).pipe(delay(0));
} else {
this.count += 1;
const response: HttpResponse<Array<Registry>> = new HttpResponse<Array<Registry>>({
headers: new HttpHeaders({'x-total-count': mockedSuccessExecutions.length.toString()}),
body: mockedSuccessExecutions
});
return of(response).pipe(delay(0));
}
},
getProjectInfo: () => of({
metadata: {
retention_id: 1
}
}).pipe(delay(0)),
getRetentionMetadata: () => of(new RuleMetadate()).pipe(delay(0)),
getRetention: () => of(new Retention()).pipe(delay(0)),
};
const mockActivatedRoute = {
snapshot: {
parent: {
parent: {
parent: {
params: {id: 1},
data: {
projectResolver: {
metadata: {
retention_id: 1
}
}
}
}
}
};
const mockErrorHandler = {
error: () => { }
};
beforeEach(waitForAsync(() => {
TestBed.configureTestingModule({
schemas: [
CUSTOM_ELEMENTS_SCHEMA
],
imports: [
SharedTestingModule
],
declarations: [TagRetentionComponent, AddRuleComponent],
providers: [
TranslateService,
{ provide: TagRetentionService, useValue: mockTagRetentionService },
{ provide: ActivatedRoute, useValue: mockActivatedRoute },
{ provide: ErrorHandler, useValue: mockErrorHandler }
}
}
};
beforeEach(waitForAsync(() => {
TestBed.configureTestingModule({
schemas: [
CUSTOM_ELEMENTS_SCHEMA
],
imports: [
SharedTestingModule
],
declarations: [TagRetentionComponent, AddRuleComponent],
providers: [
{provide: TagRetentionService, useValue: mockTagRetentionService},
{provide: ActivatedRoute, useValue: mockActivatedRoute},
]
})
.compileComponents();
}));
]
})
.compileComponents();
}));
beforeEach(() => {
fixture = TestBed.createComponent(TagRetentionComponent);
component = fixture.componentInstance;
component.loadingRule = false;
fixture.detectChanges();
});
beforeEach(() => {
fixture = TestBed.createComponent(TagRetentionComponent);
component = fixture.componentInstance;
component.loadingHistories = false;
component.loadingRule = false;
component.loadingHistories = false;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
it('should create', () => {
expect(component).toBeTruthy();
});
it('should retry getting executions', fakeAsync(() => {
tick(TIMEOUT);
fixture.detectChanges();
fixture.whenStable().then(() => {
expect(component.executionList[0].status).toEqual('Success');
});
}));
});

View File

@ -11,17 +11,17 @@
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
import { Component, OnInit, ViewChild } from '@angular/core';
import { Component, OnDestroy, OnInit, ViewChild } from '@angular/core';
import { ActivatedRoute } from '@angular/router';
import { AddRuleComponent } from "./add-rule/add-rule.component";
import {ClrDatagridStateInterface, ClrDatagridStringFilterInterface} from "@clr/angular";
import { ClrDatagridStateInterface, ClrDatagridStringFilterInterface } from "@clr/angular";
import { TagRetentionService } from "./tag-retention.service";
import { Retention, Rule } from "./retention";
import { PENDING, Retention, Rule, RUNNING, TIMEOUT } from "./retention";
import { finalize } from "rxjs/operators";
import { CronScheduleComponent } from "../../../../shared/components/cron-schedule";
import { ErrorHandler } from "../../../../shared/units/error-handler";
import { OriginCron } from "../../../../shared/services";
import {clone, DEFAULT_PAGE_SIZE} from "../../../../shared/units/utils";
import { clone, DEFAULT_PAGE_SIZE} from "../../../../shared/units/utils";
const MIN = 60000;
const SEC = 1000;
@ -38,15 +38,12 @@ const DECORATION = {
MATCHES: "matches",
EXCLUDES: "excludes",
};
const RUNNING: string = "Running";
const PENDING: string = "pending";
const TIMEOUT: number = 5000;
@Component({
selector: 'tag-retention',
templateUrl: './tag-retention.component.html',
styleUrls: ['./tag-retention.component.scss']
})
export class TagRetentionComponent implements OnInit {
export class TagRetentionComponent implements OnInit, OnDestroy {
serialFilter: ClrDatagridStringFilterInterface<any> = {
accepts(item: any, search: string): boolean {
return item.id.toString().indexOf(search) !== -1;
@ -70,27 +67,21 @@ export class TagRetentionComponent implements OnInit {
cron: string;
selectedItem: any = null;
ruleIndex: number = -1;
index: number = -1;
retentionId: number;
retention: Retention = new Retention();
editIndex: number;
executionList = [];
executionId: number;
historyList = [];
loadingExecutions: boolean = true;
loadingHistories: boolean = true;
label: string = 'TAG_RETENTION.TRIGGER';
loadingRule: boolean = false;
currentPage: number = 1;
pageSize: number = DEFAULT_PAGE_SIZE;
totalCount: number = 0;
currentLogPage: number = 1;
totalLogCount: number = 0;
logPageSize: number = 5;
isDetailOpened: boolean = false;
@ViewChild('cronScheduleComponent')
cronScheduleComponent: CronScheduleComponent;
@ViewChild('addRule') addRuleComponent: AddRuleComponent;
executionTimeout;
constructor(
private route: ActivatedRoute,
private tagRetentionService: TagRetentionService,
@ -126,6 +117,13 @@ export class TagRetentionComponent implements OnInit {
this.refreshAfterCreatRetention();
this.getMetadata();
}
ngOnDestroy() {
if (this.executionTimeout) {
clearTimeout(this.executionTimeout);
this.executionTimeout = null;
}
}
openConfirm(cron: string) {
if (cron) {
this.isConfirmOpened = true;
@ -274,15 +272,36 @@ export class TagRetentionComponent implements OnInit {
this.errorHandler.error(error);
});
}
loopGettingExecutions() {
if (this.executionList && this.executionList.length && this.executionList.some(item => {
return item.status === RUNNING || item.status === PENDING;
})) {
this.executionTimeout = setTimeout(() => {
this.loadingExecutions = true;
this.tagRetentionService.getRunNowList(this.retentionId, this.currentPage, this.pageSize)
.pipe(finalize(() => this.loadingExecutions = false))
.subscribe(res => {
// Get total count
if (res.headers) {
let xHeader: string = res.headers.get("x-total-count");
if (xHeader) {
this.totalCount = parseInt(xHeader, 0);
}
}
this.executionList = res.body as Array<any>;
TagRetentionComponent.calculateDuration(this.executionList);
this.loopGettingExecutions();
});
}, TIMEOUT);
}
}
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.loadingExecutions = true;
this.tagRetentionService.getRunNowList(this.retentionId, this.currentPage, this.pageSize)
.pipe(finalize(() => this.loadingExecutions = false))
.subscribe(
@ -296,13 +315,14 @@ export class TagRetentionComponent implements OnInit {
}
this.executionList = response.body as Array<any>;
TagRetentionComponent.calculateDuration(this.executionList);
this.loopGettingExecutions();
}, error => {
this.errorHandler.error(error);
});
} else {
setTimeout(() => {
this.loadingExecutions = false;
});
setTimeout(() => {
this.loadingExecutions = false;
}, 0);
}
}
@ -352,50 +372,6 @@ export class TagRetentionComponent implements OnInit {
this.ruleIndex = -1;
}
}
loadLog() {
if (this.isDetailOpened) {
setTimeout(() => {// when this.isDetailOpened is true, need to wait ngCheck finished
this.loadingHistories = true;
this.tagRetentionService.getExecutionHistory(this.retentionId, this.executionId, this.currentLogPage, this.logPageSize)
.pipe(finalize(() => this.loadingHistories = false))
.subscribe(
(response: any) => {
// Get total count
if (response.headers) {
let xHeader: string = response.headers.get("x-total-count");
if (xHeader) {
this.totalLogCount = parseInt(xHeader, 0);
}
}
this.historyList = response.body as Array<any>;
TagRetentionComponent.calculateDuration(this.historyList);
if (this.historyList && this.historyList.length
&& this.historyList.some(item => {
return item.status === RUNNING || item.status === PENDING;
})) {
setTimeout(() => {
this.loadLog();
}, TIMEOUT);
}
}, error => {
this.errorHandler.error(error);
});
}, 0);
}
}
openDetail(index, executionId) {
if (this.index !== index) {
this.index = index;
this.historyList = [];
this.executionId = executionId;
this.isDetailOpened = true;
} else {
this.index = -1;
this.isDetailOpened = false;
}
}
refreshAfterCreatRetention() {
this.tagRetentionService.getProjectInfo(this.projectId).subscribe(
response => {

View File

@ -33,7 +33,7 @@ ${project_tag_retention_span_daily_xpath} //cron-selection//div//span[contains(
${project_tag_retention_dry_run_xpath} //*[@id='dry-run']
${project_tag_retention_refresh_xpath} //clr-dg-action-bar/button[4]
${project_tag_retention_record_yes_xpath} //clr-datagrid[contains(.,'Yes')]
${project_tag_retention_list_expand_icon_xpath} //project-detail/app-tag-feature-integration/tag-retention//clr-datagrid//clr-dg-row//clr-dg-cell[1]/clr-icon[contains(@shape, 'angle')]
${project_tag_retention_list_expand_icon_xpath} //project-detail/app-tag-feature-integration/tag-retention//clr-datagrid//clr-dg-row//clr-expandable-animation//clr-icon[@class='datagrid-expandable-caret-icon']
${project_tag_retention_run_now_xpath} //*[@id='run-now']
${project_tag_retention_execute_run_xpath} //*[@id='execute-run']
${project_tag_retention_record_no_xpath} //clr-datagrid[contains(.,'No')]