Skip to content

Commit

Permalink
Logging in notebook (#437)
Browse files Browse the repository at this point in the history
Co-authored-by: Panagiotis Georgakopoulos <panagiotis.georgakopoulos@juliacomputing.com>
Co-authored-by: Paul <paul@plutojl.org>
Co-authored-by: Michiel Dral <m.c.dral@gmail.com>
  • Loading branch information
4 people committed Jan 17, 2022
1 parent ffb38d2 commit 665d99a
Show file tree
Hide file tree
Showing 21 changed files with 2,276 additions and 247 deletions.
24 changes: 23 additions & 1 deletion frontend/components/Cell.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
import _ from "../imports/lodash.js"
import { html, useState, useEffect, useMemo, useRef, useContext, useLayoutEffect } from "../imports/Preact.js"

import { CellOutput } from "./CellOutput.js"
import { CellInput } from "./CellInput.js"
import { Logs } from "./Logs.js"
import { RunArea, useDebouncedTruth } from "./RunArea.js"
import { cl } from "../common/ClassTable.js"
import { PlutoContext } from "../common/PlutoContext.js"
Expand Down Expand Up @@ -41,7 +43,7 @@ const useCellApi = (node_ref, published_object_keys, pluto_actions) => {
* */
export const Cell = ({
cell_input: { cell_id, code, code_folded, running_disabled },
cell_result: { queued, running, runtime, errored, output, published_object_keys, depends_on_disabled_cells },
cell_result: { queued, running, runtime, errored, output, logs, published_object_keys, depends_on_disabled_cells },
cell_dependencies,
cell_input_local,
notebook_id,
Expand All @@ -64,6 +66,17 @@ export const Cell = ({
const variables = Object.keys(notebook?.cell_dependencies?.[cell_id]?.downstream_cells_map || {})
// cm_forced_focus is null, except when a line needs to be highlighted because it is part of a stack trace
const [cm_forced_focus, set_cm_forced_focus] = useState(null)
const [cm_highlighted_line, set_cm_highlighted_line] = useState(null)
const [show_logs, set_show_logs] = useState(true)

const any_logs = useMemo(() => !_.isEmpty(logs), [logs])

useEffect(() => {
if (!any_logs) {
set_show_logs(true)
}
}, [any_logs])

useEffect(() => {
const focusListener = (e) => {
if (e.detail.cell_id === cell_id) {
Expand Down Expand Up @@ -107,6 +120,7 @@ export const Cell = ({
// during the initial page load, force_hide_input === true, so that cell outputs render fast, and codemirrors are loaded after
let show_input = !force_hide_input && (errored || class_code_differs || !class_code_folded)

const [line_heights, set_line_heights] = useState([15])
const node_ref = useRef(null)

const disable_input_ref = useRef(disable_input)
Expand All @@ -131,6 +145,7 @@ export const Cell = ({
running_disabled: running_disabled,
depends_on_disabled_cells: depends_on_disabled_cells,
show_input: show_input,
shrunk: Object.values(logs).length > 0,
hooked_up: output?.has_pluto_hook_features ?? false,
})}
id=${cell_id}
Expand Down Expand Up @@ -197,11 +212,18 @@ export const Cell = ({
}}
on_update_doc_query=${on_update_doc_query}
on_focus_neighbor=${on_focus_neighbor}
on_line_heights=${set_line_heights}
nbpkg=${nbpkg}
cell_id=${cell_id}
notebook_id=${notebook_id}
running_disabled=${running_disabled}
any_logs=${any_logs}
show_logs=${show_logs}
set_show_logs=${set_show_logs}
cm_highlighted_line=${cm_highlighted_line}
set_cm_highlighted_line=${set_cm_highlighted_line}
/>
${show_logs ? html`<${Logs} logs=${Object.values(logs)} line_heights=${line_heights} set_cm_highlighted_line=${set_cm_highlighted_line} />` : null}
<${RunArea}
cell_id=${cell_id}
running_disabled=${running_disabled}
Expand Down
44 changes: 42 additions & 2 deletions frontend/components/CellInput.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { html, useState, useEffect, useLayoutEffect, useRef, useContext, useMemo } from "../imports/Preact.js"
import observablehq_for_myself from "../common/SetupCellEnvironment.js"
import _ from "../imports/lodash.js"

import { utf8index_to_ut16index } from "../common/UnicodeTools.js"
Expand Down Expand Up @@ -53,6 +54,7 @@ import { cell_movement_plugin, prevent_holding_a_key_from_doing_things_across_ce
import { pluto_paste_plugin } from "./CellInput/pluto_paste_plugin.js"
import { bracketMatching } from "./CellInput/block_matcher_plugin.js"
import { cl } from "../common/ClassTable.js"
import { HighlightLineFacet, highlightLinePlugin } from "./CellInput/highlight_line.js"

export const pluto_syntax_colors = HighlightStyle.define([
/* The following three need a specific version of the julia parser, will add that later (still messing with it 😈) */
Expand Down Expand Up @@ -157,11 +159,16 @@ export const CellInput = ({
on_change,
on_update_doc_query,
on_focus_neighbor,
on_line_heights,
nbpkg,
cell_id,
notebook_id,
running_disabled,
cell_dependencies,
any_logs,
show_logs,
set_show_logs,
cm_highlighted_line,
variables_in_all_notebook,
}) => {
let pluto_actions = useContext(PlutoContext)
Expand All @@ -174,6 +181,7 @@ export const CellInput = ({

let nbpkg_compartment = useCompartment(newcm_ref, NotebookpackagesFacet.of(nbpkg))
let used_variables_compartment = useCompartment(newcm_ref, UsedVariablesFacet.of(variables_in_all_notebook))
let highlighted_line_compartment = useCompartment(newcm_ref, HighlightLineFacet.of(cm_highlighted_line))
let editable_compartment = useCompartment(newcm_ref, EditorState.readOnly.of(disable_input))

let on_change_compartment = useCompartment(
Expand Down Expand Up @@ -359,6 +367,7 @@ export const CellInput = ({
EditorView.theme({}, { dark: usesDarkTheme }),
// Compartments coming from react state/props
nbpkg_compartment,
highlighted_line_compartment,
used_variables_compartment,
editable_compartment,

Expand Down Expand Up @@ -479,6 +488,21 @@ export const CellInput = ({
view.focus()
})
}

// @ts-ignore
const lines_wrapper_dom_node = dom_node_ref.current.querySelector("div.cm-content")
const lines_wrapper_resize_observer = new ResizeObserver(() => {
const line_nodes = lines_wrapper_dom_node.children
const tops = _.map(line_nodes, (c) => c.offsetTop)
const diffs = tops.slice(1).map((y, i) => y - tops[i])
const heights = [...diffs, 15]
on_line_heights(heights)
})

lines_wrapper_resize_observer.observe(lines_wrapper_dom_node)
return () => {
lines_wrapper_resize_observer.unobserve(lines_wrapper_dom_node)
}
}, [])

// Effect to apply "remote_code" to the cell when it changes...
Expand Down Expand Up @@ -542,12 +566,20 @@ export const CellInput = ({

return html`
<pluto-input ref=${dom_node_ref} class="CodeMirror" translate=${false}>
<${InputContextMenu} on_delete=${on_delete} cell_id=${cell_id} run_cell=${on_submit} running_disabled=${running_disabled} />
<${InputContextMenu}
on_delete=${on_delete}
cell_id=${cell_id}
run_cell=${on_submit}
running_disabled=${running_disabled}
any_logs=${any_logs}
show_logs=${show_logs}
set_show_logs=${set_show_logs}
/>
</pluto-input>
`
}

const InputContextMenu = ({ on_delete, cell_id, run_cell, running_disabled }) => {
const InputContextMenu = ({ on_delete, cell_id, run_cell, running_disabled, any_logs, show_logs, set_show_logs }) => {
const timeout = useRef(null)
let pluto_actions = useContext(PlutoContext)
const [open, setOpen] = useState(false)
Expand All @@ -564,6 +596,7 @@ const InputContextMenu = ({ on_delete, cell_id, run_cell, running_disabled }) =>
// we also 'run' the cell if it is disabled, this will make the backend propage the disabled state to dependent cells
await run_cell()
}
const toggle_logs = () => set_show_logs(!show_logs)

return html` <button
onClick=${() => setOpen(!open)}
Expand All @@ -585,6 +618,13 @@ const InputContextMenu = ({ on_delete, cell_id, run_cell, running_disabled }) =>
${running_disabled ? html`<span class="enable_cell_icon" />` : html`<span class="disable_cell_icon" />`}
${running_disabled ? html`<b>Enable cell</b>` : html`Disable cell`}
</li>
${any_logs
? html`<li title="" onClick=${toggle_logs}>
${show_logs
? html`<span class="hide_logs_icon" /><span>Hide logs</span>`
: html`<span class="show_logs_icon" /><span>Show logs</span>`}
</li>`
: null}
<li class="coming_soon" title=""><span class="bandage_icon" /><em>Coming soon…</em></li>
</ul>`
: html``}
Expand Down
54 changes: 54 additions & 0 deletions frontend/components/CellInput/highlight_line.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
import { Decoration, ViewPlugin, EditorView, Facet } from "../../imports/CodemirrorPlutoSetup.js"

const highlighted_line = Decoration.line({
attributes: { class: "cm-highlighted-line" },
})

/**
* @param {EditorView} view
*/
function create_line_decorations(view) {
let line_number = view.state.facet(HighlightLineFacet)
if (line_number == null || line_number == undefined || line_number > view.state.doc.lines) {
return Decoration.set([])
}

let line = view.state.doc.line(line_number)
return Decoration.set([highlighted_line.range(line.from, line.from)])
}

/**
* @type Facet<number?, number?>
*/
export const HighlightLineFacet = Facet.define({
combine: (values) => values[0],
compare: (a, b) => a === b,
})

export const highlightLinePlugin = () =>
ViewPlugin.fromClass(
class {
updateDecos(view) {
this.decorations = create_line_decorations(view)
}

/**
* @param {EditorView} view
*/
constructor(view) {
this.updateDecos(view)
}

/**
* @param {ViewUpdate} update
*/
update(update) {
if (update.docChanged || update.state.facet(HighlightLineFacet) !== update.startState.facet(HighlightLineFacet)) {
this.updateDecos(update.view)
}
}
},
{
decorations: (v) => v.decorations,
}
)
22 changes: 16 additions & 6 deletions frontend/components/Editor.js
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,17 @@ const first_true_key = (obj) => {
* }}
*/

/**
* @typedef LogEntryData
* @type {{
* level: number,
* msg: string,
* file: string,
* line: number,
* kwargs: Object,
* }}
*/

/**
* @typedef CellResultData
* @type {{
Expand All @@ -120,6 +131,7 @@ const first_true_key = (obj) => {
* rootassignee: ?string,
* has_pluto_hook_features: boolean,
* },
* logs: Array<LogEntryData>,
* published_object_keys: [string],
* }}
*/
Expand Down Expand Up @@ -232,6 +244,7 @@ export class Editor extends Component {
down: false,
},
export_menu_open: false,
show_logs: true,

last_created_cell: null,
selected_cells: [],
Expand Down Expand Up @@ -638,9 +651,6 @@ patch: ${JSON.stringify(
apply_notebook_patches(message.patches)
}
break
case "log":
handle_log(message, this.state.notebook.path)
break
default:
console.error("Received unknown update type!", update)
// alert("Something went wrong 🙈\n Try clearing your browser cache and refreshing the page")
Expand Down Expand Up @@ -1250,6 +1260,8 @@ patch: ${JSON.stringify(
on_cell_input=${this.actions.set_local_cell}
on_focus_neighbor=${this.actions.focus_on_neighbor}
disable_input=${this.state.disable_ui || !this.state.connected /* && this.state.binder_phase == null*/}
show_logs=${this.state.show_logs}
set_show_logs=${(enabled) => this.setState({ show_logs: enabled })}
last_created_cell=${this.state.last_created_cell}
selected_cells=${this.state.selected_cells}
is_initializing=${this.state.initializing}
Expand All @@ -1258,9 +1270,7 @@ patch: ${JSON.stringify(
<${DropRuler}
actions=${this.actions}
selected_cells=${this.state.selected_cells}
set_scroller=${(enabled) => {
this.setState({ scroller: enabled })
}}
set_scroller=${(enabled) => this.setState({ scroller: enabled })}
serialize_selected=${this.serialize_selected}
/>
${
Expand Down
Loading

0 comments on commit 665d99a

Please sign in to comment.