[ADF-1774] Extend "Create Folder" and add "Edit Folder" dialogs to ADF (#2585)

* [ADF-1774] Extend "Create Folder" and add "Edit Folder" dialogs to ADF

- added create and edit folder directives and used them inside the demo-shell file component
- added FolderDialogComponent for edit/create actions with name validators: forbidSpecialCharacters, forbidEndingDot and forbidOnlySpaces
- updated the translation files
- added unit tests for the new components
- removed the CreateFolderDialogComponent and its usage inside demo-shell
- added documentation files for FolderCreateDirective and FolderEditDirective

* [ADF-1774] fix messed up translation files because of previous commit

* [ADF-1774] changes required on code review comments
This commit is contained in:
suzanadirla
2017-11-03 16:45:42 +02:00
committed by Eugenio Romano
parent c74b696a6e
commit 5dabc39841
28 changed files with 1431 additions and 117 deletions

View File

@@ -29,8 +29,8 @@ import { CardViewModule } from './src/components/view/card-view.module';
import { MaterialModule } from './src/material.module';
import { AppConfigModule } from './src/services/app-config.service';
import { CreateFolderDialogComponent } from './src/dialogs/create-folder.dialog';
import { DownloadZipDialogComponent } from './src/dialogs/download-zip.dialog';
import { FolderDialogComponent } from './src/dialogs/folder.dialog';
import { AlfrescoApiService } from './src/services/alfresco-api.service';
import { AlfrescoContentService } from './src/services/alfresco-content.service';
@@ -52,6 +52,8 @@ import { AlfrescoTranslateLoader } from './src/services/translate-loader.service
import { TRANSLATION_PROVIDER, TranslationService } from './src/services/translation.service';
import { UploadService } from './src/services/upload.service';
import { FolderCreateDirective } from './src/directives/folder-create.directive';
import { FolderEditDirective } from './src/directives/folder-edit.directive';
import { HighlightDirective } from './src/directives/highlight.directive';
import { LogoutDirective } from './src/directives/logout.directive';
import { NodeDeleteDirective } from './src/directives/node-delete.directive';
@@ -73,8 +75,8 @@ import { UserPreferencesService } from './src/services/user-preferences.service'
export { MomentDateAdapter, MOMENT_DATE_FORMATS } from './src/utils/momentDateAdapter';
import { MomentDateAdapter } from './src/utils/momentDateAdapter';
export { CreateFolderDialogComponent } from './src/dialogs/create-folder.dialog';
export { DownloadZipDialogComponent } from './src/dialogs/download-zip.dialog';
export { FolderDialogComponent } from './src/dialogs/folder.dialog';
export { PageTitleService } from './src/services/page-title.service';
export { ContentService } from './src/services/content.service';
@@ -264,6 +266,8 @@ export function createTranslateLoader(http: Http, logService: LogService) {
],
declarations: [
...pipes(),
FolderCreateDirective,
FolderEditDirective,
LogoutDirective,
UploadDirective,
NodeRestoreDirective,
@@ -281,8 +285,8 @@ export function createTranslateLoader(http: Http, logService: LogService) {
InfoDrawerContentDirective,
LanguageMenuComponent,
HostSettingsComponent,
CreateFolderDialogComponent,
DownloadZipDialogComponent,
FolderDialogComponent,
InfinitePaginationComponent,
PaginationComponent
],
@@ -312,6 +316,8 @@ export function createTranslateLoader(http: Http, logService: LogService) {
CollapsableModule,
ToolbarModule,
...pipes(),
FolderCreateDirective,
FolderEditDirective,
LogoutDirective,
UploadDirective,
NodeRestoreDirective,
@@ -322,8 +328,8 @@ export function createTranslateLoader(http: Http, logService: LogService) {
HostSettingsComponent,
DataColumnComponent,
DataColumnListComponent,
CreateFolderDialogComponent,
DownloadZipDialogComponent,
FolderDialogComponent,
InfoDrawerComponent,
InfoDrawerTabComponent,
InfoDrawerLayoutComponent,
@@ -335,8 +341,8 @@ export function createTranslateLoader(http: Http, logService: LogService) {
PaginationComponent
],
entryComponents: [
CreateFolderDialogComponent,
DownloadZipDialogComponent
DownloadZipDialogComponent,
FolderDialogComponent
]
})
export class CoreModule {}

View File

@@ -1,45 +0,0 @@
/*!
* @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 { Component, ViewEncapsulation } from '@angular/core';
@Component({
selector: 'adf-create-folder-dialog',
template: `
<h1 matDialogTitle>Create a new folder</h1>
<div mat-dialog-content>
<mat-form-field class="create-folder--name">
<input matInput placeholder="Folder name" [(ngModel)]="value">
</mat-form-field>
</div>
<div mat-dialog-actions>
<button mat-button matDialogClose>Cancel</button>
<button mat-button [matDialogClose]="value">Create</button>
</div>
`,
styles: [
`
.create-folder--name {
width: 100%;
}
`
],
encapsulation: ViewEncapsulation.None
})
export class CreateFolderDialogComponent {
value: string = '';
}

View File

@@ -0,0 +1,45 @@
/*!
* @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 { FormControl } from '@angular/forms';
const I18N_ERRORS_PATH = 'CORE.FOLDER_DIALOG.FOLDER_NAME.ERRORS';
export function forbidSpecialCharacters({ value }: FormControl) {
const specialCharacters: RegExp = /([\*\"\<\>\\\/\?\:\|])/;
const isValid: boolean = !specialCharacters.test(value);
return (isValid) ? null : {
message: `${I18N_ERRORS_PATH}.SPECIAL_CHARACTERS`
};
}
export function forbidEndingDot({ value }: FormControl) {
const isValid: boolean = ((value || '').trim().split('').pop() !== '.');
return isValid ? null : {
message: `${I18N_ERRORS_PATH}.ENDING_DOT`
};
}
export function forbidOnlySpaces({ value }: FormControl) {
const isValid: boolean = !!((value || '')).trim();
return isValid ? null : {
message: `${I18N_ERRORS_PATH}.ONLY_SPACES`
};
}

View File

@@ -0,0 +1,64 @@
<h2 mat-dialog-title>
{{
(editing
? 'CORE.FOLDER_DIALOG.EDIT_FOLDER_TITLE'
: 'CORE.FOLDER_DIALOG.CREATE_FOLDER_TITLE'
) | translate
}}
</h2>
<mat-dialog-content>
<form [formGroup]="form" (submit)="submit()">
<mat-input-container class="adf-full-width">
<input
placeholder="{{ 'CORE.FOLDER_DIALOG.FOLDER_NAME.LABEL' | translate }}"
matInput
required
[formControl]="form.controls['name']"
/>
<mat-hint *ngIf="form.controls['name'].dirty">
<span *ngIf="form.controls['name'].errors?.required">
{{ 'CORE.FOLDER_DIALOG.FOLDER_NAME.ERRORS.REQUIRED' | translate }}
</span>
<span *ngIf="!form.controls['name'].errors?.required && form.controls['name'].errors?.message">
{{ form.controls['name'].errors?.message | translate }}
</span>
</mat-hint>
</mat-input-container>
<br />
<br />
<mat-input-container class="adf-full-width">
<textarea
matInput
placeholder="{{ 'CORE.FOLDER_DIALOG.FOLDER_DESCRIPTION.LABEL' | translate }}"
rows="4"
[formControl]="form.controls['description']"></textarea>
</mat-input-container>
</form>
</mat-dialog-content>
<mat-dialog-actions>
<span class="adf-fill-remaining-space"></span>
<button
mat-button
mat-dialog-close>
{{ 'CORE.FOLDER_DIALOG.CANCEL_BUTTON.LABEL' | translate }}
</button>
<button
mat-button
(click)="submit()"
[disabled]="!form.valid">
{{
(editing
? 'CORE.FOLDER_DIALOG.UPDATE_BUTTON.LABEL'
: 'CORE.FOLDER_DIALOG.CREATE_BUTTON.LABEL'
) | translate
}}
</button>
</mat-dialog-actions>

View File

@@ -0,0 +1,7 @@
.adf-fill-remaining-space {
flex: 1 1 auto;
}
.adf-full-width {
width: 100%;
}

View File

@@ -0,0 +1,273 @@
/*!
* @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 { async, TestBed } from '@angular/core/testing';
import { ComponentFixture } from '@angular/core/testing';
import { FormsModule, ReactiveFormsModule } from '@angular/forms';
import { MatDialogModule, MatDialogRef } from '@angular/material';
import { BrowserDynamicTestingModule } from '@angular/platform-browser-dynamic/testing';
import { Observable } from 'rxjs/Rx';
import { AlfrescoTranslationService, CoreModule } from '../../index';
import { TranslationMock } from '../assets/translation.service.mock';
import { NodesApiService } from '../services/nodes-api.service';
import { NotificationService } from '../services/notification.service';
import { TranslationService } from '../services/translation.service';
import { FolderDialogComponent } from './folder.dialog';
describe('FolderDialogComponent', () => {
let fixture: ComponentFixture<FolderDialogComponent>;
let component: FolderDialogComponent;
let translationService: TranslationService;
let nodesApi: NodesApiService;
let notificationService: NotificationService;
let dialogRef;
beforeEach(async(() => {
dialogRef = {
close: jasmine.createSpy('close')
};
TestBed.configureTestingModule({
imports: [
CoreModule,
MatDialogModule,
FormsModule,
ReactiveFormsModule,
BrowserDynamicTestingModule
],
providers: [
{ provide: MatDialogRef, useValue: dialogRef },
{ provide: AlfrescoTranslationService, useClass: TranslationMock }
]
});
// entryComponents are not supported yet on TestBed, that is why this ugly workaround:
// https://github.com/angular/angular/issues/10760
TestBed.overrideModule(BrowserDynamicTestingModule, {
set: {entryComponents: [ FolderDialogComponent ]}
});
TestBed.compileComponents();
}));
beforeEach(() => {
fixture = TestBed.createComponent(FolderDialogComponent);
component = fixture.componentInstance;
nodesApi = TestBed.get(NodesApiService);
notificationService = TestBed.get(NotificationService);
translationService = TestBed.get(TranslationService);
spyOn(translationService, 'get').and.returnValue(Observable.of('message'));
});
describe('Edit', () => {
beforeEach(() => {
component.data = {
folder: {
id: 'node-id',
name: 'folder-name',
properties: {
['cm:description']: 'folder-description'
}
}
};
fixture.detectChanges();
});
it('should init form with folder name and description', () => {
expect(component.name).toBe('folder-name');
expect(component.description).toBe('folder-description');
});
it('should update form input', () => {
component.form.controls['name'].setValue('folder-name-update');
component.form.controls['description'].setValue('folder-description-update');
expect(component.name).toBe('folder-name-update');
expect(component.description).toBe('folder-description-update');
});
it('should submit updated values if form is valid', () => {
spyOn(nodesApi, 'updateNode').and.returnValue(Observable.of({}));
component.form.controls['name'].setValue('folder-name-update');
component.form.controls['description'].setValue('folder-description-update');
component.submit();
expect(nodesApi.updateNode).toHaveBeenCalledWith(
'node-id',
{
name: 'folder-name-update',
properties: {
'cm:title': 'folder-name-update',
'cm:description': 'folder-description-update'
}
}
);
});
it('should call dialog to close with form data when submit is succesfluly', () => {
const folder = {
data: 'folder-data'
};
spyOn(nodesApi, 'updateNode').and.returnValue(Observable.of(folder));
component.submit();
expect(dialogRef.close).toHaveBeenCalledWith(folder);
});
it('should not submit if form is invalid', () => {
spyOn(nodesApi, 'updateNode');
component.form.controls['name'].setValue('');
component.form.controls['description'].setValue('');
component.submit();
expect(component.form.valid).toBe(false);
expect(nodesApi.updateNode).not.toHaveBeenCalled();
});
it('should not call dialog to close if submit fails', () => {
spyOn(nodesApi, 'updateNode').and.returnValue(Observable.throw('error'));
spyOn(component, 'handleError').and.callFake(val => val);
component.submit();
expect(component.handleError).toHaveBeenCalled();
expect(dialogRef.close).not.toHaveBeenCalled();
});
});
describe('Create', () => {
beforeEach(() => {
component.data = {
parentNodeId: 'parentNodeId',
folder: null
};
fixture.detectChanges();
});
it('should init form with empty inputs', () => {
expect(component.name).toBe('');
expect(component.description).toBe('');
});
it('should update form input', () => {
component.form.controls['name'].setValue('folder-name-update');
component.form.controls['description'].setValue('folder-description-update');
expect(component.name).toBe('folder-name-update');
expect(component.description).toBe('folder-description-update');
});
it('should submit updated values if form is valid', () => {
spyOn(nodesApi, 'createFolder').and.returnValue(Observable.of({}));
component.form.controls['name'].setValue('folder-name-update');
component.form.controls['description'].setValue('folder-description-update');
component.submit();
expect(nodesApi.createFolder).toHaveBeenCalledWith(
'parentNodeId',
{
name: 'folder-name-update',
properties: {
'cm:title': 'folder-name-update',
'cm:description': 'folder-description-update'
}
}
);
});
it('should call dialog to close with form data when submit is succesfluly', () => {
const folder = {
data: 'folder-data'
};
component.form.controls['name'].setValue('name');
component.form.controls['description'].setValue('description');
spyOn(nodesApi, 'createFolder').and.returnValue(Observable.of(folder));
component.submit();
expect(dialogRef.close).toHaveBeenCalledWith(folder);
});
it('should not submit if form is invalid', () => {
spyOn(nodesApi, 'createFolder');
component.form.controls['name'].setValue('');
component.form.controls['description'].setValue('');
component.submit();
expect(component.form.valid).toBe(false);
expect(nodesApi.createFolder).not.toHaveBeenCalled();
});
it('should not call dialog to close if submit fails', () => {
spyOn(nodesApi, 'createFolder').and.returnValue(Observable.throw('error'));
spyOn(component, 'handleError').and.callFake(val => val);
component.form.controls['name'].setValue('name');
component.form.controls['description'].setValue('description');
component.submit();
expect(component.handleError).toHaveBeenCalled();
expect(dialogRef.close).not.toHaveBeenCalled();
});
});
describe('handleError()', () => {
it('should raise error for 409', () => {
spyOn(notificationService, 'openSnackMessage').and.stub();
const error = {
message: '{ "error": { "statusCode" : 409 } }'
};
component.handleError(error);
expect(notificationService.openSnackMessage).toHaveBeenCalled();
expect(translationService.get).toHaveBeenCalledWith('CORE.MESSAGES.ERRORS.EXISTENT_FOLDER');
});
it('should raise generic error', () => {
spyOn(notificationService, 'openSnackMessage').and.stub();
const error = {
message: '{ "error": { "statusCode" : 123 } }'
};
component.handleError(error);
expect(notificationService.openSnackMessage).toHaveBeenCalled();
expect(translationService.get).toHaveBeenCalledWith('CORE.MESSAGES.ERRORS.GENERIC');
});
});
});

View File

@@ -0,0 +1,142 @@
/*!
* @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 } from 'rxjs/Rx';
import { Component, Inject, OnInit, Optional } from '@angular/core';
import { FormBuilder, FormGroup, Validators } from '@angular/forms';
import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material';
import { MinimalNodeEntryEntity } from 'alfresco-js-api';
import { NodesApiService } from '../services/nodes-api.service';
import { NotificationService } from '../services/notification.service';
import { TranslationService } from '../services/translation.service';
import { forbidEndingDot, forbidOnlySpaces, forbidSpecialCharacters } from './folder-name.validators';
@Component({
selector: 'adf-folder-dialog',
styleUrls: ['./folder.dialog.scss'],
templateUrl: './folder.dialog.html'
})
export class FolderDialogComponent implements OnInit {
form: FormGroup;
folder: MinimalNodeEntryEntity = null;
constructor(
private formBuilder: FormBuilder,
private dialog: MatDialogRef<FolderDialogComponent>,
private nodesApi: NodesApiService,
private translation: TranslationService,
private notification: NotificationService,
@Optional()
@Inject(MAT_DIALOG_DATA)
public data: any
) {}
get editing(): boolean {
return !!this.data.folder;
}
ngOnInit() {
const { folder } = this.data;
let name = '';
let description = '';
if (folder) {
const { properties } = folder;
name = folder.name || '';
description = properties ? properties['cm:description'] : '';
}
const validators = {
name: [
Validators.required,
forbidSpecialCharacters,
forbidEndingDot,
forbidOnlySpaces
]
};
this.form = this.formBuilder.group({
name: [ name, validators.name ],
description: [ description ]
});
}
get name(): string {
let { name } = this.form.value;
return (name || '').trim();
}
get description(): string {
let { description } = this.form.value;
return (description || '').trim();
}
private get properties(): any {
const { name: title, description } = this;
return {
'cm:title': title,
'cm:description': description
};
}
private create(): Observable<MinimalNodeEntryEntity> {
const { name, properties, nodesApi, data: { parentNodeId} } = this;
return nodesApi.createFolder(parentNodeId, { name, properties });
}
private edit(): Observable<MinimalNodeEntryEntity> {
const { name, properties, nodesApi, data: { folder: { id: nodeId }} } = this;
return nodesApi.updateNode(nodeId, { name, properties });
}
submit() {
const { form, dialog, editing } = this;
if (!form.valid) { return; }
(editing ? this.edit() : this.create())
.subscribe(
(folder: MinimalNodeEntryEntity) => dialog.close(folder),
(error) => this.handleError(error)
);
}
handleError(error: any): any {
let i18nMessageString = 'CORE.MESSAGES.ERRORS.GENERIC';
try {
const { error: { statusCode } } = JSON.parse(error.message);
if (statusCode === 409) {
i18nMessageString = 'CORE.MESSAGES.ERRORS.EXISTENT_FOLDER';
}
} catch (err) { /* Do nothing, keep the original message */ }
this.translation.get(i18nMessageString).subscribe(message => {
this.notification.openSnackMessage(message, 3000);
});
return error;
}
}

View File

@@ -0,0 +1,115 @@
/*!
* @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 { Component } from '@angular/core';
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { FormsModule, ReactiveFormsModule } from '@angular/forms';
import { HttpModule } from '@angular/http';
import { MatDialog, MatDialogModule } from '@angular/material';
import { By } from '@angular/platform-browser';
import { TranslateLoader, TranslateModule } from '@ngx-translate/core';
import { Observable } from 'rxjs/Rx';
import { AppConfigService, providers } from '../../index';
import { AlfrescoContentService } from '../services/alfresco-content.service';
import { AlfrescoTranslateLoader } from '../services/translate-loader.service';
import { FolderCreateDirective } from './folder-create.directive';
@Component({
template: '<div [adf-create-folder]="parentNode"></div>'
})
class TestComponent {
parentNode = '';
}
describe('FolderCreateDirective', () => {
let fixture: ComponentFixture<TestComponent>;
let element;
let node: any;
let dialog: MatDialog;
let contentService: AlfrescoContentService;
let dialogRefMock;
const event: any = {
type: 'click',
preventDefault: () => null
};
beforeEach(() => {
TestBed.configureTestingModule({
imports: [
HttpModule,
MatDialogModule,
FormsModule,
ReactiveFormsModule,
TranslateModule.forRoot({
loader: {
provide: TranslateLoader,
useClass: AlfrescoTranslateLoader
}
})
],
declarations: [
TestComponent,
FolderCreateDirective
],
providers: [
AlfrescoContentService,
AppConfigService,
...providers()
]
});
TestBed.compileComponents();
fixture = TestBed.createComponent(TestComponent);
element = fixture.debugElement.query(By.directive(FolderCreateDirective));
dialog = TestBed.get(MatDialog);
contentService = TestBed.get(AlfrescoContentService);
});
beforeEach(() => {
node = { entry: { id: 'nodeId' } };
dialogRefMock = {
afterClosed: val => Observable.of(val)
};
spyOn(dialog, 'open').and.returnValue(dialogRefMock);
});
it('should emit folderCreate event when input value is not undefined', () => {
spyOn(dialogRefMock, 'afterClosed').and.returnValue(Observable.of(node));
contentService.folderCreate.subscribe((val) => {
expect(val).toBe(node);
});
element.triggerEventHandler('click', event);
fixture.detectChanges();
});
it('should not emit folderCreate event when input value is undefined', () => {
spyOn(dialogRefMock, 'afterClosed').and.returnValue(Observable.of(null));
spyOn(contentService.folderCreate, 'next');
element.triggerEventHandler('click', event);
fixture.detectChanges();
expect(contentService.folderCreate.next).not.toHaveBeenCalled();
});
});

View File

@@ -0,0 +1,68 @@
/*!
* @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 { Directive, HostListener, Input } from '@angular/core';
import { MatDialog, MatDialogConfig } from '@angular/material';
import { MinimalNodeEntryEntity } from 'alfresco-js-api';
import { FolderDialogComponent } from '../dialogs/folder.dialog';
import { AlfrescoContentService } from '../services/alfresco-content.service';
const DEFAULT_FOLDER_PARENT_ID = '-my-';
@Directive({
selector: '[adf-create-folder]'
})
export class FolderCreateDirective {
static DIALOG_WIDTH: number = 400;
@Input('adf-create-folder')
parentNodeId: string = DEFAULT_FOLDER_PARENT_ID;
@HostListener('click', [ '$event' ])
onClick(event) {
event.preventDefault();
this.openDialog();
}
constructor(
public dialogRef: MatDialog,
public content: AlfrescoContentService
) {}
private get dialogConfig(): MatDialogConfig {
const { DIALOG_WIDTH: width } = FolderCreateDirective;
const { parentNodeId } = this;
return {
data: { parentNodeId },
width: `${width}px`
};
}
private openDialog(): void {
const { dialogRef, dialogConfig, content } = this;
const dialogInstance = dialogRef.open(FolderDialogComponent, dialogConfig);
dialogInstance.afterClosed().subscribe((node: MinimalNodeEntryEntity) => {
if (node) {
content.folderCreate.next(node);
}
});
}
}

View File

@@ -0,0 +1,117 @@
/*!
* @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 { Component } from '@angular/core';
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { HttpModule } from '@angular/http';
import { MatDialog, MatDialogModule } from '@angular/material';
import { By } from '@angular/platform-browser';
import { FormsModule, ReactiveFormsModule } from '@angular/forms';
import { TranslateLoader, TranslateModule } from '@ngx-translate/core';
import { Observable } from 'rxjs/Rx';
import { AppConfigService, providers } from '../../index';
import { AlfrescoContentService } from '../services/alfresco-content.service';
import { AlfrescoTranslateLoader } from '../services/translate-loader.service';
import { FolderEditDirective } from './folder-edit.directive';
@Component({
template: '<div [adf-edit-folder]="folder"></div>'
})
class TestComponent {
folder = {};
}
describe('FolderEditDirective', () => {
let fixture: ComponentFixture<TestComponent>;
let element;
let node: any;
let dialog: MatDialog;
let contentService: AlfrescoContentService;
let dialogRefMock;
const event = {
type: 'click',
preventDefault: () => null
};
beforeEach(() => {
TestBed.configureTestingModule({
imports: [
HttpModule,
MatDialogModule,
FormsModule,
ReactiveFormsModule,
TranslateModule.forRoot({
loader: {
provide: TranslateLoader,
useClass: AlfrescoTranslateLoader
}
})
],
declarations: [
TestComponent,
FolderEditDirective
]
,
providers: [
AlfrescoContentService,
AppConfigService,
...providers()
]
});
TestBed.compileComponents();
fixture = TestBed.createComponent(TestComponent);
element = fixture.debugElement.query(By.directive(FolderEditDirective));
dialog = TestBed.get(MatDialog);
contentService = TestBed.get(AlfrescoContentService);
});
beforeEach(() => {
node = { entry: { id: 'folderId' } };
dialogRefMock = {
afterClosed: val => Observable.of(val)
};
spyOn(dialog, 'open').and.returnValue(dialogRefMock);
});
it('should emit folderEdit event when input value is not undefined', () => {
spyOn(dialogRefMock, 'afterClosed').and.returnValue(Observable.of(node));
contentService.folderEdit.subscribe((val) => {
expect(val).toBe(node);
});
element.triggerEventHandler('click', event);
fixture.detectChanges();
});
it('should not emit folderEdit event when input value is undefined', () => {
spyOn(dialogRefMock, 'afterClosed').and.returnValue(Observable.of(null));
spyOn(contentService.folderEdit, 'next');
element.triggerEventHandler('click', event);
fixture.detectChanges();
expect(contentService.folderEdit.next).not.toHaveBeenCalled();
});
});

View File

@@ -0,0 +1,69 @@
/*!
* @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 { Directive, ElementRef, HostListener, Input } from '@angular/core';
import { MatDialog, MatDialogConfig } from '@angular/material';
import { MinimalNodeEntryEntity } from 'alfresco-js-api';
import { FolderDialogComponent } from '../dialogs/folder.dialog';
import { AlfrescoContentService } from '../services/alfresco-content.service';
@Directive({
selector: '[adf-edit-folder]'
})
export class FolderEditDirective {
static DIALOG_WIDTH: number = 400;
@Input('adf-edit-folder')
folder: MinimalNodeEntryEntity;
@HostListener('click', [ '$event' ])
onClick(event) {
event.preventDefault();
if (this.folder) {
this.openDialog();
}
}
constructor(
public dialogRef: MatDialog,
public elementRef: ElementRef,
public content: AlfrescoContentService
) {}
private get dialogConfig(): MatDialogConfig {
const { DIALOG_WIDTH: width } = FolderEditDirective;
const { folder } = this;
return {
data: { folder },
width: `${width}px`
};
}
private openDialog(): void {
const { dialogRef, dialogConfig, content } = this;
const dialogInstance = dialogRef.open(FolderDialogComponent, dialogConfig);
dialogInstance.afterClosed().subscribe((node: MinimalNodeEntryEntity) => {
if (node) {
content.folderEdit.next(node);
}
});
}
}

View File

@@ -4,14 +4,45 @@
"ITEMS_RANGE": "Angezeigt werden {{ range }} von {{ total }}",
"ITEMS_PER_PAGE": "Elemente pro Seite",
"CURRENT_PAGE": "Seite {{ number }}",
"TOTAL_PAGES": "von {{ total }}",
"HOST_SETTINGS": {
"TITLE": "Einstellungen",
"CS-HOST": "Konfiguration der Host-URL für Content Services",
"BP-HOST": "Konfiguration der Host-URL für Process Services",
"BACK": "Zurück",
"APPLY": "ANWENDEN"
"TOTAL_PAGES": "von {{ total }}"
},
"FOLDER_DIALOG": {
"CREATE_FOLDER_TITLE": "Neuen Ordner erstellen",
"EDIT_FOLDER_TITLE": "Ordner bearbeiten",
"FOLDER_NAME": {
"LABEL": "Name",
"ERRORS": {
"REQUIRED": "Ordnername ist erforderlich",
"SPECIAL_CHARACTERS": "Ordnername darf die folgenden Zeichen nicht enthalten: * \" < > \\ / ? : |",
"ENDING_DOT": "Ordnername darf nicht mit einem Punkt enden.",
"ONLY_SPACES": "Ordnername darf nicht nur aus Leerzeichen bestehen."
}
},
"FOLDER_DESCRIPTION": {
"LABEL": "Beschreibung"
},
"CREATE_BUTTON": {
"LABEL": "Erstellen"
},
"UPDATE_BUTTON": {
"LABEL": "Aktualisieren"
},
"CANCEL_BUTTON": {
"LABEL": "Abbrechen"
}
},
"MESSAGES": {
"ERRORS": {
"GENERIC": "Die Aktion war nicht erfolgreich. Versuchen Sie es noch einmal oder wenden Sie sich an Ihr IT-Team.",
"EXISTENT_FOLDER": "Es gibt bereits einen Ordner mit diesem Namen. Probieren Sie es mit einem anderen Namen."
}
},
"HOST_SETTINGS": {
"TITLE": "Einstellungen",
"CS-HOST": "Konfiguration der Host-URL für Content Services",
"BP-HOST": "Konfiguration der Host-URL für Process Services",
"BACK": "Zurück",
"APPLY": "ANWENDEN"
}
}
}

View File

@@ -1,45 +1,76 @@
{
"CORE": {
"PAGINATION": {
"ITEMS_RANGE": "Showing {{ range }} of {{ total }}",
"ITEMS_PER_PAGE": "Items per page",
"CURRENT_PAGE": "Page {{ number }}",
"TOTAL_PAGES": "of {{ total }}"
"CORE": {
"PAGINATION": {
"ITEMS_RANGE": "Showing {{ range }} of {{ total }}",
"ITEMS_PER_PAGE": "Items per page",
"CURRENT_PAGE": "Page {{ number }}",
"TOTAL_PAGES": "of {{ total }}"
},
"DIALOG": {
"DOWNLOAD_ZIP": {
"ACTIONS": {
"CANCEL": "Cancel"
},
"DIALOG": {
"DOWNLOAD_ZIP": {
"ACTIONS": {
"CANCEL": "Cancel"
},
"TITLE": "Adding files to zip, this could take a few minutes"
}
},
"RESTORE_NODE": {
"VIEW": "View",
"PARTIAL_PLURAL": "{{ number }} items not restored because of issues with the restore location",
"NODE_EXISTS": "Can't restore, {{ name }} item already exists",
"LOCATION_MISSING": "Can't restore {{ name }} item, the original location no longer exists",
"GENERIC": "There was a problem restoring {{ name }} item",
"PLURAL": "Restore successful",
"SINGULAR": "{{ name }} item restored"
},
"DELETE_NODE": {
"SINGULAR": "{{ name }} deleted",
"PLURAL": "{{ number }} items deleted",
"PARTIAL_SINGULAR": "Deleted {{ success }} item, {{ failed }} couldn't be deleted",
"PARTIAL_PLURAL": "Deleted {{ success }} items, {{ failed }} couldn't be deleted",
"ERROR_SINGULAR": "{{ name }} couldn't be deleted",
"ERROR_PLURAL": "{{ number }} items couldn't be deleted"
},
"HOST_SETTINGS" : {
"CS_URL_ERROR":"Content service address does not match the pattern",
"PS_URL_ERROR":"Process service address does not match the pattern",
"TITLE": "Settings",
"CS-HOST": "Content Services host URL configuration",
"BP-HOST": "Process Services host URL configuration",
"BACK": "Back",
"APPLY": "APPLY",
"NOT_VALID": "Host not valid! http(s)://host|ip:port(/path)"
"TITLE": "Adding files to zip, this could take a few minutes"
}
},
"FOLDER_DIALOG": {
"CREATE_FOLDER_TITLE": "Create new folder",
"EDIT_FOLDER_TITLE": "Edit folder",
"FOLDER_NAME": {
"LABEL": "Name",
"ERRORS": {
"REQUIRED": "Folder name is required",
"SPECIAL_CHARACTERS": "Folder name can't contain these characters * \" < > \\ / ? : |",
"ENDING_DOT": "Folder name can't end with a period .",
"ONLY_SPACES": "Folder name can't contain only spaces"
}
},
"FOLDER_DESCRIPTION": {
"LABEL": "Description"
},
"CREATE_BUTTON": {
"LABEL": "Create"
},
"UPDATE_BUTTON": {
"LABEL": "Update"
},
"CANCEL_BUTTON": {
"LABEL": "Cancel"
}
},
"MESSAGES": {
"ERRORS": {
"GENERIC": "The action was unsuccessful. Try again or contact your IT Team.",
"EXISTENT_FOLDER": "There's already a folder with this name. Try a different name."
}
},
"RESTORE_NODE": {
"VIEW": "View",
"PARTIAL_PLURAL": "{{ number }} items not restored because of issues with the restore location",
"NODE_EXISTS": "Can't restore, {{ name }} item already exists",
"LOCATION_MISSING": "Can't restore {{ name }} item, the original location no longer exists",
"GENERIC": "There was a problem restoring {{ name }} item",
"PLURAL": "Restore successful",
"SINGULAR": "{{ name }} item restored"
},
"DELETE_NODE": {
"SINGULAR": "{{ name }} deleted",
"PLURAL": "{{ number }} items deleted",
"PARTIAL_SINGULAR": "Deleted {{ success }} item, {{ failed }} couldn't be deleted",
"PARTIAL_PLURAL": "Deleted {{ success }} items, {{ failed }} couldn't be deleted",
"ERROR_SINGULAR": "{{ name }} couldn't be deleted",
"ERROR_PLURAL": "{{ number }} items couldn't be deleted"
},
"HOST_SETTINGS": {
"CS_URL_ERROR": "Content service address does not match the pattern",
"PS_URL_ERROR": "Process service address does not match the pattern",
"TITLE": "Settings",
"CS-HOST": "Content Services host URL configuration",
"BP-HOST": "Process Services host URL configuration",
"BACK": "Back",
"APPLY": "APPLY",
"NOT_VALID": "Host not valid! http(s)://host|ip:port(/path)"
}
}
}

View File

@@ -6,6 +6,37 @@
"CURRENT_PAGE": "Página {{ number }}",
"TOTAL_PAGES": "de {{ total }}"
},
"FOLDER_DIALOG": {
"CREATE_FOLDER_TITLE": "Crear nueva carpeta",
"EDIT_FOLDER_TITLE": "Editar carpeta",
"FOLDER_NAME": {
"LABEL": "Nombre",
"ERRORS": {
"REQUIRED": "Se necesita un nombre de carpeta",
"SPECIAL_CHARACTERS": "El nombre de la carpeta no puede tener los caracteres * \" < > \\ / ? : |",
"ENDING_DOT": "El nombre de la carpeta no puede terminar en punto .",
"ONLY_SPACES": "El nombre de la carpeta no puede tener solo espacios"
}
},
"FOLDER_DESCRIPTION": {
"LABEL": "Descripción"
},
"CREATE_BUTTON": {
"LABEL": "Crear"
},
"UPDATE_BUTTON": {
"LABEL": "Actualizar"
},
"CANCEL_BUTTON": {
"LABEL": "Cancelar"
}
},
"MESSAGES": {
"ERRORS": {
"GENERIC": "La acción no ha sido satisfactoria. Vuelva a intentarlo o póngase en contacto con el equipo de TI.",
"EXISTENT_FOLDER": "Ya existe una carpeta con este nombre. Pruebe un nombre diferente."
}
},
"HOST_SETTINGS": {
"TITLE": "Configuración",
"CS-HOST": "Configuración de URL de host de Content Services",

View File

@@ -6,12 +6,43 @@
"CURRENT_PAGE": "Page {{ number }}",
"TOTAL_PAGES": "sur {{ total }}"
},
"FOLDER_DIALOG": {
"CREATE_FOLDER_TITLE": "Créer un nouveau filtre",
"EDIT_FOLDER_TITLE": "Modifier le dossier",
"FOLDER_NAME": {
"LABEL": "Nom",
"ERRORS": {
"REQUIRED": "Nom de dossier requis",
"SPECIAL_CHARACTERS": "Un nom de dossier ne peut pas contenir les caractères * \" < > \\ / ? : |",
"ENDING_DOT": "Un nom de dossier ne peut pas se terminer par un point .",
"ONLY_SPACES": "Un nom de dossier ne peut pas contenir uniquement des espaces"
}
},
"FOLDER_DESCRIPTION": {
"LABEL": "Description"
},
"CREATE_BUTTON": {
"LABEL": "Créer"
},
"UPDATE_BUTTON": {
"LABEL": "Mis à jour"
},
"CANCEL_BUTTON": {
"LABEL": "Annuler"
}
},
"MESSAGES": {
"ERRORS": {
"GENERIC": "L'action a échoué. Réessayez ou contactez le service informatique.",
"EXISTENT_FOLDER": "Un dossier du même nom existe déjà. Essayez avec un nom différent."
}
},
"HOST_SETTINGS": {
"TITLE": "Paramètres",
"CS-HOST": "Configuration de l'URL de l'hôte de Content Services",
"BP-HOST": "Configuration de l'URL de l'hôte de Process Services",
"BACK": "Retour",
"APPLY": "APPLIQUER"
},
}
}
}

View File

@@ -6,6 +6,37 @@
"CURRENT_PAGE": "Pagina {{ number }}",
"TOTAL_PAGES": "di {{ total }}"
},
"FOLDER_DIALOG": {
"CREATE_FOLDER_TITLE": "Crea nuova cartella",
"EDIT_FOLDER_TITLE": "Modifica cartella",
"FOLDER_NAME": {
"LABEL": "Nome",
"ERRORS": {
"REQUIRED": "Nome cartella obbligatorio",
"SPECIAL_CHARACTERS": "Il nome della cartella non può contenere questi caratteri * \" < > \\ / ? : |",
"ENDING_DOT": "Il nome della cartella non può terminare con un punto.",
"ONLY_SPACES": "Il nome della cartella non può contenere solo spazi"
}
},
"FOLDER_DESCRIPTION": {
"LABEL": "Descrizione"
},
"CREATE_BUTTON": {
"LABEL": "Crea"
},
"UPDATE_BUTTON": {
"LABEL": "Aggiorna"
},
"CANCEL_BUTTON": {
"LABEL": "Annulla"
}
},
"MESSAGES": {
"ERRORS": {
"GENERIC": "Azione non eseguita correttamente. Riprovare o contattare il team IT.",
"EXISTENT_FOLDER": "Esiste già una cartella con questo nome. Provare un nome diverso."
}
},
"HOST_SETTINGS": {
"TITLE": "Impostazioni",
"CS-HOST": "Configurazione URL host Content Services",

View File

@@ -6,6 +6,37 @@
"CURRENT_PAGE": "ページ: {{ number }}",
"TOTAL_PAGES": "/ {{ total }}"
},
"FOLDER_DIALOG": {
"CREATE_FOLDER_TITLE": "新しいフォルダの作成",
"EDIT_FOLDER_TITLE": "フォルダの編集",
"FOLDER_NAME": {
"LABEL": "名前",
"ERRORS": {
"REQUIRED": "フォルダ名を指定してください",
"SPECIAL_CHARACTERS": "名前に次の文字を含めることはできません。 * \" < > \\ / ? : |",
"ENDING_DOT": "フォルダ名の最後にピリオド (.) を付けることはできません。",
"ONLY_SPACES": "フォルダ名にスペースだけを含めることはできません"
}
},
"FOLDER_DESCRIPTION": {
"LABEL": "説明"
},
"CREATE_BUTTON": {
"LABEL": "作成"
},
"UPDATE_BUTTON": {
"LABEL": "更新"
},
"CANCEL_BUTTON": {
"LABEL": "キャンセル"
}
},
"MESSAGES": {
"ERRORS": {
"GENERIC": "処理が失敗しました。もう一度操作をやり直すか、IT 担当者に連絡してください。",
"EXISTENT_FOLDER": "この名前のフォルダが既に存在します。別の名前を使用してください。"
}
},
"HOST_SETTINGS": {
"TITLE": "設定",
"CS-HOST": "Content Services ホストの URL の設定",

View File

@@ -6,6 +6,37 @@
"CURRENT_PAGE": "Side {{ number }}",
"TOTAL_PAGES": "av {{ total }}"
},
"FOLDER_DIALOG": {
"CREATE_FOLDER_TITLE": "Opprett ny mappe",
"EDIT_FOLDER_TITLE": "Rediger mappe",
"FOLDER_NAME": {
"LABEL": "Navn",
"ERRORS": {
"REQUIRED": "Mappenavn påkrevd",
"SPECIAL_CHARACTERS": "Mappenavn kan ikke inneholde disse tegnene * \" < > \\ / ? : |",
"ENDING_DOT": "Mappenavn kan ikke slutte med punktum .",
"ONLY_SPACES": "Mappenavn kan ikke inneholde bare mellomrom"
}
},
"FOLDER_DESCRIPTION": {
"LABEL": "Beskrivelse"
},
"CREATE_BUTTON": {
"LABEL": "Opprett"
},
"UPDATE_BUTTON": {
"LABEL": "Oppdater"
},
"CANCEL_BUTTON": {
"LABEL": "Avbryt"
}
},
"MESSAGES": {
"ERRORS": {
"GENERIC": "Handlingen var mislykket. Prøv på nytt, eller kontakt IT-teamet.",
"EXISTENT_FOLDER": "Det finnes allerede en mappe med det navnet, Prøv med et annet navn."
}
},
"HOST_SETTINGS": {
"TITLE": "Innstillinger",
"CS-HOST": "Innholdstjenestevert URL-konfigurasjon",

View File

@@ -6,6 +6,37 @@
"CURRENT_PAGE": "Pagina {{ number }}",
"TOTAL_PAGES": "van {{ total }}"
},
"FOLDER_DIALOG": {
"CREATE_FOLDER_TITLE": "Nieuwe map maken",
"EDIT_FOLDER_TITLE": "Map bewerken",
"FOLDER_NAME": {
"LABEL": "Naam",
"ERRORS": {
"REQUIRED": "Mapnaam is vereist",
"SPECIAL_CHARACTERS": "Mapnaam mag de volgende tekens niet bevatten: * \" < > \\ / ? : |",
"ENDING_DOT": "Mapnaam mag niet eindigen met een punt .",
"ONLY_SPACES": "Mapnaam mag niet alleen uit spaties bestaan"
}
},
"FOLDER_DESCRIPTION": {
"LABEL": "Beschrijving"
},
"CREATE_BUTTON": {
"LABEL": "Maken"
},
"UPDATE_BUTTON": {
"LABEL": "Bijwerken"
},
"CANCEL_BUTTON": {
"LABEL": "Annuleren"
}
},
"MESSAGES": {
"ERRORS": {
"GENERIC": "De actie is mislukt. Probeer het opnieuw of neem contact op met het IT-team.",
"EXISTENT_FOLDER": "Er bestaat al een map met deze naam. Probeer een andere naam."
}
},
"HOST_SETTINGS": {
"TITLE": "Instellingen",
"CS-HOST": "URL-configuratie Content Services-host",

View File

@@ -6,6 +6,37 @@
"CURRENT_PAGE": "Página {{ number }}",
"TOTAL_PAGES": "de {{ total }}"
},
"FOLDER_DIALOG": {
"CREATE_FOLDER_TITLE": "Criar nova pasta",
"EDIT_FOLDER_TITLE": "Editar pasta",
"FOLDER_NAME": {
"LABEL": "Nome",
"ERRORS": {
"REQUIRED": "O nome da pasta é obrigatório",
"SPECIAL_CHARACTERS": "O nome da pasta não pode conter estes caracteres * \" < > \\ / ? : |",
"ENDING_DOT": "O nome da pasta não pode terminar com ponto final .",
"ONLY_SPACES": "O nome da pasta não pode conter somente espaços"
}
},
"FOLDER_DESCRIPTION": {
"LABEL": "Descrição"
},
"CREATE_BUTTON": {
"LABEL": "Criar"
},
"UPDATE_BUTTON": {
"LABEL": "Atualizar"
},
"CANCEL_BUTTON": {
"LABEL": "Cancelar"
}
},
"MESSAGES": {
"ERRORS": {
"GENERIC": "A ação não teve êxito. Tente novamente ou entre em contato com a Equipe de TI.",
"EXISTENT_FOLDER": "Já existe uma pasta com este nome. Tente outro nome."
}
},
"HOST_SETTINGS": {
"TITLE": "Configurações",
"CS-HOST": "Configuração de URL de host do Content Services",

View File

@@ -6,6 +6,37 @@
"CURRENT_PAGE": "Страница {{ number }}",
"TOTAL_PAGES": "из {{ total }}"
},
"FOLDER_DIALOG": {
"CREATE_FOLDER_TITLE": "Создать новую папку",
"EDIT_FOLDER_TITLE": "Редактировать папку",
"FOLDER_NAME": {
"LABEL": "Имя",
"ERRORS": {
"REQUIRED": "Имя папки является обязательным",
"SPECIAL_CHARACTERS": "Имя папки не может содержать следующие символы * \" < > \\ / ? : |",
"ENDING_DOT": "Имя папки не может заканчиваться точкой .",
"ONLY_SPACES": "Имя папки не может состоять только из пробелов"
}
},
"FOLDER_DESCRIPTION": {
"LABEL": "Описание"
},
"CREATE_BUTTON": {
"LABEL": "Создать"
},
"UPDATE_BUTTON": {
"LABEL": "Обновить"
},
"CANCEL_BUTTON": {
"LABEL": "Отмена"
}
},
"MESSAGES": {
"ERRORS": {
"GENERIC": "Действие не выполнено. Повторите попытку или обратитесь к IT-специалистам.",
"EXISTENT_FOLDER": "Папка с таким же именем уже существует. Используйте другое имя."
}
},
"HOST_SETTINGS": {
"TITLE": "Параметры",
"CS-HOST": "Конфигурация URL-адреса хоста Content Services",

View File

@@ -6,6 +6,37 @@
"CURRENT_PAGE": "第 {{number}} 页",
"TOTAL_PAGES": "/共 {{total}} 页"
},
"FOLDER_DIALOG": {
"CREATE_FOLDER_TITLE": "新建文件夹",
"EDIT_FOLDER_TITLE": "编辑文件夹",
"FOLDER_NAME": {
"LABEL": "名称",
"ERRORS": {
"REQUIRED": "需要文件夹名称",
"SPECIAL_CHARACTERS": "文件夹名称不能包含 * \" < > \\ / ? : | 字符",
"ENDING_DOT": "文件夹名称不能以句点结尾。",
"ONLY_SPACES": "文件夹名称不能只包含空格"
}
},
"FOLDER_DESCRIPTION": {
"LABEL": "说明"
},
"CREATE_BUTTON": {
"LABEL": "创建"
},
"UPDATE_BUTTON": {
"LABEL": "更新"
},
"CANCEL_BUTTON": {
"LABEL": "取消"
}
},
"MESSAGES": {
"ERRORS": {
"GENERIC": "此操作未成功,请重试或联系您的 IT 团队.",
"EXISTENT_FOLDER": "存在使用此名称的文件夹。请尝试使用其他名称。"
}
},
"HOST_SETTINGS": {
"TITLE": "设置",
"CS-HOST": "Content Services 主机 URL 配置",

View File

@@ -16,7 +16,7 @@
*/
import { Injectable } from '@angular/core';
import { ContentApi } from 'alfresco-js-api';
import { ContentApi, MinimalNodeEntryEntity } from 'alfresco-js-api';
import { Observable, Subject } from 'rxjs/Rx';
import { FolderCreatedEvent } from '../events/folder-created.event';
import { PermissionsEnum } from '../models/permissions.enum';
@@ -28,6 +28,8 @@ import { LogService } from './log.service';
export class AlfrescoContentService {
folderCreated: Subject<FolderCreatedEvent> = new Subject<FolderCreatedEvent>();
folderCreate: Subject<MinimalNodeEntryEntity> = new Subject<MinimalNodeEntryEntity>();
folderEdit: Subject<MinimalNodeEntryEntity> = new Subject<MinimalNodeEntryEntity>();
constructor(public authService: AuthenticationService,
public apiService: AlfrescoApiService,