pinokiod 3.9.36 → 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.
@@ -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.36",
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) {
@@ -955,6 +957,7 @@ class Server {
955
957
  items: env_requirements.items
956
958
  })
957
959
  } else {
960
+ console.log("req.query.callback", req.query.callback)
958
961
 
959
962
  // check if it's a prototype script
960
963
  let kill_message
@@ -964,6 +967,8 @@ class Server {
964
967
  // kill_message = "Done! Click to go to the project"
965
968
  }
966
969
 
970
+ console.log(">>>>>>>>>> Callback", callback)
971
+
967
972
  let logpath = encodeURIComponent(Util.log_path(filepath, this.kernel))
968
973
  const result = {
969
974
  portal: this.portal,
@@ -1569,6 +1574,7 @@ class Server {
1569
1574
  config.html = `${config.text}`
1570
1575
  }
1571
1576
  config.btn = config.html
1577
+ config.arrow = true
1572
1578
  }
1573
1579
  /*
1574
1580
  if (config.href && !config.href.startsWith("/")) {
@@ -1580,6 +1586,7 @@ class Server {
1580
1586
  if (keypath) {
1581
1587
  config.href = base.href + "/" + keypath.join("/") + "?path=" + base.cwd
1582
1588
  }
1589
+ console.log({ config })
1583
1590
  return config
1584
1591
  }
1585
1592
 
@@ -3503,6 +3510,7 @@ class Server {
3503
3510
  }
3504
3511
  }))
3505
3512
  this.app.get("/prototype/run/*", ex(async (req, res) => {
3513
+ console.log("/prototype/run", req.params[0])
3506
3514
  let pathComponents = req.params[0].split("/").concat("pinokio.js")
3507
3515
  let config = await this.kernel.api.meta({ path: req.query.path })
3508
3516
  let pinokiojson_path = path.resolve(req.query.path, "pinokio.json")
@@ -3528,6 +3536,8 @@ class Server {
3528
3536
  }
3529
3537
  req.base = this.kernel.path("prototype")
3530
3538
  req.query.callback = config.ui
3539
+ console.log("config.ui", config.ui)
3540
+ console.log("req.query", req.query)
3531
3541
  //req.query.callback = config.browse
3532
3542
  req.query.cwd = req.query.path
3533
3543
  await this.render(req, res, pathComponents, null)
@@ -3546,27 +3556,56 @@ class Server {
3546
3556
  for(let key of paths) {
3547
3557
  config = config.menu[key]
3548
3558
  }
3549
- let run_path = "/run/prototype/system/" + config.href + "?cwd=" + req.query.path
3550
- console.log({ config, run_path, query: req.query })
3551
- let readme_path = this.kernel.path("prototype/system", config.readme)
3552
- console.log("config.readme.split", config.readme.split("/").slice(0, -1))
3553
- let md = await fs.promises.readFile(readme_path, "utf8")
3554
- console.log({ readme_path, md })
3555
- let baseUrl = "/asset/prototype/system/" + (config.readme.split("/").slice(0, -1).join("/")) + "/"
3556
- console.log("baseUrl", baseUrl)
3557
- let readme = marked.parse(md, {
3558
- baseUrl
3559
- })
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
+ }
3560
3608
 
3561
- res.render("prototype/show", {
3562
- run_path,
3563
- portal: this.portal,
3564
- readme,
3565
- logo: this.logo,
3566
- theme: this.theme,
3567
- agent: this.agent,
3568
- kernel: this.kernel,
3569
- })
3570
3609
  }))
3571
3610
  this.app.get("/prototype", ex(async (req, res) => {
3572
3611
  // load meta
@@ -3591,6 +3630,7 @@ class Server {
3591
3630
  href: "/prototype/show",
3592
3631
  path: "/asset/prototype/system"
3593
3632
  })
3633
+ console.log("FINAL CONFIG", JSON.stringify(config, null, 2))
3594
3634
 
3595
3635
  // {
3596
3636
  // "icon": "fa-solid fa-power-off",
@@ -3695,6 +3735,7 @@ class Server {
3695
3735
  }
3696
3736
  }))
3697
3737
  this.app.post("/env", ex(async (req, res) => {
3738
+ console.log("REQ.body", req.body)
3698
3739
  let fullpath = path.resolve(this.kernel.homedir, req.body.filepath, "ENVIRONMENT")
3699
3740
  let updated = req.body.vals
3700
3741
  let hosts = req.body.hosts
@@ -3734,8 +3775,9 @@ class Server {
3734
3775
  this.app.get("/env/*", ex(async (req, res) => {
3735
3776
 
3736
3777
  let env_path = req.params[0]
3737
- let p = path.resolve(this.kernel.homedir, env_path, "pinokio.js")
3738
- 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)
3739
3781
  if (config.run) {
3740
3782
  await this.init_env(env_path, { no_inherit: true })
3741
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
 
@@ -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;
@@ -1164,7 +1169,7 @@ body.dark .line:hover {
1164
1169
  /*
1165
1170
  padding: 15px 15px;
1166
1171
  */
1167
- padding: 7px;
1172
+ padding: 7px 5px;
1168
1173
  border-bottom: 1px solid var(--light-thin);
1169
1174
  }
1170
1175
  .thick.line {
@@ -1862,22 +1867,27 @@ body.dark .not-running-apps, body.dark .running-apps {
1862
1867
  color: #82bc09;
1863
1868
  }
1864
1869
  */
1865
- .running-apps .line img {
1870
+ .running-apps .line {
1866
1871
  border-left: 10px solid #82bc09;
1867
- padding-left: 10px;
1872
+ }
1873
+ .running-apps .line img {
1874
+ padding-left: 3px;
1868
1875
  /*
1876
+ padding-left: 10px;
1869
1877
  border: 3px solid #8fd400;
1870
1878
  */
1871
1879
  /*
1872
1880
  border-radius: 5px;
1873
1881
  */
1874
1882
  }
1875
- body.dark .not-running-apps .line img {
1883
+ body.dark .not-running-apps .line {
1876
1884
  border-left: 10px solid rgba(255,255,255,0.1);
1877
1885
  }
1878
- .not-running-apps .line img {
1886
+ .not-running-apps .line {
1879
1887
  border-left: 10px solid rgba(0,0,0,0.04);
1880
- padding-left: 10px;
1888
+ }
1889
+ .not-running-apps .line img {
1890
+ padding-left: 3px;
1881
1891
  }
1882
1892
  /*
1883
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 {
@@ -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) => {
@@ -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>
@@ -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>
@@ -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
  <!--
@@ -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>
@@ -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
  <% } %>
@@ -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;
@@ -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>
@@ -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
  })
@@ -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
  {