mirror of
https://github.com/goharbor/harbor.git
synced 2025-02-22 14:52:17 +01:00
Refactor tag-retention page (#14749)
Signed-off-by: AllForNothing <sshijun@vmware.com>
This commit is contained in:
parent
c946457eef
commit
af12f9aa01
@ -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,
|
||||
|
@ -155,3 +155,6 @@ export class RuleMetadate {
|
||||
}
|
||||
}
|
||||
|
||||
export const RUNNING: string = "Running";
|
||||
export const PENDING: string = "pending";
|
||||
export const TIMEOUT: number = 5000;
|
||||
|
@ -0,0 +1,6 @@
|
||||
.hand {
|
||||
cursor: pointer;
|
||||
}
|
||||
.color-79b {
|
||||
color: #0079b8;
|
||||
}
|
@ -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>
|
@ -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');
|
||||
});
|
||||
}));
|
||||
});
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
@ -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">
|
||||
|
@ -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');
|
||||
});
|
||||
}));
|
||||
});
|
||||
|
@ -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 => {
|
||||
|
@ -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')]
|
||||
|
Loading…
Reference in New Issue
Block a user