mirror of
https://github.com/goharbor/harbor.git
synced 2025-02-05 22:41:24 +01:00
Improve event panel (#14664)
Signed-off-by: AllForNothing <sshijun@vmware.com>
This commit is contained in:
parent
ba4a6d94ef
commit
45663e002d
@ -15,7 +15,7 @@
|
|||||||
<clr-icon class="clr-validate-icon" shape="exclamation-circle"></clr-icon>
|
<clr-icon class="clr-validate-icon" shape="exclamation-circle"></clr-icon>
|
||||||
</div>
|
</div>
|
||||||
<clr-control-error *ngIf="!getValidationState('newPassword')">
|
<clr-control-error *ngIf="!getValidationState('newPassword')">
|
||||||
{{ 'TOOLTIP.SIGN_IN_PWD' | translate }}
|
{{ 'TOOLTIP.PASSWORD' | translate }}
|
||||||
</clr-control-error>
|
</clr-control-error>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -42,9 +42,23 @@
|
|||||||
text-decoration: none;
|
text-decoration: none;
|
||||||
}
|
}
|
||||||
.freshIcon{float: right; margin-right: 20px; margin-top: -10px;cursor: pointer;}
|
.freshIcon{float: right; margin-right: 20px; margin-top: -10px;cursor: pointer;}
|
||||||
#contentFailed, #contentAll, #contentRun{
|
:host::ng-deep#contentAll{
|
||||||
position: absolute;
|
position: absolute;
|
||||||
top: 95px;
|
top: 115px;
|
||||||
|
bottom: 0;
|
||||||
|
width: 100%;
|
||||||
|
overflow-y: auto;
|
||||||
|
}
|
||||||
|
:host::ng-deep#contentFailed{
|
||||||
|
position: absolute;
|
||||||
|
top: 115px;
|
||||||
|
bottom: 0;
|
||||||
|
width: 100%;
|
||||||
|
overflow-y: auto;
|
||||||
|
}
|
||||||
|
:host::ng-deep#contentRun{
|
||||||
|
position: absolute;
|
||||||
|
top: 115px;
|
||||||
bottom: 0;
|
bottom: 0;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
overflow-y: auto;
|
overflow-y: auto;
|
||||||
|
@ -1,10 +1,7 @@
|
|||||||
import { ComponentFixture, fakeAsync, TestBed, tick } from '@angular/core/testing';
|
import { ComponentFixture, fakeAsync, TestBed, tick } from '@angular/core/testing';
|
||||||
import { BrowserAnimationsModule } from "@angular/platform-browser/animations";
|
|
||||||
import { TranslateService } from "@ngx-translate/core";
|
|
||||||
import { OperationComponent } from './operation.component';
|
import { OperationComponent } from './operation.component';
|
||||||
import { OperationService } from './operation.service';
|
import { OperationService } from './operation.service';
|
||||||
import { OperateInfo } from './operate';
|
import { OperateInfo } from './operate';
|
||||||
import { CURRENT_BASE_HREF } from "../../units/utils";
|
|
||||||
import { SharedTestingModule } from "../../shared.module";
|
import { SharedTestingModule } from "../../shared.module";
|
||||||
|
|
||||||
describe('OperationComponent', () => {
|
describe('OperationComponent', () => {
|
||||||
@ -15,11 +12,6 @@ describe('OperationComponent', () => {
|
|||||||
TestBed.configureTestingModule({
|
TestBed.configureTestingModule({
|
||||||
imports: [
|
imports: [
|
||||||
SharedTestingModule,
|
SharedTestingModule,
|
||||||
BrowserAnimationsModule,
|
|
||||||
],
|
|
||||||
providers: [
|
|
||||||
OperationService,
|
|
||||||
TranslateService,
|
|
||||||
]
|
]
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@ -47,9 +39,9 @@ describe('OperationComponent', () => {
|
|||||||
const right: string = getComputedStyle(fixture.nativeElement.querySelector(".operDiv")).right;
|
const right: string = getComputedStyle(fixture.nativeElement.querySelector(".operDiv")).right;
|
||||||
expect(right).toEqual("-325px");
|
expect(right).toEqual("-325px");
|
||||||
}));
|
}));
|
||||||
it("should show '50+' after pushing 60 new operateInfos", fakeAsync(() => {
|
it("should show '500+' after pushing 60 new operateInfos", fakeAsync(() => {
|
||||||
const operationService: OperationService = TestBed.get(OperationService);
|
const operationService: OperationService = TestBed.inject(OperationService);
|
||||||
for (let i = 0; i < 60; i++) {
|
for (let i = 0; i < 520; i++) {
|
||||||
let operateInfo = new OperateInfo();
|
let operateInfo = new OperateInfo();
|
||||||
if (i > 19) {
|
if (i > 19) {
|
||||||
operateInfo.state = "progressing";
|
operateInfo.state = "progressing";
|
||||||
@ -62,7 +54,7 @@ describe('OperationComponent', () => {
|
|||||||
}
|
}
|
||||||
fixture.detectChanges();
|
fixture.detectChanges();
|
||||||
const toolBar: HTMLAnchorElement = fixture.nativeElement.querySelector(".toolBar");
|
const toolBar: HTMLAnchorElement = fixture.nativeElement.querySelector(".toolBar");
|
||||||
expect(toolBar.textContent).toContain('50+');
|
expect(toolBar.textContent).toContain('500+');
|
||||||
}));
|
}));
|
||||||
it('check toggleTitle function', () => {
|
it('check toggleTitle function', () => {
|
||||||
const errorSpan: HTMLSpanElement = document.createElement('span');
|
const errorSpan: HTMLSpanElement = document.createElement('span');
|
||||||
|
@ -1,10 +1,14 @@
|
|||||||
import {Component, OnInit, OnDestroy, HostListener} from '@angular/core';
|
import { Component, OnInit, OnDestroy, HostListener } from '@angular/core';
|
||||||
import {OperationService} from "./operation.service";
|
import { OperationService } from "./operation.service";
|
||||||
import {Subscription} from "rxjs";
|
import { Subscription } from "rxjs";
|
||||||
import {OperateInfo, OperationState} from "./operate";
|
import { OperateInfo, OperationState } from "./operate";
|
||||||
import {SlideInOutAnimation} from "../../_animations/slide-in-out.animation";
|
import { SlideInOutAnimation } from "../../_animations/slide-in-out.animation";
|
||||||
import {TranslateService} from "@ngx-translate/core";
|
import { TranslateService } from "@ngx-translate/core";
|
||||||
|
import { SessionService } from "../../services/session.service";
|
||||||
|
|
||||||
|
const OPERATION_KEY: string = 'operation';
|
||||||
|
const MAX_NUMBER: number = 500;
|
||||||
|
const MAX_SAVING_TIME: number = 1000 * 60 * 60 * 24 * 30; // 30 days
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'hbr-operation-model',
|
selector: 'hbr-operation-model',
|
||||||
@ -21,13 +25,21 @@ export class OperationComponent implements OnInit, OnDestroy {
|
|||||||
|
|
||||||
@HostListener('window:beforeunload', ['$event'])
|
@HostListener('window:beforeunload', ['$event'])
|
||||||
beforeUnloadHander(event) {
|
beforeUnloadHander(event) {
|
||||||
// storage to localStorage
|
if (this.session.getCurrentUser()) {
|
||||||
let timp = new Date().getTime();
|
// storage to localStorage
|
||||||
localStorage.setItem('operaion', JSON.stringify({timp: timp, data: this.resultLists}));
|
const timp = new Date().getTime();
|
||||||
localStorage.setItem('newMessageCount', this._newMessageCount.toString());
|
// group by user id
|
||||||
|
localStorage.setItem(`${OPERATION_KEY}-${this.session.getCurrentUser().user_id}`,
|
||||||
|
JSON.stringify({
|
||||||
|
timp: timp,
|
||||||
|
data: this.resultLists,
|
||||||
|
newMessageCount: this._newMessageCount
|
||||||
|
}));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
|
private session: SessionService,
|
||||||
private operationService: OperationService,
|
private operationService: OperationService,
|
||||||
private translate: TranslateService) {
|
private translate: TranslateService) {
|
||||||
|
|
||||||
@ -36,8 +48,8 @@ export class OperationComponent implements OnInit, OnDestroy {
|
|||||||
this._newMessageCount += 1;
|
this._newMessageCount += 1;
|
||||||
}
|
}
|
||||||
if (data) {
|
if (data) {
|
||||||
if (this.resultLists.length >= 50) {
|
if (this.resultLists.length >= MAX_NUMBER) {
|
||||||
this.resultLists.splice(49, this.resultLists.length - 49);
|
this.resultLists.splice(MAX_NUMBER - 1, this.resultLists.length + 1 - MAX_NUMBER);
|
||||||
}
|
}
|
||||||
this.resultLists.unshift(data);
|
this.resultLists.unshift(data);
|
||||||
}
|
}
|
||||||
@ -46,29 +58,33 @@ export class OperationComponent implements OnInit, OnDestroy {
|
|||||||
|
|
||||||
getNewMessageCountStr(): string {
|
getNewMessageCountStr(): string {
|
||||||
if (this._newMessageCount) {
|
if (this._newMessageCount) {
|
||||||
if (this._newMessageCount > 50) {
|
if (this._newMessageCount > MAX_NUMBER) {
|
||||||
return 50 + '+';
|
return MAX_NUMBER + '+';
|
||||||
}
|
}
|
||||||
return this._newMessageCount.toString();
|
return this._newMessageCount.toString();
|
||||||
}
|
}
|
||||||
return '';
|
return '';
|
||||||
}
|
}
|
||||||
|
|
||||||
resetNewMessageCount() {
|
resetNewMessageCount() {
|
||||||
this._newMessageCount = 0;
|
this._newMessageCount = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
mouseover() {
|
mouseover() {
|
||||||
if (this._timeoutInterval) {
|
if (this._timeoutInterval) {
|
||||||
clearInterval(this._timeoutInterval);
|
clearInterval(this._timeoutInterval);
|
||||||
this._timeoutInterval = null;
|
this._timeoutInterval = null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
mouseleave() {
|
mouseleave() {
|
||||||
if (!this._timeoutInterval) {
|
if (!this._timeoutInterval) {
|
||||||
this._timeoutInterval = setTimeout(() => {
|
this._timeoutInterval = setTimeout(() => {
|
||||||
this.animationState = 'out';
|
this.animationState = 'out';
|
||||||
}, 5000);
|
}, 5000);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public get runningLists(): OperateInfo[] {
|
public get runningLists(): OperateInfo[] {
|
||||||
let runningList: OperateInfo[] = [];
|
let runningList: OperateInfo[] = [];
|
||||||
this.resultLists.forEach(data => {
|
this.resultLists.forEach(data => {
|
||||||
@ -89,29 +105,38 @@ export class OperationComponent implements OnInit, OnDestroy {
|
|||||||
return failedList;
|
return failedList;
|
||||||
}
|
}
|
||||||
|
|
||||||
ngOnInit() {
|
init() {
|
||||||
this._newMessageCount = +localStorage.getItem('newMessageCount');
|
if (this.session.getCurrentUser()) {
|
||||||
let requestCookie = localStorage.getItem('operaion');
|
let requestCookie = localStorage.getItem(`${OPERATION_KEY}-${this.session.getCurrentUser().user_id}`);
|
||||||
if (requestCookie) {
|
if (requestCookie) {
|
||||||
let operInfors: any = JSON.parse(requestCookie);
|
let operInfors: any = JSON.parse(requestCookie);
|
||||||
if (operInfors) {
|
if (operInfors) {
|
||||||
if ((new Date().getTime() - operInfors.timp) > 1000 * 60 * 60 * 24) {
|
if (operInfors.newMessageCount) {
|
||||||
localStorage.removeItem('operaion');
|
this._newMessageCount = operInfors.newMessageCount;
|
||||||
} else {
|
}
|
||||||
if (operInfors.data) {
|
if ((new Date().getTime() - operInfors.timp) > MAX_SAVING_TIME) {
|
||||||
operInfors.data.forEach(operInfo => {
|
localStorage.removeItem(`${OPERATION_KEY}-${this.session.getCurrentUser().user_id}`);
|
||||||
if (operInfo.state === OperationState.progressing) {
|
} else {
|
||||||
operInfo.state = OperationState.interrupt;
|
if (operInfors.data) {
|
||||||
operInfo.data.errorInf = 'operation been interrupted';
|
operInfors.data.forEach(operInfo => {
|
||||||
}
|
if (operInfo.state === OperationState.progressing) {
|
||||||
});
|
operInfo.state = OperationState.interrupt;
|
||||||
this.resultLists = operInfors.data;
|
operInfo.data.errorInf = 'operation been interrupted';
|
||||||
|
}
|
||||||
|
});
|
||||||
|
this.resultLists = operInfors.data;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ngOnInit() {
|
||||||
|
this.init();
|
||||||
|
}
|
||||||
|
|
||||||
ngOnDestroy(): void {
|
ngOnDestroy(): void {
|
||||||
if (this.batchInfoSubscription) {
|
if (this.batchInfoSubscription) {
|
||||||
this.batchInfoSubscription.unsubscribe();
|
this.batchInfoSubscription.unsubscribe();
|
||||||
@ -144,8 +169,8 @@ export class OperationComponent implements OnInit, OnDestroy {
|
|||||||
TabEvent(): void {
|
TabEvent(): void {
|
||||||
let timp: any;
|
let timp: any;
|
||||||
this.resultLists.forEach(data => {
|
this.resultLists.forEach(data => {
|
||||||
timp = new Date().getTime() - +data.timeStamp;
|
timp = new Date().getTime() - +data.timeStamp;
|
||||||
data.timeDiff = this.calculateTime(timp);
|
data.timeDiff = this.calculateTime(timp);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -155,29 +180,15 @@ export class OperationComponent implements OnInit, OnDestroy {
|
|||||||
return Math.floor(dist) + ' minute(s) ago';
|
return Math.floor(dist) + ' minute(s) ago';
|
||||||
} else if (dist >= 60 && Math.floor(dist / 60) < 24) {
|
} else if (dist >= 60 && Math.floor(dist / 60) < 24) {
|
||||||
return Math.floor(dist / 60) + ' hour(s) ago';
|
return Math.floor(dist / 60) + ' hour(s) ago';
|
||||||
} else if (Math.floor(dist / 60) >= 24) {
|
} else if (Math.floor(dist / 60) >= 24) {
|
||||||
return Math.floor(dist / 60 / 24) + ' day(s) ago';
|
return Math.floor(dist / 60 / 24) + ' day(s) ago';
|
||||||
} else {
|
} else {
|
||||||
return 'less than 1 minute';
|
return 'less than 1 minute';
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*calculateTime(timp: number) {
|
|
||||||
let dist = Math.floor(timp / 1000 / 60); // change to minute;
|
|
||||||
if (dist > 0 && dist < 60) {
|
|
||||||
return this.translateTime('OPERATION.MINUTE_AGO', Math.floor(dist));
|
|
||||||
}else if (dist > 60 && Math.floor(dist / 60) < 24) {
|
|
||||||
return this.translateTime('OPERATION.HOUR_AGO', Math.floor(dist / 60));
|
|
||||||
} else if (Math.floor(dist / 60) >= 24 && Math.floor(dist / 60) <= 48) {
|
|
||||||
return this.translateTime('OPERATION.DAY_AGO', Math.floor(dist / 60 / 24));
|
|
||||||
} else {
|
|
||||||
return this.translateTime('OPERATION.SECOND_AGO');
|
|
||||||
}
|
|
||||||
}*/
|
|
||||||
|
|
||||||
translateTime(tim: string, param?: number) {
|
translateTime(tim: string, param?: number) {
|
||||||
this.translate.get(tim, { 'param': param }).subscribe((res: string) => {
|
this.translate.get(tim, {'param': param}).subscribe((res: string) => {
|
||||||
return res;
|
return res;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user