Skip to content

Commit

Permalink
jupyter/explicit kernel selection: also cover case of "unknown" kernel
Browse files Browse the repository at this point in the history
  • Loading branch information
haraldschilly committed Nov 8, 2018
1 parent cfe1c77 commit fa962ac
Show file tree
Hide file tree
Showing 5 changed files with 99 additions and 28 deletions.
33 changes: 25 additions & 8 deletions src/smc-webapp/jupyter/actions.ts
Expand Up @@ -44,7 +44,7 @@ const cell_utils = require("./cell-utils");
const { cm_options } = require("./cm_options");

// map project_id (string) -> kernels (immutable)
import { Kernels } from "./util";
import { Kernels, TKernel } from "./util";
let jupyter_kernels = immutable.Map<string, Kernels>();

const { IPynbImporter } = require("./import-from-ipynb");
Expand Down Expand Up @@ -377,9 +377,8 @@ export class JupyterActions extends Actions<JupyterStoreState> {
this.setState({ kernels });
// We must also update the kernel info (e.g., display name), now that we
// know the kernels (e.g., maybe it changed or is now known but wasn't before).
this.setState({
kernel_info: this.store.get_kernel_info(this.store.get("kernel"))
});
const kernel_info = this.store.get_kernel_info(this.store.get("kernel"));
this.setState({ kernel_info });
};

set_jupyter_kernels = () => {
Expand Down Expand Up @@ -888,6 +887,11 @@ export class JupyterActions extends Actions<JupyterStoreState> {
this.set_backend_kernel_info();
this.set_cm_options();
}

// unkown kernel name
if (!this._is_project && obj.kernel_info == null) {
this.show_select_kernel();
}
break;
}
});
Expand Down Expand Up @@ -3180,15 +3184,28 @@ export class JupyterActions extends Actions<JupyterStoreState> {
const kernel_selection = this.store.get_kernel_selection(kernels);
const kernels_by_name = this.store.get_kernels_by_name(kernels);
const default_kernel = this.store.get_default_kernel();
let closestKernel: TKernel | undefined = undefined;
const kernel = this.store.get("kernel");
const kernel_info = this.store.get_kernel_info(kernel);
// unknown kernel, we try to find a close match
if (kernel_info == null) {
closestKernel = misc.closest_kernel_match(kernel, kernels);
}
this.setState({
kernel_selection: kernel_selection,
kernels_by_name: kernels_by_name,
default_kernel: default_kernel
show_kernel_selector: true,
kernel_selection,
kernels_by_name,
default_kernel,
closestKernel
});
};

hide_select_kernel = (): void => {
this.setState({ kernel_selection: undefined, kernels_by_name: undefined });
this.setState({
show_kernel_selector: false,
kernel_selection: undefined,
kernels_by_name: undefined
});
};

select_kernel = (kernel_name: string | undefined): void => {
Expand Down
14 changes: 12 additions & 2 deletions src/smc-webapp/jupyter/main.tsx
Expand Up @@ -23,6 +23,7 @@ const { KeyboardShortcuts } = require("./keyboard-shortcuts");
const { JSONView } = require("./json-view");
const { RawEditor } = require("./raw-editor");
const { ExamplesDialog } = require("smc-webapp/assistant/dialog");
import { TKernel } from "./util";

const KERNEL_STYLE: React.CSSProperties = {
position: "absolute",
Expand Down Expand Up @@ -75,9 +76,12 @@ interface JupyterEditorProps {
raw_ipynb?: immutable.Map<any, any>;
metadata?: immutable.Map<any, any>;
trust?: boolean;
kernel_info: immutable.Map<any, any>;
show_kernel_selector?: boolean;
kernel_selection?: immutable.Map<string, any>;
kernels_by_name?: immutable.OrderedMap<string, immutable.Map<string, string>>;
default_kernel?: string;
closestKernel?: TKernel;
}

class JupyterEditor0 extends Component<JupyterEditorProps> {
Expand Down Expand Up @@ -122,9 +126,12 @@ class JupyterEditor0 extends Component<JupyterEditorProps> {
raw_ipynb: rtypes.immutable.Map,
metadata: rtypes.immutable.Map,
trust: rtypes.bool,
kernel_info: rtypes.immutable.Map,
show_kernel_selector: rtypes.bool,
kernel_selection: rtypes.immutable.Map,
kernels_by_name: rtypes.immutable.Map,
default_kernel: rtypes.string
default_kernel: rtypes.string,
closestKernel: rtypes.immutable.Map
}
};
}
Expand Down Expand Up @@ -339,9 +346,11 @@ class JupyterEditor0 extends Component<JupyterEditorProps> {
<KernelSelector
actions={this.props.actions}
kernel={this.props.kernel}
kernel_info={this.props.kernel_info}
kernel_selection={this.props.kernel_selection}
kernels_by_name={this.props.kernels_by_name}
default_kernel={this.props.default_kernel}
closestKernel={this.props.closestKernel}
/>
);
}
Expand Down Expand Up @@ -403,7 +412,8 @@ class JupyterEditor0 extends Component<JupyterEditorProps> {
}

render_main() {
if (this.props.kernel_selection == null) {
const ks = this.props.show_kernel_selector;
if (ks == null || ks == false) {
return (
<>
{this.render_main_view()}
Expand Down
71 changes: 56 additions & 15 deletions src/smc-webapp/jupyter/select-kernel.tsx
Expand Up @@ -8,14 +8,16 @@ import {
OrderedMap /*, List as ImmutableList*/
} from "immutable";
// import { Kernels } from "./util";
const { Icon, Markdown, Space } = require("../r_misc"); // TODO: import types
const { Icon, Markdown, Space, Loading } = require("../r_misc"); // TODO: import types
const {
Button,
Col,
Row,
MenuItem,
DropdownButton
DropdownButton,
Alert
} = require("react-bootstrap"); // TODO: import types
import { TKernel } from "./util";

const row_style: React.CSSProperties = {
marginTop: "5px",
Expand All @@ -25,9 +27,11 @@ const row_style: React.CSSProperties = {
interface IKernelSelectorProps {
actions: any;
kernel?: string;
kernel_info?: any;
default_kernel?: string;
kernel_selection?: ImmutableMap<string, string>;
kernels_by_name?: OrderedMap<string, ImmutableMap<string, string>>;
closestKernel?: TKernel;
}

interface IKernelSelectorState {
Expand Down Expand Up @@ -225,12 +229,17 @@ export class KernelSelector extends Component<

render_top() {
if (this.props.kernel == null) {
let msg: string;
if (this.props.kernel_info != null) {
msg = "This notebook kernel is unknown.";
} else {
msg = "This notebook has no kernel.";
}
return (
<>
<strong>This notebook has no kernel set.</strong> A kernel is required
in order to evaluate the code in the notebook. Based on the
programming language you want to work with, you have to select one.
(Otherwise you can only view it.)
<strong>{msg}</strong> A working kernel is required in order to
evaluate the code in the notebook. Based on the programming language
you want to work with, you have to select one.
</>
);
} else {
Expand All @@ -243,25 +252,57 @@ export class KernelSelector extends Component<
}
}

render() {
if (this.props.kernel_selection == null) return;
render_unknown() {
const closestKernel = this.props.closestKernel;
if (this.props.kernel_info != null || closestKernel == null) return;

const closestKernelDisplayName = closestKernel.get("display_name");
const closestKernelName = closestKernel.get("name");

return (
<Row style={row_style}>
<Alert bsStyle={"danger"}>
<h3>Kernel unknown</h3>
<div>
Maybe select {closestKernelDisplayName}{" "}
<code>{closestKernelName}</code>
</div>
</Alert>
</Row>
);
}

render() {
const style: React.CSSProperties = {
padding: "20px 40px",
overflowY: "auto",
overflowX: "hidden",
height: "90%"
};

let body: Rendered;
if (
this.props.kernels_by_name == null ||
this.props.kernel_selection == null
) {
body = <Loading />;
} else {
body = (
<>
<Row style={row_style}>
<h3>{"Select a Kernel"}</h3>
</Row>
<Row style={row_style}>{this.render_top()}</Row>
{this.render_unknown()}
<Row style={row_style}>{this.render_last()}</Row>
<Row style={row_style}>{this.render_suggested()}</Row>
<Row style={row_style}>{this.render_all()}</Row>
</>
);
}
return (
<Col style={style} md={6} mdOffset={3}>
<Row style={row_style}>
<h3>{"Select a Kernel"}</h3>
</Row>
<Row style={row_style}>{this.render_top()}</Row>
<Row style={row_style}>{this.render_last()}</Row>
<Row style={row_style}>{this.render_suggested()}</Row>
<Row style={row_style}>{this.render_all()}</Row>
{body}
</Col>
);
}
Expand Down
6 changes: 4 additions & 2 deletions src/smc-webapp/jupyter/store.ts
Expand Up @@ -9,7 +9,7 @@ import { Store } from "../app-framework";
import { Set, Map as ImmutableMap, OrderedMap } from "immutable";
const { export_to_ipynb } = require("./export-to-ipynb");
const { DEFAULT_COMPUTE_IMAGE } = require("smc-util/compute-images");
import { Kernels } from "./util";
import { Kernels, TKernel } from "./util";

// Used for copy/paste. We make a single global clipboard, so that
// copy/paste between different notebooks works.
Expand All @@ -31,7 +31,7 @@ export interface JupyterStoreState {
has_uncommitted_changes?: boolean;
kernel: any | string;
kernels: any;
kernel_info: any;
kernel_info?: any;
max_output_length: number;
metadata: any;
md_edit_ids: Set<string>;
Expand All @@ -58,9 +58,11 @@ export interface JupyterStoreState {
confirm_dialog: any;
insert_image: any;
scroll: any;
show_kernel_selector: boolean;
kernel_selection?: ImmutableMap<string, string>;
kernels_by_name?: OrderedMap<string, ImmutableMap<string, string>>;
default_kernel?: string;
closestKernel?: TKernel;
}

export class JupyterStore extends Store<JupyterStoreState> {
Expand Down
3 changes: 2 additions & 1 deletion src/smc-webapp/jupyter/util.ts
Expand Up @@ -25,4 +25,5 @@ export const JUPYTER_MIMETYPES = [
"text/plain"
];

export type Kernels = immutable.List<immutable.Map<string, string>>;
export type TKernel = immutable.Map<string, string>;
export type Kernels = immutable.List<TKernel>;

0 comments on commit fa962ac

Please sign in to comment.