# Correções — Edição do `SystemDataImportTemplateForm`

> **Por que este doc existe:** `web/mad-framework` é descartável — `web/reset-framework.sh`
> joga fora qualquer alteração local e recoloca o repo em `origin/main` (ou reaplica os PRs
> com `--prs`). Este markdown vive em `docs/` (fora de `web/`) para que estas correções possam
> ser **reaplicadas manualmente** após cada reset.
>
> Data: 2026-06-06 · Componente: `SystemDataImportTemplateForm` (Importação de Dados)

## Contexto

Ao salvar um template de importação com tudo preenchido e depois **abrir para editar**, vários
campos vinham vazios/errados:

1. Field-list de **Mapeamento de colunas** não renderizava as linhas salvas.
2. Os **selects** (Tabela destino / Campo destino) ficavam em "Selecione..." mesmo com linha.
3. **Grupos/Usuários com acesso** vinham vazios.
4. Switch **Ativo** aparecia desmarcado (apesar de a grid mostrar ativo).
5. **CSV modelo** existente não aparecia no preview do file-field.

---

## Arquivos e mudanças

### 1. `web/mad-framework/app/control/admin/SystemDataImportTemplateForm.php`

#### 1a. `loadMappingRows()` — popular `fields['mapping']` (linhas do field-list)

O drawer de edição é aberto via `target="SystemDataImportTemplateForm::onEdit({id})"`, que faz
**full render** pelo `show()`. Nesse caminho ops de `MadResponse` (como `fl_rows` de `setRows()`)
**não** são despachadas. O padrão canônico (mesmo do `loadDetailRows`) é popular
`$form->fields['mapping']` — assim a row vira a variável `$mapping` no contexto e chega no `:rows`
do componente.

No final do método `loadMappingRows()`, o bloco deve ser:

```php
if (!empty($rows)) {
    // Popula fields['mapping'] para o field-list renderizar as linhas no
    // primeiro render (full render do drawer). setRows() sozinho só gera
    // op fl_rows, que não é aplicada nesse caminho de navegação.
    $this->form->fields['mapping'] = \Mad\Form\FieldListColumn::normalizeRows($rows);
}
```

> ⚠️ Usar o FQN `\Mad\Form\FieldListColumn` (a classe está no namespace `Mad\Form`; sem `use`
> no controller, o nome sem `\` resolve para `\FieldListColumn` e dá `Class not found`).
> **NÃO** usar `$this->form->set('mapping', $rows)` nem `setRows()` aqui.

#### 1b. `onEdit()` — expor o CSV modelo existente

O `mad-file-field name="csv_model"` lê o arquivo existente do contexto pelo **nome do campo**,
mas o path salvo está na coluna `csv_model_path`. Em `onEdit()`, logo após `loadMappingRows($mapping);`
(e antes de carregar os logs), adicionar:

```php
// Expõe o CSV modelo existente para o mad-file-field renderizar o preview
if (!empty($template->csv_model_path)) {
    $this->form->fields['csv_model'] = $template->csv_model_path;
}
```

#### 1c. `onSave()` — gravação correta do `active`

Com o switch usando `value-off="N"` (ver 2b), o desmarcado posta `'N'`, e `!empty('N')` é `true`
→ gravaria sempre `'Y'`. Trocar a linha do `active` por comparação explícita:

```php
$template->active        = (($data->active ?? 'N') === 'Y') ? 'Y' : 'N';
```

---

### 2. `web/mad-framework/app/resources/views/admin/system-data-import-template-form.blade.php`

#### 2a. Passar `:selected` para grupos e usuários

A view já calcula `$selectedGroups` / `$selectedUsers` no bloco `@php`, mas não os passava aos
componentes. Adicionar `:selected`:

```blade
<mad-dbmulti-search-field name="groups" label="Grupos com acesso"
    model="SystemGroup" database="permission" display="name"
    min-length="0"
    max-size="0"
    :selected="$selectedGroups"
    placeholder="Buscar grupos..."/>

<mad-dbmulti-search-field name="users" label="Usuários com acesso"
    model="SystemUsers" database="permission" display="name"
    :selected="$selectedUsers"
    placeholder="Buscar usuários..." />
```

#### 2b. Switch `Ativo` com dual-value `Y`/`N`

O banco grava `'Y'`/`'N'`, mas o switch usava o default `valueOn='1'`. Adicionar `value-on`/`value-off`:

```blade
<mad-switch-field name="active" label="Ativo" value-on="Y" value-off="N"
    description="Templates inativos não aparecem para usuários comuns." />
```

---

### 3. `web/mad-framework/lib/mad/views/components/field-list.blade.php` *(componente CORE — cuidado)*

#### Selects do field-list não aplicavam o valor salvo (TomSelect)

O `<select data-mad-select>` dependia só do `x-model` para o TomSelect pegar o valor inicial, mas
há race entre o `x-model` das rows clonadas pelo Alpine e o `_madInitSelects` (`$nextTick`). O
`_madInitSelects` aplica valor via `el.dataset.madSelected`. Adicionar o binding no `<select>`:

Localizar (≈ linha 236-239):

```blade
<select class="mad-input-sm"
        name="{{ $fld }}[]"
        x-model="row['{{ $fld }}']"
        data-mad-select
```

E inserir a linha `:data-mad-selected`:

```blade
<select class="mad-input-sm"
        name="{{ $fld }}[]"
        x-model="row['{{ $fld }}']"
        :data-mad-selected="row['{{ $fld }}']"
        data-mad-select
```

> Esta é a única mudança em componente **core compartilhado** — corrige a pré-seleção de selects
> em edição para **todos** os field-lists. Se preferir não tocar no core após o reset, avaliar se
> os selects voltam a falhar; se sim, reaplicar.

#### Corrida de inicialização do TomSelect (complemento do item 3)

Mesmo com o `:data-mad-selected` (acima), os selects podiam continuar vazios em edição: o
TomSelect às vezes é criado por uma chamada de `_madInitSelects` que roda **antes** de o Alpine
avaliar o binding `:data-mad-selected` (a instância nasce sem valor). As chamadas seguintes de
`_madInitSelects` (x-init/$nextTick de cada row e o pass global de 300ms) retornavam cedo em
`if (el.tomselect) return;` e nunca reaplicavam o valor.

Em `app/lib/include/builder/ui/mad-ui.js`, dentro de `_madInitSelects()`, trocar o early-return
para reaplicar o valor pré-selecionado quando o TomSelect ainda está vazio:

```js
if (el.tomselect) {
    var pre = el.dataset.madSelected;
    if (pre && !el.tomselect.getValue()) {
        el.tomselect.setValue(pre, true);
    }
    return;
}
```

> Seguro: só preenche selects **vazios** e apenas quando há `data-mad-selected` (contexto MadForm).
> O pass global de 300ms, que roda depois de o Alpine bindar tudo, passa a garantir a aplicação.

---

## Pós-reset: passos para reaplicar

1. Reaplicar 1a, 1b, 1c em `app/control/admin/SystemDataImportTemplateForm.php`.
2. Reaplicar 2a, 2b em `app/resources/views/admin/system-data-import-template-form.blade.php`.
3. Reaplicar 3 em `lib/mad/views/components/field-list.blade.php` (core — opcional/condicional).
3b. Reaplicar o complemento do item 3 em `app/lib/include/builder/ui/mad-ui.js`
    (`_madInitSelects` reaplica `data-mad-selected` quando o TomSelect está vazio).
4. Limpar o blade-cache afetado:

   ```bash
   rm -f web/mad-framework/tmp/blade-cache/components.field-list_*.bladec \
         web/mad-framework/tmp/blade-cache/components.switch-field_*.bladec \
         web/mad-framework/tmp/blade-cache/components.file-field_*.bladec \
         web/mad-framework/tmp/blade-cache/components.dbmulti-search-field_*.bladec \
         web/mad-framework/tmp/blade-cache/admin.system-data-import-template-form_*.bladec
   ```

5. Validar sintaxe PHP:

   ```bash
   php -l web/mad-framework/app/control/admin/SystemDataImportTemplateForm.php
   ```

6. Abrir `engine.php?class=SystemDataImportTemplateForm&method=onEdit&id=<ID>` e conferir:
   linhas do mapeamento, selects preenchidos, grupos/usuários, switch Ativo e preview do CSV.

---

## Relacionado (não faz parte desta correção, mas mesmo módulo)

Botão de importação na listagem de Fabricantes
(`app/resources/views/pedido/fabricante-header-list.blade.php`), dentro de `<actions>`:

```blade
<mad-import-btn code="importar-fabricantes">Importar Fabricantes</mad-import-btn>
```

> Só renderiza se o template `importar-fabricantes` existir **e estiver ativo**.
