@openremote/or-dashboard-builder 1.2.0-snapshot.20240512160221

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (167) hide show
  1. package/README.md +156 -0
  2. package/build.gradle +15 -0
  3. package/lib/controls/dashboard-refresh-controls.d.ts +17 -0
  4. package/lib/controls/dashboard-refresh-controls.js +17 -0
  5. package/lib/controls/dashboard-refresh-controls.js.map +1 -0
  6. package/lib/index.d.ts +71 -0
  7. package/lib/index.js +285 -0
  8. package/lib/index.js.map +1 -0
  9. package/lib/or-dashboard-boardsettings.d.ts +19 -0
  10. package/lib/or-dashboard-boardsettings.js +121 -0
  11. package/lib/or-dashboard-boardsettings.js.map +1 -0
  12. package/lib/or-dashboard-browser.d.ts +9 -0
  13. package/lib/or-dashboard-browser.js +35 -0
  14. package/lib/or-dashboard-browser.js.map +1 -0
  15. package/lib/or-dashboard-engine.d.ts +4 -0
  16. package/lib/or-dashboard-engine.js +1 -0
  17. package/lib/or-dashboard-engine.js.map +1 -0
  18. package/lib/or-dashboard-keyhandler.d.ts +6 -0
  19. package/lib/or-dashboard-keyhandler.js +1 -0
  20. package/lib/or-dashboard-keyhandler.js.map +1 -0
  21. package/lib/or-dashboard-preview.d.ts +70 -0
  22. package/lib/or-dashboard-preview.js +155 -0
  23. package/lib/or-dashboard-preview.js.map +1 -0
  24. package/lib/or-dashboard-settingspanel.d.ts +44 -0
  25. package/lib/or-dashboard-settingspanel.js +216 -0
  26. package/lib/or-dashboard-settingspanel.js.map +1 -0
  27. package/lib/or-dashboard-tree.d.ts +25 -0
  28. package/lib/or-dashboard-tree.js +62 -0
  29. package/lib/or-dashboard-tree.js.map +1 -0
  30. package/lib/or-dashboard-widget.d.ts +18 -0
  31. package/lib/or-dashboard-widget.js +15 -0
  32. package/lib/or-dashboard-widget.js.map +1 -0
  33. package/lib/or-dashboard-widgetcontainer.d.ts +23 -0
  34. package/lib/or-dashboard-widgetcontainer.js +20 -0
  35. package/lib/or-dashboard-widgetcontainer.js.map +1 -0
  36. package/lib/or-dashboard-widgetsettings.d.ts +15 -0
  37. package/lib/or-dashboard-widgetsettings.js +16 -0
  38. package/lib/or-dashboard-widgetsettings.js.map +1 -0
  39. package/lib/panels/assettypes-panel.d.ts +44 -0
  40. package/lib/panels/assettypes-panel.js +51 -0
  41. package/lib/panels/assettypes-panel.js.map +1 -0
  42. package/lib/panels/attributes-panel.d.ts +41 -0
  43. package/lib/panels/attributes-panel.js +126 -0
  44. package/lib/panels/attributes-panel.js.map +1 -0
  45. package/lib/panels/thresholds-panel.d.ts +39 -0
  46. package/lib/panels/thresholds-panel.js +129 -0
  47. package/lib/panels/thresholds-panel.js.map +1 -0
  48. package/lib/service/dashboard-service.d.ts +13 -0
  49. package/lib/service/dashboard-service.js +1 -0
  50. package/lib/service/dashboard-service.js.map +1 -0
  51. package/lib/service/widget-service.d.ts +8 -0
  52. package/lib/service/widget-service.js +1 -0
  53. package/lib/service/widget-service.js.map +1 -0
  54. package/lib/settings/attribute-input-settings.d.ts +13 -0
  55. package/lib/settings/attribute-input-settings.js +36 -0
  56. package/lib/settings/attribute-input-settings.js.map +1 -0
  57. package/lib/settings/chart-settings.d.ts +30 -0
  58. package/lib/settings/chart-settings.js +144 -0
  59. package/lib/settings/chart-settings.js.map +1 -0
  60. package/lib/settings/gauge-settings.d.ts +15 -0
  61. package/lib/settings/gauge-settings.js +37 -0
  62. package/lib/settings/gauge-settings.js.map +1 -0
  63. package/lib/settings/image-settings.d.ts +17 -0
  64. package/lib/settings/image-settings.js +52 -0
  65. package/lib/settings/image-settings.js.map +1 -0
  66. package/lib/settings/kpi-settings.d.ts +15 -0
  67. package/lib/settings/kpi-settings.js +47 -0
  68. package/lib/settings/kpi-settings.js.map +1 -0
  69. package/lib/settings/map-settings.d.ts +21 -0
  70. package/lib/settings/map-settings.js +72 -0
  71. package/lib/settings/map-settings.js.map +1 -0
  72. package/lib/settings/table-settings.d.ts +14 -0
  73. package/lib/settings/table-settings.js +33 -0
  74. package/lib/settings/table-settings.js.map +1 -0
  75. package/lib/style.d.ts +1 -0
  76. package/lib/style.js +99 -0
  77. package/lib/style.js.map +1 -0
  78. package/lib/util/or-asset-widget.d.ts +20 -0
  79. package/lib/util/or-asset-widget.js +1 -0
  80. package/lib/util/or-asset-widget.js.map +1 -0
  81. package/lib/util/or-widget.d.ts +31 -0
  82. package/lib/util/or-widget.js +1 -0
  83. package/lib/util/or-widget.js.map +1 -0
  84. package/lib/util/settings-panel.d.ts +9 -0
  85. package/lib/util/settings-panel.js +56 -0
  86. package/lib/util/settings-panel.js.map +1 -0
  87. package/lib/util/widget-config.d.ts +2 -0
  88. package/lib/util/widget-config.js +1 -0
  89. package/lib/util/widget-config.js.map +1 -0
  90. package/lib/util/widget-settings.d.ts +23 -0
  91. package/lib/util/widget-settings.js +1 -0
  92. package/lib/util/widget-settings.js.map +1 -0
  93. package/lib/widgets/attribute-input-widget.d.ts +24 -0
  94. package/lib/widgets/attribute-input-widget.js +31 -0
  95. package/lib/widgets/attribute-input-widget.js.map +1 -0
  96. package/lib/widgets/chart-widget.d.ts +25 -0
  97. package/lib/widgets/chart-widget.js +15 -0
  98. package/lib/widgets/chart-widget.js.map +1 -0
  99. package/lib/widgets/gauge-widget.d.ts +22 -0
  100. package/lib/widgets/gauge-widget.js +12 -0
  101. package/lib/widgets/gauge-widget.js.map +1 -0
  102. package/lib/widgets/image-widget.d.ts +25 -0
  103. package/lib/widgets/image-widget.js +54 -0
  104. package/lib/widgets/image-widget.js.map +1 -0
  105. package/lib/widgets/kpi-widget.d.ts +21 -0
  106. package/lib/widgets/kpi-widget.js +8 -0
  107. package/lib/widgets/kpi-widget.js.map +1 -0
  108. package/lib/widgets/map-widget.d.ts +39 -0
  109. package/lib/widgets/map-widget.js +9 -0
  110. package/lib/widgets/map-widget.js.map +1 -0
  111. package/lib/widgets/or-base-widget.d.ts +15 -0
  112. package/lib/widgets/or-base-widget.js +1 -0
  113. package/lib/widgets/or-base-widget.js.map +1 -0
  114. package/lib/widgets/or-chart-widget.d.ts +36 -0
  115. package/lib/widgets/or-chart-widget.js +112 -0
  116. package/lib/widgets/or-chart-widget.js.map +1 -0
  117. package/lib/widgets/or-gauge-widget.d.ts +46 -0
  118. package/lib/widgets/or-gauge-widget.js +60 -0
  119. package/lib/widgets/or-gauge-widget.js.map +1 -0
  120. package/lib/widgets/or-kpi-widget.d.ts +44 -0
  121. package/lib/widgets/or-kpi-widget.js +63 -0
  122. package/lib/widgets/or-kpi-widget.js.map +1 -0
  123. package/lib/widgets/or-map-widget.d.ts +49 -0
  124. package/lib/widgets/or-map-widget.js +75 -0
  125. package/lib/widgets/or-map-widget.js.map +1 -0
  126. package/lib/widgets/table-widget.d.ts +25 -0
  127. package/lib/widgets/table-widget.js +12 -0
  128. package/lib/widgets/table-widget.js.map +1 -0
  129. package/package.json +32 -0
  130. package/src/controls/dashboard-refresh-controls.ts +100 -0
  131. package/src/index.ts +731 -0
  132. package/src/or-dashboard-boardsettings.ts +249 -0
  133. package/src/or-dashboard-browser.ts +160 -0
  134. package/src/or-dashboard-engine.ts +17 -0
  135. package/src/or-dashboard-keyhandler.ts +25 -0
  136. package/src/or-dashboard-preview.ts +713 -0
  137. package/src/or-dashboard-tree.ts +304 -0
  138. package/src/or-dashboard-widgetcontainer.ts +155 -0
  139. package/src/or-dashboard-widgetsettings.ts +91 -0
  140. package/src/panels/assettypes-panel.ts +311 -0
  141. package/src/panels/attributes-panel.ts +304 -0
  142. package/src/panels/thresholds-panel.ts +285 -0
  143. package/src/service/dashboard-service.ts +89 -0
  144. package/src/service/widget-service.ts +48 -0
  145. package/src/settings/attribute-input-settings.ts +79 -0
  146. package/src/settings/chart-settings.ts +306 -0
  147. package/src/settings/gauge-settings.ts +93 -0
  148. package/src/settings/image-settings.ts +175 -0
  149. package/src/settings/kpi-settings.ts +106 -0
  150. package/src/settings/map-settings.ts +185 -0
  151. package/src/settings/table-settings.ts +92 -0
  152. package/src/style.ts +104 -0
  153. package/src/util/or-asset-widget.ts +110 -0
  154. package/src/util/or-widget.ts +60 -0
  155. package/src/util/settings-panel.ts +93 -0
  156. package/src/util/widget-config.ts +2 -0
  157. package/src/util/widget-settings.ts +58 -0
  158. package/src/widgets/attribute-input-widget.ts +143 -0
  159. package/src/widgets/chart-widget.ts +203 -0
  160. package/src/widgets/gauge-widget.ts +111 -0
  161. package/src/widgets/image-widget.ts +180 -0
  162. package/src/widgets/kpi-widget.ts +97 -0
  163. package/src/widgets/map-widget.ts +187 -0
  164. package/src/widgets/table-widget.ts +157 -0
  165. package/tsconfig.json +15 -0
  166. package/tsconfig.tsbuildinfo +1 -0
  167. package/webpack.config.js +10 -0
@@ -0,0 +1,180 @@
1
+ import {WidgetConfig} from "../util/widget-config";
2
+ import {AssetModelUtil, Attribute, AttributeRef, WellknownValueTypes} from "@openremote/model";
3
+ import {OrWidget, WidgetManifest} from "../util/or-widget";
4
+ import { customElement } from "lit/decorators.js";
5
+ import {WidgetSettings} from "../util/widget-settings";
6
+ import {css, CSSResult, html, PropertyValues, TemplateResult, unsafeCSS } from "lit";
7
+ import {OrAssetWidget} from "../util/or-asset-widget";
8
+ import {ImageSettings} from "../settings/image-settings";
9
+ import { when } from "lit/directives/when.js";
10
+ import {DefaultColor2, DefaultColor3, Util} from "@openremote/core";
11
+ import { styleMap } from "lit/directives/style-map.js";
12
+
13
+ const styling = css`
14
+ #img-wrapper {
15
+ height: 100%;
16
+ width: 100%;
17
+ display: flex;
18
+ flex-direction: column;
19
+ justify-content: center;
20
+ align-items: center;
21
+ overflow: hidden;
22
+ z-index: 1;
23
+ }
24
+
25
+ #img-container {
26
+ position: relative;
27
+ max-height: 100%;
28
+ }
29
+
30
+ #img-content {
31
+ height: 100%;
32
+ max-height: 100%;
33
+ max-width: 100%;
34
+ }
35
+
36
+ #overlay {
37
+ position: absolute;
38
+ z-index: 3;
39
+
40
+ /* additional marker styling */
41
+ color: var(--or-app-color2, ${unsafeCSS(DefaultColor2)});
42
+ background-color: var(--or-app-color3, ${unsafeCSS(DefaultColor3)});
43
+ border-radius: 15px;
44
+ padding: 3px 8px 5px 8px;
45
+ object-fit: contain;
46
+ text-overflow: ellipsis;
47
+ white-space: nowrap;
48
+ }
49
+ `;
50
+
51
+ export interface ImageAssetMarker {
52
+ attributeRef: AttributeRef,
53
+ coordinates: [number, number]
54
+ }
55
+
56
+ export interface ImageWidgetConfig extends WidgetConfig {
57
+ attributeRefs: AttributeRef[];
58
+ markers: ImageAssetMarker[];
59
+ showTimestampControls: boolean;
60
+ imagePath: string;
61
+ }
62
+
63
+ function getDefaultWidgetConfig(): ImageWidgetConfig {
64
+ return {
65
+ attributeRefs: [],
66
+ showTimestampControls: false,
67
+ imagePath: '',
68
+ markers: [],
69
+ };
70
+ }
71
+
72
+ @customElement("image-widget")
73
+ export class ImageWidget extends OrAssetWidget {
74
+
75
+ // Override of widgetConfig with extended type
76
+ protected readonly widgetConfig!: ImageWidgetConfig;
77
+
78
+ static getManifest(): WidgetManifest {
79
+ return {
80
+ displayName: "Image",
81
+ displayIcon: "file-image-marker",
82
+ minColumnWidth: 1,
83
+ minColumnHeight: 1,
84
+ getContentHtml(config: ImageWidgetConfig): OrWidget {
85
+ return new ImageWidget(config);
86
+ },
87
+ getSettingsHtml(config: ImageWidgetConfig): WidgetSettings {
88
+ return new ImageSettings(config);
89
+ },
90
+ getDefaultConfig(): ImageWidgetConfig {
91
+ return getDefaultWidgetConfig();
92
+ }
93
+ }
94
+ }
95
+
96
+ public refreshContent(force: boolean) {
97
+ this.loadAssets();
98
+ }
99
+
100
+ static get styles(): CSSResult[] {
101
+ return [...super.styles, styling];
102
+ }
103
+
104
+ updated(changedProps: PropertyValues) {
105
+
106
+ if(changedProps.has('widgetConfig') && this.widgetConfig) {
107
+ const attributeRefs = this.widgetConfig.attributeRefs;
108
+ const missingAssets = attributeRefs?.filter((attrRef: AttributeRef) => !this.isAttributeRefLoaded(attrRef));
109
+ if (missingAssets.length > 0) {
110
+ this.loadAssets();
111
+ }
112
+ }
113
+ }
114
+
115
+ protected loadAssets() {
116
+ this.fetchAssets(this.widgetConfig.attributeRefs).then(assets => {
117
+ this.loadedAssets = assets!;
118
+ this.assetAttributes = this.widgetConfig.attributeRefs.map((attrRef: AttributeRef) => {
119
+ const assetIndex = assets!.findIndex(asset => asset.id === attrRef.id);
120
+ const foundAsset = assetIndex >= 0 ? assets![assetIndex] : undefined;
121
+ return foundAsset && foundAsset.attributes ? [assetIndex, foundAsset.attributes[attrRef.name!]] : undefined;
122
+ }).filter((indexAndAttr: any) => !!indexAndAttr) as [number, Attribute<any>][];
123
+ });
124
+ }
125
+
126
+ // method to render and update the markers on the image
127
+ protected handleMarkerPlacement(config: ImageWidgetConfig) {
128
+ if (this.assetAttributes.length && config.attributeRefs.length > 0) {
129
+
130
+ if(config.markers.length === 0) {
131
+ console.error("No markers found!");
132
+ return [];
133
+ }
134
+ return config.attributeRefs.map((attributeRef, index) => {
135
+ const marker = config.markers.find(m => m.attributeRef.id === attributeRef.id && m.attributeRef.name === attributeRef.name);
136
+ const asset = this.loadedAssets.find(a => a.id === attributeRef.id);
137
+ let value: string | undefined;
138
+ const styles: any = {
139
+ "left": `${marker!.coordinates[0]}%`,
140
+ "top": `${marker!.coordinates[1]}%`
141
+ };
142
+ if(asset) {
143
+ const attribute = asset.attributes![attributeRef.name!];
144
+ const descriptors = AssetModelUtil.getAttributeAndValueDescriptors(asset.type, attributeRef.name, attribute);
145
+ value = Util.getAttributeValueAsString(attribute, descriptors[0], asset.type, true, "-");
146
+ if(attribute?.type === WellknownValueTypes.COLOURRGB && value !== "-") {
147
+ styles.backgroundColor = value;
148
+ styles.minHeight = "21px";
149
+ styles.minWidth = "13px";
150
+ value = undefined;
151
+ }
152
+ }
153
+ return html`
154
+ <span id="overlay" style="${styleMap(styles)}">
155
+ ${value}
156
+ </span>
157
+ `;
158
+ });
159
+ }
160
+ }
161
+
162
+ protected render(): TemplateResult {
163
+ const imagePath = this.widgetConfig.imagePath;
164
+ return html`
165
+ <div id="img-wrapper">
166
+ ${when(imagePath, () => html`
167
+ <div id="img-container">
168
+ <img id="img-content" src="${imagePath}" alt=""/>
169
+ <div>
170
+ ${this.handleMarkerPlacement(this.widgetConfig)}
171
+ </div>
172
+ </div>
173
+ `, () => html`
174
+ <span><or-translate value="dashboard.noImageSelected"></or-translate></span>
175
+ `)}
176
+ </div>
177
+ `;
178
+ }
179
+
180
+ }
@@ -0,0 +1,97 @@
1
+ import { customElement } from "lit/decorators.js";
2
+ import {OrAssetWidget} from "../util/or-asset-widget";
3
+ import {OrWidget, WidgetManifest} from "../util/or-widget";
4
+ import {WidgetSettings} from "../util/widget-settings";
5
+ import {WidgetConfig} from "../util/widget-config";
6
+ import {Attribute, AttributeRef} from "@openremote/model";
7
+ import {html, TemplateResult } from "lit";
8
+ import {KpiSettings} from "../settings/kpi-settings";
9
+ import "@openremote/or-attribute-card";
10
+
11
+ export interface KpiWidgetConfig extends WidgetConfig {
12
+ attributeRefs: AttributeRef[];
13
+ period?: 'year' | 'month' | 'week' | 'day' | 'hour';
14
+ decimals: number;
15
+ deltaFormat: "absolute" | "percentage";
16
+ showTimestampControls: boolean;
17
+ }
18
+
19
+ function getDefaultWidgetConfig(): KpiWidgetConfig {
20
+ return {
21
+ attributeRefs: [],
22
+ period: "day",
23
+ decimals: 0,
24
+ deltaFormat: "absolute",
25
+ showTimestampControls: false
26
+ };
27
+ }
28
+
29
+ @customElement("kpi-widget")
30
+ export class KpiWidget extends OrAssetWidget {
31
+
32
+ protected widgetConfig!: KpiWidgetConfig;
33
+
34
+ static getManifest(): WidgetManifest {
35
+ return {
36
+ displayName: "KPI",
37
+ displayIcon: "label",
38
+ minColumnWidth: 1,
39
+ minColumnHeight: 1,
40
+ getContentHtml(config: KpiWidgetConfig): OrWidget {
41
+ return new KpiWidget(config);
42
+ },
43
+ getSettingsHtml(config: KpiWidgetConfig): WidgetSettings {
44
+ return new KpiSettings(config);
45
+ },
46
+ getDefaultConfig(): KpiWidgetConfig {
47
+ return getDefaultWidgetConfig();
48
+ }
49
+ }
50
+ }
51
+
52
+ refreshContent(force: boolean): void {
53
+ this.loadAssets(this.widgetConfig.attributeRefs);
54
+ }
55
+
56
+ protected updated(changedProps: Map<string, any>) {
57
+ super.updated(changedProps);
58
+
59
+ // If widgetConfig, and the attributeRefs of them have changed...
60
+ if(changedProps.has("widgetConfig") && this.widgetConfig) {
61
+ const attributeRefs = this.widgetConfig.attributeRefs;
62
+
63
+ // Check if list of attributes has changed, based on the cached assets
64
+ const loadedRefs: AttributeRef[] = attributeRefs?.filter((attrRef: AttributeRef) => this.isAttributeRefLoaded(attrRef));
65
+ if (loadedRefs?.length !== (attributeRefs ? attributeRefs.length : 0)) {
66
+
67
+ // Fetch the new list of assets
68
+ this.loadAssets(attributeRefs);
69
+
70
+ }
71
+ }
72
+ return super.updated(changedProps);
73
+ }
74
+
75
+ protected loadAssets(attributeRefs: AttributeRef[]) {
76
+ this.fetchAssets(attributeRefs).then((assets) => {
77
+ this.loadedAssets = assets;
78
+ this.assetAttributes = attributeRefs?.map((attrRef: AttributeRef) => {
79
+ const assetIndex = assets.findIndex((asset) => asset.id === attrRef.id);
80
+ const foundAsset = assetIndex >= 0 ? assets[assetIndex] : undefined;
81
+ return foundAsset && foundAsset.attributes ? [assetIndex, foundAsset.attributes[attrRef.name!]] : undefined;
82
+ }).filter((indexAndAttr: any) => !!indexAndAttr) as [number, Attribute<any>][];
83
+ });
84
+ }
85
+
86
+ protected render(): TemplateResult {
87
+ return html`
88
+ <div style="height: 100%; overflow: hidden;">
89
+ <or-attribute-card .assets="${this.loadedAssets}" .assetAttributes="${this.assetAttributes}" .period="${this.widgetConfig.period}"
90
+ .deltaFormat="${this.widgetConfig.deltaFormat}" .mainValueDecimals="${this.widgetConfig.decimals}"
91
+ showControls="${this.widgetConfig?.showTimestampControls}" showTitle="${false}" style="height: 100%;">
92
+ </or-attribute-card>
93
+ </div>
94
+ `;
95
+ }
96
+
97
+ }
@@ -0,0 +1,187 @@
1
+ import {html, PropertyValues, TemplateResult} from "lit";
2
+ import {customElement} from "lit/decorators.js";
3
+ import {OrAssetWidget} from "../util/or-asset-widget";
4
+ import {OrWidget, WidgetManifest} from "../util/or-widget";
5
+ import {WidgetSettings} from "../util/widget-settings";
6
+ import {MapSettings} from "../settings/map-settings";
7
+ import {WidgetConfig} from "../util/widget-config";
8
+ import {Asset, AssetDescriptor, Attribute, AttributeRef, GeoJSONPoint, WellknownAttributes, WellknownMetaItems} from "@openremote/model";
9
+ import {
10
+ LngLatLike,
11
+ AttributeMarkerColours,
12
+ RangeAttributeMarkerColours,
13
+ AttributeMarkerColoursRange,
14
+ MapMarkerColours, MapMarkerAssetConfig,
15
+ } from "@openremote/or-map";
16
+ import {when} from "lit/directives/when.js";
17
+ import manager, {Util} from "@openremote/core";
18
+ import { showSnackbar } from "@openremote/or-mwc-components/or-mwc-snackbar";
19
+ import "@openremote/or-map";
20
+
21
+ export interface MapWidgetConfig extends WidgetConfig {
22
+ // General values
23
+ attributeRefs: AttributeRef[];
24
+ // Map related values
25
+ zoom?: number,
26
+ center?: LngLatLike,
27
+ lat?: number,
28
+ lng?: number,
29
+ // Map marker related values
30
+ showLabels: boolean,
31
+ showUnits: boolean,
32
+ showGeoJson: boolean,
33
+ boolColors: MapMarkerColours,
34
+ textColors: [string, string][],
35
+ // Threshold related values
36
+ thresholds: [number, string][],
37
+ min?: number,
38
+ max?: number,
39
+ // Asset type related values
40
+ assetType?: string,
41
+ valueType?: string,
42
+ attributeName?: string,
43
+ assetTypes: AssetDescriptor[],
44
+ assetIds: string[],
45
+ attributes: string[],
46
+ }
47
+
48
+ function getDefaultWidgetConfig(): MapWidgetConfig {
49
+ return {
50
+ attributeRefs: [],
51
+ showLabels: false,
52
+ showUnits: false,
53
+ showGeoJson: true,
54
+ boolColors: {type: 'boolean', 'false': '#ef5350', 'true': '#4caf50'},
55
+ textColors: [['example', '4caf50'], ['example2', 'ef5350']],
56
+ thresholds: [[0, "#4caf50"], [75, "#ff9800"], [90, "#ef5350"]],
57
+ assetTypes: [],
58
+ assetType: undefined,
59
+ assetIds: [],
60
+ attributes: [],
61
+ } as MapWidgetConfig;
62
+ }
63
+
64
+ @customElement("map-widget")
65
+ export class MapWidget extends OrAssetWidget {
66
+
67
+ protected widgetConfig!: MapWidgetConfig
68
+
69
+ private markers: MapMarkerAssetConfig = {};
70
+
71
+ static getManifest(): WidgetManifest {
72
+ return {
73
+ displayName: "Map",
74
+ displayIcon: "map",
75
+ minColumnWidth: 2,
76
+ minColumnHeight: 2,
77
+ getContentHtml(config: MapWidgetConfig): OrWidget {
78
+ return new MapWidget(config);
79
+ },
80
+ getSettingsHtml(config: MapWidgetConfig): WidgetSettings {
81
+ return new MapSettings(config);
82
+ },
83
+ getDefaultConfig(): MapWidgetConfig {
84
+ return getDefaultWidgetConfig();
85
+ }
86
+ }
87
+ }
88
+
89
+ refreshContent(force: boolean): void {
90
+ this.loadAssets();
91
+ }
92
+
93
+ protected updated(changedProps: PropertyValues) {
94
+ if(changedProps.has('widgetConfig') && this.widgetConfig) {
95
+ this.loadAssets();
96
+ }
97
+ }
98
+
99
+ protected async loadAssets() {
100
+ if(this.widgetConfig.assetType && this.widgetConfig.attributeName) {
101
+ this.fetchAssetsByType([this.widgetConfig.assetType], this.widgetConfig.attributeName).then((assets) => {
102
+ this.loadedAssets = assets;
103
+ });
104
+ }
105
+ }
106
+
107
+ protected async fetchAssetsByType(assetTypes: string[], attributeName: string) {
108
+ let assets: Asset[] = [];
109
+ await manager.rest.api.AssetResource.queryAssets({
110
+ realm: {
111
+ name: manager.displayRealm
112
+ },
113
+ select: {
114
+ attributes: [attributeName, 'location']
115
+ },
116
+ types: assetTypes,
117
+
118
+ }).then(response => {
119
+ assets = response.data;
120
+ this.markers = {};
121
+ }).catch((reason) => {
122
+ console.error(reason);
123
+ showSnackbar(undefined, "errorOccurred");
124
+ });
125
+ return assets;
126
+ }
127
+
128
+
129
+ protected render(): TemplateResult {
130
+ return html`
131
+ <div style="height: 100%; display: flex; flex-direction: column; overflow: hidden;">
132
+ <or-map id="miniMap" class="or-map" .zoom="${this.widgetConfig.zoom}" .center="${this.widgetConfig.center}" .showGeoJson="${this.widgetConfig.showGeoJson}" style="flex: 1;">
133
+ ${when(this.loadedAssets, () => {
134
+ return this.getMarkerTemplates();
135
+ })}
136
+ </or-map>
137
+ </div>
138
+ `;
139
+ }
140
+
141
+ protected getMarkerTemplates(): TemplateResult[] {
142
+ return this.loadedAssets.filter((asset: Asset) => {
143
+ if (!asset.attributes) {
144
+ return false;
145
+ }
146
+ const attr = asset.attributes[WellknownAttributes.LOCATION] as Attribute<GeoJSONPoint>;
147
+ return !attr || !attr.meta || !attr.meta.hasOwnProperty(WellknownMetaItems.SHOWONDASHBOARD) || !!Util.getMetaValue(WellknownMetaItems.SHOWONDASHBOARD, attr);
148
+ }).map(asset => {
149
+ if (this.markers) {
150
+ // Configure map marker asset settings
151
+ this.markers[asset.type!] = {attributeName: this.widgetConfig.attributeName!};
152
+ this.markers[asset.type!].showUnits = this.widgetConfig.showUnits;
153
+ this.markers[asset.type!].showLabel = this.widgetConfig.showLabels;
154
+ if (this.widgetConfig.valueType == 'boolean') {
155
+ (this.widgetConfig.boolColors as any).true = (this.widgetConfig.boolColors as any).true.replace("#", "");
156
+ (this.widgetConfig.boolColors as any).false = (this.widgetConfig.boolColors as any).false.replace("#", "");
157
+ this.markers[asset.type!].colours = this.widgetConfig.boolColors;
158
+ } else if (this.widgetConfig.valueType == 'text') {
159
+ var colors: AttributeMarkerColours = {type: 'string',};
160
+ (this.widgetConfig.textColors as [string, string][]).map((threshold) => {
161
+ colors[threshold[0] as string] = (threshold[1] as string).replace('#', '');
162
+ })
163
+ this.markers[asset.type!].colours = colors;
164
+ } else {
165
+ var ranges: AttributeMarkerColoursRange[] = [];
166
+ (this.widgetConfig.thresholds as [number, string][]).sort((x, y) => (x[0] > y[0]) ? -1 : 1).map((threshold, index) => {
167
+ var range: AttributeMarkerColoursRange = {
168
+ min: threshold[0],
169
+ colour: threshold[1].replace('#', '')
170
+ }
171
+ ranges.push(range);
172
+ })
173
+ var colorsNum: RangeAttributeMarkerColours = {
174
+ type: 'range',
175
+ ranges: ranges
176
+ };
177
+ this.markers[asset.type!].colours = colorsNum;
178
+ }
179
+ }
180
+ return html`
181
+ <or-map-marker-asset .asset="${asset}" .config="${this.markers}"></or-map-marker-asset>
182
+ `
183
+ })
184
+ }
185
+
186
+
187
+ }
@@ -0,0 +1,157 @@
1
+ import {css, html, PropertyValues, TemplateResult } from "lit";
2
+ import { customElement } from "lit/decorators.js";
3
+ import {OrAssetWidget} from "../util/or-asset-widget";
4
+ import {WidgetManifest} from "../util/or-widget";
5
+ import {WidgetConfig} from "../util/widget-config";
6
+ import {WidgetSettings} from "../util/widget-settings";
7
+ import {TableSettings} from "../settings/table-settings";
8
+ import {OrMwcTableRowClickEvent, TableColumn, TableRow, TableConfig} from "@openremote/or-mwc-components/or-mwc-table";
9
+ import {i18next} from "@openremote/or-translate";
10
+ import {Util} from "@openremote/core";
11
+ import {Asset, AssetModelUtil} from "@openremote/model";
12
+ import "@openremote/or-mwc-components/or-mwc-table";
13
+
14
+ export interface TableWidgetConfig extends WidgetConfig {
15
+ assetType?: string
16
+ assetIds: string[]
17
+ attributeNames: string[],
18
+ tableSize: number,
19
+ tableOptions: number[]
20
+ }
21
+
22
+ function getDefaultConfig(): TableWidgetConfig {
23
+ return {
24
+ assetType: undefined,
25
+ assetIds: [],
26
+ attributeNames: [],
27
+ tableSize: 10,
28
+ tableOptions: [10, 25, 100]
29
+ }
30
+ }
31
+
32
+ const styling = css`
33
+ #widget-wrapper {
34
+ height: 100%;
35
+ overflow: hidden;
36
+ }
37
+ `
38
+
39
+ @customElement("table-widget")
40
+ export class TableWidget extends OrAssetWidget {
41
+
42
+ protected widgetConfig!: TableWidgetConfig;
43
+
44
+ static getManifest(): WidgetManifest {
45
+ return {
46
+ displayName: "Table",
47
+ displayIcon: "table",
48
+ getContentHtml(config: WidgetConfig): OrAssetWidget {
49
+ return new TableWidget(config);
50
+ },
51
+ getDefaultConfig(): WidgetConfig {
52
+ return getDefaultConfig();
53
+ },
54
+ getSettingsHtml(config: WidgetConfig): WidgetSettings {
55
+ return new TableSettings(config);
56
+ }
57
+
58
+ }
59
+ }
60
+
61
+ static get styles() {
62
+ return [...super.styles, styling];
63
+ }
64
+
65
+ // TODO: Improve this to be more efficient
66
+ refreshContent(force: boolean): void {
67
+ this.widgetConfig = JSON.parse(JSON.stringify(this.widgetConfig)) as TableWidgetConfig;
68
+ }
69
+
70
+ // Lit Lifecycle
71
+ protected willUpdate(changedProps: PropertyValues) {
72
+ if(changedProps.has('widgetConfig') && this.widgetConfig) {
73
+ this.loadAssets();
74
+ }
75
+
76
+ return super.willUpdate(changedProps);
77
+ }
78
+
79
+
80
+ /* --------------------------------------- */
81
+
82
+ protected loadAssets() {
83
+ if(this.widgetConfig.assetIds.find(id => !this.isAssetLoaded(id))) {
84
+ this.queryAssets({
85
+ ids: this.widgetConfig.assetIds,
86
+ select: {
87
+ attributes: this.widgetConfig.attributeNames
88
+ }
89
+ }).then((assets) => {
90
+ this.loadedAssets = assets;
91
+ })
92
+ }
93
+ }
94
+
95
+ protected getColumns(attributeNames: string[]): TableColumn[] {
96
+ const referenceAsset: Asset | undefined = this.loadedAssets[0];
97
+ const attrColumns = attributeNames.map(attrName => {
98
+ let text = attrName;
99
+ let numeric = false;
100
+ if(this.widgetConfig.assetType && referenceAsset && referenceAsset.attributes && referenceAsset.attributes[attrName]) {
101
+ const attributeDescriptor = AssetModelUtil.getAttributeDescriptor(attrName, this.widgetConfig.assetType);
102
+ text = Util.getAttributeLabel(referenceAsset.attributes[attrName], attributeDescriptor, this.widgetConfig.assetType, true);
103
+ numeric = attributeDescriptor?.format?.asNumber || attributeDescriptor?.format?.asSlider || false;
104
+ }
105
+ return {
106
+ title: text,
107
+ isSortable: true,
108
+ isNumeric: numeric
109
+ } as TableColumn;
110
+ });
111
+ return Array.of({ title: i18next.t('assetName'), isSortable: true }, ...attrColumns);
112
+ }
113
+
114
+ protected getRows(attributeNames: string[]): TableRow[] {
115
+ return this.loadedAssets.map(asset => {
116
+ const attrEntries = attributeNames.map(attrName => {
117
+ if(asset.attributes && asset.attributes[attrName]) {
118
+ const attributeDescriptor = AssetModelUtil.getAttributeDescriptor(attrName, asset.type!);
119
+ const strValue = Util.getAttributeValueAsString(asset.attributes[attrName], attributeDescriptor, asset.type, false);
120
+ const numValue = parseFloat(strValue);
121
+ return isNaN(numValue) ? strValue : numValue;
122
+ } else {
123
+ return 'N.A.'
124
+ }
125
+ })
126
+ const content: any[] = Array.of(asset.name!, ...attrEntries);
127
+ return {
128
+ content: content
129
+ };
130
+ })
131
+ }
132
+
133
+ protected render(): TemplateResult {
134
+ const tableConfig: any = {
135
+ fullHeight: true,
136
+ pagination: {
137
+ enable: true,
138
+ options: this.widgetConfig.tableOptions,
139
+ }
140
+ } as TableConfig
141
+ const columns: TableColumn[] = this.getColumns(this.widgetConfig.attributeNames);
142
+ const rows: TableRow[] = this.getRows(this.widgetConfig.attributeNames);
143
+ return html`
144
+ <div id="widget-wrapper">
145
+ <or-mwc-table .columns="${columns}" .rows="${rows}" .config="${tableConfig}" .paginationSize="${this.widgetConfig.tableSize}"
146
+ @or-mwc-table-row-click="${(ev: OrMwcTableRowClickEvent) => this.onTableRowClick(ev)}"
147
+ ></or-mwc-table>
148
+ </div>
149
+ `;
150
+ }
151
+
152
+ protected onTableRowClick(ev: OrMwcTableRowClickEvent) {
153
+
154
+ }
155
+
156
+
157
+ }
package/tsconfig.json ADDED
@@ -0,0 +1,15 @@
1
+ {
2
+ "extends": "../../tsconfig",
3
+ "compilerOptions": {
4
+ "outDir": "./lib",
5
+ "rootDir": "src"
6
+ },
7
+ "include": [
8
+ "./src"
9
+ ],
10
+ "references": [
11
+ { "path": "../core" },
12
+ { "path": "../rest" },
13
+ { "path": "../model" }
14
+ ]
15
+ }