pinokiod 3.51.0 → 3.53.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.
Files changed (117) hide show
  1. package/kernel/gitconfig_template +3 -1
  2. package/kernel/index.js +65 -43
  3. package/kernel/peer.js +21 -8
  4. package/kernel/router/index.js +10 -10
  5. package/kernel/router/localhost_static_router.js +3 -0
  6. package/kernel/router/peer_static_router.js +1 -0
  7. package/kernel/scripts/git/create +1 -2
  8. package/kernel/scripts/git/push +1 -1
  9. package/package.json +6 -2
  10. package/server/index.js +178 -87
  11. package/server/public/common.js +0 -13
  12. package/server/public/serve/directory.html +106 -0
  13. package/server/public/serve/icons/application_xp.png +0 -0
  14. package/server/public/serve/icons/application_xp_terminal.png +0 -0
  15. package/server/public/serve/icons/box.png +0 -0
  16. package/server/public/serve/icons/cd.png +0 -0
  17. package/server/public/serve/icons/controller.png +0 -0
  18. package/server/public/serve/icons/drive.png +0 -0
  19. package/server/public/serve/icons/film.png +0 -0
  20. package/server/public/serve/icons/folder.png +0 -0
  21. package/server/public/serve/icons/font.png +0 -0
  22. package/server/public/serve/icons/image.png +0 -0
  23. package/server/public/serve/icons/map.png +0 -0
  24. package/server/public/serve/icons/page.png +0 -0
  25. package/server/public/serve/icons/page_add.png +0 -0
  26. package/server/public/serve/icons/page_attach.png +0 -0
  27. package/server/public/serve/icons/page_code.png +0 -0
  28. package/server/public/serve/icons/page_copy.png +0 -0
  29. package/server/public/serve/icons/page_delete.png +0 -0
  30. package/server/public/serve/icons/page_edit.png +0 -0
  31. package/server/public/serve/icons/page_error.png +0 -0
  32. package/server/public/serve/icons/page_excel.png +0 -0
  33. package/server/public/serve/icons/page_find.png +0 -0
  34. package/server/public/serve/icons/page_gear.png +0 -0
  35. package/server/public/serve/icons/page_go.png +0 -0
  36. package/server/public/serve/icons/page_green.png +0 -0
  37. package/server/public/serve/icons/page_key.png +0 -0
  38. package/server/public/serve/icons/page_lightning.png +0 -0
  39. package/server/public/serve/icons/page_link.png +0 -0
  40. package/server/public/serve/icons/page_paintbrush.png +0 -0
  41. package/server/public/serve/icons/page_paste.png +0 -0
  42. package/server/public/serve/icons/page_red.png +0 -0
  43. package/server/public/serve/icons/page_refresh.png +0 -0
  44. package/server/public/serve/icons/page_save.png +0 -0
  45. package/server/public/serve/icons/page_white.png +0 -0
  46. package/server/public/serve/icons/page_white_acrobat.png +0 -0
  47. package/server/public/serve/icons/page_white_actionscript.png +0 -0
  48. package/server/public/serve/icons/page_white_add.png +0 -0
  49. package/server/public/serve/icons/page_white_c.png +0 -0
  50. package/server/public/serve/icons/page_white_camera.png +0 -0
  51. package/server/public/serve/icons/page_white_cd.png +0 -0
  52. package/server/public/serve/icons/page_white_code.png +0 -0
  53. package/server/public/serve/icons/page_white_code_red.png +0 -0
  54. package/server/public/serve/icons/page_white_coldfusion.png +0 -0
  55. package/server/public/serve/icons/page_white_compressed.png +0 -0
  56. package/server/public/serve/icons/page_white_copy.png +0 -0
  57. package/server/public/serve/icons/page_white_cplusplus.png +0 -0
  58. package/server/public/serve/icons/page_white_csharp.png +0 -0
  59. package/server/public/serve/icons/page_white_cup.png +0 -0
  60. package/server/public/serve/icons/page_white_database.png +0 -0
  61. package/server/public/serve/icons/page_white_delete.png +0 -0
  62. package/server/public/serve/icons/page_white_dvd.png +0 -0
  63. package/server/public/serve/icons/page_white_edit.png +0 -0
  64. package/server/public/serve/icons/page_white_error.png +0 -0
  65. package/server/public/serve/icons/page_white_excel.png +0 -0
  66. package/server/public/serve/icons/page_white_find.png +0 -0
  67. package/server/public/serve/icons/page_white_flash.png +0 -0
  68. package/server/public/serve/icons/page_white_freehand.png +0 -0
  69. package/server/public/serve/icons/page_white_gear.png +0 -0
  70. package/server/public/serve/icons/page_white_get.png +0 -0
  71. package/server/public/serve/icons/page_white_go.png +0 -0
  72. package/server/public/serve/icons/page_white_h.png +0 -0
  73. package/server/public/serve/icons/page_white_horizontal.png +0 -0
  74. package/server/public/serve/icons/page_white_key.png +0 -0
  75. package/server/public/serve/icons/page_white_lightning.png +0 -0
  76. package/server/public/serve/icons/page_white_link.png +0 -0
  77. package/server/public/serve/icons/page_white_magnify.png +0 -0
  78. package/server/public/serve/icons/page_white_medal.png +0 -0
  79. package/server/public/serve/icons/page_white_office.png +0 -0
  80. package/server/public/serve/icons/page_white_paint.png +0 -0
  81. package/server/public/serve/icons/page_white_paintbrush.png +0 -0
  82. package/server/public/serve/icons/page_white_paste.png +0 -0
  83. package/server/public/serve/icons/page_white_php.png +0 -0
  84. package/server/public/serve/icons/page_white_picture.png +0 -0
  85. package/server/public/serve/icons/page_white_powerpoint.png +0 -0
  86. package/server/public/serve/icons/page_white_put.png +0 -0
  87. package/server/public/serve/icons/page_white_ruby.png +0 -0
  88. package/server/public/serve/icons/page_white_stack.png +0 -0
  89. package/server/public/serve/icons/page_white_star.png +0 -0
  90. package/server/public/serve/icons/page_white_swoosh.png +0 -0
  91. package/server/public/serve/icons/page_white_text.png +0 -0
  92. package/server/public/serve/icons/page_white_text_width.png +0 -0
  93. package/server/public/serve/icons/page_white_tux.png +0 -0
  94. package/server/public/serve/icons/page_white_vector.png +0 -0
  95. package/server/public/serve/icons/page_white_visualstudio.png +0 -0
  96. package/server/public/serve/icons/page_white_width.png +0 -0
  97. package/server/public/serve/icons/page_white_word.png +0 -0
  98. package/server/public/serve/icons/page_white_world.png +0 -0
  99. package/server/public/serve/icons/page_white_wrench.png +0 -0
  100. package/server/public/serve/icons/page_white_zip.png +0 -0
  101. package/server/public/serve/icons/page_word.png +0 -0
  102. package/server/public/serve/icons/page_world.png +0 -0
  103. package/server/public/serve/style.css +308 -0
  104. package/server/public/style.css +13 -5
  105. package/server/public/urldropdown.css +95 -3
  106. package/server/public/urldropdown.js +245 -23
  107. package/server/serveIndex.js +691 -0
  108. package/server/views/app.ejs +305 -89
  109. package/server/views/connect.ejs +3 -0
  110. package/server/views/container.ejs +2 -1
  111. package/server/views/index.ejs +3 -0
  112. package/server/views/init/index.ejs +3 -0
  113. package/server/views/net.ejs +30 -27
  114. package/server/views/network.ejs +23 -70
  115. package/server/views/screenshots.ejs +3 -0
  116. package/server/views/settings.ejs +3 -0
  117. package/server/views/tools.ejs +3 -0
@@ -847,11 +847,16 @@ body.dark #fs-status {
847
847
  background: rgba(0,0,0,0.04);
848
848
  gap: 5px;
849
849
  box-sizing: border-box;
850
+ /*
850
851
  margin: 0 10px;
852
+ */
851
853
  padding: 5px;
852
854
  display: flex;
853
855
  align-items: center;
856
+ /*
854
857
  border-radius: 6px;
858
+ */
859
+ justify-content: flex-end;
855
860
  }
856
861
 
857
862
  .fs-status-btn {
@@ -860,7 +865,7 @@ body.dark #fs-status {
860
865
  padding: 8px 12px;
861
866
  cursor: pointer;
862
867
  border-radius: 4px;
863
- display: flex;
868
+ display: flex !important;
864
869
  align-items: center;
865
870
  gap: 8px;
866
871
  font-size: 14px;
@@ -895,6 +900,39 @@ body.dark .fs-status-btn:hover {
895
900
  text-align: center;
896
901
  }
897
902
 
903
+ /* Publish modal styles */
904
+ .publish-modal-container {
905
+ padding: 0 !important;
906
+ margin: 0 !important;
907
+ }
908
+
909
+ /* Remote selection modal styles */
910
+ .swal2-html-container select,
911
+ .swal2-html-container input[type="text"] {
912
+ font-family: inherit;
913
+ }
914
+
915
+ body.dark .swal2-html-container select,
916
+ body.dark .swal2-html-container input[type="text"] {
917
+ background: rgba(255, 255, 255, 0.1);
918
+ color: white;
919
+ border-color: rgba(255, 255, 255, 0.3);
920
+ }
921
+
922
+ body.dark .swal2-html-container option {
923
+ background: #2d3748;
924
+ color: white;
925
+ }
926
+
927
+ /* Checkbox styling for dark mode */
928
+ body.dark .swal2-html-container input[type="checkbox"] {
929
+ accent-color: #4a90e2;
930
+ }
931
+
932
+ body.dark .swal2-html-container label {
933
+ color: white;
934
+ }
935
+
898
936
  /* Git diff modal styles - using specific prefixed classes to avoid collisions */
899
937
  .pinokio-git-diff-modal-wrapper {
900
938
  width: 90vw !important;
@@ -1147,16 +1185,16 @@ body.dark .pinokio-commit-message-input:focus {
1147
1185
  }
1148
1186
 
1149
1187
  .pinokio-save-version-btn {
1150
- background: #1f883d;
1151
- color: white;
1152
- border: 1px solid rgba(31, 35, 40, 0.15);
1153
- border-radius: 6px;
1154
- padding: 8px 16px;
1155
- font-size: 14px;
1156
- font-weight: 500;
1157
- cursor: pointer;
1158
- transition: background-color 0.2s;
1159
- white-space: nowrap;
1188
+ background: #1f883d !important;
1189
+ color: white !important;
1190
+ border: 1px solid rgba(31, 35, 40, 0.15) !important;
1191
+ border-radius: 6px !important;
1192
+ padding: 8px 16px !important;
1193
+ font-size: 14px !important;
1194
+ font-weight: 500 !important;
1195
+ cursor: pointer !important;
1196
+ transition: background-color 0.2s !important;
1197
+ white-space: nowrap !important;
1160
1198
  }
1161
1199
 
1162
1200
  .pinokio-save-version-btn:hover {
@@ -1669,6 +1707,9 @@ body.minimized {
1669
1707
  body.minimized aside {
1670
1708
  display: none;
1671
1709
  }
1710
+ body.minimized #fs-status {
1711
+ padding-left: 55px;
1712
+ }
1672
1713
  @media only screen and (max-width: 800px) {
1673
1714
  .mode-selector .btn2 {
1674
1715
  width: unset;
@@ -1792,8 +1833,6 @@ body.minimized aside {
1792
1833
  <div class='app-info-card'>
1793
1834
  <% if (config.icon) { %>
1794
1835
  <img src="<%=config.icon%>" onerror="this.src='/pinokio-black.png'"/>
1795
- <% } else { %>
1796
- <i class="fa-regular fa-circle-dot"></i>
1797
1836
  <% } %>
1798
1837
  <div class='app-info-container'>
1799
1838
  <div class='app-info-title'><%=config.title%></div>
@@ -1941,13 +1980,16 @@ body.minimized aside {
1941
1980
 
1942
1981
  <div class='container'>
1943
1982
  <% if (type === "browse") { %>
1944
- <div id='fs-status' data-history-uri="<%=git_history_url%>" data-uri="<%=git_monitor_url%>">
1983
+ <div id='fs-status' data-create-uri="<%=git_create_url%>" data-history-uri="<%=git_history_url%>" data-uri="<%=git_monitor_url%>" data-push-uri="<%=git_push_url%>">
1945
1984
  <button id='fs-changes-btn' class='fs-status-btn'>
1946
- <span>Changes</span>
1985
+ <span><i class="fa-solid fa-code-compare"></i> Changes</span>
1947
1986
  <div class='badge'>loading...</div>
1948
1987
  </button>
1949
1988
  <button id='fs-history-btn' class='fs-status-btn'>
1950
- <span>History</span>
1989
+ <span><i class="fa-solid fa-clock-rotate-left"></i> History</span>
1990
+ </button>
1991
+ <button id='fs-push-btn' class='fs-status-btn'>
1992
+ <span><i class="fa-brands fa-github"></i> Publish</span>
1951
1993
  </button>
1952
1994
  </div>
1953
1995
  <% } %>
@@ -1968,12 +2010,10 @@ body.minimized aside {
1968
2010
  // Try to access the iframe's document
1969
2011
  const currentSrc = iframe.src
1970
2012
  // Check if it's a chrome error page or empty
1971
- console.log({ currentSrc, originalSrc })
1972
2013
  if (currentSrc !== originalSrc &&
1973
2014
  (currentSrc.includes('chrome-error://') ||
1974
2015
  currentSrc === 'about:blank' ||
1975
2016
  currentSrc.includes('data:'))) {
1976
- console.log('Iframe failed to load, switching to fallback');
1977
2017
  iframeDoc.classList.add("hidden")
1978
2018
  Swal.fire({
1979
2019
  html: `<i class="fa-solid fa-circle-notch fa-spin"></i> Loading...`,
@@ -1985,9 +2025,7 @@ body.minimized aside {
1985
2025
  actions: "hidden"
1986
2026
  }
1987
2027
  });
1988
- console.log("retrying after 3 seconds")
1989
2028
  setTimeout(() => {
1990
- console.log("retrying")
1991
2029
  iframe.src = iframe.src
1992
2030
  }, 3000)
1993
2031
  }
@@ -1995,7 +2033,6 @@ body.minimized aside {
1995
2033
  iframe.classList.add("hidden")
1996
2034
  // Cross-origin restriction - assume it loaded successfully
1997
2035
  // if no error was thrown during the initial load
1998
- console.log("ERROR", e)
1999
2036
  Swal.fire({
2000
2037
  html: `<i class="fa-solid fa-circle-notch fa-spin"></i> Loading...`,
2001
2038
  customClass: {
@@ -2145,11 +2182,8 @@ body.minimized aside {
2145
2182
  if (selection && selection.href) {
2146
2183
  let selection_protocol = new URL(selection.href).protocol
2147
2184
  let page_protocol = new URL(location.href).protocol
2148
- console.log({ selection_protocol, page_protocol })
2149
2185
  if (selection_protocol !== page_protocol) {
2150
- console.log({ timeout_id })
2151
2186
  if (!timeout_id) {
2152
- console.log("Retrying in 3 seconds")
2153
2187
  Swal.fire({
2154
2188
  html: `<i class="fa-solid fa-circle-notch fa-spin"></i> Loading...`,
2155
2189
  customClass: {
@@ -2168,10 +2202,8 @@ body.minimized aside {
2168
2202
  }
2169
2203
  }
2170
2204
  <% } %>
2171
- console.log("renderSelection", global_selector)
2172
2205
  if (global_selector) {
2173
2206
  selection = document.querySelector(global_selector)
2174
- console.log("selection", selection)
2175
2207
  global_selector = null
2176
2208
  }
2177
2209
  if (selection || location.hash && location.hash.length > 0) {
@@ -2185,7 +2217,6 @@ body.minimized aside {
2185
2217
  } else {
2186
2218
  let type = id[0]
2187
2219
  let index = id.slice(1)
2188
- console.log({ type, index })
2189
2220
  selector = `aside .${type} [data-index='${index}']`
2190
2221
  }
2191
2222
  if (e) {
@@ -2279,7 +2310,6 @@ body.minimized aside {
2279
2310
  let hardFrames = document.querySelectorAll(".browserview iframe[name^='@']")
2280
2311
  let port = new URL(target.href).port || 80
2281
2312
  for(let frame of hardFrames) {
2282
- console.log({ src: frame.src, href: target.href, target: target.target })
2283
2313
  // Types of links in the tab
2284
2314
  //if (String(port) === "<%=port%>") {
2285
2315
  if (String(port) === String(location.port) || /https:\/\/pinokio\..*localhost/.test(origin)) {
@@ -2290,7 +2320,6 @@ body.minimized aside {
2290
2320
  if (targetPath === framePath) {
2291
2321
  let beforeName = frame.name
2292
2322
  frame.name = target.target
2293
- console.log("SET FRAME", { before: beforeName, after: frame.name, target: target.target })
2294
2323
  targetFrame = frame
2295
2324
  break
2296
2325
  }
@@ -2472,14 +2501,12 @@ body.minimized aside {
2472
2501
  // loaded[target.target] = true
2473
2502
  // }
2474
2503
  } else {
2475
- console.log("# 13")
2476
2504
  // couldn't find item,
2477
2505
  // clear the hash
2478
2506
  //
2479
2507
  location.hash = ""
2480
2508
  }
2481
2509
  } else {
2482
- console.log("# 14")
2483
2510
  document.querySelector(".container").classList.remove("active")
2484
2511
  document.querySelector("aside").classList.add("active")
2485
2512
 
@@ -2506,8 +2533,6 @@ body.minimized aside {
2506
2533
 
2507
2534
 
2508
2535
  // persist
2509
- console.log("sync tabs", tabs)
2510
-
2511
2536
  await fetch("/pinokio/tabs", {
2512
2537
  method: "POST",
2513
2538
  headers: {
@@ -2810,7 +2835,10 @@ body.minimized aside {
2810
2835
  let script = target.closest("[data-script]")
2811
2836
  if (script) {
2812
2837
  let script_id = script.getAttribute("data-script")
2813
- target.querySelector("i.fa-square").className = "fa-solid fa-check"
2838
+ try {
2839
+ target.querySelector("i.fa-square").className = "fa-solid fa-check"
2840
+ } catch (e) {
2841
+ }
2814
2842
  n.Noty({
2815
2843
  text: `stopping script`,
2816
2844
  silent: true,
@@ -2824,14 +2852,18 @@ body.minimized aside {
2824
2852
  id: script_id
2825
2853
  }
2826
2854
  }, (packet) => {
2855
+ debugger
2827
2856
  if (packet.type === "result") {
2857
+ console.log("is result")
2828
2858
  socket.close()
2859
+ debugger
2829
2860
  n.Noty({
2830
2861
  timeout: 2000,
2831
2862
  text: `stopped`,
2832
2863
  silent: true
2833
2864
  })
2834
2865
  console.log("Refresh 4")
2866
+ debugger
2835
2867
  refresh(true)
2836
2868
  }
2837
2869
  })
@@ -2985,7 +3017,6 @@ body.minimized aside {
2985
3017
 
2986
3018
  })
2987
3019
  const refresh_du = (path) => {
2988
- console.log("REFRESH DU")
2989
3020
  let url = path ? `/du/<%=name%>/${path}` : `/du/<%=name%>`
2990
3021
  let selector = `.disk-usage[data-path='/${path || ""}']`
2991
3022
  let el = document.querySelector(selector)
@@ -3007,7 +3038,6 @@ body.minimized aside {
3007
3038
  // KB
3008
3039
  val = `${Math.floor(res.du/k * 100) / 100} KB`
3009
3040
  }
3010
- console.log("DU VAL", val)
3011
3041
  el.innerHTML = val
3012
3042
  } else {
3013
3043
  }
@@ -3018,14 +3048,12 @@ body.minimized aside {
3018
3048
  let dynamic_loaded = false
3019
3049
 
3020
3050
  const try_dynamic = async () => {
3021
- console.log("Try_dynamic")
3022
3051
  let rendered
3023
3052
  let status
3024
3053
  const dynamic = await fetch("<%=dynamic%>").then((res) => {
3025
3054
  status = res.status
3026
3055
  return res.text()
3027
3056
  })
3028
- console.log("STatus", status)
3029
3057
  if (status == 500) {
3030
3058
  ModalInput({
3031
3059
  description: dynamic,
@@ -3038,7 +3066,6 @@ body.minimized aside {
3038
3066
  return
3039
3067
  }
3040
3068
  if (dynamic && dynamic.length > 0) {
3041
- console.log({ dynamic })
3042
3069
  if (document.querySelector(".dynamic .submenu")) {
3043
3070
  document.querySelector(".dynamic .submenu").innerHTML = dynamic
3044
3071
  }
@@ -3046,7 +3073,6 @@ body.minimized aside {
3046
3073
  } else {
3047
3074
  rendered = false
3048
3075
  }
3049
- console.log({ rendered, dynamic_loaded })
3050
3076
  if (rendered) {
3051
3077
  // if (dynamic_loaded) {
3052
3078
  // // already loaded, don't touch the UI
@@ -3060,7 +3086,6 @@ body.minimized aside {
3060
3086
  // }
3061
3087
  // }
3062
3088
  } else {
3063
- console.log("Not yet rendered. Try again")
3064
3089
  setTimeout(() => {
3065
3090
  try_dynamic()
3066
3091
  }, 1000)
@@ -3082,7 +3107,6 @@ body.minimized aside {
3082
3107
  status = res.status
3083
3108
  return res.text()
3084
3109
  })
3085
- console.log({ status })
3086
3110
  if (status == 500) {
3087
3111
  ModalInput({
3088
3112
  description: html,
@@ -3132,7 +3156,6 @@ body.minimized aside {
3132
3156
  fetch("/pinokio/log", {
3133
3157
  method: "post",
3134
3158
  }).then((res) => {
3135
- console.log("RES", res)
3136
3159
  let btn = document.querySelector("#genlog")
3137
3160
  let btn2 = document.querySelector("#downloadlogs")
3138
3161
  btn2.classList.remove("hidden")
@@ -3146,36 +3169,23 @@ body.minimized aside {
3146
3169
  if (init) {
3147
3170
  init.click()
3148
3171
  }
3149
- /*
3150
- window.addEventListener("hashchange", function () {
3151
- console.log("Hash changed:", location.hash);
3152
- location.reload()
3153
- });
3154
- */
3155
3172
  window.addEventListener('message', (event) => {
3156
3173
 
3157
3174
  // only process the event it's coming from pinokio
3158
3175
  let origin = event.origin
3159
- console.log("origin", origin)
3160
3176
  if (origin) {
3161
3177
  let port = new URL(origin).port || 80
3162
- console.log("port", port)
3163
3178
  if (String(port) === String(location.port) || /https:\/\/pinokio\..*localhost/.test(origin)) {
3164
3179
  //if (String(port) === "<%=port%>" || /https:\/\/pinokio\..*localhost/.test(origin)) {
3165
3180
  //if (String(port) === "<%=port%>") {
3166
- console.log("Message received from the child: ", event); // Message received from child
3167
3181
  if (event.data) {
3168
3182
  if (event.data.action) {
3169
3183
  if (event.data.action.type === "newtab") {
3170
- console.log("create tab", event.data.action.url)
3171
3184
  addTab(event.data.action.url)
3172
3185
  } else if (event.data.action.type === "title") {
3173
3186
  console.log("title", event.data)
3174
3187
  } else if (event.data.action.type === "location") {
3175
- console.log("EVENT", event)
3176
3188
  let url = event.data.action.url
3177
- console.log({ action: event.data.action })
3178
-
3179
3189
  //document.querySelector("#location").value = url
3180
3190
  let pathname = new URL(url).pathname
3181
3191
  if (pathname.startsWith("/run")) {
@@ -3185,7 +3195,6 @@ body.minimized aside {
3185
3195
  }
3186
3196
  }
3187
3197
  } else if (event.data.launch) {
3188
- debugger
3189
3198
  global_selector = `.frame-link[target="${event.data.launch.name}"]`
3190
3199
  let s = document.querySelector(global_selector)
3191
3200
  if (!s) {
@@ -3194,15 +3203,11 @@ body.minimized aside {
3194
3203
  refresh()
3195
3204
  } else if (event.data.type) {
3196
3205
  let asideHidden = (window.getComputedStyle(document.querySelector("aside")).display === "none")
3197
- console.log("asideHidden", asideHidden)
3198
3206
  if (!asideHidden) {
3199
3207
  // refresh only if aside
3200
- console.log("type", event.data.type)
3201
3208
  if (event.data.type === 'disconnect') {
3202
- console.log("Refresh 1")
3203
3209
  refresh()
3204
3210
  } else {
3205
- console.log("Refresh 2")
3206
3211
  refresh()
3207
3212
  }
3208
3213
  } else {
@@ -3214,7 +3219,6 @@ body.minimized aside {
3214
3219
  }
3215
3220
  }
3216
3221
  } else {
3217
- console.log("Refresh 3")
3218
3222
  refresh()
3219
3223
  }
3220
3224
  }
@@ -3227,14 +3231,12 @@ body.minimized aside {
3227
3231
  let frame_key = window.frameElement?.name || "";
3228
3232
 
3229
3233
  let selection_url = windowStorage.getItem(frame_key + ":url")
3230
- console.log({ frame_key, selection_url })
3231
3234
  let selection
3232
3235
  if (selection_url) {
3233
3236
  selection = document.querySelector(`[href='${selection_url}']`)
3234
3237
  } else {
3235
3238
  selection = document.querySelector("#devtab")
3236
3239
  }
3237
- console.log("CLICK", selection)
3238
3240
  if (selection) {
3239
3241
  // setTimeout(() => {
3240
3242
  selection.click()
@@ -3256,10 +3258,8 @@ body.minimized aside {
3256
3258
  /*
3257
3259
  document.addEventListener("keydown", (e) => {
3258
3260
  let size = document.querySelectorAll(".selectable").length
3259
- console.log("size", size)
3260
3261
  e = e || window.event;
3261
3262
  if (e.key === "ArrowUp") {
3262
- console.log("up arrow pressed");
3263
3263
  if (cursorIndex > 0) {
3264
3264
  cursorIndex--;
3265
3265
  } else {
@@ -3276,7 +3276,6 @@ body.minimized aside {
3276
3276
  cursorIndex = 0;
3277
3277
  }
3278
3278
  //renderCursor()
3279
- console.log("down arrow pressed");
3280
3279
  //let cursor = document.querySelector(".selectable.cursor")
3281
3280
  //cursor.scrollIntoView(false)
3282
3281
  } else if (e.key === "Enter") {
@@ -3295,24 +3294,24 @@ body.minimized aside {
3295
3294
  let gitCommitUrl = null
3296
3295
 
3297
3296
  const check_git = () => {
3298
- console.log('check_git called, fetching from:', "<%=git_monitor_url%>")
3299
3297
  fetch("<%=git_monitor_url%>").then((res) => {
3300
- console.log('check_git response status:', res.status)
3301
3298
  return res.json()
3302
3299
  }).then((res) => {
3303
- console.log('check_git response data:', res)
3304
3300
  currentChanges = res.changes || []
3305
3301
  gitCommitUrl = res.git_commit_url || null
3306
- console.log('currentChanges updated to:', currentChanges)
3302
+ const changesBtn = document.querySelector("#fs-changes-btn")
3307
3303
  const badgeElement = document.querySelector("#fs-changes-btn .badge")
3308
- console.log('Badge element found:', badgeElement)
3304
+
3309
3305
  if (res.changes && res.changes.length > 0) {
3310
- console.log('Setting badge to:', res.changes.length)
3306
+ // Show changes button and update badge
3307
+ changesBtn.style.display = 'block'
3311
3308
  badgeElement.innerHTML = `${res.changes.length}`
3312
3309
  } else {
3313
- console.log('Clearing badge')
3310
+ // Hide changes button when no changes
3311
+ changesBtn.style.display = 'none'
3314
3312
  badgeElement.innerHTML = ''
3315
3313
  }
3314
+ updatePublishButton()
3316
3315
  }).catch((error) => {
3317
3316
  console.error('check_git error:', error)
3318
3317
  })
@@ -3335,7 +3334,6 @@ body.minimized aside {
3335
3334
  }
3336
3335
 
3337
3336
  messageListener = (event) => {
3338
- console.log('Received postMessage:', event.data)
3339
3337
 
3340
3338
  // Check if event has callback data that starts with "$"
3341
3339
  if (event.data &&
@@ -3343,8 +3341,6 @@ body.minimized aside {
3343
3341
  typeof event.data.callback === 'string' &&
3344
3342
  event.data.callback.startsWith('$')) {
3345
3343
 
3346
- console.log('Callback starts with $, closing modal')
3347
-
3348
3344
  // Close the modal
3349
3345
  Swal.close()
3350
3346
 
@@ -3424,21 +3420,14 @@ body.minimized aside {
3424
3420
  }
3425
3421
 
3426
3422
  const showGitDiffModal = async (diffData = null, modalTitle = 'File Changes', showSaveButton = true) => {
3427
- console.log('showGitDiffModal called with:', { diffData, modalTitle, showSaveButton })
3428
- console.log('currentChanges:', currentChanges)
3429
-
3430
3423
  let changes = diffData ? (diffData.changes || []) : currentChanges
3431
3424
  let commitUrl = diffData ? (diffData.git_commit_url || null) : gitCommitUrl
3432
3425
 
3433
- console.log('Initial changes:', changes)
3434
-
3435
3426
  // If no diffData provided and currentChanges is empty, try to fetch fresh data
3436
3427
  if (!diffData && changes.length === 0) {
3437
- console.log('Fetching fresh data because changes is empty')
3438
3428
  try {
3439
3429
  const response = await fetch("<%=git_monitor_url%>")
3440
3430
  const freshData = await response.json()
3441
- console.log('Fresh data received:', freshData)
3442
3431
  changes = freshData.changes || []
3443
3432
  commitUrl = freshData.git_commit_url || null
3444
3433
  currentChanges = changes // Update the global variable
@@ -3448,10 +3437,8 @@ body.minimized aside {
3448
3437
  }
3449
3438
  }
3450
3439
 
3451
- console.log('Final changes before modal:', changes)
3452
3440
 
3453
3441
  if (changes.length === 0) {
3454
- console.log('No changes found - showing info dialog')
3455
3442
  Swal.fire({
3456
3443
  title: 'No Changes',
3457
3444
  text: 'No file changes detected.',
@@ -3460,8 +3447,6 @@ body.minimized aside {
3460
3447
  return
3461
3448
  }
3462
3449
 
3463
- console.log('About to show modal with changes:', changes.length)
3464
-
3465
3450
  const modalHtml = `
3466
3451
  <div class="pinokio-git-diff-main-container">
3467
3452
  <div class="pinokio-git-diff-file-list-panel">
@@ -3533,7 +3518,6 @@ body.minimized aside {
3533
3518
  }
3534
3519
 
3535
3520
  Swal.getPopup().addEventListener('message', (event) => {
3536
- console.log("EVENT", event)
3537
3521
  // if (event.data) {
3538
3522
  // if (event.data.callback) {
3539
3523
  // if (event.data.callback.startsWith("$")) {
@@ -3832,10 +3816,242 @@ body.minimized aside {
3832
3816
  `
3833
3817
  }
3834
3818
 
3819
+ const showPublishModal = () => {
3820
+ const pushUri = document.querySelector('#fs-status').getAttribute('data-push-uri')
3821
+ if (!pushUri) {
3822
+ Swal.fire({
3823
+ title: 'Error',
3824
+ text: 'Publish URL not available.',
3825
+ icon: 'error'
3826
+ })
3827
+ return
3828
+ }
3829
+
3830
+ Swal.fire({
3831
+ title: 'Publish to GitHub',
3832
+ html: `
3833
+ <div style="width: 100%; height: 400px; position: relative;">
3834
+ <iframe src="${pushUri}" style="width: 100%; height: 100%; border: none; border-radius: 8px;"></iframe>
3835
+ </div>
3836
+ `,
3837
+ width: '80%',
3838
+ showCloseButton: true,
3839
+ showConfirmButton: false,
3840
+ showCancelButton: true,
3841
+ cancelButtonText: 'Close',
3842
+ customClass: {
3843
+ htmlContainer: 'publish-modal-container'
3844
+ }
3845
+ })
3846
+ }
3847
+
3848
+ const showCreateModal = () => {
3849
+ showCreateRepoModal()
3850
+ }
3851
+
3852
+ const showRemoteSelectionModal = (remotes, pushUri) => {
3853
+ const defaultRemote = remotes.find(r => r.remote === 'origin') || remotes[0]
3854
+
3855
+ const remoteOptions = remotes.map(remote =>
3856
+ `<option value="${remote.remote}" ${remote.remote === defaultRemote.remote ? 'selected' : ''}>
3857
+ ${remote.remote} (${remote.url})
3858
+ </option>`
3859
+ ).join('')
3860
+
3861
+ Swal.fire({
3862
+ title: 'Publish to GitHub',
3863
+ html: `
3864
+ <div style="text-align: left; margin-bottom: 20px;">
3865
+ <label style="display: block; margin-bottom: 8px; font-weight: bold;">Select Remote:</label>
3866
+ <select id="remote-select" style="width: 100%; padding: 8px; border: 1px solid #ddd; border-radius: 4px; margin-bottom: 16px;">
3867
+ ${remoteOptions}
3868
+ </select>
3869
+
3870
+ <label style="display: block; margin-bottom: 8px; font-weight: bold;">Repository Name:</label>
3871
+ <input type="text" id="repo-name-input" placeholder="Enter repository name"
3872
+ style="width: 100%; padding: 8px; border: 1px solid #ddd; border-radius: 4px; box-sizing: border-box;">
3873
+ </div>
3874
+ `,
3875
+ showCloseButton: true,
3876
+ showConfirmButton: true,
3877
+ showCancelButton: true,
3878
+ confirmButtonText: 'Publish',
3879
+ cancelButtonText: 'Cancel',
3880
+ preConfirm: () => {
3881
+ const selectedRemote = document.getElementById('remote-select').value
3882
+ const repoName = document.getElementById('repo-name-input').value.trim()
3883
+
3884
+ if (!repoName) {
3885
+ Swal.showValidationMessage('Repository name is required')
3886
+ return false
3887
+ }
3888
+
3889
+ return { remote: selectedRemote, name: repoName }
3890
+ }
3891
+ }).then((result) => {
3892
+ if (result.isConfirmed) {
3893
+ const { remote, name } = result.value
3894
+ showFinalPublishModal(pushUri, remote, name)
3895
+ }
3896
+ })
3897
+ }
3898
+
3899
+ const showFinalPublishModal = (pushUri, remote, name) => {
3900
+ const urlParams = new URLSearchParams()
3901
+ urlParams.append('remote', remote)
3902
+ urlParams.append('name', name)
3903
+
3904
+ const finalUri = `${pushUri}${pushUri.includes('?') ? '&' : '?'}${urlParams.toString()}`
3905
+
3906
+ Swal.fire({
3907
+ title: 'Publish to GitHub',
3908
+ html: `
3909
+ <div style="width: 100%; height: 400px; position: relative;">
3910
+ <iframe src="${finalUri}" style="width: 100%; height: 100%; border: none; border-radius: 8px;"></iframe>
3911
+ </div>
3912
+ `,
3913
+ width: '80%',
3914
+ showCloseButton: true,
3915
+ showConfirmButton: false,
3916
+ showCancelButton: true,
3917
+ cancelButtonText: 'Close',
3918
+ customClass: {
3919
+ htmlContainer: 'publish-modal-container'
3920
+ }
3921
+ })
3922
+ }
3923
+
3924
+ const showCreateRepoModal = () => {
3925
+ Swal.fire({
3926
+ title: 'Create Repository on GitHub',
3927
+ html: `
3928
+ <div style="text-align: left; margin-bottom: 20px;">
3929
+ <label style="display: block; margin-bottom: 8px; font-weight: bold;">Repository Name:</label>
3930
+ <input type="text" id="create-repo-name-input" placeholder="Enter repository name"
3931
+ style="width: 100%; padding: 8px; border: 1px solid #ddd; border-radius: 4px; box-sizing: border-box; margin-bottom: 16px;">
3932
+
3933
+ <div style="display: flex; align-items: center; gap: 8px;">
3934
+ <input type="checkbox" id="private-checkbox" style="margin: 0;">
3935
+ <label for="private-checkbox" style="margin: 0; font-weight: normal;">Private repository</label>
3936
+ </div>
3937
+ </div>
3938
+ `,
3939
+ showCloseButton: true,
3940
+ showConfirmButton: true,
3941
+ showCancelButton: true,
3942
+ confirmButtonText: 'Create on GitHub',
3943
+ cancelButtonText: 'Cancel',
3944
+ preConfirm: () => {
3945
+ const repoName = document.getElementById('create-repo-name-input').value.trim()
3946
+ const isPrivate = document.getElementById('private-checkbox').checked
3947
+
3948
+ if (!repoName) {
3949
+ Swal.showValidationMessage('Repository name is required')
3950
+ return false
3951
+ }
3952
+
3953
+ return { name: repoName, isPrivate: isPrivate }
3954
+ }
3955
+ }).then((result) => {
3956
+ if (result.isConfirmed) {
3957
+ const { name, isPrivate } = result.value
3958
+ showCreateRepoIframeModal(name, isPrivate)
3959
+ }
3960
+ })
3961
+ }
3962
+
3963
+ const showCreateRepoIframeModal = (name, isPrivate) => {
3964
+ const createUri = document.querySelector('#fs-status').getAttribute('data-create-uri')
3965
+
3966
+ if (!createUri) {
3967
+ Swal.fire({
3968
+ title: 'Error',
3969
+ text: 'Create repository URL not available.',
3970
+ icon: 'error'
3971
+ })
3972
+ return
3973
+ }
3974
+
3975
+ const urlParams = new URLSearchParams()
3976
+ urlParams.append('name', name)
3977
+ urlParams.append('visibility', isPrivate ? 'private' : 'public')
3978
+
3979
+ const finalUri = `${createUri}${createUri.includes('?') ? '&' : '?'}${urlParams.toString()}`
3980
+
3981
+ Swal.fire({
3982
+ title: 'Create Repository on GitHub',
3983
+ html: `
3984
+ <div style="width: 100%; height: 400px; position: relative;">
3985
+ <iframe src="${finalUri}" style="width: 100%; height: 100%; border: none; border-radius: 8px;"></iframe>
3986
+ </div>
3987
+ `,
3988
+ width: '80%',
3989
+ showCloseButton: true,
3990
+ showConfirmButton: false,
3991
+ showCancelButton: true,
3992
+ cancelButtonText: 'Close',
3993
+ customClass: {
3994
+ htmlContainer: 'publish-modal-container'
3995
+ }
3996
+ })
3997
+ }
3998
+
3999
+ // Function to update publish/create button
4000
+ const updatePublishButton = async () => {
4001
+ const historyUri = document.querySelector('#fs-status').getAttribute('data-history-uri')
4002
+ const pushBtn = document.querySelector('#fs-push-btn')
4003
+
4004
+ if (!historyUri || !pushBtn) return
4005
+
4006
+ try {
4007
+ const response = await fetch(historyUri)
4008
+ const data = await response.json()
4009
+
4010
+ // Check if GitHub is connected
4011
+ if (!data.connected) {
4012
+ // Not logged in - show "Login" button
4013
+ pushBtn.innerHTML = '<span><i class="fa-brands fa-github"></i> Login</span>'
4014
+ pushBtn.removeEventListener('click', showPublishModal)
4015
+ pushBtn.removeEventListener('click', showCreateModal)
4016
+ pushBtn.addEventListener('click', () => {
4017
+ window.location.href = '/github'
4018
+ })
4019
+ return
4020
+ }
4021
+
4022
+ // GitHub is connected - show appropriate button based on remotes
4023
+ if (!data.remotes || data.remotes.length === 0) {
4024
+ // No remotes - show "Create" button
4025
+ pushBtn.innerHTML = '<span><i class="fa-brands fa-github"></i> Create</span>'
4026
+ pushBtn.removeEventListener('click', showPublishModal)
4027
+ pushBtn.removeEventListener('click', () => window.location.href = '/github')
4028
+ pushBtn.addEventListener('click', showCreateModal)
4029
+ } else {
4030
+ // Has remotes - show "Publish" button
4031
+ pushBtn.innerHTML = '<span><i class="fa-brands fa-github"></i> Publish</span>'
4032
+ pushBtn.removeEventListener('click', showCreateModal)
4033
+ pushBtn.removeEventListener('click', () => window.location.href = '/github')
4034
+ pushBtn.addEventListener('click', showPublishModal)
4035
+ }
4036
+ } catch (error) {
4037
+ console.error('Error checking remotes:', error)
4038
+ // Default to "Login" on error
4039
+ pushBtn.innerHTML = '<span><i class="fa-brands fa-github"></i> Login</span>'
4040
+ pushBtn.removeEventListener('click', showPublishModal)
4041
+ pushBtn.removeEventListener('click', showCreateModal)
4042
+ pushBtn.addEventListener('click', () => {
4043
+ window.location.href = '/github'
4044
+ })
4045
+ }
4046
+ }
4047
+
3835
4048
  // Add click handlers for the buttons
3836
4049
  document.querySelector('#fs-changes-btn').addEventListener('click', () => showGitDiffModal())
3837
4050
  document.querySelector('#fs-history-btn').addEventListener('click', showGitHistoryModal)
3838
4051
 
4052
+ // Initialize the publish/create button
4053
+ updatePublishButton()
4054
+
3839
4055
  check_git()
3840
4056
  setInterval(check_git, 10000)
3841
4057
  <% } %>