Various small fixes (#349)

* Fix script viewer to support vm/ and tools/ scripts

- Update ScriptDetailModal to extract scriptName from any path (ct/, vm/, tools/)
- Refactor TextViewer to use actual script paths from install_methods
- Remove hardcoded path assumptions and use dynamic script paths
- Only show Install Script tab for ct/ scripts that have install scripts
- Rename CT Script tab to Script for better clarity

* Fix downloaded scripts count to include vm/ and tools/ scripts

- Update matching logic to use same robust approach as DownloadedScriptsTab
- Add normalized slug matching to handle filename-based slugs vs JSON slugs
- Add multiple fallback matching strategies for better script detection
- Fixes issue where scripts in vm/ and tools/ directories weren't being counted

* Filter categories to only show those with scripts

- Add filter to exclude categories with count 0 from category sidebar
- Only categories with at least one script will be displayed
- Reduces UI clutter by hiding empty categories

* Fix intermittent page reloads from VersionDisplay reconnect logic

- Add guards to prevent reload when not updating
- Use refs to track isUpdating and isNetworkError state in interval callbacks
- Add hasReloadedRef flag to prevent multiple reloads
- Clear reconnect interval when update completes or component unmounts
- Only start reconnect attempts when actually updating
- Prevents false positive reloads when server responds normally

* Fix Next.js HMR WebSocket and static asset handling

- Add WebSocket upgrade detection to only intercept /ws/script-execution
- Pass all other WebSocket upgrades (including HMR) to Next.js handler
- Ensure _next routes and static assets are properly handled by Next.js
- Fixes 400 errors for Next.js HMR WebSocket connections
- Fixes 403 errors for static assets by ensuring proper routing

* Fix WebSocket upgrade handling to properly route Next.js HMR

- Create WebSocketServer with noServer: true to avoid auto-attaching
- Manually handle upgrade events to route /ws/script-execution to our WebSocketServer
- Route all other WebSocket upgrades (including Next.js HMR) to Next.js handler
- This ensures Next.js HMR WebSocket connections are properly handled
- Fixes 400 errors for /_next/webpack-hmr WebSocket connections

* Revert WebSocket handling to simpler approach

- Go back to attaching WebSocketServer directly with path option
- Remove manual upgrade event handling that was causing errors
- The path option should filter to only /ws/script-execution
- Next.js should handle its own HMR WebSocket upgrades naturally

* Fix WebSocket upgrade handling to preserve Next.js HMR handlers

- Save existing upgrade listeners before adding our own
- Call existing listeners for non-matching paths to allow Next.js HMR
- Only handle /ws/script-execution ourselves
- This ensures Next.js can handle its own WebSocket upgrades for HMR

* Fix random page reloads during normal app usage

- Memoize startReconnectAttempts with useCallback to prevent recreation on every render
- Fix useEffect dependency arrays to include memoized function
- Add stricter guards checking refs before starting reconnect attempts
- Ensure reconnect logic only runs when actually updating (not during normal usage)
- Add early return in fallback useEffect to prevent false triggers
- Add ref guards in ResyncButton to prevent multiple simultaneous sync operations
- Only reload after sync if it was user-initiated

* Fix critical bug: prevent reloads from stale updateLogsData.isComplete

- Add isUpdating guard before processing updateLogsData.isComplete
- Reset shouldSubscribe when update completes or fails
- Prevent stale isComplete data from triggering reloads during normal usage

* Add update confirmation modal with changelog display

- Add UpdateConfirmationModal component that shows changelog before update
- Modify getVersionStatus to include release body (changelog) in response
- Update VersionDisplay to show confirmation modal instead of starting update directly
- Users must review changelog and click 'Proceed with Update' to start update
- Ensures users see potential breaking changes before updating
This commit is contained in:
Michel Roegl-Brunner
2025-11-26 10:21:14 +01:00
committed by GitHub
parent 2a9921a4e1
commit 66f8a84260
9 changed files with 519 additions and 185 deletions

View File

@@ -79,14 +79,27 @@ class ScriptExecutionHandler {
* @param {import('http').Server} server
*/
constructor(server) {
// Create WebSocketServer without attaching to server
// We'll handle upgrades manually to avoid interfering with Next.js HMR
this.wss = new WebSocketServer({
server,
path: '/ws/script-execution'
noServer: true
});
this.activeExecutions = new Map();
this.db = getDatabase();
this.setupWebSocket();
}
/**
* Handle WebSocket upgrade for our endpoint
* @param {import('http').IncomingMessage} request
* @param {import('stream').Duplex} socket
* @param {Buffer} head
*/
handleUpgrade(request, socket, head) {
this.wss.handleUpgrade(request, socket, head, (ws) => {
this.wss.emit('connection', ws, request);
});
}
/**
* Parse Container ID from terminal output
@@ -1159,12 +1172,22 @@ app.prepare().then(() => {
const parsedUrl = parse(req.url || '', true);
const { pathname, query } = parsedUrl;
if (pathname === '/ws/script-execution') {
// Check if this is a WebSocket upgrade request
const isWebSocketUpgrade = req.headers.upgrade === 'websocket';
// Only intercept WebSocket upgrades for /ws/script-execution
// Let Next.js handle all other WebSocket upgrades (like HMR) and all HTTP requests
if (isWebSocketUpgrade && pathname === '/ws/script-execution') {
// WebSocket upgrade will be handled by the WebSocket server
// Don't call handle() for this path - let WebSocketServer handle it
return;
}
// Let Next.js handle all other requests including HMR
// Let Next.js handle all other requests including:
// - HTTP requests to /ws/script-execution (non-WebSocket)
// - WebSocket upgrades to other paths (like /_next/webpack-hmr)
// - All static assets (_next routes)
// - All other routes
await handle(req, res, parsedUrl);
} catch (err) {
console.error('Error occurred handling', req.url, err);
@@ -1175,6 +1198,33 @@ app.prepare().then(() => {
// Create WebSocket handlers
const scriptHandler = new ScriptExecutionHandler(httpServer);
// Handle WebSocket upgrades manually to avoid interfering with Next.js HMR
// We need to preserve Next.js's upgrade handlers and call them for non-matching paths
// Save any existing upgrade listeners (Next.js might have set them up)
const existingUpgradeListeners = httpServer.listeners('upgrade').slice();
httpServer.removeAllListeners('upgrade');
// Add our upgrade handler that routes based on path
httpServer.on('upgrade', (request, socket, head) => {
const parsedUrl = parse(request.url || '', true);
const { pathname } = parsedUrl;
if (pathname === '/ws/script-execution') {
// Handle our custom WebSocket endpoint
scriptHandler.handleUpgrade(request, socket, head);
} else {
// For all other paths (including Next.js HMR), call existing listeners
// This allows Next.js to handle its own WebSocket upgrades
for (const listener of existingUpgradeListeners) {
try {
listener.call(httpServer, request, socket, head);
} catch (err) {
console.error('Error in upgrade listener:', err);
}
}
}
});
// Note: TerminalHandler removed as it's not being used by the current application
httpServer