simple-module-dashboard 0.0.2__tar.gz → 0.0.4__tar.gz
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.
- {simple_module_dashboard-0.0.2 → simple_module_dashboard-0.0.4}/.gitignore +4 -0
- {simple_module_dashboard-0.0.2 → simple_module_dashboard-0.0.4}/PKG-INFO +6 -7
- {simple_module_dashboard-0.0.2 → simple_module_dashboard-0.0.4}/README.md +1 -1
- {simple_module_dashboard-0.0.2 → simple_module_dashboard-0.0.4}/dashboard/locales/en.json +0 -1
- {simple_module_dashboard-0.0.2 → simple_module_dashboard-0.0.4}/dashboard/locales/es.json +0 -1
- {simple_module_dashboard-0.0.2 → simple_module_dashboard-0.0.4}/dashboard/module.py +2 -3
- {simple_module_dashboard-0.0.2 → simple_module_dashboard-0.0.4}/dashboard/pages/Home.tsx +3 -15
- {simple_module_dashboard-0.0.2 → simple_module_dashboard-0.0.4}/dashboard/stats.py +0 -10
- {simple_module_dashboard-0.0.2 → simple_module_dashboard-0.0.4}/pyproject.toml +5 -7
- {simple_module_dashboard-0.0.2 → simple_module_dashboard-0.0.4}/tests/test_dashboard.py +0 -3
- {simple_module_dashboard-0.0.2 → simple_module_dashboard-0.0.4}/LICENSE +0 -0
- {simple_module_dashboard-0.0.2 → simple_module_dashboard-0.0.4}/dashboard/__init__.py +0 -0
- {simple_module_dashboard-0.0.2 → simple_module_dashboard-0.0.4}/dashboard/endpoints/__init__.py +0 -0
- {simple_module_dashboard-0.0.2 → simple_module_dashboard-0.0.4}/dashboard/endpoints/api.py +0 -0
- {simple_module_dashboard-0.0.2 → simple_module_dashboard-0.0.4}/dashboard/endpoints/views.py +0 -0
- {simple_module_dashboard-0.0.2 → simple_module_dashboard-0.0.4}/dashboard/py.typed +0 -0
- {simple_module_dashboard-0.0.2 → simple_module_dashboard-0.0.4}/package.json +0 -0
- {simple_module_dashboard-0.0.2 → simple_module_dashboard-0.0.4}/tsconfig.json +0 -0
|
@@ -36,6 +36,10 @@ uploads/
|
|
|
36
36
|
# Vite
|
|
37
37
|
host/static/dist/
|
|
38
38
|
|
|
39
|
+
# VitePress (docs)
|
|
40
|
+
docs/.vitepress/cache/
|
|
41
|
+
docs/.vitepress/dist/
|
|
42
|
+
|
|
39
43
|
# Auto-generated frontend module manifest (regenerated by the host at boot
|
|
40
44
|
# or via `make gen-pages`).
|
|
41
45
|
host/client_app/modules.manifest.json
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: simple_module_dashboard
|
|
3
|
-
Version: 0.0.
|
|
3
|
+
Version: 0.0.4
|
|
4
4
|
Summary: Admin landing page and sidebar menu host for authenticated users of a simple_module app
|
|
5
5
|
Project-URL: Homepage, https://github.com/antosubash/simple_module_python
|
|
6
6
|
Project-URL: Repository, https://github.com/antosubash/simple_module_python
|
|
@@ -21,11 +21,10 @@ Classifier: Topic :: Internet :: WWW/HTTP
|
|
|
21
21
|
Classifier: Topic :: Software Development :: Libraries :: Application Frameworks
|
|
22
22
|
Classifier: Typing :: Typed
|
|
23
23
|
Requires-Python: >=3.12
|
|
24
|
-
Requires-Dist: simple-module-core==0.0.
|
|
25
|
-
Requires-Dist: simple-module-db==0.0.
|
|
26
|
-
Requires-Dist: simple-module-hosting==0.0.
|
|
27
|
-
Requires-Dist: simple-module-
|
|
28
|
-
Requires-Dist: simple-module-users==0.0.2
|
|
24
|
+
Requires-Dist: simple-module-core==0.0.4
|
|
25
|
+
Requires-Dist: simple-module-db==0.0.4
|
|
26
|
+
Requires-Dist: simple-module-hosting==0.0.4
|
|
27
|
+
Requires-Dist: simple-module-users==0.0.4
|
|
29
28
|
Description-Content-Type: text/markdown
|
|
30
29
|
|
|
31
30
|
# simple_module_dashboard
|
|
@@ -68,7 +67,7 @@ The dashboard sidebar picks it up automatically.
|
|
|
68
67
|
## Depends on
|
|
69
68
|
|
|
70
69
|
- `simple_module_core`, `simple_module_db`, `simple_module_hosting`
|
|
71
|
-
- `simple_module_users
|
|
70
|
+
- `simple_module_users` (user counts shown on the default layout)
|
|
72
71
|
|
|
73
72
|
## License
|
|
74
73
|
|
|
@@ -38,7 +38,7 @@ The dashboard sidebar picks it up automatically.
|
|
|
38
38
|
## Depends on
|
|
39
39
|
|
|
40
40
|
- `simple_module_core`, `simple_module_db`, `simple_module_hosting`
|
|
41
|
-
- `simple_module_users
|
|
41
|
+
- `simple_module_users` (user counts shown on the default layout)
|
|
42
42
|
|
|
43
43
|
## License
|
|
44
44
|
|
|
@@ -9,7 +9,6 @@ from fastapi import APIRouter
|
|
|
9
9
|
from simple_module_core.menu import MenuItem, MenuRegistry, MenuSection
|
|
10
10
|
from simple_module_core.module import ModuleBase, ModuleMeta
|
|
11
11
|
|
|
12
|
-
_MODULE_PRODUCTS = "Products"
|
|
13
12
|
_MODULE_USERS = "Users"
|
|
14
13
|
_URL_DASHBOARD = "/dashboard/"
|
|
15
14
|
_ICON_DASHBOARD = "home"
|
|
@@ -20,7 +19,7 @@ class DashboardModule(ModuleBase):
|
|
|
20
19
|
name="Dashboard",
|
|
21
20
|
route_prefix="/api/dashboard",
|
|
22
21
|
view_prefix="/dashboard",
|
|
23
|
-
depends_on=[
|
|
22
|
+
depends_on=[_MODULE_USERS],
|
|
24
23
|
)
|
|
25
24
|
|
|
26
25
|
def register_routes(self, api_router: APIRouter, view_router: APIRouter) -> None:
|
|
@@ -36,7 +35,7 @@ class DashboardModule(ModuleBase):
|
|
|
36
35
|
label="Dashboard",
|
|
37
36
|
url=_URL_DASHBOARD,
|
|
38
37
|
icon=_ICON_DASHBOARD,
|
|
39
|
-
order=
|
|
38
|
+
order=10,
|
|
40
39
|
section=MenuSection.SIDEBAR,
|
|
41
40
|
)
|
|
42
41
|
)
|
|
@@ -4,9 +4,9 @@ import { PageShell } from '@simple-module-py/ui/components/PageShell';
|
|
|
4
4
|
import { Card, CardContent, CardHeader, CardTitle } from '@simple-module-py/ui/components/ui/card';
|
|
5
5
|
import { Table, TableBody, TableCell, TableRow } from '@simple-module-py/ui/components/ui/table';
|
|
6
6
|
import { AuthenticatedLayout } from '@simple-module-py/ui/layouts/AuthenticatedLayout';
|
|
7
|
-
import { Activity, Box, Heart,
|
|
7
|
+
import { Activity, Box, Heart, Server, Users } from 'lucide-react';
|
|
8
8
|
|
|
9
|
-
type Accent = '
|
|
9
|
+
type Accent = 'emerald' | 'violet' | 'amber';
|
|
10
10
|
|
|
11
11
|
const HEALTH_STATUS_COLOR: Record<string, string> = {
|
|
12
12
|
healthy: 'bg-emerald-500',
|
|
@@ -33,7 +33,6 @@ interface SystemInfo {
|
|
|
33
33
|
interface Props {
|
|
34
34
|
total_users: number;
|
|
35
35
|
active_users_7d: number;
|
|
36
|
-
total_products: number;
|
|
37
36
|
module_count: number;
|
|
38
37
|
system_info: SystemInfo;
|
|
39
38
|
}
|
|
@@ -47,7 +46,7 @@ function Home() {
|
|
|
47
46
|
title={t(keys.dashboard.home.title)}
|
|
48
47
|
description={t(keys.dashboard.home.description)}
|
|
49
48
|
>
|
|
50
|
-
<div className="grid grid-cols-1 sm:grid-cols-
|
|
49
|
+
<div className="grid grid-cols-1 sm:grid-cols-3 gap-5 mb-8">
|
|
51
50
|
<StatCard
|
|
52
51
|
title={t(keys.dashboard.home.stats.total_users)}
|
|
53
52
|
value={String(props.total_users)}
|
|
@@ -60,12 +59,6 @@ function Home() {
|
|
|
60
59
|
icon={<Activity className="size-4" />}
|
|
61
60
|
accent="amber"
|
|
62
61
|
/>
|
|
63
|
-
<StatCard
|
|
64
|
-
title={t(keys.dashboard.home.stats.products)}
|
|
65
|
-
value={String(props.total_products)}
|
|
66
|
-
icon={<Package className="size-4" />}
|
|
67
|
-
accent="primary"
|
|
68
|
-
/>
|
|
69
62
|
<StatCard
|
|
70
63
|
title={t(keys.dashboard.home.stats.modules)}
|
|
71
64
|
value={String(props.module_count)}
|
|
@@ -143,11 +136,6 @@ function StatCard({
|
|
|
143
136
|
accent: Accent;
|
|
144
137
|
}) {
|
|
145
138
|
const styles: Record<Accent, { card: string; icon: string; value: string }> = {
|
|
146
|
-
primary: {
|
|
147
|
-
card: 'border-primary-200 bg-gradient-to-br from-primary-50 to-card',
|
|
148
|
-
icon: 'text-primary-500 bg-primary-100',
|
|
149
|
-
value: 'text-primary-900',
|
|
150
|
-
},
|
|
151
139
|
emerald: {
|
|
152
140
|
card: 'border-emerald-border bg-gradient-to-br from-emerald-bg to-card',
|
|
153
141
|
icon: 'text-emerald-icon-fg bg-emerald-icon-bg',
|
|
@@ -8,7 +8,6 @@ import time
|
|
|
8
8
|
from datetime import UTC, datetime, timedelta
|
|
9
9
|
|
|
10
10
|
from fastapi import FastAPI
|
|
11
|
-
from products.models import Product
|
|
12
11
|
from simple_module_core.health import HealthCheck, HealthStatus
|
|
13
12
|
from sqlalchemy import func, select
|
|
14
13
|
from sqlalchemy.ext.asyncio import AsyncSession
|
|
@@ -42,14 +41,12 @@ async def fetch_dashboard_stats(db: AsyncSession, app: FastAPI) -> dict:
|
|
|
42
41
|
|
|
43
42
|
total_users = await _count_users(db)
|
|
44
43
|
active_users_7d = await _count_active_users(db, days=7)
|
|
45
|
-
total_products = await _count_products(db)
|
|
46
44
|
modules_list = _get_module_info(app)
|
|
47
45
|
health_checks = await _run_health_checks(app)
|
|
48
46
|
|
|
49
47
|
result = {
|
|
50
48
|
"total_users": total_users,
|
|
51
49
|
"active_users_7d": active_users_7d,
|
|
52
|
-
"total_products": total_products,
|
|
53
50
|
"module_count": len(modules_list),
|
|
54
51
|
"system_info": {
|
|
55
52
|
"modules": modules_list,
|
|
@@ -85,13 +82,6 @@ async def _count_active_users(db: AsyncSession, *, days: int) -> int:
|
|
|
85
82
|
return result.scalar_one()
|
|
86
83
|
|
|
87
84
|
|
|
88
|
-
async def _count_products(db: AsyncSession) -> int:
|
|
89
|
-
result = await db.execute(
|
|
90
|
-
select(func.count()).select_from(Product).where(Product.is_active.is_(True))
|
|
91
|
-
)
|
|
92
|
-
return result.scalar_one()
|
|
93
|
-
|
|
94
|
-
|
|
95
85
|
def _get_module_info(app: FastAPI) -> list[dict[str, str]]:
|
|
96
86
|
# Reads from the module list discovered once at startup, avoiding
|
|
97
87
|
# expensive entry-point rescans on every request.
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "simple_module_dashboard"
|
|
3
|
-
version = "0.0.
|
|
3
|
+
version = "0.0.4"
|
|
4
4
|
description = "Admin landing page and sidebar menu host for authenticated users of a simple_module app"
|
|
5
5
|
readme = "README.md"
|
|
6
6
|
license = "MIT"
|
|
@@ -21,11 +21,10 @@ classifiers = [
|
|
|
21
21
|
"Typing :: Typed",
|
|
22
22
|
]
|
|
23
23
|
dependencies = [
|
|
24
|
-
"simple_module_core==0.0.
|
|
25
|
-
"simple_module_db==0.0.
|
|
26
|
-
"simple_module_hosting==0.0.
|
|
27
|
-
"
|
|
28
|
-
"simple_module_users==0.0.2",
|
|
24
|
+
"simple_module_core==0.0.4",
|
|
25
|
+
"simple_module_db==0.0.4",
|
|
26
|
+
"simple_module_hosting==0.0.4",
|
|
27
|
+
"simple_module_users==0.0.4",
|
|
29
28
|
]
|
|
30
29
|
|
|
31
30
|
[project.entry-points.simple_module]
|
|
@@ -53,5 +52,4 @@ packages = ["dashboard"]
|
|
|
53
52
|
simple_module_core = { workspace = true }
|
|
54
53
|
simple_module_db = { workspace = true }
|
|
55
54
|
simple_module_hosting = { workspace = true }
|
|
56
|
-
simple_module_products = { workspace = true }
|
|
57
55
|
simple_module_users = { workspace = true }
|
|
@@ -24,7 +24,6 @@ class TestDashboardModuleRegistration:
|
|
|
24
24
|
mod = DashboardModule()
|
|
25
25
|
assert mod.meta.name == "Dashboard"
|
|
26
26
|
assert mod.meta.route_prefix == "/api/dashboard"
|
|
27
|
-
assert "Products" in mod.meta.depends_on
|
|
28
27
|
assert "Users" in mod.meta.depends_on
|
|
29
28
|
|
|
30
29
|
|
|
@@ -42,7 +41,6 @@ class TestFetchDashboardStats:
|
|
|
42
41
|
async def test_returns_expected_keys(self, stats):
|
|
43
42
|
assert "total_users" in stats
|
|
44
43
|
assert "active_users_7d" in stats
|
|
45
|
-
assert "total_products" in stats
|
|
46
44
|
assert "module_count" in stats
|
|
47
45
|
assert "system_info" in stats
|
|
48
46
|
|
|
@@ -79,7 +77,6 @@ class TestDashboardStatsEndpoint:
|
|
|
79
77
|
body = resp.json()
|
|
80
78
|
assert "total_users" in body
|
|
81
79
|
assert "active_users_7d" in body
|
|
82
|
-
assert "total_products" in body
|
|
83
80
|
assert "module_count" in body
|
|
84
81
|
assert "system_info" in body
|
|
85
82
|
|
|
File without changes
|
|
File without changes
|
{simple_module_dashboard-0.0.2 → simple_module_dashboard-0.0.4}/dashboard/endpoints/__init__.py
RENAMED
|
File without changes
|
|
File without changes
|
{simple_module_dashboard-0.0.2 → simple_module_dashboard-0.0.4}/dashboard/endpoints/views.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|