@hed-hog/core 0.0.370 → 0.0.371

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 (248) hide show
  1. package/LICENSE.md +21 -0
  2. package/README.md +2 -0
  3. package/dist/ai/ai.service.d.ts.map +1 -1
  4. package/dist/ai/ai.service.js +10 -7
  5. package/dist/ai/ai.service.js.map +1 -1
  6. package/dist/app-command/app-command.module.d.ts +3 -0
  7. package/dist/app-command/app-command.module.d.ts.map +1 -0
  8. package/dist/app-command/app-command.module.js +22 -0
  9. package/dist/app-command/app-command.module.js.map +1 -0
  10. package/dist/app-command/app-command.registry.d.ts +22 -0
  11. package/dist/app-command/app-command.registry.d.ts.map +1 -0
  12. package/dist/{webhook-integration/webhook-command.registry.js → app-command/app-command.registry.js} +6 -6
  13. package/dist/app-command/app-command.registry.js.map +1 -0
  14. package/dist/auth/auth.controller.d.ts +2 -2
  15. package/dist/auth/auth.controller.d.ts.map +1 -1
  16. package/dist/auth/auth.controller.js +20 -7
  17. package/dist/auth/auth.controller.js.map +1 -1
  18. package/dist/auth/auth.service.d.ts +3 -3
  19. package/dist/auth/auth.service.d.ts.map +1 -1
  20. package/dist/auth/auth.service.js +10 -36
  21. package/dist/auth/auth.service.js.map +1 -1
  22. package/dist/auth/dto/forget.dto.d.ts +1 -0
  23. package/dist/auth/dto/forget.dto.d.ts.map +1 -1
  24. package/dist/auth/dto/forget.dto.js +5 -0
  25. package/dist/auth/dto/forget.dto.js.map +1 -1
  26. package/dist/auth/guards/auth.guard.d.ts.map +1 -1
  27. package/dist/auth/guards/auth.guard.js +4 -1
  28. package/dist/auth/guards/auth.guard.js.map +1 -1
  29. package/dist/challenge/challenge.service.d.ts +8 -7
  30. package/dist/challenge/challenge.service.d.ts.map +1 -1
  31. package/dist/challenge/challenge.service.js +27 -19
  32. package/dist/challenge/challenge.service.js.map +1 -1
  33. package/dist/file/dto/upload.dto.d.ts +3 -0
  34. package/dist/file/dto/upload.dto.d.ts.map +1 -1
  35. package/dist/file/dto/upload.dto.js +22 -0
  36. package/dist/file/dto/upload.dto.js.map +1 -1
  37. package/dist/file/file.controller.d.ts +2 -1
  38. package/dist/file/file.controller.d.ts.map +1 -1
  39. package/dist/file/file.controller.js +29 -16
  40. package/dist/file/file.controller.js.map +1 -1
  41. package/dist/file/file.service.d.ts +51 -1
  42. package/dist/file/file.service.d.ts.map +1 -1
  43. package/dist/file/file.service.js +250 -18
  44. package/dist/file/file.service.js.map +1 -1
  45. package/dist/file/image-optimization.service.d.ts +17 -4
  46. package/dist/file/image-optimization.service.d.ts.map +1 -1
  47. package/dist/file/image-optimization.service.js +101 -46
  48. package/dist/file/image-optimization.service.js.map +1 -1
  49. package/dist/file/provider/s3.provider.d.ts.map +1 -1
  50. package/dist/file/provider/s3.provider.js +15 -7
  51. package/dist/file/provider/s3.provider.js.map +1 -1
  52. package/dist/file/provider/spaces.provider.d.ts.map +1 -1
  53. package/dist/file/provider/spaces.provider.js +18 -8
  54. package/dist/file/provider/spaces.provider.js.map +1 -1
  55. package/dist/index.d.ts +4 -1
  56. package/dist/index.d.ts.map +1 -1
  57. package/dist/index.js +4 -1
  58. package/dist/index.js.map +1 -1
  59. package/dist/integration/services/event-subscriber.registry.d.ts +5 -0
  60. package/dist/integration/services/event-subscriber.registry.d.ts.map +1 -1
  61. package/dist/integration/services/event-subscriber.registry.js +15 -0
  62. package/dist/integration/services/event-subscriber.registry.js.map +1 -1
  63. package/dist/integration/services/outbox.processor.d.ts.map +1 -1
  64. package/dist/integration/services/outbox.processor.js +2 -4
  65. package/dist/integration/services/outbox.processor.js.map +1 -1
  66. package/dist/integration/services/outbox.service.d.ts +4 -2
  67. package/dist/integration/services/outbox.service.d.ts.map +1 -1
  68. package/dist/integration/services/outbox.service.js +26 -15
  69. package/dist/integration/services/outbox.service.js.map +1 -1
  70. package/dist/integration-profile/integration-credential-crypto.service.d.ts +43 -0
  71. package/dist/integration-profile/integration-credential-crypto.service.d.ts.map +1 -0
  72. package/dist/integration-profile/integration-credential-crypto.service.js +142 -0
  73. package/dist/integration-profile/integration-credential-crypto.service.js.map +1 -0
  74. package/dist/integration-profile/integration-profile.controller.d.ts +6 -7
  75. package/dist/integration-profile/integration-profile.controller.d.ts.map +1 -1
  76. package/dist/integration-profile/integration-profile.controller.js +4 -3
  77. package/dist/integration-profile/integration-profile.controller.js.map +1 -1
  78. package/dist/integration-profile/integration-profile.module.d.ts.map +1 -1
  79. package/dist/integration-profile/integration-profile.module.js +5 -2
  80. package/dist/integration-profile/integration-profile.module.js.map +1 -1
  81. package/dist/integration-profile/integration-profile.secrets.d.ts +16 -0
  82. package/dist/integration-profile/integration-profile.secrets.d.ts.map +1 -0
  83. package/dist/integration-profile/integration-profile.secrets.js +56 -0
  84. package/dist/integration-profile/integration-profile.secrets.js.map +1 -0
  85. package/dist/integration-profile/integration-profile.service.d.ts +125 -8
  86. package/dist/integration-profile/integration-profile.service.d.ts.map +1 -1
  87. package/dist/integration-profile/integration-profile.service.js +257 -68
  88. package/dist/integration-profile/integration-profile.service.js.map +1 -1
  89. package/dist/integration-profile/integration-profile.utils.d.ts +17 -0
  90. package/dist/integration-profile/integration-profile.utils.d.ts.map +1 -1
  91. package/dist/integration-profile/integration-profile.utils.js +31 -0
  92. package/dist/integration-profile/integration-profile.utils.js.map +1 -1
  93. package/dist/language/en.json +178 -0
  94. package/dist/language/pt.json +178 -0
  95. package/dist/mail/mail.controller.d.ts.map +1 -1
  96. package/dist/mail/mail.controller.js +5 -28
  97. package/dist/mail/mail.controller.js.map +1 -1
  98. package/dist/mail/mail.module.js +18 -18
  99. package/dist/mail/mail.module.js.map +1 -1
  100. package/dist/mail/mail.service.d.ts +13 -2
  101. package/dist/mail/mail.service.d.ts.map +1 -1
  102. package/dist/mail/mail.service.js +25 -15
  103. package/dist/mail/mail.service.js.map +1 -1
  104. package/dist/mcp-chat/mcp-chat.service.js +6 -5
  105. package/dist/mcp-chat/mcp-chat.service.js.map +1 -1
  106. package/dist/oauth/providers/facebook.provider.js +5 -5
  107. package/dist/oauth/providers/facebook.provider.js.map +1 -1
  108. package/dist/oauth/providers/github.provider.js +5 -5
  109. package/dist/oauth/providers/github.provider.js.map +1 -1
  110. package/dist/oauth/providers/google.provider.js +5 -5
  111. package/dist/oauth/providers/google.provider.js.map +1 -1
  112. package/dist/oauth/providers/microsoft-entra-id.provider.js +5 -5
  113. package/dist/oauth/providers/microsoft-entra-id.provider.js.map +1 -1
  114. package/dist/oauth/providers/microsoft.provider.js +5 -5
  115. package/dist/oauth/providers/microsoft.provider.js.map +1 -1
  116. package/dist/pdf/pdf.service.d.ts +4 -0
  117. package/dist/pdf/pdf.service.d.ts.map +1 -1
  118. package/dist/pdf/pdf.service.js +16 -9
  119. package/dist/pdf/pdf.service.js.map +1 -1
  120. package/dist/profile/profile.controller.d.ts +7 -7
  121. package/dist/profile/profile.controller.d.ts.map +1 -1
  122. package/dist/profile/profile.controller.js +28 -21
  123. package/dist/profile/profile.controller.js.map +1 -1
  124. package/dist/profile/profile.service.d.ts +7 -7
  125. package/dist/profile/profile.service.d.ts.map +1 -1
  126. package/dist/profile/profile.service.js +21 -25
  127. package/dist/profile/profile.service.js.map +1 -1
  128. package/dist/setting/setting.service.d.ts +1 -0
  129. package/dist/setting/setting.service.d.ts.map +1 -1
  130. package/dist/setting/setting.service.js +15 -2
  131. package/dist/setting/setting.service.js.map +1 -1
  132. package/dist/token/token.service.d.ts.map +1 -1
  133. package/dist/token/token.service.js +2 -1
  134. package/dist/token/token.service.js.map +1 -1
  135. package/dist/user/user.controller.d.ts +9 -0
  136. package/dist/user/user.controller.d.ts.map +1 -1
  137. package/dist/user/user.controller.js +13 -0
  138. package/dist/user/user.controller.js.map +1 -1
  139. package/dist/user/user.service.d.ts +7 -0
  140. package/dist/user/user.service.d.ts.map +1 -1
  141. package/dist/user/user.service.js +19 -0
  142. package/dist/user/user.service.js.map +1 -1
  143. package/dist/utils/webauthn-origin.d.ts +11 -0
  144. package/dist/utils/webauthn-origin.d.ts.map +1 -0
  145. package/dist/utils/webauthn-origin.js +37 -0
  146. package/dist/utils/webauthn-origin.js.map +1 -0
  147. package/dist/webhook-integration/webhook-integration.controller.d.ts +13 -0
  148. package/dist/webhook-integration/webhook-integration.controller.d.ts.map +1 -1
  149. package/dist/webhook-integration/webhook-integration.controller.js +29 -0
  150. package/dist/webhook-integration/webhook-integration.controller.js.map +1 -1
  151. package/dist/webhook-integration/webhook-integration.module.js +3 -3
  152. package/dist/webhook-integration/webhook-integration.module.js.map +1 -1
  153. package/dist/webhook-integration/webhook-integration.service.d.ts +18 -2
  154. package/dist/webhook-integration/webhook-integration.service.d.ts.map +1 -1
  155. package/dist/webhook-integration/webhook-integration.service.js +110 -6
  156. package/dist/webhook-integration/webhook-integration.service.js.map +1 -1
  157. package/hedhog/data/integration_provider.yaml +9 -0
  158. package/hedhog/data/integration_type.yaml +6 -0
  159. package/hedhog/data/menu.yaml +6 -0
  160. package/hedhog/data/role.yaml +7 -0
  161. package/hedhog/data/route.yaml +36 -0
  162. package/hedhog/data/setting_group.yaml +119 -13
  163. package/hedhog/frontend/app/access-log/page.tsx.ejs +35 -3
  164. package/hedhog/frontend/app/account/components/active-sessions.tsx.ejs +36 -3
  165. package/hedhog/frontend/app/account/components/mcp-tokens.tsx.ejs +39 -4
  166. package/hedhog/frontend/app/account/components/tokens.tsx.ejs +39 -4
  167. package/hedhog/frontend/app/ai_agent/page.tsx.ejs +35 -2
  168. package/hedhog/frontend/app/configurations/[slug]/components/byte-size-input.tsx.ejs +160 -0
  169. package/hedhog/frontend/app/configurations/[slug]/components/duration-input.tsx.ejs +157 -0
  170. package/hedhog/frontend/app/configurations/[slug]/components/setting-field.tsx.ejs +244 -63
  171. package/hedhog/frontend/app/dashboard/[slug]/dashboard-content.tsx.ejs +33 -1
  172. package/hedhog/frontend/app/dashboard/management/tabs/component-roles-tab.tsx.ejs +35 -3
  173. package/hedhog/frontend/app/dashboard/management/tabs/components-tab.tsx.ejs +36 -4
  174. package/hedhog/frontend/app/dashboard/management/tabs/dashboard-roles-tab.tsx.ejs +35 -3
  175. package/hedhog/frontend/app/dashboard/management/tabs/dashboards-tab.tsx.ejs +36 -4
  176. package/hedhog/frontend/app/dashboard/management/tabs/items-tab.tsx.ejs +35 -3
  177. package/hedhog/frontend/app/integration/profiles/page.tsx.ejs +141 -29
  178. package/hedhog/frontend/app/integrations-webhooks/page.tsx.ejs +118 -11
  179. package/hedhog/frontend/app/mail/log/page.tsx.ejs +37 -4
  180. package/hedhog/frontend/app/menu/page.tsx.ejs +34 -2
  181. package/hedhog/frontend/app/preferences/page.tsx.ejs +77 -0
  182. package/hedhog/frontend/app/roles/menus.tsx.ejs +35 -3
  183. package/hedhog/frontend/app/roles/page.tsx.ejs +34 -2
  184. package/hedhog/frontend/app/roles/routes.tsx.ejs +36 -4
  185. package/hedhog/frontend/app/roles/users.tsx.ejs +36 -4
  186. package/hedhog/frontend/app/routes/page.tsx.ejs +34 -2
  187. package/hedhog/frontend/app/setting-list/page.tsx.ejs +34 -2
  188. package/hedhog/frontend/app/users/page.tsx.ejs +51 -21
  189. package/hedhog/frontend/messages/en.json +69 -4
  190. package/hedhog/frontend/messages/pt.json +69 -4
  191. package/hedhog/table/setting.yaml +2 -0
  192. package/hedhog/table/webhook_call_log.yaml +49 -46
  193. package/package.json +8 -3
  194. package/src/ai/ai.service.ts +9 -6
  195. package/src/app-command/app-command.module.ts +9 -0
  196. package/src/{webhook-integration/webhook-command.registry.ts → app-command/app-command.registry.ts} +9 -9
  197. package/src/auth/auth.controller.ts +20 -4
  198. package/src/auth/auth.service.ts +10 -36
  199. package/src/auth/dto/forget.dto.ts +5 -1
  200. package/src/auth/guards/auth.guard.ts +4 -1
  201. package/src/challenge/challenge.service.ts +30 -19
  202. package/src/file/dto/upload.dto.ts +25 -1
  203. package/src/file/file.controller.ts +31 -18
  204. package/src/file/file.service.ts +341 -16
  205. package/src/file/image-optimization.service.ts +111 -46
  206. package/src/file/provider/s3.provider.ts +16 -7
  207. package/src/file/provider/spaces.provider.ts +15 -5
  208. package/src/index.ts +4 -1
  209. package/src/integration/services/event-subscriber.registry.ts +15 -0
  210. package/src/integration/services/outbox.processor.ts +2 -5
  211. package/src/integration/services/outbox.service.ts +35 -17
  212. package/src/integration-profile/integration-credential-crypto.service.ts +146 -0
  213. package/src/integration-profile/integration-profile.controller.ts +2 -0
  214. package/src/integration-profile/integration-profile.module.ts +5 -2
  215. package/src/integration-profile/integration-profile.secrets.ts +51 -0
  216. package/src/integration-profile/integration-profile.service.ts +335 -54
  217. package/src/integration-profile/integration-profile.utils.ts +56 -0
  218. package/src/language/en.json +5 -1
  219. package/src/language/pt.json +5 -1
  220. package/src/mail/mail.controller.ts +5 -29
  221. package/src/mail/mail.module.ts +5 -5
  222. package/src/mail/mail.service.ts +37 -13
  223. package/src/mcp-chat/mcp-chat.service.ts +5 -5
  224. package/src/oauth/oauth-callback-coordinator.service.spec.ts +159 -0
  225. package/src/oauth/providers/facebook.provider.ts +3 -3
  226. package/src/oauth/providers/github.provider.ts +3 -3
  227. package/src/oauth/providers/google.provider.ts +3 -3
  228. package/src/oauth/providers/microsoft-entra-id.provider.ts +3 -3
  229. package/src/oauth/providers/microsoft.provider.ts +3 -3
  230. package/src/pdf/pdf.service.ts +19 -6
  231. package/src/profile/profile.controller.ts +21 -14
  232. package/src/profile/profile.service.ts +23 -20
  233. package/src/security/security.service.spec.ts +222 -0
  234. package/src/setting/setting.service.ts +15 -2
  235. package/src/token/token.service.ts +2 -1
  236. package/src/user/user.controller.ts +26 -16
  237. package/src/user/user.service.ts +25 -0
  238. package/src/utils/webauthn-origin.ts +38 -0
  239. package/src/webhook-integration/webhook-integration.controller.ts +23 -0
  240. package/src/webhook-integration/webhook-integration.module.ts +3 -3
  241. package/src/webhook-integration/webhook-integration.service.ts +115 -5
  242. package/dist/webhook-integration/webhook-command.registry.d.ts +0 -22
  243. package/dist/webhook-integration/webhook-command.registry.d.ts.map +0 -1
  244. package/dist/webhook-integration/webhook-command.registry.js.map +0 -1
  245. package/src/menu/menu.service.spec.ts +0 -247
  246. package/src/route/route.service.spec.ts +0 -300
  247. package/src/screen/screen.service.spec.ts +0 -298
  248. package/src/user/user.service.spec.ts +0 -294
@@ -21,6 +21,8 @@
21
21
  slug: admin
22
22
  - where:
23
23
  slug: admin-mail
24
+ - where:
25
+ slug: integration-manager
24
26
  - menu_id:
25
27
  where:
26
28
  slug: /core/management
@@ -107,6 +109,8 @@
107
109
  slug: admin
108
110
  - where:
109
111
  slug: admin-mail
112
+ - where:
113
+ slug: integration-manager
110
114
  - menu_id:
111
115
  where:
112
116
  slug: /core/mail-management
@@ -151,6 +155,8 @@
151
155
  role:
152
156
  - where:
153
157
  slug: admin
158
+ - where:
159
+ slug: integration-manager
154
160
 
155
161
  - menu_id:
156
162
  where:
@@ -40,4 +40,11 @@
40
40
  description:
41
41
  en: Access to search and select email integration profiles.
42
42
  pt: Acesso para buscar e selecionar perfis de integração de email.
43
+ - slug: integration-manager
44
+ name:
45
+ en: Integration Manager
46
+ pt: Gerente de Integrações
47
+ description:
48
+ en: Access to manage integration profiles and their credentials.
49
+ pt: Acesso para gerenciar perfis de integração e suas credenciais.
43
50
 
@@ -582,6 +582,13 @@
582
582
  role:
583
583
  - where:
584
584
  slug: admin
585
+ - url: /file/image/:id
586
+ method: GET
587
+ type: HTTP
588
+ relations:
589
+ role:
590
+ - where:
591
+ slug: admin
585
592
  - url: /file/download/:token
586
593
  method: GET
587
594
  type: HTTP
@@ -1243,6 +1250,8 @@
1243
1250
  role:
1244
1251
  - where:
1245
1252
  slug: admin
1253
+ - where:
1254
+ slug: integration-manager
1246
1255
 
1247
1256
  - url: /integration-profile/providers
1248
1257
  method: GET
@@ -1251,6 +1260,8 @@
1251
1260
  role:
1252
1261
  - where:
1253
1262
  slug: admin
1263
+ - where:
1264
+ slug: integration-manager
1254
1265
 
1255
1266
  - url: /integration-profile
1256
1267
  method: GET
@@ -1259,6 +1270,8 @@
1259
1270
  role:
1260
1271
  - where:
1261
1272
  slug: admin
1273
+ - where:
1274
+ slug: integration-manager
1262
1275
 
1263
1276
  - url: /integration-profile/:id
1264
1277
  method: GET
@@ -1267,6 +1280,8 @@
1267
1280
  role:
1268
1281
  - where:
1269
1282
  slug: admin
1283
+ - where:
1284
+ slug: integration-manager
1270
1285
 
1271
1286
  - url: /integration-profile
1272
1287
  method: POST
@@ -1275,6 +1290,8 @@
1275
1290
  role:
1276
1291
  - where:
1277
1292
  slug: admin
1293
+ - where:
1294
+ slug: integration-manager
1278
1295
 
1279
1296
  - url: /integration-profile/test
1280
1297
  method: POST
@@ -1283,6 +1300,8 @@
1283
1300
  role:
1284
1301
  - where:
1285
1302
  slug: admin
1303
+ - where:
1304
+ slug: integration-manager
1286
1305
 
1287
1306
  - url: /integration-profile/:id
1288
1307
  method: PATCH
@@ -1291,6 +1310,8 @@
1291
1310
  role:
1292
1311
  - where:
1293
1312
  slug: admin
1313
+ - where:
1314
+ slug: integration-manager
1294
1315
 
1295
1316
  - url: /integration-profile
1296
1317
  method: DELETE
@@ -1299,6 +1320,8 @@
1299
1320
  role:
1300
1321
  - where:
1301
1322
  slug: admin
1323
+ - where:
1324
+ slug: integration-manager
1302
1325
 
1303
1326
  - url: /integration-profile/export
1304
1327
  method: GET
@@ -1307,6 +1330,8 @@
1307
1330
  role:
1308
1331
  - where:
1309
1332
  slug: admin
1333
+ - where:
1334
+ slug: integration-manager
1310
1335
 
1311
1336
  - url: /integration-profile/import/validate
1312
1337
  method: POST
@@ -1315,6 +1340,8 @@
1315
1340
  role:
1316
1341
  - where:
1317
1342
  slug: admin
1343
+ - where:
1344
+ slug: integration-manager
1318
1345
 
1319
1346
  - url: /integration-profile/import/confirm
1320
1347
  method: POST
@@ -1323,6 +1350,8 @@
1323
1350
  role:
1324
1351
  - where:
1325
1352
  slug: admin
1353
+ - where:
1354
+ slug: integration-manager
1326
1355
  - url: /ai/chat
1327
1356
  method: POST
1328
1357
  type: HTTP
@@ -1535,6 +1564,13 @@
1535
1564
  role:
1536
1565
  - where:
1537
1566
  slug: admin
1567
+ - url: /webhook-integration/:id/log/:logId/retry
1568
+ method: POST
1569
+ type: HTTP
1570
+ relations:
1571
+ role:
1572
+ - where:
1573
+ slug: admin
1538
1574
  - url: /event-webhook
1539
1575
  method: GET
1540
1576
  type: HTTP
@@ -62,6 +62,20 @@
62
62
  subgroup_id:
63
63
  where:
64
64
  slug: general-system
65
+ - slug: app-urls
66
+ type: array
67
+ component: input-tags
68
+ name:
69
+ en: App URLs
70
+ pt: URLs dos Aplicativos
71
+ description:
72
+ en: 'Base URLs for specific apps, formatted as "app=https://example.com" (one per tag). Used in transactional email links (e.g. password reset) when the request comes from that app, falling back to System URL otherwise.'
73
+ pt: 'URLs base de apps específicos, no formato "app=https://exemplo.com" (uma por tag). Usadas em links de e-mails transacionais (ex.: redefinição de senha) quando a solicitação vem desse app, usando a URL do Sistema como alternativa.'
74
+ value: '["training=http://localhost:3001"]'
75
+ user_override: false
76
+ subgroup_id:
77
+ where:
78
+ slug: general-system
65
79
  - slug: installed
66
80
  type: boolean
67
81
  component: switch
@@ -229,7 +243,7 @@
229
243
  where:
230
244
  slug: mail-configuration
231
245
  - slug: mail-integration-profile-id
232
- type: number
246
+ type: string
233
247
  component: entity-picker
234
248
  name:
235
249
  en: Mail Profile
@@ -237,13 +251,13 @@
237
251
  description:
238
252
  en: Select the mail profile to use for sending system notifications
239
253
  pt: Selecione o perfil de email a usar para enviar notificações do sistema
240
- value: '1'
254
+ value: ''
241
255
  user_override: false
242
256
  subgroup_id:
243
257
  where:
244
258
  slug: mail-configuration
245
259
  - slug: ai-openai-profile-id
246
- type: number
260
+ type: string
247
261
  component: entity-picker
248
262
  name:
249
263
  en: OpenAI Profile
@@ -257,7 +271,7 @@
257
271
  where:
258
272
  slug: ai-configuration
259
273
  - slug: ai-gemini-profile-id
260
- type: number
274
+ type: string
261
275
  component: entity-picker
262
276
  name:
263
277
  en: Gemini Profile
@@ -285,7 +299,7 @@
285
299
  where:
286
300
  slug: mcp-configuration
287
301
  - slug: mcp-ai-profile-id
288
- type: number
302
+ type: string
289
303
  component: entity-picker
290
304
  name:
291
305
  en: AI Profile
@@ -712,7 +726,7 @@
712
726
  where:
713
727
  slug: oauth-general
714
728
  - slug: oauth-google-profile-id
715
- type: number
729
+ type: string
716
730
  component: entity-picker
717
731
  name:
718
732
  en: Google OAuth Profile
@@ -762,7 +776,7 @@
762
776
  where:
763
777
  slug: google
764
778
  - slug: oauth-facebook-profile-id
765
- type: number
779
+ type: string
766
780
  component: entity-picker
767
781
  name:
768
782
  en: Facebook OAuth Profile
@@ -816,7 +830,7 @@
816
830
  where:
817
831
  slug: facebook
818
832
  - slug: oauth-github-profile-id
819
- type: number
833
+ type: string
820
834
  component: entity-picker
821
835
  name:
822
836
  en: GitHub OAuth Profile
@@ -864,7 +878,7 @@
864
878
  where:
865
879
  slug: github
866
880
  - slug: oauth-microsoft-profile-id
867
- type: number
881
+ type: string
868
882
  component: entity-picker
869
883
  name:
870
884
  en: Microsoft OAuth Profile
@@ -918,7 +932,7 @@
918
932
  where:
919
933
  slug: microsoft
920
934
  - slug: oauth-microsoft-entra-id-profile-id
921
- type: number
935
+ type: string
922
936
  component: entity-picker
923
937
  name:
924
938
  en: Microsoft Entra ID OAuth Profile
@@ -1519,6 +1533,56 @@
1519
1533
  subgroup_id:
1520
1534
  where:
1521
1535
  slug: theme-customization
1536
+ - slug: theme-spacing
1537
+ type: string
1538
+ name:
1539
+ en: Spacing Density
1540
+ pt: Densidade de Espaçamento
1541
+ description:
1542
+ en: Global spacing scale applied to paddings, gaps and component sizes
1543
+ pt: Escala de espaçamento global aplicada a paddings, gaps e tamanhos de componentes
1544
+ value: comfortable
1545
+ component: combobox
1546
+ user_override: true
1547
+ relations:
1548
+ setting_list:
1549
+ - value: compact
1550
+ order: 0
1551
+ - value: comfortable
1552
+ order: 1
1553
+ - value: spacious
1554
+ order: 2
1555
+ subgroup_id:
1556
+ where:
1557
+ slug: theme-customization
1558
+ - slug: theme-zoom
1559
+ type: string
1560
+ name:
1561
+ en: Interface Zoom
1562
+ pt: Zoom da Interface
1563
+ description:
1564
+ en: Global zoom level applied to the whole interface (like browser zoom)
1565
+ pt: Nível de zoom global aplicado a toda a interface (como o zoom do navegador)
1566
+ value: 100%
1567
+ component: combobox
1568
+ user_override: true
1569
+ relations:
1570
+ setting_list:
1571
+ - value: 80%
1572
+ order: 0
1573
+ - value: 90%
1574
+ order: 1
1575
+ - value: 100%
1576
+ order: 2
1577
+ - value: 110%
1578
+ order: 3
1579
+ - value: 125%
1580
+ order: 4
1581
+ - value: 150%
1582
+ order: 5
1583
+ subgroup_id:
1584
+ where:
1585
+ slug: theme-customization
1522
1586
  - slug: menu-width
1523
1587
  type: string
1524
1588
  name:
@@ -1592,7 +1656,7 @@
1592
1656
  relations:
1593
1657
  setting:
1594
1658
  - slug: file-storage-profile-id
1595
- type: number
1659
+ type: string
1596
1660
  component: entity-picker
1597
1661
  name:
1598
1662
  en: Storage Profile
@@ -1682,7 +1746,7 @@
1682
1746
  description:
1683
1747
  en: Automatically compress uploaded images to reduce file size
1684
1748
  pt: Comprime automaticamente imagens enviadas para reduzir o tamanho do arquivo
1685
- value: 'false'
1749
+ value: 'true'
1686
1750
  user_override: false
1687
1751
  subgroup_id:
1688
1752
  where:
@@ -1736,7 +1800,7 @@
1736
1800
  description:
1737
1801
  en: Automatically convert uploaded images to WebP format for better compression and web performance
1738
1802
  pt: Converte automaticamente imagens enviadas para formato WebP para melhor compressão e performance web
1739
- value: 'false'
1803
+ value: 'true'
1740
1804
  user_override: false
1741
1805
  subgroup_id:
1742
1806
  where:
@@ -1767,6 +1831,48 @@
1767
1831
  order: 3
1768
1832
  - value: image/tiff
1769
1833
  order: 4
1834
+ - slug: image-max-dimension
1835
+ type: number
1836
+ component: input-number
1837
+ name:
1838
+ en: Max Image Dimension (px)
1839
+ pt: Dimensão Máxima da Imagem (px)
1840
+ description:
1841
+ en: Largest allowed width/height for uploaded images without a specific target size. Bigger images are scaled down keeping aspect ratio. 0 disables this cap (default 1920)
1842
+ pt: Maior largura/altura permitida para imagens enviadas sem tamanho-alvo específico. Imagens maiores são reduzidas mantendo a proporção. 0 desativa este limite (padrão 1920)
1843
+ value: 1920
1844
+ user_override: false
1845
+ subgroup_id:
1846
+ where:
1847
+ slug: image-optimization
1848
+ - slug: image-cache-ttl-seconds
1849
+ type: number
1850
+ component: input-number
1851
+ name:
1852
+ en: Image Cache Duration (seconds)
1853
+ pt: Duração do Cache de Imagens (segundos)
1854
+ description:
1855
+ en: How long browsers cache images served by the dedicated image endpoint (in seconds). Default 2592000 = 30 days
1856
+ pt: Por quanto tempo os navegadores armazenam em cache as imagens servidas pelo endpoint dedicado de imagens (em segundos). Padrão 2592000 = 30 dias
1857
+ value: 2592000
1858
+ user_override: false
1859
+ subgroup_id:
1860
+ where:
1861
+ slug: image-optimization
1862
+ - slug: file-cache-ttl-seconds
1863
+ type: number
1864
+ component: input-number
1865
+ name:
1866
+ en: File Cache Duration (seconds)
1867
+ pt: Duração do Cache de Arquivos (segundos)
1868
+ description:
1869
+ en: How long browsers cache generic files served by the open endpoint (in seconds). Default 86400 = 1 day
1870
+ pt: Por quanto tempo os navegadores armazenam em cache os arquivos genéricos servidos pelo endpoint de abertura (em segundos). Padrão 86400 = 1 dia
1871
+ value: 86400
1872
+ user_override: false
1873
+ subgroup_id:
1874
+ where:
1875
+ slug: image-optimization
1770
1876
  - slug: integration
1771
1877
  icon: webhook
1772
1878
  name:
@@ -104,6 +104,8 @@ function MethodBadge({ method }: { method: string | null }) {
104
104
  );
105
105
  }
106
106
 
107
+ const DEFAULT_PAGE_SIZES = [6, 12, 24, 48, 96] as const;
108
+
107
109
  export default function AccessLogPage() {
108
110
  const t = useTranslations('core.AccessLog');
109
111
  const { request, getSettingValue } = useApp();
@@ -121,10 +123,40 @@ export default function AccessLogPage() {
121
123
  const [viewMode, setViewMode] = useState<ViewMode>('table');
122
124
  const [isLive, setIsLive] = useState(true);
123
125
  const [page, setPage] = useState(1);
126
+ const { data: generalSettings } = useQuery<{
127
+ data: Array<{ slug: string; value: string }>;
128
+ }>({
129
+ queryKey: ['setting-group-general'],
130
+ queryFn: async () => {
131
+ const response = await request<{
132
+ data: Array<{ slug: string; value: string }>;
133
+ }>({ url: '/setting/group/general', method: 'GET' });
134
+ return response.data;
135
+ },
136
+ staleTime: 5 * 60 * 1000,
137
+ });
138
+
139
+ const pageSizeOptions = useMemo(() => {
140
+ const setting = generalSettings?.data?.find(
141
+ (s) => s.slug === 'pagination-page-sizes'
142
+ );
143
+ if (!setting?.value) return DEFAULT_PAGE_SIZES;
144
+ try {
145
+ const parsed = JSON.parse(setting.value) as string[];
146
+ const sizes = parsed
147
+ .map(Number)
148
+ .filter((n) => !isNaN(n) && n > 0)
149
+ .sort((a, b) => a - b);
150
+ return sizes.length > 0 ? sizes : DEFAULT_PAGE_SIZES;
151
+ } catch {
152
+ return DEFAULT_PAGE_SIZES;
153
+ }
154
+ }, [generalSettings]);
155
+
124
156
  const [pageSize, setPageSize] = usePersistedPageSize({
125
157
  storageKey: 'pagination:global:pageSize',
126
- defaultValue: 10,
127
- allowedValues: [10, 20, 30, 40, 50],
158
+ defaultValue: 12,
159
+ allowedValues: pageSizeOptions,
128
160
  });
129
161
 
130
162
  const debouncedSearch = useDebounce(searchTerm);
@@ -731,7 +763,7 @@ export default function AccessLogPage() {
731
763
  setPageSize(s);
732
764
  setPage(1);
733
765
  }}
734
- pageSizeOptions={[10, 20, 30, 40, 50]}
766
+ pageSizeOptions={pageSizeOptions}
735
767
  />
736
768
 
737
769
  {selectedLog && (
@@ -32,12 +32,14 @@ import { usePagination } from '@/hooks/use-pagination';
32
32
  import { formatDate, formatDateTime } from '@/lib/format-date';
33
33
  import { parseBrowser, parseDeviceType, parseOS } from '@/lib/session';
34
34
  import { UserSession } from '@hed-hog/api-types';
35
- import { useApp } from '@hed-hog/next-app-provider';
35
+ import { useApp, useQuery } from '@hed-hog/next-app-provider';
36
36
  import { Calendar, Clock, LogOut, MapPin } from 'lucide-react';
37
37
  import { useTranslations } from 'next-intl';
38
- import { useState } from 'react';
38
+ import { useMemo, useState } from 'react';
39
39
  import { toast } from 'sonner';
40
40
 
41
+ const DEFAULT_PAGE_SIZES = [6, 12, 24, 48, 96] as const;
42
+
41
43
  export function ActiveSessions() {
42
44
  const { request, logout, currentLocaleCode, getSettingValue } = useApp();
43
45
  const t = useTranslations('core.ActiveSessions');
@@ -45,6 +47,36 @@ export function ActiveSessions() {
45
47
  const [revokeAllSessions, setRevokeAllSessions] = useState(false);
46
48
  const [revokeAllOtherSessions, setRevokeAllOtherSessions] = useState(false);
47
49
 
50
+ const { data: generalSettings } = useQuery<{
51
+ data: Array<{ slug: string; value: string }>;
52
+ }>({
53
+ queryKey: ['setting-group-general'],
54
+ queryFn: async () => {
55
+ const response = await request<{
56
+ data: Array<{ slug: string; value: string }>;
57
+ }>({ url: '/setting/group/general', method: 'GET' });
58
+ return response.data;
59
+ },
60
+ staleTime: 5 * 60 * 1000,
61
+ });
62
+
63
+ const pageSizeOptions = useMemo(() => {
64
+ const setting = generalSettings?.data?.find(
65
+ (s) => s.slug === 'pagination-page-sizes'
66
+ );
67
+ if (!setting?.value) return DEFAULT_PAGE_SIZES;
68
+ try {
69
+ const parsed = JSON.parse(setting.value) as string[];
70
+ const sizes = parsed
71
+ .map(Number)
72
+ .filter((n) => !isNaN(n) && n > 0)
73
+ .sort((a, b) => a - b);
74
+ return sizes.length > 0 ? sizes : DEFAULT_PAGE_SIZES;
75
+ } catch {
76
+ return DEFAULT_PAGE_SIZES;
77
+ }
78
+ }, [generalSettings]);
79
+
48
80
  const {
49
81
  items: sessions,
50
82
  refetch,
@@ -55,6 +87,7 @@ export function ActiveSessions() {
55
87
  setPageSize,
56
88
  } = usePagination({
57
89
  url: `/sessions/user`,
90
+ paginationOptions: { pageSizeOptions },
58
91
  });
59
92
 
60
93
  const handleRevokeSession = async (sessionId: number) => {
@@ -159,7 +192,7 @@ export function ActiveSessions() {
159
192
  setPageSize(newSize);
160
193
  setPage(1);
161
194
  }}
162
- pageSizeOptions={[10, 20, 30, 40, 50]}
195
+ pageSizeOptions={pageSizeOptions}
163
196
  />
164
197
  </div>
165
198
  </>
@@ -39,10 +39,10 @@ import {
39
39
  } from '@/components/ui/table';
40
40
  import { usePagination } from '@/hooks/use-pagination';
41
41
  import { formatDateTime } from '@/lib/format-date';
42
- import { useApp } from '@hed-hog/next-app-provider';
42
+ import { useApp, useQuery } from '@hed-hog/next-app-provider';
43
43
  import { Check, Copy, KeyRound, Plus, Trash2 } from 'lucide-react';
44
44
  import { useTranslations } from 'next-intl';
45
- import { useState } from 'react';
45
+ import { useMemo, useState } from 'react';
46
46
  import { toast } from 'sonner';
47
47
 
48
48
  type McpApiKey = {
@@ -54,6 +54,8 @@ type McpApiKey = {
54
54
  created_at: string;
55
55
  };
56
56
 
57
+ const DEFAULT_PAGE_SIZES = [6, 12, 24, 48, 96] as const;
58
+
57
59
  export function McpTokens() {
58
60
  const { request, getSettingValue } = useApp();
59
61
  const t = useTranslations('core.McpTokens');
@@ -64,6 +66,36 @@ export function McpTokens() {
64
66
  const [createdToken, setCreatedToken] = useState<string | null>(null);
65
67
  const [isCopied, setIsCopied] = useState(false);
66
68
  const [isCopiedUrl, setIsCopiedUrl] = useState(false);
69
+ const { data: generalSettings } = useQuery<{
70
+ data: Array<{ slug: string; value: string }>;
71
+ }>({
72
+ queryKey: ['setting-group-general'],
73
+ queryFn: async () => {
74
+ const response = await request<{
75
+ data: Array<{ slug: string; value: string }>;
76
+ }>({ url: '/setting/group/general', method: 'GET' });
77
+ return response.data;
78
+ },
79
+ staleTime: 5 * 60 * 1000,
80
+ });
81
+
82
+ const pageSizeOptions = useMemo(() => {
83
+ const setting = generalSettings?.data?.find(
84
+ (s) => s.slug === 'pagination-page-sizes'
85
+ );
86
+ if (!setting?.value) return DEFAULT_PAGE_SIZES;
87
+ try {
88
+ const parsed = JSON.parse(setting.value) as string[];
89
+ const sizes = parsed
90
+ .map(Number)
91
+ .filter((n) => !isNaN(n) && n > 0)
92
+ .sort((a, b) => a - b);
93
+ return sizes.length > 0 ? sizes : DEFAULT_PAGE_SIZES;
94
+ } catch {
95
+ return DEFAULT_PAGE_SIZES;
96
+ }
97
+ }, [generalSettings]);
98
+
67
99
  const {
68
100
  items: keys,
69
101
  refetch,
@@ -72,7 +104,10 @@ export function McpTokens() {
72
104
  totalItems,
73
105
  pageSize,
74
106
  setPageSize,
75
- } = usePagination({ url: '/mcp/api-keys' });
107
+ } = usePagination({
108
+ url: '/mcp/api-keys',
109
+ paginationOptions: { pageSizeOptions },
110
+ });
76
111
 
77
112
  const apiUrl = getSettingValue('api-url') as string | null;
78
113
  const mcpUrl = apiUrl ? `${apiUrl.replace(/\/$/, '')}/mcp` : '/mcp';
@@ -202,7 +237,7 @@ export function McpTokens() {
202
237
  setPageSize(newSize);
203
238
  setPage(1);
204
239
  }}
205
- pageSizeOptions={[10]}
240
+ pageSizeOptions={pageSizeOptions}
206
241
  />
207
242
  </CardContent>
208
243
  </Card>
@@ -39,10 +39,10 @@ import {
39
39
  } from '@/components/ui/table';
40
40
  import { ResizableSheetContent } from '@/components/ui/resizable-sheet-content';
41
41
  import { usePagination } from '@/hooks/use-pagination';
42
- import { useApp } from '@hed-hog/next-app-provider';
42
+ import { useApp, useQuery } from '@hed-hog/next-app-provider';
43
43
  import { Check, Copy, KeyRound, Plus, Trash2 } from 'lucide-react';
44
44
  import { useTranslations } from 'next-intl';
45
- import { useState } from 'react';
45
+ import { useMemo, useState } from 'react';
46
46
  import { toast } from 'sonner';
47
47
 
48
48
  type ApiToken = {
@@ -95,6 +95,8 @@ function CodeRow({ label, value }: { label: string; value: string }) {
95
95
  );
96
96
  }
97
97
 
98
+ const DEFAULT_PAGE_SIZES = [6, 12, 24, 48, 96] as const;
99
+
98
100
  export function Tokens() {
99
101
  const { request, getSettingValue } = useApp();
100
102
  const t = useTranslations('core.Tokens');
@@ -105,6 +107,36 @@ export function Tokens() {
105
107
  const [newKeyType, setNewKeyType] = useState<'mcp' | 'api'>('mcp');
106
108
  const [createdToken, setCreatedToken] = useState<string | null>(null);
107
109
  const [isCopied, setIsCopied] = useState(false);
110
+ const { data: generalSettings } = useQuery<{
111
+ data: Array<{ slug: string; value: string }>;
112
+ }>({
113
+ queryKey: ['setting-group-general'],
114
+ queryFn: async () => {
115
+ const response = await request<{
116
+ data: Array<{ slug: string; value: string }>;
117
+ }>({ url: '/setting/group/general', method: 'GET' });
118
+ return response.data;
119
+ },
120
+ staleTime: 5 * 60 * 1000,
121
+ });
122
+
123
+ const pageSizeOptions = useMemo(() => {
124
+ const setting = generalSettings?.data?.find(
125
+ (s) => s.slug === 'pagination-page-sizes'
126
+ );
127
+ if (!setting?.value) return DEFAULT_PAGE_SIZES;
128
+ try {
129
+ const parsed = JSON.parse(setting.value) as string[];
130
+ const sizes = parsed
131
+ .map(Number)
132
+ .filter((n) => !isNaN(n) && n > 0)
133
+ .sort((a, b) => a - b);
134
+ return sizes.length > 0 ? sizes : DEFAULT_PAGE_SIZES;
135
+ } catch {
136
+ return DEFAULT_PAGE_SIZES;
137
+ }
138
+ }, [generalSettings]);
139
+
108
140
  const {
109
141
  items: keys,
110
142
  refetch,
@@ -113,7 +145,10 @@ export function Tokens() {
113
145
  totalItems,
114
146
  pageSize,
115
147
  setPageSize,
116
- } = usePagination({ url: '/mcp/api-keys' });
148
+ } = usePagination({
149
+ url: '/mcp/api-keys',
150
+ paginationOptions: { pageSizeOptions },
151
+ });
117
152
 
118
153
  const apiUrl = (getSettingValue('api-url') as string | null)?.replace(/\/$/, '') ?? '';
119
154
  const mcpUrl = apiUrl ? `${apiUrl}/mcp` : '/mcp';
@@ -239,7 +274,7 @@ export function Tokens() {
239
274
  setPageSize(newSize);
240
275
  setPage(1);
241
276
  }}
242
- pageSizeOptions={[10]}
277
+ pageSizeOptions={pageSizeOptions}
243
278
  />
244
279
  </CardContent>
245
280
  </Card>