@hed-hog/core 0.0.354 → 0.0.356

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 (167) 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/core.module.d.ts.map +1 -1
  6. package/dist/core.module.js +3 -3
  7. package/dist/core.module.js.map +1 -1
  8. package/dist/file/file.service.d.ts +1 -1
  9. package/dist/file/file.service.d.ts.map +1 -1
  10. package/dist/file/file.service.js +50 -64
  11. package/dist/file/file.service.js.map +1 -1
  12. package/dist/file/provider/provider.enum.d.ts +2 -1
  13. package/dist/file/provider/provider.enum.d.ts.map +1 -1
  14. package/dist/file/provider/provider.enum.js +1 -0
  15. package/dist/file/provider/provider.enum.js.map +1 -1
  16. package/dist/file/provider/provider.factory.d.ts.map +1 -1
  17. package/dist/file/provider/provider.factory.js +3 -0
  18. package/dist/file/provider/provider.factory.js.map +1 -1
  19. package/dist/file/provider/spaces.provider.d.ts +27 -0
  20. package/dist/file/provider/spaces.provider.d.ts.map +1 -0
  21. package/dist/file/provider/spaces.provider.js +218 -0
  22. package/dist/file/provider/spaces.provider.js.map +1 -0
  23. package/dist/index.d.ts +4 -3
  24. package/dist/index.d.ts.map +1 -1
  25. package/dist/index.js +4 -3
  26. package/dist/index.js.map +1 -1
  27. package/dist/integration-profile/dto/create.dto.d.ts +9 -0
  28. package/dist/integration-profile/dto/create.dto.d.ts.map +1 -0
  29. package/dist/integration-profile/dto/create.dto.js +54 -0
  30. package/dist/integration-profile/dto/create.dto.js.map +1 -0
  31. package/dist/integration-profile/dto/export.dto.d.ts +5 -0
  32. package/dist/integration-profile/dto/export.dto.d.ts.map +1 -0
  33. package/dist/integration-profile/dto/export.dto.js +29 -0
  34. package/dist/integration-profile/dto/export.dto.js.map +1 -0
  35. package/dist/integration-profile/dto/import-confirm.dto.d.ts +17 -0
  36. package/dist/integration-profile/dto/import-confirm.dto.d.ts.map +1 -0
  37. package/dist/integration-profile/dto/import-confirm.dto.js +77 -0
  38. package/dist/integration-profile/dto/import-confirm.dto.js.map +1 -0
  39. package/dist/integration-profile/dto/update.dto.d.ts +6 -0
  40. package/dist/integration-profile/dto/update.dto.d.ts.map +1 -0
  41. package/dist/integration-profile/dto/update.dto.js +9 -0
  42. package/dist/integration-profile/dto/update.dto.js.map +1 -0
  43. package/dist/integration-profile/integration-profile.controller.d.ts +142 -0
  44. package/dist/integration-profile/integration-profile.controller.d.ts.map +1 -0
  45. package/dist/integration-profile/integration-profile.controller.js +165 -0
  46. package/dist/integration-profile/integration-profile.controller.js.map +1 -0
  47. package/dist/integration-profile/integration-profile.module.d.ts +3 -0
  48. package/dist/integration-profile/integration-profile.module.d.ts.map +1 -0
  49. package/dist/integration-profile/integration-profile.module.js +29 -0
  50. package/dist/integration-profile/integration-profile.module.js.map +1 -0
  51. package/dist/integration-profile/integration-profile.service.d.ts +160 -0
  52. package/dist/integration-profile/integration-profile.service.d.ts.map +1 -0
  53. package/dist/integration-profile/integration-profile.service.js +606 -0
  54. package/dist/integration-profile/integration-profile.service.js.map +1 -0
  55. package/dist/integration-profile/integration-profile.utils.d.ts +24 -0
  56. package/dist/integration-profile/integration-profile.utils.d.ts.map +1 -0
  57. package/dist/integration-profile/integration-profile.utils.js +147 -0
  58. package/dist/integration-profile/integration-profile.utils.js.map +1 -0
  59. package/dist/mail/mail.module.d.ts.map +1 -1
  60. package/dist/mail/mail.module.js +27 -19
  61. package/dist/mail/mail.module.js.map +1 -1
  62. package/dist/mail/mail.service.d.ts +3 -2
  63. package/dist/mail/mail.service.d.ts.map +1 -1
  64. package/dist/mail/mail.service.js +25 -47
  65. package/dist/mail/mail.service.js.map +1 -1
  66. package/dist/mcp/mcp.module.js +2 -2
  67. package/dist/mcp/mcp.module.js.map +1 -1
  68. package/dist/mcp/tools/core-mail-profile.mcp-tools.d.ts +3 -15
  69. package/dist/mcp/tools/core-mail-profile.mcp-tools.d.ts.map +1 -1
  70. package/dist/mcp/tools/core-mail-profile.mcp-tools.js +12 -94
  71. package/dist/mcp/tools/core-mail-profile.mcp-tools.js.map +1 -1
  72. package/dist/mcp-chat/mcp-chat.service.d.ts.map +1 -1
  73. package/dist/mcp-chat/mcp-chat.service.js +17 -16
  74. package/dist/mcp-chat/mcp-chat.service.js.map +1 -1
  75. package/dist/setting/setting.service.d.ts.map +1 -1
  76. package/dist/setting/setting.service.js +0 -2
  77. package/dist/setting/setting.service.js.map +1 -1
  78. package/dist/webhook-integration/event-webhook.controller.d.ts +1 -0
  79. package/dist/webhook-integration/event-webhook.controller.d.ts.map +1 -1
  80. package/dist/webhook-integration/event-webhook.controller.js +10 -0
  81. package/dist/webhook-integration/event-webhook.controller.js.map +1 -1
  82. package/dist/webhook-integration/event-webhook.service.d.ts +2 -0
  83. package/dist/webhook-integration/event-webhook.service.d.ts.map +1 -1
  84. package/dist/webhook-integration/event-webhook.service.js +30 -0
  85. package/dist/webhook-integration/event-webhook.service.js.map +1 -1
  86. package/dist/webhook-integration/webhook-integration.controller.d.ts +1 -0
  87. package/dist/webhook-integration/webhook-integration.controller.d.ts.map +1 -1
  88. package/dist/webhook-integration/webhook-integration.controller.js +10 -0
  89. package/dist/webhook-integration/webhook-integration.controller.js.map +1 -1
  90. package/dist/webhook-integration/webhook-integration.service.d.ts +2 -1
  91. package/dist/webhook-integration/webhook-integration.service.d.ts.map +1 -1
  92. package/dist/webhook-integration/webhook-integration.service.js +62 -44
  93. package/dist/webhook-integration/webhook-integration.service.js.map +1 -1
  94. package/dist/whatsapp-profile/dto/create.dto.d.ts +11 -0
  95. package/dist/whatsapp-profile/dto/create.dto.d.ts.map +1 -0
  96. package/dist/whatsapp-profile/dto/create.dto.js +55 -0
  97. package/dist/whatsapp-profile/dto/create.dto.js.map +1 -0
  98. package/dist/whatsapp-profile/dto/update.dto.d.ts +6 -0
  99. package/dist/whatsapp-profile/dto/update.dto.d.ts.map +1 -0
  100. package/dist/whatsapp-profile/dto/update.dto.js +9 -0
  101. package/dist/whatsapp-profile/dto/update.dto.js.map +1 -0
  102. package/dist/whatsapp-profile/whatsapp-profile.controller.d.ts +54 -0
  103. package/dist/whatsapp-profile/whatsapp-profile.controller.d.ts.map +1 -0
  104. package/dist/whatsapp-profile/whatsapp-profile.controller.js +85 -0
  105. package/dist/whatsapp-profile/whatsapp-profile.controller.js.map +1 -0
  106. package/dist/whatsapp-profile/whatsapp-profile.module.d.ts +3 -0
  107. package/dist/whatsapp-profile/whatsapp-profile.module.d.ts.map +1 -0
  108. package/dist/whatsapp-profile/whatsapp-profile.module.js +26 -0
  109. package/dist/whatsapp-profile/whatsapp-profile.module.js.map +1 -0
  110. package/dist/whatsapp-profile/whatsapp-profile.service.d.ts +63 -0
  111. package/dist/whatsapp-profile/whatsapp-profile.service.d.ts.map +1 -0
  112. package/dist/whatsapp-profile/whatsapp-profile.service.js +138 -0
  113. package/dist/whatsapp-profile/whatsapp-profile.service.js.map +1 -0
  114. package/hedhog/data/file_provider.yaml +9 -1
  115. package/hedhog/data/integration_provider.yaml +132 -0
  116. package/hedhog/data/integration_type.yaml +29 -0
  117. package/hedhog/data/menu.yaml +15 -14
  118. package/hedhog/data/role.yaml +8 -0
  119. package/hedhog/data/route.yaml +66 -15
  120. package/hedhog/data/setting_group.yaml +30 -191
  121. package/hedhog/data/setting_subgroup.yaml +5 -13
  122. package/hedhog/data/whatsapp_profile.yaml +6 -0
  123. package/hedhog/frontend/app/account/components/connected-accounts.tsx.ejs +25 -20
  124. package/hedhog/frontend/app/configurations/[slug]/components/setting-field.tsx.ejs +579 -204
  125. package/hedhog/frontend/app/integration/profiles/page.tsx.ejs +1662 -0
  126. package/hedhog/frontend/app/integrations-webhooks/page.tsx.ejs +233 -108
  127. package/hedhog/frontend/app/mail/profiles/page.tsx.ejs +3 -822
  128. package/hedhog/frontend/app/users/permissions.tsx.ejs +79 -2
  129. package/hedhog/frontend/app/users/user-sheet.tsx.ejs +7 -2
  130. package/hedhog/frontend/messages/en.json +172 -0
  131. package/hedhog/frontend/messages/pt.json +172 -0
  132. package/hedhog/table/integration_profile.yaml +34 -0
  133. package/hedhog/table/integration_provider.yaml +23 -0
  134. package/hedhog/table/integration_type.yaml +19 -0
  135. package/hedhog/table/webhook_action.yaml +85 -85
  136. package/hedhog/table/whatsapp_profile.yaml +26 -0
  137. package/package.json +2 -2
  138. package/src/ai/ai.service.ts +35 -153
  139. package/src/core.module.ts +3 -3
  140. package/src/file/file.service.ts +60 -76
  141. package/src/file/provider/provider.enum.ts +1 -0
  142. package/src/file/provider/provider.factory.ts +3 -0
  143. package/src/file/provider/spaces.provider.ts +261 -0
  144. package/src/index.ts +6 -3
  145. package/src/integration-profile/dto/create.dto.ts +44 -0
  146. package/src/integration-profile/dto/export.dto.ts +15 -0
  147. package/src/integration-profile/dto/import-confirm.dto.ts +61 -0
  148. package/src/integration-profile/dto/update.dto.ts +4 -0
  149. package/src/integration-profile/integration-profile.controller.ts +129 -0
  150. package/src/integration-profile/integration-profile.module.ts +16 -0
  151. package/src/integration-profile/integration-profile.service.ts +788 -0
  152. package/src/integration-profile/integration-profile.utils.ts +156 -0
  153. package/src/mail/mail.module.ts +27 -18
  154. package/src/mail/mail.service.ts +31 -60
  155. package/src/mcp/mcp.module.ts +2 -2
  156. package/src/mcp/tools/core-mail-profile.mcp-tools.ts +10 -69
  157. package/src/mcp-chat/mcp-chat.service.ts +23 -20
  158. package/src/setting/setting.service.ts +0 -2
  159. package/src/webhook-integration/event-webhook.controller.ts +55 -50
  160. package/src/webhook-integration/event-webhook.service.ts +422 -384
  161. package/src/webhook-integration/webhook-integration.controller.ts +5 -0
  162. package/src/webhook-integration/webhook-integration.service.ts +74 -46
  163. package/src/whatsapp-profile/dto/create.dto.ts +36 -0
  164. package/src/whatsapp-profile/dto/update.dto.ts +4 -0
  165. package/src/whatsapp-profile/whatsapp-profile.controller.ts +51 -0
  166. package/src/whatsapp-profile/whatsapp-profile.module.ts +13 -0
  167. package/src/whatsapp-profile/whatsapp-profile.service.ts +160 -0
@@ -1,822 +1,3 @@
1
- 'use client';
2
-
3
- import type React from 'react';
4
-
5
- import {
6
- EmptyState,
7
- Page,
8
- PageHeader,
9
- PaginationFooter,
10
- SearchBar,
11
- } from '@/components/entity-list';
12
- import {
13
- AlertDialog,
14
- AlertDialogAction,
15
- AlertDialogCancel,
16
- AlertDialogContent,
17
- AlertDialogDescription,
18
- AlertDialogFooter,
19
- AlertDialogHeader,
20
- AlertDialogTitle,
21
- } from '@/components/ui/alert-dialog';
22
- import { Badge } from '@/components/ui/badge';
23
- import { Button } from '@/components/ui/button';
24
- import { Input } from '@/components/ui/input';
25
- import { Label } from '@/components/ui/label';
26
- import {
27
- Select,
28
- SelectContent,
29
- SelectItem,
30
- SelectTrigger,
31
- SelectValue,
32
- } from '@/components/ui/select';
33
- import { ResizableSheetContent } from '@/components/ui/resizable-sheet-content';
34
- import {
35
- Sheet,
36
- SheetDescription,
37
- SheetHeader,
38
- SheetTitle,
39
- } from '@/components/ui/sheet';
40
- import { Switch } from '@/components/ui/switch';
41
- import {
42
- Table,
43
- TableBody,
44
- TableCell,
45
- TableHead,
46
- TableHeader,
47
- TableRow,
48
- } from '@/components/ui/table';
49
- import { usePagination } from '@/hooks/use-pagination';
50
- import { formatDate } from '@/lib/format-date';
51
- import { useApp } from '@hed-hog/next-app-provider';
52
- import { Mail, Pencil, Send, Trash2 } from 'lucide-react';
53
- import { useTranslations } from 'next-intl';
54
- import { useEffect, useState } from 'react';
55
- import { toast } from 'sonner';
56
-
57
- type ProviderType = 'SMTP' | 'GMAIL' | 'SES';
58
-
59
- type MailProfile = {
60
- id: number;
61
- slug: string;
62
- name: string;
63
- provider: ProviderType;
64
- from_name?: string | null;
65
- from_email: string;
66
- reply_to_name?: string | null;
67
- reply_to_email?: string | null;
68
- smtp_host?: string | null;
69
- smtp_port?: number | null;
70
- smtp_secure?: boolean;
71
- smtp_username?: string | null;
72
- smtp_password?: string | null;
73
- gmail_client_id?: string | null;
74
- gmail_client_secret?: string | null;
75
- gmail_refresh_token?: string | null;
76
- ses_access_key_id?: string | null;
77
- ses_secret_access_key?: string | null;
78
- ses_region?: string | null;
79
- created_at: string;
80
- updated_at: string;
81
- };
82
-
83
- type MailProfileForm = {
84
- slug: string;
85
- name: string;
86
- provider: ProviderType;
87
- from_name: string;
88
- from_email: string;
89
- reply_to_name: string;
90
- reply_to_email: string;
91
- smtp_host: string;
92
- smtp_port: string;
93
- smtp_secure: boolean;
94
- smtp_username: string;
95
- smtp_password: string;
96
- gmail_client_id: string;
97
- gmail_client_secret: string;
98
- gmail_refresh_token: string;
99
- ses_access_key_id: string;
100
- ses_secret_access_key: string;
101
- ses_region: string;
102
- };
103
-
104
- const defaultFormData = (): MailProfileForm => ({
105
- slug: '',
106
- name: '',
107
- provider: 'SMTP',
108
- from_name: '',
109
- from_email: '',
110
- reply_to_name: '',
111
- reply_to_email: '',
112
- smtp_host: '',
113
- smtp_port: '587',
114
- smtp_secure: true,
115
- smtp_username: '',
116
- smtp_password: '',
117
- gmail_client_id: '',
118
- gmail_client_secret: '',
119
- gmail_refresh_token: '',
120
- ses_access_key_id: '',
121
- ses_secret_access_key: '',
122
- ses_region: '',
123
- });
124
-
125
- export default function MailProfilesPage() {
126
- const t = useTranslations('core.MailProfilePage');
127
- const { request, currentLocaleCode, getSettingValue } = useApp();
128
- const {
129
- items,
130
- refetch,
131
- page,
132
- setPage,
133
- pageSize,
134
- setPageSize,
135
- totalItems,
136
- search,
137
- setSearch,
138
- } = usePagination({ url: '/mail-profile' });
139
-
140
- const [profiles, setProfiles] = useState<MailProfile[]>([]);
141
- const [isDialogOpen, setIsDialogOpen] = useState(false);
142
- const [isDeleteDialogOpen, setIsDeleteDialogOpen] = useState(false);
143
- const [profileToDelete, setProfileToDelete] = useState<number | null>(null);
144
- const [selectedProfile, setSelectedProfile] = useState<MailProfile | null>(
145
- null
146
- );
147
- const [editMode, setEditMode] = useState(false);
148
- const [formData, setFormData] = useState<MailProfileForm>(defaultFormData());
149
- const [isTesting, setIsTesting] = useState(false);
150
- const [testedSignature, setTestedSignature] = useState<string | null>(null);
151
-
152
- useEffect(() => {
153
- setProfiles(Array.isArray(items) ? (items as MailProfile[]) : []);
154
- }, [items]);
155
-
156
- const handleCreate = () => {
157
- setEditMode(false);
158
- setSelectedProfile(null);
159
- setFormData(defaultFormData());
160
- setTestedSignature(null);
161
- setIsDialogOpen(true);
162
- };
163
-
164
- const handleEdit = async (profile: MailProfile) => {
165
- setEditMode(true);
166
- setSelectedProfile(profile);
167
- setTestedSignature(null);
168
- setIsDialogOpen(true);
169
-
170
- try {
171
- const { data } = await request<MailProfile>({
172
- url: `/mail-profile/${profile.id}`,
173
- method: 'GET',
174
- });
175
-
176
- setFormData({
177
- slug: data.slug ?? '',
178
- name: data.name ?? '',
179
- provider: data.provider ?? 'SMTP',
180
- from_name: data.from_name ?? '',
181
- from_email: data.from_email ?? '',
182
- reply_to_name: data.reply_to_name ?? '',
183
- reply_to_email: data.reply_to_email ?? '',
184
- smtp_host: data.smtp_host ?? '',
185
- smtp_port: data.smtp_port ? String(data.smtp_port) : '587',
186
- smtp_secure: Boolean(data.smtp_secure),
187
- smtp_username: data.smtp_username ?? '',
188
- smtp_password: data.smtp_password ?? '',
189
- gmail_client_id: data.gmail_client_id ?? '',
190
- gmail_client_secret: data.gmail_client_secret ?? '',
191
- gmail_refresh_token: data.gmail_refresh_token ?? '',
192
- ses_access_key_id: data.ses_access_key_id ?? '',
193
- ses_secret_access_key: data.ses_secret_access_key ?? '',
194
- ses_region: data.ses_region ?? '',
195
- });
196
- } catch (error) {
197
- console.error('Error loading mail profile:', error);
198
- toast.error(t('loadError'));
199
- }
200
- };
201
-
202
- const handleDelete = (id: number) => {
203
- setProfileToDelete(id);
204
- setIsDeleteDialogOpen(true);
205
- };
206
-
207
- const confirmDelete = async () => {
208
- if (profileToDelete === null) {
209
- return;
210
- }
211
-
212
- try {
213
- await request({
214
- url: '/mail-profile',
215
- method: 'DELETE',
216
- data: { ids: [profileToDelete] },
217
- });
218
- toast.success(t('deleteSuccess'));
219
- setProfileToDelete(null);
220
- setIsDeleteDialogOpen(false);
221
- refetch();
222
- } catch (error) {
223
- console.error('Error deleting mail profile:', error);
224
- toast.error(t('deleteError'));
225
- }
226
- };
227
-
228
- const updateFormField = <K extends keyof MailProfileForm>(
229
- field: K,
230
- value: MailProfileForm[K]
231
- ) => {
232
- setFormData((current) => ({
233
- ...current,
234
- [field]: value,
235
- }));
236
- };
237
-
238
- const handleProviderChange = (provider: ProviderType) => {
239
- setFormData((current) => ({
240
- ...current,
241
- provider,
242
- }));
243
- };
244
-
245
- const createPayload = () => ({
246
- slug: formData.slug,
247
- name: formData.name,
248
- provider: formData.provider,
249
- from_name: formData.from_name || undefined,
250
- from_email: formData.from_email,
251
- reply_to_name: formData.reply_to_name || undefined,
252
- reply_to_email: formData.reply_to_email || undefined,
253
- smtp_host: formData.smtp_host || undefined,
254
- smtp_port: formData.smtp_port ? Number(formData.smtp_port) : undefined,
255
- smtp_secure: formData.smtp_secure,
256
- smtp_username: formData.smtp_username || undefined,
257
- smtp_password: formData.smtp_password || undefined,
258
- gmail_client_id: formData.gmail_client_id || undefined,
259
- gmail_client_secret: formData.gmail_client_secret || undefined,
260
- gmail_refresh_token: formData.gmail_refresh_token || undefined,
261
- ses_access_key_id: formData.ses_access_key_id || undefined,
262
- ses_secret_access_key: formData.ses_secret_access_key || undefined,
263
- ses_region: formData.ses_region || undefined,
264
- });
265
-
266
- const currentSignature = JSON.stringify(createPayload());
267
-
268
- const canSubmitProfile = testedSignature === currentSignature;
269
-
270
- const handleTest = async () => {
271
- const payload = createPayload();
272
-
273
- try {
274
- setIsTesting(true);
275
- const { data } = await request<{ success: boolean; destination: string }>({
276
- url: '/mail-profile/test',
277
- method: 'POST',
278
- data: payload,
279
- });
280
-
281
- setTestedSignature(JSON.stringify(payload));
282
- toast.success(
283
- t('testSuccess', {
284
- email: data.destination || payload.from_email,
285
- })
286
- );
287
- } catch (error) {
288
- console.error('Error testing mail profile:', error);
289
- setTestedSignature(null);
290
- toast.error(t('testError'));
291
- } finally {
292
- setIsTesting(false);
293
- }
294
- };
295
-
296
- const handleSubmit = async (event: React.FormEvent) => {
297
- event.preventDefault();
298
-
299
- const payload = createPayload();
300
-
301
- try {
302
- if (editMode && selectedProfile) {
303
- await request({
304
- url: `/mail-profile/${selectedProfile.id}`,
305
- method: 'PATCH',
306
- data: payload,
307
- });
308
- toast.success(t('updateSuccess'));
309
- } else {
310
- await request({
311
- url: '/mail-profile',
312
- method: 'POST',
313
- data: payload,
314
- });
315
- toast.success(t('createSuccess'));
316
- }
317
-
318
- setIsDialogOpen(false);
319
- setTestedSignature(null);
320
- refetch();
321
- } catch (error) {
322
- console.error('Error saving mail profile:', error);
323
- toast.error(editMode ? t('updateError') : t('createError'));
324
- }
325
- };
326
-
327
- const renderSender = (profile: MailProfile) => {
328
- if (profile.from_name) {
329
- return `${profile.from_name} <${profile.from_email}>`;
330
- }
331
-
332
- return profile.from_email;
333
- };
334
-
335
- const renderReplyTo = (profile: MailProfile) => {
336
- if (!profile.reply_to_email) {
337
- return t('notConfigured');
338
- }
339
-
340
- if (profile.reply_to_name) {
341
- return `${profile.reply_to_name} <${profile.reply_to_email}>`;
342
- }
343
-
344
- return profile.reply_to_email;
345
- };
346
-
347
- return (
348
- <Page>
349
- <PageHeader
350
- breadcrumbs={[
351
- { label: t('breadcrumbHome'), href: '/' },
352
- { label: t('breadcrumbTitle') },
353
- ]}
354
- actions={[
355
- {
356
- label: t('newProfile'),
357
- onClick: handleCreate,
358
- variant: 'default' as const,
359
- },
360
- ]}
361
- title={t('title')}
362
- description={t('description')}
363
- />
364
-
365
- <SearchBar
366
- searchQuery={search}
367
- onSearchChange={(value) => {
368
- setSearch(value);
369
- setPage(1);
370
- }}
371
- onSearch={() => setPage(1)}
372
- placeholder={t('searchPlaceholder')}
373
- />
374
-
375
- {profiles.length === 0 ? (
376
- <EmptyState
377
- icon={<Send className="h-12 w-12" />}
378
- title={t('noProfilesFound')}
379
- description={t('noProfilesHint')}
380
- actionLabel={t('newProfile')}
381
- onAction={handleCreate}
382
- />
383
- ) : (
384
- <div className="rounded-md border">
385
- <Table>
386
- <TableHeader>
387
- <TableRow>
388
- <TableHead>{t('tableName')}</TableHead>
389
- <TableHead>{t('tableSlug')}</TableHead>
390
- <TableHead>{t('tableProvider')}</TableHead>
391
- <TableHead>{t('tableSender')}</TableHead>
392
- <TableHead>{t('tableReplyTo')}</TableHead>
393
- <TableHead>{t('tableUpdated')}</TableHead>
394
- <TableHead className="text-right">
395
- {t('tableActions')}
396
- </TableHead>
397
- </TableRow>
398
- </TableHeader>
399
- <TableBody>
400
- {profiles.map((profile) => (
401
- <TableRow
402
- key={profile.id}
403
- className="cursor-pointer"
404
- onDoubleClick={() => handleEdit(profile)}
405
- >
406
- <TableCell className="font-medium">{profile.name}</TableCell>
407
- <TableCell className="font-mono text-sm">
408
- {profile.slug}
409
- </TableCell>
410
- <TableCell>
411
- <Badge variant="secondary">{profile.provider}</Badge>
412
- </TableCell>
413
- <TableCell>{renderSender(profile)}</TableCell>
414
- <TableCell>{renderReplyTo(profile)}</TableCell>
415
- <TableCell className="text-muted-foreground">
416
- {formatDate(
417
- profile.updated_at,
418
- getSettingValue,
419
- currentLocaleCode
420
- )}
421
- </TableCell>
422
- <TableCell className="text-right">
423
- <div className="flex justify-end gap-2">
424
- <Button
425
- variant="ghost"
426
- size="icon"
427
- onClick={(event) => {
428
- event.stopPropagation();
429
- handleEdit(profile);
430
- }}
431
- >
432
- <Pencil className="h-4 w-4" />
433
- </Button>
434
- <Button
435
- variant="ghost"
436
- size="icon"
437
- onClick={(event) => {
438
- event.stopPropagation();
439
- handleDelete(profile.id);
440
- }}
441
- >
442
- <Trash2 className="h-4 w-4 text-destructive" />
443
- </Button>
444
- </div>
445
- </TableCell>
446
- </TableRow>
447
- ))}
448
- </TableBody>
449
- </Table>
450
- </div>
451
- )}
452
-
453
- <PaginationFooter
454
- currentPage={page}
455
- pageSize={pageSize}
456
- totalItems={totalItems}
457
- onPageChange={setPage}
458
- onPageSizeChange={(newSize) => {
459
- setPageSize(newSize);
460
- setPage(1);
461
- }}
462
- />
463
-
464
- <Sheet open={isDialogOpen} onOpenChange={setIsDialogOpen}>
465
- <ResizableSheetContent sheetId="mail-profile-editor" defaultWidth={896}>
466
- <SheetHeader>
467
- <SheetTitle>
468
- {editMode ? t('editProfile') : t('newProfileTitle')}
469
- </SheetTitle>
470
- <SheetDescription>
471
- {editMode
472
- ? t('editProfileDescription')
473
- : t('newProfileDescription')}
474
- </SheetDescription>
475
- </SheetHeader>
476
-
477
- <form onSubmit={handleSubmit} className="space-y-6 px-3 pb-8 sm:px-4">
478
- <div className="grid gap-6 md:grid-cols-2">
479
- <div className="space-y-2">
480
- <Label htmlFor="name">{t('nameLabel')}</Label>
481
- <Input
482
- id="name"
483
- value={formData.name}
484
- onChange={(event) =>
485
- updateFormField('name', event.target.value)
486
- }
487
- placeholder={t('namePlaceholder')}
488
- required
489
- />
490
- </div>
491
-
492
- <div className="space-y-2">
493
- <Label htmlFor="slug">{t('slugLabel')}</Label>
494
- <Input
495
- id="slug"
496
- value={formData.slug}
497
- onChange={(event) =>
498
- updateFormField('slug', event.target.value)
499
- }
500
- placeholder={t('slugPlaceholder')}
501
- required
502
- />
503
- </div>
504
-
505
- <div className="space-y-2">
506
- <Label htmlFor="provider">{t('providerLabel')}</Label>
507
- <Select
508
- value={formData.provider}
509
- onValueChange={handleProviderChange}
510
- >
511
- <SelectTrigger className="w-full" id="provider">
512
- <SelectValue />
513
- </SelectTrigger>
514
- <SelectContent>
515
- <SelectItem value="SMTP">{t('providerSMTP')}</SelectItem>
516
- <SelectItem value="GMAIL">{t('providerGmail')}</SelectItem>
517
- <SelectItem value="SES">{t('providerSES')}</SelectItem>
518
- </SelectContent>
519
- </Select>
520
- </div>
521
-
522
- <div className="space-y-2">
523
- <Label htmlFor="from-email">{t('fromEmailLabel')}</Label>
524
- <Input
525
- id="from-email"
526
- type="email"
527
- value={formData.from_email}
528
- onChange={(event) =>
529
- updateFormField('from_email', event.target.value)
530
- }
531
- placeholder={t('fromEmailPlaceholder')}
532
- required
533
- />
534
- </div>
535
-
536
- <div className="space-y-2">
537
- <Label htmlFor="from-name">{t('fromNameLabel')}</Label>
538
- <Input
539
- id="from-name"
540
- value={formData.from_name}
541
- onChange={(event) =>
542
- updateFormField('from_name', event.target.value)
543
- }
544
- placeholder={t('fromNamePlaceholder')}
545
- />
546
- </div>
547
-
548
- <div className="space-y-2">
549
- <Label htmlFor="reply-to-email">{t('replyToEmailLabel')}</Label>
550
- <Input
551
- id="reply-to-email"
552
- type="email"
553
- value={formData.reply_to_email}
554
- onChange={(event) =>
555
- updateFormField('reply_to_email', event.target.value)
556
- }
557
- placeholder={t('replyToEmailPlaceholder')}
558
- />
559
- </div>
560
-
561
- <div className="space-y-2">
562
- <Label htmlFor="reply-to-name">{t('replyToNameLabel')}</Label>
563
- <Input
564
- id="reply-to-name"
565
- value={formData.reply_to_name}
566
- onChange={(event) =>
567
- updateFormField('reply_to_name', event.target.value)
568
- }
569
- placeholder={t('replyToNamePlaceholder')}
570
- />
571
- </div>
572
- </div>
573
-
574
- {formData.provider === 'SMTP' ? (
575
- <div className="space-y-4 rounded-lg border p-4">
576
- <div className="flex items-center gap-2">
577
- <Mail className="h-4 w-4" />
578
- <h3 className="text-sm font-semibold">
579
- {t('smtpSectionTitle')}
580
- </h3>
581
- </div>
582
- <div className="grid gap-6 md:grid-cols-2">
583
- <div className="space-y-2">
584
- <Label htmlFor="smtp-host">{t('smtpHostLabel')}</Label>
585
- <Input
586
- id="smtp-host"
587
- value={formData.smtp_host}
588
- onChange={(event) =>
589
- updateFormField('smtp_host', event.target.value)
590
- }
591
- placeholder={t('smtpHostPlaceholder')}
592
- required
593
- />
594
- </div>
595
- <div className="space-y-2">
596
- <Label htmlFor="smtp-port">{t('smtpPortLabel')}</Label>
597
- <Input
598
- id="smtp-port"
599
- type="number"
600
- min="1"
601
- value={formData.smtp_port}
602
- onChange={(event) =>
603
- updateFormField('smtp_port', event.target.value)
604
- }
605
- placeholder={t('smtpPortPlaceholder')}
606
- required
607
- />
608
- </div>
609
- <div className="space-y-2">
610
- <Label htmlFor="smtp-username">
611
- {t('smtpUsernameLabel')}
612
- </Label>
613
- <Input
614
- id="smtp-username"
615
- value={formData.smtp_username}
616
- onChange={(event) =>
617
- updateFormField('smtp_username', event.target.value)
618
- }
619
- placeholder={t('smtpUsernamePlaceholder')}
620
- required
621
- />
622
- </div>
623
- <div className="space-y-2">
624
- <Label htmlFor="smtp-password">
625
- {t('smtpPasswordLabel')}
626
- </Label>
627
- <Input
628
- id="smtp-password"
629
- type="password"
630
- value={formData.smtp_password}
631
- onChange={(event) =>
632
- updateFormField('smtp_password', event.target.value)
633
- }
634
- placeholder={t('smtpPasswordPlaceholder')}
635
- required
636
- />
637
- </div>
638
- </div>
639
- <div className="flex items-center justify-between rounded-md border px-4 py-3">
640
- <div className="space-y-1">
641
- <p className="text-sm font-medium">
642
- {t('smtpSecureLabel')}
643
- </p>
644
- <p className="text-xs text-muted-foreground">
645
- {t('smtpSecureHelp')}
646
- </p>
647
- </div>
648
- <Switch
649
- checked={formData.smtp_secure}
650
- onCheckedChange={(checked) =>
651
- updateFormField('smtp_secure', checked)
652
- }
653
- />
654
- </div>
655
- </div>
656
- ) : null}
657
-
658
- {formData.provider === 'GMAIL' ? (
659
- <div className="space-y-4 rounded-lg border p-4">
660
- <div className="flex items-center gap-2">
661
- <Mail className="h-4 w-4" />
662
- <h3 className="text-sm font-semibold">
663
- {t('gmailSectionTitle')}
664
- </h3>
665
- </div>
666
- <div className="grid gap-6 md:grid-cols-2">
667
- <div className="space-y-2">
668
- <Label htmlFor="gmail-client-id">
669
- {t('gmailClientIdLabel')}
670
- </Label>
671
- <Input
672
- id="gmail-client-id"
673
- value={formData.gmail_client_id}
674
- onChange={(event) =>
675
- updateFormField('gmail_client_id', event.target.value)
676
- }
677
- placeholder={t('gmailClientIdPlaceholder')}
678
- required
679
- />
680
- </div>
681
- <div className="space-y-2">
682
- <Label htmlFor="gmail-client-secret">
683
- {t('gmailClientSecretLabel')}
684
- </Label>
685
- <Input
686
- id="gmail-client-secret"
687
- type="password"
688
- value={formData.gmail_client_secret}
689
- onChange={(event) =>
690
- updateFormField(
691
- 'gmail_client_secret',
692
- event.target.value
693
- )
694
- }
695
- placeholder={t('gmailClientSecretPlaceholder')}
696
- required
697
- />
698
- </div>
699
- <div className="space-y-2 md:col-span-2">
700
- <Label htmlFor="gmail-refresh-token">
701
- {t('gmailRefreshTokenLabel')}
702
- </Label>
703
- <Input
704
- id="gmail-refresh-token"
705
- type="password"
706
- value={formData.gmail_refresh_token}
707
- onChange={(event) =>
708
- updateFormField(
709
- 'gmail_refresh_token',
710
- event.target.value
711
- )
712
- }
713
- placeholder={t('gmailRefreshTokenPlaceholder')}
714
- required
715
- />
716
- </div>
717
- </div>
718
- </div>
719
- ) : null}
720
-
721
- {formData.provider === 'SES' ? (
722
- <div className="space-y-4 rounded-lg border p-4">
723
- <div className="flex items-center gap-2">
724
- <Mail className="h-4 w-4" />
725
- <h3 className="text-sm font-semibold">
726
- {t('sesSectionTitle')}
727
- </h3>
728
- </div>
729
- <div className="grid gap-6 md:grid-cols-2">
730
- <div className="space-y-2">
731
- <Label htmlFor="ses-access-key-id">
732
- {t('sesAccessKeyIdLabel')}
733
- </Label>
734
- <Input
735
- id="ses-access-key-id"
736
- value={formData.ses_access_key_id}
737
- onChange={(event) =>
738
- updateFormField('ses_access_key_id', event.target.value)
739
- }
740
- placeholder={t('sesAccessKeyIdPlaceholder')}
741
- required
742
- />
743
- </div>
744
- <div className="space-y-2">
745
- <Label htmlFor="ses-secret-access-key">
746
- {t('sesSecretAccessKeyLabel')}
747
- </Label>
748
- <Input
749
- id="ses-secret-access-key"
750
- type="password"
751
- value={formData.ses_secret_access_key}
752
- onChange={(event) =>
753
- updateFormField(
754
- 'ses_secret_access_key',
755
- event.target.value
756
- )
757
- }
758
- placeholder={t('sesSecretAccessKeyPlaceholder')}
759
- required
760
- />
761
- </div>
762
- <div className="space-y-2">
763
- <Label htmlFor="ses-region">{t('sesRegionLabel')}</Label>
764
- <Input
765
- id="ses-region"
766
- value={formData.ses_region}
767
- onChange={(event) =>
768
- updateFormField('ses_region', event.target.value)
769
- }
770
- placeholder={t('sesRegionPlaceholder')}
771
- required
772
- />
773
- </div>
774
- </div>
775
- </div>
776
- ) : null}
777
-
778
- <div className="flex justify-end border-t pt-4">
779
- {canSubmitProfile ? (
780
- <Button type="submit" className="min-w-40">
781
- {editMode ? t('saveChanges') : t('createProfile')}
782
- </Button>
783
- ) : (
784
- <Button
785
- type="button"
786
- className="min-w-40"
787
- onClick={handleTest}
788
- disabled={isTesting}
789
- >
790
- {isTesting ? t('testing') : t('testProfile')}
791
- </Button>
792
- )}
793
- </div>
794
- </form>
795
- </ResizableSheetContent>
796
- </Sheet>
797
-
798
- <AlertDialog
799
- open={isDeleteDialogOpen}
800
- onOpenChange={setIsDeleteDialogOpen}
801
- >
802
- <AlertDialogContent>
803
- <AlertDialogHeader>
804
- <AlertDialogTitle>{t('deleteConfirmTitle')}</AlertDialogTitle>
805
- <AlertDialogDescription>
806
- {t('deleteConfirmDescription')}
807
- </AlertDialogDescription>
808
- </AlertDialogHeader>
809
- <AlertDialogFooter>
810
- <AlertDialogCancel>{t('cancel')}</AlertDialogCancel>
811
- <AlertDialogAction
812
- onClick={confirmDelete}
813
- className="bg-destructive text-destructive-foreground hover:bg-destructive/90"
814
- >
815
- {t('delete')}
816
- </AlertDialogAction>
817
- </AlertDialogFooter>
818
- </AlertDialogContent>
819
- </AlertDialog>
820
- </Page>
821
- );
822
- }
1
+ 'use client';
2
+
3
+ export { default } from '../../integration/profiles/page';