Skip to content

Commit acdae84

Browse files
committed
fix: ci failure
1 parent bbb2d1f commit acdae84

6 files changed

Lines changed: 61 additions & 42 deletions

File tree

.github/workflows/ci.yml

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,9 +22,14 @@ jobs:
2222
- name: Checkout code
2323
uses: actions/checkout@v4
2424

25+
# Pinned to 1.96.0: Rust 1.97 changed the size of core::num::TryFromIntError,
26+
# which breaks the (unmaintained, transitive) ethnum 1.5.2 crate with E0512
27+
# ("cannot transmute between types of different sizes"). No fixed ethnum
28+
# release exists yet, so pin below 1.97 until soroban's dep tree drops it.
2529
- name: Install Rust
26-
uses: dtolnay/rust-toolchain@stable
30+
uses: dtolnay/rust-toolchain@1.96.0
2731
with:
32+
components: rustfmt, clippy
2833
targets: wasm32-unknown-unknown, wasm32v1-none
2934

3035
- name: Ensure wasm32v1-none target is available

.github/workflows/deploy.yml

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,8 +36,11 @@ jobs:
3636
- name: Checkout code
3737
uses: actions/checkout@v4
3838

39+
# Pinned to 1.96.0: Rust 1.97 changed core::num::TryFromIntError's size,
40+
# breaking the transitive ethnum 1.5.2 crate (E0512). Keep below 1.97 until
41+
# soroban's dependency tree no longer pulls the broken ethnum.
3942
- name: Install Rust
40-
uses: dtolnay/rust-toolchain@stable
43+
uses: dtolnay/rust-toolchain@1.96.0
4144
with:
4245
targets: wasm32-unknown-unknown
4346

.github/workflows/release.yml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,8 +24,9 @@ jobs:
2424
node-version: "20"
2525

2626
# Install Rust
27+
# Pinned to 1.96.0: Rust 1.97+ breaks the transitive ethnum 1.5.2 crate (E0512).
2728
- name: Install Rust toolchain
28-
uses: dtolnay/rust-toolchain@stable
29+
uses: dtolnay/rust-toolchain@1.96.0
2930

3031
# Add WASM target
3132
- name: Add wasm target

frontend/components/digital_twin/HealthGauge.tsx

Lines changed: 12 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
'use client';
22

3-
import React, { useEffect, useState } from 'react';
3+
import React, { useCallback, useEffect, useState } from 'react';
44
import { Card } from '@/components/ui/card';
55
import { Badge } from '@/components/ui/badge';
66
import { Skeleton } from '@/components/ui/skeleton';
@@ -14,7 +14,7 @@ interface HealthMetric {
1414
threshold_max?: number;
1515
severity?: string;
1616
calculated_at: string;
17-
metadata: any;
17+
metadata: Record<string, unknown>;
1818
}
1919

2020
interface HealthGaugeProps {
@@ -27,13 +27,7 @@ export function HealthGauge({ twinId, className = '' }: HealthGaugeProps) {
2727
const [loading, setLoading] = useState(true);
2828
const [error, setError] = useState<string | null>(null);
2929

30-
useEffect(() => {
31-
fetchHealthMetrics();
32-
const interval = setInterval(fetchHealthMetrics, 30000); // Refresh every 30s
33-
return () => clearInterval(interval);
34-
}, [twinId]);
35-
36-
const fetchHealthMetrics = async () => {
30+
const fetchHealthMetrics = useCallback(async () => {
3731
try {
3832
const response = await fetch(`/api/v1/physics/twins/${twinId}/health-metrics`);
3933
if (!response.ok) throw new Error('Failed to fetch health metrics');
@@ -44,20 +38,16 @@ export function HealthGauge({ twinId, className = '' }: HealthGaugeProps) {
4438
setError(err instanceof Error ? err.message : 'Unknown error');
4539
setLoading(false);
4640
}
47-
};
41+
}, [twinId]);
4842

49-
const getSeverityColor = (severity?: string) => {
50-
switch (severity) {
51-
case 'normal':
52-
return 'bg-green-500';
53-
case 'warning':
54-
return 'bg-yellow-500';
55-
case 'critical':
56-
return 'bg-red-500';
57-
default:
58-
return 'bg-gray-500';
59-
}
60-
};
43+
useEffect(() => {
44+
// setState happens only after an await inside fetchHealthMetrics, so this is
45+
// an async data fetch, not a synchronous cascading render.
46+
// eslint-disable-next-line react-hooks/set-state-in-effect
47+
fetchHealthMetrics();
48+
const interval = setInterval(fetchHealthMetrics, 30000); // Refresh every 30s
49+
return () => clearInterval(interval);
50+
}, [fetchHealthMetrics]);
6151

6252
const getSeverityIcon = (severity?: string) => {
6353
switch (severity) {

frontend/components/digital_twin/TwinView.tsx

Lines changed: 36 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,28 +1,45 @@
11
'use client';
22

3-
import React, { useEffect, useState } from 'react';
3+
import React, { useCallback, useEffect, useState } from 'react';
44
import { Card } from '@/components/ui/card';
55
import { Badge } from '@/components/ui/badge';
66
import { Button } from '@/components/ui/button';
77
import { Skeleton } from '@/components/ui/skeleton';
88
import { LineChart, Line, XAxis, YAxis, CartesianGrid, Tooltip, Legend, ResponsiveContainer, AreaChart, Area, BarChart, Bar } from 'recharts';
9-
import { Activity, TrendingUp, Calendar, Clock, AlertTriangle, Play, Thermometer } from 'lucide-react';
9+
import { Activity, Calendar, Clock, AlertTriangle, Play, Thermometer } from 'lucide-react';
10+
11+
interface TwinStateData {
12+
temperature?: number;
13+
humidity?: number;
14+
}
15+
16+
interface TwinMetrics {
17+
health_score?: number;
18+
decay_rate?: number;
19+
temperature_stress?: number;
20+
humidity_stress?: number;
21+
}
22+
23+
interface HealthHistoryEntry {
24+
timestamp: string;
25+
score: number;
26+
}
1027

1128
interface TwinState {
1229
id: string;
13-
state_data: any;
14-
metrics: any;
30+
state_data: TwinStateData;
31+
metrics: TwinMetrics;
1532
timestamp: string;
1633
source: string;
1734
}
1835

1936
interface DigitalTwin {
2037
id: string;
2138
name: string;
22-
current_state: any;
39+
current_state: TwinStateData;
2340
current_health_score?: number;
2441
predicted_expiry_date?: string;
25-
health_history?: any[];
42+
health_history?: HealthHistoryEntry[];
2643
}
2744

2845
interface TwinViewProps {
@@ -37,13 +54,7 @@ export function TwinView({ twinId, className = '' }: TwinViewProps) {
3754
const [error, setError] = useState<string | null>(null);
3855
const [viewMode, setViewMode] = useState<'health' | 'temperature' | 'decay' | 'metrics'>('health');
3956

40-
useEffect(() => {
41-
fetchTwinData();
42-
const interval = setInterval(fetchTwinData, 15000); // Refresh every 15s
43-
return () => clearInterval(interval);
44-
}, [twinId]);
45-
46-
const fetchTwinData = async () => {
57+
const fetchTwinData = useCallback(async () => {
4758
try {
4859
const [twinRes, historyRes] = await Promise.all([
4960
fetch(`/api/v1/digital-twins/${twinId}`),
@@ -62,12 +73,21 @@ export function TwinView({ twinId, className = '' }: TwinViewProps) {
6273
setError(err instanceof Error ? err.message : 'Unknown error');
6374
setLoading(false);
6475
}
65-
};
76+
}, [twinId]);
77+
78+
useEffect(() => {
79+
// setState happens only after an await inside fetchTwinData, so this is an
80+
// async data fetch, not a synchronous cascading render.
81+
// eslint-disable-next-line react-hooks/set-state-in-effect
82+
fetchTwinData();
83+
const interval = setInterval(fetchTwinData, 15000); // Refresh every 15s
84+
return () => clearInterval(interval);
85+
}, [fetchTwinData]);
6686

6787
const getHealthChartData = () => {
6888
if (!twin?.health_history) return [];
69-
70-
return twin.health_history.map((entry: any) => ({
89+
90+
return twin.health_history.map((entry) => ({
7191
timestamp: new Date(entry.timestamp).toLocaleTimeString(),
7292
score: Math.round(entry.score * 100),
7393
}));

frontend/components/layouts/NavBar.test.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { render, screen, fireEvent } from '@testing-library/react';
2-
import { describe, it, expect, vi } from 'vitest';
2+
import { describe, it, expect } from 'vitest';
33
import { NavBar } from './NavBar';
44

55
// WalletStatus is mocked via setup.ts global mock

0 commit comments

Comments
 (0)