@pega/dx-component-builder-sdk 0.23.21 → 0.24.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +1 -1
- package/src/cli.js +1 -1
- package/src/constants.js +4 -0
- package/src/tasks/build-all/helper.js +6 -0
- package/src/tasks/build-comp/helper.js +6 -0
- package/src/tasks/bundle/builderAngular/webpack.config.js +14 -1
- package/src/tasks/bundle/builderAssociated/webpack.config.js +13 -0
- package/src/tasks/bundle/builderReact/webpack.config.js +14 -1
- package/src/tasks/create/templates/Constellation/field/Boolean/index.tsx.mustache +3 -2
- package/src/tasks/create/templates/Constellation/field/Icon-Button-URL/PConnProps.d.ts.mustache +46 -0
- package/src/tasks/create/templates/Constellation/field/Icon-Button-URL/config.json.mustache +64 -0
- package/src/tasks/create/templates/Constellation/field/Icon-Button-URL/demo.stories.tsx.mustache +99 -0
- package/src/tasks/create/templates/Constellation/field/Icon-Button-URL/index.tsx.mustache +204 -0
- package/src/tasks/create/templates/Constellation/field/Icon-Button-URL/mock.ts.mustache +5 -0
- package/src/tasks/create/templates/Constellation/field/Icon-Button-URL/styles.ts.mustache +8 -0
- package/src/tasks/create/templates/Constellation/field/Picklist-Autocomplete/index.tsx.mustache +11 -0
- package/src/tasks/create/templates/Constellation/field/Picklist-Autocomplete/utils.ts.mustache +3 -0
- package/src/tasks/create/templates/Constellation/field/Text/index.tsx.mustache +94 -4
- package/src/tasks/create/templates/Constellation/template/DETAILS/Avatar.tsx.mustache +78 -0
- package/src/tasks/create/templates/Constellation/template/DETAILS/DetailsRender.tsx.mustache +55 -0
- package/src/tasks/create/templates/Constellation/template/DETAILS/HighlightRender.tsx.mustache +49 -0
- package/src/tasks/create/templates/Constellation/template/DETAILS/Operator.tsx.mustache +218 -0
- package/src/tasks/create/templates/Constellation/template/DETAILS/demo.stories.tsx.mustache +77 -23
- package/src/tasks/create/templates/Constellation/template/DETAILS/index.tsx.mustache +51 -40
- package/src/tasks/create/templates/Constellation/template/DETAILS/mock.ts.mustache +78 -20
- package/src/tasks/create/templates/Constellation/template/DETAILS/styles.ts.mustache +16 -0
- package/src/tasks/create/templates/Constellation/template/DETAILS-region/Avatar.tsx.mustache +78 -0
- package/src/tasks/create/templates/Constellation/template/DETAILS-region/DetailsRender.tsx.mustache +55 -0
- package/src/tasks/create/templates/Constellation/template/DETAILS-region/HighlightRender.tsx.mustache +49 -0
- package/src/tasks/create/templates/Constellation/template/DETAILS-region/Operator.tsx.mustache +218 -0
- package/src/tasks/create/templates/Constellation/template/DETAILS-region/demo.stories.tsx.mustache +95 -26
- package/src/tasks/create/templates/Constellation/template/DETAILS-region/index.tsx.mustache +43 -40
- package/src/tasks/create/templates/Constellation/template/DETAILS-region/mock.ts.mustache +68 -10
- package/src/tasks/create/templates/Constellation/template/DETAILS-region/styles.ts.mustache +15 -0
- package/src/tasks/create/templates/Constellation/template/FORM/DetailsRender.tsx +59 -0
- package/src/tasks/create/templates/Constellation/template/FORM/index.tsx.mustache +31 -5
- package/src/tasks/create/templates/Constellation/template/FORM-region/DetailsRender.tsx +59 -0
- package/src/tasks/create/templates/Constellation/template/FORM-region/index.tsx.mustache +29 -7
- package/src/tasks/create/templates/Constellation/template/PAGE/GetNextWork.tsx.mustache +2 -1
- package/src/tasks/create/templates/Constellation/template/PAGE/localizations.json.mustache +4 -2
- package/src/tasks/create/templates/Constellation/widget/PAGE/demo.stories.tsx.mustache +87 -6
- package/src/tasks/create/templates/Constellation/widget/PAGE/index.tsx.mustache +67 -5
- package/src/tasks/create/templates/SDK-Angular/field/Icon-Button-URL/config.json.mustache +64 -0
- package/src/tasks/create/templates/SDK-Angular/field/Icon-Button-URL/demo.stories.tsx.mustache +42 -0
- package/src/tasks/create/templates/SDK-Angular/field/Icon-Button-URL/mock.ts.mustache +17 -0
- package/src/tasks/create/templates/SDK-Angular/field/Icon-Button-URL/text-url.component.html.mustache +29 -0
- package/src/tasks/create/templates/SDK-Angular/field/Icon-Button-URL/text-url.component.scss.mustache +20 -0
- package/src/tasks/create/templates/SDK-Angular/field/Icon-Button-URL/text-url.component.spec.ts.mustache +26 -0
- package/src/tasks/create/templates/SDK-Angular/field/Icon-Button-URL/text-url.component.ts.mustache +179 -0
- package/src/tasks/create/templates/SDK-React/field/Icon-Button-URL/config.json.mustache +64 -0
- package/src/tasks/create/templates/SDK-React/field/Icon-Button-URL/demo.stories.tsx.mustache +58 -0
- package/src/tasks/create/templates/SDK-React/field/Icon-Button-URL/index.tsx.mustache +79 -0
- package/src/tasks/create/templates/SDK-React/field/Icon-Button-URL/mock.ts.mustache +16 -0
- package/src/tasks/create/templates/SDK-React/field/Icon-Button-URL/styles.js.mustache +7 -0
- package/src/tasks/create/templates/SDK-React/template/DETAILS/demo.stories.tsx.mustache +0 -3
- package/src/tasks/create/templates/SDK-React/template/DETAILS/index.tsx.mustache +1 -1
- package/src/tasks/create/templates/SDK-React/template/DETAILS-region/demo.stories.tsx.mustache +0 -3
- package/src/tasks/create/templates/SDK-React/template/DETAILS-region/index.tsx.mustache +1 -1
- package/src/tasks/create-all/index.js +3 -0
- package/src/tasks/publish/helper.js +4 -0
- package/src/tasks/publish-all/helper.js +6 -2
- package/src/tasks/validator/index.js +7 -1
package/src/tasks/create/templates/Constellation/field/Picklist-Autocomplete/utils.ts.mustache
CHANGED
|
@@ -181,7 +181,9 @@ export const updatePropertiesForNewRecord = (
|
|
|
181
181
|
setDataApiObj(dataObj);
|
|
182
182
|
buildColumnForDisplayValue(dataObj);
|
|
183
183
|
// SET matchPosition to EQUALS to return exact matching record
|
|
184
|
+
// @ts-ignore
|
|
184
185
|
dataObj.matchPosition = 'equals';
|
|
186
|
+
// @ts-ignore
|
|
185
187
|
dataObj
|
|
186
188
|
.fetchData(newCaseId)
|
|
187
189
|
// @ts-ignore
|
|
@@ -212,6 +214,7 @@ export const updatePropertiesForNewRecord = (
|
|
|
212
214
|
})
|
|
213
215
|
.finally(() => {
|
|
214
216
|
// RESET matchPosition
|
|
217
|
+
// @ts-ignore
|
|
215
218
|
dataObj.matchPosition = dataConfig.matchPosition;
|
|
216
219
|
});
|
|
217
220
|
});
|
|
@@ -1,4 +1,12 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import {
|
|
2
|
+
Input,
|
|
3
|
+
FieldValueList,
|
|
4
|
+
Text,
|
|
5
|
+
EmailDisplay,
|
|
6
|
+
PhoneDisplay,
|
|
7
|
+
URLDisplay,
|
|
8
|
+
withConfiguration
|
|
9
|
+
} from '@pega/cosmos-react-core';
|
|
2
10
|
|
|
3
11
|
import type { PConnFieldProps } from './PConnProps';
|
|
4
12
|
|
|
@@ -7,7 +15,9 @@ import Styled{{COMPONENT_CLASS_NAME}}Wrapper from './styles';
|
|
|
7
15
|
// interface for props
|
|
8
16
|
interface {{COMPONENT_CLASS_NAME}}Props extends PConnFieldProps {
|
|
9
17
|
// If any, enter additional props that only exist on TextInput here
|
|
10
|
-
|
|
18
|
+
isTableFormatter?: boolean;
|
|
19
|
+
formatter: string;
|
|
20
|
+
variant?: any;
|
|
11
21
|
}
|
|
12
22
|
|
|
13
23
|
// interface for StateProps object
|
|
@@ -16,23 +26,103 @@ interface StateProps {
|
|
|
16
26
|
hasSuggestions: boolean;
|
|
17
27
|
}
|
|
18
28
|
|
|
19
|
-
|
|
29
|
+
export const formatExists = (formatterVal: string) => {
|
|
30
|
+
const formatterValues = [
|
|
31
|
+
'TextInput',
|
|
32
|
+
'WorkStatus',
|
|
33
|
+
'RichText',
|
|
34
|
+
'Email',
|
|
35
|
+
'Phone',
|
|
36
|
+
'URL',
|
|
37
|
+
'Operator'
|
|
38
|
+
];
|
|
39
|
+
let isformatter = false;
|
|
40
|
+
if (formatterValues.includes(formatterVal)) {
|
|
41
|
+
isformatter = true;
|
|
42
|
+
}
|
|
43
|
+
return isformatter;
|
|
44
|
+
};
|
|
45
|
+
|
|
46
|
+
export const textFormatter = (formatter: string, value: string) => {
|
|
47
|
+
let displayComponent: any = null;
|
|
48
|
+
switch (formatter) {
|
|
49
|
+
case 'TextInput': {
|
|
50
|
+
displayComponent = value;
|
|
51
|
+
break;
|
|
52
|
+
}
|
|
53
|
+
case 'Email': {
|
|
54
|
+
displayComponent = <EmailDisplay value={value} displayText={value} variant='link' />;
|
|
55
|
+
break;
|
|
56
|
+
}
|
|
57
|
+
case 'Phone': {
|
|
58
|
+
displayComponent = <PhoneDisplay value={value} variant='link' />;
|
|
59
|
+
break;
|
|
60
|
+
}
|
|
61
|
+
case 'URL': {
|
|
62
|
+
displayComponent = (
|
|
63
|
+
<URLDisplay target='_blank' value={value} displayText={value} variant='link' />
|
|
64
|
+
);
|
|
65
|
+
break;
|
|
66
|
+
}
|
|
67
|
+
// no default
|
|
68
|
+
}
|
|
69
|
+
return displayComponent;
|
|
70
|
+
};
|
|
20
71
|
|
|
21
72
|
// props passed in combination of props from property panel (config.json) and run time props from Constellation
|
|
22
73
|
// any default values in config.pros should be set in defaultProps at bottom of this file
|
|
23
74
|
function {{COMPONENT_CLASS_NAME}}(props: {{COMPONENT_CLASS_NAME}}Props) {
|
|
24
|
-
const { getPConnect, value, placeholder, disabled = false, readOnly = false, required = false, label, hideLabel = false, testId } = props;
|
|
75
|
+
const { getPConnect, value, placeholder, disabled = false, displayMode, readOnly = false, required = false, label, hideLabel = false, testId, isTableFormatter = false, variant = 'inline' } = props;
|
|
25
76
|
|
|
26
77
|
const pConn = getPConnect();
|
|
27
78
|
const actions = pConn.getActionsApi();
|
|
28
79
|
const stateProps = pConn.getStateProps() as StateProps;
|
|
29
80
|
const propName: string = stateProps.value;
|
|
81
|
+
const { formatter } = props;
|
|
30
82
|
|
|
31
83
|
const handleOnChange = (event: any) => {
|
|
32
84
|
const { value: updatedValue } = event.target;
|
|
33
85
|
actions.updateFieldValue(propName, updatedValue);
|
|
34
86
|
};
|
|
35
87
|
|
|
88
|
+
if (displayMode === 'LABELS_LEFT' || displayMode === 'DISPLAY_ONLY') {
|
|
89
|
+
let displayComp = value || <span aria-hidden='true'>––</span>;
|
|
90
|
+
if (isTableFormatter && formatExists(formatter)) {
|
|
91
|
+
displayComp = textFormatter(formatter, value);
|
|
92
|
+
}
|
|
93
|
+
return displayMode === 'DISPLAY_ONLY' ? (
|
|
94
|
+
<Styled{{COMPONENT_CLASS_NAME}}Wrapper> {displayComp} </Styled{{COMPONENT_CLASS_NAME}}Wrapper>
|
|
95
|
+
) : (
|
|
96
|
+
<Styled{{COMPONENT_CLASS_NAME}}Wrapper>
|
|
97
|
+
<FieldValueList
|
|
98
|
+
variant={hideLabel ? 'stacked' : variant}
|
|
99
|
+
data-testid={testId}
|
|
100
|
+
fields={[{ id: '1', name: hideLabel ? '' : label, value: displayComp }]}
|
|
101
|
+
/>
|
|
102
|
+
</Styled{{COMPONENT_CLASS_NAME}}Wrapper>
|
|
103
|
+
);
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
if (displayMode === 'STACKED_LARGE_VAL') {
|
|
107
|
+
const isValDefined = typeof value !== 'undefined' && value !== '';
|
|
108
|
+
const val = isValDefined ? (
|
|
109
|
+
<Text variant='h1' as='span'>
|
|
110
|
+
{value}
|
|
111
|
+
</Text>
|
|
112
|
+
) : (
|
|
113
|
+
''
|
|
114
|
+
);
|
|
115
|
+
return (
|
|
116
|
+
<Styled{{COMPONENT_CLASS_NAME}}Wrapper>
|
|
117
|
+
<FieldValueList
|
|
118
|
+
variant='stacked'
|
|
119
|
+
data-testid={testId}
|
|
120
|
+
fields={[{ id: '2', name: hideLabel ? '' : label, value: val }]}
|
|
121
|
+
/>
|
|
122
|
+
</Styled{{COMPONENT_CLASS_NAME}}Wrapper>
|
|
123
|
+
);
|
|
124
|
+
}
|
|
125
|
+
|
|
36
126
|
return (
|
|
37
127
|
<Styled{{COMPONENT_CLASS_NAME}}Wrapper>
|
|
38
128
|
<Input
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
/* eslint-disable react-hooks/rules-of-hooks */
|
|
2
|
+
import React from 'react';
|
|
3
|
+
import { useEffect, useState } from 'react';
|
|
4
|
+
import { Avatar as CosmosAvatar, withConfiguration } from '@pega/cosmos-react-core';
|
|
5
|
+
import type { PConnFieldProps } from './PConnProps';
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
// interface for props
|
|
9
|
+
interface {{COMPONENT_CLASS_NAME}}AvatarProps extends PConnFieldProps {
|
|
10
|
+
// If any, enter additional props that only exist on TextInput here
|
|
11
|
+
metaObj: any;
|
|
12
|
+
showStatus: boolean;
|
|
13
|
+
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
function Avatar(props: {{COMPONENT_CLASS_NAME}}AvatarProps) {
|
|
17
|
+
const { metaObj, showStatus = false } = props;
|
|
18
|
+
const [imageBlobUrl, setImageBlobUrl] = useState(null);
|
|
19
|
+
let userName: string;
|
|
20
|
+
let userIdentifier: string;
|
|
21
|
+
|
|
22
|
+
// TODO Below if conditions can be removed once we have apis to get worklist/mywork info
|
|
23
|
+
// This is non CaseView case (Dashboard, MyWork etc)
|
|
24
|
+
if (!metaObj) {
|
|
25
|
+
userName = PCore.getEnvironmentInfo().getOperatorName();
|
|
26
|
+
userIdentifier = PCore.getEnvironmentInfo().getOperatorIdentifier();
|
|
27
|
+
} else {
|
|
28
|
+
userName = metaObj.name;
|
|
29
|
+
userIdentifier = metaObj.ID;
|
|
30
|
+
}
|
|
31
|
+
if (!userName && userIdentifier) {
|
|
32
|
+
userName = userIdentifier;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
useEffect(() => {
|
|
36
|
+
const imageKey = !metaObj ? PCore.getEnvironmentInfo().getOperatorImageInsKey() : metaObj.image;
|
|
37
|
+
if (imageKey) {
|
|
38
|
+
PCore.getAssetLoader()
|
|
39
|
+
.getSvcImage(imageKey)
|
|
40
|
+
.then((blob) => window.URL.createObjectURL(blob))
|
|
41
|
+
.then((imagePath) => setImageBlobUrl(imagePath as React.SetStateAction<any>));
|
|
42
|
+
}
|
|
43
|
+
}, [metaObj]);
|
|
44
|
+
|
|
45
|
+
if (showStatus) {
|
|
46
|
+
const currentState = PCore.getMessagingServiceManager().getUserPresence().getUserState(userIdentifier);
|
|
47
|
+
const [userState, setUserState]: any = useState(currentState === 'online' ? 'active' : 'inactive');
|
|
48
|
+
|
|
49
|
+
// @ts-ignore
|
|
50
|
+
const handleUserStateChange = ({ state }) => {
|
|
51
|
+
setUserState(state === 'online' ? 'active' : 'inactive');
|
|
52
|
+
};
|
|
53
|
+
|
|
54
|
+
useEffect(() => {
|
|
55
|
+
const subId = PCore.getMessagingServiceManager()
|
|
56
|
+
.getUserPresence()
|
|
57
|
+
// @ts-ignore
|
|
58
|
+
.subscribe(userIdentifier, handleUserStateChange);
|
|
59
|
+
|
|
60
|
+
return function cleanup() {
|
|
61
|
+
PCore.getMessagingServiceManager().getUserPresence().unsubscribe(userIdentifier, subId);
|
|
62
|
+
};
|
|
63
|
+
}, [userIdentifier, handleUserStateChange]);
|
|
64
|
+
// @ts-ignore
|
|
65
|
+
return <CosmosAvatar name={userName} imageSrc={imageBlobUrl as React.SetStateAction<any>} status={userState} />;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
// Do not render when userName does not exists
|
|
69
|
+
// TODO : In CNR case, pxRequestor is not available, please remove this condition once it populates
|
|
70
|
+
if (!userName) {
|
|
71
|
+
return null;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
return <CosmosAvatar name={userName} imageSrc={imageBlobUrl as React.SetStateAction<any>} />;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
|
|
78
|
+
export default withConfiguration(Avatar);
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import { Fragment, ReactElement } from 'react';
|
|
2
|
+
import { FieldValueList } from '@pega/cosmos-react-core';
|
|
3
|
+
|
|
4
|
+
interface DetailsRenderProps {
|
|
5
|
+
children?: never;
|
|
6
|
+
child: NonNullable<ReactElement>;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
const DetailsRender = (props: DetailsRenderProps) => {
|
|
10
|
+
const { child } = props;
|
|
11
|
+
|
|
12
|
+
const kids = child.props.getPConnect().getChildren();
|
|
13
|
+
|
|
14
|
+
const displayCompArr: ReactElement[] = [];
|
|
15
|
+
|
|
16
|
+
Object.values(kids).forEach((value: any, i :number) => {
|
|
17
|
+
const { type } = value.getPConnect().getRawMetadata();
|
|
18
|
+
const { hideLabel, variant, testId, label } = value
|
|
19
|
+
.getPConnect()
|
|
20
|
+
.resolveConfigProps(value.getPConnect().getConfigProps());
|
|
21
|
+
|
|
22
|
+
let displayComp;
|
|
23
|
+
const key = JSON.stringify(value.getPConnect());
|
|
24
|
+
const key1 = key.concat(`-${i}`);
|
|
25
|
+
|
|
26
|
+
if (type === 'reference') {
|
|
27
|
+
const refElement = value.getPConnect().getComponent();
|
|
28
|
+
|
|
29
|
+
displayCompArr.push(refElement);
|
|
30
|
+
} else {
|
|
31
|
+
const element = value.getPConnect().getComponent();
|
|
32
|
+
const displayEl = <Fragment key={key}>{element}</Fragment>;
|
|
33
|
+
|
|
34
|
+
{{! pick new delimiters for mustache }}
|
|
35
|
+
{{=<% %>=}}
|
|
36
|
+
displayComp = (
|
|
37
|
+
<Fragment key={key1}>
|
|
38
|
+
<FieldValueList
|
|
39
|
+
style={{ columnGap: '0'}}
|
|
40
|
+
variant={hideLabel ? 'stacked' : variant}
|
|
41
|
+
data-testid={testId}
|
|
42
|
+
fields={[{ id: '1', name: hideLabel ? '' : label, value: displayEl }]}
|
|
43
|
+
/>
|
|
44
|
+
</Fragment>
|
|
45
|
+
);
|
|
46
|
+
<%={{ }}=%> {{! revert delimiters for mustache }}
|
|
47
|
+
|
|
48
|
+
displayCompArr.push(displayComp);
|
|
49
|
+
}
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
return <>{displayCompArr}</>;
|
|
53
|
+
};
|
|
54
|
+
|
|
55
|
+
export default DetailsRender;
|
package/src/tasks/create/templates/Constellation/template/DETAILS/HighlightRender.tsx.mustache
ADDED
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
2
|
+
import React from 'react';
|
|
3
|
+
import { FieldValueList, Text } from '@pega/cosmos-react-core';
|
|
4
|
+
import type { PConnProps } from './PConnProps';
|
|
5
|
+
|
|
6
|
+
interface HighlightRenderProps extends PConnProps {
|
|
7
|
+
field?: any;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
const HighlightRender = (props: HighlightRenderProps) => {
|
|
11
|
+
const { getPConnect, field } = props;
|
|
12
|
+
|
|
13
|
+
field.config['displayMode'] = 'DISPLAY_ONLY';
|
|
14
|
+
|
|
15
|
+
// Mark as status display when using pyStatusWork
|
|
16
|
+
if (field.config?.value === '@P .pyStatusWork') {
|
|
17
|
+
field.type = 'TextInput';
|
|
18
|
+
field.config.displayAsStatus = true;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
const configProps = getPConnect().resolveConfigProps(field.config);
|
|
22
|
+
|
|
23
|
+
// @ts-ignore
|
|
24
|
+
const reactField = getPConnect().createComponent(field);
|
|
25
|
+
|
|
26
|
+
return (
|
|
27
|
+
{{! pick new delimiters for mustache }}
|
|
28
|
+
{{=<% %>=}}
|
|
29
|
+
<FieldValueList
|
|
30
|
+
style={{ width: 'auto' }}
|
|
31
|
+
variant='stacked'
|
|
32
|
+
data-testid={field.testId}
|
|
33
|
+
fields={[
|
|
34
|
+
{
|
|
35
|
+
id: '2',
|
|
36
|
+
name: configProps.hideLabel ? '' : configProps.label,
|
|
37
|
+
value: (
|
|
38
|
+
<Text variant='h1' as='span'>
|
|
39
|
+
{reactField}
|
|
40
|
+
</Text>
|
|
41
|
+
)
|
|
42
|
+
}
|
|
43
|
+
]}
|
|
44
|
+
/>
|
|
45
|
+
<%={{ }}=%> {{! revert delimiters for mustache }}
|
|
46
|
+
);
|
|
47
|
+
};
|
|
48
|
+
|
|
49
|
+
export default HighlightRender;
|
|
@@ -0,0 +1,218 @@
|
|
|
1
|
+
// @ts-nocheck
|
|
2
|
+
import { useState, useEffect, Fragment } from 'react';
|
|
3
|
+
import {
|
|
4
|
+
Link,
|
|
5
|
+
Button,
|
|
6
|
+
Popover,
|
|
7
|
+
useOuterEvent,
|
|
8
|
+
useElement,
|
|
9
|
+
Progress,
|
|
10
|
+
FormField,
|
|
11
|
+
useTheme,
|
|
12
|
+
withConfiguration
|
|
13
|
+
} from '@pega/cosmos-react-core';
|
|
14
|
+
import { Glimpse } from '@pega/cosmos-react-work';
|
|
15
|
+
import { EmailDisplay } from '@pega/cosmos-react-core';
|
|
16
|
+
|
|
17
|
+
import type { PConnFieldProps } from './PConnProps';
|
|
18
|
+
|
|
19
|
+
import Avatar from './Avatar';
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
// interface for props
|
|
23
|
+
interface {{COMPONENT_CLASS_NAME}}OperatorProps extends PConnFieldProps {
|
|
24
|
+
// If any, enter additional props that only exist on TextInput here
|
|
25
|
+
name: string;
|
|
26
|
+
id: string;
|
|
27
|
+
label: string;
|
|
28
|
+
metaObj: any;
|
|
29
|
+
externalUser: any;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
let pTarget = null;
|
|
33
|
+
|
|
34
|
+
function Operator(props: {{COMPONENT_CLASS_NAME}}OperatorProps) {
|
|
35
|
+
const { id, name, label, testId, helperText, externalUser, metaObj } = props;
|
|
36
|
+
const [isOpen, setIsOpen] = useState(false);
|
|
37
|
+
const [isLoading, setIsLoading] = useState(true);
|
|
38
|
+
const [popoverEl, setPopoverEl] = useElement(null);
|
|
39
|
+
const [popoverContent, setpopoverContent] = useState(null);
|
|
40
|
+
const theme: any = useTheme();
|
|
41
|
+
|
|
42
|
+
/* If the id has changed, we need to reset the popover */
|
|
43
|
+
useEffect(() => {
|
|
44
|
+
pTarget = null;
|
|
45
|
+
}, [id]);
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
{{! pick new delimiters for mustache }}
|
|
49
|
+
{{=<% %>=}}
|
|
50
|
+
|
|
51
|
+
const OperatorPreview = () => {
|
|
52
|
+
const localizedVal = PCore.getLocaleUtils().getLocaleValue;
|
|
53
|
+
const localeCategory = 'Operator';
|
|
54
|
+
setpopoverContent(
|
|
55
|
+
<Progress variant='ring' message={localizedVal('Loading operator...', localeCategory)} placement='local' />
|
|
56
|
+
);
|
|
57
|
+
if (externalUser && externalUser.classID !== 'Data-Party-Operator') {
|
|
58
|
+
const fields = [
|
|
59
|
+
{
|
|
60
|
+
id: 'pyFirstName',
|
|
61
|
+
name: localizedVal('Name', localeCategory),
|
|
62
|
+
value: externalUser.name
|
|
63
|
+
},
|
|
64
|
+
{
|
|
65
|
+
id: 'pyEmail1',
|
|
66
|
+
name: localizedVal('Email', localeCategory),
|
|
67
|
+
value:
|
|
68
|
+
externalUser.email !== '' ? <Link href={`mailto:${externalUser.email}`}>{externalUser.email}</Link> : ''
|
|
69
|
+
},
|
|
70
|
+
{
|
|
71
|
+
id: 'pyPhoneNumber',
|
|
72
|
+
name: localizedVal('Phone', localeCategory),
|
|
73
|
+
value: externalUser.phone !== '' ? <Link href={`tel:${externalUser.phone}`}>{externalUser.phone}</Link> : ''
|
|
74
|
+
}
|
|
75
|
+
];
|
|
76
|
+
setIsLoading(false);
|
|
77
|
+
setpopoverContent(
|
|
78
|
+
<Glimpse
|
|
79
|
+
visual={
|
|
80
|
+
<Avatar
|
|
81
|
+
metaObj={{
|
|
82
|
+
name: externalUser.name
|
|
83
|
+
}}
|
|
84
|
+
/>
|
|
85
|
+
}
|
|
86
|
+
primary={externalUser.name}
|
|
87
|
+
secondary={[externalUser.position]}
|
|
88
|
+
fields={fields}
|
|
89
|
+
target={pTarget}
|
|
90
|
+
/>
|
|
91
|
+
);
|
|
92
|
+
} else {
|
|
93
|
+
return PCore.getUserApi()
|
|
94
|
+
.getOperatorDetails(id, true)
|
|
95
|
+
.then(res => {
|
|
96
|
+
if (res.data?.pyOperatorInfo) {
|
|
97
|
+
const fields = [];
|
|
98
|
+
const data = res.data;
|
|
99
|
+
if (data.pyOperatorInfo && data.pyOperatorInfo.pyUserName) {
|
|
100
|
+
fields.push({
|
|
101
|
+
id: 'Name',
|
|
102
|
+
name: localizedVal('Name', localeCategory),
|
|
103
|
+
value: data.pyOperatorInfo.pyUserName
|
|
104
|
+
});
|
|
105
|
+
}
|
|
106
|
+
if (data.pyOperatorInfo && data.pyOperatorInfo.pyEmailAddress) {
|
|
107
|
+
fields.push({
|
|
108
|
+
id: 'Email',
|
|
109
|
+
name: localizedVal('Email address', localeCategory),
|
|
110
|
+
value: <EmailDisplay value={data.pyOperatorInfo.pyEmailAddress} />
|
|
111
|
+
});
|
|
112
|
+
}
|
|
113
|
+
const opAvatar = (
|
|
114
|
+
<Avatar
|
|
115
|
+
metaObj={{
|
|
116
|
+
image: '',
|
|
117
|
+
name: data.pyOperatorInfo.pyUserName
|
|
118
|
+
}}
|
|
119
|
+
/>
|
|
120
|
+
);
|
|
121
|
+
|
|
122
|
+
setIsLoading(false);
|
|
123
|
+
setpopoverContent(
|
|
124
|
+
<Glimpse
|
|
125
|
+
heading={{
|
|
126
|
+
primary: data.pyOperatorInfo.pyUserName,
|
|
127
|
+
secondary: data.pyOperatorInfo.pyEmailAddress,
|
|
128
|
+
visual: opAvatar
|
|
129
|
+
}}
|
|
130
|
+
fields={fields}
|
|
131
|
+
target={pTarget}
|
|
132
|
+
onDismiss={() => {pTarget = null;}}
|
|
133
|
+
/>
|
|
134
|
+
);
|
|
135
|
+
}
|
|
136
|
+
});
|
|
137
|
+
}
|
|
138
|
+
};
|
|
139
|
+
|
|
140
|
+
<%={{ }}=%> {{! revert delimiters for mustache }}
|
|
141
|
+
|
|
142
|
+
const clickAction = (e: any) => {
|
|
143
|
+
|
|
144
|
+
setIsOpen(!isOpen);
|
|
145
|
+
if (pTarget === null) {
|
|
146
|
+
pTarget = e.currentTarget;
|
|
147
|
+
OperatorPreview();
|
|
148
|
+
}
|
|
149
|
+
};
|
|
150
|
+
|
|
151
|
+
const hidePopover = () => {
|
|
152
|
+
if (isOpen) {
|
|
153
|
+
setIsOpen(false);
|
|
154
|
+
}
|
|
155
|
+
};
|
|
156
|
+
|
|
157
|
+
useOuterEvent('mousedown', [popoverEl], hidePopover); // Call the method on clicking outside these elements
|
|
158
|
+
|
|
159
|
+
const hideOnEscape = (e: any) => {
|
|
160
|
+
if (e.key === 'Escape') hidePopover(); // Call the method when Escape key is pressed
|
|
161
|
+
};
|
|
162
|
+
|
|
163
|
+
const comp = (
|
|
164
|
+
<Fragment>
|
|
165
|
+
{metaObj ? (
|
|
166
|
+
<Button
|
|
167
|
+
variant='text'
|
|
168
|
+
aria-haspopup
|
|
169
|
+
aria-expanded={isOpen}
|
|
170
|
+
onClick={clickAction}
|
|
171
|
+
onKeyDown={hideOnEscape}
|
|
172
|
+
data-test-id={testId}
|
|
173
|
+
style={label !== null ? { width: 'max-content', height: theme.components.input.height } : undefined}
|
|
174
|
+
>
|
|
175
|
+
<Avatar {...props} />
|
|
176
|
+
</Button>
|
|
177
|
+
) : (
|
|
178
|
+
<Button
|
|
179
|
+
variant='link'
|
|
180
|
+
aria-haspopup
|
|
181
|
+
aria-expanded={isOpen}
|
|
182
|
+
onClick={clickAction}
|
|
183
|
+
onKeyDown={hideOnEscape}
|
|
184
|
+
data-test-id={testId}
|
|
185
|
+
style={label !== null ? { width: 'max-content', height: theme.components.input.height } : undefined}
|
|
186
|
+
>
|
|
187
|
+
{name}
|
|
188
|
+
</Button>
|
|
189
|
+
)}
|
|
190
|
+
|
|
191
|
+
{isOpen && (
|
|
192
|
+
<Popover
|
|
193
|
+
ref={setPopoverEl}
|
|
194
|
+
groupId='operator'
|
|
195
|
+
target={pTarget}
|
|
196
|
+
placement='bottom-start'
|
|
197
|
+
style={isLoading ? { position: 'relative', width: '10rem', minHeight: '4rem' } : undefined}
|
|
198
|
+
strategy='fixed'
|
|
199
|
+
>
|
|
200
|
+
{popoverContent}
|
|
201
|
+
</Popover>
|
|
202
|
+
)}
|
|
203
|
+
</Fragment>
|
|
204
|
+
);
|
|
205
|
+
|
|
206
|
+
if (label !== null) {
|
|
207
|
+
return (
|
|
208
|
+
<FormField label={label} info={helperText}>
|
|
209
|
+
{comp}
|
|
210
|
+
</FormField>
|
|
211
|
+
);
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
return comp;
|
|
215
|
+
};
|
|
216
|
+
|
|
217
|
+
|
|
218
|
+
export default withConfiguration(Operator);
|
|
@@ -1,12 +1,12 @@
|
|
|
1
|
-
|
|
1
|
+
/* eslint-disable no-nested-ternary */
|
|
2
2
|
/* eslint-disable react/jsx-no-useless-fragment */
|
|
3
3
|
// @ts-nocheck
|
|
4
4
|
import type { Meta, StoryObj } from '@storybook/react';
|
|
5
|
-
import { Text, FieldValueList,
|
|
5
|
+
import { Text, FieldValueList, DateTimeDisplay, useTheme } from '@pega/cosmos-react-core';
|
|
6
6
|
import {{COMPONENT_CLASS_NAME}} from './index';
|
|
7
|
-
import { pyReviewRaw, pyReviewResolved, regionChildrenResolved } from './mock';
|
|
7
|
+
import { pyReviewRaw, pyReviewResolved, regionChildrenResolved, operatorDetails, configProps } from './mock';
|
|
8
8
|
import StatusWorkRenderer from './StatusWork';
|
|
9
|
-
|
|
9
|
+
import Operator from './Operator';
|
|
10
10
|
|
|
11
11
|
const meta: Meta<typeof {{COMPONENT_CLASS_NAME}}> = {
|
|
12
12
|
title: '{{COMPONENT_CLASS_NAME}}',
|
|
@@ -20,6 +20,33 @@ const meta: Meta<typeof {{COMPONENT_CLASS_NAME}}> = {
|
|
|
20
20
|
export default meta;
|
|
21
21
|
type Story = StoryObj<typeof {{COMPONENT_CLASS_NAME}}>;
|
|
22
22
|
|
|
23
|
+
if (!window.PCore) {
|
|
24
|
+
window.PCore = {};
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
window.PCore.getLocaleUtils = () => {
|
|
28
|
+
return {
|
|
29
|
+
getLocaleValue: value => {
|
|
30
|
+
return value;
|
|
31
|
+
}
|
|
32
|
+
};
|
|
33
|
+
};
|
|
34
|
+
|
|
35
|
+
window.PCore.getUserApi = () => {
|
|
36
|
+
return {
|
|
37
|
+
getOperatorDetails: () => {
|
|
38
|
+
return new Promise(resolve => {
|
|
39
|
+
resolve(operatorDetails);
|
|
40
|
+
});
|
|
41
|
+
}
|
|
42
|
+
};
|
|
43
|
+
};
|
|
44
|
+
|
|
45
|
+
const Region = () => {
|
|
46
|
+
return <></>;
|
|
47
|
+
};
|
|
48
|
+
|
|
49
|
+
|
|
23
50
|
const renderField = resolvedProps => {
|
|
24
51
|
const {
|
|
25
52
|
displayAsStatus = false,
|
|
@@ -27,7 +54,7 @@ const renderField = resolvedProps => {
|
|
|
27
54
|
value = '',
|
|
28
55
|
label = '',
|
|
29
56
|
key,
|
|
30
|
-
// eslint-disable-next-line react-hooks/rules-of-hooks
|
|
57
|
+
// eslint-disable-next-line react-hooks/rules-of-hooks, @typescript-eslint/no-unused-vars
|
|
31
58
|
theme = useTheme()
|
|
32
59
|
} = resolvedProps;
|
|
33
60
|
|
|
@@ -55,19 +82,30 @@ const renderField = resolvedProps => {
|
|
|
55
82
|
|
|
56
83
|
if (displayAsStatus === true) val = <StatusWorkRenderer value={value} key={key} />;
|
|
57
84
|
|
|
85
|
+
const [_label] =
|
|
86
|
+
label === 'Create operator'
|
|
87
|
+
? [configProps.createLabel, configProps.createOperator, configProps.createDateTime]
|
|
88
|
+
: label === 'Update operator'
|
|
89
|
+
? [configProps.updateLabel, configProps.updateOperator, configProps.updateDateTime]
|
|
90
|
+
: [configProps.resolveLabel, configProps.resolveOperator, configProps.resolveDateTime];
|
|
91
|
+
|
|
58
92
|
if (label === 'Create Operator')
|
|
59
93
|
val = (
|
|
60
|
-
<
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
{
|
|
70
|
-
|
|
94
|
+
<Operator
|
|
95
|
+
label={configProps.hideLabel ? '' : _label}
|
|
96
|
+
name={configProps.createOperator.userName}
|
|
97
|
+
id={configProps.createOperator.userId}
|
|
98
|
+
value={undefined}
|
|
99
|
+
validatemessage=''
|
|
100
|
+
hideLabel={false}
|
|
101
|
+
readOnly={false}
|
|
102
|
+
required={false}
|
|
103
|
+
disabled={false}
|
|
104
|
+
externalUser={undefined}
|
|
105
|
+
metaObj={undefined}
|
|
106
|
+
testId=''
|
|
107
|
+
helperText=''
|
|
108
|
+
/>
|
|
71
109
|
);
|
|
72
110
|
|
|
73
111
|
if (variant === 'inline') {
|
|
@@ -124,20 +162,36 @@ export const Base{{COMPONENT_CLASS_NAME}}: Story = args => {
|
|
|
124
162
|
setInheritedProp: () => {
|
|
125
163
|
/* nothing */
|
|
126
164
|
},
|
|
127
|
-
resolveConfigProps:
|
|
128
|
-
|
|
165
|
+
resolveConfigProps: config => {
|
|
166
|
+
return config;
|
|
129
167
|
}
|
|
130
168
|
};
|
|
131
169
|
}
|
|
132
170
|
};
|
|
133
171
|
|
|
134
|
-
const regionAChildren = pyReviewRaw.children[0].children.map(child => {
|
|
135
|
-
return props.getPConnect().createComponent(child);
|
|
136
|
-
});
|
|
137
|
-
|
|
138
172
|
return (
|
|
139
173
|
<>
|
|
140
|
-
<{{COMPONENT_CLASS_NAME}} {...props} {...args}>
|
|
174
|
+
<{{COMPONENT_CLASS_NAME}} {...props} {...args}>
|
|
175
|
+
<Region
|
|
176
|
+
{...{
|
|
177
|
+
getPConnect: () => ({
|
|
178
|
+
setInheritedProp: () => {},
|
|
179
|
+
getChildren: () =>
|
|
180
|
+
pyReviewRaw.children[0].children.map((child, index) => {
|
|
181
|
+
return {
|
|
182
|
+
getPConnect: () => ({
|
|
183
|
+
getRawMetadata: () => pyReviewRaw.children[0].children[index],
|
|
184
|
+
getConfigProps: () => {},
|
|
185
|
+
resolveConfigProps: () => regionChildrenResolved[index],
|
|
186
|
+
getComponent: () =>
|
|
187
|
+
props.getPConnect().createComponent(pyReviewRaw.children[0].children[index])
|
|
188
|
+
})
|
|
189
|
+
};
|
|
190
|
+
})
|
|
191
|
+
})
|
|
192
|
+
}}
|
|
193
|
+
/>
|
|
194
|
+
</{{COMPONENT_CLASS_NAME}}>
|
|
141
195
|
</>
|
|
142
196
|
);
|
|
143
197
|
};
|