# Fila de servicio

> Una fila de ajustes para un servidor MCP, un agente o una skill: estado, interruptor y menú. Componente de Pyzed para GUIs en Python.

Source: https://albakore.github.io/pyzed/es/library/service-row/

:::tip[En pocas palabras]
Una línea de una página de ajustes para una herramienta que usa el asistente: si funciona, un interruptor para encenderla o apagarla y un menú con más opciones.
:::

`ui.ServiceRow` es un componente para algo que usa un agente de IA (un servidor MCP, un agente externo, una skill) en una página de ajustes: un icono, el nombre con su versión (`version`) y un punto de estado, el `detail` (su comando o URL, en letra monoespaciada) y un `summary`; luego un spinner mientras está `busy`, un botón principal (`primary`, como Actualizar o Instalar), un interruptor (`enabled`; `None` lo oculta) y un menú `⋯` con las acciones (`actions`, de `ui.MenuItem`). `status` colorea el punto: `running` e `installed` en verde, `starting` en amarillo, `update` en el color de acento, `error` en rojo, `off` y `missing` en gris. `status_text` es el tooltip del punto, y se ve bajo el nombre con `error`, `missing` y `update`.

`ui.ServiceRow` · Categoría: [Agentes de IA](https://albakore.github.io/pyzed/es/library/#agentes-de-ia) · [Referencia completa →](https://albakore.github.io/pyzed/es/reference/ui/#servicerow)

**Código:**

```python
pz.column([
    ui.ServiceRow(name="github", detail="npx -y @modelcontextprotocol/server-github", icon_name="github",
                  status="running", enabled=True, on_toggle=on_toggle,
                  actions=[ui.MenuItem("Edit", on_edit, icon="pencil")]),
    ui.ServiceRow(name="filesystem", detail="uvx mcp-server-filesystem ~/notes", status="error",
                  status_text="Exited with code 1", enabled=True, on_toggle=on_toggle),
    ui.ServiceRow(name="Gemini CLI", version="0.64.0", icon_name="bot", status="update",
                  status_text="0.65.0 is available", primary="Update", on_primary=on_update),
], spacing=4, width=560)
```

:::note[Nuevo]
Este componente se añadió hace poco. Cuéntanos qué tal te funciona en el [gestor de incidencias](https://github.com/albakore/pyzed/issues).
:::

## Cuándo usarlo

- En los ajustes de una app con agentes de IA: una fila por servidor MCP, agente o skill.
- Para cualquier lista de servicios que se pueden encender y apagar, actualizar o quitar.

## Uso

```python
import pyzed as pz
from pyzed import ui

class Settings(pz.App):
    def __init__(self):
        self.on = True

    def view(self):
        return ui.ServiceRow(name="github", detail="npx -y @modelcontextprotocol/server-github",
                             status="running" if self.on else "off", enabled=self.on,
                             on_toggle=lambda e: setattr(self, "on", e.value),
                             actions=[ui.MenuItem("Remove", self.remove, icon="trash-2", danger=True)])
```

## Variantes

:::note[Sobre estas capturas]
Cada captura la graba pyzed mismo, fuera de pantalla a 2x, en One Dark o One Light según el tema de este sitio, y recortada al componente para que se vea a su tamaño real. El puntero pasa por encima, pulsa o escribe en él; un componente que no reacciona al puntero recorre algunos temas. Con movimiento reducido ves el primer fotograma. Abre **Código** bajo una captura para ver el fragmento que la dibuja; los nombres libres como `on_save` son tus propios callbacks.
:::

### Estado

`enabled=False` además atenúa el nombre y el icono.

```python
pz.container(ui.ServiceRow(name="github", detail="npx -y server-github", status="running",
                           enabled=True), width=420)
```

```python
pz.container(ui.ServiceRow(name="github", detail="npx -y server-github", status="starting",
                           enabled=True), width=420)
```

```python
pz.container(ui.ServiceRow(name="github", detail="npx -y server-github", status="error",
                           status_text="Exited with code 1", enabled=True), width=420)
```

```python
pz.container(ui.ServiceRow(name="github", detail="npx -y server-github", status="off",
                           enabled=False), width=420)
```

```python
pz.container(ui.ServiceRow(name="Gemini CLI", version="0.64.0", icon_name="bot",
                           status="installed"), width=420)
```

```python
pz.container(ui.ServiceRow(name="Codex CLI", icon_name="bot", status="missing",
                           status_text="Not installed yet", primary="Install"), width=420)
```

```python
pz.container(ui.ServiceRow(name="Gemini CLI", version="0.64.0", icon_name="bot", status="update",
                           status_text="0.65.0 is available", primary="Update"), width=420)
```

### Opciones

El menú `⋯` se dibuja abierto, como queda tras pulsarlo.

```python
pz.container(ui.ServiceRow(name="notes", icon_name="book-open", status="running",
                           summary="Reads and writes the notes folder."), width=420)
```

```python
pz.container(ui.ServiceRow(name="Gemini CLI", version="0.64.0", icon_name="bot", busy=True,
                           primary="Update"), width=420)
```

```python
pz.container(ui.ServiceRow(name="github", detail="npx -y server-github", status="running", enabled=True,
                           actions=[ui.MenuItem("Edit", on_edit, icon="pencil"),
                                    ui.MenuItem("Remove", on_remove, icon="trash-2", danger=True)]),
             width=420)
```

## Eventos

Fila de servicio tiene **2 eventos propios**, en la tabla de abajo. Como todo widget, también tiene los **18 eventos comunes** (`click`, `double_click`, `right_click`, `mouse_enter`, `drag`, `key_down`, `resize`…), que se conectan con `.on(...)`: mira [Eventos](https://albakore.github.io/pyzed/es/guides/events/) y [Eventos de cada componente](https://albakore.github.io/pyzed/es/library/events/).

Es un `pz.Component`, así que también lanza `on_mount` y `on_unmount`, y sus handlers reciben un `pz.Event` cuyo `value` trae el dato.

| Evento | El handler recibe | Cuándo |
| --- | --- | --- |
| `on_toggle` | `(event)` | Se cambió el interruptor. |
| `on_primary` | `(event)` | Se pulsó el botón principal. |

**El handler recibe** es lo que Pyzed le pasa a tu función: `()` es nada. Cualquier handler también puede ser un mensaje (un valor que no se puede llamar), que va a `update()`.

### Manejar los eventos

Los mismos eventos escritos de tres formas. **Imperativa**: métodos de la app que cambian `self`. **Declarativa**: los handlers producen mensajes y un único `update()` decide. **Funcional**: una función pura dibuja un estado inmutable y pide cambios con `set_state(...)`. Mira [Imperativo, declarativo y funcional](https://albakore.github.io/pyzed/es/guides/code-styles/).

**Imperativo:**

```python
class Settings(pz.App):
    def __init__(self):
        self.on = True
        self.updates = 0

    def view(self):
        return ui.ServiceRow(name="github", status="running" if self.on else "off", enabled=self.on,
                             primary="Update",
                             on_toggle=lambda e: setattr(self, "on", e.value),     # the switch
                             on_primary=lambda e: setattr(self, "updates", self.updates + 1))
```

**Declarativo:**

```python
from dataclasses import dataclass

@dataclass
class Enable:
    on: bool

class Settings(pz.App):
    on = True

    def update(self, message):
        match message:
            case Enable(on):
                self.on = on

    def view(self):
        return ui.ServiceRow(name="github", enabled=self.on, status="running" if self.on else "off",
                             on_toggle=lambda e: Enable(e.value))
```

**Funcional:**

```python
from dataclasses import dataclass

@dataclass(frozen=True)
class State:
    on: bool = True

def view(state, set_state):
    return ui.ServiceRow(name="github", enabled=state.on, status="running" if state.on else "off",
                         on_toggle=lambda e: set_state(on=e.value))
```

## Propiedades y API

### `ui.ServiceRow`

```python
class ServiceRow
```

Un componente para algo que usa un agente (un servidor MCP, un agente externo, una skill), como las filas de los ajustes de agentes de Zed: un punto de estado, el nombre y el comando, un interruptor, un botón principal y un menú `⋯`.

| Propiedad | Por defecto | Descripción |
| --- | --- | --- |
| `name` | `""` | Nombre. |
| `detail` | `""` | El comando o la URL, en letra monoespaciada. |
| `summary` | `""` | Una línea sobre él. |
| `icon_name` | `"plug"` | El icono. |
| `status` | `""` | `running`, `starting`, `error`, `off`, `installed`, `missing` o `update` (el color del punto). |
| `status_text` | `""` | El tooltip del punto; se muestra bajo el nombre en errores y actualizaciones. |
| `version` | `""` | Una versión o un origen. |
| `enabled` | `None` | El interruptor (`None` lo oculta). |
| `busy` | `False` | Muestra un indicador de carga. |
| `primary` | `""` | Texto del botón principal (Actualizar, Instalar…). |
| `actions` | `None` | Entradas `ui.MenuItem` del menú `⋯`. |
| `theme` | `None` | Tema. |

Eventos: `on_toggle`, `on_primary` ([eventos](#eventos)).

[Referencia completa →](https://albakore.github.io/pyzed/es/reference/ui/#servicerow)

## Relacionados

- [Catálogo](https://albakore.github.io/pyzed/es/library/catalog/): Cosas para instalar, con buscador e Instalar o Actualizar.
- [Interruptor](https://albakore.github.io/pyzed/es/library/switch/): Un interruptor para ajustes que se aplican al momento.
- [Menú](https://albakore.github.io/pyzed/es/library/menu/): Un menú contextual con iconos, atajos y marcas.
- [Grupo de ajustes](https://albakore.github.io/pyzed/es/library/settings-group/): Un bloque con título de filas de ajustes, para pantallas de ajustes.
