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