plainbook 0.0.7__py3-none-any.whl → 0.0.9__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- plainbook/js/AppNavbar.js +76 -0
- plainbook/js/CellInsertionZone.js +21 -0
- plainbook/js/CodeCell.js +2 -1
- plainbook/js/ExplanationEditor.js +5 -12
- plainbook/js/InfoModal.js +29 -0
- plainbook/js/MarkdownCell.js +1 -1
- plainbook/js/NotebookCell.js +72 -0
- plainbook/js/SettingsModal.js +46 -0
- plainbook/js/ValidationCell.js +2 -2
- plainbook/js/nb.js +14 -25
- plainbook/main.py +2 -1
- plainbook/views/index.html +60 -193
- {plainbook-0.0.7.dist-info → plainbook-0.0.9.dist-info}/METADATA +1 -1
- {plainbook-0.0.7.dist-info → plainbook-0.0.9.dist-info}/RECORD +18 -13
- {plainbook-0.0.7.dist-info → plainbook-0.0.9.dist-info}/WHEEL +0 -0
- {plainbook-0.0.7.dist-info → plainbook-0.0.9.dist-info}/entry_points.txt +0 -0
- {plainbook-0.0.7.dist-info → plainbook-0.0.9.dist-info}/licenses/LICENSE.md +0 -0
- {plainbook-0.0.7.dist-info → plainbook-0.0.9.dist-info}/top_level.txt +0 -0
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
export default {
|
|
2
|
+
props: ['isLocked', 'running', 'hasNotebook', 'lastRunIndex', 'cellCount', 'hasApiKey'],
|
|
3
|
+
emits: [
|
|
4
|
+
'lock', 'refresh', 'interrupt', 'regenerate-all',
|
|
5
|
+
'reset-run-all', 'open-info', 'open-settings'
|
|
6
|
+
],
|
|
7
|
+
template: /* html */ `
|
|
8
|
+
<nav class="navbar is-dark is-fixed-top" role="navigation" aria-label="main navigation">
|
|
9
|
+
<div id="the-navbar-menu" class="navbar-menu">
|
|
10
|
+
<div class="navbar-start">
|
|
11
|
+
<div class="navbar-item">
|
|
12
|
+
<div class="buttons">
|
|
13
|
+
<button v-if="isLocked" class="button is-warning" title="Unlock Notebook" @click="$emit('lock', false)">
|
|
14
|
+
<span class="icon"><i class="fa fa-lock"></i></span>
|
|
15
|
+
</button>
|
|
16
|
+
<button v-else class="button is-light" title="Lock Notebook" @click="$emit('lock', true)">
|
|
17
|
+
<span class="icon"><i class="fa fa-unlock"></i></span>
|
|
18
|
+
</button>
|
|
19
|
+
|
|
20
|
+
<button v-if="!running && hasNotebook"
|
|
21
|
+
@click="$emit('refresh')"
|
|
22
|
+
class="button is-light" title="Reload Notebook">
|
|
23
|
+
<span class="icon"><i class="fa fa-refresh"></i></span>
|
|
24
|
+
<span>Refresh</span>
|
|
25
|
+
</button>
|
|
26
|
+
|
|
27
|
+
<button v-if="running && hasNotebook"
|
|
28
|
+
@click="$emit('interrupt')"
|
|
29
|
+
class="button is-danger" title="Interrupt Execution">
|
|
30
|
+
<span class="icon"><i class="fa fa-stop"></i></span>
|
|
31
|
+
<span>Running...</span>
|
|
32
|
+
</button>
|
|
33
|
+
|
|
34
|
+
<button v-if="!running && hasNotebook && lastRunIndex >= cellCount - 1"
|
|
35
|
+
class="button is-light" title="All cells have been run">
|
|
36
|
+
<span class="icon"><i class="fa fa-check-circle"></i></span>
|
|
37
|
+
<span>Up to Date</span>
|
|
38
|
+
</button>
|
|
39
|
+
|
|
40
|
+
<button v-if="!running && hasNotebook"
|
|
41
|
+
:disabled="cellCount === 0 || isLocked"
|
|
42
|
+
@click="$emit('regenerate-all')"
|
|
43
|
+
title="Regenerate all code from descriptions"
|
|
44
|
+
class="button is-success">
|
|
45
|
+
<span class="icon"><i class="fa fa-repeat"></i></span>
|
|
46
|
+
<span>Regenerate All</span>
|
|
47
|
+
</button>
|
|
48
|
+
|
|
49
|
+
<button v-if="!running && hasNotebook"
|
|
50
|
+
:disabled="cellCount === 0"
|
|
51
|
+
@click="$emit('reset-run-all')"
|
|
52
|
+
title="Reset and run all cells"
|
|
53
|
+
class="button is-primary">
|
|
54
|
+
<span class="icon"><i class="fa fa-play"></i></span>
|
|
55
|
+
<span>Reset and Run All</span>
|
|
56
|
+
</button>
|
|
57
|
+
</div>
|
|
58
|
+
</div>
|
|
59
|
+
</div>
|
|
60
|
+
<div class="navbar-end">
|
|
61
|
+
<div class="navbar-item">
|
|
62
|
+
<div class="buttons">
|
|
63
|
+
<button class="button is-light" @click="$emit('open-info')" title="About Plainbook">
|
|
64
|
+
<span class="icon"><i class="fa fa-info"></i></span>
|
|
65
|
+
</button>
|
|
66
|
+
<button class="button" :class="hasApiKey ? 'is-light' : 'is-warning'"
|
|
67
|
+
@click="$emit('open-settings')" title="Settings">
|
|
68
|
+
<span class="icon"><i :class="hasApiKey ? 'fa fa-cog' : 'fa fa-warning'"></i></span>
|
|
69
|
+
<span>Settings</span>
|
|
70
|
+
</button>
|
|
71
|
+
</div>
|
|
72
|
+
</div>
|
|
73
|
+
</div>
|
|
74
|
+
</div>
|
|
75
|
+
</nav>`
|
|
76
|
+
};
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
// CellInsertionZone.js
|
|
2
|
+
export default {
|
|
3
|
+
props: [],
|
|
4
|
+
emits: ['insert'],
|
|
5
|
+
template: /* html */ `
|
|
6
|
+
<div class="cell-insert-zone">
|
|
7
|
+
<div class="cell-insert-buttons">
|
|
8
|
+
<button
|
|
9
|
+
class="button insert-cell is-info is-small py-0 px-3"
|
|
10
|
+
@click.stop="$emit('insert', 'markdown')">
|
|
11
|
+
Insert Comment
|
|
12
|
+
</button>
|
|
13
|
+
<button
|
|
14
|
+
class="button insert-cell is-info is-small py-0 px-3"
|
|
15
|
+
@click.stop="$emit('insert', 'code')">
|
|
16
|
+
Insert Action
|
|
17
|
+
</button>
|
|
18
|
+
</div>
|
|
19
|
+
</div>
|
|
20
|
+
`
|
|
21
|
+
};
|
plainbook/js/CodeCell.js
CHANGED
|
@@ -128,7 +128,8 @@ export default {
|
|
|
128
128
|
if (!isCollapsed.value && isEditing.value) nextTick(autoResize);
|
|
129
129
|
};
|
|
130
130
|
|
|
131
|
-
return { isCollapsed, toggleCollapse, isEditing, cancelEdit, localSource,
|
|
131
|
+
return { isCollapsed, toggleCollapse, isEditing, cancelEdit, localSource,
|
|
132
|
+
localIsLocked, highlightedCode, enterEditMode, saveCode, textareaEl, autoResize, handleTabKey };
|
|
132
133
|
},
|
|
133
134
|
template: /* html */ `
|
|
134
135
|
<div class="code-cell-wrapper" style="position: relative; min-height: 1.75rem;">
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { ref, computed, watch, nextTick } from './vue.esm-browser.js';
|
|
2
2
|
|
|
3
3
|
const ExplanationRenderer = {
|
|
4
|
-
props: ['source', 'isActive', '
|
|
4
|
+
props: ['source', 'isActive', 'needsRunning', 'asRead', 'startEditKey', 'isLocked'],
|
|
5
5
|
emits: ['update:source', 'save', 'saveandrun', 'gencode', 'validate',
|
|
6
6
|
'run', 'delete', 'moveUp', 'moveDown'],
|
|
7
7
|
setup(props, { emit }) {
|
|
@@ -95,19 +95,11 @@ const ExplanationRenderer = {
|
|
|
95
95
|
<div class="toolbar-left">
|
|
96
96
|
<button class="button run-button is-small is-primary mr-1"
|
|
97
97
|
title="Run this cell and all necessary preceding cells" @click.stop="$emit('run')">
|
|
98
|
-
<
|
|
99
|
-
<span class="icon"><i class="fa fa-repeat"></i></span><span>Re-Run</span>
|
|
100
|
-
</template>
|
|
101
|
-
<template v-else-if="lastRunIndex < index">
|
|
102
|
-
<span class="icon"><i class="fa fa-step-forward"></i></span><span>Run Up To Here</span>
|
|
103
|
-
</template>
|
|
104
|
-
<template v-else>
|
|
105
|
-
<span class="icon"><i class="fa fa-step-forward"></i></span><span>Run From Start To Here</span>
|
|
106
|
-
</template>
|
|
98
|
+
<span class="icon"><i class="fa fa-step-forward"></i></span><span>Run</span>
|
|
107
99
|
</button>
|
|
108
100
|
<button class="button is-small" style="opacity: 0.6;">
|
|
109
101
|
<span v-if="asRead">Unmodified</span>
|
|
110
|
-
<span v-else-if="
|
|
102
|
+
<span v-else-if="needsRunning">Needs running</span>
|
|
111
103
|
<span v-else>Up to date</span>
|
|
112
104
|
</button>
|
|
113
105
|
</div>
|
|
@@ -159,7 +151,8 @@ const ExplanationRenderer = {
|
|
|
159
151
|
Save
|
|
160
152
|
</button>
|
|
161
153
|
<button class="button is-small is-primary" :disabled="localIsLocked" @click="saveAndRun">
|
|
162
|
-
|
|
154
|
+
<span class="icon"><i class="fa fa-play"></i></span>
|
|
155
|
+
<span>Save and Run</span>
|
|
163
156
|
</button>
|
|
164
157
|
</div>
|
|
165
158
|
</div>
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
export default {
|
|
2
|
+
props: ['isActive'],
|
|
3
|
+
emits: ['close'],
|
|
4
|
+
template: /* html */ `
|
|
5
|
+
<div class="modal" :class="{'is-active': isActive}">
|
|
6
|
+
<div class="modal-background" @click="$emit('close')"></div>
|
|
7
|
+
<div class="modal-card">
|
|
8
|
+
<header class="modal-card-head">
|
|
9
|
+
<p class="modal-card-title">Information</p>
|
|
10
|
+
<button class="delete" aria-label="close" @click="$emit('close')"></button>
|
|
11
|
+
</header>
|
|
12
|
+
<section class="modal-card-body">
|
|
13
|
+
<h1 class="title">Plainbook</h1>
|
|
14
|
+
<div class="content">
|
|
15
|
+
<p>Plainbook is an interactive notebook application for creating executable documents in natural language.</p>
|
|
16
|
+
<ul>
|
|
17
|
+
<li><strong>Action cells:</strong> Generate Python code from English explanations using AI.</li>
|
|
18
|
+
<li><strong>Markdown cells:</strong> Rich text for documentation.</li>
|
|
19
|
+
</ul>
|
|
20
|
+
<p>Locking prevents accidental edits while allowing validation and execution.</p>
|
|
21
|
+
<p><a href="https://github.com/lucadealfaro/plainbook" target="_blank">Plainbook Home Page</a></p>
|
|
22
|
+
</div>
|
|
23
|
+
</section>
|
|
24
|
+
<footer class="modal-card-foot">
|
|
25
|
+
<button class="button" @click="$emit('close')">Close</button>
|
|
26
|
+
</footer>
|
|
27
|
+
</div>
|
|
28
|
+
</div>`
|
|
29
|
+
};
|
plainbook/js/MarkdownCell.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { ref, watch, nextTick } from './vue.esm-browser.js';
|
|
2
2
|
|
|
3
3
|
const MarkdownCell = {
|
|
4
|
-
props: ['source', 'startEditKey', 'isActive', '
|
|
4
|
+
props: ['source', 'startEditKey', 'isActive', 'isLocked'],
|
|
5
5
|
emits: ['save', 'delete', 'moveUp', 'moveDown'],
|
|
6
6
|
setup(props, { emit }) {
|
|
7
7
|
const md = new markdownit({ html: true });
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
// NotebookCell.js
|
|
2
|
+
import MarkdownCell from './MarkdownCell.js';
|
|
3
|
+
import CodeCell from './CodeCell.js';
|
|
4
|
+
import ExplanationEditor from './ExplanationEditor.js';
|
|
5
|
+
import ValidationCell from './ValidationCell.js';
|
|
6
|
+
import OutputRenderer from './OutputRenderer.js';
|
|
7
|
+
|
|
8
|
+
export default {
|
|
9
|
+
components: { MarkdownCell, CodeCell, ExplanationEditor, ValidationCell, OutputRenderer },
|
|
10
|
+
props: ['cell', 'isActive', 'isLocked', 'needsRunning', 'asRead', 'markdownEditKey', 'explanationEditKey'],
|
|
11
|
+
emits: [
|
|
12
|
+
'save-markdown', 'save-explanation', 'save-code',
|
|
13
|
+
'run-cell', 'save-and-run', 'generate-code',
|
|
14
|
+
'validate-code', 'dismiss-validation',
|
|
15
|
+
'delete', 'move-up', 'move-down'
|
|
16
|
+
],
|
|
17
|
+
template: /* html */ `
|
|
18
|
+
<div class="notebook-cell box p-0 mb-2 is-clipped shadow-sm"
|
|
19
|
+
:style="{
|
|
20
|
+
border: isActive ? '2px solid #1d4ed8' : '1px solid transparent',
|
|
21
|
+
cursor: 'pointer'
|
|
22
|
+
}">
|
|
23
|
+
|
|
24
|
+
<markdown-cell
|
|
25
|
+
v-if="cell.cell_type === 'markdown'"
|
|
26
|
+
v-model:source="cell.source"
|
|
27
|
+
:is-active="isActive"
|
|
28
|
+
:start-edit-key="markdownEditKey"
|
|
29
|
+
:isLocked="isLocked"
|
|
30
|
+
@save="$emit('save-markdown', $event)"
|
|
31
|
+
@delete="$emit('delete')"
|
|
32
|
+
@moveUp="$emit('move-up')"
|
|
33
|
+
@moveDown="$emit('move-down')" />
|
|
34
|
+
|
|
35
|
+
<div v-else-if="cell.cell_type === 'code'">
|
|
36
|
+
<div v-if="cell.metadata?.explanation" class="has-background-light p-0 border-bottom">
|
|
37
|
+
<explanation-editor
|
|
38
|
+
v-model:source="cell.metadata.explanation"
|
|
39
|
+
:isActive="isActive"
|
|
40
|
+
:isLocked="isLocked"
|
|
41
|
+
:asRead="asRead"
|
|
42
|
+
:needs-running="needsRunning"
|
|
43
|
+
:start-edit-key="explanationEditKey"
|
|
44
|
+
@save="$emit('save-explanation', $event)"
|
|
45
|
+
@gencode="$emit('generate-code')"
|
|
46
|
+
@validate="$emit('validate-code')"
|
|
47
|
+
@run="$emit('run-cell')"
|
|
48
|
+
@saveandrun="$emit('save-and-run', $event)"
|
|
49
|
+
@delete="$emit('delete')"
|
|
50
|
+
@moveUp="$emit('move-up')"
|
|
51
|
+
@moveDown="$emit('move-down')" />
|
|
52
|
+
</div>
|
|
53
|
+
|
|
54
|
+
<validation-cell
|
|
55
|
+
v-if="cell.metadata?.validation && !cell.metadata?.validation.is_hidden"
|
|
56
|
+
:validation="cell.metadata.validation"
|
|
57
|
+
@dismiss_validation="$emit('dismiss-validation')" />
|
|
58
|
+
|
|
59
|
+
<code-cell
|
|
60
|
+
v-model:source="cell.source"
|
|
61
|
+
:execution-count="cell.execution_count"
|
|
62
|
+
:is-active="isActive"
|
|
63
|
+
:is-locked="isLocked"
|
|
64
|
+
@save="$emit('save-code', $event)" />
|
|
65
|
+
|
|
66
|
+
<div v-if="cell.outputs?.length" class="p-2 border-top has-background-white">
|
|
67
|
+
<output-renderer v-for="(out, oIdx) in cell.outputs" :key="oIdx" :output="out" />
|
|
68
|
+
</div>
|
|
69
|
+
</div>
|
|
70
|
+
</div>
|
|
71
|
+
`
|
|
72
|
+
};
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import { ref, watch } from './vue.esm-browser.js';
|
|
2
|
+
|
|
3
|
+
export default {
|
|
4
|
+
props: ['isActive', 'apiKey'],
|
|
5
|
+
emits: ['close', 'save'],
|
|
6
|
+
setup(props, { emit }) {
|
|
7
|
+
// Create a local draft of the API key
|
|
8
|
+
const localKey = ref(props.apiKey);
|
|
9
|
+
|
|
10
|
+
// Sync local draft whenever the modal is opened with the current parent value
|
|
11
|
+
watch(() => props.isActive, (active) => {
|
|
12
|
+
if (active) {
|
|
13
|
+
localKey.value = props.apiKey;
|
|
14
|
+
}
|
|
15
|
+
});
|
|
16
|
+
|
|
17
|
+
const handleSave = () => {
|
|
18
|
+
emit('save', localKey.value);
|
|
19
|
+
};
|
|
20
|
+
|
|
21
|
+
return { localKey, handleSave };
|
|
22
|
+
},
|
|
23
|
+
template: /* html */ `
|
|
24
|
+
<div class="modal" :class="{'is-active': isActive}">
|
|
25
|
+
<div class="modal-background" @click="$emit('close')"></div>
|
|
26
|
+
<div class="modal-card">
|
|
27
|
+
<header class="modal-card-head">
|
|
28
|
+
<p class="modal-card-title">Settings</p>
|
|
29
|
+
<button class="delete" aria-label="close" @click="$emit('close')"></button>
|
|
30
|
+
</header>
|
|
31
|
+
<section class="modal-card-body">
|
|
32
|
+
<div class="field">
|
|
33
|
+
<label class="label">Gemini API Key</label>
|
|
34
|
+
<div class="control">
|
|
35
|
+
<input class="input" type="text"
|
|
36
|
+
v-model="localKey"
|
|
37
|
+
placeholder="Enter your Gemini API key">
|
|
38
|
+
</div>
|
|
39
|
+
</div>
|
|
40
|
+
</section>
|
|
41
|
+
<footer class="modal-card-foot" style="justify-content: flex-end;">
|
|
42
|
+
<button class="button is-primary" @click="handleSave">Save</button>
|
|
43
|
+
</footer>
|
|
44
|
+
</div>
|
|
45
|
+
</div>`
|
|
46
|
+
};
|
plainbook/js/ValidationCell.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import {ref, watch, nextTick, computed} from './vue.esm-browser.js';
|
|
2
2
|
|
|
3
3
|
export default {
|
|
4
|
-
props: ['validation'
|
|
4
|
+
props: ['validation'],
|
|
5
5
|
emits: ['dismiss_validation'],
|
|
6
6
|
|
|
7
7
|
setup(props, { emit }) {
|
|
@@ -25,7 +25,7 @@ export default {
|
|
|
25
25
|
if (is_hidden.value) {
|
|
26
26
|
is_hidden.value = true;
|
|
27
27
|
}
|
|
28
|
-
emit('dismiss_validation'
|
|
28
|
+
emit('dismiss_validation');
|
|
29
29
|
};
|
|
30
30
|
return { dismiss, renderedMarkdown, message, is_valid, is_hidden };
|
|
31
31
|
},
|
plainbook/js/nb.js
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
import { createApp, ref, onMounted, onBeforeUnmount, nextTick, getCurrentInstance } from './vue.esm-browser.js';
|
|
2
2
|
|
|
3
|
-
import
|
|
4
|
-
import
|
|
5
|
-
import
|
|
6
|
-
import
|
|
7
|
-
import
|
|
3
|
+
import AppNavbar from './AppNavbar.js';
|
|
4
|
+
import NotebookCell from './NotebookCell.js';
|
|
5
|
+
import CellInsertionZone from './CellInsertionZone.js';
|
|
6
|
+
import SettingsModal from './SettingsModal.js';
|
|
7
|
+
import InfoModal from './InfoModal.js';
|
|
8
8
|
|
|
9
9
|
createApp({
|
|
10
|
-
components: {
|
|
10
|
+
components: { AppNavbar, NotebookCell, CellInsertionZone, SettingsModal, InfoModal },
|
|
11
11
|
setup() {
|
|
12
12
|
// Extract token from URL
|
|
13
13
|
const urlParams = new URLSearchParams(window.location.search);
|
|
@@ -395,6 +395,8 @@ createApp({
|
|
|
395
395
|
const r = await response.json();
|
|
396
396
|
if (r.status === 'error') {
|
|
397
397
|
throw new Error(r.message || 'Execution failed');
|
|
398
|
+
} else if (r.details !== 'ok') {
|
|
399
|
+
throw new Error('Cell execution error');
|
|
398
400
|
} else {
|
|
399
401
|
console.log('Cell executed:', cellIndex, r.details);
|
|
400
402
|
// Update outputs in the notebook model
|
|
@@ -405,9 +407,11 @@ createApp({
|
|
|
405
407
|
if (r.last_executed_cell !== undefined && r.last_executed_cell !== null) {
|
|
406
408
|
lastRunIndex.value = r.last_executed_cell;
|
|
407
409
|
}
|
|
410
|
+
//
|
|
408
411
|
}
|
|
409
412
|
} catch (err) {
|
|
410
|
-
|
|
413
|
+
running.value = false; // No longer running.
|
|
414
|
+
throw new Error(err.message);
|
|
411
415
|
}
|
|
412
416
|
};
|
|
413
417
|
|
|
@@ -461,13 +465,7 @@ createApp({
|
|
|
461
465
|
}
|
|
462
466
|
};
|
|
463
467
|
|
|
464
|
-
const
|
|
465
|
-
// Get the Gemini API key from the server settings.
|
|
466
|
-
|
|
467
|
-
showSettings.value = true;
|
|
468
|
-
};
|
|
469
|
-
|
|
470
|
-
const closeSettings = async () => {
|
|
468
|
+
const saveSettings = async (newKey) => {
|
|
471
469
|
// Save the Gemini API key to the server
|
|
472
470
|
try {
|
|
473
471
|
const response = await fetch(`/set_key?token=${authToken}`, {
|
|
@@ -483,21 +481,13 @@ createApp({
|
|
|
483
481
|
} catch (err) {
|
|
484
482
|
throw new Error('Error saving API key: ' + err.message);
|
|
485
483
|
}
|
|
486
|
-
|
|
484
|
+
geminiApiKey.value = newKey;
|
|
487
485
|
};
|
|
488
486
|
|
|
489
487
|
const genError = () => {
|
|
490
488
|
throw new Error('This is a generated error for testing purposes. This is a generated error for testing purposes. This is a generated error for testing purposes. This is a generated error for testing purposes. ');
|
|
491
489
|
}
|
|
492
490
|
|
|
493
|
-
const openInfo = () => {
|
|
494
|
-
showInfo.value = true;
|
|
495
|
-
};
|
|
496
|
-
|
|
497
|
-
const closeInfo = () => {
|
|
498
|
-
showInfo.value = false;
|
|
499
|
-
};
|
|
500
|
-
|
|
501
491
|
const closeUiError = () => {
|
|
502
492
|
uiError.value = null;
|
|
503
493
|
};
|
|
@@ -528,8 +518,7 @@ createApp({
|
|
|
528
518
|
validateCode, dismissValidation, resetAndRunAllCells,
|
|
529
519
|
setActiveCell, runCell, running, lastRunIndex, asRead, runAllCells,
|
|
530
520
|
interruptKernel, insertCell, markdownEditKey,
|
|
531
|
-
|
|
532
|
-
openInfo, closeInfo, showInfo,
|
|
521
|
+
saveSettings, showSettings, showInfo,
|
|
533
522
|
genError, uiError, closeUiError,
|
|
534
523
|
explanationEditKey, deleteCell, moveCell, geminiApiKey };
|
|
535
524
|
},
|
plainbook/main.py
CHANGED
|
@@ -183,7 +183,8 @@ def execute_cell():
|
|
|
183
183
|
print(f"Executing cell {cell_index}")
|
|
184
184
|
try:
|
|
185
185
|
outputs, details = notebook.execute_cell(cell_index)
|
|
186
|
-
return dict(status="ok", details=details,
|
|
186
|
+
return dict(status="ok", details=details,
|
|
187
|
+
outputs=outputs, last_executed_cell=notebook.last_executed_cell)
|
|
187
188
|
except CellExecutionError as e:
|
|
188
189
|
# The execution error is already captured in the cell outputs.
|
|
189
190
|
return dict(status="ok", details="CellExecutionError",
|
plainbook/views/index.html
CHANGED
|
@@ -33,81 +33,22 @@
|
|
|
33
33
|
<div id="app"></div>
|
|
34
34
|
|
|
35
35
|
<script type="text/x-template" id="app-template">
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
<span class="icon"><i class="fa fa-refresh"></i></span>
|
|
53
|
-
<span>Refresh</span>
|
|
54
|
-
</button>
|
|
55
|
-
<!-- Interrupt execution -->
|
|
56
|
-
<button v-if="running && notebook"
|
|
57
|
-
@click="interruptKernel"
|
|
58
|
-
class="button is-danger" title="Interrupt Execution">
|
|
59
|
-
<span class="icon"><i class="fa fa-stop"></i></span>
|
|
60
|
-
<span>Running...</span>
|
|
61
|
-
</button>
|
|
62
|
-
<!-- Status -->
|
|
63
|
-
<button v-if="!running && notebook && lastRunIndex >= notebook.cells.length - 1"
|
|
64
|
-
class="button is-light" title="All cells have been run">
|
|
65
|
-
<span class="icon"><i class="fa fa-check-circle"></i></span>
|
|
66
|
-
<span>Up to Date</span>
|
|
67
|
-
</button>
|
|
68
|
-
<!-- Running -->
|
|
69
|
-
<!-- <button v-if="!running && notebook"
|
|
70
|
-
:disabled="notebook.cells.length === 0 || isLocked"
|
|
71
|
-
@click="regenerateAndRunAllCode" title="Regenerate all code from descriptions and run it all"
|
|
72
|
-
class="button is-success">
|
|
73
|
-
<span class="icon"><i class="fa fa-repeat"></i></span>
|
|
74
|
-
<span class="icon"><i class="fa fa-play"></i></span>
|
|
75
|
-
</button> -->
|
|
76
|
-
<button v-if="!running && notebook"
|
|
77
|
-
:disabled="notebook.cells.length === 0 || isLocked"
|
|
78
|
-
@click="regenerateAllCode" title="Regenerate all code from descriptions"
|
|
79
|
-
class="button is-success">
|
|
80
|
-
<span class="icon"><i class="fa fa-repeat"></i></span>
|
|
81
|
-
<span>Regenerate All</span>
|
|
82
|
-
</button>
|
|
83
|
-
<button v-if="!running && notebook"
|
|
84
|
-
:disabled="notebook.cells.length === 0"
|
|
85
|
-
@click="resetAndRunAllCells" title="Reset and run all cells"
|
|
86
|
-
class="button is-primary">
|
|
87
|
-
<span class="icon"><i class="fa fa-play"></i></span>
|
|
88
|
-
<span>Reset and Run All</span>
|
|
89
|
-
</button>
|
|
90
|
-
</div>
|
|
91
|
-
</div>
|
|
92
|
-
</div>
|
|
93
|
-
<div class="navbar-end">
|
|
94
|
-
<div class="navbar-item">
|
|
95
|
-
<div class="buttons">
|
|
96
|
-
<!-- <button id="btn-info" class="button is-danger" @click="genError">
|
|
97
|
-
<span class="icon"><i class="fa fa-exclamation"></i></span>
|
|
98
|
-
</button> -->
|
|
99
|
-
<button id="btn-info" class="button is-light" @click="openInfo" title="About Plainbook">
|
|
100
|
-
<span class="icon"><i class="fa fa-info"></i></span>
|
|
101
|
-
</button>
|
|
102
|
-
<button id="btn-settings" class="button" :class="geminiApiKey ? 'is-light' : 'is-warning'" @click="openSettings" title="Settings">
|
|
103
|
-
<span class="icon"><i :class="geminiApiKey ? 'fa fa-cog' : 'fa fa-warning'"></i></span>
|
|
104
|
-
<span>Settings</span>
|
|
105
|
-
</button>
|
|
106
|
-
</div>
|
|
107
|
-
</div>
|
|
108
|
-
</div>
|
|
109
|
-
</div>
|
|
110
|
-
</nav>
|
|
36
|
+
|
|
37
|
+
<app-navbar
|
|
38
|
+
:is-locked="isLocked"
|
|
39
|
+
:running="running"
|
|
40
|
+
:has-notebook="!!notebook"
|
|
41
|
+
:last-run-index="lastRunIndex"
|
|
42
|
+
:cell-count="notebook ? notebook.cells.length : 0"
|
|
43
|
+
:has-api-key="!!geminiApiKey"
|
|
44
|
+
@lock="lockNotebook"
|
|
45
|
+
@refresh="reloadNotebook"
|
|
46
|
+
@interrupt="interruptKernel"
|
|
47
|
+
@regenerate-all="regenerateAllCode"
|
|
48
|
+
@reset-run-all="resetAndRunAllCells"
|
|
49
|
+
@open-info="showInfo = true"
|
|
50
|
+
@open-settings="showSettings = true"
|
|
51
|
+
/>
|
|
111
52
|
|
|
112
53
|
<div v-if="uiError" class="notification mb-0 mt-0 px-4 pl-2 pr-6 has-text-danger has-background-danger-light"
|
|
113
54
|
style="width: 100%; border-radius: 0; align-items: center; justify-content: space-between;">
|
|
@@ -129,135 +70,61 @@
|
|
|
129
70
|
<strong>Error:</strong> {{ error }}
|
|
130
71
|
</div>
|
|
131
72
|
<div v-else="notebook">
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
73
|
+
|
|
74
|
+
<cell-insertion-zone v-if="!isLocked"
|
|
75
|
+
@insert="(celltype) => insertCell(0, celltype)"
|
|
76
|
+
/>
|
|
77
|
+
|
|
136
78
|
<template v-for="(cell, index) in notebook.cells" :key="index">
|
|
137
|
-
<!-- Insert zone before each cell -->
|
|
138
|
-
<div v-if="!isLocked" class="cell-insert-zone">
|
|
139
|
-
<div class="cell-insert-buttons">
|
|
140
|
-
<button class="button insert-cell is-info is-small py-0 px-3" @click.stop="insertCell(index, 'markdown')">Insert Comment</button>
|
|
141
|
-
<button class="button insert-cell is-info is-small py-0 px-3" @click.stop="insertCell(index, 'code')">Insert Action</button>
|
|
142
|
-
</div>
|
|
143
|
-
</div>
|
|
144
79
|
|
|
145
|
-
<
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
80
|
+
<notebook-cell
|
|
81
|
+
:cell="cell"
|
|
82
|
+
:is-active="activeIndex === index"
|
|
83
|
+
:needs-running="index > lastRunIndex"
|
|
84
|
+
:is-locked="isLocked"
|
|
85
|
+
:last-run-index="lastRunIndex"
|
|
86
|
+
:as-read="asRead"
|
|
87
|
+
:markdown-edit-key="markdownEditKey[index]"
|
|
88
|
+
:explanation-edit-key="explanationEditKey[index]"
|
|
89
|
+
@click="setActiveCell(index)"
|
|
90
|
+
|
|
91
|
+
@save-markdown="(content) => sendMarkdownToServer(content, index)"
|
|
92
|
+
@save-explanation="(content) => sendExplanationToServer(content, index)"
|
|
93
|
+
@save-code="(content) => sendCodeToServer(content, index)"
|
|
94
|
+
@save-and-run="(content) => saveExplanationAndRun(content, index)"
|
|
95
|
+
|
|
96
|
+
@run-cell="runCell(index)"
|
|
97
|
+
@generate-code="generateCode(index)"
|
|
98
|
+
@validate-code="validateCode(index)"
|
|
99
|
+
@dismiss-validation="dismissValidation(index)"
|
|
100
|
+
|
|
101
|
+
@delete="deleteCell(index)"
|
|
102
|
+
@move-up="moveCell(index, -1)"
|
|
103
|
+
@move-down="moveCell(index, 1)"
|
|
104
|
+
/>
|
|
105
|
+
|
|
106
|
+
<cell-insertion-zone v-if="!isLocked"
|
|
107
|
+
@insert="(celltype) => insertCell(index + 1, celltype)"
|
|
108
|
+
/>
|
|
160
109
|
|
|
161
|
-
<div v-if="cell.cell_type === 'code'">
|
|
162
|
-
<div v-if="cell.metadata?.explanation" class="has-background-light p-0 border-bottom">
|
|
163
|
-
<explanation-editor :source="cell.metadata.explanation"
|
|
164
|
-
:isActive="activeIndex === index"
|
|
165
|
-
:isLocked="isLocked"
|
|
166
|
-
:index="index" :asRead="asRead"
|
|
167
|
-
:lastRunIndex="lastRunIndex"
|
|
168
|
-
:start-edit-key="explanationEditKey[index]"
|
|
169
|
-
@save="(content) => sendExplanationToServer(content, index)"
|
|
170
|
-
@gencode="() => generateCode(index)"
|
|
171
|
-
@validate="() => validateCode(index)"
|
|
172
|
-
@run="() => runCell(index)"
|
|
173
|
-
@saveandrun="(content) => saveExplanationAndRun (content, index)"
|
|
174
|
-
@delete="deleteCell(index)"
|
|
175
|
-
@moveUp="moveCell(index, -1)"
|
|
176
|
-
@moveDown="moveCell(index, 1)" />
|
|
177
|
-
</div>
|
|
178
|
-
<div v-if="cell.metadata?.validation && !cell.metadata?.validation.is_hidden">
|
|
179
|
-
<validation-cell :validation="cell.metadata.validation"
|
|
180
|
-
:index="index"
|
|
181
|
-
@dismiss_validation="dismissValidation" />
|
|
182
|
-
</div>
|
|
183
|
-
<code-cell :source="cell.source"
|
|
184
|
-
:execution-count="cell.execution_count"
|
|
185
|
-
:is-active="activeIndex === index"
|
|
186
|
-
:is-locked="isLocked"
|
|
187
|
-
@save="(content) => sendCodeToServer(content, index)" />
|
|
188
|
-
|
|
189
|
-
<div v-if="cell.outputs?.length" class="p-2 border-top has-background-white">
|
|
190
|
-
<output-renderer v-for="(out, oIdx) in cell.outputs" :key="oIdx" :output="out" />
|
|
191
|
-
</div>
|
|
192
|
-
</div>
|
|
193
|
-
</div>
|
|
194
110
|
</template>
|
|
195
111
|
|
|
196
|
-
<!-- Insert zone after the last cell -->
|
|
197
|
-
<div v-if="!isLocked && !notebook.cells.length > 0" class="cell-insert-zone">
|
|
198
|
-
<div class="cell-insert-buttons">
|
|
199
|
-
<button class="button insert-cell is-info is-small py-0 px-3" @click.stop="insertCell(notebook.cells.length, 'markdown')">Insert Comment</button>
|
|
200
|
-
<button class="button insert-cell is-info is-small py-0 px-3" @click.stop="insertCell(notebook.cells.length, 'code')">Insert Action</button>
|
|
201
|
-
</div>
|
|
202
|
-
</div>
|
|
203
112
|
</div>
|
|
204
113
|
</div>
|
|
205
114
|
</div>
|
|
206
115
|
|
|
207
116
|
<!-- Settings Modal -->
|
|
208
|
-
<
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
</header>
|
|
215
|
-
<section class="modal-card-body">
|
|
216
|
-
<div class="field">
|
|
217
|
-
<label class="label">Gemini API Key</label>
|
|
218
|
-
<div class="control">
|
|
219
|
-
<input class="input" type="text" v-model="geminiApiKey" placeholder="Enter your Gemini API key">
|
|
220
|
-
</div>
|
|
221
|
-
<p class="help">Your API key is stored locally in ~/.settings/plainbook and used for AI-powered features.</p>
|
|
222
|
-
</div>
|
|
223
|
-
</section>
|
|
224
|
-
<footer class="modal-card-foot">
|
|
225
|
-
<button class="button" @click="closeSettings">Close</button>
|
|
226
|
-
</footer>
|
|
227
|
-
</div>
|
|
228
|
-
</div>
|
|
229
|
-
|
|
117
|
+
<settings-modal
|
|
118
|
+
:is-active="showSettings"
|
|
119
|
+
:api-key="geminiApiKey"
|
|
120
|
+
@close="showSettings = false"
|
|
121
|
+
@save="(newKey) => {showSettings = false; saveSettings(newKey); }"
|
|
122
|
+
/>
|
|
230
123
|
<!-- Info Modal -->
|
|
231
|
-
<
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
<p class="modal-card-title">Information</p>
|
|
236
|
-
<button class="delete" aria-label="close" @click="closeInfo"></button>
|
|
237
|
-
</header>
|
|
238
|
-
<section class="modal-card-body">
|
|
239
|
-
<h1 class="title">Plainbook</h1>
|
|
240
|
-
<div class="content">
|
|
241
|
-
<p>Plainbook is an interactive notebook application for creating executable doocuments in
|
|
242
|
-
natural language. A notebook consists of:</p>
|
|
243
|
-
<ul>
|
|
244
|
-
<li><strong>Action cells</strong> that contain an English explanation. The explanation is
|
|
245
|
-
used to generate Python code using an AI model. The generated code is then executed,
|
|
246
|
-
and the output is displayed below the cell.</li>
|
|
247
|
-
<li><strong>Markdown cells</strong> for writing explanations, comments, and documentation in rich text format.</li>
|
|
248
|
-
</ul>
|
|
249
|
-
<p>If you lock a notebook, editing of cells and generation of code will be disabled
|
|
250
|
-
to prevent accidental changes. However, you can still validate the code against
|
|
251
|
-
its description, and you can still run the notebook.
|
|
252
|
-
Unlock it to be able to edit again.</p>
|
|
253
|
-
<p><a href="https://github.com/lucadealfaro/plainbook" target="_blank">Plainbook Home Page</a></p>
|
|
254
|
-
</div>
|
|
255
|
-
</section>
|
|
256
|
-
<footer class="modal-card-foot">
|
|
257
|
-
<button class="button" @click="closeInfo">Close</button>
|
|
258
|
-
</footer>
|
|
259
|
-
</div>
|
|
260
|
-
</div>
|
|
124
|
+
<info-modal
|
|
125
|
+
:is-active="showInfo"
|
|
126
|
+
@close="showInfo = false"
|
|
127
|
+
/>
|
|
261
128
|
|
|
262
129
|
</script>
|
|
263
130
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
plainbook/__init__.py,sha256=AbpHGcgLb-kRsJGnwFEktk7uzpZOCcBY74-YBdrKVGs,1
|
|
2
2
|
plainbook/gemini.py,sha256=4lgvMdQdcKyMZLSnu9yhwlaI4LaSvvyr_-SA0DdI628,2915
|
|
3
|
-
plainbook/main.py,sha256=
|
|
3
|
+
plainbook/main.py,sha256=XruVZYj-nQ-2V9wiGKO7AV0-Via0Rz2CUafuX1id3J8,10172
|
|
4
4
|
plainbook/plainbook.py,sha256=zgi3e50r9vFfMLxXuMVcvyB9I7yEJOgZthxnz3RxuKw,17063
|
|
5
5
|
plainbook/css/font-awesome.css,sha256=NuCn4IvuZXdBaFKJOAcsU2Q3ZpwbdFisd5dux4jkQ5w,37414
|
|
6
6
|
plainbook/css/font-awesome.min.css,sha256=eZrrJcwDc_3uDhsdt61sL2oOBY362qM3lon1gyExkL0,31000
|
|
@@ -12,20 +12,25 @@ plainbook/fonts/fontawesome-webfont.svg,sha256=rWFXkmwWIrpOHQPUePFUE2hSS_xG9R5C_
|
|
|
12
12
|
plainbook/fonts/fontawesome-webfont.ttf,sha256=qljzPyOaD7AvXHpsRcBD16msmgkzNYBmlOzW1O3A1qg,165548
|
|
13
13
|
plainbook/fonts/fontawesome-webfont.woff,sha256=ugxZ3rVFD1y0Gz-TYJ7i0NmVQVh33foiPoqKdTNHTwc,98024
|
|
14
14
|
plainbook/fonts/fontawesome-webfont.woff2,sha256=Kt78vAQefRj88tQXh53FoJmXqmTWdbejxLbOM9oT8_4,77160
|
|
15
|
-
plainbook/js/
|
|
16
|
-
plainbook/js/
|
|
17
|
-
plainbook/js/
|
|
15
|
+
plainbook/js/AppNavbar.js,sha256=nEX2CXdI0136Usj-YVts6QXV4xd_vbsXh9-mPvgbi5E,3968
|
|
16
|
+
plainbook/js/CellInsertionZone.js,sha256=XPo2hmuG9lfVzYbZ1bBO-44HiyCFngHzxoUa56v42s8,676
|
|
17
|
+
plainbook/js/CodeCell.js,sha256=cK6YOKVu58g4h7KmH2aL3LA99oxe8Z3ZZpLRF0k6XZY,6943
|
|
18
|
+
plainbook/js/ExplanationEditor.js,sha256=FDflmKZKzNHkKgXHwsYrbQDLDK1ROVg00-5p9cj2jlc,7088
|
|
19
|
+
plainbook/js/InfoModal.js,sha256=ShylUmDQdQ-2g-z6PlvZ_TTlxCSdNGJJICu-RAAwab8,1442
|
|
20
|
+
plainbook/js/MarkdownCell.js,sha256=SxU_LO4TGcxOEy6sKognF_gHUXwmqR6BDsv4z0tlgVQ,5292
|
|
21
|
+
plainbook/js/NotebookCell.js,sha256=PNWdd6VSWtD1nHeUCHPEZWIwBMQT26rjN6-P0rPCEZI,3239
|
|
18
22
|
plainbook/js/OutputRenderer.js,sha256=KXECI2xd0Sk_TnZnAfqfhL0dEIT9pjZZTXo6Qdiw0o4,2981
|
|
19
|
-
plainbook/js/
|
|
23
|
+
plainbook/js/SettingsModal.js,sha256=HpU2gKj26zZHhilcfp3hghEsW-sxsgq1HBlcsIBDGCI,1689
|
|
24
|
+
plainbook/js/ValidationCell.js,sha256=4XdlBNELTpeARiNVh55_7ay24CEY-aUNJy1knX8I9MU,1595
|
|
20
25
|
plainbook/js/markdown-it.min.js,sha256=hNyljag6giCsjv_yKmxK8_VeHzvMDvc5u8AzmRvm1BI,103012
|
|
21
|
-
plainbook/js/nb.js,sha256=
|
|
26
|
+
plainbook/js/nb.js,sha256=CZs32sAevGsea7PUjJK0Prd-7_mz1G82_S9_Hpx5gmQ,22822
|
|
22
27
|
plainbook/js/prism-python.min.js,sha256=7UOFaFvPLUk1yNu6tL3hZgPaEyngktK_NsPa3WfpqFw,2113
|
|
23
28
|
plainbook/js/prism.min.js,sha256=57iL3cbHV7L8jLET4kaYAasUp47BqPraTWOR41c_X58,18997
|
|
24
29
|
plainbook/js/vue.esm-browser.js,sha256=75FuLhUTPk19sncwNIrm0BGEL0_Qw298-_v01fPWYoI,542872
|
|
25
|
-
plainbook/views/index.html,sha256=
|
|
26
|
-
plainbook-0.0.
|
|
27
|
-
plainbook-0.0.
|
|
28
|
-
plainbook-0.0.
|
|
29
|
-
plainbook-0.0.
|
|
30
|
-
plainbook-0.0.
|
|
31
|
-
plainbook-0.0.
|
|
30
|
+
plainbook/views/index.html,sha256=Y_iA3eMd7X7BSkDgyPR3MghxvzOFnOZ8mmDizRb1iIM,5251
|
|
31
|
+
plainbook-0.0.9.dist-info/licenses/LICENSE.md,sha256=JW6Hp9mBeCkRkCSeiT2KmIU3XA5mJorjcIlM2cOOxyU,1462
|
|
32
|
+
plainbook-0.0.9.dist-info/METADATA,sha256=RbHMpf1Y4mJ6U4DKR6D0NknrfDUFrrtNnn-gEKAR8dY,3023
|
|
33
|
+
plainbook-0.0.9.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
|
34
|
+
plainbook-0.0.9.dist-info/entry_points.txt,sha256=fktud-zRh9ZZ4rXv5w6kW-78u44lSYklXY1ttMTB9k8,50
|
|
35
|
+
plainbook-0.0.9.dist-info/top_level.txt,sha256=Y3jOV2n79dczNw9tJ7acufz3y3ns2pWw8b06sIN4ltc,10
|
|
36
|
+
plainbook-0.0.9.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|