From a02f81b454bd81249248d77266a61d6bfda15759 Mon Sep 17 00:00:00 2001 From: bcotrim Date: Wed, 24 Dec 2025 12:39:14 +0000 Subject: [PATCH 1/5] add new site from CLI to Studio runtime --- src/hooks/use-site-details.tsx | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/hooks/use-site-details.tsx b/src/hooks/use-site-details.tsx index cb2ab8adcf..3bf64302b7 100644 --- a/src/hooks/use-site-details.tsx +++ b/src/hooks/use-site-details.tsx @@ -194,6 +194,16 @@ export function SiteDetailsProvider( { children }: SiteDetailsProviderProps ) { ); } ); + useIpcListener( 'user-data-updated', async () => { + const updatedSites = await getIpcApi().getSiteDetails(); + setSites( updatedSites ); + + // Handle case where selected site was deleted externally + if ( selectedSiteId && ! updatedSites.find( ( site ) => site.id === selectedSiteId ) ) { + setSelectedSiteId( updatedSites.length ? updatedSites[ 0 ].id : '' ); + } + } ); + const toggleLoadingServerForSite = useCallback( ( siteId: string ) => { setLoadingServer( ( currentLoading ) => ( { ...currentLoading, From e4b5f5b6c74535017c5d7d1f5db96965239ae2a5 Mon Sep 17 00:00:00 2001 From: bcotrim Date: Wed, 24 Dec 2025 14:00:12 +0000 Subject: [PATCH 2/5] Fix external site changes not reflecting in UI (STU-1163) --- src/ipc-handlers.ts | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/ipc-handlers.ts b/src/ipc-handlers.ts index c159c56516..f92c393321 100644 --- a/src/ipc-handlers.ts +++ b/src/ipc-handlers.ts @@ -173,7 +173,13 @@ function mergeSiteDetailsWithRunningDetails( sites: SiteDetails[] ): SiteDetails return sites.map( ( site ) => { const server = SiteServer.get( site.id ); if ( server ) { - return server.details; + // Merge fresh data from disk with running state from server + // This ensures external changes (e.g., from CLI) are reflected + return { + ...site, + running: server.details.running, + url: server.details.url, + }; } return site; } ); From 1b8f3c95d65fe44e5dad5c67d6d4daf87bcbe520 Mon Sep 17 00:00:00 2001 From: bcotrim Date: Wed, 24 Dec 2025 15:47:37 +0000 Subject: [PATCH 3/5] Fix TypeScript error: handle url property for stopped sites --- src/ipc-handlers.ts | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/src/ipc-handlers.ts b/src/ipc-handlers.ts index f92c393321..d6099973c5 100644 --- a/src/ipc-handlers.ts +++ b/src/ipc-handlers.ts @@ -175,10 +175,16 @@ function mergeSiteDetailsWithRunningDetails( sites: SiteDetails[] ): SiteDetails if ( server ) { // Merge fresh data from disk with running state from server // This ensures external changes (e.g., from CLI) are reflected + if ( server.details.running ) { + return { + ...site, + running: true as const, + url: server.details.url, + }; + } return { ...site, - running: server.details.running, - url: server.details.url, + running: false as const, }; } return site; From 56a4ad886a16a42b5b2a4018da5b0be4eab41616 Mon Sep 17 00:00:00 2001 From: Antonio Sejas Date: Tue, 30 Dec 2025 23:33:11 +0100 Subject: [PATCH 4/5] Fix tests --- src/tests/ipc-handlers.test.ts | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/tests/ipc-handlers.test.ts b/src/tests/ipc-handlers.test.ts index 67c0659484..b95905b902 100644 --- a/src/tests/ipc-handlers.test.ts +++ b/src/tests/ipc-handlers.test.ts @@ -283,9 +283,11 @@ describe( 'getXdebugEnabledSite', () => { const result = await getXdebugEnabledSite( mockIpcMainInvokeEvent ); expect( result ).toEqual( { + autoStart: false, id: 'site-2', name: 'Site 2', path: '/path/to/site-2', + phpVersion: '8.0', running: true, enableXdebug: true, } ); @@ -302,9 +304,11 @@ describe( 'getXdebugEnabledSite', () => { ( fs.existsSync as jest.Mock ).mockReturnValue( true ); ( SiteServer.get as jest.Mock ).mockReturnValue( { details: { + autoStart: false, id: 'site-1', name: 'Site 1', path: '/path/to/site-1', + phpVersion: '8.0', running: false, enableXdebug: true, }, @@ -313,9 +317,11 @@ describe( 'getXdebugEnabledSite', () => { const result = await getXdebugEnabledSite( mockIpcMainInvokeEvent ); expect( result ).toEqual( { + autoStart: false, id: 'site-1', name: 'Site 1', path: '/path/to/site-1', + phpVersion: '8.0', running: false, enableXdebug: true, } ); From 8d9f0df6e722813c4d6ce56bf2d3a83be42f873b Mon Sep 17 00:00:00 2001 From: bcotrim Date: Mon, 5 Jan 2026 14:52:06 +0000 Subject: [PATCH 5/5] add comments for site changes watch workflow --- src/hooks/use-site-details.tsx | 15 ++++++++++ .../cli/lib/execute-site-watch-command.ts | 28 +++++++++++++++++++ 2 files changed, 43 insertions(+) diff --git a/src/hooks/use-site-details.tsx b/src/hooks/use-site-details.tsx index 3bf64302b7..2879f81d30 100644 --- a/src/hooks/use-site-details.tsx +++ b/src/hooks/use-site-details.tsx @@ -186,6 +186,21 @@ export function SiteDetailsProvider( { children }: SiteDetailsProviderProps ) { } } ); + /* + * Site Update Listeners + * + * Two complementary watchers keep the UI in sync with external changes: + * + * 1. 'site-status-changed' (from Site Status Watcher - execute-site-watch-command.ts): + * - Source: PM2 process events via `studio site list --watch` + * - Detects: Site start/stop/crash events + * + * 2. 'user-data-updated' (from User Data Watcher - user-data-watcher.ts): + * - Source: fs.watch on the appdata file + * - Detects: ALL changes (new sites, edits, deletions) + * - Used for: CLI site creation, property changes, external modifications + * + */ useIpcListener( 'site-status-changed', ( _, { siteId, status, url } ) => { setSites( ( prevSites ) => prevSites.map( ( site ) => diff --git a/src/modules/cli/lib/execute-site-watch-command.ts b/src/modules/cli/lib/execute-site-watch-command.ts index 38b9e665ab..4a310de1b7 100644 --- a/src/modules/cli/lib/execute-site-watch-command.ts +++ b/src/modules/cli/lib/execute-site-watch-command.ts @@ -1,3 +1,31 @@ +/** + * Site Status Watcher + * + * This module monitors site running/stopped status changes by subscribing to PM2 process events + * via `studio site list --watch`. It's primarily used to detect status changes that occur outside + * of Studio's direct control, such as: + * - Sites started/stopped via CLI commands + * - Site crashes or unexpected process terminations + * + * IMPORTANT: Architecture Notes + * ----------------------------- + * There are currently TWO separate watchers that update the UI with site changes: + * + * 1. Site Status Watcher (this file): + * - Monitors PM2 process events (start/stop/crash) + * - Only detects running/stopped status changes + * - Sends 'site-status-changed' IPC events to the renderer + * + * 2. User Data Watcher (src/lib/user-data-watcher.ts): + * - Monitors the appdata file directly via fs.watch + * - Detects ALL changes to site data (new sites, edits, deletions) + * - Sends 'user-data-updated' IPC events to the renderer + * + * The renderer (use-site-details.tsx) listens to BOTH: + * - 'site-status-changed': Updates running/stopped status for existing sites + * - 'user-data-updated': Refreshes the entire site list (handles new sites, edits, deletions) + * + */ import { z } from 'zod'; import { sendIpcEventToRenderer } from 'src/ipc-utils'; import { executeCliCommand } from 'src/modules/cli/lib/execute-command';