Fix some UI issues (#18371)

1. Fixes #17892
2. Redirect to default page when redirectUrl starts with /account/sign-in

Signed-off-by: AllForNothing <sshijun@vmware.com>
This commit is contained in:
Shijun Sun 2023-03-17 18:52:23 +08:00 committed by GitHub
parent bea8dece07
commit e086710173
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
12 changed files with 121 additions and 187 deletions

View File

@ -259,7 +259,10 @@ export class SignInComponent implements AfterViewChecked, OnInit {
this.remeberMe(); this.remeberMe();
// Redirect to the right router-guard // Redirect to the right router-guard
if (this.redirectUrl === '') { if (
!this.redirectUrl ||
this.redirectUrl.startsWith(CommonRoutes.EMBEDDED_SIGN_IN)
) {
// Routing to the default location // Routing to the default location
this.router.navigateByUrl(CommonRoutes.HARBOR_DEFAULT); this.router.navigateByUrl(CommonRoutes.HARBOR_DEFAULT);
} else { } else {

View File

@ -10,10 +10,6 @@ import { CreateEditRuleComponent } from './create-edit-rule.component';
import { DatePickerComponent } from '../../../../../shared/components/datetime-picker/datetime-picker.component'; import { DatePickerComponent } from '../../../../../shared/components/datetime-picker/datetime-picker.component';
import { FilterComponent } from '../../../../../shared/components/filter/filter.component'; import { FilterComponent } from '../../../../../shared/components/filter/filter.component';
import { InlineAlertComponent } from '../../../../../shared/components/inline-alert/inline-alert.component'; import { InlineAlertComponent } from '../../../../../shared/components/inline-alert/inline-alert.component';
import {
ReplicationJob,
ReplicationJobItem,
} from '../../../../../shared/services';
import { ErrorHandler } from '../../../../../shared/units/error-handler'; import { ErrorHandler } from '../../../../../shared/units/error-handler';
import { ReplicationService } from '../../../../../shared/services'; import { ReplicationService } from '../../../../../shared/services';
import { LabelPieceComponent } from '../../../../../shared/components/label/label-piece/label-piece.component'; import { LabelPieceComponent } from '../../../../../shared/components/label/label-piece/label-piece.component';
@ -24,6 +20,7 @@ import { SharedTestingModule } from '../../../../../shared/shared.module';
import { RegistryService } from '../../../../../../../ng-swagger-gen/services/registry.service'; import { RegistryService } from '../../../../../../../ng-swagger-gen/services/registry.service';
import { Registry } from '../../../../../../../ng-swagger-gen/models/registry'; import { Registry } from '../../../../../../../ng-swagger-gen/models/registry';
import { ReplicationPolicy } from '../../../../../../../ng-swagger-gen/models/replication-policy'; import { ReplicationPolicy } from '../../../../../../../ng-swagger-gen/models/replication-policy';
import { ReplicationExecution } from '../../../../../../../ng-swagger-gen/models/replication-execution';
describe('CreateEditRuleComponent (inline template)', () => { describe('CreateEditRuleComponent (inline template)', () => {
let mockRules: ReplicationPolicy[] = [ let mockRules: ReplicationPolicy[] = [
@ -44,7 +41,7 @@ describe('CreateEditRuleComponent (inline template)', () => {
speed: -1, speed: -1,
}, },
]; ];
let mockJobs: ReplicationJobItem[] = [ let mockJobs: ReplicationExecution[] = [
{ {
id: 1, id: 1,
status: 'stopped', status: 'stopped',
@ -80,7 +77,7 @@ describe('CreateEditRuleComponent (inline template)', () => {
}, },
]; ];
let mockJob: ReplicationJob = { let mockJob: any = {
metadata: { xTotalCount: 3 }, metadata: { xTotalCount: 3 },
data: mockJobs, data: mockJobs,
}; };

View File

@ -1,5 +1,6 @@
<div class="list-rule"> <div class="list-rule">
<clr-datagrid <clr-datagrid
#datagrid
(clrDgRefresh)="clrLoad($event)" (clrDgRefresh)="clrLoad($event)"
[clrDgLoading]="loading" [clrDgLoading]="loading"
[(clrDgSingleSelected)]="selectedRow" [(clrDgSingleSelected)]="selectedRow"
@ -91,65 +92,47 @@
</clr-dropdown> </clr-dropdown>
</clr-dg-action-bar> </clr-dg-action-bar>
<clr-dg-column> <clr-dg-column>
<ng-template <ng-template [clrDgHideableColumn]="{ hidden: hiddenArray[0] }">
[clrDgHideableColumn]="{ hidden: hiddenArray[0] }"
(clrDgHiddenChange)="columnHiddenChange(0)">
{{ 'REPLICATION.NAME' | translate }} {{ 'REPLICATION.NAME' | translate }}
</ng-template> </ng-template>
</clr-dg-column> </clr-dg-column>
<clr-dg-column class="status-width"> <clr-dg-column class="status-width">
<ng-template <ng-template [clrDgHideableColumn]="{ hidden: hiddenArray[1] }">
[clrDgHideableColumn]="{ hidden: hiddenArray[1] }"
(clrDgHiddenChange)="columnHiddenChange(1)">
{{ 'REPLICATION.STATUS' | translate }} {{ 'REPLICATION.STATUS' | translate }}
</ng-template> </ng-template>
</clr-dg-column> </clr-dg-column>
<clr-dg-column class="col-width"> <clr-dg-column class="col-width">
<ng-template <ng-template [clrDgHideableColumn]="{ hidden: hiddenArray[2] }">
[clrDgHideableColumn]="{ hidden: hiddenArray[2] }"
(clrDgHiddenChange)="columnHiddenChange(2)">
{{ 'REPLICATION.SRC_REGISTRY' | translate }} {{ 'REPLICATION.SRC_REGISTRY' | translate }}
</ng-template> </ng-template>
</clr-dg-column> </clr-dg-column>
<clr-dg-column class="col-width"> <clr-dg-column class="col-width">
<ng-template <ng-template [clrDgHideableColumn]="{ hidden: hiddenArray[3] }">
[clrDgHideableColumn]="{ hidden: hiddenArray[3] }"
(clrDgHiddenChange)="columnHiddenChange(3)">
{{ 'REPLICATION.REPLICATION_MODE' | translate }} {{ 'REPLICATION.REPLICATION_MODE' | translate }}
</ng-template> </ng-template>
</clr-dg-column> </clr-dg-column>
<clr-dg-column class="min-width"> <clr-dg-column class="min-width">
<ng-template <ng-template [clrDgHideableColumn]="{ hidden: hiddenArray[4] }">
[clrDgHideableColumn]="{ hidden: hiddenArray[4] }"
(clrDgHiddenChange)="columnHiddenChange(4)">
{{ 'REPLICATION.DESTINATION_NAMESPACE' | translate }} {{ 'REPLICATION.DESTINATION_NAMESPACE' | translate }}
</ng-template> </ng-template>
</clr-dg-column> </clr-dg-column>
<clr-dg-column> <clr-dg-column>
<ng-template <ng-template [clrDgHideableColumn]="{ hidden: hiddenArray[5] }">
[clrDgHideableColumn]="{ hidden: hiddenArray[5] }"
(clrDgHiddenChange)="columnHiddenChange(5)">
{{ 'REPLICATION.DES_REPO_FLATTENING' | translate }} {{ 'REPLICATION.DES_REPO_FLATTENING' | translate }}
</ng-template> </ng-template>
</clr-dg-column> </clr-dg-column>
<clr-dg-column> <clr-dg-column>
<ng-template <ng-template [clrDgHideableColumn]="{ hidden: hiddenArray[6] }">
[clrDgHideableColumn]="{ hidden: hiddenArray[6] }"
(clrDgHiddenChange)="columnHiddenChange(6)">
{{ 'REPLICATION.REPLICATION_TRIGGER' | translate }} {{ 'REPLICATION.REPLICATION_TRIGGER' | translate }}
</ng-template></clr-dg-column </ng-template></clr-dg-column
> >
<clr-dg-column [clrDgSortBy]="'speed'"> <clr-dg-column [clrDgSortBy]="'speed'">
<ng-template <ng-template [clrDgHideableColumn]="{ hidden: hiddenArray[7] }">
[clrDgHideableColumn]="{ hidden: hiddenArray[7] }"
(clrDgHiddenChange)="columnHiddenChange(7)">
{{ 'REPLICATION.BANDWIDTH' | translate }} {{ 'REPLICATION.BANDWIDTH' | translate }}
</ng-template> </ng-template>
</clr-dg-column> </clr-dg-column>
<clr-dg-column [clrDgField]="'description'"> <clr-dg-column [clrDgField]="'description'">
<ng-template <ng-template [clrDgHideableColumn]="{ hidden: hiddenArray[8] }">
[clrDgHideableColumn]="{ hidden: hiddenArray[8] }"
(clrDgHiddenChange)="columnHiddenChange(8)">
{{ 'REPLICATION.DESCRIPTION' | translate }} {{ 'REPLICATION.DESCRIPTION' | translate }}
</ng-template> </ng-template>
</clr-dg-column> </clr-dg-column>

View File

@ -12,10 +12,11 @@
// See the License for the specific language governing permissions and // See the License for the specific language governing permissions and
// limitations under the License. // limitations under the License.
import { import {
AfterViewInit,
Component, Component,
ElementRef,
EventEmitter, EventEmitter,
Input, Input,
OnDestroy,
OnInit, OnInit,
Output, Output,
ViewChild, ViewChild,
@ -46,7 +47,7 @@ import {
OperationState, OperationState,
} from '../../../../../shared/components/operation/operate'; } from '../../../../../shared/components/operation/operate';
import { OperationService } from '../../../../../shared/components/operation/operation.service'; import { OperationService } from '../../../../../shared/components/operation/operation.service';
import { ClrDatagridStateInterface } from '@clr/angular'; import { ClrDatagrid, ClrDatagridStateInterface } from '@clr/angular';
import { errorHandler } from '../../../../../shared/units/shared.utils'; import { errorHandler } from '../../../../../shared/units/shared.utils';
import { ConfirmationAcknowledgement } from '../../../../global-confirmation-dialog/confirmation-state-message'; import { ConfirmationAcknowledgement } from '../../../../global-confirmation-dialog/confirmation-state-message';
import { ConfirmationMessage } from '../../../../global-confirmation-dialog/confirmation-message'; import { ConfirmationMessage } from '../../../../global-confirmation-dialog/confirmation-message';
@ -67,7 +68,7 @@ import { JobType } from '../../../job-service-dashboard/job-service-dashboard.in
templateUrl: './list-replication-rule.component.html', templateUrl: './list-replication-rule.component.html',
styleUrls: ['./list-replication-rule.component.scss'], styleUrls: ['./list-replication-rule.component.scss'],
}) })
export class ListReplicationRuleComponent implements OnInit, AfterViewInit { export class ListReplicationRuleComponent implements OnInit, OnDestroy {
@Input() selectedId: number | string; @Input() selectedId: number | string;
@Input() withReplicationJob: boolean; @Input() withReplicationJob: boolean;
@Input() hasCreateReplicationPermission: boolean; @Input() hasCreateReplicationPermission: boolean;
@ -101,17 +102,15 @@ export class ListReplicationRuleComponent implements OnInit, AfterViewInit {
PageSizeMapKeys.LIST_REPLICATION_RULE_COMPONENT, PageSizeMapKeys.LIST_REPLICATION_RULE_COMPONENT,
[false, false, false, false, false, false, false, true, true] [false, false, false, false, false, false, false, true, true]
); );
copiedHiddenArray: boolean[] = []; @ViewChild('datagrid')
private _hasViewInit: boolean = false; datagrid: ClrDatagrid;
constructor( constructor(
private replicationService: ReplicationService, private replicationService: ReplicationService,
private translateService: TranslateService, private translateService: TranslateService,
private errorHandlerEntity: ErrorHandler, private errorHandlerEntity: ErrorHandler,
private operationService: OperationService, private operationService: OperationService,
private scheduleService: ScheduleService private scheduleService: ScheduleService
) { ) {}
this.copiedHiddenArray = clone(this.hiddenArray);
}
ngOnInit() { ngOnInit() {
this.scheduleService this.scheduleService
@ -121,8 +120,14 @@ export class ListReplicationRuleComponent implements OnInit, AfterViewInit {
}); });
} }
ngAfterViewInit() { ngOnDestroy(): void {
this._hasViewInit = true; this.datagrid['columnsService']?.columns?.forEach((item, index) => {
this.hiddenArray[index] = !!item?._value?.hidden;
});
setHiddenArrayToLocalStorage(
PageSizeMapKeys.LIST_REPLICATION_RULE_COMPONENT,
this.hiddenArray
);
} }
getTriggerTypeI18n(t: ReplicationTrigger) { getTriggerTypeI18n(t: ReplicationTrigger) {
@ -397,14 +402,4 @@ export class ListReplicationRuleComponent implements OnInit, AfterViewInit {
} }
return 'REPLICATION.UNLIMITED'; return 'REPLICATION.UNLIMITED';
} }
columnHiddenChange(index: number) {
if (this._hasViewInit) {
this.copiedHiddenArray[index] = !this.copiedHiddenArray[index];
setHiddenArrayToLocalStorage(
PageSizeMapKeys.LIST_REPLICATION_RULE_COMPONENT,
this.copiedHiddenArray
);
}
}
} }

View File

@ -6,7 +6,6 @@ import { Subscription, timer } from 'rxjs';
import { ErrorHandler } from '../../../../../shared/units/error-handler'; import { ErrorHandler } from '../../../../../shared/units/error-handler';
import { import {
ClrDatagridComparatorInterface, ClrDatagridComparatorInterface,
ReplicationJob,
ReplicationTasks, ReplicationTasks,
} from '../../../../../shared/services'; } from '../../../../../shared/services';
import { import {
@ -55,9 +54,9 @@ export class ReplicationTasksComponent implements OnInit, OnDestroy {
timerDelay: Subscription; timerDelay: Subscription;
executionId: string; executionId: string;
startTimeComparator: ClrDatagridComparatorInterface<ReplicationTask> = startTimeComparator: ClrDatagridComparatorInterface<ReplicationTask> =
new CustomComparator<ReplicationJob>('start_time', 'date'); new CustomComparator<ReplicationExecution>('start_time', 'date');
endTimeComparator: ClrDatagridComparatorInterface<ReplicationTask> = endTimeComparator: ClrDatagridComparatorInterface<ReplicationTask> =
new CustomComparator<ReplicationJob>('end_time', 'date'); new CustomComparator<ReplicationExecution>('end_time', 'date');
tasksTimeout: any; tasksTimeout: any;
constructor( constructor(
private translate: TranslateService, private translate: TranslateService,

View File

@ -194,7 +194,6 @@
</div> </div>
<hbr-create-edit-rule <hbr-create-edit-rule
*ngIf="isSystemAdmin" *ngIf="isSystemAdmin"
[withAdmiral]="withAdmiral"
(goToRegistry)="goRegistry()" (goToRegistry)="goRegistry()"
(reload)="reloadRules($event)"></hbr-create-edit-rule> (reload)="reloadRules($event)"></hbr-create-edit-rule>
<confirmation-dialog <confirmation-dialog

View File

@ -8,10 +8,9 @@ import { NoopAnimationsModule } from '@angular/platform-browser/animations';
import { ConfirmationDialogComponent } from '../../../../shared/components/confirmation-dialog'; import { ConfirmationDialogComponent } from '../../../../shared/components/confirmation-dialog';
import { ReplicationComponent } from './replication.component'; import { ReplicationComponent } from './replication.component';
import { CronScheduleComponent } from '../../../../shared/components/cron-schedule'; import { CronScheduleComponent } from '../../../../shared/components/cron-schedule';
import { ReplicationJob, Endpoint } from '../../../../shared/services'; import { Endpoint } from '../../../../shared/services';
import { CronTooltipComponent } from '../../../../shared/components/cron-schedule'; import { CronTooltipComponent } from '../../../../shared/components/cron-schedule';
import { ErrorHandler } from '../../../../shared/units/error-handler'; import { ErrorHandler } from '../../../../shared/units/error-handler';
import { ReplicationJobItem } from '../../../../shared/services';
import { OperationService } from '../../../../shared/components/operation/operation.service'; import { OperationService } from '../../../../shared/components/operation/operation.service';
import { RouterTestingModule } from '@angular/router/testing'; import { RouterTestingModule } from '@angular/router/testing';
import { of, Subscription } from 'rxjs'; import { of, Subscription } from 'rxjs';
@ -20,6 +19,7 @@ import { delay } from 'rxjs/operators';
import { SharedTestingModule } from '../../../../shared/shared.module'; import { SharedTestingModule } from '../../../../shared/shared.module';
import { ReplicationPolicy } from '../../../../../../ng-swagger-gen/models/replication-policy'; import { ReplicationPolicy } from '../../../../../../ng-swagger-gen/models/replication-policy';
import { ReplicationService } from 'ng-swagger-gen/services/replication.service'; import { ReplicationService } from 'ng-swagger-gen/services/replication.service';
import { ReplicationExecution } from '../../../../../../ng-swagger-gen/models/replication-execution';
describe('Replication Component (inline template)', () => { describe('Replication Component (inline template)', () => {
let mockRules: ReplicationPolicy[] = [ let mockRules: ReplicationPolicy[] = [
@ -51,7 +51,7 @@ describe('Replication Component (inline template)', () => {
}, },
]; ];
let mockJobs: ReplicationJobItem[] = [ let mockJobs: ReplicationExecution[] = [
{ {
id: 1, id: 1,
status: 'stopped', status: 'stopped',
@ -116,7 +116,7 @@ describe('Replication Component (inline template)', () => {
}, },
]; ];
let mockJob: ReplicationJob = { let mockJob: any = {
metadata: { xTotalCount: 3 }, metadata: { xTotalCount: 3 },
data: mockJobs, data: mockJobs,
}; };
@ -190,7 +190,7 @@ describe('Replication Component (inline template)', () => {
}); });
it('function "getDuration" should work', () => { it('function "getDuration" should work', () => {
// ms level // ms level
const item: ReplicationJobItem = { const item: any = {
start_time: 1589340503637, start_time: 1589340503637,
end_time: 1589340503638, end_time: 1589340503638,
id: 3, id: 3,

View File

@ -39,11 +39,7 @@ import { TranslateService } from '@ngx-translate/core';
import { ListReplicationRuleComponent } from './list-replication-rule/list-replication-rule.component'; import { ListReplicationRuleComponent } from './list-replication-rule/list-replication-rule.component';
import { CreateEditRuleComponent } from './create-edit-rule/create-edit-rule.component'; import { CreateEditRuleComponent } from './create-edit-rule/create-edit-rule.component';
import { ErrorHandler } from '../../../../shared/units/error-handler'; import { ErrorHandler } from '../../../../shared/units/error-handler';
import { import { Comparator } from '../../../../shared/services';
Comparator,
ReplicationJob,
ReplicationJobItem,
} from '../../../../shared/services';
import { import {
calculatePage, calculatePage,
@ -78,6 +74,7 @@ import { ConfirmationAcknowledgement } from '../../../global-confirmation-dialog
import { ReplicationService } from 'ng-swagger-gen/services/replication.service'; import { ReplicationService } from 'ng-swagger-gen/services/replication.service';
import { ReplicationPolicy } from '../../../../../../ng-swagger-gen/models/replication-policy'; import { ReplicationPolicy } from '../../../../../../ng-swagger-gen/models/replication-policy';
import { ReplicationExecutionFilter } from '../replication'; import { ReplicationExecutionFilter } from '../replication';
import { ReplicationExecution } from '../../../../../../ng-swagger-gen/models/replication-execution';
const ONE_HOUR_SECONDS: number = 3600; const ONE_HOUR_SECONDS: number = 3600;
const ONE_MINUTE_SECONDS: number = 60; const ONE_MINUTE_SECONDS: number = 60;
@ -126,11 +123,11 @@ export class ReplicationComponent implements OnInit, OnDestroy {
currentRuleStatus: { key: string; description: string }; currentRuleStatus: { key: string; description: string };
currentTerm: string; currentTerm: string;
defaultFilter = 'trigger'; defaultFilter = 'trigger';
selectedRow: ReplicationJobItem[] = []; selectedRow: ReplicationExecution[] = [];
isStopOnGoing: boolean; isStopOnGoing: boolean;
hiddenJobList = true; hiddenJobList = true;
jobs: ReplicationJobItem[]; jobs: ReplicationExecution[];
@ViewChild(ListReplicationRuleComponent) @ViewChild(ListReplicationRuleComponent)
listReplicationRule: ListReplicationRuleComponent; listReplicationRule: ListReplicationRuleComponent;
@ -144,10 +141,10 @@ export class ReplicationComponent implements OnInit, OnDestroy {
@ViewChild('StopConfirmDialog') @ViewChild('StopConfirmDialog')
StopConfirmDialog: ConfirmationDialogComponent; StopConfirmDialog: ConfirmationDialogComponent;
creationTimeComparator: Comparator<ReplicationJob> = creationTimeComparator: Comparator<ReplicationExecution> =
new CustomComparator<ReplicationJob>('start_time', 'date'); new CustomComparator<ReplicationExecution>('start_time', 'date');
updateTimeComparator: Comparator<ReplicationJob> = updateTimeComparator: Comparator<ReplicationExecution> =
new CustomComparator<ReplicationJob>('end_time', 'date'); new CustomComparator<ReplicationExecution>('end_time', 'date');
// Server driven pagination // Server driven pagination
currentPage: number = 1; currentPage: number = 1;
@ -290,7 +287,6 @@ export class ReplicationComponent implements OnInit, OnDestroy {
if (withLoading) { if (withLoading) {
this.jobsLoading = true; this.jobsLoading = true;
} }
this.selectedRow = [];
this.replicationService this.replicationService
.listReplicationExecutionsResponse(params) .listReplicationExecutionsResponse(params)
.subscribe( .subscribe(
@ -299,7 +295,26 @@ export class ReplicationComponent implements OnInit, OnDestroy {
response.headers.get('x-total-count'), response.headers.get('x-total-count'),
10 10
); );
this.jobs = response.body as ReplicationJobItem[]; if (withLoading) {
this.jobs = response.body;
} else {
// Do not update reference of this.jobs on refresh, otherwise datagrid will refresh
this.jobs?.forEach(item1 => {
response.body?.forEach(item2 => {
if (item1.id === item2.id) {
item1.status = item2.status;
item1.status_text = item2.status_text;
item1.failed = item2.failed;
item1.in_progress = item2.in_progress;
item1.stopped = item2.stopped;
item1.succeed = item2.succeed;
item1.total = item2.total;
item1.start_time = item2.start_time;
item1.end_time = item2.end_time;
}
});
});
}
if (!this.timerDelay) { if (!this.timerDelay) {
this.timerDelay = timer( this.timerDelay = timer(
REFRESH_TIME_DIFFERENCE, REFRESH_TIME_DIFFERENCE,
@ -320,11 +335,14 @@ export class ReplicationComponent implements OnInit, OnDestroy {
}); });
} }
// Do filtering and sorting // Do filtering and sorting
this.jobs = doFiltering<ReplicationJobItem>( this.jobs = doFiltering<ReplicationExecution>(
this.jobs,
state
);
this.jobs = doSorting<ReplicationExecution>(
this.jobs, this.jobs,
state state
); );
this.jobs = doSorting<ReplicationJobItem>(this.jobs, state);
this.jobsLoading = false; this.jobsLoading = false;
}, },
@ -461,7 +479,7 @@ export class ReplicationComponent implements OnInit, OnDestroy {
this.hiddenJobList = true; this.hiddenJobList = true;
} }
openStopExecutionsDialog(targets: ReplicationJobItem[]) { openStopExecutionsDialog(targets: ReplicationExecution[]) {
let ExecutionId = targets.map(robot => robot.id).join(','); let ExecutionId = targets.map(robot => robot.id).join(',');
let StopExecutionsMessage = new ConfirmationMessage( let StopExecutionsMessage = new ConfirmationMessage(
'REPLICATION.STOP_TITLE', 'REPLICATION.STOP_TITLE',
@ -497,7 +515,7 @@ export class ReplicationComponent implements OnInit, OnDestroy {
} }
} }
StopExecutions(targets: ReplicationJobItem[]): void { StopExecutions(targets: ReplicationExecution[]): void {
if (targets && targets.length < 1) { if (targets && targets.length < 1) {
return; return;
} }
@ -527,7 +545,7 @@ export class ReplicationComponent implements OnInit, OnDestroy {
} }
} }
StopOperate(targets: ReplicationJobItem): any { StopOperate(targets: ReplicationExecution): any {
let operMessage = new OperateInfo(); let operMessage = new OperateInfo();
operMessage.name = 'OPERATION.STOP_EXECUTIONS'; operMessage.name = 'OPERATION.STOP_EXECUTIONS';
operMessage.data.id = targets.id; operMessage.data.id = targets.id;
@ -578,6 +596,7 @@ export class ReplicationComponent implements OnInit, OnDestroy {
} }
refreshJobs() { refreshJobs() {
this.selectedRow = [];
this.currentTerm = ''; this.currentTerm = '';
this.currentPage = 1; this.currentPage = 1;
let st: ClrDatagridStateInterface = { let st: ClrDatagridStateInterface = {
@ -594,7 +613,7 @@ export class ReplicationComponent implements OnInit, OnDestroy {
this.isOpenFilterTag = isOpen; this.isOpenFilterTag = isOpen;
} }
getDuration(j: ReplicationJobItem) { getDuration(j: ReplicationExecution) {
if (!j) { if (!j) {
return; return;
} }

View File

@ -8,6 +8,7 @@
<div class="row tag-row"> <div class="row tag-row">
<div class="col-lg-12 col-md-12 col-sm-12 col-xs-12"> <div class="col-lg-12 col-md-12 col-sm-12 col-xs-12">
<clr-datagrid <clr-datagrid
#datagrid
[clrDgLoading]="loading" [clrDgLoading]="loading"
(clrDgRefresh)="clrDgRefresh($event)" (clrDgRefresh)="clrDgRefresh($event)"
[(clrDgSelected)]="selectedRow"> [(clrDgSelected)]="selectedRow">
@ -137,78 +138,58 @@
<clr-dg-column class="flex-max-width" [clrDgSortBy]="'digest'" <clr-dg-column class="flex-max-width" [clrDgSortBy]="'digest'"
><ng-template ><ng-template
[clrDgHideableColumn]="{ hidden: hiddenArray[0] }" [clrDgHideableColumn]="{ hidden: hiddenArray[0] }">
(clrDgHiddenChange)="columnHiddenChange(0)">
{{ 'REPOSITORY.ARTIFACTS_COUNT' | translate }} {{ 'REPOSITORY.ARTIFACTS_COUNT' | translate }}
</ng-template> </ng-template>
</clr-dg-column> </clr-dg-column>
<clr-dg-column class="pull-command-column"> <clr-dg-column class="pull-command-column">
<ng-template <ng-template [clrDgHideableColumn]="{ hidden: hiddenArray[1] }">
[clrDgHideableColumn]="{ hidden: hiddenArray[1] }"
(clrDgHiddenChange)="columnHiddenChange(1)">
{{ 'REPOSITORY.PULL_COMMAND' | translate }} {{ 'REPOSITORY.PULL_COMMAND' | translate }}
</ng-template> </ng-template>
</clr-dg-column> </clr-dg-column>
<clr-dg-column *ngIf="depth"> <clr-dg-column *ngIf="depth">
<ng-template <ng-template [clrDgHideableColumn]="{ hidden: hiddenArray[2] }">
[clrDgHideableColumn]="{ hidden: hiddenArray[2] }"
(clrDgHiddenChange)="columnHiddenChange(2)">
{{ 'REPOSITORY.PLATFORM' | translate }} {{ 'REPOSITORY.PLATFORM' | translate }}
</ng-template> </ng-template>
</clr-dg-column> </clr-dg-column>
<clr-dg-column> <clr-dg-column>
<ng-template <ng-template [clrDgHideableColumn]="{ hidden: hiddenArray[3] }">
[clrDgHideableColumn]="{ hidden: hiddenArray[3] }"
(clrDgHiddenChange)="columnHiddenChange(3)">
{{ 'REPOSITORY.TAGS' | translate }} {{ 'REPOSITORY.TAGS' | translate }}
</ng-template> </ng-template>
</clr-dg-column> </clr-dg-column>
<clr-dg-column class="co-signed-column"> <clr-dg-column class="co-signed-column">
<ng-template <ng-template [clrDgHideableColumn]="{ hidden: hiddenArray[4] }">
[clrDgHideableColumn]="{ hidden: hiddenArray[4] }"
(clrDgHiddenChange)="columnHiddenChange(4)">
{{ 'ACCESSORY.CO_SIGNED' | translate }} {{ 'ACCESSORY.CO_SIGNED' | translate }}
</ng-template> </ng-template>
</clr-dg-column> </clr-dg-column>
<clr-dg-column [clrDgSortBy]="'size'"> <clr-dg-column [clrDgSortBy]="'size'">
<ng-template <ng-template [clrDgHideableColumn]="{ hidden: hiddenArray[5] }">
[clrDgHideableColumn]="{ hidden: hiddenArray[5] }"
(clrDgHiddenChange)="columnHiddenChange(5)">
{{ 'REPOSITORY.SIZE' | translate }} {{ 'REPOSITORY.SIZE' | translate }}
</ng-template> </ng-template>
</clr-dg-column> </clr-dg-column>
<clr-dg-column class="vul-column"> <clr-dg-column class="vul-column">
<ng-template <ng-template [clrDgHideableColumn]="{ hidden: hiddenArray[6] }">
[clrDgHideableColumn]="{ hidden: hiddenArray[6] }"
(clrDgHiddenChange)="columnHiddenChange(6)">
{{ 'REPOSITORY.VULNERABILITY' | translate }} {{ 'REPOSITORY.VULNERABILITY' | translate }}
</ng-template> </ng-template>
</clr-dg-column> </clr-dg-column>
<clr-dg-column class="annotations-column"> <clr-dg-column class="annotations-column">
<ng-template <ng-template [clrDgHideableColumn]="{ hidden: hiddenArray[7] }">
[clrDgHideableColumn]="{ hidden: hiddenArray[7] }"
(clrDgHiddenChange)="columnHiddenChange(7)">
{{ 'ARTIFACT.ANNOTATION' | translate }} {{ 'ARTIFACT.ANNOTATION' | translate }}
</ng-template> </ng-template>
</clr-dg-column> </clr-dg-column>
<clr-dg-column> <clr-dg-column>
<ng-template <ng-template [clrDgHideableColumn]="{ hidden: hiddenArray[8] }">
[clrDgHideableColumn]="{ hidden: hiddenArray[8] }"
(clrDgHiddenChange)="columnHiddenChange(8)">
{{ 'REPOSITORY.LABELS' | translate }} {{ 'REPOSITORY.LABELS' | translate }}
</ng-template> </ng-template>
</clr-dg-column> </clr-dg-column>
<clr-dg-column [clrDgSortBy]="pushComparator"> <clr-dg-column [clrDgSortBy]="pushComparator">
<ng-template <ng-template [clrDgHideableColumn]="{ hidden: hiddenArray[9] }">
[clrDgHideableColumn]="{ hidden: hiddenArray[9] }"
(clrDgHiddenChange)="columnHiddenChange(9)">
{{ 'REPOSITORY.PUSH_TIME' | translate }} {{ 'REPOSITORY.PUSH_TIME' | translate }}
</ng-template> </ng-template>
</clr-dg-column> </clr-dg-column>
<clr-dg-column [clrDgSortBy]="pullComparator"> <clr-dg-column [clrDgSortBy]="pullComparator">
<ng-template <ng-template
[clrDgHideableColumn]="{ hidden: hiddenArray[10] }" [clrDgHideableColumn]="{ hidden: hiddenArray[10] }">
(clrDgHiddenChange)="columnHiddenChange(10)">
{{ 'REPOSITORY.PULL_TIME' | translate }} {{ 'REPOSITORY.PULL_TIME' | translate }}
</ng-template> </ng-template>
</clr-dg-column> </clr-dg-column>

View File

@ -11,13 +11,7 @@
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and // See the License for the specific language governing permissions and
// limitations under the License. // limitations under the License.
import { import { Component, OnDestroy, OnInit, ViewChild } from '@angular/core';
AfterViewInit,
Component,
OnDestroy,
OnInit,
ViewChild,
} from '@angular/core';
import { forkJoin, Observable, of, Subscription } from 'rxjs'; import { forkJoin, Observable, of, Subscription } from 'rxjs';
import { catchError, finalize, map } from 'rxjs/operators'; import { catchError, finalize, map } from 'rxjs/operators';
import { TranslateService } from '@ngx-translate/core'; import { TranslateService } from '@ngx-translate/core';
@ -104,9 +98,7 @@ const FALSE: string = 'false';
templateUrl: './artifact-list-tab.component.html', templateUrl: './artifact-list-tab.component.html',
styleUrls: ['./artifact-list-tab.component.scss'], styleUrls: ['./artifact-list-tab.component.scss'],
}) })
export class ArtifactListTabComponent export class ArtifactListTabComponent implements OnInit, OnDestroy {
implements OnInit, OnDestroy, AfterViewInit
{
projectId: number; projectId: number;
projectName: string; projectName: string;
repoName: string; repoName: string;
@ -187,9 +179,9 @@ export class ArtifactListTabComponent
false, false,
] ]
); );
copiedHiddenArray: boolean[] = [];
private _hasViewInit: boolean = false;
deleteAccessorySub: Subscription; deleteAccessorySub: Subscription;
@ViewChild('datagrid')
datagrid;
constructor( constructor(
private errorHandlerService: ErrorHandler, private errorHandlerService: ErrorHandler,
private artifactService: ArtifactService, private artifactService: ArtifactService,
@ -201,9 +193,7 @@ export class ArtifactListTabComponent
private router: Router, private router: Router,
private appConfigService: AppConfigService, private appConfigService: AppConfigService,
private artifactListPageService: ArtifactListPageService private artifactListPageService: ArtifactListPageService
) { ) {}
this.copiedHiddenArray = clone(this.hiddenArray);
}
initRouterData() { initRouterData() {
this.projectId = this.projectId =
this.activatedRoute.snapshot?.parent?.parent?.params['id']; this.activatedRoute.snapshot?.parent?.parent?.params['id'];
@ -253,10 +243,6 @@ export class ArtifactListTabComponent
} }
} }
ngAfterViewInit() {
this._hasViewInit = true;
}
ngOnDestroy() { ngOnDestroy() {
if (this.updateArtifactSub) { if (this.updateArtifactSub) {
this.updateArtifactSub.unsubscribe(); this.updateArtifactSub.unsubscribe();
@ -266,6 +252,21 @@ export class ArtifactListTabComponent
this.deleteAccessorySub.unsubscribe(); this.deleteAccessorySub.unsubscribe();
this.deleteAccessorySub = null; this.deleteAccessorySub = null;
} }
this.datagrid['columnsService']?.columns?.forEach((item, index) => {
if (this.depth) {
this.hiddenArray[index] = !!item?._value?.hidden;
} else {
if (index < 2) {
this.hiddenArray[index] = !!item?._value?.hidden;
} else {
this.hiddenArray[index + 1] = !!item?._value?.hidden;
}
}
});
setHiddenArrayToLocalStorage(
PageSizeMapKeys.ARTIFACT_LIST_TAB_COMPONENT,
this.hiddenArray
);
} }
get withNotary(): boolean { get withNotary(): boolean {
return this.appConfigService.getConfig()?.with_notary; return this.appConfigService.getConfig()?.with_notary;
@ -1063,14 +1064,4 @@ export class ArtifactListTabComponent
isEllipsisActive(ele: HTMLSpanElement): boolean { isEllipsisActive(ele: HTMLSpanElement): boolean {
return ele?.offsetWidth < ele?.scrollWidth; return ele?.offsetWidth < ele?.scrollWidth;
} }
columnHiddenChange(index: number) {
if (this._hasViewInit) {
this.copiedHiddenArray[index] = !this.copiedHiddenArray[index];
setHiddenArrayToLocalStorage(
PageSizeMapKeys.ARTIFACT_LIST_TAB_COMPONENT,
this.copiedHiddenArray
);
}
}
} }

View File

@ -74,36 +74,6 @@ export class Trigger {
} }
} }
/**
* Interface for replication job.
*
**
* interface ReplicationJob
*/
export interface ReplicationJob {
metadata?: Metadata;
data: ReplicationJobItem[];
}
/**
* Interface for replication job item.
*
**
* interface ReplicationJob
*/
export interface ReplicationJobItem extends Base {
[key: string]: any | any[];
id: number;
status: string;
policy_id: number;
trigger: string;
total: number;
failed: number;
succeed: number;
in_progress: number;
stopped: number;
}
/** /**
* Interface for replication tasks item. * Interface for replication tasks item.
* *

View File

@ -8,15 +8,12 @@ import {
HTTP_GET_OPTIONS_OBSERVE_RESPONSE, HTTP_GET_OPTIONS_OBSERVE_RESPONSE,
CURRENT_BASE_HREF, CURRENT_BASE_HREF,
} from '../units/utils'; } from '../units/utils';
import { import { ReplicationTasks } from './interface';
ReplicationJob,
ReplicationJobItem,
ReplicationTasks,
} from './interface';
import { RequestQueryParams } from './RequestQueryParams'; import { RequestQueryParams } from './RequestQueryParams';
import { map, catchError } from 'rxjs/operators'; import { map, catchError } from 'rxjs/operators';
import { Observable, throwError as observableThrowError } from 'rxjs'; import { Observable, throwError as observableThrowError } from 'rxjs';
import { ReplicationPolicy } from '../../../../ng-swagger-gen/models/replication-policy'; import { ReplicationPolicy } from '../../../../ng-swagger-gen/models/replication-policy';
import { ReplicationExecution } from '../../../../ng-swagger-gen/models/replication-execution';
/** /**
* Define the service methods to handle the replication (rule and job) related things. * Define the service methods to handle the replication (rule and job) related things.
@ -163,7 +160,7 @@ export abstract class ReplicationService {
abstract getExecutions( abstract getExecutions(
ruleId: number | string, ruleId: number | string,
queryParams?: RequestQueryParams queryParams?: RequestQueryParams
): Observable<ReplicationJob>; ): Observable<ReplicationExecution>;
/** /**
* Get the specified execution. * Get the specified execution.
@ -176,7 +173,7 @@ export abstract class ReplicationService {
*/ */
abstract getExecutionById( abstract getExecutionById(
executionId: number | string executionId: number | string
): Observable<ReplicationJob>; ): Observable<ReplicationExecution>;
/** /**
* Get the log of the specified job. * Get the log of the specified job.
@ -410,7 +407,7 @@ export class ReplicationDefaultService extends ReplicationService {
public getExecutions( public getExecutions(
ruleId: number | string, ruleId: number | string,
queryParams?: RequestQueryParams queryParams?: RequestQueryParams
): Observable<ReplicationJob> { ): Observable<ReplicationExecution> {
if (!ruleId || ruleId <= 0) { if (!ruleId || ruleId <= 0) {
return observableThrowError('Bad argument'); return observableThrowError('Bad argument');
} }
@ -421,13 +418,13 @@ export class ReplicationDefaultService extends ReplicationService {
let url: string = `${this._replicateUrl}/executions`; let url: string = `${this._replicateUrl}/executions`;
queryParams = queryParams.set('policy_id', '' + ruleId); queryParams = queryParams.set('policy_id', '' + ruleId);
return this.http return this.http
.get<HttpResponse<ReplicationJobItem[]>>( .get<HttpResponse<ReplicationExecution[]>>(
url, url,
buildHttpRequestOptionsWithObserveResponse(queryParams) buildHttpRequestOptionsWithObserveResponse(queryParams)
) )
.pipe( .pipe(
map(response => { map(response => {
let result: ReplicationJob = { let result: any = {
metadata: { metadata: {
xTotalCount: 0, xTotalCount: 0,
}, },
@ -441,7 +438,7 @@ export class ReplicationDefaultService extends ReplicationService {
result.metadata.xTotalCount = parseInt(xHeader, 0); result.metadata.xTotalCount = parseInt(xHeader, 0);
} }
} }
result.data = response.body as ReplicationJobItem[]; result.data = response.body as ReplicationExecution[];
if (result.metadata.xTotalCount === 0) { if (result.metadata.xTotalCount === 0) {
if (result.data && result.data.length > 0) { if (result.data && result.data.length > 0) {
result.metadata.xTotalCount = result.data.length; result.metadata.xTotalCount = result.data.length;
@ -456,19 +453,19 @@ export class ReplicationDefaultService extends ReplicationService {
public getExecutionById( public getExecutionById(
executionId: number | string executionId: number | string
): Observable<ReplicationJob> { ): Observable<ReplicationExecution> {
if (!executionId || executionId <= 0) { if (!executionId || executionId <= 0) {
return observableThrowError('Bad request argument.'); return observableThrowError('Bad request argument.');
} }
let requestUrl: string = `${this._replicateUrl}/executions/${executionId}`; let requestUrl: string = `${this._replicateUrl}/executions/${executionId}`;
return this.http return this.http
.get<HttpResponse<ReplicationJobItem[]>>( .get<HttpResponse<ReplicationExecution[]>>(
requestUrl, requestUrl,
HTTP_GET_OPTIONS_OBSERVE_RESPONSE HTTP_GET_OPTIONS_OBSERVE_RESPONSE
) )
.pipe( .pipe(
map(response => { map(response => {
let result: ReplicationJob = { let result: any = {
metadata: { metadata: {
xTotalCount: 0, xTotalCount: 0,
}, },
@ -482,7 +479,7 @@ export class ReplicationDefaultService extends ReplicationService {
result.metadata.xTotalCount = parseInt(xHeader, 0); result.metadata.xTotalCount = parseInt(xHeader, 0);
} }
} }
result.data = response.body as ReplicationJobItem[]; result.data = response.body as ReplicationExecution[];
if (result.metadata.xTotalCount === 0) { if (result.metadata.xTotalCount === 0) {
if (result.data && result.data.length > 0) { if (result.data && result.data.length > 0) {
result.metadata.xTotalCount = result.data.length; result.metadata.xTotalCount = result.data.length;