Dia antes primera install

This commit is contained in:
2025-12-08 15:20:28 -06:00
commit 1416478c9c
4130 changed files with 886376 additions and 0 deletions

202
node_modules/node-red-node-ui-table/LICENSE generated vendored Normal file
View File

@@ -0,0 +1,202 @@
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "[]"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright [yyyy] [name of copyright owner]
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.

173
node_modules/node-red-node-ui-table/README.md generated vendored Normal file
View File

@@ -0,0 +1,173 @@
node-red-node-ui-table
======================
A Node-RED UI widget node which displays data as a table.
## Install
Either use the Editor - Menu - Manage Palette - Install option, or run the following command in your Node-RED user directory (typically `~/.node-red`) after installing Node-RED-dashboard.
npm i node-red-node-ui-table
## Usage
This table node expects `msg.payload` to contain an array of data, one object per row.
Each data row object should have the same set of keys because the keys in the object are used as the column names.
Both examples can be imported from the Node-RED Editor - Menu - Import - Examples
### Simple Table
With no configuration the node will try to create a table with equally spaced columns of simple text for each row provided, using the keys as column titles.
![screenshot](https://raw.githubusercontent.com/node-red/node-red-ui-nodes/master/node-red-node-ui-table/screenshot.png)
### Richer Table
The columns can be configured manually. If so then only the `msg.payload` properties defined will be displayed. You can then also define the Title, Width, Alignment and Format of the column.
![screenshot2](https://raw.githubusercontent.com/node-red/node-red-ui-nodes/master/node-red-node-ui-table/screenshot2.png)
- **Title**: Text for the column title (or blank).
- **Width**: Either a number of pixels or percentage of the overall table width. e.g. 150 or 20%. Leave blank for automatic, equally spaced to fill the available space.
- **Align**: Column alignment, left, centre or right.
- **Format**: Formatting of the input.
- **Plain Text** - Simple text values.
- **HTML** - Rich html to allow text Formatting - *NOTE*: this is raw un-sanitised HTML.
- **Link** - URL link to a web page.
- **Image** - Source (src) URL of an image to display.
- **Progress** - a progress bar from 0 to 100.
- **Traffic** - Red/Amber/Green indicator light set by numbers in the range 0-33-67-100.
- **Color** - HTML color name, or hex value (#rrggbb) to fill the cell.
- **Tick/Cross** - Tick or Cross symbol, boolean true/false, numeric 1/0 or text "1"/"0".
- **Stars** - Number of stars - numeric 0 to 5.
- **Row Number** - Current row number.
### Example data
```
[
{
"Name": "Kazuhito Yokoi",
"Age": "35",
"Favourite Color": "red",
"Date Of Birth": "12/09/1983"
},
{
"Name": "Oli Bob",
"Age": "12",
"Favourite Color": "cyan",
"Date Of Birth": "12/08/2017"
}
]
```
## advanced features
ui-table is based on the **tabulator** module. You can find an excellent in depth [documentation here](http://tabulator.info/docs/4.4) with many [examples here](http://tabulator.info/examples/4.4).
## send commands to ui-table
Instead of sending an array to ui-table this node to replace the complete table data ui-table also accepts an object as payload to send commands. Beside data manipulation you can [set filters](http://tabulator.info/docs/4.5/filter#func) and do many other things with commands. The object must have the following properties
- `command` a valid tabulator function such as `addRow`, `replaceData` or `addFilter`
- `arguments` *(optional)* array of arguments for that function
- `returnPromise` *(optional)* a boolean value. `true` if the function should return a promise message. See tabulator documentation which commands will return promises
example
```json
{"payload":{
"command":"addData",
"arguments":[
{
"facility":"daemon",
"facilityCode":3,
"severity":"info",
"severityCode":6,
"tag":"systemd[1]",
"timestamp":"2020-01-02T19:17:39.793Z",
"hostname":"localhost",
"address":"127.0.0.1",
"family":"IPv4",
"port":38514,
"size":80,
"msg":"some demo data",
"id":2351
},
true
],
"returnPromise":true
}
}
```
By sending only changed or new data to ui-table it is possible to update the table very fast by only sending the new data down to cell level. Or huge amounts of data could be sent like logs.
**important notices**
Data which is sent to ui-table through commands is **not** cached by ui-table! The flow has to take care to update the table for new clients connection or dashboard tab changes!
Tabulator does not limit the amount of data it holds. It is quite efficient in showing tables with a couple of thousand rows. If it the data exceeds the capabilities of the clients browser it will crash with an **out of memory** error without notice.
Example flow "4 sending commands.json" file can be found in the examples folder or installed directly using **menu/import/examples/ui-table**.
This flow shows a basic implementation how the flow can keep a cached copy of all table data and add/delete or update selective rows.
Most nodes have info text available in the info/help tab.
## control ui-table by sending ```msg.ui_control``` messages
ui-table can be customized by sending configuration data to `msg.ui_control.tabulator`.
![customized table](https://raw.githubusercontent.com/node-red/node-red-ui-nodes/master/node-red-node-ui-table//ui-table-custom.png)
by adding ***headers***, ***footers***, ***line*** or ***column grouping*** it is sometimes not possible to determine the amount of lines. Therefore the height can be defined by sending `msg.ui_control.customHeight=lines`.
Example flow "3 ui_control table.json" file can be found in the examples folder
- grouped columns by nesting column definition in ` ui_control.tabulator.columns`
- first column ```frozen``` from horizontal scrolling
- `formatterParams` to define min/max, color, legend or other parameters for `progress` and `planText` formatters
- functions to format legend values
``` javascript
// add a unit
function(cell, formatterParams, onRendered){
return cell.getValue()+"°C";
}
```
or more sophisticated using html
``` javascript
// convert Number to Icons
function(cell, formatterParams, onRendered){
var html="<i class=\"";
switch(cell.getValue()) {
case 0: html+="fa fa-calendar-check-o"; break;
case 1: html+="fa fa-hand-o-up"; break;
case 2: html+="fa fa-suitcase"; break;
case 3: html+="fa fa-spinner fa-spin fa-fw"; break;
}
html+='\"></i>';
return html;
}
```
- `topCalc` for average and min/max calculations
- custom icons for `tickCross` formatter
- `tick` formatter
- `groupBy` parameter to use group lines. `groupHeader` function to format legend and adding html tags (Insert a field name in the groupBy paramter at the end of json in the change node to use this feature)
- `columnResized` callback function to receive a message when the user resize a column
``` javascript
function(column){
var newColumn = {
field: column._column.field,
visible: column._column.visible,
width: column._column.width,
widthFixed: column._column.widthFixed,
widthStyled: column._column.widthStyled
};
this.send({
ui_control:{callback:'columnResized',columnWidths:newColumn}
});
}
```
- use `this.send({})` to pass result to Node-RED. (to avoid a loopback add`ui_control.callback="someText"`)
```javascript
this.send({topic: "anyTopic",payload:"anyPayload",ui_control: {callback:"myCallback"}});
```
- all parameters are named according to tabulator documentation. Use ```field``` instead of ```Property``` used in node configuration
- no validation of `msg.ui_control` data is performed! So if you don`t get the results you expect take a look on your browsers console.

View File

@@ -0,0 +1,64 @@
[
{
"id": "bc380b4b.e2d668",
"type": "inject",
"z": "9663b812.93cc28",
"name": "",
"topic": "",
"payload": "[{\"Name\":\"Kazuhito Yokoi\",\"Age\":\"35\",\"Favourite Color\":\"red\",\"Date Of Birth\":\"12/09/1983\"},{\"Name\":\"Oli Bob\",\"Age\":\"12\",\"Favourite Color\":\"red\",\"Date Of Birth\":\"12/08/2017\"}]",
"payloadType": "json",
"repeat": "",
"crontab": "",
"once": false,
"onceDelay": 0.1,
"x": 150,
"y": 220,
"wires": [
[
"2460c057.cfbc4"
]
]
},
{
"id": "2460c057.cfbc4",
"type": "ui_table",
"z": "9663b812.93cc28",
"group": "625872f.40b1e8c",
"name": "",
"width": 0,
"height": 4,
"columns": [],
"x": 350,
"y": 220,
"wires": []
},
{
"id": "9e33f566.8c9098",
"type": "comment",
"z": "9663b812.93cc28",
"name": "Normal table",
"info": "",
"x": 150,
"y": 180,
"wires": []
},
{
"id": "625872f.40b1e8c",
"type": "ui_group",
"z": "",
"name": "Default",
"tab": "58c2aa06.ef46e4",
"disp": true,
"width": "6",
"collapse": false
},
{
"id": "58c2aa06.ef46e4",
"type": "ui_tab",
"z": "",
"name": "Home",
"icon": "dashboard",
"disabled": false,
"hidden": false
}
]

View File

@@ -0,0 +1,148 @@
[
{
"id": "b7dff285.69049",
"type": "inject",
"z": "bb6af731.9866a8",
"name": "",
"topic": "",
"payload": "[{\"Name\":\"<b>Yokoi</b>\",\"Age\":\"30\",\"Color\":\"lime\",\"Prog\":70,\"Star\":\"3\"},{\"Name\":\"<i>DCJ</i>\",\"Age\":\"50\",\"Color\":\"dodgerblue\",\"Prog\":\"45\",\"Star\":2,\"Pass\":false,\"web\":\"\"},{\"Name\":\"Nick\",\"Age\":\"40\",\"Color\":\"darkred\",\"Prog\":95,\"Star\":\"5\",\"Pass\":true,\"web\":\"http://nodered.org\"},{\"Name\":\"Oli\"}]",
"payloadType": "json",
"repeat": "",
"crontab": "",
"once": false,
"onceDelay": 0.1,
"x": 210,
"y": 580,
"wires": [
[
"7d48e13.90ee22"
]
]
},
{
"id": "cb53cb76.5fd0d8",
"type": "inject",
"z": "bb6af731.9866a8",
"name": "",
"topic": "",
"payload": "[{\"Name\":\"<b>Yokoi</b>\",\"Age\":\"30\",\"Color\":\"lime\",\"Prog\":20,\"Star\":\"1\"},{\"Name\":\"<i>DCJ</i>\",\"Age\":\"50\",\"Color\":\"dodgerblue\",\"Prog\":\"80\",\"Star\":4,\"Pass\":true,\"web\":\"\"},{\"Name\":\"Nick\",\"Age\":\"40\",\"Color\":\"red\",\"Prog\":90,\"Star\":\"5\",\"Pass\":true,\"web\":\"http://nodered.org\"},{\"Name\":\"Oli\"}]",
"payloadType": "json",
"repeat": "",
"crontab": "",
"once": false,
"onceDelay": 0.1,
"x": 210,
"y": 620,
"wires": [
[
"7d48e13.90ee22"
]
]
},
{
"id": "7d48e13.90ee22",
"type": "ui_table",
"z": "bb6af731.9866a8",
"group": "571a38b1.5e3638",
"name": "People",
"order": 1,
"width": "8",
"height": "3",
"columns": [
{
"field": "Name",
"title": "Who",
"width": "",
"align": "left",
"formatter": "html",
"formatterParams": {
"target": "_blank"
}
},
{
"field": "Age",
"title": "Age",
"width": "40",
"align": "center",
"formatter": "plaintext",
"formatterParams": {
"target": "_blank"
}
},
{
"field": "Color",
"title": "",
"width": "5%",
"align": "left",
"formatter": "color",
"formatterParams": {
"target": "_blank"
}
},
{
"field": "Star",
"title": "%",
"width": "100",
"align": "left",
"formatter": "star",
"formatterParams": {
"target": "_blank"
}
},
{
"field": "Pass",
"title": "",
"width": "5%",
"align": "center",
"formatter": "tickCross",
"formatterParams": {
"target": "_blank"
}
},
{
"field": "Prog",
"title": "",
"width": "80",
"align": "left",
"formatter": "progress",
"formatterParams": {
"target": "_blank"
}
},
{
"field": "web",
"title": "URL",
"width": "",
"align": "left",
"formatter": "link",
"formatterParams": {
"target": "_blank"
}
}
],
"x": 420,
"y": 580,
"wires": []
},
{
"id": "571a38b1.5e3638",
"type": "ui_group",
"z": "",
"name": "Richer Table",
"tab": "29ec6908.552b36",
"order": 1,
"disp": true,
"width": "8",
"collapse": false
},
{
"id": "29ec6908.552b36",
"type": "ui_tab",
"z": "",
"name": "Home",
"icon": "track_changes",
"order": 1,
"disabled": false,
"hidden": false
}
]

View File

@@ -0,0 +1,105 @@
[
{
"id": "ba92cba0.ee4ad8",
"type": "inject",
"z": "fbd51901.ad38e8",
"name": "",
"topic": "",
"payload": "[{\"name\":\"MEQ0451495\",\"room\":\"Bathroom\",\"SET_TEMPERATURE-value\":22,\"ACTUAL_TEMPERATURE-value\":21.8,\"VALVE_STATE-value\":90,\"BATTERY_STATE-value\":2.7,\"BOOST_STATE-value\":0,\"AUTO_MODE-value\":true,\"CONTROL_MODE-value\":0},{\"name\":\"MEQ1875547\",\"room\":\"Living Room\",\"SET_TEMPERATURE-value\":12,\"ACTUAL_TEMPERATURE-value\":16.2,\"VALVE_STATE-value\":0,\"BATTERY_STATE-value\":2.7,\"BOOST_STATE-value\":0,\"AUTO_MODE-value\":false,\"CONTROL_MODE-value\":1},{\"name\":\"MEQ1875538\",\"room\":\"Living Room\",\"SET_TEMPERATURE-value\":18,\"ACTUAL_TEMPERATURE-value\":19.5,\"VALVE_STATE-value\":0,\"BATTERY_STATE-value\":2.6,\"BOOST_STATE-value\":0,\"AUTO_MODE-value\":false,\"CONTROL_MODE-value\":2},{\"name\":\"MEQ0447462\",\"room\":\"Kitchen\",\"SET_TEMPERATURE-value\":17,\"ACTUAL_TEMPERATURE-value\":22.2,\"VALVE_STATE-value\":0,\"BATTERY_STATE-value\":2.7,\"BOOST_STATE-value\":10,\"AUTO_MODE-value\":false,\"CONTROL_MODE-value\":3},{\"name\":\"MEQ1875551\",\"room\":\"Office\",\"SET_TEMPERATURE-value\":18,\"ACTUAL_TEMPERATURE-value\":20.2,\"VALVE_STATE-value\":0,\"BATTERY_STATE-value\":2.7,\"BOOST_STATE-value\":0,\"AUTO_MODE-value\":false,\"CONTROL_MODE-value\":0},{\"name\":\"MEQ0447425\",\"room\":\"Dining Room\",\"SET_TEMPERATURE-value\":19,\"ACTUAL_TEMPERATURE-value\":20.4,\"VALVE_STATE-value\":0,\"BATTERY_STATE-value\":2.7,\"BOOST_STATE-value\":0,\"AUTO_MODE-value\":false,\"CONTROL_MODE-value\":0},{\"name\":\"MEQ1875546\",\"room\":\"Dining Room\",\"SET_TEMPERATURE-value\":20,\"ACTUAL_TEMPERATURE-value\":18.8,\"VALVE_STATE-value\":99,\"BATTERY_STATE-value\":2.7,\"BOOST_STATE-value\":0,\"AUTO_MODE-value\":false,\"CONTROL_MODE-value\":0},{\"name\":\"MEQ0447483\",\"room\":\"Bedroom\",\"SET_TEMPERATURE-value\":17,\"ACTUAL_TEMPERATURE-value\":22.4,\"VALVE_STATE-value\":0,\"BATTERY_STATE-value\":2.7,\"BOOST_STATE-value\":0,\"AUTO_MODE-value\":false,\"CONTROL_MODE-value\":0},{\"name\":\"MEQ1875541\",\"room\":\"Child\",\"SET_TEMPERATURE-value\":18,\"ACTUAL_TEMPERATURE-value\":20.4,\"VALVE_STATE-value\":0,\"BATTERY_STATE-value\":2.7,\"BOOST_STATE-value\":0,\"AUTO_MODE-value\":false,\"CONTROL_MODE-value\":0},{\"name\":\"MEQ1875552\",\"room\":\"Guest Room\",\"SET_TEMPERATURE-value\":20,\"ACTUAL_TEMPERATURE-value\":21.1,\"VALVE_STATE-value\":9,\"BATTERY_STATE-value\":2.8,\"BOOST_STATE-value\":0,\"AUTO_MODE-value\":false,\"CONTROL_MODE-value\":0}]",
"payloadType": "json",
"repeat": "",
"crontab": "",
"once": false,
"onceDelay": 0.1,
"x": 169,
"y": 221,
"wires": [
[
"8115c722.5d91d8"
]
]
},
{
"id": "8115c722.5d91d8",
"type": "change",
"z": "fbd51901.ad38e8",
"name": "ui_control",
"rules": [
{
"t": "set",
"p": "ui_control",
"pt": "msg",
"to": "{\"tabulator\":{\"columnResized\":\"function(column){ var newColumn = { field: column._column.field, visible: column._column.visible, width: column._column.width, widthFixed: column._column.widthFixed, widthStyled: column._column.widthStyled }; this.send({topic:this.config.topic,ui_control:{callback:'columnResized',columnWidths:newColumn}}); }\",\"columnMoved\":\"function(column, columns){ var newColumns=[]; columns.forEach(function (column) { newColumns.push({'field': column._column.field}); }); this.send({topic:this.config.topic,ui_control:{callback:'columnMoved',columns:newColumns}}); }\",\"groupHeader\":\"function (value, count, data, group) {return value + \\\"<span style='color:#d00; margin-left:10px;'>(\\\" + count + \\\" Termostat\\\"+((count>1) ? \\\"e\\\" : \\\"\\\") + \\\")</span>\\\";}\",\"columns\":[{\"formatterParams\":{\"target\":\"_blank\"},\"title\":\"ROom\",\"field\":\"room\",\"width\":100,\"frozen\":true},{\"formatterParams\":{\"target\":\"_blank\"},\"title\":\"Device\",\"field\":\"name\",\"width\":100,\"align\":\"center\"},{\"formatterParams\":{\"target\":\"_blank\"},\"title\":\"Type\",\"field\":\"deviceType\",\"width\":100,\"align\":\"center\"},{\"formatterParams\":{\"target\":\"_blank\"},\"title\":\"Measurements\",\"columns\":[{\"formatterParams\":{\"target\":\"_blank\"},\"title\":\"target\",\"field\":\"SET_TEMPERATURE-value\",\"formatter\":\"function(cell, formatterParams, onRendered){return cell.getValue()+'°C';}\",\"topCalc\":\"avg\",\"width\":100},{\"formatterParams\":{\"target\":\"_blank\",\"min\":10,\"max\":25,\"color\":[\"blue\",\"green\",\"red\"],\"legend\":\"function (value) {return '&nbsp;&nbsp;'+value+'°C';}\",\"legendColor\":\"#101010\",\"legendAlign\":\"left\"},\"title\":\"current\",\"field\":\"ACTUAL_TEMPERATURE-value\",\"formatter\":\"progress\",\"topCalc\":\"avg\",\"width\":100},{\"formatterParams\":{\"target\":\"_blank\",\"min\":0,\"max\":99,\"color\":[\"gray\",\"orange\",\"red\"],\"legend\":\"function (value) {return (value>0)? '&nbsp;&nbsp;'+value+' %' : '-';}\",\"legendColor\":\"#101010\",\"legendAlign\":\"center\"},\"title\":\"Valve\",\"field\":\"VALVE_STATE-value\",\"formatter\":\"progress\",\"topCalc\":\"max\",\"width\":100},{\"formatterParams\":{\"target\":\"_blank\",\"min\":1.5,\"max\":4.6,\"color\":[\"red\",\"orange\",\"green\"],\"legend\":\"function (value) {return value+' V';}\",\"legendColor\":\"#101010\",\"legendAlign\":\"center\"},\"title\":\"Batt\",\"field\":\"BATTERY_STATE-value\",\"formatter\":\"progress\",\"topCalc\":\"min\",\"width\":100}]},{\"formatterParams\":{\"target\":\"_blank\"},\"title\":\"Settings\",\"columns\":[{\"formatterParams\":{\"target\":\"_blank\",\"min\":0,\"max\":30,\"color\":[\"red\",\"orange\",\"green\"],\"legend\":\"function (value) { if (value>0) return \\\"<span style='color:#101010;'>\\\"+value+\\\" min</span>\\\"; else return \\\"<span style='color:#A0A0A0;'>aus</span>\\\"; }\",\"legendColor\":\"#101010\",\"legendAlign\":\"center\"},\"title\":\"Boost\",\"field\":\"BOOST_STATE-value\",\"formatter\":\"progress\",\"width\":100},{\"formatterParams\":{\"target\":\"_blank\",\"allowEmpty\":true,\"allowTruthy\":true,\"tickElement\":\"<i class='fa fa-clock-o'></i>\",\"crossElement\":\"<i class='fa fa-ban'></i>\"},\"title\":\"Auto\",\"field\":\"AUTO_MODE-value\",\"formatter\":\"tickCross\",\"width\":100,\"align\":\"center\"},{\"formatterParams\":{\"target\":\"_blank\"},\"title\":\"Mode\",\"field\":\"CONTROL_MODE-value\",\"formatter\":\"function(cell, formatterParams, onRendered){ var html=\\\"<i class=\\\\\\\"\\\"; switch(cell.getValue()) { case 0: html+=\\\"fa fa-calendar-check-o\\\"; break; case 1: html+=\\\"fa fa-hand-o-up\\\"; break; case 2: html+=\\\"fa fa-suitcase\\\"; break; case 3: html+=\\\"fa fa-spinner fa-spin fa-fw\\\"; break; } html+='\\\\\\\"></i>'; return html; }\",\"width\":100,\"align\":\"center\"},{\"formatterParams\":{\"target\":\"_blank\"},\"title\":\"Auto\",\"field\":\"AUTO_MODE-value\",\"formatter\":\"tick\",\"width\":100,\"align\":\"center\"}]}],\"layout\":\"fitColumns\",\"movableColumns\":true,\"groupBy\":\"\"},\"customHeight\":12}",
"tot": "json"
}
],
"action": "",
"property": "",
"from": "",
"to": "",
"reg": false,
"x": 315,
"y": 221,
"wires": [
[
"4b960bb2.f61934"
]
]
},
{
"id": "5d38f5fa.6541bc",
"type": "debug",
"z": "fbd51901.ad38e8",
"name": "",
"active": true,
"tosidebar": true,
"console": false,
"tostatus": false,
"complete": "true",
"targetType": "full",
"x": 628,
"y": 221,
"wires": []
},
{
"id": "4b960bb2.f61934",
"type": "ui_table",
"z": "fbd51901.ad38e8",
"group": "51ce6aa1.620754",
"name": "Thermostats",
"order": 1,
"width": "20",
"height": "7",
"columns": [],
"outputs": 1,
"cts": true,
"x": 478,
"y": 221,
"wires": [
[
"5d38f5fa.6541bc"
]
]
},
{
"id": "51ce6aa1.620754",
"type": "ui_group",
"z": "",
"name": "ui_control",
"tab": "3b08fac0.8f06b6",
"order": 1,
"disp": true,
"width": "22",
"collapse": false
},
{
"id": "3b08fac0.8f06b6",
"type": "ui_tab",
"z": "",
"name": "Home",
"icon": "track_changes",
"order": 1,
"disabled": false,
"hidden": false
}
]

View File

@@ -0,0 +1,944 @@
[
{
"id": "b075d2ac.a69f3",
"type": "ui_table",
"z": "292ca715.a2db08",
"group": "237da972.5d69a6",
"name": "",
"order": 0,
"width": "17",
"height": "9",
"columns": [
{
"field": "id",
"title": "id",
"width": "",
"align": "right",
"formatter": "plaintext",
"formatterParams": {
"target": "_blank"
}
},
{
"field": "timestamp",
"title": "Timestamp",
"width": "",
"align": "left",
"formatter": "plaintext",
"formatterParams": {
"target": "_blank"
}
},
{
"field": "text",
"title": "Text",
"width": "",
"align": "left",
"formatter": "plaintext",
"formatterParams": {
"target": "_blank"
}
}
],
"outputs": 1,
"cts": true,
"x": 866,
"y": 425,
"wires": [
[
"588f316.0b070d",
"76c4495f.da70f8"
]
]
},
{
"id": "f8a9323b.fedf4",
"type": "inject",
"z": "292ca715.a2db08",
"name": "add @ top",
"topic": "",
"payload": "",
"payloadType": "date",
"repeat": "",
"crontab": "",
"once": false,
"onceDelay": 0.1,
"x": 230,
"y": 323,
"wires": [
[
"eb577b4b.510388"
]
]
},
{
"id": "b54f6ce8.3b1a4",
"type": "debug",
"z": "292ca715.a2db08",
"name": "addRow",
"active": false,
"tosidebar": true,
"console": false,
"tostatus": false,
"complete": "true",
"targetType": "full",
"x": 451,
"y": 425,
"wires": []
},
{
"id": "eb577b4b.510388",
"type": "function",
"z": "292ca715.a2db08",
"name": "addRow @ top",
"func": "var id=flow.get(\"lastId\") || 0;\n++id;\nmsg.payload={\n command:\"addRow\",\n arguments: [\n [\n {\n \"id\":id,\n \"timestamp\":msg.payload,\n \"text\":\"addRow @ top (#\"+id+\")\"\n }\n ],\n true\n ],\n returnPromise: true\n}\nflow.set(\"lastId\",id);\nreturn msg;",
"outputs": 1,
"noerr": 0,
"x": 471,
"y": 289,
"wires": [
[
"b54f6ce8.3b1a4",
"b075d2ac.a69f3"
]
],
"info": "# addRow([row],onTop)\n\n`onTop=true`\n\nadds a new Row on top of the table"
},
{
"id": "588f316.0b070d",
"type": "debug",
"z": "292ca715.a2db08",
"name": "response from ui-table",
"active": true,
"tosidebar": true,
"console": false,
"tostatus": false,
"complete": "true",
"targetType": "full",
"x": 1171,
"y": 425,
"wires": []
},
{
"id": "12606591.7a3dca",
"type": "inject",
"z": "292ca715.a2db08",
"name": "Init 20 rows",
"topic": "",
"payload": "20",
"payloadType": "num",
"repeat": "",
"crontab": "",
"once": false,
"onceDelay": 0.1,
"x": 240,
"y": 153,
"wires": [
[
"d4dce9b4.1f2588"
]
]
},
{
"id": "d4dce9b4.1f2588",
"type": "function",
"z": "292ca715.a2db08",
"name": "table with n rows as array",
"func": "var numberOfRows = msg.payload;\nflow.set(\"lastId\",numberOfRows);\nmsg.payload=[];\nfor (let i=1; i<=numberOfRows; i++) {\n msg.payload.push({\"id\":i,\"timestamp\":Date.now(),\"text\":\"this is line\"+i})\n}\nreturn msg;",
"outputs": 1,
"noerr": 0,
"x": 501,
"y": 119,
"wires": [
[
"b075d2ac.a69f3",
"f9bfd98.abe1a28",
"76c4495f.da70f8"
]
]
},
{
"id": "8254f2d2.eeaa1",
"type": "function",
"z": "292ca715.a2db08",
"name": "updateOrAddData (add)",
"func": "var id=flow.get(\"lastId\") || 0;\n++id;\nmsg.payload={\n command:\"updateOrAddData\",\n arguments: [\n [\n {\n \"id\":id,\n \"timestamp\":msg.payload,\n \"text\":\"updateOrAddData (add) (#\"+id+\")\"\n }\n ]\n ],\n returnPromise: true\n}\nflow.set(\"lastId\",id);\nreturn msg;",
"outputs": 1,
"noerr": 0,
"x": 501,
"y": 476,
"wires": [
[
"570e922d.1d465c",
"b075d2ac.a69f3"
]
],
"info": "# updateOrAddData([row])\n\nadds a the row with a new id (same as addRow)"
},
{
"id": "cbd6baa0.fa7d78",
"type": "inject",
"z": "292ca715.a2db08",
"name": "add",
"topic": "",
"payload": "",
"payloadType": "date",
"repeat": "",
"crontab": "",
"once": false,
"onceDelay": 0.1,
"x": 220,
"y": 510,
"wires": [
[
"8254f2d2.eeaa1"
]
]
},
{
"id": "570e922d.1d465c",
"type": "debug",
"z": "292ca715.a2db08",
"name": "updateOrAddData",
"active": false,
"tosidebar": true,
"console": false,
"tostatus": false,
"complete": "true",
"targetType": "full",
"x": 481,
"y": 595,
"wires": []
},
{
"id": "782ab41e.cbb66c",
"type": "inject",
"z": "292ca715.a2db08",
"name": "add @ end",
"topic": "",
"payload": "",
"payloadType": "date",
"repeat": "",
"crontab": "",
"once": false,
"onceDelay": 0.1,
"x": 230,
"y": 408,
"wires": [
[
"760fde70.028f"
]
]
},
{
"id": "760fde70.028f",
"type": "function",
"z": "292ca715.a2db08",
"name": "addRow @ end",
"func": "var id=flow.get(\"lastId\") || 0;\n++id;\nmsg.payload={\n command:\"addRow\",\n arguments: [\n [\n {\n \"id\":id,\n \"timestamp\":msg.payload,\n \"text\":\"addRow @ end (#\"+id+\")\"\n }\n ],\n false\n ],\n returnPromise: true\n}\nflow.set(\"lastId\",id);\nreturn msg;",
"outputs": 1,
"noerr": 0,
"x": 471,
"y": 374,
"wires": [
[
"b54f6ce8.3b1a4",
"b075d2ac.a69f3"
]
],
"info": "# addRow([row],onTop)\n\n`onTop=false`\n\nadds a new Row on top of the table"
},
{
"id": "deeff963.289f08",
"type": "function",
"z": "292ca715.a2db08",
"name": "updateOrAddData (update)",
"func": "var id=flow.get(\"lastId\") || 0;\nif (id<2) {\n node.error(\"use only if minimum of 2 Lines existing!\")\n return;\n}\n\nid=Math.floor(id/2); //\nmsg.payload={\n command:\"updateOrAddData\",\n arguments: [\n [\n {\n \"id\":id,\n \"timestamp\":msg.payload,\n \"text\":\"updateOrAddData (update) (#\"+id+\")\"\n }\n ]\n ],\n returnPromise: true\n}\nreturn msg;",
"outputs": 1,
"noerr": 0,
"x": 511,
"y": 544,
"wires": [
[
"570e922d.1d465c",
"b075d2ac.a69f3"
]
],
"info": "# updateOrAddData([row])\n\nupdates a the row with an id in the middle from 1 to lastId, hope it exists!\nIf not a row will be added"
},
{
"id": "557e109d.f9d7e",
"type": "comment",
"z": "292ca715.a2db08",
"name": "update ui-table by passing the complete tableData as array",
"info": "",
"x": 363,
"y": 68,
"wires": []
},
{
"id": "6a095f36.8f13a",
"type": "comment",
"z": "292ca715.a2db08",
"name": "update ui-table by using commands",
"info": "",
"x": 293,
"y": 238,
"wires": []
},
{
"id": "f08308d6.c66f68",
"type": "inject",
"z": "292ca715.a2db08",
"name": "update",
"topic": "",
"payload": "",
"payloadType": "date",
"repeat": "",
"crontab": "",
"once": false,
"onceDelay": 0.1,
"x": 220,
"y": 578,
"wires": [
[
"deeff963.289f08"
]
]
},
{
"id": "77b4d006.543ed",
"type": "function",
"z": "292ca715.a2db08",
"name": "deleteRow",
"func": "var id=flow.get(\"lastId\") || 0;\nif (id<2) {\n node.error(\"use only if minimum of 2 Lines existing!\")\n return;\n}\n\nid=Math.floor(id/2); //\nmsg.payload={\n command:\"deleteRow\",\n arguments: [id],\n returnPromise: true\n}\nreturn msg;",
"outputs": 1,
"noerr": 0,
"x": 461,
"y": 697,
"wires": [
[
"e34a75a3.9f0188",
"b075d2ac.a69f3"
]
],
"info": "# deleteRow(row / [rows])\n\n`row=singleId`\n\nor\n\n`row=[array of IDs]` // seems there is a bug/issue in tabulator\n\ndelete a single the row with an id in the middle from 1 to lastId, hope it exists.\n\nWill fail on the second hit if you inject this two times because the id wad deleteted on the first"
},
{
"id": "936c8219.458bc",
"type": "inject",
"z": "292ca715.a2db08",
"name": "delete",
"topic": "",
"payload": "",
"payloadType": "date",
"repeat": "",
"crontab": "",
"once": false,
"onceDelay": 0.1,
"x": 220,
"y": 731,
"wires": [
[
"77b4d006.543ed"
]
]
},
{
"id": "e34a75a3.9f0188",
"type": "debug",
"z": "292ca715.a2db08",
"name": "deleteRow",
"active": false,
"tosidebar": true,
"console": false,
"tostatus": false,
"complete": "true",
"targetType": "full",
"x": 461,
"y": 816,
"wires": []
},
{
"id": "fafa24f8.577d28",
"type": "comment",
"z": "292ca715.a2db08",
"name": "deleteRow will punch holes in table!",
"info": "",
"x": 293,
"y": 646,
"wires": []
},
{
"id": "f9bfd98.abe1a28",
"type": "debug",
"z": "292ca715.a2db08",
"name": "addRow",
"active": false,
"tosidebar": true,
"console": false,
"tostatus": false,
"complete": "true",
"targetType": "full",
"x": 451,
"y": 170,
"wires": []
},
{
"id": "76c4495f.da70f8",
"type": "function",
"z": "292ca715.a2db08",
"name": "table recorder",
"func": "var status = {fill:\"red\",shape:\"ring\",text:\"an error occured\"};\nvar success = (msg.topic && msg.topic===\"success\") || false;\nvar tableData = flow.get(\"tableData\");\nif (tableData === undefined) {\n tableData = [];\n flow.set(\"tableData\",tableData);\n}\n\n// find the index for a row in tableData for a given index (id)\nfunction checkIndex(id) {\n let matchRow=-1\n tableData.forEach(function (row,index){\n if (row.id === id){\n matchRow=index;\n return matchRow;\n }\n })\n return matchRow;\n}\n\n// flat merge one row \nfunction mergeRow(dest,source) {\n Object.keys(source).forEach(function(key) {\n dest[key]=source[key];\n })\n}\n\n//merge or add one or many rows into tableData \nfunction mergeData(newData,toTop) {\n newData.forEach(function (item,index) {\n node.warn([\"findIndex\",item]);\n let row=checkIndex(item.id);\n if (row<0) { // row do not existst in tableData\n if (toTop) {\n tableData.push(item);\n status.text+=\"newRow @ top\";\n } else {\n tableData.unshift(item);\n status.text+=\"newRow @ bottom\";\n }\n return;\n } else { // row exists so update\n mergeRow(tableData[row],item);\n status.text+=\"row updated\";\n return;\n }\n if (status.text!==\"\") node.status(status);\n });\n}\n\nswitch (typeof msg.payload){\n case \"string\":\n node.warn([\"[table recorder] \",(typeof msg.payload),msg.payload]);\n switch (msg.payload){\n case \"change\":\n status={fill:\"green\",shape:\"dot\",text:\"table restored \"+tableData.length+\" rows\"};\n msg.payload=tableData;\n break;\n }\n break;\n case \"object\":\n node.warn([\"[table recorder] \",(typeof msg.payload),msg.payload]);\n if (Array.isArray(msg.payload)) { // replace all tableData\n status={fill:\"green\",shape:\"dot\",text:\"table replaced \"+msg.payload.length+\" rows\"};\n tableData=RED.util.cloneMessage(msg.payload); \n } else {\n switch (msg.payload.command) { // clearData does not return a promise!\n case \"clearData\":\n status={fill:\"green\",shape:\"dot\",text:\"clearData: done\"};\n tableData=[];\n flow.set(\"lastId\",0);\n break; \n }\n }\n break;\n default: // likely a msg fom a ui-table command or callback\n if (msg.hasOwnProperty(\"topic\")&&\n msg.hasOwnProperty(\"ui_control\") && \n msg.ui_control.hasOwnProperty(\"callback\") &&\n msg.hasOwnProperty(\"return\")) { // message originates from a ui-table callback\n if (success) {\n switch(msg.return.command) {\n case \"addRow\":\n status.text=\"addRow: \";\n mergeData(msg.return.arguments[0],msg.return.arguments[1]);\n status.shape=\"dot\";\n break;\n case \"updateOrAddData\":\n status.text=\"updateOrAddData: \";\n mergeData(msg.return.arguments[0]);\n break;\n case \"deleteRow\":\n let row=checkIndex(msg.return.arguments[0]);\n tableData.splice(row,1);\n status.shape=\"dot\";\n status.text=\"deleteRow: \"+row+\" deleted\";\n break;\n default:\n status={fill:\"yellow\",shape:\"dot\",text:msg.return.command + \" unknown!\"};\n break; \n }\n } else {\n status.text=msg.topic+\" \"+msg.error;\n }\n }\n break;\n}\nif (success) status.fill=\"green\";\nflow.set(\"tableData\",tableData);\nnode.status(status);\nreturn msg;",
"outputs": 1,
"noerr": 0,
"x": 1151,
"y": 493,
"wires": [
[
"b075d2ac.a69f3"
]
],
"icon": "font-awesome/fa-database",
"info": "# simple ui-table handler\n## abstract\nUsing ui-table with commands offer the hole flexibilty of tabulator. The table can be manipulated down to cell level.\nAs the ui-table node only passes the commands to tabulator and receives promises back the node does not hold the table data. If the data should be available after refresh, tab change, new connections the flow is responsible to cache the data and all the manipulations.\nThis node takes care of most simple data manipulation commands and holds a copy of the data in `flow.context.tabledata`\n\n## details\n\n### row index (id)\n\nTo identify a [row a index](http://tabulator.info/docs/4.5/data#overview) column has to be defined. This colum defaults to `id` but can be changed by specifing a **field** by using `msg.ui_control`. In this example the row index is a simple counter adding up by one if a new line is added.\n\n### addRow command\n\n[details @ tabulator addRow docs](http://tabulator.info/docs/4.5/update#alter-add)\n\nYou can add a row by sending the `addRow` command. You can decide if the row adds on the top or at the bottom of table.\n\n### addOrUpdate command\n\n[details @ tabulator addOrUpdate docs](http://tabulator.info/docs/4.5/update#alter-update)\n\nTo update data the best way is to use the `addOrUpdate` command. If the row indetified by the index is not exeisting a new row will be added automatically\n\n### deleteRow command\n\n[details @ tabulator deleteRow docs](http://tabulator.info/docs/4.5/update#row)\n\nDelete one or more rows (passing an array always results in \"row not found error\"! I think there is an issue in tabulator)\n\n### clearData\n\n[details @ tabulator clearData docs](http://tabulator.info/docs/4.5/update#alter-empty)\n\nunfortunately this command (currently) do not send a promise back! So we have to pass it directly to the table handler"
},
{
"id": "7b1c27f4.36a718",
"type": "ui_ui_control",
"z": "292ca715.a2db08",
"name": "",
"events": "all",
"x": 876,
"y": 493,
"wires": [
[
"76c4495f.da70f8"
]
]
},
{
"id": "8b79840b.aff7e8",
"type": "inject",
"z": "292ca715.a2db08",
"d": true,
"name": "delete 1-5",
"topic": "",
"payload": "",
"payloadType": "date",
"repeat": "",
"crontab": "",
"once": false,
"onceDelay": 0.1,
"x": 230,
"y": 765,
"wires": [
[
"fee8b78d.068f98"
]
]
},
{
"id": "fee8b78d.068f98",
"type": "function",
"z": "292ca715.a2db08",
"d": true,
"name": "delete Rows [2,4,6,8,10]",
"func": "var id=flow.get(\"lastId\") || 0;\nif (id<10) {\n node.error(\"use only if minimum of 10 Lines existing!\")\n return;\n}\n\nid=Math.floor(id/2); //\nmsg.payload={\n command:\"deleteRow\",\n arguments: [[2,4,6,8,10]],\n returnPromise: true\n}\nreturn msg;",
"outputs": 1,
"noerr": 0,
"x": 501,
"y": 765,
"wires": [
[
"b075d2ac.a69f3",
"e34a75a3.9f0188"
]
],
"info": "# deleteRow(row / [rows])\n\n`row=singleId`\n\nor\n\n`row=[array of IDs]` // seems there is a bug/issue in tabulator\n\ndelete a single the row with an id in the middle from 1 to lastId, hope it exists.\n\nWill fail on the second hit if you inject this two times because the id wad deleteted on the first"
},
{
"id": "fe4ba122.df8fb",
"type": "function",
"z": "292ca715.a2db08",
"name": "clearData",
"func": "\nmsg.payload={\n command:\"clearData\",\n arguments: [],\n returnPromise: true\n}\nreturn msg;",
"outputs": 1,
"noerr": 0,
"x": 451,
"y": 935,
"wires": [
[
"6e49e266.f72b6c",
"b075d2ac.a69f3",
"76c4495f.da70f8"
]
],
"info": "# clear data\n\nunfortunately this command (currently) do not send a promise back! So we have to pass it directly to the table handler"
},
{
"id": "82194704.7ab2d8",
"type": "inject",
"z": "292ca715.a2db08",
"name": "clear",
"topic": "",
"payload": "",
"payloadType": "date",
"repeat": "",
"crontab": "",
"once": false,
"onceDelay": 0.1,
"x": 220,
"y": 969,
"wires": [
[
"fe4ba122.df8fb"
]
]
},
{
"id": "df623146.8270a",
"type": "comment",
"z": "292ca715.a2db08",
"name": "Erase all data by using clearData command",
"info": "",
"x": 323,
"y": 884,
"wires": []
},
{
"id": "6e49e266.f72b6c",
"type": "debug",
"z": "292ca715.a2db08",
"name": "clearData",
"active": true,
"tosidebar": true,
"console": false,
"tostatus": false,
"complete": "true",
"targetType": "full",
"x": 451,
"y": 986,
"wires": []
},
{
"id": "d404def3.39a63",
"type": "inject",
"z": "292ca715.a2db08",
"name": "change",
"topic": "",
"payload": "change",
"payloadType": "str",
"repeat": "",
"crontab": "",
"once": false,
"onceDelay": 0.1,
"x": 866,
"y": 561,
"wires": [
[
"76c4495f.da70f8"
]
]
},
{
"id": "36be75f0.115c6a",
"type": "ui_button",
"z": "292ca715.a2db08",
"name": "",
"group": "c91332c0.50c11",
"order": 1,
"width": 0,
"height": 0,
"passthru": false,
"label": "Init 20 rows",
"tooltip": "init table by passing the hole table array (default way)",
"color": "",
"bgcolor": "",
"icon": "",
"payload": "20",
"payloadType": "num",
"topic": "",
"x": 240,
"y": 119,
"wires": [
[
"d4dce9b4.1f2588"
]
]
},
{
"id": "b496aa6a.32f2d8",
"type": "ui_button",
"z": "292ca715.a2db08",
"name": "",
"group": "c91332c0.50c11",
"order": 2,
"width": 0,
"height": 0,
"passthru": false,
"label": "add one row @ top",
"tooltip": "add a new row to the top",
"color": "",
"bgcolor": "",
"icon": "",
"payload": "",
"payloadType": "date",
"topic": "",
"x": 260,
"y": 289,
"wires": [
[
"eb577b4b.510388"
]
]
},
{
"id": "79d05aaa.e2c7d4",
"type": "ui_button",
"z": "292ca715.a2db08",
"name": "",
"group": "c91332c0.50c11",
"order": 3,
"width": 0,
"height": 0,
"passthru": false,
"label": "add one row @ end",
"tooltip": "add a new row at the end ",
"color": "",
"bgcolor": "",
"icon": "",
"payload": "",
"payloadType": "date",
"topic": "",
"x": 260,
"y": 374,
"wires": [
[
"760fde70.028f"
]
]
},
{
"id": "d37bf3a8.373dd",
"type": "ui_button",
"z": "292ca715.a2db08",
"name": "",
"group": "c91332c0.50c11",
"order": 4,
"width": 0,
"height": 0,
"passthru": false,
"label": "addOrUpdate (add)",
"tooltip": "add a new row by passing a new id",
"color": "",
"bgcolor": "",
"icon": "",
"payload": "",
"payloadType": "date",
"topic": "",
"x": 260,
"y": 476,
"wires": [
[
"8254f2d2.eeaa1"
]
]
},
{
"id": "d31c2ac7.05bed8",
"type": "ui_button",
"z": "292ca715.a2db08",
"name": "",
"group": "c91332c0.50c11",
"order": 5,
"width": 0,
"height": 0,
"passthru": false,
"label": "addOrUpdate (update)",
"tooltip": "update the row in the middle (or add if a row with that id not exists)",
"color": "",
"bgcolor": "",
"icon": "",
"payload": "",
"payloadType": "date",
"topic": "",
"x": 270,
"y": 544,
"wires": [
[
"deeff963.289f08"
]
]
},
{
"id": "c637efb3.9c38c",
"type": "ui_button",
"z": "292ca715.a2db08",
"name": "",
"group": "c91332c0.50c11",
"order": 6,
"width": 0,
"height": 0,
"passthru": false,
"label": "delete (middle)",
"tooltip": "delate the row with the id=maxId/2. Will result an error if not existing",
"color": "",
"bgcolor": "",
"icon": "",
"payload": "",
"payloadType": "date",
"topic": "",
"x": 250,
"y": 697,
"wires": [
[
"77b4d006.543ed"
]
]
},
{
"id": "5531f2d0.fb913c",
"type": "ui_button",
"z": "292ca715.a2db08",
"name": "",
"group": "c91332c0.50c11",
"order": 7,
"width": 0,
"height": 0,
"passthru": false,
"label": "clear",
"tooltip": "clear all table data",
"color": "",
"bgcolor": "",
"icon": "",
"payload": "",
"payloadType": "date",
"topic": "",
"x": 220,
"y": 935,
"wires": [
[
"fe4ba122.df8fb"
]
]
},
{
"id": "858a6bc2.0384e8",
"type": "ui_text",
"z": "292ca715.a2db08",
"group": "c91332c0.50c11",
"order": 9,
"width": 0,
"height": 0,
"name": "",
"label": "status",
"format": "{{status.text}}",
"layout": "col-center",
"x": 1036,
"y": 731,
"wires": []
},
{
"id": "213d641a.12a53c",
"type": "status",
"z": "292ca715.a2db08",
"name": "",
"scope": [
"76c4495f.da70f8"
],
"x": 875,
"y": 731,
"wires": [
[
"858a6bc2.0384e8"
]
]
},
{
"id": "e7d10007.d6e73",
"type": "ui_button",
"z": "292ca715.a2db08",
"name": "",
"group": "c91332c0.50c11",
"order": 8,
"width": 0,
"height": 0,
"passthru": false,
"label": "refresh (change)",
"tooltip": "Same as ui-control sending a change message",
"color": "",
"bgcolor": "",
"icon": "",
"payload": "change",
"payloadType": "str",
"topic": "",
"x": 896,
"y": 527,
"wires": [
[
"76c4495f.da70f8"
]
]
},
{
"id": "8386c3a7.41ead",
"type": "inject",
"z": "292ca715.a2db08",
"name": "format table",
"topic": "",
"payload": "",
"payloadType": "date",
"repeat": "",
"crontab": "",
"once": false,
"onceDelay": 0.1,
"x": 240,
"y": 1122,
"wires": [
[
"8ae898e7.418068"
]
]
},
{
"id": "f59e9830.e23608",
"type": "comment",
"z": "292ca715.a2db08",
"name": "Format Table using ui_control",
"info": "",
"x": 273,
"y": 1037,
"wires": []
},
{
"id": "19e88f0.0c32071",
"type": "debug",
"z": "292ca715.a2db08",
"name": "clearData",
"active": true,
"tosidebar": true,
"console": false,
"tostatus": false,
"complete": "true",
"targetType": "full",
"x": 451,
"y": 1139,
"wires": []
},
{
"id": "ea064e3c.22437",
"type": "ui_button",
"z": "292ca715.a2db08",
"name": "",
"group": "c91332c0.50c11",
"order": 7,
"width": 0,
"height": 0,
"passthru": false,
"label": "format table",
"tooltip": "Formats the table using msg.ui_control",
"color": "",
"bgcolor": "",
"icon": "",
"payload": "",
"payloadType": "date",
"topic": "",
"x": 240,
"y": 1088,
"wires": [
[
"8ae898e7.418068"
]
]
},
{
"id": "8ae898e7.418068",
"type": "change",
"z": "292ca715.a2db08",
"name": "",
"rules": [
{
"t": "set",
"p": "ui_control",
"pt": "msg",
"to": "{\"customHeight\":18,\"tabulator\":{\"layout\":\"fitColumns\",\"movableColumns\":false,\"index\":\"id\",\"columns\":[{\"title\":\"ID\",\"field\":\"id\",\"formatter\":\"text\",\"headerTooltip\":\"id number act as row index\"},{\"formatterParams\":{\"outputFormat\":\"HH:mm:ss.SSS\",\"inputFormat\":\"x\",\"invalidPlaceholder\":\"(unknown)\"},\"title\":\"Timestamp\",\"field\":\"timestamp\",\"formatter\":\"datetime\",\"headerTooltip\":\"timestamp of last change\"},{\"title\":\"Text\",\"field\":\"text\",\"headerTooltip\":\"last cause of reboot (provided by http json request)\"}]}}",
"tot": "json"
}
],
"action": "",
"property": "",
"from": "",
"to": "",
"reg": false,
"x": 481,
"y": 1088,
"wires": [
[
"19e88f0.0c32071",
"b075d2ac.a69f3",
"6bd61b7.a6a56e4"
]
]
},
{
"id": "6bd61b7.a6a56e4",
"type": "change",
"z": "292ca715.a2db08",
"name": "change",
"rules": [
{
"t": "delete",
"p": "ui_control",
"pt": "msg"
},
{
"t": "set",
"p": "payload",
"pt": "msg",
"to": "change",
"tot": "str"
}
],
"action": "",
"property": "",
"from": "",
"to": "",
"reg": false,
"x": 689,
"y": 1088,
"wires": [
[
"76c4495f.da70f8"
]
]
},
{
"id": "237da972.5d69a6",
"type": "ui_group",
"z": "",
"name": "ui-table with commands",
"tab": "379a501f.53b59",
"disp": true,
"width": "17",
"collapse": false
},
{
"id": "c91332c0.50c11",
"type": "ui_group",
"z": "",
"name": "commands",
"tab": "379a501f.53b59",
"disp": true,
"width": "6",
"collapse": false
},
{
"id": "379a501f.53b59",
"type": "ui_tab",
"z": "",
"name": "ui-table command",
"icon": "fa-table",
"disabled": false,
"hidden": false
}
]

View File

@@ -0,0 +1,174 @@
[
{
"id": "4512106a.2f145",
"type": "change",
"z": "4ddb981f.f34df8",
"name": "ui_control & placeholder",
"rules": [
{
"t": "set",
"p": "ui_control",
"pt": "msg",
"to": "{\"customHeight\":20,\"tabulator\":{\"layout\":\"fitColumns\",\"clipboard\":true,\"clipboardCopySelector\":\"table\",\"clipboardCopyStyled\":false,\"clipboardPasteAction\":\"function(rowData){ this.send({ui_control:{callback:'clipboardPasteAction'},payload:rowData}); return this.table.replaceData(rowData); }\",\"columns\":[{\"field\":\"col1\",\"title\":\"Column #1\"},{\"field\":\"col2\",\"title\":\"Column #2\"},{\"field\":\"col3\",\"title\":\"Column #3\"}]}}",
"tot": "json"
},
{
"t": "set",
"p": "payload",
"pt": "msg",
"to": "[{\"col1\":\"click here & CTRL+v\",\"col2\":\"or click here & CTRL+v\",\"col3\":\"or click here & CTRL+v\"},{\"col1\":\" or on any other cell\",\"col2\":\"\",\"col3\":\"\"},{\"col1\":\"\",\"col2\":\"\",\"col3\":\"\"},{\"col1\":\"\",\"col2\":\"\",\"col3\":\"\"},{\"col1\":\"\",\"col2\":\"\",\"col3\":\"\"},{\"col1\":\"\",\"col2\":\"\",\"col3\":\"\"},{\"col1\":\"\",\"col2\":\"\",\"col3\":\"\"},{\"col1\":\"\",\"col2\":\"\",\"col3\":\"\"},{\"col1\":\"\",\"col2\":\"\",\"col3\":\"\"},{\"col1\":\"\",\"col2\":\"\",\"col3\":\"\"},{\"col1\":\"\",\"col2\":\"\",\"col3\":\"\"},{\"col1\":\"\",\"col2\":\"\",\"col3\":\"\"},{\"col1\":\"there is a issue with small or empty tables\",\"col2\":\"will be dixed soon\",\"col3\":\"\"},{\"col1\":\"Untill then we have\",\"col2\":\"to fill in some\",\"col3\":\"dummy lines\"}]",
"tot": "json"
}
],
"action": "",
"property": "",
"from": "",
"to": "",
"reg": false,
"x": 399,
"y": 255,
"wires": [
[
"71d16773.2b0a38"
]
]
},
{
"id": "8d8d7ea4.2fe3f",
"type": "debug",
"z": "4ddb981f.f34df8",
"name": "clipboardPasteAction",
"active": true,
"tosidebar": true,
"console": false,
"tostatus": false,
"complete": "true",
"targetType": "full",
"x": 1018,
"y": 238,
"wires": []
},
{
"id": "71d16773.2b0a38",
"type": "ui_table",
"z": "4ddb981f.f34df8",
"group": "113a4af6.0aab85",
"name": "Copy & Paste",
"order": 1,
"width": "17",
"height": "7",
"columns": [],
"outputs": 1,
"cts": true,
"x": 641,
"y": 255,
"wires": [
[
"d9789454.020d58"
]
]
},
{
"id": "a0dee6b9.6423c8",
"type": "function",
"z": "4ddb981f.f34df8",
"name": "clipboardPasteAction Callback",
"func": "// callback: clipboardPasteAction\n// DO NOT USE IN A FLOW!\n\nclipboardPasteAction = \n// copy from here\nfunction(rowData){\n this.send({ui_control:{callback:'clipboardPasteAction'},payload:rowData});\n return this.table.replaceData(rowData);\n}\n// until here\n// use the Visual Editor!\n// paste into ui_table JSON \"clipboardPasteAction\":\"function(....\"\n\n// technical details\n//\n// the example function ends with\n//\n// return this.table.updateData(rows);\n// \n// but that's not updating the data (because it does try to update data through\n// the index field (default \"id\")\n// replaceData simply erase all existing rowData and fills in the pasted data\n// that's what we want",
"outputs": 1,
"noerr": 0,
"x": 419,
"y": 204,
"wires": [
[]
]
},
{
"id": "38c0e825.798328",
"type": "ui_ui_control",
"z": "4ddb981f.f34df8",
"name": "on tab change",
"events": "change",
"x": 182,
"y": 255,
"wires": [
[
"4512106a.2f145"
]
]
},
{
"id": "d9789454.020d58",
"type": "switch",
"z": "4ddb981f.f34df8",
"name": "",
"property": "ui_control.callback",
"propertyType": "msg",
"rules": [
{
"t": "eq",
"v": "clipboardPasteAction",
"vt": "str"
},
{
"t": "else"
}
],
"checkall": "true",
"repair": false,
"outputs": 2,
"x": 815,
"y": 255,
"wires": [
[
"8d8d7ea4.2fe3f"
],
[
"7b094d08.4d1224"
]
]
},
{
"id": "7b094d08.4d1224",
"type": "debug",
"z": "4ddb981f.f34df8",
"name": "something else",
"active": false,
"tosidebar": true,
"console": false,
"tostatus": false,
"complete": "true",
"targetType": "full",
"x": 998,
"y": 272,
"wires": []
},
{
"id": "22459d5a.5c4672",
"type": "comment",
"z": "4ddb981f.f34df8",
"name": "Copy & Paste (readme)",
"info": "# copy & paste\n\nYou need only one callback function I included in a separate function note for better readability (do not put this into your flow.\n\nThe change node does the preparation of the table with a `msg.ui_control` object. Because you need minimum one cell to paste into (you can`t paste into an empty table) I put in some dummy data\nIt is not necessary to configure the the table node only tick \"send data on click\" to activate the output.\n\nCTRL-c is working too. It is set to \"table\" (including currently invisble cells) and no styling.\n\n[Detailed documentation of this tabulator feature can be found here.](http://tabulator.info/docs/4.5/clipboard)\n\nBe aware that colum `field` names must match cells of the first row of the pasted data and the is tab \\t and new line \\n formatted, as windows clipboard does. [see here](http://tabulator.info/docs/4.5/clipboard#paste-parser)",
"x": 202,
"y": 153,
"wires": []
},
{
"id": "113a4af6.0aab85",
"type": "ui_group",
"z": "",
"name": "ui-table Copy & Paste",
"tab": "a1c14418.954cd8",
"disp": true,
"width": "17",
"collapse": false
},
{
"id": "a1c14418.954cd8",
"type": "ui_tab",
"z": "",
"name": "ui-table test",
"icon": "dashboard",
"disabled": false,
"hidden": false
}
]

View File

@@ -0,0 +1,493 @@
[
{
"id": "2e6a6379.742abc",
"type": "ui_table",
"z": "c4712650.59b5e8",
"group": "ff9fdb9a.7da098",
"name": "testTable",
"order": 6,
"width": "8",
"height": 5,
"columns": [
{
"field": "rowNumber",
"title": "Row Number 1",
"width": "",
"align": "left",
"formatter": "rownum",
"formatterParams": {
"target": "_blank"
}
},
{
"field": "textValue",
"title": "Text",
"width": "",
"align": "left",
"formatter": "plaintext",
"formatterParams": {
"target": "_blank"
}
},
{
"field": "numberValue",
"title": "Number",
"width": "",
"align": "left",
"formatter": "plaintext",
"formatterParams": {
"target": "_blank"
}
}
],
"outputs": 1,
"cts": true,
"x": 808,
"y": 357,
"wires": [
[
"1c377ea0.5801e1"
]
]
},
{
"id": "16664cef.5b26b3",
"type": "function",
"z": "c4712650.59b5e8",
"name": "table paramter",
"func": "msg.ui_control = {tabulator:{}};\n\n//workaround that buttos can`t deliver empty strings\nif (msg.payload.hasOwnProperty('payload')) {\n msg.payload=msg.payload.payload;\n}\n\nmsg.ui_control.tabulator[msg.topic]=msg.payload;\ndelete msg.topic;\nmsg.payload=null;\nreturn msg;",
"outputs": 1,
"noerr": 0,
"x": 590,
"y": 646,
"wires": [
[
"2e6a6379.742abc",
"b8d75d24.6cbed"
]
]
},
{
"id": "b8d75d24.6cbed",
"type": "debug",
"z": "c4712650.59b5e8",
"name": "table input",
"active": true,
"tosidebar": true,
"console": false,
"tostatus": false,
"complete": "true",
"targetType": "full",
"x": 818,
"y": 646,
"wires": []
},
{
"id": "1c377ea0.5801e1",
"type": "debug",
"z": "c4712650.59b5e8",
"name": "table output",
"active": true,
"tosidebar": true,
"console": false,
"tostatus": false,
"complete": "true",
"targetType": "full",
"x": 971,
"y": 357,
"wires": []
},
{
"id": "b15c31a9.af37c",
"type": "ui_switch",
"z": "c4712650.59b5e8",
"name": "selectable",
"label": "selectable",
"tooltip": "",
"group": "ff9fdb9a.7da098",
"order": 7,
"width": 0,
"height": 0,
"passthru": true,
"decouple": "false",
"topic": "selectable",
"style": "",
"onvalue": "true",
"onvalueType": "bool",
"onicon": "",
"oncolor": "",
"offvalue": "false",
"offvalueType": "bool",
"officon": "",
"offcolor": "",
"x": 230,
"y": 442,
"wires": [
[
"16664cef.5b26b3"
]
]
},
{
"id": "75207e8d.c54d4",
"type": "ui_switch",
"z": "c4712650.59b5e8",
"name": "movableColumns",
"label": "movableColumns",
"tooltip": "",
"group": "ff9fdb9a.7da098",
"order": 8,
"width": 0,
"height": 0,
"passthru": true,
"decouple": "false",
"topic": "movableColumns",
"style": "",
"onvalue": "true",
"onvalueType": "bool",
"onicon": "",
"oncolor": "",
"offvalue": "false",
"offvalueType": "bool",
"officon": "",
"offcolor": "",
"x": 260,
"y": 493,
"wires": [
[
"16664cef.5b26b3"
]
]
},
{
"id": "c585e7a1.dfc648",
"type": "ui_button",
"z": "c4712650.59b5e8",
"name": "",
"group": "ff9fdb9a.7da098",
"order": 9,
"width": "4",
"height": "1",
"passthru": false,
"label": "Format Numbers > 100",
"tooltip": "using a rowFormatter callback function",
"color": "",
"bgcolor": "",
"icon": "",
"payload": "function(row){ if(row.getData().numberValue>100){ row.getElement().style.backgroundColor = \"#A6A6DF\"; } },",
"payloadType": "str",
"topic": "rowFormatter",
"x": 280,
"y": 629,
"wires": [
[
"16664cef.5b26b3"
]
]
},
{
"id": "f178c6fe.710ef8",
"type": "ui_button",
"z": "c4712650.59b5e8",
"name": "",
"group": "ff9fdb9a.7da098",
"order": 5,
"width": 0,
"height": 0,
"passthru": false,
"label": "Fill demo data",
"tooltip": "",
"color": "",
"bgcolor": "",
"icon": "",
"payload": "[{\"textValue\":\"Line #1\",\"numberValue\":123.12},{\"textValue\":\"Line #2\",\"numberValue\":100},{\"textValue\":\"Line #3\",\"numberValue\":50}]",
"payloadType": "json",
"topic": "rowFormatter",
"x": 250,
"y": 357,
"wires": [
[
"2e6a6379.742abc"
]
]
},
{
"id": "2403f929.df4006",
"type": "ui_button",
"z": "c4712650.59b5e8",
"name": "",
"group": "ff9fdb9a.7da098",
"order": 11,
"width": "4",
"height": "1",
"passthru": false,
"label": "inject Tooltips callback",
"tooltip": "cell.getColumn().getField() + \" - \" + cell.getValue();",
"color": "",
"bgcolor": "",
"icon": "",
"payload": "function(cell){return cell.getColumn().getField() + \" - \" + cell.getValue(); },",
"payloadType": "str",
"topic": "tooltips",
"x": 270,
"y": 731,
"wires": [
[
"16664cef.5b26b3"
]
]
},
{
"id": "f6c68c45.58003",
"type": "ui_button",
"z": "c4712650.59b5e8",
"name": "",
"group": "ff9fdb9a.7da098",
"order": 12,
"width": "4",
"height": "1",
"passthru": false,
"label": "clear Tooltips callback",
"tooltip": "empty string is not possible! so use a single space",
"color": "",
"bgcolor": "",
"icon": "",
"payload": "{\"payload\":\"\"}",
"payloadType": "json",
"topic": "tooltips",
"x": 270,
"y": 765,
"wires": [
[
"16664cef.5b26b3"
]
]
},
{
"id": "d2b29dda.60a5a",
"type": "ui_button",
"z": "c4712650.59b5e8",
"name": "",
"group": "ff9fdb9a.7da098",
"order": 13,
"width": "4",
"height": "1",
"passthru": false,
"label": "reformat Number column",
"tooltip": "inject additional paramters to numberValue column",
"color": "",
"bgcolor": "",
"icon": "",
"payload": "[{\"field\":\"numberValue\",\"formatterParams\":{\"min\":0,\"max\":200,\"legend\":\"function (value) { if (value<100) return \\\"<span style='color:#FF0000;'>\\\"+value+\\\"</span>\\\"; else return \\\"<span style='color:#000000;'>\\\"+value+\\\"</span>\\\"; }\",\"legendAlign\":\"center\"},\"formatter\":\"progress\",\"topCalc\":\"function(values, data, calcParams){ var total = 0; var calc = 0; var count = 0; data.forEach(value => { total+=Number(value.numberValue); count++; }); if (count>0) calc=(total/count).toFixed(2); return `${calc} (avg)`; }\",\"headerTooltip\":\"avarage\"}]",
"payloadType": "json",
"topic": "columns",
"x": 280,
"y": 833,
"wires": [
[
"16664cef.5b26b3"
]
]
},
{
"id": "7b6490b3.cd9c7",
"type": "function",
"z": "c4712650.59b5e8",
"name": "callback function(s)",
"func": "// how to use the editor to write callback functions\n// DO NOT wire this into your flow!\n// copy / paste \"function( ... }\" into the correct calback parameter\n// use the \"debugger\" statement to debug your callback inside your browser\n\nvar topCalc = function(values, data, calcParams){\n var total = 0;\n var calc = 0;\n var count = 0;\n data.forEach(value => {\n total+=Number(value.numberValue);\n count++;\n });\n if (count>0) calc=(total/count).toFixed(2);\n return `${calc} (avg)`;\n}\n\nvar legend = function (value) {\n if (value<100) return \"<span style='color:#FF0000;'>\"+value+\"</span>\";\n else return \"<span style='color:#000000;'>\"+value+\"</span>\"; \n}",
"outputs": 1,
"noerr": 0,
"x": 600,
"y": 765,
"wires": [
[]
]
},
{
"id": "91506d4b.4956a",
"type": "comment",
"z": "c4712650.59b5e8",
"name": "Intentionally not wired into the flow!",
"info": "use the editor to write callback functions\n\nDO NOT wire this into your flow!\n\ncopy / paste `function( ... }` into the correct calback parameter\nuse the `debugger` statement to debug your callback inside your browser\n",
"x": 650,
"y": 731,
"wires": []
},
{
"id": "732afcea.f728f4",
"type": "ui_button",
"z": "c4712650.59b5e8",
"name": "",
"group": "ff9fdb9a.7da098",
"order": 14,
"width": "4",
"height": "1",
"passthru": false,
"label": "reset Number column",
"tooltip": "inject additional paramters to numberValue column",
"color": "",
"bgcolor": "",
"icon": "",
"payload": "[{\"field\":\"numberValue\",\"formatter\":\"plainText\",\"topCalc\":\"\",\"headerTooltip\":\"\"}]",
"payloadType": "json",
"topic": "columns",
"x": 270,
"y": 867,
"wires": [
[
"16664cef.5b26b3"
]
]
},
{
"id": "89cca7ea.7fc998",
"type": "ui_button",
"z": "c4712650.59b5e8",
"name": "",
"group": "ff9fdb9a.7da098",
"order": 15,
"width": "4",
"height": "1",
"passthru": false,
"label": "add/show id column",
"tooltip": "add a new column",
"color": "",
"bgcolor": "",
"icon": "",
"payload": "[{\"field\":\"id\",\"title\":\"id\",\"visible\":true,\"formatter\":\"plainText\"}]",
"payloadType": "json",
"topic": "columns",
"x": 270,
"y": 935,
"wires": [
[
"16664cef.5b26b3"
]
]
},
{
"id": "32a3c4ad.1b85fc",
"type": "ui_button",
"z": "c4712650.59b5e8",
"name": "",
"group": "ff9fdb9a.7da098",
"order": 16,
"width": "4",
"height": "1",
"passthru": false,
"label": "hide id column",
"tooltip": "hide id column (it is not possible to delete a existing column definition)",
"color": "",
"bgcolor": "",
"icon": "",
"payload": "[{\"field\":\"id\",\"title\":\"id\",\"visible\":false,\"formatter\":\"plainText\"}]",
"payloadType": "json",
"topic": "columns",
"x": 250,
"y": 969,
"wires": [
[
"16664cef.5b26b3"
]
]
},
{
"id": "25247f4b.cc7ec",
"type": "inject",
"z": "c4712650.59b5e8",
"name": "",
"topic": "",
"payload": "true",
"payloadType": "bool",
"repeat": "",
"crontab": "",
"once": true,
"onceDelay": 0.1,
"x": 84,
"y": 493,
"wires": [
[
"75207e8d.c54d4",
"bd3fd382.a2aa9"
]
]
},
{
"id": "18ed8d27.bf00a3",
"type": "ui_button",
"z": "c4712650.59b5e8",
"name": "",
"group": "ff9fdb9a.7da098",
"order": 10,
"width": "4",
"height": "1",
"passthru": false,
"label": "reset Numbers > 100",
"tooltip": "using a rowFormatter callback function",
"color": "",
"bgcolor": "",
"icon": "",
"payload": "{\"payload\":\"\"}",
"payloadType": "json",
"topic": "rowFormatter",
"x": 270,
"y": 663,
"wires": [
[
"16664cef.5b26b3"
]
]
},
{
"id": "bd3fd382.a2aa9",
"type": "ui_switch",
"z": "c4712650.59b5e8",
"name": "headerVisible",
"label": "headerVisible",
"tooltip": "",
"group": "ff9fdb9a.7da098",
"order": 7,
"width": 0,
"height": 0,
"passthru": true,
"decouple": "false",
"topic": "headerVisible",
"style": "",
"onvalue": "true",
"onvalueType": "bool",
"onicon": "",
"oncolor": "",
"offvalue": "false",
"offvalueType": "bool",
"officon": "",
"offcolor": "",
"x": 250,
"y": 544,
"wires": [
[
"16664cef.5b26b3"
]
]
},
{
"id": "ff9fdb9a.7da098",
"type": "ui_group",
"z": "",
"name": "TEST",
"tab": "7dcc246f.ee661c",
"order": 1,
"disp": false,
"width": "8",
"collapse": false
},
{
"id": "7dcc246f.ee661c",
"type": "ui_tab",
"z": "",
"name": "TEST",
"icon": "dashboard",
"order": 12,
"disabled": false,
"hidden": false
}
]

View File

@@ -0,0 +1,482 @@
[
{
"id": "b4d448ed.fc828",
"type": "tab",
"label": "Flow 1",
"disabled": false,
"info": ""
},
{
"id": "bcfb993d.8c84a",
"type": "ui_tab",
"name": "TableTest",
"icon": "dashboard",
"order": 0,
"disabled": false,
"hidden": false
},
{
"id": "fd38a9dc.02ac5",
"type": "ui_base",
"theme": {
"name": "theme-light",
"lightTheme": {
"default": "#0094CE",
"baseColor": "#0094CE",
"baseFont": "-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Oxygen-Sans,Ubuntu,Cantarell,Helvetica Neue,sans-serif",
"edited": true,
"reset": false
},
"darkTheme": {
"default": "#097479",
"baseColor": "#097479",
"baseFont": "-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Oxygen-Sans,Ubuntu,Cantarell,Helvetica Neue,sans-serif",
"edited": false
},
"customTheme": {
"name": "Untitled Theme 1",
"default": "#4B7930",
"baseColor": "#4B7930",
"baseFont": "-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Oxygen-Sans,Ubuntu,Cantarell,Helvetica Neue,sans-serif"
},
"themeState": {
"base-color": {
"default": "#0094CE",
"value": "#0094CE",
"edited": false
},
"page-titlebar-backgroundColor": {
"value": "#0094CE",
"edited": false
},
"page-backgroundColor": {
"value": "#fafafa",
"edited": false
},
"page-sidebar-backgroundColor": {
"value": "#ffffff",
"edited": false
},
"group-textColor": {
"value": "#1bbfff",
"edited": false
},
"group-borderColor": {
"value": "#ffffff",
"edited": false
},
"group-backgroundColor": {
"value": "#ffffff",
"edited": false
},
"widget-textColor": {
"value": "#111111",
"edited": false
},
"widget-backgroundColor": {
"value": "#0094ce",
"edited": false
},
"widget-borderColor": {
"value": "#ffffff",
"edited": false
},
"base-font": {
"value": "-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Oxygen-Sans,Ubuntu,Cantarell,Helvetica Neue,sans-serif"
}
},
"angularTheme": {
"primary": "indigo",
"accents": "blue",
"warn": "red",
"background": "grey"
}
},
"site": {
"name": "Node-RED Dashboard",
"hideToolbar": "false",
"allowSwipe": "false",
"lockMenu": "false",
"allowTempTheme": "true",
"dateFormat": "DD.MM.YYYY",
"sizes": {
"sx": 48,
"sy": 48,
"gx": 6,
"gy": 6,
"cx": 6,
"cy": 6,
"px": 0,
"py": 0
}
}
},
{
"id": "a005132f.6196e8",
"type": "ui_group",
"name": "Without Quotation",
"tab": "bcfb993d.8c84a",
"order": 1,
"disp": true,
"width": "6",
"collapse": false
},
{
"id": "1885673b.2145c1",
"type": "ui_group",
"name": "Quotes in TableName",
"tab": "bcfb993d.8c84a",
"order": 2,
"disp": true,
"width": "6",
"collapse": false
},
{
"id": "9971c312.3702d8",
"type": "ui_group",
"name": "Quotes in Column Title",
"tab": "bcfb993d.8c84a",
"order": 3,
"disp": true,
"width": "6",
"collapse": false
},
{
"id": "47f6a8.a2c36158",
"type": "ui_group",
"name": "Quotes in Description",
"tab": "bcfb993d.8c84a",
"order": 4,
"disp": true,
"width": "6",
"collapse": false
},
{
"id": "f69452b1.447158",
"type": "ui_table",
"z": "b4d448ed.fc828",
"group": "a005132f.6196e8",
"name": "Without quotation",
"order": 0,
"width": "6",
"height": "4",
"columns": [
{
"field": "name",
"title": "Col 1",
"width": "",
"align": "left",
"formatter": "plaintext",
"formatterParams": {
"target": "_blank"
}
},
{
"field": "city",
"title": "Col 2",
"width": "",
"align": "left",
"formatter": "plaintext",
"formatterParams": {
"target": "_blank"
}
}
],
"outputs": 0,
"cts": false,
"x": 570,
"y": 160,
"wires": [],
"info": "\n\nA really simple table without quotation marks"
},
{
"id": "a8e19fb2.35c11",
"type": "inject",
"z": "b4d448ed.fc828",
"name": "",
"props": [
{
"p": "payload"
},
{
"p": "topic",
"vt": "str"
}
],
"repeat": "",
"crontab": "",
"once": false,
"onceDelay": 0.1,
"topic": "",
"payload": "",
"payloadType": "date",
"x": 130,
"y": 160,
"wires": [
[
"69b33eaf.57d248"
]
]
},
{
"id": "69b33eaf.57d248",
"type": "change",
"z": "b4d448ed.fc828",
"name": "Set Data",
"rules": [
{
"t": "set",
"p": "payload",
"pt": "msg",
"to": "[\t {\t \"name\": \"Will\",\t \"city\": \"Paris\"\t },\t {\t \"name\": \"Jean-Claude\",\t \"city\": \"London\"\t },\t {\t \"name\": \"O'Hara\",\t \"city\": \"Beirut\"\t },\t {\t \"name\": '\"The Nail\"',\t \"city\": \"Hammersmith\"\t }\t]",
"tot": "jsonata"
}
],
"action": "",
"property": "",
"from": "",
"to": "",
"reg": false,
"x": 300,
"y": 160,
"wires": [
[
"f69452b1.447158",
"cb212221.fc40d8",
"3e460172.857ed6",
"ade38373.01654",
"9216fb01.47f52",
"e9c07312.e0e7c",
"d80cc268.700478"
]
]
},
{
"id": "cb212221.fc40d8",
"type": "ui_table",
"z": "b4d448ed.fc828",
"group": "1885673b.2145c1",
"name": "Single quote in 'TableName'",
"order": 0,
"width": "6",
"height": "4",
"columns": [
{
"field": "name",
"title": "Col 1",
"width": "",
"align": "left",
"formatter": "plaintext",
"formatterParams": {
"target": "_blank"
}
},
{
"field": "city",
"title": "Col 2",
"width": "",
"align": "left",
"formatter": "plaintext",
"formatterParams": {
"target": "_blank"
}
}
],
"outputs": 0,
"cts": false,
"x": 600,
"y": 220,
"wires": [],
"info": "\n\nA really simple table with single quotation marks in Table Name"
},
{
"id": "3e460172.857ed6",
"type": "ui_table",
"z": "b4d448ed.fc828",
"group": "9971c312.3702d8",
"name": "Single quote in Column Title",
"order": 1,
"width": "6",
"height": "4",
"columns": [
{
"field": "name",
"title": "&#39;Col 1&#39;",
"width": "",
"align": "left",
"formatter": "plaintext",
"formatterParams": {
"target": "_blank"
}
},
{
"field": "city",
"title": "Col 2",
"width": "",
"align": "left",
"formatter": "plaintext",
"formatterParams": {
"target": "_blank"
}
}
],
"outputs": 0,
"cts": false,
"x": 600,
"y": 280,
"wires": [],
"info": "\n\nA really simple table with single quotation mark in Column Title"
},
{
"id": "ade38373.01654",
"type": "ui_table",
"z": "b4d448ed.fc828",
"group": "47f6a8.a2c36158",
"name": "Single quote in Description",
"order": 1,
"width": "6",
"height": "4",
"columns": [
{
"field": "name",
"title": "Col 1",
"width": "",
"align": "left",
"formatter": "plaintext",
"formatterParams": {
"target": "_blank"
}
},
{
"field": "city",
"title": "Col 2",
"width": "",
"align": "left",
"formatter": "plaintext",
"formatterParams": {
"target": "_blank"
}
}
],
"outputs": 0,
"cts": false,
"x": 600,
"y": 340,
"wires": [],
"info": "\n\nA really simple table with 'single quotation' marks in description."
},
{
"id": "9216fb01.47f52",
"type": "ui_table",
"z": "b4d448ed.fc828",
"group": "1885673b.2145c1",
"name": "Double quote in \"TableName\"",
"order": 0,
"width": "6",
"height": "4",
"columns": [
{
"field": "name",
"title": "Col 1",
"width": "",
"align": "left",
"formatter": "plaintext",
"formatterParams": {
"target": "_blank"
}
},
{
"field": "city",
"title": "Col 2",
"width": "",
"align": "left",
"formatter": "plaintext",
"formatterParams": {
"target": "_blank"
}
}
],
"outputs": 0,
"cts": false,
"x": 600,
"y": 400,
"wires": [],
"info": "\n\nA really simple table with double quotation marks in Table Name"
},
{
"id": "e9c07312.e0e7c",
"type": "ui_table",
"z": "b4d448ed.fc828",
"group": "9971c312.3702d8",
"name": "Double quote in Column Title",
"order": 1,
"width": "6",
"height": "4",
"columns": [
{
"field": "name",
"title": "\"Col 1\"",
"width": "",
"align": "left",
"formatter": "plaintext",
"formatterParams": {
"target": "_blank"
}
},
{
"field": "city",
"title": "Col 2",
"width": "",
"align": "left",
"formatter": "plaintext",
"formatterParams": {
"target": "_blank"
}
}
],
"outputs": 0,
"cts": false,
"x": 600,
"y": 460,
"wires": [],
"info": "\n\nA really simple table with double quotation mark in Column Title"
},
{
"id": "d80cc268.700478",
"type": "ui_table",
"z": "b4d448ed.fc828",
"group": "47f6a8.a2c36158",
"name": "Double quote in Description",
"order": 1,
"width": "6",
"height": "4",
"columns": [
{
"field": "name",
"title": "Col 1",
"width": "",
"align": "left",
"formatter": "plaintext",
"formatterParams": {
"target": "_blank"
}
},
{
"field": "city",
"title": "Col 2",
"width": "",
"align": "left",
"formatter": "plaintext",
"formatterParams": {
"target": "_blank"
}
}
],
"outputs": 0,
"cts": false,
"x": 600,
"y": 520,
"wires": [],
"info": "\n\nA really simple table with \"double quotation\" marks in description."
}
]

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

22798
node_modules/node-red-node-ui-table/lib/js/tabulator.js generated vendored Normal file

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,87 @@
<script type="text/html" data-help-name="ui_table">
<p>A Node-RED-Dashboard UI widget node that displays a table of data.</p>
<h3>Inputs</h3>
<dl class="message-properties">
<dt>payload<span class="property-type">array</span></dt>
<dd>An array of objects which contains row data.</dd>
</dl>
<h3>Outputs (optional)</h3>
<dl class="message-properties">
<dt>payload<span class="property-type">object</span></dt>
<dd>An object that contains the data from the row that was selected.</dd>
<dt>topic<span class="property-type">string</span></dt>
<dd>A string that contains the property name of selected cell.</dd>
<dt>row<span class="property-type">number</span></dt>
<dd>A number that contains the row index of the clicked cell (from 0).</dd>
</dl>
<h3>Details</h3>
<p>To clear the table send an empty data array <code>[]</code>.</p>
<p>Each data row object should have the same set of keys because the keys in the object are used as the column names.</p>
<p>With no configuration the node will try to create a table with equally spaced columns of simple text for each row provided, using the keys as column titles.</p>
<p>If manual configuration is used each column can be configured with a Title, Width, Alignment and Format.</p>
<p>Width can be in pixels, or %, or left blank for automatic.</p>
<p>Format can be:<ul>
<li>Plain Text - Simple text values.</li>
<li>HTML - Rich html to allow text Formatting - <i>NOTE</i>: this is raw un-sanitised HTML.</li>
<li>Link - URL link to a web page.</li>
<li>Image - Source (src) URL of an image to display.</li>
<li>Progress - a progress bar from 0 to 100.</li>
<li>Traffic - Red/Amber/Green indicator light set by numbers in the range 0-33-67-100.</li>
<li>Color - HTML color name, or hex value (#rrggbb) to fill the cell.</li>
<li>Tick/Cross - Tick or Cross symbol, boolean true/false, numeric 1/0 or text "1"/"0".</li>
<li>Stars - Number of stars - numeric 0 to 5.</li>
<li>Row Number - Current row number.</li>
</ul></p>
<h3>Example data</h3>
<pre><code>[
{
"Name": "Kazuhito Yokoi",
"Age": "35",
"Favourite Color": "red",
"Date Of Birth": "12/09/1983",
"Rating": 5
},
{
"Name": "Oli Bob",
"Age": "12",
"Favourite Color": "red",
"Date Of Birth": "12/08/2017",
"Rating": 2
}
]</code></pre>
<h3>Advanced features</h3>
Instead of sending an array to ui-table this node to replace the complete table data it also accepts an object as payload to send commands. The object must have the following properties
<ul>
<li> `command` a valid tabulator command such as `addRow`, `replaceData` or `addFilter`</li>
<li> `arguments` *(optional)* can array of arguments for that function</li>
<li> `returnPromise` *(optional)* a boolean value. `true` if the function should return a promise.</li>
</ul>
<dl class="message-properties">
<dt>payload<span class="property-type">object</span></dt>
<dd>An object containing a command to the ui-table widget.
<pre><code>{
command: "addRow",
arguments: [
{
"Name": "Oli Bob",
"Age": "12",
"Favorite Color": "red",
"Date Of Birth": "12/08/2017",
"Rating": 2
},
true
],
returnPromise: true
}</code></pre>
</dd>
</dl>
</script>

View File

@@ -0,0 +1,12 @@
{
"table" : {
"label" : {
"group" : "Group",
"size" : "Size",
"send" : "Send data on click "
},
"error": {
"no-group": "group not configured"
}
}
}

202
node_modules/node-red-node-ui-table/node.html generated vendored Normal file
View File

@@ -0,0 +1,202 @@
<!--
Copyright JS Foundation and other contributors, http://js.foundation
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<script type='text/html' data-template-name='ui_table'>
<div class='form-row' id='template-row-group'>
<label for='node-input-group'>
<i class='fa fa-table'></i> <span data-i18n='table.label.group'></span>
</label>
<input type='text' id='node-input-group'>
</div>
<div class='form-row' id='template-row-size'>
<label>
<i class='fa fa-object-group'></i> <span data-i18n='table.label.size'></span>
</label>
<input type='hidden' id='node-input-width'>
<input type='hidden' id='node-input-height'>
<button class='editor-button' id='node-input-size'></button>
</div>
<div class='form-row'>
<label for='node-input-name'>
<i class='fa fa-tag'></i> <span data-i18n='node-red:common.label.name'></span>
</label>
<input type='text' id='node-input-name' data-i18n='[placeholder]node-red:common.label.name'>
</div>
<div class="form-row node-input-column-container-row">
<label for="node-input-width" style="vertical-align:top"><i class="fa fa-list-alt"></i> Columns</label>
<span style="float:right">
<span data-i18n='table.label.send'>&nbsp;</span><input type="checkbox" id="node-input-cts" style="display:inline-block; width:auto; vertical-align:top;">
</span>
<ol id="node-input-column-container"></ol>
</div>
</script>
<script type='text/javascript'>
RED.nodes.registerType('ui_table', {
category: 'dashboard',
color: 'rgb(63, 173, 181)',
defaults: {
group: { type: 'ui_group', required: true },
name: { value: '' },
order: { value: 0 },
width: {
value: 0,
validate: function (v) {
var valid = true;
var width = v || 0;
var currentGroup = $('#node-input-group').val() || this.group;
var groupNode = RED.nodes.node(currentGroup);
valid = !groupNode || +width <= +groupNode.width;
$('#node-input-size').toggleClass('input-error', !valid);
return valid;
}
},
height: { value: 0 },
columns: { value: [] },
outputs: { value: 0 },
cts: { value: false }
},
inputs: 1,
outputs: 0,
icon: 'font-awesome/fa-table',
paletteLabel: 'table',
label: function () {
return this.name || 'table';
},
labelStyle: function() {
return this.name?"node_label_italic":"";
},
oneditprepare: function () {
if(RED.nodes.getType('ui_group')) {
$('.form-tips').hide();
} else {
$('.form-row').hide();
}
$('#node-input-size').elementSizer({
width: '#node-input-width',
height: '#node-input-height',
group: '#node-input-group'
});
$('#node-input-column-container')
.css('min-height','250px').css('min-width','432px')
.editableList({
sortable: true,
removable: true,
addButton: true,
addItem: function(row, index, data) {
$('<div><span>Property</span></div>')
.css('display','inline-block').css('width','55px').appendTo(row);
var field = $('<input/>', {
class: 'node-input-column-field',
type: 'text',
style: "margin-left:5px; width:82%;"
}).appendTo(row);
if (data.field) {
field.val(data.field);
}
$('<br>').appendTo(row);
$('<div><span>Title</span></div>')
.css('display','inline-block').css('width','55px').appendTo(row);
var title = $('<input/>', {
class: 'node-input-column-title',
type: 'text',
style: "margin-left:5px; width:82%;"
}).appendTo(row);
if (data.title) {
title.val(data.title.replace(/\&#39;/g, "'"));
}
$('<br>').appendTo(row);
$('<div><span>Align</span></div>')
.css('display','inline-block').css('width','55px').appendTo(row);
var align = $('<select/>', {
class: 'node-input-column-align',
style: "margin-left:5px; width:25%;"
}).appendTo(row);
align.append($('<option></option>').val('left').text('left'));
align.append($('<option></option>').val('center').text('center'));
align.append($('<option></option>').val('right').text('right'));
if (data.align) {
align.val(data.align);
}
// $('<br>').appendTo(row);
$('<div><span>Width</span></div>')
.css('display','inline-block').css('width','35px').css('padding-left','19%').appendTo(row);
var title = $('<input/>', {
class: 'node-input-column-width',
type: 'text',
style: "margin-left:5px; width:28%;",
placeholder: "px, %, or blank"
}).appendTo(row);
if (data.width) {
title.val(data.width);
}
$('<br>').appendTo(row);
$('<div><span>Format</span></div>')
.css('display','inline-block').css('width','55px').appendTo(row);
var align = $('<select/>', {
class: 'node-input-column-formatter',
style: "margin-left:5px; width:50%"
}).appendTo(row);
align.append($('<option></option>').val('plaintext').text('Plain text'));
align.append($('<option></option>').val('html').text('HTML'));
align.append($('<option></option>').val('link').text('Link (http://..)'));
align.append($('<option></option>').val('image').text('Image (src url)'));
align.append($('<option></option>').val('progress').text('Progress (0-100)'));
align.append($('<option></option>').val('traffic').text('Traffic (0-33-67-100)'));
align.append($('<option></option>').val('color').text('Color (html,#rrggbb)'));
align.append($('<option></option>').val('tickCross').text('Tick / Cross (boolean,1/0)'));
align.append($('<option></option>').val('star').text('Stars (0-5)'));
// align.append($('<option></option>').val('datetime').text('Date time'));
align.append($('<option></option>').val('rownum').text('Row number'));
if (data.formatter) {
align.val(data.formatter);
}
}
});
$("#node-input-column-container").editableList('addItems', this.columns);
},
oneditsave: function() {
var columns = $("#node-input-column-container").editableList('items');
var node = this;
node.columns = [];
columns.each(function (i) {
var colum = $(this);
var c = {};
c.field = colum.find(".node-input-column-field").val();
c.title = colum.find(".node-input-column-title").val().replace(/'/g, "&#39;");
c.width = colum.find(".node-input-column-width").val();
c.align = colum.find(".node-input-column-align").val();
c.formatter = colum.find(".node-input-column-formatter").val();
c.formatterParams = { target:"_blank" };
node.columns.push(c);
});
var that = this;
if ($("#node-input-cts").is(":checked")) { that.outputs = 1; }
else that.outputs = 0;
},
oneditresize: function(size) {
var rows = $("#dialog-form>div:not(.node-input-column-container-row)");
var height = size.height;
for (var i=0; i<rows.length; i++) {
height -= $(rows[i]).outerHeight(true);
}
var editorRow = $("#dialog-form>div.node-input-column-container-row");
height -= (parseInt(editorRow.css("marginTop"))+parseInt(editorRow.css("marginBottom")));
$("#node-input-column-container").editableList('height',height);
}
});
</script>

336
node_modules/node-red-node-ui-table/node.js generated vendored Normal file
View File

@@ -0,0 +1,336 @@
/**
* Copyright JS Foundation and other contributors, http://js.foundation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
**/
var path = require('path');
var mergeTabulator = function(target,source) {
if (typeof source === 'object') {
Object.keys(source).forEach(element => {
if (typeof source[element] !== "object") {
target[element] = source[element];
} else {
if (!target.hasOwnProperty(element)) {
target[element] = (Array.isArray(source[element])) ? [] : {};
}
// handle the columns array to merge columns if the field property matches. Otherwise push a new column
if (element==='columns' && Array.isArray(source[element])){
source[element].forEach(sourceElement => {
let index = target[element].findIndex(targetElement => (
(targetElement.field && sourceElement.field && targetElement.field===sourceElement.field) || // normal column object
(targetElement.title && sourceElement.title && targetElement.title===sourceElement.title) // parent object with nested columns
));
if (index<0) { // add new column
index=target[element].push({})-1;
}
mergeTabulator(target[element][index],sourceElement);
})
} else {
mergeTabulator(target[element],source[element])
}
}
});
} else {
target=source;
}
}
module.exports = function (RED) {
function checkConfig(node, conf) {
if (!conf || !conf.hasOwnProperty('group')) {
node.error(RED._('table.error.no-group'));
return false;
}
else {
return true;
}
}
function HTML(config,dark) {
var configAsJson = JSON.stringify(config, (key, value) => {
// exclude the node description
if (key === "info") {
return undefined;
}
// replace single quotation mark (apostrophe) by html code in strings
if (typeof (value) === "string") {
return value.replace(/'/g, "&apos;");
}
// all others leave unchanged
return value;
});
var mid = (dark) ? "_midnight" : "";
var html = String.raw`
<style>.nr-dashboard-ui_table { padding:0; }</style>
<link href='ui-table/css/tabulator`+mid+`.min.css' rel='stylesheet' type='text/css'>
<script type='text/javascript' src='ui-table/js/tabulator.js'></script>
<div id='ui_table-{{$id}}' style="background-color:unset; border:unset;"></div>
<input type='hidden' ng-init='init(` + configAsJson + `)'>
`;
return html;
}
function TableNode(config) {
var done = null;
var node = this;
try {
RED.nodes.createNode(this, config);
if (checkConfig(node, config)) {
var ui = RED.require('node-red-dashboard')(RED);
var sizes = ui.getSizes();
// var luma = 255;
// if (ui.hasOwnProperty("getTheme") && (ui.getTheme() !== undefined)) {
// var rgb = parseInt(ui.getTheme()["page-sidebar-backgroundColor"].value.substring(1), 16); // convert rrggbb to decimal
// luma = 0.2126 * ((rgb >> 16) & 0xff) + 0.7152 * ((rgb >> 8) & 0xff) + 0.0722 * ((rgb >> 0) & 0xff); // per ITU-R BT.709
// }
var html = HTML(config,ui.isDark());
done = ui.addWidget({
node: node,
width: config.width,
height: (config.height > 2) ? config.height : 2, // min height to 2 so auto will show something
format: html,
templateScope: 'local',
order: config.order || 0,
group: config.group,
forwardInputMessages: false,
storeFrontEndInputAsState: false,
// to make msg.ui_control work without msg.payload we have to send msg.payload=null.
// we correct this here into undefined to get the last known payload form currentValues[opt.node.id].
convert: function (value) {
if (value===null) value=undefined;
return value;
},
// merge new ui_control messages into config.ui_control
// Help needed: use the already build in ui_control mechanism from ui.js
beforeEmit: function (msg, value) {
// cache ui_control messages for new clients
if (msg.hasOwnProperty('ui_control')) {
if (!config.hasOwnProperty('ui_control')){
config.ui_control={
"tabulator":{
"columns":config.columns
}};
}
// use mergeTabulator to correctly merge columns arrays if field property matches
mergeTabulator(config.ui_control,msg.ui_control);
// delete column definitions by sending a empty columns array (requires page reload)
if (msg.ui_control.tabulator && msg.ui_control.tabulator.columns && Array.isArray(msg.ui_control.tabulator.columns) &&
msg.ui_control.tabulator.columns.length==0) {
config.ui_control.tabulator.columns=[];
config.ui_control.tabulator.autoColumns=true;
}
}
return { msg: {
payload: value,
ui_control: config.ui_control,
socketid: msg.socketid
}};
},
beforeSend: function (msg, orig) {
if (orig) { return orig.msg; }
},
initController: function ($scope, events) {
$scope.inited = false;
$scope.tabledata = [];
var tablediv;
var mergeObject = function(target,source) {
if (typeof source === 'object') {
Object.keys(source).forEach(element => {
if (typeof source[element] !== "object") {
target[element] = source[element];
} else {
if (!target.hasOwnProperty(element)) {
target[element] = (Array.isArray(source[element])) ? [] : {};
}
mergeObject(target[element],source[element])
}
});
} else {
target = source;
}
};
var createTable = function(basediv, tabledata, columndata, outputs, ui_control) {
// add id field if not already exists
if (columndata.length>0 && tabledata.length>0 && tabledata[0] && typeof tabledata[0] === 'object' && !tabledata[0].hasOwnProperty('id')) {
tabledata.map((row,index) => row.id = index);
}
var opts = {
data: tabledata,
layout: 'fitColumns',
columns: columndata,
autoColumns: columndata.length == 0,
movableColumns: true,
}
if (!ui_control || !ui_control.tabulator) {
var y = (columndata.length === 0) ? 25 : 32;
if ($scope.height==2) { // auto height
opts.height = (tabledata.length > 0 )? tabledata.length * y + 26 : $scope.height*(sizes.sy+sizes.cy);
} else {
opts.height = $scope.height*(sizes.sy+sizes.cy);
}
}
else { // configuration via ui_control
//as Object.assign is not supported by Internet Explorer
//opts = Object.assign(opts, ui_control.tabulator);
mergeObject(opts,ui_control.tabulator);
var y = (opts.columns && (opts.columns.length > 0)) ? 32 : 25;
if (ui_control.customHeight) {
opts.height= ui_control.customHeight * y + 26;
} else {
if ($scope.height==2) { // auto height
opts.height= (tabledata.length > 0 )? tabledata.length * y + 26 : $scope.height*(sizes.sy+sizes.cy);
} else {
opts.height = $scope.height*(sizes.sy+sizes.cy);
}
}
} // end of configuration via ui_control
if ((outputs > 0) && !opts.hasOwnProperty('cellClick')) { // default cellClick if not already defined by ui_control
opts.cellClick = function(e, cell) {
$scope.send({topic:cell.getField(), payload:cell.getData(), row:(cell.getRow()).getPosition()});
};
}
//turn autoColumns off if opts.columns is array with length > 0
if (opts.columns && Array.isArray(opts.columns) && opts.columns.length>0) {
opts.autoColumns = false;
}
// console.log("createTabulator",opts);
if ($scope.table !== undefined) {
$scope.table.destroy();
}
$scope.table = new Tabulator(basediv, opts);
};
$scope.init = function (config) {
$scope.config = config;
tablediv = '#ui_table-' + $scope.$eval('$id')
var stateCheck = setInterval(function() {
if (document.querySelector(tablediv) && $scope.tabledata) {
clearInterval(stateCheck);
$scope.inited = true;
createTable(tablediv,$scope.tabledata,$scope.config.columns,$scope.config.outputs,$scope.config.ui_control);
$scope.tabledata = [];
}
}, 200); // lowest setting on my side ... still fails sometimes ;)
};
$scope.$watch('msg', function (msg) {
//console.log("ui-table message arrived:",msg);
if (msg && msg.hasOwnProperty("ui_control") && msg.ui_control.hasOwnProperty("callback")) return msg; // to avoid loopback from callbacks. No better solution jet. Help needed.
//console.log("ui-table msg: ", msg);
// configuration via ui_control
if (msg && msg.hasOwnProperty("ui_control")) {
var addValueOrFunction = function (config,param,value) {
if (typeof String.prototype.parseFunction != 'function') {
String.prototype.parseFunction = function () {
var funcReg = /function *\(([^()]*)\)[ \n\t]*{(.*)}/gmi;
var match = funcReg.exec(this.replace(/\n/g, ' '));
if (match) {
return new Function(match[1].split(','), match[2]);
}
return null;
};
}
var valueFunction;
if (typeof value === "string" && (valueFunction = value.parseFunction())) {
config[param]=valueFunction.bind($scope); // to enable this.send() for callback functions.
}
else config[param]= value;
}
var addObject = function (destinationObject,sourceObject) {
for (var element in sourceObject) {
if (!destinationObject[element]) destinationObject[element]=(Array.isArray(sourceObject[element]))? [] : {};
if (typeof sourceObject[element] === "object") {
addObject(destinationObject[element],sourceObject[element])
} else {
addValueOrFunction(destinationObject,element,sourceObject[element]);
}
}
}
if (!$scope.config.ui_control) { $scope.config.ui_control={}; }
addObject($scope.config.ui_control,msg.ui_control);
} // end of configuration via ui_control
if (msg && msg.hasOwnProperty("payload")) {
if (Array.isArray(msg.payload)) {
$scope.tabledata = msg.payload;
}
// commands to tabulator via msg.payload object
if (typeof msg.payload === "object" && msg.payload!==null && !Array.isArray(msg.payload)) {
if (msg.payload.hasOwnProperty("command") && $scope.table!==undefined) {
if (!msg.payload.hasOwnProperty("arguments") || !Array.isArray(msg.payload.arguments)) {
msg.payload.arguments=[];
}
if (msg.payload.returnPromise) {
$scope.table[msg.payload.command].apply($scope.table,msg.payload.arguments).then(function(...args){
$scope.send({topic:"success", ui_control: {callback:$scope.msg.payload.command}, return:$scope.msg.payload});
}).catch(function(error){
if (Object.keys(error).length>0) {
$scope.send({topic:"error", ui_control: {callback:$scope.msg.payload.command}, return:$scope.msg.payload, error: error});
}
});
} else {
$scope.table[msg.payload.command].apply($scope.table,msg.payload.arguments);
}
return;
}
return;
} // end of commands to tabulator via msg.payload object
}
if ($scope.inited == false) {
return;
} else {
createTable(tablediv, $scope.tabledata, $scope.config.columns, $scope.config.outputs, $scope.config.ui_control);
}
});
}
});
}
}
catch (e) { console.log(e); }
node.on('close', function () {
if (done) { done(); }
});
}
RED.nodes.registerType('ui_table', TableNode);
var uipath = 'ui';
if (RED?.settings?.ui) { uipath = RED.settings.ui.path; }
var fullPath = path.join('/', uipath, '/ui-table/*').replace(/\\/g, '/');
RED.httpNode.get(fullPath, function (req, res) {
var options = {
root: __dirname + '/lib/',
dotfiles: 'deny'
};
res.sendFile(req.params[0], options)
});
};

33
node_modules/node-red-node-ui-table/package.json generated vendored Normal file
View File

@@ -0,0 +1,33 @@
{
"name": "node-red-node-ui-table",
"version": "0.4.5",
"description": "Table UI widget node for Node-RED Dashboard",
"author": "Kazuhito Yokoi",
"contributors": ["Dave Conway-Jones","@hotNipi","@Christian-Me"],
"license": "Apache-2.0",
"node-red": {
"version": ">=3.0.0",
"nodes": {
"ui_table": "node.js"
}
},
"peerDependencies": {
"node-red-dashboard": ">2.16.0"
},
"repository": {
"type": "git",
"url": "git+https://github.com/node-red/node-red-ui-nodes.git"
},
"bugs": {
"url":"https://github.com/node-red/node-red-ui-nodes/issues"
},
"homepage": "https://github.com/node-red/node-red-ui-nodes/tree/master/node-red-node-ui-table#README.md",
"keywords": [
"node-red",
"node-red-dashboard",
"table"
],
"engines": {
"node": ">=16"
}
}

BIN
node_modules/node-red-node-ui-table/screenshot.png generated vendored Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 88 KiB

BIN
node_modules/node-red-node-ui-table/screenshot2.png generated vendored Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 57 KiB

BIN
node_modules/node-red-node-ui-table/ui-table-custom.png generated vendored Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 37 KiB