diff --git a/apps/webapp/app/components/layout/MetricsLayout.tsx b/apps/webapp/app/components/layout/MetricsLayout.tsx index ccf5129b58a..0745e56202b 100644 --- a/apps/webapp/app/components/layout/MetricsLayout.tsx +++ b/apps/webapp/app/components/layout/MetricsLayout.tsx @@ -9,6 +9,7 @@ * - `Grid` — tiles; columns derived from tile count unless `columns` is set. `kind="charts"` * bakes the fixed chart-row height. * - `Content` — table / tabs below the tiles. Full-bleed by default; `inset` for a padded column. + * `toolbar` adds a bar flush above the content for controls that scope only this region. * * Optional: * - `Sidebar` — a persistent right-hand panel; fixed `width` or `resizable`. Present ⇒ Root @@ -22,12 +23,14 @@ * ```tsx * * - *
…search + TimeFilter…
- * + *
…TimeFilter…
+ *
…page-wide actions…
*
* …stat tiles… * …chart tiles… - * …table… + * …search…}> + * …table… + * *
* ``` */ @@ -341,16 +344,44 @@ function MetricsLayoutGrid({ * spans edge to edge with its own top border; pass `inset` for a padded column (the detail page's * tabs + charts). Separation from the tiles above comes from the scroll column's gap alone (no * extra top margin), so the tile → content step matches the gap between tile rows. + * + * Pass `toolbar` for controls that scope this region only (search, pagination) — they sit flush on + * top of the content instead of in the page-wide `Filters` bar, so their scope is visible. */ function MetricsLayoutContent({ children, inset = false, + toolbar, }: { children: ReactNode; /** Pad the content into a column (page gutter) instead of letting it span edge to edge. */ inset?: boolean; + /** + * Controls that act on this region alone. Rendered as a bar directly above the content with no + * gap, so it reads as belonging to the table below rather than to the tiles above. Compose + * left/right clusters as child divs — `justify-between` spreads them. + */ + toolbar?: ReactNode; }) { - return
{children}
; + const content =
{children}
; + + if (!toolbar) { + return content; + } + + return ( +
+
+ {toolbar} +
+ {content} +
+ ); } export const MetricsLayout = { diff --git a/apps/webapp/app/routes/_app.orgs.$organizationSlug.projects.$projectParam.env.$envParam.queues/route.tsx b/apps/webapp/app/routes/_app.orgs.$organizationSlug.projects.$projectParam.env.$envParam.queues/route.tsx index 4b5673c6f0e..05ac0e7b47d 100644 --- a/apps/webapp/app/routes/_app.orgs.$organizationSlug.projects.$projectParam.env.$envParam.queues/route.tsx +++ b/apps/webapp/app/routes/_app.orgs.$organizationSlug.projects.$projectParam.env.$envParam.queues/route.tsx @@ -493,12 +493,10 @@ function QueuesWithMetricsView() { - {/* Filters — pinned bar directly under the NavBar. Left cluster = search + period; right - cluster = pagination. */} + {/* Filters — pinned bar directly under the NavBar. This row is page-wide only: Period is + the one control that changes the tiles and charts below, so it leads the row. Search + and pagination scope the table alone and live in that table's own bar instead. */} -
- -
+
+
{environment.runsEnabled && env.pauseSource !== ENVIRONMENT_PAUSE_SOURCE_BILLING_LIMIT ? ( ) : null} -
@@ -688,7 +682,22 @@ function QueuesWithMetricsView() { ) : null} - + + + + + } + > {/* Default overflow-x-auto container so wide tables still scroll horizontally on narrow viewports; the page (not this region) owns vertical scrolling. */}