kempo 4.2.16 → 4.2.18

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 (274) hide show
  1. package/bin/cli.js +21 -4
  2. package/dist/admin/components/AddGroupControl.js +2 -2
  3. package/dist/admin/components/AddGroupControl.js.map +1 -1
  4. package/dist/admin/components/ClearExpiredSessionsControl.js +2 -2
  5. package/dist/admin/components/ClearExpiredSessionsControl.js.map +1 -1
  6. package/dist/admin/components/FragmentEditor.js +15 -15
  7. package/dist/admin/components/FragmentEditor.js.map +1 -1
  8. package/dist/admin/components/GlobalContentEditor.js +12 -12
  9. package/dist/admin/components/GlobalContentEditor.js.map +1 -1
  10. package/dist/admin/components/GroupDeleteSelected.js +2 -2
  11. package/dist/admin/components/GroupDeleteSelected.js.map +1 -1
  12. package/dist/admin/components/GroupRemoveRecord.js +2 -2
  13. package/dist/admin/components/GroupRemoveRecord.js.map +1 -1
  14. package/dist/admin/components/Monaco.js +1 -1
  15. package/dist/admin/components/Monaco.js.map +1 -1
  16. package/dist/admin/components/PageEditor.js +42 -28
  17. package/dist/admin/components/PageEditor.js.map +1 -1
  18. package/dist/admin/components/TableRowDelete.js +2 -2
  19. package/dist/admin/components/TableRowDelete.js.map +1 -1
  20. package/dist/admin/components/TableRowLink.js +2 -2
  21. package/dist/admin/components/TableRowLink.js.map +1 -1
  22. package/dist/admin/components/TemplateEditor.js +18 -18
  23. package/dist/admin/components/TemplateEditor.js.map +1 -1
  24. package/dist/admin/components/ValueEditor.js +17 -17
  25. package/dist/admin/components/ValueEditor.js.map +1 -1
  26. package/dist/admin/components/tableControls/AddMember.js +2 -2
  27. package/dist/admin/components/tableControls/AddMember.js.map +1 -1
  28. package/dist/admin/components/tableControls/AddPermission.js +2 -2
  29. package/dist/admin/components/tableControls/AddPermission.js.map +1 -1
  30. package/dist/admin/components/tableControls/InstallExtension.js +2 -2
  31. package/dist/admin/components/tableControls/InstallExtension.js.map +1 -1
  32. package/dist/admin/components/tableControls/UninstallExtension.js +2 -2
  33. package/dist/admin/components/tableControls/UninstallExtension.js.map +1 -1
  34. package/dist/admin/extensions/index.page.html +49 -15
  35. package/dist/admin/icons/open_in_new.svg +1 -0
  36. package/dist/admin/nav.fragment.html +1 -1
  37. package/dist/kempo/api/admin-globals/DELETE.js +1 -1
  38. package/dist/kempo/api/admin-globals/DELETE.js.map +1 -1
  39. package/dist/kempo/api/admin-globals/GET.js +1 -1
  40. package/dist/kempo/api/admin-globals/GET.js.map +1 -1
  41. package/dist/kempo/api/admin-globals/POST.js +1 -1
  42. package/dist/kempo/api/admin-globals/POST.js.map +1 -1
  43. package/dist/kempo/api/admin-globals/[id]/GET.js +1 -1
  44. package/dist/kempo/api/admin-globals/[id]/GET.js.map +1 -1
  45. package/dist/kempo/api/admin-globals/[id]/PUT.js +1 -1
  46. package/dist/kempo/api/admin-globals/[id]/PUT.js.map +1 -1
  47. package/dist/kempo/api/admin-globals/[id]/disable/PUT.js +1 -1
  48. package/dist/kempo/api/admin-globals/[id]/disable/PUT.js.map +1 -1
  49. package/dist/kempo/api/admin-globals/[id]/enable/PUT.js +1 -1
  50. package/dist/kempo/api/admin-globals/[id]/enable/PUT.js.map +1 -1
  51. package/dist/kempo/api/auth/change-password/POST.js +1 -1
  52. package/dist/kempo/api/auth/change-password/POST.js.map +1 -1
  53. package/dist/kempo/api/auth/login/email/POST.js +1 -1
  54. package/dist/kempo/api/auth/login/email/POST.js.map +1 -1
  55. package/dist/kempo/api/auth/logout/POST.js +1 -1
  56. package/dist/kempo/api/auth/logout/POST.js.map +1 -1
  57. package/dist/kempo/api/auth/register/email/POST.js +1 -1
  58. package/dist/kempo/api/auth/register/email/POST.js.map +1 -1
  59. package/dist/kempo/api/auth/reset-password/POST.js +1 -1
  60. package/dist/kempo/api/auth/reset-password/POST.js.map +1 -1
  61. package/dist/kempo/api/auth/session/GET.js +1 -1
  62. package/dist/kempo/api/auth/session/GET.js.map +1 -1
  63. package/dist/kempo/api/auth/verify-email/POST.js +1 -1
  64. package/dist/kempo/api/auth/verify-email/POST.js.map +1 -1
  65. package/dist/kempo/api/extensions/DELETE.js +1 -1
  66. package/dist/kempo/api/extensions/DELETE.js.map +1 -1
  67. package/dist/kempo/api/extensions/GET.js +1 -1
  68. package/dist/kempo/api/extensions/GET.js.map +1 -1
  69. package/dist/kempo/api/extensions/POST.js +1 -1
  70. package/dist/kempo/api/extensions/POST.js.map +1 -1
  71. package/dist/kempo/api/extensions/[name]/disable/POST.js +1 -1
  72. package/dist/kempo/api/extensions/[name]/disable/POST.js.map +1 -1
  73. package/dist/kempo/api/extensions/[name]/enable/POST.js +1 -1
  74. package/dist/kempo/api/extensions/[name]/enable/POST.js.map +1 -1
  75. package/dist/kempo/api/extensions/[name]/update/POST.js +1 -1
  76. package/dist/kempo/api/extensions/[name]/update/POST.js.map +1 -1
  77. package/dist/kempo/api/extensions/[name]/update-check/GET.js +1 -1
  78. package/dist/kempo/api/extensions/[name]/update-check/GET.js.map +1 -1
  79. package/dist/kempo/api/extensions/available/GET.js +1 -1
  80. package/dist/kempo/api/extensions/available/GET.js.map +1 -1
  81. package/dist/kempo/api/extensions/known/GET.js +1 -1
  82. package/dist/kempo/api/extensions/known/GET.js.map +1 -1
  83. package/dist/kempo/api/forgot-password/POST.js +1 -1
  84. package/dist/kempo/api/forgot-password/POST.js.map +1 -1
  85. package/dist/kempo/api/fragments/DELETE.js +1 -1
  86. package/dist/kempo/api/fragments/DELETE.js.map +1 -1
  87. package/dist/kempo/api/fragments/GET.js +1 -1
  88. package/dist/kempo/api/fragments/GET.js.map +1 -1
  89. package/dist/kempo/api/fragments/POST.js +1 -1
  90. package/dist/kempo/api/fragments/POST.js.map +1 -1
  91. package/dist/kempo/api/fragments/disable/PUT.js +1 -1
  92. package/dist/kempo/api/fragments/disable/PUT.js.map +1 -1
  93. package/dist/kempo/api/fragments/enable/PUT.js +1 -1
  94. package/dist/kempo/api/fragments/enable/PUT.js.map +1 -1
  95. package/dist/kempo/api/fragments/file/GET.js +1 -1
  96. package/dist/kempo/api/fragments/file/GET.js.map +1 -1
  97. package/dist/kempo/api/fragments/file/PATCH.js +1 -1
  98. package/dist/kempo/api/fragments/file/PATCH.js.map +1 -1
  99. package/dist/kempo/api/fragments/file/PUT.js +1 -1
  100. package/dist/kempo/api/fragments/file/PUT.js.map +1 -1
  101. package/dist/kempo/api/fragments/lock/PUT.js +2 -2
  102. package/dist/kempo/api/fragments/lock/PUT.js.map +1 -1
  103. package/dist/kempo/api/globals/DELETE.js +1 -1
  104. package/dist/kempo/api/globals/DELETE.js.map +1 -1
  105. package/dist/kempo/api/globals/GET.js +1 -1
  106. package/dist/kempo/api/globals/GET.js.map +1 -1
  107. package/dist/kempo/api/globals/POST.js +1 -1
  108. package/dist/kempo/api/globals/POST.js.map +1 -1
  109. package/dist/kempo/api/globals/disable/PUT.js +1 -1
  110. package/dist/kempo/api/globals/disable/PUT.js.map +1 -1
  111. package/dist/kempo/api/globals/enable/PUT.js +1 -1
  112. package/dist/kempo/api/globals/enable/PUT.js.map +1 -1
  113. package/dist/kempo/api/globals/entry/GET.js +1 -1
  114. package/dist/kempo/api/globals/entry/GET.js.map +1 -1
  115. package/dist/kempo/api/globals/entry/PUT.js +1 -1
  116. package/dist/kempo/api/globals/entry/PUT.js.map +1 -1
  117. package/dist/kempo/api/globals/lock/PUT.js +2 -2
  118. package/dist/kempo/api/globals/lock/PUT.js.map +1 -1
  119. package/dist/kempo/api/groups/DELETE.js +1 -1
  120. package/dist/kempo/api/groups/DELETE.js.map +1 -1
  121. package/dist/kempo/api/groups/GET.js +1 -1
  122. package/dist/kempo/api/groups/GET.js.map +1 -1
  123. package/dist/kempo/api/groups/PATCH.js +1 -1
  124. package/dist/kempo/api/groups/PATCH.js.map +1 -1
  125. package/dist/kempo/api/groups/POST.js +1 -1
  126. package/dist/kempo/api/groups/POST.js.map +1 -1
  127. package/dist/kempo/api/groups/[name]/GET.js +1 -1
  128. package/dist/kempo/api/groups/[name]/GET.js.map +1 -1
  129. package/dist/kempo/api/groups/[name]/members/DELETE.js +1 -1
  130. package/dist/kempo/api/groups/[name]/members/DELETE.js.map +1 -1
  131. package/dist/kempo/api/groups/[name]/members/GET.js +1 -1
  132. package/dist/kempo/api/groups/[name]/members/GET.js.map +1 -1
  133. package/dist/kempo/api/groups/[name]/members/POST.js +1 -1
  134. package/dist/kempo/api/groups/[name]/members/POST.js.map +1 -1
  135. package/dist/kempo/api/groups/[name]/permissions/DELETE.js +1 -1
  136. package/dist/kempo/api/groups/[name]/permissions/DELETE.js.map +1 -1
  137. package/dist/kempo/api/groups/[name]/permissions/GET.js +1 -1
  138. package/dist/kempo/api/groups/[name]/permissions/GET.js.map +1 -1
  139. package/dist/kempo/api/groups/[name]/permissions/POST.js +1 -1
  140. package/dist/kempo/api/groups/[name]/permissions/POST.js.map +1 -1
  141. package/dist/kempo/api/pages/DELETE.js +1 -1
  142. package/dist/kempo/api/pages/DELETE.js.map +1 -1
  143. package/dist/kempo/api/pages/GET.js +1 -1
  144. package/dist/kempo/api/pages/GET.js.map +1 -1
  145. package/dist/kempo/api/pages/POST.js +1 -1
  146. package/dist/kempo/api/pages/POST.js.map +1 -1
  147. package/dist/kempo/api/pages/directories/GET.js +1 -1
  148. package/dist/kempo/api/pages/directories/GET.js.map +1 -1
  149. package/dist/kempo/api/pages/disable/PUT.js +1 -1
  150. package/dist/kempo/api/pages/disable/PUT.js.map +1 -1
  151. package/dist/kempo/api/pages/enable/PUT.js +1 -1
  152. package/dist/kempo/api/pages/enable/PUT.js.map +1 -1
  153. package/dist/kempo/api/pages/file/GET.js +1 -1
  154. package/dist/kempo/api/pages/file/GET.js.map +1 -1
  155. package/dist/kempo/api/pages/file/PATCH.js +1 -1
  156. package/dist/kempo/api/pages/file/PATCH.js.map +1 -1
  157. package/dist/kempo/api/pages/file/PUT.js +1 -1
  158. package/dist/kempo/api/pages/file/PUT.js.map +1 -1
  159. package/dist/kempo/api/pages/lock/PUT.js +2 -2
  160. package/dist/kempo/api/pages/lock/PUT.js.map +1 -1
  161. package/dist/kempo/api/pages/search/GET.js +2 -2
  162. package/dist/kempo/api/pages/search/GET.js.map +1 -1
  163. package/dist/kempo/api/pages/templates/GET.js +1 -1
  164. package/dist/kempo/api/pages/templates/GET.js.map +1 -1
  165. package/dist/kempo/api/permissions/DELETE.js +1 -1
  166. package/dist/kempo/api/permissions/DELETE.js.map +1 -1
  167. package/dist/kempo/api/permissions/GET.js +1 -1
  168. package/dist/kempo/api/permissions/GET.js.map +1 -1
  169. package/dist/kempo/api/permissions/PATCH.js +1 -1
  170. package/dist/kempo/api/permissions/PATCH.js.map +1 -1
  171. package/dist/kempo/api/permissions/POST.js +1 -1
  172. package/dist/kempo/api/permissions/POST.js.map +1 -1
  173. package/dist/kempo/api/settings/[owner]/GET.js +1 -1
  174. package/dist/kempo/api/settings/[owner]/GET.js.map +1 -1
  175. package/dist/kempo/api/settings/[owner]/[name]/DELETE.js +1 -1
  176. package/dist/kempo/api/settings/[owner]/[name]/DELETE.js.map +1 -1
  177. package/dist/kempo/api/settings/[owner]/[name]/GET.js +1 -1
  178. package/dist/kempo/api/settings/[owner]/[name]/GET.js.map +1 -1
  179. package/dist/kempo/api/settings/[owner]/[name]/POST.js +1 -1
  180. package/dist/kempo/api/settings/[owner]/[name]/POST.js.map +1 -1
  181. package/dist/kempo/api/settings/public/GET.js +1 -1
  182. package/dist/kempo/api/settings/public/GET.js.map +1 -1
  183. package/dist/kempo/api/templates/DELETE.js +1 -1
  184. package/dist/kempo/api/templates/DELETE.js.map +1 -1
  185. package/dist/kempo/api/templates/GET.js +1 -1
  186. package/dist/kempo/api/templates/GET.js.map +1 -1
  187. package/dist/kempo/api/templates/POST.js +1 -1
  188. package/dist/kempo/api/templates/POST.js.map +1 -1
  189. package/dist/kempo/api/templates/disable/PUT.js +1 -1
  190. package/dist/kempo/api/templates/disable/PUT.js.map +1 -1
  191. package/dist/kempo/api/templates/enable/PUT.js +1 -1
  192. package/dist/kempo/api/templates/enable/PUT.js.map +1 -1
  193. package/dist/kempo/api/templates/file/GET.js +1 -1
  194. package/dist/kempo/api/templates/file/GET.js.map +1 -1
  195. package/dist/kempo/api/templates/file/PATCH.js +1 -1
  196. package/dist/kempo/api/templates/file/PATCH.js.map +1 -1
  197. package/dist/kempo/api/templates/file/PUT.js +1 -1
  198. package/dist/kempo/api/templates/file/PUT.js.map +1 -1
  199. package/dist/kempo/api/templates/lock/PUT.js +2 -2
  200. package/dist/kempo/api/templates/lock/PUT.js.map +1 -1
  201. package/dist/kempo/api/user/DELETE.js +1 -1
  202. package/dist/kempo/api/user/DELETE.js.map +1 -1
  203. package/dist/kempo/api/user/GET.js +1 -1
  204. package/dist/kempo/api/user/GET.js.map +1 -1
  205. package/dist/kempo/api/user/PATCH.js +1 -1
  206. package/dist/kempo/api/user/PATCH.js.map +1 -1
  207. package/dist/kempo/api/user/[userid]/GET.js +1 -1
  208. package/dist/kempo/api/user/[userid]/GET.js.map +1 -1
  209. package/dist/kempo/api/user/[userid]/groups/DELETE.js +1 -1
  210. package/dist/kempo/api/user/[userid]/groups/DELETE.js.map +1 -1
  211. package/dist/kempo/api/user/[userid]/groups/GET.js +1 -1
  212. package/dist/kempo/api/user/[userid]/groups/GET.js.map +1 -1
  213. package/dist/kempo/api/user/[userid]/groups/POST.js +1 -1
  214. package/dist/kempo/api/user/[userid]/groups/POST.js.map +1 -1
  215. package/dist/kempo/api/user/[userid]/permissions/GET.js +1 -1
  216. package/dist/kempo/api/user/[userid]/permissions/GET.js.map +1 -1
  217. package/dist/kempo/api/user/[userid]/permissions/all/GET.js +1 -1
  218. package/dist/kempo/api/user/[userid]/permissions/all/GET.js.map +1 -1
  219. package/dist/kempo/api/user/[userid]/permissions/list/GET.js +1 -1
  220. package/dist/kempo/api/user/[userid]/permissions/list/GET.js.map +1 -1
  221. package/dist/kempo/api/user/[userid]/permissions/some/GET.js +1 -1
  222. package/dist/kempo/api/user/[userid]/permissions/some/GET.js.map +1 -1
  223. package/dist/kempo/api/user/[userid]/sessions/DELETE.js +1 -1
  224. package/dist/kempo/api/user/[userid]/sessions/DELETE.js.map +1 -1
  225. package/dist/kempo/api/user/[userid]/sessions/GET.js +1 -1
  226. package/dist/kempo/api/user/[userid]/sessions/GET.js.map +1 -1
  227. package/dist/kempo/api/user/[userid]/sessions/expired/DELETE.js +1 -1
  228. package/dist/kempo/api/user/[userid]/sessions/expired/DELETE.js.map +1 -1
  229. package/dist/kempo/api/user/create/POST.js +1 -1
  230. package/dist/kempo/api/user/create/POST.js.map +1 -1
  231. package/dist/kempo/api/user/search/GET.js +1 -1
  232. package/dist/kempo/api/user/search/GET.js.map +1 -1
  233. package/dist/kempo/components/LogoutBtn.js +1 -1
  234. package/dist/kempo/components/LogoutBtn.js.map +1 -1
  235. package/dist/kempo/components/Menu.js +9 -9
  236. package/dist/kempo/components/Menu.js.map +1 -1
  237. package/dist/kempo/components/Permission.js +1 -1
  238. package/dist/kempo/components/Permission.js.map +1 -1
  239. package/dist/kempo/components/Role.js +1 -1
  240. package/dist/kempo/components/Role.js.map +1 -1
  241. package/dist/kempo/components/UserCreatedAt.js +1 -1
  242. package/dist/kempo/components/UserCreatedAt.js.map +1 -1
  243. package/dist/kempo/components/UserEmail.js +1 -1
  244. package/dist/kempo/components/UserEmail.js.map +1 -1
  245. package/dist/kempo/components/UserEmailVerified.js +1 -1
  246. package/dist/kempo/components/UserEmailVerified.js.map +1 -1
  247. package/dist/kempo/components/UserName.js +1 -1
  248. package/dist/kempo/components/UserName.js.map +1 -1
  249. package/dist/kempo/fetch.js +1 -1
  250. package/dist/kempo/fetch.js.map +1 -1
  251. package/dist/kempo/sdk.js +1 -1
  252. package/dist/kempo/sdk.js.map +1 -1
  253. package/middleware/kempo.js +36 -6
  254. package/package.json +2 -2
  255. package/server/utils/extensions/installExtension.js +19 -13
  256. package/server/utils/extensions/uninstallExtension.js +6 -10
  257. package/server/utils/pages/deletePage.js +2 -10
  258. package/dist/admin/accounts/groups/[name]/index.html +0 -518
  259. package/dist/admin/accounts/groups/index.html +0 -378
  260. package/dist/admin/accounts/permissions/index.html +0 -397
  261. package/dist/admin/accounts/users/[id]/index.html +0 -541
  262. package/dist/admin/accounts/users/index.html +0 -396
  263. package/dist/admin/content/fragments/edit/index.html +0 -132
  264. package/dist/admin/content/fragments/index.html +0 -375
  265. package/dist/admin/content/globals/edit/index.html +0 -132
  266. package/dist/admin/content/globals/index.html +0 -358
  267. package/dist/admin/content/pages/edit/index.html +0 -132
  268. package/dist/admin/content/pages/index.html +0 -509
  269. package/dist/admin/content/templates/edit/index.html +0 -132
  270. package/dist/admin/content/templates/index.html +0 -429
  271. package/dist/admin/extensions/index.html +0 -222
  272. package/dist/admin/index.html +0 -130
  273. package/dist/admin/settings/[owner]/[name]/index.html +0 -449
  274. package/dist/admin/settings/index.html +0 -410
@@ -1,541 +0,0 @@
1
- <!--
2
- owner: system
3
- locked: true
4
- name:
5
- author:
6
- created:
7
- updated:
8
- -->
9
- <!DOCTYPE html>
10
- <html lang="en">
11
- <head>
12
- <meta charset="UTF-8">
13
- <meta name="viewport" content="width=device-width, initial-scale=1.0">
14
- <link rel="icon" type="image/png" sizes="48x48" href="/media/icon48.png">
15
- <link rel="manifest" href="/manifest.json">
16
- <title>User - Admin</title>
17
- <link rel="stylesheet" href="/kempo-css/kempo.min.css">
18
- <script src="/admin/init.js"></script>
19
-
20
- </head>
21
- <body>
22
- <!--
23
- locked: true
24
- -->
25
-
26
- <k-aside
27
- main="push"
28
- state="expanded"
29
- style="--aside_padding: 0;"
30
- persistent-id="admin-nav"
31
- >
32
- <k-aside-toggle>
33
- <h3 class="m0">Kempo Admin</h3>
34
- </k-aside-toggle>
35
- <k-aside-item
36
- icon="preview"
37
- href="/"
38
- no-expand
39
- >Site</k-aside-item>
40
- <k-aside-item
41
- icon="cards"
42
- href="/admin"
43
- no-expand
44
- >Dashboard</k-aside-item>
45
- <k-aside-menu
46
- icon="manage-accounts"
47
- label="Accounts"
48
- >
49
- <k-aside-item
50
- icon="person"
51
- href="/admin/accounts/users"
52
- no-expand
53
- >Users</k-aside-item>
54
- <k-aside-item
55
- icon="group"
56
- href="/admin/accounts/groups"
57
- no-expand
58
- >Groups</k-aside-item>
59
- <k-aside-item
60
- icon="lock"
61
- href="/admin/accounts/permissions"
62
- no-expand
63
- >Permissions</k-aside-item>
64
- </k-aside-menu>
65
- <k-aside-menu
66
- icon="cards_stack"
67
- label="Content"
68
- >
69
- <k-aside-item
70
- icon="browse"
71
- href="/admin/content/templates"
72
- >Templates</k-aside-item>
73
- <k-aside-item
74
- icon="docs"
75
- href="/admin/content/pages"
76
- >Pages</k-aside-item>
77
- <k-aside-item
78
- icon="content"
79
- href="/admin/content/fragments"
80
- >Fragments</k-aside-item>
81
- <k-aside-item
82
- icon="globe"
83
- href="/admin/content/globals"
84
- >Global Content</k-aside-item>
85
- </k-aside-menu>
86
- <k-aside-item
87
- icon="settings"
88
- href="/admin/settings"
89
- no-expand
90
- >Settings</k-aside-item>
91
- <k-aside-item
92
- icon="extension"
93
- href="/admin/extensions"
94
- no-expand
95
- >Extensions</k-aside-item>
96
- <hr>
97
- <k-aside-spacer></k-aside-spacer>
98
- <k-theme-switcher
99
- labels
100
- style="--padding:var(--spacer_h);margin:var(--spacer_h) auto"
101
- ></k-theme-switcher>
102
- </k-aside>
103
- <script type="module">
104
- import '/kempo-ui/components/ThemeSwitcher.js';
105
- const items = document.querySelectorAll('k-aside-item');
106
- const currentPath = window.location.pathname;
107
-
108
- items.forEach(item => {
109
- const href = item.getAttribute('href');
110
- if (!href) return;
111
- const isExact = href === '/admin' || href === '/';
112
- const match = isExact
113
- ? (currentPath === href || currentPath === href + '/')
114
- : (currentPath === href || currentPath.startsWith(href + '/'));
115
- if (match) {
116
- item.setAttribute('active', '');
117
- const menu = item.closest('k-aside-menu');
118
- if (menu) menu.setAttribute('open', '');
119
- }
120
- });
121
- </script>
122
-
123
- <k-main>
124
-
125
- <script type="module" src="/kempo-ui/components/Toggle.js"></script>
126
- <script type="module" src="/kempo-ui/components/Icon.js"></script>
127
- <script type="module" src="/kempo-ui/components/Table.js"></script>
128
- <script type="module" src="/kempo-ui/components/tableControls/FirstPage.js"></script>
129
- <script type="module" src="/kempo-ui/components/tableControls/PrevPage.js"></script>
130
- <script type="module" src="/kempo-ui/components/tableControls/NextPage.js"></script>
131
- <script type="module" src="/kempo-ui/components/tableControls/LastPage.js"></script>
132
- <script type="module" src="/kempo-ui/components/tableControls/PageSelect.js"></script>
133
- <script type="module" src="/kempo-ui/components/tableControls/PageSize.js"></script>
134
- <script type="module" src="/kempo-ui/components/tableControls/DeleteRecord.js"></script>
135
- <script type="module" src="/kempo-ui/components/tableControls/DeleteSelected.js"></script>
136
- <script type="module" src="/admin/components/GroupDeleteSelected.js"></script>
137
- <script type="module" src="/admin/components/AddGroupControl.js"></script>
138
- <script type="module" src="/admin/components/ClearExpiredSessionsControl.js"></script>
139
- <script type="module" src="/admin/components/TableRowLink.js"></script>
140
- <div class="d-f">
141
- <div>
142
- <a href="/admin/accounts/users" class="no-link mb">
143
- <button class="mbh"><k-icon name="arrow" direction="left"></k-icon> Users</button>
144
- </a>
145
- </div>
146
- <div class="flex"></div>
147
- <div>
148
- <button id="deleteUserBtn" class="danger mb mrh" style="display:none;">Delete User</button>
149
- <button id="saveBtn" class="primary mb" disabled style="display:none;"><k-icon name="save"></k-icon> Save</button>
150
- </div>
151
- </div>
152
- <h1 id="pageTitle">User</h1>
153
-
154
- <div id="loading">Loading user...</div>
155
- <div id="notFound" style="display: none;">
156
- <p>User not found.</p>
157
- <a href="/admin/accounts/users">Back to Users</a>
158
- </div>
159
- <div id="content" style="display: none;">
160
-
161
- <!-- User Information -->
162
- <div class="card">
163
- <h2>Information</h2>
164
- <div class="d-f mb" style="align-items: center; gap: var(--spacer);">
165
- <label for="userName" style="min-width: 120px;"><strong>Name</strong></label>
166
- <input type="text" id="userName" style="max-width: 400px;">
167
- </div>
168
- <div class="d-f mb" style="align-items: center; gap: var(--spacer);">
169
- <label for="userEmail" style="min-width: 120px;"><strong>Email</strong></label>
170
- <input type="email" id="userEmail" style="max-width: 400px;">
171
- </div>
172
- <div class="d-f mb" style="align-items: center; gap: var(--spacer);">
173
- <label style="min-width: 120px;"><strong>Verified</strong></label>
174
- <k-toggle id="emailVerified"></k-toggle>
175
- </div>
176
- <div class="d-f mb" style="align-items: center; gap: var(--spacer);">
177
- <label style="min-width: 120px;"><strong>Created</strong></label>
178
- <span id="userCreatedAt"></span>
179
- </div>
180
- </div>
181
-
182
- <!-- Groups -->
183
- <div class="card">
184
- <h2>Groups</h2>
185
- <k-table id="groupsTable" request-delete placeholder="Not a member of any groups.">
186
- <admin-table-row-link slot="before" url-pattern="/admin/accounts/groups/{name}" field-name="name"></admin-table-row-link>
187
- <k-tc-delete-record slot="after"></k-tc-delete-record>
188
- <div slot="top" id="groupsTableTop" class="d-f full" style="display:none; align-items: center;">
189
- <div><admin-group-delete-selected></admin-group-delete-selected></div>
190
- <div class="flex"></div>
191
- <div><admin-add-group-control id="addGroupBtn"></admin-add-group-control></div>
192
- </div>
193
- </k-table>
194
- </div>
195
-
196
- <!-- Sessions -->
197
- <div class="card">
198
- <h2>Sessions</h2>
199
- <k-table id="sessionsTable" enable-pages page-size="10" page-size-options="[10,25,50]" placeholder="No active sessions.">
200
- <k-tc-delete-record slot="after"></k-tc-delete-record>
201
- <div slot="top" class="d-f full" style="align-items: center;">
202
- <div><k-tc-delete-selected></k-tc-delete-selected></div>
203
- <div class="flex"></div>
204
- <div><admin-clear-expired-sessions id="clearExpiredBtn" style="display:none;"></admin-clear-expired-sessions></div>
205
- </div>
206
- <div class="d-f full" style="align-items: center;">
207
- <div>
208
- <k-tc-first-page></k-tc-first-page>
209
- <k-tc-prev-page></k-tc-prev-page>
210
- <k-tc-next-page></k-tc-next-page>
211
- <k-tc-last-page></k-tc-last-page>
212
- </div>
213
- <div class="flex"></div>
214
- <div><k-tc-page-select></k-tc-page-select></div>
215
- <div class="flex"></div>
216
- <div><k-tc-page-size></k-tc-page-size></div>
217
- </div>
218
- </k-table>
219
- </div>
220
-
221
- </div>
222
-
223
- <script type="module">
224
- import {
225
- getSession, getUser, updateUser, deleteUsers,
226
- getUserSessions, deleteUserSession, deleteExpiredUserSessions,
227
- getUserGroups, addUserToGroup, removeUserFromGroup,
228
- listGroups, getAllCurrentUserPermissions
229
- } from '/kempo/sdk.js';
230
- import { html } from '/kempo-ui/lit-all.min.js';
231
- import Toast from '/kempo-ui/components/Toast.js';
232
- import Dialog from '/kempo-ui/components/Dialog.js';
233
-
234
- const userid = window.location.pathname.split('/admin/accounts/users/')[1]?.replace(/\/$/, '');
235
-
236
- if(!userid){
237
- document.getElementById('loading').style.display = 'none';
238
- document.getElementById('notFound').style.display = '';
239
- }
240
-
241
- /*
242
- Permission checks
243
- */
244
-
245
- const [[, permResult], [, sessionData]] = await Promise.all([
246
- getAllCurrentUserPermissions(),
247
- getSession()
248
- ]);
249
- const myPerms = new Set(permResult?.permissions ?? []);
250
- const currentUserId = sessionData?.user?.id;
251
- const canEdit = myPerms.has('system:user:update');
252
- const canDelete = myPerms.has('system:user:delete');
253
- const canEditGroups = myPerms.has('system:group:update');
254
- const canReadGroups = myPerms.has('system:group:read');
255
-
256
- /*
257
- Load user
258
- */
259
-
260
- const [userError, userData] = await getUser(userid);
261
-
262
- document.getElementById('loading').style.display = 'none';
263
-
264
- if(userError){
265
- document.getElementById('notFound').style.display = '';
266
- } else {
267
- document.getElementById('content').style.display = '';
268
- document.getElementById('pageTitle').textContent = `User: ${userData.name}`;
269
- document.title = `${userData.name} - Admin`;
270
-
271
- await customElements.whenDefined('k-toggle');
272
-
273
- const $userName = document.getElementById('userName');
274
- const $userEmail = document.getElementById('userEmail');
275
- const $emailVerified = document.getElementById('emailVerified');
276
- const $userCreatedAt = document.getElementById('userCreatedAt');
277
- const $deleteBtn = document.getElementById('deleteUserBtn');
278
-
279
- $userName.value = userData.name;
280
- $userEmail.value = userData.email;
281
- $emailVerified.value = userData.emailVerified;
282
- $userCreatedAt.textContent = new Date(userData.createdAt).toLocaleString();
283
-
284
- const isSelf = userData.id === currentUserId;
285
-
286
- if(!canEdit){
287
- $userName.readOnly = true;
288
- $userEmail.readOnly = true;
289
- $emailVerified.setAttribute('disabled', '');
290
- }
291
-
292
- if(!canDelete || isSelf){
293
- $deleteBtn.style.display = 'none';
294
- } else {
295
- $deleteBtn.style.display = '';
296
- }
297
-
298
- /*
299
- Save user fields
300
- */
301
-
302
- if(canEdit){
303
- const $saveBtn = document.getElementById('saveBtn');
304
- $saveBtn.style.display = '';
305
-
306
- const origName = userData.name;
307
- const origEmail = userData.email;
308
- const origVerified = userData.emailVerified;
309
-
310
- const handleBeforeUnload = e => { e.preventDefault(); e.returnValue = ''; };
311
-
312
- const checkDirty = () => {
313
- const dirty = $userName.value !== origName
314
- || $userEmail.value !== origEmail
315
- || $emailVerified.value !== origVerified;
316
- $saveBtn.disabled = !dirty;
317
- if(dirty){
318
- window.addEventListener('beforeunload', handleBeforeUnload);
319
- } else {
320
- window.removeEventListener('beforeunload', handleBeforeUnload);
321
- }
322
- };
323
-
324
- $userName.addEventListener('input', checkDirty);
325
- $userEmail.addEventListener('input', checkDirty);
326
- $emailVerified.addEventListener('change', checkDirty);
327
-
328
- $saveBtn.addEventListener('click', async () => {
329
- const [error] = await updateUser({
330
- id: userData.id,
331
- name: $userName.value,
332
- email: $userEmail.value,
333
- emailVerified: $emailVerified.value
334
- });
335
- if(error){
336
- Toast.error(error.msg || 'Failed to save');
337
- return;
338
- }
339
- window.removeEventListener('beforeunload', handleBeforeUnload);
340
- document.getElementById('pageTitle').textContent = `User: ${$userName.value}`;
341
- document.title = `${$userName.value} - Admin`;
342
- $saveBtn.disabled = true;
343
- Toast.success('User saved');
344
- });
345
- }
346
-
347
- /*
348
- Delete user
349
- */
350
-
351
- $deleteBtn.addEventListener('click', () => {
352
- if(isSelf) return;
353
- Dialog.confirm('Are you sure you want to delete this user? This action cannot be undone.', async (confirmed) => {
354
- if(!confirmed) return;
355
- const [error] = await deleteUsers([userData.id]);
356
-
357
- if(error){
358
- Toast.error(error.msg || 'Failed to delete user');
359
- return;
360
- }
361
-
362
- Toast.success('User deleted');
363
- window.location.href = '/admin/accounts/users';
364
- });
365
- });
366
-
367
- /*
368
- Groups
369
- */
370
-
371
- await customElements.whenDefined('k-table');
372
- const $groupsTable = document.getElementById('groupsTable');
373
-
374
- if(canEditGroups){
375
- $groupsTable.setAttribute('enable-selection', '');
376
- document.getElementById('groupsTableTop').style.display = '';
377
- }
378
-
379
- $groupsTable.addEventListener('requestDelete', ({ detail: { records, approve, reject } }) => {
380
- if(records[0].name === 'system:Users') { reject(); return; }
381
- Dialog.confirm(`Remove from "${records[0].name}"?`, async (confirmed) => {
382
- if(!confirmed){ reject(); return; }
383
- const [error] = await removeUserFromGroup(userid, records[0].name);
384
- if(error){
385
- reject();
386
- Toast.error(error.msg || 'Failed to remove from group');
387
- return;
388
- }
389
- approve();
390
- Toast.success(`Removed from ${records[0].name}`);
391
- loadGroups();
392
- });
393
- });
394
-
395
- $groupsTable.addEventListener('groupRemoveSelected', ({ detail: { records, systemUsersSkipped } }) => {
396
- const count = records.length;
397
- const note = systemUsersSkipped ? '<p><small><em>Note: The user cannot be removed from system:Users, but will be removed from the other selected groups.</em></small></p>' : '';
398
- Dialog.confirm(`<div class="p"><p>Remove from ${count} group${count !== 1 ? 's' : ''}?</p>${note}</div>`, async (confirmed) => {
399
- if(!confirmed) return;
400
- const errors = [];
401
- for(const record of records){
402
- const [error] = await removeUserFromGroup(userid, record.name);
403
- if(error) errors.push(error.msg);
404
- }
405
- if(errors.length){
406
- Toast.error(errors[0] || 'Failed to remove from group');
407
- return;
408
- }
409
- Toast.success(`Removed from ${count} group${count !== 1 ? 's' : ''}`);
410
- loadGroups();
411
- });
412
- });
413
-
414
- const loadGroups = async () => {
415
- const [error, data] = await getUserGroups(userid);
416
- if(error){
417
- Toast.error(error.msg || 'Failed to load groups');
418
- return;
419
- }
420
- $groupsTable.setData({
421
- records: data.groups,
422
- fields: [{ name: 'name', label: 'Name' }]
423
- });
424
- $groupsTable.setupFetchRecords(data.total, async (start, count) => {
425
- const [err, d] = await getUserGroups(userid, { limit: count, offset: start });
426
- if(err) return [];
427
- return d.groups;
428
- });
429
- };
430
-
431
- document.getElementById('addGroupBtn').addEventListener('click', async () => {
432
- const [error, data] = await listGroups({ limit: 1000 });
433
- if(error){ Toast.error(error.msg || 'Failed to load groups'); return; }
434
-
435
- const userGroupNames = new Set($groupsTable.records.map(g => g.name));
436
- const available = data.groups.filter(g => !userGroupNames.has(g.name));
437
-
438
- const $dialog = Dialog.create(html`
439
- <div class="p">
440
- <select id="dlg-group">
441
- <option value="">Select a group...</option>
442
- ${available.map(g => html`<option value=${g.name}>${g.name}</option>`)}
443
- </select>
444
- </div>
445
- `, {
446
- title: 'Add to Group',
447
- confirmText: 'Add',
448
- confirmAction: async () => {
449
- const groupName = $dialog.querySelector('#dlg-group').value;
450
- if(!groupName) return;
451
- const [err] = await addUserToGroup(userid, groupName);
452
- if(err){ Toast.error(err.msg || 'Failed to add to group'); return; }
453
- Toast.success(`Added to ${groupName}`);
454
- loadGroups();
455
- },
456
- cancelText: 'Cancel'
457
- });
458
- });
459
-
460
- loadGroups();
461
-
462
- /*
463
- Sessions
464
- */
465
-
466
- const $sessionsTable = document.getElementById('sessionsTable');
467
-
468
- if(canEdit){
469
- $sessionsTable.setAttribute('request-delete', '');
470
- $sessionsTable.setAttribute('enable-selection', '');
471
- const $clearExpiredBtn = document.getElementById('clearExpiredBtn');
472
- $clearExpiredBtn.style.display = '';
473
- $clearExpiredBtn.addEventListener('click', async () => {
474
- const [error, result] = await deleteExpiredUserSessions(userid);
475
- if(error){
476
- Toast.error(error.msg || 'Failed to clear expired sessions');
477
- return;
478
- }
479
- Toast.success(`Cleared ${result.deleted} expired session${result.deleted !== 1 ? 's' : ''}`);
480
- loadSessions();
481
- });
482
- }
483
-
484
- $sessionsTable.addEventListener('requestDelete', async ({ detail: { records, approve, reject } }) => {
485
- const errors = [];
486
- for(const record of records){
487
- const [error] = await deleteUserSession(userid, record.token);
488
- if(error) errors.push(error.msg);
489
- }
490
- if(errors.length){
491
- reject();
492
- Toast.error(errors[0] || 'Failed to revoke session');
493
- return;
494
- }
495
- approve();
496
- Toast.success(records.length === 1 ? 'Session revoked' : `${records.length} sessions revoked`);
497
- });
498
-
499
- const loadSessions = async () => {
500
- const [error, data] = await getUserSessions(userid);
501
- if(error){
502
- Toast.error(error.msg || 'Failed to load sessions');
503
- return;
504
- }
505
- const now = new Date();
506
- $sessionsTable.setData({
507
- records: data.sessions,
508
- fields: [
509
- {
510
- name: 'createdAt',
511
- label: 'Created',
512
- formatter: v => new Date(v).toLocaleString()
513
- },
514
- {
515
- name: 'expiresAt',
516
- label: 'Expires',
517
- formatter: v => {
518
- const date = new Date(v);
519
- return `${date.toLocaleString()}${date < now ? ' (expired)' : ''}`;
520
- }
521
- },
522
- { name: 'ipAddress', label: 'IP' },
523
- { name: 'userAgent', label: 'User Agent' }
524
- ]
525
- });
526
- $sessionsTable.setupFetchRecords(data.total, async (start, count) => {
527
- const [err, d] = await getUserSessions(userid, { limit: count, offset: start });
528
- if(err) return [];
529
- return d.sessions;
530
- });
531
- };
532
-
533
- loadSessions();
534
- }
535
- </script>
536
-
537
-
538
- </k-main>
539
-
540
- </body>
541
- </html>