[ADF-325] added attach folder widget (#2831)

[ADF-325] added new attach folder widget
This commit is contained in:
Vito
2018-01-16 15:28:39 +01:00
committed by Eugenio Romano
parent 3671c12f35
commit 66262c4822
12 changed files with 393 additions and 12 deletions

View File

@@ -0,0 +1,30 @@
<div class="adf-attach-folder-widget {{field.className}}"
[class.adf-invalid]="!field.isValid"
[class.adf-readonly]="field.readOnly">
<label class="adf-label" [attr.for]="field.id">{{field.name}}<span *ngIf="isRequired()">*</span></label>
<div class="adf-attach-folder-widget-container">
<div *ngIf="hasFolder" class="adf-attach-folder-result">
<mat-icon>folder</mat-icon>
<div class="adf-attach-folder-files-row">
<span matLine id="{{'folder-'+field?.id}}"
role="button" tabindex="0" class="adf-folder">{{selectedFolderName}}</span>
<button *ngIf="!field.readOnly" mat-icon-button [id]="'folder-'+field?.id+'-remove'"
(click)="removeFolder();">
<mat-icon class="mat-24">highlight_off</mat-icon>
</button>
</div>
</div>
<div class="button-row" *ngIf="!hasFolder && !field.readOnly">
<button mat-raised-button
color="primary"
(click)="openSelectDialogFromFileSource()"
[id]="'folder-'+field?.id+'-button'">
{{ 'FORM.FIELD.UPLOAD' | translate }}
<mat-icon>cloud_upload</mat-icon>
</button>
</div>
</div>
<error-widget [error]="field.validationSummary"></error-widget>
<error-widget *ngIf="isInvalidFieldRequired()" required="{{ 'FORM.FIELD.REQUIRED' | translate }}"></error-widget>
</div>

View File

@@ -0,0 +1,39 @@
.adf {
&-attach-folder-widget-container {
margin-bottom: 15px;
display: flex;
align-items: center;
input {
cursor: pointer;
height: 100%;
right: 0;
opacity: 0;
position: absolute;
top: 0;
width: 300px;
z-index: 4;
}
}
&-attach-folder-widget {
width: 100%;
word-break: break-all;
padding: 0.4375em 0;
border-top: 0.84375em solid transparent;
}
&-attach-folder-files-row {
padding-left: 8px;
.mat-line {
margin-bottom: 0px;
}
}
&-attach-folder-result {
display: flex;
align-items: center;
}
}

View File

@@ -0,0 +1,169 @@
/*!
* @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, ComponentFixture, TestBed } from '@angular/core/testing';
import { By } from '@angular/platform-browser';
import { AttachFolderWidgetComponent } from './attach-folder-widget.component';
import {
FormFieldModel,
FormModel,
FormService,
AlfrescoApiService,
LogService,
ThumbnailService,
SitesService,
NodesApiService
} from '@alfresco/adf-core';
import { ContentNodeDialogService, DocumentListService } from '@alfresco/adf-content-services';
import { MaterialModule } from '../material.module';
import { Observable } from 'rxjs/Observable';
import { MinimalNodeEntryEntity } from 'alfresco-js-api';
const fakeMinimalNode: MinimalNodeEntryEntity = <MinimalNodeEntryEntity> {
id: 'fake',
name: 'fake-name'
};
const definedSourceParams = {
folderSource : {
serviceId: 'goofy-sources',
name: 'pippo-baudo',
selectedFolder: {
accountId: 'goku-share-account-id',
pathId: 'fake-pippo-baudo-id'
}
}
};
describe('AttachFolderWidgetComponent', () => {
let widget: AttachFolderWidgetComponent;
let fixture: ComponentFixture<AttachFolderWidgetComponent>;
let element: HTMLInputElement;
let contentNodeDialogService: ContentNodeDialogService;
let nodeService: NodesApiService;
beforeEach(async(() => {
TestBed.configureTestingModule({
imports: [MaterialModule],
declarations: [AttachFolderWidgetComponent],
providers: [
FormService,
ThumbnailService,
AlfrescoApiService,
LogService,
SitesService,
DocumentListService,
ContentNodeDialogService,
NodesApiService
]
}).compileComponents().then(() => {
fixture = TestBed.createComponent(AttachFolderWidgetComponent);
widget = fixture.componentInstance;
element = fixture.nativeElement;
contentNodeDialogService = TestBed.get(ContentNodeDialogService);
nodeService = TestBed.get(NodesApiService);
});
}));
afterEach(() => {
fixture.destroy();
});
it('should be able to create the widget', () => {
expect(widget).not.toBeNull();
});
it('should be rendered correctly', () => {
expect(widget).not.toBeNull();
widget.field = new FormFieldModel(new FormModel(), {
type: 'select-folder',
id: 'fake-widget',
value: null
});
fixture.detectChanges();
expect(element.querySelector('#folder-fake-widget-button')).toBeDefined();
expect(element.querySelector('#folder-fake-widget-button')).not.toBeNull();
});
it('should show the folder selected by content node', async(() => {
spyOn(contentNodeDialogService, 'openFolderBrowseDialogBySite').and.returnValue(Observable.of([fakeMinimalNode]));
expect(widget).not.toBeNull();
widget.field = new FormFieldModel(new FormModel(), {
type: 'select-folder',
id: 'fake-widget',
value: null
});
fixture.detectChanges();
fixture.debugElement.query(By.css('#folder-fake-widget-button')).nativeElement.click();
fixture.detectChanges();
fixture.whenStable().then(() => {
expect(element.querySelector('#folder-fake-widget')).not.toBeNull();
});
}));
it('should show the folder selected by content node opening on a configured folder', async(() => {
spyOn(contentNodeDialogService, 'openFolderBrowseDialogByFolderId').and.returnValue(Observable.of([fakeMinimalNode]));
expect(widget).not.toBeNull();
widget.field = new FormFieldModel(new FormModel(), {
type: 'select-folder',
id: 'fake-widget',
value: null,
params: definedSourceParams
});
fixture.detectChanges();
fixture.debugElement.query(By.css('#folder-fake-widget-button')).nativeElement.click();
fixture.detectChanges();
fixture.whenStable().then(() => {
expect(element.querySelector('#folder-fake-widget')).not.toBeNull();
});
}));
it('should retrieve the node information on init', async(() => {
spyOn(nodeService, 'getNode').and.returnValue(Observable.of(fakeMinimalNode));
expect(widget).not.toBeNull();
widget.field = new FormFieldModel(new FormModel(), {
type: 'select-folder',
id: 'fake-widget',
value: 'fake-pippo-baudo-id'
});
fixture.detectChanges();
fixture.whenStable().then(() => {
expect(element.querySelector('#folder-fake-widget')).not.toBeNull();
expect(element.querySelector('#folder-fake-widget-button')).toBeNull();
});
}));
it('should remove the folder via the remove button', async(() => {
spyOn(nodeService, 'getNode').and.returnValue(Observable.of(fakeMinimalNode));
expect(widget).not.toBeNull();
widget.field = new FormFieldModel(new FormModel(), {
type: 'select-folder',
id: 'fake-widget',
value: 'fake-pippo-baudo-id'
});
fixture.detectChanges();
fixture.whenStable().then(() => {
expect(element.querySelector('#folder-fake-widget')).not.toBeNull();
expect(element.querySelector('#folder-fake-widget-button')).toBeNull();
fixture.debugElement.query(By.css('#folder-fake-widget-remove')).nativeElement.click();
fixture.detectChanges();
expect(element.querySelector('#folder-fake-widget')).toBeNull();
});
}));
});

View File

@@ -0,0 +1,89 @@
/*!
* @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.
*/
/* tslint:disable:component-selector*/
import { Component, ViewEncapsulation, OnInit } from '@angular/core';
import {
baseHost,
WidgetComponent,
FormService,
NodesApiService
} from '@alfresco/adf-core';
import { ContentNodeDialogService } from '@alfresco/adf-content-services';
import { MinimalNodeEntryEntity } from 'alfresco-js-api';
@Component({
selector: 'attach-folder-widget',
templateUrl: './attach-folder-widget.component.html',
styleUrls: ['./attach-folder-widget.component.scss'],
host: baseHost,
encapsulation: ViewEncapsulation.None
})
export class AttachFolderWidgetComponent extends WidgetComponent implements OnInit {
hasFolder: boolean = false;
selectedFolderName: string = '';
constructor(private contentDialog: ContentNodeDialogService,
public formService: FormService,
private nodeService: NodesApiService) {
super();
}
ngOnInit() {
if (this.field &&
this.field.value) {
this.hasFolder = true;
this.nodeService.getNode(this.field.value).subscribe((node: MinimalNodeEntryEntity) => {
this.selectedFolderName = node.name;
});
}
}
isDefinedSourceFolder(): boolean {
return !!this.field.params &&
!!this.field.params.folderSource &&
!!this.field.params.folderSource.selectedFolder;
}
openSelectDialogFromFileSource() {
let params = this.field.params;
if (this.isDefinedSourceFolder()) {
this.contentDialog.openFolderBrowseDialogByFolderId(params.folderSource.selectedFolder.pathId).subscribe(
(selections: MinimalNodeEntryEntity[]) => {
this.selectedFolderName = selections[0].name;
this.field.value = selections[0].id;
this.hasFolder = true;
});
} else {
this.contentDialog.openFolderBrowseDialogBySite().subscribe(
(selections: MinimalNodeEntryEntity[]) => {
this.selectedFolderName = selections[0].name;
this.field.value = selections[0].id;
this.hasFolder = true;
});
}
}
removeFolder() {
this.field.value = null;
this.selectedFolderName = '';
this.hasFolder = false;
}
}

View File

@@ -23,6 +23,7 @@ import { FormsModule, ReactiveFormsModule } from '@angular/forms';
import { DataColumnModule, DataTableModule, FormModule } from '@alfresco/adf-core';
import { AttachFileWidgetComponent } from './attach-file-widget.component';
import { AttachFolderWidgetComponent } from './attach-folder-widget.component';
@NgModule({
imports: [
@@ -36,13 +37,16 @@ import { AttachFileWidgetComponent } from './attach-file-widget.component';
FormModule
],
entryComponents: [
AttachFileWidgetComponent
AttachFileWidgetComponent,
AttachFolderWidgetComponent
],
declarations: [
AttachFileWidgetComponent
AttachFileWidgetComponent,
AttachFolderWidgetComponent
],
exports: [
AttachFileWidgetComponent
AttachFileWidgetComponent,
AttachFolderWidgetComponent
]
})
export class ContentWidgetModule {}

View File

@@ -16,3 +16,4 @@
*/
export * from './attach-file-widget.component';
export * from './attach-folder-widget.component';

View File

@@ -16,14 +16,12 @@
*/
import { Component, EventEmitter, Input, OnChanges, Output, SimpleChanges, ViewChild, ViewEncapsulation } from '@angular/core';
import { StartFormComponent
, FormRenderingService
} from '@alfresco/adf-core';
import { StartFormComponent, FormRenderingService } from '@alfresco/adf-core';
import { ProcessInstanceVariable } from '../models/process-instance-variable.model';
import { ProcessDefinitionRepresentation } from './../models/process-definition.model';
import { ProcessInstance } from './../models/process-instance.model';
import { ProcessService } from './../services/process.service';
import { AttachFileWidgetComponent } from '../../content-widget';
import { AttachFileWidgetComponent, AttachFolderWidgetComponent } from '../../content-widget';
@Component({
selector: 'adf-start-process',
@@ -62,6 +60,7 @@ export class StartProcessInstanceComponent implements OnChanges {
constructor(private activitiProcess: ProcessService,
private formRenderingService: FormRenderingService) {
this.formRenderingService.setComponentTypeResolver('upload', () => AttachFileWidgetComponent, true);
this.formRenderingService.setComponentTypeResolver('select-folder', () => AttachFolderWidgetComponent, true);
}
ngOnChanges(changes: SimpleChanges) {

View File

@@ -35,7 +35,7 @@ import { TaskQueryRequestRepresentationModel } from '../models/filter.model';
import { TaskDetailsModel } from '../models/task-details.model';
import { TaskListService } from './../services/tasklist.service';
import { CommentsComponent } from '../../comments';
import { AttachFileWidgetComponent } from '../../content-widget';
import { AttachFileWidgetComponent, AttachFolderWidgetComponent } from '../../content-widget';
@Component({
selector: 'adf-task-details',
@@ -147,6 +147,7 @@ export class TaskDetailsComponent implements OnInit, OnChanges {
private cardViewUpdateService: CardViewUpdateService,
private dialog: MatDialog) {
this.formRenderingService.setComponentTypeResolver('select-folder', () => AttachFolderWidgetComponent, true);
this.formRenderingService.setComponentTypeResolver('upload', () => AttachFileWidgetComponent, true);
this.peopleSearch$ = new Observable<UserProcessModel[]>(observer => this.peopleSearchObserver = observer).share();
}