File

projects/netgrif-components-core/src/lib/view/tree-case-view/tree-task-content/tree-task-content.service.ts

Index

Methods
Accessors

Constructor

constructor(_treeCaseService: TreeCaseViewService, _taskDataService: TaskDataService, _taskContentService: TaskContentService, _taskResourceService: TaskResourceService, _taskEventService: TaskEventService, _assignPolicy: AssignPolicyService, _cancel: CancelTaskService, _userComparator: UserComparatorService, _callchain: CallChainService, _logger: LoggerService, _selectedCaseService: SelectedCaseService, _changedFieldsService: ChangedFieldsService, _permissionService: PermissionService, _taskOperations: SubjectTaskOperations)
Parameters :
Name Type Optional
_treeCaseService TreeCaseViewService No
_taskDataService TaskDataService No
_taskContentService TaskContentService No
_taskResourceService TaskResourceService No
_taskEventService TaskEventService No
_assignPolicy AssignPolicyService No
_cancel CancelTaskService No
_userComparator UserComparatorService No
_callchain CallChainService No
_logger LoggerService No
_selectedCaseService SelectedCaseService No
_changedFieldsService ChangedFieldsService No
_permissionService PermissionService No
_taskOperations SubjectTaskOperations No

Methods

Protected cancelAndLoadFeaturedTask
cancelAndLoadFeaturedTask(selectedCase: Case | undefined)

Cancels the currently selected Task if any. And then loads and assigns the new Task.

Parameters :
Name Type Optional Description
selectedCase Case | undefined No

the Case who's task should be now displayed

Returns : void
Protected clearCurrentTask
clearCurrentTask()

Notifies all connected Services that no Task is currently selected

Returns : void
Public displayEmptyTaskContent
displayEmptyTaskContent()
Returns : void
Protected getTaskFilter
getTaskFilter()

Creates a Filter object that finds the specified Task for the currently selected Case in a Tree Case View immediate data field. Returns undefined if the request body cannot be created.

Returns : Filter | undefined

a request body that finds tasks of the given case with task id that corresponds to the value in the treeTaskTransitionId immediate data field. Returns undefined if the request body cannot be created.

Protected getTransitionId
getTransitionId(examinedCase: Case)

or undefined if the currently selected case doesn't define it

Parameters :
Name Type Optional Description
examinedCase Case No

the {

Returns : string | undefined

the ID of the transition that should be displayed in the {

Protected getUniqueTaskIdentifier
getUniqueTaskIdentifier()

Returns undefined, if no task is currently selected.

Returns : string

a unique identifier for the currently selected task, that consists of it's case's id and it's transition id.

Returns undefined, if no task is currently selected.

Protected loadFeaturedTask
loadFeaturedTask(selectedCase: Case | undefined)

Changes the currently displayed Task based on the selected Case from the Tree.

Parameters :
Name Type Optional Description
selectedCase Case | undefined No

the Case who's task should be now displayed

Returns : void
ngOnDestroy
ngOnDestroy()

Attempts to cancel the currently opened Task if the Task is in such state that allows cancellation.

Returns : void
Protected resolveTaskBlockState
resolveTaskBlockState()

If the current Task is assigned to the current user it is unblocked. Otherwise it is blocked.

Returns : void
Protected setStandardTaskText
setStandardTaskText()

Sets the noData text in the task content to it's default value

Returns : void
Protected switchToTask
switchToTask(task: Task)

Changes the currently selected Task.

Parameters :
Name Type Optional Description
task Task No

the Task that should now be selected

Returns : void
Protected updateTaskState
updateTaskState()

Updates the state of the current Task from backend

Returns : void

Accessors

taskContentText$
gettaskContentText$()
processingTaskChange
getprocessingTaskChange()
import {Inject, Injectable, OnDestroy} from '@angular/core';
import {TaskContentService} from '../../../task-content/services/task-content.service';
import {TaskDataService} from '../../../task/services/task-data.service';
import {CancelTaskService} from '../../../task/services/cancel-task.service';
import {TaskEventService} from '../../../task-content/services/task-event.service';
import {TaskResourceService} from '../../../resources/engine-endpoint/task-resource.service';
import {TreeCaseViewService} from '../tree-case-view.service';
import {Case} from '../../../resources/interface/case';
import {Task} from '../../../resources/interface/task';
import {AssignPolicyService} from '../../../task/services/assign-policy.service';
import {AssignPolicy} from '../../../task-content/model/policy';
import {NAE_TASK_OPERATIONS} from '../../../task/models/task-operations-injection-token';
import {SubjectTaskOperations} from '../../../task/models/subject-task-operations';
import {UserComparatorService} from '../../../user/services/user-comparator.service';
import {TreePetriflowIdentifiers} from '../model/tree-petriflow-identifiers';
import {CallChainService} from '../../../utility/call-chain/call-chain.service';
import {LoadingEmitter} from '../../../utility/loading-emitter';
import {Observable, ReplaySubject, Subject} from 'rxjs';
import {hasContent} from '../../../utility/pagination/page-has-content';
import {getImmediateData} from '../../../utility/get-immediate-data';
import {filter} from 'rxjs/operators';
import {LoggerService} from '../../../logger/services/logger.service';
import {SelectedCaseService} from '../../../task/services/selected-case.service';
import {Filter} from '../../../filter/models/filter';
import {SimpleFilter} from '../../../filter/models/simple-filter';
import {PermissionService} from '../../../authorization/permission/permission.service';
import {ChangedFieldsService} from '../../../changed-fields/services/changed-fields.service';
import {ChangedFields} from '../../../data-fields/models/changed-fields';
import {ChangedFieldsMap} from '../../../event/services/interfaces/changed-fields-map';

@Injectable()
export class TreeTaskContentService implements OnDestroy {

    private _processingTaskChange: LoadingEmitter;
    private _displayedTaskText$: Subject<string>;
    /**
     * a unique identifier consisting of caseId and transition ID
     *
     * Is set if a reload of the given task is currently taking place, `undefined` otherwise.
     */
    private _reloadedTaskUniqueIdentifier: string;

    constructor(protected _treeCaseService: TreeCaseViewService,
                protected _taskDataService: TaskDataService,
                protected _taskContentService: TaskContentService,
                protected _taskResourceService: TaskResourceService,
                protected _taskEventService: TaskEventService,
                protected _assignPolicy: AssignPolicyService,
                protected _cancel: CancelTaskService,
                protected _userComparator: UserComparatorService,
                protected _callchain: CallChainService,
                protected _logger: LoggerService,
                protected _selectedCaseService: SelectedCaseService,
                protected _changedFieldsService: ChangedFieldsService,
                protected _permissionService: PermissionService,
                @Inject(NAE_TASK_OPERATIONS) protected _taskOperations: SubjectTaskOperations) {
        this._processingTaskChange = new LoadingEmitter();
        this._displayedTaskText$ = new ReplaySubject<string>();

        this._changedFieldsService.changedFields$.subscribe((changedFieldsMap: ChangedFieldsMap) => {
            const filteredCaseIds: Array<string> = Object.keys(changedFieldsMap).filter(
                caseId => Object.keys(this._taskContentService.referencedTaskAndCaseIds).includes(caseId)
            );
            const changedFields: Array<ChangedFields> = [];
            filteredCaseIds.forEach(caseId => {
                const taskIds: Array<string> = this._taskContentService.referencedTaskAndCaseIds[caseId];
                changedFields.push(...this._changedFieldsService.parseChangedFieldsByCaseAndTaskIds(caseId, taskIds, changedFieldsMap));
            });
            changedFields.filter(fields => fields !== undefined).forEach(fields => {
                this._taskContentService.updateFromChangedFields(fields);
            });
        });
        _taskDataService.updateSuccess$.subscribe(result => {
            if (result) {
                this._treeCaseService.reloadCase$.next();
                this.resolveTaskBlockState();
            }
        });

        _treeCaseService.loadTask$.asObservable().pipe(filter(selectedCase => this.taskChanged(selectedCase))).subscribe(selectedCase => {
            this.cancelAndLoadFeaturedTask(selectedCase);
        });

        _taskOperations.reload$.subscribe(() => {
            this.updateTaskState();
            this._treeCaseService.reloadCase$.next();
        });
        _taskOperations.open$.subscribe(() => {
            this._taskContentService.blockFields(false);
        });
        _taskOperations.close$.subscribe(() => {
            this._taskContentService.blockFields(true);
        });
    }

    public get taskContentText$(): Observable<string> {
        return this._displayedTaskText$.asObservable();
    }

    public get processingTaskChange(): boolean {
        return this._processingTaskChange.isActive;
    }

    public displayEmptyTaskContent(): void {
        this._taskContentService.$shouldCreate.next([]);
        this._displayedTaskText$.next('caseTree.noTaskSelected');
    }

    /**
     * Cancels the currently selected {@link Task} if any. And then loads and assigns the new Task.
     * @param selectedCase the Case who's task should be now displayed
     */
    protected cancelAndLoadFeaturedTask(selectedCase: Case | undefined) {
        this._processingTaskChange.on();
        this._taskContentService.blockFields(true);
        if (this.shouldCancelTask) {
            this._cancel.cancel(this._callchain.create(success => {
                if (success) {
                    this._logger.debug('Old tree task successfully canceled');
                } else {
                    this._logger.warn('Old tree task could not be canceled');
                }
            }));
        }
        this.loadFeaturedTask(selectedCase);
    }

    /**
     * Changes the currently displayed {@link Task} based on the selected {@link Case} from the Tree.
     * @param selectedCase the Case who's task should be now displayed
     */
    protected loadFeaturedTask(selectedCase: Case | undefined): void {
        this._selectedCaseService.selectedCase = selectedCase;

        const requestBody = this.getTaskFilter();
        if (requestBody === undefined) {
            this.clearCurrentTask();
            return;
        }

        this._taskResourceService.getTasks(requestBody).subscribe(page => {
            if (hasContent(page)) {
                this.setStandardTaskText();
                this.switchToTask(page.content[0]);
            } else {
                this.clearCurrentTask();
            }
        });
    }

    /**
     * Checks whether the currently displayed task differs from the new one
     * @param newCase [Case]{@link Case} object that holds the newly selected {@link Task}
     * @returns `true` if the currently selected Case has a different ID from the newly selected Case.
     * If the IDs are the same returns `true` if the transition IDs are different.
     * Returns `false` otherwise.
     */
    private taskChanged(newCase: Case | undefined): boolean {
        const currentCaseId = this._selectedCaseService.selectedCase ? this._selectedCaseService.selectedCase.stringId : undefined;
        const newCaseId = newCase ? newCase.stringId : undefined;
        if (currentCaseId !== newCaseId) {
            return true;
        }

        const currentTransitionId = this.getTransitionId(this._selectedCaseService.selectedCase);
        const newTransitionId = this.getTransitionId(newCase);
        return currentTransitionId !== newTransitionId;
    }

    /**
     * Checks whether a Task object is currently selected and if it can be cancelled by the user
     */
    private get shouldCancelTask(): boolean {
        return this._taskContentService.task && this._permissionService.canCancel(this._taskContentService.task);
    }

    /**
     * Creates a {@link Filter} object that finds the specified Task for the currently selected Case in a Tree Case View
     * @returns a request body that finds tasks of the given case with task id that corresponds to the value in the `treeTaskTransitionId`
     * immediate data field. Returns `undefined` if the request body cannot be created.
     */
    protected getTaskFilter(): Filter | undefined {
        const transitionId = this.getTransitionId(this._selectedCaseService.selectedCase);
        if (transitionId) {
            return SimpleFilter.fromTaskQuery({
                case: {id: this._selectedCaseService.selectedCase.stringId},
                transitionId
            });
        }
        return undefined;
    }

    /**
     * @param examinedCase the {@link Case} object from which we want to extract the transition ID
     * @returns the ID of the transition that should be displayed in the {@link AbstractTaskContentComponent},
     * or `undefined` if the currently selected case doesn't define it
     */
    protected getTransitionId(examinedCase: Case): string | undefined {
        if (examinedCase && examinedCase.immediateData) {
            const transitionId = getImmediateData(examinedCase, TreePetriflowIdentifiers.FEATURED_TRANSITION);
            return transitionId ? transitionId.value : undefined;
        }
        return undefined;
    }

    /**
     * Changes the currently selected {@link Task}.
     * @param task the Task that should now be selected
     */
    protected switchToTask(task: Task): void {
        if (task.caseId !== this._selectedCaseService.selectedCase.stringId) {
            this._logger.debug('Tree featured task has been loaded, but the selected case has changed since. Discarding...');
            return;
        }

        task.assignPolicy = AssignPolicy.auto;
        this._taskContentService.task = task;
        this._taskContentService.blockFields(true);
        this._assignPolicy.performAssignPolicy(true, this._callchain.create(() => {
            this._processingTaskChange.off();
        }));
    }

    /**
     * Notifies all connected Services that no Task is currently selected
     */
    protected clearCurrentTask(): void {
        this._taskContentService.task = undefined;
        this.displayEmptyTaskContent();
        this._processingTaskChange.off();
    }

    /**
     * Updates the state of the current Task from backend
     */
    protected updateTaskState(): void {
        const uniqueTaskIdentifier = this.getUniqueTaskIdentifier();
        if (uniqueTaskIdentifier === this._reloadedTaskUniqueIdentifier) {
            this._logger.debug('The currently selected task is already being reloaded. Ignoring reload request.');
            return;
        }
        this._reloadedTaskUniqueIdentifier = uniqueTaskIdentifier;
        this._taskResourceService.getTasks(this.getTaskFilter()).subscribe(page => {
            if (hasContent(page)) {
                if (this._taskContentService.task && this._taskContentService.task.stringId === page.content[0].stringId) {
                    this._reloadedTaskUniqueIdentifier = undefined;
                    Object.assign(this._taskContentService.task, page.content[0]);
                }
                this.resolveTaskBlockState();
            }
        });
    }

    /**
     * If the current {@link Task} is assigned to the current user it is unblocked. Otherwise it is blocked.
     */
    protected resolveTaskBlockState(): void {
        const taskShouldBeBlocked = !this._taskContentService.task
                                    || this._taskContentService.task.user === undefined
                                    || !this._userComparator.compareUsers(this._taskContentService.task.user);
        this._taskContentService.blockFields(taskShouldBeBlocked);
    }

    /**
     * Sets the noData text in the task content to it's default value
     */
    protected setStandardTaskText(): void {
        this._displayedTaskText$.next();
    }

    /**
     * Attempts to cancel the currently opened Task if the Task is in such state that allows cancellation.
     */
    ngOnDestroy(): void {
        if (this.shouldCancelTask) {
            this._cancel.cancel();
        }
        if (this._taskOperations) {
            this._taskOperations.destroy();
        }
    }

    /**
     * @returns a unique identifier for the currently selected task, that consists of it's case's id and it's transition id.
     *
     * Returns `undefined`, if no task is currently selected.
     */
    protected getUniqueTaskIdentifier(): string {
        if (!this._selectedCaseService.selectedCase) {
            return undefined;
        }
        return `${this._selectedCaseService.selectedCase.stringId}#${this.getTransitionId(this._selectedCaseService.selectedCase)}`;
    }
}

result-matching ""

    No results matching ""