Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(overlay): added copy filename and changed styling of error frame #550

Merged
merged 6 commits into from
Nov 6, 2024
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions .changeset/shaggy-dodos-sparkle.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
'@spotlightjs/overlay': patch
---

- Added copy filename button on error frame.
- changed styling of error frames.
3 changes: 3 additions & 0 deletions packages/overlay/src/assets/check.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
5 changes: 5 additions & 0 deletions packages/overlay/src/assets/copy.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
4 changes: 3 additions & 1 deletion packages/overlay/src/assets/pen.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
25 changes: 25 additions & 0 deletions packages/overlay/src/components/CopyToClipboard.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import { useState } from 'react';
import { ReactComponent as CheckIcon } from '~/assets/check.svg';
import { ReactComponent as CopyIcon } from '~/assets/copy.svg';

export default function CopyToClipboard({ data }: { data: string }) {
const [isCopied, setIsCopied] = useState(false);
return isCopied ? (
<CheckIcon width={18} height={18} title="Copy filename" className="stroke-primary-50 transition-all" />
) : (
<CopyIcon
width={18}
height={18}
title="Copy filename"
className="stroke-primary-50 transition-all"
onClick={evt => {
evt.stopPropagation();
navigator.clipboard.writeText(data);
setTimeout(() => {
setIsCopied(false);
}, 1000);
setIsCopied(true);
}}
/>
);
}
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ export function ErrorItem({ event }: { event: SentryErrorEvent }) {
<strong className="text-xl">{value.type}</strong>
<pre>{value.value}</pre>
</h3>
<ul className="border-primary-600 border">
<ul>
{value.stacktrace?.frames.map((frame, frameIdx) => {
return (
<Frame
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { useState } from 'react';
import { ReactComponent as PenIcon } from '~/assets/pen.svg';
import CopyToClipboard from '~/components/CopyToClipboard';
import { renderValue } from '~/utils/values';
import classNames from '../../../../../lib/classNames';
import { EventFrame, FrameVars } from '../../../types';
Expand Down Expand Up @@ -51,47 +52,59 @@ export default function Frame({
const hasSource = !!frame.context_line;
const fileName = platform === 'java' ? frame.module : frame.filename || frame.module;
return (
<li className="border-primary-900 bg-primary-900 border-b last:border-b-0">
<li
className={classNames(
hasSource ? 'cursor-pointer' : '',
!isOpen && hasSource ? 'hover:bg-primary-900' : '',
'bg-primary-950 border-primary-900 my-1 overflow-hidden rounded-md border',
)}
>
<div
className={classNames(
hasSource ? 'hover:bg-primary-800 cursor-pointer' : '',
'border-primary-950 text-primary-400 border-b px-2 py-1',
'text-primary-400 flex items-center justify-between px-2 py-1',
isOpen ? 'bg-primary-900' : '',
)}
onClick={hasSource ? () => setOpen(!isOpen) : undefined}
>
{fileName ? (
<span className="text-primary-100">
{formatFilename(fileName)}
{' in '}
</span>
) : null}

<span className="text-primary-100">{frame.function}</span>
{frame.lineno !== undefined && (
<>
{' '}
at line{' '}
<div>
{fileName ? (
<span className="text-primary-100">
{frame.lineno}
{frame.colno !== undefined && `:${frame.colno}`}
{formatFilename(fileName)}
{' in '}
</span>
</>
)}
{isOpen && !frame.filename?.includes(':') ? (
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

looks like we missed this condition !frame.filename?.includes(':')

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This was intentional but we can revisit the decision in the future if necessary.

<PenIcon
width={18}
height={18}
title="Open in editor"
className="mx-2 inline fill-green-400 stroke-green-400 align-top"
onClick={evt => {
fetch('http://localhost:8969/open', {
method: 'POST',
body: `${frame.filename}:${frame.lineno}:${frame.colno}`,
credentials: 'omit',
});
evt.stopPropagation();
}}
/>
) : null}

<span className="text-primary-100">{frame.function}</span>
{frame.lineno !== undefined && (
<>
{' '}
at line{' '}
<span className="text-primary-100">
{frame.lineno}
{frame.colno !== undefined && `:${frame.colno}`}
</span>
</>
)}
</div>
{!frame.filename?.includes(':') ? (
<div className="flex items-center gap-2">
<PenIcon
width={18}
height={18}
title="Open in editor"
className="stroke-primary-100"
onClick={evt => {
fetch('http://localhost:8969/open', {
method: 'POST',
body: `${frame.filename}:${frame.lineno}:${frame.colno}`,
credentials: 'omit',
});
evt.stopPropagation();
}}
/>

<CopyToClipboard data={frame.filename!} />
</div>
) : null}
</div>
{isOpen && (
Expand Down
Loading