mirror of
https://github.com/Alfresco/alfresco-ng2-components.git
synced 2025-05-12 17:04:57 +00:00
[AAE-10773] Make Form core process agonostic (#8032)
* move form list in a component * move things in the right place * move last pice in the right place * move things in the right place * move people and group in the right place * move radio and typehead form service start remove responsibilities * remove model service and editor service from formService * move dropdwon in process-service finish remove service from form service * fix some wrong import * move activiti * fix double quote imports * move dynamic table * fix shell * move unit test * [ci:force] fix lint issues * fix build and some unit test * fix process spec type spy problems [ci:foce] * fix * fix broken tests * fix lint issues * fix cloud dropdown test * cleanup process-service-cloud tests * fix people process * improve e2e test Co-authored-by: Kasia Biernat <kasia.biernat@hyland.com>
This commit is contained in:
parent
eb27d38eba
commit
a535af667b
demo-shell/src/app
components
form
process-service
services
docs
core
components
services
widgets
release-notes
upgrade-guide
user-guide
lib
core/src/lib
form
services
process-services-cloud/src/lib
form
components
form-cloud-custom-outcomes.component.spec.tsform-cloud.component.spec.ts
widgets
attach-file
dropdown
radio-buttons
services
task
services
task-form/components
task-header/components
process-services
karma.conf.js
src/lib
attachment
create-process-attachment.component.tscreate-task-attachment.component.spec.tscreate-task-attachment.component.tsprocess-attachment-list.component.spec.tsprocess-attachment-list.component.tstask-attachment-list.component.spec.tstask-attachment-list.component.ts
form
events
form-list
form.component.spec.tsform.component.tsform.component.visibility.spec.tsform.module.tsprocess-form-rendering.service.spec.tsprocess-form-rendering.service.tspublic-api.tsservices
activiti-alfresco.service.tsecm-model.service.spec.tsecm-model.service.tseditor.service.tsmodel.service.tsprocess-content.service.spec.tsprocess-content.service.tsprocess-definition.service.tstask-form.service.tstask.service.ts
start-form.component.spec.tsstart-form.component.tswidgets
content-widget
attach-file-widget-dialog-component.interface.tsattach-file-widget-dialog.component.htmlattach-file-widget-dialog.component.scssattach-file-widget-dialog.component.spec.tsattach-file-widget-dialog.component.tsattach-file-widget-dialog.service.spec.tsattach-file-widget-dialog.service.tsattach-file-widget.component.htmlattach-file-widget.component.scssattach-file-widget.component.spec.tsattach-file-widget.component.tsattach-folder-widget.component.htmlattach-folder-widget.component.scssattach-folder-widget.component.spec.tsattach-folder-widget.component.tscontent-widget.module.tsindex.tspublic-api.ts
document
content.widget.htmlcontent.widget.scsscontent.widget.spec.tscontent.widget.tsdocument.widget.htmldocument.widget.ts
dropdown
@ -15,26 +15,19 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { Observable, of, Subject } from 'rxjs';
|
||||
import { Observable, of } from 'rxjs';
|
||||
import { Injectable } from '@angular/core';
|
||||
|
||||
import {
|
||||
AlfrescoApiService,
|
||||
EcmModelService,
|
||||
LogService,
|
||||
FormService,
|
||||
FormOutcomeEvent
|
||||
} from '@alfresco/adf-core';
|
||||
TaskFormService
|
||||
} from '@alfresco/adf-process-services';
|
||||
import { AlfrescoApiService, LogService } from '@alfresco/adf-core';
|
||||
|
||||
@Injectable()
|
||||
export class FakeFormService extends FormService {
|
||||
executeOutcome = new Subject<FormOutcomeEvent>();
|
||||
export class FakeTaskFormService extends TaskFormService {
|
||||
|
||||
constructor(
|
||||
ecmModelService: EcmModelService,
|
||||
apiService: AlfrescoApiService,
|
||||
protected logService: LogService
|
||||
) {
|
||||
super(ecmModelService, apiService, logService);
|
||||
constructor(apiService: AlfrescoApiService, logService: LogService) {
|
||||
super(apiService, logService);
|
||||
}
|
||||
|
||||
public getRestFieldValues(
|
@ -17,7 +17,7 @@
|
||||
|
||||
import { Component, ViewChild, OnDestroy, OnInit } from '@angular/core';
|
||||
import { FormModel, FormService, LogService, FormOutcomeEvent } from '@alfresco/adf-core';
|
||||
import { FormComponent } from '@alfresco/adf-process-services';
|
||||
import { FormComponent, EditorService } from '@alfresco/adf-process-services';
|
||||
import { Subject } from 'rxjs';
|
||||
import { takeUntil } from 'rxjs/operators';
|
||||
|
||||
@ -42,7 +42,7 @@ export class FormListComponent implements OnInit, OnDestroy {
|
||||
showValidationIcon = false;
|
||||
private onDestroy$ = new Subject<boolean>();
|
||||
|
||||
constructor(private formService: FormService, private logService: LogService) {
|
||||
constructor(private formService: FormService, private editorService: EditorService, private logService: LogService) {
|
||||
}
|
||||
|
||||
ngOnInit() {
|
||||
@ -63,7 +63,7 @@ export class FormListComponent implements OnInit, OnDestroy {
|
||||
onRowDblClick(event: CustomEvent<any>) {
|
||||
const rowForm = event.detail.value.obj;
|
||||
|
||||
this.formService.getFormDefinitionById(rowForm.id).subscribe((formModel) => {
|
||||
this.editorService.getFormDefinitionById(rowForm.id).subscribe((formModel) => {
|
||||
const form = this.formService.parseForm(formModel.formDefinition);
|
||||
this.form = form;
|
||||
});
|
||||
|
@ -22,8 +22,11 @@ import {
|
||||
FormOutcomeEvent,
|
||||
CoreAutomationService
|
||||
} from '@alfresco/adf-core';
|
||||
import {
|
||||
TaskFormService
|
||||
} from '@alfresco/adf-process-services';
|
||||
import { InMemoryFormService } from '../../services/in-memory-form.service';
|
||||
import { FakeFormService } from './fake-form.service';
|
||||
import { FakeTaskFormService } from './fake-tak-form.service';
|
||||
import { Subject } from 'rxjs';
|
||||
import { takeUntil } from 'rxjs/operators';
|
||||
|
||||
@ -31,7 +34,7 @@ import { takeUntil } from 'rxjs/operators';
|
||||
selector: 'app-form-loading',
|
||||
templateUrl: './form-loading.component.html',
|
||||
styleUrls: ['./form-loading.component.scss'],
|
||||
providers: [{ provide: FormService, useClass: FakeFormService }]
|
||||
providers: [{ provide: FakeTaskFormService, useClass: TaskFormService }]
|
||||
})
|
||||
export class FormLoadingComponent implements OnInit, OnDestroy {
|
||||
form: FormModel;
|
||||
|
@ -35,8 +35,7 @@ import {
|
||||
ScriptFilesApi
|
||||
} from '@alfresco/js-api';
|
||||
import {
|
||||
FORM_FIELD_VALIDATORS, FormRenderingService, FormService,
|
||||
DynamicTableRow, ValidateDynamicTableRowEvent, AppConfigService, PaginationComponent, UserPreferenceValues,
|
||||
FORM_FIELD_VALIDATORS, FormRenderingService, FormService, AppConfigService, PaginationComponent, UserPreferenceValues,
|
||||
AlfrescoApiService, UserPreferencesService, LogService, DataCellEvent, NotificationService
|
||||
} from '@alfresco/adf-core';
|
||||
|
||||
@ -54,10 +53,12 @@ import {
|
||||
TaskFiltersComponent,
|
||||
TaskListComponent,
|
||||
ProcessFormRenderingService,
|
||||
APP_LIST_LAYOUT_LIST
|
||||
APP_LIST_LAYOUT_LIST,
|
||||
ValidateDynamicTableRowEvent,
|
||||
DynamicTableRow
|
||||
} from '@alfresco/adf-process-services';
|
||||
import { Subject } from 'rxjs';
|
||||
import { /*CustomEditorComponent*/ CustomStencil01 } from './custom-editor/custom-editor.component';
|
||||
import { CustomStencil01 } from './custom-editor/custom-editor.component';
|
||||
import { DemoFieldValidator } from './demo-field-validator';
|
||||
import { PreviewService } from '../../services/preview.service';
|
||||
import { Location } from '@angular/common';
|
||||
|
@ -16,7 +16,7 @@
|
||||
*/
|
||||
|
||||
import { Injectable } from '@angular/core';
|
||||
import { AppConfigService, AlfrescoApiService, EcmModelService, LogService,
|
||||
import { AppConfigService, LogService,
|
||||
FormFieldOption, FormService, FormValues, FormModel,
|
||||
FormOutcomeModel, FormOutcomeEvent } from '@alfresco/adf-core';
|
||||
import { Observable, Subject } from 'rxjs';
|
||||
@ -43,10 +43,8 @@ export class InMemoryFormService extends FormService {
|
||||
executeOutcome = new Subject<FormOutcomeEvent>();
|
||||
|
||||
constructor(appConfig: AppConfigService,
|
||||
ecmModelService: EcmModelService,
|
||||
apiService: AlfrescoApiService,
|
||||
protected logService: LogService) {
|
||||
super(ecmModelService, apiService, logService);
|
||||
super();
|
||||
this.data = appConfig.get<ProcessServiceData>('activiti');
|
||||
}
|
||||
|
||||
|
@ -45,16 +45,16 @@ Forms defined in APS have the following default mappings for the form fields:
|
||||
| Number | integer | [`NumberWidgetComponent`](lib/core/src/lib/form/components/widgets/number/number.widget.ts) |
|
||||
| Checkbox | boolean | [`CheckboxWidgetComponent`](lib/core/src/lib/form/components/widgets/checkbox/checkbox.widget.ts) |
|
||||
| Date | date | [`DateWidgetComponent`](lib/core/src/lib/form/components/widgets/date/date.widget.ts) |
|
||||
| Dropdown | dropdown | [`DropdownWidgetComponent`](lib/core/src/lib/form/components/widgets/dropdown/dropdown.widget.ts) |
|
||||
| Typeahead | typeahead | [`TypeaheadWidgetComponent`](lib/core/src/lib/form/components/widgets/typeahead/typeahead.widget.ts) |
|
||||
| Dropdown | dropdown | [`DropdownWidgetComponent`](lib/process-services/src/lib/form/widgets/dropdown/dropdown.widget.ts) |
|
||||
| Typeahead | typeahead | [`TypeaheadWidgetComponent`](lib/process-services/src/lib/form/widgets/typeahead/typeahead.widget.ts) |
|
||||
| Amount | amount | [`AmountWidgetComponent`](lib/core/src/lib/form/components/widgets/amount/amount.widget.ts) |
|
||||
| Radio buttons | radio-buttons | [`RadioButtonsWidgetComponent`](lib/core/src/lib/form/components/widgets/radio-buttons/radio-buttons.widget.ts) |
|
||||
| People | people | [`PeopleWidgetComponent`](lib/core/src/lib/form/components/widgets/people/people.widget.ts) |
|
||||
| Group of people | functional-group | [`FunctionalGroupWidgetComponent`](lib/core/src/lib/form/components/widgets/functional-group/functional-group.widget.ts) |
|
||||
| Dynamic table | dynamic-table | [`DynamicTableWidgetComponent`](lib/core/src/lib/form/components/widgets/dynamic-table/dynamic-table.widget.ts) |
|
||||
| Radio buttons | radio-buttons | [`RadioButtonsWidgetComponent`](lib/process-services/src/lib/form/widgets/radio-buttons/radio-buttons.widget.ts) |
|
||||
| People | people | [`PeopleWidgetComponent`](lib/process-services/src/lib/form/widgets/people/people.widget.ts) |
|
||||
| Group of people | functional-group | [`FunctionalGroupWidgetComponent`](lib/process-services/src/lib/form/widgets/functional-group/functional-group.widget.ts) |
|
||||
| Dynamic table | dynamic-table | [`DynamicTableWidgetComponent`](lib/process-services/src/lib/form/widgets/dynamic-table/dynamic-table.widget.ts) |
|
||||
| Hyperlink | hyperlink | [`HyperlinkWidgetComponent`](lib/core/src/lib/form/components/widgets/hyperlink/hyperlink.widget.ts) |
|
||||
| Header | group | [`ContainerWidgetComponent`](lib/core/src/lib/form/components/widgets/container/container.widget.ts) |
|
||||
| Attach File | upload | AttachWidgetComponent or [`UploadWidgetComponent`](lib/core/src/lib/form/components/widgets/upload/upload.widget.ts) (based on metadata) |
|
||||
| Attach File | upload | AttachWidgetComponent or [`UploadWidgetComponent`](lib/process-services/src/lib/form/widgets/upload/upload.widget.ts) (based on metadata) |
|
||||
| Display value | readonly | [`TextWidgetComponent`](lib/core/src/lib/form/components/widgets/text/text.widget.ts) |
|
||||
| Display text | readonly-text | [`DisplayTextWidgetComponent`](lib/core/src/lib/form/components/widgets/display-text/display-text.widget.ts) |
|
||||
| Display Rich text | display-rich-text | [`DisplayRichTextWidgetComponent`](lib/core/src/lib/form/components/widgets/display-rich-text/display-rich-text.widget.ts) |
|
||||
|
@ -5,7 +5,7 @@ Status: Active
|
||||
Last reviewed: 2018-11-20
|
||||
---
|
||||
|
||||
# [Form List Component](lib/core/src/lib/form/components/form-list.component.ts "Defined in form-list.component.ts")
|
||||
# [Form List Component](lib/process-services/src/lib/form/form-list/form-list.component.ts "Defined in form-list.component.ts")
|
||||
|
||||
Shows forms as a list.
|
||||
|
||||
|
@ -4,7 +4,7 @@ Added: v2.0.0
|
||||
Status: Active
|
||||
---
|
||||
|
||||
# [APS Alfresco Content Service](lib/core/src/lib/form/services/activiti-alfresco.service.ts "Defined in activiti-alfresco.service.ts")
|
||||
# [APS Alfresco Content Service](lib/process-services/src/lib/form/services/activiti-alfresco.service.ts "Defined in activiti-alfresco.service.ts")
|
||||
|
||||
Gets Alfresco Repository folder content based on a Repository account configured in Alfresco Process Services (APS).
|
||||
|
||||
|
@ -1,59 +0,0 @@
|
||||
---
|
||||
Title: Node Service
|
||||
Added: v2.0.0
|
||||
Status: Active
|
||||
Last reviewed: 2018-11-20
|
||||
---
|
||||
|
||||
# [Node Service](lib/core/src/lib/form/services/node.service.ts "Defined in node.service.ts") **Deprecated**
|
||||
|
||||
use [Nodes Api service](./nodes-api.service.md) instead of this.
|
||||
|
||||
Gets Alfresco Repository node metadata and creates nodes with metadata.
|
||||
|
||||
## Class members
|
||||
|
||||
### Methods
|
||||
|
||||
- **createNode**(name: `string`, nodeType: `string`, properties: `any`, path: `string`): [`Observable`](http://reactivex.io/documentation/observable.html)`<`[`NodeEntry`](https://github.com/Alfresco/alfresco-js-api/blob/master/src/alfresco-core-rest-api/docs/NodeEntry.md)`>`<br/>
|
||||
(**Deprecated:** in 3.8.0, use `createNodeInsideRoot` method from NodesApiService instead. Create a new Node from form metadata)
|
||||
- _name:_ `string` - Node name
|
||||
- _nodeType:_ `string` - Node type
|
||||
- _properties:_ `any` - Node body properties
|
||||
- _path:_ `string` - Path to the node
|
||||
- **Returns** [`Observable`](http://reactivex.io/documentation/observable.html)`<`[`NodeEntry`](https://github.com/Alfresco/alfresco-js-api/blob/master/src/alfresco-core-rest-api/docs/NodeEntry.md)`>` - The created node
|
||||
- **createNodeMetadata**(nodeType: `string`, nameSpace: `any`, data: `any`, path: `string`, name?: `string`): [`Observable`](http://reactivex.io/documentation/observable.html)`<`[`NodeEntry`](https://github.com/Alfresco/alfresco-js-api/blob/master/src/alfresco-core-rest-api/docs/NodeEntry.md)`>`<br/>
|
||||
(**Deprecated:** in 3.8.0, use NodesApiService instead. Create a new Node from form metadata.)
|
||||
- _nodeType:_ `string` - Node type
|
||||
- _nameSpace:_ `any` - Namespace for properties
|
||||
- _data:_ `any` - [Property](../../../lib/content-services/src/lib/content-metadata/interfaces/property.interface.ts) data to store in the node under namespace
|
||||
- _path:_ `string` - Path to the node
|
||||
- _name:_ `string` - (Optional) Node name
|
||||
- **Returns** [`Observable`](http://reactivex.io/documentation/observable.html)`<`[`NodeEntry`](https://github.com/Alfresco/alfresco-js-api/blob/master/src/alfresco-core-rest-api/docs/NodeEntry.md)`>` - The created node
|
||||
- **getNodeMetadata**(nodeId: `string`): [`Observable`](http://reactivex.io/documentation/observable.html)`<`[`NodeMetadata`](../../../lib/core/models/node-metadata.model.ts)`>`<br/>
|
||||
(**Deprecated:** in 3.8.0, use NodesApiService instead. Get the metadata and the nodeType for a nodeId cleaned by the prefix.)
|
||||
- _nodeId:_ `string` - ID of the target node
|
||||
- **Returns** [`Observable`](http://reactivex.io/documentation/observable.html)`<`[`NodeMetadata`](../../../lib/core/models/node-metadata.model.ts)`>` - Node metadata
|
||||
|
||||
## Details
|
||||
|
||||
Note that this service cannot be used to create nodes with content.
|
||||
|
||||
The `path` parameter to `createNode` and `createNodeMetadata` specifies an intermediate
|
||||
path of folders to create between the root and the target node.
|
||||
|
||||
### Importing
|
||||
|
||||
```ts
|
||||
import { NodeService } from '@alfresco/adf-core';
|
||||
|
||||
export class SomePageComponent implements OnInit {
|
||||
|
||||
constructor(private nodeService: NodeService) {
|
||||
}
|
||||
```
|
||||
|
||||
## See also
|
||||
|
||||
- [Nodes api service](nodes-api.service.md)
|
||||
- [Deleted nodes api service](deleted-nodes-api.service.md)
|
@ -4,7 +4,7 @@ Added: v2.0.0
|
||||
Status: Active
|
||||
---
|
||||
|
||||
# [Process Content Service](lib/core/src/lib/form/services/process-content.service.ts "Defined in process-content.service.ts")
|
||||
# [Process Content Service](lib/process-services/src/lib/form/services/process-content.service.ts "Defined in process-content.service.ts")
|
||||
|
||||
Manipulates content related to a Process Instance or Task Instance in APS.
|
||||
|
||||
|
@ -4,7 +4,7 @@ Added: v2.0.0
|
||||
Status: Active
|
||||
---
|
||||
|
||||
# [APS Content Component](lib/core/src/lib/form/components/widgets/content/content.widget.ts "Defined in content.widget.ts")
|
||||
# [APS Content Component](lib/process-services/src/lib/form/widgets/document/content.widget.ts "Defined in content.widget.ts")
|
||||
|
||||
Shows the content preview.
|
||||
|
||||
|
@ -759,7 +759,7 @@ Release Notes - Apps Development Framework - Version 2.0.
|
||||
- \[[ADF-1879](https://issues.alfresco.com/jira/browse/ADF-1879)] - ADF Process Services is not working properly
|
||||
- \[[ADF-1885](https://issues.alfresco.com/jira/browse/ADF-1885)] - Once accessed process services components appear throughout app
|
||||
- \[[ADF-1890](https://issues.alfresco.com/jira/browse/ADF-1890)] - Viewer - Content projection for sidebar only works if sidebarPosition is left
|
||||
- \[[ADF-1891](https://issues.alfresco.com/jira/browse/ADF-1891)] - [`ActivitiContentService`](lib/core/src/lib/form/services/activiti-alfresco.service.ts) is not exported
|
||||
- \[[ADF-1891](https://issues.alfresco.com/jira/browse/ADF-1891)] - [`ActivitiContentService`](lib/process-services/src/lib/form/services/activiti-alfresco.service.ts) is not exported
|
||||
- \[[ADF-1898](https://issues.alfresco.com/jira/browse/ADF-1898)] - [`ProcessService`](../process-services/services/process.service.md).createOrUpdateProcessInstanceVariables has incorrect method signature
|
||||
- \[[ADF-1900](https://issues.alfresco.com/jira/browse/ADF-1900)] - [`ProcessService`](../process-services/services/process.service.md).getProcessInstanceVariables has incorrect method signature
|
||||
- \[[ADF-1901](https://issues.alfresco.com/jira/browse/ADF-1901)] - [`ProcessService`](../process-services/services/process.service.md).createDefaultFilters has incorrect method signature
|
||||
|
@ -353,7 +353,7 @@ Release Notes - Apps Development Framework - Version 2.2.
|
||||
- \[[ADF-2242](https://issues.alfresco.com/jira/browse/ADF-2242)] - Search on custom sources is not working.
|
||||
- \[[ADF-2243](https://issues.alfresco.com/jira/browse/ADF-2243)] - Translation is missing for the 'Extended Search'.
|
||||
- \[[ADF-2246](https://issues.alfresco.com/jira/browse/ADF-2246)] - [Destination Picker] The selection from the dropdown is ignored after 'Clear' action
|
||||
- \[[ADF-2251](https://issues.alfresco.com/jira/browse/ADF-2251)] - [`ContentWidgetModule`](../../lib/process-services/src/lib/content-widget/content-widget.module.ts) is not exposed from ADF
|
||||
- \[[ADF-2251](https://issues.alfresco.com/jira/browse/ADF-2251)] - [`ContentWidgetModule`](lib/process-services/src/lib/form/widgets/content-widget/content-widget.module.ts) is not exposed from ADF
|
||||
- \[[ADF-2254](https://issues.alfresco.com/jira/browse/ADF-2254)] - Viewer does not update top menu on "fileNodeId" changes
|
||||
- \[[ADF-2255](https://issues.alfresco.com/jira/browse/ADF-2255)] - SelectBox field does not render the data in ADF form
|
||||
- \[[ADF-2260](https://issues.alfresco.com/jira/browse/ADF-2260)] - Action menu translation is missing when right clicking on a file/folder
|
||||
|
@ -432,7 +432,7 @@ These changes are noted with an arrow "->".
|
||||
- `adf-grid-list`
|
||||
- `adf-grid-list-item`
|
||||
|
||||
#### [../../lib/core/form/components/widgets/dynamic-table/dynamic-table.widget.scss](lib/core/src/lib/form/components/widgets/dynamic-table/dynamic-table.widget.scss)
|
||||
#### [../../lib/core/form/components/widgets/dynamic-table/dynamic-table.widget.scss](lib/process-services/src/lib/form/widgets/dynamic-table/dynamic-table.widget.scss)
|
||||
|
||||
- `adf-is-selected`
|
||||
- `adf-no-select`
|
||||
|
@ -83,21 +83,21 @@ formRenderingService.setComponentTypeResolver('text', customResolver, true);
|
||||
| Number | integer | [`NumberWidgetComponent`](lib/core/src/lib/form/components/widgets/number/number.widget.ts) |
|
||||
| Multi-line text | multi-line-text | [`MultilineTextWidgetComponentComponent`](lib/core/src/lib/form/components/widgets/multiline-text/multiline-text.widget.ts) |
|
||||
| Checkbox | boolean | [`CheckboxWidgetComponent`](lib/core/src/lib/form/components/widgets/checkbox/checkbox.widget.ts) |
|
||||
| Dropdown | dropdown | [`DropdownWidgetComponent`](lib/core/src/lib/form/components/widgets/dropdown/dropdown.widget.ts) |
|
||||
| Dropdown | dropdown | [`DropdownWidgetComponent`](lib/process-services/src/lib/form/widgets/dropdown/dropdown.widget.ts) |
|
||||
| Date | date | [`DateWidgetComponent`](lib/core/src/lib/form/components/widgets/date/date.widget.ts) |
|
||||
| Amount | amount | [`AmountWidgetComponent`](lib/core/src/lib/form/components/widgets/amount/amount.widget.ts) |
|
||||
| Radio buttons | radio-buttons | [`RadioButtonsWidgetComponent`](lib/core/src/lib/form/components/widgets/radio-buttons/radio-buttons.widget.ts) |
|
||||
| Radio buttons | radio-buttons | [`RadioButtonsWidgetComponent`](lib/process-services/src/lib/form/widgets/radio-buttons/radio-buttons.widget.ts) |
|
||||
| Hyperlink | hyperlink | [`HyperlinkWidgetComponent`](lib/core/src/lib/form/components/widgets/hyperlink/hyperlink.widget.ts) |
|
||||
| Display value | readonly | DisplayValueWidgetComponent |
|
||||
| Display Rich text | display-rich-text | [`DisplayRichTextWidgetComponent`](lib/core/src/lib/form/components/widgets/display-rich-text/display-rich-text.widget.ts) |
|
||||
| Display text | readonly-text | [`DisplayTextWidgetComponentComponent`](lib/core/src/lib/form/components/widgets/display-text/display-text.widget.ts) |
|
||||
| Typeahead | typeahead | [`TypeaheadWidgetComponent`](lib/core/src/lib/form/components/widgets/typeahead/typeahead.widget.ts) |
|
||||
| People | people | [`PeopleWidgetComponent`](lib/core/src/lib/form/components/widgets/people/people.widget.ts) |
|
||||
| Group of people | functional-group | [`FunctionalGroupWidgetComponent`](lib/core/src/lib/form/components/widgets/functional-group/functional-group.widget.ts) |
|
||||
| Dynamic table | dynamic-table | [`DynamicTableWidgetComponent`](lib/core/src/lib/form/components/widgets/dynamic-table/dynamic-table.widget.ts) |
|
||||
| Typeahead | typeahead | [`TypeaheadWidgetComponent`](lib/process-services/src/lib/form/widgets/typeahead/typeahead.widget.ts) |
|
||||
| People | people | [`PeopleWidgetComponent`](lib/process-services/src/lib/form/widgets/people/people.widget.ts) |
|
||||
| Group of people | functional-group | [`FunctionalGroupWidgetComponent`](lib/process-services/src/lib/form/widgets/functional-group/functional-group.widget.ts) |
|
||||
| Dynamic table | dynamic-table | [`DynamicTableWidgetComponent`](lib/process-services/src/lib/form/widgets/dynamic-table/dynamic-table.widget.ts) |
|
||||
| N/A | container | [`ContainerWidgetComponent`](lib/core/src/lib/form/components/widgets/container/container.widget.ts) (layout component) |
|
||||
| Header | group | [`ContainerWidgetComponent`](lib/core/src/lib/form/components/widgets/container/container.widget.ts) |
|
||||
| Attach | upload | AttachWidgetComponent or [`UploadWidgetComponent`](lib/core/src/lib/form/components/widgets/upload/upload.widget.ts) (based on metadata) |
|
||||
| Attach | upload | AttachWidgetComponent or [`UploadWidgetComponent`](lib/process-services/src/lib/form/widgets/upload/upload.widget.ts) (based on metadata) |
|
||||
| N/A | N/A | [`UnknownWidgetComponent`](lib/core/src/lib/form/components/widgets/unknown/unknown.widget.ts) |
|
||||
|
||||
## Form Extensibility for APS/AAE
|
||||
|
@ -27,13 +27,10 @@ import { TabModel } from './tab.model';
|
||||
import { fakeMetadataForm, fakeViewerForm } from '../../mock/form.mock';
|
||||
import { Node } from '@alfresco/js-api';
|
||||
import { UploadWidgetContentLinkModel } from './upload-widget-content-link.model';
|
||||
import { AlfrescoApiService } from '../../../../services';
|
||||
import { TestBed } from '@angular/core/testing';
|
||||
import { CoreTestingModule, setupTestBed } from '../../../../testing';
|
||||
|
||||
describe('FormModel', () => {
|
||||
let formService: FormService;
|
||||
let alfrescoApiService: AlfrescoApiService;
|
||||
|
||||
setupTestBed({
|
||||
imports: [
|
||||
@ -42,9 +39,7 @@ describe('FormModel', () => {
|
||||
});
|
||||
|
||||
beforeEach(() => {
|
||||
alfrescoApiService = TestBed.inject(AlfrescoApiService);
|
||||
|
||||
formService = new FormService(null, alfrescoApiService, null);
|
||||
formService = new FormService();
|
||||
});
|
||||
|
||||
it('should store original json', () => {
|
||||
|
@ -21,30 +21,14 @@ import { AmountWidgetComponent } from './amount/amount.widget';
|
||||
import { CheckboxWidgetComponent } from './checkbox/checkbox.widget';
|
||||
import { DateWidgetComponent } from './date/date.widget';
|
||||
import { DisplayTextWidgetComponent } from './display-text/display-text.widget';
|
||||
import { DocumentWidgetComponent } from './document/document.widget';
|
||||
import { DropdownWidgetComponent } from './dropdown/dropdown.widget';
|
||||
import { DynamicTableWidgetComponent } from './dynamic-table/dynamic-table.widget';
|
||||
import { BooleanEditorComponent } from './dynamic-table/editors/boolean/boolean.editor';
|
||||
import { DateEditorComponent } from './dynamic-table/editors/date/date.editor';
|
||||
import { DateTimeEditorComponent } from './dynamic-table/editors/datetime/datetime.editor';
|
||||
import { DropdownEditorComponent } from './dynamic-table/editors/dropdown/dropdown.editor';
|
||||
import { RowEditorComponent } from './dynamic-table/editors/row.editor';
|
||||
import { TextEditorComponent } from './dynamic-table/editors/text/text.editor';
|
||||
import { AmountEditorComponent } from './dynamic-table/editors/amount/amount.editor';
|
||||
import { ErrorWidgetComponent } from './error/error.component';
|
||||
import { FunctionalGroupWidgetComponent } from './functional-group/functional-group.widget';
|
||||
import { HyperlinkWidgetComponent } from './hyperlink/hyperlink.widget';
|
||||
import { MultilineTextWidgetComponentComponent } from './multiline-text/multiline-text.widget';
|
||||
import { NumberWidgetComponent } from './number/number.widget';
|
||||
import { PeopleWidgetComponent } from './people/people.widget';
|
||||
import { RadioButtonsWidgetComponent } from './radio-buttons/radio-buttons.widget';
|
||||
import { InputMaskDirective } from './text/text-mask.component';
|
||||
import { TextWidgetComponent } from './text/text.widget';
|
||||
import { TypeaheadWidgetComponent } from './typeahead/typeahead.widget';
|
||||
import { UploadWidgetComponent } from './upload/upload.widget';
|
||||
import { DateTimeWidgetComponent } from './date-time/date-time.widget';
|
||||
import { JsonWidgetComponent } from './json/json.widget';
|
||||
import { UploadFolderWidgetComponent } from './upload-folder/upload-folder.widget';
|
||||
import { FileViewerWidgetComponent } from './file-viewer/file-viewer.widget';
|
||||
import { DisplayRichTextWidgetComponent } from './display-rich-text/display-rich-text.widget';
|
||||
|
||||
@ -52,41 +36,21 @@ import { DisplayRichTextWidgetComponent } from './display-rich-text/display-rich
|
||||
export * from './widget.component';
|
||||
export * from './core';
|
||||
|
||||
|
||||
// primitives
|
||||
export * from './unknown/unknown.widget';
|
||||
export * from './text/text.widget';
|
||||
export * from './number/number.widget';
|
||||
export * from './checkbox/checkbox.widget';
|
||||
export * from './multiline-text/multiline-text.widget';
|
||||
export * from './dropdown/dropdown.widget';
|
||||
export * from './hyperlink/hyperlink.widget';
|
||||
export * from './radio-buttons/radio-buttons.widget';
|
||||
export * from './display-text/display-text.widget';
|
||||
export * from './upload/upload.widget';
|
||||
export * from './typeahead/typeahead.widget';
|
||||
export * from './functional-group/functional-group.widget';
|
||||
export * from './people/people.widget';
|
||||
export * from './date/date.widget';
|
||||
export * from './amount/amount.widget';
|
||||
export * from './dynamic-table/dynamic-table.widget';
|
||||
export * from './error/error.component';
|
||||
export * from './document/document.widget';
|
||||
export * from './date-time/date-time.widget';
|
||||
export * from './json/json.widget';
|
||||
export * from './upload-folder/upload-folder.widget';
|
||||
export * from './file-viewer/file-viewer.widget';
|
||||
export * from './display-rich-text/display-rich-text.widget';
|
||||
|
||||
// editors (dynamic table)
|
||||
export * from './dynamic-table/dynamic-table.widget.model';
|
||||
export * from './dynamic-table/editors/row.editor';
|
||||
export * from './dynamic-table/editors/date/date.editor';
|
||||
export * from './dynamic-table/editors/dropdown/dropdown.editor';
|
||||
export * from './dynamic-table/editors/boolean/boolean.editor';
|
||||
export * from './dynamic-table/editors/text/text.editor';
|
||||
export * from './dynamic-table/editors/datetime/datetime.editor';
|
||||
export * from './dynamic-table/editors/amount/amount.editor';
|
||||
export * from './text/text-mask.component';
|
||||
|
||||
export const WIDGET_DIRECTIVES: any[] = [
|
||||
@ -95,29 +59,13 @@ export const WIDGET_DIRECTIVES: any[] = [
|
||||
NumberWidgetComponent,
|
||||
CheckboxWidgetComponent,
|
||||
MultilineTextWidgetComponentComponent,
|
||||
DropdownWidgetComponent,
|
||||
HyperlinkWidgetComponent,
|
||||
RadioButtonsWidgetComponent,
|
||||
DisplayTextWidgetComponent,
|
||||
UploadWidgetComponent,
|
||||
TypeaheadWidgetComponent,
|
||||
FunctionalGroupWidgetComponent,
|
||||
PeopleWidgetComponent,
|
||||
DateWidgetComponent,
|
||||
AmountWidgetComponent,
|
||||
DynamicTableWidgetComponent,
|
||||
DateEditorComponent,
|
||||
DropdownEditorComponent,
|
||||
BooleanEditorComponent,
|
||||
TextEditorComponent,
|
||||
RowEditorComponent,
|
||||
ErrorWidgetComponent,
|
||||
DocumentWidgetComponent,
|
||||
DateTimeWidgetComponent,
|
||||
DateTimeEditorComponent,
|
||||
JsonWidgetComponent,
|
||||
AmountEditorComponent,
|
||||
UploadFolderWidgetComponent,
|
||||
FileViewerWidgetComponent,
|
||||
DisplayRichTextWidgetComponent
|
||||
];
|
||||
|
@ -1,7 +0,0 @@
|
||||
<div class="adf-upload-folder-widget {{field.className}}"
|
||||
[class.adf-invalid]="!field.isValid"
|
||||
[class.adf-readonly]="field.readOnly">
|
||||
<label class="adf-label" [attr.for]="field.id">{{field.name | translate }}<span class="adf-asterisk" *ngIf="isRequired()">*</span></label>
|
||||
<div class="adf-upload-widget-container">
|
||||
</div>
|
||||
</div>
|
@ -1,8 +0,0 @@
|
||||
.adf {
|
||||
&-upload-folder-widget {
|
||||
width: 100%;
|
||||
word-break: break-all;
|
||||
padding: 0.4375em 0;
|
||||
border-top: 0.8438em solid transparent;
|
||||
}
|
||||
}
|
@ -1,61 +0,0 @@
|
||||
/*!
|
||||
* @license
|
||||
* Copyright 2019 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 { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
import { setupTestBed } from '../../../../testing/setup-test-bed';
|
||||
import { CoreTestingModule } from '../../../../testing';
|
||||
import { UploadFolderWidgetComponent } from './upload-folder.widget';
|
||||
import { FormFieldModel } from '../core/form-field.model';
|
||||
import { FormModel } from '../core/form.model';
|
||||
import { FormFieldTypes } from '../core/form-field-types';
|
||||
|
||||
describe('UploadFolderWidgetComponent', () => {
|
||||
|
||||
let widget: UploadFolderWidgetComponent;
|
||||
let fixture: ComponentFixture<UploadFolderWidgetComponent>;
|
||||
let element: HTMLElement;
|
||||
|
||||
setupTestBed({
|
||||
imports: [
|
||||
CoreTestingModule
|
||||
]
|
||||
});
|
||||
|
||||
beforeEach(() => {
|
||||
fixture = TestBed.createComponent(UploadFolderWidgetComponent);
|
||||
widget = fixture.componentInstance;
|
||||
element = fixture.nativeElement;
|
||||
});
|
||||
|
||||
describe('when is required', () => {
|
||||
|
||||
it('should be able to display label with asterisk', async () => {
|
||||
widget.field = new FormFieldModel( new FormModel({ taskId: '<id>' }), {
|
||||
type: FormFieldTypes.UPLOAD,
|
||||
required: true
|
||||
});
|
||||
|
||||
fixture.detectChanges();
|
||||
await fixture.whenStable();
|
||||
|
||||
const asterisk: HTMLElement = element.querySelector('.adf-asterisk');
|
||||
|
||||
expect(asterisk).toBeTruthy();
|
||||
expect(asterisk.textContent).toEqual('*');
|
||||
});
|
||||
});
|
||||
});
|
@ -1,165 +0,0 @@
|
||||
/*!
|
||||
* @license
|
||||
* Copyright 2019 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.
|
||||
*/
|
||||
|
||||
/* eslint-disable @angular-eslint/component-selector */
|
||||
|
||||
import { LogService } from '../../../../services/log.service';
|
||||
import { ThumbnailService } from '../../../../services/thumbnail.service';
|
||||
import { Component, ElementRef, OnInit, ViewChild, ViewEncapsulation } from '@angular/core';
|
||||
import { Observable, from } from 'rxjs';
|
||||
import { FormService } from '../../../services/form.service';
|
||||
import { ProcessContentService } from '../../../services/process-content.service';
|
||||
import { ContentLinkModel } from '../core/content-link.model';
|
||||
import { WidgetComponent } from '../widget.component';
|
||||
import { mergeMap, map } from 'rxjs/operators';
|
||||
|
||||
@Component({
|
||||
selector: 'upload-folder-widget',
|
||||
templateUrl: './upload-folder.widget.html',
|
||||
styleUrls: ['./upload-folder.widget.scss'],
|
||||
host: {
|
||||
'(click)': 'event($event)',
|
||||
'(blur)': 'event($event)',
|
||||
'(change)': 'event($event)',
|
||||
'(focus)': 'event($event)',
|
||||
'(focusin)': 'event($event)',
|
||||
'(focusout)': 'event($event)',
|
||||
'(input)': 'event($event)',
|
||||
'(invalid)': 'event($event)',
|
||||
'(select)': 'event($event)'
|
||||
},
|
||||
encapsulation: ViewEncapsulation.None
|
||||
})
|
||||
export class UploadFolderWidgetComponent extends WidgetComponent implements OnInit {
|
||||
|
||||
hasFile: boolean;
|
||||
displayText: string;
|
||||
multipleOption: string = '';
|
||||
mimeTypeIcon: string;
|
||||
|
||||
@ViewChild('uploadFiles')
|
||||
fileInput: ElementRef;
|
||||
|
||||
constructor(public formService: FormService,
|
||||
private logService: LogService,
|
||||
private thumbnailService: ThumbnailService,
|
||||
public processContentService: ProcessContentService) {
|
||||
super(formService);
|
||||
}
|
||||
|
||||
ngOnInit() {
|
||||
if (this.field &&
|
||||
this.field.value &&
|
||||
this.field.value.length > 0) {
|
||||
this.hasFile = true;
|
||||
}
|
||||
this.getMultipleFileParam();
|
||||
}
|
||||
|
||||
removeFile(file: any) {
|
||||
if (this.field) {
|
||||
this.removeElementFromList(file);
|
||||
}
|
||||
}
|
||||
|
||||
onFileChanged(event: any) {
|
||||
const files = event.target.files;
|
||||
let filesSaved = [];
|
||||
|
||||
if (this.field.json.value) {
|
||||
filesSaved = [...this.field.json.value];
|
||||
}
|
||||
|
||||
if (files && files.length > 0) {
|
||||
from(files)
|
||||
.pipe(mergeMap((file) => this.uploadRawContent(file)))
|
||||
.subscribe(
|
||||
(res) => {
|
||||
filesSaved.push(res);
|
||||
},
|
||||
() => {
|
||||
this.logService.error('Error uploading file. See console output for more details.');
|
||||
},
|
||||
() => {
|
||||
this.field.value = filesSaved;
|
||||
this.field.json.value = filesSaved;
|
||||
}
|
||||
);
|
||||
|
||||
this.hasFile = true;
|
||||
}
|
||||
}
|
||||
|
||||
private uploadRawContent(file): Observable<any> {
|
||||
return this.processContentService.createTemporaryRawRelatedContent(file).pipe(
|
||||
map((response: any) => {
|
||||
this.logService.info(response);
|
||||
return response;
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
private getMultipleFileParam() {
|
||||
if (this.field &&
|
||||
this.field.params &&
|
||||
this.field.params.multiple) {
|
||||
this.multipleOption = this.field.params.multiple ? 'multiple' : '';
|
||||
}
|
||||
}
|
||||
|
||||
private removeElementFromList(file) {
|
||||
const index = this.field.value.indexOf(file);
|
||||
|
||||
if (index !== -1) {
|
||||
this.field.value.splice(index, 1);
|
||||
this.field.json.value = this.field.value;
|
||||
this.field.updateForm();
|
||||
}
|
||||
|
||||
this.hasFile = this.field.value.length > 0;
|
||||
|
||||
this.resetFormValueWithNoFiles();
|
||||
}
|
||||
|
||||
private resetFormValueWithNoFiles() {
|
||||
if (this.field.value.length === 0) {
|
||||
this.field.value = [];
|
||||
this.field.json.value = [];
|
||||
}
|
||||
}
|
||||
|
||||
getIcon(mimeType) {
|
||||
return this.thumbnailService.getMimeTypeIcon(mimeType);
|
||||
}
|
||||
|
||||
fileClicked(contentLinkModel: any): void {
|
||||
const file = new ContentLinkModel(contentLinkModel);
|
||||
let fetch = this.processContentService.getContentPreview(file.id);
|
||||
if (file.isTypeImage() || file.isTypePdf()) {
|
||||
fetch = this.processContentService.getFileRawContent(file.id);
|
||||
}
|
||||
fetch.subscribe(
|
||||
(blob: Blob) => {
|
||||
file.contentBlob = blob;
|
||||
this.formService.formContentClicked.next(file);
|
||||
},
|
||||
() => {
|
||||
this.logService.error('Unable to send event for file ' + file.name);
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
@ -20,5 +20,4 @@ export * from './form-error.event';
|
||||
export * from './form-field.event';
|
||||
export * from './validate-form-field.event';
|
||||
export * from './validate-form.event';
|
||||
export * from './validate-dynamic-table-row.event';
|
||||
export * from './form-rules.event';
|
||||
|
@ -31,8 +31,6 @@ import { MASK_DIRECTIVE, WIDGET_DIRECTIVES } from './components/widgets';
|
||||
import { StartFormCustomButtonDirective } from './components/form-custom-button.directive';
|
||||
|
||||
import { FormFieldComponent } from './components/form-field/form-field.component';
|
||||
import { FormListComponent } from './components/form-list.component';
|
||||
import { ContentWidgetComponent } from './components/widgets/content/content.widget';
|
||||
import { WidgetComponent } from './components/widgets/widget.component';
|
||||
import { MatDatetimepickerModule, MatNativeDatetimeModule } from '@mat-datetimepicker/core';
|
||||
import { FormRendererComponent } from './components/form-renderer.component';
|
||||
@ -61,9 +59,7 @@ import { InplaceFormInputComponent } from './components/inplace-form-input/inpla
|
||||
ViewerModule
|
||||
],
|
||||
declarations: [
|
||||
ContentWidgetComponent,
|
||||
FormFieldComponent,
|
||||
FormListComponent,
|
||||
FormRendererComponent,
|
||||
StartFormCustomButtonDirective,
|
||||
...WIDGET_DIRECTIVES,
|
||||
@ -72,9 +68,7 @@ import { InplaceFormInputComponent } from './components/inplace-form-input/inpla
|
||||
InplaceFormInputComponent
|
||||
],
|
||||
exports: [
|
||||
ContentWidgetComponent,
|
||||
FormFieldComponent,
|
||||
FormListComponent,
|
||||
FormRendererComponent,
|
||||
StartFormCustomButtonDirective,
|
||||
...WIDGET_DIRECTIVES,
|
||||
|
@ -17,21 +17,14 @@
|
||||
|
||||
export * from './components/form-field/form-field.component';
|
||||
export * from './components/form-base.component';
|
||||
export * from './components/form-list.component';
|
||||
export * from './components/inplace-form-input/inplace-form-input.component';
|
||||
export * from './components/widgets/content/content.widget';
|
||||
export * from './components/form-custom-button.directive';
|
||||
export * from './components/form-renderer.component';
|
||||
export * from './components/widgets';
|
||||
export * from './components/widgets/dynamic-table/dynamic-table-row.model';
|
||||
|
||||
export * from './services/activiti-alfresco.service';
|
||||
export * from './services/ecm-model.service';
|
||||
export * from './services/form-rendering.service';
|
||||
export * from './services/form.service';
|
||||
export * from './services/form-validation-service.interface';
|
||||
export * from './services/node.service';
|
||||
export * from './services/process-content.service';
|
||||
export * from './services/widget-visibility.service';
|
||||
|
||||
export * from './events';
|
||||
@ -39,3 +32,5 @@ export * from './events';
|
||||
export * from './form-base.module';
|
||||
|
||||
export * from './models/form-rules.model';
|
||||
export * from './models/form-definition.model';
|
||||
export * from './models/task-process-variable.model';
|
||||
|
@ -17,10 +17,8 @@
|
||||
|
||||
import { DynamicComponentResolver } from '../../../../index';
|
||||
import {
|
||||
FormFieldModel,
|
||||
FormFieldTypes,
|
||||
UnknownWidgetComponent,
|
||||
UploadWidgetComponent,
|
||||
TextWidgetComponent,
|
||||
JsonWidgetComponent,
|
||||
DisplayRichTextWidgetComponent
|
||||
@ -35,23 +33,6 @@ describe('FormRenderingService', () => {
|
||||
service = new FormRenderingService();
|
||||
});
|
||||
|
||||
it('should resolve Upload field as Upload widget', () => {
|
||||
const field = new FormFieldModel(null, {
|
||||
type: FormFieldTypes.UPLOAD,
|
||||
params: {
|
||||
link: null
|
||||
}
|
||||
});
|
||||
const type = service.resolveComponentType(field);
|
||||
expect(type).toBe(UploadWidgetComponent);
|
||||
});
|
||||
|
||||
it('should resolve Upload widget for Upload field', () => {
|
||||
const resolver = service.getComponentTypeResolver(FormFieldTypes.UPLOAD);
|
||||
const type = resolver(null);
|
||||
expect(type).toBe(UploadWidgetComponent);
|
||||
});
|
||||
|
||||
it('should resolve Unknown widget for unknown field type', () => {
|
||||
const resolver = service.getComponentTypeResolver('missing-type');
|
||||
const type = resolver(null);
|
||||
@ -70,12 +51,6 @@ describe('FormRenderingService', () => {
|
||||
expect(type).toBe(UnknownWidgetComponent);
|
||||
});
|
||||
|
||||
it('should fallback to custom resolver when field type missing', () => {
|
||||
const resolver = service.getComponentTypeResolver(null, UploadWidgetComponent);
|
||||
const type = resolver(null);
|
||||
expect(type).toBe(UploadWidgetComponent);
|
||||
});
|
||||
|
||||
it('should require field type to set resolver for type', () => {
|
||||
expect(
|
||||
() => service.setComponentTypeResolver(
|
||||
@ -120,10 +95,6 @@ describe('FormRenderingService', () => {
|
||||
expect(service.resolveComponentType(null)).toBe(UnknownWidgetComponent);
|
||||
});
|
||||
|
||||
it('should return custom value when resolving with no field', () => {
|
||||
expect(service.resolveComponentType(null, UploadWidgetComponent)).toBe(UploadWidgetComponent);
|
||||
});
|
||||
|
||||
it('should resolve Display Text Widget for JSON field type', () => {
|
||||
const resolver = service.getComponentTypeResolver('json');
|
||||
const type = resolver(null);
|
||||
|
@ -32,20 +32,12 @@ export class FormRenderingService extends DynamicComponentMapper {
|
||||
integer: DynamicComponentResolver.fromType(widgets.NumberWidgetComponent),
|
||||
'multi-line-text': DynamicComponentResolver.fromType(widgets.MultilineTextWidgetComponentComponent),
|
||||
boolean: DynamicComponentResolver.fromType(widgets.CheckboxWidgetComponent),
|
||||
dropdown: DynamicComponentResolver.fromType(widgets.DropdownWidgetComponent),
|
||||
date: DynamicComponentResolver.fromType(widgets.DateWidgetComponent),
|
||||
amount: DynamicComponentResolver.fromType(widgets.AmountWidgetComponent),
|
||||
'radio-buttons': DynamicComponentResolver.fromType(widgets.RadioButtonsWidgetComponent),
|
||||
hyperlink: DynamicComponentResolver.fromType(widgets.HyperlinkWidgetComponent),
|
||||
'readonly-text': DynamicComponentResolver.fromType(widgets.DisplayTextWidgetComponent),
|
||||
json: DynamicComponentResolver.fromType(widgets.JsonWidgetComponent),
|
||||
readonly: DynamicComponentResolver.fromType(widgets.TextWidgetComponent),
|
||||
typeahead: DynamicComponentResolver.fromType(widgets.TypeaheadWidgetComponent),
|
||||
people: DynamicComponentResolver.fromType(widgets.PeopleWidgetComponent),
|
||||
'functional-group': DynamicComponentResolver.fromType(widgets.FunctionalGroupWidgetComponent),
|
||||
'dynamic-table': DynamicComponentResolver.fromType(widgets.DynamicTableWidgetComponent),
|
||||
document: DynamicComponentResolver.fromType(widgets.DocumentWidgetComponent),
|
||||
upload: DynamicComponentResolver.fromType(widgets.UploadWidgetComponent),
|
||||
datetime: DynamicComponentResolver.fromType(widgets.DateTimeWidgetComponent),
|
||||
'file-viewer': DynamicComponentResolver.fromType(widgets.FileViewerWidgetComponent),
|
||||
'display-rich-text': DynamicComponentResolver.fromType(widgets.DisplayRichTextWidgetComponent)
|
||||
|
@ -15,40 +15,13 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { fakeAsync, TestBed } from '@angular/core/testing';
|
||||
import { TestBed } from '@angular/core/testing';
|
||||
import { formModelTabs } from '../../mock';
|
||||
import { FormService } from './form.service';
|
||||
import { setupTestBed } from '../../testing/setup-test-bed';
|
||||
import { CoreTestingModule } from '../../testing/core.testing.module';
|
||||
import { TranslateModule } from '@ngx-translate/core';
|
||||
|
||||
declare let jasmine: any;
|
||||
|
||||
const fakeGroupResponse = {
|
||||
size: 2,
|
||||
total: 2,
|
||||
start: 0,
|
||||
data: [{
|
||||
id: '2004',
|
||||
name: 'PEOPLE_GROUP',
|
||||
externalId: null,
|
||||
status: 'active',
|
||||
groups: null
|
||||
}, { id: 2005, name: 'PEOPLE_GROUP_2', externalId: null, status: 'active', groups: null }]
|
||||
};
|
||||
|
||||
const fakePeopleResponse = {
|
||||
size: 3,
|
||||
total: 3,
|
||||
start: 0,
|
||||
data: [{ id: 2002, firstName: 'Peo', lastName: 'Ple', email: 'people' }, {
|
||||
id: 2003,
|
||||
firstName: 'Peo02',
|
||||
lastName: 'Ple02',
|
||||
email: 'people02'
|
||||
}, { id: 2004, firstName: 'Peo03', lastName: 'Ple03', email: 'people03' }]
|
||||
};
|
||||
|
||||
describe('Form service', () => {
|
||||
|
||||
let service: FormService;
|
||||
@ -62,289 +35,12 @@ describe('Form service', () => {
|
||||
|
||||
beforeEach(() => {
|
||||
service = TestBed.inject(FormService);
|
||||
jasmine.Ajax.install();
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
jasmine.Ajax.uninstall();
|
||||
});
|
||||
|
||||
describe('Content tests', () => {
|
||||
|
||||
const responseBody = {
|
||||
data: [
|
||||
{ id: '1' },
|
||||
{ id: '2' }
|
||||
]
|
||||
};
|
||||
|
||||
const values = {
|
||||
field1: 'one',
|
||||
field2: 'two'
|
||||
};
|
||||
|
||||
const simpleResponseBody = { id: 1, modelType: 'test' };
|
||||
|
||||
it('should fetch and parse process definitions', (done) => {
|
||||
service.getProcessDefinitions().subscribe(() => {
|
||||
expect(jasmine.Ajax.requests.mostRecent().url.endsWith('/process-definitions')).toBeTruthy();
|
||||
expect([{ id: '1' }, { id: '2' }]).toEqual(JSON.parse(jasmine.Ajax.requests.mostRecent().response).data);
|
||||
done();
|
||||
});
|
||||
|
||||
jasmine.Ajax.requests.mostRecent().respondWith({
|
||||
status: 200,
|
||||
contentType: 'application/json',
|
||||
responseText: JSON.stringify(responseBody)
|
||||
});
|
||||
});
|
||||
|
||||
it('should fetch and parse tasks', (done) => {
|
||||
service.getTasks().subscribe(() => {
|
||||
expect(jasmine.Ajax.requests.mostRecent().url.endsWith('/tasks/query')).toBeTruthy();
|
||||
expect([{ id: '1' }, { id: '2' }]).toEqual(JSON.parse(jasmine.Ajax.requests.mostRecent().response).data);
|
||||
done();
|
||||
});
|
||||
|
||||
jasmine.Ajax.requests.mostRecent().respondWith({
|
||||
status: 200,
|
||||
contentType: 'application/json',
|
||||
responseText: JSON.stringify(responseBody)
|
||||
});
|
||||
});
|
||||
|
||||
it('should fetch and parse the task by id', (done) => {
|
||||
service.getTask('1').subscribe((result) => {
|
||||
expect(jasmine.Ajax.requests.mostRecent().url.endsWith('/tasks/1')).toBeTruthy();
|
||||
expect(result.id).toEqual('1');
|
||||
done();
|
||||
});
|
||||
|
||||
jasmine.Ajax.requests.mostRecent().respondWith({
|
||||
status: 200,
|
||||
contentType: 'application/json',
|
||||
responseText: JSON.stringify({ id: '1' })
|
||||
});
|
||||
});
|
||||
|
||||
it('should save task form', (done) => {
|
||||
service.saveTaskForm('1', values).subscribe(() => {
|
||||
expect(jasmine.Ajax.requests.mostRecent().url.endsWith('/task-forms/1/save-form')).toBeTruthy();
|
||||
expect(JSON.parse(jasmine.Ajax.requests.mostRecent().params).values.field1).toEqual(values.field1);
|
||||
expect(JSON.parse(jasmine.Ajax.requests.mostRecent().params).values.field2).toEqual(values.field2);
|
||||
done();
|
||||
});
|
||||
|
||||
jasmine.Ajax.requests.mostRecent().respondWith({
|
||||
status: 200,
|
||||
contentType: 'application/json',
|
||||
responseText: JSON.stringify(responseBody)
|
||||
});
|
||||
});
|
||||
|
||||
it('should complete task form', (done) => {
|
||||
service.completeTaskForm('1', values).subscribe(() => {
|
||||
expect(jasmine.Ajax.requests.mostRecent().url.endsWith('/task-forms/1')).toBeTruthy();
|
||||
expect(JSON.parse(jasmine.Ajax.requests.mostRecent().params).values.field1).toEqual(values.field1);
|
||||
expect(JSON.parse(jasmine.Ajax.requests.mostRecent().params).values.field2).toEqual(values.field2);
|
||||
done();
|
||||
});
|
||||
|
||||
jasmine.Ajax.requests.mostRecent().respondWith({
|
||||
status: 200,
|
||||
contentType: 'application/json',
|
||||
responseText: JSON.stringify(responseBody)
|
||||
});
|
||||
});
|
||||
|
||||
it('should complete task form with a specific outcome', (done) => {
|
||||
service.completeTaskForm('1', values, 'custom').subscribe(() => {
|
||||
expect(jasmine.Ajax.requests.mostRecent().url.endsWith('/task-forms/1')).toBeTruthy();
|
||||
expect(JSON.parse(jasmine.Ajax.requests.mostRecent().params).values.field2).toEqual(values.field2);
|
||||
expect(JSON.parse(jasmine.Ajax.requests.mostRecent().params).outcome).toEqual('custom');
|
||||
|
||||
done();
|
||||
});
|
||||
|
||||
jasmine.Ajax.requests.mostRecent().respondWith({
|
||||
status: 200,
|
||||
contentType: 'application/json',
|
||||
responseText: JSON.stringify(responseBody)
|
||||
});
|
||||
});
|
||||
|
||||
it('should get task form by id', (done) => {
|
||||
service.getTaskForm('1').subscribe((result) => {
|
||||
expect(jasmine.Ajax.requests.mostRecent().url.endsWith('/task-forms/1')).toBeTruthy();
|
||||
expect(result.id).toEqual(1);
|
||||
done();
|
||||
});
|
||||
|
||||
jasmine.Ajax.requests.mostRecent().respondWith({
|
||||
status: 200,
|
||||
contentType: 'application/json',
|
||||
responseText: JSON.stringify({ id: 1 })
|
||||
});
|
||||
});
|
||||
|
||||
it('should get form definition by id', (done) => {
|
||||
service.getFormDefinitionById(1).subscribe((result) => {
|
||||
expect(jasmine.Ajax.requests.mostRecent().url.endsWith('/form-models/1')).toBeTruthy();
|
||||
expect(result.id).toEqual(1);
|
||||
done();
|
||||
});
|
||||
|
||||
jasmine.Ajax.requests.mostRecent().respondWith({
|
||||
status: 200,
|
||||
contentType: 'application/json',
|
||||
responseText: JSON.stringify({ id: 1 })
|
||||
});
|
||||
});
|
||||
|
||||
it('should get form definition id by name', (done) => {
|
||||
const formName = 'form1';
|
||||
const formId = 1;
|
||||
const response = {
|
||||
data: [
|
||||
{ id: formId }
|
||||
]
|
||||
};
|
||||
|
||||
service.getFormDefinitionByName(formName).subscribe((result) => {
|
||||
expect(jasmine.Ajax.requests.mostRecent().url.endsWith(`models?filter=myReusableForms&filterText=${formName}&modelType=2`)).toBeTruthy();
|
||||
expect(result).toEqual(formId);
|
||||
done();
|
||||
});
|
||||
|
||||
jasmine.Ajax.requests.mostRecent().respondWith({
|
||||
status: 200,
|
||||
contentType: 'application/json',
|
||||
responseText: JSON.stringify(response)
|
||||
});
|
||||
});
|
||||
|
||||
it('should handle error with generic message', () => {
|
||||
service.handleError(null).subscribe(() => {
|
||||
}, (error) => {
|
||||
expect(error).toBe(FormService.UNKNOWN_ERROR_MESSAGE);
|
||||
});
|
||||
});
|
||||
|
||||
it('should handle error with error message', () => {
|
||||
const message = '<error>';
|
||||
|
||||
service.handleError({ message }).subscribe(() => {
|
||||
}, (error) => {
|
||||
expect(error).toBe(message);
|
||||
});
|
||||
});
|
||||
|
||||
it('should handle error with detailed message', () => {
|
||||
service.handleError({
|
||||
status: '400',
|
||||
statusText: 'Bad request'
|
||||
}).subscribe(
|
||||
() => {
|
||||
},
|
||||
(error) => {
|
||||
expect(error).toBe('400 - Bad request');
|
||||
});
|
||||
});
|
||||
|
||||
it('should handle error with generic message', () => {
|
||||
service.handleError({}).subscribe(() => {
|
||||
}, (error) => {
|
||||
expect(error).toBe(FormService.GENERIC_ERROR_MESSAGE);
|
||||
});
|
||||
});
|
||||
|
||||
it('should get all the forms with modelType=2', (done) => {
|
||||
service.getForms().subscribe((result) => {
|
||||
expect(jasmine.Ajax.requests.mostRecent().url.endsWith('models?modelType=2')).toBeTruthy();
|
||||
expect(result.length).toEqual(2);
|
||||
done();
|
||||
});
|
||||
|
||||
jasmine.Ajax.requests.mostRecent().respondWith({
|
||||
status: 200,
|
||||
contentType: 'application/json',
|
||||
responseText: JSON.stringify({
|
||||
data: [
|
||||
{ name: 'FakeName-1', lastUpdatedByFullName: 'FakeUser-1', lastUpdated: '2017-01-02' },
|
||||
{ name: 'FakeName-2', lastUpdatedByFullName: 'FakeUser-2', lastUpdated: '2017-01-03' }
|
||||
]
|
||||
})
|
||||
});
|
||||
});
|
||||
|
||||
it('should search for Form with modelType=2', (done) => {
|
||||
const response = { data: [{ id: 1, name: 'findMe' }, { id: 2, name: 'testForm' }] };
|
||||
|
||||
service.searchFrom('findMe').subscribe((result) => {
|
||||
expect(jasmine.Ajax.requests.mostRecent().url.endsWith('models?modelType=2')).toBeTruthy();
|
||||
expect(result.name).toEqual('findMe');
|
||||
expect(result.id).toEqual(1);
|
||||
done();
|
||||
});
|
||||
|
||||
jasmine.Ajax.requests.mostRecent().respondWith({
|
||||
status: 200,
|
||||
contentType: 'application/json',
|
||||
responseText: JSON.stringify(response)
|
||||
});
|
||||
});
|
||||
|
||||
it('should create a Form with modelType=2', (done) => {
|
||||
service.createForm('testName').subscribe(() => {
|
||||
expect(jasmine.Ajax.requests.mostRecent().url.endsWith('/models')).toBeTruthy();
|
||||
expect(JSON.parse(jasmine.Ajax.requests.mostRecent().params).modelType).toEqual(2);
|
||||
expect(JSON.parse(jasmine.Ajax.requests.mostRecent().params).name).toEqual('testName');
|
||||
done();
|
||||
});
|
||||
|
||||
jasmine.Ajax.requests.mostRecent().respondWith({
|
||||
status: 200,
|
||||
contentType: 'application/json',
|
||||
responseText: JSON.stringify(simpleResponseBody)
|
||||
});
|
||||
});
|
||||
|
||||
it('should return list of people', (done) => {
|
||||
spyOn(service, 'getUserProfileImageApi').and.returnValue('/app/rest/users/2002/picture');
|
||||
const fakeFilter: string = 'whatever';
|
||||
|
||||
service.getWorkflowUsers(fakeFilter).subscribe((result) => {
|
||||
expect(result).toBeDefined();
|
||||
expect(result.length).toBe(3);
|
||||
expect(result[0].id).toBe(2002);
|
||||
expect(result[0].firstName).toBe('Peo');
|
||||
done();
|
||||
});
|
||||
|
||||
jasmine.Ajax.requests.mostRecent().respondWith({
|
||||
status: 200,
|
||||
contentType: 'application/json',
|
||||
responseText: JSON.stringify(fakePeopleResponse)
|
||||
});
|
||||
});
|
||||
|
||||
it('should return list of groups', (done) => {
|
||||
const fakeFilter: string = 'whatever';
|
||||
|
||||
service.getWorkflowGroups(fakeFilter).subscribe((result) => {
|
||||
expect(result).toBeDefined();
|
||||
expect(result.length).toBe(2);
|
||||
expect(result[0].id).toBe('2004');
|
||||
expect(result[0].name).toBe('PEOPLE_GROUP');
|
||||
done();
|
||||
});
|
||||
|
||||
jasmine.Ajax.requests.mostRecent().respondWith({
|
||||
status: 200,
|
||||
contentType: 'application/json',
|
||||
responseText: JSON.stringify(fakeGroupResponse)
|
||||
});
|
||||
});
|
||||
describe('parseForm', () => {
|
||||
|
||||
it('should parse a Form Definition with tabs', () => {
|
||||
expect(formModelTabs.formRepresentation.formDefinition).toBeDefined();
|
||||
@ -352,60 +48,5 @@ describe('Form service', () => {
|
||||
expect(formParsed).toBeDefined();
|
||||
});
|
||||
|
||||
it('should create a Form form a Node', fakeAsync(() => {
|
||||
const nameForm = 'testNode';
|
||||
const formId = 100;
|
||||
|
||||
const stubCreateForm = () => {
|
||||
jasmine.Ajax.stubRequest(
|
||||
'http://localhost:9876/bpm/activiti-app/api/enterprise/models'
|
||||
).andReturn({
|
||||
status: 200,
|
||||
statusText: 'HTTP/1.1 200 OK',
|
||||
contentType: 'text/xml;charset=UTF-8',
|
||||
responseText: { id: formId, name: 'test', lastUpdatedByFullName: 'uset', lastUpdated: '12-12-2016' }
|
||||
});
|
||||
};
|
||||
|
||||
const stubGetEcmModel = () => {
|
||||
jasmine.Ajax.stubRequest(
|
||||
'http://localhost:9876/ecm/alfresco/api/-default-/private/alfresco/versions/1/cmm/activitiFormsModel/types'
|
||||
).andReturn({
|
||||
status: 200,
|
||||
statusText: 'HTTP/1.1 200 OK',
|
||||
contentType: 'text/xml;charset=UTF-8',
|
||||
responseText: {
|
||||
list: {
|
||||
entries: [{
|
||||
entry: {
|
||||
prefixedName: nameForm,
|
||||
title: nameForm,
|
||||
properties: [{ name: 'name' }, { name: 'email' }]
|
||||
}
|
||||
}, { entry: { prefixedName: 'notme', title: 'notme' } }]
|
||||
}
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
const stubAddFieldsToAForm = () => {
|
||||
jasmine.Ajax.stubRequest(
|
||||
'http://localhost:9876/bpm/activiti-app/api/enterprise/editor/form-models/' + formId
|
||||
).andReturn({
|
||||
status: 200,
|
||||
statusText: 'HTTP/1.1 200 OK',
|
||||
contentType: 'text/xml;charset=UTF-8',
|
||||
responseText: { id: formId, name: 'test', lastUpdatedByFullName: 'user', lastUpdated: '12-12-2016' }
|
||||
});
|
||||
};
|
||||
|
||||
stubCreateForm();
|
||||
stubGetEcmModel();
|
||||
stubAddFieldsToAForm();
|
||||
|
||||
service.createFormFromANode(nameForm).subscribe((result) => {
|
||||
expect(result.id).toEqual(formId);
|
||||
});
|
||||
}));
|
||||
});
|
||||
});
|
||||
|
@ -15,29 +15,9 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { AlfrescoApiService } from '../../services/alfresco-api.service';
|
||||
import { LogService } from '../../services/log.service';
|
||||
import { UserProcessModel } from '../../models';
|
||||
import { Injectable } from '@angular/core';
|
||||
import { Observable, Subject, from, of, throwError } from 'rxjs';
|
||||
import { FormDefinitionModel } from '../models/form-definition.model';
|
||||
import { Subject } from 'rxjs';
|
||||
import { ContentLinkModel } from '../components/widgets/core/content-link.model';
|
||||
import { GroupModel } from '../components/widgets/core/group.model';
|
||||
import { EcmModelService } from './ecm-model.service';
|
||||
import { map, catchError, switchMap, combineAll, defaultIfEmpty } from 'rxjs/operators';
|
||||
import {
|
||||
CompleteFormRepresentation,
|
||||
ModelsApi,
|
||||
ProcessInstanceVariablesApi,
|
||||
SaveFormRepresentation,
|
||||
TasksApi,
|
||||
TaskFormsApi,
|
||||
ProcessInstancesApi,
|
||||
FormModelsApi,
|
||||
ProcessDefinitionsApi,
|
||||
UsersApi,
|
||||
ActivitiGroupsApi
|
||||
} from '@alfresco/js-api';
|
||||
import { FormOutcomeEvent } from '../components/widgets/core/form-outcome-event.model';
|
||||
import { FormValues } from '../components/widgets/core/form-values';
|
||||
import { FormModel } from '../components/widgets/core/form.model';
|
||||
@ -47,7 +27,6 @@ import { FormFieldEvent } from '../events/form-field.event';
|
||||
import { FormErrorEvent } from '../events/form-error.event';
|
||||
import { ValidateFormEvent } from '../events/validate-form.event';
|
||||
import { ValidateFormFieldEvent } from '../events/validate-form-field.event';
|
||||
import { ValidateDynamicTableRowEvent } from '../events/validate-dynamic-table-row.event';
|
||||
import { FormValidationService } from './form-validation-service.interface';
|
||||
import { FormRulesEvent } from '../events/form-rules.event';
|
||||
|
||||
@ -56,63 +35,6 @@ import { FormRulesEvent } from '../events/form-rules.event';
|
||||
})
|
||||
export class FormService implements FormValidationService {
|
||||
|
||||
static UNKNOWN_ERROR_MESSAGE: string = 'Unknown error';
|
||||
static GENERIC_ERROR_MESSAGE: string = 'Server error';
|
||||
|
||||
_taskFormsApi: TaskFormsApi;
|
||||
get taskFormsApi(): TaskFormsApi {
|
||||
this._taskFormsApi = this._taskFormsApi ?? new TaskFormsApi(this.apiService.getInstance());
|
||||
return this._taskFormsApi;
|
||||
}
|
||||
|
||||
_taskApi: TasksApi;
|
||||
get taskApi(): TasksApi {
|
||||
this._taskApi = this._taskApi ?? new TasksApi(this.apiService.getInstance());
|
||||
return this._taskApi;
|
||||
}
|
||||
|
||||
_modelsApi: ModelsApi;
|
||||
get modelsApi(): ModelsApi {
|
||||
this._modelsApi = this._modelsApi ?? new ModelsApi(this.apiService.getInstance());
|
||||
return this._modelsApi;
|
||||
}
|
||||
|
||||
_editorApi: FormModelsApi;
|
||||
get editorApi(): FormModelsApi {
|
||||
this._editorApi = this._editorApi ?? new FormModelsApi(this.apiService.getInstance());
|
||||
return this._editorApi;
|
||||
}
|
||||
|
||||
_processDefinitionsApi: ProcessDefinitionsApi;
|
||||
get processDefinitionsApi(): ProcessDefinitionsApi {
|
||||
this._processDefinitionsApi = this._processDefinitionsApi ?? new ProcessDefinitionsApi(this.apiService.getInstance());
|
||||
return this._processDefinitionsApi;
|
||||
}
|
||||
|
||||
_processInstanceVariablesApi: ProcessInstanceVariablesApi;
|
||||
get processInstanceVariablesApi(): ProcessInstanceVariablesApi {
|
||||
this._processInstanceVariablesApi = this._processInstanceVariablesApi ?? new ProcessInstanceVariablesApi(this.apiService.getInstance());
|
||||
return this._processInstanceVariablesApi;
|
||||
}
|
||||
|
||||
_processInstancesApi: ProcessInstancesApi;
|
||||
get processInstancesApi(): ProcessInstancesApi {
|
||||
this._processInstancesApi = this._processInstancesApi ?? new ProcessInstancesApi(this.apiService.getInstance());
|
||||
return this._processInstancesApi;
|
||||
}
|
||||
|
||||
_groupsApi: ActivitiGroupsApi;
|
||||
get groupsApi(): ActivitiGroupsApi {
|
||||
this._groupsApi = this._groupsApi ?? new ActivitiGroupsApi(this.apiService.getInstance());
|
||||
return this._groupsApi;
|
||||
}
|
||||
|
||||
_usersApi: UsersApi;
|
||||
get usersApi(): UsersApi {
|
||||
this._usersApi = this._usersApi ?? new UsersApi(this.apiService.getInstance());
|
||||
return this._usersApi;
|
||||
}
|
||||
|
||||
formLoaded = new Subject<FormEvent>();
|
||||
formDataRefreshed = new Subject<FormEvent>();
|
||||
formFieldValueChanged = new Subject<FormFieldEvent>();
|
||||
@ -125,7 +47,7 @@ export class FormService implements FormValidationService {
|
||||
|
||||
validateForm = new Subject<ValidateFormEvent>();
|
||||
validateFormField = new Subject<ValidateFormFieldEvent>();
|
||||
validateDynamicTableRow = new Subject<ValidateDynamicTableRowEvent>();
|
||||
validateDynamicTableRow = new Subject<FormFieldEvent>();
|
||||
|
||||
executeOutcome = new Subject<FormOutcomeEvent>();
|
||||
|
||||
@ -133,9 +55,7 @@ export class FormService implements FormValidationService {
|
||||
|
||||
formRulesEvent = new Subject<FormRulesEvent>();
|
||||
|
||||
constructor(private ecmModelService: EcmModelService,
|
||||
private apiService: AlfrescoApiService,
|
||||
protected logService: LogService) {
|
||||
constructor() {
|
||||
}
|
||||
|
||||
/**
|
||||
@ -163,449 +83,4 @@ export class FormService implements FormValidationService {
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a Form with a field for each metadata property.
|
||||
*
|
||||
* @param formName Name of the new form
|
||||
* @returns The new form
|
||||
*/
|
||||
createFormFromANode(formName: string): Observable<any> {
|
||||
return new Observable((observer) => {
|
||||
this.createForm(formName).subscribe(
|
||||
(form) => {
|
||||
this.ecmModelService.searchEcmType(formName, EcmModelService.MODEL_NAME).subscribe(
|
||||
(customType) => {
|
||||
const formDefinitionModel = new FormDefinitionModel(form.id, form.name, form.lastUpdatedByFullName, form.lastUpdated, customType.entry.properties);
|
||||
from(
|
||||
this.editorApi.saveForm(form.id, formDefinitionModel)
|
||||
).subscribe((formData) => {
|
||||
observer.next(formData);
|
||||
observer.complete();
|
||||
}, (err) => this.handleError(err));
|
||||
},
|
||||
(err) => this.handleError(err));
|
||||
},
|
||||
(err) => this.handleError(err));
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a Form.
|
||||
*
|
||||
* @param formName Name of the new form
|
||||
* @returns The new form
|
||||
*/
|
||||
createForm(formName: string): Observable<any> {
|
||||
const dataModel = {
|
||||
name: formName,
|
||||
description: '',
|
||||
modelType: 2,
|
||||
stencilSet: 0
|
||||
};
|
||||
|
||||
return from(
|
||||
this.modelsApi.createModel(dataModel)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Saves a form.
|
||||
*
|
||||
* @param formId ID of the form to save
|
||||
* @param formModel Model data for the form
|
||||
* @returns Data for the saved form
|
||||
*/
|
||||
saveForm(formId: number, formModel: FormDefinitionModel): Observable<any> {
|
||||
return from(
|
||||
this.editorApi.saveForm(formId, formModel)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Searches for a form by name.
|
||||
*
|
||||
* @param name The form name to search for
|
||||
* @returns Form model(s) matching the search name
|
||||
*/
|
||||
searchFrom(name: string): Observable<any> {
|
||||
const opts = {
|
||||
modelType: 2
|
||||
};
|
||||
|
||||
return from(
|
||||
this.modelsApi.getModels(opts)
|
||||
)
|
||||
.pipe(
|
||||
map((forms: any) => forms.data.find((formData) => formData.name === name)),
|
||||
catchError((err) => this.handleError(err))
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets all the forms.
|
||||
*
|
||||
* @returns List of form models
|
||||
*/
|
||||
getForms(): Observable<any> {
|
||||
const opts = {
|
||||
modelType: 2
|
||||
};
|
||||
|
||||
return from(this.modelsApi.getModels(opts))
|
||||
.pipe(
|
||||
map(this.toJsonArray),
|
||||
catchError((err) => this.handleError(err))
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets process definitions.
|
||||
*
|
||||
* @returns List of process definitions
|
||||
*/
|
||||
getProcessDefinitions(): Observable<any> {
|
||||
return from(this.processDefinitionsApi.getProcessDefinitions({}))
|
||||
.pipe(
|
||||
map(this.toJsonArray),
|
||||
catchError((err) => this.handleError(err))
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets instance variables for a process.
|
||||
*
|
||||
* @param processInstanceId ID of the target process
|
||||
* @returns List of instance variable information
|
||||
*/
|
||||
getProcessVariablesById(processInstanceId: string): Observable<any[]> {
|
||||
return from(this.processInstanceVariablesApi.getProcessInstanceVariables(processInstanceId))
|
||||
.pipe(
|
||||
map(this.toJson),
|
||||
catchError((err) => this.handleError(err))
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets all the tasks.
|
||||
*
|
||||
* @returns List of tasks
|
||||
*/
|
||||
getTasks(): Observable<any> {
|
||||
return from(this.taskApi.listTasks({}))
|
||||
.pipe(
|
||||
map(this.toJsonArray),
|
||||
catchError((err) => this.handleError(err))
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a task.
|
||||
*
|
||||
* @param taskId Task Id
|
||||
* @returns Task info
|
||||
*/
|
||||
getTask(taskId: string): Observable<any> {
|
||||
return from(this.taskApi.getTask(taskId))
|
||||
.pipe(
|
||||
map(this.toJson),
|
||||
catchError((err) => this.handleError(err))
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Saves a task form.
|
||||
*
|
||||
* @param taskId Task Id
|
||||
* @param formValues Form Values
|
||||
* @returns Null response when the operation is complete
|
||||
*/
|
||||
saveTaskForm(taskId: string, formValues: FormValues): Observable<any> {
|
||||
const saveFormRepresentation = { values: formValues } as SaveFormRepresentation;
|
||||
|
||||
return from(this.taskFormsApi.saveTaskForm(taskId, saveFormRepresentation))
|
||||
.pipe(
|
||||
catchError((err) => this.handleError(err))
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Completes a Task Form.
|
||||
*
|
||||
* @param taskId Task Id
|
||||
* @param formValues Form Values
|
||||
* @param outcome Form Outcome
|
||||
* @returns Null response when the operation is complete
|
||||
*/
|
||||
completeTaskForm(taskId: string, formValues: FormValues, outcome?: string): Observable<any> {
|
||||
const completeFormRepresentation = { values: formValues } as CompleteFormRepresentation;
|
||||
if (outcome) {
|
||||
completeFormRepresentation.outcome = outcome;
|
||||
}
|
||||
|
||||
return from(this.taskFormsApi.completeTaskForm(taskId, completeFormRepresentation))
|
||||
.pipe(
|
||||
catchError((err) => this.handleError(err))
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a form related to a task.
|
||||
*
|
||||
* @param taskId ID of the target task
|
||||
* @returns Form definition
|
||||
*/
|
||||
getTaskForm(taskId: string): Observable<any> {
|
||||
return from(this.taskFormsApi.getTaskForm(taskId))
|
||||
.pipe(
|
||||
map(this.toJson),
|
||||
catchError((err) => this.handleError(err))
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a form definition.
|
||||
*
|
||||
* @param formId ID of the target form
|
||||
* @returns Form definition
|
||||
*/
|
||||
getFormDefinitionById(formId: number): Observable<any> {
|
||||
return from(this.editorApi.getForm(formId))
|
||||
.pipe(
|
||||
map(this.toJson),
|
||||
catchError((err) => this.handleError(err))
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the form definition with a given name.
|
||||
*
|
||||
* @param name The form name
|
||||
* @returns Form definition
|
||||
*/
|
||||
getFormDefinitionByName(name: string): Observable<any> {
|
||||
const opts = {
|
||||
filter: 'myReusableForms',
|
||||
filterText: name,
|
||||
modelType: 2
|
||||
};
|
||||
|
||||
return from(this.modelsApi.getModels(opts))
|
||||
.pipe(
|
||||
map(this.getFormId),
|
||||
catchError((err) => this.handleError(err))
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the start form instance for a given process.
|
||||
*
|
||||
* @param processId Process definition ID
|
||||
* @returns Form definition
|
||||
*/
|
||||
getStartFormInstance(processId: string): Observable<any> {
|
||||
return from(this.processInstancesApi.getProcessInstanceStartForm(processId))
|
||||
.pipe(
|
||||
map(this.toJson),
|
||||
catchError((err) => this.handleError(err))
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a process instance.
|
||||
*
|
||||
* @param processId ID of the process to get
|
||||
* @returns Process instance
|
||||
*/
|
||||
getProcessInstance(processId: string): Observable<any> {
|
||||
return from(this.processInstancesApi.getProcessInstance(processId))
|
||||
.pipe(
|
||||
map(this.toJson),
|
||||
catchError((err) => this.handleError(err))
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the start form definition for a given process.
|
||||
*
|
||||
* @param processId Process definition ID
|
||||
* @returns Form definition
|
||||
*/
|
||||
getStartFormDefinition(processId: string): Observable<any> {
|
||||
return from(this.processDefinitionsApi.getProcessDefinitionStartForm(processId))
|
||||
.pipe(
|
||||
map(this.toJson),
|
||||
catchError((err) => this.handleError(err))
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets values of fields populated by a REST backend.
|
||||
*
|
||||
* @param taskId Task identifier
|
||||
* @param field Field identifier
|
||||
* @returns Field values
|
||||
*/
|
||||
getRestFieldValues(taskId: string, field: string): Observable<any> {
|
||||
return from(this.taskFormsApi.getRestFieldValues(taskId, field))
|
||||
.pipe(
|
||||
catchError((err) => this.handleError(err))
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets values of fields populated by a REST backend using a process ID.
|
||||
*
|
||||
* @param processDefinitionId Process identifier
|
||||
* @param field Field identifier
|
||||
* @returns Field values
|
||||
*/
|
||||
getRestFieldValuesByProcessId(processDefinitionId: string, field: string): Observable<any> {
|
||||
return from(this.processDefinitionsApi.getRestFieldValues(processDefinitionId, field))
|
||||
.pipe(
|
||||
catchError((err) => this.handleError(err))
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets column values of fields populated by a REST backend using a process ID.
|
||||
*
|
||||
* @param processDefinitionId Process identifier
|
||||
* @param field Field identifier
|
||||
* @param column Column identifier
|
||||
* @returns Field values
|
||||
*/
|
||||
getRestFieldValuesColumnByProcessId(processDefinitionId: string, field: string, column?: string): Observable<any> {
|
||||
return from(this.processDefinitionsApi.getRestTableFieldValues(processDefinitionId, field, column))
|
||||
.pipe(
|
||||
catchError((err) => this.handleError(err))
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets column values of fields populated by a REST backend.
|
||||
*
|
||||
* @param taskId Task identifier
|
||||
* @param field Field identifier
|
||||
* @param column Column identifier
|
||||
* @returns Field values
|
||||
*/
|
||||
getRestFieldValuesColumn(taskId: string, field: string, column?: string): Observable<any> {
|
||||
return from(this.taskFormsApi.getRestFieldColumnValues(taskId, field, column))
|
||||
.pipe(
|
||||
catchError((err) => this.handleError(err))
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a URL for the profile picture of a user.
|
||||
*
|
||||
* @param userId ID of the target user
|
||||
* @returns URL string
|
||||
*/
|
||||
getUserProfileImageApi(userId: string): string {
|
||||
return this.usersApi.getUserProfilePictureUrl(userId);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a list of workflow users.
|
||||
*
|
||||
* @param filter Filter to select specific users
|
||||
* @param groupId Group ID for the search
|
||||
* @returns Array of users
|
||||
*/
|
||||
getWorkflowUsers(filter: string, groupId?: string): Observable<UserProcessModel[]> {
|
||||
const option: any = { filter };
|
||||
if (groupId) {
|
||||
option.groupId = groupId;
|
||||
}
|
||||
return from(this.usersApi.getUsers(option))
|
||||
.pipe(
|
||||
switchMap(response => response.data as UserProcessModel[] || []),
|
||||
map((user) => {
|
||||
user.userImage = this.getUserProfileImageApi(user.id.toString());
|
||||
return of(user);
|
||||
}),
|
||||
combineAll(),
|
||||
defaultIfEmpty([]),
|
||||
catchError((err) => this.handleError(err))
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a list of groups in a workflow.
|
||||
*
|
||||
* @param filter Filter to select specific groups
|
||||
* @param groupId Group ID for the search
|
||||
* @returns Array of groups
|
||||
*/
|
||||
getWorkflowGroups(filter: string, groupId?: string): Observable<GroupModel[]> {
|
||||
const option: any = { filter };
|
||||
if (groupId) {
|
||||
option.groupId = groupId;
|
||||
}
|
||||
return from(this.groupsApi.getGroups(option))
|
||||
.pipe(
|
||||
map((response: any) => response.data || []),
|
||||
catchError((err) => this.handleError(err))
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the ID of a form.
|
||||
*
|
||||
* @param form Object representing a form
|
||||
* @returns ID string
|
||||
*/
|
||||
getFormId(form: any): string {
|
||||
let result = null;
|
||||
|
||||
if (form && form.data && form.data.length > 0) {
|
||||
result = form.data[0].id;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a JSON representation of form data.
|
||||
*
|
||||
* @param res Object representing form data
|
||||
* @returns JSON data
|
||||
*/
|
||||
toJson(res: any) {
|
||||
if (res) {
|
||||
return res || {};
|
||||
}
|
||||
return {};
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a JSON array representation of form data.
|
||||
*
|
||||
* @param res Object representing form data
|
||||
* @returns JSON data
|
||||
*/
|
||||
toJsonArray(res: any) {
|
||||
if (res) {
|
||||
return res.data || [];
|
||||
}
|
||||
return [];
|
||||
}
|
||||
|
||||
/**
|
||||
* Reports an error message.
|
||||
*
|
||||
* @param error Data object with optional `message` and `status` fields for the error
|
||||
* @returns Error message
|
||||
*/
|
||||
handleError(error: any): Observable<any> {
|
||||
let errMsg = FormService.UNKNOWN_ERROR_MESSAGE;
|
||||
if (error) {
|
||||
errMsg = (error.message) ? error.message :
|
||||
error.status ? `${error.status} - ${error.statusText}` : FormService.GENERIC_ERROR_MESSAGE;
|
||||
}
|
||||
this.logService.error(errMsg);
|
||||
return throwError(errMsg);
|
||||
}
|
||||
}
|
||||
|
@ -1,171 +0,0 @@
|
||||
/*!
|
||||
* @license
|
||||
* Copyright 2019 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 { TestBed } from '@angular/core/testing';
|
||||
import { NodeMetadata } from '../../models/node-metadata.model';
|
||||
import { EcmModelService } from './ecm-model.service';
|
||||
import { NodeService } from './node.service';
|
||||
import { setupTestBed } from '../../testing/setup-test-bed';
|
||||
import { CoreTestingModule } from '../../testing/core.testing.module';
|
||||
import { TranslateModule } from '@ngx-translate/core';
|
||||
|
||||
declare let jasmine: any;
|
||||
|
||||
describe('NodeService', () => {
|
||||
|
||||
let service: NodeService;
|
||||
|
||||
setupTestBed({
|
||||
imports: [
|
||||
TranslateModule.forRoot(),
|
||||
CoreTestingModule
|
||||
]
|
||||
});
|
||||
|
||||
beforeEach(() => {
|
||||
service = TestBed.inject(NodeService);
|
||||
});
|
||||
|
||||
beforeEach(() => {
|
||||
jasmine.Ajax.install();
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
jasmine.Ajax.uninstall();
|
||||
});
|
||||
|
||||
it('Should fetch and node metadata', (done) => {
|
||||
const responseBody = {
|
||||
entry: {
|
||||
id: '111-222-33-44-1123',
|
||||
nodeType: 'typeTest',
|
||||
properties: {
|
||||
test: 'test',
|
||||
testdata: 'testdata'
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
service.getNodeMetadata('-nodeid-').subscribe((result) => {
|
||||
expect(jasmine.Ajax.requests.mostRecent().url.endsWith('nodes/-nodeid-')).toBeTruthy();
|
||||
const node = new NodeMetadata({
|
||||
test: 'test',
|
||||
testdata: 'testdata'
|
||||
}, 'typeTest');
|
||||
expect(result).toEqual(node);
|
||||
done();
|
||||
});
|
||||
|
||||
jasmine.Ajax.requests.mostRecent().respondWith({
|
||||
status: 200,
|
||||
contentType: 'application/json',
|
||||
responseText: JSON.stringify(responseBody)
|
||||
});
|
||||
});
|
||||
|
||||
it('Should clean the metadata from :', (done) => {
|
||||
const responseBody = {
|
||||
entry: {
|
||||
id: '111-222-33-44-1123',
|
||||
nodeType: 'typeTest',
|
||||
properties: {
|
||||
'metadata:test': 'test',
|
||||
'metadata:testdata': 'testdata'
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
service.getNodeMetadata('-nodeid-').subscribe((result) => {
|
||||
expect(jasmine.Ajax.requests.mostRecent().url.endsWith('nodes/-nodeid-')).toBeTruthy();
|
||||
const node = new NodeMetadata({
|
||||
test: 'test',
|
||||
testdata: 'testdata'
|
||||
}, 'typeTest');
|
||||
expect(result).toEqual(node);
|
||||
done();
|
||||
});
|
||||
|
||||
jasmine.Ajax.requests.mostRecent().respondWith({
|
||||
status: 200,
|
||||
contentType: 'application/json',
|
||||
responseText: JSON.stringify(responseBody)
|
||||
});
|
||||
});
|
||||
|
||||
it('Should create a node with metadata', (done) => {
|
||||
const data = {
|
||||
test: 'test',
|
||||
testdata: 'testdata'
|
||||
};
|
||||
|
||||
const responseBody = {
|
||||
id: 'a74d91fb-ea8a-4812-ad98-ad878366b5be',
|
||||
isFile: false,
|
||||
isFolder: true
|
||||
};
|
||||
|
||||
service.createNodeMetadata('typeTest', EcmModelService.MODEL_NAMESPACE, data, '/Sites/swsdp/documentLibrary', 'testNode').subscribe(() => {
|
||||
expect(jasmine.Ajax.requests.mostRecent().url.endsWith('-root-/children')).toBeTruthy();
|
||||
done();
|
||||
});
|
||||
|
||||
jasmine.Ajax.requests.mostRecent().respondWith({
|
||||
status: 200,
|
||||
contentType: 'application/json',
|
||||
responseText: JSON.stringify(responseBody)
|
||||
});
|
||||
});
|
||||
|
||||
it('Should add activitiForms suffix to the metadata properties', (done) => {
|
||||
const data = {
|
||||
test: 'test',
|
||||
testdata: 'testdata'
|
||||
};
|
||||
|
||||
service.createNodeMetadata('typeTest', EcmModelService.MODEL_NAMESPACE, data, '/Sites/swsdp/documentLibrary').subscribe(() => {
|
||||
expect(jasmine.Ajax.requests.mostRecent().url.endsWith('-root-/children')).toBeTruthy();
|
||||
expect(JSON.parse(jasmine.Ajax.requests.mostRecent().params).properties[EcmModelService.MODEL_NAMESPACE + ':test']).toBeDefined();
|
||||
expect(JSON.parse(jasmine.Ajax.requests.mostRecent().params).properties[EcmModelService.MODEL_NAMESPACE + ':testdata']).toBeDefined();
|
||||
done();
|
||||
});
|
||||
|
||||
jasmine.Ajax.requests.mostRecent().respondWith({
|
||||
status: 200,
|
||||
contentType: 'application/json',
|
||||
responseText: JSON.stringify({})
|
||||
});
|
||||
});
|
||||
|
||||
it('Should assign an UUID to the name when name not passed', (done) => {
|
||||
const data = {
|
||||
test: 'test',
|
||||
testdata: 'testdata'
|
||||
};
|
||||
|
||||
service.createNodeMetadata('typeTest', EcmModelService.MODEL_NAMESPACE, data, '/Sites/swsdp/documentLibrary').subscribe(() => {
|
||||
expect(jasmine.Ajax.requests.mostRecent().url.endsWith('-root-/children')).toBeTruthy();
|
||||
expect(JSON.parse(jasmine.Ajax.requests.mostRecent().params).name).toBeDefined();
|
||||
done();
|
||||
});
|
||||
|
||||
jasmine.Ajax.requests.mostRecent().respondWith({
|
||||
status: 200,
|
||||
contentType: 'application/json',
|
||||
responseText: JSON.stringify({})
|
||||
});
|
||||
});
|
||||
});
|
@ -1,70 +0,0 @@
|
||||
/*!
|
||||
* @license
|
||||
* Copyright 2019 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 { Injectable } from '@angular/core';
|
||||
import { Observable } from 'rxjs';
|
||||
import { NodeEntry } from '@alfresco/js-api';
|
||||
import { NodeMetadata } from '../../models/node-metadata.model';
|
||||
import { NodesApiService } from '../../services/nodes-api.service';
|
||||
|
||||
@Injectable({
|
||||
providedIn: 'root'
|
||||
})
|
||||
/**
|
||||
* @deprecated in 3.8.0, use NodesApiService instead.
|
||||
*/
|
||||
export class NodeService {
|
||||
|
||||
constructor(private nodesApiService: NodesApiService) {}
|
||||
|
||||
/**
|
||||
* @deprecated in 3.8.0, use NodesApiService instead.
|
||||
* Get the metadata and the nodeType for a nodeId cleaned by the prefix.
|
||||
* @param nodeId ID of the target node
|
||||
* @returns Node metadata
|
||||
*/
|
||||
public getNodeMetadata(nodeId: string): Observable<NodeMetadata> {
|
||||
return this.nodesApiService.getNodeMetadata(nodeId);
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated in 3.8.0, use NodesApiService instead.
|
||||
* Create a new Node from form metadata.
|
||||
* @param path Path to the node
|
||||
* @param nodeType Node type
|
||||
* @param name Node name
|
||||
* @param nameSpace Namespace for properties
|
||||
* @param data Property data to store in the node under namespace
|
||||
* @returns The created node
|
||||
*/
|
||||
public createNodeMetadata(nodeType: string, nameSpace: any, data: any, path: string, name?: string): Observable<NodeEntry> {
|
||||
return this.nodesApiService.createNodeMetadata(nodeType, nameSpace, data, path, name);
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated in 3.8.0, use `createNodeInsideRoot` method from NodesApiService instead.
|
||||
* Create a new Node from form metadata
|
||||
* @param name Node name
|
||||
* @param nodeType Node type
|
||||
* @param properties Node body properties
|
||||
* @param path Path to the node
|
||||
* @returns The created node
|
||||
*/
|
||||
public createNode(name: string, nodeType: string, properties: any, path: string): Observable<NodeEntry> {
|
||||
return this.nodesApiService.createNodeInsideRoot(name, nodeType, properties, path);
|
||||
}
|
||||
}
|
@ -15,7 +15,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { fakeAsync, TestBed } from '@angular/core/testing';
|
||||
import { TestBed } from '@angular/core/testing';
|
||||
import {
|
||||
ContainerModel,
|
||||
FormFieldModel,
|
||||
@ -24,12 +24,11 @@ import {
|
||||
TabModel,
|
||||
FormOutcomeModel
|
||||
} from '../components/widgets/core';
|
||||
import { TaskProcessVariableModel } from '../models/task-process-variable.model';
|
||||
import { WidgetVisibilityModel, WidgetTypeEnum } from '../models/widget-visibility.model';
|
||||
import { WidgetVisibilityService } from './widget-visibility.service';
|
||||
import { setupTestBed } from '../../testing/setup-test-bed';
|
||||
import {
|
||||
fakeFormJson, fakeTaskProcessVariableModels,
|
||||
fakeFormJson,
|
||||
formTest, formValues, complexVisibilityJsonVisible,
|
||||
nextConditionForm, complexVisibilityJsonNotVisible,
|
||||
headerVisibilityCond
|
||||
@ -156,160 +155,6 @@ describe('WidgetVisibilityCloudService', () => {
|
||||
});
|
||||
});
|
||||
|
||||
describe('should retrieve the process variables', () => {
|
||||
const fakeFormWithField = new FormModel(fakeFormJson);
|
||||
let visibilityObjTest: WidgetVisibilityModel;
|
||||
const chainedVisibilityObj = new WidgetVisibilityModel({});
|
||||
|
||||
beforeEach(() => {
|
||||
visibilityObjTest = new WidgetVisibilityModel({});
|
||||
});
|
||||
|
||||
it('should return the process variables for task', (done) => {
|
||||
service.getTaskProcessVariable('9999').subscribe(
|
||||
(res) => {
|
||||
expect(res).toBeDefined();
|
||||
expect(res.length).toEqual(3);
|
||||
expect(res[0].id).toEqual('TEST_VAR_1');
|
||||
expect(res[0].type).toEqual('string');
|
||||
expect(res[0].value).toEqual('test_value_1');
|
||||
done();
|
||||
}
|
||||
);
|
||||
jasmine.Ajax.requests.mostRecent().respondWith({
|
||||
status: 200,
|
||||
contentType: 'json',
|
||||
responseText: fakeTaskProcessVariableModels
|
||||
});
|
||||
});
|
||||
|
||||
it('should be able to retrieve the value of a process variable', (done) => {
|
||||
service.getTaskProcessVariable('9999').subscribe(
|
||||
(res: TaskProcessVariableModel[]) => {
|
||||
expect(res).toBeDefined();
|
||||
const varValue = service.getVariableValue(formTest, 'TEST_VAR_1', res);
|
||||
expect(varValue).not.toBeUndefined();
|
||||
expect(varValue).toBe('test_value_1');
|
||||
done();
|
||||
}
|
||||
);
|
||||
jasmine.Ajax.requests.mostRecent().respondWith({
|
||||
status: 200,
|
||||
contentType: 'json',
|
||||
responseText: fakeTaskProcessVariableModels
|
||||
});
|
||||
});
|
||||
|
||||
it('should return undefined if the variable does not exist', (done) => {
|
||||
service.getTaskProcessVariable('9999').subscribe(
|
||||
(res: TaskProcessVariableModel[]) => {
|
||||
const varValue = service.getVariableValue(formTest, 'TEST_MYSTERY_VAR', res);
|
||||
expect(varValue).toBeUndefined();
|
||||
done();
|
||||
}
|
||||
);
|
||||
jasmine.Ajax.requests.mostRecent().respondWith({
|
||||
status: 200,
|
||||
contentType: 'json',
|
||||
responseText: fakeTaskProcessVariableModels
|
||||
});
|
||||
});
|
||||
|
||||
it('should retrieve the value for the right field when it is a process variable', (done) => {
|
||||
service.getTaskProcessVariable('9999').subscribe(
|
||||
() => {
|
||||
visibilityObjTest.rightValue = 'test_value_2';
|
||||
spyOn(service, 'isFormFieldValid').and.returnValue(true);
|
||||
const rightValue = service.getRightValue(formTest, visibilityObjTest);
|
||||
|
||||
expect(rightValue).not.toBeNull();
|
||||
expect(rightValue).toBe('test_value_2');
|
||||
done();
|
||||
}
|
||||
);
|
||||
jasmine.Ajax.requests.mostRecent().respondWith({
|
||||
status: 200,
|
||||
contentType: 'json',
|
||||
responseText: fakeTaskProcessVariableModels
|
||||
});
|
||||
});
|
||||
|
||||
it('should retrieve the value for the left field when it is a process variable', (done) => {
|
||||
service.getTaskProcessVariable('9999').subscribe(
|
||||
() => {
|
||||
visibilityObjTest.leftValue = 'TEST_VAR_2';
|
||||
visibilityObjTest.leftType = WidgetTypeEnum.field;
|
||||
const leftValue = service.getLeftValue(formTest, visibilityObjTest);
|
||||
|
||||
expect(leftValue).not.toBeNull();
|
||||
expect(leftValue).toBe('test_value_2');
|
||||
done();
|
||||
}
|
||||
);
|
||||
jasmine.Ajax.requests.mostRecent().respondWith({
|
||||
status: 200,
|
||||
contentType: 'json',
|
||||
responseText: fakeTaskProcessVariableModels
|
||||
});
|
||||
});
|
||||
|
||||
it('should evaluate the visibility for the field between form value and process var', (done) => {
|
||||
service.getTaskProcessVariable('9999').subscribe(
|
||||
() => {
|
||||
visibilityObjTest.leftType = 'LEFT_FORM_FIELD_ID';
|
||||
visibilityObjTest.operator = '!=';
|
||||
visibilityObjTest.rightValue = 'TEST_VAR_2';
|
||||
const isVisible = service.isFieldVisible(fakeFormWithField, visibilityObjTest);
|
||||
|
||||
expect(isVisible).toBeTruthy();
|
||||
done();
|
||||
}
|
||||
);
|
||||
jasmine.Ajax.requests.mostRecent().respondWith({
|
||||
status: 200,
|
||||
contentType: 'json',
|
||||
responseText: fakeTaskProcessVariableModels
|
||||
});
|
||||
});
|
||||
|
||||
it('should evaluate visibility with multiple conditions', (done) => {
|
||||
service.getTaskProcessVariable('9999').subscribe(
|
||||
() => {
|
||||
visibilityObjTest.leftType = 'field';
|
||||
visibilityObjTest.leftValue = 'TEST_VAR_2';
|
||||
visibilityObjTest.operator = '!=';
|
||||
visibilityObjTest.rightValue = 'TEST_VAR_2';
|
||||
visibilityObjTest.nextConditionOperator = 'and';
|
||||
chainedVisibilityObj.leftType = 'field';
|
||||
chainedVisibilityObj.leftValue = 'TEST_VAR_2';
|
||||
chainedVisibilityObj.operator = '!empty';
|
||||
visibilityObjTest.nextCondition = chainedVisibilityObj;
|
||||
|
||||
const isVisible = service.isFieldVisible(fakeFormWithField, visibilityObjTest);
|
||||
|
||||
expect(isVisible).toBeTruthy();
|
||||
done();
|
||||
}
|
||||
);
|
||||
jasmine.Ajax.requests.mostRecent().respondWith({
|
||||
status: 200,
|
||||
contentType: 'json',
|
||||
responseText: fakeTaskProcessVariableModels
|
||||
});
|
||||
});
|
||||
|
||||
it('should catch error on 403 response', fakeAsync(() => {
|
||||
service.getTaskProcessVariable('9999').subscribe(() => {
|
||||
}, (errorMessage) => {
|
||||
expect(errorMessage).toEqual('Error while performing a call - Server error');
|
||||
});
|
||||
|
||||
jasmine.Ajax.requests.mostRecent().respondWith({
|
||||
status: 403
|
||||
});
|
||||
}));
|
||||
});
|
||||
|
||||
describe('should return the value of the field', () => {
|
||||
let visibilityObjTest: WidgetVisibilityModel;
|
||||
let fakeFormWithField = new FormModel(fakeFormJson);
|
||||
@ -644,143 +489,6 @@ describe('WidgetVisibilityCloudService', () => {
|
||||
expect(fakeFormWithField.outcomes[outcomeIndex].isVisible).toBeFalsy();
|
||||
});
|
||||
|
||||
it('should use the form value to evaluate the visibility condition if the form value is defined', (done) => {
|
||||
service.getTaskProcessVariable('9999').subscribe(
|
||||
(res: TaskProcessVariableModel[]) => {
|
||||
expect(res).toBeDefined();
|
||||
const varValue = service.getVariableValue(formTest, 'FIELD_FORM_EMPTY', res);
|
||||
expect(varValue).not.toBeUndefined();
|
||||
expect(varValue).toBe('PROCESS_RIGHT_FORM_FIELD_VALUE');
|
||||
|
||||
visibilityObjTest.leftType = WidgetTypeEnum.field;
|
||||
visibilityObjTest.leftValue = 'FIELD_FORM_EMPTY';
|
||||
visibilityObjTest.operator = '==';
|
||||
visibilityObjTest.rightValue = 'RIGHT_FORM_FIELD_VALUE';
|
||||
|
||||
const myForm = new FormModel({
|
||||
id: '9999',
|
||||
name: 'FORM_PROCESS_VARIABLE_VISIBILITY',
|
||||
processDefinitionId: 'PROCESS_TEST:9:9999',
|
||||
processDefinitionName: 'PROCESS_TEST',
|
||||
processDefinitionKey: 'PROCESS_TEST',
|
||||
taskId: '999',
|
||||
taskName: 'TEST',
|
||||
fields: [
|
||||
{
|
||||
fieldType: 'ContainerRepresentation',
|
||||
id: '000000000000000000',
|
||||
name: 'Label',
|
||||
type: 'container',
|
||||
value: null,
|
||||
numberOfColumns: 2,
|
||||
fields: {
|
||||
1: [
|
||||
{
|
||||
fieldType: 'FormFieldRepresentation',
|
||||
id: 'FIELD_FORM_EMPTY',
|
||||
name: 'FIELD_FORM_EMPTY',
|
||||
type: 'text',
|
||||
value: 'RIGHT_FORM_FIELD_VALUE',
|
||||
visibilityCondition: null,
|
||||
isVisible: true
|
||||
},
|
||||
{
|
||||
fieldType: 'FormFieldRepresentation',
|
||||
id: 'FIELD_FORM_WITH_CONDITION',
|
||||
name: 'FIELD_FORM_WITH_CONDITION',
|
||||
type: 'text',
|
||||
value: 'field_form_with_condition_value',
|
||||
visibilityCondition: visibilityObjTest,
|
||||
isVisible: false
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
]
|
||||
});
|
||||
|
||||
service.refreshVisibility(myForm);
|
||||
|
||||
const fieldWithVisibilityAttached = myForm.getFieldById('FIELD_FORM_WITH_CONDITION');
|
||||
expect(fieldWithVisibilityAttached.isVisible).toBeTruthy();
|
||||
done();
|
||||
}
|
||||
);
|
||||
jasmine.Ajax.requests.mostRecent().respondWith({
|
||||
status: 200,
|
||||
contentType: 'json',
|
||||
responseText: [{ id: 'FIELD_FORM_EMPTY', type: 'string', value: 'PROCESS_RIGHT_FORM_FIELD_VALUE' }]
|
||||
});
|
||||
});
|
||||
|
||||
it('should use the process value to evaluate the True visibility condition if the form value is empty', (done) => {
|
||||
|
||||
service.getTaskProcessVariable('9999').subscribe(
|
||||
(res: TaskProcessVariableModel[]) => {
|
||||
expect(res).toBeDefined();
|
||||
|
||||
visibilityObjTest.leftType = WidgetTypeEnum.field;
|
||||
visibilityObjTest.leftValue = 'FIELD_FORM_EMPTY';
|
||||
visibilityObjTest.operator = '==';
|
||||
visibilityObjTest.rightType = WidgetTypeEnum.value;
|
||||
visibilityObjTest.rightValue = 'PROCESS_RIGHT_FORM_FIELD_VALUE';
|
||||
|
||||
const myForm = new FormModel({
|
||||
id: '9999',
|
||||
name: 'FORM_PROCESS_VARIABLE_VISIBILITY',
|
||||
processDefinitionId: 'PROCESS_TEST:9:9999',
|
||||
processDefinitionName: 'PROCESS_TEST',
|
||||
processDefinitionKey: 'PROCESS_TEST',
|
||||
taskId: '999',
|
||||
taskName: 'TEST',
|
||||
fields: [
|
||||
{
|
||||
fieldType: 'ContainerRepresentation',
|
||||
id: '000000000000000000',
|
||||
name: 'Label',
|
||||
type: 'container',
|
||||
value: null,
|
||||
numberOfColumns: 2,
|
||||
fields: {
|
||||
1: [
|
||||
{
|
||||
fieldType: 'FormFieldRepresentation',
|
||||
id: 'FIELD_FORM_EMPTY',
|
||||
name: 'FIELD_FORM_EMPTY',
|
||||
type: 'text',
|
||||
value: '',
|
||||
visibilityCondition: null,
|
||||
isVisible: true
|
||||
},
|
||||
{
|
||||
fieldType: 'FormFieldRepresentation',
|
||||
id: 'FIELD_FORM_WITH_CONDITION',
|
||||
name: 'FIELD_FORM_WITH_CONDITION',
|
||||
type: 'text',
|
||||
value: 'field_form_with_condition_value',
|
||||
visibilityCondition: visibilityObjTest,
|
||||
isVisible: false
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
]
|
||||
});
|
||||
|
||||
service.refreshVisibility(myForm);
|
||||
|
||||
const fieldWithVisibilityAttached = myForm.getFieldById('FIELD_FORM_WITH_CONDITION');
|
||||
expect(fieldWithVisibilityAttached.isVisible).toBeTruthy();
|
||||
done();
|
||||
}
|
||||
);
|
||||
jasmine.Ajax.requests.mostRecent().respondWith({
|
||||
status: 200,
|
||||
contentType: 'json',
|
||||
responseText: [{ id: 'FIELD_FORM_EMPTY', type: 'string', value: 'PROCESS_RIGHT_FORM_FIELD_VALUE' }]
|
||||
});
|
||||
});
|
||||
|
||||
it('should use the process variables when they are passed to check the visibility', () => {
|
||||
|
||||
visibilityObjTest.leftType = WidgetTypeEnum.field;
|
||||
@ -837,72 +545,6 @@ describe('WidgetVisibilityCloudService', () => {
|
||||
expect(fieldWithVisibilityAttached.isVisible).toBeTruthy();
|
||||
});
|
||||
|
||||
it('should use the process value to evaluate the False visibility condition if the form value is empty', (done) => {
|
||||
|
||||
service.getTaskProcessVariable('9999').subscribe(
|
||||
(res: TaskProcessVariableModel[]) => {
|
||||
expect(res).toBeDefined();
|
||||
|
||||
visibilityObjTest.leftType = 'FIELD_FORM_EMPTY';
|
||||
visibilityObjTest.operator = '==';
|
||||
visibilityObjTest.rightValue = 'RIGHT_FORM_FIELD_VALUE';
|
||||
|
||||
const myForm = new FormModel({
|
||||
id: '9999',
|
||||
name: 'FORM_PROCESS_VARIABLE_VISIBILITY',
|
||||
processDefinitionId: 'PROCESS_TEST:9:9999',
|
||||
processDefinitionName: 'PROCESS_TEST',
|
||||
processDefinitionKey: 'PROCESS_TEST',
|
||||
taskId: '999',
|
||||
taskName: 'TEST',
|
||||
fields: [
|
||||
{
|
||||
fieldType: 'ContainerRepresentation',
|
||||
id: '000000000000000000',
|
||||
name: 'Label',
|
||||
type: 'container',
|
||||
value: null,
|
||||
numberOfColumns: 2,
|
||||
fields: {
|
||||
1: [
|
||||
{
|
||||
fieldType: 'FormFieldRepresentation',
|
||||
id: 'FIELD_FORM_EMPTY',
|
||||
name: 'FIELD_FORM_EMPTY',
|
||||
type: 'text',
|
||||
value: '',
|
||||
visibilityCondition: null,
|
||||
isVisible: true
|
||||
},
|
||||
{
|
||||
fieldType: 'FormFieldRepresentation',
|
||||
id: 'FIELD_FORM_WITH_CONDITION',
|
||||
name: 'FIELD_FORM_WITH_CONDITION',
|
||||
type: 'text',
|
||||
value: 'field_form_with_condition_value',
|
||||
visibilityCondition: visibilityObjTest,
|
||||
isVisible: true
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
]
|
||||
});
|
||||
|
||||
service.refreshVisibility(myForm);
|
||||
|
||||
const fieldWithVisibilityAttached = myForm.getFieldById('FIELD_FORM_WITH_CONDITION');
|
||||
expect(fieldWithVisibilityAttached.isVisible).toBeFalsy();
|
||||
done();
|
||||
}
|
||||
);
|
||||
jasmine.Ajax.requests.mostRecent().respondWith({
|
||||
status: 200,
|
||||
contentType: 'json',
|
||||
responseText: [{ id: 'FIELD_FORM_EMPTY', type: 'string', value: 'PROCESS_RIGHT_FORM_FIELD_VALUE' }]
|
||||
});
|
||||
});
|
||||
|
||||
it('should refresh the visibility for single tab', () => {
|
||||
visibilityObjTest.leftType = WidgetTypeEnum.field;
|
||||
visibilityObjTest.leftValue = 'FIELD_TEST';
|
||||
|
@ -15,7 +15,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { fakeAsync, TestBed } from '@angular/core/testing';
|
||||
import { TestBed } from '@angular/core/testing';
|
||||
import {
|
||||
ContainerModel,
|
||||
FormFieldModel,
|
||||
@ -23,12 +23,10 @@ import {
|
||||
FormModel,
|
||||
TabModel
|
||||
} from '../components/widgets/core';
|
||||
import { TaskProcessVariableModel } from '../models/task-process-variable.model';
|
||||
import { WidgetVisibilityModel } from '../models/widget-visibility.model';
|
||||
import { WidgetVisibilityService } from './widget-visibility.service';
|
||||
import { setupTestBed } from '../../testing/setup-test-bed';
|
||||
import {
|
||||
fakeTaskProcessVariableModels,
|
||||
fakeFormJson, formTest,
|
||||
formValues, complexVisibilityJsonVisible,
|
||||
complexVisibilityJsonNotVisible, tabVisibilityJsonMock,
|
||||
@ -39,8 +37,6 @@ import {
|
||||
import { CoreTestingModule } from '../../testing/core.testing.module';
|
||||
import { TranslateModule } from '@ngx-translate/core';
|
||||
|
||||
declare let jasmine: any;
|
||||
|
||||
describe('WidgetVisibilityService', () => {
|
||||
|
||||
let service: WidgetVisibilityService;
|
||||
@ -56,11 +52,6 @@ describe('WidgetVisibilityService', () => {
|
||||
|
||||
beforeEach(() => {
|
||||
service = TestBed.inject(WidgetVisibilityService);
|
||||
jasmine.Ajax.install();
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
jasmine.Ajax.uninstall();
|
||||
});
|
||||
|
||||
describe('should be able to evaluate next condition operations', () => {
|
||||
@ -161,158 +152,6 @@ describe('WidgetVisibilityService', () => {
|
||||
});
|
||||
});
|
||||
|
||||
describe('should retrieve the process variables', () => {
|
||||
let fakeFormWithField: FormModel;
|
||||
let visibilityObjTest: WidgetVisibilityModel;
|
||||
const chainedVisibilityObj = new WidgetVisibilityModel({});
|
||||
|
||||
beforeEach(() => {
|
||||
fakeFormWithField = new FormModel(fakeFormJson);
|
||||
visibilityObjTest = new WidgetVisibilityModel({});
|
||||
fakeFormWithField = new FormModel(fakeFormJson);
|
||||
});
|
||||
|
||||
it('should return the process variables for task', (done) => {
|
||||
service.getTaskProcessVariable('9999').subscribe(
|
||||
(res) => {
|
||||
expect(res).toBeDefined();
|
||||
expect(res.length).toEqual(3);
|
||||
expect(res[0].id).toEqual('TEST_VAR_1');
|
||||
expect(res[0].type).toEqual('string');
|
||||
expect(res[0].value).toEqual('test_value_1');
|
||||
done();
|
||||
}
|
||||
);
|
||||
jasmine.Ajax.requests.mostRecent().respondWith({
|
||||
status: 200,
|
||||
contentType: 'json',
|
||||
responseText: fakeTaskProcessVariableModels
|
||||
});
|
||||
});
|
||||
|
||||
it('should be able to retrieve the value of a process variable', (done) => {
|
||||
service.getTaskProcessVariable('9999').subscribe(
|
||||
(res: TaskProcessVariableModel[]) => {
|
||||
expect(res).toBeDefined();
|
||||
const varValue = service.getVariableValue(formTest, 'TEST_VAR_1', res);
|
||||
expect(varValue).not.toBeUndefined();
|
||||
expect(varValue).toBe('test_value_1');
|
||||
done();
|
||||
}
|
||||
);
|
||||
jasmine.Ajax.requests.mostRecent().respondWith({
|
||||
status: 200,
|
||||
contentType: 'json',
|
||||
responseText: fakeTaskProcessVariableModels
|
||||
});
|
||||
});
|
||||
|
||||
it('should return undefined if the variable does not exist', (done) => {
|
||||
service.getTaskProcessVariable('9999').subscribe(
|
||||
(res: TaskProcessVariableModel[]) => {
|
||||
const varValue = service.getVariableValue(formTest, 'TEST_MYSTERY_VAR', res);
|
||||
expect(varValue).toBeUndefined();
|
||||
done();
|
||||
}
|
||||
);
|
||||
jasmine.Ajax.requests.mostRecent().respondWith({
|
||||
status: 200,
|
||||
contentType: 'json',
|
||||
responseText: fakeTaskProcessVariableModels
|
||||
});
|
||||
});
|
||||
|
||||
it('should retrieve the value for the right field when it is a process variable', (done) => {
|
||||
service.getTaskProcessVariable('9999').subscribe(
|
||||
() => {
|
||||
visibilityObjTest.rightRestResponseId = 'TEST_VAR_2';
|
||||
const rightValue = service.getRightValue(formTest, visibilityObjTest);
|
||||
|
||||
expect(rightValue).not.toBeNull();
|
||||
expect(rightValue).toBe('test_value_2');
|
||||
done();
|
||||
}
|
||||
);
|
||||
jasmine.Ajax.requests.mostRecent().respondWith({
|
||||
status: 200,
|
||||
contentType: 'json',
|
||||
responseText: fakeTaskProcessVariableModels
|
||||
});
|
||||
});
|
||||
|
||||
it('should retrieve the value for the left field when it is a process variable', (done) => {
|
||||
service.getTaskProcessVariable('9999').subscribe(
|
||||
() => {
|
||||
visibilityObjTest.leftRestResponseId = 'TEST_VAR_2';
|
||||
const leftValue = service.getLeftValue(formTest, visibilityObjTest);
|
||||
|
||||
expect(leftValue).not.toBeNull();
|
||||
expect(leftValue).toBe('test_value_2');
|
||||
done();
|
||||
}
|
||||
);
|
||||
jasmine.Ajax.requests.mostRecent().respondWith({
|
||||
status: 200,
|
||||
contentType: 'json',
|
||||
responseText: fakeTaskProcessVariableModels
|
||||
});
|
||||
});
|
||||
|
||||
it('should evaluate the visibility for the field between form value and process var', (done) => {
|
||||
service.getTaskProcessVariable('9999').subscribe(
|
||||
() => {
|
||||
visibilityObjTest.leftFormFieldId = 'LEFT_FORM_FIELD_ID';
|
||||
visibilityObjTest.operator = '!=';
|
||||
visibilityObjTest.rightRestResponseId = 'TEST_VAR_2';
|
||||
const isVisible = service.isFieldVisible(fakeFormWithField, new WidgetVisibilityModel(visibilityObjTest));
|
||||
|
||||
expect(isVisible).toBeTruthy();
|
||||
done();
|
||||
}
|
||||
);
|
||||
jasmine.Ajax.requests.mostRecent().respondWith({
|
||||
status: 200,
|
||||
contentType: 'json',
|
||||
responseText: fakeTaskProcessVariableModels
|
||||
});
|
||||
});
|
||||
|
||||
it('should evaluate visibility with multiple conditions', (done) => {
|
||||
service.getTaskProcessVariable('9999').subscribe(
|
||||
() => {
|
||||
visibilityObjTest.leftFormFieldId = 'LEFT_FORM_FIELD_ID';
|
||||
visibilityObjTest.operator = '!=';
|
||||
visibilityObjTest.rightRestResponseId = 'TEST_VAR_2';
|
||||
visibilityObjTest.nextConditionOperator = 'and';
|
||||
chainedVisibilityObj.leftRestResponseId = 'TEST_VAR_2';
|
||||
chainedVisibilityObj.operator = '!empty';
|
||||
visibilityObjTest.nextCondition = chainedVisibilityObj;
|
||||
|
||||
const isVisible = service.isFieldVisible(fakeFormWithField, visibilityObjTest);
|
||||
|
||||
expect(isVisible).toBeTruthy();
|
||||
done();
|
||||
}
|
||||
);
|
||||
jasmine.Ajax.requests.mostRecent().respondWith({
|
||||
status: 200,
|
||||
contentType: 'json',
|
||||
responseText: fakeTaskProcessVariableModels
|
||||
});
|
||||
});
|
||||
|
||||
it('should catch error on 403 response', fakeAsync(() => {
|
||||
service.getTaskProcessVariable('9999').subscribe(() => {
|
||||
}, (errorMessage) => {
|
||||
expect(errorMessage).toEqual('Error while performing a call - Server error');
|
||||
});
|
||||
|
||||
jasmine.Ajax.requests.mostRecent().respondWith({
|
||||
status: 403
|
||||
});
|
||||
}));
|
||||
});
|
||||
|
||||
describe('should return the value of the field', () => {
|
||||
let visibilityObjTest: WidgetVisibilityModel;
|
||||
let fakeFormWithField: FormModel;
|
||||
@ -650,206 +489,6 @@ describe('WidgetVisibilityService', () => {
|
||||
expect(fakeFormWithField.tabs[0].isVisible).toBeFalsy();
|
||||
});
|
||||
|
||||
it('should use the form value to evaluate the visibility condition if the form value is defined', (done) => {
|
||||
service.getTaskProcessVariable('9999').subscribe(
|
||||
(res: TaskProcessVariableModel[]) => {
|
||||
expect(res).toBeDefined();
|
||||
const varValue = service.getVariableValue(formTest, 'FIELD_FORM_EMPTY', res);
|
||||
expect(varValue).not.toBeUndefined();
|
||||
expect(varValue).toBe('PROCESS_RIGHT_FORM_FIELD_VALUE');
|
||||
|
||||
visibilityObjTest.leftFormFieldId = 'FIELD_FORM_EMPTY';
|
||||
visibilityObjTest.operator = '==';
|
||||
visibilityObjTest.rightValue = 'RIGHT_FORM_FIELD_VALUE';
|
||||
|
||||
const myForm = new FormModel({
|
||||
id: '9999',
|
||||
name: 'FORM_PROCESS_VARIABLE_VISIBILITY',
|
||||
processDefinitionId: 'PROCESS_TEST:9:9999',
|
||||
processDefinitionName: 'PROCESS_TEST',
|
||||
processDefinitionKey: 'PROCESS_TEST',
|
||||
taskId: '999',
|
||||
taskName: 'TEST',
|
||||
fields: [
|
||||
{
|
||||
fieldType: 'ContainerRepresentation',
|
||||
id: '000000000000000000',
|
||||
name: 'Label',
|
||||
type: 'container',
|
||||
value: null,
|
||||
numberOfColumns: 2,
|
||||
fields: {
|
||||
1: [
|
||||
{
|
||||
fieldType: 'FormFieldRepresentation',
|
||||
id: 'FIELD_FORM_EMPTY',
|
||||
name: 'FIELD_FORM_EMPTY',
|
||||
type: 'text',
|
||||
value: 'RIGHT_FORM_FIELD_VALUE',
|
||||
visibilityCondition: null,
|
||||
isVisible: true
|
||||
},
|
||||
{
|
||||
fieldType: 'FormFieldRepresentation',
|
||||
id: 'FIELD_FORM_WITH_CONDITION',
|
||||
name: 'FIELD_FORM_WITH_CONDITION',
|
||||
type: 'text',
|
||||
value: 'field_form_with_condition_value',
|
||||
visibilityCondition: visibilityObjTest,
|
||||
isVisible: false
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
]
|
||||
});
|
||||
|
||||
service.refreshVisibility(myForm);
|
||||
|
||||
const fieldWithVisibilityAttached = myForm.getFieldById('FIELD_FORM_WITH_CONDITION');
|
||||
expect(fieldWithVisibilityAttached.isVisible).toBeTruthy();
|
||||
done();
|
||||
}
|
||||
);
|
||||
jasmine.Ajax.requests.mostRecent().respondWith({
|
||||
status: 200,
|
||||
contentType: 'json',
|
||||
responseText: [{ id: 'FIELD_FORM_EMPTY', type: 'string', value: 'PROCESS_RIGHT_FORM_FIELD_VALUE' }]
|
||||
});
|
||||
});
|
||||
|
||||
it('should use the process value to evaluate the True visibility condition if the form value is empty', (done) => {
|
||||
|
||||
service.getTaskProcessVariable('9999').subscribe(
|
||||
(res: TaskProcessVariableModel[]) => {
|
||||
expect(res).toBeDefined();
|
||||
|
||||
visibilityObjTest.leftFormFieldId = 'FIELD_FORM_EMPTY';
|
||||
visibilityObjTest.operator = '==';
|
||||
visibilityObjTest.rightValue = 'PROCESS_RIGHT_FORM_FIELD_VALUE';
|
||||
|
||||
const myForm = new FormModel({
|
||||
id: '9999',
|
||||
name: 'FORM_PROCESS_VARIABLE_VISIBILITY',
|
||||
processDefinitionId: 'PROCESS_TEST:9:9999',
|
||||
processDefinitionName: 'PROCESS_TEST',
|
||||
processDefinitionKey: 'PROCESS_TEST',
|
||||
taskId: '999',
|
||||
taskName: 'TEST',
|
||||
fields: [
|
||||
{
|
||||
fieldType: 'ContainerRepresentation',
|
||||
id: '000000000000000000',
|
||||
name: 'Label',
|
||||
type: 'container',
|
||||
value: null,
|
||||
numberOfColumns: 2,
|
||||
fields: {
|
||||
1: [
|
||||
{
|
||||
fieldType: 'FormFieldRepresentation',
|
||||
id: 'FIELD_FORM_EMPTY',
|
||||
name: 'FIELD_FORM_EMPTY',
|
||||
type: 'text',
|
||||
value: '',
|
||||
visibilityCondition: null,
|
||||
isVisible: true
|
||||
},
|
||||
{
|
||||
fieldType: 'FormFieldRepresentation',
|
||||
id: 'FIELD_FORM_WITH_CONDITION',
|
||||
name: 'FIELD_FORM_WITH_CONDITION',
|
||||
type: 'text',
|
||||
value: 'field_form_with_condition_value',
|
||||
visibilityCondition: visibilityObjTest,
|
||||
isVisible: false
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
]
|
||||
});
|
||||
|
||||
service.refreshVisibility(myForm);
|
||||
|
||||
const fieldWithVisibilityAttached = myForm.getFieldById('FIELD_FORM_WITH_CONDITION');
|
||||
expect(fieldWithVisibilityAttached.isVisible).toBeTruthy();
|
||||
done();
|
||||
}
|
||||
);
|
||||
jasmine.Ajax.requests.mostRecent().respondWith({
|
||||
status: 200,
|
||||
contentType: 'json',
|
||||
responseText: [{ id: 'FIELD_FORM_EMPTY', type: 'string', value: 'PROCESS_RIGHT_FORM_FIELD_VALUE' }]
|
||||
});
|
||||
});
|
||||
|
||||
it('should use the process value to evaluate the False visibility condition if the form value is empty', (done) => {
|
||||
|
||||
service.getTaskProcessVariable('9999').subscribe(
|
||||
(res: TaskProcessVariableModel[]) => {
|
||||
expect(res).toBeDefined();
|
||||
|
||||
visibilityObjTest.leftFormFieldId = 'FIELD_FORM_EMPTY';
|
||||
visibilityObjTest.operator = '==';
|
||||
visibilityObjTest.rightValue = 'RIGHT_FORM_FIELD_VALUE';
|
||||
|
||||
const myForm = new FormModel({
|
||||
id: '9999',
|
||||
name: 'FORM_PROCESS_VARIABLE_VISIBILITY',
|
||||
processDefinitionId: 'PROCESS_TEST:9:9999',
|
||||
processDefinitionName: 'PROCESS_TEST',
|
||||
processDefinitionKey: 'PROCESS_TEST',
|
||||
taskId: '999',
|
||||
taskName: 'TEST',
|
||||
fields: [
|
||||
{
|
||||
fieldType: 'ContainerRepresentation',
|
||||
id: '000000000000000000',
|
||||
name: 'Label',
|
||||
type: 'container',
|
||||
value: null,
|
||||
numberOfColumns: 2,
|
||||
fields: {
|
||||
1: [
|
||||
{
|
||||
fieldType: 'FormFieldRepresentation',
|
||||
id: 'FIELD_FORM_EMPTY',
|
||||
name: 'FIELD_FORM_EMPTY',
|
||||
type: 'text',
|
||||
value: '',
|
||||
visibilityCondition: null,
|
||||
isVisible: true
|
||||
},
|
||||
{
|
||||
fieldType: 'FormFieldRepresentation',
|
||||
id: 'FIELD_FORM_WITH_CONDITION',
|
||||
name: 'FIELD_FORM_WITH_CONDITION',
|
||||
type: 'text',
|
||||
value: 'field_form_with_condition_value',
|
||||
visibilityCondition: visibilityObjTest,
|
||||
isVisible: true
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
]
|
||||
});
|
||||
|
||||
service.refreshVisibility(myForm);
|
||||
|
||||
const fieldWithVisibilityAttached = myForm.getFieldById('FIELD_FORM_WITH_CONDITION');
|
||||
expect(fieldWithVisibilityAttached.isVisible).toBeFalsy();
|
||||
done();
|
||||
}
|
||||
);
|
||||
jasmine.Ajax.requests.mostRecent().respondWith({
|
||||
status: 200,
|
||||
contentType: 'json',
|
||||
responseText: [{ id: 'FIELD_FORM_EMPTY', type: 'string', value: 'PROCESS_RIGHT_FORM_FIELD_VALUE' }]
|
||||
});
|
||||
});
|
||||
|
||||
it('should refresh the visibility for single tab', () => {
|
||||
visibilityObjTest.leftFormFieldId = 'FIELD_TEST';
|
||||
visibilityObjTest.operator = '!=';
|
||||
|
@ -15,11 +15,9 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { AlfrescoApiService } from '../../services/alfresco-api.service';
|
||||
import { LogService } from '../../services/log.service';
|
||||
import { Injectable } from '@angular/core';
|
||||
import moment from 'moment';
|
||||
import { Observable, from, throwError } from 'rxjs';
|
||||
import {
|
||||
FormFieldModel,
|
||||
FormModel,
|
||||
@ -29,25 +27,16 @@ import {
|
||||
} from '../components/widgets/core';
|
||||
import { TaskProcessVariableModel } from '../models/task-process-variable.model';
|
||||
import { WidgetVisibilityModel, WidgetTypeEnum } from '../models/widget-visibility.model';
|
||||
import { map, catchError } from 'rxjs/operators';
|
||||
import { TaskFormsApi } from '@alfresco/js-api';
|
||||
|
||||
@Injectable({
|
||||
providedIn: 'root'
|
||||
})
|
||||
export class WidgetVisibilityService {
|
||||
|
||||
_taskFormsApi: TaskFormsApi;
|
||||
get taskFormsApi(): TaskFormsApi {
|
||||
this._taskFormsApi = this._taskFormsApi ?? new TaskFormsApi(this.apiService.getInstance());
|
||||
return this._taskFormsApi;
|
||||
}
|
||||
|
||||
private processVarList: TaskProcessVariableModel[];
|
||||
private form: FormModel;
|
||||
|
||||
constructor(private apiService: AlfrescoApiService,
|
||||
private logService: LogService) {
|
||||
constructor(private logService: LogService) {
|
||||
}
|
||||
|
||||
public refreshVisibility(form: FormModel, processVarList?: TaskProcessVariableModel[]) {
|
||||
@ -68,15 +57,15 @@ export class WidgetVisibilityService {
|
||||
}
|
||||
}
|
||||
|
||||
refreshEntityVisibility(element: FormFieldModel | TabModel) {
|
||||
public refreshEntityVisibility(element: FormFieldModel | TabModel) {
|
||||
element.isVisible = this.isParentTabVisible(this.form, element) && this.evaluateVisibility(element.form, element.visibilityCondition);
|
||||
}
|
||||
|
||||
refreshOutcomeVisibility(element: FormOutcomeModel) {
|
||||
private refreshOutcomeVisibility(element: FormOutcomeModel) {
|
||||
element.isVisible = this.evaluateVisibility(element.form, element.visibilityCondition);
|
||||
}
|
||||
|
||||
evaluateVisibility(form: FormModel, visibilityObj: WidgetVisibilityModel): boolean {
|
||||
public evaluateVisibility(form: FormModel, visibilityObj: WidgetVisibilityModel): boolean {
|
||||
const isLeftFieldPresent = visibilityObj && (visibilityObj.leftType || visibilityObj.leftValue);
|
||||
if (!isLeftFieldPresent || isLeftFieldPresent === 'null') {
|
||||
return true;
|
||||
@ -85,12 +74,12 @@ export class WidgetVisibilityService {
|
||||
}
|
||||
}
|
||||
|
||||
isFieldVisible(form: FormModel, visibilityObj: WidgetVisibilityModel, accumulator: any[] = [], result: boolean = false): boolean {
|
||||
public isFieldVisible(form: FormModel, visibilityObj: WidgetVisibilityModel, accumulator: any[] = [], result: boolean = false): boolean {
|
||||
const leftValue = this.getLeftValue(form, visibilityObj);
|
||||
const rightValue = this.getRightValue(form, visibilityObj);
|
||||
const actualResult = this.evaluateCondition(leftValue, rightValue, visibilityObj.operator);
|
||||
|
||||
accumulator.push({ value: actualResult, operator: visibilityObj.nextConditionOperator });
|
||||
accumulator.push({value: actualResult, operator: visibilityObj.nextConditionOperator});
|
||||
|
||||
if (this.isValidCondition(visibilityObj.nextCondition)) {
|
||||
result = this.isFieldVisible(form, visibilityObj.nextCondition, accumulator);
|
||||
@ -124,7 +113,7 @@ export class WidgetVisibilityService {
|
||||
}
|
||||
}
|
||||
|
||||
getLeftValue(form: FormModel, visibilityObj: WidgetVisibilityModel): string {
|
||||
public getLeftValue(form: FormModel, visibilityObj: WidgetVisibilityModel): string {
|
||||
let leftValue = '';
|
||||
if (visibilityObj.leftType && visibilityObj.leftType === WidgetTypeEnum.variable) {
|
||||
leftValue = this.getVariableValue(form, visibilityObj.leftValue, this.processVarList);
|
||||
@ -138,7 +127,7 @@ export class WidgetVisibilityService {
|
||||
return leftValue;
|
||||
}
|
||||
|
||||
getRightValue(form: FormModel, visibilityObj: WidgetVisibilityModel): string {
|
||||
public getRightValue(form: FormModel, visibilityObj: WidgetVisibilityModel): string {
|
||||
let valueFound = '';
|
||||
if (visibilityObj.rightType === WidgetTypeEnum.variable) {
|
||||
valueFound = this.getVariableValue(form, visibilityObj.rightValue, this.processVarList);
|
||||
@ -154,7 +143,7 @@ export class WidgetVisibilityService {
|
||||
return valueFound;
|
||||
}
|
||||
|
||||
getFormValue(form: FormModel, fieldId: string): any {
|
||||
public getFormValue(form: FormModel, fieldId: string): any {
|
||||
const formField = this.getFormFieldById(form, fieldId);
|
||||
let value;
|
||||
|
||||
@ -168,18 +157,18 @@ export class WidgetVisibilityService {
|
||||
return value;
|
||||
}
|
||||
|
||||
isFormFieldValid(formField: FormFieldModel): boolean {
|
||||
public isFormFieldValid(formField: FormFieldModel): boolean {
|
||||
return formField && formField.isValid;
|
||||
}
|
||||
|
||||
getFieldValue(valueList: any, fieldId: string): any {
|
||||
public getFieldValue(valueList: any, fieldId: string): any {
|
||||
let labelFilterByName;
|
||||
let valueFound;
|
||||
if (fieldId && fieldId.indexOf('_LABEL') > 0) {
|
||||
labelFilterByName = fieldId.substring(0, fieldId.length - 6);
|
||||
if (valueList[labelFilterByName]) {
|
||||
if (Array.isArray(valueList[labelFilterByName])) {
|
||||
valueFound = valueList[labelFilterByName].map(({ name }) => name);
|
||||
valueFound = valueList[labelFilterByName].map(({name}) => name);
|
||||
} else {
|
||||
valueFound = valueList[labelFilterByName].name;
|
||||
}
|
||||
@ -187,7 +176,7 @@ export class WidgetVisibilityService {
|
||||
} else if (valueList[fieldId] && valueList[fieldId].id) {
|
||||
valueFound = valueList[fieldId].id;
|
||||
} else if (valueList[fieldId] && Array.isArray(valueList[fieldId])) {
|
||||
valueFound = valueList[fieldId].map(({ id }) => id);
|
||||
valueFound = valueList[fieldId].map(({id}) => id);
|
||||
} else {
|
||||
valueFound = valueList[fieldId];
|
||||
}
|
||||
@ -198,11 +187,11 @@ export class WidgetVisibilityService {
|
||||
return value === undefined || value === null;
|
||||
}
|
||||
|
||||
getFormFieldById(form: FormModel, fieldId: string): FormFieldModel {
|
||||
public getFormFieldById(form: FormModel, fieldId: string): FormFieldModel {
|
||||
return form.getFormFields().find((formField: FormFieldModel) => this.isSearchedField(formField, fieldId));
|
||||
}
|
||||
|
||||
searchValueInForm(formField: FormFieldModel, fieldId: string): string {
|
||||
public searchValueInForm(formField: FormFieldModel, fieldId: string): string {
|
||||
let fieldValue = '';
|
||||
|
||||
if (formField) {
|
||||
@ -219,7 +208,7 @@ export class WidgetVisibilityService {
|
||||
return fieldValue;
|
||||
}
|
||||
|
||||
isParentTabVisible(form: FormModel, currentFormField: FormFieldModel | TabModel): boolean {
|
||||
private isParentTabVisible(form: FormModel, currentFormField: FormFieldModel | TabModel): boolean {
|
||||
const containers = this.getFormTabContainers(form);
|
||||
let isVisible: boolean = true;
|
||||
containers.map((container: ContainerModel) => {
|
||||
@ -281,7 +270,7 @@ export class WidgetVisibilityService {
|
||||
return (field.id && fieldToFind) ? field.id.toUpperCase() === fieldToFind.toUpperCase() : false;
|
||||
}
|
||||
|
||||
getVariableValue(form: FormModel, name: string, processVarList: TaskProcessVariableModel[]): string {
|
||||
public getVariableValue(form: FormModel, name: string, processVarList: TaskProcessVariableModel[]): string {
|
||||
const processVariableValue = this.getProcessVariableValue(name, processVarList);
|
||||
const variableDefaultValue = form.getDefaultFormVariableValue(name);
|
||||
|
||||
@ -303,7 +292,7 @@ export class WidgetVisibilityService {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
evaluateCondition(leftValue: any, rightValue: any, operator: string): boolean | undefined {
|
||||
public evaluateCondition(leftValue: any, rightValue: any, operator: string): boolean | undefined {
|
||||
switch (operator) {
|
||||
case '==':
|
||||
return leftValue + '' === rightValue + '';
|
||||
@ -339,28 +328,7 @@ export class WidgetVisibilityService {
|
||||
this.processVarList = [];
|
||||
}
|
||||
|
||||
getTaskProcessVariable(taskId: string): Observable<TaskProcessVariableModel[]> {
|
||||
return from(this.taskFormsApi.getTaskFormVariables(taskId))
|
||||
.pipe(
|
||||
map((res) => {
|
||||
const jsonRes = this.toJson(res);
|
||||
this.processVarList = jsonRes;
|
||||
return jsonRes;
|
||||
}),
|
||||
catchError(() => this.handleError())
|
||||
);
|
||||
}
|
||||
|
||||
toJson(res: any): any {
|
||||
return res || {};
|
||||
}
|
||||
|
||||
private isValidCondition(condition: WidgetVisibilityModel): boolean {
|
||||
return !!(condition && condition.operator);
|
||||
}
|
||||
|
||||
private handleError() {
|
||||
this.logService.error('Error while performing a call');
|
||||
return throwError('Error while performing a call - Server error');
|
||||
}
|
||||
}
|
||||
|
@ -16,16 +16,17 @@
|
||||
*/
|
||||
|
||||
import { Injectable } from '@angular/core';
|
||||
import { Observable, from, throwError } from 'rxjs';
|
||||
import { Observable, from, throwError, of } from 'rxjs';
|
||||
import { UserProcessModel } from '../models/user-process.model';
|
||||
import { AlfrescoApiService } from './alfresco-api.service';
|
||||
import { LogService } from './log.service';
|
||||
import { catchError, map } from 'rxjs/operators';
|
||||
import { catchError, combineAll, defaultIfEmpty, map, switchMap } from 'rxjs/operators';
|
||||
import {
|
||||
TaskActionsApi,
|
||||
UsersApi,
|
||||
ResultListDataRepresentationLightUserRepresentation
|
||||
ResultListDataRepresentationLightUserRepresentation, ActivitiGroupsApi
|
||||
} from '@alfresco/js-api';
|
||||
import { GroupModel } from '../form';
|
||||
|
||||
@Injectable({
|
||||
providedIn: 'root'
|
||||
@ -44,10 +45,35 @@ export class PeopleProcessService {
|
||||
return this._userApi;
|
||||
}
|
||||
|
||||
_groupsApi: ActivitiGroupsApi;
|
||||
get groupsApi(): ActivitiGroupsApi {
|
||||
this._groupsApi = this._groupsApi ?? new ActivitiGroupsApi(this.apiService.getInstance());
|
||||
return this._groupsApi;
|
||||
}
|
||||
|
||||
constructor(private apiService: AlfrescoApiService,
|
||||
private logService: LogService) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a list of groups in a workflow.
|
||||
*
|
||||
* @param filter Filter to select specific groups
|
||||
* @param groupId Group ID for the search
|
||||
* @returns Array of groups
|
||||
*/
|
||||
getWorkflowGroups(filter: string, groupId?: string): Observable<GroupModel[]> {
|
||||
const option: any = { filter };
|
||||
if (groupId) {
|
||||
option.groupId = groupId;
|
||||
}
|
||||
return from(this.groupsApi.getGroups(option))
|
||||
.pipe(
|
||||
map((response: any) => response.data || []),
|
||||
catchError((err) => this.handleError(err))
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets information about users across all tasks.
|
||||
*
|
||||
@ -55,15 +81,21 @@ export class PeopleProcessService {
|
||||
* @param searchWord Filter text to search for
|
||||
* @returns Array of user information objects
|
||||
*/
|
||||
getWorkflowUsers(taskId?: string, searchWord?: string): Observable<UserProcessModel[]> {
|
||||
const option = { excludeTaskId: taskId, filter: searchWord };
|
||||
getWorkflowUsers(taskId?: string, searchWord?: string, groupId?: string): Observable<UserProcessModel[]> {
|
||||
const option = { excludeTaskId: taskId, filter: searchWord, groupId };
|
||||
|
||||
return from(this.getWorkflowUserApi(option))
|
||||
.pipe(
|
||||
map((response: any) => response.data || []),
|
||||
switchMap(response => response.data as UserProcessModel[] || []),
|
||||
map((user) => {
|
||||
user.userImage = this.getUserProfileImageApi(user.id.toString());
|
||||
return of(user);
|
||||
}),
|
||||
combineAll(),
|
||||
defaultIfEmpty([]),
|
||||
catchError((err) => this.handleError(err))
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the profile picture URL for the specified user.
|
||||
*
|
||||
|
110
lib/process-services-cloud/src/lib/form/components/form-cloud-custom-outcomes.component.spec.ts
Normal file
110
lib/process-services-cloud/src/lib/form/components/form-cloud-custom-outcomes.component.spec.ts
Normal file
@ -0,0 +1,110 @@
|
||||
/*!
|
||||
* @license
|
||||
* Copyright 2019 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 {
|
||||
FormModel, setupTestBed
|
||||
} from '@alfresco/adf-core';
|
||||
import {
|
||||
Component,
|
||||
DebugElement, ViewChild
|
||||
} from '@angular/core';
|
||||
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
import { By } from '@angular/platform-browser';
|
||||
import { TranslateModule } from '@ngx-translate/core';
|
||||
import { ProcessServiceCloudTestingModule } from '../../testing/process-service-cloud.testing.module';
|
||||
import { FormCloudComponent } from './form-cloud.component';
|
||||
|
||||
@Component({
|
||||
selector: 'adf-cloud-form-with-custom-outcomes',
|
||||
template: `
|
||||
<adf-cloud-form #adfCloudForm>
|
||||
<adf-cloud-form-custom-outcomes>
|
||||
<button mat-button id="adf-custom-outcome-1" (click)="onCustomButtonOneClick()">
|
||||
CUSTOM-BUTTON-1
|
||||
</button>
|
||||
<button mat-button id="adf-custom-outcome-2" (click)="onCustomButtonTwoClick()">
|
||||
CUSTOM-BUTTON-2
|
||||
</button>
|
||||
</adf-cloud-form-custom-outcomes>
|
||||
</adf-cloud-form>`
|
||||
})
|
||||
class FormCloudWithCustomOutComesComponent {
|
||||
|
||||
@ViewChild('adfCloudForm', { static: true })
|
||||
adfCloudForm: FormCloudComponent;
|
||||
|
||||
onCustomButtonOneClick() {
|
||||
}
|
||||
|
||||
onCustomButtonTwoClick() {
|
||||
}
|
||||
}
|
||||
|
||||
describe('FormCloudWithCustomOutComesComponent', () => {
|
||||
|
||||
let fixture: ComponentFixture<FormCloudWithCustomOutComesComponent>;
|
||||
let customComponent: FormCloudWithCustomOutComesComponent;
|
||||
let debugElement: DebugElement;
|
||||
|
||||
setupTestBed({
|
||||
imports: [
|
||||
TranslateModule.forRoot(),
|
||||
ProcessServiceCloudTestingModule
|
||||
],
|
||||
declarations: [FormCloudWithCustomOutComesComponent]
|
||||
});
|
||||
|
||||
beforeEach(() => {
|
||||
fixture = TestBed.createComponent(FormCloudWithCustomOutComesComponent);
|
||||
customComponent = fixture.componentInstance;
|
||||
debugElement = fixture.debugElement;
|
||||
const formRepresentation = {
|
||||
fields: [
|
||||
{ id: 'container1' }
|
||||
],
|
||||
outcomes: [
|
||||
{ id: 'outcome-1', name: 'outcome 1' }
|
||||
]
|
||||
};
|
||||
|
||||
const form = new FormModel(formRepresentation);
|
||||
customComponent.adfCloudForm.form = form;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
fixture.destroy();
|
||||
});
|
||||
|
||||
it('should be able to inject custom outcomes and click on custom outcomes', async () => {
|
||||
fixture.detectChanges();
|
||||
|
||||
const onCustomButtonOneSpy = spyOn(customComponent, 'onCustomButtonOneClick').and.callThrough();
|
||||
const buttonOneBtn = debugElement.query(By.css('#adf-custom-outcome-1'));
|
||||
const buttonTwoBtn = debugElement.query(By.css('#adf-custom-outcome-2'));
|
||||
expect(buttonOneBtn).not.toBeNull();
|
||||
expect(buttonTwoBtn).not.toBeNull();
|
||||
|
||||
buttonOneBtn.nativeElement.click();
|
||||
fixture.detectChanges();
|
||||
await fixture.whenStable();
|
||||
|
||||
expect(onCustomButtonOneSpy).toHaveBeenCalled();
|
||||
expect(buttonOneBtn.nativeElement.innerText).toBe('CUSTOM-BUTTON-1');
|
||||
expect(buttonTwoBtn.nativeElement.innerText).toBe('CUSTOM-BUTTON-2');
|
||||
});
|
||||
});
|
@ -17,56 +17,42 @@
|
||||
|
||||
/* eslint-disable @typescript-eslint/naming-convention */
|
||||
|
||||
import { VersionCompatibilityService } from '@alfresco/adf-content-services';
|
||||
import {
|
||||
Component,
|
||||
DebugElement,
|
||||
SimpleChange,
|
||||
NgModule,
|
||||
Injector,
|
||||
ComponentFactoryResolver,
|
||||
ViewChild
|
||||
} from '@angular/core';
|
||||
import { By } from '@angular/platform-browser';
|
||||
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
import { Observable, of, throwError } from 'rxjs';
|
||||
import {
|
||||
CoreModule,
|
||||
AlfrescoApiService, ContentLinkModel, CoreModule,
|
||||
FormFieldModel,
|
||||
FormFieldTypes,
|
||||
FormModel,
|
||||
FormOutcomeEvent,
|
||||
FormOutcomeModel,
|
||||
setupTestBed,
|
||||
TRANSLATION_PROVIDER,
|
||||
WidgetVisibilityService,
|
||||
FormService,
|
||||
UploadWidgetContentLinkModel,
|
||||
ContentLinkModel,
|
||||
AlfrescoApiService
|
||||
FormOutcomeModel, FormRenderingService, FormService, setupTestBed,
|
||||
TRANSLATION_PROVIDER, UploadWidgetContentLinkModel, WidgetVisibilityService
|
||||
} from '@alfresco/adf-core';
|
||||
import { VersionCompatibilityService } from '@alfresco/adf-content-services';
|
||||
import { Node } from '@alfresco/js-api';
|
||||
import { ESCAPE } from '@angular/cdk/keycodes';
|
||||
import { HarnessLoader } from '@angular/cdk/testing';
|
||||
import { TestbedHarnessEnvironment } from '@angular/cdk/testing/testbed';
|
||||
import {
|
||||
Component, ComponentFactoryResolver, Injector, SimpleChange
|
||||
} from '@angular/core';
|
||||
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
import { MatDialog } from '@angular/material/dialog';
|
||||
import { MatDialogHarness } from '@angular/material/dialog/testing';
|
||||
import { By } from '@angular/platform-browser';
|
||||
import { NoopAnimationsModule } from '@angular/platform-browser/animations';
|
||||
import { TranslateModule, TranslateService } from '@ngx-translate/core';
|
||||
import { Observable, of, throwError } from 'rxjs';
|
||||
import { ProcessServiceCloudTestingModule } from '../../testing/process-service-cloud.testing.module';
|
||||
import { FormCloudService } from '../services/form-cloud.service';
|
||||
import { FormCloudComponent } from './form-cloud.component';
|
||||
import { FormCloudModule } from '../form-cloud.module';
|
||||
import {
|
||||
cloudFormMock,
|
||||
conditionalUploadWidgetsMock,
|
||||
emptyFormRepresentationJSON,
|
||||
fakeCloudForm,
|
||||
multilingualForm,
|
||||
fakeMetadataForm
|
||||
fakeCloudForm, fakeMetadataForm, multilingualForm
|
||||
} from '../mocks/cloud-form.mock';
|
||||
import { FormCloudRepresentation } from '../models/form-cloud-representation.model';
|
||||
import { FormCloudModule } from '../form-cloud.module';
|
||||
import { TranslateService, TranslateModule } from '@ngx-translate/core';
|
||||
import { NoopAnimationsModule } from '@angular/platform-browser/animations';
|
||||
import { FormCloudService } from '../services/form-cloud.service';
|
||||
import { CloudFormRenderingService } from './cloud-form-rendering.service';
|
||||
import { Node } from '@alfresco/js-api';
|
||||
import { ESCAPE } from '@angular/cdk/keycodes';
|
||||
import { MatDialog } from '@angular/material/dialog';
|
||||
import { HarnessLoader } from '@angular/cdk/testing';
|
||||
import { TestbedHarnessEnvironment } from '@angular/cdk/testing/testbed';
|
||||
import { MatDialogHarness } from '@angular/material/dialog/testing';
|
||||
import { FormCloudComponent } from './form-cloud.component';
|
||||
|
||||
const mockOauth2Auth: any = {
|
||||
oauth2Auth: {
|
||||
@ -83,7 +69,6 @@ describe('FormCloudComponent', () => {
|
||||
let matDialog: MatDialog;
|
||||
let visibilityService: WidgetVisibilityService;
|
||||
let formRenderingService: CloudFormRenderingService;
|
||||
let translateService: TranslateService;
|
||||
let documentRootLoader: HarnessLoader;
|
||||
|
||||
@Component({
|
||||
@ -95,13 +80,6 @@ describe('FormCloudComponent', () => {
|
||||
typeId = 'CustomWidget';
|
||||
}
|
||||
|
||||
@NgModule({
|
||||
declarations: [CustomWidget],
|
||||
exports: [CustomWidget]
|
||||
})
|
||||
class CustomUploadModule {
|
||||
}
|
||||
|
||||
const buildWidget = (type: string, injector: Injector): any => {
|
||||
const resolver = formRenderingService.getComponentTypeResolver(type);
|
||||
const widgetType = resolver(null);
|
||||
@ -115,25 +93,14 @@ describe('FormCloudComponent', () => {
|
||||
|
||||
setupTestBed({
|
||||
imports: [
|
||||
NoopAnimationsModule,
|
||||
TranslateModule.forRoot(),
|
||||
CoreModule.forRoot(),
|
||||
FormCloudModule,
|
||||
CustomUploadModule
|
||||
ProcessServiceCloudTestingModule
|
||||
],
|
||||
providers: [
|
||||
{
|
||||
provide: TRANSLATION_PROVIDER,
|
||||
multi: true,
|
||||
useValue: {
|
||||
name: 'app',
|
||||
source: 'resources'
|
||||
}
|
||||
},
|
||||
{
|
||||
provide: VersionCompatibilityService,
|
||||
useValue: {}
|
||||
}
|
||||
},
|
||||
{ provide: FormRenderingService, useClass: CloudFormRenderingService }
|
||||
]
|
||||
});
|
||||
|
||||
@ -144,7 +111,6 @@ describe('FormCloudComponent', () => {
|
||||
formRenderingService = TestBed.inject(CloudFormRenderingService);
|
||||
formCloudService = TestBed.inject(FormCloudService);
|
||||
|
||||
translateService = TestBed.inject(TranslateService);
|
||||
matDialog = TestBed.inject(MatDialog);
|
||||
|
||||
visibilityService = TestBed.inject(WidgetVisibilityService);
|
||||
@ -1100,121 +1066,77 @@ describe('FormCloudComponent', () => {
|
||||
});
|
||||
});
|
||||
|
||||
describe('Multilingual Form', () => {
|
||||
it('should translate form labels on language change', async () => {
|
||||
spyOn(formCloudService, 'getForm').and.returnValue(of(multilingualForm));
|
||||
const formId = '123';
|
||||
const appName = 'test-app';
|
||||
formComponent.formId = formId;
|
||||
formComponent.appVersion = 1;
|
||||
|
||||
formComponent.ngOnChanges({ appName: new SimpleChange(null, appName, true) });
|
||||
expect(formCloudService.getForm).toHaveBeenCalledWith(appName, formId, 1);
|
||||
|
||||
fixture.detectChanges();
|
||||
expect(getLabelValue('textField')).toEqual('Text field');
|
||||
expect(getLabelValue('fildUploadField')).toEqual('File Upload');
|
||||
expect(getLabelValue('dateField')).toEqual('Date field (D-M-YYYY)');
|
||||
expect(getLabelValue('amountField')).toEqual('Amount field');
|
||||
|
||||
fixture.ngZone.run(() => translateService.use('fr'));
|
||||
|
||||
await fixture.whenStable();
|
||||
fixture.detectChanges();
|
||||
|
||||
expect(getLabelValue('textField')).toEqual('Champ de texte');
|
||||
expect(getLabelValue('fildUploadField')).toEqual('Téléchargement de fichiers');
|
||||
expect(getLabelValue('dateField')).toEqual('Champ de date (D-M-YYYY)');
|
||||
expect(getLabelValue('amountField')).toEqual('Champ Montant');
|
||||
});
|
||||
|
||||
const getLabelValue = (containerId: string): string => {
|
||||
const label = fixture.debugElement.nativeElement.querySelector(`[id="field-${containerId}-container"] label`);
|
||||
return label.innerText;
|
||||
};
|
||||
});
|
||||
});
|
||||
|
||||
@Component({
|
||||
selector: 'adf-cloud-form-with-custom-outcomes',
|
||||
template: `
|
||||
<adf-cloud-form #adfCloudForm>
|
||||
<adf-cloud-form-custom-outcomes>
|
||||
<button mat-button id="adf-custom-outcome-1" (click)="onCustomButtonOneClick()">
|
||||
CUSTOM-BUTTON-1
|
||||
</button>
|
||||
<button mat-button id="adf-custom-outcome-2" (click)="onCustomButtonTwoClick()">
|
||||
CUSTOM-BUTTON-2
|
||||
</button>
|
||||
</adf-cloud-form-custom-outcomes>
|
||||
</adf-cloud-form>`
|
||||
})
|
||||
|
||||
class FormCloudWithCustomOutComesComponent {
|
||||
|
||||
@ViewChild('adfCloudForm', { static: true })
|
||||
adfCloudForm: FormCloudComponent;
|
||||
|
||||
onCustomButtonOneClick() {
|
||||
}
|
||||
|
||||
onCustomButtonTwoClick() {
|
||||
}
|
||||
}
|
||||
|
||||
describe('FormCloudWithCustomOutComesComponent', () => {
|
||||
|
||||
let fixture: ComponentFixture<FormCloudWithCustomOutComesComponent>;
|
||||
let customComponent: FormCloudWithCustomOutComesComponent;
|
||||
let debugElement: DebugElement;
|
||||
describe('Multilingual Form', () => {
|
||||
let translateService: TranslateService;
|
||||
let formCloudService: FormCloudService;
|
||||
let formComponent: FormCloudComponent;
|
||||
let fixture: ComponentFixture<FormCloudComponent>;
|
||||
|
||||
setupTestBed({
|
||||
imports: [
|
||||
NoopAnimationsModule,
|
||||
TranslateModule.forRoot(),
|
||||
ProcessServiceCloudTestingModule
|
||||
CoreModule.forRoot()
|
||||
],
|
||||
declarations: [FormCloudWithCustomOutComesComponent]
|
||||
providers: [
|
||||
{
|
||||
provide: TRANSLATION_PROVIDER,
|
||||
multi: true,
|
||||
useValue: {
|
||||
name: 'app',
|
||||
source: 'resources'
|
||||
}
|
||||
}
|
||||
]
|
||||
});
|
||||
|
||||
beforeEach(() => {
|
||||
fixture = TestBed.createComponent(FormCloudWithCustomOutComesComponent);
|
||||
customComponent = fixture.componentInstance;
|
||||
debugElement = fixture.debugElement;
|
||||
const formRepresentation = {
|
||||
fields: [
|
||||
{ id: 'container1' }
|
||||
],
|
||||
outcomes: [
|
||||
{ id: 'outcome-1', name: 'outcome 1' }
|
||||
]
|
||||
};
|
||||
translateService = TestBed.inject(TranslateService);
|
||||
formCloudService = TestBed.inject(FormCloudService);
|
||||
|
||||
const form = new FormModel(formRepresentation);
|
||||
customComponent.adfCloudForm.form = form;
|
||||
fixture = TestBed.createComponent(FormCloudComponent);
|
||||
formComponent = fixture.componentInstance;
|
||||
formComponent.form = formComponent.parseForm(fakeMetadataForm);
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
fixture.destroy();
|
||||
});
|
||||
it('should translate form labels on language change', async () => {
|
||||
spyOn(formCloudService, 'getForm').and.returnValue(of(multilingualForm));
|
||||
const formId = '123';
|
||||
const appName = 'test-app';
|
||||
formComponent.formId = formId;
|
||||
formComponent.appVersion = 1;
|
||||
|
||||
it('should be able to inject custom outcomes and click on custom outcomes', async () => {
|
||||
fixture.detectChanges();
|
||||
formComponent.ngOnChanges({ appName: new SimpleChange(null, appName, true) });
|
||||
expect(formCloudService.getForm).toHaveBeenCalledWith(appName, formId, 1);
|
||||
|
||||
const onCustomButtonOneSpy = spyOn(customComponent, 'onCustomButtonOneClick').and.callThrough();
|
||||
const buttonOneBtn = debugElement.query(By.css('#adf-custom-outcome-1'));
|
||||
const buttonTwoBtn = debugElement.query(By.css('#adf-custom-outcome-2'));
|
||||
expect(buttonOneBtn).not.toBeNull();
|
||||
expect(buttonTwoBtn).not.toBeNull();
|
||||
fixture.ngZone.run(() => translateService.use('fr'));
|
||||
|
||||
buttonOneBtn.nativeElement.click();
|
||||
fixture.detectChanges();
|
||||
await fixture.whenStable();
|
||||
fixture.detectChanges();
|
||||
|
||||
expect(onCustomButtonOneSpy).toHaveBeenCalled();
|
||||
expect(buttonOneBtn.nativeElement.innerText).toBe('CUSTOM-BUTTON-1');
|
||||
expect(buttonTwoBtn.nativeElement.innerText).toBe('CUSTOM-BUTTON-2');
|
||||
expect(getLabelValue('textField')).toEqual('Champ de texte');
|
||||
expect(getLabelValue('fildUploadField')).toEqual('Téléchargement de fichiers');
|
||||
expect(getLabelValue('dateField')).toEqual('Champ de date (D-M-YYYY)');
|
||||
expect(getLabelValue('amountField')).toEqual('Champ Montant');
|
||||
|
||||
fixture.ngZone.run(() => translateService.use('en'));
|
||||
|
||||
await fixture.whenStable();
|
||||
fixture.detectChanges();
|
||||
|
||||
expect(getLabelValue('textField')).toEqual('Text field');
|
||||
expect(getLabelValue('fildUploadField')).toEqual('File Upload');
|
||||
expect(getLabelValue('dateField')).toEqual('Date field (D-M-YYYY)');
|
||||
expect(getLabelValue('amountField')).toEqual('Amount field');
|
||||
});
|
||||
|
||||
const getLabelValue = (containerId: string): string => {
|
||||
const label = fixture.debugElement.nativeElement.querySelector(`[id="field-${containerId}-container"] label`);
|
||||
return label.innerText;
|
||||
};
|
||||
});
|
||||
|
||||
describe('retrieve metadata on submit', () => {
|
||||
|
@ -824,14 +824,6 @@ describe('AttachFileCloudWidgetComponent', () => {
|
||||
expect(widget.field.params.fileSource.destinationFolderPath.value).toBe('mock-folder-id');
|
||||
});
|
||||
|
||||
it('it should get a destination folder path value from a folder variable', () => {
|
||||
createUploadWidgetField(form, 'attach-file-attach', [], mockAllFileSourceWithFolderVariablePathType);
|
||||
fixture.detectChanges();
|
||||
|
||||
expect(widget.field.params.fileSource.destinationFolderPath.type).toBe('folder');
|
||||
expect(widget.field.params.fileSource.destinationFolderPath.value).toBe('mock-folder-id');
|
||||
});
|
||||
|
||||
it('it should set destination folder path value to undefined if mapped variable deleted/renamed', () => {
|
||||
createUploadWidgetField(form, 'attach-file-attach', [], mockAllFileSourceWithRenamedFolderVariablePathType);
|
||||
fixture.detectChanges();
|
||||
|
43
lib/process-services-cloud/src/lib/form/components/widgets/dropdown/dropdown-cloud.widget.spec.ts
43
lib/process-services-cloud/src/lib/form/components/widgets/dropdown/dropdown-cloud.widget.spec.ts
@ -71,7 +71,6 @@ describe('DropdownCloudWidgetComponent', () => {
|
||||
describe('Simple Dropdown', () => {
|
||||
|
||||
beforeEach(() => {
|
||||
spyOn(formService, 'getRestFieldValues').and.callFake(() => of(fakeOptionList));
|
||||
widget.field = new FormFieldModel(new FormModel({ taskId: 'fake-task-id' }), {
|
||||
id: 'dropdown-id',
|
||||
name: 'date-name',
|
||||
@ -85,13 +84,14 @@ describe('DropdownCloudWidgetComponent', () => {
|
||||
});
|
||||
|
||||
it('should require field with restUrl', () => {
|
||||
spyOn(formCloudService, 'getRestWidgetData');
|
||||
widget.field = new FormFieldModel(new FormModel());
|
||||
widget.ngOnInit();
|
||||
expect(formService.getRestFieldValues).not.toHaveBeenCalled();
|
||||
expect(formCloudService.getRestWidgetData).not.toHaveBeenCalled();
|
||||
|
||||
widget.field = new FormFieldModel(null, { restUrl: null });
|
||||
widget.ngOnInit();
|
||||
expect(formService.getRestFieldValues).not.toHaveBeenCalled();
|
||||
expect(formCloudService.getRestWidgetData).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should select the default value when an option is chosen as default', async () => {
|
||||
@ -339,46 +339,13 @@ describe('DropdownCloudWidgetComponent', () => {
|
||||
fixture.detectChanges();
|
||||
await fixture.whenStable();
|
||||
|
||||
expect(element.querySelector('.adf-invalid')).toBeTruthy();
|
||||
|
||||
const requiredErrorElement = fixture.debugElement.query(By.css('.adf-dropdown-required-message .adf-error-text'));
|
||||
expect(requiredErrorElement.nativeElement.innerText).toEqual('FORM.FIELD.REQUIRED');
|
||||
});
|
||||
});
|
||||
|
||||
describe('when is required', () => {
|
||||
|
||||
beforeEach(() => {
|
||||
widget.field = new FormFieldModel( new FormModel({ taskId: '<id>' }), {
|
||||
type: FormFieldTypes.DROPDOWN,
|
||||
required: true
|
||||
});
|
||||
});
|
||||
|
||||
it('should be able to display label with asterisk', async () => {
|
||||
fixture.detectChanges();
|
||||
await fixture.whenStable();
|
||||
|
||||
const asterisk: HTMLElement = element.querySelector('.adf-asterisk');
|
||||
|
||||
expect(asterisk).toBeTruthy();
|
||||
expect(asterisk.textContent).toEqual('*');
|
||||
});
|
||||
|
||||
it('should be invalid if no default option after interaction', async () => {
|
||||
fixture.detectChanges();
|
||||
await fixture.whenStable();
|
||||
|
||||
expect(element.querySelector('.adf-invalid')).toBeFalsy();
|
||||
|
||||
const dropdownSelect = element.querySelector('.adf-select');
|
||||
dropdownSelect.dispatchEvent(new Event('blur'));
|
||||
|
||||
fixture.detectChanges();
|
||||
await fixture.whenStable();
|
||||
|
||||
expect(element.querySelector('.adf-invalid')).toBeTruthy();
|
||||
});
|
||||
});
|
||||
|
||||
describe('filter', () => {
|
||||
|
||||
beforeEach(() => {
|
||||
|
@ -135,7 +135,7 @@ describe('RadioButtonsCloudWidgetComponent', () => {
|
||||
expect(widget.field.isValid).toBe(true);
|
||||
});
|
||||
|
||||
it('should be able to set a Radio Button widget as required', () => {
|
||||
it('should set Radio Button as valid when required and not empty', () => {
|
||||
widget.field = new FormFieldModel(new FormModel({}), {
|
||||
id: 'radio-id',
|
||||
name: 'radio-name-label',
|
||||
|
@ -20,7 +20,6 @@ import {
|
||||
AlfrescoApiService,
|
||||
FormValues,
|
||||
AppConfigService,
|
||||
FormOutcomeModel,
|
||||
FormModel,
|
||||
FormFieldOption
|
||||
} from '@alfresco/adf-core';
|
||||
@ -232,17 +231,7 @@ export class FormCloudService extends BaseCloudService implements FormCloudServi
|
||||
formValues[variable.name] = variable.value;
|
||||
});
|
||||
|
||||
const form = new FormModel(flattenForm, formValues, readOnly);
|
||||
if (!json.fields) {
|
||||
form.outcomes = [
|
||||
new FormOutcomeModel(form, {
|
||||
id: '$save',
|
||||
name: FormOutcomeModel.SAVE_ACTION,
|
||||
isSystem: true
|
||||
})
|
||||
];
|
||||
}
|
||||
return form;
|
||||
return new FormModel(flattenForm, formValues, readOnly);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
@ -306,7 +306,7 @@ describe('Task Cloud Service', () => {
|
||||
});
|
||||
});
|
||||
|
||||
it('should throw error if appName is not defined when querying by id', (done) => {
|
||||
it('should throw error if appName is not defined when querying by id with update playload', (done) => {
|
||||
const appName = null;
|
||||
const taskId = '68d54a8f';
|
||||
const updatePayload = { description: 'New description' };
|
||||
|
@ -338,7 +338,7 @@ describe('TaskFormCloudComponent', () => {
|
||||
component.onError({});
|
||||
});
|
||||
|
||||
it('should emit taskCompleted when task is completed', () => {
|
||||
it('should reload when task is completed', () => {
|
||||
spyOn(taskCloudService, 'completeTask').and.returnValue(of({}));
|
||||
const reloadSpy = spyOn(component, 'ngOnChanges').and.callThrough();
|
||||
|
||||
@ -350,7 +350,7 @@ describe('TaskFormCloudComponent', () => {
|
||||
expect(reloadSpy).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should emit taskClaimed when task is claimed', () => {
|
||||
it('should reload when task is claimed', () => {
|
||||
spyOn(taskCloudService, 'claimTask').and.returnValue(of({}));
|
||||
spyOn(component, 'hasCandidateUsers').and.returnValue(true);
|
||||
const reloadSpy = spyOn(component, 'ngOnChanges').and.callThrough();
|
||||
|
12
lib/process-services-cloud/src/lib/task/task-header/components/task-header-cloud.component.spec.ts
12
lib/process-services-cloud/src/lib/task/task-header/components/task-header-cloud.component.spec.ts
@ -168,18 +168,6 @@ describe('TaskHeaderCloudComponent', () => {
|
||||
expect(valueEl.nativeElement.value).toBe('67c4z2a8f-01f3-11e9-8e36-0a58646002ad');
|
||||
});
|
||||
|
||||
it('should display process instance id', async () => {
|
||||
fixture.detectChanges();
|
||||
await fixture.whenStable();
|
||||
fixture.detectChanges();
|
||||
|
||||
const labelEl = fixture.debugElement.query(By.css('[data-automation-id="card-textitem-label-processInstanceId"]'));
|
||||
const valueEl = fixture.debugElement.query(By.css('[data-automation-id="card-textitem-value-processInstanceId"]'));
|
||||
|
||||
expect(labelEl.nativeElement.textContent.trim()).toBe('ADF_CLOUD_TASK_HEADER.PROPERTIES.PROCESS_INSTANCE_ID');
|
||||
expect(valueEl.nativeElement.value).toBe('67c4z2a8f-01f3-11e9-8e36-0a58646002ad');
|
||||
});
|
||||
|
||||
it('should display placeholder if no due date', async () => {
|
||||
component.taskDetails.dueDate = null;
|
||||
component.refreshData();
|
||||
|
@ -80,4 +80,5 @@ module.exports = function (config) {
|
||||
browsers: ['Chrome'],
|
||||
singleRun: true
|
||||
});
|
||||
process.env.TZ = 'UTC';
|
||||
};
|
||||
|
@ -16,7 +16,7 @@
|
||||
*/
|
||||
|
||||
import { Component, EventEmitter, Input, OnChanges, Output, SimpleChanges } from '@angular/core';
|
||||
import { ProcessContentService } from '@alfresco/adf-core';
|
||||
import { ProcessContentService } from '../form/services/process-content.service';
|
||||
|
||||
@Component({
|
||||
selector: 'adf-create-process-attachment',
|
||||
|
@ -19,10 +19,11 @@ import { SimpleChange } from '@angular/core';
|
||||
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
import { of } from 'rxjs';
|
||||
|
||||
import { ProcessContentService, setupTestBed } from '@alfresco/adf-core';
|
||||
import { setupTestBed } from '@alfresco/adf-core';
|
||||
import { AttachmentComponent } from './create-task-attachment.component';
|
||||
import { ProcessTestingModule } from '../testing/process.testing.module';
|
||||
import { TranslateModule } from '@ngx-translate/core';
|
||||
import { ProcessContentService } from '../form/services/process-content.service';
|
||||
|
||||
describe('AttachmentComponent', () => {
|
||||
|
||||
|
@ -16,7 +16,7 @@
|
||||
*/
|
||||
|
||||
import { Component, EventEmitter, Input, OnChanges, Output, SimpleChanges } from '@angular/core';
|
||||
import { ProcessContentService } from '@alfresco/adf-core';
|
||||
import { ProcessContentService } from '../form/services/process-content.service';
|
||||
|
||||
@Component({
|
||||
selector: 'adf-create-task-attachment',
|
||||
|
@ -18,12 +18,13 @@
|
||||
import { SimpleChange, Component, CUSTOM_ELEMENTS_SCHEMA } from '@angular/core';
|
||||
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
import { By } from '@angular/platform-browser';
|
||||
import { ProcessContentService, setupTestBed } from '@alfresco/adf-core';
|
||||
import { setupTestBed } from '@alfresco/adf-core';
|
||||
import { of, throwError } from 'rxjs';
|
||||
import { ProcessAttachmentListComponent } from './process-attachment-list.component';
|
||||
import { ProcessTestingModule } from '../testing/process.testing.module';
|
||||
import { TranslateModule } from '@ngx-translate/core';
|
||||
import { mockEmittedProcessAttachments, mockProcessAttachments } from '../mock/process/process-attachments.mock';
|
||||
import { ProcessContentService } from '../form/services/process-content.service';
|
||||
|
||||
describe('ProcessAttachmentListComponent', () => {
|
||||
|
||||
|
@ -15,7 +15,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { ContentService, EmptyListComponent, ThumbnailService, ProcessContentService } from '@alfresco/adf-core';
|
||||
import { ContentService, EmptyListComponent, ThumbnailService } from '@alfresco/adf-core';
|
||||
import {
|
||||
AfterContentInit,
|
||||
ContentChild,
|
||||
@ -28,6 +28,7 @@ import {
|
||||
SimpleChanges,
|
||||
ViewEncapsulation
|
||||
} from '@angular/core';
|
||||
import { ProcessContentService } from '../form/services/process-content.service';
|
||||
|
||||
@Component({
|
||||
selector: 'adf-process-attachment-list',
|
||||
|
@ -20,10 +20,11 @@ import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
import { By } from '@angular/platform-browser';
|
||||
import { of, throwError } from 'rxjs';
|
||||
import { TaskAttachmentListComponent } from './task-attachment-list.component';
|
||||
import { ProcessContentService, setupTestBed } from '@alfresco/adf-core';
|
||||
import { setupTestBed } from '@alfresco/adf-core';
|
||||
import { ProcessTestingModule } from '../testing/process.testing.module';
|
||||
import { TranslateModule } from '@ngx-translate/core';
|
||||
import { mockEmittedTaskAttachments, mockTaskAttachments } from '../mock/task/task-attachments.mock';
|
||||
import { ProcessContentService } from '../form/services/process-content.service';
|
||||
|
||||
describe('TaskAttachmentList', () => {
|
||||
|
||||
|
@ -15,7 +15,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { ContentService, ThumbnailService, EmptyListComponent, ProcessContentService } from '@alfresco/adf-core';
|
||||
import { ContentService, ThumbnailService, EmptyListComponent } from '@alfresco/adf-core';
|
||||
import {
|
||||
AfterContentInit,
|
||||
ContentChild,
|
||||
@ -28,6 +28,7 @@ import {
|
||||
SimpleChanges,
|
||||
ViewEncapsulation
|
||||
} from '@angular/core';
|
||||
import { ProcessContentService } from '../form/services/process-content.service';
|
||||
|
||||
@Component({
|
||||
selector: 'adf-task-attachment-list',
|
||||
|
@ -15,11 +15,9 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { FormFieldModel } from '../components/widgets/core/form-field.model';
|
||||
import { FormModel } from '../components/widgets/core/form.model';
|
||||
import { DynamicRowValidationSummary } from '../components/widgets/dynamic-table/dynamic-row-validation-summary.model';
|
||||
import { DynamicTableRow } from '../components/widgets/dynamic-table/dynamic-table-row.model';
|
||||
import { FormFieldEvent } from './form-field.event';
|
||||
import { FormFieldModel, FormFieldEvent, FormModel } from '@alfresco/adf-core';
|
||||
import { DynamicRowValidationSummary } from '../widgets/dynamic-table/editors/models/dynamic-row-validation-summary.model';
|
||||
import { DynamicTableRow } from '../widgets/dynamic-table/editors/models/dynamic-table-row.model';
|
||||
|
||||
export class ValidateDynamicTableRowEvent extends FormFieldEvent {
|
||||
|
@ -17,22 +17,19 @@
|
||||
|
||||
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
import { of } from 'rxjs';
|
||||
import { FormService } from '../services/form.service';
|
||||
import { setupTestBed, CoreTestingModule } from '@alfresco/adf-core';
|
||||
import { FormListComponent } from './form-list.component';
|
||||
import { setupTestBed } from '../../testing/setup-test-bed';
|
||||
import { CoreTestingModule } from '../../testing/core.testing.module';
|
||||
import { TranslateModule } from '@ngx-translate/core';
|
||||
import { ModelService } from '../services/model.service';
|
||||
|
||||
describe('TaskAttachmentList', () => {
|
||||
|
||||
let component: FormListComponent;
|
||||
let fixture: ComponentFixture<FormListComponent>;
|
||||
let service: FormService;
|
||||
let modelService: ModelService;
|
||||
let element: HTMLElement;
|
||||
|
||||
setupTestBed({
|
||||
imports: [
|
||||
TranslateModule.forRoot(),
|
||||
CoreTestingModule
|
||||
]
|
||||
});
|
||||
@ -41,13 +38,13 @@ describe('TaskAttachmentList', () => {
|
||||
fixture = TestBed.createComponent(FormListComponent);
|
||||
component = fixture.componentInstance;
|
||||
element = fixture.debugElement.nativeElement;
|
||||
service = TestBed.inject(FormService);
|
||||
modelService = TestBed.inject(ModelService);
|
||||
});
|
||||
|
||||
it('should show the forms as a list', async () => {
|
||||
spyOn(service, 'getForms').and.returnValue(of([
|
||||
{ name: 'FakeName-1', lastUpdatedByFullName: 'FakeUser-1', lastUpdated: '2017-01-02' },
|
||||
{ name: 'FakeName-2', lastUpdatedByFullName: 'FakeUser-2', lastUpdated: '2017-01-03' }
|
||||
spyOn(modelService, 'getForms').and.returnValue(of([
|
||||
{name: 'FakeName-1', lastUpdatedByFullName: 'FakeUser-1', lastUpdated: '2017-01-02'},
|
||||
{name: 'FakeName-2', lastUpdatedByFullName: 'FakeUser-2', lastUpdated: '2017-01-03'}
|
||||
]));
|
||||
|
||||
component.ngOnChanges();
|
@ -16,7 +16,7 @@
|
||||
*/
|
||||
|
||||
import { Component, Input, OnChanges, ViewEncapsulation } from '@angular/core';
|
||||
import { FormService } from '../services/form.service';
|
||||
import { ModelService } from '../services/model.service';
|
||||
|
||||
@Component({
|
||||
selector: 'adf-form-list',
|
||||
@ -29,7 +29,7 @@ export class FormListComponent implements OnChanges {
|
||||
@Input()
|
||||
forms: any [] = [];
|
||||
|
||||
constructor(protected formService: FormService) {
|
||||
constructor(protected modelService: ModelService) {
|
||||
}
|
||||
|
||||
ngOnChanges() {
|
||||
@ -41,7 +41,7 @@ export class FormListComponent implements OnChanges {
|
||||
}
|
||||
|
||||
getForms() {
|
||||
this.formService.getForms().subscribe((forms) => {
|
||||
this.modelService.getForms().subscribe((forms) => {
|
||||
this.forms.push(...forms);
|
||||
});
|
||||
}
|
@ -25,18 +25,23 @@ import {
|
||||
DebugElement
|
||||
} from '@angular/core';
|
||||
import { By } from '@angular/platform-browser';
|
||||
import { TaskRepresentation } from '@alfresco/js-api';
|
||||
import { TestBed, ComponentFixture } from '@angular/core/testing';
|
||||
import { Observable, of, throwError } from 'rxjs';
|
||||
import {
|
||||
FormFieldModel, FormFieldTypes, FormModel, FormOutcomeEvent, FormOutcomeModel,
|
||||
FormService, WidgetVisibilityService, NodeService, ContainerModel, fakeForm,
|
||||
FormService, WidgetVisibilityService, ContainerModel, fakeForm,
|
||||
setupTestBed,
|
||||
NodeMetadata
|
||||
NodeMetadata, NodesApiService
|
||||
} from '@alfresco/adf-core';
|
||||
import { FormComponent } from './form.component';
|
||||
import { ProcessFormRenderingService } from './process-form-rendering.service';
|
||||
import { ProcessTestingModule } from '../testing/process.testing.module';
|
||||
import { TranslateModule } from '@ngx-translate/core';
|
||||
import { TaskFormService } from './services/task-form.service';
|
||||
import { TaskService } from './services/task.service';
|
||||
import { EditorService } from './services/editor.service';
|
||||
import { ModelService } from './services/model.service';
|
||||
|
||||
describe('FormComponent', () => {
|
||||
|
||||
@ -45,7 +50,11 @@ describe('FormComponent', () => {
|
||||
|
||||
let formService: FormService;
|
||||
let visibilityService: WidgetVisibilityService;
|
||||
let nodeService: NodeService;
|
||||
let taskFormService: TaskFormService;
|
||||
let taskService: TaskService;
|
||||
let editorService: EditorService;
|
||||
let modelService: ModelService;
|
||||
let nodeService: NodesApiService;
|
||||
let formRenderingService: ProcessFormRenderingService;
|
||||
|
||||
@Component({
|
||||
@ -87,8 +96,12 @@ describe('FormComponent', () => {
|
||||
visibilityService = TestBed.inject(WidgetVisibilityService);
|
||||
spyOn(visibilityService, 'refreshVisibility').and.stub();
|
||||
|
||||
nodeService = TestBed.inject(NodesApiService);
|
||||
formService = TestBed.inject(FormService);
|
||||
nodeService = TestBed.inject(NodeService);
|
||||
taskService = TestBed.inject(TaskService);
|
||||
taskFormService = TestBed.inject(TaskFormService);
|
||||
editorService = TestBed.inject(EditorService);
|
||||
modelService = TestBed.inject(ModelService);
|
||||
formRenderingService = TestBed.inject(ProcessFormRenderingService);
|
||||
|
||||
fixture = TestBed.createComponent(FormComponent);
|
||||
@ -159,14 +172,14 @@ describe('FormComponent', () => {
|
||||
it('should enable custom outcome buttons', () => {
|
||||
const formModel = new FormModel();
|
||||
formComponent.form = formModel;
|
||||
const outcome = new FormOutcomeModel(formModel, { id: 'action1', name: 'Action 1' });
|
||||
const outcome = new FormOutcomeModel(formModel, {id: 'action1', name: 'Action 1'});
|
||||
expect(formComponent.isOutcomeButtonVisible(outcome, formComponent.form.readOnly)).toBeTruthy();
|
||||
});
|
||||
|
||||
it('should allow controlling [complete] button visibility', () => {
|
||||
const formModel = new FormModel();
|
||||
formComponent.form = formModel;
|
||||
const outcome = new FormOutcomeModel(formModel, { id: '$save', name: FormOutcomeModel.SAVE_ACTION });
|
||||
const outcome = new FormOutcomeModel(formModel, {id: '$save', name: FormOutcomeModel.SAVE_ACTION});
|
||||
|
||||
formComponent.showSaveButton = true;
|
||||
expect(formComponent.isOutcomeButtonVisible(outcome, formComponent.form.readOnly)).toBeTruthy();
|
||||
@ -179,7 +192,7 @@ describe('FormComponent', () => {
|
||||
const formModel = new FormModel();
|
||||
formModel.readOnly = true;
|
||||
formComponent.form = formModel;
|
||||
const outcome = new FormOutcomeModel(formModel, { id: '$complete', name: FormOutcomeModel.COMPLETE_ACTION });
|
||||
const outcome = new FormOutcomeModel(formModel, {id: '$complete', name: FormOutcomeModel.COMPLETE_ACTION});
|
||||
|
||||
formComponent.showCompleteButton = true;
|
||||
expect(formComponent.isOutcomeButtonVisible(outcome, formComponent.form.readOnly)).toBeTruthy();
|
||||
@ -189,23 +202,23 @@ describe('FormComponent', () => {
|
||||
const formModel = new FormModel();
|
||||
formModel.readOnly = true;
|
||||
formComponent.form = formModel;
|
||||
const outcome = new FormOutcomeModel(formModel, { id: '$save', name: FormOutcomeModel.SAVE_ACTION });
|
||||
const outcome = new FormOutcomeModel(formModel, {id: '$save', name: FormOutcomeModel.SAVE_ACTION});
|
||||
|
||||
formComponent.showSaveButton = true;
|
||||
expect(formComponent.isOutcomeButtonVisible(outcome, formComponent.form.readOnly)).toBeFalsy();
|
||||
});
|
||||
|
||||
it('should show [custom-outcome] button with readOnly form and selected custom-outcome', () => {
|
||||
const formModel = new FormModel({ selectedOutcome: 'custom-outcome' });
|
||||
const formModel = new FormModel({selectedOutcome: 'custom-outcome'});
|
||||
formModel.readOnly = true;
|
||||
formComponent.form = formModel;
|
||||
let outcome = new FormOutcomeModel(formModel, { id: '$customoutome', name: 'custom-outcome' });
|
||||
let outcome = new FormOutcomeModel(formModel, {id: '$customoutome', name: 'custom-outcome'});
|
||||
|
||||
formComponent.showCompleteButton = true;
|
||||
formComponent.showSaveButton = true;
|
||||
expect(formComponent.isOutcomeButtonVisible(outcome, formComponent.form.readOnly)).toBeTruthy();
|
||||
|
||||
outcome = new FormOutcomeModel(formModel, { id: '$customoutome2', name: 'custom-outcome2' });
|
||||
outcome = new FormOutcomeModel(formModel, {id: '$customoutome2', name: 'custom-outcome2'});
|
||||
expect(formComponent.isOutcomeButtonVisible(outcome, formComponent.form.readOnly)).toBeFalsy();
|
||||
});
|
||||
|
||||
@ -213,7 +226,7 @@ describe('FormComponent', () => {
|
||||
const formModel = new FormModel();
|
||||
formModel.readOnly = false;
|
||||
formComponent.form = formModel;
|
||||
const outcome = new FormOutcomeModel(formModel, { id: '$save', name: FormOutcomeModel.COMPLETE_ACTION });
|
||||
const outcome = new FormOutcomeModel(formModel, {id: '$save', name: FormOutcomeModel.COMPLETE_ACTION});
|
||||
|
||||
formComponent.showCompleteButton = true;
|
||||
expect(formComponent.isOutcomeButtonVisible(outcome, formComponent.form.readOnly)).toBeTruthy();
|
||||
@ -240,44 +253,6 @@ describe('FormComponent', () => {
|
||||
expect(formComponent.getFormByTaskId).toHaveBeenCalledWith(taskId);
|
||||
});
|
||||
|
||||
it('should get process variable if is a process task', () => {
|
||||
spyOn(formService, 'getTaskForm').and.callFake((currentTaskId) => new Observable((observer) => {
|
||||
observer.next({ taskId: currentTaskId });
|
||||
observer.complete();
|
||||
}));
|
||||
|
||||
spyOn(visibilityService, 'getTaskProcessVariable').and.returnValue(of(null));
|
||||
spyOn(formService, 'getTask').and.callFake((currentTaskId) => new Observable((observer) => {
|
||||
observer.next({ taskId: currentTaskId, processDefinitionId: '10201' });
|
||||
observer.complete();
|
||||
}));
|
||||
const taskId = '123';
|
||||
|
||||
formComponent.taskId = taskId;
|
||||
formComponent.loadForm();
|
||||
|
||||
expect(visibilityService.getTaskProcessVariable).toHaveBeenCalledWith(taskId);
|
||||
});
|
||||
|
||||
it('should not get process variable if is not a process task', () => {
|
||||
spyOn(formService, 'getTaskForm').and.callFake((currentTaskId) => new Observable((observer) => {
|
||||
observer.next({ taskId: currentTaskId });
|
||||
observer.complete();
|
||||
}));
|
||||
|
||||
spyOn(visibilityService, 'getTaskProcessVariable').and.returnValue(of(null));
|
||||
spyOn(formService, 'getTask').and.callFake((currentTaskId) => new Observable((observer) => {
|
||||
observer.next({ taskId: currentTaskId, processDefinitionId: 'null' });
|
||||
observer.complete();
|
||||
}));
|
||||
const taskId = '123';
|
||||
|
||||
formComponent.taskId = taskId;
|
||||
formComponent.loadForm();
|
||||
|
||||
expect(visibilityService.getTaskProcessVariable).toHaveBeenCalledWith(taskId);
|
||||
});
|
||||
|
||||
it('should get form definition by form id on load', () => {
|
||||
spyOn(formComponent, 'getFormDefinitionByFormId').and.stub();
|
||||
const formId = 123;
|
||||
@ -289,13 +264,13 @@ describe('FormComponent', () => {
|
||||
});
|
||||
|
||||
it('should refresh visibility when the form is loaded', () => {
|
||||
spyOn(formService, 'getFormDefinitionById').and.returnValue(of(JSON.parse(JSON.stringify(fakeForm))));
|
||||
spyOn(editorService, 'getFormDefinitionById').and.returnValue(of(JSON.parse(JSON.stringify(fakeForm))));
|
||||
const formId = 123;
|
||||
|
||||
formComponent.formId = formId;
|
||||
formComponent.loadForm();
|
||||
|
||||
expect(formService.getFormDefinitionById).toHaveBeenCalledWith(formId);
|
||||
expect(editorService.getFormDefinitionById).toHaveBeenCalledWith(formId);
|
||||
expect(visibilityService.refreshVisibility).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
@ -314,7 +289,7 @@ describe('FormComponent', () => {
|
||||
const taskId = '<task id>';
|
||||
|
||||
const change = new SimpleChange(null, taskId, true);
|
||||
formComponent.ngOnChanges({ taskId: change });
|
||||
formComponent.ngOnChanges({taskId: change});
|
||||
|
||||
expect(formComponent.getFormByTaskId).toHaveBeenCalledWith(taskId);
|
||||
});
|
||||
@ -324,7 +299,7 @@ describe('FormComponent', () => {
|
||||
const formId = '123';
|
||||
|
||||
const change = new SimpleChange(null, formId, true);
|
||||
formComponent.ngOnChanges({ formId: change });
|
||||
formComponent.ngOnChanges({formId: change});
|
||||
|
||||
expect(formComponent.getFormDefinitionByFormId).toHaveBeenCalledWith(formId);
|
||||
});
|
||||
@ -334,7 +309,7 @@ describe('FormComponent', () => {
|
||||
const formName = '<form>';
|
||||
|
||||
const change = new SimpleChange(null, formName, true);
|
||||
formComponent.ngOnChanges({ formName: change });
|
||||
formComponent.ngOnChanges({formName: change});
|
||||
|
||||
expect(formComponent.getFormDefinitionByFormName).toHaveBeenCalledWith(formName);
|
||||
});
|
||||
@ -359,7 +334,7 @@ describe('FormComponent', () => {
|
||||
spyOn(formComponent, 'getFormDefinitionByFormId').and.stub();
|
||||
spyOn(formComponent, 'getFormDefinitionByFormName').and.stub();
|
||||
|
||||
formComponent.ngOnChanges({ tag: new SimpleChange(null, 'hello world', true) });
|
||||
formComponent.ngOnChanges({tag: new SimpleChange(null, 'hello world', true)});
|
||||
|
||||
expect(formComponent.getFormByTaskId).not.toHaveBeenCalled();
|
||||
expect(formComponent.getFormDefinitionByFormId).not.toHaveBeenCalled();
|
||||
@ -369,7 +344,7 @@ describe('FormComponent', () => {
|
||||
it('should complete form on custom outcome click', () => {
|
||||
const formModel = new FormModel();
|
||||
const outcomeName = 'Custom Action';
|
||||
const outcome = new FormOutcomeModel(formModel, { id: 'custom1', name: outcomeName });
|
||||
const outcome = new FormOutcomeModel(formModel, {id: 'custom1', name: outcomeName});
|
||||
|
||||
let saved = false;
|
||||
formComponent.form = formModel;
|
||||
@ -434,7 +409,7 @@ describe('FormComponent', () => {
|
||||
it('should do nothing when clicking outcome for readonly form', () => {
|
||||
const formModel = new FormModel();
|
||||
const outcomeName = 'Custom Action';
|
||||
const outcome = new FormOutcomeModel(formModel, { id: 'custom1', name: outcomeName });
|
||||
const outcome = new FormOutcomeModel(formModel, {id: 'custom1', name: outcomeName});
|
||||
|
||||
formComponent.form = formModel;
|
||||
spyOn(formComponent, 'completeTaskForm').and.stub();
|
||||
@ -453,7 +428,7 @@ describe('FormComponent', () => {
|
||||
it('should require loaded form when clicking outcome', () => {
|
||||
const formModel = new FormModel();
|
||||
const outcomeName = 'Custom Action';
|
||||
const outcome = new FormOutcomeModel(formModel, { id: 'custom1', name: outcomeName });
|
||||
const outcome = new FormOutcomeModel(formModel, {id: 'custom1', name: outcomeName});
|
||||
|
||||
formComponent.readOnly = false;
|
||||
formComponent.form = null;
|
||||
@ -462,7 +437,7 @@ describe('FormComponent', () => {
|
||||
|
||||
it('should not execute unknown system outcome', () => {
|
||||
const formModel = new FormModel();
|
||||
const outcome = new FormOutcomeModel(formModel, { id: 'unknown', name: 'Unknown', isSystem: true });
|
||||
const outcome = new FormOutcomeModel(formModel, {id: 'unknown', name: 'Unknown', isSystem: true});
|
||||
|
||||
formComponent.form = formModel;
|
||||
expect(formComponent.onOutcomeClicked(outcome)).toBeFalsy();
|
||||
@ -470,26 +445,26 @@ describe('FormComponent', () => {
|
||||
|
||||
it('should require custom action name to complete form', () => {
|
||||
const formModel = new FormModel();
|
||||
let outcome = new FormOutcomeModel(formModel, { id: 'custom' });
|
||||
let outcome = new FormOutcomeModel(formModel, {id: 'custom'});
|
||||
|
||||
formComponent.form = formModel;
|
||||
expect(formComponent.onOutcomeClicked(outcome)).toBeFalsy();
|
||||
|
||||
outcome = new FormOutcomeModel(formModel, { id: 'custom', name: 'Custom' });
|
||||
outcome = new FormOutcomeModel(formModel, {id: 'custom', name: 'Custom'});
|
||||
spyOn(formComponent, 'completeTaskForm').and.stub();
|
||||
expect(formComponent.onOutcomeClicked(outcome)).toBeTruthy();
|
||||
});
|
||||
|
||||
it('should fetch and parse form by task id', (done) => {
|
||||
spyOn(formService, 'getTask').and.returnValue(of({}));
|
||||
spyOn(formService, 'getTaskForm').and.callFake((currentTaskId) => new Observable((observer) => {
|
||||
observer.next({ taskId: currentTaskId });
|
||||
spyOn(taskService, 'getTask').and.returnValue(of(<TaskRepresentation>{}));
|
||||
spyOn(taskFormService, 'getTaskForm').and.callFake((currentTaskId) => new Observable((observer) => {
|
||||
observer.next({taskId: currentTaskId});
|
||||
observer.complete();
|
||||
}));
|
||||
|
||||
const taskId = '456';
|
||||
formComponent.formLoaded.subscribe(() => {
|
||||
expect(formService.getTaskForm).toHaveBeenCalledWith(taskId);
|
||||
expect(taskFormService.getTaskForm).toHaveBeenCalledWith(taskId);
|
||||
expect(formComponent.form).toBeDefined();
|
||||
expect(formComponent.form.taskId).toBe(taskId);
|
||||
done();
|
||||
@ -502,9 +477,9 @@ describe('FormComponent', () => {
|
||||
it('should handle error when getting form by task id', (done) => {
|
||||
const error = 'Some error';
|
||||
|
||||
spyOn(formService, 'getTask').and.returnValue(of({}));
|
||||
spyOn(taskService, 'getTask').and.returnValue(of(<TaskRepresentation>{}));
|
||||
spyOn(formComponent, 'handleError').and.stub();
|
||||
spyOn(formService, 'getTaskForm').and.callFake(() => throwError(error));
|
||||
spyOn(taskFormService, 'getTaskForm').and.callFake(() => throwError(error));
|
||||
|
||||
formComponent.getFormByTaskId('123').then((_) => {
|
||||
expect(formComponent.handleError).toHaveBeenCalledWith(error);
|
||||
@ -513,9 +488,9 @@ describe('FormComponent', () => {
|
||||
});
|
||||
|
||||
it('should apply readonly state when getting form by task id', (done) => {
|
||||
spyOn(formService, 'getTask').and.returnValue(of({}));
|
||||
spyOn(formService, 'getTaskForm').and.callFake((taskId) => new Observable((observer) => {
|
||||
observer.next({ taskId });
|
||||
spyOn(taskService, 'getTask').and.returnValue(of(<TaskRepresentation>{}));
|
||||
spyOn(taskFormService, 'getTaskForm').and.callFake((taskId) => new Observable((observer) => {
|
||||
observer.next({taskId});
|
||||
observer.complete();
|
||||
}));
|
||||
|
||||
@ -528,8 +503,8 @@ describe('FormComponent', () => {
|
||||
});
|
||||
|
||||
it('should fetch and parse form definition by id', () => {
|
||||
spyOn(formService, 'getFormDefinitionById').and.callFake((currentFormId) => new Observable((observer) => {
|
||||
observer.next({ id: currentFormId });
|
||||
spyOn(editorService, 'getFormDefinitionById').and.callFake((currentFormId) => new Observable((observer) => {
|
||||
observer.next({id: currentFormId});
|
||||
observer.complete();
|
||||
}));
|
||||
|
||||
@ -549,20 +524,20 @@ describe('FormComponent', () => {
|
||||
const error = 'Some error';
|
||||
|
||||
spyOn(formComponent, 'handleError').and.stub();
|
||||
spyOn(formService, 'getFormDefinitionById').and.callFake(() => throwError(error));
|
||||
spyOn(editorService, 'getFormDefinitionById').and.callFake(() => throwError(error));
|
||||
|
||||
formComponent.getFormDefinitionByFormId(123);
|
||||
expect(formComponent.handleError).toHaveBeenCalledWith(error);
|
||||
});
|
||||
|
||||
it('should fetch and parse form definition by form name', () => {
|
||||
spyOn(formService, 'getFormDefinitionByName').and.callFake((currentFormName) => new Observable((observer) => {
|
||||
spyOn(modelService, 'getFormDefinitionByName').and.callFake((currentFormName) => new Observable((observer) => {
|
||||
observer.next(currentFormName);
|
||||
observer.complete();
|
||||
}));
|
||||
|
||||
spyOn(formService, 'getFormDefinitionById').and.callFake((currentFormName) => new Observable((observer) => {
|
||||
observer.next({ name: currentFormName });
|
||||
spyOn(editorService, 'getFormDefinitionById').and.callFake((currentFormName) => new Observable((observer) => {
|
||||
observer.next({name: currentFormName});
|
||||
observer.complete();
|
||||
}));
|
||||
|
||||
@ -574,13 +549,13 @@ describe('FormComponent', () => {
|
||||
formComponent.getFormDefinitionByFormName(formName);
|
||||
|
||||
expect(loaded).toBeTruthy();
|
||||
expect(formService.getFormDefinitionByName).toHaveBeenCalledWith(formName);
|
||||
expect(modelService.getFormDefinitionByName).toHaveBeenCalledWith(formName);
|
||||
expect(formComponent.form).toBeDefined();
|
||||
expect(formComponent.form.name).toBe(formName);
|
||||
});
|
||||
|
||||
it('should save task form and raise corresponding event', () => {
|
||||
spyOn(formService, 'saveTaskForm').and.callFake(() => new Observable((observer) => {
|
||||
spyOn(taskFormService, 'saveTaskForm').and.callFake(() => new Observable((observer) => {
|
||||
observer.next();
|
||||
observer.complete();
|
||||
}));
|
||||
@ -595,31 +570,31 @@ describe('FormComponent', () => {
|
||||
const formModel = new FormModel({
|
||||
taskId: '123',
|
||||
fields: [
|
||||
{ id: 'field1' },
|
||||
{ id: 'field2' }
|
||||
{id: 'field1'},
|
||||
{id: 'field2'}
|
||||
]
|
||||
});
|
||||
formComponent.form = formModel;
|
||||
formComponent.saveTaskForm();
|
||||
|
||||
expect(formService.saveTaskForm).toHaveBeenCalledWith(formModel.taskId, formModel.values);
|
||||
expect(taskFormService.saveTaskForm).toHaveBeenCalledWith(formModel.taskId, formModel.values);
|
||||
expect(saved).toBeTruthy();
|
||||
expect(savedForm).toEqual(formModel);
|
||||
});
|
||||
|
||||
it('should handle error during form save', () => {
|
||||
const error = 'Error';
|
||||
spyOn(formService, 'saveTaskForm').and.callFake(() => throwError(error));
|
||||
spyOn(taskFormService, 'saveTaskForm').and.callFake(() => throwError(error));
|
||||
spyOn(formComponent, 'handleError').and.stub();
|
||||
|
||||
formComponent.form = new FormModel({ taskId: '123' });
|
||||
formComponent.form = new FormModel({taskId: '123'});
|
||||
formComponent.saveTaskForm();
|
||||
|
||||
expect(formComponent.handleError).toHaveBeenCalledWith(error);
|
||||
});
|
||||
|
||||
it('should require form with task id to save', () => {
|
||||
spyOn(formService, 'saveTaskForm').and.stub();
|
||||
spyOn(taskFormService, 'saveTaskForm').and.stub();
|
||||
|
||||
formComponent.form = null;
|
||||
formComponent.saveTaskForm();
|
||||
@ -627,11 +602,11 @@ describe('FormComponent', () => {
|
||||
formComponent.form = new FormModel();
|
||||
formComponent.saveTaskForm();
|
||||
|
||||
expect(formService.saveTaskForm).not.toHaveBeenCalled();
|
||||
expect(taskFormService.saveTaskForm).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should require form with task id to complete', () => {
|
||||
spyOn(formService, 'completeTaskForm').and.stub();
|
||||
spyOn(taskFormService, 'completeTaskForm').and.stub();
|
||||
|
||||
formComponent.form = null;
|
||||
formComponent.completeTaskForm('save');
|
||||
@ -639,11 +614,11 @@ describe('FormComponent', () => {
|
||||
formComponent.form = new FormModel();
|
||||
formComponent.completeTaskForm('complete');
|
||||
|
||||
expect(formService.completeTaskForm).not.toHaveBeenCalled();
|
||||
expect(taskFormService.completeTaskForm).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should complete form and raise corresponding event', () => {
|
||||
spyOn(formService, 'completeTaskForm').and.callFake(() => new Observable((observer) => {
|
||||
spyOn(taskFormService, 'completeTaskForm').and.callFake(() => new Observable((observer) => {
|
||||
observer.next();
|
||||
observer.complete();
|
||||
}));
|
||||
@ -655,15 +630,15 @@ describe('FormComponent', () => {
|
||||
const formModel = new FormModel({
|
||||
taskId: '123',
|
||||
fields: [
|
||||
{ id: 'field1' },
|
||||
{ id: 'field2' }
|
||||
{id: 'field1'},
|
||||
{id: 'field2'}
|
||||
]
|
||||
});
|
||||
|
||||
formComponent.form = formModel;
|
||||
formComponent.completeTaskForm(outcome);
|
||||
|
||||
expect(formService.completeTaskForm).toHaveBeenCalledWith(formModel.taskId, formModel.values, outcome);
|
||||
expect(taskFormService.completeTaskForm).toHaveBeenCalledWith(formModel.taskId, formModel.values, outcome);
|
||||
expect(completed).toBeTruthy();
|
||||
});
|
||||
|
||||
@ -675,7 +650,7 @@ describe('FormComponent', () => {
|
||||
const form = formComponent.parseForm({
|
||||
id: 1,
|
||||
fields: [
|
||||
{ id: 'field1', type: FormFieldTypes.CONTAINER }
|
||||
{id: 'field1', type: FormFieldTypes.CONTAINER}
|
||||
]
|
||||
});
|
||||
|
||||
@ -688,7 +663,7 @@ describe('FormComponent', () => {
|
||||
it('should provide outcomes for form definition', () => {
|
||||
spyOn(formComponent, 'getFormDefinitionOutcomes').and.callThrough();
|
||||
|
||||
const form = formComponent.parseForm({ id: 1 });
|
||||
const form = formComponent.parseForm({id: 1});
|
||||
expect(formComponent.getFormDefinitionOutcomes).toHaveBeenCalledWith(form);
|
||||
});
|
||||
|
||||
@ -753,7 +728,7 @@ describe('FormComponent', () => {
|
||||
|
||||
const nodeId = '<id>';
|
||||
const change = new SimpleChange(null, nodeId, false);
|
||||
formComponent.ngOnChanges({ nodeId: change });
|
||||
formComponent.ngOnChanges({nodeId: change});
|
||||
|
||||
expect(nodeService.getNodeMetadata).toHaveBeenCalledWith(nodeId);
|
||||
expect(formComponent.loadFormFromActiviti).toHaveBeenCalled();
|
||||
@ -973,10 +948,10 @@ describe('FormComponent', () => {
|
||||
id: 'option_2',
|
||||
name: 'test2'
|
||||
};
|
||||
formValues.radio = { id: 'option_2', name: 'Option 2' };
|
||||
formValues.radio = {id: 'option_2', name: 'Option 2'};
|
||||
const change = new SimpleChange(null, formValues, false);
|
||||
formComponent.data = formValues;
|
||||
formComponent.ngOnChanges({ data: change });
|
||||
formComponent.ngOnChanges({data: change});
|
||||
|
||||
formFields = formComponent.form.getFormFields();
|
||||
dropdownField = formFields.find((field) => field.id === 'dropdownId');
|
||||
@ -996,7 +971,7 @@ describe('FormComponent', () => {
|
||||
formValues.radio = 'option_3';
|
||||
const change = new SimpleChange(null, formValues, false);
|
||||
formComponent.data = formValues;
|
||||
formComponent.ngOnChanges({ data: change });
|
||||
formComponent.ngOnChanges({data: change});
|
||||
|
||||
formFields = formComponent.form.getFormFields();
|
||||
radioFieldById = formFields.find((field) => field.id === 'radio');
|
||||
@ -1021,7 +996,7 @@ describe('FormComponent', () => {
|
||||
|
||||
class FormWithCustomOutComesComponent {
|
||||
|
||||
@ViewChild('adfForm', { static: true })
|
||||
@ViewChild('adfForm', {static: true})
|
||||
adfForm: FormComponent;
|
||||
|
||||
onCustomButtonOneClick() {
|
||||
@ -1051,10 +1026,10 @@ describe('FormWithCustomOutComesComponent', () => {
|
||||
debugElement = fixture.debugElement;
|
||||
const formRepresentation = {
|
||||
fields: [
|
||||
{ id: 'container1' }
|
||||
{id: 'container1'}
|
||||
],
|
||||
outcomes: [
|
||||
{ id: 'outcome-1', name: 'outcome 1' }
|
||||
{id: 'outcome-1', name: 'outcome 1'}
|
||||
]
|
||||
};
|
||||
|
||||
|
@ -15,13 +15,41 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { Component, EventEmitter, Input, Output, ViewEncapsulation, SimpleChanges, OnInit, OnDestroy, OnChanges } from '@angular/core';
|
||||
import { EcmModelService, NodeService, WidgetVisibilityService,
|
||||
FormService, FormBaseComponent, FormOutcomeModel,
|
||||
FormEvent, FormErrorEvent, FormFieldModel,
|
||||
FormModel, FormOutcomeEvent, FormValues, ContentLinkModel } from '@alfresco/adf-core';
|
||||
import { Observable, of, Subject } from 'rxjs';
|
||||
import {
|
||||
Component,
|
||||
EventEmitter,
|
||||
Input,
|
||||
Output,
|
||||
ViewEncapsulation,
|
||||
SimpleChanges,
|
||||
OnInit,
|
||||
OnDestroy,
|
||||
OnChanges
|
||||
} from '@angular/core';
|
||||
import {
|
||||
WidgetVisibilityService,
|
||||
FormService,
|
||||
FormBaseComponent,
|
||||
FormOutcomeModel,
|
||||
FormEvent,
|
||||
FormErrorEvent,
|
||||
FormFieldModel,
|
||||
FormModel,
|
||||
FormOutcomeEvent,
|
||||
FormValues,
|
||||
ContentLinkModel,
|
||||
NodesApiService,
|
||||
FormDefinitionModel,
|
||||
TaskProcessVariableModel
|
||||
} from '@alfresco/adf-core';
|
||||
import { from, Observable, of, Subject } from 'rxjs';
|
||||
import { switchMap, takeUntil } from 'rxjs/operators';
|
||||
import { EcmModelService } from './services/ecm-model.service';
|
||||
import { ModelService } from './services/model.service';
|
||||
import { EditorService } from './services/editor.service';
|
||||
import { TaskService } from './services/task.service';
|
||||
import { TaskFormService } from './services/task-form.service';
|
||||
import { TaskRepresentation } from '@alfresco/js-api';
|
||||
|
||||
@Component({
|
||||
selector: 'adf-form',
|
||||
@ -59,7 +87,7 @@ export class FormComponent extends FormBaseComponent implements OnInit, OnDestro
|
||||
data: FormValues;
|
||||
|
||||
/** The form will set a prefixed space for invisible fields. */
|
||||
@Input()
|
||||
@Input()
|
||||
enableFixedSpacedForm: boolean = true;
|
||||
|
||||
/** Emitted when the form is submitted with the `Save` or custom outcomes. */
|
||||
@ -87,9 +115,13 @@ export class FormComponent extends FormBaseComponent implements OnInit, OnDestro
|
||||
protected onDestroy$ = new Subject<boolean>();
|
||||
|
||||
constructor(protected formService: FormService,
|
||||
protected taskFormService: TaskFormService,
|
||||
protected taskService: TaskService,
|
||||
protected editorService: EditorService,
|
||||
protected modelService: ModelService,
|
||||
protected visibilityService: WidgetVisibilityService,
|
||||
protected ecmModelService: EcmModelService,
|
||||
protected nodeService: NodeService) {
|
||||
protected nodeService: NodesApiService) {
|
||||
super();
|
||||
}
|
||||
|
||||
@ -168,13 +200,13 @@ export class FormComponent extends FormBaseComponent implements OnInit, OnDestro
|
||||
}
|
||||
}
|
||||
|
||||
findProcessVariablesByTaskId(taskId: string): Observable<any> {
|
||||
return this.formService.getTask(taskId).pipe(
|
||||
switchMap((task: any) => {
|
||||
findProcessVariablesByTaskId(taskId: string): Observable<TaskProcessVariableModel[]> {
|
||||
return this.taskService.getTask(taskId).pipe(
|
||||
switchMap((task: TaskRepresentation) => {
|
||||
if (this.isAProcessTask(task)) {
|
||||
return this.visibilityService.getTaskProcessVariable(taskId);
|
||||
return this.taskFormService.getTaskProcessVariable(taskId);
|
||||
} else {
|
||||
return of({});
|
||||
return of([]);
|
||||
}
|
||||
})
|
||||
);
|
||||
@ -186,13 +218,13 @@ export class FormComponent extends FormBaseComponent implements OnInit, OnDestro
|
||||
|
||||
getFormByTaskId(taskId: string): Promise<FormModel> {
|
||||
return new Promise<FormModel>(resolve => {
|
||||
this.findProcessVariablesByTaskId(taskId).subscribe(() => {
|
||||
this.formService
|
||||
this.findProcessVariablesByTaskId(taskId).subscribe((taskProcessVariables) => {
|
||||
this.taskFormService
|
||||
.getTaskForm(taskId)
|
||||
.subscribe(
|
||||
(form) => {
|
||||
const parsedForm = this.parseForm(form);
|
||||
this.visibilityService.refreshVisibility(parsedForm);
|
||||
this.visibilityService.refreshVisibility(parsedForm, taskProcessVariables);
|
||||
parsedForm.validateForm();
|
||||
this.form = parsedForm;
|
||||
this.onFormLoaded(this.form);
|
||||
@ -208,7 +240,7 @@ export class FormComponent extends FormBaseComponent implements OnInit, OnDestro
|
||||
}
|
||||
|
||||
getFormDefinitionByFormId(formId: number) {
|
||||
this.formService
|
||||
this.editorService
|
||||
.getFormDefinitionById(formId)
|
||||
.subscribe(
|
||||
(form) => {
|
||||
@ -225,11 +257,11 @@ export class FormComponent extends FormBaseComponent implements OnInit, OnDestro
|
||||
}
|
||||
|
||||
getFormDefinitionByFormName(formName: string) {
|
||||
this.formService
|
||||
this.modelService
|
||||
.getFormDefinitionByName(formName)
|
||||
.subscribe(
|
||||
(id) => {
|
||||
this.formService.getFormDefinitionById(id).subscribe(
|
||||
this.editorService.getFormDefinitionById(id).subscribe(
|
||||
(form) => {
|
||||
this.form = this.parseForm(form);
|
||||
this.visibilityService.refreshVisibility(this.form);
|
||||
@ -249,7 +281,7 @@ export class FormComponent extends FormBaseComponent implements OnInit, OnDestro
|
||||
|
||||
saveTaskForm() {
|
||||
if (this.form && this.form.taskId) {
|
||||
this.formService
|
||||
this.taskFormService
|
||||
.saveTaskForm(this.form.taskId, this.form.values)
|
||||
.subscribe(
|
||||
() => {
|
||||
@ -263,7 +295,7 @@ export class FormComponent extends FormBaseComponent implements OnInit, OnDestro
|
||||
|
||||
completeTaskForm(outcome?: string) {
|
||||
if (this.form && this.form.taskId) {
|
||||
this.formService
|
||||
this.taskFormService
|
||||
.completeTaskForm(this.form.taskId, this.form.values, outcome)
|
||||
.subscribe(
|
||||
() => {
|
||||
@ -300,7 +332,7 @@ export class FormComponent extends FormBaseComponent implements OnInit, OnDestro
|
||||
*/
|
||||
getFormDefinitionOutcomes(form: FormModel): FormOutcomeModel[] {
|
||||
return [
|
||||
new FormOutcomeModel(form, { id: '$save', name: FormOutcomeModel.SAVE_ACTION, isSystem: true })
|
||||
new FormOutcomeModel(form, {id: '$save', name: FormOutcomeModel.SAVE_ACTION, isSystem: true})
|
||||
];
|
||||
}
|
||||
|
||||
@ -311,10 +343,10 @@ export class FormComponent extends FormBaseComponent implements OnInit, OnDestro
|
||||
}
|
||||
|
||||
loadFormFromActiviti(nodeType: string): any {
|
||||
this.formService.searchFrom(nodeType).subscribe(
|
||||
this.modelService.searchFrom(nodeType).subscribe(
|
||||
(form) => {
|
||||
if (!form) {
|
||||
this.formService.createFormFromANode(nodeType).subscribe((formMetadata) => {
|
||||
this.createFormFromANode(nodeType).subscribe((formMetadata) => {
|
||||
this.loadFormFromFormId(formMetadata.id);
|
||||
});
|
||||
} else {
|
||||
@ -327,6 +359,33 @@ export class FormComponent extends FormBaseComponent implements OnInit, OnDestro
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Creates a Form with a field for each metadata property.
|
||||
*
|
||||
* @param formName Name of the new form
|
||||
* @returns The new form
|
||||
*/
|
||||
createFormFromANode(formName: string): Observable<any> {
|
||||
return new Observable((observer) => {
|
||||
this.modelService.createForm(formName).subscribe(
|
||||
(form) => {
|
||||
this.ecmModelService.searchEcmType(formName, EcmModelService.MODEL_NAME).subscribe(
|
||||
(customType) => {
|
||||
const formDefinitionModel = new FormDefinitionModel(form.id, form.name, form.lastUpdatedByFullName, form.lastUpdated, customType.entry.properties);
|
||||
from(
|
||||
this.editorService.saveForm(form.id, formDefinitionModel)
|
||||
).subscribe((formData) => {
|
||||
observer.next(formData);
|
||||
observer.complete();
|
||||
}, (err) => this.handleError(err));
|
||||
},
|
||||
(err) => this.handleError(err));
|
||||
},
|
||||
(err) => this.handleError(err));
|
||||
});
|
||||
}
|
||||
|
||||
protected storeFormAsMetadata() {
|
||||
if (this.saveMetadata) {
|
||||
this.ecmModelService.createEcmTypeForActivitiForm(this.formName, this.form).subscribe((type) => {
|
||||
|
@ -21,17 +21,23 @@ import { of } from 'rxjs';
|
||||
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
import { By } from '@angular/platform-browser';
|
||||
|
||||
import { formDefinitionDropdownField, formDefinitionTwoTextFields,
|
||||
formDefinitionRequiredField, FormService, setupTestBed,
|
||||
import {
|
||||
formDefinitionDropdownField, formDefinitionTwoTextFields,
|
||||
formDefinitionRequiredField, setupTestBed,
|
||||
formDefVisibilitiFieldDependsOnNextOne, formDefVisibilitiFieldDependsOnPreviousOne,
|
||||
formReadonlyTwoTextFields } from '@alfresco/adf-core';
|
||||
formReadonlyTwoTextFields
|
||||
} from '@alfresco/adf-core';
|
||||
import { FormComponent } from './form.component';
|
||||
import { ProcessTestingModule } from '../testing/process.testing.module';
|
||||
import { TranslateModule } from '@ngx-translate/core';
|
||||
import { TaskService } from './services/task.service';
|
||||
import { TaskFormService } from './services/task-form.service';
|
||||
import { TaskRepresentation } from '@alfresco/js-api';
|
||||
|
||||
describe('FormComponent UI and visibility', () => {
|
||||
let component: FormComponent;
|
||||
let service: FormService;
|
||||
let taskService: TaskService;
|
||||
let taskFormService: TaskFormService;
|
||||
let fixture: ComponentFixture<FormComponent>;
|
||||
|
||||
const openSelect = () => {
|
||||
@ -50,7 +56,8 @@ describe('FormComponent UI and visibility', () => {
|
||||
beforeEach(() => {
|
||||
fixture = TestBed.createComponent(FormComponent);
|
||||
component = fixture.componentInstance;
|
||||
service = TestBed.inject(FormService);
|
||||
taskService = TestBed.inject(TaskService);
|
||||
taskFormService = TestBed.inject(TaskFormService);
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
@ -60,11 +67,11 @@ describe('FormComponent UI and visibility', () => {
|
||||
describe('Validation icon', () => {
|
||||
|
||||
it('should display valid icon for valid form', () => {
|
||||
spyOn(service, 'getTask').and.returnValue(of({}));
|
||||
spyOn(service, 'getTaskForm').and.returnValue(of(formDefinitionTwoTextFields));
|
||||
spyOn(taskService, 'getTask').and.returnValue(of(<TaskRepresentation>{}));
|
||||
spyOn(taskFormService, 'getTaskForm').and.returnValue(of(formDefinitionTwoTextFields));
|
||||
|
||||
const change = new SimpleChange(null, 1, true);
|
||||
component.ngOnChanges({ taskId: change });
|
||||
component.ngOnChanges({taskId: change});
|
||||
fixture.detectChanges();
|
||||
expect(fixture.debugElement.query(By.css('#adf-valid-form-icon'))).toBeDefined();
|
||||
expect(fixture.debugElement.query(By.css('#adf-valid-form-icon'))).not.toBeNull();
|
||||
@ -72,11 +79,11 @@ describe('FormComponent UI and visibility', () => {
|
||||
});
|
||||
|
||||
it('should display invalid icon for valid form', () => {
|
||||
spyOn(service, 'getTask').and.returnValue(of({}));
|
||||
spyOn(service, 'getTaskForm').and.returnValue(of(formDefinitionRequiredField));
|
||||
spyOn(taskService, 'getTask').and.returnValue(of(<TaskRepresentation>{}));
|
||||
spyOn(taskFormService, 'getTaskForm').and.returnValue(of(formDefinitionRequiredField));
|
||||
|
||||
const change = new SimpleChange(null, 1, true);
|
||||
component.ngOnChanges({ taskId: change });
|
||||
component.ngOnChanges({taskId: change});
|
||||
fixture.detectChanges();
|
||||
expect(fixture.debugElement.query(By.css('#adf-valid-form-icon'))).toBeNull();
|
||||
expect(fixture.debugElement.query(By.css('#adf-invalid-form-icon'))).toBeDefined();
|
||||
@ -84,11 +91,11 @@ describe('FormComponent UI and visibility', () => {
|
||||
});
|
||||
|
||||
it('should NOT display validation icon when [showValidationIcon] is false', () => {
|
||||
spyOn(service, 'getTask').and.returnValue(of({}));
|
||||
spyOn(service, 'getTaskForm').and.returnValue(of(formDefinitionTwoTextFields));
|
||||
spyOn(taskService, 'getTask').and.returnValue(of(<TaskRepresentation>{}));
|
||||
spyOn(taskFormService, 'getTaskForm').and.returnValue(of(formDefinitionTwoTextFields));
|
||||
|
||||
const change = new SimpleChange(null, 1, true);
|
||||
component.ngOnChanges({ taskId: change });
|
||||
component.ngOnChanges({taskId: change});
|
||||
component.showValidationIcon = false;
|
||||
fixture.detectChanges();
|
||||
expect(fixture.debugElement.query(By.css('#adf-valid-form-icon'))).toBeNull();
|
||||
@ -99,11 +106,11 @@ describe('FormComponent UI and visibility', () => {
|
||||
describe('form definition', () => {
|
||||
|
||||
it('should display two text fields form definition', () => {
|
||||
spyOn(service, 'getTask').and.returnValue(of({}));
|
||||
spyOn(service, 'getTaskForm').and.returnValue(of(formDefinitionTwoTextFields));
|
||||
spyOn(taskService, 'getTask').and.returnValue(of(<TaskRepresentation>{}));
|
||||
spyOn(taskFormService, 'getTaskForm').and.returnValue(of(formDefinitionTwoTextFields));
|
||||
|
||||
const change = new SimpleChange(null, 1, true);
|
||||
component.ngOnChanges({ taskId: change });
|
||||
component.ngOnChanges({taskId: change});
|
||||
fixture.detectChanges();
|
||||
|
||||
const firstNameEl = fixture.debugElement.query(By.css('#firstname'));
|
||||
@ -116,11 +123,11 @@ describe('FormComponent UI and visibility', () => {
|
||||
});
|
||||
|
||||
it('should display dropdown field', async () => {
|
||||
spyOn(service, 'getTask').and.returnValue(of({}));
|
||||
spyOn(service, 'getTaskForm').and.returnValue(of(formDefinitionDropdownField));
|
||||
spyOn(taskService, 'getTask').and.returnValue(of(<TaskRepresentation>{}));
|
||||
spyOn(taskFormService, 'getTaskForm').and.returnValue(of(formDefinitionDropdownField));
|
||||
|
||||
const change = new SimpleChange(null, 1, true);
|
||||
component.ngOnChanges({ taskId: change });
|
||||
component.ngOnChanges({taskId: change});
|
||||
fixture.detectChanges();
|
||||
await fixture.whenStable();
|
||||
|
||||
@ -150,11 +157,11 @@ describe('FormComponent UI and visibility', () => {
|
||||
describe('Visibility conditions', () => {
|
||||
|
||||
it('should hide the field based on the next one', () => {
|
||||
spyOn(service, 'getTask').and.returnValue(of({}));
|
||||
spyOn(service, 'getTaskForm').and.returnValue(of(formDefVisibilitiFieldDependsOnNextOne));
|
||||
spyOn(taskService, 'getTask').and.returnValue(of(<TaskRepresentation>{}));
|
||||
spyOn(taskFormService, 'getTaskForm').and.returnValue(of(formDefVisibilitiFieldDependsOnNextOne));
|
||||
|
||||
const change = new SimpleChange(null, 1, true);
|
||||
component.ngOnChanges({ taskId: change });
|
||||
component.ngOnChanges({taskId: change});
|
||||
fixture.detectChanges();
|
||||
|
||||
const firstEl = fixture.debugElement.query(By.css('#field-country-container'));
|
||||
@ -167,11 +174,11 @@ describe('FormComponent UI and visibility', () => {
|
||||
});
|
||||
|
||||
it('should hide the field based on the previous one', () => {
|
||||
spyOn(service, 'getTask').and.returnValue(of({}));
|
||||
spyOn(service, 'getTaskForm').and.returnValue(of(formDefVisibilitiFieldDependsOnPreviousOne));
|
||||
spyOn(taskService, 'getTask').and.returnValue(of(<TaskRepresentation>{}));
|
||||
spyOn(taskFormService, 'getTaskForm').and.returnValue(of(formDefVisibilitiFieldDependsOnPreviousOne));
|
||||
|
||||
const change = new SimpleChange(null, 1, true);
|
||||
component.ngOnChanges({ taskId: change });
|
||||
component.ngOnChanges({taskId: change});
|
||||
fixture.detectChanges();
|
||||
|
||||
const firstEl = fixture.debugElement.query(By.css('#name'));
|
||||
@ -184,11 +191,11 @@ describe('FormComponent UI and visibility', () => {
|
||||
});
|
||||
|
||||
it('should show the hidden field when the visibility condition change to true', () => {
|
||||
spyOn(service, 'getTask').and.returnValue(of({}));
|
||||
spyOn(service, 'getTaskForm').and.returnValue(of(formDefVisibilitiFieldDependsOnNextOne));
|
||||
spyOn(taskService, 'getTask').and.returnValue(of(<TaskRepresentation>{}));
|
||||
spyOn(taskFormService, 'getTaskForm').and.returnValue(of(formDefVisibilitiFieldDependsOnNextOne));
|
||||
|
||||
const change = new SimpleChange(null, 1, true);
|
||||
component.ngOnChanges({ taskId: change });
|
||||
component.ngOnChanges({taskId: change});
|
||||
fixture.detectChanges();
|
||||
|
||||
let firstEl = fixture.debugElement.query(By.css('#field-country-container'));
|
||||
@ -209,11 +216,11 @@ describe('FormComponent UI and visibility', () => {
|
||||
|
||||
describe('Readonly Form', () => {
|
||||
it('should display two text fields readonly', async () => {
|
||||
spyOn(service, 'getTask').and.returnValue(of({}));
|
||||
spyOn(service, 'getTaskForm').and.returnValue(of(formReadonlyTwoTextFields));
|
||||
spyOn(taskService, 'getTask').and.returnValue(of(<TaskRepresentation>{}));
|
||||
spyOn(taskFormService, 'getTaskForm').and.returnValue(of(formReadonlyTwoTextFields));
|
||||
|
||||
const change = new SimpleChange(null, 1, true);
|
||||
component.ngOnChanges({ taskId: change });
|
||||
component.ngOnChanges({taskId: change});
|
||||
|
||||
fixture.detectChanges();
|
||||
await fixture.whenStable();
|
||||
|
@ -21,21 +21,48 @@ import { CoreModule } from '@alfresco/adf-core';
|
||||
import { FormComponent } from './form.component';
|
||||
import { StartFormComponent } from './start-form.component';
|
||||
import { FormCustomOutcomesComponent } from './form-custom-outcomes.component';
|
||||
import { DocumentWidgetComponent } from './widgets/document/document.widget';
|
||||
import { ContentWidgetComponent } from './widgets/document/content.widget';
|
||||
import { UploadWidgetComponent } from './widgets/upload/upload.widget';
|
||||
import { FormListComponent } from './form-list/form-list.component';
|
||||
import { FunctionalGroupWidgetComponent } from './widgets/functional-group/functional-group.widget';
|
||||
import { PeopleWidgetComponent } from './widgets/people/people.widget';
|
||||
import { RadioButtonsWidgetComponent } from './widgets/radio-buttons/radio-buttons.widget';
|
||||
import { TypeaheadWidgetComponent } from './widgets/typeahead/typeahead.widget';
|
||||
import { DropdownWidgetComponent } from './widgets/dropdown/dropdown.widget';
|
||||
import { DynamicTableModule } from './widgets/dynamic-table/dynamic-table.module';
|
||||
|
||||
@NgModule({
|
||||
imports: [
|
||||
DynamicTableModule,
|
||||
CoreModule,
|
||||
MaterialModule
|
||||
],
|
||||
declarations: [
|
||||
UploadWidgetComponent,
|
||||
FormComponent,
|
||||
StartFormComponent,
|
||||
FormCustomOutcomesComponent
|
||||
FormCustomOutcomesComponent,
|
||||
DocumentWidgetComponent,
|
||||
ContentWidgetComponent,
|
||||
PeopleWidgetComponent,
|
||||
FunctionalGroupWidgetComponent,
|
||||
FormListComponent,
|
||||
RadioButtonsWidgetComponent,
|
||||
DropdownWidgetComponent,
|
||||
TypeaheadWidgetComponent
|
||||
],
|
||||
exports: [
|
||||
FormComponent,
|
||||
StartFormComponent,
|
||||
FormCustomOutcomesComponent
|
||||
FormCustomOutcomesComponent,
|
||||
PeopleWidgetComponent,
|
||||
FunctionalGroupWidgetComponent,
|
||||
RadioButtonsWidgetComponent,
|
||||
TypeaheadWidgetComponent,
|
||||
DropdownWidgetComponent,
|
||||
FormListComponent
|
||||
]
|
||||
})
|
||||
export class FormModule {}
|
||||
export class FormModule {
|
||||
}
|
||||
|
@ -0,0 +1,103 @@
|
||||
/*!
|
||||
* @license
|
||||
* Copyright 2019 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 { ProcessFormRenderingService } from './process-form-rendering.service';
|
||||
import { FormFieldModel, FormFieldTypes } from '@alfresco/adf-core';
|
||||
import { AttachFolderWidgetComponent } from './widgets/content-widget/attach-folder-widget.component';
|
||||
import { DropdownWidgetComponent } from './widgets/dropdown/dropdown.widget';
|
||||
import { DynamicTableWidgetComponent } from './widgets/dynamic-table/dynamic-table.widget';
|
||||
import { FunctionalGroupWidgetComponent } from './widgets/functional-group/functional-group.widget';
|
||||
import { PeopleWidgetComponent } from './widgets/people/people.widget';
|
||||
import { RadioButtonsWidgetComponent } from './widgets/radio-buttons/radio-buttons.widget';
|
||||
import { TypeaheadWidgetComponent } from './widgets/typeahead/typeahead.widget';
|
||||
import { DocumentWidgetComponent } from './widgets/document/document.widget';
|
||||
import { AttachFileWidgetComponent } from './widgets/content-widget/attach-file-widget.component';
|
||||
|
||||
describe('ProcessFormRenderingService', () => {
|
||||
|
||||
let service: ProcessFormRenderingService;
|
||||
|
||||
beforeEach(() => {
|
||||
service = new ProcessFormRenderingService();
|
||||
});
|
||||
|
||||
it('should resolve Upload field as Upload widget', () => {
|
||||
const field = new FormFieldModel(null, {
|
||||
type: FormFieldTypes.UPLOAD,
|
||||
params: {
|
||||
link: null
|
||||
}
|
||||
});
|
||||
const type = service.resolveComponentType(field);
|
||||
expect(type).toBe(AttachFileWidgetComponent);
|
||||
});
|
||||
|
||||
it('should resolve Upload widget for Upload', () => {
|
||||
const resolver = service.getComponentTypeResolver(FormFieldTypes.UPLOAD);
|
||||
const type = resolver(null);
|
||||
expect(type).toBe(AttachFileWidgetComponent);
|
||||
});
|
||||
|
||||
it('should resolve Upload widget for dropdown', () => {
|
||||
const resolver = service.getComponentTypeResolver(FormFieldTypes.DROPDOWN);
|
||||
const type = resolver(null);
|
||||
expect(type).toBe(DropdownWidgetComponent);
|
||||
});
|
||||
|
||||
it('should resolve Upload widget for typeahead', () => {
|
||||
const resolver = service.getComponentTypeResolver(FormFieldTypes.TYPEAHEAD);
|
||||
const type = resolver(null);
|
||||
expect(type).toBe(TypeaheadWidgetComponent);
|
||||
});
|
||||
|
||||
it('should resolve Upload widget for radio button', () => {
|
||||
const resolver = service.getComponentTypeResolver(FormFieldTypes.RADIO_BUTTONS);
|
||||
const type = resolver(null);
|
||||
expect(type).toBe(RadioButtonsWidgetComponent);
|
||||
});
|
||||
|
||||
it('should resolve Upload widget for select folder', () => {
|
||||
const resolver = service.getComponentTypeResolver(FormFieldTypes.ATTACH_FOLDER);
|
||||
const type = resolver(null);
|
||||
expect(type).toBe(AttachFolderWidgetComponent);
|
||||
});
|
||||
|
||||
it('should resolve Upload widget for document', () => {
|
||||
const resolver = service.getComponentTypeResolver(FormFieldTypes.DOCUMENT);
|
||||
const type = resolver(null);
|
||||
expect(type).toBe(DocumentWidgetComponent);
|
||||
});
|
||||
|
||||
it('should resolve Upload widget for people', () => {
|
||||
const resolver = service.getComponentTypeResolver(FormFieldTypes.PEOPLE);
|
||||
const type = resolver(null);
|
||||
expect(type).toBe(PeopleWidgetComponent);
|
||||
});
|
||||
|
||||
it('should resolve Upload widget for group', () => {
|
||||
const resolver = service.getComponentTypeResolver(FormFieldTypes.FUNCTIONAL_GROUP);
|
||||
const type = resolver(null);
|
||||
expect(type).toBe(FunctionalGroupWidgetComponent);
|
||||
});
|
||||
|
||||
it('should resolve Upload widget for dynamic table', () => {
|
||||
const resolver = service.getComponentTypeResolver(FormFieldTypes.DYNAMIC_TABLE);
|
||||
const type = resolver(null);
|
||||
expect(type).toBe(DynamicTableWidgetComponent);
|
||||
});
|
||||
|
||||
});
|
@ -16,9 +16,19 @@
|
||||
*/
|
||||
|
||||
import { Injectable } from '@angular/core';
|
||||
import { FormRenderingService } from '@alfresco/adf-core';
|
||||
import { AttachFileWidgetComponent } from '../content-widget/attach-file-widget.component';
|
||||
import { AttachFolderWidgetComponent } from '../content-widget/attach-folder-widget.component';
|
||||
import {
|
||||
FormFieldTypes,
|
||||
FormRenderingService
|
||||
} from '@alfresco/adf-core';
|
||||
import { AttachFileWidgetComponent } from './widgets/content-widget/attach-file-widget.component';
|
||||
import { AttachFolderWidgetComponent } from './widgets/content-widget/attach-folder-widget.component';
|
||||
import { DocumentWidgetComponent } from './widgets/document/document.widget';
|
||||
import { PeopleWidgetComponent } from './widgets/people/people.widget';
|
||||
import { FunctionalGroupWidgetComponent } from './widgets/functional-group/functional-group.widget';
|
||||
import { RadioButtonsWidgetComponent } from './widgets/radio-buttons/radio-buttons.widget';
|
||||
import { TypeaheadWidgetComponent } from './widgets/typeahead/typeahead.widget';
|
||||
import { DynamicTableWidgetComponent } from './widgets/dynamic-table/dynamic-table.widget';
|
||||
import { DropdownWidgetComponent } from './widgets/dropdown/dropdown.widget';
|
||||
|
||||
@Injectable({
|
||||
providedIn: 'root'
|
||||
@ -28,8 +38,15 @@ export class ProcessFormRenderingService extends FormRenderingService {
|
||||
super();
|
||||
|
||||
this.register({
|
||||
upload: () => AttachFileWidgetComponent,
|
||||
'select-folder': () => AttachFolderWidgetComponent
|
||||
[FormFieldTypes.DROPDOWN]: () => DropdownWidgetComponent,
|
||||
[FormFieldTypes.TYPEAHEAD]: () => TypeaheadWidgetComponent,
|
||||
[FormFieldTypes.RADIO_BUTTONS]: () => RadioButtonsWidgetComponent,
|
||||
[FormFieldTypes.UPLOAD]: () => AttachFileWidgetComponent,
|
||||
[FormFieldTypes.ATTACH_FOLDER]: () => AttachFolderWidgetComponent,
|
||||
[FormFieldTypes.DOCUMENT]: () => DocumentWidgetComponent,
|
||||
[FormFieldTypes.PEOPLE]: () => PeopleWidgetComponent,
|
||||
[FormFieldTypes.FUNCTIONAL_GROUP]: () => FunctionalGroupWidgetComponent,
|
||||
[FormFieldTypes.DYNAMIC_TABLE]: () => DynamicTableWidgetComponent
|
||||
}, true);
|
||||
}
|
||||
}
|
||||
|
@ -15,8 +15,23 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
export * from './widgets/index';
|
||||
|
||||
export * from './services/ecm-model.service';
|
||||
export * from './services/editor.service';
|
||||
export * from './services/process-content.service';
|
||||
export * from './services/task.service';
|
||||
export * from './services/task-form.service';
|
||||
export * from './services/process-definition.service';
|
||||
export * from './services/activiti-alfresco.service';
|
||||
export * from './process-form-rendering.service';
|
||||
|
||||
export * from './events/validate-dynamic-table-row.event';
|
||||
|
||||
|
||||
export * from './form-list/form-list.component';
|
||||
export * from './form.component';
|
||||
export * from './start-form.component';
|
||||
export * from './process-form-rendering.service';
|
||||
export * from './form-custom-outcomes.component';
|
||||
|
||||
export * from './form.module';
|
||||
|
@ -15,9 +15,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { AlfrescoApiService } from '../../services/alfresco-api.service';
|
||||
import { LogService } from '../../services/log.service';
|
||||
import { SitesService } from '../../services/sites.service';
|
||||
import { AlfrescoApiService, LogService, SitesService, ExternalContent, ExternalContentLink } from '@alfresco/adf-core';
|
||||
import { Injectable } from '@angular/core';
|
||||
import {
|
||||
IntegrationAlfrescoOnPremiseApi,
|
||||
@ -26,8 +24,6 @@ import {
|
||||
ActivitiContentApi
|
||||
} from '@alfresco/js-api';
|
||||
import { Observable, from, throwError } from 'rxjs';
|
||||
import { ExternalContent } from '../components/widgets/core/external-content';
|
||||
import { ExternalContentLink } from '../components/widgets/core/external-content-link';
|
||||
import { map, catchError } from 'rxjs/operators';
|
||||
|
||||
@Injectable({
|
@ -16,11 +16,9 @@
|
||||
*/
|
||||
|
||||
import { Observable } from 'rxjs';
|
||||
import { FormModel } from '../components/widgets/core/form.model';
|
||||
import { FormModel, setupTestBed, CoreTestingModule } from '@alfresco/adf-core';
|
||||
import { EcmModelService } from './ecm-model.service';
|
||||
import { setupTestBed } from '../../testing/setup-test-bed';
|
||||
import { TestBed } from '@angular/core/testing';
|
||||
import { CoreTestingModule } from '../../testing/core.testing.module';
|
||||
import { TranslateModule } from '@ngx-translate/core';
|
||||
|
||||
declare let jasmine: any;
|
@ -15,11 +15,9 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { LogService } from '../../services/log.service';
|
||||
import { AlfrescoApiService } from '../../services/alfresco-api.service';
|
||||
import { AlfrescoApiService, LogService, FormModel } from '@alfresco/adf-core';
|
||||
import { Injectable } from '@angular/core';
|
||||
import { Observable, from } from 'rxjs';
|
||||
import { FormModel } from '../components/widgets/core/form.model';
|
||||
import { map, catchError } from 'rxjs/operators';
|
||||
import { CustomModelApi } from '@alfresco/js-api';
|
||||
|
||||
@ -216,7 +214,7 @@ export class EcmModelService {
|
||||
return {};
|
||||
}
|
||||
|
||||
handleError(err: any): any {
|
||||
private handleError(err: any): any {
|
||||
this.logService.error(err);
|
||||
}
|
||||
}
|
97
lib/process-services/src/lib/form/services/editor.service.ts
Normal file
97
lib/process-services/src/lib/form/services/editor.service.ts
Normal file
@ -0,0 +1,97 @@
|
||||
/*!
|
||||
* @license
|
||||
* Copyright 2019 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 { AlfrescoApiService, FormDefinitionModel, LogService } from '@alfresco/adf-core';
|
||||
import { Injectable } from '@angular/core';
|
||||
import { Observable, from, throwError } from 'rxjs';
|
||||
import { FormModelsApi } from '@alfresco/js-api';
|
||||
import { catchError, map } from 'rxjs/operators';
|
||||
|
||||
@Injectable({
|
||||
providedIn: 'root'
|
||||
})
|
||||
export class EditorService {
|
||||
|
||||
static UNKNOWN_ERROR_MESSAGE: string = 'Unknown error';
|
||||
static GENERIC_ERROR_MESSAGE: string = 'Server error';
|
||||
|
||||
_editorApi: FormModelsApi;
|
||||
get editorApi(): FormModelsApi {
|
||||
this._editorApi = this._editorApi ?? new FormModelsApi(this.apiService.getInstance());
|
||||
return this._editorApi;
|
||||
}
|
||||
|
||||
constructor(private apiService: AlfrescoApiService, private logService: LogService) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Saves a form.
|
||||
*
|
||||
* @param formId ID of the form to save
|
||||
* @param formModel Model data for the form
|
||||
* @returns Data for the saved form
|
||||
*/
|
||||
saveForm(formId: number, formModel: FormDefinitionModel): Observable<any> {
|
||||
return from(
|
||||
this.editorApi.saveForm(formId, formModel)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a form definition.
|
||||
*
|
||||
* @param formId ID of the target form
|
||||
* @returns Form definition
|
||||
*/
|
||||
getFormDefinitionById(formId: number): Observable<any> {
|
||||
return from(this.editorApi.getForm(formId))
|
||||
.pipe(
|
||||
map(this.toJson),
|
||||
catchError((err) => this.handleError(err))
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a JSON representation of form data.
|
||||
*
|
||||
* @param res Object representing form data
|
||||
* @returns JSON data
|
||||
*/
|
||||
toJson(res: any) {
|
||||
if (res) {
|
||||
return res || {};
|
||||
}
|
||||
return {};
|
||||
}
|
||||
|
||||
/**
|
||||
* Reports an error message.
|
||||
*
|
||||
* @param error Data object with optional `message` and `status` fields for the error
|
||||
* @returns Error message
|
||||
*/
|
||||
private handleError(error: any): Observable<any> {
|
||||
let errMsg = EditorService.UNKNOWN_ERROR_MESSAGE;
|
||||
if (error) {
|
||||
errMsg = (error.message) ? error.message :
|
||||
error.status ? `${error.status} - ${error.statusText}` : EditorService.GENERIC_ERROR_MESSAGE;
|
||||
}
|
||||
this.logService.error(errMsg);
|
||||
return throwError(errMsg);
|
||||
}
|
||||
|
||||
}
|
162
lib/process-services/src/lib/form/services/model.service.ts
Normal file
162
lib/process-services/src/lib/form/services/model.service.ts
Normal file
@ -0,0 +1,162 @@
|
||||
/*!
|
||||
* @license
|
||||
* Copyright 2019 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 { AlfrescoApiService, LogService } from '@alfresco/adf-core';
|
||||
import { Injectable } from '@angular/core';
|
||||
import { Observable, from, throwError } from 'rxjs';
|
||||
import { ModelsApi } from '@alfresco/js-api';
|
||||
import { catchError, map } from 'rxjs/operators';
|
||||
|
||||
@Injectable({
|
||||
providedIn: 'root'
|
||||
})
|
||||
export class ModelService {
|
||||
|
||||
static UNKNOWN_ERROR_MESSAGE: string = 'Unknown error';
|
||||
static GENERIC_ERROR_MESSAGE: string = 'Server error';
|
||||
|
||||
_modelsApi: ModelsApi;
|
||||
get modelsApi(): ModelsApi {
|
||||
this._modelsApi = this._modelsApi ?? new ModelsApi(this.apiService.getInstance());
|
||||
return this._modelsApi;
|
||||
}
|
||||
|
||||
constructor(private apiService: AlfrescoApiService, private logService: LogService) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a Form.
|
||||
*
|
||||
* @param formName Name of the new form
|
||||
* @returns The new form
|
||||
*/
|
||||
createForm(formName: string): Observable<any> {
|
||||
const dataModel = {
|
||||
name: formName,
|
||||
description: '',
|
||||
modelType: 2,
|
||||
stencilSet: 0
|
||||
};
|
||||
|
||||
return from(
|
||||
this.modelsApi.createModel(dataModel)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets all the forms.
|
||||
*
|
||||
* @returns List of form models
|
||||
*/
|
||||
getForms(): Observable<any> {
|
||||
const opts = {
|
||||
modelType: 2
|
||||
};
|
||||
|
||||
return from(this.modelsApi.getModels(opts))
|
||||
.pipe(
|
||||
map(this.toJsonArray),
|
||||
catchError((err) => this.handleError(err))
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a JSON array representation of form data.
|
||||
*
|
||||
* @param res Object representing form data
|
||||
* @returns JSON data
|
||||
*/
|
||||
toJsonArray(res: any) {
|
||||
if (res) {
|
||||
return res.data || [];
|
||||
}
|
||||
return [];
|
||||
}
|
||||
|
||||
/**
|
||||
* Searches for a form by name.
|
||||
*
|
||||
* @param name The form name to search for
|
||||
* @returns Form model(s) matching the search name
|
||||
*/
|
||||
searchFrom(name: string): Observable<any> {
|
||||
const opts = {
|
||||
modelType: 2
|
||||
};
|
||||
|
||||
return from(
|
||||
this.modelsApi.getModels(opts)
|
||||
)
|
||||
.pipe(
|
||||
map((forms: any) => forms.data.find((formData) => formData.name === name)),
|
||||
catchError((err) => this.handleError(err))
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Gets the form definition with a given name.
|
||||
*
|
||||
* @param name The form name
|
||||
* @returns Form definition
|
||||
*/
|
||||
getFormDefinitionByName(name: string): Observable<any> {
|
||||
const opts = {
|
||||
filter: 'myReusableForms',
|
||||
filterText: name,
|
||||
modelType: 2
|
||||
};
|
||||
|
||||
return from(this.modelsApi.getModels(opts))
|
||||
.pipe(
|
||||
map(this.getFormId),
|
||||
catchError((err) => this.handleError(err))
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the ID of a form.
|
||||
*
|
||||
* @param form Object representing a form
|
||||
* @returns ID string
|
||||
*/
|
||||
getFormId(form: any): string {
|
||||
let result = null;
|
||||
|
||||
if (form && form.data && form.data.length > 0) {
|
||||
result = form.data[0].id;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
/**
|
||||
* Reports an error message.
|
||||
*
|
||||
* @param error Data object with optional `message` and `status` fields for the error
|
||||
* @returns Error message
|
||||
*/
|
||||
private handleError(error: any): Observable<any> {
|
||||
let errMsg = ModelService.UNKNOWN_ERROR_MESSAGE;
|
||||
if (error) {
|
||||
errMsg = (error.message) ? error.message :
|
||||
error.status ? `${error.status} - ${error.statusText}` : ModelService.GENERIC_ERROR_MESSAGE;
|
||||
}
|
||||
this.logService.error(errMsg);
|
||||
return throwError(errMsg);
|
||||
}
|
||||
|
||||
}
|
@ -18,9 +18,8 @@
|
||||
import { TestBed } from '@angular/core/testing';
|
||||
import { of } from 'rxjs';
|
||||
import { ProcessContentService } from './process-content.service';
|
||||
import { setupTestBed } from '../../testing/setup-test-bed';
|
||||
import { CoreTestingModule } from '../../testing/core.testing.module';
|
||||
import { TranslateModule } from '@ngx-translate/core';
|
||||
import { setupTestBed, CoreTestingModule } from '@alfresco/adf-core';
|
||||
|
||||
declare let jasmine: any;
|
||||
|
@ -15,8 +15,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { AlfrescoApiService } from '../../services/alfresco-api.service';
|
||||
import { LogService } from '../../services/log.service';
|
||||
import { AlfrescoApiService, LogService } from '@alfresco/adf-core';
|
||||
import { Injectable } from '@angular/core';
|
||||
import { ActivitiContentApi, RelatedContentRepresentation } from '@alfresco/js-api';
|
||||
import { Observable, from, throwError } from 'rxjs';
|
@ -0,0 +1,100 @@
|
||||
/*!
|
||||
* @license
|
||||
* Copyright 2019 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 { AlfrescoApiService, LogService } from '@alfresco/adf-core';
|
||||
import { Injectable } from '@angular/core';
|
||||
import { Observable, from, throwError } from 'rxjs';
|
||||
import { ProcessDefinitionsApi } from '@alfresco/js-api';
|
||||
import { catchError } from 'rxjs/operators';
|
||||
|
||||
@Injectable({
|
||||
providedIn: 'root'
|
||||
})
|
||||
export class ProcessDefinitionService {
|
||||
|
||||
static UNKNOWN_ERROR_MESSAGE: string = 'Unknown error';
|
||||
static GENERIC_ERROR_MESSAGE: string = 'Server error';
|
||||
|
||||
_processDefinitionsApi: ProcessDefinitionsApi;
|
||||
get processDefinitionsApi(): ProcessDefinitionsApi {
|
||||
this._processDefinitionsApi = this._processDefinitionsApi ?? new ProcessDefinitionsApi(this.apiService.getInstance());
|
||||
return this._processDefinitionsApi;
|
||||
}
|
||||
|
||||
constructor(private apiService: AlfrescoApiService, private logService: LogService) {
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Gets values of fields populated by a REST backend using a process ID.
|
||||
*
|
||||
* @param processDefinitionId Process identifier
|
||||
* @param field Field identifier
|
||||
* @returns Field values
|
||||
*/
|
||||
getRestFieldValuesByProcessId(processDefinitionId: string, field: string): Observable<any> {
|
||||
return from(this.processDefinitionsApi.getRestFieldValues(processDefinitionId, field))
|
||||
.pipe(
|
||||
catchError((err) => this.handleError(err))
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets column values of fields populated by a REST backend using a process ID.
|
||||
*
|
||||
* @param processDefinitionId Process identifier
|
||||
* @param field Field identifier
|
||||
* @param column Column identifier
|
||||
* @returns Field values
|
||||
*/
|
||||
getRestFieldValuesColumnByProcessId(processDefinitionId: string, field: string, column?: string): Observable<any> {
|
||||
return from(this.processDefinitionsApi.getRestTableFieldValues(processDefinitionId, field, column))
|
||||
.pipe(
|
||||
catchError((err) => this.handleError(err))
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a JSON representation of form data.
|
||||
*
|
||||
* @param res Object representing form data
|
||||
* @returns JSON data
|
||||
*/
|
||||
toJson(res: any) {
|
||||
if (res) {
|
||||
return res || {};
|
||||
}
|
||||
return {};
|
||||
}
|
||||
|
||||
/**
|
||||
* Reports an error message.
|
||||
*
|
||||
* @param error Data object with optional `message` and `status` fields for the error
|
||||
* @returns Error message
|
||||
*/
|
||||
private handleError(error: any): Observable<any> {
|
||||
let errMsg = ProcessDefinitionService.UNKNOWN_ERROR_MESSAGE;
|
||||
if (error) {
|
||||
errMsg = (error.message) ? error.message :
|
||||
error.status ? `${error.status} - ${error.statusText}` : ProcessDefinitionService.GENERIC_ERROR_MESSAGE;
|
||||
}
|
||||
this.logService.error(errMsg);
|
||||
return throwError(errMsg);
|
||||
}
|
||||
|
||||
}
|
157
lib/process-services/src/lib/form/services/task-form.service.ts
Normal file
157
lib/process-services/src/lib/form/services/task-form.service.ts
Normal file
@ -0,0 +1,157 @@
|
||||
/*!
|
||||
* @license
|
||||
* Copyright 2019 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 { AlfrescoApiService, FormValues, LogService, TaskProcessVariableModel } from '@alfresco/adf-core';
|
||||
import { Injectable } from '@angular/core';
|
||||
import { from, Observable, throwError } from 'rxjs';
|
||||
import { CompleteFormRepresentation, SaveFormRepresentation, TaskFormsApi } from '@alfresco/js-api';
|
||||
import { catchError, map } from 'rxjs/operators';
|
||||
|
||||
@Injectable({
|
||||
providedIn: 'root'
|
||||
})
|
||||
export class TaskFormService {
|
||||
|
||||
static UNKNOWN_ERROR_MESSAGE: string = 'Unknown error';
|
||||
static GENERIC_ERROR_MESSAGE: string = 'Server error';
|
||||
|
||||
_taskFormsApi: TaskFormsApi;
|
||||
get taskFormsApi(): TaskFormsApi {
|
||||
this._taskFormsApi = this._taskFormsApi ?? new TaskFormsApi(this.apiService.getInstance());
|
||||
return this._taskFormsApi;
|
||||
}
|
||||
|
||||
constructor(private apiService: AlfrescoApiService, private logService: LogService) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Saves a task form.
|
||||
*
|
||||
* @param taskId Task Id
|
||||
* @param formValues Form Values
|
||||
* @returns Null response when the operation is complete
|
||||
*/
|
||||
saveTaskForm(taskId: string, formValues: FormValues): Observable<any> {
|
||||
const saveFormRepresentation = { values: formValues } as SaveFormRepresentation;
|
||||
|
||||
return from(this.taskFormsApi.saveTaskForm(taskId, saveFormRepresentation))
|
||||
.pipe(
|
||||
catchError((err) => this.handleError(err))
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Completes a Task Form.
|
||||
*
|
||||
* @param taskId Task Id
|
||||
* @param formValues Form Values
|
||||
* @param outcome Form Outcome
|
||||
* @returns Null response when the operation is complete
|
||||
*/
|
||||
completeTaskForm(taskId: string, formValues: FormValues, outcome?: string): Observable<any> {
|
||||
const completeFormRepresentation = { values: formValues } as CompleteFormRepresentation;
|
||||
if (outcome) {
|
||||
completeFormRepresentation.outcome = outcome;
|
||||
}
|
||||
|
||||
return from(this.taskFormsApi.completeTaskForm(taskId, completeFormRepresentation))
|
||||
.pipe(
|
||||
catchError((err) => this.handleError(err))
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a form related to a task.
|
||||
*
|
||||
* @param taskId ID of the target task
|
||||
* @returns Form definition
|
||||
*/
|
||||
getTaskForm(taskId: string): Observable<any> {
|
||||
return from(this.taskFormsApi.getTaskForm(taskId))
|
||||
.pipe(
|
||||
map(this.toJson),
|
||||
catchError((err) => this.handleError(err))
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets values of fields populated by a REST backend.
|
||||
*
|
||||
* @param taskId Task identifier
|
||||
* @param field Field identifier
|
||||
* @returns Field values
|
||||
*/
|
||||
getRestFieldValues(taskId: string, field: string): Observable<any> {
|
||||
return from(this.taskFormsApi.getRestFieldValues(taskId, field))
|
||||
.pipe(
|
||||
catchError((err) => this.handleError(err))
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets column values of fields populated by a REST backend.
|
||||
*
|
||||
* @param taskId Task identifier
|
||||
* @param field Field identifier
|
||||
* @param column Column identifier
|
||||
* @returns Field values
|
||||
*/
|
||||
getRestFieldValuesColumn(taskId: string, field: string, column?: string): Observable<any> {
|
||||
return from(this.taskFormsApi.getRestFieldColumnValues(taskId, field, column))
|
||||
.pipe(
|
||||
catchError((err) => this.handleError(err))
|
||||
);
|
||||
}
|
||||
|
||||
getTaskProcessVariable(taskId: string): Observable<TaskProcessVariableModel[]> {
|
||||
return from(this.taskFormsApi.getTaskFormVariables(taskId))
|
||||
.pipe(
|
||||
map((res) => this.toJson(res)),
|
||||
catchError((err) => this.handleError(err))
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a JSON representation of form data.
|
||||
*
|
||||
* @param res Object representing form data
|
||||
* @returns JSON data
|
||||
*/
|
||||
toJson(res: any) {
|
||||
if (res) {
|
||||
return res || {};
|
||||
}
|
||||
return {};
|
||||
}
|
||||
|
||||
/**
|
||||
* Reports an error message.
|
||||
*
|
||||
* @param error Data object with optional `message` and `status` fields for the error
|
||||
* @returns Error message
|
||||
*/
|
||||
private handleError(error: any): Observable<any> {
|
||||
let errMsg = TaskFormService.UNKNOWN_ERROR_MESSAGE;
|
||||
if (error) {
|
||||
errMsg = (error.message) ? error.message :
|
||||
error.status ? `${error.status} - ${error.statusText}` : TaskFormService.GENERIC_ERROR_MESSAGE;
|
||||
}
|
||||
this.logService.error(errMsg);
|
||||
return throwError(errMsg);
|
||||
}
|
||||
|
||||
}
|
85
lib/process-services/src/lib/form/services/task.service.ts
Normal file
85
lib/process-services/src/lib/form/services/task.service.ts
Normal file
@ -0,0 +1,85 @@
|
||||
/*!
|
||||
* @license
|
||||
* Copyright 2019 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 { AlfrescoApiService, LogService } from '@alfresco/adf-core';
|
||||
import { Injectable } from '@angular/core';
|
||||
import { Observable, from, throwError } from 'rxjs';
|
||||
import { TaskRepresentation, TasksApi } from '@alfresco/js-api';
|
||||
import { catchError, map } from 'rxjs/operators';
|
||||
|
||||
@Injectable({
|
||||
providedIn: 'root'
|
||||
})
|
||||
export class TaskService {
|
||||
|
||||
static UNKNOWN_ERROR_MESSAGE: string = 'Unknown error';
|
||||
static GENERIC_ERROR_MESSAGE: string = 'Server error';
|
||||
|
||||
_taskApi: TasksApi;
|
||||
get taskApi(): TasksApi {
|
||||
this._taskApi = this._taskApi ?? new TasksApi(this.apiService.getInstance());
|
||||
return this._taskApi;
|
||||
}
|
||||
|
||||
constructor(private apiService: AlfrescoApiService, private logService: LogService) {
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Gets a task.
|
||||
*
|
||||
* @param taskId Task Id
|
||||
* @returns Task info
|
||||
*/
|
||||
getTask(taskId: string): Observable<TaskRepresentation> {
|
||||
return from(this.taskApi.getTask(taskId))
|
||||
.pipe(
|
||||
map(this.toJson),
|
||||
catchError((err) => this.handleError(err))
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a JSON representation of form data.
|
||||
*
|
||||
* @param res Object representing form data
|
||||
* @returns JSON data
|
||||
*/
|
||||
toJson(res: any) {
|
||||
if (res) {
|
||||
return res || {};
|
||||
}
|
||||
return {};
|
||||
}
|
||||
|
||||
/**
|
||||
* Reports an error message.
|
||||
*
|
||||
* @param error Data object with optional `message` and `status` fields for the error
|
||||
* @returns Error message
|
||||
*/
|
||||
private handleError(error: any): Observable<any> {
|
||||
let errMsg = TaskService.UNKNOWN_ERROR_MESSAGE;
|
||||
if (error) {
|
||||
errMsg = (error.message) ? error.message :
|
||||
error.status ? `${error.status} - ${error.statusText}` : TaskService.GENERIC_ERROR_MESSAGE;
|
||||
}
|
||||
this.logService.error(errMsg);
|
||||
return throwError(errMsg);
|
||||
}
|
||||
|
||||
}
|
@ -25,18 +25,19 @@ import {
|
||||
taskFormSingleUploadMock, taskFormMultipleUploadMock, preselectedSingleNode, preselectedMultipleeNode
|
||||
} from './start-form.component.mock';
|
||||
import { StartFormComponent } from './start-form.component';
|
||||
import { FormService, WidgetVisibilityService, setupTestBed, FormModel, FormOutcomeModel } from '@alfresco/adf-core';
|
||||
import { WidgetVisibilityService, setupTestBed, FormModel, FormOutcomeModel } from '@alfresco/adf-core';
|
||||
import { TranslateService, TranslateModule } from '@ngx-translate/core';
|
||||
import { ProcessTestingModule } from '../testing/process.testing.module';
|
||||
import { ProcessService } from '../process-list/services/process.service';
|
||||
|
||||
describe('StartFormComponent', () => {
|
||||
|
||||
let formService: FormService;
|
||||
let component: StartFormComponent;
|
||||
let fixture: ComponentFixture<StartFormComponent>;
|
||||
let getStartFormSpy: jasmine.Spy;
|
||||
let visibilityService: WidgetVisibilityService;
|
||||
let translate: TranslateService;
|
||||
let processService: ProcessService;
|
||||
|
||||
const exampleId1 = 'my:process1';
|
||||
const exampleId2 = 'my:process2';
|
||||
@ -52,11 +53,11 @@ describe('StartFormComponent', () => {
|
||||
beforeEach(() => {
|
||||
fixture = TestBed.createComponent(StartFormComponent);
|
||||
component = fixture.componentInstance;
|
||||
formService = TestBed.inject(FormService);
|
||||
processService = TestBed.inject(ProcessService);
|
||||
visibilityService = TestBed.inject(WidgetVisibilityService);
|
||||
translate = TestBed.inject(TranslateService);
|
||||
|
||||
getStartFormSpy = spyOn(formService, 'getStartFormDefinition').and.returnValue(of({
|
||||
getStartFormSpy = spyOn(processService, 'getStartFormDefinition').and.returnValue(of({
|
||||
processDefinitionName: 'my:process'
|
||||
}));
|
||||
|
||||
@ -71,27 +72,27 @@ describe('StartFormComponent', () => {
|
||||
it('should load start form on change if processDefinitionId defined', () => {
|
||||
component.processDefinitionId = exampleId1;
|
||||
component.ngOnChanges({ processDefinitionId: new SimpleChange(exampleId1, exampleId2, true) });
|
||||
expect(formService.getStartFormDefinition).toHaveBeenCalled();
|
||||
expect(processService.getStartFormDefinition).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should load start form when processDefinitionId changed', () => {
|
||||
component.processDefinitionId = exampleId1;
|
||||
component.ngOnChanges({ processDefinitionId: new SimpleChange(exampleId1, exampleId2, true) });
|
||||
expect(formService.getStartFormDefinition).toHaveBeenCalled();
|
||||
expect(processService.getStartFormDefinition).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should check visibility when the start form is loaded', () => {
|
||||
spyOn(visibilityService, 'refreshVisibility');
|
||||
component.processDefinitionId = exampleId1;
|
||||
component.ngOnChanges({ processDefinitionId: new SimpleChange(exampleId1, exampleId2, true) });
|
||||
expect(formService.getStartFormDefinition).toHaveBeenCalled();
|
||||
expect(processService.getStartFormDefinition).toHaveBeenCalled();
|
||||
expect(visibilityService.refreshVisibility).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should not load start form when changes notified but no change to processDefinitionId', () => {
|
||||
component.processDefinitionId = undefined;
|
||||
component.ngOnChanges({ otherProp: new SimpleChange(exampleId1, exampleId2, true) });
|
||||
expect(formService.getStartFormDefinition).not.toHaveBeenCalled();
|
||||
expect(processService.getStartFormDefinition).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should be able to inject sigle file as value into the form with an upload single widget', () => {
|
||||
|
@ -30,6 +30,11 @@ import {
|
||||
} from '@angular/core';
|
||||
import { FormComponent } from './form.component';
|
||||
import { ContentLinkModel, FormService, WidgetVisibilityService, FormOutcomeModel } from '@alfresco/adf-core';
|
||||
import { ProcessService } from '../process-list/services/process.service';
|
||||
import { EditorService } from './services/editor.service';
|
||||
import { ModelService } from './services/model.service';
|
||||
import { TaskFormService } from './services/task-form.service';
|
||||
import { TaskService } from './services/task.service';
|
||||
|
||||
@Component({
|
||||
selector: 'adf-start-form',
|
||||
@ -70,8 +75,13 @@ export class StartFormComponent extends FormComponent implements OnChanges, OnIn
|
||||
@ViewChild('outcomesContainer')
|
||||
outcomesContainer: ElementRef = null;
|
||||
|
||||
constructor(formService: FormService, visibilityService: WidgetVisibilityService) {
|
||||
super(formService, visibilityService, null, null);
|
||||
constructor(public processService: ProcessService,
|
||||
taskFormService: TaskFormService,
|
||||
taskService: TaskService,
|
||||
editorService: EditorService,
|
||||
modelService: ModelService,
|
||||
formService: FormService, visibilityService: WidgetVisibilityService) {
|
||||
super(formService, taskFormService, taskService, editorService, modelService, visibilityService, null, null);
|
||||
this.showTitle = false;
|
||||
}
|
||||
|
||||
@ -99,9 +109,9 @@ export class StartFormComponent extends FormComponent implements OnChanges, OnIn
|
||||
}
|
||||
|
||||
loadStartForm(processId: string) {
|
||||
this.formService.getProcessInstance(processId)
|
||||
this.processService.getProcess(processId)
|
||||
.subscribe((instance: any) => {
|
||||
this.formService
|
||||
this.processService
|
||||
.getStartFormInstance(processId)
|
||||
.subscribe(
|
||||
(form) => {
|
||||
@ -117,7 +127,7 @@ export class StartFormComponent extends FormComponent implements OnChanges, OnIn
|
||||
}
|
||||
|
||||
getStartFormDefinition(processId: string) {
|
||||
this.formService
|
||||
this.processService
|
||||
.getStartFormDefinition(processId)
|
||||
.subscribe(
|
||||
(form) => {
|
||||
|
@ -19,7 +19,7 @@ import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material/dialog';
|
||||
import { ContentModule, ContentNodeSelectorPanelComponent, DocumentListService } from '@alfresco/adf-content-services';
|
||||
import { EventEmitter, NO_ERRORS_SCHEMA } from '@angular/core';
|
||||
import { ProcessTestingModule } from '../testing/process.testing.module';
|
||||
import { ProcessTestingModule } from '../../../testing/process.testing.module';
|
||||
import { AttachFileWidgetDialogComponent } from './attach-file-widget-dialog.component';
|
||||
import { setupTestBed, AuthenticationService, SitesService, AlfrescoApiService, NodesApiService } from '@alfresco/adf-core';
|
||||
import { AttachFileWidgetDialogComponentData } from './attach-file-widget-dialog-component.interface';
|
@ -20,7 +20,7 @@ import { MatDialog } from '@angular/material/dialog';
|
||||
import { AttachFileWidgetDialogService } from './attach-file-widget-dialog.service';
|
||||
import { Subject, of } from 'rxjs';
|
||||
import { setupTestBed } from '@alfresco/adf-core';
|
||||
import { ProcessTestingModule } from '../testing/process.testing.module';
|
||||
import { ProcessTestingModule } from '../../../testing/process.testing.module';
|
||||
import { TranslateModule } from '@ngx-translate/core';
|
||||
|
||||
describe('AttachFileWidgetDialogService', () => {
|
@ -40,7 +40,7 @@
|
||||
(click)="openSelectDialogFromFileSource()">
|
||||
{{field.params?.fileSource?.name}}
|
||||
<mat-icon>
|
||||
<img alt="alfresco" class="adf-attach-widget__image-logo" src="../assets/images/alfresco-flower.svg">
|
||||
<img alt="alfresco" class="adf-attach-widget__image-logo" src="../../../assets/images/alfresco-flower.svg">
|
||||
</mat-icon>
|
||||
</button>
|
||||
<div *ngIf="!isDefinedSourceFolder()">
|
||||
@ -49,7 +49,7 @@
|
||||
(click)="openSelectDialog(repo)">
|
||||
{{repo.name}}
|
||||
<mat-icon>
|
||||
<img alt="alfresco" class="adf-attach-widget__image-logo" src="../assets/images/alfresco-flower.svg">
|
||||
<img alt="alfresco" class="adf-attach-widget__image-logo" src="../../../assets/images/alfresco-flower.svg">
|
||||
</mat-icon>
|
||||
</button>
|
||||
</div>
|
@ -23,8 +23,6 @@ import {
|
||||
FormModel,
|
||||
FormFieldTypes,
|
||||
FormService,
|
||||
ProcessContentService,
|
||||
ActivitiContentService,
|
||||
FormFieldMetadata,
|
||||
setupTestBed,
|
||||
DownloadService
|
||||
@ -32,9 +30,11 @@ import {
|
||||
import { ContentNodeDialogService, ContentModule } from '@alfresco/adf-content-services';
|
||||
import { of } from 'rxjs';
|
||||
import { Node } from '@alfresco/js-api';
|
||||
import { ProcessTestingModule } from '../testing/process.testing.module';
|
||||
import { ProcessTestingModule } from '../../../testing/process.testing.module';
|
||||
import { TranslateModule } from '@ngx-translate/core';
|
||||
import { AttachFileWidgetDialogService } from './attach-file-widget-dialog.service';
|
||||
import { ActivitiContentService } from '../../services/activiti-alfresco.service';
|
||||
import { ProcessContentService } from '../../services/process-content.service';
|
||||
|
||||
const fakeRepositoryListAnswer = [
|
||||
{
|
@ -19,16 +19,13 @@
|
||||
|
||||
import { Component, OnDestroy, OnInit, ViewEncapsulation } from '@angular/core';
|
||||
import {
|
||||
ActivitiContentService,
|
||||
AppConfigService,
|
||||
AppConfigValues,
|
||||
ContentService,
|
||||
DownloadService,
|
||||
FormService,
|
||||
LogService,
|
||||
ProcessContentService,
|
||||
ThumbnailService,
|
||||
UploadWidgetComponent
|
||||
ThumbnailService
|
||||
} from '@alfresco/adf-core';
|
||||
import { ContentNodeDialogService } from '@alfresco/adf-content-services';
|
||||
import {
|
||||
@ -40,6 +37,9 @@ import {
|
||||
import { from, of, Subject, zip } from 'rxjs';
|
||||
import { mergeMap, takeUntil } from 'rxjs/operators';
|
||||
import { AttachFileWidgetDialogService } from './attach-file-widget-dialog.service';
|
||||
import { UploadWidgetComponent } from '../upload/upload.widget';
|
||||
import { ProcessContentService } from '../../services/process-content.service';
|
||||
import { ActivitiContentService } from '../../services/activiti-alfresco.service';
|
||||
|
||||
@Component({
|
||||
selector: 'attach-widget',
|
@ -27,7 +27,7 @@ import {
|
||||
import { ContentNodeDialogService } from '@alfresco/adf-content-services';
|
||||
import { of } from 'rxjs';
|
||||
import { Node } from '@alfresco/js-api';
|
||||
import { ProcessTestingModule } from '../testing/process.testing.module';
|
||||
import { ProcessTestingModule } from '../../../testing/process.testing.module';
|
||||
import { TranslateModule } from '@ngx-translate/core';
|
||||
|
||||
const fakeMinimalNode: Node = {
|
@ -16,7 +16,7 @@
|
||||
*/
|
||||
|
||||
import { NgModule } from '@angular/core';
|
||||
import { MaterialModule } from '../material.module';
|
||||
import { MaterialModule } from '../../../material.module';
|
||||
import { CoreModule } from '@alfresco/adf-core';
|
||||
import { ContentNodeSelectorModule } from '@alfresco/adf-content-services';
|
||||
|
@ -18,15 +18,16 @@
|
||||
import { SimpleChange } from '@angular/core';
|
||||
import { ComponentFixture, fakeAsync, TestBed } from '@angular/core/testing';
|
||||
import { By } from '@angular/platform-browser';
|
||||
import { ContentService } from '../../../../services';
|
||||
import {
|
||||
ContentService,
|
||||
ContentLinkModel,
|
||||
CoreTestingModule,
|
||||
setupTestBed
|
||||
} from '@alfresco/adf-core';
|
||||
import { of } from 'rxjs';
|
||||
|
||||
import { ProcessContentService } from '../../../services/process-content.service';
|
||||
import { ContentLinkModel } from '../index';
|
||||
import { ContentWidgetComponent } from './content.widget';
|
||||
import { setupTestBed } from '../../../../testing/setup-test-bed';
|
||||
import { CoreTestingModule } from '../../../../testing/core.testing.module';
|
||||
import { TranslateModule } from '@ngx-translate/core';
|
||||
import { ProcessContentService } from '../../services/process-content.service';
|
||||
|
||||
declare let jasmine: any;
|
||||
|
||||
@ -41,7 +42,7 @@ describe('ContentWidgetComponent', () => {
|
||||
|
||||
const createFakeImageBlob = () => {
|
||||
const data = atob('iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mNk+M9QDwADhgGAWjR9awAAAABJRU5ErkJggg==');
|
||||
return new Blob([data], { type: 'image/png' });
|
||||
return new Blob([data], {type: 'image/png'});
|
||||
};
|
||||
|
||||
const createFakePdfBlob = (): Blob => {
|
||||
@ -59,7 +60,7 @@ describe('ContentWidgetComponent', () => {
|
||||
'CjAwMDAwMDAwNzkgMDAwMDAgbiAKMDAwMDAwMDE3MyAwMDAwMCBuIAowMDAwMDAwMzAxIDAw' +
|
||||
'MDAwIG4gCjAwMDAwMDAzODAgMDAwMDAgbiAKdHJhaWxlcgo8PAogIC9TaXplIDYKICAvUm9v' +
|
||||
'dCAxIDAgUgo+PgpzdGFydHhyZWYKNDkyCiUlRU9G');
|
||||
return new Blob([pdfData], { type: 'application/pdf' });
|
||||
return new Blob([pdfData], {type: 'application/pdf'});
|
||||
};
|
||||
|
||||
setupTestBed({
|
||||
@ -115,7 +116,7 @@ describe('ContentWidgetComponent', () => {
|
||||
|
||||
const contentId = 1;
|
||||
const change = new SimpleChange(null, contentId, true);
|
||||
component.ngOnChanges({ id: change });
|
||||
component.ngOnChanges({id: change});
|
||||
|
||||
jasmine.Ajax.requests.mostRecent().respondWith({
|
||||
status: 200,
|
||||
@ -155,7 +156,7 @@ describe('ContentWidgetComponent', () => {
|
||||
|
||||
const contentId = 1;
|
||||
const change = new SimpleChange(null, contentId, true);
|
||||
component.ngOnChanges({ id: change });
|
||||
component.ngOnChanges({id: change});
|
||||
|
||||
jasmine.Ajax.requests.mostRecent().respondWith({
|
||||
status: 200,
|
||||
@ -183,7 +184,7 @@ describe('ContentWidgetComponent', () => {
|
||||
|
||||
const contentId = 1;
|
||||
const change = new SimpleChange(null, contentId, true);
|
||||
component.ngOnChanges({ id: change });
|
||||
component.ngOnChanges({id: change});
|
||||
|
||||
component.contentLoaded.subscribe(() => {
|
||||
fixture.detectChanges();
|
@ -15,13 +15,10 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { ContentService } from '../../../../services/content.service';
|
||||
import { LogService } from '../../../../services/log.service';
|
||||
import { ContentService, LogService, ContentLinkModel, FormService } from '@alfresco/adf-core';
|
||||
import { Component, EventEmitter, Input, OnChanges, Output, SimpleChanges, ViewEncapsulation } from '@angular/core';
|
||||
import { Observable } from 'rxjs';
|
||||
import { ProcessContentService } from '../../../services/process-content.service';
|
||||
import { ContentLinkModel } from '../core/content-link.model';
|
||||
import { FormService } from '../../../services/form.service';
|
||||
import { ProcessContentService } from '../../services/process-content.service';
|
||||
|
||||
@Component({
|
||||
selector: 'adf-content',
|
@ -16,8 +16,7 @@
|
||||
*/
|
||||
|
||||
import { Component, OnInit, ViewEncapsulation } from '@angular/core';
|
||||
import { FormService } from '../../../services/form.service';
|
||||
import { WidgetComponent } from '../widget.component';
|
||||
import { FormService, WidgetComponent } from '@alfresco/adf-core';
|
||||
|
||||
@Component({
|
||||
selector: 'adf-form-document-widget',
|
||||
@ -41,7 +40,7 @@ export class DocumentWidgetComponent extends WidgetComponent implements OnInit {
|
||||
hasFile: boolean = false;
|
||||
|
||||
constructor(public formService: FormService) {
|
||||
super(formService);
|
||||
super(formService);
|
||||
}
|
||||
|
||||
ngOnInit() {
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user