Merge pull request #10292 from AllForNothing/repo-search

Improve repo datagrid search function
This commit is contained in:
Will Sun 2019-12-20 11:07:51 +08:00 committed by GitHub
commit 1bcbb25e86
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 104 additions and 122 deletions

View File

@ -8,7 +8,7 @@
{{'CONFIG.REGISTRY_CERTIFICATE' | translate | uppercase}} {{'CONFIG.REGISTRY_CERTIFICATE' | translate | uppercase}}
</a> </a>
<hbr-push-image-button class="push-image-button" *ngIf="hasCreateRepositoryPermission" [registryUrl]="registryUrl" [projectName]="projectName"></hbr-push-image-button> <hbr-push-image-button class="push-image-button" *ngIf="hasCreateRepositoryPermission" [registryUrl]="registryUrl" [projectName]="projectName"></hbr-push-image-button>
<hbr-filter [withDivider]="true" filterPlaceholder="{{'REPOSITORY.FILTER_FOR_REPOSITORIES' | translate}}" (filterEvt)="doSearchRepoNames($event)" [currentValue]="lastFilteredRepoName"></hbr-filter> <hbr-filter [withDivider]="true" filterPlaceholder="{{'REPOSITORY.FILTER_FOR_REPOSITORIES' | translate}}" [currentValue]="lastFilteredRepoName"></hbr-filter>
<span class="card-btn" (click)="showCard(true)" (mouseenter) ="mouseEnter('card') " (mouseleave) ="mouseLeave('card')"> <span class="card-btn" (click)="showCard(true)" (mouseenter) ="mouseEnter('card') " (mouseleave) ="mouseLeave('card')">
<clr-icon [ngClass]="{'is-highlight': isCardView || isHovering('card') }" shape="view-cards"></clr-icon> <clr-icon [ngClass]="{'is-highlight': isCardView || isHovering('card') }" shape="view-cards"></clr-icon>
</span> </span>
@ -23,7 +23,7 @@
</div> </div>
<div class="row"> <div class="row">
<div *ngIf="!isCardView" class="col-lg-12 col-md-12 col-sm-12 col-xs-12"> <div *ngIf="!isCardView" class="col-lg-12 col-md-12 col-sm-12 col-xs-12">
<clr-datagrid (clrDgRefresh)="clrLoad($event)" [clrDgLoading]="loading" [(clrDgSelected)]="selectedRow" (clrDgSelectedChange)="selectedChange()"> <clr-datagrid (clrDgRefresh)="clrLoad($event)" [clrDgLoading]="loading" [(clrDgSelected)]="selectedRow">
<clr-dg-action-bar> <clr-dg-action-bar>
<button *ngIf="withAdmiral" type="button" class="btn btn-secondary" (click)="provisionItemEvent($event, selectedRow[0])" [disabled]="!(selectedRow.length===1 && hasProjectAdminRole)"><clr-icon shape="times" size="16"></clr-icon>&nbsp;{{'REPOSITORY.DEPLOY' | translate}}</button> <button *ngIf="withAdmiral" type="button" class="btn btn-secondary" (click)="provisionItemEvent($event, selectedRow[0])" [disabled]="!(selectedRow.length===1 && hasProjectAdminRole)"><clr-icon shape="times" size="16"></clr-icon>&nbsp;{{'REPOSITORY.DEPLOY' | translate}}</button>
<button *ngIf="withAdmiral" type="button" class="btn btn-secondary" (click)="itemAddInfoEvent($event, selectedRow[0])" [disabled]="!(selectedRow.length===1 && hasProjectAdminRole)"><clr-icon shape="times" size="16"></clr-icon>&nbsp;{{'REPOSITORY.ADDITIONAL_INFO' | translate}}</button> <button *ngIf="withAdmiral" type="button" class="btn btn-secondary" (click)="itemAddInfoEvent($event, selectedRow[0])" [disabled]="!(selectedRow.length===1 && hasProjectAdminRole)"><clr-icon shape="times" size="16"></clr-icon>&nbsp;{{'REPOSITORY.ADDITIONAL_INFO' | translate}}</button>
@ -39,7 +39,7 @@
<clr-dg-cell>{{r.pull_count}}</clr-dg-cell> <clr-dg-cell>{{r.pull_count}}</clr-dg-cell>
</clr-dg-row> </clr-dg-row>
<clr-dg-footer> <clr-dg-footer>
<span *ngIf="pagination.totalItems">{{pagination.firstItem + 1}} - {{pagination.lastItem + 1}} {{'REPOSITORY.OF' | translate}}</span> <span *ngIf="totalCount">{{pagination.firstItem + 1}} - {{pagination.lastItem + 1}} {{'REPOSITORY.OF' | translate}}</span>
{{pagination.totalItems}} {{'REPOSITORY.ITEMS' | translate}} {{pagination.totalItems}} {{'REPOSITORY.ITEMS' | translate}}
<clr-dg-pagination #pagination [(clrDgPage)]="currentPage" [clrDgPageSize]="pageSize" [clrDgTotalItems]="totalCount"></clr-dg-pagination> <clr-dg-pagination #pagination [(clrDgPage)]="currentPage" [clrDgPageSize]="pageSize" [clrDgTotalItems]="totalCount"></clr-dg-pagination>
</clr-dg-footer> </clr-dg-footer>

View File

@ -1,40 +1,31 @@
import { ComponentFixture, TestBed, async } from '@angular/core/testing'; import { ComponentFixture, TestBed, async } from '@angular/core/testing';
import { By } from '@angular/platform-browser'; import { By } from '@angular/platform-browser';
import { DebugElement } from '@angular/core'; import { DebugElement } from '@angular/core';
import { RouterTestingModule } from '@angular/router/testing'; import { RouterTestingModule } from '@angular/router/testing';
import { SharedModule } from '../../utils/shared/shared.module'; import { SharedModule } from '../../utils/shared/shared.module';
import { ConfirmationDialogComponent } from '../confirmation-dialog/confirmation-dialog.component';
import { ImageNameInputComponent } from "../image-name-input/image-name-input.component";
import { RepositoryGridviewComponent } from './repository-gridview.component'; import { RepositoryGridviewComponent } from './repository-gridview.component';
import { TagComponent } from '../tag/tag.component';
import { FilterComponent } from '../filter/filter.component';
import { ErrorHandler } from '../../utils/error-handler/error-handler'; import { ErrorHandler } from '../../utils/error-handler/error-handler';
import { Repository, RepositoryItem, SystemInfo } from '../../services/interface'; import { Repository, RepositoryItem, SystemInfo } from '../../services/interface';
import { SERVICE_CONFIG, IServiceConfig } from '../../entities/service.config'; import { SERVICE_CONFIG, IServiceConfig } from '../../entities/service.config';
import { RepositoryService, RepositoryDefaultService } from '../../services/repository.service'; import { RepositoryService } from '../../services/repository.service';
import { TagService, TagDefaultService } from '../../services/tag.service'; import { TagService, TagDefaultService } from '../../services/tag.service';
import { SystemInfoService, SystemInfoDefaultService } from '../../services/system-info.service'; import { SystemInfoService } from '../../services/system-info.service';
import { LabelPieceComponent } from "../label-piece/label-piece.component";
import { OperationService } from "../operation/operation.service"; import { OperationService } from "../operation/operation.service";
import { ProjectDefaultService, ProjectService, RetagDefaultService, RetagService } from "../../services"; import {
import { UserPermissionService, UserPermissionDefaultService } from "../../services/permission.service"; ProjectDefaultService,
import { USERSTATICPERMISSION } from "../../services/permission-static"; ProjectService,
RequestQueryParams,
RetagDefaultService,
RetagService
} from "../../services";
import { UserPermissionService } from "../../services/permission.service";
import { of } from "rxjs"; import { of } from "rxjs";
import { HarborLibraryModule } from "../../harbor-library.module"; import { HarborLibraryModule } from "../../harbor-library.module";
import { delay } from 'rxjs/operators';
describe('RepositoryComponentGridview (inline template)', () => { describe('RepositoryComponentGridview (inline template)', () => {
let compRepo: RepositoryGridviewComponent; let compRepo: RepositoryGridviewComponent;
let fixtureRepo: ComponentFixture<RepositoryGridviewComponent>; let fixtureRepo: ComponentFixture<RepositoryGridviewComponent>;
let repositoryService: RepositoryService;
let systemInfoService: SystemInfoService;
let userPermissionService: UserPermissionService;
let spyRepos: jasmine.Spy;
let spySystemInfo: jasmine.Spy;
let mockSystemInfo: SystemInfo = { let mockSystemInfo: SystemInfo = {
"with_notary": true, "with_notary": true,
"with_admiral": false, "with_admiral": false,
@ -46,7 +37,6 @@ describe('RepositoryComponentGridview (inline template)', () => {
"has_ca_root": false, "has_ca_root": false,
"harbor_version": "v1.1.1-rc1-160-g565110d" "harbor_version": "v1.1.1-rc1-160-g565110d"
}; };
let mockRepoData: RepositoryItem[] = [ let mockRepoData: RepositoryItem[] = [
{ {
"id": 1, "id": 1,
@ -87,28 +77,34 @@ describe('RepositoryComponentGridview (inline template)', () => {
metadata: { xTotalCount: 2 }, metadata: { xTotalCount: 2 },
data: mockRepoNginxData data: mockRepoNginxData
}; };
let mockHasCreateRepositoryPermission: boolean = true;
let mockHasDeleteRepositoryPermission: boolean = true;
// let mockTagData: Tag[] = [
// {
// "digest": "sha256:e5c82328a509aeb7c18c1d7fb36633dc638fcf433f651bdcda59c1cc04d3ee55",
// "name": "1.11.5",
// "size": "2049",
// "architecture": "amd64",
// "os": "linux",
// "docker_version": "1.12.3",
// "author": "NGINX Docker Maintainers \"docker-maint@nginx.com\"",
// "created": new Date("2016-11-08T22:41:15.912313785Z"),
// "signature": null,
// "labels": []
// }
// ];
let config: IServiceConfig = { let config: IServiceConfig = {
repositoryBaseEndpoint: '/api/repository/testing', repositoryBaseEndpoint: '/api/repository/testing',
systemInfoEndpoint: '/api/systeminfo/testing', systemInfoEndpoint: '/api/systeminfo/testing',
targetBaseEndpoint: '/api/tag/testing' targetBaseEndpoint: '/api/tag/testing'
}; };
const fakedErrorHandler = {
error() {
return undefined;
}
};
const fakedSystemInfoService = {
getSystemInfo() {
return of(mockSystemInfo);
}
};
const fakedRepositoryService = {
getRepositories(projectId: number, name: string, param?: RequestQueryParams) {
if (name === 'nginx') {
return of(mockNginxRepo);
}
return of(mockRepo).pipe(delay(0));
}
};
const fakedUserPermissionService = {
getPermission() {
return of(true);
}
};
beforeEach(async(() => { beforeEach(async(() => {
TestBed.configureTestingModule({ TestBed.configureTestingModule({
@ -118,15 +114,15 @@ describe('RepositoryComponentGridview (inline template)', () => {
HarborLibraryModule HarborLibraryModule
], ],
providers: [ providers: [
ErrorHandler, { provide: ErrorHandler, useValue: fakedErrorHandler },
{ provide: SERVICE_CONFIG, useValue: config }, { provide: SERVICE_CONFIG, useValue: config },
{ provide: RepositoryService, useClass: RepositoryDefaultService }, { provide: RepositoryService, useValue: fakedRepositoryService },
{ provide: TagService, useClass: TagDefaultService }, { provide: TagService, useClass: TagDefaultService },
{ provide: ProjectService, useClass: ProjectDefaultService }, { provide: ProjectService, useClass: ProjectDefaultService },
{ provide: RetagService, useClass: RetagDefaultService }, { provide: RetagService, useClass: RetagDefaultService },
{ provide: SystemInfoService, useClass: SystemInfoDefaultService }, { provide: SystemInfoService, useValue: fakedSystemInfoService },
{ provide: UserPermissionService, useClass: UserPermissionDefaultService }, { provide: UserPermissionService, useValue: fakedUserPermissionService },
{ provide: OperationService } { provide: OperationService },
] ]
}); });
})); }));
@ -137,34 +133,14 @@ describe('RepositoryComponentGridview (inline template)', () => {
compRepo.projectId = 1; compRepo.projectId = 1;
compRepo.mode = ''; compRepo.mode = '';
compRepo.hasProjectAdminRole = true; compRepo.hasProjectAdminRole = true;
compRepo.isCardView = false;
repositoryService = fixtureRepo.debugElement.injector.get(RepositoryService);
systemInfoService = fixtureRepo.debugElement.injector.get(SystemInfoService);
spySystemInfo = spyOn(systemInfoService, 'getSystemInfo').and.returnValues(of(mockSystemInfo));
spyRepos = spyOn(repositoryService, 'getRepositories')
.and.callFake(function (projectId: number, name: string) {
if (name === 'nginx') {
return of(mockNginxRepo);
}
return of(mockRepo);
});
userPermissionService = fixtureRepo.debugElement.injector.get(UserPermissionService);
spyOn(userPermissionService, "getPermission")
.withArgs(compRepo.projectId,
USERSTATICPERMISSION.REPOSITORY.KEY, USERSTATICPERMISSION.REPOSITORY.VALUE.CREATE)
.and.returnValue(of(mockHasCreateRepositoryPermission))
.withArgs(compRepo.projectId, USERSTATICPERMISSION.REPOSITORY.KEY, USERSTATICPERMISSION.REPOSITORY.VALUE.DELETE)
.and.returnValue(of(mockHasDeleteRepositoryPermission));
fixtureRepo.detectChanges(); fixtureRepo.detectChanges();
}); });
let originalTimeout; let originalTimeout;
beforeEach(function () { beforeEach(function () {
originalTimeout = jasmine.DEFAULT_TIMEOUT_INTERVAL; originalTimeout = jasmine.DEFAULT_TIMEOUT_INTERVAL;
jasmine.DEFAULT_TIMEOUT_INTERVAL = 100000; jasmine.DEFAULT_TIMEOUT_INTERVAL = 100000;
}); });
afterEach(function () { afterEach(function () {
jasmine.DEFAULT_TIMEOUT_INTERVAL = originalTimeout; jasmine.DEFAULT_TIMEOUT_INTERVAL = originalTimeout;
}); });
@ -183,23 +159,19 @@ describe('RepositoryComponentGridview (inline template)', () => {
expect(elRepo.textContent).toEqual('library/busybox'); expect(elRepo.textContent).toEqual('library/busybox');
}); });
})); }));
// Will fail after upgrade to angular 6. todo: need to fix it.
it('should filter data by keyword', async(() => {
fixtureRepo.whenStable().then(() => {
fixtureRepo.detectChanges();
it('should filter data by keyword', async () => {
fixtureRepo.detectChanges();
await fixtureRepo.whenStable();
compRepo.doSearchRepoNames('nginx'); compRepo.doSearchRepoNames('nginx');
fixtureRepo.whenStable().then(() => {
fixtureRepo.detectChanges(); fixtureRepo.detectChanges();
await fixtureRepo.whenStable();
let de: DebugElement[] = fixtureRepo.debugElement.queryAll(By.css('.datagrid-cell')); let de: DebugElement[] = fixtureRepo.debugElement.queryAll(By.css('.datagrid-cell'));
expect(de).toBeTruthy(); expect(de).toBeTruthy();
expect(compRepo.repositories.length).toEqual(1); expect(compRepo.repositories.length).toEqual(1);
expect(de.length).toEqual(1); expect(de.length).toEqual(4);
let el: HTMLElement = de[0].nativeElement; let el: HTMLElement = de[1].nativeElement;
expect(el).toBeTruthy(); expect(el).toBeTruthy();
expect(el.textContent).toEqual('library/nginx'); expect(el.textContent).toEqual('library/nginx');
}); });
}); });
}));
});

View File

@ -9,14 +9,12 @@ import {
EventEmitter, EventEmitter,
OnChanges, OnChanges,
SimpleChanges, SimpleChanges,
Inject Inject, OnDestroy
} from "@angular/core"; } from "@angular/core";
import { Router } from "@angular/router"; import { Router } from "@angular/router";
import { forkJoin } from "rxjs"; import { forkJoin, Subscription } from "rxjs";
import { finalize } from "rxjs/operators"; import { debounceTime, distinctUntilChanged, finalize, switchMap } from "rxjs/operators";
import { TranslateService } from "@ngx-translate/core"; import { TranslateService } from "@ngx-translate/core";
import { Comparator, State } from "../../services/interface";
import { import {
Repository, Repository,
SystemInfo, SystemInfo,
@ -26,7 +24,7 @@ import {
RepositoryItem, RepositoryItem,
TagService TagService
} from '../../services'; } from '../../services';
import { ErrorHandler } from '../../utils/error-handler/error-handler'; import { ErrorHandler } from '../../utils/error-handler';
import { DEFAULT_PAGE_SIZE, calculatePage, clone } from '../../utils/utils'; import { DEFAULT_PAGE_SIZE, calculatePage, clone } from '../../utils/utils';
import { ConfirmationState, ConfirmationTargets, ConfirmationButtons } from '../../entities/shared.const'; import { ConfirmationState, ConfirmationTargets, ConfirmationButtons } from '../../entities/shared.const';
import { ConfirmationDialogComponent } from '../confirmation-dialog/confirmation-dialog.component'; import { ConfirmationDialogComponent } from '../confirmation-dialog/confirmation-dialog.component';
@ -43,13 +41,13 @@ import { map, catchError } from "rxjs/operators";
import { Observable, throwError as observableThrowError } from "rxjs"; import { Observable, throwError as observableThrowError } from "rxjs";
import { errorHandler as errorHandFn } from "../../utils/shared/shared.utils"; import { errorHandler as errorHandFn } from "../../utils/shared/shared.utils";
import { ClrDatagridStateInterface } from "@clr/angular"; import { ClrDatagridStateInterface } from "@clr/angular";
import { FilterComponent } from "../filter/filter.component";
@Component({ @Component({
selector: "hbr-repository-gridview", selector: "hbr-repository-gridview",
templateUrl: "./repository-gridview.component.html", templateUrl: "./repository-gridview.component.html",
styleUrls: ["./repository-gridview.component.scss"], styleUrls: ["./repository-gridview.component.scss"],
changeDetection: ChangeDetectionStrategy.OnPush
}) })
export class RepositoryGridviewComponent implements OnChanges, OnInit { export class RepositoryGridviewComponent implements OnChanges, OnInit, OnDestroy {
signedCon: { [key: string]: any | string[] } = {}; signedCon: { [key: string]: any | string[] } = {};
downloadLink: string; downloadLink: string;
@Input() projectId: number; @Input() projectId: number;
@ -76,7 +74,7 @@ export class RepositoryGridviewComponent implements OnChanges, OnInit {
pageSize: number = DEFAULT_PAGE_SIZE; pageSize: number = DEFAULT_PAGE_SIZE;
currentPage = 1; currentPage = 1;
totalCount = 0; totalCount = 0;
currentState: State; currentState: ClrDatagridStateInterface;
@ViewChild("confirmationDialog", {static: false}) @ViewChild("confirmationDialog", {static: false})
confirmationDialog: ConfirmationDialogComponent; confirmationDialog: ConfirmationDialogComponent;
@ -84,6 +82,9 @@ export class RepositoryGridviewComponent implements OnChanges, OnInit {
@ViewChild("gridView", {static: false}) gridView: GridViewComponent; @ViewChild("gridView", {static: false}) gridView: GridViewComponent;
hasCreateRepositoryPermission: boolean; hasCreateRepositoryPermission: boolean;
hasDeleteRepositoryPermission: boolean; hasDeleteRepositoryPermission: boolean;
@ViewChild(FilterComponent, {static: true})
filterComponent: FilterComponent;
searchSub: Subscription;
constructor(@Inject(SERVICE_CONFIG) private configInfo: IServiceConfig, constructor(@Inject(SERVICE_CONFIG) private configInfo: IServiceConfig,
private errorHandler: ErrorHandler, private errorHandler: ErrorHandler,
private translateService: TranslateService, private translateService: TranslateService,
@ -92,8 +93,7 @@ export class RepositoryGridviewComponent implements OnChanges, OnInit {
private tagService: TagService, private tagService: TagService,
private operationService: OperationService, private operationService: OperationService,
public userPermissionService: UserPermissionService, public userPermissionService: UserPermissionService,
private ref: ChangeDetectorRef, ) {
private router: Router) {
if (this.configInfo && this.configInfo.systemInfoEndpoint) { if (this.configInfo && this.configInfo.systemInfoEndpoint) {
this.downloadLink = this.configInfo.systemInfoEndpoint + "/getcert"; this.downloadLink = this.configInfo.systemInfoEndpoint + "/getcert";
} }
@ -129,14 +129,40 @@ export class RepositoryGridviewComponent implements OnChanges, OnInit {
.subscribe(systemInfo => (this.systemInfo = systemInfo) .subscribe(systemInfo => (this.systemInfo = systemInfo)
, error => this.errorHandler.error(error)); , error => this.errorHandler.error(error));
if (this.mode === "admiral") { this.isCardView = this.mode === "admiral";
this.isCardView = true;
} else {
this.isCardView = false;
}
this.lastFilteredRepoName = ""; this.lastFilteredRepoName = "";
this.getHelmChartVersionPermission(this.projectId); this.getHelmChartVersionPermission(this.projectId);
if (!this.searchSub) {
this.searchSub = this.filterComponent.filterTerms.pipe(
debounceTime(500),
distinctUntilChanged(),
switchMap(repoName => {
this.lastFilteredRepoName = repoName;
this.currentPage = 1;
// Pagination
let params: RequestQueryParams = new RequestQueryParams()
.set("page", "" + this.currentPage).set("page_size", "" + this.pageSize);
this.loading = true;
return this.repositoryService.getRepositories(this.projectId, this.lastFilteredRepoName, params);
})
).subscribe((repo: Repository) => {
this.totalCount = repo.metadata.xTotalCount;
this.repositories = repo.data;
this.signedCon = {};
this.loading = false;
}, error => {
this.loading = false;
this.errorHandler.error(error);
});
}
}
ngOnDestroy() {
if (this.searchSub) {
this.searchSub.unsubscribe();
this.searchSub = null;
}
} }
confirmDeletion(message: ConfirmationAcknowledgement) { confirmDeletion(message: ConfirmationAcknowledgement) {
@ -160,7 +186,7 @@ export class RepositoryGridviewComponent implements OnChanges, OnInit {
forkJoin(observableLists).subscribe((item) => { forkJoin(observableLists).subscribe((item) => {
this.selectedRow = []; this.selectedRow = [];
this.refresh(); this.refresh();
let st: State = this.getStateAfterDeletion(); let st: ClrDatagridStateInterface = this.getStateAfterDeletion();
if (!st) { if (!st) {
this.refresh(); this.refresh();
} else { } else {
@ -214,7 +240,7 @@ export class RepositoryGridviewComponent implements OnChanges, OnInit {
doSearchRepoNames(repoName: string) { doSearchRepoNames(repoName: string) {
this.lastFilteredRepoName = repoName; this.lastFilteredRepoName = repoName;
this.currentPage = 1; this.currentPage = 1;
let st: State = this.currentState; let st: ClrDatagridStateInterface = this.currentState;
if (!st || !st.page) { if (!st || !st.page) {
st = { page: {} }; st = { page: {} };
} }
@ -264,11 +290,7 @@ export class RepositoryGridviewComponent implements OnChanges, OnInit {
{ {
repoName: repoName, repoName: repoName,
signedImages: signature, signedImages: signature,
}).pipe(finalize(() => { }).subscribe((res: string) => {
let hnd = setInterval(() => this.ref.markForCheck(), 100);
setTimeout(() => clearInterval(hnd), 5000);
}))
.subscribe((res: string) => {
summaryKey = res; summaryKey = res;
let message = new ConfirmationMessage( let message = new ConfirmationMessage(
summaryTitle, summaryTitle,
@ -324,12 +346,6 @@ export class RepositoryGridviewComponent implements OnChanges, OnInit {
evt.stopPropagation(); evt.stopPropagation();
this.deleteRepos([item]); this.deleteRepos([item]);
} }
selectedChange(): void {
let hnd = setInterval(() => this.ref.markForCheck(), 100);
setTimeout(() => clearInterval(hnd), 2000);
}
refresh() { refresh() {
this.doSearchRepoNames(""); this.doSearchRepoNames("");
} }
@ -356,8 +372,6 @@ export class RepositoryGridviewComponent implements OnChanges, OnInit {
this.loading = false; this.loading = false;
this.errorHandler.error(error); this.errorHandler.error(error);
}); });
let hnd = setInterval(() => this.ref.markForCheck(), 500);
setTimeout(() => clearInterval(hnd), 5000);
} }
clrLoad(state: ClrDatagridStateInterface): void { clrLoad(state: ClrDatagridStateInterface): void {
@ -401,13 +415,9 @@ export class RepositoryGridviewComponent implements OnChanges, OnInit {
this.loading = false; this.loading = false;
this.errorHandler.error(error); this.errorHandler.error(error);
}); });
// Force refresh view
let hnd = setInterval(() => this.ref.markForCheck(), 100);
setTimeout(() => clearInterval(hnd), 5000);
} }
getStateAfterDeletion(): State { getStateAfterDeletion(): ClrDatagridStateInterface {
let total: number = this.totalCount - 1; let total: number = this.totalCount - 1;
if (total <= 0) { if (total <= 0) {
return null; return null;
@ -420,7 +430,7 @@ export class RepositoryGridviewComponent implements OnChanges, OnInit {
targetPageNumber = totalPages; // Should == currentPage -1 targetPageNumber = totalPages; // Should == currentPage -1
} }
let st: State = this.currentState; let st: ClrDatagridStateInterface = this.currentState;
if (!st) { if (!st) {
st = { page: {} }; st = { page: {} };
} }