pinokiod 3.6.29 → 3.6.30
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.
- package/kernel/api/index.js +97 -26
- package/kernel/bin/index.js +127 -4
- package/kernel/bin/node.js +5 -0
- package/kernel/index.js +39 -1
- package/kernel/shell.js +34 -16
- package/kernel/shells.js +1 -0
- package/kernel/store.js +58 -0
- package/kernel/sysinfo.js +22 -12
- package/kernel/util.js +28 -7
- package/package.json +1 -1
- package/script/index.js +12 -0
- package/server/index.js +270 -187
- package/server/public/pinokio-black.png +0 -0
- package/server/public/pinokio-black2.png +0 -0
- package/server/public/style.css +5 -0
- package/server/socket.js +87 -34
- package/server/views/app.ejs +14 -2
- package/server/views/editor.ejs +12 -2
- package/server/views/index.ejs +27 -36
- package/server/views/terminal.ejs +56 -12
package/server/socket.js
CHANGED
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
const WebSocket = require('ws');
|
|
2
|
+
const Util = require("../kernel/util")
|
|
2
3
|
class Socket {
|
|
3
4
|
constructor(parent) {
|
|
4
5
|
this.buffer = {}
|
|
5
6
|
this.connected = {}
|
|
7
|
+
this.active_shell = {}
|
|
6
8
|
this.parent = parent
|
|
7
9
|
this.server = parent.server
|
|
8
10
|
// this.kernel = parent.kernel
|
|
@@ -25,42 +27,65 @@ class Socket {
|
|
|
25
27
|
// look for repos that match
|
|
26
28
|
|
|
27
29
|
if (req.uri) {
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
ws.send(JSON.stringify({
|
|
43
|
-
data: this.parent.kernel.api.running[id] ? true : false
|
|
44
|
-
}))
|
|
45
|
-
} else if (req.stop) {
|
|
46
|
-
this.parent.kernel.api.stop({ params: req })
|
|
30
|
+
if (req.mode === "open") {
|
|
31
|
+
// get the default script and respond
|
|
32
|
+
let id = this.parent.kernel.api.filePath(req.uri)
|
|
33
|
+
try {
|
|
34
|
+
let default_url = await this.parent.kernel.api.get_default(id)
|
|
35
|
+
console.log({ id, default_url })
|
|
36
|
+
ws.send(JSON.stringify({
|
|
37
|
+
data: {
|
|
38
|
+
uri: default_url
|
|
39
|
+
}
|
|
40
|
+
}))
|
|
41
|
+
} catch (e) {
|
|
42
|
+
console.log(e)
|
|
43
|
+
}
|
|
47
44
|
} else {
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
45
|
+
console.log("REQ.URI", req.uri)
|
|
46
|
+
if (req.uri.startsWith("http")) {
|
|
47
|
+
// open
|
|
48
|
+
Util.openfs(req.uri, { mode: "open" })
|
|
49
|
+
} else {
|
|
50
|
+
/******************************************************************
|
|
51
|
+
*
|
|
52
|
+
* req.uri is ALWAYS either of the two:
|
|
53
|
+
* 1. ~/...
|
|
54
|
+
* 2. https://github.com/...
|
|
55
|
+
*
|
|
56
|
+
* Need to turn it into absolute file path before subscribing
|
|
57
|
+
*
|
|
58
|
+
******************************************************************/
|
|
59
|
+
|
|
60
|
+
// req.uri is always http or absolute path
|
|
61
|
+
let id = this.parent.kernel.api.filePath(req.uri)
|
|
62
|
+
|
|
63
|
+
if (req.status) {
|
|
64
|
+
ws.send(JSON.stringify({
|
|
65
|
+
data: this.parent.kernel.api.running[id] ? true : false
|
|
66
|
+
}))
|
|
67
|
+
} else if (req.stop) {
|
|
68
|
+
this.parent.kernel.api.stop({ params: req })
|
|
69
|
+
} else {
|
|
70
|
+
let buf = this.buffer[id]
|
|
71
|
+
let sh = this.active_shell[id]
|
|
72
|
+
this.subscribe(ws, id, buf, sh)
|
|
73
|
+
if (req.mode !== "listen") {
|
|
74
|
+
// Run only if currently not running
|
|
75
|
+
if (!this.parent.kernel.api.running[id]) {
|
|
76
|
+
|
|
77
|
+
// clear the log first
|
|
78
|
+
|
|
79
|
+
await this.parent.kernel.clearLog(id)
|
|
80
|
+
|
|
81
|
+
|
|
82
|
+
this.parent.kernel.api.process(req)
|
|
83
|
+
}
|
|
84
|
+
}
|
|
60
85
|
}
|
|
61
86
|
}
|
|
62
|
-
}
|
|
63
87
|
|
|
88
|
+
}
|
|
64
89
|
} else if (req.method) {
|
|
65
90
|
this.subscribe(ws, req.method)
|
|
66
91
|
if (req.mode !== "listen") {
|
|
@@ -68,6 +93,11 @@ class Socket {
|
|
|
68
93
|
}
|
|
69
94
|
} else if (req.emit) {
|
|
70
95
|
this.parent.kernel.shell.emit(req)
|
|
96
|
+
} else if (req.key && req.id) {
|
|
97
|
+
this.parent.kernel.shell.emit({
|
|
98
|
+
id: req.id,
|
|
99
|
+
emit: req.key
|
|
100
|
+
})
|
|
71
101
|
}
|
|
72
102
|
}
|
|
73
103
|
|
|
@@ -78,11 +108,16 @@ class Socket {
|
|
|
78
108
|
headers.push('Access-Control-Allow-Headers: Origin, X-Requested-With, Content-Type, Accept');
|
|
79
109
|
});
|
|
80
110
|
}
|
|
81
|
-
subscribe(ws, id) {
|
|
111
|
+
subscribe(ws, id, buf, sh) {
|
|
82
112
|
|
|
83
113
|
if (this.parent.kernel.api.running[id]) {
|
|
84
114
|
ws.send(JSON.stringify({
|
|
85
|
-
type: "connect"
|
|
115
|
+
type: "connect",
|
|
116
|
+
data: {
|
|
117
|
+
id,
|
|
118
|
+
state: buf,
|
|
119
|
+
shell: sh
|
|
120
|
+
}
|
|
86
121
|
}))
|
|
87
122
|
}
|
|
88
123
|
|
|
@@ -120,6 +155,15 @@ class Socket {
|
|
|
120
155
|
});
|
|
121
156
|
}
|
|
122
157
|
|
|
158
|
+
if (!this.buffer[id]) {
|
|
159
|
+
this.buffer[id] = ""
|
|
160
|
+
}
|
|
161
|
+
if (e.data && e.data.raw) this.buffer[id] += e.data.raw
|
|
162
|
+
|
|
163
|
+
if (e.data && e.data.shell_id) {
|
|
164
|
+
this.active_shell[id] = e.data.shell_id
|
|
165
|
+
}
|
|
166
|
+
|
|
123
167
|
// send to caller session
|
|
124
168
|
if (e.caller) {
|
|
125
169
|
let caller
|
|
@@ -148,6 +192,15 @@ class Socket {
|
|
|
148
192
|
}
|
|
149
193
|
});
|
|
150
194
|
}
|
|
195
|
+
|
|
196
|
+
if (!this.buffer[caller]) {
|
|
197
|
+
this.buffer[caller] = ""
|
|
198
|
+
}
|
|
199
|
+
if (e.data.raw) this.buffer[caller] += e.data.raw
|
|
200
|
+
|
|
201
|
+
if (e.data && e.data.shell_id) {
|
|
202
|
+
this.active_shell[caller] = e.data.shell_id
|
|
203
|
+
}
|
|
151
204
|
}
|
|
152
205
|
}
|
|
153
206
|
}
|
package/server/views/app.ejs
CHANGED
|
@@ -29,7 +29,9 @@
|
|
|
29
29
|
*/
|
|
30
30
|
}
|
|
31
31
|
#menu.margin {
|
|
32
|
+
/*
|
|
32
33
|
padding: 5px;
|
|
34
|
+
*/
|
|
33
35
|
}
|
|
34
36
|
#menu.margin i {
|
|
35
37
|
display: none;
|
|
@@ -580,7 +582,7 @@ body.dark .loader-container {
|
|
|
580
582
|
<div class='header-top header-item'>
|
|
581
583
|
<div class='app-info'>
|
|
582
584
|
<% if (config.icon) { %>
|
|
583
|
-
<img src="<%=
|
|
585
|
+
<img src="<%=config.icon%>"/>
|
|
584
586
|
<% } else { %>
|
|
585
587
|
<i class="fa-regular fa-circle-dot"></i>
|
|
586
588
|
<% } %>
|
|
@@ -595,6 +597,15 @@ body.dark .loader-container {
|
|
|
595
597
|
<a target="<%=src%>" href="<%=src%>" class='btn header-item frame-link' data-index="0">
|
|
596
598
|
<div class='tab'><i class="fa-regular fa-folder-open"></i> Files <div class='disk-usage'></div></div>
|
|
597
599
|
</a>
|
|
600
|
+
<div class='shells'>
|
|
601
|
+
<% shells.forEach((shell, index) => { %>
|
|
602
|
+
<a target="SHELL<%=index%>" data-mode="" href="<%=shell%>" class='btn header-item frame-link'>
|
|
603
|
+
<div class='tab'>
|
|
604
|
+
<i class='fa-solid fa-terminal'></i> <%=shell%></i>
|
|
605
|
+
</div>
|
|
606
|
+
</a>
|
|
607
|
+
<% }) %>
|
|
608
|
+
</div>
|
|
598
609
|
<a target="/share/<%=name%>" href="/share/<%=name%>", class="btn header-item frame-link" data-index="1" data-mode="refresh">
|
|
599
610
|
<div class='tab'><i class="fa-solid fa-wifi"></i> Share</div>
|
|
600
611
|
</a>
|
|
@@ -653,7 +664,7 @@ body.dark .loader-container {
|
|
|
653
664
|
<div class='bar'>
|
|
654
665
|
<button class='btn2' id='menu-mobile'><i class="fa-solid fa-bars"></i></button>
|
|
655
666
|
<button class='btn2' id='menu'>
|
|
656
|
-
<img src="<%=
|
|
667
|
+
<img src="<%=config.icon%>"/>
|
|
657
668
|
<i class="fa-solid fa-arrow-right-to-bracket fa-rotate-180"></i>
|
|
658
669
|
</button>
|
|
659
670
|
<% if (agent === "electron") { %>
|
|
@@ -1510,6 +1521,7 @@ body.dark .loader-container {
|
|
|
1510
1521
|
console.log("asideHidden", asideHidden)
|
|
1511
1522
|
if (!asideHidden) {
|
|
1512
1523
|
// refresh only if aside
|
|
1524
|
+
console.log("type", event.data.type)
|
|
1513
1525
|
if (event.data.type === 'disconnect') {
|
|
1514
1526
|
console.log("Refresh 1")
|
|
1515
1527
|
refresh()
|
package/server/views/editor.ejs
CHANGED
|
@@ -113,6 +113,7 @@ body.frozen {
|
|
|
113
113
|
}
|
|
114
114
|
</style>
|
|
115
115
|
<script>
|
|
116
|
+
let shell_id
|
|
116
117
|
document.addEventListener("DOMContentLoaded", async () => {
|
|
117
118
|
<% if (error) { %>
|
|
118
119
|
document.querySelector(".requirements .content").innerHTML = '<div class="loading"><i class="fa-solid fa-circle-exclamation"></i> <%=error%></div>'
|
|
@@ -331,8 +332,17 @@ document.addEventListener("DOMContentLoaded", async () => {
|
|
|
331
332
|
|
|
332
333
|
} else if (packet.type === 'connect') {
|
|
333
334
|
// document.querySelector(".terminal-container").classList.remove("hidden")
|
|
334
|
-
|
|
335
|
-
|
|
335
|
+
if (packet.data.id) {
|
|
336
|
+
shell_id = packet.data.id
|
|
337
|
+
}
|
|
338
|
+
if (packet.data) {
|
|
339
|
+
if (packet.data.shell) {
|
|
340
|
+
shell_id = packet.data.shell
|
|
341
|
+
}
|
|
342
|
+
if (packet.data.state) {
|
|
343
|
+
this.write(packet.data.state)
|
|
344
|
+
}
|
|
345
|
+
}
|
|
336
346
|
/*
|
|
337
347
|
for(let i=0; i<message.length; i++) {
|
|
338
348
|
await new Promise((r, reject) => {
|
package/server/views/index.ejs
CHANGED
|
@@ -246,32 +246,6 @@ body.dark .browser-options-row {
|
|
|
246
246
|
<div>Serve Pinokio, installed apps, and even external apps (example: Ollama) to any device on the same network.</div>
|
|
247
247
|
</div>
|
|
248
248
|
</div>
|
|
249
|
-
<!--
|
|
250
|
-
<div class='browser-options-row'>
|
|
251
|
-
<a href="/proxy" class='flexible'>
|
|
252
|
-
<h3><i class="fa-solid fa-wifi"></i> Local Share</h3>
|
|
253
|
-
<div>Access Pinokio, Ollama, and other 3rd party apps from any device on the same network. By default it's off.</div>
|
|
254
|
-
</a>
|
|
255
|
-
<% if (false) { %>
|
|
256
|
-
<% if (proxy) { %>
|
|
257
|
-
<a id='wifi-stop' data-proxy="<%=proxy.proxy%>" class='btn'><div><i class="fa-solid fa-stop"></i> Stop</div></a>
|
|
258
|
-
<div class='flexible'>
|
|
259
|
-
<h3><i class="fa-solid fa-wifi"></i> Local Share</h3>
|
|
260
|
-
<div>Access Pinokio from any device on the same network. By default it's off.</div>
|
|
261
|
-
<span class='badge'><i class="fa-solid fa-circle-notch fa-spin"></i> Running at <a href="<%=proxy.proxy%>" target="_blank" features="browser"><%=proxy.proxy%></a></span>
|
|
262
|
-
<a id='wifi-qr' class='badge'><i class="fa-solid fa-qrcode"></i> Scan QR Code</a>
|
|
263
|
-
</div>
|
|
264
|
-
<% } else { %>
|
|
265
|
-
<a id='wifi' class='btn'><div><i class="fa-solid fa-play"></i> Start</div></a>
|
|
266
|
-
<a id='wifi-starting' class='btn disabled hidden'><div><i class="fa-solid fa-circle-notch fa-spin"></i> Starting</div></a>
|
|
267
|
-
<div class='flexible'>
|
|
268
|
-
<h3><i class="fa-solid fa-wifi"></i> Local Share</h3>
|
|
269
|
-
<div>Access Pinokio from any device on the same network. By default it's off.</div>
|
|
270
|
-
</div>
|
|
271
|
-
<% } %>
|
|
272
|
-
<% } %>
|
|
273
|
-
</div>
|
|
274
|
-
-->
|
|
275
249
|
<div class='browser-options-row hidden'>
|
|
276
250
|
<% if (cloudflare_pub) { %>
|
|
277
251
|
<a id='cloudflare-stop' class='btn'><div><i class="fa-solid fa-stop"></i> Stop</div></a>
|
|
@@ -292,17 +266,10 @@ body.dark .browser-options-row {
|
|
|
292
266
|
</div>
|
|
293
267
|
</div>
|
|
294
268
|
<% } %>
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
<a class='type-tab' href="/"><img src='/pinokio-<%=theme=='dark' ? 'white' : 'black'%>.png'> Apps</a>
|
|
299
|
-
<a class='type-tab selected' href="/?mode=task"> <img src='/<%=theme=='dark' ? 'term-dark.png' : 'term-white.png'%>'> Tasks</a>
|
|
300
|
-
<% } else { %>
|
|
301
|
-
<a class='type-tab selected' href="/"><img src='/pinokio-<%=theme=='dark' ? 'white' : 'black'%>.png'> Apps</a>
|
|
302
|
-
<a class='type-tab' href="/?mode=task"> <img src='/<%=theme=='dark' ? 'term-dark.png' : 'term-white.png'%>'> Tasks</a>
|
|
303
|
-
<% } %>
|
|
269
|
+
<div id='fsmenu'>
|
|
270
|
+
<div class='flexible'></div>
|
|
271
|
+
<button id='newfolder' class='btn'><i class="fa-solid fa-folder-plus"></i> New Folder</button>
|
|
304
272
|
</div>
|
|
305
|
-
-->
|
|
306
273
|
<% if (running.length > 0) { %>
|
|
307
274
|
<div class='running-apps'>
|
|
308
275
|
<div class='header-label'>Running</div>
|
|
@@ -1094,6 +1061,30 @@ if (document.querySelector("#genlog")) {
|
|
|
1094
1061
|
})
|
|
1095
1062
|
})
|
|
1096
1063
|
}
|
|
1064
|
+
document.querySelector("#newfolder").addEventListener("click", async (e) => {
|
|
1065
|
+
let folder = prompt("Enter a folder name for the new folder")
|
|
1066
|
+
if (folder.includes(' ')) {
|
|
1067
|
+
alert("Please use a folder name without a space")
|
|
1068
|
+
return
|
|
1069
|
+
}
|
|
1070
|
+
let res = await fetch("/mkdir", {
|
|
1071
|
+
method: "post",
|
|
1072
|
+
headers: {
|
|
1073
|
+
"Content-Type": "application/json"
|
|
1074
|
+
},
|
|
1075
|
+
body: JSON.stringify({
|
|
1076
|
+
folder
|
|
1077
|
+
})
|
|
1078
|
+
}).then((res) => {
|
|
1079
|
+
return res.json()
|
|
1080
|
+
})
|
|
1081
|
+
if (res.error) {
|
|
1082
|
+
alert(res.error)
|
|
1083
|
+
} else {
|
|
1084
|
+
console.log(res)
|
|
1085
|
+
location.href = res.success
|
|
1086
|
+
}
|
|
1087
|
+
})
|
|
1097
1088
|
|
|
1098
1089
|
</script>
|
|
1099
1090
|
</body>
|
|
@@ -111,6 +111,7 @@ body.frozen {
|
|
|
111
111
|
</style>
|
|
112
112
|
<link href="/terminal.css" rel="stylesheet"/>
|
|
113
113
|
<script>
|
|
114
|
+
let shell_id
|
|
114
115
|
document.addEventListener("DOMContentLoaded", async () => {
|
|
115
116
|
<% if (error) { %>
|
|
116
117
|
document.querySelector(".requirements .content").innerHTML = '<div class="loading"><i class="fa-solid fa-circle-exclamation"></i> <%=error%></div>'
|
|
@@ -137,9 +138,22 @@ document.addEventListener("DOMContentLoaded", async () => {
|
|
|
137
138
|
class RPC {
|
|
138
139
|
constructor() {
|
|
139
140
|
this.socket = new Socket()
|
|
141
|
+
this.buffer = []
|
|
140
142
|
}
|
|
141
143
|
write(text) {
|
|
142
|
-
|
|
144
|
+
// console.log(text)
|
|
145
|
+
// this.buffer += text;
|
|
146
|
+
// if (!this.timeout) {
|
|
147
|
+
// this.timeout = setTimeout(() => {
|
|
148
|
+
// console.log("write", this.buffer)
|
|
149
|
+
// this.term.write(this.buffer);
|
|
150
|
+
// this.buffer = "";
|
|
151
|
+
// this.timeout = null;
|
|
152
|
+
// }, 50);
|
|
153
|
+
// }
|
|
154
|
+
if (text !== "\u0007") {
|
|
155
|
+
this.term.write(text)
|
|
156
|
+
}
|
|
143
157
|
this.dirty = true
|
|
144
158
|
}
|
|
145
159
|
finished() {
|
|
@@ -234,7 +248,12 @@ document.addEventListener("DOMContentLoaded", async () => {
|
|
|
234
248
|
// </div>`
|
|
235
249
|
}
|
|
236
250
|
} else if (packet.type === "stream") {
|
|
251
|
+
// set the current shell id
|
|
252
|
+
if (packet.data.id) {
|
|
253
|
+
shell_id = packet.data.id
|
|
254
|
+
}
|
|
237
255
|
if (packet.data.raw) {
|
|
256
|
+
// console.log({ packet })
|
|
238
257
|
this.write(packet.data.raw)
|
|
239
258
|
} else if (packet.data.json) {
|
|
240
259
|
this.write(JSON.stringify(packet.data.json).replace(/\n/g, "\r\n"))
|
|
@@ -255,8 +274,14 @@ document.addEventListener("DOMContentLoaded", async () => {
|
|
|
255
274
|
document.querySelector(".run .play").classList.remove("hidden")
|
|
256
275
|
document.querySelector(".run .stop").classList.add("hidden")
|
|
257
276
|
} else if (packet.type === 'connect') {
|
|
258
|
-
|
|
259
|
-
|
|
277
|
+
if (packet.data) {
|
|
278
|
+
if (packet.data.shell) {
|
|
279
|
+
shell_id = packet.data.shell
|
|
280
|
+
}
|
|
281
|
+
if (packet.data.state) {
|
|
282
|
+
this.write(packet.data.state)
|
|
283
|
+
}
|
|
284
|
+
}
|
|
260
285
|
/*
|
|
261
286
|
for(let i=0; i<message.length; i++) {
|
|
262
287
|
await new Promise((r, reject) => {
|
|
@@ -465,7 +490,6 @@ document.addEventListener("DOMContentLoaded", async () => {
|
|
|
465
490
|
document.querySelector("#error-screen").classList.add("hidden")
|
|
466
491
|
})
|
|
467
492
|
*/
|
|
468
|
-
console.log("instance", instance)
|
|
469
493
|
instance.mark(packet.event)
|
|
470
494
|
let element = document.querySelector("mark")
|
|
471
495
|
element.scrollIntoView({ behavior: "smooth", block: "center" });
|
|
@@ -572,13 +596,19 @@ document.addEventListener("DOMContentLoaded", async () => {
|
|
|
572
596
|
}
|
|
573
597
|
const term = new Terminal(config)
|
|
574
598
|
term.open(document.querySelector("#terminal"))
|
|
575
|
-
|
|
576
599
|
term.attachCustomKeyEventHandler(event => {
|
|
577
|
-
if (event.ctrlKey && event.key === 'c'
|
|
578
|
-
|
|
600
|
+
if ((event.ctrlKey || event.metaKey) && event.key === 'c') {
|
|
601
|
+
const selection = term.getSelection();
|
|
602
|
+
if (selection) {
|
|
603
|
+
navigator.clipboard.writeText(selection);
|
|
604
|
+
return false;
|
|
605
|
+
}
|
|
579
606
|
}
|
|
580
|
-
if (event.ctrlKey && event.key === 'v'
|
|
581
|
-
|
|
607
|
+
if ((event.ctrlKey || event.metaKey) && event.key === 'v') {
|
|
608
|
+
navigator.clipboard.readText().then((text) => {
|
|
609
|
+
term.write(text);
|
|
610
|
+
})
|
|
611
|
+
return false
|
|
582
612
|
}
|
|
583
613
|
return true;
|
|
584
614
|
});
|
|
@@ -589,6 +619,17 @@ document.addEventListener("DOMContentLoaded", async () => {
|
|
|
589
619
|
////term.resize(cols, rows-5);
|
|
590
620
|
//term.resize(cols, rows);
|
|
591
621
|
|
|
622
|
+
term.onKey(({ key }) => {
|
|
623
|
+
if (this.socket) {
|
|
624
|
+
if (shell_id) {
|
|
625
|
+
this.socket.run({
|
|
626
|
+
key,
|
|
627
|
+
id: shell_id
|
|
628
|
+
})
|
|
629
|
+
}
|
|
630
|
+
}
|
|
631
|
+
});
|
|
632
|
+
|
|
592
633
|
const fitAddon = new FitAddon.FitAddon();
|
|
593
634
|
// const searchAddon = new SearchAddon.SearchAddon();
|
|
594
635
|
// const searchAddonBar = new SearchBarAddon.SearchBarAddon({searchAddon});
|
|
@@ -606,6 +647,7 @@ document.addEventListener("DOMContentLoaded", async () => {
|
|
|
606
647
|
fitAddon.fit();
|
|
607
648
|
this.term = term
|
|
608
649
|
this.fit = fitAddon
|
|
650
|
+
|
|
609
651
|
}
|
|
610
652
|
this.term.focus()
|
|
611
653
|
}
|
|
@@ -782,14 +824,16 @@ const reloadMemory = async () => {
|
|
|
782
824
|
<span class='starting hidden'><i class="fa-solid fa-circle-notch fa-spin"></i> Starting...</span>
|
|
783
825
|
<span class='stop hidden'><i class="fa-solid fa-stop"></i> Stop</span>
|
|
784
826
|
</div>
|
|
785
|
-
|
|
827
|
+
<% if (locals.filepath) { %>
|
|
828
|
+
<button class='btn' id='open-fs' data-filepath="<%=filepath%>"><i class="fa-solid fa-eye"></i> View File</button>
|
|
829
|
+
<% } %>
|
|
786
830
|
<!--
|
|
787
831
|
<button class='btn' id='open-log' data-logpath="<%=logpath%>"><i class="fa-solid fa-align-left"></i> View Logs</button>
|
|
788
832
|
-->
|
|
789
833
|
</div>
|
|
790
834
|
<% } %>
|
|
791
835
|
</header>
|
|
792
|
-
<% if (requirements_pending) { %>
|
|
836
|
+
<% if (locals.requirements_pending) { %>
|
|
793
837
|
<div class='requirements'>
|
|
794
838
|
<div class='content'>
|
|
795
839
|
<div class='loading'>
|
|
@@ -798,7 +842,7 @@ const reloadMemory = async () => {
|
|
|
798
842
|
</div>
|
|
799
843
|
</div>
|
|
800
844
|
<% } else { %>
|
|
801
|
-
<% if (install_required) { %>
|
|
845
|
+
<% if (locals.install_required) { %>
|
|
802
846
|
<div class='requirements'>
|
|
803
847
|
<div class='content'>
|
|
804
848
|
<div class='title'><i class="fa-solid fa-circle-exclamation"></i> Installation required</div>
|