# Barra de cambios

> Los archivos que cambió un agente, con Conservar todo y Rechazar todo. Componente de Pyzed para GUIs de escritorio en Python, con ejemplos y API.

Source: https://albakore.github.io/pyzed/es/library/edits-bar/

:::tip[En pocas palabras]
Una barra con los archivos que cambió un asistente de IA, para conservar o deshacer los cambios.
:::

`ui.EditsBar` es un componente que lista los archivos que cambió un agente: `3 archivos cambiados` con las líneas añadidas y quitadas, Rechazar todo y Conservar todo. Un clic en el título despliega una fila por archivo con su resumen de cambios y botones para rechazar o conservar solo ese archivo; un clic en el nombre de un archivo llega a `on_open`. `files` son diccionarios u objetos con `path` y, opcionales, las líneas añadidas (`added`) y quitadas (`removed`). Los eventos de un archivo (`on_keep_file`, `on_reject_file`, `on_open`) llevan la ruta en `event.value`.

`ui.EditsBar` · 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/#editsbar)

**Código:**

```python
pz.container(ui.EditsBar(files=[
    {"path": "app/storage.py", "added": 12, "removed": 3},
    {"path": "app/forms/login.py", "added": 40, "removed": 0},
    {"path": "tests/test_login.py", "added": 18, "removed": 2},
], on_keep=on_keep, on_reject=on_reject), width=520)
```

:::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

- Bajo el chat de un agente, cuando ya editó archivos, para que el usuario los revise antes de conservarlos.

## Uso

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

class Review(pz.App):
    def __init__(self):
        self.files = [{"path": "app/storage.py", "added": 12, "removed": 3}]

    def keep(self, path=None):  # None: every file
        self.files = [f for f in self.files if path is not None and f["path"] != path]

    def view(self):
        return ui.EditsBar(files=self.files, on_keep=lambda e: self.keep(),
                           on_keep_file=lambda e: self.keep(e.value), on_open=lambda e: self.open(e.value))
```

## 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

Las desplegadas se dibujan como quedan tras un clic en la cabecera.

```python
pz.container(ui.EditsBar(files=[{"path": "app.py", "added": 12, "removed": 3},
                             {"path": "ui/form.py", "added": 40, "removed": 0}]),
             width=440)
```

```python
pz.container(ui.EditsBar(files=[{"path": "app.py", "added": 12, "removed": 3},
                             {"path": "ui/form.py", "added": 40, "removed": 0}]),
             width=440)
```

```python
pz.container(ui.EditsBar(files=[{"path": "app.py", "added": 2, "removed": 2}]), width=440)
```

```python
pz.container(ui.EditsBar(files=[{"path": "app.py"}, {"path": "README.md"}]), width=440)
```

## Eventos

Barra de cambios tiene **5 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_keep` | `(event)` | Conservar todo. |
| `on_reject` | `(event)` | Rechazar todo. |
| `on_keep_file` | `(event)` | Conservar en un archivo (`event.value` es su ruta). |
| `on_reject_file` | `(event)` | Rechazar en un archivo. |
| `on_open` | `(event)` | Se hizo clic en un archivo. |

**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 Review(pz.App):
    def __init__(self):
        self.files = [{"path": "app/storage.py", "added": 12, "removed": 3},
                      {"path": "tests/test_storage.py", "added": 8, "removed": 0}]

    def drop(self, path=None):           # None: every file
        self.files = [f for f in self.files if path is not None and f["path"] != path]

    def view(self):                      # event.value is the file's path
        return ui.EditsBar(files=self.files,
                           on_keep=lambda e: self.drop(), on_reject=lambda e: self.drop(),
                           on_keep_file=lambda e: self.drop(e.value),
                           on_reject_file=lambda e: self.drop(e.value),
                           on_open=lambda e: print("open", e.value))
```

**Declarativo:**

```python
from dataclasses import dataclass

@dataclass
class Done:
    path: str = ""

class Review(pz.App):
    files = [{"path": "app/storage.py", "added": 12, "removed": 3}]

    def update(self, message):
        match message:
            case Done(""):
                self.files = []
            case Done(path):
                self.files = [f for f in self.files if f["path"] != path]

    def view(self):
        return ui.EditsBar(files=self.files, on_keep=Done(), on_keep_file=lambda e: Done(e.value))
```

**Funcional:**

```python
from dataclasses import dataclass

@dataclass(frozen=True)
class State:
    files: tuple = ({"path": "app/storage.py", "added": 12, "removed": 3},)

def view(state, set_state):
    without = lambda path: tuple(f for f in state.files if f["path"] != path)
    return ui.EditsBar(files=list(state.files), on_keep=lambda e: set_state(files=()),
                       on_keep_file=lambda e: set_state(files=without(e.value)))
```

## Propiedades y API

### `ui.EditsBar`

```python
class EditsBar
```

Un componente con los archivos que cambió un agente, como la barra de cambios de Zed: `3 archivos cambiados` con Rechazar todo y Conservar todo, que se despliega en una fila por archivo con sus líneas, Rechazar y Conservar.

| Propiedad | Por defecto | Descripción |
| --- | --- | --- |
| `files` | `None` | Dicts u objetos con `path` y, opcionalmente, `added` y `removed` (líneas). |
| `theme` | `None` | Tema. |

Eventos: `on_keep`, `on_reject`, `on_keep_file`, `on_reject_file`, `on_open` ([eventos](#eventos)).

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

## Relacionados

- [Vista de diferencias](https://albakore.github.io/pyzed/es/library/diff-view/): Un cambio como líneas de colores: lo añadido en verde, lo quitado en rojo.
- [Resumen de cambios](https://albakore.github.io/pyzed/es/library/diff-stat/): `+12 −3` con bloques al estilo de GitHub.
- [Llamada a herramienta](https://albakore.github.io/pyzed/es/library/tool-call/): Un paso de un agente de IA: qué hizo, su resultado y Permitir o Rechazar.
