diff --git a/application/src/main/data/json/system/widget_bundles/cards.json b/application/src/main/data/json/system/widget_bundles/cards.json
index 384fadd463..4fb124fc06 100644
--- a/application/src/main/data/json/system/widget_bundles/cards.json
+++ b/application/src/main/data/json/system/widget_bundles/cards.json
@@ -162,10 +162,10 @@
"resources": [],
"templateHtml": "\n",
"templateCss": "#container {\n overflow: auto;\n}\n\n.tbDatasource-container {\n margin: 5px;\n padding: 8px;\n}\n\n.tbDatasource-title {\n font-size: 1.200rem;\n font-weight: 500;\n padding-bottom: 10px;\n}\n\n.tbDatasource-table {\n width: 100%;\n box-shadow: 0 0 10px #ccc;\n border-collapse: collapse;\n white-space: nowrap;\n font-size: 1.000rem;\n color: #757575;\n}\n\n.tbDatasource-table td {\n position: relative;\n border-top: 1px solid rgba(0, 0, 0, 0.12);\n border-bottom: 1px solid rgba(0, 0, 0, 0.12);\n padding: 0px 18px;\n box-sizing: border-box;\n}",
- "controllerScript": "self.onInit = function() {\n}\n\nself.onDataUpdated = function() {\n self.ctx.$scope.qrCodeWidget.onDataUpdated();\n}\n\nself.typeParameters = function() {\n return {\n maxDatasources: 1,\n dataKeysOptional: true,\n singleEntity: true\n };\n}\n\nself.onDestroy = function() {\n}\n\n",
- "settingsSchema": "{\n \"schema\": {\n \"type\": \"object\",\n \"title\": \"QR Code\",\n \"properties\": {\n \"qrCodeTextPattern\": {\n \"title\": \"QR code text pattern (for ex. '${entityName} | ${keyName} - some text.')\",\n \"type\": \"string\",\n \"default\": \"${entityName}\"\n },\n \"useQrCodeTextFunction\": {\n \"title\": \"Use QR code text function\",\n \"type\": \"boolean\",\n \"default\": false\n },\n \"qrCodeTextFunction\": {\n \"title\": \"QR code text function: f(data)\",\n \"type\": \"string\",\n \"default\": \"return data['entityName'];\"\n }\n },\n \"required\": []\n },\n \"form\": [\n \"qrCodeTextPattern\",\n \"useQrCodeTextFunction\",\n {\n \"key\": \"qrCodeTextFunction\",\n \"type\": \"javascript\"\n }\n ]\n}\n",
+ "controllerScript": "self.onInit = function() {\n}\n\nself.onDataUpdated = function() {\n self.ctx.$scope.qrCodeWidget.onDataUpdated();\n}\n\nself.typeParameters = function() {\n return {\n dataKeysOptional: true,\n datasourcesOptional: true\n };\n}\n\nself.onDestroy = function() {\n}\n\n",
+ "settingsSchema": "{\n \"schema\": {\n \"type\": \"object\",\n \"title\": \"QR Code\",\n \"properties\": {\n \"qrCodeTextPattern\": {\n \"title\": \"QR code text pattern (for ex. '${entityName} | ${keyName} - some text.')\",\n \"type\": \"string\",\n \"default\": \"${entityName}\"\n },\n \"useQrCodeTextFunction\": {\n \"title\": \"Use QR code text function\",\n \"type\": \"boolean\",\n \"default\": false\n },\n \"qrCodeTextFunction\": {\n \"title\": \"QR code text function: f(data)\",\n \"type\": \"string\",\n \"default\": \"return data[0]['entityName'];\"\n }\n },\n \"required\": []\n },\n \"form\": [\n {\n \"key\": \"qrCodeTextPattern\",\n \"condition\": \"model.useQrCodeTextFunction !== true\"\n },\n \"useQrCodeTextFunction\",\n {\n \"key\": \"qrCodeTextFunction\",\n \"type\": \"javascript\",\n \"helpId\": \"widget/lib/qrcode/qrcode_text_fn\",\n \"condition\": \"model.useQrCodeTextFunction === true\"\n }\n ]\n}\n",
"dataKeySettingsSchema": "{}\n",
- "defaultConfig": "{\"datasources\":[{\"type\":\"function\",\"name\":\"function\",\"entityAliasId\":null,\"filterId\":null,\"dataKeys\":[{\"name\":\"f(x)\",\"type\":\"function\",\"label\":\"Random\",\"color\":\"#2196f3\",\"settings\":{},\"_hash\":0.7036904308224163,\"funcBody\":\"var value = prevValue + Math.random() * 100 - 50;\\nvar multiplier = Math.pow(10, 2 || 0);\\nvar value = Math.round(value * multiplier) / multiplier;\\nif (value < -1000) {\\n\\tvalue = -1000;\\n} else if (value > 1000) {\\n\\tvalue = 1000;\\n}\\nreturn value;\"}]}],\"timewindow\":{\"realtime\":{\"timewindowMs\":60000}},\"showTitle\":true,\"backgroundColor\":\"#fff\",\"color\":\"rgba(0, 0, 0, 0.87)\",\"padding\":\"8px\",\"settings\":{\"qrCodeTextPattern\":\"${entityName}\",\"useQrCodeTextFunction\":false,\"qrCodeTextFunction\":\"return data['entityName'];\"},\"title\":\"QR Code\"}"
+ "defaultConfig": "{\"datasources\":[{\"type\":\"function\",\"name\":\"function\",\"entityAliasId\":null,\"filterId\":null,\"dataKeys\":[{\"name\":\"f(x)\",\"type\":\"function\",\"label\":\"Random\",\"color\":\"#2196f3\",\"settings\":{},\"_hash\":0.7036904308224163,\"funcBody\":\"var value = prevValue + Math.random() * 100 - 50;\\nvar multiplier = Math.pow(10, 2 || 0);\\nvar value = Math.round(value * multiplier) / multiplier;\\nif (value < -1000) {\\n\\tvalue = -1000;\\n} else if (value > 1000) {\\n\\tvalue = 1000;\\n}\\nreturn value;\"}]}],\"timewindow\":{\"realtime\":{\"timewindowMs\":60000}},\"showTitle\":true,\"backgroundColor\":\"#fff\",\"color\":\"rgba(0, 0, 0, 0.87)\",\"padding\":\"8px\",\"settings\":{\"qrCodeTextPattern\":\"${entityName}\",\"useQrCodeTextFunction\":false,\"qrCodeTextFunction\":\"return data[0] ? data[0]['entityName'] : '';\"},\"title\":\"QR Code\"}"
}
},
{
@@ -181,9 +181,9 @@
"templateHtml": "\n",
"templateCss": "#container tb-markdown-widget {\n height: 100%;\n display: block;\n}\n\n#container tb-markdown-widget .tb-markdown-view {\n height: 100%;\n overflow: auto;\n}\n",
"controllerScript": "self.onInit = function() {\n}\n\nself.onDataUpdated = function() {\n self.ctx.$scope.markdownWidget.onDataUpdated();\n}\n\nself.actionSources = function() {\n return {\n 'elementClick': {\n name: 'widget-action.element-click',\n multiple: true\n }\n };\n}\n\nself.typeParameters = function() {\n return {\n dataKeysOptional: true,\n datasourcesOptional: true\n };\n}\n\nself.onDestroy = function() {\n}\n\n",
- "settingsSchema": "{\n \"schema\": {\n \"type\": \"object\",\n \"title\": \"Markdown/HTML card\",\n \"properties\": {\n \"markdownTextPattern\": {\n \"title\": \"Markdown/HTML pattern (markdown or HTML with variables, for ex. '${entityName} or ${keyName} - some text.')\",\n \"type\": \"string\",\n \"default\": \"# Markdown/HTML card \\n - **Current entity**: **${entityName}**. \\n - **Current value**: **${Random}**.\"\n },\n \"markdownCss\": {\n \"title\": \"Markdown/HTML CSS\",\n \"type\": \"string\",\n \"default\": \"\"\n },\n \"useMarkdownTextFunction\": {\n \"title\": \"Use markdown/HTML value function\",\n \"type\": \"boolean\",\n \"default\": false\n },\n \"markdownTextFunction\": {\n \"title\": \"Markdown/HTML value function: f(data)\",\n \"type\": \"string\",\n \"default\": \"return '# Some title\\\\n - Entity name: ' + data[0]['entityName'];\"\n }\n },\n \"required\": []\n },\n \"form\": [\n {\n \"key\": \"markdownTextPattern\",\n \"type\": \"markdown\"\n },\n {\n \"key\": \"markdownCss\",\n \"type\": \"css\"\n },\n \"useMarkdownTextFunction\",\n {\n \"key\": \"markdownTextFunction\",\n \"type\": \"javascript\"\n }\n ]\n}\n",
+ "settingsSchema": "{\n \"schema\": {\n \"type\": \"object\",\n \"title\": \"Markdown/HTML card\",\n \"properties\": {\n \"markdownTextPattern\": {\n \"title\": \"Markdown/HTML pattern (markdown or HTML with variables, for ex. '${entityName} or ${keyName} - some text.')\",\n \"type\": \"string\",\n \"default\": \"# Markdown/HTML card \\n - **Current entity**: **${entityName}**. \\n - **Current value**: **${Random}**.\"\n },\n \"markdownCss\": {\n \"title\": \"Markdown/HTML CSS\",\n \"type\": \"string\",\n \"default\": \"\"\n },\n \"useMarkdownTextFunction\": {\n \"title\": \"Use markdown/HTML value function\",\n \"type\": \"boolean\",\n \"default\": false\n },\n \"markdownTextFunction\": {\n \"title\": \"Markdown/HTML value function: f(data)\",\n \"type\": \"string\",\n \"default\": \"return '# Some title\\\\n - Entity name: ' + data[0]['entityName'];\"\n }\n },\n \"required\": []\n },\n \"form\": [\n {\n \"key\": \"markdownTextPattern\",\n \"type\": \"markdown\",\n \"condition\": \"model.useMarkdownTextFunction !== true\"\n },\n {\n \"key\": \"markdownCss\",\n \"type\": \"css\"\n },\n \"useMarkdownTextFunction\",\n {\n \"key\": \"markdownTextFunction\",\n \"type\": \"javascript\",\n \"helpId\": \"widget/lib/markdown/markdown_text_fn\",\n \"condition\": \"model.useMarkdownTextFunction === true\"\n }\n ]\n}\n",
"dataKeySettingsSchema": "{}\n",
- "defaultConfig": "{\"datasources\":[{\"type\":\"function\",\"name\":\"function\",\"dataKeys\":[{\"name\":\"f(x)\",\"type\":\"function\",\"label\":\"Random\",\"color\":\"#2196f3\",\"settings\":{},\"_hash\":0.15479322438769105,\"funcBody\":\"var value = prevValue + Math.random() * 100 - 50;\\nvar multiplier = Math.pow(10, 2 || 0);\\nvar value = Math.round(value * multiplier) / multiplier;\\nif (value < -1000) {\\n\\tvalue = -1000;\\n} else if (value > 1000) {\\n\\tvalue = 1000;\\n}\\nreturn value;\"}]}],\"timewindow\":{\"realtime\":{\"timewindowMs\":60000}},\"showTitle\":false,\"backgroundColor\":\"#fff\",\"color\":\"rgba(0, 0, 0, 0.87)\",\"padding\":\"0px\",\"settings\":{\"markdownTextPattern\":\"### Markdown/HTML card\\n - **Current entity**: ${entityName}.\\n - **Current value**: ${Random}.\",\"markdownTextFunction\":\"return '# Some title\\\\n - Entity name: ' + data[0]['entityName'];\"},\"title\":\"Markdown/HTML Card\",\"showTitleIcon\":false,\"iconColor\":\"rgba(0, 0, 0, 0.87)\",\"iconSize\":\"24px\",\"titleTooltip\":\"\",\"dropShadow\":true,\"enableFullscreen\":true,\"widgetStyle\":{},\"titleStyle\":{\"fontSize\":\"16px\",\"fontWeight\":400},\"showLegend\":false}"
+ "defaultConfig": "{\"datasources\":[{\"type\":\"function\",\"name\":\"function\",\"dataKeys\":[{\"name\":\"f(x)\",\"type\":\"function\",\"label\":\"Random\",\"color\":\"#2196f3\",\"settings\":{},\"_hash\":0.15479322438769105,\"funcBody\":\"var value = prevValue + Math.random() * 100 - 50;\\nvar multiplier = Math.pow(10, 2 || 0);\\nvar value = Math.round(value * multiplier) / multiplier;\\nif (value < -1000) {\\n\\tvalue = -1000;\\n} else if (value > 1000) {\\n\\tvalue = 1000;\\n}\\nreturn value;\"}]}],\"timewindow\":{\"realtime\":{\"timewindowMs\":60000}},\"showTitle\":false,\"backgroundColor\":\"#fff\",\"color\":\"rgba(0, 0, 0, 0.87)\",\"padding\":\"0px\",\"settings\":{\"markdownTextPattern\":\"### Markdown/HTML card\\n - **Current entity**: ${entityName}.\\n - **Current value**: ${Random}.\",\"markdownTextFunction\":\"return '# Some title\\\\n - Entity name: ' + data[0]['entityName'];\",\"useMarkdownTextFunction\":false},\"title\":\"Markdown/HTML Card\",\"showTitleIcon\":false,\"iconColor\":\"rgba(0, 0, 0, 0.87)\",\"iconSize\":\"24px\",\"titleTooltip\":\"\",\"dropShadow\":true,\"enableFullscreen\":true,\"widgetStyle\":{},\"titleStyle\":{\"fontSize\":\"16px\",\"fontWeight\":400},\"showLegend\":false}"
}
}
]
diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/markdown-widget.component.ts b/ui-ngx/src/app/modules/home/components/widget/lib/markdown-widget.component.ts
index e96f775007..fd0197996e 100644
--- a/ui-ngx/src/app/modules/home/components/widget/lib/markdown-widget.component.ts
+++ b/ui-ngx/src/app/modules/home/components/widget/lib/markdown-widget.component.ts
@@ -99,15 +99,12 @@ export class MarkdownWidgetComponent extends PageComponent implements OnInit {
} else {
initialData = [];
}
- let markdownText: string;
- if (initialData) {
- const data = parseData(initialData);
- markdownText = this.settings.useMarkdownTextFunction ?
- safeExecute(this.markdownTextFunction, [data]) : this.settings.markdownTextPattern;
- const allData = flatData(data);
- const replaceInfo = processPattern(markdownText, allData);
- markdownText = fillPattern(markdownText, replaceInfo, allData);
- }
+ const data = parseData(initialData);
+ let markdownText = this.settings.useMarkdownTextFunction ?
+ safeExecute(this.markdownTextFunction, [data]) : this.settings.markdownTextPattern;
+ const allData = flatData(data);
+ const replaceInfo = processPattern(markdownText, allData);
+ markdownText = fillPattern(markdownText, replaceInfo, allData);
if (this.markdownText !== markdownText) {
this.markdownText = this.utils.customTranslation(markdownText, markdownText);
this.cd.detectChanges();
diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/qrcode-widget.component.html b/ui-ngx/src/app/modules/home/components/widget/lib/qrcode-widget.component.html
index 48f888340a..74590433f4 100644
--- a/ui-ngx/src/app/modules/home/components/widget/lib/qrcode-widget.component.html
+++ b/ui-ngx/src/app/modules/home/components/widget/lib/qrcode-widget.component.html
@@ -17,8 +17,6 @@
-->
-
-
entity.no-data
-
widgets.invalid-qr-code-text
-
+
entity.no-data
+
widgets.invalid-qr-code-text
diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/qrcode-widget.component.ts b/ui-ngx/src/app/modules/home/components/widget/lib/qrcode-widget.component.ts
index a7c2c46911..621a54da50 100644
--- a/ui-ngx/src/app/modules/home/components/widget/lib/qrcode-widget.component.ts
+++ b/ui-ngx/src/app/modules/home/components/widget/lib/qrcode-widget.component.ts
@@ -20,7 +20,7 @@ import { WidgetContext } from '@home/models/widget-component.models';
import { Store } from '@ngrx/store';
import { AppState } from '@core/core.state';
import {
- fillPattern,
+ fillPattern, flatData,
parseData,
parseFunction,
processPattern,
@@ -37,7 +37,7 @@ interface QrCodeWidgetSettings {
qrCodeTextFunction: string;
}
-type QrCodeTextFunction = (data: FormattedData) => string;
+type QrCodeTextFunction = (data: FormattedData[]) => string;
@Component({
selector: 'tb-qrcode-widget',
@@ -54,7 +54,6 @@ export class QrCodeWidgetComponent extends PageComponent implements OnInit, Afte
qrCodeText: string;
invalidQrCodeText = false;
- datasourceDetected = false;
private viewInited: boolean;
private scheduleUpdateCanvas: boolean;
@@ -97,17 +96,14 @@ export class QrCodeWidgetComponent extends PageComponent implements OnInit, Afte
}
];
} else {
- this.datasourceDetected = false;
- }
- if (initialData) {
- const data = parseData(initialData);
- const dataSourceData = data[0];
- const pattern = this.settings.useQrCodeTextFunction ?
- safeExecute(this.qrCodeTextFunction, [dataSourceData]) : this.settings.qrCodeTextPattern;
- const replaceInfo = processPattern(pattern, dataSourceData);
- qrCodeText = fillPattern(pattern, replaceInfo, dataSourceData);
- this.datasourceDetected = true;
+ initialData = [];
}
+ const data = parseData(initialData);
+ const pattern = this.settings.useQrCodeTextFunction ?
+ safeExecute(this.qrCodeTextFunction, [data]) : this.settings.qrCodeTextPattern;
+ const allData = flatData(data);
+ const replaceInfo = processPattern(pattern, allData);
+ qrCodeText = fillPattern(pattern, replaceInfo, allData);
this.updateQrCodeText(qrCodeText);
}
diff --git a/ui-ngx/src/assets/help/en_US/widget/lib/markdown/markdown_text_fn.md b/ui-ngx/src/assets/help/en_US/widget/lib/markdown/markdown_text_fn.md
new file mode 100644
index 0000000000..b3ea25d683
--- /dev/null
+++ b/ui-ngx/src/assets/help/en_US/widget/lib/markdown/markdown_text_fn.md
@@ -0,0 +1,58 @@
+#### Markdown text function
+
+
+
+
+*function (data): string*
+
+A JavaScript function used to calculate markdown or HTML content.
+
+**Parameters:**
+
+
+ - data:
FormattedData[] - An array of FormattedData objects resolved from configured datasources.
+ Each object represents basic entity properties (ex. entityId, entityName)
and provides access to other entity attributes/timeseries declared in widget datasource configuration.
+
+
+
+**Returns:**
+
+Should return string value presenting markdown or HTML content.
+
+
+
+##### Examples
+
+* Display markdown with first entity name information:
+
+```javascript
+return '# Some title\n - Entity name: ' + data[0]['entityName'];
+{:copy-code}
+```
+
+
+-
+Display greetings for currently logged-in user.
+Let's assume widget has first datasource configured using Current User Single entity alias
+and has data keys for firstName, lastName and name entity fields:
+
+
+
+```javascript
+var userEntity = data[0];
+var userName;
+if (userEntity.firstName || userEntity['First name']) {
+ userName = userEntity.firstName || userEntity['First name'];
+} else if (userEntity.lastName || userEntity['Last name']) {
+ userName = userEntity.lastName || userEntity['Last name'];
+} else if (userEntity.name || userEntity['Name']) {
+ userName = userEntity.name || userEntity['Name'];
+}
+
+var welcomeText = 'Hi, ' + userName + '!\n\n';
+return welcomeText;
+{:copy-code}
+```
+
+
+
diff --git a/ui-ngx/src/assets/help/en_US/widget/lib/qrcode/qrcode_text_fn.md b/ui-ngx/src/assets/help/en_US/widget/lib/qrcode/qrcode_text_fn.md
new file mode 100644
index 0000000000..d119592030
--- /dev/null
+++ b/ui-ngx/src/assets/help/en_US/widget/lib/qrcode/qrcode_text_fn.md
@@ -0,0 +1,55 @@
+#### QR code text function
+
+
+
+
+*function (data): string*
+
+A JavaScript function used to calculate text to be displayed as QR code.
+
+**Parameters:**
+
+
+ - data:
FormattedData[] - An array of FormattedData objects resolved from configured datasources.
+ Each object represents basic entity properties (ex. entityId, entityName)
and provides access to other entity attributes/timeseries declared in widget datasource configuration.
+
+
+
+**Returns:**
+
+Should return string value presenting text to be displayed as QR code.
+
+
+
+##### Examples
+
+* Prepare QR code text from name of the first entity if present:
+
+```javascript
+return data[0] ? data[0]['entityName'] : '';
+{:copy-code}
+```
+
+
+-
+Prepare QR code text to use as device claiming info (in this case
{deviceName: string, secretKey: string}).
+Let's assume device has claimingData attribute with string JSON value containing secretKey field
+(see Claiming devices):
+
+
+
+```javascript
+var entityData = data[0];
+if (entityData) {
+ return JSON.stringify({
+ deviceName: entityData.entityName,
+ secretKey: JSON.parse(entityData.claimingData).secretKey
+ });
+} else {
+ return '';
+}
+{:copy-code}
+```
+
+
+