mirror of
https://github.com/Alfresco/alfresco-ng2-components.git
synced 2025-07-24 17:32:15 +00:00
38
lib/process-services/README.md
Normal file
38
lib/process-services/README.md
Normal file
@@ -0,0 +1,38 @@
|
||||
# Alfresco Process services
|
||||
|
||||
Contains a variety of components, directives and services used throughout ADF
|
||||
|
||||
<!-- markdown-toc start - Don't edit this section. npm run toc to generate it-->
|
||||
|
||||
<!-- toc -->
|
||||
|
||||
- [Documentation](#documentation)
|
||||
- [Prerequisites](#prerequisites)
|
||||
- [Install](#install)
|
||||
- [License](#license)
|
||||
|
||||
<!-- tocstop -->
|
||||
|
||||
<!-- markdown-toc end -->
|
||||
|
||||
## Documentation
|
||||
|
||||
See the [ADF Core](../../docs/README.md#process-services) section of the [docs index](../../docs/README.md)
|
||||
for all available documentation on this library.
|
||||
|
||||
## Prerequisites
|
||||
|
||||
Before you start using this development framework, make sure you have installed all required software and done all the
|
||||
necessary configuration, see this [page](https://github.com/Alfresco/alfresco-ng2-components/blob/master/PREREQUISITES.md).
|
||||
|
||||
> If you plan using this component with projects generated by Angular CLI, please refer to the following article: [Using ADF with Angular CLI](https://github.com/Alfresco/alfresco-ng2-components/wiki/Angular-CLI)
|
||||
|
||||
## Install
|
||||
|
||||
```sh
|
||||
npm install @alfresco/process-services
|
||||
```
|
||||
|
||||
## License
|
||||
|
||||
[Apache Version 2.0](https://github.com/Alfresco/alfresco-ng2-components/blob/master/LICENSE)
|
39
lib/process-services/app-list/apps-list.component.html
Normal file
39
lib/process-services/app-list/apps-list.component.html
Normal file
@@ -0,0 +1,39 @@
|
||||
<div class="menu-container" *ngIf="!isEmpty()">
|
||||
<mat-list *ngIf="isList()" class="adf-app-list">
|
||||
<mat-list-item class="adf-app-list-item" (click)="selectApp(app)" (keyup.enter)="selectApp(app)" *ngFor="let app of appList" tabindex="0" role="button" title="{{app.name}}">
|
||||
<mat-icon matListIcon>touch_app</mat-icon>
|
||||
<span matLine>{{getAppName(app) | async}}</span>
|
||||
</mat-list-item>
|
||||
</mat-list>
|
||||
<div fxLayout="row wrap" *ngIf="isGrid()" class="adf-app-listgrid">
|
||||
<div *ngFor="let app of appList"
|
||||
class="adf-app-listgrid-item"
|
||||
fxFlex="33.33333%" fxFlex.lt-md="50%" fxFlex.lt-sm="100%">
|
||||
<mat-card tabindex="0"
|
||||
fxLayout="column"
|
||||
role="button"
|
||||
class="adf-app-listgrid-item-card"
|
||||
title="{{getAppName(app) | async}}"
|
||||
[ngClass]="[getTheme(app)]"
|
||||
(click)="selectApp(app)"
|
||||
(keyup.enter)="selectApp(app)">
|
||||
<div class="adf-app-listgrid-item-card-logo">
|
||||
<mat-icon class="adf-app-listgrid-item-card-logo-icon">{{getBackgroundIcon(app)}}</mat-icon>
|
||||
</div>
|
||||
<div mat-card-title class="adf-app-listgrid-item-card-title">
|
||||
<h1>{{getAppName(app) | async}}</h1>
|
||||
</div>
|
||||
<mat-card-subtitle class="adf-app-listgrid-item-card-subtitle" fxFlex="1 0 auto">
|
||||
<p>{{app.description}}</p>
|
||||
</mat-card-subtitle>
|
||||
|
||||
<mat-card-actions class="adf-app-listgrid-item-card-actions">
|
||||
<mat-icon class="adf-app-listgrid-item-card-actions-icon" *ngIf="isSelected(app.id)">done</mat-icon>
|
||||
</mat-card-actions>
|
||||
</mat-card>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="menu-container" *ngIf="isEmpty()">
|
||||
{{ 'ADF_TASK_LIST.APPS.NONE' | translate }}
|
||||
</div>
|
101
lib/process-services/app-list/apps-list.component.scss
Normal file
101
lib/process-services/app-list/apps-list.component.scss
Normal file
@@ -0,0 +1,101 @@
|
||||
:host {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.adf-app-list-item {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
$themes: (
|
||||
theme-1: (bg: #269abc, color: #168aac),
|
||||
theme-2: (bg: #7da9b0, color: #6d99a0),
|
||||
theme-3: (bg: #7689ab, color: #66799b),
|
||||
theme-4: (bg: #c74e3e, color: #b73e2e),
|
||||
theme-5: (bg: #fab96c, color: #eaa95c),
|
||||
theme-6: (bg: #759d4c, color: #658d3c),
|
||||
theme-7: (bg: #b1b489, color: #a1a479),
|
||||
theme-8: (bg: #a17299, color: #916289),
|
||||
theme-9: (bg: #696c67, color: #595c57),
|
||||
theme-10: (bg: #cabb33, color: #baab23)
|
||||
);
|
||||
|
||||
.adf-app-listgrid {
|
||||
padding: 8px;
|
||||
|
||||
&-item {
|
||||
outline: none;
|
||||
padding: 8px;
|
||||
box-sizing: border-box;
|
||||
|
||||
&-card {
|
||||
|
||||
@for $i from 1 through 10 {
|
||||
&.theme-#{$i} {
|
||||
$theme: map-get($themes, theme-#{$i});
|
||||
background-color: map-get($theme, bg);
|
||||
}
|
||||
}
|
||||
|
||||
outline: none;
|
||||
transition: transform 280ms cubic-bezier(.4,0,.2,1), box-shadow 280ms cubic-bezier(.4,0,.2,1);
|
||||
min-height: 200px;
|
||||
padding: 0;
|
||||
|
||||
&:hover {
|
||||
box-shadow: 0 8px 10px 1px rgba(0, 0, 0, .14), 0 3px 14px 2px rgba(0, 0, 0, .12), 0 5px 5px -3px rgba(0, 0, 0, .2);
|
||||
cursor: pointer;
|
||||
transform: scale(1.015);
|
||||
}
|
||||
|
||||
&-logo {
|
||||
position: absolute;
|
||||
right: 20px;
|
||||
top: 20px;
|
||||
padding: 16px;
|
||||
|
||||
&-icon {
|
||||
font-size: 70px;
|
||||
width: 1em;
|
||||
height: 1em;
|
||||
|
||||
@for $i from 1 through 10 {
|
||||
.theme-#{$i} & {
|
||||
$theme: map-get($themes, theme-#{$i});
|
||||
color: map-get($theme, color);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&-title {
|
||||
padding: 16px;
|
||||
|
||||
h1 {
|
||||
color: white;
|
||||
width: 80%;
|
||||
font-size: 24px;
|
||||
margin: 0;
|
||||
line-height: normal;
|
||||
white-space: nowrap;
|
||||
text-overflow: ellipsis;
|
||||
overflow: hidden;
|
||||
}
|
||||
}
|
||||
|
||||
&-subtitle {
|
||||
padding: 16px;
|
||||
}
|
||||
|
||||
&-actions {
|
||||
padding: 16px;
|
||||
border-top: 1px solid rgba(0,0,0,.1);
|
||||
min-height: 64px;
|
||||
box-sizing: border-box;
|
||||
|
||||
&-icon {
|
||||
color: #e9f1f3;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
241
lib/process-services/app-list/apps-list.component.spec.ts
Normal file
241
lib/process-services/app-list/apps-list.component.spec.ts
Normal file
@@ -0,0 +1,241 @@
|
||||
/*!
|
||||
* @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 { DebugElement } from '@angular/core';
|
||||
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
import { By } from '@angular/platform-browser';
|
||||
import { AppsProcessService, CoreModule } from '@alfresco/core';
|
||||
import { Observable } from 'rxjs/Rx';
|
||||
|
||||
import { MaterialModule } from '../material.module';
|
||||
import { defaultApp, deployedApps, nonDeployedApps } from '../mock/apps-list.mock';
|
||||
import { AppsListComponent } from './apps-list.component';
|
||||
import { TranslateModule } from '@ngx-translate/core';
|
||||
|
||||
describe('AppsListComponent', () => {
|
||||
|
||||
let component: AppsListComponent;
|
||||
let fixture: ComponentFixture<AppsListComponent>;
|
||||
let debugElement: DebugElement;
|
||||
let service: AppsProcessService;
|
||||
let getAppsSpy: jasmine.Spy;
|
||||
|
||||
beforeEach(async(() => {
|
||||
TestBed.configureTestingModule({
|
||||
imports: [
|
||||
CoreModule,
|
||||
MaterialModule,
|
||||
TranslateModule
|
||||
],
|
||||
declarations: [
|
||||
AppsListComponent
|
||||
],
|
||||
providers: [
|
||||
]
|
||||
}).compileComponents();
|
||||
|
||||
}));
|
||||
|
||||
beforeEach(() => {
|
||||
fixture = TestBed.createComponent(AppsListComponent);
|
||||
component = fixture.componentInstance;
|
||||
debugElement = fixture.debugElement;
|
||||
|
||||
service = fixture.debugElement.injector.get(AppsProcessService);
|
||||
getAppsSpy = spyOn(service, 'getDeployedApplications').and.returnValue(Observable.of(deployedApps));
|
||||
});
|
||||
|
||||
it('should define layoutType with the default value', () => {
|
||||
component.layoutType = '';
|
||||
fixture.detectChanges();
|
||||
expect(component.isGrid()).toBe(true);
|
||||
});
|
||||
|
||||
it('should load apps on init', () => {
|
||||
fixture.detectChanges();
|
||||
expect(getAppsSpy).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should show the apps filtered by defaultAppId', () => {
|
||||
component.filtersAppId = [{defaultAppId: 'fake-app-1'}];
|
||||
fixture.detectChanges();
|
||||
expect(component.isEmpty()).toBe(false);
|
||||
expect(component.appList).toBeDefined();
|
||||
expect(component.appList.length).toEqual(1);
|
||||
});
|
||||
|
||||
it('should show the apps filtered by deploymentId', () => {
|
||||
component.filtersAppId = [{deploymentId: '4'}];
|
||||
fixture.detectChanges();
|
||||
expect(component.isEmpty()).toBe(false);
|
||||
expect(component.appList).toBeDefined();
|
||||
expect(component.appList.length).toEqual(1);
|
||||
expect(component.appList[0].deploymentId).toEqual('4');
|
||||
});
|
||||
|
||||
it('should show the apps filtered by name', () => {
|
||||
component.filtersAppId = [{name: 'App5'}];
|
||||
fixture.detectChanges();
|
||||
expect(component.isEmpty()).toBe(false);
|
||||
expect(component.appList).toBeDefined();
|
||||
expect(component.appList.length).toEqual(1);
|
||||
expect(component.appList[0].name).toEqual('App5');
|
||||
});
|
||||
|
||||
it('should show the apps filtered by id', () => {
|
||||
component.filtersAppId = [{id: 6}];
|
||||
fixture.detectChanges();
|
||||
expect(component.isEmpty()).toBe(false);
|
||||
expect(component.appList).toBeDefined();
|
||||
expect(component.appList.length).toEqual(1);
|
||||
expect(component.appList[0].id).toEqual(6);
|
||||
});
|
||||
|
||||
it('should show the apps filtered by modelId', () => {
|
||||
component.filtersAppId = [{modelId: 66}];
|
||||
fixture.detectChanges();
|
||||
expect(component.isEmpty()).toBe(false);
|
||||
expect(component.appList).toBeDefined();
|
||||
expect(component.appList.length).toEqual(2);
|
||||
expect(component.appList[0].modelId).toEqual(66);
|
||||
});
|
||||
|
||||
it('should show the apps filtered by tenandId', () => {
|
||||
component.filtersAppId = [{tenantId: 9}];
|
||||
fixture.detectChanges();
|
||||
expect(component.isEmpty()).toBe(false);
|
||||
expect(component.appList).toBeDefined();
|
||||
expect(component.appList.length).toEqual(2);
|
||||
expect(component.appList[0].tenantId).toEqual(9);
|
||||
});
|
||||
|
||||
it('should emit an error when an error occurs loading apps', () => {
|
||||
let emitSpy = spyOn(component.error, 'emit');
|
||||
getAppsSpy.and.returnValue(Observable.throw({}));
|
||||
fixture.detectChanges();
|
||||
expect(emitSpy).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
describe('internationalization', () => {
|
||||
|
||||
it('should provide a translation for the default application name, when app name is not provided', () => {
|
||||
const appDataMock = {
|
||||
defaultAppId: 'tasks',
|
||||
name: null
|
||||
};
|
||||
component.getAppName(appDataMock).subscribe((name) => {
|
||||
expect(name).toBe('ADF_TASK_LIST.APPS.TASK_APP_NAME');
|
||||
});
|
||||
});
|
||||
|
||||
it('should provide the application name, when it exists', () => {
|
||||
const appDataMock = {
|
||||
defaultAppId: 'uiu',
|
||||
name: 'the-name'
|
||||
};
|
||||
|
||||
component.getAppName(appDataMock).subscribe((name) => {
|
||||
expect(name).toBe(appDataMock.name);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('layout', () => {
|
||||
|
||||
it('should display a grid by default', () => {
|
||||
fixture.detectChanges();
|
||||
expect(component.isGrid()).toBe(true);
|
||||
expect(component.isList()).toBe(false);
|
||||
});
|
||||
|
||||
it('should display a grid when configured to', () => {
|
||||
component.layoutType = AppsListComponent.LAYOUT_GRID;
|
||||
fixture.detectChanges();
|
||||
expect(component.isGrid()).toBe(true);
|
||||
expect(component.isList()).toBe(false);
|
||||
});
|
||||
|
||||
it('should display a list when configured to', () => {
|
||||
component.layoutType = AppsListComponent.LAYOUT_LIST;
|
||||
fixture.detectChanges();
|
||||
expect(component.isGrid()).toBe(false);
|
||||
expect(component.isList()).toBe(true);
|
||||
});
|
||||
|
||||
it('should throw an exception on init if unknown type configured', () => {
|
||||
component.layoutType = 'unknown';
|
||||
expect(component.ngOnInit).toThrowError();
|
||||
});
|
||||
});
|
||||
|
||||
describe('display apps', () => {
|
||||
|
||||
it('should display all deployed apps', () => {
|
||||
getAppsSpy.and.returnValue(Observable.of(deployedApps));
|
||||
fixture.detectChanges();
|
||||
expect(debugElement.queryAll(By.css('h1')).length).toBe(6);
|
||||
});
|
||||
|
||||
it('should not display undeployed apps', () => {
|
||||
getAppsSpy.and.returnValue(Observable.of(nonDeployedApps));
|
||||
fixture.detectChanges();
|
||||
expect(debugElement.queryAll(By.css('h1')).length).toBe(0);
|
||||
});
|
||||
|
||||
it('should display default app', () => {
|
||||
getAppsSpy.and.returnValue(Observable.of(defaultApp));
|
||||
fixture.detectChanges();
|
||||
expect(debugElement.queryAll(By.css('h1')).length).toBe(1);
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
describe('select apps', () => {
|
||||
|
||||
beforeEach(() => {
|
||||
getAppsSpy.and.returnValue(Observable.of(deployedApps));
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it('should initially have no app selected', () => {
|
||||
let selectedEls = debugElement.queryAll(By.css('.selectedIcon'));
|
||||
expect(selectedEls.length).toBe(0);
|
||||
});
|
||||
|
||||
it('should emit a click event when app selected', () => {
|
||||
spyOn(component.appClick, 'emit');
|
||||
component.selectApp(deployedApps[1]);
|
||||
expect(component.appClick.emit).toHaveBeenCalledWith(deployedApps[1]);
|
||||
});
|
||||
|
||||
it('should have one app shown as selected after app selected', () => {
|
||||
component.selectApp(deployedApps[1]);
|
||||
fixture.detectChanges();
|
||||
let selectedEls = debugElement.queryAll(By.css('.adf-app-listgrid-item-card-actions-icon'));
|
||||
expect(selectedEls.length).toBe(1);
|
||||
});
|
||||
|
||||
it('should have the correct app shown as selected after app selected', () => {
|
||||
component.selectApp(deployedApps[1]);
|
||||
fixture.detectChanges();
|
||||
let appEls = debugElement.queryAll(By.css('.adf-app-listgrid > div'));
|
||||
expect(appEls[1].query(By.css('.adf-app-listgrid-item-card-actions-icon'))).not.toBeNull();
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
});
|
194
lib/process-services/app-list/apps-list.component.ts
Normal file
194
lib/process-services/app-list/apps-list.component.ts
Normal file
@@ -0,0 +1,194 @@
|
||||
/*!
|
||||
* @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 { AppsProcessService, TranslationService } from '@alfresco/core';
|
||||
import { Component, EventEmitter, Input, OnInit, Output } from '@angular/core';
|
||||
import { Observable } from 'rxjs/Observable';
|
||||
import { Observer } from 'rxjs/Observer';
|
||||
import { AppDefinitionRepresentationModel } from '../task-list';
|
||||
import { IconModel } from './icon.model';
|
||||
|
||||
@Component({
|
||||
selector: 'adf-apps',
|
||||
templateUrl: 'apps-list.component.html',
|
||||
styleUrls: ['./apps-list.component.scss']
|
||||
})
|
||||
export class AppsListComponent implements OnInit {
|
||||
|
||||
public static LAYOUT_LIST: string = 'LIST';
|
||||
public static LAYOUT_GRID: string = 'GRID';
|
||||
public static DEFAULT_TASKS_APP: string = 'tasks';
|
||||
public static DEFAULT_TASKS_APP_NAME: string = 'ADF_TASK_LIST.APPS.TASK_APP_NAME';
|
||||
public static DEFAULT_TASKS_APP_THEME: string = 'theme-2';
|
||||
public static DEFAULT_TASKS_APP_ICON: string = 'glyphicon-asterisk';
|
||||
public static DEFAULT_TASKS_APP_MATERIAL_ICON: string = 'favorite_border';
|
||||
|
||||
@Input()
|
||||
layoutType: string = AppsListComponent.LAYOUT_GRID;
|
||||
|
||||
@Input()
|
||||
filtersAppId: any[];
|
||||
|
||||
@Output()
|
||||
appClick: EventEmitter<AppDefinitionRepresentationModel> = new EventEmitter<AppDefinitionRepresentationModel>();
|
||||
|
||||
@Output()
|
||||
error: EventEmitter<any> = new EventEmitter<any>();
|
||||
|
||||
private appsObserver: Observer<AppDefinitionRepresentationModel>;
|
||||
apps$: Observable<AppDefinitionRepresentationModel>;
|
||||
|
||||
currentApp: AppDefinitionRepresentationModel;
|
||||
|
||||
appList: AppDefinitionRepresentationModel [] = [];
|
||||
|
||||
private iconsMDL: IconModel;
|
||||
|
||||
constructor(
|
||||
private appsProcessService: AppsProcessService,
|
||||
private translationService: TranslationService) {
|
||||
this.apps$ = new Observable<AppDefinitionRepresentationModel>(observer => this.appsObserver = observer).share();
|
||||
}
|
||||
|
||||
ngOnInit() {
|
||||
if (!this.isValidType()) {
|
||||
this.setDefaultLayoutType();
|
||||
}
|
||||
|
||||
this.apps$.subscribe((app: any) => {
|
||||
this.appList.push(app);
|
||||
});
|
||||
this.iconsMDL = new IconModel();
|
||||
this.load();
|
||||
}
|
||||
|
||||
private load() {
|
||||
this.appsProcessService.getDeployedApplications()
|
||||
.subscribe(
|
||||
(res: AppDefinitionRepresentationModel[]) => {
|
||||
this.filterApps(res).forEach((app: AppDefinitionRepresentationModel) => {
|
||||
if (this.isDefaultApp(app)) {
|
||||
app.theme = AppsListComponent.DEFAULT_TASKS_APP_THEME;
|
||||
app.icon = AppsListComponent.DEFAULT_TASKS_APP_ICON;
|
||||
this.appsObserver.next(app);
|
||||
} else if (app.deploymentId) {
|
||||
this.appsObserver.next(app);
|
||||
}
|
||||
});
|
||||
},
|
||||
(err) => {
|
||||
this.error.emit(err);
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
isDefaultApp(app) {
|
||||
return app.defaultAppId === AppsListComponent.DEFAULT_TASKS_APP;
|
||||
}
|
||||
|
||||
getAppName(app) {
|
||||
return this.isDefaultApp(app)
|
||||
? this.translationService.get(AppsListComponent.DEFAULT_TASKS_APP_NAME)
|
||||
: Observable.of(app.name);
|
||||
}
|
||||
|
||||
/**
|
||||
* Pass the selected app as next
|
||||
* @param app
|
||||
*/
|
||||
public selectApp(app: AppDefinitionRepresentationModel) {
|
||||
this.currentApp = app;
|
||||
this.appClick.emit(app);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if the appId is the current app
|
||||
* @param appId
|
||||
* @returns {boolean}
|
||||
*/
|
||||
isSelected(appId: number): boolean {
|
||||
return (this.currentApp !== undefined && appId === this.currentApp.id);
|
||||
}
|
||||
|
||||
private filterApps(apps: AppDefinitionRepresentationModel []): AppDefinitionRepresentationModel[] {
|
||||
let filteredApps: AppDefinitionRepresentationModel[] = [];
|
||||
if (this.filtersAppId) {
|
||||
apps.filter((app: AppDefinitionRepresentationModel) => {
|
||||
this.filtersAppId.forEach((filter) => {
|
||||
if (app.defaultAppId === filter.defaultAppId ||
|
||||
app.deploymentId === filter.deploymentId ||
|
||||
app.name === filter.name ||
|
||||
app.id === filter.id ||
|
||||
app.modelId === filter.modelId ||
|
||||
app.tenantId === filter.tenantId) {
|
||||
filteredApps.push(app);
|
||||
}
|
||||
});
|
||||
});
|
||||
} else {
|
||||
return apps;
|
||||
}
|
||||
return filteredApps;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the value of the layoutType property is an allowed value
|
||||
* @returns {boolean}
|
||||
*/
|
||||
isValidType(): boolean {
|
||||
if (this.layoutType && (this.layoutType === AppsListComponent.LAYOUT_LIST || this.layoutType === AppsListComponent.LAYOUT_GRID)) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Assign the default value to LayoutType
|
||||
*/
|
||||
setDefaultLayoutType(): void {
|
||||
this.layoutType = AppsListComponent.LAYOUT_GRID;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if the layout type is LIST
|
||||
* @returns {boolean}
|
||||
*/
|
||||
isList(): boolean {
|
||||
return this.layoutType === AppsListComponent.LAYOUT_LIST;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if the layout type is GRID
|
||||
* @returns {boolean}
|
||||
*/
|
||||
isGrid(): boolean {
|
||||
return this.layoutType === AppsListComponent.LAYOUT_GRID;
|
||||
}
|
||||
|
||||
isEmpty(): boolean {
|
||||
return this.appList.length === 0;
|
||||
}
|
||||
|
||||
getTheme(app: AppDefinitionRepresentationModel): string {
|
||||
return app.theme ? app.theme : '';
|
||||
}
|
||||
|
||||
getBackgroundIcon(app: AppDefinitionRepresentationModel): string {
|
||||
return this.iconsMDL.mapGlyphiconToMaterialDesignIcons(app.icon);
|
||||
}
|
||||
|
||||
}
|
40
lib/process-services/app-list/apps-list.module.ts
Normal file
40
lib/process-services/app-list/apps-list.module.ts
Normal file
@@ -0,0 +1,40 @@
|
||||
/*!
|
||||
* @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 { CommonModule } from '@angular/common';
|
||||
import { NgModule } from '@angular/core';
|
||||
import { MaterialModule } from '../material.module';
|
||||
import { TranslateModule } from '@ngx-translate/core';
|
||||
|
||||
import { AppsListComponent } from './apps-list.component';
|
||||
|
||||
@NgModule({
|
||||
imports: [
|
||||
CommonModule,
|
||||
MaterialModule,
|
||||
TranslateModule
|
||||
],
|
||||
declarations: [
|
||||
AppsListComponent
|
||||
],
|
||||
providers: [],
|
||||
exports: [
|
||||
AppsListComponent
|
||||
]
|
||||
})
|
||||
export class AppsListModule {
|
||||
}
|
162
lib/process-services/app-list/icon.model.ts
Normal file
162
lib/process-services/app-list/icon.model.ts
Normal file
@@ -0,0 +1,162 @@
|
||||
/*!
|
||||
* @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.
|
||||
*/
|
||||
|
||||
export class IconModel {
|
||||
public static DEFAULT_TASKS_APP_MATERIAL_ICON: string = 'favorite_border';
|
||||
|
||||
private iconsMDL: Map<string, string>;
|
||||
|
||||
constructor() {
|
||||
this.initIconsMDL();
|
||||
}
|
||||
|
||||
mapGlyphiconToMaterialDesignIcons(icon: string) {
|
||||
return this.iconsMDL.get(icon) ? this.iconsMDL.get(icon) : IconModel.DEFAULT_TASKS_APP_MATERIAL_ICON;
|
||||
}
|
||||
|
||||
/**
|
||||
* Map all the bootstrap glyphicon icons with Material design material icon
|
||||
*/
|
||||
initIconsMDL() {
|
||||
this.iconsMDL = new Map<string, string>();
|
||||
|
||||
this.iconsMDL.set('glyphicon-asterisk', 'ac_unit');
|
||||
this.iconsMDL.set('glyphicon-plus', 'add');
|
||||
this.iconsMDL.set('glyphicon-euro', 'euro_symbol');
|
||||
this.iconsMDL.set('glyphicon-cloud', 'cloud');
|
||||
this.iconsMDL.set('glyphicon-envelope', 'mail');
|
||||
this.iconsMDL.set('glyphicon-pencil', 'create');
|
||||
this.iconsMDL.set('glyphicon-glass', 'local_bar');
|
||||
this.iconsMDL.set('glyphicon-music', 'music_note');
|
||||
this.iconsMDL.set('glyphicon-search', 'search');
|
||||
this.iconsMDL.set('glyphicon-heart', 'favorite');
|
||||
this.iconsMDL.set('glyphicon-heart-empty', 'favorite_border');
|
||||
this.iconsMDL.set('glyphicon-star', 'star');
|
||||
this.iconsMDL.set('glyphicon-star-empty', 'star_border');
|
||||
this.iconsMDL.set('glyphicon-user', 'person');
|
||||
this.iconsMDL.set('glyphicon-film', 'movie_creation');
|
||||
this.iconsMDL.set('glyphicon-th-large', 'view_comfy');
|
||||
this.iconsMDL.set('glyphicon-th', 'view_compact');
|
||||
this.iconsMDL.set('glyphicon-th-list', 'list');
|
||||
this.iconsMDL.set('glyphicon-ok', 'done');
|
||||
this.iconsMDL.set('glyphicon-remove', 'cancel');
|
||||
this.iconsMDL.set('glyphicon-zoom-in', 'zoom_in');
|
||||
this.iconsMDL.set('glyphicon-zoom-out', 'zoom_out');
|
||||
this.iconsMDL.set('glyphicon-off', 'highlight_off');
|
||||
this.iconsMDL.set('glyphicon-signal', 'signal_cellular_4_bar');
|
||||
this.iconsMDL.set('glyphicon-cog', 'settings');
|
||||
this.iconsMDL.set('glyphicon-trash', 'delete');
|
||||
this.iconsMDL.set('glyphicon-home', 'home');
|
||||
this.iconsMDL.set('glyphicon-file', 'insert_drive_file');
|
||||
this.iconsMDL.set('glyphicon-time', 'access_time');
|
||||
this.iconsMDL.set('glyphicon-road', 'map');
|
||||
this.iconsMDL.set('glyphicon-download-alt', 'file_download');
|
||||
this.iconsMDL.set('glyphicon-download', 'file_download');
|
||||
this.iconsMDL.set('glyphicon-upload', 'file_upload');
|
||||
this.iconsMDL.set('glyphicon-inbox', 'inbox');
|
||||
this.iconsMDL.set('glyphicon-play-circle', 'play_circle_outline');
|
||||
this.iconsMDL.set('glyphicon-repeat', 'refresh');
|
||||
this.iconsMDL.set('glyphicon-refresh', 'sync');
|
||||
this.iconsMDL.set('glyphicon-list-alt', 'event_note');
|
||||
this.iconsMDL.set('glyphicon-lock', 'lock_outline');
|
||||
this.iconsMDL.set('glyphicon-flag', 'assistant_photo');
|
||||
this.iconsMDL.set('glyphicon-headphones', 'headset');
|
||||
this.iconsMDL.set('glyphicon-volume-up', 'volume_up');
|
||||
this.iconsMDL.set('glyphicon-tag', 'local_offer');
|
||||
this.iconsMDL.set('glyphicon-tags', 'local_offer');
|
||||
this.iconsMDL.set('glyphicon-book', 'library_books');
|
||||
this.iconsMDL.set('glyphicon-bookmark', 'collections_bookmark');
|
||||
this.iconsMDL.set('glyphicon-print', 'local_printshop');
|
||||
this.iconsMDL.set('glyphicon-camera', 'local_see');
|
||||
this.iconsMDL.set('glyphicon-list', 'view_list');
|
||||
this.iconsMDL.set('glyphicon-facetime-video', 'video_call');
|
||||
this.iconsMDL.set('glyphicon-picture', 'photo');
|
||||
this.iconsMDL.set('glyphicon-map-marker', 'add_location');
|
||||
this.iconsMDL.set('glyphicon-adjust', 'brightness_4');
|
||||
this.iconsMDL.set('glyphicon-tint', 'invert_colors');
|
||||
this.iconsMDL.set('glyphicon-edit', 'edit');
|
||||
this.iconsMDL.set('glyphicon-share', 'share');
|
||||
this.iconsMDL.set('glyphicon-check', 'assignment_turned_in');
|
||||
this.iconsMDL.set('glyphicon-move', 'open_with');
|
||||
this.iconsMDL.set('glyphicon-play', 'play_arrow');
|
||||
this.iconsMDL.set('glyphicon-eject', 'eject');
|
||||
this.iconsMDL.set('glyphicon-plus-sign', 'add_circle');
|
||||
this.iconsMDL.set('glyphicon-minus-sign', 'remove_circle');
|
||||
this.iconsMDL.set('glyphicon-remove-sign', 'cancel');
|
||||
this.iconsMDL.set('glyphicon-ok-sign', 'check_circle');
|
||||
this.iconsMDL.set('glyphicon-question-sign', 'help');
|
||||
this.iconsMDL.set('glyphicon-info-sign', 'info');
|
||||
this.iconsMDL.set('glyphicon-screenshot', 'flare');
|
||||
this.iconsMDL.set('glyphicon-remove-circle', 'cancel');
|
||||
this.iconsMDL.set('glyphicon-ok-circle', 'add_circle');
|
||||
this.iconsMDL.set('glyphicon-ban-circle', 'block');
|
||||
this.iconsMDL.set('glyphicon-share-alt', 'redo');
|
||||
this.iconsMDL.set('glyphicon-exclamation-sign', 'error');
|
||||
this.iconsMDL.set('glyphicon-gift', 'giftcard');
|
||||
this.iconsMDL.set('glyphicon-leaf', 'spa');
|
||||
this.iconsMDL.set('glyphicon-fire', 'whatshot');
|
||||
this.iconsMDL.set('glyphicon-eye-open', 'remove_red_eye');
|
||||
this.iconsMDL.set('glyphicon-eye-close', 'remove_red_eye');
|
||||
this.iconsMDL.set('glyphicon-warning-sign', 'warning');
|
||||
this.iconsMDL.set('glyphicon-plane', 'airplanemode_active');
|
||||
this.iconsMDL.set('glyphicon-calendar', IconModel.DEFAULT_TASKS_APP_MATERIAL_ICON);
|
||||
this.iconsMDL.set('glyphicon-random', IconModel.DEFAULT_TASKS_APP_MATERIAL_ICON);
|
||||
this.iconsMDL.set('glyphicon-comment', IconModel.DEFAULT_TASKS_APP_MATERIAL_ICON);
|
||||
this.iconsMDL.set('glyphicon-magnet', IconModel.DEFAULT_TASKS_APP_MATERIAL_ICON);
|
||||
this.iconsMDL.set('glyphicon-retweet', IconModel.DEFAULT_TASKS_APP_MATERIAL_ICON);
|
||||
this.iconsMDL.set('glyphicon-shopping-cart', IconModel.DEFAULT_TASKS_APP_MATERIAL_ICON);
|
||||
this.iconsMDL.set('glyphicon-folder-close', IconModel.DEFAULT_TASKS_APP_MATERIAL_ICON);
|
||||
this.iconsMDL.set('glyphicon-folder-open', IconModel.DEFAULT_TASKS_APP_MATERIAL_ICON);
|
||||
this.iconsMDL.set('glyphicon-hdd', IconModel.DEFAULT_TASKS_APP_MATERIAL_ICON);
|
||||
this.iconsMDL.set('glyphicon-bullhorn', IconModel.DEFAULT_TASKS_APP_MATERIAL_ICON);
|
||||
this.iconsMDL.set('glyphicon-bell', IconModel.DEFAULT_TASKS_APP_MATERIAL_ICON);
|
||||
this.iconsMDL.set('glyphicon-certificate', IconModel.DEFAULT_TASKS_APP_MATERIAL_ICON);
|
||||
this.iconsMDL.set('glyphicon-thumbs-up', IconModel.DEFAULT_TASKS_APP_MATERIAL_ICON);
|
||||
this.iconsMDL.set('glyphicon-thumbs-down', IconModel.DEFAULT_TASKS_APP_MATERIAL_ICON);
|
||||
this.iconsMDL.set('glyphicon-hand-left', IconModel.DEFAULT_TASKS_APP_MATERIAL_ICON);
|
||||
this.iconsMDL.set('glyphicon-globe', IconModel.DEFAULT_TASKS_APP_MATERIAL_ICON);
|
||||
this.iconsMDL.set('glyphicon-wrench', IconModel.DEFAULT_TASKS_APP_MATERIAL_ICON);
|
||||
this.iconsMDL.set('glyphicon-tasks', IconModel.DEFAULT_TASKS_APP_MATERIAL_ICON);
|
||||
this.iconsMDL.set('glyphicon-filter', IconModel.DEFAULT_TASKS_APP_MATERIAL_ICON);
|
||||
this.iconsMDL.set('glyphicon-briefcase', IconModel.DEFAULT_TASKS_APP_MATERIAL_ICON);
|
||||
this.iconsMDL.set('glyphicon-dashboard', IconModel.DEFAULT_TASKS_APP_MATERIAL_ICON);
|
||||
this.iconsMDL.set('glyphicon-paperclip', IconModel.DEFAULT_TASKS_APP_MATERIAL_ICON);
|
||||
this.iconsMDL.set('glyphicon-link', IconModel.DEFAULT_TASKS_APP_MATERIAL_ICON);
|
||||
this.iconsMDL.set('glyphicon-phone', IconModel.DEFAULT_TASKS_APP_MATERIAL_ICON);
|
||||
this.iconsMDL.set('glyphicon-pushpin', IconModel.DEFAULT_TASKS_APP_MATERIAL_ICON);
|
||||
this.iconsMDL.set('glyphicon-usd', IconModel.DEFAULT_TASKS_APP_MATERIAL_ICON);
|
||||
this.iconsMDL.set('glyphicon-gbp', IconModel.DEFAULT_TASKS_APP_MATERIAL_ICON);
|
||||
this.iconsMDL.set('glyphicon-sort', IconModel.DEFAULT_TASKS_APP_MATERIAL_ICON);
|
||||
this.iconsMDL.set('glyphicon-flash', IconModel.DEFAULT_TASKS_APP_MATERIAL_ICON);
|
||||
this.iconsMDL.set('glyphicon-record', IconModel.DEFAULT_TASKS_APP_MATERIAL_ICON);
|
||||
this.iconsMDL.set('glyphicon-save', IconModel.DEFAULT_TASKS_APP_MATERIAL_ICON);
|
||||
this.iconsMDL.set('glyphicon-open', IconModel.DEFAULT_TASKS_APP_MATERIAL_ICON);
|
||||
this.iconsMDL.set('glyphicon-saved', IconModel.DEFAULT_TASKS_APP_MATERIAL_ICON);
|
||||
this.iconsMDL.set('glyphicon-send', 'send');
|
||||
this.iconsMDL.set('glyphicon-floppy-disk', IconModel.DEFAULT_TASKS_APP_MATERIAL_ICON);
|
||||
this.iconsMDL.set('glyphicon-credit-card', IconModel.DEFAULT_TASKS_APP_MATERIAL_ICON);
|
||||
this.iconsMDL.set('glyphicon-cutlery', IconModel.DEFAULT_TASKS_APP_MATERIAL_ICON);
|
||||
this.iconsMDL.set('glyphicon-earphone', IconModel.DEFAULT_TASKS_APP_MATERIAL_ICON);
|
||||
this.iconsMDL.set('glyphicon-phone-alt', IconModel.DEFAULT_TASKS_APP_MATERIAL_ICON);
|
||||
this.iconsMDL.set('glyphicon-tower', IconModel.DEFAULT_TASKS_APP_MATERIAL_ICON);
|
||||
this.iconsMDL.set('glyphicon-stats', IconModel.DEFAULT_TASKS_APP_MATERIAL_ICON);
|
||||
this.iconsMDL.set('glyphicon-cloud-download', IconModel.DEFAULT_TASKS_APP_MATERIAL_ICON);
|
||||
this.iconsMDL.set('glyphicon-cloud-upload', IconModel.DEFAULT_TASKS_APP_MATERIAL_ICON);
|
||||
this.iconsMDL.set('glyphicon-tree-conifer', IconModel.DEFAULT_TASKS_APP_MATERIAL_ICON);
|
||||
this.iconsMDL.set('glyphicon-tree-deciduous', IconModel.DEFAULT_TASKS_APP_MATERIAL_ICON);
|
||||
}
|
||||
}
|
18
lib/process-services/app-list/index.ts
Normal file
18
lib/process-services/app-list/index.ts
Normal file
@@ -0,0 +1,18 @@
|
||||
/*!
|
||||
* @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.
|
||||
*/
|
||||
|
||||
export * from './public-api';
|
20
lib/process-services/app-list/public-api.ts
Normal file
20
lib/process-services/app-list/public-api.ts
Normal file
@@ -0,0 +1,20 @@
|
||||
/*!
|
||||
* @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.
|
||||
*/
|
||||
|
||||
export * from './apps-list.component';
|
||||
|
||||
export * from './apps-list.module';
|
208
lib/process-services/assets/images/empty_doc_lib.svg
Normal file
208
lib/process-services/assets/images/empty_doc_lib.svg
Normal file
@@ -0,0 +1,208 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<svg width="566px" height="165px" viewBox="0 0 566 165" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
|
||||
<!-- Generator: Sketch 3.8.3 (29802) - http://www.bohemiancoding.com/sketch -->
|
||||
<title>empty_doc_lib</title>
|
||||
<desc>Created with Sketch.</desc>
|
||||
<defs>
|
||||
<rect id="path-1" x="5.68434189e-14" y="-1.01962883e-12" width="78.1679389" height="78.1679389" rx="2"></rect>
|
||||
<filter x="-50%" y="-50%" width="200%" height="200%" filterUnits="objectBoundingBox" id="filter-2">
|
||||
<feOffset dx="0" dy="2" in="SourceAlpha" result="shadowOffsetOuter1"></feOffset>
|
||||
<feGaussianBlur stdDeviation="1" in="shadowOffsetOuter1" result="shadowBlurOuter1"></feGaussianBlur>
|
||||
<feColorMatrix values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.24 0" type="matrix" in="shadowBlurOuter1" result="shadowMatrixOuter1"></feColorMatrix>
|
||||
<feOffset dx="0" dy="0" in="SourceAlpha" result="shadowOffsetOuter2"></feOffset>
|
||||
<feGaussianBlur stdDeviation="1" in="shadowOffsetOuter2" result="shadowBlurOuter2"></feGaussianBlur>
|
||||
<feColorMatrix values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.12 0" type="matrix" in="shadowBlurOuter2" result="shadowMatrixOuter2"></feColorMatrix>
|
||||
<feMerge>
|
||||
<feMergeNode in="shadowMatrixOuter1"></feMergeNode>
|
||||
<feMergeNode in="shadowMatrixOuter2"></feMergeNode>
|
||||
</feMerge>
|
||||
</filter>
|
||||
<rect id="path-3" x="-4.54747351e-13" y="5.68434189e-13" width="78.1679389" height="78.1679389" rx="2"></rect>
|
||||
<filter x="-50%" y="-50%" width="200%" height="200%" filterUnits="objectBoundingBox" id="filter-4">
|
||||
<feOffset dx="0" dy="2" in="SourceAlpha" result="shadowOffsetOuter1"></feOffset>
|
||||
<feGaussianBlur stdDeviation="1" in="shadowOffsetOuter1" result="shadowBlurOuter1"></feGaussianBlur>
|
||||
<feColorMatrix values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.24 0" type="matrix" in="shadowBlurOuter1" result="shadowMatrixOuter1"></feColorMatrix>
|
||||
<feOffset dx="0" dy="0" in="SourceAlpha" result="shadowOffsetOuter2"></feOffset>
|
||||
<feGaussianBlur stdDeviation="1" in="shadowOffsetOuter2" result="shadowBlurOuter2"></feGaussianBlur>
|
||||
<feColorMatrix values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.12 0" type="matrix" in="shadowBlurOuter2" result="shadowMatrixOuter2"></feColorMatrix>
|
||||
<feMerge>
|
||||
<feMergeNode in="shadowMatrixOuter1"></feMergeNode>
|
||||
<feMergeNode in="shadowMatrixOuter2"></feMergeNode>
|
||||
</feMerge>
|
||||
</filter>
|
||||
<rect id="path-5" x="-1.08002496e-12" y="7.81597009e-14" width="78.1679389" height="78.1679389" rx="2"></rect>
|
||||
<filter x="-50%" y="-50%" width="200%" height="200%" filterUnits="objectBoundingBox" id="filter-6">
|
||||
<feOffset dx="0" dy="2" in="SourceAlpha" result="shadowOffsetOuter1"></feOffset>
|
||||
<feGaussianBlur stdDeviation="1" in="shadowOffsetOuter1" result="shadowBlurOuter1"></feGaussianBlur>
|
||||
<feColorMatrix values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.24 0" type="matrix" in="shadowBlurOuter1" result="shadowMatrixOuter1"></feColorMatrix>
|
||||
<feOffset dx="0" dy="0" in="SourceAlpha" result="shadowOffsetOuter2"></feOffset>
|
||||
<feGaussianBlur stdDeviation="1" in="shadowOffsetOuter2" result="shadowBlurOuter2"></feGaussianBlur>
|
||||
<feColorMatrix values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.12 0" type="matrix" in="shadowBlurOuter2" result="shadowMatrixOuter2"></feColorMatrix>
|
||||
<feMerge>
|
||||
<feMergeNode in="shadowMatrixOuter1"></feMergeNode>
|
||||
<feMergeNode in="shadowMatrixOuter2"></feMergeNode>
|
||||
</feMerge>
|
||||
</filter>
|
||||
<rect id="path-7" x="1.29318778e-12" y="9.23705556e-14" width="78.1679389" height="78.1679389" rx="2"></rect>
|
||||
<filter x="-50%" y="-50%" width="200%" height="200%" filterUnits="objectBoundingBox" id="filter-8">
|
||||
<feOffset dx="0" dy="2" in="SourceAlpha" result="shadowOffsetOuter1"></feOffset>
|
||||
<feGaussianBlur stdDeviation="1" in="shadowOffsetOuter1" result="shadowBlurOuter1"></feGaussianBlur>
|
||||
<feColorMatrix values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.24 0" type="matrix" in="shadowBlurOuter1" result="shadowMatrixOuter1"></feColorMatrix>
|
||||
<feOffset dx="0" dy="0" in="SourceAlpha" result="shadowOffsetOuter2"></feOffset>
|
||||
<feGaussianBlur stdDeviation="1" in="shadowOffsetOuter2" result="shadowBlurOuter2"></feGaussianBlur>
|
||||
<feColorMatrix values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.12 0" type="matrix" in="shadowBlurOuter2" result="shadowMatrixOuter2"></feColorMatrix>
|
||||
<feMerge>
|
||||
<feMergeNode in="shadowMatrixOuter1"></feMergeNode>
|
||||
<feMergeNode in="shadowMatrixOuter2"></feMergeNode>
|
||||
</feMerge>
|
||||
</filter>
|
||||
<rect id="path-9" x="-2.96651592e-13" y="-7.60280727e-13" width="78.1679389" height="78.1679389" rx="2"></rect>
|
||||
<filter x="-50%" y="-50%" width="200%" height="200%" filterUnits="objectBoundingBox" id="filter-10">
|
||||
<feOffset dx="0" dy="2" in="SourceAlpha" result="shadowOffsetOuter1"></feOffset>
|
||||
<feGaussianBlur stdDeviation="1" in="shadowOffsetOuter1" result="shadowBlurOuter1"></feGaussianBlur>
|
||||
<feColorMatrix values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.24 0" type="matrix" in="shadowBlurOuter1" result="shadowMatrixOuter1"></feColorMatrix>
|
||||
<feOffset dx="0" dy="0" in="SourceAlpha" result="shadowOffsetOuter2"></feOffset>
|
||||
<feGaussianBlur stdDeviation="1" in="shadowOffsetOuter2" result="shadowBlurOuter2"></feGaussianBlur>
|
||||
<feColorMatrix values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.12 0" type="matrix" in="shadowBlurOuter2" result="shadowMatrixOuter2"></feColorMatrix>
|
||||
<feMerge>
|
||||
<feMergeNode in="shadowMatrixOuter1"></feMergeNode>
|
||||
<feMergeNode in="shadowMatrixOuter2"></feMergeNode>
|
||||
</feMerge>
|
||||
</filter>
|
||||
<rect id="path-11" x="3.48165941e-13" y="2.27373675e-13" width="78.1679389" height="78.1679389" rx="2"></rect>
|
||||
<filter x="-50%" y="-50%" width="200%" height="200%" filterUnits="objectBoundingBox" id="filter-12">
|
||||
<feOffset dx="0" dy="2" in="SourceAlpha" result="shadowOffsetOuter1"></feOffset>
|
||||
<feGaussianBlur stdDeviation="1" in="shadowOffsetOuter1" result="shadowBlurOuter1"></feGaussianBlur>
|
||||
<feColorMatrix values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.24 0" type="matrix" in="shadowBlurOuter1" result="shadowMatrixOuter1"></feColorMatrix>
|
||||
<feOffset dx="0" dy="0" in="SourceAlpha" result="shadowOffsetOuter2"></feOffset>
|
||||
<feGaussianBlur stdDeviation="1" in="shadowOffsetOuter2" result="shadowBlurOuter2"></feGaussianBlur>
|
||||
<feColorMatrix values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.12 0" type="matrix" in="shadowBlurOuter2" result="shadowMatrixOuter2"></feColorMatrix>
|
||||
<feMerge>
|
||||
<feMergeNode in="shadowMatrixOuter1"></feMergeNode>
|
||||
<feMergeNode in="shadowMatrixOuter2"></feMergeNode>
|
||||
</feMerge>
|
||||
</filter>
|
||||
<rect id="path-13" x="0" y="-5.40012479e-13" width="78.1679389" height="78.1679389" rx="2"></rect>
|
||||
<filter x="-50%" y="-50%" width="200%" height="200%" filterUnits="objectBoundingBox" id="filter-14">
|
||||
<feOffset dx="0" dy="2" in="SourceAlpha" result="shadowOffsetOuter1"></feOffset>
|
||||
<feGaussianBlur stdDeviation="1" in="shadowOffsetOuter1" result="shadowBlurOuter1"></feGaussianBlur>
|
||||
<feColorMatrix values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.24 0" type="matrix" in="shadowBlurOuter1" result="shadowMatrixOuter1"></feColorMatrix>
|
||||
<feOffset dx="0" dy="0" in="SourceAlpha" result="shadowOffsetOuter2"></feOffset>
|
||||
<feGaussianBlur stdDeviation="1" in="shadowOffsetOuter2" result="shadowBlurOuter2"></feGaussianBlur>
|
||||
<feColorMatrix values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.12 0" type="matrix" in="shadowBlurOuter2" result="shadowMatrixOuter2"></feColorMatrix>
|
||||
<feMerge>
|
||||
<feMergeNode in="shadowMatrixOuter1"></feMergeNode>
|
||||
<feMergeNode in="shadowMatrixOuter2"></feMergeNode>
|
||||
</feMerge>
|
||||
</filter>
|
||||
<rect id="path-15" x="0" y="0" width="78.1679389" height="78.1679389" rx="2"></rect>
|
||||
<filter x="-50%" y="-50%" width="200%" height="200%" filterUnits="objectBoundingBox" id="filter-16">
|
||||
<feOffset dx="0" dy="2" in="SourceAlpha" result="shadowOffsetOuter1"></feOffset>
|
||||
<feGaussianBlur stdDeviation="1" in="shadowOffsetOuter1" result="shadowBlurOuter1"></feGaussianBlur>
|
||||
<feColorMatrix values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.24 0" type="matrix" in="shadowBlurOuter1" result="shadowMatrixOuter1"></feColorMatrix>
|
||||
<feOffset dx="0" dy="0" in="SourceAlpha" result="shadowOffsetOuter2"></feOffset>
|
||||
<feGaussianBlur stdDeviation="1" in="shadowOffsetOuter2" result="shadowBlurOuter2"></feGaussianBlur>
|
||||
<feColorMatrix values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.12 0" type="matrix" in="shadowBlurOuter2" result="shadowMatrixOuter2"></feColorMatrix>
|
||||
<feMerge>
|
||||
<feMergeNode in="shadowMatrixOuter1"></feMergeNode>
|
||||
<feMergeNode in="shadowMatrixOuter2"></feMergeNode>
|
||||
</feMerge>
|
||||
</filter>
|
||||
</defs>
|
||||
<g id="Symbols" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
|
||||
<g id="empty-folder-state-desktop" transform="translate(-37.000000, -168.000000)">
|
||||
<g id="empty_doc_lib" transform="translate(38.000000, 169.000000)">
|
||||
<g id="Group-5" transform="translate(241.569490, 92.634375) rotate(-355.000000) translate(-241.569490, -92.634375) translate(202.069490, 53.134375)">
|
||||
<g id="Rectangle-1196-Copy-2">
|
||||
<use fill="black" fill-opacity="1" filter="url(#filter-2)" xlink:href="#path-1"></use>
|
||||
<use fill="#FFFFFF" fill-rule="evenodd" xlink:href="#path-1"></use>
|
||||
</g>
|
||||
<g id="filetype_video" transform="translate(9.770992, 9.770992)">
|
||||
<polygon id="Fill-1" points="0 58.6259542 58.6259542 58.6259542 58.6259542 0 0 0"></polygon>
|
||||
<path d="M39.0839695,21.9847328 L43.9694656,21.9847328 L43.9694656,17.0992366 L39.0839695,17.0992366 L39.0839695,21.9847328 Z M39.0839695,31.7557252 L43.9694656,31.7557252 L43.9694656,26.870229 L39.0839695,26.870229 L39.0839695,31.7557252 Z M39.0839695,41.5267176 L43.9694656,41.5267176 L43.9694656,36.6412214 L39.0839695,36.6412214 L39.0839695,41.5267176 Z M14.6564885,21.9847328 L19.5419847,21.9847328 L19.5419847,17.0992366 L14.6564885,17.0992366 L14.6564885,21.9847328 Z M14.6564885,31.7557252 L19.5419847,31.7557252 L19.5419847,26.870229 L14.6564885,26.870229 L14.6564885,31.7557252 Z M14.6564885,41.5267176 L19.5419847,41.5267176 L19.5419847,36.6412214 L14.6564885,36.6412214 L14.6564885,41.5267176 Z M43.9694656,7.32824427 L43.9694656,12.2137405 L39.0839695,12.2137405 L39.0839695,7.32824427 L19.5419847,7.32824427 L19.5419847,12.2137405 L14.6564885,12.2137405 L14.6564885,7.32824427 L9.77099237,7.32824427 L9.77099237,51.2977099 L14.6564885,51.2977099 L14.6564885,46.4122137 L19.5419847,46.4122137 L19.5419847,51.2977099 L39.0839695,51.2977099 L39.0839695,46.4122137 L43.9694656,46.4122137 L43.9694656,51.2977099 L48.8549618,51.2977099 L48.8549618,7.32824427 L43.9694656,7.32824427 Z" id="Fill-2" fill="#FFC107"></path>
|
||||
</g>
|
||||
</g>
|
||||
<g id="Group-7" transform="translate(515.948329, 81.354522) rotate(-345.000000) translate(-515.948329, -81.354522) translate(476.448329, 41.854522)">
|
||||
<g id="Rectangle-1196-Copy-3">
|
||||
<use fill="black" fill-opacity="1" filter="url(#filter-4)" xlink:href="#path-3"></use>
|
||||
<use fill="#FFFFFF" fill-rule="evenodd" xlink:href="#path-3"></use>
|
||||
</g>
|
||||
<g id="filetype_image" transform="translate(9.770992, 9.770992)">
|
||||
<polygon id="Fill-1" points="0 58.6259542 58.6259542 58.6259542 58.6259542 0 0 0"></polygon>
|
||||
<path d="M20.7636031,32.9773435 L26.8704733,40.3178015 L35.4200916,29.3132214 L46.412458,43.9697099 L12.2139847,43.9697099 L20.7636031,32.9773435 Z M51.2979542,46.412458 L51.2979542,12.2139847 C51.2979542,9.51474809 49.1116947,7.32848855 46.412458,7.32848855 L12.2139847,7.32848855 C9.51474809,7.32848855 7.32848855,9.51474809 7.32848855,12.2139847 L7.32848855,46.412458 C7.32848855,49.1116947 9.51474809,51.2979542 12.2139847,51.2979542 L46.412458,51.2979542 C49.1116947,51.2979542 51.2979542,49.1116947 51.2979542,46.412458 L51.2979542,46.412458 Z" id="Fill-2" fill="#22BE73"></path>
|
||||
</g>
|
||||
</g>
|
||||
<g id="Group-8" transform="translate(309.051884, 62.261808) rotate(-5.000000) translate(-309.051884, -62.261808) translate(269.551884, 22.761808)">
|
||||
<g id="Rectangle-1196-Copy-4">
|
||||
<use fill="black" fill-opacity="1" filter="url(#filter-6)" xlink:href="#path-5"></use>
|
||||
<use fill="#FFFFFF" fill-rule="evenodd" xlink:href="#path-5"></use>
|
||||
</g>
|
||||
<g id="filetype_googledocs" transform="translate(9.770992, 9.770992)">
|
||||
<polygon id="Fill-1" points="6.82121026e-13 58.6259542 58.6259542 58.6259542 58.6259542 -2.98427949e-13 6.82121026e-13 -2.98427949e-13"></polygon>
|
||||
<g id="Group-6" transform="translate(9.770992, 4.885496)">
|
||||
<path d="M7.32824427,21.9847328 L31.7557252,21.9847328 L31.7557252,19.5419847 L7.32824427,19.5419847 L7.32824427,21.9847328 Z M7.32824427,26.870229 L31.7557252,26.870229 L31.7557252,24.4274809 L7.32824427,24.4274809 L7.32824427,26.870229 Z M7.32824427,31.7557252 L31.7557252,31.7557252 L31.7557252,29.3129771 L7.32824427,29.3129771 L7.32824427,31.7557252 Z M7.32824427,36.6412214 L21.9847328,36.6412214 L21.9847328,34.1984733 L7.32824427,34.1984733 L7.32824427,36.6412214 Z M29.3129771,0 L4.88549618,0 C2.18625954,0 0.0244274809,2.18625954 0.0244274809,4.88549618 L0,43.9694656 C0,46.6687023 2.16183206,48.8549618 4.8610687,48.8549618 L34.1984733,48.8549618 C36.8977099,48.8549618 39.0839695,46.6687023 39.0839695,43.9694656 L39.0839695,9.77099237 L29.3129771,0 Z" id="Fill-2" fill="#2979FF"></path>
|
||||
<polygon id="Fill-4" fill-opacity="0.5" fill="#FFFFFF" points="29.3129771 9.77099237 29.3129771 -2.84217094e-14 39.0839695 9.77099237"></polygon>
|
||||
<polygon id="Fill-5" fill-opacity="0.2" fill="#000000" points="39.0839695 9.77099237 39.0839695 19.5419847 29.3129771 9.77099237"></polygon>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
<g id="Group-9" transform="translate(155.408682, 49.364493) rotate(-345.000000) translate(-155.408682, -49.364493) translate(115.908682, 9.864493)">
|
||||
<g id="Rectangle-1196-Copy-5">
|
||||
<use fill="black" fill-opacity="1" filter="url(#filter-8)" xlink:href="#path-7"></use>
|
||||
<use fill="#FFFFFF" fill-rule="evenodd" xlink:href="#path-7"></use>
|
||||
</g>
|
||||
<g id="filetype_pdf" transform="translate(9.770992, 9.770992)">
|
||||
<polygon id="Fill-1" points="0 58.6259542 58.6259542 58.6259542 58.6259542 0 0 0"></polygon>
|
||||
<path d="M45.1888855,25.5877863 L45.1888855,21.9187786 L37.853313,21.9187786 L37.853313,36.5923664 L41.5198779,36.5923664 L41.5198779,31.7777099 L45.1888855,31.7777099 L45.1888855,28.1087023 L41.5198779,28.1087023 L41.5198779,25.5877863 L45.1888855,25.5877863 Z M29.3696489,32.9233588 L31.7757557,32.9233588 L31.7757557,25.5877863 L29.3696489,25.5877863 L29.3696489,32.9233588 Z M35.4447634,32.9233588 L35.4447634,25.5877863 C35.4447634,24.5960305 35.1027786,23.7361832 34.4139237,23.0082443 C33.7275115,22.2827481 32.8481221,21.9187786 31.7781985,21.9187786 L25.703084,21.9187786 L25.703084,36.5923664 L31.7781985,36.5923664 C32.8481221,36.5923664 33.7275115,36.2308397 34.4139237,35.5029008 C35.1027786,34.7774046 35.4447634,33.9175573 35.4447634,32.9233588 L35.4447634,32.9233588 Z M17.1070534,28.1087023 L19.5131603,28.1087023 L19.5131603,25.5877863 L17.1070534,25.5877863 L17.1070534,28.1087023 Z M23.1821679,28.1087023 L23.1821679,25.5877863 C23.1821679,24.5960305 22.8181985,23.7361832 22.0927023,23.0082443 C21.3672061,22.2827481 20.5073588,21.9187786 19.5131603,21.9187786 L13.4380458,21.9187786 L13.4380458,36.5923664 L17.1070534,36.5923664 L17.1070534,31.7777099 L19.5131603,31.7777099 C20.5073588,31.7777099 21.3672061,31.4161832 22.0927023,30.6882443 C22.8181985,29.9627481 23.1821679,29.1029008 23.1821679,28.1087023 L23.1821679,28.1087023 Z M46.483542,7.32824427 C47.783084,7.32824427 48.9091908,7.8070229 49.8643053,8.7621374 C50.8218626,9.71725191 51.2981985,10.8433588 51.2981985,12.1429008 L51.2981985,46.3682443 C51.2981985,47.670229 50.8218626,48.8158779 49.8643053,49.8076336 C48.9091908,50.8018321 47.783084,51.2977099 46.483542,51.2977099 L12.2581985,51.2977099 C10.9586565,51.2977099 9.81300763,50.8018321 8.81880916,49.8076336 C7.82461069,48.8158779 7.32873282,47.670229 7.32873282,46.3682443 L7.32873282,12.1429008 C7.32873282,10.8433588 7.82461069,9.71725191 8.81880916,8.7621374 C9.81300763,7.8070229 10.9586565,7.32824427 12.2581985,7.32824427 L46.483542,7.32824427 Z" id="Fill-2" fill="#E91E63"></path>
|
||||
</g>
|
||||
</g>
|
||||
<g id="Group-12" transform="translate(49.364493, 62.584254) rotate(-15.000000) translate(-49.364493, -62.584254) translate(9.864493, 23.084254)">
|
||||
<g id="Rectangle-1196-Copy-7">
|
||||
<use fill="black" fill-opacity="1" filter="url(#filter-10)" xlink:href="#path-9"></use>
|
||||
<use fill="#FFFFFF" fill-rule="evenodd" xlink:href="#path-9"></use>
|
||||
</g>
|
||||
<g id="filetype_forms" transform="translate(9.770992, 9.770992)">
|
||||
<polygon id="Fill-1" points="0 58.6259542 58.6259542 58.6259542 58.6259542 0 0 0"></polygon>
|
||||
<path d="M24.4274809,24.4250382 L41.5267176,24.4250382 L41.5267176,19.539542 L24.4274809,19.539542 L24.4274809,24.4250382 Z M24.4274809,31.7532824 L41.5267176,31.7532824 L41.5267176,26.8677863 L24.4274809,26.8677863 L24.4274809,31.7532824 Z M24.4274809,39.0839695 L41.5267176,39.0839695 L41.5267176,34.1984733 L24.4274809,34.1984733 L24.4274809,39.0839695 Z M17.0992366,24.4250382 L21.9847328,24.4250382 L21.9847328,19.539542 L17.0992366,19.539542 L17.0992366,24.4250382 Z M17.0992366,31.7532824 L21.9847328,31.7532824 L21.9847328,26.8677863 L17.0992366,26.8677863 L17.0992366,31.7532824 Z M17.0992366,39.0839695 L21.9847328,39.0839695 L21.9847328,34.1984733 L17.0992366,34.1984733 L17.0992366,39.0839695 Z M43.9694656,9.77099237 L14.6564885,9.77099237 C11.9694656,9.77099237 9.77099237,11.9694656 9.77099237,14.6564885 L9.77099237,43.9694656 C9.77099237,46.6564885 11.9694656,48.8549618 14.6564885,48.8549618 L43.9694656,48.8549618 C46.6564885,48.8549618 48.8549618,46.6564885 48.8549618,43.9694656 L48.8549618,14.6564885 C48.8549618,11.9694656 46.6564885,9.77099237 43.9694656,9.77099237 L43.9694656,9.77099237 Z" id="Fill-2" fill="#651FFF"></path>
|
||||
</g>
|
||||
</g>
|
||||
<g id="Group-11" transform="translate(107.814782, 114.998541) rotate(-10.000000) translate(-107.814782, -114.998541) translate(68.314782, 75.498541)">
|
||||
<g id="Rectangle-1196-Copy-6">
|
||||
<use fill="black" fill-opacity="1" filter="url(#filter-12)" xlink:href="#path-11"></use>
|
||||
<use fill="#FFFFFF" fill-rule="evenodd" xlink:href="#path-11"></use>
|
||||
</g>
|
||||
<g id="filetype_excel" transform="translate(9.770992, 9.770992)">
|
||||
<polygon id="Fill-1" points="-5.68434189e-14 58.6259542 58.6259542 58.6259542 58.6259542 -1.56319402e-13 -5.68434189e-14 -1.56319402e-13"></polygon>
|
||||
<g id="Group-10" transform="translate(4.885496, 4.885496)" fill="#22BE73">
|
||||
<path d="M47.1621374,41.632 L28.848855,41.632 L28.848855,38.3025344 L33.2873282,38.3025344 L33.2873282,34.4161221 L28.848855,34.4161221 L28.848855,32.1981069 L33.2873282,32.1981069 L33.2873282,28.3116947 L28.848855,28.3116947 L28.848855,26.0936794 L33.2873282,26.0936794 L33.2873282,22.2072672 L28.848855,22.2072672 L28.848855,19.9868092 L33.2873282,19.9868092 L33.2873282,16.1028397 L28.848855,16.1028397 L28.848855,13.8823817 L33.2873282,13.8823817 L33.2873282,9.99841221 L28.848855,9.99841221 L28.848855,6.66894656 L47.1621374,6.66894656 L47.1621374,41.632 L47.1621374,41.632 Z M16.3444275,33.1141374 C15.4015267,30.7984122 14.2509924,28.5632977 13.5743511,26.1425344 C12.819542,28.3947481 11.7422901,30.5223817 10.8775573,32.730626 C9.6610687,32.7135267 8.4470229,32.6646718 7.23053435,32.613374 C8.65709924,29.821313 10.0348092,27.0072672 11.5053435,24.2323053 C10.2546565,21.3742901 8.88427481,18.572458 7.59694656,15.731542 C8.81832061,15.6582595 10.0396947,15.5874198 11.2610687,15.5190229 C12.0867176,17.690626 12.9929771,19.832916 13.6745038,22.0582595 C14.4073282,19.6985649 15.5016794,17.4781069 16.4372519,15.1990229 C17.6928244,15.1086412 18.9532824,15.032916 20.2112977,14.9718473 C18.7309924,18.0057405 17.2433588,21.0420763 15.7337405,24.0661985 C17.260458,27.1758168 18.8189313,30.2610076 20.3505344,33.3681832 C19.0143511,33.2900153 17.6806107,33.2069618 16.3444275,33.1141374 L16.3444275,33.1141374 Z M48.8329771,37.2203969 C48.8280916,27.591084 48.8158779,17.961771 48.8427481,8.32757252 C48.8036641,7.38467176 48.8720611,6.34161832 48.300458,5.51841221 C47.4845802,4.9590229 46.4512977,5.0249771 45.5132824,4.98589313 C39.9584733,5.01520611 34.4036641,5.00299237 28.848855,5.00299237 L28.848855,0.564519084 L25.551145,0.564519084 C17.0381679,2.06680916 8.5178626,3.52757252 4.68958206e-13,5.00787786 L4.68958206e-13,43.852458 C8.46900763,45.3327634 16.9429008,46.7544427 25.4021374,48.2909313 L28.848855,48.2909313 L28.848855,43.2979542 C34.6039695,43.2857405 40.359084,43.3126107 46.1068702,43.2979542 C47.0351145,43.2588702 48.4225954,43.2295573 48.6448855,42.0765802 C48.9819847,40.4839084 48.8036641,38.8350534 48.8329771,37.2203969 L48.8329771,37.2203969 Z" id="Fill-2"></path>
|
||||
<path d="M35.5077863,13.8821374 L43.2781679,13.8821374 L43.2781679,9.99816794 L35.5077863,9.99816794 L35.5077863,13.8821374 Z M35.5077863,19.9865649 L43.2781679,19.9865649 L43.2781679,16.1025954 L35.5077863,16.1025954 L35.5077863,19.9865649 Z M35.5077863,26.0909924 L43.2781679,26.0909924 L43.2781679,22.2070229 L35.5077863,22.2070229 L35.5077863,26.0909924 Z M35.5077863,32.1954198 L43.2781679,32.1954198 L43.2781679,28.3114504 L35.5077863,28.3114504 L35.5077863,32.1954198 Z M35.5077863,38.3022901 L43.2781679,38.3022901 L43.2781679,34.4183206 L35.5077863,34.4183206 L35.5077863,38.3022901 Z" id="Combined-Shape"></path>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
<g id="Group-4" transform="translate(388.820630, 86.064353) rotate(-350.000000) translate(-388.820630, -86.064353) translate(349.320630, 46.564353)">
|
||||
<g id="Rectangle-1196-Copy">
|
||||
<use fill="black" fill-opacity="1" filter="url(#filter-14)" xlink:href="#path-13"></use>
|
||||
<use fill="#FFFFFF" fill-rule="evenodd" xlink:href="#path-13"></use>
|
||||
</g>
|
||||
<g id="filetype_audio" transform="translate(9.770992, 9.770992)">
|
||||
<polygon id="Fill-1" points="-1.13686838e-13 58.6259542 58.6259542 58.6259542 58.6259542 -6.39488462e-14 -1.13686838e-13 -6.39488462e-14"></polygon>
|
||||
<path d="M29.3129771,7.32824427 L43.9694656,7.32824427 L43.9694656,17.0601527 L34.2375573,17.0601527 L34.2375573,41.5658015 C34.2375573,44.2381679 33.2629008,46.5270229 31.3160305,48.4348092 C29.3691603,50.3450382 27.0607634,51.2977099 24.3883969,51.2977099 C21.7160305,51.2977099 19.4271756,50.3450382 17.5193893,48.4348092 C15.6091603,46.5270229 14.6564885,44.2381679 14.6564885,41.5658015 C14.6564885,38.8934351 15.6091603,36.5850382 17.5193893,34.6381679 C19.4271756,32.6912977 21.7160305,31.7166412 24.3883969,31.7166412 C25.9932824,31.7166412 27.6323664,32.1758779 29.3129771,33.0919084 L29.3129771,7.32824427 Z" id="Fill-2" fill="#E91E63"></path>
|
||||
</g>
|
||||
</g>
|
||||
<g id="Group-2" transform="translate(411.603053, 1.221374)">
|
||||
<g id="Group-3">
|
||||
<g id="Rectangle-1196">
|
||||
<use fill="black" fill-opacity="1" filter="url(#filter-16)" xlink:href="#path-15"></use>
|
||||
<use fill="#FFFFFF" fill-rule="evenodd" xlink:href="#path-15"></use>
|
||||
</g>
|
||||
<polygon id="Fill-1" points="9.77099237 68.3969466 68.3969466 68.3969466 68.3969466 9.77099237 9.77099237 9.77099237"></polygon>
|
||||
</g>
|
||||
<g id="filetype_book" transform="translate(9.770992, 9.770992)">
|
||||
<polygon id="Fill-1" points="0 58.6259542 58.6259542 58.6259542 58.6259542 0 0 0"></polygon>
|
||||
<path d="M14.6564885,9.77099237 L26.870229,9.77099237 L26.870229,29.3129771 L20.7633588,25.648855 L14.6564885,29.3129771 L14.6564885,9.77099237 Z M43.9694656,4.88549618 L14.6564885,4.88549618 C11.9572519,4.88549618 9.77099237,7.07175573 9.77099237,9.77099237 L9.77099237,48.8549618 C9.77099237,51.5541985 11.9572519,53.740458 14.6564885,53.740458 L43.9694656,53.740458 C46.6687023,53.740458 48.8549618,51.5541985 48.8549618,48.8549618 L48.8549618,9.77099237 C48.8549618,7.07175573 46.6687023,4.88549618 43.9694656,4.88549618 L43.9694656,4.88549618 Z" id="Fill-2" fill="#FF6D40"></path>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
After Width: | Height: | Size: 26 KiB |
57
lib/process-services/attachment/attachment.module.ts
Normal file
57
lib/process-services/attachment/attachment.module.ts
Normal file
@@ -0,0 +1,57 @@
|
||||
/*!
|
||||
* @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 { CommonModule } from '@angular/common';
|
||||
import { NgModule } from '@angular/core';
|
||||
import { TranslateModule } from '@ngx-translate/core';
|
||||
import { MaterialModule } from '../material.module';
|
||||
import { DataColumnModule, DataTableModule, DirectiveModule } from '@alfresco/core';
|
||||
|
||||
import { TaskAttachmentListComponent } from './task-attachment-list.component';
|
||||
import { ProcessAttachmentListComponent } from './process-attachment-list.component';
|
||||
import { CreateProcessAttachmentComponent } from './create-process-attachment.component';
|
||||
import { AttachmentComponent } from './create-task-attachment.component';
|
||||
import { ProcessUploadService } from '../task-list/services/process-upload.service';
|
||||
|
||||
@NgModule({
|
||||
imports: [
|
||||
DataColumnModule,
|
||||
DataTableModule,
|
||||
MaterialModule,
|
||||
CommonModule,
|
||||
TranslateModule,
|
||||
DirectiveModule
|
||||
],
|
||||
providers: [
|
||||
ProcessUploadService
|
||||
],
|
||||
declarations: [
|
||||
TaskAttachmentListComponent,
|
||||
ProcessAttachmentListComponent,
|
||||
CreateProcessAttachmentComponent,
|
||||
CreateProcessAttachmentComponent,
|
||||
AttachmentComponent
|
||||
],
|
||||
exports: [
|
||||
TaskAttachmentListComponent,
|
||||
ProcessAttachmentListComponent,
|
||||
CreateProcessAttachmentComponent,
|
||||
CreateProcessAttachmentComponent,
|
||||
AttachmentComponent
|
||||
]
|
||||
})
|
||||
export class AttachmentModule {}
|
@@ -0,0 +1,5 @@
|
||||
.adf-create-attachment {
|
||||
display: inline-block;
|
||||
line-height: 0px;
|
||||
vertical-align: middle;
|
||||
}
|
@@ -0,0 +1,13 @@
|
||||
<button
|
||||
id="add_new_process_content_button"
|
||||
color="primary"
|
||||
mat-button
|
||||
mat-raised-button
|
||||
mat-icon-button
|
||||
class="adf-create-attachment"
|
||||
[adf-upload]="true"
|
||||
mode="['click']"
|
||||
[multiple]="true"
|
||||
(upload-files)="onFileUpload($event)">
|
||||
<mat-icon>add</mat-icon>
|
||||
</button>
|
@@ -0,0 +1,132 @@
|
||||
/*!
|
||||
* @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 { SimpleChange } from '@angular/core';
|
||||
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
import { MaterialModule } from '../material.module';
|
||||
import { ProcessContentService } from '@alfresco/core';
|
||||
import { TranslationService } from '@alfresco/core';
|
||||
import { CreateProcessAttachmentComponent } from './create-process-attachment.component';
|
||||
|
||||
declare let jasmine: any;
|
||||
|
||||
describe('Activiti Process Create Attachment', () => {
|
||||
|
||||
let service: ProcessContentService;
|
||||
let component: CreateProcessAttachmentComponent;
|
||||
let fixture: ComponentFixture<CreateProcessAttachmentComponent>;
|
||||
let element: HTMLElement;
|
||||
|
||||
let file = new File([new Blob()], 'Test');
|
||||
let fileObj = { entry: null, file: file, relativeFolder: '/' };
|
||||
let customEvent = { detail: { files: [fileObj] } };
|
||||
|
||||
let fakeUploadResponse = {
|
||||
id: 9999,
|
||||
name: 'BANANA.jpeg',
|
||||
created: '2017-06-12T12:52:11.109Z',
|
||||
createdBy: { id: 2, firstName: 'fake-user', lastName: 'fake-user', email: 'fake-user' },
|
||||
relatedContent: false,
|
||||
contentAvailable: true,
|
||||
link: false,
|
||||
mimeType: 'image/jpeg',
|
||||
simpleType: 'image',
|
||||
previewStatus: 'queued',
|
||||
thumbnailStatus: 'queued'
|
||||
};
|
||||
|
||||
beforeEach(async(() => {
|
||||
TestBed.configureTestingModule({
|
||||
imports: [
|
||||
MaterialModule
|
||||
],
|
||||
declarations: [
|
||||
CreateProcessAttachmentComponent
|
||||
],
|
||||
providers: [
|
||||
{ provide: TranslationService },
|
||||
ProcessContentService
|
||||
]
|
||||
}).compileComponents();
|
||||
}));
|
||||
|
||||
beforeEach(() => {
|
||||
fixture = TestBed.createComponent(CreateProcessAttachmentComponent);
|
||||
component = fixture.componentInstance;
|
||||
service = fixture.debugElement.injector.get(ProcessContentService);
|
||||
element = fixture.nativeElement;
|
||||
|
||||
component.processInstanceId = '9999';
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
beforeEach(() => {
|
||||
jasmine.Ajax.install();
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
jasmine.Ajax.uninstall();
|
||||
});
|
||||
|
||||
it('should update the processInstanceId when it is changed', () => {
|
||||
component.processInstanceId = null;
|
||||
|
||||
let change = new SimpleChange(null, '123', true);
|
||||
component.ngOnChanges({ 'processInstanceId': change });
|
||||
|
||||
expect(component.processInstanceId).toBe('123');
|
||||
});
|
||||
|
||||
it('should emit content created event when the file is uploaded', async(() => {
|
||||
component.success.subscribe((res) => {
|
||||
expect(res).toBeDefined();
|
||||
expect(res).not.toBeNull();
|
||||
expect(res.id).toBe(9999);
|
||||
});
|
||||
|
||||
component.onFileUpload(customEvent);
|
||||
|
||||
jasmine.Ajax.requests.mostRecent().respondWith({
|
||||
'status': 200,
|
||||
contentType: 'application/json',
|
||||
responseText: JSON.stringify(fakeUploadResponse)
|
||||
});
|
||||
}));
|
||||
|
||||
it('should allow user to upload files via button', async(() => {
|
||||
let buttonUpload: HTMLElement = <HTMLElement> element.querySelector('#add_new_process_content_button');
|
||||
expect(buttonUpload).toBeDefined();
|
||||
expect(buttonUpload).not.toBeNull();
|
||||
|
||||
component.success.subscribe((res) => {
|
||||
expect(res).toBeDefined();
|
||||
expect(res).not.toBeNull();
|
||||
expect(res.id).toBe(9999);
|
||||
});
|
||||
|
||||
let dropEvent = new CustomEvent('upload-files', customEvent);
|
||||
buttonUpload.dispatchEvent(dropEvent);
|
||||
fixture.detectChanges();
|
||||
|
||||
jasmine.Ajax.requests.mostRecent().respondWith({
|
||||
'status': 200,
|
||||
contentType: 'application/json',
|
||||
responseText: JSON.stringify(fakeUploadResponse)
|
||||
});
|
||||
}));
|
||||
|
||||
});
|
@@ -0,0 +1,63 @@
|
||||
/*!
|
||||
* @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, EventEmitter, Input, OnChanges, Output, SimpleChanges } from '@angular/core';
|
||||
import { ProcessContentService } from '@alfresco/core';
|
||||
|
||||
@Component({
|
||||
selector: 'adf-create-process-attachment',
|
||||
styleUrls: ['./create-process-attachment.component.css'],
|
||||
templateUrl: './create-process-attachment.component.html'
|
||||
})
|
||||
export class CreateProcessAttachmentComponent implements OnChanges {
|
||||
|
||||
@Input()
|
||||
processInstanceId: string;
|
||||
|
||||
@Output()
|
||||
error: EventEmitter<any> = new EventEmitter<any>();
|
||||
|
||||
@Output()
|
||||
success: EventEmitter<any> = new EventEmitter<any>();
|
||||
|
||||
constructor(private activitiContentService: ProcessContentService) {
|
||||
}
|
||||
|
||||
ngOnChanges(changes: SimpleChanges) {
|
||||
if (changes['processInstanceId'] && changes['processInstanceId'].currentValue) {
|
||||
this.processInstanceId = changes['processInstanceId'].currentValue;
|
||||
}
|
||||
}
|
||||
|
||||
onFileUpload(event: any) {
|
||||
let filesList: File[] = event.detail.files.map(obj => obj.file);
|
||||
|
||||
for (let fileInfoObj of filesList) {
|
||||
let file: File = fileInfoObj;
|
||||
let opts = {
|
||||
isRelatedContent: true
|
||||
};
|
||||
this.activitiContentService.createProcessRelatedContent(this.processInstanceId, file, opts).subscribe(
|
||||
(res) => {
|
||||
this.success.emit(res);
|
||||
},
|
||||
(err) => {
|
||||
this.error.emit(err);
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,12 @@
|
||||
<button
|
||||
color="primary"
|
||||
mat-button
|
||||
mat-raised-button
|
||||
mat-icon-button
|
||||
class="adf-create-attachment"
|
||||
[adf-upload]="true"
|
||||
mode="['click']"
|
||||
[multiple]="true"
|
||||
(upload-files)="onFileUpload($event)">
|
||||
<mat-icon>add</mat-icon>
|
||||
</button>
|
@@ -0,0 +1,5 @@
|
||||
.adf-create-attachment {
|
||||
display: inline-block;
|
||||
line-height: 0px;
|
||||
vertical-align: middle;
|
||||
}
|
@@ -0,0 +1,91 @@
|
||||
/*!
|
||||
* @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 { SimpleChange } from '@angular/core';
|
||||
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
import { MaterialModule } from '../material.module';
|
||||
import { Observable } from 'rxjs/Rx';
|
||||
|
||||
import { ProcessContentService } from '@alfresco/core';
|
||||
import { AttachmentComponent } from './create-task-attachment.component';
|
||||
|
||||
describe('Activiti Task Create Attachment', () => {
|
||||
|
||||
let service: ProcessContentService;
|
||||
let component: AttachmentComponent;
|
||||
let fixture: ComponentFixture<AttachmentComponent>;
|
||||
let createTaskRelatedContentSpy: jasmine.Spy;
|
||||
|
||||
beforeEach(async(() => {
|
||||
TestBed.configureTestingModule({
|
||||
imports: [
|
||||
MaterialModule
|
||||
],
|
||||
declarations: [
|
||||
AttachmentComponent
|
||||
],
|
||||
providers: [
|
||||
ProcessContentService
|
||||
]
|
||||
}).compileComponents();
|
||||
}));
|
||||
|
||||
beforeEach(() => {
|
||||
|
||||
fixture = TestBed.createComponent(AttachmentComponent);
|
||||
component = fixture.componentInstance;
|
||||
service = fixture.debugElement.injector.get(ProcessContentService);
|
||||
|
||||
createTaskRelatedContentSpy = spyOn(service, 'createTaskRelatedContent').and.returnValue(Observable.of(
|
||||
{
|
||||
status: true
|
||||
}));
|
||||
});
|
||||
|
||||
it('should not call createTaskRelatedContent service when taskId changed', () => {
|
||||
let change = new SimpleChange(null, '123', true);
|
||||
component.ngOnChanges({'taskId': change});
|
||||
expect(createTaskRelatedContentSpy).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should not call createTaskRelatedContent service when there is no file uploaded', () => {
|
||||
let change = new SimpleChange(null, '123', true);
|
||||
component.ngOnChanges({'taskId': change});
|
||||
let customEvent: any = {
|
||||
detail: {
|
||||
files: []
|
||||
}
|
||||
};
|
||||
component.onFileUpload(customEvent);
|
||||
expect(createTaskRelatedContentSpy).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should call createTaskRelatedContent service when there is a file uploaded', () => {
|
||||
let change = new SimpleChange(null, '123', true);
|
||||
component.ngOnChanges({'taskId': change});
|
||||
let file = new File([new Blob()], 'Test');
|
||||
let customEvent = {
|
||||
detail: {
|
||||
files: [
|
||||
file
|
||||
]
|
||||
}
|
||||
};
|
||||
component.onFileUpload(customEvent);
|
||||
expect(createTaskRelatedContentSpy).toHaveBeenCalled();
|
||||
});
|
||||
});
|
@@ -0,0 +1,64 @@
|
||||
/*!
|
||||
* @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, EventEmitter, Input, OnChanges, Output, SimpleChanges } from '@angular/core';
|
||||
import { ProcessContentService } from '@alfresco/core';
|
||||
|
||||
@Component({
|
||||
selector: 'adf-create-task-attachment',
|
||||
styleUrls: ['./create-task-attachment.component.scss'],
|
||||
templateUrl: './create-task-attachment.component.html'
|
||||
})
|
||||
export class AttachmentComponent implements OnChanges {
|
||||
|
||||
@Input()
|
||||
taskId: string;
|
||||
|
||||
@Output()
|
||||
error: EventEmitter<any> = new EventEmitter<any>();
|
||||
|
||||
@Output()
|
||||
success: EventEmitter<any> = new EventEmitter<any>();
|
||||
|
||||
constructor(private activitiContentService: ProcessContentService) {
|
||||
}
|
||||
|
||||
ngOnChanges(changes: SimpleChanges) {
|
||||
if (changes['taskId'] && changes['taskId'].currentValue) {
|
||||
this.taskId = changes['taskId'].currentValue;
|
||||
}
|
||||
}
|
||||
|
||||
onFileUpload(event: any) {
|
||||
let filesList: File[] = event.detail.files.map(obj => obj.file);
|
||||
|
||||
for (let fileInfoObj of filesList) {
|
||||
let file: File = fileInfoObj;
|
||||
let opts = {
|
||||
isRelatedContent: true
|
||||
};
|
||||
this.activitiContentService.createTaskRelatedContent(this.taskId, file, opts).subscribe(
|
||||
(res) => {
|
||||
this.success.emit(res);
|
||||
},
|
||||
(err) => {
|
||||
this.error.emit(err);
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
18
lib/process-services/attachment/index.ts
Normal file
18
lib/process-services/attachment/index.ts
Normal file
@@ -0,0 +1,18 @@
|
||||
/*!
|
||||
* @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.
|
||||
*/
|
||||
|
||||
export * from './public-api';
|
@@ -0,0 +1,29 @@
|
||||
<adf-datatable [rows]="attachments" [actions]="true" [loading]="isLoading" (rowDblClick)="openContent($event)" (showRowActionsMenu)="onShowRowActionsMenu($event)"
|
||||
(executeRowAction)="onExecuteRowAction($event)">
|
||||
|
||||
<adf-empty-list *ngIf="isEmpty()">
|
||||
<div adf-empty-list-header class="adf-empty-list-header"> {{'ADF_PROCESS_LIST.PROCESS-ATTACHMENT.EMPTY.HEADER' | translate}} </div>
|
||||
<div adf-empty-list-body *ngIf="!isDisabled()">
|
||||
<div fxHide.lt-md="true" class="adf-empty-list-drag_drop">{{'ADF_PROCESS_LIST.PROCESS-ATTACHMENT.EMPTY.DRAG-AND-DROP.TITLE' | translate}}</div>
|
||||
<div fxHide.lt-md="true" class="adf-empty-list__any-files-here-to-add"> {{'ADF_PROCESS_LIST.PROCESS-ATTACHMENT.EMPTY.DRAG-AND-DROP.SUBTITLE' | translate}} </div>
|
||||
</div>
|
||||
<div adf-empty-list-footer *ngIf="!isDisabled()">
|
||||
<img class="adf-empty-list__empty_doc_lib" [src]="emptyListImageUrl">
|
||||
</div>
|
||||
</adf-empty-list>
|
||||
|
||||
<data-columns>
|
||||
<data-column key="icon" type="icon" srTitle="Thumbnail" [sortable]="false"></data-column>
|
||||
<data-column key="name" type="text" title="{{'ADF_PROCESS_LIST.PROPERTIES.NAME' | translate}}" class="full-width ellipsis-cell" [sortable]="true"></data-column>
|
||||
<data-column key="created" type="date" format="shortDate" title="{{'ADF_PROCESS_LIST.PROPERTIES.CREATED' | translate}}"></data-column>
|
||||
</data-columns>
|
||||
|
||||
<loading-content-template>
|
||||
<ng-template>
|
||||
<!--Add your custom loading template here-->
|
||||
<mat-progress-spinner class="adf-attachment-list-loading-margin" [color]="'primary'" [mode]="'indeterminate'">
|
||||
</mat-progress-spinner>
|
||||
</ng-template>
|
||||
</loading-content-template>
|
||||
|
||||
</adf-datatable>
|
@@ -0,0 +1,58 @@
|
||||
@import '~@angular/material/theming';
|
||||
|
||||
adf-datatable ::ng-deep th span {
|
||||
color: #232323;
|
||||
}
|
||||
|
||||
adf-datatable ::ng-deep .data-cell {
|
||||
cursor: pointer !important;
|
||||
}
|
||||
|
||||
.adf-attachment-list-loading-margin {
|
||||
margin-left: calc((100% - 100px) / 2);
|
||||
margin-right: calc((100% - 100px) / 2);
|
||||
}
|
||||
|
||||
.adf-empty-list-header {
|
||||
height: 32px;
|
||||
opacity: 0.26 !important;
|
||||
font-size: 24px;
|
||||
line-height: 1.33;
|
||||
letter-spacing: -1px;
|
||||
color: #000000;
|
||||
}
|
||||
|
||||
.adf-empty-list-drag_drop {
|
||||
min-height: 56px;
|
||||
opacity: 0.54;
|
||||
font-size: 56px;
|
||||
line-height: 1;
|
||||
letter-spacing: -2px;
|
||||
color: #000000;
|
||||
margin-top: 40px !important;
|
||||
word-break: break-all;
|
||||
white-space: pre-line;
|
||||
}
|
||||
|
||||
.adf-empty-list__any-files-here-to-add {
|
||||
min-height: 24px;
|
||||
opacity: 0.54;
|
||||
font-size: 16px;
|
||||
line-height: 1.5;
|
||||
letter-spacing: -0.4px;
|
||||
color: #000000;
|
||||
margin-top: 17px;
|
||||
word-break: break-all;
|
||||
white-space: pre-line;
|
||||
}
|
||||
|
||||
.adf-empty-list__empty_doc_lib {
|
||||
width: 565px;
|
||||
height: 161px;
|
||||
object-fit: contain;
|
||||
margin-top: 17px;
|
||||
|
||||
@media screen and ($mat-xsmall) {
|
||||
width: 250px;
|
||||
}
|
||||
}
|
@@ -0,0 +1,313 @@
|
||||
/*!
|
||||
* @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 { NgZone, SimpleChange } from '@angular/core';
|
||||
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
import { MatProgressSpinnerModule } from '@angular/material';
|
||||
import { By } from '@angular/platform-browser';
|
||||
import { TranslateService } from '@ngx-translate/core';
|
||||
import { ProcessContentService } from '@alfresco/core';
|
||||
import { Observable } from 'rxjs/Rx';
|
||||
|
||||
import { ProcessAttachmentListComponent } from './process-attachment-list.component';
|
||||
|
||||
describe('ProcessAttachmentListComponent', () => {
|
||||
|
||||
let service: ProcessContentService;
|
||||
let component: ProcessAttachmentListComponent;
|
||||
let fixture: ComponentFixture<ProcessAttachmentListComponent>;
|
||||
let getProcessRelatedContentSpy: jasmine.Spy;
|
||||
let deleteContentSpy: jasmine.Spy;
|
||||
let getFileRawContentSpy: jasmine.Spy;
|
||||
let mockAttachment: any;
|
||||
|
||||
beforeEach(async(() => {
|
||||
let zone = new NgZone({enableLongStackTrace: false});
|
||||
TestBed.configureTestingModule({
|
||||
imports: [
|
||||
MatProgressSpinnerModule
|
||||
],
|
||||
declarations: [
|
||||
ProcessAttachmentListComponent
|
||||
],
|
||||
providers: [
|
||||
ProcessContentService,
|
||||
{ provide: NgZone, useValue: zone }
|
||||
]
|
||||
}).compileComponents();
|
||||
}));
|
||||
|
||||
beforeEach(() => {
|
||||
|
||||
fixture = TestBed.createComponent(ProcessAttachmentListComponent);
|
||||
component = fixture.componentInstance;
|
||||
service = fixture.debugElement.injector.get(ProcessContentService);
|
||||
|
||||
const translateService: TranslateService = TestBed.get(TranslateService);
|
||||
spyOn(translateService, 'get').and.callFake((key) => {
|
||||
return Observable.of(key);
|
||||
});
|
||||
|
||||
mockAttachment = {
|
||||
'size': 2,
|
||||
'total': 2,
|
||||
'start': 0,
|
||||
'data': [{
|
||||
'id': 4001,
|
||||
'name': 'Invoice01.pdf',
|
||||
'created': '2017-05-12T12:50:05.522+0000',
|
||||
'createdBy': {
|
||||
'id': 1,
|
||||
'firstName': 'Apps',
|
||||
'lastName': 'Administrator',
|
||||
'email': 'admin@app.activiti.com',
|
||||
'company': 'Alfresco.com',
|
||||
'pictureId': 3003
|
||||
},
|
||||
'relatedContent': true,
|
||||
'contentAvailable': true,
|
||||
'link': false,
|
||||
'mimeType': 'application/pdf',
|
||||
'simpleType': 'pdf',
|
||||
'previewStatus': 'created',
|
||||
'thumbnailStatus': 'created'
|
||||
},
|
||||
{
|
||||
'id': 4002,
|
||||
'name': 'Invoice02.pdf',
|
||||
'created': '2017-05-12T12:50:05.522+0000',
|
||||
'createdBy': {
|
||||
'id': 1,
|
||||
'firstName': 'Apps',
|
||||
'lastName': 'Administrator',
|
||||
'email': 'admin@app.activiti.com',
|
||||
'company': 'Alfresco.com',
|
||||
'pictureId': 3003
|
||||
},
|
||||
'relatedContent': true,
|
||||
'contentAvailable': true,
|
||||
'link': false,
|
||||
'mimeType': 'application/pdf',
|
||||
'simpleType': 'pdf',
|
||||
'previewStatus': 'created',
|
||||
'thumbnailStatus': 'created'
|
||||
}]
|
||||
};
|
||||
|
||||
getProcessRelatedContentSpy = spyOn(service, 'getProcessRelatedContent').and.returnValue(Observable.of(mockAttachment));
|
||||
|
||||
deleteContentSpy = spyOn(service, 'deleteRelatedContent').and.returnValue(Observable.of({successCode: true}));
|
||||
|
||||
let blobObj = new Blob();
|
||||
getFileRawContentSpy = spyOn(service, 'getFileRawContent').and.returnValue(Observable.of(
|
||||
blobObj
|
||||
));
|
||||
});
|
||||
|
||||
it('should load attachments when processInstanceId specified', () => {
|
||||
let change = new SimpleChange(null, '123', true);
|
||||
component.ngOnChanges({ 'processInstanceId': change });
|
||||
expect(getProcessRelatedContentSpy).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should emit an error when an error occurs loading attachments', () => {
|
||||
let emitSpy = spyOn(component.error, 'emit');
|
||||
getProcessRelatedContentSpy.and.returnValue(Observable.throw({}));
|
||||
let change = new SimpleChange(null, '123', true);
|
||||
component.ngOnChanges({ 'processInstanceId': change });
|
||||
expect(emitSpy).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should emit a success event when the attachments are loaded', () => {
|
||||
let change = new SimpleChange(null, '123', true);
|
||||
component.success.subscribe((attachments) => {
|
||||
expect(attachments[0].name).toEqual(mockAttachment.data[0].name);
|
||||
expect(attachments[0].id).toEqual(mockAttachment.data[0].id);
|
||||
});
|
||||
|
||||
component.ngOnChanges({'taskId': change});
|
||||
});
|
||||
|
||||
it('should not attach when no processInstanceId is specified', () => {
|
||||
fixture.detectChanges();
|
||||
expect(getProcessRelatedContentSpy).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should display attachments when the process has attachments', async(() => {
|
||||
let change = new SimpleChange(null, '123', true);
|
||||
component.ngOnChanges({ 'processInstanceId': change });
|
||||
|
||||
fixture.whenStable().then(() => {
|
||||
fixture.detectChanges();
|
||||
expect(fixture.debugElement.queryAll(By.css('adf-datatable tbody tr')).length).toBe(2);
|
||||
});
|
||||
}));
|
||||
|
||||
it('should display all actions if attachements are not read only', () => {
|
||||
let change = new SimpleChange(null, '123', true);
|
||||
component.ngOnChanges({ 'processInstanceId': change });
|
||||
|
||||
fixture.detectChanges();
|
||||
let actionButton = fixture.debugElement.nativeElement.querySelector('[data-automation-id="action_menu_0"]');
|
||||
actionButton.click();
|
||||
fixture.whenStable().then(() => {
|
||||
fixture.detectChanges();
|
||||
let actionMenu = fixture.debugElement.nativeElement.querySelectorAll('button.mat-menu-item').length;
|
||||
expect(fixture.debugElement.nativeElement.querySelector('[data-automation-id="View"]')).not.toBeNull();
|
||||
expect(fixture.debugElement.nativeElement.querySelector('[data-automation-id="Remove"]')).not.toBeNull();
|
||||
expect(actionMenu).toBe(3);
|
||||
});
|
||||
});
|
||||
|
||||
it('should not display remove action if attachments are read only', () => {
|
||||
let change = new SimpleChange(null, '123', true);
|
||||
component.ngOnChanges({ 'processInstanceId': change });
|
||||
component.disabled = true;
|
||||
|
||||
fixture.detectChanges();
|
||||
let actionButton = fixture.debugElement.nativeElement.querySelector('[data-automation-id="action_menu_0"]');
|
||||
actionButton.click();
|
||||
fixture.whenStable().then(() => {
|
||||
fixture.detectChanges();
|
||||
let actionMenu = fixture.debugElement.nativeElement.querySelectorAll('button.mat-menu-item').length;
|
||||
expect(fixture.debugElement.nativeElement.querySelector('[data-automation-id="View"]')).not.toBeNull();
|
||||
expect(fixture.debugElement.nativeElement.querySelector('[data-automation-id="Remove"]')).toBeNull();
|
||||
expect(actionMenu).toBe(2);
|
||||
});
|
||||
});
|
||||
|
||||
it('should show the empty list component when the attachments list is empty', async(() => {
|
||||
getProcessRelatedContentSpy.and.returnValue(Observable.of({
|
||||
'size': 0,
|
||||
'total': 0,
|
||||
'start': 0,
|
||||
'data': []
|
||||
}));
|
||||
let change = new SimpleChange(null, '123', true);
|
||||
component.ngOnChanges({'processInstanceId': change});
|
||||
fixture.whenStable().then(() => {
|
||||
fixture.detectChanges();
|
||||
expect(fixture.nativeElement.querySelector('div[adf-empty-list-header]').innerText.trim()).toEqual('ADF_PROCESS_LIST.PROCESS-ATTACHMENT.EMPTY.HEADER');
|
||||
});
|
||||
}));
|
||||
|
||||
it('should show the empty list drag and drop component when the process is not completed', async(() => {
|
||||
getProcessRelatedContentSpy.and.returnValue(Observable.of({
|
||||
'size': 0,
|
||||
'total': 0,
|
||||
'start': 0,
|
||||
'data': []
|
||||
}));
|
||||
let change = new SimpleChange(null, '123', true);
|
||||
component.ngOnChanges({'processInstanceId': change});
|
||||
fixture.whenStable().then(() => {
|
||||
fixture.detectChanges();
|
||||
expect(fixture.nativeElement.querySelector('adf-empty-list .adf-empty-list-drag_drop').innerText.trim())
|
||||
.toEqual('ADF_PROCESS_LIST.PROCESS-ATTACHMENT.EMPTY.DRAG-AND-DROP.TITLE');
|
||||
});
|
||||
}));
|
||||
|
||||
it('should not show the empty list drag and drop component when is disabled', async(() => {
|
||||
getProcessRelatedContentSpy.and.returnValue(Observable.of({
|
||||
'size': 0,
|
||||
'total': 0,
|
||||
'start': 0,
|
||||
'data': []
|
||||
}));
|
||||
let change = new SimpleChange(null, '123', true);
|
||||
component.ngOnChanges({'processInstanceId': change});
|
||||
component.disabled = true;
|
||||
|
||||
fixture.whenStable().then(() => {
|
||||
fixture.detectChanges();
|
||||
expect(fixture.nativeElement.querySelector('adf-empty-list .adf-empty-list-drag_drop')).toBeNull();
|
||||
expect(fixture.nativeElement.querySelector('div[adf-empty-list-header]').innerText.trim()).toEqual('ADF_PROCESS_LIST.PROCESS-ATTACHMENT.EMPTY.HEADER');
|
||||
});
|
||||
}));
|
||||
|
||||
it('should show the empty list component when the attachments list is empty for completed process', async(() => {
|
||||
getProcessRelatedContentSpy.and.returnValue(Observable.of({
|
||||
'size': 0,
|
||||
'total': 0,
|
||||
'start': 0,
|
||||
'data': []
|
||||
}));
|
||||
let change = new SimpleChange(null, '123', true);
|
||||
component.ngOnChanges({'processInstanceId': change});
|
||||
component.disabled = true;
|
||||
|
||||
fixture.whenStable().then(() => {
|
||||
fixture.detectChanges();
|
||||
expect(fixture.nativeElement.querySelector('div[adf-empty-list-header]').innerText.trim())
|
||||
.toEqual('ADF_PROCESS_LIST.PROCESS-ATTACHMENT.EMPTY.HEADER');
|
||||
});
|
||||
}));
|
||||
|
||||
it('should not show the empty list component when the attachments list is not empty for completed process', async(() => {
|
||||
getProcessRelatedContentSpy.and.returnValue(Observable.of(mockAttachment));
|
||||
let change = new SimpleChange(null, '123', true);
|
||||
component.ngOnChanges({'processInstanceId': change});
|
||||
component.disabled = true;
|
||||
|
||||
fixture.whenStable().then(() => {
|
||||
fixture.detectChanges();
|
||||
expect(fixture.nativeElement.querySelector('div[adf-empty-list-header]')).toBeNull();
|
||||
});
|
||||
}));
|
||||
|
||||
describe('change detection', () => {
|
||||
|
||||
let change = new SimpleChange('123', '456', true);
|
||||
let nullChange = new SimpleChange('123', null, true);
|
||||
|
||||
beforeEach(async(() => {
|
||||
component.processInstanceId = '123';
|
||||
fixture.whenStable().then(() => {
|
||||
getProcessRelatedContentSpy.calls.reset();
|
||||
});
|
||||
}));
|
||||
|
||||
it('should fetch new attachments when processInstanceId changed', () => {
|
||||
component.ngOnChanges({ 'processInstanceId': change });
|
||||
expect(getProcessRelatedContentSpy).toHaveBeenCalledWith('456');
|
||||
});
|
||||
|
||||
it('should NOT fetch new attachments when empty changeset made', () => {
|
||||
component.ngOnChanges({});
|
||||
expect(getProcessRelatedContentSpy).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should NOT fetch new attachments when processInstanceId changed to null', () => {
|
||||
component.ngOnChanges({ 'processInstanceId': nullChange });
|
||||
expect(getProcessRelatedContentSpy).not.toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
|
||||
describe('Delete attachments', () => {
|
||||
|
||||
beforeEach(async(() => {
|
||||
component.processInstanceId = '123';
|
||||
fixture.whenStable();
|
||||
}));
|
||||
|
||||
it('should display a dialog to the user when the Add button clicked', () => {
|
||||
expect(true).toBe(true);
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
});
|
@@ -0,0 +1,196 @@
|
||||
/*!
|
||||
* @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 { ContentService, ThumbnailService } from '@alfresco/core';
|
||||
import { Component, EventEmitter, Input, NgZone, OnChanges, Output, SimpleChanges } from '@angular/core';
|
||||
import { ProcessContentService } from '@alfresco/core';
|
||||
|
||||
declare var require: any;
|
||||
|
||||
@Component({
|
||||
selector: 'adf-process-attachment-list',
|
||||
styleUrls: ['./process-attachment-list.component.scss'],
|
||||
templateUrl: './process-attachment-list.component.html'
|
||||
})
|
||||
export class ProcessAttachmentListComponent implements OnChanges {
|
||||
|
||||
@Input()
|
||||
processInstanceId: string;
|
||||
|
||||
@Input()
|
||||
disabled: boolean = false;
|
||||
|
||||
@Output()
|
||||
attachmentClick = new EventEmitter();
|
||||
|
||||
@Output()
|
||||
success = new EventEmitter();
|
||||
|
||||
@Output()
|
||||
error: EventEmitter<any> = new EventEmitter<any>();
|
||||
|
||||
@Input()
|
||||
emptyListImageUrl: string = require('../assets/images/empty_doc_lib.svg');
|
||||
|
||||
attachments: any[] = [];
|
||||
isLoading: boolean = true;
|
||||
|
||||
constructor(private activitiContentService: ProcessContentService,
|
||||
private contentService: ContentService,
|
||||
private thumbnailService: ThumbnailService,
|
||||
private ngZone: NgZone) {
|
||||
}
|
||||
|
||||
ngOnChanges(changes: SimpleChanges) {
|
||||
if (changes['processInstanceId'] && changes['processInstanceId'].currentValue) {
|
||||
this.loadAttachmentsByProcessInstanceId(changes['processInstanceId'].currentValue);
|
||||
}
|
||||
}
|
||||
|
||||
reset() {
|
||||
this.attachments = [];
|
||||
}
|
||||
|
||||
reload(): void {
|
||||
this.ngZone.run(() => {
|
||||
this.loadAttachmentsByProcessInstanceId(this.processInstanceId);
|
||||
});
|
||||
}
|
||||
|
||||
add(content: any): void {
|
||||
this.ngZone.run(() => {
|
||||
this.attachments.push({
|
||||
id: content.id,
|
||||
name: content.name,
|
||||
created: content.created,
|
||||
createdBy: content.createdBy.firstName + ' ' + content.createdBy.lastName,
|
||||
icon: this.thumbnailService.getMimeTypeIcon(content.mimeType)
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
private loadAttachmentsByProcessInstanceId(processInstanceId: string) {
|
||||
if (processInstanceId) {
|
||||
this.reset();
|
||||
this.isLoading = true;
|
||||
this.activitiContentService.getProcessRelatedContent(processInstanceId).subscribe(
|
||||
(res: any) => {
|
||||
res.data.forEach(content => {
|
||||
this.attachments.push({
|
||||
id: content.id,
|
||||
name: content.name,
|
||||
created: content.created,
|
||||
createdBy: content.createdBy.firstName + ' ' + content.createdBy.lastName,
|
||||
icon: this.thumbnailService.getMimeTypeIcon(content.mimeType)
|
||||
});
|
||||
});
|
||||
this.success.emit(this.attachments);
|
||||
this.isLoading = false;
|
||||
},
|
||||
(err) => {
|
||||
this.error.emit(err);
|
||||
this.isLoading = false;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
private deleteAttachmentById(contentId: number) {
|
||||
if (contentId) {
|
||||
this.activitiContentService.deleteRelatedContent(contentId).subscribe(
|
||||
(res: any) => {
|
||||
this.attachments = this.attachments.filter(content => {
|
||||
return content.id !== contentId;
|
||||
});
|
||||
},
|
||||
(err) => {
|
||||
this.error.emit(err);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
isEmpty(): boolean {
|
||||
return this.attachments && this.attachments.length === 0;
|
||||
}
|
||||
|
||||
onShowRowActionsMenu(event: any) {
|
||||
let viewAction = {
|
||||
title: 'ADF_PROCESS_LIST.MENU_ACTIONS.VIEW_CONTENT',
|
||||
name: 'view'
|
||||
};
|
||||
|
||||
let removeAction = {
|
||||
title: 'ADF_PROCESS_LIST.MENU_ACTIONS.REMOVE_CONTENT',
|
||||
name: 'remove'
|
||||
};
|
||||
|
||||
let downloadAction = {
|
||||
title: 'ADF_PROCESS_LIST.MENU_ACTIONS.DOWNLOAD_CONTENT',
|
||||
name: 'download'
|
||||
};
|
||||
|
||||
event.value.actions = [
|
||||
viewAction,
|
||||
downloadAction
|
||||
];
|
||||
|
||||
if (!this.disabled) {
|
||||
event.value.actions.splice(1, 0, removeAction);
|
||||
}
|
||||
}
|
||||
|
||||
onExecuteRowAction(event: any) {
|
||||
let args = event.value;
|
||||
let action = args.action;
|
||||
if (action.name === 'view') {
|
||||
this.emitDocumentContent(args.row.obj);
|
||||
} else if (action.name === 'remove') {
|
||||
this.deleteAttachmentById(args.row.obj.id);
|
||||
} else if (action.name === 'download') {
|
||||
this.downloadContent(args.row.obj);
|
||||
}
|
||||
}
|
||||
|
||||
openContent(event: any): void {
|
||||
let content = event.value.obj;
|
||||
this.emitDocumentContent(content);
|
||||
}
|
||||
|
||||
emitDocumentContent(content: any) {
|
||||
this.activitiContentService.getFileRawContent(content.id).subscribe(
|
||||
(blob: Blob) => {
|
||||
content.contentBlob = blob;
|
||||
this.attachmentClick.emit(content);
|
||||
},
|
||||
(err) => {
|
||||
this.error.emit(err);
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
downloadContent(content: any): void {
|
||||
this.activitiContentService.getFileRawContent(content.id).subscribe(
|
||||
(blob: Blob) => this.contentService.downloadBlob(blob, content.name),
|
||||
(err) => {
|
||||
this.error.emit(err);
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
isDisabled(): boolean {
|
||||
return this.disabled;
|
||||
}
|
||||
}
|
23
lib/process-services/attachment/public-api.ts
Normal file
23
lib/process-services/attachment/public-api.ts
Normal file
@@ -0,0 +1,23 @@
|
||||
/*!
|
||||
* @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.
|
||||
*/
|
||||
|
||||
export * from './task-attachment-list.component';
|
||||
export * from './process-attachment-list.component';
|
||||
export * from './create-process-attachment.component';
|
||||
export * from './create-task-attachment.component';
|
||||
|
||||
export * from './attachment.module';
|
@@ -0,0 +1,25 @@
|
||||
<adf-datatable [rows]="attachments" [actions]="true" [loading]="isLoading" (rowDblClick)="openContent($event)" (showRowActionsMenu)="onShowRowActionsMenu($event)"
|
||||
(executeRowAction)="onExecuteRowAction($event)">
|
||||
<adf-empty-list *ngIf="isEmpty()">
|
||||
<div adf-empty-list-header class="adf-empty-list-header"> {{'ADF_TASK_LIST.ATTACHMENT.EMPTY.HEADER' | translate}} </div>
|
||||
<div adf-empty-list-body *ngIf="!isDisabled()">
|
||||
<div fxHide.lt-md="true" class="adf-empty-list-drag_drop">{{'ADF_TASK_LIST.ATTACHMENT.EMPTY.DRAG-AND-DROP.TITLE' | translate}}</div>
|
||||
<div fxHide.lt-md="true" class="adf-empty-list__any-files-here-to-add"> {{'ADF_TASK_LIST.ATTACHMENT.EMPTY.DRAG-AND-DROP.SUBTITLE' | translate}} </div>
|
||||
</div>
|
||||
<div adf-empty-list-footer *ngIf="!isDisabled()">
|
||||
<img class="adf-empty-list__empty_doc_lib" [src]="emptyListImageUrl">
|
||||
</div>
|
||||
</adf-empty-list>
|
||||
<data-columns>
|
||||
<data-column key="icon" type="icon" srTitle="ADF_TASK_LIST.PROPERTIES.THUMBNAIL" [sortable]="false"></data-column>
|
||||
<data-column key="name" type="text" title="ADF_TASK_LIST.PROPERTIES.NAME" class="full-width ellipsis-cell" [sortable]="true"></data-column>
|
||||
<data-column key="created" type="date" format="shortDate" title="ADF_TASK_LIST.PROPERTIES.CREATED"></data-column>
|
||||
</data-columns>
|
||||
<loading-content-template>
|
||||
<ng-template>
|
||||
<!--Add your custom loading template here-->
|
||||
<mat-progress-spinner class="adf-attachment-list-loading-margin" [color]="'primary'" [mode]="'indeterminate'">
|
||||
</mat-progress-spinner>
|
||||
</ng-template>
|
||||
</loading-content-template>
|
||||
</adf-datatable>
|
@@ -0,0 +1,63 @@
|
||||
@import '~@angular/material/theming';
|
||||
|
||||
adf-datatable ::ng-deep th span {
|
||||
color: #232323;
|
||||
}
|
||||
|
||||
adf-datatable ::ng-deep .data-cell {
|
||||
cursor: pointer !important;
|
||||
}
|
||||
|
||||
.adf-attachment-list-loading-margin {
|
||||
margin-left: calc((100% - 100px) / 2);
|
||||
margin-right: calc((100% - 100px) / 2);
|
||||
}
|
||||
|
||||
.adf-empty-list-header {
|
||||
height: 32px;
|
||||
opacity: 0.26;
|
||||
font-size: 24px;
|
||||
line-height: 1.33;
|
||||
letter-spacing: -1px;
|
||||
color: #000000;
|
||||
}
|
||||
|
||||
.adf-empty-list-drag_drop {
|
||||
min-height: 56px;
|
||||
opacity: 0.54;
|
||||
font-size: 56px;
|
||||
line-height: 1;
|
||||
letter-spacing: -2px;
|
||||
color: #000000;
|
||||
margin-top: 40px;
|
||||
word-break: break-all;
|
||||
white-space: pre-line;
|
||||
|
||||
@media screen and ($mat-xsmall) {
|
||||
font-size: 40px;
|
||||
}
|
||||
}
|
||||
|
||||
.adf-empty-list__any-files-here-to-add {
|
||||
min-height: 24px;
|
||||
opacity: 0.54;
|
||||
font-size: 16px;
|
||||
line-height: 1.5;
|
||||
letter-spacing: -0.4px;
|
||||
color: #000000;
|
||||
margin-top: 17px;
|
||||
word-break: break-all;
|
||||
white-space: pre-line;
|
||||
}
|
||||
|
||||
.adf-empty-list__empty_doc_lib {
|
||||
width: 565px;
|
||||
max-width: 100%;
|
||||
height: 161px;
|
||||
object-fit: contain;
|
||||
margin-top: 17px;
|
||||
|
||||
@media screen and ($mat-xsmall) {
|
||||
width: 250px;
|
||||
}
|
||||
}
|
@@ -0,0 +1,296 @@
|
||||
/*!
|
||||
* @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 { SimpleChange } from '@angular/core';
|
||||
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
import { By } from '@angular/platform-browser';
|
||||
import { MaterialModule } from '../material.module';
|
||||
import { Observable } from 'rxjs/Rx';
|
||||
import { TaskAttachmentListComponent } from './task-attachment-list.component';
|
||||
import { ProcessContentService } from '@alfresco/core';
|
||||
|
||||
describe('TaskAttachmentList', () => {
|
||||
|
||||
let component: TaskAttachmentListComponent;
|
||||
let fixture: ComponentFixture<TaskAttachmentListComponent>;
|
||||
let service: ProcessContentService;
|
||||
let getTaskRelatedContentSpy: jasmine.Spy;
|
||||
let deleteContentSpy: jasmine.Spy;
|
||||
let getFileRawContentSpy: jasmine.Spy;
|
||||
let mockAttachment: any;
|
||||
|
||||
beforeEach(async(() => {
|
||||
TestBed.configureTestingModule({
|
||||
imports: [
|
||||
MaterialModule
|
||||
],
|
||||
declarations: [
|
||||
TaskAttachmentListComponent
|
||||
],
|
||||
providers: [
|
||||
ProcessContentService
|
||||
]
|
||||
}).compileComponents();
|
||||
|
||||
}));
|
||||
|
||||
beforeEach(() => {
|
||||
|
||||
fixture = TestBed.createComponent(TaskAttachmentListComponent);
|
||||
component = fixture.componentInstance;
|
||||
|
||||
service = TestBed.get(ProcessContentService);
|
||||
|
||||
mockAttachment = {
|
||||
size: 2,
|
||||
total: 2,
|
||||
start: 0,
|
||||
data: [
|
||||
{
|
||||
id: 8,
|
||||
name: 'fake.zip',
|
||||
created: 1494595697381,
|
||||
createdBy: {id: 2, firstName: 'user', lastName: 'user', email: 'user@user.com'},
|
||||
relatedContent: true,
|
||||
contentAvailable: true,
|
||||
link: false,
|
||||
mimeType: 'application/zip',
|
||||
simpleType: 'content',
|
||||
previewStatus: 'unsupported',
|
||||
thumbnailStatus: 'unsupported'
|
||||
},
|
||||
{
|
||||
id: 9,
|
||||
name: 'fake.jpg',
|
||||
created: 1494595655381,
|
||||
createdBy: {id: 2, firstName: 'user', lastName: 'user', email: 'user@user.com'},
|
||||
relatedContent: true,
|
||||
contentAvailable: true,
|
||||
link: false,
|
||||
mimeType: 'image/jpeg',
|
||||
simpleType: 'image',
|
||||
previewStatus: 'unsupported',
|
||||
thumbnailStatus: 'unsupported'
|
||||
}
|
||||
]
|
||||
};
|
||||
|
||||
getTaskRelatedContentSpy = spyOn(service, 'getTaskRelatedContent').and.returnValue(Observable.of(
|
||||
mockAttachment
|
||||
));
|
||||
|
||||
deleteContentSpy = spyOn(service, 'deleteRelatedContent').and.returnValue(Observable.of({successCode: true}));
|
||||
|
||||
let blobObj = new Blob();
|
||||
getFileRawContentSpy = spyOn(service, 'getFileRawContent').and.returnValue(Observable.of(
|
||||
blobObj
|
||||
));
|
||||
|
||||
});
|
||||
|
||||
it('should load attachments when taskId specified', () => {
|
||||
let change = new SimpleChange(null, '123', true);
|
||||
component.ngOnChanges({'taskId': change});
|
||||
expect(getTaskRelatedContentSpy).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should emit an error when an error occurs loading attachments', () => {
|
||||
let emitSpy = spyOn(component.error, 'emit');
|
||||
getTaskRelatedContentSpy.and.returnValue(Observable.throw({}));
|
||||
let change = new SimpleChange(null, '123', true);
|
||||
component.ngOnChanges({'taskId': change});
|
||||
expect(emitSpy).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should emit a success event when the attachments are loaded', () => {
|
||||
let change = new SimpleChange(null, '123', true);
|
||||
component.success.subscribe((attachments) => {
|
||||
expect(attachments[0].name).toEqual(mockAttachment.data[0].name);
|
||||
expect(attachments[0].id).toEqual(mockAttachment.data[0].id);
|
||||
});
|
||||
|
||||
component.ngOnChanges({'taskId': change});
|
||||
});
|
||||
|
||||
it('should not attach when no taskId is specified', () => {
|
||||
fixture.detectChanges();
|
||||
expect(getTaskRelatedContentSpy).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should display attachments when the task has attachments', async(() => {
|
||||
let change = new SimpleChange(null, '123', true);
|
||||
component.ngOnChanges({'taskId': change});
|
||||
|
||||
fixture.whenStable().then(() => {
|
||||
fixture.detectChanges();
|
||||
expect(fixture.debugElement.queryAll(By.css('adf-datatable tbody tr')).length).toBe(2);
|
||||
});
|
||||
}));
|
||||
|
||||
it('should display all actions if attachements are not read only', () => {
|
||||
let change = new SimpleChange(null, '123', true);
|
||||
component.ngOnChanges({'taskId': change});
|
||||
fixture.detectChanges();
|
||||
|
||||
let actionButton = fixture.debugElement.nativeElement.querySelector('[data-automation-id="action_menu_0"]');
|
||||
actionButton.click();
|
||||
fixture.whenStable().then(() => {
|
||||
fixture.detectChanges();
|
||||
let actionMenu = fixture.debugElement.nativeElement.querySelectorAll('button.mat-menu-item').length;
|
||||
expect(fixture.debugElement.nativeElement.querySelector('[data-automation-id="View"]')).not.toBeNull();
|
||||
expect(fixture.debugElement.nativeElement.querySelector('[data-automation-id="Remove"]')).not.toBeNull();
|
||||
expect(actionMenu).toBe(3);
|
||||
});
|
||||
});
|
||||
|
||||
it('should not display remove action if attachments are read only', () => {
|
||||
let change = new SimpleChange(null, '123', true);
|
||||
component.ngOnChanges({'taskId': change});
|
||||
component.disabled = true;
|
||||
fixture.detectChanges();
|
||||
|
||||
let actionButton = fixture.debugElement.nativeElement.querySelector('[data-automation-id="action_menu_0"]');
|
||||
actionButton.click();
|
||||
fixture.whenStable().then(() => {
|
||||
fixture.detectChanges();
|
||||
let actionMenu = fixture.debugElement.nativeElement.querySelectorAll('button.mat-menu-item').length;
|
||||
expect(fixture.debugElement.nativeElement.querySelector('[data-automation-id="View"]')).not.toBeNull();
|
||||
expect(fixture.debugElement.nativeElement.querySelector('[data-automation-id="Remove"]')).toBeNull();
|
||||
expect(actionMenu).toBe(2);
|
||||
});
|
||||
});
|
||||
|
||||
it('should show the empty list component when the attachments list is empty', async(() => {
|
||||
getTaskRelatedContentSpy.and.returnValue(Observable.of({
|
||||
'size': 0,
|
||||
'total': 0,
|
||||
'start': 0,
|
||||
'data': []
|
||||
}));
|
||||
let change = new SimpleChange(null, '123', true);
|
||||
component.ngOnChanges({'taskId': change});
|
||||
|
||||
fixture.whenStable().then(() => {
|
||||
fixture.detectChanges();
|
||||
expect(fixture.nativeElement.querySelector('div[adf-empty-list-header]').innerText.trim()).toEqual('ADF_TASK_LIST.ATTACHMENT.EMPTY.HEADER');
|
||||
});
|
||||
}));
|
||||
|
||||
it('should show the empty list drag and drop component when the task is not completed', async(() => {
|
||||
getTaskRelatedContentSpy.and.returnValue(Observable.of({
|
||||
'size': 0,
|
||||
'total': 0,
|
||||
'start': 0,
|
||||
'data': []
|
||||
}));
|
||||
let change = new SimpleChange(null, '123', true);
|
||||
component.ngOnChanges({'taskId': change});
|
||||
|
||||
fixture.whenStable().then(() => {
|
||||
fixture.detectChanges();
|
||||
expect(fixture.nativeElement.querySelector('adf-empty-list .adf-empty-list-drag_drop').innerText.trim()).toEqual('ADF_TASK_LIST.ATTACHMENT.EMPTY.DRAG-AND-DROP.TITLE');
|
||||
});
|
||||
}));
|
||||
|
||||
it('should not show the empty list drag and drop component when is disabled', async(() => {
|
||||
getTaskRelatedContentSpy.and.returnValue(Observable.of({
|
||||
'size': 0,
|
||||
'total': 0,
|
||||
'start': 0,
|
||||
'data': []
|
||||
}));
|
||||
let change = new SimpleChange(null, '123', true);
|
||||
component.ngOnChanges({'taskId': change});
|
||||
component.disabled = true;
|
||||
|
||||
fixture.whenStable().then(() => {
|
||||
fixture.detectChanges();
|
||||
expect(fixture.nativeElement.querySelector('adf-empty-list .adf-empty-list-drag_drop')).toBeNull();
|
||||
expect(fixture.nativeElement.querySelector('div[adf-empty-list-header]').innerText.trim()).toEqual('ADF_TASK_LIST.ATTACHMENT.EMPTY.HEADER');
|
||||
});
|
||||
}));
|
||||
|
||||
it('should show the empty list component when the attachments list is empty for completed task', async(() => {
|
||||
getTaskRelatedContentSpy.and.returnValue(Observable.of({
|
||||
'size': 0,
|
||||
'total': 0,
|
||||
'start': 0,
|
||||
'data': []
|
||||
}));
|
||||
let change = new SimpleChange(null, '123', true);
|
||||
component.ngOnChanges({'taskId': change});
|
||||
component.disabled = true;
|
||||
|
||||
fixture.whenStable().then(() => {
|
||||
fixture.detectChanges();
|
||||
expect(fixture.nativeElement.querySelector('div[adf-empty-list-header]').innerText.trim()).toEqual('ADF_TASK_LIST.ATTACHMENT.EMPTY.HEADER');
|
||||
});
|
||||
}));
|
||||
|
||||
it('should not show the empty list component when the attachments list is not empty for completed task', async(() => {
|
||||
getTaskRelatedContentSpy.and.returnValue(Observable.of(mockAttachment));
|
||||
let change = new SimpleChange(null, '123', true);
|
||||
component.ngOnChanges({'taskId': change});
|
||||
component.disabled = true;
|
||||
|
||||
fixture.whenStable().then(() => {
|
||||
fixture.detectChanges();
|
||||
expect(fixture.nativeElement.querySelector('div[adf-empty-list-header]')).toBeNull();
|
||||
});
|
||||
}));
|
||||
|
||||
describe('change detection', () => {
|
||||
|
||||
let change = new SimpleChange('123', '456', true);
|
||||
let nullChange = new SimpleChange('123', null, true);
|
||||
|
||||
beforeEach(async(() => {
|
||||
component.taskId = '123';
|
||||
fixture.whenStable().then(() => {
|
||||
getTaskRelatedContentSpy.calls.reset();
|
||||
});
|
||||
}));
|
||||
|
||||
it('should fetch new attachments when taskId changed', () => {
|
||||
component.ngOnChanges({'taskId': change});
|
||||
expect(getTaskRelatedContentSpy).toHaveBeenCalledWith('456');
|
||||
});
|
||||
|
||||
it('should NOT fetch new attachments when empty changeset made', () => {
|
||||
component.ngOnChanges({});
|
||||
expect(getTaskRelatedContentSpy).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should NOT fetch new attachments when taskId changed to null', () => {
|
||||
component.ngOnChanges({'taskId': nullChange});
|
||||
expect(getTaskRelatedContentSpy).not.toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
|
||||
describe('Delete attachments', () => {
|
||||
|
||||
beforeEach(async(() => {
|
||||
component.taskId = '123';
|
||||
fixture.whenStable();
|
||||
}));
|
||||
|
||||
it('should display a dialog to the user when the Add button clicked', () => {
|
||||
expect(true).toBe(true);
|
||||
});
|
||||
|
||||
});
|
||||
});
|
@@ -0,0 +1,198 @@
|
||||
/*!
|
||||
* @license
|
||||
* Copyright 2016 Alfresco Software, Ltd.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { ContentService, ThumbnailService } from '@alfresco/core';
|
||||
import { Component, EventEmitter, Input, NgZone, OnChanges, Output, SimpleChanges } from '@angular/core';
|
||||
import { ProcessContentService } from '@alfresco/core';
|
||||
|
||||
declare var require: any;
|
||||
|
||||
@Component({
|
||||
selector: 'adf-task-attachment-list',
|
||||
styleUrls: ['./task-attachment-list.component.scss'],
|
||||
templateUrl: './task-attachment-list.component.html'
|
||||
})
|
||||
export class TaskAttachmentListComponent implements OnChanges {
|
||||
|
||||
@Input()
|
||||
taskId: string;
|
||||
|
||||
@Input()
|
||||
disabled: boolean = false;
|
||||
|
||||
@Output()
|
||||
attachmentClick = new EventEmitter();
|
||||
|
||||
@Output()
|
||||
success = new EventEmitter();
|
||||
|
||||
@Output()
|
||||
error: EventEmitter<any> = new EventEmitter<any>();
|
||||
|
||||
@Input()
|
||||
emptyListImageUrl: string = require('../assets/images/empty_doc_lib.svg');
|
||||
|
||||
attachments: any[] = [];
|
||||
isLoading: boolean = true;
|
||||
|
||||
constructor(private activitiContentService: ProcessContentService,
|
||||
private contentService: ContentService,
|
||||
private thumbnailService: ThumbnailService,
|
||||
private ngZone: NgZone) {
|
||||
}
|
||||
|
||||
ngOnChanges(changes: SimpleChanges) {
|
||||
if (changes['taskId'] && changes['taskId'].currentValue) {
|
||||
this.loadAttachmentsByTaskId(changes['taskId'].currentValue);
|
||||
}
|
||||
}
|
||||
|
||||
reset(): void {
|
||||
this.attachments = [];
|
||||
}
|
||||
|
||||
reload(): void {
|
||||
this.ngZone.run(() => {
|
||||
this.loadAttachmentsByTaskId(this.taskId);
|
||||
});
|
||||
}
|
||||
|
||||
add(content: any): void {
|
||||
this.ngZone.run(() => {
|
||||
this.attachments.push({
|
||||
id: content.id,
|
||||
name: content.name,
|
||||
created: content.created,
|
||||
createdBy: content.createdBy.firstName + ' ' + content.createdBy.lastName,
|
||||
icon: this.thumbnailService.getMimeTypeIcon(content.mimeType)
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
private loadAttachmentsByTaskId(taskId: string) {
|
||||
if (taskId) {
|
||||
this.isLoading = true;
|
||||
this.reset();
|
||||
this.activitiContentService.getTaskRelatedContent(taskId).subscribe(
|
||||
(res: any) => {
|
||||
let attachList = [];
|
||||
res.data.forEach(content => {
|
||||
attachList.push({
|
||||
id: content.id,
|
||||
name: content.name,
|
||||
created: content.created,
|
||||
createdBy: content.createdBy.firstName + ' ' + content.createdBy.lastName,
|
||||
icon: this.thumbnailService.getMimeTypeIcon(content.mimeType)
|
||||
});
|
||||
});
|
||||
this.attachments = attachList;
|
||||
this.success.emit(this.attachments);
|
||||
this.isLoading = false;
|
||||
},
|
||||
(err) => {
|
||||
this.error.emit(err);
|
||||
this.isLoading = false;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
private deleteAttachmentById(contentId: number) {
|
||||
if (contentId) {
|
||||
this.activitiContentService.deleteRelatedContent(contentId).subscribe(
|
||||
(res: any) => {
|
||||
this.attachments = this.attachments.filter(content => {
|
||||
return content.id !== contentId;
|
||||
});
|
||||
},
|
||||
(err) => {
|
||||
this.error.emit(err);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
isEmpty(): boolean {
|
||||
return this.attachments && this.attachments.length === 0;
|
||||
}
|
||||
|
||||
onShowRowActionsMenu(event: any) {
|
||||
let viewAction = {
|
||||
title: 'ADF_TASK_LIST.MENU_ACTIONS.VIEW_CONTENT',
|
||||
name: 'view'
|
||||
};
|
||||
|
||||
let removeAction = {
|
||||
title: 'ADF_TASK_LIST.MENU_ACTIONS.REMOVE_CONTENT',
|
||||
name: 'remove'
|
||||
};
|
||||
|
||||
let downloadAction = {
|
||||
title: 'ADF_TASK_LIST.MENU_ACTIONS.DOWNLOAD_CONTENT',
|
||||
name: 'download'
|
||||
};
|
||||
|
||||
event.value.actions = [
|
||||
viewAction,
|
||||
downloadAction
|
||||
];
|
||||
|
||||
if (!this.disabled) {
|
||||
event.value.actions.splice(1, 0, removeAction);
|
||||
}
|
||||
}
|
||||
|
||||
onExecuteRowAction(event: any) {
|
||||
let args = event.value;
|
||||
let action = args.action;
|
||||
if (action.name === 'view') {
|
||||
this.emitDocumentContent(args.row.obj);
|
||||
} else if (action.name === 'remove') {
|
||||
this.deleteAttachmentById(args.row.obj.id);
|
||||
} else if (action.name === 'download') {
|
||||
this.downloadContent(args.row.obj);
|
||||
}
|
||||
}
|
||||
|
||||
openContent(event: any): void {
|
||||
let content = event.value.obj;
|
||||
this.emitDocumentContent(content);
|
||||
}
|
||||
|
||||
emitDocumentContent(content: any) {
|
||||
this.activitiContentService.getFileRawContent(content.id).subscribe(
|
||||
(blob: Blob) => {
|
||||
content.contentBlob = blob;
|
||||
this.attachmentClick.emit(content);
|
||||
},
|
||||
(err) => {
|
||||
this.error.emit(err);
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
downloadContent(content: any): void {
|
||||
this.activitiContentService.getFileRawContent(content.id).subscribe(
|
||||
(blob: Blob) => this.contentService.downloadBlob(blob, content.name),
|
||||
(err) => {
|
||||
this.error.emit(err);
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
isDisabled(): boolean {
|
||||
return this.disabled;
|
||||
}
|
||||
}
|
37
lib/process-services/comments/comment-list.component.html
Normal file
37
lib/process-services/comments/comment-list.component.html
Normal file
@@ -0,0 +1,37 @@
|
||||
<adf-datatable
|
||||
[rows]="comments"
|
||||
(rowClick)="selectComment($event)" *ngIf="hasComments()">
|
||||
|
||||
<data-columns>
|
||||
<data-column key="createdBy" title="{{'ADF_TASK_LIST.DETAILS.COMMENTS.CREATED_BY_HEADER' | translate }}">
|
||||
<ng-template let-entry="$implicit">
|
||||
<div id="comment-user-icon"
|
||||
class="adf-comment-img-container">
|
||||
<div
|
||||
*ngIf="!entry.row.obj.createdBy.pictureId" class="adf-comment-user-icon">
|
||||
{{getUserShortName(entry.row.obj.createdBy)}}</div>
|
||||
<div>
|
||||
<img *ngIf="entry.row.obj.createdBy.pictureId" class="adf-people-img"
|
||||
[src]="peopleProcessService.getUserImage(entry.row.obj.createdBy)"/>
|
||||
</div>
|
||||
</div>
|
||||
</ng-template>
|
||||
</data-column>
|
||||
<data-column key="message" title="{{'ADF_TASK_LIST.DETAILS.COMMENTS.MESSAGE_HEADER' | translate }}">
|
||||
<ng-template let-entry="$implicit">
|
||||
<div class="adf-comment-contents">
|
||||
<div id="comment-user" class="adf-comment-user-name">
|
||||
{{entry.row.obj.createdBy?.firstName}} {{entry.row.obj.createdBy?.lastName}}
|
||||
</div>
|
||||
<div id="comment-message" class="adf-comment-message">
|
||||
{{entry.row.obj.message}}
|
||||
</div>
|
||||
<div id="comment-time" class="adf-comment-message-time">
|
||||
{{transformDate(entry.row.obj.created)}}
|
||||
</div>
|
||||
</div>
|
||||
</ng-template>
|
||||
</data-column>
|
||||
</data-columns>
|
||||
|
||||
</adf-datatable>
|
74
lib/process-services/comments/comment-list.component.scss
Normal file
74
lib/process-services/comments/comment-list.component.scss
Normal file
@@ -0,0 +1,74 @@
|
||||
@mixin adf-task-list-comment-list-theme($theme) {
|
||||
$primary: map-get($theme, primary);
|
||||
|
||||
.adf {
|
||||
|
||||
&-comment-img-container {
|
||||
float: left;
|
||||
width: 40px;
|
||||
padding: 5px 10px;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
&-comment-user-icon {
|
||||
padding: 10px 5px;
|
||||
width: 30px;
|
||||
background-color: mat-color($primary);
|
||||
border-radius: 50%;
|
||||
font-size: 16px;
|
||||
color: #fff;
|
||||
text-align: center;
|
||||
height: 18px;
|
||||
background-size: cover;
|
||||
}
|
||||
|
||||
&-comment-user-name {
|
||||
float: left;
|
||||
width: calc(100% - 120px);
|
||||
padding: 2px 10px;
|
||||
font-weight: 600;
|
||||
color: #595959;
|
||||
}
|
||||
|
||||
&-comment-message {
|
||||
float: left;
|
||||
width: calc(100% - 10px);
|
||||
padding: 2px 10px;
|
||||
font-style: italic;
|
||||
color: #595959;
|
||||
white-space: initial;
|
||||
}
|
||||
|
||||
&-comment-message-time {
|
||||
float: left;
|
||||
width: calc(100% - 120px);
|
||||
padding: 2px 10px;
|
||||
font-size: 12px;
|
||||
color: #595959;
|
||||
}
|
||||
|
||||
&-comment-contents {
|
||||
float: left;
|
||||
width: calc(100% - 10px);
|
||||
}
|
||||
|
||||
&-datatable ::ng-deep table {
|
||||
border: none !important;
|
||||
tbody td {
|
||||
padding: 0px !important;
|
||||
border-top: none !important;
|
||||
}
|
||||
}
|
||||
|
||||
&-people-img {
|
||||
border-radius: 90%;
|
||||
width: 40px;
|
||||
height: 40px;
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
136
lib/process-services/comments/comment-list.component.spec.ts
Normal file
136
lib/process-services/comments/comment-list.component.spec.ts
Normal file
@@ -0,0 +1,136 @@
|
||||
/*!
|
||||
* @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 { DatePipe } from '@angular/common';
|
||||
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
import { CommentProcessModel, UserProcessModel } from '@alfresco/core';
|
||||
import { DataRowEvent, ObjectDataRow } from '@alfresco/core';
|
||||
import { CommentListComponent } from './comment-list.component';
|
||||
|
||||
const testUser: UserProcessModel = new UserProcessModel({
|
||||
id: '1',
|
||||
firstName: 'Test',
|
||||
lastName: 'User',
|
||||
email: 'tu@domain.com'
|
||||
});
|
||||
const testDate = new Date();
|
||||
const testComment: CommentProcessModel = new CommentProcessModel({id: 1, message: 'Test Comment', created: testDate.toDateString(), createdBy: testUser});
|
||||
|
||||
describe('CommentListComponent', () => {
|
||||
|
||||
let commentList: CommentListComponent;
|
||||
let fixture: ComponentFixture<CommentListComponent>;
|
||||
let element: HTMLElement;
|
||||
|
||||
beforeEach(async(() => {
|
||||
TestBed.configureTestingModule({
|
||||
|
||||
declarations: [
|
||||
CommentListComponent
|
||||
],
|
||||
providers: [
|
||||
DatePipe
|
||||
]
|
||||
}).compileComponents().then(() => {
|
||||
|
||||
fixture = TestBed.createComponent(CommentListComponent);
|
||||
commentList = fixture.componentInstance;
|
||||
element = fixture.nativeElement;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
}));
|
||||
|
||||
it('should emit row click event', (done) => {
|
||||
let row = new ObjectDataRow(testComment);
|
||||
let rowEvent = new DataRowEvent(row, null);
|
||||
|
||||
commentList.clickRow.subscribe(selectedComment => {
|
||||
expect(selectedComment.id).toEqual(1);
|
||||
expect(selectedComment.message).toEqual('Test Comment');
|
||||
expect(selectedComment.createdBy).toEqual(testUser);
|
||||
expect(selectedComment.created).toEqual(testDate.toDateString());
|
||||
done();
|
||||
});
|
||||
|
||||
commentList.selectComment(rowEvent);
|
||||
});
|
||||
|
||||
it('should not show comment list if no input is given', () => {
|
||||
fixture.detectChanges();
|
||||
expect(fixture.nativeElement.querySelector('adf-datatable')).toBeNull();
|
||||
});
|
||||
|
||||
it('should show comment message when input is given', () => {
|
||||
commentList.comments = [testComment];
|
||||
fixture.detectChanges();
|
||||
let elements = fixture.nativeElement.querySelectorAll('#comment-message');
|
||||
expect(elements.length).toBe(1);
|
||||
expect(elements[0].innerText).toBe(testComment.message);
|
||||
expect(fixture.nativeElement.querySelector('#comment-message:empty')).toBeNull();
|
||||
});
|
||||
|
||||
it('should show comment user when input is given', () => {
|
||||
commentList.comments = [testComment];
|
||||
fixture.detectChanges();
|
||||
let elements = fixture.nativeElement.querySelectorAll('#comment-user');
|
||||
expect(elements.length).toBe(1);
|
||||
expect(elements[0].innerText).toBe(testComment.createdBy.firstName + ' ' + testComment.createdBy.lastName);
|
||||
expect(fixture.nativeElement.querySelector('#comment-user:empty')).toBeNull();
|
||||
});
|
||||
|
||||
it('should show comment date time when input is given', () => {
|
||||
commentList.comments = [testComment];
|
||||
fixture.detectChanges();
|
||||
let elements = fixture.nativeElement.querySelectorAll('#comment-time');
|
||||
expect(elements.length).toBe(1);
|
||||
expect(elements[0].innerText).toBe(commentList.transformDate(testDate.toDateString()));
|
||||
expect(fixture.nativeElement.querySelector('#comment-time:empty')).toBeNull();
|
||||
});
|
||||
|
||||
it('comment date time should start with Today when comment date is today', () => {
|
||||
commentList.comments = [testComment];
|
||||
fixture.detectChanges();
|
||||
element = fixture.nativeElement.querySelector('#comment-time');
|
||||
expect(element.innerText).toContain('Today');
|
||||
});
|
||||
|
||||
it('comment date time should start with Yesterday when comment date is yesterday', () => {
|
||||
testComment.created = new Date((Date.now() - 24 * 3600 * 1000));
|
||||
commentList.comments = [testComment];
|
||||
fixture.detectChanges();
|
||||
element = fixture.nativeElement.querySelector('#comment-time');
|
||||
expect(element.innerText).toContain('Yesterday');
|
||||
});
|
||||
|
||||
it('comment date time should not start with Today/Yesterday when comment date is before yesterday', () => {
|
||||
testComment.created = new Date((Date.now() - 24 * 3600 * 1000 * 2));
|
||||
commentList.comments = [testComment];
|
||||
fixture.detectChanges();
|
||||
element = fixture.nativeElement.querySelector('#comment-time');
|
||||
expect(element.innerText).not.toContain('Today');
|
||||
expect(element.innerText).not.toContain('Yesterday');
|
||||
});
|
||||
|
||||
it('should show user icon when input is given', () => {
|
||||
commentList.comments = [testComment];
|
||||
fixture.detectChanges();
|
||||
let elements = fixture.nativeElement.querySelectorAll('#comment-user-icon');
|
||||
expect(elements.length).toBe(1);
|
||||
expect(elements[0].innerText).toContain(commentList.getUserShortName(testComment.createdBy));
|
||||
expect(fixture.nativeElement.querySelector('#comment-user-icon:empty')).toBeNull();
|
||||
});
|
||||
});
|
80
lib/process-services/comments/comment-list.component.ts
Normal file
80
lib/process-services/comments/comment-list.component.ts
Normal file
@@ -0,0 +1,80 @@
|
||||
/*!
|
||||
* @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 { CommentProcessModel, PeopleProcessService, UserProcessModel } from '@alfresco/core';
|
||||
import { DatePipe } from '@angular/common';
|
||||
import { Component, EventEmitter, Input, Output } from '@angular/core';
|
||||
|
||||
@Component({
|
||||
selector: 'adf-comment-list',
|
||||
templateUrl: './comment-list.component.html',
|
||||
styleUrls: ['./comment-list.component.scss']
|
||||
})
|
||||
|
||||
export class CommentListComponent {
|
||||
|
||||
@Input()
|
||||
comments: CommentProcessModel[];
|
||||
|
||||
@Output()
|
||||
clickRow: EventEmitter<CommentProcessModel> = new EventEmitter<CommentProcessModel>();
|
||||
|
||||
selectedComment: CommentProcessModel;
|
||||
|
||||
constructor(private datePipe: DatePipe, public peopleProcessService: PeopleProcessService) {
|
||||
}
|
||||
|
||||
selectComment(event: any): void {
|
||||
this.selectedComment = event.value.obj;
|
||||
this.clickRow.emit(this.selectedComment);
|
||||
}
|
||||
|
||||
getUserShortName(user: UserProcessModel): string {
|
||||
let shortName = '';
|
||||
if (user) {
|
||||
if (user.firstName) {
|
||||
shortName = user.firstName[0].toUpperCase();
|
||||
}
|
||||
if (user.lastName) {
|
||||
shortName += user.lastName[0].toUpperCase();
|
||||
}
|
||||
}
|
||||
return shortName;
|
||||
}
|
||||
|
||||
transformDate(aDate: string): string {
|
||||
let formattedDate: string;
|
||||
let givenDate = Number.parseInt(this.datePipe.transform(aDate, 'yMMdd'));
|
||||
let today = Number.parseInt(this.datePipe.transform(Date.now(), 'yMMdd'));
|
||||
if (givenDate === today) {
|
||||
formattedDate = 'Today, ' + this.datePipe.transform(aDate, 'hh:mm a');
|
||||
} else {
|
||||
let yesterday = Number.parseInt(this.datePipe.transform(Date.now() - 24 * 3600 * 1000, 'yMMdd'));
|
||||
if (givenDate === yesterday) {
|
||||
formattedDate = 'Yesterday, ' + this.datePipe.transform(aDate, 'hh:mm a');
|
||||
} else {
|
||||
formattedDate = this.datePipe.transform(aDate, 'MMM dd y, hh:mm a');
|
||||
}
|
||||
}
|
||||
return formattedDate;
|
||||
}
|
||||
|
||||
hasComments(): boolean {
|
||||
return this.comments && this.comments.length && true;
|
||||
}
|
||||
|
||||
}
|
31
lib/process-services/comments/comments.component.css
Normal file
31
lib/process-services/comments/comments.component.css
Normal file
@@ -0,0 +1,31 @@
|
||||
.adf-comments-container {
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
overflow: auto;
|
||||
}
|
||||
|
||||
.adf-comments-header {
|
||||
padding: 10px 20px;
|
||||
font-size: 14px;
|
||||
font-weight: 600;
|
||||
border-bottom: 1px solid #e1e1e1;
|
||||
color: #a1a1a1;
|
||||
}
|
||||
|
||||
.adf-comments-input-container {
|
||||
padding: 0 15px;
|
||||
width: calc(100% - 30px);
|
||||
padding-top: 8px;
|
||||
border-bottom: 1px solid #e1e1e1;
|
||||
}
|
||||
|
||||
.adf-full-width {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
adf-comment-list {
|
||||
float: left;
|
||||
overflow: auto;
|
||||
height: calc(100% - 101px);
|
||||
width: 100%;
|
||||
}
|
15
lib/process-services/comments/comments.component.html
Normal file
15
lib/process-services/comments/comments.component.html
Normal file
@@ -0,0 +1,15 @@
|
||||
<div class="adf-comments-container">
|
||||
<div id="comment-header" class="adf-comments-header">
|
||||
{{'ADF_TASK_LIST.DETAILS.COMMENTS.HEADER' | translate: { count: comments?.length} }}
|
||||
</div>
|
||||
<div class="adf-comments-input-container" *ngIf="!isReadOnly()">
|
||||
<mat-form-field class="adf-full-width">
|
||||
<input matInput id="comment-input" placeholder="{{'ADF_TASK_LIST.DETAILS.COMMENTS.ADD' | translate}}" [(ngModel)]="message" (keyup.enter)="add()" (keyup.esc)="clear()">
|
||||
</mat-form-field>
|
||||
</div>
|
||||
|
||||
<div *ngIf="comments.length > 0">
|
||||
<adf-comment-list [comments]="comments">
|
||||
</adf-comment-list>
|
||||
</div>
|
||||
</div>
|
233
lib/process-services/comments/comments.component.spec.ts
Normal file
233
lib/process-services/comments/comments.component.spec.ts
Normal file
@@ -0,0 +1,233 @@
|
||||
/*!
|
||||
* @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 { SimpleChange } from '@angular/core';
|
||||
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
import { Observable } from 'rxjs/Rx';
|
||||
|
||||
import { FormModule } from '@alfresco/core';
|
||||
import { CommentProcessService } from '@alfresco/core';
|
||||
|
||||
import { DatePipe } from '@angular/common';
|
||||
import { MatInputModule } from '@angular/material';
|
||||
import { PeopleProcessService } from '@alfresco/core';
|
||||
import { TaskListService } from '../task-list/services/tasklist.service';
|
||||
import { CommentListComponent } from './comment-list.component';
|
||||
import { CommentsComponent } from './comments.component';
|
||||
|
||||
describe('CommentsComponent', () => {
|
||||
|
||||
let service: TaskListService;
|
||||
let component: CommentsComponent;
|
||||
let fixture: ComponentFixture<CommentsComponent>;
|
||||
let getCommentsSpy: jasmine.Spy;
|
||||
let addCommentSpy: jasmine.Spy;
|
||||
let commentProcessService: CommentProcessService;
|
||||
|
||||
beforeEach(async(() => {
|
||||
TestBed.configureTestingModule({
|
||||
imports: [
|
||||
FormModule,
|
||||
MatInputModule
|
||||
],
|
||||
declarations: [
|
||||
CommentsComponent,
|
||||
CommentListComponent
|
||||
],
|
||||
providers: [
|
||||
TaskListService,
|
||||
DatePipe,
|
||||
PeopleProcessService,
|
||||
CommentProcessService
|
||||
]
|
||||
}).compileComponents();
|
||||
|
||||
}));
|
||||
|
||||
beforeEach(() => {
|
||||
fixture = TestBed.createComponent(CommentsComponent);
|
||||
component = fixture.componentInstance;
|
||||
service = fixture.debugElement.injector.get(TaskListService);
|
||||
commentProcessService = fixture.debugElement.injector.get(CommentProcessService);
|
||||
|
||||
getCommentsSpy = spyOn(commentProcessService, 'getTaskComments').and.returnValue(Observable.of([
|
||||
{ message: 'Test1', created: Date.now(), createdBy: {firstName: 'Admin', lastName: 'User'} },
|
||||
{ message: 'Test2', created: Date.now(), createdBy: {firstName: 'Admin', lastName: 'User'} },
|
||||
{ message: 'Test3', created: Date.now(), createdBy: {firstName: 'Admin', lastName: 'User'} }
|
||||
]));
|
||||
addCommentSpy = spyOn(commentProcessService, 'addTaskComment').and.returnValue(Observable.of({id: 123, message: 'Test Comment', createdBy: {id: '999'}}));
|
||||
|
||||
});
|
||||
|
||||
it('should load comments when taskId specified', () => {
|
||||
let change = new SimpleChange(null, '123', true);
|
||||
component.ngOnChanges({ 'taskId': change });
|
||||
|
||||
expect(getCommentsSpy).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should emit an error when an error occurs loading comments', () => {
|
||||
let emitSpy = spyOn(component.error, 'emit');
|
||||
getCommentsSpy.and.returnValue(Observable.throw({}));
|
||||
|
||||
let change = new SimpleChange(null, '123', true);
|
||||
component.ngOnChanges({ 'taskId': change });
|
||||
|
||||
expect(emitSpy).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should not load comments when no taskId is specified', () => {
|
||||
fixture.detectChanges();
|
||||
expect(getCommentsSpy).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should display comments when the task has comments', async(() => {
|
||||
let change = new SimpleChange(null, '123', true);
|
||||
component.ngOnChanges({ 'taskId': change });
|
||||
|
||||
fixture.whenStable().then(() => {
|
||||
fixture.detectChanges();
|
||||
expect(fixture.nativeElement.querySelectorAll('#comment-message').length).toBe(3);
|
||||
expect(fixture.nativeElement.querySelector('#comment-message:empty')).toBeNull();
|
||||
});
|
||||
}));
|
||||
|
||||
it('should display comments count when the task has comments', () => {
|
||||
let change = new SimpleChange(null, '123', true);
|
||||
component.ngOnChanges({ 'taskId': change });
|
||||
fixture.whenStable().then(() => {
|
||||
fixture.detectChanges();
|
||||
let element = fixture.nativeElement.querySelector('#comment-header');
|
||||
expect(element.innerText).toBe('ADF_TASK_LIST.DETAILS.COMMENTS.HEADER');
|
||||
});
|
||||
});
|
||||
|
||||
it('should not display comments when the task has no comments', async(() => {
|
||||
component.taskId = '123';
|
||||
getCommentsSpy.and.returnValue(Observable.of([]));
|
||||
fixture.whenStable().then(() => {
|
||||
fixture.detectChanges();
|
||||
expect(fixture.nativeElement.querySelector('#comment-container')).toBeNull();
|
||||
});
|
||||
}));
|
||||
|
||||
it('should display comments input by default', async(() => {
|
||||
let change = new SimpleChange(null, '123', true);
|
||||
component.ngOnChanges({ 'taskId': change });
|
||||
fixture.whenStable().then(() => {
|
||||
fixture.detectChanges();
|
||||
expect(fixture.nativeElement.querySelector('#comment-input')).not.toBeNull();
|
||||
});
|
||||
}));
|
||||
|
||||
it('should not display comments input when the task is readonly', async(() => {
|
||||
component.readOnly = true;
|
||||
fixture.detectChanges();
|
||||
fixture.whenStable().then(() => {
|
||||
fixture.detectChanges();
|
||||
expect(fixture.nativeElement.querySelector('#comment-input')).toBeNull();
|
||||
});
|
||||
}));
|
||||
|
||||
describe('change detection', () => {
|
||||
|
||||
let change = new SimpleChange('123', '456', true);
|
||||
let nullChange = new SimpleChange('123', null, true);
|
||||
|
||||
beforeEach(async(() => {
|
||||
component.taskId = '123';
|
||||
fixture.detectChanges();
|
||||
fixture.whenStable().then(() => {
|
||||
getCommentsSpy.calls.reset();
|
||||
});
|
||||
}));
|
||||
|
||||
it('should fetch new comments when taskId changed', () => {
|
||||
component.ngOnChanges({ 'taskId': change });
|
||||
expect(getCommentsSpy).toHaveBeenCalledWith('456');
|
||||
});
|
||||
|
||||
it('should not fetch new comments when empty changeset made', () => {
|
||||
component.ngOnChanges({});
|
||||
expect(getCommentsSpy).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should not fetch new comments when taskId changed to null', () => {
|
||||
component.ngOnChanges({ 'taskId': nullChange });
|
||||
expect(getCommentsSpy).not.toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
|
||||
describe('Add comment', () => {
|
||||
|
||||
beforeEach(async(() => {
|
||||
component.taskId = '123';
|
||||
fixture.detectChanges();
|
||||
fixture.whenStable();
|
||||
}));
|
||||
|
||||
it('should call service to add a comment when enter key is pressed', async(() => {
|
||||
let event = new KeyboardEvent('keyup', {'key': 'Enter'});
|
||||
let element = fixture.nativeElement.querySelector('#comment-input');
|
||||
component.message = 'Test Comment';
|
||||
element.dispatchEvent(event);
|
||||
fixture.detectChanges();
|
||||
fixture.whenStable().then(() => {
|
||||
fixture.detectChanges();
|
||||
expect(addCommentSpy).toHaveBeenCalled();
|
||||
let elements = fixture.nativeElement.querySelectorAll('#comment-message');
|
||||
expect(elements.length).toBe(1);
|
||||
expect(elements[0].innerText).toBe('Test Comment');
|
||||
});
|
||||
}));
|
||||
|
||||
it('should not call service to add a comment when comment is empty', async(() => {
|
||||
let event = new KeyboardEvent('keyup', {'key': 'Enter'});
|
||||
let element = fixture.nativeElement.querySelector('#comment-input');
|
||||
component.message = '';
|
||||
element.dispatchEvent(event);
|
||||
fixture.detectChanges();
|
||||
fixture.whenStable().then(() => {
|
||||
fixture.detectChanges();
|
||||
expect(addCommentSpy).not.toHaveBeenCalled();
|
||||
});
|
||||
}));
|
||||
|
||||
it('should clear comment when escape key is pressed', async(() => {
|
||||
let event = new KeyboardEvent('keyup', {'key': 'Escape'});
|
||||
let element = fixture.nativeElement.querySelector('#comment-input');
|
||||
component.message = 'Test comment';
|
||||
element.dispatchEvent(event);
|
||||
fixture.detectChanges();
|
||||
fixture.whenStable().then(() => {
|
||||
fixture.detectChanges();
|
||||
element = fixture.nativeElement.querySelector('#comment-input');
|
||||
expect(element.value).toBe('');
|
||||
});
|
||||
}));
|
||||
|
||||
it('should emit an error when an error occurs adding the comment', () => {
|
||||
let emitSpy = spyOn(component.error, 'emit');
|
||||
addCommentSpy.and.returnValue(Observable.throw({}));
|
||||
component.message = 'Test comment';
|
||||
component.add();
|
||||
expect(emitSpy).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
});
|
117
lib/process-services/comments/comments.component.ts
Normal file
117
lib/process-services/comments/comments.component.ts
Normal 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 { CommentProcessModel, CommentProcessService } from '@alfresco/core';
|
||||
import { Component, EventEmitter, Input, OnChanges, Output, SimpleChanges } from '@angular/core';
|
||||
import { Observable, Observer } from 'rxjs/Rx';
|
||||
|
||||
@Component({
|
||||
selector: 'adf-comments',
|
||||
templateUrl: './comments.component.html',
|
||||
styleUrls: ['./comments.component.css']
|
||||
})
|
||||
export class CommentsComponent implements OnChanges {
|
||||
|
||||
@Input()
|
||||
taskId: string;
|
||||
|
||||
@Input()
|
||||
readOnly: boolean = false;
|
||||
|
||||
@Output()
|
||||
error: EventEmitter<any> = new EventEmitter<any>();
|
||||
|
||||
comments: CommentProcessModel [] = [];
|
||||
|
||||
private commentObserver: Observer<CommentProcessModel>;
|
||||
comment$: Observable<CommentProcessModel>;
|
||||
|
||||
message: string;
|
||||
|
||||
beingAdded: boolean = false;
|
||||
|
||||
constructor(private commentProcessService: CommentProcessService) {
|
||||
this.comment$ = new Observable<CommentProcessModel>(observer => this.commentObserver = observer).share();
|
||||
this.comment$.subscribe((comment: CommentProcessModel) => {
|
||||
this.comments.push(comment);
|
||||
});
|
||||
}
|
||||
|
||||
ngOnChanges(changes: SimpleChanges) {
|
||||
let taskId = changes['taskId'];
|
||||
if (taskId) {
|
||||
if (taskId.currentValue) {
|
||||
this.getTaskComments(taskId.currentValue);
|
||||
} else {
|
||||
this.resetComments();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private getTaskComments(taskId: string): void {
|
||||
this.resetComments();
|
||||
if (taskId) {
|
||||
this.commentProcessService.getTaskComments(taskId).subscribe(
|
||||
(res: CommentProcessModel[]) => {
|
||||
res = res.sort((comment1: CommentProcessModel, comment2: CommentProcessModel) => {
|
||||
let date1 = new Date(comment1.created);
|
||||
let date2 = new Date(comment2.created);
|
||||
return date1 > date2 ? -1 : date1 < date2 ? 1 : 0;
|
||||
});
|
||||
res.forEach((comment) => {
|
||||
this.commentObserver.next(comment);
|
||||
});
|
||||
},
|
||||
(err) => {
|
||||
this.error.emit(err);
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
private resetComments(): void {
|
||||
this.comments = [];
|
||||
}
|
||||
|
||||
add(): void {
|
||||
if (this.message && this.message.trim() && !this.beingAdded) {
|
||||
this.beingAdded = true;
|
||||
this.commentProcessService.addTaskComment(this.taskId, this.message)
|
||||
.subscribe(
|
||||
(res: CommentProcessModel) => {
|
||||
this.comments.unshift(res);
|
||||
this.message = '';
|
||||
this.beingAdded = false;
|
||||
|
||||
},
|
||||
(err) => {
|
||||
this.error.emit(err);
|
||||
this.beingAdded = false;
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
clear(): void {
|
||||
this.message = '';
|
||||
}
|
||||
|
||||
isReadOnly(): boolean {
|
||||
return this.readOnly;
|
||||
}
|
||||
|
||||
}
|
50
lib/process-services/comments/comments.module.ts
Normal file
50
lib/process-services/comments/comments.module.ts
Normal file
@@ -0,0 +1,50 @@
|
||||
/*!
|
||||
* @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 { CommonModule } from '@angular/common';
|
||||
import { NgModule } from '@angular/core';
|
||||
import { TranslateModule } from '@ngx-translate/core';
|
||||
import { MaterialModule } from '../material.module';
|
||||
import { FormsModule, ReactiveFormsModule } from '@angular/forms';
|
||||
import { DataColumnModule, DataTableModule } from '@alfresco/core';
|
||||
|
||||
import { ProcessCommentsComponent } from './process-comments.component';
|
||||
import { CommentListComponent } from './comment-list.component';
|
||||
import { CommentsComponent } from './comments.component';
|
||||
|
||||
@NgModule({
|
||||
imports: [
|
||||
DataColumnModule,
|
||||
DataTableModule,
|
||||
FormsModule,
|
||||
ReactiveFormsModule,
|
||||
MaterialModule,
|
||||
CommonModule,
|
||||
TranslateModule
|
||||
],
|
||||
declarations: [
|
||||
ProcessCommentsComponent,
|
||||
CommentListComponent,
|
||||
CommentsComponent
|
||||
],
|
||||
exports: [
|
||||
ProcessCommentsComponent,
|
||||
CommentListComponent,
|
||||
CommentsComponent
|
||||
]
|
||||
})
|
||||
export class CommentsModule {}
|
18
lib/process-services/comments/index.ts
Normal file
18
lib/process-services/comments/index.ts
Normal file
@@ -0,0 +1,18 @@
|
||||
/*!
|
||||
* @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.
|
||||
*/
|
||||
|
||||
export * from './public-api';
|
58
lib/process-services/comments/process-comments.component.css
Normal file
58
lib/process-services/comments/process-comments.component.css
Normal file
@@ -0,0 +1,58 @@
|
||||
:host {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.activiti-label {
|
||||
font-weight: bolder;
|
||||
vertical-align: top;
|
||||
}
|
||||
|
||||
.activiti-label + .icon {
|
||||
position: relative;
|
||||
top: -2px;
|
||||
}
|
||||
|
||||
.list-wrap {
|
||||
word-wrap: break-word;
|
||||
word-break: break-all;
|
||||
-moz-hyphens:auto;
|
||||
-webkit-hyphens:auto;
|
||||
-o-hyphens:auto;
|
||||
hyphens:auto;
|
||||
}
|
||||
|
||||
.hide-long-names {
|
||||
overflow: auto;
|
||||
}
|
||||
|
||||
.adf-comments-container {
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
overflow: auto;
|
||||
}
|
||||
|
||||
.adf-comments-header {
|
||||
padding: 10px 20px;
|
||||
font-size: 14px;
|
||||
font-weight: 600;
|
||||
border-bottom: 1px solid #e1e1e1;
|
||||
color: #a1a1a1;
|
||||
}
|
||||
|
||||
.adf-comments-input-container {
|
||||
padding: 0 15px;
|
||||
width: calc(100% - 30px);
|
||||
padding-top: 8px;
|
||||
border-bottom: 1px solid #e1e1e1;
|
||||
}
|
||||
|
||||
.adf-full-width {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
adf-comment-list {
|
||||
float: left;
|
||||
overflow: auto;
|
||||
height: calc(100% - 101px);
|
||||
width: 100%;
|
||||
}
|
@@ -0,0 +1,15 @@
|
||||
<div class="adf-comments-container">
|
||||
<div id="comment-header" class="adf-comments-header">
|
||||
{{'ADF_PROCESS_LIST.DETAILS.COMMENTS.HEADER' | translate: { count: comments?.length} }}
|
||||
</div>
|
||||
<div class="adf-comments-input-container" *ngIf="!isReadOnly()">
|
||||
<mat-form-field class="adf-full-width">
|
||||
<input matInput id="comment-input" placeholder="{{'ADF_PROCESS_LIST.DETAILS.COMMENTS.ADD' | translate}}" [(ngModel)]="message" (keyup.enter)="add()" (keyup.esc)="clear()">
|
||||
</mat-form-field>
|
||||
</div>
|
||||
|
||||
<div *ngIf="comments.length > 0">
|
||||
<adf-comment-list [comments]="comments">
|
||||
</adf-comment-list>
|
||||
</div>
|
||||
</div>
|
152
lib/process-services/comments/process-comments.component.spec.ts
Normal file
152
lib/process-services/comments/process-comments.component.spec.ts
Normal file
@@ -0,0 +1,152 @@
|
||||
/*!
|
||||
* @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 { DatePipe } from '@angular/common';
|
||||
import { SimpleChange } from '@angular/core';
|
||||
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
import { MatInputModule } from '@angular/material';
|
||||
import { Observable } from 'rxjs/Rx';
|
||||
|
||||
import { CommentListComponent, CommentsComponent } from '../index';
|
||||
import { CommentProcessService, PeopleProcessService } from '@alfresco/core';
|
||||
|
||||
import { ProcessService } from '../process-list/services/process.service';
|
||||
import { ProcessCommentsComponent } from './process-comments.component';
|
||||
|
||||
describe('ActivitiProcessInstanceComments', () => {
|
||||
|
||||
let component: ProcessCommentsComponent;
|
||||
let fixture: ComponentFixture<ProcessCommentsComponent>;
|
||||
let getCommentsSpy: jasmine.Spy;
|
||||
let commentProcessService: CommentProcessService;
|
||||
|
||||
beforeEach(async(() => {
|
||||
TestBed.configureTestingModule({
|
||||
imports: [
|
||||
MatInputModule
|
||||
],
|
||||
declarations: [
|
||||
ProcessCommentsComponent,
|
||||
CommentsComponent,
|
||||
CommentListComponent
|
||||
],
|
||||
providers: [
|
||||
ProcessService,
|
||||
DatePipe,
|
||||
PeopleProcessService,
|
||||
CommentProcessService
|
||||
]
|
||||
}).compileComponents();
|
||||
}));
|
||||
|
||||
beforeEach(() => {
|
||||
|
||||
fixture = TestBed.createComponent(ProcessCommentsComponent);
|
||||
component = fixture.componentInstance;
|
||||
commentProcessService = TestBed.get(CommentProcessService);
|
||||
|
||||
getCommentsSpy = spyOn(commentProcessService, 'getProcessInstanceComments').and.returnValue(Observable.of([
|
||||
{ message: 'Test1', created: Date.now(), createdBy: {firstName: 'Admin', lastName: 'User'} },
|
||||
{ message: 'Test2', created: Date.now(), createdBy: {firstName: 'Admin', lastName: 'User'} },
|
||||
{ message: 'Test3', created: Date.now(), createdBy: {firstName: 'Admin', lastName: 'User'} }
|
||||
]));
|
||||
});
|
||||
|
||||
it('should load comments when processInstanceId specified', () => {
|
||||
let change = new SimpleChange(null, '123', true);
|
||||
component.ngOnChanges({ 'processInstanceId': change });
|
||||
fixture.detectChanges();
|
||||
expect(getCommentsSpy).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should emit an error when an error occurs loading comments', () => {
|
||||
let emitSpy = spyOn(component.error, 'emit');
|
||||
getCommentsSpy.and.returnValue(Observable.throw({}));
|
||||
|
||||
let change = new SimpleChange(null, '123', true);
|
||||
component.ngOnChanges({ 'processInstanceId': change });
|
||||
|
||||
fixture.detectChanges();
|
||||
expect(emitSpy).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should not load comments when no processInstanceId is specified', () => {
|
||||
fixture.detectChanges();
|
||||
expect(getCommentsSpy).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should display comments when the process has comments', async(() => {
|
||||
let change = new SimpleChange(null, '123', true);
|
||||
component.ngOnChanges({ 'processInstanceId': change });
|
||||
|
||||
fixture.whenStable().then(() => {
|
||||
fixture.detectChanges();
|
||||
expect(fixture.nativeElement.querySelectorAll('#comment-message').length).toBe(3);
|
||||
expect(fixture.nativeElement.querySelector('#comment-message:empty')).toBeNull();
|
||||
});
|
||||
}));
|
||||
|
||||
it('should display comments count when the process has comments', () => {
|
||||
let change = new SimpleChange(null, '123', true);
|
||||
component.ngOnChanges({ 'processInstanceId': change });
|
||||
|
||||
fixture.whenStable().then(() => {
|
||||
fixture.detectChanges();
|
||||
let element = fixture.nativeElement.querySelector('#comment-header');
|
||||
expect(element.innerText).toBe('ADF_PROCESS_LIST.DETAILS.COMMENTS.HEADER');
|
||||
});
|
||||
});
|
||||
|
||||
it('should not display comments when the process has no comments', async(() => {
|
||||
let change = new SimpleChange(null, '123', true);
|
||||
component.ngOnChanges({ 'processInstanceId': change });
|
||||
|
||||
getCommentsSpy.and.returnValue(Observable.of([]));
|
||||
fixture.whenStable().then(() => {
|
||||
fixture.detectChanges();
|
||||
expect(fixture.nativeElement.querySelector('#comment-container')).toBeNull();
|
||||
});
|
||||
}));
|
||||
|
||||
it('should not display comments input by default', async(() => {
|
||||
let change = new SimpleChange(null, '123', true);
|
||||
component.ngOnChanges({ 'processInstanceId': change });
|
||||
|
||||
fixture.whenStable().then(() => {
|
||||
fixture.detectChanges();
|
||||
expect(fixture.nativeElement.querySelector('#comment-input')).toBeNull();
|
||||
});
|
||||
}));
|
||||
|
||||
it('should not display comments input when the process is readonly', async(() => {
|
||||
component.readOnly = true;
|
||||
fixture.detectChanges();
|
||||
fixture.whenStable().then(() => {
|
||||
fixture.detectChanges();
|
||||
expect(fixture.nativeElement.querySelector('#comment-input')).toBeNull();
|
||||
});
|
||||
}));
|
||||
|
||||
it('should display comments input when the process isn\'t readonly', async(() => {
|
||||
component.readOnly = false;
|
||||
fixture.detectChanges();
|
||||
fixture.whenStable().then(() => {
|
||||
fixture.detectChanges();
|
||||
expect(fixture.nativeElement.querySelector('#comment-input')).not.toBeNull();
|
||||
});
|
||||
}));
|
||||
});
|
121
lib/process-services/comments/process-comments.component.ts
Normal file
121
lib/process-services/comments/process-comments.component.ts
Normal file
@@ -0,0 +1,121 @@
|
||||
/*!
|
||||
* @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 { CommentProcessModel, CommentProcessService } from '@alfresco/core';
|
||||
import { Component, EventEmitter, Input, OnChanges, Output, SimpleChanges } from '@angular/core';
|
||||
import { Observable, Observer } from 'rxjs/Rx';
|
||||
|
||||
@Component({
|
||||
selector: 'adf-process-instance-comments',
|
||||
templateUrl: './process-comments.component.html',
|
||||
styleUrls: ['./process-comments.component.css']
|
||||
})
|
||||
export class ProcessCommentsComponent implements OnChanges {
|
||||
|
||||
@Input()
|
||||
processInstanceId: string;
|
||||
|
||||
@Input()
|
||||
readOnly: boolean = true;
|
||||
|
||||
@Output()
|
||||
error: EventEmitter<any> = new EventEmitter<any>();
|
||||
|
||||
comments: CommentProcessModel [] = [];
|
||||
|
||||
private commentObserver: Observer<CommentProcessModel>;
|
||||
comment$: Observable<CommentProcessModel>;
|
||||
|
||||
message: string;
|
||||
|
||||
beingAdded: boolean = false;
|
||||
|
||||
constructor(private commentProcessService: CommentProcessService) {
|
||||
this.comment$ = new Observable<CommentProcessModel>(observer => this.commentObserver = observer).share();
|
||||
this.comment$.subscribe((comment: CommentProcessModel) => {
|
||||
this.comments.push(comment);
|
||||
});
|
||||
}
|
||||
|
||||
ngOnChanges(changes: SimpleChanges) {
|
||||
let processInstanceId = changes['processInstanceId'];
|
||||
if (processInstanceId) {
|
||||
if (processInstanceId.currentValue) {
|
||||
this.getProcessInstanceComments(processInstanceId.currentValue);
|
||||
} else {
|
||||
this.resetComments();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private getProcessInstanceComments(processInstanceId: string): void {
|
||||
this.resetComments();
|
||||
if (processInstanceId) {
|
||||
this.commentProcessService.getProcessInstanceComments(processInstanceId).subscribe(
|
||||
(res: CommentProcessModel[]) => {
|
||||
res = res.sort((comment1: CommentProcessModel, comment2: CommentProcessModel) => {
|
||||
let date1 = new Date(comment1.created);
|
||||
let date2 = new Date(comment2.created);
|
||||
return date1 > date2 ? -1 : date1 < date2 ? 1 : 0;
|
||||
});
|
||||
res.forEach((comment) => {
|
||||
this.commentObserver.next(comment);
|
||||
});
|
||||
},
|
||||
(err) => {
|
||||
this.error.emit(err);
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
private resetComments(): void {
|
||||
this.comments = [];
|
||||
}
|
||||
|
||||
add(): void {
|
||||
if (this.message && this.message.trim() && !this.beingAdded) {
|
||||
this.beingAdded = true;
|
||||
this.commentProcessService.addProcessInstanceComment(this.processInstanceId, this.message)
|
||||
.subscribe(
|
||||
(res: CommentProcessModel) => {
|
||||
this.comments.unshift(res);
|
||||
this.message = '';
|
||||
this.beingAdded = false;
|
||||
|
||||
},
|
||||
(err) => {
|
||||
this.error.emit(err);
|
||||
this.beingAdded = false;
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
clear(): void {
|
||||
this.message = '';
|
||||
}
|
||||
|
||||
isReadOnly(): boolean {
|
||||
return this.readOnly;
|
||||
}
|
||||
|
||||
onError(error: any) {
|
||||
this.error.emit(error);
|
||||
}
|
||||
|
||||
}
|
22
lib/process-services/comments/public-api.ts
Normal file
22
lib/process-services/comments/public-api.ts
Normal file
@@ -0,0 +1,22 @@
|
||||
/*!
|
||||
* @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.
|
||||
*/
|
||||
|
||||
export * from './process-comments.component';
|
||||
export * from './comment-list.component';
|
||||
export * from './comments.component';
|
||||
|
||||
export * from './comments.module';
|
131
lib/process-services/i18n/de.json
Normal file
131
lib/process-services/i18n/de.json
Normal file
@@ -0,0 +1,131 @@
|
||||
{
|
||||
"DIALOG": {
|
||||
"SAVE_MESSAGE": "Klicken Sie auf 'Speichern', um einen Bericht mit den derzeitigen Einstellungen zu Ihrer Berichteliste hinzuzufügen.",
|
||||
"EXPORT_MESSAGE": ""
|
||||
},
|
||||
"DATE-WIDGET": {
|
||||
"START-DATE": "Startdatum",
|
||||
"END-DATE": "Enddatum",
|
||||
"MESSAGES": {
|
||||
"START-DATE-REQUIRED": "Startdatum ist erforderlich",
|
||||
"START-LESS-THAN-END-DATE": "Das Startdatum muss vor dem Enddatum liegen"
|
||||
}
|
||||
},
|
||||
"ADF_TASK_LIST": {
|
||||
"APPS": {
|
||||
"NONE": "Keine Anwendungen gefunden"
|
||||
},
|
||||
"LIST": {
|
||||
"MESSAGES": {
|
||||
"NONE": "Keine Aufgabenliste gefunden"
|
||||
}
|
||||
},
|
||||
"DETAILS": {
|
||||
"LABELS": {
|
||||
"ASSIGNEE": "Zugewiesener Benutzer",
|
||||
"DUE": "Fällig",
|
||||
"FORM": "Formular",
|
||||
"PEOPLE": "Personen, für die diese Aufgabe freigegeben wurde",
|
||||
"COMMENTS": "Kommentare",
|
||||
"CHECKLIST": "Prüfliste",
|
||||
"INVOLVED_PEOPLE": "Beteiligte Personen",
|
||||
"ADD_PEOPLE": "Personen und Gruppen hinzufügen",
|
||||
"ADD_ASSIGNEE": "Neuen zugewiesenen Benutzer hinzufügen"
|
||||
},
|
||||
"BUTTON": {
|
||||
"COMPLETE": "Abschließen",
|
||||
"CLAIM": "Anfordern",
|
||||
"UNCLAIM": "Erneut in Warteschlange stellen",
|
||||
"DRAG-ATTACHMENT": "Dateien hier ablegen ...",
|
||||
"UPLOAD-ATTACHMENT": "Anhang hochladen"
|
||||
},
|
||||
"MESSAGES": {
|
||||
"NONE": "Keine Aufgabendetails gefunden",
|
||||
"CLAIM": "Klicken Sie auf 'Anfordern', um diese Aufgabe zu bearbeiten."
|
||||
},
|
||||
"FORM": {
|
||||
"NONE": "Kein Formular."
|
||||
},
|
||||
"DUE": {
|
||||
"NONE": "Kein Fälligkeitsdatum."
|
||||
},
|
||||
"ASSIGNEE": {
|
||||
"NONE": "Kein zugewiesener Benutzer."
|
||||
},
|
||||
"PEOPLE": {
|
||||
"NONE": "Niemand beteiligt."
|
||||
},
|
||||
"COMMENTS": {
|
||||
"NONE": "Keine Kommentare vorhanden",
|
||||
"ADD": "Kommentar hinzufügen",
|
||||
"HEADER": "Kommentare",
|
||||
"DIALOG": {
|
||||
"TITLE": "Neuer Kommentar",
|
||||
"LABELS": {
|
||||
"MESSAGE": "Fehlermeldung"
|
||||
},
|
||||
"BUTTON": {
|
||||
"ADD": "Kommentar hinzufügen",
|
||||
"CANCEL": "Abbrechen"
|
||||
}
|
||||
}
|
||||
},
|
||||
"CHECKLIST": {
|
||||
"NONE": "Keine Prüfliste"
|
||||
},
|
||||
"ERROR": {
|
||||
"TITLE": "Vorgang konnte nicht durchgeführt werden",
|
||||
"DESCRIPTION": "Versuchen Sie es noch einmal oder überprüfen Sie, ob Sie Zugriff haben.",
|
||||
"CLOSE": "Schließen"
|
||||
}
|
||||
},
|
||||
"FILTERS": {
|
||||
"MESSAGES": {
|
||||
"NONE": "Kein Aufgabenfilter ausgewählt."
|
||||
}
|
||||
},
|
||||
"START_TASK": {
|
||||
"BUTTON": "AUFGABE ERSTELLEN",
|
||||
"FORM": {
|
||||
"TITLE": "Aufgabe starten",
|
||||
"LABEL": {
|
||||
"NONE": "Keine",
|
||||
"NAME": "Name",
|
||||
"DESCRIPTION": "Beschreibung",
|
||||
"ATTACHFORM": "Formular anhängen",
|
||||
"ASSIGNEE": "Zugewiesener Benutzer",
|
||||
"FORM": "Formular",
|
||||
"DATE": "Datum auswählen"
|
||||
},
|
||||
"ACTION": {
|
||||
"START": "Start",
|
||||
"CANCEL": "Abbrechen"
|
||||
},
|
||||
"DATE": {
|
||||
"ERROR": "Datumsformat TT.MM.JJJJ"
|
||||
}
|
||||
}
|
||||
},
|
||||
"PEOPLE": {
|
||||
"DIALOG_CLOSE": "SCHLIESSEN",
|
||||
"ADD_USER": "HINZUFÜGEN",
|
||||
"ADD_ASSIGNEE": "ZUWEISEN",
|
||||
"SEARCH_USER": "Benutzer suchen",
|
||||
"SEARCH": {
|
||||
"NO_USERS": "Niemand gefunden, der beteiligt werden kann"
|
||||
}
|
||||
},
|
||||
"ATTACHMENT": {
|
||||
"EMPTY": {
|
||||
"HEADER": "Diese Liste ist leer",
|
||||
"DRAG-AND-DROP": {
|
||||
"TITLE": "Ziehen und ablegen",
|
||||
"SUBTITLE": "um Dateien hochzuladen"
|
||||
}
|
||||
},
|
||||
"EMPTY-LIST": {
|
||||
"HEADER": "Keine Dateien verfügbar"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
165
lib/process-services/i18n/en.json
Normal file
165
lib/process-services/i18n/en.json
Normal file
@@ -0,0 +1,165 @@
|
||||
{
|
||||
"DIALOG": {
|
||||
"SAVE_MESSAGE": "Click Save to add a report with the current settings to your reports list.",
|
||||
"EXPORT_MESSAGE": ""
|
||||
},
|
||||
"DATE-WIDGET": {
|
||||
"START-DATE": "Start date",
|
||||
"END-DATE": "End date",
|
||||
"MESSAGES": {
|
||||
"START-DATE-REQUIRED": "Start date is required",
|
||||
"START-LESS-THAN-END-DATE": "Start date must be before end date"
|
||||
}
|
||||
},
|
||||
"ADF_TASK_LIST": {
|
||||
"APPS": {
|
||||
"NONE": "No apps found",
|
||||
"TASK_APP_NAME": "Task App"
|
||||
},
|
||||
"LIST": {
|
||||
"MESSAGES": {
|
||||
"NONE": "No task lists found"
|
||||
}
|
||||
},
|
||||
"PROPERTIES": {
|
||||
"TASK_NAME": "Task",
|
||||
"THUMBNAIL": "Thumbnail",
|
||||
"NAME": "Name",
|
||||
"ASSIGNEE": "Assignee",
|
||||
"ASSIGNEE_DEFAULT": "No assignee",
|
||||
"PRIORITY": "Priority",
|
||||
"DUE_DATE": "Due Date",
|
||||
"DUE_DATE_DEFAULT": "No date",
|
||||
"STATUS": "Status",
|
||||
"CATEGORY": "Category",
|
||||
"CATEGORY_DEFAULT": "No category",
|
||||
"PARENT_NAME": "Parent name",
|
||||
"PARENT_NAME_DEFAULT": "No parent",
|
||||
"CREATED_BY": "Created By",
|
||||
"CREATED": "Created",
|
||||
"ID": "ID",
|
||||
"DESCRIPTION": "Description",
|
||||
"DESCRIPTION_DEFAULT": "No description",
|
||||
"FORM_NAME": "Form Name",
|
||||
"FORM_NAME_DEFAULT": "No form"
|
||||
},
|
||||
"MENU_ACTIONS": {
|
||||
"VIEW_CONTENT": "View",
|
||||
"REMOVE_CONTENT": "Remove",
|
||||
"DOWNLOAD_CONTENT": "Download",
|
||||
"DOWNLOAD_AUDIT": "Download Audit"
|
||||
},
|
||||
"DETAILS": {
|
||||
"LABELS": {
|
||||
"INFO_DRAWER_TITLE": "Activities",
|
||||
"INFO_DRAWER_TAB_ACTIVITY_TITLE": "Activity",
|
||||
"INFO_DRAWER_TAB_DETAILS_TITLE": "Details",
|
||||
"ASSIGNEE": "Assignee",
|
||||
"DUE": "Due",
|
||||
"FORM": "Form",
|
||||
"PEOPLE": "People this task is shared with",
|
||||
"COMMENTS": "Comments",
|
||||
"CHECKLIST": "Checklist",
|
||||
"INVOLVED_PEOPLE": "People Involved",
|
||||
"ADD_PEOPLE": "Add people and groups",
|
||||
"ADD_ASSIGNEE": "Add new assignee"
|
||||
},
|
||||
"BUTTON": {
|
||||
"COMPLETE": "Complete",
|
||||
"CLAIM": "Claim",
|
||||
"UNCLAIM": "Requeue",
|
||||
"DRAG-ATTACHMENT": "Drop files to upload",
|
||||
"UPLOAD-ATTACHMENT": "Upload Attachment"
|
||||
},
|
||||
"MESSAGES": {
|
||||
"NONE": "No task details found",
|
||||
"CLAIM": "Click Claim to work on this task"
|
||||
},
|
||||
"FORM": {
|
||||
"NONE": "No form"
|
||||
},
|
||||
"DUE": {
|
||||
"NONE": "No due date"
|
||||
},
|
||||
"ASSIGNEE": {
|
||||
"NONE": "No assignee"
|
||||
},
|
||||
"PEOPLE": {
|
||||
"NONE": "Nobody involved"
|
||||
},
|
||||
"COMMENTS": {
|
||||
"NONE": "No comments",
|
||||
"ADD": "Add a comment",
|
||||
"HEADER": "Comments ({{ count }})",
|
||||
"CREATED_BY_HEADER": "Created by",
|
||||
"MESSAGE_HEADER": "Message",
|
||||
"DIALOG": {
|
||||
"TITLE": "New comment",
|
||||
"LABELS": {
|
||||
"MESSAGE": "Message"
|
||||
},
|
||||
"BUTTON": {
|
||||
"ADD": "Add Comment",
|
||||
"CANCEL": "Cancel"
|
||||
}
|
||||
}
|
||||
},
|
||||
"CHECKLIST": {
|
||||
"NONE": "No checklist"
|
||||
},
|
||||
"ERROR": {
|
||||
"TITLE": "Couldn't complete the action",
|
||||
"DESCRIPTION": "Try again or check that you have access.",
|
||||
"CLOSE": "Close"
|
||||
}
|
||||
},
|
||||
"FILTERS": {
|
||||
"MESSAGES": {
|
||||
"NONE": "No task filter selected"
|
||||
}
|
||||
},
|
||||
"START_TASK": {
|
||||
"BUTTON": "CREATE TASK",
|
||||
"FORM": {
|
||||
"TITLE": "Start Task",
|
||||
"LABEL": {
|
||||
"NONE": "None",
|
||||
"NAME": "Name",
|
||||
"DESCRIPTION": "Description",
|
||||
"ATTACHFORM": "Attach Form",
|
||||
"ASSIGNEE": "Assignee",
|
||||
"FORM": "Form",
|
||||
"DATE": "Choose Date"
|
||||
},
|
||||
"ACTION": {
|
||||
"START": "Start",
|
||||
"CANCEL": "Cancel"
|
||||
},
|
||||
"DATE": {
|
||||
"ERROR": "Date format DD/MM/YYYY"
|
||||
}
|
||||
}
|
||||
},
|
||||
"PEOPLE": {
|
||||
"DIALOG_CLOSE": "CLOSE",
|
||||
"ADD_USER": "ADD",
|
||||
"ADD_ASSIGNEE": "ASSIGN",
|
||||
"SEARCH_USER": "Search user",
|
||||
"SEARCH": {
|
||||
"NO_USERS": "Nobody found to involve"
|
||||
}
|
||||
},
|
||||
"ATTACHMENT": {
|
||||
"EMPTY": {
|
||||
"HEADER": "This list is empty",
|
||||
"DRAG-AND-DROP": {
|
||||
"TITLE": "Drag and drop",
|
||||
"SUBTITLE": "to upload files"
|
||||
}
|
||||
},
|
||||
"EMPTY-LIST": {
|
||||
"HEADER": "No files are available"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
131
lib/process-services/i18n/es.json
Normal file
131
lib/process-services/i18n/es.json
Normal file
@@ -0,0 +1,131 @@
|
||||
{
|
||||
"DIALOG": {
|
||||
"SAVE_MESSAGE": "Haga clic en Guardar para añadir un informe con los ajustes actuales a su lista de informes.",
|
||||
"EXPORT_MESSAGE": ""
|
||||
},
|
||||
"DATE-WIDGET": {
|
||||
"START-DATE": "Fecha de inicio",
|
||||
"END-DATE": "Fecha de fin",
|
||||
"MESSAGES": {
|
||||
"START-DATE-REQUIRED": "Fecha de inicio obligatoria",
|
||||
"START-LESS-THAN-END-DATE": "La fecha de inicio debe ser anterior a la fecha de finalización"
|
||||
}
|
||||
},
|
||||
"ADF_TASK_LIST": {
|
||||
"APPS": {
|
||||
"NONE": "No se han encontrado aplicaciones"
|
||||
},
|
||||
"LIST": {
|
||||
"MESSAGES": {
|
||||
"NONE": "No se ha encontrado la lista de tareas"
|
||||
}
|
||||
},
|
||||
"DETAILS": {
|
||||
"LABELS": {
|
||||
"ASSIGNEE": "Asignado a",
|
||||
"DUE": "Vencimiento",
|
||||
"FORM": "Formulario",
|
||||
"PEOPLE": "Personas con las que se comparte esta tarea",
|
||||
"COMMENTS": "Comentarios",
|
||||
"CHECKLIST": "Lista de comprobación",
|
||||
"INVOLVED_PEOPLE": "Personas involucradas",
|
||||
"ADD_PEOPLE": "Añadir personas y grupos",
|
||||
"ADD_ASSIGNEE": "Añadir nuevo usuario a asignar"
|
||||
},
|
||||
"BUTTON": {
|
||||
"COMPLETE": "Completado",
|
||||
"CLAIM": "Pedir",
|
||||
"UNCLAIM": "Volver a poner en cola",
|
||||
"DRAG-ATTACHMENT": "Soltar ficheros aquí...",
|
||||
"UPLOAD-ATTACHMENT": "Cargar adjunto"
|
||||
},
|
||||
"MESSAGES": {
|
||||
"NONE": "No se han encontrado detalles de la tarea",
|
||||
"CLAIM": "Para trabajar en esta tarea, haga clic en Pedir."
|
||||
},
|
||||
"FORM": {
|
||||
"NONE": "Sin formulario."
|
||||
},
|
||||
"DUE": {
|
||||
"NONE": "Sin fecha de vencimiento."
|
||||
},
|
||||
"ASSIGNEE": {
|
||||
"NONE": "Sin usuario a asignar."
|
||||
},
|
||||
"PEOPLE": {
|
||||
"NONE": "Nadie involucrado."
|
||||
},
|
||||
"COMMENTS": {
|
||||
"NONE": "No hay comentarios",
|
||||
"ADD": "Añadir comentario",
|
||||
"HEADER": "Comentarios",
|
||||
"DIALOG": {
|
||||
"TITLE": "Nuevo comentario",
|
||||
"LABELS": {
|
||||
"MESSAGE": "Mensaje"
|
||||
},
|
||||
"BUTTON": {
|
||||
"ADD": "Añadir comentario",
|
||||
"CANCEL": "Cancelar"
|
||||
}
|
||||
}
|
||||
},
|
||||
"CHECKLIST": {
|
||||
"NONE": "No hay lista de comprobación"
|
||||
},
|
||||
"ERROR": {
|
||||
"TITLE": "No se ha podido finalizar la acción.",
|
||||
"DESCRIPTION": "Vuelva a intentarlo o compruebe que tiene acceso.",
|
||||
"CLOSE": "Cerrar"
|
||||
}
|
||||
},
|
||||
"FILTERS": {
|
||||
"MESSAGES": {
|
||||
"NONE": "No se ha seleccionado filtro de tareas."
|
||||
}
|
||||
},
|
||||
"START_TASK": {
|
||||
"BUTTON": "CREAR TAREA",
|
||||
"FORM": {
|
||||
"TITLE": "Iniciar tarea",
|
||||
"LABEL": {
|
||||
"NONE": "Ninguno",
|
||||
"NAME": "Nombre",
|
||||
"DESCRIPTION": "Descripción",
|
||||
"ATTACHFORM": "Adjuntar formulario",
|
||||
"ASSIGNEE": "Asignado a",
|
||||
"FORM": "Formulario",
|
||||
"DATE": "Seleccione una fecha"
|
||||
},
|
||||
"ACTION": {
|
||||
"START": "Iniciar",
|
||||
"CANCEL": "Cancelar"
|
||||
},
|
||||
"DATE": {
|
||||
"ERROR": "Formato de fecha DD/MM/AAAA"
|
||||
}
|
||||
}
|
||||
},
|
||||
"PEOPLE": {
|
||||
"DIALOG_CLOSE": "CERRAR",
|
||||
"ADD_USER": "AÑADIR",
|
||||
"ADD_ASSIGNEE": "ASIGNAR",
|
||||
"SEARCH_USER": "Buscar usuario",
|
||||
"SEARCH": {
|
||||
"NO_USERS": "No se ha encontrado nadie a quien involucrar"
|
||||
}
|
||||
},
|
||||
"ATTACHMENT": {
|
||||
"EMPTY": {
|
||||
"HEADER": "Esta lista está vacía",
|
||||
"DRAG-AND-DROP": {
|
||||
"TITLE": "Arrastrar y soltar",
|
||||
"SUBTITLE": "para cargar ficheros"
|
||||
}
|
||||
},
|
||||
"EMPTY-LIST": {
|
||||
"HEADER": "No hay ficheros disponibles"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
131
lib/process-services/i18n/fr.json
Normal file
131
lib/process-services/i18n/fr.json
Normal file
@@ -0,0 +1,131 @@
|
||||
{
|
||||
"DIALOG": {
|
||||
"SAVE_MESSAGE": "Cliquez sur Enregistrer pour ajouter un rapport avec les paramètres actuels à la liste des rapports.",
|
||||
"EXPORT_MESSAGE": ""
|
||||
},
|
||||
"DATE-WIDGET": {
|
||||
"START-DATE": "Date de début",
|
||||
"END-DATE": "Date de fin",
|
||||
"MESSAGES": {
|
||||
"START-DATE-REQUIRED": "La date de début est obligatoire",
|
||||
"START-LESS-THAN-END-DATE": "La date de début doit être antérieure à la date de fin"
|
||||
}
|
||||
},
|
||||
"ADF_TASK_LIST": {
|
||||
"APPS": {
|
||||
"NONE": "Aucune application trouvée"
|
||||
},
|
||||
"LIST": {
|
||||
"MESSAGES": {
|
||||
"NONE": "Aucune liste de tâches trouvée"
|
||||
}
|
||||
},
|
||||
"DETAILS": {
|
||||
"LABELS": {
|
||||
"ASSIGNEE": "Personne assignée",
|
||||
"DUE": "Echéance",
|
||||
"FORM": "Formulaire",
|
||||
"PEOPLE": "Personnes avec lesquelles cette tâche est partagée",
|
||||
"COMMENTS": "Commentaires",
|
||||
"CHECKLIST": "Liste de contrôle",
|
||||
"INVOLVED_PEOPLE": "Personnes impliquées",
|
||||
"ADD_PEOPLE": "Ajouter des personnes et des groupes",
|
||||
"ADD_ASSIGNEE": "Ajouter une nouvelle personne assignée"
|
||||
},
|
||||
"BUTTON": {
|
||||
"COMPLETE": "Terminer",
|
||||
"CLAIM": "Se l'attribuer",
|
||||
"UNCLAIM": "Replacer dans la file d'attente",
|
||||
"DRAG-ATTACHMENT": "Déposer des fichiers ici...",
|
||||
"UPLOAD-ATTACHMENT": "Importer la pièce jointe"
|
||||
},
|
||||
"MESSAGES": {
|
||||
"NONE": "Aucun détail de tâche trouvé",
|
||||
"CLAIM": "Pour travailler sur cette tâche, cliquez sur Se l'attribuer."
|
||||
},
|
||||
"FORM": {
|
||||
"NONE": "Aucun formulaire."
|
||||
},
|
||||
"DUE": {
|
||||
"NONE": "Aucune date d'échéance."
|
||||
},
|
||||
"ASSIGNEE": {
|
||||
"NONE": "Aucune personne assignée."
|
||||
},
|
||||
"PEOPLE": {
|
||||
"NONE": "Aucune personne impliquée."
|
||||
},
|
||||
"COMMENTS": {
|
||||
"NONE": "Pas de commentaire",
|
||||
"ADD": "Ajouter un commentaire",
|
||||
"HEADER": "Commentaires",
|
||||
"DIALOG": {
|
||||
"TITLE": "Nouveau commentaire",
|
||||
"LABELS": {
|
||||
"MESSAGE": "Message"
|
||||
},
|
||||
"BUTTON": {
|
||||
"ADD": "Ajouter un commentaire",
|
||||
"CANCEL": "Annuler"
|
||||
}
|
||||
}
|
||||
},
|
||||
"CHECKLIST": {
|
||||
"NONE": "Aucune liste de contrôle"
|
||||
},
|
||||
"ERROR": {
|
||||
"TITLE": "Impossible de terminer l'action",
|
||||
"DESCRIPTION": "Réessayez ou vérifiez que vous avez le niveau d'accès requis.",
|
||||
"CLOSE": "Fermer"
|
||||
}
|
||||
},
|
||||
"FILTERS": {
|
||||
"MESSAGES": {
|
||||
"NONE": "Aucun filtre de tâches sélectionné."
|
||||
}
|
||||
},
|
||||
"START_TASK": {
|
||||
"BUTTON": "CRÉER UNE TÂCHE",
|
||||
"FORM": {
|
||||
"TITLE": "Démarrer la tâche",
|
||||
"LABEL": {
|
||||
"NONE": "Aucune",
|
||||
"NAME": "Nom",
|
||||
"DESCRIPTION": "Description",
|
||||
"ATTACHFORM": "Joindre un formulaire",
|
||||
"ASSIGNEE": "Personne assignée",
|
||||
"FORM": "Formulaire",
|
||||
"DATE": "Choisir une date"
|
||||
},
|
||||
"ACTION": {
|
||||
"START": "Démarrer",
|
||||
"CANCEL": "Annuler"
|
||||
},
|
||||
"DATE": {
|
||||
"ERROR": "Format de date JJ/MM/AAAA"
|
||||
}
|
||||
}
|
||||
},
|
||||
"PEOPLE": {
|
||||
"DIALOG_CLOSE": "FERMER",
|
||||
"ADD_USER": "AJOUTER",
|
||||
"ADD_ASSIGNEE": "ASSIGNER",
|
||||
"SEARCH_USER": "Rechercher des utilisateurs",
|
||||
"SEARCH": {
|
||||
"NO_USERS": "Aucune personne à impliquer trouvée"
|
||||
}
|
||||
},
|
||||
"ATTACHMENT": {
|
||||
"EMPTY": {
|
||||
"HEADER": "Cette liste est vide",
|
||||
"DRAG-AND-DROP": {
|
||||
"TITLE": "Glissez-déposez",
|
||||
"SUBTITLE": "les fichiers à importer"
|
||||
}
|
||||
},
|
||||
"EMPTY-LIST": {
|
||||
"HEADER": "Aucun fichier disponible"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
143
lib/process-services/i18n/it.json
Normal file
143
lib/process-services/i18n/it.json
Normal file
@@ -0,0 +1,143 @@
|
||||
{
|
||||
"DIALOG": {
|
||||
"SAVE_MESSAGE": "Fai clic su Salva per aggiungere un rapporto con le impostazioni correnti all'elenco dei rapporti.",
|
||||
"EXPORT_MESSAGE": ""
|
||||
},
|
||||
"DATE-WIDGET": {
|
||||
"START-DATE": "Data di inizio",
|
||||
"END-DATE": "Data di fine",
|
||||
"MESSAGES": {
|
||||
"START-DATE-REQUIRED": "Data di inizio richiesta",
|
||||
"START-LESS-THAN-END-DATE": "La data di inizio deve essere precedente alla data di fine"
|
||||
}
|
||||
},
|
||||
"ADF_TASK_LIST": {
|
||||
"APPS": {
|
||||
"NONE": "Nessuna applicazione trovata",
|
||||
"TASK_APP_NAME": "I miei compiti"
|
||||
},
|
||||
"LIST": {
|
||||
"MESSAGES": {
|
||||
"NONE": "Nessun elenco compiti trovato"
|
||||
}
|
||||
},
|
||||
"DETAILS": {
|
||||
"LABELS": {
|
||||
"ASSIGNEE": "Assegnatario",
|
||||
"DUE": "Scadenza",
|
||||
"FORM": "Modulo",
|
||||
"PEOPLE": "Persone con cui è condiviso questo compito",
|
||||
"COMMENTS": "Commenti",
|
||||
"CHECKLIST": "Lista di controllo",
|
||||
"INVOLVED_PEOPLE": "Persone coinvolte",
|
||||
"ADD_PEOPLE": "Aggiungi persone e gruppi",
|
||||
"ADD_ASSIGNEE": "Aggiungi nuovo assegnatario"
|
||||
},
|
||||
"BUTTON": {
|
||||
"COMPLETE": "Completa",
|
||||
"CLAIM": "Richiedi",
|
||||
"UNCLAIM": "Metti di nuovo in coda",
|
||||
"DRAG-ATTACHMENT": "Rilascia qui i file...",
|
||||
"UPLOAD-ATTACHMENT": "Carica allegato"
|
||||
},
|
||||
"MESSAGES": {
|
||||
"NONE": "Nessun dettaglio compito trovato",
|
||||
"CLAIM": "Per lavorare su questo compito, fai clic su Richiedi."
|
||||
},
|
||||
"FORM": {
|
||||
"NONE": "Nessun modulo."
|
||||
},
|
||||
"DUE": {
|
||||
"NONE": "Nessuna data di scadenza."
|
||||
},
|
||||
"ASSIGNEE": {
|
||||
"NONE": "Nessun assegnatario."
|
||||
},
|
||||
"PEOPLE": {
|
||||
"NONE": "Nessuno coinvolto."
|
||||
},
|
||||
"COMMENTS": {
|
||||
"NONE": "Nessun commento",
|
||||
"ADD": "Aggiungi un commento",
|
||||
"HEADER": "Commenti",
|
||||
"DIALOG": {
|
||||
"TITLE": "Nuovo commento",
|
||||
"LABELS": {
|
||||
"INFO_DRAWER_TITLE": "pippo",
|
||||
"INFO_DRAWER_TAB_ACTIVITY_TITLE": "Attivita",
|
||||
"INFO_DRAWER_TAB_DETAILS_TITLE": "Dettagli",
|
||||
"ASSIGNEE": "Assegnatario",
|
||||
"DUE": "Scadenza",
|
||||
"FORM": "Form",
|
||||
"PEOPLE": "Persone",
|
||||
"MESSAGE": "Messaggio",
|
||||
"COMMENTS": "Commenti",
|
||||
"CHECKLIST": "Checklist",
|
||||
"INVOLVED_PEOPLE": "Persone coinvolte",
|
||||
"ADD_PEOPLE": "Aggiungi persone & gruppi"
|
||||
},
|
||||
"BUTTON": {
|
||||
"ADD": "Aggiungi commento",
|
||||
"CANCEL": "Annulla"
|
||||
}
|
||||
}
|
||||
},
|
||||
"CHECKLIST": {
|
||||
"NONE": "Nessun elenco di controllo"
|
||||
},
|
||||
"ERROR": {
|
||||
"TITLE": "Impossibile completare l'azione",
|
||||
"DESCRIPTION": "Riprova o verifica di avere l'accesso.",
|
||||
"CLOSE": "Chiudi"
|
||||
}
|
||||
},
|
||||
"FILTERS": {
|
||||
"MESSAGES": {
|
||||
"NONE": "Nessun filtro compito selezionato."
|
||||
}
|
||||
},
|
||||
"START_TASK": {
|
||||
"BUTTON": "CREA COMPITO",
|
||||
"FORM": {
|
||||
"TITLE": "Avvia compito",
|
||||
"LABEL": {
|
||||
"NONE": "Nessuno",
|
||||
"NAME": "Nome",
|
||||
"DESCRIPTION": "Descrizione",
|
||||
"ATTACHFORM": "Allega modulo",
|
||||
"ASSIGNEE": "Assegnatario",
|
||||
"FORM": "Modulo",
|
||||
"DATE": "Scegli data"
|
||||
},
|
||||
"ACTION": {
|
||||
"START": "Avvia",
|
||||
"CANCEL": "Annulla"
|
||||
},
|
||||
"DATE": {
|
||||
"ERROR": "Formato data GG/MM/AAAA"
|
||||
}
|
||||
}
|
||||
},
|
||||
"PEOPLE": {
|
||||
"DIALOG_CLOSE": "CHIUDI",
|
||||
"ADD_USER": "Aggiungi",
|
||||
"ADD_ASSIGNEE": "ASSEGNA",
|
||||
"SEARCH_USER": "Cerca utente",
|
||||
"SEARCH": {
|
||||
"NO_USERS": "Nessun utente trovato da coinvolgere"
|
||||
}
|
||||
},
|
||||
"ATTACHMENT": {
|
||||
"EMPTY": {
|
||||
"HEADER": "Questo elenco è vuoto",
|
||||
"DRAG-AND-DROP": {
|
||||
"TITLE": "Trascinare e rilasciare",
|
||||
"SUBTITLE": "per caricare i file"
|
||||
}
|
||||
},
|
||||
"EMPTY-LIST": {
|
||||
"HEADER": "Nessun file disponibile"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
131
lib/process-services/i18n/ja.json
Normal file
131
lib/process-services/i18n/ja.json
Normal file
@@ -0,0 +1,131 @@
|
||||
{
|
||||
"DIALOG": {
|
||||
"SAVE_MESSAGE": "レポートを現在の設定でレポートリストに追加するには、[保存] をクリックします。",
|
||||
"EXPORT_MESSAGE": ""
|
||||
},
|
||||
"DATE-WIDGET": {
|
||||
"START-DATE": "開始日",
|
||||
"END-DATE": "終了日",
|
||||
"MESSAGES": {
|
||||
"START-DATE-REQUIRED": "開始日を指定してください",
|
||||
"START-LESS-THAN-END-DATE": "開始日は終了日より前の日付でなければなりません"
|
||||
}
|
||||
},
|
||||
"ADF_TASK_LIST": {
|
||||
"APPS": {
|
||||
"NONE": "アプリが見つかりません"
|
||||
},
|
||||
"LIST": {
|
||||
"MESSAGES": {
|
||||
"NONE": "タスクリストが見つかりません"
|
||||
}
|
||||
},
|
||||
"DETAILS": {
|
||||
"LABELS": {
|
||||
"ASSIGNEE": "担当者",
|
||||
"DUE": "期限",
|
||||
"FORM": "フォーム",
|
||||
"PEOPLE": "このタスクを共有しているメンバー",
|
||||
"COMMENTS": "コメント",
|
||||
"CHECKLIST": "チェックリスト",
|
||||
"INVOLVED_PEOPLE": "タスクに関わっているメンバー",
|
||||
"ADD_PEOPLE": "メンバーとグループの追加",
|
||||
"ADD_ASSIGNEE": "新しい担当者の追加"
|
||||
},
|
||||
"BUTTON": {
|
||||
"COMPLETE": "完了",
|
||||
"CLAIM": "要求",
|
||||
"UNCLAIM": "キューへの再登録",
|
||||
"DRAG-ATTACHMENT": "ここにファイルをドロップしてください...",
|
||||
"UPLOAD-ATTACHMENT": "添付ファイルをアップロード"
|
||||
},
|
||||
"MESSAGES": {
|
||||
"NONE": "タスクの詳細が見つかりません",
|
||||
"CLAIM": "このタスクの作業を行うには、[要求] をクリックします。"
|
||||
},
|
||||
"FORM": {
|
||||
"NONE": "フォームはありません。"
|
||||
},
|
||||
"DUE": {
|
||||
"NONE": "期限はありません。"
|
||||
},
|
||||
"ASSIGNEE": {
|
||||
"NONE": "担当者はありません。"
|
||||
},
|
||||
"PEOPLE": {
|
||||
"NONE": "関わっているメンバーはいません。"
|
||||
},
|
||||
"COMMENTS": {
|
||||
"NONE": "コメントなし",
|
||||
"ADD": "コメントの追加",
|
||||
"HEADER": "コメント",
|
||||
"DIALOG": {
|
||||
"TITLE": "新しいコメント",
|
||||
"LABELS": {
|
||||
"MESSAGE": "メッセージ"
|
||||
},
|
||||
"BUTTON": {
|
||||
"ADD": "コメントの追加",
|
||||
"CANCEL": "キャンセル"
|
||||
}
|
||||
}
|
||||
},
|
||||
"CHECKLIST": {
|
||||
"NONE": "チェックリストなし"
|
||||
},
|
||||
"ERROR": {
|
||||
"TITLE": "処理を完了できませんでした",
|
||||
"DESCRIPTION": "もう一度操作をやり直すか、アクセス権があることを確認してください。",
|
||||
"CLOSE": "閉じる"
|
||||
}
|
||||
},
|
||||
"FILTERS": {
|
||||
"MESSAGES": {
|
||||
"NONE": "タスクのフィルタが選択されていません。"
|
||||
}
|
||||
},
|
||||
"START_TASK": {
|
||||
"BUTTON": "タスクの作成",
|
||||
"FORM": {
|
||||
"TITLE": "タスクの開始",
|
||||
"LABEL": {
|
||||
"NONE": "なし",
|
||||
"NAME": "名前",
|
||||
"DESCRIPTION": "説明",
|
||||
"ATTACHFORM": "フォームの添付",
|
||||
"ASSIGNEE": "担当者",
|
||||
"FORM": "フォーム",
|
||||
"DATE": "日付を選択してください"
|
||||
},
|
||||
"ACTION": {
|
||||
"START": "開始",
|
||||
"CANCEL": "キャンセル"
|
||||
},
|
||||
"DATE": {
|
||||
"ERROR": "日付形式: YYYY/MM/DD"
|
||||
}
|
||||
}
|
||||
},
|
||||
"PEOPLE": {
|
||||
"DIALOG_CLOSE": "閉じる",
|
||||
"ADD_USER": "追加",
|
||||
"ADD_ASSIGNEE": "割り当て",
|
||||
"SEARCH_USER": "ユーザーの検索",
|
||||
"SEARCH": {
|
||||
"NO_USERS": "タスクに関わっているメンバーが見つかりません"
|
||||
}
|
||||
},
|
||||
"ATTACHMENT": {
|
||||
"EMPTY": {
|
||||
"HEADER": "このリストは空です",
|
||||
"DRAG-AND-DROP": {
|
||||
"TITLE": "アップロードするファイルをドラッグ & ドロップしてください",
|
||||
"SUBTITLE": ""
|
||||
}
|
||||
},
|
||||
"EMPTY-LIST": {
|
||||
"HEADER": "使用できるファイルがありません"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
131
lib/process-services/i18n/nb.json
Normal file
131
lib/process-services/i18n/nb.json
Normal file
@@ -0,0 +1,131 @@
|
||||
{
|
||||
"DIALOG": {
|
||||
"SAVE_MESSAGE": "Klikk på Lagre for å legge til en rapport med gjeldende innstillinger til rapportlisten.",
|
||||
"EXPORT_MESSAGE": ""
|
||||
},
|
||||
"DATE-WIDGET": {
|
||||
"START-DATE": "Startdato",
|
||||
"END-DATE": "Sluttdato",
|
||||
"MESSAGES": {
|
||||
"START-DATE-REQUIRED": "Startdato er påkrevd",
|
||||
"START-LESS-THAN-END-DATE": "Startdato må være før sluttdato"
|
||||
}
|
||||
},
|
||||
"ADF_TASK_LIST": {
|
||||
"APPS": {
|
||||
"NONE": "Ingen apper funnet"
|
||||
},
|
||||
"LIST": {
|
||||
"MESSAGES": {
|
||||
"NONE": "Ingen oppgaveliste funnet"
|
||||
}
|
||||
},
|
||||
"DETAILS": {
|
||||
"LABELS": {
|
||||
"ASSIGNEE": "Tilordnet",
|
||||
"DUE": "Forfaller",
|
||||
"FORM": "Skjema",
|
||||
"PEOPLE": "Folk som denne oppgaven deles med",
|
||||
"COMMENTS": "Kommentarer",
|
||||
"CHECKLIST": "Sjekkliste",
|
||||
"INVOLVED_PEOPLE": "Folk involvert",
|
||||
"ADD_PEOPLE": "Legg til folk og grupper",
|
||||
"ADD_ASSIGNEE": "Legg til ny tilordnet"
|
||||
},
|
||||
"BUTTON": {
|
||||
"COMPLETE": "Fullfør",
|
||||
"CLAIM": "Krev",
|
||||
"UNCLAIM": "Legg tilbake i kø",
|
||||
"DRAG-ATTACHMENT": "Slipp filer her...",
|
||||
"UPLOAD-ATTACHMENT": "Last opp vedlegg"
|
||||
},
|
||||
"MESSAGES": {
|
||||
"NONE": "Ingen oppgavedetaljer funnet",
|
||||
"CLAIM": "Klikk på Krev for å jobbe med denne oppgaven."
|
||||
},
|
||||
"FORM": {
|
||||
"NONE": "Ingen skjema."
|
||||
},
|
||||
"DUE": {
|
||||
"NONE": "Ingen forfallsdato."
|
||||
},
|
||||
"ASSIGNEE": {
|
||||
"NONE": "Ingen tilordnet."
|
||||
},
|
||||
"PEOPLE": {
|
||||
"NONE": "Ingen involvert."
|
||||
},
|
||||
"COMMENTS": {
|
||||
"NONE": "Ingen kommentarer",
|
||||
"ADD": "Legg til en kommentar",
|
||||
"HEADER": "Kommentarer",
|
||||
"DIALOG": {
|
||||
"TITLE": "Nytt kommentar",
|
||||
"LABELS": {
|
||||
"MESSAGE": "Melding"
|
||||
},
|
||||
"BUTTON": {
|
||||
"ADD": "Legg til kommentar",
|
||||
"CANCEL": "Avbryt"
|
||||
}
|
||||
}
|
||||
},
|
||||
"CHECKLIST": {
|
||||
"NONE": "Ingen sjekkliste"
|
||||
},
|
||||
"ERROR": {
|
||||
"TITLE": "Kan ikke fullføre handlingen",
|
||||
"DESCRIPTION": "Prøve på nytt, eller kontroller at du har tilgang.",
|
||||
"CLOSE": "Lukk"
|
||||
}
|
||||
},
|
||||
"FILTERS": {
|
||||
"MESSAGES": {
|
||||
"NONE": "Ingen oppgavefilter valgt."
|
||||
}
|
||||
},
|
||||
"START_TASK": {
|
||||
"BUTTON": "OPPRETT OPPGAVE",
|
||||
"FORM": {
|
||||
"TITLE": "Start oppgave",
|
||||
"LABEL": {
|
||||
"NONE": "Ingen",
|
||||
"NAME": "Navn",
|
||||
"DESCRIPTION": "Beskrivelse",
|
||||
"ATTACHFORM": "Legg ved skjema",
|
||||
"ASSIGNEE": "Tilordnet",
|
||||
"FORM": "Skjema",
|
||||
"DATE": "Velg dato"
|
||||
},
|
||||
"ACTION": {
|
||||
"START": "Start",
|
||||
"CANCEL": "Avbryt"
|
||||
},
|
||||
"DATE": {
|
||||
"ERROR": "Datoformat DD/MM/ÅÅÅÅ"
|
||||
}
|
||||
}
|
||||
},
|
||||
"PEOPLE": {
|
||||
"DIALOG_CLOSE": "LUKK",
|
||||
"ADD_USER": "LEGG TIL",
|
||||
"ADD_ASSIGNEE": "TILORDNE",
|
||||
"SEARCH_USER": "Søk etter bruker",
|
||||
"SEARCH": {
|
||||
"NO_USERS": "Ingen funnet å involvere"
|
||||
}
|
||||
},
|
||||
"ATTACHMENT": {
|
||||
"EMPTY": {
|
||||
"HEADER": "Denne listen er tom",
|
||||
"DRAG-AND-DROP": {
|
||||
"TITLE": "Dra og slipp",
|
||||
"SUBTITLE": "for å laste opp filer"
|
||||
}
|
||||
},
|
||||
"EMPTY-LIST": {
|
||||
"HEADER": "Ingen tilgjengelige filer"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
131
lib/process-services/i18n/nl.json
Normal file
131
lib/process-services/i18n/nl.json
Normal file
@@ -0,0 +1,131 @@
|
||||
{
|
||||
"DIALOG": {
|
||||
"SAVE_MESSAGE": "Klik op Opslaan om een rapport met de huidige instellingen toe te voegen aan uw lijst met rapporten.",
|
||||
"EXPORT_MESSAGE": ""
|
||||
},
|
||||
"DATE-WIDGET": {
|
||||
"START-DATE": "Begindatum",
|
||||
"END-DATE": "Einddatum",
|
||||
"MESSAGES": {
|
||||
"START-DATE-REQUIRED": "Begindatum is vereist",
|
||||
"START-LESS-THAN-END-DATE": "De begindatum moet voor de einddatum liggen"
|
||||
}
|
||||
},
|
||||
"ADF_TASK_LIST": {
|
||||
"APPS": {
|
||||
"NONE": "Geen apps gevonden"
|
||||
},
|
||||
"TASK_LIST": {
|
||||
"MESSAGES": {
|
||||
"NONE": "Geen takenlijst gevonden"
|
||||
}
|
||||
},
|
||||
"DETAILS": {
|
||||
"LABELS": {
|
||||
"ASSIGNEE": "Toegewezen persoon",
|
||||
"DUE": "Vervalt",
|
||||
"FORM": "Formulier",
|
||||
"PEOPLE": "Personen met wie deze taak is gedeeld",
|
||||
"COMMENTS": "Opmerkingen",
|
||||
"CHECKLIST": "Controlelijst",
|
||||
"INVOLVED_PEOPLE": "Betrokken personen",
|
||||
"ADD_PEOPLE": "Personen en groepen toevoegen",
|
||||
"ADD_ASSIGNEE": "Nieuwe uitvoerder toevoegen"
|
||||
},
|
||||
"BUTTON": {
|
||||
"COMPLETE": "Voltooid",
|
||||
"CLAIM": "Claimen",
|
||||
"UNCLAIM": "Opnieuw in wachtrij plaatsen",
|
||||
"DRAG-ATTACHMENT": "Bestanden hier neerzetten...",
|
||||
"UPLOAD-ATTACHMENT": "Bijlage uploaden"
|
||||
},
|
||||
"MESSAGES": {
|
||||
"NONE": "Geen taakdetails gevonden",
|
||||
"CLAIM": "Klik op Claimen om aan deze taak te werken."
|
||||
},
|
||||
"FORM": {
|
||||
"NONE": "Geen formulier."
|
||||
},
|
||||
"DUE": {
|
||||
"NONE": "Geen einddatum."
|
||||
},
|
||||
"ASSIGNEE": {
|
||||
"NONE": "Geen uitvoerder."
|
||||
},
|
||||
"PEOPLE": {
|
||||
"NONE": "Niemand betrokken."
|
||||
},
|
||||
"COMMENTS": {
|
||||
"NONE": "Geen opmerkingen",
|
||||
"ADD": "Een opmerking toevoegen",
|
||||
"HEADER": "Opmerkingen",
|
||||
"DIALOG": {
|
||||
"TITLE": "Nieuwe opmerking",
|
||||
"LABELS": {
|
||||
"MESSAGE": "Bericht"
|
||||
},
|
||||
"BUTTON": {
|
||||
"ADD": "Opmerking toevoegen",
|
||||
"CANCEL": "Annuleren"
|
||||
}
|
||||
}
|
||||
},
|
||||
"CHECKLIST": {
|
||||
"NONE": "Geen controlelijst"
|
||||
},
|
||||
"ERROR": {
|
||||
"TITLE": "Kan de actie niet voltooien",
|
||||
"DESCRIPTION": "Probeer het opnieuw of controleer of u over toegang beschikt.",
|
||||
"CLOSE": "Sluiten"
|
||||
}
|
||||
},
|
||||
"FILTERS": {
|
||||
"MESSAGES": {
|
||||
"NONE": "Geen taakfilter geselecteerd."
|
||||
}
|
||||
},
|
||||
"START_TASK": {
|
||||
"BUTTON": "TAAK MAKEN",
|
||||
"FORM": {
|
||||
"TITLE": "Begintaak",
|
||||
"LABEL": {
|
||||
"NONE": "Geen",
|
||||
"NAME": "Naam",
|
||||
"DESCRIPTION": "Beschrijving",
|
||||
"ATTACHFORM": "Formulier bijvoegen",
|
||||
"ASSIGNEE": "Toegewezen persoon",
|
||||
"FORM": "Formulier",
|
||||
"DATE": "Datum kiezen"
|
||||
},
|
||||
"ACTION": {
|
||||
"START": "Start",
|
||||
"CANCEL": "Annuleren"
|
||||
},
|
||||
"DATE": {
|
||||
"ERROR": "Datumnotatie dd-mm-jjjj"
|
||||
}
|
||||
}
|
||||
},
|
||||
"PEOPLE": {
|
||||
"DIALOG_CLOSE": "SLUITEN",
|
||||
"ADD_USER": "TOEVOEGEN",
|
||||
"ADD_ASSIGNEE": "TOEWIJZEN",
|
||||
"SEARCH_USER": "Gebruiker zoeken",
|
||||
"SEARCH": {
|
||||
"NO_USERS": "Niemand gevonden om te betrekken"
|
||||
}
|
||||
},
|
||||
"ATTACHMENT": {
|
||||
"EMPTY": {
|
||||
"HEADER": "Deze lijst is leeg",
|
||||
"DRAG-AND-DROP": {
|
||||
"TITLE": "Slepen en neerzetten",
|
||||
"SUBTITLE": "om bestanden te uploaden"
|
||||
}
|
||||
},
|
||||
"EMPTY-LIST": {
|
||||
"HEADER": "Er zijn geen bestanden beschikbaar"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
131
lib/process-services/i18n/pt-BR.json
Normal file
131
lib/process-services/i18n/pt-BR.json
Normal file
@@ -0,0 +1,131 @@
|
||||
{
|
||||
"DIALOG": {
|
||||
"SAVE_MESSAGE": "Clique em Salvar para adicionar um relatório com as configurações atuais à sua lista de relatórios.",
|
||||
"EXPORT_MESSAGE": ""
|
||||
},
|
||||
"DATE-WIDGET": {
|
||||
"START-DATE": "Data de início",
|
||||
"END-DATE": "Data de término",
|
||||
"MESSAGES": {
|
||||
"START-DATE-REQUIRED": "A data de início é obrigatória",
|
||||
"START-LESS-THAN-END-DATE": "A data de início deve ser anterior à data de término"
|
||||
}
|
||||
},
|
||||
"ADF_TASK_LIST": {
|
||||
"APPS": {
|
||||
"NONE": "Nenhum aplicativo encontrado"
|
||||
},
|
||||
"LIST": {
|
||||
"MESSAGES": {
|
||||
"NONE": "Nenhuma lista de tarefas encontrada"
|
||||
}
|
||||
},
|
||||
"DETAILS": {
|
||||
"LABELS": {
|
||||
"ASSIGNEE": "Destinatário",
|
||||
"DUE": "Vencimento",
|
||||
"FORM": "Formulário",
|
||||
"PEOPLE": "Pessoas com quem esta tarefa foi compartilhada",
|
||||
"COMMENTS": "Comentários",
|
||||
"CHECKLIST": "Lista de verificação",
|
||||
"INVOLVED_PEOPLE": "Pessoas Envolvidas",
|
||||
"ADD_PEOPLE": "Adicionar pessoas e grupos",
|
||||
"ADD_ASSIGNEE": "Adicionar novo destinatário"
|
||||
},
|
||||
"BUTTON": {
|
||||
"COMPLETE": "Concluído",
|
||||
"CLAIM": "Reivindicar",
|
||||
"UNCLAIM": "Recolocar na fila",
|
||||
"DRAG-ATTACHMENT": "Soltar os arquivos aqui...",
|
||||
"UPLOAD-ATTACHMENT": "Carregar anexo"
|
||||
},
|
||||
"MESSAGES": {
|
||||
"NONE": "Nenhum detalhe de tarefa encontrado",
|
||||
"CLAIM": "Para trabalhar nesta tarefa, clique em Reivindicar."
|
||||
},
|
||||
"FORM": {
|
||||
"NONE": "Nenhum formulário."
|
||||
},
|
||||
"DUE": {
|
||||
"NONE": "Nenhuma data de vencimento."
|
||||
},
|
||||
"ASSIGNEE": {
|
||||
"NONE": "Nenhum destinatário."
|
||||
},
|
||||
"PEOPLE": {
|
||||
"NONE": "Ninguém envolvido."
|
||||
},
|
||||
"COMMENTS": {
|
||||
"NONE": "Sem comentários",
|
||||
"ADD": "Adicionar comentário",
|
||||
"HEADER": "Comentários",
|
||||
"DIALOG": {
|
||||
"TITLE": "Novo comentário",
|
||||
"LABELS": {
|
||||
"MESSAGE": "Mensagem"
|
||||
},
|
||||
"BUTTON": {
|
||||
"ADD": "Adicionar comentário",
|
||||
"CANCEL": "Cancelar"
|
||||
}
|
||||
}
|
||||
},
|
||||
"CHECKLIST": {
|
||||
"NONE": "Nenhuma lista de verificação"
|
||||
},
|
||||
"ERROR": {
|
||||
"TITLE": "Não foi possível concluir a ação",
|
||||
"DESCRIPTION": "Tente novamente ou verifique se você tem acesso.",
|
||||
"CLOSE": "Fechar"
|
||||
}
|
||||
},
|
||||
"FILTERS": {
|
||||
"MESSAGES": {
|
||||
"NONE": "Nenhum filtro de tarefa selecionado."
|
||||
}
|
||||
},
|
||||
"START_TASK": {
|
||||
"BUTTON": "CRIAR TAREFA",
|
||||
"FORM": {
|
||||
"TITLE": "Iniciar Tarefa",
|
||||
"LABEL": {
|
||||
"NONE": "Nenhum",
|
||||
"NAME": "Nome",
|
||||
"DESCRIPTION": "Descrição",
|
||||
"ATTACHFORM": "Anexar Formulário",
|
||||
"ASSIGNEE": "Destinatário",
|
||||
"FORM": "Formulário",
|
||||
"DATE": "Escolher Data"
|
||||
},
|
||||
"ACTION": {
|
||||
"START": "Iniciar",
|
||||
"CANCEL": "Cancelar"
|
||||
},
|
||||
"DATE": {
|
||||
"ERROR": "Formato de data DD/MM/AAAA"
|
||||
}
|
||||
}
|
||||
},
|
||||
"PEOPLE": {
|
||||
"DIALOG_CLOSE": "FECHAR",
|
||||
"ADD_USER": "ADICIONAR",
|
||||
"ADD_ASSIGNEE": "ATRIBUIR",
|
||||
"SEARCH_USER": "Pesquisar usuário",
|
||||
"SEARCH": {
|
||||
"NO_USERS": "Ninguém para envolver"
|
||||
}
|
||||
},
|
||||
"ATTACHMENT": {
|
||||
"EMPTY": {
|
||||
"HEADER": "Esta lista está vazia",
|
||||
"DRAG-AND-DROP": {
|
||||
"TITLE": "Arraste e solte",
|
||||
"SUBTITLE": "para carregar arquivos"
|
||||
}
|
||||
},
|
||||
"EMPTY-LIST": {
|
||||
"HEADER": "Nenhum arquivo disponível"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
131
lib/process-services/i18n/ru.json
Normal file
131
lib/process-services/i18n/ru.json
Normal file
@@ -0,0 +1,131 @@
|
||||
{
|
||||
"DIALOG": {
|
||||
"SAVE_MESSAGE": "Нажмите Сохранить, чтобы добавить отчет с текущими параметрами в список отчетов.",
|
||||
"EXPORT_MESSAGE": ""
|
||||
},
|
||||
"DATE-WIDGET": {
|
||||
"START-DATE": "Дата начала",
|
||||
"END-DATE": "Дата окончания",
|
||||
"MESSAGES": {
|
||||
"START-DATE-REQUIRED": "Необходимо указать дату начала",
|
||||
"START-LESS-THAN-END-DATE": "Дата начала должна быть раньше даты окончания"
|
||||
}
|
||||
},
|
||||
"ADF_TASK_LIST": {
|
||||
"APPS": {
|
||||
"NONE": "Приложения не найдены"
|
||||
},
|
||||
"LIST": {
|
||||
"MESSAGES": {
|
||||
"NONE": "Не найдено ни одного списка задач"
|
||||
}
|
||||
},
|
||||
"DETAILS": {
|
||||
"LABELS": {
|
||||
"ASSIGNEE": "Исполнитель",
|
||||
"DUE": "Срок",
|
||||
"FORM": "Форма",
|
||||
"PEOPLE": "Люди, имеющие доступ к данной задаче",
|
||||
"COMMENTS": "Комментарии",
|
||||
"CHECKLIST": "Контрольный список",
|
||||
"INVOLVED_PEOPLE": "Участвующие лица",
|
||||
"ADD_PEOPLE": "Добавить людей и группы",
|
||||
"ADD_ASSIGNEE": "Добавить нового исполнителя"
|
||||
},
|
||||
"BUTTON": {
|
||||
"COMPLETE": "Завершить",
|
||||
"CLAIM": "Я выполню это",
|
||||
"UNCLAIM": "Повторно поставить в очередь",
|
||||
"DRAG-ATTACHMENT": "Перетащите файлы сюда...",
|
||||
"UPLOAD-ATTACHMENT": "Выгрузить приложение"
|
||||
},
|
||||
"MESSAGES": {
|
||||
"NONE": "Сведения о задаче не найдены",
|
||||
"CLAIM": "Для работы над этой задачей нажмите кнопку Я выполню это."
|
||||
},
|
||||
"FORM": {
|
||||
"NONE": "Нет формы."
|
||||
},
|
||||
"DUE": {
|
||||
"NONE": "Нет даты выполнения."
|
||||
},
|
||||
"ASSIGNEE": {
|
||||
"NONE": "Нет исполнителя."
|
||||
},
|
||||
"PEOPLE": {
|
||||
"NONE": "Нет участвующих лиц."
|
||||
},
|
||||
"COMMENTS": {
|
||||
"NONE": "Нет комментариев",
|
||||
"ADD": "Добавить комментарий",
|
||||
"HEADER": "Комментарии",
|
||||
"DIALOG": {
|
||||
"TITLE": "Новый комментарий",
|
||||
"LABELS": {
|
||||
"MESSAGE": "Сообщение"
|
||||
},
|
||||
"BUTTON": {
|
||||
"ADD": "Добавить комментарий",
|
||||
"CANCEL": "Отмена"
|
||||
}
|
||||
}
|
||||
},
|
||||
"CHECKLIST": {
|
||||
"NONE": "Нет контрольных списков"
|
||||
},
|
||||
"ERROR": {
|
||||
"TITLE": "Не удалось выполнить действие",
|
||||
"DESCRIPTION": "Повторите попытку или убедитесь, что у вас есть доступ.",
|
||||
"CLOSE": "Закрыть"
|
||||
}
|
||||
},
|
||||
"FILTERS": {
|
||||
"MESSAGES": {
|
||||
"NONE": "Фильтр задач не выбран."
|
||||
}
|
||||
},
|
||||
"START_TASK": {
|
||||
"BUTTON": "СОЗДАТЬ ЗАДАЧУ",
|
||||
"FORM": {
|
||||
"TITLE": "Начать задачу",
|
||||
"LABEL": {
|
||||
"NONE": "Нет",
|
||||
"NAME": "Имя",
|
||||
"DESCRIPTION": "Описание",
|
||||
"ATTACHFORM": "Прикрепить форму",
|
||||
"ASSIGNEE": "Исполнитель",
|
||||
"FORM": "Форма",
|
||||
"DATE": "Выберите дату"
|
||||
},
|
||||
"ACTION": {
|
||||
"START": "Начало",
|
||||
"CANCEL": "Отмена"
|
||||
},
|
||||
"DATE": {
|
||||
"ERROR": "Формат даты ДД.ММ.ГГГГ"
|
||||
}
|
||||
}
|
||||
},
|
||||
"PEOPLE": {
|
||||
"DIALOG_CLOSE": "ЗАКРЫТЬ",
|
||||
"ADD_USER": "ДОБАВИТЬ",
|
||||
"ADD_ASSIGNEE": "НАЗНАЧИТЬ",
|
||||
"SEARCH_USER": "Искать пользователя",
|
||||
"SEARCH": {
|
||||
"NO_USERS": "Участвующие лица не найдены"
|
||||
}
|
||||
},
|
||||
"ATTACHMENT": {
|
||||
"EMPTY": {
|
||||
"HEADER": "Этот список пуст",
|
||||
"DRAG-AND-DROP": {
|
||||
"TITLE": "Перетащите",
|
||||
"SUBTITLE": "для выгрузки файлов"
|
||||
}
|
||||
},
|
||||
"EMPTY-LIST": {
|
||||
"HEADER": "Нет файлов"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
131
lib/process-services/i18n/zh-CN.json
Normal file
131
lib/process-services/i18n/zh-CN.json
Normal file
@@ -0,0 +1,131 @@
|
||||
{
|
||||
"DIALOG": {
|
||||
"SAVE_MESSAGE": "单击保存以用当前设置将报告添加至报告列表。",
|
||||
"EXPORT_MESSAGE": ""
|
||||
},
|
||||
"DATE-WIDGET": {
|
||||
"START-DATE": "启动日期",
|
||||
"END-DATE": "结束日期",
|
||||
"MESSAGES": {
|
||||
"START-DATE-REQUIRED": "需要启动日期",
|
||||
"START-LESS-THAN-END-DATE": "启动日期必须在结束日期前"
|
||||
}
|
||||
},
|
||||
"ADF_TASK_LIST": {
|
||||
"APPS": {
|
||||
"NONE": "未找到应用程序"
|
||||
},
|
||||
"LIST": {
|
||||
"MESSAGES": {
|
||||
"NONE": "未找到任务列表"
|
||||
}
|
||||
},
|
||||
"DETAILS": {
|
||||
"LABELS": {
|
||||
"ASSIGNEE": "被指派者",
|
||||
"DUE": "截止时间",
|
||||
"FORM": "表单",
|
||||
"PEOPLE": "此任务分享的人员",
|
||||
"COMMENTS": "注释",
|
||||
"CHECKLIST": "检查表",
|
||||
"INVOLVED_PEOPLE": "涉及的人员",
|
||||
"ADD_PEOPLE": "添加人和组",
|
||||
"ADD_ASSIGNEE": "添加新的被分配人员"
|
||||
},
|
||||
"BUTTON": {
|
||||
"COMPLETE": "完成",
|
||||
"CLAIM": "申领",
|
||||
"UNCLAIM": "重新排队",
|
||||
"DRAG-ATTACHMENT": "将文件放到此处...",
|
||||
"UPLOAD-ATTACHMENT": "上传附件"
|
||||
},
|
||||
"MESSAGES": {
|
||||
"NONE": "未找到任务详情",
|
||||
"CLAIM": "要执行此任务,单击申领。"
|
||||
},
|
||||
"FORM": {
|
||||
"NONE": "无格式。"
|
||||
},
|
||||
"DUE": {
|
||||
"NONE": "无过期时间。"
|
||||
},
|
||||
"ASSIGNEE": {
|
||||
"NONE": "无被分配人员。"
|
||||
},
|
||||
"PEOPLE": {
|
||||
"NONE": "未涉及任何人。"
|
||||
},
|
||||
"COMMENTS": {
|
||||
"NONE": "无注释",
|
||||
"ADD": "添加注释",
|
||||
"HEADER": "注释",
|
||||
"DIALOG": {
|
||||
"TITLE": "新建注释",
|
||||
"LABELS": {
|
||||
"MESSAGE": "消息"
|
||||
},
|
||||
"BUTTON": {
|
||||
"ADD": "添加注释",
|
||||
"CANCEL": "取消"
|
||||
}
|
||||
}
|
||||
},
|
||||
"CHECKLIST": {
|
||||
"NONE": "没有检查表"
|
||||
},
|
||||
"ERROR": {
|
||||
"TITLE": "无法完成此操作",
|
||||
"DESCRIPTION": "请重试或检查您是否具有访问权。",
|
||||
"CLOSE": "关闭"
|
||||
}
|
||||
},
|
||||
"FILTERS": {
|
||||
"MESSAGES": {
|
||||
"NONE": "未选择任务过滤器。"
|
||||
}
|
||||
},
|
||||
"START_TASK": {
|
||||
"BUTTON": "创建任务",
|
||||
"FORM": {
|
||||
"TITLE": "启动任务",
|
||||
"LABEL": {
|
||||
"NONE": "无",
|
||||
"NAME": "名称",
|
||||
"DESCRIPTION": "说明",
|
||||
"ATTACHFORM": "附加表单",
|
||||
"ASSIGNEE": "被指派者",
|
||||
"FORM": "表单",
|
||||
"DATE": "选择日期"
|
||||
},
|
||||
"ACTION": {
|
||||
"START": "启动",
|
||||
"CANCEL": "取消"
|
||||
},
|
||||
"DATE": {
|
||||
"ERROR": "日期格式:年/月/日"
|
||||
}
|
||||
}
|
||||
},
|
||||
"PEOPLE": {
|
||||
"DIALOG_CLOSE": "关闭",
|
||||
"ADD_USER": "添加",
|
||||
"ADD_ASSIGNEE": "分配",
|
||||
"SEARCH_USER": "搜索用户",
|
||||
"SEARCH": {
|
||||
"NO_USERS": "没找到涉及的人员"
|
||||
}
|
||||
},
|
||||
"ATTACHMENT": {
|
||||
"EMPTY": {
|
||||
"HEADER": "此列表为空",
|
||||
"DRAG-AND-DROP": {
|
||||
"TITLE": "拖放",
|
||||
"SUBTITLE": "要上传文件"
|
||||
}
|
||||
},
|
||||
"EMPTY-LIST": {
|
||||
"HEADER": "没有可用文件"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
25
lib/process-services/index.ts
Normal file
25
lib/process-services/index.ts
Normal file
@@ -0,0 +1,25 @@
|
||||
/*!
|
||||
* @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.
|
||||
*/
|
||||
|
||||
export * from './process-list';
|
||||
export * from './task-list';
|
||||
export * from './app-list';
|
||||
export * from './attachment';
|
||||
export * from './comments';
|
||||
export * from './people';
|
||||
|
||||
export * from './process.module';
|
44
lib/process-services/karma-test-shim.js
Normal file
44
lib/process-services/karma-test-shim.js
Normal file
@@ -0,0 +1,44 @@
|
||||
Error.stackTraceLimit = Infinity;
|
||||
|
||||
require('core-js/es6');
|
||||
require('core-js/es7/reflect');
|
||||
|
||||
require('zone.js/dist/zone');
|
||||
require('zone.js/dist/long-stack-trace-zone');
|
||||
require('zone.js/dist/proxy');
|
||||
require('zone.js/dist/sync-test');
|
||||
require('zone.js/dist/jasmine-patch');
|
||||
require('zone.js/dist/async-test');
|
||||
require('zone.js/dist/fake-async-test');
|
||||
|
||||
jasmine.DEFAULT_TIMEOUT_INTERVAL = 20000;
|
||||
|
||||
var appContext = require.context(".", true, /.spec.ts/);appContext.keys().forEach(appContext);
|
||||
|
||||
const TestBed = require('@angular/core/testing').TestBed;
|
||||
const browser = require('@angular/platform-browser-dynamic/testing');
|
||||
const CoreModule = require('@alfresco/core').CoreModule;
|
||||
const AppConfigService = require('@alfresco/core').AppConfigService;
|
||||
const AppConfigServiceMock = require('@alfresco/core').AppConfigServiceMock;
|
||||
const TranslationService = require('@alfresco/core').TranslationService;
|
||||
const TranslationMock = require('@alfresco/core').TranslationMock;
|
||||
const TranslateModule = require('@ngx-translate/core').TranslateModule;
|
||||
const CommonModule = require('@angular/common').CommonModule;
|
||||
const FormsModule = require('@angular/forms').FormsModule;
|
||||
const ReactiveFormsModule = require('@angular/forms').ReactiveFormsModule;
|
||||
|
||||
TestBed.initTestEnvironment(browser.BrowserDynamicTestingModule, browser.platformBrowserDynamicTesting());
|
||||
|
||||
beforeEach(() => {
|
||||
TestBed.configureTestingModule({
|
||||
imports: [CoreModule, TranslateModule, CommonModule, FormsModule, ReactiveFormsModule],
|
||||
providers: [
|
||||
{provide: AppConfigService, useClass: AppConfigServiceMock},
|
||||
{provide: TranslationService, useClass: TranslationMock}
|
||||
]
|
||||
});
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
TestBed.resetTestingModule();
|
||||
});
|
44
lib/process-services/material.module.ts
Normal file
44
lib/process-services/material.module.ts
Normal file
@@ -0,0 +1,44 @@
|
||||
/*!
|
||||
* @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 { NgModule } from '@angular/core';
|
||||
import {
|
||||
MAT_PLACEHOLDER_GLOBAL_OPTIONS, MatAutocompleteModule, MatButtonModule, MatCardModule, MatCheckboxModule,
|
||||
MatChipsModule, MatDatepickerModule, MatDialogModule, MatGridListModule, MatIconModule,
|
||||
MatInputModule, MatListModule, MatNativeDateModule, MatOptionModule, MatProgressSpinnerModule, MatRadioModule,
|
||||
MatRippleModule, MatSelectModule, MatSlideToggleModule, MatTableModule, MatTabsModule,
|
||||
MatTooltipModule
|
||||
} from '@angular/material';
|
||||
|
||||
export function modules() {
|
||||
return [
|
||||
MatAutocompleteModule, MatButtonModule, MatCardModule, MatDialogModule,
|
||||
MatCheckboxModule, MatDatepickerModule, MatGridListModule, MatIconModule, MatInputModule,
|
||||
MatListModule, MatOptionModule, MatRadioModule, MatSelectModule, MatSlideToggleModule, MatTableModule,
|
||||
MatTabsModule, MatProgressSpinnerModule, MatNativeDateModule, MatRippleModule, MatTooltipModule,
|
||||
MatChipsModule
|
||||
];
|
||||
}
|
||||
|
||||
@NgModule({
|
||||
providers: [
|
||||
{provide: MAT_PLACEHOLDER_GLOBAL_OPTIONS, useValue: { float: 'never' }}
|
||||
],
|
||||
imports: modules(),
|
||||
exports: modules()
|
||||
})
|
||||
export class MaterialModule {}
|
79
lib/process-services/mock/apps-list.mock.ts
Normal file
79
lib/process-services/mock/apps-list.mock.ts
Normal file
@@ -0,0 +1,79 @@
|
||||
/*!
|
||||
* @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 { AppDefinitionRepresentationModel } from '../task-list';
|
||||
|
||||
export let nonDeployedApps = [new AppDefinitionRepresentationModel({
|
||||
id: '1',
|
||||
name: '1',
|
||||
icon: 'icon1'
|
||||
}), new AppDefinitionRepresentationModel({
|
||||
id: '1',
|
||||
name: '2',
|
||||
icon: 'icon2'
|
||||
}), new AppDefinitionRepresentationModel({
|
||||
id: '1',
|
||||
name: '3',
|
||||
icon: 'icon3'
|
||||
})];
|
||||
export let deployedApps = [new AppDefinitionRepresentationModel({
|
||||
id: 1,
|
||||
name: 'App1',
|
||||
icon: 'icon1',
|
||||
deploymentId: '1',
|
||||
defaultAppId: 'fake-app-1',
|
||||
modelId: null,
|
||||
tenantId: null
|
||||
}), new AppDefinitionRepresentationModel({
|
||||
id: 2,
|
||||
name: 'App2',
|
||||
icon: 'icon2',
|
||||
deploymentId: '2',
|
||||
modelId: null,
|
||||
tenantId: null
|
||||
}), new AppDefinitionRepresentationModel({
|
||||
id: 3,
|
||||
name: 'App3',
|
||||
icon: 'icon3',
|
||||
deploymentId: '3',
|
||||
modelId: null,
|
||||
tenantId: null
|
||||
}), new AppDefinitionRepresentationModel({
|
||||
id: 4,
|
||||
name: 'App4',
|
||||
icon: 'icon4',
|
||||
deploymentId: '4',
|
||||
modelId: 65,
|
||||
tenantId: null
|
||||
}), new AppDefinitionRepresentationModel({
|
||||
id: 5,
|
||||
name: 'App5',
|
||||
icon: 'icon5',
|
||||
deploymentId: '5',
|
||||
modelId: 66,
|
||||
tenantId: 9
|
||||
}), new AppDefinitionRepresentationModel({
|
||||
id: 6,
|
||||
name: 'App6',
|
||||
icon: 'icon6',
|
||||
deploymentId: '6',
|
||||
tenantId: 9,
|
||||
modelId: 66
|
||||
})];
|
||||
export let defaultApp = [new AppDefinitionRepresentationModel({
|
||||
defaultAppId: 'tasks'
|
||||
})];
|
18
lib/process-services/mock/index.ts
Normal file
18
lib/process-services/mock/index.ts
Normal file
@@ -0,0 +1,18 @@
|
||||
/*!
|
||||
* @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.
|
||||
*/
|
||||
|
||||
export * from './public-api';
|
@@ -0,0 +1,74 @@
|
||||
/*!
|
||||
* @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 { ProcessInstance } from '../../process-list/models/process-instance.model';
|
||||
|
||||
export let fakeProcessInstance = [
|
||||
new ProcessInstance({
|
||||
id: 1,
|
||||
name: 'Process 773443333',
|
||||
processDefinitionId: 'fakeprocess:5:7507',
|
||||
processDefinitionKey: 'fakeprocess',
|
||||
processDefinitionName: 'Fake Process Name',
|
||||
description: null, category: null,
|
||||
started: '2015-11-09T12:36:14.184+0000',
|
||||
startedBy: {
|
||||
id: 3, firstName: 'tenant2', lastName: 'tenantLastname', email: 'tenant2@tenant'
|
||||
}
|
||||
}),
|
||||
new ProcessInstance({
|
||||
id: 2,
|
||||
name: 'Process 382927392',
|
||||
processDefinitionId: 'fakeprocess:5:7507',
|
||||
processDefinitionKey: 'fakeprocess',
|
||||
processDefinitionName: 'Fake Process Name',
|
||||
description: null,
|
||||
category: null,
|
||||
started: '2017-11-09T12:37:25.184+0000',
|
||||
startedBy: {
|
||||
id: 3, firstName: 'tenant2', lastName: 'tenantLastname', email: 'tenant2@tenant'
|
||||
}
|
||||
})
|
||||
];
|
||||
|
||||
export let fakeProcessInstancesWithNoName = [
|
||||
new ProcessInstance({
|
||||
id: 1,
|
||||
name: null,
|
||||
processDefinitionId: 'fakeprocess:5:7507',
|
||||
processDefinitionKey: 'fakeprocess',
|
||||
processDefinitionName: 'Fake Process Name',
|
||||
description: null, category: null,
|
||||
started: '2017-11-09T12:36:14.184+0000',
|
||||
startedBy: {
|
||||
id: 3, firstName: 'tenant2', lastName: 'tenantLastname', email: 'tenant2@tenant'
|
||||
}
|
||||
}),
|
||||
new ProcessInstance({
|
||||
id: 2,
|
||||
name: '',
|
||||
processDefinitionId: 'fakeprocess:5:7507',
|
||||
processDefinitionKey: 'fakeprocess',
|
||||
processDefinitionName: 'Fake Process Name',
|
||||
description: null,
|
||||
category: null,
|
||||
started: '2017-11-09T12:37:25.184+0000',
|
||||
startedBy: {
|
||||
id: 3, firstName: 'tenant2', lastName: 'tenantLastname', email: 'tenant2@tenant'
|
||||
}
|
||||
})
|
||||
];
|
161
lib/process-services/mock/process/process.model.mock.ts
Normal file
161
lib/process-services/mock/process/process.model.mock.ts
Normal file
@@ -0,0 +1,161 @@
|
||||
/*!
|
||||
* @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 { ProcessInstance } from '../../process-list/models/process-instance.model';
|
||||
|
||||
export class ProcessList {
|
||||
|
||||
data: ProcessInstance[];
|
||||
size: number;
|
||||
start: number;
|
||||
total: number;
|
||||
|
||||
constructor(data?: ProcessInstance[]) {
|
||||
this.data = data || [];
|
||||
}
|
||||
}
|
||||
|
||||
export class SingleProcessList extends ProcessList {
|
||||
constructor(name?: string) {
|
||||
let instance = new ProcessInstance({
|
||||
id: '123',
|
||||
name: name
|
||||
});
|
||||
super([instance]);
|
||||
}
|
||||
}
|
||||
|
||||
export let exampleProcess = new ProcessInstance({
|
||||
id: '123',
|
||||
name: 'Process 123',
|
||||
started: '2016-11-10T03:37:30.010+0000',
|
||||
startedBy: {
|
||||
id: 1001,
|
||||
firstName: 'Bob',
|
||||
lastName: 'Jones',
|
||||
email: 'bob@app.activiti.com'
|
||||
}
|
||||
});
|
||||
|
||||
export let processEnded = new ProcessInstance({
|
||||
id: '123',
|
||||
name: 'Process 123',
|
||||
started: '2016-11-10T03:37:30.010+0000',
|
||||
startedBy: {
|
||||
id: 1001,
|
||||
firstName: 'Bob',
|
||||
lastName: 'Jones',
|
||||
email: 'bob@app.activiti.com'
|
||||
},
|
||||
ended: '2016-11-11T03:37:30.010+0000'
|
||||
});
|
||||
|
||||
export let exampleProcessNoName = new ProcessInstance({
|
||||
id: '123',
|
||||
name: null,
|
||||
started: '2016-11-10T03:37:30.010+0000',
|
||||
startedBy: {
|
||||
id: 1001,
|
||||
firstName: 'Bob',
|
||||
lastName: 'Jones',
|
||||
email: 'bob@app.activiti.com'
|
||||
},
|
||||
processDefinitionName: 'My Process'
|
||||
});
|
||||
|
||||
export let fakeProcessInstances = {
|
||||
size: 2,
|
||||
total: 2,
|
||||
start: 0,
|
||||
data: [
|
||||
{
|
||||
id: '340124',
|
||||
name: 'James Franklin EMEA Onboarding',
|
||||
businessKey: null,
|
||||
processDefinitionId: 'HROnboarding:60:338704',
|
||||
tenantId: 'tenant_1',
|
||||
started: new Date('2017-10-09T12:19:44.560+0000'),
|
||||
ended: null,
|
||||
startedBy: {
|
||||
id: 4004,
|
||||
firstName: 'Integration',
|
||||
lastName: 'Test',
|
||||
email: 'srintegrationtest@test.com'
|
||||
},
|
||||
processDefinitionName: 'HROnboarding',
|
||||
processDefinitionDescription: 'HR Onboarding Workflow',
|
||||
processDefinitionKey: 'fakeProcessDefinitionKey1',
|
||||
processDefinitionCategory: 'http://www.activiti.org/processdef',
|
||||
processDefinitionVersion: 60,
|
||||
processDefinitionDeploymentId: '338695',
|
||||
graphicalNotationDefined: true,
|
||||
startFormDefined: false,
|
||||
suspended: false,
|
||||
variables: []
|
||||
},
|
||||
{
|
||||
id: '340063',
|
||||
name: 'Mary Franklin AMERICAS Onboarding',
|
||||
businessKey: null,
|
||||
processDefinitionId: 'HROnboarding:60:338704',
|
||||
tenantId: 'tenant_1',
|
||||
started: '2017-10-09T12:18:07.484+0000',
|
||||
ended: null,
|
||||
startedBy: {
|
||||
id: 4004,
|
||||
firstName: 'Integration',
|
||||
lastName: 'Test',
|
||||
email: 'srintegrationtest@test.com'
|
||||
},
|
||||
processDefinitionName: 'HROnboarding',
|
||||
processDefinitionDescription: 'HR Onboarding Workflow',
|
||||
processDefinitionKey: 'HROnboarding',
|
||||
processDefinitionCategory: 'http://www.activiti.org/processdef',
|
||||
processDefinitionVersion: 60,
|
||||
processDefinitionDeploymentId: '338695',
|
||||
graphicalNotationDefined: true,
|
||||
startFormDefined: false,
|
||||
suspended: false,
|
||||
variables: []
|
||||
},
|
||||
{
|
||||
id: '337604',
|
||||
name: 'John Jacobs AMERICAS Onboarding',
|
||||
businessKey: null,
|
||||
processDefinitionId: 'HROnboarding:49:303243',
|
||||
tenantId: 'tenant_1',
|
||||
started: '2017-09-25T10:02:23.522+0000',
|
||||
ended: null,
|
||||
startedBy: {
|
||||
id: 4004,
|
||||
firstName: 'Integration',
|
||||
lastName: 'Test',
|
||||
email: 'srintegrationtest@test.com'
|
||||
},
|
||||
processDefinitionName: 'HROnboarding',
|
||||
processDefinitionDescription: 'HR Onboarding Workflow',
|
||||
processDefinitionKey: 'fakeProcessDefinitionKey2',
|
||||
processDefinitionCategory: 'http://www.activiti.org/processdef',
|
||||
processDefinitionVersion: 49,
|
||||
processDefinitionDeploymentId: '303234',
|
||||
graphicalNotationDefined: true,
|
||||
startFormDefined: false,
|
||||
suspended: false,
|
||||
variables: []
|
||||
}
|
||||
]
|
||||
};
|
82
lib/process-services/mock/process/process.service.mock.ts
Normal file
82
lib/process-services/mock/process/process.service.mock.ts
Normal file
@@ -0,0 +1,82 @@
|
||||
/*!
|
||||
* @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 { AppDefinitionRepresentationModel, TaskDetailsModel } from '../../task-list';
|
||||
import { FilterProcessRepresentationModel } from '../../process-list/models/filter-process.model';
|
||||
import { ProcessDefinitionRepresentation } from '../../process-list/models/process-definition.model';
|
||||
|
||||
export let fakeProcessFilters = {
|
||||
size: 1, total: 1, start: 0,
|
||||
data: [new FilterProcessRepresentationModel({
|
||||
'name': 'Running',
|
||||
'appId': '22',
|
||||
'id': 333,
|
||||
'recent': true,
|
||||
'icon': 'glyphicon-random',
|
||||
'filter': { 'sort': 'created-desc', 'name': '', 'state': 'running' }
|
||||
})]
|
||||
};
|
||||
|
||||
export let fakeEmptyFilters = {
|
||||
size: 0, total: 0, start: 0,
|
||||
data: []
|
||||
};
|
||||
|
||||
export let fakeError = {
|
||||
message: null,
|
||||
messageKey: 'GENERAL.ERROR.FORBIDDEN'
|
||||
};
|
||||
|
||||
export let fakeApp1 = new AppDefinitionRepresentationModel({
|
||||
deploymentId: 26,
|
||||
name: 'HR processes',
|
||||
icon: 'glyphicon-cloud',
|
||||
description: null,
|
||||
theme: 'theme-6',
|
||||
modelId: 4,
|
||||
id: 1
|
||||
});
|
||||
|
||||
export let fakeApp2 = new AppDefinitionRepresentationModel({
|
||||
deploymentId: 2501,
|
||||
name: 'Sales onboarding',
|
||||
icon: 'glyphicon-asterisk',
|
||||
description: null,
|
||||
theme: 'theme-1',
|
||||
modelId: 1002,
|
||||
id: 1000
|
||||
});
|
||||
|
||||
export let fakeTasksList = {
|
||||
data: [new TaskDetailsModel({
|
||||
id: 1,
|
||||
name: 'Task 1',
|
||||
processInstanceId: 1000,
|
||||
created: '2016-11-10T03:37:30.010+0000'
|
||||
}), new TaskDetailsModel({
|
||||
id: 2,
|
||||
name: 'Task 2',
|
||||
processInstanceId: 1000,
|
||||
created: '2016-11-10T03:37:30.010+0000'
|
||||
})]
|
||||
};
|
||||
|
||||
export let fakeProcessDef = new ProcessDefinitionRepresentation({
|
||||
id: '32323',
|
||||
key: 'blah',
|
||||
name: 'Process 1'
|
||||
});
|
@@ -0,0 +1,46 @@
|
||||
/*!
|
||||
* @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 { ProcessDefinitionRepresentation } from '../../process-list/models/process-definition.model';
|
||||
import { ProcessInstance } from '../../process-list/models/process-instance.model';
|
||||
|
||||
export let newProcess = new ProcessInstance({
|
||||
id: '32323',
|
||||
name: 'Process'
|
||||
});
|
||||
|
||||
export let testProcessDefRepr = new ProcessDefinitionRepresentation({
|
||||
id: 'my:process1',
|
||||
name: 'My Process 1',
|
||||
hasStartForm: false
|
||||
});
|
||||
|
||||
export let testProcessDefs = [new ProcessDefinitionRepresentation({
|
||||
id: 'my:process1',
|
||||
name: 'My Process 1',
|
||||
hasStartForm: false
|
||||
}), new ProcessDefinitionRepresentation({
|
||||
id: 'my:process2',
|
||||
name: 'My Process 2',
|
||||
hasStartForm: false
|
||||
})];
|
||||
|
||||
export let testProcessDefWithForm = [new ProcessDefinitionRepresentation({
|
||||
id: 'my:process1',
|
||||
name: 'My Process 1',
|
||||
hasStartForm: true
|
||||
})];
|
26
lib/process-services/mock/public-api.ts
Normal file
26
lib/process-services/mock/public-api.ts
Normal file
@@ -0,0 +1,26 @@
|
||||
/*!
|
||||
* @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.
|
||||
*/
|
||||
|
||||
export * from './process/process-instances-list.mock';
|
||||
export * from './process/process.service.mock';
|
||||
export * from './process/start-process.component.mock';
|
||||
export * from './process/process.model.mock';
|
||||
|
||||
export * from './task/start-task.mock';
|
||||
export * from './task/task-details.mock';
|
||||
export * from './task/task-details.component.mock';
|
||||
export * from './task/tasklist-service.mock';
|
34
lib/process-services/mock/task/start-task.mock.ts
Normal file
34
lib/process-services/mock/task/start-task.mock.ts
Normal file
@@ -0,0 +1,34 @@
|
||||
/*!
|
||||
* @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.
|
||||
*/
|
||||
|
||||
export let startTaskMock = {
|
||||
'name': 'fakeName',
|
||||
'description': 'fakeDescription',
|
||||
'assignee': null,
|
||||
'dueDate': '2017-11-03T15:25:42.749+0000',
|
||||
'formKey': null,
|
||||
'category': 'fakeAppId'
|
||||
};
|
||||
//
|
||||
// export let noDataMock = {
|
||||
// 'name': '',
|
||||
// 'description': '',
|
||||
// 'assignee': {},
|
||||
// 'dueDate': '',
|
||||
// 'formKey': '',
|
||||
// 'category': ';'
|
||||
// };
|
@@ -0,0 +1,20 @@
|
||||
/*!
|
||||
* @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.
|
||||
*/
|
||||
|
||||
export let mockTaskDetailsComponent = {
|
||||
noTaskDetailsTemplateComponent: null
|
||||
};
|
313
lib/process-services/mock/task/task-details.mock.ts
Normal file
313
lib/process-services/mock/task/task-details.mock.ts
Normal file
@@ -0,0 +1,313 @@
|
||||
/*!
|
||||
* @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 { TaskDetailsModel } from '../../task-list/models/task-details.model';
|
||||
|
||||
export let taskDetailsMock = new TaskDetailsModel({
|
||||
'id': '91',
|
||||
'name': 'Request translation',
|
||||
'description': null,
|
||||
'category': null,
|
||||
'assignee': {'id': 1001, 'firstName': 'Wilbur', 'lastName': 'Adams', 'email': 'wilbur@app.activiti.com'},
|
||||
'created': '2016-11-03T15:25:42.749+0000',
|
||||
'dueDate': null,
|
||||
'endDate': null,
|
||||
'duration': null,
|
||||
'priority': 50,
|
||||
'parentTaskId': null,
|
||||
'parentTaskName': null,
|
||||
'processInstanceId': '86',
|
||||
'processInstanceName': null,
|
||||
'processDefinitionId': 'TranslationProcess:2:8',
|
||||
'processDefinitionName': 'Translation Process',
|
||||
'processDefinitionDescription': null,
|
||||
'processDefinitionKey': 'TranslationProcess',
|
||||
'processDefinitionCategory': 'http://www.activiti.org/processdef',
|
||||
'processDefinitionVersion': 2,
|
||||
'processDefinitionDeploymentId': '5',
|
||||
'formKey': '4',
|
||||
'processInstanceStartUserId': '1001',
|
||||
'initiatorCanCompleteTask': false,
|
||||
'adhocTaskCanBeReassigned': false,
|
||||
'taskDefinitionKey': 'sid-DDECD9E4-0299-433F-9193-C3D905C3EEBE',
|
||||
'executionId': '86',
|
||||
'involvedGroups': [],
|
||||
'involvedPeople': [],
|
||||
'memberOfCandidateUsers': false,
|
||||
'managerOfCandidateGroup': false,
|
||||
'memberOfCandidateGroup': false
|
||||
});
|
||||
|
||||
export let completedTaskDetailsMock = new TaskDetailsModel({
|
||||
'id': '91',
|
||||
'name': 'Request translation',
|
||||
'description': null,
|
||||
'category': null,
|
||||
'assignee': {'id': 1001, 'firstName': 'Wilbur', 'lastName': 'Adams', 'email': 'wilbur@app.activiti.com'},
|
||||
'created': '2016-11-03T15:25:42.749+0000',
|
||||
'dueDate': null,
|
||||
'endDate': '2016-11-03T15:25:42.749+0000',
|
||||
'duration': null,
|
||||
'priority': 50,
|
||||
'parentTaskId': null,
|
||||
'parentTaskName': null,
|
||||
'processInstanceId': '86',
|
||||
'processInstanceName': null,
|
||||
'processDefinitionId': 'TranslationProcess:2:8',
|
||||
'processDefinitionName': 'Translation Process',
|
||||
'involvedGroups': [],
|
||||
'involvedPeople': []
|
||||
});
|
||||
|
||||
export let taskDetailsWithOutAssigneeMock = new TaskDetailsModel({
|
||||
'id': '91',
|
||||
'name': 'Request translation',
|
||||
'description': null,
|
||||
'category': null,
|
||||
'assignee': null,
|
||||
'created': '2016-11-03T15:25:42.749+0000',
|
||||
'dueDate': null,
|
||||
'endDate': null,
|
||||
'duration': null,
|
||||
'priority': 50,
|
||||
'parentTaskId': null,
|
||||
'parentTaskName': null,
|
||||
'processInstanceId': '86',
|
||||
'processInstanceName': null,
|
||||
'processDefinitionId': 'TranslationProcess:2:8',
|
||||
'processDefinitionName': 'Translation Process',
|
||||
'involvedGroups': [{'id': 7007, 'name': 'group1', 'externalId': null, 'status': 'active', 'groups': null},
|
||||
{'id': 8008, 'name': 'group2', 'externalId': null, 'status': 'active', 'groups': null}],
|
||||
'involvedPeople': []
|
||||
});
|
||||
|
||||
export let taskDetailsWithInvolvedGroupMock = new TaskDetailsModel({
|
||||
'id': '91',
|
||||
'name': 'Request translation',
|
||||
'description': null,
|
||||
'category': null,
|
||||
'assignee': {'id': 1001, 'firstName': 'Wilbur', 'lastName': 'Adams', 'email': 'wilbur@app.activiti.com'},
|
||||
'created': '2016-11-03T15:25:42.749+0000',
|
||||
'dueDate': null,
|
||||
'endDate': null,
|
||||
'duration': null,
|
||||
'priority': 50,
|
||||
'parentTaskId': null,
|
||||
'parentTaskName': null,
|
||||
'processInstanceId': '86',
|
||||
'processInstanceName': null,
|
||||
'processDefinitionId': 'TranslationProcess:2:8',
|
||||
'processDefinitionName': 'Translation Process',
|
||||
'involvedGroups': [{'id': 7007, 'name': 'group1', 'externalId': null, 'status': 'active', 'groups': null},
|
||||
{'id': 8008, 'name': 'group2', 'externalId': null, 'status': 'active', 'groups': null}],
|
||||
'involvedPeople': []
|
||||
});
|
||||
|
||||
export let taskDetailsWithInvolvedPeopleMock = new TaskDetailsModel({
|
||||
'id': '91',
|
||||
'name': 'Request translation',
|
||||
'description': null,
|
||||
'category': null,
|
||||
'assignee': {'id': 1001, 'firstName': 'Wilbur', 'lastName': 'Adams', 'email': 'wilbur@app.activiti.com'},
|
||||
'created': '2016-11-03T15:25:42.749+0000',
|
||||
'dueDate': null,
|
||||
'endDate': null,
|
||||
'duration': null,
|
||||
'priority': 50,
|
||||
'parentTaskId': null,
|
||||
'parentTaskName': null,
|
||||
'processInstanceId': '86',
|
||||
'processInstanceName': null,
|
||||
'processDefinitionId': 'TranslationProcess:2:8',
|
||||
'processDefinitionName': 'Translation Process',
|
||||
'involvedGroups': [],
|
||||
'involvedPeople': [{'id': 1001, 'firstName': 'Wilbur', 'lastName': 'Adams', 'email': 'wilbur@app.activiti.com'},
|
||||
{'id': 111, 'firstName': 'fake-first-name', 'lastName': 'fake-last-name', 'email': 'fake@app.activiti.com'}]
|
||||
});
|
||||
|
||||
export let taskDetailsWithAssigneeMock = new TaskDetailsModel({
|
||||
'id': '91',
|
||||
'name': 'Request translation',
|
||||
'description': null,
|
||||
'category': null,
|
||||
'assignee': {'id': 111, 'firstName': 'fake-first-name', 'lastName': 'fake-last-name', 'email': 'fake@app.activiti.com'},
|
||||
'created': '2016-11-03T15:25:42.749+0000',
|
||||
'dueDate': null,
|
||||
'endDate': null,
|
||||
'duration': null,
|
||||
'priority': 50,
|
||||
'parentTaskId': null,
|
||||
'parentTaskName': null,
|
||||
'processInstanceId': '86',
|
||||
'processInstanceName': null,
|
||||
'processDefinitionId': 'TranslationProcess:2:8',
|
||||
'processDefinitionName': 'Translation Process',
|
||||
'involvedGroups': [],
|
||||
'involvedPeople': [{'id': 1001, 'firstName': 'Wilbur', 'lastName': 'Adams', 'email': 'wilbur@app.activiti.com'},
|
||||
{'id': 111, 'firstName': 'fake-first-name', 'lastName': 'fake-last-name', 'email': 'fake@app.activiti.com'}]
|
||||
});
|
||||
|
||||
export let taskFormMock = new TaskDetailsModel({
|
||||
'id': 4,
|
||||
'name': 'Translation request',
|
||||
'processDefinitionId': 'TranslationProcess:2:8',
|
||||
'processDefinitionName': 'Translation Process',
|
||||
'processDefinitionKey': 'TranslationProcess',
|
||||
'taskId': '91',
|
||||
'taskName': 'Request translation',
|
||||
'taskDefinitionKey': 'sid-DDECD9E4-0299-433F-9193-C3D905C3EEBE',
|
||||
'tabs': [],
|
||||
'fields': [{
|
||||
'fieldType': 'ContainerRepresentation',
|
||||
'id': '1478093984155',
|
||||
'name': 'Label',
|
||||
'type': 'container',
|
||||
'value': null,
|
||||
'required': false,
|
||||
'readOnly': false,
|
||||
'overrideId': false,
|
||||
'colspan': 1,
|
||||
'placeholder': null,
|
||||
'minLength': 0,
|
||||
'maxLength': 0,
|
||||
'minValue': null,
|
||||
'maxValue': null,
|
||||
'regexPattern': null,
|
||||
'optionType': null,
|
||||
'hasEmptyValue': null,
|
||||
'options': null,
|
||||
'restUrl': null,
|
||||
'restResponsePath': null,
|
||||
'restIdProperty': null,
|
||||
'restLabelProperty': null,
|
||||
'tab': null,
|
||||
'className': null,
|
||||
'dateDisplayFormat': null,
|
||||
'layout': null,
|
||||
'sizeX': 2,
|
||||
'sizeY': 1,
|
||||
'row': -1,
|
||||
'col': -1,
|
||||
'visibilityCondition': null,
|
||||
'numberOfColumns': 2,
|
||||
'fields': {
|
||||
'1': [{
|
||||
'fieldType': 'AttachFileFieldRepresentation',
|
||||
'id': 'originalcontent',
|
||||
'name': 'Original content',
|
||||
'type': 'upload',
|
||||
'value': [],
|
||||
'required': true,
|
||||
'readOnly': false,
|
||||
'overrideId': false,
|
||||
'colspan': 1,
|
||||
'placeholder': null,
|
||||
'minLength': 0,
|
||||
'maxLength': 0,
|
||||
'minValue': null,
|
||||
'maxValue': null,
|
||||
'regexPattern': null,
|
||||
'optionType': null,
|
||||
'hasEmptyValue': null,
|
||||
'options': null,
|
||||
'restUrl': null,
|
||||
'restResponsePath': null,
|
||||
'restIdProperty': null,
|
||||
'restLabelProperty': null,
|
||||
'tab': null,
|
||||
'className': null,
|
||||
'params': {},
|
||||
'dateDisplayFormat': null,
|
||||
'layout': {'row': -1, 'column': -1, 'colspan': 1},
|
||||
'sizeX': 1,
|
||||
'sizeY': 1,
|
||||
'row': -1,
|
||||
'col': -1,
|
||||
'visibilityCondition': null,
|
||||
'metaDataColumnDefinitions': []
|
||||
}],
|
||||
'2': [{
|
||||
'fieldType': 'RestFieldRepresentation',
|
||||
'id': 'language',
|
||||
'name': 'Language',
|
||||
'type': 'dropdown',
|
||||
'value': 'Choose one...',
|
||||
'required': true,
|
||||
'readOnly': false,
|
||||
'overrideId': false,
|
||||
'colspan': 1,
|
||||
'placeholder': null,
|
||||
'minLength': 0,
|
||||
'maxLength': 0,
|
||||
'minValue': null,
|
||||
'maxValue': null,
|
||||
'regexPattern': null,
|
||||
'optionType': null,
|
||||
'hasEmptyValue': true,
|
||||
'options': [{'id': 'empty', 'name': 'Choose one...'}, {'id': 'fr', 'name': 'French'}, {
|
||||
'id': 'de',
|
||||
'name': 'German'
|
||||
}, {'id': 'es', 'name': 'Spanish'}],
|
||||
'restUrl': null,
|
||||
'restResponsePath': null,
|
||||
'restIdProperty': null,
|
||||
'restLabelProperty': null,
|
||||
'tab': null,
|
||||
'className': null,
|
||||
'params': {'existingColspan': 1, 'maxColspan': 1},
|
||||
'dateDisplayFormat': null,
|
||||
'layout': {'row': -1, 'column': -1, 'colspan': 1},
|
||||
'sizeX': 1,
|
||||
'sizeY': 1,
|
||||
'row': -1,
|
||||
'col': -1,
|
||||
'visibilityCondition': null,
|
||||
'endpoint': null,
|
||||
'requestHeaders': null
|
||||
}]
|
||||
}
|
||||
}],
|
||||
'outcomes': [],
|
||||
'javascriptEvents': [],
|
||||
'className': '',
|
||||
'style': '',
|
||||
'customFieldTemplates': {},
|
||||
'metadata': {},
|
||||
'variables': [],
|
||||
'gridsterForm': false,
|
||||
'globalDateFormat': 'D-M-YYYY'
|
||||
});
|
||||
|
||||
export let tasksMock = new TaskDetailsModel({
|
||||
data: [
|
||||
taskDetailsMock
|
||||
]
|
||||
});
|
||||
|
||||
export let noDataMock = new TaskDetailsModel({
|
||||
data: [{
|
||||
'size': 1,
|
||||
'total': 1,
|
||||
'start': 0,
|
||||
'data': [{
|
||||
'id': 1005,
|
||||
'message': 'example-message',
|
||||
'created': '2017-10-06T11:54:53.443+0000',
|
||||
'createdBy': {'id': 4004, 'firstName': 'gadget', 'lastName': 'inspector', 'email': 'gadget@inspector.com'}
|
||||
}]
|
||||
}]
|
||||
});
|
270
lib/process-services/mock/task/tasklist-service.mock.ts
Normal file
270
lib/process-services/mock/task/tasklist-service.mock.ts
Normal file
@@ -0,0 +1,270 @@
|
||||
/*!
|
||||
* @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 {
|
||||
AppDefinitionRepresentationModel,
|
||||
FilterRepresentationModel
|
||||
} from '../../task-list/models/filter.model';
|
||||
|
||||
export let fakeFilters = {
|
||||
size: 2, total: 2, start: 0,
|
||||
data: [
|
||||
new AppDefinitionRepresentationModel(
|
||||
{
|
||||
id: 1, name: 'FakeInvolvedTasks', recent: false, icon: 'glyphicon-align-left',
|
||||
filter: { sort: 'created-desc', name: '', state: 'open', assignment: 'fake-involved' }
|
||||
}
|
||||
),
|
||||
{
|
||||
id: 2, name: 'FakeMyTasks', recent: false, icon: 'glyphicon-align-left',
|
||||
filter: { sort: 'created-desc', name: '', state: 'open', assignment: 'fake-assignee' }
|
||||
}
|
||||
]
|
||||
};
|
||||
|
||||
export let fakeAppFilter = {
|
||||
size: 1, total: 1, start: 0,
|
||||
data: [
|
||||
{
|
||||
id: 1, name: 'FakeInvolvedTasks', recent: false, icon: 'glyphicon-align-left',
|
||||
filter: { sort: 'created-desc', name: '', state: 'open', assignment: 'fake-involved' }
|
||||
}
|
||||
]
|
||||
};
|
||||
|
||||
export let fakeApps = {
|
||||
size: 2, total: 2, start: 0,
|
||||
data: [
|
||||
{
|
||||
id: 1, defaultAppId: null, name: 'Sales-Fakes-App', description: 'desc-fake1', modelId: 22,
|
||||
theme: 'theme-1-fake', icon: 'glyphicon-asterisk', 'deploymentId': '111', 'tenantId': null
|
||||
},
|
||||
{
|
||||
id: 2, defaultAppId: null, name: 'health-care-Fake', description: 'desc-fake2', modelId: 33,
|
||||
theme: 'theme-2-fake', icon: 'glyphicon-asterisk', 'deploymentId': '444', 'tenantId': null
|
||||
}
|
||||
]
|
||||
};
|
||||
|
||||
export let fakeFilter = {
|
||||
sort: 'created-desc', text: '', state: 'open', assignment: 'fake-assignee'
|
||||
};
|
||||
|
||||
export let fakeUser1 = { id: 1, email: 'fake-email@dom.com', firstName: 'firstName', lastName: 'lastName' };
|
||||
|
||||
export let fakeUser2 = { id: 1001, email: 'some-one@somegroup.com', firstName: 'some', lastName: 'one' };
|
||||
|
||||
export let fakeTaskList = {
|
||||
size: 1, total: 1, start: 0,
|
||||
data: [
|
||||
{
|
||||
id: '1', name: 'FakeNameTask', description: null, category: null,
|
||||
assignee: fakeUser1,
|
||||
created: '2016-07-15T11:19:17.440+0000'
|
||||
}
|
||||
]
|
||||
};
|
||||
|
||||
export let fakeTaskListDifferentProcessDefinitionKey = {
|
||||
size: 2, total: 1, start: 0,
|
||||
data: [
|
||||
{
|
||||
id: '1', name: 'FakeNameTask', description: null, category: null,
|
||||
assignee: fakeUser1,
|
||||
processDefinitionKey: '1',
|
||||
created: '2016-07-15T11:19:17.440+0000'
|
||||
},
|
||||
{
|
||||
id: '2', name: 'FakeNameTask2', description: null, category: null,
|
||||
assignee: fakeUser1,
|
||||
processDefinitionKey: '2',
|
||||
created: '2016-07-15T11:19:17.440+0000'
|
||||
}
|
||||
]
|
||||
};
|
||||
|
||||
export let secondFakeTaskList = {
|
||||
size: 1, total: 1, start: 0,
|
||||
data: [
|
||||
{
|
||||
id: '200', name: 'FakeNameTask', description: null, category: null,
|
||||
assignee: fakeUser1,
|
||||
created: '2016-07-15T11:19:17.440+0000'
|
||||
}
|
||||
]
|
||||
};
|
||||
|
||||
export let fakeErrorTaskList = {
|
||||
error: 'wrong request'
|
||||
};
|
||||
|
||||
export let fakeTaskDetails = { id: '999', name: 'fake-task-name', formKey: '99', assignee: fakeUser1 };
|
||||
|
||||
export let fakeTasksComment = {
|
||||
size: 2, total: 2, start: 0,
|
||||
data: [
|
||||
{
|
||||
id: 1, message: 'fake-message-1', created: '', createdBy: fakeUser1
|
||||
},
|
||||
{
|
||||
id: 2, message: 'fake-message-2', created: '', createdBy: fakeUser1
|
||||
}
|
||||
]
|
||||
};
|
||||
|
||||
export let fakeTasksChecklist = {
|
||||
size: 1, total: 1, start: 0,
|
||||
data: [
|
||||
{
|
||||
id: 1, name: 'FakeCheckTask1', description: null, category: null,
|
||||
assignee: fakeUser1,
|
||||
created: '2016-07-15T11:19:17.440+0000'
|
||||
},
|
||||
{
|
||||
id: 2, name: 'FakeCheckTask2', description: null, category: null,
|
||||
assignee: fakeUser1,
|
||||
created: '2016-07-15T11:19:17.440+0000'
|
||||
}
|
||||
]
|
||||
};
|
||||
|
||||
export let fakeRepresentationFilter1: FilterRepresentationModel = new FilterRepresentationModel({
|
||||
appId: 1,
|
||||
name: 'CONTAIN FILTER',
|
||||
recent: true,
|
||||
icon: 'glyphicon-align-left',
|
||||
filter: {
|
||||
processDefinitionId: null,
|
||||
processDefinitionKey: null,
|
||||
name: null,
|
||||
state: 'open',
|
||||
sort: 'created-desc',
|
||||
assignment: 'involved',
|
||||
dueAfter: null,
|
||||
dueBefore: null
|
||||
}
|
||||
});
|
||||
|
||||
export let fakeRepresentationFilter2: FilterRepresentationModel = new FilterRepresentationModel({
|
||||
appId: 2,
|
||||
name: 'NO TASK FILTER',
|
||||
recent: false,
|
||||
icon: 'glyphicon-inbox',
|
||||
filter: {
|
||||
processDefinitionId: null,
|
||||
processDefinitionKey: null,
|
||||
name: null,
|
||||
state: 'open',
|
||||
sort: 'created-desc',
|
||||
assignment: 'assignee',
|
||||
dueAfter: null,
|
||||
dueBefore: null
|
||||
}
|
||||
});
|
||||
|
||||
export let fakeAppPromise = new Promise(function (resolve, reject) {
|
||||
resolve(fakeAppFilter);
|
||||
});
|
||||
|
||||
export let fakeFormList = {
|
||||
size: 2,
|
||||
total: 2,
|
||||
start: 0,
|
||||
data: [{
|
||||
id: 1,
|
||||
name: 'form with all widgets',
|
||||
description: '',
|
||||
createdBy: 2,
|
||||
createdByFullName: 'Admin Admin',
|
||||
lastUpdatedBy: 2,
|
||||
lastUpdatedByFullName: 'Admin Admin',
|
||||
lastUpdated: 1491400951205,
|
||||
latestVersion: true,
|
||||
version: 4,
|
||||
comment: null,
|
||||
stencilSet: null,
|
||||
referenceId: null,
|
||||
modelType: 2,
|
||||
favorite: null,
|
||||
permission: 'write',
|
||||
tenantId: null
|
||||
}, {
|
||||
id: 2,
|
||||
name: 'uppy',
|
||||
description: '',
|
||||
createdBy: 2,
|
||||
createdByFullName: 'Admin Admin',
|
||||
lastUpdatedBy: 2,
|
||||
lastUpdatedByFullName: 'Admin Admin',
|
||||
lastUpdated: 1490951054477,
|
||||
latestVersion: true,
|
||||
version: 2,
|
||||
comment: null,
|
||||
stencilSet: null,
|
||||
referenceId: null,
|
||||
modelType: 2,
|
||||
favorite: null,
|
||||
permission: 'write',
|
||||
tenantId: null
|
||||
}]
|
||||
};
|
||||
|
||||
export let fakeTaskOpen1 = {
|
||||
id: '1', name: 'FakeOpenTask1', description: null, category: null,
|
||||
assignee: fakeUser1,
|
||||
created: '2017-07-15T11:19:17.440+0000',
|
||||
dueDate: null,
|
||||
endDate: null
|
||||
};
|
||||
|
||||
export let fakeTaskOpen2 = {
|
||||
id: '1', name: 'FakeOpenTask2', description: null, category: null,
|
||||
assignee: { id: 1, email: 'fake-open-email@dom.com', firstName: 'firstName', lastName: 'lastName' },
|
||||
created: '2017-07-15T11:19:17.440+0000',
|
||||
dueDate: null,
|
||||
endDate: null
|
||||
};
|
||||
|
||||
export let fakeTaskCompleted1 = {
|
||||
id: '1', name: 'FakeCompletedTaskName1', description: null, category: null,
|
||||
assignee: { id: 1, email: 'fake-completed-email@dom.com', firstName: 'firstName', lastName: 'lastName' },
|
||||
created: '2016-07-15T11:19:17.440+0000',
|
||||
dueDate: null,
|
||||
endDate: '2016-11-03T15:25:42.749+0000'
|
||||
};
|
||||
|
||||
export let fakeTaskCompleted2 = {
|
||||
id: '1', name: 'FakeCompletedTaskName2', description: null, category: null,
|
||||
assignee: fakeUser1,
|
||||
created: null,
|
||||
dueDate: null,
|
||||
endDate: '2016-11-03T15:25:42.749+0000'
|
||||
};
|
||||
|
||||
export let fakeOpenTaskList = {
|
||||
size: 2,
|
||||
total: 2,
|
||||
start: 0,
|
||||
data: [fakeTaskOpen1, fakeTaskOpen2]
|
||||
};
|
||||
|
||||
export let fakeCompletedTaskList = {
|
||||
size: 2,
|
||||
total: 2,
|
||||
start: 0,
|
||||
data: [fakeTaskCompleted1, fakeTaskCompleted2]
|
||||
};
|
25
lib/process-services/package.json
Normal file
25
lib/process-services/package.json
Normal file
@@ -0,0 +1,25 @@
|
||||
{
|
||||
"name": "adf-process-services",
|
||||
"description": "Alfresco ADF process services",
|
||||
"version": "2.0.0",
|
||||
"author": "Alfresco Software, Ltd.",
|
||||
"main": "bundles/process-services.js",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/Alfresco/alfresco-ng2-components.git"
|
||||
},
|
||||
"bugs": {
|
||||
"url": "https://github.com/Alfresco/alfresco-ng2-components/issues"
|
||||
},
|
||||
"dependencies": {
|
||||
},
|
||||
"devDependencies": {
|
||||
},
|
||||
"keywords": [
|
||||
"process-services",
|
||||
"alfresco-component",
|
||||
"angular",
|
||||
"components"
|
||||
],
|
||||
"license": "Apache-2.0"
|
||||
}
|
18
lib/process-services/people/index.ts
Normal file
18
lib/process-services/people/index.ts
Normal file
@@ -0,0 +1,18 @@
|
||||
/*!
|
||||
* @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.
|
||||
*/
|
||||
|
||||
export * from './public-api';
|
8
lib/process-services/people/people-list.component.html
Normal file
8
lib/process-services/people/people-list.component.html
Normal file
@@ -0,0 +1,8 @@
|
||||
<adf-datatable
|
||||
[rows]="users"
|
||||
[actions]="hasActions()"
|
||||
(rowClick)="selectUser($event)"
|
||||
(rowDblClick)="selectUser($event)"
|
||||
(showRowActionsMenu)="onShowRowActionsMenu($event)"
|
||||
(executeRowAction)="onExecuteRowAction($event)">
|
||||
</adf-datatable>
|
86
lib/process-services/people/people-list.component.spec.ts
Normal file
86
lib/process-services/people/people-list.component.spec.ts
Normal file
@@ -0,0 +1,86 @@
|
||||
/*!
|
||||
* @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 { UserProcessModel } from '@alfresco/core';
|
||||
import { DataRowActionEvent, DataRowEvent, ObjectDataRow } from '@alfresco/core';
|
||||
import { UserEventModel } from '../task-list/models/user-event.model';
|
||||
import { PeopleListComponent } from './people-list.component';
|
||||
|
||||
const fakeUser: UserProcessModel = new UserProcessModel({
|
||||
id: 1,
|
||||
firstName: 'fake-name',
|
||||
lastName: 'fake-last',
|
||||
email: 'fake@mail.com'
|
||||
});
|
||||
|
||||
describe('PeopleListComponent', () => {
|
||||
|
||||
let peopleListComponent: PeopleListComponent;
|
||||
let fixture: ComponentFixture<PeopleListComponent>;
|
||||
let element: HTMLElement;
|
||||
|
||||
beforeEach(async(() => {
|
||||
TestBed.configureTestingModule({
|
||||
|
||||
declarations: [
|
||||
PeopleListComponent
|
||||
],
|
||||
providers: [
|
||||
]
|
||||
}).compileComponents().then(() => {
|
||||
|
||||
fixture = TestBed.createComponent(PeopleListComponent);
|
||||
peopleListComponent = fixture.componentInstance;
|
||||
element = fixture.nativeElement;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
}));
|
||||
|
||||
it('should emit row click event', (done) => {
|
||||
let row = new ObjectDataRow(fakeUser);
|
||||
let rowEvent = new DataRowEvent(row, null);
|
||||
|
||||
peopleListComponent.clickRow.subscribe(selectedUser => {
|
||||
expect(selectedUser.id).toEqual(1);
|
||||
expect(selectedUser.email).toEqual('fake@mail.com');
|
||||
expect(peopleListComponent.user.id).toEqual(1);
|
||||
expect(peopleListComponent.user.email).toEqual('fake@mail.com');
|
||||
done();
|
||||
});
|
||||
|
||||
peopleListComponent.selectUser(rowEvent);
|
||||
});
|
||||
|
||||
it('should emit row action event', (done) => {
|
||||
let row = new ObjectDataRow(fakeUser);
|
||||
let removeObj = {
|
||||
name: 'remove',
|
||||
title: 'Remove'
|
||||
};
|
||||
let rowActionEvent = new DataRowActionEvent(row, removeObj);
|
||||
|
||||
peopleListComponent.clickAction.subscribe((selectedAction: UserEventModel) => {
|
||||
expect(selectedAction.type).toEqual('remove');
|
||||
expect(selectedAction.value.id).toEqual(1);
|
||||
expect(selectedAction.value.email).toEqual('fake@mail.com');
|
||||
done();
|
||||
});
|
||||
|
||||
peopleListComponent.onExecuteRowAction(rowActionEvent);
|
||||
});
|
||||
});
|
83
lib/process-services/people/people-list.component.ts
Normal file
83
lib/process-services/people/people-list.component.ts
Normal file
@@ -0,0 +1,83 @@
|
||||
/*!
|
||||
* @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 { DataTableComponent } from '@alfresco/core';
|
||||
import { DataColumnListComponent, UserProcessModel } from '@alfresco/core';
|
||||
import { AfterContentInit, AfterViewInit, Component, ContentChild, EventEmitter, Input, Output, ViewChild } from '@angular/core';
|
||||
import { UserEventModel } from '../task-list/models/user-event.model';
|
||||
|
||||
@Component({
|
||||
selector: 'adf-people-list',
|
||||
templateUrl: './people-list.component.html',
|
||||
styleUrls: ['./people-list.component.scss']
|
||||
})
|
||||
|
||||
export class PeopleListComponent implements AfterViewInit, AfterContentInit {
|
||||
|
||||
@ContentChild(DataColumnListComponent) columnList: DataColumnListComponent;
|
||||
|
||||
@ViewChild(DataTableComponent)
|
||||
peopleDataTable: DataTableComponent;
|
||||
|
||||
@Input()
|
||||
users: UserProcessModel[];
|
||||
|
||||
@Input()
|
||||
actions: boolean = false;
|
||||
|
||||
@Output()
|
||||
clickRow: EventEmitter<UserProcessModel> = new EventEmitter<UserProcessModel>();
|
||||
|
||||
@Output()
|
||||
clickAction: EventEmitter<UserEventModel> = new EventEmitter<UserEventModel>();
|
||||
|
||||
user: UserProcessModel;
|
||||
|
||||
ngAfterContentInit() {
|
||||
this.peopleDataTable.columnList = this.columnList;
|
||||
}
|
||||
|
||||
ngAfterViewInit() {
|
||||
}
|
||||
|
||||
selectUser(event: any) {
|
||||
this.user = event.value.obj;
|
||||
this.clickRow.emit(this.user);
|
||||
}
|
||||
|
||||
hasActions(): boolean {
|
||||
return this.actions;
|
||||
}
|
||||
|
||||
onShowRowActionsMenu(event: any) {
|
||||
|
||||
let removeAction = {
|
||||
title: 'Remove',
|
||||
name: 'remove'
|
||||
};
|
||||
|
||||
event.value.actions = [
|
||||
removeAction
|
||||
];
|
||||
}
|
||||
|
||||
onExecuteRowAction(event: any) {
|
||||
let args = event.value;
|
||||
let action = args.action;
|
||||
this.clickAction.emit(new UserEventModel({type: action.name, value: args.row.obj}));
|
||||
}
|
||||
}
|
37
lib/process-services/people/people-search.component.html
Normal file
37
lib/process-services/people/people-search.component.html
Normal file
@@ -0,0 +1,37 @@
|
||||
<div class="search-text-header">
|
||||
<ng-content select="[people-search-title]"></ng-content>
|
||||
</div>
|
||||
<mat-form-field class="search-text-container">
|
||||
<input matInput placeholder="{{'ADF_TASK_LIST.PEOPLE.SEARCH_USER'|translate}}" type="text" id="userSearchText" [value]="" [formControl]="searchUser">
|
||||
</mat-form-field>
|
||||
<div class="search-list-container" id="search-people-list" *ngIf="hasUsers()">
|
||||
<adf-people-list
|
||||
[users]="users"
|
||||
(clickRow)="onRowClick($event)">
|
||||
<data-columns>
|
||||
<data-column key="firstName">
|
||||
<ng-template let-entry="$implicit">
|
||||
<div *ngIf="!entry.row.obj.pictureId" class="people-pic">
|
||||
{{getInitialUserName(entry.row.obj.firstName, entry.row.obj.lastName)}}</div>
|
||||
<div>
|
||||
<img *ngIf="entry.row.obj.pictureId" class="people-img"
|
||||
[src]="peopleProcessService.getUserImage(entry.row.obj)"/>
|
||||
</div>
|
||||
</ng-template>
|
||||
</data-column>
|
||||
<data-column key="email" class="full-width">
|
||||
<ng-template let-entry="$implicit">
|
||||
<div class="people-full-name">{{ getDisplayUser(entry.row.obj.firstName, entry.row.obj.lastName, ' ') }}</div>
|
||||
</ng-template>
|
||||
</data-column>
|
||||
</data-columns>
|
||||
</adf-people-list>
|
||||
</div>
|
||||
<div class="search-list-action-container">
|
||||
<button mat-button type="button" id="close-people-search" (click)="closeSearchList()">
|
||||
{{'ADF_TASK_LIST.PEOPLE.DIALOG_CLOSE' | translate }}
|
||||
</button>
|
||||
<button mat-button type="button" id="add-people" (click)="involveUserAndClose()">
|
||||
<ng-content select="[people-search-action-label]"></ng-content>
|
||||
</button>
|
||||
</div>
|
77
lib/process-services/people/people-search.component.scss
Normal file
77
lib/process-services/people/people-search.component.scss
Normal file
@@ -0,0 +1,77 @@
|
||||
@mixin adf-task-list-people-search-theme($theme) {
|
||||
$primary: map-get($theme, primary);
|
||||
$accent: map-get($theme, accent);
|
||||
$warn: map-get($theme, warn);
|
||||
|
||||
.adf-people-search {
|
||||
width: 100%;
|
||||
|
||||
.activiti-label {
|
||||
font-weight: bolder;
|
||||
}
|
||||
|
||||
.fix-element-user-list {
|
||||
padding-top: 0px;
|
||||
padding-right: 0px;
|
||||
padding-bottom: 0px;
|
||||
padding-left: 0px;
|
||||
}
|
||||
|
||||
.search-text-header {
|
||||
font-weight: bold;
|
||||
opacity: 0.54;
|
||||
}
|
||||
|
||||
.search-text-container {
|
||||
width: 100%;
|
||||
|
||||
input {
|
||||
line-height: normal;
|
||||
}
|
||||
}
|
||||
|
||||
.search-list-container {
|
||||
max-height: 152px;
|
||||
width: 100%;
|
||||
overflow-y: auto;
|
||||
}
|
||||
|
||||
adf-people-list ::ng-deep adf-datatable ::ng-deep thead {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.search-list-action-container {
|
||||
border-top: 1px solid #eee;
|
||||
text-align: right;
|
||||
padding: 5px 0px;
|
||||
margin-top: 5px;
|
||||
> button {
|
||||
opacity: 0.54;
|
||||
font-weight: bolder;
|
||||
&:hover {
|
||||
color: mat-color($primary);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.people-pic {
|
||||
background: mat-color($primary);
|
||||
width: 30px;
|
||||
padding: 10px 5px;
|
||||
border-radius: 90%;
|
||||
color: #fff;
|
||||
text-align: center;
|
||||
font-weight: bolder;
|
||||
font-size: 18px;
|
||||
text-transform: uppercase;
|
||||
vertical-align: text-bottom;
|
||||
}
|
||||
|
||||
.people-img {
|
||||
border-radius: 90%;
|
||||
width: 40px;
|
||||
height: 40px;
|
||||
vertical-align: middle;
|
||||
}
|
||||
}
|
||||
}
|
136
lib/process-services/people/people-search.component.spec.ts
Normal file
136
lib/process-services/people/people-search.component.spec.ts
Normal file
@@ -0,0 +1,136 @@
|
||||
/*!
|
||||
* @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 { MatButtonModule, MatInputModule } from '@angular/material';
|
||||
import { UserProcessModel } from '@alfresco/core';
|
||||
import { Observable } from 'rxjs/Observable';
|
||||
import { PeopleListComponent } from './people-list.component';
|
||||
import { PeopleSearchComponent } from './people-search.component';
|
||||
|
||||
const fakeUser: UserProcessModel = new UserProcessModel({
|
||||
id: '1',
|
||||
firstName: 'fake-name',
|
||||
lastName: 'fake-last',
|
||||
email: 'fake@mail.com'
|
||||
});
|
||||
|
||||
const fakeSecondUser: UserProcessModel = new UserProcessModel({
|
||||
id: '2',
|
||||
firstName: 'fake-involve-name',
|
||||
lastName: 'fake-involve-last',
|
||||
email: 'fake-involve@mail.com'
|
||||
});
|
||||
|
||||
describe('PeopleSearchComponent', () => {
|
||||
|
||||
let peopleSearchComponent: PeopleSearchComponent;
|
||||
let fixture: ComponentFixture<PeopleSearchComponent>;
|
||||
let element: HTMLElement;
|
||||
let userArray = [fakeUser, fakeSecondUser];
|
||||
let searchInput: any;
|
||||
|
||||
beforeEach(async(() => {
|
||||
TestBed.configureTestingModule({
|
||||
imports: [
|
||||
MatButtonModule,
|
||||
MatInputModule
|
||||
],
|
||||
declarations: [
|
||||
PeopleSearchComponent,
|
||||
PeopleListComponent
|
||||
],
|
||||
providers: [
|
||||
]
|
||||
}).compileComponents().then(() => {
|
||||
|
||||
fixture = TestBed.createComponent(PeopleSearchComponent);
|
||||
peopleSearchComponent = fixture.componentInstance;
|
||||
element = fixture.nativeElement;
|
||||
peopleSearchComponent.results = Observable.of([]);
|
||||
fixture.detectChanges();
|
||||
});
|
||||
}));
|
||||
|
||||
it('should show input search text', () => {
|
||||
expect(element.querySelector('#userSearchText')).toBeDefined();
|
||||
expect(element.querySelector('#userSearchText')).not.toBeNull();
|
||||
});
|
||||
|
||||
it('should hide people-list container', () => {
|
||||
fixture.detectChanges();
|
||||
fixture.whenStable()
|
||||
.then(() => {
|
||||
expect(element.querySelector('#search-people-list')).toBeNull();
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
it('should show user which can be involved ', (done) => {
|
||||
peopleSearchComponent.searchPeople.subscribe(() => {
|
||||
peopleSearchComponent.results = Observable.of(userArray);
|
||||
peopleSearchComponent.ngOnInit();
|
||||
fixture.detectChanges();
|
||||
fixture.whenStable()
|
||||
.then(() => {
|
||||
let gatewayElement: any = element.querySelector('#search-people-list tbody');
|
||||
expect(gatewayElement).not.toBeNull();
|
||||
expect(gatewayElement.children.length).toBe(2);
|
||||
done();
|
||||
});
|
||||
});
|
||||
searchInput = element.querySelector('#userSearchText');
|
||||
searchInput.value = 'fake-search';
|
||||
peopleSearchComponent.searchUser.markAsDirty();
|
||||
searchInput.dispatchEvent(new Event('input'));
|
||||
});
|
||||
|
||||
it('should send an event when an user is clicked', (done) => {
|
||||
peopleSearchComponent.success.subscribe((user) => {
|
||||
expect(user).toBeDefined();
|
||||
expect(user.firstName).toBe('fake-name');
|
||||
done();
|
||||
});
|
||||
peopleSearchComponent.results = Observable.of(userArray);
|
||||
peopleSearchComponent.ngOnInit();
|
||||
fixture.detectChanges();
|
||||
fixture.whenStable()
|
||||
.then(() => {
|
||||
peopleSearchComponent.onRowClick(fakeUser);
|
||||
let addUserButton = <HTMLElement> element.querySelector('#add-people');
|
||||
addUserButton.click();
|
||||
});
|
||||
});
|
||||
|
||||
it('should remove clicked user', (done) => {
|
||||
peopleSearchComponent.results = Observable.of(userArray);
|
||||
peopleSearchComponent.ngOnInit();
|
||||
fixture.detectChanges();
|
||||
peopleSearchComponent.onRowClick(fakeUser);
|
||||
let addUserButton = <HTMLElement> element.querySelector('#add-people');
|
||||
addUserButton.click();
|
||||
|
||||
fixture.detectChanges();
|
||||
fixture.whenStable()
|
||||
.then(() => {
|
||||
let gatewayElement: any = element.querySelector('#search-people-list tbody');
|
||||
expect(gatewayElement).not.toBeNull();
|
||||
expect(gatewayElement.children.length).toBe(1);
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
114
lib/process-services/people/people-search.component.ts
Normal file
114
lib/process-services/people/people-search.component.ts
Normal file
@@ -0,0 +1,114 @@
|
||||
/*!
|
||||
* @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 { PeopleProcessService, UserProcessModel } from '@alfresco/core';
|
||||
import { Component, Directive, EventEmitter, Input, OnInit, Output, ViewEncapsulation } from '@angular/core';
|
||||
import { FormControl } from '@angular/forms';
|
||||
import { Observable } from 'rxjs/Observable';
|
||||
|
||||
@Component({
|
||||
selector: 'adf-people-search',
|
||||
templateUrl: './people-search.component.html',
|
||||
styleUrls: ['./people-search.component.scss'],
|
||||
host: {
|
||||
'class': 'adf-people-search'
|
||||
},
|
||||
encapsulation: ViewEncapsulation.None
|
||||
})
|
||||
|
||||
export class PeopleSearchComponent implements OnInit {
|
||||
|
||||
@Input()
|
||||
results: Observable<UserProcessModel[]>;
|
||||
|
||||
@Output()
|
||||
searchPeople: EventEmitter<any> = new EventEmitter();
|
||||
|
||||
@Output()
|
||||
success: EventEmitter<UserProcessModel> = new EventEmitter<UserProcessModel>();
|
||||
|
||||
@Output()
|
||||
closeSearch = new EventEmitter();
|
||||
|
||||
searchUser: FormControl = new FormControl();
|
||||
|
||||
users: UserProcessModel[] = [];
|
||||
|
||||
selectedUser: UserProcessModel;
|
||||
|
||||
constructor(public peopleProcessService: PeopleProcessService) {
|
||||
this.searchUser
|
||||
.valueChanges
|
||||
.debounceTime(200)
|
||||
.subscribe((event: string) => {
|
||||
if (event && event.trim()) {
|
||||
this.searchPeople.emit(event);
|
||||
} else {
|
||||
this.users = [];
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
ngOnInit() {
|
||||
this.results.subscribe((list) => {
|
||||
this.users = list;
|
||||
});
|
||||
}
|
||||
|
||||
onRowClick(user: UserProcessModel) {
|
||||
this.selectedUser = user;
|
||||
}
|
||||
|
||||
closeSearchList() {
|
||||
this.closeSearch.emit();
|
||||
}
|
||||
|
||||
involveUserAndClose() {
|
||||
this.involveUser();
|
||||
this.closeSearchList();
|
||||
}
|
||||
|
||||
involveUser() {
|
||||
if (this.selectedUser === undefined) {
|
||||
return;
|
||||
}
|
||||
this.success.emit(this.selectedUser);
|
||||
this.users = this.users.filter((user) => {
|
||||
this.searchUser.reset();
|
||||
return user.id !== this.selectedUser.id;
|
||||
});
|
||||
}
|
||||
|
||||
getDisplayUser(firstName: string, lastName: string, delimiter: string = '-'): string {
|
||||
firstName = (firstName !== null ? firstName : '');
|
||||
lastName = (lastName !== null ? lastName : '');
|
||||
return firstName + delimiter + lastName;
|
||||
}
|
||||
|
||||
getInitialUserName(firstName: string, lastName: string) {
|
||||
firstName = (firstName !== null && firstName !== '' ? firstName[0] : '');
|
||||
lastName = (lastName !== null && lastName !== '' ? lastName[0] : '');
|
||||
return this.getDisplayUser(firstName, lastName, '');
|
||||
}
|
||||
|
||||
hasUsers() {
|
||||
return (this.users && this.users.length > 0);
|
||||
}
|
||||
}
|
||||
|
||||
@Directive({ selector: 'people-search-title' }) export class PeopleSearchTitleDirective { }
|
||||
@Directive({ selector: 'people-search-action-label' }) export class PeopleSearchActionLabelDirective { }
|
51
lib/process-services/people/people.component.html
Normal file
51
lib/process-services/people/people.component.html
Normal file
@@ -0,0 +1,51 @@
|
||||
<mat-card class="assignment-top-container">
|
||||
<div mat-card-content class="assignment-top-container-content">
|
||||
<div class="assignment-header">
|
||||
<div *ngIf="hasPeople()" class="assigment-count" id="people-title">
|
||||
{{ 'ADF_TASK_LIST.DETAILS.LABELS.PEOPLE' | translate }} {{ ' (' + people.length + ')' }}
|
||||
</div>
|
||||
<div *ngIf="!hasPeople()" class="assigment-count" id="no-people-label">
|
||||
{{ 'ADF_TASK_LIST.DETAILS.PEOPLE.NONE' | translate }}
|
||||
</div>
|
||||
<div *ngIf="isEditMode()" class="add-people" (click)="onAddAssignement()">
|
||||
<mat-icon class="adf-add-person-icon">person_add</mat-icon>
|
||||
</div>
|
||||
</div>
|
||||
<div class="assignment-container" *ngIf="showAssignment">
|
||||
<adf-people-search
|
||||
(searchPeople)="searchUser($event)"
|
||||
(success)="involveUser($event)"
|
||||
(closeSearch)="onCloseSearch()"
|
||||
[results]="peopleSearch$">
|
||||
<ng-container people-search-title>{{ 'ADF_TASK_LIST.DETAILS.LABELS.ADD_PEOPLE' | translate }}</ng-container>
|
||||
<ng-container people-search-action-label>{{ 'ADF_TASK_LIST.PEOPLE.ADD_USER' | translate }}</ng-container>
|
||||
</adf-people-search>
|
||||
</div>
|
||||
<div class="assignment-list-container" id="assignment-people-list" *ngIf="hasPeople()">
|
||||
<adf-people-list
|
||||
[users]="people"
|
||||
[actions]="isEditMode()"
|
||||
(clickAction)="onClickAction($event)">
|
||||
<data-columns>
|
||||
<data-column key="firstName">
|
||||
<ng-template let-entry="$implicit">
|
||||
<div *ngIf="!entry.row.obj.pictureId" class="adf-people-search-people-pic">
|
||||
{{getInitialUserName(entry.row.obj.firstName, entry.row.obj.lastName)}}</div>
|
||||
<div>
|
||||
<img *ngIf="entry.row.obj.pictureId" class="people-img"
|
||||
[src]="peopleProcessService.getUserImage(entry.row.obj)"/>
|
||||
</div>
|
||||
</ng-template>
|
||||
</data-column>
|
||||
<data-column key="email" class="full-width">
|
||||
<ng-template let-entry="$implicit">
|
||||
<div class="people-full-name">{{ getDisplayUser(entry.row.obj.firstName, entry.row.obj.lastName, ' ') }}</div>
|
||||
<div class="people-email">{{ entry.row.obj.email }}</div>
|
||||
<div class="people-edit-label">can edit</div>
|
||||
</ng-template>
|
||||
</data-column>
|
||||
</data-columns>
|
||||
</adf-people-list>
|
||||
</div>
|
||||
</div>
|
||||
</mat-card>
|
82
lib/process-services/people/people.component.scss
Normal file
82
lib/process-services/people/people.component.scss
Normal file
@@ -0,0 +1,82 @@
|
||||
@mixin adf-task-list-people-theme($theme) {
|
||||
$primary: map-get($theme, primary);
|
||||
|
||||
.assignment-header {
|
||||
border-bottom: 1px solid #eee;
|
||||
padding: 6px 20px;
|
||||
}
|
||||
|
||||
.assigment-count {
|
||||
float: left;
|
||||
padding: 10px 0px;
|
||||
font-weight: bolder;
|
||||
opacity: 0.54;
|
||||
}
|
||||
|
||||
.add-people {
|
||||
float: right;
|
||||
padding: 8px;
|
||||
height: 26px;
|
||||
opacity: 0.54;
|
||||
cursor: pointer;
|
||||
&:hover {
|
||||
color: mat-color($primary);
|
||||
}
|
||||
}
|
||||
|
||||
.assignment-top-container.mat-card {
|
||||
border-top: 2px solid #eee;
|
||||
margin: 0px;
|
||||
padding: 0px;
|
||||
display: flex;
|
||||
flex-flow: row wrap;
|
||||
align-items: stretch;
|
||||
}
|
||||
|
||||
.assignment-top-container-content {
|
||||
display: flex;
|
||||
flex-flow: column;
|
||||
align-items: stretch;
|
||||
flex: 1 0 auto;
|
||||
max-width: 100%;
|
||||
}
|
||||
|
||||
.assignment-container {
|
||||
padding: 10px 20px;
|
||||
border-bottom: 1px solid #eee;
|
||||
max-width: 100%;
|
||||
}
|
||||
|
||||
.assignment-list-container {
|
||||
padding: 0px;
|
||||
}
|
||||
|
||||
adf-people-list ::ng-deep adf-datatable ::ng-deep {
|
||||
thead {
|
||||
display: none;
|
||||
}
|
||||
.people-email {
|
||||
opacity: 0.54;
|
||||
}
|
||||
}
|
||||
|
||||
.people-img {
|
||||
border-radius: 90%;
|
||||
width: 40px;
|
||||
height: 40px;
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
.adf-people-search-people-pic {
|
||||
background: mat-color($primary);
|
||||
width: 30px;
|
||||
padding: 10px 5px;
|
||||
border-radius: 100px;
|
||||
color: #fff;
|
||||
text-align: center;
|
||||
font-weight: bolder;
|
||||
font-size: 18px;
|
||||
text-transform: uppercase;
|
||||
vertical-align: text-bottom;
|
||||
}
|
||||
}
|
243
lib/process-services/people/people.component.spec.ts
Normal file
243
lib/process-services/people/people.component.spec.ts
Normal file
@@ -0,0 +1,243 @@
|
||||
/*!
|
||||
* @license
|
||||
* Copyright 2016 Alfresco Software, Ltd.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { NO_ERRORS_SCHEMA } from '@angular/core';
|
||||
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
import { MatButtonModule, MatInputModule } from '@angular/material';
|
||||
import { LogService } from '@alfresco/core';
|
||||
import { PeopleProcessService, UserProcessModel } from '@alfresco/core';
|
||||
import { PeopleListComponent } from './people-list.component';
|
||||
import { PeopleSearchComponent } from './people-search.component';
|
||||
import { PeopleComponent } from './people.component';
|
||||
|
||||
declare let jasmine: any;
|
||||
|
||||
const fakeUser: UserProcessModel = new UserProcessModel({
|
||||
id: 'fake-id',
|
||||
firstName: 'fake-name',
|
||||
lastName: 'fake-last',
|
||||
email: 'fake@mail.com'
|
||||
});
|
||||
|
||||
const fakeSecondUser: UserProcessModel = new UserProcessModel({
|
||||
id: 'fake-involve-id',
|
||||
firstName: 'fake-involve-name',
|
||||
lastName: 'fake-involve-last',
|
||||
email: 'fake-involve@mail.com'
|
||||
});
|
||||
|
||||
describe('PeopleComponent', () => {
|
||||
|
||||
let activitiPeopleComponent: PeopleComponent;
|
||||
let fixture: ComponentFixture<PeopleComponent>;
|
||||
let element: HTMLElement;
|
||||
let userArray = [fakeUser, fakeSecondUser];
|
||||
let logService: LogService;
|
||||
|
||||
beforeEach(async(() => {
|
||||
TestBed.configureTestingModule({
|
||||
imports: [
|
||||
MatButtonModule,
|
||||
MatInputModule
|
||||
],
|
||||
declarations: [
|
||||
PeopleSearchComponent,
|
||||
PeopleListComponent,
|
||||
PeopleComponent
|
||||
],
|
||||
providers: [
|
||||
PeopleProcessService
|
||||
],
|
||||
schemas: [ NO_ERRORS_SCHEMA ]
|
||||
}).compileComponents().then(() => {
|
||||
|
||||
logService = TestBed.get(LogService);
|
||||
fixture = TestBed.createComponent(PeopleComponent);
|
||||
activitiPeopleComponent = fixture.componentInstance;
|
||||
element = fixture.nativeElement;
|
||||
|
||||
activitiPeopleComponent.people = [];
|
||||
activitiPeopleComponent.readOnly = true;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
}));
|
||||
|
||||
it('should show people component title', async(() => {
|
||||
activitiPeopleComponent.people = [...userArray];
|
||||
fixture.detectChanges();
|
||||
fixture.whenStable()
|
||||
.then(() => {
|
||||
expect(element.querySelector('#people-title')).toBeDefined();
|
||||
expect(element.querySelector('#people-title')).not.toBeNull();
|
||||
});
|
||||
}));
|
||||
|
||||
it('should show no people involved message', () => {
|
||||
fixture.whenStable()
|
||||
.then(() => {
|
||||
expect(element.querySelector('#no-people-label')).not.toBeNull();
|
||||
expect(element.querySelector('#no-people-label').textContent).toContain('ADF_TASK_LIST.DETAILS.PEOPLE.NONE');
|
||||
});
|
||||
});
|
||||
|
||||
describe('when there are involved people', () => {
|
||||
|
||||
beforeEach(() => {
|
||||
activitiPeopleComponent.taskId = 'fake-task-id';
|
||||
activitiPeopleComponent.people.push(...userArray);
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
beforeEach(() => {
|
||||
jasmine.Ajax.install();
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
jasmine.Ajax.uninstall();
|
||||
});
|
||||
|
||||
it('should show people involved', async(() => {
|
||||
fixture.whenStable()
|
||||
.then(() => {
|
||||
let gatewayElement: any = element.querySelector('#assignment-people-list tbody');
|
||||
expect(gatewayElement).not.toBeNull();
|
||||
expect(gatewayElement.children.length).toBe(2);
|
||||
});
|
||||
}));
|
||||
|
||||
it('should remove pepole involved', async(() => {
|
||||
activitiPeopleComponent.removeInvolvedUser(fakeUser);
|
||||
jasmine.Ajax.requests.mostRecent().respondWith({
|
||||
status: 200
|
||||
});
|
||||
fixture.whenStable()
|
||||
.then(() => {
|
||||
fixture.detectChanges();
|
||||
let gatewayElement: any = element.querySelector('#assignment-people-list tbody');
|
||||
expect(gatewayElement).not.toBeNull();
|
||||
expect(gatewayElement.children.length).toBe(1);
|
||||
});
|
||||
}));
|
||||
|
||||
it('should involve pepole', async(() => {
|
||||
activitiPeopleComponent.involveUser(fakeUser);
|
||||
jasmine.Ajax.requests.mostRecent().respondWith({
|
||||
status: 200
|
||||
});
|
||||
fixture.whenStable()
|
||||
.then(() => {
|
||||
fixture.detectChanges();
|
||||
let gatewayElement: any = element.querySelector('#assignment-people-list tbody');
|
||||
expect(gatewayElement).not.toBeNull();
|
||||
expect(gatewayElement.children.length).toBe(3);
|
||||
});
|
||||
}));
|
||||
|
||||
it('should return an observable with user search results', (done) => {
|
||||
activitiPeopleComponent.peopleSearch$.subscribe((users) => {
|
||||
expect(users.length).toBe(2);
|
||||
expect(users[0].firstName).toBe('fake-test-1');
|
||||
expect(users[0].lastName).toBe('fake-last-1');
|
||||
expect(users[0].email).toBe('fake-test-1@test.com');
|
||||
expect(users[0].id).toBe(1);
|
||||
done();
|
||||
});
|
||||
activitiPeopleComponent.searchUser('fake-search-word');
|
||||
jasmine.Ajax.requests.mostRecent().respondWith({
|
||||
status: 200,
|
||||
contentType: 'json',
|
||||
responseText: {
|
||||
data: [{
|
||||
id: 1,
|
||||
firstName: 'fake-test-1',
|
||||
lastName: 'fake-last-1',
|
||||
email: 'fake-test-1@test.com'
|
||||
}, {
|
||||
id: 2,
|
||||
firstName: 'fake-test-2',
|
||||
lastName: 'fake-last-2',
|
||||
email: 'fake-test-2@test.com'
|
||||
}]
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
xit('should return an empty list for not valid search', (done) => {
|
||||
activitiPeopleComponent.peopleSearch$.subscribe((users) => {
|
||||
expect(users.length).toBe(0);
|
||||
done();
|
||||
});
|
||||
activitiPeopleComponent.searchUser('fake-search-word');
|
||||
jasmine.Ajax.requests.mostRecent().respondWith({
|
||||
status: 200,
|
||||
contentType: 'json',
|
||||
responseText: {}
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('when there are errors on service call', () => {
|
||||
|
||||
beforeEach(() => {
|
||||
jasmine.Ajax.install();
|
||||
activitiPeopleComponent.people.push(...userArray);
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
jasmine.Ajax.uninstall();
|
||||
});
|
||||
|
||||
it('should log error message when search fails', async(() => {
|
||||
activitiPeopleComponent.peopleSearch$.subscribe(() => {
|
||||
expect(logService.error).toHaveBeenCalledWith('Could not load users');
|
||||
});
|
||||
activitiPeopleComponent.searchUser('fake-search');
|
||||
jasmine.Ajax.requests.mostRecent().respondWith({
|
||||
status: 403
|
||||
});
|
||||
}));
|
||||
|
||||
it('should not remove user if remove involved user fail', async(() => {
|
||||
activitiPeopleComponent.removeInvolvedUser(fakeUser);
|
||||
jasmine.Ajax.requests.mostRecent().respondWith({
|
||||
status: 403
|
||||
});
|
||||
fixture.whenStable()
|
||||
.then(() => {
|
||||
fixture.detectChanges();
|
||||
let gatewayElement: any = element.querySelector('#assignment-people-list tbody');
|
||||
expect(gatewayElement).not.toBeNull();
|
||||
expect(gatewayElement.children.length).toBe(2);
|
||||
});
|
||||
}));
|
||||
|
||||
it('should not involve user if involve user fail', async(() => {
|
||||
activitiPeopleComponent.involveUser(fakeUser);
|
||||
jasmine.Ajax.requests.mostRecent().respondWith({
|
||||
status: 403
|
||||
});
|
||||
fixture.whenStable()
|
||||
.then(() => {
|
||||
fixture.detectChanges();
|
||||
let gatewayElement: any = element.querySelector('#assignment-people-list tbody');
|
||||
expect(gatewayElement).not.toBeNull();
|
||||
expect(gatewayElement.children.length).toBe(2);
|
||||
});
|
||||
}));
|
||||
});
|
||||
});
|
127
lib/process-services/people/people.component.ts
Normal file
127
lib/process-services/people/people.component.ts
Normal file
@@ -0,0 +1,127 @@
|
||||
/*!
|
||||
* @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 { LogService, UserProcessModel } from '@alfresco/core';
|
||||
import { PeopleProcessService } from '@alfresco/core';
|
||||
import { AfterViewInit, Component, Input, OnInit, ViewChild } from '@angular/core';
|
||||
import { Observable, Observer } from 'rxjs/Rx';
|
||||
import { UserEventModel } from '../task-list/models/user-event.model';
|
||||
import { PeopleSearchComponent } from './people-search.component';
|
||||
|
||||
@Component({
|
||||
selector: 'adf-people',
|
||||
templateUrl: './people.component.html',
|
||||
styleUrls: ['./people.component.scss']
|
||||
})
|
||||
export class PeopleComponent implements OnInit, AfterViewInit {
|
||||
|
||||
@Input()
|
||||
people: UserProcessModel[] = [];
|
||||
|
||||
@Input()
|
||||
taskId: string = '';
|
||||
|
||||
@Input()
|
||||
readOnly: boolean = false;
|
||||
|
||||
@ViewChild(PeopleSearchComponent)
|
||||
peopleSearch: PeopleSearchComponent;
|
||||
|
||||
showAssignment: boolean = false;
|
||||
|
||||
private peopleSearchObserver: Observer<UserProcessModel[]>;
|
||||
peopleSearch$: Observable<UserProcessModel[]>;
|
||||
|
||||
constructor(private logService: LogService, public peopleProcessService: PeopleProcessService) {
|
||||
this.peopleSearch$ = new Observable<UserProcessModel[]>(observer => this.peopleSearchObserver = observer).share();
|
||||
}
|
||||
|
||||
ngOnInit() {
|
||||
}
|
||||
|
||||
ngAfterViewInit() {
|
||||
}
|
||||
|
||||
involveUserAndCloseSearch() {
|
||||
if (this.peopleSearch) {
|
||||
this.peopleSearch.involveUserAndClose();
|
||||
}
|
||||
}
|
||||
|
||||
involveUserWithoutCloseSearch() {
|
||||
if (this.peopleSearch) {
|
||||
this.peopleSearch.involveUser();
|
||||
}
|
||||
}
|
||||
|
||||
searchUser(searchedWord: string) {
|
||||
this.peopleProcessService.getWorkflowUsers(this.taskId, searchedWord)
|
||||
.subscribe((users) => {
|
||||
this.peopleSearchObserver.next(users);
|
||||
}, error => this.logService.error(error));
|
||||
}
|
||||
|
||||
involveUser(user: UserProcessModel) {
|
||||
this.peopleProcessService.involveUserWithTask(this.taskId, user.id.toString())
|
||||
.subscribe(() => {
|
||||
this.people = [...this.people, user];
|
||||
}, error => this.logService.error('Impossible to involve user with task'));
|
||||
}
|
||||
|
||||
removeInvolvedUser(user: UserProcessModel) {
|
||||
this.peopleProcessService.removeInvolvedUser(this.taskId, user.id.toString())
|
||||
.subscribe(() => {
|
||||
this.people = this.people.filter((involvedUser) => {
|
||||
return involvedUser.id !== user.id;
|
||||
});
|
||||
}, error => this.logService.error('Impossible to remove involved user from task'));
|
||||
}
|
||||
|
||||
getDisplayUser(firstName: string, lastName: string, delimiter: string = '-'): string {
|
||||
firstName = (firstName !== null ? firstName : '');
|
||||
lastName = (lastName !== null ? lastName : '');
|
||||
return firstName + delimiter + lastName;
|
||||
}
|
||||
|
||||
getInitialUserName(firstName: string, lastName: string) {
|
||||
firstName = (firstName !== null && firstName !== '' ? firstName[0] : '');
|
||||
lastName = (lastName !== null && lastName !== '' ? lastName[0] : '');
|
||||
return this.getDisplayUser(firstName, lastName, '');
|
||||
}
|
||||
|
||||
onAddAssignement() {
|
||||
this.showAssignment = true;
|
||||
}
|
||||
|
||||
onClickAction(event: UserEventModel) {
|
||||
if (event.type === 'remove') {
|
||||
this.removeInvolvedUser(event.value);
|
||||
}
|
||||
}
|
||||
|
||||
hasPeople() {
|
||||
return this.people && this.people.length > 0;
|
||||
}
|
||||
|
||||
isEditMode() {
|
||||
return !this.readOnly;
|
||||
}
|
||||
|
||||
onCloseSearch() {
|
||||
this.showAssignment = false;
|
||||
}
|
||||
}
|
55
lib/process-services/people/people.module.ts
Normal file
55
lib/process-services/people/people.module.ts
Normal file
@@ -0,0 +1,55 @@
|
||||
/*!
|
||||
* @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 { CommonModule } from '@angular/common';
|
||||
import { NgModule } from '@angular/core';
|
||||
import { TranslateModule } from '@ngx-translate/core';
|
||||
import { MaterialModule } from '../material.module';
|
||||
import { FormsModule, ReactiveFormsModule } from '@angular/forms';
|
||||
|
||||
import { DataColumnModule, DataTableModule } from '@alfresco/core';
|
||||
import { PeopleComponent } from './people.component';
|
||||
import { PeopleListComponent } from './people-list.component';
|
||||
import { PeopleSearchActionLabelDirective, PeopleSearchComponent, PeopleSearchTitleDirective } from './people-search.component';
|
||||
|
||||
@NgModule({
|
||||
imports: [
|
||||
FormsModule,
|
||||
ReactiveFormsModule,
|
||||
DataColumnModule,
|
||||
DataTableModule,
|
||||
MaterialModule,
|
||||
CommonModule,
|
||||
TranslateModule
|
||||
],
|
||||
declarations: [
|
||||
PeopleComponent,
|
||||
PeopleSearchComponent,
|
||||
PeopleSearchTitleDirective,
|
||||
PeopleSearchActionLabelDirective,
|
||||
PeopleListComponent
|
||||
],
|
||||
exports: [
|
||||
PeopleComponent,
|
||||
PeopleSearchComponent,
|
||||
PeopleSearchTitleDirective,
|
||||
PeopleSearchActionLabelDirective,
|
||||
PeopleListComponent
|
||||
]
|
||||
})
|
||||
export class PeopleModule {
|
||||
}
|
22
lib/process-services/people/public-api.ts
Normal file
22
lib/process-services/people/public-api.ts
Normal file
@@ -0,0 +1,22 @@
|
||||
/*!
|
||||
* @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.
|
||||
*/
|
||||
|
||||
export * from './people.component';
|
||||
export * from './people-list.component';
|
||||
export * from './people-search.component';
|
||||
|
||||
export * from './people.module';
|
@@ -0,0 +1,208 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<svg width="566px" height="165px" viewBox="0 0 566 165" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
|
||||
<!-- Generator: Sketch 3.8.3 (29802) - http://www.bohemiancoding.com/sketch -->
|
||||
<title>empty_doc_lib</title>
|
||||
<desc>Created with Sketch.</desc>
|
||||
<defs>
|
||||
<rect id="path-1" x="5.68434189e-14" y="-1.01962883e-12" width="78.1679389" height="78.1679389" rx="2"></rect>
|
||||
<filter x="-50%" y="-50%" width="200%" height="200%" filterUnits="objectBoundingBox" id="filter-2">
|
||||
<feOffset dx="0" dy="2" in="SourceAlpha" result="shadowOffsetOuter1"></feOffset>
|
||||
<feGaussianBlur stdDeviation="1" in="shadowOffsetOuter1" result="shadowBlurOuter1"></feGaussianBlur>
|
||||
<feColorMatrix values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.24 0" type="matrix" in="shadowBlurOuter1" result="shadowMatrixOuter1"></feColorMatrix>
|
||||
<feOffset dx="0" dy="0" in="SourceAlpha" result="shadowOffsetOuter2"></feOffset>
|
||||
<feGaussianBlur stdDeviation="1" in="shadowOffsetOuter2" result="shadowBlurOuter2"></feGaussianBlur>
|
||||
<feColorMatrix values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.12 0" type="matrix" in="shadowBlurOuter2" result="shadowMatrixOuter2"></feColorMatrix>
|
||||
<feMerge>
|
||||
<feMergeNode in="shadowMatrixOuter1"></feMergeNode>
|
||||
<feMergeNode in="shadowMatrixOuter2"></feMergeNode>
|
||||
</feMerge>
|
||||
</filter>
|
||||
<rect id="path-3" x="-4.54747351e-13" y="5.68434189e-13" width="78.1679389" height="78.1679389" rx="2"></rect>
|
||||
<filter x="-50%" y="-50%" width="200%" height="200%" filterUnits="objectBoundingBox" id="filter-4">
|
||||
<feOffset dx="0" dy="2" in="SourceAlpha" result="shadowOffsetOuter1"></feOffset>
|
||||
<feGaussianBlur stdDeviation="1" in="shadowOffsetOuter1" result="shadowBlurOuter1"></feGaussianBlur>
|
||||
<feColorMatrix values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.24 0" type="matrix" in="shadowBlurOuter1" result="shadowMatrixOuter1"></feColorMatrix>
|
||||
<feOffset dx="0" dy="0" in="SourceAlpha" result="shadowOffsetOuter2"></feOffset>
|
||||
<feGaussianBlur stdDeviation="1" in="shadowOffsetOuter2" result="shadowBlurOuter2"></feGaussianBlur>
|
||||
<feColorMatrix values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.12 0" type="matrix" in="shadowBlurOuter2" result="shadowMatrixOuter2"></feColorMatrix>
|
||||
<feMerge>
|
||||
<feMergeNode in="shadowMatrixOuter1"></feMergeNode>
|
||||
<feMergeNode in="shadowMatrixOuter2"></feMergeNode>
|
||||
</feMerge>
|
||||
</filter>
|
||||
<rect id="path-5" x="-1.08002496e-12" y="7.81597009e-14" width="78.1679389" height="78.1679389" rx="2"></rect>
|
||||
<filter x="-50%" y="-50%" width="200%" height="200%" filterUnits="objectBoundingBox" id="filter-6">
|
||||
<feOffset dx="0" dy="2" in="SourceAlpha" result="shadowOffsetOuter1"></feOffset>
|
||||
<feGaussianBlur stdDeviation="1" in="shadowOffsetOuter1" result="shadowBlurOuter1"></feGaussianBlur>
|
||||
<feColorMatrix values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.24 0" type="matrix" in="shadowBlurOuter1" result="shadowMatrixOuter1"></feColorMatrix>
|
||||
<feOffset dx="0" dy="0" in="SourceAlpha" result="shadowOffsetOuter2"></feOffset>
|
||||
<feGaussianBlur stdDeviation="1" in="shadowOffsetOuter2" result="shadowBlurOuter2"></feGaussianBlur>
|
||||
<feColorMatrix values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.12 0" type="matrix" in="shadowBlurOuter2" result="shadowMatrixOuter2"></feColorMatrix>
|
||||
<feMerge>
|
||||
<feMergeNode in="shadowMatrixOuter1"></feMergeNode>
|
||||
<feMergeNode in="shadowMatrixOuter2"></feMergeNode>
|
||||
</feMerge>
|
||||
</filter>
|
||||
<rect id="path-7" x="1.29318778e-12" y="9.23705556e-14" width="78.1679389" height="78.1679389" rx="2"></rect>
|
||||
<filter x="-50%" y="-50%" width="200%" height="200%" filterUnits="objectBoundingBox" id="filter-8">
|
||||
<feOffset dx="0" dy="2" in="SourceAlpha" result="shadowOffsetOuter1"></feOffset>
|
||||
<feGaussianBlur stdDeviation="1" in="shadowOffsetOuter1" result="shadowBlurOuter1"></feGaussianBlur>
|
||||
<feColorMatrix values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.24 0" type="matrix" in="shadowBlurOuter1" result="shadowMatrixOuter1"></feColorMatrix>
|
||||
<feOffset dx="0" dy="0" in="SourceAlpha" result="shadowOffsetOuter2"></feOffset>
|
||||
<feGaussianBlur stdDeviation="1" in="shadowOffsetOuter2" result="shadowBlurOuter2"></feGaussianBlur>
|
||||
<feColorMatrix values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.12 0" type="matrix" in="shadowBlurOuter2" result="shadowMatrixOuter2"></feColorMatrix>
|
||||
<feMerge>
|
||||
<feMergeNode in="shadowMatrixOuter1"></feMergeNode>
|
||||
<feMergeNode in="shadowMatrixOuter2"></feMergeNode>
|
||||
</feMerge>
|
||||
</filter>
|
||||
<rect id="path-9" x="-2.96651592e-13" y="-7.60280727e-13" width="78.1679389" height="78.1679389" rx="2"></rect>
|
||||
<filter x="-50%" y="-50%" width="200%" height="200%" filterUnits="objectBoundingBox" id="filter-10">
|
||||
<feOffset dx="0" dy="2" in="SourceAlpha" result="shadowOffsetOuter1"></feOffset>
|
||||
<feGaussianBlur stdDeviation="1" in="shadowOffsetOuter1" result="shadowBlurOuter1"></feGaussianBlur>
|
||||
<feColorMatrix values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.24 0" type="matrix" in="shadowBlurOuter1" result="shadowMatrixOuter1"></feColorMatrix>
|
||||
<feOffset dx="0" dy="0" in="SourceAlpha" result="shadowOffsetOuter2"></feOffset>
|
||||
<feGaussianBlur stdDeviation="1" in="shadowOffsetOuter2" result="shadowBlurOuter2"></feGaussianBlur>
|
||||
<feColorMatrix values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.12 0" type="matrix" in="shadowBlurOuter2" result="shadowMatrixOuter2"></feColorMatrix>
|
||||
<feMerge>
|
||||
<feMergeNode in="shadowMatrixOuter1"></feMergeNode>
|
||||
<feMergeNode in="shadowMatrixOuter2"></feMergeNode>
|
||||
</feMerge>
|
||||
</filter>
|
||||
<rect id="path-11" x="3.48165941e-13" y="2.27373675e-13" width="78.1679389" height="78.1679389" rx="2"></rect>
|
||||
<filter x="-50%" y="-50%" width="200%" height="200%" filterUnits="objectBoundingBox" id="filter-12">
|
||||
<feOffset dx="0" dy="2" in="SourceAlpha" result="shadowOffsetOuter1"></feOffset>
|
||||
<feGaussianBlur stdDeviation="1" in="shadowOffsetOuter1" result="shadowBlurOuter1"></feGaussianBlur>
|
||||
<feColorMatrix values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.24 0" type="matrix" in="shadowBlurOuter1" result="shadowMatrixOuter1"></feColorMatrix>
|
||||
<feOffset dx="0" dy="0" in="SourceAlpha" result="shadowOffsetOuter2"></feOffset>
|
||||
<feGaussianBlur stdDeviation="1" in="shadowOffsetOuter2" result="shadowBlurOuter2"></feGaussianBlur>
|
||||
<feColorMatrix values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.12 0" type="matrix" in="shadowBlurOuter2" result="shadowMatrixOuter2"></feColorMatrix>
|
||||
<feMerge>
|
||||
<feMergeNode in="shadowMatrixOuter1"></feMergeNode>
|
||||
<feMergeNode in="shadowMatrixOuter2"></feMergeNode>
|
||||
</feMerge>
|
||||
</filter>
|
||||
<rect id="path-13" x="0" y="-5.40012479e-13" width="78.1679389" height="78.1679389" rx="2"></rect>
|
||||
<filter x="-50%" y="-50%" width="200%" height="200%" filterUnits="objectBoundingBox" id="filter-14">
|
||||
<feOffset dx="0" dy="2" in="SourceAlpha" result="shadowOffsetOuter1"></feOffset>
|
||||
<feGaussianBlur stdDeviation="1" in="shadowOffsetOuter1" result="shadowBlurOuter1"></feGaussianBlur>
|
||||
<feColorMatrix values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.24 0" type="matrix" in="shadowBlurOuter1" result="shadowMatrixOuter1"></feColorMatrix>
|
||||
<feOffset dx="0" dy="0" in="SourceAlpha" result="shadowOffsetOuter2"></feOffset>
|
||||
<feGaussianBlur stdDeviation="1" in="shadowOffsetOuter2" result="shadowBlurOuter2"></feGaussianBlur>
|
||||
<feColorMatrix values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.12 0" type="matrix" in="shadowBlurOuter2" result="shadowMatrixOuter2"></feColorMatrix>
|
||||
<feMerge>
|
||||
<feMergeNode in="shadowMatrixOuter1"></feMergeNode>
|
||||
<feMergeNode in="shadowMatrixOuter2"></feMergeNode>
|
||||
</feMerge>
|
||||
</filter>
|
||||
<rect id="path-15" x="0" y="0" width="78.1679389" height="78.1679389" rx="2"></rect>
|
||||
<filter x="-50%" y="-50%" width="200%" height="200%" filterUnits="objectBoundingBox" id="filter-16">
|
||||
<feOffset dx="0" dy="2" in="SourceAlpha" result="shadowOffsetOuter1"></feOffset>
|
||||
<feGaussianBlur stdDeviation="1" in="shadowOffsetOuter1" result="shadowBlurOuter1"></feGaussianBlur>
|
||||
<feColorMatrix values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.24 0" type="matrix" in="shadowBlurOuter1" result="shadowMatrixOuter1"></feColorMatrix>
|
||||
<feOffset dx="0" dy="0" in="SourceAlpha" result="shadowOffsetOuter2"></feOffset>
|
||||
<feGaussianBlur stdDeviation="1" in="shadowOffsetOuter2" result="shadowBlurOuter2"></feGaussianBlur>
|
||||
<feColorMatrix values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.12 0" type="matrix" in="shadowBlurOuter2" result="shadowMatrixOuter2"></feColorMatrix>
|
||||
<feMerge>
|
||||
<feMergeNode in="shadowMatrixOuter1"></feMergeNode>
|
||||
<feMergeNode in="shadowMatrixOuter2"></feMergeNode>
|
||||
</feMerge>
|
||||
</filter>
|
||||
</defs>
|
||||
<g id="Symbols" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
|
||||
<g id="empty-folder-state-desktop" transform="translate(-37.000000, -168.000000)">
|
||||
<g id="empty_doc_lib" transform="translate(38.000000, 169.000000)">
|
||||
<g id="Group-5" transform="translate(241.569490, 92.634375) rotate(-355.000000) translate(-241.569490, -92.634375) translate(202.069490, 53.134375)">
|
||||
<g id="Rectangle-1196-Copy-2">
|
||||
<use fill="black" fill-opacity="1" filter="url(#filter-2)" xlink:href="#path-1"></use>
|
||||
<use fill="#FFFFFF" fill-rule="evenodd" xlink:href="#path-1"></use>
|
||||
</g>
|
||||
<g id="filetype_video" transform="translate(9.770992, 9.770992)">
|
||||
<polygon id="Fill-1" points="0 58.6259542 58.6259542 58.6259542 58.6259542 0 0 0"></polygon>
|
||||
<path d="M39.0839695,21.9847328 L43.9694656,21.9847328 L43.9694656,17.0992366 L39.0839695,17.0992366 L39.0839695,21.9847328 Z M39.0839695,31.7557252 L43.9694656,31.7557252 L43.9694656,26.870229 L39.0839695,26.870229 L39.0839695,31.7557252 Z M39.0839695,41.5267176 L43.9694656,41.5267176 L43.9694656,36.6412214 L39.0839695,36.6412214 L39.0839695,41.5267176 Z M14.6564885,21.9847328 L19.5419847,21.9847328 L19.5419847,17.0992366 L14.6564885,17.0992366 L14.6564885,21.9847328 Z M14.6564885,31.7557252 L19.5419847,31.7557252 L19.5419847,26.870229 L14.6564885,26.870229 L14.6564885,31.7557252 Z M14.6564885,41.5267176 L19.5419847,41.5267176 L19.5419847,36.6412214 L14.6564885,36.6412214 L14.6564885,41.5267176 Z M43.9694656,7.32824427 L43.9694656,12.2137405 L39.0839695,12.2137405 L39.0839695,7.32824427 L19.5419847,7.32824427 L19.5419847,12.2137405 L14.6564885,12.2137405 L14.6564885,7.32824427 L9.77099237,7.32824427 L9.77099237,51.2977099 L14.6564885,51.2977099 L14.6564885,46.4122137 L19.5419847,46.4122137 L19.5419847,51.2977099 L39.0839695,51.2977099 L39.0839695,46.4122137 L43.9694656,46.4122137 L43.9694656,51.2977099 L48.8549618,51.2977099 L48.8549618,7.32824427 L43.9694656,7.32824427 Z" id="Fill-2" fill="#FFC107"></path>
|
||||
</g>
|
||||
</g>
|
||||
<g id="Group-7" transform="translate(515.948329, 81.354522) rotate(-345.000000) translate(-515.948329, -81.354522) translate(476.448329, 41.854522)">
|
||||
<g id="Rectangle-1196-Copy-3">
|
||||
<use fill="black" fill-opacity="1" filter="url(#filter-4)" xlink:href="#path-3"></use>
|
||||
<use fill="#FFFFFF" fill-rule="evenodd" xlink:href="#path-3"></use>
|
||||
</g>
|
||||
<g id="filetype_image" transform="translate(9.770992, 9.770992)">
|
||||
<polygon id="Fill-1" points="0 58.6259542 58.6259542 58.6259542 58.6259542 0 0 0"></polygon>
|
||||
<path d="M20.7636031,32.9773435 L26.8704733,40.3178015 L35.4200916,29.3132214 L46.412458,43.9697099 L12.2139847,43.9697099 L20.7636031,32.9773435 Z M51.2979542,46.412458 L51.2979542,12.2139847 C51.2979542,9.51474809 49.1116947,7.32848855 46.412458,7.32848855 L12.2139847,7.32848855 C9.51474809,7.32848855 7.32848855,9.51474809 7.32848855,12.2139847 L7.32848855,46.412458 C7.32848855,49.1116947 9.51474809,51.2979542 12.2139847,51.2979542 L46.412458,51.2979542 C49.1116947,51.2979542 51.2979542,49.1116947 51.2979542,46.412458 L51.2979542,46.412458 Z" id="Fill-2" fill="#22BE73"></path>
|
||||
</g>
|
||||
</g>
|
||||
<g id="Group-8" transform="translate(309.051884, 62.261808) rotate(-5.000000) translate(-309.051884, -62.261808) translate(269.551884, 22.761808)">
|
||||
<g id="Rectangle-1196-Copy-4">
|
||||
<use fill="black" fill-opacity="1" filter="url(#filter-6)" xlink:href="#path-5"></use>
|
||||
<use fill="#FFFFFF" fill-rule="evenodd" xlink:href="#path-5"></use>
|
||||
</g>
|
||||
<g id="filetype_googledocs" transform="translate(9.770992, 9.770992)">
|
||||
<polygon id="Fill-1" points="6.82121026e-13 58.6259542 58.6259542 58.6259542 58.6259542 -2.98427949e-13 6.82121026e-13 -2.98427949e-13"></polygon>
|
||||
<g id="Group-6" transform="translate(9.770992, 4.885496)">
|
||||
<path d="M7.32824427,21.9847328 L31.7557252,21.9847328 L31.7557252,19.5419847 L7.32824427,19.5419847 L7.32824427,21.9847328 Z M7.32824427,26.870229 L31.7557252,26.870229 L31.7557252,24.4274809 L7.32824427,24.4274809 L7.32824427,26.870229 Z M7.32824427,31.7557252 L31.7557252,31.7557252 L31.7557252,29.3129771 L7.32824427,29.3129771 L7.32824427,31.7557252 Z M7.32824427,36.6412214 L21.9847328,36.6412214 L21.9847328,34.1984733 L7.32824427,34.1984733 L7.32824427,36.6412214 Z M29.3129771,0 L4.88549618,0 C2.18625954,0 0.0244274809,2.18625954 0.0244274809,4.88549618 L0,43.9694656 C0,46.6687023 2.16183206,48.8549618 4.8610687,48.8549618 L34.1984733,48.8549618 C36.8977099,48.8549618 39.0839695,46.6687023 39.0839695,43.9694656 L39.0839695,9.77099237 L29.3129771,0 Z" id="Fill-2" fill="#2979FF"></path>
|
||||
<polygon id="Fill-4" fill-opacity="0.5" fill="#FFFFFF" points="29.3129771 9.77099237 29.3129771 -2.84217094e-14 39.0839695 9.77099237"></polygon>
|
||||
<polygon id="Fill-5" fill-opacity="0.2" fill="#000000" points="39.0839695 9.77099237 39.0839695 19.5419847 29.3129771 9.77099237"></polygon>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
<g id="Group-9" transform="translate(155.408682, 49.364493) rotate(-345.000000) translate(-155.408682, -49.364493) translate(115.908682, 9.864493)">
|
||||
<g id="Rectangle-1196-Copy-5">
|
||||
<use fill="black" fill-opacity="1" filter="url(#filter-8)" xlink:href="#path-7"></use>
|
||||
<use fill="#FFFFFF" fill-rule="evenodd" xlink:href="#path-7"></use>
|
||||
</g>
|
||||
<g id="filetype_pdf" transform="translate(9.770992, 9.770992)">
|
||||
<polygon id="Fill-1" points="0 58.6259542 58.6259542 58.6259542 58.6259542 0 0 0"></polygon>
|
||||
<path d="M45.1888855,25.5877863 L45.1888855,21.9187786 L37.853313,21.9187786 L37.853313,36.5923664 L41.5198779,36.5923664 L41.5198779,31.7777099 L45.1888855,31.7777099 L45.1888855,28.1087023 L41.5198779,28.1087023 L41.5198779,25.5877863 L45.1888855,25.5877863 Z M29.3696489,32.9233588 L31.7757557,32.9233588 L31.7757557,25.5877863 L29.3696489,25.5877863 L29.3696489,32.9233588 Z M35.4447634,32.9233588 L35.4447634,25.5877863 C35.4447634,24.5960305 35.1027786,23.7361832 34.4139237,23.0082443 C33.7275115,22.2827481 32.8481221,21.9187786 31.7781985,21.9187786 L25.703084,21.9187786 L25.703084,36.5923664 L31.7781985,36.5923664 C32.8481221,36.5923664 33.7275115,36.2308397 34.4139237,35.5029008 C35.1027786,34.7774046 35.4447634,33.9175573 35.4447634,32.9233588 L35.4447634,32.9233588 Z M17.1070534,28.1087023 L19.5131603,28.1087023 L19.5131603,25.5877863 L17.1070534,25.5877863 L17.1070534,28.1087023 Z M23.1821679,28.1087023 L23.1821679,25.5877863 C23.1821679,24.5960305 22.8181985,23.7361832 22.0927023,23.0082443 C21.3672061,22.2827481 20.5073588,21.9187786 19.5131603,21.9187786 L13.4380458,21.9187786 L13.4380458,36.5923664 L17.1070534,36.5923664 L17.1070534,31.7777099 L19.5131603,31.7777099 C20.5073588,31.7777099 21.3672061,31.4161832 22.0927023,30.6882443 C22.8181985,29.9627481 23.1821679,29.1029008 23.1821679,28.1087023 L23.1821679,28.1087023 Z M46.483542,7.32824427 C47.783084,7.32824427 48.9091908,7.8070229 49.8643053,8.7621374 C50.8218626,9.71725191 51.2981985,10.8433588 51.2981985,12.1429008 L51.2981985,46.3682443 C51.2981985,47.670229 50.8218626,48.8158779 49.8643053,49.8076336 C48.9091908,50.8018321 47.783084,51.2977099 46.483542,51.2977099 L12.2581985,51.2977099 C10.9586565,51.2977099 9.81300763,50.8018321 8.81880916,49.8076336 C7.82461069,48.8158779 7.32873282,47.670229 7.32873282,46.3682443 L7.32873282,12.1429008 C7.32873282,10.8433588 7.82461069,9.71725191 8.81880916,8.7621374 C9.81300763,7.8070229 10.9586565,7.32824427 12.2581985,7.32824427 L46.483542,7.32824427 Z" id="Fill-2" fill="#E91E63"></path>
|
||||
</g>
|
||||
</g>
|
||||
<g id="Group-12" transform="translate(49.364493, 62.584254) rotate(-15.000000) translate(-49.364493, -62.584254) translate(9.864493, 23.084254)">
|
||||
<g id="Rectangle-1196-Copy-7">
|
||||
<use fill="black" fill-opacity="1" filter="url(#filter-10)" xlink:href="#path-9"></use>
|
||||
<use fill="#FFFFFF" fill-rule="evenodd" xlink:href="#path-9"></use>
|
||||
</g>
|
||||
<g id="filetype_forms" transform="translate(9.770992, 9.770992)">
|
||||
<polygon id="Fill-1" points="0 58.6259542 58.6259542 58.6259542 58.6259542 0 0 0"></polygon>
|
||||
<path d="M24.4274809,24.4250382 L41.5267176,24.4250382 L41.5267176,19.539542 L24.4274809,19.539542 L24.4274809,24.4250382 Z M24.4274809,31.7532824 L41.5267176,31.7532824 L41.5267176,26.8677863 L24.4274809,26.8677863 L24.4274809,31.7532824 Z M24.4274809,39.0839695 L41.5267176,39.0839695 L41.5267176,34.1984733 L24.4274809,34.1984733 L24.4274809,39.0839695 Z M17.0992366,24.4250382 L21.9847328,24.4250382 L21.9847328,19.539542 L17.0992366,19.539542 L17.0992366,24.4250382 Z M17.0992366,31.7532824 L21.9847328,31.7532824 L21.9847328,26.8677863 L17.0992366,26.8677863 L17.0992366,31.7532824 Z M17.0992366,39.0839695 L21.9847328,39.0839695 L21.9847328,34.1984733 L17.0992366,34.1984733 L17.0992366,39.0839695 Z M43.9694656,9.77099237 L14.6564885,9.77099237 C11.9694656,9.77099237 9.77099237,11.9694656 9.77099237,14.6564885 L9.77099237,43.9694656 C9.77099237,46.6564885 11.9694656,48.8549618 14.6564885,48.8549618 L43.9694656,48.8549618 C46.6564885,48.8549618 48.8549618,46.6564885 48.8549618,43.9694656 L48.8549618,14.6564885 C48.8549618,11.9694656 46.6564885,9.77099237 43.9694656,9.77099237 L43.9694656,9.77099237 Z" id="Fill-2" fill="#651FFF"></path>
|
||||
</g>
|
||||
</g>
|
||||
<g id="Group-11" transform="translate(107.814782, 114.998541) rotate(-10.000000) translate(-107.814782, -114.998541) translate(68.314782, 75.498541)">
|
||||
<g id="Rectangle-1196-Copy-6">
|
||||
<use fill="black" fill-opacity="1" filter="url(#filter-12)" xlink:href="#path-11"></use>
|
||||
<use fill="#FFFFFF" fill-rule="evenodd" xlink:href="#path-11"></use>
|
||||
</g>
|
||||
<g id="filetype_excel" transform="translate(9.770992, 9.770992)">
|
||||
<polygon id="Fill-1" points="-5.68434189e-14 58.6259542 58.6259542 58.6259542 58.6259542 -1.56319402e-13 -5.68434189e-14 -1.56319402e-13"></polygon>
|
||||
<g id="Group-10" transform="translate(4.885496, 4.885496)" fill="#22BE73">
|
||||
<path d="M47.1621374,41.632 L28.848855,41.632 L28.848855,38.3025344 L33.2873282,38.3025344 L33.2873282,34.4161221 L28.848855,34.4161221 L28.848855,32.1981069 L33.2873282,32.1981069 L33.2873282,28.3116947 L28.848855,28.3116947 L28.848855,26.0936794 L33.2873282,26.0936794 L33.2873282,22.2072672 L28.848855,22.2072672 L28.848855,19.9868092 L33.2873282,19.9868092 L33.2873282,16.1028397 L28.848855,16.1028397 L28.848855,13.8823817 L33.2873282,13.8823817 L33.2873282,9.99841221 L28.848855,9.99841221 L28.848855,6.66894656 L47.1621374,6.66894656 L47.1621374,41.632 L47.1621374,41.632 Z M16.3444275,33.1141374 C15.4015267,30.7984122 14.2509924,28.5632977 13.5743511,26.1425344 C12.819542,28.3947481 11.7422901,30.5223817 10.8775573,32.730626 C9.6610687,32.7135267 8.4470229,32.6646718 7.23053435,32.613374 C8.65709924,29.821313 10.0348092,27.0072672 11.5053435,24.2323053 C10.2546565,21.3742901 8.88427481,18.572458 7.59694656,15.731542 C8.81832061,15.6582595 10.0396947,15.5874198 11.2610687,15.5190229 C12.0867176,17.690626 12.9929771,19.832916 13.6745038,22.0582595 C14.4073282,19.6985649 15.5016794,17.4781069 16.4372519,15.1990229 C17.6928244,15.1086412 18.9532824,15.032916 20.2112977,14.9718473 C18.7309924,18.0057405 17.2433588,21.0420763 15.7337405,24.0661985 C17.260458,27.1758168 18.8189313,30.2610076 20.3505344,33.3681832 C19.0143511,33.2900153 17.6806107,33.2069618 16.3444275,33.1141374 L16.3444275,33.1141374 Z M48.8329771,37.2203969 C48.8280916,27.591084 48.8158779,17.961771 48.8427481,8.32757252 C48.8036641,7.38467176 48.8720611,6.34161832 48.300458,5.51841221 C47.4845802,4.9590229 46.4512977,5.0249771 45.5132824,4.98589313 C39.9584733,5.01520611 34.4036641,5.00299237 28.848855,5.00299237 L28.848855,0.564519084 L25.551145,0.564519084 C17.0381679,2.06680916 8.5178626,3.52757252 4.68958206e-13,5.00787786 L4.68958206e-13,43.852458 C8.46900763,45.3327634 16.9429008,46.7544427 25.4021374,48.2909313 L28.848855,48.2909313 L28.848855,43.2979542 C34.6039695,43.2857405 40.359084,43.3126107 46.1068702,43.2979542 C47.0351145,43.2588702 48.4225954,43.2295573 48.6448855,42.0765802 C48.9819847,40.4839084 48.8036641,38.8350534 48.8329771,37.2203969 L48.8329771,37.2203969 Z" id="Fill-2"></path>
|
||||
<path d="M35.5077863,13.8821374 L43.2781679,13.8821374 L43.2781679,9.99816794 L35.5077863,9.99816794 L35.5077863,13.8821374 Z M35.5077863,19.9865649 L43.2781679,19.9865649 L43.2781679,16.1025954 L35.5077863,16.1025954 L35.5077863,19.9865649 Z M35.5077863,26.0909924 L43.2781679,26.0909924 L43.2781679,22.2070229 L35.5077863,22.2070229 L35.5077863,26.0909924 Z M35.5077863,32.1954198 L43.2781679,32.1954198 L43.2781679,28.3114504 L35.5077863,28.3114504 L35.5077863,32.1954198 Z M35.5077863,38.3022901 L43.2781679,38.3022901 L43.2781679,34.4183206 L35.5077863,34.4183206 L35.5077863,38.3022901 Z" id="Combined-Shape"></path>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
<g id="Group-4" transform="translate(388.820630, 86.064353) rotate(-350.000000) translate(-388.820630, -86.064353) translate(349.320630, 46.564353)">
|
||||
<g id="Rectangle-1196-Copy">
|
||||
<use fill="black" fill-opacity="1" filter="url(#filter-14)" xlink:href="#path-13"></use>
|
||||
<use fill="#FFFFFF" fill-rule="evenodd" xlink:href="#path-13"></use>
|
||||
</g>
|
||||
<g id="filetype_audio" transform="translate(9.770992, 9.770992)">
|
||||
<polygon id="Fill-1" points="-1.13686838e-13 58.6259542 58.6259542 58.6259542 58.6259542 -6.39488462e-14 -1.13686838e-13 -6.39488462e-14"></polygon>
|
||||
<path d="M29.3129771,7.32824427 L43.9694656,7.32824427 L43.9694656,17.0601527 L34.2375573,17.0601527 L34.2375573,41.5658015 C34.2375573,44.2381679 33.2629008,46.5270229 31.3160305,48.4348092 C29.3691603,50.3450382 27.0607634,51.2977099 24.3883969,51.2977099 C21.7160305,51.2977099 19.4271756,50.3450382 17.5193893,48.4348092 C15.6091603,46.5270229 14.6564885,44.2381679 14.6564885,41.5658015 C14.6564885,38.8934351 15.6091603,36.5850382 17.5193893,34.6381679 C19.4271756,32.6912977 21.7160305,31.7166412 24.3883969,31.7166412 C25.9932824,31.7166412 27.6323664,32.1758779 29.3129771,33.0919084 L29.3129771,7.32824427 Z" id="Fill-2" fill="#E91E63"></path>
|
||||
</g>
|
||||
</g>
|
||||
<g id="Group-2" transform="translate(411.603053, 1.221374)">
|
||||
<g id="Group-3">
|
||||
<g id="Rectangle-1196">
|
||||
<use fill="black" fill-opacity="1" filter="url(#filter-16)" xlink:href="#path-15"></use>
|
||||
<use fill="#FFFFFF" fill-rule="evenodd" xlink:href="#path-15"></use>
|
||||
</g>
|
||||
<polygon id="Fill-1" points="9.77099237 68.3969466 68.3969466 68.3969466 68.3969466 9.77099237 9.77099237 9.77099237"></polygon>
|
||||
</g>
|
||||
<g id="filetype_book" transform="translate(9.770992, 9.770992)">
|
||||
<polygon id="Fill-1" points="0 58.6259542 58.6259542 58.6259542 58.6259542 0 0 0"></polygon>
|
||||
<path d="M14.6564885,9.77099237 L26.870229,9.77099237 L26.870229,29.3129771 L20.7633588,25.648855 L14.6564885,29.3129771 L14.6564885,9.77099237 Z M43.9694656,4.88549618 L14.6564885,4.88549618 C11.9572519,4.88549618 9.77099237,7.07175573 9.77099237,9.77099237 L9.77099237,48.8549618 C9.77099237,51.5541985 11.9572519,53.740458 14.6564885,53.740458 L43.9694656,53.740458 C46.6687023,53.740458 48.8549618,51.5541985 48.8549618,48.8549618 L48.8549618,9.77099237 C48.8549618,7.07175573 46.6687023,4.88549618 43.9694656,4.88549618 L43.9694656,4.88549618 Z" id="Fill-2" fill="#FF6D40"></path>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
After Width: | Height: | Size: 26 KiB |
@@ -0,0 +1,170 @@
|
||||
/*!
|
||||
* @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 { async, ComponentFixture, fakeAsync, TestBed } from '@angular/core/testing';
|
||||
import { Observable } from 'rxjs/Rx';
|
||||
import { ProcessService } from './../services/process.service';
|
||||
import { ProcessAuditDirective } from './process-audit.directive';
|
||||
|
||||
declare let jasmine: any;
|
||||
|
||||
describe('ProcessAuditDirective', () => {
|
||||
|
||||
let fixture: ComponentFixture<BasicButtonComponent>;
|
||||
let component: BasicButtonComponent;
|
||||
let service: ProcessService;
|
||||
|
||||
function createFakePdfBlob(): Blob {
|
||||
let pdfData = atob(
|
||||
'JVBERi0xLjcKCjEgMCBvYmogICUgZW50cnkgcG9pbnQKPDwKICAvVHlwZSAvQ2F0YWxvZwog' +
|
||||
'IC9QYWdlcyAyIDAgUgo+PgplbmRvYmoKCjIgMCBvYmoKPDwKICAvVHlwZSAvUGFnZXMKICAv' +
|
||||
'TWVkaWFCb3ggWyAwIDAgMjAwIDIwMCBdCiAgL0NvdW50IDEKICAvS2lkcyBbIDMgMCBSIF0K' +
|
||||
'Pj4KZW5kb2JqCgozIDAgb2JqCjw8CiAgL1R5cGUgL1BhZ2UKICAvUGFyZW50IDIgMCBSCiAg' +
|
||||
'L1Jlc291cmNlcyA8PAogICAgL0ZvbnQgPDwKICAgICAgL0YxIDQgMCBSIAogICAgPj4KICA+' +
|
||||
'PgogIC9Db250ZW50cyA1IDAgUgo+PgplbmRvYmoKCjQgMCBvYmoKPDwKICAvVHlwZSAvRm9u' +
|
||||
'dAogIC9TdWJ0eXBlIC9UeXBlMQogIC9CYXNlRm9udCAvVGltZXMtUm9tYW4KPj4KZW5kb2Jq' +
|
||||
'Cgo1IDAgb2JqICAlIHBhZ2UgY29udGVudAo8PAogIC9MZW5ndGggNDQKPj4Kc3RyZWFtCkJU' +
|
||||
'CjcwIDUwIFRECi9GMSAxMiBUZgooSGVsbG8sIHdvcmxkISkgVGoKRVQKZW5kc3RyZWFtCmVu' +
|
||||
'ZG9iagoKeHJlZgowIDYKMDAwMDAwMDAwMCA2NTUzNSBmIAowMDAwMDAwMDEwIDAwMDAwIG4g' +
|
||||
'CjAwMDAwMDAwNzkgMDAwMDAgbiAKMDAwMDAwMDE3MyAwMDAwMCBuIAowMDAwMDAwMzAxIDAw' +
|
||||
'MDAwIG4gCjAwMDAwMDAzODAgMDAwMDAgbiAKdHJhaWxlcgo8PAogIC9TaXplIDYKICAvUm9v' +
|
||||
'dCAxIDAgUgo+PgpzdGFydHhyZWYKNDkyCiUlRU9G');
|
||||
return new Blob([pdfData], {type: 'application/pdf'});
|
||||
}
|
||||
|
||||
beforeEach(async(() => {
|
||||
TestBed.configureTestingModule({
|
||||
declarations: [BasicButtonComponent, ProcessAuditDirective],
|
||||
providers: [ProcessService]
|
||||
});
|
||||
|
||||
TestBed.compileComponents();
|
||||
|
||||
fixture = TestBed.createComponent(BasicButtonComponent);
|
||||
component = fixture.componentInstance;
|
||||
service = TestBed.get(ProcessService);
|
||||
|
||||
jasmine.Ajax.install();
|
||||
}));
|
||||
|
||||
afterEach(() => {
|
||||
jasmine.Ajax.uninstall();
|
||||
});
|
||||
|
||||
it('should fetch the pdf Blob when the format is pdf', fakeAsync(() => {
|
||||
component.fileName = 'FakeAuditName';
|
||||
component.format = 'pdf';
|
||||
let blob = createFakePdfBlob();
|
||||
spyOn(service, 'fetchProcessAuditPdfById').and.returnValue(Observable.of(blob));
|
||||
spyOn(component, 'onAuditClick').and.callThrough();
|
||||
|
||||
fixture.detectChanges();
|
||||
|
||||
let button = fixture.nativeElement.querySelector('#auditButton');
|
||||
|
||||
fixture.whenStable().then(() => {
|
||||
fixture.detectChanges();
|
||||
expect(component.onAuditClick).toHaveBeenCalledWith({ format: 'pdf', value: blob, fileName: 'FakeAuditName' });
|
||||
});
|
||||
|
||||
button.click();
|
||||
|
||||
}));
|
||||
|
||||
it('should fetch the json info when the format is json', fakeAsync(() => {
|
||||
component.fileName = 'FakeAuditName';
|
||||
component.format = 'json';
|
||||
component.download = true;
|
||||
const auditJson = {
|
||||
processInstanceId: 42516, processInstanceName: 'Fake Process - August 3rd 2017',
|
||||
processDefinitionName: 'Claim Approval Process', processDefinitionVersion: 1, processInstanceStartTime: 'Thu Aug 03 15:32:47 UTC 2017', processInstanceEndTime: null,
|
||||
processInstanceDurationInMillis: null,
|
||||
processInstanceInitiator: 'MyName MyLastname',
|
||||
entries: [{
|
||||
index: 1, type: 'startForm',
|
||||
selectedOutcome: null, formData: [{
|
||||
fieldName: 'User Name',
|
||||
fieldId: 'username', value: 'dsassd'
|
||||
},
|
||||
{ fieldName: 'Claim Amount', fieldId: 'claimamount', value: '22' }], taskName: null, taskAssignee: null, activityId: null,
|
||||
activityName: null, activityType: null, startTime: null, endTime: null, durationInMillis: null
|
||||
}
|
||||
], decisionInfo: { calculatedValues: [], appliedRules: [] }
|
||||
};
|
||||
spyOn(service, 'fetchProcessAuditJsonById').and.returnValue(Observable.of(auditJson));
|
||||
spyOn(component, 'onAuditClick').and.callThrough();
|
||||
|
||||
fixture.detectChanges();
|
||||
|
||||
let button = fixture.nativeElement.querySelector('#auditButton');
|
||||
|
||||
fixture.whenStable().then(() => {
|
||||
fixture.detectChanges();
|
||||
expect(component.onAuditClick).toHaveBeenCalledWith({ format: 'json', value: auditJson, fileName: 'FakeAuditName' });
|
||||
});
|
||||
|
||||
button.click();
|
||||
|
||||
}));
|
||||
|
||||
it('should fetch the pdf Blob as default when the format is UNKNOW', fakeAsync(() => {
|
||||
component.fileName = 'FakeAuditName';
|
||||
component.format = 'fakeFormat';
|
||||
let blob = createFakePdfBlob();
|
||||
spyOn(service, 'fetchProcessAuditPdfById').and.returnValue(Observable.of(blob));
|
||||
spyOn(component, 'onAuditClick').and.callThrough();
|
||||
|
||||
fixture.detectChanges();
|
||||
|
||||
let button = fixture.nativeElement.querySelector('#auditButton');
|
||||
|
||||
fixture.whenStable().then(() => {
|
||||
fixture.detectChanges();
|
||||
expect(component.onAuditClick).toHaveBeenCalledWith({ format: 'pdf', value: blob, fileName: 'FakeAuditName' });
|
||||
});
|
||||
|
||||
button.click();
|
||||
|
||||
}));
|
||||
|
||||
});
|
||||
|
||||
@Component({
|
||||
selector: 'adf-basic-button',
|
||||
template: `
|
||||
<button id="auditButton"
|
||||
adf-process-audit
|
||||
[process-id]="currentProcessId"
|
||||
[download]="download"
|
||||
[fileName]="fileName"
|
||||
[format]="format"
|
||||
(clicked)="onAuditClick($event)">My button
|
||||
</button>`
|
||||
})
|
||||
class BasicButtonComponent {
|
||||
|
||||
download: boolean = false;
|
||||
fileName: string;
|
||||
format: string;
|
||||
constructor() {
|
||||
|
||||
}
|
||||
|
||||
onAuditClick(event: any) {
|
||||
}
|
||||
}
|
@@ -0,0 +1,120 @@
|
||||
/*!
|
||||
* @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 { ContentService } from '@alfresco/core';
|
||||
import { Directive, EventEmitter, Input, OnChanges, Output, SimpleChanges } from '@angular/core';
|
||||
import { ProcessService } from './../services/process.service';
|
||||
|
||||
const JSON_FORMAT: string = 'json';
|
||||
const PDF_FORMAT: string = 'pdf';
|
||||
|
||||
@Directive({
|
||||
selector: 'button[adf-process-audit]',
|
||||
host: {
|
||||
'role': 'button',
|
||||
'(click)': 'onClickAudit()'
|
||||
}
|
||||
})
|
||||
export class ProcessAuditDirective implements OnChanges {
|
||||
|
||||
@Input('process-id')
|
||||
processId: string;
|
||||
|
||||
@Input()
|
||||
fileName: string = 'Audit';
|
||||
|
||||
@Input()
|
||||
format: string = 'pdf';
|
||||
|
||||
@Input()
|
||||
download: boolean = true;
|
||||
|
||||
@Output()
|
||||
clicked: EventEmitter<any> = new EventEmitter<any>();
|
||||
|
||||
@Output()
|
||||
error: EventEmitter<any> = new EventEmitter<any>();
|
||||
|
||||
public audit: any;
|
||||
|
||||
/**
|
||||
*
|
||||
* @param translateService
|
||||
* @param processListService
|
||||
*/
|
||||
constructor(private contentService: ContentService,
|
||||
private processListService: ProcessService) {
|
||||
}
|
||||
|
||||
ngOnChanges(changes: SimpleChanges): void {
|
||||
if (!this.isValidType()) {
|
||||
this.setDefaultFormatType();
|
||||
}
|
||||
}
|
||||
|
||||
isValidType() {
|
||||
if (this.format && (this.isJsonFormat() || this.isPdfFormat())) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
setDefaultFormatType(): void {
|
||||
this.format = PDF_FORMAT;
|
||||
}
|
||||
|
||||
/**
|
||||
* fetch the audit information in the requested format
|
||||
*/
|
||||
fetchAuditInfo(): void {
|
||||
if (this.isPdfFormat()) {
|
||||
this.processListService.fetchProcessAuditPdfById(this.processId).subscribe(
|
||||
(blob: Blob) => {
|
||||
this.audit = blob;
|
||||
if (this.download) {
|
||||
this.contentService.downloadBlob(this.audit, this.fileName + '.pdf');
|
||||
}
|
||||
this.clicked.emit({ format: this.format, value: this.audit, fileName: this.fileName });
|
||||
},
|
||||
(err) => {
|
||||
this.error.emit(err);
|
||||
});
|
||||
} else {
|
||||
this.processListService.fetchProcessAuditJsonById(this.processId).subscribe(
|
||||
(res) => {
|
||||
this.audit = res;
|
||||
this.clicked.emit({ format: this.format, value: this.audit, fileName: this.fileName });
|
||||
},
|
||||
(err) => {
|
||||
this.error.emit(err);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
onClickAudit() {
|
||||
this.fetchAuditInfo();
|
||||
}
|
||||
|
||||
isJsonFormat() {
|
||||
return this.format === JSON_FORMAT;
|
||||
}
|
||||
|
||||
isPdfFormat() {
|
||||
return this.format === PDF_FORMAT;
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,9 @@
|
||||
<div class="menu-container">
|
||||
<mat-list>
|
||||
<mat-list-item (click)="selectFilter(filter)" *ngFor="let filter of filters"
|
||||
class="adf-filters__entry" [class.active]="currentFilter === filter">
|
||||
<mat-icon *ngIf="hasIcon" matListIcon class="adf-filters__entry-icon">assignment</mat-icon>
|
||||
<span matLine [attr.data-automation-id]="filter.name + '_filter'">{{filter.name}}</span>
|
||||
</mat-list-item>
|
||||
</mat-list>
|
||||
</div>
|
@@ -0,0 +1,29 @@
|
||||
@mixin adf-process-filters-theme($theme) {
|
||||
$primary: map-get($theme, primary);
|
||||
|
||||
.adf {
|
||||
|
||||
&-filters__entry {
|
||||
cursor: pointer;
|
||||
font-size: 14px!important;
|
||||
font-weight: bold;
|
||||
opacity: .54;
|
||||
padding-left: 30px;
|
||||
|
||||
.mat-list-item-content {
|
||||
height: 34px;
|
||||
}
|
||||
&.active, &:hover {
|
||||
color: mat-color($primary);
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
|
||||
&-filters__entry-icon {
|
||||
padding-right: 12px !important;
|
||||
padding-left: 0px !important;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,210 @@
|
||||
/*!
|
||||
* @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 { SimpleChange } from '@angular/core';
|
||||
import { AppsProcessService } from '@alfresco/core';
|
||||
import { Observable } from 'rxjs/Rx';
|
||||
import { FilterProcessRepresentationModel } from '../models/filter-process.model';
|
||||
import { ProcessFilterService } from '../services/process-filter.service';
|
||||
import { ProcessFiltersComponent } from './process-filters.component';
|
||||
|
||||
describe('ActivitiFilters', () => {
|
||||
|
||||
let filterList: ProcessFiltersComponent;
|
||||
let processFilterService: ProcessFilterService;
|
||||
let appsProcessService: AppsProcessService;
|
||||
|
||||
let fakeGlobalFilter = [];
|
||||
fakeGlobalFilter.push(new FilterProcessRepresentationModel({
|
||||
name: 'FakeInvolvedTasks',
|
||||
filter: { state: 'open', assignment: 'fake-involved' }
|
||||
}));
|
||||
fakeGlobalFilter.push(new FilterProcessRepresentationModel({
|
||||
name: 'FakeMyTasks',
|
||||
filter: { state: 'open', assignment: 'fake-assignee' }
|
||||
}));
|
||||
|
||||
fakeGlobalFilter.push(new FilterProcessRepresentationModel({
|
||||
name: 'Running',
|
||||
filter: { state: 'open', assignment: 'fake-running' }
|
||||
}));
|
||||
|
||||
let fakeGlobalFilterPromise = new Promise(function (resolve, reject) {
|
||||
resolve(fakeGlobalFilter);
|
||||
});
|
||||
|
||||
let fakeErrorFilterList = {
|
||||
error: 'wrong request'
|
||||
};
|
||||
|
||||
let fakeErrorFilterPromise = new Promise(function (resolve, reject) {
|
||||
reject(fakeErrorFilterList);
|
||||
});
|
||||
|
||||
beforeEach(() => {
|
||||
processFilterService = new ProcessFilterService(null, null);
|
||||
appsProcessService = new AppsProcessService(null, null);
|
||||
filterList = new ProcessFiltersComponent(processFilterService, appsProcessService);
|
||||
});
|
||||
|
||||
it('should return the filter task list', (done) => {
|
||||
spyOn(processFilterService, 'getProcessFilters').and.returnValue(Observable.fromPromise(fakeGlobalFilterPromise));
|
||||
const appId = '1';
|
||||
let change = new SimpleChange(null, appId, true);
|
||||
filterList.ngOnChanges({ 'appId': change });
|
||||
|
||||
filterList.success.subscribe((res) => {
|
||||
expect(res).toBeDefined();
|
||||
expect(filterList.filters).toBeDefined();
|
||||
expect(filterList.filters.length).toEqual(3);
|
||||
expect(filterList.filters[0].name).toEqual('FakeInvolvedTasks');
|
||||
expect(filterList.filters[1].name).toEqual('FakeMyTasks');
|
||||
expect(filterList.filters[2].name).toEqual('Running');
|
||||
done();
|
||||
});
|
||||
|
||||
filterList.ngOnInit();
|
||||
});
|
||||
|
||||
it('should select the Running process filter', (done) => {
|
||||
spyOn(processFilterService, 'getProcessFilters').and.returnValue(Observable.fromPromise(fakeGlobalFilterPromise));
|
||||
const appId = '1';
|
||||
let change = new SimpleChange(null, appId, true);
|
||||
filterList.ngOnChanges({ 'appId': change });
|
||||
|
||||
expect(filterList.currentFilter).toBeUndefined();
|
||||
|
||||
filterList.success.subscribe((res) => {
|
||||
filterList.selectRunningFilter();
|
||||
expect(filterList.currentFilter.name).toEqual('Running');
|
||||
done();
|
||||
});
|
||||
|
||||
filterList.ngOnInit();
|
||||
});
|
||||
|
||||
it('should return the filter task list, filtered By Name', (done) => {
|
||||
|
||||
let fakeDeployedApplicationsPromise = new Promise(function (resolve, reject) {
|
||||
resolve({ id: 1 });
|
||||
});
|
||||
|
||||
spyOn(appsProcessService, 'getDeployedApplicationsByName').and.returnValue(Observable.fromPromise(fakeDeployedApplicationsPromise));
|
||||
spyOn(processFilterService, 'getProcessFilters').and.returnValue(Observable.fromPromise(fakeGlobalFilterPromise));
|
||||
|
||||
let change = new SimpleChange(null, 'test', true);
|
||||
filterList.ngOnChanges({ 'appName': change });
|
||||
|
||||
filterList.success.subscribe((res) => {
|
||||
let deployApp: any = appsProcessService.getDeployedApplicationsByName;
|
||||
expect(deployApp.calls.count()).toEqual(1);
|
||||
expect(res).toBeDefined();
|
||||
done();
|
||||
});
|
||||
|
||||
filterList.ngOnInit();
|
||||
});
|
||||
|
||||
it('should emit an error with a bad response', (done) => {
|
||||
spyOn(processFilterService, 'getProcessFilters').and.returnValue(Observable.fromPromise(fakeErrorFilterPromise));
|
||||
|
||||
const appId = '1';
|
||||
let change = new SimpleChange(null, appId, true);
|
||||
filterList.ngOnChanges({ 'appId': change });
|
||||
|
||||
filterList.error.subscribe((err) => {
|
||||
expect(err).toBeDefined();
|
||||
done();
|
||||
});
|
||||
|
||||
filterList.ngOnInit();
|
||||
});
|
||||
|
||||
it('should emit an error with a bad response', (done) => {
|
||||
spyOn(appsProcessService, 'getDeployedApplicationsByName').and.returnValue(Observable.fromPromise(fakeErrorFilterPromise));
|
||||
|
||||
const appId = 'fake-app';
|
||||
let change = new SimpleChange(null, appId, true);
|
||||
filterList.ngOnChanges({ 'appName': change });
|
||||
|
||||
filterList.error.subscribe((err) => {
|
||||
expect(err).toBeDefined();
|
||||
done();
|
||||
});
|
||||
|
||||
filterList.ngOnInit();
|
||||
});
|
||||
|
||||
it('should emit an event when a filter is selected', (done) => {
|
||||
let currentFilter = new FilterProcessRepresentationModel({
|
||||
filter: {
|
||||
state: 'open',
|
||||
assignment: 'fake-involved'
|
||||
}
|
||||
});
|
||||
|
||||
filterList.filterClick.subscribe((filter: FilterProcessRepresentationModel) => {
|
||||
expect(filter).toBeDefined();
|
||||
expect(filter).toEqual(currentFilter);
|
||||
expect(filterList.currentFilter).toEqual(currentFilter);
|
||||
done();
|
||||
});
|
||||
|
||||
filterList.selectFilter(currentFilter);
|
||||
});
|
||||
|
||||
it('should reload filters by appId on binding changes', () => {
|
||||
spyOn(filterList, 'getFiltersByAppId').and.stub();
|
||||
const appId = '1';
|
||||
|
||||
let change = new SimpleChange(null, appId, true);
|
||||
filterList.ngOnChanges({ 'appId': change });
|
||||
|
||||
expect(filterList.getFiltersByAppId).toHaveBeenCalledWith(appId);
|
||||
});
|
||||
|
||||
it('should reload filters by appId null on binding changes', () => {
|
||||
spyOn(filterList, 'getFiltersByAppId').and.stub();
|
||||
const appId = null;
|
||||
|
||||
let change = new SimpleChange(null, appId, true);
|
||||
filterList.ngOnChanges({ 'appId': change });
|
||||
|
||||
expect(filterList.getFiltersByAppId).toHaveBeenCalledWith(appId);
|
||||
});
|
||||
|
||||
it('should reload filters by app name on binding changes', () => {
|
||||
spyOn(filterList, 'getFiltersByAppName').and.stub();
|
||||
const appName = 'fake-app-name';
|
||||
|
||||
let change = new SimpleChange(null, appName, true);
|
||||
filterList.ngOnChanges({ 'appName': change });
|
||||
|
||||
expect(filterList.getFiltersByAppName).toHaveBeenCalledWith(appName);
|
||||
});
|
||||
|
||||
it('should return the current filter after one is selected', () => {
|
||||
let filter = new FilterProcessRepresentationModel({
|
||||
name: 'FakeMyTasks',
|
||||
filter: { state: 'open', assignment: 'fake-assignee' }
|
||||
});
|
||||
expect(filterList.currentFilter).toBeUndefined();
|
||||
filterList.selectFilter(filter);
|
||||
expect(filterList.getCurrentFilter()).toBe(filter);
|
||||
});
|
||||
|
||||
});
|
@@ -0,0 +1,204 @@
|
||||
/*!
|
||||
* @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 { AppsProcessService } from '@alfresco/core';
|
||||
import { Component, EventEmitter, Input, OnChanges, OnInit, Output, SimpleChanges } from '@angular/core';
|
||||
import { ProcessInstanceFilterRepresentation } from 'alfresco-js-api';
|
||||
import { Observable, Observer } from 'rxjs/Rx';
|
||||
import { FilterProcessRepresentationModel } from '../models/filter-process.model';
|
||||
import { ProcessFilterService } from './../services/process-filter.service';
|
||||
|
||||
@Component({
|
||||
selector: 'adf-process-instance-filters',
|
||||
templateUrl: './process-filters.component.html',
|
||||
styleUrls: ['process-filters.component.scss']
|
||||
})
|
||||
export class ProcessFiltersComponent implements OnInit, OnChanges {
|
||||
|
||||
@Input()
|
||||
filterParam: FilterProcessRepresentationModel;
|
||||
|
||||
@Output()
|
||||
filterClick: EventEmitter<ProcessInstanceFilterRepresentation> = new EventEmitter<ProcessInstanceFilterRepresentation>();
|
||||
|
||||
@Output()
|
||||
success: EventEmitter<ProcessInstanceFilterRepresentation[]> = new EventEmitter<ProcessInstanceFilterRepresentation[]>();
|
||||
|
||||
@Output()
|
||||
error: EventEmitter<any> = new EventEmitter<any>();
|
||||
|
||||
@Input()
|
||||
appId: number;
|
||||
|
||||
@Input()
|
||||
appName: string;
|
||||
|
||||
@Input()
|
||||
showIcon: boolean = true;
|
||||
|
||||
private filterObserver: Observer<ProcessInstanceFilterRepresentation>;
|
||||
filter$: Observable<ProcessInstanceFilterRepresentation>;
|
||||
|
||||
currentFilter: ProcessInstanceFilterRepresentation;
|
||||
|
||||
filters: ProcessInstanceFilterRepresentation [] = [];
|
||||
|
||||
constructor(private processFilterService: ProcessFilterService, private appsProcessService: AppsProcessService) {
|
||||
this.filter$ = new Observable<ProcessInstanceFilterRepresentation>(observer => this.filterObserver = observer).share();
|
||||
}
|
||||
|
||||
ngOnInit() {
|
||||
this.filter$.subscribe((filter: ProcessInstanceFilterRepresentation) => {
|
||||
this.filters.push(filter);
|
||||
});
|
||||
}
|
||||
|
||||
ngOnChanges(changes: SimpleChanges) {
|
||||
let appId = changes['appId'];
|
||||
if (appId && (appId.currentValue || appId.currentValue === null)) {
|
||||
this.getFiltersByAppId(appId.currentValue);
|
||||
return;
|
||||
}
|
||||
let appName = changes['appName'];
|
||||
if (appName && appName.currentValue) {
|
||||
this.getFiltersByAppName(appName.currentValue);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the filter list filtered by appId
|
||||
* @param appId - optional
|
||||
*/
|
||||
getFiltersByAppId(appId?: number) {
|
||||
this.processFilterService.getProcessFilters(appId).subscribe(
|
||||
(res: ProcessInstanceFilterRepresentation[]) => {
|
||||
if (res.length === 0 && this.isFilterListEmpty()) {
|
||||
this.processFilterService.createDefaultFilters(appId).subscribe(
|
||||
(resDefault: ProcessInstanceFilterRepresentation[]) => {
|
||||
this.resetFilter();
|
||||
resDefault.forEach((filter) => {
|
||||
this.filterObserver.next(filter);
|
||||
});
|
||||
|
||||
this.selectProcessFilter(this.filterParam);
|
||||
this.success.emit(resDefault);
|
||||
},
|
||||
(errDefault: any) => {
|
||||
this.error.emit(errDefault);
|
||||
}
|
||||
);
|
||||
} else {
|
||||
this.resetFilter();
|
||||
res.forEach((filter) => {
|
||||
this.filterObserver.next(filter);
|
||||
});
|
||||
|
||||
this.selectProcessFilter(this.filterParam);
|
||||
this.success.emit(res);
|
||||
}
|
||||
},
|
||||
(err: any) => {
|
||||
this.error.emit(err);
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the filter list filtered by appName
|
||||
* @param appName
|
||||
*/
|
||||
getFiltersByAppName(appName: string) {
|
||||
this.appsProcessService.getDeployedApplicationsByName(appName).subscribe(
|
||||
application => {
|
||||
this.getFiltersByAppId(application.id);
|
||||
this.selectProcessFilter(this.filterParam);
|
||||
},
|
||||
(err) => {
|
||||
this.error.emit(err);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Pass the selected filter as next
|
||||
* @param filter
|
||||
*/
|
||||
public selectFilter(filter: ProcessInstanceFilterRepresentation) {
|
||||
this.currentFilter = filter;
|
||||
this.filterClick.emit(filter);
|
||||
}
|
||||
|
||||
/**
|
||||
* Select the first filter of a list if present
|
||||
*/
|
||||
public selectProcessFilter(filterParam: FilterProcessRepresentationModel) {
|
||||
if (filterParam) {
|
||||
this.filters.filter((processFilter: ProcessInstanceFilterRepresentation, index) => {
|
||||
if (filterParam.name && filterParam.name.toLowerCase() === processFilter.name.toLowerCase() || filterParam.index === index) {
|
||||
this.currentFilter = processFilter;
|
||||
}
|
||||
});
|
||||
}
|
||||
if (this.isCurrentFilterEmpty()) {
|
||||
this.selectDefaultTaskFilter();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Select the Running filter
|
||||
*/
|
||||
public selectRunningFilter() {
|
||||
this.selectProcessFilter(this.processFilterService.getRunningFilterInstance(null));
|
||||
}
|
||||
|
||||
/**
|
||||
* Select as default task filter the first in the list
|
||||
*/
|
||||
public selectDefaultTaskFilter() {
|
||||
if (!this.isFilterListEmpty()) {
|
||||
this.currentFilter = this.filters[0];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the current task
|
||||
* @returns {ProcessInstanceFilterRepresentation}
|
||||
*/
|
||||
getCurrentFilter(): ProcessInstanceFilterRepresentation {
|
||||
return this.currentFilter;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the filter list is empty
|
||||
* @returns {boolean}
|
||||
*/
|
||||
isFilterListEmpty(): boolean {
|
||||
return this.filters === undefined || (this.filters && this.filters.length === 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Reset the filters properties
|
||||
*/
|
||||
private resetFilter() {
|
||||
this.filters = [];
|
||||
this.currentFilter = undefined;
|
||||
}
|
||||
|
||||
private isCurrentFilterEmpty(): boolean {
|
||||
return this.currentFilter === undefined || null ? true : false;
|
||||
}
|
||||
}
|
@@ -0,0 +1,21 @@
|
||||
:host {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.activiti-process-container {
|
||||
width: 100%;
|
||||
min-height: 100px;
|
||||
overflow: visible;
|
||||
padding: 10px;
|
||||
}
|
||||
|
||||
.adf-comments-dialog {
|
||||
position: fixed;
|
||||
top: 50%;
|
||||
transform: translate(0, -50%);
|
||||
width: 40%;
|
||||
}
|
||||
|
||||
.adf-in-medias-res-button {
|
||||
margin: 16px 0;
|
||||
}
|
@@ -0,0 +1,37 @@
|
||||
<div *ngIf="!processInstanceDetails">{{ 'ADF_PROCESS_LIST.DETAILS.MESSAGES.NONE'|translate }}</div>
|
||||
<mat-card *ngIf="processInstanceDetails">
|
||||
<mat-card-header>
|
||||
<mat-card-title>{{ getProcessNameOrDescription('medium') }}</mat-card-title>
|
||||
</mat-card-header>
|
||||
<mat-card-content>
|
||||
<adf-process-instance-header
|
||||
[processInstance]="processInstanceDetails"
|
||||
(showProcessDiagram)="onShowProcessDiagram($event)">
|
||||
</adf-process-instance-header>
|
||||
|
||||
<button class="adf-in-medias-res-button" mat-button id="show-diagram-button" type="button" mat-button mat-raised-button [disabled]="isDiagramDisabled()" (click)="onShowProcessDiagram(processInstanceId)">{{ 'ADF_PROCESS_LIST.DETAILS.BUTTON.SHOW_DIAGRAM' | translate }}</button>
|
||||
|
||||
<mat-card>
|
||||
<mat-card-content>
|
||||
<adf-process-instance-tasks
|
||||
[processInstanceDetails]="processInstanceDetails"
|
||||
(taskClick)="onTaskClicked($event)">
|
||||
</adf-process-instance-tasks>
|
||||
</mat-card-content>
|
||||
</mat-card>
|
||||
|
||||
<div data-automation-id="header-status" *ngIf="isRunning()" class="adf-in-medias-res-button">
|
||||
<button mat-button type="button" (click)="cancelProcess()">{{ 'ADF_PROCESS_LIST.DETAILS.BUTTON.CANCEL' | translate }}</button>
|
||||
</div>
|
||||
|
||||
<mat-card>
|
||||
<mat-card-content>
|
||||
<adf-process-instance-comments #activiticomments
|
||||
[readOnly]="false"
|
||||
[processInstanceId]="processInstanceDetails.id">
|
||||
</adf-process-instance-comments>
|
||||
</mat-card-content>
|
||||
</mat-card>
|
||||
|
||||
</mat-card-content>
|
||||
</mat-card>
|
@@ -0,0 +1,145 @@
|
||||
/*!
|
||||
* @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 { DebugElement, NO_ERRORS_SCHEMA, SimpleChange } from '@angular/core';
|
||||
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
import { MaterialModule } from '../../material.module';
|
||||
import { By } from '@angular/platform-browser';
|
||||
import { Observable } from 'rxjs/Rx';
|
||||
|
||||
import { FormModule, FormService } from '@alfresco/core';
|
||||
import { TaskListModule } from '../../task-list';
|
||||
|
||||
import { ProcessInstance } from '../models/process-instance.model';
|
||||
import { exampleProcess, exampleProcessNoName } from './../../mock';
|
||||
import { ProcessService } from './../services/process.service';
|
||||
import { ProcessInstanceDetailsComponent } from './process-instance-details.component';
|
||||
|
||||
describe('ProcessInstanceDetailsComponent', () => {
|
||||
|
||||
let service: ProcessService;
|
||||
let formService: FormService;
|
||||
let component: ProcessInstanceDetailsComponent;
|
||||
let fixture: ComponentFixture<ProcessInstanceDetailsComponent>;
|
||||
let getProcessSpy: jasmine.Spy;
|
||||
|
||||
beforeEach(async(() => {
|
||||
TestBed.configureTestingModule({
|
||||
imports: [
|
||||
MaterialModule,
|
||||
FormModule,
|
||||
TaskListModule
|
||||
],
|
||||
declarations: [
|
||||
ProcessInstanceDetailsComponent
|
||||
],
|
||||
providers: [
|
||||
ProcessService
|
||||
],
|
||||
schemas: [ NO_ERRORS_SCHEMA ]
|
||||
}).compileComponents();
|
||||
}));
|
||||
|
||||
beforeEach(() => {
|
||||
|
||||
fixture = TestBed.createComponent(ProcessInstanceDetailsComponent);
|
||||
component = fixture.componentInstance;
|
||||
service = fixture.debugElement.injector.get(ProcessService);
|
||||
formService = fixture.debugElement.injector.get(FormService);
|
||||
|
||||
getProcessSpy = spyOn(service, 'getProcess').and.returnValue(Observable.of(exampleProcess));
|
||||
});
|
||||
|
||||
it('should not load task details when no processInstanceId is specified', () => {
|
||||
fixture.detectChanges();
|
||||
expect(getProcessSpy).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should set a placeholder message when processInstanceId not initialised', () => {
|
||||
fixture.detectChanges();
|
||||
expect(fixture.nativeElement.innerText).toBe('ADF_PROCESS_LIST.DETAILS.MESSAGES.NONE');
|
||||
});
|
||||
|
||||
it('should display a header when the processInstanceId is provided', async(() => {
|
||||
fixture.detectChanges();
|
||||
component.ngOnChanges({ 'processInstanceId': new SimpleChange(null, '123', true) });
|
||||
fixture.whenStable().then(() => {
|
||||
fixture.detectChanges();
|
||||
let headerEl: DebugElement = fixture.debugElement.query(By.css('.mat-card-title '));
|
||||
expect(headerEl).not.toBeNull();
|
||||
expect(headerEl.nativeElement.innerText).toBe('Process 123');
|
||||
});
|
||||
}));
|
||||
|
||||
it('should display default details when the process instance has no name', async(() => {
|
||||
getProcessSpy = getProcessSpy.and.returnValue(Observable.of(exampleProcessNoName));
|
||||
fixture.detectChanges();
|
||||
component.ngOnChanges({ 'processInstanceId': new SimpleChange(null, '123', true) });
|
||||
fixture.whenStable().then(() => {
|
||||
fixture.detectChanges();
|
||||
let headerEl: DebugElement = fixture.debugElement.query(By.css('.mat-card-title '));
|
||||
expect(headerEl).not.toBeNull();
|
||||
expect(headerEl.nativeElement.innerText).toBe('My Process - Nov 10, 2016, 3:37:30 AM');
|
||||
});
|
||||
}));
|
||||
|
||||
describe('change detection', () => {
|
||||
|
||||
let change = new SimpleChange('123', '456', true);
|
||||
let nullChange = new SimpleChange('123', null, true);
|
||||
|
||||
beforeEach(async(() => {
|
||||
component.processInstanceId = '123';
|
||||
fixture.detectChanges();
|
||||
component.tasksList = jasmine.createSpyObj('tasksList', ['load']);
|
||||
fixture.whenStable().then(() => {
|
||||
getProcessSpy.calls.reset();
|
||||
});
|
||||
}));
|
||||
|
||||
it('should fetch new process details when processInstanceId changed', () => {
|
||||
component.ngOnChanges({ 'processInstanceId': change });
|
||||
expect(getProcessSpy).toHaveBeenCalledWith('456');
|
||||
});
|
||||
|
||||
it('should NOT fetch new process details when empty changeset made', () => {
|
||||
component.ngOnChanges({});
|
||||
expect(getProcessSpy).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should NOT fetch new process details when processInstanceId changed to null', () => {
|
||||
component.ngOnChanges({ 'processInstanceId': nullChange });
|
||||
expect(getProcessSpy).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should set a placeholder message when processInstanceId changed to null', () => {
|
||||
component.ngOnChanges({ 'processInstanceId': nullChange });
|
||||
fixture.detectChanges();
|
||||
expect(fixture.nativeElement.innerText).toBe('ADF_PROCESS_LIST.DETAILS.MESSAGES.NONE');
|
||||
});
|
||||
|
||||
it('should display cancel button if process is running', () => {
|
||||
component.processInstanceDetails = new ProcessInstance({
|
||||
ended : null
|
||||
});
|
||||
fixture.detectChanges();
|
||||
let buttonEl = fixture.debugElement.query(By.css('[data-automation-id="header-status"] button'));
|
||||
expect(buttonEl).not.toBeNull();
|
||||
});
|
||||
});
|
||||
|
||||
});
|
@@ -0,0 +1,146 @@
|
||||
/*!
|
||||
* @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 { LogService } from '@alfresco/core';
|
||||
import { DatePipe } from '@angular/common';
|
||||
import { Component, EventEmitter, Input, OnChanges, Output, SimpleChanges, ViewChild } from '@angular/core';
|
||||
import { TaskDetailsEvent } from '../../task-list';
|
||||
|
||||
import { ProcessInstance } from '../models/process-instance.model';
|
||||
import { ProcessService } from './../services/process.service';
|
||||
import { ProcessInstanceHeaderComponent } from './process-instance-header.component';
|
||||
import { ProcessInstanceTasksComponent } from './process-instance-tasks.component';
|
||||
|
||||
@Component({
|
||||
selector: 'adf-process-instance-details',
|
||||
templateUrl: './process-instance-details.component.html',
|
||||
styleUrls: ['./process-instance-details.component.css']
|
||||
})
|
||||
export class ProcessInstanceDetailsComponent implements OnChanges {
|
||||
|
||||
@Input()
|
||||
processInstanceId: string;
|
||||
|
||||
@ViewChild(ProcessInstanceHeaderComponent)
|
||||
processInstanceHeader: ProcessInstanceHeaderComponent;
|
||||
|
||||
@ViewChild(ProcessInstanceTasksComponent)
|
||||
tasksList: ProcessInstanceTasksComponent;
|
||||
|
||||
@Input()
|
||||
showTitle: boolean = true;
|
||||
|
||||
@Input()
|
||||
showRefreshButton: boolean = true;
|
||||
|
||||
@Output()
|
||||
processCancelled: EventEmitter<any> = new EventEmitter<any>();
|
||||
|
||||
@Output()
|
||||
error: EventEmitter<any> = new EventEmitter<any>();
|
||||
|
||||
@Output()
|
||||
taskClick: EventEmitter<TaskDetailsEvent> = new EventEmitter<TaskDetailsEvent>();
|
||||
|
||||
processInstanceDetails: ProcessInstance;
|
||||
|
||||
@Output()
|
||||
showProcessDiagram: EventEmitter<any> = new EventEmitter<any>();
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
* @param translate Translation service
|
||||
* @param activitiProcess Process service
|
||||
*/
|
||||
constructor(private activitiProcess: ProcessService,
|
||||
private logService: LogService) {
|
||||
}
|
||||
|
||||
ngOnChanges(changes: SimpleChanges) {
|
||||
let processInstanceId = changes['processInstanceId'];
|
||||
if (processInstanceId && !processInstanceId.currentValue) {
|
||||
this.reset();
|
||||
return;
|
||||
}
|
||||
if (processInstanceId && processInstanceId.currentValue) {
|
||||
this.load(processInstanceId.currentValue);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Reset the task detail to undefined
|
||||
*/
|
||||
reset() {
|
||||
this.processInstanceDetails = null;
|
||||
}
|
||||
|
||||
load(processId: string) {
|
||||
if (processId) {
|
||||
this.activitiProcess.getProcess(processId).subscribe(
|
||||
(res: ProcessInstance) => {
|
||||
this.processInstanceDetails = res;
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
isRunning(): boolean {
|
||||
return this.processInstanceDetails && !this.processInstanceDetails.ended;
|
||||
}
|
||||
|
||||
isDiagramDisabled(): boolean {
|
||||
return !this.isRunning() ? true : undefined;
|
||||
}
|
||||
|
||||
cancelProcess() {
|
||||
this.activitiProcess.cancelProcess(this.processInstanceId).subscribe(
|
||||
(data) => {
|
||||
this.processCancelled.emit(data);
|
||||
}, (err) => {
|
||||
this.error.emit(err);
|
||||
});
|
||||
}
|
||||
|
||||
// bubbles (taskClick) event
|
||||
onTaskClicked(event: TaskDetailsEvent) {
|
||||
this.taskClick.emit(event);
|
||||
}
|
||||
|
||||
getProcessNameOrDescription(dateFormat): string {
|
||||
let name = '';
|
||||
if (this.processInstanceDetails) {
|
||||
name = this.processInstanceDetails.name ||
|
||||
this.processInstanceDetails.processDefinitionName + ' - ' + this.getFormatDate(this.processInstanceDetails.started, dateFormat);
|
||||
}
|
||||
return name;
|
||||
}
|
||||
|
||||
getFormatDate(value, format: string) {
|
||||
let datePipe = new DatePipe('en-US');
|
||||
try {
|
||||
return datePipe.transform(value, format);
|
||||
} catch (err) {
|
||||
this.logService.error(`ProcessListInstanceHeader: error parsing date ${value} to format ${format}`);
|
||||
}
|
||||
}
|
||||
|
||||
onShowProcessDiagram(processInstanceId: any) {
|
||||
this.showProcessDiagram.emit({value: this.processInstanceId});
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,7 @@
|
||||
:host {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.adf-card-container {
|
||||
font-family: inherit;
|
||||
}
|
@@ -0,0 +1,5 @@
|
||||
<mat-card *ngIf="processInstance" class="adf-card-container">
|
||||
<mat-card-content>
|
||||
<adf-card-view [properties]="properties"></adf-card-view>
|
||||
</mat-card-content>
|
||||
</mat-card>
|
@@ -0,0 +1,166 @@
|
||||
/*!
|
||||
* @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 { CardViewUpdateService } from '@alfresco/core';
|
||||
import { MaterialModule } from '../../material.module';
|
||||
|
||||
import { ProcessInstance } from '../models/process-instance.model';
|
||||
import { exampleProcess } from '../../mock';
|
||||
import { ProcessService } from './../services/process.service';
|
||||
import { ProcessInstanceHeaderComponent } from './process-instance-header.component';
|
||||
|
||||
describe('ProcessInstanceHeaderComponent', () => {
|
||||
|
||||
let service: ProcessService;
|
||||
let component: ProcessInstanceHeaderComponent;
|
||||
let fixture: ComponentFixture<ProcessInstanceHeaderComponent>;
|
||||
|
||||
beforeEach(async(() => {
|
||||
TestBed.configureTestingModule({
|
||||
imports: [
|
||||
MaterialModule
|
||||
],
|
||||
declarations: [
|
||||
ProcessInstanceHeaderComponent
|
||||
],
|
||||
providers: [
|
||||
ProcessService,
|
||||
CardViewUpdateService
|
||||
]
|
||||
}).compileComponents();
|
||||
}));
|
||||
|
||||
beforeEach(() => {
|
||||
|
||||
fixture = TestBed.createComponent(ProcessInstanceHeaderComponent);
|
||||
component = fixture.componentInstance;
|
||||
service = TestBed.get(ProcessService);
|
||||
|
||||
component.processInstance = new ProcessInstance(exampleProcess);
|
||||
});
|
||||
|
||||
it('should render empty component if no process details provided', () => {
|
||||
component.processInstance = undefined;
|
||||
fixture.detectChanges();
|
||||
expect(fixture.debugElement.children.length).toBe(0);
|
||||
});
|
||||
|
||||
it('should display status as running when process is not complete', () => {
|
||||
component.processInstance.ended = null;
|
||||
component.ngOnChanges({});
|
||||
fixture.detectChanges();
|
||||
let valueEl = fixture.nativeElement.querySelector('[data-automation-id="card-textitem-value-status"]');
|
||||
expect(valueEl.innerText).toBe('Running');
|
||||
});
|
||||
|
||||
it('should display status as completed when process is complete', () => {
|
||||
component.processInstance.ended = new Date('2016-11-03');
|
||||
component.ngOnChanges({});
|
||||
fixture.detectChanges();
|
||||
let valueEl = fixture.nativeElement.querySelector('[data-automation-id="card-textitem-value-status"]');
|
||||
expect(valueEl.innerText).toBe('Completed');
|
||||
});
|
||||
|
||||
it('should display due date', () => {
|
||||
component.processInstance.ended = new Date('2016-11-03');
|
||||
component.ngOnChanges({});
|
||||
fixture.detectChanges();
|
||||
let valueEl = fixture.nativeElement.querySelector('[data-automation-id="card-dateitem-dueDate"]');
|
||||
expect(valueEl.innerText).toBe('Nov 03 2016');
|
||||
});
|
||||
|
||||
it('should display placeholder if no due date', () => {
|
||||
component.processInstance.ended = null;
|
||||
component.ngOnChanges({});
|
||||
fixture.detectChanges();
|
||||
let valueEl = fixture.nativeElement.querySelector('[data-automation-id="card-dateitem-dueDate"]');
|
||||
expect(valueEl.innerText).toBe('ADF_PROCESS_LIST.PROPERTIES.DUE_DATE_DEFAULT');
|
||||
});
|
||||
|
||||
it('should display process category', () => {
|
||||
component.processInstance.processDefinitionCategory = 'Accounts';
|
||||
component.ngOnChanges({});
|
||||
fixture.detectChanges();
|
||||
let valueEl = fixture.nativeElement.querySelector('[data-automation-id="card-textitem-value-category"]');
|
||||
expect(valueEl.innerText).toBe('Accounts');
|
||||
});
|
||||
|
||||
it('should display placeholder if no process category', () => {
|
||||
component.processInstance.processDefinitionCategory = null;
|
||||
component.ngOnChanges({});
|
||||
fixture.detectChanges();
|
||||
let valueEl = fixture.nativeElement.querySelector('[data-automation-id="card-textitem-value-category"]');
|
||||
expect(valueEl.innerText).toBe('ADF_PROCESS_LIST.PROPERTIES.CATEGORY_DEFAULT');
|
||||
});
|
||||
|
||||
it('should display created date', () => {
|
||||
component.processInstance.started = new Date('2016-11-03');
|
||||
component.ngOnChanges({});
|
||||
fixture.detectChanges();
|
||||
let valueEl = fixture.nativeElement.querySelector('[data-automation-id="card-dateitem-created"]');
|
||||
expect(valueEl.innerText).toBe('Nov 03 2016');
|
||||
});
|
||||
|
||||
it('should display started by', () => {
|
||||
component.processInstance.startedBy = {firstName: 'Admin', lastName: 'User'};
|
||||
component.ngOnChanges({});
|
||||
fixture.detectChanges();
|
||||
let valueEl = fixture.nativeElement.querySelector('[data-automation-id="card-textitem-value-assignee"]');
|
||||
expect(valueEl.innerText).toBe('Admin User');
|
||||
});
|
||||
|
||||
it('should display process instance id', () => {
|
||||
component.processInstance.id = '123';
|
||||
component.ngOnChanges({});
|
||||
fixture.detectChanges();
|
||||
let valueEl = fixture.nativeElement.querySelector('[data-automation-id="card-textitem-value-id"]');
|
||||
expect(valueEl.innerText).toBe('123');
|
||||
});
|
||||
|
||||
it('should display description', () => {
|
||||
component.processInstance.processDefinitionDescription = 'Test process';
|
||||
component.ngOnChanges({});
|
||||
fixture.detectChanges();
|
||||
let valueEl = fixture.nativeElement.querySelector('[data-automation-id="card-textitem-value-description"]');
|
||||
expect(valueEl.innerText).toBe('Test process');
|
||||
});
|
||||
|
||||
it('should display placeholder if no description', () => {
|
||||
component.processInstance.processDefinitionDescription = null;
|
||||
component.ngOnChanges({});
|
||||
fixture.detectChanges();
|
||||
let valueEl = fixture.nativeElement.querySelector('[data-automation-id="card-textitem-value-description"]');
|
||||
expect(valueEl.innerText).toBe('ADF_PROCESS_LIST.PROPERTIES.DESCRIPTION_DEFAULT');
|
||||
});
|
||||
|
||||
it('should display businessKey value', () => {
|
||||
component.processInstance.businessKey = 'fakeBusinessKey';
|
||||
component.ngOnChanges({});
|
||||
fixture.detectChanges();
|
||||
let valueEl = fixture.nativeElement.querySelector('[data-automation-id="card-textitem-value-businessKey"]');
|
||||
expect(valueEl.innerText).toBe('fakeBusinessKey');
|
||||
});
|
||||
|
||||
it('should display default key if no businessKey', () => {
|
||||
component.processInstance.businessKey = null;
|
||||
component.ngOnChanges({});
|
||||
fixture.detectChanges();
|
||||
let valueEl = fixture.nativeElement.querySelector('[data-automation-id="card-textitem-value-businessKey"]');
|
||||
expect(valueEl.innerText).toBe('ADF_PROCESS_LIST.PROPERTIES.BUSINESS_KEY_DEFAULT');
|
||||
});
|
||||
});
|
@@ -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 { CardViewDateItemModel, CardViewItem, CardViewTextItemModel } from '@alfresco/core';
|
||||
import { Component, Input, OnChanges, SimpleChanges } from '@angular/core';
|
||||
import { ProcessInstance } from '../models/process-instance.model';
|
||||
|
||||
@Component({
|
||||
selector: 'adf-process-instance-header',
|
||||
templateUrl: './process-instance-header.component.html',
|
||||
styleUrls: ['./process-instance-header.component.css']
|
||||
})
|
||||
export class ProcessInstanceHeaderComponent implements OnChanges {
|
||||
|
||||
@Input()
|
||||
processInstance: ProcessInstance;
|
||||
|
||||
properties: CardViewItem [];
|
||||
|
||||
ngOnChanges(changes: SimpleChanges) {
|
||||
this.refreshData();
|
||||
}
|
||||
|
||||
refreshData() {
|
||||
if (this.processInstance) {
|
||||
this.properties = [
|
||||
new CardViewTextItemModel(
|
||||
{
|
||||
label: 'ADF_PROCESS_LIST.PROPERTIES.STATUS',
|
||||
value: this.getProcessStatus(),
|
||||
key: 'status'
|
||||
}),
|
||||
new CardViewDateItemModel(
|
||||
{
|
||||
label: 'ADF_PROCESS_LIST.PROPERTIES.DUE_DATE',
|
||||
value: this.processInstance.ended,
|
||||
format: 'MMM DD YYYY',
|
||||
key: 'dueDate',
|
||||
default: 'ADF_PROCESS_LIST.PROPERTIES.DUE_DATE_DEFAULT'
|
||||
}),
|
||||
new CardViewTextItemModel(
|
||||
{
|
||||
label: 'ADF_PROCESS_LIST.PROPERTIES.CATEGORY',
|
||||
value: this.processInstance.processDefinitionCategory,
|
||||
key: 'category',
|
||||
default: 'ADF_PROCESS_LIST.PROPERTIES.CATEGORY_DEFAULT'
|
||||
}),
|
||||
new CardViewTextItemModel(
|
||||
{
|
||||
label: 'ADF_PROCESS_LIST.PROPERTIES.BUSINESS_KEY',
|
||||
value: this.processInstance.businessKey,
|
||||
key: 'businessKey',
|
||||
default: 'ADF_PROCESS_LIST.PROPERTIES.BUSINESS_KEY_DEFAULT'
|
||||
}),
|
||||
new CardViewTextItemModel(
|
||||
{
|
||||
label: 'ADF_PROCESS_LIST.PROPERTIES.CREATED_BY',
|
||||
value: this.getStartedByFullName(),
|
||||
key: 'assignee',
|
||||
default: 'ADF_PROCESS_LIST.PROPERTIES.CREATED_BY_DEFAULT'
|
||||
}),
|
||||
new CardViewDateItemModel(
|
||||
{
|
||||
label: 'ADF_PROCESS_LIST.PROPERTIES.CREATED',
|
||||
value: this.processInstance.started,
|
||||
format: 'MMM DD YYYY',
|
||||
key: 'created'
|
||||
}),
|
||||
new CardViewTextItemModel(
|
||||
{label: 'ADF_PROCESS_LIST.PROPERTIES.ID',
|
||||
value: this.processInstance.id,
|
||||
key: 'id'
|
||||
}),
|
||||
new CardViewTextItemModel(
|
||||
{label: 'ADF_PROCESS_LIST.PROPERTIES.DESCRIPTION',
|
||||
value: this.processInstance.processDefinitionDescription,
|
||||
key: 'description',
|
||||
default: 'ADF_PROCESS_LIST.PROPERTIES.DESCRIPTION_DEFAULT'
|
||||
})
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
getProcessStatus(): string {
|
||||
if (this.processInstance) {
|
||||
return this.isRunning() ? 'Running' : 'Completed';
|
||||
}
|
||||
}
|
||||
|
||||
getStartedByFullName(): string {
|
||||
let fullName = '';
|
||||
if (this.processInstance && this.processInstance.startedBy) {
|
||||
fullName += this.processInstance.startedBy.firstName || '';
|
||||
fullName += fullName ? ' ' : '';
|
||||
fullName += this.processInstance.startedBy.lastName || '';
|
||||
}
|
||||
return fullName;
|
||||
}
|
||||
|
||||
isRunning(): boolean {
|
||||
return this.processInstance && !this.processInstance.ended;
|
||||
}
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user