pinokiod 3.108.0 → 3.109.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)
@@ -31,6 +51,7 @@ class Caddy {
31
51
  console.log("kill existing caddy before restarting")
32
52
  await new Promise((resolve, reject) => {
33
53
  let interval = setInterval(() => {
54
+ console.log("CADDY_PID", this.kernel.processes.caddy_pid)
34
55
  if (this.kernel.processes.caddy_pid) {
35
56
  try {
36
57
  console.log("kill caddy", this.kernel.processes.caddy_pid)
@@ -39,10 +60,12 @@ class Caddy {
39
60
  clearInterval(interval)
40
61
  resolve()
41
62
  } catch (error) {
63
+ console.log("ERROR", error)
42
64
  clearInterval(interval)
43
65
  reject(error)
44
66
  }
45
67
  } else {
68
+ //clearInterval(interval)
46
69
  console.log("try killing existing caddy again in 1 sec")
47
70
  }
48
71
  }, 1000)
@@ -76,6 +99,7 @@ class Caddy {
76
99
  this.kernel.peer.announce()
77
100
  console.log("announced to peers")
78
101
  // this.kernel.refresh(true)
102
+ } else {
79
103
  }
80
104
  }
81
105
  async install(req, ondata, kernel, id) {
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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pinokiod",
3
- "version": "3.108.0",
3
+ "version": "3.109.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() {
@@ -1947,6 +1947,40 @@ body.dark {
1947
1947
  background: #2d6ae0 !important;
1948
1948
  }
1949
1949
 
1950
+ .pinokio-github-login-modal.swal2-popup {
1951
+ max-width: 420px !important;
1952
+ width: calc(100vw - 48px) !important;
1953
+ }
1954
+ .pinokio-github-login {
1955
+ padding: 36px 40px 32px 40px;
1956
+ display: flex;
1957
+ flex-direction: column;
1958
+ align-items: center;
1959
+ text-align: center;
1960
+ gap: 14px;
1961
+ }
1962
+ .pinokio-github-login__icon {
1963
+ width: 64px;
1964
+ height: 64px;
1965
+ border-radius: 18px;
1966
+ display: grid;
1967
+ place-items: center;
1968
+ background: var(--pinokio-modal-icon-bg);
1969
+ color: var(--pinokio-modal-icon-color);
1970
+ font-size: 28px;
1971
+ }
1972
+ .pinokio-github-login__title {
1973
+ font-size: 20px;
1974
+ font-weight: 600;
1975
+ color: var(--pinokio-modal-text);
1976
+ }
1977
+ .pinokio-github-login__body {
1978
+ font-size: 14px;
1979
+ line-height: 1.6;
1980
+ color: var(--pinokio-modal-subtitle-color);
1981
+ max-width: 280px;
1982
+ }
1983
+
1950
1984
  .pinokio-modern-modal.swal2-popup {
1951
1985
  background: var(--pinokio-modal-bg) !important;
1952
1986
  color: var(--pinokio-modal-text) !important;
@@ -4160,6 +4194,13 @@ body.dark {
4160
4194
  })(),
4161
4195
  target: node.getAttribute('target') || null,
4162
4196
  dataIndex: node.getAttribute('data-index') || null,
4197
+ pagePath: (() => {
4198
+ try {
4199
+ return window.location?.pathname || null
4200
+ } catch (_) {
4201
+ return null
4202
+ }
4203
+ })()
4163
4204
  }
4164
4205
  try {
4165
4206
  const key = selectionStorageKey()
@@ -4173,24 +4214,41 @@ body.dark {
4173
4214
  })
4174
4215
  } catch (_) {}
4175
4216
  }
4176
- const restorePersistedFrameLink = () => {
4217
+ const restorePersistedFrameLink = (providedPayload = null) => {
4177
4218
  const storage = getWindowStorage()
4178
- if (!storage) {
4179
- return null
4180
- }
4181
4219
  const key = selectionStorageKey()
4182
- if (!key) {
4183
- return null
4220
+ const currentPath = (() => {
4221
+ try {
4222
+ return window.location?.pathname || ""
4223
+ } catch (_) {
4224
+ return ""
4225
+ }
4226
+ })()
4227
+ let payload = providedPayload
4228
+ if (!payload) {
4229
+ if (!storage || !key) {
4230
+ return null
4231
+ }
4232
+ const raw = storage.getItem(key)
4233
+ if (!raw) {
4234
+ return null
4235
+ }
4236
+ try {
4237
+ payload = JSON.parse(raw)
4238
+ } catch (_) {
4239
+ payload = { selector: raw }
4240
+ }
4184
4241
  }
4185
- const raw = storage.getItem(key)
4186
- if (!raw) {
4242
+ if (!payload) {
4187
4243
  return null
4188
4244
  }
4189
- let payload
4190
- try {
4191
- payload = JSON.parse(raw)
4192
- } catch (_) {
4193
- payload = { selector: raw }
4245
+ if (typeof payload === 'object' && payload !== null && typeof payload.pagePath === 'string') {
4246
+ if (currentPath && payload.pagePath !== currentPath) {
4247
+ return null
4248
+ }
4249
+ }
4250
+ if (typeof payload === 'string') {
4251
+ payload = { selector: payload }
4194
4252
  }
4195
4253
  const trySelector = (selector) => {
4196
4254
  if (!selector || typeof selector !== 'string') {
@@ -4849,14 +4907,48 @@ body.dark {
4849
4907
  const renderSelection = async ({ event: eventParam = null, target: explicitTarget = null, force = false } = {}) => {
4850
4908
  const storage = getWindowStorage()
4851
4909
  const selectionKey = selectionStorageKey()
4852
- const originalHasPersistedSelection = Boolean(selectionKey && storage && storage.getItem(selectionKey))
4910
+ const currentPath = (() => {
4911
+ try {
4912
+ return window.location?.pathname || ""
4913
+ } catch (_) {
4914
+ return ""
4915
+ }
4916
+ })()
4853
4917
  let persistedSelectionRaw = selectionKey && storage ? storage.getItem(selectionKey) : null
4918
+ const devRouteActive = /\/dev(?:$|\/)/.test(currentPath || "")
4919
+ let persistedSelectionPayload = null
4920
+ if (persistedSelectionRaw) {
4921
+ try {
4922
+ const parsed = JSON.parse(persistedSelectionRaw)
4923
+ if (parsed && typeof parsed === "object") {
4924
+ if (typeof parsed.pagePath === "string") {
4925
+ if (!currentPath || parsed.pagePath === currentPath) {
4926
+ persistedSelectionPayload = parsed
4927
+ }
4928
+ } else if (!devRouteActive) {
4929
+ persistedSelectionPayload = parsed
4930
+ }
4931
+ }
4932
+ } catch (_) {
4933
+ if (!devRouteActive) {
4934
+ persistedSelectionPayload = { selector: persistedSelectionRaw }
4935
+ }
4936
+ }
4937
+ }
4938
+ if (!persistedSelectionPayload) {
4939
+ persistedSelectionRaw = null
4940
+ }
4941
+ const originalHasPersistedSelection = Boolean(persistedSelectionPayload)
4854
4942
  const skipPersistedSelection = ignorePersistedSelection
4855
4943
  let hasPersistedSelection = skipPersistedSelection ? false : originalHasPersistedSelection
4856
4944
  if (skipPersistedSelection) {
4857
4945
  persistedSelectionRaw = null
4946
+ persistedSelectionPayload = null
4858
4947
  }
4859
4948
 
4949
+ const triggeredByUser = Boolean(eventParam || explicitTarget)
4950
+ let resolvedByGlobalSelector = false
4951
+
4860
4952
  let target = explicitTarget
4861
4953
  let preselected = null
4862
4954
 
@@ -4869,22 +4961,22 @@ body.dark {
4869
4961
  if (candidate) {
4870
4962
  target = candidate
4871
4963
  global_selector = null
4964
+ resolvedByGlobalSelector = true
4872
4965
  } else {
4873
4966
  scheduleSelectionRetry()
4874
4967
  return
4875
4968
  }
4876
4969
  }
4877
4970
 
4971
+ console.log({ target, skipPersistedSelection })
4878
4972
  if (!target && !skipPersistedSelection) {
4879
4973
  preselected = document.querySelector('#devtab.frame-link.selected') || document.querySelector('.frame-link.selected')
4880
- if (preselected) {
4881
- target = preselected
4882
- }
4974
+ console.log({ preselected })
4883
4975
  }
4884
4976
 
4885
- if (!target && persistedSelectionRaw) {
4886
- target = restorePersistedFrameLink()
4887
- if (!target && persistedSelectionRaw) {
4977
+ if (!target && persistedSelectionPayload) {
4978
+ target = restorePersistedFrameLink(persistedSelectionPayload)
4979
+ if (!target && originalHasPersistedSelection) {
4888
4980
  scheduleSelectionRetry()
4889
4981
  return
4890
4982
  }
@@ -4898,11 +4990,18 @@ body.dark {
4898
4990
  }
4899
4991
  }
4900
4992
 
4901
- if (!target && skipPersistedSelection) {
4993
+ const devTab = document.querySelector('#devtab.frame-link')
4994
+ if (!triggeredByUser && !resolvedByGlobalSelector && !target && devRouteActive && devTab) {
4995
+ target = devTab
4996
+ } else if (!target && preselected) {
4997
+ target = preselected
4998
+ }
4999
+
5000
+ if (!target) {
4902
5001
  const defaultSelection = document.querySelector("[data-default]")
4903
5002
  if (defaultSelection) {
4904
5003
  target = defaultSelection
4905
- } else {
5004
+ } else if (skipPersistedSelection) {
4906
5005
  scheduleSelectionRetry()
4907
5006
  return
4908
5007
  }
@@ -4939,6 +5038,12 @@ body.dark {
4939
5038
  }
4940
5039
  <% } %>
4941
5040
 
5041
+ if (!target && preselected) {
5042
+ target = preselected
5043
+ }
5044
+
5045
+ console.log({ targetAfter: target })
5046
+
4942
5047
  if (!target) {
4943
5048
  target = document.querySelector(".frame-link")
4944
5049
  }
@@ -5239,7 +5344,7 @@ body.dark {
5239
5344
  item.href = url
5240
5345
  item.setAttribute("data-index", index)
5241
5346
  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>`
5347
+ 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
5348
 
5244
5349
  document.querySelector(".temp-menu").appendChild(item)
5245
5350
 
@@ -5920,7 +6025,7 @@ body.dark {
5920
6025
  })
5921
6026
  setupTabLinkHover()
5922
6027
  document.addEventListener("click", (event) => {
5923
- if (event.target.closest("#fs-status .fs-dropdown-menu")) {
6028
+ if (event.target.closest("#fs-status .fs-dropdown-menu") || event.target.closest("#fs-status .fs-status-btn")) {
5924
6029
  return
5925
6030
  }
5926
6031
  closeStatusDropdowns()
@@ -6409,6 +6514,7 @@ body.dark {
6409
6514
 
6410
6515
  const detachHandlers = () => {
6411
6516
  forkBtn.removeEventListener('click', handlePushLogin)
6517
+ forkBtn.removeEventListener('click', requireGitLogin)
6412
6518
  }
6413
6519
 
6414
6520
  const enableDropdown = () => {
@@ -6419,7 +6525,11 @@ body.dark {
6419
6525
  const disableDropdown = () => {
6420
6526
  forkBtn.classList.remove('revealer')
6421
6527
  forkBtn.removeAttribute('data-group')
6422
- closeStatusDropdowns()
6528
+ const forkMenuEl = document.querySelector('#fs-fork-menu')
6529
+ if (forkMenuEl && !forkMenuEl.classList.contains('hidden')) {
6530
+ forkMenuEl.classList.add('hidden')
6531
+ }
6532
+ setDropdownState(forkBtn, false)
6423
6533
  }
6424
6534
 
6425
6535
  detachHandlers()
@@ -6435,12 +6545,12 @@ body.dark {
6435
6545
  if (!isConnected) {
6436
6546
  disableDropdown()
6437
6547
  if (labelEl) {
6438
- labelEl.textContent = 'Login'
6548
+ labelEl.textContent = 'Fork'
6439
6549
  }
6440
6550
  forkBtn.disabled = false
6441
6551
  forkBtn.classList.remove('fs-status-btn--disabled')
6442
- forkBtn.setAttribute('title', 'Connect GitHub to fork this workspace')
6443
- forkBtn.addEventListener('click', handlePushLogin)
6552
+ forkBtn.setAttribute('title', 'Log in to GitHub to fork this workspace')
6553
+ forkBtn.addEventListener('click', requireGitLogin)
6444
6554
  return
6445
6555
  }
6446
6556
 
@@ -8148,6 +8258,41 @@ body.dark {
8148
8258
  function handlePushLogin() {
8149
8259
  window.location.href = '/github'
8150
8260
  }
8261
+ const promptGitLogin = () => {
8262
+ Swal.fire({
8263
+ html: `
8264
+ <div class="pinokio-github-login">
8265
+ <div class="pinokio-github-login__icon"><i class="fa-brands fa-github"></i></div>
8266
+ <div class="pinokio-github-login__title">Log in to GitHub</div>
8267
+ <div class="pinokio-github-login__body">Connect your GitHub account to fork or publish this workspace.</div>
8268
+ </div>
8269
+ `,
8270
+ showCancelButton: true,
8271
+ confirmButtonText: 'Log in',
8272
+ cancelButtonText: 'Not now',
8273
+ reverseButtons: true,
8274
+ showCloseButton: true,
8275
+ focusConfirm: true,
8276
+ customClass: {
8277
+ popup: 'pinokio-modern-modal pinokio-github-login-modal',
8278
+ htmlContainer: 'pinokio-modern-html',
8279
+ confirmButton: 'pinokio-modern-confirm',
8280
+ cancelButton: 'pinokio-modern-cancel',
8281
+ closeButton: 'pinokio-modern-close'
8282
+ }
8283
+ }).then((result) => {
8284
+ if (result.isConfirmed) {
8285
+ handlePushLogin()
8286
+ }
8287
+ })
8288
+ }
8289
+ const requireGitLogin = (event) => {
8290
+ if (event) {
8291
+ event.preventDefault()
8292
+ event.stopPropagation()
8293
+ }
8294
+ promptGitLogin()
8295
+ }
8151
8296
 
8152
8297
  // Function to update publish/create button
8153
8298
  const updatePublishButton = async () => {
@@ -8167,6 +8312,7 @@ body.dark {
8167
8312
  pushBtn.removeEventListener('click', showPublishModal)
8168
8313
  pushBtn.removeEventListener('click', showCreateModal)
8169
8314
  pushBtn.removeEventListener('click', handlePushLogin)
8315
+ pushBtn.removeEventListener('click', requireGitLogin)
8170
8316
  }
8171
8317
  const enableDropdown = () => {
8172
8318
  pushBtn.classList.add('revealer')
@@ -8175,7 +8321,11 @@ body.dark {
8175
8321
  const disableDropdown = () => {
8176
8322
  pushBtn.classList.remove('revealer')
8177
8323
  pushBtn.removeAttribute('data-group')
8178
- closeStatusDropdowns()
8324
+ const pushMenuEl = document.querySelector('#fs-push-menu')
8325
+ if (pushMenuEl && !pushMenuEl.classList.contains('hidden')) {
8326
+ pushMenuEl.classList.add('hidden')
8327
+ }
8328
+ setDropdownState(pushBtn, false)
8179
8329
  }
8180
8330
 
8181
8331
  const repos = getRepoListSnapshot()
@@ -8227,12 +8377,12 @@ body.dark {
8227
8377
  renderPublishDropdown(repos, { emptyMessage })
8228
8378
 
8229
8379
  if (!isConnected) {
8230
- setLabel('Login')
8380
+ setLabel('Publish')
8231
8381
  pushBtn.disabled = false
8232
8382
  pushBtn.classList.remove('fs-status-btn--disabled')
8233
- pushBtn.setAttribute('title', 'Connect GitHub to publish this workspace')
8383
+ pushBtn.setAttribute('title', 'Log in to GitHub to publish this workspace')
8234
8384
  disableDropdown()
8235
- pushBtn.addEventListener('click', handlePushLogin)
8385
+ pushBtn.addEventListener('click', requireGitLogin)
8236
8386
  syncForkButton()
8237
8387
  return
8238
8388
  }
@@ -8266,12 +8416,12 @@ body.dark {
8266
8416
  } catch (error) {
8267
8417
  console.error('Error checking remotes:', error)
8268
8418
  setPublishMenuMessage('Git integration unavailable')
8269
- setLabel('Login')
8419
+ setLabel('Publish')
8270
8420
  pushBtn.disabled = false
8271
8421
  pushBtn.classList.remove('fs-status-btn--disabled')
8272
- pushBtn.setAttribute('title', 'Connect GitHub to publish this workspace')
8422
+ pushBtn.setAttribute('title', 'Log in to GitHub to publish this workspace')
8273
8423
  disableDropdown()
8274
- pushBtn.addEventListener('click', handlePushLogin)
8424
+ pushBtn.addEventListener('click', requireGitLogin)
8275
8425
  latestGitIntegration = null
8276
8426
  updateForkButton()
8277
8427
  }
@@ -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) { %>