@hed-hog/core 0.0.367 → 0.0.370

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 (62) hide show
  1. package/dist/file/file.service.d.ts +1 -0
  2. package/dist/file/file.service.d.ts.map +1 -1
  3. package/dist/file/file.service.js +1 -1
  4. package/dist/file/file.service.js.map +1 -1
  5. package/dist/notification/events/notification-stale-progress-check.event.d.ts +6 -0
  6. package/dist/notification/events/notification-stale-progress-check.event.d.ts.map +1 -0
  7. package/dist/notification/events/notification-stale-progress-check.event.js +11 -0
  8. package/dist/notification/events/notification-stale-progress-check.event.js.map +1 -0
  9. package/dist/notification/notification.service.d.ts +4 -1
  10. package/dist/notification/notification.service.d.ts.map +1 -1
  11. package/dist/notification/notification.service.js +9 -26
  12. package/dist/notification/notification.service.js.map +1 -1
  13. package/dist/task/task.service.d.ts +19 -0
  14. package/dist/task/task.service.d.ts.map +1 -1
  15. package/dist/task/task.service.js +46 -0
  16. package/dist/task/task.service.js.map +1 -1
  17. package/dist/user/user.controller.d.ts +23 -5
  18. package/dist/user/user.controller.d.ts.map +1 -1
  19. package/dist/user/user.controller.js +32 -15
  20. package/dist/user/user.controller.js.map +1 -1
  21. package/dist/user/user.service.d.ts +28 -8
  22. package/dist/user/user.service.d.ts.map +1 -1
  23. package/dist/user/user.service.js +120 -8
  24. package/dist/user/user.service.js.map +1 -1
  25. package/hedhog/data/integration_event_catalog.yaml +118 -118
  26. package/hedhog/data/route.yaml +162 -204
  27. package/hedhog/data/setting_group.yaml +14 -0
  28. package/hedhog/frontend/app/roles/page.tsx.ejs +4 -1
  29. package/hedhog/frontend/app/users/user-logs.tsx.ejs +190 -0
  30. package/hedhog/frontend/app/users/user-sheet.tsx.ejs +15 -1
  31. package/hedhog/frontend/messages/en.json +13 -0
  32. package/hedhog/frontend/messages/pt.json +13 -0
  33. package/hedhog/table/event_webhook.yaml +55 -55
  34. package/hedhog/table/event_webhook_delivery_log.yaml +66 -66
  35. package/hedhog/table/event_webhook_event.yaml +26 -26
  36. package/hedhog/table/integration_event_catalog.yaml +41 -41
  37. package/hedhog/table/mcp_conversation.yaml +12 -12
  38. package/hedhog/table/mcp_conversation_message.yaml +23 -23
  39. package/hedhog/table/mcp_tool_call_log.yaml +22 -22
  40. package/hedhog/table/route.yaml +33 -33
  41. package/hedhog/table/user_change_log.yaml +40 -0
  42. package/hedhog/table/webhook_call_log.yaml +46 -46
  43. package/hedhog/table/webhook_integration.yaml +43 -43
  44. package/package.json +5 -5
  45. package/src/file/file.service.ts +2 -1
  46. package/src/integration/types/event.types.ts +4 -4
  47. package/src/mcp/decorators/mcp-tool.decorator.ts +7 -7
  48. package/src/mcp/guards/mcp-permission.guard.ts +51 -51
  49. package/src/mcp/interfaces/mcp-tool-definition.interface.ts +6 -6
  50. package/src/mcp/mcp-server.service.ts +87 -87
  51. package/src/mcp/types/mcp-context.type.ts +6 -6
  52. package/src/mcp-chat/dto/create-conversation.dto.ts +7 -7
  53. package/src/mcp-chat/dto/send-message.dto.ts +7 -7
  54. package/src/notification/events/notification-stale-progress-check.event.ts +5 -0
  55. package/src/notification/notification.service.ts +12 -25
  56. package/src/route/dto/create.dto.ts +32 -32
  57. package/src/route/dto/update.dto.ts +31 -31
  58. package/src/task/task.service.ts +52 -0
  59. package/src/user/user.controller.ts +23 -9
  60. package/src/user/user.service.ts +183 -8
  61. package/src/webhook-integration/integration-event-catalog.controller.ts +50 -50
  62. package/src/webhook-integration/integration-event-catalog.service.ts +117 -117
@@ -0,0 +1,190 @@
1
+ 'use client';
2
+
3
+ import { EmptyState } from '@/components/entity-list';
4
+ import { formatDateTime } from '@/lib/format-date';
5
+ import { User } from '@hed-hog/api-types';
6
+ import { useApp, useQuery } from '@hed-hog/next-app-provider';
7
+ import {
8
+ Image as ImageIcon,
9
+ KeyRound,
10
+ Loader2,
11
+ Pencil,
12
+ ScrollText,
13
+ ShieldMinus,
14
+ ShieldPlus,
15
+ } from 'lucide-react';
16
+ import { useTranslations } from 'next-intl';
17
+
18
+ type UserChangeLog = {
19
+ id: string;
20
+ actorUserId: string | null;
21
+ actorName: string | null;
22
+ actorEmail: string | null;
23
+ action: string;
24
+ summary: string;
25
+ beforeData: string;
26
+ afterData: string;
27
+ ipAddress: string;
28
+ createdAt: string | null;
29
+ };
30
+
31
+ function getActionIcon(action: string) {
32
+ switch (action) {
33
+ case 'update':
34
+ return Pencil;
35
+ case 'reset_password':
36
+ return KeyRound;
37
+ case 'role_assigned':
38
+ return ShieldPlus;
39
+ case 'role_removed':
40
+ return ShieldMinus;
41
+ case 'avatar_changed':
42
+ return ImageIcon;
43
+ default:
44
+ return ScrollText;
45
+ }
46
+ }
47
+
48
+ function safeParse(raw: string): Record<string, unknown> | null {
49
+ if (!raw) return null;
50
+ try {
51
+ const parsed = JSON.parse(raw);
52
+ return parsed && typeof parsed === 'object' ? parsed : null;
53
+ } catch {
54
+ return null;
55
+ }
56
+ }
57
+
58
+ function formatValue(value: unknown) {
59
+ if (value === null || value === undefined || value === '') return '—';
60
+ return String(value);
61
+ }
62
+
63
+ function DiffList({ before, after }: { before: string; after: string }) {
64
+ const beforeObj = safeParse(before);
65
+ const afterObj = safeParse(after);
66
+
67
+ if (!beforeObj && !afterObj) return null;
68
+
69
+ const keys = Array.from(
70
+ new Set([
71
+ ...Object.keys(beforeObj ?? {}),
72
+ ...Object.keys(afterObj ?? {}),
73
+ ]),
74
+ );
75
+
76
+ if (!keys.length) return null;
77
+
78
+ return (
79
+ <div className="mt-2 space-y-1 rounded-md bg-muted/40 p-2">
80
+ {keys.map((key) => (
81
+ <div key={key} className="flex flex-wrap items-center gap-1 text-[11px]">
82
+ <span className="font-medium text-muted-foreground">{key}:</span>
83
+ {beforeObj && key in beforeObj && (
84
+ <span className="rounded bg-rose-50 px-1 py-0.5 text-rose-700 line-through">
85
+ {formatValue(beforeObj[key])}
86
+ </span>
87
+ )}
88
+ {afterObj && key in afterObj && (
89
+ <span className="rounded bg-emerald-50 px-1 py-0.5 text-emerald-700">
90
+ {formatValue(afterObj[key])}
91
+ </span>
92
+ )}
93
+ </div>
94
+ ))}
95
+ </div>
96
+ );
97
+ }
98
+
99
+ export function UserLogs({ editingUser }: { editingUser: User }) {
100
+ const { request, currentLocaleCode, getSettingValue } = useApp();
101
+ const t = useTranslations('core.UserChangeLog');
102
+ const userId = editingUser?.id;
103
+
104
+ const { data: logs = [], isLoading } = useQuery<UserChangeLog[]>({
105
+ queryKey: ['user-change-logs', userId, currentLocaleCode],
106
+ queryFn: async () => {
107
+ const response = await request<{ data: UserChangeLog[] }>({
108
+ url: `/user/${userId}/log`,
109
+ method: 'GET',
110
+ });
111
+ return response.data?.data || [];
112
+ },
113
+ enabled: !!userId,
114
+ });
115
+
116
+ const knownActions = [
117
+ 'update',
118
+ 'reset_password',
119
+ 'role_assigned',
120
+ 'role_removed',
121
+ 'avatar_changed',
122
+ ];
123
+ const getActionLabel = (action: string) =>
124
+ knownActions.includes(action) ? t(action as never) : action;
125
+
126
+ if (isLoading) {
127
+ return (
128
+ <div className="flex items-center justify-center py-8 text-muted-foreground">
129
+ <Loader2 className="h-5 w-5 animate-spin" />
130
+ </div>
131
+ );
132
+ }
133
+
134
+ return (
135
+ <div className="space-y-3">
136
+ <h4 className="text-sm font-medium">{t('title')}</h4>
137
+
138
+ <div className="space-y-2">
139
+ {logs.length ? (
140
+ logs.map((log) => {
141
+ const Icon = getActionIcon(log.action);
142
+ const actor =
143
+ log.actorName || log.actorEmail || t('systemActor');
144
+
145
+ return (
146
+ <div key={log.id} className="rounded-lg border p-3">
147
+ <div className="flex items-start gap-3">
148
+ <div className="rounded-md bg-slate-50 p-2">
149
+ <Icon className="h-5 w-5 text-muted-foreground" />
150
+ </div>
151
+ <div className="flex-1">
152
+ <div className="flex flex-wrap items-center justify-between gap-2">
153
+ <p className="text-sm font-medium">
154
+ {getActionLabel(log.action)}
155
+ </p>
156
+ {log.createdAt && (
157
+ <span className="text-[11px] text-muted-foreground">
158
+ {formatDateTime(
159
+ log.createdAt,
160
+ getSettingValue,
161
+ currentLocaleCode,
162
+ )}
163
+ </span>
164
+ )}
165
+ </div>
166
+ <p className="text-xs text-muted-foreground">
167
+ {t('byActor')} {actor}
168
+ </p>
169
+ {log.summary && (
170
+ <p className="mt-1 text-xs text-muted-foreground">
171
+ {log.summary}
172
+ </p>
173
+ )}
174
+ <DiffList before={log.beforeData} after={log.afterData} />
175
+ </div>
176
+ </div>
177
+ </div>
178
+ );
179
+ })
180
+ ) : (
181
+ <EmptyState
182
+ icon={<ScrollText className="h-6 w-6" />}
183
+ title={t('emptyTitle')}
184
+ description={t('emptyDescription')}
185
+ />
186
+ )}
187
+ </div>
188
+ </div>
189
+ );
190
+ }
@@ -66,6 +66,7 @@ import {
66
66
  LucideIcon,
67
67
  Mail,
68
68
  Monitor,
69
+ ScrollText,
69
70
  RefreshCcw,
70
71
  Save,
71
72
  Shield,
@@ -84,6 +85,7 @@ import { z } from 'zod';
84
85
  import { ActiveSessions } from './active-session';
85
86
  import { UserIdentifiersSection } from './identifiers';
86
87
  import { PermissionsSection } from './permissions';
88
+ import { UserLogs } from './user-logs';
87
89
 
88
90
  export type UserSheetProps = {
89
91
  open: boolean;
@@ -765,6 +767,10 @@ function UserEditSheet({
765
767
  <Monitor className="h-4 w-4" />
766
768
  <span>{t('tabSessions')}</span>
767
769
  </TabsTrigger>
770
+ <TabsTrigger value="logs">
771
+ <ScrollText className="h-4 w-4" />
772
+ <span>{t('tabLogs')}</span>
773
+ </TabsTrigger>
768
774
  </TabsList>
769
775
  </div>
770
776
 
@@ -1110,7 +1116,10 @@ function UserEditSheet({
1110
1116
  <FormActions
1111
1117
  statusContent={editDraftStatusContent}
1112
1118
  cancelLabel={t('cancel')}
1113
- onCancel={() => onOpenChange(false)}
1119
+ onCancel={() => {
1120
+ clearEditDraft();
1121
+ onOpenChange(false);
1122
+ }}
1114
1123
  submitLabel={t('saveChanges')}
1115
1124
  submitType="submit"
1116
1125
  className="pt-2"
@@ -1478,6 +1487,11 @@ function UserEditSheet({
1478
1487
  refetch={handleRefreshUser}
1479
1488
  />
1480
1489
  </TabsContent>
1490
+
1491
+ {/* Logs Tab */}
1492
+ <TabsContent value="logs" className="space-y-4 mt-4 p-4 pt-0">
1493
+ <UserLogs editingUser={editingUser} />
1494
+ </TabsContent>
1481
1495
  </Tabs>
1482
1496
  </ResizableSheetContent>
1483
1497
  </Sheet>
@@ -244,6 +244,7 @@
244
244
  "tabIdentifiers": "Identifiers",
245
245
  "tabMfa": "MFA",
246
246
  "tabSessions": "Sessions",
247
+ "tabLogs": "Logs",
247
248
  "cardLastLoginDescription": "Last Login",
248
249
  "cardLastLoginTitle": "Never",
249
250
  "securityTitle": "Security Overview",
@@ -944,6 +945,18 @@
944
945
  "revokeAllSuccess": "Sessions revoked successfully!",
945
946
  "revokeAllFailure": "Failed to revoke sessions"
946
947
  },
948
+ "UserChangeLog": {
949
+ "title": "Change History",
950
+ "byActor": "by",
951
+ "systemActor": "System",
952
+ "update": "Profile updated",
953
+ "reset_password": "Password reset",
954
+ "role_assigned": "Role assigned",
955
+ "role_removed": "Role removed",
956
+ "avatar_changed": "Avatar changed",
957
+ "emptyTitle": "No changes recorded",
958
+ "emptyDescription": "Administrative changes made to this user will appear here."
959
+ },
947
960
  "UserActiveSessions": {
948
961
  "title": "Active Sessions",
949
962
  "revokeAll": "Revoke All",
@@ -244,6 +244,7 @@
244
244
  "tabIdentifiers": "Identificadores",
245
245
  "tabMfa": "MFA",
246
246
  "tabSessions": "Sessões",
247
+ "tabLogs": "Logs",
247
248
  "cardLastLoginDescription": "Último login",
248
249
  "cardLastLoginTitle": "Nunca",
249
250
  "securityTitle": "Visão Geral de Segurança",
@@ -944,6 +945,18 @@
944
945
  "revokeAllSuccess": "Sessões revogadas com sucesso!",
945
946
  "revokeAllFailure": "Falha ao revogar sessões"
946
947
  },
948
+ "UserChangeLog": {
949
+ "title": "Histórico de Alterações",
950
+ "byActor": "por",
951
+ "systemActor": "Sistema",
952
+ "update": "Perfil atualizado",
953
+ "reset_password": "Senha redefinida",
954
+ "role_assigned": "Papel atribuído",
955
+ "role_removed": "Papel removido",
956
+ "avatar_changed": "Avatar alterado",
957
+ "emptyTitle": "Nenhuma alteração registrada",
958
+ "emptyDescription": "As alterações administrativas feitas neste usuário aparecerão aqui."
959
+ },
947
960
  "UserActiveSessions": {
948
961
  "title": "Sessões Ativas",
949
962
  "revokeAll": "Revogar Todas",
@@ -1,55 +1,55 @@
1
- columns:
2
- - type: pk
3
- - type: slug
4
- - name: name
5
- type: varchar
6
- length: 127
7
- - name: description
8
- type: text
9
- isNullable: true
10
- - name: status
11
- type: enum
12
- enum:
13
- - active
14
- - inactive
15
- default: active
16
- - name: priority
17
- type: int
18
- default: 0
19
- - name: url
20
- type: text
21
- - name: method
22
- type: enum
23
- enum:
24
- - GET
25
- - POST
26
- - PUT
27
- - PATCH
28
- - DELETE
29
- default: POST
30
- - name: headers
31
- type: json
32
- isNullable: true
33
- - name: query
34
- type: json
35
- isNullable: true
36
- - name: payload
37
- type: json
38
- isNullable: true
39
- - name: timeout_ms
40
- type: int
41
- default: 10000
42
- - name: retry_count
43
- type: int
44
- default: 0
45
- - type: created_at
46
- - type: updated_at
47
- indices:
48
- - columns:
49
- - slug
50
- isUnique: true
51
- - columns:
52
- - status
53
- - columns:
54
- - priority
55
-
1
+ columns:
2
+ - type: pk
3
+ - type: slug
4
+ - name: name
5
+ type: varchar
6
+ length: 127
7
+ - name: description
8
+ type: text
9
+ isNullable: true
10
+ - name: status
11
+ type: enum
12
+ enum:
13
+ - active
14
+ - inactive
15
+ default: active
16
+ - name: priority
17
+ type: int
18
+ default: 0
19
+ - name: url
20
+ type: text
21
+ - name: method
22
+ type: enum
23
+ enum:
24
+ - GET
25
+ - POST
26
+ - PUT
27
+ - PATCH
28
+ - DELETE
29
+ default: POST
30
+ - name: headers
31
+ type: json
32
+ isNullable: true
33
+ - name: query
34
+ type: json
35
+ isNullable: true
36
+ - name: payload
37
+ type: json
38
+ isNullable: true
39
+ - name: timeout_ms
40
+ type: int
41
+ default: 10000
42
+ - name: retry_count
43
+ type: int
44
+ default: 0
45
+ - type: created_at
46
+ - type: updated_at
47
+ indices:
48
+ - columns:
49
+ - slug
50
+ isUnique: true
51
+ - columns:
52
+ - status
53
+ - columns:
54
+ - priority
55
+
@@ -1,66 +1,66 @@
1
- columns:
2
- - type: pk
3
- - type: fk
4
- name: event_webhook_id
5
- isNullable: true
6
- references:
7
- table: event_webhook
8
- column: id
9
- onDelete: set null
10
- onUpdate: cascade
11
- - type: fk
12
- name: integration_event_catalog_id
13
- isNullable: true
14
- references:
15
- table: integration_event_catalog
16
- column: id
17
- onDelete: set null
18
- onUpdate: cascade
19
- - name: outbox_event_id
20
- type: int
21
- isNullable: true
22
- - name: event_name
23
- type: varchar
24
- length: 255
25
- - name: method
26
- type: varchar
27
- length: 15
28
- - name: url
29
- type: text
30
- - name: status
31
- type: enum
32
- enum:
33
- - success
34
- - failed
35
- - name: http_status
36
- type: int
37
- isNullable: true
38
- - name: duration_ms
39
- type: int
40
- default: 0
41
- - name: attempt_count
42
- type: int
43
- default: 1
44
- - name: error_message
45
- type: text
46
- isNullable: true
47
- - name: request_summary
48
- type: json
49
- isNullable: true
50
- - name: response_summary
51
- type: json
52
- isNullable: true
53
- - type: created_at
54
- - type: updated_at
55
- indices:
56
- - columns:
57
- - event_webhook_id
58
- - columns:
59
- - integration_event_catalog_id
60
- - columns:
61
- - event_name
62
- - columns:
63
- - status
64
- - columns:
65
- - created_at
66
-
1
+ columns:
2
+ - type: pk
3
+ - type: fk
4
+ name: event_webhook_id
5
+ isNullable: true
6
+ references:
7
+ table: event_webhook
8
+ column: id
9
+ onDelete: set null
10
+ onUpdate: cascade
11
+ - type: fk
12
+ name: integration_event_catalog_id
13
+ isNullable: true
14
+ references:
15
+ table: integration_event_catalog
16
+ column: id
17
+ onDelete: set null
18
+ onUpdate: cascade
19
+ - name: outbox_event_id
20
+ type: int
21
+ isNullable: true
22
+ - name: event_name
23
+ type: varchar
24
+ length: 255
25
+ - name: method
26
+ type: varchar
27
+ length: 15
28
+ - name: url
29
+ type: text
30
+ - name: status
31
+ type: enum
32
+ enum:
33
+ - success
34
+ - failed
35
+ - name: http_status
36
+ type: int
37
+ isNullable: true
38
+ - name: duration_ms
39
+ type: int
40
+ default: 0
41
+ - name: attempt_count
42
+ type: int
43
+ default: 1
44
+ - name: error_message
45
+ type: text
46
+ isNullable: true
47
+ - name: request_summary
48
+ type: json
49
+ isNullable: true
50
+ - name: response_summary
51
+ type: json
52
+ isNullable: true
53
+ - type: created_at
54
+ - type: updated_at
55
+ indices:
56
+ - columns:
57
+ - event_webhook_id
58
+ - columns:
59
+ - integration_event_catalog_id
60
+ - columns:
61
+ - event_name
62
+ - columns:
63
+ - status
64
+ - columns:
65
+ - created_at
66
+
@@ -1,26 +1,26 @@
1
- columns:
2
- - type: pk
3
- - type: fk
4
- name: event_webhook_id
5
- references:
6
- table: event_webhook
7
- column: id
8
- onDelete: cascade
9
- onUpdate: cascade
10
- - type: fk
11
- name: integration_event_catalog_id
12
- references:
13
- table: integration_event_catalog
14
- column: id
15
- onDelete: cascade
16
- onUpdate: cascade
17
- - type: created_at
18
- - type: updated_at
19
- indices:
20
- - columns:
21
- - event_webhook_id
22
- - integration_event_catalog_id
23
- isUnique: true
24
- - columns:
25
- - integration_event_catalog_id
26
-
1
+ columns:
2
+ - type: pk
3
+ - type: fk
4
+ name: event_webhook_id
5
+ references:
6
+ table: event_webhook
7
+ column: id
8
+ onDelete: cascade
9
+ onUpdate: cascade
10
+ - type: fk
11
+ name: integration_event_catalog_id
12
+ references:
13
+ table: integration_event_catalog
14
+ column: id
15
+ onDelete: cascade
16
+ onUpdate: cascade
17
+ - type: created_at
18
+ - type: updated_at
19
+ indices:
20
+ - columns:
21
+ - event_webhook_id
22
+ - integration_event_catalog_id
23
+ isUnique: true
24
+ - columns:
25
+ - integration_event_catalog_id
26
+
@@ -1,41 +1,41 @@
1
- columns:
2
- - type: pk
3
- - type: slug
4
- - name: name
5
- type: varchar
6
- length: 127
7
- - name: module
8
- type: varchar
9
- length: 127
10
- - name: aggregate_type
11
- type: varchar
12
- length: 127
13
- isNullable: true
14
- - name: description
15
- type: text
16
- isNullable: true
17
- - name: payload_schema
18
- type: json
19
- isNullable: true
20
- - name: metadata_schema
21
- type: json
22
- isNullable: true
23
- - name: status
24
- type: enum
25
- enum:
26
- - active
27
- - inactive
28
- default: active
29
- - type: created_at
30
- - type: updated_at
31
- indices:
32
- - columns:
33
- - slug
34
- isUnique: true
35
- - columns:
36
- - module
37
- - columns:
38
- - aggregate_type
39
- - columns:
40
- - status
41
-
1
+ columns:
2
+ - type: pk
3
+ - type: slug
4
+ - name: name
5
+ type: varchar
6
+ length: 127
7
+ - name: module
8
+ type: varchar
9
+ length: 127
10
+ - name: aggregate_type
11
+ type: varchar
12
+ length: 127
13
+ isNullable: true
14
+ - name: description
15
+ type: text
16
+ isNullable: true
17
+ - name: payload_schema
18
+ type: json
19
+ isNullable: true
20
+ - name: metadata_schema
21
+ type: json
22
+ isNullable: true
23
+ - name: status
24
+ type: enum
25
+ enum:
26
+ - active
27
+ - inactive
28
+ default: active
29
+ - type: created_at
30
+ - type: updated_at
31
+ indices:
32
+ - columns:
33
+ - slug
34
+ isUnique: true
35
+ - columns:
36
+ - module
37
+ - columns:
38
+ - aggregate_type
39
+ - columns:
40
+ - status
41
+