@hed-hog/core 0.0.355 → 0.0.358

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 (287) hide show
  1. package/dist/ai/ai.service.d.ts +3 -12
  2. package/dist/ai/ai.service.d.ts.map +1 -1
  3. package/dist/ai/ai.service.js +34 -125
  4. package/dist/ai/ai.service.js.map +1 -1
  5. package/dist/auth/guards/auth.guard.d.ts +6 -1
  6. package/dist/auth/guards/auth.guard.d.ts.map +1 -1
  7. package/dist/auth/guards/auth.guard.js +33 -2
  8. package/dist/auth/guards/auth.guard.js.map +1 -1
  9. package/dist/core.module.d.ts.map +1 -1
  10. package/dist/core.module.js +3 -3
  11. package/dist/core.module.js.map +1 -1
  12. package/dist/file/file.controller.d.ts +4 -2
  13. package/dist/file/file.controller.d.ts.map +1 -1
  14. package/dist/file/file.controller.js +44 -38
  15. package/dist/file/file.controller.js.map +1 -1
  16. package/dist/file/file.service.d.ts +2 -2
  17. package/dist/file/file.service.d.ts.map +1 -1
  18. package/dist/file/file.service.js +58 -89
  19. package/dist/file/file.service.js.map +1 -1
  20. package/dist/file/provider/azure.provider.d.ts.map +1 -1
  21. package/dist/file/provider/azure.provider.js +10 -15
  22. package/dist/file/provider/azure.provider.js.map +1 -1
  23. package/dist/file/provider/gcs.provider.d.ts.map +1 -1
  24. package/dist/file/provider/gcs.provider.js +8 -9
  25. package/dist/file/provider/gcs.provider.js.map +1 -1
  26. package/dist/file/provider/local.provider.d.ts.map +1 -1
  27. package/dist/file/provider/local.provider.js +11 -10
  28. package/dist/file/provider/local.provider.js.map +1 -1
  29. package/dist/file/provider/provider.enum.d.ts +2 -1
  30. package/dist/file/provider/provider.enum.d.ts.map +1 -1
  31. package/dist/file/provider/provider.enum.js +1 -0
  32. package/dist/file/provider/provider.enum.js.map +1 -1
  33. package/dist/file/provider/provider.factory.d.ts +1 -1
  34. package/dist/file/provider/provider.factory.d.ts.map +1 -1
  35. package/dist/file/provider/provider.factory.js +18 -5
  36. package/dist/file/provider/provider.factory.js.map +1 -1
  37. package/dist/file/provider/s3.provider.d.ts.map +1 -1
  38. package/dist/file/provider/s3.provider.js +4 -20
  39. package/dist/file/provider/s3.provider.js.map +1 -1
  40. package/dist/file/provider/spaces.provider.d.ts +27 -0
  41. package/dist/file/provider/spaces.provider.d.ts.map +1 -0
  42. package/dist/file/provider/spaces.provider.js +203 -0
  43. package/dist/file/provider/spaces.provider.js.map +1 -0
  44. package/dist/index.d.ts +4 -3
  45. package/dist/index.d.ts.map +1 -1
  46. package/dist/index.js +4 -3
  47. package/dist/index.js.map +1 -1
  48. package/dist/integration-profile/dto/create.dto.d.ts +9 -0
  49. package/dist/integration-profile/dto/create.dto.d.ts.map +1 -0
  50. package/dist/integration-profile/dto/create.dto.js +54 -0
  51. package/dist/integration-profile/dto/create.dto.js.map +1 -0
  52. package/dist/integration-profile/dto/export.dto.d.ts +5 -0
  53. package/dist/integration-profile/dto/export.dto.d.ts.map +1 -0
  54. package/dist/integration-profile/dto/export.dto.js +29 -0
  55. package/dist/integration-profile/dto/export.dto.js.map +1 -0
  56. package/dist/integration-profile/dto/import-confirm.dto.d.ts +17 -0
  57. package/dist/integration-profile/dto/import-confirm.dto.d.ts.map +1 -0
  58. package/dist/integration-profile/dto/import-confirm.dto.js +77 -0
  59. package/dist/integration-profile/dto/import-confirm.dto.js.map +1 -0
  60. package/dist/integration-profile/dto/update.dto.d.ts.map +1 -0
  61. package/dist/integration-profile/dto/update.dto.js.map +1 -0
  62. package/dist/integration-profile/integration-profile.controller.d.ts +142 -0
  63. package/dist/integration-profile/integration-profile.controller.d.ts.map +1 -0
  64. package/dist/integration-profile/integration-profile.controller.js +166 -0
  65. package/dist/integration-profile/integration-profile.controller.js.map +1 -0
  66. package/dist/integration-profile/integration-profile.module.d.ts +3 -0
  67. package/dist/integration-profile/integration-profile.module.d.ts.map +1 -0
  68. package/dist/{mail-profile/mail-profile.module.js → integration-profile/integration-profile.module.js} +11 -13
  69. package/dist/integration-profile/integration-profile.module.js.map +1 -0
  70. package/dist/integration-profile/integration-profile.service.d.ts +160 -0
  71. package/dist/integration-profile/integration-profile.service.d.ts.map +1 -0
  72. package/dist/integration-profile/integration-profile.service.js +609 -0
  73. package/dist/integration-profile/integration-profile.service.js.map +1 -0
  74. package/dist/integration-profile/integration-profile.utils.d.ts +30 -0
  75. package/dist/integration-profile/integration-profile.utils.d.ts.map +1 -0
  76. package/dist/integration-profile/integration-profile.utils.js +156 -0
  77. package/dist/integration-profile/integration-profile.utils.js.map +1 -0
  78. package/dist/mail/mail.module.d.ts.map +1 -1
  79. package/dist/mail/mail.module.js +36 -23
  80. package/dist/mail/mail.module.js.map +1 -1
  81. package/dist/mail/mail.service.d.ts +4 -2
  82. package/dist/mail/mail.service.d.ts.map +1 -1
  83. package/dist/mail/mail.service.js +33 -51
  84. package/dist/mail/mail.service.js.map +1 -1
  85. package/dist/mcp/guards/mcp-auth.guard.js +1 -1
  86. package/dist/mcp/guards/mcp-auth.guard.js.map +1 -1
  87. package/dist/mcp/mcp-api-key.controller.d.ts +2 -0
  88. package/dist/mcp/mcp-api-key.controller.d.ts.map +1 -1
  89. package/dist/mcp/mcp-api-key.controller.js +1 -1
  90. package/dist/mcp/mcp-api-key.controller.js.map +1 -1
  91. package/dist/mcp/mcp-api-key.service.d.ts +2 -1
  92. package/dist/mcp/mcp-api-key.service.d.ts.map +1 -1
  93. package/dist/mcp/mcp-api-key.service.js +6 -2
  94. package/dist/mcp/mcp-api-key.service.js.map +1 -1
  95. package/dist/mcp/mcp.module.d.ts.map +1 -1
  96. package/dist/mcp/mcp.module.js +3 -5
  97. package/dist/mcp/mcp.module.js.map +1 -1
  98. package/dist/mcp-chat/mcp-chat.service.d.ts.map +1 -1
  99. package/dist/mcp-chat/mcp-chat.service.js +17 -16
  100. package/dist/mcp-chat/mcp-chat.service.js.map +1 -1
  101. package/dist/oauth/interfaces/OAuthProvider.d.ts +1 -1
  102. package/dist/oauth/interfaces/OAuthProvider.d.ts.map +1 -1
  103. package/dist/oauth/oauth.controller.d.ts +4 -1
  104. package/dist/oauth/oauth.controller.d.ts.map +1 -1
  105. package/dist/oauth/oauth.controller.js +31 -5
  106. package/dist/oauth/oauth.controller.js.map +1 -1
  107. package/dist/oauth/oauth.service.d.ts +12 -1
  108. package/dist/oauth/oauth.service.d.ts.map +1 -1
  109. package/dist/oauth/oauth.service.js +125 -23
  110. package/dist/oauth/oauth.service.js.map +1 -1
  111. package/dist/oauth/providers/abstract.provider.d.ts +1 -1
  112. package/dist/oauth/providers/abstract.provider.d.ts.map +1 -1
  113. package/dist/oauth/providers/facebook.provider.d.ts +5 -2
  114. package/dist/oauth/providers/facebook.provider.d.ts.map +1 -1
  115. package/dist/oauth/providers/facebook.provider.js +34 -19
  116. package/dist/oauth/providers/facebook.provider.js.map +1 -1
  117. package/dist/oauth/providers/github.provider.d.ts +6 -2
  118. package/dist/oauth/providers/github.provider.d.ts.map +1 -1
  119. package/dist/oauth/providers/github.provider.js +43 -20
  120. package/dist/oauth/providers/github.provider.js.map +1 -1
  121. package/dist/oauth/providers/google.provider.d.ts +5 -2
  122. package/dist/oauth/providers/google.provider.d.ts.map +1 -1
  123. package/dist/oauth/providers/google.provider.js +34 -19
  124. package/dist/oauth/providers/google.provider.js.map +1 -1
  125. package/dist/oauth/providers/microsoft-entra-id.provider.d.ts +5 -2
  126. package/dist/oauth/providers/microsoft-entra-id.provider.d.ts.map +1 -1
  127. package/dist/oauth/providers/microsoft-entra-id.provider.js +43 -40
  128. package/dist/oauth/providers/microsoft-entra-id.provider.js.map +1 -1
  129. package/dist/oauth/providers/microsoft.provider.d.ts +5 -2
  130. package/dist/oauth/providers/microsoft.provider.d.ts.map +1 -1
  131. package/dist/oauth/providers/microsoft.provider.js +34 -19
  132. package/dist/oauth/providers/microsoft.provider.js.map +1 -1
  133. package/dist/profile/profile.controller.js +1 -1
  134. package/dist/profile/profile.controller.js.map +1 -1
  135. package/dist/security/security.service.d.ts +2 -0
  136. package/dist/security/security.service.d.ts.map +1 -1
  137. package/dist/security/security.service.js +21 -0
  138. package/dist/security/security.service.js.map +1 -1
  139. package/dist/setting/setting.service.d.ts +26 -1
  140. package/dist/setting/setting.service.d.ts.map +1 -1
  141. package/dist/setting/setting.service.js +240 -7
  142. package/dist/setting/setting.service.js.map +1 -1
  143. package/dist/user/user.controller.d.ts +2 -1
  144. package/dist/user/user.controller.d.ts.map +1 -1
  145. package/dist/user/user.controller.js +5 -4
  146. package/dist/user/user.controller.js.map +1 -1
  147. package/dist/user/user.service.d.ts +4 -2
  148. package/dist/user/user.service.d.ts.map +1 -1
  149. package/dist/user/user.service.js +19 -4
  150. package/dist/user/user.service.js.map +1 -1
  151. package/dist/webhook-integration/dto/webhook-action.dto.d.ts +17 -2
  152. package/dist/webhook-integration/dto/webhook-action.dto.d.ts.map +1 -1
  153. package/dist/webhook-integration/dto/webhook-action.dto.js +93 -2
  154. package/dist/webhook-integration/dto/webhook-action.dto.js.map +1 -1
  155. package/dist/webhook-integration/event-webhook.controller.d.ts +1 -0
  156. package/dist/webhook-integration/event-webhook.controller.d.ts.map +1 -1
  157. package/dist/webhook-integration/event-webhook.controller.js +10 -0
  158. package/dist/webhook-integration/event-webhook.controller.js.map +1 -1
  159. package/dist/webhook-integration/event-webhook.service.d.ts +2 -0
  160. package/dist/webhook-integration/event-webhook.service.d.ts.map +1 -1
  161. package/dist/webhook-integration/event-webhook.service.js +30 -0
  162. package/dist/webhook-integration/event-webhook.service.js.map +1 -1
  163. package/dist/webhook-integration/webhook-command.registry.d.ts +15 -0
  164. package/dist/webhook-integration/webhook-command.registry.d.ts.map +1 -0
  165. package/dist/webhook-integration/webhook-command.registry.js +36 -0
  166. package/dist/webhook-integration/webhook-command.registry.js.map +1 -0
  167. package/dist/webhook-integration/webhook-integration.controller.d.ts +20 -0
  168. package/dist/webhook-integration/webhook-integration.controller.d.ts.map +1 -1
  169. package/dist/webhook-integration/webhook-integration.controller.js +48 -0
  170. package/dist/webhook-integration/webhook-integration.controller.js.map +1 -1
  171. package/dist/webhook-integration/webhook-integration.module.d.ts.map +1 -1
  172. package/dist/webhook-integration/webhook-integration.module.js +5 -0
  173. package/dist/webhook-integration/webhook-integration.module.js.map +1 -1
  174. package/dist/webhook-integration/webhook-integration.service.d.ts +27 -2
  175. package/dist/webhook-integration/webhook-integration.service.d.ts.map +1 -1
  176. package/dist/webhook-integration/webhook-integration.service.js +377 -50
  177. package/dist/webhook-integration/webhook-integration.service.js.map +1 -1
  178. package/hedhog/data/file_provider.yaml +9 -1
  179. package/hedhog/data/integration_provider.yaml +148 -0
  180. package/hedhog/data/integration_type.yaml +29 -0
  181. package/hedhog/data/menu.yaml +6 -21
  182. package/hedhog/data/role.yaml +8 -0
  183. package/hedhog/data/route.yaml +73 -373
  184. package/hedhog/data/setting_group.yaml +209 -365
  185. package/hedhog/data/setting_subgroup.yaml +21 -13
  186. package/hedhog/frontend/app/account/components/connected-accounts.tsx.ejs +25 -20
  187. package/hedhog/frontend/app/account/components/tokens.tsx.ejs +421 -0
  188. package/hedhog/frontend/app/account/layout.tsx.ejs +6 -3
  189. package/hedhog/frontend/app/account/mcp-tokens/page.tsx.ejs +2 -2
  190. package/hedhog/frontend/app/account/tokens/page.tsx.ejs +5 -0
  191. package/hedhog/frontend/app/configurations/[slug]/components/setting-field.tsx.ejs +938 -225
  192. package/hedhog/frontend/app/configurations/layout.tsx.ejs +1 -1
  193. package/hedhog/frontend/app/dashboard/dashboard-home-tabs.tsx.ejs +3 -1
  194. package/hedhog/frontend/app/integration/profiles/page.tsx.ejs +1830 -0
  195. package/hedhog/frontend/app/integrations-webhooks/page.tsx.ejs +829 -128
  196. package/hedhog/frontend/app/mail/profiles/page.tsx.ejs +1 -820
  197. package/hedhog/frontend/app/setting-list/page.tsx.ejs +229 -395
  198. package/hedhog/frontend/app/users/permissions.tsx.ejs +79 -2
  199. package/hedhog/frontend/app/users/user-sheet.tsx.ejs +7 -2
  200. package/hedhog/frontend/messages/en.json +239 -3
  201. package/hedhog/frontend/messages/pt.json +239 -3
  202. package/hedhog/table/file.yaml +1 -1
  203. package/hedhog/table/integration_profile.yaml +34 -0
  204. package/hedhog/table/integration_provider.yaml +23 -0
  205. package/hedhog/table/integration_type.yaml +19 -0
  206. package/hedhog/table/mcp_api_key.yaml +4 -0
  207. package/hedhog/table/webhook_action.yaml +141 -85
  208. package/package.json +4 -3
  209. package/src/ai/ai.service.ts +35 -153
  210. package/src/auth/guards/auth.guard.ts +32 -0
  211. package/src/core.module.ts +3 -3
  212. package/src/file/file.controller.ts +51 -42
  213. package/src/file/file.service.ts +67 -104
  214. package/src/file/provider/azure.provider.ts +14 -28
  215. package/src/file/provider/gcs.provider.ts +9 -9
  216. package/src/file/provider/local.provider.ts +10 -13
  217. package/src/file/provider/provider.enum.ts +1 -0
  218. package/src/file/provider/provider.factory.ts +21 -6
  219. package/src/file/provider/s3.provider.ts +4 -20
  220. package/src/file/provider/spaces.provider.ts +246 -0
  221. package/src/index.ts +6 -3
  222. package/src/integration-profile/dto/create.dto.ts +44 -0
  223. package/src/integration-profile/dto/export.dto.ts +15 -0
  224. package/src/integration-profile/dto/import-confirm.dto.ts +61 -0
  225. package/src/integration-profile/integration-profile.controller.ts +131 -0
  226. package/src/integration-profile/integration-profile.module.ts +16 -0
  227. package/src/integration-profile/integration-profile.service.ts +793 -0
  228. package/src/integration-profile/integration-profile.utils.ts +173 -0
  229. package/src/mail/mail.module.ts +41 -22
  230. package/src/mail/mail.service.ts +40 -64
  231. package/src/mcp/guards/mcp-auth.guard.ts +1 -1
  232. package/src/mcp/mcp-api-key.controller.ts +2 -2
  233. package/src/mcp/mcp-api-key.service.ts +6 -2
  234. package/src/mcp/mcp.module.ts +3 -5
  235. package/src/mcp-chat/mcp-chat.service.ts +23 -20
  236. package/src/oauth/interfaces/OAuthProvider.ts +1 -1
  237. package/src/oauth/oauth.controller.ts +30 -2
  238. package/src/oauth/oauth.service.ts +194 -35
  239. package/src/oauth/providers/abstract.provider.ts +1 -1
  240. package/src/oauth/providers/facebook.provider.ts +36 -20
  241. package/src/oauth/providers/github.provider.ts +46 -23
  242. package/src/oauth/providers/google.provider.ts +36 -20
  243. package/src/oauth/providers/microsoft-entra-id.provider.ts +42 -46
  244. package/src/oauth/providers/microsoft.provider.ts +36 -21
  245. package/src/profile/profile.controller.ts +2 -2
  246. package/src/security/security.service.ts +34 -1
  247. package/src/setting/setting.service.ts +307 -9
  248. package/src/user/user.controller.ts +4 -1
  249. package/src/user/user.service.ts +20 -2
  250. package/src/webhook-integration/dto/webhook-action.dto.ts +85 -4
  251. package/src/webhook-integration/event-webhook.controller.ts +55 -50
  252. package/src/webhook-integration/event-webhook.service.ts +422 -384
  253. package/src/webhook-integration/webhook-command.registry.ts +42 -0
  254. package/src/webhook-integration/webhook-integration.controller.ts +25 -0
  255. package/src/webhook-integration/webhook-integration.module.ts +50 -45
  256. package/src/webhook-integration/webhook-integration.service.ts +444 -53
  257. package/dist/mail-profile/dto/create.dto.d.ts +0 -23
  258. package/dist/mail-profile/dto/create.dto.d.ts.map +0 -1
  259. package/dist/mail-profile/dto/create.dto.js +0 -139
  260. package/dist/mail-profile/dto/create.dto.js.map +0 -1
  261. package/dist/mail-profile/dto/update.dto.d.ts.map +0 -1
  262. package/dist/mail-profile/dto/update.dto.js.map +0 -1
  263. package/dist/mail-profile/mail-profile.controller.d.ts +0 -94
  264. package/dist/mail-profile/mail-profile.controller.d.ts.map +0 -1
  265. package/dist/mail-profile/mail-profile.controller.js +0 -95
  266. package/dist/mail-profile/mail-profile.controller.js.map +0 -1
  267. package/dist/mail-profile/mail-profile.module.d.ts +0 -3
  268. package/dist/mail-profile/mail-profile.module.d.ts.map +0 -1
  269. package/dist/mail-profile/mail-profile.module.js.map +0 -1
  270. package/dist/mail-profile/mail-profile.service.d.ts +0 -109
  271. package/dist/mail-profile/mail-profile.service.d.ts.map +0 -1
  272. package/dist/mail-profile/mail-profile.service.js +0 -278
  273. package/dist/mail-profile/mail-profile.service.js.map +0 -1
  274. package/dist/mcp/tools/core-mail-profile.mcp-tools.d.ts +0 -32
  275. package/dist/mcp/tools/core-mail-profile.mcp-tools.d.ts.map +0 -1
  276. package/dist/mcp/tools/core-mail-profile.mcp-tools.js +0 -178
  277. package/dist/mcp/tools/core-mail-profile.mcp-tools.js.map +0 -1
  278. package/hedhog/data/mail_profile.yaml +0 -18
  279. package/hedhog/table/mail_profile.yaml +0 -75
  280. package/src/mail-profile/dto/create.dto.ts +0 -145
  281. package/src/mail-profile/mail-profile.controller.ts +0 -56
  282. package/src/mail-profile/mail-profile.module.ts +0 -18
  283. package/src/mail-profile/mail-profile.service.ts +0 -308
  284. package/src/mcp/tools/core-mail-profile.mcp-tools.ts +0 -128
  285. /package/dist/{mail-profile → integration-profile}/dto/update.dto.d.ts +0 -0
  286. /package/dist/{mail-profile → integration-profile}/dto/update.dto.js +0 -0
  287. /package/src/{mail-profile → integration-profile}/dto/update.dto.ts +0 -0
@@ -74,6 +74,7 @@ import {
74
74
  BookOpenText,
75
75
  ChevronRight,
76
76
  Clock3,
77
+ Copy,
77
78
  GripVertical,
78
79
  Pencil,
79
80
  Plus,
@@ -114,11 +115,16 @@ type EventCatalog = {
114
115
 
115
116
  type IncomingAction = {
116
117
  id: number;
117
- type: 'email' | 'whatsapp_evolution';
118
+ type:
119
+ | 'email'
120
+ | 'whatsapp_evolution'
121
+ | 'http_request'
122
+ | 'internal_api'
123
+ | 'app_command';
118
124
  name: string;
119
125
  order: number;
120
126
  status: Status;
121
- mail_profile_id?: number | null;
127
+ integration_profile_id?: number | null;
122
128
  mail_id?: number | null;
123
129
  email_to?: string | null;
124
130
  email_cc?: string | null;
@@ -129,6 +135,21 @@ type IncomingAction = {
129
135
  whatsapp_instance?: string | null;
130
136
  whatsapp_base_url?: string | null;
131
137
  whatsapp_token?: string | null;
138
+ http_url?: string | null;
139
+ http_method?: string | null;
140
+ http_headers?: string | null;
141
+ http_query?: string | null;
142
+ http_body?: string | null;
143
+ http_timeout_ms?: number | null;
144
+ http_retry_count?: number | null;
145
+ internal_api_path?: string | null;
146
+ internal_api_method?: string | null;
147
+ internal_api_query?: string | null;
148
+ internal_api_body?: string | null;
149
+ internal_api_token?: string | null;
150
+ internal_api_user_id?: number | null;
151
+ app_command_slug?: string | null;
152
+ app_command_params?: string | null;
132
153
  };
133
154
 
134
155
  type IncomingActionForm = {
@@ -136,7 +157,7 @@ type IncomingActionForm = {
136
157
  name: string;
137
158
  order: number;
138
159
  status: Status;
139
- mail_profile_id: number | null;
160
+ integration_profile_id: number | null;
140
161
  mail_id: number | null;
141
162
  email_to: string;
142
163
  email_cc: string;
@@ -147,6 +168,21 @@ type IncomingActionForm = {
147
168
  whatsapp_instance: string;
148
169
  whatsapp_base_url: string;
149
170
  whatsapp_token: string;
171
+ http_url: string;
172
+ http_method: string;
173
+ http_headers: string;
174
+ http_query: string;
175
+ http_body: string;
176
+ http_timeout_ms: number;
177
+ http_retry_count: number;
178
+ internal_api_path: string;
179
+ internal_api_method: string;
180
+ internal_api_query: string;
181
+ internal_api_body: string;
182
+ internal_api_token: string;
183
+ internal_api_user_id: number | null;
184
+ app_command_slug: string;
185
+ app_command_params: string;
150
186
  };
151
187
 
152
188
  type IncomingIntegration = {
@@ -225,22 +261,32 @@ type MailProfileDetail = {
225
261
  id: number;
226
262
  slug: string;
227
263
  name: string;
228
- provider: MailProfileProvider;
229
- from_name?: string | null;
230
- from_email: string;
231
- reply_to_name?: string | null;
232
- reply_to_email?: string | null;
233
- smtp_host?: string | null;
234
- smtp_port?: number | null;
235
- smtp_secure?: boolean;
236
- smtp_username?: string | null;
237
- smtp_password?: string | null;
238
- gmail_client_id?: string | null;
239
- gmail_client_secret?: string | null;
240
- gmail_refresh_token?: string | null;
241
- ses_access_key_id?: string | null;
242
- ses_secret_access_key?: string | null;
243
- ses_region?: string | null;
264
+ type_id: number;
265
+ provider_id: number;
266
+ config?: Record<string, unknown> | null;
267
+ integration_provider?: {
268
+ slug?: string | null;
269
+ };
270
+ };
271
+
272
+ type IntegrationProvider = {
273
+ id: number;
274
+ slug: string;
275
+ type_id: number;
276
+ };
277
+
278
+ const EMAIL_TYPE_SLUG = 'email';
279
+
280
+ const MAIL_PROVIDER_SLUG_BY_LABEL: Record<MailProfileProvider, string> = {
281
+ SMTP: 'smtp',
282
+ GMAIL: 'gmail',
283
+ SES: 'ses',
284
+ };
285
+
286
+ const MAIL_PROVIDER_LABEL_BY_SLUG: Record<string, MailProfileProvider> = {
287
+ smtp: 'SMTP',
288
+ gmail: 'GMAIL',
289
+ ses: 'SES',
244
290
  };
245
291
 
246
292
  type MailTemplateDetail = {
@@ -274,6 +320,51 @@ const defaultMailProfileEditForm = {
274
320
  ses_region: '',
275
321
  };
276
322
 
323
+ function trimString(value: unknown) {
324
+ return String(value ?? '').trim();
325
+ }
326
+
327
+ function buildMailConfigFromForm(
328
+ providerSlug: string,
329
+ form: typeof defaultMailProfileEditForm
330
+ ) {
331
+ if (providerSlug === 'smtp') {
332
+ return {
333
+ host: trimString(form.smtp_host),
334
+ port: Number(trimString(form.smtp_port) || 587),
335
+ username: trimString(form.smtp_username),
336
+ password: trimString(form.smtp_password),
337
+ secure: Boolean(form.smtp_secure),
338
+ from_email: trimString(form.from_email),
339
+ from_name: trimString(form.from_name),
340
+ reply_to_email: trimString(form.reply_to_email),
341
+ reply_to_name: trimString(form.reply_to_name),
342
+ };
343
+ }
344
+
345
+ if (providerSlug === 'gmail') {
346
+ return {
347
+ client_id: trimString(form.gmail_client_id),
348
+ client_secret: trimString(form.gmail_client_secret),
349
+ refresh_token: trimString(form.gmail_refresh_token),
350
+ from_email: trimString(form.from_email),
351
+ from_name: trimString(form.from_name),
352
+ reply_to_email: trimString(form.reply_to_email),
353
+ reply_to_name: trimString(form.reply_to_name),
354
+ };
355
+ }
356
+
357
+ return {
358
+ access_key_id: trimString(form.ses_access_key_id),
359
+ secret_access_key: trimString(form.ses_secret_access_key),
360
+ region: trimString(form.ses_region),
361
+ from_email: trimString(form.from_email),
362
+ from_name: trimString(form.from_name),
363
+ reply_to_email: trimString(form.reply_to_email),
364
+ reply_to_name: trimString(form.reply_to_name),
365
+ };
366
+ }
367
+
277
368
  const defaultMailTemplateEditForm = {
278
369
  slug: '',
279
370
  locale_code: 'en',
@@ -317,7 +408,7 @@ const defaultActionForm: IncomingActionForm = {
317
408
  name: '',
318
409
  order: 0,
319
410
  status: 'active' as Status,
320
- mail_profile_id: null,
411
+ integration_profile_id: null,
321
412
  mail_id: null,
322
413
  email_to: '',
323
414
  email_cc: '',
@@ -328,6 +419,21 @@ const defaultActionForm: IncomingActionForm = {
328
419
  whatsapp_instance: '',
329
420
  whatsapp_base_url: '',
330
421
  whatsapp_token: '',
422
+ http_url: '',
423
+ http_method: 'POST',
424
+ http_headers: '',
425
+ http_query: '',
426
+ http_body: '',
427
+ http_timeout_ms: 30000,
428
+ http_retry_count: 0,
429
+ internal_api_path: '',
430
+ internal_api_method: 'POST',
431
+ internal_api_query: '',
432
+ internal_api_body: '',
433
+ internal_api_token: '',
434
+ internal_api_user_id: null,
435
+ app_command_slug: '',
436
+ app_command_params: '',
331
437
  };
332
438
 
333
439
  const defaultEventWebhookForm = {
@@ -431,6 +537,7 @@ export default function IntegrationsWebhooksPage() {
431
537
  const [incomingForm, setIncomingForm] = useState(defaultIncomingForm);
432
538
  const [incomingSheetTab, setIncomingSheetTab] = useState('settings');
433
539
  const [oneTimeToken, setOneTimeToken] = useState<string | null>(null);
540
+ const [generatedToken, setGeneratedToken] = useState<string | null>(null);
434
541
  const [allowedIpDraft, setAllowedIpDraft] = useState('');
435
542
  const [incomingActions, setIncomingActions] = useState<IncomingAction[]>([]);
436
543
  const [actionSheetOpen, setActionSheetOpen] = useState(false);
@@ -493,17 +600,46 @@ export default function IntegrationsWebhooksPage() {
493
600
  const { data: mailProfiles = [], refetch: refetchMailProfiles } = useQuery<
494
601
  SelectOption[]
495
602
  >({
496
- queryKey: ['webhook-mail-profiles', currentLocaleCode],
603
+ queryKey: ['webhook-integration-profiles', currentLocaleCode],
497
604
  queryFn: async () => {
498
- const response = await request<{ data: SelectOption[] }>({
499
- url: '/mail-profile?pageSize=100',
605
+ const response = await request<{
606
+ data: Array<{
607
+ id: number;
608
+ slug: string;
609
+ name: string;
610
+ integration_provider?: { slug?: string | null };
611
+ }>;
612
+ }>({
613
+ url: '/integration-profile?pageSize=100&typeSlug=email',
500
614
  method: 'GET',
501
615
  });
502
- return response.data.data || [];
616
+ return (response.data.data || []).map((item) => ({
617
+ id: item.id,
618
+ slug: item.slug,
619
+ name: item.name,
620
+ provider: String(item.integration_provider?.slug ?? ''),
621
+ }));
503
622
  },
504
623
  placeholderData: (previous) => previous ?? [],
505
624
  });
506
625
 
626
+ const resolveEmailProviderMeta = async (providerSlug: string) => {
627
+ const response = await request<IntegrationProvider[]>({
628
+ url: `/integration-profile/providers?typeSlug=${EMAIL_TYPE_SLUG}`,
629
+ method: 'GET',
630
+ });
631
+
632
+ const provider = (response.data ?? []).find(
633
+ (item) => item.slug === providerSlug
634
+ );
635
+
636
+ if (!provider) {
637
+ throw new Error(`Integration provider "${providerSlug}" not found.`);
638
+ }
639
+
640
+ return provider;
641
+ };
642
+
507
643
  const { data: mailTemplates = [], refetch: refetchMailTemplates } = useQuery<
508
644
  SelectOption[]
509
645
  >({
@@ -518,6 +654,56 @@ export default function IntegrationsWebhooksPage() {
518
654
  placeholderData: (previous) => previous ?? [],
519
655
  });
520
656
 
657
+ const { data: appCommands = [] } = useQuery<
658
+ Array<{
659
+ slug: string;
660
+ name: string;
661
+ description: string;
662
+ inputSchema: Record<string, unknown>;
663
+ }>
664
+ >({
665
+ queryKey: ['webhook-app-commands'],
666
+ queryFn: async () => {
667
+ const response = await request<
668
+ Array<{
669
+ slug: string;
670
+ name: string;
671
+ description: string;
672
+ inputSchema: Record<string, unknown>;
673
+ }>
674
+ >({
675
+ url: '/webhook-integration/app-commands',
676
+ method: 'GET',
677
+ });
678
+ return response.data || [];
679
+ },
680
+ placeholderData: (previous) => previous ?? [],
681
+ });
682
+
683
+ const { data: internalRoutes = [] } = useQuery<
684
+ Array<{
685
+ id: number;
686
+ url: string;
687
+ method: string;
688
+ }>
689
+ >({
690
+ queryKey: ['webhook-internal-routes'],
691
+ queryFn: async () => {
692
+ const response = await request<
693
+ Array<{
694
+ id: number;
695
+ url: string;
696
+ method: string;
697
+ }>
698
+ >({
699
+ url: '/webhook-integration/internal-routes',
700
+ method: 'GET',
701
+ });
702
+ return response.data || [];
703
+ },
704
+ placeholderData: (previous) => previous ?? [],
705
+ });
706
+
521
707
  const { data: incomingLogsResult, isFetching: isFetchingIncomingLogs } =
522
708
  useQuery<PaginatedResponse<IncomingCallLog>>({
523
709
  queryKey: [
@@ -765,6 +951,7 @@ export default function IntegrationsWebhooksPage() {
765
951
 
766
952
  const openActionCreate = () => {
767
953
  setActionEdit(null);
954
+ setGeneratedToken(null);
768
955
  setActionForm({
769
956
  ...defaultActionForm,
770
957
  order: incomingActions.length,
@@ -774,12 +961,13 @@ export default function IntegrationsWebhooksPage() {
774
961
 
775
962
  const openActionEdit = (action: IncomingAction) => {
776
963
  setActionEdit(action);
964
+ setGeneratedToken(null);
777
965
  setActionForm({
778
966
  type: action.type,
779
967
  name: action.name,
780
968
  order: Number(action.order || 0),
781
969
  status: action.status,
782
- mail_profile_id: action.mail_profile_id ?? null,
970
+ integration_profile_id: action.integration_profile_id ?? null,
783
971
  mail_id: action.mail_id ?? null,
784
972
  email_to: action.email_to || '',
785
973
  email_cc: action.email_cc || '',
@@ -790,6 +978,31 @@ export default function IntegrationsWebhooksPage() {
790
978
  whatsapp_instance: action.whatsapp_instance || '',
791
979
  whatsapp_base_url: action.whatsapp_base_url || '',
792
980
  whatsapp_token: action.whatsapp_token || '',
981
+ http_url: action.http_url || '',
982
+ http_method: action.http_method || 'POST',
983
+ http_headers: action.http_headers
984
+ ? JSON.stringify(action.http_headers, null, 2)
985
+ : '',
986
+ http_query: action.http_query
987
+ ? JSON.stringify(action.http_query, null, 2)
988
+ : '',
989
+ http_body: action.http_body || '',
990
+ http_timeout_ms: action.http_timeout_ms ?? 30000,
991
+ http_retry_count: action.http_retry_count ?? 0,
992
+ internal_api_path: action.internal_api_path || '',
993
+ internal_api_method: action.internal_api_method || 'POST',
994
+ internal_api_query: action.internal_api_query
995
+ ? JSON.stringify(action.internal_api_query, null, 2)
996
+ : '',
997
+ internal_api_body: action.internal_api_body
998
+ ? JSON.stringify(action.internal_api_body, null, 2)
999
+ : '',
1000
+ internal_api_token: action.internal_api_token || '',
1001
+ internal_api_user_id: action.internal_api_user_id ?? null,
1002
+ app_command_slug: action.app_command_slug || '',
1003
+ app_command_params: action.app_command_params
1004
+ ? JSON.stringify(action.app_command_params, null, 2)
1005
+ : '',
793
1006
  });
794
1007
  setActionSheetOpen(true);
795
1008
  };
@@ -797,31 +1010,33 @@ export default function IntegrationsWebhooksPage() {
797
1010
  const openMailProfileEditor = async (id: number) => {
798
1011
  try {
799
1012
  const response = await request<MailProfileDetail>({
800
- url: `/mail-profile/${id}`,
1013
+ url: `/integration-profile/${id}`,
801
1014
  method: 'GET',
802
1015
  });
803
1016
 
804
1017
  const data = response.data;
1018
+ const config = (data.config as Record<string, unknown> | null) ?? {};
1019
+ const providerSlug = String(data.integration_provider?.slug ?? 'smtp');
805
1020
  setMailProfileEditId(data.id);
806
1021
  setMailProfileEditForm({
807
1022
  slug: data.slug || '',
808
1023
  name: data.name || '',
809
- provider: data.provider || 'SMTP',
810
- from_name: data.from_name || '',
811
- from_email: data.from_email || '',
812
- reply_to_name: data.reply_to_name || '',
813
- reply_to_email: data.reply_to_email || '',
814
- smtp_host: data.smtp_host || '',
815
- smtp_port: data.smtp_port ? String(data.smtp_port) : '587',
816
- smtp_secure: Boolean(data.smtp_secure),
817
- smtp_username: data.smtp_username || '',
818
- smtp_password: data.smtp_password || '',
819
- gmail_client_id: data.gmail_client_id || '',
820
- gmail_client_secret: data.gmail_client_secret || '',
821
- gmail_refresh_token: data.gmail_refresh_token || '',
822
- ses_access_key_id: data.ses_access_key_id || '',
823
- ses_secret_access_key: data.ses_secret_access_key || '',
824
- ses_region: data.ses_region || '',
1024
+ provider: MAIL_PROVIDER_LABEL_BY_SLUG[providerSlug] || 'SMTP',
1025
+ from_name: String(config.from_name ?? ''),
1026
+ from_email: String(config.from_email ?? ''),
1027
+ reply_to_name: String(config.reply_to_name ?? ''),
1028
+ reply_to_email: String(config.reply_to_email ?? ''),
1029
+ smtp_host: String(config.host ?? ''),
1030
+ smtp_port: String(config.port ?? '587'),
1031
+ smtp_secure: Boolean(config.secure),
1032
+ smtp_username: String(config.username ?? ''),
1033
+ smtp_password: String(config.password ?? ''),
1034
+ gmail_client_id: String(config.client_id ?? ''),
1035
+ gmail_client_secret: String(config.client_secret ?? ''),
1036
+ gmail_refresh_token: String(config.refresh_token ?? ''),
1037
+ ses_access_key_id: String(config.access_key_id ?? ''),
1038
+ ses_secret_access_key: String(config.secret_access_key ?? ''),
1039
+ ses_region: String(config.region ?? ''),
825
1040
  });
826
1041
  setMailProfileTestedSignature(null);
827
1042
  setMailProfileEditorOpen(true);
@@ -830,57 +1045,51 @@ export default function IntegrationsWebhooksPage() {
830
1045
  }
831
1046
  };
832
1047
 
833
- const createMailProfilePayload = () => ({
834
- slug: mailProfileEditForm.slug,
835
- name: mailProfileEditForm.name,
836
- provider: mailProfileEditForm.provider,
837
- from_name: mailProfileEditForm.from_name || undefined,
838
- from_email: mailProfileEditForm.from_email,
839
- reply_to_name: mailProfileEditForm.reply_to_name || undefined,
840
- reply_to_email: mailProfileEditForm.reply_to_email || undefined,
841
- smtp_host: mailProfileEditForm.smtp_host || undefined,
842
- smtp_port: mailProfileEditForm.smtp_port
843
- ? Number(mailProfileEditForm.smtp_port)
844
- : undefined,
845
- smtp_secure: mailProfileEditForm.smtp_secure,
846
- smtp_username: mailProfileEditForm.smtp_username || undefined,
847
- smtp_password: mailProfileEditForm.smtp_password || undefined,
848
- gmail_client_id: mailProfileEditForm.gmail_client_id || undefined,
849
- gmail_client_secret: mailProfileEditForm.gmail_client_secret || undefined,
850
- gmail_refresh_token: mailProfileEditForm.gmail_refresh_token || undefined,
851
- ses_access_key_id: mailProfileEditForm.ses_access_key_id || undefined,
852
- ses_secret_access_key:
853
- mailProfileEditForm.ses_secret_access_key || undefined,
854
- ses_region: mailProfileEditForm.ses_region || undefined,
855
- });
1048
+ const createMailProfilePayload = async () => {
1049
+ const providerSlug =
1050
+ MAIL_PROVIDER_SLUG_BY_LABEL[mailProfileEditForm.provider] ?? 'smtp';
1051
+ const provider = await resolveEmailProviderMeta(providerSlug);
1052
+
1053
+ return {
1054
+ slug: trimString(mailProfileEditForm.slug),
1055
+ name: trimString(mailProfileEditForm.name),
1056
+ type_id: provider.type_id,
1057
+ provider_id: provider.id,
1058
+ config: buildMailConfigFromForm(providerSlug, mailProfileEditForm),
1059
+ is_active: true,
1060
+ };
1061
+ };
856
1062
 
857
- const currentMailProfileSignature = JSON.stringify(
858
- createMailProfilePayload()
859
- );
1063
+ const currentMailProfileSignature = JSON.stringify(mailProfileEditForm);
860
1064
  const canSubmitMailProfile =
861
1065
  mailProfileTestedSignature === currentMailProfileSignature;
862
1066
 
863
1067
  const handleTestMailProfile = async () => {
864
- const payload = createMailProfilePayload();
1068
+ const payload = await createMailProfilePayload();
865
1069
 
866
1070
  try {
867
1071
  setMailProfileIsTesting(true);
868
1072
  const { data } = await request<{ success: boolean; destination: string }>(
869
1073
  {
870
- url: '/mail-profile/test',
1074
+ url: '/integration-profile/test',
871
1075
  method: 'POST',
872
1076
  data: payload,
873
1077
  }
874
1078
  );
875
1079
 
876
- setMailProfileTestedSignature(JSON.stringify(payload));
1080
+ const fallbackFromEmail =
1081
+ payload.config && typeof payload.config === 'object'
1082
+ ? String((payload.config as Record<string, unknown>).from_email ?? '')
1083
+ : '';
1084
+
1085
+ setMailProfileTestedSignature(currentMailProfileSignature);
877
1086
  toast.success(
878
- data.destination || payload.from_email
879
- ? `Perfil testado com sucesso para ${data.destination || payload.from_email}`
1087
+ data.destination || fallbackFromEmail
1088
+ ? `Perfil testado com sucesso para ${data.destination || fallbackFromEmail}`
880
1089
  : 'Perfil testado com sucesso.'
881
1090
  );
882
1091
  } catch (error) {
883
- console.error('Error testing mail profile:', error);
1092
+ console.error('Error testing integration profile:', error);
884
1093
  setMailProfileTestedSignature(null);
885
1094
  toast.error('Erro ao testar o perfil de e-mail.');
886
1095
  } finally {
@@ -890,36 +1099,13 @@ export default function IntegrationsWebhooksPage() {
890
1099
 
891
1100
  const saveMailProfileEditor = async () => {
892
1101
  if (!mailProfileEditId) return;
1102
+ const payload = await createMailProfilePayload();
893
1103
 
894
1104
  try {
895
1105
  await request({
896
- url: `/mail-profile/${mailProfileEditId}`,
1106
+ url: `/integration-profile/${mailProfileEditId}`,
897
1107
  method: 'PATCH',
898
- data: {
899
- slug: mailProfileEditForm.slug,
900
- name: mailProfileEditForm.name,
901
- provider: mailProfileEditForm.provider,
902
- from_name: mailProfileEditForm.from_name || undefined,
903
- from_email: mailProfileEditForm.from_email,
904
- reply_to_name: mailProfileEditForm.reply_to_name || undefined,
905
- reply_to_email: mailProfileEditForm.reply_to_email || undefined,
906
- smtp_host: mailProfileEditForm.smtp_host || undefined,
907
- smtp_port: mailProfileEditForm.smtp_port
908
- ? Number(mailProfileEditForm.smtp_port)
909
- : undefined,
910
- smtp_secure: mailProfileEditForm.smtp_secure,
911
- smtp_username: mailProfileEditForm.smtp_username || undefined,
912
- smtp_password: mailProfileEditForm.smtp_password || undefined,
913
- gmail_client_id: mailProfileEditForm.gmail_client_id || undefined,
914
- gmail_client_secret:
915
- mailProfileEditForm.gmail_client_secret || undefined,
916
- gmail_refresh_token:
917
- mailProfileEditForm.gmail_refresh_token || undefined,
918
- ses_access_key_id: mailProfileEditForm.ses_access_key_id || undefined,
919
- ses_secret_access_key:
920
- mailProfileEditForm.ses_secret_access_key || undefined,
921
- ses_region: mailProfileEditForm.ses_region || undefined,
922
- },
1108
+ data: payload,
923
1109
  });
924
1110
 
925
1111
  await refetchMailProfiles();
@@ -1076,8 +1262,8 @@ export default function IntegrationsWebhooksPage() {
1076
1262
  const missingFields: string[] = [];
1077
1263
 
1078
1264
  if (actionForm.type === 'email') {
1079
- if (actionForm.mail_profile_id == null)
1080
- missingFields.push('mail_profile_id');
1265
+ if (actionForm.integration_profile_id == null)
1266
+ missingFields.push('integration_profile_id');
1081
1267
  if (actionForm.mail_id == null) missingFields.push('mail_id');
1082
1268
  if (!actionForm.email_to.trim()) missingFields.push('email_to');
1083
1269
  }
@@ -1100,6 +1286,24 @@ export default function IntegrationsWebhooksPage() {
1100
1286
  }
1101
1287
  }
1102
1288
 
1289
+ if (actionForm.type === 'http_request') {
1290
+ if (!actionForm.http_url.trim()) missingFields.push('http_url');
1291
+ }
1292
+
1293
+ if (actionForm.type === 'internal_api') {
1294
+ if (!actionForm.internal_api_path.trim())
1295
+ missingFields.push('internal_api_path');
1296
+ if (actionForm.internal_api_user_id == null)
1297
+ missingFields.push('internal_api_user_id');
1298
+ if (!actionForm.internal_api_token.trim())
1299
+ missingFields.push('internal_api_token');
1300
+ }
1301
+
1302
+ if (actionForm.type === 'app_command') {
1303
+ if (!actionForm.app_command_slug.trim())
1304
+ missingFields.push('app_command_slug');
1305
+ }
1306
+
1103
1307
  if (missingFields.length) {
1104
1308
  toast.error(
1105
1309
  `Preencha os campos obrigatorios da acao: ${missingFields.join(', ')}`
@@ -1111,7 +1315,7 @@ export default function IntegrationsWebhooksPage() {
1111
1315
  const payload = {
1112
1316
  ...actionForm,
1113
1317
  order: Number(actionForm.order || 0),
1114
- mail_profile_id: actionForm.mail_profile_id,
1318
+ integration_profile_id: actionForm.integration_profile_id,
1115
1319
  mail_id: actionForm.mail_id,
1116
1320
  email_to: actionForm.email_to.trim(),
1117
1321
  email_cc: actionForm.email_cc.trim(),
@@ -1121,6 +1325,61 @@ export default function IntegrationsWebhooksPage() {
1121
1325
  whatsapp_instance: actionForm.whatsapp_instance.trim(),
1122
1326
  whatsapp_base_url: actionForm.whatsapp_base_url.trim(),
1123
1327
  whatsapp_token: actionForm.whatsapp_token.trim(),
1328
+ http_url: actionForm.http_url.trim() || undefined,
1329
+ http_method: actionForm.http_method || 'POST',
1330
+ http_headers: actionForm.http_headers.trim()
1331
+ ? (() => {
1332
+ try {
1333
+ return JSON.parse(actionForm.http_headers);
1334
+ } catch {
1335
+ return undefined;
1336
+ }
1337
+ })()
1338
+ : undefined,
1339
+ http_query: actionForm.http_query.trim()
1340
+ ? (() => {
1341
+ try {
1342
+ return JSON.parse(actionForm.http_query);
1343
+ } catch {
1344
+ return undefined;
1345
+ }
1346
+ })()
1347
+ : undefined,
1348
+ http_body: actionForm.http_body.trim() || undefined,
1349
+ http_timeout_ms: actionForm.http_timeout_ms || undefined,
1350
+ http_retry_count: actionForm.http_retry_count ?? 0,
1351
+ internal_api_path: actionForm.internal_api_path.trim() || undefined,
1352
+ internal_api_method: actionForm.internal_api_method || 'POST',
1353
+ internal_api_query: actionForm.internal_api_query.trim()
1354
+ ? (() => {
1355
+ try {
1356
+ return JSON.parse(actionForm.internal_api_query);
1357
+ } catch {
1358
+ return undefined;
1359
+ }
1360
+ })()
1361
+ : undefined,
1362
+ internal_api_body: actionForm.internal_api_body.trim()
1363
+ ? (() => {
1364
+ try {
1365
+ return JSON.parse(actionForm.internal_api_body);
1366
+ } catch {
1367
+ return undefined;
1368
+ }
1369
+ })()
1370
+ : undefined,
1371
+ internal_api_token: actionForm.internal_api_token.trim() || undefined,
1372
+ internal_api_user_id: actionForm.internal_api_user_id ?? undefined,
1373
+ app_command_slug: actionForm.app_command_slug.trim() || undefined,
1374
+ app_command_params: actionForm.app_command_params.trim()
1375
+ ? (() => {
1376
+ try {
1377
+ return JSON.parse(actionForm.app_command_params);
1378
+ } catch {
1379
+ return undefined;
1380
+ }
1381
+ })()
1382
+ : undefined,
1124
1383
  };
1125
1384
 
1126
1385
  if (actionEdit) {
@@ -1141,6 +1400,7 @@ export default function IntegrationsWebhooksPage() {
1141
1400
 
1142
1401
  setActionEdit(null);
1143
1402
  setActionSheetOpen(false);
1403
+ setGeneratedToken(null);
1144
1404
  setActionForm(defaultActionForm);
1145
1405
  await openIncomingEdit(incomingEdit);
1146
1406
  await incoming.refetch();
@@ -1221,6 +1481,16 @@ export default function IntegrationsWebhooksPage() {
1221
1481
  await incoming.refetch();
1222
1482
  };
1223
1483
 
1484
+ const duplicateIncoming = async (item: IncomingIntegration) => {
1485
+ const response = await request<IncomingIntegration>({
1486
+ url: `/webhook-integration/${item.id}/duplicate`,
1487
+ method: 'POST',
1488
+ });
1489
+ toast.success(t('duplicated'));
1490
+ await incoming.refetch();
1491
+ await openIncomingEdit(response.data);
1492
+ };
1493
+
1224
1494
  const openEventWebhookCreate = () => {
1225
1495
  setEventWebhookEdit(null);
1226
1496
  setEventWebhookForm(defaultEventWebhookForm);
@@ -1255,6 +1525,16 @@ export default function IntegrationsWebhooksPage() {
1255
1525
  setEventWebhookOpen(true);
1256
1526
  };
1257
1527
 
1528
+ const duplicateEventWebhook = async (item: EventWebhook) => {
1529
+ const response = await request<EventWebhook>({
1530
+ url: `/event-webhook/${item.id}/duplicate`,
1531
+ method: 'POST',
1532
+ });
1533
+ toast.success(t('duplicated'));
1534
+ await eventWebhooks.refetch();
1535
+ await openEventWebhookEdit(response.data);
1536
+ };
1537
+
1258
1538
  const saveEventWebhook = async () => {
1259
1539
  try {
1260
1540
  const payload = {
@@ -1563,6 +1843,13 @@ export default function IntegrationsWebhooksPage() {
1563
1843
  >
1564
1844
  <Pencil className="h-4 w-4" />
1565
1845
  </Button>
1846
+ <Button
1847
+ variant="ghost"
1848
+ size="icon"
1849
+ onClick={() => duplicateIncoming(item)}
1850
+ >
1851
+ <Copy className="h-4 w-4" />
1852
+ </Button>
1566
1853
  <Button
1567
1854
  variant="ghost"
1568
1855
  size="icon"
@@ -1672,6 +1959,13 @@ export default function IntegrationsWebhooksPage() {
1672
1959
  >
1673
1960
  <Pencil className="h-4 w-4" />
1674
1961
  </Button>
1962
+ <Button
1963
+ variant="ghost"
1964
+ size="icon"
1965
+ onClick={() => duplicateEventWebhook(item)}
1966
+ >
1967
+ <Copy className="h-4 w-4" />
1968
+ </Button>
1675
1969
  <Button
1676
1970
  variant="ghost"
1677
1971
  size="icon"
@@ -1707,7 +2001,10 @@ export default function IntegrationsWebhooksPage() {
1707
2001
  </Tabs>
1708
2002
 
1709
2003
  <Sheet open={catalogOpen} onOpenChange={setCatalogOpen}>
1710
- <ResizableSheetContent sheetId="webhooks-catalog-form" defaultWidth={672}>
2004
+ <ResizableSheetContent
2005
+ sheetId="webhooks-catalog-form"
2006
+ defaultWidth={672}
2007
+ >
1711
2008
  <SheetHeader>
1712
2009
  <SheetTitle>
1713
2010
  {catalogEdit ? t('editEvent') : t('newEvent')}
@@ -1782,7 +2079,10 @@ export default function IntegrationsWebhooksPage() {
1782
2079
  }
1783
2080
  }}
1784
2081
  >
1785
- <ResizableSheetContent sheetId="webhooks-incoming-form" defaultWidth={1024}>
2082
+ <ResizableSheetContent
2083
+ sheetId="webhooks-incoming-form"
2084
+ defaultWidth={1024}
2085
+ >
1786
2086
  <SheetHeader>
1787
2087
  <SheetTitle>
1788
2088
  {incomingEdit ? t('editIncoming') : t('newIncoming')}
@@ -2268,11 +2568,15 @@ export default function IntegrationsWebhooksPage() {
2268
2568
  setActionSheetOpen(open);
2269
2569
  if (!open) {
2270
2570
  setActionEdit(null);
2571
+ setGeneratedToken(null);
2271
2572
  setActionForm(defaultActionForm);
2272
2573
  }
2273
2574
  }}
2274
2575
  >
2275
- <ResizableSheetContent sheetId="webhooks-action-form" defaultWidth={768}>
2576
+ <ResizableSheetContent
2577
+ sheetId="webhooks-action-form"
2578
+ defaultWidth={768}
2579
+ >
2276
2580
  <SheetHeader>
2277
2581
  <SheetTitle>
2278
2582
  {actionEdit ? t('updated') : t('addAction')}
@@ -2296,6 +2600,13 @@ export default function IntegrationsWebhooksPage() {
2296
2600
  <SelectItem value="whatsapp_evolution">
2297
2601
  {t('whatsapp')}
2298
2602
  </SelectItem>
2603
+ <SelectItem value="http_request">
2604
+ HTTP Request
2605
+ </SelectItem>
2606
+ <SelectItem value="internal_api">
2607
+ Internal API
2608
+ </SelectItem>
2609
+ <SelectItem value="app_command">App Command</SelectItem>
2299
2610
  </SelectContent>
2300
2611
  </Select>
2301
2612
  </Field>
@@ -2324,12 +2635,12 @@ export default function IntegrationsWebhooksPage() {
2324
2635
  </Field>
2325
2636
  </div>
2326
2637
 
2327
- {actionForm.type === 'email' ? (
2638
+ {actionForm.type === 'email' && (
2328
2639
  <div className="grid gap-3 md:grid-cols-2">
2329
2640
  <Field label={t('mailProfile')}>
2330
2641
  <div className="flex items-start gap-2">
2331
2642
  <EntityPicker<SelectOption>
2332
- value={actionForm.mail_profile_id}
2643
+ value={actionForm.integration_profile_id}
2333
2644
  className="w-full"
2334
2645
  valueType="number"
2335
2646
  placeholder={t('select')}
@@ -2337,14 +2648,28 @@ export default function IntegrationsWebhooksPage() {
2337
2648
  options={mailProfiles}
2338
2649
  loadOptions={async ({ page, pageSize, search }) => {
2339
2650
  const response = await request<{
2340
- data: SelectOption[];
2651
+ data: Array<{
2652
+ id: number;
2653
+ slug: string;
2654
+ name: string;
2655
+ integration_provider?: { slug?: string | null };
2656
+ }>;
2341
2657
  }>({
2342
- url: `/mail-profile?page=${page}&pageSize=${pageSize}&search=${encodeURIComponent(search)}`,
2658
+ url: `/integration-profile?page=${page}&pageSize=${pageSize}&typeSlug=email&search=${encodeURIComponent(search)}`,
2343
2659
  method: 'GET',
2344
2660
  });
2345
2661
 
2346
2662
  return {
2347
- items: response.data?.data || [],
2663
+ items: (response.data?.data || []).map(
2664
+ (item) => ({
2665
+ id: item.id,
2666
+ slug: item.slug,
2667
+ name: item.name,
2668
+ provider: String(
2669
+ item.integration_provider?.slug ?? ''
2670
+ ),
2671
+ })
2672
+ ),
2348
2673
  hasMore: false,
2349
2674
  };
2350
2675
  }}
@@ -2399,19 +2724,25 @@ export default function IntegrationsWebhooksPage() {
2399
2724
  createTitle="Criar perfil de e-mail"
2400
2725
  createDescription="Crie rapidamente um perfil SMTP para usar nesta ação."
2401
2726
  onCreate={async (values) => {
2727
+ const provider =
2728
+ await resolveEmailProviderMeta('smtp');
2402
2729
  const response = await request<SelectOption>({
2403
- url: '/mail-profile',
2730
+ url: '/integration-profile',
2404
2731
  method: 'POST',
2405
2732
  data: {
2406
2733
  slug: values.slug,
2407
2734
  name: values.name,
2408
- provider: 'SMTP',
2409
- from_email: values.from_email,
2410
- smtp_host: values.smtp_host,
2411
- smtp_port: Number(values.smtp_port || 587),
2412
- smtp_secure: false,
2413
- smtp_username: values.smtp_username,
2414
- smtp_password: values.smtp_password,
2735
+ type_id: provider.type_id,
2736
+ provider_id: provider.id,
2737
+ config: {
2738
+ from_email: values.from_email,
2739
+ host: values.smtp_host,
2740
+ port: Number(values.smtp_port || 587),
2741
+ secure: false,
2742
+ username: values.smtp_username,
2743
+ password: values.smtp_password,
2744
+ },
2745
+ is_active: true,
2415
2746
  },
2416
2747
  });
2417
2748
 
@@ -2427,7 +2758,7 @@ export default function IntegrationsWebhooksPage() {
2427
2758
  onChange={(value) =>
2428
2759
  setActionForm((current) => ({
2429
2760
  ...current,
2430
- mail_profile_id:
2761
+ integration_profile_id:
2431
2762
  typeof value === 'number'
2432
2763
  ? value
2433
2764
  : value != null && value !== ''
@@ -2442,13 +2773,13 @@ export default function IntegrationsWebhooksPage() {
2442
2773
  variant="outline"
2443
2774
  size="icon"
2444
2775
  className="h-10 w-10 shrink-0"
2445
- disabled={!actionForm.mail_profile_id}
2776
+ disabled={!actionForm.integration_profile_id}
2446
2777
  aria-label="Editar perfil de e-mail selecionado"
2447
2778
  title="Editar perfil de e-mail selecionado"
2448
2779
  onClick={() => {
2449
- if (actionForm.mail_profile_id) {
2780
+ if (actionForm.integration_profile_id) {
2450
2781
  void openMailProfileEditor(
2451
- actionForm.mail_profile_id
2782
+ actionForm.integration_profile_id
2452
2783
  );
2453
2784
  }
2454
2785
  }}
@@ -2568,7 +2899,9 @@ export default function IntegrationsWebhooksPage() {
2568
2899
  />
2569
2900
  </Field>
2570
2901
  </div>
2571
- ) : (
2902
+ )}
2903
+
2904
+ {actionForm.type === 'whatsapp_evolution' && (
2572
2905
  <div className="grid gap-3 md:grid-cols-2">
2573
2906
  <Field label={t('whatsappTargetType')}>
2574
2907
  <Select
@@ -2650,6 +2983,357 @@ export default function IntegrationsWebhooksPage() {
2650
2983
  </div>
2651
2984
  )}
2652
2985
 
2986
+ {actionForm.type === 'http_request' && (
2987
+ <div className="grid gap-3 md:grid-cols-2">
2988
+ <Field label="Método HTTP">
2989
+ <Select
2990
+ value={actionForm.http_method}
2991
+ onValueChange={(value) =>
2992
+ setActionForm({ ...actionForm, http_method: value })
2993
+ }
2994
+ >
2995
+ <SelectTrigger className="w-full">
2996
+ <SelectValue />
2997
+ </SelectTrigger>
2998
+ <SelectContent>
2999
+ {['GET', 'POST', 'PUT', 'PATCH', 'DELETE'].map(
3000
+ (m) => (
3001
+ <SelectItem key={m} value={m}>
3002
+ {m}
3003
+ </SelectItem>
3004
+ )
3005
+ )}
3006
+ </SelectContent>
3007
+ </Select>
3008
+ </Field>
3009
+ <Field label="URL *">
3010
+ <Input
3011
+ value={actionForm.http_url}
3012
+ onChange={(event) =>
3013
+ setActionForm({
3014
+ ...actionForm,
3015
+ http_url: event.target.value,
3016
+ })
3017
+ }
3018
+ placeholder="https://example.com/api/{{endpoint}}"
3019
+ />
3020
+ </Field>
3021
+ <Field label="Timeout (ms)">
3022
+ <Input
3023
+ type="number"
3024
+ value={actionForm.http_timeout_ms}
3025
+ onChange={(event) =>
3026
+ setActionForm({
3027
+ ...actionForm,
3028
+ http_timeout_ms: Number(event.target.value),
3029
+ })
3030
+ }
3031
+ placeholder="30000"
3032
+ />
3033
+ </Field>
3034
+ <Field label="Tentativas extras (retry)">
3035
+ <Input
3036
+ type="number"
3037
+ value={actionForm.http_retry_count}
3038
+ onChange={(event) =>
3039
+ setActionForm({
3040
+ ...actionForm,
3041
+ http_retry_count: Number(event.target.value),
3042
+ })
3043
+ }
3044
+ placeholder="0"
3045
+ />
3046
+ </Field>
3047
+ <Field label="Headers (JSON)">
3048
+ <Textarea
3049
+ value={actionForm.http_headers}
3050
+ onChange={(event) =>
3051
+ setActionForm({
3052
+ ...actionForm,
3053
+ http_headers: event.target.value,
3054
+ })
3055
+ }
3056
+ className="font-mono text-xs"
3057
+ rows={3}
3058
+ placeholder='{"Authorization": "Bearer {{token}}"}'
3059
+ />
3060
+ </Field>
3061
+ <Field label="Query Params (JSON)">
3062
+ <Textarea
3063
+ value={actionForm.http_query}
3064
+ onChange={(event) =>
3065
+ setActionForm({
3066
+ ...actionForm,
3067
+ http_query: event.target.value,
3068
+ })
3069
+ }
3070
+ className="font-mono text-xs"
3071
+ rows={3}
3072
+ placeholder='{"search": "{{query}}"}'
3073
+ />
3074
+ </Field>
3075
+ <div className="md:col-span-2">
3076
+ <Field label="Body">
3077
+ <Textarea
3078
+ value={actionForm.http_body}
3079
+ onChange={(event) =>
3080
+ setActionForm({
3081
+ ...actionForm,
3082
+ http_body: event.target.value,
3083
+ })
3084
+ }
3085
+ className="font-mono text-xs"
3086
+ rows={5}
3087
+ placeholder='{"userId": "{{userId}}", "event": "{{type}}"}'
3088
+ />
3089
+ </Field>
3090
+ </div>
3091
+ </div>
3092
+ )}
3093
+
3094
+ {actionForm.type === 'internal_api' && (
3095
+ <div className="grid gap-3 md:grid-cols-2">
3096
+ <Field label="Usuário (ID) *">
3097
+ <Input
3098
+ type="number"
3099
+ value={actionForm.internal_api_user_id ?? ''}
3100
+ onChange={(event) =>
3101
+ setActionForm({
3102
+ ...actionForm,
3103
+ internal_api_user_id: event.target.value
3104
+ ? Number(event.target.value)
3105
+ : null,
3106
+ })
3107
+ }
3108
+ placeholder="ID do usuário dono do token"
3109
+ />
3110
+ </Field>
3111
+ <Field label="Token de autenticação *">
3112
+ <div className="flex items-start gap-2">
3113
+ <Input
3114
+ type="password"
3115
+ value={actionForm.internal_api_token}
3116
+ onChange={(event) =>
3117
+ setActionForm({
3118
+ ...actionForm,
3119
+ internal_api_token: event.target.value,
3120
+ })
3121
+ }
3122
+ placeholder="hedhog_api_..."
3123
+ className="flex-1"
3124
+ />
3125
+ <Button
3126
+ type="button"
3127
+ variant="outline"
3128
+ size="sm"
3129
+ disabled={!actionForm.internal_api_user_id}
3130
+ onClick={async () => {
3131
+ if (!actionForm.internal_api_user_id) return;
3132
+ try {
3133
+ const response = await request<{
3134
+ rawToken: string;
3135
+ }>({
3136
+ url: '/webhook-integration/user-tokens',
3137
+ method: 'POST',
3138
+ data: {
3139
+ userId: actionForm.internal_api_user_id,
3140
+ name: `webhook-action-${Date.now()}`,
3141
+ },
3142
+ });
3143
+ const raw = response.data?.rawToken;
3144
+ if (raw) {
3145
+ setActionForm({
3146
+ ...actionForm,
3147
+ internal_api_token: raw,
3148
+ });
3149
+ setGeneratedToken(raw);
3150
+ toast.success(
3151
+ 'Token gerado! Copie-o antes de salvar.'
3152
+ );
3153
+ }
3154
+ } catch {
3155
+ toast.error('Erro ao gerar token');
3156
+ }
3157
+ }}
3158
+ >
3159
+ Gerar
3160
+ </Button>
3161
+ </div>
3162
+ </Field>
3163
+ {generatedToken && (
3164
+ <div className="md:col-span-2 rounded border border-yellow-300 bg-yellow-50 p-3 text-xs text-yellow-800">
3165
+ <strong>Token gerado (exibido apenas uma vez):</strong>
3166
+ <div className="mt-1 flex items-center gap-2 font-mono break-all">
3167
+ <span className="flex-1">{generatedToken}</span>
3168
+ <Button
3169
+ type="button"
3170
+ variant="ghost"
3171
+ size="sm"
3172
+ onClick={() => {
3173
+ void navigator.clipboard.writeText(
3174
+ generatedToken
3175
+ );
3176
+ toast.success('Token copiado!');
3177
+ }}
3178
+ >
3179
+ Copiar
3180
+ </Button>
3181
+ </div>
3182
+ </div>
3183
+ )}
3184
+ <Field label="Método HTTP">
3185
+ <Select
3186
+ value={actionForm.internal_api_method}
3187
+ onValueChange={(value) =>
3188
+ setActionForm({
3189
+ ...actionForm,
3190
+ internal_api_method: value,
3191
+ })
3192
+ }
3193
+ >
3194
+ <SelectTrigger className="w-full">
3195
+ <SelectValue />
3196
+ </SelectTrigger>
3197
+ <SelectContent>
3198
+ {['GET', 'POST', 'PUT', 'PATCH', 'DELETE'].map(
3199
+ (m) => (
3200
+ <SelectItem key={m} value={m}>
3201
+ {m}
3202
+ </SelectItem>
3203
+ )
3204
+ )}
3205
+ </SelectContent>
3206
+ </Select>
3207
+ </Field>
3208
+ <Field label="Path / Endpoint *">
3209
+ <Select
3210
+ value={actionForm.internal_api_path}
3211
+ onValueChange={(value) => {
3212
+ const route = internalRoutes.find(
3213
+ (r) => r.url === value
3214
+ );
3215
+ setActionForm({
3216
+ ...actionForm,
3217
+ internal_api_path: value,
3218
+ internal_api_method:
3219
+ route?.method || actionForm.internal_api_method,
3220
+ });
3221
+ }}
3222
+ >
3223
+ <SelectTrigger className="w-full">
3224
+ <SelectValue placeholder="Selecione um endpoint" />
3225
+ </SelectTrigger>
3226
+ <SelectContent>
3227
+ {internalRoutes.map((route) => (
3228
+ <SelectItem key={route.id} value={route.url}>
3229
+ <span className="mr-2 font-mono text-xs text-muted-foreground">
3230
+ {route.method}
3231
+ </span>
3232
+ {route.url}
3233
+ </SelectItem>
3234
+ ))}
3235
+ </SelectContent>
3236
+ </Select>
3237
+ </Field>
3238
+ <Field label="Query Params (JSON)">
3239
+ <Textarea
3240
+ value={actionForm.internal_api_query}
3241
+ onChange={(event) =>
3242
+ setActionForm({
3243
+ ...actionForm,
3244
+ internal_api_query: event.target.value,
3245
+ })
3246
+ }
3247
+ className="font-mono text-xs"
3248
+ rows={3}
3249
+ placeholder='{"page": "1"}'
3250
+ />
3251
+ </Field>
3252
+ <Field label="Body (JSON)">
3253
+ <Textarea
3254
+ value={actionForm.internal_api_body}
3255
+ onChange={(event) =>
3256
+ setActionForm({
3257
+ ...actionForm,
3258
+ internal_api_body: event.target.value,
3259
+ })
3260
+ }
3261
+ className="font-mono text-xs"
3262
+ rows={3}
3263
+ placeholder='{"userId": "{{userId}}"}'
3264
+ />
3265
+ </Field>
3266
+ </div>
3267
+ )}
3268
+
3269
+ {actionForm.type === 'app_command' && (
3270
+ <div className="grid gap-3">
3271
+ <Field label="Comando *">
3272
+ <Select
3273
+ value={actionForm.app_command_slug}
3274
+ onValueChange={(value) =>
3275
+ setActionForm({
3276
+ ...actionForm,
3277
+ app_command_slug: value,
3278
+ })
3279
+ }
3280
+ >
3281
+ <SelectTrigger className="w-full">
3282
+ <SelectValue placeholder="Selecione um comando" />
3283
+ </SelectTrigger>
3284
+ <SelectContent>
3285
+ {appCommands.map((cmd) => (
3286
+ <SelectItem key={cmd.slug} value={cmd.slug}>
3287
+ {cmd.name}
3288
+ </SelectItem>
3289
+ ))}
3290
+ </SelectContent>
3291
+ </Select>
3292
+ </Field>
3293
+ {actionForm.app_command_slug &&
3294
+ (() => {
3295
+ const cmd = appCommands.find(
3296
+ (c) => c.slug === actionForm.app_command_slug
3297
+ );
3298
+ return cmd ? (
3299
+ <p className="text-sm text-muted-foreground">
3300
+ {cmd.description}
3301
+ </p>
3302
+ ) : null;
3303
+ })()}
3304
+ <Field label="Parâmetros (JSON)">
3305
+ <Textarea
3306
+ value={actionForm.app_command_params}
3307
+ onChange={(event) =>
3308
+ setActionForm({
3309
+ ...actionForm,
3310
+ app_command_params: event.target.value,
3311
+ })
3312
+ }
3313
+ className="font-mono text-xs"
3314
+ rows={5}
3315
+ placeholder="{}"
3316
+ />
3317
+ </Field>
3318
+ {actionForm.app_command_slug &&
3319
+ (() => {
3320
+ const cmd = appCommands.find(
3321
+ (c) => c.slug === actionForm.app_command_slug
3322
+ );
3323
+ return cmd?.inputSchema ? (
3324
+ <div className="rounded border bg-muted/40 p-2">
3325
+ <p className="mb-1 text-xs font-medium text-muted-foreground">
3326
+ Schema esperado:
3327
+ </p>
3328
+ <pre className="whitespace-pre-wrap break-all font-mono text-xs">
3329
+ {JSON.stringify(cmd.inputSchema, null, 2)}
3330
+ </pre>
3331
+ </div>
3332
+ ) : null;
3333
+ })()}
3334
+ </div>
3335
+ )}
3336
+
2653
3337
  <SheetActions
2654
3338
  onSave={saveAction}
2655
3339
  onCancel={() => setActionSheetOpen(false)}
@@ -2662,7 +3346,10 @@ export default function IntegrationsWebhooksPage() {
2662
3346
  </Sheet>
2663
3347
 
2664
3348
  <Sheet open={eventWebhookOpen} onOpenChange={setEventWebhookOpen}>
2665
- <ResizableSheetContent sheetId="webhooks-event-webhook-form" defaultWidth={1024}>
3349
+ <ResizableSheetContent
3350
+ sheetId="webhooks-event-webhook-form"
3351
+ defaultWidth={1024}
3352
+ >
2666
3353
  <SheetHeader>
2667
3354
  <SheetTitle>
2668
3355
  {eventWebhookEdit ? t('editEventWebhook') : t('newEventWebhook')}
@@ -2856,7 +3543,10 @@ export default function IntegrationsWebhooksPage() {
2856
3543
  }
2857
3544
  }}
2858
3545
  >
2859
- <ResizableSheetContent sheetId="webhooks-mail-profile-editor" defaultWidth={896}>
3546
+ <ResizableSheetContent
3547
+ sheetId="webhooks-integration-profile-editor"
3548
+ defaultWidth={896}
3549
+ >
2860
3550
  <SheetHeader>
2861
3551
  <SheetTitle>Editar perfil de e-mail</SheetTitle>
2862
3552
  <SheetDescription>
@@ -3140,7 +3830,10 @@ export default function IntegrationsWebhooksPage() {
3140
3830
  }
3141
3831
  }}
3142
3832
  >
3143
- <ResizableSheetContent sheetId="webhooks-mail-template-editor" defaultWidth={896}>
3833
+ <ResizableSheetContent
3834
+ sheetId="webhooks-mail-template-editor"
3835
+ defaultWidth={896}
3836
+ >
3144
3837
  <SheetHeader>
3145
3838
  <SheetTitle>Editar template de e-mail</SheetTitle>
3146
3839
  <SheetDescription>
@@ -3493,7 +4186,15 @@ function SortableIncomingActionRow({
3493
4186
  <TableCell>{action.name}</TableCell>
3494
4187
  <TableCell>
3495
4188
  <Badge variant="secondary">
3496
- {action.type === 'email' ? t('email') : t('whatsapp')}
4189
+ {action.type === 'email'
4190
+ ? t('email')
4191
+ : action.type === 'whatsapp_evolution'
4192
+ ? t('whatsapp')
4193
+ : action.type === 'http_request'
4194
+ ? 'HTTP Request'
4195
+ : action.type === 'internal_api'
4196
+ ? 'Internal API'
4197
+ : 'App Command'}
3497
4198
  </Badge>
3498
4199
  </TableCell>
3499
4200
  <TableCell>{action.order}</TableCell>