Files
2026-09-23 12:29:08 -03:00

11 KiB

name, description
name description
vitruvio-criar-form-desktop 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

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 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 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)

<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

// 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.