Skip to content

Commit 20318a6

Browse files
committed
Upgrade to Zustand 5.x
1 parent 38bb8c0 commit 20318a6

6 files changed

Lines changed: 46 additions & 47 deletions

File tree

scripts/build_cgo.sh

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ msg_info "▶ Generating UI index"
2323
./ui_index.gen.sh
2424

2525
msg_info "▶ Building native library"
26+
git config --global --add safe.directory "/build/internal/*"
2627
VERBOSE=1 cmake -B "${BUILD_DIR}" \
2728
-DCMAKE_SYSTEM_PROCESSOR=armv7l \
2829
-DCMAKE_SYSTEM_NAME=Linux \

ui/package-lock.json

Lines changed: 11 additions & 10 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

ui/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,7 @@
6060
"tslog": "^4.10.2",
6161
"usehooks-ts": "^3.1.1",
6262
"validator": "^13.15.23",
63-
"zustand": "^4.5.2"
63+
"zustand": "^5.0.12"
6464
},
6565
"devDependencies": {
6666
"@inlang/cli": "^3.0.12",

ui/src/hooks/stores.ts

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -829,7 +829,9 @@ export interface NetworkState {
829829
ipv6_gateway?: string;
830830
dhcp_lease?: DhcpLease;
831831
hostname?: string;
832+
}
832833

834+
interface NetworkStateStore extends NetworkState {
833835
setNetworkState: (state: NetworkState) => void;
834836
setDhcpLease: (lease: NetworkState["dhcp_lease"]) => void;
835837
setDhcpLeaseExpiry: (expiry: Date) => void;
@@ -881,7 +883,7 @@ export interface NetworkSettings {
881883
time_sync_http_urls?: string[];
882884
}
883885

884-
export const useNetworkStateStore = create<NetworkState>((set, get) => ({
886+
export const useNetworkStateStore = create<NetworkStateStore>((set, get) => ({
885887
setNetworkState: (state: NetworkState) => set(state),
886888
setDhcpLease: (lease: NetworkState["dhcp_lease"]) => set({ dhcp_lease: lease }),
887889
setDhcpLeaseExpiry: (expiry: Date) => {
@@ -891,8 +893,7 @@ export const useNetworkStateStore = create<NetworkState>((set, get) => ({
891893
return;
892894
}
893895

894-
lease.lease_expiry = expiry;
895-
set({ dhcp_lease: lease });
896+
set({ dhcp_lease: { ...lease, lease_expiry: expiry } });
896897
},
897898
}));
898899

ui/src/routes/devices.$id.settings.general._index.tsx

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import { useState, useEffect, useMemo } from "react";
22

33
import { JsonRpcResponse, useJsonRpc } from "@hooks/useJsonRpc";
44
import { useDeviceUiNavigation } from "@hooks/useAppNavigation";
5+
import { useShallow } from "zustand/shallow";
56
import { useDeviceStore } from "@hooks/stores";
67
import { Button } from "@components/Button";
78
import Checkbox from "@components/Checkbox";
@@ -17,11 +18,10 @@ export default function SettingsGeneralRoute() {
1718
const { send } = useJsonRpc();
1819
const { navigateTo } = useDeviceUiNavigation();
1920
const [autoUpdate, setAutoUpdate] = useState(true);
20-
const currentVersions = useDeviceStore(state => {
21-
const { appVersion, systemVersion } = state;
22-
if (!appVersion || !systemVersion) return null;
23-
return { appVersion, systemVersion };
24-
});
21+
const { appVersion, systemVersion } = useDeviceStore(
22+
useShallow(state => ({ appVersion: state.appVersion, systemVersion: state.systemVersion })),
23+
);
24+
const currentVersions = appVersion && systemVersion ? { appVersion, systemVersion } : null;
2525

2626
useEffect(() => {
2727
send("getAutoUpdateState", {}, (resp: JsonRpcResponse) => {

ui/src/routes/devices.$id.settings.network.tsx

Lines changed: 24 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import validator from "validator";
88
import PublicIPCard from "@components/PublicIPCard";
99
import TailscaleCard from "@components/TailscaleCard";
1010
import { NetworkSettings, NetworkState, useNetworkStateStore, useRTCStore } from "@hooks/stores";
11+
import { useShallow } from "zustand/shallow";
1112
import { JsonRpcResponse, useJsonRpc } from "@hooks/useJsonRpc";
1213
import AutoHeight from "@components/AutoHeight";
1314
import { Button } from "@components/Button";
@@ -33,32 +34,13 @@ dayjs.extend(relativeTime);
3334

3435
const isLLDPAvailable = false; // LLDP is not supported yet
3536

36-
const resolveOnRtcReady = () => {
37-
return new Promise(resolve => {
38-
// Check if RTC is already connected
39-
const currentState = useRTCStore.getState();
40-
if (currentState.rpcDataChannel?.readyState === "open") {
41-
// Already connected, fetch data immediately
42-
return resolve(void 0);
43-
}
44-
45-
// Not connected yet, subscribe to state changes
46-
const unsubscribe = useRTCStore.subscribe(state => {
47-
if (state.rpcDataChannel?.readyState === "open") {
48-
unsubscribe(); // Clean up subscription
49-
return resolve(void 0);
50-
}
51-
});
52-
});
53-
};
54-
5537
export function LifeTimeLabel({ lifetime }: Readonly<{ lifetime: string }>) {
5638
const [remaining, setRemaining] = useState<string | null>(null);
5739

58-
// rrecalculate remaining time every 30 seconds
40+
// recalculate remaining time every 30 seconds
5941
useEffect(() => {
60-
// schedule immediate initial update
61-
setInterval(() => setRemaining(dayjs(lifetime).fromNow()), 0);
42+
// immediate initial update
43+
setRemaining(dayjs(lifetime).fromNow());
6244

6345
const interval = setInterval(() => {
6446
setRemaining(dayjs(lifetime).fromNow());
@@ -85,7 +67,16 @@ const NonCustomDomainOptions = ["dhcp", "local"];
8567
export default function SettingsNetworkRoute() {
8668
const { send } = useJsonRpc();
8769

88-
const networkState = useNetworkStateStore(state => state);
70+
const networkState = useNetworkStateStore(
71+
useShallow(state => ({
72+
mac_address: state.mac_address,
73+
hostname: state.hostname,
74+
dhcp_lease: state.dhcp_lease,
75+
ipv6_addresses: state.ipv6_addresses,
76+
ipv6_link_local: state.ipv6_link_local,
77+
ipv6_gateway: state.ipv6_gateway,
78+
})),
79+
);
8980
const setNetworkState = useNetworkStateStore(state => state.setNetworkState);
9081

9182
// Some input needs direct state management. Mostly options that open more details
@@ -164,8 +155,6 @@ export default function SettingsNetworkRoute() {
164155
mode: "onBlur",
165156

166157
defaultValues: async () => {
167-
// Ensure data channel is ready, before fetching network data from the device
168-
await resolveOnRtcReady();
169158
const { settings } = await fetchNetworkData();
170159
return settings;
171160
},
@@ -215,7 +204,6 @@ export default function SettingsNetworkRoute() {
215204
} catch (error) {
216205
console.error("Failed to fetch network data:", error);
217206
}
218-
notifications.success(m.network_dhcp_lease_renew_success());
219207
}
220208
});
221209
},
@@ -270,7 +258,11 @@ export default function SettingsNetworkRoute() {
270258
});
271259
}
272260

273-
if (dirty.ipv4_static?.dns && dirty.ipv4_static.dns.length > 0 && dirty.ipv4_static.dns.every(dirty => dirty)) {
261+
if (
262+
dirty.ipv4_static?.dns &&
263+
dirty.ipv4_static.dns.length > 0 &&
264+
dirty.ipv4_static.dns.every(dirty => dirty)
265+
) {
274266
changes.push({
275267
label: m.network_ipv4_dns(),
276268
from: initialSettingsRef.current?.ipv4_static?.dns.join(", ").toString() ?? "",
@@ -302,7 +294,11 @@ export default function SettingsNetworkRoute() {
302294
});
303295
}
304296

305-
if (dirty.ipv6_static?.dns && dirty.ipv6_static.dns.length > 0 && dirty.ipv6_static.dns.every(dirty => dirty)) {
297+
if (
298+
dirty.ipv6_static?.dns &&
299+
dirty.ipv6_static.dns.length > 0 &&
300+
dirty.ipv6_static.dns.every(dirty => dirty)
301+
) {
306302
changes.push({
307303
label: m.network_ipv6_dns(),
308304
from: initialSettingsRef.current?.ipv6_static?.dns.join(", ").toString() ?? "",

0 commit comments

Comments
 (0)