- Get link
- X
- Other Apps
SOURCE CODE:
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>JSON Dashboard - Light Theme</title>
<style>
body {
font-family: Arial, sans-serif;
padding: 20px;
background: #f9fafb;
color: #333;
}
/* ---------- Boxes / Sections ---------- */
.box {
border-radius: 8px;
background: #ffffff;
box-shadow: 0 2px 6px rgba(0,0,0,0.1);
padding: 20px;
margin-bottom: 25px;
}
.box h3 {
margin-top: 0;
font-size: 18px;
background: #e3f2fd;
color: #0d47a1;
padding: 8px 12px;
border-radius: 6px;
}
/* ---------- Forms ---------- */
form input, form select, form button {
margin: 5px;
padding: 6px 10px;
border-radius: 4px;
border: 1px solid #ccc;
}
form button {
background: #1976d2;
color: #fff;
border: none;
cursor: pointer;
}
form button:hover { background: #1565c0; }
select[multiple] {
height:100px;
width:200px;
border: 1px solid #ccc;
}
/* ---------- Scrollable Table Container ---------- */
.table-container {
overflow-x:auto;
overflow-y:auto;
width:100%;
height:300px;
margin-top:10px;
border-radius: 6px;
border: 1px solid #ddd;
}
/* ---------- Table Styling ---------- */
table {
border-collapse: collapse;
white-space: nowrap;
min-width: 100%;
}
table th, table td {
border: 1px solid #ddd;
padding: 8px 12px;
text-align: left;
}
th {
cursor:pointer;
background-color:#e8f0fe;
position: sticky;
top: 0;
z-index: 2;
}
tr:nth-child(even) { background: #f6f8fa; }
/* ---------- Flash highlight ---------- */
tr.new { background-color: #d0f0c0; animation: blinkNew 2s ease; }
tr.edited { background-color: #fff4b3; animation: blinkEdit 2s ease; }
@keyframes blinkNew {0%,100%{background:#d0f0c0;}50%{background:#fff;}}
@keyframes blinkEdit {0%,100%{background:#fff4b3;}50%{background:#fff;}}
/* ---------- Output / Input buttons ---------- */
button#exportJSON, button#exportCSV {
background: #4caf50;
color: #fff;
border: none;
padding: 6px 12px;
border-radius: 4px;
margin-right: 8px;
cursor: pointer;
}
button#exportJSON:hover, button#exportCSV:hover { background: #388e3c; }
</style>
</head>
<body>
<!-- ==================== 1) CRUD SECTION ==================== -->
<div class="box">
<h3>ADD / EDIT / DELETE</h3>
<form id="addForm">
<input type="hidden" name="edit_id" value="">
<input type="text" name="name" placeholder="Item Name" required>
<input type="text" name="value" placeholder="Value" required>
<input type="text" name="user_id" placeholder="User ID" required>
<select name="status">
<option value="active">Active</option>
<option value="inactive">Inactive</option>
</select>
<button type="submit">Add Item</button>
<button type="button" id="cancelEdit" style="display:none;">Cancel Edit</button>
</form>
</div>
<!-- ==================== 2) INPUT - DATA (ALL) - OUTPUT ==================== -->
<div class="box">
<h3>ALL DATA<hr>BATCH INPUT and BATCH OUTPUT</h3>
<div>
<h4>INPUT</h4>
<input type="file" id="importFile" accept=".json">
</div>
<div>
<h4>DATA (ALL)</h4>
<div class="table-container">
<table id="resultsTable">
<thead>
<tr>
<th data-column="id">ID</th>
<th data-column="name">Name</th>
<th data-column="value">Value</th>
<th data-column="user_id">User ID</th>
<th data-column="status">Status</th>
<th data-column="created_at">Created At</th>
<th>Actions</th>
</tr>
</thead>
<tbody id="resultsBody"></tbody>
</table>
</div>
<div style="margin-top:10px;">
<h4>OUTPUT</h4>
<button id="exportJSON">Export JSON</button>
<button id="exportCSV">Export CSV</button>
</div>
</div>
<br>
<hr>
<!-- ==================== 3) Filter Inputs - Data Result ==================== -->
<div class="box">
<h3>AUTO-REFRESH<br>QUERY SCOPING</h3>
<div class="filter-group">
<h4>Filter Options</h4>
<select id="filterName" multiple></select>
<select id="filterUser" multiple></select>
<select id="filterStatus" multiple></select>
<select id="filterValue" multiple></select>
</div>
<div id="filteredCounter" style="margin-bottom:5px; font-weight:bold;">Filtered Rows: 0 / 0</div>
<div class="table-container">
<table class="output-table">
<thead>
<tr>
<th>ID</th>
<th>Name</th>
<th>Value</th>
<th>User ID</th>
<th>Status</th>
<th>Created At</th>
</tr>
</thead>
<tbody id="filteredBody"></tbody>
</table>
</div>
<hr>
</div>
<script>
// ---------- Sample Database ----------
let database=[
{id:1,user_id:"123",name:"Item A",value:100,status:"active",created_at:"2026-03-24 10:00:00"},
{id:2,user_id:"123",name:"Item B",value:200,status:"active",created_at:"2026-03-24 10:05:00"},
{id:3,user_id:"456",name:"Item C",value:150,status:"inactive",created_at:"2026-03-24 09:50:00"}
];
let previousIds=new Set(), editedIds=new Set(), sortConfig={column:"id",asc:true};
// ---------- Display Main Table ----------
function displayMainTable(scroll=true){
let data=database.slice();
data.sort((a,b)=>sortConfig.asc?(a[sortConfig.column]<b[sortConfig.column]?-1:1):(a[sortConfig.column]<b[sortConfig.column]?1:-1));
let tbody='';
data.forEach(r=>{
const isNew=!previousIds.has(r.id), isEdited=editedIds.has(r.id);
if(isNew) previousIds.add(r.id);
tbody+=`<tr class="${isNew?'new':isEdited?'edited':''}">
<td>${r.id}</td><td>${r.name}</td><td>${r.value}</td><td>${r.user_id}</td>
<td>${r.status}</td><td>${r.created_at}</td>
<td><button onclick="editItem(${r.id})">Edit</button>
<button onclick="deleteItem(${r.id})">Delete</button></td></tr>`;
});
document.getElementById('resultsBody').innerHTML=tbody;
if(scroll) document.getElementById('resultsBody').parentElement.scrollTop=document.getElementById('resultsBody').parentElement.scrollHeight;
setTimeout(()=>{ editedIds.clear(); },2000);
}
// ---------- Populate Filters ----------
function populateFilters(){
const uniqueValues = (key) => [...new Set(database.map(r=>r[key]))].sort();
const fName=document.getElementById('filterName'); fName.innerHTML=''; uniqueValues('name').forEach(v=>{fName.innerHTML+=`<option value="${v}">${v}</option>`});
const fUser=document.getElementById('filterUser'); fUser.innerHTML=''; uniqueValues('user_id').forEach(v=>{fUser.innerHTML+=`<option value="${v}">${v}</option>`});
const fStatus=document.getElementById('filterStatus'); fStatus.innerHTML=''; uniqueValues('status').forEach(v=>{fStatus.innerHTML+=`<option value="${v}">${v}</option>`});
const fValue=document.getElementById('filterValue'); fValue.innerHTML=''; uniqueValues('value').forEach(v=>{fValue.innerHTML+=`<option value="${v}">${v}</option>`});
}
// ---------- Get Selected Values ----------
function getSelectedValues(selectEl){return [...selectEl.selectedOptions].map(o=>o.value);}
// ---------- Filtered Output ----------
function displayFilteredOutput(){
const selectedNames=getSelectedValues(document.getElementById('filterName'));
const selectedUsers=getSelectedValues(document.getElementById('filterUser'));
const selectedStatus=getSelectedValues(document.getElementById('filterStatus'));
const selectedValues=getSelectedValues(document.getElementById('filterValue'));
let filtered=database.filter(r=>{
return (selectedNames.length===0||selectedNames.includes(r.name)) &&
(selectedUsers.length===0||selectedUsers.includes(r.user_id)) &&
(selectedStatus.length===0||selectedStatus.includes(r.status)) &&
(selectedValues.length===0||selectedValues.includes(r.value.toString()));
});
document.getElementById('filteredCounter').textContent=`Filtered Rows: ${filtered.length} / ${database.length}`;
const tbody=document.getElementById('filteredBody');
tbody.innerHTML=filtered.map(r=>`<tr>
<td>${r.id}</td><td>${r.name}</td><td>${r.value}</td><td>${r.user_id}</td>
<td>${r.status}</td><td>${r.created_at}</td>
</tr>`).join('');
}
// ---------- Add/Edit ----------
const addForm=document.getElementById('addForm'), cancelEditBtn=document.getElementById('cancelEdit');
addForm.addEventListener('submit',function(e){
e.preventDefault(); const f=e.target; const editId=f.edit_id.value;
const newItem={id:editId?parseInt(editId):database.length+1,user_id:f.user_id.value,name:f.name.value,value:parseFloat(f.value.value),status:f.status.value,created_at:new Date().toISOString().slice(0,19).replace("T"," ")};
if(editId){ const idx=database.findIndex(r=>r.id===parseInt(editId)); database[idx]=newItem; editedIds.add(newItem.id);}
else database.push(newItem);
f.reset(); f.edit_id=''; cancelEditBtn.style.display='none';
populateFilters(); displayMainTable(); displayFilteredOutput();
});
cancelEditBtn.addEventListener('click',()=>{addForm.reset(); addForm.edit_id=''; cancelEditBtn.style.display='none';});
// ---------- Edit/Delete ----------
function editItem(id){const r=database.find(r=>r.id===id); addForm.edit_id.value=r.id; addForm.name.value=r.name; addForm.value.value=r.value; addForm.user_id.value=r.user_id; addForm.status.value=r.status; cancelEditBtn.style.display='inline';}
function deleteItem(id){if(confirm("Delete this item?")){database=database.filter(r=>r.id!==id); previousIds.delete(id); editedIds.delete(id); populateFilters(); displayMainTable(); displayFilteredOutput();}}
// ---------- Sorting ----------
document.querySelectorAll('th[data-column]').forEach(th=>{th.addEventListener('click',()=>{
const col=th.dataset.column;
sortConfig.column===col?sortConfig.asc=!sortConfig.asc:sortConfig={column:col,asc:true};
displayMainTable();
});});
// ---------- Filters Event ----------
['filterName','filterUser','filterStatus','filterValue'].forEach(id=>{
document.getElementById(id).addEventListener('change', displayFilteredOutput);
});
// ---------- Export JSON & CSV ----------
document.getElementById('exportJSON').addEventListener('click',()=>{
const dataStr="data:text/json;charset=utf-8,"+encodeURIComponent(JSON.stringify(database,null,2));
const dl=document.createElement('a'); dl.href=dataStr; dl.download='database.json'; dl.click();
});
document.getElementById('exportCSV').addEventListener('click',()=>{
const rows=database.map(r=>[r.id,r.name,r.value,r.user_id,r.status,r.created_at]);
const csvContent="data:text/csv;charset=utf-8,"+["ID,Name,Value,UserID,Status,CreatedAt",...rows.map(r=>r.join(","))].join("\n");
const dl=document.createElement('a'); dl.href=csvContent; dl.download='database.csv'; dl.click();
});
// ---------- Safe Merge-Import ----------
document.getElementById('importFile').addEventListener('change',function(e){
const f=e.target.files[0]; if(!f) return;
const reader=new FileReader();
reader.onload=function(evt){
try{
const imp=JSON.parse(evt.target.result); if(!Array.isArray(imp)){alert("Invalid JSON"); return;}
let maxId=Math.max(...database.map(r=>r.id),0);
imp.forEach(item=>{if(!item.id)item.id=++maxId; else if(database.some(r=>r.id===item.id)) item.id=++maxId; database.push(item); editedIds.add(item.id);});
populateFilters(); displayMainTable(); displayFilteredOutput(); alert("Data imported safely!");
}catch(err){alert("Error parsing JSON");}
}; reader.readAsText(f);
});
// ---------- Auto-refresh ----------
setInterval(()=>{displayMainTable(false); displayFilteredOutput();},5000);
// ---------- Initial Display ----------
populateFilters(); displayMainTable(); displayFilteredOutput();
</script>
</body>
</html>
Comments