--- name: vitruvio-criar-form-desktop description: > Use when the user wants to create or edit the DESKTOP (web) XML form of a Vitruvio panel or process — the Vaadin form rendered on desktop. Triggers: "create desktop form", "criar formulário desktop", "form xml", "desktop form xml", "tela desktop", "add a field to the desktop form", "process desktop form". This is the single home for desktop form knowledge; vitruvio-criar-painel and vitruvio-criar-processo call it for their form part. For the mobile form use vitruvio-criar-form-mobile. --- # Create Vitruvio Desktop Form > All messages shown to the user must be written in Portuguese. Desktop forms are Vaadin 8 forms defined in XML and rendered by the Vitruvio engine. This skill creates the **desktop** form. There are two variants that share almost all of their component vocabulary but differ in their root element and how variables flow — see **Differences: panel vs process** below. ## Step 1 — Confirm you are inside a Vitruvio repo ```bash ls vitruvio.json 2>/dev/null && echo "OK" || echo "NOT_A_VITRUVIO_REPO" ``` If `NOT_A_VITRUVIO_REPO`, stop and tell the user to `cd` into the correct repo. ## Step 2 — Determine variant and target Ask (only what is missing): - **Panel or process form?** (decides root element / file location — see below) - **Key** — the panel or process key (the folder name). - For a **process**, which `formKey`(s) are needed — they must match the `activiti:formKey` values in `processes//.bpmn`. - **What should the form show/do?** — fields and behaviour, so you can scaffold something useful. ## Differences: panel vs process | | Panel | Process | |----------------|-------|---------| | File | `panels//-desktop.xml` | `processes//-desktop.xml` | | Root element | `` | `` (with `processKey` attribute optional) | | Namespace | `http://www.davinti.com.br/vitruvio/form/panel` | `http://www.davinti.com.br/vitruvio/form` | | XSD | `vitruvio-panel-form.xsd` | `vitruvio-form.xsd` | | Forms per file | exactly one `
` | **one `` per BPMN `activiti:formKey`** | | Variables | none built-in; use `engine.getGlobalVariable` | process variables: `engine.getVariable`/`setVariable`; submitted field `id="X"` in `formKey="A"` → variable `A_X` | | `` | not used | optional: shared `` reused via `` | Everything below (components, DBTable, engine API, ES5 rules) is **identical** for both. ## Step 3 — Scaffold the file ### Panel variant — `panels//-desktop.xml` ```xml ``` ### Process variant — `processes//-desktop.xml` ```xml
Abertura Abertura do processo
Executar Etapa de execução
``` ## Components (78 desktop components) Before using a component you are unsure about, read its reference: `~/.local/share/vitruvio-platform/docs/components/desktop/.md` (full list in `docs/components/INDEX.md`). ### Layout | Component | Common attributes | |---|---| | `VerticalLayout` | `spacing`, `margin`, `width`, `height`, `expandRatio` | | `HorizontalLayout` | same as above | | `Panel` | `id`, `caption`, `width`, `height`, `margin` | | `TabLayout` | `id`, `width`, `framed` — contains `` children | ### Widgets | Component | Key attributes | |---|---| | `TextField` | `id`, `type` (`string`/`number`), `caption`, `width`, `required` | | `NumericField` | `id`, `type`, `caption`, `width`, `visible` | | `DateField` | `id`, `type` (`date`/`datetime`), `caption`, `resolution` (`DAY`/`MINUTE`) | | `ComboBox` | `id`, `type`, `caption`, `allowNullSelection` — children: `` | | `Label` | `id`, `width`, `contentMode` (`HTML`/`TEXT`) — child: `...` | | `ButtonWidget` | `id`, `caption`, `style` (`GREEN`/`RED`/`DEFAULT`), `defaultIcon` — child: `` | | `RichTextArea` | `id`, `type`, `caption`, `width`, `height` | | `ImageWidget` | `id`, `width`, `height` — child: `...` | ### DBTable (data grid) ```xml CHAVE ``` **SQL in datasources:** use `${paramName}` for substitution — NOT `:paramName`. Named params (`:paramName`) are only for `queries/*.sql` files. ## engine API ```javascript // Fields engine.getField('id').getValue() engine.getField('id').getConvertedValue() // typed value (number, date, etc.) engine.getField('id').setValue(value) engine.getField('id').setEnabled(bool) engine.getField('id').setVisible(bool) engine.getField('id').setRequired(bool) engine.getField('id').setCaption('new caption') engine.getField('id').refresh() // DBTable — re-run its query // Widgets / layouts engine.getWidgetController('id').getButton() engine.getLayout('id').getSelectedTab() // User engine.getLoggedUser().getLogin() engine.getLoggedUser().getNome() // Global variables (survive tab changes within a session) engine.setGlobalVariable('key', value) engine.getGlobalVariable('key') // Process forms only — process variables: engine.getVariable('varName') engine.setVariable('varName', value) engine.getProcessDefinitionId() engine.formKey() // current form's formKey engine.getFormName() // Open another panel / load a library var vUI = libService.loadScript('vUI'); vUI.showPanel('panelKey', { param1: value1 }); var lib = libService.loadScript('scriptKey'); ``` ## Script rules (Rhino ES5) Desktop form scripts run on **Rhino ES5** — no `let`/`const`, arrow functions, template literals, destructuring, `class`, `import/export`. Use `var`, string `+` concat, `JSON.parse`/`JSON.stringify`, `importClass(Packages.some.java.Class)` for Java interop. (See the repo `CLAUDE.md` "JavaScript — ES5 / Rhino Engine" section.) > Note: this ES5 rule is for **desktop**. Mobile forms use modern JS on the client — see > **vitruvio-criar-form-mobile**. ## Step 4 — Manifest If run **standalone**, set `"forms"."desktop"` to the file path on the existing panel or process entry in `vitruvio.json`. Full entry creation is handled by **vitruvio-criar-painel** / **vitruvio-criar-processo**. ## Step 5 — Report Tell the user: - File created/updated and which variant (panel/process). - For processes: each `
` must match an `activiti:formKey` in the BPMN, and submitted field `id="X"` in `formKey="A"` becomes process variable `A_X`. - `run()` in `` is called every time the form opens. - `${paramName}` for SQL substitution in datasources; `:paramName` only in named query files.