diff --git a/demo-shell/src/app/components/form/fake-form.service.ts b/demo-shell/src/app/components/form/fake-tak-form.service.ts similarity index 76% rename from demo-shell/src/app/components/form/fake-form.service.ts rename to demo-shell/src/app/components/form/fake-tak-form.service.ts index 7a7edcd1bc..72269df6be 100644 --- a/demo-shell/src/app/components/form/fake-form.service.ts +++ b/demo-shell/src/app/components/form/fake-tak-form.service.ts @@ -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(); +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( diff --git a/demo-shell/src/app/components/form/form-list.component.ts b/demo-shell/src/app/components/form/form-list.component.ts index 2c3d3e7623..cc1c178fb9 100644 --- a/demo-shell/src/app/components/form/form-list.component.ts +++ b/demo-shell/src/app/components/form/form-list.component.ts @@ -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(); - 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) { 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; }); diff --git a/demo-shell/src/app/components/form/form-loading.component.ts b/demo-shell/src/app/components/form/form-loading.component.ts index 58d4cbcee7..905d8e71f8 100644 --- a/demo-shell/src/app/components/form/form-loading.component.ts +++ b/demo-shell/src/app/components/form/form-loading.component.ts @@ -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; diff --git a/demo-shell/src/app/components/process-service/process-service.component.ts b/demo-shell/src/app/components/process-service/process-service.component.ts index 1754ba4e68..e89d0d8b5e 100644 --- a/demo-shell/src/app/components/process-service/process-service.component.ts +++ b/demo-shell/src/app/components/process-service/process-service.component.ts @@ -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'; diff --git a/demo-shell/src/app/services/in-memory-form.service.ts b/demo-shell/src/app/services/in-memory-form.service.ts index ee69359af2..1e9ee878b7 100644 --- a/demo-shell/src/app/services/in-memory-form.service.ts +++ b/demo-shell/src/app/services/in-memory-form.service.ts @@ -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(); constructor(appConfig: AppConfigService, - ecmModelService: EcmModelService, - apiService: AlfrescoApiService, protected logService: LogService) { - super(ecmModelService, apiService, logService); + super(); this.data = appConfig.get('activiti'); } diff --git a/docs/core/components/form-field.component.md b/docs/core/components/form-field.component.md index 1b9c79fe8a..04e7209cc9 100644 --- a/docs/core/components/form-field.component.md +++ b/docs/core/components/form-field.component.md @@ -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) | diff --git a/docs/core/components/form-list.component.md b/docs/core/components/form-list.component.md index 7dad8e22a6..9da4b955f7 100644 --- a/docs/core/components/form-list.component.md +++ b/docs/core/components/form-list.component.md @@ -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. diff --git a/docs/core/services/activiti-alfresco.service.md b/docs/core/services/activiti-alfresco.service.md index d7c633a8b5..572ba2b6e6 100644 --- a/docs/core/services/activiti-alfresco.service.md +++ b/docs/core/services/activiti-alfresco.service.md @@ -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). diff --git a/docs/core/services/node.service.md b/docs/core/services/node.service.md deleted file mode 100644 index 83cf2ac61a..0000000000 --- a/docs/core/services/node.service.md +++ /dev/null @@ -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)`>`
- (**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)`>`
- (**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)`>`
- (**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) diff --git a/docs/core/services/process-content.service.md b/docs/core/services/process-content.service.md index 8a6080c783..06c358b72a 100644 --- a/docs/core/services/process-content.service.md +++ b/docs/core/services/process-content.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. diff --git a/docs/core/widgets/content.widget.md b/docs/core/widgets/content.widget.md index 71a18dd92f..845c77da2a 100644 --- a/docs/core/widgets/content.widget.md +++ b/docs/core/widgets/content.widget.md @@ -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. diff --git a/docs/release-notes/RelNote200.md b/docs/release-notes/RelNote200.md index 617526a44c..64e5180a5b 100644 --- a/docs/release-notes/RelNote200.md +++ b/docs/release-notes/RelNote200.md @@ -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 diff --git a/docs/release-notes/RelNote220.md b/docs/release-notes/RelNote220.md index b1c1f3c1a8..c1320b93ec 100644 --- a/docs/release-notes/RelNote220.md +++ b/docs/release-notes/RelNote220.md @@ -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 diff --git a/docs/upgrade-guide/upgrade26-30.md b/docs/upgrade-guide/upgrade26-30.md index 023d74106d..9a8f797760 100644 --- a/docs/upgrade-guide/upgrade26-30.md +++ b/docs/upgrade-guide/upgrade26-30.md @@ -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` diff --git a/docs/user-guide/extensibility.md b/docs/user-guide/extensibility.md index 41a0a6c6e4..e41dfe469e 100644 --- a/docs/user-guide/extensibility.md +++ b/docs/user-guide/extensibility.md @@ -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 diff --git a/lib/core/src/lib/form/components/widgets/core/form.model.spec.ts b/lib/core/src/lib/form/components/widgets/core/form.model.spec.ts index 65d33afe5d..efa6641078 100644 --- a/lib/core/src/lib/form/components/widgets/core/form.model.spec.ts +++ b/lib/core/src/lib/form/components/widgets/core/form.model.spec.ts @@ -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', () => { diff --git a/lib/core/src/lib/form/components/widgets/index.ts b/lib/core/src/lib/form/components/widgets/index.ts index 047f61c5e0..c51b9d3b37 100644 --- a/lib/core/src/lib/form/components/widgets/index.ts +++ b/lib/core/src/lib/form/components/widgets/index.ts @@ -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 ]; diff --git a/lib/core/src/lib/form/components/widgets/upload-folder/upload-folder.widget.html b/lib/core/src/lib/form/components/widgets/upload-folder/upload-folder.widget.html deleted file mode 100644 index 7ab49c52d8..0000000000 --- a/lib/core/src/lib/form/components/widgets/upload-folder/upload-folder.widget.html +++ /dev/null @@ -1,7 +0,0 @@ -
- -
-
-
diff --git a/lib/core/src/lib/form/components/widgets/upload-folder/upload-folder.widget.scss b/lib/core/src/lib/form/components/widgets/upload-folder/upload-folder.widget.scss deleted file mode 100644 index d41125f976..0000000000 --- a/lib/core/src/lib/form/components/widgets/upload-folder/upload-folder.widget.scss +++ /dev/null @@ -1,8 +0,0 @@ -.adf { - &-upload-folder-widget { - width: 100%; - word-break: break-all; - padding: 0.4375em 0; - border-top: 0.8438em solid transparent; - } -} diff --git a/lib/core/src/lib/form/components/widgets/upload-folder/upload-folder.widget.spec.ts b/lib/core/src/lib/form/components/widgets/upload-folder/upload-folder.widget.spec.ts deleted file mode 100644 index e5ec401daf..0000000000 --- a/lib/core/src/lib/form/components/widgets/upload-folder/upload-folder.widget.spec.ts +++ /dev/null @@ -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; - 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: '' }), { - type: FormFieldTypes.UPLOAD, - required: true - }); - - fixture.detectChanges(); - await fixture.whenStable(); - - const asterisk: HTMLElement = element.querySelector('.adf-asterisk'); - - expect(asterisk).toBeTruthy(); - expect(asterisk.textContent).toEqual('*'); - }); - }); -}); diff --git a/lib/core/src/lib/form/components/widgets/upload-folder/upload-folder.widget.ts b/lib/core/src/lib/form/components/widgets/upload-folder/upload-folder.widget.ts deleted file mode 100644 index 6d75e47037..0000000000 --- a/lib/core/src/lib/form/components/widgets/upload-folder/upload-folder.widget.ts +++ /dev/null @@ -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 { - 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); - } - ); - } -} diff --git a/lib/core/src/lib/form/events/index.ts b/lib/core/src/lib/form/events/index.ts index ba2617e5d4..051a975b8a 100644 --- a/lib/core/src/lib/form/events/index.ts +++ b/lib/core/src/lib/form/events/index.ts @@ -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'; diff --git a/lib/core/src/lib/form/form-base.module.ts b/lib/core/src/lib/form/form-base.module.ts index 21c49ec2b6..220174904a 100644 --- a/lib/core/src/lib/form/form-base.module.ts +++ b/lib/core/src/lib/form/form-base.module.ts @@ -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, diff --git a/lib/core/src/lib/form/public-api.ts b/lib/core/src/lib/form/public-api.ts index 8bd8587370..8a9d7d1e38 100644 --- a/lib/core/src/lib/form/public-api.ts +++ b/lib/core/src/lib/form/public-api.ts @@ -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'; diff --git a/lib/core/src/lib/form/services/form-rendering.service.spec.ts b/lib/core/src/lib/form/services/form-rendering.service.spec.ts index 82eb927030..e590e97558 100644 --- a/lib/core/src/lib/form/services/form-rendering.service.spec.ts +++ b/lib/core/src/lib/form/services/form-rendering.service.spec.ts @@ -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); diff --git a/lib/core/src/lib/form/services/form-rendering.service.ts b/lib/core/src/lib/form/services/form-rendering.service.ts index 9fd9e84133..dfc23dc71d 100644 --- a/lib/core/src/lib/form/services/form-rendering.service.ts +++ b/lib/core/src/lib/form/services/form-rendering.service.ts @@ -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) diff --git a/lib/core/src/lib/form/services/form.service.spec.ts b/lib/core/src/lib/form/services/form.service.spec.ts index e28c8bfdfb..1216076f3a 100644 --- a/lib/core/src/lib/form/services/form.service.spec.ts +++ b/lib/core/src/lib/form/services/form.service.spec.ts @@ -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 = ''; - - 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); - }); - })); }); }); diff --git a/lib/core/src/lib/form/services/form.service.ts b/lib/core/src/lib/form/services/form.service.ts index f229a33138..f0fb747a49 100644 --- a/lib/core/src/lib/form/services/form.service.ts +++ b/lib/core/src/lib/form/services/form.service.ts @@ -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(); formDataRefreshed = new Subject(); formFieldValueChanged = new Subject(); @@ -125,7 +47,7 @@ export class FormService implements FormValidationService { validateForm = new Subject(); validateFormField = new Subject(); - validateDynamicTableRow = new Subject(); + validateDynamicTableRow = new Subject(); executeOutcome = new Subject(); @@ -133,9 +55,7 @@ export class FormService implements FormValidationService { formRulesEvent = new Subject(); - 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 { - 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 { - 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 { - 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 { - 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 { - 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 { - 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 { - 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 { - 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 { - 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 { - 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 { - 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 { - 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 { - 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 { - 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 { - 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 { - 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 { - 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 { - 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 { - 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 { - 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 { - 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 { - 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 { - 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 { - 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); - } } diff --git a/lib/core/src/lib/form/services/node.service.spec.ts b/lib/core/src/lib/form/services/node.service.spec.ts deleted file mode 100644 index 8e8bd9788f..0000000000 --- a/lib/core/src/lib/form/services/node.service.spec.ts +++ /dev/null @@ -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({}) - }); - }); -}); diff --git a/lib/core/src/lib/form/services/node.service.ts b/lib/core/src/lib/form/services/node.service.ts deleted file mode 100644 index 591d12f5d5..0000000000 --- a/lib/core/src/lib/form/services/node.service.ts +++ /dev/null @@ -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 { - 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 { - 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 { - return this.nodesApiService.createNodeInsideRoot(name, nodeType, properties, path); - } -} diff --git a/lib/core/src/lib/form/services/widget-visibility-cloud.service.spec.ts b/lib/core/src/lib/form/services/widget-visibility-cloud.service.spec.ts index 5208a941b0..7f5d4168dc 100644 --- a/lib/core/src/lib/form/services/widget-visibility-cloud.service.spec.ts +++ b/lib/core/src/lib/form/services/widget-visibility-cloud.service.spec.ts @@ -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'; diff --git a/lib/core/src/lib/form/services/widget-visibility.service.spec.ts b/lib/core/src/lib/form/services/widget-visibility.service.spec.ts index 46489f393a..223f32ff95 100644 --- a/lib/core/src/lib/form/services/widget-visibility.service.spec.ts +++ b/lib/core/src/lib/form/services/widget-visibility.service.spec.ts @@ -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 = '!='; diff --git a/lib/core/src/lib/form/services/widget-visibility.service.ts b/lib/core/src/lib/form/services/widget-visibility.service.ts index 434710f5e1..8576e19ff7 100644 --- a/lib/core/src/lib/form/services/widget-visibility.service.ts +++ b/lib/core/src/lib/form/services/widget-visibility.service.ts @@ -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 { - 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'); - } } diff --git a/lib/core/src/lib/services/people-process.service.ts b/lib/core/src/lib/services/people-process.service.ts index 88502474c3..2e790ab55f 100644 --- a/lib/core/src/lib/services/people-process.service.ts +++ b/lib/core/src/lib/services/people-process.service.ts @@ -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 { + 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 { - const option = { excludeTaskId: taskId, filter: searchWord }; + getWorkflowUsers(taskId?: string, searchWord?: string, groupId?: string): Observable { + 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. * diff --git a/lib/process-services-cloud/src/lib/form/components/form-cloud-custom-outcomes.component.spec.ts b/lib/process-services-cloud/src/lib/form/components/form-cloud-custom-outcomes.component.spec.ts new file mode 100644 index 0000000000..6a1dbbb13d --- /dev/null +++ b/lib/process-services-cloud/src/lib/form/components/form-cloud-custom-outcomes.component.spec.ts @@ -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: ` + + + + + + ` +}) +class FormCloudWithCustomOutComesComponent { + + @ViewChild('adfCloudForm', { static: true }) + adfCloudForm: FormCloudComponent; + + onCustomButtonOneClick() { + } + + onCustomButtonTwoClick() { + } +} + +describe('FormCloudWithCustomOutComesComponent', () => { + + let fixture: ComponentFixture; + 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'); + }); +}); diff --git a/lib/process-services-cloud/src/lib/form/components/form-cloud.component.spec.ts b/lib/process-services-cloud/src/lib/form/components/form-cloud.component.spec.ts index 9aa2bb3ec1..af0e3ad09d 100644 --- a/lib/process-services-cloud/src/lib/form/components/form-cloud.component.spec.ts +++ b/lib/process-services-cloud/src/lib/form/components/form-cloud.component.spec.ts @@ -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: ` - - - - - - ` -}) - -class FormCloudWithCustomOutComesComponent { - - @ViewChild('adfCloudForm', { static: true }) - adfCloudForm: FormCloudComponent; - - onCustomButtonOneClick() { - } - - onCustomButtonTwoClick() { - } -} - -describe('FormCloudWithCustomOutComesComponent', () => { - - let fixture: ComponentFixture; - let customComponent: FormCloudWithCustomOutComesComponent; - let debugElement: DebugElement; +describe('Multilingual Form', () => { + let translateService: TranslateService; + let formCloudService: FormCloudService; + let formComponent: FormCloudComponent; + let fixture: ComponentFixture; 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', () => { diff --git a/lib/process-services-cloud/src/lib/form/components/widgets/attach-file/attach-file-cloud-widget.component.spec.ts b/lib/process-services-cloud/src/lib/form/components/widgets/attach-file/attach-file-cloud-widget.component.spec.ts index 4ece93306c..f1be55737f 100644 --- a/lib/process-services-cloud/src/lib/form/components/widgets/attach-file/attach-file-cloud-widget.component.spec.ts +++ b/lib/process-services-cloud/src/lib/form/components/widgets/attach-file/attach-file-cloud-widget.component.spec.ts @@ -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(); diff --git a/lib/process-services-cloud/src/lib/form/components/widgets/dropdown/dropdown-cloud.widget.spec.ts b/lib/process-services-cloud/src/lib/form/components/widgets/dropdown/dropdown-cloud.widget.spec.ts index 3dec807c2f..3852ab4f1b 100644 --- a/lib/process-services-cloud/src/lib/form/components/widgets/dropdown/dropdown-cloud.widget.spec.ts +++ b/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: '' }), { - 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(() => { diff --git a/lib/process-services-cloud/src/lib/form/components/widgets/radio-buttons/radio-buttons-cloud.widget.spec.ts b/lib/process-services-cloud/src/lib/form/components/widgets/radio-buttons/radio-buttons-cloud.widget.spec.ts index fc1d6d4ee8..979c7d68e0 100644 --- a/lib/process-services-cloud/src/lib/form/components/widgets/radio-buttons/radio-buttons-cloud.widget.spec.ts +++ b/lib/process-services-cloud/src/lib/form/components/widgets/radio-buttons/radio-buttons-cloud.widget.spec.ts @@ -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', diff --git a/lib/process-services-cloud/src/lib/form/services/form-cloud.service.ts b/lib/process-services-cloud/src/lib/form/services/form-cloud.service.ts index 1fff4639fd..6d08d89325 100644 --- a/lib/process-services-cloud/src/lib/form/services/form-cloud.service.ts +++ b/lib/process-services-cloud/src/lib/form/services/form-cloud.service.ts @@ -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; } diff --git a/lib/process-services-cloud/src/lib/task/services/task-cloud.service.spec.ts b/lib/process-services-cloud/src/lib/task/services/task-cloud.service.spec.ts index f484d8fa2c..bdac7f1bfd 100644 --- a/lib/process-services-cloud/src/lib/task/services/task-cloud.service.spec.ts +++ b/lib/process-services-cloud/src/lib/task/services/task-cloud.service.spec.ts @@ -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' }; diff --git a/lib/process-services-cloud/src/lib/task/task-form/components/task-form-cloud.component.spec.ts b/lib/process-services-cloud/src/lib/task/task-form/components/task-form-cloud.component.spec.ts index efd0fdd62a..b49b828b91 100644 --- a/lib/process-services-cloud/src/lib/task/task-form/components/task-form-cloud.component.spec.ts +++ b/lib/process-services-cloud/src/lib/task/task-form/components/task-form-cloud.component.spec.ts @@ -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(); diff --git a/lib/process-services-cloud/src/lib/task/task-header/components/task-header-cloud.component.spec.ts b/lib/process-services-cloud/src/lib/task/task-header/components/task-header-cloud.component.spec.ts index 9b5b1901e1..ee94d65f7e 100644 --- a/lib/process-services-cloud/src/lib/task/task-header/components/task-header-cloud.component.spec.ts +++ b/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(); diff --git a/lib/process-services/karma.conf.js b/lib/process-services/karma.conf.js index 9a6e8f8693..34b269157e 100644 --- a/lib/process-services/karma.conf.js +++ b/lib/process-services/karma.conf.js @@ -80,4 +80,5 @@ module.exports = function (config) { browsers: ['Chrome'], singleRun: true }); + process.env.TZ = 'UTC'; }; diff --git a/lib/process-services/src/lib/attachment/create-process-attachment.component.ts b/lib/process-services/src/lib/attachment/create-process-attachment.component.ts index a5227a7386..ec557dcc0e 100644 --- a/lib/process-services/src/lib/attachment/create-process-attachment.component.ts +++ b/lib/process-services/src/lib/attachment/create-process-attachment.component.ts @@ -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', diff --git a/lib/process-services/src/lib/attachment/create-task-attachment.component.spec.ts b/lib/process-services/src/lib/attachment/create-task-attachment.component.spec.ts index 4cc1c524fc..dfc275619b 100644 --- a/lib/process-services/src/lib/attachment/create-task-attachment.component.spec.ts +++ b/lib/process-services/src/lib/attachment/create-task-attachment.component.spec.ts @@ -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', () => { diff --git a/lib/process-services/src/lib/attachment/create-task-attachment.component.ts b/lib/process-services/src/lib/attachment/create-task-attachment.component.ts index 62b0704fc1..b7ea9a5e41 100644 --- a/lib/process-services/src/lib/attachment/create-task-attachment.component.ts +++ b/lib/process-services/src/lib/attachment/create-task-attachment.component.ts @@ -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', diff --git a/lib/process-services/src/lib/attachment/process-attachment-list.component.spec.ts b/lib/process-services/src/lib/attachment/process-attachment-list.component.spec.ts index f622d65b3e..e01351a06b 100644 --- a/lib/process-services/src/lib/attachment/process-attachment-list.component.spec.ts +++ b/lib/process-services/src/lib/attachment/process-attachment-list.component.spec.ts @@ -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', () => { diff --git a/lib/process-services/src/lib/attachment/process-attachment-list.component.ts b/lib/process-services/src/lib/attachment/process-attachment-list.component.ts index 2b28cb4c96..772b5a83d5 100644 --- a/lib/process-services/src/lib/attachment/process-attachment-list.component.ts +++ b/lib/process-services/src/lib/attachment/process-attachment-list.component.ts @@ -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', diff --git a/lib/process-services/src/lib/attachment/task-attachment-list.component.spec.ts b/lib/process-services/src/lib/attachment/task-attachment-list.component.spec.ts index 1eb3ce0d25..c22b7f390a 100644 --- a/lib/process-services/src/lib/attachment/task-attachment-list.component.spec.ts +++ b/lib/process-services/src/lib/attachment/task-attachment-list.component.spec.ts @@ -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', () => { diff --git a/lib/process-services/src/lib/attachment/task-attachment-list.component.ts b/lib/process-services/src/lib/attachment/task-attachment-list.component.ts index a7ea33c003..b4263d084f 100644 --- a/lib/process-services/src/lib/attachment/task-attachment-list.component.ts +++ b/lib/process-services/src/lib/attachment/task-attachment-list.component.ts @@ -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', diff --git a/lib/core/src/lib/form/events/validate-dynamic-table-row.event.ts b/lib/process-services/src/lib/form/events/validate-dynamic-table-row.event.ts similarity index 69% rename from lib/core/src/lib/form/events/validate-dynamic-table-row.event.ts rename to lib/process-services/src/lib/form/events/validate-dynamic-table-row.event.ts index d6b592d4a0..0332fefa50 100644 --- a/lib/core/src/lib/form/events/validate-dynamic-table-row.event.ts +++ b/lib/process-services/src/lib/form/events/validate-dynamic-table-row.event.ts @@ -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 { diff --git a/lib/core/src/lib/form/components/form-list.component.html b/lib/process-services/src/lib/form/form-list/form-list.component.html similarity index 100% rename from lib/core/src/lib/form/components/form-list.component.html rename to lib/process-services/src/lib/form/form-list/form-list.component.html diff --git a/lib/core/src/lib/form/components/form-list.component.spec.ts b/lib/process-services/src/lib/form/form-list/form-list.component.spec.ts similarity index 71% rename from lib/core/src/lib/form/components/form-list.component.spec.ts rename to lib/process-services/src/lib/form/form-list/form-list.component.spec.ts index 1e7a12464f..0d526e5456 100644 --- a/lib/core/src/lib/form/components/form-list.component.spec.ts +++ b/lib/process-services/src/lib/form/form-list/form-list.component.spec.ts @@ -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; - 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(); diff --git a/lib/core/src/lib/form/components/form-list.component.ts b/lib/process-services/src/lib/form/form-list/form-list.component.ts similarity index 87% rename from lib/core/src/lib/form/components/form-list.component.ts rename to lib/process-services/src/lib/form/form-list/form-list.component.ts index ece2b61dff..8d342aee97 100644 --- a/lib/core/src/lib/form/components/form-list.component.ts +++ b/lib/process-services/src/lib/form/form-list/form-list.component.ts @@ -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); }); } diff --git a/lib/process-services/src/lib/form/form.component.spec.ts b/lib/process-services/src/lib/form/form.component.spec.ts index 82de8badc1..dcc8fd8842 100644 --- a/lib/process-services/src/lib/form/form.component.spec.ts +++ b/lib/process-services/src/lib/form/form.component.spec.ts @@ -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 = ''; 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 = '
'; 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({})); + 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({})); 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({})); + 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 = ''; 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'} ] }; diff --git a/lib/process-services/src/lib/form/form.component.ts b/lib/process-services/src/lib/form/form.component.ts index a0b342b00b..175ddca055 100644 --- a/lib/process-services/src/lib/form/form.component.ts +++ b/lib/process-services/src/lib/form/form.component.ts @@ -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(); 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 { - return this.formService.getTask(taskId).pipe( - switchMap((task: any) => { + findProcessVariablesByTaskId(taskId: string): Observable { + 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 { return new Promise(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 { + 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) => { diff --git a/lib/process-services/src/lib/form/form.component.visibility.spec.ts b/lib/process-services/src/lib/form/form.component.visibility.spec.ts index ff31c4fe99..6e2d62c860 100644 --- a/lib/process-services/src/lib/form/form.component.visibility.spec.ts +++ b/lib/process-services/src/lib/form/form.component.visibility.spec.ts @@ -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; 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({})); + 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({})); + 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({})); + 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({})); + 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({})); + 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({})); + 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({})); + 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({})); + 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({})); + 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(); diff --git a/lib/process-services/src/lib/form/form.module.ts b/lib/process-services/src/lib/form/form.module.ts index 17e7bf49cb..79b4cc9383 100644 --- a/lib/process-services/src/lib/form/form.module.ts +++ b/lib/process-services/src/lib/form/form.module.ts @@ -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 { +} diff --git a/lib/process-services/src/lib/form/process-form-rendering.service.spec.ts b/lib/process-services/src/lib/form/process-form-rendering.service.spec.ts new file mode 100644 index 0000000000..5b3b9c4e9d --- /dev/null +++ b/lib/process-services/src/lib/form/process-form-rendering.service.spec.ts @@ -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); + }); + +}); diff --git a/lib/process-services/src/lib/form/process-form-rendering.service.ts b/lib/process-services/src/lib/form/process-form-rendering.service.ts index 21d64106e9..7774a718cb 100644 --- a/lib/process-services/src/lib/form/process-form-rendering.service.ts +++ b/lib/process-services/src/lib/form/process-form-rendering.service.ts @@ -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); } } diff --git a/lib/process-services/src/lib/form/public-api.ts b/lib/process-services/src/lib/form/public-api.ts index d16c7c3488..e9b4f772b9 100644 --- a/lib/process-services/src/lib/form/public-api.ts +++ b/lib/process-services/src/lib/form/public-api.ts @@ -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'; diff --git a/lib/core/src/lib/form/services/activiti-alfresco.service.ts b/lib/process-services/src/lib/form/services/activiti-alfresco.service.ts similarity index 93% rename from lib/core/src/lib/form/services/activiti-alfresco.service.ts rename to lib/process-services/src/lib/form/services/activiti-alfresco.service.ts index 5ea094b721..b9a907719d 100644 --- a/lib/core/src/lib/form/services/activiti-alfresco.service.ts +++ b/lib/process-services/src/lib/form/services/activiti-alfresco.service.ts @@ -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({ diff --git a/lib/core/src/lib/form/services/ecm-model.service.spec.ts b/lib/process-services/src/lib/form/services/ecm-model.service.spec.ts similarity index 98% rename from lib/core/src/lib/form/services/ecm-model.service.spec.ts rename to lib/process-services/src/lib/form/services/ecm-model.service.spec.ts index 7d2ffd2743..2ee0fd9f87 100644 --- a/lib/core/src/lib/form/services/ecm-model.service.spec.ts +++ b/lib/process-services/src/lib/form/services/ecm-model.service.spec.ts @@ -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; diff --git a/lib/core/src/lib/form/services/ecm-model.service.ts b/lib/process-services/src/lib/form/services/ecm-model.service.ts similarity index 97% rename from lib/core/src/lib/form/services/ecm-model.service.ts rename to lib/process-services/src/lib/form/services/ecm-model.service.ts index 7583c16760..11139b5585 100644 --- a/lib/core/src/lib/form/services/ecm-model.service.ts +++ b/lib/process-services/src/lib/form/services/ecm-model.service.ts @@ -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); } } diff --git a/lib/process-services/src/lib/form/services/editor.service.ts b/lib/process-services/src/lib/form/services/editor.service.ts new file mode 100644 index 0000000000..85fe62511e --- /dev/null +++ b/lib/process-services/src/lib/form/services/editor.service.ts @@ -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 { + 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 { + 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 { + 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); + } + +} diff --git a/lib/process-services/src/lib/form/services/model.service.ts b/lib/process-services/src/lib/form/services/model.service.ts new file mode 100644 index 0000000000..12ecba939b --- /dev/null +++ b/lib/process-services/src/lib/form/services/model.service.ts @@ -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 { + 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 { + 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 { + 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 { + 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 { + 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); + } + +} diff --git a/lib/core/src/lib/form/services/process-content.service.spec.ts b/lib/process-services/src/lib/form/services/process-content.service.spec.ts similarity index 98% rename from lib/core/src/lib/form/services/process-content.service.spec.ts rename to lib/process-services/src/lib/form/services/process-content.service.spec.ts index 90e0eb2c1a..cb98766004 100644 --- a/lib/core/src/lib/form/services/process-content.service.spec.ts +++ b/lib/process-services/src/lib/form/services/process-content.service.spec.ts @@ -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; diff --git a/lib/core/src/lib/form/services/process-content.service.ts b/lib/process-services/src/lib/form/services/process-content.service.ts similarity index 98% rename from lib/core/src/lib/form/services/process-content.service.ts rename to lib/process-services/src/lib/form/services/process-content.service.ts index 84c4ee6517..9929850c92 100644 --- a/lib/core/src/lib/form/services/process-content.service.ts +++ b/lib/process-services/src/lib/form/services/process-content.service.ts @@ -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'; diff --git a/lib/process-services/src/lib/form/services/process-definition.service.ts b/lib/process-services/src/lib/form/services/process-definition.service.ts new file mode 100644 index 0000000000..82ae8f11f7 --- /dev/null +++ b/lib/process-services/src/lib/form/services/process-definition.service.ts @@ -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 { + 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 { + 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 { + 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); + } + +} diff --git a/lib/process-services/src/lib/form/services/task-form.service.ts b/lib/process-services/src/lib/form/services/task-form.service.ts new file mode 100644 index 0000000000..e474506240 --- /dev/null +++ b/lib/process-services/src/lib/form/services/task-form.service.ts @@ -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 { + 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 { + 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 { + 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 { + 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 { + return from(this.taskFormsApi.getRestFieldColumnValues(taskId, field, column)) + .pipe( + catchError((err) => this.handleError(err)) + ); + } + + getTaskProcessVariable(taskId: string): Observable { + 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 { + 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); + } + +} diff --git a/lib/process-services/src/lib/form/services/task.service.ts b/lib/process-services/src/lib/form/services/task.service.ts new file mode 100644 index 0000000000..22ade5934e --- /dev/null +++ b/lib/process-services/src/lib/form/services/task.service.ts @@ -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 { + 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 { + 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); + } + +} diff --git a/lib/process-services/src/lib/form/start-form.component.spec.ts b/lib/process-services/src/lib/form/start-form.component.spec.ts index 685fcdfe5e..a5c90a6fdc 100644 --- a/lib/process-services/src/lib/form/start-form.component.spec.ts +++ b/lib/process-services/src/lib/form/start-form.component.spec.ts @@ -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; 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', () => { diff --git a/lib/process-services/src/lib/form/start-form.component.ts b/lib/process-services/src/lib/form/start-form.component.ts index bbc29b256c..98b8b9250b 100644 --- a/lib/process-services/src/lib/form/start-form.component.ts +++ b/lib/process-services/src/lib/form/start-form.component.ts @@ -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) => { diff --git a/lib/process-services/src/lib/content-widget/attach-file-widget-dialog-component.interface.ts b/lib/process-services/src/lib/form/widgets/content-widget/attach-file-widget-dialog-component.interface.ts similarity index 100% rename from lib/process-services/src/lib/content-widget/attach-file-widget-dialog-component.interface.ts rename to lib/process-services/src/lib/form/widgets/content-widget/attach-file-widget-dialog-component.interface.ts diff --git a/lib/process-services/src/lib/content-widget/attach-file-widget-dialog.component.html b/lib/process-services/src/lib/form/widgets/content-widget/attach-file-widget-dialog.component.html similarity index 100% rename from lib/process-services/src/lib/content-widget/attach-file-widget-dialog.component.html rename to lib/process-services/src/lib/form/widgets/content-widget/attach-file-widget-dialog.component.html diff --git a/lib/process-services/src/lib/content-widget/attach-file-widget-dialog.component.scss b/lib/process-services/src/lib/form/widgets/content-widget/attach-file-widget-dialog.component.scss similarity index 100% rename from lib/process-services/src/lib/content-widget/attach-file-widget-dialog.component.scss rename to lib/process-services/src/lib/form/widgets/content-widget/attach-file-widget-dialog.component.scss diff --git a/lib/process-services/src/lib/content-widget/attach-file-widget-dialog.component.spec.ts b/lib/process-services/src/lib/form/widgets/content-widget/attach-file-widget-dialog.component.spec.ts similarity index 99% rename from lib/process-services/src/lib/content-widget/attach-file-widget-dialog.component.spec.ts rename to lib/process-services/src/lib/form/widgets/content-widget/attach-file-widget-dialog.component.spec.ts index 6c0e4dc936..69bdc5789c 100644 --- a/lib/process-services/src/lib/content-widget/attach-file-widget-dialog.component.spec.ts +++ b/lib/process-services/src/lib/form/widgets/content-widget/attach-file-widget-dialog.component.spec.ts @@ -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'; diff --git a/lib/process-services/src/lib/content-widget/attach-file-widget-dialog.component.ts b/lib/process-services/src/lib/form/widgets/content-widget/attach-file-widget-dialog.component.ts similarity index 100% rename from lib/process-services/src/lib/content-widget/attach-file-widget-dialog.component.ts rename to lib/process-services/src/lib/form/widgets/content-widget/attach-file-widget-dialog.component.ts diff --git a/lib/process-services/src/lib/content-widget/attach-file-widget-dialog.service.spec.ts b/lib/process-services/src/lib/form/widgets/content-widget/attach-file-widget-dialog.service.spec.ts similarity index 96% rename from lib/process-services/src/lib/content-widget/attach-file-widget-dialog.service.spec.ts rename to lib/process-services/src/lib/form/widgets/content-widget/attach-file-widget-dialog.service.spec.ts index eef600fa0b..94e6172718 100644 --- a/lib/process-services/src/lib/content-widget/attach-file-widget-dialog.service.spec.ts +++ b/lib/process-services/src/lib/form/widgets/content-widget/attach-file-widget-dialog.service.spec.ts @@ -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', () => { diff --git a/lib/process-services/src/lib/content-widget/attach-file-widget-dialog.service.ts b/lib/process-services/src/lib/form/widgets/content-widget/attach-file-widget-dialog.service.ts similarity index 100% rename from lib/process-services/src/lib/content-widget/attach-file-widget-dialog.service.ts rename to lib/process-services/src/lib/form/widgets/content-widget/attach-file-widget-dialog.service.ts diff --git a/lib/process-services/src/lib/content-widget/attach-file-widget.component.html b/lib/process-services/src/lib/form/widgets/content-widget/attach-file-widget.component.html similarity index 97% rename from lib/process-services/src/lib/content-widget/attach-file-widget.component.html rename to lib/process-services/src/lib/form/widgets/content-widget/attach-file-widget.component.html index d28f1affef..948edb5755 100644 --- a/lib/process-services/src/lib/content-widget/attach-file-widget.component.html +++ b/lib/process-services/src/lib/form/widgets/content-widget/attach-file-widget.component.html @@ -40,7 +40,7 @@ (click)="openSelectDialogFromFileSource()"> {{field.params?.fileSource?.name}} - +
@@ -49,7 +49,7 @@ (click)="openSelectDialog(repo)"> {{repo.name}} - +
diff --git a/lib/process-services/src/lib/content-widget/attach-file-widget.component.scss b/lib/process-services/src/lib/form/widgets/content-widget/attach-file-widget.component.scss similarity index 100% rename from lib/process-services/src/lib/content-widget/attach-file-widget.component.scss rename to lib/process-services/src/lib/form/widgets/content-widget/attach-file-widget.component.scss diff --git a/lib/process-services/src/lib/content-widget/attach-file-widget.component.spec.ts b/lib/process-services/src/lib/form/widgets/content-widget/attach-file-widget.component.spec.ts similarity index 99% rename from lib/process-services/src/lib/content-widget/attach-file-widget.component.spec.ts rename to lib/process-services/src/lib/form/widgets/content-widget/attach-file-widget.component.spec.ts index 1da3a87f6e..29e68001bc 100644 --- a/lib/process-services/src/lib/content-widget/attach-file-widget.component.spec.ts +++ b/lib/process-services/src/lib/form/widgets/content-widget/attach-file-widget.component.spec.ts @@ -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 = [ { diff --git a/lib/process-services/src/lib/content-widget/attach-file-widget.component.ts b/lib/process-services/src/lib/form/widgets/content-widget/attach-file-widget.component.ts similarity index 97% rename from lib/process-services/src/lib/content-widget/attach-file-widget.component.ts rename to lib/process-services/src/lib/form/widgets/content-widget/attach-file-widget.component.ts index 89cb550ffa..650b07b491 100644 --- a/lib/process-services/src/lib/content-widget/attach-file-widget.component.ts +++ b/lib/process-services/src/lib/form/widgets/content-widget/attach-file-widget.component.ts @@ -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', diff --git a/lib/process-services/src/lib/content-widget/attach-folder-widget.component.html b/lib/process-services/src/lib/form/widgets/content-widget/attach-folder-widget.component.html similarity index 100% rename from lib/process-services/src/lib/content-widget/attach-folder-widget.component.html rename to lib/process-services/src/lib/form/widgets/content-widget/attach-folder-widget.component.html diff --git a/lib/process-services/src/lib/content-widget/attach-folder-widget.component.scss b/lib/process-services/src/lib/form/widgets/content-widget/attach-folder-widget.component.scss similarity index 100% rename from lib/process-services/src/lib/content-widget/attach-folder-widget.component.scss rename to lib/process-services/src/lib/form/widgets/content-widget/attach-folder-widget.component.scss diff --git a/lib/process-services/src/lib/content-widget/attach-folder-widget.component.spec.ts b/lib/process-services/src/lib/form/widgets/content-widget/attach-folder-widget.component.spec.ts similarity index 98% rename from lib/process-services/src/lib/content-widget/attach-folder-widget.component.spec.ts rename to lib/process-services/src/lib/form/widgets/content-widget/attach-folder-widget.component.spec.ts index d509c825f3..a56f829e5a 100644 --- a/lib/process-services/src/lib/content-widget/attach-folder-widget.component.spec.ts +++ b/lib/process-services/src/lib/form/widgets/content-widget/attach-folder-widget.component.spec.ts @@ -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 = { diff --git a/lib/process-services/src/lib/content-widget/attach-folder-widget.component.ts b/lib/process-services/src/lib/form/widgets/content-widget/attach-folder-widget.component.ts similarity index 100% rename from lib/process-services/src/lib/content-widget/attach-folder-widget.component.ts rename to lib/process-services/src/lib/form/widgets/content-widget/attach-folder-widget.component.ts diff --git a/lib/process-services/src/lib/content-widget/content-widget.module.ts b/lib/process-services/src/lib/form/widgets/content-widget/content-widget.module.ts similarity index 96% rename from lib/process-services/src/lib/content-widget/content-widget.module.ts rename to lib/process-services/src/lib/form/widgets/content-widget/content-widget.module.ts index 7f7bf8a09c..15665211a2 100644 --- a/lib/process-services/src/lib/content-widget/content-widget.module.ts +++ b/lib/process-services/src/lib/form/widgets/content-widget/content-widget.module.ts @@ -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'; diff --git a/lib/process-services/src/lib/content-widget/index.ts b/lib/process-services/src/lib/form/widgets/content-widget/index.ts similarity index 100% rename from lib/process-services/src/lib/content-widget/index.ts rename to lib/process-services/src/lib/form/widgets/content-widget/index.ts diff --git a/lib/process-services/src/lib/content-widget/public-api.ts b/lib/process-services/src/lib/form/widgets/content-widget/public-api.ts similarity index 100% rename from lib/process-services/src/lib/content-widget/public-api.ts rename to lib/process-services/src/lib/form/widgets/content-widget/public-api.ts diff --git a/lib/core/src/lib/form/components/widgets/content/content.widget.html b/lib/process-services/src/lib/form/widgets/document/content.widget.html similarity index 100% rename from lib/core/src/lib/form/components/widgets/content/content.widget.html rename to lib/process-services/src/lib/form/widgets/document/content.widget.html diff --git a/lib/core/src/lib/form/components/widgets/content/content.widget.scss b/lib/process-services/src/lib/form/widgets/document/content.widget.scss similarity index 100% rename from lib/core/src/lib/form/components/widgets/content/content.widget.scss rename to lib/process-services/src/lib/form/widgets/document/content.widget.scss diff --git a/lib/core/src/lib/form/components/widgets/content/content.widget.spec.ts b/lib/process-services/src/lib/form/widgets/document/content.widget.spec.ts similarity index 94% rename from lib/core/src/lib/form/components/widgets/content/content.widget.spec.ts rename to lib/process-services/src/lib/form/widgets/document/content.widget.spec.ts index 1f81e5c16c..f52ea61d03 100644 --- a/lib/core/src/lib/form/components/widgets/content/content.widget.spec.ts +++ b/lib/process-services/src/lib/form/widgets/document/content.widget.spec.ts @@ -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(); diff --git a/lib/core/src/lib/form/components/widgets/content/content.widget.ts b/lib/process-services/src/lib/form/widgets/document/content.widget.ts similarity index 92% rename from lib/core/src/lib/form/components/widgets/content/content.widget.ts rename to lib/process-services/src/lib/form/widgets/document/content.widget.ts index a5f04e41da..614ef5f36a 100644 --- a/lib/core/src/lib/form/components/widgets/content/content.widget.ts +++ b/lib/process-services/src/lib/form/widgets/document/content.widget.ts @@ -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', diff --git a/lib/core/src/lib/form/components/widgets/document/document.widget.html b/lib/process-services/src/lib/form/widgets/document/document.widget.html similarity index 100% rename from lib/core/src/lib/form/components/widgets/document/document.widget.html rename to lib/process-services/src/lib/form/widgets/document/document.widget.html diff --git a/lib/core/src/lib/form/components/widgets/document/document.widget.ts b/lib/process-services/src/lib/form/widgets/document/document.widget.ts similarity index 92% rename from lib/core/src/lib/form/components/widgets/document/document.widget.ts rename to lib/process-services/src/lib/form/widgets/document/document.widget.ts index d96a08ffd4..82847b34ae 100644 --- a/lib/core/src/lib/form/components/widgets/document/document.widget.ts +++ b/lib/process-services/src/lib/form/widgets/document/document.widget.ts @@ -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() { diff --git a/lib/core/src/lib/form/components/widgets/dropdown/dropdown.widget.html b/lib/process-services/src/lib/form/widgets/dropdown/dropdown.widget.html similarity index 100% rename from lib/core/src/lib/form/components/widgets/dropdown/dropdown.widget.html rename to lib/process-services/src/lib/form/widgets/dropdown/dropdown.widget.html diff --git a/lib/core/src/lib/form/components/widgets/dropdown/dropdown.widget.scss b/lib/process-services/src/lib/form/widgets/dropdown/dropdown.widget.scss similarity index 100% rename from lib/core/src/lib/form/components/widgets/dropdown/dropdown.widget.scss rename to lib/process-services/src/lib/form/widgets/dropdown/dropdown.widget.scss diff --git a/lib/core/src/lib/form/components/widgets/dropdown/dropdown.widget.spec.ts b/lib/process-services/src/lib/form/widgets/dropdown/dropdown.widget.spec.ts similarity index 82% rename from lib/core/src/lib/form/components/widgets/dropdown/dropdown.widget.spec.ts rename to lib/process-services/src/lib/form/widgets/dropdown/dropdown.widget.spec.ts index a4c69e764d..a0a4021e37 100644 --- a/lib/core/src/lib/form/components/widgets/dropdown/dropdown.widget.spec.ts +++ b/lib/process-services/src/lib/form/widgets/dropdown/dropdown.widget.spec.ts @@ -18,20 +18,24 @@ import { ComponentFixture, TestBed } from '@angular/core/testing'; import { By } from '@angular/platform-browser'; import { Observable, of } from 'rxjs'; -import { FormService } from '../../../services/form.service'; -import { WidgetVisibilityService } from '../../../services/widget-visibility.service'; -import { FormFieldOption } from '../core/form-field-option'; -import { FormFieldModel } from '../core/form-field.model'; -import { FormModel } from '../core/form.model'; -import { FormFieldTypes } from '../core/form-field-types'; +import { + WidgetVisibilityService, + FormFieldOption, + FormFieldModel, + FormModel, + FormFieldTypes, + CoreTestingModule, + setupTestBed +} from '@alfresco/adf-core'; import { DropdownWidgetComponent } from './dropdown.widget'; -import { setupTestBed } from '../../../../testing/setup-test-bed'; -import { CoreTestingModule } from '../../../../testing/core.testing.module'; import { TranslateModule } from '@ngx-translate/core'; +import { TaskFormService } from '../../services/task-form.service'; +import { ProcessDefinitionService } from '../../services/process-definition.service'; describe('DropdownWidgetComponent', () => { - let formService: FormService; + let taskFormService: TaskFormService; + let processDefinitionService: ProcessDefinitionService; let widget: DropdownWidgetComponent; let visibilityService: WidgetVisibilityService; let fixture: ComponentFixture; @@ -43,9 +47,9 @@ describe('DropdownWidgetComponent', () => { }; const fakeOptionList: FormFieldOption[] = [ - { id: 'opt_1', name: 'option_1' }, - { id: 'opt_2', name: 'option_2' }, - { id: 'opt_3', name: 'option_3' }]; + {id: 'opt_1', name: 'option_1'}, + {id: 'opt_2', name: 'option_2'}, + {id: 'opt_3', name: 'option_3'}]; setupTestBed({ imports: [ @@ -58,21 +62,22 @@ describe('DropdownWidgetComponent', () => { fixture = TestBed.createComponent(DropdownWidgetComponent); widget = fixture.componentInstance; element = fixture.nativeElement; - formService = TestBed.inject(FormService); + taskFormService = TestBed.inject(TaskFormService); visibilityService = TestBed.inject(WidgetVisibilityService); + processDefinitionService = TestBed.inject(ProcessDefinitionService); widget.field = new FormFieldModel(new FormModel()); }); it('should require field with restUrl', () => { - spyOn(formService, 'getRestFieldValues').and.stub(); + spyOn(taskFormService, 'getRestFieldValues').and.stub(); widget.field = null; widget.ngOnInit(); - expect(formService.getRestFieldValues).not.toHaveBeenCalled(); + expect(taskFormService.getRestFieldValues).not.toHaveBeenCalled(); - widget.field = new FormFieldModel(null, { restUrl: null }); + widget.field = new FormFieldModel(null, {restUrl: null}); widget.ngOnInit(); - expect(formService.getRestFieldValues).not.toHaveBeenCalled(); + expect(taskFormService.getRestFieldValues).not.toHaveBeenCalled(); }); it('should request field values from service', () => { @@ -88,25 +93,25 @@ describe('DropdownWidgetComponent', () => { restUrl: '' }); - spyOn(formService, 'getRestFieldValues').and.returnValue( + spyOn(taskFormService, 'getRestFieldValues').and.returnValue( new Observable((observer) => { observer.next(null); observer.complete(); }) ); widget.ngOnInit(); - expect(formService.getRestFieldValues).toHaveBeenCalledWith(taskId, fieldId); + expect(taskFormService.getRestFieldValues).toHaveBeenCalledWith(taskId, fieldId); }); it('should preserve empty option when loading fields', () => { - const restFieldValue: FormFieldOption = { id: '1', name: 'Option1' } as FormFieldOption; - spyOn(formService, 'getRestFieldValues').and.callFake(() => new Observable((observer) => { + const restFieldValue: FormFieldOption = {id: '1', name: 'Option1'} as FormFieldOption; + spyOn(taskFormService, 'getRestFieldValues').and.callFake(() => new Observable((observer) => { observer.next([restFieldValue]); observer.complete(); })); - const form = new FormModel({ taskId: '' }); - const emptyOption: FormFieldOption = { id: 'empty', name: 'Empty' } as FormFieldOption; + const form = new FormModel({taskId: ''}); + const emptyOption: FormFieldOption = {id: 'empty', name: 'Empty'} as FormFieldOption; widget.field = new FormFieldModel(form, { id: '', restUrl: '/some/url/address', @@ -115,7 +120,7 @@ describe('DropdownWidgetComponent', () => { }); widget.ngOnInit(); - expect(formService.getRestFieldValues).toHaveBeenCalled(); + expect(taskFormService.getRestFieldValues).toHaveBeenCalled(); expect(widget.field.options.length).toBe(2); expect(widget.field.options[0]).toBe(emptyOption); expect(widget.field.options[1]).toBe(restFieldValue); @@ -124,7 +129,7 @@ describe('DropdownWidgetComponent', () => { describe('when is required', () => { beforeEach(() => { - widget.field = new FormFieldModel( new FormModel({ taskId: '' }), { + widget.field = new FormFieldModel(new FormModel({taskId: ''}), { type: FormFieldTypes.DROPDOWN, required: true }); @@ -169,15 +174,15 @@ describe('DropdownWidgetComponent', () => { beforeEach(() => { spyOn(visibilityService, 'refreshVisibility').and.stub(); - spyOn(formService, 'getRestFieldValues').and.callFake(() => of(fakeOptionList)); - widget.field = new FormFieldModel(new FormModel({ taskId: 'fake-task-id' }), { + spyOn(taskFormService, 'getRestFieldValues').and.callFake(() => of(fakeOptionList)); + widget.field = new FormFieldModel(new FormModel({taskId: 'fake-task-id'}), { id: 'dropdown-id', name: 'date-name', type: 'dropdown', readOnly: 'false', restUrl: 'fake-rest-url' }); - widget.field.emptyOption = { id: 'empty', name: 'Choose one...' }; + widget.field.emptyOption = {id: 'empty', name: 'Choose one...'}; widget.field.isVisible = true; fixture.detectChanges(); }); @@ -230,15 +235,15 @@ describe('DropdownWidgetComponent', () => { beforeEach(() => { spyOn(visibilityService, 'refreshVisibility').and.stub(); - spyOn(formService, 'getRestFieldValuesByProcessId').and.callFake(() => of(fakeOptionList)); - widget.field = new FormFieldModel(new FormModel({ processDefinitionId: 'fake-process-id' }), { + spyOn(processDefinitionService, 'getRestFieldValuesByProcessId').and.callFake(() => of(fakeOptionList)); + widget.field = new FormFieldModel(new FormModel({processDefinitionId: 'fake-process-id'}), { id: 'dropdown-id', name: 'date-name', type: 'dropdown', readOnly: 'false', restUrl: 'fake-rest-url' }); - widget.field.emptyOption = { id: 'empty', name: 'Choose one...' }; + widget.field.emptyOption = {id: 'empty', name: 'Choose one...'}; widget.field.isVisible = true; fixture.detectChanges(); }); @@ -287,7 +292,7 @@ describe('DropdownWidgetComponent', () => { }); it('should be disabled when the field is readonly', async () => { - widget.field = new FormFieldModel(new FormModel({ processDefinitionId: 'fake-process-id' }), { + widget.field = new FormFieldModel(new FormModel({processDefinitionId: 'fake-process-id'}), { id: 'dropdown-id', name: 'date-name', type: 'dropdown', @@ -304,13 +309,13 @@ describe('DropdownWidgetComponent', () => { }); it('should show the option value when the field is readonly', async () => { - widget.field = new FormFieldModel(new FormModel({ processDefinitionId: 'fake-process-id' }), { + widget.field = new FormFieldModel(new FormModel({processDefinitionId: 'fake-process-id'}), { id: 'dropdown-id', name: 'date-name', type: 'readonly', value: 'FakeValue', readOnly: true, - params: { field: { name: 'date-name', type: 'dropdown' } } + params: {field: {name: 'date-name', type: 'dropdown'}} }); openSelect(); diff --git a/lib/core/src/lib/form/components/widgets/dropdown/dropdown.widget.ts b/lib/process-services/src/lib/form/widgets/dropdown/dropdown.widget.ts similarity index 86% rename from lib/core/src/lib/form/components/widgets/dropdown/dropdown.widget.ts rename to lib/process-services/src/lib/form/widgets/dropdown/dropdown.widget.ts index de79380210..b15dfef870 100644 --- a/lib/core/src/lib/form/components/widgets/dropdown/dropdown.widget.ts +++ b/lib/process-services/src/lib/form/widgets/dropdown/dropdown.widget.ts @@ -15,13 +15,17 @@ * limitations under the License. */ - /* eslint-disable @angular-eslint/component-selector */ +/* eslint-disable @angular-eslint/component-selector */ -import { LogService } from '../../../../services/log.service'; import { Component, OnInit, ViewEncapsulation } from '@angular/core'; -import { FormService } from '../../../services/form.service'; -import { FormFieldOption } from '../core/form-field-option'; -import { WidgetComponent } from '../widget.component'; +import { + FormService, + FormFieldOption, + WidgetComponent, + LogService +} from '@alfresco/adf-core'; +import { ProcessDefinitionService } from '../../services/process-definition.service'; +import { TaskFormService } from '../../services/task-form.service'; @Component({ selector: 'dropdown-widget', @@ -43,8 +47,10 @@ import { WidgetComponent } from '../widget.component'; export class DropdownWidgetComponent extends WidgetComponent implements OnInit { constructor(public formService: FormService, + public taskFormService: TaskFormService, + public processDefinitionService: ProcessDefinitionService, private logService: LogService) { - super(formService); + super(formService); } ngOnInit() { @@ -58,7 +64,7 @@ export class DropdownWidgetComponent extends WidgetComponent implements OnInit { } getValuesByTaskId() { - this.formService + this.taskFormService .getRestFieldValues( this.field.form.taskId, this.field.id @@ -77,7 +83,7 @@ export class DropdownWidgetComponent extends WidgetComponent implements OnInit { } getValuesByProcessDefinitionId() { - this.formService + this.processDefinitionService .getRestFieldValuesByProcessId( this.field.form.processDefinitionId, this.field.id diff --git a/lib/process-services/src/lib/form/widgets/dynamic-table/dynamic-table.module.ts b/lib/process-services/src/lib/form/widgets/dynamic-table/dynamic-table.module.ts new file mode 100644 index 0000000000..cd7f713623 --- /dev/null +++ b/lib/process-services/src/lib/form/widgets/dynamic-table/dynamic-table.module.ts @@ -0,0 +1,51 @@ +/*! + * @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 { NgModule } from '@angular/core'; +import { MaterialModule } from '../../../material.module'; +import { CoreModule } from '@alfresco/adf-core'; +import { RowEditorComponent } from './editors/row-editor/row.editor'; +import { DynamicTableWidgetComponent } from './dynamic-table.widget'; +import { DropdownEditorComponent } from './editors/dropdown/dropdown.editor'; +import { DateTimeEditorComponent } from './editors/datetime/datetime.editor'; +import { DateEditorComponent } from './editors/date/date.editor'; +import { BooleanEditorComponent } from './editors/boolean/boolean.editor'; +import { AmountEditorComponent } from './editors/amount/amount.editor'; +import { TextEditorComponent } from './editors/text/text.editor'; + +@NgModule({ + imports: [ + CoreModule, + MaterialModule + ], + declarations: [ + AmountEditorComponent, + BooleanEditorComponent, + DateEditorComponent, + DateTimeEditorComponent, + DropdownEditorComponent, + RowEditorComponent, + DynamicTableWidgetComponent, + TextEditorComponent + ], + exports: [ + DynamicTableWidgetComponent, + RowEditorComponent + ] +}) +export class DynamicTableModule { +} diff --git a/lib/core/src/lib/form/components/widgets/dynamic-table/dynamic-table.widget.html b/lib/process-services/src/lib/form/widgets/dynamic-table/dynamic-table.widget.html similarity index 100% rename from lib/core/src/lib/form/components/widgets/dynamic-table/dynamic-table.widget.html rename to lib/process-services/src/lib/form/widgets/dynamic-table/dynamic-table.widget.html diff --git a/lib/core/src/lib/form/components/widgets/dynamic-table/dynamic-table.widget.scss b/lib/process-services/src/lib/form/widgets/dynamic-table/dynamic-table.widget.scss similarity index 98% rename from lib/core/src/lib/form/components/widgets/dynamic-table/dynamic-table.widget.scss rename to lib/process-services/src/lib/form/widgets/dynamic-table/dynamic-table.widget.scss index d6132be481..fafbc5c2b4 100644 --- a/lib/core/src/lib/form/components/widgets/dynamic-table/dynamic-table.widget.scss +++ b/lib/process-services/src/lib/form/widgets/dynamic-table/dynamic-table.widget.scss @@ -1,5 +1,5 @@ /* stylelint-disable no-descending-specificity */ -@import '../../../../styles/mixins'; +@import '../../../../../../core/src/lib/styles/mixins'; $dynamic-table-font-size: var(--theme-body-1-font-size) !default; $dynamic-table-header-font-size: var(--theme-caption-font-size) !default; diff --git a/lib/core/src/lib/form/components/widgets/dynamic-table/dynamic-table.widget.spec.ts b/lib/process-services/src/lib/form/widgets/dynamic-table/dynamic-table.widget.spec.ts similarity index 95% rename from lib/core/src/lib/form/components/widgets/dynamic-table/dynamic-table.widget.spec.ts rename to lib/process-services/src/lib/form/widgets/dynamic-table/dynamic-table.widget.spec.ts index 060426acc3..ec01146c8e 100644 --- a/lib/core/src/lib/form/components/widgets/dynamic-table/dynamic-table.widget.spec.ts +++ b/lib/process-services/src/lib/form/widgets/dynamic-table/dynamic-table.widget.spec.ts @@ -16,15 +16,19 @@ */ import { ComponentFixture, TestBed } from '@angular/core/testing'; -import { LogService } from '../../../../services'; -import { FormService } from '../../../services/form.service'; -import { FormFieldModel, FormFieldTypes, FormModel } from '../core'; -import { DynamicTableColumn } from './dynamic-table-column.model'; -import { DynamicTableRow } from './dynamic-table-row.model'; +import { + FormFieldModel, + FormFieldTypes, + FormModel, + LogService, + FormService, + setupTestBed, + CoreTestingModule +} from '@alfresco/adf-core'; +import { DynamicTableColumn } from './editors/models/dynamic-table-column.model'; +import { DynamicTableRow } from './editors/models/dynamic-table-row.model'; import { DynamicTableWidgetComponent } from './dynamic-table.widget'; -import { DynamicTableModel } from './dynamic-table.widget.model'; -import { setupTestBed } from '../../../../testing/setup-test-bed'; -import { CoreTestingModule } from '../../../../testing/core.testing.module'; +import { DynamicTableModel } from './editors/models/dynamic-table.widget.model'; import { TranslateModule } from '@ngx-translate/core'; const fakeFormField = { @@ -308,7 +312,7 @@ describe('DynamicTableWidgetComponent', () => { expect(widget.content.field.validate()).toBeTruthy(); expect(widget.isValid()).toBe(widget.content.field.isValid); expect(widget.content.field.isValid).toBeTruthy(); - }); + }); it('should prepend default currency for amount columns', () => { const row = {value: {key: '100'}} as DynamicTableRow; diff --git a/lib/core/src/lib/form/components/widgets/dynamic-table/dynamic-table.widget.ts b/lib/process-services/src/lib/form/widgets/dynamic-table/dynamic-table.widget.ts similarity index 91% rename from lib/core/src/lib/form/components/widgets/dynamic-table/dynamic-table.widget.ts rename to lib/process-services/src/lib/form/widgets/dynamic-table/dynamic-table.widget.ts index 77dd978c7b..326f3cf052 100644 --- a/lib/core/src/lib/form/components/widgets/dynamic-table/dynamic-table.widget.ts +++ b/lib/process-services/src/lib/form/widgets/dynamic-table/dynamic-table.widget.ts @@ -17,14 +17,11 @@ /* eslint-disable @angular-eslint/component-selector */ -import { LogService } from '../../../../services/log.service'; +import { LogService, WidgetVisibilityService, WidgetComponent, FormService } from '@alfresco/adf-core'; import { ChangeDetectorRef, Component, ElementRef, OnInit, ViewEncapsulation } from '@angular/core'; -import { WidgetVisibilityService } from '../../../services/widget-visibility.service'; -import { FormService } from '../../../services/form.service'; -import { WidgetComponent } from '../widget.component'; -import { DynamicTableColumn } from './dynamic-table-column.model'; -import { DynamicTableRow } from './dynamic-table-row.model'; -import { DynamicTableModel } from './dynamic-table.widget.model'; +import { DynamicTableColumn } from './editors/models/dynamic-table-column.model'; +import { DynamicTableRow } from './editors/models/dynamic-table-row.model'; +import { DynamicTableModel } from './editors/models/dynamic-table.widget.model'; @Component({ selector: 'dynamic-table-widget', @@ -195,7 +192,7 @@ export class DynamicTableWidgetComponent extends WidgetComponent implements OnIn } copyRow(row: DynamicTableRow): DynamicTableRow { - return { value: this.copyObject(row.value) } as DynamicTableRow; + return {value: this.copyObject(row.value)} as DynamicTableRow; } private copyObject(obj: any): any { diff --git a/lib/core/src/lib/form/components/widgets/dynamic-table/editors/amount/amount.editor.html b/lib/process-services/src/lib/form/widgets/dynamic-table/editors/amount/amount.editor.html similarity index 100% rename from lib/core/src/lib/form/components/widgets/dynamic-table/editors/amount/amount.editor.html rename to lib/process-services/src/lib/form/widgets/dynamic-table/editors/amount/amount.editor.html diff --git a/lib/core/src/lib/form/components/widgets/dynamic-table/editors/amount/amount.editor.scss b/lib/process-services/src/lib/form/widgets/dynamic-table/editors/amount/amount.editor.scss similarity index 100% rename from lib/core/src/lib/form/components/widgets/dynamic-table/editors/amount/amount.editor.scss rename to lib/process-services/src/lib/form/widgets/dynamic-table/editors/amount/amount.editor.scss diff --git a/lib/core/src/lib/form/components/widgets/dynamic-table/editors/amount/amount.editor.spec.ts b/lib/process-services/src/lib/form/widgets/dynamic-table/editors/amount/amount.editor.spec.ts similarity index 89% rename from lib/core/src/lib/form/components/widgets/dynamic-table/editors/amount/amount.editor.spec.ts rename to lib/process-services/src/lib/form/widgets/dynamic-table/editors/amount/amount.editor.spec.ts index c0ab2da832..a8d9c4ab34 100644 --- a/lib/core/src/lib/form/components/widgets/dynamic-table/editors/amount/amount.editor.spec.ts +++ b/lib/process-services/src/lib/form/widgets/dynamic-table/editors/amount/amount.editor.spec.ts @@ -15,8 +15,8 @@ * limitations under the License. */ -import { DynamicTableColumn } from '../../dynamic-table-column.model'; -import { DynamicTableRow } from '../../dynamic-table-row.model'; +import { DynamicTableColumn } from '../models/dynamic-table-column.model'; +import { DynamicTableRow } from '../models/dynamic-table-row.model'; import { AmountEditorComponent } from './amount.editor'; describe('AmountEditorComponent', () => { diff --git a/lib/core/src/lib/form/components/widgets/dynamic-table/editors/amount/amount.editor.ts b/lib/process-services/src/lib/form/widgets/dynamic-table/editors/amount/amount.editor.ts similarity index 86% rename from lib/core/src/lib/form/components/widgets/dynamic-table/editors/amount/amount.editor.ts rename to lib/process-services/src/lib/form/widgets/dynamic-table/editors/amount/amount.editor.ts index b15f660358..c39e47708a 100644 --- a/lib/core/src/lib/form/components/widgets/dynamic-table/editors/amount/amount.editor.ts +++ b/lib/process-services/src/lib/form/widgets/dynamic-table/editors/amount/amount.editor.ts @@ -18,9 +18,9 @@ /* eslint-disable @angular-eslint/component-selector */ import { Component, Input, OnInit } from '@angular/core'; -import { DynamicTableColumn } from '../../dynamic-table-column.model'; -import { DynamicTableRow } from '../../dynamic-table-row.model'; -import { DynamicTableModel } from '../../dynamic-table.widget.model'; +import { DynamicTableColumn } from '../models/dynamic-table-column.model'; +import { DynamicTableRow } from '../models/dynamic-table-row.model'; +import { DynamicTableModel } from '../models/dynamic-table.widget.model'; @Component({ selector: 'adf-amount-editor', diff --git a/lib/core/src/lib/form/components/widgets/dynamic-table/editors/boolean/boolean.editor.html b/lib/process-services/src/lib/form/widgets/dynamic-table/editors/boolean/boolean.editor.html similarity index 100% rename from lib/core/src/lib/form/components/widgets/dynamic-table/editors/boolean/boolean.editor.html rename to lib/process-services/src/lib/form/widgets/dynamic-table/editors/boolean/boolean.editor.html diff --git a/lib/core/src/lib/form/components/widgets/dynamic-table/editors/boolean/boolean.editor.scss b/lib/process-services/src/lib/form/widgets/dynamic-table/editors/boolean/boolean.editor.scss similarity index 100% rename from lib/core/src/lib/form/components/widgets/dynamic-table/editors/boolean/boolean.editor.scss rename to lib/process-services/src/lib/form/widgets/dynamic-table/editors/boolean/boolean.editor.scss diff --git a/lib/core/src/lib/form/components/widgets/dynamic-table/editors/boolean/boolean.editor.spec.ts b/lib/process-services/src/lib/form/widgets/dynamic-table/editors/boolean/boolean.editor.spec.ts similarity index 88% rename from lib/core/src/lib/form/components/widgets/dynamic-table/editors/boolean/boolean.editor.spec.ts rename to lib/process-services/src/lib/form/widgets/dynamic-table/editors/boolean/boolean.editor.spec.ts index 5245d743fe..3f5182e396 100644 --- a/lib/core/src/lib/form/components/widgets/dynamic-table/editors/boolean/boolean.editor.spec.ts +++ b/lib/process-services/src/lib/form/widgets/dynamic-table/editors/boolean/boolean.editor.spec.ts @@ -15,8 +15,8 @@ * limitations under the License. */ -import { DynamicTableColumn } from '../../dynamic-table-column.model'; -import { DynamicTableRow } from '../../dynamic-table-row.model'; +import { DynamicTableColumn } from '../models/dynamic-table-column.model'; +import { DynamicTableRow } from '../models/dynamic-table-row.model'; import { BooleanEditorComponent } from './boolean.editor'; diff --git a/lib/core/src/lib/form/components/widgets/dynamic-table/editors/boolean/boolean.editor.ts b/lib/process-services/src/lib/form/widgets/dynamic-table/editors/boolean/boolean.editor.ts similarity index 84% rename from lib/core/src/lib/form/components/widgets/dynamic-table/editors/boolean/boolean.editor.ts rename to lib/process-services/src/lib/form/widgets/dynamic-table/editors/boolean/boolean.editor.ts index e8b6130e57..2dc366274c 100644 --- a/lib/core/src/lib/form/components/widgets/dynamic-table/editors/boolean/boolean.editor.ts +++ b/lib/process-services/src/lib/form/widgets/dynamic-table/editors/boolean/boolean.editor.ts @@ -18,9 +18,9 @@ /* eslint-disable @angular-eslint/component-selector */ import { Component, Input } from '@angular/core'; -import { DynamicTableColumn } from '../../dynamic-table-column.model'; -import { DynamicTableRow } from '../../dynamic-table-row.model'; -import { DynamicTableModel } from '../../dynamic-table.widget.model'; +import { DynamicTableColumn } from '../models/dynamic-table-column.model'; +import { DynamicTableRow } from '../models/dynamic-table-row.model'; +import { DynamicTableModel } from '../models/dynamic-table.widget.model'; @Component({ selector: 'adf-boolean-editor', diff --git a/lib/core/src/lib/form/components/widgets/dynamic-table/editors/date/date.editor.html b/lib/process-services/src/lib/form/widgets/dynamic-table/editors/date/date.editor.html similarity index 100% rename from lib/core/src/lib/form/components/widgets/dynamic-table/editors/date/date.editor.html rename to lib/process-services/src/lib/form/widgets/dynamic-table/editors/date/date.editor.html diff --git a/lib/core/src/lib/form/components/widgets/dynamic-table/editors/date/date.editor.scss b/lib/process-services/src/lib/form/widgets/dynamic-table/editors/date/date.editor.scss similarity index 100% rename from lib/core/src/lib/form/components/widgets/dynamic-table/editors/date/date.editor.scss rename to lib/process-services/src/lib/form/widgets/dynamic-table/editors/date/date.editor.scss diff --git a/lib/core/src/lib/form/components/widgets/dynamic-table/editors/date/date.editor.spec.ts b/lib/process-services/src/lib/form/widgets/dynamic-table/editors/date/date.editor.spec.ts similarity index 87% rename from lib/core/src/lib/form/components/widgets/dynamic-table/editors/date/date.editor.spec.ts rename to lib/process-services/src/lib/form/widgets/dynamic-table/editors/date/date.editor.spec.ts index 5bef84e870..fda906f647 100644 --- a/lib/core/src/lib/form/components/widgets/dynamic-table/editors/date/date.editor.spec.ts +++ b/lib/process-services/src/lib/form/widgets/dynamic-table/editors/date/date.editor.spec.ts @@ -16,15 +16,13 @@ */ import { ComponentFixture, TestBed } from '@angular/core/testing'; -import { FormFieldModel, FormModel } from '../../../index'; -import { DynamicTableColumn } from '../../dynamic-table-column.model'; -import { DynamicTableRow } from '../../dynamic-table-row.model'; -import { DynamicTableModel } from '../../dynamic-table.widget.model'; +import { FormFieldModel, FormModel, setupTestBed, CoreTestingModule } from '@alfresco/adf-core'; +import { DynamicTableColumn } from '../models/dynamic-table-column.model'; +import { DynamicTableRow } from '../models/dynamic-table-row.model'; +import { DynamicTableModel } from '../models/dynamic-table.widget.model'; import { DateEditorComponent } from './date.editor'; -import { setupTestBed } from '../../../../../../testing/setup-test-bed'; import { By } from '@angular/platform-browser'; import { MatDatepickerInputEvent } from '@angular/material/datepicker'; -import { CoreTestingModule } from '../../../../../../testing'; import { TranslateModule } from '@ngx-translate/core'; describe('DateEditorComponent', () => { @@ -45,8 +43,8 @@ describe('DateEditorComponent', () => { fixture = TestBed.createComponent(DateEditorComponent); component = fixture.componentInstance; - row = { value: { date: '1879-03-14T00:00:00.000Z' } } as DynamicTableRow; - column = { id: 'date', type: 'Date' } as DynamicTableColumn; + row = {value: {date: '1879-03-14T00:00:00.000Z'}} as DynamicTableRow; + column = {id: 'date', type: 'Date'} as DynamicTableColumn; const field = new FormFieldModel(new FormModel()); table = new DynamicTableModel(field, null); table.rows.push(row); @@ -58,7 +56,7 @@ describe('DateEditorComponent', () => { describe('using Date Piker', () => { it('should update row value on change', () => { - const input = {value: '14-03-2016' } as MatDatepickerInputEvent; + const input = {value: '14-03-2016'} as MatDatepickerInputEvent; component.ngOnInit(); component.onDateChanged(input); @@ -69,7 +67,7 @@ describe('DateEditorComponent', () => { it('should flush value on user input', () => { spyOn(table, 'flushValue').and.callThrough(); - const input = {value: '14-03-2016' } as MatDatepickerInputEvent; + const input = {value: '14-03-2016'} as MatDatepickerInputEvent; component.ngOnInit(); component.onDateChanged(input); @@ -139,5 +137,5 @@ describe('DateEditorComponent', () => { const actual = row.value[column.id]; expect(actual).toBe(''); }); - }); + }); }); diff --git a/lib/core/src/lib/form/components/widgets/dynamic-table/editors/date/date.editor.ts b/lib/process-services/src/lib/form/widgets/dynamic-table/editors/date/date.editor.ts similarity index 83% rename from lib/core/src/lib/form/components/widgets/dynamic-table/editors/date/date.editor.ts rename to lib/process-services/src/lib/form/widgets/dynamic-table/editors/date/date.editor.ts index a0351229f4..540e18a52e 100644 --- a/lib/core/src/lib/form/components/widgets/dynamic-table/editors/date/date.editor.ts +++ b/lib/process-services/src/lib/form/widgets/dynamic-table/editors/date/date.editor.ts @@ -17,17 +17,19 @@ /* eslint-disable @angular-eslint/component-selector */ -import { UserPreferencesService, UserPreferenceValues } from '../../../../../../services/user-preferences.service'; - -import { MomentDateAdapter } from '../../../../../../utils/moment-date-adapter'; -import { MOMENT_DATE_FORMATS } from '../../../../../../utils/moment-date-formats.model'; +import { + UserPreferencesService, + UserPreferenceValues, + MomentDateAdapter, + MOMENT_DATE_FORMATS +} from '@alfresco/adf-core'; import { Component, Input, OnInit, OnDestroy } from '@angular/core'; import { DateAdapter, MAT_DATE_FORMATS } from '@angular/material/core'; import { MatDatepickerInputEvent } from '@angular/material/datepicker'; import moment, { Moment } from 'moment'; -import { DynamicTableColumn } from '../../dynamic-table-column.model'; -import { DynamicTableRow } from '../../dynamic-table-row.model'; -import { DynamicTableModel } from '../../dynamic-table.widget.model'; +import { DynamicTableColumn } from '../models/dynamic-table-column.model'; +import { DynamicTableRow } from '../models/dynamic-table-row.model'; +import { DynamicTableModel } from '../models/dynamic-table.widget.model'; import { Subject } from 'rxjs'; import { takeUntil } from 'rxjs/operators'; @@ -86,7 +88,7 @@ export class DateEditorComponent implements OnInit, OnDestroy { const momentDate = moment(newDateValue.value, this.DATE_FORMAT, true); if (!momentDate.isValid()) { - this.row.value[this.column.id] = newDateValue.value; + this.row.value[this.column.id] = newDateValue.value; } else { this.row.value[this.column.id] = `${momentDate.format('YYYY-MM-DD')}T00:00:00.000Z`; this.table.flushValue(); diff --git a/lib/core/src/lib/form/components/widgets/dynamic-table/editors/datetime/datetime.editor.html b/lib/process-services/src/lib/form/widgets/dynamic-table/editors/datetime/datetime.editor.html similarity index 100% rename from lib/core/src/lib/form/components/widgets/dynamic-table/editors/datetime/datetime.editor.html rename to lib/process-services/src/lib/form/widgets/dynamic-table/editors/datetime/datetime.editor.html diff --git a/lib/core/src/lib/form/components/widgets/dynamic-table/editors/datetime/datetime.editor.scss b/lib/process-services/src/lib/form/widgets/dynamic-table/editors/datetime/datetime.editor.scss similarity index 100% rename from lib/core/src/lib/form/components/widgets/dynamic-table/editors/datetime/datetime.editor.scss rename to lib/process-services/src/lib/form/widgets/dynamic-table/editors/datetime/datetime.editor.scss diff --git a/lib/core/src/lib/form/components/widgets/dynamic-table/editors/datetime/datetime.editor.spec.ts b/lib/process-services/src/lib/form/widgets/dynamic-table/editors/datetime/datetime.editor.spec.ts similarity index 80% rename from lib/core/src/lib/form/components/widgets/dynamic-table/editors/datetime/datetime.editor.spec.ts rename to lib/process-services/src/lib/form/widgets/dynamic-table/editors/datetime/datetime.editor.spec.ts index 763dfc4fa6..de6a973cf7 100644 --- a/lib/core/src/lib/form/components/widgets/dynamic-table/editors/datetime/datetime.editor.spec.ts +++ b/lib/process-services/src/lib/form/widgets/dynamic-table/editors/datetime/datetime.editor.spec.ts @@ -17,13 +17,11 @@ import { ComponentFixture, TestBed } from '@angular/core/testing'; import moment from 'moment'; -import { FormFieldModel, FormModel } from '../../../index'; -import { DynamicTableColumn } from '../../dynamic-table-column.model'; -import { DynamicTableRow } from '../../dynamic-table-row.model'; -import { DynamicTableModel } from '../../dynamic-table.widget.model'; +import { FormFieldModel, FormModel, setupTestBed, CoreTestingModule } from '@alfresco/adf-core'; +import { DynamicTableColumn } from '../models/dynamic-table-column.model'; +import { DynamicTableRow } from '../models/dynamic-table-row.model'; +import { DynamicTableModel } from '../models/dynamic-table.widget.model'; import { DateTimeEditorComponent } from './datetime.editor'; -import { setupTestBed } from '../../../../../../testing/setup-test-bed'; -import { CoreTestingModule } from '../../../../../../testing/core.testing.module'; import { TranslateModule } from '@ngx-translate/core'; describe('DateTimeEditorComponent', () => { @@ -44,8 +42,8 @@ describe('DateTimeEditorComponent', () => { fixture = TestBed.createComponent(DateTimeEditorComponent); component = fixture.componentInstance; - row = { value: { date: '1879-03-14T00:00:00.000Z' } } as DynamicTableRow; - column = { id: 'datetime', type: 'Datetime' } as DynamicTableColumn; + row = {value: {date: '1879-03-14T00:00:00.000Z'}} as DynamicTableRow; + column = {id: 'datetime', type: 'Datetime'} as DynamicTableColumn; const field = new FormFieldModel(new FormModel()); table = new DynamicTableModel(field, null); table.rows.push(row); diff --git a/lib/core/src/lib/form/components/widgets/dynamic-table/editors/datetime/datetime.editor.ts b/lib/process-services/src/lib/form/widgets/dynamic-table/editors/datetime/datetime.editor.ts similarity index 79% rename from lib/core/src/lib/form/components/widgets/dynamic-table/editors/datetime/datetime.editor.ts rename to lib/process-services/src/lib/form/widgets/dynamic-table/editors/datetime/datetime.editor.ts index f98b290a75..9cf19649dc 100644 --- a/lib/core/src/lib/form/components/widgets/dynamic-table/editors/datetime/datetime.editor.ts +++ b/lib/process-services/src/lib/form/widgets/dynamic-table/editors/datetime/datetime.editor.ts @@ -17,15 +17,18 @@ /* eslint-disable @angular-eslint/component-selector */ -import { UserPreferencesService, UserPreferenceValues } from '../../../../../../services/user-preferences.service'; -import { MomentDateAdapter } from '../../../../../../utils/moment-date-adapter'; -import { MOMENT_DATE_FORMATS } from '../../../../../../utils/moment-date-formats.model'; +import { + MOMENT_DATE_FORMATS, + MomentDateAdapter, + UserPreferencesService, + UserPreferenceValues +} from '@alfresco/adf-core'; import { Component, Input, OnInit, OnDestroy } from '@angular/core'; import { DateAdapter, MAT_DATE_FORMATS } from '@angular/material/core'; import moment, { Moment } from 'moment'; -import { DynamicTableColumn } from '../../dynamic-table-column.model'; -import { DynamicTableRow } from '../../dynamic-table-row.model'; -import { DynamicTableModel } from '../../dynamic-table.widget.model'; +import { DynamicTableColumn } from '../models/dynamic-table-column.model'; +import { DynamicTableRow } from '../models/dynamic-table-row.model'; +import { DynamicTableModel } from '../models/dynamic-table.widget.model'; import { DatetimeAdapter, MAT_DATETIME_FORMATS } from '@mat-datetimepicker/core'; import { MomentDatetimeAdapter, MAT_MOMENT_DATETIME_FORMATS } from '@mat-datetimepicker/moment'; import { Subject } from 'rxjs'; @@ -35,10 +38,10 @@ import { takeUntil } from 'rxjs/operators'; selector: 'adf-datetime-editor', templateUrl: './datetime.editor.html', providers: [ - { provide: DateAdapter, useClass: MomentDateAdapter }, - { provide: MAT_DATE_FORMATS, useValue: MOMENT_DATE_FORMATS }, - { provide: DatetimeAdapter, useClass: MomentDatetimeAdapter }, - { provide: MAT_DATETIME_FORMATS, useValue: MAT_MOMENT_DATETIME_FORMATS } + {provide: DateAdapter, useClass: MomentDateAdapter}, + {provide: MAT_DATE_FORMATS, useValue: MOMENT_DATE_FORMATS}, + {provide: DatetimeAdapter, useClass: MomentDatetimeAdapter}, + {provide: MAT_DATETIME_FORMATS, useValue: MAT_MOMENT_DATETIME_FORMATS} ], styleUrls: ['./datetime.editor.scss'] }) diff --git a/lib/core/src/lib/form/components/widgets/dynamic-table/editors/dropdown/dropdown.editor.html b/lib/process-services/src/lib/form/widgets/dynamic-table/editors/dropdown/dropdown.editor.html similarity index 100% rename from lib/core/src/lib/form/components/widgets/dynamic-table/editors/dropdown/dropdown.editor.html rename to lib/process-services/src/lib/form/widgets/dynamic-table/editors/dropdown/dropdown.editor.html diff --git a/lib/core/src/lib/form/components/widgets/dynamic-table/editors/dropdown/dropdown.editor.scss b/lib/process-services/src/lib/form/widgets/dynamic-table/editors/dropdown/dropdown.editor.scss similarity index 100% rename from lib/core/src/lib/form/components/widgets/dynamic-table/editors/dropdown/dropdown.editor.scss rename to lib/process-services/src/lib/form/widgets/dynamic-table/editors/dropdown/dropdown.editor.scss diff --git a/lib/core/src/lib/form/components/widgets/dynamic-table/editors/dropdown/dropdown.editor.spec.ts b/lib/process-services/src/lib/form/widgets/dynamic-table/editors/dropdown/dropdown.editor.spec.ts similarity index 83% rename from lib/core/src/lib/form/components/widgets/dynamic-table/editors/dropdown/dropdown.editor.spec.ts rename to lib/process-services/src/lib/form/widgets/dynamic-table/editors/dropdown/dropdown.editor.spec.ts index ce096a1324..c8a69f7643 100644 --- a/lib/core/src/lib/form/components/widgets/dynamic-table/editors/dropdown/dropdown.editor.spec.ts +++ b/lib/process-services/src/lib/form/widgets/dynamic-table/editors/dropdown/dropdown.editor.spec.ts @@ -17,28 +17,35 @@ import { ComponentFixture, TestBed } from '@angular/core/testing'; import { By } from '@angular/platform-browser'; -import { Observable, of, throwError } from 'rxjs'; -import { FormService } from '../../../../../services/form.service'; -import { FormFieldModel, FormModel } from '../../../core'; -import { DynamicTableColumnOption } from '../../dynamic-table-column-option.model'; -import { DynamicTableColumn } from '../../dynamic-table-column.model'; -import { DynamicTableRow } from '../../dynamic-table-row.model'; -import { DynamicTableModel } from '../../dynamic-table.widget.model'; +import { Observable, throwError } from 'rxjs'; +import { + AlfrescoApiService, + setupTestBed, + CoreTestingModule, + FormFieldModel, + FormModel, + FormService +} from '@alfresco/adf-core'; +import { DynamicTableColumnOption } from '../models/dynamic-table-column-option.model'; +import { DynamicTableColumn } from '../models/dynamic-table-column.model'; +import { DynamicTableRow } from '../models/dynamic-table-row.model'; +import { DynamicTableModel } from '../models/dynamic-table.widget.model'; import { DropdownEditorComponent } from './dropdown.editor'; -import { setupTestBed } from '../../../../../../testing/setup-test-bed'; -import { CoreTestingModule } from '../../../../../../testing/core.testing.module'; import { TranslateModule } from '@ngx-translate/core'; -import { AlfrescoApiService } from '../../../../../../services'; +import { TaskFormService } from '../../../../services/task-form.service'; +import { ProcessDefinitionService } from '../../../../services/process-definition.service'; describe('DropdownEditorComponent', () => { let component: DropdownEditorComponent; let formService: FormService; + let taskFormService: TaskFormService; + let processDefinitionService: ProcessDefinitionService; + let alfrescoApiService: AlfrescoApiService; let form: FormModel; let table: DynamicTableModel; let column: DynamicTableColumn; let row: DynamicTableRow; - let alfrescoApiService: AlfrescoApiService; setupTestBed({ imports: [ @@ -49,7 +56,10 @@ describe('DropdownEditorComponent', () => { beforeEach(() => { alfrescoApiService = TestBed.inject(AlfrescoApiService); - formService = new FormService(null, alfrescoApiService, null); + + formService = new FormService(); + taskFormService = new TaskFormService(alfrescoApiService, null); + processDefinitionService = new ProcessDefinitionService(alfrescoApiService, null); row = {value: {dropdown: 'one'}} as DynamicTableRow; column = { @@ -65,7 +75,7 @@ describe('DropdownEditorComponent', () => { table.rows.push(row); table.columns.push(column); - component = new DropdownEditorComponent(formService, null); + component = new DropdownEditorComponent(formService, taskFormService, processDefinitionService, null); component.table = table; component.row = row; component.column = column; @@ -100,7 +110,7 @@ describe('DropdownEditorComponent', () => { {id: '12', name: 'twelve'} ]; - spyOn(formService, 'getRestFieldValuesColumn').and.returnValue( + spyOn(taskFormService, 'getRestFieldValuesColumn').and.returnValue( new Observable((observer) => { observer.next(restResults); observer.complete(); @@ -109,7 +119,7 @@ describe('DropdownEditorComponent', () => { component.ngOnInit(); - expect(formService.getRestFieldValuesColumn).toHaveBeenCalledWith( + expect(taskFormService.getRestFieldValuesColumn).toHaveBeenCalledWith( form.taskId, table.field.id, column.id @@ -123,7 +133,7 @@ describe('DropdownEditorComponent', () => { it('should create empty options array on REST response', () => { column.optionType = 'rest'; - spyOn(formService, 'getRestFieldValuesColumn').and.returnValue( + spyOn(taskFormService, 'getRestFieldValuesColumn').and.returnValue( new Observable((observer) => { observer.next(null); observer.complete(); @@ -132,7 +142,7 @@ describe('DropdownEditorComponent', () => { component.ngOnInit(); - expect(formService.getRestFieldValuesColumn).toHaveBeenCalledWith( + expect(taskFormService.getRestFieldValuesColumn).toHaveBeenCalledWith( form.taskId, table.field.id, column.id @@ -147,7 +157,7 @@ describe('DropdownEditorComponent', () => { column.optionType = 'rest'; const error = 'error'; - spyOn(formService, 'getRestFieldValuesColumn').and.returnValue( + spyOn(taskFormService, 'getRestFieldValuesColumn').and.returnValue( throwError(error) ); spyOn(component, 'handleError').and.stub(); @@ -163,7 +173,7 @@ describe('DropdownEditorComponent', () => { component.table = procTable; const error = 'error'; - spyOn(formService, 'getRestFieldValuesColumnByProcessId').and.returnValue( + spyOn(processDefinitionService, 'getRestFieldValuesColumnByProcessId').and.returnValue( throwError(error) ); spyOn(component, 'handleError').and.stub(); @@ -182,14 +192,6 @@ describe('DropdownEditorComponent', () => { let dropDownEditorComponent: DropdownEditorComponent; let fixture: ComponentFixture; let element: HTMLElement; - let stubFormService; - const fakeOptionList: DynamicTableColumnOption[] = [{ - id: 'opt_1', - name: 'option_1' - }, { - id: 'opt_2', - name: 'option_2' - }, {id: 'opt_3', name: 'option_3'}]; let dynamicTable: DynamicTableModel; const openSelect = () => { @@ -211,8 +213,6 @@ describe('DropdownEditorComponent', () => { describe('and dropdown is populated via taskId', () => { beforeEach(() => { - stubFormService = fixture.debugElement.injector.get(FormService); - spyOn(stubFormService, 'getRestFieldValuesColumn').and.returnValue(of(fakeOptionList)); row = {value: {dropdown: 'one'}} as DynamicTableRow; column = { id: 'column-id', @@ -259,8 +259,6 @@ describe('DropdownEditorComponent', () => { describe('and dropdown is populated via processDefinitionId', () => { beforeEach(() => { - stubFormService = fixture.debugElement.injector.get(FormService); - spyOn(stubFormService, 'getRestFieldValuesColumnByProcessId').and.returnValue(of(fakeOptionList)); row = {value: {dropdown: 'one'}} as DynamicTableRow; column = { id: 'column-id', @@ -303,5 +301,5 @@ describe('DropdownEditorComponent', () => { expect(optThree).not.toBeNull(); }); }); - }); + }); }); diff --git a/lib/core/src/lib/form/components/widgets/dynamic-table/editors/dropdown/dropdown.editor.ts b/lib/process-services/src/lib/form/widgets/dynamic-table/editors/dropdown/dropdown.editor.ts similarity index 80% rename from lib/core/src/lib/form/components/widgets/dynamic-table/editors/dropdown/dropdown.editor.ts rename to lib/process-services/src/lib/form/widgets/dynamic-table/editors/dropdown/dropdown.editor.ts index 54114e7df5..8e81b88903 100644 --- a/lib/core/src/lib/form/components/widgets/dynamic-table/editors/dropdown/dropdown.editor.ts +++ b/lib/process-services/src/lib/form/widgets/dynamic-table/editors/dropdown/dropdown.editor.ts @@ -15,15 +15,16 @@ * limitations under the License. */ - /* eslint-disable @angular-eslint/component-selector */ +/* eslint-disable @angular-eslint/component-selector */ -import { LogService } from '../../../../../../services/log.service'; +import { LogService, FormService } from '@alfresco/adf-core'; import { Component, Input, OnInit } from '@angular/core'; -import { FormService } from '../../../../../services/form.service'; -import { DynamicTableColumnOption } from '../../dynamic-table-column-option.model'; -import { DynamicTableColumn } from '../../dynamic-table-column.model'; -import { DynamicTableRow } from '../../dynamic-table-row.model'; -import { DynamicTableModel } from '../../dynamic-table.widget.model'; +import { DynamicTableColumnOption } from '../models/dynamic-table-column-option.model'; +import { DynamicTableColumn } from '../models/dynamic-table-column.model'; +import { DynamicTableRow } from '../models/dynamic-table-row.model'; +import { DynamicTableModel } from '../models/dynamic-table.widget.model'; +import { ProcessDefinitionService } from '../../../../services/process-definition.service'; +import { TaskFormService } from '../../../../services/task-form.service'; @Component({ selector: 'adf-dropdown-editor', @@ -45,6 +46,8 @@ export class DropdownEditorComponent implements OnInit { column: DynamicTableColumn; constructor(public formService: FormService, + private taskFormService: TaskFormService, + private processDefinitionService: ProcessDefinitionService, private logService: LogService) { } @@ -65,7 +68,7 @@ export class DropdownEditorComponent implements OnInit { } getValuesByTaskId(field) { - this.formService + this.taskFormService .getRestFieldValuesColumn( field.form.taskId, field.id, @@ -82,7 +85,7 @@ export class DropdownEditorComponent implements OnInit { } getValuesByProcessDefinitionId(field) { - this.formService + this.processDefinitionService .getRestFieldValuesColumnByProcessId( field.form.processDefinitionId, field.id, diff --git a/lib/core/src/lib/form/components/widgets/dynamic-table/cell-validator.model.ts b/lib/process-services/src/lib/form/widgets/dynamic-table/editors/models/cell-validator.model.ts similarity index 100% rename from lib/core/src/lib/form/components/widgets/dynamic-table/cell-validator.model.ts rename to lib/process-services/src/lib/form/widgets/dynamic-table/editors/models/cell-validator.model.ts diff --git a/lib/core/src/lib/form/components/widgets/dynamic-table/date-cell-validator-model.ts b/lib/process-services/src/lib/form/widgets/dynamic-table/editors/models/date-cell-validator-model.ts similarity index 100% rename from lib/core/src/lib/form/components/widgets/dynamic-table/date-cell-validator-model.ts rename to lib/process-services/src/lib/form/widgets/dynamic-table/editors/models/date-cell-validator-model.ts diff --git a/lib/core/src/lib/form/components/widgets/dynamic-table/dynamic-row-validation-summary.model.ts b/lib/process-services/src/lib/form/widgets/dynamic-table/editors/models/dynamic-row-validation-summary.model.ts similarity index 93% rename from lib/core/src/lib/form/components/widgets/dynamic-table/dynamic-row-validation-summary.model.ts rename to lib/process-services/src/lib/form/widgets/dynamic-table/editors/models/dynamic-row-validation-summary.model.ts index c88d5679ae..2dfd8265b3 100644 --- a/lib/core/src/lib/form/components/widgets/dynamic-table/dynamic-row-validation-summary.model.ts +++ b/lib/process-services/src/lib/form/widgets/dynamic-table/editors/models/dynamic-row-validation-summary.model.ts @@ -15,7 +15,7 @@ * limitations under the License. */ -import { ErrorMessageModel } from '../core/error-message.model'; +import { ErrorMessageModel } from '@alfresco/adf-core'; /* eslint-disable @angular-eslint/component-selector */ diff --git a/lib/core/src/lib/form/components/widgets/dynamic-table/dynamic-table-column-option.model.ts b/lib/process-services/src/lib/form/widgets/dynamic-table/editors/models/dynamic-table-column-option.model.ts similarity index 100% rename from lib/core/src/lib/form/components/widgets/dynamic-table/dynamic-table-column-option.model.ts rename to lib/process-services/src/lib/form/widgets/dynamic-table/editors/models/dynamic-table-column-option.model.ts diff --git a/lib/core/src/lib/form/components/widgets/dynamic-table/dynamic-table-column.model.ts b/lib/process-services/src/lib/form/widgets/dynamic-table/editors/models/dynamic-table-column.model.ts similarity index 100% rename from lib/core/src/lib/form/components/widgets/dynamic-table/dynamic-table-column.model.ts rename to lib/process-services/src/lib/form/widgets/dynamic-table/editors/models/dynamic-table-column.model.ts diff --git a/lib/core/src/lib/form/components/widgets/dynamic-table/dynamic-table-row.model.ts b/lib/process-services/src/lib/form/widgets/dynamic-table/editors/models/dynamic-table-row.model.ts similarity index 100% rename from lib/core/src/lib/form/components/widgets/dynamic-table/dynamic-table-row.model.ts rename to lib/process-services/src/lib/form/widgets/dynamic-table/editors/models/dynamic-table-row.model.ts diff --git a/lib/core/src/lib/form/components/widgets/dynamic-table/dynamic-table.widget.model.ts b/lib/process-services/src/lib/form/widgets/dynamic-table/editors/models/dynamic-table.widget.model.ts similarity index 91% rename from lib/core/src/lib/form/components/widgets/dynamic-table/dynamic-table.widget.model.ts rename to lib/process-services/src/lib/form/widgets/dynamic-table/editors/models/dynamic-table.widget.model.ts index 9e632a0eae..82e701f2ac 100644 --- a/lib/core/src/lib/form/components/widgets/dynamic-table/dynamic-table.widget.model.ts +++ b/lib/process-services/src/lib/form/widgets/dynamic-table/editors/models/dynamic-table.widget.model.ts @@ -15,13 +15,11 @@ * limitations under the License. */ - /* eslint-disable @angular-eslint/component-selector */ +/* eslint-disable @angular-eslint/component-selector */ import moment from 'moment'; -import { ValidateDynamicTableRowEvent } from '../../../events/validate-dynamic-table-row.event'; -import { FormService } from '../../../services/form.service'; -import { FormFieldModel } from '../core/form-field.model'; -import { FormWidgetModel } from '../core/form-widget.model'; +import { ValidateDynamicTableRowEvent } from '../../../../events/validate-dynamic-table-row.event'; +import { FormService, FormFieldModel, FormWidgetModel } from '@alfresco/adf-core'; import { CellValidator } from './cell-validator.model'; import { DateCellValidator } from './date-cell-validator-model'; import { DynamicRowValidationSummary } from './dynamic-row-validation-summary.model'; @@ -72,7 +70,7 @@ export class DynamicTableModel extends FormWidgetModel { } if (field.json.value) { - this.rows = field.json.value.map((obj) => ({ selected: false, value: obj } as DynamicTableRow)); + this.rows = field.json.value.map((obj) => ({selected: false, value: obj} as DynamicTableRow)); } } @@ -145,7 +143,7 @@ export class DynamicTableModel extends FormWidgetModel { } validateRow(row: DynamicTableRow): DynamicRowValidationSummary { - const summary = new DynamicRowValidationSummary( { + const summary = new DynamicRowValidationSummary({ isValid: true, message: null }); diff --git a/lib/core/src/lib/form/components/widgets/dynamic-table/number-cell-validator.model.ts b/lib/process-services/src/lib/form/widgets/dynamic-table/editors/models/number-cell-validator.model.ts similarity index 100% rename from lib/core/src/lib/form/components/widgets/dynamic-table/number-cell-validator.model.ts rename to lib/process-services/src/lib/form/widgets/dynamic-table/editors/models/number-cell-validator.model.ts diff --git a/lib/core/src/lib/form/components/widgets/dynamic-table/required-cell-validator.model.ts b/lib/process-services/src/lib/form/widgets/dynamic-table/editors/models/required-cell-validator.model.ts similarity index 100% rename from lib/core/src/lib/form/components/widgets/dynamic-table/required-cell-validator.model.ts rename to lib/process-services/src/lib/form/widgets/dynamic-table/editors/models/required-cell-validator.model.ts diff --git a/lib/core/src/lib/form/components/widgets/dynamic-table/editors/row.editor.css b/lib/process-services/src/lib/form/widgets/dynamic-table/editors/row-editor/row.editor.css similarity index 100% rename from lib/core/src/lib/form/components/widgets/dynamic-table/editors/row.editor.css rename to lib/process-services/src/lib/form/widgets/dynamic-table/editors/row-editor/row.editor.css diff --git a/lib/core/src/lib/form/components/widgets/dynamic-table/editors/row.editor.html b/lib/process-services/src/lib/form/widgets/dynamic-table/editors/row-editor/row.editor.html similarity index 100% rename from lib/core/src/lib/form/components/widgets/dynamic-table/editors/row.editor.html rename to lib/process-services/src/lib/form/widgets/dynamic-table/editors/row-editor/row.editor.html diff --git a/lib/core/src/lib/form/components/widgets/dynamic-table/editors/row.editor.spec.ts b/lib/process-services/src/lib/form/widgets/dynamic-table/editors/row-editor/row.editor.spec.ts similarity index 74% rename from lib/core/src/lib/form/components/widgets/dynamic-table/editors/row.editor.spec.ts rename to lib/process-services/src/lib/form/widgets/dynamic-table/editors/row-editor/row.editor.spec.ts index 86cf382e68..5fa1162208 100644 --- a/lib/core/src/lib/form/components/widgets/dynamic-table/editors/row.editor.spec.ts +++ b/lib/process-services/src/lib/form/widgets/dynamic-table/editors/row-editor/row.editor.spec.ts @@ -15,22 +15,23 @@ * limitations under the License. */ -import { FormFieldModel, FormModel } from '../../core'; -import { FormService } from '../../../../services/form.service'; -import { DynamicTableColumn } from '../dynamic-table-column.model'; -import { DynamicTableRow } from '../dynamic-table-row.model'; -import { DynamicTableModel } from '../dynamic-table.widget.model'; +import { + FormFieldModel, + FormModel, + FormService, + CoreTestingModule, + setupTestBed +} from '@alfresco/adf-core'; +import { DynamicTableColumn } from '../models/dynamic-table-column.model'; +import { DynamicTableRow } from '../models/dynamic-table-row.model'; +import { DynamicTableModel } from '../models/dynamic-table.widget.model'; import { RowEditorComponent } from './row.editor'; -import { AlfrescoApiService } from '../../../../../services'; -import { TestBed } from '@angular/core/testing'; -import { CoreTestingModule, setupTestBed } from '../../../../../testing'; import { TranslateModule } from '@ngx-translate/core'; -import { DynamicRowValidationSummary } from '../dynamic-row-validation-summary.model'; +import { DynamicRowValidationSummary } from '../models/dynamic-row-validation-summary.model'; describe('RowEditorComponent', () => { let component: RowEditorComponent; - let alfrescoApiService: AlfrescoApiService; setupTestBed({ imports: [ @@ -40,11 +41,9 @@ describe('RowEditorComponent', () => { }); beforeEach(() => { - alfrescoApiService = TestBed.inject(AlfrescoApiService); - component = new RowEditorComponent(); const field = new FormFieldModel(new FormModel()); - component.table = new DynamicTableModel(field, new FormService(null, alfrescoApiService, null)); + component.table = new DynamicTableModel(field, new FormService()); component.row = {} as DynamicTableRow; component.column = {} as DynamicTableColumn; }); @@ -72,7 +71,7 @@ describe('RowEditorComponent', () => { it('should emit [save] event', (done) => { spyOn(component.table, 'validateRow').and.returnValue( - new DynamicRowValidationSummary({ isValid: true, message: null }) + new DynamicRowValidationSummary({isValid: true, message: null}) ); component.save.subscribe((event) => { expect(event.table).toBe(component.table); @@ -85,7 +84,7 @@ describe('RowEditorComponent', () => { it('should not emit [save] event for invalid row', () => { spyOn(component.table, 'validateRow').and.returnValue( - new DynamicRowValidationSummary({ isValid: false, message: 'error' }) + new DynamicRowValidationSummary({isValid: false, message: 'error'}) ); let raised = false; component.save.subscribe(() => raised = true); diff --git a/lib/core/src/lib/form/components/widgets/dynamic-table/editors/row.editor.ts b/lib/process-services/src/lib/form/widgets/dynamic-table/editors/row-editor/row.editor.ts similarity index 86% rename from lib/core/src/lib/form/components/widgets/dynamic-table/editors/row.editor.ts rename to lib/process-services/src/lib/form/widgets/dynamic-table/editors/row-editor/row.editor.ts index 426006b28d..ae79b7bcbd 100644 --- a/lib/core/src/lib/form/components/widgets/dynamic-table/editors/row.editor.ts +++ b/lib/process-services/src/lib/form/widgets/dynamic-table/editors/row-editor/row.editor.ts @@ -18,10 +18,10 @@ /* eslint-disable @angular-eslint/component-selector */ import { Component, EventEmitter, Input, Output } from '@angular/core'; -import { DynamicRowValidationSummary } from '../dynamic-row-validation-summary.model'; -import { DynamicTableColumn } from '../dynamic-table-column.model'; -import { DynamicTableRow } from '../dynamic-table-row.model'; -import { DynamicTableModel } from '../dynamic-table.widget.model'; +import { DynamicRowValidationSummary } from '../models/dynamic-row-validation-summary.model'; +import { DynamicTableColumn } from '../models/dynamic-table-column.model'; +import { DynamicTableRow } from '../models/dynamic-table-row.model'; +import { DynamicTableModel } from '../models/dynamic-table.widget.model'; @Component({ selector: 'row-editor', diff --git a/lib/core/src/lib/form/components/widgets/dynamic-table/editors/text/text.editor.html b/lib/process-services/src/lib/form/widgets/dynamic-table/editors/text/text.editor.html similarity index 100% rename from lib/core/src/lib/form/components/widgets/dynamic-table/editors/text/text.editor.html rename to lib/process-services/src/lib/form/widgets/dynamic-table/editors/text/text.editor.html diff --git a/lib/core/src/lib/form/components/widgets/dynamic-table/editors/text/text.editor.scss b/lib/process-services/src/lib/form/widgets/dynamic-table/editors/text/text.editor.scss similarity index 100% rename from lib/core/src/lib/form/components/widgets/dynamic-table/editors/text/text.editor.scss rename to lib/process-services/src/lib/form/widgets/dynamic-table/editors/text/text.editor.scss diff --git a/lib/core/src/lib/form/components/widgets/dynamic-table/editors/text/text.editor.spec.ts b/lib/process-services/src/lib/form/widgets/dynamic-table/editors/text/text.editor.spec.ts similarity index 89% rename from lib/core/src/lib/form/components/widgets/dynamic-table/editors/text/text.editor.spec.ts rename to lib/process-services/src/lib/form/widgets/dynamic-table/editors/text/text.editor.spec.ts index 0e9a14415e..bf61871c5a 100644 --- a/lib/core/src/lib/form/components/widgets/dynamic-table/editors/text/text.editor.spec.ts +++ b/lib/process-services/src/lib/form/widgets/dynamic-table/editors/text/text.editor.spec.ts @@ -15,8 +15,8 @@ * limitations under the License. */ -import { DynamicTableColumn } from '../../dynamic-table-column.model'; -import { DynamicTableRow } from '../../dynamic-table-row.model'; +import { DynamicTableColumn } from '../models/dynamic-table-column.model'; +import { DynamicTableRow } from '../models/dynamic-table-row.model'; import { TextEditorComponent } from './text.editor'; describe('TextEditorComponent', () => { diff --git a/lib/core/src/lib/form/components/widgets/dynamic-table/editors/text/text.editor.ts b/lib/process-services/src/lib/form/widgets/dynamic-table/editors/text/text.editor.ts similarity index 86% rename from lib/core/src/lib/form/components/widgets/dynamic-table/editors/text/text.editor.ts rename to lib/process-services/src/lib/form/widgets/dynamic-table/editors/text/text.editor.ts index 8cbafc5af6..a31ae69c71 100644 --- a/lib/core/src/lib/form/components/widgets/dynamic-table/editors/text/text.editor.ts +++ b/lib/process-services/src/lib/form/widgets/dynamic-table/editors/text/text.editor.ts @@ -18,9 +18,9 @@ /* eslint-disable @angular-eslint/component-selector */ import { Component, Input, OnInit } from '@angular/core'; -import { DynamicTableColumn } from '../../dynamic-table-column.model'; -import { DynamicTableRow } from '../../dynamic-table-row.model'; -import { DynamicTableModel } from '../../dynamic-table.widget.model'; +import { DynamicTableColumn } from '../models/dynamic-table-column.model'; +import { DynamicTableRow } from '../models/dynamic-table-row.model'; +import { DynamicTableModel } from '../models/dynamic-table.widget.model'; @Component({ selector: 'adf-text-editor', diff --git a/lib/process-services/src/lib/form/widgets/dynamic-table/index.ts b/lib/process-services/src/lib/form/widgets/dynamic-table/index.ts new file mode 100644 index 0000000000..a7e30cc675 --- /dev/null +++ b/lib/process-services/src/lib/form/widgets/dynamic-table/index.ts @@ -0,0 +1,18 @@ +/*! + * @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. + */ + +export * from './public-api'; diff --git a/lib/process-services/src/lib/form/widgets/dynamic-table/public-api.ts b/lib/process-services/src/lib/form/widgets/dynamic-table/public-api.ts new file mode 100644 index 0000000000..6f38864d71 --- /dev/null +++ b/lib/process-services/src/lib/form/widgets/dynamic-table/public-api.ts @@ -0,0 +1,31 @@ +/*! + * @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. + */ + +export * from './editors/dropdown/dropdown.editor'; +export * from './editors/amount/amount.editor'; +export * from './editors/boolean/boolean.editor'; +export * from './editors/date/date.editor'; +export * from './editors/datetime/datetime.editor'; +export * from './editors/row-editor/row.editor'; +export * from './editors/text/text.editor'; + +export * from './editors/models/dynamic-table-row.model'; + +export * from './dynamic-table.widget'; + + +export * from './dynamic-table.module'; diff --git a/lib/core/src/lib/form/components/widgets/functional-group/functional-group.widget.html b/lib/process-services/src/lib/form/widgets/functional-group/functional-group.widget.html similarity index 100% rename from lib/core/src/lib/form/components/widgets/functional-group/functional-group.widget.html rename to lib/process-services/src/lib/form/widgets/functional-group/functional-group.widget.html diff --git a/lib/core/src/lib/form/components/widgets/functional-group/functional-group.widget.scss b/lib/process-services/src/lib/form/widgets/functional-group/functional-group.widget.scss similarity index 100% rename from lib/core/src/lib/form/components/widgets/functional-group/functional-group.widget.scss rename to lib/process-services/src/lib/form/widgets/functional-group/functional-group.widget.scss diff --git a/lib/core/src/lib/form/components/widgets/functional-group/functional-group.widget.spec.ts b/lib/process-services/src/lib/form/widgets/functional-group/functional-group.widget.spec.ts similarity index 85% rename from lib/core/src/lib/form/components/widgets/functional-group/functional-group.widget.spec.ts rename to lib/process-services/src/lib/form/widgets/functional-group/functional-group.widget.spec.ts index 881c443e43..c7ff88fe96 100644 --- a/lib/core/src/lib/form/components/widgets/functional-group/functional-group.widget.spec.ts +++ b/lib/process-services/src/lib/form/widgets/functional-group/functional-group.widget.spec.ts @@ -16,25 +16,28 @@ */ import { of, timer } from 'rxjs'; -import { FormService } from '../../../services/form.service'; -import { FormFieldModel } from '../core/form-field.model'; -import { FormModel } from '../core/form.model'; -import { GroupModel } from '../core/group.model'; +import { + FormFieldModel, + FormModel, + GroupModel, + CoreTestingModule, + setupTestBed, + FormFieldTypes, + PeopleProcessService +} from '@alfresco/adf-core'; import { FunctionalGroupWidgetComponent } from './functional-group.widget'; import { ComponentFixture, TestBed } from '@angular/core/testing'; -import { CoreTestingModule, setupTestBed } from '../../../../testing'; import { TranslateModule } from '@ngx-translate/core'; -import { FormFieldTypes } from '../core/form-field-types'; describe('FunctionalGroupWidgetComponent', () => { let fixture: ComponentFixture; let component: FunctionalGroupWidgetComponent; - let formService: FormService; + let peopleProcessService: PeopleProcessService; let getWorkflowGroupsSpy: jasmine.Spy; let element: HTMLElement; const groups: GroupModel[] = [ - { id: '1', name: 'group 1' }, - { id: '2', name: 'group 2' } + {id: '1', name: 'group 1'}, + {id: '2', name: 'group 2'} ]; setupTestBed({ @@ -45,8 +48,8 @@ describe('FunctionalGroupWidgetComponent', () => { }); beforeEach(() => { - formService = TestBed.inject(FormService); - getWorkflowGroupsSpy = spyOn(formService, 'getWorkflowGroups').and.returnValue(of([])); + peopleProcessService = TestBed.inject(PeopleProcessService); + getWorkflowGroupsSpy = spyOn(peopleProcessService, 'getWorkflowGroups').and.returnValue(of([])); fixture = TestBed.createComponent(FunctionalGroupWidgetComponent); component = fixture.componentInstance; @@ -78,7 +81,7 @@ describe('FunctionalGroupWidgetComponent', () => { }; it('should setup text from underlying field on init', async () => { - const group: GroupModel = { name: 'group-1'}; + const group: GroupModel = {name: 'group-1'}; component.field.value = group; component.ngOnInit(); @@ -95,7 +98,7 @@ describe('FunctionalGroupWidgetComponent', () => { component.ngOnInit(); expect(component.groupId).toBeUndefined(); - component.field.params = { restrictWithGroup: { id: '' } }; + component.field.params = {restrictWithGroup: {id: ''}}; component.ngOnInit(); expect(component.groupId).toBe(''); }); @@ -114,7 +117,7 @@ describe('FunctionalGroupWidgetComponent', () => { expect(component.field.value).toBe(groups[1]); }); - it('should fetch groups and show popup on key up', async () => { + it('should fetch groups and show popup on key up', async () => { component.groupId = 'parentGroup'; getWorkflowGroupsSpy.and.returnValue(of(groups)); @@ -141,7 +144,7 @@ describe('FunctionalGroupWidgetComponent', () => { expect(getWorkflowGroupsSpy).toHaveBeenCalledTimes(2); }); - it('should not fetch groups when value is missing', async () => { + it('should not fetch groups when value is missing', async () => { await typeIntoInput(''); expect(getWorkflowGroupsSpy).not.toHaveBeenCalled(); }); @@ -155,7 +158,7 @@ describe('FunctionalGroupWidgetComponent', () => { describe('when is required', () => { beforeEach(() => { - component.field = new FormFieldModel( new FormModel({ taskId: '' }), { + component.field = new FormFieldModel(new FormModel({taskId: ''}), { type: FormFieldTypes.FUNCTIONAL_GROUP, required: true }); diff --git a/lib/core/src/lib/form/components/widgets/functional-group/functional-group.widget.ts b/lib/process-services/src/lib/form/widgets/functional-group/functional-group.widget.ts similarity index 87% rename from lib/core/src/lib/form/components/widgets/functional-group/functional-group.widget.ts rename to lib/process-services/src/lib/form/widgets/functional-group/functional-group.widget.ts index 834744eb0d..79a53fbb55 100644 --- a/lib/core/src/lib/form/components/widgets/functional-group/functional-group.widget.ts +++ b/lib/process-services/src/lib/form/widgets/functional-group/functional-group.widget.ts @@ -15,12 +15,10 @@ * limitations under the License. */ - /* eslint-disable @angular-eslint/component-selector */ +/* eslint-disable @angular-eslint/component-selector */ import { Component, ElementRef, OnInit, ViewEncapsulation } from '@angular/core'; -import { FormService } from '../../../services/form.service'; -import { GroupModel } from '../core/group.model'; -import { WidgetComponent } from '../widget.component'; +import { FormService, GroupModel, PeopleProcessService, WidgetComponent } from '@alfresco/adf-core'; import { catchError, debounceTime, filter, switchMap, tap } from 'rxjs/operators'; import { merge, of } from 'rxjs'; import { UntypedFormControl } from '@angular/forms'; @@ -51,18 +49,19 @@ export class FunctionalGroupWidgetComponent extends WidgetComponent implements O tap((search: GroupModel | string) => { const isValid = typeof search !== 'string'; const empty = search === ''; - this.updateOption( isValid ? search as GroupModel : null ); + this.updateOption(isValid ? search as GroupModel : null); this.validateGroup(isValid, empty); }), filter((group: string | GroupModel) => typeof group === 'string' && group.length >= this.minTermLength), debounceTime(300), - switchMap((searchTerm: string) => this.formService.getWorkflowGroups(searchTerm, this.groupId) + switchMap((searchTerm: string) => this.peopleProcessService.getWorkflowGroups(searchTerm, this.groupId) .pipe(catchError(() => of([])))) ); - constructor(public formService: FormService, + constructor(public peopleProcessService: PeopleProcessService, + public formService: FormService, public elementRef: ElementRef) { - super(formService); + super(formService); } ngOnInit() { @@ -84,7 +83,7 @@ export class FunctionalGroupWidgetComponent extends WidgetComponent implements O } } - updateOption(option?: GroupModel) { + updateOption(option?: GroupModel) { if (option) { this.field.value = option; } else { diff --git a/lib/process-services/src/lib/form/widgets/index.ts b/lib/process-services/src/lib/form/widgets/index.ts new file mode 100644 index 0000000000..a7e30cc675 --- /dev/null +++ b/lib/process-services/src/lib/form/widgets/index.ts @@ -0,0 +1,18 @@ +/*! + * @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. + */ + +export * from './public-api'; diff --git a/lib/core/src/lib/form/components/widgets/people/people.widget.html b/lib/process-services/src/lib/form/widgets/people/people.widget.html similarity index 100% rename from lib/core/src/lib/form/components/widgets/people/people.widget.html rename to lib/process-services/src/lib/form/widgets/people/people.widget.html diff --git a/lib/core/src/lib/form/components/widgets/people/people.widget.scss b/lib/process-services/src/lib/form/widgets/people/people.widget.scss similarity index 100% rename from lib/core/src/lib/form/components/widgets/people/people.widget.scss rename to lib/process-services/src/lib/form/widgets/people/people.widget.scss diff --git a/lib/core/src/lib/form/components/widgets/people/people.widget.spec.ts b/lib/process-services/src/lib/form/widgets/people/people.widget.spec.ts similarity index 87% rename from lib/core/src/lib/form/components/widgets/people/people.widget.spec.ts rename to lib/process-services/src/lib/form/widgets/people/people.widget.spec.ts index 5b4be3d4fa..d006d0f8ed 100644 --- a/lib/core/src/lib/form/components/widgets/people/people.widget.spec.ts +++ b/lib/process-services/src/lib/form/widgets/people/people.widget.spec.ts @@ -17,24 +17,25 @@ import { ComponentFixture, TestBed } from '@angular/core/testing'; import { By } from '@angular/platform-browser'; -import { UserProcessModel } from '../../../../models'; +import { + UserProcessModel, + FormFieldTypes, + FormFieldModel, + FormModel, + setupTestBed, + CoreTestingModule, PeopleProcessService +} from '@alfresco/adf-core'; import { Observable, of } from 'rxjs'; -import { FormService } from '../../../services/form.service'; -import { FormFieldTypes } from '../core/form-field-types'; -import { FormFieldModel } from '../core/form-field.model'; -import { FormModel } from '../core/form.model'; import { PeopleWidgetComponent } from './people.widget'; -import { setupTestBed } from '../../../../testing/setup-test-bed'; import { TranslateService, TranslateModule } from '@ngx-translate/core'; -import { CoreTestingModule } from '../../../../testing/core.testing.module'; describe('PeopleWidgetComponent', () => { let widget: PeopleWidgetComponent; let fixture: ComponentFixture; let element: HTMLElement; - let formService: FormService; let translationService: TranslateService; + let peopleProcessService: PeopleProcessService; setupTestBed({ imports: [ @@ -45,7 +46,7 @@ describe('PeopleWidgetComponent', () => { beforeEach(() => { fixture = TestBed.createComponent(PeopleWidgetComponent); - formService = TestBed.inject(FormService); + peopleProcessService = TestBed.inject(PeopleProcessService); translationService = TestBed.inject(TranslateService); spyOn(translationService, 'instant').and.callFake((key) => key); @@ -70,12 +71,12 @@ describe('PeopleWidgetComponent', () => { }); it('should skip first name for display name', () => { - const model = new UserProcessModel({ firstName: null, lastName: 'Doe' }); + const model = new UserProcessModel({firstName: null, lastName: 'Doe'}); expect(widget.getDisplayName(model)).toBe('Doe'); }); it('should skip last name for display name', () => { - const model = new UserProcessModel({ firstName: 'John', lastName: null }); + const model = new UserProcessModel({firstName: 'John', lastName: null}); expect(widget.getDisplayName(model)).toBe('John'); }); @@ -86,7 +87,7 @@ describe('PeopleWidgetComponent', () => { lastName: 'Doe' }); - spyOn(formService, 'getWorkflowUsers').and.returnValue(of(null)); + spyOn(peopleProcessService, 'getWorkflowUsers').and.returnValue(of(null)); widget.ngOnInit(); fixture.detectChanges(); @@ -104,7 +105,7 @@ describe('PeopleWidgetComponent', () => { widget.field.readOnly = true; widget.field.form.readOnly = true; - spyOn(formService, 'getWorkflowUsers').and.returnValue(of(null)); + spyOn(peopleProcessService, 'getWorkflowUsers').and.returnValue(of(null)); widget.ngOnInit(); fixture.detectChanges(); @@ -127,13 +128,13 @@ describe('PeopleWidgetComponent', () => { widget.ngOnInit(); expect(widget.groupId).toBeUndefined(); - widget.field.params = { restrictWithGroup: { id: '' } }; + widget.field.params = {restrictWithGroup: {id: ''}}; widget.ngOnInit(); expect(widget.groupId).toBe(''); }); it('should display involved user in task form', async () => { - spyOn(formService, 'getWorkflowUsers').and.returnValue( + spyOn(peopleProcessService, 'getWorkflowUsers').and.returnValue( new Observable((observer) => { observer.next(null); observer.complete(); @@ -159,7 +160,7 @@ describe('PeopleWidgetComponent', () => { describe('when is required', () => { beforeEach(() => { - widget.field = new FormFieldModel( new FormModel({ taskId: '' }), { + widget.field = new FormFieldModel(new FormModel({taskId: ''}), { type: FormFieldTypes.PEOPLE, required: true }); @@ -191,15 +192,15 @@ describe('PeopleWidgetComponent', () => { describe('when template is ready', () => { const fakeUserResult = [ - { id: 1001, firstName: 'Test01', lastName: 'Test01', email: 'test' }, - { id: 1002, firstName: 'Test02', lastName: 'Test02', email: 'test2' }]; + {id: 1001, firstName: 'Test01', lastName: 'Test01', email: 'test'}, + {id: 1002, firstName: 'Test02', lastName: 'Test02', email: 'test2'}]; beforeEach(() => { - spyOn(formService, 'getWorkflowUsers').and.returnValue(new Observable((observer) => { + spyOn(peopleProcessService, 'getWorkflowUsers').and.returnValue(new Observable((observer) => { observer.next(fakeUserResult); observer.complete(); })); - widget.field = new FormFieldModel(new FormModel({ taskId: 'fake-task-id' }), { + widget.field = new FormFieldModel(new FormModel({taskId: 'fake-task-id'}), { id: 'people-id', name: 'people-name', type: FormFieldTypes.PEOPLE, @@ -249,7 +250,7 @@ describe('PeopleWidgetComponent', () => { expect(fixture.debugElement.query(By.css('#adf-people-widget-user-1'))).not.toBeNull(); }); - it('should hide result list if input is empty', async () => { + it('should hide result list if input is empty', async () => { const peopleHTMLElement = element.querySelector('input'); peopleHTMLElement.focus(); peopleHTMLElement.value = ''; diff --git a/lib/core/src/lib/form/components/widgets/people/people.widget.ts b/lib/process-services/src/lib/form/widgets/people/people.widget.ts similarity index 93% rename from lib/core/src/lib/form/components/widgets/people/people.widget.ts rename to lib/process-services/src/lib/form/widgets/people/people.widget.ts index 94eac8fa60..6e5d3f61dc 100644 --- a/lib/core/src/lib/form/components/widgets/people/people.widget.ts +++ b/lib/process-services/src/lib/form/widgets/people/people.widget.ts @@ -17,11 +17,8 @@ /* eslint-disable @angular-eslint/component-selector */ -import { PeopleProcessService } from '../../../../services/people-process.service'; -import { UserProcessModel } from '../../../../models'; +import { UserProcessModel, PeopleProcessService, FormService, WidgetComponent } from '@alfresco/adf-core'; import { Component, ElementRef, EventEmitter, OnInit, Output, ViewChild, ViewEncapsulation } from '@angular/core'; -import { FormService } from '../../../services/form.service'; -import { WidgetComponent } from '../widget.component'; import { UntypedFormControl } from '@angular/forms'; import { Observable, of } from 'rxjs'; import { @@ -72,7 +69,7 @@ export class PeopleWidgetComponent extends WidgetComponent implements OnInit { distinctUntilChanged(), switchMap((searchTerm) => { const value = searchTerm.email ? this.getDisplayName(searchTerm) : searchTerm; - return this.formService.getWorkflowUsers(value, this.groupId) + return this.peopleProcessService.getWorkflowUsers(undefined, value, this.groupId) .pipe(catchError(() => of([]))); }), map((list: UserProcessModel[]) => { diff --git a/lib/process-services/src/lib/form/widgets/public-api.ts b/lib/process-services/src/lib/form/widgets/public-api.ts new file mode 100644 index 0000000000..ae819f1a57 --- /dev/null +++ b/lib/process-services/src/lib/form/widgets/public-api.ts @@ -0,0 +1,28 @@ +/*! + * @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. + */ + +export * from './document/content.widget'; +export * from './content-widget/index'; +export * from './people/people.widget'; +export * from './radio-buttons/radio-buttons.widget'; +export * from './functional-group/functional-group.widget'; +export * from './typeahead/typeahead.widget'; +export * from './dropdown/dropdown.widget'; + +export * from './dynamic-table/index'; + +export * from './upload/upload.widget'; diff --git a/lib/core/src/lib/form/components/widgets/radio-buttons/radio-buttons.widget.html b/lib/process-services/src/lib/form/widgets/radio-buttons/radio-buttons.widget.html similarity index 100% rename from lib/core/src/lib/form/components/widgets/radio-buttons/radio-buttons.widget.html rename to lib/process-services/src/lib/form/widgets/radio-buttons/radio-buttons.widget.html diff --git a/lib/core/src/lib/form/components/widgets/radio-buttons/radio-buttons.widget.scss b/lib/process-services/src/lib/form/widgets/radio-buttons/radio-buttons.widget.scss similarity index 100% rename from lib/core/src/lib/form/components/widgets/radio-buttons/radio-buttons.widget.scss rename to lib/process-services/src/lib/form/widgets/radio-buttons/radio-buttons.widget.scss diff --git a/lib/core/src/lib/form/components/widgets/radio-buttons/radio-buttons.widget.spec.ts b/lib/process-services/src/lib/form/widgets/radio-buttons/radio-buttons.widget.spec.ts similarity index 86% rename from lib/core/src/lib/form/components/widgets/radio-buttons/radio-buttons.widget.spec.ts rename to lib/process-services/src/lib/form/widgets/radio-buttons/radio-buttons.widget.spec.ts index f3fed33bf3..5c586e6e86 100644 --- a/lib/core/src/lib/form/components/widgets/radio-buttons/radio-buttons.widget.spec.ts +++ b/lib/process-services/src/lib/form/widgets/radio-buttons/radio-buttons.widget.spec.ts @@ -17,26 +17,30 @@ import { ComponentFixture, fakeAsync, TestBed } from '@angular/core/testing'; import { Observable, of } from 'rxjs'; -import { FormService } from '../../../services/form.service'; -import { ContainerModel } from '../core/container.model'; -import { FormFieldTypes } from '../core/form-field-types'; -import { FormFieldOption } from '../core/form-field-option'; -import { FormFieldModel } from '../core/form-field.model'; -import { FormModel } from '../core/form.model'; +import { + FormService, + ContainerModel, + FormFieldTypes, + FormFieldOption, + FormFieldModel, + FormModel, + setupTestBed, + CoreTestingModule +} from '@alfresco/adf-core'; import { RadioButtonsWidgetComponent } from './radio-buttons.widget'; -import { setupTestBed } from '../../../../testing/setup-test-bed'; import { MatIconModule } from '@angular/material/icon'; import { MatRadioModule } from '@angular/material/radio'; import { FormsModule } from '@angular/forms'; -import { CoreTestingModule } from '../../../../testing'; import { TranslateModule } from '@ngx-translate/core'; -import { AlfrescoApiService } from '../../../../services'; +import { TaskFormService } from '../../services/task-form.service'; +import { ProcessDefinitionService } from '../../services/process-definition.service'; describe('RadioButtonsWidgetComponent', () => { let formService: FormService; let widget: RadioButtonsWidgetComponent; - let alfrescoApiService: AlfrescoApiService; + let taskFormService: TaskFormService; + let processDefinitionService: ProcessDefinitionService; setupTestBed({ imports: [ @@ -49,11 +53,12 @@ describe('RadioButtonsWidgetComponent', () => { }); beforeEach(() => { - alfrescoApiService = TestBed.inject(AlfrescoApiService); + taskFormService = TestBed.inject(TaskFormService); + processDefinitionService = TestBed.inject(ProcessDefinitionService); - formService = new FormService(null, alfrescoApiService, null); - widget = new RadioButtonsWidgetComponent(formService, null); - widget.field = new FormFieldModel(new FormModel(), { restUrl: '' }); + formService = new FormService(); + widget = new RadioButtonsWidgetComponent(formService, taskFormService, processDefinitionService, null); + widget.field = new FormFieldModel(new FormModel(), {restUrl: ''}); }); it('should request field values from service', () => { @@ -69,12 +74,12 @@ describe('RadioButtonsWidgetComponent', () => { restUrl: '' }); - spyOn(formService, 'getRestFieldValues').and.returnValue(new Observable((observer) => { + spyOn(taskFormService, 'getRestFieldValues').and.returnValue(new Observable((observer) => { observer.next(null); observer.complete(); })); widget.ngOnInit(); - expect(formService.getRestFieldValues).toHaveBeenCalledWith(taskId, fieldId); + expect(taskFormService.getRestFieldValues).toHaveBeenCalledWith(taskId, fieldId); }); it('should update form on values fetched', () => { @@ -92,7 +97,7 @@ describe('RadioButtonsWidgetComponent', () => { const field = widget.field; spyOn(field, 'updateForm').and.stub(); - spyOn(formService, 'getRestFieldValues').and.returnValue(new Observable((observer) => { + spyOn(taskFormService, 'getRestFieldValues').and.returnValue(new Observable((observer) => { observer.next(null); observer.complete(); })); @@ -112,7 +117,7 @@ describe('RadioButtonsWidgetComponent', () => { id: fieldId, restUrl: '' }); - spyOn(formService, 'getRestFieldValues').and.returnValue(new Observable((observer) => { + spyOn(taskFormService, 'getRestFieldValues').and.returnValue(new Observable((observer) => { observer.next(null); observer.complete(); })); @@ -120,16 +125,16 @@ describe('RadioButtonsWidgetComponent', () => { const field = widget.field; widget.field = null; widget.ngOnInit(); - expect(formService.getRestFieldValues).not.toHaveBeenCalled(); + expect(taskFormService.getRestFieldValues).not.toHaveBeenCalled(); widget.field = field; widget.field.restUrl = null; widget.ngOnInit(); - expect(formService.getRestFieldValues).not.toHaveBeenCalled(); + expect(taskFormService.getRestFieldValues).not.toHaveBeenCalled(); widget.field.restUrl = ''; widget.ngOnInit(); - expect(formService.getRestFieldValues).toHaveBeenCalled(); + expect(taskFormService.getRestFieldValues).toHaveBeenCalled(); }); it('should update the field value when an option is selected', () => { @@ -143,7 +148,6 @@ describe('RadioButtonsWidgetComponent', () => { let radioButtonWidget: RadioButtonsWidgetComponent; let fixture: ComponentFixture; let element: HTMLElement; - let stubFormService: FormService; const restOption: FormFieldOption[] = [ { id: 'opt-1', @@ -158,7 +162,6 @@ describe('RadioButtonsWidgetComponent', () => { fixture = TestBed.createComponent(RadioButtonsWidgetComponent); radioButtonWidget = fixture.componentInstance; element = fixture.nativeElement; - stubFormService = fixture.debugElement.injector.get(FormService); }); it('should show radio buttons as text when is readonly', async () => { @@ -215,7 +218,7 @@ describe('RadioButtonsWidgetComponent', () => { expect(radioButtonWidget.field.isValid).toBe(true); }); - it('should be able to set a Radio Button widget as required', () => { + it('should be able to set another Radio Button widget as required', () => { radioButtonWidget.field = new FormFieldModel(new FormModel({}), { id: 'radio-id', name: 'radio-name-label', @@ -259,8 +262,8 @@ describe('RadioButtonsWidgetComponent', () => { describe('and radioButton is populated via taskId', () => { beforeEach(() => { - spyOn(stubFormService, 'getRestFieldValues').and.returnValue(of(restOption)); - radioButtonWidget.field = new FormFieldModel(new FormModel({ taskId: 'task-id' }), { + spyOn(taskFormService, 'getRestFieldValues').and.returnValue(of(restOption)); + radioButtonWidget.field = new FormFieldModel(new FormModel({taskId: 'task-id'}), { id: 'radio-id', name: 'radio-name', type: FormFieldTypes.RADIO_BUTTONS, @@ -322,13 +325,13 @@ describe('RadioButtonsWidgetComponent', () => { describe('and radioButton is populated via processDefinitionId', () => { beforeEach(() => { - radioButtonWidget.field = new FormFieldModel(new FormModel({ processDefinitionId: 'proc-id' }), { + radioButtonWidget.field = new FormFieldModel(new FormModel({processDefinitionId: 'proc-id'}), { id: 'radio-id', name: 'radio-name', type: FormFieldTypes.RADIO_BUTTONS, restUrl: 'rest-url' }); - spyOn(stubFormService, 'getRestFieldValuesByProcessId').and.returnValue(of(restOption)); + spyOn(processDefinitionService, 'getRestFieldValuesByProcessId').and.returnValue(of(restOption)); radioButtonWidget.field.isVisible = true; fixture.detectChanges(); }); diff --git a/lib/core/src/lib/form/components/widgets/radio-buttons/radio-buttons.widget.ts b/lib/process-services/src/lib/form/widgets/radio-buttons/radio-buttons.widget.ts similarity index 83% rename from lib/core/src/lib/form/components/widgets/radio-buttons/radio-buttons.widget.ts rename to lib/process-services/src/lib/form/widgets/radio-buttons/radio-buttons.widget.ts index 8695098deb..84aa968618 100644 --- a/lib/core/src/lib/form/components/widgets/radio-buttons/radio-buttons.widget.ts +++ b/lib/process-services/src/lib/form/widgets/radio-buttons/radio-buttons.widget.ts @@ -15,13 +15,12 @@ * limitations under the License. */ - /* eslint-disable @angular-eslint/component-selector */ +/* eslint-disable @angular-eslint/component-selector */ -import { LogService } from '../../../../services/log.service'; +import { LogService, FormService, FormFieldOption, WidgetComponent } from '@alfresco/adf-core'; import { Component, OnInit, ViewEncapsulation } from '@angular/core'; -import { FormService } from '../../../services/form.service'; -import { FormFieldOption } from '../core/form-field-option'; -import { WidgetComponent } from '../widget.component'; +import { TaskFormService } from '../../services/task-form.service'; +import { ProcessDefinitionService } from '../../services/process-definition.service'; @Component({ selector: 'radio-buttons-widget', @@ -43,8 +42,10 @@ import { WidgetComponent } from '../widget.component'; export class RadioButtonsWidgetComponent extends WidgetComponent implements OnInit { constructor(public formService: FormService, + private taskFormService: TaskFormService, + private processDefinitionService: ProcessDefinitionService, private logService: LogService) { - super(formService); + super(formService); } ngOnInit() { @@ -58,7 +59,7 @@ export class RadioButtonsWidgetComponent extends WidgetComponent implements OnIn } getOptionsByTaskId() { - this.formService + this.taskFormService .getRestFieldValues( this.field.form.taskId, this.field.id @@ -73,7 +74,7 @@ export class RadioButtonsWidgetComponent extends WidgetComponent implements OnIn } getOptionsByProcessDefinitionId() { - this.formService + this.processDefinitionService .getRestFieldValuesByProcessId( this.field.form.processDefinitionId, this.field.id diff --git a/lib/core/src/lib/form/components/widgets/typeahead/typeahead.widget.html b/lib/process-services/src/lib/form/widgets/typeahead/typeahead.widget.html similarity index 100% rename from lib/core/src/lib/form/components/widgets/typeahead/typeahead.widget.html rename to lib/process-services/src/lib/form/widgets/typeahead/typeahead.widget.html diff --git a/lib/core/src/lib/form/components/widgets/typeahead/typeahead.widget.scss b/lib/process-services/src/lib/form/widgets/typeahead/typeahead.widget.scss similarity index 100% rename from lib/core/src/lib/form/components/widgets/typeahead/typeahead.widget.scss rename to lib/process-services/src/lib/form/widgets/typeahead/typeahead.widget.scss diff --git a/lib/core/src/lib/form/components/widgets/typeahead/typeahead.widget.spec.ts b/lib/process-services/src/lib/form/widgets/typeahead/typeahead.widget.spec.ts similarity index 77% rename from lib/core/src/lib/form/components/widgets/typeahead/typeahead.widget.spec.ts rename to lib/process-services/src/lib/form/widgets/typeahead/typeahead.widget.spec.ts index 597e893aa4..50963a7356 100644 --- a/lib/core/src/lib/form/components/widgets/typeahead/typeahead.widget.spec.ts +++ b/lib/process-services/src/lib/form/widgets/typeahead/typeahead.widget.spec.ts @@ -19,23 +19,27 @@ import { ComponentFixture, TestBed } from '@angular/core/testing'; import { Observable, of, throwError } from 'rxjs'; import { By } from '@angular/platform-browser'; -import { FormService } from '../../../services/form.service'; -import { FormFieldOption } from '../core/form-field-option'; -import { FormFieldTypes } from '../core/form-field-types'; -import { FormFieldModel } from '../core/form-field.model'; -import { FormModel } from '../core/form.model'; +import { + FormService, + FormFieldOption, + FormFieldTypes, + FormFieldModel, + FormModel, + setupTestBed, + CoreTestingModule +} from '@alfresco/adf-core'; import { TypeaheadWidgetComponent } from './typeahead.widget'; -import { setupTestBed } from '../../../../testing/setup-test-bed'; import { TranslateService, TranslateModule } from '@ngx-translate/core'; -import { CoreTestingModule } from '../../../../testing/core.testing.module'; -import { AlfrescoApiService } from '../../../../services'; +import { TaskFormService } from '../../services/task-form.service'; +import { ProcessDefinitionService } from '../../services/process-definition.service'; describe('TypeaheadWidgetComponent', () => { let formService: FormService; let widget: TypeaheadWidgetComponent; let translationService: TranslateService; - let alfrescoApiService: AlfrescoApiService; + let taskFormService: TaskFormService; + let processDefinitionService: ProcessDefinitionService; setupTestBed({ imports: [ @@ -45,14 +49,15 @@ describe('TypeaheadWidgetComponent', () => { }); beforeEach(() => { - alfrescoApiService = TestBed.inject(AlfrescoApiService); translationService = TestBed.inject(TranslateService); + taskFormService = TestBed.inject(TaskFormService); + processDefinitionService = TestBed.inject(ProcessDefinitionService); spyOn(translationService, 'instant').and.callFake((key) => key); spyOn(translationService, 'get').and.callFake((key) => of(key)); - formService = new FormService(null, alfrescoApiService, null); - widget = new TypeaheadWidgetComponent(formService, null); - widget.field = new FormFieldModel(new FormModel({ taskId: 'task-id' })); + formService = new FormService(); + widget = new TypeaheadWidgetComponent(formService, taskFormService, processDefinitionService, null); + widget.field = new FormFieldModel(new FormModel({taskId: 'task-id'})); widget.field.restUrl = 'whateverURL'; }); @@ -69,12 +74,12 @@ describe('TypeaheadWidgetComponent', () => { restUrl: 'whateverURL' }); - spyOn(formService, 'getRestFieldValues').and.returnValue(new Observable((observer) => { + spyOn(taskFormService, 'getRestFieldValues').and.returnValue(new Observable((observer) => { observer.next(null); observer.complete(); })); widget.ngOnInit(); - expect(formService.getRestFieldValues).toHaveBeenCalledWith(taskId, fieldId); + expect(taskFormService.getRestFieldValues).toHaveBeenCalledWith(taskId, fieldId); }); it('should not perform any request if restUrl is not present', () => { @@ -89,9 +94,9 @@ describe('TypeaheadWidgetComponent', () => { id: fieldId }); - spyOn(formService, 'getRestFieldValues'); + spyOn(taskFormService, 'getRestFieldValues'); widget.ngOnInit(); - expect(formService.getRestFieldValues).not.toHaveBeenCalled(); + expect(taskFormService.getRestFieldValues).not.toHaveBeenCalled(); }); it('should handle error when requesting fields with task id', () => { @@ -107,12 +112,12 @@ describe('TypeaheadWidgetComponent', () => { restUrl: 'whateverURL' }); const err = 'Error'; - spyOn(formService, 'getRestFieldValues').and.returnValue(throwError(err)); + spyOn(taskFormService, 'getRestFieldValues').and.returnValue(throwError(err)); spyOn(widget, 'handleError').and.stub(); widget.ngOnInit(); - expect(formService.getRestFieldValues).toHaveBeenCalled(); + expect(taskFormService.getRestFieldValues).toHaveBeenCalled(); expect(widget.handleError).toHaveBeenCalledWith(err); }); @@ -129,20 +134,20 @@ describe('TypeaheadWidgetComponent', () => { restUrl: 'whateverURL' }); const err = 'Error'; - spyOn(formService, 'getRestFieldValuesByProcessId').and.returnValue(throwError(err)); + spyOn(processDefinitionService, 'getRestFieldValuesByProcessId').and.returnValue(throwError(err)); spyOn(widget, 'handleError').and.stub(); widget.ngOnInit(); - expect(formService.getRestFieldValuesByProcessId).toHaveBeenCalled(); + expect(processDefinitionService.getRestFieldValuesByProcessId).toHaveBeenCalled(); expect(widget.handleError).toHaveBeenCalledWith(err); }); it('should setup initial value', () => { - spyOn(formService, 'getRestFieldValues').and.returnValue(new Observable((observer) => { + spyOn(taskFormService, 'getRestFieldValues').and.returnValue(new Observable((observer) => { observer.next([ - { id: '1', name: 'One' }, - { id: '2', name: 'Two' } + {id: '1', name: 'One'}, + {id: '2', name: 'Two'} ]); observer.complete(); })); @@ -150,15 +155,15 @@ describe('TypeaheadWidgetComponent', () => { widget.field.restUrl = 'whateverURL'; widget.ngOnInit(); - expect(formService.getRestFieldValues).toHaveBeenCalled(); + expect(taskFormService.getRestFieldValues).toHaveBeenCalled(); expect(widget.value).toBe('Two'); }); it('should not setup initial value due to missing option', () => { - spyOn(formService, 'getRestFieldValues').and.returnValue(new Observable((observer) => { + spyOn(taskFormService, 'getRestFieldValues').and.returnValue(new Observable((observer) => { observer.next([ - { id: '1', name: 'One' }, - { id: '2', name: 'Two' } + {id: '1', name: 'One'}, + {id: '2', name: 'Two'} ]); observer.complete(); })); @@ -167,17 +172,17 @@ describe('TypeaheadWidgetComponent', () => { widget.field.restUrl = 'whateverURL'; widget.ngOnInit(); - expect(formService.getRestFieldValues).toHaveBeenCalled(); + expect(taskFormService.getRestFieldValues).toHaveBeenCalled(); expect(widget.value).toBeUndefined(); }); it('should setup field options on load', () => { const options: FormFieldOption[] = [ - { id: '1', name: 'One' }, - { id: '2', name: 'Two' } + {id: '1', name: 'One'}, + {id: '2', name: 'Two'} ]; - spyOn(formService, 'getRestFieldValues').and.returnValue(new Observable((observer) => { + spyOn(taskFormService, 'getRestFieldValues').and.returnValue(new Observable((observer) => { observer.next(options); observer.complete(); })); @@ -187,7 +192,7 @@ describe('TypeaheadWidgetComponent', () => { }); it('should update form upon options setup', () => { - spyOn(formService, 'getRestFieldValues').and.returnValue(new Observable((observer) => { + spyOn(taskFormService, 'getRestFieldValues').and.returnValue(new Observable((observer) => { observer.next([]); observer.complete(); })); @@ -200,8 +205,8 @@ describe('TypeaheadWidgetComponent', () => { it('should get filtered options', () => { const options: FormFieldOption[] = [ - { id: '1', name: 'Item one' }, - { id: '2', name: 'Item two' } + {id: '1', name: 'Item one'}, + {id: '2', name: 'Item two'} ]; widget.field.options = options; widget.value = 'tw'; @@ -213,8 +218,8 @@ describe('TypeaheadWidgetComponent', () => { it('should be case insensitive when filtering options', () => { const options: FormFieldOption[] = [ - { id: '1', name: 'Item one' }, - { id: '2', name: 'iTEM TWo' } + {id: '1', name: 'Item one'}, + {id: '2', name: 'iTEM TWo'} ]; widget.field.options = options; widget.value = 'tW'; @@ -228,14 +233,14 @@ describe('TypeaheadWidgetComponent', () => { let typeaheadWidgetComponent: TypeaheadWidgetComponent; let fixture: ComponentFixture; let element: HTMLElement; - let stubFormService; + let stubProcessDefinitionService; const fakeOptionList: FormFieldOption[] = [{ id: '1', name: 'Fake Name 1 ' }, { id: '2', name: 'Fake Name 2' - }, { id: '3', name: 'Fake Name 3' }]; + }, {id: '3', name: 'Fake Name 3'}]; beforeEach(() => { fixture = TestBed.createComponent(TypeaheadWidgetComponent); @@ -248,16 +253,16 @@ describe('TypeaheadWidgetComponent', () => { TestBed.resetTestingModule(); }); - describe ('and typeahead is in readonly mode', () => { + describe('and typeahead is in readonly mode', () => { it('should show typeahead value with input disabled', async () => { typeaheadWidgetComponent.field = new FormFieldModel( - new FormModel({ processVariables: [{ name: 'typeahead-id_LABEL', value: 'FakeProcessValue' }] }), { - id: 'typeahead-id', - name: 'typeahead-name', - type: 'readonly', - params: { field: { id: 'typeahead-id', name: 'typeahead-name', type: 'typeahead' } } - }); + new FormModel({processVariables: [{name: 'typeahead-id_LABEL', value: 'FakeProcessValue'}]}), { + id: 'typeahead-id', + name: 'typeahead-name', + type: 'readonly', + params: {field: {id: 'typeahead-id', name: 'typeahead-name', type: 'typeahead'}} + }); fixture.detectChanges(); await fixture.whenStable(); @@ -277,9 +282,8 @@ describe('TypeaheadWidgetComponent', () => { describe('and typeahead is populated via taskId', () => { beforeEach(() => { - stubFormService = fixture.debugElement.injector.get(FormService); - spyOn(stubFormService, 'getRestFieldValues').and.returnValue(of(fakeOptionList)); - typeaheadWidgetComponent.field = new FormFieldModel(new FormModel({ taskId: 'fake-task-id' }), { + spyOn(taskFormService, 'getRestFieldValues').and.returnValue(of(fakeOptionList)); + typeaheadWidgetComponent.field = new FormFieldModel(new FormModel({taskId: 'fake-task-id'}), { id: 'typeahead-id', name: 'typeahead-name', type: FormFieldTypes.TYPEAHEAD, @@ -355,15 +359,15 @@ describe('TypeaheadWidgetComponent', () => { describe('and typeahead is populated via processDefinitionId', () => { beforeEach(() => { - stubFormService = fixture.debugElement.injector.get(FormService); - spyOn(stubFormService, 'getRestFieldValuesByProcessId').and.returnValue(of(fakeOptionList)); - typeaheadWidgetComponent.field = new FormFieldModel(new FormModel({ processDefinitionId: 'fake-process-id' }), { + stubProcessDefinitionService = fixture.debugElement.injector.get(ProcessDefinitionService); + spyOn(stubProcessDefinitionService, 'getRestFieldValuesByProcessId').and.returnValue(of(fakeOptionList)); + typeaheadWidgetComponent.field = new FormFieldModel(new FormModel({processDefinitionId: 'fake-process-id'}), { id: 'typeahead-id', name: 'typeahead-name', type: FormFieldTypes.TYPEAHEAD, readOnly: 'false' }); - typeaheadWidgetComponent.field.emptyOption = { id: 'empty', name: 'Choose one...' }; + typeaheadWidgetComponent.field.emptyOption = {id: 'empty', name: 'Choose one...'}; typeaheadWidgetComponent.field.isVisible = true; fixture.detectChanges(); }); diff --git a/lib/core/src/lib/form/components/widgets/typeahead/typeahead.widget.ts b/lib/process-services/src/lib/form/widgets/typeahead/typeahead.widget.ts similarity index 91% rename from lib/core/src/lib/form/components/widgets/typeahead/typeahead.widget.ts rename to lib/process-services/src/lib/form/widgets/typeahead/typeahead.widget.ts index e2095a229a..875614f6df 100644 --- a/lib/core/src/lib/form/components/widgets/typeahead/typeahead.widget.ts +++ b/lib/process-services/src/lib/form/widgets/typeahead/typeahead.widget.ts @@ -17,12 +17,11 @@ /* eslint-disable @angular-eslint/component-selector */ -import { LogService } from '../../../../services/log.service'; +import { LogService, FormService, FormFieldOption, WidgetComponent } from '@alfresco/adf-core'; import { ENTER, ESCAPE } from '@angular/cdk/keycodes'; import { Component, OnInit, ViewEncapsulation } from '@angular/core'; -import { FormService } from '../../../services/form.service'; -import { FormFieldOption } from '../core/form-field-option'; -import { WidgetComponent } from '../widget.component'; +import { TaskFormService } from '../../services/task-form.service'; +import { ProcessDefinitionService } from '../../services/process-definition.service'; @Component({ selector: 'typeahead-widget', @@ -49,6 +48,8 @@ export class TypeaheadWidgetComponent extends WidgetComponent implements OnInit options: FormFieldOption[] = []; constructor(public formService: FormService, + private taskFormService: TaskFormService, + private processDefinitionService: ProcessDefinitionService, private logService: LogService) { super(formService); } @@ -65,7 +66,7 @@ export class TypeaheadWidgetComponent extends WidgetComponent implements OnInit } getValuesByTaskId() { - this.formService + this.taskFormService .getRestFieldValues( this.field.form.taskId, this.field.id @@ -90,7 +91,7 @@ export class TypeaheadWidgetComponent extends WidgetComponent implements OnInit } getValuesByProcessDefinitionId() { - this.formService + this.processDefinitionService .getRestFieldValuesByProcessId( this.field.form.processDefinitionId, this.field.id @@ -124,7 +125,7 @@ export class TypeaheadWidgetComponent extends WidgetComponent implements OnInit isValidOptionName(optionName: string): boolean { const option = this.field.options.find((item) => item.name && item.name.toLocaleLowerCase() === optionName.toLocaleLowerCase()); - return option ? true : false; + return !!option; } onKeyUp(event: KeyboardEvent) { @@ -166,7 +167,7 @@ export class TypeaheadWidgetComponent extends WidgetComponent implements OnInit } isReadOnlyType(): boolean { - return this.field.type === 'readonly' ? true : false; + return this.field.type === 'readonly'; } } diff --git a/lib/core/src/lib/form/components/widgets/upload/upload.widget.html b/lib/process-services/src/lib/form/widgets/upload/upload.widget.html similarity index 100% rename from lib/core/src/lib/form/components/widgets/upload/upload.widget.html rename to lib/process-services/src/lib/form/widgets/upload/upload.widget.html diff --git a/lib/core/src/lib/form/components/widgets/upload/upload.widget.scss b/lib/process-services/src/lib/form/widgets/upload/upload.widget.scss similarity index 100% rename from lib/core/src/lib/form/components/widgets/upload/upload.widget.scss rename to lib/process-services/src/lib/form/widgets/upload/upload.widget.scss diff --git a/lib/core/src/lib/form/components/widgets/upload/upload.widget.spec.ts b/lib/process-services/src/lib/form/widgets/upload/upload.widget.spec.ts similarity index 92% rename from lib/core/src/lib/form/components/widgets/upload/upload.widget.spec.ts rename to lib/process-services/src/lib/form/widgets/upload/upload.widget.spec.ts index 80c2397401..14c193961c 100644 --- a/lib/core/src/lib/form/components/widgets/upload/upload.widget.spec.ts +++ b/lib/process-services/src/lib/form/widgets/upload/upload.widget.spec.ts @@ -19,22 +19,24 @@ import { DebugElement } from '@angular/core'; import { ComponentFixture, TestBed } from '@angular/core/testing'; import { By } from '@angular/platform-browser'; import { of } from 'rxjs'; -import { FormService } from '../../../services/form.service'; -import { ProcessContentService } from '../../../services/process-content.service'; -import { FormFieldTypes } from '../core/form-field-types'; -import { FormModel } from '../core/form.model'; -import { FormFieldModel } from '../core/form-field.model'; +import { + FormService, + FormFieldTypes, + FormModel, + FormFieldModel, + setupTestBed, + CoreTestingModule +} from '@alfresco/adf-core'; import { UploadWidgetComponent } from './upload.widget'; -import { setupTestBed } from '../../../../testing/setup-test-bed'; -import { CoreTestingModule } from '../../../../testing/core.testing.module'; import { TranslateModule } from '@ngx-translate/core'; import { RelatedContentRepresentation } from '@alfresco/js-api'; +import { ProcessContentService } from '../../services/process-content.service'; const fakePngAnswer = new RelatedContentRepresentation({ id: 1155, name: 'a_png_file.png', created: '2017-07-25T17:17:37.099Z', - createdBy: { id: 1001, firstName: 'Admin', lastName: 'admin', email: 'admin' }, + createdBy: {id: 1001, firstName: 'Admin', lastName: 'admin', email: 'admin'}, relatedContent: false, contentAvailable: true, link: false, @@ -48,7 +50,7 @@ const fakeJpgAnswer = { id: 1156, name: 'a_jpg_file.jpg', created: '2017-07-25T17:17:37.118Z', - createdBy: { id: 1001, firstName: 'Admin', lastName: 'admin', email: 'admin' }, + createdBy: {id: 1001, firstName: 'Admin', lastName: 'admin', email: 'admin'}, relatedContent: false, contentAvailable: true, link: false, @@ -64,7 +66,7 @@ describe('UploadWidgetComponent', () => { id, name, created: '2017-07-25T17:17:37.118Z', - createdBy: { id: 1001, firstName: 'Admin', lastName: 'admin', email: 'admin' }, + createdBy: {id: 1001, firstName: 'Admin', lastName: 'admin', email: 'admin'}, relatedContent: false, contentAvailable: true, link: false, @@ -76,8 +78,8 @@ describe('UploadWidgetComponent', () => { let contentService: ProcessContentService; - const filePngFake = new File(['fakePng'], 'file-fake.png', { type: 'image/png' }); - const filJpgFake = new File(['fakeJpg'], 'file-fake.jpg', { type: 'image/jpg' }); + const filePngFake = new File(['fakePng'], 'file-fake.png', {type: 'image/png'}); + const filJpgFake = new File(['fakeJpg'], 'file-fake.jpg', {type: 'image/jpg'}); setupTestBed({ imports: [ @@ -109,7 +111,7 @@ describe('UploadWidgetComponent', () => { uploadWidgetComponent.field = new FormFieldModel(null, { type: FormFieldTypes.UPLOAD, value: [ - { name: encodedFileName } + {name: encodedFileName} ] }); @@ -128,7 +130,7 @@ describe('UploadWidgetComponent', () => { uploadWidgetComponent.field = new FormFieldModel(new FormModel(), { type: FormFieldTypes.UPLOAD, value: [ - { name: 'filename' } + {name: 'filename'} ] }); @@ -139,7 +141,7 @@ describe('UploadWidgetComponent', () => { }); beforeEach(() => { - uploadWidgetComponent.field = new FormFieldModel(new FormModel({ taskId: 'fake-upload-id' }), { + uploadWidgetComponent.field = new FormFieldModel(new FormModel({taskId: 'fake-upload-id'}), { id: 'upload-id', name: 'upload-name', value: '', @@ -196,7 +198,7 @@ describe('UploadWidgetComponent', () => { await fixture.whenStable(); const inputDebugElement = fixture.debugElement.query(By.css('#upload-id')); - inputDebugElement.triggerEventHandler('change', { target: { files: [filJpgFake] } }); + inputDebugElement.triggerEventHandler('change', {target: {files: [filJpgFake]}}); const filesList = fixture.debugElement.query(By.css('#file-1156')); expect(filesList).toBeDefined(); @@ -224,7 +226,7 @@ describe('UploadWidgetComponent', () => { await fixture.whenStable(); const inputDebugElement = fixture.debugElement.query(By.css('#upload-id')); - inputDebugElement.triggerEventHandler('change', { target: { files: [filePngFake, filJpgFake] } }); + inputDebugElement.triggerEventHandler('change', {target: {files: [filePngFake, filJpgFake]}}); fixture.detectChanges(); await fixture.whenStable(); @@ -254,7 +256,7 @@ describe('UploadWidgetComponent', () => { await fixture.whenStable(); const inputDebugElement = fixture.debugElement.query(By.css('#upload-id')); - inputDebugElement.triggerEventHandler('change', { target: { files: [filePngFake, filJpgFake] } }); + inputDebugElement.triggerEventHandler('change', {target: {files: [filePngFake, filJpgFake]}}); fixture.detectChanges(); await fixture.whenStable(); @@ -407,5 +409,5 @@ describe('UploadWidgetComponent', () => { }); }); - }); + }); }); diff --git a/lib/core/src/lib/form/components/widgets/upload/upload.widget.ts b/lib/process-services/src/lib/form/widgets/upload/upload.widget.ts similarity index 92% rename from lib/core/src/lib/form/components/widgets/upload/upload.widget.ts rename to lib/process-services/src/lib/form/widgets/upload/upload.widget.ts index 81455e965e..25c61afa19 100644 --- a/lib/core/src/lib/form/components/widgets/upload/upload.widget.ts +++ b/lib/process-services/src/lib/form/widgets/upload/upload.widget.ts @@ -17,14 +17,10 @@ /* eslint-disable @angular-eslint/component-selector */ -import { LogService } from '../../../../services/log.service'; -import { ThumbnailService } from '../../../../services/thumbnail.service'; +import { LogService, ThumbnailService, FormService, ContentLinkModel, WidgetComponent } from '@alfresco/adf-core'; 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 { ProcessContentService } from '../../services/process-content.service'; import { mergeMap, map } from 'rxjs/operators'; @Component({ diff --git a/lib/process-services/src/lib/process-list/components/process-filters.component.spec.ts b/lib/process-services/src/lib/process-list/components/process-filters.component.spec.ts index e590a021ee..75efb45ef9 100644 --- a/lib/process-services/src/lib/process-list/components/process-filters.component.spec.ts +++ b/lib/process-services/src/lib/process-list/components/process-filters.component.spec.ts @@ -155,7 +155,7 @@ describe('ProcessFiltersComponent', () => { fixture.detectChanges(); }); - it('should emit an error with a bad response', async () => { + it('should emit an error with a bad response of getProcessFilters', async () => { const mockErrorFilterPromise = Promise.reject({ error: 'wrong request' }); @@ -172,7 +172,7 @@ describe('ProcessFiltersComponent', () => { fixture.detectChanges(); }); - it('should emit an error with a bad response', async () => { + it('should emit an error with a bad response of getDeployedApplicationsByName', async () => { const mockErrorFilterPromise = Promise.reject({ error: 'wrong request' }); diff --git a/lib/process-services/src/lib/process-list/components/start-process.component.spec.ts b/lib/process-services/src/lib/process-list/components/start-process.component.spec.ts index afaf7a445a..ebe5b27206 100644 --- a/lib/process-services/src/lib/process-list/components/start-process.component.spec.ts +++ b/lib/process-services/src/lib/process-list/components/start-process.component.spec.ts @@ -17,7 +17,7 @@ import { DebugElement, SimpleChange } from '@angular/core'; import { ComponentFixture, TestBed } from '@angular/core/testing'; -import { ActivitiContentService, AppConfigService, FormService, setupTestBed, AppsProcessService } from '@alfresco/adf-core'; +import { AppConfigService, setupTestBed, AppsProcessService } from '@alfresco/adf-core'; import { of, throwError } from 'rxjs'; import { MatSelectChange } from '@angular/material/select'; import { ProcessInstanceVariable } from '../models/process-instance-variable.model'; @@ -37,6 +37,7 @@ import { TranslateModule } from '@ngx-translate/core'; import { deployedApps } from '../../mock/apps-list.mock'; import { ProcessNamePipe } from '../../pipes/process-name.pipe'; import { ProcessInstance } from '../models/process-instance.model'; +import { ActivitiContentService } from '../../form/services/activiti-alfresco.service'; describe('StartProcessComponent', () => { @@ -45,7 +46,6 @@ describe('StartProcessComponent', () => { let component: StartProcessInstanceComponent; let fixture: ComponentFixture; let processService: ProcessService; - let formService: FormService; let appsProcessService: AppsProcessService; let getDefinitionsSpy: jasmine.Spy; let getStartFormDefinitionSpy: jasmine.Spy; @@ -84,12 +84,11 @@ describe('StartProcessComponent', () => { fixture = TestBed.createComponent(StartProcessInstanceComponent); component = fixture.componentInstance; processService = TestBed.inject(ProcessService); - formService = TestBed.inject(FormService); appsProcessService = TestBed.inject(AppsProcessService); getDefinitionsSpy = spyOn(processService, 'getProcessDefinitions').and.returnValue(of(testMultipleProcessDefs)); startProcessSpy = spyOn(processService, 'startProcess').and.returnValue(of(newProcess)); - getStartFormDefinitionSpy = spyOn(formService, 'getStartFormDefinition').and.returnValue(of(taskFormMock)); + getStartFormDefinitionSpy = spyOn(processService, 'getStartFormDefinition').and.returnValue(of(taskFormMock)); applyAlfrescoNodeSpy = spyOn(activitiContentService, 'applyAlfrescoNode').and.returnValue(of({ id: 1234 })); spyOn(activitiContentService, 'getAlfrescoRepositories').and.returnValue(of([{ id: '1', name: 'fake-repo-name'}])); }); diff --git a/lib/process-services/src/lib/process-list/components/start-process.component.ts b/lib/process-services/src/lib/process-list/components/start-process.component.ts index b91b86e493..51d66cb8e5 100644 --- a/lib/process-services/src/lib/process-list/components/start-process.component.ts +++ b/lib/process-services/src/lib/process-list/components/start-process.component.ts @@ -20,7 +20,6 @@ import { Output, SimpleChanges, ViewChild, ViewEncapsulation, OnDestroy } from '@angular/core'; import { - ActivitiContentService, AppConfigService, AppConfigValues, AppsProcessService, @@ -39,6 +38,7 @@ import { StartFormComponent } from '../../form'; import { MinimalNode, RelatedContentRepresentation } from '@alfresco/js-api'; import { AppDefinitionRepresentationModel } from '../../task-list'; import { ProcessNamePipe } from '../../pipes/process-name.pipe'; +import { ActivitiContentService } from '../../form/services/activiti-alfresco.service'; const MAX_LENGTH = 255; @Component({ diff --git a/lib/process-services/src/lib/process-list/process-list.module.ts b/lib/process-services/src/lib/process-list/process-list.module.ts index 3efe0dcd79..2566cecfc2 100644 --- a/lib/process-services/src/lib/process-list/process-list.module.ts +++ b/lib/process-services/src/lib/process-list/process-list.module.ts @@ -24,7 +24,7 @@ import { MaterialModule } from '../material.module'; import { ProcessCommentsModule } from '../process-comments/process-comments.module'; import { TaskListModule } from '../task-list/task-list.module'; import { PeopleModule } from '../people/people.module'; -import { ContentWidgetModule } from '../content-widget/content-widget.module'; +import { ContentWidgetModule } from '../form/widgets/content-widget/content-widget.module'; import { ProcessAuditDirective } from './components/process-audit.directive'; import { ProcessFiltersComponent } from './components/process-filters.component'; import { ProcessInstanceDetailsComponent } from './components/process-instance-details.component'; diff --git a/lib/process-services/src/lib/process-list/services/process.service.ts b/lib/process-services/src/lib/process-list/services/process.service.ts index 8293222075..f78e7791fb 100644 --- a/lib/process-services/src/lib/process-list/services/process.service.ts +++ b/lib/process-services/src/lib/process-list/services/process.service.ts @@ -148,10 +148,54 @@ export class ProcessService { getProcess(processInstanceId: string): Observable { return from(this.processInstancesApi.getProcessInstance(processInstanceId)) .pipe( + map(this.toJson), catchError((err) => this.handleProcessError(err)) ); } + /** + * Gets the start form definition for a given process. + * + * @param processId Process definition ID + * @returns Form definition + */ + getStartFormDefinition(processId: string): Observable { + return from(this.processDefinitionsApi.getProcessDefinitionStartForm(processId)) + .pipe( + map(this.toJson), + catchError((err) => this.handleProcessError(err)) + ); + } + + + /** + * Gets the start form instance for a given process. + * + * @param processId Process definition ID + * @returns Form definition + */ + getStartFormInstance(processId: string): Observable { + return from(this.processInstancesApi.getProcessInstanceStartForm(processId)) + .pipe( + map(this.toJson), + catchError((err) => this.handleProcessError(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 {}; + } + /** * Gets task instances for a process instance. * diff --git a/lib/process-services/src/lib/task-list/components/attach-form.component.ts b/lib/process-services/src/lib/task-list/components/attach-form.component.ts index f932decb28..1606b9a04c 100644 --- a/lib/process-services/src/lib/task-list/components/attach-form.component.ts +++ b/lib/process-services/src/lib/task-list/components/attach-form.component.ts @@ -15,11 +15,13 @@ * limitations under the License. */ -import { FormService, LogService } from '@alfresco/adf-core'; +import { LogService } from '@alfresco/adf-core'; import { Component, EventEmitter, Input, OnChanges, OnInit, Output } from '@angular/core'; import { Form } from '../models/form.model'; import { TaskListService } from './../services/tasklist.service'; import { UntypedFormControl, Validators } from '@angular/forms'; +import { ModelService } from '../../form/services/model.service'; +import { TaskFormService } from '../../form/services/task-form.service'; @Component({ selector: 'adf-attach-form', @@ -59,7 +61,8 @@ export class AttachFormComponent implements OnInit, OnChanges { constructor(private taskService: TaskListService, private logService: LogService, - private formService: FormService) { } + private modelService: ModelService, + private taskFormService: TaskFormService) { } ngOnInit() { this.attachFormControl = new UntypedFormControl('', Validators.required); @@ -111,9 +114,9 @@ export class AttachFormComponent implements OnInit, OnChanges { } private onFormAttached() { - this.formService.getTaskForm(this.taskId) + this.taskFormService.getTaskForm(this.taskId) .subscribe((res) => { - this.formService.getFormDefinitionByName(res.name).subscribe((formDef) => { + this.modelService.getFormDefinitionByName(res.name).subscribe((formDef) => { this.formId = this.selectedFormId = formDef; }); }, (err) => { diff --git a/lib/process-services/src/lib/task-list/components/task-details.component.spec.ts b/lib/process-services/src/lib/task-list/components/task-details.component.spec.ts index 398e800528..dd81cf0cfe 100644 --- a/lib/process-services/src/lib/task-list/components/task-details.component.spec.ts +++ b/lib/process-services/src/lib/task-list/components/task-details.component.spec.ts @@ -23,7 +23,6 @@ import { FormModel, FormOutcomeEvent, FormOutcomeModel, - FormService, setupTestBed, BpmUserService, CommentProcessService, LogService, AuthenticationService, @@ -43,6 +42,8 @@ import { TaskListService } from './../services/tasklist.service'; import { TaskDetailsComponent } from './task-details.component'; import { ProcessTestingModule } from '../../testing/process.testing.module'; import { TranslateModule } from '@ngx-translate/core'; +import { TaskService } from '../../form/services/task.service'; +import { TaskFormService } from '../../form/services/task-form.service'; const fakeUser = new UserProcessModel({ id: 'fake-id', @@ -60,8 +61,9 @@ const fakeTaskAssignResponse = new TaskDetailsModel({ describe('TaskDetailsComponent', () => { - let service: TaskListService; - let formService: FormService; + let taskListService: TaskListService; + let taskService: TaskService; + let taskFormService: TaskFormService; let component: TaskDetailsComponent; let fixture: ComponentFixture; let getTaskDetailsSpy: jasmine.Spy; @@ -86,18 +88,19 @@ describe('TaskDetailsComponent', () => { const userService: BpmUserService = TestBed.inject(BpmUserService); spyOn(userService, 'getCurrentUserInfo').and.returnValue(of(null)); - service = TestBed.inject(TaskListService); - spyOn(service, 'getTaskChecklist').and.returnValue(of(noDataMock)); + taskListService = TestBed.inject(TaskListService); + spyOn(taskListService, 'getTaskChecklist').and.returnValue(of(noDataMock)); - formService = TestBed.inject(FormService); + taskService = TestBed.inject(TaskService); + taskFormService = TestBed.inject(TaskFormService); - getTaskDetailsSpy = spyOn(service, 'getTaskDetails').and.returnValue(of(taskDetailsMock)); - spyOn(formService, 'getTaskForm').and.returnValue(of(taskFormMock)); + getTaskDetailsSpy = spyOn(taskListService, 'getTaskDetails').and.returnValue(of(taskDetailsMock)); + spyOn(taskFormService, 'getTaskForm').and.returnValue(of(taskFormMock)); taskDetailsMock.processDefinitionId = null; - spyOn(formService, 'getTask').and.returnValue(of(taskDetailsMock)); + spyOn(taskService, 'getTask').and.returnValue(of(taskDetailsMock)); - getTasksSpy = spyOn(service, 'getTasks').and.returnValue(of(tasksMock)); - assignTaskSpy = spyOn(service, 'assignTask').and.returnValue(of(fakeTaskAssignResponse)); + getTasksSpy = spyOn(taskListService, 'getTasks').and.returnValue(of(tasksMock)); + assignTaskSpy = spyOn(taskListService, 'assignTask').and.returnValue(of(fakeTaskAssignResponse)); commentProcessService = TestBed.inject(CommentProcessService); authService = TestBed.inject(AuthenticationService); diff --git a/lib/process-services/src/lib/task-list/components/task-form/task-form.component.spec.ts b/lib/process-services/src/lib/task-list/components/task-form/task-form.component.spec.ts index 7395753b85..7973b4a33d 100644 --- a/lib/process-services/src/lib/task-list/components/task-form/task-form.component.spec.ts +++ b/lib/process-services/src/lib/task-list/components/task-form/task-form.component.spec.ts @@ -23,7 +23,6 @@ import { FormModel, FormOutcomeEvent, FormOutcomeModel, - FormService, setupTestBed } from '@alfresco/adf-core'; import { TaskListService } from '../../services/tasklist.service'; @@ -52,11 +51,14 @@ import { TaskDetailsModel } from '../../models/task-details.model'; import { ProcessTestingModule } from '../../../testing/process.testing.module'; import { TranslateModule } from '@ngx-translate/core'; import { By } from '@angular/platform-browser'; +import { TaskFormService } from '../../../form/services/task-form.service'; +import { TaskService } from '../../../form/services/task.service'; describe('TaskFormComponent', () => { let component: TaskFormComponent; let fixture: ComponentFixture; - let formService: FormService; + let taskService: TaskService; + let taskFormService: TaskFormService; let taskListService: TaskListService; let getTaskDetailsSpy: jasmine.Spy; let completeTaskSpy: jasmine.Spy; @@ -78,13 +80,14 @@ describe('TaskFormComponent', () => { element = fixture.nativeElement; taskListService = TestBed.inject(TaskListService); - formService = TestBed.inject(FormService); + taskFormService = TestBed.inject(TaskFormService); + taskService = TestBed.inject(TaskService); getTaskDetailsSpy = spyOn(taskListService, 'getTaskDetails').and.returnValue(of(taskDetailsMock)); completeTaskSpy = spyOn(taskListService, 'completeTask').and.returnValue(of({})); - spyOn(formService, 'getTaskForm').and.returnValue(of(taskFormMock)); + spyOn(taskFormService, 'getTaskForm').and.returnValue(of(taskFormMock)); taskDetailsMock.processDefinitionId = null; - spyOn(formService, 'getTask').and.returnValue(of(taskDetailsMock)); + spyOn(taskService, 'getTask').and.returnValue(of(taskDetailsMock)); authService = TestBed.inject(AuthenticationService); getBpmLoggedUserSpy = spyOn(authService, 'getBpmLoggedUser').and.returnValue(of(fakeUser)); }); @@ -123,7 +126,7 @@ describe('TaskFormComponent', () => { getBpmLoggedUserSpy.and.returnValue(of({ id: 1001, firstName: 'Wilbur', lastName: 'Adams', email: 'wilbur@app.activiti.com' })); getTaskDetailsSpy.and.returnValue(of(taskDetailsMock)); const formCompletedSpy: jasmine.Spy = spyOn(component.formCompleted, 'emit'); - const completeTaskFormSpy = spyOn(formService, 'completeTaskForm').and.returnValue(of({})); + const completeTaskFormSpy = spyOn(taskFormService, 'completeTaskForm').and.returnValue(of({})); component.taskId = '123'; component.ngOnInit(); fixture.detectChanges(); @@ -137,7 +140,7 @@ describe('TaskFormComponent', () => { it('Should emit error event in case form complete service fails', async () => { const errorSpy: jasmine.Spy = spyOn(component.error, 'emit'); - const completeTaskFormSpy = spyOn(formService, 'completeTaskForm').and.returnValue(throwError({message: 'servce failed'})); + const completeTaskFormSpy = spyOn(taskFormService, 'completeTaskForm').and.returnValue(throwError({message: 'servce failed'})); getTaskDetailsSpy.and.returnValue(of(initiatorCanCompleteTaskDetailsMock)); component.taskId = '123'; fixture.detectChanges(); @@ -471,7 +474,7 @@ describe('TaskFormComponent', () => { beforeEach(async () => { component.taskId = '123'; - spyOn(formService, 'completeTaskForm').and.returnValue(of({})); + spyOn(taskFormService, 'completeTaskForm').and.returnValue(of({})); taskDetailsMock.formKey = '4'; getTaskDetailsSpy.and.returnValue(of(taskDetailsMock)); fixture.detectChanges(); @@ -552,7 +555,7 @@ describe('TaskFormComponent', () => { getTaskDetailsSpy.and.returnValue(of(taskDetailsMock)); const formCompletedSpy: jasmine.Spy = spyOn(component.formCompleted, 'emit'); - const completeTaskFormSpy = spyOn(formService, 'completeTaskForm').and.returnValue(of({})); + const completeTaskFormSpy = spyOn(taskFormService, 'completeTaskForm').and.returnValue(of({})); component.taskId = '123'; component.ngOnInit(); @@ -573,7 +576,7 @@ describe('TaskFormComponent', () => { it('Should be able to complete the task if process initiator allowed to complete the task', async () => { getBpmLoggedUserSpy.and.returnValue(of({ id: 1001, firstName: 'Wilbur', lastName: 'Adams', email: 'wilbur@app.activiti.com' })); const formCompletedSpy: jasmine.Spy = spyOn(component.formCompleted, 'emit'); - const completeTaskFormSpy = spyOn(formService, 'completeTaskForm').and.returnValue(of({})); + const completeTaskFormSpy = spyOn(taskFormService, 'completeTaskForm').and.returnValue(of({})); getTaskDetailsSpy.and.returnValue(of(initiatorCanCompleteTaskDetailsMock)); component.taskId = '123'; @@ -614,7 +617,7 @@ describe('TaskFormComponent', () => { it('Should be able to complete a task with candidates users if process initiator not allowed to complete the task', async () => { const formCompletedSpy: jasmine.Spy = spyOn(component.formCompleted, 'emit'); getBpmLoggedUserSpy.and.returnValue(of({ id: 1001, firstName: 'Wilbur', lastName: 'Adams', email: 'wilbur@app.activiti.com' })); - const completeTaskFormSpy = spyOn(formService, 'completeTaskForm').and.returnValue(of({})); + const completeTaskFormSpy = spyOn(taskFormService, 'completeTaskForm').and.returnValue(of({})); getTaskDetailsSpy.and.returnValue(of(claimedTaskDetailsMock)); component.taskId = '123'; @@ -800,7 +803,7 @@ describe('TaskFormComponent', () => { beforeEach(() => { component.taskId = '20259'; - spyOn(formService, 'saveTaskForm').and.returnValue(of({})); + spyOn(taskFormService, 'saveTaskForm').and.returnValue(of({})); }); it('[T14599423] Form in unassigned task is read-only', async () => { @@ -821,7 +824,7 @@ describe('TaskFormComponent', () => { await fixture.whenStable(); const saveButton = fixture.debugElement.nativeElement.querySelector('[id="adf-form-save"]'); saveButton.click(); - expect(formService.saveTaskForm).toHaveBeenCalled(); + expect(taskFormService.saveTaskForm).toHaveBeenCalled(); }); it('Should be able to save a form for a involved group user', async () => { @@ -835,7 +838,7 @@ describe('TaskFormComponent', () => { expect(saveButton.disabled).toEqual(false); expect(completeButton.disabled).toEqual(true); saveButton.click(); - expect(formService.saveTaskForm).toHaveBeenCalled(); + expect(taskFormService.saveTaskForm).toHaveBeenCalled(); }); }); diff --git a/lib/process-services/src/lib/task-list/services/tasklist.service.spec.ts b/lib/process-services/src/lib/task-list/services/tasklist.service.spec.ts index e06b137f66..43847313bc 100644 --- a/lib/process-services/src/lib/task-list/services/tasklist.service.spec.ts +++ b/lib/process-services/src/lib/task-list/services/tasklist.service.spec.ts @@ -139,26 +139,6 @@ describe('Activiti TaskList Service', () => { }); }); - it('should return the task list filtered', (done) => { - service.findTasksByState(fakeFilter).subscribe((res) => { - expect(res.size).toEqual(1); - expect(res.start).toEqual(0); - expect(res.data).toBeDefined(); - expect(res.data.length).toEqual(1); - expect(res.data[0].name).toEqual('FakeNameTask'); - expect(res.data[0].assignee.email).toEqual('fake-email@dom.com'); - expect(res.data[0].assignee.firstName).toEqual('firstName'); - expect(res.data[0].assignee.lastName).toEqual('lastName'); - done(); - }); - - jasmine.Ajax.requests.mostRecent().respondWith({ - status: 200, - contentType: 'application/json', - responseText: JSON.stringify(fakeTaskList) - }); - }); - it('should return the task list with all tasks filtered without state', (done) => { spyOn(service, 'getTasks').and.returnValue(of(fakeTaskList)); spyOn(service, 'getTotalTasks').and.returnValue(of(fakeTaskList)); diff --git a/lib/process-services/src/lib/task-list/task-list.module.ts b/lib/process-services/src/lib/task-list/task-list.module.ts index 3fb4582edd..da0c8e7fd5 100644 --- a/lib/process-services/src/lib/task-list/task-list.module.ts +++ b/lib/process-services/src/lib/task-list/task-list.module.ts @@ -24,7 +24,7 @@ import { FormsModule, ReactiveFormsModule } from '@angular/forms'; import { MaterialModule } from '../material.module'; import { PeopleModule } from '../people/people.module'; -import { ContentWidgetModule } from '../content-widget/content-widget.module'; +import { ContentWidgetModule } from '../form/widgets/content-widget/content-widget.module'; import { ChecklistComponent } from './components/checklist.component'; import { NoTaskDetailsTemplateDirective } from './components/no-task-detail-template.directive'; diff --git a/lib/process-services/src/public-api.ts b/lib/process-services/src/public-api.ts index 689dbd62ce..4ddfe63f81 100644 --- a/lib/process-services/src/public-api.ts +++ b/lib/process-services/src/public-api.ts @@ -21,7 +21,6 @@ export * from './lib/app-list/index'; export * from './lib/attachment/index'; export * from './lib/process-comments/index'; export * from './lib/people/index'; -export * from './lib/content-widget/index'; export * from './lib/form/index'; export * from './lib/task-comments/index'; export * from './lib/pipes/process-name.pipe'; diff --git a/lib/testing/src/lib/protractor/core/pages/form/form.page.ts b/lib/testing/src/lib/protractor/core/pages/form/form.page.ts index 99b045060e..3d9c217c41 100644 --- a/lib/testing/src/lib/protractor/core/pages/form/form.page.ts +++ b/lib/testing/src/lib/protractor/core/pages/form/form.page.ts @@ -47,7 +47,7 @@ export class FormPage { } async isSaveButtonDisabled(): Promise { - const saveButtonDisabled = $('.adf-form-mat-card-actions [disabled]'); + const saveButtonDisabled = $('#adf-form-save[disabled]'); try { await saveButtonDisabled.isDisplayed(); return true;