@hedhog/admin 0.48.15 → 0.48.17

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.
@@ -0,0 +1,126 @@
1
+ import { Database } from 'lucide-react'
2
+ import { useEffect, useState } from 'react'
3
+
4
+ import {
5
+ Card,
6
+ CardContent,
7
+ CardDescription,
8
+ CardHeader,
9
+ CardTitle,
10
+ } from '@/components/ui/card'
11
+ import { useApp } from '@/hooks/use-app'
12
+ import { bytesToHuman } from '@/lib/bytes-to-human'
13
+ import { DashboardDefaultData } from '@/types'
14
+
15
+ const DatabaseStats = () => {
16
+ const { request } = useApp()
17
+ const [isRefreshing, setIsRefreshing] = useState(false)
18
+ const [data, setData] = useState<DashboardDefaultData>({
19
+ os: {
20
+ name: '',
21
+ platform: '',
22
+ version: '',
23
+ architecture: '',
24
+ uptime: 0,
25
+ cpu: {
26
+ model: '',
27
+ speed: 0,
28
+ physicalCores: 0,
29
+ virtualCores: 0,
30
+ },
31
+ memory: {
32
+ total: 0,
33
+ free: 0,
34
+ },
35
+ disk: [],
36
+ },
37
+ modules: [],
38
+ users: {
39
+ total: 0,
40
+ admin: 0,
41
+ active: 0,
42
+ activities: [],
43
+ },
44
+ database: {
45
+ connections: 0,
46
+ size: 0,
47
+ queriesPerSecond: 0,
48
+ },
49
+ } as DashboardDefaultData)
50
+
51
+ const load = async () => {
52
+ setIsRefreshing(true)
53
+ const { data } = await request<DashboardDefaultData>({
54
+ url: '/core',
55
+ })
56
+
57
+ setData(data)
58
+
59
+ setIsRefreshing(false)
60
+ }
61
+
62
+ useEffect(() => {
63
+ load()
64
+ }, [])
65
+
66
+ return (
67
+ <Card>
68
+ <CardHeader>
69
+ <CardTitle className='flex items-center'>
70
+ <Database className='mr-2 h-5 w-5 text-primary' />
71
+ Estatísticas do Banco de Dados
72
+ </CardTitle>
73
+ <CardDescription>
74
+ Informações sobre o banco de dados do sistema
75
+ </CardDescription>
76
+ </CardHeader>
77
+ <CardContent>
78
+ {isRefreshing ? (
79
+ <div className='grid grid-cols-1 gap-4 md:grid-cols-3'>
80
+ <div className='animate-pulse rounded-lg border p-4'>
81
+ <div className='h-4 w-1/3 rounded bg-muted-foreground/20'></div>
82
+ <div className='mt-2 h-6 w-2/3 rounded bg-muted-foreground/20'></div>
83
+ </div>
84
+ <div className='animate-pulse rounded-lg border p-4'>
85
+ <div className='h-4 w-1/3 rounded bg-muted-foreground/20'></div>
86
+ <div className='mt-2 h-6 w-2/3 rounded bg-muted-foreground/20'></div>
87
+ </div>
88
+ <div className='animate-pulse rounded-lg border p-4'>
89
+ <div className='h-4 w-1/3 rounded bg-muted-foreground/20'></div>
90
+ <div className='mt-2 h-6 w-2/3 rounded bg-muted-foreground/20'></div>
91
+ </div>
92
+ </div>
93
+ ) : (
94
+ <div className='grid grid-cols-1 gap-4 md:grid-cols-3'>
95
+ <div className='rounded-lg border p-4'>
96
+ <div className='text-sm font-medium text-muted-foreground'>
97
+ Conexões
98
+ </div>
99
+ <div className='mt-1 text-2xl font-bold'>
100
+ {data.database.connections}
101
+ </div>
102
+ </div>
103
+ <div className='rounded-lg border p-4'>
104
+ <div className='text-sm font-medium text-muted-foreground'>
105
+ Tamanho
106
+ </div>
107
+ <div className='mt-1 text-2xl font-bold'>
108
+ {bytesToHuman(data.database.size)}
109
+ </div>
110
+ </div>
111
+ <div className='rounded-lg border p-4'>
112
+ <div className='text-sm font-medium text-muted-foreground'>
113
+ Consultas/min
114
+ </div>
115
+ <div className='mt-1 text-2xl font-bold'>
116
+ {data.database.queriesPerSecond}
117
+ </div>
118
+ </div>
119
+ </div>
120
+ )}
121
+ </CardContent>
122
+ </Card>
123
+ )
124
+ }
125
+
126
+ export default DatabaseStats
@@ -0,0 +1,113 @@
1
+ import { Package } from 'lucide-react'
2
+ import { useEffect, useState } from 'react'
3
+
4
+ import { Badge } from '@/components/ui/badge'
5
+ import {
6
+ Card,
7
+ CardContent,
8
+ CardDescription,
9
+ CardHeader,
10
+ CardTitle,
11
+ } from '@/components/ui/card'
12
+ import { useApp } from '@/hooks/use-app'
13
+ import { DashboardDefaultData } from '@/types'
14
+
15
+ const ModuleInstalled = () => {
16
+ const { request } = useApp()
17
+ const [isRefreshing, setIsRefreshing] = useState(false)
18
+ const [data, setData] = useState<DashboardDefaultData>({
19
+ os: {
20
+ name: '',
21
+ platform: '',
22
+ version: '',
23
+ architecture: '',
24
+ uptime: 0,
25
+ cpu: {
26
+ model: '',
27
+ speed: 0,
28
+ physicalCores: 0,
29
+ virtualCores: 0,
30
+ },
31
+ memory: {
32
+ total: 0,
33
+ free: 0,
34
+ },
35
+ disk: [],
36
+ },
37
+ modules: [],
38
+ users: {
39
+ total: 0,
40
+ admin: 0,
41
+ active: 0,
42
+ activities: [],
43
+ },
44
+ database: {
45
+ connections: 0,
46
+ size: 0,
47
+ queriesPerSecond: 0,
48
+ },
49
+ } as DashboardDefaultData)
50
+
51
+ const load = async () => {
52
+ setIsRefreshing(true)
53
+ const { data } = await request<DashboardDefaultData>({
54
+ url: '/core',
55
+ })
56
+
57
+ setData(data)
58
+
59
+ setIsRefreshing(false)
60
+ }
61
+
62
+ useEffect(() => {
63
+ load()
64
+ }, [])
65
+
66
+ return (
67
+ <Card>
68
+ <CardHeader className='pb-2'>
69
+ <CardTitle className='flex items-center'>
70
+ <Package className='mr-2 h-5 w-5 text-primary' />
71
+ Módulos Instalados
72
+ </CardTitle>
73
+ <CardDescription>Módulos e suas versões</CardDescription>
74
+ </CardHeader>
75
+ <CardContent>
76
+ {isRefreshing ? (
77
+ <div className='space-y-4'>
78
+ {Array.from({ length: 5 }).map((_, index) => (
79
+ <div
80
+ key={index}
81
+ className='flex animate-pulse items-center justify-between'
82
+ >
83
+ <div>
84
+ <div className='h-4 w-24 rounded bg-muted'></div>
85
+ <div className='mt-1 h-3 w-16 rounded bg-muted'></div>
86
+ </div>
87
+ <div className='h-6 w-20 rounded bg-muted'></div>
88
+ </div>
89
+ ))}
90
+ </div>
91
+ ) : (
92
+ <div className='space-y-4'>
93
+ {data.modules.map((module, index) => (
94
+ <div key={index} className='flex items-center justify-between'>
95
+ <div>
96
+ <div className='font-medium'>{module.name}</div>
97
+ <div className='text-sm text-muted-foreground'>
98
+ v{String(module.version).replace(/\^/g, '')}
99
+ </div>
100
+ </div>
101
+ <Badge variant={module.upToDate ? 'outline' : 'secondary'}>
102
+ {module.upToDate ? 'Atualizado' : 'Atualização disponível'}
103
+ </Badge>
104
+ </div>
105
+ ))}
106
+ </div>
107
+ )}
108
+ </CardContent>
109
+ </Card>
110
+ )
111
+ }
112
+
113
+ export default ModuleInstalled
@@ -0,0 +1,144 @@
1
+ import { Cpu, HardDrive, Server } from 'lucide-react'
2
+ import { useEffect, useState } from 'react'
3
+
4
+ import {
5
+ Card,
6
+ CardContent,
7
+ CardDescription,
8
+ CardHeader,
9
+ CardTitle,
10
+ } from '@/components/ui/card'
11
+ import { Separator } from '@/components/ui/separator'
12
+ import { useApp } from '@/hooks/use-app'
13
+ import { bytesToHuman } from '@/lib/bytes-to-human'
14
+ import { secondsToHuman } from '@/lib/seconds-to-human'
15
+ import { DashboardDefaultData } from '@/types'
16
+
17
+ const SystemInfo = () => {
18
+ const { request } = useApp()
19
+ const [isRefreshing, setIsRefreshing] = useState(false)
20
+ const [data, setData] = useState<DashboardDefaultData>({
21
+ os: {
22
+ name: '',
23
+ platform: '',
24
+ version: '',
25
+ architecture: '',
26
+ uptime: 0,
27
+ cpu: {
28
+ model: '',
29
+ speed: 0,
30
+ physicalCores: 0,
31
+ virtualCores: 0,
32
+ },
33
+ memory: {
34
+ total: 0,
35
+ free: 0,
36
+ },
37
+ disk: [],
38
+ },
39
+ modules: [],
40
+ users: {
41
+ total: 0,
42
+ admin: 0,
43
+ active: 0,
44
+ activities: [],
45
+ },
46
+ database: {
47
+ connections: 0,
48
+ size: 0,
49
+ queriesPerSecond: 0,
50
+ },
51
+ } as DashboardDefaultData)
52
+
53
+ const load = async () => {
54
+ setIsRefreshing(true)
55
+ const { data } = await request<DashboardDefaultData>({
56
+ url: '/core',
57
+ })
58
+
59
+ setData(data)
60
+
61
+ setIsRefreshing(false)
62
+ }
63
+
64
+ useEffect(() => {
65
+ load()
66
+ }, [])
67
+
68
+ return (
69
+ <Card>
70
+ <CardHeader className='pb-2'>
71
+ <CardTitle className='flex items-center'>
72
+ <Server className='mr-2 h-5 w-5 text-primary' />
73
+ Informações do Sistema
74
+ </CardTitle>
75
+ <CardDescription>
76
+ Detalhes do sistema operacional e hardware
77
+ </CardDescription>
78
+ </CardHeader>
79
+ <CardContent>
80
+ {isRefreshing ? (
81
+ <div className='space-y-4'>
82
+ <div className='animate-pulse'>
83
+ <div className='mb-2 h-4 w-3/4 rounded bg-gray-200'></div>
84
+ <div className='mb-2 h-4 w-1/2 rounded bg-gray-200'></div>
85
+ <div className='mb-2 h-4 w-1/4 rounded bg-gray-200'></div>
86
+ <div className='mb-2 h-4 w-2/3 rounded bg-gray-200'></div>
87
+ </div>
88
+ <Separator />
89
+ <div className='animate-pulse'>
90
+ <div className='mb-2 h-4 w-3/4 rounded bg-gray-200'></div>
91
+ <div className='mb-2 h-4 w-1/2 rounded bg-gray-200'></div>
92
+ <div className='mb-2 h-4 w-1/4 rounded bg-gray-200'></div>
93
+ <div className='mb-2 h-4 w-2/3 rounded bg-gray-200'></div>
94
+ </div>
95
+ </div>
96
+ ) : (
97
+ <div className='space-y-4'>
98
+ <div>
99
+ <h3 className='flex items-center text-sm font-medium'>
100
+ <HardDrive className='mr-2 h-4 w-4 text-muted-foreground' />
101
+ Sistema Operacional
102
+ </h3>
103
+ <div className='mt-1 grid grid-cols-2 gap-1 text-sm'>
104
+ <div className='text-muted-foreground'>Nome:</div>
105
+ <div>{data.os.name}</div>
106
+ <div className='text-muted-foreground'>Versão:</div>
107
+ <div>{data.os.version}</div>
108
+ <div className='text-muted-foreground'>Arquitetura:</div>
109
+ <div>{data.os.architecture}</div>
110
+ <div className='text-muted-foreground'>Tempo ativo:</div>
111
+ <div>{secondsToHuman(data.os.uptime, true)}</div>
112
+ </div>
113
+ </div>
114
+ <Separator />
115
+ <div>
116
+ <h3 className='flex items-center text-sm font-medium'>
117
+ <Cpu className='mr-2 h-4 w-4 text-muted-foreground' />
118
+ Hardware
119
+ </h3>
120
+ <div className='mt-1 grid grid-cols-2 gap-1 text-sm'>
121
+ <div className='text-muted-foreground'>CPU:</div>
122
+ <div>{data.os.cpu.model}</div>
123
+ <div className='text-muted-foreground'>Memória:</div>
124
+ <div>{bytesToHuman(data.os.memory.total)}</div>
125
+ {data.os.disk.map((disk) => (
126
+ <>
127
+ <div className='text-muted-foreground'>
128
+ Disco {disk.filesystem}:
129
+ </div>
130
+ <div>
131
+ {bytesToHuman(disk.size)} ({bytesToHuman(disk.free)} free)
132
+ </div>
133
+ </>
134
+ ))}
135
+ </div>
136
+ </div>
137
+ </div>
138
+ )}
139
+ </CardContent>
140
+ </Card>
141
+ )
142
+ }
143
+
144
+ export default SystemInfo
@@ -0,0 +1,151 @@
1
+ import { User, Users } from 'lucide-react'
2
+ import { useEffect, useState } from 'react'
3
+
4
+ import { Button } from '@/components/ui/button'
5
+ import {
6
+ Card,
7
+ CardContent,
8
+ CardDescription,
9
+ CardFooter,
10
+ CardHeader,
11
+ CardTitle,
12
+ } from '@/components/ui/card'
13
+ import { useApp } from '@/hooks/use-app'
14
+ import { DashboardDefaultData } from '@/types'
15
+ import { useNavigate } from 'react-router-dom'
16
+
17
+ const UserSummary = () => {
18
+ const navigate = useNavigate()
19
+ const { request } = useApp()
20
+ const [isRefreshing, setIsRefreshing] = useState(false)
21
+ const [data, setData] = useState<DashboardDefaultData>({
22
+ os: {
23
+ name: '',
24
+ platform: '',
25
+ version: '',
26
+ architecture: '',
27
+ uptime: 0,
28
+ cpu: {
29
+ model: '',
30
+ speed: 0,
31
+ physicalCores: 0,
32
+ virtualCores: 0,
33
+ },
34
+ memory: {
35
+ total: 0,
36
+ free: 0,
37
+ },
38
+ disk: [],
39
+ },
40
+ modules: [],
41
+ users: {
42
+ total: 0,
43
+ admin: 0,
44
+ active: 0,
45
+ activities: [],
46
+ },
47
+ database: {
48
+ connections: 0,
49
+ size: 0,
50
+ queriesPerSecond: 0,
51
+ },
52
+ } as DashboardDefaultData)
53
+
54
+ const load = async () => {
55
+ setIsRefreshing(true)
56
+ const { data } = await request<DashboardDefaultData>({
57
+ url: '/core',
58
+ })
59
+
60
+ setData(data)
61
+
62
+ setIsRefreshing(false)
63
+ }
64
+
65
+ useEffect(() => {
66
+ load()
67
+ }, [])
68
+
69
+ return (
70
+ <Card>
71
+ <CardHeader className='pb-2'>
72
+ <CardTitle className='flex items-center'>
73
+ <Users className='mr-2 h-5 w-5 text-primary' />
74
+ Resumo de Usuários
75
+ </CardTitle>
76
+ <CardDescription>Visão geral dos usuários do sistema</CardDescription>
77
+ </CardHeader>
78
+ <CardContent>
79
+ <div className='space-y-4'>
80
+ {isRefreshing ? (
81
+ <div className='grid grid-cols-3 gap-4'>
82
+ {Array.from({ length: 3 }).map((_, index) => (
83
+ <div
84
+ key={index}
85
+ className='flex animate-pulse flex-col items-center justify-center rounded-lg bg-primary/10 p-3'
86
+ >
87
+ <div className='h-6 w-12 rounded bg-muted'></div>
88
+ <div className='mt-2 h-4 w-16 rounded bg-muted'></div>
89
+ </div>
90
+ ))}
91
+ </div>
92
+ ) : (
93
+ <>
94
+ <div className='grid grid-cols-3 gap-4'>
95
+ <div className='flex flex-col items-center justify-center rounded-lg bg-primary/10 p-3'>
96
+ <div className='text-2xl font-bold'>{data.users.total}</div>
97
+ <div className='text-xs text-muted-foreground'>Total</div>
98
+ </div>
99
+ <div className='flex flex-col items-center justify-center rounded-lg bg-primary/10 p-3'>
100
+ <div className='text-2xl font-bold'>{data.users.admin}</div>
101
+ <div className='text-xs text-muted-foreground'>Admins</div>
102
+ </div>
103
+ <div className='flex flex-col items-center justify-center rounded-lg bg-primary/10 p-3'>
104
+ <div className='text-2xl font-bold'>{data.users.active}</div>
105
+ <div className='text-xs text-muted-foreground'>Ativos</div>
106
+ </div>
107
+ </div>
108
+ {data.users.activities.length > 0 && (
109
+ <div>
110
+ <h3 className='mb-2 text-sm font-medium'>
111
+ Atividade Recente
112
+ </h3>
113
+
114
+ <div className='space-y-2'>
115
+ {data.users.activities.map((activity, index) => (
116
+ <div
117
+ key={index}
118
+ className='flex items-center justify-between text-sm'
119
+ >
120
+ <div className='flex items-center'>
121
+ <User className='mr-2 h-4 w-4 text-muted-foreground' />
122
+ <span>{activity.user.name}</span>
123
+ </div>
124
+ <div className='text-muted-foreground'>
125
+ {activity.created_at}
126
+ </div>
127
+ </div>
128
+ ))}
129
+ </div>
130
+ </div>
131
+ )}
132
+ </>
133
+ )}
134
+ </div>
135
+ </CardContent>
136
+ <CardFooter>
137
+ <Button
138
+ variant='outline'
139
+ size='sm'
140
+ className='w-full'
141
+ onClick={() => navigate('/users')}
142
+ >
143
+ <User className='mr-2 h-4 w-4' />
144
+ Ver Todos Usuários
145
+ </Button>
146
+ </CardFooter>
147
+ </Card>
148
+ )
149
+ }
150
+
151
+ export default UserSummary
package/hedhog.yaml CHANGED
@@ -812,12 +812,33 @@ data:
812
812
  - slug: default
813
813
  dashboard_component:
814
814
  - slug: system-info
815
- path: '@/components/dashboard/SystemInfo'
816
- width: 1
817
- height: 1
815
+ path: SystemInfo
816
+ width: 4
817
+ height: 14
818
818
  name:
819
819
  en: System Info
820
820
  pt: Informações do Sistema
821
+ - slug: module-installed
822
+ path: ModuleInstalled
823
+ width: 4
824
+ height: 14
825
+ name:
826
+ en: Modules Installed
827
+ pt: Módulos Instalados
828
+ - slug: user-summary
829
+ path: UserSummary
830
+ width: 4
831
+ height: 14
832
+ name:
833
+ en: Users Summary
834
+ pt: Resumo de Usuários
835
+ - slug: database-stats
836
+ path: DatabaseStats
837
+ width: 12
838
+ height: 4
839
+ name:
840
+ en: Database Stats
841
+ pt: Estatísticas do Banco de Dados
821
842
  dashboard_item:
822
843
  - component_id:
823
844
  where:
@@ -825,11 +846,40 @@ data:
825
846
  dashboard_id:
826
847
  where:
827
848
  slug: default
828
- width: 2
829
- height: 5
849
+ width: 4
850
+ height: 14
830
851
  x_axis: 0
831
852
  y_axis: 0
832
-
853
+ - component_id:
854
+ where:
855
+ slug: module-installed
856
+ dashboard_id:
857
+ where:
858
+ slug: default
859
+ width: 4
860
+ height: 14
861
+ x_axis: 4
862
+ y_axis: 0
863
+ - component_id:
864
+ where:
865
+ slug: user-summary
866
+ dashboard_id:
867
+ where:
868
+ slug: default
869
+ width: 4
870
+ height: 14
871
+ x_axis: 8
872
+ y_axis: 0
873
+ - component_id:
874
+ where:
875
+ slug: database-stats
876
+ dashboard_id:
877
+ where:
878
+ slug: default
879
+ width: 12
880
+ height: 4
881
+ x_axis: 0
882
+ y_axis: 14
833
883
  screens:
834
884
  dashboard:
835
885
  title:
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hedhog/admin",
3
- "version": "0.48.15",
3
+ "version": "0.48.17",
4
4
  "private": false,
5
5
  "main": "dist/index.js",
6
6
  "scripts": {
@@ -25,7 +25,7 @@
25
25
  "license": "MIT",
26
26
  "description": "",
27
27
  "devDependencies": {
28
- "@hedhog/locale": "^0.48.2",
28
+ "@hedhog/locale": "^0.48.4",
29
29
  "@hedhog/mail": "^0.48.1",
30
30
  "@hedhog/pagination": "^0.46.1",
31
31
  "@hedhog/prisma": "^0.46.1",