mirror of
https://github.com/Alfresco/alfresco-ng2-components.git
synced 2026-09-09 18:03:21 +00:00
AAE-38328 Support screens on start process event (#11261)
* AAE-38328 Start event supports using IDP dedicated screens * Added task type resolver * update tests * clean * update * add units * cr * update * update * cr
This commit is contained in:
+10
@@ -109,6 +109,16 @@
|
|||||||
<ng-template [ngTemplateOutlet]="taskFormCloudButtons" />
|
<ng-template [ngTemplateOutlet]="taskFormCloudButtons" />
|
||||||
</adf-cloud-form-custom-outcomes>
|
</adf-cloud-form-custom-outcomes>
|
||||||
</adf-cloud-form>
|
</adf-cloud-form>
|
||||||
|
} @else if (hasScreen) {
|
||||||
|
<adf-cloud-start-process-screen-cloud
|
||||||
|
[screenId]="processDefinitionCurrent.formKey"
|
||||||
|
(screenStartProcessPayloadChange)="onScreenStartProcessPayloadChange($event)"
|
||||||
|
(disableStartProcessButton)="onDisableStartProcessButtonForScreen($event)"
|
||||||
|
>
|
||||||
|
<adf-cloud-form-custom-outcomes>
|
||||||
|
<ng-template [ngTemplateOutlet]="taskFormCloudButtons" />
|
||||||
|
</adf-cloud-form-custom-outcomes>
|
||||||
|
</adf-cloud-start-process-screen-cloud>
|
||||||
} @else {
|
} @else {
|
||||||
<ng-template [ngTemplateOutlet]="taskFormCloudButtons" />
|
<ng-template [ngTemplateOutlet]="taskFormCloudButtons" />
|
||||||
}
|
}
|
||||||
|
|||||||
+122
-45
@@ -15,7 +15,7 @@
|
|||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { SimpleChange } from '@angular/core';
|
import { DebugElement, SimpleChange } from '@angular/core';
|
||||||
import { ComponentFixture, TestBed, fakeAsync, tick } from '@angular/core/testing';
|
import { ComponentFixture, TestBed, fakeAsync, tick } from '@angular/core/testing';
|
||||||
import { FormModel, FormOutcomeEvent, FormOutcomeModel } from '@alfresco/adf-core';
|
import { FormModel, FormOutcomeEvent, FormOutcomeModel } from '@alfresco/adf-core';
|
||||||
import { of, throwError } from 'rxjs';
|
import { of, throwError } from 'rxjs';
|
||||||
@@ -49,6 +49,11 @@ import { MatButtonHarness } from '@angular/material/button/testing';
|
|||||||
import { FormCloudDisplayMode } from '../../../services/form-fields.interfaces';
|
import { FormCloudDisplayMode } from '../../../services/form-fields.interfaces';
|
||||||
import { MatDialogHarness } from '@angular/material/dialog/testing';
|
import { MatDialogHarness } from '@angular/material/dialog/testing';
|
||||||
import { MatDialog } from '@angular/material/dialog';
|
import { MatDialog } from '@angular/material/dialog';
|
||||||
|
import { ReactiveFormsModule } from '@angular/forms';
|
||||||
|
import { StartProcessScreenCloudComponent } from '../../../screen/components/screen-cloud/start-process-event-screen/start-process-screen-cloud.component';
|
||||||
|
import { provideScreen } from '../../../screen/services/provide-screen';
|
||||||
|
import { StartProcessScreenCloud } from '../../../screen/components/screen-cloud/start-process-event-screen/start-process-screen.model';
|
||||||
|
import { MockedTaskScreenCloudComponent } from '../../../testing/start-process-screen-mock.component';
|
||||||
|
|
||||||
describe('StartProcessCloudComponent', () => {
|
describe('StartProcessCloudComponent', () => {
|
||||||
let loader: HarnessLoader;
|
let loader: HarnessLoader;
|
||||||
@@ -57,7 +62,7 @@ describe('StartProcessCloudComponent', () => {
|
|||||||
let fixture: ComponentFixture<StartProcessCloudComponent>;
|
let fixture: ComponentFixture<StartProcessCloudComponent>;
|
||||||
let processService: StartProcessCloudService;
|
let processService: StartProcessCloudService;
|
||||||
let formCloudService: FormCloudService;
|
let formCloudService: FormCloudService;
|
||||||
let getDefinitionsSpy: jasmine.Spy;
|
let getProcessDefinitionsSpy: jasmine.Spy;
|
||||||
let startProcessSpy: jasmine.Spy;
|
let startProcessSpy: jasmine.Spy;
|
||||||
let startProcessWithFormSpy: jasmine.Spy;
|
let startProcessWithFormSpy: jasmine.Spy;
|
||||||
let formDefinitionSpy: jasmine.Spy;
|
let formDefinitionSpy: jasmine.Spy;
|
||||||
@@ -65,6 +70,7 @@ describe('StartProcessCloudComponent', () => {
|
|||||||
let getStartEventConstantSpy: jasmine.Spy;
|
let getStartEventConstantSpy: jasmine.Spy;
|
||||||
|
|
||||||
const firstChange = new SimpleChange(undefined, 'myApp', true);
|
const firstChange = new SimpleChange(undefined, 'myApp', true);
|
||||||
|
const screenId = 'screen-1234-5678-121212-123456';
|
||||||
|
|
||||||
const selectOptionByName = async (name: string) => {
|
const selectOptionByName = async (name: string) => {
|
||||||
const arrowButton = await loader.getHarness(MatButtonHarness.with({ selector: '#adf-select-process-dropdown' }));
|
const arrowButton = await loader.getHarness(MatButtonHarness.with({ selector: '#adf-select-process-dropdown' }));
|
||||||
@@ -84,14 +90,15 @@ describe('StartProcessCloudComponent', () => {
|
|||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
TestBed.configureTestingModule({
|
TestBed.configureTestingModule({
|
||||||
imports: [StartProcessCloudComponent]
|
imports: [StartProcessCloudComponent, ReactiveFormsModule, StartProcessScreenCloudComponent],
|
||||||
|
providers: [provideScreen(screenId, MockedTaskScreenCloudComponent)]
|
||||||
});
|
});
|
||||||
processService = TestBed.inject(StartProcessCloudService);
|
processService = TestBed.inject(StartProcessCloudService);
|
||||||
formCloudService = TestBed.inject(FormCloudService);
|
formCloudService = TestBed.inject(FormCloudService);
|
||||||
fixture = TestBed.createComponent(StartProcessCloudComponent);
|
fixture = TestBed.createComponent(StartProcessCloudComponent);
|
||||||
component = fixture.componentInstance;
|
component = fixture.componentInstance;
|
||||||
|
|
||||||
getDefinitionsSpy = spyOn(processService, 'getProcessDefinitions');
|
getProcessDefinitionsSpy = spyOn(processService, 'getProcessDefinitions');
|
||||||
formDefinitionSpy = spyOn(formCloudService, 'getForm');
|
formDefinitionSpy = spyOn(formCloudService, 'getForm');
|
||||||
spyOn(processService, 'updateProcess').and.returnValue(of());
|
spyOn(processService, 'updateProcess').and.returnValue(of());
|
||||||
startProcessSpy = spyOn(processService, 'startProcess').and.returnValue(of(fakeProcessInstance));
|
startProcessSpy = spyOn(processService, 'startProcess').and.returnValue(of(fakeProcessInstance));
|
||||||
@@ -143,7 +150,7 @@ describe('StartProcessCloudComponent', () => {
|
|||||||
|
|
||||||
component.name = 'My new process';
|
component.name = 'My new process';
|
||||||
component.processDefinitionName = 'processwithoutform2';
|
component.processDefinitionName = 'processwithoutform2';
|
||||||
getDefinitionsSpy.and.returnValue(of(fakeSingleProcessDefinitionWithoutForm(component.processDefinitionName)));
|
getProcessDefinitionsSpy.and.returnValue(of(fakeSingleProcessDefinitionWithoutForm(component.processDefinitionName)));
|
||||||
fixture.detectChanges();
|
fixture.detectChanges();
|
||||||
|
|
||||||
const change = new SimpleChange(null, 'MyApp', true);
|
const change = new SimpleChange(null, 'MyApp', true);
|
||||||
@@ -162,7 +169,7 @@ describe('StartProcessCloudComponent', () => {
|
|||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
component.name = 'My formless new process';
|
component.name = 'My formless new process';
|
||||||
component.appName = 'myApp';
|
component.appName = 'myApp';
|
||||||
getDefinitionsSpy.and.returnValue(of(fakeProcessDefinitions));
|
getProcessDefinitionsSpy.and.returnValue(of(fakeProcessDefinitions));
|
||||||
fixture.detectChanges();
|
fixture.detectChanges();
|
||||||
const change = new SimpleChange(null, 'MyApp', true);
|
const change = new SimpleChange(null, 'MyApp', true);
|
||||||
component.ngOnChanges({ appName: change });
|
component.ngOnChanges({ appName: change });
|
||||||
@@ -172,7 +179,7 @@ describe('StartProcessCloudComponent', () => {
|
|||||||
it('should be able to start a process with a valid process name and process definition', fakeAsync(() => {
|
it('should be able to start a process with a valid process name and process definition', fakeAsync(() => {
|
||||||
component.name = 'My new process';
|
component.name = 'My new process';
|
||||||
component.processDefinitionName = 'processwithoutform2';
|
component.processDefinitionName = 'processwithoutform2';
|
||||||
getDefinitionsSpy.and.returnValue(of(fakeSingleProcessDefinitionWithoutForm(component.processDefinitionName)));
|
getProcessDefinitionsSpy.and.returnValue(of(fakeSingleProcessDefinitionWithoutForm(component.processDefinitionName)));
|
||||||
fixture.detectChanges();
|
fixture.detectChanges();
|
||||||
|
|
||||||
const change = new SimpleChange(null, 'MyApp', true);
|
const change = new SimpleChange(null, 'MyApp', true);
|
||||||
@@ -187,7 +194,7 @@ describe('StartProcessCloudComponent', () => {
|
|||||||
}));
|
}));
|
||||||
|
|
||||||
it('should create a process instance if the selection is valid', async () => {
|
it('should create a process instance if the selection is valid', async () => {
|
||||||
getDefinitionsSpy = getDefinitionsSpy.and.returnValue(of(fakeProcessDefinitions));
|
getProcessDefinitionsSpy = getProcessDefinitionsSpy.and.returnValue(of(fakeProcessDefinitions));
|
||||||
component.name = 'My new process';
|
component.name = 'My new process';
|
||||||
component.processDefinitionName = 'process';
|
component.processDefinitionName = 'process';
|
||||||
await selectOptionByName('processwithoutform2');
|
await selectOptionByName('processwithoutform2');
|
||||||
@@ -276,11 +283,81 @@ describe('StartProcessCloudComponent', () => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe('screen on start process event', () => {
|
||||||
|
let screenDebugComponent: DebugElement;
|
||||||
|
let screenComponent: StartProcessScreenCloud;
|
||||||
|
|
||||||
|
beforeEach(async () => {
|
||||||
|
fixture.detectChanges();
|
||||||
|
|
||||||
|
const processDefinitionWithScreen = fakeSingleProcessDefinition('processWithScreen', { formKey: screenId });
|
||||||
|
const someOtherProcess = fakeSingleProcessDefinition('otherProcess');
|
||||||
|
getProcessDefinitionsSpy.and.returnValue(of([...processDefinitionWithScreen, ...someOtherProcess]));
|
||||||
|
component.processDefinitionName = 'processWithScreen';
|
||||||
|
|
||||||
|
component.ngOnChanges({ appName: new SimpleChange(null, 'myAppName', true) });
|
||||||
|
fixture.detectChanges();
|
||||||
|
|
||||||
|
screenDebugComponent = fixture.debugElement.query(By.directive(MockedTaskScreenCloudComponent));
|
||||||
|
screenComponent = screenDebugComponent.componentInstance;
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should show screen', () => {
|
||||||
|
expect(screenComponent).toBeDefined();
|
||||||
|
|
||||||
|
const contentElement = screenDebugComponent.nativeElement.querySelector('div');
|
||||||
|
expect(contentElement.textContent).toBe('Mock Screen Component');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should toggle default process buttons', () => {
|
||||||
|
screenComponent.defaultStartProcessButtonsConfigurationChange.emit({ show: false, disable: false });
|
||||||
|
fixture.detectChanges();
|
||||||
|
|
||||||
|
let startButton = fixture.nativeElement.querySelector('#button-start');
|
||||||
|
let cancelButton = fixture.nativeElement.querySelector('#cancel_process');
|
||||||
|
expect(startButton).toBeNull();
|
||||||
|
expect(cancelButton).toBeNull();
|
||||||
|
|
||||||
|
screenComponent.defaultStartProcessButtonsConfigurationChange.emit({ show: true, disable: false });
|
||||||
|
fixture.detectChanges();
|
||||||
|
|
||||||
|
startButton = fixture.nativeElement.querySelector('#button-start');
|
||||||
|
cancelButton = fixture.nativeElement.querySelector('#cancel_process');
|
||||||
|
expect(startButton).not.toBeNull();
|
||||||
|
expect(cancelButton).not.toBeNull();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should toggle disable start process button', () => {
|
||||||
|
screenComponent.defaultStartProcessButtonsConfigurationChange.emit({ show: true, disable: true });
|
||||||
|
fixture.detectChanges();
|
||||||
|
const startButton = fixture.nativeElement.querySelector('#button-start');
|
||||||
|
|
||||||
|
expect(startButton.disabled).toBe(true);
|
||||||
|
|
||||||
|
screenComponent.defaultStartProcessButtonsConfigurationChange.emit({ show: true, disable: false });
|
||||||
|
fixture.detectChanges();
|
||||||
|
|
||||||
|
expect(startButton.disabled).toBe(false);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should set payload for screen', () => {
|
||||||
|
const screenPayload = 'My payload';
|
||||||
|
screenComponent.defaultStartProcessButtonsConfigurationChange.emit({ show: true, disable: false });
|
||||||
|
screenComponent.startProcessPayloadChanged.emit(screenPayload);
|
||||||
|
fixture.detectChanges();
|
||||||
|
|
||||||
|
const startButton = fixture.debugElement.query(By.css('#button-start'));
|
||||||
|
startButton.triggerEventHandler('click', null);
|
||||||
|
|
||||||
|
expect(startProcessWithFormSpy).toHaveBeenCalledWith('myAppName', screenId, 0, jasmine.objectContaining({ values: screenPayload }));
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
describe('start a process with start form', () => {
|
describe('start a process with start form', () => {
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
component.name = 'My new process with form';
|
component.name = 'My new process with form';
|
||||||
component.appName = 'startformwithoutupload';
|
component.appName = 'startformwithoutupload';
|
||||||
getDefinitionsSpy.and.returnValue(of(fakeProcessDefinitions));
|
getProcessDefinitionsSpy.and.returnValue(of(fakeProcessDefinitions));
|
||||||
fixture.detectChanges();
|
fixture.detectChanges();
|
||||||
const change = new SimpleChange(null, 'startformwithoutupload', true);
|
const change = new SimpleChange(null, 'startformwithoutupload', true);
|
||||||
component.ngOnChanges({ appName: change });
|
component.ngOnChanges({ appName: change });
|
||||||
@@ -315,7 +392,7 @@ describe('StartProcessCloudComponent', () => {
|
|||||||
|
|
||||||
it('should be able to start a process with a valid form', async () => {
|
it('should be able to start a process with a valid form', async () => {
|
||||||
formDefinitionSpy.and.returnValue(of(fakeStartForm));
|
formDefinitionSpy.and.returnValue(of(fakeStartForm));
|
||||||
getDefinitionsSpy.and.returnValue(of(fakeSingleProcessDefinition('processwithform')));
|
getProcessDefinitionsSpy.and.returnValue(of(fakeSingleProcessDefinition('processwithform')));
|
||||||
typeValueInto('[data-automation-id="adf-inplace-input"]', 'My new process with form');
|
typeValueInto('[data-automation-id="adf-inplace-input"]', 'My new process with form');
|
||||||
typeValueInto('#processDefinitionName', 'processwithform');
|
typeValueInto('#processDefinitionName', 'processwithform');
|
||||||
fixture.detectChanges();
|
fixture.detectChanges();
|
||||||
@@ -353,7 +430,7 @@ describe('StartProcessCloudComponent', () => {
|
|||||||
(fakeStartFormClone.formRepresentation as any).displayMode = FormCloudDisplayMode.fullScreen;
|
(fakeStartFormClone.formRepresentation as any).displayMode = FormCloudDisplayMode.fullScreen;
|
||||||
|
|
||||||
formDefinitionSpy.and.returnValue(of(fakeStartFormClone));
|
formDefinitionSpy.and.returnValue(of(fakeStartFormClone));
|
||||||
getDefinitionsSpy.and.returnValue(of(fakeSingleProcessDefinition('processwithform')));
|
getProcessDefinitionsSpy.and.returnValue(of(fakeSingleProcessDefinition('processwithform')));
|
||||||
typeValueInto('[data-automation-id="adf-inplace-input"]', 'My new process with form');
|
typeValueInto('[data-automation-id="adf-inplace-input"]', 'My new process with form');
|
||||||
typeValueInto('#processDefinitionName', 'processwithform');
|
typeValueInto('#processDefinitionName', 'processwithform');
|
||||||
fixture.detectChanges();
|
fixture.detectChanges();
|
||||||
@@ -371,7 +448,7 @@ describe('StartProcessCloudComponent', () => {
|
|||||||
|
|
||||||
it('should NOT be able to start a process with a form NOT valid', async () => {
|
it('should NOT be able to start a process with a form NOT valid', async () => {
|
||||||
formDefinitionSpy.and.returnValue(of(fakeStartFormNotValid));
|
formDefinitionSpy.and.returnValue(of(fakeStartFormNotValid));
|
||||||
getDefinitionsSpy.and.returnValue(of(fakeSingleProcessDefinition('processwithform')));
|
getProcessDefinitionsSpy.and.returnValue(of(fakeSingleProcessDefinition('processwithform')));
|
||||||
typeValueInto('[data-automation-id="adf-inplace-input"]', 'My new process with form');
|
typeValueInto('[data-automation-id="adf-inplace-input"]', 'My new process with form');
|
||||||
typeValueInto('#processDefinitionName', 'processwithform');
|
typeValueInto('#processDefinitionName', 'processwithform');
|
||||||
fixture.detectChanges();
|
fixture.detectChanges();
|
||||||
@@ -388,7 +465,7 @@ describe('StartProcessCloudComponent', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('should be able to start a process with a prefilled valid form', async () => {
|
it('should be able to start a process with a prefilled valid form', async () => {
|
||||||
getDefinitionsSpy.and.returnValue(of(fakeSingleProcessDefinition('processwithform')));
|
getProcessDefinitionsSpy.and.returnValue(of(fakeSingleProcessDefinition('processwithform')));
|
||||||
formDefinitionSpy.and.returnValue(of(fakeStartForm));
|
formDefinitionSpy.and.returnValue(of(fakeStartForm));
|
||||||
typeValueInto('[data-automation-id="adf-inplace-input"]', 'My new process with form');
|
typeValueInto('[data-automation-id="adf-inplace-input"]', 'My new process with form');
|
||||||
typeValueInto('#processDefinitionName', 'processwithform');
|
typeValueInto('#processDefinitionName', 'processwithform');
|
||||||
@@ -409,7 +486,7 @@ describe('StartProcessCloudComponent', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('should NOT be able to start a process with a prefilled NOT valid form', async () => {
|
it('should NOT be able to start a process with a prefilled NOT valid form', async () => {
|
||||||
getDefinitionsSpy.and.returnValue(of(fakeSingleProcessDefinition('processwithform')));
|
getProcessDefinitionsSpy.and.returnValue(of(fakeSingleProcessDefinition('processwithform')));
|
||||||
formDefinitionSpy.and.returnValue(of(fakeStartFormNotValid));
|
formDefinitionSpy.and.returnValue(of(fakeStartFormNotValid));
|
||||||
typeValueInto('[data-automation-id="adf-inplace-input"]', 'My new process with form');
|
typeValueInto('[data-automation-id="adf-inplace-input"]', 'My new process with form');
|
||||||
typeValueInto('#processDefinitionName', 'processwithform');
|
typeValueInto('#processDefinitionName', 'processwithform');
|
||||||
@@ -431,7 +508,7 @@ describe('StartProcessCloudComponent', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('should display enabled start process button if the selection is valid', async () => {
|
it('should display enabled start process button if the selection is valid', async () => {
|
||||||
getDefinitionsSpy.and.returnValue(of(fakeSingleProcessDefinition('processwithoutform2')));
|
getProcessDefinitionsSpy.and.returnValue(of(fakeSingleProcessDefinition('processwithoutform2')));
|
||||||
formDefinitionSpy.and.returnValue(of(fakeStartForm));
|
formDefinitionSpy.and.returnValue(of(fakeStartForm));
|
||||||
typeValueInto('[data-automation-id="adf-inplace-input"]', 'My new process with form');
|
typeValueInto('[data-automation-id="adf-inplace-input"]', 'My new process with form');
|
||||||
typeValueInto('#processDefinitionName', 'processwithoutform2');
|
typeValueInto('#processDefinitionName', 'processwithoutform2');
|
||||||
@@ -444,7 +521,7 @@ describe('StartProcessCloudComponent', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('should have start button enabled when default values are set', async () => {
|
it('should have start button enabled when default values are set', async () => {
|
||||||
getDefinitionsSpy.and.returnValue(of(fakeSingleProcessDefinition('processwithoutform2')));
|
getProcessDefinitionsSpy.and.returnValue(of(fakeSingleProcessDefinition('processwithoutform2')));
|
||||||
formDefinitionSpy.and.returnValue(of(fakeStartForm));
|
formDefinitionSpy.and.returnValue(of(fakeStartForm));
|
||||||
|
|
||||||
const change = new SimpleChange(null, 'MyApp', true);
|
const change = new SimpleChange(null, 'MyApp', true);
|
||||||
@@ -461,7 +538,7 @@ describe('StartProcessCloudComponent', () => {
|
|||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
component.name = 'My new process';
|
component.name = 'My new process';
|
||||||
component.appName = 'myApp';
|
component.appName = 'myApp';
|
||||||
getDefinitionsSpy.and.returnValue(of(fakeProcessDefinitions));
|
getProcessDefinitionsSpy.and.returnValue(of(fakeProcessDefinitions));
|
||||||
fixture.detectChanges();
|
fixture.detectChanges();
|
||||||
const change = new SimpleChange(null, 'MyApp', true);
|
const change = new SimpleChange(null, 'MyApp', true);
|
||||||
component.ngOnChanges({ appName: change });
|
component.ngOnChanges({ appName: change });
|
||||||
@@ -471,7 +548,7 @@ describe('StartProcessCloudComponent', () => {
|
|||||||
it('should call service to fetch process definitions with appId', async () => {
|
it('should call service to fetch process definitions with appId', async () => {
|
||||||
await fixture.whenStable();
|
await fixture.whenStable();
|
||||||
|
|
||||||
expect(getDefinitionsSpy).toHaveBeenCalledWith('MyApp');
|
expect(getProcessDefinitionsSpy).toHaveBeenCalledWith('MyApp');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should display the correct number of processes in the select list', async () => {
|
it('should display the correct number of processes in the select list', async () => {
|
||||||
@@ -497,7 +574,7 @@ describe('StartProcessCloudComponent', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('should indicate an error to the user if process defs cannot be loaded', async () => {
|
it('should indicate an error to the user if process defs cannot be loaded', async () => {
|
||||||
getDefinitionsSpy.and.returnValue(throwError({}));
|
getProcessDefinitionsSpy.and.returnValue(throwError({}));
|
||||||
const change = new SimpleChange('myApp', 'myApp1', true);
|
const change = new SimpleChange('myApp', 'myApp1', true);
|
||||||
component.ngOnChanges({ appName: change });
|
component.ngOnChanges({ appName: change });
|
||||||
|
|
||||||
@@ -509,7 +586,7 @@ describe('StartProcessCloudComponent', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('should show no process available message when no process definition is loaded', async () => {
|
it('should show no process available message when no process definition is loaded', async () => {
|
||||||
getDefinitionsSpy.and.returnValue(of([]));
|
getProcessDefinitionsSpy.and.returnValue(of([]));
|
||||||
const change = new SimpleChange('myApp', 'myApp1', true);
|
const change = new SimpleChange('myApp', 'myApp1', true);
|
||||||
component.ngOnChanges({ appName: change });
|
component.ngOnChanges({ appName: change });
|
||||||
|
|
||||||
@@ -522,7 +599,7 @@ describe('StartProcessCloudComponent', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('should select automatically the processDefinition if the app contain only one', async () => {
|
it('should select automatically the processDefinition if the app contain only one', async () => {
|
||||||
getDefinitionsSpy.and.returnValue(of([fakeProcessDefinitions[0]]));
|
getProcessDefinitionsSpy.and.returnValue(of([fakeProcessDefinitions[0]]));
|
||||||
const change = new SimpleChange('myApp', 'myApp1', true);
|
const change = new SimpleChange('myApp', 'myApp1', true);
|
||||||
component.ngOnChanges({ appName: change });
|
component.ngOnChanges({ appName: change });
|
||||||
|
|
||||||
@@ -533,7 +610,7 @@ describe('StartProcessCloudComponent', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('should select automatically the form when processDefinition is selected as default', async () => {
|
it('should select automatically the form when processDefinition is selected as default', async () => {
|
||||||
getDefinitionsSpy.and.returnValue(of([fakeProcessDefinitions[2]]));
|
getProcessDefinitionsSpy.and.returnValue(of([fakeProcessDefinitions[2]]));
|
||||||
formDefinitionSpy.and.returnValue(of(fakeStartForm));
|
formDefinitionSpy.and.returnValue(of(fakeStartForm));
|
||||||
const change = new SimpleChange('myApp', 'myApp1', true);
|
const change = new SimpleChange('myApp', 'myApp1', true);
|
||||||
component.ngOnChanges({ appName: change });
|
component.ngOnChanges({ appName: change });
|
||||||
@@ -553,7 +630,7 @@ describe('StartProcessCloudComponent', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('should not select automatically any processDefinition if the app contain multiple process and does not have any processDefinition as input', async () => {
|
it('should not select automatically any processDefinition if the app contain multiple process and does not have any processDefinition as input', async () => {
|
||||||
getDefinitionsSpy.and.returnValue(of(fakeProcessDefinitions));
|
getProcessDefinitionsSpy.and.returnValue(of(fakeProcessDefinitions));
|
||||||
component.appName = 'myApp';
|
component.appName = 'myApp';
|
||||||
component.ngOnChanges({});
|
component.ngOnChanges({});
|
||||||
|
|
||||||
@@ -564,7 +641,7 @@ describe('StartProcessCloudComponent', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('should select the right process when the processKey begins with the name', async () => {
|
it('should select the right process when the processKey begins with the name', async () => {
|
||||||
getDefinitionsSpy.and.returnValue(of(fakeProcessDefinitions));
|
getProcessDefinitionsSpy.and.returnValue(of(fakeProcessDefinitions));
|
||||||
formDefinitionSpy.and.returnValue(of(fakeStartForm));
|
formDefinitionSpy.and.returnValue(of(fakeStartForm));
|
||||||
component.name = 'My new process';
|
component.name = 'My new process';
|
||||||
component.processDefinitionName = 'process';
|
component.processDefinitionName = 'process';
|
||||||
@@ -579,7 +656,7 @@ describe('StartProcessCloudComponent', () => {
|
|||||||
describe('dropdown', () => {
|
describe('dropdown', () => {
|
||||||
it('should hide the process dropdown button if showSelectProcessDropdown is false', async () => {
|
it('should hide the process dropdown button if showSelectProcessDropdown is false', async () => {
|
||||||
fixture.detectChanges();
|
fixture.detectChanges();
|
||||||
getDefinitionsSpy.and.returnValue(of(fakeProcessDefinitions));
|
getProcessDefinitionsSpy.and.returnValue(of(fakeProcessDefinitions));
|
||||||
component.appName = 'myApp';
|
component.appName = 'myApp';
|
||||||
component.showSelectProcessDropdown = false;
|
component.showSelectProcessDropdown = false;
|
||||||
component.ngOnChanges({});
|
component.ngOnChanges({});
|
||||||
@@ -593,7 +670,7 @@ describe('StartProcessCloudComponent', () => {
|
|||||||
|
|
||||||
it('should show the process dropdown button if showSelectProcessDropdown is false', async () => {
|
it('should show the process dropdown button if showSelectProcessDropdown is false', async () => {
|
||||||
fixture.detectChanges();
|
fixture.detectChanges();
|
||||||
getDefinitionsSpy.and.returnValue(of(fakeProcessDefinitions));
|
getProcessDefinitionsSpy.and.returnValue(of(fakeProcessDefinitions));
|
||||||
component.appName = 'myApp';
|
component.appName = 'myApp';
|
||||||
component.processDefinitionName = 'NewProcess 2';
|
component.processDefinitionName = 'NewProcess 2';
|
||||||
component.showSelectProcessDropdown = true;
|
component.showSelectProcessDropdown = true;
|
||||||
@@ -608,7 +685,7 @@ describe('StartProcessCloudComponent', () => {
|
|||||||
|
|
||||||
it('should show the process dropdown button by default', async () => {
|
it('should show the process dropdown button by default', async () => {
|
||||||
fixture.detectChanges();
|
fixture.detectChanges();
|
||||||
getDefinitionsSpy.and.returnValue(of(fakeProcessDefinitions));
|
getProcessDefinitionsSpy.and.returnValue(of(fakeProcessDefinitions));
|
||||||
component.appName = 'myApp';
|
component.appName = 'myApp';
|
||||||
component.processDefinitionName = 'NewProcess 2';
|
component.processDefinitionName = 'NewProcess 2';
|
||||||
component.ngOnChanges({});
|
component.ngOnChanges({});
|
||||||
@@ -631,18 +708,18 @@ describe('StartProcessCloudComponent', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('should reload processes when appName input changed', async () => {
|
it('should reload processes when appName input changed', async () => {
|
||||||
getDefinitionsSpy.and.returnValue(of(fakeProcessDefinitions));
|
getProcessDefinitionsSpy.and.returnValue(of(fakeProcessDefinitions));
|
||||||
component.ngOnChanges({ appName: firstChange });
|
component.ngOnChanges({ appName: firstChange });
|
||||||
component.ngOnChanges({ appName: change });
|
component.ngOnChanges({ appName: change });
|
||||||
|
|
||||||
fixture.detectChanges();
|
fixture.detectChanges();
|
||||||
await fixture.whenStable();
|
await fixture.whenStable();
|
||||||
|
|
||||||
expect(getDefinitionsSpy).toHaveBeenCalledWith('myApp1');
|
expect(getProcessDefinitionsSpy).toHaveBeenCalledWith('myApp1');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should reload processes ONLY when appName input changed', async () => {
|
it('should reload processes ONLY when appName input changed', async () => {
|
||||||
getDefinitionsSpy.and.returnValue(of(fakeProcessDefinitions));
|
getProcessDefinitionsSpy.and.returnValue(of(fakeProcessDefinitions));
|
||||||
component.ngOnChanges({ appName: firstChange });
|
component.ngOnChanges({ appName: firstChange });
|
||||||
fixture.detectChanges();
|
fixture.detectChanges();
|
||||||
|
|
||||||
@@ -650,19 +727,19 @@ describe('StartProcessCloudComponent', () => {
|
|||||||
fixture.detectChanges();
|
fixture.detectChanges();
|
||||||
await fixture.whenStable();
|
await fixture.whenStable();
|
||||||
|
|
||||||
expect(getDefinitionsSpy).toHaveBeenCalledTimes(1);
|
expect(getProcessDefinitionsSpy).toHaveBeenCalledTimes(1);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should get current processDef', () => {
|
it('should get current processDef', () => {
|
||||||
getDefinitionsSpy.and.returnValue(of(fakeProcessDefinitions));
|
getProcessDefinitionsSpy.and.returnValue(of(fakeProcessDefinitions));
|
||||||
component.ngOnChanges({ appName: change });
|
component.ngOnChanges({ appName: change });
|
||||||
fixture.detectChanges();
|
fixture.detectChanges();
|
||||||
expect(getDefinitionsSpy).toHaveBeenCalled();
|
expect(getProcessDefinitionsSpy).toHaveBeenCalled();
|
||||||
expect(component.processDefinitionList).toBe(fakeProcessDefinitions);
|
expect(component.processDefinitionList).toBe(fakeProcessDefinitions);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should display the matching results in the dropdown as the user types down', async () => {
|
it('should display the matching results in the dropdown as the user types down', async () => {
|
||||||
getDefinitionsSpy.and.returnValue(of(fakeProcessDefinitions));
|
getProcessDefinitionsSpy.and.returnValue(of(fakeProcessDefinitions));
|
||||||
component.ngOnChanges({ appName: change });
|
component.ngOnChanges({ appName: change });
|
||||||
fixture.detectChanges();
|
fixture.detectChanges();
|
||||||
|
|
||||||
@@ -680,7 +757,7 @@ describe('StartProcessCloudComponent', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('should display the process definion field as empty if are more than one process definition in the list', async () => {
|
it('should display the process definion field as empty if are more than one process definition in the list', async () => {
|
||||||
getDefinitionsSpy.and.returnValue(of(fakeProcessDefinitions));
|
getProcessDefinitionsSpy.and.returnValue(of(fakeProcessDefinitions));
|
||||||
component.ngOnChanges({ appName: change });
|
component.ngOnChanges({ appName: change });
|
||||||
|
|
||||||
fixture.detectChanges();
|
fixture.detectChanges();
|
||||||
@@ -696,7 +773,7 @@ describe('StartProcessCloudComponent', () => {
|
|||||||
fixture.detectChanges();
|
fixture.detectChanges();
|
||||||
component.name = 'NewProcess 1';
|
component.name = 'NewProcess 1';
|
||||||
component.appName = 'myApp';
|
component.appName = 'myApp';
|
||||||
getDefinitionsSpy.and.returnValue(of(fakeProcessDefinitions));
|
getProcessDefinitionsSpy.and.returnValue(of(fakeProcessDefinitions));
|
||||||
fixture.detectChanges();
|
fixture.detectChanges();
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -836,7 +913,7 @@ describe('StartProcessCloudComponent', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('should call service with the correct parameters when variables are undefined and formCloud is defined', async () => {
|
it('should call service with the correct parameters when variables are undefined and formCloud is defined', async () => {
|
||||||
getDefinitionsSpy.and.returnValue(of([fakeProcessDefinitions[2]]));
|
getProcessDefinitionsSpy.and.returnValue(of([fakeProcessDefinitions[2]]));
|
||||||
formDefinitionSpy.and.returnValue(of(fakeStartForm));
|
formDefinitionSpy.and.returnValue(of(fakeStartForm));
|
||||||
const change = new SimpleChange('myApp', 'myApp1', true);
|
const change = new SimpleChange('myApp', 'myApp1', true);
|
||||||
component.ngOnChanges({ appName: change });
|
component.ngOnChanges({ appName: change });
|
||||||
@@ -894,7 +971,7 @@ describe('StartProcessCloudComponent', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('should indicate an error to the user if process cannot be started', async () => {
|
it('should indicate an error to the user if process cannot be started', async () => {
|
||||||
getDefinitionsSpy.and.returnValue(of(fakeProcessDefinitions));
|
getProcessDefinitionsSpy.and.returnValue(of(fakeProcessDefinitions));
|
||||||
const change = new SimpleChange('myApp', 'myApp1', true);
|
const change = new SimpleChange('myApp', 'myApp1', true);
|
||||||
component.ngOnChanges({ appName: change });
|
component.ngOnChanges({ appName: change });
|
||||||
const error = {
|
const error = {
|
||||||
@@ -915,7 +992,7 @@ describe('StartProcessCloudComponent', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('should use fallback error message when no specific error message is provided', async () => {
|
it('should use fallback error message when no specific error message is provided', async () => {
|
||||||
getDefinitionsSpy.and.returnValue(of(fakeProcessDefinitions));
|
getProcessDefinitionsSpy.and.returnValue(of(fakeProcessDefinitions));
|
||||||
const change = new SimpleChange('myApp', 'myApp1', true);
|
const change = new SimpleChange('myApp', 'myApp1', true);
|
||||||
component.ngOnChanges({ appName: change });
|
component.ngOnChanges({ appName: change });
|
||||||
const errorWithoutMessage = {
|
const errorWithoutMessage = {
|
||||||
@@ -1040,7 +1117,7 @@ describe('StartProcessCloudComponent', () => {
|
|||||||
fixture.detectChanges();
|
fixture.detectChanges();
|
||||||
let noProcessElement = fixture.nativeElement.querySelector('#no-process-message');
|
let noProcessElement = fixture.nativeElement.querySelector('#no-process-message');
|
||||||
expect(noProcessElement).toBeNull();
|
expect(noProcessElement).toBeNull();
|
||||||
getDefinitionsSpy.and.returnValue(of([]));
|
getProcessDefinitionsSpy.and.returnValue(of([]));
|
||||||
|
|
||||||
component.loadProcessDefinitions();
|
component.loadProcessDefinitions();
|
||||||
fixture.detectChanges();
|
fixture.detectChanges();
|
||||||
@@ -1051,7 +1128,7 @@ describe('StartProcessCloudComponent', () => {
|
|||||||
it('should set the process name using the processName cloud pipe when a process definition gets selected', async () => {
|
it('should set the process name using the processName cloud pipe when a process definition gets selected', async () => {
|
||||||
const getDefaultProcessNameSpy = spyOn(component, 'getDefaultProcessName').and.returnValue('fake-transformed-name');
|
const getDefaultProcessNameSpy = spyOn(component, 'getDefaultProcessName').and.returnValue('fake-transformed-name');
|
||||||
const expectedProcessInstanceDetails: ProcessInstanceCloud = { processDefinitionName: fakeProcessDefinitions[0].name };
|
const expectedProcessInstanceDetails: ProcessInstanceCloud = { processDefinitionName: fakeProcessDefinitions[0].name };
|
||||||
getDefinitionsSpy.and.returnValue(of([fakeProcessDefinitions[0]]));
|
getProcessDefinitionsSpy.and.returnValue(of([fakeProcessDefinitions[0]]));
|
||||||
formDefinitionSpy.and.stub();
|
formDefinitionSpy.and.stub();
|
||||||
|
|
||||||
component.appName = 'myApp';
|
component.appName = 'myApp';
|
||||||
@@ -1085,7 +1162,7 @@ describe('StartProcessCloudComponent', () => {
|
|||||||
done();
|
done();
|
||||||
});
|
});
|
||||||
|
|
||||||
getDefinitionsSpy.and.returnValue(of(definitions));
|
getProcessDefinitionsSpy.and.returnValue(of(definitions));
|
||||||
|
|
||||||
const fakeTransformedName = 'fake-transformed-name';
|
const fakeTransformedName = 'fake-transformed-name';
|
||||||
spyOn(component, 'getDefaultProcessName').and.returnValue(fakeTransformedName);
|
spyOn(component, 'getDefaultProcessName').and.returnValue(fakeTransformedName);
|
||||||
@@ -1166,7 +1243,7 @@ describe('StartProcessCloudComponent', () => {
|
|||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
component.name = 'NewProcess 1';
|
component.name = 'NewProcess 1';
|
||||||
component.appName = 'myApp';
|
component.appName = 'myApp';
|
||||||
getDefinitionsSpy.and.returnValue(of(fakeProcessDefinitions));
|
getProcessDefinitionsSpy.and.returnValue(of(fakeProcessDefinitions));
|
||||||
component.ngOnChanges({ appName: firstChange });
|
component.ngOnChanges({ appName: firstChange });
|
||||||
component.processDefinitionList = fakeProcessDefinitions;
|
component.processDefinitionList = fakeProcessDefinitions;
|
||||||
component.processDefinitionName = fakeProcessDefinitions[0].name;
|
component.processDefinitionName = fakeProcessDefinitions[0].name;
|
||||||
@@ -1212,7 +1289,7 @@ describe('StartProcessCloudComponent', () => {
|
|||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
component.name = 'NewProcess 1';
|
component.name = 'NewProcess 1';
|
||||||
component.appName = 'myApp';
|
component.appName = 'myApp';
|
||||||
getDefinitionsSpy.and.returnValue(of(fakeProcessDefinitions));
|
getProcessDefinitionsSpy.and.returnValue(of(fakeProcessDefinitions));
|
||||||
component.ngOnChanges({ appName: firstChange });
|
component.ngOnChanges({ appName: firstChange });
|
||||||
fixture.detectChanges();
|
fixture.detectChanges();
|
||||||
});
|
});
|
||||||
@@ -1235,7 +1312,7 @@ describe('StartProcessCloudComponent', () => {
|
|||||||
const customOutcomeSelectedSpy = spyOn(component.customOutcomeSelected, 'emit');
|
const customOutcomeSelectedSpy = spyOn(component.customOutcomeSelected, 'emit');
|
||||||
const successSpy = spyOn(component.success, 'emit');
|
const successSpy = spyOn(component.success, 'emit');
|
||||||
|
|
||||||
getDefinitionsSpy.and.returnValue(of(fakeProcessDefinitions));
|
getProcessDefinitionsSpy.and.returnValue(of(fakeProcessDefinitions));
|
||||||
formDefinitionSpy.and.returnValue(of(fakeFormModelJson));
|
formDefinitionSpy.and.returnValue(of(fakeFormModelJson));
|
||||||
startProcessWithFormSpy.and.returnValue(of(fakeProcessInstance));
|
startProcessWithFormSpy.and.returnValue(of(fakeProcessInstance));
|
||||||
|
|
||||||
|
|||||||
+56
-24
@@ -63,6 +63,8 @@ import { MatOptionModule } from '@angular/material/core';
|
|||||||
import { FormCloudComponent } from '../../../form/components/form-cloud.component';
|
import { FormCloudComponent } from '../../../form/components/form-cloud.component';
|
||||||
import { FormCustomOutcomesComponent } from '../../../form/components/form-cloud-custom-outcomes.component';
|
import { FormCustomOutcomesComponent } from '../../../form/components/form-cloud-custom-outcomes.component';
|
||||||
import { MatDialog } from '@angular/material/dialog';
|
import { MatDialog } from '@angular/material/dialog';
|
||||||
|
import { StartProcessScreenCloudComponent } from '../../../screen/components/screen-cloud/start-process-event-screen/start-process-screen-cloud.component';
|
||||||
|
import { TaskTypeResolverService } from '../../../services/task-type-resolver/task-type-resolver.service';
|
||||||
|
|
||||||
const MAX_NAME_LENGTH: number = 255;
|
const MAX_NAME_LENGTH: number = 255;
|
||||||
const PROCESS_DEFINITION_DEBOUNCE: number = 300;
|
const PROCESS_DEFINITION_DEBOUNCE: number = 300;
|
||||||
@@ -85,7 +87,8 @@ const PROCESS_DEFINITION_IDENTIFIER_REG_EXP = /%{processdefinition}/i;
|
|||||||
MatAutocompleteModule,
|
MatAutocompleteModule,
|
||||||
ReactiveFormsModule,
|
ReactiveFormsModule,
|
||||||
FormCloudComponent,
|
FormCloudComponent,
|
||||||
FormCustomOutcomesComponent
|
FormCustomOutcomesComponent,
|
||||||
|
StartProcessScreenCloudComponent
|
||||||
],
|
],
|
||||||
providers: [LocalizedDatePipe],
|
providers: [LocalizedDatePipe],
|
||||||
templateUrl: './start-process-cloud.component.html',
|
templateUrl: './start-process-cloud.component.html',
|
||||||
@@ -177,6 +180,7 @@ export class StartProcessCloudComponent implements OnChanges, OnInit {
|
|||||||
isFormCloudLoading = true;
|
isFormCloudLoading = true;
|
||||||
processDefinitionLoaded = false;
|
processDefinitionLoaded = false;
|
||||||
|
|
||||||
|
disableStartProcessForScreen = false;
|
||||||
showStartProcessButton$: Observable<boolean>;
|
showStartProcessButton$: Observable<boolean>;
|
||||||
startProcessButtonLabel: string;
|
startProcessButtonLabel: string;
|
||||||
cancelButtonLabel: string;
|
cancelButtonLabel: string;
|
||||||
@@ -197,6 +201,9 @@ export class StartProcessCloudComponent implements OnChanges, OnInit {
|
|||||||
private readonly displayStartSubject = new BehaviorSubject<string>(null);
|
private readonly displayStartSubject = new BehaviorSubject<string>(null);
|
||||||
private readonly hasVisibleOutcomesSubject = new BehaviorSubject<boolean>(false);
|
private readonly hasVisibleOutcomesSubject = new BehaviorSubject<boolean>(false);
|
||||||
private readonly dialog = inject(MatDialog);
|
private readonly dialog = inject(MatDialog);
|
||||||
|
private readonly taskTypeResolverService = inject(TaskTypeResolverService);
|
||||||
|
|
||||||
|
private screenSubmitPayload: unknown;
|
||||||
|
|
||||||
showSaveButton = false;
|
showSaveButton = false;
|
||||||
showCompleteButton = false;
|
showCompleteButton = false;
|
||||||
@@ -204,13 +211,17 @@ export class StartProcessCloudComponent implements OnChanges, OnInit {
|
|||||||
get isProcessFormValid(): boolean {
|
get isProcessFormValid(): boolean {
|
||||||
if (this.hasForm && this.isFormCloudLoaded) {
|
if (this.hasForm && this.isFormCloudLoaded) {
|
||||||
return (this.formCloud ? !Object.keys(this.formCloud.values).length : false) || this.formCloud?.isValid || this.isProcessStarting;
|
return (this.formCloud ? !Object.keys(this.formCloud.values).length : false) || this.formCloud?.isValid || this.isProcessStarting;
|
||||||
|
} else if (this.hasScreen) {
|
||||||
|
return true;
|
||||||
} else {
|
} else {
|
||||||
return this.processForm.valid || this.isProcessStarting;
|
return this.processForm.valid || this.isProcessStarting;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
get disableStartButton(): boolean {
|
get disableStartButton(): boolean {
|
||||||
return !this.appName || !this.processDefinition.valid || this.isProcessStarting || this.isFormCloudLoading;
|
return (
|
||||||
|
!this.appName || !this.processDefinition.valid || this.isProcessStarting || this.isFormCloudLoading || this.disableStartProcessForScreen
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
get isProcessDefinitionsEmpty(): boolean {
|
get isProcessDefinitionsEmpty(): boolean {
|
||||||
@@ -226,7 +237,15 @@ export class StartProcessCloudComponent implements OnChanges, OnInit {
|
|||||||
}
|
}
|
||||||
|
|
||||||
get hasForm(): boolean {
|
get hasForm(): boolean {
|
||||||
return !!this.processDefinitionCurrent?.formKey;
|
return this.taskTypeResolverService.isFormTask(this.processDefinitionCurrent?.formKey);
|
||||||
|
}
|
||||||
|
|
||||||
|
get hasScreen(): boolean {
|
||||||
|
return this.taskTypeResolverService.isScreenTask(this.processDefinitionCurrent?.formKey);
|
||||||
|
}
|
||||||
|
|
||||||
|
get screenId(): string {
|
||||||
|
return this.taskTypeResolverService.getScreenId(this.processDefinitionCurrent?.formKey);
|
||||||
}
|
}
|
||||||
|
|
||||||
get defaultStartProcessButtonLabel(): string {
|
get defaultStartProcessButtonLabel(): string {
|
||||||
@@ -294,6 +313,14 @@ export class StartProcessCloudComponent implements OnChanges, OnInit {
|
|||||||
this.hasVisibleOutcomesSubject.next(anyOutcomeVisible);
|
this.hasVisibleOutcomesSubject.next(anyOutcomeVisible);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
onDisableStartProcessButtonForScreen(disable: boolean): void {
|
||||||
|
this.disableStartProcessForScreen = disable;
|
||||||
|
}
|
||||||
|
|
||||||
|
onScreenStartProcessPayloadChange(payload: unknown): void {
|
||||||
|
this.screenSubmitPayload = payload;
|
||||||
|
}
|
||||||
|
|
||||||
private getMaxNameLength(): number {
|
private getMaxNameLength(): number {
|
||||||
return this.maxNameLength > MAX_NAME_LENGTH ? MAX_NAME_LENGTH : this.maxNameLength;
|
return this.maxNameLength > MAX_NAME_LENGTH ? MAX_NAME_LENGTH : this.maxNameLength;
|
||||||
}
|
}
|
||||||
@@ -301,6 +328,7 @@ export class StartProcessCloudComponent implements OnChanges, OnInit {
|
|||||||
private selectProcessDefinitionByProcessDefinitionName(processDefinitionName: string): void {
|
private selectProcessDefinitionByProcessDefinitionName(processDefinitionName: string): void {
|
||||||
this.filteredProcesses = this.getProcessDefinitionListByNameOrKey(processDefinitionName);
|
this.filteredProcesses = this.getProcessDefinitionListByNameOrKey(processDefinitionName);
|
||||||
this.isFormCloudLoading = this.isProcessFormValid && this.filteredProcesses && this.filteredProcesses.length === 1;
|
this.isFormCloudLoading = this.isProcessFormValid && this.filteredProcesses && this.filteredProcesses.length === 1;
|
||||||
|
|
||||||
if (this.isFormCloudLoading) {
|
if (this.isFormCloudLoading) {
|
||||||
this.setProcessDefinitionOnForm(this.filteredProcesses[0].name);
|
this.setProcessDefinitionOnForm(this.filteredProcesses[0].name);
|
||||||
}
|
}
|
||||||
@@ -447,27 +475,31 @@ export class StartProcessCloudComponent implements OnChanges, OnInit {
|
|||||||
startProcessWithoutConfirmation() {
|
startProcessWithoutConfirmation() {
|
||||||
this.isProcessStarting = true;
|
this.isProcessStarting = true;
|
||||||
|
|
||||||
const action = this.hasForm
|
let action: Observable<ProcessInstanceCloud>;
|
||||||
? this.startProcessCloudService.startProcessWithForm(
|
|
||||||
this.appName,
|
if (this.hasForm || this.hasScreen) {
|
||||||
this.processDefinitionCurrent.formKey,
|
action = this.startProcessCloudService.startProcessWithForm(
|
||||||
this.processDefinitionCurrent.version,
|
this.appName,
|
||||||
new ProcessWithFormPayloadCloud({
|
this.processDefinitionCurrent.formKey,
|
||||||
processName: this.processInstanceName.value,
|
this.processDefinitionCurrent.version,
|
||||||
processDefinitionKey: this.processPayloadCloud.processDefinitionKey,
|
new ProcessWithFormPayloadCloud({
|
||||||
variables: this.variables ?? {},
|
processName: this.processInstanceName.value,
|
||||||
values: this.formCloud.values,
|
processDefinitionKey: this.processPayloadCloud.processDefinitionKey,
|
||||||
outcome: this.customOutcomeName
|
variables: this.variables ?? {},
|
||||||
})
|
values: this.hasForm ? this.formCloud.values : this.screenSubmitPayload,
|
||||||
)
|
outcome: this.customOutcomeName
|
||||||
: this.startProcessCloudService.startProcess(
|
})
|
||||||
this.appName,
|
);
|
||||||
new ProcessPayloadCloud({
|
} else {
|
||||||
name: this.processInstanceName.value,
|
action = this.startProcessCloudService.startProcess(
|
||||||
processDefinitionKey: this.processPayloadCloud.processDefinitionKey,
|
this.appName,
|
||||||
variables: this.variables ?? {}
|
new ProcessPayloadCloud({
|
||||||
})
|
name: this.processInstanceName.value,
|
||||||
);
|
processDefinitionKey: this.processPayloadCloud.processDefinitionKey,
|
||||||
|
variables: this.variables ?? {}
|
||||||
|
})
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
action.subscribe({
|
action.subscribe({
|
||||||
next: (res) => {
|
next: (res) => {
|
||||||
|
|||||||
+3
-2
@@ -81,13 +81,14 @@ export const fakeProcessDefinitions: ProcessDefinitionCloud[] = [
|
|||||||
})
|
})
|
||||||
];
|
];
|
||||||
|
|
||||||
export const fakeSingleProcessDefinition = (name: string): ProcessDefinitionCloud[] => [
|
export const fakeSingleProcessDefinition = (name: string, processDefinitionData?: Partial<ProcessDefinitionCloud>): ProcessDefinitionCloud[] => [
|
||||||
new ProcessDefinitionCloud({
|
new ProcessDefinitionCloud({
|
||||||
appName: 'startformwithoutupload',
|
appName: 'startformwithoutupload',
|
||||||
formKey: 'form-a5d50817-5183-4850-802d-17af54b2632f',
|
formKey: 'form-a5d50817-5183-4850-802d-17af54b2632f',
|
||||||
id: 'd00c0237-8772-11e9-859a-428f83d5904f',
|
id: 'd00c0237-8772-11e9-859a-428f83d5904f',
|
||||||
key: 'process-5151ad1d-f992-4ee6-9742-3a04617469fe',
|
key: 'process-5151ad1d-f992-4ee6-9742-3a04617469fe',
|
||||||
name
|
name,
|
||||||
|
...(processDefinitionData ?? {})
|
||||||
})
|
})
|
||||||
];
|
];
|
||||||
|
|
||||||
|
|||||||
+50
@@ -0,0 +1,50 @@
|
|||||||
|
/*!
|
||||||
|
* @license
|
||||||
|
* Copyright © 2005-2025 Hyland Software, Inc. and its affiliates. All rights reserved.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import { Component, ComponentRef, inject, Input, OnInit, ViewChild, ViewContainerRef } from '@angular/core';
|
||||||
|
import { ScreenRenderingService } from '../../../services/screen-rendering.service';
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
template: ''
|
||||||
|
})
|
||||||
|
export abstract class BaseScreenCloudComponent<TScreenComponent = unknown> implements OnInit {
|
||||||
|
@Input()
|
||||||
|
screenId: string = '';
|
||||||
|
|
||||||
|
@ViewChild('container', { read: ViewContainerRef, static: true })
|
||||||
|
container: ViewContainerRef;
|
||||||
|
|
||||||
|
protected componentRef: ComponentRef<TScreenComponent>;
|
||||||
|
protected readonly screenRenderingService = inject(ScreenRenderingService);
|
||||||
|
|
||||||
|
ngOnInit() {
|
||||||
|
this.createDynamicComponent();
|
||||||
|
}
|
||||||
|
|
||||||
|
private createDynamicComponent(): void {
|
||||||
|
if (this.screenId) {
|
||||||
|
const componentType = this.screenRenderingService.resolveComponentType({ type: this.screenId });
|
||||||
|
this.componentRef = this.container.createComponent(componentType);
|
||||||
|
this.setInputsForDynamicComponent();
|
||||||
|
this.subscribeToOutputs();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected abstract setInputsForDynamicComponent(): void;
|
||||||
|
|
||||||
|
protected abstract subscribeToOutputs(): void;
|
||||||
|
}
|
||||||
+9
@@ -0,0 +1,9 @@
|
|||||||
|
<mat-card class="adf-cloud-start-process-screen-cloud">
|
||||||
|
<mat-card-content>
|
||||||
|
<ng-container #container />
|
||||||
|
</mat-card-content>
|
||||||
|
|
||||||
|
@if(showStartProcessButtons()) {
|
||||||
|
<ng-content />
|
||||||
|
}
|
||||||
|
</mat-card>
|
||||||
+8
@@ -0,0 +1,8 @@
|
|||||||
|
.adf-cloud-start-process-screen-cloud {
|
||||||
|
position: fixed;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
z-index: 100;
|
||||||
|
}
|
||||||
+70
@@ -0,0 +1,70 @@
|
|||||||
|
/*!
|
||||||
|
* @license
|
||||||
|
* Copyright © 2005-2025 Hyland Software, Inc. and its affiliates. All rights reserved.
|
||||||
|
*
|
||||||
|
* 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 { StartProcessScreenCloudComponent } from './start-process-screen-cloud.component';
|
||||||
|
import { MockedTaskScreenCloudComponent } from '../../../../testing/start-process-screen-mock.component';
|
||||||
|
import { provideScreen } from '../../../services/provide-screen';
|
||||||
|
import { By } from '@angular/platform-browser';
|
||||||
|
import { StartProcessScreenCloud, StartProcessScreenDefaultButtons } from './start-process-screen.model';
|
||||||
|
|
||||||
|
describe('StartProcessScreenCloudComponent', () => {
|
||||||
|
let component: StartProcessScreenCloudComponent;
|
||||||
|
let fixture: ComponentFixture<StartProcessScreenCloudComponent>;
|
||||||
|
const screenId = 'screen-1234-5678-121212-123456';
|
||||||
|
const processDefinitionId = 'definition-id';
|
||||||
|
|
||||||
|
beforeEach(async () => {
|
||||||
|
await TestBed.configureTestingModule({
|
||||||
|
imports: [StartProcessScreenCloudComponent],
|
||||||
|
providers: [provideScreen(screenId, MockedTaskScreenCloudComponent)]
|
||||||
|
}).compileComponents();
|
||||||
|
|
||||||
|
fixture = TestBed.createComponent(StartProcessScreenCloudComponent);
|
||||||
|
component = fixture.componentInstance;
|
||||||
|
fixture.componentRef.setInput('processDefinitionId', processDefinitionId);
|
||||||
|
fixture.componentRef.setInput('screenId', screenId);
|
||||||
|
|
||||||
|
fixture.detectChanges();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should create provided screen component', () => {
|
||||||
|
const screenDebugComponent = fixture.debugElement.query(By.directive(MockedTaskScreenCloudComponent));
|
||||||
|
expect(screenDebugComponent).toBeTruthy();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should subscribe to outputs', () => {
|
||||||
|
const screenStartProcessPayloadChangeSpy = spyOn(component.screenStartProcessPayloadChange, 'emit');
|
||||||
|
const disableStartProcessButtonSpy = spyOn(component.disableStartProcessButton, 'emit');
|
||||||
|
|
||||||
|
const screenInstance: StartProcessScreenCloud = fixture.debugElement.query(By.directive(MockedTaskScreenCloudComponent)).componentInstance;
|
||||||
|
|
||||||
|
const startProcessScreenDefaultButtons: StartProcessScreenDefaultButtons = { show: true, disable: false };
|
||||||
|
const startProcessPayload = { payload: 'TEST' };
|
||||||
|
screenInstance.defaultStartProcessButtonsConfigurationChange.emit(startProcessScreenDefaultButtons);
|
||||||
|
screenInstance.startProcessPayloadChanged.emit(startProcessPayload);
|
||||||
|
|
||||||
|
expect(screenStartProcessPayloadChangeSpy).toHaveBeenCalledWith(startProcessPayload);
|
||||||
|
expect(disableStartProcessButtonSpy).toHaveBeenCalledWith(startProcessScreenDefaultButtons.disable);
|
||||||
|
expect(component.showStartProcessButtons()).toBe(startProcessScreenDefaultButtons.show);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should set process definition id', () => {
|
||||||
|
const screenInstance: StartProcessScreenCloud = fixture.debugElement.query(By.directive(MockedTaskScreenCloudComponent)).componentInstance;
|
||||||
|
expect(screenInstance.processDefinitionId()).toBe(processDefinitionId);
|
||||||
|
});
|
||||||
|
});
|
||||||
+52
@@ -0,0 +1,52 @@
|
|||||||
|
/*!
|
||||||
|
* @license
|
||||||
|
* Copyright © 2005-2025 Hyland Software, Inc. and its affiliates. All rights reserved.
|
||||||
|
*
|
||||||
|
* 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 { ChangeDetectionStrategy, Component, input, output, signal } from '@angular/core';
|
||||||
|
import { BaseScreenCloudComponent } from '../base-screen/base-screen-cloud.component';
|
||||||
|
import { MatCardModule } from '@angular/material/card';
|
||||||
|
import { CommonModule } from '@angular/common';
|
||||||
|
import { StartProcessScreenCloud } from './start-process-screen.model';
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'adf-cloud-start-process-screen-cloud',
|
||||||
|
imports: [CommonModule, MatCardModule],
|
||||||
|
templateUrl: './start-process-screen-cloud.component.html',
|
||||||
|
host: { class: 'adf-cloud-start-process-screen-cloud' },
|
||||||
|
styleUrls: ['./start-process-screen-cloud.component.scss'],
|
||||||
|
changeDetection: ChangeDetectionStrategy.OnPush
|
||||||
|
})
|
||||||
|
export class StartProcessScreenCloudComponent extends BaseScreenCloudComponent<StartProcessScreenCloud> {
|
||||||
|
processDefinitionId = input('');
|
||||||
|
screenStartProcessPayloadChange = output<unknown>();
|
||||||
|
disableStartProcessButton = output<boolean>();
|
||||||
|
|
||||||
|
showStartProcessButtons = signal(false);
|
||||||
|
|
||||||
|
protected setInputsForDynamicComponent(): void {
|
||||||
|
if (this.processDefinitionId()) {
|
||||||
|
this.componentRef.setInput('processDefinitionId', this.processDefinitionId());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected subscribeToOutputs(): void {
|
||||||
|
this.componentRef.instance.startProcessPayloadChanged.subscribe((payload) => this.screenStartProcessPayloadChange.emit(payload));
|
||||||
|
this.componentRef.instance.defaultStartProcessButtonsConfigurationChange.subscribe((config) => {
|
||||||
|
this.showStartProcessButtons.set(config.show);
|
||||||
|
this.disableStartProcessButton.emit(config.disable);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
+28
@@ -0,0 +1,28 @@
|
|||||||
|
/*!
|
||||||
|
* @license
|
||||||
|
* Copyright © 2005-2025 Hyland Software, Inc. and its affiliates. All rights reserved.
|
||||||
|
*
|
||||||
|
* 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 { InputSignal, OutputEmitterRef } from '@angular/core';
|
||||||
|
|
||||||
|
export interface StartProcessScreenDefaultButtons {
|
||||||
|
show: boolean;
|
||||||
|
disable: boolean;
|
||||||
|
}
|
||||||
|
export interface StartProcessScreenCloud {
|
||||||
|
processDefinitionId: InputSignal<string>;
|
||||||
|
defaultStartProcessButtonsConfigurationChange: OutputEmitterRef<StartProcessScreenDefaultButtons>;
|
||||||
|
startProcessPayloadChanged: OutputEmitterRef<unknown>;
|
||||||
|
}
|
||||||
+1
-1
@@ -18,7 +18,7 @@
|
|||||||
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||||
import { Component, EventEmitter, Input, Output, ViewChild } from '@angular/core';
|
import { Component, EventEmitter, Input, Output, ViewChild } from '@angular/core';
|
||||||
import { By } from '@angular/platform-browser';
|
import { By } from '@angular/platform-browser';
|
||||||
import { ScreenRenderingService } from '../../services/screen-rendering.service';
|
import { ScreenRenderingService } from '../../../services/screen-rendering.service';
|
||||||
import { TaskScreenCloudComponent } from './screen-cloud.component';
|
import { TaskScreenCloudComponent } from './screen-cloud.component';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
+7
-30
@@ -16,19 +16,19 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import { CommonModule } from '@angular/common';
|
import { CommonModule } from '@angular/common';
|
||||||
import { Component, ComponentRef, DestroyRef, EventEmitter, inject, Input, OnInit, Output, ViewChild, ViewContainerRef } from '@angular/core';
|
import { Component, DestroyRef, EventEmitter, inject, Input, Output } from '@angular/core';
|
||||||
import { ScreenRenderingService } from '../../services/screen-rendering.service';
|
|
||||||
import { MatCardModule } from '@angular/material/card';
|
import { MatCardModule } from '@angular/material/card';
|
||||||
import { UserTaskCustomUi } from './screen-cloud.model';
|
import { UserTaskCustomUi } from './screen-cloud.model';
|
||||||
import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
|
import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
|
||||||
import { MatCheckboxChange } from '@angular/material/checkbox';
|
import { MatCheckboxChange } from '@angular/material/checkbox';
|
||||||
|
import { BaseScreenCloudComponent } from '../base-screen/base-screen-cloud.component';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'adf-cloud-task-screen',
|
selector: 'adf-cloud-task-screen',
|
||||||
imports: [CommonModule, MatCardModule],
|
imports: [CommonModule, MatCardModule],
|
||||||
templateUrl: './screen-cloud.component.html'
|
templateUrl: './screen-cloud.component.html'
|
||||||
})
|
})
|
||||||
export class TaskScreenCloudComponent implements OnInit {
|
export class TaskScreenCloudComponent extends BaseScreenCloudComponent<UserTaskCustomUi> {
|
||||||
/** Task id to fetch corresponding form and values. */
|
/** Task id to fetch corresponding form and values. */
|
||||||
@Input()
|
@Input()
|
||||||
taskId: string;
|
taskId: string;
|
||||||
@@ -48,10 +48,6 @@ export class TaskScreenCloudComponent implements OnInit {
|
|||||||
@Input()
|
@Input()
|
||||||
showCancelButton: boolean;
|
showCancelButton: boolean;
|
||||||
|
|
||||||
/** Screen id to create dynamic component. */
|
|
||||||
@Input()
|
|
||||||
screenId: string = '';
|
|
||||||
|
|
||||||
/** Process Instance Id to fetch corresponding data. */
|
/** Process Instance Id to fetch corresponding data. */
|
||||||
@Input()
|
@Input()
|
||||||
processInstanceId: string = '';
|
processInstanceId: string = '';
|
||||||
@@ -104,27 +100,9 @@ export class TaskScreenCloudComponent implements OnInit {
|
|||||||
@Output()
|
@Output()
|
||||||
nextTaskCheckboxCheckedChanged = new EventEmitter<MatCheckboxChange>();
|
nextTaskCheckboxCheckedChanged = new EventEmitter<MatCheckboxChange>();
|
||||||
|
|
||||||
@ViewChild('container', { read: ViewContainerRef, static: true })
|
private readonly destroyRef = inject(DestroyRef);
|
||||||
container: ViewContainerRef;
|
|
||||||
|
|
||||||
private destroyRef = inject(DestroyRef);
|
protected override setInputsForDynamicComponent(): void {
|
||||||
componentRef: ComponentRef<UserTaskCustomUi>;
|
|
||||||
private readonly screenRenderingService = inject(ScreenRenderingService);
|
|
||||||
|
|
||||||
ngOnInit() {
|
|
||||||
this.createDynamicComponent();
|
|
||||||
}
|
|
||||||
|
|
||||||
createDynamicComponent() {
|
|
||||||
if (this.screenId) {
|
|
||||||
const componentType = this.screenRenderingService.resolveComponentType({ type: this.screenId });
|
|
||||||
this.componentRef = this.container.createComponent(componentType);
|
|
||||||
this.setInputsForDynamicComponent();
|
|
||||||
this.subscribeToOutputs();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
setInputsForDynamicComponent(): void {
|
|
||||||
if (this.taskId && Object.prototype.hasOwnProperty.call(this.componentRef.instance, 'taskId')) {
|
if (this.taskId && Object.prototype.hasOwnProperty.call(this.componentRef.instance, 'taskId')) {
|
||||||
this.componentRef.setInput('taskId', this.taskId);
|
this.componentRef.setInput('taskId', this.taskId);
|
||||||
}
|
}
|
||||||
@@ -160,7 +138,7 @@ export class TaskScreenCloudComponent implements OnInit {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
subscribeToOutputs() {
|
protected override subscribeToOutputs(): void {
|
||||||
if (this.componentRef.instance?.taskSaved) {
|
if (this.componentRef.instance?.taskSaved) {
|
||||||
this.componentRef.instance.taskSaved.pipe(takeUntilDestroyed(this.destroyRef)).subscribe(() => this.taskSaved.emit());
|
this.componentRef.instance.taskSaved.pipe(takeUntilDestroyed(this.destroyRef)).subscribe(() => this.taskSaved.emit());
|
||||||
}
|
}
|
||||||
@@ -172,7 +150,6 @@ export class TaskScreenCloudComponent implements OnInit {
|
|||||||
if (this.componentRef.instance?.error) {
|
if (this.componentRef.instance?.error) {
|
||||||
this.componentRef.instance.error.pipe(takeUntilDestroyed(this.destroyRef)).subscribe((data) => this.error.emit(data));
|
this.componentRef.instance.error.pipe(takeUntilDestroyed(this.destroyRef)).subscribe((data) => this.error.emit(data));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.componentRef.instance?.claimTask) {
|
if (this.componentRef.instance?.claimTask) {
|
||||||
this.componentRef.instance.claimTask.pipe(takeUntilDestroyed(this.destroyRef)).subscribe((data) => this.claimTask.emit(data));
|
this.componentRef.instance.claimTask.pipe(takeUntilDestroyed(this.destroyRef)).subscribe((data) => this.claimTask.emit(data));
|
||||||
}
|
}
|
||||||
@@ -189,7 +166,7 @@ export class TaskScreenCloudComponent implements OnInit {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
switchToDisplayMode(newDisplayMode?: string) {
|
switchToDisplayMode(newDisplayMode?: string): void {
|
||||||
if (this.componentRef?.instance?.switchToDisplayMode) {
|
if (this.componentRef?.instance?.switchToDisplayMode) {
|
||||||
this.componentRef.instance.switchToDisplayMode(newDisplayMode);
|
this.componentRef.instance.switchToDisplayMode(newDisplayMode);
|
||||||
}
|
}
|
||||||
@@ -15,6 +15,7 @@
|
|||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
export * from './components/screen-cloud/screen-cloud.model';
|
export * from './components/screen-cloud/user-task-screen/screen-cloud.model';
|
||||||
|
export * from './components/screen-cloud/start-process-event-screen/start-process-screen-cloud.component';
|
||||||
export * from './services/screen-rendering.service';
|
export * from './services/screen-rendering.service';
|
||||||
export * from './services/provide-screen';
|
export * from './services/provide-screen';
|
||||||
|
|||||||
+63
@@ -0,0 +1,63 @@
|
|||||||
|
/*!
|
||||||
|
* @license
|
||||||
|
* Copyright © 2005-2025 Hyland Software, Inc. and its affiliates. All rights reserved.
|
||||||
|
*
|
||||||
|
* 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 { TaskTypeResolverService, UserTaskContentType } from './task-type-resolver.service';
|
||||||
|
|
||||||
|
describe('TaskTypeResolverService', () => {
|
||||||
|
let service: TaskTypeResolverService;
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
TestBed.configureTestingModule({});
|
||||||
|
service = TestBed.inject(TaskTypeResolverService);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should return proper user task type', () => {
|
||||||
|
expect(service.getUserTaskType('form-1234')).toBe(UserTaskContentType.Form);
|
||||||
|
expect(service.getUserTaskType('screen-1234')).toBe(UserTaskContentType.Screen);
|
||||||
|
|
||||||
|
expect(service.getUserTaskType('other-1234')).toBe(UserTaskContentType.None);
|
||||||
|
expect(service.getUserTaskType('')).toBe(UserTaskContentType.None);
|
||||||
|
expect(service.getUserTaskType()).toBe(UserTaskContentType.None);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should detect form task', () => {
|
||||||
|
expect(service.isFormTask('form-1234')).toBeTrue();
|
||||||
|
|
||||||
|
expect(service.isFormTask('screen-1234')).toBeFalse();
|
||||||
|
expect(service.isFormTask('other-1234')).toBeFalse();
|
||||||
|
expect(service.isFormTask('')).toBeFalse();
|
||||||
|
expect(service.isFormTask()).toBeFalse();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should detect screen task', () => {
|
||||||
|
expect(service.isScreenTask('screen-1234')).toBeTrue();
|
||||||
|
|
||||||
|
expect(service.isScreenTask('form-1234')).toBeFalse();
|
||||||
|
expect(service.isScreenTask('other-1234')).toBeFalse();
|
||||||
|
expect(service.isScreenTask('')).toBeFalse();
|
||||||
|
expect(service.isScreenTask()).toBeFalse();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should extract screen id from form key', () => {
|
||||||
|
expect(service.getScreenId('screen-1234-5678-9121')).toBe('1234-5678-9121');
|
||||||
|
expect(service.getScreenId('form-1234')).toBe('');
|
||||||
|
expect(service.getScreenId('other-1234')).toBe('');
|
||||||
|
expect(service.getScreenId('')).toBe('');
|
||||||
|
expect(service.getScreenId()).toBe('');
|
||||||
|
});
|
||||||
|
});
|
||||||
+61
@@ -0,0 +1,61 @@
|
|||||||
|
/*!
|
||||||
|
* @license
|
||||||
|
* Copyright © 2005-2025 Hyland Software, Inc. and its affiliates. All rights reserved.
|
||||||
|
*
|
||||||
|
* 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';
|
||||||
|
|
||||||
|
export const UserTaskContentType = {
|
||||||
|
Form: 'form',
|
||||||
|
Screen: 'screen',
|
||||||
|
None: ''
|
||||||
|
} as const;
|
||||||
|
|
||||||
|
export type UserTaskType = (typeof UserTaskContentType)[keyof typeof UserTaskContentType];
|
||||||
|
|
||||||
|
@Injectable({
|
||||||
|
providedIn: 'root'
|
||||||
|
})
|
||||||
|
export class TaskTypeResolverService {
|
||||||
|
isScreenTask(formKey?: string): boolean {
|
||||||
|
return this.getUserTaskType(formKey) === UserTaskContentType.Screen;
|
||||||
|
}
|
||||||
|
|
||||||
|
isFormTask(formKey?: string): boolean {
|
||||||
|
return this.getUserTaskType(formKey) === UserTaskContentType.Form;
|
||||||
|
}
|
||||||
|
|
||||||
|
getScreenId(formKey?: string): string {
|
||||||
|
const taskType = this.getUserTaskType(formKey);
|
||||||
|
|
||||||
|
if (taskType === UserTaskContentType.Screen) {
|
||||||
|
return formKey.replace(`${taskType}-`, '');
|
||||||
|
}
|
||||||
|
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
|
||||||
|
getUserTaskType(formKey?: string): UserTaskType {
|
||||||
|
if (formKey?.includes(UserTaskContentType.Form)) {
|
||||||
|
return UserTaskContentType.Form;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (formKey?.includes(UserTaskContentType.Screen)) {
|
||||||
|
return UserTaskContentType.Screen;
|
||||||
|
}
|
||||||
|
|
||||||
|
return UserTaskContentType.None;
|
||||||
|
}
|
||||||
|
}
|
||||||
+6
-3
@@ -26,7 +26,7 @@ import { of, throwError } from 'rxjs';
|
|||||||
import { IdentityUserService } from '../../../../people/services/identity-user.service';
|
import { IdentityUserService } from '../../../../people/services/identity-user.service';
|
||||||
import { UserTaskCloudComponent } from './user-task-cloud.component';
|
import { UserTaskCloudComponent } from './user-task-cloud.component';
|
||||||
import { By } from '@angular/platform-browser';
|
import { By } from '@angular/platform-browser';
|
||||||
import { TaskScreenCloudComponent } from '../../../../screen/components/screen-cloud/screen-cloud.component';
|
import { TaskScreenCloudComponent } from '../../../../screen/components/screen-cloud/user-task-screen/screen-cloud.component';
|
||||||
import { MatCheckboxChange } from '@angular/material/checkbox';
|
import { MatCheckboxChange } from '@angular/material/checkbox';
|
||||||
import { NoopAuthModule, NoopTranslateModule } from '@alfresco/adf-core';
|
import { NoopAuthModule, NoopTranslateModule } from '@alfresco/adf-core';
|
||||||
import {
|
import {
|
||||||
@@ -42,7 +42,7 @@ import { TaskCloudService } from '../../../services/task-cloud.service';
|
|||||||
import { FormModel } from '../../../../../../../core';
|
import { FormModel } from '../../../../../../../core';
|
||||||
import { UserTaskCloudButtonsComponent } from '../user-task-cloud-buttons/user-task-cloud-buttons.component';
|
import { UserTaskCloudButtonsComponent } from '../user-task-cloud-buttons/user-task-cloud-buttons.component';
|
||||||
|
|
||||||
const taskDetails: TaskDetailsCloudModel = {
|
const createTaskDetailsCloudModel = (): TaskDetailsCloudModel => ({
|
||||||
appName: 'simple-app',
|
appName: 'simple-app',
|
||||||
assignee: 'admin.adf',
|
assignee: 'admin.adf',
|
||||||
completedDate: null,
|
completedDate: null,
|
||||||
@@ -55,7 +55,7 @@ const taskDetails: TaskDetailsCloudModel = {
|
|||||||
standalone: false,
|
standalone: false,
|
||||||
status: TASK_ASSIGNED_STATE,
|
status: TASK_ASSIGNED_STATE,
|
||||||
permissions: [TASK_VIEW_PERMISSION]
|
permissions: [TASK_VIEW_PERMISSION]
|
||||||
};
|
});
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'adf-cloud-task-screen',
|
selector: 'adf-cloud-task-screen',
|
||||||
@@ -94,8 +94,11 @@ describe('UserTaskCloudComponent', () => {
|
|||||||
let loader: HarnessLoader;
|
let loader: HarnessLoader;
|
||||||
let identityUserService: IdentityUserService;
|
let identityUserService: IdentityUserService;
|
||||||
let errorEmitSpy: jasmine.Spy;
|
let errorEmitSpy: jasmine.Spy;
|
||||||
|
let taskDetails: TaskDetailsCloudModel;
|
||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
|
taskDetails = createTaskDetailsCloudModel();
|
||||||
|
|
||||||
TestBed.configureTestingModule({
|
TestBed.configureTestingModule({
|
||||||
imports: [NoopTranslateModule, NoopAuthModule, UserTaskCloudComponent, TaskFormCloudComponent]
|
imports: [NoopTranslateModule, NoopAuthModule, UserTaskCloudComponent, TaskFormCloudComponent]
|
||||||
}).overrideComponent(UserTaskCloudComponent, {
|
}).overrideComponent(UserTaskCloudComponent, {
|
||||||
|
|||||||
+10
-25
@@ -28,18 +28,11 @@ import { UserTaskCloudButtonsComponent } from '../user-task-cloud-buttons/user-t
|
|||||||
import { TranslatePipe } from '@ngx-translate/core';
|
import { TranslatePipe } from '@ngx-translate/core';
|
||||||
import { MatButtonModule } from '@angular/material/button';
|
import { MatButtonModule } from '@angular/material/button';
|
||||||
import { MatCardModule } from '@angular/material/card';
|
import { MatCardModule } from '@angular/material/card';
|
||||||
import { TaskScreenCloudComponent } from '../../../../screen/components/screen-cloud/screen-cloud.component';
|
import { TaskScreenCloudComponent } from '../../../../screen/components/screen-cloud/user-task-screen/screen-cloud.component';
|
||||||
import { CompleteTaskDirective } from './complete-task/complete-task.directive';
|
import { CompleteTaskDirective } from './complete-task/complete-task.directive';
|
||||||
import { catchError, EMPTY, forkJoin } from 'rxjs';
|
import { catchError, EMPTY, forkJoin } from 'rxjs';
|
||||||
import { MatCheckboxChange, MatCheckboxModule } from '@angular/material/checkbox';
|
import { MatCheckboxChange, MatCheckboxModule } from '@angular/material/checkbox';
|
||||||
|
import { UserTaskContentType, TaskTypeResolverService, UserTaskType } from '../../../../services/task-type-resolver/task-type-resolver.service';
|
||||||
const TaskTypes = {
|
|
||||||
Form: 'form',
|
|
||||||
Screen: 'screen',
|
|
||||||
None: ''
|
|
||||||
} as const;
|
|
||||||
|
|
||||||
type TaskTypesType = (typeof TaskTypes)[keyof typeof TaskTypes];
|
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'adf-cloud-user-task',
|
selector: 'adf-cloud-user-task',
|
||||||
@@ -183,12 +176,13 @@ export class UserTaskCloudComponent implements OnInit, OnChanges {
|
|||||||
candidateUsers: string[] = [];
|
candidateUsers: string[] = [];
|
||||||
candidateGroups: string[] = [];
|
candidateGroups: string[] = [];
|
||||||
loading: boolean = false;
|
loading: boolean = false;
|
||||||
screenId: string;
|
|
||||||
taskDetails: TaskDetailsCloudModel;
|
taskDetails: TaskDetailsCloudModel;
|
||||||
taskType: TaskTypesType;
|
taskType: UserTaskType;
|
||||||
taskTypeEnum = TaskTypes;
|
taskTypeEnum = UserTaskContentType;
|
||||||
|
screenId: string;
|
||||||
|
|
||||||
private taskCloudService: TaskCloudService = inject(TaskCloudService);
|
private taskCloudService: TaskCloudService = inject(TaskCloudService);
|
||||||
|
private readonly taskTypeResolverService = inject(TaskTypeResolverService);
|
||||||
private readonly destroyRef = inject(DestroyRef);
|
private readonly destroyRef = inject(DestroyRef);
|
||||||
|
|
||||||
ngOnChanges(changes: SimpleChanges) {
|
ngOnChanges(changes: SimpleChanges) {
|
||||||
@@ -224,19 +218,8 @@ export class UserTaskCloudComponent implements OnInit, OnChanges {
|
|||||||
}
|
}
|
||||||
|
|
||||||
getTaskType(): void {
|
getTaskType(): void {
|
||||||
if (this.taskDetails && !!this.taskDetails.formKey) {
|
this.taskType = this.taskTypeResolverService.getUserTaskType(this.taskDetails?.formKey);
|
||||||
if (this.taskDetails.formKey.includes(this.taskTypeEnum.Form)) {
|
this.screenId = this.taskTypeResolverService.getScreenId(this.taskDetails?.formKey);
|
||||||
this.taskType = this.taskTypeEnum.Form;
|
|
||||||
return;
|
|
||||||
} else if (this.taskDetails.formKey.includes(this.taskTypeEnum.Screen)) {
|
|
||||||
this.taskType = this.taskTypeEnum.Screen;
|
|
||||||
const screenId = this.taskDetails.formKey.replace(this.taskTypeEnum.Screen + '-', '');
|
|
||||||
this.screenId = screenId;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
this.taskType = this.taskTypeEnum.None;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
hasCandidateUsers(): boolean {
|
hasCandidateUsers(): boolean {
|
||||||
@@ -284,6 +267,7 @@ export class UserTaskCloudComponent implements OnInit, OnChanges {
|
|||||||
onExecuteOutcome(outcome: FormOutcomeEvent): void {
|
onExecuteOutcome(outcome: FormOutcomeEvent): void {
|
||||||
this.executeOutcome.emit(outcome);
|
this.executeOutcome.emit(outcome);
|
||||||
}
|
}
|
||||||
|
|
||||||
onFormContentClicked(content: ContentLinkModel): void {
|
onFormContentClicked(content: ContentLinkModel): void {
|
||||||
this.formContentClicked.emit(content);
|
this.formContentClicked.emit(content);
|
||||||
}
|
}
|
||||||
@@ -309,6 +293,7 @@ export class UserTaskCloudComponent implements OnInit, OnChanges {
|
|||||||
const tasks$ = this.taskCloudService.getTaskById(this.appName, this.taskId);
|
const tasks$ = this.taskCloudService.getTaskById(this.appName, this.taskId);
|
||||||
const candidateUsers$ = this.taskCloudService.getCandidateUsers(this.appName, this.taskId);
|
const candidateUsers$ = this.taskCloudService.getCandidateUsers(this.appName, this.taskId);
|
||||||
const candidateGroups$ = this.taskCloudService.getCandidateGroups(this.appName, this.taskId);
|
const candidateGroups$ = this.taskCloudService.getCandidateGroups(this.appName, this.taskId);
|
||||||
|
|
||||||
forkJoin({
|
forkJoin({
|
||||||
tasks: tasks$,
|
tasks: tasks$,
|
||||||
candidateUsers: candidateUsers$,
|
candidateUsers: candidateUsers$,
|
||||||
|
|||||||
@@ -0,0 +1,32 @@
|
|||||||
|
/*!
|
||||||
|
* @license
|
||||||
|
* Copyright © 2005-2025 Hyland Software, Inc. and its affiliates. All rights reserved.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import { Component, input, output } from '@angular/core';
|
||||||
|
import {
|
||||||
|
StartProcessScreenCloud,
|
||||||
|
StartProcessScreenDefaultButtons
|
||||||
|
} from '../screen/components/screen-cloud/start-process-event-screen/start-process-screen.model';
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'adf-cloud-mock-screen-component',
|
||||||
|
template: `<div>Mock Screen Component</div>`
|
||||||
|
})
|
||||||
|
export class MockedTaskScreenCloudComponent implements StartProcessScreenCloud {
|
||||||
|
processDefinitionId = input('');
|
||||||
|
defaultStartProcessButtonsConfigurationChange = output<StartProcessScreenDefaultButtons>();
|
||||||
|
startProcessPayloadChanged = output<unknown>();
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user