Files
shopfloor-dashboard/server.js
cproudlock 49f8274f47 Feature: Priority-based sorting and display limit optimization
Backend (server.js):
- Implemented severity-based sorting for current events
- Priority hierarchy: Incident > Change > Awareness > TBD
- Events with same severity sorted by starttime (earliest first)
- Upcoming events remain sorted by starttime only
- Added severityPriority mapping for consistent ordering

Frontend (index.html):
- Reduced display limits for 1080p TVs: 2 current + 2 upcoming = 4 total
- Prevents content overflow on 1080p displays
- 4K displays still auto-scale content appropriately
- Ensures critical incidents always appear first in current events

Testing:
- Verified Incident appears before Change before Awareness
- Verified all 4 events fit on 1080p screen without scrolling

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-10-24 10:01:55 -04:00

124 lines
3.9 KiB
JavaScript

const express = require('express');
const mysql = require('mysql2');
const path = require('path');
const app = express();
const PORT = process.env.PORT || 3000;
// Database connection pool
const pool = mysql.createPool({
host: process.env.DB_HOST || 'localhost',
port: process.env.DB_PORT || 3306,
user: process.env.DB_USER || '570005354',
password: process.env.DB_PASS || '570005354',
database: process.env.DB_NAME || 'shopdb',
waitForConnections: true,
connectionLimit: 10,
queueLimit: 0
});
// Promisify for async/await
const promisePool = pool.promise();
// Serve static files
app.use(express.static('public'));
// API endpoint to get notifications
app.get('/api/notifications', async (req, res) => {
try {
const now = new Date();
const future = new Date(now.getTime() + (72 * 60 * 60 * 1000)); // 72 hours from now
const [rows] = await promisePool.query(
`SELECT n.notificationid, n.notification, n.starttime, n.endtime, n.ticketnumber, n.link,
n.isactive, n.isshopfloor, nt.typename, nt.typecolor
FROM notifications n
LEFT JOIN notificationtypes nt ON n.notificationtypeid = nt.notificationtypeid
WHERE n.isactive = 1
AND n.isshopfloor = 1
AND (
(n.starttime <= ? AND (n.endtime IS NULL OR n.endtime >= ?))
OR (n.starttime BETWEEN ? AND ?)
)
ORDER BY n.starttime ASC`,
[future, now, now, future]
);
// Categorize notifications
const currentEvents = [];
const upcomingEvents = [];
rows.forEach(notification => {
const start = new Date(notification.starttime);
const end = notification.endtime ? new Date(notification.endtime) : null;
if (start <= now && (end === null || end >= now)) {
currentEvents.push(notification);
} else {
upcomingEvents.push(notification);
}
});
// Sort current events by severity priority, then by starttime
// Priority: Incident (danger) > Change (warning) > Awareness/TBD (success)
const severityPriority = {
'danger': 1, // Incident - highest priority
'warning': 2, // Change
'success': 3, // Awareness/TBD - lowest priority
'secondary': 4 // Fallback
};
currentEvents.sort((a, b) => {
const priorityA = severityPriority[a.typecolor] || 4;
const priorityB = severityPriority[b.typecolor] || 4;
// First sort by priority
if (priorityA !== priorityB) {
return priorityA - priorityB;
}
// If same priority, sort by starttime (earliest first)
return new Date(a.starttime) - new Date(b.starttime);
});
// Upcoming events stay sorted by starttime only
upcomingEvents.sort((a, b) => {
return new Date(a.starttime) - new Date(b.starttime);
});
res.json({
success: true,
timestamp: new Date().toISOString(),
current: currentEvents,
upcoming: upcomingEvents
});
} catch (error) {
console.error('Database error:', error);
res.status(500).json({
success: false,
error: 'Database error: ' + error.message
});
}
});
// Health check endpoint
app.get('/health', (req, res) => {
res.json({ status: 'ok', timestamp: new Date().toISOString() });
});
// Start server
app.listen(PORT, () => {
console.log(`Shopfloor Dashboard running on port ${PORT}`);
console.log(`Access at: http://localhost:${PORT}`);
});
// Graceful shutdown
process.on('SIGTERM', () => {
console.log('SIGTERM signal received: closing HTTP server');
pool.end(() => {
console.log('Database pool closed');
process.exit(0);
});
});