@typed-assistant/builder 0.0.52 → 0.0.54
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/package.json +6 -5
- package/src/appProcess.tsx +7 -0
- package/src/setupWebserver.tsx +6 -0
- package/src/webserver/App.tsx +1 -1
- package/src/webserver/Terminal.tsx +132 -5
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@typed-assistant/builder",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.54",
|
|
4
4
|
"exports": {
|
|
5
5
|
"./appProcess": "./src/appProcess.tsx",
|
|
6
6
|
"./bunInstall": "./src/bunInstall.tsx",
|
|
@@ -14,6 +14,7 @@
|
|
|
14
14
|
"ignore": "^5.3.0",
|
|
15
15
|
"react": "^18",
|
|
16
16
|
"react-dom": "^18",
|
|
17
|
+
"tailwind-merge": "^2.2.1",
|
|
17
18
|
"zod": "^3.22.4"
|
|
18
19
|
},
|
|
19
20
|
"devDependencies": {
|
|
@@ -24,10 +25,10 @@
|
|
|
24
25
|
"home-assistant-js-websocket": "^8.2.0",
|
|
25
26
|
"ts-toolbelt": "^9.6.0",
|
|
26
27
|
"typescript": "^5.3.3",
|
|
27
|
-
"@typed-assistant/eslint-config": "0.0.
|
|
28
|
-
"@typed-assistant/logger": "0.0.
|
|
29
|
-
"@typed-assistant/typescript-config": "0.0.
|
|
30
|
-
"@typed-assistant/utils": "0.0.
|
|
28
|
+
"@typed-assistant/eslint-config": "0.0.9",
|
|
29
|
+
"@typed-assistant/logger": "0.0.17",
|
|
30
|
+
"@typed-assistant/typescript-config": "0.0.9",
|
|
31
|
+
"@typed-assistant/utils": "0.0.15"
|
|
31
32
|
},
|
|
32
33
|
"peerDependencies": {
|
|
33
34
|
"home-assistant-js-websocket": "^8.2.0"
|
package/src/appProcess.tsx
CHANGED
|
@@ -40,6 +40,13 @@ export async function setup({
|
|
|
40
40
|
startWebappServer({
|
|
41
41
|
basePath,
|
|
42
42
|
getSubprocesses: () => subprocesses,
|
|
43
|
+
onRestartAppRequest: async () => {
|
|
44
|
+
subprocesses = await killAndRestartApp(
|
|
45
|
+
entryFile,
|
|
46
|
+
{ mdiPaths },
|
|
47
|
+
subprocesses,
|
|
48
|
+
)
|
|
49
|
+
},
|
|
43
50
|
})
|
|
44
51
|
setupWatcher({
|
|
45
52
|
directoryToWatch,
|
package/src/setupWebserver.tsx
CHANGED
|
@@ -57,11 +57,13 @@ let lastMessage = ""
|
|
|
57
57
|
export const startWebappServer = async ({
|
|
58
58
|
basePath,
|
|
59
59
|
getSubprocesses,
|
|
60
|
+
onRestartAppRequest,
|
|
60
61
|
}: {
|
|
61
62
|
basePath: string
|
|
62
63
|
getSubprocesses: () => {
|
|
63
64
|
app: Subprocess<"ignore", "pipe", "pipe">
|
|
64
65
|
}
|
|
66
|
+
onRestartAppRequest: () => void
|
|
65
67
|
}) => {
|
|
66
68
|
const buildResult = await Bun.build({
|
|
67
69
|
entrypoints: [tsEntryPoint],
|
|
@@ -105,6 +107,10 @@ export const startWebappServer = async ({
|
|
|
105
107
|
headers: { "content-type": "text/html" },
|
|
106
108
|
}),
|
|
107
109
|
)
|
|
110
|
+
.get("/restart-app", async () => {
|
|
111
|
+
onRestartAppRequest()
|
|
112
|
+
return { message: "Restarting app..." }
|
|
113
|
+
})
|
|
108
114
|
.get("/restart-addon", async () => {
|
|
109
115
|
await killSubprocess(getSubprocesses().app)
|
|
110
116
|
restartAddon()
|
package/src/webserver/App.tsx
CHANGED
|
@@ -1,11 +1,75 @@
|
|
|
1
|
-
import { useCallback, useState } from "react"
|
|
1
|
+
import { useCallback, useEffect, useState } from "react"
|
|
2
2
|
import { app } from "./api"
|
|
3
3
|
import { useWS } from "./useWS"
|
|
4
4
|
import { WSIndicator } from "./WSIndicator"
|
|
5
5
|
import { AppSection } from "./AppSection"
|
|
6
6
|
import { buttonStyle } from "./styles"
|
|
7
|
+
import { twMerge } from "tailwind-merge"
|
|
7
8
|
|
|
8
|
-
|
|
9
|
+
type ButtonAsyncProps = {
|
|
10
|
+
onClick: () => Promise<{ error?: unknown }>
|
|
11
|
+
stateLabels: {
|
|
12
|
+
idle: string
|
|
13
|
+
loading?: string
|
|
14
|
+
error?: string
|
|
15
|
+
success?: string
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
const ButtonAsync = ({
|
|
20
|
+
onClick,
|
|
21
|
+
stateLabels: stateLabelsProp,
|
|
22
|
+
}: ButtonAsyncProps) => {
|
|
23
|
+
const stateLabels = {
|
|
24
|
+
error: "Error",
|
|
25
|
+
loading: "Loading...",
|
|
26
|
+
success: "Success",
|
|
27
|
+
...stateLabelsProp,
|
|
28
|
+
}
|
|
29
|
+
const [state, setState] = useState<"idle" | "loading" | "error" | "success">(
|
|
30
|
+
"idle",
|
|
31
|
+
)
|
|
32
|
+
|
|
33
|
+
useEffect(() => {
|
|
34
|
+
if (state !== "loading" && state !== "idle") {
|
|
35
|
+
const timeout = setTimeout(() => setState("idle"), 2000)
|
|
36
|
+
|
|
37
|
+
return () => {
|
|
38
|
+
clearTimeout(timeout)
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
}, [state])
|
|
42
|
+
|
|
43
|
+
const handleClick = async () => {
|
|
44
|
+
if (state !== "idle") return
|
|
45
|
+
setState("loading")
|
|
46
|
+
|
|
47
|
+
const { error } = await onClick()
|
|
48
|
+
|
|
49
|
+
if (error) {
|
|
50
|
+
setState("error")
|
|
51
|
+
return
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
setState("success")
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
return (
|
|
58
|
+
<button
|
|
59
|
+
className={twMerge(
|
|
60
|
+
buttonStyle,
|
|
61
|
+
state === "loading" && "bg-blue-300 text-blue-800",
|
|
62
|
+
state === "error" && "bg-red-300 text-red-800",
|
|
63
|
+
state === "success" && "bg-green-300 text-green-800",
|
|
64
|
+
)}
|
|
65
|
+
onClick={handleClick}
|
|
66
|
+
>
|
|
67
|
+
{stateLabels[state]}
|
|
68
|
+
</button>
|
|
69
|
+
)
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
export function Terminal() {
|
|
9
73
|
const [content, setContent] = useState("")
|
|
10
74
|
const ws = useWS({
|
|
11
75
|
subscribe: useCallback(() => app.ws.subscribe(), []),
|
|
@@ -20,9 +84,22 @@ export function Terminal({ basePath }: { basePath: string }) {
|
|
|
20
84
|
TypedAssistant <WSIndicator ws={ws.ws} />
|
|
21
85
|
</h1>
|
|
22
86
|
<div className="flex flex-wrap gap-2">
|
|
23
|
-
<
|
|
24
|
-
|
|
25
|
-
|
|
87
|
+
<ButtonAsync
|
|
88
|
+
onClick={() => app["restart-app"].get()}
|
|
89
|
+
stateLabels={{
|
|
90
|
+
idle: "Restart app",
|
|
91
|
+
loading: "Restarting app...",
|
|
92
|
+
success: "App restarted",
|
|
93
|
+
}}
|
|
94
|
+
/>
|
|
95
|
+
<ButtonAsync
|
|
96
|
+
onClick={() => app["restart-addon"].get()}
|
|
97
|
+
stateLabels={{
|
|
98
|
+
idle: "Restart addon",
|
|
99
|
+
loading: "Restarting addon...",
|
|
100
|
+
success: "Addon restarted",
|
|
101
|
+
}}
|
|
102
|
+
/>
|
|
26
103
|
</div>
|
|
27
104
|
</>
|
|
28
105
|
)}
|
|
@@ -31,3 +108,53 @@ export function Terminal({ basePath }: { basePath: string }) {
|
|
|
31
108
|
</AppSection>
|
|
32
109
|
)
|
|
33
110
|
}
|
|
111
|
+
|
|
112
|
+
const RestartAppButton = () => {
|
|
113
|
+
const [state, setState] = useState<"idle" | "loading" | "error" | "success">(
|
|
114
|
+
"idle",
|
|
115
|
+
)
|
|
116
|
+
|
|
117
|
+
useEffect(() => {
|
|
118
|
+
if (state !== "loading" && state !== "idle") {
|
|
119
|
+
const timeout = setTimeout(() => setState("idle"), 2000)
|
|
120
|
+
|
|
121
|
+
return () => {
|
|
122
|
+
clearTimeout(timeout)
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
}, [state])
|
|
126
|
+
|
|
127
|
+
const onClick = async () => {
|
|
128
|
+
if (state !== "idle") return
|
|
129
|
+
setState("loading")
|
|
130
|
+
|
|
131
|
+
const { data, error } = await app["restart-app"].get()
|
|
132
|
+
|
|
133
|
+
if (error) {
|
|
134
|
+
setState("error")
|
|
135
|
+
return
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
setState("success")
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
return (
|
|
142
|
+
<button
|
|
143
|
+
className={twMerge(
|
|
144
|
+
buttonStyle,
|
|
145
|
+
state === "loading" && "bg-blue-500",
|
|
146
|
+
state === "error" && "bg-red-500",
|
|
147
|
+
state === "success" && "bg-green-500",
|
|
148
|
+
)}
|
|
149
|
+
onClick={onClick}
|
|
150
|
+
>
|
|
151
|
+
{state === "loading"
|
|
152
|
+
? "Restarting app..."
|
|
153
|
+
: state === "error"
|
|
154
|
+
? "Error restarting app"
|
|
155
|
+
: state === "success"
|
|
156
|
+
? "App restarted"
|
|
157
|
+
: "Restart app"}
|
|
158
|
+
</button>
|
|
159
|
+
)
|
|
160
|
+
}
|