Skip to content

Commit

Permalink
Turn into class component and hook kernelspy (#382)
Browse files Browse the repository at this point in the history
If we want to have the kernelspy handler to control the papyri browser
from the outside, we need to turn the functional component into a class
one for access the methods instead of having closures.

-- 

Create component ref and hook into the kernelspy.

This using the IPython extension and using `?` on an existing object, it
should pop out the right docstring.

    %load_ext papyri

    import numpy as np
    np.einsum?
  • Loading branch information
Carreau authored Jan 31, 2024
2 parents f6c56a3 + fdbb53f commit d665532
Show file tree
Hide file tree
Showing 2 changed files with 102 additions and 64 deletions.
3 changes: 2 additions & 1 deletion papyri-lab/src/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -86,9 +86,10 @@ const plugin: JupyterFrontEndPlugin<void> = {
}

const kernelSpy = new KernelSpyModel(notebookTracker);
kernelSpy.questionMarkSubmitted.connect((_, args) => {
kernelSpy.questionMarkSubmitted.connect((_, args: any) => {
console.info('KSpy questionMarkSubmitted args:', args);
if (args !== undefined) {
widget.content.updateSeachTerm(args.qualname);
console.info('DO your thing here.');
}
});
Expand Down
163 changes: 100 additions & 63 deletions papyri-lab/src/widgets.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { requestAPI } from './handler';
import { MyPapyri, RENDERERS, SearchContext } from './papyri-comp';
import { ReactWidget } from '@jupyterlab/apputils';
import { ThemeProvider } from '@myst-theme/providers';
import React, { useState } from 'react';
import React from 'react';

// this is a papyri react component that in the end should
// have navigation UI and a myst renderer to display the
Expand All @@ -14,33 +14,57 @@ import React, { useState } from 'react';
//
// I'm going to guess it will need some configuration hook for when we click on links.
//
const PapyriComponent = (): JSX.Element => {
// list of a few pages in the database that matches
// the current query
const [possibilities, setPossibilities] = useState([]);
const [navs, setNavs] = useState<string[]>([]);
const [root, setRoot] = useState({});
//
class PapyriComponent extends React.Component {
state = {
possibilities: [],
navs: [],
root: {},
searchterm: ''
};
constructor(props: any) {
super(props);
this.state = {
possibilities: [],
navs: [],
root: {},
searchterm: ''
};
}

const [searchTerm, setSearchTerm] = useState('');
setPossibilities(pos: any) {
this.setState({ possibilities: pos });
}

// callback when typing in the input field.
const onChange = async (event: any) => {
setSearchTerm(event.target.value);
search(event.target.value);
};
setNavs(navs: any) {
this.setState({ navs: navs });
}

const back = async () => {
navs.pop();
const pen = navs.pop();
setRoot(root: any) {
this.setState({ root: root });
}

setSearchTerm(searchterm: string) {
this.setState({ searchterm: searchterm });
}

async handleInputChange(event: any) {
console.log('on change, this is', this);
this.setSearchTerm(event.target.value);
this.search(event.target.value);
}

async back() {
this.state.navs.pop();
const pen = this.state.navs.pop();
if (pen !== undefined) {
console.log('Setting search term', pen);
await setSearchTerm(pen);
await this.setSearchTerm(pen);
console.log('... and searchg for ', pen);
await search(pen);
await this.search(pen);
}
};

const search = async (query: string) => {
}
async search(query: string) {
const res = await requestAPI<any>('get-example', {
body: query,
method: 'post'
Expand All @@ -49,69 +73,82 @@ const PapyriComponent = (): JSX.Element => {
// response has body (MyST–json if the query has an exact match)
// and data if we have some close matches.
if (res.body !== null) {
setNavs([...navs, query]);
setRoot(res.body);
setPossibilities([]);
this.setNavs([...this.state.navs, query]);
this.setRoot(res.body);
this.setPossibilities([]);
} else {
setRoot({});
setPossibilities(res.data);
this.setRoot({});
this.setPossibilities(res.data);
}
};
}

async onClick(query: string) {
console.log('On click trigger', query, 'this is', this);

const onClick = async (query: string) => {
console.log('On click trigger', query);
setSearchTerm(query);
this.setSearchTerm(query);
try {
search(query);
this.search(query);
} catch (e) {
console.error(e);
}
return false;
};
}

return (
<React.StrictMode>
<input onChange={onChange} value={searchTerm} />
<button onClick={back}>Back</button>
<ul>
{possibilities.map(e => {
return (
<li>
<a
href={e}
onClick={async () => {
await onClick(e);
}}
>
{e}
</a>
</li>
);
})}
</ul>
<div className="view">
<SearchContext.Provider value={onClick}>
<ThemeProvider renderers={RENDERERS}>
<MyPapyri node={root} />
</ThemeProvider>
</SearchContext.Provider>
</div>
</React.StrictMode>
);
};
render(): JSX.Element {
return (
<React.StrictMode>
<input
onChange={this.handleInputChange.bind(this)}
value={this.state.searchterm}
/>
<button onClick={this.back}>Back</button>
<ul>
{this.state.possibilities.map((e: any) => {
return (
<li>
<a
href={e}
onClick={async () => {
await this.onClick(e);
}}
>
{e}
</a>
</li>
);
})}
</ul>
<div className="view">
<SearchContext.Provider value={this.onClick.bind(this)}>
<ThemeProvider renderers={RENDERERS}>
<MyPapyri node={this.state.root} />
</ThemeProvider>
</SearchContext.Provider>
</div>
</React.StrictMode>
);
}
}

// This seem to be the way to have an adapter between lumino and react, and
// allow to render react inside a JupyterLab panel
export class PapyriPanel extends ReactWidget {
comp: any;
constructor() {
super();
this.addClass('jp-ReactWidget');
this.id = 'papyri-browser';
this.title.label = 'Papyri browser';
this.title.closable = true;
this.comp = React.createRef();
}

updateSeachTerm(str: string) {
this.comp.current.setSearchTerm(str);
this.comp.current.search(str);
}

render(): JSX.Element {
return <PapyriComponent />;
return <PapyriComponent ref={this.comp} />;
}
}

0 comments on commit d665532

Please sign in to comment.