mirror of
https://github.com/Alfresco/alfresco-ng2-components.git
synced 2025-09-10 14:11:42 +00:00
AAE-36335 Handle custom redirects
This commit is contained in:
@@ -223,8 +223,8 @@ export abstract class FormBaseComponent {
|
||||
}
|
||||
} else {
|
||||
// Note: Activiti is using NAME field rather than ID for outcomes
|
||||
if (outcome.name) {
|
||||
this.completeTaskForm(outcome.name);
|
||||
if (outcome.name && outcome.id) {
|
||||
this.completeTaskForm(outcome.name, outcome.id);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -243,7 +243,7 @@ export abstract class FormBaseComponent {
|
||||
|
||||
abstract saveTaskForm(): void;
|
||||
|
||||
abstract completeTaskForm(outcome?: string): void;
|
||||
abstract completeTaskForm(outcome?: string, outcomeId?: string): void;
|
||||
|
||||
protected abstract onTaskSaved(form: FormModel): void;
|
||||
|
||||
|
@@ -73,7 +73,6 @@ export class FormModel implements ProcessFormModel {
|
||||
readonly confirmMessage: ConfirmMessage;
|
||||
readonly taskName = FormModel.UNSET_TASK_NAME;
|
||||
readonly processDefinitionId: string;
|
||||
readonly selectedOutcome: string;
|
||||
readonly enableFixedSpace: boolean;
|
||||
readonly displayMode: any;
|
||||
|
||||
@@ -88,6 +87,8 @@ export class FormModel implements ProcessFormModel {
|
||||
fieldValidators: FormFieldValidator[] = [];
|
||||
customFieldTemplates: FormFieldTemplates = {};
|
||||
theme?: ThemeModel;
|
||||
selectedOutcomeId?: string;
|
||||
selectedOutcome: string;
|
||||
|
||||
className: string;
|
||||
readOnly = false;
|
||||
|
@@ -464,7 +464,8 @@ describe('FormCloudComponent', () => {
|
||||
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 outcomeId = 'custom1';
|
||||
const outcome = new FormOutcomeModel(formModel, { id: outcomeId, name: outcomeName });
|
||||
|
||||
let saved = false;
|
||||
formComponent.form = formModel;
|
||||
@@ -474,7 +475,7 @@ describe('FormCloudComponent', () => {
|
||||
const result = formComponent.onOutcomeClicked(outcome);
|
||||
expect(result).toBeTruthy();
|
||||
expect(saved).toBeFalse();
|
||||
expect(formComponent.completeTaskForm).toHaveBeenCalledWith(outcomeName);
|
||||
expect(formComponent.completeTaskForm).toHaveBeenCalledWith(outcomeName, outcomeId);
|
||||
});
|
||||
|
||||
it('should save form on [save] outcome click', () => {
|
||||
@@ -800,8 +801,13 @@ describe('FormCloudComponent', () => {
|
||||
);
|
||||
|
||||
const outcome = 'complete';
|
||||
const outcomeId = 'custom-outcome-id';
|
||||
let completed = false;
|
||||
formComponent.formCompleted.subscribe(() => (completed = true));
|
||||
let completedForm = null;
|
||||
formComponent.formCompleted.subscribe((form) => {
|
||||
completed = true;
|
||||
completedForm = form;
|
||||
});
|
||||
|
||||
const taskId = '123-223';
|
||||
const appVersion = 1;
|
||||
@@ -819,7 +825,7 @@ describe('FormCloudComponent', () => {
|
||||
formComponent.taskId = taskId;
|
||||
formComponent.appName = appName;
|
||||
formComponent.processInstanceId = processInstanceId;
|
||||
formComponent.completeTaskForm(outcome);
|
||||
formComponent.completeTaskForm(outcome, outcomeId);
|
||||
|
||||
expect(formCloudService.completeTaskForm).toHaveBeenCalledWith(
|
||||
appName,
|
||||
@@ -831,6 +837,9 @@ describe('FormCloudComponent', () => {
|
||||
appVersion
|
||||
);
|
||||
expect(completed).toBeTruthy();
|
||||
expect(completedForm.selectedOutcome).toBe(outcome);
|
||||
expect(completedForm.selectedOutcomeId).toBe(outcomeId);
|
||||
expect(completedForm).toBe(formComponent.form);
|
||||
});
|
||||
|
||||
it('should open confirmation dialog on complete task', async () => {
|
||||
@@ -865,9 +874,11 @@ describe('FormCloudComponent', () => {
|
||||
formComponent.appName = 'appName';
|
||||
|
||||
spyOn(formComponent['formCloudService'], 'completeTaskForm').and.returnValue(of(formModel as any));
|
||||
formComponent.completeTaskForm('complete');
|
||||
const outcomeId = 'test-outcome-id';
|
||||
formComponent.completeTaskForm('complete', outcomeId);
|
||||
|
||||
expect(formComponent['formCloudService'].completeTaskForm).toHaveBeenCalled();
|
||||
expect(formComponent.form.selectedOutcomeId).toBe(outcomeId);
|
||||
});
|
||||
|
||||
it('should not confirm form if user rejects', () => {
|
||||
@@ -940,7 +951,7 @@ describe('FormCloudComponent', () => {
|
||||
const result = formComponent.onOutcomeClicked(outcome);
|
||||
expect(result).toBeTruthy();
|
||||
|
||||
expect(formComponent.completeTaskForm).toHaveBeenCalledWith(outcome.name);
|
||||
expect(formComponent.completeTaskForm).toHaveBeenCalledWith(outcome.name, outcome.id);
|
||||
});
|
||||
|
||||
it('should check visibility only if field with form provided', () => {
|
||||
@@ -1760,4 +1771,76 @@ describe('retrieve metadata on submit', () => {
|
||||
|
||||
expect(formComponent.disableSaveButton).toBeFalse();
|
||||
});
|
||||
|
||||
it('should handle outcomeId correctly when completing form with confirmation dialog', () => {
|
||||
let matDialog = TestBed.inject(MatDialog);
|
||||
spyOn(matDialog, 'open').and.returnValue({ afterClosed: () => of(true) } as any);
|
||||
spyOn(formComponent['formCloudService'], 'completeTaskForm').and.returnValue(of({} as any));
|
||||
|
||||
const formModel = new FormModel({
|
||||
confirmMessage: {
|
||||
show: true,
|
||||
message: 'Are you sure you want to submit the form?'
|
||||
}
|
||||
});
|
||||
formComponent.form = formModel;
|
||||
formComponent.taskId = 'task-123';
|
||||
formComponent.appName = 'test-app';
|
||||
|
||||
const outcome = 'approve';
|
||||
const outcomeId = 'approve-outcome-id';
|
||||
|
||||
formComponent.completeTaskForm(outcome, outcomeId);
|
||||
|
||||
expect(matDialog.open).toHaveBeenCalled();
|
||||
expect(formComponent.form.selectedOutcome).toBe(outcome);
|
||||
expect(formComponent.form.selectedOutcomeId).toBe(outcomeId);
|
||||
});
|
||||
|
||||
it('should pass outcomeId when completing form without confirmation dialog', () => {
|
||||
spyOn(formComponent['formCloudService'], 'completeTaskForm').and.returnValue(of({} as any));
|
||||
|
||||
const formModel = new FormModel();
|
||||
formComponent.form = formModel;
|
||||
formComponent.taskId = 'task-123';
|
||||
formComponent.appName = 'test-app';
|
||||
|
||||
const outcome = 'reject';
|
||||
const outcomeId = 'reject-outcome-id';
|
||||
|
||||
formComponent.completeTaskForm(outcome, outcomeId);
|
||||
|
||||
expect(formComponent.form.selectedOutcome).toBe(outcome);
|
||||
expect(formComponent.form.selectedOutcomeId).toBe(outcomeId);
|
||||
expect(formComponent['formCloudService'].completeTaskForm).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should set form values before calling onTaskCompleted', () => {
|
||||
const formModel = new FormModel({
|
||||
id: '23',
|
||||
taskId: '123-223',
|
||||
fields: [{ id: 'field1' }, { id: 'field2' }]
|
||||
});
|
||||
|
||||
formComponent.form = formModel;
|
||||
formComponent.taskId = '123-223';
|
||||
formComponent.appName = 'test-app';
|
||||
|
||||
const outcome = 'approve';
|
||||
const outcomeId = 'custom-approve-id';
|
||||
let emittedForm = null;
|
||||
|
||||
spyOn(formComponent['formCloudService'], 'completeTaskForm').and.returnValue(of({} as any));
|
||||
|
||||
formComponent.formCompleted.subscribe((form) => {
|
||||
emittedForm = form;
|
||||
});
|
||||
|
||||
formComponent.completeTaskForm(outcome, outcomeId);
|
||||
|
||||
expect(emittedForm).not.toBeNull();
|
||||
expect(emittedForm.selectedOutcome).toBe(outcome);
|
||||
expect(emittedForm.selectedOutcomeId).toBe(outcomeId);
|
||||
expect(formComponent['formCloudService'].completeTaskForm).toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
|
@@ -395,7 +395,7 @@ export class FormCloudComponent extends FormBaseComponent implements OnChanges,
|
||||
}
|
||||
}
|
||||
|
||||
completeTaskForm(outcome?: string) {
|
||||
completeTaskForm(outcome?: string, outcomeId?: string) {
|
||||
if (this.form?.confirmMessage?.show === true) {
|
||||
const dialogRef = this.dialog.open(ConfirmDialogComponent, {
|
||||
data: {
|
||||
@@ -406,22 +406,24 @@ export class FormCloudComponent extends FormBaseComponent implements OnChanges,
|
||||
|
||||
dialogRef.afterClosed().subscribe((result) => {
|
||||
if (result === true) {
|
||||
this.completeForm(outcome);
|
||||
this.completeForm(outcome, outcomeId);
|
||||
}
|
||||
});
|
||||
} else {
|
||||
this.completeForm(outcome);
|
||||
this.completeForm(outcome, outcomeId);
|
||||
}
|
||||
this.displayModeService.onCompleteTask(this.id, this.displayMode, this.displayModeConfigurations);
|
||||
}
|
||||
|
||||
private completeForm(outcome?: string) {
|
||||
private completeForm(outcome?: string, outcomeId?: string) {
|
||||
if (this.form && this.appName && this.taskId) {
|
||||
this.formCloudService
|
||||
.completeTaskForm(this.appName, this.taskId, this.processInstanceId, `${this.form.id}`, this.form.values, outcome, this.appVersion)
|
||||
.pipe(takeUntilDestroyed(this.destroyRef))
|
||||
.subscribe({
|
||||
next: () => {
|
||||
this.form.selectedOutcome = outcome;
|
||||
this.form.selectedOutcomeId = outcomeId;
|
||||
this.onTaskCompleted(this.form);
|
||||
},
|
||||
error: (error) => this.onTaskCompletedError(error)
|
||||
|
@@ -103,7 +103,7 @@
|
||||
[showTitle]="false"
|
||||
(formContentClicked)="onFormContentClicked($event)"
|
||||
(formLoaded)="onFormLoaded($event)"
|
||||
(executeOutcome)="onCustomOutcomeClicked($event.outcome.name)"
|
||||
(executeOutcome)="onCustomOutcomeClicked($event)"
|
||||
>
|
||||
<adf-cloud-form-custom-outcomes>
|
||||
<ng-template [ngTemplateOutlet]="taskFormCloudButtons" />
|
||||
|
@@ -17,7 +17,7 @@
|
||||
|
||||
import { SimpleChange } from '@angular/core';
|
||||
import { ComponentFixture, TestBed, fakeAsync, tick } from '@angular/core/testing';
|
||||
import { FormModel } from '@alfresco/adf-core';
|
||||
import { FormModel, FormOutcomeEvent, FormOutcomeModel } from '@alfresco/adf-core';
|
||||
import { of, throwError } from 'rxjs';
|
||||
import { StartProcessCloudService } from '../services/start-process-cloud.service';
|
||||
import { FormCloudService } from '../../../form/services/form-cloud.service';
|
||||
@@ -820,9 +820,12 @@ describe('StartProcessCloudComponent', () => {
|
||||
outcome: 'custom_outcome'
|
||||
});
|
||||
|
||||
const formOutcomeModel = new FormOutcomeModel(null, fakeFormModelJson.outcomes[0]);
|
||||
const event = new FormOutcomeEvent(formOutcomeModel);
|
||||
|
||||
fixture.detectChanges();
|
||||
|
||||
component.onCustomOutcomeClicked('custom_outcome');
|
||||
component.onCustomOutcomeClicked(event);
|
||||
|
||||
expect(startProcessWithFormSpy).toHaveBeenCalledWith(
|
||||
component.appName,
|
||||
@@ -869,7 +872,7 @@ describe('StartProcessCloudComponent', () => {
|
||||
);
|
||||
});
|
||||
|
||||
it('should output start event when process started successfully', () => {
|
||||
it('should emit start event when process started successfully', () => {
|
||||
const emitSpy = spyOn(component.success, 'emit');
|
||||
component.startProcess();
|
||||
expect(emitSpy).toHaveBeenCalledWith(fakeProcessInstance);
|
||||
@@ -1214,4 +1217,40 @@ describe('StartProcessCloudComponent', () => {
|
||||
component.cancelStartProcess();
|
||||
});
|
||||
});
|
||||
|
||||
it('should emit customOutcomeSelected and success events when onCustomOutcomeClicked is called', async () => {
|
||||
const customOutcomeSelectedSpy = spyOn(component.customOutcomeSelected, 'emit');
|
||||
const successSpy = spyOn(component.success, 'emit');
|
||||
|
||||
getDefinitionsSpy.and.returnValue(of(fakeProcessDefinitions));
|
||||
formDefinitionSpy.and.returnValue(of(fakeFormModelJson));
|
||||
startProcessWithFormSpy.and.returnValue(of(fakeProcessInstance));
|
||||
|
||||
component.ngOnChanges({ appName: firstChange });
|
||||
component.processForm.controls['processInstanceName'].setValue('My Process 1');
|
||||
component.appName = 'test app name';
|
||||
component.formCloud = new FormModel(JSON.stringify(fakeFormModelJson));
|
||||
component.formCloud.values = { dropdown: { id: '1', name: 'label 2' } };
|
||||
component.processDefinitionCurrent = fakeProcessDefinitions[2];
|
||||
component.processPayloadCloud.processDefinitionKey = fakeProcessDefinitions[2].key;
|
||||
|
||||
const customOutcome = {
|
||||
id: 'custom_outcome_id',
|
||||
name: 'custom_outcome'
|
||||
};
|
||||
const formOutcomeModel = new FormOutcomeModel(null, customOutcome);
|
||||
const event = new FormOutcomeEvent(formOutcomeModel);
|
||||
|
||||
fixture.detectChanges();
|
||||
|
||||
component.onCustomOutcomeClicked(event);
|
||||
|
||||
await fixture.whenStable();
|
||||
|
||||
expect(customOutcomeSelectedSpy).toHaveBeenCalledWith(customOutcome.id);
|
||||
expect(successSpy).toHaveBeenCalledWith(fakeProcessInstance);
|
||||
expect(startProcessWithFormSpy).toHaveBeenCalledTimes(1);
|
||||
expect(component.customOutcomeName).toBe(customOutcome.name);
|
||||
expect(component.customOutcomeId).toBe(customOutcome.id);
|
||||
});
|
||||
});
|
||||
|
@@ -33,6 +33,7 @@ import {
|
||||
ConfirmDialogComponent,
|
||||
ContentLinkModel,
|
||||
FormModel,
|
||||
FormOutcomeEvent,
|
||||
InplaceFormInputComponent,
|
||||
LocalizedDatePipe,
|
||||
TranslationService,
|
||||
@@ -158,6 +159,9 @@ export class StartProcessCloudComponent implements OnChanges, OnInit {
|
||||
@Output()
|
||||
processDefinitionSelection: EventEmitter<ProcessDefinitionCloud> = new EventEmitter<ProcessDefinitionCloud>();
|
||||
|
||||
@Output()
|
||||
customOutcomeSelected: EventEmitter<string> = new EventEmitter<string>();
|
||||
|
||||
processDefinitionList: ProcessDefinitionCloud[] = [];
|
||||
processDefinitionCurrent?: ProcessDefinitionCloud;
|
||||
errorMessageId: string = '';
|
||||
@@ -165,7 +169,8 @@ export class StartProcessCloudComponent implements OnChanges, OnInit {
|
||||
filteredProcesses: ProcessDefinitionCloud[] = [];
|
||||
staticMappings: TaskVariableCloud[] = [];
|
||||
resolvedValues?: TaskVariableCloud[];
|
||||
customOutcome: string;
|
||||
customOutcomeName: string;
|
||||
customOutcomeId: string;
|
||||
|
||||
isProcessStarting = false;
|
||||
isFormCloudLoaded = false;
|
||||
@@ -421,8 +426,9 @@ export class StartProcessCloudComponent implements OnChanges, OnInit {
|
||||
}
|
||||
}
|
||||
|
||||
onCustomOutcomeClicked(outcome: string) {
|
||||
this.customOutcome = outcome;
|
||||
onCustomOutcomeClicked(outcome: FormOutcomeEvent) {
|
||||
this.customOutcomeName = outcome.outcome.name;
|
||||
this.customOutcomeId = outcome.outcome.id;
|
||||
this.startProcess();
|
||||
}
|
||||
|
||||
@@ -439,7 +445,7 @@ export class StartProcessCloudComponent implements OnChanges, OnInit {
|
||||
processDefinitionKey: this.processPayloadCloud.processDefinitionKey,
|
||||
variables: this.variables ?? {},
|
||||
values: this.formCloud.values,
|
||||
outcome: this.customOutcome
|
||||
outcome: this.customOutcomeName
|
||||
})
|
||||
)
|
||||
: this.startProcessCloudService.startProcess(
|
||||
@@ -453,6 +459,7 @@ export class StartProcessCloudComponent implements OnChanges, OnInit {
|
||||
|
||||
action.subscribe({
|
||||
next: (res) => {
|
||||
this.customOutcomeSelected.emit(this.customOutcomeId);
|
||||
this.success.emit(res);
|
||||
this.isProcessStarting = false;
|
||||
},
|
||||
|
@@ -323,7 +323,13 @@ export const fakeFormModelJson = {
|
||||
}
|
||||
}
|
||||
],
|
||||
outcomes: [],
|
||||
outcomes: [
|
||||
{
|
||||
id: 'custom_outcome_id',
|
||||
name: 'custom_outcome',
|
||||
visibilityCondition: null
|
||||
}
|
||||
],
|
||||
metadata: {},
|
||||
variables: []
|
||||
};
|
||||
|
@@ -348,6 +348,17 @@ describe('TaskFormCloudComponent', () => {
|
||||
expect(component.formLoaded.emit).toHaveBeenCalledOnceWith(mockForm);
|
||||
});
|
||||
|
||||
it('should emit both formCompleted and taskCompleted events when form is completed', () => {
|
||||
const mockForm = new FormModel();
|
||||
spyOn(component.formCompleted, 'emit').and.stub();
|
||||
spyOn(component.taskCompleted, 'emit').and.stub();
|
||||
|
||||
component.onFormCompleted(mockForm);
|
||||
|
||||
expect(component.formCompleted.emit).toHaveBeenCalledOnceWith(mockForm);
|
||||
expect(component.taskCompleted.emit).toHaveBeenCalledOnceWith(mockForm);
|
||||
});
|
||||
|
||||
it('should handle formLoaded event from adf-cloud-form and re-emit it', () => {
|
||||
const mockForm = new FormModel();
|
||||
spyOn(component.formLoaded, 'emit').and.stub();
|
||||
|
@@ -125,7 +125,7 @@ export class TaskFormCloudComponent {
|
||||
|
||||
/** Emitted when the task is completed. */
|
||||
@Output()
|
||||
taskCompleted = new EventEmitter<string>();
|
||||
taskCompleted = new EventEmitter<FormModel>();
|
||||
|
||||
/** Emitted when the task is claimed. */
|
||||
@Output()
|
||||
@@ -167,7 +167,10 @@ export class TaskFormCloudComponent {
|
||||
|
||||
loading: boolean = false;
|
||||
|
||||
constructor(private taskCloudService: TaskCloudService, private formRenderingService: FormRenderingService) {
|
||||
constructor(
|
||||
private taskCloudService: TaskCloudService,
|
||||
private formRenderingService: FormRenderingService
|
||||
) {
|
||||
this.formRenderingService.setComponentTypeResolver('upload', () => AttachFileCloudWidgetComponent, true);
|
||||
this.formRenderingService.setComponentTypeResolver('dropdown', () => DropdownCloudWidgetComponent, true);
|
||||
this.formRenderingService.setComponentTypeResolver('date', () => DateCloudWidgetComponent, true);
|
||||
@@ -205,10 +208,6 @@ export class TaskFormCloudComponent {
|
||||
return this.readOnly || !this.taskCloudService.canCompleteTask(this.taskDetails);
|
||||
}
|
||||
|
||||
onCompleteTask() {
|
||||
this.taskCompleted.emit(this.taskId);
|
||||
}
|
||||
|
||||
onClaimTask() {
|
||||
this.taskClaimed.emit(this.taskId);
|
||||
}
|
||||
@@ -227,7 +226,7 @@ export class TaskFormCloudComponent {
|
||||
|
||||
onFormCompleted(form: FormModel) {
|
||||
this.formCompleted.emit(form);
|
||||
this.taskCompleted.emit(this.taskId);
|
||||
this.taskCompleted.emit(form);
|
||||
}
|
||||
|
||||
onError(data: any) {
|
||||
|
@@ -347,7 +347,7 @@ describe('FormComponent', () => {
|
||||
const result = formComponent.onOutcomeClicked(outcome);
|
||||
expect(result).toBeTruthy();
|
||||
expect(saved).toBeFalse();
|
||||
expect(formComponent.completeTaskForm).toHaveBeenCalledWith(outcomeName);
|
||||
expect(formComponent.completeTaskForm).toHaveBeenCalledWith(outcomeName, outcome.id);
|
||||
});
|
||||
|
||||
it('should save form on [save] outcome click', () => {
|
||||
@@ -707,7 +707,7 @@ describe('FormComponent', () => {
|
||||
const result = formComponent.onOutcomeClicked(outcome);
|
||||
expect(result).toBeTruthy();
|
||||
|
||||
expect(formComponent.completeTaskForm).toHaveBeenCalledWith(outcome.name);
|
||||
expect(formComponent.completeTaskForm).toHaveBeenCalledWith(outcome.name, outcome.id);
|
||||
});
|
||||
|
||||
it('should check visibility only if field with form provided', () => {
|
||||
|
Reference in New Issue
Block a user