mirror of
https://github.com/DSpace/dspace-angular.git
synced 2025-10-15 05:53:03 +00:00
58789: Metadata field create/edit/delete feature
This commit is contained in:
@@ -13,8 +13,7 @@ import { MetadataSchema } from '../../../../core/metadata/metadataschema.model';
|
||||
|
||||
@Component({
|
||||
selector: 'ds-metadata-schema-form',
|
||||
templateUrl: './metadata-schema-form.component.html',
|
||||
// styleUrls: ['./metadata-schema-form.component.css']
|
||||
templateUrl: './metadata-schema-form.component.html'
|
||||
})
|
||||
export class MetadataSchemaFormComponent implements OnInit {
|
||||
|
||||
|
@@ -6,11 +6,11 @@ import { RegistryService } from '../../../../core/registry/registry.service';
|
||||
import { FormBuilderService } from '../../../../shared/form/builder/form-builder.service';
|
||||
import { Observable } from 'rxjs/internal/Observable';
|
||||
import { MetadataField } from '../../../../core/metadata/metadatafield.model';
|
||||
import { take } from 'rxjs/operators';
|
||||
|
||||
@Component({
|
||||
selector: 'ds-metadata-field-form',
|
||||
templateUrl: './metadata-field-form.component.html',
|
||||
// styleUrls: ['./metadata-field-form.component.css']
|
||||
templateUrl: './metadata-field-form.component.html'
|
||||
})
|
||||
export class MetadataFieldFormComponent implements OnInit {
|
||||
|
||||
@@ -60,7 +60,6 @@ export class MetadataFieldFormComponent implements OnInit {
|
||||
}
|
||||
|
||||
ngOnInit() {
|
||||
|
||||
this.formGroup = this.formBuilderService.createFormGroup(this.formModel);
|
||||
this.registryService.getActiveMetadataField().subscribe((field) => {
|
||||
this.formGroup.patchValue({
|
||||
@@ -74,36 +73,33 @@ export class MetadataFieldFormComponent implements OnInit {
|
||||
});
|
||||
}
|
||||
|
||||
getMetadataField(): Observable<MetadataField> {
|
||||
return this.registryService.getActiveMetadataField();
|
||||
}
|
||||
|
||||
onCancel() {
|
||||
this.registryService.cancelEditMetadataField();
|
||||
}
|
||||
|
||||
onSubmit() {
|
||||
this.registryService.getActiveMetadataField().subscribe(
|
||||
this.registryService.getActiveMetadataField().pipe(take(1)).subscribe(
|
||||
(field) => {
|
||||
|
||||
const values = {
|
||||
schema: this.metadataSchema,
|
||||
element: this.element.value,
|
||||
qualifier: this.qualifier.value,
|
||||
scopeNote: this.scopeNote.value
|
||||
};
|
||||
if (field == null) {
|
||||
console.log('metadata field to create:');
|
||||
console.log('element: ' + this.element.value);
|
||||
if (this.qualifier.value) {
|
||||
console.log('qualifier: ' + this.qualifier.value);
|
||||
}
|
||||
if (this.scopeNote.value) {
|
||||
console.log('scopeNote: ' + this.scopeNote.value);
|
||||
}
|
||||
this.registryService.createOrUpdateMetadataField(Object.assign(new MetadataField(), values)).subscribe((newField) => {
|
||||
this.submitForm.emit(newField);
|
||||
});
|
||||
} else {
|
||||
console.log('metadata field to update:');
|
||||
console.log('element: ' + this.element.value);
|
||||
if (this.qualifier.value) {
|
||||
console.log('qualifier: ' + this.qualifier.value);
|
||||
}
|
||||
if (this.scopeNote.value) {
|
||||
console.log('scopeNote: ' + this.scopeNote.value);
|
||||
}
|
||||
this.registryService.createOrUpdateMetadataField(Object.assign(new MetadataField(), {
|
||||
id: field.id,
|
||||
schema: this.metadataSchema,
|
||||
element: (values.element ? values.element : field.element),
|
||||
qualifier: (values.qualifier ? values.qualifier : field.qualifier),
|
||||
scopeNote: (values.scopeNote ? values.scopeNote : field.scopeNote)
|
||||
})).subscribe((updatedField) => {
|
||||
this.submitForm.emit(updatedField);
|
||||
});
|
||||
}
|
||||
}
|
||||
);
|
||||
|
@@ -6,7 +6,9 @@
|
||||
|
||||
<p id="description" class="pb-2">{{'admin.registries.schema.description' | translate:namespace }}</p>
|
||||
|
||||
<ds-metadata-field-form [metadataSchema]="metadataSchema | async"></ds-metadata-field-form>
|
||||
<ds-metadata-field-form
|
||||
[metadataSchema]="(metadataSchema | async)?.payload"
|
||||
(submitForm)="forceUpdateFields()"></ds-metadata-field-form>
|
||||
|
||||
<h3>{{'admin.registries.schema.fields.head' | translate}}</h3>
|
||||
|
||||
@@ -28,7 +30,8 @@
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr *ngFor="let field of (metadataFields | async)?.payload?.page" (click)="editField(field)">
|
||||
<tr *ngFor="let field of (metadataFields | async)?.payload?.page"
|
||||
[ngClass]="{'table-primary' : isActive(field) | async}">
|
||||
<td>
|
||||
<label>
|
||||
<input type="checkbox"
|
||||
@@ -36,8 +39,8 @@
|
||||
(change)="selectMetadataField(field, $event)">
|
||||
</label>
|
||||
</td>
|
||||
<td>{{(metadataSchema | async)?.payload?.prefix}}.{{field.element}}<label *ngIf="field.qualifier">.</label>{{field.qualifier}}</td>
|
||||
<td>{{field.scopeNote}}</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)">{{field.scopeNote}}</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
@@ -0,0 +1,5 @@
|
||||
@import '../../../../styles/variables.scss';
|
||||
|
||||
.selectable-row:hover {
|
||||
cursor: pointer;
|
||||
}
|
@@ -1,17 +1,22 @@
|
||||
import { Component, OnInit } from '@angular/core';
|
||||
import { RegistryService } from '../../../core/registry/registry.service';
|
||||
import { ActivatedRoute } from '@angular/router';
|
||||
import { ActivatedRoute, Router } from '@angular/router';
|
||||
import { Observable } from 'rxjs';
|
||||
import { RemoteData } from '../../../core/data/remote-data';
|
||||
import { PaginatedList } from '../../../core/data/paginated-list';
|
||||
import { MetadataField } from '../../../core/metadata/metadatafield.model';
|
||||
import { MetadataSchema } from '../../../core/metadata/metadataschema.model';
|
||||
import { PaginationComponentOptions } from '../../../shared/pagination/pagination-component-options.model';
|
||||
import { map } from 'rxjs/operators';
|
||||
import { map, take } from 'rxjs/operators';
|
||||
import { hasValue } from '../../../shared/empty.util';
|
||||
import { RestResponse } from '../../../core/cache/response.models';
|
||||
import { zip } from 'rxjs/internal/observable/zip';
|
||||
import { NotificationsService } from '../../../shared/notifications/notifications.service';
|
||||
|
||||
@Component({
|
||||
selector: 'ds-metadata-schema',
|
||||
templateUrl: './metadata-schema.component.html'
|
||||
templateUrl: './metadata-schema.component.html',
|
||||
styleUrls: ['./metadata-schema.component.scss']
|
||||
})
|
||||
export class MetadataSchemaComponent implements OnInit {
|
||||
|
||||
@@ -25,7 +30,10 @@ export class MetadataSchemaComponent implements OnInit {
|
||||
pageSizeOptions: [25, 50, 100, 200]
|
||||
});
|
||||
|
||||
constructor(private registryService: RegistryService, private route: ActivatedRoute) {
|
||||
constructor(private registryService: RegistryService,
|
||||
private route: ActivatedRoute,
|
||||
private notificationsService: NotificationsService,
|
||||
private router: Router) {
|
||||
|
||||
}
|
||||
|
||||
@@ -53,8 +61,19 @@ export class MetadataSchemaComponent implements OnInit {
|
||||
});
|
||||
}
|
||||
|
||||
private forceUpdateFields() {
|
||||
this.registryService.clearMetadataFieldRequests().subscribe();
|
||||
this.updateFields();
|
||||
}
|
||||
|
||||
editField(field: MetadataField) {
|
||||
this.registryService.editMetadataField(field);
|
||||
this.getActiveField().pipe(take(1)).subscribe((activeField) => {
|
||||
if (field === activeField) {
|
||||
this.registryService.cancelEditMetadataField();
|
||||
} else {
|
||||
this.registryService.editMetadataField(field);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
isActive(field: MetadataField): Observable<boolean> {
|
||||
@@ -80,12 +99,27 @@ export class MetadataSchemaComponent implements OnInit {
|
||||
}
|
||||
|
||||
deleteFields() {
|
||||
this.registryService.getSelectedMetadataFields().subscribe(
|
||||
this.registryService.getSelectedMetadataFields().pipe(take(1)).subscribe(
|
||||
(fields) => {
|
||||
console.log('metadata fields to delete: ');
|
||||
const tasks$ = [];
|
||||
for (const field of fields) {
|
||||
console.log(field);
|
||||
if (hasValue(field.id)) {
|
||||
tasks$.push(this.registryService.deleteMetadataSchema(field.id));
|
||||
}
|
||||
}
|
||||
zip(...tasks$).subscribe((responses: RestResponse[]) => {
|
||||
const successResponses = responses.filter((response: RestResponse) => response.isSuccessful);
|
||||
const failedResponses = responses.filter((response: RestResponse) => !response.isSuccessful);
|
||||
if (successResponses.length > 0) {
|
||||
this.notificationsService.success('Success', `Successfully deleted ${successResponses.length} metadata fields`);
|
||||
}
|
||||
if (failedResponses.length > 0) {
|
||||
this.notificationsService.error('Error', `Failed to delete ${failedResponses.length} metadata fields`);
|
||||
}
|
||||
this.registryService.deselectAllMetadataField();
|
||||
this.router.navigate([], { queryParams: { page: 1 }, queryParamsHandling: 'merge'});
|
||||
this.forceUpdateFields();
|
||||
});
|
||||
}
|
||||
)
|
||||
}
|
||||
|
10
src/app/core/cache/response.models.ts
vendored
10
src/app/core/cache/response.models.ts
vendored
@@ -10,6 +10,7 @@ import { RegistryMetadatafieldsResponse } from '../registry/registry-metadatafie
|
||||
import { RegistryBitstreamformatsResponse } from '../registry/registry-bitstreamformats-response.model';
|
||||
import { AuthStatus } from '../auth/models/auth-status.model';
|
||||
import { MetadataSchema } from '../metadata/metadataschema.model';
|
||||
import { MetadataField } from '../metadata/metadatafield.model';
|
||||
|
||||
/* tslint:disable:max-classes-per-file */
|
||||
export class RestResponse {
|
||||
@@ -71,6 +72,15 @@ export class MetadataschemaSuccessResponse extends RestResponse {
|
||||
}
|
||||
}
|
||||
|
||||
export class MetadatafieldSuccessResponse extends RestResponse {
|
||||
constructor(
|
||||
public metadatafield: MetadataField,
|
||||
public statusCode: string
|
||||
) {
|
||||
super(true, statusCode);
|
||||
}
|
||||
}
|
||||
|
||||
export class SearchSuccessResponse extends RestResponse {
|
||||
constructor(
|
||||
public results: SearchQueryResponse,
|
||||
|
19
src/app/core/data/metadatafield-parsing.service.ts
Normal file
19
src/app/core/data/metadatafield-parsing.service.ts
Normal file
@@ -0,0 +1,19 @@
|
||||
import { DSpaceRESTv2Serializer } from '../dspace-rest-v2/dspace-rest-v2.serializer';
|
||||
import { DSpaceRESTV2Response } from '../dspace-rest-v2/dspace-rest-v2-response.model';
|
||||
import { RestRequest } from './request.models';
|
||||
import { ResponseParsingService } from './parsing.service';
|
||||
import { Injectable } from '@angular/core';
|
||||
import { MetadatafieldSuccessResponse, MetadataschemaSuccessResponse, RestResponse } from '../cache/response.models';
|
||||
import { MetadataField } from '../metadata/metadatafield.model';
|
||||
|
||||
@Injectable()
|
||||
export class MetadatafieldParsingService implements ResponseParsingService {
|
||||
|
||||
parse(request: RestRequest, data: DSpaceRESTV2Response): RestResponse {
|
||||
const payload = data.payload;
|
||||
|
||||
const deserialized = new DSpaceRESTv2Serializer(MetadataField).deserialize(payload);
|
||||
return new MetadatafieldSuccessResponse(deserialized, data.statusCode);
|
||||
}
|
||||
|
||||
}
|
@@ -9,6 +9,7 @@ import { DSpaceRESTv2Serializer } from '../dspace-rest-v2/dspace-rest-v2.seriali
|
||||
import { DSOResponseParsingService } from './dso-response-parsing.service';
|
||||
import { Injectable } from '@angular/core';
|
||||
import { RegistryMetadatafieldsResponse } from '../registry/registry-metadatafields-response.model';
|
||||
import { hasValue } from '../../shared/empty.util';
|
||||
|
||||
@Injectable()
|
||||
export class RegistryMetadatafieldsResponseParsingService implements ResponseParsingService {
|
||||
@@ -18,10 +19,14 @@ export class RegistryMetadatafieldsResponseParsingService implements ResponsePar
|
||||
parse(request: RestRequest, data: DSpaceRESTV2Response): RestResponse {
|
||||
const payload = data.payload;
|
||||
|
||||
const metadatafields = payload._embedded.metadatafields;
|
||||
metadatafields.forEach((field) => {
|
||||
field.schema = field._embedded.schema;
|
||||
});
|
||||
let metadatafields = [];
|
||||
|
||||
if (hasValue(payload._embedded)) {
|
||||
metadatafields = payload._embedded.metadatafields;
|
||||
metadatafields.forEach((field) => {
|
||||
field.schema = field._embedded.schema;
|
||||
});
|
||||
}
|
||||
|
||||
payload.metadatafields = metadatafields;
|
||||
|
||||
|
@@ -13,6 +13,7 @@ import { RestRequestMethod } from './rest-request-method';
|
||||
import { BrowseItemsResponseParsingService } from './browse-items-response-parsing-service';
|
||||
import { RegistryMetadataschemasResponseParsingService } from './registry-metadataschemas-response-parsing.service';
|
||||
import { MetadataschemaParsingService } from './metadataschema-parsing.service';
|
||||
import { MetadatafieldParsingService } from './metadatafield-parsing.service';
|
||||
|
||||
/* tslint:disable:max-classes-per-file */
|
||||
|
||||
@@ -239,6 +240,26 @@ export class UpdateMetadataSchemaRequest extends PutRequest {
|
||||
}
|
||||
}
|
||||
|
||||
export class CreateMetadataFieldRequest extends PostRequest {
|
||||
constructor(uuid: string, href: string, public body?: any, public options?: HttpOptions) {
|
||||
super(uuid, href, body, options);
|
||||
}
|
||||
|
||||
getResponseParser(): GenericConstructor<ResponseParsingService> {
|
||||
return MetadatafieldParsingService;
|
||||
}
|
||||
}
|
||||
|
||||
export class UpdateMetadataFieldRequest extends PutRequest {
|
||||
constructor(uuid: string, href: string, public body?: any, public options?: HttpOptions) {
|
||||
super(uuid, href, body, options);
|
||||
}
|
||||
|
||||
getResponseParser(): GenericConstructor<ResponseParsingService> {
|
||||
return MetadatafieldParsingService;
|
||||
}
|
||||
}
|
||||
|
||||
export class RequestError extends Error {
|
||||
statusText: string;
|
||||
}
|
||||
|
@@ -3,6 +3,9 @@ import { autoserialize } from 'cerialize';
|
||||
import { ListableObject } from '../../shared/object-collection/shared/listable-object.model';
|
||||
|
||||
export class MetadataField implements ListableObject {
|
||||
@autoserialize
|
||||
id: number;
|
||||
|
||||
@autoserialize
|
||||
self: string;
|
||||
|
||||
|
@@ -20,7 +20,7 @@ import { RemoteDataBuildService } from '../cache/builders/remote-data-build.serv
|
||||
import { RequestService } from '../data/request.service';
|
||||
import { RegistryMetadataschemasResponse } from './registry-metadataschemas-response.model';
|
||||
import {
|
||||
ErrorResponse, MetadataschemaSuccessResponse,
|
||||
ErrorResponse, MetadatafieldSuccessResponse, MetadataschemaSuccessResponse,
|
||||
RegistryBitstreamformatsSuccessResponse,
|
||||
RegistryMetadatafieldsSuccessResponse,
|
||||
RegistryMetadataschemasSuccessResponse, RestResponse
|
||||
@@ -304,7 +304,7 @@ export class RegistryService {
|
||||
this.store.dispatch(new MetadataRegistryDeselectFieldAction(field))
|
||||
}
|
||||
|
||||
public deselectAllMetadataField(field: MetadataField) {
|
||||
public deselectAllMetadataField() {
|
||||
this.store.dispatch(new MetadataRegistryDeselectAllFieldAction())
|
||||
}
|
||||
|
||||
@@ -366,8 +366,79 @@ export class RegistryService {
|
||||
}
|
||||
|
||||
public deleteMetadataSchema(id: number): Observable<RestResponse> {
|
||||
return this.delete(this.metadataSchemasPath, id);
|
||||
}
|
||||
|
||||
public clearMetadataSchemaRequests(): Observable<string> {
|
||||
return this.halService.getEndpoint(this.metadataSchemasPath).pipe(
|
||||
tap((href: string) => this.requestService.removeByHrefSubstring(href))
|
||||
)
|
||||
}
|
||||
|
||||
public createOrUpdateMetadataField(field: MetadataField): Observable<MetadataField> {
|
||||
const isUpdate = hasValue(field.id);
|
||||
const requestId = this.requestService.generateRequestId();
|
||||
const endpoint$ = this.halService.getEndpoint(this.metadataSchemasPath).pipe(
|
||||
const endpoint$ = this.halService.getEndpoint(this.metadataFieldsPath).pipe(
|
||||
isNotEmptyOperator(),
|
||||
map((endpoint: string) => (isUpdate ? `${endpoint}/${field.id}` : `${endpoint}?schemaId=${field.schema.id}`)),
|
||||
distinctUntilChanged()
|
||||
);
|
||||
|
||||
const request$ = endpoint$.pipe(
|
||||
take(1),
|
||||
map((endpoint: string) => {
|
||||
if (isUpdate) {
|
||||
const options: HttpOptions = Object.create({});
|
||||
let headers = new HttpHeaders();
|
||||
headers = headers.append('Content-Type', 'application/json');
|
||||
options.headers = headers;
|
||||
return new UpdateMetadataSchemaRequest(requestId, endpoint, JSON.stringify(field), options);
|
||||
} else {
|
||||
return new CreateMetadataSchemaRequest(requestId, endpoint, JSON.stringify(field));
|
||||
}
|
||||
})
|
||||
);
|
||||
|
||||
// Execute the post/put request
|
||||
request$.pipe(
|
||||
configureRequest(this.requestService)
|
||||
).subscribe();
|
||||
|
||||
// Return created/updated field
|
||||
return this.requestService.getByUUID(requestId).pipe(
|
||||
getResponseFromEntry(),
|
||||
map((response: RestResponse) => {
|
||||
if (!response.isSuccessful) {
|
||||
if (hasValue((response as any).errorMessage)) {
|
||||
this.notificationsService.error('Server Error:', (response as any).errorMessage, new NotificationOptions(-1));
|
||||
}
|
||||
} else {
|
||||
this.notificationsService.success('Success', `Successfully ${isUpdate ? 'updated' : 'created'} metadata field "${field.schema.prefix}.${field.element}.${field.qualifier}"`);
|
||||
return response;
|
||||
}
|
||||
}),
|
||||
isNotEmptyOperator(),
|
||||
map((response: MetadatafieldSuccessResponse) => {
|
||||
if (isNotEmpty(response.metadatafield)) {
|
||||
return response.metadatafield;
|
||||
}
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
public deleteMetadataField(id: number): Observable<RestResponse> {
|
||||
return this.delete(this.metadataFieldsPath, id);
|
||||
}
|
||||
|
||||
public clearMetadataFieldRequests(): Observable<string> {
|
||||
return this.halService.getEndpoint(this.metadataFieldsPath).pipe(
|
||||
tap((href: string) => this.requestService.removeByHrefSubstring(href))
|
||||
)
|
||||
}
|
||||
|
||||
private delete(path: string, id: number): Observable<RestResponse> {
|
||||
const requestId = this.requestService.generateRequestId();
|
||||
const endpoint$ = this.halService.getEndpoint(path).pipe(
|
||||
isNotEmptyOperator(),
|
||||
map((endpoint: string) => `${endpoint}/${id}`),
|
||||
distinctUntilChanged()
|
||||
@@ -387,10 +458,4 @@ export class RegistryService {
|
||||
getResponseFromEntry()
|
||||
);
|
||||
}
|
||||
|
||||
public clearMetadataSchemaRequests(): Observable<string> {
|
||||
return this.halService.getEndpoint(this.metadataSchemasPath).pipe(
|
||||
tap((href: string) => this.requestService.removeByHrefSubstring(href))
|
||||
)
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user