Skip to content

Commit 34b85a8

Browse files
authored
1 parent 6914a31 commit 34b85a8

File tree

2 files changed

+404
-79
lines changed

2 files changed

+404
-79
lines changed

packages/databricks-vscode/src/run/WorkflowOutputPanel.ts

Lines changed: 74 additions & 79 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,8 @@ import {
44
jobs,
55
ApiClientResponseError,
66
} from "@databricks/databricks-sdk";
7-
import {basename} from "path";
7+
import {basename} from "node:path";
8+
import * as fs from "node:fs/promises";
89
import {
910
CancellationToken,
1011
CancellationTokenSource,
@@ -80,12 +81,7 @@ export async function runAsWorkflow({
8081
token: cancellation.token,
8182
});
8283
let htmlContent = response.views![0].content;
83-
// window.parent doesn't exist in a Webview
84-
htmlContent = htmlContent?.replace(
85-
"<script>window.__STATIC_SETTINGS__",
86-
"<script>window.parent = { postMessage: function() {}}; window.__STATIC_SETTINGS__"
87-
);
88-
panel.html = htmlContent || "";
84+
panel.showHtmlResult(htmlContent || "");
8985
} else {
9086
let response = await cluster.runPythonAndWait({
9187
path: syncDestination.localToRemoteNotebook(program) + ".py",
@@ -120,7 +116,9 @@ export async function runAsWorkflow({
120116
export class WorkflowOutputPanel {
121117
private run?: WorkflowRun;
122118
constructor(private panel: WebviewPanel, private extensionUri: Uri) {
123-
panel.webview.html = this.getWebviewContent("Starting ...");
119+
this.getWebviewContent().then((html) => {
120+
panel.webview.html = html;
121+
});
124122
}
125123

126124
onDidDispose(listener: () => void): Disposable {
@@ -135,47 +133,26 @@ export class WorkflowOutputPanel {
135133
this.panel.webview.html = htmlContent;
136134
}
137135

136+
showHtmlResult(htmlContent: string) {
137+
this.panel.webview.postMessage({
138+
fn: "setOutputHtml",
139+
args: [htmlContent],
140+
});
141+
}
142+
138143
showStdoutResult(output: string) {
139-
/* html */
140-
this.html = `<html>
141-
<head>
142-
<script type="module" src="${this.getToolkitUri()}"></script>
143-
<body>
144-
<h1>Output</h1>
145-
<hr>
146-
<pre>${output}</pre>
147-
</body>
148-
</html>`;
144+
this.panel.webview.postMessage({
145+
fn: "setStdout",
146+
args: [output],
147+
});
149148
}
150149

150+
// TODO: use new webview to render errors
151151
showError({message, stack}: {message?: string; stack?: string}) {
152-
/* html */
153-
this.html = [
154-
`<html>
155-
<head>
156-
<script type="module" src="${this.getToolkitUri()}"></script>
157-
<style>
158-
.alert-error {
159-
padding: 8px;
160-
color: rgb(200, 45, 76);
161-
border-color: rgb(251, 208, 216);
162-
background-color: #FFF5F7;
163-
border: 1px solid #FBD0D8;
164-
border-radius: 4px;
165-
overflow: scroll;
166-
}
167-
</style>
168-
</head>
169-
<body>
170-
<h1>Error</h1><hr>`,
171-
message ? `<pre class="alert-error">${message}</pre>` : "",
172-
stack ? `<pre class="alert-error">${stack}</pre>` : "",
173-
this.run?.runPageUrl
174-
? `<vscode-link href="${this.run?.runPageUrl}">View job on Databricks</vscode-link>`
175-
: "",
176-
`</body>
177-
</html>`,
178-
].join("\n");
152+
this.panel.webview.postMessage({
153+
fn: "setError",
154+
args: [message, stack],
155+
});
179156
}
180157

181158
updateState(state: jobs.RunLifeCycleState, run: WorkflowRun) {
@@ -185,6 +162,43 @@ export class WorkflowOutputPanel {
185162
state,
186163
pageUrl: run.runPageUrl,
187164
});
165+
166+
const task = run.tasks![0];
167+
const cluster = task.cluster_instance;
168+
169+
let clusterUrl = "#";
170+
if (cluster) {
171+
clusterUrl = `https://${
172+
new URL(run.runPageUrl).hostname
173+
}/#setting/sparkui/${cluster.cluster_id}/driver-${
174+
cluster.spark_context_id
175+
}`;
176+
}
177+
178+
this.panel.webview.postMessage({
179+
fn: "updateDetails",
180+
args: [
181+
{
182+
runUrl: run.runPageUrl,
183+
runId: task.run_id,
184+
clusterUrl,
185+
clusterId: cluster?.cluster_id || "-",
186+
started: task.start_time
187+
? new Date(task.start_time).toLocaleString()
188+
: "-",
189+
ended: task.end_time
190+
? new Date(task.end_time).toLocaleString()
191+
: "-",
192+
status: state,
193+
},
194+
],
195+
});
196+
if (task.end_time) {
197+
this.panel.webview.postMessage({
198+
fn: "stop",
199+
args: [],
200+
});
201+
}
188202
}
189203

190204
getToolkitUri(): Uri {
@@ -197,39 +211,20 @@ export class WorkflowOutputPanel {
197211
);
198212
}
199213

200-
private getWebviewContent(message: string): string {
201-
/* html */
202-
return `<html>
203-
<head>
204-
<script type="module" src="${this.getToolkitUri()}"></script>
205-
</head>
206-
<body>
207-
<div style="margin:20px; display: flex; justify-content: center; width: 100%"><vscode-progress-ring></vscode-progress-ring></div>
208-
<div style="display: flex; justify-content: center; width: 100%"><span id="message">${message}</span> <span id="duration"></span></div>
209-
210-
<script>
211-
window.addEventListener('message', event => {
212-
const messageEl = document.getElementById("message")
213-
messageEl.innerHTML = "";
214-
215-
switch(event.data.type) {
216-
case "status":
217-
const message = 'State: ' + event.data.state + ' - <vscode-link href="' + event.data.pageUrl + '">View job on Databricks</vscode-link>';
218-
messageEl.innerHTML = message;
219-
break;
220-
221-
default:
222-
messageEl.innerText = event.data.message;
223-
break;
224-
}
225-
});
226-
227-
let start = Date.now();
228-
let interval = setInterval(function() {
229-
document.getElementById("duration").innerText = "(" + Math.floor((Date.now()-start) / 1000) + "s)";
230-
}, 300);
231-
</script>
232-
</body>
233-
</html>`;
214+
private async getWebviewContent(): Promise<string> {
215+
const htmlFile = Uri.joinPath(
216+
this.extensionUri,
217+
"webview-ui",
218+
"job.html"
219+
);
220+
let html = await fs.readFile(htmlFile.fsPath, "utf8");
221+
html = html
222+
.replace(/\/\*\* STRIP -> \*\*\/(.*?)\/\*\* <- STRIP \*\*\//gs, "")
223+
.replace(
224+
/src="[^"].*?\/toolkit.js"/g,
225+
`src="${this.getToolkitUri()}"`
226+
);
227+
228+
return html;
234229
}
235230
}

0 commit comments

Comments
 (0)