Skip to content

Commit a350acf

Browse files
Sharmavishalshrm539
authored andcommitted
Added Object Reference and enhanced Semantic Link components
1 parent 156b6f5 commit a350acf

File tree

6 files changed

+524
-26
lines changed

6 files changed

+524
-26
lines changed

packages/react-sdk-components/src/bridge/react_pconnect.jsx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
/* eslint-disable max-classes-per-file */
12
import { Component, createElement } from 'react';
23
import PropTypes from 'prop-types';
34
import { connect, shallowEqual } from 'react-redux';
Lines changed: 246 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,246 @@
1+
import { useMemo } from 'react';
2+
3+
import { Grid2 } from '@mui/material';
4+
import PropTypes from 'prop-types';
5+
6+
import { SELECTION_MODE, generateColumns, getDataRelationshipContextFromKey } from './utils';
7+
import { getComponentFromMap } from '../../../bridge/helpers/sdk_component_map';
8+
9+
export default function ObjectReference(props) {
10+
const {
11+
getPConnect,
12+
label,
13+
displayMode,
14+
allowAndPersistChangesInReviewMode: editableInReview = false,
15+
targetObjectType,
16+
mode = '',
17+
parameters,
18+
hideLabel = false,
19+
inline = false,
20+
showPromotedFilters = false,
21+
additionalFields
22+
} = props;
23+
24+
const SingleReferenceReadonly = getComponentFromMap('SingleReferenceReadOnly');
25+
26+
// Configs
27+
const pConn = getPConnect();
28+
const referenceType = targetObjectType === 'case' ? 'Case' : 'Data';
29+
const rawViewMetadata = pConn.getRawMetadata();
30+
const refFieldMetadata = pConn.getFieldMetadata(rawViewMetadata?.config?.value?.split('.', 2)[1]);
31+
32+
// Destructured properties
33+
const propsToUse = { label, ...pConn.getInheritedProps(), ...props };
34+
35+
// Computed variables
36+
const isDisplayModeEnabled = displayMode === 'DISPLAY_ONLY';
37+
const canBeChangedInReviewMode = editableInReview && ['Autocomplete', 'Dropdown'].includes(rawViewMetadata.config.componentType);
38+
39+
// Editable first child on change handler
40+
const onRecordChange = event => {
41+
const caseKey = pConn.getCaseInfo().getKey();
42+
const refreshOptions = { autoDetectRefresh: true, propertyName: '' };
43+
refreshOptions.propertyName = rawViewMetadata.config?.value;
44+
45+
if (!canBeChangedInReviewMode || !pConn.getValue('__currentPageTabViewName')) {
46+
const pgRef = pConn.getPageReference().replace('caseInfo.content', '');
47+
const viewName = rawViewMetadata.name;
48+
if (viewName && viewName.length > 0) {
49+
getPConnect().getActionsApi().refreshCaseView(caseKey, viewName, pgRef, refreshOptions);
50+
}
51+
}
52+
53+
// AutoComplete sets value on event.id whereas Dropdown sets it on event.target.value if event.id is unset
54+
// When value is empty propValue will be undefined here and no value will be set for the reference
55+
const propValue = event?.id || event?.target?.value;
56+
const propName =
57+
rawViewMetadata.type === 'SimpleTableSelect' && mode === SELECTION_MODE.MULTI
58+
? PCore.getAnnotationUtils().getPropertyName(rawViewMetadata.config.selectionList)
59+
: PCore.getAnnotationUtils().getPropertyName(rawViewMetadata.config?.value);
60+
61+
if (propValue && canBeChangedInReviewMode && isDisplayModeEnabled) {
62+
PCore.getCaseUtils()
63+
.getCaseEditLock(caseKey, '')
64+
.then(caseResponse => {
65+
const pageTokens = pConn.getPageReference().replace('caseInfo.content', '').split('.');
66+
let curr = {};
67+
const commitData = curr;
68+
69+
pageTokens.forEach(el => {
70+
if (el !== '') {
71+
curr[el] = {};
72+
curr = curr[el];
73+
}
74+
});
75+
76+
// expecting format like {Customer: {pyID:"C-100"}}
77+
const propArr = propName.split('.');
78+
propArr.forEach((element, idx) => {
79+
if (idx + 1 === propArr.length) {
80+
curr[element] = propValue;
81+
} else {
82+
curr[element] = {};
83+
curr = curr[element];
84+
}
85+
});
86+
87+
PCore.getCaseUtils()
88+
.updateCaseEditFieldsData(caseKey, { [caseKey]: commitData }, caseResponse.headers.etag, pConn.getContextName())
89+
.then(response => {
90+
PCore.getContainerUtils().updateParentLastUpdateTime(pConn.getContextName(), response.data.data.caseInfo.lastUpdateTime);
91+
PCore.getContainerUtils().updateRelatedContextEtag(pConn.getContextName(), response.headers.etag);
92+
});
93+
});
94+
}
95+
};
96+
97+
// Prepare first child
98+
const recreatedFirstChild = useMemo(() => {
99+
const type = rawViewMetadata.config.componentType;
100+
101+
/* Read-only variants */
102+
if (type === 'SemanticLink' && !canBeChangedInReviewMode) {
103+
const config = {
104+
...rawViewMetadata.config,
105+
primaryField: rawViewMetadata.config.displayField
106+
};
107+
config.caseClass = rawViewMetadata.config.targetObjectClass;
108+
config.text = config.primaryField;
109+
config.caseID = config.value;
110+
config.contextPage = `@P .${
111+
rawViewMetadata.config?.displayField ? getDataRelationshipContextFromKey(rawViewMetadata.config.displayField) : null
112+
}`;
113+
config.resourceParams = {
114+
workID: config.value
115+
};
116+
config.resourcePayload = {
117+
caseClassName: config.caseClass
118+
};
119+
120+
return getPConnect().createComponent({
121+
type: 'SemanticLink',
122+
config: {
123+
...config,
124+
displayMode,
125+
referenceType,
126+
hideLabel,
127+
dataRelationshipContext: rawViewMetadata.config?.displayField
128+
? getDataRelationshipContextFromKey(rawViewMetadata.config.displayField)
129+
: null
130+
}
131+
});
132+
}
133+
if (isDisplayModeEnabled && !canBeChangedInReviewMode) {
134+
// code coverage
135+
return (
136+
<SingleReferenceReadonly
137+
config={{
138+
...rawViewMetadata.config,
139+
primaryField: rawViewMetadata.config.displayField
140+
}}
141+
getPConnect={getPConnect}
142+
label={propsToUse.label}
143+
type={type}
144+
displayAs='readonly'
145+
displayMode={displayMode}
146+
activeViewRuleClass={rawViewMetadata.config.targetObjectClass} // for older views which may not have context class set, fall back to previous behavior
147+
referenceType={referenceType}
148+
hideLabel={hideLabel}
149+
dataRelationshipContext={
150+
rawViewMetadata.config?.displayField ? getDataRelationshipContextFromKey(rawViewMetadata.config.displayField) : null
151+
}
152+
additionalFields={additionalFields}
153+
/>
154+
);
155+
}
156+
157+
// 1) Set datasource
158+
generateColumns(rawViewMetadata.config, pConn, referenceType);
159+
rawViewMetadata.config.deferDatasource = true;
160+
rawViewMetadata.config.listType = 'datapage';
161+
if (['Dropdown', 'AutoComplete'].includes(type) && !rawViewMetadata.config.placeholder) {
162+
rawViewMetadata.config.placeholder = '@L Select...';
163+
}
164+
165+
// 2) Pass through configs
166+
rawViewMetadata.config.showPromotedFilters = showPromotedFilters;
167+
168+
if (!canBeChangedInReviewMode) {
169+
rawViewMetadata.config.displayMode = displayMode;
170+
}
171+
172+
// 3) Define field meta
173+
let fieldMetaData: any = null;
174+
175+
fieldMetaData = {
176+
datasourceMetadata: {
177+
datasource: {
178+
parameters: {}
179+
}
180+
}
181+
};
182+
if (rawViewMetadata.config?.parameters) {
183+
fieldMetaData.datasourceMetadata.datasource.parameters = parameters;
184+
}
185+
fieldMetaData.datasourceMetadata.datasource.propertyForDisplayText = rawViewMetadata?.config?.datasource?.fields?.text.startsWith('@P')
186+
? rawViewMetadata?.config?.datasource?.fields?.text?.substring(3)
187+
: rawViewMetadata?.config?.datasource?.fields?.text;
188+
fieldMetaData.datasourceMetadata.datasource.propertyForValue = rawViewMetadata?.config?.datasource?.fields?.value.startsWith('@P')
189+
? rawViewMetadata?.config?.datasource?.fields?.value?.substring(3)
190+
: rawViewMetadata?.config?.datasource?.fields?.value;
191+
fieldMetaData.datasourceMetadata.datasource.name = rawViewMetadata.config?.referenceList;
192+
193+
return getPConnect().createComponent({
194+
type,
195+
config: {
196+
...rawViewMetadata.config,
197+
descriptors: mode === SELECTION_MODE.SINGLE ? refFieldMetadata?.descriptors : null,
198+
datasourceMetadata: fieldMetaData?.datasourceMetadata,
199+
required: propsToUse.required,
200+
visibility: propsToUse.visibility,
201+
disabled: propsToUse.disabled,
202+
label: propsToUse.label,
203+
parameters: rawViewMetadata.config.parameters,
204+
readOnly: false,
205+
localeReference: rawViewMetadata.config.localeReference,
206+
...(mode === SELECTION_MODE.SINGLE ? { referenceType } : ''),
207+
contextClass: rawViewMetadata.config.targetObjectClass,
208+
primaryField: rawViewMetadata.config?.displayField,
209+
dataRelationshipContext: rawViewMetadata.config?.displayField ? getDataRelationshipContextFromKey(rawViewMetadata.config.displayField) : null,
210+
hideLabel,
211+
onRecordChange,
212+
inline
213+
}
214+
});
215+
}, [rawViewMetadata.config?.datasource?.source, parameters, propsToUse.required, propsToUse.disabled, getPConnect().getPageReference()]);
216+
217+
// Prepare children to render
218+
return (
219+
<Grid2 container>
220+
<Grid2>{recreatedFirstChild}</Grid2>
221+
</Grid2>
222+
);
223+
}
224+
225+
ObjectReference.propTypes = {
226+
getPConnect: PropTypes.func.isRequired,
227+
label: PropTypes.string,
228+
displayMode: PropTypes.string,
229+
allowAndPersistChangesInReviewMode: PropTypes.bool,
230+
mode: PropTypes.string,
231+
parameters: PropTypes.arrayOf(
232+
PropTypes.shape({
233+
key: PropTypes.string,
234+
value: PropTypes.string
235+
})
236+
),
237+
hideLabel: PropTypes.bool,
238+
additionalFields: PropTypes.arrayOf(
239+
PropTypes.shape({
240+
source: PropTypes.string,
241+
target: PropTypes.string
242+
})
243+
),
244+
inline: PropTypes.bool,
245+
showPromotedFilters: PropTypes.bool
246+
};
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
export { default } from './ObjectReference';
Lines changed: 111 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,111 @@
1+
import { getMappedKey } from '../../template/AdvancedSearch/SearchGroup/persistUtils';
2+
3+
export const SELECTION_MODE = { SINGLE: 'single', MULTI: 'multi' };
4+
5+
const getLeafNameFromPropertyName = property => property?.substr(property.lastIndexOf('.'));
6+
7+
const isSelfReferencedProperty = (param, referenceProp) => param === referenceProp?.split('.', 2)[1];
8+
9+
export const AT_FILTEREDLIST = '@FILTERED_LIST';
10+
export const AT_PROPERTY = '@P';
11+
export const SQUARE_BRACKET_START = '[';
12+
export const SQUARE_BRACKET_END = ']';
13+
14+
export const SIMPLE_TABLE_MANUAL_READONLY = 'SimpleTableManualReadOnly';
15+
export const PAGE = '!P!';
16+
export const PAGELIST = '!PL!';
17+
export const PERIOD = '.';
18+
const AT = '@';
19+
20+
export function updatePageListPropertyValue(value) {
21+
value = value.substring(0, value.indexOf(SQUARE_BRACKET_START)) + value.substring(value.indexOf(SQUARE_BRACKET_END) + 1);
22+
return value;
23+
}
24+
25+
export function getPropertyValue(value) {
26+
if (value.startsWith(AT)) {
27+
value = value.substring(value.indexOf(' ') + 1);
28+
if (value.startsWith(PERIOD)) value = value.substring(1);
29+
}
30+
if (value.includes(SQUARE_BRACKET_START)) {
31+
value = updatePageListPropertyValue(value);
32+
}
33+
return value;
34+
}
35+
36+
const getCompositeKeys = (c11nEnv, property) => {
37+
const { datasource: { parameters = {} } = {} } = c11nEnv.getFieldMetadata(property) || {};
38+
return Object.values(parameters).reduce((compositeKeys: any, param) => {
39+
if (isSelfReferencedProperty(property, param)) {
40+
let propName = getPropertyValue(param);
41+
propName = propName.substring(propName.indexOf('.'));
42+
compositeKeys.push(propName);
43+
}
44+
return compositeKeys;
45+
}, []);
46+
};
47+
48+
export const generateColumns = (config, pConn, referenceType) => {
49+
const displayField = getLeafNameFromPropertyName(config.displayField);
50+
const referenceProp = config.value.split('.', 2)[1];
51+
const compositeKeys: any = getCompositeKeys(pConn, referenceProp);
52+
let value = getLeafNameFromPropertyName(config.value);
53+
54+
const columns: any = [];
55+
if (displayField) {
56+
columns.push({
57+
value: displayField,
58+
display: 'true',
59+
useForSearch: true,
60+
primary: 'true'
61+
});
62+
}
63+
if (value && compositeKeys.indexOf(value) !== -1) {
64+
columns.push({
65+
value,
66+
setProperty: 'Associated property',
67+
key: 'true'
68+
});
69+
} else {
70+
const actualValue = compositeKeys.length > 0 ? compositeKeys[0] : value;
71+
config.value = `@P .${referenceProp}${actualValue}`;
72+
value = actualValue;
73+
columns.push({
74+
value: actualValue,
75+
setProperty: 'Associated property',
76+
key: 'true'
77+
});
78+
}
79+
80+
config.datasource = {
81+
fields: {
82+
key: getLeafNameFromPropertyName(config.value),
83+
text: getLeafNameFromPropertyName(config.displayField),
84+
value: getLeafNameFromPropertyName(config.value)
85+
}
86+
};
87+
88+
if (referenceType === 'Case') {
89+
columns.push({
90+
secondary: 'true',
91+
display: 'true',
92+
value: getMappedKey('pyID'),
93+
useForSearch: true
94+
});
95+
}
96+
97+
compositeKeys.forEach(key => {
98+
if (value !== key)
99+
columns.push({
100+
value: key,
101+
display: 'false',
102+
secondary: 'true',
103+
useForSearch: false,
104+
setProperty: `.${referenceProp}${key}`
105+
});
106+
});
107+
108+
config.columns = columns;
109+
};
110+
111+
export const getDataRelationshipContextFromKey = key => key.split('.', 2)[1];

0 commit comments

Comments
 (0)