mirror of
https://github.com/DSpace/dspace-angular.git
synced 2025-10-13 13:03:04 +00:00
97075: Margin fixes + metadata field autofocus and validation
This commit is contained in:
@@ -1,18 +1,18 @@
|
||||
<div class="item-metadata" *ngIf="form">
|
||||
<div class="button-row top d-flex my-2 space-children-mr">
|
||||
<div class="button-row top d-flex my-2 space-children-mr ml-gap">
|
||||
<button class="mr-auto btn btn-success" [disabled]="form.newValue || (saving$ | async)"
|
||||
(click)="add()"><i class="fas fa-plus"></i>
|
||||
<span class="d-none d-sm-inline"> {{ dsoType + '.edit.metadata.add-button' | translate }}</span>
|
||||
</button>
|
||||
<button class="btn btn-warning ml-2" *ngIf="isReinstatable" [disabled]="(saving$ | async)"
|
||||
<button class="btn btn-warning ml-1" *ngIf="isReinstatable" [disabled]="(saving$ | async)"
|
||||
(click)="reinstate()"><i class="fas fa-undo-alt"></i>
|
||||
<span class="d-none d-sm-inline"> {{ dsoType + '.edit.metadata.reinstate-button' | translate }}</span>
|
||||
</button>
|
||||
<button class="btn btn-primary ml-2" [disabled]="!hasChanges || (saving$ | async)"
|
||||
<button class="btn btn-primary ml-1" [disabled]="!hasChanges || (saving$ | async)"
|
||||
(click)="submit()"><i class="fas fa-save"></i>
|
||||
<span class="d-none d-sm-inline"> {{ dsoType + '.edit.metadata.save-button' | translate }}</span>
|
||||
</button>
|
||||
<button class="btn btn-danger ml-2" *ngIf="!isReinstatable"
|
||||
<button class="btn btn-danger ml-1" *ngIf="!isReinstatable"
|
||||
[disabled]="!hasChanges || (saving$ | async)"
|
||||
(click)="discard()"><i class="fas fa-times"></i>
|
||||
<span class="d-none d-sm-inline"> {{ dsoType + '.edit.metadata.discard-button' | translate }}</span>
|
||||
@@ -31,10 +31,10 @@
|
||||
</div>
|
||||
<div class="d-flex flex-row ds-field-row" *ngIf="form.newValue">
|
||||
<div class="lbl-cell ds-success">
|
||||
<ds-metadata-field-selector [(mdField)]="newMdField"></ds-metadata-field-selector>
|
||||
<ds-metadata-field-selector [(mdField)]="newMdField" [autofocus]="true"></ds-metadata-field-selector>
|
||||
</div>
|
||||
<div class="flex-grow-1 ds-drop-list">
|
||||
<div class="d-flex flex-row ds-value-row ds-success">
|
||||
<div class="d-flex flex-row ds-value-row ds-success h-100">
|
||||
<div class="flex-grow-1 ds-flex-cell ds-value-cell d-flex align-items-center">
|
||||
<textarea class="form-control" rows="2" [(ngModel)]="form.newValue.newValue.value"></textarea>
|
||||
</div>
|
||||
@@ -44,16 +44,19 @@
|
||||
<div class="text-center ds-flex-cell ds-edit-cell">
|
||||
<div class="btn-group edit-field">
|
||||
<button class="btn btn-outline-success btn-sm ng-star-inserted" ngbTooltip="Confirm changes"
|
||||
[disabled]="!newMdField || (saving$ | async)" (click)="form.setMetadataField(newMdField); onValueSaved()">
|
||||
[disabled]="!newMdField || (saving$ | async) || (loadingFieldValidation$ | async)" (click)="setMetadataField()">
|
||||
<i class="fas fa-check fa-fw"></i>
|
||||
</button>
|
||||
<button class="btn btn-outline-danger btn-sm" ngbTooltip="Remove" [disabled]="true">
|
||||
<button class="btn btn-outline-danger btn-sm" ngbTooltip="Remove"
|
||||
[disabled]="true">
|
||||
<i class="fas fa-trash-alt fa-fw"></i>
|
||||
</button>
|
||||
<button class="btn btn-outline-warning btn-sm" ngbTooltip="Undo changes" [disabled]="(saving$ | async)" (click)="form.newValue = undefined">
|
||||
<button class="btn btn-outline-warning btn-sm" ngbTooltip="Undo changes"
|
||||
[disabled]="(saving$ | async) || (loadingFieldValidation$ | async)" (click)="form.newValue = undefined">
|
||||
<i class="fas fa-undo-alt fa-fw"></i>
|
||||
</button>
|
||||
<button class="btn btn-outline-secondary ds-drag-handle btn-sm disabled" ngbTooltip="Drag to reorder" [disabled]="true">
|
||||
<button class="btn btn-outline-secondary ds-drag-handle btn-sm disabled" ngbTooltip="Drag to reorder"
|
||||
[disabled]="true">
|
||||
<i class="fas fa-grip-vertical fa-fw"></i>
|
||||
</button>
|
||||
</div>
|
||||
@@ -109,15 +112,15 @@
|
||||
<div *ngIf="isEmpty">
|
||||
<ds-alert [content]="dsoType + '.edit.metadata.empty'" [type]="AlertTypeEnum.Info"></ds-alert>
|
||||
</div>
|
||||
<div class="button-row bottom">
|
||||
<div class="button-row bottom d-inline-block w-100">
|
||||
<div class="mt-2 float-right space-children-mr ml-gap">
|
||||
<button class="btn btn-warning ml-2" *ngIf="isReinstatable" [disabled]="(saving$ | async)"
|
||||
<button class="btn btn-warning" *ngIf="isReinstatable" [disabled]="(saving$ | async)"
|
||||
(click)="reinstate()"><i class="fas fa-undo-alt"></i> {{ dsoType + '.edit.metadata.reinstate-button' | translate }}
|
||||
</button>
|
||||
<button class="btn btn-primary ml-2" [disabled]="!hasChanges || (saving$ | async)"
|
||||
<button class="btn btn-primary" [disabled]="!hasChanges || (saving$ | async)"
|
||||
(click)="submit()"><i class="fas fa-save"></i> {{ dsoType + '.edit.metadata.save-button' | translate }}
|
||||
</button>
|
||||
<button class="btn btn-danger ml-2" *ngIf="!isReinstatable"
|
||||
<button class="btn btn-danger" *ngIf="!isReinstatable"
|
||||
[disabled]="!hasChanges || (saving$ | async)"
|
||||
(click)="discard()"><i class="fas fa-times"></i> {{ dsoType + '.edit.metadata.discard-button' | translate }}
|
||||
</button>
|
||||
|
@@ -1,7 +1,7 @@
|
||||
import { Component, Injector, Input, OnDestroy, OnInit } from '@angular/core';
|
||||
import { Component, Injector, Input, OnDestroy, OnInit, ViewChild } from '@angular/core';
|
||||
import { AlertType } from '../../shared/alert/aletr-type';
|
||||
import { DSpaceObject } from '../../core/shared/dspace-object.model';
|
||||
import { DsoEditMetadataChangeType, DsoEditMetadataForm } from './dso-edit-metadata-form';
|
||||
import { DsoEditMetadataChangeType, DsoEditMetadataForm, DsoEditMetadataValue } from './dso-edit-metadata-form';
|
||||
import { map, switchMap } from 'rxjs/operators';
|
||||
import { ActivatedRoute, Data } from '@angular/router';
|
||||
import { combineLatest as observableCombineLatest } from 'rxjs/internal/observable/combineLatest';
|
||||
@@ -23,6 +23,7 @@ import { ResourceType } from '../../core/shared/resource-type';
|
||||
import { NotificationsService } from '../../shared/notifications/notifications.service';
|
||||
import { TranslateService } from '@ngx-translate/core';
|
||||
import { DataService } from '../../core/data/data.service';
|
||||
import { MetadataFieldSelectorComponent } from './metadata-field-selector/metadata-field-selector.component';
|
||||
|
||||
@Component({
|
||||
selector: 'ds-dso-edit-metadata',
|
||||
@@ -31,6 +32,7 @@ import { DataService } from '../../core/data/data.service';
|
||||
})
|
||||
export class DsoEditMetadataComponent implements OnInit, OnDestroy {
|
||||
@Input() dso: DSpaceObject;
|
||||
@ViewChild(MetadataFieldSelectorComponent) metadataFieldSelectorComponent: MetadataFieldSelectorComponent;
|
||||
updateDataService: UpdateDataService<DSpaceObject>;
|
||||
dsoType: string;
|
||||
|
||||
@@ -41,6 +43,7 @@ export class DsoEditMetadataComponent implements OnInit, OnDestroy {
|
||||
hasChanges: boolean;
|
||||
isEmpty: boolean;
|
||||
saving$: BehaviorSubject<boolean> = new BehaviorSubject<boolean>(false);
|
||||
loadingFieldValidation$: BehaviorSubject<boolean> = new BehaviorSubject<boolean>(false);
|
||||
|
||||
/**
|
||||
* The AlertType enumeration for access in the component's template
|
||||
@@ -120,6 +123,17 @@ export class DsoEditMetadataComponent implements OnInit, OnDestroy {
|
||||
});
|
||||
}
|
||||
|
||||
setMetadataField() {
|
||||
this.loadingFieldValidation$.next(true);
|
||||
this.metadataFieldSelectorComponent.validate().subscribe((valid) => {
|
||||
this.loadingFieldValidation$.next(false);
|
||||
if (valid) {
|
||||
this.form.setMetadataField(this.newMdField);
|
||||
this.onValueSaved();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
add(): void {
|
||||
this.newMdField = undefined;
|
||||
this.form.add();
|
||||
|
@@ -1,11 +1,12 @@
|
||||
<div class="w-100 position-relative">
|
||||
<input type="text"
|
||||
class="form-control"
|
||||
<input type="text" #mdFieldInput
|
||||
class="form-control" [ngClass]="{ 'is-invalid': showInvalid }"
|
||||
[value]="mdField"
|
||||
[formControl]="input"
|
||||
(focusin)="query$.next(mdField)"
|
||||
(dsClickOutside)="query$.next(null)"
|
||||
(click)="$event.stopPropagation();" />
|
||||
<div class="invalid-feedback show-feedback" *ngIf="showInvalid">Invalid metadata field, please pick an existing one from the suggestions when searching</div>
|
||||
<div class="autocomplete dropdown-menu" [ngClass]="{'show': (mdFieldOptions$ | async)?.length > 0}">
|
||||
<div class="dropdown-list">
|
||||
<div *ngFor="let mdFieldOption of (mdFieldOptions$ | async)">
|
||||
|
@@ -1,15 +1,25 @@
|
||||
import { Component, EventEmitter, Input, OnDestroy, OnInit, Output } from '@angular/core';
|
||||
import { switchMap, debounceTime, distinctUntilChanged } from 'rxjs/operators';
|
||||
import {
|
||||
AfterViewInit,
|
||||
Component,
|
||||
ElementRef,
|
||||
EventEmitter,
|
||||
Input,
|
||||
OnDestroy,
|
||||
OnInit,
|
||||
Output,
|
||||
ViewChild
|
||||
} from '@angular/core';
|
||||
import { switchMap, debounceTime, distinctUntilChanged, map, tap, take } from 'rxjs/operators';
|
||||
import { followLink } from '../../../shared/utils/follow-link-config.model';
|
||||
import {
|
||||
getAllSucceededRemoteData,
|
||||
getAllSucceededRemoteData, getFirstCompletedRemoteData, getFirstSucceededRemoteData,
|
||||
metadataFieldsToString
|
||||
} from '../../../core/shared/operators';
|
||||
import { Observable } from 'rxjs/internal/Observable';
|
||||
import { RegistryService } from '../../../core/registry/registry.service';
|
||||
import { FormControl } from '@angular/forms';
|
||||
import { BehaviorSubject } from 'rxjs/internal/BehaviorSubject';
|
||||
import { hasValue } from '../../../shared/empty.util';
|
||||
import { hasValue, isNotEmpty } from '../../../shared/empty.util';
|
||||
import { Subscription } from 'rxjs/internal/Subscription';
|
||||
|
||||
@Component({
|
||||
@@ -17,9 +27,11 @@ import { Subscription } from 'rxjs/internal/Subscription';
|
||||
styleUrls: ['./metadata-field-selector.component.scss'],
|
||||
templateUrl: './metadata-field-selector.component.html'
|
||||
})
|
||||
export class MetadataFieldSelectorComponent implements OnInit, OnDestroy {
|
||||
export class MetadataFieldSelectorComponent implements OnInit, OnDestroy, AfterViewInit {
|
||||
@Input() mdField: string;
|
||||
@Input() autofocus = false;
|
||||
@Output() mdFieldChange = new EventEmitter<string>();
|
||||
@ViewChild('mdFieldInput', { static: true }) mdFieldInput: ElementRef;
|
||||
mdFieldOptions$: Observable<string[]>;
|
||||
|
||||
public input: FormControl = new FormControl();
|
||||
@@ -27,6 +39,7 @@ export class MetadataFieldSelectorComponent implements OnInit, OnDestroy {
|
||||
query$: BehaviorSubject<string> = new BehaviorSubject<string>(null);
|
||||
debounceTime = 300;
|
||||
selectedValueLoading = false;
|
||||
showInvalid = false;
|
||||
|
||||
subs: Subscription[] = [];
|
||||
|
||||
@@ -49,6 +62,7 @@ export class MetadataFieldSelectorComponent implements OnInit, OnDestroy {
|
||||
this.mdFieldOptions$ = this.query$.pipe(
|
||||
distinctUntilChanged(),
|
||||
switchMap((query) => {
|
||||
this.showInvalid = false;
|
||||
if (query !== null) {
|
||||
return this.registryService.queryMetadataFields(query, null, true, false, followLink('schema')).pipe(
|
||||
getAllSucceededRemoteData(),
|
||||
@@ -61,6 +75,20 @@ export class MetadataFieldSelectorComponent implements OnInit, OnDestroy {
|
||||
);
|
||||
}
|
||||
|
||||
ngAfterViewInit(): void {
|
||||
this.mdFieldInput.nativeElement.focus();
|
||||
}
|
||||
|
||||
validate(): Observable<boolean> {
|
||||
return this.registryService.queryMetadataFields(this.mdField, null, true, false, followLink('schema')).pipe(
|
||||
getFirstSucceededRemoteData(),
|
||||
metadataFieldsToString(),
|
||||
take(1),
|
||||
map((fields: string[]) => fields.indexOf(this.mdField) > -1),
|
||||
tap((exists) => this.showInvalid = !exists),
|
||||
);
|
||||
}
|
||||
|
||||
select(mdFieldOption: string) {
|
||||
this.selectedValueLoading = true;
|
||||
this.input.setValue(mdFieldOption);
|
||||
|
Reference in New Issue
Block a user