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" ;
89import {
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({
120116export 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 ( / \/ \* \* S T R I P - > \* \* \/ ( .* ?) \/ \* \* < - S T R I P \* \* \/ / gs, "" )
223+ . replace (
224+ / s r c = " [ ^ " ] .* ?\/ t o o l k i t .j s " / g,
225+ `src="${ this . getToolkitUri ( ) } "`
226+ ) ;
227+
228+ return html ;
234229 }
235230}
0 commit comments