Descripción
A partir de v1.50.0 (13 de julio de 2026), los usuarios pueden reordenar manualmente las secciones del Dashboard (Maps y Filas) simplemente arrastrando su cabecera hacia arriba o abajo.
El orden es por organización (decisión arquitectónica): es información del datacenter compartida por todo el equipo, no una preferencia personal. Solo quienes tienen permiso blueprints:edit pueden reordenar; los lectores ven el resultado pero no pueden moverlo.
Comportamiento
- Arrastra cualquier sección (Maps/Rows) por su cabecera (
draggable="true"en HTML5 nativo). - El orden se guarda al instante en el servidor (
POST /api/blueprints/reorder). - “Rooms” (sala madre) y “No Map” (racks sin blueprint) no se mueven: son fijas al inicio y final respectivamente.
- La acción de plegar/desplegar secciones (click en flecha) funciona igual, independiente del drag.
- El navegador sobrevive a los swaps HTMX: delegación de eventos en
document, no en elementos que pueden ser reemplazados.
Inicialización y persistencia
- Al deploy: el orden de partida es el alfabético anterior (via migración
blueprints/0010con backfill). Los maps nuevos aparecen al final (sort_order=NULL) hasta que se reordenan. - Sort en dos renders:
racks/views.py(first render, GET/).core/htmx_views.py(refresh partial HTMX, para{% regroup %}).
- Key de sort:
(no_map, sin_ordenar, sort_order, nombre_blueprint, nombre_rack)— garantiza que el orden se aplica consistentemente en ambos path.
Arquitectura técnica
Backend
Modelo: Blueprint.sort_order (IntegerField, nullable)
- Campo por organización (FK
Organization). NULL= sin ordenar todavía → va al final.0..N= posición manual asignada por drag&drop.
Endpoint: POST /api/blueprints/reorder
- Payload:
BlueprintsReorderSchema { blueprint_ids: list[int] } - Response:
{ "ok": true, "count": 3 } - Permisos:
require_perm(request, "blueprints", "edit")— reader 403. - Lógica:
select_for_update()(transacción atómica).- Filtra por
organization=current_org, omitedeleted_at != NULL(soft-delete). - IDs ajenos o borrados se ignoran silenciosamente (no son un error).
bulk_update()en un sola query.
Frontend
JavaScript: static/js/dashboard.js
- Handlers delegados en
document(dragstart, dragover, drop, dragend). - Dragstart: marca la sección con clase
section-dragging(opacidad 0.5). - Dragover: reordena en vivo en el DOM (visual feedback); extrae todos los
data-blueprint-idordenados. - Dragend: POST
/api/blueprints/reordercon la lista nueva; toast “Orden de secciones guardado” (o error); si falla,window.location.reload().
CSS: static/css/pages/dashboard.css
.blueprint-section-header[draggable="true"]→cursor: grab..blueprint-section.section-dragging→opacity: 0.5.
HTML: Data attributes en templates
data-blueprint-name="{{ bp_group.grouper }}"— clave de agrupación (regroup).data-blueprint-id="{{ bp_group.list.0.blueprint_id }}"— para serializar el orden nuevo.draggable="true"en cabecera.title="{% trans 'Drag to reorder sections' %}"— tooltip.
Internacionalización
3 strings nuevos en catálogo ES (locale/es/LC_MESSAGES):
- django.po:
"Drag to reorder sections"→"Arrastra para reordenar las secciones" - djangojs.po:
"Section order saved"→"Orden de secciones guardado" - djangojs.po:
"Could not save the section order"→"No se pudo guardar el orden de las secciones"
Testing
tests/api/test_blueprints_reorder.py (3 test cases, todos verdes):
test_reorder_applies_index_order: verifica que losblueprint_idsse mapean asort_order = índice.test_foreign_and_deleted_ids_ignored: confirma que IDs de otra org y blueprints borrados no afectan.test_viewer_cannot_reorder: viewer (readonly) recibe 403,sort_orderno cambia.
Migración: makemigrations --check sin drift; backfill seguro por organización.
Notas de implementación
- Sin dependencias nuevas: HTML5 DnD nativo, sin librerías externas.
- Orden previo alfabético restaurable: si se quiere revertir a orden alfabético, reset
sort_order=NULL+ reload. - Concurrencia:
select_for_update()previene race conditions; múltiples usuarios reordenando simultáneamente van en serie.
Véase también
- [[entity—blueprints—endpoint—reorder]]
- [[entity—blueprints—model—blueprint-sort-order]]
- [[concept—saas—multi-tenancy]]
- [[entity—blueprints—model—blueprint]]
- [[entity—core—model—organization]]