initial
This commit is contained in:
@@ -0,0 +1,290 @@
|
||||
---
|
||||
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/<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.
|
||||
Reference in New Issue
Block a user