@hed-hog/core 0.0.299 → 0.0.301
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/ai/ai.service.d.ts +13 -2
- package/dist/ai/ai.service.d.ts.map +1 -1
- package/dist/ai/ai.service.js +104 -2
- package/dist/ai/ai.service.js.map +1 -1
- package/dist/dashboard/dashboard/dashboard.controller.d.ts +6 -0
- package/dist/dashboard/dashboard/dashboard.controller.d.ts.map +1 -1
- package/dist/dashboard/dashboard/dashboard.service.d.ts +6 -0
- package/dist/dashboard/dashboard/dashboard.service.d.ts.map +1 -1
- package/dist/dashboard/dashboard-component/dashboard-component.controller.d.ts +2 -1
- package/dist/dashboard/dashboard-component/dashboard-component.controller.d.ts.map +1 -1
- package/dist/dashboard/dashboard-component/dashboard-component.controller.js +6 -3
- package/dist/dashboard/dashboard-component/dashboard-component.controller.js.map +1 -1
- package/dist/dashboard/dashboard-component/dashboard-component.service.d.ts +7 -1
- package/dist/dashboard/dashboard-component/dashboard-component.service.d.ts.map +1 -1
- package/dist/dashboard/dashboard-component/dashboard-component.service.js +76 -33
- package/dist/dashboard/dashboard-component/dashboard-component.service.js.map +1 -1
- package/dist/dashboard/dashboard-core/dashboard-core.controller.d.ts +82 -0
- package/dist/dashboard/dashboard-core/dashboard-core.controller.d.ts.map +1 -1
- package/dist/dashboard/dashboard-core/dashboard-core.controller.js +117 -0
- package/dist/dashboard/dashboard-core/dashboard-core.controller.js.map +1 -1
- package/dist/dashboard/dashboard-core/dashboard-core.service.d.ts +93 -0
- package/dist/dashboard/dashboard-core/dashboard-core.service.d.ts.map +1 -1
- package/dist/dashboard/dashboard-core/dashboard-core.service.js +654 -20
- package/dist/dashboard/dashboard-core/dashboard-core.service.js.map +1 -1
- package/dist/dashboard/dashboard-item/dashboard-item.controller.d.ts +2 -0
- package/dist/dashboard/dashboard-item/dashboard-item.controller.d.ts.map +1 -1
- package/dist/dashboard/dashboard-item/dashboard-item.service.d.ts +2 -0
- package/dist/dashboard/dashboard-item/dashboard-item.service.d.ts.map +1 -1
- package/dist/dashboard/dashboard-role/dashboard-role.controller.d.ts +2 -0
- package/dist/dashboard/dashboard-role/dashboard-role.controller.d.ts.map +1 -1
- package/dist/dashboard/dashboard-role/dashboard-role.service.d.ts +2 -0
- package/dist/dashboard/dashboard-role/dashboard-role.service.d.ts.map +1 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -0
- package/dist/index.js.map +1 -1
- package/dist/mail/mail.service.d.ts +9 -2
- package/dist/mail/mail.service.d.ts.map +1 -1
- package/dist/mail/mail.service.js +56 -4
- package/dist/mail/mail.service.js.map +1 -1
- package/dist/setting/setting.service.d.ts +6 -1
- package/dist/setting/setting.service.d.ts.map +1 -1
- package/dist/setting/setting.service.js +188 -15
- package/dist/setting/setting.service.js.map +1 -1
- package/hedhog/data/dashboard.yaml +12 -6
- package/hedhog/data/dashboard_component_role.yaml +66 -0
- package/hedhog/data/dashboard_role.yaml +2 -8
- package/hedhog/data/route.yaml +72 -0
- package/hedhog/data/setting_group.yaml +28 -0
- package/hedhog/frontend/app/dashboard/[slug]/dashboard-content.tsx.ejs +333 -128
- package/hedhog/frontend/app/dashboard/[slug]/widget-renderer.tsx.ejs +277 -53
- package/hedhog/frontend/app/dashboard/components/add-widget-selector-dialog.tsx.ejs +179 -231
- package/hedhog/frontend/app/dashboard/components/draggable-grid.tsx.ejs +64 -18
- package/hedhog/frontend/app/dashboard/dashboard-home-tabs.tsx.ejs +1619 -0
- package/hedhog/frontend/app/dashboard/dashboard.css.ejs +37 -0
- package/hedhog/frontend/app/dashboard/management/page.tsx.ejs +1 -1
- package/hedhog/frontend/app/dashboard/management/tabs/components-tab.tsx.ejs +6 -6
- package/hedhog/frontend/app/dashboard/management/tabs/dashboards-tab.tsx.ejs +8 -8
- package/hedhog/frontend/app/dashboard/management/tabs/items-tab.tsx.ejs +3 -3
- package/hedhog/frontend/app/dashboard/page.tsx.ejs +3 -25
- package/hedhog/frontend/messages/en.json +124 -2
- package/hedhog/frontend/messages/pt.json +123 -1
- package/hedhog/frontend/widgets/account-security.tsx.ejs +1 -1
- package/hedhog/frontend/widgets/active-users-card.tsx.ejs +2 -2
- package/hedhog/frontend/widgets/activity-timeline.tsx.ejs +1 -1
- package/hedhog/frontend/widgets/email-notifications.tsx.ejs +1 -1
- package/hedhog/frontend/widgets/locale-config.tsx.ejs +1 -1
- package/hedhog/frontend/widgets/login-history-chart.tsx.ejs +1 -1
- package/hedhog/frontend/widgets/mail-config.tsx.ejs +1 -1
- package/hedhog/frontend/widgets/mail-sent-card.tsx.ejs +2 -2
- package/hedhog/frontend/widgets/mail-sent-chart.tsx.ejs +1 -1
- package/hedhog/frontend/widgets/menus-card.tsx.ejs +2 -2
- package/hedhog/frontend/widgets/oauth-config.tsx.ejs +1 -1
- package/hedhog/frontend/widgets/permissions-card.tsx.ejs +2 -2
- package/hedhog/frontend/widgets/permissions-chart.tsx.ejs +1 -1
- package/hedhog/frontend/widgets/profile-card.tsx.ejs +1 -1
- package/hedhog/frontend/widgets/routes-card.tsx.ejs +2 -2
- package/hedhog/frontend/widgets/session-activity-chart.tsx.ejs +1 -1
- package/hedhog/frontend/widgets/sessions-today-card.tsx.ejs +2 -2
- package/hedhog/frontend/widgets/stat-access-level.tsx.ejs +1 -1
- package/hedhog/frontend/widgets/stat-actions-today.tsx.ejs +1 -1
- package/hedhog/frontend/widgets/stat-consecutive-days.tsx.ejs +1 -1
- package/hedhog/frontend/widgets/stat-online-time.tsx.ejs +1 -1
- package/hedhog/frontend/widgets/storage-config.tsx.ejs +1 -1
- package/hedhog/frontend/widgets/theme-config.tsx.ejs +1 -1
- package/hedhog/frontend/widgets/user-growth-chart.tsx.ejs +1 -1
- package/hedhog/frontend/widgets/user-roles.tsx.ejs +1 -1
- package/hedhog/frontend/widgets/user-sessions.tsx.ejs +1 -1
- package/hedhog/table/dashboard.yaml +6 -0
- package/package.json +3 -3
- package/src/ai/ai.service.ts +129 -1
- package/src/dashboard/dashboard-component/dashboard-component.controller.ts +15 -2
- package/src/dashboard/dashboard-component/dashboard-component.service.ts +107 -43
- package/src/dashboard/dashboard-core/dashboard-core.controller.ts +119 -1
- package/src/dashboard/dashboard-core/dashboard-core.service.ts +876 -20
- package/src/index.ts +7 -6
- package/src/mail/mail.service.ts +67 -3
- package/src/setting/setting.service.ts +222 -15
- package/hedhog/frontend/app/dashboard/components/widgets/core..gitkeep.ejs +0 -11
- package/hedhog/frontend/app/dashboard/components/widgets/core.account-security.tsx.ejs +0 -192
- package/hedhog/frontend/app/dashboard/components/widgets/core.active-users-card.tsx.ejs +0 -58
- package/hedhog/frontend/app/dashboard/components/widgets/core.activity-timeline.tsx.ejs +0 -223
- package/hedhog/frontend/app/dashboard/components/widgets/core.email-notifications.tsx.ejs +0 -226
- package/hedhog/frontend/app/dashboard/components/widgets/core.locale-config.tsx.ejs +0 -168
- package/hedhog/frontend/app/dashboard/components/widgets/core.login-history-chart.tsx.ejs +0 -115
- package/hedhog/frontend/app/dashboard/components/widgets/core.mail-config.tsx.ejs +0 -199
- package/hedhog/frontend/app/dashboard/components/widgets/core.mail-sent-card.tsx.ejs +0 -58
- package/hedhog/frontend/app/dashboard/components/widgets/core.mail-sent-chart.tsx.ejs +0 -149
- package/hedhog/frontend/app/dashboard/components/widgets/core.menus-card.tsx.ejs +0 -58
- package/hedhog/frontend/app/dashboard/components/widgets/core.oauth-config.tsx.ejs +0 -175
- package/hedhog/frontend/app/dashboard/components/widgets/core.permissions-card.tsx.ejs +0 -61
- package/hedhog/frontend/app/dashboard/components/widgets/core.permissions-chart.tsx.ejs +0 -156
- package/hedhog/frontend/app/dashboard/components/widgets/core.profile-card.tsx.ejs +0 -186
- package/hedhog/frontend/app/dashboard/components/widgets/core.routes-card.tsx.ejs +0 -58
- package/hedhog/frontend/app/dashboard/components/widgets/core.session-activity-chart.tsx.ejs +0 -183
- package/hedhog/frontend/app/dashboard/components/widgets/core.sessions-today-card.tsx.ejs +0 -62
- package/hedhog/frontend/app/dashboard/components/widgets/core.stat-access-level.tsx.ejs +0 -57
- package/hedhog/frontend/app/dashboard/components/widgets/core.stat-actions-today.tsx.ejs +0 -57
- package/hedhog/frontend/app/dashboard/components/widgets/core.stat-consecutive-days.tsx.ejs +0 -57
- package/hedhog/frontend/app/dashboard/components/widgets/core.stat-online-time.tsx.ejs +0 -57
- package/hedhog/frontend/app/dashboard/components/widgets/core.storage-config.tsx.ejs +0 -196
- package/hedhog/frontend/app/dashboard/components/widgets/core.theme-config.tsx.ejs +0 -213
- package/hedhog/frontend/app/dashboard/components/widgets/core.user-growth-chart.tsx.ejs +0 -210
- package/hedhog/frontend/app/dashboard/components/widgets/core.user-roles.tsx.ejs +0 -132
- package/hedhog/frontend/app/dashboard/components/widgets/core.user-sessions.tsx.ejs +0 -236
- package/hedhog/frontend/app/dashboard/components/widgets/finance.alerts.tsx.ejs +0 -108
- package/hedhog/frontend/app/dashboard/components/widgets/finance.cash-balance-kpi.tsx.ejs +0 -66
- package/hedhog/frontend/app/dashboard/components/widgets/finance.cash-flow-chart.tsx.ejs +0 -122
- package/hedhog/frontend/app/dashboard/components/widgets/finance.default-kpi.tsx.ejs +0 -63
- package/hedhog/frontend/app/dashboard/components/widgets/finance.payable-30d-kpi.tsx.ejs +0 -73
- package/hedhog/frontend/app/dashboard/components/widgets/finance.receivable-30d-kpi.tsx.ejs +0 -73
- package/hedhog/frontend/app/dashboard/components/widgets/finance.upcoming-payable.tsx.ejs +0 -123
- package/hedhog/frontend/app/dashboard/components/widgets/finance.upcoming-receivable.tsx.ejs +0 -118
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { useWidgetData } from '@/hooks/use-widget-data';
|
|
2
2
|
import { LayoutList } from 'lucide-react';
|
|
3
3
|
import { useTranslations } from 'next-intl';
|
|
4
|
-
import StatCard from '
|
|
5
|
-
import { WidgetWrapper } from '
|
|
4
|
+
import StatCard from '@/app/(app)/(libraries)/core/dashboard/components/stats';
|
|
5
|
+
import { WidgetWrapper } from '@/app/(app)/(libraries)/core/dashboard/components';
|
|
6
6
|
|
|
7
7
|
interface MenusCardProps {
|
|
8
8
|
widget?: any;
|
|
@@ -15,7 +15,7 @@ import type {
|
|
|
15
15
|
} from '@/types/widget-data';
|
|
16
16
|
import { CheckCircle2, KeyRound, XCircle } from 'lucide-react';
|
|
17
17
|
import { useTranslations } from 'next-intl';
|
|
18
|
-
import { WidgetWrapper } from '
|
|
18
|
+
import { WidgetWrapper } from '@/app/(app)/(libraries)/core/dashboard/components';
|
|
19
19
|
|
|
20
20
|
const defaultOAuthConfigData: OAuthConfigWidgetData = {
|
|
21
21
|
status: {
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { useWidgetData } from '@/hooks/use-widget-data';
|
|
2
2
|
import { Shield } from 'lucide-react';
|
|
3
3
|
import { useTranslations } from 'next-intl';
|
|
4
|
-
import StatCard from '
|
|
5
|
-
import { WidgetWrapper } from '
|
|
4
|
+
import StatCard from '@/app/(app)/(libraries)/core/dashboard/components/stats';
|
|
5
|
+
import { WidgetWrapper } from '@/app/(app)/(libraries)/core/dashboard/components';
|
|
6
6
|
|
|
7
7
|
interface PermissionsCardProps {
|
|
8
8
|
widget?: any;
|
|
@@ -11,7 +11,7 @@ import { useWidgetData } from '@/hooks/use-widget-data';
|
|
|
11
11
|
import { IconGripVertical } from '@tabler/icons-react';
|
|
12
12
|
import { useTranslations } from 'next-intl';
|
|
13
13
|
import { Cell, Pie, PieChart, ResponsiveContainer, Tooltip } from 'recharts';
|
|
14
|
-
import { WidgetWrapper } from '
|
|
14
|
+
import { WidgetWrapper } from '@/app/(app)/(libraries)/core/dashboard/components';
|
|
15
15
|
|
|
16
16
|
function CustomTooltip({
|
|
17
17
|
active,
|
|
@@ -21,7 +21,7 @@ import {
|
|
|
21
21
|
} from 'lucide-react';
|
|
22
22
|
import { useTranslations } from 'next-intl';
|
|
23
23
|
import { useRouter } from 'next/navigation';
|
|
24
|
-
import { WidgetWrapper } from '
|
|
24
|
+
import { WidgetWrapper } from '@/app/(app)/(libraries)/core/dashboard/components';
|
|
25
25
|
|
|
26
26
|
function getInitials(name: string): string {
|
|
27
27
|
return name
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { useWidgetData } from '@/hooks/use-widget-data';
|
|
2
2
|
import { Route } from 'lucide-react';
|
|
3
3
|
import { useTranslations } from 'next-intl';
|
|
4
|
-
import StatCard from '
|
|
5
|
-
import { WidgetWrapper } from '
|
|
4
|
+
import StatCard from '@/app/(app)/(libraries)/core/dashboard/components/stats';
|
|
5
|
+
import { WidgetWrapper } from '@/app/(app)/(libraries)/core/dashboard/components';
|
|
6
6
|
|
|
7
7
|
interface RoutesCardProps {
|
|
8
8
|
widget?: any;
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { useWidgetData } from '@/hooks/use-widget-data';
|
|
2
2
|
import { Activity } from 'lucide-react';
|
|
3
3
|
import { useTranslations } from 'next-intl';
|
|
4
|
-
import StatCard from '
|
|
5
|
-
import { WidgetWrapper } from '
|
|
4
|
+
import StatCard from '@/app/(app)/(libraries)/core/dashboard/components/stats';
|
|
5
|
+
import { WidgetWrapper } from '@/app/(app)/(libraries)/core/dashboard/components';
|
|
6
6
|
|
|
7
7
|
interface SessionsTodayProps {
|
|
8
8
|
widget?: any;
|
|
@@ -5,7 +5,7 @@ import { useWidgetData } from '@/hooks/use-widget-data';
|
|
|
5
5
|
import type { AllWidgetsData } from '@/types/widget-data';
|
|
6
6
|
import { Zap } from 'lucide-react';
|
|
7
7
|
import { useTranslations } from 'next-intl';
|
|
8
|
-
import { WidgetWrapper } from '
|
|
8
|
+
import { WidgetWrapper } from '@/app/(app)/(libraries)/core/dashboard/components';
|
|
9
9
|
|
|
10
10
|
interface StatAccessLevelProps {
|
|
11
11
|
widget?: { name?: string };
|
|
@@ -5,7 +5,7 @@ import { useWidgetData } from '@/hooks/use-widget-data';
|
|
|
5
5
|
import type { AllWidgetsData } from '@/types/widget-data';
|
|
6
6
|
import { MousePointerClick } from 'lucide-react';
|
|
7
7
|
import { useTranslations } from 'next-intl';
|
|
8
|
-
import { WidgetWrapper } from '
|
|
8
|
+
import { WidgetWrapper } from '@/app/(app)/(libraries)/core/dashboard/components';
|
|
9
9
|
|
|
10
10
|
interface StatActionsTodayProps {
|
|
11
11
|
widget?: { name?: string };
|
|
@@ -5,7 +5,7 @@ import { useWidgetData } from '@/hooks/use-widget-data';
|
|
|
5
5
|
import type { AllWidgetsData } from '@/types/widget-data';
|
|
6
6
|
import { CalendarDays } from 'lucide-react';
|
|
7
7
|
import { useTranslations } from 'next-intl';
|
|
8
|
-
import { WidgetWrapper } from '
|
|
8
|
+
import { WidgetWrapper } from '@/app/(app)/(libraries)/core/dashboard/components';
|
|
9
9
|
|
|
10
10
|
interface StatConsecutiveDaysProps {
|
|
11
11
|
widget?: { name?: string };
|
|
@@ -5,7 +5,7 @@ import { useWidgetData } from '@/hooks/use-widget-data';
|
|
|
5
5
|
import type { AllWidgetsData } from '@/types/widget-data';
|
|
6
6
|
import { Clock } from 'lucide-react';
|
|
7
7
|
import { useTranslations } from 'next-intl';
|
|
8
|
-
import { WidgetWrapper } from '
|
|
8
|
+
import { WidgetWrapper } from '@/app/(app)/(libraries)/core/dashboard/components';
|
|
9
9
|
|
|
10
10
|
interface StatOnlineTimeProps {
|
|
11
11
|
widget?: { name?: string };
|
|
@@ -15,7 +15,7 @@ import type {
|
|
|
15
15
|
} from '@/types/widget-data';
|
|
16
16
|
import { CheckCircle2, HardDrive } from 'lucide-react';
|
|
17
17
|
import { useTranslations } from 'next-intl';
|
|
18
|
-
import { WidgetWrapper } from '
|
|
18
|
+
import { WidgetWrapper } from '@/app/(app)/(libraries)/core/dashboard/components';
|
|
19
19
|
|
|
20
20
|
const defaultStorageConfigData: StorageConfigWidgetData = {
|
|
21
21
|
status: {
|
|
@@ -15,7 +15,7 @@ import type {
|
|
|
15
15
|
} from '@/types/widget-data';
|
|
16
16
|
import { Palette } from 'lucide-react';
|
|
17
17
|
import { useTranslations } from 'next-intl';
|
|
18
|
-
import { WidgetWrapper } from '
|
|
18
|
+
import { WidgetWrapper } from '@/app/(app)/(libraries)/core/dashboard/components';
|
|
19
19
|
|
|
20
20
|
const emptyPaletteMode = {
|
|
21
21
|
primary: null,
|
|
@@ -12,7 +12,7 @@ import { useWidgetData } from '@/hooks/use-widget-data';
|
|
|
12
12
|
import type { AllWidgetsData, RoleData } from '@/types/widget-data';
|
|
13
13
|
import { Crown, ShieldCheck } from 'lucide-react';
|
|
14
14
|
import { useTranslations } from 'next-intl';
|
|
15
|
-
import { WidgetWrapper } from '
|
|
15
|
+
import { WidgetWrapper } from '@/app/(app)/(libraries)/core/dashboard/components';
|
|
16
16
|
|
|
17
17
|
const levelStyles = [
|
|
18
18
|
{
|
|
@@ -29,7 +29,7 @@ import {
|
|
|
29
29
|
} from 'lucide-react';
|
|
30
30
|
import { useTranslations } from 'next-intl';
|
|
31
31
|
import { useRouter } from 'next/navigation';
|
|
32
|
-
import { WidgetWrapper } from '
|
|
32
|
+
import { WidgetWrapper } from '@/app/(app)/(libraries)/core/dashboard/components';
|
|
33
33
|
|
|
34
34
|
function detectDeviceType(ua: string): 'desktop' | 'mobile' | 'tablet' {
|
|
35
35
|
const u = ua.toLowerCase();
|
|
@@ -1,11 +1,17 @@
|
|
|
1
1
|
columns:
|
|
2
2
|
- type: pk
|
|
3
3
|
- type: slug
|
|
4
|
+
- name: icon
|
|
5
|
+
length: 255
|
|
6
|
+
isNullable: true
|
|
4
7
|
- name: name
|
|
5
8
|
type: locale_varchar
|
|
6
9
|
length: 255
|
|
7
10
|
locale:
|
|
8
11
|
en: Name
|
|
9
12
|
pt: Nome
|
|
13
|
+
- name: is_template
|
|
14
|
+
type: boolean
|
|
15
|
+
default: false
|
|
10
16
|
- type: created_at
|
|
11
17
|
- type: updated_at
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@hed-hog/core",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.301",
|
|
4
4
|
"main": "dist/index.js",
|
|
5
5
|
"types": "dist/index.d.ts",
|
|
6
6
|
"dependencies": {
|
|
@@ -32,9 +32,9 @@
|
|
|
32
32
|
"uuid": "^11.1.0",
|
|
33
33
|
"@hed-hog/api": "0.0.6",
|
|
34
34
|
"@hed-hog/api-types": "0.0.1",
|
|
35
|
-
"@hed-hog/api-pagination": "0.0.7",
|
|
36
|
-
"@hed-hog/api-locale": "0.0.14",
|
|
37
35
|
"@hed-hog/api-mail": "0.0.9",
|
|
36
|
+
"@hed-hog/api-locale": "0.0.14",
|
|
37
|
+
"@hed-hog/api-pagination": "0.0.7",
|
|
38
38
|
"@hed-hog/api-prisma": "0.0.6"
|
|
39
39
|
},
|
|
40
40
|
"exports": {
|
package/src/ai/ai.service.ts
CHANGED
|
@@ -7,12 +7,14 @@ import {
|
|
|
7
7
|
Injectable,
|
|
8
8
|
Logger,
|
|
9
9
|
NotFoundException,
|
|
10
|
+
OnModuleInit,
|
|
10
11
|
} from '@nestjs/common';
|
|
11
12
|
import axios from 'axios';
|
|
12
13
|
import { createHash } from 'crypto';
|
|
13
14
|
import pdfParse from 'pdf-parse';
|
|
14
15
|
import { DeleteDTO } from '../dto/delete.dto';
|
|
15
16
|
import { FileService } from '../file/file.service';
|
|
17
|
+
import { IntegrationDeveloperApiService } from '../integration/services/integration-developer-api.service';
|
|
16
18
|
import { SettingService } from '../setting/setting.service';
|
|
17
19
|
import { ChatAgentDTO } from './dto/chat-agent.dto';
|
|
18
20
|
import { ChatDTO } from './dto/chat.dto';
|
|
@@ -38,8 +40,10 @@ type AiAttachment = {
|
|
|
38
40
|
buffer: Buffer;
|
|
39
41
|
};
|
|
40
42
|
|
|
43
|
+
type AiProviderKeySettingSlug = 'ai-openai-api-key' | 'ai-gemini-api-key';
|
|
44
|
+
|
|
41
45
|
@Injectable()
|
|
42
|
-
export class AiService {
|
|
46
|
+
export class AiService implements OnModuleInit {
|
|
43
47
|
private readonly logger = new Logger(AiService.name);
|
|
44
48
|
|
|
45
49
|
constructor(
|
|
@@ -49,8 +53,29 @@ export class AiService {
|
|
|
49
53
|
private readonly settingService: SettingService,
|
|
50
54
|
@Inject(forwardRef(() => FileService))
|
|
51
55
|
private readonly fileService: FileService,
|
|
56
|
+
@Inject(forwardRef(() => IntegrationDeveloperApiService))
|
|
57
|
+
private readonly integrationApi: IntegrationDeveloperApiService,
|
|
52
58
|
) {}
|
|
53
59
|
|
|
60
|
+
onModuleInit(): void {
|
|
61
|
+
this.integrationApi.subscribe({
|
|
62
|
+
eventName: 'core.setting.changed',
|
|
63
|
+
consumerName: 'core.ai-provider-key-validator',
|
|
64
|
+
priority: 0,
|
|
65
|
+
handler: async (event) => {
|
|
66
|
+
const slug = String(event.payload?.slug || '').trim();
|
|
67
|
+
|
|
68
|
+
if (!this.isAiProviderKeySlug(slug)) {
|
|
69
|
+
return;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
await this.syncProviderEnabledFlag(slug);
|
|
73
|
+
},
|
|
74
|
+
});
|
|
75
|
+
|
|
76
|
+
void this.syncAllProviderEnabledFlags();
|
|
77
|
+
}
|
|
78
|
+
|
|
54
79
|
async chat(data: ChatDTO, file?: MulterFile) {
|
|
55
80
|
const provider = data.provider || 'openai';
|
|
56
81
|
const attachment = await this.resolveAttachment(file, data.file_id);
|
|
@@ -398,6 +423,109 @@ export class AiService {
|
|
|
398
423
|
return 'gemini-1.5-flash';
|
|
399
424
|
}
|
|
400
425
|
|
|
426
|
+
private isAiProviderKeySlug(slug: string): slug is AiProviderKeySettingSlug {
|
|
427
|
+
return slug === 'ai-openai-api-key' || slug === 'ai-gemini-api-key';
|
|
428
|
+
}
|
|
429
|
+
|
|
430
|
+
private getEnabledSlugFromProviderKey(slug: AiProviderKeySettingSlug) {
|
|
431
|
+
return slug === 'ai-openai-api-key'
|
|
432
|
+
? 'ai-openai-api-key-enabled'
|
|
433
|
+
: 'ai-gemini-api-key-enabled';
|
|
434
|
+
}
|
|
435
|
+
|
|
436
|
+
private async syncAllProviderEnabledFlags() {
|
|
437
|
+
const results = await Promise.allSettled([
|
|
438
|
+
this.syncProviderEnabledFlag('ai-openai-api-key'),
|
|
439
|
+
this.syncProviderEnabledFlag('ai-gemini-api-key'),
|
|
440
|
+
]);
|
|
441
|
+
|
|
442
|
+
results.forEach((result, index) => {
|
|
443
|
+
if (result.status === 'rejected') {
|
|
444
|
+
const slug = index === 0 ? 'ai-openai-api-key' : 'ai-gemini-api-key';
|
|
445
|
+
this.logger.warn(
|
|
446
|
+
`Failed to sync provider availability for ${slug}: ${result.reason instanceof Error ? result.reason.message : String(result.reason)}`,
|
|
447
|
+
);
|
|
448
|
+
}
|
|
449
|
+
});
|
|
450
|
+
}
|
|
451
|
+
|
|
452
|
+
private async syncProviderEnabledFlag(slug: AiProviderKeySettingSlug) {
|
|
453
|
+
const values = await this.settingService.getSettingValues(slug);
|
|
454
|
+
const apiKey = String(values?.[slug] || '').trim();
|
|
455
|
+
const enabledSlug = this.getEnabledSlugFromProviderKey(slug);
|
|
456
|
+
|
|
457
|
+
const isValid = slug === 'ai-openai-api-key'
|
|
458
|
+
? await this.validateOpenAiKey(apiKey)
|
|
459
|
+
: await this.validateGeminiKey(apiKey);
|
|
460
|
+
|
|
461
|
+
await this.settingService.setValue(enabledSlug, isValid ? 'true' : 'false');
|
|
462
|
+
}
|
|
463
|
+
|
|
464
|
+
private getValidationErrorMessage(error: unknown) {
|
|
465
|
+
if (axios.isAxiosError(error)) {
|
|
466
|
+
const providerMessage =
|
|
467
|
+
error.response?.data?.error?.message ||
|
|
468
|
+
error.response?.data?.message ||
|
|
469
|
+
error.message;
|
|
470
|
+
const status = error.response?.status || 'network';
|
|
471
|
+
return `${status}: ${providerMessage}`;
|
|
472
|
+
}
|
|
473
|
+
|
|
474
|
+
return error instanceof Error ? error.message : String(error);
|
|
475
|
+
}
|
|
476
|
+
|
|
477
|
+
private async validateOpenAiKey(apiKey?: string | null): Promise<boolean> {
|
|
478
|
+
const normalizedKey = String(apiKey || '').trim();
|
|
479
|
+
|
|
480
|
+
if (!normalizedKey) {
|
|
481
|
+
return false;
|
|
482
|
+
}
|
|
483
|
+
|
|
484
|
+
try {
|
|
485
|
+
await axios.get('https://api.openai.com/v1/models', {
|
|
486
|
+
headers: {
|
|
487
|
+
Authorization: `Bearer ${normalizedKey}`,
|
|
488
|
+
},
|
|
489
|
+
params: {
|
|
490
|
+
limit: 1,
|
|
491
|
+
},
|
|
492
|
+
timeout: 5000,
|
|
493
|
+
});
|
|
494
|
+
|
|
495
|
+
return true;
|
|
496
|
+
} catch (error) {
|
|
497
|
+
this.logger.warn(
|
|
498
|
+
`OpenAI key validation failed: ${this.getValidationErrorMessage(error)}`,
|
|
499
|
+
);
|
|
500
|
+
return false;
|
|
501
|
+
}
|
|
502
|
+
}
|
|
503
|
+
|
|
504
|
+
private async validateGeminiKey(apiKey?: string | null): Promise<boolean> {
|
|
505
|
+
const normalizedKey = String(apiKey || '').trim();
|
|
506
|
+
|
|
507
|
+
if (!normalizedKey) {
|
|
508
|
+
return false;
|
|
509
|
+
}
|
|
510
|
+
|
|
511
|
+
try {
|
|
512
|
+
await axios.get('https://generativelanguage.googleapis.com/v1beta/models', {
|
|
513
|
+
params: {
|
|
514
|
+
key: normalizedKey,
|
|
515
|
+
pageSize: 1,
|
|
516
|
+
},
|
|
517
|
+
timeout: 5000,
|
|
518
|
+
});
|
|
519
|
+
|
|
520
|
+
return true;
|
|
521
|
+
} catch (error) {
|
|
522
|
+
this.logger.warn(
|
|
523
|
+
`Gemini key validation failed: ${this.getValidationErrorMessage(error)}`,
|
|
524
|
+
);
|
|
525
|
+
return false;
|
|
526
|
+
}
|
|
527
|
+
}
|
|
528
|
+
|
|
401
529
|
private async getApiKeys() {
|
|
402
530
|
const settings = await this.settingService.getSettingValues([
|
|
403
531
|
'ai-openai-api-key',
|
|
@@ -12,6 +12,7 @@ import {
|
|
|
12
12
|
ParseIntPipe,
|
|
13
13
|
Patch,
|
|
14
14
|
Post,
|
|
15
|
+
Query,
|
|
15
16
|
UploadedFile,
|
|
16
17
|
UseInterceptors,
|
|
17
18
|
forwardRef
|
|
@@ -37,8 +38,20 @@ export class DashboardComponentController {
|
|
|
37
38
|
}
|
|
38
39
|
|
|
39
40
|
@Get('user')
|
|
40
|
-
getAllComponentsByUserRole(
|
|
41
|
-
|
|
41
|
+
getAllComponentsByUserRole(
|
|
42
|
+
@Pagination() paginationParams,
|
|
43
|
+
@User() { id },
|
|
44
|
+
@Query('librarySlug') librarySlug?: string,
|
|
45
|
+
@Query('exclude') exclude?: string,
|
|
46
|
+
) {
|
|
47
|
+
return this.dashboardComponentService.getAllComponentsByUserRole(
|
|
48
|
+
{
|
|
49
|
+
...paginationParams,
|
|
50
|
+
librarySlug,
|
|
51
|
+
exclude,
|
|
52
|
+
},
|
|
53
|
+
id,
|
|
54
|
+
);
|
|
42
55
|
}
|
|
43
56
|
|
|
44
57
|
@Get(':id')
|
|
@@ -2,19 +2,24 @@ import { getLocaleText } from '@hed-hog/api-locale';
|
|
|
2
2
|
import { PaginationDTO, PaginationService } from '@hed-hog/api-pagination';
|
|
3
3
|
import { PrismaService } from '@hed-hog/api-prisma';
|
|
4
4
|
import {
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
5
|
+
BadRequestException,
|
|
6
|
+
ForbiddenException,
|
|
7
|
+
forwardRef,
|
|
8
|
+
Inject,
|
|
9
|
+
Injectable,
|
|
10
|
+
NotFoundException,
|
|
11
11
|
} from '@nestjs/common';
|
|
12
12
|
import { existsSync, promises as fs } from 'fs';
|
|
13
13
|
import { join, resolve } from 'path';
|
|
14
14
|
import {
|
|
15
|
-
|
|
16
|
-
|
|
15
|
+
CreateDashboardComponentDTO,
|
|
16
|
+
UpdateDashboardComponentDTO,
|
|
17
17
|
} from './dto';
|
|
18
|
+
type DashboardComponentUserPagination = PaginationDTO & {
|
|
19
|
+
librarySlug?: string;
|
|
20
|
+
exclude?: string;
|
|
21
|
+
};
|
|
22
|
+
|
|
18
23
|
@Injectable()
|
|
19
24
|
export class DashboardComponentService {
|
|
20
25
|
constructor(
|
|
@@ -79,7 +84,10 @@ export class DashboardComponentService {
|
|
|
79
84
|
);
|
|
80
85
|
}
|
|
81
86
|
|
|
82
|
-
async getAllComponentsByUserRole(
|
|
87
|
+
async getAllComponentsByUserRole(
|
|
88
|
+
paginationParams: DashboardComponentUserPagination,
|
|
89
|
+
userId: number,
|
|
90
|
+
) {
|
|
83
91
|
const userRoles = await this.prismaService.role_user.findMany({
|
|
84
92
|
where: { user_id: userId },
|
|
85
93
|
select: { role_id: true },
|
|
@@ -88,7 +96,7 @@ export class DashboardComponentService {
|
|
|
88
96
|
const userRoleIds = userRoles.map((ur) => ur.role_id);
|
|
89
97
|
|
|
90
98
|
if (userRoleIds.length === 0) {
|
|
91
|
-
|
|
99
|
+
const emptyResult = await this.paginationService.paginate(
|
|
92
100
|
this.prismaService.dashboard_component,
|
|
93
101
|
paginationParams,
|
|
94
102
|
{
|
|
@@ -121,9 +129,30 @@ export class DashboardComponentService {
|
|
|
121
129
|
},
|
|
122
130
|
'dashboardComponent',
|
|
123
131
|
);
|
|
132
|
+
|
|
133
|
+
return {
|
|
134
|
+
...emptyResult,
|
|
135
|
+
modules: [],
|
|
136
|
+
};
|
|
124
137
|
}
|
|
125
138
|
|
|
126
|
-
const
|
|
139
|
+
const requestedLibrarySlug = paginationParams.librarySlug?.trim();
|
|
140
|
+
const excludedComponents = (paginationParams.exclude ?? '')
|
|
141
|
+
.split(',')
|
|
142
|
+
.map((value) => value.trim())
|
|
143
|
+
.filter(Boolean)
|
|
144
|
+
.map((value) => {
|
|
145
|
+
const slugParts = value.split('.').filter(Boolean);
|
|
146
|
+
const baseSlug = slugParts[slugParts.length - 1] || value;
|
|
147
|
+
const librarySlug = slugParts.length > 1 ? slugParts[0] : undefined;
|
|
148
|
+
|
|
149
|
+
return {
|
|
150
|
+
slug: baseSlug,
|
|
151
|
+
...(librarySlug ? { library_slug: librarySlug } : {}),
|
|
152
|
+
};
|
|
153
|
+
});
|
|
154
|
+
|
|
155
|
+
const fields = ['slug', 'library_slug'];
|
|
127
156
|
const OR = this.prismaService.createInsensitiveSearch(
|
|
128
157
|
fields,
|
|
129
158
|
paginationParams,
|
|
@@ -142,52 +171,87 @@ export class DashboardComponentService {
|
|
|
142
171
|
});
|
|
143
172
|
}
|
|
144
173
|
|
|
145
|
-
|
|
146
|
-
this.prismaService.dashboard_component,
|
|
147
|
-
paginationParams,
|
|
174
|
+
const baseFilters = [
|
|
148
175
|
{
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
176
|
+
dashboard_component_role: {
|
|
177
|
+
some: {
|
|
178
|
+
role_id: {
|
|
179
|
+
in: userRoleIds,
|
|
153
180
|
},
|
|
154
181
|
},
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
182
|
+
},
|
|
183
|
+
},
|
|
184
|
+
...(OR.length > 0 ? [{ OR }] : []),
|
|
185
|
+
...(excludedComponents.length > 0
|
|
186
|
+
? [
|
|
187
|
+
{
|
|
188
|
+
NOT: {
|
|
189
|
+
OR: excludedComponents,
|
|
190
|
+
},
|
|
191
|
+
},
|
|
192
|
+
]
|
|
193
|
+
: []),
|
|
194
|
+
];
|
|
195
|
+
|
|
196
|
+
const [paginatedResult, modules] = await Promise.all([
|
|
197
|
+
this.paginationService.paginate(
|
|
198
|
+
this.prismaService.dashboard_component,
|
|
199
|
+
paginationParams,
|
|
200
|
+
{
|
|
201
|
+
include: {
|
|
202
|
+
dashboard_component_locale: {
|
|
203
|
+
include: {
|
|
204
|
+
locale: true,
|
|
205
|
+
},
|
|
206
|
+
},
|
|
207
|
+
dashboard_component_role: {
|
|
208
|
+
include: {
|
|
209
|
+
role: {
|
|
210
|
+
include: {
|
|
211
|
+
role_locale: {
|
|
212
|
+
include: {
|
|
213
|
+
locale: true,
|
|
214
|
+
},
|
|
162
215
|
},
|
|
163
216
|
},
|
|
164
217
|
},
|
|
165
218
|
},
|
|
166
219
|
},
|
|
167
220
|
},
|
|
221
|
+
where: {
|
|
222
|
+
AND: [
|
|
223
|
+
...baseFilters,
|
|
224
|
+
...(requestedLibrarySlug
|
|
225
|
+
? [{ library_slug: requestedLibrarySlug }]
|
|
226
|
+
: []),
|
|
227
|
+
],
|
|
228
|
+
},
|
|
229
|
+
orderBy: {
|
|
230
|
+
created_at: 'desc',
|
|
231
|
+
},
|
|
168
232
|
},
|
|
233
|
+
'dashboardComponent',
|
|
234
|
+
),
|
|
235
|
+
this.prismaService.dashboard_component.findMany({
|
|
169
236
|
where: {
|
|
170
|
-
AND:
|
|
171
|
-
{
|
|
172
|
-
dashboard_component_role: {
|
|
173
|
-
some: {
|
|
174
|
-
role_id: {
|
|
175
|
-
in: userRoleIds,
|
|
176
|
-
},
|
|
177
|
-
},
|
|
178
|
-
},
|
|
179
|
-
},
|
|
180
|
-
{
|
|
181
|
-
OR,
|
|
182
|
-
},
|
|
183
|
-
],
|
|
237
|
+
AND: baseFilters,
|
|
184
238
|
},
|
|
239
|
+
select: {
|
|
240
|
+
library_slug: true,
|
|
241
|
+
},
|
|
242
|
+
distinct: ['library_slug'],
|
|
185
243
|
orderBy: {
|
|
186
|
-
|
|
244
|
+
library_slug: 'asc',
|
|
187
245
|
},
|
|
188
|
-
},
|
|
189
|
-
|
|
190
|
-
|
|
246
|
+
}),
|
|
247
|
+
]);
|
|
248
|
+
|
|
249
|
+
return {
|
|
250
|
+
...paginatedResult,
|
|
251
|
+
modules: modules
|
|
252
|
+
.map((component) => component.library_slug)
|
|
253
|
+
.filter((value): value is string => Boolean(value)),
|
|
254
|
+
};
|
|
191
255
|
}
|
|
192
256
|
|
|
193
257
|
async getComponent(id: number, locale: string, userId?: number) {
|