From f7f590fa4790ba0d9f089b0e50e1a684a930113a Mon Sep 17 00:00:00 2001 From: Developer Date: Fri, 26 Jun 2026 21:21:59 +0000 Subject: [PATCH] Fix: ServicePage content tabs wrapped in SheetForm on mobile The reconciliation with mobile-responsive-parity applied the SheetForm wrapper (designed when ServicePage was config-only) to the ENTIRE service page, including content tabs. Clicking a nav item like 'Media' on mobile opened a form sheet with Save/Cancel instead of the tabbed content browser. Fix: ServicePage now renders the Tabs skeleton on ALL breakpoints. Content tabs (Media, Files, Actions, etc.) are operational views, not forms -- they have their own mobile handling (MobileCardRow, etc.) and should not be wrapped in a Save/Cancel sheet. The Config tab renders inline like every other tab. Removes the isMobile branch + SheetForm wrapper + dead imports (useIsMobile, SheetForm) + sheetOpen state. 117 tests pass; lint/build green. --- frontend/src/pages/ServicePage.tsx | 59 +----------------------------- 1 file changed, 2 insertions(+), 57 deletions(-) diff --git a/frontend/src/pages/ServicePage.tsx b/frontend/src/pages/ServicePage.tsx index 038ad24..b69a613 100644 --- a/frontend/src/pages/ServicePage.tsx +++ b/frontend/src/pages/ServicePage.tsx @@ -20,8 +20,6 @@ import { useServiceInstances, useServiceTypes, } from "../hooks/useServices"; -import { useIsMobile } from "../hooks/useIsMobile"; -import { SheetForm } from "@/components/ui/sheet-form"; import type { ServiceInstance, ServiceInstanceInput, @@ -99,8 +97,6 @@ export function ServicePage() { const [draftSecrets, setDraftSecrets] = useState>({}); const [deleteOpen, setDeleteOpen] = useState(false); const [hydrated, setHydrated] = useState(false); - const isMobile = useIsMobile(); - const [sheetOpen, setSheetOpen] = useState(true); if (instance && !hydrated) { setName(instance.name); @@ -149,9 +145,10 @@ export function ServicePage() { setDraftSecrets({}); } + const allTabs: ContentTab[] = [OVERVIEW_TAB, ...contentTabs]; - // The config + widgets body, shared between desktop tabs and mobile SheetForm. + // The config + widgets body, rendered inside the Config and Widgets tabs. const widgetsContent = binding.widgets.length > 0 ? (
@@ -197,58 +194,6 @@ export function ServicePage() { /> ); - // Mobile: render inside a SheetForm (open on mount; cancel navigates back). - if (isMobile) { - return ( -
- { - setSheetOpen(false); - navigate("/services"); - }} - isPending={saveService.isPending} - isDirty={ - name !== instance.name || - enabled !== instance.enabled || - JSON.stringify(draftConfig) !== JSON.stringify(instance.config) - } - > -
- {allTabs.map((tab) => { - const TabComponent = tab.Component; - return ( -
-

- {tab.label} -

- -
- ); - })} - {widgetsContent} - {configBody} -
-
- setDeleteOpen(false)} - onConfirm={() => { - deleteService.mutate(instance.id); - setDeleteOpen(false); - navigate("/services"); - }} - /> -
- ); - } - return (
{/* Header + instance switcher */}