@pega/react-sdk-overrides 0.25.7 → 0.25.11
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/lib/designSystemExtension/AlertBanner/AlertBanner.css +46 -0
- package/lib/designSystemExtension/AlertBanner/AlertBanner.tsx +37 -20
- package/lib/designSystemExtension/FieldGroupList/FieldGroupList.tsx +1 -1
- package/lib/infra/Assignment/Assignment.tsx +12 -3
- package/lib/infra/Assignment/useValidationBanner.ts +29 -0
- package/lib/infra/Containers/FlowContainer/FlowContainer.tsx +4 -5
- package/lib/infra/Containers/ModalViewContainer/ModalViewContainer.tsx +6 -1
- package/lib/infra/Containers/ViewContainer/ViewContainer.tsx +4 -8
- package/lib/infra/DeferLoad/DeferLoad.tsx +24 -9
- package/lib/infra/NavBar/NavBar.tsx +19 -5
- package/lib/infra/Reference/Reference.tsx +5 -0
- package/lib/infra/RootContainer/RootContainer.tsx +4 -5
- package/lib/infra/Stages/Stages.tsx +2 -3
- package/lib/infra/View/View.tsx +5 -6
- package/lib/template/AppShell/AppShell.css +0 -4
- package/lib/template/CaseView/CaseView.tsx +3 -2
- package/lib/template/FieldGroupTemplate/FieldGroupTemplate.tsx +10 -3
- package/lib/template/HierarchicalForm/HierarchicalForm.tsx +58 -0
- package/lib/template/HierarchicalForm/hooks.ts +224 -0
- package/lib/template/HierarchicalForm/index.tsx +1 -0
- package/lib/template/ListView/ListView.tsx +73 -15
- package/lib/template/MultiReferenceReadOnly/MultiReferenceReadOnly.tsx +16 -1
- package/lib/template/ObjectPage/index.tsx +1 -0
- package/lib/template/SelfServiceCaseView/SelfServiceCaseView.tsx +51 -43
- package/lib/template/SimpleTable/SimpleTableManual/SimpleTableManual.tsx +14 -6
- package/lib/template/SimpleTable/SimpleTableSelectReadonly/SimpleTableSelectReadonly.tsx +179 -0
- package/lib/template/SimpleTable/SimpleTableSelectReadonly/index.tsx +1 -0
- package/package.json +1 -1
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
.alert-banner-title {
|
|
2
|
+
font-weight: 700;
|
|
3
|
+
font-size: 1rem;
|
|
4
|
+
display: flex;
|
|
5
|
+
align-items: center;
|
|
6
|
+
gap: 0.25rem;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
.alert-banner-badge {
|
|
10
|
+
display: inline-flex;
|
|
11
|
+
align-items: center;
|
|
12
|
+
justify-content: center;
|
|
13
|
+
min-width: 1rem;
|
|
14
|
+
height: 1rem;
|
|
15
|
+
padding: 0 0.2rem;
|
|
16
|
+
border-radius: 999px;
|
|
17
|
+
font-size: 0.6rem;
|
|
18
|
+
font-weight: 700;
|
|
19
|
+
line-height: 1;
|
|
20
|
+
vertical-align: middle;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
.alert-banner-badge--urgent {
|
|
24
|
+
background: var(--app-error-dark-color);
|
|
25
|
+
color: #fff;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
.alert-banner-badge--warning {
|
|
29
|
+
background: var(--app-warning-color-dark);
|
|
30
|
+
color: #fff;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
.alert-banner-badge--success {
|
|
34
|
+
background: var(--stepper-completed-bg-color);
|
|
35
|
+
color: #fff;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
.alert-banner-badge--info {
|
|
39
|
+
background: var(--link-button-color);
|
|
40
|
+
color: #fff;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
.alert-banner-list {
|
|
44
|
+
margin: 0;
|
|
45
|
+
padding-left: 1.25rem;
|
|
46
|
+
}
|
|
@@ -1,39 +1,56 @@
|
|
|
1
|
-
import { Alert } from '@mui/material';
|
|
1
|
+
import { Alert, AlertTitle } from '@mui/material';
|
|
2
|
+
import './AlertBanner.css';
|
|
2
3
|
|
|
3
4
|
// AlertBanner is one of the few components that does NOT have getPConnect.
|
|
4
5
|
// So, no need to extend PConnProps
|
|
5
6
|
interface AlertBannerProps {
|
|
6
|
-
// If any, enter additional props that only exist on Date here
|
|
7
7
|
id: string;
|
|
8
8
|
variant: string;
|
|
9
9
|
messages: string[];
|
|
10
10
|
onDismiss?: any;
|
|
11
11
|
}
|
|
12
12
|
|
|
13
|
-
const
|
|
14
|
-
urgent: 'error',
|
|
15
|
-
warning: 'warning',
|
|
16
|
-
success: 'success',
|
|
17
|
-
info: 'info'
|
|
13
|
+
const VARIANT_MAP: Record<string, { severity: string; label: string }> = {
|
|
14
|
+
urgent: { severity: 'error', label: 'Error' },
|
|
15
|
+
warning: { severity: 'warning', label: 'Warning' },
|
|
16
|
+
success: { severity: 'success', label: 'Success' },
|
|
17
|
+
info: { severity: 'info', label: 'Info' }
|
|
18
18
|
};
|
|
19
19
|
|
|
20
|
-
|
|
21
|
-
const
|
|
22
|
-
|
|
20
|
+
function renderMessage(message: string) {
|
|
21
|
+
const colonIndex = message.indexOf(':');
|
|
22
|
+
if (colonIndex === -1) return message;
|
|
23
|
+
return (
|
|
24
|
+
<>
|
|
25
|
+
<strong>{message.slice(0, colonIndex + 1)}</strong>
|
|
26
|
+
{message.slice(colonIndex + 1)}
|
|
27
|
+
</>
|
|
28
|
+
);
|
|
29
|
+
}
|
|
23
30
|
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
};
|
|
28
|
-
}
|
|
31
|
+
export default function AlertBanner({ id, variant, messages, onDismiss }: AlertBannerProps) {
|
|
32
|
+
const { severity, label } = VARIANT_MAP[variant] ?? VARIANT_MAP.info;
|
|
33
|
+
const isMultiple = messages.length > 1;
|
|
29
34
|
|
|
30
35
|
return (
|
|
31
36
|
<div id={id}>
|
|
32
|
-
{
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
+
<Alert variant='outlined' severity={severity as any} {...(onDismiss && { onClose: onDismiss })}>
|
|
38
|
+
{isMultiple && (
|
|
39
|
+
<AlertTitle className='alert-banner-title'>
|
|
40
|
+
{label}
|
|
41
|
+
<span className={`alert-banner-badge alert-banner-badge--${variant}`}>{messages.length}</span>
|
|
42
|
+
</AlertTitle>
|
|
43
|
+
)}
|
|
44
|
+
{isMultiple ? (
|
|
45
|
+
<ul className='alert-banner-list'>
|
|
46
|
+
{messages.map(message => (
|
|
47
|
+
<li key={message}>{renderMessage(message)}</li>
|
|
48
|
+
))}
|
|
49
|
+
</ul>
|
|
50
|
+
) : (
|
|
51
|
+
renderMessage(messages[0])
|
|
52
|
+
)}
|
|
53
|
+
</Alert>
|
|
37
54
|
</div>
|
|
38
55
|
);
|
|
39
56
|
}
|
|
@@ -24,7 +24,7 @@ export default function FieldGroupList(props: FieldGroupListProps) {
|
|
|
24
24
|
<Grid2 style={{ width: '100%' }}>
|
|
25
25
|
<Grid2 container spacing={1}>
|
|
26
26
|
{props.items.map(item => (
|
|
27
|
-
<Grid2 style={{ width: '100%' }}>
|
|
27
|
+
<Grid2 key={item.name} style={{ width: '100%' }}>
|
|
28
28
|
<b>{item.name}</b>
|
|
29
29
|
{props.onDelete && (
|
|
30
30
|
<button
|
|
@@ -5,6 +5,8 @@ import CloseIcon from '@mui/icons-material/Close';
|
|
|
5
5
|
|
|
6
6
|
import { getComponentFromMap } from '@pega/react-sdk-components/lib/bridge/helpers/sdk_component_map';
|
|
7
7
|
import { useFocusFirstField, useScrolltoTop } from '@pega/react-sdk-components/lib/hooks';
|
|
8
|
+
import AlertBanner from '@pega/react-sdk-components/lib/components/designSystemExtension/AlertBanner/AlertBanner';
|
|
9
|
+
import { useValidationBanner } from './useValidationBanner';
|
|
8
10
|
|
|
9
11
|
import type { PConnProps } from '@pega/react-sdk-components/lib/types/PConnProps';
|
|
10
12
|
|
|
@@ -23,6 +25,7 @@ export default function Assignment(props: PropsWithChildren<AssignmentProps>) {
|
|
|
23
25
|
const MultiStep = getComponentFromMap('MultiStep');
|
|
24
26
|
|
|
25
27
|
const { getPConnect, children, itemKey = '', isInModal = false, banners = [] } = props;
|
|
28
|
+
const validationMessages = useValidationBanner(itemKey);
|
|
26
29
|
const thePConn = getPConnect();
|
|
27
30
|
|
|
28
31
|
const [bHasNavigation, setHasNavigation] = useState(false);
|
|
@@ -33,8 +36,8 @@ export default function Assignment(props: PropsWithChildren<AssignmentProps>) {
|
|
|
33
36
|
|
|
34
37
|
const actionsAPI = thePConn.getActionsApi();
|
|
35
38
|
const localizedVal = PCore.getLocaleUtils().getLocaleValue;
|
|
39
|
+
const localizationService = thePConn.getLocalizationService();
|
|
36
40
|
const localeCategory = 'Assignment';
|
|
37
|
-
const localeReference = getPConnect()?.getCaseLocaleReference();
|
|
38
41
|
|
|
39
42
|
// store off bound functions to above pointers
|
|
40
43
|
const finishAssignment = actionsAPI.finishAssignment.bind(actionsAPI);
|
|
@@ -76,7 +79,7 @@ export default function Assignment(props: PropsWithChildren<AssignmentProps>) {
|
|
|
76
79
|
function getStepsInfo(steps, formedSteps: any = []) {
|
|
77
80
|
steps.forEach(step => {
|
|
78
81
|
if (step.name) {
|
|
79
|
-
step.name =
|
|
82
|
+
step.name = localizationService.getLocalizedText(step.name);
|
|
80
83
|
}
|
|
81
84
|
if (step.steps) {
|
|
82
85
|
formedSteps = getStepsInfo(step.steps, formedSteps);
|
|
@@ -88,8 +91,9 @@ export default function Assignment(props: PropsWithChildren<AssignmentProps>) {
|
|
|
88
91
|
}
|
|
89
92
|
|
|
90
93
|
const scrollId = window.location.href.includes('embedded') ? '#pega-part-of-page' : '#portal';
|
|
94
|
+
const currentAssignmentViewName = getPConnect().getCaseInfo().getCurrentAssignmentViewName();
|
|
91
95
|
useScrolltoTop(scrollId, children);
|
|
92
|
-
useFocusFirstField('Assignment',
|
|
96
|
+
useFocusFirstField('Assignment', currentAssignmentViewName);
|
|
93
97
|
|
|
94
98
|
useEffect(() => {
|
|
95
99
|
if (children) {
|
|
@@ -310,6 +314,11 @@ export default function Assignment(props: PropsWithChildren<AssignmentProps>) {
|
|
|
310
314
|
|
|
311
315
|
return (
|
|
312
316
|
<div id='Assignment'>
|
|
317
|
+
{validationMessages.length > 0 && (
|
|
318
|
+
<div style={{ marginBottom: '1rem' }}>
|
|
319
|
+
<AlertBanner id={`validation-banner-${itemKey}`} variant='urgent' messages={validationMessages} />
|
|
320
|
+
</div>
|
|
321
|
+
)}
|
|
313
322
|
{banners}
|
|
314
323
|
{bHasNavigation ? (
|
|
315
324
|
<>
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { useState, useEffect, useCallback } from 'react';
|
|
2
|
+
|
|
3
|
+
function formatError(error: any, localizedVal: Function): string {
|
|
4
|
+
if (typeof error === 'string') return localizedVal(error, 'Messages');
|
|
5
|
+
const label = error.label?.endsWith(':') ? error.label : `${error.label}:`;
|
|
6
|
+
return localizedVal(`${label} ${error.description}`, 'Messages');
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Subscribes to the PCore store and returns formatted validation error messages
|
|
11
|
+
* for the given itemKey. Reacts to any ADD_MESSAGES / CLEAR_MESSAGES dispatch
|
|
12
|
+
* (blur, tab, submit, etc.) so the banner appears and clears in real time.
|
|
13
|
+
*/
|
|
14
|
+
export function useValidationBanner(itemKey: string): string[] {
|
|
15
|
+
const [messages, setMessages] = useState<string[]>([]);
|
|
16
|
+
|
|
17
|
+
const readMessages = useCallback(() => {
|
|
18
|
+
const localizedVal = PCore.getLocaleUtils().getLocaleValue;
|
|
19
|
+
const errors: any[] = PCore.getMessageManager().getValidationErrorMessages(itemKey) || [];
|
|
20
|
+
setMessages(errors.map(error => formatError(error, localizedVal)));
|
|
21
|
+
}, [itemKey]);
|
|
22
|
+
|
|
23
|
+
useEffect(() => {
|
|
24
|
+
readMessages();
|
|
25
|
+
return PCore.getStore().subscribe(readMessages);
|
|
26
|
+
}, [readMessages]);
|
|
27
|
+
|
|
28
|
+
return messages;
|
|
29
|
+
}
|
|
@@ -22,11 +22,10 @@ interface FlowContainerProps extends PConnProps {
|
|
|
22
22
|
activeContainerItemID: string;
|
|
23
23
|
}
|
|
24
24
|
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
//
|
|
25
|
+
/**
|
|
26
|
+
* WARNING: This file is part of the infrastructure component responsible for working with Redux and managing the creation and update of Redux containers and PConnect.
|
|
27
|
+
* You may override Material components within this component if needed, but do not modify any container-related logic. Changing this logic can lead to unexpected behavior.
|
|
28
|
+
*/
|
|
30
29
|
|
|
31
30
|
const useStyles = makeStyles(theme => ({
|
|
32
31
|
root: {
|
|
@@ -13,6 +13,11 @@ import { getComponentFromMap } from '@pega/react-sdk-components/lib/bridge/helpe
|
|
|
13
13
|
import { getBanners } from '@pega/react-sdk-components/lib/components/helpers/case-utils';
|
|
14
14
|
import type { PConnProps } from '@pega/react-sdk-components/lib/types/PConnProps';
|
|
15
15
|
|
|
16
|
+
/**
|
|
17
|
+
* WARNING: This file is part of the infrastructure component responsible for working with Redux and managing the creation and update of Redux containers and PConnect.
|
|
18
|
+
* You may override Material components within this component if needed, but do not modify any container-related logic. Changing this logic can lead to unexpected behavior.
|
|
19
|
+
*/
|
|
20
|
+
|
|
16
21
|
interface ModalViewContainerProps extends PConnProps {
|
|
17
22
|
// If any, enter additional props that only exist on this component
|
|
18
23
|
loadingInfo?: string;
|
|
@@ -310,7 +315,7 @@ export default function ModalViewContainer(props: ModalViewContainerProps) {
|
|
|
310
315
|
|
|
311
316
|
return (
|
|
312
317
|
<>
|
|
313
|
-
<Dialog open={bShowModal} aria-labelledby='form-dialog-title' maxWidth=
|
|
318
|
+
<Dialog open={bShowModal} aria-labelledby='form-dialog-title' maxWidth='sm' fullWidth>
|
|
314
319
|
<DialogTitle id='form-dialog-title' className={`${classes.dlgTitle} psdk-dialog-title`}>
|
|
315
320
|
{title}
|
|
316
321
|
</DialogTitle>
|
|
@@ -17,14 +17,10 @@ interface ViewContainerProps extends PConnProps {
|
|
|
17
17
|
limit?: number;
|
|
18
18
|
}
|
|
19
19
|
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
// WARNING: It is not expected that this file should be modified. It is part of infrastructure code that works with
|
|
25
|
-
// Redux and creation/update of Redux containers and PConnect. Modifying this code could have undesireable results and
|
|
26
|
-
// is totally at your own risk.
|
|
27
|
-
//
|
|
20
|
+
/**
|
|
21
|
+
* WARNING: This file is part of the infrastructure component responsible for working with Redux and managing the creation and update of Redux containers and PConnect.
|
|
22
|
+
* You may override Material components within this component if needed, but do not modify any container-related logic. Changing this logic can lead to unexpected behavior.
|
|
23
|
+
*/
|
|
28
24
|
|
|
29
25
|
export default function ViewContainer(props: ViewContainerProps) {
|
|
30
26
|
// const { getPConnect, children, routingInfo, name } = props;
|
|
@@ -13,13 +13,13 @@ interface DeferLoadProps extends PConnProps {
|
|
|
13
13
|
isTab: boolean;
|
|
14
14
|
deferLoadId: string;
|
|
15
15
|
lastUpdateCaseTime: any;
|
|
16
|
+
template?: string;
|
|
16
17
|
}
|
|
17
18
|
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
//
|
|
19
|
+
/**
|
|
20
|
+
* WARNING: This file is part of the infrastructure component responsible for working with Redux and managing the creation and update of Redux containers and PConnect.
|
|
21
|
+
* You may override Material components within this component if needed, but do not modify any container-related logic. Changing this logic can lead to unexpected behavior.
|
|
22
|
+
*/
|
|
23
23
|
|
|
24
24
|
const useStyles = makeStyles(theme => ({
|
|
25
25
|
root: {
|
|
@@ -35,7 +35,7 @@ const useStyles = makeStyles(theme => ({
|
|
|
35
35
|
}));
|
|
36
36
|
|
|
37
37
|
export default function DeferLoad(props: DeferLoadProps) {
|
|
38
|
-
const { getPConnect, name, deferLoadId, isTab, lastUpdateCaseTime } = props;
|
|
38
|
+
const { getPConnect, name, deferLoadId, isTab, lastUpdateCaseTime, template } = props;
|
|
39
39
|
const [content, setContent] = useState<any>(null);
|
|
40
40
|
const [isLoading, setLoading] = useState(true);
|
|
41
41
|
const [currentLoadedAssignment, setCurrentLoadedAssignment] = useState('');
|
|
@@ -75,7 +75,7 @@ export default function DeferLoad(props: DeferLoadProps) {
|
|
|
75
75
|
updateData: isContainerPreview
|
|
76
76
|
});
|
|
77
77
|
|
|
78
|
-
const onResponse = data => {
|
|
78
|
+
const onResponse = (data: any, isEditable = false) => {
|
|
79
79
|
setLoading(false);
|
|
80
80
|
if (deferLoadId) {
|
|
81
81
|
PCore.getDeferLoadManager().start(
|
|
@@ -92,11 +92,16 @@ export default function DeferLoad(props: DeferLoadProps) {
|
|
|
92
92
|
meta: data,
|
|
93
93
|
options: {
|
|
94
94
|
context: pConnect.getContextName(),
|
|
95
|
-
pageReference: pConnect.getPageReference()
|
|
95
|
+
pageReference: pConnect.getPageReference(),
|
|
96
|
+
target: pConnect.getTarget(),
|
|
97
|
+
hasForm: true,
|
|
98
|
+
viewName: (pConnect as any).viewName
|
|
96
99
|
}
|
|
97
100
|
};
|
|
98
101
|
const configObject = PCore.createPConnect(config);
|
|
99
|
-
|
|
102
|
+
if (!isEditable) {
|
|
103
|
+
configObject.getPConnect().setInheritedProp('displayMode', 'DISPLAY_ONLY');
|
|
104
|
+
}
|
|
100
105
|
setContent(createElement(createPConnectComponent(), configObject));
|
|
101
106
|
if (deferLoadId) {
|
|
102
107
|
PCore.getDeferLoadManager().stop(deferLoadId, getPConnect().getContextName());
|
|
@@ -132,6 +137,16 @@ export default function DeferLoad(props: DeferLoadProps) {
|
|
|
132
137
|
.then(data => {
|
|
133
138
|
onResponse(data);
|
|
134
139
|
});
|
|
140
|
+
} else if (template === 'HierarchicalForm') {
|
|
141
|
+
const root = {
|
|
142
|
+
config: {
|
|
143
|
+
context: pConnect.getPageReference(),
|
|
144
|
+
name,
|
|
145
|
+
type: 'view'
|
|
146
|
+
},
|
|
147
|
+
type: 'reference'
|
|
148
|
+
};
|
|
149
|
+
onResponse(root, true);
|
|
135
150
|
} else {
|
|
136
151
|
getPConnect()
|
|
137
152
|
.getActionsApi()
|
|
@@ -133,19 +133,31 @@ export default function NavBar(props: NavBarProps) {
|
|
|
133
133
|
const portalLogoImage = Utils.getIconPath(Utils.getSDKStaticConentUrl()).concat('pzpega-logo-mark.svg');
|
|
134
134
|
const portalOperator = PCore.getEnvironmentInfo().getOperatorName();
|
|
135
135
|
const portalApp = PCore.getEnvironmentInfo().getApplicationLabel();
|
|
136
|
-
|
|
136
|
+
// @ts-ignore
|
|
137
|
+
const localeReference = PCore.getLocaleUtils().getPortalLocaleReference() || pConn.getValue('.pyLocaleReference');
|
|
137
138
|
useEffect(() => {
|
|
138
|
-
|
|
139
|
+
const updatedPages = pages.map((page: any) => {
|
|
140
|
+
const destinationObject: any = {};
|
|
141
|
+
pConn.resolveConfigProps(
|
|
142
|
+
{ defaultHeading: page.pyDefaultHeading || page.pyLabel, localeReference: page.pyLocalizationReference },
|
|
143
|
+
destinationObject
|
|
144
|
+
);
|
|
145
|
+
const name = localeUtils.getLocaleValue(destinationObject.defaultHeading, '', destinationObject.localeReference || localeReference);
|
|
146
|
+
return { ...page, name };
|
|
147
|
+
});
|
|
148
|
+
setNavPages(updatedPages);
|
|
139
149
|
}, [pages]);
|
|
140
150
|
|
|
141
151
|
function navPanelButtonClick(oPageData: any) {
|
|
142
152
|
const { pyClassName, pyRuleName } = oPageData;
|
|
143
|
-
|
|
144
153
|
pConn
|
|
145
154
|
.getActionsApi()
|
|
146
155
|
.showPage(pyRuleName, pyClassName)
|
|
147
156
|
.then(() => {
|
|
148
157
|
console.log(`${localizedVal('showPage completed', localeCategory)}`);
|
|
158
|
+
})
|
|
159
|
+
.catch(error => {
|
|
160
|
+
console.error('Failed to navigate to page from NavBar', error);
|
|
149
161
|
});
|
|
150
162
|
}
|
|
151
163
|
|
|
@@ -155,12 +167,14 @@ export default function NavBar(props: NavBarProps) {
|
|
|
155
167
|
containerName: 'primary',
|
|
156
168
|
flowType: sFlowType || 'pyStartCase'
|
|
157
169
|
};
|
|
158
|
-
|
|
159
170
|
pConn
|
|
160
171
|
.getActionsApi()
|
|
161
172
|
.createWork(sCaseType, actionInfo)
|
|
162
173
|
.then(() => {
|
|
163
174
|
console.log(`${localizedVal('createWork completed', localeCategory)}`);
|
|
175
|
+
})
|
|
176
|
+
.catch(error => {
|
|
177
|
+
console.error('Failed to create case from NavBar', error);
|
|
164
178
|
});
|
|
165
179
|
}
|
|
166
180
|
|
|
@@ -249,7 +263,7 @@ export default function NavBar(props: NavBarProps) {
|
|
|
249
263
|
{navPages.map(page => (
|
|
250
264
|
<ListItemButton onClick={() => navPanelButtonClick(page)} key={page.pyLabel}>
|
|
251
265
|
<ListItemIcon>{iconMap[page.pxPageViewIcon]}</ListItemIcon>
|
|
252
|
-
<ListItemText primary={
|
|
266
|
+
<ListItemText primary={page.name} />
|
|
253
267
|
</ListItemButton>
|
|
254
268
|
))}
|
|
255
269
|
</List>
|
|
@@ -38,6 +38,11 @@ export default function Reference(props: ReferenceProps) {
|
|
|
38
38
|
pageReference: context && context.startsWith('@CLASS') ? '' : context
|
|
39
39
|
});
|
|
40
40
|
|
|
41
|
+
if (referenceConfig.inheritedProps && referenceConfig.inheritedProps.length > 0) {
|
|
42
|
+
const inheritedProps = pConnect.getInheritedProps();
|
|
43
|
+
referenceConfig.inheritedProps = Object.keys(inheritedProps).map(prop => ({ prop, value: inheritedProps[prop] }));
|
|
44
|
+
}
|
|
45
|
+
|
|
41
46
|
viewComponent.props.getPConnect().setInheritedConfig({
|
|
42
47
|
...referenceConfig,
|
|
43
48
|
readOnly,
|
|
@@ -15,11 +15,10 @@ interface RootContainerProps extends PConnProps {
|
|
|
15
15
|
httpMessages: any[];
|
|
16
16
|
}
|
|
17
17
|
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
//
|
|
18
|
+
/**
|
|
19
|
+
* WARNING: This file is part of the infrastructure component responsible for working with Redux and managing the creation and update of Redux containers and PConnect.
|
|
20
|
+
* You may override Material components within this component if needed, but do not modify any container-related logic. Changing this logic can lead to unexpected behavior.
|
|
21
|
+
*/
|
|
23
22
|
|
|
24
23
|
const renderingModes = ['portal', 'view'];
|
|
25
24
|
|
|
@@ -57,14 +57,13 @@ export default function Stages(props: StagesProps) {
|
|
|
57
57
|
|
|
58
58
|
const { getPConnect, stages } = props;
|
|
59
59
|
const pConn = getPConnect();
|
|
60
|
-
const
|
|
61
|
-
|
|
60
|
+
const localizationService = pConn.getLocalizationService();
|
|
62
61
|
const filteredStages = getFilteredStages(stages);
|
|
63
62
|
const currentStageID = pConn.getValue(PCore.getConstants().CASE_INFO.STAGEID, ''); // 2nd arg empty string until typedef allows optional
|
|
64
63
|
const stagesObj = filteredStages.map((stage, index, arr) => {
|
|
65
64
|
const theID = stage.ID || stage.id;
|
|
66
65
|
return {
|
|
67
|
-
name:
|
|
66
|
+
name: localizationService.getLocalizedText(stage.name),
|
|
68
67
|
id: theID,
|
|
69
68
|
complete: stage.visited_status === 'completed',
|
|
70
69
|
current: theID === currentStageID,
|
package/lib/infra/View/View.tsx
CHANGED
|
@@ -21,13 +21,12 @@ interface ViewProps extends PConnProps {
|
|
|
21
21
|
type?: any;
|
|
22
22
|
}
|
|
23
23
|
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
//
|
|
24
|
+
/**
|
|
25
|
+
* WARNING: This file is part of the infrastructure component responsible for working with Redux and managing the creation and update of Redux containers and PConnect.
|
|
26
|
+
* You may override Material components within this component if needed, but do not modify any container-related logic. Changing this logic can lead to unexpected behavior.
|
|
27
|
+
*/
|
|
29
28
|
|
|
30
|
-
const FORMTEMPLATES = ['OneColumn', 'TwoColumn', 'DefaultForm', 'WideNarrow', 'NarrowWide'];
|
|
29
|
+
const FORMTEMPLATES = ['OneColumn', 'TwoColumn', 'DefaultForm', 'WideNarrow', 'NarrowWide', 'HierarchicalForm'];
|
|
31
30
|
const NO_HEADER_TEMPLATES = [
|
|
32
31
|
'SubTabs',
|
|
33
32
|
'SimpleTable',
|
|
@@ -70,8 +70,9 @@ export default function CaseView(props: PropsWithChildren<CaseViewProps>) {
|
|
|
70
70
|
const editAction = availableActions.find(action => action.ID === 'pyUpdateCaseDetails');
|
|
71
71
|
|
|
72
72
|
const localizedVal = PCore.getLocaleUtils().getLocaleValue;
|
|
73
|
+
const localizationService = thePConn.getLocalizationService();
|
|
73
74
|
const localeCategory = 'CaseView';
|
|
74
|
-
|
|
75
|
+
|
|
75
76
|
/**
|
|
76
77
|
*
|
|
77
78
|
* @param inName the metadata <em>name</em> that will cause a region to be returned
|
|
@@ -214,7 +215,7 @@ export default function CaseView(props: PropsWithChildren<CaseViewProps>) {
|
|
|
214
215
|
className={classes.caseViewHeader}
|
|
215
216
|
title={
|
|
216
217
|
<Typography variant='h6' component='div' id='case-name'>
|
|
217
|
-
{
|
|
218
|
+
{localizationService.getLocalizedText(header)}
|
|
218
219
|
</Typography>
|
|
219
220
|
}
|
|
220
221
|
subheader={
|
|
@@ -14,6 +14,7 @@ interface FieldGroupTemplateProps extends PConnProps {
|
|
|
14
14
|
displayMode?: string;
|
|
15
15
|
fieldHeader?: string;
|
|
16
16
|
allowTableEdit: boolean;
|
|
17
|
+
allowActions?: any;
|
|
17
18
|
}
|
|
18
19
|
|
|
19
20
|
export default function FieldGroupTemplate(props: FieldGroupTemplateProps) {
|
|
@@ -30,6 +31,7 @@ export default function FieldGroupTemplate(props: FieldGroupTemplateProps) {
|
|
|
30
31
|
heading = '',
|
|
31
32
|
displayMode,
|
|
32
33
|
fieldHeader,
|
|
34
|
+
allowActions,
|
|
33
35
|
allowTableEdit: allowAddEdit
|
|
34
36
|
} = props;
|
|
35
37
|
const pConn = getPConnect();
|
|
@@ -39,6 +41,11 @@ export default function FieldGroupTemplate(props: FieldGroupTemplateProps) {
|
|
|
39
41
|
const isReadonlyMode = renderMode === 'ReadOnly' || displayMode === 'DISPLAY_ONLY';
|
|
40
42
|
const HEADING = heading ?? 'Row';
|
|
41
43
|
|
|
44
|
+
const hasAllowActions = Object.keys(allowActions ?? {}).length > 0;
|
|
45
|
+
const { allowAdd: actionAdd, allowDelete: actionDelete } = allowActions ?? {};
|
|
46
|
+
const allowAdd = hasAllowActions ? (actionAdd ?? true) : (allowAddEdit ?? true);
|
|
47
|
+
const allowDelete = hasAllowActions ? (actionDelete ?? true) : (allowAddEdit ?? true);
|
|
48
|
+
|
|
42
49
|
useLayoutEffect(() => {
|
|
43
50
|
if (!isReadonlyMode) {
|
|
44
51
|
// @ts-expect-error - Expected 3 arguments, but got 1
|
|
@@ -72,7 +79,7 @@ export default function FieldGroupTemplate(props: FieldGroupTemplateProps) {
|
|
|
72
79
|
pConn.getListActions().deleteEntry(index);
|
|
73
80
|
}
|
|
74
81
|
};
|
|
75
|
-
if (referenceList.length === 0 &&
|
|
82
|
+
if (referenceList.length === 0 && allowAdd) {
|
|
76
83
|
addFieldGroupItem();
|
|
77
84
|
}
|
|
78
85
|
|
|
@@ -87,8 +94,8 @@ export default function FieldGroupTemplate(props: FieldGroupTemplateProps) {
|
|
|
87
94
|
return (
|
|
88
95
|
<FieldGroupList
|
|
89
96
|
items={MemoisedChildren}
|
|
90
|
-
onAdd={
|
|
91
|
-
onDelete={
|
|
97
|
+
onAdd={allowAdd ? addFieldGroupItem : undefined}
|
|
98
|
+
onDelete={allowDelete ? deleteFieldGroupItem : undefined}
|
|
92
99
|
/>
|
|
93
100
|
);
|
|
94
101
|
}
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import { type PropsWithChildren } from 'react';
|
|
2
|
+
import { Tab, Tabs, Box, Badge, Tooltip } from '@mui/material';
|
|
3
|
+
import { TabContext, TabPanel } from '@mui/lab';
|
|
4
|
+
|
|
5
|
+
import { useHierarchicalForm, type HierarchicalFormProps } from './hooks';
|
|
6
|
+
|
|
7
|
+
export default function HierarchicalForm(props: PropsWithChildren<HierarchicalFormProps>) {
|
|
8
|
+
const { currentTabId, handleTabClick, processedTabs, instructions } = useHierarchicalForm(props);
|
|
9
|
+
|
|
10
|
+
if (!currentTabId) {
|
|
11
|
+
return null;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
return (
|
|
15
|
+
<Box display='flex' flexDirection='column'>
|
|
16
|
+
{instructions && (
|
|
17
|
+
<Box mb={2}>
|
|
18
|
+
<div dangerouslySetInnerHTML={{ __html: instructions }} />
|
|
19
|
+
</Box>
|
|
20
|
+
)}
|
|
21
|
+
<Box sx={{ flexGrow: 1 }}>
|
|
22
|
+
<TabContext value={currentTabId.toString()}>
|
|
23
|
+
<Box sx={{ borderBottom: 1, borderColor: 'divider' }}>
|
|
24
|
+
<Tabs onChange={handleTabClick} value={currentTabId.toString()} variant='scrollable'>
|
|
25
|
+
{processedTabs.map((tab: any) => {
|
|
26
|
+
const tabLabel = tab.name || tab.label;
|
|
27
|
+
return (
|
|
28
|
+
<Tab
|
|
29
|
+
key={tab.id}
|
|
30
|
+
sx={{ textTransform: 'none' }}
|
|
31
|
+
label={
|
|
32
|
+
tab.errors ? (
|
|
33
|
+
<Tooltip title={`${tabLabel} has errors`} placement='top'>
|
|
34
|
+
<Box sx={{ display: 'flex', alignItems: 'center', gap: 1 }}>
|
|
35
|
+
<span>{tabLabel}</span>
|
|
36
|
+
<Badge badgeContent={tab.errors} color='error' sx={{ '& .MuiBadge-badge': { position: 'static', transform: 'none' } }} />
|
|
37
|
+
</Box>
|
|
38
|
+
</Tooltip>
|
|
39
|
+
) : (
|
|
40
|
+
tabLabel
|
|
41
|
+
)
|
|
42
|
+
}
|
|
43
|
+
value={tab.id?.toString()}
|
|
44
|
+
/>
|
|
45
|
+
);
|
|
46
|
+
})}
|
|
47
|
+
</Tabs>
|
|
48
|
+
</Box>
|
|
49
|
+
{processedTabs.map((tab: any) => (
|
|
50
|
+
<TabPanel key={tab.id} value={tab.id?.toString()} tabIndex={+tab.id} keepMounted sx={{ px: 0 }}>
|
|
51
|
+
<div>{tab.content ? tab.content : 'No content exists'}</div>
|
|
52
|
+
</TabPanel>
|
|
53
|
+
))}
|
|
54
|
+
</TabContext>
|
|
55
|
+
</Box>
|
|
56
|
+
</Box>
|
|
57
|
+
);
|
|
58
|
+
}
|