[ACS-5991] ESLint fixes and code quality improvements (#8893)

* prefer-optional-chain: core

* prefer-optional-chain: content, fix typings

* prefer-optional-chain: process, fix typings

* prefer-optional-chain: process-cloud, fix typings, fix ts configs and eslint

* [ci: force] sonar errors fixes, insights lib

* [ci:force] fix security issues

* [ci:force] fix metadata e2e bug, js assignment bugs

* [ci:force] fix lint issue

* [ci:force] fix tests
This commit is contained in:
Denys Vuika
2023-09-18 09:42:16 +01:00
committed by GitHub
parent 99f591ed67
commit a1dd270c5d
203 changed files with 4155 additions and 4960 deletions

View File

@@ -24,7 +24,6 @@ import { ProcessContentService } from '../form/services/process-content.service'
templateUrl: './create-process-attachment.component.html'
})
export class CreateProcessAttachmentComponent implements OnChanges {
/** (required) The ID of the process instance to display. */
@Input()
processInstanceId: string;
@@ -41,11 +40,10 @@ export class CreateProcessAttachmentComponent implements OnChanges {
@Output()
success: EventEmitter<any> = new EventEmitter<any>();
constructor(private activitiContentService: ProcessContentService) {
}
constructor(private activitiContentService: ProcessContentService) {}
ngOnChanges(changes: SimpleChanges) {
if (changes['processInstanceId'] && changes['processInstanceId'].currentValue) {
if (changes['processInstanceId']?.currentValue) {
this.processInstanceId = changes['processInstanceId'].currentValue;
}
}
@@ -64,7 +62,8 @@ export class CreateProcessAttachmentComponent implements OnChanges {
},
(err) => {
this.error.emit(err);
});
}
);
}
}
}

View File

@@ -24,7 +24,6 @@ import { ProcessContentService } from '../form/services/process-content.service'
templateUrl: './create-task-attachment.component.html'
})
export class AttachmentComponent implements OnChanges {
/** (required) The numeric ID of the task to display. */
@Input()
taskId: string;
@@ -39,13 +38,12 @@ export class AttachmentComponent implements OnChanges {
* from within the component.
*/
@Output()
success: EventEmitter<any> = new EventEmitter<any>();
success = new EventEmitter<any>();
constructor(private activitiContentService: ProcessContentService) {
}
constructor(private activitiContentService: ProcessContentService) {}
ngOnChanges(changes: SimpleChanges) {
if (changes['taskId'] && changes['taskId'].currentValue) {
if (changes['taskId']?.currentValue) {
this.taskId = changes['taskId'].currentValue;
}
}

View File

@@ -37,7 +37,6 @@ import { ProcessContentService } from '../form/services/process-content.service'
encapsulation: ViewEncapsulation.None
})
export class ProcessAttachmentListComponent implements OnChanges, AfterContentInit {
@ContentChild(EmptyListComponent)
emptyTemplate: EmptyListComponent;
@@ -74,14 +73,15 @@ export class ProcessAttachmentListComponent implements OnChanges, AfterContentIn
attachments: any[] = [];
isLoading: boolean = false;
constructor(private activitiContentService: ProcessContentService,
private downloadService: DownloadService,
private thumbnailService: ThumbnailService,
private ngZone: NgZone) {
}
constructor(
private activitiContentService: ProcessContentService,
private downloadService: DownloadService,
private thumbnailService: ThumbnailService,
private ngZone: NgZone
) {}
ngOnChanges(changes: SimpleChanges) {
if (changes['processInstanceId'] && changes['processInstanceId'].currentValue) {
if (changes['processInstanceId']?.currentValue) {
this.loadAttachmentsByProcessInstanceId(changes['processInstanceId'].currentValue);
}
}
@@ -119,7 +119,7 @@ export class ProcessAttachmentListComponent implements OnChanges, AfterContentIn
}
isEmpty(): boolean {
return this.attachments && this.attachments.length === 0;
return this.attachments?.length === 0;
}
onShowRowActionsMenu(event: any) {
@@ -138,10 +138,7 @@ export class ProcessAttachmentListComponent implements OnChanges, AfterContentIn
name: 'download'
};
event.value.actions = [
viewAction,
downloadAction
];
event.value.actions = [viewAction, downloadAction];
if (!this.disabled) {
event.value.actions.splice(1, 0, removeAction);
@@ -212,7 +209,8 @@ export class ProcessAttachmentListComponent implements OnChanges, AfterContentIn
(err) => {
this.error.emit(err);
this.isLoading = false;
});
}
);
}
}
@@ -224,7 +222,8 @@ export class ProcessAttachmentListComponent implements OnChanges, AfterContentIn
},
(err) => {
this.error.emit(err);
});
}
);
}
}
}

View File

@@ -37,7 +37,6 @@ import { ProcessContentService } from '../form/services/process-content.service'
encapsulation: ViewEncapsulation.None
})
export class TaskAttachmentListComponent implements OnChanges, AfterContentInit {
@ContentChild(EmptyListComponent)
emptyTemplate: EmptyListComponent;
@@ -71,14 +70,15 @@ export class TaskAttachmentListComponent implements OnChanges, AfterContentInit
attachments: any[] = [];
isLoading: boolean = false;
constructor(private activitiContentService: ProcessContentService,
private downloadService: DownloadService,
private thumbnailService: ThumbnailService,
private ngZone: NgZone) {
}
constructor(
private activitiContentService: ProcessContentService,
private downloadService: DownloadService,
private thumbnailService: ThumbnailService,
private ngZone: NgZone
) {}
ngOnChanges(changes: SimpleChanges) {
if (changes['taskId'] && changes['taskId'].currentValue) {
if (changes['taskId']?.currentValue) {
this.loadAttachmentsByTaskId(changes['taskId'].currentValue);
}
}
@@ -123,7 +123,8 @@ export class TaskAttachmentListComponent implements OnChanges, AfterContentInit
},
(err) => {
this.error.emit(err);
});
}
);
}
}
@@ -147,10 +148,7 @@ export class TaskAttachmentListComponent implements OnChanges, AfterContentInit
name: 'download'
};
event.value.actions = [
viewAction,
downloadAction
];
event.value.actions = [viewAction, downloadAction];
if (!this.disabled) {
event.value.actions.splice(1, 0, removeAction);
@@ -223,7 +221,8 @@ export class TaskAttachmentListComponent implements OnChanges, AfterContentInit
(err) => {
this.error.emit(err);
this.isLoading = false;
});
}
);
}
}
}

View File

@@ -15,18 +15,7 @@
* limitations under the License.
*/
import {
Component,
EventEmitter,
Input,
Output,
ViewEncapsulation,
SimpleChanges,
OnInit,
OnDestroy,
OnChanges,
inject
} from '@angular/core';
import { Component, EventEmitter, Input, Output, ViewEncapsulation, SimpleChanges, OnInit, OnDestroy, OnChanges, inject } from '@angular/core';
import {
WidgetVisibilityService,
FormService,
@@ -48,7 +37,6 @@ import { ModelService } from './services/model.service';
import { EditorService } from './services/editor.service';
import { TaskService } from './services/task.service';
import { TaskFormService } from './services/task-form.service';
import { TaskRepresentation } from '@alfresco/js-api';
import { NodesApiService } from '@alfresco/adf-content-services';
import { FormDefinitionModel } from './model/form-definition.model';
@@ -128,17 +116,13 @@ export class FormComponent extends FormBaseComponent implements OnInit, OnDestro
}
ngOnInit() {
this.formService.formContentClicked
.pipe(takeUntil(this.onDestroy$))
.subscribe(content => this.formContentClicked.emit(content));
this.formService.formContentClicked.pipe(takeUntil(this.onDestroy$)).subscribe((content) => this.formContentClicked.emit(content));
this.formService.validateForm
.pipe(takeUntil(this.onDestroy$))
.subscribe(validateFormEvent => {
if (validateFormEvent.errorsField.length > 0) {
this.formError.next(validateFormEvent.errorsField);
}
});
this.formService.validateForm.pipe(takeUntil(this.onDestroy$)).subscribe((validateFormEvent) => {
if (validateFormEvent.errorsField.length > 0) {
this.formError.next(validateFormEvent.errorsField);
}
});
}
ngOnDestroy() {
@@ -148,31 +132,31 @@ export class FormComponent extends FormBaseComponent implements OnInit, OnDestro
ngOnChanges(changes: SimpleChanges) {
const taskId = changes['taskId'];
if (taskId && taskId.currentValue) {
if (taskId?.currentValue) {
this.getFormByTaskId(taskId.currentValue);
return;
}
const formId = changes['formId'];
if (formId && formId.currentValue) {
if (formId?.currentValue) {
this.getFormDefinitionByFormId(formId.currentValue);
return;
}
const formName = changes['formName'];
if (formName && formName.currentValue) {
if (formName?.currentValue) {
this.getFormDefinitionByFormName(formName.currentValue);
return;
}
const nodeId = changes['nodeId'];
if (nodeId && nodeId.currentValue) {
if (nodeId?.currentValue) {
this.loadFormForEcmNode(nodeId.currentValue);
return;
}
const data = changes['data'];
if (data && data.currentValue) {
if (data?.currentValue) {
this.refreshFormData();
return;
}
@@ -204,7 +188,7 @@ export class FormComponent extends FormBaseComponent implements OnInit, OnDestro
findProcessVariablesByTaskId(taskId: string): Observable<TaskProcessVariableModel[]> {
return this.taskService.getTask(taskId).pipe(
switchMap((task: TaskRepresentation) => {
switchMap((task) => {
if (this.isAProcessTask(task)) {
return this.taskFormService.getTaskProcessVariable(taskId);
} else {
@@ -219,93 +203,83 @@ export class FormComponent extends FormBaseComponent implements OnInit, OnDestro
}
getFormByTaskId(taskId: string): Promise<FormModel> {
return new Promise<FormModel>(resolve => {
return new Promise<FormModel>((resolve) => {
this.findProcessVariablesByTaskId(taskId).subscribe((taskProcessVariables) => {
this.taskFormService
.getTaskForm(taskId)
.subscribe(
(form) => {
const parsedForm = this.parseForm(form);
this.visibilityService.refreshVisibility(parsedForm, taskProcessVariables);
parsedForm.validateForm();
this.form = parsedForm;
this.onFormLoaded(this.form);
resolve(this.form);
},
(error) => {
this.handleError(error);
resolve(null);
}
);
this.taskFormService.getTaskForm(taskId).subscribe(
(form) => {
const parsedForm = this.parseForm(form);
this.visibilityService.refreshVisibility(parsedForm, taskProcessVariables);
parsedForm.validateForm();
this.form = parsedForm;
this.onFormLoaded(this.form);
resolve(this.form);
},
(error) => {
this.handleError(error);
resolve(null);
}
);
});
});
}
getFormDefinitionByFormId(formId: number) {
this.editorService
.getFormDefinitionById(formId)
.subscribe(
(form) => {
this.formName = form.name;
this.form = this.parseForm(form);
this.visibilityService.refreshVisibility(this.form);
this.form.validateForm();
this.onFormLoaded(this.form);
},
(error) => {
this.handleError(error);
}
);
this.editorService.getFormDefinitionById(formId).subscribe(
(form) => {
this.formName = form.name;
this.form = this.parseForm(form);
this.visibilityService.refreshVisibility(this.form);
this.form.validateForm();
this.onFormLoaded(this.form);
},
(error) => {
this.handleError(error);
}
);
}
getFormDefinitionByFormName(formName: string) {
this.modelService
.getFormDefinitionByName(formName)
.subscribe(
(id) => {
this.editorService.getFormDefinitionById(id).subscribe(
(form) => {
this.form = this.parseForm(form);
this.visibilityService.refreshVisibility(this.form);
this.form.validateForm();
this.onFormLoaded(this.form);
},
(error) => {
this.handleError(error);
}
);
},
(error) => {
this.handleError(error);
}
);
this.modelService.getFormDefinitionByName(formName).subscribe(
(id) => {
this.editorService.getFormDefinitionById(id).subscribe(
(form) => {
this.form = this.parseForm(form);
this.visibilityService.refreshVisibility(this.form);
this.form.validateForm();
this.onFormLoaded(this.form);
},
(error) => {
this.handleError(error);
}
);
},
(error) => {
this.handleError(error);
}
);
}
saveTaskForm() {
if (this.form && this.form.taskId) {
this.taskFormService
.saveTaskForm(this.form.taskId, this.form.values)
.subscribe(
() => {
this.onTaskSaved(this.form);
this.storeFormAsMetadata();
},
(error) => this.onTaskSavedError(this.form, error)
);
if (this.form?.taskId) {
this.taskFormService.saveTaskForm(this.form.taskId, this.form.values).subscribe(
() => {
this.onTaskSaved(this.form);
this.storeFormAsMetadata();
},
(error) => this.onTaskSavedError(this.form, error)
);
}
}
completeTaskForm(outcome?: string) {
if (this.form && this.form.taskId) {
this.taskFormService
.completeTaskForm(this.form.taskId, this.form.values, outcome)
.subscribe(
() => {
this.onTaskCompleted(this.form);
this.storeFormAsMetadata();
},
(error) => this.onTaskCompletedError(this.form, error)
);
if (this.form?.taskId) {
this.taskFormService.completeTaskForm(this.form.taskId, this.form.values, outcome).subscribe(
() => {
this.onTaskCompleted(this.form);
this.storeFormAsMetadata();
},
(error) => this.onTaskCompletedError(this.form, error)
);
}
}
@@ -319,7 +293,7 @@ export class FormComponent extends FormBaseComponent implements OnInit, OnDestro
if (!formRepresentationJSON.fields) {
form.outcomes = this.getFormDefinitionOutcomes(form);
}
if (this.fieldValidators && this.fieldValidators.length > 0) {
if (this.fieldValidators?.length > 0) {
form.fieldValidators = this.fieldValidators;
}
return form;
@@ -333,13 +307,11 @@ export class FormComponent extends FormBaseComponent implements OnInit, OnDestro
* @param form Form definition model.
*/
getFormDefinitionOutcomes(form: FormModel): FormOutcomeModel[] {
return [
new FormOutcomeModel(form, {id: '$save', name: FormOutcomeModel.SAVE_ACTION, isSystem: true})
];
return [new FormOutcomeModel(form, { id: '$save', name: FormOutcomeModel.SAVE_ACTION, isSystem: true })];
}
checkVisibility(field: FormFieldModel) {
if (field && field.form) {
if (field?.form) {
this.visibilityService.refreshVisibility(field.form);
}
}
@@ -361,7 +333,6 @@ export class FormComponent extends FormBaseComponent implements OnInit, OnDestro
);
}
/**
* Creates a Form with a field for each metadata property.
*
@@ -374,24 +345,40 @@ export class FormComponent extends FormBaseComponent implements OnInit, OnDestro
(form) => {
this.ecmModelService.searchEcmType(formName, EcmModelService.MODEL_NAME).subscribe(
(customType) => {
const formDefinitionModel = new FormDefinitionModel(form.id, form.name, form.lastUpdatedByFullName, form.lastUpdated, customType.entry.properties);
from(
this.editorService.saveForm(form.id, formDefinitionModel)
).subscribe((formData) => {
observer.next(formData);
observer.complete();
}, (err) => this.handleError(err));
const formDefinitionModel = new FormDefinitionModel(
form.id,
form.name,
form.lastUpdatedByFullName,
form.lastUpdated,
customType.entry.properties
);
from(this.editorService.saveForm(form.id, formDefinitionModel)).subscribe(
(formData) => {
observer.next(formData);
observer.complete();
},
(err) => this.handleError(err)
);
},
(err) => this.handleError(err));
(err) => this.handleError(err)
);
},
(err) => this.handleError(err));
(err) => this.handleError(err)
);
});
}
protected storeFormAsMetadata() {
if (this.saveMetadata) {
this.ecmModelService.createEcmTypeForActivitiForm(this.formName, this.form).subscribe((type) => {
this.nodeService.createNodeMetadata(type.nodeType || type.entry.prefixedName, EcmModelService.MODEL_NAMESPACE, this.form.values, this.path, this.nameNode);
this.ecmModelService.createEcmTypeForActivitiForm(this.formName, this.form).subscribe(
(type) => {
this.nodeService.createNodeMetadata(
type.nodeType || type.entry.prefixedName,
EcmModelService.MODEL_NAMESPACE,
this.form.values,
this.path,
this.nameNode
);
},
(error) => {
this.handleError(error);
@@ -450,10 +437,9 @@ export class FormComponent extends FormBaseComponent implements OnInit, OnDestro
private loadFormForEcmNode(nodeId: string): void {
this.nodeService.getNodeMetadata(nodeId).subscribe((data) => {
this.data = data.metadata;
this.loadFormFromActiviti(data.nodeType);
},
this.handleError);
this.data = data.metadata;
this.loadFormFromActiviti(data.nodeType);
}, this.handleError);
}
private loadFormFromFormId(formId: number) {

View File

@@ -25,7 +25,6 @@ import { CustomModelApi } from '@alfresco/js-api';
providedIn: 'root'
})
export class EcmModelService {
public static MODEL_NAMESPACE: string = 'activitiForms';
public static MODEL_NAME: string = 'activitiFormsModel';
public static TYPE_MODEL: string = 'cm:folder';
@@ -36,9 +35,7 @@ export class EcmModelService {
return this._customModelApi;
}
constructor(private apiService: AlfrescoApiService,
private logService: LogService) {
}
constructor(private apiService: AlfrescoApiService, private logService: LogService) {}
public createEcmTypeForActivitiForm(formName: string, form: FormModel): Observable<any> {
return new Observable((observer) => {
@@ -59,11 +56,12 @@ export class EcmModelService {
(err) => this.handleError(err)
);
});
}
searchActivitiEcmModel() {
return this.getEcmModels().pipe(map((ecmModels: any) => ecmModels.list.entries.find((model) => model.entry.name === EcmModelService.MODEL_NAME)));
return this.getEcmModels().pipe(
map((ecmModels: any) => ecmModels.list.entries.find((model) => model.entry.name === EcmModelService.MODEL_NAME))
);
}
createActivitiEcmModel(formName: string, form: FormModel): Observable<any> {
@@ -118,64 +116,62 @@ export class EcmModelService {
observer.next(typeCreated);
observer.complete();
},
(err) => this.handleError(err));
(err) => this.handleError(err)
);
},
(err) => this.handleError(err));
(err) => this.handleError(err)
);
});
}
public searchEcmType(typeName: string, modelName: string): Observable<any> {
return this.getEcmType(modelName).pipe(map((customTypes: any) =>
customTypes.list.entries.find((type) => type.entry.prefixedName === typeName || type.entry.title === typeName)));
return this.getEcmType(modelName).pipe(
map((customTypes: any) => customTypes.list.entries.find((type) => type.entry.prefixedName === typeName || type.entry.title === typeName))
);
}
public activeEcmModel(modelName: string): Observable<any> {
return from(this.customModelApi.activateCustomModel(modelName))
.pipe(
map(this.toJson),
catchError((err) => this.handleError(err))
);
return from(this.customModelApi.activateCustomModel(modelName)).pipe(
map(this.toJson),
catchError((err) => this.handleError(err))
);
}
public createEcmModel(modelName: string, nameSpace: string): Observable<any> {
return from(this.customModelApi.createCustomModel('DRAFT', '', modelName, modelName, nameSpace))
.pipe(
map(this.toJson),
catchError((err) => this.handleError(err))
);
return from(this.customModelApi.createCustomModel('DRAFT', '', modelName, modelName, nameSpace)).pipe(
map(this.toJson),
catchError((err) => this.handleError(err))
);
}
public getEcmModels(): Observable<any> {
return from(this.customModelApi.getAllCustomModel())
.pipe(
map(this.toJson),
catchError((err) => this.handleError(err))
);
return from(this.customModelApi.getAllCustomModel()).pipe(
map(this.toJson),
catchError((err) => this.handleError(err))
);
}
public getEcmType(modelName: string): Observable<any> {
return from(this.customModelApi.getAllCustomType(modelName))
.pipe(
map(this.toJson),
catchError((err) => this.handleError(err))
);
return from(this.customModelApi.getAllCustomType(modelName)).pipe(
map(this.toJson),
catchError((err) => this.handleError(err))
);
}
public createEcmType(typeName: string, modelName: string, parentType: string): Observable<any> {
const name = this.cleanNameType(typeName);
return from(this.customModelApi.createCustomType(modelName, name, parentType, typeName, ''))
.pipe(
map(this.toJson),
catchError((err) => this.handleError(err))
);
return from(this.customModelApi.createCustomType(modelName, name, parentType, typeName, '')).pipe(
map(this.toJson),
catchError((err) => this.handleError(err))
);
}
public addPropertyToAType(modelName: string, typeName: string, formFields: any) {
const name = this.cleanNameType(typeName);
const properties = [];
if (formFields && formFields.values) {
if (formFields?.values) {
for (const key in formFields.values) {
if (key) {
properties.push({
@@ -191,12 +187,10 @@ export class EcmModelService {
}
}
return from(this.customModelApi.addPropertyToType(modelName, name, properties))
.pipe(
map(this.toJson),
catchError((err) => this.handleError(err))
);
return from(this.customModelApi.addPropertyToType(modelName, name, properties)).pipe(
map(this.toJson),
catchError((err) => this.handleError(err))
);
}
cleanNameType(name: string): string {
@@ -208,10 +202,7 @@ export class EcmModelService {
}
toJson(res: any) {
if (res) {
return res || {};
}
return {};
return res || {};
}
private handleError(err: any): any {

View File

@@ -25,7 +25,6 @@ import { catchError, map } from 'rxjs/operators';
providedIn: 'root'
})
export class ModelService {
static UNKNOWN_ERROR_MESSAGE: string = 'Unknown error';
static GENERIC_ERROR_MESSAGE: string = 'Server error';
@@ -35,8 +34,7 @@ export class ModelService {
return this._modelsApi;
}
constructor(private apiService: AlfrescoApiService, private logService: LogService) {
}
constructor(private apiService: AlfrescoApiService, private logService: LogService) {}
/**
* Create a Form.
@@ -52,9 +50,7 @@ export class ModelService {
stencilSet: 0
};
return from(
this.modelsApi.createModel(dataModel)
);
return from(this.modelsApi.createModel(dataModel));
}
/**
@@ -67,11 +63,10 @@ export class ModelService {
modelType: 2
};
return from(this.modelsApi.getModels(opts))
.pipe(
map(this.toJsonArray),
catchError((err) => this.handleError(err))
);
return from(this.modelsApi.getModels(opts)).pipe(
map(this.toJsonArray),
catchError((err) => this.handleError(err))
);
}
/**
@@ -81,10 +76,7 @@ export class ModelService {
* @returns JSON data
*/
toJsonArray(res: any) {
if (res) {
return res.data || [];
}
return [];
return res?.data || [];
}
/**
@@ -98,16 +90,12 @@ export class ModelService {
modelType: 2
};
return from(
this.modelsApi.getModels(opts)
)
.pipe(
map((forms: any) => forms.data.find((formData) => formData.name === name)),
catchError((err) => this.handleError(err))
);
return from(this.modelsApi.getModels(opts)).pipe(
map((forms) => forms.data.find((formData) => formData.name === name)),
catchError((err) => this.handleError(err))
);
}
/**
* Gets the form definition with a given name.
*
@@ -121,11 +109,10 @@ export class ModelService {
modelType: 2
};
return from(this.modelsApi.getModels(opts))
.pipe(
map(this.getFormId),
catchError((err) => this.handleError(err))
);
return from(this.modelsApi.getModels(opts)).pipe(
map(this.getFormId),
catchError((err) => this.handleError(err))
);
}
/**
@@ -137,7 +124,7 @@ export class ModelService {
getFormId(form: any): string {
let result = null;
if (form && form.data && form.data.length > 0) {
if (form?.data?.length > 0) {
result = form.data[0].id;
}
@@ -152,11 +139,9 @@ export class ModelService {
private handleError(error: any): Observable<any> {
let errMsg = ModelService.UNKNOWN_ERROR_MESSAGE;
if (error) {
errMsg = (error.message) ? error.message :
error.status ? `${error.status} - ${error.statusText}` : ModelService.GENERIC_ERROR_MESSAGE;
errMsg = error.message ? error.message : error.status ? `${error.status} - ${error.statusText}` : ModelService.GENERIC_ERROR_MESSAGE;
}
this.logService.error(errMsg);
return throwError(errMsg);
}
}

View File

@@ -15,17 +15,17 @@
* limitations under the License.
*/
import { AlfrescoApiService, LogService } from '@alfresco/adf-core';
import { AlfrescoApiService, FormFieldOption, LogService } from '@alfresco/adf-core';
import { Injectable } from '@angular/core';
import { Observable, from, throwError } from 'rxjs';
import { ProcessDefinitionsApi } from '@alfresco/js-api';
import { catchError } from 'rxjs/operators';
import { DynamicTableColumnOption } from '../widgets/dynamic-table/editors/models/dynamic-table-column-option.model';
@Injectable({
providedIn: 'root'
})
export class ProcessDefinitionService {
static UNKNOWN_ERROR_MESSAGE: string = 'Unknown error';
static GENERIC_ERROR_MESSAGE: string = 'Server error';
@@ -35,9 +35,7 @@ export class ProcessDefinitionService {
return this._processDefinitionsApi;
}
constructor(private apiService: AlfrescoApiService, private logService: LogService) {
}
constructor(private apiService: AlfrescoApiService, private logService: LogService) {}
/**
* Gets values of fields populated by a REST backend using a process ID.
@@ -46,11 +44,8 @@ export class ProcessDefinitionService {
* @param field Field identifier
* @returns Field values
*/
getRestFieldValuesByProcessId(processDefinitionId: string, field: string): Observable<any> {
return from(this.processDefinitionsApi.getRestFieldValues(processDefinitionId, field))
.pipe(
catchError((err) => this.handleError(err))
);
getRestFieldValuesByProcessId(processDefinitionId: string, field: string): Observable<FormFieldOption[]> {
return from(this.processDefinitionsApi.getRestFieldValues(processDefinitionId, field)).pipe(catchError((err) => this.handleError(err)));
}
/**
@@ -61,11 +56,10 @@ export class ProcessDefinitionService {
* @param column Column identifier
* @returns Field values
*/
getRestFieldValuesColumnByProcessId(processDefinitionId: string, field: string, column?: string): Observable<any> {
return from(this.processDefinitionsApi.getRestTableFieldValues(processDefinitionId, field, column))
.pipe(
catchError((err) => this.handleError(err))
);
getRestFieldValuesColumnByProcessId(processDefinitionId: string, field: string, column?: string): Observable<DynamicTableColumnOption[]> {
return from(this.processDefinitionsApi.getRestTableFieldValues(processDefinitionId, field, column)).pipe(
catchError((err) => this.handleError(err))
);
}
/**
@@ -90,11 +84,13 @@ export class ProcessDefinitionService {
private handleError(error: any): Observable<any> {
let errMsg = ProcessDefinitionService.UNKNOWN_ERROR_MESSAGE;
if (error) {
errMsg = (error.message) ? error.message :
error.status ? `${error.status} - ${error.statusText}` : ProcessDefinitionService.GENERIC_ERROR_MESSAGE;
errMsg = error.message
? error.message
: error.status
? `${error.status} - ${error.statusText}`
: ProcessDefinitionService.GENERIC_ERROR_MESSAGE;
}
this.logService.error(errMsg);
return throwError(errMsg);
}
}

View File

@@ -15,17 +15,17 @@
* limitations under the License.
*/
import { AlfrescoApiService, FormValues, LogService, TaskProcessVariableModel } from '@alfresco/adf-core';
import { AlfrescoApiService, FormFieldOption, FormValues, LogService, TaskProcessVariableModel } from '@alfresco/adf-core';
import { Injectable } from '@angular/core';
import { from, Observable, throwError } from 'rxjs';
import { CompleteFormRepresentation, SaveFormRepresentation, TaskFormsApi } from '@alfresco/js-api';
import { catchError, map } from 'rxjs/operators';
import { DynamicTableColumnOption } from '../widgets/dynamic-table/editors/models/dynamic-table-column-option.model';
@Injectable({
providedIn: 'root'
})
export class TaskFormService {
static UNKNOWN_ERROR_MESSAGE: string = 'Unknown error';
static GENERIC_ERROR_MESSAGE: string = 'Server error';
@@ -35,8 +35,7 @@ export class TaskFormService {
return this._taskFormsApi;
}
constructor(private apiService: AlfrescoApiService, private logService: LogService) {
}
constructor(private apiService: AlfrescoApiService, private logService: LogService) {}
/**
* Saves a task form.
@@ -48,10 +47,7 @@ export class TaskFormService {
saveTaskForm(taskId: string, formValues: FormValues): Observable<any> {
const saveFormRepresentation = { values: formValues } as SaveFormRepresentation;
return from(this.taskFormsApi.saveTaskForm(taskId, saveFormRepresentation))
.pipe(
catchError((err) => this.handleError(err))
);
return from(this.taskFormsApi.saveTaskForm(taskId, saveFormRepresentation)).pipe(catchError((err) => this.handleError(err)));
}
/**
@@ -68,10 +64,7 @@ export class TaskFormService {
completeFormRepresentation.outcome = outcome;
}
return from(this.taskFormsApi.completeTaskForm(taskId, completeFormRepresentation))
.pipe(
catchError((err) => this.handleError(err))
);
return from(this.taskFormsApi.completeTaskForm(taskId, completeFormRepresentation)).pipe(catchError((err) => this.handleError(err)));
}
/**
@@ -81,11 +74,10 @@ export class TaskFormService {
* @returns Form definition
*/
getTaskForm(taskId: string): Observable<any> {
return from(this.taskFormsApi.getTaskForm(taskId))
.pipe(
map(this.toJson),
catchError((err) => this.handleError(err))
);
return from(this.taskFormsApi.getTaskForm(taskId)).pipe(
map(this.toJson),
catchError((err) => this.handleError(err))
);
}
/**
@@ -95,11 +87,8 @@ export class TaskFormService {
* @param field Field identifier
* @returns Field values
*/
getRestFieldValues(taskId: string, field: string): Observable<any> {
return from(this.taskFormsApi.getRestFieldValues(taskId, field))
.pipe(
catchError((err) => this.handleError(err))
);
getRestFieldValues(taskId: string, field: string): Observable<FormFieldOption[]> {
return from(this.taskFormsApi.getRestFieldValues(taskId, field)).pipe(catchError((err) => this.handleError(err)));
}
/**
@@ -110,19 +99,15 @@ export class TaskFormService {
* @param column Column identifier
* @returns Field values
*/
getRestFieldValuesColumn(taskId: string, field: string, column?: string): Observable<any> {
return from(this.taskFormsApi.getRestFieldColumnValues(taskId, field, column))
.pipe(
catchError((err) => this.handleError(err))
);
getRestFieldValuesColumn(taskId: string, field: string, column?: string): Observable<DynamicTableColumnOption[]> {
return from(this.taskFormsApi.getRestFieldColumnValues(taskId, field, column)).pipe(catchError((err) => this.handleError(err)));
}
getTaskProcessVariable(taskId: string): Observable<TaskProcessVariableModel[]> {
return from(this.taskFormsApi.getTaskFormVariables(taskId))
.pipe(
map((res) => this.toJson(res)),
catchError((err) => this.handleError(err))
);
return from(this.taskFormsApi.getTaskFormVariables(taskId)).pipe(
map((res) => this.toJson(res)),
catchError((err) => this.handleError(err))
);
}
/**
@@ -147,11 +132,9 @@ export class TaskFormService {
private handleError(error: any): Observable<any> {
let errMsg = TaskFormService.UNKNOWN_ERROR_MESSAGE;
if (error) {
errMsg = (error.message) ? error.message :
error.status ? `${error.status} - ${error.statusText}` : TaskFormService.GENERIC_ERROR_MESSAGE;
errMsg = error.message ? error.message : error.status ? `${error.status} - ${error.statusText}` : TaskFormService.GENERIC_ERROR_MESSAGE;
}
this.logService.error(errMsg);
return throwError(errMsg);
}
}

View File

@@ -80,7 +80,7 @@ export class StartFormComponent extends FormComponent implements OnChanges, OnIn
ngOnChanges(changes: SimpleChanges) {
const processDefinitionId = changes['processDefinitionId'];
if (processDefinitionId && processDefinitionId.currentValue) {
if (processDefinitionId?.currentValue) {
this.processDefinitionId = processDefinitionId.currentValue;
this.visibilityService.cleanProcessVariable();
this.getStartFormDefinition(this.processDefinitionId);
@@ -88,13 +88,13 @@ export class StartFormComponent extends FormComponent implements OnChanges, OnIn
}
const data = changes['data'];
if (data && data.currentValue) {
if (data?.currentValue) {
this.parseRefreshVisibilityValidateForm(this.form.json);
return;
}
const processId = changes['processId'];
if (processId && processId.currentValue) {
if (processId?.currentValue) {
this.visibilityService.cleanProcessVariable();
this.loadStartForm(processId.currentValue);
return;
@@ -102,33 +102,28 @@ export class StartFormComponent extends FormComponent implements OnChanges, OnIn
}
loadStartForm(processId: string) {
this.processService.getProcess(processId)
.subscribe((instance: any) => {
this.processService
.getStartFormInstance(processId)
.subscribe(
(form) => {
this.formName = form.name;
if (instance.variables) {
form.processVariables = instance.variables;
}
this.parseRefreshVisibilityValidateForm(form);
},
(error) => this.handleError(error)
);
});
}
getStartFormDefinition(processId: string) {
this.processService
.getStartFormDefinition(processId)
.subscribe(
this.processService.getProcess(processId).subscribe((instance: any) => {
this.processService.getStartFormInstance(processId).subscribe(
(form) => {
this.formName = form.processDefinitionName;
this.formName = form.name;
if (instance.variables) {
form.processVariables = instance.variables;
}
this.parseRefreshVisibilityValidateForm(form);
},
(error) => this.handleError(error)
);
});
}
getStartFormDefinition(processId: string) {
this.processService.getStartFormDefinition(processId).subscribe(
(form) => {
this.formName = form.processDefinitionName;
this.parseRefreshVisibilityValidateForm(form);
},
(error) => this.handleError(error)
);
}
parseRefreshVisibilityValidateForm(form) {
@@ -141,10 +136,9 @@ export class StartFormComponent extends FormComponent implements OnChanges, OnIn
/** @override */
isOutcomeButtonVisible(outcome: FormOutcomeModel, isFormReadOnly: boolean): boolean {
if (outcome && outcome.isSystem && (outcome.name === FormOutcomeModel.SAVE_ACTION ||
outcome.name === FormOutcomeModel.COMPLETE_ACTION)) {
if (outcome?.isSystem && (outcome.name === FormOutcomeModel.SAVE_ACTION || outcome.name === FormOutcomeModel.COMPLETE_ACTION)) {
return false;
} else if (outcome && outcome.name === FormOutcomeModel.START_PROCESS_ACTION) {
} else if (outcome?.name === FormOutcomeModel.START_PROCESS_ACTION) {
return true;
}
return super.isOutcomeButtonVisible(outcome, isFormReadOnly);

View File

@@ -18,21 +18,9 @@
/* eslint-disable @angular-eslint/component-selector */
import { Component, OnDestroy, OnInit, ViewEncapsulation } from '@angular/core';
import {
AppConfigService,
AppConfigValues,
DownloadService,
FormService,
LogService,
ThumbnailService
} from '@alfresco/adf-core';
import { AppConfigService, AppConfigValues, DownloadService, FormService, LogService, ThumbnailService } from '@alfresco/adf-core';
import { ContentNodeDialogService, ContentService } from '@alfresco/adf-content-services';
import {
AlfrescoEndpointRepresentation,
Node,
NodeChildAssociation,
RelatedContentRepresentation
} from '@alfresco/js-api';
import { AlfrescoEndpointRepresentation, Node, NodeChildAssociation, RelatedContentRepresentation } from '@alfresco/js-api';
import { from, of, Subject, zip } from 'rxjs';
import { mergeMap, takeUntil } from 'rxjs/operators';
import { AttachFileWidgetDialogService } from './attach-file-widget-dialog.service';
@@ -58,22 +46,23 @@ import { ActivitiContentService } from '../../services/activiti-alfresco.service
encapsulation: ViewEncapsulation.None
})
export class AttachFileWidgetComponent extends UploadWidgetComponent implements OnInit, OnDestroy {
typeId = 'AttachFileWidgetComponent';
repositoryList: AlfrescoEndpointRepresentation[] = [];
private tempFilesList = [];
private onDestroy$ = new Subject<boolean>();
constructor(public formService: FormService,
private logger: LogService,
public thumbnails: ThumbnailService,
public processContentService: ProcessContentService,
private activitiContentService: ActivitiContentService,
private contentService: ContentService,
private contentDialog: ContentNodeDialogService,
private appConfigService: AppConfigService,
private downloadService: DownloadService,
private attachDialogService: AttachFileWidgetDialogService) {
constructor(
public formService: FormService,
private logger: LogService,
public thumbnails: ThumbnailService,
public processContentService: ProcessContentService,
private activitiContentService: ActivitiContentService,
private contentService: ContentService,
private contentDialog: ContentNodeDialogService,
private appConfigService: AppConfigService,
private downloadService: DownloadService,
private attachDialogService: AttachFileWidgetDialogService
) {
super(formService, logger, thumbnails, processContentService);
}
@@ -84,13 +73,11 @@ export class AttachFileWidgetComponent extends UploadWidgetComponent implements
this.repositoryList = repoList;
});
this.formService.taskSaved
.pipe(takeUntil(this.onDestroy$))
.subscribe(formSaved => {
if (formSaved.form.id === this.field.form.id) {
this.tempFilesList = [];
}
});
this.formService.taskSaved.pipe(takeUntil(this.onDestroy$)).subscribe((formSaved) => {
if (formSaved.form.id === this.field.form.id) {
this.tempFilesList = [];
}
});
}
ngOnDestroy() {
@@ -99,7 +86,7 @@ export class AttachFileWidgetComponent extends UploadWidgetComponent implements
}
isFileSourceConfigured(): boolean {
return !!this.field.params && !!this.field.params.fileSource;
return !!this.field.params?.fileSource;
}
isMultipleSourceUpload(): boolean {
@@ -107,22 +94,15 @@ export class AttachFileWidgetComponent extends UploadWidgetComponent implements
}
isAllFileSourceSelected(): boolean {
return this.field.params &&
this.field.params.fileSource &&
this.field.params.fileSource.serviceId === 'all-file-sources' &&
!this.field.params.link;
return this.field.params?.fileSource?.serviceId === 'all-file-sources' && !this.field.params.link;
}
isOnlyLocalSourceSelected(): boolean {
return this.field.params &&
this.field.params.fileSource &&
this.field.params.fileSource.serviceId === 'local-file';
return this.field.params?.fileSource?.serviceId === 'local-file';
}
isSimpleUploadButton(): boolean {
return this.isUploadButtonVisible() &&
!this.isFileSourceConfigured() ||
this.isOnlyLocalSourceSelected();
return (this.isUploadButtonVisible() && !this.isFileSourceConfigured()) || this.isOnlyLocalSourceSelected();
}
isUploadButtonVisible(): boolean {
@@ -133,11 +113,11 @@ export class AttachFileWidgetComponent extends UploadWidgetComponent implements
return !!this.field.params?.fileSource?.selectedFolder;
}
isTemporaryFile(file): boolean {
isTemporaryFile(file: { name?: string }): boolean {
return this.tempFilesList.findIndex((elem) => elem.name === file.name) >= 0;
}
getNodeFromTempFile(file): NodeChildAssociation {
getNodeFromTempFile(file: { name?: string }): NodeChildAssociation {
return this.tempFilesList.find((elem) => elem.name === file.name);
}
@@ -147,13 +127,14 @@ export class AttachFileWidgetComponent extends UploadWidgetComponent implements
if (repository && this.isExternalHost(repository)) {
this.uploadFileFromExternalCS(repository, params?.fileSource?.selectedFolder?.pathId);
} else {
this.contentDialog.openFileBrowseDialogByFolderId(params.fileSource.selectedFolder.pathId).subscribe(
(selections: Node[]) => {
this.tempFilesList.push(...selections);
this.uploadFileFromCS(selections,
this.field.params.fileSource.selectedFolder.accountId,
this.field.params.fileSource.selectedFolder.siteId);
});
this.contentDialog.openFileBrowseDialogByFolderId(params.fileSource.selectedFolder.pathId).subscribe((selections: Node[]) => {
this.tempFilesList.push(...selections);
this.uploadFileFromCS(
selections,
this.field.params.fileSource.selectedFolder.accountId,
this.field.params.fileSource.selectedFolder.siteId
);
});
}
}
@@ -218,11 +199,10 @@ export class AttachFileWidgetComponent extends UploadWidgetComponent implements
if (this.isExternalHost(repository)) {
this.uploadFileFromExternalCS(repository);
} else {
this.contentDialog.openFileBrowseDialogByDefaultLocation().subscribe(
(selections: Node[]) => {
this.tempFilesList.push(...selections);
this.uploadFileFromCS(selections, `alfresco-${repository.id}-${repository.name}`);
});
this.contentDialog.openFileBrowseDialogByDefaultLocation().subscribe((selections: Node[]) => {
this.tempFilesList.push(...selections);
this.uploadFileFromCS(selections, `alfresco-${repository.id}-${repository.name}`);
});
}
}
@@ -237,36 +217,33 @@ export class AttachFileWidgetComponent extends UploadWidgetComponent implements
}
private findSource(sourceIdentifier: string): AlfrescoEndpointRepresentation {
return this.repositoryList.find(repository => sourceIdentifier === `alfresco-${repository.id}-${repository.name}`);
return this.repositoryList.find((repository) => sourceIdentifier === `alfresco-${repository.id}-${repository.name}`);
}
private uploadFileFromExternalCS(repository: AlfrescoEndpointRepresentation, currentFolderId?: string) {
const accountIdentifier = `alfresco-${repository.id}-${repository.name}`;
this.attachDialogService.openLogin(repository, currentFolderId, accountIdentifier).subscribe(
(selections: any[]) => {
selections.forEach((node) => node.isExternal = true);
this.tempFilesList.push(...selections);
this.uploadFileFromCS(selections, accountIdentifier);
});
this.attachDialogService.openLogin(repository, currentFolderId, accountIdentifier).subscribe((selections: any[]) => {
selections.forEach((node) => (node.isExternal = true));
this.tempFilesList.push(...selections);
this.uploadFileFromCS(selections, accountIdentifier);
});
}
private uploadFileFromCS(fileNodeList: any[], accountId: string, siteId?: string) {
const filesSaved = [];
fileNodeList.forEach(node => {
fileNodeList.forEach((node) => {
node.isLink = this.field.params.link;
});
from(fileNodeList).pipe(
mergeMap((node) =>
zip(
of(node?.content?.mimeType),
this.activitiContentService.applyAlfrescoNode(node, siteId, accountId),
of(node.isExternal)
from(fileNodeList)
.pipe(
mergeMap((node) =>
zip(of(node?.content?.mimeType), this.activitiContentService.applyAlfrescoNode(node, siteId, accountId), of(node.isExternal))
)
)
)
.subscribe(([mimeType, res, isExternal]) => {
.subscribe(
([mimeType, res, isExternal]) => {
res.mimeType = mimeType;
res.isExternal = isExternal;
filesSaved.push(res);
@@ -279,12 +256,12 @@ export class AttachFileWidgetComponent extends UploadWidgetComponent implements
this.field.value = [...previousFiles, ...filesSaved];
this.field.json.value = [...previousFiles, ...filesSaved];
this.hasFile = true;
});
}
);
}
private getDomainHost(urlToCheck: string): string {
const result = urlToCheck.match('^(?:https?:\/\/)?(?:[^@\/\n]+@)?(?:www\\.)?([^:\/?\n]+)');
const result = urlToCheck.match('^(?:https?://)?(?:[^@/\n]+@)?(?:www\\.)?([^:/?\n]+)');
return result[1];
}
}

View File

@@ -18,10 +18,7 @@
/* eslint-disable @angular-eslint/component-selector */
import { Component, ViewEncapsulation, OnInit } from '@angular/core';
import {
WidgetComponent,
FormService
} from '@alfresco/adf-core';
import { WidgetComponent, FormService } from '@alfresco/adf-core';
import { ContentNodeDialogService, NodesApiService } from '@alfresco/adf-content-services';
import { Node } from '@alfresco/js-api';
@@ -43,20 +40,16 @@ import { Node } from '@alfresco/js-api';
encapsulation: ViewEncapsulation.None
})
export class AttachFolderWidgetComponent extends WidgetComponent implements OnInit {
typeId = 'AttachFolderWidgetComponent';
hasFolder: boolean = false;
selectedFolderName: string = '';
constructor(private contentDialog: ContentNodeDialogService,
public formService: FormService,
private nodeService: NodesApiService) {
constructor(private contentDialog: ContentNodeDialogService, public formService: FormService, private nodeService: NodesApiService) {
super();
}
ngOnInit() {
if (this.field &&
this.field.value) {
if (this.field?.value) {
this.hasFolder = true;
this.nodeService.getNode(this.field.value).subscribe((node: Node) => {
this.selectedFolderName = node.name;
@@ -65,27 +58,23 @@ export class AttachFolderWidgetComponent extends WidgetComponent implements OnIn
}
isDefinedSourceFolder(): boolean {
return !!this.field.params &&
!!this.field.params.folderSource &&
!!this.field.params.folderSource.selectedFolder;
return !!this.field.params?.folderSource?.selectedFolder;
}
openSelectDialogFromFileSource() {
const params = this.field.params;
if (this.isDefinedSourceFolder()) {
this.contentDialog.openFolderBrowseDialogByFolderId(params.folderSource.selectedFolder.pathId).subscribe(
(selections: Node[]) => {
this.selectedFolderName = selections[0].name;
this.field.value = selections[0].id;
this.hasFolder = true;
});
this.contentDialog.openFolderBrowseDialogByFolderId(params.folderSource.selectedFolder.pathId).subscribe((selections: Node[]) => {
this.selectedFolderName = selections[0].name;
this.field.value = selections[0].id;
this.hasFolder = true;
});
} else {
this.contentDialog.openFolderBrowseDialogBySite().subscribe(
(selections: Node[]) => {
this.selectedFolderName = selections[0].name;
this.field.value = selections[0].id;
this.hasFolder = true;
});
this.contentDialog.openFolderBrowseDialogBySite().subscribe((selections: Node[]) => {
this.selectedFolderName = selections[0].name;
this.field.value = selections[0].id;
this.hasFolder = true;
});
}
}
@@ -94,5 +83,4 @@ export class AttachFolderWidgetComponent extends WidgetComponent implements OnIn
this.selectedFolderName = '';
this.hasFolder = false;
}
}

View File

@@ -62,7 +62,7 @@ export class ContentWidgetComponent implements OnChanges {
ngOnChanges(changes: SimpleChanges) {
const contentId = changes['id'];
if (contentId && contentId.currentValue) {
if (contentId?.currentValue) {
this.loadContent(contentId.currentValue);
}
}

View File

@@ -18,12 +18,7 @@
/* eslint-disable @angular-eslint/component-selector */
import { Component, OnInit, ViewEncapsulation } from '@angular/core';
import {
FormService,
FormFieldOption,
WidgetComponent,
LogService
} from '@alfresco/adf-core';
import { FormService, FormFieldOption, WidgetComponent, LogService } from '@alfresco/adf-core';
import { ProcessDefinitionService } from '../../services/process-definition.service';
import { TaskFormService } from '../../services/task-form.service';
@@ -45,16 +40,17 @@ import { TaskFormService } from '../../services/task-form.service';
encapsulation: ViewEncapsulation.None
})
export class DropdownWidgetComponent extends WidgetComponent implements OnInit {
constructor(public formService: FormService,
public taskFormService: TaskFormService,
public processDefinitionService: ProcessDefinitionService,
private logService: LogService) {
constructor(
public formService: FormService,
public taskFormService: TaskFormService,
public processDefinitionService: ProcessDefinitionService,
private logService: LogService
) {
super(formService);
}
ngOnInit() {
if (this.field && this.field.restUrl) {
if (this.field?.restUrl) {
if (this.field.form.taskId) {
this.getValuesByTaskId();
} else {
@@ -64,41 +60,31 @@ export class DropdownWidgetComponent extends WidgetComponent implements OnInit {
}
getValuesByTaskId() {
this.taskFormService
.getRestFieldValues(
this.field.form.taskId,
this.field.id
)
.subscribe(
(formFieldOption: FormFieldOption[]) => {
const options = [];
if (this.field.emptyOption) {
options.push(this.field.emptyOption);
}
this.field.options = options.concat((formFieldOption || []));
this.field.updateForm();
},
(err) => this.handleError(err)
);
this.taskFormService.getRestFieldValues(this.field.form.taskId, this.field.id).subscribe(
(formFieldOption) => {
const options = [];
if (this.field.emptyOption) {
options.push(this.field.emptyOption);
}
this.field.options = options.concat(formFieldOption || []);
this.field.updateForm();
},
(err) => this.handleError(err)
);
}
getValuesByProcessDefinitionId() {
this.processDefinitionService
.getRestFieldValuesByProcessId(
this.field.form.processDefinitionId,
this.field.id
)
.subscribe(
(formFieldOption: FormFieldOption[]) => {
const options = [];
if (this.field.emptyOption) {
options.push(this.field.emptyOption);
}
this.field.options = options.concat((formFieldOption || []));
this.field.updateForm();
},
(err) => this.handleError(err)
);
this.processDefinitionService.getRestFieldValuesByProcessId(this.field.form.processDefinitionId, this.field.id).subscribe(
(formFieldOption) => {
const options = [];
if (this.field.emptyOption) {
options.push(this.field.emptyOption);
}
this.field.options = options.concat(formFieldOption || []);
this.field.updateForm();
},
(err) => this.handleError(err)
);
}
getOptionValue(option: FormFieldOption, fieldValue: string): string {

View File

@@ -41,7 +41,6 @@ import { DynamicTableModel } from './editors/models/dynamic-table.widget.model';
encapsulation: ViewEncapsulation.None
})
export class DynamicTableWidgetComponent extends WidgetComponent implements OnInit {
ERROR_MODEL_NOT_FOUND = 'Table model not found';
content: DynamicTableModel;
@@ -51,11 +50,13 @@ export class DynamicTableWidgetComponent extends WidgetComponent implements OnIn
private selectArrayCode = [32, 0, 13];
constructor(public formService: FormService,
public elementRef: ElementRef,
private visibilityService: WidgetVisibilityService,
private logService: LogService,
private cd: ChangeDetectorRef) {
constructor(
public formService: FormService,
public elementRef: ElementRef,
private visibilityService: WidgetVisibilityService,
private logService: LogService,
private cd: ChangeDetectorRef
) {
super(formService);
}
@@ -69,21 +70,21 @@ export class DynamicTableWidgetComponent extends WidgetComponent implements OnIn
forceFocusOnAddButton() {
if (this.content) {
this.cd.detectChanges();
const buttonAddRow = this.elementRef.nativeElement.querySelector('#' + this.content.id + '-add-row');
const buttonAddRow = this.elementRef.nativeElement.querySelector('#' + this.content.id + '-add-row') as HTMLButtonElement;
if (this.isDynamicTableReady(buttonAddRow)) {
buttonAddRow.focus();
}
}
}
private isDynamicTableReady(buttonAddRow) {
private isDynamicTableReady(buttonAddRow: HTMLButtonElement) {
return this.field && !this.editMode && buttonAddRow;
}
isValid() {
let valid = true;
if (this.content && this.content.field) {
if (this.content?.field) {
valid = this.content.field.isValid;
}
@@ -107,7 +108,7 @@ export class DynamicTableWidgetComponent extends WidgetComponent implements OnIn
}
hasSelection(): boolean {
return !!(this.content && this.content.selectedRow);
return !!this.content?.selectedRow;
}
moveSelectionUp(): boolean {
@@ -192,7 +193,7 @@ export class DynamicTableWidgetComponent extends WidgetComponent implements OnIn
}
copyRow(row: DynamicTableRow): DynamicTableRow {
return {value: this.copyObject(row.value)} as DynamicTableRow;
return { value: this.copyObject(row.value) } as DynamicTableRow;
}
private copyObject(obj: any): any {

View File

@@ -17,12 +17,7 @@
/* eslint-disable @angular-eslint/component-selector */
import {
UserPreferencesService,
UserPreferenceValues,
MomentDateAdapter,
MOMENT_DATE_FORMATS
} from '@alfresco/adf-core';
import { UserPreferencesService, UserPreferenceValues, MomentDateAdapter, MOMENT_DATE_FORMATS } from '@alfresco/adf-core';
import { Component, Input, OnInit, OnDestroy } from '@angular/core';
import { DateAdapter, MAT_DATE_FORMATS } from '@angular/material/core';
import { MatDatepickerInputEvent } from '@angular/material/datepicker';
@@ -37,12 +32,12 @@ import { takeUntil } from 'rxjs/operators';
selector: 'adf-date-editor',
templateUrl: './date.editor.html',
providers: [
{provide: DateAdapter, useClass: MomentDateAdapter},
{provide: MAT_DATE_FORMATS, useValue: MOMENT_DATE_FORMATS}],
{ provide: DateAdapter, useClass: MomentDateAdapter },
{ provide: MAT_DATE_FORMATS, useValue: MOMENT_DATE_FORMATS }
],
styleUrls: ['./date.editor.scss']
})
export class DateEditorComponent implements OnInit, OnDestroy {
DATE_FORMAT: string = 'DD-MM-YYYY';
value: any;
@@ -61,15 +56,13 @@ export class DateEditorComponent implements OnInit, OnDestroy {
private onDestroy$ = new Subject<boolean>();
constructor(private dateAdapter: DateAdapter<Moment>,
private userPreferencesService: UserPreferencesService) {
}
constructor(private dateAdapter: DateAdapter<Moment>, private userPreferencesService: UserPreferencesService) {}
ngOnInit() {
this.userPreferencesService
.select(UserPreferenceValues.Locale)
.pipe(takeUntil(this.onDestroy$))
.subscribe(locale => this.dateAdapter.setLocale(locale));
.subscribe((locale) => this.dateAdapter.setLocale(locale));
const momentDateAdapter = this.dateAdapter as MomentDateAdapter;
momentDateAdapter.overrideDisplayFormat = this.DATE_FORMAT;
@@ -83,7 +76,7 @@ export class DateEditorComponent implements OnInit, OnDestroy {
}
onDateChanged(newDateValue: MatDatepickerInputEvent<any> | HTMLInputElement) {
if (newDateValue && newDateValue.value) {
if (newDateValue?.value) {
/* validates the user inputs */
const momentDate = moment(newDateValue.value, this.DATE_FORMAT, true);
@@ -98,5 +91,4 @@ export class DateEditorComponent implements OnInit, OnDestroy {
this.row.value[this.column.id] = '';
}
}
}

View File

@@ -17,12 +17,7 @@
/* eslint-disable @angular-eslint/component-selector */
import {
MOMENT_DATE_FORMATS,
MomentDateAdapter,
UserPreferencesService,
UserPreferenceValues
} from '@alfresco/adf-core';
import { MOMENT_DATE_FORMATS, MomentDateAdapter, UserPreferencesService, UserPreferenceValues } from '@alfresco/adf-core';
import { Component, Input, OnInit, OnDestroy } from '@angular/core';
import { DateAdapter, MAT_DATE_FORMATS } from '@angular/material/core';
import moment, { Moment } from 'moment';
@@ -38,15 +33,14 @@ import { takeUntil } from 'rxjs/operators';
selector: 'adf-datetime-editor',
templateUrl: './datetime.editor.html',
providers: [
{provide: DateAdapter, useClass: MomentDateAdapter},
{provide: MAT_DATE_FORMATS, useValue: MOMENT_DATE_FORMATS},
{provide: DatetimeAdapter, useClass: MomentDatetimeAdapter},
{provide: MAT_DATETIME_FORMATS, useValue: MAT_MOMENT_DATETIME_FORMATS}
{ provide: DateAdapter, useClass: MomentDateAdapter },
{ provide: MAT_DATE_FORMATS, useValue: MOMENT_DATE_FORMATS },
{ provide: DatetimeAdapter, useClass: MomentDatetimeAdapter },
{ provide: MAT_DATETIME_FORMATS, useValue: MAT_MOMENT_DATETIME_FORMATS }
],
styleUrls: ['./datetime.editor.scss']
})
export class DateTimeEditorComponent implements OnInit, OnDestroy {
DATE_TIME_FORMAT: string = 'DD/MM/YYYY HH:mm';
value: any;
@@ -65,15 +59,13 @@ export class DateTimeEditorComponent implements OnInit, OnDestroy {
private onDestroy$ = new Subject<boolean>();
constructor(private dateAdapter: DateAdapter<Moment>,
private userPreferencesService: UserPreferencesService) {
}
constructor(private dateAdapter: DateAdapter<Moment>, private userPreferencesService: UserPreferencesService) {}
ngOnInit() {
this.userPreferencesService
.select(UserPreferenceValues.Locale)
.pipe(takeUntil(this.onDestroy$))
.subscribe(locale => this.dateAdapter.setLocale(locale));
.subscribe((locale) => this.dateAdapter.setLocale(locale));
const momentDateAdapter = this.dateAdapter as MomentDateAdapter;
momentDateAdapter.overrideDisplayFormat = this.DATE_TIME_FORMAT;
@@ -87,7 +79,7 @@ export class DateTimeEditorComponent implements OnInit, OnDestroy {
}
onDateChanged(newDateValue) {
if (newDateValue && newDateValue.value) {
if (newDateValue?.value) {
const newValue = moment(newDateValue.value, this.DATE_TIME_FORMAT);
this.row.value[this.column.id] = newDateValue.value.format(this.DATE_TIME_FORMAT);
this.value = newValue;
@@ -101,5 +93,4 @@ export class DateTimeEditorComponent implements OnInit, OnDestroy {
this.row.value[this.column.id] = '';
}
}
}

View File

@@ -17,14 +17,14 @@
/* eslint-disable @angular-eslint/component-selector */
import { LogService, FormService } from '@alfresco/adf-core';
import { LogService, FormService, FormFieldModel } from '@alfresco/adf-core';
import { Component, Input, OnInit } from '@angular/core';
import { DynamicTableColumnOption } from '../models/dynamic-table-column-option.model';
import { DynamicTableColumn } from '../models/dynamic-table-column.model';
import { DynamicTableRow } from '../models/dynamic-table-row.model';
import { DynamicTableModel } from '../models/dynamic-table.widget.model';
import { ProcessDefinitionService } from '../../../../services/process-definition.service';
import { TaskFormService } from '../../../../services/task-form.service';
import { TaskFormService } from '../../../../services/task-form.service';
@Component({
selector: 'adf-dropdown-editor',
@@ -32,7 +32,6 @@ import { TaskFormService } from '../../../../services/task-form.service';
styleUrls: ['./dropdown.editor.scss']
})
export class DropdownEditorComponent implements OnInit {
value: any = null;
options: DynamicTableColumnOption[] = [];
@@ -45,17 +44,18 @@ export class DropdownEditorComponent implements OnInit {
@Input()
column: DynamicTableColumn;
constructor(public formService: FormService,
private taskFormService: TaskFormService,
private processDefinitionService: ProcessDefinitionService,
private logService: LogService) {
}
constructor(
public formService: FormService,
private taskFormService: TaskFormService,
private processDefinitionService: ProcessDefinitionService,
private logService: LogService
) {}
ngOnInit() {
const field = this.table.field;
if (field) {
if (this.column.optionType === 'rest') {
if (this.table.form && this.table.form.taskId) {
if (this.table.form?.taskId) {
this.getValuesByTaskId(field);
} else {
this.getValuesByProcessDefinitionId(field);
@@ -67,38 +67,26 @@ export class DropdownEditorComponent implements OnInit {
}
}
getValuesByTaskId(field) {
this.taskFormService
.getRestFieldValuesColumn(
field.form.taskId,
field.id,
this.column.id
)
.subscribe(
(dynamicTableColumnOption: DynamicTableColumnOption[]) => {
this.column.options = dynamicTableColumnOption || [];
this.options = this.column.options;
this.value = this.table.getCellValue(this.row, this.column);
},
(err) => this.handleError(err)
);
getValuesByTaskId(field: FormFieldModel) {
this.taskFormService.getRestFieldValuesColumn(field.form.taskId, field.id, this.column.id).subscribe(
(dynamicTableColumnOption) => {
this.column.options = dynamicTableColumnOption || [];
this.options = this.column.options;
this.value = this.table.getCellValue(this.row, this.column);
},
(err) => this.handleError(err)
);
}
getValuesByProcessDefinitionId(field) {
this.processDefinitionService
.getRestFieldValuesColumnByProcessId(
field.form.processDefinitionId,
field.id,
this.column.id
)
.subscribe(
(dynamicTableColumnOption: DynamicTableColumnOption[]) => {
this.column.options = dynamicTableColumnOption || [];
this.options = this.column.options;
this.value = this.table.getCellValue(this.row, this.column);
},
(err) => this.handleError(err)
);
getValuesByProcessDefinitionId(field: FormFieldModel) {
this.processDefinitionService.getRestFieldValuesColumnByProcessId(field.form.processDefinitionId, field.id, this.column.id).subscribe(
(dynamicTableColumnOption) => {
this.column.options = dynamicTableColumnOption || [];
this.options = this.column.options;
this.value = this.table.getCellValue(this.row, this.column);
},
(err) => this.handleError(err)
);
}
onValueChanged(row: DynamicTableRow, column: DynamicTableColumn, event: any) {

View File

@@ -24,17 +24,13 @@ import { DynamicTableColumn } from './dynamic-table-column.model';
import { DynamicTableRow } from './dynamic-table-row.model';
export class DateCellValidator implements CellValidator {
private supportedTypes: string[] = [
'Date'
];
private supportedTypes: string[] = ['Date'];
isSupported(column: DynamicTableColumn): boolean {
return column && column.editable && this.supportedTypes.indexOf(column.type) > -1;
return column?.editable && this.supportedTypes.indexOf(column.type) > -1;
}
validate(row: DynamicTableRow, column: DynamicTableColumn, summary?: DynamicRowValidationSummary): boolean {
if (this.isSupported(column)) {
const value = row.value[column.id];

View File

@@ -29,7 +29,6 @@ import { NumberCellValidator } from './number-cell-validator.model';
import { RequiredCellValidator } from './required-cell-validator.model';
export class DynamicTableModel extends FormWidgetModel {
field: FormFieldModel;
columns: DynamicTableColumn[] = [];
visibleColumns: DynamicTableColumn[] = [];
@@ -49,7 +48,7 @@ export class DynamicTableModel extends FormWidgetModel {
return;
}
this.rows.forEach((row) => row.selected = false);
this.rows.forEach((row) => (row.selected = false));
this._selectedRow = value;
@@ -70,19 +69,15 @@ export class DynamicTableModel extends FormWidgetModel {
}
if (field.json.value) {
this.rows = field.json.value.map((obj) => ({selected: false, value: obj} as DynamicTableRow));
this.rows = field.json.value.map((obj) => ({ selected: false, value: obj } as DynamicTableRow));
}
}
this._validators = [
new RequiredCellValidator(),
new DateCellValidator(),
new NumberCellValidator()
];
this._validators = [new RequiredCellValidator(), new DateCellValidator(), new NumberCellValidator()];
}
private getColumns(field: FormFieldModel): DynamicTableColumn[] {
if (field && field.json) {
if (field?.json) {
let definitions = field.json.columnDefinitions;
if (!definitions && field.json.params && field.json.params.field) {
definitions = field.json.params.field.columnDefinitions;
@@ -105,7 +100,7 @@ export class DynamicTableModel extends FormWidgetModel {
moveRow(row: DynamicTableRow, offset: number) {
const oldIndex = this.rows.indexOf(row);
if (oldIndex > -1) {
let newIndex = (oldIndex + offset);
let newIndex = oldIndex + offset;
if (newIndex < 0) {
newIndex = 0;

View File

@@ -23,14 +23,10 @@ import { DynamicTableColumn } from './dynamic-table-column.model';
import { DynamicTableRow } from './dynamic-table-row.model';
export class NumberCellValidator implements CellValidator {
private supportedTypes: string[] = [
'Number',
'Amount'
];
private supportedTypes: string[] = ['Number', 'Amount'];
isSupported(column: DynamicTableColumn): boolean {
return column && column.required && this.supportedTypes.indexOf(column.type) > -1;
return column?.required && this.supportedTypes.indexOf(column.type) > -1;
}
isNumber(value: any): boolean {
@@ -42,13 +38,9 @@ export class NumberCellValidator implements CellValidator {
}
validate(row: DynamicTableRow, column: DynamicTableColumn, summary?: DynamicRowValidationSummary): boolean {
if (this.isSupported(column)) {
const value = row.value[column.id];
if (value === null ||
value === undefined ||
value === '' ||
this.isNumber(value)) {
if (value === null || value === undefined || value === '' || this.isNumber(value)) {
return true;
}

View File

@@ -23,17 +23,10 @@ import { DynamicTableColumn } from './dynamic-table-column.model';
import { DynamicTableRow } from './dynamic-table-row.model';
export class RequiredCellValidator implements CellValidator {
private supportedTypes: string[] = [
'String',
'Number',
'Amount',
'Date',
'Dropdown'
];
private supportedTypes: string[] = ['String', 'Number', 'Amount', 'Date', 'Dropdown'];
isSupported(column: DynamicTableColumn): boolean {
return column && column.required && this.supportedTypes.indexOf(column.type) > -1;
return column?.required && this.supportedTypes.indexOf(column.type) > -1;
}
validate(row: DynamicTableRow, column: DynamicTableColumn, summary?: DynamicRowValidationSummary): boolean {

View File

@@ -15,7 +15,7 @@
* limitations under the License.
*/
/* eslint-disable @angular-eslint/component-selector */
/* eslint-disable @angular-eslint/component-selector */
import { Component, EventEmitter, Input, Output } from '@angular/core';
import { DynamicRowValidationSummary } from '../models/dynamic-row-validation-summary.model';
@@ -29,7 +29,6 @@ import { DynamicTableModel } from '../models/dynamic-table.widget.model';
styleUrls: ['./row.editor.css']
})
export class RowEditorComponent {
@Input()
table: DynamicTableModel;
@@ -71,11 +70,10 @@ export class RowEditorComponent {
}
private isValid(): boolean {
return this.validationSummary && this.validationSummary.isValid;
return this.validationSummary?.isValid;
}
private validate() {
this.validationSummary = this.table.validateRow(this.row);
}
}

View File

@@ -42,7 +42,6 @@ import { PeopleProcessService } from '../../../common/services/people-process.se
encapsulation: ViewEncapsulation.None
})
export class FunctionalGroupWidgetComponent extends WidgetComponent implements OnInit {
minTermLength: number = 1;
groupId: string;
searchTerm = new UntypedFormControl();
@@ -50,30 +49,26 @@ export class FunctionalGroupWidgetComponent extends WidgetComponent implements O
tap((search: GroupModel | string) => {
const isValid = typeof search !== 'string';
const empty = search === '';
this.updateOption(isValid ? search as GroupModel : null);
this.updateOption(isValid ? (search as GroupModel) : null);
this.validateGroup(isValid, empty);
}),
filter((group: string | GroupModel) => typeof group === 'string' && group.length >= this.minTermLength),
debounceTime(300),
switchMap((searchTerm: string) => this.peopleProcessService.getWorkflowGroups(searchTerm, this.groupId)
.pipe(catchError(() => of([]))))
switchMap((searchTerm: string) => this.peopleProcessService.getWorkflowGroups(searchTerm, this.groupId).pipe(catchError(() => of([]))))
);
constructor(public peopleProcessService: PeopleProcessService,
public formService: FormService,
public elementRef: ElementRef) {
constructor(public peopleProcessService: PeopleProcessService, public formService: FormService, public elementRef: ElementRef) {
super(formService);
}
ngOnInit() {
if (this.field) {
if (this.field.readOnly) {
this.searchTerm.disable();
}
const params = this.field.params;
if (params && params.restrictWithGroup) {
if (params?.restrictWithGroup) {
const restrictWithGroup = params.restrictWithGroup;
this.groupId = restrictWithGroup.id;
}

View File

@@ -21,13 +21,7 @@ import { FormService, WidgetComponent } from '@alfresco/adf-core';
import { Component, ElementRef, EventEmitter, OnInit, Output, ViewChild, ViewEncapsulation } from '@angular/core';
import { UntypedFormControl } from '@angular/forms';
import { Observable, of } from 'rxjs';
import {
catchError,
distinctUntilChanged,
map,
switchMap,
tap
} from 'rxjs/operators';
import { catchError, distinctUntilChanged, map, switchMap, tap } from 'rxjs/operators';
import { UserProcessModel } from '../../../common/models/user-process.model';
import { PeopleProcessService } from '../../../common/services/people-process.service';
@@ -49,7 +43,6 @@ import { PeopleProcessService } from '../../../common/services/people-process.se
encapsulation: ViewEncapsulation.None
})
export class PeopleWidgetComponent extends WidgetComponent implements OnInit {
@ViewChild('inputValue', { static: true })
input: ElementRef;
@@ -71,8 +64,7 @@ export class PeopleWidgetComponent extends WidgetComponent implements OnInit {
distinctUntilChanged(),
switchMap((searchTerm) => {
const value = searchTerm.email ? this.getDisplayName(searchTerm) : searchTerm;
return this.peopleProcessService.getWorkflowUsers(undefined, value, this.groupId)
.pipe(catchError(() => of([])));
return this.peopleProcessService.getWorkflowUsers(undefined, value, this.groupId).pipe(catchError(() => of([])));
}),
map((list: UserProcessModel[]) => {
const value = this.searchTerm.value.email ? this.getDisplayName(this.searchTerm.value) : this.searchTerm.value;
@@ -94,7 +86,7 @@ export class PeopleWidgetComponent extends WidgetComponent implements OnInit {
this.searchTerm.disable();
}
const params = this.field.params;
if (params && params.restrictWithGroup) {
if (params?.restrictWithGroup) {
const restrictWithGroup = params.restrictWithGroup;
this.groupId = restrictWithGroup.id;
}
@@ -119,7 +111,7 @@ export class PeopleWidgetComponent extends WidgetComponent implements OnInit {
return !!users.find((user) => {
const selectedUser = this.getDisplayName(user).toLocaleLowerCase() === name.toLocaleLowerCase();
if (selectedUser) {
this.peopleSelected.emit(user && user.id || undefined);
this.peopleSelected.emit(user?.id || undefined);
}
return selectedUser;
});

View File

@@ -17,7 +17,7 @@
/* eslint-disable @angular-eslint/component-selector */
import { LogService, FormService, FormFieldOption, WidgetComponent } from '@alfresco/adf-core';
import { LogService, FormService, WidgetComponent } from '@alfresco/adf-core';
import { Component, OnInit, ViewEncapsulation } from '@angular/core';
import { TaskFormService } from '../../services/task-form.service';
import { ProcessDefinitionService } from '../../services/process-definition.service';
@@ -40,16 +40,17 @@ import { ProcessDefinitionService } from '../../services/process-definition.serv
encapsulation: ViewEncapsulation.None
})
export class RadioButtonsWidgetComponent extends WidgetComponent implements OnInit {
constructor(public formService: FormService,
private taskFormService: TaskFormService,
private processDefinitionService: ProcessDefinitionService,
private logService: LogService) {
constructor(
public formService: FormService,
private taskFormService: TaskFormService,
private processDefinitionService: ProcessDefinitionService,
private logService: LogService
) {
super(formService);
}
ngOnInit() {
if (this.field && this.field.restUrl) {
if (this.field?.restUrl) {
if (this.field.form.taskId) {
this.getOptionsByTaskId();
} else {
@@ -59,33 +60,23 @@ export class RadioButtonsWidgetComponent extends WidgetComponent implements OnIn
}
getOptionsByTaskId() {
this.taskFormService
.getRestFieldValues(
this.field.form.taskId,
this.field.id
)
.subscribe(
(formFieldOption: FormFieldOption[]) => {
this.field.options = formFieldOption || [];
this.field.updateForm();
},
(err) => this.handleError(err)
);
this.taskFormService.getRestFieldValues(this.field.form.taskId, this.field.id).subscribe(
(formFieldOption) => {
this.field.options = formFieldOption || [];
this.field.updateForm();
},
(err) => this.handleError(err)
);
}
getOptionsByProcessDefinitionId() {
this.processDefinitionService
.getRestFieldValuesByProcessId(
this.field.form.processDefinitionId,
this.field.id
)
.subscribe(
(formFieldOption: FormFieldOption[]) => {
this.field.options = formFieldOption || [];
this.field.updateForm();
},
(err) => this.handleError(err)
);
this.processDefinitionService.getRestFieldValuesByProcessId(this.field.form.processDefinitionId, this.field.id).subscribe(
(formFieldOption) => {
this.field.options = formFieldOption || [];
this.field.updateForm();
},
(err) => this.handleError(err)
);
}
onOptionClick(optionSelected: any) {
@@ -96,5 +87,4 @@ export class RadioButtonsWidgetComponent extends WidgetComponent implements OnIn
handleError(error: any) {
this.logService.error(error);
}
}

View File

@@ -41,16 +41,17 @@ import { ProcessDefinitionService } from '../../services/process-definition.serv
encapsulation: ViewEncapsulation.None
})
export class TypeaheadWidgetComponent extends WidgetComponent implements OnInit {
minTermLength: number = 1;
value: string;
oldValue: string;
options: FormFieldOption[] = [];
constructor(public formService: FormService,
private taskFormService: TaskFormService,
private processDefinitionService: ProcessDefinitionService,
private logService: LogService) {
constructor(
public formService: FormService,
private taskFormService: TaskFormService,
private processDefinitionService: ProcessDefinitionService,
private logService: LogService
) {
super(formService);
}
@@ -66,53 +67,45 @@ export class TypeaheadWidgetComponent extends WidgetComponent implements OnInit
}
getValuesByTaskId() {
this.taskFormService
.getRestFieldValues(
this.field.form.taskId,
this.field.id
)
.subscribe(
(formFieldOption: FormFieldOption[]) => {
const options = formFieldOption || [];
this.field.options = options;
this.taskFormService.getRestFieldValues(this.field.form.taskId, this.field.id).subscribe(
(formFieldOption) => {
const options = formFieldOption || [];
this.field.options = options;
const fieldValue = this.field.value;
if (fieldValue) {
const toSelect = options.find((item) => item.id === fieldValue || item.name.toLocaleLowerCase() === fieldValue.toLocaleLowerCase());
if (toSelect) {
this.value = toSelect.name;
}
const fieldValue = this.field.value;
if (fieldValue) {
const toSelect = options.find(
(item) => item.id === fieldValue || item.name.toLocaleLowerCase() === fieldValue.toLocaleLowerCase()
);
if (toSelect) {
this.value = toSelect.name;
}
this.onFieldChanged(this.field);
this.field.updateForm();
},
(err) => this.handleError(err)
);
}
this.onFieldChanged(this.field);
this.field.updateForm();
},
(err) => this.handleError(err)
);
}
getValuesByProcessDefinitionId() {
this.processDefinitionService
.getRestFieldValuesByProcessId(
this.field.form.processDefinitionId,
this.field.id
)
.subscribe(
(formFieldOption: FormFieldOption[]) => {
const options = formFieldOption || [];
this.field.options = options;
this.processDefinitionService.getRestFieldValuesByProcessId(this.field.form.processDefinitionId, this.field.id).subscribe(
(formFieldOption) => {
const options = formFieldOption || [];
this.field.options = options;
const fieldValue = this.field.value;
if (fieldValue) {
const toSelect = options.find((item) => item.id === fieldValue);
if (toSelect) {
this.value = toSelect.name;
}
const fieldValue = this.field.value;
if (fieldValue) {
const toSelect = options.find((item) => item.id === fieldValue);
if (toSelect) {
this.value = toSelect.name;
}
this.onFieldChanged(this.field);
this.field.updateForm();
},
(err) => this.handleError(err)
);
}
this.onFieldChanged(this.field);
this.field.updateForm();
},
(err) => this.handleError(err)
);
}
getOptions(): FormFieldOption[] {
@@ -169,5 +162,4 @@ export class TypeaheadWidgetComponent extends WidgetComponent implements OnInit
isReadOnlyType(): boolean {
return this.field.type === 'readonly';
}
}

View File

@@ -41,7 +41,6 @@ import { mergeMap, map } from 'rxjs/operators';
encapsulation: ViewEncapsulation.None
})
export class UploadWidgetComponent extends WidgetComponent implements OnInit {
hasFile: boolean;
displayText: string;
multipleOption: string = '';
@@ -50,17 +49,17 @@ export class UploadWidgetComponent extends WidgetComponent implements OnInit {
@ViewChild('uploadFiles')
fileInput: ElementRef;
constructor(public formService: FormService,
private logService: LogService,
private thumbnailService: ThumbnailService,
public processContentService: ProcessContentService) {
constructor(
public formService: FormService,
private logService: LogService,
private thumbnailService: ThumbnailService,
public processContentService: ProcessContentService
) {
super(formService);
}
ngOnInit() {
if (this.field &&
this.field.value &&
this.field.value.length > 0) {
if (this.field?.value?.length > 0) {
this.hasFile = true;
}
this.getMultipleFileParam();
@@ -96,20 +95,17 @@ export class UploadWidgetComponent extends WidgetComponent implements OnInit {
}
private uploadRawContent(file): Observable<any> {
return this.processContentService.createTemporaryRawRelatedContent(file)
.pipe(
map((response: any) => {
this.logService.info(response);
response.contentBlob = file;
return response;
})
);
return this.processContentService.createTemporaryRawRelatedContent(file).pipe(
map((response: any) => {
this.logService.info(response);
response.contentBlob = file;
return response;
})
);
}
getMultipleFileParam() {
if (this.field &&
this.field.params &&
this.field.params.multiple) {
if (this.field?.params?.multiple) {
this.multipleOption = this.field.params.multiple ? 'multiple' : '';
}
}

View File

@@ -39,15 +39,19 @@ export const fakeProcessFilters = [
];
export const fakeProcessFiltersResponse = {
size: 1, total: 1, start: 0,
data: [new FilterProcessRepresentationModel({
name: 'Running',
appId: '22',
id: 333,
recent: true,
icon: 'glyphicon-random',
filter: { sort: 'created-desc', name: '', state: 'running' }
})]
size: 1,
total: 1,
start: 0,
data: [
new FilterProcessRepresentationModel({
name: 'Running',
appId: '22',
id: 333,
recent: true,
icon: 'glyphicon-random',
filter: { sort: 'created-desc', name: '', state: 'running' }
})
]
};
export const dummyRunningFilter = {
@@ -58,9 +62,7 @@ export const dummyRunningFilter = {
id: 18,
index: 10,
recent: false,
hasFilter: () => {
return true;
}
hasFilter: () => true
};
export const dummyCompletedFilter = {
@@ -71,9 +73,7 @@ export const dummyCompletedFilter = {
id: 19,
index: 11,
recent: false,
hasFilter: () => {
return true;
}
hasFilter: () => true
};
export const dummyAllFilter = {
@@ -84,9 +84,7 @@ export const dummyAllFilter = {
id: 20,
index: 12,
recent: false,
hasFilter: () => {
return true;
}
hasFilter: () => true
};
export const dummyDuplicateRunningFilter = {
@@ -97,7 +95,5 @@ export const dummyDuplicateRunningFilter = {
id: 21,
index: 13,
recent: false,
hasFilter: () => {
return true;
}
hasFilter: () => true
};

View File

@@ -18,14 +18,22 @@
import { FilterRepresentationModel, TaskQueryRequestRepresentationModel } from '../../task-list/models/filter.model';
export const fakeFiltersResponse: any = {
size: 2, total: 2, start: 0,
size: 2,
total: 2,
start: 0,
data: [
{
id: 1, name: 'FakeInvolvedTasks', recent: false, icon: 'glyphicon-align-left',
id: 1,
name: 'FakeInvolvedTasks',
recent: false,
icon: 'glyphicon-align-left',
filter: { sort: 'created-desc', name: '', state: 'open', assignment: 'fake-involved' }
},
{
id: 2, name: 'FakeMyTasks', recent: false, icon: 'glyphicon-align-left',
id: 2,
name: 'FakeMyTasks',
recent: false,
icon: 'glyphicon-align-left',
filter: { sort: 'created-desc', name: '', state: 'open', assignment: 'fake-assignee' }
}
]
@@ -53,10 +61,15 @@ export const fakeTaskFilters = [
];
export const fakeAppFilter = {
size: 1, total: 1, start: 0,
size: 1,
total: 1,
start: 0,
data: [
{
id: 1, name: 'FakeInvolvedTasks', recent: false, icon: 'glyphicon-align-left',
id: 1,
name: 'FakeInvolvedTasks',
recent: false,
icon: 'glyphicon-align-left',
filter: { sort: 'created-desc', name: '', state: 'open', assignment: 'fake-involved' }
}
]
@@ -111,9 +124,7 @@ export const dummyMyTasksFilter = {
id: 81,
index: 21,
recent: false,
hasFilter: () => {
return true;
}
hasFilter: () => true
};
export const dummyInvolvedTasksFilter = {
@@ -124,9 +135,7 @@ export const dummyInvolvedTasksFilter = {
id: 82,
index: 22,
recent: false,
hasFilter: () => {
return true;
}
hasFilter: () => true
};
export const dummyQueuedTasksFilter = {
@@ -137,9 +146,7 @@ export const dummyQueuedTasksFilter = {
id: 83,
index: 23,
recent: false,
hasFilter: () => {
return true;
}
hasFilter: () => true
};
export const dummyCompletedTasksFilter = {
@@ -150,9 +157,7 @@ export const dummyCompletedTasksFilter = {
id: 84,
index: 24,
recent: false,
hasFilter: () => {
return true;
}
hasFilter: () => true
};
export const dummyDuplicateMyTasksFilter = {
@@ -163,7 +168,5 @@ export const dummyDuplicateMyTasksFilter = {
id: 85,
index: 25,
recent: false,
hasFilter: () => {
return true;
}
hasFilter: () => true
};

View File

@@ -32,9 +32,7 @@ import { UserProcessModel } from '../../../common/models/user-process.model';
host: { class: 'adf-people-search-field' },
encapsulation: ViewEncapsulation.None
})
export class PeopleSearchFieldComponent {
@Input()
performSearch: PerformSearchCallback;
@@ -49,19 +47,17 @@ export class PeopleSearchFieldComponent {
defaultPlaceholder = 'ADF_TASK_LIST.PEOPLE.SEARCH_USER';
constructor(public peopleProcessService: PeopleProcessService,
private translationService: TranslationService) {
this.users$ = this.searchUser.valueChanges
.pipe(
debounceTime(200),
switchMap((searchWord: string) => {
if (searchWord && searchWord.trim()) {
return this.performSearch(searchWord);
} else {
return of([]);
}
})
);
constructor(public peopleProcessService: PeopleProcessService, private translationService: TranslationService) {
this.users$ = this.searchUser.valueChanges.pipe(
debounceTime(200),
switchMap((searchWord: string) => {
if (searchWord?.trim()) {
return this.performSearch(searchWord);
} else {
return of([]);
}
})
);
this.defaultPlaceholder = this.translationService.instant(this.defaultPlaceholder);
}
@@ -83,8 +79,8 @@ export class PeopleSearchFieldComponent {
}
getInitialUserName(firstName: string, lastName: string): string {
firstName = (firstName !== null && firstName !== '' ? firstName[0] : '');
lastName = (lastName !== null && lastName !== '' ? lastName[0] : '');
firstName = firstName !== null && firstName !== '' ? firstName[0] : '';
lastName = lastName !== null && lastName !== '' ? lastName[0] : '';
return this.getDisplayUser(firstName, lastName, '');
}
}

View File

@@ -34,9 +34,7 @@ const DEFAULT_ASSIGNEE_PLACEHOLDER = 'ADF_TASK_LIST.PEOPLE.ASSIGNEE';
host: { class: 'adf-people-selector' },
encapsulation: ViewEncapsulation.None
})
export class PeopleSelectorComponent {
@Input()
peopleId: UserProcessModel;
@@ -51,21 +49,14 @@ export class PeopleSelectorComponent {
selectedUser: UserProcessModel;
defaultPlaceholder: string;
constructor(
private peopleProcessService: PeopleProcessService,
private logService: LogService,
private translationService: TranslationService) {
constructor(private peopleProcessService: PeopleProcessService, private logService: LogService, private translationService: TranslationService) {
this.peopleIdChange = new EventEmitter();
this.performSearch = this.searchUser.bind(this);
this.defaultPlaceholder = this.translationService.instant(DEFAULT_ASSIGNEE_PLACEHOLDER);
}
searchUser(searchWord: string): Observable<any | UserProcessModel[]> {
return this.peopleProcessService.getWorkflowUsers(undefined, searchWord)
.pipe(
catchError(this.onSearchUserError.bind(this))
);
return this.peopleProcessService.getWorkflowUsers(undefined, searchWord).pipe(catchError(this.onSearchUserError.bind(this)));
}
userSelected(user: UserProcessModel): void {
@@ -83,7 +74,7 @@ export class PeopleSelectorComponent {
private updateUserSelection(user: UserProcessModel): void {
this.selectedUser = user;
this.peopleIdChange.emit(user && user.id || undefined);
this.peopleIdChange.emit(user?.id);
this.searchFieldComponent.reset();
}

View File

@@ -29,7 +29,6 @@ import { share, takeUntil } from 'rxjs/operators';
host: { class: 'adf-process-instance-comments' }
})
export class ProcessCommentsComponent implements OnChanges, OnDestroy {
/** (**required**) The numeric ID of the process instance to display comments for. */
@Input()
processInstanceId: string;
@@ -42,7 +41,7 @@ export class ProcessCommentsComponent implements OnChanges, OnDestroy {
@Output()
error: EventEmitter<any> = new EventEmitter<any>();
comments: CommentModel [] = [];
comments: CommentModel[] = [];
comment$: Observable<CommentModel>;
message: string;
beingAdded: boolean = false;
@@ -51,10 +50,8 @@ export class ProcessCommentsComponent implements OnChanges, OnDestroy {
private onDestroy$ = new Subject<boolean>();
constructor(private commentProcessService: CommentProcessService) {
this.comment$ = new Observable<CommentModel>(observer => this.commentObserver = observer).pipe(share());
this.comment$
.pipe(takeUntil(this.onDestroy$))
.subscribe(comment => this.comments.push(comment));
this.comment$ = new Observable<CommentModel>((observer) => (this.commentObserver = observer)).pipe(share());
this.comment$.pipe(takeUntil(this.onDestroy$)).subscribe((comment) => this.comments.push(comment));
}
ngOnDestroy() {
@@ -74,21 +71,19 @@ export class ProcessCommentsComponent implements OnChanges, OnDestroy {
}
add(): void {
if (this.message && this.message.trim() && !this.beingAdded) {
if (this.message?.trim() && !this.beingAdded) {
this.beingAdded = true;
this.commentProcessService.add(this.processInstanceId, this.message)
.subscribe(
(res: CommentModel) => {
this.comments.unshift(res);
this.message = '';
this.beingAdded = false;
},
(err) => {
this.error.emit(err);
this.beingAdded = false;
}
);
this.commentProcessService.add(this.processInstanceId, this.message).subscribe(
(res: CommentModel) => {
this.comments.unshift(res);
this.message = '';
this.beingAdded = false;
},
(err) => {
this.error.emit(err);
this.beingAdded = false;
}
);
}
}

View File

@@ -33,7 +33,6 @@ import { Location } from '@angular/common';
encapsulation: ViewEncapsulation.None
})
export class ProcessFiltersComponent implements OnInit, OnChanges, OnDestroy {
/** The parameters to filter the task filter. If there is no match then the default one
* (ie, the first filter in the list) is selected.
*/
@@ -72,7 +71,7 @@ export class ProcessFiltersComponent implements OnInit, OnChanges, OnDestroy {
currentFilter: ProcessInstanceFilterRepresentation;
filters: UserProcessInstanceFilterRepresentation [] = [];
filters: UserProcessInstanceFilterRepresentation[] = [];
active = false;
isProcessRoute: boolean;
isProcessActive: boolean;
@@ -80,23 +79,24 @@ export class ProcessFiltersComponent implements OnInit, OnChanges, OnDestroy {
private iconsMDL: IconModel;
constructor(private processFilterService: ProcessFilterService,
private appsProcessService: AppsProcessService,
private router: Router,
private location: Location) {
}
constructor(
private processFilterService: ProcessFilterService,
private appsProcessService: AppsProcessService,
private router: Router,
private location: Location
) {}
ngOnInit() {
this.iconsMDL = new IconModel();
this.router.events
.pipe(
filter((event) => event instanceof NavigationStart),
takeUntil(this.onDestroy$)
)
.subscribe((navigationStart: NavigationStart) => {
const activeRoute = navigationStart.url;
this.isProcessActive = activeRoute.includes('processes');
});
.pipe(
filter((event) => event instanceof NavigationStart),
takeUntil(this.onDestroy$)
)
.subscribe((navigationStart: NavigationStart) => {
const activeRoute = navigationStart.url;
this.isProcessActive = activeRoute.includes('processes');
});
const currentRoute = this.location.path();
this.isProcessRoute = currentRoute.includes('processes');
}
@@ -108,7 +108,7 @@ export class ProcessFiltersComponent implements OnInit, OnChanges, OnDestroy {
if (appId && (appId.currentValue || appId.currentValue === null)) {
this.getFiltersByAppId(appId.currentValue);
} else if (appName && appName.currentValue) {
} else if (appName?.currentValue) {
this.getFiltersByAppName(appName.currentValue);
} else if (filterParam && filterParam.currentValue !== filterParam.previousValue) {
this.selectProcessFilter(filterParam.currentValue);
@@ -165,7 +165,8 @@ export class ProcessFiltersComponent implements OnInit, OnChanges, OnDestroy {
},
(err) => {
this.error.emit(err);
});
}
);
}
/**
@@ -184,12 +185,12 @@ export class ProcessFiltersComponent implements OnInit, OnChanges, OnDestroy {
*/
selectProcessFilter(filterParam: FilterProcessRepresentationModel) {
if (filterParam) {
const newFilter = this.filters.find((processFilter, index) =>
filterParam.index === index ||
filterParam.id === processFilter.id ||
(filterParam.name &&
(filterParam.name.toLocaleLowerCase() === processFilter.name.toLocaleLowerCase())
));
const newFilter = this.filters.find(
(processFilter, index) =>
filterParam.index === index ||
filterParam.id === processFilter.id ||
(filterParam.name && filterParam.name.toLocaleLowerCase() === processFilter.name.toLocaleLowerCase())
);
this.currentFilter = newFilter;
if (newFilter) {

View File

@@ -31,7 +31,6 @@ import { ProcessInstanceTasksComponent } from './process-instance-tasks.componen
styleUrls: ['./process-instance-details.component.css']
})
export class ProcessInstanceDetailsComponent implements OnChanges {
/** (required) The numeric ID of the process instance to display. */
@Input()
processInstanceId: string;
@@ -71,12 +70,10 @@ export class ProcessInstanceDetailsComponent implements OnChanges {
/**
* Constructor
*
* @param translate Translation service
* @param activitiProcess Process service
* @param logService
*/
constructor(private activitiProcess: ProcessService,
private logService: LogService) {
}
constructor(private activitiProcess: ProcessService, private logService: LogService) {}
ngOnChanges(changes: SimpleChanges) {
const processInstanceId = changes['processInstanceId'];
@@ -84,7 +81,7 @@ export class ProcessInstanceDetailsComponent implements OnChanges {
this.reset();
return;
}
if (processInstanceId && processInstanceId.currentValue) {
if (processInstanceId?.currentValue) {
this.load(processInstanceId.currentValue);
return;
}
@@ -99,11 +96,9 @@ export class ProcessInstanceDetailsComponent implements OnChanges {
load(processId: string) {
if (processId) {
this.activitiProcess.getProcess(processId).subscribe(
(res: ProcessInstance) => {
this.processInstanceDetails = res;
}
);
this.activitiProcess.getProcess(processId).subscribe((res) => {
this.processInstanceDetails = res;
});
}
}
@@ -115,9 +110,11 @@ export class ProcessInstanceDetailsComponent implements OnChanges {
this.activitiProcess.cancelProcess(this.processInstanceId).subscribe(
(data) => {
this.processCancelled.emit(data);
}, (err) => {
},
(err) => {
this.error.emit(err);
});
}
);
}
// bubbles (taskClick) event
@@ -128,7 +125,8 @@ export class ProcessInstanceDetailsComponent implements OnChanges {
getProcessNameOrDescription(dateFormat: string): string {
let name = '';
if (this.processInstanceDetails) {
name = this.processInstanceDetails.name ||
name =
this.processInstanceDetails.name ||
this.processInstanceDetails.processDefinitionName + ' - ' + this.getFormatDate(this.processInstanceDetails.started, dateFormat);
}
return name;
@@ -144,7 +142,6 @@ export class ProcessInstanceDetailsComponent implements OnChanges {
}
onShowProcessDiagram() {
this.showProcessDiagram.emit({value: this.processInstanceId});
this.showProcessDiagram.emit({ value: this.processInstanceId });
}
}

View File

@@ -15,7 +15,14 @@
* limitations under the License.
*/
import { AppConfigService, CardViewDateItemModel, CardViewItem, CardViewBaseItemModel, CardViewTextItemModel, TranslationService } from '@alfresco/adf-core';
import {
AppConfigService,
CardViewDateItemModel,
CardViewItem,
CardViewBaseItemModel,
CardViewTextItemModel,
TranslationService
} from '@alfresco/adf-core';
import { Component, Input, OnChanges } from '@angular/core';
import { ProcessInstance } from '../models/process-instance.model';
@@ -25,17 +32,15 @@ import { ProcessInstance } from '../models/process-instance.model';
styleUrls: ['./process-instance-header.component.css']
})
export class ProcessInstanceHeaderComponent implements OnChanges {
/** (**required**) Full details of the process instance to display information about. */
@Input()
processInstance: ProcessInstance;
properties: CardViewItem [];
properties: CardViewItem[];
dateFormat: string;
dateLocale: string;
constructor(private translationService: TranslationService,
private appConfig: AppConfigService) {
constructor(private translationService: TranslationService, private appConfig: AppConfigService) {
this.dateFormat = this.appConfig.get('dateValues.defaultDateFormat');
this.dateLocale = this.appConfig.get('dateValues.defaultDateLocale');
}
@@ -61,7 +66,7 @@ export class ProcessInstanceHeaderComponent implements OnChanges {
getStartedByFullName(): string {
let fullName = '';
if (this.processInstance && this.processInstance.startedBy) {
if (this.processInstance?.startedBy) {
fullName += this.processInstance.startedBy.firstName || '';
fullName += fullName ? ' ' : '';
fullName += this.processInstance.startedBy.lastName || '';
@@ -75,57 +80,47 @@ export class ProcessInstanceHeaderComponent implements OnChanges {
private initDefaultProperties(): any[] {
return [
new CardViewTextItemModel(
{
label: 'ADF_PROCESS_LIST.PROPERTIES.STATUS',
value: this.getProcessStatus(),
key: 'status'
}),
new CardViewDateItemModel(
{
label: 'ADF_PROCESS_LIST.PROPERTIES.END_DATE',
value: this.processInstance.ended,
format: this.dateFormat,
locale: this.dateLocale,
key: 'ended',
default: this.translationService.instant('ADF_PROCESS_LIST.PROPERTIES.END_DATE_DEFAULT')
}),
new CardViewTextItemModel(
{
label: 'ADF_PROCESS_LIST.PROPERTIES.CATEGORY',
value: this.processInstance.processDefinitionCategory,
key: 'category',
default: this.translationService.instant('ADF_PROCESS_LIST.PROPERTIES.CATEGORY_DEFAULT')
}),
new CardViewTextItemModel(
{
label: 'ADF_PROCESS_LIST.PROPERTIES.BUSINESS_KEY',
value: this.processInstance.businessKey,
key: 'businessKey',
default: this.translationService.instant('ADF_PROCESS_LIST.PROPERTIES.BUSINESS_KEY_DEFAULT')
}),
new CardViewTextItemModel(
{
label: 'ADF_PROCESS_LIST.PROPERTIES.CREATED_BY',
value: this.getStartedByFullName(),
key: 'createdBy',
default: this.translationService.instant('ADF_PROCESS_LIST.PROPERTIES.CREATED_BY_DEFAULT')
}),
new CardViewDateItemModel(
{
label: 'ADF_PROCESS_LIST.PROPERTIES.CREATED',
value: this.processInstance.started,
format: this.dateFormat,
locale: this.dateLocale,
key: 'created'
}),
new CardViewTextItemModel(
{label: 'ADF_PROCESS_LIST.PROPERTIES.ID',
value: this.processInstance.id,
key: 'id'
new CardViewTextItemModel({
label: 'ADF_PROCESS_LIST.PROPERTIES.STATUS',
value: this.getProcessStatus(),
key: 'status'
}),
new CardViewTextItemModel(
{label: 'ADF_PROCESS_LIST.PROPERTIES.DESCRIPTION',
new CardViewDateItemModel({
label: 'ADF_PROCESS_LIST.PROPERTIES.END_DATE',
value: this.processInstance.ended,
format: this.dateFormat,
locale: this.dateLocale,
key: 'ended',
default: this.translationService.instant('ADF_PROCESS_LIST.PROPERTIES.END_DATE_DEFAULT')
}),
new CardViewTextItemModel({
label: 'ADF_PROCESS_LIST.PROPERTIES.CATEGORY',
value: this.processInstance.processDefinitionCategory,
key: 'category',
default: this.translationService.instant('ADF_PROCESS_LIST.PROPERTIES.CATEGORY_DEFAULT')
}),
new CardViewTextItemModel({
label: 'ADF_PROCESS_LIST.PROPERTIES.BUSINESS_KEY',
value: this.processInstance.businessKey,
key: 'businessKey',
default: this.translationService.instant('ADF_PROCESS_LIST.PROPERTIES.BUSINESS_KEY_DEFAULT')
}),
new CardViewTextItemModel({
label: 'ADF_PROCESS_LIST.PROPERTIES.CREATED_BY',
value: this.getStartedByFullName(),
key: 'createdBy',
default: this.translationService.instant('ADF_PROCESS_LIST.PROPERTIES.CREATED_BY_DEFAULT')
}),
new CardViewDateItemModel({
label: 'ADF_PROCESS_LIST.PROPERTIES.CREATED',
value: this.processInstance.started,
format: this.dateFormat,
locale: this.dateLocale,
key: 'created'
}),
new CardViewTextItemModel({ label: 'ADF_PROCESS_LIST.PROPERTIES.ID', value: this.processInstance.id, key: 'id' }),
new CardViewTextItemModel({
label: 'ADF_PROCESS_LIST.PROPERTIES.DESCRIPTION',
value: this.processInstance.processDefinitionDescription,
key: 'description',
default: this.translationService.instant('ADF_PROCESS_LIST.PROPERTIES.DESCRIPTION_DEFAULT')

View File

@@ -31,7 +31,6 @@ import { share, takeUntil } from 'rxjs/operators';
styleUrls: ['./process-instance-tasks.component.css']
})
export class ProcessInstanceTasksComponent implements OnInit, OnChanges, OnDestroy {
/** (**required**) The ID of the process instance to display tasks for. */
@Input()
processInstanceDetails: ProcessInstance;
@@ -67,23 +66,15 @@ export class ProcessInstanceTasksComponent implements OnInit, OnChanges, OnDestr
private completedTaskObserver: Observer<TaskDetailsModel>;
private onDestroy$ = new Subject<boolean>();
constructor(private activitiProcess: ProcessService,
private logService: LogService,
private dialog: MatDialog) {
this.task$ = new Observable<TaskDetailsModel>((observer) => this.taskObserver = observer)
.pipe(share());
this.completedTask$ = new Observable<TaskDetailsModel>((observer) => this.completedTaskObserver = observer)
.pipe(share());
constructor(private activitiProcess: ProcessService, private logService: LogService, private dialog: MatDialog) {
this.task$ = new Observable<TaskDetailsModel>((observer) => (this.taskObserver = observer)).pipe(share());
this.completedTask$ = new Observable<TaskDetailsModel>((observer) => (this.completedTaskObserver = observer)).pipe(share());
}
ngOnInit() {
this.task$
.pipe(takeUntil(this.onDestroy$))
.subscribe(task => this.activeTasks.push(task));
this.task$.pipe(takeUntil(this.onDestroy$)).subscribe((task) => this.activeTasks.push(task));
this.completedTask$
.pipe(takeUntil(this.onDestroy$))
.subscribe(task => this.completedTasks.push(task));
this.completedTask$.pipe(takeUntil(this.onDestroy$)).subscribe((task) => this.completedTasks.push(task));
}
ngOnDestroy() {
@@ -93,7 +84,7 @@ export class ProcessInstanceTasksComponent implements OnInit, OnChanges, OnDestr
ngOnChanges(changes: SimpleChanges) {
const processInstanceDetails = changes['processInstanceDetails'];
if (processInstanceDetails && processInstanceDetails.currentValue) {
if (processInstanceDetails?.currentValue) {
this.load(processInstanceDetails.currentValue.id);
}
}
@@ -107,7 +98,7 @@ export class ProcessInstanceTasksComponent implements OnInit, OnChanges, OnDestr
this.activeTasks = [];
if (processInstanceId) {
this.activitiProcess.getProcessTasks(processInstanceId, null).subscribe(
(res: TaskDetailsModel[]) => {
(res) => {
res.forEach((task) => {
this.taskObserver.next(task);
});
@@ -125,7 +116,7 @@ export class ProcessInstanceTasksComponent implements OnInit, OnChanges, OnDestr
this.completedTasks = [];
if (processInstanceId) {
this.activitiProcess.getProcessTasks(processInstanceId, 'completed').subscribe(
(res: TaskDetailsModel[]) => {
(res) => {
res.forEach((task) => {
this.completedTaskObserver.next(task);
});
@@ -140,14 +131,12 @@ export class ProcessInstanceTasksComponent implements OnInit, OnChanges, OnDestr
}
hasStartFormDefined(): boolean {
return this.processInstanceDetails && this.processInstanceDetails.startFormDefined === true;
return this.processInstanceDetails?.startFormDefined === true;
}
getUserFullName(user: any): string {
if (user) {
return (user.firstName && user.firstName !== 'null'
? user.firstName + ' ' : '') +
user.lastName;
return (user.firstName && user.firstName !== 'null' ? user.firstName + ' ' : '') + user.lastName;
}
return 'Nobody';
}

View File

@@ -30,16 +30,7 @@ import {
DataCellEvent,
DEFAULT_PAGINATION
} from '@alfresco/adf-core';
import {
AfterContentInit,
Component,
ContentChild,
EventEmitter,
Input,
OnChanges,
Output,
SimpleChanges
} from '@angular/core';
import { AfterContentInit, Component, ContentChild, EventEmitter, Input, OnChanges, Output, SimpleChanges } from '@angular/core';
import { ProcessFilterParamRepresentationModel } from '../models/filter-process.model';
import { processPresetsDefaultModel } from '../models/process-preset.model';
import { ProcessService } from '../services/process.service';
@@ -55,7 +46,6 @@ const PRESET_KEY = 'adf-process-list.presets';
templateUrl: './process-list.component.html'
})
export class ProcessInstanceListComponent extends DataTableSchema implements OnChanges, AfterContentInit, PaginatedComponent {
@ContentChild(CustomEmptyContentTemplateDirective)
customEmptyContent: CustomEmptyContentTemplateDirective;
@@ -151,9 +141,7 @@ export class ProcessInstanceListComponent extends DataTableSchema implements OnC
sorting: any[] = ['created', 'desc'];
pagination: BehaviorSubject<PaginationModel>;
constructor(private processService: ProcessService,
private userPreferences: UserPreferencesService,
appConfig: AppConfigService) {
constructor(private processService: ProcessService, private userPreferences: UserPreferencesService, appConfig: AppConfigService) {
super(appConfig, PRESET_KEY, processPresetsDefaultModel);
this.size = this.userPreferences.paginationSize;
@@ -167,7 +155,7 @@ export class ProcessInstanceListComponent extends DataTableSchema implements OnC
ngAfterContentInit() {
this.createDatatableSchema();
if (this.data && this.data.getColumns().length === 0) {
if (this.data?.getColumns().length === 0) {
this.data.setColumns(this.columns);
}
@@ -266,7 +254,7 @@ export class ProcessInstanceListComponent extends DataTableSchema implements OnC
}
currentPage(skipCount: number, maxItems: number): number {
return (skipCount && maxItems) ? Math.floor(skipCount / maxItems) : 0;
return skipCount && maxItems ? Math.floor(skipCount / maxItems) : 0;
}
private createRequestNode(): ProcessFilterParamRepresentationModel {
@@ -284,7 +272,7 @@ export class ProcessInstanceListComponent extends DataTableSchema implements OnC
private isSortChanged(changes: SimpleChanges): boolean {
const actualSort = changes['sort'];
return actualSort && actualSort.currentValue && actualSort.currentValue !== actualSort.previousValue;
return actualSort?.currentValue && actualSort.currentValue !== actualSort.previousValue;
}
private isPropertyChanged(changes: SimpleChanges): boolean {
@@ -298,17 +286,17 @@ export class ProcessInstanceListComponent extends DataTableSchema implements OnC
const page = changes['page'];
const size = changes['size'];
if (appId && appId.currentValue) {
if (appId?.currentValue) {
changed = true;
} else if (processDefinitionId) {
changed = true;
} else if (processInstanceId) {
changed = true;
} else if (state && state.currentValue) {
} else if (state?.currentValue) {
changed = true;
} else if (sort && sort.currentValue) {
} else if (sort?.currentValue) {
changed = true;
} else if (page && page.currentValue !== page.previousValue) {
} else if (page && page?.currentValue !== page.previousValue) {
changed = true;
} else if (size && size.currentValue !== size.previousValue) {
changed = true;
@@ -318,10 +306,11 @@ export class ProcessInstanceListComponent extends DataTableSchema implements OnC
private load(requestNode: ProcessFilterParamRepresentationModel) {
this.isLoading = true;
this.processService.getProcesses(requestNode)
.pipe(finalize(() => this.isLoading = false))
this.processService
.getProcesses(requestNode)
.pipe(finalize(() => (this.isLoading = false)))
.subscribe(
response => {
(response) => {
this.rows = response.data;
this.selectFirst();
this.success.emit(response);
@@ -332,7 +321,7 @@ export class ProcessInstanceListComponent extends DataTableSchema implements OnC
totalItems: response.total
});
},
error => {
(error) => {
this.error.emit(error);
}
);

View File

@@ -23,14 +23,7 @@ import { of, throwError } from 'rxjs';
import { MatSelectChange } from '@angular/material/select';
import { ProcessInstanceVariable } from '../models/process-instance-variable.model';
import { ProcessService } from '../services/process.service';
import {
newProcess,
taskFormMock,
testProcessDef,
testMultipleProcessDefs,
testProcessDefWithForm,
testProcessDefinitions
} from '../../mock';
import { newProcess, taskFormMock, testProcessDef, testMultipleProcessDefs, testProcessDefWithForm, testProcessDefinitions } from '../../mock';
import { StartProcessInstanceComponent } from './start-process.component';
import { ProcessTestingModule } from '../../testing/process.testing.module';
import { By } from '@angular/platform-browser';
@@ -41,7 +34,6 @@ import { ProcessInstance } from '../models/process-instance.model';
import { ActivitiContentService } from '../../form/services/activiti-alfresco.service';
describe('StartProcessComponent', () => {
let appConfig: AppConfigService;
let activitiContentService: ActivitiContentService;
let component: StartProcessInstanceComponent;
@@ -56,10 +48,7 @@ describe('StartProcessComponent', () => {
beforeEach(() => {
TestBed.configureTestingModule({
imports: [
TranslateModule.forRoot(),
ProcessTestingModule
]
imports: [TranslateModule.forRoot(), ProcessTestingModule]
});
});
@@ -68,7 +57,7 @@ describe('StartProcessComponent', () => {
selectElement.click();
fixture.detectChanges();
const options: any = fixture.debugElement.queryAll(By.css('.mat-option-text'));
const currentOption = options.find( (option: DebugElement) => option.nativeElement.innerHTML.trim() === name );
const currentOption = options.find((option: DebugElement) => option.nativeElement.innerHTML.trim() === name);
if (currentOption) {
currentOption.nativeElement.click();
@@ -93,7 +82,7 @@ describe('StartProcessComponent', () => {
startProcessSpy = spyOn(processService, 'startProcess').and.returnValue(of(newProcess));
getStartFormDefinitionSpy = spyOn(processService, 'getStartFormDefinition').and.returnValue(of(taskFormMock));
applyAlfrescoNodeSpy = spyOn(activitiContentService, 'applyAlfrescoNode').and.returnValue(of({ id: 1234 }));
spyOn(activitiContentService, 'getAlfrescoRepositories').and.returnValue(of([{ id: '1', name: 'fake-repo-name'}]));
spyOn(activitiContentService, 'getAlfrescoRepositories').and.returnValue(of([{ id: '1', name: 'fake-repo-name' }]));
});
afterEach(() => {
@@ -102,9 +91,7 @@ describe('StartProcessComponent', () => {
});
describe('first step', () => {
describe('without start form', () => {
beforeEach(() => {
fixture.detectChanges();
component.name = 'My new process';
@@ -165,7 +152,6 @@ describe('StartProcessComponent', () => {
});
describe('with start form', () => {
beforeEach(() => {
fixture.detectChanges();
getDefinitionsSpy.and.returnValue(of(testProcessDefWithForm));
@@ -199,7 +185,7 @@ describe('StartProcessComponent', () => {
await fixture.whenStable();
const inputLabelsNodes = document.querySelectorAll('.adf-start-process .adf-process-input-container');
inputLabelsNodes.forEach(labelNode => {
inputLabelsNodes.forEach((labelNode) => {
expect(labelNode.getAttribute('ng-reflect-float-label')).toBe('always');
});
});
@@ -245,7 +231,6 @@ describe('StartProcessComponent', () => {
});
describe('CS content connection', () => {
it('Should get the alfrescoRepositoryName from the config json', async () => {
appConfig.config = Object.assign(appConfig.config, {
alfrescoRepositoryName: 'alfresco-123'
@@ -307,7 +292,6 @@ describe('StartProcessComponent', () => {
});
describe('process definitions list', () => {
beforeEach(() => {
fixture.detectChanges();
component.name = 'My new process';
@@ -374,11 +358,10 @@ describe('StartProcessComponent', () => {
fixture.detectChanges();
await fixture.whenStable();
expect(component.selectedProcessDef.name).toBeNull();
expect(component.selectedProcessDef.name).not.toBeDefined();
});
describe('dropdown', () => {
it('should hide the process dropdown button if showSelectProcessDropdown is false', async () => {
fixture.detectChanges();
getDefinitionsSpy = getDefinitionsSpy.and.returnValue(of([testProcessDef]));
@@ -427,7 +410,6 @@ describe('StartProcessComponent', () => {
});
describe('input changes', () => {
beforeEach(async () => {
component.appId = 123;
fixture.detectChanges();
@@ -449,7 +431,6 @@ describe('StartProcessComponent', () => {
});
describe('start process', () => {
beforeEach(() => {
fixture.detectChanges();
component.name = 'My new process';
@@ -574,10 +555,9 @@ describe('StartProcessComponent', () => {
fixture.detectChanges();
expect(startSpy).not.toHaveBeenCalled();
});
});
});
describe('Select applications', () => {
beforeEach(() => {
fixture.detectChanges();
component.name = 'My new process';
@@ -623,7 +603,7 @@ describe('StartProcessComponent', () => {
expect(component.processDefinitions[0].name).toEqual('My Process 1');
expect(component.processDefinitions[1].name).toEqual('My Process 2');
getDefinitionsSpy.and.returnValue(of([ { id: 'my:process 3', name: 'My Process 3', hasStartForm: true } ]));
getDefinitionsSpy.and.returnValue(of([{ id: 'my:process 3', name: 'My Process 3', hasStartForm: true }]));
fixture.detectChanges();
const newApplication = { value: deployedApps[1] } as MatSelectChange;
@@ -811,9 +791,9 @@ describe('StartProcessComponent', () => {
changeAppId(123);
fixture.detectChanges();
const application1 = deployedApps[0];
const application2 = deployedApps[1];
const application3 = deployedApps[2];
const application1 = deployedApps[0];
const application2 = deployedApps[1];
const application3 = deployedApps[2];
expect(component.applications.length).toBe(6);
@@ -857,10 +837,9 @@ describe('StartProcessComponent', () => {
expect(component.selectedProcessDef.name).toEqual(processDefWithNoStartForm.name);
expect(component.selectedProcessDef.hasStartForm).toEqual(processDefWithNoStartForm.hasStartForm);
});
});
});
describe('Empty Template', () => {
it('[333510] Should be able to show empty template when no applications deployed', async () => {
getDeployedApplicationsSpy = spyOn(appsProcessService, 'getDeployedApplications').and.returnValue(of([]));
@@ -939,7 +918,6 @@ describe('StartProcessComponent', () => {
});
describe('Error event', () => {
const processDefError = { message: 'Failed to load Process definitions' };
const applicationsError = { message: 'Failed to load applications' };
const startProcessError = { message: 'Failed to start process' };

View File

@@ -146,7 +146,7 @@ export class StartProcessInstanceComponent implements OnChanges, OnInit, OnDestr
);
this.activitiContentService.getAlfrescoRepositories().subscribe((repoList) => {
if (repoList && repoList[0]) {
if (repoList?.[0]) {
const alfrescoRepository = repoList[0];
this.alfrescoRepositoryName = `alfresco-${alfrescoRepository.id}-${alfrescoRepository.name}`;
}
@@ -159,7 +159,7 @@ export class StartProcessInstanceComponent implements OnChanges, OnInit, OnDestr
}
ngOnChanges(changes: SimpleChanges) {
if (changes['values'] && changes['values'].currentValue) {
if (changes['values']?.currentValue) {
this.moveNodeFromCStoPS();
}
@@ -281,7 +281,7 @@ export class StartProcessInstanceComponent implements OnChanges, OnInit, OnDestr
}
loadProcessDefinitionsBasedOnSelectedApp() {
if (this.selectedApplication && this.selectedApplication.id) {
if (this.selectedApplication?.id) {
this.loadProcessDefinitions(this.selectedApplication ? this.selectedApplication.id : null);
} else {
this.isProcessDefinitionsLoading = false;
@@ -298,15 +298,15 @@ export class StartProcessInstanceComponent implements OnChanges, OnInit, OnDestr
}
hasApplications(): boolean {
return this.applications && this.applications.length > 0;
return this.applications?.length > 0;
}
hasProcessDefinitions(): boolean {
return this.processDefinitions && this.processDefinitions.length > 0;
return this.processDefinitions?.length > 0;
}
isProcessDefinitionSelected(): boolean {
return !!(this.selectedProcessDef && this.selectedProcessDef.id);
return !!this.selectedProcessDef?.id;
}
isProcessDefinitionsEmpty(): boolean {
@@ -332,7 +332,7 @@ export class StartProcessInstanceComponent implements OnChanges, OnInit, OnDestr
if (this.values.hasOwnProperty(key)) {
const currentValue = Array.isArray(this.values[key]) ? this.values[key] : [this.values[key]];
const contents = currentValue
.filter((value: any) => value && value.isFile)
.filter((value: any) => !!value?.isFile)
.map((content: Node) => this.activitiContentService.applyAlfrescoNode(content, null, accountIdentifier));
forkJoin(contents).subscribe((res: RelatedContentRepresentation[]) => {
this.movedNodeToPS = { [key]: [...res] };
@@ -342,7 +342,7 @@ export class StartProcessInstanceComponent implements OnChanges, OnInit, OnDestr
}
startProcess(outcome?: string) {
if (this.selectedProcessDef && this.selectedProcessDef.id && this.nameController.value) {
if (this.selectedProcessDef?.id && this.nameController.value) {
const formValues = this.startForm ? this.startForm.form.values : undefined;
this.activitiProcess.startProcess(this.selectedProcessDef.id, this.nameController.value, outcome, formValues, this.variables).subscribe(
(res) => {
@@ -361,19 +361,19 @@ export class StartProcessInstanceComponent implements OnChanges, OnInit, OnDestr
}
hasStartForm(): boolean {
return this.selectedProcessDef && this.selectedProcessDef.hasStartForm;
return this.selectedProcessDef?.hasStartForm;
}
isStartFormMissingOrValid(): boolean {
if (this.startForm) {
return this.startForm.form && this.startForm.form.isValid;
return this.startForm.form?.isValid;
} else {
return true;
}
}
validateForm(): boolean {
return this.selectedProcessDef && this.selectedProcessDef.id && this.processNameInput.valid && this.isStartFormMissingOrValid();
return this.selectedProcessDef?.id && this.processNameInput.valid && this.isStartFormMissingOrValid();
}
onOutcomeClick(outcome: string) {
@@ -436,7 +436,7 @@ export class StartProcessInstanceComponent implements OnChanges, OnInit, OnDestr
}
private isAppSelected(): boolean {
return !!(this.selectedApplication && this.selectedApplication.id);
return !!this.selectedApplication?.id;
}
private removeDefaultApps(apps: AppDefinitionRepresentationModel[]): AppDefinitionRepresentationModel[] {
@@ -466,13 +466,12 @@ export class StartProcessInstanceComponent implements OnChanges, OnInit, OnDestr
}
private isAppIdChanged(changes: SimpleChanges) {
return changes['appId'] && changes['appId'].currentValue && changes['appId'].currentValue !== changes['appId'].previousValue;
return changes['appId']?.currentValue && changes['appId'].currentValue !== changes['appId'].previousValue;
}
private isProcessDefinitionChanged(changes: SimpleChanges) {
return (
changes['processDefinitionName'] &&
changes['processDefinitionName'].currentValue &&
changes['processDefinitionName']?.currentValue &&
changes['processDefinitionName'].currentValue !== changes['processDefinitionName'].previousValue
);
}

View File

@@ -28,15 +28,15 @@ export class ProcessDefinitionRepresentation {
hasStartForm: boolean;
constructor(obj?: any) {
this.id = obj && obj.id || null;
this.name = obj && obj.name || null;
this.description = obj && obj.description || null;
this.key = obj && obj.key || null;
this.category = obj && obj.category || null;
this.version = obj && obj.version || 0;
this.deploymentId = obj && obj.deploymentId || null;
this.tenantId = obj && obj.tenantId || null;
this.metaDataValues = obj && obj.metaDataValues || [];
this.hasStartForm = obj && obj.hasStartForm === true;
this.id = obj?.id;
this.name = obj?.name;
this.description = obj?.description;
this.key = obj?.key;
this.category = obj?.category;
this.version = obj?.version || 0;
this.deploymentId = obj?.deploymentId;
this.tenantId = obj?.tenantId;
this.metaDataValues = obj?.metaDataValues || [];
this.hasStartForm = obj?.hasStartForm === true;
}
}

View File

@@ -24,11 +24,11 @@ export class ProcessFilterRequestRepresentation {
size: number;
constructor(obj?: any) {
this.processDefinitionId = obj && obj.processDefinitionId || null;
this.appDefinitionId = obj && obj.appDefinitionId || null;
this.state = obj && obj.state || null;
this.sort = obj && obj.sort || null;
this.page = obj && obj.page || 0;
this.size = obj && obj.size || 25;
this.processDefinitionId = obj?.processDefinitionId;
this.appDefinitionId = obj?.appDefinitionId;
this.state = obj?.state;
this.sort = obj?.sort;
this.page = obj?.page || 0;
this.size = obj?.size || 25;
}
}

View File

@@ -18,7 +18,6 @@
import { RestVariable } from '@alfresco/js-api';
export class ProcessInstanceVariable implements RestVariable {
name?: string;
scope?: string;
type?: string;
@@ -26,9 +25,9 @@ export class ProcessInstanceVariable implements RestVariable {
valueUrl?: string;
constructor(obj?: any) {
this.name = obj && obj.name !== undefined ? obj.name : null;
this.scope = obj && obj.scope !== undefined ? obj.scope : null;
this.value = obj && obj.value !== undefined ? obj.value : null;
this.valueUrl = obj && obj.valueUrl !== undefined ? obj.valueUrl : null;
this.name = obj?.name;
this.scope = obj?.scope;
this.value = obj?.value;
this.valueUrl = obj?.valueUrl;
}
}

View File

@@ -18,7 +18,6 @@
import { LightUserRepresentation, ProcessInstanceRepresentation, RestVariable } from '@alfresco/js-api';
export class ProcessInstance implements ProcessInstanceRepresentation {
businessKey?: string;
ended?: Date;
graphicalNotationDefined?: boolean;
@@ -38,23 +37,22 @@ export class ProcessInstance implements ProcessInstanceRepresentation {
variables?: RestVariable[];
constructor(data?: any) {
this.businessKey = data && data.businessKey !== undefined ? data.businessKey : null;
this.ended = data && data.ended !== undefined ? data.ended : null;
this.graphicalNotationDefined = data && data.graphicalNotationDefined !== undefined ? data.graphicalNotationDefined : null;
this.id = data && data.id !== undefined ? data.id : null;
this.name = data && data.name !== undefined ? data.name : null;
this.processDefinitionCategory = data && data.processDefinitionCategory !== undefined ? data.processDefinitionCategory : null;
this.processDefinitionDeploymentId = data && data.processDefinitionDeploymentId !== undefined ? data.processDefinitionDeploymentId : null;
this.processDefinitionDescription = data && data.processDefinitionDescription !== undefined ? data.processDefinitionDescription : null;
this.processDefinitionId = data && data.processDefinitionId !== undefined ? data.processDefinitionId : null;
this.processDefinitionKey = data && data.processDefinitionKey !== undefined ? data.processDefinitionKey : null;
this.processDefinitionName = data && data.processDefinitionName !== undefined ? data.processDefinitionName : null;
this.processDefinitionVersion = data && data.processDefinitionVersion !== undefined ? data.processDefinitionVersion : null;
this.startFormDefined = data && data.startFormDefined !== undefined ? data.startFormDefined : null;
this.started = data && data.started !== undefined ? data.started : null;
this.startedBy = data && data.startedBy !== undefined ? data.startedBy : null;
this.tenantId = data && data.tenantId !== undefined ? data.tenantId : null;
this.variables = data && data.variables !== undefined ? data.variables : null;
this.businessKey = data?.businessKey;
this.ended = data?.ended;
this.graphicalNotationDefined = data?.graphicalNotationDefined;
this.id = data?.id;
this.name = data?.name;
this.processDefinitionCategory = data?.processDefinitionCategory;
this.processDefinitionDeploymentId = data?.processDefinitionDeploymentId;
this.processDefinitionDescription = data?.processDefinitionDescription;
this.processDefinitionId = data?.processDefinitionId;
this.processDefinitionKey = data?.processDefinitionKey;
this.processDefinitionName = data?.processDefinitionName;
this.processDefinitionVersion = data?.processDefinitionVersion;
this.startFormDefined = data?.startFormDefined;
this.started = data?.started;
this.startedBy = data?.startedBy;
this.tenantId = data?.tenantId;
this.variables = data?.variables;
}
}

View File

@@ -16,7 +16,14 @@
*/
import { TestBed } from '@angular/core/testing';
import { mockError, fakeProcessFiltersResponse, dummyRunningFilter, dummyAllFilter, dummyCompletedFilter, dummyDuplicateRunningFilter } from '../../mock';
import {
mockError,
fakeProcessFiltersResponse,
dummyRunningFilter,
dummyAllFilter,
dummyCompletedFilter,
dummyDuplicateRunningFilter
} from '../../mock';
import { FilterProcessRepresentationModel } from '../models/filter-process.model';
import { ProcessFilterService } from './process-filter.service';
import { CoreTestingModule } from '@alfresco/adf-core';
@@ -30,22 +37,19 @@ describe('Process filter', () => {
beforeEach(() => {
TestBed.configureTestingModule({
imports: [
CoreTestingModule
]
imports: [CoreTestingModule]
});
service = TestBed.inject(ProcessFilterService);
});
describe('filters', () => {
let getFilters: jasmine.Spy;
let createFilter: jasmine.Spy;
beforeEach(() => {
getFilters = spyOn(service['userFiltersApi'], 'getUserProcessInstanceFilters')
.and
.returnValue(Promise.resolve(fakeProcessFiltersResponse));
getFilters = spyOn(service['userFiltersApi'], 'getUserProcessInstanceFilters').and.returnValue(
Promise.resolve(fakeProcessFiltersResponse)
);
jasmine.Ajax.install();
});
@@ -55,7 +59,6 @@ describe('Process filter', () => {
});
describe('get filters', () => {
it('should call the API without an appId defined by default', () => {
service.getProcessFilters(null);
expect(getFilters).toHaveBeenCalled();
@@ -67,33 +70,29 @@ describe('Process filter', () => {
});
it('should return the task filter by id', (done) => {
service.getProcessFilterById(333).subscribe(
(processFilter: FilterProcessRepresentationModel) => {
expect(processFilter).toBeDefined();
expect(processFilter.id).toEqual(333);
expect(processFilter.name).toEqual('Running');
expect(processFilter.filter.sort).toEqual('created-desc');
expect(processFilter.filter.state).toEqual('running');
done();
}
);
service.getProcessFilterById(333).subscribe((processFilter: FilterProcessRepresentationModel) => {
expect(processFilter).toBeDefined();
expect(processFilter.id).toEqual(333);
expect(processFilter.name).toEqual('Running');
expect(processFilter.filter.sort).toEqual('created-desc');
expect(processFilter.filter.state).toEqual('running');
done();
});
});
it('should return the task filter by name', (done) => {
service.getProcessFilterByName('Running').subscribe(
(res: FilterProcessRepresentationModel) => {
expect(res).toBeDefined();
expect(res.id).toEqual(333);
expect(res.name).toEqual('Running');
expect(res.filter.sort).toEqual('created-desc');
expect(res.filter.state).toEqual('running');
done();
}
);
service.getProcessFilterByName('Running').subscribe((res: FilterProcessRepresentationModel) => {
expect(res).toBeDefined();
expect(res.id).toEqual(333);
expect(res.name).toEqual('Running');
expect(res.filter.sort).toEqual('created-desc');
expect(res.filter.state).toEqual('running');
done();
});
});
it('should return the default filters', (done) => {
service.createDefaultFilters(1234).subscribe((res: FilterProcessRepresentationModel []) => {
service.createDefaultFilters(1234).subscribe((res: FilterProcessRepresentationModel[]) => {
expect(res).toBeDefined();
expect(res.length).toEqual(3);
expect(res[0].name).toEqual('Running');
@@ -109,7 +108,11 @@ describe('Process filter', () => {
status: 200,
contentType: 'application/json',
responseText: JSON.stringify({
appId: 1001, id: 111, name: 'Running', icon: 'fake-icon', recent: false
appId: 1001,
id: 111,
name: 'Running',
icon: 'fake-icon',
recent: false
})
});
@@ -117,7 +120,11 @@ describe('Process filter', () => {
status: 200,
contentType: 'application/json',
responseText: JSON.stringify({
appId: 1001, id: 222, name: 'Completed', icon: 'fake-icon', recent: false
appId: 1001,
id: 222,
name: 'Completed',
icon: 'fake-icon',
recent: false
})
});
@@ -125,13 +132,17 @@ describe('Process filter', () => {
status: 200,
contentType: 'application/json',
responseText: JSON.stringify({
appId: 1001, id: 333, name: 'All', icon: 'fake-icon', recent: false
appId: 1001,
id: 333,
name: 'All',
icon: 'fake-icon',
recent: false
})
});
});
it('should be able create filters and add sorting information to the response', (done) => {
service.createDefaultFilters(1234).subscribe((res: FilterProcessRepresentationModel []) => {
service.createDefaultFilters(1234).subscribe((res: FilterProcessRepresentationModel[]) => {
expect(res).toBeDefined();
expect(res.length).toEqual(3);
expect(res[0].name).toEqual('Running');
@@ -152,7 +163,11 @@ describe('Process filter', () => {
status: 200,
contentType: 'application/json',
responseText: JSON.stringify({
appId: 1001, id: 111, name: 'Running', icon: 'fake-icon', recent: false
appId: 1001,
id: 111,
name: 'Running',
icon: 'fake-icon',
recent: false
})
});
@@ -160,7 +175,11 @@ describe('Process filter', () => {
status: 200,
contentType: 'application/json',
responseText: JSON.stringify({
appId: 1001, id: 222, name: 'Completed', icon: 'fake-icon', recent: false
appId: 1001,
id: 222,
name: 'Completed',
icon: 'fake-icon',
recent: false
})
});
@@ -168,7 +187,11 @@ describe('Process filter', () => {
status: 200,
contentType: 'application/json',
responseText: JSON.stringify({
appId: 1001, id: 333, name: 'All', icon: 'fake-icon', recent: false
appId: 1001,
id: 333,
name: 'All',
icon: 'fake-icon',
recent: false
})
});
});
@@ -177,23 +200,20 @@ describe('Process filter', () => {
getFilters = getFilters.and.returnValue(Promise.reject(mockError));
service.getProcessFilters(null).subscribe(
() => {
},
() => {},
(res) => {
expect(res).toBe(mockError);
done();
}
);
});
});
describe('add filter', () => {
beforeEach(() => {
createFilter = spyOn(service['userFiltersApi'], 'createUserProcessInstanceFilter')
.and
.callFake((processfilter: FilterProcessRepresentationModel) => Promise.resolve(processfilter));
createFilter = spyOn(service['userFiltersApi'], 'createUserProcessInstanceFilter').and.callFake(
(processfilter: FilterProcessRepresentationModel) => Promise.resolve(processfilter)
);
});
const filter = fakeProcessFiltersResponse.data[0];
@@ -214,8 +234,7 @@ describe('Process filter', () => {
createFilter = createFilter.and.returnValue(Promise.reject(mockError));
service.addProcessFilter(filter).subscribe(
() => {
},
() => {},
(res) => {
expect(res).toBe(mockError);
done();
@@ -226,15 +245,13 @@ describe('Process filter', () => {
it('should return a default error if no data is returned by the API', (done) => {
createFilter = createFilter.and.returnValue(Promise.reject(null));
service.addProcessFilter(filter).subscribe(
() => {
},
() => {},
(res) => {
expect(res).toBe('Server error');
done();
}
);
});
});
describe('isFilterAlreadyExisting', () => {
@@ -251,16 +268,14 @@ describe('Process filter', () => {
index: 0,
name: 'Running',
recent: false,
hasFilter: () => {
return true;
}
hasFilter: () => true
}
];
filterRepresentationData = {
name : '',
sort : 'created-desc',
state : 'running'
name: '',
sort: 'created-desc',
state: 'running'
};
});
@@ -278,7 +293,6 @@ describe('Process filter', () => {
});
describe('createDefaultFilters', () => {
it('should return an array with unique process filters', (done) => {
const appId = 123;
@@ -296,7 +310,12 @@ describe('Process filter', () => {
spyOn<any>(service, 'getCompletedFilterInstance').and.returnValue(completedFilter);
spyOn<any>(service, 'getAllFilterInstance').and.returnValue(allFilter);
spyOn(service, 'addProcessFilter').and.returnValues(runningObservable, completedObservable, allObservable, duplicateRunningObservable);
spyOn(service, 'addProcessFilter').and.returnValues(
runningObservable,
completedObservable,
allObservable,
duplicateRunningObservable
);
service.createDefaultFilters(appId).subscribe((result) => {
expect(result).toEqual([
@@ -307,7 +326,6 @@ describe('Process filter', () => {
done();
});
});
});
});
});

View File

@@ -26,7 +26,6 @@ import { TaskListService } from './../services/tasklist.service';
styleUrls: ['./checklist.component.scss']
})
export class ChecklistComponent implements OnChanges {
/** (required) The id of the parent task to which subtasks are
* attached.
*/
@@ -60,15 +59,13 @@ export class ChecklistComponent implements OnChanges {
taskName: string;
checklist: TaskDetailsModel [] = [];
checklist: TaskDetailsModel[] = [];
constructor(private activitiTaskList: TaskListService,
private dialog: MatDialog) {
}
constructor(private activitiTaskList: TaskListService, private dialog: MatDialog) {}
ngOnChanges(changes: SimpleChanges) {
const taskId = changes['taskId'];
if (taskId && taskId.currentValue) {
if (taskId?.currentValue) {
this.getTaskChecklist();
return;
}
@@ -78,7 +75,7 @@ export class ChecklistComponent implements OnChanges {
this.checklist = [];
if (this.taskId) {
this.activitiTaskList.getTaskChecklist(this.taskId).subscribe(
(taskDetailsModel: TaskDetailsModel[]) => {
(taskDetailsModel) => {
taskDetailsModel.forEach((task) => {
this.checklist.push(task);
});
@@ -103,7 +100,7 @@ export class ChecklistComponent implements OnChanges {
assignee: { id: this.assignee }
});
this.activitiTaskList.addTask(newTask).subscribe(
(taskDetailsModel: TaskDetailsModel) => {
(taskDetailsModel) => {
this.checklist.push(taskDetailsModel);
this.checklistTaskCreated.emit(taskDetailsModel);
this.taskName = '';
@@ -123,7 +120,8 @@ export class ChecklistComponent implements OnChanges {
},
(error) => {
this.error.emit(error);
});
}
);
}
public cancel() {

View File

@@ -56,7 +56,6 @@ import { PeopleProcessService } from '../../common/services/people-process.servi
encapsulation: ViewEncapsulation.None
})
export class TaskDetailsComponent implements OnInit, OnChanges, OnDestroy {
@ViewChild('activitiComments')
activitiComments: CommentsComponent;
@@ -149,7 +148,7 @@ export class TaskDetailsComponent implements OnInit, OnChanges, OnDestroy {
/** Emitted when a checklist task is deleted. */
@Output()
taskDeleted: EventEmitter<string> = new EventEmitter<string>();
taskDeleted = new EventEmitter<string>();
/** Emitted when an error occurs. */
@Output()
@@ -163,7 +162,7 @@ export class TaskDetailsComponent implements OnInit, OnChanges, OnDestroy {
/** Emitted when a task is assigned. */
@Output()
assignTask: EventEmitter<void> = new EventEmitter<void>();
assignTask = new EventEmitter<void>();
/** Emitted when a task is claimed. */
@Output()
@@ -187,27 +186,24 @@ export class TaskDetailsComponent implements OnInit, OnChanges, OnDestroy {
private peopleSearchObserver: Observer<UserProcessModel[]>;
private onDestroy$ = new Subject<boolean>();
constructor(private taskListService: TaskListService,
private peopleProcessService: PeopleProcessService,
private logService: LogService,
private cardViewUpdateService: CardViewUpdateService,
private dialog: MatDialog) {
}
constructor(
private taskListService: TaskListService,
private peopleProcessService: PeopleProcessService,
private logService: LogService,
private cardViewUpdateService: CardViewUpdateService,
private dialog: MatDialog
) {}
ngOnInit() {
this.peopleSearch = new Observable<UserProcessModel[]>((observer) => this.peopleSearchObserver = observer).pipe(share());
this.peopleSearch = new Observable<UserProcessModel[]>((observer) => (this.peopleSearchObserver = observer)).pipe(share());
if (this.taskId) {
this.loadDetails(this.taskId);
}
this.cardViewUpdateService.itemUpdated$
.pipe(takeUntil(this.onDestroy$))
.subscribe(this.updateTaskDetails.bind(this));
this.cardViewUpdateService.itemUpdated$.pipe(takeUntil(this.onDestroy$)).subscribe(this.updateTaskDetails.bind(this));
this.cardViewUpdateService.itemClicked$
.pipe(takeUntil(this.onDestroy$))
.subscribe(this.clickTaskDetails.bind(this));
this.cardViewUpdateService.itemClicked$.pipe(takeUntil(this.onDestroy$)).subscribe(this.clickTaskDetails.bind(this));
}
ngOnDestroy() {
@@ -221,7 +217,7 @@ export class TaskDetailsComponent implements OnInit, OnChanges, OnDestroy {
if (taskId && !taskId.currentValue) {
this.reset();
} else if (taskId && taskId.currentValue) {
} else if (taskId?.currentValue) {
this.loadDetails(taskId.currentValue);
}
}
@@ -276,7 +272,7 @@ export class TaskDetailsComponent implements OnInit, OnChanges, OnDestroy {
}
onFormLoaded(form: FormModel): void {
this.taskFormName = (form && form.name ? form.name : null);
this.taskFormName = form?.name;
this.formLoaded.emit(form);
}
@@ -312,14 +308,13 @@ export class TaskDetailsComponent implements OnInit, OnChanges, OnDestroy {
}
searchUser(searchedWord: string) {
this.peopleProcessService.getWorkflowUsers(null, searchedWord)
.subscribe(
users => {
users = users.filter((user) => user.id !== this.taskDetails.assignee.id);
this.peopleSearchObserver.next(users);
},
() => this.logService.error('Could not load users')
);
this.peopleProcessService.getWorkflowUsers(null, searchedWord).subscribe(
(users) => {
users = users.filter((user) => user.id !== this.taskDetails.assignee.id);
this.peopleSearchObserver.next(users);
},
() => this.logService.error('Could not load users')
);
}
onCloseSearch() {
@@ -327,12 +322,10 @@ export class TaskDetailsComponent implements OnInit, OnChanges, OnDestroy {
}
assignTaskToUser(selectedUser: UserProcessModel) {
this.taskListService
.assignTask(this.taskDetails.id, selectedUser)
.subscribe(() => {
this.logService.info('Task Assigned to ' + selectedUser.email);
this.assignTask.emit();
});
this.taskListService.assignTask(this.taskDetails.id, selectedUser).subscribe(() => {
this.logService.info('Task Assigned to ' + selectedUser.email);
this.assignTask.emit();
});
this.showAssignee = false;
}
@@ -345,7 +338,7 @@ export class TaskDetailsComponent implements OnInit, OnChanges, OnDestroy {
}
isReadOnlyComment(): boolean {
return (this.taskDetails && this.taskDetails.isCompleted()) && (this.taskPeople && this.taskPeople.length === 0);
return this.taskDetails?.isCompleted() && this.taskPeople?.length === 0;
}
private reset() {
@@ -355,10 +348,12 @@ export class TaskDetailsComponent implements OnInit, OnChanges, OnDestroy {
private updateTaskDetails(updateNotification: UpdateNotification) {
this.taskListService
.updateTask(this.taskId, updateNotification.changed)
.pipe(catchError(() => {
this.cardViewUpdateService.updateElement(updateNotification.target);
return of(null);
}))
.pipe(
catchError(() => {
this.cardViewUpdateService.updateElement(updateNotification.target);
return of(null);
})
)
.subscribe(() => this.loadDetails(this.taskId));
}
@@ -375,38 +370,35 @@ export class TaskDetailsComponent implements OnInit, OnChanges, OnDestroy {
this.taskPeople = [];
if (taskId) {
this.taskListService.getTaskDetails(taskId).subscribe(
(res: TaskDetailsModel) => {
this.showAttachForm = false;
this.taskDetails = res;
this.taskListService.getTaskDetails(taskId).subscribe((res) => {
this.showAttachForm = false;
this.taskDetails = res;
if (this.taskDetails.name === 'null') {
this.taskDetails.name = 'No name';
}
if (this.taskDetails.name === 'null') {
this.taskDetails.name = 'No name';
}
const endDate: any = res.endDate;
if (endDate && !isNaN(endDate.getTime())) {
this.internalReadOnlyForm = true;
} else {
this.internalReadOnlyForm = this.readOnlyForm;
}
const endDate: any = res.endDate;
if (endDate && !isNaN(endDate.getTime())) {
this.internalReadOnlyForm = true;
} else {
this.internalReadOnlyForm = this.readOnlyForm;
}
if (this.taskDetails && this.taskDetails.involvedPeople) {
this.taskDetails.involvedPeople.forEach((user) => {
this.taskPeople.push(new UserProcessModel(user));
});
}
});
if (this.taskDetails?.involvedPeople) {
this.taskDetails.involvedPeople.forEach((user) => {
this.taskPeople.push(new UserProcessModel(user));
});
}
});
}
}
private loadNextTask(processInstanceId: string, processDefinitionId: string): void {
const requestNode = new TaskQueryRequestRepresentationModel(
{
processInstanceId,
processDefinitionId
}
);
const requestNode = new TaskQueryRequestRepresentationModel({
processInstanceId,
processDefinitionId
});
this.taskListService.getTasks(requestNode).subscribe(
(response) => {
if (response && response.length > 0) {
@@ -414,8 +406,10 @@ export class TaskDetailsComponent implements OnInit, OnChanges, OnDestroy {
} else {
this.reset();
}
}, (error) => {
},
(error) => {
this.error.emit(error);
});
}
);
}
}

View File

@@ -32,7 +32,6 @@ import { filter, takeUntil } from 'rxjs/operators';
encapsulation: ViewEncapsulation.None
})
export class TaskFiltersComponent implements OnInit, OnChanges, OnDestroy {
/** Parameters to use for the task filter. If there is no match then
* the default filter (the first one the list) is selected.
*/
@@ -71,7 +70,7 @@ export class TaskFiltersComponent implements OnInit, OnChanges, OnDestroy {
currentFilter: FilterRepresentationModel;
filters: FilterRepresentationModel [] = [];
filters: FilterRepresentationModel[] = [];
private onDestroy$ = new Subject<boolean>();
isTaskRoute: boolean;
@@ -79,12 +78,13 @@ export class TaskFiltersComponent implements OnInit, OnChanges, OnDestroy {
private iconsMDL: IconModel;
constructor(private taskFilterService: TaskFilterService,
private taskListService: TaskListService,
private appsProcessService: AppsProcessService,
private router: Router,
private activatedRoute: ActivatedRoute) {
}
constructor(
private taskFilterService: TaskFilterService,
private taskListService: TaskListService,
private appsProcessService: AppsProcessService,
private router: Router,
private activatedRoute: ActivatedRoute
) {}
ngOnInit() {
this.iconsMDL = new IconModel();
@@ -97,17 +97,17 @@ export class TaskFiltersComponent implements OnInit, OnChanges, OnDestroy {
const activeRoute = navigationStart.url;
this.isTaskActive = activeRoute.includes('tasks');
});
this.activatedRoute.url.subscribe((segments) => {
const currentRoute = segments.join('/');
this.isTaskRoute = currentRoute.includes('tasks');
});
this.activatedRoute.url.subscribe((segments) => {
const currentRoute = segments.join('/');
this.isTaskRoute = currentRoute.includes('tasks');
});
}
ngOnChanges(changes: SimpleChanges) {
const appName = changes['appName'];
const appId = changes['appId'];
const filterParam = changes['filterParam'];
if (appName && appName.currentValue) {
if (appName?.currentValue) {
this.getFiltersByAppName(appName.currentValue);
} else if (appId && appId.currentValue !== appId.previousValue) {
this.getFiltersByAppId(appId.currentValue);
@@ -169,7 +169,8 @@ export class TaskFiltersComponent implements OnInit, OnChanges, OnDestroy {
},
(err) => {
this.error.emit(err);
});
}
);
}
/**
@@ -198,12 +199,12 @@ export class TaskFiltersComponent implements OnInit, OnChanges, OnDestroy {
*/
public selectFilter(newFilter: FilterParamsModel) {
if (newFilter) {
this.currentFilter = this.filters.find( (entry, index) =>
newFilter.index === index ||
newFilter.id === entry.id ||
(newFilter.name &&
(newFilter.name.toLocaleLowerCase() === entry.name.toLocaleLowerCase())
));
this.currentFilter = this.filters.find(
(entry, index) =>
newFilter.index === index ||
newFilter.id === entry.id ||
(newFilter.name && newFilter.name.toLocaleLowerCase() === entry.name.toLocaleLowerCase())
);
}
}
@@ -239,7 +240,8 @@ export class TaskFiltersComponent implements OnInit, OnChanges, OnDestroy {
this.selectFilter(filteredFilterList[0]);
this.filterSelected.emit(this.currentFilter);
}
});
}
);
}
/**

View File

@@ -16,345 +16,336 @@
*/
import { Component, OnInit, Input, Output, EventEmitter, SimpleChanges, ViewEncapsulation, OnChanges } from '@angular/core';
import {
FormModel,
ContentLinkModel,
FormFieldValidator,
FormOutcomeEvent,
TranslationService,
FormFieldModel
} from '@alfresco/adf-core';
import { FormModel, ContentLinkModel, FormFieldValidator, FormOutcomeEvent, TranslationService, FormFieldModel } from '@alfresco/adf-core';
import { TaskDetailsModel } from '../../models/task-details.model';
import { TaskListService } from '../../services/tasklist.service';
import { UserRepresentation, LightGroupRepresentation, LightUserRepresentation } from '@alfresco/js-api';
import { UserRepresentation } from '@alfresco/js-api';
import { Observable } from 'rxjs';
import { PeopleProcessService } from '../../../common/services/people-process.service';
@Component({
selector: 'adf-task-form',
templateUrl: './task-form.component.html',
styleUrls: ['./task-form.component.scss'],
encapsulation: ViewEncapsulation.None
selector: 'adf-task-form',
templateUrl: './task-form.component.html',
styleUrls: ['./task-form.component.scss'],
encapsulation: ViewEncapsulation.None
})
export class TaskFormComponent implements OnInit, OnChanges {
/** (**required**) The id of the task whose details we are asking for. */
@Input()
taskId: string;
/** (**required**) The id of the task whose details we are asking for. */
@Input()
taskId: string;
/** Toggles rendering of the form title. */
@Input()
showFormTitle: boolean = false;
/** Toggles rendering of the form title. */
@Input()
showFormTitle: boolean = false;
/** Toggles rendering of the `Complete` outcome button. */
@Input()
showFormCompleteButton: boolean = true;
/** Toggles rendering of the `Complete` outcome button. */
@Input()
showFormCompleteButton: boolean = true;
/** Toggles rendering of the `Save` outcome button. */
@Input()
showFormSaveButton: boolean = true;
/** Toggles rendering of the `Save` outcome button. */
@Input()
showFormSaveButton: boolean = true;
/** Toggle rendering of the `Cancel` button. */
@Input()
showCancelButton: boolean = true;
/** Toggle rendering of the `Cancel` button. */
@Input()
showCancelButton: boolean = true;
/** Toggles read-only state of the form. All form widgets render as read-only
* if enabled.
*/
@Input()
readOnlyForm: boolean = false;
/** Toggles read-only state of the form. All form widgets render as read-only
* if enabled.
*/
@Input()
readOnlyForm: boolean = false;
/** Toggles rendering of the `Refresh` button. */
@Input()
showFormRefreshButton: boolean = true;
/** Toggles rendering of the `Refresh` button. */
@Input()
showFormRefreshButton: boolean = true;
/** Toggle rendering of the validation icon next to the form title. */
@Input()
showFormValidationIcon: boolean = true;
/** Toggle rendering of the validation icon next to the form title. */
@Input()
showFormValidationIcon: boolean = true;
/** Field validators for use with the form. */
@Input()
fieldValidators: FormFieldValidator[] = [];
/** Field validators for use with the form. */
@Input()
fieldValidators: FormFieldValidator[] = [];
/** Emitted when the form is submitted with the `Save` or custom outcomes. */
@Output()
formSaved = new EventEmitter<FormModel>();
/** Emitted when the form is submitted with the `Save` or custom outcomes. */
@Output()
formSaved = new EventEmitter<FormModel>();
/** Emitted when the form is submitted with the `Complete` outcome. */
@Output()
formCompleted = new EventEmitter<FormModel>();
/** Emitted when the form is submitted with the `Complete` outcome. */
@Output()
formCompleted = new EventEmitter<FormModel>();
/** Emitted when the form field content is clicked. */
@Output()
formContentClicked = new EventEmitter<ContentLinkModel>();
/** Emitted when the form field content is clicked. */
@Output()
formContentClicked = new EventEmitter<ContentLinkModel>();
/** Emitted when the form is loaded or reloaded. */
@Output()
formLoaded = new EventEmitter<FormModel>();
/** Emitted when the form is loaded or reloaded. */
@Output()
formLoaded = new EventEmitter<FormModel>();
/** Emitted when the form associated with the form task is attached. */
@Output()
showAttachForm = new EventEmitter<void>();
/** Emitted when the form associated with the form task is attached. */
@Output()
showAttachForm = new EventEmitter<void>();
/** Emitted when any outcome is executed. Default behaviour can be prevented
* via `event.preventDefault()`.
*/
@Output()
executeOutcome = new EventEmitter<FormOutcomeEvent>();
/** Emitted when any outcome is executed. Default behaviour can be prevented
* via `event.preventDefault()`.
*/
@Output()
executeOutcome = new EventEmitter<FormOutcomeEvent>();
/** Emitted when the form associated with the task is completed. */
@Output()
completed = new EventEmitter<void>();
/** Emitted when the form associated with the task is completed. */
@Output()
completed = new EventEmitter<void>();
/** Emitted when the supplied form values have a validation error. */
@Output()
formError = new EventEmitter<FormFieldModel[]>();
/** Emitted when the supplied form values have a validation error. */
@Output()
formError = new EventEmitter<FormFieldModel[]>();
/** Emitted when an error occurs. */
@Output()
error = new EventEmitter<any>();
/** Emitted when an error occurs. */
@Output()
error = new EventEmitter<any>();
/** Emitted when the "Cancel" button is clicked. */
@Output()
cancel = new EventEmitter<void>();
/** Emitted when the "Cancel" button is clicked. */
@Output()
cancel = new EventEmitter<void>();
/** Emitted when the task is claimed. */
@Output()
taskClaimed = new EventEmitter<string>();
/** Emitted when the task is claimed. */
@Output()
taskClaimed = new EventEmitter<string>();
/** Emitted when the task is unclaimed (ie, requeued).. */
@Output()
taskUnclaimed = new EventEmitter<string>();
/** Emitted when the task is unclaimed (ie, requeued).. */
@Output()
taskUnclaimed = new EventEmitter<string>();
taskDetails: TaskDetailsModel;
currentLoggedUser: UserRepresentation;
loading: boolean = false;
completedTaskMessage: string;
internalReadOnlyForm: boolean = false;
taskDetails: TaskDetailsModel;
currentLoggedUser: UserRepresentation;
loading: boolean = false;
completedTaskMessage: string;
internalReadOnlyForm: boolean = false;
constructor(
private taskListService: TaskListService,
private peopleProcessService: PeopleProcessService,
private translationService: TranslationService
) {}
constructor(
private taskListService: TaskListService,
private peopleProcessService: PeopleProcessService,
private translationService: TranslationService
) {
}
ngOnInit() {
this.peopleProcessService.getCurrentUserInfo().subscribe(user => {
this.currentLoggedUser = user;
});
this.loadTask(this.taskId);
}
ngOnChanges(changes: SimpleChanges) {
const taskId = changes['taskId'];
if (taskId && taskId.currentValue) {
this.loadTask(this.taskId);
return;
}
}
loadTask(taskId: string) {
this.loading = true;
if (taskId) {
this.taskListService.getTaskDetails(taskId).subscribe(
(res: TaskDetailsModel) => {
this.taskDetails = res;
if (!this.taskDetails.name) {
this.taskDetails.name = 'No name';
}
const endDate: any = res.endDate;
if (endDate && !isNaN(endDate.getTime())) {
this.internalReadOnlyForm = true;
} else {
this.internalReadOnlyForm = this.readOnlyForm;
}
this.loading = false;
ngOnInit() {
this.peopleProcessService.getCurrentUserInfo().subscribe((user) => {
this.currentLoggedUser = user;
});
}
}
onFormSaved(savedForm: FormModel) {
this.formSaved.emit(savedForm);
}
onFormCompleted(form: FormModel) {
this.formCompleted.emit(form);
}
onFormLoaded(form: FormModel): void {
this.formLoaded.emit(form);
}
onFormContentClick(content: ContentLinkModel): void {
this.formContentClicked.emit(content);
}
onFormExecuteOutcome(outcome: FormOutcomeEvent) {
this.executeOutcome.emit(outcome);
}
onFormError(error: any) {
this.formError.emit(error);
}
onError(error: any) {
this.error.emit(error);
}
onCompleteTask() {
this.taskListService.completeTask(this.taskDetails.id).subscribe(
() => this.completed.emit(),
(error) => this.error.emit(error));
}
onCancel() {
this.cancel.emit();
}
onShowAttachForm() {
this.showAttachForm.emit();
}
hasFormKey(): boolean {
return (this.taskDetails && (!!this.taskDetails.formKey));
}
isStandaloneTask(): boolean {
return !(this.taskDetails && (!!this.taskDetails.processDefinitionId));
}
isTaskLoaded(): boolean {
return !!this.taskDetails;
}
isCompletedTask(): boolean {
return this.taskDetails && this.taskDetails.endDate !== undefined && this.taskDetails.endDate !== null;
}
isCompleteButtonVisible(): boolean {
return !this.hasFormKey() && this.isTaskActive() && this.isCompleteButtonEnabled();
}
isTaskActive() {
return this.taskDetails && this.taskDetails.duration === null;
}
isAssigned(): boolean {
return !!this.taskDetails.assignee;
}
isAssignedToMe(): boolean {
return this.isAssigned() && this.hasEmailAddress() ?
this.isEmailEqual() :
this.isExternalIdEqual();
}
isCompleteButtonEnabled(): boolean {
return this.isAssignedToMe() || this.canInitiatorComplete();
}
canInitiatorComplete(): boolean {
return this.taskDetails.initiatorCanCompleteTask;
}
isReadOnlyForm(): boolean {
let readOnlyForm: boolean;
if (this.isCandidateMember()) {
readOnlyForm = this.internalReadOnlyForm || !this.isAssignedToMe();
} else {
readOnlyForm = this.internalReadOnlyForm || !(this.isAssignedToMe() || this.canCurrentUserAsInitiatorComplete() || this.isCurrentUserInvolved());
this.loadTask(this.taskId);
}
return readOnlyForm;
}
ngOnChanges(changes: SimpleChanges) {
const taskId = changes['taskId'];
if (taskId?.currentValue) {
this.loadTask(this.taskId);
return;
}
}
isCurrentUserInvolved(): boolean {
let isInvolved = false;
if (this.taskDetails.involvedPeople && this.currentLoggedUser) {
const userInvolved = this.taskDetails.involvedPeople.find(
(involvedUser: LightUserRepresentation) =>
involvedUser.email.toLocaleLowerCase() === this.currentLoggedUser.email.toLocaleLowerCase() ||
involvedUser.id + '' === this.currentLoggedUser.externalId
loadTask(taskId: string) {
this.loading = true;
if (taskId) {
this.taskListService.getTaskDetails(taskId).subscribe((res) => {
this.taskDetails = res;
if (!this.taskDetails.name) {
this.taskDetails.name = 'No name';
}
const endDate: any = res.endDate;
if (endDate && !isNaN(endDate.getTime())) {
this.internalReadOnlyForm = true;
} else {
this.internalReadOnlyForm = this.readOnlyForm;
}
this.loading = false;
});
}
}
onFormSaved(savedForm: FormModel) {
this.formSaved.emit(savedForm);
}
onFormCompleted(form: FormModel) {
this.formCompleted.emit(form);
}
onFormLoaded(form: FormModel): void {
this.formLoaded.emit(form);
}
onFormContentClick(content: ContentLinkModel): void {
this.formContentClicked.emit(content);
}
onFormExecuteOutcome(outcome: FormOutcomeEvent) {
this.executeOutcome.emit(outcome);
}
onFormError(error: any) {
this.formError.emit(error);
}
onError(error: any) {
this.error.emit(error);
}
onCompleteTask() {
this.taskListService.completeTask(this.taskDetails.id).subscribe(
() => this.completed.emit(),
(error) => this.error.emit(error)
);
isInvolved = !!userInvolved;
}
if (this.taskDetails.involvedGroups?.length && this.currentLoggedUser.groups?.length && !isInvolved) {
const userGroup = this.taskDetails.involvedGroups.find(
(involvedGroup: LightGroupRepresentation) =>
this.currentLoggedUser.groups.find(
group => group.name === involvedGroup.name.toLocaleLowerCase() || group.id === involvedGroup.id
)
onCancel() {
this.cancel.emit();
}
onShowAttachForm() {
this.showAttachForm.emit();
}
hasFormKey(): boolean {
return !!this.taskDetails?.formKey;
}
isStandaloneTask(): boolean {
return !!!this.taskDetails?.processDefinitionId;
}
isTaskLoaded(): boolean {
return !!this.taskDetails;
}
isCompletedTask(): boolean {
return !!this.taskDetails?.endDate;
}
isCompleteButtonVisible(): boolean {
return !this.hasFormKey() && this.isTaskActive() && this.isCompleteButtonEnabled();
}
isTaskActive() {
return this.taskDetails?.duration === null;
}
isAssigned(): boolean {
return !!this.taskDetails.assignee;
}
isAssignedToMe(): boolean {
return this.isAssigned() && this.hasEmailAddress() ? this.isEmailEqual() : this.isExternalIdEqual();
}
isCompleteButtonEnabled(): boolean {
return this.isAssignedToMe() || this.canInitiatorComplete();
}
canInitiatorComplete(): boolean {
return !!this.taskDetails?.initiatorCanCompleteTask;
}
isReadOnlyForm(): boolean {
let readOnlyForm: boolean;
if (this.isCandidateMember()) {
readOnlyForm = this.internalReadOnlyForm || !this.isAssignedToMe();
} else {
readOnlyForm =
this.internalReadOnlyForm || !(this.isAssignedToMe() || this.canCurrentUserAsInitiatorComplete() || this.isCurrentUserInvolved());
}
return readOnlyForm;
}
isCurrentUserInvolved(): boolean {
let isInvolved = false;
if (this.taskDetails.involvedPeople && this.currentLoggedUser) {
const userInvolved = this.taskDetails.involvedPeople.find(
(involvedUser) =>
involvedUser.email.toLocaleLowerCase() === this.currentLoggedUser.email.toLocaleLowerCase() ||
involvedUser.id + '' === this.currentLoggedUser.externalId
);
isInvolved = !!userInvolved;
}
if (this.taskDetails.involvedGroups?.length && this.currentLoggedUser.groups?.length && !isInvolved) {
const userGroup = this.taskDetails.involvedGroups.find((involvedGroup) =>
this.currentLoggedUser.groups.find((group) => group.name === involvedGroup.name.toLocaleLowerCase() || group.id === involvedGroup.id)
);
isInvolved = !!userGroup;
}
return isInvolved;
}
canCurrentUserAsInitiatorComplete(): boolean {
return this.canInitiatorComplete() && this.isProcessInitiator();
}
isProcessInitiator(): boolean {
return this.currentLoggedUser && this.currentLoggedUser.id === +this.taskDetails.processInstanceStartUserId;
}
isSaveButtonVisible(): boolean {
return this.showFormSaveButton && (!this.canInitiatorComplete() || this.isAssignedToMe() || this.isCurrentUserInvolved());
}
canCompleteNoFormTask(): boolean {
return this.isReadOnlyForm();
}
getCompletedTaskTranslatedMessage(): Observable<string> {
return this.translationService.get('ADF_TASK_FORM.COMPLETED_TASK.TITLE', { taskName: this.taskDetails.name });
}
isCandidateMember(): boolean {
return this.taskDetails.managerOfCandidateGroup || this.taskDetails.memberOfCandidateGroup || this.taskDetails.memberOfCandidateUsers;
}
isTaskClaimable(): boolean {
return this.isCandidateMember() && !this.isAssigned();
}
isTaskClaimedByCandidateMember(): boolean {
return this.isCandidateMember() && this.isAssignedToMe() && !this.isCompletedTask();
}
reloadTask() {
this.loadTask(this.taskId);
}
onClaimTask(taskId: string) {
this.taskClaimed.emit(taskId);
}
onClaimTaskError(error: any) {
this.error.emit(error);
}
onUnclaimTask(taskId: string) {
this.taskUnclaimed.emit(taskId);
}
onUnclaimTaskError(error: any) {
this.error.emit(error);
}
private hasEmailAddress(): boolean {
return !!this.taskDetails.assignee.email;
}
private isEmailEqual(): boolean {
return (
this.taskDetails.assignee &&
this.currentLoggedUser &&
this.taskDetails.assignee.email.toLocaleLowerCase() === this.currentLoggedUser.email.toLocaleLowerCase()
);
isInvolved = !!userGroup;
}
return isInvolved;
}
canCurrentUserAsInitiatorComplete(): boolean {
return this.canInitiatorComplete() && this.isProcessInitiator();
}
isProcessInitiator(): boolean {
return this.currentLoggedUser && ( this.currentLoggedUser.id === +this.taskDetails.processInstanceStartUserId);
}
isSaveButtonVisible(): boolean {
return this.showFormSaveButton && (!this.canInitiatorComplete() || this.isAssignedToMe() || this.isCurrentUserInvolved());
}
canCompleteNoFormTask(): boolean {
return this.isReadOnlyForm();
}
getCompletedTaskTranslatedMessage(): Observable<string> {
return this.translationService.get('ADF_TASK_FORM.COMPLETED_TASK.TITLE', { taskName: this.taskDetails.name });
}
isCandidateMember(): boolean {
return this.taskDetails.managerOfCandidateGroup || this.taskDetails.memberOfCandidateGroup || this.taskDetails.memberOfCandidateUsers;
}
isTaskClaimable(): boolean {
return this.isCandidateMember() && !this.isAssigned();
}
isTaskClaimedByCandidateMember(): boolean {
return this.isCandidateMember() && this.isAssignedToMe() && !this.isCompletedTask();
}
reloadTask() {
this.loadTask(this.taskId);
}
onClaimTask(taskId: string) {
this.taskClaimed.emit(taskId);
}
onClaimTaskError(error: any) {
this.error.emit(error);
}
onUnclaimTask(taskId: string) {
this.taskUnclaimed.emit(taskId);
}
onUnclaimTaskError(error: any) {
this.error.emit(error);
}
private hasEmailAddress(): boolean {
return this.taskDetails.assignee.email ? true : false;
}
private isEmailEqual(): boolean {
return (this.taskDetails.assignee && this.currentLoggedUser) && ( this.taskDetails.assignee.email.toLocaleLowerCase() === this.currentLoggedUser.email.toLocaleLowerCase());
}
private isExternalIdEqual(): boolean {
return (this.taskDetails.assignee && this.currentLoggedUser) && (this.taskDetails.assignee.externalId === this.currentLoggedUser.externalId);
}
private isExternalIdEqual(): boolean {
return this.taskDetails.assignee && this.currentLoggedUser && this.taskDetails.assignee.externalId === this.currentLoggedUser.externalId;
}
}

View File

@@ -37,7 +37,6 @@ import { TaskDescriptionValidator } from '../validators/task-description.validat
encapsulation: ViewEncapsulation.None
})
export class TaskHeaderComponent implements OnChanges, OnInit {
/** The name of the form. */
@Input()
formName: string = null;
@@ -58,7 +57,7 @@ export class TaskHeaderComponent implements OnChanges, OnInit {
@Output()
unclaim: EventEmitter<any> = new EventEmitter<any>();
properties: any [] = [];
properties: any[] = [];
inEdit: boolean = false;
displayDateClearAction = false;
dateFormat: string;
@@ -66,9 +65,11 @@ export class TaskHeaderComponent implements OnChanges, OnInit {
private currentUserId: number;
constructor(private peopleProcessService: PeopleProcessService,
private translationService: TranslationService,
private appConfig: AppConfigService) {
constructor(
private peopleProcessService: PeopleProcessService,
private translationService: TranslationService,
private appConfig: AppConfigService
) {
this.dateFormat = this.appConfig.get('dateValues.defaultDateFormat');
this.dateLocale = this.appConfig.get('dateValues.defaultDateLocale');
}
@@ -175,7 +176,7 @@ export class TaskHeaderComponent implements OnChanges, OnInit {
* Returns task's status
*/
getTaskStatus(): string {
return (this.taskDetails && this.taskDetails.isCompleted()) ? 'Completed' : 'Running';
return this.taskDetails?.isCompleted() ? 'Completed' : 'Running';
}
onClaimTask(taskId: string) {
@@ -190,7 +191,7 @@ export class TaskHeaderComponent implements OnChanges, OnInit {
* Returns true if the task is completed
*/
isCompleted(): boolean {
return this.taskDetails && !!this.taskDetails.endDate;
return !!this.taskDetails?.endDate;
}
isFormClickable(): boolean {
@@ -203,120 +204,94 @@ export class TaskHeaderComponent implements OnChanges, OnInit {
private initDefaultProperties(parentInfoMap): any[] {
return [
new CardViewTextItemModel(
{
label: 'ADF_TASK_LIST.PROPERTIES.ASSIGNEE',
value: this.taskDetails.getFullName(),
key: 'assignee',
default: this.translationService.instant('ADF_TASK_LIST.PROPERTIES.ASSIGNEE_DEFAULT'),
clickable: !this.isCompleted(),
icon: 'create'
}
),
new CardViewTextItemModel(
{
label: 'ADF_TASK_LIST.PROPERTIES.STATUS',
value: this.getTaskStatus(),
key: 'status'
}
),
new CardViewIntItemModel(
{
label: 'ADF_TASK_LIST.PROPERTIES.PRIORITY',
value: this.taskDetails.priority,
key: 'priority',
editable: true,
validators: [new CardViewItemLengthValidator(1, 10)]
}
),
new CardViewDateItemModel(
{
label: 'ADF_TASK_LIST.PROPERTIES.DUE_DATE',
value: this.taskDetails.dueDate,
key: 'dueDate',
default: this.translationService.instant('ADF_TASK_LIST.PROPERTIES.DUE_DATE_DEFAULT'),
editable: true,
format: this.dateFormat,
locale: this.dateLocale
}
),
new CardViewTextItemModel(
{
label: 'ADF_TASK_LIST.PROPERTIES.CATEGORY',
value: this.taskDetails.category,
key: 'category',
default: this.translationService.instant('ADF_TASK_LIST.PROPERTIES.CATEGORY_DEFAULT')
}
),
new CardViewMapItemModel(
{
label: 'ADF_TASK_LIST.PROPERTIES.PARENT_NAME',
value: parentInfoMap,
key: 'parentName',
default: this.translationService.instant('ADF_TASK_LIST.PROPERTIES.PARENT_NAME_DEFAULT'),
clickable: true
}
),
new CardViewDateItemModel(
{
label: 'ADF_TASK_LIST.PROPERTIES.CREATED',
value: this.taskDetails.created,
key: 'created',
format: this.dateFormat,
locale: this.dateLocale
}
),
new CardViewTextItemModel(
{
label: 'ADF_TASK_LIST.PROPERTIES.DURATION',
value: this.getTaskDuration(),
key: 'duration'
}
),
new CardViewTextItemModel(
{
label: 'ADF_TASK_LIST.PROPERTIES.PARENT_TASK_ID',
value: this.taskDetails.parentTaskId,
key: 'parentTaskId'
}
),
new CardViewDateItemModel(
{
label: 'ADF_TASK_LIST.PROPERTIES.END_DATE',
value: this.taskDetails.endDate,
key: 'endDate',
format: this.dateFormat,
locale: this.dateLocale
}
),
new CardViewTextItemModel(
{
label: 'ADF_TASK_LIST.PROPERTIES.ID',
value: this.taskDetails.id,
key: 'id'
}
),
new CardViewTextItemModel(
{
label: 'ADF_TASK_LIST.PROPERTIES.DESCRIPTION',
value: this.taskDetails.description,
key: 'description',
default: this.translationService.instant('ADF_TASK_LIST.PROPERTIES.DESCRIPTION_DEFAULT'),
multiline: true,
editable: true,
validators: [new TaskDescriptionValidator()]
}
),
new CardViewTextItemModel(
{
label: 'ADF_TASK_LIST.PROPERTIES.FORM_NAME',
value: this.formName,
key: 'formName',
default: this.translationService.instant('ADF_TASK_LIST.PROPERTIES.FORM_NAME_DEFAULT'),
clickable: this.isFormClickable(),
icon: 'create'
}
)
new CardViewTextItemModel({
label: 'ADF_TASK_LIST.PROPERTIES.ASSIGNEE',
value: this.taskDetails.getFullName(),
key: 'assignee',
default: this.translationService.instant('ADF_TASK_LIST.PROPERTIES.ASSIGNEE_DEFAULT'),
clickable: !this.isCompleted(),
icon: 'create'
}),
new CardViewTextItemModel({
label: 'ADF_TASK_LIST.PROPERTIES.STATUS',
value: this.getTaskStatus(),
key: 'status'
}),
new CardViewIntItemModel({
label: 'ADF_TASK_LIST.PROPERTIES.PRIORITY',
value: this.taskDetails.priority,
key: 'priority',
editable: true,
validators: [new CardViewItemLengthValidator(1, 10)]
}),
new CardViewDateItemModel({
label: 'ADF_TASK_LIST.PROPERTIES.DUE_DATE',
value: this.taskDetails.dueDate,
key: 'dueDate',
default: this.translationService.instant('ADF_TASK_LIST.PROPERTIES.DUE_DATE_DEFAULT'),
editable: true,
format: this.dateFormat,
locale: this.dateLocale
}),
new CardViewTextItemModel({
label: 'ADF_TASK_LIST.PROPERTIES.CATEGORY',
value: this.taskDetails.category,
key: 'category',
default: this.translationService.instant('ADF_TASK_LIST.PROPERTIES.CATEGORY_DEFAULT')
}),
new CardViewMapItemModel({
label: 'ADF_TASK_LIST.PROPERTIES.PARENT_NAME',
value: parentInfoMap,
key: 'parentName',
default: this.translationService.instant('ADF_TASK_LIST.PROPERTIES.PARENT_NAME_DEFAULT'),
clickable: true
}),
new CardViewDateItemModel({
label: 'ADF_TASK_LIST.PROPERTIES.CREATED',
value: this.taskDetails.created,
key: 'created',
format: this.dateFormat,
locale: this.dateLocale
}),
new CardViewTextItemModel({
label: 'ADF_TASK_LIST.PROPERTIES.DURATION',
value: this.getTaskDuration(),
key: 'duration'
}),
new CardViewTextItemModel({
label: 'ADF_TASK_LIST.PROPERTIES.PARENT_TASK_ID',
value: this.taskDetails.parentTaskId,
key: 'parentTaskId'
}),
new CardViewDateItemModel({
label: 'ADF_TASK_LIST.PROPERTIES.END_DATE',
value: this.taskDetails.endDate,
key: 'endDate',
format: this.dateFormat,
locale: this.dateLocale
}),
new CardViewTextItemModel({
label: 'ADF_TASK_LIST.PROPERTIES.ID',
value: this.taskDetails.id,
key: 'id'
}),
new CardViewTextItemModel({
label: 'ADF_TASK_LIST.PROPERTIES.DESCRIPTION',
value: this.taskDetails.description,
key: 'description',
default: this.translationService.instant('ADF_TASK_LIST.PROPERTIES.DESCRIPTION_DEFAULT'),
multiline: true,
editable: true,
validators: [new TaskDescriptionValidator()]
}),
new CardViewTextItemModel({
label: 'ADF_TASK_LIST.PROPERTIES.FORM_NAME',
value: this.formName,
key: 'formName',
default: this.translationService.instant('ADF_TASK_LIST.PROPERTIES.FORM_NAME_DEFAULT'),
clickable: this.isFormClickable(),
icon: 'create'
})
];
}

View File

@@ -16,12 +16,20 @@
*/
import {
DataRowEvent, DataTableAdapter, DataTableSchema, CustomEmptyContentTemplateDirective, CustomLoadingContentTemplateDirective,
AppConfigService, PaginatedComponent,
UserPreferencesService, UserPreferenceValues, PaginationModel, DataCellEvent, DEFAULT_PAGINATION } from '@alfresco/adf-core';
import {
AfterContentInit, Component, ContentChild, EventEmitter,
Input, OnChanges, Output, SimpleChanges, OnDestroy, OnInit } from '@angular/core';
DataRowEvent,
DataTableAdapter,
DataTableSchema,
CustomEmptyContentTemplateDirective,
CustomLoadingContentTemplateDirective,
AppConfigService,
PaginatedComponent,
UserPreferencesService,
UserPreferenceValues,
PaginationModel,
DataCellEvent,
DEFAULT_PAGINATION
} from '@alfresco/adf-core';
import { AfterContentInit, Component, ContentChild, EventEmitter, Input, OnChanges, Output, SimpleChanges, OnDestroy, OnInit } from '@angular/core';
import { Observable, BehaviorSubject, Subject } from 'rxjs';
import { TaskQueryRequestRepresentationModel } from '../models/filter.model';
@@ -39,7 +47,6 @@ export const PRESET_KEY = 'adf-task-list.presets';
styleUrls: ['./task-list.component.css']
})
export class TaskListComponent extends DataTableSchema implements OnChanges, AfterContentInit, PaginatedComponent, OnDestroy, OnInit {
@ContentChild(CustomEmptyContentTemplateDirective)
customEmptyContent: CustomEmptyContentTemplateDirective;
@@ -183,9 +190,7 @@ export class TaskListComponent extends DataTableSchema implements OnChanges, Aft
private onDestroy$ = new Subject<boolean>();
constructor(private taskListService: TaskListService,
appConfigService: AppConfigService,
private userPreferences: UserPreferencesService) {
constructor(private taskListService: TaskListService, appConfigService: AppConfigService, private userPreferences: UserPreferencesService) {
super(appConfigService, PRESET_KEY, taskPresetsDefaultModel);
this.pagination = new BehaviorSubject<PaginationModel>({
@@ -210,7 +215,7 @@ export class TaskListComponent extends DataTableSchema implements OnChanges, Aft
this.userPreferences
.select(UserPreferenceValues.PaginationSize)
.pipe(takeUntil(this.onDestroy$))
.subscribe(pageSize => this.size = pageSize);
.subscribe((pageSize) => (this.size = pageSize));
}
ngOnDestroy() {
@@ -335,12 +340,12 @@ export class TaskListComponent extends DataTableSchema implements OnChanges, Aft
}
currentPage(skipCount: number, maxItems: number): number {
return (skipCount && maxItems) ? Math.floor(skipCount / maxItems) : 0;
return skipCount && maxItems ? Math.floor(skipCount / maxItems) : 0;
}
private isSortChanged(changes: SimpleChanges): boolean {
const actualSort = changes['sort'];
return actualSort && actualSort.currentValue && actualSort.currentValue !== actualSort.previousValue;
return actualSort?.currentValue && actualSort.currentValue !== actualSort.previousValue;
}
private isPropertyChanged(changes: SimpleChanges): boolean {
@@ -349,7 +354,7 @@ export class TaskListComponent extends DataTableSchema implements OnChanges, Aft
const landingTaskId = changes['landingTaskId'];
const page = changes['page'];
const size = changes['size'];
if (landingTaskId && landingTaskId.currentValue && this.isEqualToCurrentId(landingTaskId.currentValue)) {
if (landingTaskId?.currentValue && this.isEqualToCurrentId(landingTaskId.currentValue)) {
changed = false;
} else if (page && page.currentValue !== page.previousValue) {
changed = true;
@@ -364,9 +369,9 @@ export class TaskListComponent extends DataTableSchema implements OnChanges, Aft
this.isLoading = true;
this.loadTasksByState()
.pipe(finalize(() => this.isLoading = false))
.pipe(finalize(() => (this.isLoading = false)))
.subscribe(
tasks => {
(tasks) => {
this.rows = this.optimizeTaskDetails(tasks.data);
this.selectTask(this.landingTaskId);
this.success.emit(tasks);
@@ -377,9 +382,10 @@ export class TaskListComponent extends DataTableSchema implements OnChanges, Aft
totalItems: tasks.total
});
},
error => {
(error) => {
this.error.emit(error);
});
}
);
}
private loadTasksByState(): Observable<TaskListModel> {

View File

@@ -21,7 +21,6 @@
import { UserProcessModel } from '../../common/models/user-process.model';
export class StartTaskModel {
name: string;
description: string;
assignee: UserProcessModel;
@@ -30,11 +29,11 @@ export class StartTaskModel {
category: string;
constructor(obj?: any) {
this.name = obj && obj.name || null;
this.description = obj && obj.description || null;
this.assignee = obj && obj.assignee ? new UserProcessModel(obj.assignee) : null;
this.dueDate = obj && obj.dueDate || null;
this.formKey = obj && obj.formKey || null;
this.category = obj && obj.category || null;
this.name = obj?.name;
this.description = obj?.description;
this.assignee = obj?.assignee ? new UserProcessModel(obj.assignee) : null;
this.dueDate = obj?.dueDate;
this.formKey = obj?.formKey;
this.category = obj?.category;
}
}

View File

@@ -17,7 +17,15 @@
import { TestBed } from '@angular/core/testing';
import { fakeAppPromise } from '../../mock';
import { fakeFiltersResponse, fakeAppFilter, dummyMyTasksFilter, dummyInvolvedTasksFilter, dummyQueuedTasksFilter, dummyCompletedTasksFilter, dummyDuplicateMyTasksFilter } from '../../mock/task/task-filters.mock';
import {
fakeFiltersResponse,
fakeAppFilter,
dummyMyTasksFilter,
dummyInvolvedTasksFilter,
dummyQueuedTasksFilter,
dummyCompletedTasksFilter,
dummyDuplicateMyTasksFilter
} from '../../mock/task/task-filters.mock';
import { FilterRepresentationModel } from '../models/filter.model';
import { TaskFilterService } from './task-filter.service';
import { CoreModule } from '@alfresco/adf-core';
@@ -28,15 +36,11 @@ import { of } from 'rxjs';
declare let jasmine: any;
describe('Activiti Task filter Service', () => {
let service: TaskFilterService;
beforeEach(() => {
TestBed.configureTestingModule({
imports: [
CoreModule.forRoot(),
ProcessTestingModule
]
imports: [CoreModule.forRoot(), ProcessTestingModule]
});
service = TestBed.inject(TaskFilterService);
jasmine.Ajax.install();
@@ -47,7 +51,6 @@ describe('Activiti Task filter Service', () => {
});
describe('Content tests', () => {
it('should return the task list filters', (done) => {
service.getTaskListFilters().subscribe((res) => {
expect(res).toBeDefined();
@@ -84,15 +87,14 @@ describe('Activiti Task filter Service', () => {
it('should return the task filter by name', (done) => {
service.getTaskFilterByName('FakeMyTasks').subscribe((res: FilterRepresentationModel) => {
expect(res).toBeDefined();
expect(res.id).toEqual(2);
expect(res.name).toEqual('FakeMyTasks');
expect(res.filter.sort).toEqual('created-desc');
expect(res.filter.state).toEqual('open');
expect(res.filter.assignment).toEqual('fake-assignee');
done();
}
);
expect(res).toBeDefined();
expect(res.id).toEqual(2);
expect(res.name).toEqual('FakeMyTasks');
expect(res.filter.sort).toEqual('created-desc');
expect(res.filter.state).toEqual('open');
expect(res.filter.assignment).toEqual('fake-assignee');
done();
});
jasmine.Ajax.requests.mostRecent().respondWith({
status: 200,
@@ -102,7 +104,7 @@ describe('Activiti Task filter Service', () => {
});
it('should call the api with the appId', (done) => {
spyOn(service, 'callApiTaskFilters').and.returnValue((fakeAppPromise));
spyOn(service, 'callApiTaskFilters').and.returnValue(fakeAppPromise);
const appId = 1;
service.getTaskListFilters(appId).subscribe(() => {
@@ -146,7 +148,11 @@ describe('Activiti Task filter Service', () => {
status: 200,
contentType: 'application/json',
responseText: JSON.stringify({
appId: 1001, id: 111, name: 'My Tasks', icon: 'fake-icon', recent: false
appId: 1001,
id: 111,
name: 'My Tasks',
icon: 'fake-icon',
recent: false
})
});
@@ -154,7 +160,11 @@ describe('Activiti Task filter Service', () => {
status: 200,
contentType: 'application/json',
responseText: JSON.stringify({
appId: 1001, id: 222, name: 'Involved Tasks', icon: 'fake-icon', recent: false
appId: 1001,
id: 222,
name: 'Involved Tasks',
icon: 'fake-icon',
recent: false
})
});
@@ -162,7 +172,11 @@ describe('Activiti Task filter Service', () => {
status: 200,
contentType: 'application/json',
responseText: JSON.stringify({
appId: 1001, id: 333, name: 'Queued Tasks', icon: 'fake-icon', recent: false
appId: 1001,
id: 333,
name: 'Queued Tasks',
icon: 'fake-icon',
recent: false
})
});
@@ -170,7 +184,11 @@ describe('Activiti Task filter Service', () => {
status: 200,
contentType: 'application/json',
responseText: JSON.stringify({
appId: 1001, id: 444, name: 'Completed Tasks', icon: 'fake-icon', recent: false
appId: 1001,
id: 444,
name: 'Completed Tasks',
icon: 'fake-icon',
recent: false
})
});
});
@@ -201,7 +219,11 @@ describe('Activiti Task filter Service', () => {
status: 200,
contentType: 'application/json',
responseText: JSON.stringify({
appId: 1001, id: 111, name: 'My Tasks', icon: 'fake-icon', recent: false
appId: 1001,
id: 111,
name: 'My Tasks',
icon: 'fake-icon',
recent: false
})
});
@@ -209,7 +231,11 @@ describe('Activiti Task filter Service', () => {
status: 200,
contentType: 'application/json',
responseText: JSON.stringify({
appId: 1001, id: 222, name: 'Involved Tasks', icon: 'fake-icon', recent: false
appId: 1001,
id: 222,
name: 'Involved Tasks',
icon: 'fake-icon',
recent: false
})
});
@@ -217,7 +243,11 @@ describe('Activiti Task filter Service', () => {
status: 200,
contentType: 'application/json',
responseText: JSON.stringify({
appId: 1001, id: 333, name: 'Queued Tasks', icon: 'fake-icon', recent: false
appId: 1001,
id: 333,
name: 'Queued Tasks',
icon: 'fake-icon',
recent: false
})
});
@@ -225,7 +255,11 @@ describe('Activiti Task filter Service', () => {
status: 200,
contentType: 'application/json',
responseText: JSON.stringify({
appId: 1001, id: 444, name: 'Completed Tasks', icon: 'fake-icon', recent: false
appId: 1001,
id: 444,
name: 'Completed Tasks',
icon: 'fake-icon',
recent: false
})
});
});
@@ -248,11 +282,13 @@ describe('Activiti Task filter Service', () => {
status: 200,
contentType: 'application/json',
responseText: JSON.stringify({
id: '2233', name: 'FakeNameFilter', filter: { assignment: 'fake-assignment' }
id: '2233',
name: 'FakeNameFilter',
filter: { assignment: 'fake-assignment' }
})
});
});
});
});
describe('isFilterAlreadyExisting', () => {
let dummyTaskFilters: FilterRepresentationModel[];
@@ -268,16 +304,14 @@ describe('Activiti Task filter Service', () => {
index: 0,
name: 'My Tasks',
recent: false,
hasFilter: () => {
return true;
}
hasFilter: () => true
}
];
filterRepresentationData = {
name : '',
sort : 'created-desc',
state : 'running'
name: '',
sort: 'created-desc',
state: 'running'
};
});
@@ -295,7 +329,6 @@ describe('Activiti Task filter Service', () => {
});
describe('createDefaultFilters', () => {
it('should return an array with unique task filters', (done) => {
const appId = 101;
@@ -316,7 +349,13 @@ describe('Activiti Task filter Service', () => {
spyOn(service, 'getQueuedTasksFilterInstance').and.returnValue(queuedTasksFilter);
spyOn(service, 'getCompletedTasksFilterInstance').and.returnValue(completedTasksFilter);
spyOn(service, 'addFilter').and.returnValues(myTasksObservableObservable, involvedTasksObservable, queuedTasksObservable, completedTasksObservable, duplicateMyTasksObservableObservable);
spyOn(service, 'addFilter').and.returnValues(
myTasksObservableObservable,
involvedTasksObservable,
queuedTasksObservable,
completedTasksObservable,
duplicateMyTasksObservableObservable
);
service.createDefaultFilters(appId).subscribe((result) => {
expect(result).toEqual([
@@ -328,6 +367,5 @@ describe('Activiti Task filter Service', () => {
done();
});
});
});
});