feat: drag-and-drop dashboard editing, alert dynamic fields

- Replace up/down arrow reorder buttons on dashboard edit page with
  SortableJS drag handles; add POST /d/<id>/edit/reorder endpoint
  accepting ordered widget ID array
- Add {% block extra_scripts %} hook to base.html for page-specific JS
- Add dynamic alert rule field loading via HTMX partial (_rule_fields)
  so metric/threshold fields update when source is changed
- Add docs/plugins/index.yaml.example showing catalog index format

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-03-23 08:16:04 -04:00
parent 93d5ed8fb0
commit edc9b752d2
8 changed files with 423 additions and 58 deletions
@@ -7,3 +7,37 @@
</div>
{% include "dashboard/_edit_panels.html" %}
{% endblock %}
{% block extra_scripts %}
<script src="https://cdn.jsdelivr.net/npm/sortablejs@1.15.2/Sortable.min.js"></script>
<script>
(function () {
function initSortable() {
var el = document.getElementById('widget-sort-list');
if (!el) return;
var dashId = el.dataset.dashId;
Sortable.create(el, {
handle: '.drag-handle',
animation: 150,
ghostClass: 'sortable-ghost',
onEnd: function () {
var order = Array.from(el.querySelectorAll('[data-widget-id]'))
.map(function (row) { return parseInt(row.dataset.widgetId, 10); });
fetch('/d/' + dashId + '/edit/reorder', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ order: order }),
});
},
});
}
// Init on first load and after every HTMX swap (add/remove re-renders the list)
document.addEventListener('DOMContentLoaded', initSortable);
document.addEventListener('htmx:afterSwap', initSortable);
})();
</script>
<style>
.sortable-ghost { opacity: 0.4; }
.drag-handle:active { cursor: grabbing; }
</style>
{% endblock %}