@hed-hog/core 0.0.279 → 0.0.286
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.
- package/dist/auth/auth.controller.d.ts +3 -3
- package/dist/auth/auth.service.d.ts +8 -8
- package/dist/file/file.controller.d.ts +2 -2
- package/dist/file/file.service.d.ts +4 -4
- package/dist/role/guards/role.guard.d.ts.map +1 -1
- package/dist/role/guards/role.guard.js +1 -1
- package/dist/role/guards/role.guard.js.map +1 -1
- package/dist/session/session.controller.d.ts +1 -1
- package/dist/session/session.service.d.ts +3 -3
- package/dist/setting/setting.controller.d.ts +3 -0
- package/dist/setting/setting.controller.d.ts.map +1 -1
- package/dist/setting/setting.controller.js +10 -0
- package/dist/setting/setting.controller.js.map +1 -1
- package/dist/setting/setting.service.d.ts +2 -1
- package/dist/setting/setting.service.d.ts.map +1 -1
- package/dist/setting/setting.service.js +51 -12
- package/dist/setting/setting.service.js.map +1 -1
- package/dist/user/user.controller.d.ts +2 -2
- package/dist/user/user.service.d.ts +6 -6
- package/hedhog/data/route.yaml +8 -0
- package/hedhog/frontend/app/ai_agent/page.tsx.ejs +72 -65
- package/hedhog/frontend/app/configurations/[slug]/components/setting-field.tsx.ejs +1 -92
- package/hedhog/frontend/app/dashboard/page.tsx.ejs +2 -2
- package/hedhog/frontend/app/mail/log/page.tsx.ejs +37 -42
- package/hedhog/frontend/app/mail/template/page.tsx.ejs +176 -126
- package/hedhog/frontend/app/menu/page.tsx.ejs +45 -39
- package/hedhog/frontend/app/preferences/page.tsx.ejs +34 -121
- package/hedhog/frontend/app/roles/page.tsx.ejs +45 -46
- package/hedhog/frontend/app/users/page.tsx.ejs +71 -68
- package/hedhog/frontend/messages/en.json +7 -0
- package/hedhog/frontend/messages/pt.json +7 -0
- package/package.json +2 -2
- package/src/role/guards/role.guard.ts +9 -8
- package/src/setting/setting.controller.ts +21 -16
- package/src/setting/setting.service.ts +63 -17
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
'use client';
|
|
2
2
|
|
|
3
3
|
import {
|
|
4
|
+
EmptyState,
|
|
4
5
|
Page,
|
|
5
6
|
PageHeader,
|
|
6
7
|
PaginationFooter,
|
|
@@ -115,7 +116,7 @@ export default function AiAgentPage() {
|
|
|
115
116
|
},
|
|
116
117
|
});
|
|
117
118
|
|
|
118
|
-
const { data, isLoading, refetch } = useQuery<PaginatedResponse<Agent>>({
|
|
119
|
+
const { data, isLoading, refetch } = useQuery<PaginatedResponse<Agent>>({
|
|
119
120
|
queryKey: ['ai-agents', page, pageSize, debouncedSearch],
|
|
120
121
|
queryFn: async () => {
|
|
121
122
|
const params = new URLSearchParams();
|
|
@@ -130,14 +131,14 @@ export default function AiAgentPage() {
|
|
|
130
131
|
|
|
131
132
|
return response.data;
|
|
132
133
|
},
|
|
133
|
-
});
|
|
134
|
-
const agentList = data ?? {
|
|
135
|
-
data: [],
|
|
136
|
-
total: 0,
|
|
137
|
-
page: 1,
|
|
138
|
-
pageSize: 10,
|
|
139
|
-
totalPages: 1,
|
|
140
|
-
};
|
|
134
|
+
});
|
|
135
|
+
const agentList = data ?? {
|
|
136
|
+
data: [],
|
|
137
|
+
total: 0,
|
|
138
|
+
page: 1,
|
|
139
|
+
pageSize: 10,
|
|
140
|
+
totalPages: 1,
|
|
141
|
+
};
|
|
141
142
|
|
|
142
143
|
useEffect(() => {
|
|
143
144
|
if (editingAgent) {
|
|
@@ -261,69 +262,75 @@ export default function AiAgentPage() {
|
|
|
261
262
|
placeholder={t('searchPlaceholder')}
|
|
262
263
|
/>
|
|
263
264
|
|
|
264
|
-
|
|
265
|
-
<
|
|
266
|
-
<
|
|
267
|
-
<
|
|
268
|
-
<
|
|
269
|
-
<TableHead>Slug</TableHead>
|
|
270
|
-
<TableHead>{t('columnProvider')}</TableHead>
|
|
271
|
-
<TableHead>{t('columnModel')}</TableHead>
|
|
272
|
-
<TableHead>{t('columnExternalId')}</TableHead>
|
|
273
|
-
<TableHead className="text-right">
|
|
274
|
-
{t('columnActions')}
|
|
275
|
-
</TableHead>
|
|
276
|
-
</TableRow>
|
|
277
|
-
</TableHeader>
|
|
278
|
-
<TableBody>
|
|
279
|
-
{isLoading ? (
|
|
265
|
+
{isLoading || agentList.data.length > 0 ? (
|
|
266
|
+
<Card>
|
|
267
|
+
<CardContent className="p-0">
|
|
268
|
+
<Table>
|
|
269
|
+
<TableHeader>
|
|
280
270
|
<TableRow>
|
|
281
|
-
<
|
|
271
|
+
<TableHead>Slug</TableHead>
|
|
272
|
+
<TableHead>{t('columnProvider')}</TableHead>
|
|
273
|
+
<TableHead>{t('columnModel')}</TableHead>
|
|
274
|
+
<TableHead>{t('columnExternalId')}</TableHead>
|
|
275
|
+
<TableHead className="text-right">
|
|
276
|
+
{t('columnActions')}
|
|
277
|
+
</TableHead>
|
|
282
278
|
</TableRow>
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
agentList.data.map((agent) => (
|
|
289
|
-
<TableRow key={agent.id}>
|
|
290
|
-
<TableCell>{agent.slug}</TableCell>
|
|
291
|
-
<TableCell className="uppercase">
|
|
292
|
-
{agent.provider}
|
|
293
|
-
</TableCell>
|
|
294
|
-
<TableCell>{agent.model || '-'}</TableCell>
|
|
295
|
-
<TableCell>{agent.external_agent_id || '-'}</TableCell>
|
|
296
|
-
<TableCell className="text-right">
|
|
297
|
-
<div className="flex items-center justify-end gap-2">
|
|
298
|
-
<Button
|
|
299
|
-
variant="outline"
|
|
300
|
-
size="icon"
|
|
301
|
-
onClick={() => handleOpenEdit(agent)}
|
|
302
|
-
>
|
|
303
|
-
<Pencil className="h-4 w-4" />
|
|
304
|
-
</Button>
|
|
305
|
-
<Button
|
|
306
|
-
variant="destructive"
|
|
307
|
-
size="icon"
|
|
308
|
-
onClick={() => setAgentToDelete(agent)}
|
|
309
|
-
>
|
|
310
|
-
<Trash2 className="h-4 w-4" />
|
|
311
|
-
</Button>
|
|
312
|
-
</div>
|
|
313
|
-
</TableCell>
|
|
279
|
+
</TableHeader>
|
|
280
|
+
<TableBody>
|
|
281
|
+
{isLoading ? (
|
|
282
|
+
<TableRow>
|
|
283
|
+
<TableCell colSpan={5}>{t('loading')}</TableCell>
|
|
314
284
|
</TableRow>
|
|
315
|
-
)
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
285
|
+
) : (
|
|
286
|
+
agentList.data.map((agent) => (
|
|
287
|
+
<TableRow key={agent.id}>
|
|
288
|
+
<TableCell>{agent.slug}</TableCell>
|
|
289
|
+
<TableCell className="uppercase">
|
|
290
|
+
{agent.provider}
|
|
291
|
+
</TableCell>
|
|
292
|
+
<TableCell>{agent.model || '-'}</TableCell>
|
|
293
|
+
<TableCell>{agent.external_agent_id || '-'}</TableCell>
|
|
294
|
+
<TableCell className="text-right">
|
|
295
|
+
<div className="flex items-center justify-end gap-2">
|
|
296
|
+
<Button
|
|
297
|
+
variant="outline"
|
|
298
|
+
size="icon"
|
|
299
|
+
onClick={() => handleOpenEdit(agent)}
|
|
300
|
+
>
|
|
301
|
+
<Pencil className="h-4 w-4" />
|
|
302
|
+
</Button>
|
|
303
|
+
<Button
|
|
304
|
+
variant="destructive"
|
|
305
|
+
size="icon"
|
|
306
|
+
onClick={() => setAgentToDelete(agent)}
|
|
307
|
+
>
|
|
308
|
+
<Trash2 className="h-4 w-4" />
|
|
309
|
+
</Button>
|
|
310
|
+
</div>
|
|
311
|
+
</TableCell>
|
|
312
|
+
</TableRow>
|
|
313
|
+
))
|
|
314
|
+
)}
|
|
315
|
+
</TableBody>
|
|
316
|
+
</Table>
|
|
317
|
+
</CardContent>
|
|
318
|
+
</Card>
|
|
319
|
+
) : (
|
|
320
|
+
<EmptyState
|
|
321
|
+
icon={<Bot className="h-12 w-12" />}
|
|
322
|
+
title={t('empty')}
|
|
323
|
+
description={t('description')}
|
|
324
|
+
actionLabel={t('newAgent')}
|
|
325
|
+
onAction={handleOpenCreate}
|
|
326
|
+
/>
|
|
327
|
+
)}
|
|
321
328
|
|
|
322
329
|
<PaginationFooter
|
|
323
330
|
currentPage={page}
|
|
324
331
|
pageSize={pageSize}
|
|
325
|
-
totalItems={agentList.total}
|
|
326
|
-
onPageChange={setPage}
|
|
332
|
+
totalItems={agentList.total}
|
|
333
|
+
onPageChange={setPage}
|
|
327
334
|
onPageSizeChange={(value) => {
|
|
328
335
|
setPageSize(value);
|
|
329
336
|
setPage(1);
|
|
@@ -50,98 +50,7 @@ export const SettingField = ({ setting, className }: SettingFieldProps) => {
|
|
|
50
50
|
|
|
51
51
|
const newSettings = response.data?.setting || {};
|
|
52
52
|
localStorage.setItem('settings', JSON.stringify(newSettings));
|
|
53
|
-
|
|
54
|
-
const root = document.documentElement;
|
|
55
|
-
const themeMode = newSettings['theme-mode'] || 'system';
|
|
56
|
-
let currentTheme: 'light' | 'dark' = 'light';
|
|
57
|
-
|
|
58
|
-
if (themeMode === 'system') {
|
|
59
|
-
const prefersDark = window.matchMedia(
|
|
60
|
-
'(prefers-color-scheme: dark)'
|
|
61
|
-
).matches;
|
|
62
|
-
currentTheme = prefersDark ? 'dark' : 'light';
|
|
63
|
-
} else {
|
|
64
|
-
currentTheme = themeMode as 'light' | 'dark';
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
root.classList.remove('light', 'dark');
|
|
68
|
-
root.classList.add(currentTheme);
|
|
69
|
-
|
|
70
|
-
const existingStyle = document.getElementById('theme-custom-styles');
|
|
71
|
-
if (existingStyle) {
|
|
72
|
-
existingStyle.remove();
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
const styleTag = document.createElement('style');
|
|
76
|
-
styleTag.id = 'theme-custom-styles';
|
|
77
|
-
let cssRules = '';
|
|
78
|
-
|
|
79
|
-
const addRule = (varName: string, settingKey: string) => {
|
|
80
|
-
const hexColor = newSettings[settingKey];
|
|
81
|
-
if (
|
|
82
|
-
hexColor &&
|
|
83
|
-
typeof hexColor === 'string' &&
|
|
84
|
-
hexColor.startsWith('#')
|
|
85
|
-
) {
|
|
86
|
-
cssRules += ` ${varName}: ${hexColor} !important;\n`;
|
|
87
|
-
}
|
|
88
|
-
};
|
|
89
|
-
|
|
90
|
-
if (currentTheme === 'light') {
|
|
91
|
-
cssRules += '@supports (color: lab(0% 0 0)) {\n';
|
|
92
|
-
cssRules += ' html.light, .light, :root.light {\n';
|
|
93
|
-
addRule('--primary', 'theme-primary-light');
|
|
94
|
-
addRule('--bprogress-color', 'theme-primary-light');
|
|
95
|
-
addRule('--primary-foreground', 'theme-primary-foreground-light');
|
|
96
|
-
addRule('--secondary', 'theme-secondary-light');
|
|
97
|
-
addRule('--secondary-foreground', 'theme-secondary-foreground-light');
|
|
98
|
-
addRule('--accent', 'theme-accent-light');
|
|
99
|
-
addRule('--accent-foreground', 'theme-accent-foreground-light');
|
|
100
|
-
addRule('--muted', 'theme-muted-light');
|
|
101
|
-
addRule('--muted-foreground', 'theme-muted-foreground-light');
|
|
102
|
-
addRule('--background', 'theme-background-light');
|
|
103
|
-
addRule('--foreground', 'theme-background-foreground-light');
|
|
104
|
-
addRule('--card', 'theme-card-light');
|
|
105
|
-
addRule('--card-foreground', 'theme-card-foreground-light');
|
|
106
|
-
} else {
|
|
107
|
-
cssRules += '@supports (color: lab(0% 0 0)) {\n';
|
|
108
|
-
cssRules += ' html.dark, .dark, :root.dark {\n';
|
|
109
|
-
addRule('--primary', 'theme-primary-dark');
|
|
110
|
-
addRule('--bprogress-color', 'theme-primary-dark');
|
|
111
|
-
addRule('--primary-foreground', 'theme-primary-foreground-dark');
|
|
112
|
-
addRule('--secondary', 'theme-secondary-dark');
|
|
113
|
-
addRule('--secondary-foreground', 'theme-secondary-foreground-dark');
|
|
114
|
-
addRule('--accent', 'theme-accent-dark');
|
|
115
|
-
addRule('--accent-foreground', 'theme-accent-foreground-dark');
|
|
116
|
-
addRule('--muted', 'theme-muted-dark');
|
|
117
|
-
addRule('--muted-foreground', 'theme-muted-foreground-dark');
|
|
118
|
-
addRule('--background', 'theme-background-dark');
|
|
119
|
-
addRule('--foreground', 'theme-background-foreground-dark');
|
|
120
|
-
addRule('--card', 'theme-card-dark');
|
|
121
|
-
addRule('--card-foreground', 'theme-card-foreground-dark');
|
|
122
|
-
}
|
|
123
|
-
|
|
124
|
-
if (newSettings['theme-radius']) {
|
|
125
|
-
cssRules += ` --radius: ${newSettings['theme-radius']}rem !important;\n`;
|
|
126
|
-
}
|
|
127
|
-
if (newSettings['theme-text-size']) {
|
|
128
|
-
cssRules += ` font-size: ${newSettings['theme-text-size']}rem !important;\n`;
|
|
129
|
-
}
|
|
130
|
-
|
|
131
|
-
cssRules += ' }\n';
|
|
132
|
-
cssRules += '}\n';
|
|
133
|
-
|
|
134
|
-
if (newSettings['theme-font']) {
|
|
135
|
-
cssRules += `:root {\n`;
|
|
136
|
-
cssRules += ` --font-sans: ${newSettings['theme-font']} !important;\n`;
|
|
137
|
-
cssRules += `}\n`;
|
|
138
|
-
cssRules += `html {\n`;
|
|
139
|
-
cssRules += ` font-family: ${newSettings['theme-font']} !important;\n`;
|
|
140
|
-
cssRules += `}\n`;
|
|
141
|
-
}
|
|
142
|
-
|
|
143
|
-
styleTag.textContent = cssRules;
|
|
144
|
-
document.head.appendChild(styleTag);
|
|
53
|
+
window.dispatchEvent(new CustomEvent('hedhog:settings-change'));
|
|
145
54
|
} catch (error) {
|
|
146
55
|
console.error('Error applying theme settings:', error);
|
|
147
56
|
}
|
|
@@ -12,10 +12,10 @@ export default function DashboardRedirectPage() {
|
|
|
12
12
|
const { data: dashboardData, isLoading } = useQuery<Dashboard | null>({
|
|
13
13
|
queryKey: ['dashboard-home-redirect', currentLocaleCode],
|
|
14
14
|
queryFn: async () => {
|
|
15
|
-
const response = await request<Dashboard
|
|
15
|
+
const response = await request<Dashboard>({
|
|
16
16
|
url: '/dashboard-core/home',
|
|
17
17
|
});
|
|
18
|
-
return response.data;
|
|
18
|
+
return response.data ?? null;
|
|
19
19
|
},
|
|
20
20
|
});
|
|
21
21
|
|
|
@@ -1,6 +1,12 @@
|
|
|
1
1
|
'use client';
|
|
2
2
|
|
|
3
|
-
import {
|
|
3
|
+
import {
|
|
4
|
+
EmptyState,
|
|
5
|
+
Page,
|
|
6
|
+
PageHeader,
|
|
7
|
+
PaginationFooter,
|
|
8
|
+
SearchBar,
|
|
9
|
+
} from '@/components/entity-list';
|
|
4
10
|
import { Badge } from '@/components/ui/badge';
|
|
5
11
|
import { Button } from '@/components/ui/button';
|
|
6
12
|
import { Card, CardContent } from '@/components/ui/card';
|
|
@@ -11,14 +17,13 @@ import {
|
|
|
11
17
|
DialogHeader,
|
|
12
18
|
DialogTitle,
|
|
13
19
|
} from '@/components/ui/dialog';
|
|
14
|
-
import { Input } from '@/components/ui/input';
|
|
15
20
|
import { ScrollArea } from '@/components/ui/scroll-area';
|
|
16
21
|
import { useDebounce } from '@/hooks/use-debounce';
|
|
17
22
|
import { formatDate } from '@/lib/format-date';
|
|
18
23
|
import { useApp, useQuery } from '@hed-hog/next-app-provider';
|
|
19
|
-
import { Clock, Mail,
|
|
24
|
+
import { Clock, Mail, User } from 'lucide-react';
|
|
20
25
|
import { useTranslations } from 'next-intl';
|
|
21
|
-
import {
|
|
26
|
+
import { useState } from 'react';
|
|
22
27
|
|
|
23
28
|
type PaginationResult<T> = {
|
|
24
29
|
data: T[];
|
|
@@ -42,7 +47,6 @@ type MailSent = {
|
|
|
42
47
|
|
|
43
48
|
export default function MailLogPage() {
|
|
44
49
|
const t = useTranslations('core.MailLog');
|
|
45
|
-
const [logs, setLogs] = useState<MailSent[]>([]);
|
|
46
50
|
const [selectedLog, setSelectedLog] = useState<MailSent | null>(null);
|
|
47
51
|
const [isDetailDialogOpen, setIsDetailDialogOpen] = useState(false);
|
|
48
52
|
const [searchTerm, setSearchTerm] = useState('');
|
|
@@ -51,9 +55,9 @@ export default function MailLogPage() {
|
|
|
51
55
|
const [pageSize, setPageSize] = useState(10);
|
|
52
56
|
const { request, getSettingValue } = useApp();
|
|
53
57
|
|
|
54
|
-
const { data: logsResult, refetch: refetchLogs } = useQuery<
|
|
55
|
-
PaginationResult<MailSent>
|
|
56
|
-
>({
|
|
58
|
+
const { data: logsResult, refetch: refetchLogs } = useQuery<
|
|
59
|
+
PaginationResult<MailSent>
|
|
60
|
+
>({
|
|
57
61
|
queryKey: ['mail-sent', debouncedSearch, page, pageSize],
|
|
58
62
|
queryFn: async () => {
|
|
59
63
|
const response = await request({
|
|
@@ -66,14 +70,8 @@ export default function MailLogPage() {
|
|
|
66
70
|
});
|
|
67
71
|
return response.data as PaginationResult<MailSent>;
|
|
68
72
|
},
|
|
69
|
-
});
|
|
70
|
-
const { data = [], total = 0 } = logsResult ?? {};
|
|
71
|
-
|
|
72
|
-
useEffect(() => {
|
|
73
|
-
if (data) {
|
|
74
|
-
setLogs(data);
|
|
75
|
-
}
|
|
76
|
-
}, [data]);
|
|
73
|
+
});
|
|
74
|
+
const { data: logs = [], total = 0 } = logsResult ?? {};
|
|
77
75
|
|
|
78
76
|
const handleViewDetails = (log: MailSent): void => {
|
|
79
77
|
setSelectedLog(log);
|
|
@@ -92,12 +90,8 @@ export default function MailLogPage() {
|
|
|
92
90
|
: text;
|
|
93
91
|
};
|
|
94
92
|
|
|
95
|
-
useEffect(() => {
|
|
96
|
-
refetchLogs();
|
|
97
|
-
}, [debouncedSearch, page, pageSize]);
|
|
98
|
-
|
|
99
93
|
return (
|
|
100
|
-
<
|
|
94
|
+
<Page>
|
|
101
95
|
<PageHeader
|
|
102
96
|
breadcrumbs={[
|
|
103
97
|
{ label: t('breadcrumbHome'), href: '/' },
|
|
@@ -141,29 +135,30 @@ export default function MailLogPage() {
|
|
|
141
135
|
</Card>
|
|
142
136
|
</div>
|
|
143
137
|
|
|
144
|
-
<
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
className="pl-10"
|
|
151
|
-
/>
|
|
152
|
-
</div>
|
|
138
|
+
<SearchBar
|
|
139
|
+
searchQuery={searchTerm}
|
|
140
|
+
onSearchChange={handleSearchChange}
|
|
141
|
+
onSearch={() => setPage(1)}
|
|
142
|
+
placeholder={t('searchPlaceholder')}
|
|
143
|
+
/>
|
|
153
144
|
|
|
154
145
|
<div className="space-y-3 mb-4">
|
|
155
146
|
{logs.length === 0 ? (
|
|
156
|
-
<
|
|
157
|
-
<
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
147
|
+
<EmptyState
|
|
148
|
+
icon={<Mail className="h-12 w-12" />}
|
|
149
|
+
title={t('noLogsFound')}
|
|
150
|
+
description={searchTerm ? t('adjustSearch') : t('noEmailsSent')}
|
|
151
|
+
actionLabel={searchTerm ? t('clearSearch') : t('refreshList')}
|
|
152
|
+
onAction={() => {
|
|
153
|
+
if (searchTerm) {
|
|
154
|
+
setSearchTerm('');
|
|
155
|
+
setPage(1);
|
|
156
|
+
return;
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
refetchLogs();
|
|
160
|
+
}}
|
|
161
|
+
/>
|
|
167
162
|
) : (
|
|
168
163
|
logs.map((log) => (
|
|
169
164
|
<Card
|
|
@@ -301,6 +296,6 @@ export default function MailLogPage() {
|
|
|
301
296
|
</DialogContent>
|
|
302
297
|
</Dialog>
|
|
303
298
|
)}
|
|
304
|
-
</
|
|
299
|
+
</Page>
|
|
305
300
|
);
|
|
306
301
|
}
|