|
| 1 | +import { CommonModule } from '@angular/common'; |
| 2 | +import { Component, Input, OnInit, forwardRef, OnDestroy } from '@angular/core'; |
| 3 | +import { FormGroup } from '@angular/forms'; |
| 4 | +import { ComponentMetadataConfig } from '@pega/pcore-pconnect-typedefs/interpreter/types'; |
| 5 | +import { AngularPConnectData, AngularPConnectService } from '../../../_bridge/angular-pconnect'; |
| 6 | +import { ComponentMapperComponent } from '../../../_bridge/component-mapper/component-mapper.component'; |
| 7 | +import { generateColumns, getDataRelationshipContextFromKey } from '../../../_helpers/objectReference-utils'; |
| 8 | +import { PConnFieldProps } from '../../../_types/PConnProps.interface'; |
| 9 | + |
| 10 | +interface ObjectReferenceProps extends PConnFieldProps { |
| 11 | + showPromotedFilters: boolean; |
| 12 | + inline: boolean; |
| 13 | + parameters: Object; |
| 14 | + mode: string; |
| 15 | + targetObjectType: any; |
| 16 | + allowAndPersistChangesInReviewMode: boolean; |
| 17 | +} |
| 18 | + |
| 19 | +@Component({ |
| 20 | + selector: 'app-object-reference', |
| 21 | + imports: [CommonModule, forwardRef(() => ComponentMapperComponent)], |
| 22 | + templateUrl: './object-reference.component.html', |
| 23 | + styleUrl: './object-reference.component.scss' |
| 24 | +}) |
| 25 | +export class ObjectReferenceComponent implements OnInit, OnDestroy { |
| 26 | + @Input() pConn$: typeof PConnect; |
| 27 | + @Input() formGroup$: FormGroup; |
| 28 | + |
| 29 | + angularPConnectData: AngularPConnectData = {}; |
| 30 | + configProps: ObjectReferenceProps; |
| 31 | + value: { [key: string]: any }; |
| 32 | + readOnly: boolean; |
| 33 | + isForm: boolean; |
| 34 | + type: string; |
| 35 | + isDisplayModeEnabled: boolean; |
| 36 | + canBeChangedInReviewMode: boolean; |
| 37 | + newComponentName: string; |
| 38 | + newPconn: typeof PConnect; |
| 39 | + rawViewMetadata: ComponentMetadataConfig | undefined; |
| 40 | + |
| 41 | + constructor(private angularPConnect: AngularPConnectService) {} |
| 42 | + |
| 43 | + ngOnInit() { |
| 44 | + this.angularPConnectData = this.angularPConnect.registerAndSubscribeComponent(this, this.onStateChange); |
| 45 | + this.checkAndUpdate(); |
| 46 | + } |
| 47 | + |
| 48 | + onStateChange() { |
| 49 | + this.checkAndUpdate(); |
| 50 | + } |
| 51 | + |
| 52 | + ngOnDestroy() { |
| 53 | + if (this.angularPConnectData.unsubscribeFn) { |
| 54 | + this.angularPConnectData.unsubscribeFn(); |
| 55 | + } |
| 56 | + } |
| 57 | + |
| 58 | + checkAndUpdate() { |
| 59 | + const shouldUpdate = this.angularPConnect.shouldComponentUpdate(this); |
| 60 | + if (shouldUpdate) { |
| 61 | + this.updateSelf(); |
| 62 | + } |
| 63 | + } |
| 64 | + |
| 65 | + updateSelf() { |
| 66 | + this.configProps = this.pConn$.resolveConfigProps(this.pConn$.getConfigProps()) as ObjectReferenceProps; |
| 67 | + const displayMode = this.configProps.displayMode; |
| 68 | + const editableInReview = this.configProps.allowAndPersistChangesInReviewMode ?? false; |
| 69 | + const targetObjectType = this.configProps.targetObjectType; |
| 70 | + const mode = this.configProps.mode; |
| 71 | + const parameters = this.configProps.parameters; |
| 72 | + const hideLabel = this.configProps.hideLabel; |
| 73 | + const inline = this.configProps.inline; |
| 74 | + const showPromotedFilters = this.configProps.showPromotedFilters; |
| 75 | + const referenceType: string = targetObjectType === 'case' ? 'Case' : 'Data'; |
| 76 | + this.rawViewMetadata = this.pConn$.getRawMetadata(); |
| 77 | + const refFieldMetadata = this.pConn$.getFieldMetadata(this.rawViewMetadata?.config?.value?.split('.', 2)[1] ?? ''); |
| 78 | + |
| 79 | + // Destructured properties |
| 80 | + const propsToUse = { ...this.pConn$.getInheritedProps(), ...this.configProps }; |
| 81 | + |
| 82 | + // Computed variables |
| 83 | + this.isDisplayModeEnabled = displayMode === 'DISPLAY_ONLY'; |
| 84 | + this.canBeChangedInReviewMode = editableInReview && ['Autocomplete', 'Dropdown'].includes((this.rawViewMetadata?.config as any)?.componentType); |
| 85 | + // componentType is not defined in ComponentMetadataConfig type so using any |
| 86 | + this.type = (this.rawViewMetadata?.config as any)?.componentType; |
| 87 | + |
| 88 | + if (this.type === 'SemanticLink' && !this.canBeChangedInReviewMode) { |
| 89 | + const config: any = { |
| 90 | + ...this.rawViewMetadata?.config, |
| 91 | + primaryField: (this.rawViewMetadata?.config as any).displayField |
| 92 | + }; |
| 93 | + config.caseClass = (this.rawViewMetadata?.config as any).targetObjectClass; |
| 94 | + config.text = config.primaryField; |
| 95 | + config.caseID = config.value; |
| 96 | + config.contextPage = `@P .${ |
| 97 | + (this.rawViewMetadata?.config as any)?.displayField |
| 98 | + ? getDataRelationshipContextFromKey((this.rawViewMetadata?.config as any).displayField) |
| 99 | + : null |
| 100 | + }`; |
| 101 | + config.resourceParams = { |
| 102 | + workID: config.value |
| 103 | + }; |
| 104 | + config.resourcePayload = { |
| 105 | + caseClassName: config.caseClass |
| 106 | + }; |
| 107 | + |
| 108 | + const component = this.pConn$.createComponent( |
| 109 | + { |
| 110 | + type: 'SemanticLink', |
| 111 | + config: { |
| 112 | + ...config, |
| 113 | + displayMode, |
| 114 | + referenceType, |
| 115 | + hideLabel, |
| 116 | + dataRelationshipContext: (this.rawViewMetadata?.config as any)?.displayField |
| 117 | + ? getDataRelationshipContextFromKey((this.rawViewMetadata?.config as any).displayField) |
| 118 | + : null |
| 119 | + } |
| 120 | + }, |
| 121 | + '', |
| 122 | + 0, |
| 123 | + {} |
| 124 | + ); |
| 125 | + this.newPconn = component?.getPConnect(); |
| 126 | + } |
| 127 | + |
| 128 | + if (this.type !== 'SemanticLink' && !this.isDisplayModeEnabled) { |
| 129 | + // 1) Set datasource |
| 130 | + const config: any = { ...this.rawViewMetadata?.config }; |
| 131 | + generateColumns(config, this.pConn$, referenceType); |
| 132 | + config.deferDatasource = true; |
| 133 | + config.listType = 'datapage'; |
| 134 | + if (['Dropdown', 'AutoComplete'].includes(this.type) && !config.placeholder) { |
| 135 | + config.placeholder = '@L Select...'; |
| 136 | + } |
| 137 | + |
| 138 | + // 2) Pass through configs |
| 139 | + config.showPromotedFilters = showPromotedFilters; |
| 140 | + |
| 141 | + if (!this.canBeChangedInReviewMode) { |
| 142 | + config.displayMode = displayMode; |
| 143 | + } |
| 144 | + |
| 145 | + // 3) Define field meta |
| 146 | + |
| 147 | + const fieldMetaData = { |
| 148 | + datasourceMetadata: { |
| 149 | + datasource: { |
| 150 | + parameters: {}, |
| 151 | + propertyForDisplayText: false, |
| 152 | + propertyForValue: false, |
| 153 | + name: '' |
| 154 | + } |
| 155 | + } |
| 156 | + }; |
| 157 | + if (config?.parameters) { |
| 158 | + fieldMetaData.datasourceMetadata.datasource.parameters = parameters; |
| 159 | + } |
| 160 | + fieldMetaData.datasourceMetadata.datasource.propertyForDisplayText = config?.datasource?.fields?.text?.startsWith('@P') |
| 161 | + ? config?.datasource?.fields?.text?.substring(3) |
| 162 | + : config?.datasource?.fields?.text; |
| 163 | + fieldMetaData.datasourceMetadata.datasource.propertyForValue = config?.datasource?.fields?.value?.startsWith('@P') |
| 164 | + ? config?.datasource?.fields?.value?.substring(3) |
| 165 | + : config?.datasource?.fields?.value; |
| 166 | + fieldMetaData.datasourceMetadata.datasource.name = config?.referenceList ?? ''; |
| 167 | + |
| 168 | + const component = this.pConn$.createComponent( |
| 169 | + { |
| 170 | + type: this.type, |
| 171 | + config: { |
| 172 | + ...config, |
| 173 | + descriptors: mode === 'single' ? refFieldMetadata?.descriptors : null, |
| 174 | + datasourceMetadata: fieldMetaData?.datasourceMetadata, |
| 175 | + required: propsToUse.required, |
| 176 | + visibility: propsToUse.visibility, |
| 177 | + disabled: propsToUse.disabled, |
| 178 | + label: propsToUse.label, |
| 179 | + parameters: config.parameters, |
| 180 | + readOnly: false, |
| 181 | + localeReference: config.localeReference, |
| 182 | + ...(mode === 'single' ? { referenceType } : ''), |
| 183 | + contextClass: config.targetObjectClass, |
| 184 | + primaryField: config?.displayField, |
| 185 | + dataRelationshipContext: config?.displayField ? getDataRelationshipContextFromKey(config.displayField) : null, |
| 186 | + hideLabel, |
| 187 | + inline |
| 188 | + } |
| 189 | + }, |
| 190 | + '', |
| 191 | + 0, |
| 192 | + {} |
| 193 | + ); |
| 194 | + this.newComponentName = component?.getPConnect().getComponentName(); |
| 195 | + this.newPconn = component?.getPConnect(); |
| 196 | + if (this.rawViewMetadata?.config) { |
| 197 | + this.rawViewMetadata.config = config ? { ...config } : this.rawViewMetadata.config; |
| 198 | + } |
| 199 | + } |
| 200 | + } |
| 201 | + |
| 202 | + onRecordChange(value) { |
| 203 | + const caseKey = this.pConn$.getCaseInfo().getKey() ?? ''; |
| 204 | + const refreshOptions = { autoDetectRefresh: true, propertyName: '' }; |
| 205 | + refreshOptions.propertyName = this.rawViewMetadata?.config?.value ?? ''; |
| 206 | + |
| 207 | + if (!this.canBeChangedInReviewMode || !this.pConn$.getValue('__currentPageTabViewName')) { |
| 208 | + const pgRef = this.pConn$.getPageReference().replace('caseInfo.content', '') ?? ''; |
| 209 | + const viewName = this.rawViewMetadata?.name; |
| 210 | + if (viewName && viewName.length > 0) { |
| 211 | + getPConnect().getActionsApi().refreshCaseView(caseKey, viewName, pgRef, refreshOptions); |
| 212 | + } |
| 213 | + } |
| 214 | + |
| 215 | + const propValue = value; |
| 216 | + const propName = |
| 217 | + this.rawViewMetadata?.type === 'SimpleTableSelect' && this.configProps.mode === 'multi' |
| 218 | + ? PCore.getAnnotationUtils().getPropertyName(this.rawViewMetadata?.config?.selectionList ?? '') |
| 219 | + : PCore.getAnnotationUtils().getPropertyName(this.rawViewMetadata?.config?.value ?? ''); |
| 220 | + |
| 221 | + if (propValue && this.canBeChangedInReviewMode && this.isDisplayModeEnabled) { |
| 222 | + PCore.getCaseUtils() |
| 223 | + .getCaseEditLock(caseKey, '') |
| 224 | + .then(caseResponse => { |
| 225 | + const pageTokens = this.pConn$.getPageReference().replace('caseInfo.content', '').split('.'); |
| 226 | + let curr = {}; |
| 227 | + const commitData = curr; |
| 228 | + |
| 229 | + pageTokens?.forEach(el => { |
| 230 | + if (el !== '') { |
| 231 | + curr[el] = {}; |
| 232 | + curr = curr[el]; |
| 233 | + } |
| 234 | + }); |
| 235 | + |
| 236 | + // expecting format like {Customer: {pyID:"C-100"}} |
| 237 | + const propArr = propName.split('.'); |
| 238 | + propArr.forEach((element, idx) => { |
| 239 | + if (idx + 1 === propArr.length) { |
| 240 | + curr[element] = propValue; |
| 241 | + } else { |
| 242 | + curr[element] = {}; |
| 243 | + curr = curr[element]; |
| 244 | + } |
| 245 | + }); |
| 246 | + |
| 247 | + PCore.getCaseUtils() |
| 248 | + .updateCaseEditFieldsData(caseKey, { [caseKey]: commitData }, caseResponse.headers.etag, this.pConn$?.getContextName() ?? '') |
| 249 | + .then(response => { |
| 250 | + PCore.getContainerUtils().updateParentLastUpdateTime(this.pConn$.getContextName() ?? '', response.data.data.caseInfo.lastUpdateTime); |
| 251 | + PCore.getContainerUtils().updateRelatedContextEtag(this.pConn$.getContextName() ?? '', response.headers.etag); |
| 252 | + }); |
| 253 | + }); |
| 254 | + } |
| 255 | + } |
| 256 | +} |
0 commit comments