diff --git a/packages/angular-sdk-components/src/lib/_components/infra/Containers/flow-container-base/flow-container-base.component.ts b/packages/angular-sdk-components/src/lib/_components/infra/Containers/flow-container-base/flow-container-base.component.ts new file mode 100644 index 00000000..236c798e --- /dev/null +++ b/packages/angular-sdk-components/src/lib/_components/infra/Containers/flow-container-base/flow-container-base.component.ts @@ -0,0 +1,22 @@ +import { Injector } from '@angular/core'; +import { getPConnectOfActiveContainerItem } from './helper'; +import { AngularPConnectData, AngularPConnectService } from 'packages/angular-sdk-components/src/public-api'; + +export class FlowContainerBaseComponent { + // For interaction with AngularPConnect + protected angularPConnectData: AngularPConnectData = {}; + protected angularPConnect; + + constructor(injector: Injector) { + this.angularPConnect = injector.get(AngularPConnectService); + } + + getPConnectOfActiveContainerItem(parentPConnect) { + const routingInfo = this.angularPConnect.getComponentProp(this, 'routingInfo'); + const isAssignmentView = this.angularPConnect.getComponentProp(this, 'isAssignmentView'); + return getPConnectOfActiveContainerItem(routingInfo, { + isAssignmentView, + parentPConnect + }); + } +} diff --git a/packages/angular-sdk-components/src/lib/_components/infra/Containers/flow-container-base/helper.ts b/packages/angular-sdk-components/src/lib/_components/infra/Containers/flow-container-base/helper.ts new file mode 100644 index 00000000..16096b2e --- /dev/null +++ b/packages/angular-sdk-components/src/lib/_components/infra/Containers/flow-container-base/helper.ts @@ -0,0 +1,90 @@ +const processRootViewDetails = (rootView, containerItem, options) => { + const { + config: { context: viewContext, name: viewName } + } = rootView; + const { context: containerContext } = containerItem; + const { parentPConnect } = options; + let resolvedViewName = viewName; + let resolvedViewContext = viewContext; + + const isAnnotedViewName = PCore.getAnnotationUtils().isProperty(viewName); + const isAnnotedViewContext = PCore.getAnnotationUtils().isProperty(viewContext); + + // resolving annoted view context + if (isAnnotedViewContext) { + const viewContextProperty = PCore.getAnnotationUtils().getPropertyName(viewContext); + resolvedViewContext = PCore.getStoreValue( + `.${viewContextProperty}`, + viewContextProperty.startsWith('.') ? parentPConnect.getPageReference() : '', + containerContext + ); + } + + if (!resolvedViewContext) { + resolvedViewContext = parentPConnect.getPageReference(); + } + + // resolving annoted view name + if (isAnnotedViewName) { + const viewNameProperty = PCore.getAnnotationUtils().getPropertyName(viewName); + resolvedViewName = PCore.getStoreValue(`.${viewNameProperty}`, resolvedViewContext, containerContext); + } + + /* Special case where context and viewname are dynamic values + Use case - split for each shape + + Ex - (caseInfo.content.SCRequestWorkQueues[1]):context --> .pyViewName:viewName + */ + if (isAnnotedViewName && isAnnotedViewContext && resolvedViewName !== '') { + /* Allow context processor to resolve view and context when both are dynamic */ + resolvedViewName = viewName; + resolvedViewContext = viewContext; + } + + return { + viewName: resolvedViewName, + viewContext: resolvedViewContext + }; +}; + +export const getPConnectOfActiveContainerItem = (containerInfo, options) => { + const { accessedOrder, items } = containerInfo; + const { isAssignmentView = false, parentPConnect } = options; + const containerName = parentPConnect.getContainerName(); + const { CONTAINER_NAMES } = PCore.getContainerUtils(); + const { CREATE_DETAILS_VIEW_NAME } = PCore.getConstants(); + + if (accessedOrder && items) { + const activeContainerItemKey = accessedOrder[accessedOrder.length - 1]; + + if (items[activeContainerItemKey] && items[activeContainerItemKey].view && Object.keys(items[activeContainerItemKey].view).length > 0) { + const activeContainerItem = items[activeContainerItemKey]; + const target = activeContainerItemKey.substring(0, activeContainerItemKey.lastIndexOf('_')); + + const { view: rootView, context } = activeContainerItem; + const { viewName, viewContext } = processRootViewDetails(rootView, activeContainerItem, { parentPConnect }); + + if (!viewName) return null; + + const config = { + meta: rootView, + options: { + context, + pageReference: viewContext || parentPConnect.getPageReference(), + containerName, + containerItemID: activeContainerItemKey, + parentPageReference: parentPConnect.getPageReference(), + hasForm: + isAssignmentView || + containerName === CONTAINER_NAMES.WORKAREA || + containerName === CONTAINER_NAMES.MODAL || + viewName === CREATE_DETAILS_VIEW_NAME, + target + } + }; + + return PCore.createPConnect(config).getPConnect; + } + } + return null; +}; diff --git a/packages/angular-sdk-components/src/lib/_components/infra/Containers/flow-container/flow-container.component.html b/packages/angular-sdk-components/src/lib/_components/infra/Containers/flow-container/flow-container.component.html index 6ca29a42..d978b749 100644 --- a/packages/angular-sdk-components/src/lib/_components/infra/Containers/flow-container/flow-container.component.html +++ b/packages/angular-sdk-components/src/lib/_components/infra/Containers/flow-container/flow-container.component.html @@ -10,19 +10,17 @@

{{ containerName$ }}

-
- +
+
diff --git a/packages/angular-sdk-components/src/lib/_components/infra/Containers/flow-container/flow-container.component.ts b/packages/angular-sdk-components/src/lib/_components/infra/Containers/flow-container/flow-container.component.ts index c1870028..b5ee4e1b 100644 --- a/packages/angular-sdk-components/src/lib/_components/infra/Containers/flow-container/flow-container.component.ts +++ b/packages/angular-sdk-components/src/lib/_components/infra/Containers/flow-container/flow-container.component.ts @@ -1,14 +1,14 @@ -import { Component, OnInit, Input, ChangeDetectorRef, NgZone, forwardRef, OnDestroy } from '@angular/core'; +import { Component, OnInit, Input, ChangeDetectorRef, NgZone, forwardRef, OnDestroy, Injector } from '@angular/core'; import { CommonModule } from '@angular/common'; import { FormBuilder, FormGroup } from '@angular/forms'; import { MatCardModule } from '@angular/material/card'; import { publicConstants } from '@pega/pcore-pconnect-typedefs/constants'; -import { AngularPConnectData, AngularPConnectService } from '../../../../_bridge/angular-pconnect'; import { ProgressSpinnerService } from '../../../../_messages/progress-spinner.service'; import { ReferenceComponent } from '../../reference/reference.component'; import { Utils } from '../../../../_helpers/utils'; import { getToDoAssignments, showBanner } from './helpers'; import { ComponentMapperComponent } from '../../../../_bridge/component-mapper/component-mapper.component'; +import { FlowContainerBaseComponent } from '../flow-container-base/flow-container-base.component'; /** * WARNING: It is not expected that this file should be modified. It is part of infrastructure code that works with @@ -32,11 +32,9 @@ interface FlowContainerProps { standalone: true, imports: [CommonModule, MatCardModule, forwardRef(() => ComponentMapperComponent)] }) -export class FlowContainerComponent implements OnInit, OnDestroy { +export class FlowContainerComponent extends FlowContainerBaseComponent implements OnInit, OnDestroy { @Input() pConn$: typeof PConnect; - // For interaction with AngularPConnect - angularPConnectData: AngularPConnectData = {}; pCoreConstants: typeof publicConstants; configProps$: FlowContainerProps; @@ -53,8 +51,6 @@ export class FlowContainerComponent implements OnInit, OnDestroy { todo_datasource$: any; todo_headerText$ = 'To do'; todo_type$: string; - todo_context$: string; - todo_pConn$: typeof PConnect; bHasCancel = false; @@ -72,14 +68,17 @@ export class FlowContainerComponent implements OnInit, OnDestroy { banners: any[]; // itemKey: string = ""; // JA - this is what Nebula/Constellation uses to pass to finishAssignment, navigateToStep + pConnectOfActiveContainerItem; + constructor( - private angularPConnect: AngularPConnectService, + injector: Injector, private cdRef: ChangeDetectorRef, private psService: ProgressSpinnerService, private fb: FormBuilder, private ngZone: NgZone, private utils: Utils ) { + super(injector); // create the formGroup this.formGroup$ = this.fb.group({ hideRequired: false }); } @@ -148,10 +147,14 @@ export class FlowContainerComponent implements OnInit, OnDestroy { // Should always check the bridge to see if the component should update itself (re-render) const bUpdateSelf = this.angularPConnect.shouldComponentUpdate(this); + const pConn = this.pConnectOfActiveContainerItem || this.pConn$; + const caseViewModeFromProps = this.angularPConnect.getComponentProp(this, 'caseViewMode'); + const caseViewModeFromRedux = pConn.getValue('context_data.caseViewMode', ''); + // ONLY call updateSelf when the component should update // AND removing the "gate" that was put there since shouldComponentUpdate // should be the real "gate" - if (bUpdateSelf) { + if (bUpdateSelf || caseViewModeFromProps !== caseViewModeFromRedux) { // don't want to redraw the flow container when there are page messages, because // the redraw causes us to loose the errors on the elements const completeProps = this.angularPConnect.getCurrentCompleteProps(this) as FlowContainerProps; @@ -182,11 +185,6 @@ export class FlowContainerComponent implements OnInit, OnDestroy { // @ts-ignore - second parameter pageReference for getValue method should be optional const caseViewMode = this.pConn$.getValue('context_data.caseViewMode'); if (caseViewMode && caseViewMode === 'review') { - const kid = this.pConn$.getChildren()[0]; - const todoKid = kid.getPConnect().getChildren()[0]; - - this.todo_pConn$ = todoKid.getPConnect(); - return true; } @@ -368,14 +366,16 @@ export class FlowContainerComponent implements OnInit, OnDestroy { updateSelf() { // for now // const { getPConnect } = this.arChildren$[0].getPConnect(); - const localPConn = this.arChildren$[0].getPConnect(); + // const localPConn = this.arChildren$[0].getPConnect(); + + this.pConnectOfActiveContainerItem = this.getPConnectOfActiveContainerItem(this.pConn$) || this.pConn$; // @ts-ignore - second parameter pageReference for getValue method should be optional - const caseViewMode = this.pConn$.getValue('context_data.caseViewMode'); + const caseViewMode = this.pConnectOfActiveContainerItem.getValue('context_data.caseViewMode'); this.bShowBanner = showBanner(this.pConn$); if (caseViewMode && caseViewMode == 'review') { - this.loadReviewPage(localPConn); + this.loadReviewPage(); // in Nebula/Constellation, when cancel is called, somehow the constructor for flowContainer is called which // does init/add of containers. This mimics that @@ -398,7 +398,7 @@ export class FlowContainerComponent implements OnInit, OnDestroy { this.updateFlowContainerChildren(); } - loadReviewPage(localPConn) { + loadReviewPage() { const { CASE_INFO: CASE_CONSTS } = PCore.getConstants(); setTimeout(() => { @@ -429,21 +429,6 @@ export class FlowContainerComponent implements OnInit, OnDestroy { this.todo_datasource$ = { source: todoAssignments }; } - /* remove this commented out code when update React/WC */ - // let kid = this.pConn$.getChildren()[0]; - - // kid.getPConnect() can be a Reference component. So normalize it just in case - // let todoKid = ReferenceComponent.normalizePConn(kid.getPConnect()).getChildren()[0]; - - // this.todo_pConn$ = todoKid.getPConnect(); - - /* code change here to note for React/WC */ - // todo now needs pConn to open the work item on click "go" - this.todo_pConn$ = this.pConn$; - - // still needs the context of the original work item - this.todo_context$ = localPConn.getContextName(); - this.todo_showTodo$ = true; this.psService.sendMessage(false); @@ -531,8 +516,6 @@ export class FlowContainerComponent implements OnInit, OnDestroy { return; } - this.todo_context$ = currentItem.context; - config.options = { context: currentItem.context, pageReference: context || localPConn.getPageReference(), diff --git a/packages/angular-sdk-components/src/lib/_components/infra/Containers/view-container/view-container.component.ts b/packages/angular-sdk-components/src/lib/_components/infra/Containers/view-container/view-container.component.ts index 6c82e58c..34e22aed 100644 --- a/packages/angular-sdk-components/src/lib/_components/infra/Containers/view-container/view-container.component.ts +++ b/packages/angular-sdk-components/src/lib/_components/infra/Containers/view-container/view-container.component.ts @@ -118,11 +118,14 @@ export class ViewContainerComponent implements OnInit, OnDestroy { /* NOTE: setContainerLimit use is temporary. It is a non-public, unsupported API. */ PCore.getContainerUtils().setContainerLimit(`${APP.APP}/${name}`, limit); } + + // const { visible } = this.state; + // if (visible) containerMgr.addContainerItem(this.dispatchObject); } if (sessionStorage.getItem('hasViewContainer') == 'false') { // @ts-ignore - Property 'getMetadata' is private and only accessible within class - if (this.pConn$.getMetadata().children) { + if (visible) { containerMgr.addContainerItem(this.dispatchObject); } diff --git a/packages/angular-sdk-components/src/lib/_components/infra/assignment/assignment.component.ts b/packages/angular-sdk-components/src/lib/_components/infra/assignment/assignment.component.ts index d9da6926..b28362f6 100644 --- a/packages/angular-sdk-components/src/lib/_components/infra/assignment/assignment.component.ts +++ b/packages/angular-sdk-components/src/lib/_components/infra/assignment/assignment.component.ts @@ -9,6 +9,14 @@ import { ProgressSpinnerService } from '../../../_messages/progress-spinner.serv import { ReferenceComponent } from '../../infra/reference/reference.component'; import { ComponentMapperComponent } from '../../../_bridge/component-mapper/component-mapper.component'; +function getRefreshProps(refreshConditions) { + // refreshConditions cuurently supports only "Changes" event + if (!refreshConditions) { + return []; + } + return refreshConditions.filter(item => item.event && item.event === 'Changes').map(item => [item.field, item.field?.substring(1)]) || []; +} + interface AssignmentProps { // If any, enter additional props that only exist on this component template: string; @@ -127,6 +135,8 @@ export class AssignmentComponent implements OnInit, OnDestroy, OnChanges { } updateChanges() { + this.registerForRefresh(); + this.bIsRefComponent = this.checkIfRefComponent(this.pConn$); this.ngZone.run(() => { @@ -460,4 +470,36 @@ export class AssignmentComponent implements OnInit, OnDestroy, OnChanges { control.markAsTouched(); }); } + + registerForRefresh() { + // @ts-ignore - Property 'getActionRefreshConditions' is private and only accessible within class 'CaseInfo' + const refreshConditions = this.pConn$.getCaseInfo()?.getActionRefreshConditions(); + const pageReference = this.pConn$.getPageReference(); + const context = this.pConn$.getContextName(); + + // refresh api de-registration + PCore.getRefreshManager().deRegisterForRefresh(context); + + // refresh api registration + const refreshProps = getRefreshProps(refreshConditions); + const caseKey = this.pConn$.getCaseInfo().getKey(); + const refreshOptions = { + autoDetectRefresh: true, + preserveClientChanges: false + }; + if (refreshProps.length > 0) { + refreshProps.forEach(prop => { + PCore.getRefreshManager().registerForRefresh( + 'PROP_CHANGE', + this.pConn$.getActionsApi().refreshCaseView.bind(this.pConn$.getActionsApi(), caseKey, null, pageReference, { + ...refreshOptions, + refreshFor: prop[0] + }), + `${pageReference}.${prop[1]}`, + `${context}/${pageReference}`, + context + ); + }); + } + } } diff --git a/packages/angular-sdk-components/src/lib/angular-sdk-components.module.ts b/packages/angular-sdk-components/src/lib/angular-sdk-components.module.ts index ffd5e2b1..4e381e9c 100644 --- a/packages/angular-sdk-components/src/lib/angular-sdk-components.module.ts +++ b/packages/angular-sdk-components/src/lib/angular-sdk-components.module.ts @@ -1,8 +1,9 @@ import { NgModule } from '@angular/core'; import { AngularSdkComponentsComponent } from './angular-sdk-components.component'; +import { FlowContainerBaseComponent } from './_components/infra/Containers/flow-container-base/flow-container-base.component'; @NgModule({ - declarations: [AngularSdkComponentsComponent], + declarations: [AngularSdkComponentsComponent, FlowContainerBaseComponent], imports: [], exports: [AngularSdkComponentsComponent] })