Skip to content

Commit

Permalink
Merge branch 'main' into slider-server-in-pluto-export-json
Browse files Browse the repository at this point in the history
  • Loading branch information
fonsp authored Oct 22, 2023
2 parents 5c3c0e2 + fb7ca86 commit 80beb08
Show file tree
Hide file tree
Showing 49 changed files with 1,320 additions and 302 deletions.
1 change: 1 addition & 0 deletions .github/workflows/FrontendTest.yml
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@ jobs:
options = Pluto.Configuration.from_flat_kwargs(;
port=parse(Int, ENV["PLUTO_PORT"]),
require_secret_for_access=false,
workspace_use_distributed_stdlib=false,
)
🍭 = Pluto.ServerSession(; options)
server = Pluto.run!(🍭)
Expand Down
1 change: 1 addition & 0 deletions frontend/common/Binder.js
Original file line number Diff line number Diff line change
Expand Up @@ -144,6 +144,7 @@ export const start_binder = async ({ setStatePromise, connect, launch_params })
const upload_url = with_token(
with_query_params(new URL("notebookupload", binder_session_url), {
name: new URLSearchParams(window.location.search).get("name"),
execution_allowed: "true",
})
)
console.log(`downloading locally and uploading `, upload_url, launch_params.notebookfile)
Expand Down
99 changes: 99 additions & 0 deletions frontend/common/InstallTimeEstimate.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
import { useEffect, useState } from "../imports/Preact.js"
import _ from "../imports/lodash.js"

const loading_times_url = `https://julia-loading-times-test.netlify.app/pkg_load_times.csv`
const package_list_url = `https://julia-loading-times-test.netlify.app/top_packages_sorted_with_deps.txt`

/** @typedef {{ install: Number, precompile: Number, load: Number }} LoadingTime */

/**
* @typedef PackageTimingData
* @type {{
* times: Map<String,LoadingTime>,
* packages: Map<String,String[]>,
* }}
*/

/** @type {{ current: Promise<PackageTimingData>? }} */
const data_promise_ref = { current: null }

export const get_data = () => {
if (data_promise_ref.current != null) {
return data_promise_ref.current
} else {
const times_p = fetch(loading_times_url)
.then((res) => res.text())
.then((text) => {
const lines = text.split("\n")
const header = lines[0].split(",")
return new Map(
lines.slice(1).map((line) => {
let [pkg, ...times] = line.split(",")

return [pkg, { install: Number(times[0]), precompile: Number(times[1]), load: Number(times[2]) }]
})
)
})

const packages_p = fetch(package_list_url)
.then((res) => res.text())
.then(
(text) =>
new Map(
text.split("\n").map((line) => {
let [pkg, ...deps] = line.split(",")
return [pkg, deps]
})
)
)

data_promise_ref.current = Promise.all([times_p, packages_p]).then(([times, packages]) => ({ times, packages }))

return data_promise_ref.current
}
}

export const usePackageTimingData = () => {
const [data, set_data] = useState(/** @type {PackageTimingData?} */ (null))

useEffect(() => {
get_data().then(set_data)
}, [])

return data
}

const recursive_deps = (/** @type {PackageTimingData} */ data, /** @type {string} */ pkg, found = []) => {
const deps = data.packages.get(pkg)
if (deps == null) {
return []
} else {
const newfound = _.union(found, deps)
return [...deps, ..._.difference(deps, found).flatMap((dep) => recursive_deps(data, dep, newfound))]
}
}

export const time_estimate = (/** @type {PackageTimingData} */ data, /** @type {string[]} */ packages) => {
let deps = packages.flatMap((pkg) => recursive_deps(data, pkg))
let times = _.uniq([...packages, ...deps])
.map((pkg) => data.times.get(pkg))
.filter((x) => x != null)

console.log({ packages, deps, times, z: _.uniq([...packages, ...deps]) })
let sum = (xs) => xs.reduce((acc, x) => acc + (x == null || isNaN(x) ? 0 : x), 0)

return {
install: sum(times.map(_.property("install"))) * timing_weights.install,
precompile: sum(times.map(_.property("precompile"))) * timing_weights.precompile,
load: sum(times.map(_.property("load"))) * timing_weights.load,
}
}

const timing_weights = {
// Because the GitHub Action runner has superfast internet
install: 2,
// Because the GitHub Action runner has average compute speed
load: 1,
// Because precompilation happens in parallel
precompile: 0.3,
}
7 changes: 7 additions & 0 deletions frontend/common/ProcessStatus.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
export const ProcessStatus = {
ready: "ready",
starting: "starting",
no_process: "no_process",
waiting_to_restart: "waiting_to_restart",
waiting_for_permission: "waiting_for_permission",
}
1 change: 1 addition & 0 deletions frontend/common/RunLocal.js
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ export const start_local = async ({ setStatePromise, connect, launch_params }) =
with_query_params(new URL("notebookupload", binder_session_url), {
name: new URLSearchParams(window.location.search).get("name"),
clear_frontmatter: "yesplease",
execution_allowed: "yepperz",
})
),
{
Expand Down
118 changes: 70 additions & 48 deletions frontend/components/Cell.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import { RunArea, useDebouncedTruth } from "./RunArea.js"
import { cl } from "../common/ClassTable.js"
import { PlutoActionsContext } from "../common/PlutoContext.js"
import { open_pluto_popup } from "./Popup.js"
import { SafePreviewOutput } from "./SafePreviewUI.js"

const useCellApi = (node_ref, published_object_keys, pluto_actions) => {
const [cell_api_ready, set_cell_api_ready] = useState(false)
Expand Down Expand Up @@ -96,6 +97,8 @@ const on_jump = (hasBarrier, pluto_actions, cell_id) => () => {
* selected: boolean,
* force_hide_input: boolean,
* focus_after_creation: boolean,
* process_waiting_for_permission: boolean,
* sanitize_html: boolean,
* [key: string]: any,
* }} props
* */
Expand All @@ -110,6 +113,8 @@ export const Cell = ({
focus_after_creation,
is_process_ready,
disable_input,
process_waiting_for_permission,
sanitize_html = true,
nbpkg,
global_definition_locations,
}) => {
Expand All @@ -134,8 +139,8 @@ export const Cell = ({

const remount = useMemo(() => () => setKey(key + 1))
// 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(/** @type{any} */ (null))
const [cm_highlighted_range, set_cm_highlighted_range] = useState(null)
const [cm_forced_focus, set_cm_forced_focus] = useState(/** @type {any} */ (null))
const [cm_highlighted_range, set_cm_highlighted_range] = useState(/** @type {{from, to}?} */ (null))
const [cm_highlighted_line, set_cm_highlighted_line] = useState(null)
const [cm_diagnostics, set_cm_diagnostics] = useState([])

Expand Down Expand Up @@ -200,9 +205,11 @@ export const Cell = ({

const class_code_differs = code !== (cell_input_local?.code ?? code)
const class_code_folded = code_folded && cm_forced_focus == null
const no_output_yet = (output?.last_run_timestamp ?? 0) === 0
const code_not_trusted_yet = process_waiting_for_permission && no_output_yet

// 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)
let show_input = !force_hide_input && (code_not_trusted_yet || errored || class_code_differs || !class_code_folded)

const [line_heights, set_line_heights] = useState([15])
const node_ref = useRef(null)
Expand All @@ -211,18 +218,23 @@ export const Cell = ({
disable_input_ref.current = disable_input
const should_set_waiting_to_run_ref = useRef(true)
should_set_waiting_to_run_ref.current = !running_disabled && !depends_on_disabled_cells
const set_waiting_to_run_smart = (x) => set_waiting_to_run(x && should_set_waiting_to_run_ref.current)
useEffect(() => {
const handler = (e) => {
if (e.detail.cell_ids.includes(cell_id)) set_waiting_to_run(should_set_waiting_to_run_ref.current)
}
window.addEventListener("set_waiting_to_run_smart", handler)
return () => window.removeEventListener("set_waiting_to_run_smart", handler)
}, [cell_id])

const cell_api_ready = useCellApi(node_ref, published_object_keys, pluto_actions)
const on_delete = useCallback(() => {
pluto_actions.confirm_delete_multiple("Delete", pluto_actions.get_selected_cells(cell_id, selected))
}, [pluto_actions, selected, cell_id])
const on_submit = useCallback(() => {
if (!disable_input_ref.current) {
set_waiting_to_run_smart(true)
pluto_actions.set_and_run_multiple([cell_id])
}
}, [pluto_actions, set_waiting_to_run, cell_id])
}, [pluto_actions, cell_id])
const on_change_cell_input = useCallback(
(new_code) => {
if (!disable_input_ref.current) {
Expand All @@ -242,8 +254,7 @@ export const Cell = ({
}, [pluto_actions, cell_id, selected, code_folded])
const on_run = useCallback(() => {
pluto_actions.set_and_run_multiple(pluto_actions.get_selected_cells(cell_id, selected))
set_waiting_to_run_smart(true)
}, [pluto_actions, cell_id, selected, set_waiting_to_run_smart])
}, [pluto_actions, cell_id, selected])
const set_show_logs = useCallback(
(show_logs) =>
pluto_actions.update_notebook((notebook) => {
Expand Down Expand Up @@ -272,21 +283,23 @@ export const Cell = ({
key=${cell_key}
ref=${node_ref}
class=${cl({
queued: queued || (waiting_to_run && is_process_ready),
running,
activate_animation,
errored,
selected,
code_differs: class_code_differs,
code_folded: class_code_folded,
skip_as_script,
running_disabled,
depends_on_disabled_cells,
depends_on_skipped_cells,
show_input,
shrunk: Object.values(logs).length > 0,
hooked_up: output?.has_pluto_hook_features ?? false,
})}
queued: queued || (waiting_to_run && is_process_ready),
internal_test_queued: !is_process_ready && (queued || waiting_to_run),
running,
activate_animation,
errored,
selected,
code_differs: class_code_differs,
code_folded: class_code_folded,
skip_as_script,
running_disabled,
depends_on_disabled_cells,
depends_on_skipped_cells,
show_input,
shrunk: Object.values(logs).length > 0,
hooked_up: output?.has_pluto_hook_features ?? false,
no_output_yet,
})}
id=${cell_id}
>
${variables.map((name) => html`<span id=${encodeURI(name)} />`)}
Expand All @@ -298,14 +311,18 @@ export const Cell = ({
<pluto-trafficlight></pluto-trafficlight>
<button
onClick=${() => {
pluto_actions.add_remote_cell(cell_id, "before")
}}
pluto_actions.add_remote_cell(cell_id, "before")
}}
class="add_cell before"
title="Add cell (Ctrl + Enter)"
>
<span></span>
</button>
${cell_api_ready ? html`<${CellOutput} errored=${errored} ...${output} cell_id=${cell_id} />` : html``}
${code_not_trusted_yet
? html`<${SafePreviewOutput} />`
: cell_api_ready
? html`<${CellOutput} errored=${errored} ...${output} sanitize_html=${sanitize_html} cell_id=${cell_id} />`
: html``}
<${CellInput}
local_code=${cell_input_local?.code ?? code}
remote_code=${code}
Expand Down Expand Up @@ -337,16 +354,21 @@ export const Cell = ({
onerror=${remount}
/>
${show_logs && cell_api_ready
? html`<${Logs} logs=${Object.values(logs)} line_heights=${line_heights} set_cm_highlighted_line=${set_cm_highlighted_line} />`
? html`<${Logs}
logs=${Object.values(logs)}
line_heights=${line_heights}
set_cm_highlighted_line=${set_cm_highlighted_line}
sanitize_html=${sanitize_html}
/>`
: null}
<${RunArea}
cell_id=${cell_id}
running_disabled=${running_disabled}
depends_on_disabled_cells=${depends_on_disabled_cells}
on_run=${on_run}
on_interrupt=${() => {
pluto_actions.interrupt_remote(cell_id)
}}
pluto_actions.interrupt_remote(cell_id)
}}
set_cell_disabled=${set_cell_disabled}
runtime=${runtime}
running=${running}
Expand All @@ -356,42 +378,42 @@ export const Cell = ({
/>
<button
onClick=${() => {
pluto_actions.add_remote_cell(cell_id, "after")
}}
pluto_actions.add_remote_cell(cell_id, "after")
}}
class="add_cell after"
title="Add cell (Ctrl + Enter)"
>
<span></span>
</button>
${skip_as_script
? html`<div
? html`<div
class="skip_as_script_marker"
title=${`This cell is directly flagged as disabled in file. Click to know more!`}
onClick=${(e) => {
open_pluto_popup({
type: "info",
source_element: e.target,
body: html`This cell is currently stored in the notebook file as a Julia <em>comment</em>, instead of <em>code</em>.<br />
open_pluto_popup({
type: "info",
source_element: e.target,
body: html`This cell is currently stored in the notebook file as a Julia <em>comment</em>, instead of <em>code</em>.<br />
This way, it will not run when the notebook runs as a script outside of Pluto.<br />
Use the context menu to enable it again`,
})
}}
})
}}
></div>`
: depends_on_skipped_cells
: depends_on_skipped_cells
? html`<div
class="depends_on_skipped_marker"
title=${`This cell is indirectly flagged as disabled in file. Click to know more!`}
onClick=${(e) => {
open_pluto_popup({
type: "info",
source_element: e.target,
body: html`This cell is currently stored in the notebook file as a Julia <em>comment</em>, instead of <em>code</em>.<br />
open_pluto_popup({
type: "info",
source_element: e.target,
body: html`This cell is currently stored in the notebook file as a Julia <em>comment</em>, instead of <em>code</em>.<br />
This way, it will not run when the notebook runs as a script outside of Pluto.<br />
An upstream cell is <b> indirectly</b> <em>disabling in file</em> this one; enable
<span onClick=${skip_as_script_jump} style="cursor: pointer; text-decoration: underline"> the upstream one</span> to affect
this cell.`,
})
}}
})
}}
></div>`
: null}
</pluto-cell>
Expand All @@ -404,16 +426,16 @@ export const Cell = ({
* [key: string]: any,
* }} props
* */
export const IsolatedCell = ({ cell_input: { cell_id, metadata }, cell_result: { logs, output, published_object_keys }, hidden }) => {
export const IsolatedCell = ({ cell_input: { cell_id, metadata }, cell_result: { logs, output, published_object_keys }, hidden }, sanitize_html = true) => {
const node_ref = useRef(null)
let pluto_actions = useContext(PlutoActionsContext)
const cell_api_ready = useCellApi(node_ref, published_object_keys, pluto_actions)
const { show_logs } = metadata

return html`
<pluto-cell ref=${node_ref} id=${cell_id} class=${hidden ? "hidden-cell" : "isolated-cell"}>
${cell_api_ready ? html`<${CellOutput} ...${output} cell_id=${cell_id} />` : html``}
${show_logs ? html`<${Logs} logs=${Object.values(logs)} line_heights=${[15]} set_cm_highlighted_line=${() => { }} />` : null}
${cell_api_ready ? html`<${CellOutput} ...${output} sanitize_html=${sanitize_html} cell_id=${cell_id} />` : html``}
${show_logs ? html`<${Logs} logs=${Object.values(logs)} line_heights=${[15]} set_cm_highlighted_line=${() => {}} />` : null}
</pluto-cell>
`
}
Loading

0 comments on commit 80beb08

Please sign in to comment.