[ADF-4496] Share dialog enhancements (#4705)

* raise snackbars on unshare errors

* remove time from datepicker

* update tests

* Update en.json

* code updates as per review

* update docs

* bind datetimepicker type attribute

* set datetimepicker type by configuration or default

* tests

* e2e test

* update docs

* e2e set sharedLinkDateTimePickerType config
This commit is contained in:
Denys Vuika
2019-06-06 16:32:36 +01:00
committed by Eugenio Romano
parent c3b1300d86
commit 99f4b07878
24 changed files with 381 additions and 121 deletions
@@ -1,6 +1,5 @@
<div class="adf-share-link__dialog-content">
<h1 data-automation-id="adf-share-dialog-title"
class="adf-share-link__title">
<h1 data-automation-id="adf-share-dialog-title" class="adf-share-link__title">
{{ 'SHARE.DIALOG-TITLE' | translate }} {{ fileName }}
</h1>
@@ -10,50 +9,47 @@
<div class="adf-share-link--row">
<h1 class="adf-share-link__label">{{ 'SHARE.TITLE' | translate }}</h1>
<mat-slide-toggle
color="primary"
data-automation-id="adf-share-toggle"
[checked]="isFileShared"
[disabled]="!canUpdate || isDisabled"
(change)="onSlideShareChange($event)">
<mat-slide-toggle color="primary" data-automation-id="adf-share-toggle" [checked]="isFileShared"
[disabled]="!canUpdate || isDisabled" (change)="onSlideShareChange($event)">
</mat-slide-toggle>
</div>
<form [formGroup]="form">
<mat-form-field class="adf-full-width">
<input #sharedLinkInput
data-automation-id="adf-share-link"
class="adf-share-link__input"
matInput
cdkFocusInitial
placeholder="{{ 'SHARE.PUBLIC-LINK' | translate }}"
formControlName="sharedUrl"
<input #sharedLinkInput data-automation-id="adf-share-link" class="adf-share-link__input" matInput
cdkFocusInitial placeholder="{{ 'SHARE.PUBLIC-LINK' | translate }}" formControlName="sharedUrl"
readonly="readonly">
<mat-icon class="adf-input-action" matSuffix
[clipboard-notification]="'SHARE.CLIPBOARD-MESSAGE' | translate"
[adf-clipboard] [target]="sharedLinkInput">
link
</mat-icon>
<mat-icon class="adf-input-action" matSuffix
[clipboard-notification]="'SHARE.CLIPBOARD-MESSAGE' | translate" [adf-clipboard]
[target]="sharedLinkInput">
link
</mat-icon>
</mat-form-field>
<div class="adf-share-link--row">
<h1 class="adf-share-link__label">{{ 'SHARE.EXPIRES' | translate }}</h1>
<mat-slide-toggle [disabled]="!canUpdate" #slideToggleExpirationDate color="primary"
data-automation-id="adf-expire-toggle" [checked]="form.controls['time'].value"
(change)="onToggleExpirationDate($event)">
</mat-slide-toggle>
</div>
<mat-form-field class="adf-full-width">
<mat-datetimepicker-toggle [for]="datetimePicker" matSuffix></mat-datetimepicker-toggle>
<mat-datetimepicker #datetimePicker type="datetime" openOnFocus="true" timeInterval="1"></mat-datetimepicker>
<mat-datetimepicker-toggle #matDatetimepickerToggle="matDatetimepickerToggle" [for]="datetimePicker" matSuffix></mat-datetimepicker-toggle>
<mat-datetimepicker #datetimePicker (closed)="onDatetimepickerClosed()" [type]="type" openOnFocus="true" timeInterval="1"></mat-datetimepicker>
<input class="adf-share-link__input"
#dateTimePickerInput
matInput
[min]="minDate"
formControlName="time"
[matDatetimepicker]="datetimePicker">
[matDatetimepicker]="datetimePicker" />
</mat-form-field>
</form>
</mat-dialog-content>
<div mat-dialog-actions>
<button
data-automation-id="adf-share-dialog-close"
mat-button color="primary" mat-dialog-close>
<button data-automation-id="adf-share-dialog-close" mat-button color="primary" mat-dialog-close>
{{ 'SHARE.CLOSE' | translate }}
</button>
</div>
</div>
</div>
@@ -16,17 +16,19 @@
*/
import { NoopAnimationsModule } from '@angular/platform-browser/animations';
import { TestBed, fakeAsync, async } from '@angular/core/testing';
import { TestBed, fakeAsync, async, ComponentFixture } from '@angular/core/testing';
import { MatDialogRef, MAT_DIALOG_DATA, MatDialog } from '@angular/material';
import { of, empty } from 'rxjs';
import {
setupTestBed,
CoreModule,
SharedLinksApiService,
NodesApiService,
NotificationService,
RenditionsService
RenditionsService,
AppConfigService
} from '@alfresco/adf-core';
import { CoreTestingModule } from '../../core/testing/core.testing.module';
import { AppConfigServiceMock } from '../../core/mock/app-config.service.mock';
import { ContentNodeShareModule } from './content-node-share.module';
import { ShareDialogComponent } from './content-node-share.dialog';
import moment from 'moment-es6';
@@ -40,18 +42,20 @@ describe('ShareDialogComponent', () => {
let sharedLinksApiService: SharedLinksApiService;
let renditionService: RenditionsService;
let nodesApiService: NodesApiService;
let fixture;
let component;
let fixture: ComponentFixture<ShareDialogComponent>;
let component: ShareDialogComponent;
let appConfigService: AppConfigService;
setupTestBed({
imports: [
NoopAnimationsModule,
CoreModule.forRoot(),
CoreTestingModule,
ContentNodeShareModule
],
providers: [
NodesApiService,
SharedLinksApiService,
{ provide: AppConfigService, useClass: AppConfigServiceMock },
{ provide: NotificationService, useValue: notificationServiceMock },
{ provide: MatDialogRef, useValue: { close: () => {}} },
{ provide: MAT_DIALOG_DATA, useValue: {} }
@@ -64,10 +68,9 @@ describe('ShareDialogComponent', () => {
sharedLinksApiService = TestBed.get(SharedLinksApiService);
renditionService = TestBed.get(RenditionsService);
nodesApiService = TestBed.get(NodesApiService);
appConfigService = TestBed.get(AppConfigService);
component = fixture.componentInstance;
});
beforeEach(() => {
node = {
entry: {
id: 'nodeId',
@@ -78,6 +81,38 @@ describe('ShareDialogComponent', () => {
};
});
describe('Error Handling', () => {
it('should emit a generic error when unshare fails', (done) => {
spyOn(sharedLinksApiService, 'deleteSharedLink').and.returnValue(
of(new Error(`{ "error": { "statusCode": 999 } }`))
);
const sub = sharedLinksApiService.error.subscribe((err) => {
expect(err.statusCode).toBe(999);
expect(err.message).toBe('SHARE.UNSHARE_ERROR');
sub.unsubscribe();
done();
});
component.deleteSharedLink('guid');
});
it('should emit permission error when unshare fails', (done) => {
spyOn(sharedLinksApiService, 'deleteSharedLink').and.returnValue(
of(new Error(`{ "error": { "statusCode": 403 } }`))
);
const sub = sharedLinksApiService.error.subscribe((err) => {
expect(err.statusCode).toBe(403);
expect(err.message).toBe('SHARE.UNSHARE_PERMISSION_ERROR');
sub.unsubscribe();
done();
});
component.deleteSharedLink('guid');
});
});
it(`should toggle share action when property 'sharedId' does not exists`, () => {
spyOn(sharedLinksApiService, 'createSharedLinks').and.returnValue(of({
entry: { id: 'sharedId', sharedId: 'sharedId' }
@@ -196,21 +231,126 @@ describe('ShareDialogComponent', () => {
expect(fixture.nativeElement.querySelector('mat-datetimepicker-toggle button').disabled).toBe(true);
});
it('should not update shared node expiryDate property when value changes', () => {
const date = moment();
it('should reset expiration date when toggle is unchecked', () => {
spyOn(nodesApiService, 'updateNode').and.returnValue(of({}));
node.entry.properties['qshare:sharedId'] = 'sharedId';
spyOn(nodesApiService, 'updateNode');
fixture.componentInstance.form.controls['time'].setValue(null);
node.entry.properties['qshare:sharedId'] = '2017-04-15T18:31:37+00:00';
node.entry.allowableOperations = ['update'];
component.data = {
node,
baseShareUrl: 'some-url/'
};
fixture.detectChanges();
component.form.controls['time'].setValue(moment());
fixture.detectChanges();
fixture.nativeElement
.querySelector(
'.mat-slide-toggle[data-automation-id="adf-expire-toggle"] label'
)
.dispatchEvent(new MouseEvent('click'));
fixture.detectChanges();
expect(nodesApiService.updateNode).toHaveBeenCalledWith('nodeId', {
properties: { 'qshare:expiryDate': null }
});
expect(
fixture.nativeElement.querySelector('input[formcontrolname="time"]').value
).toBe('');
});
it('should not allow expiration date action when node has no update permission', () => {
node.entry.properties['qshare:sharedId'] = 'sharedId';
node.entry.allowableOperations = [];
component.data = {
node,
baseShareUrl: 'some-url/'
};
fixture.detectChanges();
expect(fixture.nativeElement.querySelector('input[formcontrolname="time"]').disabled).toBe(true);
expect(fixture.nativeElement.querySelector('.mat-slide-toggle[data-automation-id="adf-expire-toggle"]')
.classList).toContain('mat-disabled');
});
it('should update node expiration date with selected date', () => {
const date = moment();
node.entry.allowableOperations = ['update'];
node.entry.properties['qshare:sharedId'] = 'sharedId';
spyOn(nodesApiService, 'updateNode').and.returnValue(of({}));
fixture.componentInstance.form.controls['time'].setValue(null);
component.data = {
node,
baseShareUrl: 'some-url/'
};
fixture.detectChanges();
fixture.nativeElement
.querySelector(
'mat-slide-toggle[data-automation-id="adf-expire-toggle"] label'
)
.dispatchEvent(new MouseEvent('click'));
fixture.componentInstance.form.controls['time'].setValue(date);
fixture.detectChanges();
expect(nodesApiService.updateNode).toHaveBeenCalled();
expect(nodesApiService.updateNode).toHaveBeenCalledWith('nodeId', {
properties: { 'qshare:expiryDate': date.utc().format() }
});
});
describe('datetimepicker type', () => {
beforeEach(() => {
spyOn(nodesApiService, 'updateNode').and.returnValue(of({}));
spyOn(sharedLinksApiService, 'createSharedLinks').and.returnValue(of({}));
node.entry.allowableOperations = ['update'];
component.data = {
node,
baseShareUrl: 'some-url/'
};
});
it('it should update node with input date and end of day time when type is `date`', () => {
const dateTimePickerType = 'date';
const date = moment('2525-01-01 13:00:00');
spyOn(appConfigService, 'get').and.callFake(() => dateTimePickerType);
fixture.detectChanges();
fixture.nativeElement.querySelector('mat-slide-toggle[data-automation-id="adf-expire-toggle"] label')
.dispatchEvent(new MouseEvent('click'));
fixture.componentInstance.form.controls['time'].setValue(date);
fixture.detectChanges();
expect(nodesApiService.updateNode).toHaveBeenCalledWith('nodeId', {
properties: { 'qshare:expiryDate': date.endOf('day').utc().format() }
});
});
it('it should update node with input date and time when type is `datetime`', () => {
const dateTimePickerType = 'datetime';
const date = moment('2525-01-01 13:00:00');
spyOn(appConfigService, 'get').and.callFake(() => dateTimePickerType);
fixture.detectChanges();
fixture.nativeElement.querySelector('mat-slide-toggle[data-automation-id="adf-expire-toggle"] label')
.dispatchEvent(new MouseEvent('click'));
fixture.componentInstance.form.controls['time'].setValue(date);
fixture.detectChanges();
expect(nodesApiService.updateNode).toHaveBeenCalledWith('nodeId', {
properties: { 'qshare:expiryDate': date.utc().format() }
});
});
});
});
@@ -21,18 +21,23 @@ import {
OnInit,
ViewEncapsulation,
ViewChild,
ElementRef,
OnDestroy
} from '@angular/core';
import { MAT_DIALOG_DATA, MatDialogRef, MatDialog } from '@angular/material';
import { MAT_DIALOG_DATA, MatDialogRef, MatDialog, MatSlideToggleChange } from '@angular/material';
import { FormGroup, FormControl } from '@angular/forms';
import { Subscription, Observable } from 'rxjs';
import { tap, skip } from 'rxjs/operators';
import { Subscription, Observable, throwError } from 'rxjs';
import {
skip,
distinctUntilChanged,
mergeMap,
catchError
} from 'rxjs/operators';
import {
SharedLinksApiService,
NodesApiService,
ContentService,
RenditionsService
RenditionsService,
AppConfigService
} from '@alfresco/adf-core';
import { SharedLinkEntry, Node } from '@alfresco/js-api';
import { ConfirmDialogComponent } from '../dialogs/confirm.dialog';
@@ -42,7 +47,7 @@ import moment from 'moment-es6';
selector: 'adf-share-dialog',
templateUrl: './content-node-share.dialog.html',
styleUrls: ['./content-node-share.dialog.scss'],
host: { 'class': 'adf-share-dialog' },
host: { class: 'adf-share-dialog' },
encapsulation: ViewEncapsulation.None
})
export class ShareDialogComponent implements OnInit, OnDestroy {
@@ -55,34 +60,49 @@ export class ShareDialogComponent implements OnInit, OnDestroy {
isFileShared: boolean = false;
isDisabled: boolean = false;
form: FormGroup = new FormGroup({
'sharedUrl': new FormControl(''),
'time': new FormControl({value: '', disabled: false})
sharedUrl: new FormControl(''),
time: new FormControl({ value: '', disabled: false })
});
type = 'datetime';
@ViewChild('sharedLinkInput') sharedLinkInput: ElementRef;
@ViewChild('matDatetimepickerToggle')
matDatetimepickerToggle;
@ViewChild('slideToggleExpirationDate')
slideToggleExpirationDate;
@ViewChild('dateTimePickerInput')
dateTimePickerInput;
constructor(
private appConfigService: AppConfigService,
private sharedLinksApiService: SharedLinksApiService,
private dialogRef: MatDialogRef<ShareDialogComponent>,
private dialog: MatDialog,
private nodesApiService: NodesApiService,
private contentService: ContentService,
private renditionService: RenditionsService,
@Inject(MAT_DIALOG_DATA) public data: any) {
}
@Inject(MAT_DIALOG_DATA) public data: any
) {}
ngOnInit() {
this.type = this.appConfigService.get<string>('sharedLinkDateTimePickerType', 'datetime');
if (!this.canUpdate) {
this.form.controls['time'].disable();
}
this.subscriptions.push(
this.form.valueChanges
this.form.controls.time.valueChanges
.pipe(
skip(1),
tap((updates) => {
this.updateNode(updates);
distinctUntilChanged(),
mergeMap(
(updates) => this.updateNode(updates),
(formUpdates) => formUpdates
),
catchError((error) => {
return throwError(error);
})
)
.subscribe((updates) => this.updateEntryExpiryDate(updates))
@@ -94,9 +114,7 @@ export class ShareDialogComponent implements OnInit, OnDestroy {
const properties = this.data.node.entry.properties;
if (properties && !properties['qshare:sharedId']) {
this.createSharedLinks(this.data.node.entry.id);
} else {
this.sharedId = properties['qshare:sharedId'];
this.isFileShared = true;
@@ -123,7 +141,27 @@ export class ShareDialogComponent implements OnInit, OnDestroy {
}
get canUpdate() {
return this.contentService.hasAllowableOperations(this.data.node.entry, 'update');
return this.contentService.hasAllowableOperations(
this.data.node.entry,
'update'
);
}
onToggleExpirationDate(slideToggle: MatSlideToggleChange) {
if (slideToggle.checked) {
this.matDatetimepickerToggle.datetimepicker.open();
} else {
this.matDatetimepickerToggle.datetimepicker.close();
this.form.controls.time.setValue(null);
}
}
onDatetimepickerClosed() {
this.dateTimePickerInput.nativeElement.blur();
if (!this.form.controls.time.value) {
this.slideToggleExpirationDate.checked = false;
}
}
private openConfirmationDialog() {
@@ -140,7 +178,8 @@ export class ShareDialogComponent implements OnInit, OnDestroy {
minWidth: '250px',
closeOnNavigation: true
})
.beforeClose().subscribe((deleteSharedLink) => {
.beforeClose()
.subscribe((deleteSharedLink) => {
if (deleteSharedLink) {
this.deleteSharedLink(this.sharedId);
} else {
@@ -152,15 +191,18 @@ export class ShareDialogComponent implements OnInit, OnDestroy {
private createSharedLinks(nodeId: string) {
this.isDisabled = true;
this.sharedLinksApiService.createSharedLinks(nodeId)
.subscribe((sharedLink: SharedLinkEntry) => {
this.sharedLinksApiService.createSharedLinks(nodeId).subscribe(
(sharedLink: SharedLinkEntry) => {
if (sharedLink.entry) {
this.sharedId = sharedLink.entry.id;
this.data.node.entry.properties['qshare:sharedId'] = this.sharedId;
this.data.node.entry.properties[
'qshare:sharedId'
] = this.sharedId;
this.isDisabled = false;
this.isFileShared = true;
this.renditionService.generateRenditionForNode(this.data.node.entry.id).subscribe(() => {});
this.renditionService
.generateRenditionForNode(this.data.node.entry.id)
.subscribe(() => {});
this.updateForm();
}
@@ -168,21 +210,48 @@ export class ShareDialogComponent implements OnInit, OnDestroy {
() => {
this.isDisabled = false;
this.isFileShared = false;
});
}
);
}
private deleteSharedLink(sharedId: string) {
deleteSharedLink(sharedId: string) {
this.isDisabled = true;
this.sharedLinksApiService.deleteSharedLink(sharedId).subscribe(() => {
this.data.node.entry.properties['qshare:sharedId'] = null;
this.data.node.entry.properties['qshare:expiryDate'] = null;
this.dialogRef.close(false);
this.sharedLinksApiService.deleteSharedLink(sharedId).subscribe(
(response: any) => {
if (response instanceof Error) {
this.isDisabled = false;
this.isFileShared = true;
this.handleError(response);
} else {
this.data.node.entry.properties['qshare:sharedId'] = null;
this.data.node.entry.properties['qshare:expiryDate'] = null;
this.dialogRef.close(false);
}
},
() => {
this.isDisabled = false;
this.isFileShared = false;
});
}
);
}
private handleError(error: Error) {
let message = 'SHARE.UNSHARE_ERROR';
let statusCode = 0;
try {
statusCode = JSON.parse(error.message).error.statusCode;
} catch {}
if (statusCode === 403) {
message = 'SHARE.UNSHARE_PERMISSION_ERROR';
}
this.sharedLinksApiService.error.next({
statusCode,
message
});
}
private updateForm() {
@@ -190,27 +259,26 @@ export class ShareDialogComponent implements OnInit, OnDestroy {
const expiryDate = entry.properties['qshare:expiryDate'];
this.form.setValue({
'sharedUrl': `${this.baseShareUrl}${this.sharedId}`,
'time': expiryDate ? expiryDate : null
sharedUrl: `${this.baseShareUrl}${this.sharedId}`,
time: expiryDate ? moment(expiryDate).local() : null
});
}
private updateNode(updates): Observable<Node> {
return this.nodesApiService.updateNode(
this.data.node.entry.id,
{
properties: {
'qshare:expiryDate': updates.time ? updates.time.utc().format() : null
}
private updateNode(date: moment.Moment): Observable<Node> {
return this.nodesApiService.updateNode(this.data.node.entry.id, {
properties: {
'qshare:expiryDate': date ?
(this.type === 'date' ? date.endOf('day').utc().format() : date.utc().format()) :
null
}
);
});
}
private updateEntryExpiryDate(updates) {
private updateEntryExpiryDate(date: moment.Moment) {
const { properties } = this.data.node.entry;
properties['qshare:expiryDate'] = updates.time
? updates.time.local()
properties['qshare:expiryDate'] = date
? date.local()
: null;
}
}
+3 -2
View File
@@ -292,7 +292,8 @@
"MESSAGE": "سيتم حذف هذا الرابط وسيتم إنشاء رابط جديد في المرة التالية التي يتم فيها مشاركة هذا الملف",
"CANCEL": "إلغاء",
"REMOVE": "إزالة"
}
},
"UNSHARE_PERMISSION_ERROR": "ليس لديك إذن لإلغاء مشاركة هذا الملف"
},
"PERMISSION_MANAGER": {
"PERMISSION_DISPLAY": {
@@ -363,4 +364,4 @@
"LIBRARY_UPDATED": "تم تحديث خصائص المكتبة"
}
}
}
}
+3 -2
View File
@@ -292,7 +292,8 @@
"MESSAGE": "Tento odkaz se odstraní a při dalším sdílení tohoto souboru se vytvoří odkaz nový",
"CANCEL": "Zrušit",
"REMOVE": "Odstranit"
}
},
"UNSHARE_PERMISSION_ERROR": "Nemáte potřebná oprávnění pro zrušení sdílení tohoto souboru"
},
"PERMISSION_MANAGER": {
"PERMISSION_DISPLAY": {
@@ -363,4 +364,4 @@
"LIBRARY_UPDATED": "Vlastnosti knihovny byly upraveny"
}
}
}
}
+3 -2
View File
@@ -292,7 +292,8 @@
"MESSAGE": "Dette link bliver slettet, og der oprettes et nyt link, når filen deles næste gang",
"CANCEL": "Annuller",
"REMOVE": "Fjern"
}
},
"UNSHARE_PERMISSION_ERROR": "Du har ikke tilladelse til at ophæve delingen af denne fil"
},
"PERMISSION_MANAGER": {
"PERMISSION_DISPLAY": {
@@ -363,4 +364,4 @@
"LIBRARY_UPDATED": "Egenskaberne for biblioteket er blevet opdateret"
}
}
}
}
+3 -2
View File
@@ -292,7 +292,8 @@
"MESSAGE": "Dieser Link wird gelöscht und ein neuer Link wird erstellt wenn diese Datei das nächste Mal geteilt wird.",
"CANCEL": "Abbrechen",
"REMOVE": "Entfernen"
}
},
"UNSHARE_PERMISSION_ERROR": "Sie verfügen nicht über die Berechtigung die Freigabe für diese Datei aufzuheben"
},
"PERMISSION_MANAGER": {
"PERMISSION_DISPLAY": {
@@ -363,4 +364,4 @@
"LIBRARY_UPDATED": "Bibliothekseigenschaften aktualisiert"
}
}
}
}
+3 -1
View File
@@ -297,7 +297,9 @@
"MESSAGE": "This link will be deleted and a new link will be created next time this file is shared",
"CANCEL": "Cancel",
"REMOVE": "Remove"
}
},
"UNSHARE_ERROR": "Error unsharing this file",
"UNSHARE_PERMISSION_ERROR": "You don't have permission to unshare this file"
},
"PERMISSION_MANAGER": {
"PERMISSION_DISPLAY": {
+3 -2
View File
@@ -292,7 +292,8 @@
"MESSAGE": "Este enlace será eliminado. Se creará un enlace nuevo la próxima vez que comparta este fichero.",
"CANCEL": "Cancelar",
"REMOVE": "Eliminar"
}
},
"UNSHARE_PERMISSION_ERROR": "No tiene acceso para dejar de compartir este fichero"
},
"PERMISSION_MANAGER": {
"PERMISSION_DISPLAY": {
@@ -363,4 +364,4 @@
"LIBRARY_UPDATED": "Propiedades de la biblioteca actualizadas"
}
}
}
}
+3 -2
View File
@@ -292,7 +292,8 @@
"MESSAGE": "Tämä linkki poistetaan ja uusi linkki luodaan, kun tiedosto jaetaan seuraavan kerran",
"CANCEL": "Peruuta",
"REMOVE": "Poista"
}
},
"UNSHARE_PERMISSION_ERROR": "Sinulla ei ole oikeuksia peruuttaa tämän tiedoston jakamista"
},
"PERMISSION_MANAGER": {
"PERMISSION_DISPLAY": {
@@ -363,4 +364,4 @@
"LIBRARY_UPDATED": "Kirjaston ominaisuudet päivitettiin"
}
}
}
}
+3 -2
View File
@@ -292,7 +292,8 @@
"MESSAGE": "Ce lien sera supprimé et un nouveau lien sera créé lors du prochain partage de ce fichier",
"CANCEL": "Annuler",
"REMOVE": "Supprimer"
}
},
"UNSHARE_PERMISSION_ERROR": "Vous n'avez pas les droits d'accès pour ne pas partager ce fichier"
},
"PERMISSION_MANAGER": {
"PERMISSION_DISPLAY": {
@@ -363,4 +364,4 @@
"LIBRARY_UPDATED": "Les propriétés de la bibliothèque ont été mises à jour"
}
}
}
}
+3 -2
View File
@@ -292,7 +292,8 @@
"MESSAGE": "Il link verrà eliminato e verrà creato un nuovo link per il prossimo file condiviso",
"CANCEL": "Annulla",
"REMOVE": "Rimuovi"
}
},
"UNSHARE_PERMISSION_ERROR": "Non hai il permesso per rimuovere la condivisione di questo file"
},
"PERMISSION_MANAGER": {
"PERMISSION_DISPLAY": {
@@ -363,4 +364,4 @@
"LIBRARY_UPDATED": "Proprietà della raccolta aggiornate"
}
}
}
}
+3 -2
View File
@@ -292,7 +292,8 @@
"MESSAGE": "このリンクは削除され、次回このファイルを共有するときに新しいリンクが作成されます。",
"CANCEL": "キャンセル",
"REMOVE": "削除"
}
},
"UNSHARE_PERMISSION_ERROR": "このファイルの共有を解除する権限がありません。"
},
"PERMISSION_MANAGER": {
"PERMISSION_DISPLAY": {
@@ -363,4 +364,4 @@
"LIBRARY_UPDATED": "ライブラリのプロパティが更新されました"
}
}
}
}
+3 -2
View File
@@ -292,7 +292,8 @@
"MESSAGE": "Denne koblingen vil bli slettet, og en ny kobling vil bli opprettet neste gang denne filen deles",
"CANCEL": "Avbryt",
"REMOVE": "Fjern"
}
},
"UNSHARE_PERMISSION_ERROR": "Du har ikke tillatelse til å oppheve deling av denne filen"
},
"PERMISSION_MANAGER": {
"PERMISSION_DISPLAY": {
@@ -363,4 +364,4 @@
"LIBRARY_UPDATED": "Bibliotekegenskaper oppdatert"
}
}
}
}
+3 -2
View File
@@ -292,7 +292,8 @@
"MESSAGE": "Deze koppeling wordt verwijderd en er wordt een nieuwe koppeling gemaakt de volgende keer dat dit bestand wordt gedeeld",
"CANCEL": "Annuleren",
"REMOVE": "Verwijderen"
}
},
"UNSHARE_PERMISSION_ERROR": "U hebt geen rechten om het delen van dit bestand ongedaan te maken"
},
"PERMISSION_MANAGER": {
"PERMISSION_DISPLAY": {
@@ -363,4 +364,4 @@
"LIBRARY_UPDATED": "Bibliotheekeigenschappen bijgewerkt"
}
}
}
}
+3 -2
View File
@@ -292,7 +292,8 @@
"MESSAGE": "Ten link zostanie usunięty, a przy następnym udostępnieniu tego pliku zostanie utworzony nowy link.",
"CANCEL": "Anuluj",
"REMOVE": "Usuń"
}
},
"UNSHARE_PERMISSION_ERROR": "Nie masz uprawnień, aby cofnąć udostępnianie tego pliku"
},
"PERMISSION_MANAGER": {
"PERMISSION_DISPLAY": {
@@ -363,4 +364,4 @@
"LIBRARY_UPDATED": "Zaktualizowano właściwości biblioteki"
}
}
}
}
+3 -2
View File
@@ -292,7 +292,8 @@
"MESSAGE": "Este link será excluído. Um novo link será criado na próxima vez que esse arquivo for compartilhado.",
"CANCEL": "Cancelar",
"REMOVE": "Remover"
}
},
"UNSHARE_PERMISSION_ERROR": "Você não tem permissão para descompartilhar deste arquivo"
},
"PERMISSION_MANAGER": {
"PERMISSION_DISPLAY": {
@@ -363,4 +364,4 @@
"LIBRARY_UPDATED": "Propriedades da biblioteca atualizadas"
}
}
}
}
+3 -2
View File
@@ -292,7 +292,8 @@
"MESSAGE": "Эта ссылка будет удалена, и новая ссылка будет создана при следующем совместном использовании этого файла",
"CANCEL": "Отмена",
"REMOVE": "Удалить"
}
},
"UNSHARE_PERMISSION_ERROR": "У вас нет разрешения на снятие этого файла с публикации"
},
"PERMISSION_MANAGER": {
"PERMISSION_DISPLAY": {
@@ -363,4 +364,4 @@
"LIBRARY_UPDATED": "Свойства библиотеки обновлены"
}
}
}
}
+3 -2
View File
@@ -292,7 +292,8 @@
"MESSAGE": "Den här länken kommer att raderas och en ny länk kommer att skapas nästa gång den här filen delas",
"CANCEL": "Avbryt",
"REMOVE": "Ta bort"
}
},
"UNSHARE_PERMISSION_ERROR": "Du har inte behörighet att sluta dela den här filen"
},
"PERMISSION_MANAGER": {
"PERMISSION_DISPLAY": {
@@ -363,4 +364,4 @@
"LIBRARY_UPDATED": "Biblioteksegenskaper uppdaterade"
}
}
}
}
+3 -2
View File
@@ -292,7 +292,8 @@
"MESSAGE": "此链接将被删除,下次共享此文件时将会创建新链接",
"CANCEL": "取消",
"REMOVE": "删除"
}
},
"UNSHARE_PERMISSION_ERROR": "你没有权限取消这个文件的共享"
},
"PERMISSION_MANAGER": {
"PERMISSION_DISPLAY": {
@@ -363,4 +364,4 @@
"LIBRARY_UPDATED": "已更新库属性"
}
}
}
}