From 27f1f1d2073402c51e369eeca1bf7e1eaa188ac8 Mon Sep 17 00:00:00 2001 From: Mohamed Boudra Date: Thu, 2 Jul 2026 15:41:08 +0200 Subject: [PATCH] fix(app): align schedules screen shell with app conventions Move the New schedule button out of the screen header (the only screen using MenuHeader rightContent) into the content filter row, and match the History screen's full-width layout instead of the 720px centered column. Tighten the shared sm SegmentedControl and Button vertical padding so the status switcher and button sit flush with the host-filter pill; this is a global sm change and also affects settings and the schedule form sheet. --- .../app/e2e/schedules-project-target.spec.ts | 4 +- .../components/schedules/schedules-table.tsx | 17 ++--- packages/app/src/components/ui/button.tsx | 2 +- .../src/components/ui/segmented-control.tsx | 2 +- packages/app/src/screens/schedules-screen.tsx | 70 ++++++++----------- 5 files changed, 41 insertions(+), 54 deletions(-) diff --git a/packages/app/e2e/schedules-project-target.spec.ts b/packages/app/e2e/schedules-project-target.spec.ts index d78133957..c1bfa16e9 100644 --- a/packages/app/e2e/schedules-project-target.spec.ts +++ b/packages/app/e2e/schedules-project-target.spec.ts @@ -83,7 +83,7 @@ test.describe("Schedules project target", () => { await expect(page).not.toHaveURL(/\/h\//); await expect(page.getByTestId("schedules-empty")).toBeVisible(); - await page.getByTestId("schedules-new").click(); + await page.getByTestId("schedules-empty-new").click(); await expect(page.getByTestId("schedule-form-sheet")).toBeVisible({ timeout: 10_000 }); await expect(page.getByTestId("schedule-cwd-trigger")).toHaveCount(0); @@ -127,7 +127,7 @@ test.describe("Schedules project target", () => { port: fakePort, }); await expect(page.getByTestId("schedules-empty")).toBeVisible({ timeout: 30_000 }); - await page.getByTestId("schedules-new").click(); + await page.getByTestId("schedules-empty-new").click(); await expect(page.getByTestId("schedule-form-sheet")).toBeVisible({ timeout: 10_000 }); await page.getByRole("button", { name: /select project/i }).click(); diff --git a/packages/app/src/components/schedules/schedules-table.tsx b/packages/app/src/components/schedules/schedules-table.tsx index 86b5bd52e..037bc1f10 100644 --- a/packages/app/src/components/schedules/schedules-table.tsx +++ b/packages/app/src/components/schedules/schedules-table.tsx @@ -24,7 +24,7 @@ interface SchedulesTableProps { rows: ScheduleRowView[]; /** * The form sheet is owned by the screen (it serves both create and edit and - * shares the header's "New schedule" button), so the table delegates edit + * shares the screen's "New schedule" button), so the table delegates edit * upward rather than mounting a second sheet here. */ onEditSchedule: (schedule: AggregatedSchedule) => void; @@ -32,9 +32,9 @@ interface SchedulesTableProps { /** * The schedules list: a single settings-style card of rows across every - * connected host, in a centered, width-constrained reading column matching the - * projects list. Rows own their host-scoped mutations (pause/resume/run/delete - * via the mutations hook + a destructive confirm) and delegate editing upward. + * connected host, in a full-width list matching the History screen. Rows own + * their host-scoped mutations (pause/resume/run/delete via the mutations hook + + * a destructive confirm) and delegate editing upward. */ export function SchedulesTable({ rows, onEditSchedule }: SchedulesTableProps): ReactElement { return ( @@ -145,14 +145,9 @@ function SchedulesTableRow({ ); } -const CONTENT_MAX_WIDTH = 720; - const styles = StyleSheet.create((theme) => ({ - // Center the card in a readable column, matching settings and projects. + // Full-width list padding matching the History screen. listContent: { - width: "100%", - maxWidth: CONTENT_MAX_WIDTH, - alignSelf: "center", - paddingHorizontal: theme.spacing[4], + paddingHorizontal: { xs: theme.spacing[3], md: theme.spacing[6] }, }, })); diff --git a/packages/app/src/components/ui/button.tsx b/packages/app/src/components/ui/button.tsx index e6bb7b349..51f8abd68 100644 --- a/packages/app/src/components/ui/button.tsx +++ b/packages/app/src/components/ui/button.tsx @@ -50,7 +50,7 @@ const styles = StyleSheet.create((theme) => ({ borderRadius: theme.borderRadius.md, }, sm: { - paddingVertical: theme.spacing[2], + paddingVertical: theme.spacing[1.5], paddingHorizontal: theme.spacing[3], borderRadius: theme.borderRadius.md, }, diff --git a/packages/app/src/components/ui/segmented-control.tsx b/packages/app/src/components/ui/segmented-control.tsx index 01d279fe8..934a6fa28 100644 --- a/packages/app/src/components/ui/segmented-control.tsx +++ b/packages/app/src/components/ui/segmented-control.tsx @@ -161,7 +161,7 @@ const styles = StyleSheet.create((theme) => ({ gap: theme.spacing[1], }, segmentSm: { - paddingVertical: theme.spacing[2], + paddingVertical: theme.spacing[1.5], paddingHorizontal: theme.spacing[4], }, segmentMd: { diff --git a/packages/app/src/screens/schedules-screen.tsx b/packages/app/src/screens/schedules-screen.tsx index a750610a2..8a459ada1 100644 --- a/packages/app/src/screens/schedules-screen.tsx +++ b/packages/app/src/screens/schedules-screen.tsx @@ -154,21 +154,12 @@ function SchedulesScreenContent(): ReactElement { })); }, [resolvedRows, selectedHost, statusFilter, hosts.length]); - const headerAction = useMemo( - () => ( - - ), - [openCreate], - ); - const showLoadError = isError && schedules.length === 0; const showHostFilter = hosts.length > 1; return ( - + - {showHostFilter ? ( - + {showHostFilter ? ( + + ) : null} + - ) : null} - + + ({ container: { flex: 1, @@ -332,16 +326,20 @@ const styles = StyleSheet.create((theme) => ({ padding: theme.spacing[6], }, filterRow: { - width: "100%", - maxWidth: CONTENT_MAX_WIDTH, - alignSelf: "center", flexDirection: "row", alignItems: "center", - flexWrap: "wrap", + justifyContent: "space-between", gap: theme.spacing[3], - paddingHorizontal: theme.spacing[4], + paddingHorizontal: { xs: theme.spacing[3], md: theme.spacing[6] }, paddingTop: theme.spacing[4], }, + filterRowControls: { + flexDirection: "row", + alignItems: "center", + gap: theme.spacing[3], + flexShrink: 1, + flexWrap: "wrap", + }, scroll: { flex: 1, minHeight: 0, @@ -352,10 +350,7 @@ const styles = StyleSheet.create((theme) => ({ paddingBottom: theme.spacing[6], }, errorsBannerWrap: { - width: "100%", - maxWidth: CONTENT_MAX_WIDTH, - alignSelf: "center", - paddingHorizontal: theme.spacing[4], + paddingHorizontal: { xs: theme.spacing[3], md: theme.spacing[6] }, }, errorsBanner: { borderWidth: 1, @@ -369,10 +364,7 @@ const styles = StyleSheet.create((theme) => ({ fontSize: theme.fontSize.xs, }, filterEmpty: { - width: "100%", - maxWidth: CONTENT_MAX_WIDTH, - alignSelf: "center", - paddingHorizontal: theme.spacing[4], + paddingHorizontal: { xs: theme.spacing[3], md: theme.spacing[6] }, paddingVertical: theme.spacing[6], alignItems: "center", },