<?php
require_once '/home/www/GNU/_PAGE/head.php';
/**
* @name Maria DB Premium Dashboard V10 - Precision Layout
* @desc 구조 유지 + 설명 편집 로직 유지 + 수정 버튼 컬럼 최소화 및 우측 배치
*/
error_reporting(E_ALL);
ini_set('display_errors', 1);
// 1. DB 연결 (기존 로직 유지)
$ROOT = "/home/www";
$db_info_path = $ROOT . "/DB/db_upbit.php";
if (file_exists($db_info_path)) {
require_once $db_info_path;
}
if (!isset($db_upbit)) { exit("DB 연결 실패"); }
$pdo = $db_upbit;
// 2. 설명(Comment) 편집 로직 (기존 로직 유지)
if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['action']) && $_POST['action'] === 'update_comment') {
$eventName = $_POST['event_name'];
$newComment = $_POST['new_comment'];
$sql = "ALTER EVENT `$eventName` COMMENT ?";
$stmt = $pdo->prepare($sql);
$stmt->execute([$newComment]);
header("Location: " . $_SERVER['PHP_SELF']);
exit;
}
// 3. 스마트 볼륨 탐색 엔진 (기존 로직 유지)
function get_smart_disk_info() {
exec('df -P', $output);
$oldboy = null; $maria = null;
foreach ($output as $line) {
if (preg_match('/^(\/\S+)\s+(\d+)\s+(\d+)\s+(\d+)\s+(\d+)%\s+(\/.*)$/', $line, $m)) {
$path = $m[6];
$total_gb = round($m[2] / (1024 * 1024), 2);
$used_gb = round($m[3] / (1024 * 1024), 2);
$percent = $m[5];
if ($path === '/') {
$oldboy = ['label' => 'Oldboy (OS Root)', 'total' => $total_gb, 'used' => $used_gb, 'percent' => $percent, 'path' => '/'];
}
if ($total_gb > 150 && $total_gb < 250) {
$maria = ['label' => 'Maria (Storage)', 'total' => $total_gb, 'used' => $used_gb, 'percent' => $percent, 'path' => $path];
}
}
}
if (!$oldboy) $oldboy = ['label' => 'Oldboy (C:)', 'total' => 48.28, 'used' => 8.52, 'percent' => 17.6, 'path' => '/'];
if (!$maria) $maria = ['label' => 'Maria (D:)', 'total' => 200, 'used' => 0, 'percent' => 0, 'path' => 'Path Not Found'];
return [$oldboy, $maria];
}
$volumes = get_smart_disk_info();
require_once '/home/www/GNU/_PAGE/head.php';
?>
<title>Maria DB Dashboard v10 - Compact Actions</title>
<link href="https://fonts.googleapis.com/css2?family=Pretendard:wght@300;450;700&display=swap" rel="stylesheet">
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
<style>
:root {
--bg: #0d1117; --card: #161b22; --border: #30363d; --text: #e6edf3;
--accent: #58a6ff; --maria: #9d50bb; --accent-glow: rgba(88, 166, 255, 0.3);
}
@keyframes fadeInUp {
from { opacity: 0; transform: translateY(15px); }
to { opacity: 1; transform: translateY(0); }
}
@keyframes growWidth { from { width: 0; } }
body {
font-family: 'Pretendard', sans-serif; background: var(--bg); color: var(--text);
margin: 0; overflow-x: hidden;
}
.dictionary { padding:50px; }
.header {
display: flex; justify-content: space-between; align-items: center;
margin-bottom: 30px; padding: 15px 25px; background: var(--card);
border-radius: 12px; border: 1px solid var(--border); animation: fadeInUp 0.5s ease-out;
}
h1 { color: #3ecbf6; font-size:30px; padding: 10px; }
h1 i { font-size:30px; padding: 10px; }
.disk-grid { display: grid; grid-template-columns: repeat(2, 1fr); gap: 20px; margin-bottom: 30px; }
.card {
background: var(--card); border-radius: 16px; padding: 20px; border: 1px solid var(--border);
transition: 0.3s; animation: fadeInUp 0.7s ease-out both;
}
.card:hover { transform: translateY(-3px); border-color: var(--accent); box-shadow: 0 8px 20px rgba(0,0,0,0.4); }
.card.maria-vol { border-left: 5px solid var(--maria); }
.progress { height: 8px; background: #30363d; border-radius: 4px; margin: 15px 0; overflow: hidden; }
.progress-fill { height: 100%; border-radius: 4px; animation: growWidth 1s ease-out forwards; }
.table-container {
background: var(--card); border-radius: 16px; border: 1px solid var(--border);
overflow: hidden; animation: fadeInUp 0.9s ease-out both;
}
table { width: 100%; border-collapse: collapse; table-layout: fixed; }
th { background: #21262d; padding: 15px; text-align: left; font-size: 0.8rem; color: #8b949e; text-transform: uppercase; letter-spacing: 0.5px; }
td { padding: 16px 18px; border-bottom: 1px solid var(--border); vertical-align: middle; font-size: 0.95rem; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
/* 컬럼 폭 조정: 수정 버튼 컬럼 축소 및 우측 배치 */
.col-comment { width: 55%; }
.col-name { width: 15%; }
.col-status { width: 10%; text-align: center; }
.col-interval { width: 12%; }
.col-edit { width: 8%; text-align: right; } /* 폭을 줄이고 우측 정렬 */
.badge-base { display: inline-block; padding: 2px 8px; border-radius: 4px; font-weight: 700; font-size: 0.7rem; margin-right: 8px; }
.prefix-badge { background: rgba(88, 166, 255, 0.15); color: var(--accent); border: 1px solid rgba(88, 166, 255, 0.3); }
.suffix-badge { background: rgba(157, 80, 187, 0.15); color: #d3adf7; border: 1px solid rgba(157, 80, 187, 0.3); }
.status-badge { padding: 4px 12px; border-radius: 20px; font-size: 0.75rem; font-weight: bold; }
.status-ENABLED { background: rgba(35, 134, 54, 0.2); color: #3fb950; border: 1px solid #238636; }
.status-DISABLED { background: rgba(248, 81, 73, 0.2); color: #f85149; border: 1px solid #da3633; }
.btn-edit {
background: #21262d; border: 1px solid var(--border); color: var(--text);
padding: 6px 12px; border-radius: 6px; cursor: pointer; font-size: 0.8rem; transition: 0.2s;
display: inline-flex; align-items: center; gap: 5px;
}
.btn-edit:hover { background: var(--accent); color: #fff; border-color: var(--accent); box-shadow: 0 0 10px var(--accent-glow); }
input#eventSearch { padding: 10px 15px; border-radius: 8px; border: 1px solid var(--border); background:#0d1117; color:#fff; width:300px; outline: none; transition: 0.3s; }
input#eventSearch:focus { border-color: var(--accent); box-shadow: 0 0 8px var(--accent-glow); }
code { color: #f6c23e; background: #0d1117; padding: 2px 6px; border-radius: 4px; font-family: 'Consolas', monospace; }
tr:hover td { background: rgba(255,255,255,0.02); }
/* 전체 스크롤바 스타일 */
::-webkit-scrollbar { width: 10px; }
::-webkit-scrollbar-track { background: #0d1117; }
::-webkit-scrollbar-thumb { background: #30363d; border-radius: 7px; border: 2px solid #0d1117; }
::-webkit-scrollbar-thumb:hover { background: #8b949e; }
</style>
<div class="dictionary">
<div class="header">
<h1><i class="fa-solid fa-microchip"></i> DB EVENTS ENGINE V10</h1>
<div style="display:flex; gap:15px; align-items:center;">
<input type="text" id="eventSearch" placeholder="Search tasks...">
<a href="?" class="btn-edit" style="padding:10px 15px;"><i class="fa-solid fa-sync"></i></a>
</div>
</div>
<div class="disk-grid">
<?php foreach ($volumes as $idx => $v): ?>
<div class="card <?php echo $idx == 1 ? 'maria-vol' : ''; ?>" style="animation-delay: <?php echo $idx * 0.2; ?>s;">
<div style="font-size:0.85rem; color:#8b949e; font-weight:bold; display:flex; justify-content:space-between;">
<span><i class="fa-solid fa-database"></i> <?php echo $v['label']; ?></span>
<span><?php echo $v['percent']; ?>%</span>
</div>
<div style="font-size:1.8rem; font-weight:800; margin:10px 0;">
<?php echo $v['used']; ?> <small style="font-size:0.9rem;">GB</small> / <?php echo $v['total']; ?> <small style="font-size:0.9rem;">GB</small>
</div>
<div class="progress"><div class="progress-fill" style="width:<?php echo $v['percent']; ?>%; background:<?php echo $idx == 1 ? 'var(--maria)' : 'var(--accent)'; ?>;"></div></div>
</div>
<?php endforeach; ?>
</div>
<div class="table-container">
<table id="eventTable">
<thead>
<tr>
<th class="col-comment">Objective Description</th>
<th class="col-name">System Name</th>
<th class="col-status">Status</th>
<th class="col-interval">Interval</th>
<th class="col-edit">Action</th>
</tr>
</thead>
<tbody>
<?php
$query = "SELECT EVENT_COMMENT, EVENT_NAME, STATUS, INTERVAL_VALUE, INTERVAL_FIELD FROM INFORMATION_SCHEMA.EVENTS WHERE EVENT_SCHEMA = 'upbit_data' ORDER BY EVENT_NAME ASC";
$events = $pdo->query($query)->fetchAll(PDO::FETCH_ASSOC);
foreach ($events as $trIdx => $e):
?>
<tr style="animation: fadeInUp 0.5s ease-out both; animation-delay: <?php echo 0.6 + ($trIdx * 0.03); ?>s;">
<td title="<?php echo htmlspecialchars($e['EVENT_COMMENT']); ?>">
<?php
$comment = $e['EVENT_COMMENT'] ?: 'UNDEFINED_상세 설명 없음';
$parts = explode('_', $comment);
if (count($parts) >= 3) {
echo '<span class="badge-base prefix-badge">'.$parts[0].'</span>';
echo '<span style="font-weight:500;">'.implode('_', array_slice($parts, 1, -1)).'</span>';
echo '<span class="badge-base suffix-badge" style="margin-left:8px;">'.$parts[count($parts)-1].'</span>';
} else { echo $comment; }
?>
</td>
<td><code><?php echo $e['EVENT_NAME']; ?></code></td>
<td style="text-align:center;">
<span class="status-badge status-<?php echo $e['STATUS']; ?>"><?php echo $e['STATUS']; ?></span>
</td>
<td style="color:#8b949e; font-size:0.85rem;">Every <?php echo $e['INTERVAL_VALUE'].' '.$e['INTERVAL_FIELD']; ?></td>
<td class="col-edit">
<button class="btn-edit" onclick="editComment('<?php echo $e['EVENT_NAME']; ?>', '<?php echo $e['EVENT_COMMENT']; ?>')">
<i class="fa-solid fa-pen-nib"></i> EDIT
</button>
</td>
</tr>
<?php endforeach; ?>
</tbody>
</table>
</div>
<!-- 폼 유지 -->
<form id="editForm" method="POST" style="display:none;">
<input type="hidden" name="action" value="update_comment">
<input type="hidden" name="event_name" id="formEventName">
<input type="hidden" name="new_comment" id="formNewComment">
</form>
<script>
// 기존 편집 로직 유지
function editComment(name, oldVal) {
const newVal = prompt("수정할 작업 설명을 입력하세요:", oldVal);
if (newVal !== null && newVal !== oldVal) {
document.getElementById('formEventName').value = name;
document.getElementById('formNewComment').value = newVal;
document.getElementById('editForm').submit();
}
}
// 실시간 검색 로직 유지
document.getElementById('eventSearch').addEventListener('input', function() {
const val = this.value.toLowerCase();
document.querySelectorAll('#eventTable tbody tr').forEach(row => {
row.style.display = row.innerText.toLowerCase().includes(val) ? '' : 'none';
});
});
</script>
</div>
<?php require_once '/home/www/GNU/_PAGE/tail.php'; ?>