diff --git a/.changeset/top-align-growing-query-toolbars.md b/.changeset/top-align-growing-query-toolbars.md new file mode 100644 index 0000000000..e7aa6981be --- /dev/null +++ b/.changeset/top-align-growing-query-toolbars.md @@ -0,0 +1,7 @@ +--- +'@hyperdx/app': patch +--- + +fix: keep toolbar controls level with the first line of a wrapping query field + +Date pickers, Run, and nearby row actions stay top-aligned as a SQL or Lucene field grows. Sessions opts into PageHeader block padding so a taller search bar still has room. diff --git a/.claude/skills/page-layout/SKILL.md b/.claude/skills/page-layout/SKILL.md index 7d2cadccd2..2a4577cc77 100644 --- a/.claude/skills/page-layout/SKILL.md +++ b/.claude/skills/page-layout/SKILL.md @@ -40,5 +40,5 @@ import { PageLayout } from '@/components/PageLayout'; | List page | `AlertsPage.tsx` | `PageHeader` + `title` + `Container` (no inputs in header) | | Tool page with inputs + hierarchy | `KubernetesDashboardPage.tsx`, `ClickhousePage.tsx` | `PageLayout` **without** `title`; **`breadcrumbs`** + `leading` + `actions` in one sticky header | | Tool page (top-level) | `DBServiceMapPage.tsx` | `PageLayout` **without** `title`; `leading` / `actions` only; no duplicate breadcrumb unless you add a real hierarchy | -| Custom toolbar | `SessionsPage.tsx` | `PageLayout` + `header` = custom `PageHeader` `children` (single-row inputs, no `title`) | +| Custom toolbar | `SessionsPage.tsx` | `PageLayout` + `header` = custom `PageHeader` `children` with `growing` (single-row inputs, no `title`) | | Custom title | `TeamPage.tsx` | `PageHeader` with `children` only | diff --git a/agent_docs/page_layout.md b/agent_docs/page_layout.md index 18d7274bb2..1c34590d26 100644 --- a/agent_docs/page_layout.md +++ b/agent_docs/page_layout.md @@ -35,8 +35,9 @@ Both live next to `withAppNav` in `packages/app/src/layout.tsx`, which wraps pag | `leading` | Left cluster: source picker, badges, or other controls. When inputs are present, **do not** pair with `title` for the same page name. | | `actions` | Right-aligned cluster: time range, Run/Save, sampling, refresh. | | `children` | Full custom header when slots are not enough. Do not combine with `title` / `leading` / `actions` / `breadcrumbs` unless you use the breadcrumbs-only branch. | +| `growing` | Opt in to block padding that only shows once the toolbar outgrows `min-height`. Sessions uses this for its multi-line search; title-only pages omit it. | -Header styling is defined in `PageHeader.module.scss`: sticky top, bottom border, horizontal padding `var(--mantine-spacing-sm)` (same as Search `px="sm"`). Single-row headers keep `min-height: 60px`; stacked header (breadcrumbs + toolbar) grows with content. +Header styling is defined in `PageHeader.module.scss`: sticky top, bottom border, horizontal padding `var(--mantine-spacing-sm)` (same as Search `px="sm"`). Single-row headers keep `min-height: 60px`; stacked header (breadcrumbs + toolbar) grows with content. Pass `growing` when the toolbar can outgrow that min-height (Sessions' multi-line search) so block padding appears only once the row is taller than the bar. ## PageLayout API diff --git a/packages/app/src/DBSearchPage.tsx b/packages/app/src/DBSearchPage.tsx index d93506e048..087a2a1063 100644 --- a/packages/app/src/DBSearchPage.tsx +++ b/packages/app/src/DBSearchPage.tsx @@ -2394,7 +2394,7 @@ export function DBSearchPage() { - + + )} - + {filtersToggle != null && tabQueriesData(activeTab) && ( - + + + )} {(activeTab === 'table' || activeTab === 'pie' || diff --git a/packages/app/src/components/DBEditTimeChartForm/ChartEditorControls.tsx b/packages/app/src/components/DBEditTimeChartForm/ChartEditorControls.tsx index a172809faf..f19100573d 100644 --- a/packages/app/src/components/DBEditTimeChartForm/ChartEditorControls.tsx +++ b/packages/app/src/components/DBEditTimeChartForm/ChartEditorControls.tsx @@ -34,6 +34,7 @@ import { isFormulaDisplayType, isFormulaSourceKind, } from '@/components/ChartEditor/utils'; +import { EDITOR_INPUT_HEIGHTS } from '@/components/editorInputHeights'; import MVOptimizationIndicator from '@/components/MaterializedViews/MVOptimizationIndicator'; import SearchWhereInput from '@/components/SearchInput/SearchWhereInput'; import SourceSchemaPreview, { @@ -325,13 +326,14 @@ export function ChartEditorControls({ <>
-
+ Group By -
+
{displayType === DisplayType.Table && ( <> -
+ Having -
+
{showWhere && ( <> - Where + + Where +
- - Group By - + + + Group By + +
{showHaving && ( <> - - Having - + + + Having + +
Trace ID Expression - + = ({ }; return ( - + {K8S_FILTER_FIELDS.map(({ field, placeholder, dataTestId }) => ( `, which lets it stay pinned for the full // length of the page rather than only the height of the header. const chromeStickyClass = hasStickyRow ? styles.notSticky : undefined; + const chromeClassName = classNames( + styles.header, + growing && styles.growing, + chromeStickyClass, + className, + ); const toolbarInner = ( <> @@ -118,21 +131,13 @@ export function PageHeader({ // it. A page with only a `stickyRow` (no breadcrumbs, no title) // skips the empty chrome entirely. children != null ? ( -
+
{children}
) : null ) : hasBreadcrumbs && hasToolbar ? (
{breadcrumbs}
@@ -140,22 +145,14 @@ export function PageHeader({
) : hasBreadcrumbs && !hasToolbar ? (
{breadcrumbs}
{children}
) : ( -
+
{toolbarInner}
); diff --git a/packages/app/src/components/Sources/SourceForm/HighlightedAttributes.tsx b/packages/app/src/components/Sources/SourceForm/HighlightedAttributes.tsx index 7b82510c19..9159318abf 100644 --- a/packages/app/src/components/Sources/SourceForm/HighlightedAttributes.tsx +++ b/packages/app/src/components/Sources/SourceForm/HighlightedAttributes.tsx @@ -8,6 +8,7 @@ import { IconTrash, } from '@tabler/icons-react'; +import { EDITOR_INPUT_HEIGHTS } from '@/components/editorInputHeights'; import { ErrorCollapse } from '@/components/Error/ErrorCollapse'; import { InputControlled } from '@/components/InputControlled'; import { SQLInlineEditorControlled } from '@/components/SQLEditor/SQLInlineEditor'; @@ -83,34 +84,38 @@ function HighlightedAttributeRow({
- - AS + + + AS + - + + + + + + removeHighlightedAttribute(index)} > - + - - removeHighlightedAttribute(index)} - > - - + diff --git a/packages/app/src/components/Sources/SourceForm/MaterializedViews.tsx b/packages/app/src/components/Sources/SourceForm/MaterializedViews.tsx index 07ccdea0f3..264ca64b8b 100644 --- a/packages/app/src/components/Sources/SourceForm/MaterializedViews.tsx +++ b/packages/app/src/components/Sources/SourceForm/MaterializedViews.tsx @@ -6,6 +6,7 @@ import { Box, Button, Divider, + Flex, Grid, Group, Select, @@ -19,6 +20,7 @@ import { IconCirclePlus, IconHelpCircle, IconTrash } from '@tabler/icons-react'; import { DatabaseSelectControlled } from '@/components/DatabaseSelect'; import { DBTableSelectControlled } from '@/components/DBTableSelect'; +import { EDITOR_INPUT_HEIGHTS } from '@/components/editorInputHeights'; import SelectControlled from '@/components/SelectControlled'; import { SQLInlineEditorControlled } from '@/components/SQLEditor/SQLInlineEditor'; import { useMetadataWithSettings } from '@/hooks/useMetadata'; @@ -556,7 +558,7 @@ function AggregatedColumnRow({ )} - + - - - + + + + + diff --git a/packages/app/src/components/Sources/SourceForm/OrderByFormRow.tsx b/packages/app/src/components/Sources/SourceForm/OrderByFormRow.tsx index bcc09a0e73..4d11b4feb6 100644 --- a/packages/app/src/components/Sources/SourceForm/OrderByFormRow.tsx +++ b/packages/app/src/components/Sources/SourceForm/OrderByFormRow.tsx @@ -6,6 +6,7 @@ import { ActionIcon, Box, Flex, Text, Tooltip } from '@mantine/core'; import { useDebouncedCallback, useDidUpdate } from '@mantine/hooks'; import { IconCheck } from '@tabler/icons-react'; +import { EDITOR_INPUT_HEIGHTS } from '@/components/editorInputHeights'; import { ErrorCollapse } from '@/components/Error/ErrorCollapse'; import { SQLInlineEditorControlled } from '@/components/SQLEditor/SQLInlineEditor'; import { useExplainQuery } from '@/hooks/useExplainQuery'; @@ -73,7 +74,7 @@ export function OrderByFormRow({ label="Default Order By" helpText="Custom ORDER BY expression that overrides the default ordering. Leave empty to use the auto-detected default. (This can be customized per search later)" > - + - - - - - + + + + + + + {shouldShowResult && (