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

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 (146) 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-tree.d.ts +25 -0
  25. package/lib/or-dashboard-tree.js +62 -0
  26. package/lib/or-dashboard-tree.js.map +1 -0
  27. package/lib/or-dashboard-widgetcontainer.d.ts +23 -0
  28. package/lib/or-dashboard-widgetcontainer.js +20 -0
  29. package/lib/or-dashboard-widgetcontainer.js.map +1 -0
  30. package/lib/or-dashboard-widgetsettings.d.ts +15 -0
  31. package/lib/or-dashboard-widgetsettings.js +16 -0
  32. package/lib/or-dashboard-widgetsettings.js.map +1 -0
  33. package/lib/panels/assettypes-panel.d.ts +44 -0
  34. package/lib/panels/assettypes-panel.js +51 -0
  35. package/lib/panels/assettypes-panel.js.map +1 -0
  36. package/lib/panels/attributes-panel.d.ts +41 -0
  37. package/lib/panels/attributes-panel.js +126 -0
  38. package/lib/panels/attributes-panel.js.map +1 -0
  39. package/lib/panels/thresholds-panel.d.ts +39 -0
  40. package/lib/panels/thresholds-panel.js +129 -0
  41. package/lib/panels/thresholds-panel.js.map +1 -0
  42. package/lib/service/dashboard-service.d.ts +13 -0
  43. package/lib/service/dashboard-service.js +1 -0
  44. package/lib/service/dashboard-service.js.map +1 -0
  45. package/lib/service/widget-service.d.ts +8 -0
  46. package/lib/service/widget-service.js +1 -0
  47. package/lib/service/widget-service.js.map +1 -0
  48. package/lib/settings/attribute-input-settings.d.ts +13 -0
  49. package/lib/settings/attribute-input-settings.js +36 -0
  50. package/lib/settings/attribute-input-settings.js.map +1 -0
  51. package/lib/settings/chart-settings.d.ts +30 -0
  52. package/lib/settings/chart-settings.js +144 -0
  53. package/lib/settings/chart-settings.js.map +1 -0
  54. package/lib/settings/gauge-settings.d.ts +15 -0
  55. package/lib/settings/gauge-settings.js +37 -0
  56. package/lib/settings/gauge-settings.js.map +1 -0
  57. package/lib/settings/image-settings.d.ts +17 -0
  58. package/lib/settings/image-settings.js +52 -0
  59. package/lib/settings/image-settings.js.map +1 -0
  60. package/lib/settings/kpi-settings.d.ts +15 -0
  61. package/lib/settings/kpi-settings.js +47 -0
  62. package/lib/settings/kpi-settings.js.map +1 -0
  63. package/lib/settings/map-settings.d.ts +21 -0
  64. package/lib/settings/map-settings.js +72 -0
  65. package/lib/settings/map-settings.js.map +1 -0
  66. package/lib/settings/table-settings.d.ts +14 -0
  67. package/lib/settings/table-settings.js +33 -0
  68. package/lib/settings/table-settings.js.map +1 -0
  69. package/lib/style.d.ts +1 -0
  70. package/lib/style.js +99 -0
  71. package/lib/style.js.map +1 -0
  72. package/lib/util/or-asset-widget.d.ts +20 -0
  73. package/lib/util/or-asset-widget.js +1 -0
  74. package/lib/util/or-asset-widget.js.map +1 -0
  75. package/lib/util/or-widget.d.ts +31 -0
  76. package/lib/util/or-widget.js +1 -0
  77. package/lib/util/or-widget.js.map +1 -0
  78. package/lib/util/settings-panel.d.ts +9 -0
  79. package/lib/util/settings-panel.js +56 -0
  80. package/lib/util/settings-panel.js.map +1 -0
  81. package/lib/util/widget-config.d.ts +2 -0
  82. package/lib/util/widget-config.js +1 -0
  83. package/lib/util/widget-config.js.map +1 -0
  84. package/lib/util/widget-settings.d.ts +23 -0
  85. package/lib/util/widget-settings.js +1 -0
  86. package/lib/util/widget-settings.js.map +1 -0
  87. package/lib/widgets/attribute-input-widget.d.ts +24 -0
  88. package/lib/widgets/attribute-input-widget.js +31 -0
  89. package/lib/widgets/attribute-input-widget.js.map +1 -0
  90. package/lib/widgets/chart-widget.d.ts +25 -0
  91. package/lib/widgets/chart-widget.js +15 -0
  92. package/lib/widgets/chart-widget.js.map +1 -0
  93. package/lib/widgets/gauge-widget.d.ts +22 -0
  94. package/lib/widgets/gauge-widget.js +12 -0
  95. package/lib/widgets/gauge-widget.js.map +1 -0
  96. package/lib/widgets/image-widget.d.ts +25 -0
  97. package/lib/widgets/image-widget.js +54 -0
  98. package/lib/widgets/image-widget.js.map +1 -0
  99. package/lib/widgets/kpi-widget.d.ts +21 -0
  100. package/lib/widgets/kpi-widget.js +8 -0
  101. package/lib/widgets/kpi-widget.js.map +1 -0
  102. package/lib/widgets/map-widget.d.ts +39 -0
  103. package/lib/widgets/map-widget.js +9 -0
  104. package/lib/widgets/map-widget.js.map +1 -0
  105. package/lib/widgets/table-widget.d.ts +25 -0
  106. package/lib/widgets/table-widget.js +12 -0
  107. package/lib/widgets/table-widget.js.map +1 -0
  108. package/package.json +32 -0
  109. package/src/controls/dashboard-refresh-controls.ts +100 -0
  110. package/src/index.ts +731 -0
  111. package/src/or-dashboard-boardsettings.ts +249 -0
  112. package/src/or-dashboard-browser.ts +160 -0
  113. package/src/or-dashboard-engine.ts +17 -0
  114. package/src/or-dashboard-keyhandler.ts +25 -0
  115. package/src/or-dashboard-preview.ts +713 -0
  116. package/src/or-dashboard-tree.ts +304 -0
  117. package/src/or-dashboard-widgetcontainer.ts +155 -0
  118. package/src/or-dashboard-widgetsettings.ts +91 -0
  119. package/src/panels/assettypes-panel.ts +311 -0
  120. package/src/panels/attributes-panel.ts +304 -0
  121. package/src/panels/thresholds-panel.ts +285 -0
  122. package/src/service/dashboard-service.ts +89 -0
  123. package/src/service/widget-service.ts +48 -0
  124. package/src/settings/attribute-input-settings.ts +79 -0
  125. package/src/settings/chart-settings.ts +306 -0
  126. package/src/settings/gauge-settings.ts +93 -0
  127. package/src/settings/image-settings.ts +175 -0
  128. package/src/settings/kpi-settings.ts +106 -0
  129. package/src/settings/map-settings.ts +185 -0
  130. package/src/settings/table-settings.ts +92 -0
  131. package/src/style.ts +104 -0
  132. package/src/util/or-asset-widget.ts +110 -0
  133. package/src/util/or-widget.ts +60 -0
  134. package/src/util/settings-panel.ts +93 -0
  135. package/src/util/widget-config.ts +2 -0
  136. package/src/util/widget-settings.ts +58 -0
  137. package/src/widgets/attribute-input-widget.ts +143 -0
  138. package/src/widgets/chart-widget.ts +203 -0
  139. package/src/widgets/gauge-widget.ts +111 -0
  140. package/src/widgets/image-widget.ts +180 -0
  141. package/src/widgets/kpi-widget.ts +97 -0
  142. package/src/widgets/map-widget.ts +187 -0
  143. package/src/widgets/table-widget.ts +157 -0
  144. package/tsconfig.json +15 -0
  145. package/tsconfig.tsbuildinfo +1 -0
  146. package/webpack.config.js +10 -0
@@ -0,0 +1,285 @@
1
+ import {InputType, OrInputChangedEvent} from "@openremote/or-mwc-components/or-mwc-input";
2
+ import {css, CSSResult, html, LitElement, PropertyValues, TemplateResult, unsafeCSS} from "lit";
3
+ import {customElement, property} from "lit/decorators.js";
4
+ import {ifDefined} from "lit/directives/if-defined.js";
5
+ import {DefaultColor5} from "@openremote/core";
6
+ import {style} from "../style";
7
+
8
+ export class ThresholdChangeEvent extends CustomEvent<[number, string][]> {
9
+
10
+ public static readonly NAME = "threshold-change";
11
+
12
+ constructor(thresholds: [number, string][]) {
13
+ super(ThresholdChangeEvent.NAME, {
14
+ bubbles: true,
15
+ composed: true,
16
+ detail: thresholds
17
+ });
18
+ }
19
+ }
20
+
21
+ export class TextColorsChangeEvent extends CustomEvent<[string, string][]> {
22
+
23
+ public static readonly NAME = "text-colors-change";
24
+
25
+ constructor(textColors: [string, string][]) {
26
+ super(TextColorsChangeEvent.NAME, {
27
+ bubbles: true,
28
+ composed: true,
29
+ detail: textColors
30
+ });
31
+ }
32
+ }
33
+
34
+ export class BoolColorsChangeEvent extends CustomEvent<{ type: string, false: string, true: string }> {
35
+
36
+ public static readonly NAME = "bool-colors-change";
37
+
38
+ constructor(boolColors: { type: string, false: string, true: string }) {
39
+ super(BoolColorsChangeEvent.NAME, {
40
+ bubbles: true,
41
+ composed: true,
42
+ detail: boolColors
43
+ });
44
+ }
45
+ }
46
+
47
+ const styling = css`
48
+
49
+ #thresholds-list {
50
+ display: flex;
51
+ flex-direction: column;
52
+ gap: 12px;
53
+ }
54
+
55
+ .threshold-list-item {
56
+ display: flex;
57
+ flex-direction: row;
58
+ align-items: center;
59
+ }
60
+
61
+ .threshold-list-item-colour {
62
+ height: 100%;
63
+ padding: 0 4px 0 0;
64
+ }
65
+
66
+ .threshold-list-item:hover .button-clear {
67
+ visibility: visible;
68
+ }
69
+
70
+ .button-clear {
71
+ background: none;
72
+ visibility: hidden;
73
+ color: var(--or-app-color5, ${unsafeCSS(DefaultColor5)});
74
+ --or-icon-fill: var(--or-app-color5, ${unsafeCSS(DefaultColor5)});
75
+ display: inline-block;
76
+ border: none;
77
+ padding: 0;
78
+ cursor: pointer;
79
+ }
80
+
81
+ .button-clear:hover {
82
+ --or-icon-fill: var(--or-app-color4);
83
+ }
84
+
85
+ `;
86
+
87
+ @customElement("thresholds-panel")
88
+ export class ThresholdsPanel extends LitElement {
89
+
90
+ @property()
91
+ protected thresholds: [number, string][] = [];
92
+
93
+ @property()
94
+ protected textColors: [string, string][] = [];
95
+
96
+ @property()
97
+ protected boolColors!: { type: string, false: string, true: string };
98
+
99
+ @property()
100
+ protected readonly min?: number;
101
+
102
+ @property()
103
+ protected readonly max?: number;
104
+
105
+ @property()
106
+ protected readonly valueType!: string;
107
+
108
+ static get styles(): CSSResult[] {
109
+ return [styling, style];
110
+ }
111
+
112
+ protected updated(changedProps: PropertyValues) {
113
+ if (changedProps.has('thresholds') && this.thresholds) {
114
+ this.dispatchEvent(new ThresholdChangeEvent(this.thresholds));
115
+ }
116
+ if (changedProps.has('textColors') && this.textColors) {
117
+ this.dispatchEvent(new TextColorsChangeEvent(this.textColors));
118
+ }
119
+ if (changedProps.has('boolColors') && this.boolColors) {
120
+ this.dispatchEvent(new BoolColorsChangeEvent(this.boolColors));
121
+ }
122
+ }
123
+
124
+ protected render(): TemplateResult {
125
+ return html`
126
+ <div id="thresholds-list" class="expanded-panel">
127
+
128
+ <!-- Thresholds by number -->
129
+ ${(this.valueType === 'number' || this.valueType === 'positiveInteger'
130
+ || this.valueType === 'positiveNumber' || this.valueType === 'negativeInteger'
131
+ || this.valueType === 'negativeNumber') ? html`
132
+ ${(this.thresholds as [number, string][]).sort((x, y) => (x[0] < y[0]) ? -1 : 1).map((threshold, index) => {
133
+ return html`
134
+ <div class="threshold-list-item">
135
+ <div class="threshold-list-item-colour">
136
+ <or-mwc-input type="${InputType.COLOUR}" value="${threshold[1]}"
137
+ @or-mwc-input-changed="${(event: OrInputChangedEvent) => {
138
+ this.thresholds[index][1] = event.detail.value;
139
+ this.requestUpdate('thresholds');
140
+ }}"
141
+ ></or-mwc-input>
142
+ </div>
143
+ <or-mwc-input type="${InputType.NUMBER}" comfortable .value="${threshold[0]}"
144
+ ?disabled="${index === 0 && this.max}"
145
+ .min="${ifDefined(this.min)}" .max="${ifDefined(this.max)}"
146
+ @or-mwc-input-changed="${(event: OrInputChangedEvent) => {
147
+ if ((!this.min || event.detail.value >= this.min) && (!this.max || event.detail.value <= this.max)) {
148
+ this.thresholds[index][0] = event.detail.value;
149
+ this.requestUpdate('thresholds');
150
+ }
151
+ }}"
152
+ ></or-mwc-input>
153
+ ${index === 0 ? html`
154
+ <button class="button-clear"
155
+ style="margin-left: 8px;">
156
+ <or-icon icon="lock" style="--or-icon-fill: var(--or-app-color5, ${unsafeCSS(DefaultColor5)});"></or-icon>
157
+ </button>
158
+ ` : html`
159
+ <button class="button-clear"
160
+ style="margin-left: 8px;"
161
+ @click="${() => {
162
+ this.removeThreshold(threshold);
163
+ }}">
164
+ <or-icon icon="close-circle"></or-icon>
165
+ </button>
166
+ `}
167
+ </div>
168
+ `
169
+ })}
170
+ <or-mwc-input .type="${InputType.BUTTON}" label="threshold" icon="plus"
171
+ @or-mwc-input-changed="${() => this.addNewThreshold()}">
172
+ </or-mwc-input>
173
+ ` : null}
174
+
175
+ <!-- Thresholds by boolean -->
176
+ ${(this.valueType === 'boolean') ? html`
177
+ <div class="threshold-list-item">
178
+ <div class="threshold-list-item-colour">
179
+ <or-mwc-input type="${InputType.COLOUR}" value="${this.boolColors.true}"
180
+ @or-mwc-input-changed="${(event: OrInputChangedEvent) => {
181
+ this.boolColors.true = event.detail.value;
182
+ this.requestUpdate('boolColors');
183
+ }}"
184
+ ></or-mwc-input>
185
+ </div>
186
+ <or-mwc-input type="${InputType.TEXT}" comfortable .value="${'True'}" .readonly="${true}"
187
+ ></or-mwc-input>
188
+ </div>
189
+ <div class="threshold-list-item">
190
+ <div class="threshold-list-item-colour">
191
+ <or-mwc-input type="${InputType.COLOUR}" value="${this.boolColors.false}"
192
+ @or-mwc-input-changed="${(event: OrInputChangedEvent) => {
193
+ this.boolColors.false = event.detail.value;
194
+ this.requestUpdate('boolColors');
195
+ }}"
196
+ ></or-mwc-input>
197
+ </div>
198
+ <or-mwc-input type="${InputType.TEXT}" comfortable .value="${'False'}" .readonly="${true}"
199
+ ></or-mwc-input>
200
+ </div>
201
+ ` : null}
202
+
203
+ <!-- Thresholds by string -->
204
+ ${(this.valueType === 'text' && this.textColors) ? html`
205
+ ${(this.textColors as [string, string][]).map((threshold, index) => {
206
+ return html`
207
+ <div class="threshold-list-item">
208
+ <div class="threshold-list-item-colour">
209
+ <or-mwc-input type="${InputType.COLOUR}" value="${threshold[1]}"
210
+ @or-mwc-input-changed="${(event: OrInputChangedEvent) => {
211
+ this.textColors[index][1] = event.detail.value;
212
+ this.requestUpdate('textColors');
213
+ }}"
214
+ ></or-mwc-input>
215
+ </div>
216
+ <or-mwc-input type="${InputType.TEXT}" comfortable .value="${threshold[0]}"
217
+ @or-mwc-input-changed="${(event: OrInputChangedEvent) => {
218
+ this.textColors[index][0] = event.detail.value;
219
+ this.requestUpdate('textColors');
220
+ }}"
221
+
222
+ ></or-mwc-input>
223
+ ${index === 0 ? html`
224
+ <button class="button-clear"
225
+ style="margin-left: 8px;">
226
+ <or-icon icon="lock" style="--or-icon-fill: var(--or-app-color5, ${unsafeCSS(DefaultColor5)});"></or-icon>
227
+ </button>
228
+ ` : html`
229
+ <button class="button-clear"
230
+ style="margin-left: 8px;"
231
+ @click="${() => {
232
+ this.removeThreshold(threshold);
233
+ }}">
234
+ <or-icon icon="close-circle"></or-icon>
235
+ </button>
236
+ `}
237
+ </div>
238
+ `
239
+ })}
240
+ <or-mwc-input .type="${InputType.BUTTON}" label="threshold" icon="plus"
241
+ @or-mwc-input-changed="${() => this.addNewThreshold()}">
242
+ </or-mwc-input>
243
+ ` : null}
244
+ </div>
245
+ `
246
+ }
247
+
248
+ protected removeThreshold(threshold: [any, string]) {
249
+ switch (typeof threshold[0]) {
250
+ case "number":
251
+ this.thresholds = (this.thresholds as [number, string][]).filter((x) => x !== threshold);
252
+ break;
253
+ default:
254
+ this.textColors = (this.textColors as [string, string][]).filter((x) => x !== threshold);
255
+ break;
256
+ }
257
+ }
258
+
259
+ protected addThreshold(threshold: [any, string]) {
260
+ switch (typeof threshold[0]) {
261
+ case "number":
262
+ (this.thresholds as [number, string][]).push(threshold as [number, string]);
263
+ this.requestUpdate('thresholds');
264
+ break;
265
+ default:
266
+ (this.textColors as [string, string][]).push(threshold as [string, string]);
267
+ this.requestUpdate('textColors');
268
+ break;
269
+ }
270
+ }
271
+
272
+ protected addNewThreshold() {
273
+ if (this.valueType === 'text') {
274
+ this.addThreshold(["new", "#000000"]);
275
+ } else {
276
+ const suggestedValue = (this.thresholds[this.thresholds.length - 1][0] + 10);
277
+ this.addThreshold([(!this.max || suggestedValue <= this.max ? suggestedValue : this.max), "#000000"]);
278
+ }
279
+ this.updateComplete.then(() => {
280
+ const elem = this.shadowRoot?.getElementById('thresholds-list') as HTMLElement;
281
+ const inputField = Array.from(elem.children)[elem.children.length - 2] as HTMLElement;
282
+ (inputField.children[1] as HTMLElement).setAttribute('focused', 'true');
283
+ })
284
+ }
285
+ }
@@ -0,0 +1,89 @@
1
+ import {Dashboard, DashboardRefreshInterval, DashboardScalingPreset, DashboardScreenPreset} from "@openremote/model";
2
+ import manager from "@openremote/core";
3
+ import {i18next} from "@openremote/or-translate";
4
+
5
+ export enum DashboardSizeOption {
6
+ DESKTOP, MOBILE
7
+ }
8
+
9
+ export class DashboardService {
10
+
11
+ public static async create(dashboard?: Dashboard, size: DashboardSizeOption = DashboardSizeOption.DESKTOP, realm: string = manager.displayRealm, post = true): Promise<Dashboard> {
12
+ const randomId = () => (Math.random() + 1).toString(36).substring(2);
13
+ if(!dashboard) {
14
+ dashboard = {
15
+ realm: realm,
16
+ displayName: this.getDefaultDisplayName(size),
17
+ template: {
18
+ id: randomId(),
19
+ columns: this.getDefaultColumns(size),
20
+ maxScreenWidth: this.getDefaultMaxScreenWidth(size),
21
+ refreshInterval: DashboardRefreshInterval.OFF,
22
+ screenPresets: this.getDefaultScreenPresets(size),
23
+ }
24
+ } as Dashboard;
25
+ } else {
26
+ dashboard.id = randomId();
27
+ if(dashboard.template) {
28
+ dashboard.template.id = randomId();
29
+ dashboard.template.widgets?.forEach(w => w.id = randomId());
30
+ }
31
+ }
32
+
33
+ if(post) {
34
+ return (await manager.rest.api.DashboardResource.create(dashboard)).data;
35
+ } else {
36
+ return dashboard;
37
+ }
38
+ }
39
+
40
+ public static async delete(id: string, realm: string = manager.displayRealm) {
41
+ return (await manager.rest.api.DashboardResource.delete(realm, id)).data;
42
+ }
43
+
44
+
45
+ /* -------------------------------------------------------- */
46
+
47
+ private static getDefaultColumns(preset: DashboardSizeOption): number {
48
+ switch (preset) {
49
+ case DashboardSizeOption.MOBILE: { return 4; }
50
+ case DashboardSizeOption.DESKTOP: { return 12; }
51
+ default: { return 12; }
52
+ }
53
+ }
54
+
55
+ private static getDefaultDisplayName(preset: DashboardSizeOption): string {
56
+ switch (preset) {
57
+ case DashboardSizeOption.DESKTOP: { return i18next.t('dashboard.initialName'); }
58
+ case DashboardSizeOption.MOBILE: { return i18next.t('dashboard.initialName') + " (" + i18next.t('dashboard.size.mobile') + ")"; }
59
+ }
60
+ }
61
+
62
+ private static getDefaultScreenPresets(preset: DashboardSizeOption): DashboardScreenPreset[] {
63
+ switch (preset) {
64
+ case DashboardSizeOption.MOBILE: {
65
+ return [{
66
+ id: "mobile",
67
+ displayName: 'dashboard.size.mobile',
68
+ breakpoint: 640,
69
+ scalingPreset: DashboardScalingPreset.KEEP_LAYOUT
70
+ }];
71
+ }
72
+ default: { // DashboardSizeOption.DESKTOP since that is the default
73
+ return [{
74
+ id: "mobile",
75
+ displayName: 'dashboard.size.mobile',
76
+ breakpoint: 640,
77
+ scalingPreset: DashboardScalingPreset.WRAP_TO_SINGLE_COLUMN
78
+ }];
79
+ }
80
+ }
81
+ }
82
+
83
+ private static getDefaultMaxScreenWidth(preset: DashboardSizeOption): number {
84
+ switch (preset) {
85
+ case DashboardSizeOption.DESKTOP: return 4000;
86
+ case DashboardSizeOption.MOBILE: return 640;
87
+ }
88
+ }
89
+ }
@@ -0,0 +1,48 @@
1
+ import {DashboardWidget} from "@openremote/model";
2
+ import {widgetTypes} from "../index";
3
+ import {WidgetConfig} from "../util/widget-config";
4
+ import {Util} from "@openremote/core";
5
+ import {WidgetManifest} from "../util/or-widget";
6
+
7
+ export class WidgetService {
8
+
9
+ public static getManifest(widgetTypeId: string) {
10
+ const manifest = widgetTypes.get(widgetTypeId);
11
+ if(!manifest) {
12
+ throw new Error("Widget manifest could not be found during widget creation.");
13
+ }
14
+ return manifest;
15
+ }
16
+
17
+ public static async placeNew(widgetTypeId: string, x: number, y: number): Promise<DashboardWidget> {
18
+ const randomId = (Math.random() + 1).toString(36).substring(2);
19
+ const manifest = this.getManifest(widgetTypeId);
20
+ const widget = {
21
+ id: randomId,
22
+ displayName: manifest.displayName,
23
+ gridItem: {
24
+ id: randomId,
25
+ x: x,
26
+ y: y,
27
+ w: 2,
28
+ h: 2,
29
+ minW: manifest.minColumnWidth,
30
+ minH: manifest.minColumnHeight,
31
+ minPixelW: manifest.minPixelWidth,
32
+ minPixelH: manifest.minPixelHeight,
33
+ noResize: false,
34
+ noMove: false,
35
+ locked: false,
36
+ }, // Left empty until it is generated by or-dashboard-preview
37
+ widgetConfig: manifest.getDefaultConfig(),
38
+ widgetTypeId: widgetTypeId
39
+ } as DashboardWidget;
40
+ return widget;
41
+ }
42
+
43
+ // Method used to correct the OrWidgetConfig specification
44
+ // So, if certain fields are removed or invalid, it will be corrected by merging the object with the default OrWidgetConfig.
45
+ public static correctToConfigSpec(manifest: WidgetManifest, widgetConfig: WidgetConfig) {
46
+ return Util.mergeObjects(manifest.getDefaultConfig(), widgetConfig, false) as WidgetConfig;
47
+ }
48
+ }
@@ -0,0 +1,79 @@
1
+ import {css, html, TemplateResult } from "lit";
2
+ import { customElement } from "lit/decorators.js";
3
+ import {AttributeInputWidgetConfig} from "../widgets/attribute-input-widget";
4
+ import {AttributesSelectEvent} from "../panels/attributes-panel";
5
+ import { InputType, OrInputChangedEvent } from "@openremote/or-mwc-components/or-mwc-input";
6
+ import {AssetWidgetSettings} from "../util/or-asset-widget";
7
+
8
+ const styling = css`
9
+ .switch-container {
10
+ display: flex;
11
+ align-items: center;
12
+ justify-content: space-between;
13
+ }
14
+ `;
15
+
16
+ @customElement("attribute-input-settings")
17
+ export class AttributeInputSettings extends AssetWidgetSettings {
18
+
19
+ protected readonly widgetConfig!: AttributeInputWidgetConfig;
20
+
21
+ static get styles() {
22
+ return [...super.styles, styling];
23
+ }
24
+
25
+ protected render(): TemplateResult {
26
+ return html`
27
+ <div>
28
+ <!-- Attribute selection -->
29
+ <settings-panel displayName="attributes" expanded="${true}">
30
+ <attributes-panel .attributeRefs="${this.widgetConfig.attributeRefs}" style="padding-bottom: 12px;"
31
+ @attribute-select="${(ev: AttributesSelectEvent) => this.onAttributesSelect(ev)}"
32
+ ></attributes-panel>
33
+ </settings-panel>
34
+
35
+ <!-- Other settings -->
36
+ <settings-panel displayName="settings" expanded="${true}">
37
+ <div>
38
+ <!-- Toggle readonly -->
39
+ <div class="switch-container">
40
+ <span><or-translate value="dashboard.userCanEdit"></or-translate></span>
41
+ <or-mwc-input .type="${InputType.SWITCH}" style="margin: 0 -10px;" .value="${!this.widgetConfig.readonly}"
42
+ @or-mwc-input-changed="${(ev: OrInputChangedEvent) => this.onReadonlyToggle(ev)}"
43
+ ></or-mwc-input>
44
+ </div>
45
+ <!-- Toggle helper text -->
46
+ <div class="switch-container">
47
+ <span><or-translate value="dashboard.showHelperText"></or-translate></span>
48
+ <or-mwc-input .type="${InputType.SWITCH}" style="margin: 0 -10px;" .value="${this.widgetConfig.showHelperText}"
49
+ @or-mwc-input-changed="${(ev: OrInputChangedEvent) => this.onHelperTextToggle(ev)}"
50
+ ></or-mwc-input>
51
+ </div>
52
+ </div>
53
+ </settings-panel>
54
+ </div>
55
+ `;
56
+ }
57
+
58
+ protected onAttributesSelect(ev: AttributesSelectEvent) {
59
+ this.widgetConfig.attributeRefs = ev.detail.attributeRefs;
60
+ if(ev.detail.attributeRefs.length === 1) {
61
+ const asset = ev.detail.assets.find((asset) => asset.id === ev.detail.attributeRefs[0].id);
62
+ if(asset) {
63
+ this.setDisplayName!(asset.name);
64
+ }
65
+ }
66
+ this.notifyConfigUpdate();
67
+ }
68
+
69
+ protected onReadonlyToggle(ev: OrInputChangedEvent) {
70
+ this.widgetConfig.readonly = !ev.detail.value;
71
+ this.notifyConfigUpdate();
72
+ }
73
+
74
+ protected onHelperTextToggle(ev: OrInputChangedEvent) {
75
+ this.widgetConfig.showHelperText = ev.detail.value;
76
+ this.notifyConfigUpdate();
77
+ }
78
+
79
+ }