homebridge-plugin-utils 1.1.0 → 1.2.0
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/build/eslint-rules.mjs +158 -12
- package/dist/featureoptions.d.ts +24 -11
- package/dist/featureoptions.js +32 -22
- package/dist/featureoptions.js.map +1 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.js +1 -0
- package/dist/index.js.map +1 -1
- package/dist/mqttclient.js.map +1 -1
- package/dist/rtp.d.ts +25 -0
- package/dist/rtp.js +178 -0
- package/dist/rtp.js.map +1 -0
- package/dist/ui/featureoptions.js +32 -22
- package/dist/ui/featureoptions.js.map +1 -1
- package/dist/ui/{webui-featureoptions.mjs → webUi-featureoptions.mjs} +353 -117
- package/dist/ui/webUi.mjs +47 -33
- package/dist/utils.d.ts +22 -0
- package/dist/utils.js.map +1 -1
- package/package.json +4 -4
package/dist/ui/webUi.mjs
CHANGED
|
@@ -4,30 +4,43 @@
|
|
|
4
4
|
*/
|
|
5
5
|
"use strict";
|
|
6
6
|
|
|
7
|
+
import { webUiFeatureOptions } from "./webUi-featureoptions.mjs";
|
|
8
|
+
|
|
7
9
|
export class webUi {
|
|
8
10
|
|
|
9
11
|
// Feature options class instance.
|
|
10
|
-
|
|
12
|
+
featureOptions;
|
|
11
13
|
|
|
12
14
|
// First run webUI callback endpoints for customization.
|
|
13
|
-
#
|
|
14
|
-
#firstRunRequired;
|
|
15
|
-
#firstRunSubmit;
|
|
16
|
-
|
|
17
|
-
// Homebridge class instance.
|
|
18
|
-
#homebridge;
|
|
15
|
+
#firstRun;
|
|
19
16
|
|
|
20
17
|
// Plugin name.
|
|
21
18
|
#name;
|
|
22
19
|
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
20
|
+
/**
|
|
21
|
+
* featureOptions - parameters to webUiFeatureOptions.
|
|
22
|
+
* firstRun - first run handlers:
|
|
23
|
+
* isRequired - do we need to run the first run UI workflow?
|
|
24
|
+
* onStart - initialization for the first run webUI to populate forms and other startup tasks.
|
|
25
|
+
* onSubmit - execute the first run workflow, typically a login or configuration validation of some sort.
|
|
26
|
+
* name - plugin name.
|
|
27
|
+
*/
|
|
28
|
+
constructor({ featureOptions, firstRun = {}, name } = {}) {
|
|
29
|
+
|
|
30
|
+
// Defaults for our first run handlers.
|
|
31
|
+
this.firstRun = { isRequired: () => false, onStart: () => true, onSubmit: () => true };
|
|
32
|
+
|
|
33
|
+
// Figure out the options passed in to us.
|
|
34
|
+
this.featureOptions = new webUiFeatureOptions(featureOptions);
|
|
35
|
+
this.firstRun = Object.assign({}, this.firstRun, firstRun);
|
|
30
36
|
this.name = name;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* Render the webUI.
|
|
41
|
+
*/
|
|
42
|
+
// Render the UI.
|
|
43
|
+
show() {
|
|
31
44
|
|
|
32
45
|
// Fire off our UI, catching errors along the way.
|
|
33
46
|
try {
|
|
@@ -36,11 +49,11 @@ export class webUi {
|
|
|
36
49
|
} catch(err) {
|
|
37
50
|
|
|
38
51
|
// If we had an error instantiating or updating the UI, notify the user.
|
|
39
|
-
|
|
52
|
+
homebridge.toast.error(err.message, "Error");
|
|
40
53
|
} finally {
|
|
41
54
|
|
|
42
55
|
// Always leave the UI in a usable place for the end user.
|
|
43
|
-
|
|
56
|
+
homebridge.hideSpinner();
|
|
44
57
|
}
|
|
45
58
|
}
|
|
46
59
|
|
|
@@ -50,7 +63,7 @@ export class webUi {
|
|
|
50
63
|
const buttonFirstRun = document.getElementById("firstRun");
|
|
51
64
|
|
|
52
65
|
// Run a custom initialization handler the user may have provided.
|
|
53
|
-
if(!(await this.#processHandler(this.
|
|
66
|
+
if(!(await this.#processHandler(this.firstRun.onStart))) {
|
|
54
67
|
|
|
55
68
|
return;
|
|
56
69
|
}
|
|
@@ -59,10 +72,10 @@ export class webUi {
|
|
|
59
72
|
buttonFirstRun.addEventListener("click", async () => {
|
|
60
73
|
|
|
61
74
|
// Show the beachball while we setup.
|
|
62
|
-
|
|
75
|
+
homebridge.showSpinner();
|
|
63
76
|
|
|
64
77
|
// Run a custom submit handler the user may have provided.
|
|
65
|
-
if(!(await this.#processHandler(this.
|
|
78
|
+
if(!(await this.#processHandler(this.firstRun.onSubmit))) {
|
|
66
79
|
|
|
67
80
|
return;
|
|
68
81
|
}
|
|
@@ -70,10 +83,10 @@ export class webUi {
|
|
|
70
83
|
// Create our UI.
|
|
71
84
|
document.getElementById("pageFirstRun").style.display = "none";
|
|
72
85
|
document.getElementById("menuWrapper").style.display = "inline-flex";
|
|
73
|
-
this.featureOptions.
|
|
86
|
+
this.featureOptions.show();
|
|
74
87
|
|
|
75
88
|
// All done. Let the user interact with us, although in practice, we shouldn't get here.
|
|
76
|
-
//
|
|
89
|
+
// homebridge.hideSpinner();
|
|
77
90
|
});
|
|
78
91
|
|
|
79
92
|
document.getElementById("pageFirstRun").style.display = "block";
|
|
@@ -83,7 +96,7 @@ export class webUi {
|
|
|
83
96
|
#showSettings() {
|
|
84
97
|
|
|
85
98
|
// Show the beachball while we setup.
|
|
86
|
-
|
|
99
|
+
homebridge.showSpinner();
|
|
87
100
|
|
|
88
101
|
// Highlight the tab in our UI.
|
|
89
102
|
this.#toggleClasses("menuHome", "btn-elegant", "btn-primary");
|
|
@@ -93,18 +106,18 @@ export class webUi {
|
|
|
93
106
|
document.getElementById("pageSupport").style.display = "none";
|
|
94
107
|
document.getElementById("pageFeatureOptions").style.display = "none";
|
|
95
108
|
|
|
96
|
-
|
|
109
|
+
homebridge.showSchemaForm();
|
|
97
110
|
|
|
98
111
|
// All done. Let the user interact with us.
|
|
99
|
-
|
|
112
|
+
homebridge.hideSpinner();
|
|
100
113
|
}
|
|
101
114
|
|
|
102
115
|
// Show the support tab.
|
|
103
116
|
#showSupport() {
|
|
104
117
|
|
|
105
118
|
// Show the beachball while we setup.
|
|
106
|
-
|
|
107
|
-
|
|
119
|
+
homebridge.showSpinner();
|
|
120
|
+
homebridge.hideSchemaForm();
|
|
108
121
|
|
|
109
122
|
// Highlight the tab in our UI.
|
|
110
123
|
this.#toggleClasses("menuHome", "btn-primary", "btn-elegant");
|
|
@@ -115,28 +128,28 @@ export class webUi {
|
|
|
115
128
|
document.getElementById("pageFeatureOptions").style.display = "none";
|
|
116
129
|
|
|
117
130
|
// All done. Let the user interact with us.
|
|
118
|
-
|
|
131
|
+
homebridge.hideSpinner();
|
|
119
132
|
}
|
|
120
133
|
|
|
121
134
|
// Launch our webUI.
|
|
122
135
|
async #launchWebUI() {
|
|
123
136
|
|
|
124
137
|
// Retrieve the current plugin configuration.
|
|
125
|
-
this.featureOptions.currentConfig = await
|
|
138
|
+
this.featureOptions.currentConfig = await homebridge.getPluginConfig();
|
|
126
139
|
|
|
127
140
|
// Add our event listeners to animate the UI.
|
|
128
141
|
document.getElementById("menuHome").addEventListener("click", () => this.#showSupport());
|
|
129
|
-
document.getElementById("menuFeatureOptions").addEventListener("click", () => this.featureOptions.
|
|
142
|
+
document.getElementById("menuFeatureOptions").addEventListener("click", () => this.featureOptions.show());
|
|
130
143
|
document.getElementById("menuSettings").addEventListener("click", () => this.#showSettings());
|
|
131
144
|
|
|
132
145
|
// Get the list of devices the plugin knows about.
|
|
133
|
-
const devices = await
|
|
146
|
+
const devices = await homebridge.getCachedAccessories();
|
|
134
147
|
|
|
135
148
|
// If we've got devices detected, we launch our feature option UI. Otherwise, we launch our first run UI.
|
|
136
|
-
if(this.featureOptions.currentConfig.length && devices?.length && !(await this.#processHandler(this.
|
|
149
|
+
if(this.featureOptions.currentConfig.length && devices?.length && !(await this.#processHandler(this.firstRun.isRequired))) {
|
|
137
150
|
|
|
138
151
|
document.getElementById("menuWrapper").style.display = "inline-flex";
|
|
139
|
-
this.featureOptions.
|
|
152
|
+
this.featureOptions.show();
|
|
140
153
|
|
|
141
154
|
return;
|
|
142
155
|
}
|
|
@@ -145,7 +158,7 @@ export class webUi {
|
|
|
145
158
|
(this.featureOptions.currentConfig[0] ??= { name: this.name }).name ??= this.name;
|
|
146
159
|
|
|
147
160
|
// Update the plugin configuration and launch the first run UI.
|
|
148
|
-
await
|
|
161
|
+
await homebridge.updatePluginConfig(this.featureOptions.currentConfig);
|
|
149
162
|
this.#showFirstRun();
|
|
150
163
|
}
|
|
151
164
|
|
|
@@ -164,6 +177,7 @@ export class webUi {
|
|
|
164
177
|
#toggleClasses(id, removeClass, addClass) {
|
|
165
178
|
|
|
166
179
|
const element = document.getElementById(id);
|
|
180
|
+
|
|
167
181
|
element.classList.remove(removeClass);
|
|
168
182
|
element.classList.add(addClass);
|
|
169
183
|
}
|
package/dist/utils.d.ts
CHANGED
|
@@ -1,4 +1,26 @@
|
|
|
1
1
|
/// <reference types="node" />
|
|
2
|
+
/**
|
|
3
|
+
* @internal
|
|
4
|
+
*
|
|
5
|
+
* A utility type that recursively makes all properties of an object, including nested objects, optional. This should only be used on JSON objects only. Otherwise,
|
|
6
|
+
* you're going to end up with class methods marked as optional as well. Credit for this belongs to: https://github.com/joonhocho/tsdef.
|
|
7
|
+
*
|
|
8
|
+
* @template T - The type to make recursively partial.
|
|
9
|
+
*/
|
|
10
|
+
export type DeepPartial<T> = {
|
|
11
|
+
[P in keyof T]?: T[P] extends Array<infer I> ? Array<DeepPartial<I>> : DeepPartial<T[P]>;
|
|
12
|
+
};
|
|
13
|
+
/**
|
|
14
|
+
* @internal
|
|
15
|
+
*
|
|
16
|
+
* A utility type that recursively makes all properties of an object, including nested objects, optional. This should only be used on JSON objects only. Otherwise,
|
|
17
|
+
* you're going to end up with class methods marked as optional as well. Credit for this belongs to: https://github.com/joonhocho/tsdef.
|
|
18
|
+
*
|
|
19
|
+
* @template T - The type to make recursively partial.
|
|
20
|
+
*/
|
|
21
|
+
export type DeepReadonly<T> = {
|
|
22
|
+
readonly [P in keyof T]: T[P] extends Array<infer I> ? Array<DeepReadonly<I>> : DeepReadonly<T[P]>;
|
|
23
|
+
};
|
|
2
24
|
export interface HomebridgePluginLogging {
|
|
3
25
|
debug: (message: string, ...parameters: unknown[]) => void;
|
|
4
26
|
error: (message: string, ...parameters: unknown[]) => void;
|
package/dist/utils.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"utils.js","sourceRoot":"","sources":["../src/utils.ts"],"names":[],"mappings":"AAAA;;;GAGG;
|
|
1
|
+
{"version":3,"file":"utils.js","sourceRoot":"","sources":["../src/utils.ts"],"names":[],"mappings":"AAAA;;;GAGG;AA4CH,4BAA4B;AAC5B,MAAM,UAAU,KAAK,CAAC,UAAkB;IAEtC,OAAO,IAAI,OAAO,CAAC,OAAO,CAAC,EAAE,CAAC,UAAU,CAAC,OAAO,EAAE,UAAU,CAAC,CAAC,CAAC;AACjE,CAAC;AAED,6CAA6C;AAC7C,MAAM,CAAC,KAAK,UAAU,KAAK,CAAC,SAAiC,EAAE,aAAqB;IAElF,wCAAwC;IACxC,IAAG,CAAC,CAAC,MAAM,SAAS,EAAE,CAAC,EAAE,CAAC;QAExB,4FAA4F;QAC5F,MAAM,KAAK,CAAC,aAAa,CAAC,CAAC;QAE3B,OAAO,KAAK,CAAC,SAAS,EAAE,aAAa,CAAC,CAAC;IACzC,CAAC;IAED,mCAAmC;IACnC,OAAO,IAAI,CAAC;AACd,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "homebridge-plugin-utils",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.2.0",
|
|
4
4
|
"displayName": "Homebridge Plugin Utilities",
|
|
5
5
|
"description": "Opinionated utilities to provide common capabilities and create rich configuration webUI experiences for Homebridge plugins.",
|
|
6
6
|
"author": {
|
|
@@ -40,13 +40,13 @@
|
|
|
40
40
|
"main": "dist/index.js",
|
|
41
41
|
"devDependencies": {
|
|
42
42
|
"@stylistic/eslint-plugin": "2.1.0",
|
|
43
|
-
"@types/node": "20.
|
|
43
|
+
"@types/node": "20.13.0",
|
|
44
44
|
"eslint": "8.57.0",
|
|
45
45
|
"shx": "^0.3.4",
|
|
46
46
|
"typescript": "5.4.5",
|
|
47
|
-
"typescript-eslint": "^7.
|
|
47
|
+
"typescript-eslint": "^7.11.0"
|
|
48
48
|
},
|
|
49
49
|
"dependencies": {
|
|
50
|
-
"mqtt": "^5.
|
|
50
|
+
"mqtt": "^5.7.0"
|
|
51
51
|
}
|
|
52
52
|
}
|