280 lines
10 KiB
Markdown
280 lines
10 KiB
Markdown
# 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/<key>/<key>.bpmn`.
|
|
- **What should the form show/do?** — fields and behaviour, so you can scaffold something useful.
|
|
|
|
## Differences: panel vs process
|
|
|
|
| | Panel | Process |
|
|
|----------------|-------|---------|
|
|
| File | `panels/<key>/<key>-desktop.xml` | `processes/<key>/<key>-desktop.xml` |
|
|
| Root element | `<panel-form>` | `<forms>` (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 `<form>` | **one `<form formKey>` 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` |
|
|
| `<library>` | not used | optional: shared `<complex-component id>` reused via `<component-ref refId>` |
|
|
|
|
Everything below (components, DBTable, engine API, ES5 rules) is **identical** for both.
|
|
|
|
## Step 3 — Scaffold the file
|
|
|
|
### Panel variant — `panels/<key>/<key>-desktop.xml`
|
|
|
|
```xml
|
|
<?xml version="1.0" encoding="UTF-8"?>
|
|
<panel-form xmlns="http://www.davinti.com.br/vitruvio/form/panel"
|
|
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
|
xsi:schemaLocation="http://www.davinti.com.br/vitruvio/form/panel https://bitbucket.org/davinTI/vitruvio-xds/raw/master/vitruvio-panel-form.xsd">
|
|
|
|
<form formKey="<key>" width="100%" height="100%">
|
|
<name><name></name>
|
|
<description><description></description>
|
|
|
|
<initScript language="JavaScript">
|
|
<![CDATA[
|
|
function run() {
|
|
// called once when the panel opens
|
|
}
|
|
]]>
|
|
</initScript>
|
|
|
|
<components>
|
|
<VerticalLayout spacing="true" margin="true" width="100%" height="100%">
|
|
<!-- add widgets here -->
|
|
</VerticalLayout>
|
|
</components>
|
|
</form>
|
|
</panel-form>
|
|
```
|
|
|
|
### Process variant — `processes/<key>/<key>-desktop.xml`
|
|
|
|
```xml
|
|
<?xml version="1.0" encoding="UTF-8"?>
|
|
<forms xmlns="http://www.davinti.com.br/vitruvio/form"
|
|
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
|
xsi:schemaLocation="http://www.davinti.com.br/vitruvio/form https://bitbucket.org/davinTI/vitruvio-xds/raw/master/vitruvio-form.xsd">
|
|
|
|
<!-- Optional: shared components used across multiple forms -->
|
|
<library>
|
|
<!-- <complex-component id="libShared">...</complex-component> -->
|
|
</library>
|
|
|
|
<!-- One <form> per activiti:formKey in the BPMN -->
|
|
<form formKey="formAbertura" width="100%">
|
|
<name>Abertura</name>
|
|
<description>Abertura do processo</description>
|
|
<initScript language="JavaScript">
|
|
<![CDATA[
|
|
function run() {
|
|
// called when the form opens
|
|
}
|
|
]]>
|
|
</initScript>
|
|
<components>
|
|
<VerticalLayout spacing="true" margin="true" width="100%">
|
|
<TextField id="descricao" type="string" caption="Descrição" width="100%" required="true" />
|
|
</VerticalLayout>
|
|
</components>
|
|
</form>
|
|
|
|
<form formKey="formExecutar" width="100%">
|
|
<name>Executar</name>
|
|
<description>Etapa de execução</description>
|
|
<initScript language="JavaScript">
|
|
<![CDATA[
|
|
function run() {
|
|
// read a process variable set during a previous step
|
|
// var valor = engine.getVariable('formAbertura_descricao');
|
|
}
|
|
]]>
|
|
</initScript>
|
|
<components>
|
|
<VerticalLayout spacing="true" margin="true" width="100%">
|
|
<TextField id="resultado" type="string" caption="Resultado" width="100%" required="true" />
|
|
<ComboBox id="aprovado" type="string" caption="Aprovado?" required="true" allowNullSelection="false">
|
|
<entry key="1" value="Sim"/>
|
|
<entry key="0" value="Não"/>
|
|
</ComboBox>
|
|
</VerticalLayout>
|
|
</components>
|
|
</form>
|
|
|
|
</forms>
|
|
```
|
|
|
|
## Components (78 desktop components)
|
|
|
|
Before using a component you are unsure about, read its reference:
|
|
`~/.local/share/vitruvio-platform/docs/components/desktop/<ComponentName>.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 `<Tab caption="...">` 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: `<entry key="..." value="..."/>` |
|
|
| `Label` | `id`, `width`, `contentMode` (`HTML`/`TEXT`) — child: `<value>...</value>` |
|
|
| `ButtonWidget` | `id`, `caption`, `style` (`GREEN`/`RED`/`DEFAULT`), `defaultIcon` — child: `<onClickScript>` |
|
|
| `RichTextArea` | `id`, `type`, `caption`, `width`, `height` |
|
|
| `ImageWidget` | `id`, `width`, `height` — child: `<image><base64 extension="png">...</base64></image>` |
|
|
|
|
### DBTable (data grid)
|
|
|
|
```xml
|
|
<DBTable id="tbDados" type="string" width="100%" rows="8"
|
|
exportXLS="true" showRowCount="true" selectable="true">
|
|
<datasource>
|
|
<!-- Option A: static query -->
|
|
<freeQuery connection-key="vitruvio_producao">
|
|
<![CDATA[
|
|
SELECT col1, col2
|
|
FROM my_table
|
|
WHERE param = ${myParam}
|
|
]]>
|
|
</freeQuery>
|
|
|
|
<!-- Option B: dynamic query built in JS -->
|
|
<sqlBuilderDataSource connection-key="vitruvio_producao" language="JavaScript">
|
|
<![CDATA[
|
|
function buildSQL(params) {
|
|
var sql = 'SELECT col1, col2 FROM my_table WHERE 1=1';
|
|
var val = engine.getField('myFilter').getValue();
|
|
if (val) {
|
|
sql += ' AND col1 = ${val}';
|
|
params.put('val', val);
|
|
}
|
|
return sql;
|
|
}
|
|
]]>
|
|
</sqlBuilderDataSource>
|
|
</datasource>
|
|
<key-field>CHAVE</key-field>
|
|
<columns>
|
|
<column name="COL1" caption="Column 1" expand-ratio="1"/>
|
|
<column name="COL2" caption="Column 2" expand-ratio="2"/>
|
|
<generated name="Action" expand-ratio="0.5">
|
|
<scriptColumnGenerator language="JavaScript">
|
|
<![CDATA[
|
|
function Generator() {
|
|
var com = libService.loadScript('vaadinComponents');
|
|
this.generate = function(itemId, columnId, item, container) {
|
|
var btn = com.buttonIcon('action', function() {
|
|
var id = item.getItemProperty('CHAVE').getValue();
|
|
// do something
|
|
}, 'edit');
|
|
return com.horizontalLayout([btn]);
|
|
}
|
|
}
|
|
var script = new Generator();
|
|
]]>
|
|
</scriptColumnGenerator>
|
|
</generated>
|
|
</columns>
|
|
<bind>
|
|
<parameter value-type="number" defaultValue="0" parameterName="myParam" field-ref="otherTable"/>
|
|
</bind>
|
|
</DBTable>
|
|
```
|
|
|
|
**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 `<form formKey>` must match an `activiti:formKey` in the BPMN, and
|
|
submitted field `id="X"` in `formKey="A"` becomes process variable `A_X`.
|
|
- `run()` in `<initScript>` is called every time the form opens.
|
|
- `${paramName}` for SQL substitution in datasources; `:paramName` only in named query files.
|