Skip to content

Commit 065cabd

Browse files
authored
fix: Update "Copy Object" in line viewer to work with nested objects and arrays (#1274)
Fixes: HDX-2617
1 parent 4cfbd75 commit 065cabd

File tree

3 files changed

+84
-12
lines changed

3 files changed

+84
-12
lines changed

.changeset/shy-carrots-wash.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"@hyperdx/app": patch
3+
---
4+
5+
fix: Update "Copy Object" in line viewer to work with nested objects and arrays

packages/app/src/components/DBRowJsonViewer.test.tsx

Lines changed: 68 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -52,15 +52,6 @@ describe('DBRowJsonViewer', () => {
5252
jest.clearAllMocks();
5353
});
5454

55-
// Helper function to simulate clicking a button in a line
56-
const clickLineButton = (fieldText: string, buttonText: string) => {
57-
const line = screen.getByText(fieldText).closest('.line')! as HTMLElement;
58-
fireEvent.mouseEnter(line);
59-
const lineMenu = line.querySelector('.lineMenu')! as HTMLElement;
60-
const button = within(lineMenu).getByText(buttonText);
61-
fireEvent.click(button);
62-
};
63-
6455
// Helper to render component
6556
const renderComponent = (data: any) => {
6657
return renderWithMantine(
@@ -70,6 +61,33 @@ describe('DBRowJsonViewer', () => {
7061
);
7162
};
7263

64+
// Helper to click a button on a line
65+
const clickLineButton = (fieldText: string, buttonText: string) => {
66+
const line = screen.getByText(fieldText).closest('.line')! as HTMLElement;
67+
fireEvent.mouseEnter(line);
68+
const button = within(line).getByText(buttonText);
69+
fireEvent.click(button);
70+
};
71+
72+
// Helper to expand a field and click a button on a nested field
73+
const expandAndClickButton = (
74+
parentField: string,
75+
childField: string,
76+
buttonText: string,
77+
) => {
78+
const parentLine = screen
79+
.getByText(parentField)
80+
.closest('.line')! as HTMLElement;
81+
fireEvent.click(parentLine);
82+
83+
const childLine = screen
84+
.getByText(childField)
85+
.closest('.line')! as HTMLElement;
86+
fireEvent.mouseEnter(childLine);
87+
const button = within(childLine).getByText(buttonText);
88+
fireEvent.click(button);
89+
};
90+
7391
it('formats log attributes correctly', () => {
7492
renderComponent(logData);
7593
clickLineButton('field1', 'Search');
@@ -136,4 +154,45 @@ describe('DBRowJsonViewer', () => {
136154
},
137155
);
138156
});
157+
158+
describe('copy functionality', () => {
159+
const mockClipboard = jest.fn();
160+
161+
beforeEach(() => {
162+
Object.assign(navigator, {
163+
clipboard: { writeText: mockClipboard },
164+
});
165+
});
166+
167+
it('copies array elements from expanded stringified JSON', () => {
168+
const arrayObject = { status: 'True', type: 'PodReady' };
169+
const data = { conditions: JSON.stringify([arrayObject]) };
170+
171+
renderComponent(data);
172+
expandAndClickButton('conditions', '0', 'Copy Object');
173+
174+
expect(mockClipboard).toHaveBeenCalledWith(
175+
JSON.stringify(arrayObject, null, 2),
176+
);
177+
});
178+
179+
it('copies entire stringified value when not expanded', () => {
180+
const arrayData = [{ type: 'Ready' }, { type: 'Init' }];
181+
const data = { conditions: JSON.stringify(arrayData) };
182+
183+
renderComponent(data);
184+
clickLineButton('conditions', 'Copy Value');
185+
186+
expect(mockClipboard).toHaveBeenCalledWith(JSON.stringify(arrayData));
187+
});
188+
189+
it('copies regular nested objects', () => {
190+
renderComponent(logData);
191+
clickLineButton('nested', 'Copy Object');
192+
193+
expect(mockClipboard).toHaveBeenCalledWith(
194+
JSON.stringify({ field3: 'nested value' }, null, 2),
195+
);
196+
});
197+
});
139198
});

packages/app/src/components/DBRowJsonViewer.tsx

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@ import { useAtom, useAtomValue } from 'jotai';
44
import { atomWithStorage } from 'jotai/utils';
55
import get from 'lodash/get';
66
import {
7-
ActionIcon,
87
Box,
98
Button,
109
Group,
@@ -344,8 +343,17 @@ export function DBRowJsonViewer({
344343
}
345344

346345
const handleCopyObject = () => {
347-
const copiedObj =
348-
keyPath.length === 0 ? rowData : get(rowData, keyPath);
346+
let copiedObj;
347+
348+
// When in parsed JSON context (e.g., expanded stringified JSON),
349+
// use the value directly since keyPath doesn't match rowData structure
350+
if (isInParsedJson && parsedJsonRootPath) {
351+
copiedObj = value;
352+
} else {
353+
// For regular nested objects, use keyPath to navigate rowData
354+
copiedObj = keyPath.length === 0 ? rowData : get(rowData, keyPath);
355+
}
356+
349357
window.navigator.clipboard.writeText(
350358
JSON.stringify(copiedObj, null, 2),
351359
);

0 commit comments

Comments
 (0)