pinokiod 3.108.0 → 3.110.0

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.
@@ -23,6 +23,26 @@ class Caddy {
23
23
  }
24
24
  }
25
25
  async start() {
26
+ // if peer.https_active is true,
27
+ // 1. kill existing caddy
28
+ // 2. start caddy
29
+ if (!this.kernel.peer || !("https_active" in this.kernel.peer)) {
30
+ // wait until they are available
31
+ await new Promise((resolve, reject) => {
32
+ let interval = setInterval(() => {
33
+ console.log("wait until peer becomes available")
34
+ if (this.kernel.peer && "https_active" in this.kernel.peer) {
35
+ console.log("peer ready")
36
+ clearInterval(interval)
37
+ resolve()
38
+ }
39
+ }, 1000)
40
+ })
41
+ }
42
+ if (!this.kernel.peer.https_active) {
43
+ console.log("https_active false")
44
+ return
45
+ }
26
46
  // console.log("Existing caddy pid?", this.kernel.processes.caddy_pid)
27
47
  let running = await this.running()
28
48
  console.log("Caddy running?", running)
package/kernel/git.js CHANGED
@@ -67,41 +67,39 @@ class Git {
67
67
  display_name = `${name}/${gitRelPathSansGit}`
68
68
  main = false
69
69
  }
70
+ let gitRemote = null
70
71
  try {
71
- let gitRemote = await git.getConfig({
72
+ gitRemote = await git.getConfig({
72
73
  fs,
73
74
  http,
74
75
  dir,
75
76
  path: 'remote.origin.url'
76
77
  })
77
- repos.push({
78
- main,
79
- name: display_name,
80
- gitPath,
81
- gitRelPath,
82
- gitParentPath,
83
- gitParentRelPath,
84
- dir,
85
- url: gitRemote,
86
- })
87
- if (!this.mapping[gitRemote]) {
78
+ } catch (_) {}
79
+
80
+ const repoEntry = {
81
+ main,
82
+ name: display_name,
83
+ gitPath,
84
+ gitRelPath,
85
+ gitParentPath,
86
+ gitParentRelPath,
87
+ dir,
88
+ }
89
+ if (gitRemote) {
90
+ repoEntry.url = gitRemote
91
+ }
92
+ repos.push(repoEntry)
93
+
94
+ if (gitRemote && !this.mapping[gitRemote]) {
95
+ try {
88
96
  let head = await this.getHead(gitParentPath)
89
97
  this.mapping[gitRemote] = {
90
98
  main,
91
99
  path: gitParentPath,
92
100
  head
93
101
  }
94
- }
95
- } catch (e) {
96
- repos.push({
97
- main,
98
- name: display_name,
99
- gitPath,
100
- gitRelPath,
101
- gitParentPath,
102
- gitParentRelPath,
103
- dir,
104
- })
102
+ } catch (_) {}
105
103
  }
106
104
  this.dirs.add(dir)
107
105
  }
package/kernel/peer.js CHANGED
@@ -249,7 +249,7 @@ class PeerDiscovery {
249
249
  async router_info() {
250
250
  try {
251
251
  let processes = []
252
- if (this.info[this.host]) {
252
+ if (this.info && this.info[this.host]) {
253
253
  let procs = this.info[this.host].proc
254
254
  let router = this.info[this.host].router
255
255
  let port_mapping = this.info[this.host].port_mapping
@@ -406,6 +406,7 @@ class PeerDiscovery {
406
406
  }
407
407
  return {
408
408
  active: this.active,
409
+ https_active: this.https_active,
409
410
  version: this.kernel.version,
410
411
  home: this.kernel.homedir,
411
412
  arch: this.kernel.arch,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pinokiod",
3
- "version": "3.108.0",
3
+ "version": "3.110.0",
4
4
  "description": "",
5
5
  "main": "index.js",
6
6
  "scripts": {
package/server/index.js CHANGED
@@ -484,98 +484,112 @@ class Server {
484
484
  }
485
485
  }
486
486
  async getGit(ref, filepath) {
487
- let dir = this.kernel.path("api", filepath)
488
- let branches = await git.listBranches({ fs, dir });
489
- // no branch, means no git repo => initialize
490
- if (branches.length === 0) {
491
- return {}
492
- // const defaultBranch = 'main';
493
- // await git.init({ fs, dir, defaultBranch });
494
- // branches = await git.listBranches({ fs, dir });
495
- // const current = await git.currentBranch({ fs, dir, fullname: false }) || defaultBranch;
496
- // if (!branches.includes(current)) {
497
- // branches.unshift(current);
498
- // }
499
- // if (!ref || ref === 'HEAD') {
500
- // ref = current;
501
- // }
502
- }
503
- let log = []
487
+ const dir = this.kernel.path("api", filepath)
488
+
489
+ let branchList = []
504
490
  try {
505
- log = await git.log({ fs, dir, depth: 50, ref: ref }); // fetch last 50 commits
506
- log.forEach((item) => {
491
+ branchList = await git.listBranches({ fs, dir })
492
+ } catch (_) {}
493
+
494
+ const collectLog = async (targetRef) => {
495
+ const entries = await git.log({ fs, dir, depth: 50, ref: targetRef })
496
+ entries.forEach((item) => {
507
497
  item.info = `/gitcommit/${item.oid}/${filepath}`
508
498
  })
509
- } catch (e) {
510
- console.log("Log error", e)
499
+ return entries
500
+ }
501
+
502
+ let log = []
503
+ let logError = null
504
+ if (ref) {
505
+ try {
506
+ log = await collectLog(ref)
507
+ } catch (error) {
508
+ logError = error
509
+ }
510
+ }
511
+ if (log.length === 0) {
512
+ try {
513
+ log = await collectLog('HEAD')
514
+ } catch (error) {
515
+ if (!logError) {
516
+ logError = error
517
+ }
518
+ }
519
+ }
520
+
521
+ let currentBranch = null
522
+ try {
523
+ currentBranch = await git.currentBranch({ fs, dir, fullname: false })
524
+ } catch (_) {}
525
+
526
+ let branches = []
527
+ if (branchList.length > 0) {
528
+ branches = branchList.map((name) => ({
529
+ branch: name,
530
+ selected: currentBranch ? name === currentBranch : false
531
+ }))
532
+ if (!currentBranch && log.length > 0) {
533
+ const headOid = log[0].oid
534
+ branches = [{ branch: headOid, selected: true }, ...branches.map((entry) => ({ ...entry, selected: false }))]
535
+ currentBranch = headOid
536
+ }
537
+ } else {
538
+ if (currentBranch) {
539
+ branches = [{ branch: currentBranch, selected: true }]
540
+ } else if (log.length > 0) {
541
+ const headOid = log[0].oid
542
+ branches = [{ branch: headOid, selected: true }]
543
+ currentBranch = headOid
544
+ }
545
+ }
546
+
547
+ if (!currentBranch && log.length > 0) {
548
+ currentBranch = log[0].oid
549
+ }
550
+
551
+ if (branches.length === 0) {
552
+ branches = [{ branch: currentBranch || 'HEAD', selected: true }]
511
553
  }
512
554
 
513
- let config = await this.kernel.git.config(dir)
555
+ const config = await this.kernel.git.config(dir)
514
556
 
515
557
  let hosts = ""
516
- let hosts_file = this.kernel.path("config/gh/hosts.yml")
517
- let e = await this.exists(hosts_file)
518
- if (e) {
519
- hosts = await fs.promises.readFile(hosts_file, "utf8")
558
+ const hostsFile = this.kernel.path("config/gh/hosts.yml")
559
+ if (await this.exists(hostsFile)) {
560
+ hosts = await fs.promises.readFile(hostsFile, "utf8")
520
561
  if (hosts.startsWith("{}")) {
521
562
  hosts = ""
522
563
  }
523
564
  }
524
- let connected = (hosts.length > 0)
565
+ const connected = hosts.length > 0
566
+
525
567
  let remote = null
526
- if (config["remote \"origin\""]) {
568
+ if (config && config["remote \"origin\""]) {
527
569
  remote = config["remote \"origin\""].url
528
570
  }
529
571
 
530
- // Get all remotes
531
572
  let remotes = []
532
573
  try {
533
574
  remotes = await git.listRemotes({ fs, dir, verbose: true })
534
- } catch (e) {
535
- console.log("Remotes error", e)
536
- }
575
+ } catch (_) {}
537
576
 
538
- let branch = await git.currentBranch({ fs, dir, fullname: false });
577
+ if (!currentBranch) {
578
+ currentBranch = 'HEAD'
579
+ }
539
580
 
540
- const remote2 = await git.getConfig({
541
- fs,
581
+ return {
582
+ ref,
583
+ config,
584
+ remote,
585
+ remotes,
586
+ connected,
587
+ log,
588
+ branch: currentBranch,
589
+ branches,
542
590
  dir,
543
- path: `branch.${branch}.remote`
544
- });
545
-
546
- // if current branch exitss => currengt branch is selected
547
- // if current branch does not exist => get logs[0].oid
548
- if (branch) {
549
- branches = branches.map((b) => {
550
- if (b === branch) {
551
- return {
552
- branch: b,
553
- selected: true
554
- }
555
- } else {
556
- return {
557
- branch: b,
558
- selected: false
559
- }
560
- }
561
- })
562
- } else {
563
- branches.push(log[0].oid)
564
- branches = branches.map((b) => {
565
- if (b === log[0].oid) {
566
- return {
567
- branch: b,
568
- selected: true
569
- }
570
- } else {
571
- return {
572
- branch: b,
573
- selected: false
574
- }
575
- }
576
- })
591
+ logError: logError ? String(logError.message || logError) : null
577
592
  }
578
- return { ref, config, remote, remotes, connected, log, branch, branches, dir }
579
593
  }
580
594
  async init_env(env_dir_path, options) {
581
595
  let current = this.kernel.path(env_dir_path, "ENVIRONMENT")
@@ -4084,11 +4098,14 @@ class Server {
4084
4098
  defaultUrl.searchParams.set('mode', 'settings')
4085
4099
  }
4086
4100
 
4101
+ const initialPath = initialUrl.pathname + initialUrl.search + initialUrl.hash
4102
+ const defaultPath = defaultUrl.pathname + defaultUrl.search + defaultUrl.hash
4103
+
4087
4104
  res.render('layout', {
4088
4105
  theme: this.theme,
4089
4106
  agent: req.agent,
4090
- initialPath: initialUrl.pathname + initialUrl.search + initialUrl.hash,
4091
- defaultPath: defaultUrl.pathname + defaultUrl.search + defaultUrl.hash,
4107
+ initialPath,
4108
+ defaultPath,
4092
4109
  sessionId: typeof req.query.session === 'string' ? req.query.session : null
4093
4110
  })
4094
4111
  }))
@@ -5532,7 +5549,6 @@ class Server {
5532
5549
  // }))
5533
5550
  this.app.post("/env", ex(async (req, res) => {
5534
5551
  let fullpath = path.resolve(this.kernel.homedir, req.body.filepath, "ENVIRONMENT")
5535
- console.log({ fullpath })
5536
5552
  let updated = req.body.vals
5537
5553
  let hosts = req.body.hosts
5538
5554
  await Util.update_env(fullpath, updated)
@@ -37,6 +37,26 @@
37
37
  const leafElements = new Map();
38
38
  const gutterElements = new Map();
39
39
  const layoutCache = new Map();
40
+ const PRESERVED_QUERY_PARAMS = new Set(['session']);
41
+
42
+ function stripTransientQueryParams() {
43
+ try {
44
+ const url = new URL(window.location.href);
45
+ let changed = false;
46
+ const keys = Array.from(url.searchParams.keys());
47
+ keys.forEach((key) => {
48
+ if (!PRESERVED_QUERY_PARAMS.has(key)) {
49
+ url.searchParams.delete(key);
50
+ changed = true;
51
+ }
52
+ });
53
+ if (changed) {
54
+ window.history.replaceState(window.history.state, '', url.toString());
55
+ }
56
+ } catch (_) {
57
+ // ignore malformed URLs
58
+ }
59
+ }
40
60
 
41
61
  function normalizeSrc(raw) {
42
62
  if (!raw || typeof raw !== 'string') {
@@ -698,6 +718,7 @@
698
718
  applyLayout();
699
719
  attachGutterHandlers();
700
720
  broadcastLayoutState();
721
+ stripTransientQueryParams();
701
722
  }
702
723
 
703
724
  function onResize() {
@@ -890,6 +890,33 @@ body.dark .tab-link-popover .tab-link-popover-item .value {
890
890
  body.dark .tab-link-popover .tab-link-popover-item .value .muted {
891
891
  color: rgba(226, 232, 240, 0.65);
892
892
  }
893
+ .tab-link-popover .tab-link-popover-footer {
894
+ border-top: 1px solid rgba(15, 23, 42, 0.08);
895
+ margin-top: 4px;
896
+ padding-top: 12px;
897
+ background: rgba(59, 130, 246, 0.12);
898
+ color: #1d4ed8;
899
+ }
900
+ .tab-link-popover .tab-link-popover-footer .label,
901
+ .tab-link-popover .tab-link-popover-footer .value {
902
+ color: inherit;
903
+ }
904
+ .tab-link-popover .tab-link-popover-footer .value {
905
+ font-weight: 600;
906
+ }
907
+ .tab-link-popover .tab-link-popover-footer:hover,
908
+ .tab-link-popover .tab-link-popover-footer:focus-visible {
909
+ background: rgba(37, 99, 235, 0.2);
910
+ }
911
+ body.dark .tab-link-popover .tab-link-popover-footer {
912
+ border-top-color: rgba(148, 163, 184, 0.2);
913
+ background: rgba(96, 165, 250, 0.22);
914
+ color: #bfdbfe;
915
+ }
916
+ body.dark .tab-link-popover .tab-link-popover-footer:hover,
917
+ body.dark .tab-link-popover .tab-link-popover-footer:focus-visible {
918
+ background: rgba(147, 197, 253, 0.35);
919
+ }
893
920
  .tab.has-preview .tab-preview {
894
921
  color: rgba(0, 0, 0, 0.6);
895
922
  min-width: 0;
@@ -1947,6 +1974,40 @@ body.dark {
1947
1974
  background: #2d6ae0 !important;
1948
1975
  }
1949
1976
 
1977
+ .pinokio-github-login-modal.swal2-popup {
1978
+ max-width: 420px !important;
1979
+ width: calc(100vw - 48px) !important;
1980
+ }
1981
+ .pinokio-github-login {
1982
+ padding: 36px 40px 32px 40px;
1983
+ display: flex;
1984
+ flex-direction: column;
1985
+ align-items: center;
1986
+ text-align: center;
1987
+ gap: 14px;
1988
+ }
1989
+ .pinokio-github-login__icon {
1990
+ width: 64px;
1991
+ height: 64px;
1992
+ border-radius: 18px;
1993
+ display: grid;
1994
+ place-items: center;
1995
+ background: var(--pinokio-modal-icon-bg);
1996
+ color: var(--pinokio-modal-icon-color);
1997
+ font-size: 28px;
1998
+ }
1999
+ .pinokio-github-login__title {
2000
+ font-size: 20px;
2001
+ font-weight: 600;
2002
+ color: var(--pinokio-modal-text);
2003
+ }
2004
+ .pinokio-github-login__body {
2005
+ font-size: 14px;
2006
+ line-height: 1.6;
2007
+ color: var(--pinokio-modal-subtitle-color);
2008
+ max-width: 280px;
2009
+ }
2010
+
1950
2011
  .pinokio-modern-modal.swal2-popup {
1951
2012
  background: var(--pinokio-modal-bg) !important;
1952
2013
  color: var(--pinokio-modal-text) !important;
@@ -3054,6 +3115,7 @@ body.dark {
3054
3115
  let tabLinkLocalInfoExpiry = 0
3055
3116
  let tabLinkRouterInfoPromise = null
3056
3117
  let tabLinkRouterInfoExpiry = 0
3118
+ let tabLinkRouterHttpsActive = null
3057
3119
 
3058
3120
  const ensureTabLinkPopoverEl = () => {
3059
3121
  if (!tabLinkPopoverEl) {
@@ -3078,7 +3140,12 @@ body.dark {
3078
3140
  event.stopPropagation()
3079
3141
  const url = item.getAttribute("data-url")
3080
3142
  if (url) {
3081
- window.open(url, "_blank", "noopener")
3143
+ const targetMode = (item.getAttribute("data-target") || "_blank").toLowerCase()
3144
+ if (targetMode === "_self") {
3145
+ window.location.assign(url)
3146
+ } else {
3147
+ window.open(url, "_blank", "noopener")
3148
+ }
3082
3149
  }
3083
3150
  hideTabLinkPopover({ immediate: true })
3084
3151
  })
@@ -3395,6 +3462,9 @@ body.dark {
3395
3462
  return response.json()
3396
3463
  })
3397
3464
  .then((data) => {
3465
+ if (typeof data?.https_active === "boolean") {
3466
+ tabLinkRouterHttpsActive = data.https_active
3467
+ }
3398
3468
  const processes = Array.isArray(data?.router_info) ? data.router_info : []
3399
3469
  const rewriteMapping = data?.rewrite_mapping && typeof data.rewrite_mapping === "object"
3400
3470
  ? Object.values(data.rewrite_mapping)
@@ -3628,10 +3698,13 @@ body.dark {
3628
3698
  hostPortMap
3629
3699
  }
3630
3700
  })
3631
- .catch(() => ({
3632
- portMap: new Map(),
3633
- hostPortMap: new Map()
3634
- }))
3701
+ .catch(() => {
3702
+ tabLinkRouterHttpsActive = null
3703
+ return {
3704
+ portMap: new Map(),
3705
+ hostPortMap: new Map()
3706
+ }
3707
+ })
3635
3708
  tabLinkRouterInfoExpiry = now + 3000
3636
3709
  }
3637
3710
  return tabLinkRouterInfoPromise
@@ -3991,6 +4064,8 @@ body.dark {
3991
4064
  header.innerHTML = `<i class="fa-solid fa-arrow-up-right-from-square"></i><span>Open in browser</span>`
3992
4065
  popover.appendChild(header)
3993
4066
 
4067
+ const hasHttpsEntry = entries.some((entry) => entry && entry.type === "https")
4068
+
3994
4069
  entries.forEach((entry) => {
3995
4070
  const item = document.createElement("button")
3996
4071
  item.type = "button"
@@ -4006,6 +4081,26 @@ body.dark {
4006
4081
  popover.appendChild(item)
4007
4082
  })
4008
4083
 
4084
+ if (tabLinkRouterHttpsActive === false && !hasHttpsEntry) {
4085
+ const footerButton = document.createElement("button")
4086
+ footerButton.type = "button"
4087
+ footerButton.className = "tab-link-popover-item tab-link-popover-footer"
4088
+ footerButton.setAttribute("data-url", "/network")
4089
+ footerButton.setAttribute("data-target", "_self")
4090
+ footerButton.setAttribute("aria-label", "Open network settings to configure local HTTPS")
4091
+
4092
+ const footerLabel = document.createElement("span")
4093
+ footerLabel.className = "label"
4094
+ footerLabel.textContent = "Custom domain not active"
4095
+
4096
+ const footerValue = document.createElement("span")
4097
+ footerValue.className = "value"
4098
+ footerValue.textContent = "Click to activate"
4099
+
4100
+ footerButton.append(footerLabel, footerValue)
4101
+ popover.appendChild(footerButton)
4102
+ }
4103
+
4009
4104
  tabLinkActiveLink = link
4010
4105
  tabLinkPendingLink = null
4011
4106
  positionTabLinkPopover(popover, link)
@@ -4160,6 +4255,13 @@ body.dark {
4160
4255
  })(),
4161
4256
  target: node.getAttribute('target') || null,
4162
4257
  dataIndex: node.getAttribute('data-index') || null,
4258
+ pagePath: (() => {
4259
+ try {
4260
+ return window.location?.pathname || null
4261
+ } catch (_) {
4262
+ return null
4263
+ }
4264
+ })()
4163
4265
  }
4164
4266
  try {
4165
4267
  const key = selectionStorageKey()
@@ -4173,24 +4275,41 @@ body.dark {
4173
4275
  })
4174
4276
  } catch (_) {}
4175
4277
  }
4176
- const restorePersistedFrameLink = () => {
4278
+ const restorePersistedFrameLink = (providedPayload = null) => {
4177
4279
  const storage = getWindowStorage()
4178
- if (!storage) {
4179
- return null
4180
- }
4181
4280
  const key = selectionStorageKey()
4182
- if (!key) {
4183
- return null
4281
+ const currentPath = (() => {
4282
+ try {
4283
+ return window.location?.pathname || ""
4284
+ } catch (_) {
4285
+ return ""
4286
+ }
4287
+ })()
4288
+ let payload = providedPayload
4289
+ if (!payload) {
4290
+ if (!storage || !key) {
4291
+ return null
4292
+ }
4293
+ const raw = storage.getItem(key)
4294
+ if (!raw) {
4295
+ return null
4296
+ }
4297
+ try {
4298
+ payload = JSON.parse(raw)
4299
+ } catch (_) {
4300
+ payload = { selector: raw }
4301
+ }
4184
4302
  }
4185
- const raw = storage.getItem(key)
4186
- if (!raw) {
4303
+ if (!payload) {
4187
4304
  return null
4188
4305
  }
4189
- let payload
4190
- try {
4191
- payload = JSON.parse(raw)
4192
- } catch (_) {
4193
- payload = { selector: raw }
4306
+ if (typeof payload === 'object' && payload !== null && typeof payload.pagePath === 'string') {
4307
+ if (currentPath && payload.pagePath !== currentPath) {
4308
+ return null
4309
+ }
4310
+ }
4311
+ if (typeof payload === 'string') {
4312
+ payload = { selector: payload }
4194
4313
  }
4195
4314
  const trySelector = (selector) => {
4196
4315
  if (!selector || typeof selector !== 'string') {
@@ -4849,14 +4968,48 @@ body.dark {
4849
4968
  const renderSelection = async ({ event: eventParam = null, target: explicitTarget = null, force = false } = {}) => {
4850
4969
  const storage = getWindowStorage()
4851
4970
  const selectionKey = selectionStorageKey()
4852
- const originalHasPersistedSelection = Boolean(selectionKey && storage && storage.getItem(selectionKey))
4971
+ const currentPath = (() => {
4972
+ try {
4973
+ return window.location?.pathname || ""
4974
+ } catch (_) {
4975
+ return ""
4976
+ }
4977
+ })()
4853
4978
  let persistedSelectionRaw = selectionKey && storage ? storage.getItem(selectionKey) : null
4979
+ const devRouteActive = /\/dev(?:$|\/)/.test(currentPath || "")
4980
+ let persistedSelectionPayload = null
4981
+ if (persistedSelectionRaw) {
4982
+ try {
4983
+ const parsed = JSON.parse(persistedSelectionRaw)
4984
+ if (parsed && typeof parsed === "object") {
4985
+ if (typeof parsed.pagePath === "string") {
4986
+ if (!currentPath || parsed.pagePath === currentPath) {
4987
+ persistedSelectionPayload = parsed
4988
+ }
4989
+ } else if (!devRouteActive) {
4990
+ persistedSelectionPayload = parsed
4991
+ }
4992
+ }
4993
+ } catch (_) {
4994
+ if (!devRouteActive) {
4995
+ persistedSelectionPayload = { selector: persistedSelectionRaw }
4996
+ }
4997
+ }
4998
+ }
4999
+ if (!persistedSelectionPayload) {
5000
+ persistedSelectionRaw = null
5001
+ }
5002
+ const originalHasPersistedSelection = Boolean(persistedSelectionPayload)
4854
5003
  const skipPersistedSelection = ignorePersistedSelection
4855
5004
  let hasPersistedSelection = skipPersistedSelection ? false : originalHasPersistedSelection
4856
5005
  if (skipPersistedSelection) {
4857
5006
  persistedSelectionRaw = null
5007
+ persistedSelectionPayload = null
4858
5008
  }
4859
5009
 
5010
+ const triggeredByUser = Boolean(eventParam || explicitTarget)
5011
+ let resolvedByGlobalSelector = false
5012
+
4860
5013
  let target = explicitTarget
4861
5014
  let preselected = null
4862
5015
 
@@ -4869,22 +5022,22 @@ body.dark {
4869
5022
  if (candidate) {
4870
5023
  target = candidate
4871
5024
  global_selector = null
5025
+ resolvedByGlobalSelector = true
4872
5026
  } else {
4873
5027
  scheduleSelectionRetry()
4874
5028
  return
4875
5029
  }
4876
5030
  }
4877
5031
 
5032
+ console.log({ target, skipPersistedSelection })
4878
5033
  if (!target && !skipPersistedSelection) {
4879
5034
  preselected = document.querySelector('#devtab.frame-link.selected') || document.querySelector('.frame-link.selected')
4880
- if (preselected) {
4881
- target = preselected
4882
- }
5035
+ console.log({ preselected })
4883
5036
  }
4884
5037
 
4885
- if (!target && persistedSelectionRaw) {
4886
- target = restorePersistedFrameLink()
4887
- if (!target && persistedSelectionRaw) {
5038
+ if (!target && persistedSelectionPayload) {
5039
+ target = restorePersistedFrameLink(persistedSelectionPayload)
5040
+ if (!target && originalHasPersistedSelection) {
4888
5041
  scheduleSelectionRetry()
4889
5042
  return
4890
5043
  }
@@ -4898,11 +5051,18 @@ body.dark {
4898
5051
  }
4899
5052
  }
4900
5053
 
4901
- if (!target && skipPersistedSelection) {
5054
+ const devTab = document.querySelector('#devtab.frame-link')
5055
+ if (!triggeredByUser && !resolvedByGlobalSelector && !target && devRouteActive && devTab) {
5056
+ target = devTab
5057
+ } else if (!target && preselected) {
5058
+ target = preselected
5059
+ }
5060
+
5061
+ if (!target) {
4902
5062
  const defaultSelection = document.querySelector("[data-default]")
4903
5063
  if (defaultSelection) {
4904
5064
  target = defaultSelection
4905
- } else {
5065
+ } else if (skipPersistedSelection) {
4906
5066
  scheduleSelectionRetry()
4907
5067
  return
4908
5068
  }
@@ -4939,6 +5099,12 @@ body.dark {
4939
5099
  }
4940
5100
  <% } %>
4941
5101
 
5102
+ if (!target && preselected) {
5103
+ target = preselected
5104
+ }
5105
+
5106
+ console.log({ targetAfter: target })
5107
+
4942
5108
  if (!target) {
4943
5109
  target = document.querySelector(".frame-link")
4944
5110
  }
@@ -5239,7 +5405,7 @@ body.dark {
5239
5405
  item.href = url
5240
5406
  item.setAttribute("data-index", index)
5241
5407
  item.className = "btn header-item frame-link"
5242
- item.innerHTML = `<div class='tab'><i class="fa-solid fa-link"></i><div class='display'>${url}</div><div class='flexible'></div><button class='btn2 del'><i class="fa-solid fa-xmark"></i></button></div>`
5408
+ item.innerHTML = `<div class='tab'><i class="fa-solid fa-link"></i><div class='display'>${url}</div><div class='flexible'></div><button class='btn2 del'><i class="fa-solid fa-circle-stop"></i></button></div>`
5243
5409
 
5244
5410
  document.querySelector(".temp-menu").appendChild(item)
5245
5411
 
@@ -5920,7 +6086,7 @@ body.dark {
5920
6086
  })
5921
6087
  setupTabLinkHover()
5922
6088
  document.addEventListener("click", (event) => {
5923
- if (event.target.closest("#fs-status .fs-dropdown-menu")) {
6089
+ if (event.target.closest("#fs-status .fs-dropdown-menu") || event.target.closest("#fs-status .fs-status-btn")) {
5924
6090
  return
5925
6091
  }
5926
6092
  closeStatusDropdowns()
@@ -6409,6 +6575,7 @@ body.dark {
6409
6575
 
6410
6576
  const detachHandlers = () => {
6411
6577
  forkBtn.removeEventListener('click', handlePushLogin)
6578
+ forkBtn.removeEventListener('click', requireGitLogin)
6412
6579
  }
6413
6580
 
6414
6581
  const enableDropdown = () => {
@@ -6419,7 +6586,11 @@ body.dark {
6419
6586
  const disableDropdown = () => {
6420
6587
  forkBtn.classList.remove('revealer')
6421
6588
  forkBtn.removeAttribute('data-group')
6422
- closeStatusDropdowns()
6589
+ const forkMenuEl = document.querySelector('#fs-fork-menu')
6590
+ if (forkMenuEl && !forkMenuEl.classList.contains('hidden')) {
6591
+ forkMenuEl.classList.add('hidden')
6592
+ }
6593
+ setDropdownState(forkBtn, false)
6423
6594
  }
6424
6595
 
6425
6596
  detachHandlers()
@@ -6435,12 +6606,12 @@ body.dark {
6435
6606
  if (!isConnected) {
6436
6607
  disableDropdown()
6437
6608
  if (labelEl) {
6438
- labelEl.textContent = 'Login'
6609
+ labelEl.textContent = 'Fork'
6439
6610
  }
6440
6611
  forkBtn.disabled = false
6441
6612
  forkBtn.classList.remove('fs-status-btn--disabled')
6442
- forkBtn.setAttribute('title', 'Connect GitHub to fork this workspace')
6443
- forkBtn.addEventListener('click', handlePushLogin)
6613
+ forkBtn.setAttribute('title', 'Log in to GitHub to fork this workspace')
6614
+ forkBtn.addEventListener('click', requireGitLogin)
6444
6615
  return
6445
6616
  }
6446
6617
 
@@ -8148,6 +8319,41 @@ body.dark {
8148
8319
  function handlePushLogin() {
8149
8320
  window.location.href = '/github'
8150
8321
  }
8322
+ const promptGitLogin = () => {
8323
+ Swal.fire({
8324
+ html: `
8325
+ <div class="pinokio-github-login">
8326
+ <div class="pinokio-github-login__icon"><i class="fa-brands fa-github"></i></div>
8327
+ <div class="pinokio-github-login__title">Log in to GitHub</div>
8328
+ <div class="pinokio-github-login__body">Connect your GitHub account to fork or publish this workspace.</div>
8329
+ </div>
8330
+ `,
8331
+ showCancelButton: true,
8332
+ confirmButtonText: 'Log in',
8333
+ cancelButtonText: 'Not now',
8334
+ reverseButtons: true,
8335
+ showCloseButton: true,
8336
+ focusConfirm: true,
8337
+ customClass: {
8338
+ popup: 'pinokio-modern-modal pinokio-github-login-modal',
8339
+ htmlContainer: 'pinokio-modern-html',
8340
+ confirmButton: 'pinokio-modern-confirm',
8341
+ cancelButton: 'pinokio-modern-cancel',
8342
+ closeButton: 'pinokio-modern-close'
8343
+ }
8344
+ }).then((result) => {
8345
+ if (result.isConfirmed) {
8346
+ handlePushLogin()
8347
+ }
8348
+ })
8349
+ }
8350
+ const requireGitLogin = (event) => {
8351
+ if (event) {
8352
+ event.preventDefault()
8353
+ event.stopPropagation()
8354
+ }
8355
+ promptGitLogin()
8356
+ }
8151
8357
 
8152
8358
  // Function to update publish/create button
8153
8359
  const updatePublishButton = async () => {
@@ -8167,6 +8373,7 @@ body.dark {
8167
8373
  pushBtn.removeEventListener('click', showPublishModal)
8168
8374
  pushBtn.removeEventListener('click', showCreateModal)
8169
8375
  pushBtn.removeEventListener('click', handlePushLogin)
8376
+ pushBtn.removeEventListener('click', requireGitLogin)
8170
8377
  }
8171
8378
  const enableDropdown = () => {
8172
8379
  pushBtn.classList.add('revealer')
@@ -8175,7 +8382,11 @@ body.dark {
8175
8382
  const disableDropdown = () => {
8176
8383
  pushBtn.classList.remove('revealer')
8177
8384
  pushBtn.removeAttribute('data-group')
8178
- closeStatusDropdowns()
8385
+ const pushMenuEl = document.querySelector('#fs-push-menu')
8386
+ if (pushMenuEl && !pushMenuEl.classList.contains('hidden')) {
8387
+ pushMenuEl.classList.add('hidden')
8388
+ }
8389
+ setDropdownState(pushBtn, false)
8179
8390
  }
8180
8391
 
8181
8392
  const repos = getRepoListSnapshot()
@@ -8227,12 +8438,12 @@ body.dark {
8227
8438
  renderPublishDropdown(repos, { emptyMessage })
8228
8439
 
8229
8440
  if (!isConnected) {
8230
- setLabel('Login')
8441
+ setLabel('Publish')
8231
8442
  pushBtn.disabled = false
8232
8443
  pushBtn.classList.remove('fs-status-btn--disabled')
8233
- pushBtn.setAttribute('title', 'Connect GitHub to publish this workspace')
8444
+ pushBtn.setAttribute('title', 'Log in to GitHub to publish this workspace')
8234
8445
  disableDropdown()
8235
- pushBtn.addEventListener('click', handlePushLogin)
8446
+ pushBtn.addEventListener('click', requireGitLogin)
8236
8447
  syncForkButton()
8237
8448
  return
8238
8449
  }
@@ -8266,12 +8477,12 @@ body.dark {
8266
8477
  } catch (error) {
8267
8478
  console.error('Error checking remotes:', error)
8268
8479
  setPublishMenuMessage('Git integration unavailable')
8269
- setLabel('Login')
8480
+ setLabel('Publish')
8270
8481
  pushBtn.disabled = false
8271
8482
  pushBtn.classList.remove('fs-status-btn--disabled')
8272
- pushBtn.setAttribute('title', 'Connect GitHub to publish this workspace')
8483
+ pushBtn.setAttribute('title', 'Log in to GitHub to publish this workspace')
8273
8484
  disableDropdown()
8274
- pushBtn.addEventListener('click', handlePushLogin)
8485
+ pushBtn.addEventListener('click', requireGitLogin)
8275
8486
  latestGitIntegration = null
8276
8487
  updateForkButton()
8277
8488
  }
@@ -202,7 +202,7 @@ body.dark .browser-options-row {
202
202
  <% if (dep.downloaded) { %>
203
203
  <div class='item'><i class="fa-solid fa-check"></i> <a class='downloaded' href="<%=dep.downloaded%>" target="_blank"><%=dep.uri%></a><div class='flexible'></div></div>
204
204
  <% } else { %>
205
- <div class='item'><a class='btn' href="/home?mode=download&uri=<%=dep.uri%>" target="_blank"><i class="fa-solid fa-download"></i> Download</a> <%=dep.uri%><div class='flexible'></div></div>
205
+ <div class='item'><a class='btn' href="/?mode=download&uri=<%= encodeURIComponent(dep.uri) %>" target="_blank"><i class="fa-solid fa-download"></i> Download</a> <%=dep.uri%><div class='flexible'></div></div>
206
206
  <% } %>
207
207
  <% }) %>
208
208
  </div>
@@ -464,7 +464,7 @@ body.dark aside .current.selected {
464
464
  <% if (dep.downloaded) { %>
465
465
  <div class='item'><i class="fa-solid fa-check"></i> <a class='downloaded' href="<%=dep.downloaded%>" target="_blank"><%=dep.uri%></a><div class='flexible'></div></div>
466
466
  <% } else { %>
467
- <div class='item'><a class='btn' href="/home?mode=download&uri=<%=dep.uri%>" target="_blank"><i class="fa-solid fa-download"></i> Download</a> <%=dep.uri%><div class='flexible'></div></div>
467
+ <div class='item'><a class='btn' href="/?mode=download&uri=<%= encodeURIComponent(dep.uri) %>" target="_blank"><i class="fa-solid fa-download"></i> Download</a> <%=dep.uri%><div class='flexible'></div></div>
468
468
  <% } %>
469
469
  <% }) %>
470
470
  </div>
@@ -290,7 +290,7 @@ body.dark .open-menu, body.dark .browse {
290
290
  <% if (dep.downloaded) { %>
291
291
  <div class='item'><i class="fa-solid fa-check"></i> <a class='downloaded' href="<%=dep.downloaded%>" target="_blank"><%=dep.uri%></a><div class='flexible'></div></div>
292
292
  <% } else { %>
293
- <div class='item'><a class='btn' href="/home?mode=download&uri=<%=dep.uri%>" target="_blank"><i class="fa-solid fa-download"></i> Download</a> <%=dep.uri%><div class='flexible'></div></div>
293
+ <div class='item'><a class='btn' href="/?mode=download&uri=<%= encodeURIComponent(dep.uri) %>" target="_blank"><i class="fa-solid fa-download"></i> Download</a> <%=dep.uri%><div class='flexible'></div></div>
294
294
  <% } %>
295
295
  <% }) %>
296
296
  </div>
@@ -46,7 +46,7 @@
46
46
  </div>
47
47
  <% } else { %>
48
48
  <div class='loader shutdown'>
49
- <i class="fa-solid fa-xmark"></i>
49
+ <i class="fa-solid fa-circle-stop"></i>
50
50
  </div>
51
51
  <% } %>
52
52
  <% } else { %>
@@ -65,7 +65,7 @@
65
65
  <i class='fa-solid fa-spin fa-circle-notch'></i>
66
66
  <i class="fa-solid fa-chevron-right"></i>
67
67
  -->
68
- <i class="fa-solid fa-xmark"></i>
68
+ <i class="fa-solid fa-circle-stop"></i>
69
69
  </div>
70
70
  <% } %>
71
71
  <% if (item.arrow) { %>