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 = `