Skip to content

Commit b0e2f75

Browse files
doublegateclaude
andcommitted
fix(clients): add AppImage build targets and fix React lint warnings
- Add AppImage to default build targets for all Tauri clients - Configure bundleMediaFramework: false for Linux AppImage builds - Fix React compiler purity warnings in wraith-transfer components - SessionPanel.tsx: use useEffect for duration calculation - SettingsPanel.tsx: use controlled state pattern - TransferList.tsx: use useState for speed calculation - Update ESLint config to allow export * in test files - Add VMware/AppImage conflict troubleshooting documentation - Format Rust code with cargo fmt Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
1 parent 808e833 commit b0e2f75

File tree

11 files changed

+236
-32
lines changed

11 files changed

+236
-32
lines changed

CHANGELOG.md

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,25 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
77

88
## [Unreleased]
99

10-
No unreleased changes yet.
10+
### Added
11+
- **VMware/AppImage Conflict Troubleshooting Guide:**
12+
- New documentation at `docs/troubleshooting/appimage-vmware-conflict.md`
13+
- Documents FuseBlk and vmwgfx_dri.so compatibility issues
14+
- Provides workarounds for running AppImage builds in VMware virtual machines
15+
16+
### Changed
17+
- **AppImage Added to Default Build Targets:**
18+
- All Tauri desktop clients now include AppImage in default bundle targets
19+
- Updated `tauri.conf.json` for wraith-chat, wraith-transfer, and wraith-sync
20+
- Configured `bundleMediaFramework: false` for Linux AppImage builds
21+
- Build targets now explicit: `["deb", "rpm", "appimage"]` instead of `"all"`
22+
23+
### Fixed
24+
- **React Compiler Purity Warnings:**
25+
- Fixed `Date.now()` calls in render functions (SessionPanel.tsx, TransferList.tsx)
26+
- Fixed setState in effects pattern in SettingsPanel.tsx
27+
- Updated ESLint config to allow export * in test utility files
28+
- Zero lint warnings in wraith-transfer frontend
1129

1230
---
1331

clients/wraith-chat/src-tauri/src/database.rs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,10 @@ pub struct DatabaseKeyMismatchError;
1212

1313
impl std::fmt::Display for DatabaseKeyMismatchError {
1414
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
15-
write!(f, "Database exists but cannot be decrypted with the current key")
15+
write!(
16+
f,
17+
"Database exists but cannot be decrypted with the current key"
18+
)
1619
}
1720
}
1821

clients/wraith-chat/src-tauri/src/lib.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -130,7 +130,9 @@ fn setup_app<R: Runtime>(app: &mut tauri::App<R>) -> Result<(), Box<dyn std::err
130130
Ok(db) => db,
131131
Err(e) => {
132132
// Check if this is a key mismatch error
133-
if e.downcast_ref::<database::DatabaseKeyMismatchError>().is_some() {
133+
if e.downcast_ref::<database::DatabaseKeyMismatchError>()
134+
.is_some()
135+
{
134136
log::warn!(
135137
"Database key mismatch detected. The encryption key has changed since the database was created."
136138
);

clients/wraith-chat/src-tauri/tauri.conf.json

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,14 +11,19 @@
1111
},
1212
"bundle": {
1313
"active": true,
14-
"targets": "all",
14+
"targets": ["deb", "rpm", "appimage"],
1515
"icon": [
1616
"icons/32x32.png",
1717
"icons/128x128.png",
1818
"icons/128x128@2x.png",
1919
"icons/icon.icns",
2020
"icons/icon.ico"
2121
],
22+
"linux": {
23+
"appimage": {
24+
"bundleMediaFramework": false
25+
}
26+
},
2227
"windows": {
2328
"certificateThumbprint": null,
2429
"digestAlgorithm": "sha256",

clients/wraith-sync/src-tauri/tauri.conf.json

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@
3333
},
3434
"bundle": {
3535
"active": true,
36-
"targets": "all",
36+
"targets": ["deb", "rpm", "appimage"],
3737
"icon": [
3838
"icons/32x32.png",
3939
"icons/128x128.png",
@@ -43,7 +43,12 @@
4343
],
4444
"category": "Utility",
4545
"shortDescription": "Decentralized file synchronization",
46-
"longDescription": "WRAITH Sync is a cross-platform desktop application for secure, private file synchronization using the WRAITH Protocol. Sync folders across unlimited devices with end-to-end encryption, delta sync, and conflict resolution."
46+
"longDescription": "WRAITH Sync is a cross-platform desktop application for secure, private file synchronization using the WRAITH Protocol. Sync folders across unlimited devices with end-to-end encryption, delta sync, and conflict resolution.",
47+
"linux": {
48+
"appimage": {
49+
"bundleMediaFramework": false
50+
}
51+
}
4752
},
4853
"plugins": {}
4954
}

clients/wraith-transfer/frontend/eslint.config.js

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,4 +20,11 @@ export default defineConfig([
2020
globals: globals.browser,
2121
},
2222
},
23+
// Test utilities - allow export * pattern for re-exporting testing-library
24+
{
25+
files: ['**/test/**/*.{ts,tsx}', '**/*.test.{ts,tsx}'],
26+
rules: {
27+
'react-refresh/only-export-components': 'off',
28+
},
29+
},
2330
])

clients/wraith-transfer/frontend/src/components/SessionPanel.tsx

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
// WRAITH Transfer - Session Panel Component
22

3+
import { useState, useEffect } from 'react';
34
import { useSessionStore } from '../stores/sessionStore';
45
import type { SessionInfo } from '../types';
56

@@ -13,6 +14,18 @@ function formatBytes(bytes: number): string {
1314

1415
function SessionItem({ session }: { session: SessionInfo }) {
1516
const { closeSession } = useSessionStore();
17+
const [duration, setDuration] = useState(0);
18+
19+
// Calculate connection duration with interval
20+
useEffect(() => {
21+
const updateDuration = () => {
22+
const now = Math.floor(Date.now() / 1000);
23+
setDuration(now - session.established_at);
24+
};
25+
updateDuration();
26+
const interval = setInterval(updateDuration, 1000);
27+
return () => clearInterval(interval);
28+
}, [session.established_at]);
1629

1730
const connectionStatus = session.connection_status || 'connected';
1831
const statusColors: Record<string, string> = {
@@ -28,10 +41,6 @@ function SessionItem({ session }: { session: SessionInfo }) {
2841
disconnecting: 'bg-orange-500 animate-pulse',
2942
failed: 'bg-red-500',
3043
};
31-
32-
// Calculate connection duration
33-
const now = Math.floor(Date.now() / 1000);
34-
const duration = now - session.established_at;
3544
const formatDuration = (seconds: number): string => {
3645
if (seconds < 60) return `${seconds}s`;
3746
if (seconds < 3600) return `${Math.floor(seconds / 60)}m`;

clients/wraith-transfer/frontend/src/components/SettingsPanel.tsx

Lines changed: 17 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
// WRAITH Transfer - Settings Panel Component
22

3-
import { useState, useEffect } from 'react';
3+
import { useState } from 'react';
44
import { open } from '@tauri-apps/plugin-dialog';
55
import { useSettingsStore, type Theme } from '../stores/settingsStore';
66

@@ -24,17 +24,23 @@ export function SettingsPanel({ isOpen, onClose }: Props) {
2424
resetToDefaults,
2525
} = useSettingsStore();
2626

27-
const [localDownloadDir, setLocalDownloadDir] = useState(downloadDir);
28-
const [localMaxTransfers, setLocalMaxTransfers] = useState(maxConcurrentTransfers);
29-
const [localPort, setLocalPort] = useState(port);
27+
// Use controlled state that syncs with props when dialog opens
28+
// We use a key pattern by tracking the open state to reset local values
29+
const [localDownloadDir, setLocalDownloadDir] = useState('');
30+
const [localMaxTransfers, setLocalMaxTransfers] = useState(3);
31+
const [localPort, setLocalPort] = useState(8337);
32+
const [initialized, setInitialized] = useState(false);
3033

31-
useEffect(() => {
32-
if (isOpen) {
33-
setLocalDownloadDir(downloadDir);
34-
setLocalMaxTransfers(maxConcurrentTransfers);
35-
setLocalPort(port);
36-
}
37-
}, [isOpen, downloadDir, maxConcurrentTransfers, port]);
34+
// Sync local state when dialog opens (using key pattern instead of effect setState)
35+
if (isOpen && !initialized) {
36+
setLocalDownloadDir(downloadDir);
37+
setLocalMaxTransfers(maxConcurrentTransfers);
38+
setLocalPort(port);
39+
setInitialized(true);
40+
}
41+
if (!isOpen && initialized) {
42+
setInitialized(false);
43+
}
3844

3945
const handleSelectDirectory = async () => {
4046
try {

clients/wraith-transfer/frontend/src/components/TransferList.tsx

Lines changed: 8 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
// WRAITH Transfer - Transfer List Component
22

3-
import { useEffect, useRef } from 'react';
3+
import { useEffect, useRef, useState } from 'react';
44
import { useTransferStore } from '../stores/transferStore';
55
import type { TransferInfo } from '../types';
66

@@ -37,24 +37,23 @@ function TransferItem({ transfer }: { transfer: TransferInfo }) {
3737
const { cancelTransfer } = useTransferStore();
3838
const progressPercent = Math.round(transfer.progress * 100);
3939

40-
// Track previous state for speed calculation
40+
// Track previous state for speed calculation using state for time initialization
4141
const prevBytesRef = useRef(transfer.transferred_bytes);
42-
const prevTimeRef = useRef(Date.now());
43-
const speedRef = useRef(0);
42+
const [prevTime, setPrevTime] = useState(() => Date.now());
43+
const [speed, setSpeed] = useState(0);
4444

4545
useEffect(() => {
4646
const now = Date.now();
47-
const timeDiff = (now - prevTimeRef.current) / 1000; // seconds
47+
const timeDiff = (now - prevTime) / 1000; // seconds
4848

4949
if (timeDiff >= 1.0 && transfer.status === 'in_progress') {
5050
const bytesDiff = transfer.transferred_bytes - prevBytesRef.current;
51-
speedRef.current = bytesDiff / timeDiff;
51+
setSpeed(bytesDiff / timeDiff);
5252
prevBytesRef.current = transfer.transferred_bytes;
53-
prevTimeRef.current = now;
53+
setPrevTime(now);
5454
}
55-
}, [transfer.transferred_bytes, transfer.status]);
55+
}, [transfer.transferred_bytes, transfer.status, prevTime]);
5656

57-
const speed = speedRef.current;
5857
const remainingBytes = transfer.total_bytes - transfer.transferred_bytes;
5958
const eta = speed > 0 ? remainingBytes / speed : 0;
6059

clients/wraith-transfer/src-tauri/tauri.conf.json

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@
2828
},
2929
"bundle": {
3030
"active": true,
31-
"targets": "all",
31+
"targets": ["deb", "rpm", "appimage"],
3232
"icon": [
3333
"icons/32x32.png",
3434
"icons/128x128.png",
@@ -38,7 +38,12 @@
3838
],
3939
"category": "Utility",
4040
"shortDescription": "Secure peer-to-peer file transfer",
41-
"longDescription": "WRAITH Transfer is a cross-platform desktop application for secure, private file transfers using the WRAITH Protocol."
41+
"longDescription": "WRAITH Transfer is a cross-platform desktop application for secure, private file transfers using the WRAITH Protocol.",
42+
"linux": {
43+
"appimage": {
44+
"bundleMediaFramework": false
45+
}
46+
}
4247
},
4348
"plugins": {}
4449
}

0 commit comments

Comments
 (0)