[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

@@ -53,10 +53,6 @@
"@typescript-eslint/no-inferrable-types": "off",
"@typescript-eslint/no-require-imports": "off",
"@typescript-eslint/no-var-requires": "error",
"brace-style": [
"error",
"1tbs"
],
"comma-dangle": "error",
"default-case": "error",
"import/order": "off",

View File

@@ -15,10 +15,7 @@
* limitations under the License.
*/
import {
Component, EventEmitter, Input, OnChanges,
Output, SimpleChanges, OnDestroy, HostListener
} from '@angular/core';
import { Component, EventEmitter, Input, OnChanges, Output, SimpleChanges, OnDestroy, HostListener } from '@angular/core';
import { Observable, of, forkJoin, Subject, Subscription } from 'rxjs';
import { switchMap, takeUntil, map } from 'rxjs/operators';
import {
@@ -40,16 +37,13 @@ import { FormCloudService } from '../services/form-cloud.service';
import { TaskVariableCloud } from '../models/task-variable-cloud.model';
import { TaskDetailsCloudModel } from '../../task/start-task/models/task-details-cloud.model';
import { MatDialog } from '@angular/material/dialog';
import {
ConfirmDialogComponent
} from '@alfresco/adf-content-services';
import { ConfirmDialogComponent } from '@alfresco/adf-content-services';
@Component({
selector: 'adf-cloud-form',
templateUrl: './form-cloud.component.html'
})
export class FormCloudComponent extends FormBaseComponent implements OnChanges, OnDestroy {
/** App name to fetch corresponding form and values. */
@Input()
appName: string = '';
@@ -108,38 +102,34 @@ export class FormCloudComponent extends FormBaseComponent implements OnChanges,
protected onDestroy$ = new Subject<boolean>();
constructor(protected formCloudService: FormCloudService,
protected formService: FormService,
private dialog: MatDialog,
protected visibilityService: WidgetVisibilityService) {
constructor(
protected formCloudService: FormCloudService,
protected formService: FormService,
private dialog: MatDialog,
protected visibilityService: WidgetVisibilityService
) {
super();
this.formService.formContentClicked
.pipe(takeUntil(this.onDestroy$))
.subscribe((content) => {
if (content instanceof UploadWidgetContentLinkModel) {
this.form.setNodeIdValueForViewersLinkedToUploadWidget(content);
this.onFormDataRefreshed(this.form);
this.formService.formDataRefreshed.next(new FormEvent(this.form));
} else {
this.formContentClicked.emit(content);
}
});
this.formService.updateFormValuesRequested
.pipe(takeUntil(this.onDestroy$))
.subscribe((valuesToSetIfNotPresent) => {
this.form.addValuesNotPresent(valuesToSetIfNotPresent);
this.formService.formContentClicked.pipe(takeUntil(this.onDestroy$)).subscribe((content) => {
if (content instanceof UploadWidgetContentLinkModel) {
this.form.setNodeIdValueForViewersLinkedToUploadWidget(content);
this.onFormDataRefreshed(this.form);
});
this.formService.formDataRefreshed.next(new FormEvent(this.form));
} else {
this.formContentClicked.emit(content);
}
});
this.formService.formFieldValueChanged
.pipe(takeUntil(this.onDestroy$))
.subscribe(() => {
if (this.disableSaveButton) {
this.disableSaveButton = false;
}
});
this.formService.updateFormValuesRequested.pipe(takeUntil(this.onDestroy$)).subscribe((valuesToSetIfNotPresent) => {
this.form.addValuesNotPresent(valuesToSetIfNotPresent);
this.onFormDataRefreshed(this.form);
});
this.formService.formFieldValueChanged.pipe(takeUntil(this.onDestroy$)).subscribe(() => {
if (this.disableSaveButton) {
this.disableSaveButton = false;
}
});
}
@HostListener('keydown', ['$event'])
@@ -150,7 +140,7 @@ export class FormCloudComponent extends FormBaseComponent implements OnChanges,
ngOnChanges(changes: SimpleChanges) {
const appName = changes['appName'];
if (appName && appName.currentValue) {
if (appName?.currentValue) {
if (this.taskId) {
this.getFormByTaskId(appName.currentValue, this.taskId, this.appVersion);
} else if (this.formId) {
@@ -160,19 +150,19 @@ export class FormCloudComponent extends FormBaseComponent implements OnChanges,
}
const formId = changes['formId'];
if (formId && formId.currentValue && this.appName) {
if (formId?.currentValue && this.appName) {
this.getFormById(this.appName, formId.currentValue, this.appVersion);
return;
}
const taskId = changes['taskId'];
if (taskId && taskId.currentValue && this.appName) {
if (taskId?.currentValue && this.appName) {
this.getFormByTaskId(this.appName, taskId.currentValue, this.appVersion);
return;
}
const data = changes['data'];
if (data && data.currentValue) {
if (data?.currentValue) {
this.refreshFormData();
return;
}
@@ -191,12 +181,11 @@ export class FormCloudComponent extends FormBaseComponent implements OnChanges,
} else if (this.appName && this.formId) {
this.getFormById(this.appName, this.formId, this.appVersion);
}
}
findProcessVariablesByTaskId(appName: string, taskId: string): Observable<TaskVariableCloud[]> {
return this.formCloudService.getTask(appName, taskId).pipe(
switchMap(task => {
switchMap((task) => {
if (this.isAProcessTask(task)) {
return this.formCloudService.getTaskVariables(appName, taskId);
} else {
@@ -211,32 +200,29 @@ export class FormCloudComponent extends FormBaseComponent implements OnChanges,
}
getFormByTaskId(appName: string, taskId: string, version?: number): Promise<FormModel> {
return new Promise<FormModel>(resolve => {
forkJoin(
this.formCloudService.getTaskForm(appName, taskId, version),
this.formCloudService.getTaskVariables(appName, taskId)
)
.pipe(takeUntil(this.onDestroy$))
.subscribe(
(data) => {
this.formCloudRepresentationJSON = data[0];
return new Promise<FormModel>((resolve) => {
forkJoin(this.formCloudService.getTaskForm(appName, taskId, version), this.formCloudService.getTaskVariables(appName, taskId))
.pipe(takeUntil(this.onDestroy$))
.subscribe(
(data) => {
this.formCloudRepresentationJSON = data[0];
this.formCloudRepresentationJSON.processVariables = data[1];
this.data = data[1];
this.formCloudRepresentationJSON.processVariables = data[1];
this.data = data[1];
const parsedForm = this.parseForm(this.formCloudRepresentationJSON);
this.visibilityService.refreshVisibility(parsedForm, this.data);
parsedForm.validateForm();
this.form = parsedForm;
this.form.nodeId = '-my-';
this.onFormLoaded(this.form);
resolve(this.form);
},
(error) => {
this.handleError(error);
resolve(null);
}
);
const parsedForm = this.parseForm(this.formCloudRepresentationJSON);
this.visibilityService.refreshVisibility(parsedForm, this.data);
parsedForm.validateForm();
this.form = parsedForm;
this.form.nodeId = '-my-';
this.onFormLoaded(this.form);
resolve(this.form);
},
(error) => {
this.handleError(error);
resolve(null);
}
);
});
}
@@ -244,12 +230,13 @@ export class FormCloudComponent extends FormBaseComponent implements OnChanges,
this.formCloudService
.getForm(appName, formId, appVersion)
.pipe(
map((form: any) => {
map((form) => {
const flattenForm = { ...form.formRepresentation, ...form.formRepresentation.formDefinition };
delete flattenForm.formDefinition;
return flattenForm;
}),
takeUntil(this.onDestroy$))
takeUntil(this.onDestroy$)
)
.subscribe(
(form) => {
this.formCloudRepresentationJSON = form;
@@ -289,13 +276,11 @@ export class FormCloudComponent extends FormBaseComponent implements OnChanges,
minWidth: '450px'
});
dialogRef.afterClosed()
.subscribe(
(result) => {
if (result === true) {
this.completeForm(outcome);
}
});
dialogRef.afterClosed().subscribe((result) => {
if (result === true) {
this.completeForm(outcome);
}
});
} else {
this.completeForm(outcome);
}
@@ -318,7 +303,7 @@ export class FormCloudComponent extends FormBaseComponent implements OnChanges,
parseForm(formCloudRepresentationJSON: any): FormModel {
if (formCloudRepresentationJSON) {
const formValues: FormValues = {};
(this.data || []).forEach(variable => {
(this.data || []).forEach((variable) => {
formValues[variable.name] = variable.value;
});
@@ -340,13 +325,11 @@ export class FormCloudComponent extends FormBaseComponent implements OnChanges,
* @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);
}
}
@@ -392,8 +375,7 @@ export class FormCloudComponent extends FormBaseComponent implements OnChanges,
return !args.defaultPrevented;
}
protected storeFormAsMetadata() {
}
protected storeFormAsMetadata() {}
ngOnDestroy() {
this.onDestroy$.next(true);

View File

@@ -44,7 +44,6 @@ import { VersionManagerUploadData } from '@alfresco/adf-content-services';
encapsulation: ViewEncapsulation.None
})
export class UploadCloudWidgetComponent extends WidgetComponent implements OnInit {
hasFile: boolean;
displayText: string;
multipleOption: string = '';
@@ -58,14 +57,13 @@ export class UploadCloudWidgetComponent extends WidgetComponent implements OnIni
private thumbnailService: ThumbnailService,
protected processCloudContentService: ProcessCloudContentService,
protected notificationService: NotificationService,
protected logService: LogService) {
protected logService: LogService
) {
super(formService);
}
ngOnInit() {
if (this.field &&
this.field.value &&
this.field.value.length > 0) {
if (this.field?.value?.length > 0) {
this.hasFile = true;
this.fixIncompatibilityFromPreviousAndNewForm([]);
}
@@ -80,8 +78,8 @@ export class UploadCloudWidgetComponent extends WidgetComponent implements OnIni
}
replaceOldFileVersionWithNew(versionManagerData: VersionManagerUploadData) {
const currentUploadedFileIndex = this.uploadedFiles.findIndex(file => file.name === versionManagerData.currentVersion.name);
this.uploadedFiles[currentUploadedFileIndex] = { ...versionManagerData.newVersion.value.entry};
const currentUploadedFileIndex = this.uploadedFiles.findIndex((file) => file.name === versionManagerData.currentVersion.name);
this.uploadedFiles[currentUploadedFileIndex] = { ...versionManagerData.newVersion.value.entry };
this.field.value = [...this.uploadedFiles];
this.field.form.values[this.field.id] = [...this.uploadedFiles];
}
@@ -116,12 +114,12 @@ export class UploadCloudWidgetComponent extends WidgetComponent implements OnIni
private isUploaded(file: File): boolean {
const current: Node[] = this.field.value || [];
return current.some(entry => entry.name === file.name);
return current.some((entry) => entry.name === file.name);
}
protected fixIncompatibilityFromPreviousAndNewForm(filesSaved: Node[]) {
const value: Node[] = [...this.field.value || []];
value.push(...filesSaved || []);
const value: Node[] = [...(this.field.value || [])];
value.push(...(filesSaved || []));
this.field.value = value;
this.field.form.values[this.field.id] = value;
@@ -138,9 +136,7 @@ export class UploadCloudWidgetComponent extends WidgetComponent implements OnIni
}
getMultipleFileParam() {
if (this.field &&
this.field.params &&
this.field.params.multiple) {
if (this.field?.params?.multiple) {
this.multipleOption = this.field.params.multiple ? 'multiple' : '';
}
}
@@ -151,7 +147,7 @@ export class UploadCloudWidgetComponent extends WidgetComponent implements OnIni
}
private removeElementFromList(file: any) {
const filteredValues = this.uploadedFiles.filter(value => value.id !== file.id);
const filteredValues = this.uploadedFiles.filter((value) => value.id !== file.id);
this.resetFormValues(filteredValues);
}

View File

@@ -27,7 +27,6 @@ import { Node } from '@alfresco/js-api';
encapsulation: ViewEncapsulation.None
})
export class PropertiesViewerWrapperComponent implements OnInit, OnChanges {
node: Node;
loading = true;
@@ -36,21 +35,21 @@ export class PropertiesViewerWrapperComponent implements OnInit, OnChanges {
/** Toggles whether the edit button should be shown */
@Input()
editable;
editable: boolean;
/** Toggles whether to display empty values in the card view */
@Input()
displayEmpty;
displayEmpty: boolean;
/** Toggles between expanded (ie, full information) and collapsed
* (ie, reduced information) in the display
*/
@Input()
expanded;
expanded: boolean;
/** The multi parameter of the underlying material expansion panel, set to true to allow multi accordion to be expanded at the same time */
@Input()
multi;
multi: boolean;
/** Name or configuration of the metadata preset, which defines aspects and their properties */
@Input()
@@ -58,27 +57,27 @@ export class PropertiesViewerWrapperComponent implements OnInit, OnChanges {
/** Toggles whether the metadata properties should be shown */
@Input()
displayDefaultProperties;
displayDefaultProperties: boolean;
/** (optional) shows the given aspect in the expanded card */
@Input()
displayAspect: string = null;
/** Toggles whether or not to enable copy to clipboard action. */
/** Toggles the clipboard action. */
@Input()
copyToClipboardAction;
copyToClipboardAction: boolean;
/** Toggles whether or not to enable chips for multivalued properties. */
/** Toggles chips for multivalued properties. */
@Input()
useChipsForMultiValueProperty;
useChipsForMultiValueProperty: boolean;
@Output()
nodeContentLoaded: EventEmitter<Node> = new EventEmitter();
nodeContentLoaded = new EventEmitter<Node>();
constructor(private nodesApiService: NodesApiService) { }
constructor(private nodesApiService: NodesApiService) {}
ngOnChanges(changes: SimpleChanges): void {
if (changes && changes['nodeId'] && changes['nodeId'].currentValue && !changes['nodeId'].isFirstChange()) {
if (changes?.['nodeId'] && changes['nodeId'].currentValue && !changes['nodeId'].isFirstChange()) {
this.getNode(changes['nodeId'].currentValue);
}
}
@@ -91,7 +90,7 @@ export class PropertiesViewerWrapperComponent implements OnInit, OnChanges {
private getNode(nodeId: string) {
this.loading = true;
this.nodesApiService.getNode(nodeId).subscribe(retrievedNode => {
this.nodesApiService.getNode(nodeId).subscribe((retrievedNode) => {
this.node = retrievedNode;
this.loading = false;
this.nodeContentLoaded.emit(retrievedNode);

View File

@@ -42,35 +42,40 @@ import { TranslateService } from '@ngx-translate/core';
encapsulation: ViewEncapsulation.None
})
export class RadioButtonsCloudWidgetComponent extends WidgetComponent implements OnInit {
typeId = 'RadioButtonsCloudWidgetComponent';
restApiError: ErrorMessageModel;
protected onDestroy$ = new Subject<boolean>();
constructor(public formService: FormService,
private formCloudService: FormCloudService,
private logService: LogService,
private translateService: TranslateService) {
constructor(
public formService: FormService,
private formCloudService: FormCloudService,
private logService: LogService,
private translateService: TranslateService
) {
super(formService);
}
ngOnInit() {
if (this.field && this.field.restUrl) {
if (this.field?.restUrl) {
this.getValuesFromRestApi();
}
}
getValuesFromRestApi() {
this.formCloudService.getRestWidgetData(this.field.form.id, this.field.id)
this.formCloudService
.getRestWidgetData(this.field.form.id, this.field.id)
.pipe(takeUntil(this.onDestroy$))
.subscribe((result: FormFieldOption[]) => {
this.field.options = result;
this.field.updateForm();
}, (err) => {
this.resetRestApiOptions();
this.handleError(err);
});
.subscribe(
(result: FormFieldOption[]) => {
this.field.options = result;
this.field.updateForm();
},
(err) => {
this.resetRestApiOptions();
this.handleError(err);
}
);
}
onOptionClick(optionSelected: any) {
@@ -79,7 +84,9 @@ export class RadioButtonsCloudWidgetComponent extends WidgetComponent implements
}
handleError(error: any) {
this.restApiError = new ErrorMessageModel({ message: this.translateService.instant('FORM.FIELD.REST_API_FAILED', { hostname: this.getRestUrlHostName() }) });
this.restApiError = new ErrorMessageModel({
message: this.translateService.instant('FORM.FIELD.REST_API_FAILED', { hostname: this.getRestUrlHostName() })
});
this.logService.error(error);
}

View File

@@ -52,22 +52,20 @@ describe('ContentCloudNodeSelectorService', () => {
beforeEach(() => {
TestBed.configureTestingModule({
imports: [TranslateModule.forRoot(), ProcessServiceCloudTestingModule, MatDialogModule],
providers: [
{ provide: AlfrescoApiService, useClass: AlfrescoApiServiceMock }
]
providers: [{ provide: AlfrescoApiService, useClass: AlfrescoApiServiceMock }]
});
service = TestBed.inject(ContentCloudNodeSelectorService);
notificationService = TestBed.inject(NotificationService);
dialog = TestBed.inject(MatDialog);
showWarningSpy = spyOn(notificationService, 'showWarning');
openDialogSpy = spyOn(dialog, 'open').and.returnValue(<any> {
openDialogSpy = spyOn(dialog, 'open').and.returnValue({
afterOpened: () => of({}),
afterClosed: () => of({}),
componentInstance: {
error: new Subject<any>()
}
});
} as any);
getNodeSpy = spyOn(service.nodesApi, 'getNode');
});

View File

@@ -18,11 +18,7 @@
import { Injectable } from '@angular/core';
import { throwError, Observable, from } from 'rxjs';
import { catchError, map } from 'rxjs/operators';
import {
AlfrescoApiService,
LogService,
DownloadService
} from '@alfresco/adf-core';
import { AlfrescoApiService, LogService, DownloadService } from '@alfresco/adf-core';
import { ContentService, NodesApiService } from '@alfresco/adf-content-services';
import { AuthenticationApi, Node, UploadApi } from '@alfresco/js-api';
@@ -30,7 +26,6 @@ import { AuthenticationApi, Node, UploadApi } from '@alfresco/js-api';
providedIn: 'root'
})
export class ProcessCloudContentService {
private _uploadApi: UploadApi;
get uploadApi(): UploadApi {
this._uploadApi = this._uploadApi ?? new UploadApi(this.apiService.getInstance());
@@ -49,22 +44,15 @@ export class ProcessCloudContentService {
private nodesApiService: NodesApiService,
private contentService: ContentService,
private downloadService: DownloadService
) {
}
) {}
createTemporaryRawRelatedContent(
file: File,
nodeId: string
): Observable<Node> {
return from(
this.uploadApi.uploadFile(file, '', nodeId, null, {overwrite: true})
).pipe(
createTemporaryRawRelatedContent(file: File, nodeId: string): Observable<Node> {
return from(this.uploadApi.uploadFile(file, '', nodeId, null, { overwrite: true })).pipe(
map((res: any) => ({
...res.entry,
nodeId: res.entry.id
})),
catchError(err => this.handleError(err))
catchError((err) => this.handleError(err))
);
}
@@ -77,7 +65,6 @@ export class ProcessCloudContentService {
}
async downloadFile(nodeId: string) {
const ticket = await this.getAuthTicket();
const url = this.contentService.getContentUrl(nodeId, true, ticket);
@@ -86,12 +73,7 @@ export class ProcessCloudContentService {
async getAuthTicket(): Promise<string> {
const ticket = await this.authenticationApi.getTicket();
if (ticket && ticket.entry) {
return ticket.entry.id || '';
}
return '';
return ticket?.entry?.id || '';
}
private handleError(error: any) {

View File

@@ -46,16 +46,12 @@ import { IDENTITY_GROUP_SERVICE_TOKEN } from '../services/identity-group-service
animations: [
trigger('transitionMessages', [
state('enter', style({ opacity: 1, transform: 'translateY(0%)' })),
transition('void => enter', [
style({ opacity: 0, transform: 'translateY(-100%)' }),
animate('300ms cubic-bezier(0.55, 0, 0.55, 0.2)')
])
transition('void => enter', [style({ opacity: 0, transform: 'translateY(-100%)' }), animate('300ms cubic-bezier(0.55, 0, 0.55, 0.2)')])
])
],
encapsulation: ViewEncapsulation.None
})
export class GroupCloudComponent implements OnInit, OnChanges, OnDestroy {
/** Name of the application. If specified this shows the groups who have access to the app. */
@Input()
appName: string;
@@ -142,7 +138,8 @@ export class GroupCloudComponent implements OnInit, OnChanges, OnDestroy {
constructor(
@Inject(IDENTITY_GROUP_SERVICE_TOKEN)
private identityGroupService: IdentityGroupServiceInterface,
private logService: LogService) {}
private logService: LogService
) {}
ngOnInit(): void {
this.initSearch();
@@ -165,28 +162,28 @@ export class GroupCloudComponent implements OnInit, OnChanges, OnDestroy {
private initSearch(): void {
this.initializeStream();
this.typingUniqueValueNotEmpty$.pipe(
switchMap((name: string) =>
this.identityGroupService.search(name, { roles: this.roles, withinApplication: this.appName })
),
mergeMap((groups: IdentityGroupModel[]) => {
this.resetSearchGroups();
this.searchLoading = false;
return groups;
}),
filter(group => !this.isGroupAlreadySelected(group)),
takeUntil(this.onDestroy$)
).subscribe((searchedGroup: IdentityGroupModel) => {
this.searchGroups.push(searchedGroup);
this.searchGroups$.next(this.searchGroups);
});
this.typingUniqueValueNotEmpty$
.pipe(
switchMap((name: string) => this.identityGroupService.search(name, { roles: this.roles, withinApplication: this.appName })),
mergeMap((groups: IdentityGroupModel[]) => {
this.resetSearchGroups();
this.searchLoading = false;
return groups;
}),
filter((group) => !this.isGroupAlreadySelected(group)),
takeUntil(this.onDestroy$)
)
.subscribe((searchedGroup: IdentityGroupModel) => {
this.searchGroups.push(searchedGroup);
this.searchGroups$.next(this.searchGroups);
});
}
private initializeStream() {
const typingValueFromControl$ = this.searchGroupsControl.valueChanges;
const typingValueTypeSting$ = typingValueFromControl$.pipe(
filter(value => {
filter((value) => {
this.searchLoading = true;
return typeof value === 'string';
})
@@ -200,10 +197,7 @@ export class GroupCloudComponent implements OnInit, OnChanges, OnDestroy {
})
);
const typingValueDebouncedUnique$ = typingValueHandleErrorMessage$.pipe(
debounceTime(500),
distinctUntilChanged()
);
const typingValueDebouncedUnique$ = typingValueHandleErrorMessage$.pipe(debounceTime(500), distinctUntilChanged());
this.typingUniqueValueNotEmpty$ = typingValueDebouncedUnique$.pipe(
tap((value: string) => {
@@ -233,7 +227,7 @@ export class GroupCloudComponent implements OnInit, OnChanges, OnDestroy {
private getPreselectedGroups(): IdentityGroupModel[] {
if (this.isSingleMode()) {
return [this.preSelectGroups[0]];
return [this.preSelectGroups[0]];
} else {
return this.removeDuplicatedGroups(this.preSelectGroups);
}
@@ -326,7 +320,6 @@ export class GroupCloudComponent implements OnInit, OnChanges, OnDestroy {
this.changedGroups.emit(this.selectedGroups);
if (this.selectedGroups.length === 0) {
this.groupChipsCtrlValue('');
} else {
this.groupChipsCtrlValue(this.selectedGroups[0].name);
}
@@ -340,7 +333,7 @@ export class GroupCloudComponent implements OnInit, OnChanges, OnDestroy {
}
private isPreselectedGroupInvalid(preselectedGroup: IdentityGroupModel, validatedGroup: IdentityGroupModel): boolean {
if (validatedGroup && validatedGroup.name !== undefined) {
if (validatedGroup?.name !== undefined) {
return preselectedGroup.name !== validatedGroup.name;
} else {
return true;
@@ -348,8 +341,9 @@ export class GroupCloudComponent implements OnInit, OnChanges, OnDestroy {
}
removeDuplicatedGroups(groups: IdentityGroupModel[]): IdentityGroupModel[] {
return groups.filter((group, index, self) =>
index === self.findIndex((auxGroup) => group.id === auxGroup.id && group.name === auxGroup.name));
return groups.filter(
(group, index, self) => index === self.findIndex((auxGroup) => group.id === auxGroup.id && group.name === auxGroup.name)
);
}
private groupChipsCtrlValue(value: string) {
@@ -359,7 +353,7 @@ export class GroupCloudComponent implements OnInit, OnChanges, OnDestroy {
}
private removeGroupFromSelected({ id, name }: IdentityGroupModel): void {
const indexToRemove = this.selectedGroups.findIndex(group => group.id === id && group.name === name);
const indexToRemove = this.selectedGroups.findIndex((group) => group.id === id && group.name === name);
if (indexToRemove !== -1) {
this.selectedGroups.splice(indexToRemove, 1);
@@ -367,7 +361,7 @@ export class GroupCloudComponent implements OnInit, OnChanges, OnDestroy {
}
private removeGroupFromValidation({ id, name }: IdentityGroupModel): void {
const indexToRemove = this.invalidGroups.findIndex(group => group.id === id && group.name === name);
const indexToRemove = this.invalidGroups.findIndex((group) => group.id === id && group.name === name);
if (indexToRemove !== -1) {
this.invalidGroups.splice(indexToRemove, 1);
@@ -396,27 +390,19 @@ export class GroupCloudComponent implements OnInit, OnChanges, OnDestroy {
}
private hasModeChanged(changes: SimpleChanges): boolean {
return changes
&& changes.mode
&& changes.mode.currentValue !== changes.mode.previousValue;
return changes?.mode && changes.mode.currentValue !== changes.mode.previousValue;
}
private isValidationChanged(changes: SimpleChanges): boolean {
return changes
&& changes.validate
&& changes.validate.currentValue !== changes.validate.previousValue;
return changes?.validate && changes.validate.currentValue !== changes.validate.previousValue;
}
private hasPreselectedGroupsChanged(changes: SimpleChanges): boolean {
return changes
&& changes.preSelectGroups
&& changes.preSelectGroups.currentValue !== changes.preSelectGroups.previousValue;
return changes?.preSelectGroups && changes.preSelectGroups.currentValue !== changes.preSelectGroups.previousValue;
}
private hasPreselectedGroupsCleared(changes: SimpleChanges): boolean {
return changes
&& changes.preSelectGroups
&& changes.preSelectGroups.currentValue.length === 0;
return changes?.preSelectGroups?.currentValue.length === 0;
}
private setTypingError(): void {
@@ -435,7 +421,7 @@ export class GroupCloudComponent implements OnInit, OnChanges, OnDestroy {
}
getDisplayName(group: IdentityGroupModel): string {
return group ? group.name : '';
return group?.name || '';
}
hasError(): boolean {

View File

@@ -30,15 +30,15 @@ export class ProcessDefinitionCloud {
variableDefinitions?: ProcessVariableDefinition[];
constructor(obj?: any) {
this.id = obj && obj.id || null;
this.name = obj && obj.name || null;
this.appName = obj && obj.appName || null;
this.key = obj && obj.key || null;
this.formKey = obj && obj.formKey || null;
this.version = obj && obj.version || 0;
this.appVersion = obj && obj.appVersion || 0;
this.category = obj && obj?.category || '';
this.description = obj && obj?.description || '';
this.id = obj?.id;
this.name = obj?.name;
this.appName = obj?.appName;
this.key = obj?.key;
this.formKey = obj?.formKey;
this.version = obj?.version || 0;
this.appVersion = obj?.appVersion || 0;
this.category = obj?.category || '';
this.description = obj?.description || '';
this.variableDefinitions = obj?.variableDefinitions ?? [];
}
}

View File

@@ -32,10 +32,7 @@ import {
} from '@angular/core';
import { BehaviorSubject, Observable, Subject } from 'rxjs';
import { switchMap, debounceTime, distinctUntilChanged, mergeMap, tap, filter, takeUntil } from 'rxjs/operators';
import {
FullNamePipe,
LogService
} from '@alfresco/adf-core';
import { FullNamePipe, LogService } from '@alfresco/adf-core';
import { trigger, state, style, transition, animate } from '@angular/animations';
import { ComponentSelectionMode } from '../../types';
import { IdentityUserModel } from '../models/identity-user.model';
@@ -49,18 +46,13 @@ import { IDENTITY_USER_SERVICE_TOKEN } from '../services/identity-user-service.t
animations: [
trigger('transitionMessages', [
state('enter', style({ opacity: 1, transform: 'translateY(0%)' })),
transition('void => enter', [
style({ opacity: 0, transform: 'translateY(-100%)' }),
animate('300ms cubic-bezier(0.55, 0, 0.55, 0.2)')
])
transition('void => enter', [style({ opacity: 0, transform: 'translateY(-100%)' }), animate('300ms cubic-bezier(0.55, 0, 0.55, 0.2)')])
])
],
providers: [FullNamePipe],
encapsulation: ViewEncapsulation.None
})
export class PeopleCloudComponent implements OnInit, OnChanges, OnDestroy {
/** Name of the application. If specified, this shows the users who have access to the app. */
@Input()
appName: string;
@@ -164,7 +156,8 @@ export class PeopleCloudComponent implements OnInit, OnChanges, OnDestroy {
constructor(
@Inject(IDENTITY_USER_SERVICE_TOKEN)
private identityUserService: IdentityUserServiceInterface,
private logService: LogService) { }
private logService: LogService
) {}
ngOnInit(): void {
this.initSearch();
@@ -187,29 +180,31 @@ export class PeopleCloudComponent implements OnInit, OnChanges, OnDestroy {
private initSearch(): void {
this.initializeStream();
this.typingUniqueValueNotEmpty$.pipe(
filter((name: string) => name.length >= 1),
switchMap((name: string) =>
this.identityUserService.search(name, { roles: this.roles, withinApplication: this.appName, groups: this.groupsRestriction })
),
mergeMap((users: IdentityUserModel[]) => {
this.resetSearchUsers();
this.searchLoading = false;
return users;
}),
filter(user => !this.isUserAlreadySelected(user) && !this.isExcludedUser(user)),
takeUntil(this.onDestroy$)
).subscribe((user: IdentityUserModel) => {
this.searchUsers.push(user);
this.searchUsers$.next(this.searchUsers);
});
this.typingUniqueValueNotEmpty$
.pipe(
filter((name: string) => name.length >= 1),
switchMap((name: string) =>
this.identityUserService.search(name, { roles: this.roles, withinApplication: this.appName, groups: this.groupsRestriction })
),
mergeMap((users: IdentityUserModel[]) => {
this.resetSearchUsers();
this.searchLoading = false;
return users;
}),
filter((user) => !this.isUserAlreadySelected(user) && !this.isExcludedUser(user)),
takeUntil(this.onDestroy$)
)
.subscribe((user: IdentityUserModel) => {
this.searchUsers.push(user);
this.searchUsers$.next(this.searchUsers);
});
}
private initializeStream() {
const typingValueFromControl$ = this.searchUserCtrl.valueChanges;
const typingValueTypeSting$ = typingValueFromControl$.pipe(
filter(value => {
filter((value) => {
this.searchLoading = true;
return typeof value === 'string';
})
@@ -223,10 +218,7 @@ export class PeopleCloudComponent implements OnInit, OnChanges, OnDestroy {
})
);
const typingValueDebouncedUnique$ = typingValueHandleErrorMessage$.pipe(
debounceTime(500),
distinctUntilChanged()
);
const typingValueDebouncedUnique$ = typingValueHandleErrorMessage$.pipe(debounceTime(500), distinctUntilChanged());
this.typingUniqueValueNotEmpty$ = typingValueDebouncedUnique$.pipe(
tap((value: string) => {
@@ -256,7 +248,7 @@ export class PeopleCloudComponent implements OnInit, OnChanges, OnDestroy {
private isExcludedUser(searchUser: IdentityUserModel): boolean {
if (this.excludedUsers?.length > 0) {
return !!this.excludedUsers.find(excludedUser => this.equalsUsers(excludedUser, searchUser));
return !!this.excludedUsers.find((excludedUser) => this.equalsUsers(excludedUser, searchUser));
}
return false;
}
@@ -290,7 +282,11 @@ export class PeopleCloudComponent implements OnInit, OnChanges, OnDestroy {
for (const user of this.getPreselectedUsers()) {
try {
const validationResult = (await this.identityUserService.search(user.username, { roles: this.roles, withinApplication: this.appName, groups: this.groupsRestriction }).toPromise())[0];
const validationResult = (
await this.identityUserService
.search(user.username, { roles: this.roles, withinApplication: this.appName, groups: this.groupsRestriction })
.toPromise()
)[0];
if (!this.equalsUsers(user, validationResult)) {
this.invalidUsers.push(user);
@@ -317,10 +313,10 @@ export class PeopleCloudComponent implements OnInit, OnChanges, OnDestroy {
}
removeDuplicatedUsers(users: IdentityUserModel[]): IdentityUserModel[] {
return users.filter((user, index, self) =>
index === self.findIndex(auxUser =>
user.id === auxUser.id && user.username === auxUser.username && user.email === auxUser.email
));
return users.filter(
(user, index, self) =>
index === self.findIndex((auxUser) => user.id === auxUser.id && user.username === auxUser.username && user.email === auxUser.email)
);
}
onSelect(user: IdentityUserModel): void {
@@ -351,7 +347,6 @@ export class PeopleCloudComponent implements OnInit, OnChanges, OnDestroy {
this.changedUsers.emit(this.selectedUsers);
if (this.selectedUsers.length === 0) {
this.userChipsControlValue('');
} else {
this.userChipsControlValue(this.selectedUsers[0].username);
}
@@ -378,9 +373,7 @@ export class PeopleCloudComponent implements OnInit, OnChanges, OnDestroy {
}
private removeUserFromSelected({ id, username, email }: IdentityUserModel): void {
const indexToRemove = this.selectedUsers.findIndex(user => user.id === id
&& user.username === username
&& user.email === email);
const indexToRemove = this.selectedUsers.findIndex((user) => user.id === id && user.username === username && user.email === email);
if (indexToRemove !== -1) {
this.selectedUsers.splice(indexToRemove, 1);
@@ -388,9 +381,7 @@ export class PeopleCloudComponent implements OnInit, OnChanges, OnDestroy {
}
private removeUserFromValidation({ id, username, email }: IdentityUserModel): void {
const indexToRemove = this.invalidUsers.findIndex(user => user.id === id
&& user.username === username
&& user.email === email);
const indexToRemove = this.invalidUsers.findIndex((user) => user.id === id && user.username === username && user.email === email);
if (indexToRemove !== -1) {
this.invalidUsers.splice(indexToRemove, 1);
@@ -410,8 +401,7 @@ export class PeopleCloudComponent implements OnInit, OnChanges, OnDestroy {
}
hasPreselectError(): boolean {
return this.invalidUsers
&& this.invalidUsers.length > 0;
return this.invalidUsers && this.invalidUsers.length > 0;
}
getDisplayName(user): string {
@@ -427,39 +417,27 @@ export class PeopleCloudComponent implements OnInit, OnChanges, OnDestroy {
}
private isSingleSelectionReadonly(): boolean {
return this.isSingleMode()
&& this.selectedUsers.length === 1
&& this.selectedUsers[0].readonly === true;
return this.isSingleMode() && this.selectedUsers.length === 1 && this.selectedUsers[0].readonly === true;
}
private hasPreSelectUsers(): boolean {
return this.preSelectUsers
&& this.preSelectUsers.length > 0;
return this.preSelectUsers && this.preSelectUsers.length > 0;
}
private hasModeChanged(changes: SimpleChanges): boolean {
return changes
&& changes.mode
&& changes.mode.currentValue !== changes.mode.previousValue;
return changes?.mode && changes.mode.currentValue !== changes.mode.previousValue;
}
private isValidationChanged(changes: SimpleChanges): boolean {
return changes
&& changes.validate
&& changes.validate.currentValue !== changes.validate.previousValue;
return changes?.validate && changes.validate.currentValue !== changes.validate.previousValue;
}
private hasPreselectedUsersChanged(changes: SimpleChanges): boolean {
return changes
&& changes.preSelectUsers
&& changes.preSelectUsers.currentValue !== changes.preSelectUsers.previousValue;
return changes?.preSelectUsers && changes.preSelectUsers.currentValue !== changes.preSelectUsers.previousValue;
}
private hasPreselectedUsersCleared(changes: SimpleChanges): boolean {
return changes
&& changes.preSelectUsers
&& changes.preSelectUsers.currentValue
&& changes.preSelectUsers.currentValue.length === 0;
return changes?.preSelectUsers?.currentValue?.length === 0;
}
private resetSearchUsers(): void {

View File

@@ -23,7 +23,13 @@ import { debounceTime, filter, takeUntil, finalize, switchMap, tap } from 'rxjs/
import { Subject, Observable, Subscription } from 'rxjs';
import moment, { Moment } from 'moment';
import { AppsProcessCloudService } from '../../../app/services/apps-process-cloud.service';
import { ProcessFilterCloudModel, ProcessFilterProperties, ProcessFilterAction, ProcessFilterOptions, ProcessSortFilterProperty } from '../models/process-filter-cloud.model';
import {
ProcessFilterCloudModel,
ProcessFilterProperties,
ProcessFilterAction,
ProcessFilterOptions,
ProcessSortFilterProperty
} from '../models/process-filter-cloud.model';
import { TranslationService, UserPreferencesService, UserPreferenceValues } from '@alfresco/adf-core';
import { ProcessFilterCloudService } from '../services/process-filter-cloud.service';
import { ProcessFilterDialogCloudComponent } from './process-filter-dialog-cloud.component';
@@ -152,10 +158,7 @@ export class EditProcessFilterCloudComponent implements OnInit, OnChanges, OnDes
{ value: 'ASC', label: 'ADF_CLOUD_PROCESS_FILTERS.DIRECTION.ASCENDING' },
{ value: 'DESC', label: 'ADF_CLOUD_PROCESS_FILTERS.DIRECTION.DESCENDING' }
];
actionDisabledForDefault = [
PROCESS_FILTER_ACTION_SAVE,
PROCESS_FILTER_ACTION_DELETE
];
actionDisabledForDefault = [PROCESS_FILTER_ACTION_SAVE, PROCESS_FILTER_ACTION_DELETE];
applicationNames: any[] = [];
allProcessDefinitionNamesOption: DropdownOption = {
label: 'ADF_CLOUD_PROCESS_FILTERS.STATUS.ALL',
@@ -181,14 +184,14 @@ export class EditProcessFilterCloudComponent implements OnInit, OnChanges, OnDes
private translateService: TranslationService,
private processFilterCloudService: ProcessFilterCloudService,
private appsProcessCloudService: AppsProcessCloudService,
private processCloudService: ProcessCloudService) {
}
private processCloudService: ProcessCloudService
) {}
ngOnInit() {
this.userPreferencesService
.select(UserPreferenceValues.Locale)
.pipe(takeUntil(this.onDestroy$))
.subscribe(locale => this.dateAdapter.setLocale(locale));
.subscribe((locale) => this.dateAdapter.setLocale(locale));
}
ngOnChanges(changes: SimpleChanges) {
@@ -216,7 +219,7 @@ export class EditProcessFilterCloudComponent implements OnInit, OnChanges, OnDes
return { [property.key]: property.value };
}
});
return properties.reduce(((result, current) => Object.assign(result, current)), {});
return properties.reduce((result, current) => Object.assign(result, current), {});
}
private getAttributesControlConfig(property: ProcessFilterProperties) {
@@ -233,12 +236,10 @@ export class EditProcessFilterCloudComponent implements OnInit, OnChanges, OnDes
this.isLoading = true;
this.processFilterCloudService
.getFilterById(this.appName, this.id)
.pipe(finalize(() => this.isLoading = false))
.subscribe(response => {
.pipe(finalize(() => (this.isLoading = false)))
.subscribe((response) => {
this.filterHasBeenChanged = false;
this.processFilter = new ProcessFilterCloudModel(
Object.assign({}, response || {}, this.processFilter || {})
);
this.processFilter = new ProcessFilterCloudModel(Object.assign({}, response || {}, this.processFilter || {}));
});
}
@@ -288,7 +289,7 @@ export class EditProcessFilterCloudComponent implements OnInit, OnChanges, OnDes
if (this.filterProperties.includes('initiator')) {
this.initiatorOptions = !!this.processFilter.initiator
? this.processFilter.initiator.split(',').map(username => Object.assign({}, { username }))
? this.processFilter.initiator.split(',').map((username) => Object.assign({}, { username }))
: [];
}
@@ -296,14 +297,11 @@ export class EditProcessFilterCloudComponent implements OnInit, OnChanges, OnDes
let filteredProperties = defaultProperties.filter((filterProperty) => this.isValidProperty(this.filterProperties, filterProperty.key));
if (!this.filterProperties.includes('sort')) {
filteredProperties = filteredProperties.filter(property => property.key !== 'order');
filteredProperties = filteredProperties.filter((property) => property.key !== 'order');
}
if (this.filterProperties.includes('lastModified')) {
filteredProperties = [
...filteredProperties,
...this.createLastModifiedProperty(this.processFilter)
];
filteredProperties = [...filteredProperties, ...this.createLastModifiedProperty(this.processFilter)];
}
return filteredProperties;
@@ -329,7 +327,7 @@ export class EditProcessFilterCloudComponent implements OnInit, OnChanges, OnDes
this.appVersionOptions = [];
this.processCloudService.getApplicationVersions(this.appName).subscribe((appVersions) => {
appVersions.forEach(appVersion => {
appVersions.forEach((appVersion) => {
this.appVersionOptions.push({ label: appVersion.entry.version, value: appVersion.entry.version });
});
});
@@ -383,22 +381,18 @@ export class EditProcessFilterCloudComponent implements OnInit, OnChanges, OnDes
}
onDateRangeFilterChanged(dateRange: DateRangeFilter, property: ProcessFilterProperties) {
this.editProcessFilterForm.get(property.attributes?.from).setValue(
dateRange.startDate ? dateRange.startDate : null
);
this.editProcessFilterForm.get(property.attributes?.to).setValue(
dateRange.endDate ? dateRange.endDate : null
);
this.editProcessFilterForm.get(property.attributes?.from).setValue(dateRange.startDate ? dateRange.startDate : null);
this.editProcessFilterForm.get(property.attributes?.to).setValue(dateRange.endDate ? dateRange.endDate : null);
this.editProcessFilterForm.get(property.attributes.dateType).setValue(DateCloudFilterType.RANGE);
}
onChangedUser(users: IdentityUserModel[], processProperty: ProcessFilterProperties) {
this.getPropertyController(processProperty).setValue(users.map(user => user.username).join(','));
this.getPropertyController(processProperty).setValue(users.map((user) => user.username).join(','));
}
hasError(property: ProcessFilterProperties): boolean {
const controller = this.getPropertyController(property);
return controller.errors && controller.errors.invalid;
return !!controller.errors?.invalid;
}
compareFilters(editedQuery: ProcessFilterCloudModel, currentQuery: ProcessFilterCloudModel): boolean {
@@ -408,15 +402,16 @@ export class EditProcessFilterCloudComponent implements OnInit, OnChanges, OnDes
getRunningApplications() {
this.applicationNames = [];
this.appsProcessCloudService
.getDeployedApplicationsByStatus('RUNNING', this.role)
.subscribe((applications) => {
if (applications && applications.length > 0) {
applications.map((application) => {
this.applicationNames.push({ label: this.appsProcessCloudService.getApplicationLabel(application, this.environmentList), value: application.name });
this.appsProcessCloudService.getDeployedApplicationsByStatus('RUNNING', this.role).subscribe((applications) => {
if (applications && applications.length > 0) {
applications.map((application) => {
this.applicationNames.push({
label: this.appsProcessCloudService.getApplicationLabel(application, this.environmentList),
value: application.name
});
}
});
});
}
});
}
getProcessDefinitions() {
@@ -448,13 +443,11 @@ export class EditProcessFilterCloudComponent implements OnInit, OnChanges, OnDes
}
save(saveAction: ProcessFilterAction) {
this.processFilterCloudService
.updateFilter(this.processFilter)
.subscribe(() => {
saveAction.filter = this.processFilter;
this.filterHasBeenChanged = false;
this.action.emit(saveAction);
});
this.processFilterCloudService.updateFilter(this.processFilter).subscribe(() => {
saveAction.filter = this.processFilter;
this.filterHasBeenChanged = false;
this.action.emit(saveAction);
});
}
/**
@@ -469,8 +462,9 @@ export class EditProcessFilterCloudComponent implements OnInit, OnChanges, OnDes
this.action.emit(deleteAction);
return filters.length === 0;
}),
switchMap(() => this.restoreDefaultProcessFilters()))
.subscribe(() => { });
switchMap(() => this.restoreDefaultProcessFilters())
)
.subscribe(() => {});
}
/**
@@ -495,25 +489,26 @@ export class EditProcessFilterCloudComponent implements OnInit, OnChanges, OnDes
key: 'custom-' + filterKey
};
const resultFilter: ProcessFilterCloudModel = Object.assign({}, this.processFilter, newFilter);
this.processFilterCloudService
.addFilter(resultFilter)
.subscribe(() => {
saveAsAction.filter = resultFilter;
this.filterHasBeenChanged = false;
this.action.emit(saveAsAction);
});
this.processFilterCloudService.addFilter(resultFilter).subscribe(() => {
saveAsAction.filter = resultFilter;
this.filterHasBeenChanged = false;
this.action.emit(saveAsAction);
});
}
});
}
reset(resetAction: ProcessFilterAction) {
this.processFilterCloudService.resetProcessFilterToDefaults(this.appName, this.processFilter).pipe(
tap((filters: ProcessFilterCloudModel[]) => {
resetAction.filter = filters.find(defaultFilter => defaultFilter.name === this.processFilter.name) || this.processFilter;
this.action.emit(resetAction);
}),
switchMap(() => this.restoreDefaultProcessFilters()))
.subscribe(() => { });
this.processFilterCloudService
.resetProcessFilterToDefaults(this.appName, this.processFilter)
.pipe(
tap((filters) => {
resetAction.filter = filters.find((defaultFilter) => defaultFilter.name === this.processFilter.name) || this.processFilter;
this.action.emit(resetAction);
}),
switchMap(() => this.restoreDefaultProcessFilters())
)
.subscribe(() => {});
}
/**
@@ -549,16 +544,15 @@ export class EditProcessFilterCloudComponent implements OnInit, OnChanges, OnDes
}
isDisabledAction(action: ProcessFilterAction): boolean {
return (
this.processFilterCloudService.isDefaultFilter(this.processFilter.name) &&
this.actionDisabledForDefault.includes(action.actionType)
) ? true : this.hasFilterChanged(action);
return this.processFilterCloudService.isDefaultFilter(this.processFilter.name) && this.actionDisabledForDefault.includes(action.actionType)
? true
: this.hasFilterChanged(action);
}
hasFilterChanged(action: ProcessFilterAction): boolean {
return action.actionType === PROCESS_FILTER_ACTION_SAVE ||
action.actionType === PROCESS_FILTER_ACTION_SAVE_AS ?
!this.filterHasBeenChanged : false;
return action.actionType === PROCESS_FILTER_ACTION_SAVE || action.actionType === PROCESS_FILTER_ACTION_SAVE_AS
? !this.filterHasBeenChanged
: false;
}
private setLastModifiedToFilter(formValues: ProcessFilterCloudModel) {
@@ -707,12 +701,8 @@ export class EditProcessFilterCloudComponent implements OnInit, OnChanges, OnDes
}
private isFilterChanged(oldValue: ProcessFilterCloudModel, newValue: ProcessFilterCloudModel): boolean {
const oldJson = JSON.stringify(
this.processFilterCloudService.writeQueryParams(oldValue || {}, this.filterProperties)
);
const newJson = JSON.stringify(
this.processFilterCloudService.writeQueryParams(newValue || {}, this.filterProperties)
);
const oldJson = JSON.stringify(this.processFilterCloudService.writeQueryParams(oldValue || {}, this.filterProperties));
const newJson = JSON.stringify(this.processFilterCloudService.writeQueryParams(newValue || {}, this.filterProperties));
return oldJson !== newJson;
}
@@ -722,9 +712,7 @@ export class EditProcessFilterCloudComponent implements OnInit, OnChanges, OnDes
if (filterModel.appVersion) {
appVersionMultiple.push(
Array.isArray(filterModel.appVersion)
? filterModel.appVersion.map(entry => entry.toString())
: `${filterModel.appVersion}`
Array.isArray(filterModel.appVersion) ? filterModel.appVersion.map((entry) => entry.toString()) : `${filterModel.appVersion}`
);
}

View File

@@ -30,7 +30,6 @@ import { takeUntil } from 'rxjs/operators';
encapsulation: ViewEncapsulation.None
})
export class ProcessFiltersCloudComponent implements OnInit, OnChanges, OnDestroy {
/** (required) The application name */
@Input()
appName: string = '';
@@ -60,16 +59,12 @@ export class ProcessFiltersCloudComponent implements OnInit, OnChanges, OnDestro
error = new EventEmitter<any>();
filters$: Observable<ProcessFilterCloudModel[]>;
currentFilter: ProcessFilterCloudModel;
filters: ProcessFilterCloudModel [] = [];
filters: ProcessFilterCloudModel[] = [];
private onDestroy$ = new Subject<boolean>();
constructor(
private processFilterCloudService: ProcessFilterCloudService,
private translationService: TranslationService ) { }
constructor(private processFilterCloudService: ProcessFilterCloudService, private translationService: TranslationService) {}
ngOnInit() {
if (this.appName === '') {
@@ -80,7 +75,7 @@ export class ProcessFiltersCloudComponent implements OnInit, OnChanges, OnDestro
ngOnChanges(changes: SimpleChanges) {
const appName = changes['appName'];
const filter = changes['filterParam'];
if (appName && appName.currentValue) {
if (appName?.currentValue) {
this.getFilters(appName.currentValue);
} else if (filter && filter.currentValue !== filter.previousValue) {
this.selectFilterAndEmit(filter.currentValue);
@@ -94,7 +89,7 @@ export class ProcessFiltersCloudComponent implements OnInit, OnChanges, OnDestro
this.filters$ = this.processFilterCloudService.getProcessFilters(appName);
this.filters$.pipe(takeUntil(this.onDestroy$)).subscribe(
(res: ProcessFilterCloudModel[]) => {
(res) => {
this.resetFilter();
this.filters = res || [];
this.selectFilterAndEmit(this.filterParam);
@@ -111,17 +106,20 @@ export class ProcessFiltersCloudComponent implements OnInit, OnChanges, OnDestro
*/
public selectFilter(paramFilter: FilterParamsModel) {
if (paramFilter) {
this.currentFilter = this.filters.find((filter, index) => paramFilter.id === filter.id ||
(paramFilter.name && this.checkFilterNamesEquality(paramFilter.name, filter.name)) ||
(paramFilter.key && (paramFilter.key === filter.key)) ||
paramFilter.index === index);
this.currentFilter = this.filters.find(
(filter, index) =>
paramFilter.id === filter.id ||
(paramFilter.name && this.checkFilterNamesEquality(paramFilter.name, filter.name)) ||
(paramFilter.key && paramFilter.key === filter.key) ||
paramFilter.index === index
);
}
}
/**
* Check equality of the filter names by translating the given name strings
*/
private checkFilterNamesEquality(name1: string, name2: string ): boolean {
private checkFilterNamesEquality(name1: string, name2: string): boolean {
const translatedName1 = this.translationService.instant(name1);
const translatedName2 = this.translationService.instant(name2);
@@ -144,7 +142,7 @@ export class ProcessFiltersCloudComponent implements OnInit, OnChanges, OnDestro
* Select filter with the id
*/
public selectFilterById(id: string) {
this.selectFilterAndEmit({id});
this.selectFilterAndEmit({ id });
}
/**

View File

@@ -26,13 +26,13 @@ import { IdentityUserService } from '../../../people/services/identity-user.serv
providedIn: 'root'
})
export class ProcessFilterCloudService {
private filtersSubject: BehaviorSubject<ProcessFilterCloudModel[]>;
filters$: Observable<ProcessFilterCloudModel[]>;
constructor(
@Inject(PROCESS_FILTERS_SERVICE_TOKEN) public preferenceService: PreferenceCloudServiceInterface,
private identityUserService: IdentityUserService) {
private identityUserService: IdentityUserService
) {
this.filtersSubject = new BehaviorSubject([]);
this.filters$ = this.filtersSubject.asObservable();
}
@@ -42,7 +42,7 @@ export class ProcessFilterCloudService {
if (obj.hasOwnProperty('appVersion') && obj['appVersion']) {
if (typeof obj['appVersion'] === 'string') {
model.appVersion = obj['appVersion'].split(',').map(str => parseInt(str, 10));
model.appVersion = obj['appVersion'].split(',').map((str) => parseInt(str, 10));
}
}
@@ -62,11 +62,9 @@ export class ProcessFilterCloudService {
const result = {
appName: appName || value['appName'],
id: id || value['id'],
...(
value['environmentId'] && {
environmentId: value['environmentId']
}
)
...(value['environmentId'] && {
environmentId: value['environmentId']
})
};
for (const prop of filterProperties) {
@@ -84,7 +82,6 @@ export class ProcessFilterCloudService {
if (value['lastModifiedTo']) {
result['lastModifiedTo'] = value['lastModifiedTo'].valueOf();
}
} else if (value.hasOwnProperty(prop)) {
result[prop] = value[prop];
}
@@ -101,21 +98,24 @@ export class ProcessFilterCloudService {
*/
private createDefaultFilters(appName: string) {
const key: string = this.prepareKey(appName);
this.preferenceService.getPreferences(appName, key).pipe(
switchMap((response: any) => {
const preferences = (response && response.list && response.list.entries) ? response.list.entries : [];
if (!this.hasPreferences(preferences)) {
return this.createProcessFilters(appName, key, this.defaultProcessFilters(appName));
} else if (!this.hasProcessFilters(preferences, key)) {
return this.createProcessFilters(appName, key, this.defaultProcessFilters(appName));
} else {
return of(this.findFiltersByKeyInPreferences(preferences, key));
}
}),
catchError((err) => this.handleProcessError(err))
).subscribe((filters) => {
this.addFiltersToStream(filters);
});
this.preferenceService
.getPreferences(appName, key)
.pipe(
switchMap((response: any) => {
const preferences = response?.list?.entries ? response.list.entries : [];
if (!this.hasPreferences(preferences)) {
return this.createProcessFilters(appName, key, this.defaultProcessFilters(appName));
} else if (!this.hasProcessFilters(preferences, key)) {
return this.createProcessFilters(appName, key, this.defaultProcessFilters(appName));
} else {
return of(this.findFiltersByKeyInPreferences(preferences, key));
}
}),
catchError((err) => this.handleProcessError(err))
)
.subscribe((filters) => {
this.addFiltersToStream(filters);
});
}
/**
@@ -140,13 +140,13 @@ export class ProcessFilterCloudService {
const key: string = this.prepareKey(appName);
return this.getProcessFiltersByKey(appName, key).pipe(
switchMap((filters: ProcessFilterCloudModel[]) => {
if (filters && filters.length === 0) {
if (filters?.length === 0) {
return this.createProcessFilters(appName, key, this.defaultProcessFilters(appName));
} else {
return of(filters);
}
}),
map((filters: ProcessFilterCloudModel[]) => filters.filter((filter: ProcessFilterCloudModel) => filter.id === id)[0]),
map((filters) => filters.filter((filter) => filter.id === id)[0]),
catchError((err) => this.handleProcessError(err))
);
}
@@ -154,7 +154,7 @@ export class ProcessFilterCloudService {
/**
* Adds a new process instance filter
*
* @param filter The new filter to add
* @param newFilter The new filter to add
* @returns Observable of process instance filters with newly added filter
*/
addFilter(newFilter: ProcessFilterCloudModel): Observable<ProcessFilterCloudModel[]> {
@@ -162,11 +162,11 @@ export class ProcessFilterCloudService {
const key: string = this.prepareKey(appName);
return this.getProcessFiltersByKey(appName, key).pipe(
switchMap((filters: ProcessFilterCloudModel[]) => {
if (filters && filters.length === 0) {
switchMap((filters) => {
if (filters?.length === 0) {
return this.createProcessFilters(appName, key, [newFilter]);
} else {
const index = filters.findIndex(filter => filter.name === name);
const index = filters.findIndex((filter) => filter.name === name);
if (index >= 0) {
filters.splice(index, 1);
}
@@ -186,22 +186,22 @@ export class ProcessFilterCloudService {
/**
* Update process instance filter
*
* @param filter The new filter to update
* @param updatedFilter The new filter to update
* @returns Observable of process instance filters with updated filter
*/
updateFilter(updatedFilter: ProcessFilterCloudModel): Observable<ProcessFilterCloudModel[]> {
const key: string = this.prepareKey(updatedFilter.appName);
return this.getProcessFiltersByKey(updatedFilter.appName, key).pipe(
switchMap((filters: any) => {
if (filters && filters.length === 0) {
switchMap((filters) => {
if (filters?.length === 0) {
return this.createProcessFilters(updatedFilter.appName, key, [updatedFilter]);
} else {
const itemIndex = filters.findIndex((filter: ProcessFilterCloudModel) => filter.id === updatedFilter.id);
const itemIndex = filters.findIndex((filter) => filter.id === updatedFilter.id);
filters[itemIndex] = updatedFilter;
return this.updateProcessFilters(updatedFilter.appName, key, filters);
}
}),
map((updatedFilters: ProcessFilterCloudModel[]) => {
map((updatedFilters) => {
this.addFiltersToStream(updatedFilters);
return updatedFilters;
}),
@@ -212,16 +212,16 @@ export class ProcessFilterCloudService {
/**
* Delete process instance filter
*
* @param filter The new filter to delete
* @param deletedFilter The new filter to delete
* @returns Observable of process instance filters without deleted filter
*/
deleteFilter(deletedFilter: ProcessFilterCloudModel): Observable<ProcessFilterCloudModel[]> {
const key = this.prepareKey(deletedFilter.appName);
return this.getProcessFiltersByKey(deletedFilter.appName, key).pipe(
switchMap(filters => {
switchMap((filters) => {
if (filters && filters.length > 0) {
filters = filters.filter(filter => filter.id !== deletedFilter.id);
filters = filters.filter((filter) => filter.id !== deletedFilter.id);
return this.updateProcessFilters(deletedFilter.appName, key, filters);
} else {
return of([]);
@@ -256,7 +256,8 @@ export class ProcessFilterCloudService {
* @returns Observable of process filters details
*/
resetProcessFilterToDefaults(appName: string, filter: ProcessFilterCloudModel): Observable<ProcessFilterCloudModel[]> {
const defaultFilter = this.defaultProcessFilters(appName).find(defaultFilterDefinition => defaultFilterDefinition.name === filter.name) || filter;
const defaultFilter =
this.defaultProcessFilters(appName).find((defaultFilterDefinition) => defaultFilterDefinition.name === filter.name) || filter;
defaultFilter.id = filter.id;
return this.updateFilter(defaultFilter);
}
@@ -276,12 +277,11 @@ export class ProcessFilterCloudService {
*
* @param preferences User preferences of the target app
* @param key Key of the process instance filters
* @param filters Details of create filter
* @returns Boolean value if the preference has process instance filters
*/
private hasProcessFilters(preferences: any, key: string): boolean {
const filters = preferences.find((filter: any) => filter.entry.key === key);
return (filters && filters.entry) ? JSON.parse(filters.entry.value).length > 0 : false;
return filters?.entry ? JSON.parse(filters.entry.value).length > 0 : false;
}
/**
@@ -339,7 +339,7 @@ export class ProcessFilterCloudService {
*/
private findFiltersByKeyInPreferences(preferences: any, key: string): ProcessFilterCloudModel[] {
const result = preferences.find((filter: any) => filter.entry.key === key);
return result && result.entry ? JSON.parse(result.entry.value) : [];
return result?.entry ? JSON.parse(result.entry.value) : [];
}
private addFiltersToStream(filters: ProcessFilterCloudModel[]) {

View File

@@ -26,7 +26,8 @@ import {
DataRowEvent,
DataTableModule,
getDataColumnMock,
ObjectDataRow, User
ObjectDataRow,
User
} from '@alfresco/adf-core';
import { ProcessListCloudService } from '../services/process-list-cloud.service';
import { ProcessListCloudComponent } from './process-list-cloud.component';
@@ -45,14 +46,13 @@ import { MatProgressSpinnerModule } from '@angular/material/progress-spinner';
import { PreferenceCloudServiceInterface } from '@alfresco/adf-process-services-cloud';
@Component({
template: `
<adf-cloud-process-list #processListCloud>
template: ` <adf-cloud-process-list #processListCloud>
<data-columns>
<data-column key="name" title="ADF_CLOUD_TASK_LIST.PROPERTIES.NAME" class="adf-full-width adf-name-column"></data-column>
<data-column key="created" title="ADF_CLOUD_TASK_LIST.PROPERTIES.CREATED" class="adf-hidden"></data-column>
<data-column key="startedBy" title="ADF_CLOUD_TASK_LIST.PROPERTIES.CREATED" class="adf-desktop-only dw-dt-col-3 adf-ellipsis-cell">
<ng-template let-entry="$implicit">
<div>{{getFullName(entry.row.obj.startedBy)}}</div>
<div>{{ getFullName(entry.row.obj.startedBy) }}</div>
</ng-template>
</data-column>
</data-columns>
@@ -78,10 +78,7 @@ describe('ProcessListCloudComponent', () => {
beforeEach(() => {
TestBed.configureTestingModule({
imports: [
TranslateModule.forRoot(),
ProcessServiceCloudTestingModule
]
imports: [TranslateModule.forRoot(), ProcessServiceCloudTestingModule]
});
appConfig = TestBed.inject(AppConfigService);
processListCloudService = TestBed.inject(ProcessListCloudService);
@@ -136,7 +133,7 @@ describe('ProcessListCloudComponent', () => {
});
it('should display empty content when process list is empty', () => {
const emptyList = {list: {entries: []}};
const emptyList = { list: { entries: [] } };
spyOn(processListCloudService, 'getProcessByRequest').and.returnValue(of(emptyList));
fixture.detectChanges();
@@ -308,11 +305,13 @@ describe('ProcessListCloudComponent', () => {
it('should NOT request process variable if columns for process variables are not displayed', () => {
spyOn(processListCloudService, 'getProcessByRequest').and.returnValue(of(fakeProcessCloudList));
spyOn(preferencesService, 'getPreferences').and.returnValue(of({
list: {
entries: []
}
}));
spyOn(preferencesService, 'getPreferences').and.returnValue(
of({
list: {
entries: []
}
})
);
component.ngAfterContentInit();
component.reload();
@@ -324,16 +323,20 @@ describe('ProcessListCloudComponent', () => {
component.presetColumn = schemaWithVariable;
spyOn(processListCloudService, 'getProcessByRequest').and.returnValue(of(fakeProcessCloudList));
spyOn(preferencesService, 'getPreferences').and.returnValue(of({
list: {
entries: [{
entry: {
key: ProcessListCloudPreferences.columnsVisibility,
value: '{"variableColumnId":"id", "2":true}'
}
}]
}
}));
spyOn(preferencesService, 'getPreferences').and.returnValue(
of({
list: {
entries: [
{
entry: {
key: ProcessListCloudPreferences.columnsVisibility,
value: '{"variableColumnId":"id", "2":true}'
}
}
]
}
})
);
component.ngAfterContentInit();
component.reload();
@@ -462,7 +465,6 @@ describe('ProcessListCloudComponent', () => {
});
describe('component changes', () => {
beforeEach(() => {
component.rows = fakeProcessCloudList.list.entries;
fixture.detectChanges();
@@ -509,13 +511,15 @@ describe('ProcessListCloudComponent', () => {
it('should reload process list when sorting on a column changes', () => {
const getProcessByRequestSpy = spyOn(processListCloudService, 'getProcessByRequest').and.returnValue(of(fakeProcessCloudList));
component.onSortingChanged(new CustomEvent('sorting-changed', {
detail: {
key: 'fakeName',
direction: 'asc'
},
bubbles: true
}));
component.onSortingChanged(
new CustomEvent('sorting-changed', {
detail: {
key: 'fakeName',
direction: 'asc'
},
bubbles: true
})
);
fixture.detectChanges();
expect(component.sorting).toEqual([
new ProcessListCloudSortingModel({
@@ -537,8 +541,7 @@ describe('ProcessListCloudComponent', () => {
const size = component.size;
const skipCount = component.skipCount;
component.pagination.pipe(skip(3))
.subscribe((updatedPagination) => {
component.pagination.pipe(skip(3)).subscribe((updatedPagination) => {
fixture.detectChanges();
expect(component.size).toBe(size);
expect(component.skipCount).toBe(skipCount);
@@ -552,7 +555,7 @@ describe('ProcessListCloudComponent', () => {
skipCount: 200
};
component.updatePagination(pagination);
fixture.whenStable().then( () => {
fixture.whenStable().then(() => {
component.resetPagination();
});
});
@@ -568,8 +571,7 @@ describe('ProcessListCloudComponent', () => {
maxItems: 250,
skipCount: 200
};
component.pagination.pipe(skip(1))
.subscribe((updatedPagination) => {
component.pagination.pipe(skip(1)).subscribe((updatedPagination) => {
fixture.detectChanges();
expect(component.size).toBe(pagination.maxItems);
expect(component.skipCount).toBe(pagination.skipCount);
@@ -581,8 +583,6 @@ describe('ProcessListCloudComponent', () => {
component.updatePagination(pagination);
});
});
});
describe('ProcessListCloudComponent: Injecting custom columns for task list - CustomTaskListComponent', () => {
@@ -591,10 +591,7 @@ describe('ProcessListCloudComponent: Injecting custom columns for task list - Cu
beforeEach(() => {
TestBed.configureTestingModule({
imports: [
TranslateModule.forRoot(),
ProcessServiceCloudTestingModule
],
imports: [TranslateModule.forRoot(), ProcessServiceCloudTestingModule],
declarations: [CustomTaskListComponent]
});
fixtureCustom = TestBed.createComponent(CustomTaskListComponent);
@@ -616,37 +613,29 @@ describe('ProcessListCloudComponent: Injecting custom columns for task list - Cu
});
describe('ProcessListCloudComponent: Creating an empty custom template - EmptyTemplateComponent', () => {
let preferencesService: PreferenceCloudServiceInterface;
@Component({
template: `
<adf-cloud-process-list #processListCloud>
<adf-custom-empty-content-template>
<p id="custom-id">TEST</p>
</adf-custom-empty-content-template>
</adf-cloud-process-list>
`
<adf-cloud-process-list #processListCloud>
<adf-custom-empty-content-template>
<p id="custom-id">TEST</p>
</adf-custom-empty-content-template>
</adf-cloud-process-list>
`
})
class EmptyTemplateComponent {
@ViewChild(ProcessListCloudComponent)
processListCloud: ProcessListCloudComponent;
}
let fixtureEmpty: ComponentFixture<EmptyTemplateComponent>;
preferencesService = jasmine.createSpyObj('preferencesService', {
const preferencesService = jasmine.createSpyObj('preferencesService', {
getPreferences: of({}),
updatePreference: of({})
});
beforeEach(() => {
TestBed.configureTestingModule({
imports: [
TranslateModule.forRoot(),
HttpClientModule,
NoopAnimationsModule,
DataTableModule,
MatProgressSpinnerModule
],
imports: [TranslateModule.forRoot(), HttpClientModule, NoopAnimationsModule, DataTableModule, MatProgressSpinnerModule],
providers: [{ provide: PROCESS_LISTS_PREFERENCES_SERVICE_TOKEN, useValue: preferencesService }],
declarations: [EmptyTemplateComponent, ProcessListCloudComponent, CustomEmptyContentTemplateDirective]
});
@@ -665,6 +654,5 @@ describe('ProcessListCloudComponent: Creating an empty custom template - EmptyTe
expect(fixtureEmpty.debugElement.query(By.css('#custom-id'))).not.toBeNull();
expect(fixtureEmpty.debugElement.query(By.css('.adf-empty-content'))).toBeNull();
});
});

View File

@@ -15,11 +15,35 @@
* limitations under the License.
*/
import { Component, ViewEncapsulation, OnChanges, AfterContentInit, ContentChild, Output, EventEmitter, SimpleChanges, Input, ViewChild, Inject } from '@angular/core';
import { DataTableSchema, PaginatedComponent,
CustomEmptyContentTemplateDirective, AppConfigService,
UserPreferencesService, PaginationModel,
UserPreferenceValues, DataRowEvent, CustomLoadingContentTemplateDirective, DataCellEvent, DataRowActionEvent, DataTableComponent, DataColumn } from '@alfresco/adf-core';
import {
Component,
ViewEncapsulation,
OnChanges,
AfterContentInit,
ContentChild,
Output,
EventEmitter,
SimpleChanges,
Input,
ViewChild,
Inject,
OnDestroy
} from '@angular/core';
import {
DataTableSchema,
PaginatedComponent,
CustomEmptyContentTemplateDirective,
AppConfigService,
UserPreferencesService,
PaginationModel,
UserPreferenceValues,
DataRowEvent,
CustomLoadingContentTemplateDirective,
DataCellEvent,
DataRowActionEvent,
DataTableComponent,
DataColumn
} from '@alfresco/adf-core';
import { ProcessListCloudService } from '../services/process-list-cloud.service';
import { BehaviorSubject, Subject, of } from 'rxjs';
import { processCloudPresetsDefaultModel } from '../models/process-cloud-preset.model';
@@ -41,7 +65,11 @@ const PRESET_KEY = 'adf-cloud-process-list.presets';
styleUrls: ['./process-list-cloud.component.scss'],
encapsulation: ViewEncapsulation.None
})
export class ProcessListCloudComponent extends DataTableSchema<ProcessListDataColumnCustomData> implements OnChanges, AfterContentInit, PaginatedComponent {
export class ProcessListCloudComponent
extends DataTableSchema<ProcessListDataColumnCustomData>
implements OnChanges, AfterContentInit, PaginatedComponent, OnDestroy
// eslint-disable-next-line @typescript-eslint/brace-style
{
@ViewChild(DataTableComponent)
dataTable: DataTableComponent;
@@ -218,12 +246,13 @@ export class ProcessListCloudComponent extends DataTableSchema<ProcessListDataCo
private defaultSorting = { key: 'startDate', direction: 'desc' };
constructor(private processListCloudService: ProcessListCloudService,
appConfigService: AppConfigService,
private userPreferences: UserPreferencesService,
@Inject(PROCESS_LISTS_PREFERENCES_SERVICE_TOKEN) private cloudPreferenceService: PreferenceCloudServiceInterface,
private variableMapperService: VariableMapperService
) {
constructor(
private processListCloudService: ProcessListCloudService,
appConfigService: AppConfigService,
private userPreferences: UserPreferencesService,
@Inject(PROCESS_LISTS_PREFERENCES_SERVICE_TOKEN) private cloudPreferenceService: PreferenceCloudServiceInterface,
private variableMapperService: VariableMapperService
) {
super(appConfigService, PRESET_KEY, processCloudPresetsDefaultModel);
this.size = userPreferences.paginationSize;
this.userPreferences.select(UserPreferenceValues.PaginationSize).subscribe((pageSize) => {
@@ -237,21 +266,24 @@ export class ProcessListCloudComponent extends DataTableSchema<ProcessListDataCo
}
ngAfterContentInit() {
this.cloudPreferenceService.getPreferences(this.appName)
this.cloudPreferenceService
.getPreferences(this.appName)
.pipe(
take(1),
map((preferences => {
const preferencesList = preferences?.list?.entries ?? [];
const columnsOrder = preferencesList.find(preference => preference.entry.key === ProcessListCloudPreferences.columnOrder);
const columnsVisibility = preferencesList.find(preference => preference.entry.key === ProcessListCloudPreferences.columnsVisibility);
const columnsWidths = preferencesList.find(preference => preference.entry.key === ProcessListCloudPreferences.columnsWidths);
map((preferences) => {
const preferencesList = preferences?.list?.entries || [];
const columnsOrder = preferencesList.find((preference) => preference.entry.key === ProcessListCloudPreferences.columnOrder);
const columnsVisibility = preferencesList.find(
(preference) => preference.entry.key === ProcessListCloudPreferences.columnsVisibility
);
const columnsWidths = preferencesList.find((preference) => preference.entry.key === ProcessListCloudPreferences.columnsWidths);
return {
columnsOrder: columnsOrder ? JSON.parse(columnsOrder.entry.value) : undefined,
columnsVisibility: columnsVisibility ? JSON.parse(columnsVisibility.entry.value) : this.columnsVisibility,
columnsWidths: columnsWidths ? JSON.parse(columnsWidths.entry.value) : undefined
};
}))
})
)
.subscribe(({ columnsOrder, columnsVisibility, columnsWidths }) => {
if (columnsVisibility) {
@@ -262,7 +294,6 @@ export class ProcessListCloudComponent extends DataTableSchema<ProcessListDataCo
this.columnsOrder = columnsOrder;
}
if (columnsWidths) {
this.columnsWidths = columnsWidths;
}
@@ -300,26 +331,28 @@ export class ProcessListCloudComponent extends DataTableSchema<ProcessListDataCo
private load() {
this.isLoading = true;
this.isColumnSchemaCreated$.pipe(
switchMap(() => of(this.createRequestNode())),
tap((requestNode) => this.requestNode = requestNode),
switchMap((requestNode) => this.processListCloudService.getProcessByRequest(requestNode)),
takeUntil(this.onDestroy$)
).subscribe((processes) => {
this.rows = this.variableMapperService.mapVariablesByColumnTitle(
processes.list.entries,
this.columns
this.isColumnSchemaCreated$
.pipe(
switchMap(() => of(this.createRequestNode())),
tap((requestNode) => (this.requestNode = requestNode)),
switchMap((requestNode) => this.processListCloudService.getProcessByRequest(requestNode)),
takeUntil(this.onDestroy$)
)
.subscribe(
(processes) => {
this.rows = this.variableMapperService.mapVariablesByColumnTitle(processes.list.entries, this.columns);
this.dataAdapter = new ProcessListDatatableAdapter(this.rows, this.columns);
this.success.emit(processes);
this.isLoading = false;
this.pagination.next(processes.list.pagination);
},
(error) => {
this.error.emit(error);
this.isLoading = false;
}
);
this.dataAdapter = new ProcessListDatatableAdapter(this.rows, this.columns);
this.success.emit(processes);
this.isLoading = false;
this.pagination.next(processes.list.pagination);
}, (error) => {
this.error.emit(error);
this.isLoading = false;
});
}
private isAnyPropertyChanged(changes: SimpleChanges): boolean {
@@ -371,15 +404,11 @@ export class ProcessListCloudComponent extends DataTableSchema<ProcessListDataCo
}
onColumnOrderChanged(columnsWithNewOrder: DataColumn[]): void {
this.columnsOrder = columnsWithNewOrder.map(column => column.id);
this.columnsOrder = columnsWithNewOrder.map((column) => column.id);
this.createColumns();
if (this.appName) {
this.cloudPreferenceService.updatePreference(
this.appName,
ProcessListCloudPreferences.columnOrder,
this.columnsOrder
);
this.cloudPreferenceService.updatePreference(this.appName, ProcessListCloudPreferences.columnOrder, this.columnsOrder);
}
}
@@ -396,11 +425,7 @@ export class ProcessListCloudComponent extends DataTableSchema<ProcessListDataCo
this.createDatatableSchema();
if (this.appName) {
this.cloudPreferenceService.updatePreference(
this.appName,
ProcessListCloudPreferences.columnsVisibility,
this.columnsVisibility
);
this.cloudPreferenceService.updatePreference(this.appName, ProcessListCloudPreferences.columnsVisibility, this.columnsVisibility);
}
}
@@ -412,16 +437,12 @@ export class ProcessListCloudComponent extends DataTableSchema<ProcessListDataCo
return widthsColumnsMap;
}, {});
this.columnsWidths = {...this.columnsWidths, ...newColumnsWidths};
this.columnsWidths = { ...this.columnsWidths, ...newColumnsWidths };
this.createColumns();
if (this.appName) {
this.cloudPreferenceService.updatePreference(
this.appName,
ProcessListCloudPreferences.columnsWidths,
this.columnsWidths
);
this.cloudPreferenceService.updatePreference(this.appName, ProcessListCloudPreferences.columnsWidths, this.columnsWidths);
}
}
@@ -492,22 +513,21 @@ export class ProcessListCloudComponent extends DataTableSchema<ProcessListDataCo
}
getAppVersions(): string {
return this.appVersion instanceof Array ? this.appVersion.join(',') : (this.appVersion ? String(this.appVersion) : '');
return this.appVersion instanceof Array ? this.appVersion.join(',') : this.appVersion ? String(this.appVersion) : '';
}
setSorting(sortDetail) {
const sorting = sortDetail ? {
orderBy: sortDetail.key,
direction: sortDetail.direction.toUpperCase()
} : { ... this.defaultSorting };
const sorting = sortDetail
? {
orderBy: sortDetail.key,
direction: sortDetail.direction.toUpperCase()
}
: { ...this.defaultSorting };
this.sorting = [new ProcessListCloudSortingModel(sorting)];
}
formatSorting(sorting: ProcessListCloudSortingModel[]) {
this.formattedSorting = this.isValidSorting(sorting) ? [
sorting[0].orderBy,
sorting[0].direction.toLocaleLowerCase()
] : null;
this.formattedSorting = this.isValidSorting(sorting) ? [sorting[0].orderBy, sorting[0].direction.toLocaleLowerCase()] : null;
}
isValidSorting(sorting: ProcessListCloudSortingModel[]) {
@@ -516,11 +536,8 @@ export class ProcessListCloudComponent extends DataTableSchema<ProcessListDataCo
private getVariableDefinitionsRequestModel(): string[] | undefined {
const displayedVariableColumns = this.columns
.filter(column =>
column.customData?.columnType === PROCESS_LIST_CUSTOM_VARIABLE_COLUMN &&
column.isHidden !== true
)
.map(column => {
.filter((column) => column.customData?.columnType === PROCESS_LIST_CUSTOM_VARIABLE_COLUMN && column.isHidden !== true)
.map((column) => {
const variableDefinitionsPayload = column.customData.variableDefinitionsPayload;
return variableDefinitionsPayload;
})

View File

@@ -40,8 +40,9 @@ export class ProcessListCloudService extends BaseCloudService {
return callback(queryUrl, queryParams).pipe(
map((response: any) => {
const entries = response.list && response.list.entries;
const entries = response.list?.entries;
if (entries) {
// TODO: this is a hack of the model and needs to be revisited
response.list.entries = entries.map((entryData) => entryData.entry);
}
return response;
@@ -98,7 +99,7 @@ export class ProcessListCloudService extends BaseCloudService {
return queryParams['variableKeys'].split(',');
}
protected isPropertyValueValid(requestNode: any, property: string): boolean {
protected isPropertyValueValid(requestNode: ProcessQueryCloudRequestModel, property: string): boolean {
return requestNode[property] !== '' && requestNode[property] !== null && requestNode[property] !== undefined;
}
@@ -106,9 +107,7 @@ export class ProcessListCloudService extends BaseCloudService {
const queryParam = {};
for (const property in requestNode) {
if (requestNode.hasOwnProperty(property) &&
!this.isExcludedField(property) &&
this.isPropertyValueValid(requestNode, property)) {
if (requestNode.hasOwnProperty(property) && !this.isExcludedField(property) && this.isPropertyValueValid(requestNode, property)) {
queryParam[property] = this.getQueryParamValueFromRequestNode(requestNode, property as keyof ProcessQueryCloudRequestModel);
}
}
@@ -120,12 +119,9 @@ export class ProcessListCloudService extends BaseCloudService {
return queryParam;
}
private getQueryParamValueFromRequestNode(
requestNode: ProcessQueryCloudRequestModel,
property: keyof ProcessQueryCloudRequestModel
) {
private getQueryParamValueFromRequestNode(requestNode: ProcessQueryCloudRequestModel, property: keyof ProcessQueryCloudRequestModel) {
if (property === 'variableKeys' && requestNode[property]?.length > 0) {
return `${requestNode[property].map(variableId => variableId).join(',')}`;
return `${requestNode[property].map((variableId) => variableId).join(',')}`;
}
return requestNode[property];

View File

@@ -42,9 +42,10 @@ export class ProcessTaskListCloudService extends BaseCloudService implements Tas
queryParams['sort'] = sortingParams;
}
return this.get<TaskCloudNodePaging>(queryUrl, queryParams).pipe(
map((response: any) => {
const entries = response.list && response.list.entries;
map((response) => {
const entries = response.list?.entries;
if (entries) {
// TODO: this is a hack of the model and should be revisited
response.list.entries = entries.map((entryData: any) => entryData.entry);
}
return response;
@@ -59,9 +60,7 @@ export class ProcessTaskListCloudService extends BaseCloudService implements Tas
protected buildQueryParams(requestNode: TaskQueryCloudRequestModel): any {
const queryParam: any = {};
for (const property in requestNode) {
if (requestNode.hasOwnProperty(property) &&
!this.isExcludedField(property) &&
this.isPropertyValueValid(requestNode, property)) {
if (requestNode.hasOwnProperty(property) && !this.isExcludedField(property) && this.isPropertyValueValid(requestNode, property)) {
queryParam[property] = requestNode[property];
}
}
@@ -72,7 +71,7 @@ export class ProcessTaskListCloudService extends BaseCloudService implements Tas
return property === 'appName' || property === 'sorting';
}
protected isPropertyValueValid(requestNode: any, property: string): boolean {
protected isPropertyValueValid(requestNode: TaskQueryCloudRequestModel, property: string): boolean {
return requestNode[property] !== '' && requestNode[property] !== null && requestNode[property] !== undefined;
}

View File

@@ -32,8 +32,11 @@ import { MatInputModule } from '@angular/material/input';
import { FormsModule, ReactiveFormsModule } from '@angular/forms';
import {
fakeProcessDefinitions, fakeStartForm, fakeStartFormNotValid,
fakeProcessInstance, fakeNoNameProcessDefinitions,
fakeProcessDefinitions,
fakeStartForm,
fakeStartFormNotValid,
fakeProcessInstance,
fakeNoNameProcessDefinitions,
fakeSingleProcessDefinition,
fakeSingleProcessDefinitionWithoutForm,
fakeFormModelJson
@@ -49,7 +52,6 @@ import { ProcessDefinitionCloud, TaskVariableCloud } from '@alfresco/adf-process
import { first } from 'rxjs/operators';
describe('StartProcessCloudComponent', () => {
let component: StartProcessCloudComponent;
let fixture: ComponentFixture<StartProcessCloudComponent>;
let processService: StartProcessCloudService;
@@ -62,13 +64,14 @@ describe('StartProcessCloudComponent', () => {
const firstChange = new SimpleChange(undefined, 'myApp', true);
const selectOptionByName = async (name: string) => {
const selectElement = fixture.nativeElement.querySelector('button#adf-select-process-dropdown');
selectElement.click();
fixture.detectChanges();
await fixture.whenStable();
const options: any = fixture.debugElement.queryAll(By.css('.mat-autocomplete-panel .mat-option'));
const currentOption: DebugElement = options.find((option: DebugElement) => option.nativeElement.querySelector('.mat-option-text').innerHTML.trim() === name);
const currentOption: DebugElement = options.find(
(option: DebugElement) => option.nativeElement.querySelector('.mat-option-text').innerHTML.trim() === name
);
if (currentOption) {
currentOption.nativeElement.click();
@@ -117,7 +120,6 @@ describe('StartProcessCloudComponent', () => {
});
describe('start a process without start form', () => {
beforeEach(() => {
component.name = 'My formless new process';
component.appName = 'myApp';
@@ -210,7 +212,6 @@ describe('StartProcessCloudComponent', () => {
});
describe('start a process with start form', () => {
beforeEach(() => {
component.name = 'My new process with form';
component.appName = 'startformwithoutupload';
@@ -218,28 +219,32 @@ describe('StartProcessCloudComponent', () => {
fixture.detectChanges();
const change = new SimpleChange(null, 'startformwithoutupload', true);
component.ngOnChanges({ appName: change });
component.values = [{
id: '1',
type: 'string',
name: 'firstName',
value: 'FakeName',
get hasValue() {
return this['value'];
component.values = [
{
id: '1',
type: 'string',
name: 'firstName',
value: 'FakeName',
get hasValue() {
return this['value'];
},
set hasValue(value) {
this['value'] = value;
}
},
set hasValue(value) {
this['value'] = value;
{
id: '1',
type: 'string',
name: 'lastName',
value: 'FakeLastName',
get hasValue() {
return this['value'];
},
set hasValue(value) {
this['value'] = value;
}
}
}, {
id: '1', type: 'string',
name: 'lastName',
value: 'FakeLastName',
get hasValue() {
return this['value'];
},
set hasValue(value) {
this['value'] = value;
}
}];
];
fixture.detectChanges();
});
@@ -350,7 +355,6 @@ describe('StartProcessCloudComponent', () => {
});
describe('process definitions list', () => {
beforeEach(() => {
component.name = 'My new process';
component.appName = 'myApp';
@@ -472,7 +476,7 @@ describe('StartProcessCloudComponent', () => {
fixture.detectChanges();
await fixture.whenStable();
expect(component.processPayloadCloud.name).toBeNull();
expect(component.processPayloadCloud.name).toBeUndefined();
});
it('should select the right process when the processKey begins with the name', async () => {
@@ -492,7 +496,6 @@ describe('StartProcessCloudComponent', () => {
});
describe('dropdown', () => {
it('should hide the process dropdown button if showSelectProcessDropdown is false', async () => {
fixture.detectChanges();
getDefinitionsSpy.and.returnValue(of(fakeProcessDefinitions));
@@ -539,7 +542,6 @@ describe('StartProcessCloudComponent', () => {
});
describe('input changes', () => {
const change = new SimpleChange('myApp', 'myApp1', false);
beforeEach(() => {
@@ -624,7 +626,6 @@ describe('StartProcessCloudComponent', () => {
});
describe('start process', () => {
beforeEach(() => {
fixture.detectChanges();
component.name = 'NewProcess 1';
@@ -667,7 +668,6 @@ describe('StartProcessCloudComponent', () => {
expect(data).not.toBeNull();
expect(data).toEqual(fakeProcessInstance);
});
});
it('should call service with the correct parameters when variables and formCloud are both undefined', async () => {
@@ -876,16 +876,18 @@ describe('StartProcessCloudComponent', () => {
});
it('should set the process name on when a process definition name is present', (done) => {
const definitions: ProcessDefinitionCloud[] = [{
appName: 'app',
appVersion: 1,
category: '',
description: '',
id: 'id',
key: 'key',
name: 'fake-name',
version: 1
}];
const definitions: ProcessDefinitionCloud[] = [
{
appName: 'app',
appVersion: 1,
category: '',
description: '',
id: 'id',
key: 'key',
name: 'fake-name',
version: 1
}
];
component.processInstanceName.valueChanges.subscribe((value) => {
expect(value).toBe(fakeTransformedName);
@@ -969,7 +971,6 @@ describe('StartProcessCloudComponent', () => {
expect(card).toBeTruthy();
});
});
describe('start button', () => {
@@ -1032,6 +1033,5 @@ describe('StartProcessCloudComponent', () => {
});
component.cancelStartProcess();
});
});
});

View File

@@ -16,8 +16,17 @@
*/
import {
Component, EventEmitter, HostListener, Input, OnChanges, OnDestroy, OnInit,
Output, SimpleChanges, ViewChild, ViewEncapsulation
Component,
EventEmitter,
HostListener,
Input,
OnChanges,
OnDestroy,
OnInit,
Output,
SimpleChanges,
ViewChild,
ViewEncapsulation
} from '@angular/core';
import { ContentLinkModel, FormModel } from '@alfresco/adf-core';
@@ -113,14 +122,19 @@ export class StartProcessCloudComponent implements OnChanges, OnInit, OnDestroy
processDefinitionLoaded = false;
loading$ = new BehaviorSubject<boolean>(!this.processDefinitionLoaded);
constructor(private startProcessCloudService: StartProcessCloudService,
constructor(
private startProcessCloudService: StartProcessCloudService,
private formBuilder: UntypedFormBuilder,
private processNameCloudPipe: ProcessNameCloudPipe) {
}
private processNameCloudPipe: ProcessNameCloudPipe
) {}
ngOnInit() {
this.processForm = this.formBuilder.group({
processInstanceName: new UntypedFormControl('', [Validators.required, Validators.maxLength(this.getMaxNameLength()), Validators.pattern('^[^\\s]+(\\s+[^\\s]+)*$')]),
processInstanceName: new UntypedFormControl('', [
Validators.required,
Validators.maxLength(this.getMaxNameLength()),
Validators.pattern('^[^\\s]+(\\s+[^\\s]+)*$')
]),
processDefinition: new UntypedFormControl(this.processDefinitionName, [Validators.required, this.processDefinitionNameValidator()])
});
@@ -167,31 +181,32 @@ export class StartProcessCloudComponent implements OnChanges, OnInit, OnDestroy
private selectProcessDefinitionByProcessDefinitionName(processDefinitionName: string): void {
this.filteredProcesses = this.getProcessDefinitionListByNameOrKey(processDefinitionName);
if (this.isProcessFormValid() &&
this.filteredProcesses && this.filteredProcesses.length === 1) {
if (this.isProcessFormValid() && this.filteredProcesses && this.filteredProcesses.length === 1) {
this.setProcessDefinitionOnForm(this.filteredProcesses[0].name);
}
}
setProcessDefinitionOnForm(selectedProcessDefinitionName: string) {
this.processDefinitionCurrent = this.filteredProcesses.find((process: ProcessDefinitionCloud) =>
process.name === selectedProcessDefinitionName || process.key === selectedProcessDefinitionName);
this.processDefinitionCurrent = this.filteredProcesses.find(
(process: ProcessDefinitionCloud) => process.name === selectedProcessDefinitionName || process.key === selectedProcessDefinitionName
);
this.startProcessCloudService.getStartEventFormStaticValuesMapping(this.appName, this.processDefinitionCurrent.id)
.subscribe(
staticMappings => {
this.staticMappings = staticMappings;
this.resolvedValues = this.staticMappings.concat(this.values || []);
},
() => this.resolvedValues = this.values
);
this.startProcessCloudService.getStartEventFormStaticValuesMapping(this.appName, this.processDefinitionCurrent.id).subscribe(
(staticMappings) => {
this.staticMappings = staticMappings;
this.resolvedValues = this.staticMappings.concat(this.values || []);
},
() => (this.resolvedValues = this.values)
);
this.isFormCloudLoaded = false;
this.processPayloadCloud.processDefinitionKey = this.processDefinitionCurrent.key;
}
private getProcessDefinitionListByNameOrKey(processDefinitionName: string): ProcessDefinitionCloud[] {
return this.processDefinitionList.filter((processDefinitionCloud) => !processDefinitionName || this.getProcessDefinition(processDefinitionCloud, processDefinitionName));
return this.processDefinitionList.filter(
(processDefinitionCloud) => !processDefinitionName || this.getProcessDefinition(processDefinitionCloud, processDefinitionName)
);
}
private getProcessIfExists(processDefinition: string): ProcessDefinitionCloud {
@@ -219,31 +234,35 @@ export class StartProcessCloudComponent implements OnChanges, OnInit, OnDestroy
public loadProcessDefinitions() {
this.resetErrorMessage();
this.startProcessCloudService.getProcessDefinitions(this.appName)
this.startProcessCloudService
.getProcessDefinitions(this.appName)
.pipe(
tap(() => {
this.processDefinitionLoaded = true;
this.loading$.next(false);
}),
takeUntil(this.onDestroy$))
.subscribe((processDefinitionRepresentations: ProcessDefinitionCloud[]) => {
this.processDefinitionList = processDefinitionRepresentations;
if (processDefinitionRepresentations.length === 1) {
this.selectDefaultProcessDefinition();
} else if (this.processDefinitionName) {
this.processDefinition.setValue(this.processDefinitionName);
takeUntil(this.onDestroy$)
)
.subscribe(
(processDefinitionRepresentations: ProcessDefinitionCloud[]) => {
this.processDefinitionList = processDefinitionRepresentations;
if (processDefinitionRepresentations.length === 1) {
this.selectDefaultProcessDefinition();
} else if (this.processDefinitionName) {
this.processDefinition.setValue(this.processDefinitionName);
const processDefinition = this.processDefinitionList.find(process => process.name === this.processDefinitionName);
if (processDefinition) {
this.filteredProcesses = this.getProcessDefinitionListByNameOrKey(processDefinition.name);
this.setProcessDefinitionOnForm(processDefinition.name);
this.processDefinitionSelectionChanged(processDefinition);
const processDefinition = this.processDefinitionList.find((process) => process.name === this.processDefinitionName);
if (processDefinition) {
this.filteredProcesses = this.getProcessDefinitionListByNameOrKey(processDefinition.name);
this.setProcessDefinitionOnForm(processDefinition.name);
this.processDefinitionSelectionChanged(processDefinition);
}
}
}
},
},
() => {
this.errorMessageId = 'ADF_CLOUD_PROCESS_LIST.ADF_CLOUD_START_PROCESS.ERROR.LOAD_PROCESS_DEFS';
});
}
);
}
private isValidName(name: string): boolean {
@@ -259,8 +278,11 @@ export class StartProcessCloudComponent implements OnChanges, OnInit, OnDestroy
}
private getProcessDefinition(processDefinitionCloud: ProcessDefinitionCloud, processDefinitionName: string): boolean {
return (this.isValidName(processDefinitionCloud.name) && processDefinitionCloud.name.toLowerCase().includes(processDefinitionName.toLowerCase())) ||
(processDefinitionCloud.key && processDefinitionCloud.key.toLowerCase().includes(processDefinitionName.toLowerCase()));
return (
(this.isValidName(processDefinitionCloud.name) &&
processDefinitionCloud.name.toLowerCase().includes(processDefinitionName.toLowerCase())) ||
processDefinitionCloud.key?.toLowerCase().includes(processDefinitionName.toLowerCase())
);
}
isProcessDefinitionsEmpty(): boolean {
@@ -287,23 +309,22 @@ export class StartProcessCloudComponent implements OnChanges, OnInit, OnDestroy
if (this.hasForm()) {
payloadVariables = Object.assign(payloadVariables, this.formCloud.values);
}
const createPayload: ProcessPayloadCloud = new ProcessPayloadCloud({
const createPayload = new ProcessPayloadCloud({
name: this.processInstanceName.value,
processDefinitionKey: this.processPayloadCloud.processDefinitionKey,
variables: payloadVariables
});
this.startProcessCloudService.startProcess(this.appName, createPayload)
.subscribe(
(res) => {
this.success.emit(res);
this.isLoading = false;
},
(err) => {
this.errorMessageId = 'ADF_CLOUD_PROCESS_LIST.ADF_CLOUD_START_PROCESS.ERROR.START';
this.error.emit(err);
this.isLoading = false;
}
);
this.startProcessCloudService.startProcess(this.appName, createPayload).subscribe(
(res) => {
this.success.emit(res);
this.isLoading = false;
},
(err) => {
this.errorMessageId = 'ADF_CLOUD_PROCESS_LIST.ADF_CLOUD_START_PROCESS.ERROR.START';
this.error.emit(err);
this.isLoading = false;
}
);
}
cancelStartProcess() {

View File

@@ -23,9 +23,9 @@ export class ProcessPayloadCloud {
payloadType: string = 'StartProcessPayload';
constructor(obj?: any) {
this.processDefinitionKey = obj && obj.processDefinitionKey ? obj.processDefinitionKey : null;
this.name = obj && obj.name ? obj.name : null;
this.businessKey = obj && obj.businessKey ? obj.businessKey : null;
this.variables = obj && obj.variables ? obj.variables : {};
this.processDefinitionKey = obj?.processDefinitionKey;
this.name = obj?.name;
this.businessKey = obj?.businessKey;
this.variables = obj?.variables || {};
}
}

View File

@@ -43,7 +43,6 @@ export interface DropdownOption {
@Directive()
// eslint-disable-next-line @angular-eslint/directive-class-suffix
export abstract class BaseEditTaskFilterCloudComponent<T> implements OnInit, OnChanges, OnDestroy {
public static ACTION_SAVE = 'save';
public static ACTION_SAVE_AS = 'saveAs';
public static ACTION_DELETE = 'delete';
@@ -55,10 +54,7 @@ export abstract class BaseEditTaskFilterCloudComponent<T> implements OnInit, OnC
public static ORDER: string = 'order';
public static DEFAULT_ACTIONS = ['save', 'saveAs', 'delete'];
public static FORMAT_DATE: string = 'DD/MM/YYYY';
public static ACTIONS_DISABLED_BY_DEFAULT = [
BaseEditTaskFilterCloudComponent.ACTION_SAVE,
BaseEditTaskFilterCloudComponent.ACTION_DELETE
];
public static ACTIONS_DISABLED_BY_DEFAULT = [BaseEditTaskFilterCloudComponent.ACTION_SAVE, BaseEditTaskFilterCloudComponent.ACTION_DELETE];
/** (required) Name of the app. */
@Input()
@@ -146,14 +142,14 @@ export abstract class BaseEditTaskFilterCloudComponent<T> implements OnInit, OnC
protected appsProcessCloudService: AppsProcessCloudService,
protected taskCloudService: TaskCloudService,
protected dialog: MatDialog,
protected translateService: TranslationService) {
}
protected translateService: TranslationService
) {}
ngOnInit() {
this.userPreferencesService
.select(UserPreferenceValues.Locale)
.pipe(takeUntil(this.onDestroy$))
.subscribe(locale => this.dateAdapter.setLocale(locale));
.subscribe((locale) => this.dateAdapter.setLocale(locale));
}
ngOnChanges(changes: SimpleChanges) {
@@ -249,22 +245,24 @@ export abstract class BaseEditTaskFilterCloudComponent<T> implements OnInit, OnC
.subscribe((applications) => {
if (applications && applications.length > 0) {
applications.map((application) => {
this.applicationNames.push({ label: this.appsProcessCloudService.getApplicationLabel(application, this.environmentList), value: application.name });
this.applicationNames.push({
label: this.appsProcessCloudService.getApplicationLabel(application, this.environmentList),
value: application.name
});
});
}
});
}
getProcessDefinitions() {
this.taskCloudService.getProcessDefinitions(this.appName)
.subscribe((processDefinitions) => {
if (processDefinitions && processDefinitions.length > 0) {
this.processDefinitionNames.push(this.allProcessDefinitionNamesOption);
processDefinitions.map((processDefinition) => {
this.processDefinitionNames.push({ label: processDefinition.name, value: processDefinition.name });
});
}
});
this.taskCloudService.getProcessDefinitions(this.appName).subscribe((processDefinitions) => {
if (processDefinitions && processDefinitions.length > 0) {
this.processDefinitionNames.push(this.allProcessDefinitionNamesOption);
processDefinitions.map((processDefinition) => {
this.processDefinitionNames.push({ label: processDefinition.name, value: processDefinition.name });
});
}
});
}
checkMandatoryActions(): void {
@@ -300,12 +298,8 @@ export abstract class BaseEditTaskFilterCloudComponent<T> implements OnInit, OnC
}
onDateRangeFilterChanged(dateRange: DateRangeFilter, property: TaskFilterProperties) {
this.editTaskFilterForm.get(property.attributes?.from).setValue(
dateRange.startDate ? dateRange.startDate : null
);
this.editTaskFilterForm.get(property.attributes?.to).setValue(
dateRange.endDate ? dateRange.endDate : null
);
this.editTaskFilterForm.get(property.attributes?.from).setValue(dateRange.startDate ? dateRange.startDate : null);
this.editTaskFilterForm.get(property.attributes?.to).setValue(dateRange.endDate ? dateRange.endDate : null);
this.editTaskFilterForm.get(property.attributes.dateType).setValue(DateCloudFilterType.RANGE);
}
@@ -364,7 +358,7 @@ export abstract class BaseEditTaskFilterCloudComponent<T> implements OnInit, OnC
hasError(property: TaskFilterProperties): boolean {
const controller = this.getPropertyController(property);
return controller.errors && controller.errors.invalid;
return !!controller.errors?.invalid;
}
hasLastModifiedProperty(): boolean {
@@ -379,7 +373,7 @@ export abstract class BaseEditTaskFilterCloudComponent<T> implements OnInit, OnC
createAndFilterActions(): TaskFilterAction[] {
this.checkMandatoryActions();
return this.createFilterActions().filter(action => this.isValidAction(this.actions, action));
return this.createFilterActions().filter((action) => this.isValidAction(this.actions, action));
}
isValidProperty(filterProperties: string[], key: string): boolean {
@@ -395,8 +389,8 @@ export abstract class BaseEditTaskFilterCloudComponent<T> implements OnInit, OnC
}
removeOrderProperty(filteredProperties: TaskFilterProperties[]): TaskFilterProperties[] {
if (filteredProperties && filteredProperties.length > 0) {
return filteredProperties.filter(property => property.key !== BaseEditTaskFilterCloudComponent.ORDER);
if (filteredProperties?.length > 0) {
return filteredProperties.filter((property) => property.key !== BaseEditTaskFilterCloudComponent.ORDER);
}
return [];
}
@@ -446,7 +440,7 @@ export abstract class BaseEditTaskFilterCloudComponent<T> implements OnInit, OnC
return { [property.key]: property.value };
}
});
return properties.reduce(((result, current) => Object.assign(result, current)), {});
return properties.reduce((result, current) => Object.assign(result, current), {});
}
private getAttributesControlConfig(property: TaskFilterProperties) {
@@ -471,10 +465,10 @@ export abstract class BaseEditTaskFilterCloudComponent<T> implements OnInit, OnC
this.getTaskFilterById(this.appName, this.id)
.pipe(
finalize(() => this.isLoading = false),
finalize(() => (this.isLoading = false)),
takeUntil(this.onDestroy$)
)
.subscribe(response => {
.subscribe((response) => {
this.taskFilter = response;
this.taskFilterProperties = this.createAndFilterProperties();
this.taskFilterActions = this.createAndFilterActions();
@@ -491,8 +485,9 @@ export abstract class BaseEditTaskFilterCloudComponent<T> implements OnInit, OnC
return filters.length === 0;
}),
switchMap(() => this.restoreDefaultTaskFilters()),
takeUntil(this.onDestroy$))
.subscribe(() => { });
takeUntil(this.onDestroy$)
)
.subscribe(() => {});
}
save(saveAction: TaskFilterAction): void {

View File

@@ -27,17 +27,14 @@ import { IdentityUserService } from '../../../people/services/identity-user.serv
providedIn: 'root'
})
export class ServiceTaskFilterCloudService {
private filtersSubject: BehaviorSubject<ServiceTaskFilterCloudModel[]>;
filters$: Observable<ServiceTaskFilterCloudModel[]>;
private filtersSubject = new BehaviorSubject<ServiceTaskFilterCloudModel[]>([]);
filters$ = this.filtersSubject.asObservable();
constructor(
private identityUserService: IdentityUserService,
@Inject(TASK_FILTERS_SERVICE_TOKEN)
public preferenceService: PreferenceCloudServiceInterface
) {
this.filtersSubject = new BehaviorSubject([]);
this.filters$ = this.filtersSubject.asObservable();
}
) {}
/**
* Creates and returns the default task filters for an app.
@@ -47,18 +44,21 @@ export class ServiceTaskFilterCloudService {
*/
private createDefaultFilters(appName: string) {
const key: string = this.prepareKey(appName);
this.preferenceService.getPreferences(appName, key).pipe(
switchMap((response: any) => {
const preferences = (response && response.list && response.list.entries) ? response.list.entries : [];
if (!this.hasPreferences(preferences) || !this.hasTaskFilters(preferences, key)) {
return this.createTaskFilters(appName, key, this.defaultServiceTaskFilters(appName));
} else {
return of(this.findFiltersByKeyInPreferences(preferences, key));
}
})
).subscribe((filters) => {
this.addFiltersToStream(filters);
});
this.preferenceService
.getPreferences(appName, key)
.pipe(
switchMap((response) => {
const preferences = response?.list?.entries || [];
if (!this.hasPreferences(preferences) || !this.hasTaskFilters(preferences, key)) {
return this.createTaskFilters(appName, key, this.defaultServiceTaskFilters(appName));
} else {
return of(this.findFiltersByKeyInPreferences(preferences, key));
}
})
)
.subscribe((filters) => {
this.addFiltersToStream(filters);
});
}
/**
@@ -68,7 +68,7 @@ export class ServiceTaskFilterCloudService {
* @returns Boolean value if the preferences are not empty
*/
private hasPreferences(preferences: any): boolean {
return preferences && preferences.length > 0;
return preferences?.length > 0;
}
/**
@@ -76,12 +76,11 @@ export class ServiceTaskFilterCloudService {
*
* @param preferences User preferences of the target app
* @param key Key of the task filters
* @param filters Details of create filter
* @returns Boolean value if the preference has task filters
*/
private hasTaskFilters(preferences: any, key: string): boolean {
const filters = preferences.find((filter: any) => filter.entry.key === key);
return (filters && filters.entry) ? JSON.parse(filters.entry.value).length > 0 : false;
return filters?.entry ? JSON.parse(filters.entry.value).length > 0 : false;
}
/**
@@ -128,27 +127,27 @@ export class ServiceTaskFilterCloudService {
getTaskFilterById(appName: string, id: string): Observable<ServiceTaskFilterCloudModel> {
const key: string = this.prepareKey(appName);
return this.getTaskFiltersByKey(appName, key).pipe(
switchMap((filters: ServiceTaskFilterCloudModel[]) => {
switchMap((filters) => {
if (filters && filters.length === 0) {
return this.createTaskFilters(appName, key, this.defaultServiceTaskFilters(appName));
} else {
return of(filters);
}
}),
map((filters: any) => filters.filter((filter: ServiceTaskFilterCloudModel) => filter.id === id)[0])
map((filters) => filters.filter((filter) => filter.id === id)[0])
);
}
/**
* Adds a new task filter.
*
* @param filter The new filter to add
* @param newFilter The new filter to add
* @returns Observable of task instance filters with newly added filter
*/
addFilter(newFilter: ServiceTaskFilterCloudModel): Observable<ServiceTaskFilterCloudModel[]> {
const key: string = this.prepareKey(newFilter.appName);
return this.getTaskFiltersByKey(newFilter.appName, key).pipe(
switchMap((filters: ServiceTaskFilterCloudModel[]) => {
switchMap((filters) => {
if (filters && filters.length === 0) {
return this.createTaskFilters(newFilter.appName, key, [newFilter]);
} else {
@@ -170,22 +169,22 @@ export class ServiceTaskFilterCloudService {
/**
* Updates a task filter.
*
* @param filter The filter to update
* @param updatedFilter The filter to update
* @returns Observable of task instance filters with updated filter
*/
updateFilter(updatedFilter: ServiceTaskFilterCloudModel): Observable<ServiceTaskFilterCloudModel[]> {
const key: string = this.prepareKey(updatedFilter.appName);
return this.getTaskFiltersByKey(updatedFilter.appName, key).pipe(
switchMap((filters: ServiceTaskFilterCloudModel[]) => {
if (filters && filters.length === 0) {
switchMap((filters) => {
if (filters?.length === 0) {
return this.createTaskFilters(updatedFilter.appName, key, [updatedFilter]);
} else {
const itemIndex = filters.findIndex((filter: ServiceTaskFilterCloudModel) => filter.id === updatedFilter.id);
const itemIndex = filters.findIndex((filter) => filter.id === updatedFilter.id);
filters[itemIndex] = updatedFilter;
return this.updateTaskFilters(updatedFilter.appName, key, filters);
}
}),
map((updatedFilters: ServiceTaskFilterCloudModel[]) => {
map((updatedFilters) => {
this.addFiltersToStream(updatedFilters);
return updatedFilters;
})
@@ -195,20 +194,20 @@ export class ServiceTaskFilterCloudService {
/**
* Deletes a task filter
*
* @param filter The filter to delete
* @param deletedFilter The filter to delete
* @returns Observable of task instance filters without deleted filter
*/
deleteFilter(deletedFilter: ServiceTaskFilterCloudModel): Observable<ServiceTaskFilterCloudModel[]> {
const key = this.prepareKey(deletedFilter.appName);
return this.getTaskFiltersByKey(deletedFilter.appName, key).pipe(
switchMap((filters: ServiceTaskFilterCloudModel[]) => {
if (filters && filters.length > 0) {
filters = filters.filter(filter => filter.id !== deletedFilter.id);
switchMap((filters) => {
if (filters?.length > 0) {
filters = filters.filter((filter) => filter.id !== deletedFilter.id);
return this.updateTaskFilters(deletedFilter.appName, key, filters);
}
return of([]);
}),
map(filters => {
map((filters) => {
this.addFiltersToStream(filters);
return filters;
})
@@ -251,12 +250,13 @@ export class ServiceTaskFilterCloudService {
/**
* Finds and returns the task filters from preferences
*
* @param appName Name of the target app
* @returns Array of TaskFilterCloudModel
* @param preferences
* @param key
*/
private findFiltersByKeyInPreferences(preferences: any, key: string): ServiceTaskFilterCloudModel[] {
const result = preferences.find((filter: any) => filter.entry.key === key);
return result && result.entry ? JSON.parse(result.entry.value) : [];
return result?.entry ? JSON.parse(result.entry.value) : [];
}
/**
@@ -301,6 +301,6 @@ export class ServiceTaskFilterCloudService {
}
generateRandomId(): string {
return Math.random().toString(36).substr(2, 9);
return Math.random().toString(36).substring(2, 9);
}
}

View File

@@ -48,18 +48,17 @@ const TASK_EVENT_SUBSCRIPTION_QUERY = `
providedIn: 'root'
})
export class TaskFilterCloudService extends BaseCloudService {
private filtersSubject: BehaviorSubject<TaskFilterCloudModel[]>;
filters$: Observable<TaskFilterCloudModel[]>;
private filtersSubject = new BehaviorSubject<TaskFilterCloudModel[]>([]);
filters$ = this.filtersSubject.asObservable();
constructor(
private identityUserService: IdentityUserService,
@Inject(TASK_FILTERS_SERVICE_TOKEN)
public preferenceService: PreferenceCloudServiceInterface,
private notificationCloudService: NotificationCloudService,
adfHttpClient: AdfHttpClient) {
adfHttpClient: AdfHttpClient
) {
super(adfHttpClient);
this.filtersSubject = new BehaviorSubject([]);
this.filters$ = this.filtersSubject.asObservable();
}
/**
@@ -70,18 +69,21 @@ export class TaskFilterCloudService extends BaseCloudService {
*/
private createDefaultFilters(appName: string) {
const key: string = this.prepareKey(appName);
this.preferenceService.getPreferences(appName, key).pipe(
switchMap((response: any) => {
const preferences = (response && response.list && response.list.entries) ? response.list.entries : [];
if (!this.hasPreferences(preferences) || !this.hasTaskFilters(preferences, key)) {
return this.createTaskFilters(appName, key, this.defaultTaskFilters(appName));
} else {
return of(this.findFiltersByKeyInPreferences(preferences, key));
}
})
).subscribe((filters) => {
this.addFiltersToStream(filters);
});
this.preferenceService
.getPreferences(appName, key)
.pipe(
switchMap((response) => {
const preferences = response?.list?.entries || [];
if (!this.hasPreferences(preferences) || !this.hasTaskFilters(preferences, key)) {
return this.createTaskFilters(appName, key, this.defaultTaskFilters(appName));
} else {
return of(this.findFiltersByKeyInPreferences(preferences, key));
}
})
)
.subscribe((filters) => {
this.addFiltersToStream(filters);
});
}
/**
@@ -99,12 +101,11 @@ export class TaskFilterCloudService extends BaseCloudService {
*
* @param preferences User preferences of the target app
* @param key Key of the task filters
* @param filters Details of create filter
* @returns Boolean value if the preference has task filters
*/
private hasTaskFilters(preferences: any, key: string): boolean {
const filters = preferences.find((filter: any) => filter.entry.key === key);
return (filters && filters.entry) ? JSON.parse(filters.entry.value).length > 0 : false;
return filters?.entry ? JSON.parse(filters.entry.value).length > 0 : false;
}
/**
@@ -151,35 +152,35 @@ export class TaskFilterCloudService extends BaseCloudService {
getTaskFilterById(appName: string, id: string): Observable<TaskFilterCloudModel> {
const key: string = this.prepareKey(appName);
return this.getTaskFiltersByKey(appName, key).pipe(
switchMap((filters: TaskFilterCloudModel[]) => {
switchMap((filters) => {
if (filters && filters.length === 0) {
return this.createTaskFilters(appName, key, this.defaultTaskFilters(appName));
} else {
return of(filters);
}
}),
map((filters: any) => filters.filter((filter: TaskFilterCloudModel) => filter.id === id)[0])
map((filters) => filters.filter((filter) => filter.id === id)[0])
);
}
/**
* Adds a new task filter.
*
* @param filter The new filter to add
* @param newFilter The new filter to add
* @returns Observable of task instance filters with newly added filter
*/
addFilter(newFilter: TaskFilterCloudModel): Observable<TaskFilterCloudModel[]> {
const key: string = this.prepareKey(newFilter.appName);
return this.getTaskFiltersByKey(newFilter.appName, key).pipe(
switchMap((filters: any) => {
if (filters && filters.length === 0) {
switchMap((filters) => {
if (filters?.length === 0) {
return this.createTaskFilters(newFilter.appName, key, [newFilter]);
} else {
filters.push(newFilter);
return this.preferenceService.updatePreference(newFilter.appName, key, filters);
}
}),
map((filters: TaskFilterCloudModel[]) => {
map((filters) => {
this.addFiltersToStream(filters);
return filters;
})
@@ -193,22 +194,22 @@ export class TaskFilterCloudService extends BaseCloudService {
/**
* Updates a task filter.
*
* @param filter The filter to update
* @param updatedFilter The filter to update
* @returns Observable of task instance filters with updated filter
*/
updateFilter(updatedFilter: TaskFilterCloudModel): Observable<TaskFilterCloudModel[]> {
const key: string = this.prepareKey(updatedFilter.appName);
return this.getTaskFiltersByKey(updatedFilter.appName, key).pipe(
switchMap((filters: TaskFilterCloudModel[]) => {
if (filters && filters.length === 0) {
switchMap((filters) => {
if (filters?.length === 0) {
return this.createTaskFilters(updatedFilter.appName, key, [updatedFilter]);
} else {
const itemIndex = filters.findIndex((filter: TaskFilterCloudModel) => filter.id === updatedFilter.id);
const itemIndex = filters.findIndex((filter) => filter.id === updatedFilter.id);
filters[itemIndex] = updatedFilter;
return this.updateTaskFilters(updatedFilter.appName, key, filters);
}
}),
map((updatedFilters: TaskFilterCloudModel[]) => {
map((updatedFilters) => {
this.addFiltersToStream(updatedFilters);
return updatedFilters;
})
@@ -218,20 +219,20 @@ export class TaskFilterCloudService extends BaseCloudService {
/**
* Deletes a task filter
*
* @param filter The filter to delete
* @param deletedFilter The filter to delete
* @returns Observable of task instance filters without deleted filter
*/
deleteFilter(deletedFilter: TaskFilterCloudModel): Observable<TaskFilterCloudModel[]> {
const key = this.prepareKey(deletedFilter.appName);
return this.getTaskFiltersByKey(deletedFilter.appName, key).pipe(
switchMap((filters: TaskFilterCloudModel[]) => {
if (filters && filters.length > 0) {
filters = filters.filter(filter => filter.id !== deletedFilter.id);
switchMap((filters) => {
if (filters?.length > 0) {
filters = filters.filter((filter) => filter.id !== deletedFilter.id);
return this.updateTaskFilters(deletedFilter.appName, key, filters);
}
return of([]);
}),
map(filters => {
map((filters) => {
this.addFiltersToStream(filters);
return filters;
})
@@ -252,8 +253,8 @@ export class TaskFilterCloudService extends BaseCloudService {
/**
* Finds a task using an object with optional query properties.
*
* @param requestNode Query object
* @returns Task information
* @param taskFilter
*/
getTaskFilterCounter(taskFilter: TaskFilterCloudModel): Observable<any> {
if (taskFilter.appName || taskFilter.appName === '') {
@@ -280,9 +281,7 @@ export class TaskFilterCloudService extends BaseCloudService {
dueDate: taskFilter.dueDate,
maxItems: 1
};
return this.get<TaskCloudNodePaging>(queryUrl, queryParams).pipe(
map((tasks) => tasks.list.pagination.totalItems)
);
return this.get<TaskCloudNodePaging>(queryUrl, queryParams).pipe(map((tasks) => tasks.list.pagination.totalItems));
} else {
return throwError('Appname not configured');
}
@@ -313,12 +312,13 @@ export class TaskFilterCloudService extends BaseCloudService {
/**
* Finds and returns the task filters from preferences
*
* @param appName Name of the target app
* @returns Array of TaskFilterCloudModel
* @param preferences
* @param key
*/
private findFiltersByKeyInPreferences(preferences: any, key: string): TaskFilterCloudModel[] {
const result = preferences.find((filter: any) => filter.entry.key === key);
return result && result.entry ? JSON.parse(result.entry.value) : [];
return result?.entry ? JSON.parse(result.entry.value) : [];
}
/**
@@ -365,7 +365,8 @@ export class TaskFilterCloudService extends BaseCloudService {
}
getTaskNotificationSubscription(appName: string): Observable<TaskCloudEngineEvent[]> {
return this.notificationCloudService.makeGQLQuery(appName, TASK_EVENT_SUBSCRIPTION_QUERY)
return this.notificationCloudService
.makeGQLQuery(appName, TASK_EVENT_SUBSCRIPTION_QUERY)
.pipe(map((events: any) => events.data.engineEvents));
}
}

View File

@@ -15,10 +15,7 @@
* limitations under the License.
*/
import {
Component, EventEmitter, Input, OnChanges,
Output, SimpleChanges, OnInit, ViewEncapsulation, OnDestroy
} from '@angular/core';
import { Component, EventEmitter, Input, OnChanges, Output, SimpleChanges, OnInit, ViewEncapsulation, OnDestroy } from '@angular/core';
import { TaskDetailsCloudModel } from '../../start-task/models/task-details-cloud.model';
import { TaskCloudService } from '../../services/task-cloud.service';
import { FormRenderingService, FormModel, ContentLinkModel, FormOutcomeEvent } from '@alfresco/adf-core';
@@ -35,7 +32,6 @@ import { Subject } from 'rxjs';
encapsulation: ViewEncapsulation.None
})
export class TaskFormCloudComponent implements OnInit, OnChanges, OnDestroy {
/** App id to fetch corresponding form and values. */
@Input()
appName: string = '';
@@ -106,7 +102,6 @@ export class TaskFormCloudComponent implements OnInit, OnChanges, OnDestroy {
@Output()
executeOutcome = new EventEmitter<FormOutcomeEvent>();
/** Emitted when a task is loaded`.
*/
@Output()
@@ -120,9 +115,7 @@ export class TaskFormCloudComponent implements OnInit, OnChanges, OnDestroy {
loading: boolean = false;
onDestroy$ = new Subject<boolean>();
constructor(
private taskCloudService: TaskCloudService,
private formRenderingService: FormRenderingService) {
constructor(private taskCloudService: TaskCloudService, private formRenderingService: FormRenderingService) {
this.formRenderingService.setComponentTypeResolver('upload', () => AttachFileCloudWidgetComponent, true);
this.formRenderingService.setComponentTypeResolver('dropdown', () => DropdownCloudWidgetComponent, true);
this.formRenderingService.setComponentTypeResolver('date', () => DateCloudWidgetComponent, true);
@@ -136,13 +129,13 @@ export class TaskFormCloudComponent implements OnInit, OnChanges, OnDestroy {
ngOnChanges(changes: SimpleChanges) {
const appName = changes['appName'];
if (appName && (appName.currentValue !== appName.previousValue) && this.taskId) {
if (appName && appName.currentValue !== appName.previousValue && this.taskId) {
this.loadTask();
return;
}
const taskId = changes['taskId'];
if (taskId && taskId.currentValue && this.appName) {
if (taskId?.currentValue && this.appName) {
this.loadTask();
return;
}
@@ -151,20 +144,17 @@ export class TaskFormCloudComponent implements OnInit, OnChanges, OnDestroy {
private loadTask() {
this.loading = true;
this.taskCloudService
.getTaskById(this.appName, this.taskId).pipe(takeUntil(this.onDestroy$))
.subscribe(details => {
.getTaskById(this.appName, this.taskId)
.pipe(takeUntil(this.onDestroy$))
.subscribe((details) => {
this.taskDetails = details;
this.loading = false;
this.onTaskLoaded.emit(this.taskDetails);
});
this.taskCloudService
.getCandidateUsers(this.appName, this.taskId)
.subscribe(users => this.candidateUsers = users || []);
this.taskCloudService.getCandidateUsers(this.appName, this.taskId).subscribe((users) => (this.candidateUsers = users || []));
this.taskCloudService
.getCandidateGroups(this.appName, this.taskId)
.subscribe(groups => this.candidateGroups = groups || []);
this.taskCloudService.getCandidateGroups(this.appName, this.taskId).subscribe((groups) => (this.candidateGroups = groups || []));
}
hasForm(): boolean {

View File

@@ -17,10 +17,19 @@
import { OnChanges, Input, SimpleChanges, Output, EventEmitter, ContentChild, AfterContentInit, OnDestroy, OnInit, Directive } from '@angular/core';
import {
AppConfigService, UserPreferencesService,
DataTableSchema, UserPreferenceValues,
PaginatedComponent, PaginationModel,
DataRowEvent, CustomEmptyContentTemplateDirective, DataCellEvent, DataRowActionEvent, DataRow, DataColumn, ObjectDataTableAdapter
AppConfigService,
UserPreferencesService,
DataTableSchema,
UserPreferenceValues,
PaginatedComponent,
PaginationModel,
DataRowEvent,
CustomEmptyContentTemplateDirective,
DataCellEvent,
DataRowActionEvent,
DataRow,
DataColumn,
ObjectDataTableAdapter
} from '@alfresco/adf-core';
import { taskPresetsCloudDefaultModel } from '../models/task-preset-cloud.model';
import { TaskQueryCloudRequestModel } from '../../../models/filter-cloud-model';
@@ -33,8 +42,11 @@ import { TasksListCloudPreferences } from '../models/tasks-cloud-preferences';
@Directive()
// eslint-disable-next-line @angular-eslint/directive-class-suffix
export abstract class BaseTaskListCloudComponent<T = unknown> extends DataTableSchema<T> implements OnChanges, AfterContentInit, PaginatedComponent, OnDestroy, OnInit {
export abstract class BaseTaskListCloudComponent<T = unknown>
extends DataTableSchema<T>
implements OnChanges, AfterContentInit, PaginatedComponent, OnDestroy, OnInit
// eslint-disable-next-line @typescript-eslint/brace-style
{
@ContentChild(CustomEmptyContentTemplateDirective)
emptyCustomContent: CustomEmptyContentTemplateDirective;
@@ -131,11 +143,13 @@ export abstract class BaseTaskListCloudComponent<T = unknown> extends DataTableS
protected abstract isLoading$: Observable<boolean>;
protected isLoadingPreferences$ = new BehaviorSubject<boolean>(true);
constructor(appConfigService: AppConfigService,
constructor(
appConfigService: AppConfigService,
private taskCloudService: TaskCloudService,
private userPreferences: UserPreferencesService,
presetKey: string,
private cloudPreferenceService: PreferenceCloudServiceInterface) {
private cloudPreferenceService: PreferenceCloudServiceInterface
) {
super(appConfigService, presetKey, taskPresetsCloudDefaultModel);
this.size = userPreferences.paginationSize;
@@ -152,7 +166,7 @@ export abstract class BaseTaskListCloudComponent<T = unknown> extends DataTableS
this.userPreferences
.select(UserPreferenceValues.PaginationSize)
.pipe(takeUntil(this.onDestroy$))
.subscribe(pageSize => this.size = pageSize);
.subscribe((pageSize) => (this.size = pageSize));
}
ngOnChanges(changes: SimpleChanges) {
@@ -172,40 +186,48 @@ export abstract class BaseTaskListCloudComponent<T = unknown> extends DataTableS
private retrieveTasksPreferences(): void {
this.isLoadingPreferences$.next(true);
this.cloudPreferenceService.getPreferences(this.appName).pipe(
take(1),
map((preferences => {
const preferencesList = preferences?.list?.entries ?? [];
const columnsOrder = preferencesList.find(preference => preference.entry.key === TasksListCloudPreferences.columnOrder);
const columnsVisibility = preferencesList.find(preference => preference.entry.key === TasksListCloudPreferences.columnsVisibility);
const columnsWidths = preferencesList.find(preference => preference.entry.key === TasksListCloudPreferences.columnsWidths);
this.cloudPreferenceService
.getPreferences(this.appName)
.pipe(
take(1),
map((preferences) => {
const preferencesList = preferences?.list?.entries ?? [];
const columnsOrder = preferencesList.find((preference) => preference.entry.key === TasksListCloudPreferences.columnOrder);
const columnsVisibility = preferencesList.find(
(preference) => preference.entry.key === TasksListCloudPreferences.columnsVisibility
);
const columnsWidths = preferencesList.find((preference) => preference.entry.key === TasksListCloudPreferences.columnsWidths);
return {
columnsOrder: columnsOrder ? JSON.parse(columnsOrder.entry.value) : undefined,
columnsVisibility: columnsVisibility ? JSON.parse(columnsVisibility.entry.value) : undefined,
columnsWidths: columnsWidths ? JSON.parse(columnsWidths.entry.value) : undefined
};
}))
).subscribe(({ columnsOrder, columnsVisibility, columnsWidths }) => {
if (columnsOrder) {
this.columnsOrder = columnsOrder;
}
return {
columnsOrder: columnsOrder ? JSON.parse(columnsOrder.entry.value) : undefined,
columnsVisibility: columnsVisibility ? JSON.parse(columnsVisibility.entry.value) : undefined,
columnsWidths: columnsWidths ? JSON.parse(columnsWidths.entry.value) : undefined
};
})
)
.subscribe(
({ columnsOrder, columnsVisibility, columnsWidths }) => {
if (columnsOrder) {
this.columnsOrder = columnsOrder;
}
if (columnsVisibility) {
this.columnsVisibility = columnsVisibility;
}
if (columnsVisibility) {
this.columnsVisibility = columnsVisibility;
}
if (columnsWidths) {
this.columnsWidths = columnsWidths;
}
if (columnsWidths) {
this.columnsWidths = columnsWidths;
}
this.createDatatableSchema();
this.createColumns();
this.isLoadingPreferences$.next(false);
}, (error) => {
this.error.emit(error);
this.isLoadingPreferences$.next(false);
});
this.createDatatableSchema();
this.createColumns();
this.isLoadingPreferences$.next(false);
},
(error) => {
this.error.emit(error);
this.isLoadingPreferences$.next(false);
}
);
}
ngAfterContentInit(): void {
@@ -283,15 +305,11 @@ export abstract class BaseTaskListCloudComponent<T = unknown> extends DataTableS
}
onColumnOrderChanged(columnsWithNewOrder: DataColumn[]): void {
this.columnsOrder = columnsWithNewOrder.map(column => column.id);
this.columnsOrder = columnsWithNewOrder.map((column) => column.id);
this.createColumns();
if (this.appName) {
this.cloudPreferenceService.updatePreference(
this.appName,
TasksListCloudPreferences.columnOrder,
this.columnsOrder
);
this.cloudPreferenceService.updatePreference(this.appName, TasksListCloudPreferences.columnOrder, this.columnsOrder);
}
}
@@ -308,11 +326,7 @@ export abstract class BaseTaskListCloudComponent<T = unknown> extends DataTableS
this.createDatatableSchema();
if (this.appName) {
this.cloudPreferenceService.updatePreference(
this.appName,
TasksListCloudPreferences.columnsVisibility,
this.columnsVisibility
);
this.cloudPreferenceService.updatePreference(this.appName, TasksListCloudPreferences.columnsVisibility, this.columnsVisibility);
}
}
@@ -324,44 +338,39 @@ export abstract class BaseTaskListCloudComponent<T = unknown> extends DataTableS
return widthsColumnsMap;
}, {});
this.columnsWidths = {...this.columnsWidths, ...newColumnsWidths};
this.columnsWidths = { ...this.columnsWidths, ...newColumnsWidths };
this.createColumns();
if (this.appName) {
this.cloudPreferenceService.updatePreference(
this.appName,
TasksListCloudPreferences.columnsWidths,
this.columnsWidths
);
this.cloudPreferenceService.updatePreference(this.appName, TasksListCloudPreferences.columnsWidths, this.columnsWidths);
}
}
setSorting(sortDetail) {
const sorting = sortDetail ? {
orderBy: sortDetail.key,
direction: sortDetail.direction.toUpperCase()
} : { ... this.defaultSorting };
const sorting = sortDetail
? {
orderBy: sortDetail.key,
direction: sortDetail.direction.toUpperCase()
}
: { ...this.defaultSorting };
this.sorting = [new TaskListCloudSortingModel(sorting)];
}
formatSorting(sorting: TaskListCloudSortingModel[]) {
this.formattedSorting = this.isValidSorting(sorting) ? [
sorting[0].orderBy,
sorting[0].direction.toLocaleLowerCase()
] : null;
this.formattedSorting = this.isValidSorting(sorting) ? [sorting[0].orderBy, sorting[0].direction.toLocaleLowerCase()] : null;
}
isValidSorting(sorting: TaskListCloudSortingModel[]) {
return sorting && sorting.length && sorting[0].orderBy && sorting[0].direction;
return sorting?.length && sorting[0].orderBy && sorting[0].direction;
}
replacePriorityValues(row: DataRow, column: DataColumn) {
return column.key.split('.').reduce((source, key) => {
if (key === 'priority' && source && typeof (source[key]) === 'number') {
return source[key] = this.taskCloudService.getPriorityLabel(source[key]);
if (key === 'priority' && source && typeof source[key] === 'number') {
return (source[key] = this.taskCloudService.getPriorityLabel(source[key]));
}
return source && typeof (source) === 'object' ? source[key] : undefined;
return source && typeof source === 'object' ? source[key] : undefined;
}, row.obj);
}

View File

@@ -42,10 +42,11 @@ export class TaskListCloudService extends BaseCloudService implements TaskListCl
queryParams['sort'] = sortingParams;
}
return this.get<TaskCloudNodePaging>(queryUrl, queryParams).pipe(
map((response: any) => {
const entries = response.list && response.list.entries;
map((response) => {
const entries = response.list?.entries;
if (entries) {
response.list.entries = entries.map((entryData: any) => entryData.entry);
// TODO: this looks like a hack of the TaskCloudNodePaging collection
response.list.entries = entries.map((entryData) => entryData.entry) as any;
}
return response;
})

View File

@@ -2,6 +2,7 @@
"extends": "./tsconfig.json",
"compilerOptions": {
"outDir": "../../dist/out-tsc",
"declaration": true,
"declarationMap": true,
"resolveJsonModule": true,
"paths": {