mirror of
https://github.com/cesanta/mongoose.git
synced 2026-10-18 10:59:45 +00:00
Add file manager
This commit is contained in:
1 parent
8534053e57
commit
573bc152b1
10 files changed
+418
-98
No files matched your search
@@ -4,15 +4,17 @@
|
||||
<title>My Dashboard</title>
|
||||
|
||||
<!-- Mongoose device dashboard -->
|
||||
<script src="https://cdn.jsdelivr.net/gh/cesanta/mongoose@master/resources/dashboard.js"></script>
|
||||
<!--<script src="https://cdn.jsdelivr.net/gh/cesanta/mongoose@master/resources/dashboard.js"></script>-->
|
||||
<script src="dashboard.js"></script>
|
||||
<script>
|
||||
Dashboard.init({
|
||||
debug: true,
|
||||
data: {
|
||||
chart1: {data: ''},
|
||||
chart1: {data: []},
|
||||
leds: { led1: true, led2: false, led3: false },
|
||||
settings: { volume: 12, log_level: 3, name: 'Galway' },
|
||||
metrics: { temperature: 1.2, humidity: 3, cpu: 4, ram: 5 },
|
||||
files: {data: [{name: 'device-log-2026-04-25.txt', size: 8625563}]},
|
||||
},
|
||||
});
|
||||
</script>
|
||||
@@ -55,22 +57,21 @@
|
||||
</svg>
|
||||
Firmware Update
|
||||
</a>
|
||||
<a href="#events" id="tab-events" class="nav-link" role="tab" aria-controls="events" aria-selected="false" tabindex="-1">
|
||||
<a href="#files" id="tab-files" class="nav-link" role="tab" aria-controls="files" aria-selected="false" tabindex="-1">
|
||||
<svg viewBox="0 0 24 24" class="nav-icon" fill="none" stroke="currentColor" stroke-width="2">
|
||||
<path d="M8 7h8" />
|
||||
<path d="M8 12h8" />
|
||||
<path d="M8 17h5" />
|
||||
<rect x="4" y="4" width="16" height="16" rx="3" />
|
||||
<path d="M4 7a2 2 0 0 1 2-2h4l2 2h6a2 2 0 0 1 2 2v2H4Z" />
|
||||
<path d="M4 11h16v7a2 2 0 0 1-2 2H6a2 2 0 0 1-2-2Z" />
|
||||
<path d="M8 15h8" />
|
||||
</svg>
|
||||
Event Log
|
||||
File Manager
|
||||
</a>
|
||||
</nav>
|
||||
</div>
|
||||
<div class="header-actions">
|
||||
<div class="connection-badge" aria-label="connection active">
|
||||
<span class="connection-label">live</span>
|
||||
<span class="connection-dot" aria-hidden="true"></span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="header-actions">
|
||||
<nav class="nav-tabs">
|
||||
<div class="nav-link">
|
||||
<svg viewBox="0 0 24 24" class="nav-icon" fill="none" stroke="currentColor" stroke-width="2">
|
||||
@@ -205,14 +206,79 @@
|
||||
</div>
|
||||
</div>
|
||||
<div class="panel-footer">
|
||||
<button class="btn btn-secondary" type="button" data-cancel="settings">Cancel</button>
|
||||
<button class="btn btn-primary" type="button" data-save="settings">Save</button>
|
||||
<button class="btn btn-secondary" type="button" data-cancel="settings">
|
||||
<svg viewBox="0 0 24 24" class="nav-icon" fill="none" stroke="currentColor" stroke-width="2">
|
||||
<path d="M18 6 6 18" />
|
||||
<path d="m6 6 12 12" />
|
||||
</svg>
|
||||
Cancel
|
||||
</button>
|
||||
<button class="btn btn-primary" type="button" data-save="settings">
|
||||
<svg viewBox="0 0 24 24" class="nav-icon" fill="none" stroke="currentColor" stroke-width="2">
|
||||
<path d="M19 21H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h11l5 5v11a2 2 0 0 1-2 2Z" />
|
||||
<path d="M17 21v-8H7v8" />
|
||||
<path d="M7 3v5h8" />
|
||||
</svg>
|
||||
Save
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
<section id="firmware" class="tab-panel" role="tabpanel" aria-labelledby="tab-firmware" hidden></section>
|
||||
<section id="events" class="tab-panel" role="tabpanel" aria-labelledby="tab-events" hidden>
|
||||
<pre id="logs" class="file-content"></pre>
|
||||
<section id="files" class="tab-panel" role="tabpanel" aria-labelledby="tab-files" hidden>
|
||||
<div class="panel" style="max-width: 40rem;">
|
||||
<div class="panel-title">
|
||||
<span>
|
||||
<span>File Manager</span>
|
||||
<span class="metric-status">${files.data.length} Files</span>
|
||||
</span>
|
||||
<div class="header-actions">
|
||||
<label class="btn btn-primary">
|
||||
<svg viewBox="0 0 24 24" class="nav-icon" fill="none" stroke="currentColor" stroke-width="2">
|
||||
<path d="M12 3v12" />
|
||||
<path d="m7 8 5-5 5 5" />
|
||||
<path d="M5 21h14" />
|
||||
</svg>
|
||||
Upload
|
||||
<input type="file" hidden data-upload="1" />
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
<div class="panel-body">
|
||||
<div class="file-list" data-repeat="files.data" data-iterator="f">
|
||||
<div class="file-row">
|
||||
<div class="file-info">
|
||||
<span class="file-icon" aria-hidden="true">
|
||||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
||||
<path d="M14 2H7a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h10a2 2 0 0 0 2-2V7Z" />
|
||||
<path d="M14 2v5h5" />
|
||||
</svg>
|
||||
</span>
|
||||
<div class="file-name">${f.name}</div>
|
||||
</div>
|
||||
<div class="file-size">${f.size}</div>
|
||||
<div class="file-actions">
|
||||
<a onclick="window.open('files/${encodeURIComponent(f.name)}', '_blank')" target="_blank" class="btn btn-secondary">
|
||||
<svg viewBox="0 0 24 24" class="nav-icon" fill="none" stroke="currentColor" stroke-width="2">
|
||||
<path d="M12 3v12" />
|
||||
<path d="m7 10 5 5 5-5" />
|
||||
<path d="M5 21h14" />
|
||||
</svg>
|
||||
</a>
|
||||
<button onclick="fetch('files/${encodeURIComponent(f.name)}?action=delete'); return false;" class="btn btn-secondary">
|
||||
<svg viewBox="0 0 24 24" class="nav-icon" fill="none" stroke="currentColor" stroke-width="2">
|
||||
<path d="M3 6h18" />
|
||||
<path d="M8 6V4h8v2" />
|
||||
<path d="M19 6l-1 14H6L5 6" />
|
||||
<path d="M10 11v5" />
|
||||
<path d="M14 11v5" />
|
||||
</svg>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
</main>
|
||||
</body>
|
||||
|
||||
@@ -7,17 +7,17 @@
|
||||
</defs>
|
||||
|
||||
<!-- icon: two rounded rectangles -->
|
||||
<g fill="none" stroke="url(#g)" stroke-width="40" stroke-linecap="round" stroke-linejoin="round">
|
||||
<rect x="140" y="160" width="260" height="260" rx="70"/>
|
||||
<rect x="260" y="80" width="260" height="260" rx="70"/>
|
||||
<g fill="none" stroke="url(#g)" stroke-width="30" stroke-linecap="round" stroke-linejoin="round">
|
||||
<rect x="160" y="60" width="300" height="300" rx="70"/>
|
||||
<rect x="20" y="200" width="300" height="300" rx="70"/>
|
||||
</g>
|
||||
|
||||
<!-- text -->
|
||||
<text x="560" y="330"
|
||||
<text x="560" y="360"
|
||||
font-family="system-ui, -apple-system, Segoe UI, Roboto, sans-serif"
|
||||
font-size="160"
|
||||
font-size="180"
|
||||
font-weight="600"
|
||||
fill="#6b7280">
|
||||
my logo
|
||||
MyLogo
|
||||
</text>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 773 B After Width: | Height: | Size: 771 B |
@@ -73,7 +73,8 @@ document.addEventListener("DOMContentLoaded", () => {
|
||||
|
||||
function updateGraphPoints(data) {
|
||||
if (!data) return;
|
||||
const parsed = JSON.parse(data);
|
||||
// const parsed = JSON.parse(data);
|
||||
const parsed = data || [];
|
||||
const uplot_data = [
|
||||
parsed.map(x => x[0]),
|
||||
parsed.map(x => x[1]),
|
||||
@@ -87,7 +88,8 @@ document.addEventListener("DOMContentLoaded", () => {
|
||||
Dashboard.call('get', 'chart1').then(resp => updateGraphPoints(resp?.data));
|
||||
|
||||
// Show logs
|
||||
fetch('logs/')
|
||||
.then(resp => resp.text())
|
||||
.then(text => document.getElementById("logs").textContent = text);
|
||||
// fetch('logs/')
|
||||
// .then(resp => resp.text())
|
||||
// .then(text => document.getElementById("logs").textContent = text);
|
||||
|
||||
});
|
||||
@@ -44,7 +44,7 @@ body {
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
gap: var(--spacing-4);
|
||||
padding: var(--spacing-2) var(--spacing-6);
|
||||
padding: var(--spacing-3) var(--spacing-6);
|
||||
}
|
||||
|
||||
.header-left {
|
||||
@@ -93,7 +93,7 @@ body {
|
||||
gap: var(--spacing-2);
|
||||
background: rgb(248, 250, 252);
|
||||
border: 1px solid rgb(226, 232, 240);
|
||||
padding: calc(var(--spacing-1) + 2px);
|
||||
padding: var(--spacing-1) var(--spacing-2);
|
||||
border-radius: 1rem;
|
||||
box-shadow: rgba(0, 0, 0, 0) 0px 0px 0px 0px, rgba(0, 0, 0, 0) 0px 0px 0px 0px, rgba(0, 0, 0, 0.05) 0px 2px 4px 0px inset;
|
||||
}
|
||||
@@ -255,7 +255,7 @@ body {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: flex-end;
|
||||
gap: 0.5rem;
|
||||
gap: 0.75rem;
|
||||
padding: 0.75rem 1.25rem;
|
||||
border-top: 1px solid #e2e8f0;
|
||||
}
|
||||
@@ -335,11 +335,14 @@ body {
|
||||
.btn {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
padding: 0.42rem 1rem;
|
||||
font-size: 0.82rem;
|
||||
justify-content: center;
|
||||
gap: 0.5rem;
|
||||
height: 2rem;
|
||||
padding: 0.3rem 1rem;
|
||||
font-size: 0.85rem;
|
||||
font-family: inherit;
|
||||
font-weight: 600;
|
||||
border-radius: 0.55rem;
|
||||
border-radius: 0.5rem;
|
||||
border: 1px solid transparent;
|
||||
cursor: pointer;
|
||||
transition: all 0.15s ease;
|
||||
@@ -398,7 +401,7 @@ body {
|
||||
.panel {
|
||||
background: #ffffff;
|
||||
border: 1px solid rgba(203, 213, 225, 0.75);
|
||||
border-radius: 1rem;
|
||||
border-radius: 0.75rem;
|
||||
box-shadow:
|
||||
inset 0 1px 0 rgba(255, 255, 255, 1),
|
||||
0 2px 6px rgba(148, 163, 184, 0.1),
|
||||
@@ -415,7 +418,8 @@ body {
|
||||
font-size: 0.95rem;
|
||||
font-weight: 700;
|
||||
color: #334155;
|
||||
padding: 1rem 1.25rem 0.9rem;
|
||||
padding: 0 1rem;
|
||||
min-height: 3rem;
|
||||
border-bottom: 1px solid #e2e8f0;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
@@ -449,6 +453,80 @@ body {
|
||||
color: #64748b;
|
||||
}
|
||||
|
||||
/* File manager */
|
||||
|
||||
.file-list {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
.file-list:empty::before {
|
||||
content: "No Files";
|
||||
color: #888;
|
||||
}
|
||||
|
||||
.file-row {
|
||||
display: grid;
|
||||
grid-template-columns: minmax(0, 1fr) auto auto;
|
||||
align-items: center;
|
||||
gap: 1rem;
|
||||
padding: 0.82rem 0;
|
||||
border-top: 1px solid #edf2f7;
|
||||
}
|
||||
|
||||
.file-row:first-child {
|
||||
border-top: none;
|
||||
}
|
||||
|
||||
.file-info {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.75rem;
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
.file-icon {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
width: 2.25rem;
|
||||
height: 2.25rem;
|
||||
color: #0369a1;
|
||||
background: #e0f2fe;
|
||||
border: 1px solid #bae6fd;
|
||||
border-radius: 0.65rem;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.file-icon svg {
|
||||
width: 1.15rem;
|
||||
height: 1.15rem;
|
||||
}
|
||||
|
||||
.file-name {
|
||||
min-width: 0;
|
||||
color: #334155;
|
||||
font-size: 0.9rem;
|
||||
font-weight: 700;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.file-size {
|
||||
color: #94a3b8;
|
||||
font-size: 0.8rem;
|
||||
font-weight: 700;
|
||||
text-align: right;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.file-actions {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: flex-end;
|
||||
gap: 0.45rem;
|
||||
}
|
||||
|
||||
/* Chart */
|
||||
|
||||
.chart-panel {
|
||||
@@ -594,4 +672,20 @@ body {
|
||||
.overview-grid {
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
|
||||
.file-row {
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
|
||||
.file-actions {
|
||||
justify-content: flex-start;
|
||||
}
|
||||
|
||||
.file-row {
|
||||
gap: 0.65rem;
|
||||
}
|
||||
|
||||
.file-size {
|
||||
text-align: left;
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user