- Replace raw TOML textarea with Alpine.js interactive form editor (10 collapsible sections with change-tier badges, dynamic array management for connections/shares/ warmup rules, proper input controls per field type) - Add SSE-based live dashboard updates replacing htmx polling - Add log viewer tab with ring buffer backend and incremental polling - Fix SMB not seeing new shares after config reload: kill entire smbd process group (not just parent PID) so forked workers release port 445 - Add SIGHUP-based smbd config reload for share changes instead of full restart, preserving existing client connections - Generate human-readable commented TOML from config editor instead of bare toml::to_string_pretty() output - Fix Alpine.js 2.x __x.$data calls in dashboard/share templates (now Alpine 3.x) - Fix toggle switch CSS overlap with field labels - Fix dashboard going blank on tab switch (remove hx-swap-oob from tab content) - Add htmx:afterSettle → Alpine.initTree() bridge for robust tab switching Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
80 lines
3.2 KiB
HTML
80 lines
3.2 KiB
HTML
<div x-data="{ expanded: new URLSearchParams(location.search).get('expand') || '{{ expand }}' }">
|
|
<table class="share-table">
|
|
<thead>
|
|
<tr>
|
|
<th>Name</th>
|
|
<th>Health</th>
|
|
<th>Mount</th>
|
|
<th>Cache</th>
|
|
<th>Dirty</th>
|
|
<th>Speed</th>
|
|
<th>Transfers</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
{% for share in shares %}
|
|
<tr class="share-row" @click="expanded = expanded === '{{ share.name }}' ? '' : '{{ share.name }}'">
|
|
<td><strong>{{ share.name }}</strong></td>
|
|
<td>
|
|
{% if share.health == "OK" %}
|
|
<span class="badge badge-ok">OK</span>
|
|
{% elif share.health == "FAILED" %}
|
|
<span class="badge badge-error">FAILED</span>
|
|
{% elif share.health == "PROBING" %}
|
|
<span class="badge badge-warn">PROBING</span>
|
|
{% else %}
|
|
<span class="badge badge-warn">PENDING</span>
|
|
{% endif %}
|
|
{% if share.read_only %}
|
|
<span class="badge badge-ro">RO</span>
|
|
{% endif %}
|
|
</td>
|
|
<td class="mono">{{ share.mount_point }}</td>
|
|
<td>{{ share.cache_display }}</td>
|
|
<td>{{ share.dirty_count }}</td>
|
|
<td>{{ share.speed_display }}</td>
|
|
<td>{{ share.transfers }}</td>
|
|
</tr>
|
|
<tr x-show="expanded === '{{ share.name }}'" x-transition x-cloak class="detail-row">
|
|
<td colspan="7">
|
|
<div class="detail-panel">
|
|
<div class="detail-grid">
|
|
<div class="detail-card">
|
|
<div class="label">Cache Used</div>
|
|
<div class="value">{{ share.cache_display }}</div>
|
|
</div>
|
|
<div class="detail-card">
|
|
<div class="label">Dirty Files</div>
|
|
<div class="value">{{ share.dirty_count }}</div>
|
|
</div>
|
|
<div class="detail-card">
|
|
<div class="label">Transfer Speed</div>
|
|
<div class="value">{{ share.speed_display }}</div>
|
|
</div>
|
|
<div class="detail-card">
|
|
<div class="label">Active Transfers</div>
|
|
<div class="value">{{ share.transfers }}</div>
|
|
</div>
|
|
</div>
|
|
<table class="info-table">
|
|
<tr><td>Health</td><td>{{ share.health }}</td></tr>
|
|
{% if share.health == "FAILED" %}
|
|
<tr><td>Probe Error</td><td class="error-text">{{ share.health_message }}</td></tr>
|
|
{% endif %}
|
|
<tr><td>Connection</td><td class="mono">{{ share.connection }}</td></tr>
|
|
<tr><td>Mount Point</td><td class="mono">{{ share.mount_point }}</td></tr>
|
|
<tr><td>Remote Path</td><td class="mono">{{ share.remote_path }}</td></tr>
|
|
<tr><td>RC Port</td><td>{{ share.rc_port }}</td></tr>
|
|
<tr><td>Errored Files</td><td>{{ share.errored_files }}</td></tr>
|
|
<tr><td>Total Errors</td><td>{{ share.errors }}</td></tr>
|
|
<tr><td>Mounted</td><td>{% if share.mounted %}Yes{% else %}No{% endif %}</td></tr>
|
|
<tr><td>Read-Only</td><td>{% if share.read_only %}Yes{% else %}No{% endif %}</td></tr>
|
|
</table>
|
|
</div>
|
|
</td>
|
|
</tr>
|
|
{% endfor %}
|
|
</tbody>
|
|
</table>
|
|
</div>
|