@record-evolution/widget-switch 1.0.1
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.
- package/README.md +104 -0
- package/dist/src/widget-switch.d.ts +38 -0
- package/dist/tsconfig.tsbuildinfo +1 -0
- package/dist/widget-switch.js +3142 -0
- package/dist/widget-switch.js.map +1 -0
- package/package.json +69 -0
- package/src/default-data.json +46 -0
- package/src/definition-schema.d.ts +91 -0
- package/src/definition-schema.json +121 -0
- package/src/widget-switch.ts +307 -0
package/package.json
ADDED
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@record-evolution/widget-switch",
|
|
3
|
+
"description": "IronFlock Widget widget-switch",
|
|
4
|
+
"license": "MIT",
|
|
5
|
+
"author": "widget-switch",
|
|
6
|
+
"version": "1.0.1",
|
|
7
|
+
"engines": {
|
|
8
|
+
"node": "18.18.2",
|
|
9
|
+
"npm": ">=10.0.2"
|
|
10
|
+
},
|
|
11
|
+
"type": "module",
|
|
12
|
+
"main": "dist/widget-switch.js",
|
|
13
|
+
"types": "dist/src/widget-switch.d.ts",
|
|
14
|
+
"files": [
|
|
15
|
+
"dist",
|
|
16
|
+
"src"
|
|
17
|
+
],
|
|
18
|
+
"scripts": {
|
|
19
|
+
"analyze": "cem analyze --litelement",
|
|
20
|
+
"start": "concurrently -k -r \"npm run watch\" \"wds\"",
|
|
21
|
+
"build": "rollup -c rollup.config.js",
|
|
22
|
+
"watch": "rollup -w -c rollup.config.js",
|
|
23
|
+
"link": "npm link && cd ../RESWARM/frontend && npm link @record-evolution/widget-switch",
|
|
24
|
+
"unlink": "npm unlink --global && cd ../RESWARM/frontend && npm unlink @record-evolution/widget-switch && npm i @record-evolution/widget-switch",
|
|
25
|
+
"types": "cat src/definition-schema.json | json2ts > src/definition-schema.d.ts",
|
|
26
|
+
"start:build": "npm run build && es-dev-server --root-dir dist --app-index index.html --compatibility none --open",
|
|
27
|
+
"release": "npm run build && npm run types && npm version patch --tag-version-prefix='' && git push && git push --tag"
|
|
28
|
+
},
|
|
29
|
+
"dependencies": {
|
|
30
|
+
"@material/web": "^2.3.0",
|
|
31
|
+
"lit": "^3.3.0"
|
|
32
|
+
},
|
|
33
|
+
"devDependencies": {
|
|
34
|
+
"@custom-elements-manifest/analyzer": "^0.10.4",
|
|
35
|
+
"@rollup/plugin-babel": "^6.0.4",
|
|
36
|
+
"@rollup/plugin-commonjs": "^28.0.6",
|
|
37
|
+
"@rollup/plugin-node-resolve": "^16.0.1",
|
|
38
|
+
"@rollup/plugin-replace": "^6.0.2",
|
|
39
|
+
"@rollup/plugin-typescript": "^12.1.3",
|
|
40
|
+
"@typescript-eslint/eslint-plugin": "^8.34.1",
|
|
41
|
+
"@typescript-eslint/parser": "^8.34.1",
|
|
42
|
+
"@web/dev-server": "^0.4.6",
|
|
43
|
+
"concurrently": "^9.1.2",
|
|
44
|
+
"deepmerge": "^4.3.1",
|
|
45
|
+
"es-dev-server": "^2.1.0",
|
|
46
|
+
"eslint": "^9.29.0",
|
|
47
|
+
"eslint-config-prettier": "^10.1.5",
|
|
48
|
+
"husky": "^9.1.7",
|
|
49
|
+
"json-schema-to-typescript": "^15.0.4",
|
|
50
|
+
"lint-staged": "^16.1.2",
|
|
51
|
+
"prettier": "^3.5.3",
|
|
52
|
+
"rimraf": "^6.0.1",
|
|
53
|
+
"rollup": "^4.43.0",
|
|
54
|
+
"tslib": "^2.8.1",
|
|
55
|
+
"typescript": "^5.8.3"
|
|
56
|
+
},
|
|
57
|
+
"repository": {
|
|
58
|
+
"type": "git",
|
|
59
|
+
"url": "git+https://github.com/RecordEvolution/widget-switch.git"
|
|
60
|
+
},
|
|
61
|
+
"keywords": [
|
|
62
|
+
"widget",
|
|
63
|
+
"switch"
|
|
64
|
+
],
|
|
65
|
+
"bugs": {
|
|
66
|
+
"url": "https://github.com/RecordEvolution/widget-switch/issues"
|
|
67
|
+
},
|
|
68
|
+
"homepage": "https://github.com/RecordEvolution/widget-switch#readme"
|
|
69
|
+
}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
{
|
|
2
|
+
"title": "Machine Switch Panel",
|
|
3
|
+
"subTitle": "Main Line Controls",
|
|
4
|
+
"dataseries": [
|
|
5
|
+
{
|
|
6
|
+
"label": "Lamp",
|
|
7
|
+
"stateMap": {
|
|
8
|
+
"on": ">1",
|
|
9
|
+
"off": "<=1"
|
|
10
|
+
},
|
|
11
|
+
"styling": {
|
|
12
|
+
"labelColor": "#000000",
|
|
13
|
+
"valueColor": "#00cc66"
|
|
14
|
+
},
|
|
15
|
+
"data": [
|
|
16
|
+
{
|
|
17
|
+
"tsp": "2025-07-15T10:00:00.000Z",
|
|
18
|
+
"value": 1,
|
|
19
|
+
"actionApp": "machineControlApp",
|
|
20
|
+
"actionDevice": 1,
|
|
21
|
+
"actionTopic": "lamp"
|
|
22
|
+
}
|
|
23
|
+
]
|
|
24
|
+
},
|
|
25
|
+
{
|
|
26
|
+
"label": "Cooling",
|
|
27
|
+
"stateMap": {
|
|
28
|
+
"on": "COOL_ON,1",
|
|
29
|
+
"off": "COOL_OFF,0"
|
|
30
|
+
},
|
|
31
|
+
"styling": {
|
|
32
|
+
"labelColor": "#0033cc",
|
|
33
|
+
"valueColor": "#0099ff"
|
|
34
|
+
},
|
|
35
|
+
"data": [
|
|
36
|
+
{
|
|
37
|
+
"tsp": "2025-07-15T10:05:00.000Z",
|
|
38
|
+
"value": "COOL_ON",
|
|
39
|
+
"actionApp": "coolingSystemApp",
|
|
40
|
+
"actionDevice": 1,
|
|
41
|
+
"actionTopic": "cooling"
|
|
42
|
+
}
|
|
43
|
+
]
|
|
44
|
+
}
|
|
45
|
+
]
|
|
46
|
+
}
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
/* eslint-disable */
|
|
2
|
+
/**
|
|
3
|
+
* This file was automatically generated by json-schema-to-typescript.
|
|
4
|
+
* DO NOT MODIFY IT BY HAND. Instead, modify the source JSONSchema file,
|
|
5
|
+
* and run json-schema-to-typescript to regenerate this file.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
export type Title = string;
|
|
9
|
+
export type Subtitle = string;
|
|
10
|
+
/**
|
|
11
|
+
* The label for the switch.
|
|
12
|
+
*/
|
|
13
|
+
export type Label = string;
|
|
14
|
+
/**
|
|
15
|
+
* The value or list of values that represent the ON state. You can also use an expression like <4 or >33 to specify a numeric range. If a value matches an ON and an OFF state, the ON state will be used.
|
|
16
|
+
*/
|
|
17
|
+
export type ONValues = string;
|
|
18
|
+
/**
|
|
19
|
+
* The value or list of values that represent the OFF state. You can also use an expression like <4 or >33 to specify a numeric range. If a value matches an ON and an OFF state, the ON state will be used.
|
|
20
|
+
*/
|
|
21
|
+
export type OFFValues = string;
|
|
22
|
+
/**
|
|
23
|
+
* This should be an ISO String date like 2023-11-04T22:47:52.351152+00:00. Will only be used to detect age of data.
|
|
24
|
+
*/
|
|
25
|
+
export type Timestamp = string;
|
|
26
|
+
export type Value = string;
|
|
27
|
+
/**
|
|
28
|
+
* The action topic that is called when clicking the switch. The arguments will be True for ON and False for OFF. Refer to the app documentation for available topics to call.
|
|
29
|
+
*/
|
|
30
|
+
export type ActionTopic = string;
|
|
31
|
+
/**
|
|
32
|
+
* You can specify a column in the input data to autogenerate dataseries for each distinct entry in this column. E.g. if you have a table with columns [city, timestamp, temperature] and specify 'city' as split column, then you will get a value field for each city.
|
|
33
|
+
*/
|
|
34
|
+
export type SplitDataBy = string;
|
|
35
|
+
/**
|
|
36
|
+
* The data for the switch state.
|
|
37
|
+
*/
|
|
38
|
+
export type SwitchStateData = {
|
|
39
|
+
tsp?: Timestamp;
|
|
40
|
+
value?: Value;
|
|
41
|
+
actionApp?: ActionApp;
|
|
42
|
+
actionDevice?: ActionDeviceTarget;
|
|
43
|
+
actionTopic?: ActionTopic;
|
|
44
|
+
pivot?: SplitDataBy;
|
|
45
|
+
[k: string]: unknown;
|
|
46
|
+
}[];
|
|
47
|
+
export type Switches = {
|
|
48
|
+
label?: Label;
|
|
49
|
+
stateMap?: StateMap;
|
|
50
|
+
styling?: Styling;
|
|
51
|
+
data?: SwitchStateData;
|
|
52
|
+
[k: string]: unknown;
|
|
53
|
+
}[];
|
|
54
|
+
|
|
55
|
+
export interface InputData {
|
|
56
|
+
title?: Title;
|
|
57
|
+
subTitle?: Subtitle;
|
|
58
|
+
dataseries?: Switches;
|
|
59
|
+
[k: string]: unknown;
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* Specify the values for the ON and OFF states. Any value that does not match to either an ON or OFF state will be considered as UNKNOWN.
|
|
63
|
+
*/
|
|
64
|
+
export interface StateMap {
|
|
65
|
+
on?: ONValues;
|
|
66
|
+
off?: OFFValues;
|
|
67
|
+
[k: string]: unknown;
|
|
68
|
+
}
|
|
69
|
+
export interface Styling {
|
|
70
|
+
labelColor?: LabelColor;
|
|
71
|
+
valueColor?: ValueColor;
|
|
72
|
+
[k: string]: unknown;
|
|
73
|
+
}
|
|
74
|
+
export interface LabelColor {
|
|
75
|
+
[k: string]: unknown;
|
|
76
|
+
}
|
|
77
|
+
export interface ValueColor {
|
|
78
|
+
[k: string]: unknown;
|
|
79
|
+
}
|
|
80
|
+
/**
|
|
81
|
+
* The app that should handle the click on the switch.
|
|
82
|
+
*/
|
|
83
|
+
export interface ActionApp {
|
|
84
|
+
[k: string]: unknown;
|
|
85
|
+
}
|
|
86
|
+
/**
|
|
87
|
+
* The device that should handele the click on the switch. The 'Device ID' column can be used here when using data driven mode.
|
|
88
|
+
*/
|
|
89
|
+
export interface ActionDeviceTarget {
|
|
90
|
+
[k: string]: unknown;
|
|
91
|
+
}
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
{
|
|
2
|
+
"title": "InputData",
|
|
3
|
+
"type": "object",
|
|
4
|
+
"properties": {
|
|
5
|
+
"title": {
|
|
6
|
+
"title": "Title",
|
|
7
|
+
"type": "string",
|
|
8
|
+
"order": 1
|
|
9
|
+
},
|
|
10
|
+
"subTitle": {
|
|
11
|
+
"title": "Subtitle",
|
|
12
|
+
"type": "string",
|
|
13
|
+
"order": 2
|
|
14
|
+
},
|
|
15
|
+
"dataseries": {
|
|
16
|
+
"title": "Switches",
|
|
17
|
+
"type": "array",
|
|
18
|
+
"dataDrivenDisabled": true,
|
|
19
|
+
"order": 2,
|
|
20
|
+
"items": {
|
|
21
|
+
"type": "object",
|
|
22
|
+
"properties": {
|
|
23
|
+
"label": {
|
|
24
|
+
"title": "Label",
|
|
25
|
+
"description": "The label for the switch.",
|
|
26
|
+
"type": "string",
|
|
27
|
+
"order": 1
|
|
28
|
+
},
|
|
29
|
+
"stateMap": {
|
|
30
|
+
"title": "State Map",
|
|
31
|
+
"description": "Specify the values for the ON and OFF states. Any value that does not match to either an ON or OFF state will be considered as UNKNOWN.",
|
|
32
|
+
"type": "object",
|
|
33
|
+
"required": true,
|
|
34
|
+
"order": 3,
|
|
35
|
+
"properties": {
|
|
36
|
+
"on": {
|
|
37
|
+
"title": "ON Values",
|
|
38
|
+
"description": "The value or list of values that represent the ON state. You can also use an expression like <4 or >33 to specify a numeric range. If a value matches an ON and an OFF state, the ON state will be used.",
|
|
39
|
+
"type": "string",
|
|
40
|
+
"required": true
|
|
41
|
+
},
|
|
42
|
+
"off": {
|
|
43
|
+
"title": "OFF Values",
|
|
44
|
+
"description": "The value or list of values that represent the OFF state. You can also use an expression like <4 or >33 to specify a numeric range. If a value matches an ON and an OFF state, the ON state will be used.",
|
|
45
|
+
"type": "string",
|
|
46
|
+
"required": true
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
},
|
|
50
|
+
"styling": {
|
|
51
|
+
"title": "Styling",
|
|
52
|
+
"description": "",
|
|
53
|
+
"type": "object",
|
|
54
|
+
"order": 6,
|
|
55
|
+
"properties": {
|
|
56
|
+
"labelColor": {
|
|
57
|
+
"title": "Label Color",
|
|
58
|
+
"type": "color",
|
|
59
|
+
"color": true,
|
|
60
|
+
"order": 4
|
|
61
|
+
},
|
|
62
|
+
"valueColor": {
|
|
63
|
+
"title": "Value Color",
|
|
64
|
+
"type": "color",
|
|
65
|
+
"color": true,
|
|
66
|
+
"order": 5
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
},
|
|
70
|
+
"data": {
|
|
71
|
+
"title": "Switch State Data",
|
|
72
|
+
"description": "The data for the switch state.",
|
|
73
|
+
"type": "array",
|
|
74
|
+
"order": 4,
|
|
75
|
+
"items": {
|
|
76
|
+
"type": "object",
|
|
77
|
+
"properties": {
|
|
78
|
+
"tsp": {
|
|
79
|
+
"title": "Timestamp",
|
|
80
|
+
"description": "This should be an ISO String date like 2023-11-04T22:47:52.351152+00:00. Will only be used to detect age of data.",
|
|
81
|
+
"type": "string",
|
|
82
|
+
"order": 1
|
|
83
|
+
},
|
|
84
|
+
"value": {
|
|
85
|
+
"title": "Value",
|
|
86
|
+
"type": "string",
|
|
87
|
+
"required": true,
|
|
88
|
+
"order": 2
|
|
89
|
+
},
|
|
90
|
+
"actionApp": {
|
|
91
|
+
"title": "Action App",
|
|
92
|
+
"description": "The app that should handle the click on the switch.",
|
|
93
|
+
"type": "actionApp",
|
|
94
|
+
"order": 3
|
|
95
|
+
},
|
|
96
|
+
"actionDevice": {
|
|
97
|
+
"title": "Action Device Target",
|
|
98
|
+
"description": "The device that should handele the click on the switch. The 'Device ID' column can be used here when using data driven mode.",
|
|
99
|
+
"type": "actionDevice",
|
|
100
|
+
"order": 4
|
|
101
|
+
},
|
|
102
|
+
"actionTopic": {
|
|
103
|
+
"title": "Action Topic",
|
|
104
|
+
"description": "The action topic that is called when clicking the switch. The arguments will be True for ON and False for OFF. Refer to the app documentation for available topics to call.",
|
|
105
|
+
"type": "string",
|
|
106
|
+
"order": 5
|
|
107
|
+
},
|
|
108
|
+
"pivot": {
|
|
109
|
+
"title": "Split Data by",
|
|
110
|
+
"description": "You can specify a column in the input data to autogenerate dataseries for each distinct entry in this column. E.g. if you have a table with columns [city, timestamp, temperature] and specify 'city' as split column, then you will get a value field for each city.",
|
|
111
|
+
"type": "string",
|
|
112
|
+
"order": 6
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
}
|
|
@@ -0,0 +1,307 @@
|
|
|
1
|
+
import { html, css, LitElement, PropertyValueMap } from 'lit'
|
|
2
|
+
import { repeat } from 'lit/directives/repeat.js'
|
|
3
|
+
import { customElement, property, state } from 'lit/decorators.js'
|
|
4
|
+
import { InputData } from './definition-schema.js'
|
|
5
|
+
import '@material/web/switch/switch.js'
|
|
6
|
+
import { MdSwitch } from '@material/web/switch/switch.js'
|
|
7
|
+
|
|
8
|
+
type Dataseries = Exclude<InputData['dataseries'], undefined>[number] & { needleValue?: number }
|
|
9
|
+
type Data = Exclude<Dataseries['data'], undefined>[number]
|
|
10
|
+
type Theme = {
|
|
11
|
+
theme_name: string
|
|
12
|
+
theme_object: any
|
|
13
|
+
}
|
|
14
|
+
@customElement('widget-switch-versionplaceholder')
|
|
15
|
+
export class WidgetSwitch extends LitElement {
|
|
16
|
+
@property({ type: Object })
|
|
17
|
+
inputData?: InputData
|
|
18
|
+
|
|
19
|
+
@property({ type: Object })
|
|
20
|
+
theme?: Theme
|
|
21
|
+
|
|
22
|
+
@state()
|
|
23
|
+
private dataSets: Map<string, Dataseries> = new Map()
|
|
24
|
+
|
|
25
|
+
@state()
|
|
26
|
+
private textActive: boolean = true
|
|
27
|
+
|
|
28
|
+
@state() private themeBgColor?: string
|
|
29
|
+
@state() private themeTitleColor?: string
|
|
30
|
+
@state() private themeSubtitleColor?: string
|
|
31
|
+
|
|
32
|
+
version: string = 'versionplaceholder'
|
|
33
|
+
|
|
34
|
+
private resizeObserver: ResizeObserver
|
|
35
|
+
|
|
36
|
+
valueContainer?: HTMLDivElement
|
|
37
|
+
boxes?: HTMLDivElement[]
|
|
38
|
+
origWidth: number = 0
|
|
39
|
+
origHeight: number = 0
|
|
40
|
+
constructor() {
|
|
41
|
+
super()
|
|
42
|
+
this.resizeObserver = new ResizeObserver(this.applyData.bind(this))
|
|
43
|
+
this.resizeObserver.observe(this)
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
disconnectedCallback() {
|
|
47
|
+
super.disconnectedCallback()
|
|
48
|
+
if (this.resizeObserver) {
|
|
49
|
+
this.resizeObserver.disconnect()
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
protected firstUpdated(_changedProperties: PropertyValueMap<any> | Map<PropertyKey, unknown>) {
|
|
54
|
+
this.valueContainer = this?.shadowRoot?.querySelector('.value-container') as HTMLDivElement
|
|
55
|
+
|
|
56
|
+
this.registerTheme(this.theme)
|
|
57
|
+
this.transformData()
|
|
58
|
+
this.applyData()
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
update(changedProperties: Map<string, any>) {
|
|
62
|
+
if (changedProperties.has('inputData')) {
|
|
63
|
+
this.transformData()
|
|
64
|
+
this.applyData()
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
if (changedProperties.has('theme')) {
|
|
68
|
+
this.registerTheme(this.theme)
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
super.update(changedProperties)
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
registerTheme(theme?: Theme) {
|
|
75
|
+
const cssTextColor = getComputedStyle(this).getPropertyValue('--re-text-color').trim()
|
|
76
|
+
const cssBgColor = getComputedStyle(this).getPropertyValue('--re-tile-background-color').trim()
|
|
77
|
+
this.themeBgColor = cssBgColor || this.theme?.theme_object?.backgroundColor
|
|
78
|
+
this.themeTitleColor = cssTextColor || this.theme?.theme_object?.title?.textStyle?.color
|
|
79
|
+
this.themeSubtitleColor =
|
|
80
|
+
cssTextColor || this.theme?.theme_object?.title?.subtextStyle?.color || this.themeTitleColor
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
applyData() {}
|
|
84
|
+
|
|
85
|
+
async transformData() {
|
|
86
|
+
if (!this.inputData) return
|
|
87
|
+
this.dataSets.forEach((d) => {
|
|
88
|
+
d.label ??= ''
|
|
89
|
+
})
|
|
90
|
+
this.dataSets = new Map()
|
|
91
|
+
this.inputData?.dataseries
|
|
92
|
+
// ?.sort((a, b) => a.order - b.order)
|
|
93
|
+
?.forEach((ds) => {
|
|
94
|
+
// pivot data
|
|
95
|
+
const distincts = [...new Set(ds.data?.map((d: Data) => d.pivot))].sort() as string[]
|
|
96
|
+
ds.selected = undefined
|
|
97
|
+
|
|
98
|
+
distincts.forEach((piv) => {
|
|
99
|
+
const prefix = piv ?? ''
|
|
100
|
+
const label = ds.label ?? ''
|
|
101
|
+
const value =
|
|
102
|
+
distincts.length === 1 ? ds.data?.[0] : ds.data?.filter((d) => d.pivot === piv)?.[0]
|
|
103
|
+
const pds: Dataseries = {
|
|
104
|
+
label: prefix + (!!prefix && !!label ? ' - ' : '') + label,
|
|
105
|
+
actionApp: value?.actionApp,
|
|
106
|
+
actionDevice: value?.actionDevice,
|
|
107
|
+
actionTopic: value?.actionTopic,
|
|
108
|
+
styling: ds.styling,
|
|
109
|
+
selected: this.isSelected(ds, value)
|
|
110
|
+
}
|
|
111
|
+
this.dataSets.set(pds.label ?? '', pds)
|
|
112
|
+
})
|
|
113
|
+
})
|
|
114
|
+
// console.log('Value Datasets', this.dataSets)
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
isSelected(ds: Dataseries, value?: Data): boolean | undefined {
|
|
118
|
+
if (!value) return undefined
|
|
119
|
+
const on = ds?.stateMap?.on
|
|
120
|
+
if (on?.startsWith('<=')) {
|
|
121
|
+
const val = parseFloat(value.value ?? '')
|
|
122
|
+
const comp = parseFloat(on.substring(2))
|
|
123
|
+
return isNaN(val) || isNaN(comp) ? undefined : val <= comp
|
|
124
|
+
}
|
|
125
|
+
if (on?.startsWith('<')) {
|
|
126
|
+
const val = parseFloat(value.value ?? '')
|
|
127
|
+
const comp = parseFloat(on.substring(1))
|
|
128
|
+
return isNaN(val) || isNaN(comp) ? undefined : val < comp
|
|
129
|
+
}
|
|
130
|
+
if (on?.startsWith('>=')) {
|
|
131
|
+
const val = parseFloat(value.value ?? '')
|
|
132
|
+
const comp = parseFloat(on.substring(2))
|
|
133
|
+
return isNaN(val) || isNaN(comp) ? undefined : val >= comp
|
|
134
|
+
}
|
|
135
|
+
if (on?.startsWith('>')) {
|
|
136
|
+
const val = parseFloat(value.value ?? '')
|
|
137
|
+
const comp = parseFloat(on.substring(1))
|
|
138
|
+
return isNaN(val) || isNaN(comp) ? undefined : val > comp
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
const off = ds?.stateMap?.off
|
|
142
|
+
if (off?.startsWith('<=')) {
|
|
143
|
+
const val = parseFloat(value.value ?? '')
|
|
144
|
+
const comp = parseFloat(off.substring(2))
|
|
145
|
+
return isNaN(val) || isNaN(comp) ? undefined : val > comp
|
|
146
|
+
}
|
|
147
|
+
if (off?.startsWith('<')) {
|
|
148
|
+
const val = parseFloat(value.value ?? '')
|
|
149
|
+
const comp = parseFloat(off.substring(1))
|
|
150
|
+
return isNaN(val) || isNaN(comp) ? undefined : val <= comp
|
|
151
|
+
}
|
|
152
|
+
if (off?.startsWith('>=')) {
|
|
153
|
+
const val = parseFloat(value.value ?? '')
|
|
154
|
+
const comp = parseFloat(off.substring(2))
|
|
155
|
+
return isNaN(val) || isNaN(comp) ? undefined : val < comp
|
|
156
|
+
}
|
|
157
|
+
if (off?.startsWith('>')) {
|
|
158
|
+
const val = parseFloat(value.value ?? '')
|
|
159
|
+
const comp = parseFloat(off.substring(1))
|
|
160
|
+
return isNaN(val) || isNaN(comp) ? undefined : val <= comp
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
const onValues = on?.split(',').map((v) => v.trim().replace('"', '').replace("'", '')) ?? []
|
|
164
|
+
if (onValues.includes(String(value.value) ?? '')) return true
|
|
165
|
+
|
|
166
|
+
const offValues = off?.split(',').map((v) => v.trim().replace('"', '').replace("'", '')) ?? []
|
|
167
|
+
if (offValues.includes(String(value.value) ?? '')) return false
|
|
168
|
+
|
|
169
|
+
return undefined
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
handleActionSubmit(e: any) {
|
|
173
|
+
const switchEl = e.target
|
|
174
|
+
const payload = {
|
|
175
|
+
args: switchEl?.selected,
|
|
176
|
+
actionApp: switchEl?.actionApp,
|
|
177
|
+
actionDevice: switchEl?.actionDevice,
|
|
178
|
+
actionTopic: switchEl?.actionTopic,
|
|
179
|
+
label: switchEl?.label
|
|
180
|
+
}
|
|
181
|
+
console.log('Action Submit', payload)
|
|
182
|
+
this.dispatchEvent(
|
|
183
|
+
new CustomEvent('action-submit', {
|
|
184
|
+
detail: payload,
|
|
185
|
+
bubbles: false,
|
|
186
|
+
composed: false
|
|
187
|
+
})
|
|
188
|
+
)
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
static styles = css`
|
|
192
|
+
:host {
|
|
193
|
+
display: block;
|
|
194
|
+
font-family: sans-serif;
|
|
195
|
+
box-sizing: border-box;
|
|
196
|
+
position: relative;
|
|
197
|
+
margin: auto;
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
.paging:not([active]) {
|
|
201
|
+
display: none !important;
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
.wrapper {
|
|
205
|
+
display: flex;
|
|
206
|
+
flex-direction: column;
|
|
207
|
+
height: 100%;
|
|
208
|
+
width: 100%;
|
|
209
|
+
padding: 16px;
|
|
210
|
+
box-sizing: border-box;
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
h3 {
|
|
214
|
+
margin: 0;
|
|
215
|
+
max-width: 300px;
|
|
216
|
+
overflow: hidden;
|
|
217
|
+
text-overflow: ellipsis;
|
|
218
|
+
white-space: nowrap;
|
|
219
|
+
}
|
|
220
|
+
p {
|
|
221
|
+
margin: 10px 0 0 0;
|
|
222
|
+
max-width: 300px;
|
|
223
|
+
font-size: 14px;
|
|
224
|
+
line-height: 17px;
|
|
225
|
+
overflow: hidden;
|
|
226
|
+
text-overflow: ellipsis;
|
|
227
|
+
white-space: nowrap;
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
.value-container {
|
|
231
|
+
display: flex;
|
|
232
|
+
flex-wrap: wrap;
|
|
233
|
+
align-items: center;
|
|
234
|
+
justify-content: center;
|
|
235
|
+
line-height: 0.9;
|
|
236
|
+
flex: 1;
|
|
237
|
+
overflow: hidden;
|
|
238
|
+
position: relative;
|
|
239
|
+
gap: 12px;
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
.switch {
|
|
243
|
+
overflow: hidden;
|
|
244
|
+
display: flex;
|
|
245
|
+
align-items: center;
|
|
246
|
+
gap: 12px;
|
|
247
|
+
box-sizing: border-box;
|
|
248
|
+
/* border-left: 4px solid #ddd; */
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
.no-data {
|
|
252
|
+
font-size: 20px;
|
|
253
|
+
display: flex;
|
|
254
|
+
height: 100%;
|
|
255
|
+
width: 100%;
|
|
256
|
+
text-align: center;
|
|
257
|
+
align-items: center;
|
|
258
|
+
justify-content: center;
|
|
259
|
+
}
|
|
260
|
+
`
|
|
261
|
+
|
|
262
|
+
render() {
|
|
263
|
+
return html`
|
|
264
|
+
<div
|
|
265
|
+
class="wrapper"
|
|
266
|
+
style="background-color: ${this.themeBgColor}; color: ${this.themeTitleColor}"
|
|
267
|
+
>
|
|
268
|
+
<header>
|
|
269
|
+
<h3 class="paging" ?active=${this.inputData?.title}>${this.inputData?.title}</h3>
|
|
270
|
+
<p
|
|
271
|
+
class="paging"
|
|
272
|
+
?active=${this.inputData?.subTitle}
|
|
273
|
+
style="color: ${this.themeSubtitleColor}"
|
|
274
|
+
>
|
|
275
|
+
${this.inputData?.subTitle}
|
|
276
|
+
</p>
|
|
277
|
+
</header>
|
|
278
|
+
|
|
279
|
+
<div class="paging no-data" ?active=${!this.dataSets.size}>No Data</div>
|
|
280
|
+
<div class="value-container">
|
|
281
|
+
${repeat(
|
|
282
|
+
[...this.dataSets.entries()].sort(),
|
|
283
|
+
([label]) => label,
|
|
284
|
+
([label, ds]) => {
|
|
285
|
+
return html`
|
|
286
|
+
<div class="switch" label="${label}">
|
|
287
|
+
${label}
|
|
288
|
+
<label
|
|
289
|
+
><md-switch
|
|
290
|
+
aria-label="${label}"
|
|
291
|
+
?selected="${!!ds.selected}"
|
|
292
|
+
.actionApp="${ds?.actionApp}"
|
|
293
|
+
.actionDevice="${ds?.actionDevice}"
|
|
294
|
+
.actionTopic="${ds?.actionTopic}"
|
|
295
|
+
.label="${label}"
|
|
296
|
+
@change="${this.handleActionSubmit}"
|
|
297
|
+
></md-switch
|
|
298
|
+
></label>
|
|
299
|
+
</div>
|
|
300
|
+
`
|
|
301
|
+
}
|
|
302
|
+
)}
|
|
303
|
+
</div>
|
|
304
|
+
</div>
|
|
305
|
+
`
|
|
306
|
+
}
|
|
307
|
+
}
|