70834: Metadata schema component refactoring and caching issue fix

This commit is contained in:
Kristof De Langhe
2020-05-13 13:56:42 +02:00
parent 7677a673aa
commit cd46f33909
4 changed files with 76 additions and 50 deletions

View File

@@ -177,6 +177,7 @@ export class MetadataFieldFormComponent implements OnInit, OnDestroy {
}); });
} }
this.clearFields(); this.clearFields();
this.registryService.cancelEditMetadataField();
} }
); );
} }

View File

@@ -1,36 +1,37 @@
<div class="container"> <div class="container">
<div class="metadata-schema row"> <div class="metadata-schema row">
<div class="col-12"> <div class="col-12" *ngVar="(metadataSchema$ | async) as schema">
<h2 id="header" class="border-bottom pb-2">{{'admin.registries.schema.head' | translate}}: "{{(metadataSchema | async)?.payload?.prefix}}"</h2> <h2 id="header" class="border-bottom pb-2">{{'admin.registries.schema.head' | translate}}: "{{schema?.prefix}}"</h2>
<p id="description" class="pb-2">{{'admin.registries.schema.description' | translate:namespace }}</p> <p id="description" class="pb-2">{{'admin.registries.schema.description' | translate:{ namespace: schema?.namespace } }}</p>
<ds-metadata-field-form <ds-metadata-field-form
[metadataSchema]="(metadataSchema | async)?.payload" [metadataSchema]="schema"
(submitForm)="forceUpdateFields()"></ds-metadata-field-form> (submitForm)="forceUpdateFields()"></ds-metadata-field-form>
<h3>{{'admin.registries.schema.fields.head' | translate}}</h3> <h3>{{'admin.registries.schema.fields.head' | translate}}</h3>
<ds-pagination <ng-container *ngVar="(metadataFields$ | async)?.payload as fields">
*ngIf="(metadataFields | async)?.payload?.totalElements > 0" <ds-pagination
[paginationOptions]="config" *ngIf="fields?.totalElements > 0"
[pageInfoState]="(metadataFields | async)?.payload" [paginationOptions]="config"
[collectionSize]="(metadataFields | async)?.payload?.totalElements" [pageInfoState]="fields"
[hideGear]="false" [collectionSize]="fields?.totalElements"
[hidePagerWhenSinglePage]="true" [hideGear]="false"
(pageChange)="onPageChange($event)"> [hidePagerWhenSinglePage]="true"
<div class="table-responsive"> (pageChange)="onPageChange($event)">
<table id="metadata-fields" class="table table-striped table-hover"> <div class="table-responsive">
<thead> <table id="metadata-fields" class="table table-striped table-hover">
<thead>
<tr> <tr>
<th></th> <th></th>
<th scope="col">{{'admin.registries.schema.fields.table.field' | translate}}</th> <th scope="col">{{'admin.registries.schema.fields.table.field' | translate}}</th>
<th scope="col">{{'admin.registries.schema.fields.table.scopenote' | translate}}</th> <th scope="col">{{'admin.registries.schema.fields.table.scopenote' | translate}}</th>
</tr> </tr>
</thead> </thead>
<tbody> <tbody>
<tr *ngFor="let field of (metadataFields | async)?.payload?.page" <tr *ngFor="let field of fields?.page"
[ngClass]="{'table-primary' : isActive(field) | async}"> [ngClass]="{'table-primary' : isActive(field) | async}">
<td> <td>
<label> <label>
@@ -39,22 +40,23 @@
(change)="selectMetadataField(field, $event)"> (change)="selectMetadataField(field, $event)">
</label> </label>
</td> </td>
<td class="selectable-row" (click)="editField(field)">{{(metadataSchema | async)?.payload?.prefix}}.{{field.element}}<label *ngIf="field.qualifier">.</label>{{field.qualifier}}</td> <td class="selectable-row" (click)="editField(field)">{{schema?.prefix}}.{{field.element}}<label *ngIf="field.qualifier">.</label>{{field.qualifier}}</td>
<td class="selectable-row" (click)="editField(field)">{{field.scopeNote}}</td> <td class="selectable-row" (click)="editField(field)">{{field.scopeNote}}</td>
</tr> </tr>
</tbody> </tbody>
</table> </table>
</div>
</ds-pagination>
<div *ngIf="fields?.totalElements == 0" class="alert alert-info w-100 mb-2" role="alert">
{{'admin.registries.schema.fields.no-items' | translate}}
</div> </div>
</ds-pagination>
<div *ngIf="(metadataFields | async)?.payload?.totalElements == 0" class="alert alert-info w-100 mb-2" role="alert"> <div>
{{'admin.registries.schema.fields.no-items' | translate}} <button [routerLink]="['/admin/registries/metadata']" class="btn btn-primary">{{'admin.registries.schema.return' | translate}}</button>
</div> <button *ngIf="fields?.page?.length > 0" type="submit" class="btn btn-danger float-right" (click)="deleteFields()">{{'admin.registries.schema.fields.table.delete' | translate}}</button>
</div>
<div> </ng-container>
<button [routerLink]="['/admin/registries/metadata']" class="btn btn-primary">{{'admin.registries.schema.return' | translate}}</button>
<button *ngIf="(metadataFields | async)?.payload?.page?.length > 0" type="submit" class="btn btn-danger float-right" (click)="deleteFields()">{{'admin.registries.schema.fields.table.delete' | translate}}</button>
</div>
</div> </div>
</div> </div>

View File

@@ -5,7 +5,7 @@ import { Observable, combineLatest as observableCombineLatest } from 'rxjs';
import { RemoteData } from '../../../core/data/remote-data'; import { RemoteData } from '../../../core/data/remote-data';
import { PaginatedList } from '../../../core/data/paginated-list'; import { PaginatedList } from '../../../core/data/paginated-list';
import { PaginationComponentOptions } from '../../../shared/pagination/pagination-component-options.model'; import { PaginationComponentOptions } from '../../../shared/pagination/pagination-component-options.model';
import { map, take } from 'rxjs/operators'; import { map, switchMap, take } from 'rxjs/operators';
import { hasValue } from '../../../shared/empty.util'; import { hasValue } from '../../../shared/empty.util';
import { RestResponse } from '../../../core/cache/response.models'; import { RestResponse } from '../../../core/cache/response.models';
import { zip } from 'rxjs/internal/observable/zip'; import { zip } from 'rxjs/internal/observable/zip';
@@ -13,8 +13,10 @@ import { NotificationsService } from '../../../shared/notifications/notification
import { TranslateService } from '@ngx-translate/core'; import { TranslateService } from '@ngx-translate/core';
import { MetadataField } from '../../../core/metadata/metadata-field.model'; import { MetadataField } from '../../../core/metadata/metadata-field.model';
import { MetadataSchema } from '../../../core/metadata/metadata-schema.model'; import { MetadataSchema } from '../../../core/metadata/metadata-schema.model';
import { getSucceededRemoteData } from '../../../core/shared/operators'; import { getFirstSucceededRemoteDataPayload } from '../../../core/shared/operators';
import { toFindListOptions } from '../../../shared/pagination/pagination.utils'; import { toFindListOptions } from '../../../shared/pagination/pagination.utils';
import { BehaviorSubject } from 'rxjs/internal/BehaviorSubject';
import { combineLatest } from 'rxjs/internal/observable/combineLatest';
@Component({ @Component({
selector: 'ds-metadata-schema', selector: 'ds-metadata-schema',
@@ -26,21 +28,15 @@ import { toFindListOptions } from '../../../shared/pagination/pagination.utils';
* The admin can create, edit or delete metadata fields here. * The admin can create, edit or delete metadata fields here.
*/ */
export class MetadataSchemaComponent implements OnInit { export class MetadataSchemaComponent implements OnInit {
/**
* The namespace of the metadata schema
*/
namespace;
/** /**
* The metadata schema * The metadata schema
*/ */
metadataSchema: Observable<RemoteData<MetadataSchema>>; metadataSchema$: Observable<MetadataSchema>;
/** /**
* A list of all the fields attached to this metadata schema * A list of all the fields attached to this metadata schema
*/ */
metadataFields: Observable<RemoteData<PaginatedList<MetadataField>>>; metadataFields$: Observable<RemoteData<PaginatedList<MetadataField>>>;
/** /**
* Pagination config used to display the list of metadata fields * Pagination config used to display the list of metadata fields
@@ -51,6 +47,11 @@ export class MetadataSchemaComponent implements OnInit {
pageSizeOptions: [25, 50, 100, 200] pageSizeOptions: [25, 50, 100, 200]
}); });
/**
* Whether or not the list of MetadataFields needs an update
*/
needsUpdate: BehaviorSubject<boolean> = new BehaviorSubject<boolean>(true);
constructor(private registryService: RegistryService, constructor(private registryService: RegistryService,
private route: ActivatedRoute, private route: ActivatedRoute,
private notificationsService: NotificationsService, private notificationsService: NotificationsService,
@@ -70,7 +71,7 @@ export class MetadataSchemaComponent implements OnInit {
* @param params * @param params
*/ */
initialize(params) { initialize(params) {
this.metadataSchema = this.registryService.getMetadataSchemaByName(params.schemaName); this.metadataSchema$ = this.registryService.getMetadataSchemaByName(params.schemaName).pipe(getFirstSucceededRemoteDataPayload());
this.updateFields(); this.updateFields();
} }
@@ -80,18 +81,21 @@ export class MetadataSchemaComponent implements OnInit {
*/ */
onPageChange(event) { onPageChange(event) {
this.config.currentPage = event; this.config.currentPage = event;
this.updateFields(); this.needsUpdate.next(true);
} }
/** /**
* Update the list of fields by fetching it from the rest api or cache * Update the list of fields by fetching it from the rest api or cache
*/ */
private updateFields() { private updateFields() {
this.metadataSchema.pipe(getSucceededRemoteData()).subscribe((schemaData) => { this.metadataFields$ = combineLatest(this.metadataSchema$, this.needsUpdate).pipe(
const schema = schemaData.payload; switchMap(([schema, update]: [MetadataSchema, boolean]) => {
this.metadataFields = this.registryService.getMetadataFieldsBySchema(schema, toFindListOptions(this.config)); if (update) {
this.namespace = {namespace: schemaData.payload.namespace}; console.log('reloaded list');
}); return this.registryService.getMetadataFieldsBySchema(schema, toFindListOptions(this.config));
}
})
);
} }
/** /**
@@ -99,8 +103,7 @@ export class MetadataSchemaComponent implements OnInit {
* a new REST call * a new REST call
*/ */
public forceUpdateFields() { public forceUpdateFields() {
this.registryService.clearMetadataFieldRequests().subscribe(); this.registryService.clearMetadataFieldRequests().subscribe(() => this.needsUpdate.next(true));
this.updateFields();
} }
/** /**

View File

@@ -45,6 +45,12 @@ export class MetadataFieldDataService extends DataService<MetadataField> {
super(); super();
} }
/**
* Find metadata fields belonging to a metadata schema
* @param schema The metadata schema to list fields for
* @param options The options info used to retrieve the fields
* @param linksToFollow List of {@link FollowLinkConfig} that indicate which {@link HALLink}s should be automatically resolved
*/
findBySchema(schema: MetadataSchema, options: FindListOptions = {}, ...linksToFollow: Array<FollowLinkConfig<MetadataField>>) { findBySchema(schema: MetadataSchema, options: FindListOptions = {}, ...linksToFollow: Array<FollowLinkConfig<MetadataField>>) {
const optionsWithSchema = Object.assign(new FindListOptions(), options, { const optionsWithSchema = Object.assign(new FindListOptions(), options, {
searchParams: [new SearchParam('schema', schema.prefix)] searchParams: [new SearchParam('schema', schema.prefix)]
@@ -52,6 +58,14 @@ export class MetadataFieldDataService extends DataService<MetadataField> {
return this.searchBy(this.searchBySchemaLinkPath, optionsWithSchema, ...linksToFollow); return this.searchBy(this.searchBySchemaLinkPath, optionsWithSchema, ...linksToFollow);
} }
/**
* Create or Update a MetadataField
* If the MetadataField contains an id, it is assumed the field already exists and is updated instead
* Since creating or updating is nearly identical, the only real difference is the request (and slight difference in endpoint):
* - On creation, a CreateMetadataFieldRequest is used
* - On update, a UpdateMetadataFieldRequest is used
* @param field The MetadataField to create or update
*/
createOrUpdateMetadataField(field: MetadataField): Observable<RestResponse> { createOrUpdateMetadataField(field: MetadataField): Observable<RestResponse> {
const isUpdate = hasValue(field.id); const isUpdate = hasValue(field.id);
const requestId = this.requestService.generateRequestId(); const requestId = this.requestService.generateRequestId();
@@ -97,9 +111,15 @@ export class MetadataFieldDataService extends DataService<MetadataField> {
); );
} }
/**
* Clear all metadata field requests
* Used for refreshing lists after adding/updating/removing a metadata field from a metadata schema
*/
clearRequests(): Observable<string> { clearRequests(): Observable<string> {
return this.getBrowseEndpoint().pipe( return this.getBrowseEndpoint().pipe(
tap((href: string) => this.requestService.removeByHrefSubstring(href)) tap((href: string) => {
this.requestService.removeByHrefSubstring(href);
})
); );
} }