@aphexcms/cms-core 2.0.9 → 2.0.11

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 (381) hide show
  1. package/LICENSE +21 -0
  2. package/dist/api/api-keys.d.ts +8 -7
  3. package/dist/api/api-keys.d.ts.map +1 -1
  4. package/dist/api/assets.d.ts +7 -22
  5. package/dist/api/assets.d.ts.map +1 -1
  6. package/dist/api/assets.js +1 -10
  7. package/dist/api/documents.d.ts +17 -16
  8. package/dist/api/documents.d.ts.map +1 -1
  9. package/dist/api/documents.js +2 -2
  10. package/dist/api/index.d.ts +1 -0
  11. package/dist/api/index.d.ts.map +1 -1
  12. package/dist/api/index.js +1 -0
  13. package/dist/api/organizations.d.ts +15 -35
  14. package/dist/api/organizations.d.ts.map +1 -1
  15. package/dist/api/roles.d.ts +22 -0
  16. package/dist/api/roles.d.ts.map +1 -0
  17. package/dist/api/roles.js +26 -0
  18. package/dist/api/schemas/api-keys.d.ts +62 -0
  19. package/dist/api/schemas/api-keys.d.ts.map +1 -0
  20. package/dist/api/schemas/api-keys.js +28 -0
  21. package/dist/api/schemas/assets.d.ts +174 -0
  22. package/dist/api/schemas/assets.d.ts.map +1 -0
  23. package/dist/api/schemas/assets.js +99 -0
  24. package/dist/api/schemas/documents.d.ts +325 -0
  25. package/dist/api/schemas/documents.d.ts.map +1 -0
  26. package/dist/api/schemas/documents.js +161 -0
  27. package/dist/api/schemas/organizations.d.ts +41 -0
  28. package/dist/api/schemas/organizations.d.ts.map +1 -0
  29. package/dist/api/schemas/organizations.js +56 -0
  30. package/dist/api/schemas/roles.d.ts +77 -0
  31. package/dist/api/schemas/roles.d.ts.map +1 -0
  32. package/dist/api/schemas/roles.js +42 -0
  33. package/dist/api/schemas/user.d.ts +10 -0
  34. package/dist/api/schemas/user.d.ts.map +1 -0
  35. package/dist/api/schemas/user.js +11 -0
  36. package/dist/api/user.d.ts +4 -6
  37. package/dist/api/user.d.ts.map +1 -1
  38. package/dist/app-augment.d.ts +32 -0
  39. package/dist/app-augment.d.ts.map +1 -0
  40. package/dist/app-augment.js +18 -0
  41. package/dist/auth/auth-hooks.d.ts +2 -1
  42. package/dist/auth/auth-hooks.d.ts.map +1 -1
  43. package/dist/auth/auth-hooks.js +22 -2
  44. package/dist/auth/provider.d.ts +5 -0
  45. package/dist/auth/provider.d.ts.map +1 -1
  46. package/dist/cli/index.js +0 -0
  47. package/dist/client/index.d.ts +4 -0
  48. package/dist/client/index.d.ts.map +1 -1
  49. package/dist/client/index.js +7 -0
  50. package/dist/components/AdminApp.svelte +306 -142
  51. package/dist/components/AdminApp.svelte.d.ts +8 -0
  52. package/dist/components/AdminApp.svelte.d.ts.map +1 -1
  53. package/dist/components/admin/DocumentEditor.svelte +653 -365
  54. package/dist/components/admin/DocumentEditor.svelte.d.ts +2 -0
  55. package/dist/components/admin/DocumentEditor.svelte.d.ts.map +1 -1
  56. package/dist/components/admin/DocumentVersionPanel.svelte +57 -44
  57. package/dist/components/admin/DocumentVersionPanel.svelte.d.ts.map +1 -1
  58. package/dist/components/admin/MediaBrowser.svelte +70 -30
  59. package/dist/components/admin/MediaBrowser.svelte.d.ts.map +1 -1
  60. package/dist/components/admin/ObjectModal.svelte +70 -95
  61. package/dist/components/admin/ObjectModal.svelte.d.ts +1 -2
  62. package/dist/components/admin/ObjectModal.svelte.d.ts.map +1 -1
  63. package/dist/components/admin/PermissionsDebug.svelte +119 -0
  64. package/dist/components/admin/PermissionsDebug.svelte.d.ts +4 -0
  65. package/dist/components/admin/PermissionsDebug.svelte.d.ts.map +1 -0
  66. package/dist/components/admin/SchemaField.svelte +3 -1
  67. package/dist/components/admin/SchemaField.svelte.d.ts.map +1 -1
  68. package/dist/components/admin/confirm-dialog/ConfirmDialogHost.svelte +35 -0
  69. package/dist/components/admin/confirm-dialog/ConfirmDialogHost.svelte.d.ts +19 -0
  70. package/dist/components/admin/confirm-dialog/ConfirmDialogHost.svelte.d.ts.map +1 -0
  71. package/dist/components/admin/confirm-dialog/confirm-dialog.svelte.d.ts +16 -0
  72. package/dist/components/admin/confirm-dialog/confirm-dialog.svelte.d.ts.map +1 -0
  73. package/dist/components/admin/confirm-dialog/confirm-dialog.svelte.js +29 -0
  74. package/dist/components/admin/fields/ArrayField.svelte +104 -108
  75. package/dist/components/admin/fields/ArrayField.svelte.d.ts.map +1 -1
  76. package/dist/components/admin/fields/FileField.svelte +22 -17
  77. package/dist/components/admin/fields/FileField.svelte.d.ts.map +1 -1
  78. package/dist/components/admin/fields/ImageField.svelte +21 -15
  79. package/dist/components/admin/fields/ImageField.svelte.d.ts.map +1 -1
  80. package/dist/components/admin/fields/ReferenceField.svelte +142 -112
  81. package/dist/components/admin/fields/ReferenceField.svelte.d.ts.map +1 -1
  82. package/dist/components/admin/fields/TextareaField.svelte +4 -3
  83. package/dist/components/admin/fields/TextareaField.svelte.d.ts +2 -2
  84. package/dist/components/admin/fields/TextareaField.svelte.d.ts.map +1 -1
  85. package/dist/components/layout/Sidebar.svelte +21 -11
  86. package/dist/components/layout/Sidebar.svelte.d.ts.map +1 -1
  87. package/dist/components/layout/sidebar/NavMain.svelte +1 -0
  88. package/dist/db/interfaces/document.d.ts.map +1 -1
  89. package/dist/db/interfaces/index.d.ts +3 -1
  90. package/dist/db/interfaces/index.d.ts.map +1 -1
  91. package/dist/db/interfaces/organization.d.ts +1 -1
  92. package/dist/db/interfaces/organization.d.ts.map +1 -1
  93. package/dist/db/interfaces/role.d.ts +25 -0
  94. package/dist/db/interfaces/role.d.ts.map +1 -0
  95. package/dist/db/interfaces/role.js +1 -0
  96. package/dist/engine.d.ts.map +1 -1
  97. package/dist/engine.js +5 -0
  98. package/dist/field-access.d.ts +30 -0
  99. package/dist/field-access.d.ts.map +1 -0
  100. package/dist/field-access.js +79 -0
  101. package/dist/hooks.d.ts +2 -0
  102. package/dist/hooks.d.ts.map +1 -1
  103. package/dist/hooks.js +23 -13
  104. package/dist/lib/api/api-keys.d.ts +8 -7
  105. package/dist/lib/api/api-keys.d.ts.map +1 -1
  106. package/dist/lib/api/api-keys.js.map +1 -1
  107. package/dist/lib/api/assets.d.ts +7 -22
  108. package/dist/lib/api/assets.d.ts.map +1 -1
  109. package/dist/lib/api/assets.js +1 -10
  110. package/dist/lib/api/assets.js.map +1 -1
  111. package/dist/lib/api/documents.d.ts +17 -16
  112. package/dist/lib/api/documents.d.ts.map +1 -1
  113. package/dist/lib/api/documents.js +2 -2
  114. package/dist/lib/api/documents.js.map +1 -1
  115. package/dist/lib/api/index.d.ts +1 -0
  116. package/dist/lib/api/index.d.ts.map +1 -1
  117. package/dist/lib/api/index.js +1 -0
  118. package/dist/lib/api/index.js.map +1 -1
  119. package/dist/lib/api/organizations.d.ts +15 -35
  120. package/dist/lib/api/organizations.d.ts.map +1 -1
  121. package/dist/lib/api/organizations.js.map +1 -1
  122. package/dist/lib/api/roles.d.ts +22 -0
  123. package/dist/lib/api/roles.d.ts.map +1 -0
  124. package/dist/lib/api/roles.js +27 -0
  125. package/dist/lib/api/roles.js.map +1 -0
  126. package/dist/lib/api/schemas/api-keys.d.ts +62 -0
  127. package/dist/lib/api/schemas/api-keys.d.ts.map +1 -0
  128. package/dist/lib/api/schemas/api-keys.js +29 -0
  129. package/dist/lib/api/schemas/api-keys.js.map +1 -0
  130. package/dist/lib/api/schemas/assets.d.ts +174 -0
  131. package/dist/lib/api/schemas/assets.d.ts.map +1 -0
  132. package/dist/lib/api/schemas/assets.js +100 -0
  133. package/dist/lib/api/schemas/assets.js.map +1 -0
  134. package/dist/lib/api/schemas/documents.d.ts +325 -0
  135. package/dist/lib/api/schemas/documents.d.ts.map +1 -0
  136. package/dist/lib/api/schemas/documents.js +162 -0
  137. package/dist/lib/api/schemas/documents.js.map +1 -0
  138. package/dist/lib/api/schemas/organizations.d.ts +41 -0
  139. package/dist/lib/api/schemas/organizations.d.ts.map +1 -0
  140. package/dist/lib/api/schemas/organizations.js +57 -0
  141. package/dist/lib/api/schemas/organizations.js.map +1 -0
  142. package/dist/lib/api/schemas/roles.d.ts +77 -0
  143. package/dist/lib/api/schemas/roles.d.ts.map +1 -0
  144. package/dist/lib/api/schemas/roles.js +43 -0
  145. package/dist/lib/api/schemas/roles.js.map +1 -0
  146. package/dist/lib/api/schemas/user.d.ts +10 -0
  147. package/dist/lib/api/schemas/user.d.ts.map +1 -0
  148. package/dist/lib/api/schemas/user.js +12 -0
  149. package/dist/lib/api/schemas/user.js.map +1 -0
  150. package/dist/lib/api/user.d.ts +4 -6
  151. package/dist/lib/api/user.d.ts.map +1 -1
  152. package/dist/lib/api/user.js.map +1 -1
  153. package/dist/lib/app-augment.d.ts +32 -0
  154. package/dist/lib/app-augment.d.ts.map +1 -0
  155. package/dist/lib/app-augment.js +19 -0
  156. package/dist/lib/app-augment.js.map +1 -0
  157. package/dist/lib/auth/auth-hooks.d.ts +2 -1
  158. package/dist/lib/auth/auth-hooks.d.ts.map +1 -1
  159. package/dist/lib/auth/auth-hooks.js +22 -2
  160. package/dist/lib/auth/auth-hooks.js.map +1 -1
  161. package/dist/lib/auth/provider.d.ts +5 -0
  162. package/dist/lib/auth/provider.d.ts.map +1 -1
  163. package/dist/lib/client/index.d.ts +4 -0
  164. package/dist/lib/client/index.d.ts.map +1 -1
  165. package/dist/lib/client/index.js +7 -0
  166. package/dist/lib/client/index.js.map +1 -1
  167. package/dist/lib/components/admin/confirm-dialog/confirm-dialog.svelte.d.ts +16 -0
  168. package/dist/lib/components/admin/confirm-dialog/confirm-dialog.svelte.d.ts.map +1 -0
  169. package/dist/lib/components/admin/confirm-dialog/confirm-dialog.svelte.js +30 -0
  170. package/dist/lib/components/admin/confirm-dialog/confirm-dialog.svelte.js.map +1 -0
  171. package/dist/lib/db/interfaces/document.d.ts.map +1 -1
  172. package/dist/lib/db/interfaces/index.d.ts +3 -1
  173. package/dist/lib/db/interfaces/index.d.ts.map +1 -1
  174. package/dist/lib/db/interfaces/organization.d.ts +1 -1
  175. package/dist/lib/db/interfaces/organization.d.ts.map +1 -1
  176. package/dist/lib/db/interfaces/role.d.ts +25 -0
  177. package/dist/lib/db/interfaces/role.d.ts.map +1 -0
  178. package/dist/lib/db/interfaces/role.js +2 -0
  179. package/dist/lib/db/interfaces/role.js.map +1 -0
  180. package/dist/lib/engine.d.ts.map +1 -1
  181. package/dist/lib/engine.js +5 -0
  182. package/dist/lib/engine.js.map +1 -1
  183. package/dist/lib/field-access.d.ts +30 -0
  184. package/dist/lib/field-access.d.ts.map +1 -0
  185. package/dist/lib/field-access.js +80 -0
  186. package/dist/lib/field-access.js.map +1 -0
  187. package/dist/lib/hooks.d.ts +2 -0
  188. package/dist/lib/hooks.d.ts.map +1 -1
  189. package/dist/lib/hooks.js +23 -13
  190. package/dist/lib/hooks.js.map +1 -1
  191. package/dist/lib/local-api/collection-api.d.ts +2 -0
  192. package/dist/lib/local-api/collection-api.d.ts.map +1 -1
  193. package/dist/lib/local-api/collection-api.js +98 -30
  194. package/dist/lib/local-api/collection-api.js.map +1 -1
  195. package/dist/lib/local-api/index.d.ts.map +1 -1
  196. package/dist/lib/local-api/index.js.map +1 -1
  197. package/dist/lib/local-api/permissions.d.ts +26 -26
  198. package/dist/lib/local-api/permissions.d.ts.map +1 -1
  199. package/dist/lib/local-api/permissions.js +122 -80
  200. package/dist/lib/local-api/permissions.js.map +1 -1
  201. package/dist/lib/permissions-context.svelte.d.ts +44 -0
  202. package/dist/lib/permissions-context.svelte.d.ts.map +1 -0
  203. package/dist/lib/permissions-context.svelte.js +80 -0
  204. package/dist/lib/permissions-context.svelte.js.map +1 -0
  205. package/dist/lib/routes/assets-bulk.d.ts.map +1 -1
  206. package/dist/lib/routes/assets-bulk.js +10 -3
  207. package/dist/lib/routes/assets-bulk.js.map +1 -1
  208. package/dist/lib/routes/assets-by-id.d.ts.map +1 -1
  209. package/dist/lib/routes/assets-by-id.js +11 -1
  210. package/dist/lib/routes/assets-by-id.js.map +1 -1
  211. package/dist/lib/routes/assets-references-counts.d.ts.map +1 -1
  212. package/dist/lib/routes/assets-references-counts.js +12 -2
  213. package/dist/lib/routes/assets-references-counts.js.map +1 -1
  214. package/dist/lib/routes/assets.d.ts.map +1 -1
  215. package/dist/lib/routes/assets.js +14 -13
  216. package/dist/lib/routes/assets.js.map +1 -1
  217. package/dist/lib/routes/document-versions.d.ts.map +1 -1
  218. package/dist/lib/routes/document-versions.js +16 -2
  219. package/dist/lib/routes/document-versions.js.map +1 -1
  220. package/dist/lib/routes/documents-by-id.d.ts.map +1 -1
  221. package/dist/lib/routes/documents-by-id.js +15 -3
  222. package/dist/lib/routes/documents-by-id.js.map +1 -1
  223. package/dist/lib/routes/documents-query.d.ts.map +1 -1
  224. package/dist/lib/routes/documents-query.js +13 -10
  225. package/dist/lib/routes/documents-query.js.map +1 -1
  226. package/dist/lib/routes/documents.d.ts.map +1 -1
  227. package/dist/lib/routes/documents.js +29 -26
  228. package/dist/lib/routes/documents.js.map +1 -1
  229. package/dist/lib/routes/organizations-by-id.d.ts.map +1 -1
  230. package/dist/lib/routes/organizations-by-id.js +17 -4
  231. package/dist/lib/routes/organizations-by-id.js.map +1 -1
  232. package/dist/lib/routes/organizations-invitations.d.ts.map +1 -1
  233. package/dist/lib/routes/organizations-invitations.js +48 -18
  234. package/dist/lib/routes/organizations-invitations.js.map +1 -1
  235. package/dist/lib/routes/organizations-members.d.ts.map +1 -1
  236. package/dist/lib/routes/organizations-members.js +24 -18
  237. package/dist/lib/routes/organizations-members.js.map +1 -1
  238. package/dist/lib/routes/organizations-switch.d.ts.map +1 -1
  239. package/dist/lib/routes/organizations-switch.js +7 -3
  240. package/dist/lib/routes/organizations-switch.js.map +1 -1
  241. package/dist/lib/routes/organizations.d.ts.map +1 -1
  242. package/dist/lib/routes/organizations.js +11 -5
  243. package/dist/lib/routes/organizations.js.map +1 -1
  244. package/dist/lib/routes/roles-by-name.d.ts +4 -0
  245. package/dist/lib/routes/roles-by-name.d.ts.map +1 -0
  246. package/dist/lib/routes/roles-by-name.js +112 -0
  247. package/dist/lib/routes/roles-by-name.js.map +1 -0
  248. package/dist/lib/routes/roles.d.ts +4 -0
  249. package/dist/lib/routes/roles.d.ts.map +1 -0
  250. package/dist/lib/routes/roles.js +91 -0
  251. package/dist/lib/routes/roles.js.map +1 -0
  252. package/dist/lib/routes/user-preferences.d.ts.map +1 -1
  253. package/dist/lib/routes/user-preferences.js +7 -13
  254. package/dist/lib/routes/user-preferences.js.map +1 -1
  255. package/dist/lib/routes-exports.d.ts +2 -0
  256. package/dist/lib/routes-exports.d.ts.map +1 -1
  257. package/dist/lib/routes-exports.js +3 -0
  258. package/dist/lib/routes-exports.js.map +1 -1
  259. package/dist/lib/save-state-context.svelte.d.ts +8 -0
  260. package/dist/lib/save-state-context.svelte.d.ts.map +1 -0
  261. package/dist/lib/save-state-context.svelte.js +9 -0
  262. package/dist/lib/save-state-context.svelte.js.map +1 -0
  263. package/dist/lib/schema-utils/validator.d.ts.map +1 -1
  264. package/dist/lib/schema-utils/validator.js +14 -0
  265. package/dist/lib/schema-utils/validator.js.map +1 -1
  266. package/dist/lib/server/index.d.ts +1 -0
  267. package/dist/lib/server/index.d.ts.map +1 -1
  268. package/dist/lib/server/index.js +1 -0
  269. package/dist/lib/server/index.js.map +1 -1
  270. package/dist/lib/services/index.d.ts +1 -0
  271. package/dist/lib/services/index.d.ts.map +1 -1
  272. package/dist/lib/services/index.js +1 -0
  273. package/dist/lib/services/index.js.map +1 -1
  274. package/dist/lib/services/roles-service.d.ts +35 -0
  275. package/dist/lib/services/roles-service.d.ts.map +1 -0
  276. package/dist/lib/services/roles-service.js +91 -0
  277. package/dist/lib/services/roles-service.js.map +1 -0
  278. package/dist/lib/services/version-service.d.ts.map +1 -1
  279. package/dist/lib/services/version-service.js.map +1 -1
  280. package/dist/lib/types/auth.d.ts +43 -9
  281. package/dist/lib/types/auth.d.ts.map +1 -1
  282. package/dist/lib/types/auth.js +31 -26
  283. package/dist/lib/types/auth.js.map +1 -1
  284. package/dist/lib/types/capabilities.d.ts +104 -0
  285. package/dist/lib/types/capabilities.d.ts.map +1 -0
  286. package/dist/lib/types/capabilities.js +217 -0
  287. package/dist/lib/types/capabilities.js.map +1 -0
  288. package/dist/lib/types/index.d.ts +1 -0
  289. package/dist/lib/types/index.d.ts.map +1 -1
  290. package/dist/lib/types/index.js +1 -0
  291. package/dist/lib/types/index.js.map +1 -1
  292. package/dist/lib/types/organization.d.ts +13 -4
  293. package/dist/lib/types/organization.d.ts.map +1 -1
  294. package/dist/lib/types/schemas.d.ts +71 -0
  295. package/dist/lib/types/schemas.d.ts.map +1 -1
  296. package/dist/lib/types/sidebar.d.ts +1 -1
  297. package/dist/lib/types/sidebar.d.ts.map +1 -1
  298. package/dist/lib/utils/mime-detect.d.ts.map +1 -1
  299. package/dist/lib/utils/mime-detect.js +28 -6
  300. package/dist/lib/utils/mime-detect.js.map +1 -1
  301. package/dist/local-api/collection-api.d.ts +2 -0
  302. package/dist/local-api/collection-api.d.ts.map +1 -1
  303. package/dist/local-api/collection-api.js +98 -30
  304. package/dist/local-api/index.d.ts.map +1 -1
  305. package/dist/local-api/permissions.d.ts +26 -26
  306. package/dist/local-api/permissions.d.ts.map +1 -1
  307. package/dist/local-api/permissions.js +122 -80
  308. package/dist/permissions-context.svelte.d.ts +44 -0
  309. package/dist/permissions-context.svelte.d.ts.map +1 -0
  310. package/dist/permissions-context.svelte.js +79 -0
  311. package/dist/plugins/README.md +20 -20
  312. package/dist/routes/assets-bulk.d.ts.map +1 -1
  313. package/dist/routes/assets-bulk.js +10 -3
  314. package/dist/routes/assets-by-id.d.ts.map +1 -1
  315. package/dist/routes/assets-by-id.js +11 -1
  316. package/dist/routes/assets-references-counts.d.ts.map +1 -1
  317. package/dist/routes/assets-references-counts.js +12 -2
  318. package/dist/routes/assets.d.ts.map +1 -1
  319. package/dist/routes/assets.js +14 -13
  320. package/dist/routes/document-versions.d.ts.map +1 -1
  321. package/dist/routes/document-versions.js +16 -2
  322. package/dist/routes/documents-by-id.d.ts.map +1 -1
  323. package/dist/routes/documents-by-id.js +15 -3
  324. package/dist/routes/documents-query.d.ts.map +1 -1
  325. package/dist/routes/documents-query.js +13 -10
  326. package/dist/routes/documents.d.ts.map +1 -1
  327. package/dist/routes/documents.js +29 -26
  328. package/dist/routes/organizations-by-id.d.ts.map +1 -1
  329. package/dist/routes/organizations-by-id.js +17 -4
  330. package/dist/routes/organizations-invitations.d.ts.map +1 -1
  331. package/dist/routes/organizations-invitations.js +48 -18
  332. package/dist/routes/organizations-members.d.ts.map +1 -1
  333. package/dist/routes/organizations-members.js +24 -18
  334. package/dist/routes/organizations-switch.d.ts.map +1 -1
  335. package/dist/routes/organizations-switch.js +7 -3
  336. package/dist/routes/organizations.d.ts.map +1 -1
  337. package/dist/routes/organizations.js +11 -5
  338. package/dist/routes/roles-by-name.d.ts +4 -0
  339. package/dist/routes/roles-by-name.d.ts.map +1 -0
  340. package/dist/routes/roles-by-name.js +111 -0
  341. package/dist/routes/roles.d.ts +4 -0
  342. package/dist/routes/roles.d.ts.map +1 -0
  343. package/dist/routes/roles.js +90 -0
  344. package/dist/routes/user-preferences.d.ts.map +1 -1
  345. package/dist/routes/user-preferences.js +7 -13
  346. package/dist/routes-exports.d.ts +2 -0
  347. package/dist/routes-exports.d.ts.map +1 -1
  348. package/dist/routes-exports.js +3 -0
  349. package/dist/save-state-context.svelte.d.ts +8 -0
  350. package/dist/save-state-context.svelte.d.ts.map +1 -0
  351. package/dist/save-state-context.svelte.js +8 -0
  352. package/dist/schema-utils/validator.d.ts.map +1 -1
  353. package/dist/schema-utils/validator.js +14 -0
  354. package/dist/server/index.d.ts +1 -0
  355. package/dist/server/index.d.ts.map +1 -1
  356. package/dist/server/index.js +1 -0
  357. package/dist/services/index.d.ts +1 -0
  358. package/dist/services/index.d.ts.map +1 -1
  359. package/dist/services/index.js +1 -0
  360. package/dist/services/roles-service.d.ts +35 -0
  361. package/dist/services/roles-service.d.ts.map +1 -0
  362. package/dist/services/roles-service.js +90 -0
  363. package/dist/services/version-service.d.ts.map +1 -1
  364. package/dist/types/auth.d.ts +43 -9
  365. package/dist/types/auth.d.ts.map +1 -1
  366. package/dist/types/auth.js +31 -26
  367. package/dist/types/capabilities.d.ts +104 -0
  368. package/dist/types/capabilities.d.ts.map +1 -0
  369. package/dist/types/capabilities.js +216 -0
  370. package/dist/types/index.d.ts +1 -0
  371. package/dist/types/index.d.ts.map +1 -1
  372. package/dist/types/index.js +1 -0
  373. package/dist/types/organization.d.ts +13 -4
  374. package/dist/types/organization.d.ts.map +1 -1
  375. package/dist/types/schemas.d.ts +71 -0
  376. package/dist/types/schemas.d.ts.map +1 -1
  377. package/dist/types/sidebar.d.ts +1 -1
  378. package/dist/types/sidebar.d.ts.map +1 -1
  379. package/dist/utils/mime-detect.d.ts.map +1 -1
  380. package/dist/utils/mime-detect.js +28 -6
  381. package/package.json +142 -138
@@ -17,6 +17,7 @@
17
17
  import DocumentVersionPanel from './admin/DocumentVersionPanel.svelte';
18
18
  import DocumentsSkeleton from './admin/DocumentsSkeleton.svelte';
19
19
  import MediaBrowser from './admin/MediaBrowser.svelte';
20
+ import ConfirmDialogHost from './admin/confirm-dialog/ConfirmDialogHost.svelte';
20
21
  import { documents, organizations } from '../api/index';
21
22
  import {
22
23
  FileText,
@@ -34,6 +35,8 @@
34
35
  import { cmsLogger } from '../utils/logger';
35
36
  import { pluralize } from '../utils/pluralize';
36
37
  import { toast } from 'svelte-sonner';
38
+ import { resolve } from '$app/paths';
39
+ import { setPermissionsContext } from '../permissions-context.svelte';
37
40
 
38
41
  interface Props {
39
42
  schemas: SchemaType[];
@@ -42,6 +45,14 @@
42
45
  title?: string;
43
46
  graphqlSettings?: { endpoint: string; enableGraphiQL: boolean } | null;
44
47
  isReadOnly?: boolean;
48
+ /**
49
+ * Capabilities resolved for the current session. Used for per-action UI
50
+ * gating. When absent, all actions are shown and the server remains the
51
+ * enforcement surface.
52
+ */
53
+ capabilities?: string[];
54
+ /** Effective organization role name, for role-list style checks. */
55
+ rbacRole?: string | null;
45
56
  activeTab?: { value: 'structure' | 'vision' | 'media' };
46
57
  handleTabChange: (value: string) => void;
47
58
  userPreferences?: UserSessionPreferences | null;
@@ -54,27 +65,68 @@
54
65
  title = 'Aphex CMS',
55
66
  graphqlSettings = null,
56
67
  isReadOnly = false,
68
+ capabilities = [],
69
+ rbacRole = null,
57
70
  activeTab = { value: 'structure' } as { value: 'structure' | 'vision' | 'media' },
58
71
  handleTabChange = () => {},
59
72
  userPreferences = null
60
73
  }: Props = $props();
61
74
 
75
+ // Publish capabilities to every descendant (DocumentEditor, fields, etc)
76
+ // via Svelte context. Using a getter closure so prop reactivity propagates:
77
+ // if the parent swaps the capabilities array (e.g. role change mid-session)
78
+ // every `perms.can()` call in the subtree picks it up on next read.
79
+ const perms = setPermissionsContext(
80
+ () => capabilities,
81
+ () => rbacRole
82
+ );
83
+
62
84
  // Keep a state of the organization id
63
85
  let currentOrgId = $state<string | null>(page.url.searchParams.get('orgId'));
64
86
 
65
- // Merge document types with schema icons (schemas have icons, server data doesn't)
87
+ // Merge document types with schema icons (schemas have icons, server data doesn't),
88
+ // then filter out any schemas the caller can't read. Mirrors the server check:
89
+ // an `access.read` list on a schema is an allowlist of role names (built-in
90
+ // or custom); absence of a list means "whoever can read documents at all".
66
91
  const documentTypes = $derived(
67
- documentTypesFromServer.map((docType) => {
68
- const schema = schemas.find((s) => s.name === docType.name);
69
- return {
70
- ...docType,
71
- icon: schema?.icon
72
- };
73
- })
92
+ documentTypesFromServer
93
+ .map((docType) => {
94
+ const schema = schemas.find((s) => s.name === docType.name);
95
+ return {
96
+ ...docType,
97
+ icon: schema?.icon,
98
+ group: schema?.group,
99
+ access: schema?.access
100
+ };
101
+ })
102
+ .filter((docType) => {
103
+ const readList = docType.access?.read;
104
+ if (!readList) return true; // no list = open to any reader
105
+ // Functions (policy-based access) can't be evaluated on the client
106
+ // without a target doc — show them and let the server enforce.
107
+ if (typeof readList === 'function') return true;
108
+ const role = perms.role;
109
+ return role !== null && readList.includes(role);
110
+ })
74
111
  );
75
112
 
76
113
  const hasDocumentTypes = $derived(documentTypes.length > 0);
77
114
 
115
+ // Bucket document types by their `group` property. Ungrouped types sit in a
116
+ // leading null bucket; named groups follow in first-seen order.
117
+ const groupedDocumentTypes = $derived.by(() => {
118
+ const buckets = new Map<string | null, typeof documentTypes>();
119
+ buckets.set(null, []);
120
+ for (const dt of documentTypes) {
121
+ const key = dt.group ?? null;
122
+ if (!buckets.has(key)) buckets.set(key, []);
123
+ buckets.get(key)!.push(dt);
124
+ }
125
+ return Array.from(buckets.entries())
126
+ .filter(([, items]) => items.length > 0)
127
+ .map(([name, items]) => ({ name, items }));
128
+ });
129
+
78
130
  // Client-side routing state
79
131
  let currentView = $state<'dashboard' | 'documents' | 'editor'>('dashboard');
80
132
  let selectedDocumentType = $state<string | null>(null);
@@ -107,7 +159,11 @@
107
159
  // Version history panel state
108
160
  let showVersionPanel = $state(false);
109
161
  let versionPanelDocId = $state<string | null>(null);
110
- let versionPreviewData = $state<{ versionNumber: number; data: Record<string, any>; eventType: string } | null>(null);
162
+ let versionPreviewData = $state<{
163
+ versionNumber: number;
164
+ data: Record<string, any>;
165
+ eventType: string;
166
+ } | null>(null);
111
167
 
112
168
  // Documents list sorting state
113
169
  let sortDropdownOpen = $state(false);
@@ -169,14 +225,15 @@
169
225
  let activeEditorIndex = $state<number>(0);
170
226
 
171
227
  // Calculate how many editors can be shown expanded based on available space
172
- const MIN_EDITOR_WIDTH = 600; // Minimum width for ANY expanded editor
228
+ const MIN_EDITOR_WIDTH = 700; // Minimum width for ANY expanded editor
173
229
  const COLLAPSED_WIDTH = 60; // Width of collapsed panels
174
230
  const TYPES_EXPANDED = 350;
175
231
  const DOCS_EXPANDED = 350;
176
232
 
177
233
  let layoutConfig = $derived.by(() => {
178
234
  const start = performance.now();
179
- const totalEditors = (currentView === 'editor' ? 1 : 0) + editorStack.length + (showVersionPanel ? 1 : 0);
235
+ const totalEditors =
236
+ (currentView === 'editor' ? 1 : 0) + editorStack.length + (showVersionPanel ? 1 : 0);
180
237
 
181
238
  if (totalEditors === 0) {
182
239
  return {
@@ -431,10 +488,19 @@
431
488
  cmsLogger.debug('[URL Effect]', 'Branch: CREATE');
432
489
  currentView = 'editor';
433
490
  mobileView = 'editor';
434
- selectedDocumentType = docType;
435
491
  isCreatingDocument = true;
436
492
  editingDocumentId = null;
437
493
  editorStack = [];
494
+ if (selectedDocumentType !== docType) {
495
+ docCurrentPage = 1;
496
+ selectedDocumentType = docType;
497
+ fetchDocuments(docType);
498
+ }
499
+ // Note: no fallback refetch when docsList is empty — empty is a valid
500
+ // steady state (type has no records). fetchDocuments reassigns the
501
+ // list (new identity), which retriggers this effect; any "refetch if
502
+ // empty" guard loops forever. If you need a manual refresh, use a
503
+ // button, not an effect.
438
504
  } else if (docId) {
439
505
  cmsLogger.debug('[URL Effect]', 'Branch: EDIT (docId)');
440
506
  currentView = 'editor';
@@ -476,8 +542,8 @@
476
542
  }
477
543
 
478
544
  if (docType) {
479
- selectedDocumentType = docType;
480
- if (documentsList.length === 0 || selectedDocumentType !== docType) {
545
+ if (selectedDocumentType !== docType) {
546
+ selectedDocumentType = docType;
481
547
  fetchDocuments(docType);
482
548
  }
483
549
  } else {
@@ -521,6 +587,9 @@
521
587
  });
522
588
 
523
589
  async function navigateToDocumentType(docType: string) {
590
+ if (activeTab.value !== 'structure') {
591
+ handleTabChange('structure');
592
+ }
524
593
  const params = new SvelteURLSearchParams(page.url.searchParams);
525
594
  params.set('docType', docType);
526
595
  params.delete('docId');
@@ -625,7 +694,19 @@
625
694
  return;
626
695
  }
627
696
 
628
- // On desktop, add to editor stack
697
+ // On desktop, add to editor stack — unless the document is already open somewhere
698
+ if (editingDocumentId === documentId) {
699
+ // Already open as the primary editor — just focus it
700
+ activeEditorIndex = 0;
701
+ return;
702
+ }
703
+ const existingIndex = editorStack.findIndex((item) => item.documentId === documentId);
704
+ if (existingIndex !== -1) {
705
+ // Already open in the stack — focus that editor (stack index 0 = activeEditorIndex 1)
706
+ activeEditorIndex = existingIndex + 1;
707
+ return;
708
+ }
709
+
629
710
  const newStack = [...editorStack, { documentId, documentType, isCreating: false }];
630
711
 
631
712
  // Build stack param string: type1:id1,type2:id2,...
@@ -816,8 +897,10 @@
816
897
  </button>
817
898
  <span class="text-muted-foreground mx-2">/</span>
818
899
  <span class="text-sm font-medium">
819
- {pluralize(documentTypes.find((t) => t.name === selectedDocumentType)?.title ||
820
- selectedDocumentType)}
900
+ {pluralize(
901
+ documentTypes.find((t) => t.name === selectedDocumentType)?.title ||
902
+ selectedDocumentType
903
+ )}
821
904
  </span>
822
905
  {:else if mobileView === 'editor'}
823
906
  <Button
@@ -875,7 +958,7 @@
875
958
  {:else}
876
959
  <!-- Types Panel -->
877
960
  <div
878
- class="border-r transition-all duration-200 {windowWidth < 620
961
+ class="border-rule border-r transition-all duration-200 {windowWidth < 620
879
962
  ? typesPanel === 'hidden'
880
963
  ? 'hidden'
881
964
  : 'h-full w-screen'
@@ -886,12 +969,12 @@
886
969
  {#if typesPanel === 'w-[60px]'}
887
970
  <button
888
971
  onclick={() => setActiveEditor(-1)}
889
- class="hover:bg-muted/30 flex h-full w-full flex-col transition-colors"
972
+ class="hover:bg-muted/30 flex h-full w-full cursor-pointer flex-col transition-colors"
890
973
  title="Click to expand content types"
891
974
  >
892
975
  <div class="flex flex-1 items-start justify-center p-2 pt-8 text-left">
893
976
  <div
894
- class="text-foreground rotate-90 transform text-sm font-medium whitespace-nowrap"
977
+ class="text-foreground -mt-2 text-sm font-medium whitespace-nowrap [writing-mode:vertical-rl]"
895
978
  >
896
979
  Content
897
980
  </div>
@@ -901,46 +984,55 @@
901
984
  <div class="h-full overflow-y-auto p-3">
902
985
  {#if hasDocumentTypes}
903
986
  <h2
904
- class="text-muted-foreground mb-2 hidden px-2 text-sm font-medium sm:block"
987
+ class="text-muted-foreground border-rule mt-2 mb-3 hidden px-2 pb-3 text-sm font-medium sm:block sm:border-b"
905
988
  >
906
989
  Content
907
990
  </h2>
908
- {#each documentTypes as docType, index (index)}
909
- <button
910
- onclick={() => navigateToDocumentType(docType.name)}
911
- class="hover:bg-muted/50 group flex w-full cursor-pointer items-center justify-between rounded-md px-2 py-2.5 text-left transition-colors {selectedDocumentType ===
912
- docType.name
913
- ? 'bg-muted/50'
914
- : ''}"
915
- title={docType.description || ''}
916
- >
917
- <div class="flex items-center gap-2">
918
- <div
919
- class="text-muted-foreground flex h-5 w-5 items-center justify-center"
920
- >
921
- {#if docType.icon}
922
- {@const Icon = docType.icon}
923
- <Icon class="h-4 w-4" />
924
- {:else}
925
- <FileText class="h-4 w-4" />
926
- {/if}
927
- </div>
928
- <span class="text-sm">{pluralize(docType.title)}</span>
991
+ {#each groupedDocumentTypes as bucket (bucket.name ?? '__ungrouped__')}
992
+ {#if bucket.name}
993
+ <div
994
+ class="text-muted-foreground mt-3 mb-1 px-2 text-xs font-semibold tracking-wide uppercase first:mt-0"
995
+ >
996
+ {bucket.name}
929
997
  </div>
930
- <svg
931
- class="text-muted-foreground h-4 w-4 opacity-0 transition-opacity group-hover:opacity-100"
932
- fill="none"
933
- viewBox="0 0 24 24"
934
- stroke="currentColor"
998
+ {/if}
999
+ {#each bucket.items as docType (docType.name)}
1000
+ <button
1001
+ onclick={() => navigateToDocumentType(docType.name)}
1002
+ class="hover:bg-muted/50 group flex w-full cursor-pointer items-center justify-between rounded-md px-2 py-2.5 text-left transition-colors {selectedDocumentType ===
1003
+ docType.name
1004
+ ? 'bg-muted/50'
1005
+ : ''}"
1006
+ title={docType.description || ''}
935
1007
  >
936
- <path
937
- stroke-linecap="round"
938
- stroke-linejoin="round"
939
- stroke-width="2"
940
- d="M9 5l7 7-7 7"
941
- />
942
- </svg>
943
- </button>
1008
+ <div class="flex items-center gap-2">
1009
+ <div
1010
+ class="text-muted-foreground flex h-5 w-5 items-center justify-center"
1011
+ >
1012
+ {#if docType.icon}
1013
+ {@const Icon = docType.icon}
1014
+ <Icon class="h-4 w-4" />
1015
+ {:else}
1016
+ <FileText class="h-4 w-4" />
1017
+ {/if}
1018
+ </div>
1019
+ <span class="text-sm">{pluralize(docType.title)}</span>
1020
+ </div>
1021
+ <svg
1022
+ class="text-muted-foreground h-4 w-4 opacity-0 transition-opacity group-hover:opacity-100"
1023
+ fill="none"
1024
+ viewBox="0 0 24 24"
1025
+ stroke="currentColor"
1026
+ >
1027
+ <path
1028
+ stroke-linecap="round"
1029
+ stroke-linejoin="round"
1030
+ stroke-width="2"
1031
+ d="M9 5l7 7-7 7"
1032
+ />
1033
+ </svg>
1034
+ </button>
1035
+ {/each}
944
1036
  {/each}
945
1037
  {:else}
946
1038
  <div class="p-6 text-center">
@@ -967,7 +1059,7 @@
967
1059
  <!-- Documents Panel -->
968
1060
  {#if selectedDocumentType}
969
1061
  <div
970
- class="flex h-full flex-col overflow-hidden border-r transition-all duration-200
1062
+ class="border-rule flex h-full flex-col overflow-hidden border-r transition-all duration-200
971
1063
  {!documentsPanelState.visible ? 'hidden' : ''}
972
1064
  {windowWidth < 620 ? (documentsPanelState.visible ? 'w-screen' : 'hidden') : ''}
973
1065
  {windowWidth >= 620 && documentsPanelState.width === 'full' ? 'w-full' : ''}
@@ -979,13 +1071,17 @@
979
1071
  {#if documentsPanelState.width === 'compact'}
980
1072
  <button
981
1073
  onclick={() => setActiveEditor(-2)}
982
- class="hover:bg-muted/30 flex h-full w-full flex-col transition-colors"
1074
+ class="hover:bg-muted/30 flex h-full w-full cursor-pointer flex-col transition-colors"
983
1075
  title="Click to expand documents list"
984
1076
  >
985
1077
  <div class="flex flex-1 items-start justify-center p-2 pt-8 text-left">
986
- <div class="text-foreground rotate-90 transform text-sm font-medium">
987
- {pluralize(documentTypes.find((t) => t.name === selectedDocumentType)?.title ||
988
- selectedDocumentType)}
1078
+ <div
1079
+ class="text-foreground -mt-2 text-sm font-medium whitespace-nowrap [writing-mode:vertical-rl]"
1080
+ >
1081
+ {pluralize(
1082
+ documentTypes.find((t) => t.name === selectedDocumentType)?.title ||
1083
+ selectedDocumentType
1084
+ )}
989
1085
  </div>
990
1086
  </div>
991
1087
  </button>
@@ -1017,7 +1113,7 @@
1017
1113
  </div>
1018
1114
  </div>
1019
1115
  <div class="flex items-center gap-1">
1020
- {#if !isReadOnly}
1116
+ {#if perms.can('document.create')}
1021
1117
  <Button
1022
1118
  size="sm"
1023
1119
  variant="ghost"
@@ -1049,7 +1145,7 @@
1049
1145
  {...props}
1050
1146
  size="sm"
1051
1147
  variant="ghost"
1052
- class="h-8 w-8 p-0"
1148
+ class="h-8 w-8 cursor-pointer p-0"
1053
1149
  title="Sort documents"
1054
1150
  >
1055
1151
  <Ellipsis class="h-4 w-4" />
@@ -1162,7 +1258,7 @@
1162
1258
  {@const isActive = editingDocumentId === doc.id}
1163
1259
  <button
1164
1260
  onclick={() => navigateToEditDocument(doc.id, selectedDocumentType!)}
1165
- class="hover:bg-muted/50 border-border group flex w-full items-center justify-between border-b p-3 text-left transition-colors {isActive
1261
+ class="hover:bg-muted/50 border-border group flex w-full cursor-pointer items-center justify-between border-b p-3 text-left transition-colors {isActive
1166
1262
  ? 'bg-muted/50'
1167
1263
  : ''}"
1168
1264
  >
@@ -1188,13 +1284,37 @@
1188
1284
  </p>
1189
1285
  {:else if doc.slug}
1190
1286
  <p class="text-muted-foreground text-xs">/{doc.slug}</p>
1191
- {:else if doc.status}
1192
- <p class="text-muted-foreground text-xs">{doc.status}</p>
1193
1287
  {/if}
1194
1288
  </div>
1195
1289
  </div>
1196
- <div class="text-muted-foreground text-xs">
1197
- {doc.updatedAt?.toLocaleDateString() || ''}
1290
+ <div class="flex items-center gap-2">
1291
+ <span class="text-muted-foreground text-xs">
1292
+ {doc.updatedAt?.toLocaleDateString() || ''}
1293
+ </span>
1294
+ <div class="flex items-center gap-1">
1295
+ {#if doc.status === 'published'}
1296
+ {#if doc.hasChanges}
1297
+ <span
1298
+ class="h-1.5 w-1.5 shrink-0 rounded-full bg-amber-500"
1299
+ title="Unpublished changes"
1300
+ ></span>
1301
+ {/if}
1302
+ <span
1303
+ class="h-1.5 w-1.5 shrink-0 rounded-full bg-green-500"
1304
+ title="Published"
1305
+ ></span>
1306
+ {:else if doc.status === 'unpublished'}
1307
+ <span
1308
+ class="bg-muted-foreground/60 h-1.5 w-1.5 shrink-0 rounded-full"
1309
+ title="Unpublished"
1310
+ ></span>
1311
+ {:else}
1312
+ <span
1313
+ class="h-1.5 w-1.5 shrink-0 rounded-full bg-amber-500"
1314
+ title="Draft"
1315
+ ></span>
1316
+ {/if}
1317
+ </div>
1198
1318
  </div>
1199
1319
  </button>
1200
1320
  {/each}
@@ -1287,75 +1407,100 @@
1287
1407
 
1288
1408
  <!-- Primary Editor Panel -->
1289
1409
  {#if primaryEditorState.visible}
1290
- {#if primaryEditorState.expanded}
1291
- <div
1292
- class="transition-all duration-200 {windowWidth < 620
1293
- ? 'w-screen'
1294
- : 'flex-1'} h-full overflow-y-auto"
1295
- style={windowWidth >= 620 ? 'min-width: 0;' : ''}
1296
- >
1297
- <DocumentEditor
1298
- {schemas}
1299
- documentType={selectedDocumentType!}
1300
- documentId={editingDocumentId}
1301
- isCreating={isCreatingDocument}
1302
- onBack={navigateBack}
1303
- onOpenReference={handleOpenReference}
1304
- onOpenVersionHistory={handleOpenVersionHistory}
1305
- externalVersionPreview={versionPreviewData}
1306
- onSaved={async (docId) => {
1307
- if (selectedDocumentType) {
1308
- await fetchDocuments(selectedDocumentType);
1309
- }
1310
- // For first-time creation, just update URL without changing props
1311
- // This prevents DocumentEditor from reloading and keeps focus
1312
- if (isCreatingDocument) {
1313
- const params = new SvelteURLSearchParams(page.url.searchParams);
1314
- params.set('docId', docId);
1315
- if (selectedDocumentType) params.set('docType', selectedDocumentType);
1316
- params.delete('action');
1317
- replaceState(`/admin?${params.toString()}`, { ...page.state });
1318
-
1319
- // Update local state immediately to prevent creating duplicate documents
1320
- isCreatingDocument = false;
1321
- editingDocumentId = docId;
1322
- } else {
1323
- // For subsequent saves, use normal navigation
1324
- navigateToEditDocument(docId, selectedDocumentType!);
1325
- }
1326
- }}
1327
- onAutoSaved={handleAutoSave}
1328
- onPublished={async (_) => {
1329
- if (selectedDocumentType) {
1330
- await fetchDocuments(selectedDocumentType);
1331
- }
1332
- }}
1333
- onDeleted={async () => {
1334
- if (selectedDocumentType) {
1335
- await fetchDocuments(selectedDocumentType);
1336
- const params = new SvelteURLSearchParams(page.url.searchParams);
1337
- params.set('docType', selectedDocumentType);
1338
- params.delete('docId');
1339
- params.delete('action');
1340
- await goto(`/admin?${params.toString()}`, { replaceState: false });
1341
- } else {
1342
- const orgId = page.url.searchParams.get('orgId');
1343
- const url = orgId ? `/admin?orgId=${orgId}` : '/admin';
1344
- await goto(url, { replaceState: false });
1345
- }
1346
- }}
1347
- {isReadOnly}
1348
- />
1349
- </div>
1350
- {:else}
1410
+ <div
1411
+ class="transition-all duration-200 {windowWidth < 620
1412
+ ? 'w-screen'
1413
+ : 'flex-1'} h-full overflow-x-hidden overflow-y-auto {primaryEditorState.expanded
1414
+ ? ''
1415
+ : 'hidden'}"
1416
+ style={windowWidth >= 620 ? 'min-width: 0;' : ''}
1417
+ >
1418
+ <DocumentEditor
1419
+ {schemas}
1420
+ documentType={selectedDocumentType!}
1421
+ documentId={editingDocumentId}
1422
+ isCreating={isCreatingDocument}
1423
+ onBack={navigateBack}
1424
+ onOpenReference={handleOpenReference}
1425
+ onOpenVersionHistory={handleOpenVersionHistory}
1426
+ externalVersionPreview={versionPanelDocId === editingDocumentId
1427
+ ? versionPreviewData
1428
+ : null}
1429
+ onSaved={async (docId) => {
1430
+ if (selectedDocumentType) {
1431
+ await fetchDocuments(selectedDocumentType);
1432
+ }
1433
+ // For first-time creation, update URL and local state.
1434
+ // Use goto with replaceState:true so page.url stays in sync —
1435
+ // raw replaceState() from $app/navigation updates the URL bar
1436
+ // but leaves page.url.searchParams stale, which breaks any
1437
+ // subsequent navigation that reads from it (e.g. opening a
1438
+ // stacked reference editor) because the old ?action=create
1439
+ // gets carried forward.
1440
+ if (isCreatingDocument) {
1441
+ // Update local state FIRST so the URL Effect's EDIT branch
1442
+ // sees consistent values when goto fires it.
1443
+ isCreatingDocument = false;
1444
+ editingDocumentId = docId;
1445
+
1446
+ const params = new SvelteURLSearchParams(page.url.searchParams);
1447
+ params.set('docId', docId);
1448
+ if (selectedDocumentType) params.set('docType', selectedDocumentType);
1449
+ params.delete('action');
1450
+ await goto(`/admin?${params.toString()}`, {
1451
+ replaceState: true,
1452
+ keepFocus: true,
1453
+ noScroll: true
1454
+ });
1455
+ } else {
1456
+ // For subsequent saves, use normal navigation
1457
+ navigateToEditDocument(docId, selectedDocumentType!);
1458
+ }
1459
+ }}
1460
+ onAutoSaved={handleAutoSave}
1461
+ onPublished={async (_) => {
1462
+ if (selectedDocumentType) {
1463
+ await fetchDocuments(selectedDocumentType);
1464
+ }
1465
+ }}
1466
+ onUnpublished={async (_) => {
1467
+ if (selectedDocumentType) {
1468
+ await fetchDocuments(selectedDocumentType);
1469
+ }
1470
+ }}
1471
+ onRestored={async (_) => {
1472
+ if (selectedDocumentType) {
1473
+ await fetchDocuments(selectedDocumentType);
1474
+ }
1475
+ }}
1476
+ onDeleted={async () => {
1477
+ if (selectedDocumentType) {
1478
+ await fetchDocuments(selectedDocumentType);
1479
+ const params = new SvelteURLSearchParams(page.url.searchParams);
1480
+ params.set('docType', selectedDocumentType);
1481
+ params.delete('docId');
1482
+ params.delete('action');
1483
+ await goto(`/admin?${params.toString()}`, { replaceState: false });
1484
+ } else {
1485
+ const orgId = page.url.searchParams.get('orgId');
1486
+ const url = orgId ? `/admin?orgId=${orgId}` : '/admin';
1487
+ await goto(url, { replaceState: false });
1488
+ }
1489
+ }}
1490
+ {isReadOnly}
1491
+ />
1492
+ </div>
1493
+ {#if !primaryEditorState.expanded}
1351
1494
  <!-- Collapsed Primary Editor Strip -->
1352
1495
  <button
1353
1496
  onclick={() => setActiveEditor(0)}
1354
- class="hover:bg-muted/50 flex h-full w-[60px] flex-col border-l transition-colors"
1497
+ class="border-rule hover:bg-muted/50 flex h-full w-[60px] cursor-pointer flex-col border-l transition-colors"
1355
1498
  title="Click to expand {selectedDocumentType}"
1356
1499
  >
1357
- <div class="mt-7 flex flex-1 items-start justify-center p-2 pt-8 text-left">
1358
- <div class="text-foreground rotate-90 transform text-sm font-medium">
1500
+ <div class="flex flex-1 items-start justify-center p-2 pt-8 text-left">
1501
+ <div
1502
+ class="text-foreground -mt-2 text-sm font-medium whitespace-nowrap [writing-mode:vertical-rl]"
1503
+ >
1359
1504
  {selectedDocumentType
1360
1505
  ? selectedDocumentType.charAt(0).toUpperCase() +
1361
1506
  selectedDocumentType.slice(1)
@@ -1373,7 +1518,7 @@
1373
1518
 
1374
1519
  {#if isExpanded}
1375
1520
  <div
1376
- class="h-full flex-1 overflow-y-auto border-l transition-all duration-200"
1521
+ class="border-rule h-full flex-1 overflow-x-hidden overflow-y-auto border-l transition-all duration-200"
1377
1522
  style="min-width: 0;"
1378
1523
  >
1379
1524
  <DocumentEditor
@@ -1384,9 +1529,26 @@
1384
1529
  onBack={() => handleCloseStackedEditor(index)}
1385
1530
  onOpenReference={handleOpenReference}
1386
1531
  onOpenVersionHistory={handleOpenVersionHistory}
1387
- onSaved={async (_) => {}}
1532
+ externalVersionPreview={versionPanelDocId === stackedEditor.documentId
1533
+ ? versionPreviewData
1534
+ : null}
1535
+ onSaved={async () => {}}
1388
1536
  onAutoSaved={() => {}}
1389
- onPublished={async (_) => {}}
1537
+ onPublished={async () => {
1538
+ if (selectedDocumentType) {
1539
+ await fetchDocuments(selectedDocumentType);
1540
+ }
1541
+ }}
1542
+ onUnpublished={async () => {
1543
+ if (selectedDocumentType) {
1544
+ await fetchDocuments(selectedDocumentType);
1545
+ }
1546
+ }}
1547
+ onRestored={async () => {
1548
+ if (selectedDocumentType) {
1549
+ await fetchDocuments(selectedDocumentType);
1550
+ }
1551
+ }}
1390
1552
  onDeleted={async () => {
1391
1553
  handleCloseStackedEditor(index);
1392
1554
  }}
@@ -1397,14 +1559,12 @@
1397
1559
  <!-- Collapsed Stacked Editor Strip -->
1398
1560
  <button
1399
1561
  onclick={() => setActiveEditor(editorIndex)}
1400
- class="hover:bg-muted/50 flex h-full w-[60px] flex-col border-l transition-colors"
1562
+ class="border-rule hover:bg-muted/50 flex h-full w-[60px] cursor-pointer flex-col border-l transition-colors"
1401
1563
  title="Click to expand {stackedEditor.documentType}"
1402
1564
  >
1403
- <div
1404
- class="-mt-2 flex h-full flex-1 items-start justify-center p-2 pt-8 text-left"
1405
- >
1565
+ <div class="flex h-full flex-1 items-start justify-center p-2 pt-8 text-left">
1406
1566
  <div
1407
- class="text-foreground rotate-90 transform text-sm font-medium whitespace-nowrap"
1567
+ class="text-foreground text-sm font-medium whitespace-nowrap [writing-mode:vertical-rl]"
1408
1568
  >
1409
1569
  {stackedEditor.documentType.charAt(0).toUpperCase() +
1410
1570
  stackedEditor.documentType.slice(1)}
@@ -1418,12 +1578,14 @@
1418
1578
  <!-- Version History Panel -->
1419
1579
  {#if showVersionPanel && versionPanelDocId}
1420
1580
  <div
1421
- class="h-full w-[280px] min-w-[250px] overflow-y-auto border-l transition-all duration-200"
1581
+ class="border-rule h-full w-[280px] min-w-[250px] overflow-y-auto border-l transition-all duration-200"
1422
1582
  >
1423
1583
  <DocumentVersionPanel
1424
1584
  documentId={versionPanelDocId}
1425
1585
  onClose={handleCloseVersionPanel}
1426
- onPreviewVersion={(v) => { versionPreviewData = v; }}
1586
+ onPreviewVersion={(v) => {
1587
+ versionPreviewData = v;
1588
+ }}
1427
1589
  onRestored={async () => {
1428
1590
  versionPreviewData = null;
1429
1591
  if (selectedDocumentType) {
@@ -1465,7 +1627,7 @@
1465
1627
  <p class="text-muted-foreground mb-4">Query your CMS data with the GraphQL API</p>
1466
1628
 
1467
1629
  <a
1468
- href={graphqlSettings.endpoint}
1630
+ href={resolve(graphqlSettings.endpoint, {})}
1469
1631
  target="_blank"
1470
1632
  class="bg-primary text-primary-foreground hover:bg-primary/90 inline-flex items-center gap-2 rounded-md px-4 py-2 transition-colors"
1471
1633
  >
@@ -1492,3 +1654,5 @@
1492
1654
  </Tabs.Root>
1493
1655
  </div>
1494
1656
  </div>
1657
+
1658
+ <ConfirmDialogHost />