Merge branch 'dmp-refactoring' of https://code-repo.d4science.org/MaDgiK-CITE/argos into dmp-refactoring
This commit is contained in:
commit
f6151b085f
|
@ -56,6 +56,8 @@ BEGIN
|
||||||
|
|
||||||
ALTER TABLE public."DescriptionTemplate" ALTER COLUMN version_status SET NOT NULL;
|
ALTER TABLE public."DescriptionTemplate" ALTER COLUMN version_status SET NOT NULL;
|
||||||
|
|
||||||
|
ALTER TABLE public."DescriptionTemplate" ALTER COLUMN version DROP DEFAULT;
|
||||||
|
|
||||||
INSERT INTO public."DBVersion" VALUES ('DMPDB', '00.01.010', '2023-11-02 12:00:00.000000+02', now(), 'Aling DescriptionTemplate table.');
|
INSERT INTO public."DBVersion" VALUES ('DMPDB', '00.01.010', '2023-11-02 12:00:00.000000+02', now(), 'Aling DescriptionTemplate table.');
|
||||||
|
|
||||||
END$$;
|
END$$;
|
|
@ -17,6 +17,16 @@ export interface DescriptionTemplatePersist extends BaseEntityPersist {
|
||||||
users: UserDescriptionTemplatePersist[];
|
users: UserDescriptionTemplatePersist[];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface NewVersionDescriptionTemplatePersist extends BaseEntityPersist {
|
||||||
|
label: string;
|
||||||
|
description: string;
|
||||||
|
language: string;
|
||||||
|
type: Guid;
|
||||||
|
status: DescriptionTemplateStatus;
|
||||||
|
definition: DescriptionTemplateDefinitionPersist;
|
||||||
|
users: UserDescriptionTemplatePersist[];
|
||||||
|
}
|
||||||
|
|
||||||
export interface UserDescriptionTemplatePersist {
|
export interface UserDescriptionTemplatePersist {
|
||||||
userId?: Guid;
|
userId?: Guid;
|
||||||
role?: UserDescriptionTemplateRole;
|
role?: UserDescriptionTemplateRole;
|
||||||
|
|
|
@ -2,7 +2,7 @@ import { HttpClient, HttpHeaders, HttpResponse } from '@angular/common/http';
|
||||||
import { Injectable } from '@angular/core';
|
import { Injectable } from '@angular/core';
|
||||||
import { IsActive } from '@app/core/common/enum/is-active.enum';
|
import { IsActive } from '@app/core/common/enum/is-active.enum';
|
||||||
import { DescriptionTemplate } from '@app/core/model/description-template/description-template';
|
import { DescriptionTemplate } from '@app/core/model/description-template/description-template';
|
||||||
import { DescriptionTemplatePersist } from '@app/core/model/description-template/description-template-persist';
|
import { DescriptionTemplatePersist, NewVersionDescriptionTemplatePersist } from '@app/core/model/description-template/description-template-persist';
|
||||||
import { DescriptionTemplateLookup } from '@app/core/query/description-template.lookup';
|
import { DescriptionTemplateLookup } from '@app/core/query/description-template.lookup';
|
||||||
import { MultipleAutoCompleteConfiguration } from '@app/library/auto-complete/multiple/multiple-auto-complete-configuration';
|
import { MultipleAutoCompleteConfiguration } from '@app/library/auto-complete/multiple/multiple-auto-complete-configuration';
|
||||||
import { SingleAutoCompleteConfiguration } from '@app/library/auto-complete/single/single-auto-complete-configuration';
|
import { SingleAutoCompleteConfiguration } from '@app/library/auto-complete/single/single-auto-complete-configuration';
|
||||||
|
@ -68,6 +68,15 @@ export class DescriptionTemplateService {
|
||||||
catchError((error: any) => throwError(error)));
|
catchError((error: any) => throwError(error)));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
newVersion(item: NewVersionDescriptionTemplatePersist, reqFields: string[] = []): Observable<DescriptionTemplate> {
|
||||||
|
const url = `${this.apiBase}/new-version`;
|
||||||
|
const options = { params: { f: reqFields } };
|
||||||
|
|
||||||
|
return this.http
|
||||||
|
.post<DescriptionTemplate>(url, item).pipe(
|
||||||
|
catchError((error: any) => throwError(error)));
|
||||||
|
}
|
||||||
|
|
||||||
downloadXML(id: Guid): Observable<HttpResponse<Blob>> {
|
downloadXML(id: Guid): Observable<HttpResponse<Blob>> {
|
||||||
const url = `${this.apiBase}/xml/export/${id}`;
|
const url = `${this.apiBase}/xml/export/${id}`;
|
||||||
let headerXml: HttpHeaders = this.headers.set('Content-Type', 'application/xml');
|
let headerXml: HttpHeaders = this.headers.set('Content-Type', 'application/xml');
|
||||||
|
|
|
@ -14,6 +14,14 @@ const routes: Routes = [
|
||||||
component: DescriptionTemplateListingComponent,
|
component: DescriptionTemplateListingComponent,
|
||||||
canActivate: [AuthGuard]
|
canActivate: [AuthGuard]
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
path: 'versions/:groupid',
|
||||||
|
component: DescriptionTemplateListingComponent,
|
||||||
|
canActivate: [AuthGuard],
|
||||||
|
data: {
|
||||||
|
mode: 'versions-listing'
|
||||||
|
}
|
||||||
|
},
|
||||||
{
|
{
|
||||||
path: 'new',
|
path: 'new',
|
||||||
canActivate: [AuthGuard],
|
canActivate: [AuthGuard],
|
||||||
|
@ -24,7 +32,7 @@ const routes: Routes = [
|
||||||
permissions: [AppPermission.EditDescriptionTemplate]
|
permissions: [AppPermission.EditDescriptionTemplate]
|
||||||
},
|
},
|
||||||
...BreadcrumbService.generateRouteDataConfiguration({
|
...BreadcrumbService.generateRouteDataConfiguration({
|
||||||
title: 'BREADCRUMBS.NEW-DMP-BLUEPRINT'
|
title: 'BREADCRUMBS.NEW-DESCRIPTION-TEMPLATES'
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -38,13 +46,31 @@ const routes: Routes = [
|
||||||
},
|
},
|
||||||
data: {
|
data: {
|
||||||
...BreadcrumbService.generateRouteDataConfiguration({
|
...BreadcrumbService.generateRouteDataConfiguration({
|
||||||
title: 'BREADCRUMBS.EDIT-DMP-BLUEPRINT'
|
title: 'BREADCRUMBS.EDIT-DESCRIPTION-TEMPLATES'
|
||||||
}),
|
}),
|
||||||
authContext: {
|
authContext: {
|
||||||
permissions: [AppPermission.EditDescriptionTemplate]
|
permissions: [AppPermission.EditDescriptionTemplate]
|
||||||
|
},
|
||||||
|
action: 'clone'
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: 'new-version/:newversionid',
|
||||||
|
canActivate: [AuthGuard],
|
||||||
|
component: DescriptionTemplateEditorComponent,
|
||||||
|
canDeactivate: [PendingChangesGuard],
|
||||||
|
resolve: {
|
||||||
|
'entity': DescriptionTemplateEditorResolver
|
||||||
|
},
|
||||||
|
data: {
|
||||||
|
...BreadcrumbService.generateRouteDataConfiguration({
|
||||||
|
title: 'BREADCRUMBS.EDIT-DESCRIPTION-TEMPLATES'
|
||||||
|
}),
|
||||||
|
authContext: {
|
||||||
|
permissions: [AppPermission.EditDescriptionTemplate]
|
||||||
|
},
|
||||||
|
action: 'new-version'
|
||||||
}
|
}
|
||||||
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: ':id',
|
path: ':id',
|
||||||
|
@ -56,7 +82,7 @@ const routes: Routes = [
|
||||||
},
|
},
|
||||||
data: {
|
data: {
|
||||||
...BreadcrumbService.generateRouteDataConfiguration({
|
...BreadcrumbService.generateRouteDataConfiguration({
|
||||||
title: 'BREADCRUMBS.EDIT-DMP-BLUEPRINT'
|
title: 'BREADCRUMBS.EDIT-DESCRIPTION-TEMPLATES'
|
||||||
}),
|
}),
|
||||||
authContext: {
|
authContext: {
|
||||||
permissions: [AppPermission.EditDescriptionTemplate]
|
permissions: [AppPermission.EditDescriptionTemplate]
|
||||||
|
|
|
@ -14,7 +14,7 @@ import { IsActive } from '@app/core/common/enum/is-active.enum';
|
||||||
import { AppPermission } from '@app/core/common/enum/permission.enum';
|
import { AppPermission } from '@app/core/common/enum/permission.enum';
|
||||||
import { UserDescriptionTemplateRole } from '@app/core/common/enum/user-description-template-role';
|
import { UserDescriptionTemplateRole } from '@app/core/common/enum/user-description-template-role';
|
||||||
import { DescriptionTemplate } from '@app/core/model/description-template/description-template';
|
import { DescriptionTemplate } from '@app/core/model/description-template/description-template';
|
||||||
import { DescriptionTemplatePersist } from '@app/core/model/description-template/description-template-persist';
|
import { DescriptionTemplatePersist, NewVersionDescriptionTemplatePersist } from '@app/core/model/description-template/description-template-persist';
|
||||||
import { LanguageInfo } from '@app/core/model/language-info';
|
import { LanguageInfo } from '@app/core/model/language-info';
|
||||||
import { User } from '@app/core/model/user/user';
|
import { User } from '@app/core/model/user/user';
|
||||||
import { AuthService } from '@app/core/services/auth/auth.service';
|
import { AuthService } from '@app/core/services/auth/auth.service';
|
||||||
|
@ -201,6 +201,7 @@ export class DescriptionTemplateEditorComponent extends BaseEditor<DescriptionTe
|
||||||
}
|
}
|
||||||
|
|
||||||
persistEntity(onSuccess?: (response) => void): void {
|
persistEntity(onSuccess?: (response) => void): void {
|
||||||
|
if (this.isNew && !this.isClone && !this.isNewVersion){
|
||||||
const formData = this.formService.getValue(this.formGroup.value) as DescriptionTemplatePersist;
|
const formData = this.formService.getValue(this.formGroup.value) as DescriptionTemplatePersist;
|
||||||
|
|
||||||
this.descriptionTemplateService.persist(formData)
|
this.descriptionTemplateService.persist(formData)
|
||||||
|
@ -208,6 +209,15 @@ export class DescriptionTemplateEditorComponent extends BaseEditor<DescriptionTe
|
||||||
complete => onSuccess ? onSuccess(complete) : this.onCallbackSuccess(complete),
|
complete => onSuccess ? onSuccess(complete) : this.onCallbackSuccess(complete),
|
||||||
error => this.onCallbackError(error)
|
error => this.onCallbackError(error)
|
||||||
);
|
);
|
||||||
|
} else if (this.isNewVersion && !this.isNew && !this.isClone) {
|
||||||
|
const formData = this.formService.getValue(this.formGroup.value) as NewVersionDescriptionTemplatePersist;
|
||||||
|
|
||||||
|
this.descriptionTemplateService.newVersion(formData)
|
||||||
|
.pipe(takeUntil(this._destroyed)).subscribe(
|
||||||
|
complete => onSuccess ? onSuccess(complete) : this.onCallbackSuccess(complete),
|
||||||
|
error => this.onCallbackError(error)
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
formSubmit(): void {
|
formSubmit(): void {
|
||||||
|
|
|
@ -103,10 +103,13 @@ export class DescriptionTemplateEditorResolver extends BaseEditorResolver {
|
||||||
];
|
];
|
||||||
const id = route.paramMap.get('id');
|
const id = route.paramMap.get('id');
|
||||||
const cloneid = route.paramMap.get('cloneid');
|
const cloneid = route.paramMap.get('cloneid');
|
||||||
|
const newversion = route.paramMap.get('newversionid');
|
||||||
if (id != null) {
|
if (id != null) {
|
||||||
return this.descriptionTemplateService.getSingle(Guid.parse(id), fieldSets).pipe(tap(x => this.breadcrumbService.addIdResolvedValue(x.id?.toString(), x.label)), takeUntil(this._destroyed));
|
return this.descriptionTemplateService.getSingle(Guid.parse(id), fieldSets).pipe(tap(x => this.breadcrumbService.addIdResolvedValue(x.id?.toString(), x.label)), takeUntil(this._destroyed));
|
||||||
} else if (cloneid != null) {
|
} else if (cloneid != null) {
|
||||||
return this.descriptionTemplateService.clone(Guid.parse(cloneid), fieldSets).pipe(tap(x => this.breadcrumbService.addIdResolvedValue(x.id?.toString(), x.label)), takeUntil(this._destroyed));
|
return this.descriptionTemplateService.clone(Guid.parse(cloneid), fieldSets).pipe(tap(x => this.breadcrumbService.addIdResolvedValue(x.id?.toString(), x.label)), takeUntil(this._destroyed));
|
||||||
|
} else if (newversion != null) {
|
||||||
|
return this.descriptionTemplateService.getSingle(Guid.parse(newversion), fieldSets).pipe(tap(x => this.breadcrumbService.addIdResolvedValue(x.id?.toString(), x.label)), takeUntil(this._destroyed));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -23,7 +23,7 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<app-hybrid-listing [rows]="gridRows" [columns]="gridColumns" [visibleColumns]="visibleColumns" [count]="totalElements" [offset]="currentPageNumber" [limit]="lookup.page.size" [defaultSort]="lookup.order?.items" [externalSorting]="true" (rowActivated)="onRowActivated($event)" (pageLoad)="alterPage($event)" (columnSort)="onColumnSort($event)" (columnsChanged)="onColumnsChanged($event)" [listItemTemplate]="listItemTemplate">
|
<app-hybrid-listing [rows]="gridRows" [columns]="gridColumns" [visibleColumns]="visibleColumns" [count]="totalElements" [offset]="currentPageNumber" [limit]="lookup.page.size" [defaultSort]="lookup.order?.items" [externalSorting]="true" (rowActivated)="onRowActivated($event, '/description-templates')" (pageLoad)="alterPage($event)" (columnSort)="onColumnSort($event)" (columnsChanged)="onColumnsChanged($event)" [listItemTemplate]="listItemTemplate">
|
||||||
|
|
||||||
<app-description-template-listing-filters hybrid-listing-filters [(filter)]="lookup" (filterChange)="filterChanged($event)" />
|
<app-description-template-listing-filters hybrid-listing-filters [(filter)]="lookup" (filterChange)="filterChanged($event)" />
|
||||||
|
|
||||||
|
@ -95,23 +95,20 @@
|
||||||
<mat-icon>more_horiz</mat-icon>
|
<mat-icon>more_horiz</mat-icon>
|
||||||
</button>
|
</button>
|
||||||
<mat-menu #actionsMenu="matMenu">
|
<mat-menu #actionsMenu="matMenu">
|
||||||
<button mat-menu-item [routerLink]="['./' + row.id]">
|
<button mat-menu-item [routerLink]="['/description-templates/', row.id]">
|
||||||
<mat-icon>edit</mat-icon>{{'DESCRIPTION-TEMPLATE-LISTING.ACTIONS.EDIT' | translate}}
|
<mat-icon>edit</mat-icon>{{'DESCRIPTION-TEMPLATE-LISTING.ACTIONS.EDIT' | translate}}
|
||||||
</button>
|
</button>
|
||||||
<button mat-menu-item [routerLink]="['./new-version/' + row.id]">
|
<button mat-menu-item [routerLink]="['/description-templates/new-version/', row.id]">
|
||||||
<mat-icon>queue</mat-icon>{{'DESCRIPTION-TEMPLATE-LISTING.ACTIONS.NEW-VERSION' | translate}}
|
<mat-icon>queue</mat-icon>{{'DESCRIPTION-TEMPLATE-LISTING.ACTIONS.NEW-VERSION' | translate}}
|
||||||
</button>
|
</button>
|
||||||
<button mat-menu-item (click)="newVersionFromFile(row.id, row.label)">
|
<button mat-menu-item [routerLink]="['/description-templates/clone/', row.id]">
|
||||||
<mat-icon>file_copy</mat-icon>{{'DESCRIPTION-TEMPLATE-LISTING.ACTIONS.NEW-VERSION-FROM-FILE' | translate}}
|
|
||||||
</button>
|
|
||||||
<button mat-menu-item [routerLink]="['./clone/' + row.id]">
|
|
||||||
<mat-icon>content_copy</mat-icon>{{'DESCRIPTION-TEMPLATE-LISTING.ACTIONS.CLONE' | translate}}
|
<mat-icon>content_copy</mat-icon>{{'DESCRIPTION-TEMPLATE-LISTING.ACTIONS.CLONE' | translate}}
|
||||||
</button>
|
</button>
|
||||||
<button mat-menu-item [routerLink]="['./versions/' + row.id]">
|
<button mat-menu-item [routerLink]="['/description-templates/versions/', row.groupId]">
|
||||||
<mat-icon>library_books</mat-icon>
|
<mat-icon>library_books</mat-icon>
|
||||||
{{'DESCRIPTION-TEMPLATE-LISTING.ACTIONS.VIEW-VERSIONS' | translate}}
|
{{'DESCRIPTION-TEMPLATE-LISTING.ACTIONS.VIEW-VERSIONS' | translate}}
|
||||||
</button>
|
</button>
|
||||||
<button mat-menu-item (click)="export(row.id)" [routerLink]="['./' + row.id]">
|
<button mat-menu-item (click)="export(row.id)" [routerLink]="['/description-templates/', row.id]">
|
||||||
<mat-icon>download</mat-icon>{{'DESCRIPTION-TEMPLATE-LISTING.ACTIONS.DOWNLOAD-XML' | translate}}
|
<mat-icon>download</mat-icon>{{'DESCRIPTION-TEMPLATE-LISTING.ACTIONS.DOWNLOAD-XML' | translate}}
|
||||||
</button>
|
</button>
|
||||||
<button mat-menu-item (click)="delete(row.id)">
|
<button mat-menu-item (click)="delete(row.id)">
|
||||||
|
|
|
@ -40,6 +40,7 @@ export class DescriptionTemplateListingComponent extends BaseListingComponent<De
|
||||||
userSettingsKey = { key: 'DescriptionTemplateListingUserSettings' };
|
userSettingsKey = { key: 'DescriptionTemplateListingUserSettings' };
|
||||||
propertiesAvailableForOrder: ColumnDefinition[];
|
propertiesAvailableForOrder: ColumnDefinition[];
|
||||||
descriptionTemplateStatuses = DescriptionTemplateStatus;
|
descriptionTemplateStatuses = DescriptionTemplateStatus;
|
||||||
|
mode;
|
||||||
|
|
||||||
@ViewChild('descriptionTemplateStatus', { static: true }) descriptionTemplateStatus?: TemplateRef<any>;
|
@ViewChild('descriptionTemplateStatus', { static: true }) descriptionTemplateStatus?: TemplateRef<any>;
|
||||||
@ViewChild('actions', { static: true }) actions?: TemplateRef<any>;
|
@ViewChild('actions', { static: true }) actions?: TemplateRef<any>;
|
||||||
|
@ -50,6 +51,8 @@ export class DescriptionTemplateListingComponent extends BaseListingComponent<De
|
||||||
nameof<DescriptionTemplate>(x => x.label),
|
nameof<DescriptionTemplate>(x => x.label),
|
||||||
nameof<DescriptionTemplate>(x => x.description),
|
nameof<DescriptionTemplate>(x => x.description),
|
||||||
nameof<DescriptionTemplate>(x => x.status),
|
nameof<DescriptionTemplate>(x => x.status),
|
||||||
|
nameof<DescriptionTemplate>(x => x.version),
|
||||||
|
nameof<DescriptionTemplate>(x => x.groupId),
|
||||||
nameof<DescriptionTemplate>(x => x.updatedAt),
|
nameof<DescriptionTemplate>(x => x.updatedAt),
|
||||||
nameof<DescriptionTemplate>(x => x.createdAt),
|
nameof<DescriptionTemplate>(x => x.createdAt),
|
||||||
nameof<DescriptionTemplate>(x => x.hash),
|
nameof<DescriptionTemplate>(x => x.hash),
|
||||||
|
@ -76,6 +79,7 @@ export class DescriptionTemplateListingComponent extends BaseListingComponent<De
|
||||||
super(router, route, uiNotificationService, httpErrorHandlingService, queryParamsService);
|
super(router, route, uiNotificationService, httpErrorHandlingService, queryParamsService);
|
||||||
// Lookup setup
|
// Lookup setup
|
||||||
// Default lookup values are defined in the user settings class.
|
// Default lookup values are defined in the user settings class.
|
||||||
|
this.mode = this.route.snapshot?.data['mode'];
|
||||||
this.lookup = this.initializeLookup();
|
this.lookup = this.initializeLookup();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -90,6 +94,7 @@ export class DescriptionTemplateListingComponent extends BaseListingComponent<De
|
||||||
lookup.page = { offset: 0, size: this.ITEMS_PER_PAGE };
|
lookup.page = { offset: 0, size: this.ITEMS_PER_PAGE };
|
||||||
lookup.isActive = [IsActive.Active];
|
lookup.isActive = [IsActive.Active];
|
||||||
lookup.order = { items: [this.toDescSortField(nameof<DescriptionTemplate>(x => x.createdAt))] };
|
lookup.order = { items: [this.toDescSortField(nameof<DescriptionTemplate>(x => x.createdAt))] };
|
||||||
|
if (this.mode && this.mode == 'versions-listing') lookup.groupIds = [Guid.parse(this.route.snapshot.paramMap.get('groupid'))]
|
||||||
this.updateOrderUiFields(lookup.order);
|
this.updateOrderUiFields(lookup.order);
|
||||||
|
|
||||||
lookup.project = {
|
lookup.project = {
|
||||||
|
@ -116,6 +121,11 @@ export class DescriptionTemplateListingComponent extends BaseListingComponent<De
|
||||||
languageName: 'DESCRIPTION-TEMPLATE-LISTING.FIELDS.STATUS',
|
languageName: 'DESCRIPTION-TEMPLATE-LISTING.FIELDS.STATUS',
|
||||||
cellTemplate: this.descriptionTemplateStatus
|
cellTemplate: this.descriptionTemplateStatus
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
prop: nameof<DescriptionTemplate>(x => x.version),
|
||||||
|
sortable: true,
|
||||||
|
languageName: 'DESCRIPTION-TEMPLATE-LISTING.FIELDS.VERSION'
|
||||||
|
},
|
||||||
{
|
{
|
||||||
prop: nameof<DescriptionTemplate>(x => x.createdAt),
|
prop: nameof<DescriptionTemplate>(x => x.createdAt),
|
||||||
sortable: true,
|
sortable: true,
|
||||||
|
|
|
@ -1074,6 +1074,7 @@
|
||||||
"NAME": "Name",
|
"NAME": "Name",
|
||||||
"DESCRIPTION": "Description",
|
"DESCRIPTION": "Description",
|
||||||
"STATUS": "Status",
|
"STATUS": "Status",
|
||||||
|
"VERSION": "Version",
|
||||||
"UPDATED-AT": "Updated",
|
"UPDATED-AT": "Updated",
|
||||||
"CREATED-AT": "Created",
|
"CREATED-AT": "Created",
|
||||||
"PUBLISHED-AT": "Published",
|
"PUBLISHED-AT": "Published",
|
||||||
|
@ -1097,7 +1098,6 @@
|
||||||
"CLONE": "Clone",
|
"CLONE": "Clone",
|
||||||
"DOWNLOAD-XML": "Download XML",
|
"DOWNLOAD-XML": "Download XML",
|
||||||
"NEW-VERSION": "New Version",
|
"NEW-VERSION": "New Version",
|
||||||
"NEW-VERSION-FROM-FILE": "New Version from File",
|
|
||||||
"VIEW-VERSIONS": "All Description Template Versions"
|
"VIEW-VERSIONS": "All Description Template Versions"
|
||||||
},
|
},
|
||||||
"IMPORT": {
|
"IMPORT": {
|
||||||
|
|
Loading…
Reference in New Issue