mirror of
https://github.com/hyperdxio/hyperdx
synced 2026-04-21 13:37:15 +00:00
Improve Discoverability Inline Expansion of Items in Search Table (#1168)
This commit is contained in:
parent
3d82583fce
commit
970c0027b8
4 changed files with 207 additions and 56 deletions
5
.changeset/purple-pens-grab.md
Normal file
5
.changeset/purple-pens-grab.md
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
---
|
||||
"@hyperdx/app": minor
|
||||
---
|
||||
|
||||
Fix: improve the discoverability of inline item expansion within the search table
|
||||
|
|
@ -43,11 +43,7 @@ import {
|
|||
Tooltip as MantineTooltip,
|
||||
UnstyledButton,
|
||||
} from '@mantine/core';
|
||||
import {
|
||||
FetchNextPageOptions,
|
||||
useQuery,
|
||||
useQueryClient,
|
||||
} from '@tanstack/react-query';
|
||||
import { FetchNextPageOptions, useQuery } from '@tanstack/react-query';
|
||||
import {
|
||||
ColumnDef,
|
||||
ColumnResizeMode,
|
||||
|
|
@ -696,11 +692,7 @@ export const RawLogTable = memo(
|
|||
config={config}
|
||||
/>
|
||||
)}
|
||||
<table
|
||||
className="w-100 bg-inherit"
|
||||
id={tableId}
|
||||
style={{ tableLayout: 'fixed' }}
|
||||
>
|
||||
<table className={cx('w-100 bg-inherit', styles.table)} id={tableId}>
|
||||
<thead className={styles.tableHead}>
|
||||
{table.getHeaderGroups().map(headerGroup => (
|
||||
<tr key={headerGroup.id}>
|
||||
|
|
@ -832,34 +824,82 @@ export const RawLogTable = memo(
|
|||
<React.Fragment key={virtualRow.key}>
|
||||
<tr
|
||||
data-testid={`table-row-${rowId}`}
|
||||
onClick={() => {
|
||||
// onRowExpandClick(row.original.id, row.original.sort_key);
|
||||
_onRowExpandClick(row.original);
|
||||
}}
|
||||
role="button"
|
||||
// TODO: Restore highlight
|
||||
className={cx(styles.tableRow, {
|
||||
[styles.tableRow__selected]: highlightedLineId === rowId,
|
||||
})}
|
||||
data-index={virtualRow.index}
|
||||
ref={rowVirtualizer.measureElement}
|
||||
>
|
||||
{row.getVisibleCells().map(cell => {
|
||||
return (
|
||||
<td
|
||||
key={cell.id}
|
||||
className={cx('align-top overflow-hidden', {
|
||||
'text-break': wrapLinesEnabled,
|
||||
'text-truncate': !wrapLinesEnabled,
|
||||
{/* Expand button cell */}
|
||||
{showExpandButton && (
|
||||
<td
|
||||
className="align-top overflow-hidden"
|
||||
style={{ width: '40px' }}
|
||||
>
|
||||
{flexRender(
|
||||
row.getVisibleCells()[0].column.columnDef.cell,
|
||||
row.getVisibleCells()[0].getContext(),
|
||||
)}
|
||||
</td>
|
||||
)}
|
||||
|
||||
{/* Content columns grouped as one button */}
|
||||
<td
|
||||
className="align-top overflow-hidden p-0"
|
||||
colSpan={columns.length - (showExpandButton ? 1 : 0)}
|
||||
>
|
||||
<button
|
||||
type="button"
|
||||
className={styles.rowContentButton}
|
||||
onClick={e => {
|
||||
e.stopPropagation();
|
||||
_onRowExpandClick(row.original);
|
||||
}}
|
||||
aria-label="View details for log entry"
|
||||
>
|
||||
{row
|
||||
.getVisibleCells()
|
||||
.slice(showExpandButton ? 1 : 0) // Skip expand column
|
||||
.map((cell, cellIndex) => {
|
||||
const columnCustomClassName = (
|
||||
cell.column.columnDef.meta as any
|
||||
)?.className;
|
||||
const columnSize = cell.column.getSize();
|
||||
const totalContentCells =
|
||||
row.getVisibleCells().length -
|
||||
(showExpandButton ? 1 : 0);
|
||||
|
||||
return (
|
||||
<div
|
||||
key={cell.id}
|
||||
className={cx(
|
||||
'flex-shrink-0 overflow-hidden',
|
||||
{
|
||||
'text-break': wrapLinesEnabled,
|
||||
'text-truncate': !wrapLinesEnabled,
|
||||
},
|
||||
columnCustomClassName,
|
||||
)}
|
||||
style={{
|
||||
width:
|
||||
columnSize === UNDEFINED_WIDTH
|
||||
? 'auto'
|
||||
: `${columnSize}px`,
|
||||
flex:
|
||||
columnSize === UNDEFINED_WIDTH
|
||||
? '1'
|
||||
: 'none',
|
||||
}}
|
||||
>
|
||||
{flexRender(
|
||||
cell.column.columnDef.cell,
|
||||
cell.getContext(),
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
>
|
||||
{flexRender(
|
||||
cell.column.columnDef.cell,
|
||||
cell.getContext(),
|
||||
)}
|
||||
</td>
|
||||
);
|
||||
})}
|
||||
</button>
|
||||
</td>
|
||||
</tr>
|
||||
{showExpandButton && isExpanded && (
|
||||
<ExpandedLogRow
|
||||
|
|
@ -1213,8 +1253,6 @@ function DBSqlRowTableComponent({
|
|||
return noisyPatterns.data?.map(p => p.id) ?? [];
|
||||
}, [noisyPatterns.data]);
|
||||
|
||||
const queryClient = useQueryClient();
|
||||
|
||||
const denoisedRows = useQuery({
|
||||
queryKey: [
|
||||
'denoised-rows',
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@ import React, { memo, useCallback, useState } from 'react';
|
|||
import cx from 'classnames';
|
||||
import { useQueryState } from 'nuqs';
|
||||
import { TSource } from '@hyperdx/common-utils/dist/types';
|
||||
import { IconChevronRight } from '@tabler/icons-react';
|
||||
|
||||
import { useLocalStorage } from '@/utils';
|
||||
|
||||
|
|
@ -179,6 +180,44 @@ export const useExpandableRows = (
|
|||
};
|
||||
};
|
||||
|
||||
const ExpandButton = memo(
|
||||
({
|
||||
rowId,
|
||||
isExpanded,
|
||||
highlightedLineId,
|
||||
toggleRowExpansion,
|
||||
}: {
|
||||
rowId: string;
|
||||
isExpanded: boolean;
|
||||
highlightedLineId?: string;
|
||||
toggleRowExpansion: (rowId: string) => void;
|
||||
}) => {
|
||||
return (
|
||||
<span className="d-flex align-items-center justify-content-center">
|
||||
<button
|
||||
type="button"
|
||||
className={cx(styles.expandButton, {
|
||||
[styles.expanded]: isExpanded,
|
||||
'text-success': highlightedLineId === rowId,
|
||||
'text-muted': highlightedLineId !== rowId,
|
||||
})}
|
||||
onClick={e => {
|
||||
e.stopPropagation();
|
||||
toggleRowExpansion(rowId);
|
||||
}}
|
||||
aria-expanded={isExpanded}
|
||||
aria-label={`${isExpanded ? 'Collapse' : 'Expand'} log details`}
|
||||
>
|
||||
<IconChevronRight size={16} />
|
||||
</button>
|
||||
<span className={styles.expandButtonSeparator} />
|
||||
</span>
|
||||
);
|
||||
},
|
||||
);
|
||||
|
||||
ExpandButton.displayName = 'ExpandButton';
|
||||
|
||||
// Utility function for creating expand button column
|
||||
export const createExpandButtonColumn = (
|
||||
expandedRows: Record<string, boolean>,
|
||||
|
|
@ -191,25 +230,19 @@ export const createExpandButtonColumn = (
|
|||
cell: (info: any) => {
|
||||
const rowId = info.getValue() as string;
|
||||
const isExpanded = expandedRows[rowId] ?? false;
|
||||
|
||||
return (
|
||||
<button
|
||||
type="button"
|
||||
className={cx('btn btn-link p-0 border-0', {
|
||||
'text-success': highlightedLineId === rowId,
|
||||
'text-muted': highlightedLineId !== rowId,
|
||||
})}
|
||||
onClick={e => {
|
||||
e.stopPropagation();
|
||||
toggleRowExpansion(rowId);
|
||||
}}
|
||||
aria-expanded={isExpanded}
|
||||
aria-label={`${isExpanded ? 'Collapse' : 'Expand'} log details`}
|
||||
style={{ lineHeight: 1 }}
|
||||
>
|
||||
<i className={`bi bi-chevron-${isExpanded ? 'down' : 'right'}`} />
|
||||
</button>
|
||||
<ExpandButton
|
||||
rowId={rowId}
|
||||
isExpanded={isExpanded}
|
||||
highlightedLineId={highlightedLineId}
|
||||
toggleRowExpansion={toggleRowExpansion}
|
||||
/>
|
||||
);
|
||||
},
|
||||
size: 8,
|
||||
size: 32,
|
||||
enableResizing: false,
|
||||
meta: {
|
||||
className: 'text-center',
|
||||
},
|
||||
});
|
||||
|
|
|
|||
|
|
@ -1,5 +1,11 @@
|
|||
@import './variables';
|
||||
|
||||
.table {
|
||||
table-layout: fixed;
|
||||
border-spacing: 0 2px;
|
||||
border-collapse: separate;
|
||||
}
|
||||
|
||||
.tableHead {
|
||||
background: inherit;
|
||||
position: sticky;
|
||||
|
|
@ -7,10 +13,6 @@
|
|||
}
|
||||
|
||||
.tableRow {
|
||||
&:hover {
|
||||
background-color: $slate-800;
|
||||
}
|
||||
|
||||
&__selected {
|
||||
background-color: $slate-800;
|
||||
font-weight: bold;
|
||||
|
|
@ -25,8 +27,81 @@
|
|||
}
|
||||
|
||||
.expandButton {
|
||||
background: transparent;
|
||||
border: none;
|
||||
padding: 0 2px;
|
||||
color: inherit;
|
||||
cursor: pointer;
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
transition: background-color 0.15s ease-in-out;
|
||||
border-radius: 4px;
|
||||
|
||||
&:hover {
|
||||
background-color: rgb(255 255 255 / 10%) !important;
|
||||
color: #fff !important;
|
||||
background-color: $slate-800;
|
||||
}
|
||||
|
||||
&:focus,
|
||||
&:focus-visible {
|
||||
background-color: $slate-800;
|
||||
outline: none;
|
||||
}
|
||||
|
||||
&:active {
|
||||
outline: none;
|
||||
box-shadow: none;
|
||||
background-color: $slate-800;
|
||||
}
|
||||
|
||||
svg {
|
||||
transition: transform 0.2s ease-in-out;
|
||||
transform-origin: center;
|
||||
}
|
||||
|
||||
&.expanded svg {
|
||||
transform: rotate(90deg);
|
||||
}
|
||||
}
|
||||
|
||||
.expandButtonSeparator {
|
||||
width: 1px;
|
||||
height: 12px;
|
||||
border-right: 1px solid $slate-800;
|
||||
margin-left: 2px;
|
||||
margin-right: 2px;
|
||||
display: inline-block;
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
.rowContentButton {
|
||||
background: transparent;
|
||||
border: none;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
cursor: pointer;
|
||||
display: flex;
|
||||
align-items: stretch;
|
||||
text-align: left;
|
||||
color: inherit;
|
||||
transition: background-color 0.15s ease-in-out;
|
||||
border-radius: 4px;
|
||||
|
||||
&:hover {
|
||||
background-color: $slate-800;
|
||||
}
|
||||
|
||||
&:focus,
|
||||
&:focus-visible {
|
||||
background-color: $slate-800;
|
||||
outline: none;
|
||||
}
|
||||
|
||||
&:active {
|
||||
outline: none;
|
||||
box-shadow: none;
|
||||
background-color: $slate-800;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue