From 041a489fadbfabd40d4b216e6b5b79ff1ee463af Mon Sep 17 00:00:00 2001 From: AllForNothing Date: Thu, 6 Aug 2020 16:46:51 +0800 Subject: [PATCH] Add name and endpoint check for p2p-preheat Signed-off-by: AllForNothing --- .../distribution-instances.component.scss | 1 + .../distribution-setup-modal.component.html | 91 +++++++------- ...distribution-setup-modal.component.spec.ts | 9 +- .../distribution-setup-modal.component.ts | 97 ++++++++++++++- .../add-p2p-policy.component.html | 14 ++- .../add-p2p-policy.component.spec.ts | 5 +- .../add-p2p-policy.component.ts | 56 ++++++++- .../p2p-provider/policy/policy.component.html | 11 +- .../p2p-provider/policy/policy.component.scss | 2 +- .../p2p-provider/policy/policy.component.ts | 56 ++++++--- .../task-list/task-list.component.html | 40 ++++--- .../task-list/task-list.component.scss | 14 ++- .../task-list/task-list.component.spec.ts | 10 +- .../task-list/task-list.component.ts | 113 +++++++++++++++--- src/portal/src/i18n/lang/zh-cn-lang.json | 8 +- 15 files changed, 403 insertions(+), 124 deletions(-) diff --git a/src/portal/src/app/distribution/distribution-instances/distribution-instances.component.scss b/src/portal/src/app/distribution/distribution-instances/distribution-instances.component.scss index 775bcbfda8..63b7653489 100644 --- a/src/portal/src/app/distribution/distribution-instances/distribution-instances.component.scss +++ b/src/portal/src/app/distribution/distribution-instances/distribution-instances.component.scss @@ -16,6 +16,7 @@ $refrsh-btn-color: #007CBB; } .action-head-pos { + padding-top: 12px; padding-right: 18px; height: 24px; display: flex; diff --git a/src/portal/src/app/distribution/distribution-setup-modal/distribution-setup-modal.component.html b/src/portal/src/app/distribution/distribution-setup-modal/distribution-setup-modal.component.html index ebb6c9722a..cd7df4b3ca 100644 --- a/src/portal/src/app/distribution/distribution-setup-modal/distribution-setup-modal.component.html +++ b/src/portal/src/app/distribution/distribution-setup-modal/distribution-setup-modal.component.html @@ -33,24 +33,30 @@ - - - - - {{ 'TOOLTIP.ITEM_REQUIRED' | translate }} - - +
+ +
+
+ + + +
+ + {{'SCANNER.NAME_EXISTS' | translate}} + {{ 'TOOLTIP.ITEM_REQUIRED' | translate }} + +
+
@@ -65,27 +71,32 @@ [ngModelOptions]="{ standalone: true }" > - - - - - {{ - 'TOOLTIP.ENDPOINT_FORMAT' | translate - }} - +
+ +
+
+ + + +
+ + {{'SCANNER.ENDPOINT_EXISTS' | translate}} + {{ 'TOOLTIP.ENDPOINT_FORMAT' | translate }} + +
+
@@ -232,7 +243,7 @@ diff --git a/src/portal/src/app/project/p2p-provider/add-p2p-policy/add-p2p-policy.component.spec.ts b/src/portal/src/app/project/p2p-provider/add-p2p-policy/add-p2p-policy.component.spec.ts index d4b8f5b41e..b6d0d2cd9b 100644 --- a/src/portal/src/app/project/p2p-provider/add-p2p-policy/add-p2p-policy.component.spec.ts +++ b/src/portal/src/app/project/p2p-provider/add-p2p-policy/add-p2p-policy.component.spec.ts @@ -33,6 +33,9 @@ describe('AddP2pPolicyComponent', () => { }, UpdatePolicy() { return of(true).pipe(delay(0)); + }, + ListPolicies() { + return of([]).pipe(delay(0)); } }; const mockActivatedRoute = { @@ -135,7 +138,7 @@ describe('AddP2pPolicyComponent', () => { nameInput.dispatchEvent(new Event('input')); nameInput.blur(); const errorEle: HTMLElement = fixture.nativeElement.querySelector("clr-control-error"); - expect(errorEle.innerText).toEqual('P2P_PROVIDER.NAME_REQUIRED'); + expect(errorEle.innerText).toEqual('PROJECT.NAME_TOOLTIP'); }); it("save button should work", async () => { fixture.autoDetectChanges(true); diff --git a/src/portal/src/app/project/p2p-provider/add-p2p-policy/add-p2p-policy.component.ts b/src/portal/src/app/project/p2p-provider/add-p2p-policy/add-p2p-policy.component.ts index 120445cbf9..fdc1da6f5c 100644 --- a/src/portal/src/app/project/p2p-provider/add-p2p-policy/add-p2p-policy.component.ts +++ b/src/portal/src/app/project/p2p-provider/add-p2p-policy/add-p2p-policy.component.ts @@ -1,11 +1,11 @@ -import { Component, EventEmitter, Input, OnInit, Output, ViewChild, } from '@angular/core'; +import { Component, EventEmitter, Input, OnDestroy, OnInit, Output, ViewChild, } from '@angular/core'; import { PreheatPolicy } from '../../../../../ng-swagger-gen/models/preheat-policy'; import { InlineAlertComponent } from '../../../shared/inline-alert/inline-alert.component'; import { NgForm } from '@angular/forms'; import { OriginCron, ProjectService } from '../../../../lib/services'; import { CronScheduleComponent } from '../../../../lib/components/cron-schedule'; import { PreheatService } from '../../../../../ng-swagger-gen/services/preheat.service'; -import { finalize } from 'rxjs/operators'; +import { debounceTime, distinctUntilChanged, filter, finalize, switchMap } from 'rxjs/operators'; import { deleteEmptyKey } from '../../../../lib/utils/utils'; import { ClrLoadingState } from '@clr/angular'; import { SessionService } from '../../../shared/session.service'; @@ -14,6 +14,7 @@ import { ActivatedRoute } from '@angular/router'; import { FILTER_TYPE, PROJECT_SEVERITY_LEVEL_MAP, TRIGGER, TRIGGER_I18N_MAP } from '../p2p-provider.service'; import { ProviderUnderProject } from '../../../../../ng-swagger-gen/models/provider-under-project'; import { AppConfigService } from '../../../services/app-config.service'; +import { Subject, Subscription } from 'rxjs'; const SCHEDULE_TYPE = { NONE: "None", @@ -28,7 +29,7 @@ const TRUE: string = 'true'; templateUrl: './add-p2p-policy.component.html', styleUrls: ['./add-p2p-policy.component.scss'] }) -export class AddP2pPolicyComponent implements OnInit { +export class AddP2pPolicyComponent implements OnInit, OnDestroy { severityOptions = [ {severity: 5, severityLevel: 'VULNERABILITY.SEVERITY.CRITICAL'}, {severity: 4, severityLevel: 'VULNERABILITY.SEVERITY.HIGH'}, @@ -73,7 +74,10 @@ export class AddP2pPolicyComponent implements OnInit { projectSeverity: string; triggers: string[] = [TRIGGER.MANUAL, TRIGGER.SCHEDULED, TRIGGER.EVENT_BASED]; enableContentTrust: boolean = false; - + private _nameSubject: Subject = new Subject(); + private _nameSubscription: Subscription; + isNameExisting: boolean = false; + checkNameOnGoing: boolean = false; constructor(private preheatService: PreheatService, private session: SessionService, private route: ActivatedRoute, @@ -90,6 +94,43 @@ export class AddP2pPolicyComponent implements OnInit { // get latest project info this.getProject(); } + this.subscribeName(); + } + ngOnDestroy() { + if (this._nameSubscription) { + this._nameSubscription.unsubscribe(); + this._nameSubscription = null; + } + } + subscribeName() { + if (!this._nameSubscription) { + this._nameSubscription = this._nameSubject + .pipe( + debounceTime(500), + distinctUntilChanged(), + filter(name => { + if (this.isEdit && this.originPolicyForEdit && this.originPolicyForEdit.name === name) { + return false; + } + return name.length > 0; + }), + switchMap((name) => { + this.isNameExisting = false; + this.checkNameOnGoing = true; + return this.preheatService.ListPolicies({ + projectName: this.projectName, + q: encodeURIComponent(`name=${name}`) + }).pipe(finalize(() => this.checkNameOnGoing = false)); + })) + .subscribe(res => { + if (res && res.length > 0) { + this.isNameExisting = true; + } + }); + } + } + inputName() { + this._nameSubject.next(this.policy.name); } getProject() { this.projectService.getProject(this.projectId) @@ -115,6 +156,13 @@ export class AddP2pPolicyComponent implements OnInit { severity: PROJECT_SEVERITY_LEVEL_MAP[this.projectSeverity], onlySignedImages: this.enableContentTrust }); + if (this.providers && this.providers.length) { + this.providers.forEach(item => { + if (item.default) { + this.policy.provider_id = item.id; + } + }); + } } setCron(event: any) { diff --git a/src/portal/src/app/project/p2p-provider/policy/policy.component.html b/src/portal/src/app/project/p2p-provider/policy/policy.component.html index bf80b017ec..8a42d3fbcc 100644 --- a/src/portal/src/app/project/p2p-provider/policy/policy.component.html +++ b/src/portal/src/app/project/p2p-provider/policy/policy.component.html @@ -77,7 +77,7 @@ {{'P2P_PROVIDER.NAME' | translate}} {{'P2P_PROVIDER.ENABLED' | translate}} - {{'P2P_PROVIDER.PROVIDER' | translate}} + {{'P2P_PROVIDER.PROVIDER' | translate}} {{'P2P_PROVIDER.FILTERS' | translate}} {{'P2P_PROVIDER.TRIGGER' | translate}} {{'P2P_PROVIDER.CREATED' | translate}} @@ -164,20 +164,19 @@ - + {{'REPLICATION.ID' | translate}} {{'REPLICATION.STATUS' | translate}} - {{'REPLICATION.REPLICATION_TRIGGER' | translate}} + {{'P2P_PROVIDER.TRIGGER' | translate}} {{'REPLICATION.CREATION_TIME' | translate}} {{'REPLICATION.DURATION' | translate}} {{'REPLICATION.SUCCESS_RATE' | translate}} @@ -196,7 +195,7 @@ - {{execution.trigger}} + {{getTriggerTypeI18nForExecution(execution.trigger) | translate}} {{execution.start_time | date: 'short'}} {{getDuration(execution)}} {{getSuccessRate(execution.metrics)}} @@ -206,7 +205,7 @@ {{pagination.firstItem + 1}} - {{pagination.lastItem + 1}} {{'REPLICATION.OF' | translate}} {{totalExecutionCount}} {{'REPLICATION.ITEMS' | translate}} - diff --git a/src/portal/src/app/project/p2p-provider/policy/policy.component.scss b/src/portal/src/app/project/p2p-provider/policy/policy.component.scss index 178e1d39c3..b93c6c41c4 100644 --- a/src/portal/src/app/project/p2p-provider/policy/policy.component.scss +++ b/src/portal/src/app/project/p2p-provider/policy/policy.component.scss @@ -33,7 +33,7 @@ cursor: pointer; } .filter-tag { - margin-top: 6px; + margin-top: 7px; } .filter-title { font-weight: 400; diff --git a/src/portal/src/app/project/p2p-provider/policy/policy.component.ts b/src/portal/src/app/project/p2p-provider/policy/policy.component.ts index d10ab70b9d..1245c173be 100644 --- a/src/portal/src/app/project/p2p-provider/policy/policy.component.ts +++ b/src/portal/src/app/project/p2p-provider/policy/policy.component.ts @@ -11,7 +11,7 @@ // 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 { distinctUntilChanged, finalize, switchMap } from 'rxjs/operators'; +import { debounceTime, distinctUntilChanged, finalize, switchMap } from 'rxjs/operators'; import { TranslateService } from '@ngx-translate/core'; import { Component, OnDestroy, OnInit, ViewChild } from '@angular/core'; import { ActivatedRoute, Router } from '@angular/router'; @@ -106,10 +106,7 @@ export class PolicyComponent implements OnInit, OnDestroy { this._searchSubscription.unsubscribe(); this._searchSubscription = null; } - if (this.timeout) { - clearTimeout(this.timeout); - this.timeout = null; - } + this.clearLoop(); } getPermissions() { const permissionsList: Observable[] = []; @@ -134,7 +131,11 @@ export class PolicyComponent implements OnInit, OnDestroy { getProviders() { this.preheatService.ListProvidersUnderProject({projectName: this.projectName}) .subscribe(res => { - this.providers = res; + if (res && res.length) { + this.providers = res.filter(provider => { + return provider.enabled; + }); + } }); } refresh() { @@ -358,23 +359,13 @@ export class PolicyComponent implements OnInit, OnDestroy { }).pipe(finalize(() => this.jobsLoading = false)) .subscribe(response => { if (response.headers) { - let xHeader: string = response.headers.get('x-total-count'); + let xHeader: string = response.headers.get('X-Total-Count'); if (xHeader) { this.totalExecutionCount = parseInt(xHeader, 0); } } this.executionList = response.body; - if (this.executionList && this.executionList.length) { - for (let i = 0; i < this.executionList.length; i++) { - if (this.p2pProviderService.willChangStatus(this.executionList[i].status)) { - if (!this.timeout) { - this.timeout = setTimeout(() => { - this.clrLoadJobs(null, false); - }, TIME_OUT); - } - } - } - } + this.setLoop(); }, error => { this.messageHandlerService.handleError(error); }); @@ -412,6 +403,12 @@ export class PolicyComponent implements OnInit, OnDestroy { } return TRIGGER_I18N_MAP[TRIGGER.MANUAL]; } + getTriggerTypeI18nForExecution(trigger: string) { + if (trigger && TRIGGER_I18N_MAP[trigger]) { + return TRIGGER_I18N_MAP[trigger]; + } + return trigger; + } isScheduled(trigger: string): boolean { return JSON.parse(trigger).type === TRIGGER.SCHEDULED; } @@ -459,7 +456,7 @@ export class PolicyComponent implements OnInit, OnDestroy { subscribeSearch() { if (!this._searchSubscription) { this._searchSubscription = this._searchSubject.pipe( - distinctUntilChanged(), + debounceTime(500), switchMap(searchString => { this.jobsLoading = true; let params: string; @@ -481,10 +478,31 @@ export class PolicyComponent implements OnInit, OnDestroy { } } this.executionList = response.body; + this.setLoop(); }); } } canStop(): boolean { return this.selectedExecutionRow && this.p2pProviderService.willChangStatus(this.selectedExecutionRow.status); } + clearLoop() { + if (this.timeout) { + clearTimeout(this.timeout); + this.timeout = null; + } + } + setLoop() { + this.clearLoop(); + if (this.executionList && this.executionList.length) { + for (let i = 0; i < this.executionList.length; i++) { + if (this.p2pProviderService.willChangStatus(this.executionList[i].status)) { + if (!this.timeout) { + this.timeout = setTimeout(() => { + this.clrLoadJobs(null, false); + }, TIME_OUT); + } + } + } + } + } } diff --git a/src/portal/src/app/project/p2p-provider/task-list/task-list.component.html b/src/portal/src/app/project/p2p-provider/task-list/task-list.component.html index 020e9c364d..cd7176a457 100644 --- a/src/portal/src/app/project/p2p-provider/task-list/task-list.component.html +++ b/src/portal/src/app/project/p2p-provider/task-list/task-list.component.html @@ -76,25 +76,34 @@
-
-
- - - -
-
- {{'REPLICATION.TASK_ID'| translate}} - {{'P2P_PROVIDER.ID' | translate}} - {{'REPLICATION.STATUS' | translate}} + +
+
+ +
+ + + + +
+
+ {{'REPLICATION.TASK_ID'| translate}} + {{'P2P_PROVIDER.ID' | translate}} + {{'REPLICATION.STATUS' | translate}} {{'P2P_PROVIDER.ARTIFACT' | translate}} {{'P2P_PROVIDER.DIGEST' | translate}} {{'P2P_PROVIDER.TYPE' | translate}} - {{'REPLICATION.CREATION_TIME' | translate}} + {{'REPLICATION.CREATION_TIME' | translate}} {{'REPLICATION.DURATION' | translate}} {{'REPLICATION.LOGS' | translate}} {{'P2P_PROVIDER.TASKS_PLACEHOLDER' | translate }} - + {{t.id}} {{t.execution_id}} {{t.status}} @@ -124,8 +133,11 @@ - {{pagination.firstItem + 1}} - {{pagination.lastItem +1 }} {{'REPLICATION.OF' | translate}} {{totalCount }} {{'REPLICATION.ITEMS' | translate}} - + {{pagination.firstItem + 1}} + - {{pagination.lastItem + 1}} {{'REPLICATION.OF' | translate}} + {{totalCount}} {{'REPLICATION.ITEMS' | translate}} +
diff --git a/src/portal/src/app/project/p2p-provider/task-list/task-list.component.scss b/src/portal/src/app/project/p2p-provider/task-list/task-list.component.scss index f4cef3a6c6..705a94789e 100644 --- a/src/portal/src/app/project/p2p-provider/task-list/task-list.component.scss +++ b/src/portal/src/app/project/p2p-provider/task-list/task-list.component.scss @@ -103,7 +103,6 @@ } } clr-datagrid { - margin-top: 20px; .resource-width { width: 150px; } @@ -113,3 +112,16 @@ .margin-top-075 { margin-top: 0.75rem; } +.flex-end { + align-items: center; + display: flex; + justify-content: flex-end; + padding-right: 1.5rem; +} +.refresh-btn { + margin-top: 6px; + cursor: pointer; +} +.filter-tag { + margin-top: 7px; +} diff --git a/src/portal/src/app/project/p2p-provider/task-list/task-list.component.spec.ts b/src/portal/src/app/project/p2p-provider/task-list/task-list.component.spec.ts index 35e80a789d..fd95862b39 100644 --- a/src/portal/src/app/project/p2p-provider/task-list/task-list.component.spec.ts +++ b/src/portal/src/app/project/p2p-provider/task-list/task-list.component.spec.ts @@ -17,6 +17,7 @@ import { TaskListComponent } from './task-list.component'; import { MessageHandlerService } from '../../../shared/message-handler/message-handler.service'; import { UserPermissionService } from '../../../../lib/services'; import { Task } from '../../../../../ng-swagger-gen/models/task'; +import { HttpHeaders, HttpResponse } from '@angular/common/http'; describe('TaskListComponent', () => { let component: TaskListComponent; let fixture: ComponentFixture; @@ -38,8 +39,13 @@ describe('TaskListComponent', () => { GetExecution() { return of(execution).pipe(delay(0)); }, - ListTasks() { - return of([task]).pipe(delay(0)); + ListTasksResponse() { + return of(new HttpResponse({ + body: [task], + headers: new HttpHeaders({ + "X-Total-Count": "1" + }) + })).pipe(delay(0)); } }; const mockActivatedRoute = { diff --git a/src/portal/src/app/project/p2p-provider/task-list/task-list.component.ts b/src/portal/src/app/project/p2p-provider/task-list/task-list.component.ts index 36cfbcce79..1645ab17fb 100644 --- a/src/portal/src/app/project/p2p-provider/task-list/task-list.component.ts +++ b/src/portal/src/app/project/p2p-provider/task-list/task-list.component.ts @@ -1,16 +1,16 @@ import { Component, OnDestroy, OnInit } from '@angular/core'; import { ActivatedRoute, Router } from '@angular/router'; import { TranslateService } from '@ngx-translate/core'; -import { finalize } from 'rxjs/operators'; -import { clone, CustomComparator, DEFAULT_PAGE_SIZE, isEmptyObject } from '../../../../lib/utils/utils'; +import { debounceTime, finalize, switchMap } from 'rxjs/operators'; +import { clone, DEFAULT_PAGE_SIZE } from '../../../../lib/utils/utils'; import { Task } from '../../../../../ng-swagger-gen/models/task'; import { MessageHandlerService } from '../../../shared/message-handler/message-handler.service'; import { Project } from '../../project'; -import { ClrDatagridComparatorInterface, UserPermissionService, USERSTATICPERMISSION } from '../../../../lib/services'; +import { UserPermissionService, USERSTATICPERMISSION } from '../../../../lib/services'; 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 } from 'rxjs'; +import { forkJoin, Observable, Subject, Subscription } from 'rxjs'; import { ClrLoadingState } from '@clr/angular'; @Component({ @@ -31,12 +31,15 @@ export class TaskListComponent implements OnInit, OnDestroy { stopOnGoing: boolean; executionId: string; preheatPolicyName: string; - startTimeComparator: ClrDatagridComparatorInterface = new CustomComparator("start_time", "date"); execution: Execution; hasUpdatePermission: boolean = false; btnState: ClrLoadingState = ClrLoadingState.DEFAULT; timeout: any; timeoutForTaskList: any; + searchString: string; + private _searchSubject: Subject = new Subject(); + private _searchSubscription: Subscription; + filterKey: string = 'id'; constructor( private translate: TranslateService, private router: Router, @@ -60,6 +63,37 @@ export class TaskListComponent implements OnInit, OnDestroy { this.getExecutionDetail(true); } this.getPermissions(); + this.subscribeSearch(); + } + subscribeSearch() { + if (!this._searchSubscription) { + this._searchSubscription = this._searchSubject.pipe( + debounceTime(500), + switchMap(searchString => { + this.loading = true; + let params: string; + if (this.searchString) { + params = encodeURIComponent(`${this.filterKey}=~${searchString}`); + } + return this.preheatService.ListTasksResponse({ + projectName: this.projectName, + preheatPolicyName: this.preheatPolicyName, + executionId: +this.executionId, + page: this.currentPage, + pageSize: this.pageSize, + q: params + }).pipe(finalize(() => this.loading = false)); + })).subscribe(res => { + if (res.headers) { + let xHeader: string = res.headers.get('x-total-count'); + if (xHeader) { + this.totalCount = parseInt(xHeader, 0); + } + } + this.tasks = res.body; + this.setLoop(); + }); + } } ngOnDestroy(): void { if (this.timeout) { @@ -70,6 +104,10 @@ export class TaskListComponent implements OnInit, OnDestroy { clearTimeout(this.timeoutForTaskList); this.timeoutForTaskList = null; } + if (this._searchSubscription) { + this._searchSubscription.unsubscribe(); + this._searchSubscription = null; + } } getPermissions() { const permissionsList: Observable[] = []; @@ -93,10 +131,14 @@ export class TaskListComponent implements OnInit, OnDestroy { projectName: this.projectName, preheatPolicyName: this.preheatPolicyName, executionId: +this.executionId - }).pipe(finalize(() => (this.inProgress = false))) + }).pipe(finalize(() => this.inProgress = false)) .subscribe(res => { this.execution = res; if (!this.execution || this.p2pProviderService.willChangStatus(this.execution.status)) { + if (this.timeout) { + clearTimeout(this.timeout); + this.timeout = null; + } if (!this.timeout) { this.timeout = setTimeout(() => { this.getExecutionDetail(false); @@ -182,28 +224,30 @@ export class TaskListComponent implements OnInit, OnDestroy { if (withLoading) { this.loading = true; } - this.preheatService.ListTasks({ + let params: string; + if (this.searchString) { + params = encodeURIComponent(`${this.filterKey}=~${this.searchString}`); + } + this.preheatService.ListTasksResponse({ projectName: this.projectName, preheatPolicyName: this.preheatPolicyName, - executionId: +this.executionId + executionId: +this.executionId, + page: this.currentPage, + pageSize: this.pageSize, + q: params }) .pipe(finalize(() => { this.loading = false; })) .subscribe(res => { - this.tasks = res; - if (this.tasks && this.tasks.length) { - this.totalCount = this.tasks.length; - for (let i = 0; i < this.tasks.length; i++) { - if (this.p2pProviderService.willChangStatus(this.tasks[i].status)) { - if (!this.timeoutForTaskList) { - this.timeoutForTaskList = setTimeout(() => { - this.clrLoadTasks(false); - }, TIME_OUT); - } - } + if (res.headers) { + let xHeader: string = res.headers.get('x-total-count'); + if (xHeader) { + this.totalCount = parseInt(xHeader, 0); } } + this.tasks = res.body; + this.setLoop(); }, error => { this.messageHandlerService.error(error); @@ -233,4 +277,35 @@ export class TaskListComponent implements OnInit, OnDestroy { canStop(): boolean { return this.execution && this.p2pProviderService.willChangStatus(this.execution.status); } + setLoop() { + if (this.timeoutForTaskList) { + clearTimeout(this.timeoutForTaskList); + this.timeoutForTaskList = null; + } + if (this.tasks && this.tasks.length) { + for (let i = 0; i < this.tasks.length; i++) { + if (this.p2pProviderService.willChangStatus(this.tasks[i].status)) { + if (!this.timeoutForTaskList) { + this.timeoutForTaskList = setTimeout(() => { + this.clrLoadTasks(false); + }, TIME_OUT); + } + } + } + } + } + selectFilterKey($event: any): void { + this.filterKey = $event['target'].value; + } + doFilter(terms: string): void { + this.searchString = terms; + if (terms.trim()) { + this._searchSubject.next(terms.trim()); + } else { + this.clrLoadTasks(true); + } + } + openFilter(isOpen: boolean): void { + this.isOpenFilterTag = isOpen; + } } diff --git a/src/portal/src/i18n/lang/zh-cn-lang.json b/src/portal/src/i18n/lang/zh-cn-lang.json index ddb7dfd0d9..af6a5da86b 100644 --- a/src/portal/src/i18n/lang/zh-cn-lang.json +++ b/src/portal/src/i18n/lang/zh-cn-lang.json @@ -175,7 +175,7 @@ "LOGS": "日志", "TASKS": "任务", "API_EXPLORER": "API控制中心", - "HARBOR_API_MANAGEMENT": "Harbor Api V2.0", + "HARBOR_API_MANAGEMENT": "Harbor API V2.0", "HELM_API_MANAGEMENT": "Harbor Api", "DISTRIBUTIONS": { "NAME": "分布式分发", @@ -289,7 +289,7 @@ "SYS_ADMIN": "系统管理员", "PROJECT_ADMIN": "项目管理员", "PROJECT_MAINTAINER": "维护人员", - "DEVELOPER": "开发人员", + "DEVELOPER": "开发者", "GUEST": "访客", "LIMITED_GUEST": "受限访客", "DELETE": "删除", @@ -503,7 +503,7 @@ "SOURCE": "源", "DESTINATION": "目标", "POLICY": "政策", - "DURATION": "到期时间", + "DURATION": "持续时间", "SUCCESS_RATE": "成功百分比", "SUCCESS": "成功", "FAILURE": "失败", @@ -1446,7 +1446,7 @@ "ENDPOINT": "端点", "STATUS": "状态", "ENABLED": "启用", - "SETUP_TIMESTAMP": "设置时间", + "SETUP_TIMESTAMP": "创建时间", "PROVIDER": "供应商", "DELETION_TITLE": "删除实例", "DELETION_SUMMARY": "你确认删除实例 {{param}}?",