mirror of
https://github.com/goharbor/harbor.git
synced 2024-11-26 20:26:13 +01:00
Merge pull request #12701 from AllForNothing/artifact-icon
get artifact icon from backend API
This commit is contained in:
commit
9671ff1f10
@ -151,11 +151,6 @@ export class AddP2pPolicyComponent implements OnInit, OnDestroy {
|
|||||||
this.tags = null;
|
this.tags = null;
|
||||||
this.labels = null;
|
this.labels = null;
|
||||||
this.cron = null;
|
this.cron = null;
|
||||||
this.currentForm.reset({
|
|
||||||
triggerType: "manual",
|
|
||||||
severity: PROJECT_SEVERITY_LEVEL_MAP[this.projectSeverity],
|
|
||||||
onlySignedImages: this.enableContentTrust
|
|
||||||
});
|
|
||||||
if (this.providers && this.providers.length) {
|
if (this.providers && this.providers.length) {
|
||||||
this.providers.forEach(item => {
|
this.providers.forEach(item => {
|
||||||
if (item.default) {
|
if (item.default) {
|
||||||
@ -163,6 +158,12 @@ export class AddP2pPolicyComponent implements OnInit, OnDestroy {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
this.currentForm.reset({
|
||||||
|
triggerType: "manual",
|
||||||
|
severity: PROJECT_SEVERITY_LEVEL_MAP[this.projectSeverity],
|
||||||
|
onlySignedImages: this.enableContentTrust,
|
||||||
|
provider: this.policy.provider_id
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
setCron(event: any) {
|
setCron(event: any) {
|
||||||
|
@ -40,7 +40,7 @@
|
|||||||
<div class="execution-select">
|
<div class="execution-select">
|
||||||
<div class="select filter-tag" [hidden]="!openSelectFilterPiece">
|
<div class="select filter-tag" [hidden]="!openSelectFilterPiece">
|
||||||
<clr-select-container>
|
<clr-select-container>
|
||||||
<select clrSelect [(ngModel)]="filterByType" (change)="selectFilterType($event)" >
|
<select clrSelect [(ngModel)]="filterByType" (change)="selectFilterType()" >
|
||||||
<option *ngFor="let filter of mutipleFilter" value="{{filter.filterBy}}">{{ filter.filterByShowText | translate}}</option>
|
<option *ngFor="let filter of mutipleFilter" value="{{filter.filterBy}}">{{ filter.filterByShowText | translate}}</option>
|
||||||
</select>
|
</select>
|
||||||
</clr-select-container>
|
</clr-select-container>
|
||||||
@ -161,19 +161,10 @@
|
|||||||
<clr-dg-row *ngFor="let artifact of artifactList" [clrDgItem]="artifact" >
|
<clr-dg-row *ngFor="let artifact of artifactList" [clrDgItem]="artifact" >
|
||||||
<clr-dg-cell class="truncated flex-max-width">
|
<clr-dg-cell class="truncated flex-max-width">
|
||||||
<div class="cell white-normal">
|
<div class="cell white-normal">
|
||||||
<img *ngIf="artifact?.type !== 'IMAGE';else elseBlock" class="artifact-icon" [title]="artifact.type"
|
<div class="artifact-icon clr-display-inline-block" *ngIf="artifact.icon">
|
||||||
[src]="artifact.type | selectArtifactIcon" />
|
<img *ngIf="getIcon(artifact.icon)" class="artifact-icon" [title]="artifact.type"
|
||||||
<ng-template #elseBlock>
|
[src]="getIcon(artifact.icon)" (error)="showDefaultIcon($event)" />
|
||||||
<clr-tooltip>
|
|
||||||
<div clrTooltipTrigger class="level-border">
|
|
||||||
<img class="artifact-icon" [title]="artifact.type"
|
|
||||||
[src]="artifact.type | selectArtifactIcon" />
|
|
||||||
</div>
|
</div>
|
||||||
<clr-tooltip-content clrPosition="top-right" clrSize="lg" *clrIfOpen>
|
|
||||||
<span>Docker and the Docker logo are trademarks or registered trademarks of Docker, Inc. in the United States and/or other countries.</span>
|
|
||||||
</clr-tooltip-content>
|
|
||||||
</clr-tooltip>
|
|
||||||
</ng-template>
|
|
||||||
<a href="javascript:void(0)" class="max-width-100 margin-left-5" (click)="goIntoArtifactSummaryPage(artifact)"
|
<a href="javascript:void(0)" class="max-width-100 margin-left-5" (click)="goIntoArtifactSummaryPage(artifact)"
|
||||||
title="{{artifact.digest}}">
|
title="{{artifact.digest}}">
|
||||||
{{ artifact.digest | slice:0:15}}</a>
|
{{ artifact.digest | slice:0:15}}</a>
|
||||||
@ -256,7 +247,7 @@
|
|||||||
</clr-dg-cell>
|
</clr-dg-cell>
|
||||||
<clr-dg-cell>
|
<clr-dg-cell>
|
||||||
<div class="cell">
|
<div class="cell">
|
||||||
{{artifact.size?sizeTransform(artifact.size): ""}}
|
{{artifact.size?sizeTransform(artifact.size+''): ""}}
|
||||||
</div>
|
</div>
|
||||||
</clr-dg-cell>
|
</clr-dg-cell>
|
||||||
<clr-dg-cell>
|
<clr-dg-cell>
|
||||||
|
@ -282,8 +282,13 @@ describe("ArtifactListTabComponent (inline template)", () => {
|
|||||||
).pipe(delay(0));
|
).pipe(delay(0));
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
deleteArtifact: () => of (null)
|
deleteArtifact: () => of (null),
|
||||||
|
getIconsFromBackEnd() {
|
||||||
|
return undefined;
|
||||||
|
},
|
||||||
|
getIcon() {
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
beforeEach(async(() => {
|
beforeEach(async(() => {
|
||||||
TestBed.configureTestingModule({
|
TestBed.configureTestingModule({
|
||||||
|
@ -54,11 +54,18 @@ import {
|
|||||||
} from "../../../../../../lib/entities/shared.const";
|
} from "../../../../../../lib/entities/shared.const";
|
||||||
import { operateChanges, OperateInfo, OperationState } from "../../../../../../lib/components/operation/operate";
|
import { operateChanges, OperateInfo, OperationState } from "../../../../../../lib/components/operation/operate";
|
||||||
import { errorHandler } from "../../../../../../lib/utils/shared/shared.utils";
|
import { errorHandler } from "../../../../../../lib/utils/shared/shared.utils";
|
||||||
import { ArtifactFront as Artifact, mutipleFilter, artifactPullCommands } from "../../../artifact/artifact";
|
import {
|
||||||
|
ArtifactFront as Artifact,
|
||||||
|
mutipleFilter,
|
||||||
|
artifactPullCommands,
|
||||||
|
artifactDefault
|
||||||
|
} from '../../../artifact/artifact';
|
||||||
import { Project } from "../../../../project";
|
import { Project } from "../../../../project";
|
||||||
import { ArtifactService as NewArtifactService } from "../../../../../../../ng-swagger-gen/services/artifact.service";
|
import { ArtifactService as NewArtifactService } from "../../../../../../../ng-swagger-gen/services/artifact.service";
|
||||||
import { ADDITIONS } from "../../../artifact/artifact-additions/models";
|
import { ADDITIONS } from "../../../artifact/artifact-additions/models";
|
||||||
import { Platform } from "../../../../../../../ng-swagger-gen/models/platform";
|
import { Platform } from "../../../../../../../ng-swagger-gen/models/platform";
|
||||||
|
import { IconService } from '../../../../../../../ng-swagger-gen/services/icon.service';
|
||||||
|
import { DomSanitizer, SafeUrl } from '@angular/platform-browser';
|
||||||
export interface LabelState {
|
export interface LabelState {
|
||||||
iconsShow: boolean;
|
iconsShow: boolean;
|
||||||
label: Label;
|
label: Label;
|
||||||
@ -161,7 +168,6 @@ export class ArtifactListTabComponent implements OnInit, OnDestroy {
|
|||||||
|
|
||||||
scanFiinishArtifactLength: number = 0;
|
scanFiinishArtifactLength: number = 0;
|
||||||
onScanArtifactsLength: number = 0;
|
onScanArtifactsLength: number = 0;
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
private errorHandlerService: ErrorHandler,
|
private errorHandlerService: ErrorHandler,
|
||||||
private userPermissionService: UserPermissionService,
|
private userPermissionService: UserPermissionService,
|
||||||
@ -374,6 +380,7 @@ export class ArtifactListTabComponent implements OnInit, OnDestroy {
|
|||||||
artifact.platform = clone(platFormAttr[index].platform);
|
artifact.platform = clone(platFormAttr[index].platform);
|
||||||
});
|
});
|
||||||
this.getPullCommand(this.artifactList);
|
this.getPullCommand(this.artifactList);
|
||||||
|
this.getIconsFromBackEnd();
|
||||||
}, error => {
|
}, error => {
|
||||||
this.errorHandlerService.error(error);
|
this.errorHandlerService.error(error);
|
||||||
});
|
});
|
||||||
@ -403,6 +410,7 @@ export class ArtifactListTabComponent implements OnInit, OnDestroy {
|
|||||||
this.artifactList = doSorting<Artifact>(this.artifactList, state);
|
this.artifactList = doSorting<Artifact>(this.artifactList, state);
|
||||||
|
|
||||||
this.getPullCommand(this.artifactList);
|
this.getPullCommand(this.artifactList);
|
||||||
|
this.getIconsFromBackEnd();
|
||||||
}, error => {
|
}, error => {
|
||||||
// error
|
// error
|
||||||
this.errorHandlerService.error(error);
|
this.errorHandlerService.error(error);
|
||||||
@ -992,4 +1000,17 @@ export class ArtifactListTabComponent implements OnInit, OnDestroy {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
getIconsFromBackEnd() {
|
||||||
|
if (this.artifactList && this.artifactList.length) {
|
||||||
|
this.artifactService.getIconsFromBackEnd(this.artifactList);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
showDefaultIcon(event: any) {
|
||||||
|
if (event && event.target) {
|
||||||
|
event.target.src = artifactDefault;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
getIcon(icon: string): SafeUrl {
|
||||||
|
return this.artifactService.getIcon(icon);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -15,19 +15,10 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="title-block">
|
<div class="title-block">
|
||||||
<h2 class="custom-h2 center-align-items">
|
<h2 class="custom-h2 center-align-items">
|
||||||
<img *ngIf="artifact?.type !== 'IMAGE';else elseBlock" class="artifact-icon" [title]="artifact.type"
|
<div class="artifact-icon clr-display-inline-block" *ngIf="artifact.icon">
|
||||||
[src]="artifact.type | selectArtifactIcon" />
|
<img *ngIf="getIcon(artifact.icon)" class="artifact-icon" [title]="artifact.type"
|
||||||
<ng-template #elseBlock>
|
[src]="getIcon(artifact.icon)" (error)="showDefaultIcon($event)" />
|
||||||
<clr-tooltip>
|
|
||||||
<div clrTooltipTrigger class="level-border">
|
|
||||||
<img class="artifact-icon" [title]="artifact.type"
|
|
||||||
[src]="artifact.type | selectArtifactIcon" />
|
|
||||||
</div>
|
</div>
|
||||||
<clr-tooltip-content clrPosition="top-right" clrSize="lg" *clrIfOpen>
|
|
||||||
<span>Docker and the Docker logo are trademarks or registered trademarks of Docker, Inc. in the United States and/or other countries.</span>
|
|
||||||
</clr-tooltip-content>
|
|
||||||
</clr-tooltip>
|
|
||||||
</ng-template>
|
|
||||||
<span class="margin-left-10px">{{artifact?.digest | slice:0:15}}</span>
|
<span class="margin-left-10px">{{artifact?.digest | slice:0:15}}</span>
|
||||||
<clr-icon size="25" *ngIf="artifact?.references && artifact?.references?.length" class="icon-folder margin-left-10px" shape="folder"></clr-icon>
|
<clr-icon size="25" *ngIf="artifact?.references && artifact?.references?.length" class="icon-folder margin-left-10px" shape="folder"></clr-icon>
|
||||||
</h2>
|
</h2>
|
||||||
|
@ -12,6 +12,7 @@ import { ActivatedRoute, Router } from "@angular/router";
|
|||||||
import { AppConfigService } from "../../../services/app-config.service";
|
import { AppConfigService } from "../../../services/app-config.service";
|
||||||
import { Project } from "../../project";
|
import { Project } from "../../project";
|
||||||
import { AllPipesModule } from "../../../all-pipes/all-pipes.module";
|
import { AllPipesModule } from "../../../all-pipes/all-pipes.module";
|
||||||
|
import { ArtifactDefaultService } from './artifact.service';
|
||||||
|
|
||||||
describe('ArtifactSummaryComponent', () => {
|
describe('ArtifactSummaryComponent', () => {
|
||||||
|
|
||||||
@ -26,9 +27,12 @@ describe('ArtifactSummaryComponent', () => {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const fakedArtifactService = {
|
const fakedArtifactDefaultService = {
|
||||||
getArtifact() {
|
getIconsFromBackEnd() {
|
||||||
return of(mockedArtifact);
|
return undefined;
|
||||||
|
},
|
||||||
|
getIcon() {
|
||||||
|
return undefined;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
let component: ArtifactSummaryComponent;
|
let component: ArtifactSummaryComponent;
|
||||||
@ -86,7 +90,7 @@ describe('ArtifactSummaryComponent', () => {
|
|||||||
{ provide: Router, useValue: mockRouter },
|
{ provide: Router, useValue: mockRouter },
|
||||||
{ provide: ActivatedRoute, useValue: mockActivatedRoute },
|
{ provide: ActivatedRoute, useValue: mockActivatedRoute },
|
||||||
{ provide: ProjectService, useValue: fakedProjectService },
|
{ provide: ProjectService, useValue: fakedProjectService },
|
||||||
{ provide: ArtifactService, useValue: fakedArtifactService },
|
{ provide: ArtifactDefaultService, useValue: fakedArtifactDefaultService },
|
||||||
ErrorHandler
|
ErrorHandler
|
||||||
]
|
]
|
||||||
})
|
})
|
||||||
|
@ -1,14 +1,14 @@
|
|||||||
import { Component, Output, EventEmitter, OnInit } from "@angular/core";
|
import { Component, Output, EventEmitter, OnInit } from "@angular/core";
|
||||||
import { Artifact } from "../../../../../ng-swagger-gen/models/artifact";
|
import { Artifact } from "../../../../../ng-swagger-gen/models/artifact";
|
||||||
import { ArtifactService } from "../../../../../ng-swagger-gen/services/artifact.service";
|
|
||||||
import { ErrorHandler } from "../../../../lib/utils/error-handler";
|
import { ErrorHandler } from "../../../../lib/utils/error-handler";
|
||||||
import { Label } from "../../../../../ng-swagger-gen/models/label";
|
import { Label } from "../../../../../ng-swagger-gen/models/label";
|
||||||
import { ProjectService } from "../../../../lib/services";
|
import { ProjectService } from "../../../../lib/services";
|
||||||
import { ActivatedRoute, Router } from "@angular/router";
|
import { ActivatedRoute, Router } from "@angular/router";
|
||||||
import { AppConfigService } from "../../../services/app-config.service";
|
import { AppConfigService } from "../../../services/app-config.service";
|
||||||
import { Project } from "../../project";
|
import { Project } from "../../project";
|
||||||
import { finalize } from "rxjs/operators";
|
import { artifactDefault } from './artifact';
|
||||||
import { dbEncodeURIComponent } from "../../../../lib/utils/utils";
|
import { SafeUrl } from '@angular/platform-browser';
|
||||||
|
import { ArtifactDefaultService } from './artifact.service';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: "artifact-summary",
|
selector: "artifact-summary",
|
||||||
@ -34,11 +34,11 @@ export class ArtifactSummaryComponent implements OnInit {
|
|||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
private projectService: ProjectService,
|
private projectService: ProjectService,
|
||||||
private artifactService: ArtifactService,
|
|
||||||
private errorHandler: ErrorHandler,
|
private errorHandler: ErrorHandler,
|
||||||
private route: ActivatedRoute,
|
private route: ActivatedRoute,
|
||||||
private appConfigService: AppConfigService,
|
private appConfigService: AppConfigService,
|
||||||
private router: Router
|
private router: Router,
|
||||||
|
private frontEndArtifactService: ArtifactDefaultService,
|
||||||
) {
|
) {
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -81,27 +81,24 @@ export class ArtifactSummaryComponent implements OnInit {
|
|||||||
const pro: Project = <Project>(resolverData['artifactResolver'][1]);
|
const pro: Project = <Project>(resolverData['artifactResolver'][1]);
|
||||||
this.projectName = pro.name;
|
this.projectName = pro.name;
|
||||||
this.artifact = <Artifact>(resolverData['artifactResolver'][0]);
|
this.artifact = <Artifact>(resolverData['artifactResolver'][0]);
|
||||||
|
this.getIconFromBackEnd();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
getArtifactDetails(): void {
|
|
||||||
this.loading = true;
|
|
||||||
this.artifactService.getArtifact({
|
|
||||||
repositoryName: dbEncodeURIComponent(this.repositoryName),
|
|
||||||
reference: this.artifactDigest,
|
|
||||||
projectName: this.projectName,
|
|
||||||
withLabel: true,
|
|
||||||
withScanOverview: true
|
|
||||||
}).pipe(finalize(() => this.loading = false))
|
|
||||||
.subscribe(response => {
|
|
||||||
this.artifact = response;
|
|
||||||
}, error => {
|
|
||||||
this.errorHandler.error(error);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
onBack(): void {
|
onBack(): void {
|
||||||
this.backEvt.emit(this.repositoryName);
|
this.backEvt.emit(this.repositoryName);
|
||||||
}
|
}
|
||||||
|
showDefaultIcon(event: any) {
|
||||||
|
if (event && event.target) {
|
||||||
|
event.target.src = artifactDefault;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
getIcon(icon: string): SafeUrl {
|
||||||
|
return this.frontEndArtifactService.getIcon(icon);
|
||||||
|
}
|
||||||
|
getIconFromBackEnd() {
|
||||||
|
if (this.artifact && this.artifact.icon) {
|
||||||
|
this.frontEndArtifactService.getIconsFromBackEnd([this.artifact]);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -3,6 +3,8 @@ import { IServiceConfig, SERVICE_CONFIG } from "../../../../lib/entities/service
|
|||||||
import { SharedModule } from "../../../../lib/utils/shared/shared.module";
|
import { SharedModule } from "../../../../lib/utils/shared/shared.module";
|
||||||
import { ArtifactDefaultService, ArtifactService } from "../artifact/artifact.service";
|
import { ArtifactDefaultService, ArtifactService } from "../artifact/artifact.service";
|
||||||
import { CURRENT_BASE_HREF } from "../../../../lib/utils/utils";
|
import { CURRENT_BASE_HREF } from "../../../../lib/utils/utils";
|
||||||
|
import { IconService } from '../../../../../ng-swagger-gen/services/icon.service';
|
||||||
|
import { DomSanitizer } from '@angular/platform-browser';
|
||||||
|
|
||||||
describe('ArtifactService', () => {
|
describe('ArtifactService', () => {
|
||||||
|
|
||||||
@ -16,7 +18,10 @@ describe('ArtifactService', () => {
|
|||||||
{
|
{
|
||||||
provide: ArtifactService,
|
provide: ArtifactService,
|
||||||
useClass: ArtifactDefaultService
|
useClass: ArtifactDefaultService
|
||||||
}]
|
},
|
||||||
|
IconService,
|
||||||
|
DomSanitizer
|
||||||
|
]
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -1,6 +1,9 @@
|
|||||||
import { Injectable, Inject } from "@angular/core";
|
import { Injectable, Inject } from "@angular/core";
|
||||||
import { Subject } from "rxjs";
|
import { Subject } from "rxjs";
|
||||||
import { IServiceConfig, SERVICE_CONFIG } from "../../../../lib/entities/service.config";
|
import { DomSanitizer, SafeUrl } from '@angular/platform-browser';
|
||||||
|
import { Artifact } from '../../../../../ng-swagger-gen/models/artifact';
|
||||||
|
import { IconService } from '../../../../../ng-swagger-gen/services/icon.service';
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Define the service methods to handle the repository tag related things.
|
* Define the service methods to handle the repository tag related things.
|
||||||
@ -13,15 +16,39 @@ export abstract class ArtifactService {
|
|||||||
reference: string[];
|
reference: string[];
|
||||||
triggerUploadArtifact = new Subject<string>();
|
triggerUploadArtifact = new Subject<string>();
|
||||||
TriggerArtifactChan$ = this.triggerUploadArtifact.asObservable();
|
TriggerArtifactChan$ = this.triggerUploadArtifact.asObservable();
|
||||||
|
abstract getIcon(digest: string): SafeUrl;
|
||||||
|
abstract setIcon(digest: string, url: SafeUrl);
|
||||||
|
abstract getIconsFromBackEnd(artifactList: Artifact[]);
|
||||||
}
|
}
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class ArtifactDefaultService extends ArtifactService {
|
export class ArtifactDefaultService extends ArtifactService {
|
||||||
|
|
||||||
triggerUploadArtifact = new Subject<string>();
|
triggerUploadArtifact = new Subject<string>();
|
||||||
TriggerArtifactChan$ = this.triggerUploadArtifact.asObservable();
|
TriggerArtifactChan$ = this.triggerUploadArtifact.asObservable();
|
||||||
|
private _iconMap: {[key: string]: SafeUrl} = {};
|
||||||
constructor() {
|
constructor(private iconService: IconService,
|
||||||
|
private domSanitizer: DomSanitizer) {
|
||||||
super();
|
super();
|
||||||
}
|
}
|
||||||
|
getIcon(icon: string): SafeUrl {
|
||||||
|
return this._iconMap[icon];
|
||||||
|
}
|
||||||
|
setIcon(icon: string, url: SafeUrl) {
|
||||||
|
if (!this._iconMap[icon]) {
|
||||||
|
this._iconMap[icon] = url;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
getIconsFromBackEnd(artifactList: Artifact[]) {
|
||||||
|
if (artifactList && artifactList.length) {
|
||||||
|
artifactList.forEach(item => {
|
||||||
|
if (item.icon && !this.getIcon(item.icon)) {
|
||||||
|
this.iconService.getIcon({digest: item.icon})
|
||||||
|
.subscribe(res => {
|
||||||
|
this.setIcon(item.icon, this.domSanitizer
|
||||||
|
.bypassSecurityTrustUrl(`data:${res['content-type']};charset=utf-8;base64,${res.content}`));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -5,6 +5,7 @@ export interface ArtifactFront extends Artifact {
|
|||||||
platform?: Platform;
|
platform?: Platform;
|
||||||
showImage?: string;
|
showImage?: string;
|
||||||
pullCommand?: string;
|
pullCommand?: string;
|
||||||
|
annotationsArray?: Array<{[key: string]: any}>;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const mutipleFilter = [
|
export const mutipleFilter = [
|
||||||
|
Loading…
Reference in New Issue
Block a user