@jxsuite/studio 6.1.2 → 8.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (522) hide show
  1. package/README.md +5 -5
  2. package/dist/chunks/2020-5wtzce5g.js +4 -0
  3. package/dist/chunks/adapter-5tphg7xe.js +4 -0
  4. package/dist/chunks/add-new-flow-psym14sn.js +4 -0
  5. package/dist/chunks/cf-account-picker-haqazq5r.js +4 -0
  6. package/dist/chunks/cf-settings-h2wrh6hq.js +4 -0
  7. package/dist/chunks/{color-area-0fj8a4ga.js → color-area-6rbra5dy.js} +2 -2
  8. package/dist/chunks/{color-field-xch8kx2g.js → color-field-gy56c94g.js} +3 -3
  9. package/dist/chunks/color-m7r1vk54.js +4 -0
  10. package/dist/chunks/{color-slider-jxd8v350.js → color-slider-sqqdyf6c.js} +2 -2
  11. package/dist/chunks/{combobox-p0efwjke.js → combobox-72h32ejk.js} +3 -3
  12. package/dist/chunks/components-r22xca09.js +4 -0
  13. package/dist/chunks/content-source-mmppmcyg.js +4 -0
  14. package/dist/chunks/convert-to-repeater-he70fc2b.js +4 -0
  15. package/dist/chunks/editor-ccd9jwsa.js +4 -0
  16. package/dist/chunks/entry-commands-6qxz9e8p.js +4 -0
  17. package/dist/chunks/extension-sections-0egb88dm.js +4 -0
  18. package/dist/chunks/file-ops-qnab36ek.js +4 -0
  19. package/dist/chunks/files-rcn56qvm.js +4 -0
  20. package/dist/chunks/format-host-yxz0kjjs.js +4 -0
  21. package/dist/chunks/fs-events-d1qxq4z4.js +4 -0
  22. package/dist/chunks/grid-open-4z1g062t.js +4 -0
  23. package/dist/chunks/{grid-view-d2wq9ezg.js → grid-view-qg1b5eqx.js} +25 -25
  24. package/dist/chunks/{icons-pnfz478q.js → icons-63bjtbs7.js} +2 -2
  25. package/dist/chunks/{iframe-entry-jdcktez8.js → iframe-entry-2zggzajv.js} +4 -4
  26. package/dist/chunks/{iframe-entry-zap785cw.js → iframe-entry-76j8vwwx.js} +4 -4
  27. package/dist/chunks/iframe-entry-99nr5zfb.js +5 -0
  28. package/dist/chunks/{iframe-entry-x0ygf2yr.js → iframe-entry-pkgmcgp0.js} +4 -4
  29. package/dist/chunks/iframe-host-ssv7kyj0.js +4 -0
  30. package/dist/chunks/{index-zpjmzqfk.js → index-32eqzv1k.js} +3 -3
  31. package/dist/chunks/index-f0jn7nnp.js +4 -0
  32. package/dist/chunks/{javascript-m54mnwp6.js → javascript-pjp734q4.js} +3 -3
  33. package/dist/chunks/jsonMode-njkvsa02.js +13 -0
  34. package/dist/chunks/jx-validate-ttasrbh7.js +4 -0
  35. package/dist/chunks/layers-bgyr11tr.js +4 -0
  36. package/dist/chunks/layers-panel-7ez66zeq.js +4 -0
  37. package/dist/chunks/{listbox-e74qjyq6.js → listbox-c421cf8c.js} +2 -2
  38. package/dist/chunks/lit-html-v9gh687x.js +4 -0
  39. package/dist/chunks/media-library-sq468wts.js +4 -0
  40. package/dist/chunks/media-picker-shfe59pt.js +4 -0
  41. package/dist/chunks/{menu-n6yzswmy.js → menu-bdpzbfvs.js} +2 -2
  42. package/dist/chunks/{monaco-binding-7gx83x3r.js → monaco-binding-vq1hgnn0.js} +3 -3
  43. package/dist/chunks/monaco-buffer-3afgwvbp.js +4 -0
  44. package/dist/chunks/monaco-setup-xrd2cbkp.js +4 -0
  45. package/dist/chunks/notify-kzrjr3fv.js +4 -0
  46. package/dist/chunks/parse-v77xtwv7.js +4 -0
  47. package/dist/chunks/platform-7v4rtd7m.js +4 -0
  48. package/dist/chunks/popover-b89sfej7.js +4 -0
  49. package/dist/chunks/publish-panel-2z9gw8ee.js +4 -0
  50. package/dist/chunks/publish-quick-qx2455cj.js +4 -0
  51. package/dist/chunks/publish-workspace-wrc1dgwx.js +4 -0
  52. package/dist/chunks/quick-search-n0t0eqxb.js +4 -0
  53. package/dist/chunks/references-9547rg5s.js +4 -0
  54. package/dist/chunks/right-panel-wsgnr9pn.js +4 -0
  55. package/dist/chunks/source-control-kwktr9y6.js +4 -0
  56. package/dist/chunks/{split-n2gfpm5m.js → split-c9zfdgxf.js} +2 -2
  57. package/dist/chunks/studio-03ct6yfv.js +9 -0
  58. package/dist/chunks/studio-07rcfje3.js +5 -0
  59. package/dist/chunks/studio-3e54qh39.js +7 -0
  60. package/dist/chunks/studio-3exxhz5g.js +5 -0
  61. package/dist/chunks/studio-3q40e3rj.js +5 -0
  62. package/dist/chunks/studio-3qeh9t0h.js +6 -0
  63. package/dist/chunks/studio-3qqjeep5.js +6 -0
  64. package/dist/chunks/studio-43sd2mam.js +4 -0
  65. package/dist/chunks/studio-4hp8pkyt.js +5 -0
  66. package/dist/chunks/studio-58xg6j2q.js +9 -0
  67. package/dist/chunks/studio-5g0rprdt.js +7 -0
  68. package/dist/chunks/{studio-2j1cb95x.js → studio-6m380wp7.js} +4 -4
  69. package/dist/chunks/studio-80jyh1xh.js +4 -0
  70. package/dist/chunks/studio-83mk4bgg.js +9 -0
  71. package/dist/chunks/{studio-v0jzqdjm.js → studio-881z1xrx.js} +4 -4
  72. package/dist/chunks/studio-8m0y2qe7.js +5 -0
  73. package/dist/chunks/{studio-d81xfh1g.js → studio-8tr6cfrc.js} +4 -4
  74. package/dist/chunks/studio-8vcvfs7r.js +6 -0
  75. package/dist/chunks/studio-9tmebf0s.js +5 -0
  76. package/dist/chunks/studio-a2bvaptz.js +5 -0
  77. package/dist/chunks/studio-b7y5mr30.js +5 -0
  78. package/dist/chunks/studio-bavb31r0.js +5 -0
  79. package/dist/chunks/{studio-dgz8d0c1.js → studio-bbe4c90a.js} +4 -4
  80. package/dist/chunks/studio-c05wdnt3.js +5 -0
  81. package/dist/chunks/studio-ccv2svc6.js +5 -0
  82. package/dist/chunks/studio-d5grtb9e.js +16 -0
  83. package/dist/chunks/studio-df0baea9.js +5 -0
  84. package/dist/chunks/studio-dgk4dqtx.js +7 -0
  85. package/dist/chunks/studio-e1g64q43.js +5 -0
  86. package/dist/chunks/studio-ed1hp6zf.js +6 -0
  87. package/dist/chunks/studio-ed3xx40h.js +7 -0
  88. package/dist/chunks/studio-f14e1zdj.js +5 -0
  89. package/dist/chunks/studio-fbhxxc5f.js +5 -0
  90. package/dist/chunks/studio-fyh0jc96.js +5 -0
  91. package/dist/chunks/studio-gcxk20n7.js +5 -0
  92. package/dist/chunks/studio-jaaz8ce9.js +5 -0
  93. package/dist/chunks/{studio-90pq9km1.js → studio-jcnsdaep.js} +4 -4
  94. package/dist/chunks/studio-jsgf2q5k.js +7 -0
  95. package/dist/chunks/{studio-0q988f9w.js → studio-k3xxbagr.js} +3 -3
  96. package/dist/chunks/{studio-5ve6bbep.js → studio-k7evxqh4.js} +4 -4
  97. package/dist/chunks/studio-kt3pjkwd.js +5 -0
  98. package/dist/chunks/studio-m8g16bgz.js +5 -0
  99. package/dist/chunks/studio-mn0476ag.js +5 -0
  100. package/dist/chunks/studio-mx1smyq0.js +5 -0
  101. package/dist/chunks/studio-n0c5h6mf.js +5 -0
  102. package/dist/chunks/{studio-485046te.js → studio-nh6d342n.js} +7 -7
  103. package/dist/chunks/studio-nqxqf8p2.js +4 -0
  104. package/dist/chunks/studio-p4nrkvqr.js +5 -0
  105. package/dist/chunks/{studio-1fxkaaea.js → studio-pbxa5fpc.js} +4 -4
  106. package/dist/chunks/studio-pgmvdv7z.js +7 -0
  107. package/dist/chunks/studio-ph84avkf.js +5 -0
  108. package/dist/chunks/{studio-tq0rtfwj.js → studio-q0mvbaq6.js} +4 -4
  109. package/dist/chunks/studio-q0tccd43.js +5 -0
  110. package/dist/chunks/studio-q7rtx6zq.js +14 -0
  111. package/dist/chunks/{studio-a3g98wjr.js → studio-qgh13jtz.js} +4 -4
  112. package/dist/chunks/studio-qmn1xc24.js +5 -0
  113. package/dist/chunks/studio-qwdqwkj0.js +5 -0
  114. package/dist/chunks/studio-r5qy30vx.js +5 -0
  115. package/dist/chunks/studio-rj9eamf8.js +5 -0
  116. package/dist/chunks/studio-rptgsk96.js +5 -0
  117. package/dist/chunks/studio-rthyg42z.js +928 -0
  118. package/dist/chunks/studio-s19tp1xr.js +5 -0
  119. package/dist/chunks/studio-s32578pn.js +5 -0
  120. package/dist/chunks/studio-svb7yyve.js +5 -0
  121. package/dist/chunks/studio-syreb644.js +5 -0
  122. package/dist/chunks/studio-tf9jryb1.js +10 -0
  123. package/dist/chunks/studio-tfkznv39.js +5 -0
  124. package/dist/chunks/studio-tft6r105.js +5 -0
  125. package/dist/chunks/studio-txf2kysx.js +5 -0
  126. package/dist/chunks/studio-v8867ddv.js +12 -0
  127. package/dist/chunks/studio-vxq7fcvv.js +5 -0
  128. package/dist/chunks/studio-w4rz9hdk.js +5 -0
  129. package/dist/chunks/studio-wbcjbhy1.js +9 -0
  130. package/dist/chunks/studio-wc649wss.js +5 -0
  131. package/dist/chunks/studio-wys23mxz.js +5 -0
  132. package/dist/chunks/studio-x1x167jh.js +5 -0
  133. package/dist/chunks/studio-x9hsze61.js +5 -0
  134. package/dist/chunks/studio-y0n7yxea.js +9 -0
  135. package/dist/chunks/studio-y3ahhdpx.js +5 -0
  136. package/dist/chunks/studio-z97c48fk.js +5 -0
  137. package/dist/chunks/studio-zat62m0c.js +5 -0
  138. package/dist/chunks/studio-zcd2e7yz.js +5 -0
  139. package/dist/chunks/studio-zz9qe3rw.js +64 -0
  140. package/dist/chunks/toast-1gv0h53h.js +4 -0
  141. package/dist/chunks/{toast-host-ke5z4ng7.js → toast-host-1yg5ar8d.js} +3 -3
  142. package/dist/chunks/{tooltip-5v8ngwj2.js → tooltip-yypz28gq.js} +3 -3
  143. package/dist/chunks/{tree-mdq3v5cw.js → tree-9xa4hm7n.js} +2 -2
  144. package/dist/chunks/tsMode-epyfz1hv.js +14 -0
  145. package/dist/chunks/workspace-dz7nxfhv.js +4 -0
  146. package/dist/chunks/workspace-home-xsd7hkjw.js +4 -0
  147. package/dist/chunks/{ws-client-nze0k6mv.js → ws-client-bv552sfx.js} +3 -3
  148. package/dist/iframe-entry.js +20 -16
  149. package/dist/manifest.json +77 -63
  150. package/dist/studio.js +103 -104
  151. package/dist/workers/ts.worker.js +3 -3
  152. package/package.json +12 -11
  153. package/src/browse/component-examples.ts +272 -0
  154. package/src/browse/library-commands.ts +64 -104
  155. package/src/browse/library-layouts.ts +263 -49
  156. package/src/browse/library-model.ts +181 -133
  157. package/src/browse/library-pane.ts +738 -446
  158. package/src/browse/library-preview.ts +149 -19
  159. package/src/browse/library-source.ts +308 -41
  160. package/src/browse/preview-root.ts +78 -0
  161. package/src/browse/preview-style.ts +155 -0
  162. package/src/canvas/asset-refs.ts +16 -1
  163. package/src/canvas/canvas-live-render.ts +222 -30
  164. package/src/canvas/canvas-origin.ts +37 -12
  165. package/src/canvas/canvas-page-context.ts +112 -0
  166. package/src/canvas/canvas-render.ts +113 -107
  167. package/src/canvas/canvas-utils.ts +57 -12
  168. package/src/canvas/iframe-drop.ts +107 -0
  169. package/src/canvas/iframe-entry.ts +24 -12
  170. package/src/canvas/iframe-host.ts +134 -62
  171. package/src/canvas/iframe-keys.ts +11 -0
  172. package/src/canvas/iframe-patch.ts +8 -7
  173. package/src/canvas/iframe-protocol.ts +24 -5
  174. package/src/canvas/iframe-render.ts +48 -1
  175. package/src/canvas/iframe-subtree.ts +5 -2
  176. package/src/canvas/npm-modules.ts +22 -0
  177. package/src/canvas/preview-navigate.ts +16 -0
  178. package/src/canvas/repeater-sources.ts +200 -0
  179. package/src/canvas/stage-scrollbar.ts +5 -1
  180. package/src/canvas/surface-registry.ts +6 -0
  181. package/src/commands/app-commands.ts +16 -6
  182. package/src/commands/budget.ts +10 -8
  183. package/src/commands/context.ts +35 -10
  184. package/src/commands/defaults.ts +69 -45
  185. package/src/commands/keymap.ts +9 -0
  186. package/src/commands/levels.ts +11 -5
  187. package/src/commands/live-context.ts +2 -0
  188. package/src/commands/registry.ts +10 -1
  189. package/src/content/collection-match.ts +6 -5
  190. package/src/content/collection-pages.ts +412 -0
  191. package/src/content/content-collections.ts +270 -0
  192. package/src/content/entry-commands.ts +51 -60
  193. package/src/content/entry-editor.ts +111 -18
  194. package/src/content/entry-fields.ts +13 -1
  195. package/src/content/entry-inspector.ts +225 -0
  196. package/src/content/entry-model.ts +17 -3
  197. package/src/content/entry-open.ts +80 -0
  198. package/src/content/entry-summaries.ts +440 -0
  199. package/src/content/file-record-ids.ts +80 -0
  200. package/src/content/file-records.ts +125 -0
  201. package/src/content/page-summaries.ts +129 -0
  202. package/src/content/record-entry.ts +201 -0
  203. package/src/content/writing-banner.ts +177 -0
  204. package/src/create/add-new-commands.ts +185 -0
  205. package/src/create/add-new-flow.ts +1116 -0
  206. package/src/create/add-new.ts +1014 -0
  207. package/src/create/element-name.ts +121 -0
  208. package/src/editor/convert-to-component.ts +67 -43
  209. package/src/editor/file-drop-action.ts +9 -1
  210. package/src/editor/inline-edit-apply.ts +44 -0
  211. package/src/editor/inline-edit.ts +10 -0
  212. package/src/editor/insert-component.ts +91 -0
  213. package/src/editor/insert-zone-action.ts +13 -4
  214. package/src/editor/shortcuts.ts +44 -22
  215. package/src/editor/slash-menu.ts +51 -8
  216. package/src/files/components.ts +74 -10
  217. package/src/files/file-ops.ts +15 -5
  218. package/src/files/files.ts +164 -150
  219. package/src/files/fs-events.ts +18 -7
  220. package/src/files/media-meta.ts +95 -1
  221. package/src/files/media-types.ts +55 -0
  222. package/src/files/media-upload.ts +209 -52
  223. package/src/files/new-file-name.ts +156 -0
  224. package/src/files/serialize-document.ts +13 -3
  225. package/src/format/format-host.ts +15 -0
  226. package/src/github/github-auth.ts +2 -2
  227. package/src/github/github-publish.ts +4 -3
  228. package/src/grid/grid-controller.ts +5 -1
  229. package/src/grid/grid-open.ts +0 -27
  230. package/src/grid/grid-panel.ts +54 -2
  231. package/src/grid/grid-reveal.ts +34 -0
  232. package/src/grid/grid-source.ts +3 -25
  233. package/src/grid/grid-view.ts +31 -6
  234. package/src/grid/sources/content-source.ts +75 -7
  235. package/src/grid/tabulator-tables.d.ts +6 -0
  236. package/src/hosting/document.ts +2 -2
  237. package/src/i18n/i18n-commands.ts +2 -1
  238. package/src/media/media-commands.ts +181 -0
  239. package/src/media/media-library-model.ts +232 -0
  240. package/src/media/media-library.ts +1283 -0
  241. package/src/media/media-pane.ts +47 -19
  242. package/src/packages/pull-package-sync.ts +1 -1
  243. package/src/panels/activity-panel.ts +21 -5
  244. package/src/panels/ai-chat/chat-markdown.ts +8 -8
  245. package/src/panels/block-action-bar.ts +11 -11
  246. package/src/panels/canvas-dnd-bridge.ts +5 -2
  247. package/src/panels/chat-panel.ts +6 -6
  248. package/src/panels/collections-panel.ts +306 -0
  249. package/src/panels/component-preview.ts +35 -13
  250. package/src/panels/data-explorer.ts +1 -1
  251. package/src/panels/data-grid.ts +4 -0
  252. package/src/panels/dnd.ts +17 -30
  253. package/src/panels/elements-panel.ts +9 -2
  254. package/src/panels/empty-state.ts +2 -2
  255. package/src/panels/formula-workspace.ts +2 -3
  256. package/src/panels/frontmatter-fields.ts +9 -9
  257. package/src/panels/git-diff-open.ts +9 -5
  258. package/src/panels/head-panel.ts +369 -103
  259. package/src/panels/i18n-panel.ts +11 -10
  260. package/src/panels/imports-panel.ts +2 -0
  261. package/src/panels/jump-bar.ts +27 -2
  262. package/src/panels/layers-panel.ts +36 -30
  263. package/src/panels/left-panel.ts +22 -8
  264. package/src/panels/navigator-panels.ts +23 -11
  265. package/src/panels/pane-context.ts +111 -29
  266. package/src/panels/pane-grid.ts +6 -6
  267. package/src/panels/panel-registry.ts +14 -9
  268. package/src/panels/properties-panel.ts +7 -3
  269. package/src/panels/right-panel.ts +199 -43
  270. package/src/panels/seo-modal.ts +41 -108
  271. package/src/panels/settings-menu.ts +52 -50
  272. package/src/panels/settings-pane.ts +268 -162
  273. package/src/panels/signals-panel.ts +3 -4
  274. package/src/panels/site-model.ts +367 -0
  275. package/src/panels/site-panel.ts +638 -0
  276. package/src/panels/style-panel.ts +37 -3
  277. package/src/panels/stylebook-doc.ts +142 -10
  278. package/src/panels/stylebook-layers-panel.ts +39 -80
  279. package/src/panels/stylebook-panel.ts +47 -10
  280. package/src/panels/styles-panel.ts +327 -0
  281. package/src/panels/tab-strip.ts +109 -25
  282. package/src/platform.ts +1 -1
  283. package/src/platforms/cloud.ts +28 -1
  284. package/src/platforms/default-platform.ts +4 -4
  285. package/src/platforms/devserver.ts +51 -25
  286. package/src/publish/deploy-checklist.ts +12 -7
  287. package/src/publish/pages-service.ts +38 -14
  288. package/src/publish/publish-changes.ts +491 -0
  289. package/src/publish/publish-commands.ts +83 -18
  290. package/src/publish/publish-ids.ts +49 -0
  291. package/src/publish/publish-quick.ts +148 -0
  292. package/src/publish/publish-workspace.ts +926 -0
  293. package/src/publish/source-control.ts +907 -0
  294. package/src/services/automation.ts +16 -20
  295. package/src/services/cf-settings.ts +4 -4
  296. package/src/services/connection.ts +2 -2
  297. package/src/services/directory-picker.ts +2 -2
  298. package/src/services/references.ts +0 -0
  299. package/src/services/render-critic.ts +21 -2
  300. package/src/services/settings/definitions.ts +25 -14
  301. package/src/settings/contributed-section.ts +49 -10
  302. package/src/settings/css-vars-editor.ts +93 -27
  303. package/src/settings/developer-panels.ts +43 -0
  304. package/src/settings/extension-sections.ts +20 -2
  305. package/src/settings/general-settings.ts +91 -21
  306. package/src/settings/preferences-dialog.ts +8 -1
  307. package/src/settings/project-sections.ts +27 -10
  308. package/src/settings/schema-field-ui.ts +3 -1
  309. package/src/settings/section-registry.ts +116 -11
  310. package/src/settings/settings-dialog.ts +192 -0
  311. package/src/settings/settings-document.ts +182 -162
  312. package/src/shell.ts +467 -431
  313. package/src/site-context.ts +64 -10
  314. package/src/state.ts +28 -9
  315. package/src/studio.ts +194 -41
  316. package/src/style/project-styles.ts +34 -0
  317. package/src/style/stylebook-specimens.ts +89 -0
  318. package/src/style/stylebook-target.ts +26 -0
  319. package/src/style/tag-inheritance.ts +105 -0
  320. package/src/style/variables-focus.ts +61 -0
  321. package/src/style/variables-view.ts +235 -0
  322. package/src/surfaces/add-new.json +1482 -0
  323. package/src/surfaces/add-new.ts +325 -0
  324. package/src/surfaces/ai-chat.ts +2 -2
  325. package/src/surfaces/boot-failure.json +4 -3
  326. package/src/surfaces/bottom-dock.json +1 -1
  327. package/src/surfaces/canvas-stage.json +30 -19
  328. package/src/surfaces/canvas-stage.ts +5 -5
  329. package/src/surfaces/collections-panel.json +615 -0
  330. package/src/surfaces/collections-panel.ts +168 -0
  331. package/src/surfaces/commandbar.json +241 -96
  332. package/src/surfaces/commandbar.ts +134 -99
  333. package/src/surfaces/empty-state.json +1 -1
  334. package/src/surfaces/entry-editor.json +136 -0
  335. package/src/surfaces/entry-editor.ts +21 -0
  336. package/src/surfaces/entry-inspector.json +371 -0
  337. package/src/surfaces/entry-inspector.ts +143 -0
  338. package/src/surfaces/inspector-dock.json +162 -14
  339. package/src/surfaces/inspector-dock.ts +46 -19
  340. package/src/surfaces/library-pane.json +670 -437
  341. package/src/surfaces/library-pane.ts +94 -59
  342. package/src/surfaces/media-browser.json +62 -6
  343. package/src/surfaces/media-browser.ts +15 -1
  344. package/src/surfaces/media-field.json +1 -1
  345. package/src/surfaces/media-library.json +1586 -0
  346. package/src/surfaces/media-library.ts +282 -0
  347. package/src/surfaces/media-pick-dialog.json +71 -0
  348. package/src/surfaces/media-pick-dialog.ts +132 -0
  349. package/src/surfaces/menu.ts +18 -0
  350. package/src/surfaces/pane-context.json +144 -77
  351. package/src/surfaces/pane-context.ts +24 -0
  352. package/src/surfaces/panel-deploy-checklist.json +12 -6
  353. package/src/surfaces/panel-deploy-checklist.ts +3 -1
  354. package/src/surfaces/panel-page.json +72 -2
  355. package/src/surfaces/panel-page.ts +38 -7
  356. package/src/surfaces/panel-signals.json +1 -1
  357. package/src/surfaces/panel-signals.ts +5 -5
  358. package/src/surfaces/panel-stylebook-layers.json +71 -204
  359. package/src/surfaces/panel-stylebook-layers.ts +0 -21
  360. package/src/surfaces/preferences.json +120 -48
  361. package/src/surfaces/preferences.ts +8 -0
  362. package/src/surfaces/publish-quick.json +428 -0
  363. package/src/surfaces/publish-quick.ts +165 -0
  364. package/src/surfaces/publish-workspace.json +2892 -0
  365. package/src/surfaces/publish-workspace.ts +391 -0
  366. package/src/surfaces/rail.json +1 -159
  367. package/src/surfaces/rail.ts +18 -75
  368. package/src/surfaces/schema-form.json +10 -2
  369. package/src/surfaces/schema-form.ts +2 -0
  370. package/src/surfaces/seo.json +1 -1
  371. package/src/surfaces/settings-contributed.json +5 -5
  372. package/src/surfaces/settings-contributed.ts +18 -2
  373. package/src/surfaces/settings-css-vars.json +44 -36
  374. package/src/surfaces/settings-css-vars.ts +77 -4
  375. package/src/surfaces/settings-deploy.json +2 -15
  376. package/src/surfaces/settings-deploy.ts +1 -1
  377. package/src/surfaces/settings-dialog.json +51 -0
  378. package/src/surfaces/settings-dialog.ts +169 -0
  379. package/src/surfaces/settings-overview.json +3 -3
  380. package/src/surfaces/settings-overview.ts +9 -2
  381. package/src/surfaces/settings-pane.json +269 -46
  382. package/src/surfaces/settings-pane.ts +85 -24
  383. package/src/surfaces/shell.json +2 -1
  384. package/src/surfaces/site-panel.json +1029 -0
  385. package/src/surfaces/site-panel.ts +233 -0
  386. package/src/surfaces/slash-menu.json +63 -21
  387. package/src/surfaces/slash-menu.ts +23 -0
  388. package/src/surfaces/statusbar.ts +39 -15
  389. package/src/surfaces/styles-panel.json +735 -0
  390. package/src/surfaces/styles-panel.ts +195 -0
  391. package/src/surfaces/styles-variables.json +149 -0
  392. package/src/surfaces/styles-variables.ts +145 -0
  393. package/src/surfaces/tab-strip.json +4 -4
  394. package/src/surfaces/welcome.ts +1 -1
  395. package/src/surfaces/writing-banner.json +94 -0
  396. package/src/surfaces/writing-banner.ts +80 -0
  397. package/src/tabs/bare-repeaters.ts +101 -0
  398. package/src/tabs/tab.ts +47 -7
  399. package/src/types.ts +21 -26
  400. package/src/ui/form-controls.ts +47 -8
  401. package/src/ui/layers.ts +13 -0
  402. package/src/ui/media-picker.ts +284 -40
  403. package/src/ui/regions.ts +7 -6
  404. package/src/ui/schema-form.ts +259 -27
  405. package/src/ui/virtual-window.ts +26 -1
  406. package/src/utils/base64.ts +3 -3
  407. package/src/utils/edit-display.ts +322 -67
  408. package/src/utils/local-day.ts +18 -0
  409. package/src/workspace/pane-derive.ts +4 -4
  410. package/src/workspace/session.ts +28 -7
  411. package/src/workspace/tab-workspace.ts +137 -0
  412. package/src/workspace/workspace-back.ts +189 -0
  413. package/src/workspace/workspace-home.ts +133 -0
  414. package/src/workspace/workspace-ids.ts +129 -0
  415. package/src/workspace/workspace-switch.ts +372 -0
  416. package/src/workspace/workspace.ts +125 -11
  417. package/styles/shell-frame.css +30 -7
  418. package/styles/shell-frame.json +15 -3
  419. package/dist/chunks/2020-f2gkpy8d.js +0 -4
  420. package/dist/chunks/adapter-4912g339.js +0 -4
  421. package/dist/chunks/cf-account-picker-wccaenh6.js +0 -4
  422. package/dist/chunks/cf-settings-br6105tr.js +0 -4
  423. package/dist/chunks/color-28ksk2qm.js +0 -4
  424. package/dist/chunks/components-db68vsn7.js +0 -4
  425. package/dist/chunks/content-source-1449qesq.js +0 -4
  426. package/dist/chunks/convert-to-repeater-5h457egj.js +0 -4
  427. package/dist/chunks/editor-x9jn86a7.js +0 -4
  428. package/dist/chunks/entry-commands-may24cpt.js +0 -4
  429. package/dist/chunks/extension-sections-pvr14vxr.js +0 -4
  430. package/dist/chunks/file-ops-x9v54pcj.js +0 -4
  431. package/dist/chunks/files-j3knqf0s.js +0 -4
  432. package/dist/chunks/format-host-tyre2trb.js +0 -4
  433. package/dist/chunks/fs-events-64ma9htc.js +0 -4
  434. package/dist/chunks/git-panel-84ps5dex.js +0 -4
  435. package/dist/chunks/iframe-entry-fvbk89gm.js +0 -5
  436. package/dist/chunks/iframe-host-ck6vejt5.js +0 -4
  437. package/dist/chunks/index-b8xw3vy9.js +0 -4
  438. package/dist/chunks/jsonMode-w15cmrcm.js +0 -13
  439. package/dist/chunks/jx-validate-at3zn8wa.js +0 -4
  440. package/dist/chunks/layers-h4xp1pss.js +0 -4
  441. package/dist/chunks/layers-panel-m5hw1d7g.js +0 -4
  442. package/dist/chunks/lit-html-8t8t3dnr.js +0 -4
  443. package/dist/chunks/media-picker-2cweexc5.js +0 -4
  444. package/dist/chunks/menu-ynw13y0s.js +0 -4
  445. package/dist/chunks/monaco-buffer-qzxn567r.js +0 -4
  446. package/dist/chunks/monaco-setup-gxf6656g.js +0 -4
  447. package/dist/chunks/notify-cj5zbrs2.js +0 -4
  448. package/dist/chunks/parse-b7ddhr8m.js +0 -4
  449. package/dist/chunks/platform-3dfws9js.js +0 -4
  450. package/dist/chunks/popover-jt2gxmzs.js +0 -4
  451. package/dist/chunks/publish-panel-1gvxbj21.js +0 -4
  452. package/dist/chunks/quick-search-0dajrwqg.js +0 -4
  453. package/dist/chunks/references-49qgt404.js +0 -4
  454. package/dist/chunks/right-panel-jm1bwe53.js +0 -4
  455. package/dist/chunks/section-registry-6kwc4fky.js +0 -4
  456. package/dist/chunks/studio-0rt52vpq.js +0 -5
  457. package/dist/chunks/studio-18vgbhs5.js +0 -5
  458. package/dist/chunks/studio-24mccdrj.js +0 -5
  459. package/dist/chunks/studio-2eh507zk.js +0 -9
  460. package/dist/chunks/studio-2hcbccfv.js +0 -5
  461. package/dist/chunks/studio-2jbs3rxv.js +0 -5
  462. package/dist/chunks/studio-4h8k4dw9.js +0 -5
  463. package/dist/chunks/studio-5f6n18kx.js +0 -5
  464. package/dist/chunks/studio-5gthpky6.js +0 -5
  465. package/dist/chunks/studio-6ep3js6b.js +0 -9
  466. package/dist/chunks/studio-6wkmf3wz.js +0 -9
  467. package/dist/chunks/studio-841rf3cg.js +0 -5
  468. package/dist/chunks/studio-8gmwgheg.js +0 -5
  469. package/dist/chunks/studio-8qm0ep50.js +0 -5
  470. package/dist/chunks/studio-924p1tm1.js +0 -6
  471. package/dist/chunks/studio-a3shpz9y.js +0 -5
  472. package/dist/chunks/studio-amsbaaar.js +0 -6
  473. package/dist/chunks/studio-at5spjbc.js +0 -7
  474. package/dist/chunks/studio-b2xv945e.js +0 -5
  475. package/dist/chunks/studio-bn5nkafw.js +0 -5
  476. package/dist/chunks/studio-bw6q5xjf.js +0 -9
  477. package/dist/chunks/studio-c7q0t9x1.js +0 -5
  478. package/dist/chunks/studio-camnhc96.js +0 -6
  479. package/dist/chunks/studio-cffqvnzd.js +0 -5
  480. package/dist/chunks/studio-efvfrsf8.js +0 -5
  481. package/dist/chunks/studio-er30bpcx.js +0 -5
  482. package/dist/chunks/studio-ezscgr64.js +0 -5
  483. package/dist/chunks/studio-ffrrncvz.js +0 -5
  484. package/dist/chunks/studio-fpphgn8y.js +0 -10
  485. package/dist/chunks/studio-j1kvhdjk.js +0 -4
  486. package/dist/chunks/studio-j430n16g.js +0 -7
  487. package/dist/chunks/studio-jjkg84nj.js +0 -5
  488. package/dist/chunks/studio-m0q32ars.js +0 -4
  489. package/dist/chunks/studio-m6bdst11.js +0 -5
  490. package/dist/chunks/studio-nv2cptd4.js +0 -64
  491. package/dist/chunks/studio-nwfrc98n.js +0 -5
  492. package/dist/chunks/studio-p1wgvp7r.js +0 -5
  493. package/dist/chunks/studio-pag2wncm.js +0 -5
  494. package/dist/chunks/studio-qvanvzfd.js +0 -5
  495. package/dist/chunks/studio-qwa64kt7.js +0 -5
  496. package/dist/chunks/studio-rk1zc4x3.js +0 -928
  497. package/dist/chunks/studio-se2r3ptc.js +0 -5
  498. package/dist/chunks/studio-sg2a0dh0.js +0 -5
  499. package/dist/chunks/studio-tjzjhe68.js +0 -5
  500. package/dist/chunks/studio-v2w7q8r1.js +0 -7
  501. package/dist/chunks/studio-v5vjq1h0.js +0 -4
  502. package/dist/chunks/studio-v8aga3vp.js +0 -14
  503. package/dist/chunks/studio-vfcdrfmv.js +0 -5
  504. package/dist/chunks/studio-vmfkgdjf.js +0 -5
  505. package/dist/chunks/studio-wt1816jj.js +0 -5
  506. package/dist/chunks/studio-wz73q5kq.js +0 -4
  507. package/dist/chunks/studio-y04qtxvp.js +0 -7
  508. package/dist/chunks/studio-y21g8zzg.js +0 -5
  509. package/dist/chunks/studio-y64hrt8p.js +0 -12
  510. package/dist/chunks/studio-ynn90f58.js +0 -16
  511. package/dist/chunks/studio-yxz682sx.js +0 -5
  512. package/dist/chunks/studio-zp7snvkq.js +0 -5
  513. package/dist/chunks/studio-zq4z6tm6.js +0 -5
  514. package/dist/chunks/toast-c9fn075p.js +0 -4
  515. package/dist/chunks/tsMode-sf49ee9x.js +0 -14
  516. package/dist/chunks/workspace-jtfahpee.js +0 -4
  517. package/src/panels/frontmatter-panel.ts +0 -711
  518. package/src/panels/git-panel.ts +0 -1108
  519. package/src/surfaces/doc-header.json +0 -776
  520. package/src/surfaces/doc-header.ts +0 -222
  521. package/src/surfaces/git-panel.json +0 -1880
  522. package/src/surfaces/git-panel.ts +0 -264
@@ -0,0 +1,491 @@
1
+ /// <reference lib="dom" />
2
+ /**
3
+ * Publishing a change set: the destination, the checks, and the one operation both Review changes
4
+ * and the quick publish dialog run (studio.md §22.8).
5
+ *
6
+ * **Two destinations, decided by the host rather than assumed.** **Publish live** commits what is
7
+ * included to the current branch and ships it: through `runDeploy` when a deploy provider is
8
+ * connected (which pushes and asks Cloudflare what it built), otherwise by pushing to the remote,
9
+ * otherwise by committing alone and saying that nothing left the machine. **Send for review** needs
10
+ * a host that opens pull requests (`createPullRequest`); on one that does not (the dev server and
11
+ * the desktop app today) it is drawn disabled with that sentence rather than falling back to a
12
+ * branch push that opens nothing. On a host whose branches are sessions (`gitHosted`, the cloud) a
13
+ * branch cannot be made and committed to mid-flow, so review there commits to the session's own
14
+ * branch and opens the pull request from it, and the destination's note says so.
15
+ *
16
+ * **Every word a control shows is decided here**, so the workspace and the dialog cannot disagree
17
+ * about what a button does: {@link destinationChoices}, {@link publishLabel} and
18
+ * {@link publishBlocker} are read by both, and {@link publishChanges} is the verb behind both
19
+ * primary buttons.
20
+ *
21
+ * @docs studio/publish
22
+ */
23
+
24
+ import { errorMessage } from "@jxsuite/schema/parse";
25
+ import { flushAllCollab } from "../collab/collab-session";
26
+ import { getPlatform, hasPlatform } from "../platform";
27
+ import { notify } from "../services/notify";
28
+ import { shell } from "../shell";
29
+ import { projectState } from "../store";
30
+ import { slugify } from "../files/new-file-name";
31
+ import { currentDeploy, nextDeployStep } from "./deploy-checklist";
32
+ import { platformSupportsPublish } from "./pages-service";
33
+ import { runDeploy } from "./publish-commands";
34
+ import { platformHostsGit, platformOpensPullRequests, refreshGitStatus } from "./source-control";
35
+ import type { GitFileStatus } from "../types";
36
+ import type { PublishDestination } from "./publish-ids";
37
+
38
+ // ─── Where a change set can go ───────────────────────────────────────────────
39
+
40
+ /** The remote the status names first, or `""` (a host may omit the array). */
41
+ function firstRemote(): string {
42
+ const remotes = shell.git.status?.remotes;
43
+ return Array.isArray(remotes) && remotes.length > 0 ? (remotes[0] ?? "") : "";
44
+ }
45
+
46
+ /** The branch a commit lands on now. */
47
+ export function currentBranch(): string {
48
+ return shell.git.branches?.current || shell.git.status?.branch || "";
49
+ }
50
+
51
+ /**
52
+ * Whether Publish live deploys: a provider is connected, the host can reach it, and there is a
53
+ * remote for it to build from.
54
+ */
55
+ export function deployReady(): boolean {
56
+ return currentDeploy() !== undefined && platformSupportsPublish() && firstRemote() !== "";
57
+ }
58
+
59
+ /** Where a live publish ends up, in words: the site's address, else the Pages project's name. */
60
+ function liveTarget(): string {
61
+ const deploy = currentDeploy();
62
+ return deploy?.productionUrl ?? deploy?.projectName ?? "";
63
+ }
64
+
65
+ /**
66
+ * The branch a review is sent from: `studio/` and the summary as a slug, cut short enough to read
67
+ * in a branch picker. A summary with nothing sluggable in it still names a branch.
68
+ */
69
+ export function reviewBranchName(summary: string): string {
70
+ const slug = slugify(summary).replaceAll(/-+/g, "-").replaceAll(/^-|-$/g, "").slice(0, 48);
71
+ return `studio/${slug.replace(/-$/, "") || "changes"}`;
72
+ }
73
+
74
+ /** One destination, as a radio card draws it. */
75
+ export interface DestinationChoice {
76
+ value: PublishDestination;
77
+ label: string;
78
+ /** What choosing it does, in one sentence: where the commit lands and what happens next. */
79
+ note: string;
80
+ /**
81
+ * `"true"` for the chosen one. A string, because `jx-action-button`'s `checked` is the radio
82
+ * segment's `"true"`/`"false"`: a boolean draws neither the selection nor the radio role.
83
+ */
84
+ checked: "true" | "false";
85
+ disabled: boolean;
86
+ /** Why it is disabled, or `""`. Drawn as the card's hint. */
87
+ reason: string;
88
+ }
89
+
90
+ /** The repository's default branch, when the host reported it, or `""`. */
91
+ export function defaultBranch(): string {
92
+ return shell.git.branches?.defaultBranch ?? "";
93
+ }
94
+
95
+ /** Why Send for review cannot run on this host, or `""` when it can. */
96
+ export function reviewRefusal(): string {
97
+ if (!platformOpensPullRequests()) {
98
+ return (
99
+ "This host cannot open a pull request yet. Publish live, or create a branch under " +
100
+ "Branches and push it."
101
+ );
102
+ }
103
+ if (platformHostsGit()) {
104
+ /* A commit here lands on GitHub as it is made, and the pull request is opened from the session's
105
+ own branch. On the default branch that is a live publish followed by a pull request into
106
+ itself, so review is refused until the session is on a branch of its own. A host that has
107
+ not said which branch is the default is refused too: the safe answer is the one that cannot
108
+ publish by accident. */
109
+ const base = defaultBranch();
110
+ const branch = currentBranch();
111
+ if (!base || !branch || branch === base) {
112
+ return (
113
+ `Every commit to ${base || "the default branch"} on this host is live. Create a branch ` +
114
+ "under Branches and send it for review from there."
115
+ );
116
+ }
117
+ return "";
118
+ }
119
+ if (firstRemote() === "") {
120
+ return "A pull request needs a remote. Create the GitHub repository under Hosting first.";
121
+ }
122
+ return "";
123
+ }
124
+
125
+ /** What Publish live does, said before it runs. */
126
+ function liveNote(): string {
127
+ const branch = currentBranch() || "the current branch";
128
+ if (deployReady()) {
129
+ return `Commits to ${branch} and deploys to ${liveTarget()}.`;
130
+ }
131
+ if (platformHostsGit()) {
132
+ return `Commits to ${branch} on GitHub.`;
133
+ }
134
+ const remote = firstRemote();
135
+ return remote
136
+ ? `Commits to ${branch} and pushes it to ${remote}.`
137
+ : `Commits to ${branch}. This repository has no remote, so nothing leaves this machine.`;
138
+ }
139
+
140
+ /** What Send for review does, said before it runs. */
141
+ function reviewNote(): string {
142
+ const branch = currentBranch() || "the current branch";
143
+ if (platformHostsGit()) {
144
+ return (
145
+ `Commits to ${branch} and opens a pull request from it into ` +
146
+ `${defaultBranch() || "the default branch"}.`
147
+ );
148
+ }
149
+ const summary = shell.git.commitMessage.trim();
150
+ const head = summary ? reviewBranchName(summary) : "a new studio/ branch";
151
+ return `Saves to ${head}, pushes it and opens a pull request into ${branch}.`;
152
+ }
153
+
154
+ /** The two destinations, with the chosen one checked and a refused one disabled. */
155
+ export function destinationChoices(chosen: PublishDestination): DestinationChoice[] {
156
+ const refusal = reviewRefusal();
157
+ return [
158
+ {
159
+ checked: chosen === "live" ? "true" : "false",
160
+ disabled: false,
161
+ label: "Publish live",
162
+ note: liveNote(),
163
+ reason: "",
164
+ value: "live",
165
+ },
166
+ {
167
+ checked: chosen === "review" ? "true" : "false",
168
+ disabled: refusal !== "",
169
+ label: "Send for review",
170
+ note: reviewNote(),
171
+ reason: refusal,
172
+ value: "review",
173
+ },
174
+ ];
175
+ }
176
+
177
+ /**
178
+ * The destination actually in effect: the chosen one, unless it is refused here, in which case the
179
+ * one that is not. A host that cannot open a pull request never leaves the primary button naming
180
+ * one.
181
+ */
182
+ export function effectiveDestination(chosen: PublishDestination): PublishDestination {
183
+ return chosen === "review" && reviewRefusal() !== "" ? "live" : chosen;
184
+ }
185
+
186
+ /** The primary button's words for a destination. */
187
+ export function publishLabel(destination: PublishDestination): string {
188
+ if (destination === "review") {
189
+ return "Send for review";
190
+ }
191
+ if (deployReady()) {
192
+ return "Publish live";
193
+ }
194
+ return platformHostsGit() || firstRemote() !== "" ? "Commit and push" : "Commit";
195
+ }
196
+
197
+ /** The files a publish would take: the included ones, or every change when `includeAll`. */
198
+ function filesToPublish(includeAll: boolean): GitFileStatus[] {
199
+ const files = shell.git.status?.files ?? [];
200
+ return includeAll ? files : files.filter((file) => Boolean(file.staged));
201
+ }
202
+
203
+ /**
204
+ * Why the primary button is disabled, or `""` when it may run. One sentence, drawn beside it.
205
+ *
206
+ * @param destination Where the change set would go.
207
+ * @param includeAll Whether the caller publishes every change (the quick dialog) or only the
208
+ * included ones (Review changes).
209
+ */
210
+ export function publishBlocker(destination: PublishDestination, includeAll = false): string {
211
+ const { status } = shell.git;
212
+ if (!projectState || !status?.isRepo) {
213
+ return "Track this project with git first.";
214
+ }
215
+ if (shell.git.loading) {
216
+ return "Source control is busy.";
217
+ }
218
+ if (status.files.length === 0) {
219
+ return "There is nothing to publish.";
220
+ }
221
+ if (filesToPublish(includeAll).length === 0) {
222
+ return "Include at least one change.";
223
+ }
224
+ if (!shell.git.commitMessage.trim()) {
225
+ return "Write a summary of the change first.";
226
+ }
227
+ return destination === "review" ? reviewRefusal() : "";
228
+ }
229
+
230
+ // ─── Checks ──────────────────────────────────────────────────────────────────
231
+
232
+ /** One check, as a row draws it. */
233
+ export interface PublishCheck {
234
+ key: "deploy" | "build";
235
+ /** `done`, `todo`, `unknown` (not asked), `running` or `failed`. */
236
+ state: "done" | "todo" | "unknown" | "running" | "failed";
237
+ text: string;
238
+ /** The command that resolves a deploy step, or `""`. */
239
+ command: string;
240
+ }
241
+
242
+ /** The change set a build check is about: the changed paths and their letters. */
243
+ function changeSignature(): string {
244
+ return (shell.git.status?.files ?? []).map((file) => `${file.status}:${file.path}`).join("|");
245
+ }
246
+
247
+ /** Whether this host can build the site at all (`StudioPlatform.buildSite`). */
248
+ export function canCheckBuild(): boolean {
249
+ return hasPlatform() && getPlatform().buildSite !== undefined;
250
+ }
251
+
252
+ /**
253
+ * Build the site and record what it said, for the change set as it stands.
254
+ *
255
+ * A live preview is not a build and the check says so: a host that renders the working tree in the
256
+ * browser (the cloud) has prerendered nothing, so "the site builds" would be a claim it cannot
257
+ * make.
258
+ */
259
+ export async function runBuildCheck(): Promise<void> {
260
+ if (!canCheckBuild() || shell.publish.build.state === "running") {
261
+ return;
262
+ }
263
+ const build = getPlatform().buildSite;
264
+ if (!build) {
265
+ return;
266
+ }
267
+ shell.publish.build.state = "running";
268
+ shell.publish.build.text = "Building the site…";
269
+ shell.publish.build.for = changeSignature();
270
+ try {
271
+ const result = await build();
272
+ if (result.errors.length > 0) {
273
+ shell.publish.build.state = "failed";
274
+ shell.publish.build.text = `Built with ${result.errors.length} error(s): ${result.errors[0]}`;
275
+ } else {
276
+ shell.publish.build.state = "passed";
277
+ shell.publish.build.text =
278
+ result.mode === "live"
279
+ ? `${result.routes} page(s) render. This host previews the working tree; it does not build.`
280
+ : `Site builds: ${result.routes} page(s).`;
281
+ }
282
+ } catch (error) {
283
+ shell.publish.build.state = "failed";
284
+ shell.publish.build.text = `The site could not be built: ${errorMessage(error)}`;
285
+ }
286
+ }
287
+
288
+ /**
289
+ * The checks a change set is published under: the deploy checklist's next step, and a build check
290
+ * where the host can build. A build check about a different set of changes is not shown as passed.
291
+ */
292
+ export function publishChecks(): PublishCheck[] {
293
+ const checks: PublishCheck[] = [];
294
+ const next = nextDeployStep();
295
+ checks.push(
296
+ next
297
+ ? {
298
+ command: next.command,
299
+ key: "deploy",
300
+ state: next.state === "unknown" ? "unknown" : "todo",
301
+ text: `${next.label}: ${next.detail}`,
302
+ }
303
+ : {
304
+ command: "",
305
+ key: "deploy",
306
+ state: "done",
307
+ text: "Everything this project needs to ship is in place.",
308
+ },
309
+ );
310
+ if (canCheckBuild()) {
311
+ const current =
312
+ shell.publish.build.for === changeSignature() || shell.publish.build.state === "running";
313
+ checks.push(
314
+ current && shell.publish.build.state !== "idle"
315
+ ? {
316
+ command: "",
317
+ key: "build",
318
+ state:
319
+ shell.publish.build.state === "passed"
320
+ ? "done"
321
+ : shell.publish.build.state === "failed"
322
+ ? "failed"
323
+ : "running",
324
+ text: shell.publish.build.text,
325
+ }
326
+ : {
327
+ command: "",
328
+ key: "build",
329
+ state: "unknown",
330
+ text: "The site has not been built with these changes.",
331
+ },
332
+ );
333
+ }
334
+ return checks;
335
+ }
336
+
337
+ /** The checks as one line, for the quick publish dialog: what is not done, or that all is. */
338
+ export function checksLine(checks: readonly PublishCheck[]): string {
339
+ const open = checks.filter((check) => check.state !== "done");
340
+ if (open.length === 0) {
341
+ return "Checks passed: ready to publish.";
342
+ }
343
+ return open.map((check) => check.text).join(" · ");
344
+ }
345
+
346
+ // ─── The operation ───────────────────────────────────────────────────────────
347
+
348
+ /** The last pull request this session opened, or null. */
349
+ export function lastPullRequest(): { number: number; url: string } | null {
350
+ return shell.publish.review.number > 0
351
+ ? { number: shell.publish.review.number, url: shell.publish.review.url }
352
+ : null;
353
+ }
354
+
355
+ /**
356
+ * Put the summary back after a publish that failed before its commit landed, unless the author has
357
+ * already typed another.
358
+ */
359
+ function restoreSummary(message: string): void {
360
+ if (!shell.git.commitMessage) {
361
+ shell.git.commitMessage = message;
362
+ }
363
+ }
364
+
365
+ /**
366
+ * Publish the change set to a destination.
367
+ *
368
+ * @param destination `live` or `review`; a refused review is never run.
369
+ * @param options `includeAll` stages every change first (the quick dialog); otherwise only the
370
+ * included files are committed.
371
+ * @returns Whether the change set reached its destination. A failure is already on screen.
372
+ */
373
+ export async function publishChanges(
374
+ destination: PublishDestination,
375
+ options: { includeAll?: boolean } = {},
376
+ ): Promise<boolean> {
377
+ const includeAll = options.includeAll ?? false;
378
+ const blocker = publishBlocker(destination, includeAll);
379
+ if (blocker) {
380
+ shell.git.error = blocker;
381
+ return false;
382
+ }
383
+ const message = shell.git.commitMessage.trim();
384
+ const plat = getPlatform();
385
+ shell.git.commitMessage = "";
386
+ shell.git.loading = true;
387
+ shell.git.error = null;
388
+ // Fold co-editing sessions into the backend's tree first so the commit never misses trailing
389
+ // Keystrokes (the mirror is debounced).
390
+ await flushAllCollab();
391
+ let committed = false;
392
+ // Whether the commit left for its destination. Only a deploy can say no without throwing.
393
+ let shipped = true;
394
+ try {
395
+ if (includeAll) {
396
+ const unstaged = filesToPublish(true)
397
+ .filter((file) => !file.staged)
398
+ .map((file) => file.path);
399
+ if (unstaged.length > 0) {
400
+ await plat.gitStage(unstaged);
401
+ }
402
+ }
403
+ if (destination === "review") {
404
+ await sendForReview(plat, message, () => {
405
+ committed = true;
406
+ });
407
+ } else {
408
+ await plat.gitCommit(message);
409
+ committed = true;
410
+ if (deployReady()) {
411
+ /* The deploy is an Activity with its own steps, log and failure report (§16.4), and it
412
+ pushes with an upstream itself, so it runs after the loading flag is down: a running
413
+ deploy is not source control being busy. */
414
+ shell.git.loading = false;
415
+ /* `false` is a push that failed, a Cloudflare that did not answer, or a cancel; the
416
+ Activity has already said which. The commit landed either way, so the summary stays
417
+ cleared, but the change set did not reach the live site and the caller must not say it
418
+ did. */
419
+ shipped = await runDeploy();
420
+ } else if (!platformHostsGit() && firstRemote() !== "") {
421
+ await plat.gitPush();
422
+ }
423
+ }
424
+ await refreshGitStatus();
425
+ return shipped;
426
+ } catch (error) {
427
+ shell.git.error = errorMessage(error);
428
+ shell.git.loading = false;
429
+ // A push that failed after the commit landed must not offer the same summary again.
430
+ if (!committed) {
431
+ restoreSummary(message);
432
+ }
433
+ return false;
434
+ }
435
+ }
436
+
437
+ /** What a pull request is opened with: its title, and the branches when the flow chose them. */
438
+ interface PullRequestRequest {
439
+ title: string;
440
+ head?: string;
441
+ base?: string;
442
+ }
443
+
444
+ /**
445
+ * Commit for review and say what the pull request is opened from.
446
+ *
447
+ * On a host whose branches are sessions, the commit lands on the session's branch, which already is
448
+ * the branch the pull request is opened from. Elsewhere the change set gets a `studio/` branch of
449
+ * its own, pushed with an upstream, and the pull request goes from it into the branch the author
450
+ * was on.
451
+ */
452
+ async function commitForReview(
453
+ plat: ReturnType<typeof getPlatform>,
454
+ message: string,
455
+ onCommitted: () => void,
456
+ ): Promise<PullRequestRequest> {
457
+ if (platformHostsGit()) {
458
+ // `reviewRefusal` has already refused the default branch, so this commit is not a live one.
459
+ await plat.gitCommit(message);
460
+ onCommitted();
461
+ const base = defaultBranch();
462
+ return base ? { base, title: message } : { title: message };
463
+ }
464
+ const base = currentBranch();
465
+ const head = reviewBranchName(message);
466
+ await plat.gitCreateBranch(head);
467
+ await plat.gitCommit(message);
468
+ onCommitted();
469
+ await plat.gitPush({ setUpstream: true });
470
+ return base ? { base, head, title: message } : { head, title: message };
471
+ }
472
+
473
+ /** Send a change set for review: the commit, then the pull request, then where it went. */
474
+ async function sendForReview(
475
+ plat: ReturnType<typeof getPlatform>,
476
+ message: string,
477
+ onCommitted: () => void,
478
+ ): Promise<void> {
479
+ const open = plat.createPullRequest;
480
+ if (!open) {
481
+ throw new Error(reviewRefusal());
482
+ }
483
+ const pr = await open(await commitForReview(plat, message, onCommitted));
484
+ shell.publish.review.number = pr.number;
485
+ shell.publish.review.url = pr.url;
486
+ notify.success(`Pull request #${pr.number} opened for review.`, {
487
+ detail: pr.url,
488
+ key: "publish.review",
489
+ source: "Publish",
490
+ });
491
+ }
@@ -8,13 +8,15 @@
8
8
  * ships a site was, in the shipped app, unreachable. The toolbar's Publish button had already gone
9
9
  * with the toolbar, and nothing replaced it.
10
10
  *
11
- * Three records, always reachable, each disabled with the one sentence that says why:
11
+ * Five records, always reachable, each disabled with the one sentence that says why:
12
12
  *
13
- * | id | what it does |
14
- * | ----------------------- | --------------------------------------------------------- |
15
- * | `publish.setUp` | opens the provider connection flow |
16
- * | `publish.deploy` | pushes the branch and asks Cloudflare what it did with it |
17
- * | `publish.openDashboard` | opens the connected Pages project on Cloudflare |
13
+ * | id | what it does |
14
+ * | ----------------------- | ----------------------------------------------------------- |
15
+ * | `publish.setUp` | opens the provider connection flow |
16
+ * | `publish.deploy` | pushes the branch and asks Cloudflare what it did with it |
17
+ * | `publish.openDashboard` | opens the connected Pages project on Cloudflare |
18
+ * | `publish.quick` | opens the quick publish dialog (the chevron beside Publish) |
19
+ * | `publish.open` | shows the Publish workspace, on one of its four sub-tabs |
18
20
  *
19
21
  * **`runDeploy` is an Activity, not a toast.** A deploy pushes a branch and then waits on a build
20
22
  * that is happening somewhere else; that is the definition of the long operation §16.4 gave the
@@ -25,17 +27,21 @@
25
27
  * whether one is connected is a `project.json` question; the token that proves it is read only by
26
28
  * `platforms/devserver.ts` on its way to the same-origin proxy (`studio.md` §15 rule 1).
27
29
  *
28
- * **The panel is imported lazily** so this module carries no DOM at import time: `commands/
29
- * app-commands.ts` is loaded by three CI checks in a bare Bun process, and a module that opens a
30
- * modal at import would break all three.
30
+ * **The panel, the workspace and the quick dialog are imported lazily** so this module carries no
31
+ * DOM at import time: `commands/app-commands.ts` is loaded by three CI checks in a bare Bun
32
+ * process, and a module that opens a modal at import would break all three.
31
33
  */
32
34
 
33
35
  import { getPlatform } from "../platform";
34
36
  import { beginActivity } from "../panels/activity-panel";
35
37
  import { currentDeploy, noteDeployment } from "./deploy-checklist";
36
38
  import { errorMessage } from "@jxsuite/schema/parse";
37
- import { latestDeployment, platformSupportsPublish } from "./pages-service";
39
+ import { latestDeployment } from "./pages-service";
40
+ import { activeRegistry } from "../commands/active-registry";
41
+ import { argsSchema, enumArg, enumProperty } from "../commands/command-args";
42
+ import { PUBLISH_TABS } from "./publish-ids";
38
43
  import type { AnyCommand, CommandRegistry } from "../commands/registry";
44
+ import type { CommandArgValues } from "../commands/command-args";
39
45
 
40
46
  /**
41
47
  * How long the deploy waits for Cloudflare to admit the push happened.
@@ -133,12 +139,11 @@ export async function runDeploy(
133
139
  }
134
140
 
135
141
  /**
136
- * The three records.
142
+ * The five records.
137
143
  *
138
- * `enablement` reads `platformSupportsPublish()` rather than a `capability.*` key because there is
139
- * no `publish` capability yet — adding one is a `commands/context.ts` + `commands/live-context.ts`
140
- * change, and §13.4 is explicit that PAL differences belong there. Until it exists this is the one
141
- * `if (platform.x)` the family carries, in the one place a reader looks for it.
144
+ * Whether the host can reach Cloudflare is `ctx.capability.publish` (presence of the PAL's
145
+ * `cfApi`), so the family's refusals read the context like every other PAL difference does (§13.4)
146
+ * rather than asking the platform from inside a predicate.
142
147
  */
143
148
  export function publishCommands(): AnyCommand[] {
144
149
  return [
@@ -158,7 +163,7 @@ export function publishCommands(): AnyCommand[] {
158
163
  requires: "an open project on a platform that can reach the Cloudflare API",
159
164
  when: (ctx) => ctx.project.open,
160
165
  // `when` already asked about the project.
161
- enablement: () => platformSupportsPublish(),
166
+ enablement: (ctx) => ctx.capability.publish,
162
167
  /* No `aiTool`, by `studio-ui-guidelines.md` §12.4's second rule: an auth flow that waits on a
163
168
  person, with credentials. */
164
169
  run: async () => {
@@ -178,7 +183,7 @@ export function publishCommands(): AnyCommand[] {
178
183
  "reach the Cloudflare API",
179
184
  when: (ctx) => ctx.project.open,
180
185
  enablement: (ctx) =>
181
- ctx.project.isRepo && currentDeploy() !== undefined && platformSupportsPublish(),
186
+ ctx.project.isRepo && currentDeploy() !== undefined && ctx.capability.publish,
182
187
  /* No `aiTool`, by `studio-ui-guidelines.md` §12.4's third rule: remote and irreversible, the
183
188
  same class as `packages.remove`. */
184
189
  run: async () => {
@@ -194,7 +199,7 @@ export function publishCommands(): AnyCommand[] {
194
199
  group: "8_publish",
195
200
  requires: "a connected deploy provider, on a platform that can reach the Cloudflare API",
196
201
  when: (ctx) => ctx.project.open,
197
- enablement: () => currentDeploy() !== undefined && platformSupportsPublish(),
202
+ enablement: (ctx) => currentDeploy() !== undefined && ctx.capability.publish,
198
203
  run: () => {
199
204
  const deploy = currentDeploy();
200
205
  if (deploy) {
@@ -203,6 +208,66 @@ export function publishCommands(): AnyCommand[] {
203
208
  },
204
209
  title: "Open Deployment Dashboard",
205
210
  },
211
+ {
212
+ category: "Publish",
213
+ id: "publish.quick",
214
+ level: "project",
215
+ /* Overflow and palette, never `commandbar/primary`: the Command Bar draws it as the chevron
216
+ beside the Publish workspace tab (studio.md §22.2), which is a rendering of this record,
217
+ and publishing is a workspace rather than a primary verb. */
218
+ menus: ["commandbar/overflow", "palette"],
219
+ group: "8_publish",
220
+ requires: "a project tracked by git",
221
+ when: (ctx) => ctx.project.open,
222
+ enablement: (ctx) => ctx.project.isRepo,
223
+ /* No `aiTool`, by `studio-ui-guidelines.md` §12.4's first rule: it opens a dialog for a
224
+ person, and what that dialog publishes is the person's to send. */
225
+ run: async () => {
226
+ const { openQuickPublish } = await import("./publish-quick");
227
+ openQuickPublish();
228
+ },
229
+ title: "Quick Publish",
230
+ },
231
+ {
232
+ args: argsSchema(
233
+ {
234
+ tab: enumProperty(
235
+ PUBLISH_TABS,
236
+ "Which view of the Publish workspace to show: review (the changes and where they " +
237
+ "go), deploys (the live site and its deployments), branches, or hosting (where the " +
238
+ "project is saved and hosted). Defaults to the view the workspace was left on.",
239
+ ),
240
+ },
241
+ [],
242
+ ),
243
+ category: "Publish",
244
+ id: "publish.open",
245
+ level: "project",
246
+ /* `never`, for the reason `styles.open` gives: the palette's way into Publish is
247
+ `workspace.focus.publish` ("Go to Publish"), and a second row running the same switch would
248
+ be the same action under a second name. This is the scripted door, and `tab` is what it can
249
+ say that the chord cannot: the quick dialog's Review all and the screenshot manifest name
250
+ it. */
251
+ menus: ["never"],
252
+ group: "8_publish",
253
+ requires: "an open project",
254
+ enablement: (ctx) => ctx.project.open,
255
+ /* No `aiTool`, by `studio-ui-guidelines.md` §12.4's first rule: it shows a surface. */
256
+ run: async (_commandCtx, args: CommandArgValues) => {
257
+ const tab =
258
+ args["tab"] === undefined ? null : enumArg("publish.open", args, "tab", PUBLISH_TABS);
259
+ const registry = activeRegistry();
260
+ if (!registry) {
261
+ throw new Error('command "publish.open" needs the window\'s command registry');
262
+ }
263
+ await registry.run("view.setWorkspace", { workspace: "publish" });
264
+ if (tab !== null) {
265
+ const { showPublishTab } = await import("./publish-workspace");
266
+ showPublishTab(tab);
267
+ }
268
+ },
269
+ title: "Show Publish",
270
+ },
206
271
  ];
207
272
  }
208
273