---
name: create-ui-page
description: >
    Use when creating or modifying .userinterface.xml files for CG Mobile modeler screens.
    Trigger phrases: "UI for X", "screen for X", "page for X", ".userinterface.xml",
    "form for X", "dialog for X", "list screen for X", "detail screen for X".
    Invokes create-business-object or create-list-object first if the target BO/LO does not exist.
    NOT for cockpit cards (use add-cockpit-card) — cockpit card layout is handled separately.
---

# Create UI Page — CG Mobile Modeler

A `.userinterface.xml` file describes a single screen (page): its layout, form controls, data
bindings to ProcessContext variables, and user interaction events that trigger process transitions.
Every UI file lives co-located with the process that drives it in `src/<Module>/PR/<FlowName>/`.

## When to Use This Skill

| Invoked by      | Phrase                                                                                       |
| --------------- | -------------------------------------------------------------------------------------------- |
| User directly   | "UI for X", "screen for X", "page for X", ".userinterface.xml", "dialog for X", "form for X" |
| Workflow skills | `add-detail-screen` (for the backing BO detail UI), `add-list-screen` (for the list UI)      |

NOT for:

-   Cockpit card layouts — use `add-cockpit-card`
-   Build errors in an existing UI — use `build-and-simulate`
-   Process flow logic — use `create-process`

---

## Prerequisites

1. **Confirm the BO or LO being bound to exists.** If not, invoke `create-business-object` or `create-list-object` first and return here after it completes.

2. **Confirm the sibling process exists or will be created.** The UI does not drive itself — a `.processflow.xml` must declare the ProcessContext variables the UI binds to, and must handle the events the UI fires. If the process does not exist, invoke `create-process` after writing the UI (or in tandem).

3. **Identify all ProcessContext variable names.** Every `binding="ProcessContext::<VarName>.<prop>"` path must resolve to a variable declared in the process. Mismatched names cause blank fields at runtime with no build error.

---

## Mandatory Checklist

-   [ ] `UIDescription` `name` follows `<Module>::<FlowName>UI` pattern (e.g., `Visit::RescheduleUI`)
-   [ ] File lives in `src/<Module>/PR/<FlowName>/<FlowName>UI.userinterface.xml` — co-located with process (NOT in a `UI/` subfolder)
-   [ ] `schemaVersion="0.0.0.5"` on the root `UIDescription` element
-   [ ] Every `<Binding target="Value" ...>` points to an existing ProcessContext declaration in the sibling process
-   [ ] Every `<Resource>` label has a non-empty `id` and non-empty `defaultLabel`
-   [ ] Every `<ButtonPressedEvent event="X" />` name matches an `<Action name="X">` in the sibling `.processflow.xml`
-   [ ] List control `dataSource` paths end in `.Items[]` with **capital I**

---

## Failure Modes

### Failure mode 1: Screen renders but fields are blank

**Symptom:** Page loads, controls appear, but every field shows empty/undefined. No build error.
**Diagnosis:** `binding="ProcessContext::<VarName>.<prop>"` references a ProcessContext variable or
property name that does not exist or is spelled differently from the process declaration.
**Fix:** Open the sibling `.processflow.xml`, find the `<Declarations>` block, and verify each
`ProcessContext::` path exactly matches a declared variable name. Check case — `BoVisit` vs `boVisit`
will fail silently.

```xml
<!-- WRONG — "rescheduleVisitBo" vs actual declaration "RescheduleVisitBo" -->
<Binding target="Value" binding="ProcessContext::rescheduleVisitBo.dateFrom" ... />

<!-- CORRECT -->
<Binding target="Value" binding="ProcessContext::RescheduleVisitBo.dateFrom" ... />
```

---

### Failure mode 2: Button does nothing

**Symptom:** The user taps a button, nothing happens. No error in devtools console.
**Diagnosis:** `<ButtonPressedEvent event="X" />` fires event `X`, but no action with that name
exists in the sibling `.processflow.xml`. The process simply ignores unrecognized event names.
**Fix:** Open the sibling process file. Find or add `<Action name="X" type="TRANSITIONTO" ...>`.
The event name in the UI and the action name in the process must match exactly.

```xml
<!-- UI fires this event -->
<ButtonPressedEvent event="rescheduleVisit" />

<!-- Process must have a matching action -->
<Action name="rescheduleVisit" type="TRANSITIONTO" target="SaveState" />
```

---

### Failure mode 3: Label shows raw id string instead of text

**Symptom:** A field label or button text shows something like `"rescheduleVisitId"` instead of
the expected human text. No build error.
**Diagnosis:** The `<Resource>` element is missing `defaultLabel`, or `defaultLabel=""` (empty).
The localization system falls back to the raw `id` when no label resource is registered and
`defaultLabel` is absent.
**Fix:** Ensure every label Resource has both a non-empty `id` **and** a non-empty `defaultLabel`:

```xml
<!-- WRONG — empty defaultLabel -->
<Resource target="Text" type="Label" id="doneButtonId" defaultLabel="" />

<!-- CORRECT -->
<Resource target="Text" type="Label" id="doneButtonId" defaultLabel="Done" />
```

---

### Failure mode 4: Two-way binding doesn't save

**Symptom:** User edits a field and taps "Done", but the saved record shows the old value.
**Diagnosis:** Either (a) the BO property has no `dataSourceProperty` so changes aren't persisted
to the DS, or (b) the DS has no `editableEntity` so the platform has no write target.
**Fix (a):** Verify the BO's `<SimpleProperty>` has `dataSourceProperty="<dsAttrName>"`.
**Fix (b):** Run `create-datasource` and confirm `editableEntity="<TableName>"` is set.
Both conditions must be true. See the `create-business-object` skill for full lifecycle guidance.

---

### Failure mode 5: Page crashes with "Missing child element" or schema error

**Symptom:** `sf mdl build` fails with a schema validation error referencing the UI file. The
error message often says "missing child element" or "unknown element".
**Diagnosis:** Common causes:

-   `<Items>` is missing inside a `GroupedList` (items placed directly inside the list)
-   `areaPattern` value is wrong for the children placed inside (e.g., using `GroupedElementsArea`
    but placing a `GroupedList` — a list control needs `SingleElementArea`)
-   `pagePattern` has a typo (only 5 valid values — see `references/page-patterns.md`)
    **Fix:** Cross-check the element hierarchy against the templates. A `GroupedList` must be inside
    a `SingleElementArea`; form controls must be inside a `GroupedElementsArea`. A list control's
    items must be inside `<Items name="Items">`, not directly inside the list element.

---

### Failure mode 6: List shows empty with `.items[]` (lowercase)

**Symptom:** A `GroupedList` or similar list control renders no rows even though the LO has data.
**Diagnosis:** `dataSource="ProcessContext::MyList.items[]"` uses lowercase `i`. The platform
requires capital `I` in `.Items[]`.
**Fix:**

```xml
<!-- WRONG -->
dataSource="ProcessContext::OverviewList.items[]"

<!-- CORRECT -->
dataSource="ProcessContext::OverviewList.Items[]"
```

---

## Minimal Template (inline)

Based on `src/Visit/PR/Visit_Reschedule/Visit_RescheduleUI.userinterface.xml`:

```xml
<UIDescription name="Visit::RescheduleUI" schemaVersion="0.0.0.5">
  <Page pagePattern="SingleSectionDialogPage" onBackDiscard="true">
    <PageHeader>
      <Bindings>
        <Resource target="title" type="Label" id="VisitRescheduleId" defaultLabel="Reschedule" />
      </Bindings>
      <MenuItems>
        <MenuItem directlyVisible="true" itemId="rescheduleVisit">
          <Bindings>
            <Resource target="Text" type="Label" id="rescheduleVisitId" defaultLabel="Done" />
            <Resource target="Icon" type="Image" id="CheckGrey24" defaultImage="light/done_24.png" />
          </Bindings>
          <Events>
            <ButtonPressedEvent event="rescheduleVisit" />
          </Events>
        </MenuItem>
      </MenuItems>
    </PageHeader>
    <Section sectionName="masterSection" sectionPattern="SingleAreaSection">
      <Area areaName="mainArea" areaPattern="GroupedElementsArea">
        <GroupElement name="VisitInfoGroup">
          <Bindings>
            <Resource target="Title" type="Label" id="VisitInformation" defaultLabel=" " />
          </Bindings>
          <InputArea name="FieldName">
            <Bindings>
              <Resource target="Label" type="Label" id="FieldNameLabelId" defaultLabel="Field Label" />
              <Binding target="Value" binding="ProcessContext::RescheduleVisitBo.fieldName"
                       bindingMode="TWO_WAY" />
            </Bindings>
          </InputArea>
        </GroupElement>
      </Area>
    </Section>
  </Page>
</UIDescription>
```

Full templates in `templates/`.

---

## Common Variants

### Variant 1 — Dialog (modal input form)

Use when: a process step collects structured input from the user in a modal overlay.

Template: `templates/dialog-page.userinterface.xml.template`

Pattern: `SingleSectionDialogPage` + `onBackDiscard="true"` + one `SingleAreaSection` + one or
more `GroupedElementsArea` `GroupElement` blocks with form controls.

Real file: `src/Visit/PR/Visit_Reschedule/Visit_RescheduleUI.userinterface.xml`

Key notes:

-   `directlyVisible="true"` on the "Done" `MenuItem` places it in the header bar.
-   The event name on `<ButtonPressedEvent>` must match the transition action in the process.
-   Use `<Merger pattern="twoInputControls">` to combine date + time pickers side-by-side.

---

### Variant 2 — List overview page

Use when: a full-screen page displays a list of records from an LO (orders list, visits for a
customer, task list).

Template: `templates/list-page.userinterface.xml.template`

Pattern: `SingleSectionPage` + `SingleAreaSection` + `SingleElementArea` + `GroupedList`.

Real file: `src/Order/PR/Order_Overview/Order_Overview.userinterface.xml`

Key notes:

-   `dataSource="ProcessContext::<LoVarName>.Items[]"` — capital I is required.
-   `<Items name="Items">` must wrap the layout and bindings — no items outside that tag.
-   Define `<Default>`, `<Tablet>`, and `<Phone>` layouts inside `<ItemListLayout>` for responsive rendering.
-   `<ItemSelectedEvent>` passes `.pKey` (and any other needed params) to the process.

---

### Variant 3 — Detail / edit form

Use when: a full-screen page displays and optionally edits the properties of a single BO.

Template: `templates/detail-page.userinterface.xml.template`

Pattern: `SingleSectionPage` + `SingleAreaSection` + `GroupedElementsArea` + multiple `GroupElement`
sections.

Real file: `src/Visit/PR/visit_Details/visit_DetailsUI.userinterface.xml`

Key notes:

-   Read-only fields use `disabled="true"` + `bindingMode="ONE_WAY"`.
-   Editable fields use `bindingMode="TWO_WAY"`.
-   A "Save" `MenuItem` fires an event that the process handles with a SAVE action.
-   Multiple `GroupElement` sections organise fields logically (e.g., "Basic Info", "Notes").

---

### Variant 4 — Tabbed detail page

Use when: a detail page has multiple tabs (e.g., Details | Items | Notes).

Pattern: `SingleSectionPage` + `sectionPattern="TabbedViewAreaSection"` + `TabElementArea` +
multiple `MultiArea` panes.

See `ai-wiki/wiki/user-interface.md` for the full `TabbedViewAreaSection` template.

Real file: `src/Order/PR/Order_HeaderTab/Order_HeaderTab.userinterface.xml` (multi-tab order view).

---

## Decision Table

| User wants...                          | Template         | `pagePattern`                                 | Area pattern                   |
| -------------------------------------- | ---------------- | --------------------------------------------- | ------------------------------ |
| Modal dialog to collect inputs         | `dialog-page`    | `SingleSectionDialogPage`                     | `GroupedElementsArea`          |
| Full-screen list of records            | `list-page`      | `SingleSectionPage`                           | `SingleElementArea`            |
| Read/edit detail view (single BO)      | `detail-page`    | `SingleSectionPage`                           | `GroupedElementsArea`          |
| Tabbed detail (multiple content panes) | custom from wiki | `SingleSectionPage` + `TabbedViewAreaSection` | `TabElementArea` + `MultiArea` |

---

## File and Folder Layout

```
src/<Module>/
└── PR/
    └── <FlowName>/
        ├── <Module>_<FlowName>Process.processflow.xml   ← sibling process
        └── <Module>_<FlowName>UI.userinterface.xml      ← this file
```

The UI file and its process always share the same `PR/<FlowName>/` folder. The naming convention
is `<Module>_<FlowName>UI.userinterface.xml`. See `_shared/naming.md`.

---

## Real File Reference (Visit_RescheduleUI full annotated)

```
src/Visit/PR/Visit_Reschedule/Visit_RescheduleUI.userinterface.xml
```

Structure summary:

-   Root: `<UIDescription name="Visit::RescheduleUI" schemaVersion="0.0.0.5">`
-   Page: `SingleSectionDialogPage` with `onBackDiscard="true"`
-   PageHeader: static title "Reschedule" + one "Done" button firing `rescheduleVisit` event
-   Section: `SingleAreaSection` → Area: `GroupedElementsArea` → GroupElement `VisitInfoGroup`
-   Controls: two `<Merger>` elements (start date+time, end date+time), one `<InputArea>` (duration)
-   All fields bound to `ProcessContext::RescheduleVisitBo.*` with `bindingMode="TWO_WAY"`

---

## Escape Hatch

When the above isn't enough, consult in order:

1. `references/page-patterns.md` — all valid `pagePattern` values, `Section`/`Area` patterns, `PageHeader` shape
2. `references/form-controls.md` — every control type with required bindings and real examples
3. `references/bindings-and-events.md` — `Resource` vs `Binding`, event wiring, `ItemSelectedEvent` params, `ContextOpeningEvent`
4. `ai-wiki/wiki/user-interface.md` — full 485-line wiki covering lists, cockpit, layout system, `CalendarControl`

Real-file anchors:

-   Dialog: `src/Visit/PR/Visit_Reschedule/Visit_RescheduleUI.userinterface.xml`
-   Flyout with list: `src/Workflow/PR/Workflow_NextStateByTypeFlyout/Workflow_NextStatesFlyoutUI.userinterface.xml`
-   List overview: `src/Order/PR/Order_Overview/Order_Overview.userinterface.xml`
-   Detail form: `src/Visit/PR/visit_Details/visit_DetailsUI.userinterface.xml`
-   Cockpit: `src/Visit/PR/Visit_RetailStoreCockpit/Visit_RetailStoreCockpitUI.userinterface.xml`

---

## Verify

After writing the UI file, run a build:

```bash
# cd to your workspace root
sf mdl build 2>&1 | tail -20
```

Then load the owning process in the simulator and exercise every control:

```bash
sf mdl simulate
# Open the screen that triggers this process/UI
# Check: all field labels show human text (not raw ids)
# Check: editable fields accept input
# Check: buttons trigger the expected process transitions
# Check: list rows appear with populated columns
# Open devtools Console: look for "undefined" in binding logs or "is not a function" errors
```

A clean build and a fully-populated screen with all buttons responsive confirms the UI is correctly wired.
