Files
controls-web/controls-rework/alerts-admin.php
2026-02-17 09:29:34 -06:00

686 lines
25 KiB
PHP
Raw Permalink Blame History

This file contains invisible Unicode characters
This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<?php // phpcs:ignoreFile
/**
* Alerts Admin - Manage alert definitions
*/
require __DIR__ . '/session.php';
require __DIR__ . '/userAccess.php';
// Only allow admin or controls
if ($_SESSION['SESS_MEMBER_LEVEL'] < 4) {
header("Location: access-denied.php");
exit();
}
$alertsConn = mysqli_connect('192.168.0.16', 'lasucaai', 'is413#dfslw', 'controls');
if (!$alertsConn) {
die("Connection failed: " . mysqli_connect_error());
}
mysqli_set_charset($alertsConn, 'utf8mb4');
// Create alert_definitions table if not exists
$createTable = "CREATE TABLE IF NOT EXISTS alert_definitions (
id INT AUTO_INCREMENT PRIMARY KEY,
tag_name VARCHAR(100) NOT NULL,
alert_type ENUM('danger', 'warning', 'info') DEFAULT 'warning',
comparison ENUM('<', '>', '<=', '>=', '=', '!=') DEFAULT '<',
threshold_value DECIMAL(18,4) NOT NULL,
duration_seconds INT DEFAULT 0,
message_template VARCHAR(255) NOT NULL,
icon VARCHAR(10) DEFAULT '⚠️',
is_active TINYINT(1) DEFAULT 1,
display_alert TINYINT(1) DEFAULT 1,
created_by VARCHAR(100) NULL,
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
INDEX idx_tag_name (tag_name),
INDEX idx_is_active (is_active)
)";
mysqli_query($alertsConn, $createTable);
$message = '';
$messageType = '';
// Handle form submissions
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
$action = $_POST['action'] ?? '';
switch ($action) {
case 'add':
$tagName = trim($_POST['tag_name'] ?? '');
$alertType = $_POST['alert_type'] ?? 'warning';
$comparison = $_POST['comparison'] ?? '<';
$threshold = floatval($_POST['threshold_value'] ?? 0);
$duration = intval($_POST['duration_seconds'] ?? 0);
$messageTemplate = trim($_POST['message_template'] ?? '');
$icon = trim($_POST['icon'] ?? '⚠️');
$displayAlert = isset($_POST['display_alert']) ? 1 : 0;
$createdBy = $_SESSION['SESS_FIRST_NAME'] ?? 'Unknown';
if ($tagName && $messageTemplate) {
$stmt = mysqli_prepare($alertsConn,
"INSERT INTO alert_definitions
(tag_name, alert_type, comparison, threshold_value, duration_seconds,
message_template, icon, display_alert, created_by)
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)"
);
mysqli_stmt_bind_param($stmt, 'sssdissis',
$tagName, $alertType, $comparison, $threshold, $duration,
$messageTemplate, $icon, $displayAlert, $createdBy
);
if (mysqli_stmt_execute($stmt)) {
$message = "Alert added successfully!";
$messageType = 'success';
} else {
$message = "Error adding alert: " . mysqli_error($alertsConn);
$messageType = 'error';
}
mysqli_stmt_close($stmt);
} else {
$message = "Tag name and message are required.";
$messageType = 'error';
}
break;
case 'update':
$id = intval($_POST['id'] ?? 0);
$tagName = trim($_POST['tag_name'] ?? '');
$alertType = $_POST['alert_type'] ?? 'warning';
$comparison = $_POST['comparison'] ?? '<';
$threshold = floatval($_POST['threshold_value'] ?? 0);
$duration = intval($_POST['duration_seconds'] ?? 0);
$messageTemplate = trim($_POST['message_template'] ?? '');
$icon = trim($_POST['icon'] ?? '⚠️');
$isActive = isset($_POST['is_active']) ? 1 : 0;
$displayAlert = isset($_POST['display_alert']) ? 1 : 0;
if ($id && $tagName && $messageTemplate) {
$stmt = mysqli_prepare($alertsConn,
"UPDATE alert_definitions SET
tag_name = ?, alert_type = ?, comparison = ?, threshold_value = ?,
duration_seconds = ?, message_template = ?, icon = ?,
is_active = ?, display_alert = ?
WHERE id = ?"
);
mysqli_stmt_bind_param($stmt, 'sssdiasiii',
$tagName, $alertType, $comparison, $threshold, $duration,
$messageTemplate, $icon, $isActive, $displayAlert, $id
);
if (mysqli_stmt_execute($stmt)) {
$message = "Alert updated successfully!";
$messageType = 'success';
} else {
$message = "Error updating alert: " . mysqli_error($alertsConn);
$messageType = 'error';
}
mysqli_stmt_close($stmt);
}
break;
case 'delete':
$id = intval($_POST['id'] ?? 0);
if ($id) {
$stmt = mysqli_prepare($alertsConn, "DELETE FROM alert_definitions WHERE id = ?");
mysqli_stmt_bind_param($stmt, 'i', $id);
if (mysqli_stmt_execute($stmt)) {
$message = "Alert deleted!";
$messageType = 'success';
} else {
$message = "Error deleting alert.";
$messageType = 'error';
}
mysqli_stmt_close($stmt);
}
break;
case 'toggle':
$id = intval($_POST['id'] ?? 0);
if ($id) {
mysqli_query($alertsConn, "UPDATE alert_definitions SET is_active = NOT is_active WHERE id = $id");
$message = "Alert toggled!";
$messageType = 'success';
}
break;
}
}
// Fetch all alerts
$alerts = [];
$result = mysqli_query($alertsConn, "SELECT * FROM alert_definitions ORDER BY is_active DESC, tag_name ASC");
while ($row = mysqli_fetch_assoc($result)) {
$alerts[] = $row;
}
// Fetch available tags for autocomplete
$tags = [];
$tagResult = mysqli_query($alertsConn, "SELECT DISTINCT Name FROM items ORDER BY Name");
while ($row = mysqli_fetch_assoc($tagResult)) {
$tags[] = $row['Name'];
}
// Layout config
$layoutWithoutSidebar = true;
$layoutReturnUrl = 'overview.php';
$layoutReturnLabel = 'Back to overview';
$assetBasePath = '';
include __DIR__ . '/includes/layout/header.php';
?>
<style>
.admin-container {
max-width: 1200px;
margin: 0 auto;
padding: 20px;
}
h1 {
color: var(--text);
margin-bottom: 20px;
font-size: 1.5rem;
}
.message {
padding: 12px 16px;
border-radius: 6px;
margin-bottom: 20px;
}
.message.success {
background: rgba(76, 175, 80, 0.2);
border: 1px solid #4caf50;
color: #4caf50;
}
.message.error {
background: rgba(244, 67, 54, 0.2);
border: 1px solid #f44336;
color: #f44336;
}
.add-form {
background: var(--surface);
border-radius: 8px;
padding: 20px;
margin-bottom: 30px;
border: 1px solid var(--border);
}
.add-form h2 {
color: var(--text);
font-size: 1.1rem;
margin-bottom: 15px;
}
.form-grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
gap: 15px;
}
.form-group {
display: flex;
flex-direction: column;
gap: 5px;
}
.form-group.full-width {
grid-column: 1 / -1;
}
.form-group label {
font-size: 0.8rem;
color: var(--text-muted, #888);
}
.form-group input,
.form-group select {
background: var(--surface-alt, #2a2a4a);
border: 1px solid var(--border);
border-radius: 4px;
padding: 8px 12px;
color: var(--text);
font-size: 0.9rem;
}
.form-group input:focus,
.form-group select:focus {
outline: none;
border-color: var(--accent);
}
.form-actions {
margin-top: 15px;
display: flex;
gap: 10px;
}
.btn {
padding: 8px 16px;
border: none;
border-radius: 4px;
cursor: pointer;
font-size: 0.9rem;
transition: opacity 0.2s;
}
.btn:hover {
opacity: 0.8;
}
.btn-primary {
background: var(--accent, #3b82f6);
color: #fff;
}
.btn-danger {
background: #f44336;
color: #fff;
}
.btn-secondary {
background: #666;
color: #fff;
}
.btn-sm {
padding: 4px 10px;
font-size: 0.8rem;
}
.alerts-table {
width: 100%;
border-collapse: collapse;
background: var(--surface);
border-radius: 8px;
overflow: hidden;
}
.alerts-table th,
.alerts-table td {
padding: 12px;
text-align: left;
border-bottom: 1px solid var(--border);
}
.alerts-table th {
background: var(--surface-alt, #2a2a4a);
color: var(--text);
font-weight: 600;
font-size: 0.8rem;
text-transform: uppercase;
}
.alerts-table tr:hover {
background: rgba(255, 255, 255, 0.03);
}
.alerts-table tr.inactive {
opacity: 0.5;
}
.tag-badge {
font-family: monospace;
background: var(--surface-alt, #2a2a4a);
padding: 4px 8px;
border-radius: 4px;
font-size: 0.85rem;
}
.type-badge {
display: inline-block;
padding: 2px 8px;
border-radius: 10px;
font-size: 0.75rem;
font-weight: 600;
}
.type-badge.danger {
background: rgba(244, 67, 54, 0.2);
color: #f44336;
}
.type-badge.warning {
background: rgba(255, 152, 0, 0.2);
color: #ff9800;
}
.type-badge.info {
background: rgba(33, 150, 243, 0.2);
color: #2196f3;
}
.condition-cell {
font-family: monospace;
font-size: 0.85rem;
}
.actions-cell {
display: flex;
gap: 6px;
flex-wrap: wrap;
}
.status-toggle {
cursor: pointer;
}
.edit-row {
display: none;
background: var(--surface-alt, #2a2a4a);
}
.edit-row.active {
display: table-row;
}
.edit-form {
padding: 15px;
}
.checkbox-group {
display: flex;
align-items: center;
gap: 8px;
}
.checkbox-group input[type="checkbox"] {
width: 18px;
height: 18px;
}
.help-text {
font-size: 0.75rem;
color: var(--text-muted, #666);
margin-top: 3px;
}
</style>
<div class="admin-container">
<h1>🔔 Alerts Admin</h1>
<?php if ($message): ?>
<div class="message <?= $messageType ?>"><?= htmlspecialchars($message) ?></div>
<?php endif; ?>
<!-- Add New Alert Form -->
<div class="add-form">
<h2> Add New Alert</h2>
<form method="POST">
<input type="hidden" name="action" value="add">
<div class="form-grid">
<div class="form-group">
<label>Tag Name</label>
<input type="text" name="tag_name" list="tag-list" required
placeholder="e.g., HouseAirPressure">
<datalist id="tag-list">
<?php foreach ($tags as $tag): ?>
<option value="<?= htmlspecialchars($tag) ?>">
<?php endforeach; ?>
</datalist>
</div>
<div class="form-group">
<label>Alert Type</label>
<select name="alert_type">
<option value="danger">🔴 Danger (Red)</option>
<option value="warning" selected>🟠 Warning (Orange)</option>
<option value="info">🔵 Info (Log only)</option>
</select>
</div>
<div class="form-group">
<label>Comparison</label>
<select name="comparison">
<option value="<">Less than (&lt;)</option>
<option value="<=">Less or equal (≤)</option>
<option value=">">Greater than (&gt;)</option>
<option value=">=">Greater or equal (≥)</option>
<option value="=">Equal to (=)</option>
<option value="!=">Not equal (≠)</option>
</select>
</div>
<div class="form-group">
<label>Threshold Value</label>
<input type="number" name="threshold_value" step="0.0001" required
placeholder="e.g., 75">
</div>
<div class="form-group">
<label>Duration (seconds)</label>
<input type="number" name="duration_seconds" value="0" min="0">
<div class="help-text">0 = trigger immediately</div>
</div>
<div class="form-group">
<label>Icon</label>
<select name="icon">
<option value="⚠️">⚠️ Warning</option>
<option value="🔴">🔴 Red Circle</option>
<option value="🚨">🚨 Siren</option>
<option value="⛔">⛔ Stop</option>
<option value="🔥">🔥 Fire</option>
<option value="❄️">❄️ Cold</option>
<option value="💧">💧 Water</option>
<option value="⚡">⚡ Electric</option>
<option value="🛑">🛑 Stop Sign</option>
<option value=""> Info</option>
</select>
</div>
<div class="form-group full-width">
<label>Message Template</label>
<input type="text" name="message_template" required
placeholder="e.g., LOW PRESSURE: {value} PSI (Threshold: {threshold})">
<div class="help-text">Use {value} for current value, {threshold} for threshold</div>
</div>
<div class="form-group">
<label>&nbsp;</label>
<div class="checkbox-group">
<input type="checkbox" name="display_alert" id="display_alert_new" checked>
<label for="display_alert_new">Display on page</label>
</div>
<div class="help-text">Unchecked = log only</div>
</div>
</div>
<div class="form-actions">
<button type="submit" class="btn btn-primary">Add Alert</button>
</div>
</form>
</div>
<!-- Existing Alerts Table -->
<h2 style="color: var(--text); margin-bottom: 15px;">📋 Active Alerts (<?= count($alerts) ?>)</h2>
<?php if (empty($alerts)): ?>
<p style="color: var(--text-muted);">No alerts defined yet. Add one above!</p>
<?php else: ?>
<table class="alerts-table">
<thead>
<tr>
<th>Tag</th>
<th>Type</th>
<th>Condition</th>
<th>Duration</th>
<th>Message</th>
<th>Display</th>
<th>Status</th>
<th>Actions</th>
</tr>
</thead>
<tbody>
<?php foreach ($alerts as $alert): ?>
<tr class="<?= $alert['is_active'] ? '' : 'inactive' ?>" id="row-<?= $alert['id'] ?>">
<td><span class="tag-badge"><?= htmlspecialchars($alert['tag_name']) ?></span></td>
<td>
<span class="type-badge <?= $alert['alert_type'] ?>">
<?= $alert['icon'] ?> <?= strtoupper($alert['alert_type']) ?>
</span>
</td>
<td class="condition-cell">
<?= htmlspecialchars($alert['comparison']) ?> <?= $alert['threshold_value'] ?>
</td>
<td><?= $alert['duration_seconds'] ?>s</td>
<td style="max-width: 200px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;">
<?= htmlspecialchars($alert['message_template']) ?>
</td>
<td><?= $alert['display_alert'] ? '✅' : '📝' ?></td>
<td>
<form method="POST" style="display: inline;">
<input type="hidden" name="action" value="toggle">
<input type="hidden" name="id" value="<?= $alert['id'] ?>">
<button type="submit" class="btn btn-sm <?= $alert['is_active'] ? 'btn-primary' : 'btn-secondary' ?>">
<?= $alert['is_active'] ? 'ON' : 'OFF' ?>
</button>
</form>
</td>
<td>
<div class="actions-cell">
<button type="button" class="btn btn-sm btn-secondary"
onclick="toggleEdit(<?= $alert['id'] ?>)">Edit</button>
<form method="POST" style="display: inline;"
onsubmit="return confirm('Delete this alert?');">
<input type="hidden" name="action" value="delete">
<input type="hidden" name="id" value="<?= $alert['id'] ?>">
<button type="submit" class="btn btn-sm btn-danger">×</button>
</form>
</div>
</td>
</tr>
<tr class="edit-row" id="edit-<?= $alert['id'] ?>">
<td colspan="8">
<form method="POST" class="edit-form">
<input type="hidden" name="action" value="update">
<input type="hidden" name="id" value="<?= $alert['id'] ?>">
<div class="form-grid">
<div class="form-group">
<label>Tag Name</label>
<input type="text" name="tag_name" list="tag-list" required
value="<?= htmlspecialchars($alert['tag_name']) ?>">
</div>
<div class="form-group">
<label>Alert Type</label>
<select name="alert_type">
<option value="danger" <?= $alert['alert_type'] === 'danger' ? 'selected' : '' ?>>
🔴 Danger
</option>
<option value="warning" <?= $alert['alert_type'] === 'warning' ? 'selected' : '' ?>>
🟠 Warning
</option>
<option value="info" <?= $alert['alert_type'] === 'info' ? 'selected' : '' ?>>
🔵 Info
</option>
</select>
</div>
<div class="form-group">
<label>Comparison</label>
<select name="comparison">
<option value="<" <?= $alert['comparison'] === '<' ? 'selected' : '' ?>>
Less than (&lt;)
</option>
<option value="<=" <?= $alert['comparison'] === '<=' ? 'selected' : '' ?>>
Less or equal (≤)
</option>
<option value=">" <?= $alert['comparison'] === '>' ? 'selected' : '' ?>>
Greater than (&gt;)
</option>
<option value=">=" <?= $alert['comparison'] === '>=' ? 'selected' : '' ?>>
Greater or equal (≥)
</option>
<option value="=" <?= $alert['comparison'] === '=' ? 'selected' : '' ?>>
Equal to (=)
</option>
<option value="!=" <?= $alert['comparison'] === '!=' ? 'selected' : '' ?>>
Not equal (≠)
</option>
</select>
</div>
<div class="form-group">
<label>Threshold</label>
<input type="number" name="threshold_value" step="0.0001" required
value="<?= $alert['threshold_value'] ?>">
</div>
<div class="form-group">
<label>Duration (sec)</label>
<input type="number" name="duration_seconds" min="0"
value="<?= $alert['duration_seconds'] ?>">
</div>
<div class="form-group">
<label>Icon</label>
<select name="icon">
<?php
$icons = ['⚠️', '🔴', '🚨', '⛔', '🔥', '❄️', '💧', '⚡', '🛑', ''];
foreach ($icons as $ico):
?>
<option value="<?= $ico ?>" <?= $alert['icon'] === $ico ? 'selected' : '' ?>>
<?= $ico ?>
</option>
<?php endforeach; ?>
</select>
</div>
<div class="form-group full-width">
<label>Message Template</label>
<input type="text" name="message_template" required
value="<?= htmlspecialchars($alert['message_template']) ?>">
</div>
<div class="form-group">
<div class="checkbox-group">
<input type="checkbox" name="is_active"
id="active-<?= $alert['id'] ?>"
<?= $alert['is_active'] ? 'checked' : '' ?>>
<label for="active-<?= $alert['id'] ?>">Active</label>
</div>
</div>
<div class="form-group">
<div class="checkbox-group">
<input type="checkbox" name="display_alert"
id="display-<?= $alert['id'] ?>"
<?= $alert['display_alert'] ? 'checked' : '' ?>>
<label for="display-<?= $alert['id'] ?>">Display on page</label>
</div>
</div>
</div>
<div class="form-actions">
<button type="submit" class="btn btn-primary">Save Changes</button>
<button type="button" class="btn btn-secondary"
onclick="toggleEdit(<?= $alert['id'] ?>)">Cancel</button>
</div>
</form>
</td>
</tr>
<?php endforeach; ?>
</tbody>
</table>
<?php endif; ?>
</div>
<script>
function toggleEdit(id) {
const editRow = document.getElementById('edit-' + id);
editRow.classList.toggle('active');
}
</script>
<?php
mysqli_close($alertsConn);
include __DIR__ . '/includes/layout/footer.php';
?>