Skip to content

Commit 1e02036

Browse files
ui: add inline iframe viewer on advanced debug for detail files (#165955)
ui: add inline iframe viewer on advanced debug for detail files
2 parents 872d1c4 + c55ee7f commit 1e02036

4 files changed

Lines changed: 265 additions & 121 deletions

File tree

pkg/ui/ui.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ const (
3636
cspHeader = "default-src 'self'; " +
3737
"style-src 'self' 'unsafe-inline'; " +
3838
"font-src 'self' data:; " +
39+
"frame-src 'self' blob: https://cockroachdb.github.io; " +
3940
"img-src 'self' data:; " +
4041
"connect-src 'self' https://register.cockroachdb.com;"
4142
)
Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
// Copyright 2026 The Cockroach Authors.
2+
//
3+
// Use of this software is governed by the CockroachDB Software License
4+
// included in the /LICENSE file.
5+
6+
import { Button, Icon } from "@cockroachlabs/ui-components";
7+
import classnames from "classnames/bind";
8+
import React, { useCallback } from "react";
9+
10+
import styles from "./jobProfilerView.module.scss";
11+
12+
const cx = classnames.bind(styles);
13+
14+
interface ExecutionDetailViewerProps {
15+
filename: string;
16+
blobUrl: string;
17+
onClose: () => void;
18+
}
19+
20+
export const ExecutionDetailViewer: React.FC<ExecutionDetailViewerProps> = ({
21+
filename,
22+
blobUrl,
23+
onClose,
24+
}) => {
25+
const openInNewTab = useCallback(() => {
26+
// Blob URL already exists so this is synchronous and won't
27+
// trigger popup blockers.
28+
window.open(blobUrl, "_blank");
29+
}, [blobUrl]);
30+
31+
return (
32+
<div className={cx("viewer-overlay")} onClick={onClose}>
33+
<div className={cx("viewer-panel")} onClick={e => e.stopPropagation()}>
34+
<div className={cx("viewer-header")}>
35+
<span className={cx("viewer-filename")}>{filename}</span>
36+
<span className={cx("viewer-actions")}>
37+
<Button
38+
as="a"
39+
size="small"
40+
intent="tertiary"
41+
onClick={openInNewTab}
42+
aria-label="Open in new tab"
43+
>
44+
<Icon iconName="Open" />
45+
</Button>
46+
<Button
47+
as="a"
48+
size="small"
49+
intent="tertiary"
50+
onClick={onClose}
51+
aria-label="Close"
52+
>
53+
<Icon iconName="Cancel" />
54+
</Button>
55+
</span>
56+
</div>
57+
<iframe
58+
src={blobUrl}
59+
className={cx("viewer-iframe")}
60+
sandbox="allow-same-origin allow-scripts"
61+
title={filename}
62+
/>
63+
</div>
64+
</div>
65+
);
66+
};

pkg/ui/workspaces/cluster-ui/src/jobs/jobDetailsPage/jobProfilerView.module.scss

Lines changed: 77 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -6,34 +6,96 @@
66
@import "src/core/index.module";
77

88
.crl-job-profiler-view {
9-
&__actions-column {
10-
display: flex;
11-
flex-direction: row;
12-
flex-wrap: nowrap;
13-
justify-content: flex-end;
14-
}
9+
&__actions-column {
10+
display: flex;
11+
flex-direction: row;
12+
flex-wrap: nowrap;
13+
justify-content: flex-end;
14+
}
1515
}
1616

1717
.column-size-medium {
18-
width: 230px;
18+
width: 230px;
1919
}
2020

2121
.view-execution-detail-button {
22-
white-space: nowrap;
22+
white-space: nowrap;
2323

24-
>svg {
25-
margin-right: $spacing-x-small;
26-
}
24+
> svg {
25+
margin-right: $spacing-x-small;
26+
}
2727
}
2828

2929
.download-execution-detail-button {
30-
white-space: nowrap;
30+
white-space: nowrap;
3131

32-
>svg {
33-
margin-right: $spacing-x-small;
34-
}
32+
> svg {
33+
margin-right: $spacing-x-small;
34+
}
3535
}
3636

3737
.full-width {
3838
width: 100%;
3939
}
40+
41+
// Execution detail viewer overlay and panel.
42+
.viewer-overlay {
43+
position: fixed;
44+
top: 0;
45+
left: 0;
46+
right: 0;
47+
bottom: 0;
48+
background: rgba(0, 0, 0, 0.15);
49+
z-index: 1000;
50+
display: flex;
51+
align-items: center;
52+
justify-content: center;
53+
}
54+
55+
.viewer-panel {
56+
background-color: white;
57+
border: 0.5px solid $colors--neutral-2;
58+
border-radius: 8px;
59+
box-shadow: 0 0 4px rgba(154, 161, 171, 0.33);
60+
width: 98vw;
61+
height: 98vh;
62+
display: flex;
63+
flex-direction: column;
64+
overflow: hidden;
65+
}
66+
67+
.viewer-header {
68+
display: flex;
69+
align-items: center;
70+
justify-content: space-between;
71+
padding: 12px 16px;
72+
border-bottom: 0.5px solid $colors--neutral-2;
73+
}
74+
75+
.viewer-filename {
76+
font-family: $font-family--base;
77+
font-weight: $font-weight--bold;
78+
font-size: $font-size--small;
79+
line-height: $line-height--small;
80+
letter-spacing: 0.3px;
81+
color: $colors--neutral-7;
82+
overflow: hidden;
83+
text-overflow: ellipsis;
84+
white-space: nowrap;
85+
min-width: 0;
86+
}
87+
88+
.viewer-actions {
89+
display: flex;
90+
gap: 8px;
91+
flex-shrink: 0;
92+
margin-left: 16px;
93+
}
94+
95+
.viewer-iframe {
96+
width: 100%;
97+
border: none;
98+
display: block;
99+
flex: 1;
100+
min-height: 0;
101+
}

0 commit comments

Comments
 (0)