trident-git 0.2.0 → 0.2.2

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 (311) hide show
  1. package/.next/BUILD_ID +1 -0
  2. package/.next/app-path-routes-manifest.json +23 -0
  3. package/.next/build-manifest.json +20 -0
  4. package/.next/export-marker.json +6 -0
  5. package/.next/images-manifest.json +73 -0
  6. package/.next/next-minimal-server.js.nft.json +1 -0
  7. package/.next/next-server.js.nft.json +1 -0
  8. package/.next/package.json +1 -0
  9. package/.next/prerender-manifest.json +282 -0
  10. package/.next/react-loadable-manifest.json +1 -0
  11. package/.next/required-server-files.js +330 -0
  12. package/.next/required-server-files.json +330 -0
  13. package/.next/routes-manifest.json +170 -0
  14. package/.next/server/app/_global-error/page.js +3 -0
  15. package/.next/server/app/_global-error/page.js.nft.json +1 -0
  16. package/.next/server/app/_global-error/page_client-reference-manifest.js +1 -0
  17. package/.next/server/app/_global-error.html +2 -0
  18. package/.next/server/app/_global-error.meta +16 -0
  19. package/.next/server/app/_global-error.rsc +12 -0
  20. package/.next/server/app/_global-error.segments/_full.segment.rsc +12 -0
  21. package/.next/server/app/_global-error.segments/_global-error/__PAGE__.segment.rsc +5 -0
  22. package/.next/server/app/_global-error.segments/_global-error.segment.rsc +4 -0
  23. package/.next/server/app/_global-error.segments/_head.segment.rsc +5 -0
  24. package/.next/server/app/_global-error.segments/_index.segment.rsc +4 -0
  25. package/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -0
  26. package/.next/server/app/_not-found/page.js +2 -0
  27. package/.next/server/app/_not-found/page.js.nft.json +1 -0
  28. package/.next/server/app/_not-found/page_client-reference-manifest.js +1 -0
  29. package/.next/server/app/_not-found.html +1 -0
  30. package/.next/server/app/_not-found.meta +16 -0
  31. package/.next/server/app/_not-found.rsc +19 -0
  32. package/.next/server/app/_not-found.segments/_full.segment.rsc +19 -0
  33. package/.next/server/app/_not-found.segments/_head.segment.rsc +6 -0
  34. package/.next/server/app/_not-found.segments/_index.segment.rsc +8 -0
  35. package/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +5 -0
  36. package/.next/server/app/_not-found.segments/_not-found.segment.rsc +4 -0
  37. package/.next/server/app/_not-found.segments/_tree.segment.rsc +6 -0
  38. package/.next/server/app/api/credentials/route.js +1 -0
  39. package/.next/server/app/api/credentials/route.js.nft.json +1 -0
  40. package/.next/server/app/api/credentials/route_client-reference-manifest.js +1 -0
  41. package/.next/server/app/api/custom-scripts/route.js +3 -0
  42. package/.next/server/app/api/custom-scripts/route.js.nft.json +1 -0
  43. package/.next/server/app/api/custom-scripts/route_client-reference-manifest.js +1 -0
  44. package/.next/server/app/api/fs/route.js +1 -0
  45. package/.next/server/app/api/fs/route.js.nft.json +1 -0
  46. package/.next/server/app/api/fs/route_client-reference-manifest.js +1 -0
  47. package/.next/server/app/api/git/action/route.js +1 -0
  48. package/.next/server/app/api/git/action/route.js.nft.json +1 -0
  49. package/.next/server/app/api/git/action/route_client-reference-manifest.js +1 -0
  50. package/.next/server/app/api/git/branches/route.js +1 -0
  51. package/.next/server/app/api/git/branches/route.js.nft.json +1 -0
  52. package/.next/server/app/api/git/branches/route_client-reference-manifest.js +1 -0
  53. package/.next/server/app/api/git/diff/route.js +1 -0
  54. package/.next/server/app/api/git/diff/route.js.nft.json +1 -0
  55. package/.next/server/app/api/git/diff/route_client-reference-manifest.js +1 -0
  56. package/.next/server/app/api/git/log/route.js +1 -0
  57. package/.next/server/app/api/git/log/route.js.nft.json +1 -0
  58. package/.next/server/app/api/git/log/route_client-reference-manifest.js +1 -0
  59. package/.next/server/app/api/git/status/route.js +1 -0
  60. package/.next/server/app/api/git/status/route.js.nft.json +1 -0
  61. package/.next/server/app/api/git/status/route_client-reference-manifest.js +1 -0
  62. package/.next/server/app/api/repos/route.js +1 -0
  63. package/.next/server/app/api/repos/route.js.nft.json +1 -0
  64. package/.next/server/app/api/repos/route_client-reference-manifest.js +1 -0
  65. package/.next/server/app/api/settings/route.js +1 -0
  66. package/.next/server/app/api/settings/route.js.nft.json +1 -0
  67. package/.next/server/app/api/settings/route_client-reference-manifest.js +1 -0
  68. package/.next/server/app/credentials/page.js +4 -0
  69. package/.next/server/app/credentials/page.js.nft.json +1 -0
  70. package/.next/server/app/credentials/page_client-reference-manifest.js +1 -0
  71. package/.next/server/app/credentials.html +1 -0
  72. package/.next/server/app/credentials.meta +15 -0
  73. package/.next/server/app/credentials.rsc +23 -0
  74. package/.next/server/app/credentials.segments/_full.segment.rsc +23 -0
  75. package/.next/server/app/credentials.segments/_head.segment.rsc +6 -0
  76. package/.next/server/app/credentials.segments/_index.segment.rsc +8 -0
  77. package/.next/server/app/credentials.segments/_tree.segment.rsc +6 -0
  78. package/.next/server/app/credentials.segments/credentials/__PAGE__.segment.rsc +9 -0
  79. package/.next/server/app/credentials.segments/credentials.segment.rsc +4 -0
  80. package/.next/server/app/icon.png/route.js +1 -0
  81. package/.next/server/app/icon.png/route.js.nft.json +1 -0
  82. package/.next/server/app/icon.png.meta +1 -0
  83. package/.next/server/app/index.html +1 -0
  84. package/.next/server/app/index.meta +14 -0
  85. package/.next/server/app/index.rsc +20 -0
  86. package/.next/server/app/index.segments/__PAGE__.segment.rsc +6 -0
  87. package/.next/server/app/index.segments/_full.segment.rsc +20 -0
  88. package/.next/server/app/index.segments/_head.segment.rsc +6 -0
  89. package/.next/server/app/index.segments/_index.segment.rsc +8 -0
  90. package/.next/server/app/index.segments/_tree.segment.rsc +6 -0
  91. package/.next/server/app/page.js +2 -0
  92. package/.next/server/app/page.js.nft.json +1 -0
  93. package/.next/server/app/page_client-reference-manifest.js +1 -0
  94. package/.next/server/app/workspace/changes/page.js +4 -0
  95. package/.next/server/app/workspace/changes/page.js.nft.json +1 -0
  96. package/.next/server/app/workspace/changes/page_client-reference-manifest.js +1 -0
  97. package/.next/server/app/workspace/changes.html +1 -0
  98. package/.next/server/app/workspace/changes.meta +16 -0
  99. package/.next/server/app/workspace/changes.rsc +26 -0
  100. package/.next/server/app/workspace/changes.segments/_full.segment.rsc +26 -0
  101. package/.next/server/app/workspace/changes.segments/_head.segment.rsc +6 -0
  102. package/.next/server/app/workspace/changes.segments/_index.segment.rsc +8 -0
  103. package/.next/server/app/workspace/changes.segments/_tree.segment.rsc +7 -0
  104. package/.next/server/app/workspace/changes.segments/workspace/changes/__PAGE__.segment.rsc +10 -0
  105. package/.next/server/app/workspace/changes.segments/workspace/changes.segment.rsc +4 -0
  106. package/.next/server/app/workspace/changes.segments/workspace.segment.rsc +7 -0
  107. package/.next/server/app/workspace/custom-scripts/page.js +2 -0
  108. package/.next/server/app/workspace/custom-scripts/page.js.nft.json +1 -0
  109. package/.next/server/app/workspace/custom-scripts/page_client-reference-manifest.js +1 -0
  110. package/.next/server/app/workspace/custom-scripts.html +1 -0
  111. package/.next/server/app/workspace/custom-scripts.meta +16 -0
  112. package/.next/server/app/workspace/custom-scripts.rsc +25 -0
  113. package/.next/server/app/workspace/custom-scripts.segments/_full.segment.rsc +25 -0
  114. package/.next/server/app/workspace/custom-scripts.segments/_head.segment.rsc +6 -0
  115. package/.next/server/app/workspace/custom-scripts.segments/_index.segment.rsc +8 -0
  116. package/.next/server/app/workspace/custom-scripts.segments/_tree.segment.rsc +6 -0
  117. package/.next/server/app/workspace/custom-scripts.segments/workspace/custom-scripts/__PAGE__.segment.rsc +9 -0
  118. package/.next/server/app/workspace/custom-scripts.segments/workspace/custom-scripts.segment.rsc +4 -0
  119. package/.next/server/app/workspace/custom-scripts.segments/workspace.segment.rsc +7 -0
  120. package/.next/server/app/workspace/history/page.js +2 -0
  121. package/.next/server/app/workspace/history/page.js.nft.json +1 -0
  122. package/.next/server/app/workspace/history/page_client-reference-manifest.js +1 -0
  123. package/.next/server/app/workspace/history.html +1 -0
  124. package/.next/server/app/workspace/history.meta +16 -0
  125. package/.next/server/app/workspace/history.rsc +26 -0
  126. package/.next/server/app/workspace/history.segments/_full.segment.rsc +26 -0
  127. package/.next/server/app/workspace/history.segments/_head.segment.rsc +6 -0
  128. package/.next/server/app/workspace/history.segments/_index.segment.rsc +8 -0
  129. package/.next/server/app/workspace/history.segments/_tree.segment.rsc +7 -0
  130. package/.next/server/app/workspace/history.segments/workspace/history/__PAGE__.segment.rsc +10 -0
  131. package/.next/server/app/workspace/history.segments/workspace/history.segment.rsc +4 -0
  132. package/.next/server/app/workspace/history.segments/workspace.segment.rsc +7 -0
  133. package/.next/server/app/workspace/page.js +2 -0
  134. package/.next/server/app/workspace/page.js.nft.json +1 -0
  135. package/.next/server/app/workspace/page_client-reference-manifest.js +1 -0
  136. package/.next/server/app/workspace/settings/page.js +2 -0
  137. package/.next/server/app/workspace/settings/page.js.nft.json +1 -0
  138. package/.next/server/app/workspace/settings/page_client-reference-manifest.js +1 -0
  139. package/.next/server/app/workspace/settings.html +1 -0
  140. package/.next/server/app/workspace/settings.meta +16 -0
  141. package/.next/server/app/workspace/settings.rsc +25 -0
  142. package/.next/server/app/workspace/settings.segments/_full.segment.rsc +25 -0
  143. package/.next/server/app/workspace/settings.segments/_head.segment.rsc +6 -0
  144. package/.next/server/app/workspace/settings.segments/_index.segment.rsc +8 -0
  145. package/.next/server/app/workspace/settings.segments/_tree.segment.rsc +6 -0
  146. package/.next/server/app/workspace/settings.segments/workspace/settings/__PAGE__.segment.rsc +9 -0
  147. package/.next/server/app/workspace/settings.segments/workspace/settings.segment.rsc +4 -0
  148. package/.next/server/app/workspace/settings.segments/workspace.segment.rsc +7 -0
  149. package/.next/server/app/workspace/stashes/page.js +2 -0
  150. package/.next/server/app/workspace/stashes/page.js.nft.json +1 -0
  151. package/.next/server/app/workspace/stashes/page_client-reference-manifest.js +1 -0
  152. package/.next/server/app/workspace/stashes.html +1 -0
  153. package/.next/server/app/workspace/stashes.meta +16 -0
  154. package/.next/server/app/workspace/stashes.rsc +26 -0
  155. package/.next/server/app/workspace/stashes.segments/_full.segment.rsc +26 -0
  156. package/.next/server/app/workspace/stashes.segments/_head.segment.rsc +6 -0
  157. package/.next/server/app/workspace/stashes.segments/_index.segment.rsc +8 -0
  158. package/.next/server/app/workspace/stashes.segments/_tree.segment.rsc +7 -0
  159. package/.next/server/app/workspace/stashes.segments/workspace/stashes/__PAGE__.segment.rsc +10 -0
  160. package/.next/server/app/workspace/stashes.segments/workspace/stashes.segment.rsc +4 -0
  161. package/.next/server/app/workspace/stashes.segments/workspace.segment.rsc +7 -0
  162. package/.next/server/app/workspace.html +1 -0
  163. package/.next/server/app/workspace.meta +15 -0
  164. package/.next/server/app/workspace.rsc +26 -0
  165. package/.next/server/app/workspace.segments/_full.segment.rsc +26 -0
  166. package/.next/server/app/workspace.segments/_head.segment.rsc +6 -0
  167. package/.next/server/app/workspace.segments/_index.segment.rsc +8 -0
  168. package/.next/server/app/workspace.segments/_tree.segment.rsc +7 -0
  169. package/.next/server/app/workspace.segments/workspace/__PAGE__.segment.rsc +10 -0
  170. package/.next/server/app/workspace.segments/workspace.segment.rsc +7 -0
  171. package/.next/server/app-paths-manifest.json +23 -0
  172. package/.next/server/chunks/116.js +1 -0
  173. package/.next/server/chunks/170.js +1 -0
  174. package/.next/server/chunks/309.js +6 -0
  175. package/.next/server/chunks/356.js +1 -0
  176. package/.next/server/chunks/392.js +1 -0
  177. package/.next/server/chunks/443.js +37 -0
  178. package/.next/server/chunks/445.js +22 -0
  179. package/.next/server/chunks/471.js +13 -0
  180. package/.next/server/chunks/557.js +5 -0
  181. package/.next/server/chunks/680.js +1 -0
  182. package/.next/server/chunks/739.js +5 -0
  183. package/.next/server/chunks/781.js +1 -0
  184. package/.next/server/chunks/813.js +1 -0
  185. package/.next/server/chunks/816.js +13 -0
  186. package/.next/server/functions-config-manifest.json +6 -0
  187. package/.next/server/interception-route-rewrite-manifest.js +1 -0
  188. package/.next/server/middleware-build-manifest.js +1 -0
  189. package/.next/server/middleware-manifest.json +6 -0
  190. package/.next/server/middleware-react-loadable-manifest.js +1 -0
  191. package/.next/server/next-font-manifest.js +1 -0
  192. package/.next/server/next-font-manifest.json +1 -0
  193. package/.next/server/pages/404.html +1 -0
  194. package/.next/server/pages/500.html +2 -0
  195. package/.next/server/pages-manifest.json +4 -0
  196. package/.next/server/server-reference-manifest.js +1 -0
  197. package/.next/server/server-reference-manifest.json +1 -0
  198. package/.next/server/webpack-runtime.js +1 -0
  199. package/.next/static/VTWJwhFJd5VcC6GP5bbli/_buildManifest.js +1 -0
  200. package/.next/static/VTWJwhFJd5VcC6GP5bbli/_ssgManifest.js +1 -0
  201. package/.next/static/chunks/131-6237c77d708182b1.js +1 -0
  202. package/.next/static/chunks/147-d4cb3e03218d75df.js +6 -0
  203. package/.next/static/chunks/176-b068120641913226.js +1 -0
  204. package/.next/static/chunks/200-3664e65687e716a2.js +1 -0
  205. package/.next/static/chunks/26-d93e82c9c09ff972.js +1 -0
  206. package/.next/static/chunks/4bd1b696-096d35a2bd1da3af.js +1 -0
  207. package/.next/static/chunks/500-5d45efbf86b8d36e.js +1 -0
  208. package/.next/static/chunks/772-b39107b40c31b6b6.js +3 -0
  209. package/.next/static/chunks/785-e6d755147ff87934.js +1 -0
  210. package/.next/static/chunks/790-3e8fa6e595d97940.js +6 -0
  211. package/.next/static/chunks/794-37dad9bbc14b04b8.js +2 -0
  212. package/.next/static/chunks/841-4d865378216d36eb.js +13 -0
  213. package/.next/static/chunks/app/_global-error/page-9eb8a19109bbd711.js +1 -0
  214. package/.next/static/chunks/app/_not-found/page-5bea07380837254f.js +1 -0
  215. package/.next/static/chunks/app/api/credentials/route-9eb8a19109bbd711.js +1 -0
  216. package/.next/static/chunks/app/api/custom-scripts/route-9eb8a19109bbd711.js +1 -0
  217. package/.next/static/chunks/app/api/fs/route-9eb8a19109bbd711.js +1 -0
  218. package/.next/static/chunks/app/api/git/action/route-9eb8a19109bbd711.js +1 -0
  219. package/.next/static/chunks/app/api/git/branches/route-9eb8a19109bbd711.js +1 -0
  220. package/.next/static/chunks/app/api/git/diff/route-9eb8a19109bbd711.js +1 -0
  221. package/.next/static/chunks/app/api/git/log/route-9eb8a19109bbd711.js +1 -0
  222. package/.next/static/chunks/app/api/git/status/route-9eb8a19109bbd711.js +1 -0
  223. package/.next/static/chunks/app/api/repos/route-9eb8a19109bbd711.js +1 -0
  224. package/.next/static/chunks/app/api/settings/route-9eb8a19109bbd711.js +1 -0
  225. package/.next/static/chunks/app/credentials/page-23c1807ad9f68a40.js +1 -0
  226. package/.next/static/chunks/app/layout-a06241c385e50ae0.js +1 -0
  227. package/.next/static/chunks/app/page-c8404790f5191fd7.js +1 -0
  228. package/.next/static/chunks/app/workspace/changes/page-8cca17f80e66f534.js +3 -0
  229. package/.next/static/chunks/app/workspace/custom-scripts/page-ee24b9dd7779244f.js +1 -0
  230. package/.next/static/chunks/app/workspace/history/page-b7017fea285c804c.js +1 -0
  231. package/.next/static/chunks/app/workspace/layout-cb86c00fdcd8db08.js +1 -0
  232. package/.next/static/chunks/app/workspace/page-21211acc90c08509.js +1 -0
  233. package/.next/static/chunks/app/workspace/settings/page-7ccb58ece31492e9.js +1 -0
  234. package/.next/static/chunks/app/workspace/stashes/page-0e1b8304c4b0f4f3.js +1 -0
  235. package/.next/static/chunks/framework-75892d61b920805f.js +1 -0
  236. package/.next/static/chunks/main-app-221e1b945693a142.js +1 -0
  237. package/.next/static/chunks/main-f1d55fffd3cc9809.js +5 -0
  238. package/.next/static/chunks/next/dist/client/components/builtin/app-error-9eb8a19109bbd711.js +1 -0
  239. package/.next/static/chunks/next/dist/client/components/builtin/forbidden-9eb8a19109bbd711.js +1 -0
  240. package/.next/static/chunks/next/dist/client/components/builtin/global-error-f2a2c324f3740ed8.js +1 -0
  241. package/.next/static/chunks/next/dist/client/components/builtin/not-found-9eb8a19109bbd711.js +1 -0
  242. package/.next/static/chunks/next/dist/client/components/builtin/unauthorized-9eb8a19109bbd711.js +1 -0
  243. package/.next/static/chunks/polyfills-42372ed130431b0a.js +1 -0
  244. package/.next/static/chunks/webpack-7dec27dc3bfe207a.js +1 -0
  245. package/.next/static/css/36968b90b2339533.css +1 -0
  246. package/.next/static/css/c56c0e57397a3a60.css +1 -0
  247. package/.next/static/css/de70bee13400563f.css +1 -0
  248. package/.next/static/media/4cf2300e9c8272f7-s.p.woff2 +0 -0
  249. package/.next/static/media/747892c23ea88013-s.woff2 +0 -0
  250. package/.next/static/media/8d697b304b401681-s.woff2 +0 -0
  251. package/.next/static/media/93f479601ee12b01-s.p.woff2 +0 -0
  252. package/.next/static/media/9610d9e46709d722-s.woff2 +0 -0
  253. package/.next/static/media/ba015fad6dcf6784-s.woff2 +0 -0
  254. package/README.md +2 -0
  255. package/bin/trident-git.mjs +9 -11
  256. package/{next.config.ts → next.config.mjs} +7 -8
  257. package/package.json +8 -6
  258. package/eslint.config.mjs +0 -18
  259. package/postcss.config.mjs +0 -7
  260. package/src/app/api/credentials/route.ts +0 -113
  261. package/src/app/api/custom-scripts/route.ts +0 -203
  262. package/src/app/api/fs/route.ts +0 -75
  263. package/src/app/api/git/action/route.ts +0 -383
  264. package/src/app/api/git/branches/route.ts +0 -20
  265. package/src/app/api/git/diff/route.ts +0 -104
  266. package/src/app/api/git/log/route.ts +0 -28
  267. package/src/app/api/git/status/route.ts +0 -28
  268. package/src/app/api/repos/route.ts +0 -84
  269. package/src/app/api/settings/route.ts +0 -37
  270. package/src/app/credentials/page.tsx +0 -408
  271. package/src/app/globals.css +0 -109
  272. package/src/app/layout.tsx +0 -38
  273. package/src/app/page.tsx +0 -10
  274. package/src/app/providers.tsx +0 -21
  275. package/src/app/workspace/changes/page.tsx +0 -27
  276. package/src/app/workspace/custom-scripts/page.tsx +0 -247
  277. package/src/app/workspace/history/page.tsx +0 -27
  278. package/src/app/workspace/layout.tsx +0 -26
  279. package/src/app/workspace/page.tsx +0 -27
  280. package/src/app/workspace/settings/page.tsx +0 -233
  281. package/src/app/workspace/stashes/page.tsx +0 -395
  282. package/src/components/command-palette.tsx +0 -178
  283. package/src/components/context-menu.tsx +0 -200
  284. package/src/components/fs-browser.tsx +0 -154
  285. package/src/components/git/diff-view.tsx +0 -137
  286. package/src/components/git/git-graph.tsx +0 -489
  287. package/src/components/git/grouped-diff-viewer.tsx +0 -332
  288. package/src/components/git/history-view.tsx +0 -4862
  289. package/src/components/git/image-diff-view.tsx +0 -342
  290. package/src/components/git/status-view.tsx +0 -597
  291. package/src/components/home-settings-modal.tsx +0 -192
  292. package/src/components/layout/sidebar.tsx +0 -256
  293. package/src/components/repo-list.tsx +0 -206
  294. package/src/components/theme-toggle.tsx +0 -37
  295. package/src/components/toaster.tsx +0 -36
  296. package/src/components/workspace-repo-open-tracker.tsx +0 -39
  297. package/src/hooks/use-credentials.ts +0 -123
  298. package/src/hooks/use-escape-dismiss.ts +0 -72
  299. package/src/hooks/use-git.ts +0 -448
  300. package/src/hooks/use-toast.ts +0 -280
  301. package/src/hooks/use-workspace-title.ts +0 -23
  302. package/src/lib/api-utils.ts +0 -24
  303. package/src/lib/branch-colors.ts +0 -98
  304. package/src/lib/credentials.ts +0 -404
  305. package/src/lib/git.ts +0 -1510
  306. package/src/lib/graph-utils.ts +0 -253
  307. package/src/lib/store.ts +0 -145
  308. package/src/lib/types.ts +0 -95
  309. package/src/lib/utils.ts +0 -266
  310. package/tsconfig.json +0 -34
  311. /package/{src/app/icon.png → .next/server/app/icon.png.body} +0 -0
@@ -1,247 +0,0 @@
1
- 'use client';
2
-
3
- import { Suspense, useMemo, useState } from 'react';
4
- import { useSearchParams } from 'next/navigation';
5
- import { useWorkspaceTitle } from '@/hooks/use-workspace-title';
6
- import { useRepositories, useRepository, useUpdateRepository } from '@/hooks/use-git';
7
- import { RepositoryCustomScript, RepositoryCustomScriptAction, RepositoryCustomScriptTarget } from '@/lib/types';
8
-
9
- type ScriptDraft = {
10
- name: string;
11
- target: RepositoryCustomScriptTarget;
12
- action: RepositoryCustomScriptAction;
13
- content: string;
14
- };
15
-
16
- const EMPTY_DRAFT: ScriptDraft = {
17
- name: '',
18
- target: 'branch',
19
- action: 'run-bash-script',
20
- content: '',
21
- };
22
-
23
- function generateScriptId(): string {
24
- if (typeof crypto !== 'undefined' && typeof crypto.randomUUID === 'function') {
25
- return crypto.randomUUID();
26
- }
27
- return `script-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`;
28
- }
29
-
30
- function WorkspaceCustomScriptsContent() {
31
- const searchParams = useSearchParams();
32
- const repoPath = searchParams.get('path');
33
-
34
- useWorkspaceTitle(repoPath, 'Custom scripts');
35
-
36
- const { isLoading: isReposLoading } = useRepositories();
37
- const repository = useRepository(repoPath);
38
- const updateRepository = useUpdateRepository();
39
-
40
- const scripts = useMemo(() => repository?.customScripts ?? [], [repository?.customScripts]);
41
- const [editingScriptId, setEditingScriptId] = useState<string | null>(null);
42
- const [draft, setDraft] = useState<ScriptDraft>(EMPTY_DRAFT);
43
- const [formError, setFormError] = useState<string | null>(null);
44
-
45
- if (isReposLoading) {
46
- return <div className="flex items-center justify-center h-full"><span className="loading loading-spinner"></span></div>;
47
- }
48
-
49
- if (!repoPath || !repository) {
50
- return <div className="p-8">Repository not found.</div>;
51
- }
52
-
53
- const resetForm = () => {
54
- setDraft(EMPTY_DRAFT);
55
- setEditingScriptId(null);
56
- setFormError(null);
57
- };
58
-
59
- const saveScripts = (nextScripts: RepositoryCustomScript[]) => {
60
- updateRepository.mutate({
61
- path: repoPath,
62
- updates: {
63
- customScripts: nextScripts,
64
- },
65
- });
66
- };
67
-
68
- const handleSubmit = (e: React.FormEvent) => {
69
- e.preventDefault();
70
-
71
- const name = draft.name.trim();
72
- const content = draft.content;
73
-
74
- if (!name) {
75
- setFormError('Script name is required.');
76
- return;
77
- }
78
-
79
- if (!content.trim()) {
80
- setFormError('Script content is required.');
81
- return;
82
- }
83
-
84
- const nextScript: RepositoryCustomScript = {
85
- id: editingScriptId || generateScriptId(),
86
- name,
87
- target: draft.target,
88
- action: draft.action,
89
- content,
90
- };
91
-
92
- const nextScripts = editingScriptId
93
- ? scripts.map((script) => (script.id === editingScriptId ? nextScript : script))
94
- : [...scripts, nextScript];
95
-
96
- saveScripts(nextScripts);
97
- resetForm();
98
- };
99
-
100
- const handleEdit = (script: RepositoryCustomScript) => {
101
- setEditingScriptId(script.id);
102
- setDraft({
103
- name: script.name,
104
- target: script.target,
105
- action: script.action,
106
- content: script.content,
107
- });
108
- setFormError(null);
109
- };
110
-
111
- const handleDelete = (scriptId: string) => {
112
- const nextScripts = scripts.filter((script) => script.id !== scriptId);
113
- saveScripts(nextScripts);
114
- if (editingScriptId === scriptId) {
115
- resetForm();
116
- }
117
- };
118
-
119
- return (
120
- <div className="p-8 max-w-4xl mx-auto space-y-6">
121
- <div>
122
- <h1 className="text-2xl font-bold">Custom Scripts</h1>
123
- <p className="text-sm opacity-70 mt-2">
124
- Manage custom bash scripts for this repository. Scripts appear in branch context menus.
125
- </p>
126
- </div>
127
-
128
- <div className="card bg-base-100 shadow-xl border border-base-200">
129
- <div className="card-body">
130
- <h2 className="card-title">{editingScriptId ? 'Edit Script' : 'New Script'}</h2>
131
- <form className="space-y-4" onSubmit={handleSubmit}>
132
- <div className="form-control">
133
- <label className="label">
134
- <span className="label-text">Name</span>
135
- </label>
136
- <input
137
- type="text"
138
- className="input input-bordered w-full"
139
- value={draft.name}
140
- onChange={(e) => setDraft((prev) => ({ ...prev, name: e.target.value }))}
141
- placeholder="Example: Run tests"
142
- />
143
- </div>
144
-
145
- <div className="grid grid-cols-1 md:grid-cols-2 gap-4">
146
- <div className="form-control">
147
- <label className="label">
148
- <span className="label-text">Target</span>
149
- </label>
150
- <select
151
- className="select select-bordered w-full"
152
- value={draft.target}
153
- onChange={(e) => setDraft((prev) => ({ ...prev, target: e.target.value as RepositoryCustomScriptTarget }))}
154
- >
155
- <option value="branch">Branch</option>
156
- </select>
157
- </div>
158
-
159
- <div className="form-control">
160
- <label className="label">
161
- <span className="label-text">Action</span>
162
- </label>
163
- <select
164
- className="select select-bordered w-full"
165
- value={draft.action}
166
- onChange={(e) => setDraft((prev) => ({ ...prev, action: e.target.value as RepositoryCustomScriptAction }))}
167
- >
168
- <option value="run-bash-script">Run bash script</option>
169
- </select>
170
- </div>
171
- </div>
172
-
173
- <div className="form-control">
174
- <label className="label">
175
- <span className="label-text">Script Content</span>
176
- </label>
177
- <textarea
178
- className="textarea textarea-bordered w-full h-56 font-mono text-sm"
179
- value={draft.content}
180
- onChange={(e) => setDraft((prev) => ({ ...prev, content: e.target.value }))}
181
- placeholder={'#!/usr/bin/env bash\nset -euo pipefail\n\necho "Hello from custom script"'}
182
- />
183
- </div>
184
-
185
- {formError && (
186
- <div className="alert alert-error py-2">
187
- <span>{formError}</span>
188
- </div>
189
- )}
190
-
191
- <div className="flex items-center gap-2">
192
- <button type="submit" className="btn btn-primary btn-sm" disabled={updateRepository.isPending}>
193
- {editingScriptId ? 'Update Script' : 'Add Script'}
194
- </button>
195
- {editingScriptId && (
196
- <button type="button" className="btn btn-ghost btn-sm" onClick={resetForm} disabled={updateRepository.isPending}>
197
- Cancel Edit
198
- </button>
199
- )}
200
- </div>
201
- </form>
202
- </div>
203
- </div>
204
-
205
- <div className="card bg-base-100 shadow-xl border border-base-200">
206
- <div className="card-body">
207
- <h2 className="card-title">Saved Scripts</h2>
208
- {scripts.length === 0 ? (
209
- <p className="text-sm opacity-60">No custom scripts yet.</p>
210
- ) : (
211
- <div className="space-y-3">
212
- {scripts.map((script) => (
213
- <div key={script.id} className="border border-base-300 rounded-lg p-4 bg-base-100">
214
- <div className="flex items-start justify-between gap-3">
215
- <div className="min-w-0">
216
- <div className="font-medium truncate">{script.name}</div>
217
- <div className="text-xs opacity-60 mt-1">
218
- Target: Branch | Action: Run bash script
219
- </div>
220
- </div>
221
- <div className="flex items-center gap-2 shrink-0">
222
- <button className="btn btn-ghost btn-xs" onClick={() => handleEdit(script)} disabled={updateRepository.isPending}>
223
- Edit
224
- </button>
225
- <button className="btn btn-ghost btn-xs text-error" onClick={() => handleDelete(script.id)} disabled={updateRepository.isPending}>
226
- Delete
227
- </button>
228
- </div>
229
- </div>
230
- <pre className="mt-3 text-xs font-mono bg-base-200 rounded p-3 overflow-auto max-h-36 whitespace-pre-wrap break-words">{script.content}</pre>
231
- </div>
232
- ))}
233
- </div>
234
- )}
235
- </div>
236
- </div>
237
- </div>
238
- );
239
- }
240
-
241
- export default function WorkspaceCustomScriptsPage() {
242
- return (
243
- <Suspense fallback={<div className="flex items-center justify-center h-full"><span className="loading loading-spinner"></span></div>}>
244
- <WorkspaceCustomScriptsContent />
245
- </Suspense>
246
- );
247
- }
@@ -1,27 +0,0 @@
1
- 'use client';
2
-
3
- import { useSearchParams } from 'next/navigation';
4
- import { HistoryView } from '@/components/git/history-view';
5
- import { Suspense } from 'react';
6
- import { useWorkspaceTitle } from '@/hooks/use-workspace-title';
7
-
8
- function WorkspaceHistoryContent() {
9
- const searchParams = useSearchParams();
10
- const repoPath = searchParams.get('path');
11
-
12
- useWorkspaceTitle(repoPath, 'History');
13
-
14
- if (!repoPath) {
15
- return <div className="p-8">No repository path specified.</div>;
16
- }
17
-
18
- return <HistoryView repoPath={repoPath} />;
19
- }
20
-
21
- export default function WorkspaceHistoryPage() {
22
- return (
23
- <Suspense fallback={<div className="flex items-center justify-center h-full"><span className="loading loading-spinner"></span></div>}>
24
- <WorkspaceHistoryContent />
25
- </Suspense>
26
- );
27
- }
@@ -1,26 +0,0 @@
1
- import { Sidebar } from '@/components/layout/sidebar';
2
- import { Suspense } from 'react';
3
- import { WorkspaceRepoOpenTracker } from '@/components/workspace-repo-open-tracker';
4
- import { getSettings } from '@/lib/store';
5
-
6
- export default function WorkspaceLayout({
7
- children,
8
- }: {
9
- children: React.ReactNode;
10
- }) {
11
- const sidebarCollapsed = getSettings().sidebarCollapsed ?? false;
12
-
13
- return (
14
- <div className="flex min-h-screen max-h-screen bg-base-100">
15
- <Suspense fallback={null}>
16
- <WorkspaceRepoOpenTracker />
17
- </Suspense>
18
- <Suspense fallback={<div className={`${sidebarCollapsed ? 'w-16' : 'w-64'} border-r border-base-300 min-h-screen bg-base-200/30 flex items-center justify-center`}><span className="loading loading-spinner"></span></div>}>
19
- <Sidebar initialCollapsed={sidebarCollapsed} />
20
- </Suspense>
21
- <main className="flex-1 overflow-auto">
22
- {children}
23
- </main>
24
- </div>
25
- );
26
- }
@@ -1,27 +0,0 @@
1
- 'use client';
2
-
3
- import { useSearchParams } from 'next/navigation';
4
- import { HistoryView } from '@/components/git/history-view';
5
- import { Suspense } from 'react';
6
- import { useWorkspaceTitle } from '@/hooks/use-workspace-title';
7
-
8
- function WorkspaceHistoryContent() {
9
- const searchParams = useSearchParams();
10
- const repoPath = searchParams.get('path');
11
-
12
- useWorkspaceTitle(repoPath, 'History');
13
-
14
- if (!repoPath) {
15
- return <div className="p-8">No repository path specified.</div>;
16
- }
17
-
18
- return <HistoryView repoPath={repoPath} />;
19
- }
20
-
21
- export default function WorkspacePage() {
22
- return (
23
- <Suspense fallback={<div className="flex items-center justify-center h-full"><span className="loading loading-spinner"></span></div>}>
24
- <WorkspaceHistoryContent />
25
- </Suspense>
26
- );
27
- }
@@ -1,233 +0,0 @@
1
- 'use client';
2
-
3
- import { useSearchParams } from 'next/navigation';
4
- import { Suspense, useMemo, useState } from 'react';
5
- import { useWorkspaceTitle } from '@/hooks/use-workspace-title';
6
- import { useRepositories, useUpdateRepository, useGitBranches } from '@/hooks/use-git';
7
- import { useCredentials } from '@/hooks/use-credentials';
8
- import { getRepoFolderName, getRepositoryDisplayName } from '@/lib/utils';
9
-
10
- function getHostname(url: string): string | null {
11
- try {
12
- // Handle git@github.com:user/repo.git format
13
- if (url.startsWith('git@')) {
14
- const match = url.match(/git@([^:]+):/);
15
- return match ? match[1] : null;
16
- }
17
- // Handle https://github.com/user/repo.git format
18
- return new URL(url).hostname;
19
- } catch {
20
- return null;
21
- }
22
- }
23
-
24
- function WorkspaceSettingsContent() {
25
- const searchParams = useSearchParams();
26
- const repoPath = searchParams.get('path');
27
-
28
- useWorkspaceTitle(repoPath, 'Settings');
29
-
30
- const { data: repos, isLoading: isLoadingRepos } = useRepositories();
31
- const { data: credentials, isLoading: isLoadingCreds } = useCredentials();
32
- const { data: gitData, isLoading: isLoadingGit } = useGitBranches(repoPath);
33
- const updateRepo = useUpdateRepository();
34
-
35
- const currentRepo = useMemo(() =>
36
- repos?.find(r => r.path === repoPath),
37
- [repos, repoPath]);
38
- const [displayNameDraftState, setDisplayNameDraftState] = useState<{
39
- path: string | null;
40
- value: string;
41
- isDirty: boolean;
42
- }>({
43
- path: null,
44
- value: '',
45
- isDirty: false,
46
- });
47
-
48
- const matchingCredentials = useMemo(() => {
49
- if (!credentials || !gitData?.remoteUrls) return [];
50
-
51
- // specific remote URLs
52
- const urls = Object.values(gitData.remoteUrls);
53
- const remoteHosts = new Set(urls.map(getHostname).filter(Boolean) as string[]);
54
-
55
- return credentials.filter(cred => {
56
- if (cred.type === 'github') {
57
- return remoteHosts.has('github.com');
58
- }
59
- if (cred.type === 'gitlab' && cred.serverUrl) {
60
- const credHost = getHostname(cred.serverUrl);
61
- return credHost && remoteHosts.has(credHost);
62
- }
63
- return false;
64
- });
65
- }, [credentials, gitData]);
66
-
67
- const isLoading = isLoadingRepos || isLoadingCreds || isLoadingGit;
68
-
69
- if (isLoading) {
70
- return <div className="flex items-center justify-center h-full"><span className="loading loading-spinner"></span></div>;
71
- }
72
-
73
- if (!repoPath || !currentRepo) {
74
- return <div className="p-8">Repository not found.</div>;
75
- }
76
-
77
- const displayNameDraft = displayNameDraftState.path === repoPath && displayNameDraftState.isDirty
78
- ? displayNameDraftState.value
79
- : (currentRepo.displayName ?? '');
80
- const normalizedSavedDisplayName = currentRepo.displayName?.trim() ?? '';
81
- const normalizedDraftDisplayName = displayNameDraft.trim();
82
- const isDisplayNameDirty = normalizedDraftDisplayName !== normalizedSavedDisplayName;
83
- const previewName = getRepositoryDisplayName({
84
- path: currentRepo.path,
85
- name: currentRepo.name,
86
- displayName: displayNameDraft,
87
- });
88
- const fallbackFolderName = getRepoFolderName(currentRepo.path);
89
-
90
- const handleDisplayNameSave = () => {
91
- setDisplayNameDraftState({
92
- path: repoPath,
93
- value: displayNameDraft,
94
- isDirty: false,
95
- });
96
- updateRepo.mutate({
97
- path: repoPath,
98
- updates: { displayName: displayNameDraft }
99
- });
100
- };
101
-
102
- const handleDisplayNameReset = () => {
103
- setDisplayNameDraftState({
104
- path: repoPath,
105
- value: '',
106
- isDirty: false,
107
- });
108
- updateRepo.mutate({
109
- path: repoPath,
110
- updates: { displayName: null }
111
- });
112
- };
113
-
114
- const handleCredentialChange = (e: React.ChangeEvent<HTMLSelectElement>) => {
115
- const credentialId = e.target.value;
116
- updateRepo.mutate({
117
- path: repoPath,
118
- updates: { credentialId: credentialId === 'none' ? null : credentialId }
119
- });
120
- };
121
-
122
- return (
123
- <div className="p-8 max-w-2xl mx-auto">
124
- <h1 className="text-2xl font-bold mb-6">Workspace Settings</h1>
125
-
126
- <div className="space-y-6">
127
- <div className="card bg-base-100 shadow-xl border border-base-200">
128
- <div className="card-body">
129
- <h2 className="card-title">Repository Display Name</h2>
130
- <p className="text-sm opacity-70">
131
- Set a custom name for this repository in the workspace UI.
132
- </p>
133
-
134
- <div className="form-control w-full mt-4">
135
- <label className="label">
136
- <span className="label-text">Display Name</span>
137
- </label>
138
- <input
139
- type="text"
140
- className="input input-bordered w-full"
141
- placeholder={fallbackFolderName}
142
- value={displayNameDraft}
143
- onChange={(e) => {
144
- setDisplayNameDraftState({
145
- path: repoPath,
146
- value: e.target.value,
147
- isDirty: true,
148
- });
149
- }}
150
- onKeyDown={(e) => {
151
- if (e.key === 'Enter' && isDisplayNameDirty && !updateRepo.isPending) {
152
- e.preventDefault();
153
- handleDisplayNameSave();
154
- }
155
- }}
156
- />
157
- <label className="label">
158
- <span className="label-text-alt opacity-70">
159
- Preview: <span className="font-medium">{previewName}</span>
160
- </span>
161
- </label>
162
- </div>
163
-
164
- <div className="flex items-center gap-2 mt-2">
165
- <button
166
- type="button"
167
- className="btn btn-primary btn-sm"
168
- onClick={handleDisplayNameSave}
169
- disabled={!isDisplayNameDirty || updateRepo.isPending}
170
- >
171
- Save Name
172
- </button>
173
- <button
174
- type="button"
175
- className="btn btn-ghost btn-sm"
176
- onClick={handleDisplayNameReset}
177
- disabled={(!normalizedDraftDisplayName && !currentRepo.displayName) || updateRepo.isPending}
178
- >
179
- Reset
180
- </button>
181
- </div>
182
- </div>
183
- </div>
184
-
185
- <div className="card bg-base-100 shadow-xl border border-base-200">
186
- <div className="card-body">
187
- <h2 className="card-title">Repository Credentials</h2>
188
- <p className="text-sm opacity-70">
189
- Associate a credential with this repository to authenticate with remote servers.
190
- </p>
191
-
192
- <div className="form-control w-full mt-4">
193
- <label className="label">
194
- <span className="label-text">Associated Credential</span>
195
- </label>
196
- <select
197
- className="select select-bordered w-full"
198
- value={currentRepo.credentialId || 'none'}
199
- onChange={handleCredentialChange}
200
- >
201
- <option value="none">None</option>
202
- {matchingCredentials.map((cred) => (
203
- <option key={cred.id} value={cred.id}>
204
- {cred.type === 'github' ? 'GitHub' : 'GitLab'}
205
- {cred.type === 'gitlab' && ` (${new URL(cred.serverUrl!).hostname})`}
206
- {' - '}
207
- {cred.type === 'github' ? 'Account' : 'Token'}
208
- </option>
209
- ))}
210
- </select>
211
- {matchingCredentials.length === 0 && (
212
- <label className="label">
213
- <span className="label-text-alt opacity-70">
214
- No matching credentials found for this repository&apos;s remotes.
215
- Add credentials in the Credentials page.
216
- </span>
217
- </label>
218
- )}
219
- </div>
220
- </div>
221
- </div>
222
- </div>
223
- </div>
224
- );
225
- }
226
-
227
- export default function WorkspaceSettingsPage() {
228
- return (
229
- <Suspense fallback={<div className="flex items-center justify-center h-full"><span className="loading loading-spinner"></span></div>}>
230
- <WorkspaceSettingsContent />
231
- </Suspense>
232
- );
233
- }