@storyshelf/core 0.3.2 → 0.5.3

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 (393) hide show
  1. package/README.md +38 -31
  2. package/dist/adapter/capture-queue.d.mts +29 -1
  3. package/dist/adapter/capture-runner.d.mts +18 -2
  4. package/dist/adapter/capture-runner.mjs +12 -1
  5. package/dist/adapter/capture-runner.mjs.map +1 -0
  6. package/dist/adapter/database.d.mts +67 -17
  7. package/dist/adapter/database.mjs +22 -55
  8. package/dist/adapter/database.mjs.map +1 -1
  9. package/dist/adapter/email-sender.d.mts +27 -0
  10. package/dist/adapter/email-sender.mjs +4 -0
  11. package/dist/adapter/metadata.d.mts +21 -15
  12. package/dist/adapter/notifier.d.mts +7 -0
  13. package/dist/adapter/notifier.mjs +6 -0
  14. package/dist/adapter/setup.d.mts +61 -0
  15. package/dist/adapter/setup.mjs +29 -0
  16. package/dist/adapter/setup.mjs.map +1 -0
  17. package/dist/adapter/webhook-events.d.mts +29 -0
  18. package/dist/adapter/webhook-events.mjs +83 -0
  19. package/dist/adapter/webhook-events.mjs.map +1 -0
  20. package/dist/adapters/notifier/events.d.mts +26 -0
  21. package/dist/adapters/notifier/events.mjs +66 -0
  22. package/dist/adapters/notifier/events.mjs.map +1 -0
  23. package/dist/adapters/notifier/format.d.mts +14 -0
  24. package/dist/adapters/notifier/format.mjs +96 -0
  25. package/dist/adapters/notifier/format.mjs.map +1 -0
  26. package/dist/adapters/notifier/provider.d.mts +32 -0
  27. package/dist/adapters/notifier/types.d.mts +56 -0
  28. package/dist/adapters/setup-runner.d.mts +23 -0
  29. package/dist/adapters/setup-runner.mjs +149 -0
  30. package/dist/adapters/setup-runner.mjs.map +1 -0
  31. package/dist/adapters/validate.d.mts +30 -0
  32. package/dist/adapters/validate.mjs +313 -0
  33. package/dist/adapters/validate.mjs.map +1 -0
  34. package/dist/auth.d.mts +94 -0
  35. package/dist/auth.mjs +4 -0
  36. package/dist/brand-packs.d.mts +16 -0
  37. package/dist/brand-packs.mjs +130 -0
  38. package/dist/brand-packs.mjs.map +1 -0
  39. package/dist/capture/adapter.d.mts +51 -1
  40. package/dist/capture/adapter.mjs.map +1 -1
  41. package/dist/capture/affected.d.mts +16 -0
  42. package/dist/capture/affected.mjs +64 -0
  43. package/dist/capture/affected.mjs.map +1 -0
  44. package/dist/capture/diff-record.mjs +30 -0
  45. package/dist/capture/diff-record.mjs.map +1 -0
  46. package/dist/capture/dispatch.d.mts +36 -0
  47. package/dist/capture/dispatch.mjs +88 -31
  48. package/dist/capture/dispatch.mjs.map +1 -1
  49. package/dist/capture/guards.mjs +31 -0
  50. package/dist/capture/guards.mjs.map +1 -0
  51. package/dist/capture/orchestrator.d.mts +41 -6
  52. package/dist/capture/orchestrator.mjs +151 -28
  53. package/dist/capture/orchestrator.mjs.map +1 -1
  54. package/dist/capture/pipeline.d.mts +30 -16
  55. package/dist/capture/pipeline.mjs +143 -39
  56. package/dist/capture/pipeline.mjs.map +1 -1
  57. package/dist/capture/recovery.d.mts +21 -0
  58. package/dist/capture/recovery.mjs +83 -0
  59. package/dist/capture/recovery.mjs.map +1 -0
  60. package/dist/capture/rediff.d.mts +35 -0
  61. package/dist/capture/rediff.mjs +77 -0
  62. package/dist/capture/rediff.mjs.map +1 -0
  63. package/dist/capture/sizing.d.mts +58 -0
  64. package/dist/capture/sizing.mjs +119 -0
  65. package/dist/capture/sizing.mjs.map +1 -0
  66. package/dist/capture/skip-checks.mjs +3 -3
  67. package/dist/capture/skip-checks.mjs.map +1 -1
  68. package/dist/capture/statics.d.mts +38 -0
  69. package/dist/capture/statics.mjs +38 -4
  70. package/dist/capture/statics.mjs.map +1 -1
  71. package/dist/capture/status-fanout.mjs +7 -2
  72. package/dist/capture/status-fanout.mjs.map +1 -1
  73. package/dist/capture/storybook.d.mts +31 -2
  74. package/dist/capture/storybook.mjs +77 -2
  75. package/dist/capture/storybook.mjs.map +1 -1
  76. package/dist/capture.d.mts +10 -4
  77. package/dist/capture.mjs +7 -2
  78. package/dist/config.d.mts +121 -4
  79. package/dist/config.mjs +55 -8
  80. package/dist/config.mjs.map +1 -1
  81. package/dist/index.d.mts +5 -56
  82. package/dist/index.mjs +4 -284
  83. package/dist/logger.d.mts +26 -17
  84. package/dist/logger.mjs +10 -5
  85. package/dist/logger.mjs.map +1 -1
  86. package/dist/models/baseline-status.d.mts +29 -0
  87. package/dist/models/baseline-status.mjs +26 -0
  88. package/dist/models/baseline-status.mjs.map +1 -0
  89. package/dist/models/baseline.d.mts +33 -0
  90. package/dist/models/baseline.mjs +35 -13
  91. package/dist/models/baseline.mjs.map +1 -1
  92. package/dist/models/build.d.mts +87 -0
  93. package/dist/models/build.mjs +83 -35
  94. package/dist/models/build.mjs.map +1 -1
  95. package/dist/models/capture-attempt.d.mts +40 -0
  96. package/dist/models/capture-attempt.mjs +85 -0
  97. package/dist/models/capture-attempt.mjs.map +1 -0
  98. package/dist/models/capture-log.d.mts +21 -0
  99. package/dist/models/capture-log.mjs +44 -0
  100. package/dist/models/capture-log.mjs.map +1 -0
  101. package/dist/models/comment.d.mts +29 -0
  102. package/dist/models/comment.mjs +11 -8
  103. package/dist/models/comment.mjs.map +1 -1
  104. package/dist/models/content-ref.d.mts +21 -0
  105. package/dist/models/content-ref.mjs +49 -0
  106. package/dist/models/content-ref.mjs.map +1 -0
  107. package/dist/models/credentials.d.mts +36 -0
  108. package/dist/models/credentials.mjs +103 -0
  109. package/dist/models/credentials.mjs.map +1 -0
  110. package/dist/models/label.d.mts +58 -0
  111. package/dist/models/label.mjs +32 -27
  112. package/dist/models/label.mjs.map +1 -1
  113. package/dist/models/member.d.mts +34 -0
  114. package/dist/models/member.mjs +20 -11
  115. package/dist/models/member.mjs.map +1 -1
  116. package/dist/models/notification-channel.d.mts +52 -0
  117. package/dist/models/notification-channel.mjs +93 -0
  118. package/dist/models/notification-channel.mjs.map +1 -0
  119. package/dist/models/notification-subscription.d.mts +44 -0
  120. package/dist/models/notification-subscription.mjs +89 -0
  121. package/dist/models/notification-subscription.mjs.map +1 -0
  122. package/dist/models/project-group-mapping.d.mts +30 -0
  123. package/dist/models/project-group-mapping.mjs +46 -0
  124. package/dist/models/project-group-mapping.mjs.map +1 -0
  125. package/dist/models/project.d.mts +54 -0
  126. package/dist/models/project.mjs +15 -11
  127. package/dist/models/project.mjs.map +1 -1
  128. package/dist/models/snapshot.d.mts +58 -0
  129. package/dist/models/snapshot.mjs +13 -7
  130. package/dist/models/snapshot.mjs.map +1 -1
  131. package/dist/models/status-config.d.mts +38 -0
  132. package/dist/models/status-config.mjs +12 -11
  133. package/dist/models/status-config.mjs.map +1 -1
  134. package/dist/models/token.d.mts +44 -0
  135. package/dist/models/token.mjs +18 -15
  136. package/dist/models/token.mjs.map +1 -1
  137. package/dist/models/user.d.mts +42 -0
  138. package/dist/models/user.mjs +65 -0
  139. package/dist/models/user.mjs.map +1 -0
  140. package/dist/models/webhook.d.mts +50 -0
  141. package/dist/models/webhook.mjs +12 -10
  142. package/dist/models/webhook.mjs.map +1 -1
  143. package/dist/models.d.mts +22 -0
  144. package/dist/models.mjs +23 -0
  145. package/dist/paths.mjs +29 -0
  146. package/dist/paths.mjs.map +1 -1
  147. package/dist/retention.d.mts +45 -0
  148. package/dist/retention.mjs +145 -0
  149. package/dist/retention.mjs.map +1 -0
  150. package/dist/schema/baseline.d.mts +1 -0
  151. package/dist/schema/build.d.mts +8 -0
  152. package/dist/schema/capture-attempt.d.mts +38 -0
  153. package/dist/schema/comment.d.mts +1 -1
  154. package/dist/schema/content-ref.d.mts +13 -0
  155. package/dist/schema/member.d.mts +2 -0
  156. package/dist/schema/notification.d.mts +35 -0
  157. package/dist/schema/project-group-mapping.d.mts +15 -0
  158. package/dist/schema/project.d.mts +4 -0
  159. package/dist/schema/snapshot.d.mts +7 -0
  160. package/dist/schema/token.d.mts +2 -0
  161. package/dist/schema/user.d.mts +11 -1
  162. package/dist/schema.d.mts +9 -46
  163. package/dist/schema.mjs +1 -55
  164. package/dist/test-helpers/create-project.d.mts +15 -0
  165. package/dist/test-helpers/create-project.mjs +28 -0
  166. package/dist/test-helpers/create-project.mjs.map +1 -0
  167. package/dist/test-helpers/database-contract.d.mts +13 -0
  168. package/dist/test-helpers/database-contract.mjs +58 -0
  169. package/dist/test-helpers/database-contract.mjs.map +1 -0
  170. package/dist/test-helpers/fake-adapters.d.mts +14 -0
  171. package/dist/test-helpers/fake-adapters.mjs +20 -0
  172. package/dist/test-helpers/fake-adapters.mjs.map +1 -0
  173. package/dist/test-helpers/fake-database.d.mts +11 -0
  174. package/dist/test-helpers/fake-database.mjs +104 -0
  175. package/dist/test-helpers/fake-database.mjs.map +1 -0
  176. package/dist/test-helpers/fake-storage.d.mts +14 -0
  177. package/dist/test-helpers/fake-storage.mjs +49 -0
  178. package/dist/test-helpers/fake-storage.mjs.map +1 -0
  179. package/dist/test-helpers/fake-tables.mjs +276 -0
  180. package/dist/test-helpers/fake-tables.mjs.map +1 -0
  181. package/dist/test-helpers/git-contract.d.mts +11 -0
  182. package/dist/test-helpers/git-contract.mjs +34 -0
  183. package/dist/test-helpers/git-contract.mjs.map +1 -0
  184. package/dist/test-helpers/notifier-contract.d.mts +11 -0
  185. package/dist/test-helpers/notifier-contract.mjs +34 -0
  186. package/dist/test-helpers/notifier-contract.mjs.map +1 -0
  187. package/dist/test-helpers/queue-contract.d.mts +11 -0
  188. package/dist/test-helpers/queue-contract.mjs +64 -0
  189. package/dist/test-helpers/queue-contract.mjs.map +1 -0
  190. package/dist/test-helpers/runner-contract.d.mts +11 -0
  191. package/dist/test-helpers/runner-contract.mjs +32 -0
  192. package/dist/test-helpers/runner-contract.mjs.map +1 -0
  193. package/dist/test-helpers/sql-chunks.mjs +138 -0
  194. package/dist/test-helpers/sql-chunks.mjs.map +1 -0
  195. package/dist/test-helpers/storage-contract.d.mts +11 -0
  196. package/dist/test-helpers/storage-contract.mjs +87 -0
  197. package/dist/test-helpers/storage-contract.mjs.map +1 -0
  198. package/dist/test-helpers.d.mts +13 -0
  199. package/dist/test-helpers.mjs +14 -0
  200. package/dist/tracing.mjs +63 -0
  201. package/dist/tracing.mjs.map +1 -0
  202. package/dist/types.d.mts +38 -5
  203. package/dist/types.mjs +18 -5
  204. package/dist/types.mjs.map +1 -1
  205. package/dist/urls.d.mts +12 -1
  206. package/dist/urls.mjs +22 -3
  207. package/dist/urls.mjs.map +1 -1
  208. package/dist/utils/encrypt.d.mts +48 -0
  209. package/dist/utils/encrypt.mjs +67 -13
  210. package/dist/utils/encrypt.mjs.map +1 -1
  211. package/dist/utils/hash.d.mts +17 -0
  212. package/dist/utils/hash.mjs +8 -2
  213. package/dist/utils/hash.mjs.map +1 -1
  214. package/dist/utils/http.d.mts +58 -0
  215. package/dist/utils/http.mjs +147 -0
  216. package/dist/utils/http.mjs.map +1 -0
  217. package/dist/utils/mime.d.mts +9 -0
  218. package/dist/utils/mime.mjs +33 -0
  219. package/dist/utils/mime.mjs.map +1 -0
  220. package/dist/utils/path-security.d.mts +12 -0
  221. package/dist/utils/path-security.mjs +24 -0
  222. package/dist/utils/path-security.mjs.map +1 -0
  223. package/dist/utils/redact.d.mts +17 -0
  224. package/dist/utils/redact.mjs +42 -0
  225. package/dist/utils/redact.mjs.map +1 -0
  226. package/dist/utils/timing.d.mts +19 -0
  227. package/dist/utils/timing.mjs +46 -0
  228. package/dist/utils/timing.mjs.map +1 -0
  229. package/dist/utils/ulid.d.mts +10 -0
  230. package/dist/utils/ulid.mjs +8 -8
  231. package/dist/utils/ulid.mjs.map +1 -1
  232. package/dist/utils.d.mts +12 -0
  233. package/dist/utils.mjs +13 -0
  234. package/package.json +69 -28
  235. package/dist/adapter/auth.d.mts +0 -50
  236. package/dist/adapter/auth.mjs +0 -10
  237. package/dist/adapter/auth.mjs.map +0 -1
  238. package/dist/adapter/init.d.mts +0 -58
  239. package/dist/adapter/init.mjs +0 -93
  240. package/dist/adapter/init.mjs.map +0 -1
  241. package/dist/adapters/webhook-events.mjs +0 -55
  242. package/dist/adapters/webhook-events.mjs.map +0 -1
  243. package/dist/ddl.d.mts +0 -8
  244. package/dist/ddl.mjs +0 -158
  245. package/dist/ddl.mjs.map +0 -1
  246. package/dist/index.mjs.map +0 -1
  247. package/dist/middleware/auth-gate.mjs +0 -36
  248. package/dist/middleware/auth-gate.mjs.map +0 -1
  249. package/dist/middleware/csrf.mjs +0 -40
  250. package/dist/middleware/csrf.mjs.map +0 -1
  251. package/dist/middleware/rate-limit.mjs +0 -39
  252. package/dist/middleware/rate-limit.mjs.map +0 -1
  253. package/dist/middleware/request-log.mjs +0 -28
  254. package/dist/middleware/request-log.mjs.map +0 -1
  255. package/dist/middleware/store-scope.mjs +0 -29
  256. package/dist/middleware/store-scope.mjs.map +0 -1
  257. package/dist/pages/build-detail.mjs +0 -339
  258. package/dist/pages/build-detail.mjs.map +0 -1
  259. package/dist/pages/build-diff-comments.mjs +0 -113
  260. package/dist/pages/build-diff-comments.mjs.map +0 -1
  261. package/dist/pages/build-diff-header.mjs +0 -163
  262. package/dist/pages/build-diff-header.mjs.map +0 -1
  263. package/dist/pages/build-diff-nav.mjs +0 -66
  264. package/dist/pages/build-diff-nav.mjs.map +0 -1
  265. package/dist/pages/build-diff-viewer.mjs +0 -197
  266. package/dist/pages/build-diff-viewer.mjs.map +0 -1
  267. package/dist/pages/build-diff.mjs +0 -90
  268. package/dist/pages/build-diff.mjs.map +0 -1
  269. package/dist/pages/compute-jobs.mjs +0 -198
  270. package/dist/pages/compute-jobs.mjs.map +0 -1
  271. package/dist/pages/label-detail.mjs +0 -228
  272. package/dist/pages/label-detail.mjs.map +0 -1
  273. package/dist/pages/login.mjs +0 -78
  274. package/dist/pages/login.mjs.map +0 -1
  275. package/dist/pages/project-builds.mjs +0 -231
  276. package/dist/pages/project-builds.mjs.map +0 -1
  277. package/dist/pages/project-create.mjs +0 -169
  278. package/dist/pages/project-create.mjs.map +0 -1
  279. package/dist/pages/project-settings.mjs +0 -102
  280. package/dist/pages/project-settings.mjs.map +0 -1
  281. package/dist/pages/projects.mjs +0 -184
  282. package/dist/pages/projects.mjs.map +0 -1
  283. package/dist/pages/root.mjs +0 -94
  284. package/dist/pages/root.mjs.map +0 -1
  285. package/dist/pages/settings-general.mjs +0 -192
  286. package/dist/pages/settings-general.mjs.map +0 -1
  287. package/dist/pages/settings-labels.mjs +0 -150
  288. package/dist/pages/settings-labels.mjs.map +0 -1
  289. package/dist/pages/settings-members.mjs +0 -125
  290. package/dist/pages/settings-members.mjs.map +0 -1
  291. package/dist/pages/settings-status.mjs +0 -152
  292. package/dist/pages/settings-status.mjs.map +0 -1
  293. package/dist/pages/settings-tests.mjs +0 -149
  294. package/dist/pages/settings-tests.mjs.map +0 -1
  295. package/dist/pages/settings-tokens.mjs +0 -96
  296. package/dist/pages/settings-tokens.mjs.map +0 -1
  297. package/dist/pages/settings-webhooks.mjs +0 -150
  298. package/dist/pages/settings-webhooks.mjs.map +0 -1
  299. package/dist/pages/storybook.mjs +0 -96
  300. package/dist/pages/storybook.mjs.map +0 -1
  301. package/dist/retention/purge.mjs +0 -70
  302. package/dist/retention/purge.mjs.map +0 -1
  303. package/dist/routers/admin.mjs +0 -42
  304. package/dist/routers/admin.mjs.map +0 -1
  305. package/dist/routers/assets.mjs +0 -25
  306. package/dist/routers/assets.mjs.map +0 -1
  307. package/dist/routers/auth.mjs +0 -78
  308. package/dist/routers/auth.mjs.map +0 -1
  309. package/dist/routers/builds.handlers.mjs +0 -184
  310. package/dist/routers/builds.handlers.mjs.map +0 -1
  311. package/dist/routers/builds.mjs +0 -185
  312. package/dist/routers/builds.mjs.map +0 -1
  313. package/dist/routers/comments.mjs +0 -90
  314. package/dist/routers/comments.mjs.map +0 -1
  315. package/dist/routers/health.mjs +0 -137
  316. package/dist/routers/health.mjs.map +0 -1
  317. package/dist/routers/helpers.mjs +0 -82
  318. package/dist/routers/helpers.mjs.map +0 -1
  319. package/dist/routers/htmx.mjs +0 -20
  320. package/dist/routers/htmx.mjs.map +0 -1
  321. package/dist/routers/labels.mjs +0 -110
  322. package/dist/routers/labels.mjs.map +0 -1
  323. package/dist/routers/media.mjs +0 -55
  324. package/dist/routers/media.mjs.map +0 -1
  325. package/dist/routers/members.mjs +0 -102
  326. package/dist/routers/members.mjs.map +0 -1
  327. package/dist/routers/projects.mjs +0 -122
  328. package/dist/routers/projects.mjs.map +0 -1
  329. package/dist/routers/schemas.mjs +0 -224
  330. package/dist/routers/schemas.mjs.map +0 -1
  331. package/dist/routers/settings-general.mjs +0 -95
  332. package/dist/routers/settings-general.mjs.map +0 -1
  333. package/dist/routers/settings-labels.mjs +0 -49
  334. package/dist/routers/settings-labels.mjs.map +0 -1
  335. package/dist/routers/settings-members.mjs +0 -30
  336. package/dist/routers/settings-members.mjs.map +0 -1
  337. package/dist/routers/settings-status.mjs +0 -73
  338. package/dist/routers/settings-status.mjs.map +0 -1
  339. package/dist/routers/settings-tokens.mjs +0 -40
  340. package/dist/routers/settings-tokens.mjs.map +0 -1
  341. package/dist/routers/settings-webhooks.mjs +0 -63
  342. package/dist/routers/settings-webhooks.mjs.map +0 -1
  343. package/dist/routers/settings.handlers.mjs +0 -93
  344. package/dist/routers/settings.handlers.mjs.map +0 -1
  345. package/dist/routers/settings.mjs +0 -23
  346. package/dist/routers/settings.mjs.map +0 -1
  347. package/dist/routers/snapshots.mjs +0 -144
  348. package/dist/routers/snapshots.mjs.map +0 -1
  349. package/dist/routers/status-configs.mjs +0 -101
  350. package/dist/routers/status-configs.mjs.map +0 -1
  351. package/dist/routers/storybook.mjs +0 -120
  352. package/dist/routers/storybook.mjs.map +0 -1
  353. package/dist/routers/tokens.mjs +0 -81
  354. package/dist/routers/tokens.mjs.map +0 -1
  355. package/dist/routers/ui.mjs +0 -165
  356. package/dist/routers/ui.mjs.map +0 -1
  357. package/dist/routers/webhooks.mjs +0 -90
  358. package/dist/routers/webhooks.mjs.map +0 -1
  359. package/dist/schema/baseline.mjs +0 -22
  360. package/dist/schema/baseline.mjs.map +0 -1
  361. package/dist/schema/build.mjs +0 -29
  362. package/dist/schema/build.mjs.map +0 -1
  363. package/dist/schema/comment.mjs +0 -26
  364. package/dist/schema/comment.mjs.map +0 -1
  365. package/dist/schema/label.mjs +0 -30
  366. package/dist/schema/label.mjs.map +0 -1
  367. package/dist/schema/member.mjs +0 -19
  368. package/dist/schema/member.mjs.map +0 -1
  369. package/dist/schema/project.mjs +0 -25
  370. package/dist/schema/project.mjs.map +0 -1
  371. package/dist/schema/snapshot.mjs +0 -34
  372. package/dist/schema/snapshot.mjs.map +0 -1
  373. package/dist/schema/status-config.mjs +0 -20
  374. package/dist/schema/status-config.mjs.map +0 -1
  375. package/dist/schema/token.mjs +0 -19
  376. package/dist/schema/token.mjs.map +0 -1
  377. package/dist/schema/user.mjs +0 -19
  378. package/dist/schema/user.mjs.map +0 -1
  379. package/dist/schema/webhook.mjs +0 -20
  380. package/dist/schema/webhook.mjs.map +0 -1
  381. package/dist/schema.mjs.map +0 -1
  382. package/dist/store.mjs +0 -20
  383. package/dist/store.mjs.map +0 -1
  384. package/dist/ui/document.mjs +0 -348
  385. package/dist/ui/document.mjs.map +0 -1
  386. package/dist/ui/feedback.mjs +0 -24
  387. package/dist/ui/feedback.mjs.map +0 -1
  388. package/dist/ui/forms.mjs +0 -117
  389. package/dist/ui/forms.mjs.map +0 -1
  390. package/dist/ui/styles.mjs +0 -174
  391. package/dist/ui/styles.mjs.map +0 -1
  392. package/dist/ui/theme.mjs +0 -44
  393. package/dist/ui/theme.mjs.map +0 -1
@@ -1,152 +0,0 @@
1
- import "node:path";
2
- import "node:url";
3
- import.meta.url;
4
- import { Badge } from "../ui/feedback.mjs";
5
- import { Field, SelectField, TextareaField } from "../ui/forms.mjs";
6
- import { jsx, jsxs } from "hono/jsx/jsx-runtime";
7
- //#region src/pages/settings-status.tsx
8
- function providerOptions(providers) {
9
- return providers.map((provider) => ({
10
- value: provider.metadata.kind,
11
- label: provider.metadata.name
12
- }));
13
- }
14
- const StatusConfigRow = ({ config, provider, project, isAdmin }) => {
15
- const rendered = JSON.stringify(config.config);
16
- return /* @__PURE__ */ jsxs("tr", { children: [
17
- /* @__PURE__ */ jsx("td", { children: provider?.metadata.name ?? config.provider }),
18
- /* @__PURE__ */ jsx("td", {
19
- style: "max-width:32ch; overflow:hidden; text-overflow:ellipsis; white-space:nowrap;",
20
- title: rendered,
21
- children: /* @__PURE__ */ jsx("code", { children: rendered })
22
- }),
23
- /* @__PURE__ */ jsx("td", { children: config.hasToken ? /* @__PURE__ */ jsx(Badge, {
24
- tone: "success",
25
- children: "configured"
26
- }) : /* @__PURE__ */ jsx(Badge, {
27
- tone: "danger",
28
- children: "missing"
29
- }) }),
30
- /* @__PURE__ */ jsx("td", { children: new Date(config.createdAt).toLocaleDateString() }),
31
- /* @__PURE__ */ jsx("td", { children: isAdmin ? /* @__PURE__ */ jsx("form", {
32
- method: "post",
33
- action: `/projects/${project.slug}/settings/status/${config.id}/delete`,
34
- "hx-post": `/projects/${project.slug}/settings/status/${config.id}/delete`,
35
- "hx-target": "body",
36
- children: /* @__PURE__ */ jsx("button", {
37
- class: "btn btn--ghost",
38
- type: "submit",
39
- children: "Delete"
40
- })
41
- }) : null })
42
- ] }, config.id);
43
- };
44
- const StatusCreateCard = ({ project, providers, formState }) => {
45
- return /* @__PURE__ */ jsxs("div", {
46
- class: "card card--padded",
47
- children: [/* @__PURE__ */ jsx("h3", {
48
- style: "margin:0 0 .5rem;",
49
- children: "Add git provider"
50
- }), /* @__PURE__ */ jsxs("form", {
51
- method: "post",
52
- action: `/projects/${project.slug}/settings/status`,
53
- "hx-post": `/projects/${project.slug}/settings/status`,
54
- "hx-target": "body",
55
- children: [
56
- /* @__PURE__ */ jsx(SelectField, {
57
- label: "Provider",
58
- name: "provider",
59
- options: providerOptions(providers),
60
- hint: "Integration that posts commit statuses for this project."
61
- }),
62
- /* @__PURE__ */ jsx(Field, {
63
- label: "Token",
64
- name: "token",
65
- type: "password",
66
- required: true,
67
- placeholder: "ghp_…",
68
- error: formState?.errors?.["token"],
69
- hint: "Scoped token for the provider (e.g. a GitHub PAT with repo:status)."
70
- }),
71
- /* @__PURE__ */ jsx(TextareaField, {
72
- label: "Config",
73
- name: "config",
74
- rows: 6,
75
- placeholder: "{\"owner\":\"my-org\",\"repo\":\"my-repo\"}",
76
- error: formState?.errors?.["config"],
77
- hint: "JSON configuration for the provider. See the provider documentation for its fields."
78
- }),
79
- /* @__PURE__ */ jsx("button", {
80
- class: "btn btn--primary",
81
- type: "submit",
82
- children: "Add git provider"
83
- })
84
- ]
85
- })]
86
- });
87
- };
88
- function renderCreateSection(project, providers, formState) {
89
- if (providers.length === 0) return /* @__PURE__ */ jsx("p", {
90
- class: "field__hint",
91
- children: "No git providers registered on this server."
92
- });
93
- return /* @__PURE__ */ jsx(StatusCreateCard, {
94
- project,
95
- providers,
96
- formState
97
- });
98
- }
99
- /** Git status settings tab: configured providers plus the add-provider form. */
100
- function renderSettingsStatus(project, statusConfigs, providers, isAdmin, formState) {
101
- const byProvider = new Map(providers.map((provider) => [provider.metadata.kind, provider]));
102
- return /* @__PURE__ */ jsxs("div", {
103
- class: "grid",
104
- style: "max-width: 880px;",
105
- children: [
106
- formState?.globalError ? /* @__PURE__ */ jsx("div", {
107
- class: "alert alert--danger",
108
- role: "alert",
109
- children: formState.globalError
110
- }) : null,
111
- /* @__PURE__ */ jsxs("div", {
112
- class: "card card--padded",
113
- children: [
114
- /* @__PURE__ */ jsx("h2", {
115
- style: "margin:0 0 .3rem;",
116
- children: "Git status"
117
- }),
118
- /* @__PURE__ */ jsx("p", {
119
- class: "field__hint",
120
- children: "Post commit statuses to a git provider so visual tests show up in your PR checks. Status is reported for each configured provider: pending while capturing, success on approval, failure on rejection or capture errors."
121
- }),
122
- /* @__PURE__ */ jsx("div", {
123
- class: "table-wrap",
124
- style: "margin-top:.75rem;",
125
- children: /* @__PURE__ */ jsxs("table", { children: [/* @__PURE__ */ jsx("thead", { children: /* @__PURE__ */ jsxs("tr", { children: [
126
- /* @__PURE__ */ jsx("th", { children: "Provider" }),
127
- /* @__PURE__ */ jsx("th", { children: "Config" }),
128
- /* @__PURE__ */ jsx("th", { children: "Token" }),
129
- /* @__PURE__ */ jsx("th", { children: "Created" }),
130
- /* @__PURE__ */ jsx("th", {})
131
- ] }) }), /* @__PURE__ */ jsx("tbody", { children: statusConfigs.map((config) => /* @__PURE__ */ jsx(StatusConfigRow, {
132
- config,
133
- provider: byProvider.get(config.provider),
134
- project,
135
- isAdmin
136
- }, config.id)) })] })
137
- }),
138
- statusConfigs.length === 0 ? /* @__PURE__ */ jsx("p", {
139
- class: "field__hint",
140
- style: "margin-top:.5rem;",
141
- children: "No git providers configured for this project."
142
- }) : null
143
- ]
144
- }),
145
- isAdmin ? renderCreateSection(project, providers, formState) : null
146
- ]
147
- });
148
- }
149
- //#endregion
150
- export { renderSettingsStatus };
151
-
152
- //# sourceMappingURL=settings-status.mjs.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"settings-status.mjs","names":[],"sources":["../../src/pages/settings-status.tsx"],"sourcesContent":["import type { FC } from \"hono/jsx\";\nimport type { GitHostProvider } from \"../adapters/git-host/index.ts\";\nimport type { Project } from \"../schema/project.ts\";\nimport { Badge, Field, SelectField, TextareaField } from \"../ui/components.tsx\";\n\n/** Git status configuration row as rendered in the status settings tab. */\nexport interface SettingsStatusConfig {\n id: string;\n provider: string;\n config: Record<string, unknown>;\n hasToken: boolean;\n createdAt: string;\n updatedAt: string;\n}\n\n/** Form state for the git status settings tab. */\nexport interface StatusFormState {\n errors?: Record<string, string>;\n globalError?: string;\n}\n\n/* eslint-disable promise-function-async -- JSX components return HtmlEscapedString | Promise<HtmlEscapedString> */\n\nfunction providerOptions(providers: GitHostProvider[]): { value: string; label: string }[] {\n return providers.map((provider) => ({\n value: provider.metadata.kind,\n label: provider.metadata.name,\n }));\n}\n\nconst StatusConfigRow: FC<{\n config: SettingsStatusConfig;\n provider: GitHostProvider | undefined;\n project: Project;\n isAdmin: boolean;\n}> = ({ config, provider, project, isAdmin }) => {\n const rendered = JSON.stringify(config.config);\n return (\n <tr key={config.id}>\n <td>{provider?.metadata.name ?? config.provider}</td>\n <td\n style=\"max-width:32ch; overflow:hidden; text-overflow:ellipsis; white-space:nowrap;\"\n title={rendered}\n >\n <code>{rendered}</code>\n </td>\n <td>\n {config.hasToken ? (\n <Badge tone=\"success\">configured</Badge>\n ) : (\n <Badge tone=\"danger\">missing</Badge>\n )}\n </td>\n <td>{new Date(config.createdAt).toLocaleDateString()}</td>\n <td>\n {isAdmin ? (\n <form\n method=\"post\"\n action={`/projects/${project.slug}/settings/status/${config.id}/delete`}\n hx-post={`/projects/${project.slug}/settings/status/${config.id}/delete`}\n hx-target=\"body\"\n >\n <button class=\"btn btn--ghost\" type=\"submit\">\n Delete\n </button>\n </form>\n ) : null}\n </td>\n </tr>\n );\n};\n\nconst StatusCreateCard: FC<{\n project: Project;\n providers: GitHostProvider[];\n formState?: StatusFormState;\n}> = ({ project, providers, formState }) => {\n return (\n <div class=\"card card--padded\">\n <h3 style=\"margin:0 0 .5rem;\">Add git provider</h3>\n <form\n method=\"post\"\n action={`/projects/${project.slug}/settings/status`}\n hx-post={`/projects/${project.slug}/settings/status`}\n hx-target=\"body\"\n >\n <SelectField\n label=\"Provider\"\n name=\"provider\"\n options={providerOptions(providers)}\n hint=\"Integration that posts commit statuses for this project.\"\n />\n <Field\n label=\"Token\"\n name=\"token\"\n type=\"password\"\n required\n placeholder=\"ghp_…\"\n error={formState?.errors?.[\"token\"]}\n hint=\"Scoped token for the provider (e.g. a GitHub PAT with repo:status).\"\n />\n <TextareaField\n label=\"Config\"\n name=\"config\"\n rows={6}\n placeholder='{\"owner\":\"my-org\",\"repo\":\"my-repo\"}'\n error={formState?.errors?.[\"config\"]}\n hint=\"JSON configuration for the provider. See the provider documentation for its fields.\"\n />\n <button class=\"btn btn--primary\" type=\"submit\">\n Add git provider\n </button>\n </form>\n </div>\n );\n};\n\nfunction renderCreateSection(\n project: Project,\n providers: GitHostProvider[],\n formState?: StatusFormState,\n): unknown {\n if (providers.length === 0) {\n return <p class=\"field__hint\">No git providers registered on this server.</p>;\n }\n return <StatusCreateCard project={project} providers={providers} formState={formState} />;\n}\n\n/** Git status settings tab: configured providers plus the add-provider form. */\n// eslint-disable-next-line max-params -- matches sibling settings render functions\nexport function renderSettingsStatus(\n project: Project,\n statusConfigs: SettingsStatusConfig[],\n providers: GitHostProvider[],\n isAdmin: boolean,\n formState?: StatusFormState,\n): unknown {\n const byProvider = new Map(providers.map((provider) => [provider.metadata.kind, provider]));\n return (\n <div class=\"grid\" style=\"max-width: 880px;\">\n {formState?.globalError ? (\n <div class=\"alert alert--danger\" role=\"alert\">\n {formState.globalError}\n </div>\n ) : null}\n\n <div class=\"card card--padded\">\n <h2 style=\"margin:0 0 .3rem;\">Git status</h2>\n <p class=\"field__hint\">\n Post commit statuses to a git provider so visual tests show up in your PR checks. Status\n is reported for each configured provider: pending while capturing, success on approval,\n failure on rejection or capture errors.\n </p>\n <div class=\"table-wrap\" style=\"margin-top:.75rem;\">\n <table>\n <thead>\n <tr>\n <th>Provider</th>\n <th>Config</th>\n <th>Token</th>\n <th>Created</th>\n <th></th>\n </tr>\n </thead>\n <tbody>\n {statusConfigs.map((config) => (\n <StatusConfigRow\n key={config.id}\n config={config}\n provider={byProvider.get(config.provider)}\n project={project}\n isAdmin={isAdmin}\n />\n ))}\n </tbody>\n </table>\n </div>\n {statusConfigs.length === 0 ? (\n <p class=\"field__hint\" style=\"margin-top:.5rem;\">\n No git providers configured for this project.\n </p>\n ) : null}\n </div>\n\n {isAdmin ? renderCreateSection(project, providers, formState) : null}\n </div>\n );\n}\n"],"mappings":"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"}
@@ -1,149 +0,0 @@
1
- import "node:path";
2
- import "node:url";
3
- import.meta.url;
4
- import { jsx, jsxs } from "hono/jsx/jsx-runtime";
5
- //#region src/pages/settings-tests.tsx
6
- /** Interaction-tests settings tab: play execution toggle and timeout. */
7
- function renderSettingsTests(project, isAdmin, formState) {
8
- return /* @__PURE__ */ jsxs("div", {
9
- class: "grid",
10
- style: "max-width: 720px;",
11
- children: [
12
- formState?.globalError ? /* @__PURE__ */ jsx("div", {
13
- class: "alert alert--danger",
14
- role: "alert",
15
- children: formState.globalError
16
- }) : null,
17
- /* @__PURE__ */ jsxs("div", {
18
- class: "card card--padded",
19
- children: [
20
- /* @__PURE__ */ jsx("h2", {
21
- style: "margin:0 0 .5rem;",
22
- children: "Interaction tests"
23
- }),
24
- /* @__PURE__ */ jsxs("p", {
25
- class: "field__hint",
26
- style: "margin-bottom:1rem;",
27
- children: [
28
- "When enabled, Storybook ",
29
- /* @__PURE__ */ jsx("code", { children: "play" }),
30
- " functions run before each screenshot. Failures block the build unless the story is marked",
31
- /* @__PURE__ */ jsx("code", { children: "flaky-test" }),
32
- " via ",
33
- /* @__PURE__ */ jsx("code", { children: "tags: ['flaky-test']" }),
34
- " or",
35
- /* @__PURE__ */ jsx("code", { children: "parameters: { flakyTest: true }" }),
36
- " (supports both",
37
- " ",
38
- /* @__PURE__ */ jsx("code", { children: "chromatic" }),
39
- " and ",
40
- /* @__PURE__ */ jsx("code", { children: "storyshelf" }),
41
- " keys, story-level, case-insensitive). Use ",
42
- /* @__PURE__ */ jsx("code", { children: "disableSnapshot" }),
43
- " to skip a story entirely."
44
- ]
45
- }),
46
- /* @__PURE__ */ jsxs("form", {
47
- method: "post",
48
- action: `/projects/${project.slug}/settings/tests`,
49
- "hx-post": `/projects/${project.slug}/settings/tests`,
50
- "hx-target": "body",
51
- "hx-swap": "outerHTML",
52
- children: [
53
- /* @__PURE__ */ jsxs("div", {
54
- class: "field",
55
- children: [/* @__PURE__ */ jsxs("label", {
56
- class: "field__label",
57
- style: "display:flex; gap:.5rem; align-items:center;",
58
- children: [/* @__PURE__ */ jsx("input", {
59
- type: "checkbox",
60
- name: "executePlay",
61
- value: "true",
62
- checked: project.executePlay ? true : void 0,
63
- disabled: !isAdmin
64
- }), "Enable interaction tests (play)"]
65
- }), /* @__PURE__ */ jsx("p", {
66
- class: "field__hint",
67
- children: "When enabled, failing play blocks the build (failed). Flaky stories show warnings but status stays successful."
68
- })]
69
- }),
70
- /* @__PURE__ */ jsxs("div", {
71
- class: "field",
72
- children: [
73
- /* @__PURE__ */ jsx("label", {
74
- class: "field__label",
75
- for: "playTimeoutMs",
76
- children: "Play timeout (ms)"
77
- }),
78
- /* @__PURE__ */ jsx("input", {
79
- class: "field__input",
80
- id: "playTimeoutMs",
81
- name: "playTimeoutMs",
82
- type: "number",
83
- min: "1000",
84
- max: "30000",
85
- step: "1000",
86
- value: String(project.playTimeoutMs),
87
- disabled: !isAdmin
88
- }),
89
- /* @__PURE__ */ jsx("p", {
90
- class: "field__hint",
91
- children: "Timeout for each play function (1000–30000 ms, default 10000)."
92
- })
93
- ]
94
- }),
95
- isAdmin ? /* @__PURE__ */ jsx("button", {
96
- class: "btn btn--primary",
97
- type: "submit",
98
- children: "Save changes"
99
- }) : /* @__PURE__ */ jsx("p", {
100
- class: "field__hint",
101
- children: "You need admin access to edit settings."
102
- })
103
- ]
104
- })
105
- ]
106
- }),
107
- /* @__PURE__ */ jsxs("div", {
108
- class: "card card--padded",
109
- children: [
110
- /* @__PURE__ */ jsx("h3", {
111
- style: "margin:0 0 .4rem;",
112
- children: "How to mark stories"
113
- }),
114
- /* @__PURE__ */ jsx("pre", {
115
- class: "field__hint",
116
- style: "white-space:pre-wrap; background: var(--surface); padding:.75rem; border-radius:.5rem;",
117
- children: `// Disable snapshot entirely (skip capture + play)
118
- export const Hidden: Story = {
119
- parameters: { storyshelf: { disableSnapshot: true } }
120
- };
121
- // Mark as flaky (non-blocking, shows warning)
122
- export const Flaky: Story = {
123
- tags: ['flaky-test'],
124
- play: async ({canvasElement}) => { /* ... */ }
125
- };
126
- // or via parameters (both keys work, storyshelf wins)
127
- export const Flaky2: Story = {
128
- parameters: { chromatic: { flakyTest: true } }
129
- };`
130
- }),
131
- /* @__PURE__ */ jsxs("p", {
132
- class: "field__hint",
133
- children: [
134
- "Tags are story-level and case-insensitive (",
135
- /* @__PURE__ */ jsx("code", { children: "flaky-test" }),
136
- "). Whole story is non-blocking when flaky. GitHub status stays",
137
- /* @__PURE__ */ jsx("code", { children: "success" }),
138
- " with a warning comment."
139
- ]
140
- })
141
- ]
142
- })
143
- ]
144
- });
145
- }
146
- //#endregion
147
- export { renderSettingsTests };
148
-
149
- //# sourceMappingURL=settings-tests.mjs.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"settings-tests.mjs","names":[],"sources":["../../src/pages/settings-tests.tsx"],"sourcesContent":["import type { Project } from \"../schema/project.ts\";\n\n/** Interaction-tests settings tab: play execution toggle and timeout. */\nexport function renderSettingsTests(\n project: Project,\n isAdmin: boolean,\n formState?: { globalError?: string },\n): unknown {\n return (\n <div class=\"grid\" style=\"max-width: 720px;\">\n {formState?.globalError ? (\n <div class=\"alert alert--danger\" role=\"alert\">\n {formState.globalError}\n </div>\n ) : null}\n <div class=\"card card--padded\">\n <h2 style=\"margin:0 0 .5rem;\">Interaction tests</h2>\n <p class=\"field__hint\" style=\"margin-bottom:1rem;\">\n When enabled, Storybook <code>play</code> functions run before each screenshot. Failures\n block the build unless the story is marked\n <code>flaky-test</code> via <code>tags: ['flaky-test']</code> or\n <code>parameters: &#123; flakyTest: true &#125;</code> (supports both{\" \"}\n <code>chromatic</code> and <code>storyshelf</code> keys, story-level, case-insensitive).\n Use <code>disableSnapshot</code> to skip a story entirely.\n </p>\n <form\n method=\"post\"\n action={`/projects/${project.slug}/settings/tests`}\n hx-post={`/projects/${project.slug}/settings/tests`}\n hx-target=\"body\"\n hx-swap=\"outerHTML\"\n >\n <div class=\"field\">\n <label class=\"field__label\" style=\"display:flex; gap:.5rem; align-items:center;\">\n <input\n type=\"checkbox\"\n name=\"executePlay\"\n value=\"true\"\n checked={project.executePlay ? true : undefined}\n disabled={!isAdmin}\n />\n Enable interaction tests (play)\n </label>\n <p class=\"field__hint\">\n When enabled, failing play blocks the build (failed). Flaky stories show warnings but\n status stays successful.\n </p>\n </div>\n <div class=\"field\">\n <label class=\"field__label\" for=\"playTimeoutMs\">\n Play timeout (ms)\n </label>\n <input\n class=\"field__input\"\n id=\"playTimeoutMs\"\n name=\"playTimeoutMs\"\n type=\"number\"\n min=\"1000\"\n max=\"30000\"\n step=\"1000\"\n value={String(project.playTimeoutMs)}\n disabled={!isAdmin}\n />\n <p class=\"field__hint\">\n Timeout for each play function (1000–30000 ms, default 10000).\n </p>\n </div>\n {isAdmin ? (\n <button class=\"btn btn--primary\" type=\"submit\">\n Save changes\n </button>\n ) : (\n <p class=\"field__hint\">You need admin access to edit settings.</p>\n )}\n </form>\n </div>\n <div class=\"card card--padded\">\n <h3 style=\"margin:0 0 .4rem;\">How to mark stories</h3>\n <pre\n class=\"field__hint\"\n style=\"white-space:pre-wrap; background: var(--surface); padding:.75rem; border-radius:.5rem;\"\n >\n {`// Disable snapshot entirely (skip capture + play)\nexport const Hidden: Story = {\n parameters: { storyshelf: { disableSnapshot: true } }\n};\n// Mark as flaky (non-blocking, shows warning)\nexport const Flaky: Story = {\n tags: ['flaky-test'],\n play: async ({canvasElement}) => { /* ... */ }\n};\n// or via parameters (both keys work, storyshelf wins)\nexport const Flaky2: Story = {\n parameters: { chromatic: { flakyTest: true } }\n};`}\n </pre>\n <p class=\"field__hint\">\n Tags are story-level and case-insensitive (<code>flaky-test</code>). Whole story is\n non-blocking when flaky. GitHub status stays\n <code>success</code> with a warning comment.\n </p>\n </div>\n </div>\n );\n}\n"],"mappings":";;;;;;AAGA,SAAgB,oBACd,SACA,SACA,WACS;CACT,OACE,qBAAC,OAAD;EAAK,OAAM;EAAO,OAAM;EAAxB,UAAA;GACG,WAAW,cACV,oBAAC,OAAD;IAAK,OAAM;IAAsB,MAAK;IACnC,UAAA,UAAU;GACR,CAAA,IACH;GACJ,qBAAC,OAAD;IAAK,OAAM;IAAX,UAAA;KACE,oBAAC,MAAD;MAAI,OAAM;MAAoB,UAAA;KAAqB,CAAA;KACnD,qBAAC,KAAD;MAAG,OAAM;MAAc,OAAM;MAA7B,UAAA;OAAmD;OACzB,oBAAC,QAAD,EAAA,UAAM,OAAU,CAAA;OAAC;OAEzC,oBAAC,QAAD,EAAA,UAAM,aAAgB,CAAA;OAAC;OAAK,oBAAC,QAAD,EAAA,UAAM,uBAA0B,CAAA;OAAC;OAC7D,oBAAC,QAAD,EAAA,UAAM,kCAA+C,CAAA;OAAC;OAAgB;OACtE,oBAAC,QAAD,EAAA,UAAM,YAAe,CAAA;OAAC;OAAK,oBAAC,QAAD,EAAA,UAAM,aAAgB,CAAA;OAAC;OAC9C,oBAAC,QAAD,EAAA,UAAM,kBAAqB,CAAA;OAAC;MAC/B;;KACH,qBAAC,QAAD;MACE,QAAO;MACP,QAAQ,aAAa,QAAQ,KAAK;MAClC,WAAS,aAAa,QAAQ,KAAK;MACnC,aAAU;MACV,WAAQ;MALV,UAAA;OAOE,qBAAC,OAAD;QAAK,OAAM;QAAX,UAAA,CACE,qBAAC,SAAD;SAAO,OAAM;SAAe,OAAM;SAAlC,UAAA,CACE,oBAAC,SAAD;UACE,MAAK;UACL,MAAK;UACL,OAAM;UACN,SAAS,QAAQ,cAAc,OAAO,KAAA;UACtC,UAAU,CAAC;SACZ,CAAA,GAAC,iCAEG;QACP,CAAA,GAAA,oBAAC,KAAD;SAAG,OAAM;SAAc,UAAA;QAGpB,CAAA,CACA;;OACL,qBAAC,OAAD;QAAK,OAAM;QAAX,UAAA;SACE,oBAAC,SAAD;UAAO,OAAM;UAAe,KAAI;UAAgB,UAAA;SAEzC,CAAA;SACP,oBAAC,SAAD;UACE,OAAM;UACN,IAAG;UACH,MAAK;UACL,MAAK;UACL,KAAI;UACJ,KAAI;UACJ,MAAK;UACL,OAAO,OAAO,QAAQ,aAAa;UACnC,UAAU,CAAC;SACZ,CAAA;SACD,oBAAC,KAAD;UAAG,OAAM;UAAc,UAAA;SAEpB,CAAA;QACA;;OACJ,UACC,oBAAC,UAAD;QAAQ,OAAM;QAAmB,MAAK;QAAS,UAAA;OAEvC,CAAA,IAER,oBAAC,KAAD;QAAG,OAAM;QAAc,UAAA;OAA0C,CAAA;MAE/D;;IACH;;GACL,qBAAC,OAAD;IAAK,OAAM;IAAX,UAAA;KACE,oBAAC,MAAD;MAAI,OAAM;MAAoB,UAAA;KAAuB,CAAA;KACrD,oBAAC,OAAD;MACE,OAAM;MACN,OAAM;MAEL,UAAA;;;;;;;;;;;;;KAaE,CAAA;KACL,qBAAC,KAAD;MAAG,OAAM;MAAT,UAAA;OAAuB;OACsB,oBAAC,QAAD,EAAA,UAAM,aAAgB,CAAA;OAAC;OAElE,oBAAC,QAAD,EAAA,UAAM,UAAa,CAAA;OAAC;MACnB;;IACA;;EACF;;AAET"}
@@ -1,96 +0,0 @@
1
- import "node:path";
2
- import "node:url";
3
- import.meta.url;
4
- import { jsx, jsxs } from "hono/jsx/jsx-runtime";
5
- //#region src/pages/settings-tokens.tsx
6
- /** Tokens settings tab: project CLI tokens plus the create-token form. */
7
- function renderSettingsTokens(project, tokens, isAdmin) {
8
- return /* @__PURE__ */ jsxs("div", {
9
- class: "grid",
10
- style: "max-width: 880px;",
11
- children: [/* @__PURE__ */ jsxs("div", {
12
- class: "card card--padded",
13
- children: [
14
- /* @__PURE__ */ jsx("h2", {
15
- style: "margin:0 0 .3rem;",
16
- children: "API tokens"
17
- }),
18
- /* @__PURE__ */ jsx("p", {
19
- class: "field__hint",
20
- children: "Tokens are used by the CLI to upload builds. They are scoped to this project."
21
- }),
22
- /* @__PURE__ */ jsx("div", {
23
- class: "table-wrap",
24
- style: "margin-top:.75rem;",
25
- children: /* @__PURE__ */ jsxs("table", { children: [/* @__PURE__ */ jsx("thead", { children: /* @__PURE__ */ jsxs("tr", { children: [
26
- /* @__PURE__ */ jsx("th", { children: "Name" }),
27
- /* @__PURE__ */ jsx("th", { children: "Created" }),
28
- /* @__PURE__ */ jsx("th", { children: "Last used" }),
29
- /* @__PURE__ */ jsx("th", {})
30
- ] }) }), /* @__PURE__ */ jsx("tbody", { children: tokens.map((token) => /* @__PURE__ */ jsxs("tr", { children: [
31
- /* @__PURE__ */ jsx("td", { children: token.name }),
32
- /* @__PURE__ */ jsx("td", { children: new Date(token.createdAt).toLocaleDateString() }),
33
- /* @__PURE__ */ jsx("td", { children: token.lastUsedAt ? new Date(token.lastUsedAt).toLocaleDateString() : "—" }),
34
- /* @__PURE__ */ jsx("td", { children: isAdmin ? /* @__PURE__ */ jsx("form", {
35
- method: "post",
36
- action: `/projects/${project.slug}/settings/tokens/${token.id}/delete`,
37
- "hx-post": `/projects/${project.slug}/settings/tokens/${token.id}/delete`,
38
- "hx-target": "body",
39
- children: /* @__PURE__ */ jsx("button", {
40
- class: "btn btn--ghost",
41
- type: "submit",
42
- children: "Revoke"
43
- })
44
- }) : null })
45
- ] }, token.id)) })] })
46
- }),
47
- tokens.length === 0 ? /* @__PURE__ */ jsx("p", {
48
- class: "field__hint",
49
- style: "margin-top:.5rem;",
50
- children: "No tokens yet. Create one for CI."
51
- }) : null
52
- ]
53
- }), isAdmin ? /* @__PURE__ */ jsxs("div", {
54
- class: "card card--padded",
55
- children: [
56
- /* @__PURE__ */ jsx("h3", {
57
- style: "margin:0 0 .5rem;",
58
- children: "Create token"
59
- }),
60
- /* @__PURE__ */ jsxs("form", {
61
- method: "post",
62
- action: `/projects/${project.slug}/settings/tokens`,
63
- "hx-post": `/projects/${project.slug}/settings/tokens`,
64
- "hx-target": "body",
65
- children: [/* @__PURE__ */ jsxs("div", {
66
- class: "field",
67
- children: [/* @__PURE__ */ jsx("label", {
68
- class: "field__label",
69
- for: "tokenName",
70
- children: "Name"
71
- }), /* @__PURE__ */ jsx("input", {
72
- class: "field__input",
73
- id: "tokenName",
74
- name: "tokenName",
75
- required: true,
76
- placeholder: "ci"
77
- })]
78
- }), /* @__PURE__ */ jsx("button", {
79
- class: "btn btn--primary",
80
- type: "submit",
81
- children: "Create token"
82
- })]
83
- }),
84
- /* @__PURE__ */ jsx("p", {
85
- class: "field__hint",
86
- style: "margin-top:.5rem;",
87
- children: "Token value is shown once after creation. Store it securely."
88
- })
89
- ]
90
- }) : null]
91
- });
92
- }
93
- //#endregion
94
- export { renderSettingsTokens };
95
-
96
- //# sourceMappingURL=settings-tokens.mjs.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"settings-tokens.mjs","names":[],"sources":["../../src/pages/settings-tokens.tsx"],"sourcesContent":["import type { HtmlEscapedString } from \"hono/utils/html\";\nimport type { Project } from \"../schema/project.ts\";\nimport type { Token } from \"../schema/token.ts\";\n\n/** Tokens settings tab: project CLI tokens plus the create-token form. */\nexport function renderSettingsTokens(\n project: Project,\n tokens: Omit<Token, \"hash\">[],\n isAdmin: boolean,\n): unknown {\n return (\n <div class=\"grid\" style=\"max-width: 880px;\">\n <div class=\"card card--padded\">\n <h2 style=\"margin:0 0 .3rem;\">API tokens</h2>\n <p class=\"field__hint\">\n Tokens are used by the CLI to upload builds. They are scoped to this project.\n </p>\n <div class=\"table-wrap\" style=\"margin-top:.75rem;\">\n <table>\n <thead>\n <tr>\n <th>Name</th>\n <th>Created</th>\n <th>Last used</th>\n <th></th>\n </tr>\n </thead>\n <tbody>\n {tokens.map((token): HtmlEscapedString | Promise<HtmlEscapedString> => (\n <tr key={token.id}>\n <td>{token.name}</td>\n <td>{new Date(token.createdAt).toLocaleDateString()}</td>\n <td>\n {token.lastUsedAt ? new Date(token.lastUsedAt).toLocaleDateString() : \"—\"}\n </td>\n <td>\n {isAdmin ? (\n <form\n method=\"post\"\n action={`/projects/${project.slug}/settings/tokens/${token.id}/delete`}\n hx-post={`/projects/${project.slug}/settings/tokens/${token.id}/delete`}\n hx-target=\"body\"\n >\n <button class=\"btn btn--ghost\" type=\"submit\">\n Revoke\n </button>\n </form>\n ) : null}\n </td>\n </tr>\n ))}\n </tbody>\n </table>\n </div>\n {tokens.length === 0 ? (\n <p class=\"field__hint\" style=\"margin-top:.5rem;\">\n No tokens yet. Create one for CI.\n </p>\n ) : null}\n </div>\n\n {isAdmin ? (\n <div class=\"card card--padded\">\n <h3 style=\"margin:0 0 .5rem;\">Create token</h3>\n <form\n method=\"post\"\n action={`/projects/${project.slug}/settings/tokens`}\n hx-post={`/projects/${project.slug}/settings/tokens`}\n hx-target=\"body\"\n >\n <div class=\"field\">\n <label class=\"field__label\" for=\"tokenName\">\n Name\n </label>\n <input\n class=\"field__input\"\n id=\"tokenName\"\n name=\"tokenName\"\n required\n placeholder=\"ci\"\n />\n </div>\n <button class=\"btn btn--primary\" type=\"submit\">\n Create token\n </button>\n </form>\n <p class=\"field__hint\" style=\"margin-top:.5rem;\">\n Token value is shown once after creation. Store it securely.\n </p>\n </div>\n ) : null}\n </div>\n );\n}\n"],"mappings":";;;;;;AAKA,SAAgB,qBACd,SACA,QACA,SACS;CACT,OACE,qBAAC,OAAD;EAAK,OAAM;EAAO,OAAM;EAAxB,UAAA,CACE,qBAAC,OAAD;GAAK,OAAM;GAAX,UAAA;IACE,oBAAC,MAAD;KAAI,OAAM;KAAoB,UAAA;IAAc,CAAA;IAC5C,oBAAC,KAAD;KAAG,OAAM;KAAc,UAAA;IAEpB,CAAA;IACH,oBAAC,OAAD;KAAK,OAAM;KAAa,OAAM;KAC5B,UAAA,qBAAC,SAAD,EAAA,UAAA,CACE,oBAAC,SAAD,EAAA,UACE,qBAAC,MAAD,EAAA,UAAA;MACE,oBAAC,MAAD,EAAA,UAAI,OAAQ,CAAA;MACZ,oBAAC,MAAD,EAAA,UAAI,UAAW,CAAA;MACf,oBAAC,MAAD,EAAA,UAAI,YAAa,CAAA;MACjB,oBAAC,MAAD,CAAQ,CAAA;KACN,EAAA,CAAA,EACC,CAAA,GACP,oBAAC,SAAD,EAAA,UACG,OAAO,KAAK,UACX,qBAAC,MAAD,EAAA,UAAA;MACE,oBAAC,MAAD,EAAA,UAAK,MAAM,KAAS,CAAA;MACpB,oBAAC,MAAD,EAAA,UAAK,IAAI,KAAK,MAAM,SAAS,CAAC,CAAC,mBAAmB,EAAM,CAAA;MACxD,oBAAC,MAAD,EAAA,UACG,MAAM,aAAa,IAAI,KAAK,MAAM,UAAU,CAAC,CAAC,mBAAmB,IAAI,IACpE,CAAA;MACJ,oBAAC,MAAD,EAAA,UACG,UACC,oBAAC,QAAD;OACE,QAAO;OACP,QAAQ,aAAa,QAAQ,KAAK,mBAAmB,MAAM,GAAG;OAC9D,WAAS,aAAa,QAAQ,KAAK,mBAAmB,MAAM,GAAG;OAC/D,aAAU;OAEV,UAAA,oBAAC,UAAD;QAAQ,OAAM;QAAiB,MAAK;QAAS,UAAA;OAErC,CAAA;MACJ,CAAA,IACJ,KACF,CAAA;KACF,EAAA,GApBK,MAAM,EAoBX,CACL,EACI,CAAA,CACF,EAAA,CAAA;IACJ,CAAA;IACJ,OAAO,WAAW,IACjB,oBAAC,KAAD;KAAG,OAAM;KAAc,OAAM;KAAoB,UAAA;IAE9C,CAAA,IACD;GACD;EAEJ,CAAA,GAAA,UACC,qBAAC,OAAD;GAAK,OAAM;GAAX,UAAA;IACE,oBAAC,MAAD;KAAI,OAAM;KAAoB,UAAA;IAAgB,CAAA;IAC9C,qBAAC,QAAD;KACE,QAAO;KACP,QAAQ,aAAa,QAAQ,KAAK;KAClC,WAAS,aAAa,QAAQ,KAAK;KACnC,aAAU;KAJZ,UAAA,CAME,qBAAC,OAAD;MAAK,OAAM;MAAX,UAAA,CACE,oBAAC,SAAD;OAAO,OAAM;OAAe,KAAI;OAAY,UAAA;MAErC,CAAA,GACP,oBAAC,SAAD;OACE,OAAM;OACN,IAAG;OACH,MAAK;OACL,UAAA;OACA,aAAY;MACb,CAAA,CACE;KACL,CAAA,GAAA,oBAAC,UAAD;MAAQ,OAAM;MAAmB,MAAK;MAAS,UAAA;KAEvC,CAAA,CACJ;;IACN,oBAAC,KAAD;KAAG,OAAM;KAAc,OAAM;KAAoB,UAAA;IAE9C,CAAA;GACA;EACH,CAAA,IAAA,IACD;;AAET"}
@@ -1,150 +0,0 @@
1
- import "node:path";
2
- import "node:url";
3
- import.meta.url;
4
- import { jsx, jsxs } from "hono/jsx/jsx-runtime";
5
- //#region src/pages/settings-webhooks.tsx
6
- /** Webhooks settings tab: webhook list plus the create-webhook form. */
7
- function renderSettingsWebhooks(project, webhooks, isAdmin, formState) {
8
- return /* @__PURE__ */ jsxs("div", {
9
- class: "grid",
10
- style: "max-width: 880px;",
11
- children: [
12
- formState?.secret ? /* @__PURE__ */ jsxs("div", {
13
- class: "alert alert--success",
14
- role: "alert",
15
- children: [/* @__PURE__ */ jsx("strong", {
16
- class: "alert__title",
17
- children: "Webhook created"
18
- }), /* @__PURE__ */ jsxs("div", {
19
- class: "alert__body",
20
- children: ["Copy the signing secret now — shown once: ", /* @__PURE__ */ jsx("code", { children: formState.secret })]
21
- })]
22
- }) : null,
23
- formState?.globalError ? /* @__PURE__ */ jsx("div", {
24
- class: "alert alert--danger",
25
- role: "alert",
26
- children: formState.globalError
27
- }) : null,
28
- /* @__PURE__ */ jsxs("div", {
29
- class: "card card--padded",
30
- children: [
31
- /* @__PURE__ */ jsx("h2", {
32
- style: "margin:0 0 .3rem;",
33
- children: "Webhooks"
34
- }),
35
- /* @__PURE__ */ jsx("p", {
36
- class: "field__hint",
37
- children: "Notify external services when builds are created, updated, approved or rejected. Payloads are POSTed as JSON and signed with the webhook secret."
38
- }),
39
- /* @__PURE__ */ jsx("div", {
40
- class: "table-wrap",
41
- style: "margin-top:.75rem;",
42
- children: /* @__PURE__ */ jsxs("table", { children: [/* @__PURE__ */ jsx("thead", { children: /* @__PURE__ */ jsxs("tr", { children: [
43
- /* @__PURE__ */ jsx("th", { children: "URL" }),
44
- /* @__PURE__ */ jsx("th", { children: "Events" }),
45
- /* @__PURE__ */ jsx("th", {})
46
- ] }) }), /* @__PURE__ */ jsx("tbody", { children: webhooks.map((webhook) => /* @__PURE__ */ jsxs("tr", { children: [
47
- /* @__PURE__ */ jsx("td", {
48
- style: "max-width:36ch; overflow:hidden; text-overflow:ellipsis; white-space:nowrap;",
49
- title: webhook.url,
50
- children: webhook.url
51
- }),
52
- /* @__PURE__ */ jsx("td", { children: webhook.events.length === 0 ? /* @__PURE__ */ jsx("span", {
53
- class: "field__hint",
54
- children: "all events"
55
- }) : /* @__PURE__ */ jsx("div", {
56
- style: "display:flex; gap:.25rem; flex-wrap:wrap;",
57
- children: webhook.events.map((event) => /* @__PURE__ */ jsx("span", {
58
- class: "badge badge--neutral",
59
- children: event
60
- }, event))
61
- }) }),
62
- /* @__PURE__ */ jsx("td", { children: isAdmin ? /* @__PURE__ */ jsx("form", {
63
- method: "post",
64
- action: `/projects/${project.slug}/settings/webhooks/${webhook.id}/delete`,
65
- "hx-post": `/projects/${project.slug}/settings/webhooks/${webhook.id}/delete`,
66
- "hx-target": "body",
67
- children: /* @__PURE__ */ jsx("button", {
68
- class: "btn btn--ghost",
69
- type: "submit",
70
- children: "Delete"
71
- })
72
- }) : null })
73
- ] }, webhook.id)) })] })
74
- }),
75
- webhooks.length === 0 ? /* @__PURE__ */ jsx("p", {
76
- class: "field__hint",
77
- style: "margin-top:.5rem;",
78
- children: "No webhooks configured."
79
- }) : null
80
- ]
81
- }),
82
- isAdmin ? /* @__PURE__ */ jsxs("div", {
83
- class: "card card--padded",
84
- children: [/* @__PURE__ */ jsx("h3", {
85
- style: "margin:0 0 .5rem;",
86
- children: "Create webhook"
87
- }), /* @__PURE__ */ jsxs("form", {
88
- method: "post",
89
- action: `/projects/${project.slug}/settings/webhooks`,
90
- "hx-post": `/projects/${project.slug}/settings/webhooks`,
91
- "hx-target": "body",
92
- children: [
93
- /* @__PURE__ */ jsxs("div", {
94
- class: "field",
95
- children: [
96
- /* @__PURE__ */ jsx("label", {
97
- class: "field__label",
98
- for: "url",
99
- children: "URL"
100
- }),
101
- /* @__PURE__ */ jsx("input", {
102
- class: `field__input ${formState?.errors?.["url"] ? "field__input--error" : ""}`,
103
- id: "url",
104
- name: "url",
105
- type: "url",
106
- required: true,
107
- placeholder: "https://example.com/hooks/storyshelf"
108
- }),
109
- formState?.errors?.["url"] ? /* @__PURE__ */ jsx("p", {
110
- class: "field__error",
111
- role: "alert",
112
- children: formState.errors["url"]
113
- }) : null
114
- ]
115
- }),
116
- /* @__PURE__ */ jsxs("div", {
117
- class: "field",
118
- children: [
119
- /* @__PURE__ */ jsx("label", {
120
- class: "field__label",
121
- for: "events",
122
- children: "Events"
123
- }),
124
- /* @__PURE__ */ jsx("input", {
125
- class: "field__input",
126
- id: "events",
127
- name: "events",
128
- placeholder: "build.created, build.approved, snapshot.reviewed"
129
- }),
130
- /* @__PURE__ */ jsx("p", {
131
- class: "field__hint",
132
- children: "Comma-separated. Leave blank to receive all events."
133
- })
134
- ]
135
- }),
136
- /* @__PURE__ */ jsx("button", {
137
- class: "btn btn--primary",
138
- type: "submit",
139
- children: "Add webhook"
140
- })
141
- ]
142
- })]
143
- }) : null
144
- ]
145
- });
146
- }
147
- //#endregion
148
- export { renderSettingsWebhooks };
149
-
150
- //# sourceMappingURL=settings-webhooks.mjs.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"settings-webhooks.mjs","names":[],"sources":["../../src/pages/settings-webhooks.tsx"],"sourcesContent":["import type { HtmlEscapedString } from \"hono/utils/html\";\nimport type { Project } from \"../schema/project.ts\";\n\n/** Webhook row as rendered in the webhooks settings tab. */\nexport interface SettingsWebhook {\n id: string;\n url: string;\n events: string[];\n}\n\n/** Webhooks settings tab: webhook list plus the create-webhook form. */\nexport function renderSettingsWebhooks(\n project: Project,\n webhooks: SettingsWebhook[],\n isAdmin: boolean,\n formState?: { errors?: Record<string, string>; globalError?: string; secret?: string },\n): unknown {\n return (\n <div class=\"grid\" style=\"max-width: 880px;\">\n {formState?.secret ? (\n <div class=\"alert alert--success\" role=\"alert\">\n <strong class=\"alert__title\">Webhook created</strong>\n <div class=\"alert__body\">\n Copy the signing secret now — shown once: <code>{formState.secret}</code>\n </div>\n </div>\n ) : null}\n {formState?.globalError ? (\n <div class=\"alert alert--danger\" role=\"alert\">\n {formState.globalError}\n </div>\n ) : null}\n\n <div class=\"card card--padded\">\n <h2 style=\"margin:0 0 .3rem;\">Webhooks</h2>\n <p class=\"field__hint\">\n Notify external services when builds are created, updated, approved or rejected. Payloads\n are POSTed as JSON and signed with the webhook secret.\n </p>\n <div class=\"table-wrap\" style=\"margin-top:.75rem;\">\n <table>\n <thead>\n <tr>\n <th>URL</th>\n <th>Events</th>\n <th></th>\n </tr>\n </thead>\n <tbody>\n {webhooks.map((webhook): HtmlEscapedString | Promise<HtmlEscapedString> => (\n <tr key={webhook.id}>\n <td\n style=\"max-width:36ch; overflow:hidden; text-overflow:ellipsis; white-space:nowrap;\"\n title={webhook.url}\n >\n {webhook.url}\n </td>\n <td>\n {webhook.events.length === 0 ? (\n <span class=\"field__hint\">all events</span>\n ) : (\n <div style=\"display:flex; gap:.25rem; flex-wrap:wrap;\">\n {webhook.events.map(\n (event): HtmlEscapedString | Promise<HtmlEscapedString> => (\n <span key={event} class=\"badge badge--neutral\">\n {event}\n </span>\n ),\n )}\n </div>\n )}\n </td>\n <td>\n {isAdmin ? (\n <form\n method=\"post\"\n action={`/projects/${project.slug}/settings/webhooks/${webhook.id}/delete`}\n hx-post={`/projects/${project.slug}/settings/webhooks/${webhook.id}/delete`}\n hx-target=\"body\"\n >\n <button class=\"btn btn--ghost\" type=\"submit\">\n Delete\n </button>\n </form>\n ) : null}\n </td>\n </tr>\n ))}\n </tbody>\n </table>\n </div>\n {webhooks.length === 0 ? (\n <p class=\"field__hint\" style=\"margin-top:.5rem;\">\n No webhooks configured.\n </p>\n ) : null}\n </div>\n\n {isAdmin ? (\n <div class=\"card card--padded\">\n <h3 style=\"margin:0 0 .5rem;\">Create webhook</h3>\n <form\n method=\"post\"\n action={`/projects/${project.slug}/settings/webhooks`}\n hx-post={`/projects/${project.slug}/settings/webhooks`}\n hx-target=\"body\"\n >\n <div class=\"field\">\n <label class=\"field__label\" for=\"url\">\n URL\n </label>\n <input\n class={`field__input ${formState?.errors?.[\"url\"] ? \"field__input--error\" : \"\"}`}\n id=\"url\"\n name=\"url\"\n type=\"url\"\n required\n placeholder=\"https://example.com/hooks/storyshelf\"\n />\n {formState?.errors?.[\"url\"] ? (\n <p class=\"field__error\" role=\"alert\">\n {formState.errors[\"url\"]}\n </p>\n ) : null}\n </div>\n <div class=\"field\">\n <label class=\"field__label\" for=\"events\">\n Events\n </label>\n <input\n class=\"field__input\"\n id=\"events\"\n name=\"events\"\n placeholder=\"build.created, build.approved, snapshot.reviewed\"\n />\n <p class=\"field__hint\">Comma-separated. Leave blank to receive all events.</p>\n </div>\n <button class=\"btn btn--primary\" type=\"submit\">\n Add webhook\n </button>\n </form>\n </div>\n ) : null}\n </div>\n );\n}\n"],"mappings":"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"}