Add USB, Notifications, Network plugins and reusable EmployeeSearch component

New Plugins:
- USB plugin: Device checkout/checkin with employee lookup, checkout history
- Notifications plugin: Announcements with types, scheduling, shopfloor display
- Network plugin: Network device management with subnets and VLANs
- Equipment and Computers plugins: Asset type separation

Frontend:
- EmployeeSearch component: Reusable employee lookup with autocomplete
- USB views: List, detail, checkout/checkin modals
- Notifications views: List, form with recognition mode
- Network views: Device list, detail, form
- Calendar view with FullCalendar integration
- Shopfloor and TV dashboard views
- Reports index page
- Map editor for asset positioning
- Light/dark mode fixes for map tooltips

Backend:
- Employee search API with external lookup service
- Collector API for PowerShell data collection
- Reports API endpoints
- Slides API for TV dashboard
- Fixed AppVersion model (removed BaseModel inheritance)
- Added checkout_name column to usbcheckouts table

Styling:
- Unified detail page styles
- Improved pagination (page numbers instead of prev/next)
- Dark/light mode theme improvements

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
cproudlock
2026-01-21 16:37:49 -05:00
parent 02d83335ee
commit 9c220a4194
110 changed files with 17693 additions and 600 deletions

View File

@@ -1,11 +1,11 @@
"""Machine relationship models."""
"""Machine and Asset relationship models."""
from shopdb.extensions import db
from .base import BaseModel
class RelationshipType(BaseModel):
"""Types of relationships between machines."""
"""Types of relationships between machines/assets."""
__tablename__ = 'relationshiptypes'
relationshiptypeid = db.Column(db.Integer, primary_key=True)
@@ -21,6 +21,65 @@ class RelationshipType(BaseModel):
return f"<RelationshipType {self.relationshiptype}>"
class AssetRelationship(BaseModel):
"""
Relationships between assets.
Examples:
- Computer controls Equipment
- Two machines are dualpath partners
- Network device connects to equipment
"""
__tablename__ = 'assetrelationships'
relationshipid = db.Column(db.Integer, primary_key=True)
source_assetid = db.Column(
db.Integer,
db.ForeignKey('assets.assetid'),
nullable=False
)
target_assetid = db.Column(
db.Integer,
db.ForeignKey('assets.assetid'),
nullable=False
)
relationshiptypeid = db.Column(
db.Integer,
db.ForeignKey('relationshiptypes.relationshiptypeid'),
nullable=False
)
notes = db.Column(db.Text)
# Relationships
source_asset = db.relationship(
'Asset',
foreign_keys=[source_assetid],
backref='outgoing_relationships'
)
target_asset = db.relationship(
'Asset',
foreign_keys=[target_assetid],
backref='incoming_relationships'
)
relationship_type = db.relationship('RelationshipType', backref='asset_relationships')
__table_args__ = (
db.UniqueConstraint(
'source_assetid',
'target_assetid',
'relationshiptypeid',
name='uq_asset_relationship'
),
db.Index('idx_asset_rel_source', 'source_assetid'),
db.Index('idx_asset_rel_target', 'target_assetid'),
)
def __repr__(self):
return f"<AssetRelationship {self.source_assetid} -> {self.target_assetid}>"
class MachineRelationship(BaseModel):
"""
Relationships between machines.