Skip to content

Commit

Permalink
Merge pull request #46 from pegasystems/feature/dynamicform
Browse files Browse the repository at this point in the history
Add support for the new Dynamic Form component
  • Loading branch information
ricmars authored Apr 3, 2024
2 parents d915aad + 9ab43b2 commit 84dafd0
Show file tree
Hide file tree
Showing 13 changed files with 1,087 additions and 270 deletions.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
600 changes: 330 additions & 270 deletions package-lock.json

Large diffs are not rendered by default.

45 changes: 45 additions & 0 deletions src/components/Pega_Extensions_DynamicHierarchicalForm/Docs.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
import { Meta, Primary, Controls, Story } from '@storybook/blocks';
import * as DemoStories from './demo.stories';

<Meta of={DemoStories} />

# Overview

The DynamicHierarchicalForm template is designed for utilization within a form template. Its core function is to allow users to choose from a multitude of items available in a multi-select combobox. Each selected item correlates to a data object embedded within the case, exposing a series of input fields.

This component displays the form of every embedded object within a unique tab component. The tabs dynamically adjust their displays based on the items selected from the combobox.

The component is divided into two distinct regions:

- The 'Selection' region: This area should house a singular embedded data list of available items. This field serves to hold your chosen items list. Every selected item will be recognizable through a unique pyGUID, pyLabel, RuleClass and an IsSelected property.
- The 'Tabs' region: This is where all the embedded data fields should be placed, leading to the view that will be rendered for object. The RuleClass field from the item should match the class of the embedded data object.

The component also exposes an action that will trigger a refresh on the assignment - This action can be used to update parts of the assignment, for example provide a detailed quotation. It is also possible to hide this refresh action as well as the multi-select picklist.

<Primary />

## Props

<Controls />

## example

Assuming that you have a set of data objects that represent different types of insurance products and you want users to pick and configure them. Create a Products data object that exposes a pyLabel, IsSelected and RuleClass fields

![Product list](DynamicHierarchicalForm_Configuration_1.png)

Include in your case type each product as an embedded data object as well as create a embedded list object of products.

![Case type model](DynamicHierarchicalForm_Configuration_2.png)

Before rendering the widget, make sure to populate the products field with the pyLabel, pyGUID, RuleClass and IsSelected

![Products initialization](DynamicHierarchicalForm_Configuration_3.png)

In your assignment, use the component as a template and configure the different regions

![Template usage](DynamicHierarchicalForm_Configuration_4.png)

Here is how the component will render at runtime.

![Demo](DynamicHierarchicalForm_Configuration_Demo.png)
46 changes: 46 additions & 0 deletions src/components/Pega_Extensions_DynamicHierarchicalForm/config.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
{
"name": "Pega_Extensions_DynamicHierarchicalForm",
"label": "Dynamic Hierarchical Form",
"description": "Dynamic Hierarchical Form",
"organization": "Pega",
"version": "1.0.0",
"library": "Extensions",
"allowedApplications": [],
"componentKey": "Pega_Extensions_DynamicHierarchicalForm",
"type": "Template",
"subtype": "DETAILS",
"properties": [
{
"name": "refreshActionLabel",
"label": "Label of the Refresh Action button",
"format": "TEXT"
},
{
"name": "showRefreshAction",
"label": "Show refresh action",
"format": "BOOLEAN",
"defaultValue": true
},
{
"name": "enableItemSelection",
"label": "Show multi-select picker",
"format": "BOOLEAN",
"defaultValue": true
},
{
"name": "Selection",
"label": "Selection",
"format": "CONTENTPICKER",
"addTypeList": ["Fields"]
},
{
"name": "Tabs",
"label": "Tabs",
"format": "CONTENTPICKER",
"addTypeList": ["Fields"]
}
],
"defaultConfig": {
"refreshActionLabel": "Refresh details"
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,302 @@
import type { StoryObj } from '@storybook/react';
import PegaExtensionsDynamicHierarchicalForm from './index';
import { type DynamicHierarchicalFormProps } from './index';
import {
Checkbox,
CheckboxGroup,
Grid,
Input,
RadioButton,
RadioButtonGroup,
TextArea
} from '@pega/cosmos-react-core';
import type { ChangeEvent } from 'react';

type configInfo = {
values?: Array<any>;
value?: string;
componentType?: string;
pyGUID?: string;
authorContext?: string;
pyLabel?: string;
label?: string;
IsSelected?: boolean;
heading?: string;
inheritedProps?: Array<any>;
name?: string;
ruleClass?: string;
};

type info = {
config: configInfo;
type: string;
children?: Array<info>;
};

export default {
title: 'Templates/Dynamic Hierarchical Form',
argTypes: {
getPConnect: {
table: {
disable: true
}
}
},
parameters: {
a11y: {
element: '#storybook-root',
config: {
rules: [
{
id: 'nested-interactive',
enabled: false
}
]
}
}
},
component: PegaExtensionsDynamicHierarchicalForm
};

const genComponent = (config: any) => {
return config.config.text;
};

const setPCore = (numProducts: number) => {
const productsConfig: any[] = [];
for (let i = 1; i <= numProducts; i += 1) {
productsConfig.push({
pyLabel: `Product #${i}`,
pyGUID: `product${i}`,
IsSelected: true,
RuleClass: `Class-Product-${i}` /* The classID must match the ruleClass from the embedded obj */
});
}

(window as any).PCore = {
createPConnect: () => ({
getPConnect: () => ({
createComponent: (meta: any) => {
return (
<Grid
container={{ gap: 1, cols: `repeat(1, minmax(0, 1fr))` }}
style={{ maxWidth: '80ch' }}
>
{Math.random() < 0.8 ? (
<Input name={`${meta.config.name}field1`} label='Field1' />
) : null}
{Math.random() < 0.8 ? (
<Input name={`${meta.config.name}field2`} label='Field2' />
) : null}
{Math.random() < 0.8 ? (
<TextArea name={`${meta.config.name}field3`} label='Field3' />
) : null}
{Math.random() < 0.8 ? (
<Input name={`${meta.config.name}field4`} label='Field4' />
) : null}
{Math.random() < 0.8 ? (
<Input name={`${meta.config.name}field5`} label='Field5' />
) : null}
{Math.random() < 0.8 ? (
<CheckboxGroup name={`${meta.config.name}options`} label='Options'>
{['Option1', 'Option2', 'Option3'].map(option => (
<Checkbox key={option} label={option} value={option} />
))}
</CheckboxGroup>
) : null}
{Math.random() < 0.8 ? (
<RadioButtonGroup name={`${meta.config.name}choice`} label='Choice'>
{['Yes', 'No'].map(option => (
<RadioButton key={option} label={option} value={option} />
))}
</RadioButtonGroup>
) : null}
</Grid>
);
},
getActionsApi: () => {
return {
updateFieldValue: (prop: string, value: string) => {}
};
}
})
}),
getComponentsRegistry: () => {
return {
getLazyComponent: (f: string) => f
};
},
getViewResources: () => {
return {
fetchViewResources: (name: string) => {
return {
config: {
name
}
};
},
updateViewResources: () => {}
};
},
getStore: () => {
return {
getState: () => {
return {
data: {
primary: {
caseInfo: {
content: {
Products: productsConfig
}
}
}
}
};
},
dispatch: () => {}
};
}
};
};

const genResponse = (numProducts: number) => {
const demoView = {
name: 'demoView',
type: 'View',
config: {
template: 'Pega_Extensions_DynamicHierarchicalForm',
ruleClass: 'Work-',
inheritedProps: []
},
children: [
{
name: 'Selection',
type: 'Region',
children: [] as Array<info>,
getPConnect: () => {}
},
{
name: 'Tabs',
type: 'Region',
children: [] as Array<info>,
getPConnect: () => {}
}
],
classID: 'Work-MyComponents'
};

demoView.children[0].children = [
{
config: {
authorContext: '.Products',
inheritedProps: [{ prop: 'label', value: 'Products' }]
},
type: 'reference'
}
];

const productsConfig = [];
for (let i = 1; i <= numProducts; i += 1) {
productsConfig.push({
config: {
name: `Product #${i}`,
ruleClass: `Class-Product-${i}`,
inheritedProps: [{ value: `Product #${i}` }]
},
type: 'reference'
});
}

demoView.children[1].children = productsConfig;
demoView.children[0].getPConnect = () => {
return {
getRawMetadata: () => {
return demoView.children[0];
}
};
};
demoView.children[1].getPConnect = () => {
return {
getRawMetadata: () => {
return demoView.children[1];
}
};
};
return demoView;
};

interface DynamicHierarchicalFormPropsExt extends DynamicHierarchicalFormProps {
numProducts: number;
}
type Story = StoryObj<DynamicHierarchicalFormPropsExt>;
export const Default: Story = {
render: (args: any) => {
const response = genResponse(args.numProducts);
setPCore(args.numProducts);
const props = {
template: 'DynamicTabs',
...args,
getPConnect: () => {
return {
getListActions: () => {
return {
update: () => {}
};
},
getCaseInfo: () => {
return {
getKey: () => 'S-123',
getCurrentAssignmentViewName: () => 'Enter info'
};
},
getActionsApi: () => {
return {
updateFieldValue: (prop: string, value: string) => {},
refreshCaseView: () => {
alert('Refresh UI');
}
};
},
getChildren: () => {
return response.children;
},
getRawMetadata: () => {
return response;
},
getInheritedProps: () => {
return response.config.inheritedProps;
},
getContextName: () => {
return 'primary';
},
getTarget: () => {
return 'caseInfo';
},
createComponent: (config: any) => {
return genComponent(config);
},
setInheritedProp: () => {
/* nothing */
},
setValue: () => {
/* nothing */
},
resolveConfigProps: (f: any) => {
return f;
}
};
}
};
return (
<PegaExtensionsDynamicHierarchicalForm {...props}></PegaExtensionsDynamicHierarchicalForm>
);
},
args: {
label: 'Select your products',
showLabel: true,
refreshActionLabel: 'Refresh product',
showRefreshAction: true,
enableItemSelection: true,
numProducts: 3
}
};
Loading

0 comments on commit 84dafd0

Please sign in to comment.