pinokiod 3.9.35 → 3.9.37

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.
Files changed (38) hide show
  1. package/kernel/api/filepicker/index.js +3 -1
  2. package/kernel/api/fs/index.js +4 -2
  3. package/kernel/api/index.js +4 -0
  4. package/kernel/api/web/index.js +6 -1
  5. package/kernel/environment.js +36 -34
  6. package/kernel/index.js +27 -0
  7. package/kernel/prototype.js +9 -0
  8. package/kernel/router/index.js +1 -1
  9. package/kernel/util.js +4 -2
  10. package/package.json +2 -2
  11. package/server/index.js +82 -38
  12. package/server/public/common.js +32 -1
  13. package/server/public/modalinput.js +2 -1
  14. package/server/public/nav.js +12 -1
  15. package/server/public/opener.js +47 -16
  16. package/server/public/pinokio-black-3.png +0 -0
  17. package/server/public/pinokio-black.png +0 -0
  18. package/server/public/style.css +23 -8
  19. package/server/socket.js +7 -1
  20. package/server/views/app.ejs +24 -12
  21. package/server/views/connect/x.ejs +1 -1
  22. package/server/views/connect.ejs +1 -6
  23. package/server/views/download.ejs +1 -6
  24. package/server/views/explore.ejs +1 -6
  25. package/server/views/file_explorer.ejs +1 -1
  26. package/server/views/general_editor.ejs +1 -1
  27. package/server/views/github.ejs +1 -6
  28. package/server/views/help.ejs +1 -1
  29. package/server/views/index.ejs +1 -6
  30. package/server/views/network.ejs +1 -6
  31. package/server/views/partials/menu.ejs +18 -0
  32. package/server/views/prototype/index.ejs +5 -0
  33. package/server/views/prototype/old_index.ejs +1 -6
  34. package/server/views/settings.ejs +1 -6
  35. package/server/views/setup_home.ejs +0 -5
  36. package/server/views/shell.ejs +3 -0
  37. package/server/views/sidebar.ejs +1 -1
  38. package/server/views/terminal.ejs +8 -5
@@ -6,7 +6,7 @@ const { spawn } = require("child_process");
6
6
  params: {
7
7
  title, := <dialog title>
8
8
  type, := folder | file (default)
9
- cwd, := <cwd to open from>
9
+ path, := <cwd to open from>
10
10
  filetypes, := <file types to accept> (example: [["Images", "*.png *.jpg *.jpeg"]] )
11
11
  multiple, := True | False (allow multiple)
12
12
  save, := True | False ('save as' dialog, which lets the user select a file name)
@@ -30,6 +30,8 @@ class Filepicker {
30
30
  async open(req, ondata, kernel) {
31
31
  if (req.params.cwd) {
32
32
  req.params.cwd = path.resolve(req.cwd, req.params.cwd)
33
+ } else if (req.params.path) {
34
+ req.params.cwd = path.resolve(req.cwd, req.params.path)
33
35
  } else {
34
36
  req.params.cwd = req.cwd
35
37
  }
@@ -75,13 +75,15 @@ class FS {
75
75
  /*
76
76
  params := {
77
77
  path: <filepath>,
78
- command: "view(default)|open|<any command in PATH>"
78
+ action: "view(default)|open|<any command in PATH>"
79
79
  }
80
80
  open finder/file explorer at path
81
81
  */
82
82
  let dirPath = path.resolve(req.cwd, req.params.path)
83
83
  ondata({ raw: `\r\nopening path: ${dirPath}\r\n` })
84
- if (req.params.command) {
84
+ if (req.params.action) {
85
+ Util.openfs(dirPath, req.params, kernel)
86
+ } else if (req.params.command) {
85
87
  Util.openfs(dirPath, req.params, kernel)
86
88
  } else if (req.params.mode) {
87
89
  Util.openfs(dirPath, req.params, kernel)
@@ -77,6 +77,9 @@ class Api {
77
77
  meta.web_path = `/api/${api_name}`
78
78
  meta.ui = `/pinokio/browser/${api_name}`
79
79
  meta.browse = `/pinokio/browser/${api_name}/browse`
80
+ if (!pinokio && !pinokio2 && !pinokio3 ) {
81
+ meta.init_required = true
82
+ }
80
83
  return meta
81
84
  }
82
85
  get_proxy_url(root, port) {
@@ -707,6 +710,7 @@ class Api {
707
710
  uri: request.uri,
708
711
  path: request.path,
709
712
  git: this.parentGitURI(request.path),
713
+ origin: request.origin,
710
714
  body: script
711
715
  }
712
716
  // 7. resolve the rpc
@@ -22,7 +22,12 @@ class Web {
22
22
  console.log("kernel.exposed", kernel.exposed)
23
23
  }
24
24
  async open(req, ondata, kernel) {
25
- ondata(req.params, "browser.open")
25
+ console.log("WEB.open", req)
26
+ //ondata(req.params, "browser.open")
27
+ let type = req.params.type || "web"
28
+ req.params.uri = kernel.url(req.parent.origin, req.params.uri, type)
29
+ console.log("params", req.params)
30
+ ondata(req.params, "web.open")
26
31
  }
27
32
  async close(req, ondata, kernel) {
28
33
  ondata(req.params, "browser.close")
@@ -443,46 +443,48 @@ const get_raw = async (homedir) => {
443
443
  const requirements = async (script, filepath, kernel) => {
444
444
  let pre_items = []
445
445
  let requires_instantiation = false
446
- if (script && script.pre) {
447
- let env = await get2(filepath, kernel)
448
- for(let item of script.pre) {
449
- if (item.env) {
450
- // if index is not set, use 0 as default (for key)
451
- if (!item.index) {
452
- item.index = 0
453
- }
454
- if (item.key) {
455
- const hasProtocol = /^[a-zA-Z][a-zA-Z\d+\-.]*:\/\//.test(item.key);
456
- const url = new URL(hasProtocol ? item.key : `https://${item.key}`);
457
- item.host = url.host
458
- item.val = await kernel.kv.get(item.host, item.index)
459
- } else {
460
- item.host = ""
446
+ if (script) {
447
+ let pre
448
+ if (script.pre) {
449
+ pre = script.pre
450
+ } else if (script.env) {
451
+ pre = script.env
452
+ }
453
+ if (pre) {
454
+ let env = await get2(filepath, kernel)
455
+ for(let item of pre) {
456
+ let env_key
457
+ if (item.env) {
458
+ env_key = item.env
459
+ } else if (item.key) {
460
+ env_key = item.key
461
+ item.env = item.key
461
462
  }
463
+ if (env_key) {
464
+ // if index is not set, use 0 as default (for key)
465
+ if (!item.index) {
466
+ item.index = 0
467
+ }
468
+ if (item.host) {
469
+ const hasProtocol = /^[a-zA-Z][a-zA-Z\d+\-.]*:\/\//.test(item.host);
470
+ const url = new URL(hasProtocol ? item.host : `https://${item.host}`);
471
+ item.host = url.host
472
+ item.val = await kernel.kv.get(item.host, item.index)
473
+ } else {
474
+ item.host = ""
475
+ }
476
+ console.log({ env, env_key })
462
477
 
463
- if (env[item.env]) {
464
- item.val = env[item.env]
465
- } else {
466
- if (item.default) {
467
- if (typeof item.default === 'object') {
468
- if (item.default.key) {
469
- const hasProtocol = /^[a-zA-Z][a-zA-Z\d+\-.]*:\/\//.test(item.default.key);
470
- const url = new URL(hasProtocol ? item.default.key : `https://${item.default.key}`);
471
- item.host = url.host
472
-
473
- let index = item.default.index || 0
474
- item.index = index
475
- item.val = await kernel.kv.get(item.host, index)
476
- } else {
477
- item.host = ""
478
- }
479
- } else {
478
+ if (env[env_key]) {
479
+ item.val = env[env_key]
480
+ } else {
481
+ if (item.default) {
480
482
  item.val = item.default
481
483
  }
484
+ requires_instantiation = true
482
485
  }
483
- requires_instantiation = true
486
+ pre_items.push(item)
484
487
  }
485
- pre_items.push(item)
486
488
  }
487
489
  }
488
490
  }
package/kernel/index.js CHANGED
@@ -176,6 +176,33 @@ class Kernel {
176
176
  let id = this.api.filePath(uri, cwd)
177
177
  return this.api.running[id]
178
178
  }
179
+ url (origin, _path, _type) {
180
+ console.log("kernel.url", { origin, _path, _type })
181
+ /*
182
+ // get web url / asset / run URL
183
+ type := "web" (default) | "asset" | "run"
184
+ */
185
+ let relative = path.relative(this.homedir, _path)
186
+ let chunks = relative.split(path.sep)
187
+ let type = _type || "web"
188
+ let result
189
+ if (type === "web") {
190
+ if (chunks[0] === "api") {
191
+ result = "/pinokio/browser/" + chunks.slice(1).join("/")
192
+ }
193
+ } else if (type === "browse" || type === "dev") {
194
+ if (chunks[0] === "api") {
195
+ result = "/pinokio/browser/" + chunks.slice(1).join("/") + "/browse"
196
+ }
197
+ // } else if (type === "web") {
198
+ // result = "/" + chunks.join("/")
199
+ } else if (type === "asset") {
200
+ result = "/asset/" + chunks.join("/")
201
+ } else if (type === "run") {
202
+ result = "/run/" + chunks.join("/")
203
+ }
204
+ return origin + result
205
+ }
179
206
  start_port () {
180
207
  if (this.router.port_mapping && Object.keys(this.router.port_mapping).length > 0) {
181
208
  let max_caddy_port = Math.max(...Object.values(this.router.port_mapping))
@@ -29,6 +29,15 @@ class Proto {
29
29
  let config = await this.kernel.require(pinokiojs_path)
30
30
  this.config = config
31
31
 
32
+ this.config.menu.push({
33
+ icon: "fa-solid fa-rotate",
34
+ text: "Update",
35
+ shell: {
36
+ message: "git pull",
37
+ path: this.kernel.path("prototype/system")
38
+ }
39
+ })
40
+
32
41
 
33
42
 
34
43
  //// let prototype_paths = (await glob('**/pinokio.js', { cwd }))
@@ -209,7 +209,7 @@ class Router {
209
209
  if (JSON.stringify(this.config) === JSON.stringify(this.old_config)) {
210
210
  // console.log("config hasn't updated")
211
211
  } else {
212
- console.log("caddy config has updated", this.config)
212
+ // console.log("caddy config has updated", this.config)
213
213
  try {
214
214
  let response = await axios.post('http://127.0.0.1:2019/load', this.config, {
215
215
  headers: { 'Content-Type': 'application/json' }
package/kernel/util.js CHANGED
@@ -126,10 +126,12 @@ const openfs = (dirPath, options, kernel) => {
126
126
  let command = '';
127
127
  const platform = os.platform()
128
128
  console.log("openfs", dirPath, options)
129
- if (options && options.command) {
129
+ if (options && (options.command || options.action)) {
130
130
  let mode = "view"
131
- if (options && options.command) {
131
+ if (options.command) {
132
132
  mode = options.command
133
+ } else if (options.action) {
134
+ mode = options.action
133
135
  }
134
136
  console.log("> mode", mode)
135
137
  if (mode === "view") {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pinokiod",
3
- "version": "3.9.35",
3
+ "version": "3.9.37",
4
4
  "description": "",
5
5
  "main": "index.js",
6
6
  "scripts": {
@@ -38,7 +38,7 @@
38
38
  "http-terminator": "^3.2.0",
39
39
  "https": "^1.0.0",
40
40
  "isomorphic-git": "^1.23.0",
41
- "jimini": "^0.0.7",
41
+ "jimini": "^0.0.8",
42
42
  "jsdom": "^24.0.0",
43
43
  "key-store": "^1.2.0",
44
44
  "kill-sync": "^1.0.3",
package/server/index.js CHANGED
@@ -371,20 +371,8 @@ class Server {
371
371
  // }
372
372
 
373
373
 
374
-
375
- if (config && config.menu) {
376
- if (typeof config.menu === "function") {
377
- if (config.menu.constructor.name === "AsyncFunction") {
378
- config.menu = await config.menu(this.kernel, this.kernel.info)
379
- } else {
380
- config.menu = config.menu(this.kernel, this.kernel.info)
381
- }
382
- }
383
-
384
- let uri = this.kernel.path("api")
385
- await this.renderMenu(uri, name, config, [])
386
-
387
- } else {
374
+ if (config.init_required) {
375
+ // none of the pinokio.js, pinokio.json, pinokio_meta.json exists => need to initialize
388
376
  // if there is no menu, display all files
389
377
  let p = this.kernel.path("api", name)
390
378
  let files = await fs.promises.readdir(p, { withFileTypes: true })
@@ -406,7 +394,21 @@ class Server {
406
394
  }
407
395
  let uri = this.kernel.path("api")
408
396
  await this.renderMenu(uri, name, config, [])
397
+ } else {
398
+ let menu = config.menu || []
399
+ if (typeof config.menu === "function") {
400
+ if (config.menu.constructor.name === "AsyncFunction") {
401
+ config.menu = await config.menu(this.kernel, this.kernel.info)
402
+ } else {
403
+ config.menu = config.menu(this.kernel, this.kernel.info)
404
+ }
405
+ }
406
+
407
+ let uri = this.kernel.path("api")
408
+ await this.renderMenu(uri, name, config, [])
409
+
409
410
  }
411
+
410
412
  let platform = os.platform()
411
413
 
412
414
  // if (config.icon) {
@@ -564,7 +566,8 @@ class Server {
564
566
  let p = "/api" // run mode
565
567
  let _p = "/_api" // edit mode
566
568
  let paths = [{
567
- name: '<i class="fa-solid fa-house"></i>',
569
+ name: "<img src='/pinokio-black.png'>",
570
+ //name: '<i class="fa-solid fa-house"></i>',
568
571
  path: "/",
569
572
  }, {
570
573
  id: "back",
@@ -954,6 +957,7 @@ class Server {
954
957
  items: env_requirements.items
955
958
  })
956
959
  } else {
960
+ console.log("req.query.callback", req.query.callback)
957
961
 
958
962
  // check if it's a prototype script
959
963
  let kill_message
@@ -963,6 +967,8 @@ class Server {
963
967
  // kill_message = "Done! Click to go to the project"
964
968
  }
965
969
 
970
+ console.log(">>>>>>>>>> Callback", callback)
971
+
966
972
  let logpath = encodeURIComponent(Util.log_path(filepath, this.kernel))
967
973
  const result = {
968
974
  portal: this.portal,
@@ -1568,6 +1574,7 @@ class Server {
1568
1574
  config.html = `${config.text}`
1569
1575
  }
1570
1576
  config.btn = config.html
1577
+ config.arrow = true
1571
1578
  }
1572
1579
  /*
1573
1580
  if (config.href && !config.href.startsWith("/")) {
@@ -1579,6 +1586,7 @@ class Server {
1579
1586
  if (keypath) {
1580
1587
  config.href = base.href + "/" + keypath.join("/") + "?path=" + base.cwd
1581
1588
  }
1589
+ console.log({ config })
1582
1590
  return config
1583
1591
  }
1584
1592
 
@@ -2116,7 +2124,8 @@ class Server {
2116
2124
  }
2117
2125
  }
2118
2126
  //this.logo = (this.theme === 'dark' ? "<img class='icon' src='/pinokio-white.png'>" : "<img class='icon' src='/pinokio-black.png'>")
2119
- this.logo = '<i class="fa-solid fa-house"></i>'
2127
+ //this.logo = '<i class="fa-solid fa-house"></i>'
2128
+ this.logo = "<img src='/pinokio-black.png' class='icon'>"
2120
2129
 
2121
2130
  // 4. existing home is set + new home is set + existing home does NOT exist => delete the "home" field and DO NOT go through with the move command
2122
2131
  // 5. existing home is NOT set + new home is set => go through with the "home" setting procedure
@@ -3501,6 +3510,7 @@ class Server {
3501
3510
  }
3502
3511
  }))
3503
3512
  this.app.get("/prototype/run/*", ex(async (req, res) => {
3513
+ console.log("/prototype/run", req.params[0])
3504
3514
  let pathComponents = req.params[0].split("/").concat("pinokio.js")
3505
3515
  let config = await this.kernel.api.meta({ path: req.query.path })
3506
3516
  let pinokiojson_path = path.resolve(req.query.path, "pinokio.json")
@@ -3526,6 +3536,8 @@ class Server {
3526
3536
  }
3527
3537
  req.base = this.kernel.path("prototype")
3528
3538
  req.query.callback = config.ui
3539
+ console.log("config.ui", config.ui)
3540
+ console.log("req.query", req.query)
3529
3541
  //req.query.callback = config.browse
3530
3542
  req.query.cwd = req.query.path
3531
3543
  await this.render(req, res, pathComponents, null)
@@ -3544,27 +3556,56 @@ class Server {
3544
3556
  for(let key of paths) {
3545
3557
  config = config.menu[key]
3546
3558
  }
3547
- let run_path = "/run/prototype/system/" + config.href + "?cwd=" + req.query.path
3548
- console.log({ config, run_path, query: req.query })
3549
- let readme_path = this.kernel.path("prototype/system", config.readme)
3550
- console.log("config.readme.split", config.readme.split("/").slice(0, -1))
3551
- let md = await fs.promises.readFile(readme_path, "utf8")
3552
- console.log({ readme_path, md })
3553
- let baseUrl = "/asset/prototype/system/" + (config.readme.split("/").slice(0, -1).join("/")) + "/"
3554
- console.log("baseUrl", baseUrl)
3555
- let readme = marked.parse(md, {
3556
- baseUrl
3557
- })
3559
+ console.log("config.shell", config.shell)
3560
+ if (config.shell) {
3561
+
3562
+ let rendered = this.kernel.template.render(config.shell, {})
3563
+ let params = new URLSearchParams()
3564
+ if (rendered.path) params.set("path", encodeURIComponent(rendered.path))
3565
+ if (rendered.message) params.set("message", encodeURIComponent(rendered.message))
3566
+ if (rendered.venv) params.set("venv", encodeURIComponent(rendered.venv))
3567
+ if (rendered.input) params.set("input", true)
3568
+ if (rendered.callback) params.set("callback", encodeURIComponent(rendered.callback))
3569
+ if (rendered.kill) params.set("kill", encodeURIComponent(rendered.kill))
3570
+ if (rendered.done) params.set("done", encodeURIComponent(rendered.done))
3571
+ if (rendered.env) {
3572
+ for(let key in rendered.env) {
3573
+ let env_key = "env." + key
3574
+ params.set(env_key, rendered.env[key])
3575
+ }
3576
+ }
3577
+ if (rendered.conda) {
3578
+ for(let key in rendered.conda) {
3579
+ let conda_key = "conda." + key
3580
+ params.set(conda_key, rendered.conda[key])
3581
+ }
3582
+ }
3583
+ let shell_id = Math.floor("SH_" + 1000000000000 * Math.random())
3584
+ let href = "/shell/" + shell_id + "?" + params.toString()
3585
+ res.redirect(href)
3586
+ } else {
3587
+ let run_path = "/run/prototype/system/" + config.href + "?cwd=" + req.query.path
3588
+ console.log({ config, run_path, query: req.query })
3589
+ let readme_path = this.kernel.path("prototype/system", config.readme)
3590
+ console.log("config.readme.split", config.readme.split("/").slice(0, -1))
3591
+ let md = await fs.promises.readFile(readme_path, "utf8")
3592
+ console.log({ readme_path, md })
3593
+ let baseUrl = "/asset/prototype/system/" + (config.readme.split("/").slice(0, -1).join("/")) + "/"
3594
+ console.log("baseUrl", baseUrl)
3595
+ let readme = marked.parse(md, {
3596
+ baseUrl
3597
+ })
3598
+ res.render("prototype/show", {
3599
+ run_path,
3600
+ portal: this.portal,
3601
+ readme,
3602
+ logo: this.logo,
3603
+ theme: this.theme,
3604
+ agent: this.agent,
3605
+ kernel: this.kernel,
3606
+ })
3607
+ }
3558
3608
 
3559
- res.render("prototype/show", {
3560
- run_path,
3561
- portal: this.portal,
3562
- readme,
3563
- logo: this.logo,
3564
- theme: this.theme,
3565
- agent: this.agent,
3566
- kernel: this.kernel,
3567
- })
3568
3609
  }))
3569
3610
  this.app.get("/prototype", ex(async (req, res) => {
3570
3611
  // load meta
@@ -3589,6 +3630,7 @@ class Server {
3589
3630
  href: "/prototype/show",
3590
3631
  path: "/asset/prototype/system"
3591
3632
  })
3633
+ console.log("FINAL CONFIG", JSON.stringify(config, null, 2))
3592
3634
 
3593
3635
  // {
3594
3636
  // "icon": "fa-solid fa-power-off",
@@ -3693,6 +3735,7 @@ class Server {
3693
3735
  }
3694
3736
  }))
3695
3737
  this.app.post("/env", ex(async (req, res) => {
3738
+ console.log("REQ.body", req.body)
3696
3739
  let fullpath = path.resolve(this.kernel.homedir, req.body.filepath, "ENVIRONMENT")
3697
3740
  let updated = req.body.vals
3698
3741
  let hosts = req.body.hosts
@@ -3732,8 +3775,9 @@ class Server {
3732
3775
  this.app.get("/env/*", ex(async (req, res) => {
3733
3776
 
3734
3777
  let env_path = req.params[0]
3735
- let p = path.resolve(this.kernel.homedir, env_path, "pinokio.js")
3736
- let config = (await this.kernel.loader.load(p)).resolved
3778
+ // let p = path.resolve(this.kernel.homedir, env_path, "pinokio.js")
3779
+ // let config = (await this.kernel.loader.load(p)).resolved
3780
+ let config = await this.kernel.api.meta(env_path)
3737
3781
  if (config.run) {
3738
3782
  await this.init_env(env_path, { no_inherit: true })
3739
3783
  } else {
@@ -1,5 +1,36 @@
1
+ const open_url2 = (href, target, features) => {
2
+ if (target) {
3
+ if (target === "_blank") {
4
+ // if target=_blank => open in new window
5
+ // - if features=pinokio => open in pinokio
6
+ // - otherwise => open in a regular browser
7
+ if (features && features.includes("pinokio")) {
8
+ window.open(el.href, "_blank", features)
9
+ } else {
10
+ fetch("/go", {
11
+ method: "POST",
12
+ headers: {
13
+ "Content-Type": "application/json"
14
+ },
15
+ body: JSON.stringify({ url: el.href })
16
+ }).then((res) => {
17
+ return res.json()
18
+ }).then((res) => {
19
+ console.log(res)
20
+ })
21
+ }
22
+ } else {
23
+ // no target => just move from the same window
24
+ window.open(href, target, features)
25
+ }
26
+ } else {
27
+ // no target => just use window.open => move in the current window
28
+ window.open(href, "_self", features)
29
+ }
30
+ }
1
31
  hotkeys("ctrl+t,cmd+t,ctrl+n,cmd+n", (e) => {
2
- window.open("/", "_blank", "self")
32
+ open_url2(location.href, "_blank")
33
+ // window.open("/", "_blank", "self")
3
34
  })
4
35
  const refreshParent = (e) => {
5
36
  if (window.parent === window.top) {
@@ -46,7 +46,7 @@ const ModalInput = async (params, uri) => {
46
46
  </div>
47
47
  </div>`
48
48
  } else if (type === 'file') {
49
- input = `<div class='dropzone' data-type='file' data-id='${field.key}'></div>`
49
+ input = `<div data-accept='${field.accept}' class='dropzone' data-type='file' data-id='${field.key}'></div>`
50
50
  //input = `<input type='file' data-id="${field.key}" />`
51
51
  } else {
52
52
  input = `<input ${autofocus} type='${type}' data-id="${field.key}" class="swal2-input" placeholder="${field.placeholder ? field.placeholder : ''}">`
@@ -73,6 +73,7 @@ const ModalInput = async (params, uri) => {
73
73
  Swal.getPopup().querySelectorAll('[data-type=file]').forEach((el, index) => {
74
74
  const dz = new Dropzone(el, {
75
75
  url: '/no-op', // dummy, not used
76
+ acceptedFiles: el.getAttribute("data-accept") || null,
76
77
  autoProcessQueue: false,
77
78
  uploadMultiple: false,
78
79
  maxFiles: 1,
@@ -14,7 +14,18 @@ document.addEventListener("DOMContentLoaded", () => {
14
14
  //}
15
15
  if (document.querySelector("#new-window")) {
16
16
  document.querySelector("#new-window").addEventListener("click", (e) => {
17
- window.open("/", "_blank", "self")
17
+ //window.open("/", "_blank", "self")
18
+ fetch("/go", {
19
+ method: "POST",
20
+ headers: {
21
+ "Content-Type": "application/json"
22
+ },
23
+ body: JSON.stringify({ url: location.href })
24
+ }).then((res) => {
25
+ return res.json()
26
+ }).then((res) => {
27
+ console.log(res)
28
+ })
18
29
  })
19
30
  }
20
31
  })
@@ -1,3 +1,34 @@
1
+ const open_url = (href, target, features) => {
2
+ debugger
3
+ if (target) {
4
+ if (target === "_blank") {
5
+ // if target=_blank => open in new window
6
+ // - if features=pinokio => open in pinokio
7
+ // - otherwise => open in a regular browser
8
+ if (features && features.includes("pinokio")) {
9
+ window.open(el.href, "_blank", features)
10
+ } else {
11
+ fetch("/go", {
12
+ method: "POST",
13
+ headers: {
14
+ "Content-Type": "application/json"
15
+ },
16
+ body: JSON.stringify({ url: el.href })
17
+ }).then((res) => {
18
+ return res.json()
19
+ }).then((res) => {
20
+ console.log(res)
21
+ })
22
+ }
23
+ } else {
24
+ // no target => just move from the same window
25
+ window.open(href, target, features)
26
+ }
27
+ } else {
28
+ // no target => just use window.open => move in the current window
29
+ window.open(href, "_self", features)
30
+ }
31
+ }
1
32
  document.addEventListener("click", async (e) => {
2
33
  // [data-filepath] should open in file explorer
3
34
  let el = e.target.closest("[data-filepath]")
@@ -69,22 +100,22 @@ document.addEventListener("click", async (e) => {
69
100
  e.preventDefault()
70
101
  e.stopPropagation()
71
102
  let features = el.getAttribute("features")
72
- if (features.includes("browser")) {
73
- debugger
74
- fetch("/go", {
75
- method: "POST",
76
- headers: {
77
- "Content-Type": "application/json"
78
- },
79
- body: JSON.stringify({ url: el.href })
80
- }).then((res) => {
81
- return res.json()
82
- }).then((res) => {
83
- console.log(res)
84
- })
85
- } else {
86
- window.open(el.href, "_blank", features)
87
- }
103
+ open_url(el.href, "_blank", features)
104
+ // if (features && features.includes("app")) {
105
+ // window.open(el.href, "_blank", features)
106
+ // } else {
107
+ // fetch("/go", {
108
+ // method: "POST",
109
+ // headers: {
110
+ // "Content-Type": "application/json"
111
+ // },
112
+ // body: JSON.stringify({ url: el.href })
113
+ // }).then((res) => {
114
+ // return res.json()
115
+ // }).then((res) => {
116
+ // console.log(res)
117
+ // })
118
+ // }
88
119
  return
89
120
  }
90
121
 
Binary file
@@ -114,11 +114,16 @@ body.dark *::-webkit-scrollbar-thumb {
114
114
  max-height: 0;
115
115
  }
116
116
  .dynamic.selected {
117
+ /*
117
118
  background: rgba(0,0,0,0.05);
119
+ */
120
+ border-left: 10px solid rgb(130, 188, 9);
118
121
  }
122
+ /*
119
123
  body.dark .dynamic.selected {
120
124
  background: rgba(0,150,250,0.05);
121
125
  }
126
+ */
122
127
  .dynamic-item img {
123
128
  width: 20px !important;
124
129
  height: 20px !important;
@@ -382,8 +387,7 @@ footer b {
382
387
  color: royalblue;
383
388
  }
384
389
  .requirements .requirement-item .name {
385
- font-weight: bold;
386
- color: silver;
390
+ color: rgba(0,0,0,0.7);
387
391
  }
388
392
  .requirements .requirement-item {
389
393
  display: flex;
@@ -406,6 +410,12 @@ body.dark .requirement-item:first-child {
406
410
  border-top: 1px solid rgba(0,0,0,0.08);
407
411
  }
408
412
  */
413
+ body.dark .requirements .requirement-item .name {
414
+ color: rgba(255,255,255,0.8);
415
+ }
416
+ body.dark .requirements .requirement-item .name.highlighted {
417
+ color: royalblue;
418
+ }
409
419
  body.dark .requirement-item {
410
420
  /*
411
421
  border-bottom: 1px solid rgba(255,255,255,0.04);
@@ -1159,7 +1169,7 @@ body.dark .line:hover {
1159
1169
  /*
1160
1170
  padding: 15px 15px;
1161
1171
  */
1162
- padding: 7px;
1172
+ padding: 7px 5px;
1163
1173
  border-bottom: 1px solid var(--light-thin);
1164
1174
  }
1165
1175
  .thick.line {
@@ -1857,22 +1867,27 @@ body.dark .not-running-apps, body.dark .running-apps {
1857
1867
  color: #82bc09;
1858
1868
  }
1859
1869
  */
1860
- .running-apps .line img {
1870
+ .running-apps .line {
1861
1871
  border-left: 10px solid #82bc09;
1862
- padding-left: 10px;
1872
+ }
1873
+ .running-apps .line img {
1874
+ padding-left: 3px;
1863
1875
  /*
1876
+ padding-left: 10px;
1864
1877
  border: 3px solid #8fd400;
1865
1878
  */
1866
1879
  /*
1867
1880
  border-radius: 5px;
1868
1881
  */
1869
1882
  }
1870
- body.dark .not-running-apps .line img {
1883
+ body.dark .not-running-apps .line {
1871
1884
  border-left: 10px solid rgba(255,255,255,0.1);
1872
1885
  }
1873
- .not-running-apps .line img {
1886
+ .not-running-apps .line {
1874
1887
  border-left: 10px solid rgba(0,0,0,0.04);
1875
- padding-left: 10px;
1888
+ }
1889
+ .not-running-apps .line img {
1890
+ padding-left: 3px;
1876
1891
  }
1877
1892
  /*
1878
1893
  .running-apps .line.align-top h3 .col .title {
package/server/socket.js CHANGED
@@ -12,13 +12,18 @@ class Socket {
12
12
  this.subscriptions = new Map(); // Initialize a Map to store the WebSocket connections interested in each event
13
13
  this.parent.kernel.api.listen("server.socket", this.trigger.bind(this))
14
14
  wss.on('connection', (ws, request) => {
15
+ ws._headers = request.headers;
16
+ ws._ip = request.socket.remoteAddress;
17
+ ws._boundUrl = (request.headers['x-forwarded-proto'] || 'ws') + '://' +
18
+ (request.headers['x-forwarded-host'] || request.headers.host) +
19
+ request.url;
20
+ ws._origin = request.headers.origin;
15
21
  ws.on('close', () => {
16
22
  this.subscriptions.forEach((set, eventName) => {
17
23
  set.delete(ws);
18
24
  });
19
25
  });
20
26
  ws.on('message', async (message, isBinary) => {
21
-
22
27
  let req
23
28
  if (isBinary) {
24
29
  const buffer = Buffer.from(message);
@@ -46,6 +51,7 @@ class Socket {
46
51
  } else {
47
52
  req = JSON.parse(message)
48
53
  }
54
+ req.origin = ws._origin
49
55
  if (req.response) {
50
56
  this.parent.kernel.api.respond(req)
51
57
  } else {
@@ -738,7 +738,7 @@ body.dark .appcanvas {
738
738
  <body class='<%=theme%>' data-platform="<%=platform%>">
739
739
  <header class='navheader grabbable'>
740
740
  <h1>
741
- <a class='home' href="/"><i class="fa-solid fa-house"></i></a>
741
+ <a class='home' href="/"><img class='icon' src="/pinokio-black.png"></a>
742
742
  <button class='btn2' id='back'><div><i class="fa-solid fa-chevron-left"></i></div><div>Prev</div></button>
743
743
  <button class='btn2' id='forward'><div><i class="fa-solid fa-chevron-right"></i></div><div>Next</div></button>
744
744
  <a class='btn2 create-new' id='create-new-folder'><div><i class='fa-solid fa-plus'></i></div><div>New</div></a>
@@ -752,11 +752,6 @@ body.dark .appcanvas {
752
752
  <button class='btn2' id='genlog'><div><i class="fa-solid fa-laptop-code"></i></div><div>Logs</div></button>
753
753
  <a id='downloadlogs' download class='hidden btn2' href="/pinokio/logs.zip"><div><i class="fa-solid fa-download"></i></div><div>Download logs</div></a>
754
754
  <a class='btn2' href="/?mode=settings"><div><i class="fa-solid fa-gear"></i></div><div>Settings</div></a>
755
- <% if (agent === "electron") { %>
756
- <a href="/" target="_blank" class='btn2' features="browser"><div><i class="fa-solid fa-square-up-right"></i></div><div>Open</div></a>
757
- <% } else { %>
758
- <a href="/" target="_blank" class='btn2'><div><i class="fa-solid fa-square-up-right"></i></div><div>Open</div></a>
759
- <% } %>
760
755
  <button id='new-window' title='open a new window' class='btn2'><div><i class="fa-solid fa-plus"></i></div><div>Window</div></button>
761
756
  </div>
762
757
  </h1>
@@ -1702,13 +1697,20 @@ body.dark .appcanvas {
1702
1697
  e.stopPropagation()
1703
1698
  <% if (type === 'run') { %>
1704
1699
  // run mode => switch to dev mode
1700
+ location.hash = ""
1705
1701
  location.pathname = location.pathname + "/browse"
1706
1702
  <% } else { %>
1707
1703
  // dev mode => already dev. reveal the hidden menu
1708
- target.closest(".dynamic").classList.toggle("selected")
1709
- target.closest(".nested-menu").querySelector(".submenu").classList.toggle("hidden")
1710
- target.querySelector(".loader .fa-angle-down").classList.toggle("hidden")
1711
- target.querySelector(".loader .fa-angle-up").classList.toggle("hidden")
1704
+ if (target.closest(".dynamic")) {
1705
+ target.closest(".dynamic").classList.toggle("selected")
1706
+ target.closest(".nested-menu").querySelector(".submenu").classList.toggle("hidden")
1707
+ target.querySelector(".loader .fa-angle-down").classList.toggle("hidden")
1708
+ target.querySelector(".loader .fa-angle-up").classList.toggle("hidden")
1709
+ } else {
1710
+ target.closest(".nested-menu").querySelector(".submenu").classList.toggle("hidden")
1711
+ target.querySelector(".loader .fa-angle-down").classList.toggle("hidden")
1712
+ target.querySelector(".loader .fa-angle-up").classList.toggle("hidden")
1713
+ }
1712
1714
  <% } %>
1713
1715
  return
1714
1716
  } else {
@@ -1793,7 +1795,9 @@ body.dark .appcanvas {
1793
1795
  return res.text()
1794
1796
  })
1795
1797
  console.log({ dynamic })
1796
- document.querySelector(".dynamic").innerHTML = dynamic
1798
+ if (document.querySelector(".dynamic")) {
1799
+ document.querySelector(".dynamic").innerHTML = dynamic
1800
+ }
1797
1801
 
1798
1802
  location.hash = ""
1799
1803
 
@@ -1826,6 +1830,12 @@ body.dark .appcanvas {
1826
1830
  if (init) {
1827
1831
  init.click()
1828
1832
  }
1833
+ /*
1834
+ window.addEventListener("hashchange", function () {
1835
+ console.log("Hash changed:", location.hash);
1836
+ location.reload()
1837
+ });
1838
+ */
1829
1839
  window.addEventListener('message', (event) => {
1830
1840
 
1831
1841
  // only process the event it's coming from pinokio
@@ -1898,7 +1908,9 @@ body.dark .appcanvas {
1898
1908
  });
1899
1909
  refresh_du()
1900
1910
  <% if (type !== 'run') { %>
1901
- document.querySelector(".dynamic .reveal").click()
1911
+ if (document.querySelector(".dynamic .reveal")) {
1912
+ document.querySelector(".dynamic .reveal").click()
1913
+ }
1902
1914
  <% } %>
1903
1915
  /*
1904
1916
  document.addEventListener("keydown", (e) => {
@@ -188,7 +188,7 @@ pre {
188
188
  <body class='<%=theme%>'>
189
189
  <header class='navheader grabbable'>
190
190
  <h1>
191
- <a class='home' href="/"><i class="fa-solid fa-house"></i></a>
191
+ <a class='home' href="/"><img class='icon' src="/pinokio-black.png"></a>
192
192
  <button class='btn2' id='back'><div><i class="fa-solid fa-chevron-left"></i></div><div>Prev</div></button>
193
193
  <button class='btn2' id='forward'><div><i class="fa-solid fa-chevron-right"></i></div><div>Next</div></button>
194
194
  <a class='btn2 create-new' id='create-new-folder'><div><i class='fa-solid fa-plus'></i></div><div>New</div></a>
@@ -226,7 +226,7 @@ body.dark .config {
226
226
  <body class='<%=theme%>'>
227
227
  <header class='navheader grabbable'>
228
228
  <h1>
229
- <a class='home' href="/"><i class="fa-solid fa-house"></i></a>
229
+ <a class='home' href="/"><img class='icon' src="/pinokio-black.png"></a>
230
230
  <button class='btn2' id='back'><div><i class="fa-solid fa-chevron-left"></i></div><div>Prev</div></button>
231
231
  <button class='btn2' id='forward'><div><i class="fa-solid fa-chevron-right"></i></div><div>Next</div></button>
232
232
  <a class='btn2 create-new' id='create-new-folder'><div><i class='fa-solid fa-plus'></i></div><div>New</div></a>
@@ -239,11 +239,6 @@ body.dark .config {
239
239
  <button class='btn2' id='genlog'><div><i class="fa-solid fa-laptop-code"></i></div><div>Logs</div></button>
240
240
  <a id='downloadlogs' download class='hidden btn2' href="/pinokio/logs.zip"><div><i class="fa-solid fa-download"></i></div><div>Download logs</div></a>
241
241
  <a class='btn2' href="/?mode=settings"><div><i class="fa-solid fa-gear"></i></div><div>Settings</div></a>
242
- <% if (agent === "electron") { %>
243
- <a href="/" target="_blank" class='btn2' features="browser"><div><i class="fa-solid fa-square-up-right"></i></div><div>Open</div></a>
244
- <% } else { %>
245
- <a href="/" target="_blank" class='btn2'><div><i class="fa-solid fa-square-up-right"></i></div><div>Open</div></a>
246
- <% } %>
247
242
  <button id='new-window' title='open a new window' class='btn2'><div><i class="fa-solid fa-plus"></i></div><div>Window</div></button>
248
243
  </div>
249
244
  </h1>
@@ -113,7 +113,7 @@ body.frozen {
113
113
  <% } %>
114
114
  <header class='grabbable'>
115
115
  <h1>
116
- <a class='home' href="/"><i class="fa-solid fa-house"></i></a>
116
+ <a class='home' href="/"><img class='icon' src="/pinokio-black.png"></a>
117
117
  <button class='btn2' id='back'><div><i class="fa-solid fa-chevron-left"></i></div><div>Prev</div></button>
118
118
  <button class='btn2' id='forward'><div><i class="fa-solid fa-chevron-right"></i></div><div>Next</div></button>
119
119
  <a class='btn2 create-new' id='create-new-folder'><div><i class='fa-solid fa-plus'></i></div><div>New</div></a>
@@ -126,11 +126,6 @@ body.frozen {
126
126
  <button class='btn2' id='genlog'><div><i class="fa-solid fa-laptop-code"></i></div><div>Logs</div></button>
127
127
  <a id='downloadlogs' download class='hidden btn2' href="/pinokio/logs.zip"><div><i class="fa-solid fa-download"></i></div><div>Download logs</div></a>
128
128
  <a class='btn2' href="/?mode=settings"><div><i class="fa-solid fa-gear"></i></div><div>Settings</div></a>
129
- <% if (agent === "electron") { %>
130
- <a href="/" target="_blank" class='btn2' features="browser"><div><i class="fa-solid fa-square-up-right"></i></div><div>Open</div></a>
131
- <% } else { %>
132
- <a href="/" target="_blank" class='btn2'><div><i class="fa-solid fa-square-up-right"></i></div><div>Open</div></a>
133
- <% } %>
134
129
  <button id='new-window' title='open a new window' class='btn2'><div><i class="fa-solid fa-plus"></i></div><div>Window</div></button>
135
130
  </div>
136
131
  </h1>
@@ -120,7 +120,7 @@ body main iframe {
120
120
  <body class='<%=theme%>'>
121
121
  <header class='navheader grabbable'>
122
122
  <h1>
123
- <a class='home' href="/"><i class="fa-solid fa-house"></i></a>
123
+ <a class='home' href="/"><img class='icon' src="/pinokio-black.png"></a>
124
124
  <button class='btn2' id='back'><div><i class="fa-solid fa-chevron-left"></i></div><div>Prev</div></button>
125
125
  <button class='btn2' id='forward'><div><i class="fa-solid fa-chevron-right"></i></div><div>Next</div></button>
126
126
  <a class='btn2 create-new' id='create-new-folder'><div><i class='fa-solid fa-plus'></i></div><div>New</div></a>
@@ -133,11 +133,6 @@ body main iframe {
133
133
  <button class='btn2' id='genlog'><div><i class="fa-solid fa-laptop-code"></i></div><div>Logs</div></button>
134
134
  <a id='downloadlogs' download class='hidden btn2' href="/pinokio/logs.zip"><div><i class="fa-solid fa-download"></i></div><div>Download logs</div></a>
135
135
  <a class='btn2' href="/?mode=settings"><div><i class="fa-solid fa-gear"></i></div><div>Settings</div></a>
136
- <% if (agent === "electron") { %>
137
- <a href="/" target="_blank" class='btn2' features="browser"><div><i class="fa-solid fa-square-up-right"></i></div><div>Open</div></a>
138
- <% } else { %>
139
- <a href="/" target="_blank" class='btn2'><div><i class="fa-solid fa-square-up-right"></i></div><div>Open</div></a>
140
- <% } %>
141
136
  <button id='new-window' title='open a new window' class='btn2'><div><i class="fa-solid fa-plus"></i></div><div>Window</div></button>
142
137
  </div>
143
138
  <!--
@@ -162,7 +162,7 @@ body.dark .browser-options-row {
162
162
  <header class='navheader grabbable'>
163
163
  <h1>
164
164
  <% if (ishome) { %>
165
- <a class='home' href="/"><i class="fa-solid fa-house"></i></a>
165
+ <a class='home' href="/"><img class='icon' src="/pinokio-black.png"></a>
166
166
  <button class='btn2' id='back'><i class="fa-solid fa-chevron-left"></i></button>
167
167
  <button class='btn2' id='forward'><i class="fa-solid fa-chevron-right"></i></button>
168
168
  <% } %>
@@ -188,7 +188,7 @@ document.addEventListener("DOMContentLoaded", async () => {
188
188
  <body class='columns <%=theme%>'>
189
189
  <header class='navheader grabbable'>
190
190
  <h1>
191
- <a class='home' href="/"><i class="fa-solid fa-house"></i></a>
191
+ <a class='home' href="/"><img class='icon' src="/pinokio-black.png"></a>
192
192
  <%=filepath%>
193
193
  </h1>
194
194
  <div class='runner'>
@@ -175,7 +175,7 @@ hr {
175
175
  <body class='<%=theme%>'>
176
176
  <header class='navheader grabbable'>
177
177
  <h1>
178
- <a class='home' href="/"><i class="fa-solid fa-house"></i></a>
178
+ <a class='home' href="/"><img class='icon' src="/pinokio-black.png"></a>
179
179
  <button class='btn2' id='back'><div><i class="fa-solid fa-chevron-left"></i></div><div>Prev</div></button>
180
180
  <button class='btn2' id='forward'><div><i class="fa-solid fa-chevron-right"></i></div><div>Next</div></button>
181
181
  <a class='btn2 create-new' id='create-new-folder'><div><i class='fa-solid fa-plus'></i></div><div>New</div></a>
@@ -188,11 +188,6 @@ hr {
188
188
  <button class='btn2' id='genlog'><div><i class="fa-solid fa-laptop-code"></i></div><div>Logs</div></button>
189
189
  <a id='downloadlogs' download class='hidden btn2' href="/pinokio/logs.zip"><div><i class="fa-solid fa-download"></i></div><div>Download logs</div></a>
190
190
  <a class='btn2' href="/?mode=settings"><div><i class="fa-solid fa-gear"></i></div><div>Settings</div></a>
191
- <% if (agent === "electron") { %>
192
- <a href="/" target="_blank" class='btn2' features="browser"><div><i class="fa-solid fa-square-up-right"></i></div><div>Open</div></a>
193
- <% } else { %>
194
- <a href="/" target="_blank" class='btn2'><div><i class="fa-solid fa-square-up-right"></i></div><div>Open</div></a>
195
- <% } %>
196
191
  <button id='new-window' title='open a new window' class='btn2'><div><i class="fa-solid fa-plus"></i></div><div>Window</div></button>
197
192
  </div>
198
193
  </h1>
@@ -253,7 +253,7 @@ body.dark .item .tile .badge {
253
253
  <body class='<%=theme%>'>
254
254
  <header class='navheader grabbable'>
255
255
  <h1>
256
- <a class='home' href="/"><i class="fa-solid fa-house"></i></a>
256
+ <a class='home' href="/"><img class='icon' src="/pinokio-black.png"></a>
257
257
  <button class='btn2' id='back'><div><i class="fa-solid fa-chevron-left"></i></div><div>Prev</div></button>
258
258
  <button class='btn2' id='forward'><div><i class="fa-solid fa-chevron-right"></i></div><div>Next</div></button>
259
259
  <a class='btn2 create-new' id='create-new-folder'><div><i class='fa-solid fa-plus'></i></div><div>New</div></a>
@@ -242,7 +242,7 @@ body.dark .open-menu, body.dark .browse {
242
242
  <header class='navheader grabbable'>
243
243
  <h1>
244
244
  <% if (ishome) { %>
245
- <a class='home' href="/"><i class="fa-solid fa-house"></i></a>
245
+ <a class='home' href="/"><img class='icon' src="/pinokio-black.png"></a>
246
246
  <button class='btn2' id='back'><div><i class="fa-solid fa-chevron-left"></i></div><div>Prev</div></button>
247
247
  <button class='btn2' id='forward'><div><i class="fa-solid fa-chevron-right"></i></div><div>Next</div></button>
248
248
  <a class='btn2 create-new' id='create-new-folder'><div><i class='fa-solid fa-plus'></i></div><div>New</div></a>
@@ -275,11 +275,6 @@ body.dark .open-menu, body.dark .browse {
275
275
  <button class='btn2' id='genlog'><div><i class="fa-solid fa-laptop-code"></i></div><div>Logs</div></button>
276
276
  <a id='downloadlogs' download class='hidden btn2' href="/pinokio/logs.zip"><div><i class="fa-solid fa-download"></i></div><div>Download logs</div></a>
277
277
  <a class='btn2' href="/?mode=settings"><div><i class="fa-solid fa-gear"></i></div><div>Settings</div></a>
278
- <% if (agent === "electron") { %>
279
- <a href="/" target="_blank" class='btn2' features="browser"><div><i class="fa-solid fa-square-up-right"></i></div><div>Open</div></a>
280
- <% } else { %>
281
- <a href="/" target="_blank" class='btn2'><div><i class="fa-solid fa-square-up-right"></i></div><div>Open</div></a>
282
- <% } %>
283
278
  <button id='new-window' title='open a new window' class='btn2'><div><i class="fa-solid fa-plus"></i></div><div>Window</div></button>
284
279
  </div>
285
280
  <% } %>
@@ -401,7 +401,7 @@ input:checked + .slider:before {
401
401
  <body class='<%=theme%>'>
402
402
  <header class='navheader grabbable'>
403
403
  <h1>
404
- <a class='home' href="/"><i class="fa-solid fa-house"></i></a>
404
+ <a class='home' href="/"><img class='icon' src="/pinokio-black.png"></a>
405
405
  <button class='btn2' id='back'><div><i class="fa-solid fa-chevron-left"></i></div><div>Prev</div></button>
406
406
  <button class='btn2' id='forward'><div><i class="fa-solid fa-chevron-right"></i></div><div>Next</div></button>
407
407
  <a class='btn2 create-new' id='create-new-folder'><div><i class='fa-solid fa-plus'></i></div><div>New</div></a>
@@ -414,11 +414,6 @@ input:checked + .slider:before {
414
414
  <button class='btn2' id='genlog'><div><i class="fa-solid fa-laptop-code"></i></div><div>Logs</div></button>
415
415
  <a id='downloadlogs' download class='hidden btn2' href="/pinokio/logs.zip"><div><i class="fa-solid fa-download"></i></div><div>Download logs</div></a>
416
416
  <a class='btn2' href="/?mode=settings"><div><i class="fa-solid fa-gear"></i></div><div>Settings</div></a>
417
- <% if (agent === "electron") { %>
418
- <a href="/" target="_blank" class='btn2' features="browser"><div><i class="fa-solid fa-square-up-right"></i></div><div>Open</div></a>
419
- <% } else { %>
420
- <a href="/" target="_blank" class='btn2'><div><i class="fa-solid fa-square-up-right"></i></div><div>Open</div></a>
421
- <% } %>
422
417
  <button id='new-window' title='open a new window' class='btn2'><div><i class="fa-solid fa-plus"></i></div><div>Window</div></button>
423
418
  </div>
424
419
  </h1>
@@ -14,22 +14,37 @@
14
14
  <% if (item.action) { %>
15
15
  <div <%=item.default ? 'data-default' : ''%> data-action="<%=JSON.stringify(item.action)%>" class='btn header-item frame-link <%=item.display || ""%>'>
16
16
  <div class='tab'><%-item.btn%></div>
17
+ <% if (item.arrow) { %>
18
+ <i class="fa-solid fa-angle-right"></i>
19
+ <% } %>
17
20
  </div>
18
21
  <% } else if (item.run) { %>
19
22
  <div data-run="<%=item.run%>" data-cwd="<%=item.cwd%>" class='btn header-item frame-link <%=item.display || ""%>'>
20
23
  <div class='tab'><%-item.btn%></div>
24
+ <% if (item.arrow) { %>
25
+ <i class="fa-solid fa-angle-right"></i>
26
+ <% } %>
21
27
  </div>
22
28
  <% } else if (item.command) { %>
23
29
  <div data-command="<%=item.command%>" data-filepath="<%=item.href%>" class='btn header-item frame-link <%=item.display || ""%>'>
24
30
  <div class='tab'><%-item.btn%></div>
31
+ <% if (item.arrow) { %>
32
+ <i class="fa-solid fa-angle-right"></i>
33
+ <% } %>
25
34
  </div>
26
35
  <% } else if (item.fs) { %>
27
36
  <div data-filepath="<%=item.href%>" class='btn header-item frame-link <%=item.display || ""%>'>
28
37
  <div class='tab'><%-item.btn%></div>
38
+ <% if (item.arrow) { %>
39
+ <i class="fa-solid fa-angle-right"></i>
40
+ <% } %>
29
41
  </div>
30
42
  <% } else if (item.target === "_blank") { %>
31
43
  <a <%=item.default ? 'data-default' : ''%> data-confirm="<%=item.confirm%>" data-index="<%=index%>" target="<%=item.target%>" data-mode="<%=item.mode%>" href="<%=item.href%>" class='btn header-item frame-link <%=item.display || ""%>'>
32
44
  <div class='tab'><%-item.btn%></div>
45
+ <% if (item.arrow) { %>
46
+ <i class="fa-solid fa-angle-right"></i>
47
+ <% } %>
33
48
  <div class='loader'>
34
49
  <i class="fa-solid fa-up-right-from-square"></i>
35
50
  </div>
@@ -50,6 +65,9 @@
50
65
  </button>
51
66
  </div>
52
67
  <% } %>
68
+ <% if (item.arrow) { %>
69
+ <i class="fa-solid fa-angle-right"></i>
70
+ <% } %>
53
71
  </a>
54
72
  <% } %>
55
73
  <% } %>
@@ -143,6 +143,11 @@ body.dark .header-item .btn2 {
143
143
  .header-item > * {
144
144
  display: block;
145
145
  }
146
+ .header-item i {
147
+ font-size: 20px !important;
148
+ width: 20px !important;
149
+ padding: 10px;
150
+ }
146
151
  .header-item img {
147
152
  /*
148
153
  width: 60px;
@@ -544,7 +544,7 @@ body.dark .header-item.cursor.header-top {
544
544
  <body class='<%=theme%>'>
545
545
  <header class='navheader grabbable'>
546
546
  <h1>
547
- <a class='home' href="/"><i class="fa-solid fa-house"></i></a>
547
+ <a class='home' href="/"><img class='icon' src="/pinokio-black.png"></a>
548
548
  <button class='btn2' id='back'><div><i class="fa-solid fa-chevron-left"></i></div><div>Prev</div></button>
549
549
  <button class='btn2' id='forward'><div><i class="fa-solid fa-chevron-right"></i></div><div>Next</div></button>
550
550
  <a class='btn2 create-new' id='create-new-folder'><div><i class='fa-solid fa-plus'></i></div><div>New</div></a>
@@ -558,11 +558,6 @@ body.dark .header-item.cursor.header-top {
558
558
  <button class='btn2' id='genlog'><div><i class="fa-solid fa-laptop-code"></i></div><div>Logs</div></button>
559
559
  <a id='downloadlogs' download class='hidden btn2' href="/pinokio/logs.zip"><div><i class="fa-solid fa-download"></i></div><div>Download logs</div></a>
560
560
  <a class='btn2' href="/?mode=settings"><div><i class="fa-solid fa-gear"></i></div><div>Settings</div></a>
561
- <% if (agent === "electron") { %>
562
- <a href="/" target="_blank" class='btn2' features="browser"><div><i class="fa-solid fa-square-up-right"></i></div><div>Open</div></a>
563
- <% } else { %>
564
- <a href="/" target="_blank" class='btn2'><div><i class="fa-solid fa-square-up-right"></i></div><div>Open</div></a>
565
- <% } %>
566
561
  <button id='new-window' title='open a new window' class='btn2'><div><i class="fa-solid fa-plus"></i></div><div>Window</div></button>
567
562
  </div>
568
563
  </h1>
@@ -256,7 +256,7 @@ body.dark .keys pre {
256
256
  -->
257
257
  <header class='navheader grabbable'>
258
258
  <h1>
259
- <a class='home' href="/"><i class="fa-solid fa-house"></i></a>
259
+ <a class='home' href="/"><img class='icon' src="/pinokio-black.png"></a>
260
260
  <button class='btn2' id='back'><div><i class="fa-solid fa-chevron-left"></i></div><div>Prev</div></button>
261
261
  <button class='btn2' id='forward'><div><i class="fa-solid fa-chevron-right"></i></div><div>Next</div></button>
262
262
  <a class='btn2 create-new' id='create-new-folder'><div><i class='fa-solid fa-plus'></i></div><div>New</div></a>
@@ -276,11 +276,6 @@ body.dark .keys pre {
276
276
  <button class='btn2' id='genlog'><div><i class="fa-solid fa-laptop-code"></i></div><div>Logs</div></button>
277
277
  <a id='downloadlogs' download class='hidden btn2' href="/pinokio/logs.zip"><div><i class="fa-solid fa-download"></i></div><div>Download logs</div></a>
278
278
  <a class='btn2' href="/?mode=settings"><div><i class="fa-solid fa-gear"></i></div><div>Settings</div></a>
279
- <% if (agent === "electron") { %>
280
- <a href="/" target="_blank" class='btn2' features="browser"><div><i class="fa-solid fa-square-up-right"></i></div><div>Open</div></a>
281
- <% } else { %>
282
- <a href="/" target="_blank" class='btn2'><div><i class="fa-solid fa-square-up-right"></i></div><div>Open</div></a>
283
- <% } %>
284
279
  <button id='new-window' title='open a new window' class='btn2'><div><i class="fa-solid fa-plus"></i></div><div>Window</div></button>
285
280
  </div>
286
281
  <!--
@@ -162,11 +162,6 @@ body.dark .card {
162
162
  <button class='btn2' id='genlog'><div><i class="fa-solid fa-laptop-code"></i></div><div>Logs</div></button>
163
163
  <a id='downloadlogs' download class='hidden btn2' href="/pinokio/logs.zip"><div><i class="fa-solid fa-download"></i></div><div>Download logs</div></a>
164
164
  <a class='btn2' href="/?mode=settings"><div><i class="fa-solid fa-gear"></i></div><div>Settings</div></a>
165
- <% if (agent === "electron") { %>
166
- <a href="/" target="_blank" class='btn2' features="browser"><div><i class="fa-solid fa-square-up-right"></i></div><div>Open</div></a>
167
- <% } else { %>
168
- <a href="/" target="_blank" class='btn2'><div><i class="fa-solid fa-square-up-right"></i></div><div>Open</div></a>
169
- <% } %>
170
165
  <button id='new-window' title='open a new window' class='btn2'><i class="fa-solid fa-plus"></i></button>
171
166
 
172
167
  </div>
@@ -578,13 +578,16 @@ document.addEventListener("DOMContentLoaded", async () => {
578
578
  callbacks: {
579
579
  onClose: () => {
580
580
  location.href = "<%=callback%>"
581
+ location.reload()
581
582
  }
582
583
  }
583
584
  <% } %>
584
585
  })
585
586
  <% } else { %>
586
587
  <% if (callback) { %>
588
+ debugger
587
589
  location.href = "<%=callback%>"
590
+ location.reload()
588
591
  <% } %>
589
592
  <% } %>
590
593
  })
@@ -35,7 +35,7 @@ html, body {
35
35
  </style>
36
36
  </head>
37
37
  <body class='<%=theme%>'>
38
- <a class='header-item' href="/"><i class="fa-solid fa-house"></i></a>
38
+ <a class='home' href="/"><img class='icon' src="/pinokio-black.png"></a>
39
39
  <a class='header-item' href="<%=home%>">
40
40
  <img src="<%=rawpath%>/<%=config.icon%>?raw=true"/>
41
41
  <div><%=config.title%></div>
@@ -435,11 +435,14 @@ document.addEventListener("DOMContentLoaded", async () => {
435
435
 
436
436
  refreshParent()
437
437
  let params = packet.data
438
- window.open(
439
- params.uri,
440
- (params.target || "_self"),
441
- params.features
442
- )
438
+ debugger
439
+ console.log("Web open", params)
440
+ open_url(params.uri, params.target, params.features)
441
+ // window.open(
442
+ // params.uri,
443
+ // (params.target || "_self"),
444
+ // params.features
445
+ // )
443
446
  } else if (packet.type === "browser.open") {
444
447
  /*
445
448
  {