@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
package/hedhog/frontend/app/dashboard/components/widgets/core.session-activity-chart.tsx.ejs
DELETED
|
@@ -1,183 +0,0 @@
|
|
|
1
|
-
'use client';
|
|
2
|
-
|
|
3
|
-
import {
|
|
4
|
-
Card,
|
|
5
|
-
CardContent,
|
|
6
|
-
CardDescription,
|
|
7
|
-
CardHeader,
|
|
8
|
-
CardTitle,
|
|
9
|
-
} from '@/components/ui/card';
|
|
10
|
-
import { useWidgetData } from '@/hooks/use-widget-data';
|
|
11
|
-
import { IconGripVertical } from '@tabler/icons-react';
|
|
12
|
-
import { useTranslations } from 'next-intl';
|
|
13
|
-
import {
|
|
14
|
-
CartesianGrid,
|
|
15
|
-
Line,
|
|
16
|
-
LineChart,
|
|
17
|
-
ResponsiveContainer,
|
|
18
|
-
Tooltip,
|
|
19
|
-
XAxis,
|
|
20
|
-
YAxis,
|
|
21
|
-
} from 'recharts';
|
|
22
|
-
import { WidgetWrapper } from '../widget-wrapper';
|
|
23
|
-
|
|
24
|
-
function CustomTooltip({
|
|
25
|
-
active,
|
|
26
|
-
payload,
|
|
27
|
-
label,
|
|
28
|
-
}: {
|
|
29
|
-
active?: boolean;
|
|
30
|
-
payload?: Array<{ value: number; dataKey: string }>;
|
|
31
|
-
label?: string;
|
|
32
|
-
}) {
|
|
33
|
-
const t = useTranslations('core.Dashboard');
|
|
34
|
-
if (!active || !payload?.length) return null;
|
|
35
|
-
|
|
36
|
-
return (
|
|
37
|
-
<div className="rounded-lg border bg-card px-3 py-2 shadow-xl">
|
|
38
|
-
<p className="mb-1 text-xs font-medium text-card-foreground">{label}</p>
|
|
39
|
-
{payload.map((entry) => (
|
|
40
|
-
<p key={entry.dataKey} className="text-xs text-muted-foreground">
|
|
41
|
-
<span
|
|
42
|
-
className="mr-1.5 inline-block h-2 w-2 rounded-full"
|
|
43
|
-
style={{
|
|
44
|
-
backgroundColor:
|
|
45
|
-
entry.dataKey === 'active' ? '#10b981' : '#f59e0b',
|
|
46
|
-
}}
|
|
47
|
-
/>
|
|
48
|
-
{entry.dataKey === 'active' ? t('active') : t('expired')}:{' '}
|
|
49
|
-
{entry.value}
|
|
50
|
-
</p>
|
|
51
|
-
))}
|
|
52
|
-
</div>
|
|
53
|
-
);
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
interface SessionActivityChartProps {
|
|
57
|
-
widget?: any;
|
|
58
|
-
onRemove?: () => void;
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
interface UserStatsData {
|
|
62
|
-
charts?: {
|
|
63
|
-
sessionActivity?: Array<{
|
|
64
|
-
hour: string;
|
|
65
|
-
active: number;
|
|
66
|
-
expired: number;
|
|
67
|
-
}>;
|
|
68
|
-
};
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
export default function SessionActivityChart({
|
|
72
|
-
widget,
|
|
73
|
-
onRemove,
|
|
74
|
-
}: SessionActivityChartProps) {
|
|
75
|
-
const t = useTranslations('core.Dashboard');
|
|
76
|
-
|
|
77
|
-
const {
|
|
78
|
-
data: statsData,
|
|
79
|
-
isLoading,
|
|
80
|
-
isAccessDenied,
|
|
81
|
-
isError,
|
|
82
|
-
} = useWidgetData<UserStatsData>({
|
|
83
|
-
endpoint: '/dashboard-core/stats/overview/users',
|
|
84
|
-
queryKey: 'dashboard-stats-users',
|
|
85
|
-
});
|
|
86
|
-
|
|
87
|
-
const data = statsData?.charts?.sessionActivity || [];
|
|
88
|
-
|
|
89
|
-
return (
|
|
90
|
-
<WidgetWrapper
|
|
91
|
-
isLoading={isLoading}
|
|
92
|
-
isAccessDenied={isAccessDenied}
|
|
93
|
-
isError={isError}
|
|
94
|
-
widgetName={widget?.name || t('sessionActivityTitle')}
|
|
95
|
-
onRemove={onRemove}
|
|
96
|
-
>
|
|
97
|
-
<Card className="h-full flex flex-col group">
|
|
98
|
-
<div
|
|
99
|
-
className="drag-handle absolute top-3 left-4 z-10"
|
|
100
|
-
style={{ cursor: 'grab' }}
|
|
101
|
-
>
|
|
102
|
-
<IconGripVertical className="text-muted-foreground/50 size-4 shrink-0" />
|
|
103
|
-
</div>
|
|
104
|
-
<CardHeader className="flex flex-row items-center justify-between pb-2 pt-4">
|
|
105
|
-
<div className="pl-6">
|
|
106
|
-
<CardTitle className="text-base font-semibold">
|
|
107
|
-
{t('sessionActivityTitle')}
|
|
108
|
-
</CardTitle>
|
|
109
|
-
<CardDescription>{t('sessionActivityDescription')}</CardDescription>
|
|
110
|
-
</div>
|
|
111
|
-
</CardHeader>
|
|
112
|
-
<CardContent className="flex-1 pt-0">
|
|
113
|
-
<div className="h-[200px] w-full">
|
|
114
|
-
<ResponsiveContainer width="100%" height="100%">
|
|
115
|
-
<LineChart
|
|
116
|
-
data={data}
|
|
117
|
-
margin={{ top: 5, right: 10, left: -20, bottom: 0 }}
|
|
118
|
-
>
|
|
119
|
-
<CartesianGrid
|
|
120
|
-
strokeDasharray="3 3"
|
|
121
|
-
stroke="currentColor"
|
|
122
|
-
opacity={0.1}
|
|
123
|
-
/>
|
|
124
|
-
<XAxis
|
|
125
|
-
dataKey="hour"
|
|
126
|
-
tick={{ fill: 'hsl(var(--muted-foreground))', fontSize: 11 }}
|
|
127
|
-
axisLine={false}
|
|
128
|
-
tickLine={false}
|
|
129
|
-
/>
|
|
130
|
-
<YAxis
|
|
131
|
-
tick={{ fill: 'hsl(var(--muted-foreground))', fontSize: 11 }}
|
|
132
|
-
axisLine={false}
|
|
133
|
-
tickLine={false}
|
|
134
|
-
/>
|
|
135
|
-
<Tooltip content={<CustomTooltip />} />
|
|
136
|
-
<Line
|
|
137
|
-
type="monotone"
|
|
138
|
-
dataKey="active"
|
|
139
|
-
stroke="#10b981"
|
|
140
|
-
strokeWidth={3}
|
|
141
|
-
dot={false}
|
|
142
|
-
activeDot={{ r: 5, fill: '#10b981' }}
|
|
143
|
-
animationDuration={1500}
|
|
144
|
-
/>
|
|
145
|
-
<Line
|
|
146
|
-
type="monotone"
|
|
147
|
-
dataKey="expired"
|
|
148
|
-
stroke="#f59e0b"
|
|
149
|
-
strokeWidth={2.5}
|
|
150
|
-
dot={false}
|
|
151
|
-
strokeDasharray="5 5"
|
|
152
|
-
activeDot={{ r: 4, fill: '#f59e0b' }}
|
|
153
|
-
animationDuration={1500}
|
|
154
|
-
animationBegin={300}
|
|
155
|
-
/>
|
|
156
|
-
</LineChart>
|
|
157
|
-
</ResponsiveContainer>
|
|
158
|
-
</div>
|
|
159
|
-
<div className="mt-2 flex items-center justify-center gap-6">
|
|
160
|
-
<div className="flex items-center gap-2">
|
|
161
|
-
<div
|
|
162
|
-
className="h-0.5 w-4 rounded-full"
|
|
163
|
-
style={{ backgroundColor: '#10b981' }}
|
|
164
|
-
/>
|
|
165
|
-
<span className="text-xs text-muted-foreground">
|
|
166
|
-
{t('active')}
|
|
167
|
-
</span>
|
|
168
|
-
</div>
|
|
169
|
-
<div className="flex items-center gap-2">
|
|
170
|
-
<div
|
|
171
|
-
className="h-0.5 w-4 rounded-full"
|
|
172
|
-
style={{ backgroundColor: '#f59e0b' }}
|
|
173
|
-
/>
|
|
174
|
-
<span className="text-xs text-muted-foreground">
|
|
175
|
-
{t('expired')}
|
|
176
|
-
</span>
|
|
177
|
-
</div>
|
|
178
|
-
</div>
|
|
179
|
-
</CardContent>
|
|
180
|
-
</Card>
|
|
181
|
-
</WidgetWrapper>
|
|
182
|
-
);
|
|
183
|
-
}
|
|
@@ -1,62 +0,0 @@
|
|
|
1
|
-
import { useWidgetData } from '@/hooks/use-widget-data';
|
|
2
|
-
import { Activity } from 'lucide-react';
|
|
3
|
-
import { useTranslations } from 'next-intl';
|
|
4
|
-
import StatCard from '../stats';
|
|
5
|
-
import { WidgetWrapper } from '../widget-wrapper';
|
|
6
|
-
|
|
7
|
-
interface SessionsTodayProps {
|
|
8
|
-
widget?: any;
|
|
9
|
-
onRemove?: () => void;
|
|
10
|
-
}
|
|
11
|
-
|
|
12
|
-
interface UserStatsData {
|
|
13
|
-
cards?: {
|
|
14
|
-
sessionsToday?: {
|
|
15
|
-
value: number;
|
|
16
|
-
change: number | null;
|
|
17
|
-
};
|
|
18
|
-
};
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
export default function SessionsToday({
|
|
22
|
-
widget,
|
|
23
|
-
onRemove,
|
|
24
|
-
}: SessionsTodayProps) {
|
|
25
|
-
const t = useTranslations('core.Dashboard');
|
|
26
|
-
|
|
27
|
-
const { data, isLoading, isAccessDenied, isError } =
|
|
28
|
-
useWidgetData<UserStatsData>({
|
|
29
|
-
endpoint: '/dashboard-core/stats/overview/users',
|
|
30
|
-
queryKey: 'dashboard-stats-users',
|
|
31
|
-
});
|
|
32
|
-
|
|
33
|
-
const value =
|
|
34
|
-
data?.cards?.sessionsToday?.value?.toLocaleString('pt-BR') || '0';
|
|
35
|
-
const change = data?.cards?.sessionsToday?.change;
|
|
36
|
-
const changeType =
|
|
37
|
-
change !== null && change !== undefined && change >= 0 ? 'up' : 'down';
|
|
38
|
-
|
|
39
|
-
return (
|
|
40
|
-
<WidgetWrapper
|
|
41
|
-
isLoading={isLoading}
|
|
42
|
-
isAccessDenied={isAccessDenied}
|
|
43
|
-
isError={isError}
|
|
44
|
-
widgetName={widget?.name || t('sessionsToday')}
|
|
45
|
-
onRemove={onRemove}
|
|
46
|
-
>
|
|
47
|
-
<StatCard
|
|
48
|
-
title={t('sessionsToday')}
|
|
49
|
-
value={value}
|
|
50
|
-
change={
|
|
51
|
-
change !== null && change !== undefined
|
|
52
|
-
? `${change > 0 ? '+' : ''}${change}%`
|
|
53
|
-
: undefined
|
|
54
|
-
}
|
|
55
|
-
changeType={changeType}
|
|
56
|
-
icon={<Activity className="h-6 w-6 text-emerald-500" />}
|
|
57
|
-
iconBg="bg-emerald-500/10"
|
|
58
|
-
delay={100}
|
|
59
|
-
/>
|
|
60
|
-
</WidgetWrapper>
|
|
61
|
-
);
|
|
62
|
-
}
|
|
@@ -1,57 +0,0 @@
|
|
|
1
|
-
'use client';
|
|
2
|
-
|
|
3
|
-
import { Card, CardContent } from '@/components/ui/card';
|
|
4
|
-
import { useWidgetData } from '@/hooks/use-widget-data';
|
|
5
|
-
import type { AllWidgetsData } from '@/types/widget-data';
|
|
6
|
-
import { Zap } from 'lucide-react';
|
|
7
|
-
import { useTranslations } from 'next-intl';
|
|
8
|
-
import { WidgetWrapper } from '../widget-wrapper';
|
|
9
|
-
|
|
10
|
-
interface StatAccessLevelProps {
|
|
11
|
-
widget?: { name?: string };
|
|
12
|
-
onRemove?: () => void;
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
export default function StatAccessLevel({
|
|
16
|
-
widget,
|
|
17
|
-
onRemove,
|
|
18
|
-
}: StatAccessLevelProps) {
|
|
19
|
-
const t = useTranslations('core.DashboardPage.quickStats');
|
|
20
|
-
const { data, isLoading, isError, isAccessDenied } = useWidgetData<
|
|
21
|
-
AllWidgetsData,
|
|
22
|
-
number
|
|
23
|
-
>({
|
|
24
|
-
endpoint: '/dashboard-core/widgets/me',
|
|
25
|
-
queryKey: 'widget-me',
|
|
26
|
-
select: (d) => d.quickStats.securityLevel,
|
|
27
|
-
});
|
|
28
|
-
|
|
29
|
-
return (
|
|
30
|
-
<WidgetWrapper
|
|
31
|
-
isLoading={isLoading}
|
|
32
|
-
isError={isError}
|
|
33
|
-
isAccessDenied={isAccessDenied}
|
|
34
|
-
widgetName={widget?.name ?? 'stat-access-level'}
|
|
35
|
-
onRemove={onRemove}
|
|
36
|
-
>
|
|
37
|
-
<Card className="h-full overflow-hidden transition-all duration-300 hover:shadow-md">
|
|
38
|
-
<CardContent className="flex h-full items-center gap-2.5 p-2.5 sm:gap-3 sm:p-3 md:gap-4 md:p-4">
|
|
39
|
-
<div className="flex h-8 w-8 shrink-0 items-center justify-center rounded-xl bg-amber-50 dark:bg-amber-950/40 sm:h-9 sm:w-9 md:h-11 md:w-11">
|
|
40
|
-
<Zap className="h-3.5 w-3.5 text-amber-600 dark:text-amber-400 sm:h-4 sm:w-4 md:h-5 md:w-5" />
|
|
41
|
-
</div>
|
|
42
|
-
<div className="flex min-w-0 flex-col">
|
|
43
|
-
<span className="text-[10px] font-medium uppercase tracking-wider text-muted-foreground sm:text-[11px]">
|
|
44
|
-
{t('accessLevel')}
|
|
45
|
-
</span>
|
|
46
|
-
<span className="truncate text-base font-bold tracking-tight text-foreground sm:text-lg md:text-2xl">
|
|
47
|
-
{data ? t('accessLevelValue', { level: data }) : '—'}
|
|
48
|
-
</span>
|
|
49
|
-
<span className="truncate text-[10px] text-muted-foreground sm:text-[11px]">
|
|
50
|
-
{t('accessLevelSubtitle')}
|
|
51
|
-
</span>
|
|
52
|
-
</div>
|
|
53
|
-
</CardContent>
|
|
54
|
-
</Card>
|
|
55
|
-
</WidgetWrapper>
|
|
56
|
-
);
|
|
57
|
-
}
|
|
@@ -1,57 +0,0 @@
|
|
|
1
|
-
'use client';
|
|
2
|
-
|
|
3
|
-
import { Card, CardContent } from '@/components/ui/card';
|
|
4
|
-
import { useWidgetData } from '@/hooks/use-widget-data';
|
|
5
|
-
import type { AllWidgetsData } from '@/types/widget-data';
|
|
6
|
-
import { MousePointerClick } from 'lucide-react';
|
|
7
|
-
import { useTranslations } from 'next-intl';
|
|
8
|
-
import { WidgetWrapper } from '../widget-wrapper';
|
|
9
|
-
|
|
10
|
-
interface StatActionsTodayProps {
|
|
11
|
-
widget?: { name?: string };
|
|
12
|
-
onRemove?: () => void;
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
export default function StatActionsToday({
|
|
16
|
-
widget,
|
|
17
|
-
onRemove,
|
|
18
|
-
}: StatActionsTodayProps) {
|
|
19
|
-
const t = useTranslations('core.DashboardPage.quickStats');
|
|
20
|
-
const { data, isLoading, isError, isAccessDenied } = useWidgetData<
|
|
21
|
-
AllWidgetsData,
|
|
22
|
-
number
|
|
23
|
-
>({
|
|
24
|
-
endpoint: '/dashboard-core/widgets/me',
|
|
25
|
-
queryKey: 'widget-me',
|
|
26
|
-
select: (d) => d.quickStats.actionsToday,
|
|
27
|
-
});
|
|
28
|
-
|
|
29
|
-
return (
|
|
30
|
-
<WidgetWrapper
|
|
31
|
-
isLoading={isLoading}
|
|
32
|
-
isError={isError}
|
|
33
|
-
isAccessDenied={isAccessDenied}
|
|
34
|
-
widgetName={widget?.name ?? 'stat-actions-today'}
|
|
35
|
-
onRemove={onRemove}
|
|
36
|
-
>
|
|
37
|
-
<Card className="h-full overflow-hidden transition-all duration-300 hover:shadow-md">
|
|
38
|
-
<CardContent className="flex h-full items-center gap-2.5 p-2.5 sm:gap-3 sm:p-3 md:gap-4 md:p-4">
|
|
39
|
-
<div className="flex h-8 w-8 shrink-0 items-center justify-center rounded-xl bg-indigo-50 dark:bg-indigo-950/40 sm:h-9 sm:w-9 md:h-11 md:w-11">
|
|
40
|
-
<MousePointerClick className="h-3.5 w-3.5 text-indigo-600 dark:text-indigo-400 sm:h-4 sm:w-4 md:h-5 md:w-5" />
|
|
41
|
-
</div>
|
|
42
|
-
<div className="flex min-w-0 flex-col">
|
|
43
|
-
<span className="text-[10px] font-medium uppercase tracking-wider text-muted-foreground sm:text-[11px]">
|
|
44
|
-
{t('actionsToday')}
|
|
45
|
-
</span>
|
|
46
|
-
<span className="truncate text-lg font-bold tracking-tight text-foreground sm:text-xl md:text-2xl">
|
|
47
|
-
{data ?? '—'}
|
|
48
|
-
</span>
|
|
49
|
-
<span className="truncate text-[10px] text-muted-foreground sm:text-[11px]">
|
|
50
|
-
{t('actionsTodaySubtitle')}
|
|
51
|
-
</span>
|
|
52
|
-
</div>
|
|
53
|
-
</CardContent>
|
|
54
|
-
</Card>
|
|
55
|
-
</WidgetWrapper>
|
|
56
|
-
);
|
|
57
|
-
}
|
|
@@ -1,57 +0,0 @@
|
|
|
1
|
-
'use client';
|
|
2
|
-
|
|
3
|
-
import { Card, CardContent } from '@/components/ui/card';
|
|
4
|
-
import { useWidgetData } from '@/hooks/use-widget-data';
|
|
5
|
-
import type { AllWidgetsData } from '@/types/widget-data';
|
|
6
|
-
import { CalendarDays } from 'lucide-react';
|
|
7
|
-
import { useTranslations } from 'next-intl';
|
|
8
|
-
import { WidgetWrapper } from '../widget-wrapper';
|
|
9
|
-
|
|
10
|
-
interface StatConsecutiveDaysProps {
|
|
11
|
-
widget?: { name?: string };
|
|
12
|
-
onRemove?: () => void;
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
export default function StatConsecutiveDays({
|
|
16
|
-
widget,
|
|
17
|
-
onRemove,
|
|
18
|
-
}: StatConsecutiveDaysProps) {
|
|
19
|
-
const t = useTranslations('core.DashboardPage.quickStats');
|
|
20
|
-
const { data, isLoading, isError, isAccessDenied } = useWidgetData<
|
|
21
|
-
AllWidgetsData,
|
|
22
|
-
number
|
|
23
|
-
>({
|
|
24
|
-
endpoint: '/dashboard-core/widgets/me',
|
|
25
|
-
queryKey: 'widget-me',
|
|
26
|
-
select: (d) => d.quickStats.consecutiveDays,
|
|
27
|
-
});
|
|
28
|
-
|
|
29
|
-
return (
|
|
30
|
-
<WidgetWrapper
|
|
31
|
-
isLoading={isLoading}
|
|
32
|
-
isError={isError}
|
|
33
|
-
isAccessDenied={isAccessDenied}
|
|
34
|
-
widgetName={widget?.name ?? 'stat-consecutive-days'}
|
|
35
|
-
onRemove={onRemove}
|
|
36
|
-
>
|
|
37
|
-
<Card className="h-full overflow-hidden transition-all duration-300 hover:shadow-md">
|
|
38
|
-
<CardContent className="flex h-full items-center gap-2.5 p-2.5 sm:gap-3 sm:p-3 md:gap-4 md:p-4">
|
|
39
|
-
<div className="flex h-8 w-8 shrink-0 items-center justify-center rounded-xl bg-emerald-50 dark:bg-emerald-950/40 sm:h-9 sm:w-9 md:h-11 md:w-11">
|
|
40
|
-
<CalendarDays className="h-3.5 w-3.5 text-emerald-600 dark:text-emerald-400 sm:h-4 sm:w-4 md:h-5 md:w-5" />
|
|
41
|
-
</div>
|
|
42
|
-
<div className="flex min-w-0 flex-col">
|
|
43
|
-
<span className="text-[10px] font-medium uppercase tracking-wider text-muted-foreground sm:text-[11px]">
|
|
44
|
-
{t('consecutiveDays')}
|
|
45
|
-
</span>
|
|
46
|
-
<span className="truncate text-lg font-bold tracking-tight text-foreground sm:text-xl md:text-2xl">
|
|
47
|
-
{data ?? '—'}
|
|
48
|
-
</span>
|
|
49
|
-
<span className="truncate text-[10px] text-muted-foreground sm:text-[11px]">
|
|
50
|
-
{t('consecutiveDaysSubtitle')}
|
|
51
|
-
</span>
|
|
52
|
-
</div>
|
|
53
|
-
</CardContent>
|
|
54
|
-
</Card>
|
|
55
|
-
</WidgetWrapper>
|
|
56
|
-
);
|
|
57
|
-
}
|
|
@@ -1,57 +0,0 @@
|
|
|
1
|
-
'use client';
|
|
2
|
-
|
|
3
|
-
import { Card, CardContent } from '@/components/ui/card';
|
|
4
|
-
import { useWidgetData } from '@/hooks/use-widget-data';
|
|
5
|
-
import type { AllWidgetsData } from '@/types/widget-data';
|
|
6
|
-
import { Clock } from 'lucide-react';
|
|
7
|
-
import { useTranslations } from 'next-intl';
|
|
8
|
-
import { WidgetWrapper } from '../widget-wrapper';
|
|
9
|
-
|
|
10
|
-
interface StatOnlineTimeProps {
|
|
11
|
-
widget?: { name?: string };
|
|
12
|
-
onRemove?: () => void;
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
export default function StatOnlineTime({
|
|
16
|
-
widget,
|
|
17
|
-
onRemove,
|
|
18
|
-
}: StatOnlineTimeProps) {
|
|
19
|
-
const t = useTranslations('core.DashboardPage.quickStats');
|
|
20
|
-
const { data, isLoading, isError, isAccessDenied } = useWidgetData<
|
|
21
|
-
AllWidgetsData,
|
|
22
|
-
string
|
|
23
|
-
>({
|
|
24
|
-
endpoint: '/dashboard-core/widgets/me',
|
|
25
|
-
queryKey: 'widget-me',
|
|
26
|
-
select: (d) => d.quickStats.onlineTime,
|
|
27
|
-
});
|
|
28
|
-
|
|
29
|
-
return (
|
|
30
|
-
<WidgetWrapper
|
|
31
|
-
isLoading={isLoading}
|
|
32
|
-
isError={isError}
|
|
33
|
-
isAccessDenied={isAccessDenied}
|
|
34
|
-
widgetName={widget?.name ?? 'stat-online-time'}
|
|
35
|
-
onRemove={onRemove}
|
|
36
|
-
>
|
|
37
|
-
<Card className="h-full overflow-hidden transition-all duration-300 hover:shadow-md">
|
|
38
|
-
<CardContent className="flex h-full items-center gap-2.5 p-2.5 sm:gap-3 sm:p-3 md:gap-4 md:p-4">
|
|
39
|
-
<div className="flex h-8 w-8 shrink-0 items-center justify-center rounded-xl bg-blue-50 dark:bg-blue-950/40 sm:h-9 sm:w-9 md:h-11 md:w-11">
|
|
40
|
-
<Clock className="h-3.5 w-3.5 text-blue-600 dark:text-blue-400 sm:h-4 sm:w-4 md:h-5 md:w-5" />
|
|
41
|
-
</div>
|
|
42
|
-
<div className="flex min-w-0 flex-col">
|
|
43
|
-
<span className="text-[10px] font-medium uppercase tracking-wider text-muted-foreground sm:text-[11px]">
|
|
44
|
-
{t('onlineTime')}
|
|
45
|
-
</span>
|
|
46
|
-
<span className="truncate text-lg font-bold tracking-tight text-foreground sm:text-xl md:text-2xl">
|
|
47
|
-
{data ?? '—'}
|
|
48
|
-
</span>
|
|
49
|
-
<span className="truncate text-[10px] text-muted-foreground sm:text-[11px]">
|
|
50
|
-
{t('onlineTimeSubtitle')}
|
|
51
|
-
</span>
|
|
52
|
-
</div>
|
|
53
|
-
</CardContent>
|
|
54
|
-
</Card>
|
|
55
|
-
</WidgetWrapper>
|
|
56
|
-
);
|
|
57
|
-
}
|
|
@@ -1,196 +0,0 @@
|
|
|
1
|
-
'use client';
|
|
2
|
-
|
|
3
|
-
import { Badge } from '@/components/ui/badge';
|
|
4
|
-
import {
|
|
5
|
-
Card,
|
|
6
|
-
CardContent,
|
|
7
|
-
CardDescription,
|
|
8
|
-
CardHeader,
|
|
9
|
-
CardTitle,
|
|
10
|
-
} from '@/components/ui/card';
|
|
11
|
-
import { useWidgetData } from '@/hooks/use-widget-data';
|
|
12
|
-
import type {
|
|
13
|
-
DashboardCoreConfigOverviewData,
|
|
14
|
-
StorageConfigWidgetData,
|
|
15
|
-
} from '@/types/widget-data';
|
|
16
|
-
import { CheckCircle2, HardDrive } from 'lucide-react';
|
|
17
|
-
import { useTranslations } from 'next-intl';
|
|
18
|
-
import { WidgetWrapper } from '../widget-wrapper';
|
|
19
|
-
|
|
20
|
-
const defaultStorageConfigData: StorageConfigWidgetData = {
|
|
21
|
-
status: {
|
|
22
|
-
isConfigured: false,
|
|
23
|
-
totalProfiles: 0,
|
|
24
|
-
activeProfiles: 0,
|
|
25
|
-
defaultProfileId: null,
|
|
26
|
-
},
|
|
27
|
-
providers: [],
|
|
28
|
-
profiles: [],
|
|
29
|
-
};
|
|
30
|
-
|
|
31
|
-
interface StorageConfigProps {
|
|
32
|
-
widget?: { name?: string };
|
|
33
|
-
onRemove?: () => void;
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
export default function StorageConfig({
|
|
37
|
-
widget,
|
|
38
|
-
onRemove,
|
|
39
|
-
}: StorageConfigProps) {
|
|
40
|
-
const t = useTranslations('core.DashboardPage.storageConfig');
|
|
41
|
-
|
|
42
|
-
const { data, isLoading, isError, isAccessDenied } = useWidgetData<
|
|
43
|
-
DashboardCoreConfigOverviewData,
|
|
44
|
-
StorageConfigWidgetData
|
|
45
|
-
>({
|
|
46
|
-
endpoint: '/dashboard-core/config/overview',
|
|
47
|
-
queryKey: 'dashboard-core-config-overview',
|
|
48
|
-
select: (d) => d.storageConfig,
|
|
49
|
-
});
|
|
50
|
-
|
|
51
|
-
const storageData = data ?? defaultStorageConfigData;
|
|
52
|
-
const defaultProfile = storageData.profiles.find(
|
|
53
|
-
(profile) => profile.id === storageData.status.defaultProfileId
|
|
54
|
-
);
|
|
55
|
-
|
|
56
|
-
return (
|
|
57
|
-
<WidgetWrapper
|
|
58
|
-
isLoading={isLoading}
|
|
59
|
-
isError={isError}
|
|
60
|
-
isAccessDenied={isAccessDenied}
|
|
61
|
-
widgetName={widget?.name ?? t('title')}
|
|
62
|
-
onRemove={onRemove}
|
|
63
|
-
>
|
|
64
|
-
<Card className="flex h-full min-h-0 flex-col overflow-hidden">
|
|
65
|
-
<CardHeader className="shrink-0">
|
|
66
|
-
<div className="flex items-center justify-between gap-3">
|
|
67
|
-
<div className="flex items-center gap-3">
|
|
68
|
-
<div className="flex h-10 w-10 items-center justify-center rounded-lg bg-violet-50">
|
|
69
|
-
<HardDrive className="h-5 w-5 text-violet-600" />
|
|
70
|
-
</div>
|
|
71
|
-
<div>
|
|
72
|
-
<CardTitle className="text-base">{t('title')}</CardTitle>
|
|
73
|
-
<CardDescription>{t('description')}</CardDescription>
|
|
74
|
-
</div>
|
|
75
|
-
</div>
|
|
76
|
-
<Badge
|
|
77
|
-
variant="secondary"
|
|
78
|
-
className={
|
|
79
|
-
storageData.status.isConfigured
|
|
80
|
-
? 'bg-emerald-50 text-emerald-700'
|
|
81
|
-
: 'bg-amber-50 text-amber-700'
|
|
82
|
-
}
|
|
83
|
-
>
|
|
84
|
-
{storageData.status.isConfigured ? t('configured') : t('pending')}
|
|
85
|
-
</Badge>
|
|
86
|
-
</div>
|
|
87
|
-
</CardHeader>
|
|
88
|
-
<CardContent className="flex min-h-0 flex-1 flex-col gap-4 overflow-hidden pt-0">
|
|
89
|
-
<div className="grid grid-cols-3 gap-2">
|
|
90
|
-
<div className="rounded-lg border bg-muted/30 p-3 text-center">
|
|
91
|
-
<p className="text-[11px] text-muted-foreground">
|
|
92
|
-
{t('profiles')}
|
|
93
|
-
</p>
|
|
94
|
-
<p className="mt-1 text-lg font-semibold">
|
|
95
|
-
{storageData.status.totalProfiles}
|
|
96
|
-
</p>
|
|
97
|
-
</div>
|
|
98
|
-
<div className="rounded-lg border bg-muted/30 p-3 text-center">
|
|
99
|
-
<p className="text-[11px] text-muted-foreground">{t('active')}</p>
|
|
100
|
-
<p className="mt-1 text-lg font-semibold">
|
|
101
|
-
{storageData.status.activeProfiles}
|
|
102
|
-
</p>
|
|
103
|
-
</div>
|
|
104
|
-
<div className="rounded-lg border bg-muted/30 p-3 text-center">
|
|
105
|
-
<p className="text-[11px] text-muted-foreground">
|
|
106
|
-
{t('providers')}
|
|
107
|
-
</p>
|
|
108
|
-
<p className="mt-1 text-lg font-semibold">
|
|
109
|
-
{storageData.providers.length}
|
|
110
|
-
</p>
|
|
111
|
-
</div>
|
|
112
|
-
</div>
|
|
113
|
-
|
|
114
|
-
<div className="rounded-lg border p-3">
|
|
115
|
-
<p className="mb-1 text-xs text-muted-foreground">
|
|
116
|
-
{t('defaultProfile')}
|
|
117
|
-
</p>
|
|
118
|
-
<p className="truncate text-sm font-medium">
|
|
119
|
-
{defaultProfile?.name || t('notSet')}
|
|
120
|
-
</p>
|
|
121
|
-
{defaultProfile && (
|
|
122
|
-
<p className="mt-1 text-[11px] text-muted-foreground">
|
|
123
|
-
{defaultProfile.providerType.toUpperCase()} |{' '}
|
|
124
|
-
{defaultProfile.bucketName}
|
|
125
|
-
</p>
|
|
126
|
-
)}
|
|
127
|
-
</div>
|
|
128
|
-
|
|
129
|
-
<div className="grid gap-2 sm:grid-cols-2">
|
|
130
|
-
{storageData.providers.map((provider) => (
|
|
131
|
-
<div
|
|
132
|
-
key={provider.providerType}
|
|
133
|
-
className="rounded-lg border p-3"
|
|
134
|
-
>
|
|
135
|
-
<div className="flex items-center justify-between">
|
|
136
|
-
<p className="text-sm font-medium">
|
|
137
|
-
{provider.providerType.toUpperCase()}
|
|
138
|
-
</p>
|
|
139
|
-
<Badge variant="outline" className="text-[10px]">
|
|
140
|
-
{provider.defaults} {t('defaults')}
|
|
141
|
-
</Badge>
|
|
142
|
-
</div>
|
|
143
|
-
<p className="mt-1 text-[11px] text-muted-foreground">
|
|
144
|
-
{t('providerSummary', {
|
|
145
|
-
total: provider.total,
|
|
146
|
-
active: provider.active,
|
|
147
|
-
})}
|
|
148
|
-
</p>
|
|
149
|
-
</div>
|
|
150
|
-
))}
|
|
151
|
-
</div>
|
|
152
|
-
|
|
153
|
-
<div className="min-h-0 flex-1 space-y-2 overflow-auto">
|
|
154
|
-
{storageData.profiles.slice(0, 4).map((profile) => (
|
|
155
|
-
<div key={profile.id} className="rounded-lg border p-3">
|
|
156
|
-
<div className="flex items-center justify-between gap-2">
|
|
157
|
-
<p className="truncate text-sm font-medium">{profile.name}</p>
|
|
158
|
-
<div className="flex items-center gap-1.5">
|
|
159
|
-
{profile.isDefault && (
|
|
160
|
-
<Badge variant="outline" className="text-[10px]">
|
|
161
|
-
{t('defaultTag')}
|
|
162
|
-
</Badge>
|
|
163
|
-
)}
|
|
164
|
-
<Badge
|
|
165
|
-
variant="secondary"
|
|
166
|
-
className={
|
|
167
|
-
profile.isActive
|
|
168
|
-
? 'bg-emerald-50 text-emerald-700'
|
|
169
|
-
: 'bg-muted text-muted-foreground'
|
|
170
|
-
}
|
|
171
|
-
>
|
|
172
|
-
{profile.isActive ? (
|
|
173
|
-
<>
|
|
174
|
-
<CheckCircle2 className="mr-1 h-3 w-3" />
|
|
175
|
-
{t('active')}
|
|
176
|
-
</>
|
|
177
|
-
) : (
|
|
178
|
-
t('inactive')
|
|
179
|
-
)}
|
|
180
|
-
</Badge>
|
|
181
|
-
</div>
|
|
182
|
-
</div>
|
|
183
|
-
<p className="mt-1 truncate text-[11px] text-muted-foreground">
|
|
184
|
-
{profile.providerType.toUpperCase()} | {profile.bucketName}
|
|
185
|
-
</p>
|
|
186
|
-
</div>
|
|
187
|
-
))}
|
|
188
|
-
{storageData.profiles.length === 0 && (
|
|
189
|
-
<p className="text-xs text-muted-foreground">{t('noProfiles')}</p>
|
|
190
|
-
)}
|
|
191
|
-
</div>
|
|
192
|
-
</CardContent>
|
|
193
|
-
</Card>
|
|
194
|
-
</WidgetWrapper>
|
|
195
|
-
);
|
|
196
|
-
}
|