Refactor: Remove bootstrap, adopt semantic tokens, and improve Mantine UI usage (#1347)

This commit is contained in:
Elizabet Oliveira 2025-11-14 18:01:54 +00:00 committed by GitHub
parent a7e150c825
commit af6a8d0dac
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
118 changed files with 2828 additions and 2070 deletions

View file

@ -0,0 +1,5 @@
---
"@hyperdx/app": minor
---
feat: Remove `bootstrap`, `react-bootstrap` and unused `react-bootstrap-range-slider`, adopt semantic tokens, and improve Mantine UI usage

View file

@ -50,7 +50,6 @@
"@uiw/codemirror-themes": "^4.23.3",
"@uiw/react-codemirror": "^4.23.3",
"@xyflow/react": "^12.9.0",
"bootstrap": "^5.1.3",
"chrono-node": "^2.7.8",
"classnames": "^2.3.1",
"crypto-js": "^4.2.0",
@ -76,8 +75,6 @@
"nuqs": "^1.17.0",
"object-hash": "^3.0.0",
"react": "18.3.1",
"react-bootstrap": "^2.4.0",
"react-bootstrap-range-slider": "^3.0.8",
"react-copy-to-clipboard": "^5.1.0",
"react-dom": "18.3.1",
"react-error-boundary": "^3.1.4",

View file

@ -5,7 +5,6 @@ import Head from 'next/head';
import { NextAdapter } from 'next-query-params';
import randomUUID from 'crypto-randomuuid';
import { enableMapSet } from 'immer';
import SSRProvider from 'react-bootstrap/SSRProvider';
import { QueryParamProvider } from 'use-query-params';
import HyperDX from '@hyperdx/browser';
import { ColorSchemeScript } from '@mantine/core';
@ -96,13 +95,11 @@ export default function MyApp({ Component, pageProps }: AppPropsWithLayout) {
}, []);
useEffect(() => {
document.documentElement.className =
userPreferences.theme === 'dark' ? 'hdx-theme-dark' : 'hdx-theme-light';
// TODO: Remove after migration to Mantine
document.body.style.fontFamily = userPreferences.font
? `"${userPreferences.font}", sans-serif`
: '"IBM Plex Mono"';
}, [userPreferences.theme, userPreferences.font]);
}, [userPreferences.font]);
const getLayout = Component.getLayout ?? (page => page);
@ -117,23 +114,26 @@ export default function MyApp({ Component, pageProps }: AppPropsWithLayout) {
/>
<meta name="theme-color" content="#25292e"></meta>
<meta name="google" content="notranslate" />
<ColorSchemeScript forceColorScheme="dark" />
<ColorSchemeScript
forceColorScheme={userPreferences.theme === 'dark' ? 'dark' : 'light'}
/>
</Head>
<SSRProvider>
<HDXQueryParamProvider>
<QueryParamProvider adapter={NextAdapter}>
<QueryClientProvider client={queryClient}>
<ThemeWrapper fontFamily={userPreferences.font}>
{getLayout(<Component {...pageProps} />)}
{confirmModal}
</ThemeWrapper>
<ReactQueryDevtools initialIsOpen={true} />
{background}
</QueryClientProvider>
</QueryParamProvider>
</HDXQueryParamProvider>
</SSRProvider>
<HDXQueryParamProvider>
<QueryParamProvider adapter={NextAdapter}>
<QueryClientProvider client={queryClient}>
<ThemeWrapper
fontFamily={userPreferences.font}
colorScheme={userPreferences.theme === 'dark' ? 'dark' : 'light'}
>
{getLayout(<Component {...pageProps} />)}
{confirmModal}
</ThemeWrapper>
<ReactQueryDevtools initialIsOpen={true} />
{background}
</QueryClientProvider>
</QueryParamProvider>
</HDXQueryParamProvider>
</React.Fragment>
);
}

View file

@ -58,7 +58,7 @@ function AlertHistoryCardList({ history }: { history: AlertHistory[] }) {
return (
<div className={styles.historyCardWrapper}>
{paddingItems.map((_, index) => (
<Tooltip label="No data" color="dark" withArrow key={index}>
<Tooltip label="No data" withArrow key={index}>
<div className={styles.historyCard} />
</Tooltip>
))}
@ -84,7 +84,7 @@ function AlertDetails({ alert }: { alert: AlertsPageItem }) {
{alert.dashboard?.name}
{tileName ? (
<>
<i className="bi bi-chevron-right fs-8 mx-1 text-slate-400" />
<i className="bi bi-chevron-right fs-8 mx-1 " />
{tileName}
</>
) : null}
@ -123,7 +123,7 @@ function AlertDetails({ alert }: { alert: AlertsPageItem }) {
<>
If value is {alert.thresholdType === 'above' ? 'over' : 'under'}{' '}
<span className="fw-bold">{alert.threshold}</span>
<span className="text-slate-400">&middot;</span>
<span>&middot;</span>
</>
);
}, [alert]);
@ -172,16 +172,16 @@ function AlertDetails({ alert }: { alert: AlertsPageItem }) {
className={styles.alertLink}
title={linkTitle}
>
<i className={`bi ${alertIcon} text-slate-200 me-2 fs-8`} />
<i className={`bi ${alertIcon} me-2 fs-8`} />
{alertName}
</Link>
</div>
<div className="text-slate-400 fs-8 d-flex gap-2">
<div className="fs-8 d-flex gap-2">
{alertType}
{notificationMethod}
{alert.createdBy && (
<>
<span className="text-slate-400">&middot;</span>
<span>&middot;</span>
<span>
Created by {alert.createdBy.name || alert.createdBy.email}
</span>
@ -219,7 +219,7 @@ function AlertCardList({ alerts }: { alerts: AlertsPageItem[] }) {
<i className="bi bi-check-lg"></i> OK
</div>
{okData.length === 0 && (
<div className="text-center text-slate-400 my-4 fs-8">No alerts</div>
<div className="text-center my-4 fs-8">No alerts</div>
)}
{okData.map((alert, index) => (
<AlertDetails key={index} alert={alert} />
@ -243,7 +243,7 @@ export default function AlertsPage() {
<div className="my-4">
<Container maw={1500}>
<Alert
icon={<i className="bi bi-info-circle-fill text-slate-400" />}
icon={<i className="bi bi-info-circle-fill " />}
color="gray"
py="xs"
mt="md"
@ -259,19 +259,15 @@ export default function AlertsPage() {
from dashboard charts and saved searches.
</Alert>
{isLoading ? (
<div className="text-center text-slate-400 my-4 fs-8">
Loading...
</div>
<div className="text-center my-4 fs-8">Loading...</div>
) : isError ? (
<div className="text-center text-slate-400 my-4 fs-8">Error</div>
<div className="text-center my-4 fs-8">Error</div>
) : alerts?.length ? (
<>
<AlertCardList alerts={alerts} />
</>
) : (
<div className="text-center text-slate-400 my-4 fs-8">
No alerts created yet
</div>
<div className="text-center my-4 fs-8">No alerts created yet</div>
)}
</Container>
</div>

View file

@ -33,10 +33,8 @@ export const AppNavContext = React.createContext<{
export const AppNavCloudBanner = () => {
return (
<div className="my-3 bg-hdx-dark rounded p-2 text-center">
<span className="text-slate-300 fs-8">
Ready to deploy on ClickHouse Cloud?
</span>
<div className="my-3 bg-muted rounded p-2 text-center">
<span className="fs-8">Ready to deploy on ClickHouse Cloud?</span>
<div className="mt-2 mb-2">
<Link
href="https://clickhouse.com/docs/use-cases/observability/clickstack/getting-started#deploy-with-clickhouse-cloud"
@ -84,16 +82,9 @@ export const AppNavUserMenu = ({
<Menu.Target>
<Paper
data-testid="user-menu-trigger"
m="sm"
mt={8}
px={8}
py={4}
radius="md"
{...(isCollapsed && {
p: 2,
bg: 'transparent',
className={cx(styles.userMenuTrigger, {
[styles.userMenuTriggerCollapsed]: isCollapsed,
})}
className={styles.appNavMenu}
>
<Group gap="xs" wrap="nowrap" miw={0}>
<Avatar size="sm" radius="xl" color="green">
@ -141,7 +132,7 @@ export const AppNavUserMenu = ({
</Text>
</div>
</Tooltip>
<Icon name="chevron-right" className="fs-8 text-slate-400" />
<Icon name="chevron-right" className="fs-8 " />
</>
)}
</Group>
@ -213,21 +204,13 @@ export const AppNavHelpMenu = ({
] = useDisclosure(false);
// const isTeamHasNoData = useIsTeamHasNoData();
const size = 28;
return (
<>
<Paper
mb={8}
ml="sm"
withBorder
w={size}
h={size}
radius="xl"
{...(isCollapsed && {
ml: 'sm',
className={cx(styles.helpMenuTrigger, {
[styles.helpMenuTriggerCollapsed]: isCollapsed,
})}
className={styles.appNavMenu}
>
<Menu
withArrow
@ -237,12 +220,7 @@ export const AppNavHelpMenu = ({
>
<Menu.Target>
<UnstyledButton data-testid="help-menu-trigger" w="100%">
<Group
align="center"
justify="center"
h={size}
className="text-slate-200 "
>
<Group align="center" justify="center" h={28}>
<Icon name="question-lg" />
</Group>
</UnstyledButton>
@ -251,7 +229,7 @@ export const AppNavHelpMenu = ({
<Menu.Label>
Help{' '}
{version && (
<Text size="xs" c="gray.7" component="span">
<Text size="xs" component="span">
v{version}
</Text>
)}
@ -295,7 +273,7 @@ export const AppNavHelpMenu = ({
export const AppNavLink = ({
className,
label,
iconName,
icon,
href,
isExpanded,
onToggle,
@ -303,7 +281,7 @@ export const AppNavLink = ({
}: {
className?: string;
label: React.ReactNode;
iconName: string;
icon: React.ReactNode;
href: string;
isExpanded?: boolean;
onToggle?: () => void;
@ -320,37 +298,26 @@ export const AppNavLink = ({
data-testid={testId}
href={href}
className={cx(
styles.listLink,
{ [styles.listLinkActive]: pathname?.includes(href) },
className,
'text-decoration-none d-flex justify-content-between align-items-center fs-7 text-muted-hover',
{ 'fw-600 text-success': pathname?.includes(href) },
)}
style={{ display: 'flex', alignItems: 'center' }}
>
<span>
<i className={`bi ${iconName} pe-2 text-slate-300`} />{' '}
{!isCollapsed && (
<span>
{label}
{isBeta && (
<Badge
size="xs"
ms="xs"
color="gray.4"
autoContrast
radius="sm"
className="align-text-bottom"
>
Beta
</Badge>
)}
</span>
)}
<span style={{ display: 'flex', alignItems: 'center' }}>
<span className={styles.linkIcon}>{icon}</span>
{!isCollapsed && <span>{label}</span>}
</span>
</Link>
{!isCollapsed && isBeta && (
<Badge size="xs" radius="sm" color="gray" style={{ marginRight: 8 }}>
Beta
</Badge>
)}
{!isCollapsed && onToggle && (
<ActionIcon
data-testid={`${testId}-toggle`}
variant="subtle"
color="dark.2"
size="sm"
onClick={onToggle}
>

View file

@ -13,6 +13,7 @@ import {
import HyperDX from '@hyperdx/browser';
import { AlertState } from '@hyperdx/common-utils/dist/types';
import {
ActionIcon,
Badge,
Box,
Button,
@ -24,6 +25,16 @@ import {
ScrollArea,
} from '@mantine/core';
import { useDisclosure, useLocalStorage } from '@mantine/hooks';
import {
IconBell,
IconChartDots,
IconDeviceLaptop,
IconLayoutGrid,
IconLayoutSidebarLeftCollapse,
IconSettings,
IconSitemap,
IconTable,
} from '@tabler/icons-react';
import {
useCreateDashboard,
@ -66,10 +77,10 @@ function NewDashboardButton() {
<Button
data-testid="create-dashboard-button"
variant="transparent"
color="var(--color-text)"
py="0px"
px="sm"
fw={400}
color="gray.2"
>
<span className="pe-2">+</span> Create Dashboard
</Button>
@ -81,10 +92,10 @@ function NewDashboardButton() {
<Button
data-testid="create-dashboard-button"
variant="transparent"
color="var(--color-text)"
py="0px"
px="sm"
fw={400}
color="gray.2"
onClick={() =>
createDashboard.mutate(
{
@ -144,7 +155,7 @@ function SearchInput({
placeholder={placeholder}
value={value}
onChange={e => onChange(e.currentTarget.value)}
leftSection={<i className="bi bi-search fs-8 ps-1 text-slate-400" />}
leftSection={<i className="bi bi-search fs-8 ps-1 " />}
onKeyDown={handleKeyDown}
rightSection={
value ? (
@ -461,8 +472,8 @@ export default function AppNav({ fixed = false }: { fixed?: boolean }) {
key={savedSearch.id}
tabIndex={0}
className={cx(
styles.listLink,
savedSearch.id === query.savedSearchId && styles.listLinkActive,
styles.nestedLink,
savedSearch.id === query.savedSearchId && styles.nestedLinkActive,
)}
title={savedSearch.name}
draggable
@ -524,8 +535,8 @@ export default function AppNav({ fixed = false }: { fixed?: boolean }) {
href={`/dashboards/${dashboard.id}`}
key={dashboard.id}
tabIndex={0}
className={cx(styles.listLink, {
[styles.listLinkActive]: dashboard.id === query.dashboardId,
className={cx(styles.nestedLink, {
[styles.nestedLinkActive]: dashboard.id === query.dashboardId,
})}
draggable
data-dashboardid={dashboard.id}
@ -606,7 +617,6 @@ export default function AppNav({ fixed = false }: { fixed?: boolean }) {
<Badge
size="xs"
color="gray"
bg="gray.8"
variant="light"
fw="normal"
title="Showing time in UTC"
@ -617,19 +627,16 @@ export default function AppNav({ fixed = false }: { fixed?: boolean }) {
</Group>
)}
</Link>
<Button
variant="subtle"
color="gray.4"
p={isCollapsed ? '0px' : '8px'}
h="32px"
size="md"
<ActionIcon
variant="transparent"
size="sm"
className={isCollapsed ? 'mt-4' : ''}
style={{ marginRight: -4 }}
style={{ marginRight: -4, marginLeft: -4 }}
title="Collapse/Expand Navigation"
onClick={() => setIsPreferCollapsed((v: boolean) => !v)}
>
<i className="bi bi-layout-sidebar"></i>
</Button>
<IconLayoutSidebarLeftCollapse size={16} />
</ActionIcon>
</div>
</div>
<ScrollArea
@ -647,7 +654,7 @@ export default function AppNav({ fixed = false }: { fixed?: boolean }) {
<div className="mt-2">
<AppNavLink
label="Search"
iconName="bi-layout-text-sidebar-reverse"
icon={<IconTable size={16} />}
href="/search"
className={cx({
'text-success fw-600':
@ -667,13 +674,7 @@ export default function AppNav({ fixed = false }: { fixed?: boolean }) {
<Collapse in={isSearchExpanded}>
<div className={styles.list}>
{isLogViewsLoading ? (
<Loader
color="gray.7"
variant="dots"
mx="md"
my="xs"
size="sm"
/>
<Loader variant="dots" mx="md" my="xs" size="sm" />
) : (
!IS_LOCAL_MODE && (
<>
@ -719,28 +720,32 @@ export default function AppNav({ fixed = false }: { fixed?: boolean }) {
<AppNavLink
label="Chart Explorer"
href="/chart"
iconName="bi-graph-up"
icon={<IconChartDots size={16} />}
/>
{!IS_LOCAL_MODE && (
<AppNavLink label="Alerts" href="/alerts" iconName="bi-bell" />
<AppNavLink
label="Alerts"
href="/alerts"
icon={<IconBell size={16} />}
/>
)}
<AppNavLink
label="Client Sessions"
href="/sessions"
iconName="bi-laptop"
icon={<IconDeviceLaptop size={16} />}
/>
<AppNavLink
label="Service Map"
href="/service-map"
iconName="bi-diagram-2-fill"
icon={<IconSitemap size={16} />}
isBeta
/>
<AppNavLink
label="Dashboards"
href="/dashboards"
iconName="bi-grid-1x2"
icon={<IconLayoutGrid size={16} />}
isExpanded={isDashboardsExpanded}
onToggle={() => setIsDashboardExpanded(!isDashboardsExpanded)}
/>
@ -751,13 +756,7 @@ export default function AppNav({ fixed = false }: { fixed?: boolean }) {
<NewDashboardButton />
{isDashboardsLoading ? (
<Loader
color="gray.7"
variant="dots"
mx="md"
my="xs"
size="sm"
/>
<Loader variant="dots" mx="md" my="xs" size="sm" />
) : (
!IS_LOCAL_MODE && (
<>
@ -811,8 +810,8 @@ export default function AppNav({ fixed = false }: { fixed?: boolean }) {
<Link
href={`/clickhouse`}
tabIndex={0}
className={cx(styles.listLink, {
[styles.listLinkActive]:
className={cx(styles.nestedLink, {
[styles.nestedLinkActive]:
pathname.startsWith('/clickhouse'),
})}
>
@ -821,8 +820,8 @@ export default function AppNav({ fixed = false }: { fixed?: boolean }) {
<Link
href={`/services`}
tabIndex={0}
className={cx(styles.listLink, {
[styles.listLinkActive]:
className={cx(styles.nestedLink, {
[styles.nestedLinkActive]:
pathname.startsWith('/services'),
})}
>
@ -832,8 +831,8 @@ export default function AppNav({ fixed = false }: { fixed?: boolean }) {
<Link
href={`/kubernetes`}
tabIndex={0}
className={cx(styles.listLink, {
[styles.listLinkActive]:
className={cx(styles.nestedLink, {
[styles.nestedLinkActive]:
pathname.startsWith('/kubernetes'),
})}
data-testid="k8s-dashboard-nav-link"
@ -851,7 +850,7 @@ export default function AppNav({ fixed = false }: { fixed?: boolean }) {
<AppNavLink
label="Team Settings"
href="/team"
iconName="bi-gear"
icon={<IconSettings size={16} />}
/>
</Box>
)}
@ -871,11 +870,9 @@ export default function AppNav({ fixed = false }: { fixed?: boolean }) {
</ScrollArea>
<div
className={styles.bottomSection}
style={{
width: navWidth,
position: 'absolute',
bottom: 0,
pointerEvents: 'none',
}}
>
<AppNavHelpMenu

View file

@ -124,10 +124,7 @@ export default function AuthPage({ action }: { action: 'register' | 'login' }) {
<LandingHeader activeKey={`/${action}`} fixed />
<div className="d-flex justify-content-center align-items-center vh-100">
<div style={{ width: '26rem' }}>
<div
className="text-center mb-2 fs-5 text-slate-300"
style={{ marginTop: -30 }}
>
<div className="text-center mb-2 fs-5 " style={{ marginTop: -30 }}>
{config.IS_OSS && isRegister
? 'Setup '
: isRegister
@ -136,7 +133,7 @@ export default function AuthPage({ action }: { action: 'register' | 'login' }) {
<span className="text-success fw-bold">HyperDX</span>
</div>
{action === 'login' && (
<div className="text-center mb-2 text-slate-300">Welcome back!</div>
<div className="text-center mb-2 ">Welcome back!</div>
)}
{isRegister && config.IS_OSS === true && (
<div className="text-center mb-2 text-muted">
@ -187,7 +184,7 @@ export default function AuthPage({ action }: { action: 'register' | 'login' }) {
placeholder="Confirm Password"
{...form.confirmPassword}
/>
<Notification color="gray.7" withCloseButton={false}>
<Notification withCloseButton={false}>
<PasswordCheck password={currentPassword} />
</Notification>
</>
@ -243,19 +240,13 @@ export default function AuthPage({ action }: { action: 'register' | 'login' }) {
)}
{isRegister && config.IS_OSS === false && (
<div
data-test-id="login-link"
className="text-center fs-8 text-slate-400"
>
<div data-test-id="login-link" className="text-center fs-8 ">
Already have an account? <Link href="/login">Log in</Link>{' '}
instead.
</div>
)}
{action === 'login' && config.IS_OSS === false && (
<div
data-test-id="register-link"
className="text-center fs-8 text-slate-400"
>
<div data-test-id="register-link" className="text-center fs-8 ">
Don{"'"}t have an account yet?{' '}
<Link href="/register">Register</Link> instead.
</div>

View file

@ -1,7 +1,6 @@
import { useEffect, useMemo, useRef, useState } from 'react';
import Fuse from 'fuse.js';
import { OverlayTrigger } from 'react-bootstrap';
import { Textarea, UnstyledButton } from '@mantine/core';
import { Popover, Textarea, UnstyledButton } from '@mantine/core';
import { useQueryHistory } from '@/utils';
@ -131,210 +130,198 @@ export default function AutocompleteInput({
const ref = useRef<HTMLDivElement>(null);
return (
<OverlayTrigger
rootClose
onToggle={opened => {
// if opened is transitioning to false, but input is focused, ignore it
if (!opened && isSearchInputFocused) {
return;
}
setIsInputDropdownOpen(opened);
<Popover
opened={isInputDropdownOpen}
onChange={setIsInputDropdownOpen}
position="bottom-start"
offset={8}
width="target"
withinPortal
closeOnClickOutside
closeOnEscape
styles={{
dropdown: {
maxWidth:
(inputRef.current?.clientWidth || 0) > 300
? inputRef.current?.clientWidth
: 720,
width: '100%',
zIndex,
},
}}
show={isInputDropdownOpen}
placement="bottom-start"
delay={{ show: 0, hide: 0 }}
overlay={({ style, ...props }) => (
<div
className="bg-body border border-dark rounded"
style={{
...style,
maxWidth:
(inputRef.current?.clientWidth || 0) > 300
? inputRef.current?.clientWidth
: 720,
width: '100%',
zIndex,
}}
{...props}
>
{aboveSuggestions != null && (
<div className="d-flex p-2 flex-wrap px-3">{aboveSuggestions}</div>
)}
<div>
{suggestedProperties.length > 0 && (
<div className="border-top border-dark fs-8 py-2">
<div className="d-flex justify-content-between px-3 mb-2">
<div className="me-2 text-light">{suggestionsHeader}</div>
{suggestedProperties.length > suggestionsLimit && (
<div className="text-muted">
(Showing Top {suggestionsLimit})
</div>
)}
</div>
{suggestedProperties
.slice(0, suggestionsLimit)
.map(({ value, label }, i) => (
<div
className={`py-2 px-3 ${
selectedAutocompleteIndex === i ? 'bg-hdx-dark' : ''
}`}
role="button"
key={value}
onMouseOver={() => {
setSelectedAutocompleteIndex(i);
}}
onClick={() => {
onAcceptSuggestion(value);
}}
>
<span className="me-1">{label}</span>
</div>
))}
</div>
)}
</div>
{belowSuggestions != null && (
<div className="border-top border-dark bg-body px-3 pt-2 pb-1 mt-2 fs-8 d-flex align-items-center text-muted flex-wrap">
{belowSuggestions}
</div>
)}
<div>
{showSearchHistory && (
<div className="border-top border-dark fs-8 py-2">
<div className="text-muted fs-8 fw-bold me-1 px-3">
Search History:
</div>
{queryHistoryList.map(({ value, label }, i) => {
return (
<UnstyledButton
className={`d-block w-100 text-start text-muted fw-normal px-3 py-2 fs-8 ${
selectedQueryHistoryIndex === i ? 'bg-hdx-dark' : ''
}`}
key={value}
onMouseOver={() => setSelectedQueryHistoryIndex(i)}
onClick={() => onSelectSearchHistory(value)}
>
<span className="me-1 text-truncate">{label}</span>
</UnstyledButton>
);
})}
</div>
)}
</div>
</div>
)}
popperConfig={{
modifiers: [
{
name: 'offset',
options: {
offset: [0, 8],
},
},
],
}}
trigger={[]}
>
<Textarea
ref={inputRef}
placeholder={placeholder}
className="fs-8"
value={value}
size={size}
autosize
minRows={1}
maxRows={4}
style={{
flexGrow: 1,
resize: 'none',
}}
data-testid={dataTestId}
onChange={e => onChange(e.target.value)}
onFocus={() => {
setSelectedAutocompleteIndex(-1);
setSelectedQueryHistoryIndex(-1);
setIsSearchInputFocused(true);
}}
onBlur={() => {
setSelectedAutocompleteIndex(-1);
setSelectedQueryHistoryIndex(-1);
setIsSearchInputFocused(false);
}}
onKeyDown={e => {
if (e.key === 'Escape' && e.target instanceof HTMLTextAreaElement) {
e.target.blur();
}
// Autocomplete Navigation/Acceptance Keys
if (e.key === 'Tab' && e.target instanceof HTMLTextAreaElement) {
if (
suggestedProperties.length > 0 &&
selectedAutocompleteIndex < suggestedProperties.length &&
selectedAutocompleteIndex >= 0
) {
<Popover.Target>
<Textarea
ref={inputRef}
placeholder={placeholder}
className="fs-8"
value={value}
size={size}
autosize
minRows={1}
maxRows={4}
style={{
flexGrow: 1,
resize: 'none',
}}
data-testid={dataTestId}
onChange={e => onChange(e.target.value)}
onFocus={() => {
setSelectedAutocompleteIndex(-1);
setSelectedQueryHistoryIndex(-1);
setIsSearchInputFocused(true);
}}
onBlur={() => {
setSelectedAutocompleteIndex(-1);
setSelectedQueryHistoryIndex(-1);
setIsSearchInputFocused(false);
}}
onKeyDown={e => {
if (e.key === 'Escape' && e.target instanceof HTMLTextAreaElement) {
e.preventDefault();
onAcceptSuggestion(
suggestedProperties[selectedAutocompleteIndex].value,
);
setIsInputDropdownOpen(false);
e.target.blur();
}
}
if (e.key === 'Enter' && e.target instanceof HTMLTextAreaElement) {
if (
suggestedProperties.length > 0 &&
selectedAutocompleteIndex < suggestedProperties.length &&
selectedAutocompleteIndex >= 0
) {
e.preventDefault();
onAcceptSuggestion(
suggestedProperties[selectedAutocompleteIndex].value,
);
} else {
// Allow shift+enter to still create new lines
if (!e.shiftKey) {
// Autocomplete Navigation/Acceptance Keys
if (e.key === 'Tab' && e.target instanceof HTMLTextAreaElement) {
if (
suggestedProperties.length > 0 &&
selectedAutocompleteIndex < suggestedProperties.length &&
selectedAutocompleteIndex >= 0
) {
e.preventDefault();
if (queryHistoryType && value) {
setQueryHistory(value);
}
onSubmit?.();
onAcceptSuggestion(
suggestedProperties[selectedAutocompleteIndex].value,
);
}
}
}
if (
e.key === 'ArrowDown' &&
e.target instanceof HTMLTextAreaElement
) {
if (suggestedProperties.length > 0) {
setSelectedAutocompleteIndex(
Math.min(
selectedAutocompleteIndex + 1,
suggestedProperties.length - 1,
suggestionsLimit - 1,
),
);
if (e.key === 'Enter' && e.target instanceof HTMLTextAreaElement) {
if (
suggestedProperties.length > 0 &&
selectedAutocompleteIndex < suggestedProperties.length &&
selectedAutocompleteIndex >= 0
) {
e.preventDefault();
onAcceptSuggestion(
suggestedProperties[selectedAutocompleteIndex].value,
);
} else {
// Allow shift+enter to still create new lines
if (!e.shiftKey) {
e.preventDefault();
if (queryHistoryType && value) {
setQueryHistory(value);
}
onSubmit?.();
}
}
}
}
if (e.key === 'ArrowUp' && e.target instanceof HTMLTextAreaElement) {
if (suggestedProperties.length > 0) {
setSelectedAutocompleteIndex(
Math.max(selectedAutocompleteIndex - 1, 0),
);
if (
e.key === 'ArrowDown' &&
e.target instanceof HTMLTextAreaElement
) {
if (suggestedProperties.length > 0) {
setSelectedAutocompleteIndex(
Math.min(
selectedAutocompleteIndex + 1,
suggestedProperties.length - 1,
suggestionsLimit - 1,
),
);
}
}
if (
e.key === 'ArrowUp' &&
e.target instanceof HTMLTextAreaElement
) {
if (suggestedProperties.length > 0) {
setSelectedAutocompleteIndex(
Math.max(selectedAutocompleteIndex - 1, 0),
);
}
}
}}
rightSectionWidth={ref.current?.clientWidth ?? 'auto'}
rightSection={
language != null && onLanguageChange != null ? (
<div ref={ref}>
<InputLanguageSwitch
showHotkey={showHotkey && isSearchInputFocused}
language={language}
onLanguageChange={onLanguageChange}
/>
</div>
) : undefined
}
}}
rightSectionWidth={ref.current?.clientWidth ?? 'auto'}
rightSection={
language != null && onLanguageChange != null ? (
<div ref={ref}>
<InputLanguageSwitch
showHotkey={showHotkey && isSearchInputFocused}
language={language}
onLanguageChange={onLanguageChange}
/>
/>
</Popover.Target>
<Popover.Dropdown className="p-0">
{aboveSuggestions != null && (
<div className="d-flex p-2 flex-wrap px-3">{aboveSuggestions}</div>
)}
<div>
{suggestedProperties.length > 0 && (
<div className="border-top border-dark fs-8 py-2">
<div className="d-flex justify-content-between px-3 mb-2">
<div className="me-2 text-light">{suggestionsHeader}</div>
{suggestedProperties.length > suggestionsLimit && (
<div className="text-muted">
(Showing Top {suggestionsLimit})
</div>
)}
</div>
{suggestedProperties
.slice(0, suggestionsLimit)
.map(({ value, label }, i) => (
<div
className={`py-2 px-3 ${
selectedAutocompleteIndex === i ? 'bg-muted' : ''
}`}
role="button"
key={value}
onMouseOver={() => {
setSelectedAutocompleteIndex(i);
}}
onClick={() => {
onAcceptSuggestion(value);
}}
>
<span className="me-1">{label}</span>
</div>
))}
</div>
) : undefined
}
/>
</OverlayTrigger>
)}
</div>
{belowSuggestions != null && (
<div className="border-top px-3 pt-2 pb-1 fs-8 d-flex align-items-center text-muted flex-wrap">
{belowSuggestions}
</div>
)}
<div>
{showSearchHistory && (
<div className="border-top border-dark fs-8 py-2">
<div className="text-muted fs-8 fw-bold me-1 px-3">
Search History:
</div>
{queryHistoryList.map(({ value, label }, i) => {
return (
<UnstyledButton
className={`d-block w-100 text-start text-muted fw-normal px-3 py-2 fs-8 ${
selectedQueryHistoryIndex === i ? 'bg-muted' : ''
}`}
key={value}
onMouseOver={() => setSelectedQueryHistoryIndex(i)}
onClick={() => onSelectSearchHistory(value)}
>
<span className="me-1 text-truncate">{label}</span>
</UnstyledButton>
);
})}
</div>
)}
</div>
</Popover.Dropdown>
</Popover>
);
}

View file

@ -235,9 +235,7 @@ function BenchmarkPage() {
<Grid>
<Grid.Col span={6}>
<Stack>
<Text size="lg" c="gray.4">
Query 1
</Text>
<Text size="lg">Query 1</Text>
<ConnectionSelectControlled
control={control}
name="connections.0"
@ -247,9 +245,7 @@ function BenchmarkPage() {
</Grid.Col>
<Grid.Col span={6}>
<Stack>
<Text size="lg" c="gray.4">
Query 2
</Text>
<Text size="lg">Query 2</Text>
<ConnectionSelectControlled
control={control}
name="connections.1"
@ -270,12 +266,8 @@ function BenchmarkPage() {
<Grid mt="md">
<Grid.Col span={12}>
<Stack>
<Text size="lg" c="gray.2">
Query Estimate & Indexes
</Text>
<Text c="gray.4" size="sm">
Index utilization of your query
</Text>
<Text size="lg">Query Estimate & Indexes</Text>
<Text size="sm">Index utilization of your query</Text>
</Stack>
</Grid.Col>
<Grid.Col span={6}>

View file

@ -59,7 +59,7 @@ function InfrastructureTab({
<Grid mt="md">
<Grid.Col span={6}>
<ChartBox style={{ minHeight: 400 }}>
<Text size="sm" c="gray.4" mb="sm">
<Text size="sm" mb="sm">
CPU Usage (Cores)
</Text>
<DBTimeChart
@ -86,7 +86,7 @@ function InfrastructureTab({
</Grid.Col>
<Grid.Col span={6}>
<ChartBox style={{ minHeight: 400 }}>
<Text size="sm" c="gray.4" mb="sm">
<Text size="sm" mb="sm">
Memory Usage
</Text>
<DBTimeChart
@ -112,7 +112,7 @@ function InfrastructureTab({
</Grid.Col>
<Grid.Col span={6}>
<ChartBox style={{ minHeight: 400 }}>
<Text size="sm" c="gray.4" mb="sm">
<Text size="sm" mb="sm">
Disk
</Text>
<DBTimeChart
@ -146,7 +146,7 @@ function InfrastructureTab({
</Grid.Col>
<Grid.Col span={6}>
<ChartBox style={{ minHeight: 400 }}>
<Text size="sm" c="gray.4" mb="sm">
<Text size="sm" mb="sm">
S3 Requests
</Text>
<DBTimeChart
@ -198,10 +198,10 @@ function InfrastructureTab({
</Grid.Col>
<Grid.Col span={6}>
<ChartBox style={{ minHeight: 400 }}>
<Text size="sm" c="gray.4" mb="xs">
<Text size="sm" mb="xs">
Network
</Text>
<Text size="xs" c="gray.4" mb="sm">
<Text size="xs" mb="sm">
Network activity for the entire machine, not only Clickhouse.
</Text>
<DBTimeChart
@ -249,7 +249,7 @@ function InsertsTab({
<Grid.Col span={12}>
<ChartBox style={{ minHeight: 400 }}>
<Group justify="space-between" align="center" mb="sm">
<Text size="sm" c="gray.4">
<Text size="sm">
Insert{' '}
{insertsBy === 'queries'
? 'Queries'
@ -323,9 +323,7 @@ function InsertsTab({
<Grid.Col span={12}>
<ChartBox style={{ minHeight: 200, height: 200 }}>
<Group justify="space-between" align="center" mb="sm">
<Text size="sm" c="gray.4">
Max Active Parts per Partition
</Text>
<Text size="sm">Max Active Parts per Partition</Text>
</Group>
<DBTimeChart
config={{
@ -355,10 +353,10 @@ function InsertsTab({
</Grid.Col>
<Grid.Col span={12}>
<ChartBox style={{ height: 400 }}>
<Text size="sm" c="gray.4" mb="sm">
<Text size="sm" mb="sm">
Active Parts Per Partition
</Text>
<Text size="xs" c="gray.4" mb="md">
<Text size="xs" mb="md">
Recommended to stay under 300, ClickHouse will automatically
throttle inserts after 1,000 parts per partition and stop inserts at
3,000 parts per partition.
@ -499,9 +497,7 @@ function ClickhousePage() {
<OnboardingModal requireSource={false} />
<Group justify="space-between">
<Group>
<Text c="gray.4" size="xl">
Clickhouse Dashboard
</Text>
<Text size="xl">Clickhouse Dashboard</Text>
<ConnectionSelectControlled
control={control}
name="connection"
@ -557,7 +553,7 @@ function ClickhousePage() {
{/* <Grid.Col span={12}>
<ChartBox style={{ minHeight: 300, height: 300 }}>
<Group justify="space-between" align="center" mb="md">
<Text size="sm" c="gray.4" ms="xs">
<Text size="sm" ms="xs">
Select P95 Query Latency
</Text>
<SegmentedControl
@ -600,14 +596,13 @@ function ClickhousePage() {
<Grid.Col span={12}>
<ChartBox style={{ height: 250 }}>
<Flex justify="space-between" align="center">
<Text size="sm" c="gray.4" ms="xs">
<Text size="sm" ms="xs">
Query Latency
</Text>
{latencyFilter.latencyMin != null ||
latencyFilter.latencyMax != null ? (
<Button
size="xs"
color="gray.4"
variant="subtle"
onClick={() => {
// Clears the min/max latency filters that are used to filter the query results
@ -657,7 +652,7 @@ function ClickhousePage() {
</Grid.Col>
<Grid.Col span={12}>
<ChartBox style={{ height: 400 }}>
<Text size="sm" c="gray.4" mb="md">
<Text size="sm" mb="md">
Query Count by Table
</Text>
@ -698,7 +693,7 @@ function ClickhousePage() {
</Grid.Col>
<Grid.Col span={12}>
<ChartBox style={{ height: 400 }}>
<Text size="sm" c="gray.4" mb="md">
<Text size="sm" mb="md">
Most Time Consuming Query Patterns
</Text>
<DBTableChart
@ -756,7 +751,7 @@ function ClickhousePage() {
</Grid.Col>
<Grid.Col span={12}>
<ChartBox style={{ height: 400 }}>
<Text size="sm" c="gray.4" mb="md">
<Text size="sm" mb="md">
Slowest Queries
</Text>
<DBSqlRowTable

View file

@ -1,7 +1,7 @@
import { useState } from 'react';
import cx from 'classnames';
import { Button } from 'react-bootstrap';
import { CopyToClipboard } from 'react-copy-to-clipboard';
import { Button } from '@mantine/core';
export default function Clipboard({
text,
@ -23,8 +23,11 @@ export default function Clipboard({
}}
>
<Button
variant="link"
className={cx('px-0 text-decoration-none fs-7', className)}
variant="default"
p={0}
className={cx('text-decoration-none', className)}
size="xs"
fullWidth
>
{children({ isCopied })}
</Button>

View file

@ -119,14 +119,14 @@ function AIAssistant({
return (
<Box mb="sm">
<Alert
color="dark.3"
color="dark"
icon={<i className="bi bi-info-circle" />}
variant="outline"
withCloseButton
onClose={() => setAlertDismissed(true)}
p="xxs"
>
<Text size="xs" c="dark.2" pt="2px">
<Text size="xs" pt="2px">
New AI Assistant available, enable with configuring the{' '}
<code>ANTHROPIC_API_KEY</code> environment variable on the HyperDX
server.
@ -223,7 +223,7 @@ function DBChartExplorerPage() {
);
return (
<Box data-testid="chart-explorer-page" p="sm" className="bg-hdx-dark">
<Box data-testid="chart-explorer-page" p="sm">
<Head>
<title>Chart Explorer - HyperDX</title>
</Head>

View file

@ -3,7 +3,6 @@ import dynamic from 'next/dynamic';
import Head from 'next/head';
import { useRouter } from 'next/router';
import { filter } from 'lodash';
import { Container } from 'react-bootstrap';
import { Controller, useForm } from 'react-hook-form';
import { StringParam, useQueryParam } from 'use-query-params';
import { z } from 'zod';
@ -13,6 +12,7 @@ import { DashboardTemplateSchema } from '@hyperdx/common-utils/dist/types';
import {
Button,
Collapse,
Container,
Group,
Input,
Stack,
@ -110,21 +110,21 @@ function FileSelection({
<Dropzone.Accept>
<IconUpload
size={52}
color="var(--mantine-color-green-4)"
color="var(--color-text-success)"
stroke={1.5}
/>
</Dropzone.Accept>
<Dropzone.Reject>
<IconX
size={52}
color="var(--mantine-color-red-6)"
color="var(--color-text-danger)"
stroke={1.5}
/>
</Dropzone.Reject>
<Dropzone.Idle>
<IconFile
size={52}
color="var(--mantine-color-dimmed)"
color="var(--color-text-muted)"
stroke={1.5}
/>
</Dropzone.Idle>

View file

@ -45,7 +45,7 @@ import {
} from '@mantine/core';
import { useHover } from '@mantine/hooks';
import { notifications } from '@mantine/notifications';
import { IconFilterEdit } from '@tabler/icons-react';
import { IconFilterEdit, IconPlayerPlay } from '@tabler/icons-react';
import { ContactSupportText } from '@/components/ContactSupportText';
import EditTimeChartForm from '@/components/DBEditTimeChartForm';
@ -212,7 +212,7 @@ const Tile = forwardRef(
return (
<div
data-testid={`dashboard-tile-${chart.id}`}
className={`p-2 ${className} d-flex flex-column ${
className={`p-2 ${className} d-flex flex-column bg-muted rounded ${
isHighlighed && 'dashboard-chart-highlighted'
}`}
id={`chart-${chart.id}`}
@ -221,9 +221,6 @@ const Tile = forwardRef(
key={chart.id}
ref={ref}
style={{
background:
'linear-gradient(180deg, rgba(250,250,250,0.018) 0%, rgba(250,250,250,0.008) 100%)',
borderRadius: 2,
...style,
}}
onMouseDown={onMouseDown}
@ -231,7 +228,7 @@ const Tile = forwardRef(
onTouchEnd={onTouchEnd}
>
<div className="d-flex justify-content-between align-items-center mb-2 cursor-grab">
<Text size="sm" c="gray.2" ms="xs">
<Text size="sm" ms="xs">
{chart.config.name}
</Text>
{hovered ? (
@ -241,15 +238,13 @@ const Tile = forwardRef(
size={5}
zIndex={1}
color={alertIndicatorColor}
label={
!alert && <span className="text-slate-400 fs-8">+</span>
}
label={!alert && <span className="fs-8">+</span>}
mr={4}
>
<Button
data-testid={`tile-alerts-button-${chart.id}`}
variant="subtle"
color="gray.4"
color="gray"
size="xxs"
onClick={onEditClick}
title="Alerts"
@ -262,7 +257,7 @@ const Tile = forwardRef(
<Button
data-testid={`tile-duplicate-button-${chart.id}`}
variant="subtle"
color="gray.4"
color="gray"
size="xxs"
onClick={onDuplicateClick}
title="Duplicate"
@ -272,8 +267,8 @@ const Tile = forwardRef(
<Button
data-testid={`tile-edit-button-${chart.id}`}
variant="subtle"
color="gray"
size="xxs"
color="gray.4"
onClick={onEditClick}
title="Edit"
>
@ -282,8 +277,8 @@ const Tile = forwardRef(
<Button
data-testid={`tile-delete-button-${chart.id}`}
variant="subtle"
color="gray"
size="xxs"
color="gray.4"
onClick={onDeleteClick}
title="Delete"
>
@ -481,7 +476,6 @@ function DashboardName({
ms="xs"
variant="subtle"
size="xs"
color="gray.4"
onClick={() => setEditing(true)}
>
<i className="bi bi-pencil"></i>
@ -882,7 +876,7 @@ function DBDashboardPage({ presetConfig }: { presetConfig?: Dashboard }) {
{IS_LOCAL_MODE === false && isLocalDashboard && isLocalDashboardEmpty && (
<Paper my="lg" p="md">
<Flex justify="space-between" align="center">
<Text c="gray.4" size="sm">
<Text size="sm">
This is a temporary dashboard and can not be saved.
</Text>
<Button
@ -917,8 +911,7 @@ function DBDashboardPage({ presetConfig }: { presetConfig?: Dashboard }) {
onChange={handleUpdateTags}
>
<Button
variant="outline"
color="dark.2"
variant="default"
px="xs"
size="xs"
style={{ flexShrink: 0 }}
@ -932,7 +925,7 @@ function DBDashboardPage({ presetConfig }: { presetConfig?: Dashboard }) {
{!isLocalDashboard /* local dashboards cant be "deleted" */ && (
<Menu width={250}>
<Menu.Target>
<Button variant="outline" color="dark.2" px="xs" size="xs">
<Button variant="default" px="xs" size="xs">
<i className="bi bi-three-dots-vertical" />
</Button>
</Menu.Target>
@ -993,7 +986,7 @@ function DBDashboardPage({ presetConfig }: { presetConfig?: Dashboard }) {
</Menu>
)}
</Group>
{/* <Button variant="outline" color="gray.4" size="sm">
{/* <Button variant="outline" size="sm">
Save
</Button> */}
</Flex>
@ -1058,10 +1051,9 @@ function DBDashboardPage({ presetConfig }: { presetConfig?: Dashboard }) {
>
<Button
onClick={() => setIsLive(prev => !prev)}
color={isLive ? 'green' : 'gray'}
mr={6}
size="sm"
variant="outline"
variant={isLive ? 'filled' : 'default'}
title={isLive ? 'Disable auto-refresh' : 'Enable auto-refresh'}
>
Live
@ -1072,9 +1064,8 @@ function DBDashboardPage({ presetConfig }: { presetConfig?: Dashboard }) {
onClick={refresh}
loading={manualRefreshCooloff}
disabled={manualRefreshCooloff}
color="gray"
mr={6}
variant="outline"
variant="default"
title="Refresh dashboard"
px="xs"
>
@ -1083,8 +1074,7 @@ function DBDashboardPage({ presetConfig }: { presetConfig?: Dashboard }) {
</Tooltip>
<Tooltip withArrow label="Edit Filters" fz="xs" color="gray">
<Button
variant="outline"
color="gray"
variant="default"
px="xs"
mr={6}
onClick={() => setShowFiltersModal(true)}
@ -1092,8 +1082,12 @@ function DBDashboardPage({ presetConfig }: { presetConfig?: Dashboard }) {
<IconFilterEdit strokeWidth={1} />
</Button>
</Tooltip>
<Button variant="outline" type="submit" color="green">
<i className="bi bi-play"></i>
<Button
data-testid="search-submit-button"
variant="outline"
type="submit"
>
<IconPlayerPlay size={16} />
</Button>
</Flex>
<DashboardFilters
@ -1157,7 +1151,7 @@ function DBDashboardPage({ presetConfig }: { presetConfig?: Dashboard }) {
data-testid="add-new-tile-button"
variant="outline"
mt="sm"
color={dashboard?.tiles.length === 0 ? 'green' : 'dark.3'}
color={dashboard?.tiles.length === 0 ? 'green' : 'gray'}
fw={400}
onClick={onAddTile}
w="100%"

View file

@ -57,6 +57,7 @@ import {
useDocumentVisibility,
} from '@mantine/hooks';
import { notifications } from '@mantine/notifications';
import { IconPlayerPlay } from '@tabler/icons-react';
import { useIsFetching } from '@tanstack/react-query';
import { SortingState } from '@tanstack/react-table';
import CodeMirror from '@uiw/react-codemirror';
@ -177,7 +178,7 @@ function SearchNumRows({
const numRows = data?.[0]?.rows;
return (
<Text size="xs" c="gray.4" mb={4}>
<Text size="xs" mb={4}>
{isLoading
? 'Scanned Rows ...'
: error || !numRows
@ -307,44 +308,36 @@ function SaveSearchModal({
<Stack>
{chartConfig != null ? (
<Card withBorder>
<Text c="gray.4" size="xs" mb="xs">
<Text size="xs" mb="xs">
SELECT
</Text>
<Text
mb="sm"
size="xs"
c="gray.2"
>{`${chartConfig.select}`}</Text>
<Text c="gray.4" size="xs" mb="xs">
<Text mb="sm" size="xs">{`${chartConfig.select}`}</Text>
<Text size="xs" mb="xs">
FROM
</Text>
<Text mb="sm" size="xs" c="gray.2">
<Text mb="sm" size="xs">
{chartConfig?.from.databaseName}.{chartConfig?.from.tableName}
</Text>
<Text c="gray.4" size="xs" mb="xs">
<Text size="xs" mb="xs">
WHERE
</Text>
{chartConfig.where ? (
<Text size="xs" c="gray.2">
{chartConfig.where}
</Text>
<Text size="xs">{chartConfig.where}</Text>
) : (
<Text size="xxs" c="gray.4" fs="italic">
<Text size="xxs" fs="italic">
None
</Text>
)}
<Text c="gray.4" size="xs" mb="xs" mt="sm">
<Text size="xs" mb="xs" mt="sm">
ORDER BY
</Text>
<Text size="xs" c="gray.2">
{chartConfig.orderBy}
</Text>
<Text size="xs">{chartConfig.orderBy}</Text>
</Card>
) : (
<Text c="gray.4">Loading Chart Config...</Text>
<Text>Loading Chart Config...</Text>
)}
<Box>
<Text c="gray.4" size="xs" mb="xs">
<Text size="xs" mb="xs">
Name
</Text>
<InputControlled
@ -355,7 +348,7 @@ function SaveSearchModal({
/>
</Box>
<Box mb="sm">
<Text c="gray.4" size="xs" mb="xs">
<Text size="xs" mb="xs">
Tags
</Text>
<Group gap="xs" align="center" mb="xs">
@ -1312,7 +1305,6 @@ function DBSearchPage() {
<ActionIcon
data-testid="source-settings-menu"
variant="subtle"
color="dark.2"
size="sm"
title="Edit Source"
>
@ -1381,9 +1373,7 @@ function DBSearchPage() {
{!savedSearchId ? (
<Button
data-testid="save-search-button"
variant="outline"
color="dark.2"
px="xs"
variant="default"
size="xs"
onClick={onSaveSearch}
style={{ flexShrink: 0 }}
@ -1393,9 +1383,7 @@ function DBSearchPage() {
) : (
<Button
data-testid="update-search-button"
variant="outline"
color="dark.2"
px="xs"
variant="default"
size="xs"
onClick={() => {
setSaveSearchModalState('update');
@ -1408,9 +1396,7 @@ function DBSearchPage() {
{!IS_LOCAL_MODE && (
<Button
data-testid="alerts-button"
variant="outline"
color="dark.2"
px="xs"
variant="default"
size="xs"
onClick={openAlertModal}
style={{ flexShrink: 0 }}
@ -1427,8 +1413,7 @@ function DBSearchPage() {
>
<Button
data-testid="tags-button"
variant="outline"
color="dark.2"
variant="default"
px="xs"
size="xs"
style={{ flexShrink: 0 }}
@ -1551,9 +1536,9 @@ function DBSearchPage() {
data-testid="search-submit-button"
variant="outline"
type="submit"
color={formState.isDirty ? 'green' : 'gray.4'}
color={formState.isDirty ? 'var(--color-text-success)' : 'gray'}
>
<i className="bi bi-play"></i>
<IconPlayerPlay size={16} />
</Button>
</Flex>
</form>
@ -1570,12 +1555,12 @@ function DBSearchPage() {
<Flex
direction="column"
style={{ overflow: 'hidden', height: '100%' }}
className="bg-hdx-dark"
className="bg-body"
>
{!queryReady ? (
<Paper shadow="xs" p="xl" h="100%">
<Center mih={100} h="100%">
<Text size="sm" c="gray.4">
<Text size="sm">
Please start by selecting a database, table, and timestamp
column above to view data.
</Text>

View file

@ -56,7 +56,7 @@ const SavedSearchAlertFormSchema = z
.passthrough();
const CHANNEL_ICONS = {
webhook: <i className="bi bi-slack fs-7 text-slate-400" />,
webhook: <i className="bi bi-slack fs-7 " />,
};
const AlertForm = ({
@ -106,7 +106,7 @@ const AlertForm = ({
return (
<form onSubmit={handleSubmit(onSubmit)}>
<Stack gap="xs">
<Paper px="md" py="sm" bg="dark.6" radius="xs">
<Paper px="md" py="sm" radius="xs">
<Text size="xxs" opacity={0.5}>
Trigger
</Text>
@ -158,7 +158,7 @@ const AlertForm = ({
size="xs"
/>
</Paper>
<Paper px="md" py="sm" bg="dark.6" radius="xs">
<Paper px="md" py="sm" radius="xs">
<Text size="xxs" opacity={0.5} mb={4}>
Send to
</Text>
@ -166,8 +166,8 @@ const AlertForm = ({
</Paper>
{groupBy && thresholdType === AlertThresholdType.BELOW && (
<MantineAlert
icon={<i className="bi bi-info-circle-fill text-slate-400" />}
bg="dark.6"
icon={<i className="bi bi-info-circle-fill " />}
bg="dark"
py="xs"
>
<Text size="sm" opacity={0.7}>
@ -202,7 +202,7 @@ const AlertForm = ({
</Accordion>
{defaultValues?.createdBy && (
<Paper px="md" py="sm" bg="dark.6" radius="xs" mt="sm">
<Paper px="md" py="sm" radius="xs" mt="sm">
<Text size="xxs" opacity={0.5} mb={4}>
Created by
</Text>
@ -390,7 +390,7 @@ export const DBSearchPageAlertModal = ({
/>
<Stack gap={0} mb="md">
<Group>
<Text c="dark.1" size="sm">
<Text size="sm">
Alerts for <strong>{savedSearch?.name}</strong>
</Text>
{!id && (
@ -403,9 +403,7 @@ export const DBSearchPageAlertModal = ({
/>
)}
</Group>
<Text c="dark.2" size="xxs">
{savedSearch?.where}
</Text>
<Text size="xxs">{savedSearch?.where}</Text>
</Stack>
<Tabs value={activeIndex} onChange={setTab} mb="xs">
@ -419,10 +417,7 @@ export const DBSearchPageAlertModal = ({
))}
<Tabs.Tab value="stage">
<Group gap={4}>
<i
className="bi bi-plus fs-5 text-slate-400"
style={{ marginLeft: -8 }}
/>
<i className="bi bi-plus fs-5 " style={{ marginLeft: -8 }} />
New Alert
</Group>
</Tabs.Tab>

View file

@ -90,14 +90,12 @@ function DBServiceMapPage() {
<Box
data-testid="service-map-page"
p="sm"
className="bg-hdx-dark"
className="bg-body"
style={{ display: 'flex', flexDirection: 'column', height: '100vh' }}
>
<Group mb="md" justify="space-between">
<Group>
<Text c="gray.4" size="xl">
Service Map
</Text>
<Text size="xl">Service Map</Text>
<SourceSelectControlled
control={control}
name="source"
@ -109,7 +107,7 @@ function DBServiceMapPage() {
/>
</Group>
<Group justify="flex-end">
<Text c="gray.4" bg="inherit" size="sm">
<Text bg="inherit" size="sm">
Sampling {samplingLabel}
</Text>
<div style={{ minWidth: '200px' }}>

View file

@ -43,13 +43,13 @@ const URLHoverCard = memo(({ url }: { url: string }) => {
<table className="table fs-8 mb-0">
<tr>
<td>
<i className="bi bi-globe fs-8 text-slate-300"></i>
<i className="bi bi-globe fs-8 "></i>
</td>
<td>{parsedUrl?.host}</td>
</tr>
<tr>
<td>
<i className="bi bi-link-45deg text-slate-300 fs-7"></i>
<i className="bi bi-link-45deg fs-7"></i>
</td>
<td>{parsedUrl?.pathname}</td>
</tr>
@ -470,7 +470,7 @@ export default function DOMPlayer({
<ActionIcon
onClick={() => setPlayerFullWidth(!playerFullWidth)}
size="sm"
color="gray.7"
color="gray"
>
{playerFullWidth ? (
<i className="bi bi-list"></i>

View file

@ -191,7 +191,7 @@ const DashboardFilterEditForm = ({
</CustomInputWrapper>
<Group justify="flex-end" my="xs">
<Button variant="outline" color="gray.2" onClick={onCancel}>
<Button variant="default" onClick={onCancel}>
Cancel
</Button>
<Button type="submit">Save filter</Button>
@ -218,7 +218,7 @@ const EmptyState = ({ onCreateFilter, onClose }: EmptyStateProps) => {
Add filters to let users quickly narrow data on key columns. Saved
filters will stay with this dashboard.
</Text>
<Button variant="outline" color="gray.2" onClick={onCreateFilter}>
<Button variant="filled" onClick={onCreateFilter}>
Add new filter
</Button>
</Stack>
@ -258,9 +258,9 @@ const DashboardFiltersList = ({
<Paper
key={filter.id}
withBorder
bg={'dark.5'}
className={styles.filterPaper}
p="xs"
variant="muted"
>
<Group justify="space-between" className={styles.filterHeader}>
<Text size="xs">{filter.name}</Text>
@ -296,7 +296,7 @@ const DashboardFiltersList = ({
</Stack>
<Group justify="center" my="sm">
<Button variant="outline" color="gray.2" onClick={onAddNew}>
<Button variant="filled" onClick={onAddNew}>
Add new filter
</Button>
</Group>

View file

@ -196,17 +196,16 @@ export const Table = ({
);
return (
<div
className="overflow-auto h-100 fs-8 bg-inherit dark:bg-dark"
ref={tableContainerRef}
>
<table className="w-100 bg-inherit" style={{ tableLayout: 'fixed' }}>
<div className="overflow-auto h-100 fs-8" ref={tableContainerRef}>
<table
className="w-100"
style={{ tableLayout: 'fixed', borderCollapse: 'collapse' }}
>
<thead
className="bg-inherit"
style={{
background: 'inherit',
position: 'sticky',
top: 0,
background: 'var(--color-bg-body)',
}}
>
{table.getHeaderGroups().map(headerGroup => (
@ -229,7 +228,7 @@ export const Table = ({
<CsvExportButton
data={csvData}
filename="HyperDX_table_results"
className="fs-8 text-muted-hover ms-2"
className="fs-8 ms-2"
title="Download table as CSV"
>
<i className="bi bi-download" />
@ -255,7 +254,7 @@ export const Table = ({
return (
<tr
key={virtualRow.key}
className="bg-default-dark-grey-hover"
className="bg-muted-hover"
data-index={virtualRow.index}
ref={rowVirtualizer.measureElement}
>

View file

@ -476,10 +476,7 @@ export const MemoChart = memo(function MemoChart({
})}
</defs>
{isHovered && (
<CartesianGrid
strokeDasharray="3 3"
stroke="var(--mantine-color-dark-6)"
/>
<CartesianGrid strokeDasharray="3 3" stroke="var(--color-border)" />
)}
<XAxis
dataKey={timestampKey ?? 'ts_bucket'}

View file

@ -10,11 +10,11 @@ export default function Icon({ size = 16 }: { size?: number }) {
<g clipPath="url(#clip0_614_1164)">
<path
d="M256 0L477.703 128V384L256 512L34.2975 384V128L256 0Z"
fill="#4FFA7A"
fill="var(--color-bg-brand)"
/>
<path
d="M311.365 84.4663C314.818 86.9946 316.431 92.1862 315.256 96.9926L284.313 223.563H341.409C344.836 223.563 347.936 226.127 349.295 230.086C350.655 234.046 350.014 238.644 347.665 241.786L210.211 425.598C207.472 429.26 203.089 430.062 199.635 427.534C196.182 425.005 194.569 419.814 195.744 415.007L226.686 288.437H169.591C166.164 288.437 163.064 285.873 161.705 281.914C160.345 277.954 160.986 273.356 163.335 270.214L300.789 86.4023C303.528 82.7403 307.911 81.938 311.365 84.4663Z"
fill="#080A0B"
fill="var(--color-text-inverted)"
/>
</g>
<defs>

View file

@ -1,5 +1,5 @@
import cx from 'classnames';
import { Button, Modal } from 'react-bootstrap';
import { Button, Modal } from '@mantine/core';
import api from './api';
import Clipboard from './Clipboard';
@ -12,12 +12,12 @@ function CopyableValue({
value: string;
}) {
return (
<Clipboard text={value} className="d-block mx-auto p-0 w-100">
<Clipboard text={value} className="d-flex mx-auto p-0 w-100">
{({ isCopied }) => {
return (
<div
className={cx(
'd-flex fs-6 py-2 px-3 bg-grey rounded align-items-center justify-content-between cursor-pointer text-white-hover',
'd-flex w-100 py-2 px-2 gap-2 rounded align-items-center justify-content-between cursor-pointer',
{
'text-success': isCopied,
},
@ -25,7 +25,7 @@ function CopyableValue({
>
<div className="fs-7 d-flex text-truncate align-items-center">
{label}
<pre className="mb-0 user-select-all d-inline text-truncate fs-7 lh-1">
<pre className="m-0 user-select-all d-inline text-truncate fs-7 lh-1">
{value}
</pre>
</div>
@ -36,7 +36,7 @@ function CopyableValue({
'bi-clipboard-check': isCopied,
})}
></i>
{isCopied ? 'Copied to Clipboard!' : 'Copy'}
{isCopied ? 'Copied!' : 'Copy'}
</div>
</div>
);
@ -56,14 +56,13 @@ export default function InstallInstructionModal({
return (
<Modal
aria-labelledby="contained-modal-title-vcenter"
centered
onHide={onHide}
show={show}
opened={show}
onClose={onHide}
title="Start Sending Telemetry"
size="lg"
centered
>
<Modal.Body className="bg-hdx-dark rounded inter">
<div className="fs-4 mb-4">Start Sending Telemetry</div>
<div className="inter">
{team != null && (
<div className="mb-4">
<CopyableValue
@ -80,106 +79,115 @@ export default function InstallInstructionModal({
Click on a link below to view installation instructions for your
application.
</div>
<div className="fs-5 mb-2">Backend</div>
<div className="fs-6 mb-2">
<div className="fs-6 mb-2">Backend</div>
<div className="mb-2">
<a
href="https://clickhouse.com/docs/use-cases/observability/clickstack/sdks/nodejs"
target="_blank"
rel="noreferrer"
className="text-link"
>
Node.js
</a>
<span className="ms-2 text-muted">(Logs + Traces)</span>
</div>
<div className="fs-6 mb-2">
<div className="mb-2">
<a
href="https://clickhouse.com/docs/use-cases/observability/clickstack/sdks/golang"
target="_blank"
rel="noreferrer"
className="text-link"
>
Go
</a>
<span className="ms-2 text-muted">(Logs + Traces)</span>
</div>
<div className="fs-6 mb-2">
<div className="mb-2">
<a
href="https://clickhouse.com/docs/use-cases/observability/clickstack/sdks/python"
target="_blank"
rel="noreferrer"
className="text-link"
>
Python
</a>
<span className="ms-2 text-muted">(Logs + Traces)</span>
</div>
<div className="fs-6 mb-2">
<div className="mb-2">
<a
href="https://clickhouse.com/docs/use-cases/observability/clickstack/sdks/java"
target="_blank"
rel="noreferrer"
className="text-link"
>
Java
</a>
<span className="ms-2 text-muted">(Logs + Traces)</span>
</div>
<div className="fs-6 mb-2">
<div className="mb-2">
<a
href="https://clickhouse.com/docs/use-cases/observability/clickstack/sdks/elixir"
target="_blank"
rel="noreferrer"
className="text-link"
>
Elixir
</a>
<span className="ms-2 text-muted">(Logs)</span>
</div>
<div className="fs-6 mb-2">
<div className="mb-2">
<a
href="https://clickhouse.com/docs/use-cases/observability/clickstack/sdks/ruby-on-rails"
target="_blank"
rel="noreferrer"
className="text-link"
>
Ruby on Rails
</a>
<span className="ms-2 text-muted">(Traces)</span>
</div>
<div className="fs-5 mb-2 mt-4">Platform</div>
<div className="fs-6 mb-2">
<div className="fs-6 mb-2 mt-4">Platform</div>
<div className="mb-2">
<a
href="https://clickhouse.com/docs/use-cases/observability/clickstack/ingesting-data/kubernetes"
target="_blank"
rel="noreferrer"
className="text-link"
>
Kubernetes
</a>
<span className="ms-2 text-muted">(Logs + Metrics)</span>
</div>
<div className="fs-5 mb-2 mt-4">Browser</div>
<div className="fs-6 mb-2">
<div className="fs-6 mb-2 mt-4">Browser</div>
<div className="mb-2">
<a
href="https://clickhouse.com/docs/use-cases/observability/clickstack/sdks/browser"
target="_blank"
rel="noreferrer"
className="text-link"
>
JavaScript/TypeScript
</a>
<span className="ms-2 text-muted">(Logs + Traces)</span>
</div>
<div className="fs-5 mb-2 mt-4">Data Collector</div>
<div className="fs-6 mb-2">
<div className="fs-6 mb-2 mt-4">Data Collector</div>
<div className="mb-2">
<a
href="https://clickhouse.com/docs/use-cases/observability/clickstack/ingesting-data/opentelemetry#sending-otel-data"
target="_blank"
rel="noreferrer"
className="text-link"
>
OpenTelemetry
</a>
<span className="ms-2 text-muted">(Logs + Traces)</span>
</div>
<div className="mt-4">
<Button variant="dark" onClick={() => onHide()}>
<Button variant="default" onClick={() => onHide()}>
Cancel
</Button>
</div>
</Modal.Body>
</div>
</Modal>
);
}

View file

@ -1,7 +1,6 @@
import { useRouter } from 'next/router';
import { NextSeo } from 'next-seo';
import { Button, Form } from 'react-bootstrap';
import { Paper } from '@mantine/core';
import { Button, Paper, Text, TextInput } from '@mantine/core';
export default function JoinTeam() {
const router = useRouter();
@ -17,32 +16,30 @@ export default function JoinTeam() {
</div>
<Paper p="xl" withBorder>
<div className="text-center">
<Form
<form
className="text-start"
action={`/api/team/setup/${token}`}
method="POST"
>
<Form.Label
htmlFor="password"
className="text-start text-muted fs-7 mb-1"
>
Password
</Form.Label>
<Form.Control
<TextInput
id="password"
name="password"
type="password"
className="border-0"
label="Password"
styles={{
label: {
fontSize: '0.875rem',
color: 'var(--color-text-muted)',
marginBottom: 4,
},
}}
/>
{err != null && (
<div
className="text-danger mt-2"
data-test-id="auth-error-msg"
>
<Text c="red" mt="sm" data-test-id="auth-error-msg">
{err === 'invalid'
? 'Password is invalid'
: 'Unknown error occurred, please try again later.'}
</div>
</Text>
)}
<div className="text-center mt-4">
<Button
@ -54,7 +51,7 @@ export default function JoinTeam() {
Setup a password
</Button>
</div>
</Form>
</form>
</div>
</Paper>
</div>

View file

@ -83,7 +83,7 @@ const Th = React.memo<{
{children}
{!!sort && (
<i
className={`ps-1 text-slate-400 fs-8.5 bi bi-caret-${
className={`ps-1 fs-8.5 bi bi-caret-${
sort === 'asc' ? 'up-fill' : 'down-fill'
}`}
/>
@ -357,13 +357,11 @@ export const InfraPodsStatusTable = ({
{isLoading ? (
<TableLoading />
) : isError ? (
<div className="p-4 text-center text-slate-500 fs-8">
<div className="p-4 text-center text-muted fs-8">
Unable to load pod metrics
</div>
) : podsList.length === 0 ? (
<div className="p-4 text-center text-slate-500 fs-8">
No pods found
</div>
<div className="p-4 text-center text-muted fs-8">No pods found</div>
) : (
<Table horizontalSpacing="md" highlightOnHover>
<Table.Thead className="muted-thead">
@ -428,7 +426,7 @@ export const InfraPodsStatusTable = ({
>
<Text
span
c={pod.cpuLimitUtilization ? undefined : 'gray.7'}
c={pod.cpuLimitUtilization ? undefined : 'gray'}
>
{pod.cpuLimitUtilization
? formatNumber(
@ -449,7 +447,7 @@ export const InfraPodsStatusTable = ({
>
<Text
span
c={pod.memLimitUtilization ? undefined : 'gray.7'}
c={pod.memLimitUtilization ? undefined : 'gray'}
>
{pod.memLimitUtilization
? formatNumber(
@ -461,7 +459,7 @@ export const InfraPodsStatusTable = ({
</Tooltip>
</Table.Td>
<Table.Td>
<Text span c={pod.uptime ? undefined : 'gray.7'}>
<Text span c={pod.uptime ? undefined : 'gray'}>
{pod.uptime ? formatUptime(pod.uptime) : ''}
</Text>
</Table.Td>
@ -469,10 +467,10 @@ export const InfraPodsStatusTable = ({
<Text
color={
pod.restarts >= 10
? 'red.6'
? 'red'
: pod.restarts >= 5
? 'yellow.3'
: 'grey.7'
? 'yellow'
: 'gray'
}
>
{pod.restarts}
@ -603,11 +601,11 @@ const NodesTable = ({
{isLoading ? (
<TableLoading />
) : isError ? (
<div className="p-4 text-center text-slate-500 fs-8">
<div className="p-4 text-center text-muted fs-8">
Unable to load nodes
</div>
) : nodesList.length === 0 ? (
<div className="p-4 text-center text-slate-500 fs-8">
<div className="p-4 text-center text-muted fs-8">
No nodes found
</div>
) : (
@ -800,11 +798,11 @@ const NamespacesTable = ({
{isLoading ? (
<TableLoading />
) : isError ? (
<div className="p-4 text-center text-slate-500 fs-8">
<div className="p-4 text-center text-muted fs-8">
Unable to load namespaces
</div>
) : namespacesList.length === 0 ? (
<div className="p-4 text-center text-slate-500 fs-8">
<div className="p-4 text-center text-muted fs-8">
No namespaces found
</div>
) : (
@ -1142,9 +1140,7 @@ function KubernetesDashboardPage() {
)}
<Group justify="space-between">
<Group>
<Text c="gray.4" size="xl">
Kubernetes Dashboard
</Text>
<Text size="xl">Kubernetes Dashboard</Text>
<SourceSelectControlled
name="logSourceId"
control={control}

View file

@ -1,11 +1,11 @@
// @ts-nocheck TODO: remove this line
import Link from 'next/link';
import { Button, Container, Nav, Navbar, NavDropdown } from 'react-bootstrap';
import { Anchor, Burger, Button, Container, Group } from '@mantine/core';
import { useDisclosure } from '@mantine/hooks';
import api from './api';
import Logo from './Logo';
import NavHoverDropdown from './NavHoverDropdown';
export default function LandingHeader({
activeKey,
@ -18,69 +18,149 @@ export default function LandingHeader({
const isLoggedIn = Boolean(me);
const { data: installation } = api.useInstallation();
const [opened, { toggle }] = useDisclosure(false);
return (
<>
<Navbar
collapseOnSelect
expand="lg"
variant="dark"
fixed="top"
style={{ background: '#0f1216b3', backdropFilter: 'blur(12px)' }}
<div
style={{
position: 'fixed',
top: 0,
left: 0,
right: 0,
background: 'var(--color-bg-body)',
backdropFilter: 'blur(12px)',
border: '1px solid var(--color-border)',
zIndex: 100,
}}
>
<Container fluid className="mx-md-4 mt-3">
<Navbar.Brand href="/">
<Logo />
</Navbar.Brand>
<Navbar.Toggle aria-controls="responsive-navbar-nav" />
<Navbar.Collapse className="justify-content-end">
<Nav style={{ fontSize: 14 }} activeKey={activeKey}>
<Nav.Link href="https://hyperdx.io" className="mx-2">
<Container fluid px="xl" py="md">
<Group justify="space-between" align="center">
<Link href="/" style={{ textDecoration: 'none' }}>
<Logo />
</Link>
<Burger
opened={opened}
onClick={toggle}
hiddenFrom="lg"
color="white"
/>
<Group gap="md" visibleFrom="lg" style={{ fontSize: 14 }}>
<Anchor
href="https://hyperdx.io"
c={activeKey === 'cloud' ? 'green' : 'gray'}
underline="never"
style={{ fontWeight: activeKey === 'cloud' ? 600 : 400 }}
>
HyperDX Cloud
</Nav.Link>
<Nav.Link
</Anchor>
<Anchor
href="https://clickhouse.com/docs/use-cases/observability/clickstack"
className="mx-2"
c={activeKey === 'docs' ? 'green' : 'gray'}
underline="never"
style={{ fontWeight: activeKey === 'docs' ? 600 : 400 }}
>
Docs
</Nav.Link>
</Anchor>
{!isLoggedIn && installation?.isTeamExisting === true && (
<Nav.Link
<Anchor
href="/login"
active={activeKey === '/login'}
className="mx-2"
c={activeKey === '/login' ? 'green' : 'gray'}
underline="never"
style={{ fontWeight: activeKey === '/login' ? 600 : 400 }}
>
Login
</Nav.Link>
</Anchor>
)}
{!isLoggedIn &&
activeKey !== '/register' &&
installation?.isTeamExisting === false && (
<div className="d-flex align-items-center mx-2">
<Link href={'/register'} passHref legacyBehavior>
<Button variant="outline-success" className="fs-7.5">
Setup Account
</Button>
</Link>
</div>
)}
{isLoggedIn && (
<div className="d-flex align-items-center mx-2">
<Link href="/search" passHref legacyBehavior>
<Link href="/register" passHref legacyBehavior>
<Button
variant="outline-success"
className="px-3"
component="a"
variant="outline"
color="green"
size="sm"
>
Go to Search
Setup Account
</Button>
</Link>
</div>
)}
{isLoggedIn && (
<Link href="/search" passHref legacyBehavior>
<Button
component="a"
variant="outline"
color="green"
size="sm"
>
Go to Search
</Button>
</Link>
)}
</Nav>
</Navbar.Collapse>
</Group>
</Group>
{/* Mobile menu */}
{opened && (
<Group gap="sm" mt="md" hiddenFrom="lg" style={{ fontSize: 14 }}>
<Anchor
href="https://hyperdx.io"
underline="never"
style={{ fontWeight: activeKey === 'cloud' ? 600 : 400 }}
>
HyperDX Cloud
</Anchor>
<Anchor
href="https://clickhouse.com/docs/use-cases/observability/clickstack"
underline="never"
style={{ fontWeight: activeKey === 'docs' ? 600 : 400 }}
>
Docs
</Anchor>
{!isLoggedIn && installation?.isTeamExisting === true && (
<Anchor
href="/login"
underline="never"
style={{ fontWeight: activeKey === '/login' ? 600 : 400 }}
>
Login
</Anchor>
)}
{!isLoggedIn &&
activeKey !== '/register' &&
installation?.isTeamExisting === false && (
<Link href="/register" passHref legacyBehavior>
<Button
component="a"
variant="outline"
color="green"
size="sm"
fullWidth
>
Setup Account
</Button>
</Link>
)}
{isLoggedIn && (
<Link href="/search" passHref legacyBehavior>
<Button
component="a"
variant="outline"
color="green"
size="sm"
fullWidth
>
Go to Search
</Button>
</Link>
)}
</Group>
)}
</Container>
</Navbar>
</div>
{!fixed && <div style={{ height: 70 }} />}
</>
);

View file

@ -3,9 +3,8 @@ import { useEffect, useMemo, useState } from 'react';
import Link from 'next/link';
import cx from 'classnames';
import { format } from 'date-fns';
import { CloseButton } from 'react-bootstrap';
import { JSONTree } from 'react-json-tree';
import { Alert, Button, Text, Tooltip } from '@mantine/core';
import { Alert, Button, CloseButton, Kbd, Text, Tooltip } from '@mantine/core';
import { ColumnDef, Row, Table } from '@tanstack/react-table';
import HyperJson from './components/HyperJson';
@ -39,7 +38,7 @@ export const CollapsibleSection = ({
onClick={() => setCollapsed(!collapsed)}
>
<i className={`bi bi-chevron-${collapsed ? 'right' : 'down'} me-2`}></i>
<div className="fs-7 text-slate-200">{title}</div>
<div className="fs-7">{title}</div>
</div>
{collapsed ? null : <div className="mb-4">{children}</div>}
</div>
@ -73,7 +72,7 @@ export const StacktraceValue = ({
borderRight: '1px solid #ffffff20',
}}
>
<div className="text-slate-400">{label}</div>
<div>{label}</div>
<div className="fs-7">{value}</div>
</div>
);
@ -138,10 +137,7 @@ export const StacktraceRow = ({
withArrow
color="gray"
>
<i
className="bi bi-box-seam text-slate-400 me-2"
title="in_app: false"
/>
<i className="bi bi-box-seam me-2" title="in_app: false" />
</Tooltip>
)}
{augmentedFrame && (
@ -207,11 +203,7 @@ export const stacktraceColumns: ColumnDef<StacktraceFrame>[] = [
* Breadcrumbs
*/
const Url = ({ url }: { url?: string }) => (
<span className="text-slate-300" title={url}>
{url}
</span>
);
const Url = ({ url }: { url?: string }) => <span title={url}>{url}</span>;
const StatusChip = React.memo(({ status }: { status?: number }) => {
if (!status) {
@ -240,7 +232,7 @@ const LevelChip = React.memo(({ level }: { level?: string }) => {
? 'text-danger bg-danger'
: level.includes('warn') || level.includes('warning')
? 'text-warning bg-warning'
: 'text-slate-300 bg-grey';
: 'bg-muted';
return (
<span
@ -257,7 +249,7 @@ export const breadcrumbColumns: ColumnDef<StacktraceBreadcrumb>[] = [
header: 'Category',
size: 180,
cell: ({ row }) => (
<span className="text-slate-300 d-flex align-items-center gap-2">
<span className="d-flex align-items-center gap-2">
{row.original.category}
{row.original.category === 'console' && (
<LevelChip level={row.original.level} />
@ -283,7 +275,7 @@ export const breadcrumbColumns: ColumnDef<StacktraceBreadcrumb>[] = [
return (
<div className="text-truncate">
<span>{method} </span>
<span className="text-slate-300" title={url}>
<span title={url}>
<Url url={url} />
</span>
</div>
@ -295,11 +287,11 @@ export const breadcrumbColumns: ColumnDef<StacktraceBreadcrumb>[] = [
const { from, to } = row.original.data;
return (
<div className="text-truncate">
<span className="text-slate-300" title={from}>
<span title={from}>
<Url url={from} />
</span>
<span>{' → '}</span>
<span className="text-slate-300" title={to}>
<span title={to}>
<Url url={to} />
</span>
</div>
@ -310,10 +302,7 @@ export const breadcrumbColumns: ColumnDef<StacktraceBreadcrumb>[] = [
if (row.original.category === 'console') {
const { message } = row.original;
return (
<pre
className="text-slate-300 mb-0 text-truncate fs-8"
title={message}
>
<pre className="mb-0 text-truncate fs-8" title={message}>
{message}
</pre>
);
@ -323,14 +312,14 @@ export const breadcrumbColumns: ColumnDef<StacktraceBreadcrumb>[] = [
return <div className="text-truncate">{row.original.message}</div>;
}
return <span className="text-slate-500">Empty</span>;
return <span className="text-muted">Empty</span>;
},
},
{
header: 'Timestamp',
size: 220,
cell: ({ row }) => (
<span className="text-slate-500">
<span className="text-muted">
<FormatTime value={row.original.timestamp * 1000} format="withMs" />
</span>
),
@ -371,7 +360,7 @@ export const headerColumns: ColumnDef<[string, string]>[] = [
header: 'Header',
size: 260,
cell: ({ row }) => (
<div className="text-slate-300 text-truncate" title={row.original[0]}>
<div className="text-truncate" title={row.original[0]}>
{row.original[0]}
</div>
),
@ -395,9 +384,7 @@ export const networkColumns: ColumnDef<{
accessorKey: 'label',
header: 'Label',
size: 260,
cell: ({ row }) => (
<span className="text-slate-300">{row.original.label}</span>
),
cell: ({ row }) => <span>{row.original.label}</span>,
},
{
size: UNDEFINED_WIDTH,
@ -475,9 +462,9 @@ export const NetworkBody = ({
)}
</pre>
) : body === '' ? (
<div className="text-slate-400 px-4 py-3">{emptyMessage}</div>
<div className="px-4 py-3">{emptyMessage}</div>
) : (
<div className="text-slate-400 px-4 py-3">{notCollectedMessage}</div>
<div className="px-4 py-3">{notCollectedMessage}</div>
)}
</>
);
@ -486,10 +473,6 @@ export const NetworkBody = ({
/**
* Keyboard shortcuts
*/
export const Kbd = ({ children }: { children: string }) => (
<div className={styles.kbd}>{children}</div>
);
export const LogSidePanelKbdShortcuts = () => {
const [isDismissed, setDismissed] = useLocalStorage<boolean>(
'kbd-shortcuts-dismissed',
@ -509,8 +492,8 @@ export const LogSidePanelKbdShortcuts = () => {
<div className="d-flex justify-content-between align-items-center ">
<div className="d-flex align-items-center gap-3">
<div>
Use <Kbd></Kbd>
<Kbd></Kbd> arrow keys or <Kbd>k</Kbd>
Use <Kbd className="me-1"></Kbd>
<Kbd></Kbd> arrow keys or <Kbd className="me-1">k</Kbd>
<Kbd>j</Kbd> to move through events
</div>
<div className={styles.kbdDivider} />
@ -518,11 +501,7 @@ export const LogSidePanelKbdShortcuts = () => {
<Kbd>ESC</Kbd> to close
</div>
</div>
<CloseButton
variant="white"
aria-label="Hide"
onClick={handleDismiss}
/>
<CloseButton aria-label="Hide" onClick={handleDismiss} />
</div>
</div>
);
@ -546,7 +525,7 @@ export const SourceMapsFtux = () => {
mt="xs"
onClose={() => setIsDismissed(true)}
>
<Text size="xs" c="gray.4">
<Text size="xs">
<Icon name="code-square" /> Some of the stack frames are pointing to
minified files. Use hyperdx-cli to upload your source maps and see the
original code.

View file

@ -31,16 +31,13 @@ export default function Logo({
};
return (
<div
className="align-items-center d-flex"
style={{
color: 'white',
userSelect: 'none',
}}
>
<div className="align-items-center d-flex">
<div
className="me-2"
style={{ marginBottom: configs[size].iconMarginBottom }}
style={{
display: 'inline-flex',
alignItems: 'center',
}}
>
<Icon size={configs[size].iconSize} />
</div>

View file

@ -43,12 +43,10 @@ const PodDetailsProperty = React.memo(
if (!value) return null;
return (
<div className="pe-4">
<Text size="xs" color="gray.6">
<Text size="xs" color="gray">
{label}
</Text>
<Text size="sm" color="gray.3">
{value}
</Text>
<Text size="sm">{value}</Text>
</div>
);
},

View file

@ -1,17 +0,0 @@
import { useState } from 'react';
import { NavDropdown } from 'react-bootstrap';
export default function NavHoverDropdown(
props: React.ComponentProps<typeof NavDropdown>,
) {
const [show, setShow] = useState(false);
return (
<NavDropdown
{...props}
show={show}
onClick={() => setShow(v => !v)}
onMouseEnter={() => setShow(true)}
onMouseLeave={() => setShow(false)}
/>
);
}

View file

@ -47,12 +47,10 @@ const PodDetailsProperty = React.memo(
if (!value) return null;
return (
<div className="pe-4">
<Text size="xs" color="gray.6">
<Text size="xs" color="gray">
{label}
</Text>
<Text size="sm" color="gray.3">
{value}
</Text>
<Text size="sm">{value}</Text>
</div>
);
},

View file

@ -146,19 +146,10 @@ const OnboardingChecklist = ({
}
return (
<Card
withBorder
p="xs"
mb="sm"
radius="md"
style={{
background: 'var(--mantine-color-dark-8)',
borderColor: 'var(--mantine-color-dark-4)',
}}
>
<Card withBorder p="xs" mb="sm" radius="md">
<Group justify="space-between" align="center" mb={isCollapsed ? 0 : 'xs'}>
<Group gap="xs" align="center">
<Text size="sm" fw="bold" c="gray.3">
<Text size="sm" fw="bold">
Get Started
</Text>
<Badge
@ -175,7 +166,7 @@ const OnboardingChecklist = ({
onClick={() => setIsCollapsed(!isCollapsed)}
>
<i
className={`bi bi-chevron-${isCollapsed ? 'down' : 'up'} text-slate-400`}
className={`bi bi-chevron-${isCollapsed ? 'down' : 'up'} `}
style={{ fontSize: 12 }}
/>
</ActionIcon>
@ -195,14 +186,14 @@ const OnboardingChecklist = ({
alignItems: 'center',
justifyContent: 'center',
border: step.isComplete
? '1px solid var(--mantine-color-green-6)'
: 'none',
? '1px solid var(--color-text-success)'
: '1px solid var(--color-border)',
backgroundColor: step.isComplete
? 'transparent'
: 'var(--mantine-color-dark-5)',
: 'var(--color-bg-muted)',
color: step.isComplete
? 'var(--mantine-color-green-6)'
: 'var(--mantine-color-gray-5)',
? 'var(--color-text-success)'
: 'var(--color-text)',
flexShrink: 0,
}}
>
@ -228,7 +219,6 @@ const OnboardingChecklist = ({
<Text
size="sm"
fw="500"
c={step.isComplete ? 'gray.5' : 'gray.3'}
style={{
textDecoration: step.isComplete ? 'line-through' : 'none',
opacity: step.isComplete ? 0.8 : 1,
@ -236,7 +226,7 @@ const OnboardingChecklist = ({
>
{step.title}
</Text>
<Text size="xs" c="gray.6">
<Text size="xs" c="dimmed">
{step.description}
</Text>
</div>
@ -246,7 +236,7 @@ const OnboardingChecklist = ({
className="bi bi-arrow-right"
style={{
fontSize: 12,
color: 'var(--mantine-color-gray-5)',
color: 'var(--color-text-muted)',
}}
/>
)}
@ -267,7 +257,7 @@ const OnboardingChecklist = ({
borderRadius: 6,
cursor: 'pointer',
':hover': {
backgroundColor: 'var(--mantine-color-dark-7)',
backgroundColor: 'var(--color-bg-muted)',
},
}}
>
@ -288,7 +278,7 @@ const OnboardingChecklist = ({
borderRadius: 6,
cursor: 'pointer',
':hover': {
backgroundColor: 'var(--mantine-color-dark-7)',
backgroundColor: 'var(--color-bg-hover)',
},
}}
>

View file

@ -61,10 +61,10 @@ export const PlaybarSlider = ({
className={styles.markerDot}
style={{
backgroundColor: mark.isSuccess
? 'var(--mantine-color-green-6)'
? 'var(--color-text-success)'
: mark.isError
? 'var(--mantine-color-red-6)'
: 'var(--mantine-color-gray-6)',
? 'var(--color-text-danger)'
: 'var(--color-text-muted)',
left: `${((mark.ts - min) / (max - min)) * 100}%`,
}}
onClick={() => onChange(mark.ts)}
@ -87,7 +87,7 @@ export const PlaybarSlider = ({
<div className={styles.wrapper}>
<div className={styles.markers}>{markersContent}</div>
<Slider
color={playerState === 'playing' ? 'green' : 'gray.5'}
color={playerState === 'playing' ? 'green' : 'gray'}
size="sm"
min={min}
max={max}

View file

@ -42,12 +42,10 @@ const PodDetailsProperty = React.memo(
if (!value) return null;
return (
<div className="pe-4">
<Text size="xs" color="gray.6">
<Text size="xs" color="gray">
{label}
</Text>
<Text size="sm" color="gray.3">
{value}
</Text>
<Text size="sm">{value}</Text>
</div>
);
},

View file

@ -118,7 +118,7 @@ export default function SearchInputV2({
<div className="mb-2 me-2">
<span className="me-1">Full Text:</span>
<code
className="text-muted bg-body p-1 rounded border border-dark"
className="text-muted bg-highlighted p-1 rounded border border-dark"
role="button"
onClick={() => {
const newValue =
@ -133,7 +133,7 @@ export default function SearchInputV2({
<div className="mb-2 me-2">
<span className="me-1">Substring:</span>
<code
className="text-muted bg-body p-1 rounded border border-dark"
className="text-muted bg-highlighted p-1 rounded border border-dark"
role="button"
onClick={() => {
const newValue =
@ -148,7 +148,7 @@ export default function SearchInputV2({
<div className="mb-2 me-2">
<span className="me-1">Exact:</span>
<code
className="text-muted bg-body p-1 rounded border border-dark"
className="text-muted bg-highlighted p-1 rounded border border-dark"
role="button"
onClick={() => {
const newValue =
@ -163,7 +163,7 @@ export default function SearchInputV2({
<div className="mb-2 me-2">
<span className="me-1">Not:</span>
<code
className="text-muted bg-body p-1 rounded border border-dark"
className="text-muted bg-highlighted p-1 rounded border border-dark"
role="button"
onClick={() => {
const newValue =
@ -178,7 +178,7 @@ export default function SearchInputV2({
<div className="mb-2 me-2">
<span className="me-1">Existence:</span>
<code
className="text-muted bg-body p-1 rounded border border-dark"
className="text-muted bg-highlighted p-1 rounded border border-dark"
role="button"
onClick={() => {
const newValue =
@ -193,7 +193,7 @@ export default function SearchInputV2({
<div className="mb-2 me-2">
<span className="me-1">Boolean:</span>
<code
className="text-muted bg-body p-1 rounded border border-dark"
className="text-muted bg-highlighted p-1 rounded border border-dark"
role="button"
onClick={() => {
const newValue =

View file

@ -24,6 +24,7 @@ import {
Text,
Tooltip,
} from '@mantine/core';
import { IconPlayerPlay } from '@tabler/icons-react';
import {
ERROR_RATE_PERCENTAGE_NUMBER_FORMAT,
@ -174,14 +175,12 @@ export function EndpointLatencyChart({
return (
<ChartBox style={{ height: 350 }}>
<Group justify="space-between" align="center" mb="sm">
<Text size="sm" c="gray.4">
Request Latency
</Text>
<Text size="sm">Request Latency</Text>
<Box>
<Button.Group>
<Button
variant="subtle"
color={latencyChartType === 'line' ? 'green' : 'dark.2'}
color={latencyChartType === 'line' ? 'green' : 'gray'}
size="xs"
title="Line Chart"
onClick={() => setLatencyChartType('line')}
@ -191,7 +190,7 @@ export function EndpointLatencyChart({
<Button
variant="subtle"
color={latencyChartType === 'histogram' ? 'green' : 'dark.2'}
color={latencyChartType === 'histogram' ? 'green' : 'gray'}
size="xs"
title="Histogram"
onClick={() => setLatencyChartType('histogram')}
@ -302,9 +301,7 @@ function HttpTab({
<Grid.Col span={6}>
<ChartBox style={{ height: 350 }}>
<Group justify="space-between" align="center" mb="sm">
<Text size="sm" c="gray.4">
Request Error Rate
</Text>
<Text size="sm">Request Error Rate</Text>
<SegmentedControl
size="xs"
value={reqChartType}
@ -354,9 +351,7 @@ function HttpTab({
<Grid.Col span={6}>
<ChartBox style={{ height: 350 }}>
<Group justify="space-between" align="center" mb="sm">
<Text size="sm" c="gray.4">
Request Throughput
</Text>
<Text size="sm">Request Throughput</Text>
</Group>
{source && (
<DBTimeChart
@ -389,9 +384,7 @@ function HttpTab({
<Grid.Col span={6}>
<ChartBox style={{ height: 350, overflow: 'auto' }}>
<Group justify="space-between" align="center" mb="sm">
<Text size="sm" c="gray.4">
20 Top Most Time Consuming Endpoints
</Text>
<Text size="sm">20 Top Most Time Consuming Endpoints</Text>
</Group>
{source && (
@ -466,7 +459,7 @@ function HttpTab({
<Grid.Col span={12}>
<ChartBox style={{ height: 350 }}>
<Group justify="space-between" align="center" mb="sm">
<Text size="sm" c="gray.4">
<Text size="sm">
Top 20{' '}
{topEndpointsChartType === 'time'
? 'Most Time Consuming'
@ -569,9 +562,7 @@ function DatabaseTab({
<Grid.Col span={6}>
<ChartBox style={{ height: 350 }}>
<Group justify="space-between" align="center" mb="sm">
<Text size="sm" c="gray.4">
Total Time Consumed per Query
</Text>
<Text size="sm">Total Time Consumed per Query</Text>
</Group>
{source && (
<DBTimeChart
@ -604,9 +595,7 @@ function DatabaseTab({
<Grid.Col span={6}>
<ChartBox style={{ height: 350 }}>
<Group justify="space-between" align="center" mb="sm">
<Text size="sm" c="gray.4">
Throughput per Query
</Text>
<Text size="sm">Throughput per Query</Text>
</Group>
{source && (
<DBTimeChart
@ -642,14 +631,12 @@ function DatabaseTab({
<Grid.Col span={12}>
<ChartBox style={{ height: 350, overflow: 'auto' }}>
<Group justify="space-between" align="center" mb="sm">
<Text size="sm" c="gray.4">
Top 20 Most Time Consuming Queries
</Text>
<Text size="sm">Top 20 Most Time Consuming Queries</Text>
<Box>
<Button.Group>
<Button
variant="subtle"
color={chartType === 'list' ? 'green' : 'dark.2'}
color={chartType === 'list' ? 'green' : 'gray'}
size="xs"
title="List"
onClick={() => setChartType('list')}
@ -659,7 +646,7 @@ function DatabaseTab({
<Button
variant="subtle"
color={chartType === 'table' ? 'green' : 'dark.2'}
color={chartType === 'table' ? 'green' : 'gray'}
size="xs"
title="Table"
onClick={() => setChartType('table')}
@ -815,9 +802,7 @@ function ErrorsTab({
<Grid.Col span={12}>
<ChartBox style={{ height: 350 }}>
<Group justify="space-between" align="center" mb="sm">
<Text size="sm" c="gray.4">
Error Events per Service
</Text>
<Text size="sm">Error Events per Service</Text>
</Group>
{source && (
<DBTimeChart
@ -1019,7 +1004,7 @@ function ServicesDashboardPage() {
</Button>
</Tooltip>
<Button variant="outline" type="submit" px="sm">
<i className="bi bi-play"></i>
<IconPlayerPlay size={16} />
</Button>
</Group>
</Group>

View file

@ -3,6 +3,7 @@ import cx from 'classnames';
import { ChartConfigWithOptDateRange } from '@hyperdx/common-utils/dist/types';
import { ScrollArea, Skeleton, Stack } from '@mantine/core';
import { useThrottledCallback, useThrottledValue } from '@mantine/hooks';
import { IconPlayerPlay } from '@tabler/icons-react';
import { useVirtualizer } from '@tanstack/react-virtual';
import useRowWhere from '@/hooks/useRowWhere';
@ -78,7 +79,7 @@ const EventRow = React.forwardRef(
</div>
</div>
<div className={styles.eventRowTimestamp} onClick={onTimeClick}>
<i className="bi bi-play-fill me-1 fs-8" />
<IconPlayerPlay size={12} className="me-1" />
{event.formattedTimestamp}
</div>
</div>

View file

@ -1,5 +1,4 @@
import { useState } from 'react';
import { Button } from 'react-bootstrap';
import CopyToClipboard from 'react-copy-to-clipboard';
import { useHotkeys } from 'react-hotkeys-hook';
import {
@ -8,6 +7,7 @@ import {
SearchConditionLanguage,
TSource,
} from '@hyperdx/common-utils/dist/types';
import { Button } from '@mantine/core';
import { Drawer } from '@mantine/core';
import { notifications } from '@mantine/notifications';
@ -85,11 +85,10 @@ export default function SessionSidePanel({
styles={{
body: {
padding: 0,
background: '#0F1216',
height: '100vh',
},
}}
className="border-start border-dark"
className="border-start"
>
<ZIndexContext.Provider value={zIndex}>
<div className="d-flex flex-column h-100">
@ -111,7 +110,7 @@ export default function SessionSidePanel({
<span>{session?.sessionCount} Events</span>
</div>
</div>
<div className="d-flex">
<div className="d-flex gap-2">
<CopyToClipboard
text={window.location.href}
onCopy={() => {
@ -122,19 +121,19 @@ export default function SessionSidePanel({
}}
>
<Button
variant="dark"
className="text-muted-hover mx-2 d-flex align-items-center fs-8"
variant="default"
size="sm"
leftSection={<i className="bi bi-link-45deg fs-7.5" />}
style={{ fontSize: '12px' }}
>
<i className="bi bi-link-45deg me-2 fs-7.5" />
Share Session
</Button>
</CopyToClipboard>
<Button
variant="dark"
className="text-muted-hover d-flex align-items-center"
variant="default"
size="sm"
onClick={onClose}
style={{ padding: '4px 8px' }}
>
<i className="bi bi-x-lg" />
</Button>

View file

@ -610,7 +610,7 @@ export default function SessionSubpanel({
{showRelativeTime ? (
<>
{formatmmss((focus?.ts ?? 0) - minTs)}
<span className="fw-normal text-slate-300 ms-2">
<span className="fw-normal ms-2">
{' / '}
{formatmmss(maxTs - minTs)}
</span>
@ -625,7 +625,7 @@ export default function SessionSubpanel({
<Tooltip label="Go 15 seconds back" color="gray">
<ActionIcon
variant="filled"
color="gray.8"
color="gray"
size="md"
radius="xl"
onClick={skipBackward}
@ -640,7 +640,7 @@ export default function SessionSubpanel({
>
<ActionIcon
variant="filled"
color="gray.8"
color="gray"
size="lg"
radius="xl"
onClick={togglePlayerState}
@ -655,7 +655,7 @@ export default function SessionSubpanel({
<Tooltip label="Skip 15 seconds" color="gray">
<ActionIcon
variant="filled"
color="gray.8"
color="gray"
size="md"
radius="xl"
onClick={skipForward}

View file

@ -36,6 +36,7 @@ import {
Text,
} from '@mantine/core';
import { notifications } from '@mantine/notifications';
import { IconPlayerPlay } from '@tabler/icons-react';
import { useVirtualizer } from '@tanstack/react-virtual';
import { SourceSelectControlled } from '@/components/SourceSelect';
@ -53,6 +54,8 @@ import { useSource, useSources } from './source';
import { FormatTime } from './useFormatTime';
import { formatDistanceToNowStrictShort } from './utils';
import styles from '../styles/SessionsPage.module.scss';
function SessionCard({
email,
maxTime,
@ -84,14 +87,11 @@ function SessionCard({
return (
<div
data-testid={`session-card-${sessionId}`}
className="bg-hdx-dark rounded p-3 d-flex align-items-center justify-content-between text-white-hover-success-trigger"
className={`bg-muted rounded p-3 d-flex align-items-center justify-content-between ${styles.sessionCard}`}
onClick={onClick}
role="button"
>
<div
style={{ width: '50%', maxWidth: 500 }}
className="child-hover-trigger"
>
<div style={{ width: '50%', maxWidth: 500 }} className={styles.emailText}>
{email || `Anonymous Session ${sessionId}`}
</div>
<div>
@ -491,7 +491,7 @@ export default function SessionsPage() {
}}
/>
<Button variant="outline" type="submit" px="sm">
<i className="bi bi-play"></i>
<IconPlayerPlay size={16} />
</Button>
</Group>
</Flex>
@ -510,7 +510,7 @@ export default function SessionsPage() {
<>
{sessionSource && sessionSource.kind !== SourceKind.Session && (
<Alert
icon={<i className="bi bi-info-circle-fill text-slate-400" />}
icon={<i className="bi bi-info-circle-fill " />}
color="gray"
py="xs"
mt="md"
@ -544,7 +544,7 @@ function SessionSetupInstructions() {
return (
<>
<Stack w={500} mx="auto" mt="xl" gap="xxs">
<i className="bi bi-laptop text-slate-600 fs-1"></i>
<i className="bi bi-laptop text-muted fs-1"></i>
<Text c="gray" fw={500} size="xs">
Instructions
</Text>

View file

@ -23,11 +23,13 @@ export default function TabItem({
{...props}
>
<span>{children}</span>
<div className="w-100 mt-2" style={{ height: 4 }}>
<div className="w-100 mt-2" style={{ height: 2 }}>
<div
className="h-100 w-100"
style={{
background: active ? '#50FA7B' : '#242d33',
background: active
? 'var(--color-bg-success)'
: 'var(--color-border)',
}}
></div>
</div>

View file

@ -1,7 +1,6 @@
import { Fragment, useCallback, useMemo, useState } from 'react';
import Head from 'next/head';
import { HTTPError } from 'ky';
import { Button as BSButton, Modal as BSModal } from 'react-bootstrap';
import { CopyToClipboard } from 'react-copy-to-clipboard';
import { SubmitHandler, useForm } from 'react-hook-form';
import { DEFAULT_METADATA_MAX_ROWS_TO_READ } from '@hyperdx/common-utils/dist/core/metadata';
@ -18,7 +17,7 @@ import {
Group,
InputLabel,
Loader,
Modal as MModal,
Modal,
Stack,
Table,
Text,
@ -72,7 +71,7 @@ function InviteTeamMemberForm({
placeholder="you@company.com"
withAsterisk={false}
/>
<div className="text-slate-300 fs-8">
<div className="fs-8">
The invite link will automatically expire after 30 days.
</div>
<Button variant="light" type="submit" disabled={!email || isSubmitting}>
@ -93,11 +92,9 @@ function ConnectionsSection() {
return (
<Box id="connections">
<Text size="md" c="gray.4">
Connections
</Text>
<Text size="md">Connections</Text>
<Divider my="md" />
<Card>
<Card variant="muted">
<Stack mb="md">
{connections?.map(c => (
<Box key={c.id}>
@ -119,7 +116,6 @@ function ConnectionsSection() {
{editedConnectionId !== c.id && (
<Button
variant="subtle"
color="gray.4"
onClick={() => setEditedConnectionId(c.id)}
size="sm"
>
@ -129,7 +125,6 @@ function ConnectionsSection() {
{editedConnectionId === c.id && (
<Button
variant="subtle"
color="gray.4"
onClick={() => setEditedConnectionId(null)}
size="sm"
>
@ -156,7 +151,6 @@ function ConnectionsSection() {
(IS_LOCAL_MODE ? (connections?.length ?? 0) < 1 : true) && (
<Button
variant="outline"
color="gray.4"
onClick={() => setIsCreatingConnection(true)}
>
Add Connection
@ -193,11 +187,9 @@ function SourcesSection() {
return (
<Box id="sources">
<Text size="md" c="gray.4">
Sources
</Text>
<Text size="md">Sources</Text>
<Divider my="md" />
<Card>
<Card variant="muted">
<Stack>
{sources?.map(s => (
<>
@ -227,7 +219,6 @@ function SourcesSection() {
{editedSourceId !== s.id && (
<Button
variant="subtle"
color="gray.4"
onClick={() => setEditedSourceId(s.id)}
size="sm"
>
@ -237,7 +228,6 @@ function SourcesSection() {
{editedSourceId === s.id && (
<Button
variant="subtle"
color="gray.4"
onClick={() => setEditedSourceId(null)}
size="sm"
>
@ -264,11 +254,7 @@ function SourcesSection() {
/>
)}
{!IS_LOCAL_MODE && !isCreatingSource && (
<Button
variant="outline"
onClick={() => setIsCreatingSource(true)}
color="gray.4"
>
<Button variant="default" onClick={() => setIsCreatingSource(true)}>
Add Source
</Button>
)}
@ -467,15 +453,13 @@ function TeamMembersSection() {
return (
<Box id="team_members">
<Text size="md" c="gray.4">
Team
</Text>
<Text size="md">Team</Text>
<Divider my="md" />
<Card>
<Card.Section withBorder py="sm" px="lg">
<Group align="center" justify="space-between">
<div className="text-slate-300 fs-7">Team Members</div>
<div className="fs-7">Team Members</div>
<Button
variant="light"
leftSection={<i className="bi bi-person-plus-fill" />}
@ -506,7 +490,7 @@ function TeamMembersSection() {
<Group mt={4} fz="xs">
<div>{member.email}</div>
{member.hasPasswordAuth && (
<div className="text-slate-300">
<div>
<i className="bi bi-lock-fill" /> Password Auth
</div>
)}
@ -566,7 +550,7 @@ function TeamMembersSection() {
</span>
</Table.Td>
<Table.Td>
<Badge variant="dot" color="gray.6" fw="normal" tt="none">
<Badge variant="dot" color="gray" fw="normal" tt="none">
Pending Invite
</Badge>
<CopyToClipboard text={invitation.url}>
@ -602,7 +586,7 @@ function TeamMembersSection() {
</Card.Section>
</Card>
<MModal
<Modal
centered
onClose={() => setTeamInviteModalShow(false)}
opened={teamInviteModalShow}
@ -612,58 +596,56 @@ function TeamMembersSection() {
onSubmit={onSubmitTeamInviteForm}
isSubmitting={saveTeamInvitation.isPending}
/>
</MModal>
</Modal>
<BSModal
aria-labelledby="contained-modal-title-vcenter"
<Modal
centered
onHide={() =>
onClose={() =>
setDeleteTeamMemberConfirmationModalData({
mode: null,
id: null,
email: null,
})
}
show={deleteTeamMemberConfirmationModalData.id != null}
opened={deleteTeamMemberConfirmationModalData.id != null}
size="lg"
title="Delete Team Member"
>
<BSModal.Body className="bg-grey rounded">
<h3 className="text-muted">Delete Team Member</h3>
<p className="text-muted">
<Stack>
<Text>
Deleting this team member (
{deleteTeamMemberConfirmationModalData.email}) will revoke their
access to the team&apos;s resources and services. This action is not
reversible.
</p>
<BSButton
variant="outline-secondary"
className="mt-2 px-4 ms-2 float-end"
size="sm"
onClick={() =>
setDeleteTeamMemberConfirmationModalData({
mode: null,
id: null,
email: null,
})
}
>
Cancel
</BSButton>
<BSButton
variant="outline-danger"
className="mt-2 px-4 float-end"
size="sm"
onClick={() =>
deleteTeamMemberConfirmationModalData.id &&
onConfirmDeleteTeamMember(
deleteTeamMemberConfirmationModalData.id,
)
}
>
Confirm
</BSButton>
</BSModal.Body>
</BSModal>
</Text>
<Group justify="flex-end" gap="xs">
<Button
variant="default"
onClick={() =>
setDeleteTeamMemberConfirmationModalData({
mode: null,
id: null,
email: null,
})
}
>
Cancel
</Button>
<Button
variant="outline"
color="red"
onClick={() =>
deleteTeamMemberConfirmationModalData.id &&
onConfirmDeleteTeamMember(
deleteTeamMemberConfirmationModalData.id,
)
}
>
Confirm
</Button>
</Group>
</Stack>
</Modal>
</Box>
);
}
@ -741,11 +723,9 @@ function IntegrationsSection() {
return (
<Box id="integrations">
<Text size="md" c="gray.4">
Integrations
</Text>
<Text size="md">Integrations</Text>
<Divider my="md" />
<Card>
<Card variant="muted">
<Text mb="xs">Webhooks</Text>
<Stack>
@ -770,7 +750,6 @@ function IntegrationsSection() {
<>
<Button
variant="subtle"
color="gray.4"
onClick={() => setEditedWebhookId(webhook._id)}
size="compact-xs"
leftSection={<IconPencil size={14} />}
@ -787,7 +766,6 @@ function IntegrationsSection() {
{editedWebhookId === webhook._id && (
<Button
variant="subtle"
color="gray.4"
onClick={() => setEditedWebhookId(null)}
size="compact-xs"
>
@ -812,7 +790,7 @@ function IntegrationsSection() {
</Stack>
{!isAddWebhookModalOpen ? (
<Button variant="outline" color="gray.4" onClick={openWebhookModal}>
<Button variant="outline" onClick={openWebhookModal}>
Add Webhook
</Button>
) : (
@ -866,11 +844,9 @@ function TeamNameSection() {
);
return (
<Box id="team_name">
<Text size="md" c="gray.4">
Team Name
</Text>
<Text size="md">Team Name</Text>
<Divider my="md" />
<Card>
<Card variant="muted">
{isEditingTeamName ? (
<form onSubmit={form.handleSubmit(onSubmit)}>
<Group gap="xs">
@ -912,12 +888,12 @@ function TeamNameSection() {
</form>
) : (
<Group gap="lg">
<div className="text-slate-300 fs-7">{team.name}</div>
<div className="fs-7">{team.name}</div>
{hasAdminAccess && (
<Button
size="xs"
variant="default"
leftSection={<i className="bi bi-pencil text-slate-300" />}
leftSection={<i className="bi bi-pencil " />}
onClick={() => {
setIsEditingTeamName(true);
}}
@ -1022,12 +998,10 @@ function ClickhouseSettingForm({
return (
<Stack gap="xs" mb="md">
<Group gap="xs">
<InputLabel c="gray.3" size="md">
{label}
</InputLabel>
<InputLabel size="md">{label}</InputLabel>
{tooltip && (
<Tooltip label={tooltip}>
<Text c="gray.5" size="sm" style={{ cursor: 'help' }}>
<Text size="sm" style={{ cursor: 'help' }}>
<i className="bi bi-question-circle" />
</Text>
</Tooltip>
@ -1113,7 +1087,7 @@ function ClickhouseSettingForm({
<Button
size="xs"
variant="default"
leftSection={<i className="bi bi-pencil text-slate-300" />}
leftSection={<i className="bi bi-pencil " />}
onClick={() => setIsEditing(true)}
>
Change
@ -1136,11 +1110,9 @@ function TeamQueryConfigSection() {
return (
<Box id="team_name">
<Text size="md" c="gray.4">
ClickHouse Client Settings
</Text>
<Text size="md">ClickHouse Client Settings</Text>
<Divider my="md" />
<Card>
<Card variant="muted">
<Stack>
<ClickhouseSettingForm
settingKey="searchRowLimit"
@ -1202,7 +1174,7 @@ const APIKeyCopyButton = ({
variant={copied ? 'light' : 'default'}
color="gray"
rightSection={
<div className="text-slate-300 ms-2 text-nowrap">
<div className="ms-2 text-nowrap">
{copied ? (
<i className="bi bi-check-lg me-2" />
) : (
@ -1254,14 +1226,10 @@ function ApiKeysSection() {
return (
<Box id="api_keys">
<Text size="md" c="gray.4">
API Keys
</Text>
<Text size="md">API Keys</Text>
<Divider my="md" />
<Card>
<Text c="gray.3" mb="md">
Ingestion API Key
</Text>
<Card variant="muted" mb="md">
<Text mb="md">Ingestion API Key</Text>
<Group gap="xs">
{team?.apiKey && (
<APIKeyCopyButton value={team.apiKey} dataTestId="api-key" />
@ -1276,7 +1244,7 @@ function ApiKeysSection() {
</Button>
)}
</Group>
<MModal
<Modal
aria-labelledby="contained-modal-title-vcenter"
centered
onClose={() => setRotateApiKeyConfirmationModalShow(false)}
@ -1288,15 +1256,14 @@ function ApiKeysSection() {
</Text>
}
>
<MModal.Body>
<Modal.Body>
<Text size="md">
Rotating the API key will invalidate your existing API key and
generate a new one for you. This action is <b>not reversible</b>.
</Text>
<Group justify="end">
<Button
variant="outline"
color="gray.5"
variant="default"
className="mt-2 px-4 ms-2 float-end"
size="sm"
onClick={() => setRotateApiKeyConfirmationModalShow(false)}
@ -1305,7 +1272,7 @@ function ApiKeysSection() {
</Button>
<Button
variant="outline"
color="red.6"
color="red"
className="mt-2 px-4 float-end"
size="sm"
onClick={onConfirmUpdateTeamApiKey}
@ -1313,15 +1280,13 @@ function ApiKeysSection() {
Confirm
</Button>
</Group>
</MModal.Body>
</MModal>
</Modal.Body>
</Modal>
</Card>
{!isLoadingMe && me != null && (
<Card>
<Card variant="muted">
<Card.Section p="md">
<Text c="gray.3" mb="md">
Personal API Access Key
</Text>
<Text mb="md">Personal API Access Key</Text>
<APIKeyCopyButton value={me.accessKey} dataTestId="api-key" />
</Card.Section>
</Card>

View file

@ -1,10 +1,13 @@
import React from 'react';
import {
ActionIcon,
Button,
MantineProvider,
MantineTheme,
MantineThemeOverride,
rem,
Select,
Text,
} from '@mantine/core';
import { Notifications } from '@mantine/notifications';
@ -13,11 +16,11 @@ const makeTheme = ({
}: {
fontFamily?: string;
}): MantineThemeOverride => ({
defaultRadius: 'xs',
cursorType: 'pointer',
fontFamily,
primaryColor: 'green',
primaryShade: 8,
autoContrast: true,
white: '#fff',
fontSizes: {
xxs: '11px',
@ -37,18 +40,18 @@ const makeTheme = ({
xl: 'calc(2rem * var(--mantine-scale))',
},
colors: {
// https://mantine.dev/colors-generator/?color=09D99C
// https://uicolors.app/generate/00c28a
green: [
'#e2fff8',
'#cefef0',
'#a0fbe0',
'#6df9cf',
'#09D99C', // Toned Down
'#2ff5b8',
'#1ef5b3',
'#09da9d',
'#eafff6',
'#cdfee7',
'#a0fad5',
'#63f2bf',
'#25e2a5',
'#00c28a',
'#00a875',
'#00a475',
'#008362',
'#00674e',
'#005542',
],
// https://mantine.dev/colors-generator/?color=A1A1AA
// Customized with FAFAFA, D7D8DB, A1A1AA
@ -75,7 +78,6 @@ const makeTheme = ({
'#1A1B1E',
'#141517',
'#101113',
'#14171b',
],
},
headings: {
@ -104,24 +106,99 @@ const makeTheme = ({
Select: Select.extend({
styles: {
input: {
border: '1px solid var(--mantine-color-gray-7)',
border: '1px solid var(--color-border)',
},
},
}),
Input: {
styles: {
input: {
border: '1px solid var(--mantine-color-gray-7)',
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: {
backgroundColor: '#191B1F',
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') {
@ -137,20 +214,64 @@ const makeTheme = ({
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 {};
},
}),
},
});
export const ThemeWrapper = ({
fontFamily,
colorScheme = 'dark',
children,
}: {
fontFamily?: string;
colorScheme?: 'dark' | 'light';
children: React.ReactNode;
}) => {
const theme = React.useMemo(() => makeTheme({ fontFamily }), [fontFamily]);
return (
<MantineProvider forceColorScheme="dark" theme={theme}>
<MantineProvider forceColorScheme={colorScheme} theme={theme}>
<Notifications zIndex={999999} />
{children}
</MantineProvider>

View file

@ -2,6 +2,7 @@ import { memo, RefObject, useEffect, useMemo, useRef, useState } from 'react';
import cx from 'classnames';
import { Tooltip } from '@mantine/core';
import { useVirtualizer } from '@tanstack/react-virtual';
import { color } from '@uiw/react-codemirror';
import useResizable from './hooks/useResizable';
import { useDrag, usePrevious } from './utils';
@ -165,12 +166,10 @@ function TimelineXAxis({
width: 1,
marginRight: -1,
marginLeft: i === 0 ? 0 : `${percSpacing.toFixed(6)}%`,
background: 'rgba(255, 255, 255, 0.08)',
background: 'var(--color-bg-surface)',
}}
>
<div className="ms-2 text-slate-400 fs-8.5">
{renderMs(i * interval)}
</div>
<div className="ms-2 fs-8.5">{renderMs(i * interval)}</div>
</div>,
);
}
@ -338,6 +337,7 @@ type Row = {
style?: any;
type?: string;
className?: string;
isActive?: boolean;
};
export default function TimelineChart({
@ -560,6 +560,7 @@ export default function TimelineChart({
'd-flex align-items-center overflow-hidden',
row.className,
styles.timelineRow,
row.isActive && styles.timelineRowActive,
)}`}
style={{
// position: 'absolute',
@ -582,7 +583,7 @@ export default function TimelineChart({
<div
className={resizeStyles.resizeHandle}
onMouseDown={startResize}
style={{ backgroundColor: '#3a3a44' }}
style={{ backgroundColor: 'var(--color-bg-neutral)' }}
/>
</div>
<NewTimelineRow
@ -590,10 +591,11 @@ export default function TimelineChart({
height={rowHeight}
maxVal={maxVal}
eventStyles={{
boxShadow: '0px 0px 4px rgba(0, 0, 0, 0.5)',
borderRadius: 2,
fontSize: rowHeight * 0.5,
border: '1px solid #FFFFFF10',
border: '1px solid var(--color-border)',
backgroundColor: 'var(--color-bg-neutral)',
color: 'var(--color-text)',
}}
scale={scale}
offset={offset}

View file

@ -63,7 +63,7 @@ const SettingContainer = ({
<div style={{ flex: 1 }}>
{label}
{description && (
<Text c="gray.6" size="xs" mt={2}>
<Text size="xs" mt={2}>
{description}
</Text>
)}
@ -87,7 +87,7 @@ export const UserPreferencesModal = ({
title={
<>
<span>Preferences</span>
<Text size="xs" c="gray.6" mt={6}>
<Text size="xs" mt={6}>
Customize your experience
</Text>
</>

View file

@ -15,9 +15,9 @@ export function ChartBox({
width: '100%',
display: 'flex',
flexDirection: 'column',
background:
'linear-gradient(180deg, rgba(250,250,250,0.018) 0%, rgba(250,250,250,0.008) 100%)',
borderRadius: 2,
background: 'var(--color-bg-body)',
borderRadius: 'var(--mantine-radius-sm)',
border: '1px solid var(--color-border)',
...style,
}}
>

View file

@ -4,6 +4,7 @@ import { sql } from '@codemirror/lang-sql';
import { format } from '@hyperdx/common-utils/dist/sqlFormatter';
import { ChartConfigWithDateRange } from '@hyperdx/common-utils/dist/types';
import { Button, Paper } from '@mantine/core';
import { IconCheck, IconCopy } from '@tabler/icons-react';
import CodeMirror from '@uiw/react-codemirror';
import { useRenderedSqlChartConfig } from '@/hooks/useChartConfig';
@ -19,20 +20,29 @@ function tryFormat(data?: string) {
}
}
function CopyButton({ text = '' }: { text?: string }) {
function CopyButton({
text = '',
size = 'md',
}: {
text?: string;
size?: 'xs' | 'md';
}) {
const [copied, setCopied] = useState(false);
const iconSize = size === 'xs' ? 14 : 16;
const buttonSize = size === 'xs' ? 'compact-xs' : 'sm';
return (
<CopyToClipboard text={text ?? ''} onCopy={() => setCopied(true)}>
<Button
variant={copied ? 'light' : 'outline'}
color="gray"
variant={copied ? 'light' : 'default'}
size={buttonSize}
className="position-absolute top-0 end-0"
>
{copied ? (
<i className="bi bi-check-lg me-2" />
<IconCheck size={iconSize} className="me-2" />
) : (
<i className="bi bi-clipboard-fill me-2" />
<IconCopy size={iconSize} className="me-2" />
)}
{copied ? 'Copied!' : 'Copy'}
</Button>
@ -44,10 +54,12 @@ export function SQLPreview({
data,
formatData = true,
enableCopy = false,
copyButtonSize = 'md',
}: {
data?: string;
formatData?: boolean;
enableCopy?: boolean;
copyButtonSize?: 'xs' | 'md';
}) {
const displayed = formatData ? tryFormat(data) : data;
@ -66,7 +78,7 @@ export function SQLPreview({
extensions={[sql()]}
editable={false}
/>
{enableCopy && <CopyButton text={displayed} />}
{enableCopy && <CopyButton text={displayed} size={copyButtonSize} />}
</div>
);
}

View file

@ -52,20 +52,15 @@ export const ColorSwatchInput = ({
size="compact-xs"
variant="light"
color="gray"
bg="gray.8"
onClick={() => setOpened(o => !o)}
>
{value ? (
<Group gap="xs">
<Text size="xs" c="gray.5">
Color
</Text>
<Text size="xs">Color</Text>
<ColorSwatch color={value} size={14} />
</Group>
) : (
<Text size="xs" c="gray.5">
Choose color
</Text>
<Text size="xs">Choose color</Text>
)}
</Button>
</Popover.Target>

View file

@ -8,7 +8,7 @@ export default function ConfirmDeleteMenu({
return (
<Menu withArrow>
<Menu.Target>
<Button variant="outline" color="gray.4" size="xs">
<Button variant="outline" size="xs">
Delete
</Button>
</Menu.Target>

View file

@ -209,7 +209,7 @@ export function ConnectionForm({
>
<Stack gap="md">
<Box>
<Text c="gray.4" size="xs" mb="xs">
<Text size="xs" mb="xs">
Connection Name
</Text>
<InputControlled
@ -221,7 +221,7 @@ export function ConnectionForm({
/>
</Box>
<Box>
<Text c="gray.4" size="xs" mb="xs">
<Text size="xs" mb="xs">
Host
</Text>
<InputControlled
@ -233,7 +233,7 @@ export function ConnectionForm({
/>
</Box>
<Box>
<Text c="gray.4" size="xs" mb="xs">
<Text size="xs" mb="xs">
Username
</Text>
<InputControlled
@ -244,14 +244,13 @@ export function ConnectionForm({
/>
</Box>
<Box>
<Text c="gray.4" size="xs" mb="xs">
<Text size="xs" mb="xs">
Password
</Text>
{!showUpdatePassword && !isNew && (
<Button
data-testid="update-password-button"
variant="outline"
color="gray.4"
onClick={() => {
setShowUpdatePassword(true);
}}
@ -272,7 +271,6 @@ export function ConnectionForm({
<Button
data-testid="cancel-password-button"
variant="outline"
color="gray.4"
onClick={() => {
setShowUpdatePassword(false);
resetField('password');
@ -339,7 +337,7 @@ export function ConnectionForm({
/>
)}
{onClose && showCancelButton && (
<Button variant="outline" color="gray.4" onClick={onClose}>
<Button variant="outline" onClick={onClose}>
Cancel
</Button>
)}

View file

@ -247,8 +247,6 @@ export default function ContextSubpanel({
<Flex direction="column" mih="0px" style={{ flexGrow: 1 }}>
<Group justify="space-between" p="sm">
<SegmentedControl
bg="dark.7"
color="dark.5"
size="xs"
data={generateSegmentedControlData()}
value={contextBy}
@ -287,8 +285,6 @@ export default function ContextSubpanel({
/>
)}
<SegmentedControl
bg="dark.7"
color="dark.5"
size="xs"
data={[
{ label: '100ms', value: ms('100ms').toString() },

View file

@ -166,7 +166,7 @@ const HDXBarChartTooltip = withErrorBoundary(
<div className={styles.chartTooltip}>
<div className={styles.chartTooltipContent}>
{title && (
<Text size="xs" mb="xs" c="gray.4">
<Text size="xs" mb="xs">
{title}
</Text>
)}
@ -212,7 +212,7 @@ function PropertyComparisonChart({
return (
<div style={{ width: 340, height: 120 }}>
<Text size="xs" c="gray.4" ta="center" title={name}>
<Text size="xs" ta="center" title={name}>
{truncateMiddle(name, 32)}
</Text>
<ResponsiveContainer width="100%" height="100%">

View file

@ -47,6 +47,7 @@ import {
Text,
Textarea,
} from '@mantine/core';
import { IconPlayerPlay } from '@tabler/icons-react';
import { AGG_FNS } from '@/ChartUtils';
import { AlertChannelForm, getAlertReferenceLines } from '@/components/Alerts';
@ -229,7 +230,6 @@ function ChartSeriesEditorComponent({
)}
</Group>
}
c="dark.2"
labelPosition="right"
mb={8}
mt="sm"
@ -677,7 +677,7 @@ export default function EditTimeChartForm({
)}
/>
<Flex align="center" gap="sm" mb="sm">
<Text c="gray.4" size="sm" className="text-nowrap">
<Text size="sm" className="text-nowrap">
Chart Name
</Text>
<InputControlled
@ -704,7 +704,7 @@ export default function EditTimeChartForm({
},
}}
/>
<Box p="md" bg="dark.6" mb="md">
<Box p="md" mb="md">
<HDXMarkdownChart
config={{
markdown: watch('markdown') || 'Preview',
@ -715,7 +715,7 @@ export default function EditTimeChartForm({
) : (
<>
<Flex mb="md" align="center" gap="sm">
<Text c="gray.4" pe="md" size="sm">
<Text pe="md" size="sm">
Data Source
</Text>
<SourceSelectControlled
@ -758,7 +758,6 @@ export default function EditTimeChartForm({
<Divider mt="md" mb="sm" />
<Flex align="center" mt="sm">
<Text
c="gray.4"
me="sm"
size="sm"
style={{
@ -888,7 +887,7 @@ export default function EditTimeChartForm({
{alert && (
<Paper my="sm">
<Stack gap="xs">
<Paper px="md" py="sm" bg="dark.6" radius="xs">
<Paper px="md" py="sm" radius="xs">
<Group gap="xs" justify="space-between">
<Group gap="xs">
<Text size="sm" opacity={0.7}>
@ -962,7 +961,7 @@ export default function EditTimeChartForm({
{onClose != null && (
<Button
variant="subtle"
color="dark.2"
color="dark"
onClick={onClose}
disabled={isSaving}
>
@ -994,10 +993,9 @@ export default function EditTimeChartForm({
data-testid="chart-run-query-button"
variant="outline"
type="submit"
color="green"
onClick={onSubmit}
>
<i className="bi bi-play"></i>
<IconPlayerPlay size={16} />
</Button>
)}
</Flex>
@ -1005,7 +1003,7 @@ export default function EditTimeChartForm({
{!queryReady && activeTab !== 'markdown' ? (
<Paper shadow="xs" p="xl">
<Center mih={400}>
<Text size="sm" c="gray.4">
<Text size="sm">
Please start by selecting a database, table, and timestamp column
above and then click the play button to query data.
</Text>

View file

@ -481,7 +481,7 @@ function HeatmapContainer({
if (isLoading || isMinMaxLoading) {
return (
<Paper shadow="xs" p="xl">
<Text size="sm" c="gray.4" ta="center">
<Text size="sm" ta="center">
Loading...
</Text>
</Paper>
@ -539,7 +539,7 @@ function HeatmapContainer({
if (time.length < 2 || generatedTsBuckets?.length < 2) {
return (
<Paper shadow="xs" p="xl">
<Text size="sm" c="gray.4" ta="center">
<Text size="sm" ta="center">
Not enough data points to render heatmap. Try expanding your search
criteria.
</Text>
@ -845,7 +845,7 @@ function Heatmap({
}}
/>
<div
className="px-2 py-1 fs-8 text-slate-200"
className="px-2 py-1 fs-8"
style={{
position: 'absolute',
top: highlightedPoint.yCoord + 5,
@ -885,7 +885,7 @@ function Heatmap({
)}
{selectingInfo != null && onFilter != null && (
<div
className="px-2 py-1 text-slate-200 fs-8"
className="px-2 py-1 fs-8"
style={{
backdropFilter: 'blur(4px)',
backgroundColor: 'rgba(#1A1D23 0.4)',

View file

@ -154,7 +154,7 @@ const HDXHistogramChartTooltip = (props: any) => {
return (
<div
className="bg-grey px-3 py-2 rounded fs-8"
className="bg-muted px-3 py-2 rounded fs-8"
style={{ pointerEvents: 'auto' }}
>
<div className="mb-2">

View file

@ -72,10 +72,8 @@ const InfraSubpanelGroup = ({
<div data-testid={`infra-subpanel-${fieldPrefix}`}>
<Group justify="space-between" align="center">
<Group align="center">
<h4 className="text-slate-300 fs-6 m-0">{title}</h4>
<h4 className="fs-6 m-0">{title}</h4>
<SegmentedControl
bg="dark.7"
color="dark.5"
size="xs"
data={[
{ label: '30m', value: '30m' },
@ -88,8 +86,6 @@ const InfraSubpanelGroup = ({
</Group>
<Group align="center">
<SegmentedControl
bg="dark.7"
color="dark.5"
size="xs"
data={[
{ label: 'SM', value: 'sm' },

View file

@ -192,7 +192,7 @@ export function RowDataPanel({
const jsonColumns = getJSONColumnNames(data?.meta);
return (
<div className="flex-grow-1 bg-body overflow-auto" data-testid={dataTestId}>
<div className="flex-grow-1 overflow-auto" data-testid={dataTestId}>
<Box mx="md" my="sm">
<DBRowJsonViewer data={firstRow} jsonColumns={jsonColumns} />
</Box>

View file

@ -76,7 +76,7 @@ function HyperJsonMenu() {
return (
<Group>
<UnstyledButton
color="gray.0"
color="gray"
onClick={() =>
setJsonOptions({ ...jsonOptions, lineWrap: !jsonOptions.lineWrap })
}
@ -403,7 +403,7 @@ export function DBRowJsonViewer({
const jsonOptions = useAtomValue(viewerOptionsAtom);
return (
<div className="flex-grow-1 bg-body overflow-auto">
<div className="flex-grow-1 overflow-auto">
<Box py="xs">
<Group gap="xs">
<Input

View file

@ -160,7 +160,7 @@ export function RowOverviewPanel({
: undefined;
return (
<div className="flex-grow-1 bg-body overflow-auto" data-testid={dataTestId}>
<div className="flex-grow-1 overflow-auto" data-testid={dataTestId}>
{!hideHeader && (
<Box px="32px" pt="md">
<DBRowSidePanelHeader
@ -187,7 +187,7 @@ export function RowOverviewPanel({
{isHttpRequest && (
<Accordion.Item value="network">
<Accordion.Control>
<Text size="sm" c="gray.2" ps="md">
<Text size="sm" ps="md">
HTTP Request
</Text>
</Accordion.Control>
@ -206,7 +206,7 @@ export function RowOverviewPanel({
{hasException && (
<Accordion.Item value="exception">
<Accordion.Control>
<Text size="sm" c="gray.2" ps="md">
<Text size="sm" ps="md">
Exception
</Text>
</Accordion.Control>
@ -227,7 +227,7 @@ export function RowOverviewPanel({
{hasSpanEvents && (
<Accordion.Item value="spanEvents">
<Accordion.Control>
<Text size="sm" c="gray.2" ps="md">
<Text size="sm" ps="md">
Span Events
</Text>
</Accordion.Control>
@ -242,7 +242,7 @@ export function RowOverviewPanel({
{Object.keys(topLevelAttributes).length > 0 && (
<Accordion.Item value="topLevelAttributes">
<Accordion.Control>
<Text size="sm" c="gray.2" ps="md">
<Text size="sm" ps="md">
Top Level Attributes
</Text>
</Accordion.Control>
@ -259,7 +259,7 @@ export function RowOverviewPanel({
<Accordion.Item value="eventAttributes">
<Accordion.Control>
<Text size="sm" c="gray.2" ps="md">
<Text size="sm" ps="md">
{source.kind === 'log' ? 'Log' : 'Span'} Attributes
</Text>
</Accordion.Control>
@ -275,7 +275,7 @@ export function RowOverviewPanel({
<Accordion.Item value="resourceAttributes">
<Accordion.Control>
<Text size="sm" c="gray.2" ps="md">
<Text size="sm" ps="md">
Resource Attributes
</Text>
</Accordion.Control>

View file

@ -567,7 +567,7 @@ export default function DBRowSidePanelErrorBoundary({
An error occurred while rendering this event.
</div>
<div className="px-2 py-1 m-2 fs-7 font-monospace bg-dark-grey p-4">
<div className="px-2 py-1 m-2 fs-7 font-monospace bg-body p-4">
{error?.error?.message}
</div>
</Stack>

View file

@ -89,7 +89,7 @@ function BreadcrumbNavigation({
onClick={() => handleBreadcrumbItemClick(index)}
style={{ textDecoration: 'none' }}
>
<Text size="sm" c="blue.4" style={{ cursor: 'pointer' }}>
<Text size="sm" c="blue" style={{ cursor: 'pointer' }}>
{index === 0 ? 'Original Event' : crumb.label}
</Text>
</UnstyledButton>
@ -99,7 +99,7 @@ function BreadcrumbNavigation({
// Add current level
items.push(
<Text key="current" size="sm" c="gray.2">
<Text key="current" size="sm">
Selected Event
</Text>,
);
@ -198,12 +198,12 @@ export default function DBRowSidePanelHeader({
<Flex>
{severityText && <LogLevel level={severityText} />}
{severityText && isValidDate(date) && (
<Text size="xs" mx="xs" c="gray.4">
<Text size="xs" mx="xs">
&middot;
</Text>
)}
{isValidDate(date) && (
<Text c="gray.4" size="xs">
<Text size="xs">
<FormatTime value={date} /> &middot;{' '}
{formatDistanceToNowStrictShort(date)} ago
</Text>
@ -211,7 +211,6 @@ export default function DBRowSidePanelHeader({
</Flex>
{mainContent ? (
<Paper
bg="dark.7"
p="xs"
mt="sm"
style={{
@ -222,15 +221,12 @@ export default function DBRowSidePanelHeader({
ref={headerRef}
>
<Flex justify="space-between" mb="xs">
<Text size="xs" c="gray.4">
{mainContentHeader}
</Text>
<Text size="xs">{mainContentHeader}</Text>
{/* Toggles expanded sidebar header*/}
{headerHeight >= maxBoxHeight && (
<Button
size="compact-xs"
variant="subtle"
color="gray.3"
onClick={() =>
setUserPreference({
...userPreferences,
@ -262,8 +258,8 @@ export default function DBRowSidePanelHeader({
)}
</Paper>
) : (
<Paper bg="dark.7" p="xs" mt="sm">
<Text size="xs" c="gray.4" mb="xs">
<Paper p="xs" mt="sm">
<Text size="xs" mb="xs">
[Empty]
</Text>
</Paper>

View file

@ -720,7 +720,7 @@ export const RawLogTable = memo(
return (
<div
data-testid="search-results-table"
className="overflow-auto h-100 fs-8 bg-inherit"
className="overflow-auto h-100 fs-8"
onScroll={e => {
fetchMoreOnBottomReached(e.target as HTMLDivElement);
@ -740,7 +740,7 @@ export const RawLogTable = memo(
config={config}
/>
)}
<table className={cx('w-100 bg-inherit', styles.table)} id={tableId}>
<table className={cx('w-100', styles.table)} id={tableId}>
<thead className={styles.tableHead}>
{table.getHeaderGroups().map(headerGroup => (
<tr key={headerGroup.id}>
@ -946,7 +946,7 @@ export const RawLogTable = memo(
})}
<tr>
<td colSpan={800}>
<div className="rounded fs-7 bg-grey text-center d-flex align-items-center justify-content-center mt-3">
<div className="rounded fs-7 bg-muted text-center d-flex align-items-center justify-content-center mt-3">
{isLoading ? (
<div className="my-3">
<div className="spin-animate d-inline-block">
@ -1020,12 +1020,12 @@ export const RawLogTable = memo(
dedupedRows.length === 0 ? (
<div className="my-3" data-testid="db-row-table-no-results">
No results found.
<Text mt="sm" c="gray.3">
<Text mt="sm">
Try checking the query explainer in the search bar if
there are any search syntax issues.
</Text>
{dateRange?.[0] != null && dateRange?.[1] != null ? (
<Text mt="sm" c="gray.3">
<Text mt="sm">
Searched Time Range:{' '}
{formatDistance(dateRange?.[1], dateRange?.[0])} {'('}
<FormatTime
@ -1389,14 +1389,12 @@ function DBSqlRowTableComponent({
</Text>
<Box mah={100} style={{ overflow: 'auto' }}>
{noisyPatterns.data?.map(p => (
<Text c="gray.3" fz="xs" key={p.id}>
<Text fz="xs" key={p.id}>
{p.pattern}
</Text>
))}
{noisyPatternIds.length === 0 && (
<Text c="gray.3" fz="xs">
No noisy patterns found
</Text>
<Text fz="xs">No noisy patterns found</Text>
)}
</Box>
</Box>

View file

@ -104,7 +104,7 @@ export const TextButton = ({
className={classes.textButton}
data-testid={dataTestId}
>
<Text size="xxs" c="gray.6" lh={1} ms={ms}>
<Text size="xxs" lh={1} ms={ms}>
{label}
</Text>
</UnstyledButton>
@ -125,7 +125,7 @@ const FilterPercentage = ({ percentage, isLoading }: FilterPercentageProps) => {
: `~${Math.round(percentage)}%`;
return (
<Text size="xs" c="gray.3" className={isLoading ? 'effect-pulse' : ''}>
<Text size="xs" className={isLoading ? 'effect-pulse' : ''}>
{formattedPercentage}
</Text>
);
@ -154,7 +154,6 @@ export const FilterCheckbox = ({
onClick={() => onChange?.(!value)}
style={{ minWidth: 0 }}
wrap="nowrap"
align="flex-start"
>
<Checkbox
checked={!!value}
@ -184,7 +183,11 @@ export const FilterCheckbox = ({
>
<Text
size="xs"
c={value === 'excluded' ? 'red.4' : 'gray.3'}
c={
value === 'excluded'
? 'var(--color-text-danger)'
: 'var(--color-text)'
}
truncate="end"
flex={1}
title={label}
@ -222,7 +225,7 @@ export const FilterCheckbox = ({
/>
</div>
{pinned && (
<Text size="xxs" c="gray.6">
<Text size="xxs">
<i className="bi bi-pin-angle-fill"></i>
</Text>
)}
@ -457,6 +460,7 @@ export const FilterGroup = ({
component={UnstyledButton}
flex="1"
p="0"
pr="xxxs"
data-testid="filter-group-control"
classNames={{
chevron: 'm-0',
@ -488,15 +492,8 @@ export const FilterGroup = ({
}
}}
styles={{ input: { transition: 'padding 0.2s' } }}
rightSectionWidth={isExpanded ? 20 : 2}
rightSection={
<IconSearch
size={15}
stroke={2}
className={`${isExpanded ? 'opacity-100' : 'opacity-0'}`}
style={{ transition: 'opacity 0.4s 0.2s' }}
/>
}
rightSectionWidth={20}
rightSection={<IconSearch size={12} stroke={2} />}
classNames={{
input: 'ps-0.5',
}}
@ -581,7 +578,7 @@ export const FilterGroup = ({
))}
{optionsLoading ? (
<Group m={6} gap="xs">
<Loader size={12} color="gray.6" />
<Loader size={12} color="gray" />
<Text c="dimmed" size="xs">
Loading...
</Text>
@ -624,7 +621,7 @@ export const FilterGroup = ({
<div className="d-flex m-1">
{loadMoreLoading ? (
<Group m={6} gap="xs">
<Loader size={12} color="gray.6" />
<Loader size={12} color="gray" />
<Text c="dimmed" size="xs">
Loading more...
</Text>
@ -961,15 +958,15 @@ const DBSearchPageFiltersComponent = ({
placement="right"
>
<Tabs.List w="100%">
<Tabs.Tab value="results" size="xs" c="gray.4" h="24px">
<Tabs.Tab value="results" size="xs" h="24px">
<Text size="xs">Results Table</Text>
</Tabs.Tab>
{showDelta && (
<Tabs.Tab value="delta" size="xs" c="gray.4" h="24px">
<Tabs.Tab value="delta" size="xs" h="24px">
<Text size="xs">Event Deltas</Text>
</Tabs.Tab>
)}
<Tabs.Tab value="pattern" size="xs" c="gray.4" h="24px">
<Tabs.Tab value="pattern" size="xs" h="24px">
<Text size="xs">Event Patterns</Text>
</Tabs.Tab>
</Tabs.List>
@ -1014,7 +1011,7 @@ const DBSearchPageFiltersComponent = ({
withArrow
label="Denoise results will visually remove events matching common event patterns from the results table."
>
<Text size="xs" c="gray.3" mt="-1px">
<Text size="xs" mt="-1px">
<i className="bi bi-noise-reduction"></i> Denoise Results
</Text>
</Tooltip>
@ -1052,9 +1049,7 @@ const DBSearchPageFiltersComponent = ({
</Flex>
) : (
shownFacets.length === 0 && (
<Text size="xxs" c="gray.6">
No filters available
</Text>
<Text size="xxs">No filters available</Text>
)
)}
{/* Show facets even when loading to ensure pinned filters are visible while loading */}
@ -1118,10 +1113,10 @@ const DBSearchPageFiltersComponent = ({
{showMoreFields && (
<div>
<Text size="xs" c="gray.6" fw="bold">
<Text size="xs" fw="bold">
Not seeing a filter?
</Text>
<Text size="xxs" c="gray.6">
<Text size="xxs">
{`Try searching instead (e.g. column:foo)`}
</Text>
</div>

View file

@ -138,7 +138,7 @@ function RowOverviewPanelWrapper({
return (
<div className="position-relative">
<div className="bg-body px-3 pt-2 position-relative">
<div className="px-3 pt-2 position-relative">
<TabBar
className="fs-8"
items={[
@ -155,7 +155,7 @@ function RowOverviewPanelWrapper({
onClick={setActiveTab}
/>
</div>
<div className="bg-body">
<div>
{activeTab === InlineTab.Overview && (
<div className="inline-overview-panel">
<RowOverviewPanel source={source} rowId={rowId} />

View file

@ -9,6 +9,8 @@ import { flexRender, Header } from '@tanstack/react-table';
import { UNDEFINED_WIDTH } from '@/tableUtils';
import styles from '../Table.module.scss';
export default function TableHeader({
isLast,
header,
@ -20,7 +22,7 @@ export default function TableHeader({
}) {
return (
<th
className="overflow-hidden bg-hdx-dark"
className="overflow-hidden"
key={header.id}
colSpan={header.colSpan}
style={{
@ -47,7 +49,7 @@ export default function TableHeader({
>
<>
{header.isPlaceholder ? null : (
<Text truncate="end" size="xs" flex="1" c="white">
<Text truncate="end" size="xs" flex="1">
{flexRender(
header.column.columnDef.header,
header.getContext(),
@ -83,7 +85,7 @@ export default function TableHeader({
onMouseDown={header.getResizeHandler()}
onTouchStart={header.getResizeHandler()}
className={cx(
`resizer text-gray-600 cursor-col-resize`,
`resizer ${styles.cursorColResize}`,
header.column.getIsResizing() && 'isResizing',
)}
>

View file

@ -264,7 +264,7 @@ function DBTimeChartComponent({
// only View Events for single series
(!Array.isArray(config.select) || config.select.length === 1) ? (
<div
className="bg-grey px-3 py-2 rounded fs-8"
className="bg-muted px-3 py-2 rounded fs-8"
style={{
zIndex: 5,
position: 'absolute',
@ -290,7 +290,7 @@ function DBTimeChartComponent({
) : null}
{/* {totalGroups > groupKeys.length ? (
<div
className="bg-grey px-3 py-2 rounded fs-8"
className="bg-muted px-3 py-2 rounded fs-8"
style={{
zIndex: 5,
position: 'absolute',
@ -310,7 +310,7 @@ function DBTimeChartComponent({
) : null*/}
{showDisplaySwitcher && (
<div
className="bg-grey px-3 py-2 rounded fs-8"
className="bg-muted px-3 py-2 rounded fs-8"
style={{
zIndex: 5,
position: 'absolute',

View file

@ -127,14 +127,13 @@ export default function DBTracePanel({
<div data-testid={dataTestId}>
<Flex align="center" justify="space-between" mb="sm">
<Flex align="center">
<Text c="dark.2" size="xs" me="xs">
<Text size="xs" me="xs">
{parentSourceData?.traceIdExpression}:{' '}
{traceId || 'No trace id found for event'}
</Text>
{traceId != null && (
<Button
variant="subtle"
color="gray.4"
size="xs"
onClick={() => setShowTraceIdInput(v => !v)}
>
@ -143,7 +142,7 @@ export default function DBTracePanel({
)}
</Flex>
<Group gap="sm">
<Text size="sm" c="gray.4">
<Text size="sm">
{parentSourceData?.kind === SourceKind.Log
? 'Trace Source'
: 'Correlated Log Source'}
@ -153,9 +152,7 @@ export default function DBTracePanel({
</Flex>
{(showTraceIdInput || !traceId) && parentSourceId != null && (
<Stack gap="xs">
<Text c="gray.4" size="xs">
Trace ID Expression
</Text>
<Text size="xs">Trace ID Expression</Text>
<Flex>
<SQLInlineEditorControlled
tableConnection={tcFromSource(parentSourceData)}
@ -185,7 +182,6 @@ export default function DBTracePanel({
<Button
ms="sm"
variant="outline"
color="gray.4"
onClick={() => setShowTraceIdInput(false)}
size="xs"
>
@ -209,7 +205,7 @@ export default function DBTracePanel({
)}
{traceSourceData != null && eventRowWhere != null && (
<>
<Text size="sm" c="dark.2" my="sm">
<Text size="sm" my="sm">
Event Details
</Text>
<TabBar
@ -252,9 +248,7 @@ export default function DBTracePanel({
{traceSourceData != null && !eventRowWhere && (
<Paper shadow="xs" p="xl" mt="md">
<Center mih={100}>
<Text size="sm" c="gray.4">
Please select a span above to view details.
</Text>
<Text size="sm">Please select a span above to view details.</Text>
</Center>
</Paper>
)}

View file

@ -480,7 +480,7 @@ export function DBTraceWaterfallChartContainer({
<div
key={index}
style={{
borderLeft: '1px solid var(--mantine-color-dark-4)',
borderLeft: '1px solid var(--color-border)',
marginLeft: 5,
width: 8,
minWidth: 8,
@ -490,7 +490,6 @@ export function DBTraceWaterfallChartContainer({
></div>
))}
<Text
c="dark.2"
span
me="xxs"
style={{
@ -506,7 +505,7 @@ export function DBTraceWaterfallChartContainer({
}`}
/>{' '}
</Text>
<Text span size="xxs" c="dark.2" me="xs" pt="2px">
<Text span size="xxs" me="xs" pt="2px">
{result.children.length > 0 ? `(${result.children.length})` : ''}
</Text>
<Text
@ -535,8 +534,8 @@ export function DBTraceWaterfallChartContainer({
style: {
// paddingTop: 1,
marginTop: i === 0 ? 32 : 0,
backgroundColor: isHighlighted ? '#202127' : undefined,
},
isActive: isHighlighted,
events: [
{
id,

View file

@ -29,7 +29,7 @@ export default function EventTag({
if (!hasActions) {
return (
<div key={name} className="bg-hdx-dark px-2 py-0.5 me-1 my-1">
<div key={name} className="bg-highlighted px-2 py-0.5 me-1 my-1">
{displayedKey || name}: {value}
</div>
);
@ -46,7 +46,7 @@ export default function EventTag({
<Popover.Target>
<div
key={name}
className="text-muted-hover bg-hdx-dark px-2 py-0.5 me-1 my-1 cursor-pointer"
className="bg-highlighted px-2 py-0.5 me-1 my-1 cursor-pointer"
onClick={() => setOpened(!opened)}
>
{displayedKey || name}: {value}

View file

@ -62,17 +62,17 @@ export const StacktraceFrame = ({
return (
<Group gap="xs" display="inline-flex">
<div
className="text-slate-200 fs-8"
className=" fs-8"
style={{
opacity: isLoading ? 0.8 : 1,
filter: isLoading ? 'blur(1px)' : 'none',
}}
>
{filename}
<span className="text-slate-400">
<span>
:{lineno}:{colno}
</span>
<span className="text-slate-400">{' in '}</span>
<span>{' in '}</span>
{functionName && (
<span
style={{
@ -127,7 +127,7 @@ export const CollapsibleSection = ({
onClick={() => setCollapsed(!collapsed)}
>
<i className={`bi bi-chevron-${collapsed ? 'right' : 'down'} me-2`}></i>
<div className="fs-7 text-slate-200">{title}</div>
<div className="fs-7">{title}</div>
</div>
{collapsed ? null : <div className="mb-4">{children}</div>}
</div>
@ -161,7 +161,7 @@ export const StacktraceValue = ({
borderRight: '1px solid #ffffff20',
}}
>
<div className="text-slate-400">{label}</div>
<div>{label}</div>
<div className="fs-7">{value}</div>
</div>
);
@ -226,10 +226,7 @@ export const StacktraceRow = ({
withArrow
color="gray"
>
<i
className="bi bi-box-seam text-slate-400 me-2"
title="in_app: false"
/>
<i className="bi bi-box-seam me-2" title="in_app: false" />
</Tooltip>
)}
{augmentedFrame && (
@ -295,11 +292,7 @@ export const stacktraceColumns: ColumnDef<TStacktraceFrame>[] = [
* Breadcrumbs
*/
const Url = ({ url }: { url?: string }) => (
<span className="text-slate-300" title={url}>
{url}
</span>
);
const Url = ({ url }: { url?: string }) => <span title={url}>{url}</span>;
const StatusChip = React.memo(({ status }: { status?: number }) => {
if (!status) {
@ -328,7 +321,7 @@ const LevelChip = React.memo(({ level }: { level?: string }) => {
? 'text-danger bg-danger'
: level.includes('warn') || level.includes('warning')
? 'text-warning bg-warning'
: 'text-slate-300 bg-grey';
: 'bg-muted';
return (
<span
@ -345,7 +338,7 @@ export const breadcrumbColumns: ColumnDef<StacktraceBreadcrumb>[] = [
header: 'Category',
size: 180,
cell: ({ row }) => (
<span className="text-slate-300 d-flex align-items-center gap-2">
<span className="d-flex align-items-center gap-2">
{row.original.category}
{row.original.category === 'console' && (
<LevelChip level={row.original.level} />
@ -371,7 +364,7 @@ export const breadcrumbColumns: ColumnDef<StacktraceBreadcrumb>[] = [
return (
<div className="text-truncate">
<span>{method} </span>
<span className="text-slate-300" title={url}>
<span title={url}>
<Url url={url} />
</span>
</div>
@ -383,11 +376,11 @@ export const breadcrumbColumns: ColumnDef<StacktraceBreadcrumb>[] = [
const { from, to } = row.original.data;
return (
<div className="text-truncate">
<span className="text-slate-300" title={from}>
<span title={from}>
<Url url={from} />
</span>
<span>{' → '}</span>
<span className="text-slate-300" title={to}>
<span title={to}>
<Url url={to} />
</span>
</div>
@ -398,10 +391,7 @@ export const breadcrumbColumns: ColumnDef<StacktraceBreadcrumb>[] = [
if (row.original.category === 'console') {
const { message } = row.original;
return (
<pre
className="text-slate-300 mb-0 text-truncate fs-8"
title={message}
>
<pre className="mb-0 text-truncate fs-8" title={message}>
{message}
</pre>
);
@ -411,14 +401,14 @@ export const breadcrumbColumns: ColumnDef<StacktraceBreadcrumb>[] = [
return <div className="text-truncate">{row.original.message}</div>;
}
return <span className="text-slate-500">Empty</span>;
return <span className="text-muted">Empty</span>;
},
},
{
header: 'Timestamp',
size: 220,
cell: ({ row }) => (
<span className="text-slate-500">
<span className="text-muted">
<FormatTime value={row.original.timestamp * 1000} format="withMs" />
</span>
),
@ -540,7 +530,7 @@ export const ExceptionSubpanel = ({
firstException && (
<>
<div>
<Text fw="bold" component="span" size="sm" c="red.6">
<Text fw="bold" component="span" size="sm" variant="danger">
{firstException.type}:{' '}
</Text>
<span className="text-muted">{firstException.value}</span>
@ -621,8 +611,7 @@ export const ExceptionSubpanel = ({
{stacktraceHiddenRowsCount ? (
<Button
variant="outline"
color="gray.6"
variant="default"
size="xs"
m="xs"
onClick={handleStacktraceToggleMoreRows}
@ -651,8 +640,7 @@ export const ExceptionSubpanel = ({
/>
{breadcrumbHiddenRowsCount ? (
<Button
variant="outline"
color="gray.6"
variant="default"
size="xs"
m="xs"
onClick={handleBreadcrumbToggleMoreRows}

View file

@ -51,7 +51,7 @@ export const ExpandedLogRow = memo(
<td colSpan={columnsLength} className="p-0 border-0">
<div className={cx('mx-2 mb-2 rounded', styles.expandedRowContent)}>
<div className="position-relative">
<div className="bg-body px-3 pt-2 position-relative">
<div className="px-3 pt-2 position-relative">
{openSidebar && (
<button
type="button"

View file

@ -1,3 +1,4 @@
/* stylelint-disable */
.container {
display: flex;
height: 100%;
@ -29,15 +30,13 @@
display: flex;
gap: 10px;
padding: 2px 8px;
// margin: 0 -10px;margin
align-items: flex-start;
border-radius: 3px;
position: relative;
overflow: hidden;
&:hover {
background-color: #26282b;
background-color: var(--color-bg-muted);
.lineMenu {
display: flex;
@ -47,7 +46,7 @@
&.expanded {
.object,
.array {
color: #999;
color: var(--color-text-muted);
}
}
@ -64,7 +63,7 @@
}
&:active {
background-color: #1e1f21;
background-color: var(--color-bg-highlighted);
}
}
}
@ -77,34 +76,30 @@
top: 0;
height: calc(100% + 1px);
max-height: 24px;
border-bottom: 1px solid #34373e;
border-bottom: 1px solid var(color-border);
}
.lineMenuBtn {
border: 0;
background-color: rgb(0 0 0 / 20%);
backdrop-filter: blur(4px);
color: #b8b7c9;
border-left: 1px solid #444;
color: var(--color-text);
border-left: 1px solid var(--color-border);
padding: 0 8px;
height: 100%;
&:hover {
background-color: #34373e;
background-color: var(--color-bg-highlighted);
}
&:active {
background-color: #1e1f21;
background-color: var(--color-bg-muted);
}
}
.nestedLine {
// margin-bottom: 8px;margin-bottom
}
.clickable {
&:active {
background-color: #1e1f21;
background-color: var(--color-bg-highlighted);
}
}
@ -119,7 +114,7 @@
&:hover,
&:focus {
background-color: #26282b;
background-color: var(--color-bg-muted);
.hoverContent {
display: flex;
@ -129,7 +124,7 @@
.hoverContent {
position: absolute;
left: 100%;
background-color: #26282b;
background-color: var(--color-bg-muted);
padding-right: 8px;
padding-left: 4px;
}
@ -141,26 +136,25 @@
.jsonBtn {
display: block;
color: #b8b7c9;
color: var(--color-text-secondary);
cursor: pointer;
background-color: #26282b;
background-color: var(--color-bg-muted);
font-size: 11px;
border: 1px solid #444;
border: 1px solid var(--color-border);
border-radius: 3px;
padding: 0 6px;
margin-bottom: 2px;
&:hover {
background-color: #444;
background-color: var(--color-border);
}
&:active {
background-color: #1e1f21;
background-color: var(--color-bg-highlighted);
}
}
.keyContainer {
// min-width: 160px;min-width
display: flex;
flex-direction: column;
align-items: flex-start;
@ -169,7 +163,7 @@
.key {
align-items: center;
width: auto;
color: #8378ff;
color: var(--color-json-key);
cursor: pointer;
display: flex;
gap: 6px;
@ -178,7 +172,7 @@
// @extend .clickable;
i {
color: #555;
color: var(--color-json-punctuation);
margin-right: -4px;
}
}
@ -203,37 +197,36 @@
}
.string {
color: #a6e22e;
color: var(--color-json-string);
word-break: break-all;
// margin-left: -6px;margin-left
&::before,
&::after {
content: '"';
color: #888;
color: var(--color-json-punctuation);
}
}
.number {
color: #f90;
color: var(--color-json-number);
}
.boolean {
color: #f90;
color: var(--color-json-boolean);
}
.object {
color: #a6e22e;
color: var(--color-json-object);
font-size: 11px;
}
.array {
color: #a6e22e;
color: var(--color-json-array);
font-size: 11px;
}
.expandMoreProps {
color: #f90;
color: var(--color-json-number);
font-weight: 500;
i {

View file

@ -408,11 +408,7 @@ const HyperJson = ({
[styles.withLineWrap]: lineWrap,
})}
>
{isEmpty ? (
<div className="text-slate-400">Empty</div>
) : (
<TreeNode data={data} />
)}
{isEmpty ? <div>Empty</div> : <TreeNode data={data} />}
</div>
</HydrateAtoms>
</Provider>

View file

@ -12,25 +12,32 @@ export default function InputLanguageSwitch({
return (
<Flex wrap="nowrap" gap="xxxs" px="sm">
{showHotkey && (
<Text c="gray.3" size="xxs" bg="gray.8" px={4} py={0} mr={4} lh={1.4}>
<Text
size="xxs"
bg="var(--color-bg-neutral)"
c="white"
px={4}
py={0}
mr={4}
lh={1.4}
>
/
</Text>
)}
<Text
c={language === 'sql' ? 'green' : 'dark.0'}
c={language === 'sql' ? 'var(--color-text-success)' : 'gray'}
onClick={() => onLanguageChange('sql')}
size="xs"
role="button"
>
SQL
</Text>
<Text c="dark.2" size="xs">
|
</Text>
<Text size="xs">|</Text>
<Text
size="xs"
role="button"
c={language === 'lucene' ? 'green' : 'dark.0'}
fw={500}
c={language === 'lucene' ? 'var(--color-text-success)' : 'gray'}
onClick={() => onLanguageChange('lucene')}
>
Lucene

View file

@ -131,7 +131,7 @@ const renderKubeEvent = (source: TSource) => (event: KubeEvent) => {
return (
<Timeline.Item key={event.id}>
<Link href={href} passHref legacyBehavior>
<Anchor size="xs" fz={11} c="gray.6" title={event.timestamp}>
<Anchor size="xs" fz={11} title={event.timestamp}>
<FormatTime value={event.timestamp} />
</Anchor>
</Link>
@ -285,7 +285,7 @@ export const KubeTimeline = ({
<Timeline bulletSize={12} lineWidth={1}>
{podEventsAfterAnchor.map(renderKubeEvent(logSource))}
<Timeline.Item key={anchorEvent.timestamp} ref={anchorRef}>
<Text size="xs" fz={11} c="gray.6" title={anchorEvent.timestamp}>
<Text size="xs" fz={11} title={anchorEvent.timestamp}>
<FormatTime value={anchorEvent.timestamp} />
</Text>
<Group gap="xs" my={4}>

View file

@ -17,7 +17,7 @@ export default function LogLevel({
? 'red'
: levelClass === 'warn'
? 'yellow'
: 'gray.4'
: 'gray'
}
{...props}
>

View file

@ -179,9 +179,9 @@ export const NetworkBody = ({
)}
</pre>
) : body === '' ? (
<div className="text-slate-400 px-4 py-3">{emptyMessage}</div>
<div className="px-4 py-3">{emptyMessage}</div>
) : (
<div className="text-slate-400 px-4 py-3">{notCollectedMessage}</div>
<div className="px-4 py-3">{notCollectedMessage}</div>
)}
</>
);
@ -232,7 +232,7 @@ export function NetworkPropertySubpanel({
});
}}
>
<Button size="xs" color="gray.4" variant="light">
<Button size="xs" variant="light">
<i className="bi bi-terminal-plus me-2" />
Copy Request as Curl
</Button>

View file

@ -115,9 +115,8 @@ export const NumberFormatForm: React.VFC<{
</div>
<div style={{ marginTop: -6 }}>
<Paper p="xs" py={4} bg="dark.8">
<Paper p="xs" py={4}>
<div
className="text-slate-400"
style={{
fontSize: 11,
}}
@ -130,9 +129,7 @@ export const NumberFormatForm: React.VFC<{
{values.output !== 'time' && (
<div>
<div className="text-slate-300 fs-8 mt-2 fw-bold mb-1">
Decimals
</div>
<div className="fs-8 mt-2 fw-bold mb-1">Decimals</div>
<Slider
mb="xl"
min={0}

View file

@ -366,7 +366,7 @@ export default function OnboardingModal({
/>
)}
{!IS_LOCAL_MODE && (
<Text size="xs" mt="md" c="gray.4">
<Text size="xs" mt="md">
You can always add and edit connections later.
</Text>
)}
@ -375,7 +375,6 @@ export default function OnboardingModal({
data-testid="demo-server-button"
variant="outline"
w="100%"
color="gray.4"
onClick={handleDemoServerClick}
>
Connect to Demo Server
@ -386,7 +385,6 @@ export default function OnboardingModal({
<>
<Button
variant="subtle"
color="gray.4"
onClick={() => setStep('connection')}
p="xs"
mb="md"
@ -403,7 +401,7 @@ export default function OnboardingModal({
setStep(undefined);
}}
/>
<Text size="xs" mt="lg" c="gray.4">
<Text size="xs" mt="lg">
You can always add and edit sources later.
</Text>
</>

View file

@ -1,10 +1,8 @@
@import '../../styles/variables';
.header {
align-items: center;
background-color: $body-bg;
border-bottom: 1px solid $slate-950;
color: $slate-200;
background-color: var(--color-bg-body);
border-bottom: 1px solid var(--color-border);
color: var(--color-text-default);
display: flex;
font-weight: 500;
height: 60px;

View file

@ -2,7 +2,7 @@ import { useCallback, useEffect, useMemo, useRef } from 'react';
import { useController, UseControllerProps } from 'react-hook-form';
import { acceptCompletion, startCompletion } from '@codemirror/autocomplete';
import { sql, SQLDialect } from '@codemirror/lang-sql';
import { Flex, Group, Paper, Text } from '@mantine/core';
import { Flex, Group, Paper, Text, useMantineColorScheme } from '@mantine/core';
import CodeMirror, {
Compartment,
EditorView,
@ -34,6 +34,7 @@ export default function SQLEditor({
placeholder,
value,
}: SQLInlineEditorProps) {
const { colorScheme } = useMantineColorScheme();
const ref = useRef<ReactCodeMirrorRef>(null);
const compartmentRef = useRef<Compartment>(new Compartment());
@ -42,9 +43,8 @@ export default function SQLEditor({
<Paper
flex="auto"
shadow="none"
bg="dark.6"
style={{
border: '1px solid var(--mantine-color-gray-7)',
bg: 'var(--color-bg-field)',
display: 'flex',
alignItems: 'center',
}}
@ -56,7 +56,7 @@ export default function SQLEditor({
ref={ref}
value={value}
onChange={onChange}
theme={'dark'}
theme={colorScheme === 'dark' ? 'dark' : 'light'}
minHeight={'100px'}
extensions={[
styleTheme,

View file

@ -13,7 +13,13 @@ import {
Field,
TableConnectionChoice,
} from '@hyperdx/common-utils/dist/core/metadata';
import { Flex, Paper, Text, Tooltip } from '@mantine/core';
import {
Flex,
Paper,
Text,
Tooltip,
useMantineColorScheme,
} from '@mantine/core';
import { IconInfoCircle } from '@tabler/icons-react';
import CodeMirror, {
Compartment,
@ -136,6 +142,46 @@ const createStyleTheme = (allowMultiline: boolean = false) =>
whiteSpace: 'nowrap',
wordWrap: 'break-word',
maxWidth: '100%',
backgroundColor: 'var(--color-bg-field) !important',
border: '1px solid var(--color-border) !important',
borderRadius: '8px',
boxShadow:
'0 4px 6px -1px rgb(0 0 0 / 0.1), 0 2px 4px -2px rgb(0 0 0 / 0.1)',
padding: '4px',
},
'& .cm-tooltip-autocomplete > ul': {
fontFamily: 'inherit',
maxHeight: '300px',
},
'& .cm-tooltip-autocomplete > ul > li': {
padding: '4px 8px',
borderRadius: '4px',
cursor: 'pointer',
color: 'var(--color-text)',
},
'& .cm-tooltip-autocomplete > ul > li[aria-selected]': {
backgroundColor: 'var(--color-bg-field-highlighted) !important',
color: 'var(--color-text-muted) !important',
},
'& .cm-tooltip-autocomplete .cm-completionLabel': {
color: 'var(--color-text)',
},
'& .cm-tooltip-autocomplete .cm-completionDetail': {
color: 'var(--color-text-muted)',
fontStyle: 'normal',
marginLeft: '8px',
},
'& .cm-tooltip-autocomplete .cm-completionInfo': {
backgroundColor: 'var(--color-bg-field)',
border: '1px solid var(--color-border)',
borderRadius: '4px',
padding: '8px',
color: 'var(--color-text)',
},
'& .cm-completionIcon': {
width: '16px',
marginRight: '6px',
opacity: 0.7,
},
'& .cm-scroller': {
overflowX: 'hidden',
@ -167,6 +213,7 @@ export default function SQLInlineEditor({
parentRef,
allowMultiline = false,
}: SQLInlineEditorProps & TableConnectionChoice) {
const { colorScheme } = useMantineColorScheme();
const _tableConnections = tableConnection
? [tableConnection]
: tableConnections;
@ -309,9 +356,9 @@ export default function SQLInlineEditor({
<Paper
flex="auto"
shadow="none"
bg="dark.6"
style={{
border: `1px solid ${error ? 'var(--mantine-color-red-7)' : 'var(--mantine-color-gray-7)'}`,
backgroundColor: 'var(--color-bg-field)',
border: `1px solid ${error ? 'var(--color-bg-danger)' : 'var(--color-border)'}`,
display: 'flex',
alignItems: 'center',
minHeight: size === 'xs' ? 30 : 36,
@ -320,7 +367,6 @@ export default function SQLInlineEditor({
>
{label != null && (
<Text
c="gray.4"
mx="4px"
size="xs"
fw="bold"
@ -343,7 +389,7 @@ export default function SQLInlineEditor({
ref={ref}
value={value}
onChange={onChange}
theme={'dark'}
theme={colorScheme === 'dark' ? 'dark' : 'light'}
onFocus={() => {
setIsFocused(true);
}}

View file

@ -124,7 +124,7 @@ export function DBSearchHeatmapChart({
) : (
<Paper shadow="xs" p="xl" h="100%">
<Center mih={100} h="100%">
<Text size="sm" c="gray.4">
<Text size="sm">
Please highlight an outlier range in the heatmap to view the delta
chart.
</Text>

View file

@ -12,7 +12,7 @@ export default function SearchPageActionBar({
<Menu.Target>
<Button
variant="outline"
color="dark.2"
color="gray"
px="xs"
size="xs"
style={{ flexShrink: 0 }}

View file

@ -59,7 +59,7 @@ export default function SearchTotalCountChart({
);
return (
<Text size="xs" c="gray.4" mb={4}>
<Text size="xs" mb={4}>
{isLoading ? (
<span className="effect-pulse">&middot;&middot;&middot; Results</span>
) : totalCount !== null && !isError ? (

View file

@ -95,9 +95,7 @@ export default function ServiceDashboardDbQuerySidePanel({
<Grid.Col span={6}>
<ChartBox style={{ height: 350 }}>
<Group justify="space-between" align="center" mb="sm">
<Text size="sm" c="gray.4">
Total Query Time
</Text>
<Text size="sm">Total Query Time</Text>
</Group>
{source && (
<DBTimeChart
@ -125,9 +123,7 @@ export default function ServiceDashboardDbQuerySidePanel({
<Grid.Col span={6}>
<ChartBox style={{ height: 350 }}>
<Group justify="space-between" align="center" mb="sm">
<Text size="sm" c="gray.4">
Query Throughput
</Text>
<Text size="sm">Query Throughput</Text>
</Group>
{source && (
<DBTimeChart

View file

@ -88,9 +88,7 @@ export default function ServiceDashboardEndpointPerformanceChart({
return (
<ChartBox style={{ height: 350, overflow: 'auto' }}>
<Group justify="space-between" align="center" mb="sm">
<Text size="sm" c="gray.4">
20 Top Most Time Consuming Operations
</Text>
<Text size="sm">20 Top Most Time Consuming Operations</Text>
</Group>
{source && (
<DBListBarChart

View file

@ -100,9 +100,7 @@ export default function ServiceDashboardEndpointSidePanel({
<Grid.Col span={6}>
<ChartBox style={{ height: 350 }}>
<Group justify="space-between" align="center" mb="sm">
<Text size="sm" c="gray.4">
Request Error Rate
</Text>
<Text size="sm">Request Error Rate</Text>
</Group>
{source && (
<DBTimeChart
@ -134,9 +132,7 @@ export default function ServiceDashboardEndpointSidePanel({
<Grid.Col span={6}>
<ChartBox style={{ height: 350 }}>
<Group justify="space-between" align="center" mb="sm">
<Text size="sm" c="gray.4">
Request Throughput
</Text>
<Text size="sm">Request Throughput</Text>
</Group>
{source && (
<DBTimeChart

View file

@ -64,12 +64,8 @@ export default function SlowestEventsTile({
return (
<ChartBox style={{ height }}>
<Group justify="space-between" align="center" mb="sm">
<Text size="sm" c="gray.4">
{title}
</Text>
<Text size="xs" c="dark.2">
(Slower than {roundedP95}ms)
</Text>
<Text size="sm">{title}</Text>
<Text size="xs">(Slower than {roundedP95}ms)</Text>
</Group>
{isLoading && !data ? (
<div className="d-flex h-100 w-100 align-items-center justify-content-center text-muted">

View file

@ -20,17 +20,10 @@ export default function ServiceMapSidePanel({
return (
<Stack w="100%">
<Group gap={0}>
<Text size="sm" c="gray.2" ps="sm">
<Text size="sm" ps="sm">
Service Map
</Text>
<Badge
size="xs"
ms="xs"
color="gray.4"
autoContrast
radius="sm"
className="align-text-bottom"
>
<Badge size="xs" ms="xs" color="gray" autoContrast radius="sm">
Beta
</Badge>
</Group>

View file

@ -112,7 +112,7 @@ function FormRow({
}}
>
{typeof label === 'string' ? (
<Text tt="capitalize" c="gray.6" size="sm">
<Text tt="capitalize" size="sm">
{label}
</Text>
) : (
@ -120,7 +120,6 @@ function FormRow({
)}
</Stack>
<Text
c="gray.4"
me="sm"
style={{
...(!helpText ? { opacity: 0, pointerEvents: 'none' } : {}),
@ -196,7 +195,6 @@ export function LogTableModelForm({ control, watch }: TableModelProps) {
underline="always"
onClick={() => setShowOptionalFields(true)}
size="xs"
c="gray.4"
>
<Text me="sm" span>
<i className="bi bi-gear" />
@ -209,7 +207,6 @@ export function LogTableModelForm({ control, watch }: TableModelProps) {
onClick={() => setShowOptionalFields(false)}
size="xs"
variant="subtle"
color="gray.4"
>
Hide Optional Fields
</Button>
@ -1126,15 +1123,10 @@ export function TableSourceForm({
>
<Stack gap="md" mb="md">
<Flex justify="space-between" align="center" mb="lg">
<Text c="gray.4">Source Settings</Text>
<Text>Source Settings</Text>
<Group>
{onCancel && (
<Button
variant="outline"
color="gray.4"
onClick={onCancel}
size="xs"
>
<Button variant="outline" onClick={onCancel} size="xs">
Cancel
</Button>
)}

View file

@ -1,6 +1,6 @@
import { useState } from 'react';
import { MetricsDataType, TSource } from '@hyperdx/common-utils/dist/types';
import { Modal, Paper, Tabs, TextProps, Tooltip } from '@mantine/core';
import { Modal, Paper, Tabs, Text, TextProps, Tooltip } from '@mantine/core';
import { IconCode } from '@tabler/icons-react';
import { useTableMetadata } from '@/hooks/useMetadata';
@ -32,16 +32,18 @@ const SourceSchemaInfoIcon = ({
<Tooltip
label={tooltipText}
color="dark"
c="white"
position="right"
onClick={() => isEnabled && onClick()}
>
{variant === 'text' ? (
<span
<Text
fw={500}
size="xs"
className="text-sucess-hover"
style={{ cursor: isEnabled ? 'pointer' : 'default', ...iconStyles }}
>
Schema
</span>
</Text>
) : (
<IconCode size={16} />
)}
@ -67,7 +69,13 @@ const TableSchemaPreview = ({
});
return (
<Paper flex="auto" shadow="none" radius="sm" style={{ overflow: 'hidden' }}>
<Paper
flex="auto"
shadow="none"
radius="sm"
p="xs"
style={{ overflow: 'hidden' }}
>
{isLoading ? (
<div className="spin-animate d-inline-block">
<i className="bi bi-arrow-repeat" />
@ -76,6 +84,7 @@ const TableSchemaPreview = ({
<SQLPreview
data={data?.create_table_query ?? 'Schema is not available'}
enableCopy={!!data?.create_table_query}
copyButtonSize="xs"
/>
)}
</Paper>

View file

@ -22,7 +22,7 @@ const spanEventColumns: ColumnDef<SpanEventData>[] = [
header: 'Timestamp',
size: 120,
cell: ({ row }) => (
<span className="text-slate-500">
<span className="text-muted">
<FormatTime
value={new Date(row.original.Timestamp).getTime()}
format="withMs"
@ -35,7 +35,7 @@ const spanEventColumns: ColumnDef<SpanEventData>[] = [
header: 'Name',
size: 180,
cell: ({ row }) => (
<span className="text-slate-300 d-flex align-items-center gap-2">
<span className="d-flex align-items-center gap-2">
{row.original.Name}
</span>
),
@ -53,7 +53,7 @@ const spanEventColumns: ColumnDef<SpanEventData>[] = [
</Box>
);
}
return <span className="text-slate-500">Empty</span>;
return <span className="text-muted">Empty</span>;
},
},
];
@ -93,7 +93,7 @@ export const SpanEventsSubpanel = ({
if (!sortedEvents || sortedEvents.length === 0) {
return (
<div className="p-3 text-slate-500 fs-7">
<div className="p-3 text-muted fs-7">
No span events available for this trace
</div>
);
@ -124,7 +124,6 @@ export const SpanEventsSubpanel = ({
variant="default"
size="xs"
my="sm"
c="gray.4"
onClick={handleToggleMoreRows}
>
{isExpanded ? (

View file

@ -16,17 +16,17 @@ export const StacktraceFrame = ({
return (
<Group gap="xs" display="inline-flex">
<div
className="text-slate-200 fs-8"
className=" fs-8"
style={{
opacity: isLoading ? 0.8 : 1,
filter: isLoading ? 'blur(1px)' : 'none',
}}
>
{filename}
<span className="text-slate-400">
<span>
:{lineno}:{colno}
</span>
<span className="text-slate-400">{' in '}</span>
<span>{' in '}</span>
{functionName && (
<span
style={{

View file

@ -1,5 +1,3 @@
@import '../../styles/variables';
$compactVerticalPadding: 6px;
$normalVerticalPadding: 10px;
$comfortableVerticalPadding: 14px;
@ -22,7 +20,7 @@ $horizontalPadding: 12px;
}
tr {
border-bottom: 1px solid $slate-950;
border-bottom: 1px solid var(--color-border);
}
tbody {
@ -32,7 +30,7 @@ $horizontalPadding: 12px;
}
th {
color: $slate-300;
color: red;
text-transform: uppercase;
font-size: 9px;
font-weight: 500;
@ -103,7 +101,7 @@ $horizontalPadding: 12px;
}
.emptyMessage {
color: $slate-500;
color: var(--color-text);
text-align: center;
padding: 10px;
}
@ -112,19 +110,25 @@ $horizontalPadding: 12px;
display: flex;
gap: 4px;
border-radius: 4px;
background-color: $slate-950;
border: 1px solid $slate-900;
color: $slate-300;
background-color: var(--color-bg-field);
border: 1px solid var(--color-border);
color: var(--color-text);
text-align: center;
font-size: 11px;
&:hover {
background-color: $slate-900;
border-color: $slate-800;
background-color: var(--color-bg-field-highlighted);
border-color: var(--color-border);
}
&:active {
background-color: $slate-950;
border-color: $slate-950;
background-color: var(--color-bg-field-highlighted);
border-color: var(--color-border);
}
}
.cursorColResize {
cursor: col-resize;
display: flex;
align-items: center;
}

View file

@ -101,7 +101,7 @@ export const Tags = React.memo(
color="gray"
style={{ cursor: 'pointer' }}
>
<i className="bi bi-tags text-slate-300 fs-7" />
<i className="bi bi-tags fs-7" />
</ActionIcon>
)}
</Popover.Target>
@ -127,11 +127,10 @@ export const Tags = React.memo(
/>
<ScrollArea viewportProps={{ style: { maxHeight: 200 } }}>
{filtered.length === 0 && (
<div className="pt-3 px-4 fs-8 text-slate-400 text-center">
<div className="pt-3 px-4 fs-8 text-center">
{allowCreate ? (
<>
Type and press <span className="text-slate-300">Enter</span>{' '}
to create new tag
Type and press <span>Enter</span> to create new tag
</>
) : (
'No tags found'
@ -171,9 +170,7 @@ export const Tags = React.memo(
</Checkbox.Group>
</ScrollArea>
<div className="p-2 border-top border-dark d-flex justify-content-between align-items-center">
<div className="ms-2 fs-8 text-slate-400">
{values.length || 'None'} selected
</div>
<div className="ms-2 fs-8 ">{values.length || 'None'} selected</div>
{values.length >= 1 && (
<Button
variant="default"

View file

@ -373,7 +373,7 @@ export function WebhookForm({
/>
</div>,
<Alert
icon={<i className="bi bi-info-circle-fill text-slate-400" />}
icon={<i className="bi bi-info-circle-fill " />}
key="5"
className="mb-4"
color="gray"

View file

@ -22,11 +22,10 @@ import {
} from '@mantine/core';
import { DateInput, DateInputProps } from '@mantine/dates';
import { useDisclosure } from '@mantine/hooks';
import { IconBolt, IconCalendarFilled } from '@tabler/icons-react';
import { useUserPreferences } from '@/useUserPreferences';
import { Icon } from '../Icon';
import { TimePickerMode } from './types';
import { useTimePickerForm } from './useTimePickerForm';
import {
@ -224,24 +223,21 @@ export const TimePicker = ({
data-testid="time-picker-input"
leftSection={
isLiveMode ? (
<Icon
name="lightning-charge-fill"
className="fs-8 text-success"
/>
<IconBolt size={16} className="text-success" />
) : (
<Icon name="calendar-fill" className="fs-8" />
<IconCalendarFilled size={16} />
)
}
styles={{
input: {
color: isLiveMode
? 'var(--mantine-color-green-5)'
: 'var(--mantine-color-gray-1)',
? 'var(--color-text-success)'
: 'var(--color-text)',
},
}}
rightSection={
opened && (
<Text size="xxs" bg="gray.8" px={4}>
<Text size="xxs" bg="var(--color-bg-neutral)" px={4} c="white">
d
</Text>
)
@ -322,7 +318,7 @@ export const TimePicker = ({
<Stack gap={0} p="xs">
{relativeTimeOptions.map((item, index) =>
item === 'divider' ? (
<Divider key={index} my={4} color="gray.9" />
<Divider key={index} my={4} />
) : (
<Button
key={item[0]}
@ -445,7 +441,7 @@ export const TimePicker = ({
</>
)}
</Stack>
<Text size="xxs" lh={1.2} c="gray.7">
<Text size="xxs" lh={1.2}>
You can use natural language to select dates (e.g. yesterday, last
monday at 5pm)
</Text>
@ -454,7 +450,7 @@ export const TimePicker = ({
justify="flex-end"
mt={8}
pt={8}
style={{ borderTop: '1px solid #282828' }}
style={{ borderTop: '1px solid var(--color-border)' }}
>
<Button
data-testid="time-picker-apply"

View file

@ -1,11 +1,9 @@
@import './variables';
.sectionHeader {
border-bottom: 1px solid $slate-950;
border-bottom: 1px solid var(--color-border);
margin-top: 30px;
padding-bottom: 10px;
font-size: 14px;
color: $slate-400;
color: var(--color-text-muted);
}
.historyCardWrapper {
@ -22,7 +20,7 @@
.historyCard {
width: 4px;
height: 16px;
background-color: $slate-950;
background-color: var(--color-bg-muted);
border-radius: 2px;
margin: 0 1px;
cursor: pointer;
@ -34,11 +32,11 @@
}
&.ok {
background-color: #00d474;
background-color: var(--color-success);
}
&.alarm {
background-color: #e74c3c;
background-color: var(--color-danger);
}
}
@ -48,15 +46,15 @@
justify-content: space-between;
gap: 16px;
padding: 12px 0;
border-bottom: 1px solid $slate-950;
border-bottom: 1px solid var(--color-border);
}
.alertLink {
font-weight: 500;
color: $slate-200;
color: var(--color-text-secondary);
text-decoration: none;
&:hover {
color: #fff;
color: var(--color-text);
}
}

View file

@ -1,4 +1,4 @@
@import './variables';
/* stylelint-disable */
.wrapper {
height: 100vh;
@ -6,13 +6,12 @@
display: flex;
flex-flow: column nowrap;
justify-content: space-between;
border-right: 1px solid $slate-950;
border-right: 1px solid var(--color-border);
background: var(--color-bg-sidebar);
}
.list {
// background-color: #00000030;
// border-bottom: 1px solid $slate-950;
border-top: 1px solid $slate-950;
border-top: 1px solid var(--color-border);
overflow-x: hidden;
max-width: 100%;
padding: 4px 16px;
@ -21,7 +20,7 @@
.scrollbar {
.thumb {
background-color: var(--mantine-color-gray-9);
background-color: var(--color-border);
}
}
@ -32,21 +31,20 @@
}
.listGroupName {
color: $slate-400;
color: var(--color-text-muted);
text-transform: uppercase;
font-size: 11px;
letter-spacing: 1px;
margin-bottom: 6px;
margin-bottom: 2x;
margin-top: 6px;
padding-left: 16px;
width: 100%;
display: flex;
align-items: center;
// justify-content: space-between;
gap: 6px;
&:hover {
color: $slate-300;
color: var(--color-text);
cursor: pointer;
}
}
@ -55,55 +53,82 @@
display: flex;
justify-content: space-between;
text-decoration: none;
color: $slate-200;
font-size: 13px;
margin-bottom: 4px;
color: var(--color-text);
font-size: 14px;
max-width: 100%;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
padding-left: 16px;
user-select: none;
gap: 10px;
&:hover {
color: $slate-100;
color: var(--color-text-success);
}
&:focus-visible {
outline: none;
border-left: 2px solid $green;
background: var(--color-bg-muted);
}
}
&:last-of-type {
margin-bottom: 12px;
.linkIcon {
margin-right: 8px;
display: inline-flex;
align-items: center;
vertical-align: middle;
transition: all 0.2s ease-in-out;
&:hover {
color: var(--color-text-success);
}
}
.listEmptyMsg {
color: $slate-400;
color: var(--color-text-muted);
font-size: 12px;
margin: 8px 16px;
overflow: hidden;
text-overflow: ellipsis;
}
.listLinkActive {
// color: $green;
color: var(--mantine-color-green-3);
font-weight: 500;
.nestedLink {
display: block;
color: var(--color-text);
text-decoration: none;
font-size: 13px;
padding-left: 16px;
padding-block: 2px;
transition: all 0.2s ease-in-out;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
&:hover {
// color: $green;
color: var(--mantine-color-green-3);
&:hover {
color: var(--color-text-success);
}
&:focus-visible {
outline: none;
background: var(--color-bg-muted);
}
}
.nestedLinkActive {
color: var(--color-text-success);
font-weight: 500;
}
.listLinkActive {
color: var(--color-text-success);
font-weight: 500;
}
.kbd {
white-space: nowrap;
letter-spacing: -1px;
color: $slate-400;
background: $slate-950;
color: var(--color-text-muted);
background: var(--color-bg-surface);
border-radius: 4px;
padding: 0 4px;
font-size: 10px;
@ -118,18 +143,90 @@
}
}
.appNavMenu {
// User menu trigger styling
.userMenuTrigger {
pointer-events: all;
cursor: pointer;
box-shadow: 0 5px 10px 10px #0f1215e0;
background: var(--mantine-color-gray-9);
margin: 8px 0.875rem 0.875rem;
padding: 4px 8px;
border-radius: 8px;
transition: background-color 0.2s ease, transform 0.1s ease;
max-width: 100%;
overflow: hidden;
&:hover {
background: var(--mantine-color-gray-8);
background: var(--color-bg-muted);
}
&:active {
// background: var(--mantine-color-gray-9);
transform: translate(0, 1px);
}
&Collapsed {
padding: 2px;
margin: 8px auto 0.875rem;
background: transparent;
border: none !important;
width: fit-content;
&:hover {
background: var(--color-bg-muted);
}
&:active {
transform: translate(0, 1px);
}
}
}
// Help menu trigger styling
.helpMenuTrigger {
pointer-events: all;
cursor: pointer;
margin: 0 0.875rem 8px;
width: 28px;
height: 28px;
border-radius: 50%;
border: 1px solid var(--color-border);
transition: background-color 0.2s ease, transform 0.1s ease, border-color 0.2s ease;
display: flex;
align-items: center;
justify-content: center;
&:hover {
background: var(--color-bg-muted);
border-color: var(--color-border);
}
&:active {
transform: translate(0, 1px);
}
&Collapsed {
margin: 0 auto 8px;
border: none;
background: transparent;
&:hover {
background: var(--color-bg-muted);
}
&:active {
transform: translate(0, 1px);
}
}
}
// Bottom section with gradient overlay
.bottomSection {
position: absolute;
bottom: 0;
pointer-events: none;
background: linear-gradient(
to top,
var(--color-bg-sidebar) 50%,
transparent 100%
);
padding-top: 40px;
}

Some files were not shown because too many files have changed in this diff Show more