# Plugin UI Components Configure how your plugin's data is displayed in the NetAlertX web interface. ## Overview Plugin results are displayed in the UI via the **Plugins page** and **Device details tabs**. You control the appearance and functionality of these displays by defining `database_column_definitions` in your plugin's `config.json`. Each column definition specifies: - Which data field to display - How to render it (label, link, color-coded badge, etc.) - What CSS classes to apply - What transformations to apply (regex, string replacement, etc.) ## Column Definition Structure ```json { "column": "Object_PrimaryID", "mapped_to_column": "devMac", "mapped_to_column_data": null, "css_classes": "col-sm-2", "show": true, "type": "device_mac", "default_value": "", "options": [], "options_params": [], "localized": ["name"], "name": [ { "language_code": "en_us", "string": "MAC Address" } ] } ``` ## Properties | Property | Type | Required | Description | |----------|------|----------|-------------| | `column` | string | **YES** | Source column name from data contract (e.g., `Object_PrimaryID`, `Watched_Value1`) | | `mapped_to_column` | string | no | Target database column if mapping to a table like `CurrentScan` | | `mapped_to_column_data` | object | no | Static value to map instead of using column data | | `css_classes` | string | no | Bootstrap CSS classes for width/spacing (e.g., `"col-sm-2"`, `"col-sm-6"`) | | `show` | boolean | **YES** | Whether to display in UI (must be `true` to appear) | | `type` | string | **YES** | How to render the value (see [Render Types](#render-types)) | | `default_value` | varies | **YES** | Default if column is empty | | `options` | array | no | Options for `select`/`threshold`/`replace`/`regex` types | | `options_params` | array | no | Dynamic options from SQL or settings | | `localized` | array | **YES** | Which properties need translations (e.g., `["name", "description"]`) | | `name` | array | **YES** | Display name in UI (localized strings) | | `description` | array | no | Help text in UI (localized strings) | | `maxLength` | number | no | Character limit for input fields | ## Render Types ### Display-Only Types These render as read-only display elements: #### `label` Plain text display (read-only). ```json { "column": "Watched_Value1", "show": true, "type": "label", "localized": ["name"], "name": [{"language_code": "en_us", "string": "Status"}] } ``` **Output:** `online` --- #### `device_mac` Renders as a clickable link to the device with the given MAC address. ```json { "column": "ForeignKey", "show": true, "type": "device_mac", "localized": ["name"], "name": [{"language_code": "en_us", "string": "Device"}] } ``` **Input:** `aa:bb:cc:dd:ee:ff` **Output:** Clickable link to device details page --- #### `device_ip` Resolves an IP address to a MAC address and creates a device link. ```json { "column": "Object_SecondaryID", "show": true, "type": "device_ip", "localized": ["name"], "name": [{"language_code": "en_us", "string": "Host"}] } ``` **Input:** `192.168.1.100` **Output:** Link to device with that IP (if known) --- #### `device_name_mac` Creates a device link with the target device's name as the link label. ```json { "column": "Object_PrimaryID", "show": true, "type": "device_name_mac", "localized": ["name"], "name": [{"language_code": "en_us", "string": "Device Name"}] } ``` **Input:** `aa:bb:cc:dd:ee:ff` **Output:** Device name (clickable link to device) --- #### `url` Renders as a clickable HTTP/HTTPS link. ```json { "column": "Watched_Value1", "show": true, "type": "url", "localized": ["name"], "name": [{"language_code": "en_us", "string": "Endpoint"}] } ``` **Input:** `https://example.com/api` **Output:** Clickable link --- #### `url_http_https` Creates two links (HTTP and HTTPS) as lock icons for the given IP/hostname. ```json { "column": "Object_SecondaryID", "show": true, "type": "url_http_https", "localized": ["name"], "name": [{"language_code": "en_us", "string": "Web Links"}] } ``` **Input:** `192.168.1.50` **Output:** 🔓 HTTP link | 🔒 HTTPS link --- #### `textarea_readonly` Multi-line read-only display with newlines preserved. ```json { "column": "Extra", "show": true, "type": "textarea_readonly", "localized": ["name"], "name": [{"language_code": "en_us", "string": "Details"}] } ``` --- ### Interactive Types #### `textbox_save` User-editable text box that persists changes to the database (typically `UserData` column). ```json { "column": "UserData", "show": true, "type": "textbox_save", "default_value": "", "localized": ["name"], "name": [{"language_code": "en_us", "string": "Notes"}] } ``` --- ### Styled/Transformed Types #### `label` with `threshold` Color-codes values based on ranges. Useful for status codes, latency, capacity percentages. ```json { "column": "Watched_Value1", "show": true, "type": "threshold", "options": [ { "maximum": 199, "hexColor": "#792D86" // Purple for <199 }, { "maximum": 299, "hexColor": "#5B862D" // Green for 200-299 }, { "maximum": 399, "hexColor": "#7D862D" // Orange for 300-399 }, { "maximum": 499, "hexColor": "#BF6440" // Red-orange for 400-499 }, { "maximum": 999, "hexColor": "#D33115" // Dark red for 500+ } ], "localized": ["name"], "name": [{"language_code": "en_us", "string": "HTTP Status"}] } ``` **How it works:** - Value `150` → Purple (≤199) - Value `250` → Green (≤299) - Value `350` → Orange (≤399) - Value `450` → Red-orange (≤499) - Value `550` → Dark red (>500) --- #### `replace` Replaces specific values with display strings or HTML. ```json { "column": "Watched_Value2", "show": true, "type": "replace", "options": [ { "equals": "online", "replacement": " Online" }, { "equals": "offline", "replacement": " Offline" }, { "equals": "idle", "replacement": " Idle" } ], "localized": ["name"], "name": [{"language_code": "en_us", "string": "Status"}] } ``` **Output Examples:** - `"online"` → 🟢 Online - `"offline"` → 🔴 Offline - `"idle"` → 🟡 Idle --- #### `regex` Applies a regular expression to extract/transform values. ```json { "column": "Watched_Value1", "show": true, "type": "regex", "options": [ { "type": "regex", "param": "([0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3})" } ], "localized": ["name"], "name": [{"language_code": "en_us", "string": "IP Address"}] } ``` **Input:** `Host: 192.168.1.100 Port: 8080` **Output:** `192.168.1.100` --- #### `eval` Evaluates JavaScript code with access to the column value (use `${value}` or `{value}`). ```json { "column": "Watched_Value1", "show": true, "type": "eval", "default_value": "", "localized": ["name"], "name": [{"language_code": "en_us", "string": "Formatted Value"}] } ``` **Example with custom formatting:** ```json { "column": "Watched_Value1", "show": true, "type": "eval", "options": [ { "type": "eval", "param": "`${value} units`" } ], "localized": ["name"], "name": [{"language_code": "en_us", "string": "Value with Units"}] } ``` **Input:** `42` **Output:** **42** units --- ### Chaining Types You can chain multiple transformations with dot notation: ```json { "column": "Watched_Value3", "show": true, "type": "regex.url_http_https", "options": [ { "type": "regex", "param": "([\\d.:]+)" // Extract IP/host } ], "localized": ["name"], "name": [{"language_code": "en_us", "string": "HTTP/S Links"}] } ``` **Flow:** 1. Apply regex to extract `192.168.1.50` from input 2. Create HTTP/HTTPS links for that host --- ## Dynamic Options ### SQL-Driven Select Use SQL query results to populate dropdown options: ```json { "column": "Watched_Value2", "show": true, "type": "select", "options": ["{value}"], "options_params": [ { "name": "value", "type": "sql", "value": "SELECT devType as id, devType as name FROM Devices UNION SELECT 'Unknown' as id, 'Unknown' as name ORDER BY id" } ], "localized": ["name"], "name": [{"language_code": "en_us", "string": "Device Type"}] } ``` The SQL query must return exactly **2 columns:** - **First column (id):** Option value - **Second column (name):** Display label --- ### Setting-Driven Select Use plugin settings to populate options: ```json { "column": "Watched_Value1", "show": true, "type": "select", "options": ["{value}"], "options_params": [ { "name": "value", "type": "setting", "value": "MYPLN_AVAILABLE_STATUSES" } ], "localized": ["name"], "name": [{"language_code": "en_us", "string": "Status"}] } ``` --- ## Mapping to Database Tables ### Mapping to `CurrentScan` To import plugin data into the device scan pipeline (for notifications, heuristics, etc.): 1. Add `"mapped_to_table": "CurrentScan"` at the root level of `config.json` 2. Add `"mapped_to_column"` property to each column definition ```json { "code_name": "my_device_scanner", "unique_prefix": "MYSCAN", "mapped_to_table": "CurrentScan", "database_column_definitions": [ { "column": "Object_PrimaryID", "mapped_to_column": "cur_MAC", "show": true, "type": "device_mac", "localized": ["name"], "name": [{"language_code": "en_us", "string": "MAC Address"}] }, { "column": "Object_SecondaryID", "mapped_to_column": "cur_IP", "show": true, "type": "device_ip", "localized": ["name"], "name": [{"language_code": "en_us", "string": "IP Address"}] }, { "column": "NameDoesntMatter", "mapped_to_column": "cur_ScanMethod", "mapped_to_column_data": { "value": "MYSCAN" }, "show": true, "type": "label", "localized": ["name"], "name": [{"language_code": "en_us", "string": "Scan Method"}] } ] } ``` --- ### Using Static Values Use `mapped_to_column_data` to map a static value instead of reading from a column: ```json { "column": "NameDoesntMatter", "mapped_to_column": "cur_ScanMethod", "mapped_to_column_data": { "value": "MYSCAN" }, "show": true, "type": "label", "localized": ["name"], "name": [{"language_code": "en_us", "string": "Discovery Method"}] } ``` This always sets `cur_ScanMethod` to `"MYSCAN"` regardless of column data. --- ## Filters Control which rows are displayed based on filter conditions. Filters are applied on the client-side in JavaScript. ```json { "data_filters": [ { "compare_column": "Object_PrimaryID", "compare_operator": "==", "compare_field_id": "txtMacFilter", "compare_js_template": "'{value}'.toString()", "compare_use_quotes": true } ] } ``` | Property | Description | |----------|-------------| | `compare_column` | The column from plugin results to compare (left side) | | `compare_operator` | JavaScript operator: `==`, `!=`, `<`, `>`, `<=`, `>=`, `includes`, `startsWith` | | `compare_field_id` | HTML input field ID containing the filter value (right side) | | `compare_js_template` | JavaScript template to transform values. Use `{value}` placeholder | | `compare_use_quotes` | If `true`, wrap result in quotes for string comparison | **Example: Filter by MAC address** ```json { "data_filters": [ { "compare_column": "ForeignKey", "compare_operator": "==", "compare_field_id": "txtMacFilter", "compare_js_template": "'{value}'.toString()", "compare_use_quotes": true } ] } ``` When viewing a device detail page, the `txtMacFilter` field is populated with that device's MAC, and only rows where `ForeignKey == MAC` are shown. --- ## Example: Complete Column Definitions ```json { "database_column_definitions": [ { "column": "Object_PrimaryID", "mapped_to_column": "cur_MAC", "css_classes": "col-sm-2", "show": true, "type": "device_mac", "default_value": "", "localized": ["name"], "name": [{"language_code": "en_us", "string": "MAC Address"}] }, { "column": "Object_SecondaryID", "mapped_to_column": "cur_IP", "css_classes": "col-sm-2", "show": true, "type": "device_ip", "default_value": "unknown", "localized": ["name"], "name": [{"language_code": "en_us", "string": "IP Address"}] }, { "column": "DateTime", "css_classes": "col-sm-2", "show": true, "type": "label", "default_value": "", "localized": ["name"], "name": [{"language_code": "en_us", "string": "Last Seen"}] }, { "column": "Watched_Value1", "css_classes": "col-sm-2", "show": true, "type": "threshold", "options": [ {"maximum": 199, "hexColor": "#792D86"}, {"maximum": 299, "hexColor": "#5B862D"}, {"maximum": 399, "hexColor": "#7D862D"}, {"maximum": 499, "hexColor": "#BF6440"}, {"maximum": 999, "hexColor": "#D33115"} ], "localized": ["name"], "name": [{"language_code": "en_us", "string": "HTTP Status"}] }, { "column": "Watched_Value2", "css_classes": "col-sm-1", "show": true, "type": "label", "default_value": "", "localized": ["name"], "name": [{"language_code": "en_us", "string": "Response Time"}] }, { "column": "Extra", "css_classes": "col-sm-3", "show": true, "type": "textarea_readonly", "default_value": "", "localized": ["name"], "name": [{"language_code": "en_us", "string": "Additional Info"}] } ] } ``` --- ## CSS Classes Use Bootstrap grid classes to control column widths in tables: | Class | Width | Usage | |-------|-------|-------| | `col-sm-1` | ~8% | Very narrow (icons, status) | | `col-sm-2` | ~16% | Narrow (MACs, IPs) | | `col-sm-3` | ~25% | Medium (names, URLs) | | `col-sm-4` | ~33% | Medium-wide (descriptions) | | `col-sm-6` | ~50% | Wide (large content) | --- ## Validation Checklist - [ ] All columns have `"show": true` or `false` - [ ] Display columns with `"type"` specified from supported types - [ ] Localized strings include at least `en_us` - [ ] `mapped_to_column` matches target table schema (if using mapping) - [ ] Options/thresholds have correct structure - [ ] CSS classes are valid Bootstrap grid classes - [ ] Chaining types (e.g., `regex.url_http_https`) are supported combinations --- ## See Also - [Plugin Data Contract](PLUGINS_DEV_DATA_CONTRACT.md) - What data fields are available - [Plugin Settings System](PLUGINS_DEV_SETTINGS.md) - Configure user input - [Database Mapping](PLUGINS_DEV.md#-mapping-the-plugin-results-into-a-database-table) - Map data to core tables - [Debugging Plugins](DEBUG_PLUGINS.md) - Troubleshoot display issues