# Custom fields (Workspace)

> Define organization-wide metadata fields and project scope from Workspace.

**Campos personalizados** in the Workspace side rail opens `/workspace/custom-fields`. Organization **owners** and **admins** manage field definitions for the active organization. **Members** and **viewers** see a permission message and cannot change definitions.

## Management table

Above the table, a shared **filter bar** hosts a **search** field that filters rows by field title (case-insensitive, server-side). From **Add filter** you can add **Entity**, **Type**, and **Group** chips — each a multi-select that writes a comma-separated param (`type=select_single,radio`); values OR within a chip and AND across the search and chips. A **field count** shows how many definitions match the active query out of the total (for example `1 of 12 fields`). Filter state lives in the URL and any change resets to page 1. Whenever any search or filter is active, the core-section rows are hidden so only matching custom-field definitions show; clearing the empty-filtered state removes the search and all filter params together.

The table lists every definition (system and custom) with columns:

| Column   | Meaning                                                                                                                                                                                                              |
| -------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| NAME     | Display title of the field                                                                                                                                                                                           |
| GROUP    | Badge: **System** (seeded, muted style) or **Custom** (accent style)                                                                                                                                                 |
| TYPE     | Input type with the same icon as the add dialog (Short text, Select list, Checkbox, …)                                                                                                                               |
| ENTITY   | Target object with the same icon as the add dialog (**Test case**, **Test run**, or **Defect**)                                                                                                                      |
| PROJECTS | **All projects** (globe-style label) when the field applies everywhere; a stacked project avatar with count when scoped to specific projects; or an italic **No projects** warning when scoped but none are selected |
| REQUIRED | Accent dot: filled when required, hollow when optional (screen readers still hear Yes/No)                                                                                                                            |
| ACTIONS  | Edit (all rows); delete (custom rows only)                                                                                                                                                                           |

Data loads from the organization API when you open the page. Rows are ordered with all **System** fields first, then **Custom** fields; within each group, titles are sorted A–Z.

On a narrow (phone-width) screen the table becomes a card list: each definition (and each core defect
section) presents as its own card, showing the same group, type, entity, projects, and required values,
with edit/delete still available. At tablet width and above the list is the table described above.

### Core defect sections

Three built-in defect sections — **Description**, **Evidence**, and **Affected cases** — appear as pinned rows with a **Core** badge when the table includes any defect-scoped field (or on their own when you have no custom defect fields yet). They are not custom-field definitions: you can rename the section title for your organization, but you cannot delete them, change their type, or scope them per project.

- **Edit** opens a title-only dialog with an EN/ES locale toggle in the header, alongside **Save** and **Reset to default**. Both slots always prefill — with your stored override in that language when one exists, or the localized product default otherwise — so English is never blank and you can save a Spanish-only rename with no extra step.
- **Reset to default** is always visible and always enabled, whether or not an override exists; resetting a section with no override is a harmless no-op.
- Overrides are bilingual organization data, resolved per reader: a reader viewing the app in Spanish sees your stored Spanish text (or your English text, if you haven't translated that section yet — never the untouched product default while an override exists in the other language). Switching your own app language updates these headings immediately, with no reload.
- Renames apply to defect **detail section headings** only. Labels elsewhere (for example the **Description** field in the New defect dialog) stay on the catalog copy.

## Add a custom field

Use **Agregar campo personalizado** to open the create dialog. The header carries the subtitle _"Define an extra field for test cases, plans, defects, and other entities."_ and the primary action reads **Save field**. Required fields are marked with an asterisk (`*`); optional fields carry no marker.

- **Title**, **Entity** (**Test case**, **Test run**, or **Defect**), and **Type** — all three marked as required
- **Test run** fields have one extra rule: a **Test run** field marked **Campo obligatorio** MUST carry a non-empty default value, on both create and edit. Saving a required test-run field with an empty default is rejected (`422 validation_failed`, `details.field = "defaultValue"`); **Test case** and **Defect** fields keep the existing behavior and may stay required with no default. The rule exists because run creation must never fail for an integrator who omits a value — with a guaranteed non-empty default, an omitted required run value always resolves from it.
- **Enable for all projects** is on by default; turning it off reveals the **Projects** multi-select with the helper _"The field will only appear in the selected projects."_
- **Placeholder**, **Default value**, and **Campo obligatorio** depend on the field type (see matrix below)
- For **Date picker**, **Default value** uses the in-app calendar (not the browser’s native date control); pick a day, **Clear**, or **Today**. Stored values use `YYYY-MM-DD`.
- For **Checkbox**, the placeholder row is hidden; use **Estado por defecto** (Checked/Unchecked) instead of “required”
- For **Paragraph**, **Default value** is a multi-line textarea
- For **Number** and **URL**, **Default value** validates on save (finite number / valid URL)
- For **Select list (single)**, **Select list (multi)**, and **Radio**, open the **Values** tab to add options (name, Font Awesome icon class, color: pick a preset, type a hex value, or select the color swatch beside the hex field to open the color picker). System fields ship with canonical seed options that already include default Font Awesome icons and semantic hex colors (for example High priority uses an up-arrow with accent color). The **Values** tab also shows a live count of the options defined so far. **Default value** is a dropdown or multi-select fed from that live list
- Drag the handle (⠿) at the left of each option row to reorder. Keyboard: focus the handle, press Space to pick up, Arrow Up / Down to move, Space to drop, Escape to cancel.

### Placeholder and default controls by type

| Type                 | Placeholder | Default value                  |
| -------------------- | ----------- | ------------------------------ |
| Short text           | Text        | Text                           |
| Paragraph            | Text        | Multi-line textarea            |
| Number               | Text        | Numeric (validated)            |
| URL                  | Text        | URL (validated)                |
| Date picker          | Text        | In-app date picker             |
| Checkbox             | Hidden      | Checked / Unchecked            |
| Radio                | Text        | Dropdown of Values options     |
| Select list (single) | Text        | Dropdown of Values options     |
| Select list (multi)  | Text        | Multi-select of Values options |
| User picker          | Text        | Hidden                         |

For option-based types, the default control stays **disabled** until the **Values** tab has at least one option. If you remove an option that was selected as the default, the default clears automatically. On edit, if a stored default no longer matches any option, the dialog clears it and shows a short Spanish notice.

Saving creates a **Custom** definition scoped to your organization.

## Edit and delete

The edit dialog reuses the same chrome and the same **Save field** action as the create dialog, with the subtitle _"Edit the properties of this custom field."_ **Entity** and **Type** are shown disabled and unmarked; **Title** still carries the required asterisk.

- **Entity** and **Type** cannot change after create (protects stored values).
- You can update title, placeholder, default, required, and project scope. Removing a project from scope **does not delete** values already captured; they reappear if you link the project again.
- **System** rows (for example Priority, Severity, Status) cannot be deleted. You may rename the title, customize options (rename seed values, change icon/color, reorder, add user options), and adjust placeholder, default, required, and project scope. Seed options cannot be removed from the list; use **Restore defaults** in the edit dialog to undo customizations.
- Editing or reordering options on any field preserves stored test-case values for those options; deleting an option still drops any values that pointed at it.
- **Restore defaults** (system fields only) opens a confirmation dialog. Confirming calls `POST /api/v1/orgs/{orgUlid}/custom-fields/{fieldUlid}/reset`, which restores the seed title, placeholder, default, required flag, and option names/icons/colors while keeping stable option ULIDs. User-added options are removed. Project scope (`all_projects` / `project_ulids`) is preserved. Test cases that pointed at removed options receive the field default when one exists, or the value is cleared.
- **Custom** rows can be deleted even when cases, runs, or defects already hold values for them. If the field holds values, the delete dialog states how many values across how many projects will be lost, and **Delete** stays disabled until you type the field name exactly. Deleting removes the field and all of its values permanently; it cannot be undone. To keep the values, remove the field from the project's scope instead.

## Plans

Creating custom fields and editing field definitions are part of the **Pro** and **Enterprise** plans, and of the trial. On the Free plan the screen shows every field read-only: **Add custom field** and **Save field** in the edit dialog show the upgrade option instead. Filling in field values on cases, runs, results, and defects works on every plan.

### If your organization moves to Free

Nothing is deleted:

- Every field keeps its definition, and its values stay editable everywhere.
- Owners and admins can still open a field's edit dialog to review it, **delete** custom fields, and use **Restore defaults** on system fields.

What stops until you are back on a paid plan: creating fields and saving changes to a field's definition, system fields included.

## Relationship to test cases and defects

Definitions edited here drive labels and option visuals on test case and defect surfaces through the API.

For **test cases**, embedded `customFieldValues` on case GET/list responses include `optionName`, `optionIcon`, and `optionColor` when the stored value resolves to a known option, so the repository **Pri** column and editorial priority chips render Font Awesome from persisted option data without fetching definitions per row.

For **defects**, every organization receives seeded **Severity** and **Priority** system fields (required, with default options). You can rename options, add new ones (for example a **Blocker** severity), and change icons/colors — option names are org data, not fixed product copy. The same definitions appear on the **New defect** dialog (system fields first), in the detail **Properties** sidebar (severity/priority rows before assignee and other typed rows), and in the run **capture** flow. List and run-defect responses expose severity/priority only via `systemFieldValues`; defect detail `GET` embeds full `customFieldValues`. Required defect fields without a default block one-keystroke capture: **Enter** opens the full **New defect** dialog prefilled from the quick-create form instead of posting immediately.

The **Restore defaults** action on system fields resets option names, icons, and colors to the canonical seed map while keeping stable option ULIDs. Type labels ("Short text", "Select list (multi)") and entity labels ("Test case", "Defect") come from the product i18n catalog.

## Bilingual field text

Field titles, placeholders, and option names can now carry a Spanish translation. The title and each option name require English wording; a placeholder's English wording is optional, so a field with no placeholder simply has no text in either language. All eleven system field titles and thirty-seven seed option names already ship with a human-authored Spanish translation, so a newly created organization is bilingual from the start; an existing organization's untouched system rows were backfilled the same way.

- Searching the table (the **search** field described above) matches a title stored in **either** language, so you can find a field by its Spanish title even while the app itself is showing English.
- Restoring a system field's defaults restores both the English and the Spanish seed text.
- The server resolves title/placeholder/option text for the caller's requested language, and the Workspace app sends that request itself: the management table follows your active language switch, so a translated title, placeholder, or option name renders in Spanish the moment you switch the app to Spanish. The add/edit dialogs carry an EN/ES toggle in the header for authoring the Spanish translation alongside the English wording, and both dialogs open on your own active language by default.
- After you save, the app offers to sync the other language whenever you changed text in exactly one of them — title, placeholder, or an option name — even if the other language already has text, since it may now be out of date with what you just changed. Accept to switch straight to that language and keep editing, or decline to leave it as it was; you won't be asked again for that same save.
- Creating a field requires an English title. If you write only the Spanish title and try to save, the dialog stops you and offers to switch to English so you can fill it in, or to copy your Spanish text into English as a starting point.
- Translations can also be edited through the API's optional `titleI18n` / `placeholderI18n` / `nameI18n` maps (see the [API reference](https://docs.probara.net/en/developers/api-reference/)).
