Compare commits

..

2 Commits

Author SHA1 Message Date
4478cdbcb3 fix(dashboard): add more websocket related logs
All checks were successful
Build and Publish Docker Image / build-and-push (push) Successful in 1m8s
2025-10-29 23:10:25 +00:00
866fd0eacc feat(dashboard): improve brightness slider anim
Co-authored-by: Ona <no-reply@ona.com>
2025-10-29 23:09:51 +00:00
5 changed files with 67 additions and 11 deletions

View File

@@ -28,12 +28,28 @@ const intermediateBrightnessAtoms = atom({
}) })
function App() { function App() {
const websocket = useRef(new WebSocket(`ws://${import.meta.env.VITE_API_HOST}/api/zigbee`)) const wsProtocol = window.location.protocol === "https:" ? "wss:" : "ws:"
const wsHost = import.meta.env.VITE_API_HOST || window.location.host
const websocket = useRef(new WebSocket(`${wsProtocol}//${wsHost}/api/zigbee`))
const store = useStore() const store = useStore()
useEffect(() => { useEffect(() => {
websocket.current.onmessage = (event) => { const ws = websocket.current
ws.onopen = () => {
console.log("WebSocket connected")
}
ws.onerror = (error) => {
console.error("WebSocket error:", error)
}
ws.onclose = () => {
console.log("WebSocket disconnected")
}
ws.onmessage = (event) => {
const data = JSON.parse(event.data) as JrpcRequest | JrpcResponse const data = JSON.parse(event.data) as JrpcRequest | JrpcResponse
if ("method" in data) { if ("method" in data) {
switch (data.method) { switch (data.method) {
@@ -45,14 +61,22 @@ function App() {
} }
} }
} }
return () => { return () => {
if (websocket.current.readyState === WebSocket.OPEN) { if (ws.readyState === WebSocket.OPEN) {
websocket.current.close() ws.close()
} }
} }
}, [store]) }, [store])
function setBrightness(deviceName: ZigbeeDeviceName, brightness: number) { function setBrightness(deviceName: ZigbeeDeviceName, brightness: number) {
const ws = websocket.current
if (ws.readyState !== WebSocket.OPEN) {
console.warn("WebSocket is not open. Current state:", ws.readyState)
return
}
const request: JrpcRequest<"setDeviceState"> = { const request: JrpcRequest<"setDeviceState"> = {
id: crypto.randomUUID(), id: crypto.randomUUID(),
jsonrpc: "2.0", jsonrpc: "2.0",
@@ -65,7 +89,9 @@ function App() {
: { state: "ON", brightness: Math.round((brightness / 100) * 254) }, : { state: "ON", brightness: Math.round((brightness / 100) * 254) },
}, },
} }
websocket.current.send(JSON.stringify(request))
ws.send(JSON.stringify(request))
console.log("Sent brightness change:", { deviceName, brightness })
} }
return ( return (
@@ -621,9 +647,12 @@ function LightControlTile({
if (bar.dataset.touched === "true") { if (bar.dataset.touched === "true") {
bar.dataset.thumb = "true" bar.dataset.thumb = "true"
} else {
bar.dataset.thumb = "false"
} }
bar.dataset.touched = "false" bar.dataset.touched = "false"
delete bar.dataset.touchProximity delete bar.dataset.touchProximity
} }
@@ -642,11 +671,11 @@ function LightControlTile({
delete bar.dataset.thumb delete bar.dataset.thumb
if (x > barRect.left - 2 && x < barRect.right + 2) { if (x > barRect.left - 2 && x < barRect.right + 2 && touchedIndex === -1) {
touchedIndex = i touchedIndex = i
bar.dataset.touched = "true" bar.dataset.touched = "true"
bar.dataset.highlighted = "true" bar.dataset.highlighted = "false"
delete bar.dataset.touchProximity delete bar.dataset.touchProximity
const brightness = 1 - i / BAR_COUNT const brightness = 1 - i / BAR_COUNT
@@ -662,6 +691,11 @@ function LightControlTile({
barRefs.current[i - 3]!.dataset.touchProximity = "far" barRefs.current[i - 3]!.dataset.touchProximity = "far"
} }
} else if (barRect.left < x) { } else if (barRect.left < x) {
if (bar.dataset.touched === "true") {
bar.dataset.prevTouched = "true"
} else {
delete bar.dataset.prevTouched
}
bar.dataset.touched = "false" bar.dataset.touched = "false"
bar.dataset.highlighted = "true" bar.dataset.highlighted = "true"
if (touchedIndex >= 0) { if (touchedIndex >= 0) {
@@ -734,7 +768,7 @@ function LightControlTile({
}} }}
// biome-ignore lint/suspicious/noArrayIndexKey: <explanation> // biome-ignore lint/suspicious/noArrayIndexKey: <explanation>
key={index} key={index}
className="transition-all group-data-[active=true]:transition-none w-[2px] h-[2px] bg-neutral-400 rounded-full data-[highlighted=true]:h-2 data-[touch-proximity=close]:h-6 data-[touch-proximity=medium]:h-4 data-[touch-proximity=far]:h-2 data-[highlighted=true]:bg-teal-500 data-[touched=true]:h-8 data-[touched=true]:w-1 data-[thumb=true]:h-8" className="transition-all transition-75 w-[2px] h-[2px] bg-neutral-400 rounded-full data-[highlighted=true]:h-2 data-[touch-proximity=close]:h-6 data-[touch-proximity=medium]:h-4 data-[touch-proximity=far]:h-2 data-[highlighted=true]:bg-teal-500 data-[touched=true]:h-8 data-[touched=true]:w-1 data-[touched=true]:bg-teal-500 data-[touched=true]:transition-none data-[prev-touched=true]:transition-none data-[thumb=true]:h-8 data-[thumb=true]:bg-teal-500"
/> />
) )
})} })}

View File

@@ -5,7 +5,13 @@
import { queryOptions } from "@tanstack/react-query" import { queryOptions } from "@tanstack/react-query"
const API_BASE_URL = `http://${import.meta.env.VITE_API_HOST || "localhost:8000"}` const getApiBaseUrl = () => {
const protocol = window.location.protocol
const host = import.meta.env.VITE_API_HOST || window.location.host
return `${protocol}//${host}`
}
const API_BASE_URL = getApiBaseUrl()
// System Info // System Info
export interface BeszelSystemInfo { export interface BeszelSystemInfo {

View File

@@ -10,3 +10,7 @@ body {
-moz-osx-font-smoothing: grayscale; -moz-osx-font-smoothing: grayscale;
overscroll-behavior: none; overscroll-behavior: none;
} }
input[type="range"].brightness-slider {
@apply appearance-none w-full bg-transparent;
}

View File

@@ -5,7 +5,13 @@
import { queryOptions } from "@tanstack/react-query" import { queryOptions } from "@tanstack/react-query"
const API_BASE_URL = `http://${import.meta.env.VITE_API_HOST || "localhost:8000"}` const getApiBaseUrl = () => {
const protocol = window.location.protocol
const host = import.meta.env.VITE_API_HOST || window.location.host
return `${protocol}//${host}`
}
const API_BASE_URL = getApiBaseUrl()
// Disruption Summary // Disruption Summary
export interface DisruptionSummary { export interface DisruptionSummary {

View File

@@ -26,7 +26,13 @@ import {
Wind, Wind,
} from "lucide-react" } from "lucide-react"
const API_BASE_URL = `http://${import.meta.env.VITE_API_HOST || "localhost:3000"}` const getApiBaseUrl = () => {
const protocol = window.location.protocol
const host = import.meta.env.VITE_API_HOST || window.location.host
return `${protocol}//${host}`
}
const API_BASE_URL = getApiBaseUrl()
export const DEFAULT_LATITUDE = Number(import.meta.env.VITE_DEFAULT_LATITUDE) || 37.7749 export const DEFAULT_LATITUDE = Number(import.meta.env.VITE_DEFAULT_LATITUDE) || 37.7749
export const DEFAULT_LONGITUDE = Number(import.meta.env.VITE_DEFAULT_LONGITUDE) || -122.4194 export const DEFAULT_LONGITUDE = Number(import.meta.env.VITE_DEFAULT_LONGITUDE) || -122.4194