# Panels Panels are UI screens defined entirely in XML. Vitruvio parses the XML against its XSD schema and renders Vaadin 7 components through a Java presenter layer — no Java UI code lives here. --- ## vitruvio.json Registration ```json { "key": "my-panel", "name": "My Panel", "description": "Short description.", "category": "Category/Subcategory", "displayOrder": 10, "showInPresentation": false, "openInNewWindow": false, "showInMobileList": false, "displayTimeInSeconds": 0, "allowedGroups": ["group-key"], "allowedUsers": [], "forms": { "desktop": "panels/my-panel/my-panel-desktop.xml", "mobile": "panels/my-panel/my-panel-mobile.xml" } } ``` - `displayOrder` — use gaps (10, 20, 30…) to allow future insertions. - `forms.mobile` is optional. Omit if there is no mobile form. - `allowedGroups` and `allowedUsers` are additive — a user in any allowed group or listed directly gets access. --- ## Desktop Form — File Structure ```xml
Human-readable title Short description.
``` - `formKey` must be unique within the panel. By convention it matches the panel key. - `` runs once when the panel is opened. The `run()` function is the entry point. - Everything in `` is the Vaadin component tree. --- ## Mobile Form — File Structure Mobile forms use a different namespace and XSD, and support a `` block for server-executed bridge functions. ```xml
Title
``` ### Calling bridges from mobile client scripts ```javascript vCommunicationService.executeOnServer('myBridge', params).then(function(result) { // handle result }).catch(function(error) { console.log('Error: ' + error); }); ``` ### Mobile timers ```javascript engine.startTimer('timerName', function() { // runs every intervalMs }, intervalMs); engine.stopTimer('timerName'); ``` --- ## The `engine` API (Desktop) `engine` is injected into all script contexts inside a panel. ### Fields ```javascript var field = engine.getField('fieldId'); field.getValue(); // returns null when empty; for DB-backed fields returns a Java type — use == not === when comparing field.setValue(value); field.clear(); field.setEnabled(true/false); field.setVisible(true/false); field.setRequired(true/false); field.focus(); field.refresh(); // DB components — re-runs the datasource query ``` ### Layouts ```javascript var layout = engine.getLayout('layoutId'); layout.getRootComposition().setVisible(true/false); layout.getRootComposition().setCaption('New caption'); layout.getRootComposition().removeAllComponents(); layout.getRootComposition().addComponent(component); layout.getRootComposition().setScrollTop(100000); // scroll to bottom // WindowLayout only layout.showWindow(); layout.closeWindow(); ``` ### User & Session ```javascript var user = engine.getLoggedUser(); user.getLogin(); // username string user.getNome(); // display name (desktop) ``` ### Global variables — sharing state across components ```javascript // Set in initScript or any handler engine.setGlobalVariable('myHelper', function() { ... }); engine.setGlobalVariable('myData', { key: 'value' }); // Read anywhere in the form engine.getGlobalVariable('myHelper')(); var data = engine.getGlobalVariable('myData'); // Clean up engine.unsetGlobalVariable('myVar'); ``` Use global variables to expose reusable functions (e.g. `limparCampos`, `carregarDados`) and shared state across components and events. ### Form validation ```javascript if (engine.isValid()) { // all required fields are filled } ``` ### Repeating timers (desktop polling) ```javascript var timer = engine.registerRepeatingTimer(3000, function() { // do something every 3s // return true to keep running, false/undefined to stop }); engine.setGlobalVariable('myTimer', timer); // Later, to stop it: engine.getGlobalVariable('myTimer').setEnabled(false); engine.unsetGlobalVariable('myTimer'); ``` --- ## Script Blocks and Events ### initScript Runs when the panel loads. Define helper functions here and expose them via `setGlobalVariable` so other components can call them. ```xml ``` ### Button click ```xml ``` ### Field value change ```xml ``` `immediate="true"` is required for `valueChange` to fire on every keystroke. --- ## Layout Components ### VerticalLayout / HorizontalLayout ```xml ``` **Sizing fields inside `layouts`:** always prefer `width="100%"` combined with `expandRatio` instead of fixed pixel widths. `expandRatio` controls the proportional share of the available space each child receives. ```xml ``` ### Panel A styled container with an optional caption and background color. ```xml ... ``` ### CrudPanel The standard page chrome: header bar + section content area. > Validators will reject it as a root element. Always wrap it in a Layout element like `VerticalLayout`, `HorizontalLayout`, `TabLayout`, or `AbsoluteLayout` as the root component inside ``. ```xml
Page Title Subtitle text
``` ### TabLayout ```xml ``` ### ScrollPanel ```xml ``` ### WindowLayout (modal) ```xml ``` Open/close via `engine.getLayout('myModal').showWindow()` / `.closeWindow()`. --- ## Input Components ### Common attributes | Attribute | Purpose | | ------------- | ---------------------------------------------- | | `id` | Required for `engine.getField()` access | | `caption` | Label above the component | | `width` | CSS width (`100%`, `200px`) | | `expandRatio` | Flex grow ratio within parent layout | | `visible` | `true`/`false` | | `required` | Marks field as required for `engine.isValid()` | | `enabled` | `true`/`false` | | `description` | Tooltip text | | `immediate` | `true` to fire events on every change | | `maxLength` | Max character count (TextField, TextArea) | ### TextField / TextArea / NumericField / DateField ```xml