mirror of
https://github.com/goharbor/harbor.git
synced 2024-12-03 15:43:39 +01:00
Merge pull request #11073 from AllForNothing/permission
Swith to new API for recent log page
This commit is contained in:
commit
2b6fb4abcf
@ -456,7 +456,9 @@
|
|||||||
"FILTER_PLACEHOLDER": "Filter Logs",
|
"FILTER_PLACEHOLDER": "Filter Logs",
|
||||||
"INVALID_DATE": "Invalid date.",
|
"INVALID_DATE": "Invalid date.",
|
||||||
"OF": "of",
|
"OF": "of",
|
||||||
"NOT_FOUND": "We couldn't find any logs!"
|
"NOT_FOUND": "We couldn't find any logs!",
|
||||||
|
"RESOURCE": "Resource",
|
||||||
|
"RESOURCE_TYPE": "Resource Type"
|
||||||
},
|
},
|
||||||
"REPLICATION": {
|
"REPLICATION": {
|
||||||
"YES": "Yes",
|
"YES": "Yes",
|
||||||
|
@ -456,7 +456,9 @@
|
|||||||
"FILTER_PLACEHOLDER": "Filtrar logs",
|
"FILTER_PLACEHOLDER": "Filtrar logs",
|
||||||
"INVALID_DATE": "Fecha invalida.",
|
"INVALID_DATE": "Fecha invalida.",
|
||||||
"OF": "of",
|
"OF": "of",
|
||||||
"NOT_FOUND": "No pudimos encontrar ningún registro!"
|
"NOT_FOUND": "No pudimos encontrar ningún registro!",
|
||||||
|
"RESOURCE": "Resource",
|
||||||
|
"RESOURCE_TYPE": "Resource Type"
|
||||||
},
|
},
|
||||||
"REPLICATION": {
|
"REPLICATION": {
|
||||||
"YES": "Yes",
|
"YES": "Yes",
|
||||||
|
@ -448,7 +448,9 @@
|
|||||||
"FILTER_PLACEHOLDER": "Filtrer les Logs",
|
"FILTER_PLACEHOLDER": "Filtrer les Logs",
|
||||||
"INVALID_DATE": "Date invalide.",
|
"INVALID_DATE": "Date invalide.",
|
||||||
"OF": "de",
|
"OF": "de",
|
||||||
"NOT_FOUND": "Nous n'avons trouvé aucun journal!"
|
"NOT_FOUND": "Nous n'avons trouvé aucun journal!",
|
||||||
|
"RESOURCE": "Resource",
|
||||||
|
"RESOURCE_TYPE": "Resource Type"
|
||||||
},
|
},
|
||||||
"REPLICATION": {
|
"REPLICATION": {
|
||||||
"YES": "Yes",
|
"YES": "Yes",
|
||||||
|
@ -454,7 +454,9 @@
|
|||||||
"FILTER_PLACEHOLDER": "Filtrar Logs",
|
"FILTER_PLACEHOLDER": "Filtrar Logs",
|
||||||
"INVALID_DATE": "Data inválida.",
|
"INVALID_DATE": "Data inválida.",
|
||||||
"OF": "de",
|
"OF": "de",
|
||||||
"NOT_FOUND": "Nós não encontramos nenhum registro!"
|
"NOT_FOUND": "Nós não encontramos nenhum registro!",
|
||||||
|
"RESOURCE": "Resource",
|
||||||
|
"RESOURCE_TYPE": "Resource Type"
|
||||||
},
|
},
|
||||||
"REPLICATION": {
|
"REPLICATION": {
|
||||||
"YES": "Yes",
|
"YES": "Yes",
|
||||||
|
@ -455,7 +455,10 @@
|
|||||||
"ITEMS": "adet",
|
"ITEMS": "adet",
|
||||||
"FILTER_PLACEHOLDER": "Günlükleri Filtrele",
|
"FILTER_PLACEHOLDER": "Günlükleri Filtrele",
|
||||||
"INVALID_DATE": "Geçersiz tarih.",
|
"INVALID_DATE": "Geçersiz tarih.",
|
||||||
"OF": "of"
|
"OF": "of",
|
||||||
|
"NOT_FOUND": "We couldn't find any logs!",
|
||||||
|
"RESOURCE": "Resource",
|
||||||
|
"RESOURCE_TYPE": "Resource Type"
|
||||||
},
|
},
|
||||||
"REPLICATION": {
|
"REPLICATION": {
|
||||||
"YES": "Evet",
|
"YES": "Evet",
|
||||||
|
@ -455,7 +455,9 @@
|
|||||||
"FILTER_PLACEHOLDER": "过滤日志",
|
"FILTER_PLACEHOLDER": "过滤日志",
|
||||||
"INVALID_DATE": "无效日期。",
|
"INVALID_DATE": "无效日期。",
|
||||||
"OF": "共计",
|
"OF": "共计",
|
||||||
"NOT_FOUND": "未发现任何日志!"
|
"NOT_FOUND": "未发现任何日志!",
|
||||||
|
"RESOURCE": "资源",
|
||||||
|
"RESOURCE_TYPE": "资源类型"
|
||||||
},
|
},
|
||||||
"REPLICATION": {
|
"REPLICATION": {
|
||||||
"YES": "是",
|
"YES": "是",
|
||||||
|
@ -6,8 +6,8 @@
|
|||||||
<div class="select filter-tag clr-select-wrapper" [hidden]="!isOpenFilterTag">
|
<div class="select filter-tag clr-select-wrapper" [hidden]="!isOpenFilterTag">
|
||||||
<select id="selectKey" (change)="selectFilterKey($event)">
|
<select id="selectKey" (change)="selectFilterKey($event)">
|
||||||
<option value="username">{{"AUDIT_LOG.USERNAME" | translate | lowercase}}</option>
|
<option value="username">{{"AUDIT_LOG.USERNAME" | translate | lowercase}}</option>
|
||||||
<option value="repository">{{"CONFIG.REPOSITORY" | translate | lowercase}}</option>
|
<option value="resource">{{"AUDIT_LOG.RESOURCE" | translate | lowercase}}</option>
|
||||||
<option value="tag">{{"REPOSITORY.TAG" | translate | lowercase}}</option>
|
<option value="resourceType">{{"AUDIT_LOG.RESOURCE_TYPE" | translate | lowercase}}</option>
|
||||||
<option value="operation">{{"AUDIT_LOG.OPERATION" | translate | lowercase}}</option>
|
<option value="operation">{{"AUDIT_LOG.OPERATION" | translate | lowercase}}</option>
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
@ -20,17 +20,17 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<clr-datagrid (clrDgRefresh)="load($event)" [clrDgLoading]="loading">
|
<clr-datagrid (clrDgRefresh)="load()" [clrDgLoading]="loading">
|
||||||
<clr-dg-column>{{'AUDIT_LOG.USERNAME' | translate}}</clr-dg-column>
|
<clr-dg-column>{{'AUDIT_LOG.USERNAME' | translate}}</clr-dg-column>
|
||||||
<clr-dg-column>{{'AUDIT_LOG.REPOSITORY_NAME' | translate}}</clr-dg-column>
|
<clr-dg-column>{{'AUDIT_LOG.RESOURCE' | translate}}</clr-dg-column>
|
||||||
<clr-dg-column>{{'AUDIT_LOG.TAGS' | translate}}</clr-dg-column>
|
<clr-dg-column>{{'AUDIT_LOG.RESOURCE_TYPE' | translate}}</clr-dg-column>
|
||||||
<clr-dg-column>{{'AUDIT_LOG.OPERATION' | translate}}</clr-dg-column>
|
<clr-dg-column>{{'AUDIT_LOG.OPERATION' | translate}}</clr-dg-column>
|
||||||
<clr-dg-column>{{'AUDIT_LOG.TIMESTAMP' | translate}}</clr-dg-column>
|
<clr-dg-column>{{'AUDIT_LOG.TIMESTAMP' | translate}}</clr-dg-column>
|
||||||
<clr-dg-placeholder>{{ 'AUDIT_LOG.NOT_FOUND' | translate }}</clr-dg-placeholder>
|
<clr-dg-placeholder>{{ 'AUDIT_LOG.NOT_FOUND' | translate }}</clr-dg-placeholder>
|
||||||
<clr-dg-row *ngFor="let l of recentLogs">
|
<clr-dg-row *ngFor="let l of recentLogs">
|
||||||
<clr-dg-cell>{{l.username}}</clr-dg-cell>
|
<clr-dg-cell>{{l.username}}</clr-dg-cell>
|
||||||
<clr-dg-cell>{{l.repo_name}}</clr-dg-cell>
|
<clr-dg-cell>{{l.resource}}</clr-dg-cell>
|
||||||
<clr-dg-cell>{{l.repo_tag}}</clr-dg-cell>
|
<clr-dg-cell>{{l.resource_type}}</clr-dg-cell>
|
||||||
<clr-dg-cell>{{l.operation}}</clr-dg-cell>
|
<clr-dg-cell>{{l.operation}}</clr-dg-cell>
|
||||||
<clr-dg-cell>{{l.op_time | date: 'short'}}</clr-dg-cell>
|
<clr-dg-cell>{{l.op_time | date: 'short'}}</clr-dg-cell>
|
||||||
</clr-dg-row>
|
</clr-dg-row>
|
||||||
|
@ -1,41 +1,79 @@
|
|||||||
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
|
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
|
||||||
import { DebugElement } from '@angular/core';
|
import { DebugElement } from '@angular/core';
|
||||||
import { AccessLog, AccessLogItem, RequestQueryParams } from '../../services';
|
|
||||||
|
|
||||||
import { RecentLogComponent } from './recent-log.component';
|
import { RecentLogComponent } from './recent-log.component';
|
||||||
import { AccessLogService, AccessLogDefaultService } from '../../services/access-log.service';
|
|
||||||
import { SERVICE_CONFIG, IServiceConfig } from '../../entities/service.config';
|
import { SERVICE_CONFIG, IServiceConfig } from '../../entities/service.config';
|
||||||
import { ErrorHandler } from '../../utils/error-handler';
|
import { ErrorHandler } from '../../utils/error-handler';
|
||||||
import { SharedModule } from '../../utils/shared/shared.module';
|
import { SharedModule } from '../../utils/shared/shared.module';
|
||||||
import { FilterComponent } from '../filter/filter.component';
|
import { FilterComponent } from '../filter/filter.component';
|
||||||
|
|
||||||
import { click, CURRENT_BASE_HREF } from '../../utils/utils';
|
import { click, CURRENT_BASE_HREF } from '../../utils/utils';
|
||||||
import { of } from 'rxjs';
|
import { of } from 'rxjs';
|
||||||
import { delay } from 'rxjs/operators';
|
import { AuditLog } from "../../../../ng-swagger-gen/models/audit-log";
|
||||||
|
import { AuditlogService } from "../../../../ng-swagger-gen/services/auditlog.service";
|
||||||
|
import { HttpHeaders, HttpResponse } from "@angular/common/http";
|
||||||
|
import ListAuditLogsParams = AuditlogService.ListAuditLogsParams;
|
||||||
|
import { delay } from "rxjs/operators";
|
||||||
|
|
||||||
describe('RecentLogComponent (inline template)', () => {
|
describe('RecentLogComponent (inline template)', () => {
|
||||||
let component: RecentLogComponent;
|
let component: RecentLogComponent;
|
||||||
let fixture: ComponentFixture<RecentLogComponent>;
|
let fixture: ComponentFixture<RecentLogComponent>;
|
||||||
let serviceConfig: IServiceConfig;
|
let serviceConfig: IServiceConfig;
|
||||||
let logService: AccessLogService;
|
let auditlogService: AuditlogService;
|
||||||
let spy: jasmine.Spy;
|
|
||||||
let mockItems: AccessLogItem[] = [];
|
|
||||||
let mockData: AccessLog = {
|
|
||||||
metadata: {
|
|
||||||
xTotalCount: 18
|
|
||||||
},
|
|
||||||
data: []
|
|
||||||
};
|
|
||||||
let mockData2: AccessLog = {
|
|
||||||
metadata: {
|
|
||||||
xTotalCount: 1
|
|
||||||
},
|
|
||||||
data: []
|
|
||||||
};
|
|
||||||
let testConfig: IServiceConfig = {
|
let testConfig: IServiceConfig = {
|
||||||
logBaseEndpoint: CURRENT_BASE_HREF + "/logs/testing"
|
logBaseEndpoint: CURRENT_BASE_HREF + "/logs/testing"
|
||||||
};
|
};
|
||||||
|
const fakedErrorHandler = {
|
||||||
|
error() {
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
const mockedAuditLogs: AuditLog [] = [];
|
||||||
|
for (let i = 0; i < 18; i++) {
|
||||||
|
let item: AuditLog = {
|
||||||
|
id: 23 + i,
|
||||||
|
resource: "myproject/demo" + i,
|
||||||
|
resource_type: "N/A",
|
||||||
|
operation: "create",
|
||||||
|
op_time: "2017-04-11T10:26:22Z",
|
||||||
|
username: "user91" + i
|
||||||
|
};
|
||||||
|
mockedAuditLogs.push(item);
|
||||||
|
}
|
||||||
|
const fakedAuditlogService = {
|
||||||
|
listAuditLogsResponse(params: ListAuditLogsParams) {
|
||||||
|
if (params && params.username) {
|
||||||
|
if (params.username === 'demo0') {
|
||||||
|
return of(new HttpResponse({
|
||||||
|
body: mockedAuditLogs.slice(0, 1),
|
||||||
|
headers: new HttpHeaders({
|
||||||
|
"x-total-count": "18"
|
||||||
|
})
|
||||||
|
})).pipe(delay(0));
|
||||||
|
}
|
||||||
|
return of(new HttpResponse({
|
||||||
|
body: mockedAuditLogs,
|
||||||
|
headers: new HttpHeaders({
|
||||||
|
"x-total-count": "18"
|
||||||
|
})
|
||||||
|
})).pipe(delay(0));
|
||||||
|
} else {
|
||||||
|
if (params.page === 1) {
|
||||||
|
return of(new HttpResponse({
|
||||||
|
body: mockedAuditLogs.slice(0, 15),
|
||||||
|
headers: new HttpHeaders({
|
||||||
|
"x-total-count": "18"
|
||||||
|
})
|
||||||
|
})).pipe(delay(0));
|
||||||
|
} else {
|
||||||
|
return of(new HttpResponse({
|
||||||
|
body: mockedAuditLogs.slice(15),
|
||||||
|
headers: new HttpHeaders({
|
||||||
|
"x-total-count": "18"
|
||||||
|
})
|
||||||
|
})).pipe(delay(0));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
beforeEach(async(() => {
|
beforeEach(async(() => {
|
||||||
TestBed.configureTestingModule({
|
TestBed.configureTestingModule({
|
||||||
imports: [
|
imports: [
|
||||||
@ -43,9 +81,9 @@ describe('RecentLogComponent (inline template)', () => {
|
|||||||
],
|
],
|
||||||
declarations: [FilterComponent, RecentLogComponent],
|
declarations: [FilterComponent, RecentLogComponent],
|
||||||
providers: [
|
providers: [
|
||||||
ErrorHandler,
|
{ provide: ErrorHandler, useValue: fakedErrorHandler },
|
||||||
|
{ provide: AuditlogService, useValue: fakedAuditlogService },
|
||||||
{ provide: SERVICE_CONFIG, useValue: testConfig },
|
{ provide: SERVICE_CONFIG, useValue: testConfig },
|
||||||
{ provide: AccessLogService, useClass: AccessLogDefaultService }
|
|
||||||
]
|
]
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -55,38 +93,7 @@ describe('RecentLogComponent (inline template)', () => {
|
|||||||
fixture = TestBed.createComponent(RecentLogComponent);
|
fixture = TestBed.createComponent(RecentLogComponent);
|
||||||
component = fixture.componentInstance;
|
component = fixture.componentInstance;
|
||||||
serviceConfig = TestBed.get(SERVICE_CONFIG);
|
serviceConfig = TestBed.get(SERVICE_CONFIG);
|
||||||
logService = fixture.debugElement.injector.get(AccessLogService);
|
auditlogService = fixture.debugElement.injector.get(AuditlogService);
|
||||||
// Mock data
|
|
||||||
for (let i = 0; i < 18; i++) {
|
|
||||||
let item: AccessLogItem = {
|
|
||||||
log_id: 23 + i,
|
|
||||||
user_id: 45 + i,
|
|
||||||
project_id: 11 + i,
|
|
||||||
repo_name: "myproject/demo" + i,
|
|
||||||
repo_tag: "N/A",
|
|
||||||
operation: "create",
|
|
||||||
op_time: "2017-04-11T10:26:22Z",
|
|
||||||
username: "user91" + i
|
|
||||||
};
|
|
||||||
mockItems.push(item);
|
|
||||||
}
|
|
||||||
mockData2.data = mockItems.slice(0, 1);
|
|
||||||
mockData.data = mockItems;
|
|
||||||
|
|
||||||
spy = spyOn(logService, 'getRecentLogs')
|
|
||||||
.and.callFake(function (params: RequestQueryParams) {
|
|
||||||
if (params && params.get('username')) {
|
|
||||||
return of(mockData2);
|
|
||||||
} else {
|
|
||||||
if (params.get('page') === '1') {
|
|
||||||
mockData.data = mockItems.slice(0, 15);
|
|
||||||
} else {
|
|
||||||
mockData.data = mockItems.slice(15, 18);
|
|
||||||
}
|
|
||||||
return of(mockData).pipe(delay(0));
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
fixture.detectChanges();
|
fixture.detectChanges();
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -100,15 +107,11 @@ describe('RecentLogComponent (inline template)', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('should get data from AccessLogService', async(() => {
|
it('should get data from AccessLogService', async(() => {
|
||||||
expect(logService).toBeTruthy();
|
expect(auditlogService).toBeTruthy();
|
||||||
expect(spy.calls.any()).toBe(true, 'getRecentLogs called');
|
|
||||||
|
|
||||||
fixture.detectChanges();
|
fixture.detectChanges();
|
||||||
|
|
||||||
fixture.whenStable().then(() => { // wait for async getRecentLogs
|
fixture.whenStable().then(() => { // wait for async getRecentLogs
|
||||||
fixture.detectChanges();
|
fixture.detectChanges();
|
||||||
expect(component.recentLogs).toBeTruthy();
|
expect(component.recentLogs).toBeTruthy();
|
||||||
expect(component.logsCache).toBeTruthy();
|
|
||||||
expect(component.recentLogs.length).toEqual(15);
|
expect(component.recentLogs.length).toEqual(15);
|
||||||
});
|
});
|
||||||
}));
|
}));
|
||||||
@ -125,28 +128,16 @@ describe('RecentLogComponent (inline template)', () => {
|
|||||||
expect(el.textContent.trim()).toEqual('user910');
|
expect(el.textContent.trim()).toEqual('user910');
|
||||||
});
|
});
|
||||||
}));
|
}));
|
||||||
|
it('should support pagination', async () => {
|
||||||
// Will fail after upgrade to angular 6. todo: need to fix it.
|
fixture.autoDetectChanges(true);
|
||||||
xit('should support pagination', () => {
|
await fixture.whenStable();
|
||||||
|
let el: HTMLButtonElement = fixture.nativeElement.querySelector('.pagination-next');
|
||||||
|
expect(el).toBeTruthy();
|
||||||
|
el.click();
|
||||||
fixture.detectChanges();
|
fixture.detectChanges();
|
||||||
|
await fixture.whenStable();
|
||||||
fixture.whenStable().then(() => {
|
expect(component.currentPage).toEqual(2);
|
||||||
fixture.detectChanges();
|
expect(component.recentLogs.length).toEqual(3);
|
||||||
|
|
||||||
let el: HTMLButtonElement = fixture.nativeElement.querySelector('.pagination-next');
|
|
||||||
expect(el).toBeTruthy();
|
|
||||||
el.click();
|
|
||||||
jasmine.clock().tick(100);
|
|
||||||
fixture.detectChanges();
|
|
||||||
|
|
||||||
fixture.whenStable().then(() => {
|
|
||||||
fixture.detectChanges();
|
|
||||||
|
|
||||||
let els: HTMLElement[] = fixture.nativeElement.querySelectorAll('.datagrid-row');
|
|
||||||
expect(els).toBeTruthy();
|
|
||||||
expect(els.length).toEqual(4);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should support filtering list by keywords', async(() => {
|
it('should support filtering list by keywords', async(() => {
|
||||||
@ -154,22 +145,17 @@ describe('RecentLogComponent (inline template)', () => {
|
|||||||
let el: HTMLElement = fixture.nativeElement.querySelector('.search-btn');
|
let el: HTMLElement = fixture.nativeElement.querySelector('.search-btn');
|
||||||
expect(el).toBeTruthy("Not found search icon");
|
expect(el).toBeTruthy("Not found search icon");
|
||||||
click(el);
|
click(el);
|
||||||
|
|
||||||
fixture.detectChanges();
|
fixture.detectChanges();
|
||||||
let el2: HTMLInputElement = fixture.nativeElement.querySelector('input');
|
let el2: HTMLInputElement = fixture.nativeElement.querySelector('input');
|
||||||
expect(el2).toBeTruthy("Not found input");
|
expect(el2).toBeTruthy("Not found input");
|
||||||
|
|
||||||
fixture.detectChanges();
|
fixture.detectChanges();
|
||||||
fixture.whenStable().then(() => {
|
fixture.whenStable().then(() => {
|
||||||
fixture.detectChanges();
|
fixture.detectChanges();
|
||||||
|
|
||||||
component.doFilter("demo0");
|
component.doFilter("demo0");
|
||||||
|
|
||||||
fixture.detectChanges();
|
fixture.detectChanges();
|
||||||
fixture.whenStable().then(() => {
|
fixture.whenStable().then(() => {
|
||||||
fixture.detectChanges();
|
fixture.detectChanges();
|
||||||
expect(component.recentLogs).toBeTruthy();
|
expect(component.recentLogs).toBeTruthy();
|
||||||
expect(component.logsCache).toBeTruthy();
|
|
||||||
expect(component.recentLogs.length).toEqual(1);
|
expect(component.recentLogs.length).toEqual(1);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@ -177,32 +163,23 @@ describe('RecentLogComponent (inline template)', () => {
|
|||||||
|
|
||||||
it('should support refreshing', async(() => {
|
it('should support refreshing', async(() => {
|
||||||
fixture.detectChanges();
|
fixture.detectChanges();
|
||||||
|
|
||||||
fixture.whenStable().then(() => {
|
fixture.whenStable().then(() => {
|
||||||
fixture.detectChanges();
|
fixture.detectChanges();
|
||||||
|
|
||||||
let el: HTMLButtonElement = fixture.nativeElement.querySelector('.pagination-next');
|
let el: HTMLButtonElement = fixture.nativeElement.querySelector('.pagination-next');
|
||||||
expect(el).toBeTruthy();
|
expect(el).toBeTruthy();
|
||||||
el.click();
|
el.click();
|
||||||
|
|
||||||
fixture.detectChanges();
|
fixture.detectChanges();
|
||||||
|
|
||||||
fixture.whenStable().then(() => {
|
fixture.whenStable().then(() => {
|
||||||
fixture.detectChanges();
|
fixture.detectChanges();
|
||||||
expect(component.recentLogs).toBeTruthy();
|
expect(component.recentLogs).toBeTruthy();
|
||||||
expect(component.logsCache).toBeTruthy();
|
|
||||||
expect(component.recentLogs.length).toEqual(3);
|
expect(component.recentLogs.length).toEqual(3);
|
||||||
|
|
||||||
let refreshEl: HTMLElement = fixture.nativeElement.querySelector(".refresh-btn");
|
let refreshEl: HTMLElement = fixture.nativeElement.querySelector(".refresh-btn");
|
||||||
expect(refreshEl).toBeTruthy("Not found refresh button");
|
expect(refreshEl).toBeTruthy("Not found refresh button");
|
||||||
refreshEl.click();
|
refreshEl.click();
|
||||||
|
|
||||||
fixture.detectChanges();
|
fixture.detectChanges();
|
||||||
|
|
||||||
fixture.whenStable().then(() => {
|
fixture.whenStable().then(() => {
|
||||||
fixture.detectChanges();
|
fixture.detectChanges();
|
||||||
expect(component.recentLogs).toBeTruthy();
|
expect(component.recentLogs).toBeTruthy();
|
||||||
expect(component.logsCache).toBeTruthy();
|
|
||||||
expect(component.recentLogs.length).toEqual(15);
|
expect(component.recentLogs.length).toEqual(15);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -12,20 +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 { Component, OnInit, Input } from '@angular/core';
|
import { Component, OnInit, Input } from '@angular/core';
|
||||||
import { Comparator, State } from '../../services/interface';
|
|
||||||
|
|
||||||
import {
|
|
||||||
AccessLogService,
|
|
||||||
AccessLog,
|
|
||||||
AccessLogItem,
|
|
||||||
RequestQueryParams
|
|
||||||
} from '../../services';
|
|
||||||
import { ErrorHandler } from '../../utils/error-handler';
|
import { ErrorHandler } from '../../utils/error-handler';
|
||||||
import { CustomComparator } from '../../utils/utils';
|
|
||||||
import {
|
|
||||||
DEFAULT_PAGE_SIZE,
|
|
||||||
} from '../../utils/utils';
|
|
||||||
import { finalize } from "rxjs/operators";
|
import { finalize } from "rxjs/operators";
|
||||||
|
import { AuditlogService } from "../../../../ng-swagger-gen/services/auditlog.service";
|
||||||
|
import { AuditLog } from "../../../../ng-swagger-gen/models/audit-log";
|
||||||
|
import ListAuditLogsParams = AuditlogService.ListAuditLogsParams;
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'hbr-log',
|
selector: 'hbr-log',
|
||||||
@ -34,8 +25,7 @@ import { finalize } from "rxjs/operators";
|
|||||||
})
|
})
|
||||||
|
|
||||||
export class RecentLogComponent implements OnInit {
|
export class RecentLogComponent implements OnInit {
|
||||||
recentLogs: AccessLogItem[] = [];
|
recentLogs: AuditLog[] = [];
|
||||||
logsCache: AccessLog;
|
|
||||||
loading: boolean = true;
|
loading: boolean = true;
|
||||||
currentTerm: string;
|
currentTerm: string;
|
||||||
defaultFilter = "username";
|
defaultFilter = "username";
|
||||||
@ -43,17 +33,13 @@ export class RecentLogComponent implements OnInit {
|
|||||||
@Input() withTitle: boolean = false;
|
@Input() withTitle: boolean = false;
|
||||||
pageSize: number = 15;
|
pageSize: number = 15;
|
||||||
currentPage: number = 1; // Double bound to pagination component
|
currentPage: number = 1; // Double bound to pagination component
|
||||||
|
totalCount: number = 0;
|
||||||
constructor(
|
constructor(
|
||||||
private logService: AccessLogService,
|
private logService: AuditlogService,
|
||||||
private errorHandler: ErrorHandler) { }
|
private errorHandler: ErrorHandler) { }
|
||||||
|
|
||||||
ngOnInit(): void {
|
ngOnInit(): void {
|
||||||
}
|
}
|
||||||
|
|
||||||
public get totalCount(): number {
|
|
||||||
return this.logsCache && this.logsCache.metadata ? this.logsCache.metadata.xTotalCount : 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
public get inProgress(): boolean {
|
public get inProgress(): boolean {
|
||||||
return this.loading;
|
return this.loading;
|
||||||
}
|
}
|
||||||
@ -66,7 +52,8 @@ export class RecentLogComponent implements OnInit {
|
|||||||
this.currentTerm = terms.trim();
|
this.currentTerm = terms.trim();
|
||||||
this.loading = true;
|
this.loading = true;
|
||||||
this.currentPage = 1;
|
this.currentPage = 1;
|
||||||
this.load({page: {}});
|
this.totalCount = 0;
|
||||||
|
this.load();
|
||||||
}
|
}
|
||||||
|
|
||||||
public refresh(): void {
|
public refresh(): void {
|
||||||
@ -74,11 +61,7 @@ export class RecentLogComponent implements OnInit {
|
|||||||
}
|
}
|
||||||
|
|
||||||
openFilter(isOpen: boolean): void {
|
openFilter(isOpen: boolean): void {
|
||||||
if (isOpen) {
|
this.isOpenFilterTag = isOpen;
|
||||||
this.isOpenFilterTag = true;
|
|
||||||
} else {
|
|
||||||
this.isOpenFilterTag = false;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
selectFilterKey($event: any): void {
|
selectFilterKey($event: any): void {
|
||||||
@ -86,21 +69,27 @@ export class RecentLogComponent implements OnInit {
|
|||||||
this.doFilter(this.currentTerm);
|
this.doFilter(this.currentTerm);
|
||||||
}
|
}
|
||||||
|
|
||||||
load(state) {
|
load() {
|
||||||
if (!state || !state.page) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
// Keep it for future filter
|
// Keep it for future filter
|
||||||
// this.currentState = state;
|
// this.currentState = state;
|
||||||
let params: RequestQueryParams = new RequestQueryParams().set("page", '' + this.currentPage).set("page_size", '' + this.pageSize);
|
const params: ListAuditLogsParams = {
|
||||||
|
page: this.currentPage,
|
||||||
|
pageSize: this.pageSize
|
||||||
|
};
|
||||||
if (this.currentTerm && this.currentTerm !== "") {
|
if (this.currentTerm && this.currentTerm !== "") {
|
||||||
params = params.set(this.defaultFilter, this.currentTerm);
|
params[this.defaultFilter] = this.currentTerm;
|
||||||
}
|
}
|
||||||
this.loading = true;
|
this.loading = true;
|
||||||
this.logService.getRecentLogs(params).pipe(finalize(() => (this.loading = false)))
|
this.logService.listAuditLogsResponse(params).pipe(finalize(() => (this.loading = false)))
|
||||||
.subscribe(response => {
|
.subscribe(response => {
|
||||||
this.logsCache = response; // Keep the data
|
// Get total count
|
||||||
this.recentLogs = response.data;
|
if (response.headers) {
|
||||||
|
let xHeader: string = response.headers.get("x-total-count");
|
||||||
|
if (xHeader) {
|
||||||
|
this.totalCount = parseInt(xHeader, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
this.recentLogs = response.body as AuditLog[];
|
||||||
}, error => {
|
}, error => {
|
||||||
this.errorHandler.error(error);
|
this.errorHandler.error(error);
|
||||||
});
|
});
|
||||||
|
@ -13,8 +13,8 @@
|
|||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
|
|
||||||
import { Injectable } from '@angular/core';
|
import { Injectable } from '@angular/core';
|
||||||
import { Observable, forkJoin, of, throwError as observableThrowError } from "rxjs";
|
import { Observable, forkJoin} from "rxjs";
|
||||||
import { map, tap, publishReplay, refCount } from "rxjs/operators";
|
import { map, share } from "rxjs/operators";
|
||||||
import { HttpClient } from '@angular/common/http';
|
import { HttpClient } from '@angular/common/http';
|
||||||
import { CacheObservable } from "../utils/cache-util";
|
import { CacheObservable } from "../utils/cache-util";
|
||||||
import { CURRENT_BASE_HREF } from "../utils/utils";
|
import { CURRENT_BASE_HREF } from "../utils/utils";
|
||||||
@ -46,6 +46,8 @@ export abstract class UserPermissionService {
|
|||||||
// @dynamic
|
// @dynamic
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class UserPermissionDefaultService extends UserPermissionService {
|
export class UserPermissionDefaultService extends UserPermissionService {
|
||||||
|
// to prevent duplicate permissions HTTP requests
|
||||||
|
private _sharedPermissionObservableMap: {[key: string]: Observable<Array<Permission>>} = {};
|
||||||
constructor(
|
constructor(
|
||||||
private http: HttpClient,
|
private http: HttpClient,
|
||||||
) {
|
) {
|
||||||
@ -55,7 +57,12 @@ export class UserPermissionDefaultService extends UserPermissionService {
|
|||||||
@CacheObservable({ maxAge: 1000 * 60 })
|
@CacheObservable({ maxAge: 1000 * 60 })
|
||||||
private getPermissions(scope: string, relative?: boolean): Observable<Array<Permission>> {
|
private getPermissions(scope: string, relative?: boolean): Observable<Array<Permission>> {
|
||||||
const url = `${ CURRENT_BASE_HREF }/users/current/permissions?scope=${scope}&relative=${relative ? 'true' : 'false'}`;
|
const url = `${ CURRENT_BASE_HREF }/users/current/permissions?scope=${scope}&relative=${relative ? 'true' : 'false'}`;
|
||||||
return this.http.get<Array<Permission>>(url);
|
if (this._sharedPermissionObservableMap[url]) {
|
||||||
|
return this._sharedPermissionObservableMap[url];
|
||||||
|
} else {
|
||||||
|
this._sharedPermissionObservableMap[url] = this.http.get<Array<Permission>>(url).pipe(share());
|
||||||
|
return this._sharedPermissionObservableMap[url];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private hasPermission(permission: Permission, scope: string, relative?: boolean): Observable<boolean> {
|
private hasPermission(permission: Permission, scope: string, relative?: boolean): Observable<boolean> {
|
||||||
|
Loading…
Reference in New Issue
Block a user