diff --git a/scripts/copyassets.js b/scripts/copyassets.js index 70ba026b..28fc638b 100644 --- a/scripts/copyassets.js +++ b/scripts/copyassets.js @@ -61,6 +61,10 @@ function copyAssests() { path.join(srcDir, 'assets', 'jupyterlab-wordmark.svg'), path.join(dest, '../app-assets', 'jupyterlab-wordmark.svg') ); + fs.copySync( + path.join(srcDir, 'assets', 'copyable-span.js'), + path.join(dest, '../app-assets', 'copyable-span.js') + ); const toolkitPath = path.join( '../node_modules', diff --git a/src/assets/copyable-span.js b/src/assets/copyable-span.js new file mode 100644 index 00000000..17c62399 --- /dev/null +++ b/src/assets/copyable-span.js @@ -0,0 +1,70 @@ +const template = document.createElement('template'); +template.innerHTML = ` + +
+
+
+
+
+`; + +class CopyableSpan extends HTMLElement { + constructor() { + super(); + + this.attachShadow({ mode: 'open' }); + + this.shadowRoot.appendChild(template.content.cloneNode(true)); + this.shadowRoot.querySelector('.container').onclick = evt => { + window.electronAPI.copyToClipboard(evt.currentTarget.dataset.copied); + }; + } + + static get observedAttributes() { + return ['label', 'title', 'copied']; + } + + attributeChangedCallback(name, oldValue, newValue) { + switch (name) { + case 'label': + this.shadowRoot.querySelector('.label').innerText = decodeURIComponent( + newValue + ); + break; + case 'title': + this.shadowRoot.querySelector('.container').title = decodeURIComponent( + newValue + ); + break; + case 'copied': + this.shadowRoot.querySelector( + '.container' + ).dataset.copied = decodeURIComponent(newValue); + break; + } + } +} + +window.customElements.define('copyable-span', CopyableSpan); diff --git a/src/main/cli.ts b/src/main/cli.ts index b0728e99..08423c6a 100644 --- a/src/main/cli.ts +++ b/src/main/cli.ts @@ -449,22 +449,36 @@ export async function runCommandInEnvironment( ' && ' ); + // TODO: implement timeout. in case there is network issues + return new Promise((resolve, reject) => { const shell = isWin ? spawn('cmd', ['/c', commandScript], { - env: process.env + env: process.env, + windowsVerbatimArguments: true }) : spawn('bash', ['-c', commandScript], { - stdio: 'inherit', env: { ...process.env, BASH_SILENCE_DEPRECATION_WARNING: '1' } }); + if (shell.stdout) { + shell.stdout.on('data', chunk => { + console.debug('>', Buffer.from(chunk).toString()); + }); + } + if (shell.stderr) { + shell.stderr.on('data', chunk => { + console.error('>', Buffer.from(chunk).toString()); + }); + } + shell.on('close', code => { if (code !== 0) { console.error('Shell exit with code:', code); + resolve(false); } resolve(true); }); diff --git a/src/main/eventtypes.ts b/src/main/eventtypes.ts index a05dedc5..5f39aa51 100644 --- a/src/main/eventtypes.ts +++ b/src/main/eventtypes.ts @@ -55,7 +55,10 @@ export enum EventTypeMain { SetServerLaunchArgs = 'set-server-launch-args', SetServerEnvVars = 'set-server-env-vars', SetCtrlWBehavior = 'set-ctrl-w-behavior', - SetAuthDialogResponse = 'set-auth-dialog-response' + SetAuthDialogResponse = 'set-auth-dialog-response', + InstallPythonEnvRequirements = 'install-python-env-requirements', + ShowLogs = 'show-logs', + CopyToClipboard = 'copy-to-clipboard' } // events sent to Renderer process diff --git a/src/main/progressview/preload.ts b/src/main/progressview/preload.ts index 21deea5d..727b6978 100644 --- a/src/main/progressview/preload.ts +++ b/src/main/progressview/preload.ts @@ -34,6 +34,9 @@ contextBridge.exposeInMainWorld('electronAPI', { callback: InstallBundledPythonEnvStatusListener ) => { onInstallBundledPythonEnvStatusListener = callback; + }, + copyToClipboard: (content: string) => { + ipcRenderer.send(EventTypeMain.CopyToClipboard, content); } }); diff --git a/src/main/progressview/progressview.ts b/src/main/progressview/progressview.ts index 465dfb2f..053e015e 100644 --- a/src/main/progressview/progressview.ts +++ b/src/main/progressview/progressview.ts @@ -17,6 +17,9 @@ export class ProgressView { const progressLogo = fs.readFileSync( path.join(__dirname, '../../../app-assets/progress-logo.svg') ); + const copyableSpanSrc = fs.readFileSync( + path.join(__dirname, '../../../app-assets/copyable-span.js') + ); const template = `