mirror of
https://github.com/hyperdxio/hyperdx
synced 2026-04-21 13:37:15 +00:00
feat: Toggle columns from LogSidePanel (#82)
Allow to toggle columns from LogSidePanel <img width="821" alt="Screenshot 2023-11-03 at 10 39 13 PM" src="https://github.com/hyperdxio/hyperdx/assets/20255948/b997cd3d-edf1-4df5-a201-affdbea27cb6"> Co-authored-by: Shorpo <149748269+svc-shorpo@users.noreply.github.com>
This commit is contained in:
parent
ef0fb17e09
commit
bf8af29d68
6 changed files with 79 additions and 1 deletions
5
.changeset/famous-files-attend.md
Normal file
5
.changeset/famous-files-attend.md
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
---
|
||||
'@hyperdx/app': minor
|
||||
---
|
||||
|
||||
feat: Toggle columns from LogSidePanel
|
||||
|
|
@ -482,6 +482,8 @@ function TraceSubpanel({
|
|||
onPropertyAddClick,
|
||||
generateChartUrl,
|
||||
generateSearchUrl,
|
||||
displayedColumns,
|
||||
toggleColumn,
|
||||
}: {
|
||||
logData: any;
|
||||
onClose: () => void;
|
||||
|
|
@ -493,6 +495,8 @@ function TraceSubpanel({
|
|||
}) => string;
|
||||
|
||||
onPropertyAddClick?: (name: string, value: string) => void;
|
||||
displayedColumns?: string[];
|
||||
toggleColumn?: (column: string) => void;
|
||||
}) {
|
||||
const date = new Date(logData.timestamp);
|
||||
const start = add(date, { minutes: -240 });
|
||||
|
|
@ -681,6 +685,8 @@ function TraceSubpanel({
|
|||
generateSearchUrl={generateSearchUrl}
|
||||
onClose={onClose}
|
||||
generateChartUrl={generateChartUrl}
|
||||
displayedColumns={displayedColumns}
|
||||
toggleColumn={toggleColumn}
|
||||
/>
|
||||
</ErrorBoundary>
|
||||
</>
|
||||
|
|
@ -1300,6 +1306,8 @@ function PropertySubpanel({
|
|||
generateSearchUrl,
|
||||
onClose,
|
||||
generateChartUrl,
|
||||
displayedColumns,
|
||||
toggleColumn,
|
||||
}: {
|
||||
logData: any;
|
||||
generateSearchUrl: (query?: string, timeRange?: [Date, Date]) => string;
|
||||
|
|
@ -1312,6 +1320,8 @@ function PropertySubpanel({
|
|||
}) => string;
|
||||
|
||||
onPropertyAddClick?: (key: string, value: string) => void;
|
||||
displayedColumns?: string[];
|
||||
toggleColumn?: (column: string) => void;
|
||||
}) {
|
||||
const [propertySearchValue, setPropertySearchValue] = useState('');
|
||||
const [isNestedView, setIsNestedView] = useLocalStorage(
|
||||
|
|
@ -1582,6 +1592,8 @@ function PropertySubpanel({
|
|||
}}
|
||||
valueRenderer={(raw, value, ...rawKeyPath) => {
|
||||
const keyPath = rawKeyPath.slice().reverse();
|
||||
const keyPathString = keyPath.join('.');
|
||||
|
||||
return (
|
||||
<div className="parent-hover-trigger d-inline-block px-2">
|
||||
<pre
|
||||
|
|
@ -1648,6 +1660,24 @@ function PropertySubpanel({
|
|||
</Button>
|
||||
</Link>
|
||||
) : null}
|
||||
|
||||
{!!toggleColumn && keyPath.length === 1 ? (
|
||||
<Button
|
||||
className="fs-8 text-muted-hover child-hover-trigger p-0"
|
||||
variant="link"
|
||||
as="a"
|
||||
title={
|
||||
displayedColumns?.includes(keyPathString)
|
||||
? `Remove ${keyPathString} column from results table`
|
||||
: `Add ${keyPathString} column to results table`
|
||||
}
|
||||
style={{ width: 20 }}
|
||||
onClick={() => toggleColumn(keyPathString)}
|
||||
>
|
||||
<i className="bi bi-table" />
|
||||
</Button>
|
||||
) : null}
|
||||
|
||||
<CopyToClipboard
|
||||
text={value}
|
||||
onCopy={() => {
|
||||
|
|
@ -2032,6 +2062,8 @@ export default function LogSidePanel({
|
|||
generateChartUrl,
|
||||
sortKey,
|
||||
isNestedPanel = false,
|
||||
displayedColumns,
|
||||
toggleColumn,
|
||||
}: {
|
||||
logId: string | undefined;
|
||||
onClose: () => void;
|
||||
|
|
@ -2048,6 +2080,8 @@ export default function LogSidePanel({
|
|||
}) => string;
|
||||
sortKey: string | undefined;
|
||||
isNestedPanel?: boolean;
|
||||
displayedColumns?: string[];
|
||||
toggleColumn?: (column: string) => void;
|
||||
}) {
|
||||
const contextZIndex = useZIndex();
|
||||
|
||||
|
|
@ -2222,6 +2256,8 @@ export default function LogSidePanel({
|
|||
generateSearchUrl={generateSearchUrl}
|
||||
generateChartUrl={generateChartUrl}
|
||||
onClose={_onClose}
|
||||
displayedColumns={displayedColumns}
|
||||
toggleColumn={toggleColumn}
|
||||
/>
|
||||
<EventTagSubpanel
|
||||
logData={logData}
|
||||
|
|
@ -2251,6 +2287,8 @@ export default function LogSidePanel({
|
|||
generateSearchUrl={generateSearchUrl}
|
||||
generateChartUrl={generateChartUrl}
|
||||
onClose={_onClose}
|
||||
displayedColumns={displayedColumns}
|
||||
toggleColumn={toggleColumn}
|
||||
/>
|
||||
</div>
|
||||
) : null}
|
||||
|
|
|
|||
|
|
@ -784,6 +784,8 @@ export default function LogTable({
|
|||
onEnd,
|
||||
onShowPatternsClick,
|
||||
tableId,
|
||||
displayedColumns,
|
||||
setDisplayedColumns,
|
||||
}: {
|
||||
config: {
|
||||
where: string;
|
||||
|
|
@ -802,10 +804,11 @@ export default function LogTable({
|
|||
onEnd?: () => void;
|
||||
onShowPatternsClick?: () => void;
|
||||
tableId?: string;
|
||||
displayedColumns: string[];
|
||||
setDisplayedColumns: (columns: string[]) => void;
|
||||
}) {
|
||||
const [instructionsOpen, setInstructionsOpen] = useState(false);
|
||||
const [settingsOpen, setSettingsOpen] = useState(false);
|
||||
const [displayedColumns, setDisplayedColumns] = useState<string[]>([]);
|
||||
const [wrapLines, setWrapLines] = useState(false);
|
||||
|
||||
const prevQueryConfig = usePrevious({ searchedQuery, isLive });
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@ import usePortal from 'react-useportal';
|
|||
import type { LogView } from './types';
|
||||
import LogSidePanel from './LogSidePanel';
|
||||
import LogTable from './LogTable';
|
||||
import { useDisplayedColumns } from './useDisplayedColumns';
|
||||
|
||||
export function LogTableWithSidePanel({
|
||||
config,
|
||||
|
|
@ -82,6 +83,9 @@ export function LogTableWithSidePanel({
|
|||
|
||||
const voidFn = useCallback(() => {}, []);
|
||||
|
||||
const { displayedColumns, setDisplayedColumns, toggleColumn } =
|
||||
useDisplayedColumns();
|
||||
|
||||
return (
|
||||
<>
|
||||
{openedLog != null ? (
|
||||
|
|
@ -95,6 +99,8 @@ export function LogTableWithSidePanel({
|
|||
onPropertyAddClick={onPropertyAddClick}
|
||||
generateSearchUrl={generateSearchUrl}
|
||||
generateChartUrl={generateChartUrl}
|
||||
displayedColumns={displayedColumns}
|
||||
toggleColumn={toggleColumn}
|
||||
/>
|
||||
</Portal>
|
||||
) : null}
|
||||
|
|
@ -114,6 +120,8 @@ export function LogTableWithSidePanel({
|
|||
[setOpenedLog, onRowExpandClick],
|
||||
)}
|
||||
onEnd={onSettled}
|
||||
displayedColumns={displayedColumns}
|
||||
setDisplayedColumns={setDisplayedColumns}
|
||||
/>
|
||||
</>
|
||||
);
|
||||
|
|
|
|||
|
|
@ -45,6 +45,7 @@ import SearchPageActionBar from './SearchPageActionBar';
|
|||
import { useTimeQuery } from './timeQuery';
|
||||
import { MemoPatternTableWithSidePanel } from './PatternTableWithSidePanel';
|
||||
import { ErrorBoundary } from 'react-error-boundary';
|
||||
import { useDisplayedColumns } from './useDisplayedColumns';
|
||||
|
||||
const formatDate = (
|
||||
date: Date,
|
||||
|
|
@ -323,6 +324,9 @@ const LogViewerContainer = memo(function LogViewerContainer({
|
|||
[setOpenedLogQuery],
|
||||
);
|
||||
|
||||
const { displayedColumns, setDisplayedColumns, toggleColumn } =
|
||||
useDisplayedColumns();
|
||||
|
||||
return (
|
||||
<>
|
||||
<ErrorBoundary
|
||||
|
|
@ -346,6 +350,8 @@ const LogViewerContainer = memo(function LogViewerContainer({
|
|||
onPropertyAddClick={onPropertyAddClick}
|
||||
generateSearchUrl={generateSearchUrl}
|
||||
generateChartUrl={generateChartUrl}
|
||||
displayedColumns={displayedColumns}
|
||||
toggleColumn={toggleColumn}
|
||||
/>
|
||||
</ErrorBoundary>
|
||||
<LogTable
|
||||
|
|
@ -373,6 +379,8 @@ const LogViewerContainer = memo(function LogViewerContainer({
|
|||
[setOpenedLog, setIsLive],
|
||||
)}
|
||||
onShowPatternsClick={onShowPatternsClick}
|
||||
displayedColumns={displayedColumns}
|
||||
setDisplayedColumns={setDisplayedColumns}
|
||||
/>
|
||||
</>
|
||||
);
|
||||
|
|
|
|||
16
packages/app/src/useDisplayedColumns.ts
Normal file
16
packages/app/src/useDisplayedColumns.ts
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
import { useState } from 'react';
|
||||
|
||||
// TODO: Instead of prop drilling additional columns, we can consider using React.Context or Jotai
|
||||
export const useDisplayedColumns = () => {
|
||||
const [displayedColumns, setDisplayedColumns] = useState<string[]>([]);
|
||||
|
||||
const toggleColumn = (column: string) => {
|
||||
if (displayedColumns.includes(column)) {
|
||||
setDisplayedColumns(displayedColumns.filter(c => c !== column));
|
||||
} else {
|
||||
setDisplayedColumns([...displayedColumns, column]);
|
||||
}
|
||||
};
|
||||
|
||||
return { displayedColumns, setDisplayedColumns, toggleColumn };
|
||||
};
|
||||
Loading…
Reference in a new issue