mirror of
https://github.com/maziggy/bambuddy.git
synced 2026-10-07 23:01:06 +02:00
- Added maintenance interval type clendar days
- Minor improvements to maintenance module
This commit is contained in:
@@ -136,6 +136,7 @@ async def create_maintenance_type(
|
||||
name=data.name,
|
||||
description=data.description,
|
||||
default_interval_hours=data.default_interval_hours,
|
||||
interval_type=data.interval_type,
|
||||
icon=data.icon,
|
||||
is_system=False,
|
||||
)
|
||||
@@ -225,11 +226,16 @@ async def _get_printer_maintenance_internal(
|
||||
due_count = 0
|
||||
warning_count = 0
|
||||
|
||||
now = datetime.utcnow()
|
||||
|
||||
for maint_type in all_types:
|
||||
item = existing_items.get(maint_type.id)
|
||||
default_interval_type = getattr(maint_type, 'interval_type', 'hours') or 'hours'
|
||||
|
||||
if item:
|
||||
interval = item.custom_interval_hours or maint_type.default_interval_hours
|
||||
# Use custom interval type if set, otherwise use type's default
|
||||
interval_type = getattr(item, 'custom_interval_type', None) or default_interval_type
|
||||
enabled = item.enabled
|
||||
last_performed_hours = item.last_performed_hours
|
||||
last_performed_at = item.last_performed_at
|
||||
@@ -246,15 +252,41 @@ async def _get_printer_maintenance_internal(
|
||||
await db.flush()
|
||||
|
||||
interval = maint_type.default_interval_hours
|
||||
interval_type = default_interval_type
|
||||
enabled = True
|
||||
last_performed_hours = 0.0
|
||||
last_performed_at = None
|
||||
item_id = item.id
|
||||
|
||||
hours_since = total_hours - last_performed_hours
|
||||
hours_until = interval - hours_since
|
||||
is_due = hours_until <= 0
|
||||
is_warning = hours_until <= (interval * 0.1) and not is_due
|
||||
# Calculate status based on interval type
|
||||
if interval_type == "days":
|
||||
# Time-based: calculate days since last performed
|
||||
if last_performed_at:
|
||||
days_since = (now - last_performed_at).total_seconds() / 86400.0
|
||||
else:
|
||||
# Never performed - consider it due
|
||||
days_since = interval + 1
|
||||
|
||||
days_until = interval - days_since
|
||||
is_due = days_until <= 0
|
||||
is_warning = days_until <= (interval * 0.1) and not is_due
|
||||
|
||||
# For compatibility, also set hours values (but they won't be primary)
|
||||
hours_since = total_hours - last_performed_hours
|
||||
hours_until = 0 # Not applicable for time-based
|
||||
else:
|
||||
# Print-hours based (default)
|
||||
hours_since = total_hours - last_performed_hours
|
||||
hours_until = interval - hours_since
|
||||
is_due = hours_until <= 0
|
||||
is_warning = hours_until <= (interval * 0.1) and not is_due
|
||||
|
||||
# Calculate days for reference
|
||||
if last_performed_at:
|
||||
days_since = (now - last_performed_at).total_seconds() / 86400.0
|
||||
else:
|
||||
days_since = None
|
||||
days_until = None
|
||||
|
||||
if enabled:
|
||||
if is_due:
|
||||
@@ -271,9 +303,12 @@ async def _get_printer_maintenance_internal(
|
||||
maintenance_type_icon=maint_type.icon,
|
||||
enabled=enabled,
|
||||
interval_hours=interval,
|
||||
interval_type=interval_type,
|
||||
current_hours=total_hours,
|
||||
hours_since_maintenance=hours_since,
|
||||
hours_until_due=hours_until,
|
||||
days_since_maintenance=days_since if interval_type == "days" else None,
|
||||
days_until_due=days_until if interval_type == "days" else None,
|
||||
is_due=is_due,
|
||||
is_warning=is_warning,
|
||||
last_performed_at=last_performed_at,
|
||||
@@ -389,6 +424,7 @@ async def perform_maintenance(
|
||||
|
||||
# Calculate status
|
||||
interval = item.custom_interval_hours or item.maintenance_type.default_interval_hours
|
||||
interval_type = getattr(item.maintenance_type, 'interval_type', 'hours') or 'hours'
|
||||
hours_since = current_hours - item.last_performed_hours
|
||||
hours_until = interval - hours_since
|
||||
|
||||
@@ -401,9 +437,12 @@ async def perform_maintenance(
|
||||
maintenance_type_icon=item.maintenance_type.icon,
|
||||
enabled=item.enabled,
|
||||
interval_hours=interval,
|
||||
interval_type=interval_type,
|
||||
current_hours=current_hours,
|
||||
hours_since_maintenance=hours_since,
|
||||
hours_until_due=hours_until,
|
||||
hours_until_due=hours_until if interval_type == "hours" else 0,
|
||||
days_since_maintenance=0 if interval_type == "days" else None,
|
||||
days_until_due=interval if interval_type == "days" else None,
|
||||
is_due=False,
|
||||
is_warning=False,
|
||||
last_performed_at=item.last_performed_at,
|
||||
|
||||
@@ -109,3 +109,21 @@ async def run_migrations(conn):
|
||||
except Exception:
|
||||
# Column already exists
|
||||
pass
|
||||
|
||||
# Migration: Add interval_type column to maintenance_types
|
||||
try:
|
||||
await conn.execute(text(
|
||||
"ALTER TABLE maintenance_types ADD COLUMN interval_type VARCHAR(20) DEFAULT 'hours'"
|
||||
))
|
||||
except Exception:
|
||||
# Column already exists
|
||||
pass
|
||||
|
||||
# Migration: Add custom_interval_type column to printer_maintenance
|
||||
try:
|
||||
await conn.execute(text(
|
||||
"ALTER TABLE printer_maintenance ADD COLUMN custom_interval_type VARCHAR(20)"
|
||||
))
|
||||
except Exception:
|
||||
# Column already exists
|
||||
pass
|
||||
|
||||
@@ -15,6 +15,8 @@ class MaintenanceType(Base):
|
||||
name: Mapped[str] = mapped_column(String(100))
|
||||
description: Mapped[str | None] = mapped_column(Text)
|
||||
default_interval_hours: Mapped[float] = mapped_column(Float, default=100.0)
|
||||
# Interval type: "hours" (print hours) or "days" (calendar days)
|
||||
interval_type: Mapped[str] = mapped_column(String(20), default="hours")
|
||||
icon: Mapped[str | None] = mapped_column(String(50)) # Icon name for UI
|
||||
is_system: Mapped[bool] = mapped_column(Boolean, default=False) # Pre-defined vs custom
|
||||
created_at: Mapped[datetime] = mapped_column(
|
||||
@@ -37,6 +39,8 @@ class PrinterMaintenance(Base):
|
||||
|
||||
# Custom interval for this printer (overrides default if set)
|
||||
custom_interval_hours: Mapped[float | None] = mapped_column(Float, nullable=True)
|
||||
# Custom interval type for this printer (overrides default if set)
|
||||
custom_interval_type: Mapped[str | None] = mapped_column(String(20), nullable=True)
|
||||
|
||||
# Tracking
|
||||
enabled: Mapped[bool] = mapped_column(Boolean, default=True)
|
||||
|
||||
@@ -9,6 +9,8 @@ class MaintenanceTypeBase(BaseModel):
|
||||
name: str = Field(..., min_length=1, max_length=100)
|
||||
description: str | None = None
|
||||
default_interval_hours: float = Field(default=100.0, ge=1.0)
|
||||
# "hours" = print hours, "days" = calendar days
|
||||
interval_type: str = Field(default="hours", pattern="^(hours|days)$")
|
||||
icon: str | None = None
|
||||
|
||||
|
||||
@@ -20,6 +22,7 @@ class MaintenanceTypeUpdate(BaseModel):
|
||||
name: str | None = None
|
||||
description: str | None = None
|
||||
default_interval_hours: float | None = Field(default=None, ge=1.0)
|
||||
interval_type: str | None = Field(default=None, pattern="^(hours|days)$")
|
||||
icon: str | None = None
|
||||
|
||||
|
||||
@@ -46,6 +49,7 @@ class PrinterMaintenanceCreate(PrinterMaintenanceBase):
|
||||
|
||||
class PrinterMaintenanceUpdate(BaseModel):
|
||||
custom_interval_hours: float | None = None
|
||||
custom_interval_type: str | None = Field(default=None, pattern="^(hours|days)$")
|
||||
enabled: bool | None = None
|
||||
|
||||
|
||||
@@ -94,12 +98,19 @@ class MaintenanceStatus(BaseModel):
|
||||
maintenance_type_name: str
|
||||
maintenance_type_icon: str | None
|
||||
enabled: bool
|
||||
interval_hours: float # custom or default
|
||||
# Interval configuration
|
||||
interval_hours: float # custom or default (hours for print-based, days for time-based)
|
||||
interval_type: str # "hours" or "days"
|
||||
# For print-hour based maintenance
|
||||
current_hours: float # total print hours for printer
|
||||
hours_since_maintenance: float # current - last_performed
|
||||
hours_until_due: float # interval - hours_since
|
||||
is_due: bool # hours_until_due <= 0
|
||||
is_warning: bool # hours_until_due <= 10% of interval
|
||||
hours_until_due: float # interval - hours_since (for hours type)
|
||||
# For time-based maintenance
|
||||
days_since_maintenance: float | None # days since last performed
|
||||
days_until_due: float | None # for days type
|
||||
# Status flags
|
||||
is_due: bool # hours_until_due <= 0 OR days_until_due <= 0
|
||||
is_warning: bool # within 10% of interval
|
||||
last_performed_at: datetime | None
|
||||
|
||||
|
||||
|
||||
@@ -721,6 +721,7 @@ export interface MaintenanceType {
|
||||
name: string;
|
||||
description: string | null;
|
||||
default_interval_hours: number;
|
||||
interval_type: 'hours' | 'days'; // "hours" = print hours, "days" = calendar days
|
||||
icon: string | null;
|
||||
is_system: boolean;
|
||||
created_at: string;
|
||||
@@ -730,6 +731,7 @@ export interface MaintenanceTypeCreate {
|
||||
name: string;
|
||||
description?: string | null;
|
||||
default_interval_hours?: number;
|
||||
interval_type?: 'hours' | 'days';
|
||||
icon?: string | null;
|
||||
}
|
||||
|
||||
@@ -741,10 +743,13 @@ export interface MaintenanceStatus {
|
||||
maintenance_type_name: string;
|
||||
maintenance_type_icon: string | null;
|
||||
enabled: boolean;
|
||||
interval_hours: number;
|
||||
interval_hours: number; // For hours type: print hours; for days type: number of days
|
||||
interval_type: 'hours' | 'days';
|
||||
current_hours: number;
|
||||
hours_since_maintenance: number;
|
||||
hours_until_due: number;
|
||||
days_since_maintenance: number | null; // For days type
|
||||
days_until_due: number | null; // For days type
|
||||
is_due: boolean;
|
||||
is_warning: boolean;
|
||||
last_performed_at: string | null;
|
||||
@@ -1274,7 +1279,7 @@ export const api = {
|
||||
getMaintenanceOverview: () => request<PrinterMaintenanceOverview[]>('/maintenance/overview'),
|
||||
getPrinterMaintenance: (printerId: number) =>
|
||||
request<PrinterMaintenanceOverview>(`/maintenance/printers/${printerId}`),
|
||||
updateMaintenanceItem: (itemId: number, data: { custom_interval_hours?: number | null; enabled?: boolean }) =>
|
||||
updateMaintenanceItem: (itemId: number, data: { custom_interval_hours?: number | null; custom_interval_type?: 'hours' | 'days' | null; enabled?: boolean }) =>
|
||||
request<MaintenanceStatus>(`/maintenance/items/${itemId}`, {
|
||||
method: 'PATCH',
|
||||
body: JSON.stringify(data),
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
+2
-2
@@ -7,8 +7,8 @@
|
||||
<link rel="icon" type="image/png" sizes="32x32" href="/img/favicon-32x32.png" />
|
||||
<link rel="icon" type="image/png" sizes="16x16" href="/img/favicon-16x16.png" />
|
||||
<link rel="apple-touch-icon" sizes="180x180" href="/img/apple-touch-icon.png" />
|
||||
<script type="module" crossorigin src="/assets/index-BOLoyzZ9.js"></script>
|
||||
<link rel="stylesheet" crossorigin href="/assets/index-DO3k-CBG.css">
|
||||
<script type="module" crossorigin src="/assets/index-6YKRUSex.js"></script>
|
||||
<link rel="stylesheet" crossorigin href="/assets/index-BP1T2ML7.css">
|
||||
</head>
|
||||
<body>
|
||||
<div id="root"></div>
|
||||
|
||||
Reference in New Issue
Block a user