[ADF-3442] create library dialog (#4018)

* library dialog

* integrate with demo shell

* update resources

* fix license

* auto focus for the first input

* update e2e tests

* try close the dialog between tests

* fix afterEach

* Revert "try close the dialog between tests"

This reverts commit 63464f2b03c226c606d09b18c7d2782e3bb52c0a.

* update code due to css lint issues

* csslint settings for vs code

* missing import
lint fix
remove not used import
convert errorPage js to ts
convert tasklistpage js to ts
fix redirection creation folder in root
fix lint issue
fix e2e

* e2e fix

* fix PS tests

* navigation import

* fix tests tooltip
convert paginapage to ts

* fix lint

* fix lock files e2e
filterspage to ts

* fix lint

* fix cs cre
git dept 3 and not 50 as default in travis

* quiet log git download

* add some delay and change the delete lock

* fix node entry

* convert searchDialog to typescript
parallel protractor

* disable browser execute

* restote test

* change search tests

* move search in a separate e2e folder

* experiment fix e2e

* change util presence
change protractor conf

* fix unshare test

* improve query viewerPage using css over xpath

* waitForAngularEnabled before browser redirect

* convert util to ts and more

* convert other files to ts

* convert to ts other files

* trigger build

* function fixes use arrow function

* process service fixes

* lint fix
review timeout default

* fix failing tests

* restore timeout

* share dialog fix

* remove

* use configuration admin

* fix APS 2 login sso
This commit is contained in:
Denys Vuika
2018-12-05 13:05:39 +00:00
committed by Eugenio Romano
parent 9fd564a78e
commit 058d23d57f
237 changed files with 8974 additions and 9201 deletions

View File

@@ -27,6 +27,7 @@ import { NodeLockDialogComponent } from './node-lock.dialog';
import { ConfirmDialogComponent } from './confirm.dialog';
import { MatDatetimepickerModule } from '@mat-datetimepicker/core';
import { MatMomentDatetimeModule } from '@mat-datetimepicker/moment';
import { LibraryDialogComponent } from './library/library.dialog';
@NgModule({
imports: [
@@ -42,19 +43,22 @@ import { MatMomentDatetimeModule } from '@mat-datetimepicker/moment';
DownloadZipDialogComponent,
FolderDialogComponent,
NodeLockDialogComponent,
ConfirmDialogComponent
ConfirmDialogComponent,
LibraryDialogComponent
],
exports: [
DownloadZipDialogComponent,
FolderDialogComponent,
NodeLockDialogComponent,
ConfirmDialogComponent
ConfirmDialogComponent,
LibraryDialogComponent
],
entryComponents: [
DownloadZipDialogComponent,
FolderDialogComponent,
NodeLockDialogComponent,
ConfirmDialogComponent
ConfirmDialogComponent,
LibraryDialogComponent
]
})
export class DialogModule {}

View File

@@ -0,0 +1,85 @@
<h2 mat-dialog-title>{{ createTitle | translate }}</h2>
<mat-dialog-content>
<form novalidate [formGroup]="form" (submit)="submit()">
<mat-form-field>
<input
placeholder="{{ 'LIBRARY.DIALOG.FORM.NAME' | translate }}"
required
matInput
autofocus
formControlName="title"
autocomplete="off"
/>
<mat-hint *ngIf="libraryTitleExists">{{
'LIBRARY.HINTS.SITE_TITLE_EXISTS' | translate
}}</mat-hint>
<mat-error *ngIf="form.controls['title'].hasError('maxlength')">
{{ 'LIBRARY.ERRORS.TITLE_TOO_LONG' | translate }}
</mat-error>
</mat-form-field>
<mat-form-field>
<input
required
placeholder="{{ 'LIBRARY.DIALOG.FORM.SITE_ID' | translate }}"
matInput
formControlName="id"
autocomplete="off"
/>
<mat-error *ngIf="form.controls['id'].errors?.message">
{{ form.controls['id'].errors?.message | translate }}
</mat-error>
<mat-error *ngIf="form.controls['id'].hasError('maxlength')">
{{ 'LIBRARY.ERRORS.ID_TOO_LONG' | translate }}
</mat-error>
</mat-form-field>
<mat-form-field>
<textarea
matInput
placeholder="{{ 'LIBRARY.DIALOG.FORM.DESCRIPTION' | translate }}"
rows="3"
formControlName="description"
></textarea>
<mat-error *ngIf="form.controls['description'].hasError('maxlength')">
{{ 'LIBRARY.ERRORS.DESCRIPTION_TOO_LONG' | translate }}
</mat-error>
</mat-form-field>
<mat-radio-group
[ngModelOptions]="{ standalone: true }"
[(ngModel)]="visibilityOption"
(change)="visibilityChangeHandler($event)"
>
<mat-radio-button
color="primary"
[disabled]="option.disabled"
*ngFor="let option of visibilityOptions"
[value]="option.value"
[checked]="visibilityOption.value === option.value"
>
{{ option.label | translate }}
</mat-radio-button>
</mat-radio-group>
</form>
</mat-dialog-content>
<mat-dialog-actions class="adf-action-buttons">
<button mat-button mat-dialog-close>
{{ 'LIBRARY.DIALOG.CANCEL' | translate }}
</button>
<button
color="primary"
mat-button
(click)="submit()"
[disabled]="!form.valid"
>
{{ 'LIBRARY.DIALOG.CREATE' | translate }}
</button>
</mat-dialog-actions>

View File

@@ -0,0 +1,29 @@
.adf-library-dialog {
.mat-radio-group {
display: flex;
flex-direction: column;
margin: 0 0 20px;
}
.mat-radio-group .mat-radio-button {
margin: 10px 0;
}
.mat-form-field {
width: 100%;
}
mat-form-field {
padding-top: 20px;
}
.adf-action-buttons {
display: flex;
flex-direction: row;
justify-content: flex-end;
.mat-button {
text-transform: uppercase;
}
}
}

View File

@@ -0,0 +1,198 @@
/*!
* @license
* Copyright 2016 Alfresco Software, Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import { NoopAnimationsModule } from '@angular/platform-browser/animations';
import { ReactiveFormsModule } from '@angular/forms';
import { CoreModule } from '@alfresco/adf-core';
import { LibraryDialogComponent } from './library.dialog';
import { TestBed, fakeAsync, tick, flush } from '@angular/core/testing';
import { NO_ERRORS_SCHEMA } from '@angular/core';
import { MatDialogRef } from '@angular/material';
import {
AlfrescoApiService,
AlfrescoApiServiceMock,
setupTestBed
} from '@alfresco/adf-core';
describe('LibraryDialogComponent', () => {
let fixture;
let component;
let alfrescoApi;
const dialogRef = {
close: jasmine.createSpy('close')
};
setupTestBed({
imports: [NoopAnimationsModule, CoreModule, ReactiveFormsModule],
declarations: [LibraryDialogComponent],
providers: [
{
provide: AlfrescoApiService,
useClass: AlfrescoApiServiceMock
},
{ provide: MatDialogRef, useValue: dialogRef }
],
schemas: [NO_ERRORS_SCHEMA]
});
beforeEach(() => {
fixture = TestBed.createComponent(LibraryDialogComponent);
component = fixture.componentInstance;
alfrescoApi = TestBed.get(AlfrescoApiService);
spyOn(
alfrescoApi.getInstance().core.queriesApi,
'findSites'
).and.returnValue(
Promise.resolve({
list: { entries: [] }
})
);
});
it('should set library id automatically on title input', fakeAsync(() => {
spyOn(alfrescoApi.sitesApi, 'getSite').and.callFake(() => {
return new Promise((resolve, reject) => reject());
});
fixture.detectChanges();
component.form.controls.title.setValue('libraryTitle');
tick(500);
flush();
fixture.detectChanges();
expect(component.form.controls.id.value).toBe('libraryTitle');
}));
it('should translate library title space character to dash for library id', fakeAsync(() => {
spyOn(alfrescoApi.sitesApi, 'getSite').and.callFake(() => {
return new Promise((resolve, reject) => reject());
});
fixture.detectChanges();
component.form.controls.title.setValue('library title');
tick(500);
flush();
fixture.detectChanges();
expect(component.form.controls.id.value).toBe('library-title');
}));
it('should not change custom library id on title input', fakeAsync(() => {
spyOn(alfrescoApi.sitesApi, 'getSite').and.callFake(() => {
return new Promise((resolve, reject) => reject());
});
fixture.detectChanges();
component.form.controls.id.setValue('custom-id');
component.form.controls.id.markAsDirty();
tick(500);
flush();
fixture.detectChanges();
component.form.controls.title.setValue('library title');
tick(500);
flush();
fixture.detectChanges();
expect(component.form.controls.id.value).toBe('custom-id');
}));
it('should invalidate form when library id already exists', fakeAsync(() => {
spyOn(alfrescoApi.sitesApi, 'getSite').and.returnValue(Promise.resolve());
fixture.detectChanges();
component.form.controls.id.setValue('existingLibrary');
tick(500);
flush();
fixture.detectChanges();
expect(component.form.controls.id.errors).toEqual({
message: 'LIBRARY.ERRORS.EXISTENT_SITE'
});
expect(component.form.valid).toBe(false);
}));
it('should create site when form is valid', fakeAsync(() => {
spyOn(alfrescoApi.sitesApi, 'createSite').and.returnValue(
Promise.resolve()
);
spyOn(alfrescoApi.sitesApi, 'getSite').and.callFake(() => {
return new Promise((resolve, reject) => reject());
});
fixture.detectChanges();
component.form.controls.title.setValue('library title');
tick(500);
flush();
fixture.detectChanges();
component.submit();
fixture.detectChanges();
flush();
expect(alfrescoApi.sitesApi.createSite).toHaveBeenCalledWith({
id: 'library-title',
title: 'library title',
description: '',
visibility: 'PUBLIC'
});
}));
it('should not create site when form is invalid', fakeAsync(() => {
spyOn(alfrescoApi.sitesApi, 'createSite').and.returnValue(
Promise.resolve({})
);
spyOn(alfrescoApi.sitesApi, 'getSite').and.returnValue(Promise.resolve());
fixture.detectChanges();
component.form.controls.title.setValue('existingLibrary');
tick(500);
flush();
fixture.detectChanges();
component.submit();
fixture.detectChanges();
flush();
expect(alfrescoApi.sitesApi.createSite).not.toHaveBeenCalled();
}));
it('should notify on 409 conflict error (might be in trash)', fakeAsync(() => {
const error = { message: '{ "error": { "statusCode": 409 } }' };
spyOn(alfrescoApi.sitesApi, 'createSite').and.callFake(() => {
return new Promise((resolve, reject) => reject(error));
});
spyOn(alfrescoApi.sitesApi, 'getSite').and.callFake(() => {
return new Promise((resolve, reject) => reject());
});
fixture.detectChanges();
component.form.controls.title.setValue('test');
tick(500);
flush();
fixture.detectChanges();
component.submit();
fixture.detectChanges();
flush();
expect(component.form.controls.id.errors).toEqual({
message: 'LIBRARY.ERRORS.CONFLICT'
});
}));
});

View File

@@ -0,0 +1,243 @@
/*!
* @license
* Copyright 2016 Alfresco Software, Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import { Observable, Subject, from } from 'rxjs';
import {
Component,
OnInit,
Output,
EventEmitter,
OnDestroy,
ViewEncapsulation
} from '@angular/core';
import {
FormBuilder,
FormGroup,
Validators,
FormControl,
AbstractControl
} from '@angular/forms';
import { MatDialogRef } from '@angular/material';
import { SiteBody, SiteEntry, SitePaging } from 'alfresco-js-api';
import { AlfrescoApiService } from '@alfresco/adf-core';
import { debounceTime, mergeMap, takeUntil } from 'rxjs/operators';
@Component({
selector: 'adf-library-dialog',
styleUrls: ['./library.dialog.scss'],
templateUrl: './library.dialog.html',
encapsulation: ViewEncapsulation.None,
host: { class: 'adf-library-dialog' }
})
export class LibraryDialogComponent implements OnInit, OnDestroy {
@Output()
error: EventEmitter<any> = new EventEmitter<any>();
@Output()
success: EventEmitter<any> = new EventEmitter<any>();
onDestroy$: Subject<boolean> = new Subject<boolean>();
createTitle = 'LIBRARY.DIALOG.CREATE_TITLE';
libraryTitleExists = false;
form: FormGroup;
visibilityOption: any;
visibilityOptions = [
{ value: 'PUBLIC', label: 'LIBRARY.VISIBILITY.PUBLIC', disabled: false },
{ value: 'PRIVATE', label: 'LIBRARY.VISIBILITY.PRIVATE', disabled: false },
{
value: 'MODERATED',
label: 'LIBRARY.VISIBILITY.MODERATED',
disabled: false
}
];
constructor(
private alfrescoApiService: AlfrescoApiService,
private formBuilder: FormBuilder,
private dialog: MatDialogRef<LibraryDialogComponent>
) {}
ngOnInit() {
const validators = {
id: [
Validators.required,
Validators.maxLength(72),
this.forbidSpecialCharacters
],
title: [Validators.required, Validators.maxLength(256)],
description: [Validators.maxLength(512)]
};
this.form = this.formBuilder.group({
title: ['', validators.title],
id: ['', validators.id, this.createSiteIdValidator()],
description: ['', validators.description]
});
this.visibilityOption = this.visibilityOptions[0].value;
this.form.controls['title'].valueChanges
.pipe(
debounceTime(300),
mergeMap(
(title) => this.checkLibraryNameExists(title),
(title) => title
),
takeUntil(this.onDestroy$)
)
.subscribe((title: string) => {
if (!title.trim().length) {
return;
}
if (!this.form.controls['id'].dirty) {
this.form.patchValue({ id: this.sanitize(title.trim()) });
this.form.controls['id'].markAsTouched();
}
});
}
ngOnDestroy() {
this.onDestroy$.next(true);
this.onDestroy$.complete();
}
get title(): string {
const { title } = this.form.value;
return (title || '').trim();
}
get id(): string {
const { id } = this.form.value;
return (id || '').trim();
}
get description(): string {
const { description } = this.form.value;
return (description || '').trim();
}
get visibility(): string {
return this.visibilityOption || '';
}
submit() {
const { form, dialog } = this;
if (!form.valid) {
return;
}
this.create().subscribe(
(node: SiteEntry) => {
this.success.emit(node);
dialog.close(node);
},
(error) => this.handleError(error)
);
}
visibilityChangeHandler(event) {
this.visibilityOption = event.value;
}
private create(): Observable<SiteEntry> {
const { title, id, description, visibility } = this;
const siteBody = <SiteBody> {
id,
title,
description,
visibility
};
return from(this.alfrescoApiService.sitesApi.createSite(siteBody));
}
private sanitize(input: string) {
return input.replace(/[\s]/g, '-').replace(/[^A-Za-z0-9-]/g, '');
}
private handleError(error: any): any {
const {
error: { statusCode }
} = JSON.parse(error.message);
if (statusCode === 409) {
this.form.controls['id'].setErrors({
message: 'LIBRARY.ERRORS.CONFLICT'
});
}
return error;
}
private async checkLibraryNameExists(libraryTitle: string) {
const { entries } = (await this.findLibraryByTitle(libraryTitle)).list;
if (entries.length) {
this.libraryTitleExists = entries[0].entry.title === libraryTitle;
} else {
this.libraryTitleExists = false;
}
}
private findLibraryByTitle(libraryTitle: string): Promise<SitePaging> {
return this.alfrescoApiService
.getInstance()
.core.queriesApi.findSites(libraryTitle, {
maxItems: 1,
fields: ['title']
})
.catch(() => ({ list: { entries: [] } }));
}
private forbidSpecialCharacters({ value }: FormControl) {
const validCharacters: RegExp = /[^A-Za-z0-9-]/;
const isValid: boolean = !validCharacters.test(value);
return isValid
? null
: {
message: 'LIBRARY.ERRORS.ILLEGAL_CHARACTERS'
};
}
private createSiteIdValidator() {
let timer;
return (control: AbstractControl) => {
if (timer) {
clearTimeout(timer);
}
return new Promise((resolve) => {
timer = setTimeout(() => {
return from(
this.alfrescoApiService.sitesApi.getSite(control.value)
).subscribe(
() => resolve({ message: 'LIBRARY.ERRORS.EXISTENT_SITE' }),
() => resolve(null)
);
}, 300);
});
};
}
}

View File

@@ -5,7 +5,7 @@
<mat-dialog-content>
<br />
<form [formGroup]="form" (submit)="submit()">
<mat-checkbox class="adf-lock-file-name" [formControl]="form.controls['isLocked']" ngDefaultControl>
<mat-checkbox data-automation-id="adf-lock-node-checkbox" class="adf-lock-file-name" [formControl]="form.controls['isLocked']" ngDefaultControl>
{{ 'CORE.FILE_DIALOG.FILE_LOCK_CHECKBOX' | translate }} <strong>"{{ nodeName }}"</strong>
</mat-checkbox>

View File

@@ -21,3 +21,4 @@ export * from './node-lock.dialog';
export * from './confirm.dialog';
export * from './dialog.module';
export * from './library/library.dialog';

View File

@@ -287,5 +287,31 @@
"DUPLICATE-PERMISSION": "Mindestens eine der von Ihnen bestimmten Berechtigungen ist bereits vorhanden: {{list}}",
"NOT-ALLOWED": "Sie sind nicht zum Ändern von Berechtigungen berechtigt."
}
},
"LIBRARY": {
"DIALOG": {
"CREATE_TITLE": "Bibliothek erstellen",
"CREATE": "Erstellen",
"CANCEL": "Abbrechen",
"FORM": {
"DESCRIPTION": "Beschreibung",
"SITE_ID": "Bibliotheks-ID",
"NAME": "Name"
}
},
"VISIBILITY": {
"PRIVATE": "Privat",
"PUBLIC": "Öffentlich",
"MODERATED": "Moderiert"
},
"ERRORS": {
"GENERIC": "Es ist ein Problem aufgetreten",
"EXISTENT_SITE": "Diese Bibliotheks-ID ist nicht verfügbar. Versuchen Sie es mit einer anderen Bibliothek.",
"CONFLICT": "Diese Bibliotheks-ID wird bereits verwendet. Sehen Sie im Papierkorb nach.",
"ID_TOO_LONG": "Der URL-Name darf höchstens 72 Zeichen lang sein",
"DESCRIPTION_TOO_LONG": "Die Beschreibung darf höchstens 512 Zeichen lang sein",
"TITLE_TOO_LONG": "Der Titel darf höchstens 256 Zeichen lang sein",
"ILLEGAL_CHARACTERS": "Verwenden Sie nur Zahlen und Buchstaben"
}
}
}

View File

@@ -292,5 +292,41 @@
},
"ADF-TREE-VIEW": {
"MISSING-ID": "No nodeId provided!"
},
"LIBRARY": {
"DIALOG": {
"CREATE_TITLE": "Create Library",
"CREATE": "Create",
"UPDATE": "Update",
"EDIT": "Edit",
"CANCEL": "Cancel",
"FORM": {
"DESCRIPTION": "Description",
"SITE_ID": "Library ID",
"NAME": "Name",
"VISIBILITY": "Visibility"
}
},
"VISIBILITY": {
"PRIVATE": "Private",
"PUBLIC": "Public",
"MODERATED": "Moderated"
},
"HINTS": {
"SITE_TITLE_EXISTS": "Library name already in use"
},
"ERRORS": {
"GENERIC": "We hit a problem",
"EXISTENT_SITE": "This Library ID isn't available. Try a different Library ID.",
"CONFLICT": "This Library ID is already used. Check the trashcan.",
"ID_TOO_LONG": "Use 72 characters or less for the URL name",
"DESCRIPTION_TOO_LONG": "Use 512 characters or less for description",
"TITLE_TOO_LONG": "Use 256 characters or less for title",
"ILLEGAL_CHARACTERS": "Use numbers and letters only",
"LIBRARY_UPDATE_ERROR": "There was an error updating library properties"
},
"SUCCESS": {
"LIBRARY_UPDATED": "Library properties updated"
}
}
}

View File

@@ -287,5 +287,31 @@
"DUPLICATE-PERMISSION": "Uno o más de los permisos que ha establecido ya existe: {{list}}",
"NOT-ALLOWED": "No puede cambiar los permisos"
}
},
"LIBRARY": {
"DIALOG": {
"CREATE_TITLE": "Crear biblioteca",
"CREATE": "Crear",
"CANCEL": "Cancelar",
"FORM": {
"DESCRIPTION": "Descripción",
"SITE_ID": "ID de biblioteca",
"NAME": "Nombre"
}
},
"VISIBILITY": {
"PRIVATE": "Lista privada",
"PUBLIC": "Público",
"MODERATED": "Moderado"
},
"ERRORS": {
"GENERIC": "Se ha producido un error",
"EXISTENT_SITE": "La ID de biblioteca no está disponible. Pruebe una biblioteca diferente.",
"CONFLICT": "Esta ID de biblioteca ya está utilizada. Compruebe la papelera.",
"ID_TOO_LONG": "Utilice como máximo 72 caracteres para el nombre de la URL",
"DESCRIPTION_TOO_LONG": "Utilice como máximo 512 caracteres para la descripción",
"TITLE_TOO_LONG": "Utilice como máximo 256 caracteres para el título",
"ILLEGAL_CHARACTERS": "Use solo números y letras"
}
}
}

View File

@@ -287,5 +287,31 @@
"DUPLICATE-PERMISSION": "Un ou plusieurs droits d'accès définis existent déjà : {{list}}",
"NOT-ALLOWED": "Vous n'avez pas le droit de modifier les droits d'accès"
}
},
"LIBRARY": {
"DIALOG": {
"CREATE_TITLE": "Créer une Bibliothèque",
"CREATE": "Créer",
"CANCEL": "Annuler",
"FORM": {
"DESCRIPTION": "Description",
"SITE_ID": "ID de Bibliothèque",
"NAME": "Nom"
}
},
"VISIBILITY": {
"PRIVATE": "Liste privée",
"PUBLIC": "Public",
"MODERATED": "Modéré"
},
"ERRORS": {
"GENERIC": "Une erreur est survenue",
"EXISTENT_SITE": "Cet ID de Bibliothèque est indisponible. Essayez avec une autre Bibliothèque.",
"CONFLICT": "Cet ID de Bibliothèque est déjà utilisé. Vérifiez la corbeille.",
"ID_TOO_LONG": "L'URL doit contenir 72 caractères maximum",
"DESCRIPTION_TOO_LONG": "La description doit contenir 512 caractères maximum",
"TITLE_TOO_LONG": "Le titre doit contenir 256 caractères maximum",
"ILLEGAL_CHARACTERS": "Utilisez uniquement des chiffres et des lettres"
}
}
}

View File

@@ -287,5 +287,31 @@
"DUPLICATE-PERMISSION": "Uno o più autorizzazioni impostate sono già presenti: {{list}}",
"NOT-ALLOWED": "Non è consentito modificare le autorizzazioni"
}
},
"LIBRARY": {
"DIALOG": {
"CREATE_TITLE": "Crea libreria",
"CREATE": "Crea",
"CANCEL": "Annulla",
"FORM": {
"DESCRIPTION": "Descrizione",
"SITE_ID": "ID libreria",
"NAME": "Nome"
}
},
"VISIBILITY": {
"PRIVATE": "Privato",
"PUBLIC": "Pubblico",
"MODERATED": "Moderato"
},
"ERRORS": {
"GENERIC": "Si è verificato un errore",
"EXISTENT_SITE": "L'ID libreria specificato non è disponibile. Provare con un'altra libreria.",
"CONFLICT": "L'ID libreria specificato è già in uso. Verificare il cestino.",
"ID_TOO_LONG": "Utilizzare 72 caratteri o meno per il nome URL",
"DESCRIPTION_TOO_LONG": "Utilizzare 512 o meno per la descrizione",
"TITLE_TOO_LONG": "Utilizzare 256 caratteri o meno per il titolo",
"ILLEGAL_CHARACTERS": "Utilizzare solo lettere e numeri"
}
}
}

View File

@@ -287,5 +287,31 @@
"DUPLICATE-PERMISSION": "設定済みの権限が既にあります: {{list}}",
"NOT-ALLOWED": "権限を変更することはできません"
}
},
"LIBRARY": {
"DIALOG": {
"CREATE_TITLE": "ライブラリの作成",
"CREATE": "作成",
"CANCEL": "キャンセル",
"FORM": {
"DESCRIPTION": "説明",
"SITE_ID": "ライブラリ ID",
"NAME": "名前"
}
},
"VISIBILITY": {
"PRIVATE": "非公開",
"PUBLIC": "公開",
"MODERATED": "条件付き公開"
},
"ERRORS": {
"GENERIC": "問題が発生しました",
"EXISTENT_SITE": "このライブラリ ID は使用できません。別のライブラリを使用してください。",
"CONFLICT": "このライブラリ ID は既に使われています。ごみ箱をチェックしてください。",
"ID_TOO_LONG": "URL 名は 72 文字以内で入力してください",
"DESCRIPTION_TOO_LONG": "説明は 512 文字以内で入力してください",
"TITLE_TOO_LONG": "タイトルは 256 文字以内で入力してください",
"ILLEGAL_CHARACTERS": "英数字だけを使用してください"
}
}
}

View File

@@ -287,5 +287,31 @@
"DUPLICATE-PERMISSION": "Én eller flere av tillatelsene du har angitt, er allerede til stede: {{list}}",
"NOT-ALLOWED": "Du har ikke lov til å endre tillatelser"
}
},
"LIBRARY": {
"DIALOG": {
"CREATE_TITLE": "Opprett bibliotek",
"CREATE": "Opprett",
"CANCEL": "Avbryt",
"FORM": {
"DESCRIPTION": "Beskrivelse",
"SITE_ID": "Biblioteks-ID",
"NAME": "Navn"
}
},
"VISIBILITY": {
"PRIVATE": "Privat",
"PUBLIC": "Offentlig",
"MODERATED": "Moderert"
},
"ERRORS": {
"GENERIC": "Vi støtte på et problem",
"EXISTENT_SITE": "Denne biblioteks-ID-en er ikke tilgjengelig. Prøv et annet bibliotek.",
"CONFLICT": "Denne biblioteks-ID-en er alt brukt. Sjekk papirkurven.",
"ID_TOO_LONG": "Bruk 72 tegn eller mindre i URL-navnet",
"DESCRIPTION_TOO_LONG": "Bruk 512 tegn eller mindre i beskrivelsen",
"TITLE_TOO_LONG": "Bruk 256 tegn eller mindre i tittelen",
"ILLEGAL_CHARACTERS": "Bruk kun tall og bokstaver"
}
}
}

View File

@@ -287,5 +287,31 @@
"DUPLICATE-PERMISSION": "Een of meerdere machtigingen die u hebt ingesteld zijn al aanwezig: {{list}}",
"NOT-ALLOWED": "Het is u niet toegestaan om machtigingen te wijzigen"
}
},
"LIBRARY": {
"DIALOG": {
"CREATE_TITLE": "Bibliotheek maken",
"CREATE": "Maken",
"CANCEL": "Annuleren",
"FORM": {
"DESCRIPTION": "Beschrijving",
"SITE_ID": "Bibliotheek-id",
"NAME": "Naam"
}
},
"VISIBILITY": {
"PRIVATE": "Privé",
"PUBLIC": "Openbaar",
"MODERATED": "Onder toezicht"
},
"ERRORS": {
"GENERIC": "Er is een probleem opgetreden",
"EXISTENT_SITE": "Deze bibliotheek-id is niet beschikbaar. Probeer een andere bibliotheek.",
"CONFLICT": "Deze bibliotheek wordt al gebruikt. Controleer de prullenbak.",
"ID_TOO_LONG": "Gebruik 72 tekens of minder voor de URL-naam",
"DESCRIPTION_TOO_LONG": "Gebruik 512 tekens of minder voor de beschrijving",
"TITLE_TOO_LONG": "Gebruik 256 tekens of minder voor de titel",
"ILLEGAL_CHARACTERS": "Gebruik alleen cijfers en letters"
}
}
}

View File

@@ -287,5 +287,31 @@
"DUPLICATE-PERMISSION": "Uma ou mais permissões definidas já está presente: {{list}}",
"NOT-ALLOWED": "Você não pode alterar permissões"
}
},
"LIBRARY": {
"DIALOG": {
"CREATE_TITLE": "Criar Biblioteca",
"CREATE": "Criar",
"CANCEL": "Cancelar",
"FORM": {
"DESCRIPTION": "Descrição",
"SITE_ID": "ID de Biblioteca",
"NAME": "Nome"
}
},
"VISIBILITY": {
"PRIVATE": "Privado",
"PUBLIC": "Público",
"MODERATED": "Moderado"
},
"ERRORS": {
"GENERIC": "Ocorreu um erro",
"EXISTENT_SITE": "Este ID de Biblioteca não está disponível. Tente uma Biblioteca diferente.",
"CONFLICT": "Este ID de Biblioteca já foi usado. Verifique a lixeira.",
"ID_TOO_LONG": "Use 72 caracteres ou menos para o nome da URL",
"DESCRIPTION_TOO_LONG": "Use 512 caracteres ou menos para a descrição",
"TITLE_TOO_LONG": "Use 256 caracteres ou menos para o título",
"ILLEGAL_CHARACTERS": "Use somente números e letras"
}
}
}

View File

@@ -287,5 +287,31 @@
"DUPLICATE-PERMISSION": "Одно или несколько установленных вами разрешений уже присутствует: {{list}}",
"NOT-ALLOWED": "У вас нет прав на изменение разрешений"
}
},
"LIBRARY": {
"DIALOG": {
"CREATE_TITLE": "Создание библиотеки",
"CREATE": "Создать",
"CANCEL": "Отмена",
"FORM": {
"DESCRIPTION": "Описание",
"SITE_ID": "Идентификатор библиотеки",
"NAME": "Имя"
}
},
"VISIBILITY": {
"PRIVATE": "Частный",
"PUBLIC": "Общедоступный",
"MODERATED": "Модерируемый"
},
"ERRORS": {
"GENERIC": "Возникла проблема",
"EXISTENT_SITE": "Идентификатор библиотеки недоступен. Попробуйте использовать другую библиотеку.",
"CONFLICT": "Этот идентификатор библиотеки уже используется. Проверьте корзину.",
"ID_TOO_LONG": "Имя URL должно содержать не более 72 символов",
"DESCRIPTION_TOO_LONG": "Описание должно содержать не более 512 символов",
"TITLE_TOO_LONG": "Название должно содержать не более 256 символов",
"ILLEGAL_CHARACTERS": "Используйте только буквы и цифры"
}
}
}

View File

@@ -287,5 +287,31 @@
"DUPLICATE-PERMISSION": "您所设置的一个或多个权限已经存在:{{list}}",
"NOT-ALLOWED": "不允许更改权限"
}
},
"LIBRARY": {
"DIALOG": {
"CREATE_TITLE": "创建库",
"CREATE": "创建",
"CANCEL": "取消",
"FORM": {
"DESCRIPTION": "说明",
"SITE_ID": "库 ID",
"NAME": "名称"
}
},
"VISIBILITY": {
"PRIVATE": "私有",
"PUBLIC": "公共",
"MODERATED": "适中"
},
"ERRORS": {
"GENERIC": "我们遇到了问题",
"EXISTENT_SITE": "此库 ID 不可用。请尝试使用其他库。",
"CONFLICT": "此库 ID 已被使用。请检查回收站。",
"ID_TOO_LONG": "对 URL 名称使用 72 个字符或更少字符",
"DESCRIPTION_TOO_LONG": "对描述使用 512 个字符或更少字符",
"TITLE_TOO_LONG": "对标题使用 256 个字符或更少字符",
"ILLEGAL_CHARACTERS": "仅使用数字和字母"
}
}
}

View File

@@ -1,4 +1,4 @@
<div class="adf-search-container">
<div class="adf-search-container" [attr.state]="subscriptAnimationState">
<div *ngIf="isLoggedIn()" [@transitionMessages]="subscriptAnimationState"
(@transitionMessages.done)="applySearchFocus($event)">
<button mat-icon-button