---
name: metabase_dashboard_next_row
kind: function
lang: py
domain: infra
version: "1.0.0"
purity: impure
signature: "def metabase_dashboard_next_row(client: MetabaseClient, *, dashboard_id: int, tab_id: int = 0) -> int"
description: "Calcula la primera fila libre al final de una tab de dashboard: max(dc.row + dc.size_y) entre las dashcards de esa tab. Retorna 0 si la tab esta vacia. Evita el boilerplate manual de max() al colocar nuevas cards al final del dashboard."
tags: [metabase, dashboard, layout, dashcard, row, tab, api, python]
uses_functions:
  - metabase_get_dashboard_py_infra
uses_types: []
returns: []
returns_optional: false
error_type: "error_go_core"
imports: []
params:
  - name: client
    desc: "MetabaseClient autenticado con sesion activa"
  - name: dashboard_id
    desc: "ID del dashboard cuyas filas se calculan"
  - name: tab_id
    desc: "ID de la tab cuya fila final se calcula. 0 (default) = dashcards sin dashboard_tab_id (dashboard sin pestanas o tab raiz)"
output: "int: indice de fila (0-indexed) donde colocar la siguiente card. 0 si la tab no tiene dashcards."
tested: false
tests: []
test_file_path: ""
file_path: "python/functions/metabase/metabase_dashboard_next_row.py"
---

## Ejemplo

```python
from metabase import MetabaseClient, metabase_dashboard_next_row

client = MetabaseClient("https://metabase.example.com", "token...")

# Dashboard sin tabs: siguiente fila libre en la raiz
next_row = metabase_dashboard_next_row(client, dashboard_id=10)

new_dashcard = {
    "id": -1,
    "card_id": 99,
    "col": 0, "row": next_row, "size_x": 6, "size_y": 4,
    "parameter_mappings": [],
    "visualization_settings": {},
}

# Dashboard con tabs: siguiente fila libre en tab 3
next_row = metabase_dashboard_next_row(client, dashboard_id=10, tab_id=3)
```

## Notas

- Cuando `tab_id == 0` se filtran dashcards donde `dashboard_tab_id` es falsy
  (None, 0 o ausente). Esto cubre dashboards sin tabs y la "tab raiz".
- Requiere 1 request HTTP (GET dashboard). Si ya tienes el objeto dashboard
  en memoria, es mas eficiente calcular directamente:
  `max((dc["row"] + dc["size_y"] for dc in dashcards), default=0)`.
- La fila retornada es la inmediatamente disponible — no reserva espacio
  ni verifica solapamiento de columnas.
