Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Custom env variables #2

Open
wants to merge 29 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 23 commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
be85760
Add custom env form
AnastasiaSliusar Jul 10, 2024
f57183e
Add link from jupyterlab to jupyterserver for passing custom env vari…
AnastasiaSliusar Jul 11, 2024
3226375
Update the dialog
AnastasiaSliusar Jul 18, 2024
775cd68
Fix a dialog
AnastasiaSliusar Jul 19, 2024
9a5339c
Update a dialog, add css styles, saving user selection into kernelpre…
AnastasiaSliusar Jul 23, 2024
3b070bf
Add context menu on Laucher
AnastasiaSliusar Jul 24, 2024
de1702e
Merge branch 'jupyterlab:main' into custom-env-variables
AnastasiaSliusar Jul 24, 2024
91fc3a0
Automatic application of license header
github-actions[bot] Jul 24, 2024
00009c7
Fix context menu on each kernel icon on Launcher
AnastasiaSliusar Jul 24, 2024
802924b
Merge branch 'custom-env-variables' of https://github.com/AnastasiaSl…
AnastasiaSliusar Jul 24, 2024
e8c6a88
Fixing context menu on Launcher
AnastasiaSliusar Jul 25, 2024
d63760d
Fix running a kernel with custom env variables
AnastasiaSliusar Jul 26, 2024
b21f63c
Resolving merge conflicts
AnastasiaSliusar Jul 29, 2024
2e88b88
Fix a kernel selection dialog
AnastasiaSliusar Jul 30, 2024
774dabd
Fix showing checkbox
AnastasiaSliusar Jul 31, 2024
feb48de
Add support of calling a dialog for custom env variables for console …
AnastasiaSliusar Jul 31, 2024
d9f7ec6
Format code
AnastasiaSliusar Aug 1, 2024
55e31e5
Fix condition of showing a part of dialog for setuping custom env var…
AnastasiaSliusar Aug 1, 2024
765a2c4
Change name of the flag
AnastasiaSliusar Aug 6, 2024
7b18f44
Add tests
AnastasiaSliusar Aug 9, 2024
651732d
Fix lint and a test
AnastasiaSliusar Aug 15, 2024
56c53b6
Resolve conflicts
AnastasiaSliusar Aug 16, 2024
d959874
Fix tests
AnastasiaSliusar Aug 19, 2024
ed2fed8
Fix tests and eslint
AnastasiaSliusar Aug 20, 2024
7c11957
Update Playwright Snapshots
github-actions[bot] Aug 20, 2024
d45d3d4
Merge remote-tracking branch 'upstream/main' into custom-env-variables
AnastasiaSliusar Aug 20, 2024
a9e9a0e
Merge branch 'custom-env-variables' of https://github.com/AnastasiaSl…
AnastasiaSliusar Aug 20, 2024
f991f2b
Rename parameter
AnastasiaSliusar Aug 29, 2024
05fa30b
resolve conflicts
AnastasiaSliusar Sep 10, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
138 changes: 127 additions & 11 deletions packages/apputils/src/sessioncontext.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
// Copyright (c) Jupyter Development Team.
// Distributed under the terms of the Modified BSD License.

import { IChangedArgs, PathExt } from '@jupyterlab/coreutils';
import { IChangedArgs, PageConfig, PathExt } from '@jupyterlab/coreutils';
import {
Kernel,
KernelMessage,
Expand All @@ -16,12 +16,18 @@ import {
TranslationBundle
} from '@jupyterlab/translation';
import { find } from '@lumino/algorithm';
import { JSONExt, PromiseDelegate, UUID } from '@lumino/coreutils';
import {
JSONExt,
PartialJSONObject,
PromiseDelegate,
UUID
} from '@lumino/coreutils';
import { IDisposable, IObservableDisposable } from '@lumino/disposable';
import { ISignal, Signal } from '@lumino/signaling';
import { Widget } from '@lumino/widgets';
import * as React from 'react';
import { Dialog, showDialog } from './dialog';
import { CustomEnvWidget } from '@jupyterlab/ui-components';

/**
* A context object to manage a widget's kernel session connection.
Expand Down Expand Up @@ -301,6 +307,11 @@ export namespace ISessionContext {
* Skip showing the kernel restart dialog if checked (default `false`).
*/
readonly skipKernelRestartDialog?: boolean;

/**
* Custom kernel variables
*/
customEnvVars?: undefined | PartialJSONObject;
}

export type KernelDisplayStatus =
Expand Down Expand Up @@ -709,7 +720,14 @@ export class SessionContext implements ISessionContext {
preference
});
if (name) {
options = { name };
if (preference.customEnvVars) {
options = {
name,
custom_env_vars: preference.customEnvVars
};
} else {
options = { name };
}
}
}

Expand Down Expand Up @@ -1407,14 +1425,23 @@ export class SessionContextDialogs implements ISessionContext.IDialogs {
return;
}

const model = result.value as Kernel.IModel;

if (model && sessionContext.kernelPreference?.customEnvVars) {
sessionContext.kernelPreference.customEnvVars = undefined;
}

if (model.custom_env_vars) {
sessionContext.kernelPreference.customEnvVars = model.custom_env_vars;
}

if (hasCheckbox && result.isChecked !== null) {
sessionContext.kernelPreference = {
...sessionContext.kernelPreference,
autoStartDefault: result.isChecked
};
}

const model = result.value;
if (model === null && !sessionContext.hasNoKernel) {
return sessionContext.shutdown();
}
Expand Down Expand Up @@ -1812,21 +1839,55 @@ namespace Private {
export const createKernelSelector = (
sessionContext: ISessionContext,
translator?: ITranslator
) =>
new KernelSelector({
node: createSelectorNode(sessionContext, translator)
});
) => new KernelSelector(sessionContext, translator);

/**
* A widget that provides a kernel selection.
*/
class KernelSelector extends Widget {
export class KernelSelector extends Widget {
sessionContext: ISessionContext;
translator: ITranslator | undefined;

constructor(sessionContext: ISessionContext, translator?: ITranslator) {
super({ node: createSelectorNode(sessionContext, translator) });
this.sessionContext = sessionContext;
this.translator = translator;
}
/**
* Get the value of the kernel selector widget.
*/
getValue(): Kernel.IModel {
const selector = this.node.querySelector('select') as HTMLSelectElement;
return JSON.parse(selector.value) as Kernel.IModel;
let kernelData = JSON.parse(selector.value) as Kernel.IModel;
let tmp = {} as PartialJSONObject;
const envVarsBlock = this.node.querySelector(
'div.jp-custom-env-vars-block'
);

if (envVarsBlock) {
let customEnvParameters = envVarsBlock.getAttribute(
'data-custom-env-vars'
);
if (customEnvParameters) {
let envParameters = JSON.parse(
customEnvParameters
) as PartialJSONObject;

for (let index in envParameters) {
let env = envParameters[index] as PartialJSONObject;
let envName: string =
env && typeof env.name === 'string' ? env.name : '';
let envValue: string =
env && typeof env.value === 'string' ? env.value : ('' as string);
if (envName && envValue) {
tmp[envName] = envValue;
}
}

kernelData['custom_env_vars'] = tmp;
}
}
return kernelData;
}
}

Expand All @@ -1853,25 +1914,80 @@ namespace Private {
sessionContext,
translator
);

const allowCustomEnvVariables =
PageConfig.getOption('allow_setup_custom_env_variables') === 'true'
? true
: false;
const envVarsDiv = document.createElement('div');
envVarsDiv.setAttribute('class', 'jp-custom-env-vars-block');
envVarsDiv.setAttribute('data-custom-env-vars', '');

if (options.disabled) select.disabled = true;
for (const group of options.groups) {
const { label, options } = group;
const optgroup = document.createElement('optgroup');
optgroup.label = label;
for (const { selected, text, title, value } of options) {
const option = document.createElement('option');
if (selected) option.selected = true;
if (selected) {
option.selected = true;
let val = JSON.parse(value);
let id = val && val.id ? val.id : '';
if (allowCustomEnvVariables && !id) {
let defaultEnvValue = {};
envVarsDiv.innerHTML = '';
addEnvBlock(envVarsDiv, defaultEnvValue, translator);
}
}

if (title) option.title = title;
option.text = text;
option.value = value;
optgroup.appendChild(option);
}
select.appendChild(optgroup);
}

select.onchange = () => {
let kernelData = JSON.parse(select.value) as Kernel.IModel;
envVarsDiv.innerHTML = '';
body.setAttribute('data-custom-env-vars', '');
if (allowCustomEnvVariables && !kernelData.id) {
let defaultEnvValue = {};
addEnvBlock(envVarsDiv, defaultEnvValue, translator);
}
};
body.appendChild(select);
body.appendChild(envVarsDiv);
return body;
}

function addEnvBlock(
body: HTMLDivElement,
defaultEnvValues: PartialJSONObject,
translator?: ITranslator
) {
let envConfiguration: PartialJSONObject = {};
body.setAttribute('data-custom-env-vars', '');

let customEnvBlock = new CustomEnvWidget(
envConfiguration,
defaultEnvValues,
formData => {
envConfiguration = formData as PartialJSONObject;
body.setAttribute(
'data-custom-env-vars',
JSON.stringify(envConfiguration)
);
},
false,
translator
);

Widget.attach(customEnvBlock, body);
}

/**
* Get the default kernel name given select options.
*/
Expand Down
16 changes: 16 additions & 0 deletions packages/apputils/style/dialog.css
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,11 @@ button.jp-Dialog-close-button {
min-height: unset;
}

button.jp-Dialog-button.jp-mod-styled.js-custom-env {
margin-left: 5px;
margin-top: 5px;
}

.jp-Dialog-header {
display: flex;
justify-content: space-between;
Expand Down Expand Up @@ -151,3 +156,14 @@ button.jp-Dialog-close-button {
.jp-Dialog-button.jp-mod-styled:not(:last-child) {
margin-right: 12px;
}

.jp-Dialog-body .js-Dialog-form-custom-env span {
display: inline-block;
width: 40px;
margin-right: 10px;
}

.jp-Dialog-body .js-Dialog-form-custom-env input {
margin-top: 10px;
margin-bottom: 10px;
}
31 changes: 31 additions & 0 deletions packages/apputils/test/sessioncontext.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,8 @@ describe('@jupyterlab/apputils', () => {
// eslint-disable-next-line camelcase
allow_external_kernels: true,
// eslint-disable-next-line camelcase
allow_setup_custom_env_variables: true,
// eslint-disable-next-line camelcase
external_connection_dir: external
}
}
Expand Down Expand Up @@ -165,6 +167,25 @@ describe('@jupyterlab/apputils', () => {
});
});

describe('#kernelChanged with custom env variables', () => {
it('should be emitted when the kernel changes', async () => {
let called = false;
sessionContext.kernelChanged.connect(
(sender, { oldValue, newValue }) => {
if (oldValue !== null) {
return;
}
expect(sender).toBe(sessionContext);
expect(oldValue).toBeNull();
expect(newValue).toBe(sessionContext.session?.kernel || null);
called = true;
}
);
await sessionContext.initialize();
expect(called).toBe(true);
});
});

describe('#sessionChanged', () => {
it('should be emitted when the session changes', async () => {
let called = false;
Expand Down Expand Up @@ -477,6 +498,16 @@ describe('@jupyterlab/apputils', () => {
expect(kernel.name).toBe(name);
});

it('should change the current kernel and have custom_env_vars', async () => {
await sessionContext.initialize();

const name = sessionContext.session?.kernel?.name;
const id = sessionContext.session?.kernel?.id;
const customEnvVars = {'TEST_ENV_NAME': 'test_env_value'}
const kernel = (await sessionContext.changeKernel({ name, custom_env_vars:customEnvVars }))!;
expect(kernel.id).not.toBe(id);
});

it('should still work if called before fully initialized', async () => {
const initPromise = sessionContext.initialize(); // Start but don't finish init.
const name = 'echo';
Expand Down
Loading
Loading