# Editor Page



The editor is the step-by-step page users fill in to build a quote or transaction. There is one editor per product, under `pages.editor`. It serves quotes and every transaction type. Express the differences between them with [scope](/configuration/configurable-ui/scope-and-access#scope) on steps, sections, workflows, and journeys, rather than duplicating the editor.

An editor is built from steps, grouped into workflows. Journeys then choose which workflows a quote or transaction goes through. This skeleton, from `uiConfigs/operationsWorkbench/products/HO3/config.json`, shows how they nest:

```json
{
	"pages": {
		"editor": {
			"journeys": [{ "workflows": ["submission"] }],
			"workflows": {
				"submission": {
					"display": { "label": "Submission" },
					"steps": [
						{
							"name": "Submission Details",
							"sections": [
								{ "title": "Details", "include": ["data.policyType"] }
							],
							"buttons": [
								{
									"title": "Continue",
									"type": "next",
									"actions": ["validateForm", "save"]
								}
							]
						}
					]
				}
			}
		}
	}
}
```

For a complete starting editor, see [Starting Editor for Any Product](#starting-editor-for-any-product).

Starting Editor for Any Product [#starting-editor-for-any-product]

A product needs only an editor that lists the fields on each step; every other page keeps the platform's default, and every label, input, and format is deduced (see [Defaults](/configuration/configurable-ui/overview#defaults)). This starting editor has two workflows: a data-entry workflow that collects the product's fields, and a lifecycle workflow of read-only result steps. For a homeowners product, shortened:

```json
{
	"display": { "label": "Homeowners HO3" },
	"pages": {
		"editor": {
			"journeys": [{ "workflows": ["default", "lifecycle"] }],
			"workflows": {
				"default": {
					"steps": [
						{
							"name": "Application Details",
							"sections": [
								{
									"hideTitle": true,
									"include": [
										"startTime",
										"endTime",
										"expirationTime",
										"currency",
										"timezone"
									]
								},
								{
									"title": "Details",
									"include": [
										"data.expireIn",
										"data.directBusiness",
										"data.brokerOfRecord"
									]
								},
								{ "title": "Applicant Details", "include": ["data.applicant"] },
								{
									"title": "Advanced Details",
									"layout": { "collapse": "collapsed" },
									"include": [
										"billingLevel",
										"billingTrigger",
										"durationBasis",
										"delinquencyPlanName"
									]
								}
							]
						},
						{
							"name": "Dwelling",
							"sections": [
								{ "title": "Dwelling", "include": ["elements.HO3Dwelling"] }
							]
						}
					]
				},
				"lifecycle": {
					"steps": [
						{
							"name": "Pricing",
							"sections": [{ "title": "Pricing", "type": "pricing-review" }]
						},
						{
							"name": "Validation",
							"sections": [
								{ "title": "Validation", "type": "validation-preview" }
							]
						},
						{
							"name": "Underwriting",
							"sections": [
								{ "title": "Underwriting", "type": "underwriting-original" }
							]
						},
						{
							"name": "Documents",
							"sections": [{ "title": "Documents", "type": "documents" }]
						},
						{
							"name": "Work Management",
							"sections": [
								{ "title": "Work Management", "type": "work-management" }
							]
						}
					]
				}
			}
		}
	}
}
```

The data-entry workflow follows this pattern, which works for any product:

1. Open with an Application Details step. Its first section has no title and lists the quote-root lifecycle fields, plus the installment plan preference if the product uses one.
2. Put all of the product's primitive root data fields (strings, numbers, booleans, and dates) into one Details section.
3. Give each complex root data field (a nested object or custom data type) its own section.
4. Add a collapsed Advanced Details section for administrative and billing root fields, such as `billingLevel`, `billingTrigger`, `durationBasis`, `delinquencyPlanName`, and `autoRenewalPlanName`.
5. Add one step per element on the product. A single element renders flat; an array of elements keeps its accordion.

`journeys` sets the order of the workflows in the step list, and the first workflow opens first. See [Journeys](#journeys).

Steps [#steps]

A step is one screen of the editor and one entry in the step list. It has `sections` and footer `buttons`. This step has a different name on quotes and renewals:

```json
{
	"name": [
		{ "scope": ["quote"], "name": "Submission Details" },
		{ "scope": ["transaction.*.RenewalAmendment"], "name": "Renewal Details" },
		{ "name": "Quote Details" }
	],
	"sections": [
		{
			"title": "Submission",
			"include": ["data.policyType", "data.policyTerm", "data.floridaMarket"]
		}
	],
	"buttons": [
		{ "title": "Continue", "type": "next", "actions": ["validateForm", "save"] }
	]
}
```

* `name` can be a string or a list of [gated variants](/configuration/configurable-ui/scope-and-access#gated-variants).
* `elementName` makes the step edit one exposure, such as the dwelling. Paths in the step's sections are then the exposure's own, such as `data.censusBlockGroup`.
* A step with `"type": "divider"` draws a separator in the step list instead of a step.
* A step can set its own `subheaders` and `menu`, which override the workflow's or editor's.
* A section slot in `sections` can hold one section, or a list of gated section variants. See [Gated Variants](/configuration/configurable-ui/scope-and-access#gated-variants).

Step Navigation [#step-navigation]

By default, users can't skip ahead in the step list. The editor remembers the furthest step a user has reached with a "Continue" (`next`) button. That step and every step before it can be opened from the step list; later steps are disabled. To let users open any step, set `allowNavigationToUncompletedStep` to `true` on the editor.

* Opening an earlier step from the step list doesn't change the saved progress.
* On an issued quote or transaction, every step can be opened.

{/* TODO: confirm that allowNavigationToUncompletedStep is customer-facing */}

Buttons and Navigation [#buttons-and-navigation]

A button runs its `actions`, then can go to a workflow, a step, or a page. For example:

```json
{
	"title": "Continue",
	"type": "next",
	"actions": ["save"],
	"navigation": { "flow": "underwriting" }
}
```

| Property           | Type    | Description                                                                                                                               |
| ------------------ | ------- | ----------------------------------------------------------------------------------------------------------------------------------------- |
| `title`            | string  | The button text.                                                                                                                          |
| `type`             | string  | The button kind, such as `next`, `previous`, `custom`, `save`, `reset`, `discard`, `refuse`, `change`, `renew`, `cancel`, or `reinstate`. |
| `variant`          | string  | Visual style, such as `primary` or `destructive`.                                                                                         |
| `position`         | string  | Which side of the button row: `left` or `right`.                                                                                          |
| `hide`             | boolean | Hides the button.                                                                                                                         |
| `actions`          | array   | Action names to run. See [Actions](/configuration/configurable-ui/actions).                                                               |
| `navigation`       | object  | Where to go after the actions run: `{ "flow": … }`, `{ "flow": …, "step": … }` or `{ "page": … }`, such as `{ "page": "policy360" }`.     |
| `access`           | object  | Who can see and run the button. Use `access.execute` to control who can run it.                                                           |
| `messageOverrides` | array   | Per-button message overrides, as `{ key, value, message }` entries, matched against a plugin's error codes.                               |
| `actionOptions`    | object  | Per-action options: `refreshAuxData: { keys }`, and `label: { dataKey, maxLength }` for an editable button label.                         |

* A "Continue" (`next`) button on the last step of a workflow moves to the first step of the next workflow in the journey. A `previous` button on the first step moves back to the last step of the previous workflow. Set `navigation.flow` only to go somewhere else.
* A `next` button also moves the user's saved progress forward. See [Step Navigation](#step-navigation).
* A button can also be shown or hidden with its own `scope`, `roles`, `when`, and `unless`.
* `type` sets the button's role, such as moving to the next step; `actions` sets what runs when it's clicked. A `save` button still lists `"save"` in its `actions`.

See [Actions](/configuration/configurable-ui/actions) for the actions a button can run and the order they run in.

{/* TODO: confirm the full list of button types for public docs. */}

Workflows [#workflows]

A workflow groups steps under one name in the step list, such as Submission or Underwriting. `workflows` is a map of workflows keyed by name. Several variants of a workflow can share one `id`; the variant whose `scope` best matches the quote or transaction is used.

| Property     | Type   | Description                                                                                  |
| ------------ | ------ | -------------------------------------------------------------------------------------------- |
| `id`         | string | A logical ID shared by variants of the same workflow.                                        |
| `display`    | object | `label` is the workflow's name in the step list.                                             |
| `subheaders` | array  | The row under the page title for all of the workflow's steps. See [Subheaders](#subheaders). |
| `steps`      | array  | The workflow's steps, in order.                                                              |

Journeys [#journeys]

A journey picks which workflows a quote or transaction goes through, and in which order; that order is the step list. Journeys are checked in order, and the first match is used. Each journey is an access rule, so it can use `scope`, `roles`, `when`, and `unless`. In this example, quotes and two transaction types share the same workflows, and a third transaction type has its own:

```json
{
	"journeys": [
		{
			"scope": ["quote"],
			"workflows": ["submission", "underwriting", "issuance"]
		},
		{
			"scope": [
				"transaction.*.RenewalAmendment",
				"transaction.*.GenericAmendment"
			],
			"workflows": ["submission", "underwriting", "issuance"]
		},
		{
			"scope": ["transaction.*.ApplicantAmendment"],
			"workflows": ["applicantAmendment"]
		}
	]
}
```

* The first workflow in the selected journey opens first.
* A journey with no `scope` applies to every entity, so put specific journeys before general ones.
* A workflow named in a journey that doesn't resolve, because it is hidden by `access.read` or misspelled, is dropped from the step list.
* Without `journeys`, or when no journey matches, the step list follows the order of the `workflows` keys. End with a journey that has no `scope` to set the fallback yourself.
* There are no `groupedWorkflows` or `entryFlow` fields in this version; setting them has no effect.

<Callout>
  Transaction-editor journeys may be resolved without the entity's data or the user's roles, so select journeys by `scope` for now.
</Callout>

Page Header, Subheaders, Menu, and Sidebar [#page-header-subheaders-menu-and-sidebar]

Above the steps, every page has a header, a row of subheaders, and a ⋮ menu. The editor can also have a sidebar beside the steps.

| Piece      | Default                                                    | Configure with                                             |
| ---------- | ---------------------------------------------------------- | ---------------------------------------------------------- |
| Header     | The entity's identity, such as the quote or policy number. | `headerTemplate`. Not yet applied on every editor surface. |
| Subheaders | The product name, then a linked "Account:" row.            | `subheaders` on a workflow or step.                        |
| Menu       | A default set of actions. See [Menu](#menu).               | `menu` on the editor or a step.                            |
| Sidebar    | None.                                                      | `sidebar`, `{ "name": …, "sections": [...] }`.             |

Not every piece can be configured on every page yet:

| Piece      | Editor                                            | Policy 360                                                                           | Account 360                   |
| ---------- | ------------------------------------------------- | ------------------------------------------------------------------------------------ | ----------------------------- |
| Header     | Default only (`headerTemplate` isn't applied yet) | Default only                                                                         | Default only                  |
| Subheaders | On a workflow or step                             | On `policy360`                                                                       | Default only (account number) |
| Menu       | On the editor or a step                           | The policy menu from the [Details Page](/configuration/configurable-ui/details-page) | None                          |
| Sidebar    | On the editor                                     | None                                                                                 | None                          |

Subheaders [#subheaders]

`subheaders` is an ordered array, and it is the whole row. Each entry is a predefined row (`"productName"` or `"account"`), or a literal row with a `template`. Any entry can carry a `display.label` prefix. For example:

```json
{
	"subheaders": [
		"productName",
		{ "type": "account", "display": { "label": "Customer" } },
		{ "template": "${data.floridaMarket}", "display": { "label": "Market" } }
	]
}
```

* Omit `subheaders` for the default row: the product name, then a labeled "Account:" row.
* An `account` entry with no `display.label` shows the account without a label.
* A row whose template resolves to nothing is dropped, and the account row is skipped when there is no account.
* A step's `subheaders` override its workflow's.

Menu [#menu]

The actions menu in the page header lists page actions. With no `menu`, it shows the default actions ("Reset", "Copy", and "Refuse"), each shown only when valid for the quote's or transaction's current state. A menu is an object with a `buttons` list, and its buttons take the same `type`s as step buttons. To show different menus on a quote and a transaction, make `menu` a list of these objects, each with a `scope`; it is evaluated as [gated variants](/configuration/configurable-ui/scope-and-access#gated-variants). This example shows a different menu on quotes and on transactions:

```json
{
	"menu": [
		{
			"scope": ["quote"],
			"buttons": [
				{ "type": "reset" },
				{ "type": "custom", "title": "Copy", "actions": ["quote_copyToGroup"] }
			]
		},
		{ "buttons": [{ "type": "reset" }, { "type": "discard" }] }
	]
}
```

Sidebar [#sidebar]

The sidebar is a read-only panel beside every step of the editor. It has a `name`, its header, and `sections`, written like a step's sections. For example:

```json
{
	"sidebar": {
		"name": "File Attachments",
		"sections": [{ "hideTitle": true, "include": ["data.documents"] }]
	}
}
```

Exposure Editor [#exposure-editor]

An exposure can have its own editor, under `pages.editor` in `exposures/<Exposure>/config.json`. It lists `steps` directly, with no workflows or journeys. Paths in its sections are the exposure's own: `data.<field>` for its fields and `elements.<Coverage>` for a coverage on it. This example is from `uiConfigs/operationsWorkbench/exposures/HO3Dwelling/config.json`:

```json
{
	"display": { "label": "Dwelling" },
	"pages": {
		"editor": {
			"steps": [
				{
					"name": "Dwelling Details",
					"sections": [
						{
							"title": "Property Address",
							"include": [
								"data.propertyStreetAddress",
								"data.propertyCity",
								"data.propertyState"
							]
						}
					]
				},
				{
					"name": "Coverages",
					"sections": [
						{ "title": "Coverages", "include": ["elements.HO3CoverageA"] }
					],
					"buttons": [
						{
							"type": "save",
							"title": "Save",
							"actions": ["validateForm", "save"]
						}
					]
				}
			]
		}
	}
}
```

* The exposure editor has its own step progress, separate from the quote's. Progress moves only when a button's `actions` include `save` and the save succeeds. See [Step Navigation](#step-navigation).
* The exposure editor follows the product editor's `allowNavigationToUncompletedStep` unless it sets its own.
* The "Steps" back link at the top of the exposure editor's step list goes back to the quote step it was opened from.

<Callout>
  On the exposure editor, `headerTemplate` and `navigation.back` are accepted but not yet applied.
</Callout>

Exposures with Their Own Editor on a Quote Step [#exposures-with-their-own-editor-on-a-quote-step]

Once an exposure has its own editor, a quote step that shows it renders the exposure as a read-only summary, with an edit link that opens the exposure's editor.

* **Array of exposures**: Each row of the accordion has its own edit link.
* **Single exposure**: The summary renders inline, and the edit link is on the right of the section header.
* **Step scoped to the exposure**: When the step sets `elementName`, every section of the step is read-only, and the edit link is in the first section's header. There is no link when the step is the exposure's own editor.
* **Optional single exposure**: When the product's `contents` lists the exposure with `?`, the section header also has an add or remove control. The edit link shows once the exposure exists. A prepopulated exposure has no remove control.

Set these on the section's `layout`:

| Property               | Type    | Description                                                                                                                                     |
| ---------------------- | ------- | ----------------------------------------------------------------------------------------------------------------------------------------------- |
| `buttons.editButton`   | boolean | Shows the edit link. On a step scoped to the exposure, `false` on the first section removes the link and keeps the fields editable on the step. |
| `buttons.addButton`    | boolean | Shows the add control. Set `false` to hide it.                                                                                                  |
| `buttons.removeButton` | boolean | Shows the remove control. Set `false` to hide it.                                                                                               |
| `elementEditorQuery`   | object  | Where the edit link opens the exposure's editor, such as `{ "flow": "bind", "step": 0 }`.                                                       |

{/* TODO: confirm this is ready for public docs */}

Next Steps [#next-steps]

* [Overview Pages](/configuration/configurable-ui/overview-pages)

See Also [#see-also]

* [Configurable UI Overview](/configuration/configurable-ui/overview)
* [Scope, Access, and Conditions](/configuration/configurable-ui/scope-and-access)
* [Actions](/configuration/configurable-ui/actions)
* [Build Steps and Workflows](/learning/configurable-ui/steps-and-workflows)
* [Add Buttons, Menus, and Editors](/learning/configurable-ui/buttons-and-editors)
* [Set Journeys, Scope, and the Landing Page](/learning/configurable-ui/journeys-and-scope)
