diff --git a/src/portal/src/app/base/left-side-nav/gc-page/gc.module.ts b/src/portal/src/app/base/left-side-nav/gc-page/gc.module.ts index 447fbadf87..c84aafb79b 100644 --- a/src/portal/src/app/base/left-side-nav/gc-page/gc.module.ts +++ b/src/portal/src/app/base/left-side-nav/gc-page/gc.module.ts @@ -3,10 +3,7 @@ import { RouterModule, Routes } from "@angular/router"; import { GcPageComponent } from "./gc-page.component"; import { GcComponent } from "./gc/gc.component"; import { GcHistoryComponent } from "./gc/gc-history/gc-history.component"; -import { GcRepoService } from "./gc/gc.service"; import { SharedModule } from "../../../shared/shared.module"; -import { GcApiDefaultRepository, GcApiRepository } from "./gc/gc.api.repository"; -import { GcViewModelFactory } from "./gc/gc.viewmodel.factory"; const routes: Routes = [ { @@ -24,10 +21,5 @@ const routes: Routes = [ GcComponent, GcHistoryComponent ], - providers: [ - GcRepoService, - {provide: GcApiRepository, useClass: GcApiDefaultRepository }, - GcViewModelFactory - ] }) export class GcModule {} diff --git a/src/portal/src/app/base/left-side-nav/gc-page/gc/gc-history/gc-history.component.html b/src/portal/src/app/base/left-side-nav/gc-page/gc/gc-history/gc-history.component.html index 42a7c9ee93..da631bb4be 100644 --- a/src/portal/src/app/base/left-side-nav/gc-page/gc/gc-history/gc-history.component.html +++ b/src/portal/src/app/base/left-side-nav/gc-page/gc/gc-history/gc-history.component.html @@ -1,30 +1,35 @@
{{'GC.JOB_HISTORY' | translate}}
- + - - {{'GC.JOB_ID' | translate}} - {{'GC.TRIGGER_TYPE' | translate}} - {{'TAG_RETENTION.DRY_RUN' | translate}} - {{'STATUS' | translate}} - {{'CREATION_TIME' | translate}} - {{'UPDATE_TIME' | translate}} - {{'LOGS' | translate}} - - {{job.id }} - {{(job.type ? 'SCHEDULE.'+ job.type.toUpperCase() : '') | translate }} - {{isDryRun(job?.parameters) | translate}} - {{job.status.toUpperCase() | translate}} - {{job.createTime | harborDatetime:'medium'}} - {{job.updateTime | harborDatetime:'medium'}} - - - - - - - {{"PAGINATION.PAGE_SIZE" | translate}} - {{'GC.LATEST_JOBS' | translate :{param: jobs.length} }} - - + + {{'GC.JOB_ID' | translate}} + {{'GC.TRIGGER_TYPE' | translate}} + {{'TAG_RETENTION.DRY_RUN' | translate}} + {{'STATUS' | translate}} + {{'CREATION_TIME' | translate}} + {{'UPDATE_TIME' | translate}} + {{'LOGS' | translate}} + + {{job.id }} + {{(job.schedule?.type ? 'SCHEDULE.' + job.schedule?.type.toUpperCase() : '') | translate }} + {{isDryRun(job?.job_parameters) | translate}} + {{job.job_status.toUpperCase() | translate}} + {{job.creation_time | harborDatetime:'medium'}} + {{job.update_time | harborDatetime:'medium'}} + + + + + + + + + {{"PAGINATION.PAGE_SIZE" | translate}} + {{pagination.firstItem + 1}} + - {{pagination.lastItem + 1}} {{'DESTINATION.OF' | translate}} + {{total}} {{'DESTINATION.ITEMS' | translate}} + + diff --git a/src/portal/src/app/base/left-side-nav/gc-page/gc/gc-history/gc-history.component.spec.ts b/src/portal/src/app/base/left-side-nav/gc-page/gc/gc-history/gc-history.component.spec.ts index 565a2c225a..560e0c79bb 100644 --- a/src/portal/src/app/base/left-side-nav/gc-page/gc/gc-history/gc-history.component.spec.ts +++ b/src/portal/src/app/base/left-side-nav/gc-page/gc/gc-history/gc-history.component.spec.ts @@ -1,100 +1,99 @@ import { - ComponentFixture, - ComponentFixtureAutoDetect, - TestBed, - waitForAsync + ComponentFixture, + ComponentFixtureAutoDetect, fakeAsync, + TestBed, tick, } from '@angular/core/testing'; -import { GcRepoService } from "../gc.service"; import { of } from 'rxjs'; -import { GcViewModelFactory } from "../gc.viewmodel.factory"; -import { TranslateModule, TranslateService } from '@ngx-translate/core'; -import { ErrorHandler } from '../../../../../shared/units/error-handler'; import { GcHistoryComponent } from './gc-history.component'; -import { GcJobData } from "../gcLog"; import { SharedTestingModule } from "../../../../../shared/shared.module"; +import { GCHistory } from "../../../../../../../ng-swagger-gen/models/gchistory"; +import { HttpHeaders, HttpResponse } from "@angular/common/http"; +import { Registry } from "../../../../../../../ng-swagger-gen/models/registry"; +import { GcService } from "../../../../../../../ng-swagger-gen/services/gc.service"; +import { CURRENT_BASE_HREF } from "../../../../../shared/units/utils"; +import { delay } from "rxjs/operators"; describe('GcHistoryComponent', () => { - let component: GcHistoryComponent; - let fixture: ComponentFixture; - const mockJobs: GcJobData[] = [ - { - id: 1, - job_name: 'test', - job_kind: 'manual', - schedule: null, - job_status: 'pending', - job_parameters: '{"dry_run":true}', - job_uuid: 'abc', - creation_time: null, - update_time: null, - delete: false - }, - { - id: 2, - job_name: 'test', - job_kind: 'manual', - schedule: null, - job_status: 'finished', - job_parameters: '{"dry_run":true}', - job_uuid: 'bcd', - creation_time: null, - update_time: null, - delete: false - } - ]; - let fakeGcRepoService = { - count: 0, - getJobs() { - if (this.count === 0) { - this.count += 1; - return of([mockJobs[0]]); - } else { - this.count += 1; - return of([mockJobs[1]]); - } - }, - getLogLink() { - return null; - } - }; - const fakeGcViewModelFactory = new GcViewModelFactory(); - beforeEach(() => { - TestBed.configureTestingModule({ - declarations: [GcHistoryComponent], - imports: [ - SharedTestingModule, - TranslateModule.forRoot() - ], - providers: [ - ErrorHandler, - TranslateService, - GcViewModelFactory, - { provide: GcRepoService, useValue: fakeGcRepoService }, - { provide: GcViewModelFactory, useValue: fakeGcViewModelFactory }, - // open auto detect - { provide: ComponentFixtureAutoDetect, useValue: true } - ] + let component: GcHistoryComponent; + let fixture: ComponentFixture; + const mockJobs: GCHistory[] = [ + { + id: 1, + job_name: 'test', + job_kind: 'manual', + schedule: null, + job_status: 'pending', + job_parameters: '{"dry_run":true}', + creation_time: null, + update_time: null, + }, + { + id: 2, + job_name: 'test', + job_kind: 'manual', + schedule: null, + job_status: 'finished', + job_parameters: '{"dry_run":true}', + creation_time: null, + update_time: null, + } + ]; + const fakedGcService = { + count: 0, + getGCHistoryResponse() { + if (this.count === 0) { + this.count += 1; + const response: HttpResponse> = new HttpResponse>({ + headers: new HttpHeaders({'x-total-count': [mockJobs[0]].length.toString()}), + body: [mockJobs[0]] }); + return of(response).pipe(delay(0)); + } else { + this.count += 1; + const response: HttpResponse> = new HttpResponse>({ + headers: new HttpHeaders({'x-total-count': [mockJobs[1]].length.toString()}), + body: [mockJobs[1]] + }); + return of(response).pipe(delay(0)); + } + } + }; + beforeEach(() => { + TestBed.configureTestingModule({ + declarations: [GcHistoryComponent], + imports: [ + SharedTestingModule, + ], + providers: [ + {provide: GcService, useValue: fakedGcService}, + // open auto detect + {provide: ComponentFixtureAutoDetect, useValue: true} + ] }); + }); - beforeEach(() => { - fixture = TestBed.createComponent(GcHistoryComponent); - component = fixture.componentInstance; - fixture.detectChanges(); + beforeEach(() => { + fixture = TestBed.createComponent(GcHistoryComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + afterEach(() => { + if (component && component.timerDelay) { + component.timerDelay.unsubscribe(); + component.timerDelay = null; + } + }); + it('should create', () => { + expect(component).toBeTruthy(); + }); + it('should retry getting jobs', fakeAsync(() => { + tick(10000); + fixture.detectChanges(); + fixture.whenStable().then(() => { + expect(component.jobs[0].job_status).toEqual('finished'); }); - afterEach(() => { - if (component && component.timerDelay) { - component.timerDelay.unsubscribe(); - component.timerDelay = null; - } - }); - it('should create', () => { - expect(component).toBeTruthy(); - }); - it('should retry getting jobs', waitForAsync(() => { - fixture.detectChanges(); - fixture.whenStable().then(() => { - expect(component.jobs[1].status).toEqual('finished'); - }); - })); + })); + it('should return right log link', () => { + expect(component.getLogLink('1')).toEqual(`${CURRENT_BASE_HREF}/system/gc/1/log`); + }); }); diff --git a/src/portal/src/app/base/left-side-nav/gc-page/gc/gc-history/gc-history.component.ts b/src/portal/src/app/base/left-side-nav/gc-page/gc/gc-history/gc-history.component.ts index 1bc51754f5..5c5fb9d407 100644 --- a/src/portal/src/app/base/left-side-nav/gc-page/gc/gc-history/gc-history.component.ts +++ b/src/portal/src/app/base/left-side-nav/gc-page/gc/gc-history/gc-history.component.ts @@ -1,64 +1,103 @@ import { Component, OnInit, OnDestroy } from '@angular/core'; -import { GcRepoService } from "../gc.service"; -import { GcJobViewModel } from "../gcLog"; -import { GcViewModelFactory } from "../gc.viewmodel.factory"; import { ErrorHandler } from "../../../../../shared/units/error-handler"; import { Subscription, timer } from "rxjs"; import { REFRESH_TIME_DIFFERENCE } from '../../../../../shared/entities/shared.const'; +import { GcService } from "../../../../../../../ng-swagger-gen/services/gc.service"; +import { CURRENT_BASE_HREF, DEFAULT_PAGE_SIZE, getSortingString } from "../../../../../shared/units/utils"; +import { ClrDatagridStateInterface } from "@clr/angular"; +import { finalize } from "rxjs/operators"; +import { GCHistory } from "../../../../../../../ng-swagger-gen/models/gchistory"; + const JOB_STATUS = { PENDING: "pending", RUNNING: "running" }; const YES: string = 'TAG_RETENTION.YES'; const NO: string = 'TAG_RETENTION.NO'; + @Component({ selector: 'gc-history', templateUrl: './gc-history.component.html', styleUrls: ['./gc-history.component.scss'] }) export class GcHistoryComponent implements OnInit, OnDestroy { - jobs: Array = []; - loading: boolean; + jobs: Array = []; + loading: boolean = true; timerDelay: Subscription; + pageSize: number = DEFAULT_PAGE_SIZE; + page: number = 1; + total: number = 0; + state: ClrDatagridStateInterface; constructor( - private gcRepoService: GcRepoService, - private gcViewModelFactory: GcViewModelFactory, + private gcService: GcService, private errorHandler: ErrorHandler - ) {} + ) { + } ngOnInit() { + } + + refresh() { + this.page = 1; + this.total = 0; this.getJobs(); } - getJobs() { + getJobs(state?: ClrDatagridStateInterface) { + if (state) { + this.state = state; + } + if (state && state.page) { + this.pageSize = state.page.size; + } + let q: string; + if (state && state.filters && state.filters.length) { + q = encodeURIComponent(`${state.filters[0].property}=~${state.filters[0].value}`); + } + let sort: string; + if (state && state.sort && state.sort.by) { + sort = getSortingString(state); + } this.loading = true; - this.gcRepoService.getJobs().subscribe(jobs => { - this.jobs = this.gcViewModelFactory.createJobViewModel(jobs); - this.loading = false; - // to avoid some jobs not finished. - if (!this.timerDelay) { - this.timerDelay = timer(REFRESH_TIME_DIFFERENCE, REFRESH_TIME_DIFFERENCE).subscribe(() => { - let count: number = 0; - this.jobs.forEach(job => { - if ( - job['status'] === JOB_STATUS.PENDING || - job['status'] === JOB_STATUS.RUNNING - ) { - count++; + this.gcService.getGCHistoryResponse({ + page: this.page, + pageSize: this.pageSize, + q: q, + sort: sort + }).pipe(finalize(() => this.loading = false)) + .subscribe(res => { + // Get total count + if (res.headers) { + const xHeader: string = res.headers.get("X-Total-Count"); + if (xHeader) { + this.total = parseInt(xHeader, 0); + } + this.jobs = res.body; + } + // to avoid some jobs not finished. + if (!this.timerDelay) { + this.timerDelay = timer(REFRESH_TIME_DIFFERENCE, REFRESH_TIME_DIFFERENCE).subscribe(() => { + let count: number = 0; + this.jobs.forEach(job => { + if ( + job.job_status === JOB_STATUS.PENDING || + job.job_status === JOB_STATUS.RUNNING + ) { + count++; + } + }); + if (count > 0) { + this.getJobs(this.state); + } else { + this.timerDelay.unsubscribe(); + this.timerDelay = null; } }); - if (count > 0) { - this.getJobs(); - } else { - this.timerDelay.unsubscribe(); - this.timerDelay = null; - } - }); - } - }, error => { + } + }, error => { this.errorHandler.error(error); this.loading = false; - }); + }); } isDryRun(param: string): string { @@ -78,7 +117,7 @@ export class GcHistoryComponent implements OnInit, OnDestroy { } getLogLink(id): string { - return this.gcRepoService.getLogLink(id); + return `${CURRENT_BASE_HREF}/system/gc/${id}/log`; } } diff --git a/src/portal/src/app/base/left-side-nav/gc-page/gc/gc.api.repository.ts b/src/portal/src/app/base/left-side-nav/gc-page/gc/gc.api.repository.ts deleted file mode 100644 index f5c8699dfc..0000000000 --- a/src/portal/src/app/base/left-side-nav/gc-page/gc/gc.api.repository.ts +++ /dev/null @@ -1,65 +0,0 @@ -import { Injectable } from '@angular/core'; -import { HttpClient } from '@angular/common/http'; -import { throwError as observableThrowError, Observable } from 'rxjs'; -import { catchError } from 'rxjs/operators'; -import { CURRENT_BASE_HREF } from "../../../../shared/units/utils"; - -export abstract class GcApiRepository { - abstract postSchedule(param): Observable; - - abstract putSchedule(param): Observable; - - abstract getSchedule(): Observable; - - abstract getLog(id): Observable; - - abstract getStatus(id): Observable; - - abstract getJobs(): Observable; - - abstract getLogLink(id): string; -} - -@Injectable() -export class GcApiDefaultRepository extends GcApiRepository { - constructor( - private http: HttpClient - ) { - super(); - } - - public postSchedule(param): Observable { - return this.http.post(`${CURRENT_BASE_HREF}/system/gc/schedule`, param) - .pipe(catchError(error => observableThrowError(error))); - } - - public putSchedule(param): Observable { - return this.http.put(`${CURRENT_BASE_HREF}/system/gc/schedule`, param) - .pipe(catchError(error => observableThrowError(error))); - } - - public getSchedule(): Observable { - return this.http.get(`${CURRENT_BASE_HREF}/system/gc/schedule`) - .pipe(catchError(error => observableThrowError(error))); - } - - public getLog(id): Observable { - return this.http.get(`${CURRENT_BASE_HREF}/system/gc/${id}/log`) - .pipe(catchError(error => observableThrowError(error))); - } - - public getStatus(id): Observable { - return this.http.get(`${CURRENT_BASE_HREF}/system/gc/${id}`) - .pipe(catchError(error => observableThrowError(error))); - } - - public getJobs(): Observable { - return this.http.get(`${CURRENT_BASE_HREF}/system/gc`) - .pipe(catchError(error => observableThrowError(error))); - } - - public getLogLink(id) { - return `${CURRENT_BASE_HREF}/system/gc/${id}/log`; - } - -} diff --git a/src/portal/src/app/base/left-side-nav/gc-page/gc/gc.component.html b/src/portal/src/app/base/left-side-nav/gc-page/gc/gc.component.html index cca32fb405..39a9c58b79 100644 --- a/src/portal/src/app/base/left-side-nav/gc-page/gc/gc.component.html +++ b/src/portal/src/app/base/left-side-nav/gc-page/gc/gc.component.html @@ -1,6 +1,6 @@
+ [originCron]='originCron' (inputvalue)="saveGcSchedule($event)">
@@ -22,11 +22,11 @@
-
-
diff --git a/src/portal/src/app/base/left-side-nav/gc-page/gc/gc.component.spec.ts b/src/portal/src/app/base/left-side-nav/gc-page/gc/gc.component.spec.ts index 12e112bdaf..56d3451615 100644 --- a/src/portal/src/app/base/left-side-nav/gc-page/gc/gc.component.spec.ts +++ b/src/portal/src/app/base/left-side-nav/gc-page/gc/gc.component.spec.ts @@ -1,35 +1,18 @@ import { waitForAsync, ComponentFixture, TestBed } from '@angular/core/testing'; import { GcComponent } from './gc.component'; -import { GcApiRepository, GcApiDefaultRepository} from './gc.api.repository'; -import { GcRepoService } from './gc.service'; import { ErrorHandler } from '../../../../shared/units/error-handler'; -import { GcViewModelFactory } from './gc.viewmodel.factory'; import { CronScheduleComponent } from '../../../../shared/components/cron-schedule'; import { CronTooltipComponent } from "../../../../shared/components/cron-schedule"; import { of } from 'rxjs'; -import { GcJobData } from './gcLog'; -import { CURRENT_BASE_HREF } from "../../../../shared/units/utils"; import { SharedTestingModule } from "../../../../shared/shared.module"; +import { GcService } from "../../../../../../ng-swagger-gen/services/gc.service"; +import { ScheduleType } from "../../../../shared/entities/shared.const"; describe('GcComponent', () => { let component: GcComponent; let fixture: ComponentFixture; - let gcRepoService: GcRepoService; + let gcRepoService: GcService; let mockSchedule = []; - let mockJobs: GcJobData[] = [ - { - id: 22222, - schedule: null, - job_status: 'string', - job_parameters: '{"dry_run":true}', - creation_time: new Date().toDateString(), - update_time: new Date().toDateString(), - job_name: 'string', - job_kind: 'string', - job_uuid: 'string', - delete: false - } - ]; const fakedErrorHandler = { error(error) { return error; @@ -39,7 +22,6 @@ describe('GcComponent', () => { } }; let spySchedule: jasmine.Spy; - let spyJobs: jasmine.Spy; let spyGcNow: jasmine.Spy; beforeEach(waitForAsync(() => { TestBed.configureTestingModule({ @@ -48,10 +30,7 @@ describe('GcComponent', () => { ], declarations: [ GcComponent, CronScheduleComponent, CronTooltipComponent], providers: [ - { provide: GcApiRepository, useClass: GcApiDefaultRepository }, { provide: ErrorHandler, useValue: fakedErrorHandler }, - GcRepoService, - GcViewModelFactory ] }) .compileComponents(); @@ -61,10 +40,9 @@ describe('GcComponent', () => { fixture = TestBed.createComponent(GcComponent); component = fixture.componentInstance; - gcRepoService = fixture.debugElement.injector.get(GcRepoService); - spySchedule = spyOn(gcRepoService, "getSchedule").and.returnValues(of(mockSchedule)); - spyJobs = spyOn(gcRepoService, "getJobs").and.returnValues(of(mockJobs)); - spyGcNow = spyOn(gcRepoService, "manualGc").and.returnValues(of(true)); + gcRepoService = fixture.debugElement.injector.get(GcService); + spySchedule = spyOn(gcRepoService, "getGCSchedule").and.returnValues(of(mockSchedule)); + spyGcNow = spyOn(gcRepoService, "createGCSchedule").and.returnValues(of(true)); fixture.detectChanges(); }); it('should create', () => { @@ -72,12 +50,25 @@ describe('GcComponent', () => { }); it('should get schedule and job', () => { expect(spySchedule.calls.count()).toEqual(1); - expect(spyJobs.calls.count()).toEqual(1); }); it('should trigger gcNow', () => { - const ele: HTMLButtonElement = fixture.nativeElement.querySelector('.gc-start-btn'); + const ele: HTMLButtonElement = fixture.nativeElement.querySelector('#gc-now'); ele.click(); fixture.detectChanges(); expect(spyGcNow.calls.count()).toEqual(1); }); + it('should trigger dry run', () => { + const ele: HTMLButtonElement = fixture.nativeElement.querySelector('#gc-dry-run'); + ele.click(); + fixture.detectChanges(); + expect(spyGcNow.calls.count()).toEqual(1); + }); + it('getScheduleType function should work', () => { + expect(GcComponent.getScheduleType).toBeTruthy(); + expect(GcComponent.getScheduleType(null)).toEqual(ScheduleType.NONE); + expect(GcComponent.getScheduleType('0 0 0 0 0 0')).toEqual(ScheduleType.CUSTOM); + expect(GcComponent.getScheduleType('0 0 * * * *')).toEqual(ScheduleType.HOURLY); + expect(GcComponent.getScheduleType('0 0 0 * * *')).toEqual(ScheduleType.DAILY); + expect(GcComponent.getScheduleType('0 0 0 * * 0')).toEqual(ScheduleType.WEEKLY); + }); }); diff --git a/src/portal/src/app/base/left-side-nav/gc-page/gc/gc.component.ts b/src/portal/src/app/base/left-side-nav/gc-page/gc/gc.component.ts index 6d17e50338..f8aa046c73 100644 --- a/src/portal/src/app/base/left-side-nav/gc-page/gc/gc.component.ts +++ b/src/portal/src/app/base/left-side-nav/gc-page/gc/gc.component.ts @@ -1,32 +1,26 @@ import { Component, - Input, Output, EventEmitter, ViewChild, OnInit } from "@angular/core"; -import { TranslateService } from "@ngx-translate/core"; -import { GcJobViewModel } from "./gcLog"; -import { GcViewModelFactory } from "./gc.viewmodel.factory"; -import { GcRepoService } from "./gc.service"; -import { - SCHEDULE_TYPE_NONE, - ONE_MINITUE, - THREE_SECONDS, GCSchedule -} from "./gc.const"; import { ErrorHandler } from "../../../../shared/units/error-handler"; -import { CronScheduleComponent } from "../../../../shared/components/cron-schedule/cron-schedule.component"; -import { OriginCron } from '../../../../shared/services/interface'; +import { CronScheduleComponent } from "../../../../shared/components/cron-schedule"; +import { OriginCron } from '../../../../shared/services'; import { finalize } from "rxjs/operators"; +import { GcService } from "../../../../../../ng-swagger-gen/services/gc.service"; +import { GCHistory } from "../../../../../../ng-swagger-gen/models/gchistory"; +import { ScheduleType } from "../../../../shared/entities/shared.const"; + +const ONE_MINUTE = 60000; + @Component({ selector: "gc-config", templateUrl: "./gc.component.html", styleUrls: ["./gc.component.scss"] }) export class GcComponent implements OnInit { - jobs: Array = []; - schedule: GCSchedule = {}; originCron: OriginCron; disableGC: boolean = false; getLabelCurrent = 'GC.CURRENT_SCHEDULE'; @@ -35,67 +29,66 @@ export class GcComponent implements OnInit { CronScheduleComponent: CronScheduleComponent; shouldDeleteUntagged: boolean; dryRunOnGoing: boolean = false; + constructor( - private gcRepoService: GcRepoService, - private gcViewModelFactory: GcViewModelFactory, + private gcService: GcService, private errorHandler: ErrorHandler, - private translate: TranslateService ) { - translate.setDefaultLang("en-us"); } ngOnInit() { this.getCurrentSchedule(); - this.getJobs(); } getCurrentSchedule() { this.loadingGcStatus.emit(true); - this.gcRepoService.getSchedule() - .pipe(finalize(() => { - this.loadingGcStatus.emit(false); - })) - .subscribe(schedule => { - this.initSchedule(schedule); - }, error => { - this.errorHandler.error(error); - }); + this.gcService.getGCSchedule() + .pipe(finalize(() => { + this.loadingGcStatus.emit(false); + })) + .subscribe(schedule => { + this.initSchedule(schedule); + }, error => { + this.errorHandler.error(error); + }); } - public initSchedule(schedule: GCSchedule) { - if (schedule && schedule.schedule !== null) { - this.schedule = schedule; - this.originCron = this.schedule.schedule; + private initSchedule(gcHistory: GCHistory) { + if (gcHistory && gcHistory.schedule) { + this.originCron = { + type: gcHistory.schedule.type, + cron: gcHistory.schedule.cron + }; } else { this.originCron = { - type: SCHEDULE_TYPE_NONE, + type: ScheduleType.NONE, cron: '' }; } - if (schedule && schedule.job_parameters) { - this.shouldDeleteUntagged = JSON.parse(schedule.job_parameters).delete_untagged; + if (gcHistory && gcHistory.job_parameters) { + this.shouldDeleteUntagged = JSON.parse(gcHistory.job_parameters).delete_untagged; } else { this.shouldDeleteUntagged = false; } } - getJobs() { - this.gcRepoService.getJobs().subscribe(jobs => { - this.jobs = this.gcViewModelFactory.createJobViewModel(jobs); - }); - } - gcNow(): void { this.disableGC = true; setTimeout(() => { this.enableGc(); - }, ONE_MINITUE); + }, ONE_MINUTE); - this.gcRepoService.manualGc(this.shouldDeleteUntagged, false).subscribe( + this.gcService.createGCSchedule({ + parameters: { + delete_untagged: this.shouldDeleteUntagged, + dry_run: false + }, + schedule: { + type: ScheduleType.MANUAL + } + }).subscribe( response => { - this.translate.get("GC.MSG_SUCCESS").subscribe((res: string) => { - this.errorHandler.info(res); - }); + this.errorHandler.info("GC.MSG_SUCCESS"); }, error => { this.errorHandler.error(error); @@ -105,62 +98,66 @@ export class GcComponent implements OnInit { dryRun() { this.dryRunOnGoing = true; - this.gcRepoService.manualGc(this.shouldDeleteUntagged, true) + this.gcService.createGCSchedule({ + parameters: { + delete_untagged: this.shouldDeleteUntagged, + dry_run: true + }, + schedule: { + type: ScheduleType.MANUAL + } + }) .pipe(finalize(() => this.dryRunOnGoing = false)) .subscribe( - response => { - this.translate.get("GC.DRY_RUN_SUCCESS").subscribe((res: string) => { - this.errorHandler.info(res); - }); - }, - error => { - this.errorHandler.error(error); - } - ); + response => { + this.errorHandler.info("GC.DRY_RUN_SUCCESS"); + }, + error => { + this.errorHandler.error(error); + } + ); } private enableGc() { this.disableGC = false; } - private resetSchedule(cron) { - this.schedule = { - schedule: { - type: this.CronScheduleComponent.scheduleType, - cron: cron - } - }; - if (!cron) { - this.shouldDeleteUntagged = false; - } - this.getJobs(); - } - - scheduleGc(cron: string) { - let schedule = this.schedule; - if (schedule && schedule.schedule && schedule.schedule.type !== SCHEDULE_TYPE_NONE) { - this.gcRepoService.putScheduleGc(this.shouldDeleteUntagged, this.CronScheduleComponent.scheduleType, cron).subscribe( + saveGcSchedule(cron: string) { + if (this.originCron && this.originCron.type !== ScheduleType.NONE) {// no schedule, then create + this.gcService.createGCSchedule({ + parameters: { + delete_untagged: this.shouldDeleteUntagged, + dry_run: false + }, + schedule: { + type: GcComponent.getScheduleType(cron), + cron: cron + } + }).subscribe( response => { - this.translate - .get("GC.MSG_SCHEDULE_RESET") - .subscribe((res) => { - this.errorHandler.info(res); - this.CronScheduleComponent.resetSchedule(); - }); - this.resetSchedule(cron); + this.errorHandler.info("GC.MSG_SCHEDULE_RESET"); + this.CronScheduleComponent.resetSchedule(); + this.getCurrentSchedule(); // refresh schedule }, error => { this.errorHandler.error(error); } ); } else { - this.gcRepoService.postScheduleGc(this.shouldDeleteUntagged, this.CronScheduleComponent.scheduleType, cron).subscribe( + this.gcService.updateGCSchedule({ + parameters: { + delete_untagged: this.shouldDeleteUntagged, + dry_run: false + }, + schedule: { + type: GcComponent.getScheduleType(cron), + cron: cron + } + }).subscribe( response => { - this.translate.get("GC.MSG_SCHEDULE_SET").subscribe((res) => { - this.errorHandler.info(res); - this.CronScheduleComponent.resetSchedule(); - }); - this.resetSchedule(cron); + this.errorHandler.info("GC.MSG_SCHEDULE_RESET"); + this.CronScheduleComponent.resetSchedule(); + this.getCurrentSchedule(); // refresh schedule }, error => { this.errorHandler.error(error); @@ -168,4 +165,20 @@ export class GcComponent implements OnInit { ); } } + + static getScheduleType(cron: string): 'Hourly' | 'Daily' | 'Weekly' | 'Custom' | 'Manual' | 'None' { + if (cron) { + if (cron === '0 0 * * * *') { + return ScheduleType.HOURLY; + } + if (cron === '0 0 0 * * *') { + return ScheduleType.DAILY; + } + if (cron === '0 0 0 * * 0') { + return ScheduleType.WEEKLY; + } + return ScheduleType.CUSTOM; + } + return ScheduleType.NONE; + } } diff --git a/src/portal/src/app/base/left-side-nav/gc-page/gc/gc.const.ts b/src/portal/src/app/base/left-side-nav/gc-page/gc/gc.const.ts deleted file mode 100644 index d16beb88e5..0000000000 --- a/src/portal/src/app/base/left-side-nav/gc-page/gc/gc.const.ts +++ /dev/null @@ -1,25 +0,0 @@ -import { OriginCron } from "../../../../shared/services"; - - -export const SCHEDULE_TYPE_NONE = "None"; - -export const ONE_MINITUE = 60000; -export const THREE_SECONDS = 3000; - -export interface GCSchedule { - schedule?: OriginCron; - parameters?: {[key: string]: any}; - id?: number; - job_name?: string; - job_kind?: string; - job_parameters?: string; - job_status?: string; - deleted?: boolean; - creation_time?: Date; - update_time?: Date; -} - - - - - diff --git a/src/portal/src/app/base/left-side-nav/gc-page/gc/gc.service.ts b/src/portal/src/app/base/left-side-nav/gc-page/gc/gc.service.ts deleted file mode 100644 index ee5ab69eac..0000000000 --- a/src/portal/src/app/base/left-side-nav/gc-page/gc/gc.service.ts +++ /dev/null @@ -1,72 +0,0 @@ -import { Injectable } from '@angular/core'; -import { Observable, Subscription, Subject, of } from 'rxjs'; -import { catchError, map } from 'rxjs/operators'; -import { GcApiRepository } from './gc.api.repository'; -import { ErrorHandler } from '../../../../shared/units/error-handler'; -import { GcJobData } from './gcLog'; - - -@Injectable() -export class GcRepoService { - - constructor( - private gcApiRepository: GcApiRepository, - ) {} - - public manualGc(shouldDeleteUntagged: boolean, isDryRun: boolean): Observable { - const param = { - "schedule": { - "type": "Manual" - }, - parameters: { - delete_untagged: shouldDeleteUntagged, - dry_run: isDryRun - } - }; - return this.gcApiRepository.postSchedule(param); - } - - public getJobs(): Observable { - return this.gcApiRepository.getJobs(); - } - - public getLog(id): Observable { - return this.gcApiRepository.getLog(id); - } - - public getSchedule(): Observable { - return this.gcApiRepository.getSchedule(); - } - - public postScheduleGc(shouldDeleteUntagged: boolean, type, cron): Observable { - let param = { - "schedule": { - "type": type, - "cron": cron, - }, - parameters: { - delete_untagged: shouldDeleteUntagged - } - }; - - return this.gcApiRepository.postSchedule(param); - } - - public putScheduleGc(shouldDeleteUntagged, type, cron): Observable { - let param = { - "schedule": { - "type": type, - "cron": cron, - }, - parameters: { - delete_untagged: shouldDeleteUntagged - } - }; - - return this.gcApiRepository.putSchedule(param); - } - - public getLogLink(id): string { - return this.gcApiRepository.getLogLink(id); - } -} diff --git a/src/portal/src/app/base/left-side-nav/gc-page/gc/gc.viewmodel.factory.ts b/src/portal/src/app/base/left-side-nav/gc-page/gc/gc.viewmodel.factory.ts deleted file mode 100644 index 0266a7bff2..0000000000 --- a/src/portal/src/app/base/left-side-nav/gc-page/gc/gc.viewmodel.factory.ts +++ /dev/null @@ -1,24 +0,0 @@ -import { Injectable } from '@angular/core'; -import { GcJobData, GcJobViewModel } from './gcLog'; - -@Injectable() -export class GcViewModelFactory { - public createJobViewModel(jobs: GcJobData[]): GcJobViewModel[] { - let gcViewModels: GcJobViewModel[] = []; - for (let job of jobs) { - - let createTime = new Date(job.creation_time); - let updateTime = new Date(job.update_time); - gcViewModels.push({ - id: job.id, - type: job.schedule ? job.schedule.type : null, - status: job.job_status, - parameters: job.job_parameters, - createTime: createTime, - updateTime: updateTime, - details: null - }); - } - return gcViewModels; - } -} diff --git a/src/portal/src/app/base/left-side-nav/gc-page/gc/gcLog.ts b/src/portal/src/app/base/left-side-nav/gc-page/gc/gcLog.ts deleted file mode 100644 index 04f54311db..0000000000 --- a/src/portal/src/app/base/left-side-nav/gc-page/gc/gcLog.ts +++ /dev/null @@ -1,28 +0,0 @@ -export class GcJobData { - id: number; - job_name: string; - job_kind: string; - schedule: Schedule; - job_status: string; - job_parameters: string; - job_uuid: string; - creation_time: string; - update_time: string; - delete: boolean; -} - -export class Schedule { - type: string; - cron: string; -} -export class GcJobViewModel { - id: number; - type: string; - status: string; - parameters: string; - createTime: Date; - updateTime: Date; - details: string; -} - - diff --git a/src/portal/src/app/shared/entities/shared.const.ts b/src/portal/src/app/shared/entities/shared.const.ts index b2f7e153e1..f7e6ffdaee 100644 --- a/src/portal/src/app/shared/entities/shared.const.ts +++ b/src/portal/src/app/shared/entities/shared.const.ts @@ -242,3 +242,12 @@ export enum ResourceType { } export const CARD_VIEW_LOCALSTORAGE_KEY = 'card-view'; + +export enum ScheduleType { + NONE = "None", + DAILY = "Daily", + WEEKLY = "Weekly", + HOURLY = "Hourly", + CUSTOM = "Custom", + MANUAL = 'Manual' +} diff --git a/src/portal/src/app/shared/units/error-handler/error-handler.ts b/src/portal/src/app/shared/units/error-handler/error-handler.ts index 51b63470b4..86543c87be 100644 --- a/src/portal/src/app/shared/units/error-handler/error-handler.ts +++ b/src/portal/src/app/shared/units/error-handler/error-handler.ts @@ -47,4 +47,4 @@ export abstract class ErrorHandler { abstract log(log: any): void; abstract handleErrorPopupUnauthorized(error: any): void; -} \ No newline at end of file +}