Skip to content

Latest commit

 

History

History
368 lines (294 loc) · 29.8 KB

File metadata and controls

368 lines (294 loc) · 29.8 KB

Component Build & Documentation Guide

Welcome to the Confluence of the Constellation UI Gallery – this file is the one‑stop reference for anyone who wants to add a new Pega extension component to the gallery or understand the structure of an existing one.


1️⃣ Quick Overview – List of Existing Components

Status legend: blank = actively maintained in the gallery · Deprecated = still available, prefer OOB alternative · Limited = supported only for narrow / partial use cases

Component Short Description Status Notes / reason Docs Launchpad Support
Pega_Extensions_ActionableButton A button that can trigger Pega actions or workflows. Docs Yes
Pega_Extensions_Banner Displays a banner message, typically for notifications or alerts. Docs No
Pega_Extensions_BannerInput Combines a banner with an input field for quick data entry. Deprecated Prefer instruction-text banners in Pega '26 Docs Yes
Pega_Extensions_BarCode Generates and scans barcodes. Docs No
Pega_Extensions_Calendar Calendar view for selecting dates, with support for events. Docs Yes
Pega_Extensions_CameraCapture Lets users take photos using their device camera and save them directly as case attachments. Docs No
Pega_Extensions_CardGallery Displays items in a card‑style gallery layout. Deprecated Prefer Insight-based gallery templates in Pega '26 Docs In Progress
Pega_Extensions_CaseLauncher Launches Pega cases or tasks from the UI. Docs Yes
Pega_Extensions_CaseReference References a Pega case, showing key details. Limited Prefer OOB Case Reference except for current-case / custom-ID preview use cases Docs Yes
Pega_Extensions_ChatGenAI Integrates generative AI chat into the application. Deprecated Prefer Pega Platform agent functionality Docs No
Pega_Extensions_CheckboxRow A row of checkboxes with optional triggers. Docs No
Pega_Extensions_CheckboxTrigger Checkbox that triggers actions on change. Docs No
Pega_Extensions_CompareTableLayout Displays data in a comparison table format. Docs No
Pega_Extensions_CPQTree Reads the CPQ Tree structure and displays it in Constellation. Limited Read-only; not full CPQ application support Docs No
Pega_Extensions_CustomKPIGauge Gauge widget for a single numeric value from a data page, with zones, target, and legend. Docs Yes
Pega_Extensions_DisplayAttachments Renders file attachments with download links. Docs No
Pega_Extensions_DisplayBrackets Displays tournament brackets from a JSON structure. Docs In Progress
Pega_Extensions_DisplayPDF Shows PDF documents inline. Docs Yes
Pega_Extensions_DynamicHierarchicalForm Dynamically builds a hierarchical form based on data. Docs No
Pega_Extensions_EditableTableLayout Table layout with inline editing capabilities. Docs No
Pega_Extensions_FieldGroupAsRow Groups multiple fields into a single row layout. Docs No
Pega_Extensions_FormFullWidth Expands a form to full width of container. Docs Yes
Pega_Extensions_FormWithVerticalStepper Vertical Screen flow with navigation Docs No
Pega_Extensions_GanttChart Visualizes tasks or events in a Gantt chart. Docs No
Pega_Extensions_HierarchicalFormAsTasks Presents hierarchical forms in a task‑list style. Docs No
Pega_Extensions_IframeWrapper Embeds external content within an iframe. Docs No
Pega_Extensions_ImageCarousel Carousel for images with navigation controls. Docs No
Pega_Extensions_ImageMagnify Magnifies images on hover or click. Docs No
Pega_Extensions_JawLayout Displays an interactive jaw like structure. Docs No
Pega_Extensions_KanbanBoard Kanban board layout for task management. Docs In Progress
Pega_Extensions_LangSwitch Language and timezone preference panel. Deprecated Prefer language switch via the operator menu in Pega '26 Docs No
Pega_Extensions_Map Displays maps with markers and overlays. Docs No
Pega_Extensions_MarkdownInput Text area that supports Markdown formatting. Docs No
Pega_Extensions_MaskedInput Input field with masking (e.g., phone, SSN). Deprecated Prefer OOB formatted inputs on form fields in Pega '26 Docs Yes
Pega_Extensions_Meter Visual meter for displaying progress or value ranges. Docs No
Pega_Extensions_NetworkDiagram Graphical network diagram with nodes and links. Docs In Progress
Pega_Extensions_OAuthConnect Handles OAuth authentication flows. Docs No
Pega_Extensions_PasswordInput Secure password input with strength indicator. Docs Yes
Pega_Extensions_QRCode Generates and scans QR codes. Docs No
Pega_Extensions_RangeSlider Slider for selecting a numeric range. Docs No
Pega_Extensions_RatingLayout Star or numeric rating component. Docs No
Pega_Extensions_Scheduler Scheduling UI for events and appointments. Docs No
Pega_Extensions_Shortcuts Provides keyboard shortcuts for quick actions. Deprecated Prefer the OOB Shortcuts widget in Pega '26 Docs In Progress
Pega_Extensions_SignatureCapture Capture user signatures via touch or mouse. Deprecated Prefer paragraph field as signature in Pega 26.1.2 Docs Yes
Pega_Extensions_StarRatingInput Input for star‑based ratings. Docs Yes
Pega_Extensions_StatusBadge Badge showing status with color coding. Deprecated Prefer formatting a text field as status in an Insight Docs Yes
Pega_Extensions_TaskList Displays a list of tasks with actions. Docs No
Pega_Extensions_TrendDisplay Shows trends over time (charts, graphs). Docs No
Pega_Extensions_UtilityList Generic list component for utilities. Docs In Progress
shared Shared utilities and hooks used by multiple components. N/A N/A

2️⃣ Folder Layout & Naming Convention

Every component lives in its own folder under src/components and follows the Pega_Extensions_<ComponentName> pattern. The folder typically contains:

  • Docs.mdx – Markdown + JSX documentation.
  • config.json – Pega metadata used by Designer.
  • demo.stories.tsx – Storybook demo.
  • demo.test.tsx – Jest + React‑Testing‑Library tests.
  • index.tsx – The React component.
  • styles.ts – Optional styled‑components.
  • localizations.json – (optional) i18n strings.
  • shared/create-nonce – Imported to secure script tags.
  • ../shared/utils – getMappedKey for Platform/Launchpad key and rule-name mapping (import whenever you touch property names, data pages, or local actions).

Tip: The folder name must match the name and componentKey fields in config.json.

Launchpad: See LAUNCHPAD_VS_PLATFORM.md before wiring PCore data or actions.


3️⃣ config.json – Pega Blueprint

Key Meaning Typical Value Notes
name Unique identifier "Pega_Extensions_<Name>" Must match folder name
label UI label shown in Designer "<Human readable label>"
description Short description "<Short description>"
organization Owning org "Pega"
version Semantic version "4.0.0"
library Library name "Lib"
allowedApplications Array of Pega apps that can use the component []
componentKey Same as name "Pega_Extensions_<Name>"
type Component type (Field, Template, etc.) "Field"
subtype Sub‑type (e.g., Text, DETAILS) "Text"
properties Array of property objects that describe the UI fields exposed to Designer See component‑specific examples Each object includes name, label, format, and optional defaultValue, source, etc.
defaultConfig Default prop values that Pega will use {"label": "@L $this.label"} Optional
buildDate ISO timestamp of the last build "2025-09-29T17:46:21.831Z"
infinityVersion Pega Infinity version "25.1.0-95"
packageCosmosVersion Cosmos version "8.4.1"

Tip: Keep config.json in sync with the component’s index.tsx – the properties array is what Designer will expose to the user.


4️⃣ index.tsx – The Component Skeleton

import { withConfiguration, Flex, FormControl, FormField, Text } from '@pega/cosmos-react-core';
import { useEffect, useState } from 'react';
import StyledWrapper from './styles';
import '../shared/create-nonce';
import { getMappedKey } from '../shared/utils';

export enum MyComponentProps {/* Define any enum‑style props if needed */}

type MyComponentExtProps = {
  /* Custom props that will be exposed to Designer */
  label: string;
  value: string;
  dataPage?: string;
  getPConnect: () => typeof PConnect;
  readOnly?: boolean;
  testId?: string;
};

export const PegaExtensionsMyComponent = (props: MyComponentExtProps) => {
  const { label, value, dataPage, getPConnect, readOnly, testId } = props;
  const pConn = getPConnect();
  const actions = pConn.getActionsApi();
  const [internal, setInternal] = useState(value);

  useEffect(() => {
    if (!readOnly) {
      // Prefer mapped property names when writing back to the case
      actions.updateFieldValue('.' + getMappedKey('myField'), internal);
    }
  }, [internal, readOnly, actions]);

  useEffect(() => {
    if (!dataPage) return;
    const caseId = pConn.getValue(PCore.getConstants().CASE_INFO.CASE_INFO_ID);
    const payload = {
      dataViewParameters: { [getMappedKey('pyID')]: caseId },
    };
    PCore.getDataApiUtils()
      .getData(getMappedKey(dataPage), payload, pConn.getContextName())
      .then((response: any) => {
        /* map response rows with getMappedKey('pyLabel'), etc. */
      });
  }, [dataPage, getPConnect, pConn]);

  return (
    <Flex container={{ direction: 'column' }}>
      <FormField label={label} testId={testId}>
        <FormControl>{readOnly ? <Text>{internal}</Text> : <StyledWrapper>{/* UI */}</StyledWrapper>}</FormControl>
      </FormField>
    </Flex>
  );
};

export default withConfiguration(PegaExtensionsMyComponent);

Dual-environment (Platform + Launchpad) rules

Gallery components should run on Pega Platform and Launchpad. When you touch data, case identity, actions, or rule names:

  1. Import and use getMappedKey from ../shared/utils for property names, data-page names, and local-action / flow-type names.
  2. Read the current case id via PCore.getConstants().CASE_INFO.CASE_INFO_ID — not hard-coded pyID or caseInfo.businessID.
  3. Navigate with getActionsApi() and PCore.getSemanticUrlUtils() — never hand-build URLs.
  4. Before calling Platform-only DX REST APIs (for example getDataObjectView / readDataObject), check PCore.getRestClient().doesRestApiExist('…') and provide a fallback, or mark the component as not Launchpad-supported.
  5. Do not branch on isLaunchpad; prefer key mapping and capability detection.

Full details, examples, and Storybook stub requirements: LAUNCHPAD_VS_PLATFORM.md.


5️⃣ styles.ts – Optional Styled‑Components

import styled from 'styled-components';

const StyledWrapper = styled.div`
  /* Example styles */
  display: flex;
  align-items: center;
`;

export default StyledWrapper;

6️⃣ Docs.mdx – Documentation for Designers

import { Meta, Canvas, ArgsTable } from '@storybook/addon-docs';

<Meta title='Fields/MyComponent' />

# MyComponent

This component renders a custom UI and synchronizes with Pega state.

## Props

<ArgsTable story='Primary' />

## Demo

<Canvas>
  <Story name='Primary' />
</Canvas>

7️⃣ demo.stories.tsx – Storybook Story

import type { StoryObj } from '@storybook/react-webpack5';
import { PegaExtensionsMyComponent, type PegaExtensionsMyComponentProps } from './index';

export default {
  title: 'Fields/MyComponent',
  argTypes: {
    getPConnect: { table: { disable: true } },
  },
  component: PegaExtensionsMyComponent,
} as const;

const Template: StoryObj<PegaExtensionsMyComponentProps> = (args) => {
  const props = {
    getPConnect: () =>
      ({
        getActionsApi: () => ({ updateFieldValue: () => {}, openWorkByHandle: () => {} }),
        getContextName: () => 'app/primary_1',
        getValue: () => 'CASE-1',
        getLocalizedValue: (v: string) => v,
      }) as unknown as typeof PConnect,
    ...args,
  };
  return <PegaExtensionsMyComponent {...props} />;
};

export const Primary = Template.bind({});
Primary.args = {
  label: 'Demo Label',
  value: 'Initial value',
};

window.PCore = {
  ...window.PCore,
  getConstants: () => ({ CASE_INFO: { CASE_INFO_ID: 'ID' } }),
  getNameSpaceUtils: () => ({
    getDefaultQualifiedName: (name: string) => name,
  }),
  getEnvironmentInfo: () => ({
    getKeyMapping: (key: string) => key,
  }),
  getRestClient: () => ({
    doesRestApiExist: () => true,
  }),
  getDataApiUtils: () => ({
    getData: () => Promise.resolve({ data: { data: [] } }),
  }),
  getSemanticUrlUtils: () => ({
    getActions: () => ({ ACTION_OPENWORKBYHANDLE: 'openWorkByHandle' }),
    getResolvedSemanticURL: () => '',
  }),
} as unknown as typeof PCore;

Typing: PCore / PConnect types come from @pega/pcore-pconnect-typedefs (ambient globals in src/pega-globals.d.ts). Use getPConnect: () => typeof PConnect and bare PCore.*. Cast incomplete Storybook mocks with as unknown as typeof PCore / as unknown as typeof PConnect.

Launchpad: If the component uses getMappedKey, always stub getNameSpaceUtils and getEnvironmentInfo().getKeyMapping. If it gates optional APIs, stub getRestClient().doesRestApiExist. See LAUNCHPAD_VS_PLATFORM.md §8.


8️⃣ demo.test.tsx – Jest + React‑Testing‑Library

import { render, screen } from '@testing-library/react';
import { PegaExtensionsMyComponent } from './index';

const mockPConnect = {
  getActionsApi: () => ({ updateFieldValue: jest.fn() }),
  getStateProps: () => ({ value: 'myField' }),
  getValue: jest.fn(),
};

beforeAll(() => {
  window.PCore = {
    getNameSpaceUtils: () => ({ getDefaultQualifiedName: (n: string) => n }),
    getEnvironmentInfo: () => ({ getKeyMapping: (k: string) => k }),
    getConstants: () => ({ CASE_INFO: { CASE_INFO_ID: 'ID' } }),
  } as unknown as typeof PCore;
});

test('renders label and value', () => {
  render(
    <PegaExtensionsMyComponent
      label='Test'
      value='Hello'
      getPConnect={() => mockPConnect as unknown as typeof PConnect}
    />,
  );
  expect(screen.getByText('Test')).toBeInTheDocument();
  expect(screen.getByText('Hello')).toBeInTheDocument();
});

9️⃣ localizations.json – Optional i18n

{
  "en": {
    "myLabel": "My Label"
  },
  "es": {
    "myLabel": "Mi Etiqueta"
  }
}

🔧 Build, Test & Deploy

# Format and lint
npm run lint

# Type‑check
npm run typecheck

# Run tests
npm test

# Build component bundle
npm run build

# Start Storybook
npm run storybook

📚 Further Reading


Happy building!