From 562dd7ea286ccd17c88fdf0aa248938fadc90a97 Mon Sep 17 00:00:00 2001 From: Elizabet Oliveira Date: Thu, 20 Nov 2025 15:00:42 +0000 Subject: [PATCH] Fix minor UI issues (#1382) --- .changeset/fix-minor-ui-issues.md | 5 + packages/app/.storybook/preview.tsx | 29 +- packages/app/package.json | 1 + packages/app/src/AppNav.components.tsx | 2 +- packages/app/src/AppNav.tsx | 6 +- packages/app/src/LandingHeader.tsx | 7 +- packages/app/src/ThemeWrapper.tsx | 265 +---------------- packages/app/src/TimelineChart.tsx | 31 +- .../app/src/components/DBRowOverviewPanel.tsx | 3 +- packages/app/src/components/DBTracePanel.tsx | 1 + .../src/components/DBTraceWaterfallChart.tsx | 9 +- .../components/ExceptionSubpanel.stories.tsx | 80 +++++ .../app/src/components/HyperJson.module.scss | 2 +- .../app/src/components/SQLEditor.stories.tsx | 24 ++ .../components/SQLInlineEditor.stories.tsx | 25 ++ packages/app/src/components/Table.module.scss | 3 +- .../app/src/theme/SemanticColors.stories.tsx | 39 +++ packages/app/src/theme/mantineTheme.ts | 280 ++++++++++++++++++ .../app/src/theme/semanticColorsGrouped.ts | 47 +++ packages/app/styles/LogSidePanel.module.scss | 4 +- packages/app/styles/SearchPage.module.scss | 6 +- packages/app/styles/TimelineChart.module.scss | 5 +- packages/app/styles/_semantic-colors.scss | 38 +-- yarn.lock | 12 + 24 files changed, 617 insertions(+), 307 deletions(-) create mode 100644 .changeset/fix-minor-ui-issues.md create mode 100644 packages/app/src/components/ExceptionSubpanel.stories.tsx create mode 100644 packages/app/src/components/SQLEditor.stories.tsx create mode 100644 packages/app/src/components/SQLInlineEditor.stories.tsx create mode 100644 packages/app/src/theme/SemanticColors.stories.tsx create mode 100644 packages/app/src/theme/mantineTheme.ts create mode 100644 packages/app/src/theme/semanticColorsGrouped.ts diff --git a/.changeset/fix-minor-ui-issues.md b/.changeset/fix-minor-ui-issues.md new file mode 100644 index 00000000..d35f6fde --- /dev/null +++ b/.changeset/fix-minor-ui-issues.md @@ -0,0 +1,5 @@ +--- +'@hyperdx/app': patch +--- + +Fix minor UI issues and enhance styling across various components diff --git a/packages/app/.storybook/preview.tsx b/packages/app/.storybook/preview.tsx index a41754ba..b80f6abd 100644 --- a/packages/app/.storybook/preview.tsx +++ b/packages/app/.storybook/preview.tsx @@ -16,16 +16,40 @@ import '../styles/app.scss'; import { meHandler } from '../src/mocks/handlers'; import { ThemeWrapper } from '../src/ThemeWrapper'; +export const parameters = { + layout: 'fullscreen', + options: { + showPanel: false, + storySort: (a, b) => + a.title.localeCompare(b.title, undefined, { numeric: true }), + }, +}; + +export const globalTypes = { + theme: { + name: 'Theme', + description: 'Mantine color scheme', + defaultValue: 'light', + toolbar: { + icon: 'mirror', + items: [ + { value: 'light', title: 'Light' }, + { value: 'dark', title: 'Dark' }, + ], + }, + }, +}; + initialize(); const queryClient = new QueryClient(); const preview: Preview = { decorators: [ - Story => ( + (Story, context) => ( - + @@ -37,6 +61,7 @@ const preview: Preview = { msw: { handlers: [meHandler], }, + backgrounds: { disable: true }, }, }; diff --git a/packages/app/package.json b/packages/app/package.json index d45289fd..6ecd7a35 100644 --- a/packages/app/package.json +++ b/packages/app/package.json @@ -111,6 +111,7 @@ "@storybook/addon-interactions": "^8.1.5", "@storybook/addon-links": "^8.1.5", "@storybook/addon-styling-webpack": "^1.0.0", + "@storybook/addon-themes": "^10.0.8", "@storybook/blocks": "^8.1.5", "@storybook/nextjs": "^8.1.5", "@storybook/react": "^8.1.5", diff --git a/packages/app/src/AppNav.components.tsx b/packages/app/src/AppNav.components.tsx index ef443349..3a4ec5bf 100644 --- a/packages/app/src/AppNav.components.tsx +++ b/packages/app/src/AppNav.components.tsx @@ -293,7 +293,7 @@ export const AppNavLink = ({ const testId = `nav-link-${href.replace(/^\//, '').replace(/\//g, '-') || 'home'}`; return ( - + { HyperDX.addAction('user navigated', { @@ -604,7 +605,10 @@ export default function AppNav({ fixed = false }: { fixed?: boolean }) { }} >
-
+
{isCollapsed ? (
diff --git a/packages/app/src/LandingHeader.tsx b/packages/app/src/LandingHeader.tsx index a6bf47ea..1ce95b25 100644 --- a/packages/app/src/LandingHeader.tsx +++ b/packages/app/src/LandingHeader.tsx @@ -30,7 +30,7 @@ export default function LandingHeader({ right: 0, background: 'var(--color-bg-body)', backdropFilter: 'blur(12px)', - border: '1px solid var(--color-border)', + borderBottom: '1px solid var(--color-border)', zIndex: 100, }} > @@ -47,12 +47,13 @@ export default function LandingHeader({ color="white" /> - + HyperDX Cloud @@ -61,6 +62,7 @@ export default function LandingHeader({ c={activeKey === 'docs' ? 'green' : 'gray'} underline="never" style={{ fontWeight: activeKey === 'docs' ? 600 : 400 }} + size="sm" > Docs @@ -70,6 +72,7 @@ export default function LandingHeader({ c={activeKey === '/login' ? 'green' : 'gray'} underline="never" style={{ fontWeight: activeKey === '/login' ? 600 : 400 }} + size="sm" > Login diff --git a/packages/app/src/ThemeWrapper.tsx b/packages/app/src/ThemeWrapper.tsx index b1d1c1fe..e1ed983a 100644 --- a/packages/app/src/ThemeWrapper.tsx +++ b/packages/app/src/ThemeWrapper.tsx @@ -1,263 +1,8 @@ import React from 'react'; -import { - ActionIcon, - Button, - MantineProvider, - MantineTheme, - MantineThemeOverride, - rem, - Select, - Text, -} from '@mantine/core'; +import { MantineProvider } from '@mantine/core'; import { Notifications } from '@mantine/notifications'; -const makeTheme = ({ - fontFamily = '"IBM Plex Sans", monospace', -}: { - fontFamily?: string; -}): MantineThemeOverride => ({ - cursorType: 'pointer', - fontFamily, - primaryColor: 'green', - primaryShade: 8, - autoContrast: true, - white: '#fff', - fontSizes: { - xxs: '11px', - xs: '12px', - sm: '13px', - md: '15px', - lg: '16px', - xl: '18px', - }, - spacing: { - xxxs: 'calc(0.375rem * var(--mantine-scale))', - xxs: 'calc(0.5rem * var(--mantine-scale))', - xs: 'calc(0.625rem * var(--mantine-scale))', - sm: 'calc(0.75rem * var(--mantine-scale))', - md: 'calc(1rem * var(--mantine-scale))', - lg: 'calc(1.25rem * var(--mantine-scale))', - xl: 'calc(2rem * var(--mantine-scale))', - }, - colors: { - // https://uicolors.app/generate/00c28a - green: [ - '#eafff6', - '#cdfee7', - '#a0fad5', - '#63f2bf', - '#25e2a5', - '#00c28a', - '#00a475', - '#008362', - '#00674e', - '#005542', - ], - // https://mantine.dev/colors-generator/?color=A1A1AA - // Customized with FAFAFA, D7D8DB, A1A1AA - gray: [ - '#FAFAFA', // Off White - '#e6e6ee', - '#D7D8DB', // Light Gray - '#aeaeb7', - '#A1A1AA', // Primary Gray - '#868691', - '#7e7e8b', - '#6c6c79', - '#5f5f6e', - '#515264', - ], - dark: [ - '#C1C2C5', - '#A6A7AB', - '#909296', - '#5C5F66', - '#373A40', - '#2C2E33', - '#25262B', - '#1A1B1E', - '#141517', - '#101113', - ], - }, - headings: { - fontFamily, - }, - components: { - Modal: { - styles: { - header: { - fontFamily, - fontWeight: 'bold', - }, - }, - }, - InputWrapper: { - styles: { - label: { - marginBottom: 4, - }, - description: { - marginBottom: 8, - lineHeight: 1.3, - }, - }, - }, - Select: Select.extend({ - styles: { - input: { - border: '1px solid var(--color-border)', - }, - }, - }), - Input: { - styles: { - input: { - backgroundColor: 'var(--color-bg-field)', - border: '1px solid var(--color-border)', - }, - }, - }, - Card: { - styles: (_theme: MantineTheme, props: { variant?: string }) => { - if (props.variant === 'muted') { - return { - root: { - backgroundColor: 'var(--color-bg-muted)', - border: '1px solid var(--color-border)', - }, - }; - } - return { - root: { - backgroundColor: 'var(--color-bg-body)', - }, - }; - }, - }, - Divider: { - styles: { - root: { - borderColor: 'var(--color-border)', - borderTopColor: 'var(--color-border)', - '--divider-color': 'var(--color-border)', - '--item-border-color': 'var(--color-border)', - }, - }, - }, - Accordion: { - styles: { - control: { - '--item-border-color': 'var(--color-border)', - }, - item: { - borderColor: 'var(--color-border)', - }, - }, - }, - UnstyledButton: { - styles: { - root: { - '--item-border-color': 'var(--color-border)', - }, - }, - }, - Paper: { - classNames: (_theme: MantineTheme, props: { variant?: string }) => { - if (props.variant === 'muted') { - return { - root: 'paper-muted', - }; - } - return {}; - }, - styles: (_theme: MantineTheme, props: { variant?: string }) => { - if (props.variant === 'muted') { - return { - root: { - backgroundColor: 'var(--color-bg-muted)', - border: '1px solid var(--color-border)', - }, - }; - } - return { - root: { - border: '1px solid var(--color-border)', - }, - }; - }, - }, - Text: Text.extend({ - styles: (theme, props) => { - if (props.variant === 'danger') { - return { - root: { - color: 'var(--color-text-danger)', - }, - }; - } - return {}; - }, - }), - Button: Button.extend({ - vars: (theme, props) => { - if (props.size === 'xxs') { - return { - root: { - '--button-height': rem(22), - '--button-padding-x': rem(4), - '--button-fz': rem(12), - }, - }; - } - - return { root: {} }; - }, - }), - ActionIcon: ActionIcon.extend({ - defaultProps: { - variant: 'subtle', - color: 'gray', - }, - styles: (theme, props) => { - // Subtle variant stays transparent - if (props.variant === 'subtle') { - return { - root: { - backgroundColor: 'transparent', - color: 'var(--color-text)', - '&:hover': { - backgroundColor: 'var(--color-bg-hover)', - }, - '&:active': { - backgroundColor: 'var(--color-bg-muted)', - }, - }, - }; - } - - // Default variant - if (props.variant === 'default') { - return { - root: { - backgroundColor: 'var(--color-bg-hover)', - color: 'var(--color-text)', - border: 'none', - '&:hover': { - backgroundColor: 'var(--color-bg-muted)', - }, - '&:active': { - backgroundColor: 'var(--color-bg-muted)', - }, - }, - }; - } - - return {}; - }, - }), - }, -}); +import { makeTheme, theme as defaultTheme } from './theme/mantineTheme'; export const ThemeWrapper = ({ fontFamily, @@ -268,8 +13,10 @@ export const ThemeWrapper = ({ colorScheme?: 'dark' | 'light'; children: React.ReactNode; }) => { - const theme = React.useMemo(() => makeTheme({ fontFamily }), [fontFamily]); - + const theme = React.useMemo( + () => (fontFamily ? makeTheme({ fontFamily }) : defaultTheme), + [fontFamily], + ); return ( diff --git a/packages/app/src/TimelineChart.tsx b/packages/app/src/TimelineChart.tsx index 6434a8cf..d1a6ac3b 100644 --- a/packages/app/src/TimelineChart.tsx +++ b/packages/app/src/TimelineChart.tsx @@ -18,6 +18,7 @@ type TimelineEventT = { color: string; body: React.ReactNode; minWidthPerc?: number; + isError?: boolean; }; const NewTimelineRow = memo( @@ -35,7 +36,9 @@ const NewTimelineRow = memo( height: number; scale: number; offset: number; - eventStyles?: any; + eventStyles?: + | React.CSSProperties + | ((event: TimelineEventT) => React.CSSProperties); onEventHover?: Function; onEventClick?: (event: any) => any; }) { @@ -84,7 +87,9 @@ const NewTimelineRow = memo( minWidth: `${percWidth.toFixed(6)}%`, width: `${percWidth.toFixed(6)}%`, marginLeft: `${percMarginLeft.toFixed(6)}%`, - ...eventStyles, + ...(typeof eventStyles === 'function' + ? eventStyles(e) + : eventStyles), }} >
@@ -166,7 +171,7 @@ function TimelineXAxis({ width: 1, marginRight: -1, marginLeft: i === 0 ? 0 : `${percSpacing.toFixed(6)}%`, - background: 'var(--color-bg-surface)', + background: 'var(--color-border-muted)', }} >
{renderMs(i * interval)}
@@ -179,10 +184,11 @@ function TimelineXAxis({ style={{ position: 'sticky', top: 0, - height: 4, + height: 24, paddingTop: 4, zIndex: 200, pointerEvents: 'none', + background: 'var(--color-bg-body)', }} >
@@ -242,8 +248,8 @@ function TimelineCursor({ >
{overlay} @@ -325,7 +331,7 @@ function TimelineMouseCursor({ overlay={renderMs(Math.max(cursorTime, 0))} height={height} labelWidth={labelWidth} - color="#ffffff88" + color="var(--color-bg-neutral)" /> ) : null; } @@ -590,13 +596,14 @@ export default function TimelineChart({ events={row.events} height={rowHeight} maxVal={maxVal} - eventStyles={{ + eventStyles={(event: TimelineEventT) => ({ borderRadius: 2, fontSize: rowHeight * 0.5, - border: '1px solid var(--color-border)', - backgroundColor: 'var(--color-bg-neutral)', - color: 'var(--color-text)', - }} + backgroundColor: event.isError + ? 'var(--color-bg-danger)' + : 'var(--color-bg-inverted)', + color: 'var(--color-text-inverted)', + })} scale={scale} offset={offset} /> diff --git a/packages/app/src/components/DBRowOverviewPanel.tsx b/packages/app/src/components/DBRowOverviewPanel.tsx index 68f1bb80..f20df47d 100644 --- a/packages/app/src/components/DBRowOverviewPanel.tsx +++ b/packages/app/src/components/DBRowOverviewPanel.tsx @@ -162,7 +162,7 @@ export function RowOverviewPanel({ return (
{!hideHeader && ( - + {isHttpRequest && ( diff --git a/packages/app/src/components/DBTracePanel.tsx b/packages/app/src/components/DBTracePanel.tsx index cf66819f..674fad46 100644 --- a/packages/app/src/components/DBTracePanel.tsx +++ b/packages/app/src/components/DBTracePanel.tsx @@ -182,6 +182,7 @@ export default function DBTracePanel({