node locking enhancements and fixes (#955)

* optimize image resolver

* allow previewing locked files

* allow selecting locked nodes

* fix comments and metadata tabs

* improved lock checks

* remove obsolete "experimental" directive
This commit is contained in:
Denys Vuika 2019-02-15 18:36:51 +00:00 committed by GitHub
parent 46c8062f2f
commit 4cde12dfee
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
40 changed files with 69 additions and 387 deletions

View File

@ -26,7 +26,9 @@ export class AosEditOnlineService {
// const checkedOut = node.aspectNames.find(
// (aspect: string) => aspect === 'cm:checkedOut'
// );
const checkedOut = node.properties['cm:lockType'] === 'WRITE_LOCK';
const checkedOut =
node.properties['cm:lockType'] === 'WRITE_LOCK' ||
node.properties['cm:lockType'] === 'READ_ONLY_LOCK';
const lockOwner = node.properties['cm:lockOwner'];
const differentLockOwner =
lockOwner.id !== this.alfrescoAuthenticationService.getEcmUsername();

View File

@ -32,7 +32,10 @@ export function canOpenWithOffice(
}
*/
if (file.entry.properties['cm:lockType'] === 'WRITE_LOCK') {
if (
file.entry.properties['cm:lockType'] === 'WRITE_LOCK' ||
file.entry.properties['cm:lockType'] === 'READ_ONLY_LOCK'
) {
return false;
}

View File

@ -20,7 +20,6 @@
"logo": "assets/images/alfresco-logo-flower.svg",
"copyright": "© 2017 - 2018 Alfresco Software, Inc. All rights reserved."
},
"experimental": {},
"headerColor": "#2196F3",
"languagePicker": false,
"pagination": {

View File

@ -28,6 +28,7 @@ import { EDIT_OFFLINE } from '../../../store/actions';
import { NodeEntry } from '@alfresco/js-api';
import { Subject } from 'rxjs';
import { filter, takeUntil } from 'rxjs/operators';
import { isLocked } from '../../../utils/node.utils';
@Component({
selector: 'aca-custom-name-column',
@ -84,11 +85,6 @@ export class CustomNameColumnComponent implements OnInit, OnDestroy {
}
isFileWriteLocked() {
return !!(
this.node &&
this.node.entry &&
this.node.entry.properties &&
this.node.entry.properties['cm:lockType'] === 'WRITE_LOCK'
);
return isLocked(this.node);
}
}

View File

@ -4,10 +4,6 @@
</adf-breadcrumb>
<adf-toolbar class="inline">
<app-document-display-mode
*ifExperimental="'cardview'"
></app-document-display-mode>
<ng-container *ngFor="let entry of actions; trackBy: trackByActionId">
<aca-toolbar-action [actionRef]="entry"></aca-toolbar-action>
</ng-container>

View File

@ -39,7 +39,6 @@ import { DocumentListComponent } from '@alfresco/adf-content-services';
import { FavoriteLibrariesComponent } from './favorite-libraries.component';
import { AppTestingModule } from '../../testing/app-testing.module';
import { ContentApiService } from '../../services/content-api.service';
import { ExperimentalDirective } from '../../directives/experimental.directive';
import { ContentManagementService } from '../../services/content-management.service';
import { EffectsModule } from '@ngrx/effects';
import { LibraryEffects, RouterEffects } from '../../store/effects';
@ -77,8 +76,7 @@ describe('FavoriteLibrariesComponent', () => {
NodeFavoriteDirective,
DocumentListComponent,
FavoriteLibrariesComponent,
AppConfigPipe,
ExperimentalDirective
AppConfigPipe
],
providers: [ContentManagementService, UserPreferencesService],
schemas: [NO_ERRORS_SCHEMA]

View File

@ -40,7 +40,6 @@ import { of } from 'rxjs';
import { FavoritesComponent } from './favorites.component';
import { AppTestingModule } from '../../testing/app-testing.module';
import { ContentApiService } from '../../services/content-api.service';
import { ExperimentalDirective } from '../../directives/experimental.directive';
describe('FavoritesComponent', () => {
let fixture: ComponentFixture<FavoritesComponent>;
@ -83,8 +82,7 @@ describe('FavoritesComponent', () => {
NodeFavoriteDirective,
DocumentListComponent,
FavoritesComponent,
AppConfigPipe,
ExperimentalDirective
AppConfigPipe
],
schemas: [NO_ERRORS_SCHEMA]
});

View File

@ -46,7 +46,6 @@ import { NodeActionsService } from '../../services/node-actions.service';
import { FilesComponent } from './files.component';
import { AppTestingModule } from '../../testing/app-testing.module';
import { ContentApiService } from '../../services/content-api.service';
import { ExperimentalDirective } from '../../directives/experimental.directive';
import { of, throwError } from 'rxjs';
describe('FilesComponent', () => {
@ -70,8 +69,7 @@ describe('FilesComponent', () => {
NodeFavoriteDirective,
DocumentListComponent,
FileSizePipe,
AppConfigPipe,
ExperimentalDirective
AppConfigPipe
],
providers: [
{

View File

@ -156,11 +156,6 @@ export class FilesComponent extends PageComponent implements OnInit, OnDestroy {
return;
}
if (PageComponent.isLockedNode(node.entry)) {
event.preventDefault();
return;
}
this.showPreview(node);
}
}

View File

@ -26,6 +26,7 @@
import { Component, Input } from '@angular/core';
import { MinimalNodeEntryEntity } from '@alfresco/js-api';
import { NodePermissionService } from '../../../services/node-permission.service';
import { isLocked } from '../../../utils/node.utils';
@Component({
selector: 'app-comments-tab',
@ -42,7 +43,11 @@ export class CommentsTabComponent {
constructor(private permission: NodePermissionService) {}
get canUpdateNode() {
return this.node && this.permission.check(this.node, ['update']);
get canUpdateNode(): boolean {
if (this.node && this.node.isFile && !isLocked({ entry: this.node })) {
return this.permission.check(this.node, ['update']);
}
return false;
}
}

View File

@ -28,6 +28,7 @@ import { MinimalNodeEntryEntity } from '@alfresco/js-api';
import { NodePermissionService } from '../../../services/node-permission.service';
import { AppExtensionService } from '../../../extensions/extension.service';
import { AppConfigService } from '@alfresco/adf-core';
import { isLocked } from '../../../utils/node.utils';
@Component({
selector: 'app-metadata-tab',
@ -64,26 +65,11 @@ export class MetadataTabComponent {
}
}
get canUpdateNode() {
if (this.node) {
if (this.fileIsLocked()) {
return false;
}
get canUpdateNode(): boolean {
if (this.node && this.node.isFile && !isLocked({ entry: this.node })) {
return this.permission.check(this.node, ['update']);
}
return false;
}
private fileIsLocked() {
if (!this.node.isFile) {
return false;
}
return (
this.node.isLocked ||
(this.node.properties &&
this.node.properties['cm:lockType'] === 'READ_ONLY_LOCK')
);
}
}

View File

@ -37,7 +37,6 @@ import {
import { DocumentListComponent } from '@alfresco/adf-content-services';
import { LibrariesComponent } from './libraries.component';
import { AppTestingModule } from '../../testing/app-testing.module';
import { ExperimentalDirective } from '../../directives/experimental.directive';
import { EffectsModule } from '@ngrx/effects';
import { LibraryEffects } from '../../store/effects';
@ -67,8 +66,7 @@ describe('LibrariesComponent', () => {
NodeFavoriteDirective,
DocumentListComponent,
LibrariesComponent,
AppConfigPipe,
ExperimentalDirective
AppConfigPipe
],
schemas: [NO_ERRORS_SCHEMA]
});

View File

@ -44,6 +44,7 @@ import {
sharedUrl
} from '../store/selectors/app.selectors';
import { AppStore } from '../store/states/app.state';
import { isLocked, isLibrary } from '../utils/node.utils';
export abstract class PageComponent implements OnInit, OnDestroy {
onDestroy$: Subject<boolean> = new Subject<boolean>();
@ -64,28 +65,6 @@ export abstract class PageComponent implements OnInit, OnDestroy {
protected subscriptions: Subscription[] = [];
static isLockedNode(node) {
return (
node.isLocked ||
(node.properties && node.properties['cm:lockType'] === 'READ_ONLY_LOCK')
);
}
static isWriteLockedNode(node) {
return node.properties && node.properties['cm:lockType'] === 'WRITE_LOCK';
}
static isLibrary(entry) {
return (
(entry.guid &&
entry.id &&
entry.preset &&
entry.title &&
entry.visibility) ||
entry.nodeType === 'st:site'
);
}
constructor(
protected store: Store<AppStore>,
protected extensions: AppExtensionService,
@ -137,16 +116,11 @@ export abstract class PageComponent implements OnInit, OnDestroy {
}
imageResolver(row: ShareDataRow): string | null {
const entry: MinimalNodeEntryEntity = row.node.entry;
if (
PageComponent.isLockedNode(entry) ||
PageComponent.isWriteLockedNode(entry)
) {
if (isLocked(row.node)) {
return 'assets/images/baseline-lock-24px.svg';
}
if (PageComponent.isLibrary(entry)) {
if (isLibrary(row.node)) {
return 'assets/images/baseline-library_books-24px.svg';
}

View File

@ -42,7 +42,6 @@ import {
import { PreviewComponent } from './preview.component';
import { of, throwError } from 'rxjs';
import { EffectsModule } from '@ngrx/effects';
import { ExperimentalDirective } from '../../directives/experimental.directive';
import { NodeEffects } from '../../store/effects/node.effects';
import { AppTestingModule } from '../../testing/app-testing.module';
import { ContentApiService } from '../../services/content-api.service';
@ -63,12 +62,7 @@ describe('PreviewComponent', () => {
TestBed.configureTestingModule({
imports: [AppTestingModule, EffectsModule.forRoot([NodeEffects])],
providers: [AlfrescoApiService, ContentManagementService],
declarations: [
AppConfigPipe,
PreviewComponent,
NodeFavoriteDirective,
ExperimentalDirective
],
declarations: [AppConfigPipe, PreviewComponent, NodeFavoriteDirective],
schemas: [NO_ERRORS_SCHEMA]
});

View File

@ -38,7 +38,6 @@ import { ContentManagementService } from '../../services/content-management.serv
import { RecentFilesComponent } from './recent-files.component';
import { AppTestingModule } from '../../testing/app-testing.module';
import { ExperimentalDirective } from '../../directives/experimental.directive';
describe('RecentFilesComponent', () => {
let fixture: ComponentFixture<RecentFilesComponent>;
@ -66,8 +65,7 @@ describe('RecentFilesComponent', () => {
NodeFavoriteDirective,
DocumentListComponent,
RecentFilesComponent,
AppConfigPipe,
ExperimentalDirective
AppConfigPipe
],
schemas: [NO_ERRORS_SCHEMA]
});

View File

@ -79,11 +79,6 @@ export class RecentFilesComponent extends PageComponent implements OnInit {
onNodeDoubleClick(node: MinimalNodeEntity) {
if (node && node.entry) {
if (PageComponent.isLockedNode(node.entry)) {
event.preventDefault();
return;
}
this.showPreview(node);
}
}

View File

@ -177,11 +177,6 @@ export class SearchResultsComponent extends PageComponent implements OnInit {
return;
}
if (PageComponent.isLockedNode(node.entry)) {
event.preventDefault();
return;
}
this.showPreview(node);
}
}

View File

@ -81,22 +81,4 @@
Language Picker
</mat-checkbox>
</mat-expansion-panel>
<ng-container *ngIf="experimental.length">
<mat-expansion-panel *ngIf="(profile$ | async)?.isAdmin">
<mat-expansion-panel-header>
<mat-panel-title>
{{ 'APP.SETTINGS.EXPERIMENTAL-FEATURES' | translate }}
</mat-panel-title>
</mat-expansion-panel-header>
<div *ngFor="let flag of experimental">
<mat-checkbox
[(ngModel)]="flag.value"
(change)="onToggleExperimentalFeature(flag.key, $event)"
>
{{ flag.key }}
</mat-checkbox>
</div>
</mat-expansion-panel>
</ng-container>
</mat-accordion>

View File

@ -64,7 +64,6 @@ export class SettingsComponent implements OnInit {
appName$: Observable<string>;
headerColor$: Observable<string>;
languagePicker$: Observable<boolean>;
experimental: Array<{ key: string; value: boolean }> = [];
constructor(
private store: Store<AppStore>,
@ -96,15 +95,6 @@ export class SettingsComponent implements OnInit {
});
this.reset();
const settings = this.appConfig.get('experimental');
this.experimental = Object.keys(settings).map(key => {
const value = this.appConfig.get(`experimental.${key}`);
return {
key,
value: value === true || value === 'true'
};
});
}
apply(model: RepositoryConfig, isValid: boolean) {
@ -142,8 +132,4 @@ export class SettingsComponent implements OnInit {
this.storage.setItem('languagePicker', event.checked.toString());
this.store.dispatch(new SetLanguagePickerAction(event.checked));
}
onToggleExperimentalFeature(key: string, event: MatCheckboxChange) {
this.storage.setItem(`experimental.${key}`, event.checked.toString());
}
}

View File

@ -37,7 +37,6 @@ import { DocumentListComponent } from '@alfresco/adf-content-services';
import { ContentManagementService } from '../../services/content-management.service';
import { SharedFilesComponent } from './shared-files.component';
import { AppTestingModule } from '../../testing/app-testing.module';
import { ExperimentalDirective } from '../../directives/experimental.directive';
describe('SharedFilesComponent', () => {
let fixture: ComponentFixture<SharedFilesComponent>;
@ -65,8 +64,7 @@ describe('SharedFilesComponent', () => {
NodeFavoriteDirective,
DocumentListComponent,
SharedFilesComponent,
AppConfigPipe,
ExperimentalDirective
AppConfigPipe
],
schemas: [NO_ERRORS_SCHEMA]
});

View File

@ -36,7 +36,6 @@ import { DocumentListComponent } from '@alfresco/adf-content-services';
import { ContentManagementService } from '../../services/content-management.service';
import { TrashcanComponent } from './trashcan.component';
import { AppTestingModule } from '../../testing/app-testing.module';
import { ExperimentalDirective } from '../../directives/experimental.directive';
describe('TrashcanComponent', () => {
let fixture: ComponentFixture<TrashcanComponent>;
@ -64,8 +63,7 @@ describe('TrashcanComponent', () => {
NodeFavoriteDirective,
DocumentListComponent,
TrashcanComponent,
AppConfigPipe,
ExperimentalDirective
AppConfigPipe
],
schemas: [NO_ERRORS_SCHEMA]
});

View File

@ -24,7 +24,6 @@
*/
import { NgModule } from '@angular/core';
import { ExperimentalDirective } from './experimental.directive';
import { DocumentListDirective } from './document-list.directive';
import { PaginationDirective } from './pagination.directive';
import { LibraryMembershipDirective } from './library-membership.directive';
@ -33,7 +32,6 @@ import { LockNodeDirective } from './lock-node.directive';
export function directives() {
return [
ExperimentalDirective,
DocumentListDirective,
PaginationDirective,
LibraryMembershipDirective,

View File

@ -29,9 +29,7 @@ import { ActivatedRoute, Router } from '@angular/router';
import { UserPreferencesService } from '@alfresco/adf-core';
import { Subscription } from 'rxjs';
import { Store } from '@ngrx/store';
import { AppStore } from '../store/states/app.state';
import { SetSelectedNodesAction } from '../store/actions';
import { MinimalNodeEntryEntity } from '@alfresco/js-api';
@Directive({
selector: '[acaDocumentList]'
@ -45,7 +43,7 @@ export class DocumentListDirective implements OnInit, OnDestroy {
}
constructor(
private store: Store<AppStore>,
private store: Store<any>,
private documentList: DocumentListComponent,
private preferences: UserPreferencesService,
private route: ActivatedRoute,
@ -104,11 +102,6 @@ export class DocumentListDirective implements OnInit, OnDestroy {
@HostListener('node-select', ['$event'])
onNodeSelect(event: CustomEvent) {
if (!!event.detail && !!event.detail.node) {
const node: MinimalNodeEntryEntity = event.detail.node.entry;
if (node && this.isLockedNode(node)) {
this.unSelectLockedNodes(this.documentList);
}
this.updateSelection();
}
}
@ -123,47 +116,11 @@ export class DocumentListDirective implements OnInit, OnDestroy {
}
private updateSelection() {
const selection = this.documentList.selection
.filter(node => !this.isLockedNode(node.entry))
.map(node => {
node['isLibrary'] = this.isLibrary;
return node;
});
const selection = this.documentList.selection.map(node => {
node['isLibrary'] = this.isLibrary;
return node;
});
this.store.dispatch(new SetSelectedNodesAction(selection));
}
private isLockedNode(node): boolean {
return (
node.isLocked ||
(node.properties && node.properties['cm:lockType'] === 'READ_ONLY_LOCK')
);
}
private isLockedRow(row): boolean {
return (
row.getValue('isLocked') ||
(row.getValue('properties') &&
row.getValue('properties')['cm:lockType'] === 'READ_ONLY_LOCK')
);
}
private unSelectLockedNodes(documentList: DocumentListComponent) {
documentList.selection = documentList.selection.filter(
item => !this.isLockedNode(item.entry)
);
const dataTable = documentList.dataTable;
if (dataTable && dataTable.data) {
const rows = dataTable.data.getRows();
if (rows && rows.length > 0) {
rows.forEach(r => {
if (this.isLockedRow(r)) {
r.isSelected = false;
}
});
}
}
}
}

View File

@ -1,105 +0,0 @@
/*!
* @license
* Alfresco Example Content Application
*
* Copyright (C) 2005 - 2018 Alfresco Software Limited
*
* This file is part of the Alfresco Example Content Application.
* If the software was purchased under a paid Alfresco license, the terms of
* the paid license agreement will prevail. Otherwise, the software is
* provided under the following open source license terms:
*
* The Alfresco Example Content Application is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* The Alfresco Example Content Application is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
*/
import {
Directive,
TemplateRef,
ViewContainerRef,
Input,
EmbeddedViewRef
} from '@angular/core';
import { AppConfigService, StorageService } from '@alfresco/adf-core';
import { environment } from '../../environments/environment';
@Directive({
// tslint:disable-next-line:directive-selector
selector: '[ifExperimental]'
})
export class ExperimentalDirective {
private elseTemplateRef: TemplateRef<any>;
private elseViewRef: EmbeddedViewRef<any>;
private shouldRender: boolean;
constructor(
private templateRef: TemplateRef<any>,
private viewContainerRef: ViewContainerRef,
private storage: StorageService,
private config: AppConfigService
) {}
@Input()
set ifExperimental(featureKey: string) {
const key = `experimental.${featureKey}`;
const override = this.storage.getItem(key);
if (override === 'true') {
this.shouldRender = true;
}
if (!environment.production) {
const value = this.config.get(key);
if (value === true || value === 'true') {
this.shouldRender = true;
}
}
if (override !== 'true' && environment.production) {
this.shouldRender = false;
}
this.updateView();
}
@Input()
set ifExperimentalElse(templateRef: TemplateRef<any>) {
this.elseTemplateRef = templateRef;
this.elseViewRef = null;
this.updateView();
}
private updateView() {
if (this.shouldRender) {
this.viewContainerRef.clear();
this.elseViewRef = null;
if (this.templateRef) {
this.viewContainerRef.createEmbeddedView(this.templateRef);
}
} else {
if (this.elseViewRef) {
return;
}
this.viewContainerRef.clear();
if (this.elseTemplateRef) {
this.elseViewRef = this.viewContainerRef.createEmbeddedView(
this.elseTemplateRef
);
}
}
}
}

View File

@ -32,6 +32,7 @@ import {
} from '@angular/core';
import { NodeEntry, NodeBodyLock, SharedLinkEntry } from '@alfresco/js-api';
import { AlfrescoApiService } from '@alfresco/adf-core';
import { isLocked } from '../utils/node.utils';
@Directive({
selector: '[acaLockNode]',
@ -52,33 +53,28 @@ export class LockNodeDirective {
constructor(private alfrescoApiService: AlfrescoApiService) {}
isNodeLocked() {
return !!(
this.node &&
this.node.entry.properties &&
this.node.entry.properties['cm:lockType'] === 'WRITE_LOCK'
);
isNodeLocked(): boolean {
return isLocked(this.node);
}
private async toggleLock(node: NodeEntry | SharedLinkEntry) {
const id = (<SharedLinkEntry>node).entry.nodeId || node.entry.id;
if (this.isNodeLocked()) {
if (isLocked(this.node)) {
try {
const response = await this.unlockNode(id);
const isLocked = false;
this.update(response.entry);
this.toggle.emit(isLocked);
this.toggle.emit(false);
} catch (error) {
this.unlockError.emit(error);
}
} else {
try {
const response = await this.lockNode(id);
const isLocked = true;
this.update(response.entry);
this.toggle.emit(isLocked);
this.toggle.emit(true);
} catch (error) {
this.lockError.emit(error);
}

View File

@ -310,7 +310,9 @@ export function isWriteLocked(
context.selection.file &&
context.selection.file.entry &&
context.selection.file.entry.properties &&
context.selection.file.entry.properties['cm:lockType'] === 'WRITE_LOCK'
(context.selection.file.entry.properties['cm:lockType'] === 'WRITE_LOCK' ||
context.selection.file.entry.properties['cm:lockType'] ===
'READ_ONLY_LOCK')
);
}

View File

@ -1,32 +0,0 @@
/*!
* @license
* Alfresco Example Content Application
*
* Copyright (C) 2005 - 2018 Alfresco Software Limited
*
* This file is part of the Alfresco Example Content Application.
* If the software was purchased under a paid Alfresco license, the terms of
* the paid license agreement will prevail. Otherwise, the software is
* provided under the following open source license terms:
*
* The Alfresco Example Content Application is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* The Alfresco Example Content Application is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
*/
import { ExperimentalGuard } from './experimental-guard.service';
describe('ExperimentalGuard', () => {
it('should be defined', () => {
expect(ExperimentalGuard).toBeDefined();
});
});

View File

@ -1,35 +0,0 @@
import { CanActivate, ActivatedRouteSnapshot, Router } from '@angular/router';
import { Injectable } from '@angular/core';
import { AppConfigService, StorageService } from '@alfresco/adf-core';
import { environment } from '../../environments/environment';
@Injectable()
export class ExperimentalGuard implements CanActivate {
constructor(
private config: AppConfigService,
private storage: StorageService,
private router: Router
) {}
canActivate(route: ActivatedRouteSnapshot) {
const key = `experimental.${route.data.ifExperimentalKey}`;
const value = this.config.get(key);
const override = this.storage.getItem(key);
if (override === 'true') {
return true;
}
if (!environment.production) {
if (value === true || value === 'true') {
return true;
}
this.router.navigate(['/']);
}
this.router.navigate(['/']);
return false;
}
}

View File

@ -23,10 +23,28 @@
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
*/
import { ExperimentalDirective } from './experimental.directive';
import { Node } from '@alfresco/js-api';
describe('ExperimentalDirective', () => {
it('should be defined', () => {
expect(ExperimentalDirective).toBeDefined();
});
});
export function isLocked(node: { entry: Node }): boolean {
const { entry } = node;
return (
(entry && entry.isLocked) ||
(entry.properties &&
(entry.properties['cm:lockType'] === 'READ_ONLY_LOCK' ||
entry.properties['cm:lockType'] === 'WRITE_LOCK'))
);
}
export function isLibrary(node: { entry: Node | any }): boolean {
const { entry } = node;
return (
(entry.guid &&
entry.id &&
entry.preset &&
entry.title &&
entry.visibility) ||
entry.nodeType === 'st:site'
);
}

View File

@ -41,7 +41,6 @@
"TITLE": "Einstellungen",
"APPLICATION-SETTINGS": "Anwendungseinstellungen",
"REPOSITORY-SETTINGS": "Repository-Einstellungen",
"EXPERIMENTAL-FEATURES": "Testfunktionen",
"INVALID-VALUE-FORMAT": "Wert in ungültigem Format",
"REQUIRED-FIELD": "Dieses Feld ist erforderlich.",
"RESET": "Zurücksetzen",

View File

@ -41,7 +41,6 @@
"TITLE": "Settings",
"APPLICATION-SETTINGS": "Application Settings",
"REPOSITORY-SETTINGS": "Repository Settings",
"EXPERIMENTAL-FEATURES": "Experimental Features",
"INVALID-VALUE-FORMAT": "Invalid value format",
"REQUIRED-FIELD": "This field is required",
"RESET": "Reset",

View File

@ -41,7 +41,6 @@
"TITLE": "Configuración",
"APPLICATION-SETTINGS": "Configuración de la aplicación",
"REPOSITORY-SETTINGS": "Configuración del repositorio",
"EXPERIMENTAL-FEATURES": "Funciones experimentales",
"INVALID-VALUE-FORMAT": "Formato de valor no válido",
"REQUIRED-FIELD": "Este campo es obligatorio",
"RESET": "Reiniciar",

View File

@ -41,7 +41,6 @@
"TITLE": "Paramètres",
"APPLICATION-SETTINGS": "Paramètres de l'application",
"REPOSITORY-SETTINGS": "Paramètres de l'entrepôt",
"EXPERIMENTAL-FEATURES": "Fonctionnalités expérimentales",
"INVALID-VALUE-FORMAT": "Format de valeur non valide",
"REQUIRED-FIELD": "Ce champ doit être renseigné",
"RESET": "Réinitialiser",

View File

@ -41,7 +41,6 @@
"TITLE": "Impostazioni",
"APPLICATION-SETTINGS": "Impostazioni applicazione",
"REPOSITORY-SETTINGS": "Impostazioni repository",
"EXPERIMENTAL-FEATURES": "Funzioni sperimentali",
"INVALID-VALUE-FORMAT": "Formato valore non valido",
"REQUIRED-FIELD": "Questo campo è obbligatorio",
"RESET": "Reimposta",

View File

@ -41,7 +41,6 @@
"TITLE": "設定",
"APPLICATION-SETTINGS": "アプリケーションの設定",
"REPOSITORY-SETTINGS": "リポジトリの設定",
"EXPERIMENTAL-FEATURES": "試験的な機能",
"INVALID-VALUE-FORMAT": "無効な値形式",
"REQUIRED-FIELD": "このフィールドは必須です",
"RESET": "リセット",

View File

@ -41,7 +41,6 @@
"TITLE": "Innstillinger",
"APPLICATION-SETTINGS": "Programinnstillinger",
"REPOSITORY-SETTINGS": "Databaseinnstillinger",
"EXPERIMENTAL-FEATURES": "Eksperimentelle funksjoner",
"INVALID-VALUE-FORMAT": "Ugyldig verdiformat",
"REQUIRED-FIELD": "Dette feltet er obligatorisk",
"RESET": "Tilbakestill",

View File

@ -41,7 +41,6 @@
"TITLE": "Instellingen",
"APPLICATION-SETTINGS": "Toepassingsinstellingen",
"REPOSITORY-SETTINGS": "Opslagplaatsinstellingen",
"EXPERIMENTAL-FEATURES": "Experimentele onderdelen",
"INVALID-VALUE-FORMAT": "Ongeldige indeling van waarde",
"REQUIRED-FIELD": "Dit veld is vereist",
"RESET": "Opnieuw instellen",

View File

@ -41,7 +41,6 @@
"TITLE": "Configurações",
"APPLICATION-SETTINGS": "Configurações do aplicativo",
"REPOSITORY-SETTINGS": "Configurações do repositório",
"EXPERIMENTAL-FEATURES": "Recursos experimentais",
"INVALID-VALUE-FORMAT": "Formato de valor inválido",
"REQUIRED-FIELD": "Este campo é obrigatório",
"RESET": "Redefinir",

View File

@ -41,7 +41,6 @@
"TITLE": "Параметры",
"APPLICATION-SETTINGS": "Настройки приложений",
"REPOSITORY-SETTINGS": "Настройки репозитория",
"EXPERIMENTAL-FEATURES": "Экспериментальные функции",
"INVALID-VALUE-FORMAT": "Недопустимый формат значения",
"REQUIRED-FIELD": "Это обязательное поле",
"RESET": "Сброс",

View File

@ -41,7 +41,6 @@
"TITLE": "设置",
"APPLICATION-SETTINGS": "应用程序设置",
"REPOSITORY-SETTINGS": "存储库设置",
"EXPERIMENTAL-FEATURES": "试验性功能",
"INVALID-VALUE-FORMAT": "值格式无效",
"REQUIRED-FIELD": "此字段为必填字段",
"RESET": "重置",