@hed-hog/core 0.0.356 → 0.0.359

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 (250) hide show
  1. package/dist/auth/guards/auth.guard.d.ts +6 -1
  2. package/dist/auth/guards/auth.guard.d.ts.map +1 -1
  3. package/dist/auth/guards/auth.guard.js +33 -2
  4. package/dist/auth/guards/auth.guard.js.map +1 -1
  5. package/dist/file/file.controller.d.ts +4 -2
  6. package/dist/file/file.controller.d.ts.map +1 -1
  7. package/dist/file/file.controller.js +44 -38
  8. package/dist/file/file.controller.js.map +1 -1
  9. package/dist/file/file.service.d.ts +2 -2
  10. package/dist/file/file.service.d.ts.map +1 -1
  11. package/dist/file/file.service.js +25 -42
  12. package/dist/file/file.service.js.map +1 -1
  13. package/dist/file/provider/azure.provider.d.ts.map +1 -1
  14. package/dist/file/provider/azure.provider.js +10 -15
  15. package/dist/file/provider/azure.provider.js.map +1 -1
  16. package/dist/file/provider/gcs.provider.d.ts.map +1 -1
  17. package/dist/file/provider/gcs.provider.js +8 -9
  18. package/dist/file/provider/gcs.provider.js.map +1 -1
  19. package/dist/file/provider/local.provider.d.ts.map +1 -1
  20. package/dist/file/provider/local.provider.js +11 -10
  21. package/dist/file/provider/local.provider.js.map +1 -1
  22. package/dist/file/provider/provider.factory.d.ts +1 -1
  23. package/dist/file/provider/provider.factory.d.ts.map +1 -1
  24. package/dist/file/provider/provider.factory.js +16 -6
  25. package/dist/file/provider/provider.factory.js.map +1 -1
  26. package/dist/file/provider/s3.provider.d.ts.map +1 -1
  27. package/dist/file/provider/s3.provider.js +4 -20
  28. package/dist/file/provider/s3.provider.js.map +1 -1
  29. package/dist/file/provider/spaces.provider.d.ts.map +1 -1
  30. package/dist/file/provider/spaces.provider.js +4 -19
  31. package/dist/file/provider/spaces.provider.js.map +1 -1
  32. package/dist/integration-profile/integration-profile.controller.d.ts +1 -1
  33. package/dist/integration-profile/integration-profile.controller.d.ts.map +1 -1
  34. package/dist/integration-profile/integration-profile.controller.js +4 -3
  35. package/dist/integration-profile/integration-profile.controller.js.map +1 -1
  36. package/dist/integration-profile/integration-profile.service.d.ts +1 -1
  37. package/dist/integration-profile/integration-profile.service.d.ts.map +1 -1
  38. package/dist/integration-profile/integration-profile.service.js +7 -4
  39. package/dist/integration-profile/integration-profile.service.js.map +1 -1
  40. package/dist/integration-profile/integration-profile.utils.d.ts +6 -0
  41. package/dist/integration-profile/integration-profile.utils.d.ts.map +1 -1
  42. package/dist/integration-profile/integration-profile.utils.js +9 -0
  43. package/dist/integration-profile/integration-profile.utils.js.map +1 -1
  44. package/dist/mail/mail.module.d.ts.map +1 -1
  45. package/dist/mail/mail.module.js +9 -4
  46. package/dist/mail/mail.module.js.map +1 -1
  47. package/dist/mail/mail.service.d.ts +2 -1
  48. package/dist/mail/mail.service.d.ts.map +1 -1
  49. package/dist/mail/mail.service.js +11 -7
  50. package/dist/mail/mail.service.js.map +1 -1
  51. package/dist/mcp/guards/mcp-auth.guard.js +1 -1
  52. package/dist/mcp/guards/mcp-auth.guard.js.map +1 -1
  53. package/dist/mcp/mcp-api-key.controller.d.ts +2 -0
  54. package/dist/mcp/mcp-api-key.controller.d.ts.map +1 -1
  55. package/dist/mcp/mcp-api-key.controller.js +1 -1
  56. package/dist/mcp/mcp-api-key.controller.js.map +1 -1
  57. package/dist/mcp/mcp-api-key.service.d.ts +2 -1
  58. package/dist/mcp/mcp-api-key.service.d.ts.map +1 -1
  59. package/dist/mcp/mcp-api-key.service.js +6 -2
  60. package/dist/mcp/mcp-api-key.service.js.map +1 -1
  61. package/dist/mcp/mcp.module.d.ts.map +1 -1
  62. package/dist/mcp/mcp.module.js +1 -3
  63. package/dist/mcp/mcp.module.js.map +1 -1
  64. package/dist/oauth/interfaces/OAuthProvider.d.ts +1 -1
  65. package/dist/oauth/interfaces/OAuthProvider.d.ts.map +1 -1
  66. package/dist/oauth/oauth.controller.d.ts +4 -1
  67. package/dist/oauth/oauth.controller.d.ts.map +1 -1
  68. package/dist/oauth/oauth.controller.js +31 -5
  69. package/dist/oauth/oauth.controller.js.map +1 -1
  70. package/dist/oauth/oauth.service.d.ts +12 -1
  71. package/dist/oauth/oauth.service.d.ts.map +1 -1
  72. package/dist/oauth/oauth.service.js +125 -23
  73. package/dist/oauth/oauth.service.js.map +1 -1
  74. package/dist/oauth/providers/abstract.provider.d.ts +1 -1
  75. package/dist/oauth/providers/abstract.provider.d.ts.map +1 -1
  76. package/dist/oauth/providers/facebook.provider.d.ts +5 -2
  77. package/dist/oauth/providers/facebook.provider.d.ts.map +1 -1
  78. package/dist/oauth/providers/facebook.provider.js +34 -19
  79. package/dist/oauth/providers/facebook.provider.js.map +1 -1
  80. package/dist/oauth/providers/github.provider.d.ts +6 -2
  81. package/dist/oauth/providers/github.provider.d.ts.map +1 -1
  82. package/dist/oauth/providers/github.provider.js +43 -20
  83. package/dist/oauth/providers/github.provider.js.map +1 -1
  84. package/dist/oauth/providers/google.provider.d.ts +5 -2
  85. package/dist/oauth/providers/google.provider.d.ts.map +1 -1
  86. package/dist/oauth/providers/google.provider.js +34 -19
  87. package/dist/oauth/providers/google.provider.js.map +1 -1
  88. package/dist/oauth/providers/microsoft-entra-id.provider.d.ts +5 -2
  89. package/dist/oauth/providers/microsoft-entra-id.provider.d.ts.map +1 -1
  90. package/dist/oauth/providers/microsoft-entra-id.provider.js +43 -40
  91. package/dist/oauth/providers/microsoft-entra-id.provider.js.map +1 -1
  92. package/dist/oauth/providers/microsoft.provider.d.ts +5 -2
  93. package/dist/oauth/providers/microsoft.provider.d.ts.map +1 -1
  94. package/dist/oauth/providers/microsoft.provider.js +34 -19
  95. package/dist/oauth/providers/microsoft.provider.js.map +1 -1
  96. package/dist/profile/profile.controller.js +1 -1
  97. package/dist/profile/profile.controller.js.map +1 -1
  98. package/dist/security/security.service.d.ts +2 -0
  99. package/dist/security/security.service.d.ts.map +1 -1
  100. package/dist/security/security.service.js +21 -0
  101. package/dist/security/security.service.js.map +1 -1
  102. package/dist/setting/setting.service.d.ts +26 -1
  103. package/dist/setting/setting.service.d.ts.map +1 -1
  104. package/dist/setting/setting.service.js +240 -5
  105. package/dist/setting/setting.service.js.map +1 -1
  106. package/dist/user/user.controller.d.ts +2 -1
  107. package/dist/user/user.controller.d.ts.map +1 -1
  108. package/dist/user/user.controller.js +5 -4
  109. package/dist/user/user.controller.js.map +1 -1
  110. package/dist/user/user.service.d.ts +4 -2
  111. package/dist/user/user.service.d.ts.map +1 -1
  112. package/dist/user/user.service.js +19 -4
  113. package/dist/user/user.service.js.map +1 -1
  114. package/dist/webhook-integration/dto/webhook-action.dto.d.ts +17 -2
  115. package/dist/webhook-integration/dto/webhook-action.dto.d.ts.map +1 -1
  116. package/dist/webhook-integration/dto/webhook-action.dto.js +93 -2
  117. package/dist/webhook-integration/dto/webhook-action.dto.js.map +1 -1
  118. package/dist/webhook-integration/webhook-command.registry.d.ts +15 -0
  119. package/dist/webhook-integration/webhook-command.registry.d.ts.map +1 -0
  120. package/dist/webhook-integration/webhook-command.registry.js +36 -0
  121. package/dist/webhook-integration/webhook-command.registry.js.map +1 -0
  122. package/dist/webhook-integration/webhook-integration.controller.d.ts +19 -0
  123. package/dist/webhook-integration/webhook-integration.controller.d.ts.map +1 -1
  124. package/dist/webhook-integration/webhook-integration.controller.js +38 -0
  125. package/dist/webhook-integration/webhook-integration.controller.js.map +1 -1
  126. package/dist/webhook-integration/webhook-integration.module.d.ts.map +1 -1
  127. package/dist/webhook-integration/webhook-integration.module.js +5 -0
  128. package/dist/webhook-integration/webhook-integration.module.js.map +1 -1
  129. package/dist/webhook-integration/webhook-integration.service.d.ts +25 -1
  130. package/dist/webhook-integration/webhook-integration.service.d.ts.map +1 -1
  131. package/dist/webhook-integration/webhook-integration.service.js +332 -23
  132. package/dist/webhook-integration/webhook-integration.service.js.map +1 -1
  133. package/hedhog/data/integration_provider.yaml +16 -0
  134. package/hedhog/data/menu.yaml +0 -16
  135. package/hedhog/data/route.yaml +32 -383
  136. package/hedhog/data/setting_group.yaml +179 -174
  137. package/hedhog/data/setting_subgroup.yaml +16 -0
  138. package/hedhog/frontend/app/account/components/tokens.tsx.ejs +421 -0
  139. package/hedhog/frontend/app/account/layout.tsx.ejs +6 -3
  140. package/hedhog/frontend/app/account/mcp-tokens/page.tsx.ejs +2 -2
  141. package/hedhog/frontend/app/account/tokens/page.tsx.ejs +5 -0
  142. package/hedhog/frontend/app/configurations/[slug]/components/setting-field.tsx.ejs +414 -76
  143. package/hedhog/frontend/app/configurations/layout.tsx.ejs +1 -1
  144. package/hedhog/frontend/app/dashboard/dashboard-home-tabs.tsx.ejs +3 -1
  145. package/hedhog/frontend/app/integration/profiles/page.tsx.ejs +186 -18
  146. package/hedhog/frontend/app/integrations-webhooks/page.tsx.ejs +597 -21
  147. package/hedhog/frontend/app/mail/profiles/page.tsx.ejs +2 -2
  148. package/hedhog/frontend/app/setting-list/page.tsx.ejs +229 -395
  149. package/hedhog/frontend/messages/en.json +67 -3
  150. package/hedhog/frontend/messages/pt.json +67 -3
  151. package/hedhog/table/file.yaml +1 -1
  152. package/hedhog/table/mcp_api_key.yaml +4 -0
  153. package/hedhog/table/webhook_action.yaml +57 -1
  154. package/package.json +5 -4
  155. package/src/auth/guards/auth.guard.ts +32 -0
  156. package/src/file/file.controller.ts +51 -42
  157. package/src/file/file.service.ts +31 -52
  158. package/src/file/provider/azure.provider.ts +14 -28
  159. package/src/file/provider/gcs.provider.ts +9 -9
  160. package/src/file/provider/local.provider.ts +10 -13
  161. package/src/file/provider/provider.factory.ts +19 -7
  162. package/src/file/provider/s3.provider.ts +4 -20
  163. package/src/file/provider/spaces.provider.ts +4 -19
  164. package/src/integration-profile/integration-profile.controller.ts +2 -0
  165. package/src/integration-profile/integration-profile.service.ts +7 -2
  166. package/src/integration-profile/integration-profile.utils.ts +17 -0
  167. package/src/mail/mail.module.ts +14 -4
  168. package/src/mail/mail.service.ts +12 -7
  169. package/src/mcp/guards/mcp-auth.guard.ts +1 -1
  170. package/src/mcp/mcp-api-key.controller.ts +2 -2
  171. package/src/mcp/mcp-api-key.service.ts +6 -2
  172. package/src/mcp/mcp.module.ts +1 -3
  173. package/src/oauth/interfaces/OAuthProvider.ts +1 -1
  174. package/src/oauth/oauth.controller.ts +30 -2
  175. package/src/oauth/oauth.service.ts +194 -35
  176. package/src/oauth/providers/abstract.provider.ts +1 -1
  177. package/src/oauth/providers/facebook.provider.ts +36 -20
  178. package/src/oauth/providers/github.provider.ts +46 -23
  179. package/src/oauth/providers/google.provider.ts +36 -20
  180. package/src/oauth/providers/microsoft-entra-id.provider.ts +42 -46
  181. package/src/oauth/providers/microsoft.provider.ts +36 -21
  182. package/src/profile/profile.controller.ts +2 -2
  183. package/src/security/security.service.ts +34 -1
  184. package/src/setting/setting.service.ts +307 -7
  185. package/src/user/user.controller.ts +4 -1
  186. package/src/user/user.service.ts +20 -2
  187. package/src/webhook-integration/dto/webhook-action.dto.ts +85 -4
  188. package/src/webhook-integration/webhook-command.registry.ts +42 -0
  189. package/src/webhook-integration/webhook-integration.controller.ts +20 -0
  190. package/src/webhook-integration/webhook-integration.module.ts +50 -45
  191. package/src/webhook-integration/webhook-integration.service.ts +374 -11
  192. package/dist/mail-profile/dto/create.dto.d.ts +0 -23
  193. package/dist/mail-profile/dto/create.dto.d.ts.map +0 -1
  194. package/dist/mail-profile/dto/create.dto.js +0 -139
  195. package/dist/mail-profile/dto/create.dto.js.map +0 -1
  196. package/dist/mail-profile/dto/update.dto.d.ts +0 -6
  197. package/dist/mail-profile/dto/update.dto.d.ts.map +0 -1
  198. package/dist/mail-profile/dto/update.dto.js +0 -9
  199. package/dist/mail-profile/dto/update.dto.js.map +0 -1
  200. package/dist/mail-profile/mail-profile.controller.d.ts +0 -94
  201. package/dist/mail-profile/mail-profile.controller.d.ts.map +0 -1
  202. package/dist/mail-profile/mail-profile.controller.js +0 -95
  203. package/dist/mail-profile/mail-profile.controller.js.map +0 -1
  204. package/dist/mail-profile/mail-profile.module.d.ts +0 -3
  205. package/dist/mail-profile/mail-profile.module.d.ts.map +0 -1
  206. package/dist/mail-profile/mail-profile.module.js +0 -31
  207. package/dist/mail-profile/mail-profile.module.js.map +0 -1
  208. package/dist/mail-profile/mail-profile.service.d.ts +0 -109
  209. package/dist/mail-profile/mail-profile.service.d.ts.map +0 -1
  210. package/dist/mail-profile/mail-profile.service.js +0 -278
  211. package/dist/mail-profile/mail-profile.service.js.map +0 -1
  212. package/dist/mcp/tools/core-mail-profile.mcp-tools.d.ts +0 -20
  213. package/dist/mcp/tools/core-mail-profile.mcp-tools.d.ts.map +0 -1
  214. package/dist/mcp/tools/core-mail-profile.mcp-tools.js +0 -96
  215. package/dist/mcp/tools/core-mail-profile.mcp-tools.js.map +0 -1
  216. package/dist/whatsapp-profile/dto/create.dto.d.ts +0 -11
  217. package/dist/whatsapp-profile/dto/create.dto.d.ts.map +0 -1
  218. package/dist/whatsapp-profile/dto/create.dto.js +0 -55
  219. package/dist/whatsapp-profile/dto/create.dto.js.map +0 -1
  220. package/dist/whatsapp-profile/dto/update.dto.d.ts +0 -6
  221. package/dist/whatsapp-profile/dto/update.dto.d.ts.map +0 -1
  222. package/dist/whatsapp-profile/dto/update.dto.js +0 -9
  223. package/dist/whatsapp-profile/dto/update.dto.js.map +0 -1
  224. package/dist/whatsapp-profile/whatsapp-profile.controller.d.ts +0 -54
  225. package/dist/whatsapp-profile/whatsapp-profile.controller.d.ts.map +0 -1
  226. package/dist/whatsapp-profile/whatsapp-profile.controller.js +0 -85
  227. package/dist/whatsapp-profile/whatsapp-profile.controller.js.map +0 -1
  228. package/dist/whatsapp-profile/whatsapp-profile.module.d.ts +0 -3
  229. package/dist/whatsapp-profile/whatsapp-profile.module.d.ts.map +0 -1
  230. package/dist/whatsapp-profile/whatsapp-profile.module.js +0 -26
  231. package/dist/whatsapp-profile/whatsapp-profile.module.js.map +0 -1
  232. package/dist/whatsapp-profile/whatsapp-profile.service.d.ts +0 -63
  233. package/dist/whatsapp-profile/whatsapp-profile.service.d.ts.map +0 -1
  234. package/dist/whatsapp-profile/whatsapp-profile.service.js +0 -138
  235. package/dist/whatsapp-profile/whatsapp-profile.service.js.map +0 -1
  236. package/hedhog/data/mail_profile.yaml +0 -18
  237. package/hedhog/data/whatsapp_profile.yaml +0 -6
  238. package/hedhog/table/mail_profile.yaml +0 -75
  239. package/hedhog/table/whatsapp_profile.yaml +0 -26
  240. package/src/mail-profile/dto/create.dto.ts +0 -145
  241. package/src/mail-profile/dto/update.dto.ts +0 -4
  242. package/src/mail-profile/mail-profile.controller.ts +0 -56
  243. package/src/mail-profile/mail-profile.module.ts +0 -18
  244. package/src/mail-profile/mail-profile.service.ts +0 -308
  245. package/src/mcp/tools/core-mail-profile.mcp-tools.ts +0 -69
  246. package/src/whatsapp-profile/dto/create.dto.ts +0 -36
  247. package/src/whatsapp-profile/dto/update.dto.ts +0 -4
  248. package/src/whatsapp-profile/whatsapp-profile.controller.ts +0 -51
  249. package/src/whatsapp-profile/whatsapp-profile.module.ts +0 -13
  250. package/src/whatsapp-profile/whatsapp-profile.service.ts +0 -160
@@ -1,3 +1,7 @@
1
+ import {
2
+ IntegrationProfileSheet,
3
+ type IntegrationProfileSheetSavedProfile,
4
+ } from '@/components/integration-profile/integration-profile-sheet';
1
5
  import { Button } from '@/components/ui/button';
2
6
  import { Checkbox } from '@/components/ui/checkbox';
3
7
  import { EntityPicker } from '@/components/ui/entity-picker';
@@ -20,7 +24,7 @@ import {
20
24
  SettingTypeEnum,
21
25
  } from '@hed-hog/api-types';
22
26
  import { useApp } from '@hed-hog/next-app-provider';
23
- import { Eye, EyeOff, Upload } from 'lucide-react';
27
+ import { Eye, EyeOff, Pencil, Plus, Upload } from 'lucide-react';
24
28
  import { useTranslations } from 'next-intl';
25
29
  import { useEffect, useRef, useState } from 'react';
26
30
 
@@ -83,10 +87,35 @@ function getLocalizedIntegrationName(
83
87
  );
84
88
  }
85
89
 
86
- const DAILY_REPORT_EMAIL_PROFILE_SLUG =
87
- 'operations.daily-report.email-profile-id';
88
- const DAILY_REPORT_WHATSAPP_PROFILE_SLUG =
89
- 'operations.daily-report.whatsapp-profile-id';
90
+ const DAILY_REPORT_EMAIL_INTEGRATION_SETTING_SLUG =
91
+ 'operations.daily-report.email-integration-profile-id';
92
+ const DAILY_REPORT_WHATSAPP_INTEGRATION_SETTING_SLUG =
93
+ 'operations.daily-report.whatsapp-integration-profile-id';
94
+ const AI_PROFILE_SETTING_SLUGS = [
95
+ 'ai-gemini-profile-id',
96
+ 'ai-openai-profile-id',
97
+ 'mcp-ai-profile-id',
98
+ ];
99
+ const OAUTH_PROFILE_SLUG_TO_PROVIDER: Record<string, string> = {
100
+ 'oauth-google-profile-id': 'google-oauth',
101
+ 'oauth-facebook-profile-id': 'facebook-oauth',
102
+ 'oauth-github-profile-id': 'github-oauth',
103
+ 'oauth-microsoft-profile-id': 'microsoft-oauth',
104
+ 'oauth-microsoft-entra-id-profile-id': 'microsoft-entra-id-oauth',
105
+ };
106
+ const ADMIN_LOGIN_OAUTH_SETTING_SLUG = 'admin-login-page-oauth-providers';
107
+ const ADMIN_LOGIN_PROVIDER_ENABLED_SLUG_BY_PROVIDER: Record<string, string> = {
108
+ facebook: 'oauth-facebook-enabled',
109
+ github: 'oauth-github-enabled',
110
+ google: 'oauth-google-enabled',
111
+ microsoft: 'oauth-microsoft-enabled',
112
+ 'microsoft-entra-id': 'oauth-microsoft-entra-id-enabled',
113
+ };
114
+ const INTEGRATION_PROFILE_PICKER_SLUGS = [
115
+ 'file-storage-profile-id',
116
+ ...AI_PROFILE_SETTING_SLUGS,
117
+ ...Object.keys(OAUTH_PROFILE_SLUG_TO_PROVIDER),
118
+ ];
90
119
 
91
120
  function toSlug(value: string) {
92
121
  return (value || 'profile')
@@ -98,11 +127,11 @@ function toSlug(value: string) {
98
127
  }
99
128
 
100
129
  function getDailyReportIntegrationTypeSlug(settingSlug: string) {
101
- if (settingSlug === DAILY_REPORT_EMAIL_PROFILE_SLUG) {
130
+ if (settingSlug === DAILY_REPORT_EMAIL_INTEGRATION_SETTING_SLUG) {
102
131
  return 'email';
103
132
  }
104
133
 
105
- if (settingSlug === DAILY_REPORT_WHATSAPP_PROFILE_SLUG) {
134
+ if (settingSlug === DAILY_REPORT_WHATSAPP_INTEGRATION_SETTING_SLUG) {
106
135
  return 'whatsapp';
107
136
  }
108
137
 
@@ -157,13 +186,23 @@ function buildIntegrationProfileConfig(
157
186
 
158
187
  export const SettingField = ({ setting, className }: SettingFieldProps) => {
159
188
  const t = useTranslations('core.Configurations');
160
- const { showToastHandler, setSettingValue, request, currentLocaleCode } =
161
- useApp();
189
+ const {
190
+ showToastHandler,
191
+ setSettingValue,
192
+ request,
193
+ currentLocaleCode,
194
+ getSettingValue,
195
+ } = useApp();
162
196
  const component =
163
197
  setting.component?.replaceAll('_', '-') || SettingComponentEnum.INPUT_TEXT;
164
198
  const [localValue, setLocalValue] = useState(setting.value);
165
199
  const [storageProfileSelectedLabel, setStorageProfileSelectedLabel] =
166
200
  useState('');
201
+ const [isStorageProfileSheetOpen, setIsStorageProfileSheetOpen] =
202
+ useState(false);
203
+ const [storageProfileEditingId, setStorageProfileEditingId] = useState<
204
+ number | null
205
+ >(null);
167
206
  const [showSecretValue, setShowSecretValue] = useState(false);
168
207
  const [isUploading, setIsUploading] = useState(false);
169
208
  const debounceTimerRef = useRef<NodeJS.Timeout | undefined>(undefined);
@@ -226,7 +265,7 @@ export const SettingField = ({ setting, className }: SettingFieldProps) => {
226
265
  }, [localValue]);
227
266
 
228
267
  useEffect(() => {
229
- if (setting.slug !== 'file-storage-profile-id') {
268
+ if (!INTEGRATION_PROFILE_PICKER_SLUGS.includes(setting.slug)) {
230
269
  setStorageProfileSelectedLabel('');
231
270
  return;
232
271
  }
@@ -485,6 +524,9 @@ export const SettingField = ({ setting, className }: SettingFieldProps) => {
485
524
  const selectedValues: string[] = Array.isArray(parsedValue)
486
525
  ? parsedValue
487
526
  : [];
527
+ const isAdminLoginOAuthSetting =
528
+ setting.slug === ADMIN_LOGIN_OAUTH_SETTING_SLUG;
529
+
488
530
  return (
489
531
  <div
490
532
  className={cn(
@@ -492,26 +534,50 @@ export const SettingField = ({ setting, className }: SettingFieldProps) => {
492
534
  className
493
535
  )}
494
536
  >
495
- {options.map((option) => (
496
- <div key={option.id} className="flex items-center space-x-2">
497
- <Checkbox
498
- className="bg-background"
499
- checked={selectedValues.includes(option.value)}
500
- onCheckedChange={(checked) => {
501
- let newValues = [...selectedValues];
502
- if (checked) {
503
- newValues.push(option.value);
504
- } else {
505
- newValues = newValues.filter(
506
- (val) => val !== option.value
507
- );
508
- }
509
- handleChangeValue(formatValue(newValues), true);
510
- }}
511
- />
512
- <Label>{option.value}</Label>
513
- </div>
514
- ))}
537
+ {options.map((option) => {
538
+ const enabledSettingSlug =
539
+ ADMIN_LOGIN_PROVIDER_ENABLED_SLUG_BY_PROVIDER[option.value];
540
+ const isProviderGloballyEnabled = enabledSettingSlug
541
+ ? getSettingValue(enabledSettingSlug) === true
542
+ : true;
543
+ const isOptionDisabled =
544
+ isAdminLoginOAuthSetting && !isProviderGloballyEnabled;
545
+
546
+ return (
547
+ <div key={option.id} className="flex items-center space-x-2">
548
+ <Checkbox
549
+ className="bg-background"
550
+ checked={selectedValues.includes(option.value)}
551
+ disabled={isOptionDisabled}
552
+ onCheckedChange={(checked) => {
553
+ if (isOptionDisabled) {
554
+ return;
555
+ }
556
+
557
+ let newValues = [...selectedValues];
558
+ if (checked) {
559
+ newValues.push(option.value);
560
+ } else {
561
+ newValues = newValues.filter(
562
+ (val) => val !== option.value
563
+ );
564
+ }
565
+ handleChangeValue(formatValue(newValues), true);
566
+ }}
567
+ />
568
+ <Label className={cn(isOptionDisabled && 'opacity-60')}>
569
+ {option.value}
570
+ </Label>
571
+ </div>
572
+ );
573
+ })}
574
+ {isAdminLoginOAuthSetting && (
575
+ <p className="text-xs text-muted-foreground">
576
+ {currentLocaleCode.startsWith('pt')
577
+ ? 'Providers desabilitados globalmente (oauth-*-enabled = false) ficam indisponíveis nesta lista.'
578
+ : 'Providers disabled globally (oauth-*-enabled = false) are unavailable in this list.'}
579
+ </p>
580
+ )}
515
581
  </div>
516
582
  );
517
583
  }
@@ -618,56 +684,328 @@ export const SettingField = ({ setting, className }: SettingFieldProps) => {
618
684
  };
619
685
 
620
686
  return (
621
- <EntityPicker<IntegrationProfileOption & Record<string, unknown>>
622
- placeholder={t('selectStorageProfile')}
623
- emptyStateDescription={t('storageProfileEmptyState')}
624
- value={parsedValue ? Number(parsedValue) : null}
625
- onChange={(id, option) => {
626
- setStorageProfileSelectedLabel(option?.name ?? '');
627
- handleChangeValue(id != null ? String(id) : '', true);
628
- }}
629
- valueType="number"
630
- initialSelectedLabel={storageProfileSelectedLabel}
631
- showCreateButton={false}
632
- loadOptions={async ({ page, pageSize, search }) => {
633
- const typeId = await loadStorageTypeId();
634
- const qs = new URLSearchParams({
635
- page: String(page),
636
- pageSize: String(pageSize),
637
- typeId: String(typeId),
638
- });
639
- if (search) qs.set('search', search);
640
- const response = await request<
641
- ApiPaginated<IntegrationProfileOption & Record<string, unknown>>
642
- >({
643
- url: `/integration-profile?${qs}`,
644
- method: 'GET',
645
- });
646
- const paged = response.data;
647
- return {
648
- items: paged?.data ?? [],
649
- hasMore: (paged?.page ?? 0) < (paged?.lastPage ?? 0),
650
- };
651
- }}
652
- getOptionValue={(opt) => opt.id}
653
- getOptionLabel={(opt) => String(opt.name ?? '')}
654
- getOptionDescription={(opt) => {
655
- const providerSlug = String(opt.integration_provider?.slug ?? '');
656
- const providerName = getLocalizedIntegrationName(
657
- opt.integration_provider?.integration_provider_locale,
658
- currentLocaleCode
659
- );
660
- return [providerName || providerSlug, opt.slug]
661
- .filter(Boolean)
662
- .join(' • ');
663
- }}
664
- className={cn(className, 'w-full min-w-0 md:min-w-50')}
665
- />
687
+ <>
688
+ <div className="flex w-full min-w-0 items-center gap-2 md:max-w-72">
689
+ <EntityPicker<IntegrationProfileOption & Record<string, unknown>>
690
+ placeholder={t('selectStorageProfile')}
691
+ emptyStateDescription={t('storageProfileEmptyState')}
692
+ value={parsedValue ? Number(parsedValue) : null}
693
+ onChange={(id, option) => {
694
+ setStorageProfileSelectedLabel(option?.name ?? '');
695
+ handleChangeValue(id != null ? String(id) : '', true);
696
+ }}
697
+ valueType="number"
698
+ initialSelectedLabel={storageProfileSelectedLabel}
699
+ showCreateButton={false}
700
+ clearable={false}
701
+ loadOptions={async ({ page, pageSize, search }) => {
702
+ const typeId = await loadStorageTypeId();
703
+ const qs = new URLSearchParams({
704
+ page: String(page),
705
+ pageSize: String(pageSize),
706
+ typeId: String(typeId),
707
+ });
708
+ if (search) qs.set('search', search);
709
+ const response = await request<
710
+ ApiPaginated<
711
+ IntegrationProfileOption & Record<string, unknown>
712
+ >
713
+ >({
714
+ url: `/integration-profile?${qs}`,
715
+ method: 'GET',
716
+ });
717
+ const paged = response.data;
718
+ return {
719
+ items: paged?.data ?? [],
720
+ hasMore: (paged?.page ?? 0) < (paged?.lastPage ?? 0),
721
+ };
722
+ }}
723
+ getOptionValue={(opt) => opt.id}
724
+ getOptionLabel={(opt) => String(opt.name ?? '')}
725
+ getOptionDescription={(opt) => {
726
+ const providerSlug = String(
727
+ opt.integration_provider?.slug ?? ''
728
+ );
729
+ const providerName = getLocalizedIntegrationName(
730
+ opt.integration_provider?.integration_provider_locale,
731
+ currentLocaleCode
732
+ );
733
+ return [providerName || providerSlug, opt.slug]
734
+ .filter(Boolean)
735
+ .join(' • ');
736
+ }}
737
+ className={cn('flex-1 min-w-0', className)}
738
+ />
739
+
740
+ <Button
741
+ type="button"
742
+ variant="outline"
743
+ size="icon"
744
+ className="h-10 w-10 shrink-0"
745
+ onClick={() => {
746
+ setStorageProfileEditingId(
747
+ parsedValue ? Number(parsedValue) : null
748
+ );
749
+ setIsStorageProfileSheetOpen(true);
750
+ }}
751
+ disabled={!parsedValue}
752
+ aria-label="Editar perfil de armazenamento"
753
+ title="Editar perfil de armazenamento"
754
+ >
755
+ <Pencil className="h-4 w-4" />
756
+ </Button>
757
+
758
+ <Button
759
+ type="button"
760
+ variant="outline"
761
+ size="icon"
762
+ className="h-10 w-10 shrink-0"
763
+ onClick={() => {
764
+ setStorageProfileEditingId(null);
765
+ setIsStorageProfileSheetOpen(true);
766
+ }}
767
+ aria-label="Criar perfil de armazenamento"
768
+ title="Criar perfil de armazenamento"
769
+ >
770
+ <Plus className="h-4 w-4" />
771
+ </Button>
772
+ </div>
773
+
774
+ <IntegrationProfileSheet
775
+ open={isStorageProfileSheetOpen}
776
+ onOpenChange={(nextOpen) => {
777
+ setIsStorageProfileSheetOpen(nextOpen);
778
+ if (!nextOpen) {
779
+ setStorageProfileEditingId(null);
780
+ }
781
+ }}
782
+ profileId={storageProfileEditingId}
783
+ initialTypeSlug="storage"
784
+ lockedTypeSlug="storage"
785
+ onSaved={(profile: IntegrationProfileSheetSavedProfile) => {
786
+ setStorageProfileSelectedLabel(profile.name ?? '');
787
+ handleChangeValue(String(profile.id), true);
788
+ }}
789
+ />
790
+ </>
791
+ );
792
+ }
793
+
794
+ if (AI_PROFILE_SETTING_SLUGS.includes(setting.slug)) {
795
+ return (
796
+ <>
797
+ <div className="flex w-full min-w-0 items-center gap-2 md:max-w-72">
798
+ <EntityPicker<IntegrationProfileOption & Record<string, unknown>>
799
+ placeholder={t('selectAiProfile')}
800
+ emptyStateDescription={t('aiProfileEmptyState')}
801
+ value={parsedValue ? Number(parsedValue) : null}
802
+ onChange={(id, option) => {
803
+ setStorageProfileSelectedLabel(option?.name ?? '');
804
+ handleChangeValue(id != null ? String(id) : '', true);
805
+ }}
806
+ valueType="number"
807
+ initialSelectedLabel={storageProfileSelectedLabel}
808
+ showCreateButton={false}
809
+ clearable={false}
810
+ loadOptions={async ({ page, pageSize, search }) => {
811
+ const qs = new URLSearchParams({
812
+ page: String(page),
813
+ pageSize: String(pageSize),
814
+ typeSlug: 'ai',
815
+ });
816
+ if (search) qs.set('search', search);
817
+ const response = await request<
818
+ ApiPaginated<
819
+ IntegrationProfileOption & Record<string, unknown>
820
+ >
821
+ >({
822
+ url: `/integration-profile?${qs}`,
823
+ method: 'GET',
824
+ });
825
+ const paged = response.data;
826
+ return {
827
+ items: paged?.data ?? [],
828
+ hasMore: (paged?.page ?? 0) < (paged?.lastPage ?? 0),
829
+ };
830
+ }}
831
+ getOptionValue={(opt) => opt.id}
832
+ getOptionLabel={(opt) => String(opt.name ?? '')}
833
+ getOptionDescription={(opt) => {
834
+ const providerSlug = String(
835
+ opt.integration_provider?.slug ?? ''
836
+ );
837
+ const providerName = getLocalizedIntegrationName(
838
+ opt.integration_provider?.integration_provider_locale,
839
+ currentLocaleCode
840
+ );
841
+ return [providerName || providerSlug, opt.slug]
842
+ .filter(Boolean)
843
+ .join(' • ');
844
+ }}
845
+ className={cn('flex-1 min-w-0', className)}
846
+ />
847
+
848
+ <Button
849
+ type="button"
850
+ variant="outline"
851
+ size="icon"
852
+ className="h-10 w-10 shrink-0"
853
+ onClick={() => {
854
+ setStorageProfileEditingId(
855
+ parsedValue ? Number(parsedValue) : null
856
+ );
857
+ setIsStorageProfileSheetOpen(true);
858
+ }}
859
+ disabled={!parsedValue}
860
+ aria-label="Editar perfil de IA"
861
+ title="Editar perfil de IA"
862
+ >
863
+ <Pencil className="h-4 w-4" />
864
+ </Button>
865
+
866
+ <Button
867
+ type="button"
868
+ variant="outline"
869
+ size="icon"
870
+ className="h-10 w-10 shrink-0"
871
+ onClick={() => {
872
+ setStorageProfileEditingId(null);
873
+ setIsStorageProfileSheetOpen(true);
874
+ }}
875
+ aria-label="Criar perfil de IA"
876
+ title="Criar perfil de IA"
877
+ >
878
+ <Plus className="h-4 w-4" />
879
+ </Button>
880
+ </div>
881
+
882
+ <IntegrationProfileSheet
883
+ open={isStorageProfileSheetOpen}
884
+ onOpenChange={(nextOpen) => {
885
+ setIsStorageProfileSheetOpen(nextOpen);
886
+ if (!nextOpen) setStorageProfileEditingId(null);
887
+ }}
888
+ profileId={storageProfileEditingId}
889
+ initialTypeSlug="ai"
890
+ lockedTypeSlug="ai"
891
+ onSaved={(profile: IntegrationProfileSheetSavedProfile) => {
892
+ setStorageProfileSelectedLabel(profile.name ?? '');
893
+ handleChangeValue(String(profile.id), true);
894
+ }}
895
+ />
896
+ </>
897
+ );
898
+ }
899
+
900
+ const oauthProviderSlug = OAUTH_PROFILE_SLUG_TO_PROVIDER[setting.slug];
901
+ if (oauthProviderSlug) {
902
+ return (
903
+ <>
904
+ <div className="flex w-full min-w-0 items-center gap-2 md:max-w-72">
905
+ <EntityPicker<IntegrationProfileOption & Record<string, unknown>>
906
+ placeholder={t('selectOAuthProfile')}
907
+ emptyStateDescription={t('oauthProfileEmptyState')}
908
+ value={parsedValue ? Number(parsedValue) : null}
909
+ onChange={(id, option) => {
910
+ setStorageProfileSelectedLabel(option?.name ?? '');
911
+ handleChangeValue(id != null ? String(id) : '', true);
912
+ }}
913
+ valueType="number"
914
+ initialSelectedLabel={storageProfileSelectedLabel}
915
+ showCreateButton={false}
916
+ clearable={false}
917
+ loadOptions={async ({ page, pageSize, search }) => {
918
+ const qs = new URLSearchParams({
919
+ page: String(page),
920
+ pageSize: String(pageSize),
921
+ providerSlug: oauthProviderSlug,
922
+ });
923
+ if (search) qs.set('search', search);
924
+ const response = await request<
925
+ ApiPaginated<
926
+ IntegrationProfileOption & Record<string, unknown>
927
+ >
928
+ >({
929
+ url: `/integration-profile?${qs}`,
930
+ method: 'GET',
931
+ });
932
+ const paged = response.data;
933
+ return {
934
+ items: paged?.data ?? [],
935
+ hasMore: (paged?.page ?? 0) < (paged?.lastPage ?? 0),
936
+ };
937
+ }}
938
+ getOptionValue={(opt) => opt.id}
939
+ getOptionLabel={(opt) => String(opt.name ?? '')}
940
+ getOptionDescription={(opt) => {
941
+ const providerSlug = String(
942
+ opt.integration_provider?.slug ?? ''
943
+ );
944
+ const providerName = getLocalizedIntegrationName(
945
+ opt.integration_provider?.integration_provider_locale,
946
+ currentLocaleCode
947
+ );
948
+ return [providerName || providerSlug, opt.slug]
949
+ .filter(Boolean)
950
+ .join(' • ');
951
+ }}
952
+ className={cn('flex-1 min-w-0', className)}
953
+ />
954
+
955
+ <Button
956
+ type="button"
957
+ variant="outline"
958
+ size="icon"
959
+ className="h-10 w-10 shrink-0"
960
+ onClick={() => {
961
+ setStorageProfileEditingId(
962
+ parsedValue ? Number(parsedValue) : null
963
+ );
964
+ setIsStorageProfileSheetOpen(true);
965
+ }}
966
+ disabled={!parsedValue}
967
+ aria-label="Editar perfil OAuth"
968
+ title="Editar perfil OAuth"
969
+ >
970
+ <Pencil className="h-4 w-4" />
971
+ </Button>
972
+
973
+ <Button
974
+ type="button"
975
+ variant="outline"
976
+ size="icon"
977
+ className="h-10 w-10 shrink-0"
978
+ onClick={() => {
979
+ setStorageProfileEditingId(null);
980
+ setIsStorageProfileSheetOpen(true);
981
+ }}
982
+ aria-label="Criar perfil OAuth"
983
+ title="Criar perfil OAuth"
984
+ >
985
+ <Plus className="h-4 w-4" />
986
+ </Button>
987
+ </div>
988
+
989
+ <IntegrationProfileSheet
990
+ open={isStorageProfileSheetOpen}
991
+ onOpenChange={(nextOpen) => {
992
+ setIsStorageProfileSheetOpen(nextOpen);
993
+ if (!nextOpen) setStorageProfileEditingId(null);
994
+ }}
995
+ profileId={storageProfileEditingId}
996
+ initialTypeSlug="oauth"
997
+ lockedTypeSlug="oauth"
998
+ onSaved={(profile: IntegrationProfileSheetSavedProfile) => {
999
+ setStorageProfileSelectedLabel(profile.name ?? '');
1000
+ handleChangeValue(String(profile.id), true);
1001
+ }}
1002
+ />
1003
+ </>
666
1004
  );
667
1005
  }
668
1006
 
669
1007
  if (
670
- setting.slug !== 'mail-profile-id' &&
1008
+ setting.slug !== 'mail-integration-profile-id' &&
671
1009
  !dailyReportIntegrationTypeSlug
672
1010
  ) {
673
1011
  return (
@@ -232,7 +232,7 @@ export default function ConfigurationsLayout({ children }: IProps) {
232
232
  const activeInOverflow = activeIndex >= 0 && !visibleSet.has(activeIndex);
233
233
 
234
234
  return (
235
- <div className="flex min-w-0 flex-col overflow-x-hidden px-4">
235
+ <div className="flex min-w-0 flex-col px-4">
236
236
  <PageHeader
237
237
  breadcrumbs={[
238
238
  { label: t('breadcrumbHome'), href: '/' },
@@ -311,6 +311,8 @@ const getErrorMessage = (error: unknown, fallback: string) => {
311
311
  return fallback;
312
312
  };
313
313
 
314
+ const EMPTY_DASHBOARDS: DashboardTab[] = [];
315
+
314
316
  export function DashboardHomeTabs() {
315
317
  const t = useTranslations('core.DashboardHomeTabs');
316
318
  const tDashboardPage = useTranslations('core.DashboardPage');
@@ -365,7 +367,7 @@ export function DashboardHomeTabs() {
365
367
  const debouncedShareSearch = useDebounce(shareSearch, 300);
366
368
 
367
369
  const {
368
- data: dashboards = [],
370
+ data: dashboards = EMPTY_DASHBOARDS,
369
371
  isLoading,
370
372
  refetch: refetchDashboards,
371
373
  } = useQuery<DashboardTab[]>({