CreaRack-SL

Endpoint: Reordenar secciones del Dashboard (drag&drop)

Ubicación

POST /api/blueprints/reorder
blueprints/api/blueprints.py :: reorder_blueprints(request, payload)

Descripción

Endpoint que persiste el orden manual de las secciones del Dashboard después de un arrastre (drag&drop). Consumido exclusivamente por el cliente web (static/js/dashboard.js).

Permisos: blueprints:edit (solo administradores y operadores).

Versión: Introducido en v1.50.0 (2026-07-13, solo blueprints). Evolucionado en v1.51.0 para incluir secciones fijas (Rooms, No Map).

Contrato

Request

{
  "section_keys": [
    "nomap",
    "1",
    "rooms",
    "2"
  ]
}
  • Campo: section_keys: list[str]
  • Tokens:
    • "rooms" — Sección de Salas (DCIM Fase 3)
    • "<blueprint_id>" (string entero) — Blueprint (Map o Row)
    • "nomap" — Racks sin blueprint

Semántica: Orden visual del Dashboard en el momento del POST. El índice de cada token en la lista determina su posición final.

Scoping: La organización se obtiene de request.org (middleware). Solo se aplican cambios a blueprints de esa organización; ids foráneos o borrados se ignoran silenciosamente.

Response (200 OK)

{
  "ok": true,
  "count": 3
}
  • count: Número de entidades actualizadas (suma de blueprints cuyo sort_order cambió + secciones fijas cuya posición se fijó en ui_pref).

Response (403 Forbidden)

Si el usuario no tiene permiso blueprints:edit.

Response (400 Bad Request)

Si section_keys no es una lista o contiene valores inválidos.

Lógica de persistencia

Blueprints → Blueprint.sort_order

Cada token que sea un entero válido y corresponda a un Blueprint de la organización actual:

bp = Blueprint.objects.get(id=token, organization=org, deleted_at__isnull=True)
bp.sort_order = index

Blueprints cuyo id NO aparezca en section_keys conservan su sort_order anterior.

Secciones fijas → OrgUIPreference

  • Token "rooms" → set_ui_pref(org.id, "dashboard_rooms_sort", str(index))
  • Token "nomap" → set_ui_pref(org.id, "dashboard_nomap_sort", str(index))

Estas preferencias son de organización (no de usuario individual).

Fuentes de datos

RecursoOrigen
Blueprints de la orgBlueprint.objects.filter(organization=org, deleted_at__isnull=True)
Ui-prefs de Rooms/NoMapOrgUIPreference con claves dashboard_rooms_sort, dashboard_nomap_sort

Cambios en v1.51.0

v1.50.0 (contrato inicial):

{ "blueprint_ids": [1, 2, 3] }

Solo aceptaba IDs de blueprints numéricos. Rooms y No Map no eran reordenables.

v1.51.0 (cambio breaking):

{ "section_keys": ["rooms", "1", "nomap", "2"] }
  • Campo renombrado: blueprint_ids → section_keys.
  • Tokens mixtos: además de IDs de blueprints, soporta "rooms" y "nomap".
  • Persistencia: Rooms/NoMap se guardan en OrgUIPreference (no en Blueprint).

Consumidor: Solo el cliente web (dashboard.js) consume este endpoint. Cambio interno, sin API pública documentada.

Ejemplo de flujo

  1. Usuario arrastra “No Map” a la posición 0 (primera), “Alpha” (id=5) a posición 1, y “Rooms” a posición 2.
  2. JavaScript recolecta el DOM ([...document.querySelectorAll('.blueprint-section[data-section-key]')].map(s => s.dataset.sectionKey)).
  3. Envía POST /api/blueprints/reorder con {"section_keys": ["nomap", "5", "rooms", ...]}.
  4. El endpoint:
    • Lee la org del request.
    • Actualiza Blueprint(id=5).sort_order = 1 en la org.
    • Escribe OrgUIPreference(..., key="dashboard_nomap_sort", value="0").
    • Escribe OrgUIPreference(..., key="dashboard_rooms_sort", value="2").
    • Retorna {"ok": true, "count": 3}.
  5. El dashboard se re-renderiza (HTMX o recarga) con el nuevo orden.

Validación y seguridad

  • Permiso: Requiere blueprints:edit.
  • Scoping: Solo blueprints de la organización actual son modificados.
  • Blindaje: Ids foráneos, papeleras (soft-deleted) e inválidos se ignoran sin error.
  • Atomicidad: Toda la operación ocurre en un transaction.atomic() — si falla, se revierte todo.

Mocking / Testing

Tests en tests/api/test_blueprints_reorder.py:

  • Reorden de índices con verificación de sort_order.
  • Persistencia de Rooms/NoMap en ui_prefs (leyendo directo de PostgreSQL, no caché).
  • Ignora ids foráneos y deletreados.
  • Viewer (readonly) no puede reordenar → 403.

Véase también

  • [[entity—racks—service—dashboard-sections]]
  • [[entity—blueprints—model—blueprint]]
  • [[entity—core—service—ui-pref]]
  • [[feature—dashboard—reorder-todas-secciones]]
  • [[entity—blueprints—model—room]]