@hed-hog/core 0.0.296 → 0.0.298
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 +14 -14
- package/dist/auth/auth.service.d.ts +14 -14
- package/dist/challenge/challenge.service.d.ts +2 -2
- package/dist/dashboard/dashboard-core/dashboard-core.controller.d.ts +15 -1
- package/dist/dashboard/dashboard-core/dashboard-core.controller.d.ts.map +1 -1
- package/dist/dashboard/dashboard-core/dashboard-core.controller.js +9 -0
- package/dist/dashboard/dashboard-core/dashboard-core.controller.js.map +1 -1
- package/dist/dashboard/dashboard-core/dashboard-core.module.d.ts.map +1 -1
- package/dist/dashboard/dashboard-core/dashboard-core.module.js +6 -1
- package/dist/dashboard/dashboard-core/dashboard-core.module.js.map +1 -1
- package/dist/dashboard/dashboard-core/dashboard-core.service.d.ts +175 -3
- package/dist/dashboard/dashboard-core/dashboard-core.service.d.ts.map +1 -1
- package/dist/dashboard/dashboard-core/dashboard-core.service.js +531 -5
- package/dist/dashboard/dashboard-core/dashboard-core.service.js.map +1 -1
- package/dist/file/file.controller.d.ts.map +1 -1
- package/dist/file/file.controller.js +16 -0
- package/dist/file/file.controller.js.map +1 -1
- package/dist/file/file.service.d.ts +7 -1
- package/dist/file/file.service.d.ts.map +1 -1
- package/dist/file/file.service.js +38 -1
- package/dist/file/file.service.js.map +1 -1
- package/dist/file/provider/s3.provider.d.ts +1 -0
- package/dist/file/provider/s3.provider.d.ts.map +1 -1
- package/dist/file/provider/s3.provider.js +38 -29
- package/dist/file/provider/s3.provider.js.map +1 -1
- package/dist/oauth/oauth.service.d.ts.map +1 -1
- package/dist/oauth/oauth.service.js +2 -1
- package/dist/oauth/oauth.service.js.map +1 -1
- package/dist/profile/profile.controller.d.ts +6 -6
- package/dist/profile/profile.service.d.ts +6 -6
- package/dist/session/session.controller.d.ts +2 -2
- package/dist/session/session.service.d.ts +3 -3
- package/dist/setting/setting.controller.d.ts +9 -9
- package/dist/setting/setting.service.d.ts +10 -10
- package/dist/user/constants/user.constants.d.ts +1 -0
- package/dist/user/constants/user.constants.d.ts.map +1 -1
- package/dist/user/constants/user.constants.js +2 -1
- package/dist/user/constants/user.constants.js.map +1 -1
- package/dist/user/user.controller.d.ts +15 -15
- package/dist/user/user.service.d.ts +39 -39
- package/dist/user/user.service.d.ts.map +1 -1
- package/dist/user/user.service.js +2 -1
- package/dist/user/user.service.js.map +1 -1
- package/hedhog/data/dashboard_item.yaml +11 -11
- package/hedhog/data/route.yaml +8 -0
- package/hedhog/frontend/app/dashboard/[slug]/dashboard-content.tsx.ejs +76 -15
- package/hedhog/frontend/app/dashboard/components/widgets/email-notifications.tsx.ejs +85 -61
- package/hedhog/frontend/app/dashboard/components/widgets/locale-config.tsx.ejs +139 -280
- package/hedhog/frontend/app/dashboard/components/widgets/mail-config.tsx.ejs +161 -407
- package/hedhog/frontend/app/dashboard/components/widgets/oauth-config.tsx.ejs +150 -271
- package/hedhog/frontend/app/dashboard/components/widgets/profile-card.tsx.ejs +3 -3
- package/hedhog/frontend/app/dashboard/components/widgets/storage-config.tsx.ejs +161 -305
- package/hedhog/frontend/app/dashboard/components/widgets/theme-config.tsx.ejs +184 -246
- package/hedhog/frontend/app/dashboard/components/widgets/user-roles.tsx.ejs +12 -14
- package/hedhog/frontend/messages/en.json +90 -0
- package/hedhog/frontend/messages/pt.json +90 -0
- package/hedhog/table/mail_sent_user.yaml +75 -0
- package/package.json +4 -4
- package/src/dashboard/dashboard-core/dashboard-core.controller.ts +5 -0
- package/src/dashboard/dashboard-core/dashboard-core.module.ts +6 -1
- package/src/dashboard/dashboard-core/dashboard-core.service.ts +766 -3
- package/src/file/file.controller.ts +37 -13
- package/src/file/file.service.ts +47 -5
- package/src/file/provider/s3.provider.ts +39 -29
- package/src/oauth/oauth.service.ts +8 -7
- package/src/user/constants/user.constants.ts +1 -0
- package/src/user/user.service.ts +2 -1
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
'use client';
|
|
2
2
|
|
|
3
|
-
import {
|
|
3
|
+
import { Badge } from '@/components/ui/badge';
|
|
4
4
|
import {
|
|
5
5
|
Card,
|
|
6
6
|
CardContent,
|
|
@@ -8,268 +8,206 @@ import {
|
|
|
8
8
|
CardHeader,
|
|
9
9
|
CardTitle,
|
|
10
10
|
} from '@/components/ui/card';
|
|
11
|
-
import {
|
|
12
|
-
import {
|
|
13
|
-
|
|
14
|
-
|
|
11
|
+
import { useWidgetData } from '@/hooks/use-widget-data';
|
|
12
|
+
import type {
|
|
13
|
+
DashboardCoreConfigOverviewData,
|
|
14
|
+
ThemeConfigWidgetData,
|
|
15
|
+
} from '@/types/widget-data';
|
|
16
|
+
import { Palette } from 'lucide-react';
|
|
17
|
+
import { useTranslations } from 'next-intl';
|
|
18
|
+
import { WidgetWrapper } from '../widget-wrapper';
|
|
15
19
|
|
|
16
|
-
const
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
20
|
+
const emptyPaletteMode = {
|
|
21
|
+
primary: null,
|
|
22
|
+
primaryForeground: null,
|
|
23
|
+
secondary: null,
|
|
24
|
+
secondaryForeground: null,
|
|
25
|
+
accent: null,
|
|
26
|
+
accentForeground: null,
|
|
27
|
+
muted: null,
|
|
28
|
+
mutedForeground: null,
|
|
29
|
+
background: null,
|
|
30
|
+
backgroundForeground: null,
|
|
31
|
+
card: null,
|
|
32
|
+
cardForeground: null,
|
|
33
|
+
};
|
|
30
34
|
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
35
|
+
const defaultThemeConfigData: ThemeConfigWidgetData = {
|
|
36
|
+
status: {
|
|
37
|
+
isConfigured: false,
|
|
38
|
+
configuredTokenCount: 0,
|
|
39
|
+
},
|
|
40
|
+
branding: {
|
|
41
|
+
systemName: null,
|
|
42
|
+
systemSlogan: null,
|
|
43
|
+
iconUrl: null,
|
|
44
|
+
imageUrl: null,
|
|
45
|
+
},
|
|
46
|
+
presentation: {
|
|
47
|
+
mode: null,
|
|
48
|
+
font: null,
|
|
49
|
+
textSize: null,
|
|
50
|
+
radius: null,
|
|
51
|
+
},
|
|
52
|
+
palette: {
|
|
53
|
+
light: emptyPaletteMode,
|
|
54
|
+
dark: emptyPaletteMode,
|
|
55
|
+
},
|
|
56
|
+
};
|
|
39
57
|
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
58
|
+
interface ThemeConfigProps {
|
|
59
|
+
widget?: { name?: string };
|
|
60
|
+
onRemove?: () => void;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
export default function ThemeConfig({ widget, onRemove }: ThemeConfigProps) {
|
|
64
|
+
const t = useTranslations('core.DashboardPage.themeConfig');
|
|
65
|
+
|
|
66
|
+
const { data, isLoading, isError, isAccessDenied } = useWidgetData<
|
|
67
|
+
DashboardCoreConfigOverviewData,
|
|
68
|
+
ThemeConfigWidgetData
|
|
69
|
+
>({
|
|
70
|
+
endpoint: '/dashboard-core/config/overview',
|
|
71
|
+
queryKey: 'dashboard-core-config-overview',
|
|
72
|
+
select: (d) => d.themeConfig,
|
|
73
|
+
});
|
|
74
|
+
|
|
75
|
+
const themeData = data ?? defaultThemeConfigData;
|
|
51
76
|
|
|
52
77
|
return (
|
|
53
|
-
<
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
Pre-visualizacao
|
|
72
|
-
</p>
|
|
73
|
-
<div className="flex items-center gap-3 rounded-lg border bg-background p-3">
|
|
74
|
-
<div
|
|
75
|
-
className="flex h-10 w-10 items-center justify-center rounded-lg"
|
|
76
|
-
style={{ backgroundColor: primaryColor }}
|
|
77
|
-
>
|
|
78
|
-
{logoPreview ? (
|
|
79
|
-
<img
|
|
80
|
-
src={logoPreview}
|
|
81
|
-
alt="Logo"
|
|
82
|
-
className="h-6 w-6 rounded object-contain"
|
|
83
|
-
/>
|
|
84
|
-
) : (
|
|
85
|
-
<span className="text-sm font-bold text-white">
|
|
86
|
-
{title.charAt(0)}
|
|
87
|
-
</span>
|
|
88
|
-
)}
|
|
78
|
+
<WidgetWrapper
|
|
79
|
+
isLoading={isLoading}
|
|
80
|
+
isError={isError}
|
|
81
|
+
isAccessDenied={isAccessDenied}
|
|
82
|
+
widgetName={widget?.name ?? t('title')}
|
|
83
|
+
onRemove={onRemove}
|
|
84
|
+
>
|
|
85
|
+
<Card className="flex h-full min-h-0 flex-col overflow-hidden">
|
|
86
|
+
<CardHeader className="shrink-0">
|
|
87
|
+
<div className="flex items-center justify-between gap-3">
|
|
88
|
+
<div className="flex items-center gap-3">
|
|
89
|
+
<div className="flex h-10 w-10 items-center justify-center rounded-lg bg-rose-50">
|
|
90
|
+
<Palette className="h-5 w-5 text-rose-600" />
|
|
91
|
+
</div>
|
|
92
|
+
<div>
|
|
93
|
+
<CardTitle className="text-base">{t('title')}</CardTitle>
|
|
94
|
+
<CardDescription>{t('description')}</CardDescription>
|
|
95
|
+
</div>
|
|
89
96
|
</div>
|
|
90
|
-
<
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
97
|
+
<Badge
|
|
98
|
+
variant="secondary"
|
|
99
|
+
className={
|
|
100
|
+
themeData.status.isConfigured
|
|
101
|
+
? 'bg-emerald-50 text-emerald-700'
|
|
102
|
+
: 'bg-amber-50 text-amber-700'
|
|
103
|
+
}
|
|
104
|
+
>
|
|
105
|
+
{themeData.status.isConfigured ? t('configured') : t('pending')}
|
|
106
|
+
</Badge>
|
|
107
|
+
</div>
|
|
108
|
+
</CardHeader>
|
|
109
|
+
<CardContent className="flex min-h-0 flex-1 flex-col gap-4 overflow-hidden pt-0">
|
|
110
|
+
<div className="rounded-lg border bg-muted/30 p-4">
|
|
111
|
+
<div className="flex items-center gap-3 rounded-lg border bg-background p-3">
|
|
112
|
+
<div
|
|
113
|
+
className="flex h-10 w-10 items-center justify-center rounded-lg text-sm font-bold text-white"
|
|
114
|
+
style={{
|
|
115
|
+
backgroundColor: themeData.palette.light.primary || '#64748b',
|
|
116
|
+
}}
|
|
94
117
|
>
|
|
95
|
-
{
|
|
96
|
-
</
|
|
97
|
-
<
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
src={faviconPreview}
|
|
105
|
-
alt="Favicon"
|
|
106
|
-
className="h-4 w-4 object-contain"
|
|
107
|
-
/>
|
|
108
|
-
Favicon
|
|
118
|
+
{(themeData.branding.systemName || 'S').charAt(0).toUpperCase()}
|
|
119
|
+
</div>
|
|
120
|
+
<div className="min-w-0">
|
|
121
|
+
<p className="truncate text-sm font-semibold">
|
|
122
|
+
{themeData.branding.systemName || t('notSet')}
|
|
123
|
+
</p>
|
|
124
|
+
<p className="truncate text-xs text-muted-foreground">
|
|
125
|
+
{themeData.branding.systemSlogan || t('notSet')}
|
|
126
|
+
</p>
|
|
109
127
|
</div>
|
|
110
|
-
|
|
128
|
+
<Badge variant="outline" className="ml-auto text-[10px]">
|
|
129
|
+
{themeData.presentation.mode || t('notSet')}
|
|
130
|
+
</Badge>
|
|
131
|
+
</div>
|
|
111
132
|
</div>
|
|
112
|
-
</div>
|
|
113
133
|
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
onKeyDown={(e) => {
|
|
121
|
-
if (e.key === 'Enter') logoRef.current?.click();
|
|
122
|
-
}}
|
|
123
|
-
role="button"
|
|
124
|
-
tabIndex={0}
|
|
125
|
-
className="flex h-28 cursor-pointer flex-col items-center justify-center gap-2 rounded-lg border-2 border-dashed transition-colors hover:border-foreground/30 hover:bg-muted/50"
|
|
126
|
-
>
|
|
127
|
-
{logoPreview ? (
|
|
128
|
-
<img
|
|
129
|
-
src={logoPreview}
|
|
130
|
-
alt="Logo"
|
|
131
|
-
className="h-12 w-12 object-contain"
|
|
132
|
-
/>
|
|
133
|
-
) : (
|
|
134
|
-
<>
|
|
135
|
-
<Upload className="h-5 w-5 text-muted-foreground" />
|
|
136
|
-
<span className="text-xs text-muted-foreground">
|
|
137
|
-
Clique para enviar
|
|
138
|
-
</span>
|
|
139
|
-
</>
|
|
140
|
-
)}
|
|
134
|
+
<div className="grid grid-cols-2 gap-2 sm:grid-cols-4">
|
|
135
|
+
<div className="rounded-lg border p-3 text-center">
|
|
136
|
+
<p className="text-[11px] text-muted-foreground">{t('tokens')}</p>
|
|
137
|
+
<p className="mt-1 text-lg font-semibold">
|
|
138
|
+
{themeData.status.configuredTokenCount}
|
|
139
|
+
</p>
|
|
141
140
|
</div>
|
|
142
|
-
<
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
{faviconPreview ? (
|
|
162
|
-
<img
|
|
163
|
-
src={faviconPreview}
|
|
164
|
-
alt="Favicon"
|
|
165
|
-
className="h-8 w-8 object-contain"
|
|
166
|
-
/>
|
|
167
|
-
) : (
|
|
168
|
-
<>
|
|
169
|
-
<ImageIcon className="h-5 w-5 text-muted-foreground" />
|
|
170
|
-
<span className="text-xs text-muted-foreground">
|
|
171
|
-
16x16 ou 32x32 px
|
|
172
|
-
</span>
|
|
173
|
-
</>
|
|
174
|
-
)}
|
|
141
|
+
<div className="rounded-lg border p-3 text-center">
|
|
142
|
+
<p className="text-[11px] text-muted-foreground">{t('font')}</p>
|
|
143
|
+
<p className="mt-1 truncate text-sm font-medium">
|
|
144
|
+
{themeData.presentation.font || t('notSet')}
|
|
145
|
+
</p>
|
|
146
|
+
</div>
|
|
147
|
+
<div className="rounded-lg border p-3 text-center">
|
|
148
|
+
<p className="text-[11px] text-muted-foreground">
|
|
149
|
+
{t('textSize')}
|
|
150
|
+
</p>
|
|
151
|
+
<p className="mt-1 truncate text-sm font-medium">
|
|
152
|
+
{themeData.presentation.textSize || t('notSet')}
|
|
153
|
+
</p>
|
|
154
|
+
</div>
|
|
155
|
+
<div className="rounded-lg border p-3 text-center">
|
|
156
|
+
<p className="text-[11px] text-muted-foreground">{t('radius')}</p>
|
|
157
|
+
<p className="mt-1 truncate text-sm font-medium">
|
|
158
|
+
{themeData.presentation.radius || t('notSet')}
|
|
159
|
+
</p>
|
|
175
160
|
</div>
|
|
176
|
-
<input
|
|
177
|
-
ref={faviconRef}
|
|
178
|
-
type="file"
|
|
179
|
-
accept="image/png,image/ico,image/x-icon,image/svg+xml"
|
|
180
|
-
className="hidden"
|
|
181
|
-
onChange={(e) => handleFileChange(e, setFaviconPreview)}
|
|
182
|
-
/>
|
|
183
|
-
</div>
|
|
184
|
-
</div>
|
|
185
|
-
|
|
186
|
-
{/* Title + Slogan */}
|
|
187
|
-
<div className="grid gap-4 sm:grid-cols-2">
|
|
188
|
-
<div className="space-y-2">
|
|
189
|
-
<Label htmlFor="sys-title">Titulo do sistema</Label>
|
|
190
|
-
<Input
|
|
191
|
-
id="sys-title"
|
|
192
|
-
value={title}
|
|
193
|
-
onChange={(e) => setTitle(e.target.value)}
|
|
194
|
-
placeholder="Meu Sistema"
|
|
195
|
-
/>
|
|
196
|
-
</div>
|
|
197
|
-
<div className="space-y-2">
|
|
198
|
-
<Label htmlFor="sys-slogan">Slogan</Label>
|
|
199
|
-
<Input
|
|
200
|
-
id="sys-slogan"
|
|
201
|
-
value={slogan}
|
|
202
|
-
onChange={(e) => setSlogan(e.target.value)}
|
|
203
|
-
placeholder="Seu slogan aqui"
|
|
204
|
-
/>
|
|
205
161
|
</div>
|
|
206
|
-
</div>
|
|
207
162
|
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
163
|
+
<div className="grid gap-2 sm:grid-cols-2">
|
|
164
|
+
<div className="rounded-lg border p-3">
|
|
165
|
+
<div className="mb-2 flex items-center justify-between">
|
|
166
|
+
<p className="text-xs text-muted-foreground">
|
|
167
|
+
{t('lightPalette')}
|
|
168
|
+
</p>
|
|
169
|
+
<Badge variant="outline" className="text-[10px]">
|
|
170
|
+
{themeData.palette.light.primary || t('notSet')}
|
|
171
|
+
</Badge>
|
|
172
|
+
</div>
|
|
173
|
+
<div className="flex items-center gap-2">
|
|
174
|
+
<span
|
|
175
|
+
className="h-5 w-5 rounded-full border"
|
|
176
|
+
style={{
|
|
177
|
+
backgroundColor:
|
|
178
|
+
themeData.palette.light.primary || 'transparent',
|
|
179
|
+
}}
|
|
180
|
+
/>
|
|
181
|
+
<span className="text-xs text-muted-foreground">
|
|
182
|
+
{t('primary')}
|
|
183
|
+
</span>
|
|
184
|
+
</div>
|
|
223
185
|
</div>
|
|
224
|
-
<
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
<
|
|
234
|
-
key={c.value}
|
|
235
|
-
type="button"
|
|
236
|
-
onClick={() => setPrimaryColor(c.value)}
|
|
237
|
-
className={`group relative flex h-7 w-7 items-center justify-center rounded-full border-2 transition-all ${
|
|
238
|
-
primaryColor === c.value
|
|
239
|
-
? 'border-foreground scale-110'
|
|
240
|
-
: 'border-transparent hover:scale-105'
|
|
241
|
-
}`}
|
|
242
|
-
title={c.name}
|
|
243
|
-
>
|
|
186
|
+
<div className="rounded-lg border p-3">
|
|
187
|
+
<div className="mb-2 flex items-center justify-between">
|
|
188
|
+
<p className="text-xs text-muted-foreground">
|
|
189
|
+
{t('darkPalette')}
|
|
190
|
+
</p>
|
|
191
|
+
<Badge variant="outline" className="text-[10px]">
|
|
192
|
+
{themeData.palette.dark.primary || t('notSet')}
|
|
193
|
+
</Badge>
|
|
194
|
+
</div>
|
|
195
|
+
<div className="flex items-center gap-2">
|
|
244
196
|
<span
|
|
245
|
-
className="h-5 w-5 rounded-full"
|
|
246
|
-
style={{
|
|
197
|
+
className="h-5 w-5 rounded-full border"
|
|
198
|
+
style={{
|
|
199
|
+
backgroundColor:
|
|
200
|
+
themeData.palette.dark.primary || 'transparent',
|
|
201
|
+
}}
|
|
247
202
|
/>
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
{/* Actions */}
|
|
254
|
-
<div className="flex items-center justify-end border-t pt-4">
|
|
255
|
-
<div className="flex gap-2">
|
|
256
|
-
<Button
|
|
257
|
-
variant="outline"
|
|
258
|
-
size="sm"
|
|
259
|
-
onClick={() => {
|
|
260
|
-
setTitle('HeroAdmin');
|
|
261
|
-
setSlogan('Painel de Controle Inteligente');
|
|
262
|
-
setPrimaryColor('#3b82f6');
|
|
263
|
-
setLogoPreview(null);
|
|
264
|
-
setFaviconPreview(null);
|
|
265
|
-
}}
|
|
266
|
-
>
|
|
267
|
-
Restaurar padrao
|
|
268
|
-
</Button>
|
|
269
|
-
<Button size="sm">Salvar</Button>
|
|
203
|
+
<span className="text-xs text-muted-foreground">
|
|
204
|
+
{t('primary')}
|
|
205
|
+
</span>
|
|
206
|
+
</div>
|
|
207
|
+
</div>
|
|
270
208
|
</div>
|
|
271
|
-
</
|
|
272
|
-
</
|
|
273
|
-
</
|
|
209
|
+
</CardContent>
|
|
210
|
+
</Card>
|
|
211
|
+
</WidgetWrapper>
|
|
274
212
|
);
|
|
275
213
|
}
|
|
@@ -53,46 +53,44 @@ function RolesContent({ roles }: { roles: RoleData[] }) {
|
|
|
53
53
|
|
|
54
54
|
return (
|
|
55
55
|
<Card className="flex h-full min-h-0 flex-col overflow-hidden">
|
|
56
|
-
<CardHeader className="shrink-0 pb-
|
|
57
|
-
<div className="flex items-center gap-
|
|
58
|
-
<Crown className="h-4 w-4 text-amber-600 dark:text-amber-400
|
|
56
|
+
<CardHeader className="shrink-0 space-y-1 pb-2">
|
|
57
|
+
<div className="flex items-center gap-1.5">
|
|
58
|
+
<Crown className="h-4 w-4 text-amber-600 dark:text-amber-400" />
|
|
59
59
|
<div>
|
|
60
|
-
<CardTitle className="text-sm font-semibold
|
|
60
|
+
<CardTitle className="text-sm font-semibold">
|
|
61
61
|
{t('title')}
|
|
62
62
|
</CardTitle>
|
|
63
|
-
<CardDescription className="text-xs
|
|
63
|
+
<CardDescription className="text-xs leading-tight">
|
|
64
64
|
{t('description')}
|
|
65
65
|
</CardDescription>
|
|
66
66
|
</div>
|
|
67
67
|
</div>
|
|
68
68
|
</CardHeader>
|
|
69
69
|
<CardContent className="flex min-h-0 flex-1 overflow-auto pt-0">
|
|
70
|
-
<div className="grid grid-cols-1 gap-
|
|
70
|
+
<div className="grid content-start items-start grid-cols-1 gap-1.5 md:grid-cols-2">
|
|
71
71
|
{roles.map((role, index) => {
|
|
72
72
|
const style = levelStyles[index % levelStyles.length]!;
|
|
73
73
|
return (
|
|
74
74
|
<div
|
|
75
75
|
key={role.id}
|
|
76
|
-
className={`flex items-center gap-2
|
|
76
|
+
className={`flex h-fit self-start items-center gap-2 rounded-lg border p-2 transition-all duration-200 hover:shadow-sm ${style.border} ${style.bg}`}
|
|
77
77
|
>
|
|
78
78
|
<div
|
|
79
|
-
className={`flex h-
|
|
79
|
+
className={`flex h-7 w-7 shrink-0 items-center justify-center rounded-md ${style.iconBg}`}
|
|
80
80
|
>
|
|
81
|
-
<ShieldCheck
|
|
82
|
-
className={`h-3.5 w-3.5 sm:h-4 sm:w-4 ${style.iconColor}`}
|
|
83
|
-
/>
|
|
81
|
+
<ShieldCheck className={`h-3.5 w-3.5 ${style.iconColor}`} />
|
|
84
82
|
</div>
|
|
85
83
|
<div className="flex min-w-0 flex-1 flex-col gap-0.5">
|
|
86
|
-
<span className="truncate text-
|
|
84
|
+
<span className="truncate text-xs font-medium text-foreground sm:text-[13px]">
|
|
87
85
|
{role.name}
|
|
88
86
|
</span>
|
|
89
|
-
<span className="truncate text-[
|
|
87
|
+
<span className="truncate text-[10px] text-muted-foreground sm:text-[11px]">
|
|
90
88
|
{role.slug}
|
|
91
89
|
</span>
|
|
92
90
|
</div>
|
|
93
91
|
<Badge
|
|
94
92
|
variant="secondary"
|
|
95
|
-
className={`shrink-0 text-[10px] ${style.badge}`}
|
|
93
|
+
className={`shrink-0 px-1.5 py-0 text-[10px] ${style.badge}`}
|
|
96
94
|
>
|
|
97
95
|
{t('active')}
|
|
98
96
|
</Badge>
|
|
@@ -1026,6 +1026,96 @@
|
|
|
1026
1026
|
"hoursAgo": "{count}h ago",
|
|
1027
1027
|
"daysAgo": "{count} day ago",
|
|
1028
1028
|
"daysAgoPlural": "{count} days ago"
|
|
1029
|
+
},
|
|
1030
|
+
"emailNotifications": {
|
|
1031
|
+
"title": "Email Notifications",
|
|
1032
|
+
"description": "System email flow in the last 14 days",
|
|
1033
|
+
"received": "Received",
|
|
1034
|
+
"read": "Read",
|
|
1035
|
+
"unread": "Unread",
|
|
1036
|
+
"error": "Error",
|
|
1037
|
+
"receivedShort": "Recv.",
|
|
1038
|
+
"readShort": "Read",
|
|
1039
|
+
"unreadShort": "Unrd.",
|
|
1040
|
+
"errorShort": "Err."
|
|
1041
|
+
},
|
|
1042
|
+
"localeConfig": {
|
|
1043
|
+
"title": "Localization",
|
|
1044
|
+
"description": "Locale and regional format summary",
|
|
1045
|
+
"configured": "Configured",
|
|
1046
|
+
"pending": "Pending",
|
|
1047
|
+
"enabled": "Enabled",
|
|
1048
|
+
"disabled": "Disabled",
|
|
1049
|
+
"total": "Total",
|
|
1050
|
+
"timezone": "Timezone",
|
|
1051
|
+
"dateFormat": "Date format",
|
|
1052
|
+
"timeFormat": "Time format",
|
|
1053
|
+
"enabledLocales": "Enabled locales",
|
|
1054
|
+
"noneEnabled": "No locale enabled",
|
|
1055
|
+
"notSet": "Not set"
|
|
1056
|
+
},
|
|
1057
|
+
"mailConfig": {
|
|
1058
|
+
"title": "Mail Configuration",
|
|
1059
|
+
"description": "Provider and delivery overview",
|
|
1060
|
+
"configured": "Configured",
|
|
1061
|
+
"pending": "Pending",
|
|
1062
|
+
"templates": "Templates",
|
|
1063
|
+
"sentTotal": "Sent total",
|
|
1064
|
+
"sent30Days": "Sent (30d)",
|
|
1065
|
+
"sender": "Default sender",
|
|
1066
|
+
"providers": "Providers",
|
|
1067
|
+
"selectedProvider": "Selected: {provider}",
|
|
1068
|
+
"selected": "Selected",
|
|
1069
|
+
"missingKeys": "Missing keys: {count}",
|
|
1070
|
+
"allKeysPresent": "All required keys present",
|
|
1071
|
+
"noProviders": "No providers found",
|
|
1072
|
+
"none": "None",
|
|
1073
|
+
"notSet": "Not set"
|
|
1074
|
+
},
|
|
1075
|
+
"oauthConfig": {
|
|
1076
|
+
"title": "OAuth Providers",
|
|
1077
|
+
"description": "Social login readiness summary",
|
|
1078
|
+
"configured": "Configured",
|
|
1079
|
+
"pending": "Pending",
|
|
1080
|
+
"enabled": "Enabled",
|
|
1081
|
+
"disabled": "Disabled",
|
|
1082
|
+
"configuredProviders": "Configured",
|
|
1083
|
+
"connectedAccounts": "Connected",
|
|
1084
|
+
"scopesCount": "Scopes: {count}",
|
|
1085
|
+
"connectedUsers": "Users: {count}",
|
|
1086
|
+
"missingKeys": "Missing keys: {count}",
|
|
1087
|
+
"allKeysPresent": "All required keys present",
|
|
1088
|
+
"noProviders": "No providers found"
|
|
1089
|
+
},
|
|
1090
|
+
"storageConfig": {
|
|
1091
|
+
"title": "Storage Profiles",
|
|
1092
|
+
"description": "Active providers and profile health",
|
|
1093
|
+
"configured": "Configured",
|
|
1094
|
+
"pending": "Pending",
|
|
1095
|
+
"profiles": "Profiles",
|
|
1096
|
+
"active": "Active",
|
|
1097
|
+
"providers": "Providers",
|
|
1098
|
+
"defaultProfile": "Default profile",
|
|
1099
|
+
"defaults": "defaults",
|
|
1100
|
+
"providerSummary": "{active} active of {total}",
|
|
1101
|
+
"defaultTag": "Default",
|
|
1102
|
+
"inactive": "Inactive",
|
|
1103
|
+
"noProfiles": "No profiles found",
|
|
1104
|
+
"notSet": "Not set"
|
|
1105
|
+
},
|
|
1106
|
+
"themeConfig": {
|
|
1107
|
+
"title": "Theme and Branding",
|
|
1108
|
+
"description": "Visual identity configuration snapshot",
|
|
1109
|
+
"configured": "Configured",
|
|
1110
|
+
"pending": "Pending",
|
|
1111
|
+
"tokens": "Tokens",
|
|
1112
|
+
"font": "Font",
|
|
1113
|
+
"textSize": "Text size",
|
|
1114
|
+
"radius": "Radius",
|
|
1115
|
+
"lightPalette": "Light palette",
|
|
1116
|
+
"darkPalette": "Dark palette",
|
|
1117
|
+
"primary": "Primary",
|
|
1118
|
+
"notSet": "Not set"
|
|
1029
1119
|
}
|
|
1030
1120
|
},
|
|
1031
1121
|
"HomePage": {
|