# Funcionalidade de Reordenação Nativa - Documentação de Implementação

## Visão Geral

A funcionalidade de Drag & Drop foi implementada nativamente no componente `DynamicList.vue` e em um novo componente especializado `PropertyListEditor.vue`, permitindo que coleções de metadados (como properties em um objeto) sejam reorganizadas visualmente com suporte completo ao estado "dirty" do aplicativo.

## Componentes Implementados

### 1. `DynamicList.vue` (Melhorado)

**Localização**: `app/components/core/DynamicList.vue`

**Funcionalidades principais**:
- Integração com `vuedraggable` v4.0.1 (já instalado no projeto)
- Reordenação condicional via prop `sortable` (default: `false`)
- Ícone de "drag handle" com classe `.drag-handle` (seis pontos)
- Preservação de UI compacta com badges de taxonomia (`category`, `nature`)
- Emissão de evento `reorder` ao finalizar arraste
- Animações suaves com transições CSS personalizadas

**Props**:
```typescript
interface Props {
  schema: ObjectSchema;
  data: any[];
  sortable?: boolean; // Ativa/desativa reordenação
}
```

**Eventos**:
```typescript
// Novo evento emitido quando usuário finaliza arraste
emit('reorder', localData.value);

// Eventos existentes mantidos
emit('delete', item);
emit('edit', item);
emit('update', item);
emit('refresh');
```

**Exemplo de Uso**:
```vue
<DynamicList
  :schema="propertySchema"
  :data="properties"
  :sortable="true"
  @reorder="handlePropertiesReordered"
/>
```

### 2. `PropertyListEditor.vue` (Novo)

**Localização**: `app/components/core/PropertyListEditor.vue`

**Funcionalidades principais**:
- Componente especializado para editar e reordenar propriedades de um objeto
- Drag & Drop nativo com validação de UX
- Edição inline de todos os atributos de propriedade
- Checkboxes para flags (`required`, `show_in_list`, `show_in_form`)
- Indicador visual de ordem (número serial)
- Adição/remoção de propriedades com confirmação
- Sincronização bidirecional com estado do objeto

**Props**:
```typescript
interface Props {
  properties: PropSchema[];
}
```

**Eventos**:
```typescript
// Emitido ao modificar uma propriedade individual
emit('update', { 
  index: number;
  property?: PropSchema;
  action?: string;
  deletedIndex?: number;
});

// Emitido ao finalizar reordenação
emit('reorder', reorderedProperties: PropSchema[]);
```

**Exemplo de Uso**:
```vue
<PropertyListEditor
  :properties="editingObject.properties"
  @update="onPropertyUpdate"
  @reorder="onPropertyReorder"
/>
```

## Integração no Schema Manager

A funcionalidade foi integrada na página de Schema Manager (`app/pages/fastapp/schema.vue`):

### Mudanças Implementadas

1. **Importação do Componente**:
```typescript
import PropertyListEditor from '~/components/core/PropertyListEditor.vue';
```

2. **Substituição da Interface de Edição**:
```vue
<!-- Antes: Lista inline com inputs -->
<div v-for="(p, idx) in editingObject.properties">
  <InputText v-model="p.name" ... />
  <!-- ... mais inputs ... -->
</div>

<!-- Depois: Componente especializado com Drag & Drop -->
<PropertyListEditor
  v-if="editingObject"
  :properties="editingObject.properties"
  @update="onPropertyUpdate"
  @reorder="onPropertyReorder"
/>
```

3. **Handlers de Eventos**:
```typescript
/**
 * Handle property updates (add/edit/delete)
 */
function onPropertyUpdate(event: { index: number; property?: any; action?: string; deletedIndex?: number }) {
    if (!editingObject.value) return;
    isDirty.value = true;
}

/**
 * Handle property reordering
 * Sincroniza a nova ordem e marca como dirty
 */
function onPropertyReorder(reorderedProperties: any[]) {
    if (!editingObject.value) return;
    
    editingObject.value.properties = reorderedProperties;
    isDirty.value = true;
    
    toast.add({ 
        severity: 'info', 
        summary: 'Propriedades Reordenadas', 
        detail: 'Salve a aplicação para persistir as alterações.',
        life: 2000
    });
}
```

## Caso de Uso: Schema Manager

### Fluxo de Uso

1. **Abrir Schema Manager** → Selecionar um App
2. **Clicar em "Editar Objeto"** na seção "Objetos do Sistema"
3. **Dialog Se Abre** com a interface visual de edição
4. **PropertyListEditor é Renderizado** com lista de propriedades
5. **Usuário Arrasta Propriedades** para reordenar
6. **Evento `reorder` é Emitido** com a nova ordem
7. **Estado `isDirty` é Marcado como `true`** (visível no indicador amarelo)
8. **Botão "Salvar"** na header fica habilitado
9. **Usuário Clica "Aplicar ao App"** para persistir a ordem no objeto
10. **Usuário Clica "Salvar"** para persistir no banco de dados

### Exemplo Visual

```
📋 Schema Manager

┌─────────────────────────────────────────┐
│ Definição de Objeto: lead               │
├─────────────────────────────────────────┤
│ ID Interno: lead                        │
│ Label: Lead                             │
│                                         │
│ PROPRIEDADES (5)        [+ Adicionar]   │
│ ┌─────────────────────────────────────┐ │
│ │ ⋮⋮  name    Full Name   string      │ │
│ │ ⋮⋮  email   E-mail      string  🔳 🔲│ │
│ │ ⋮⋮  phone   Telefone    string  ✓ ✓ │ │ ← Reordenável via arraste
│ │ ⋮⋮  status  Status      enum    ✓ ✓ │ │
│ │ ⋮⋮  notes   Notas       json    🔲 ✓ │ │
│ └─────────────────────────────────────┘ │
│                                         │
│ [Fechar]  [Aplicar ao App]              │
└─────────────────────────────────────────┘
```

## Sincronização com Store

### Estado "Dirty" Flow

```typescript
// 1. Usuário arrasta propriedade
onPropertyReorder(reorderedProperties) {
    // 2. Propriedades do objeto são atualizadas
    editingObject.value.properties = reorderedProperties;
    
    // 3. isDirty é marcado como true
    isDirty.value = true;
    
    // 4. Toast notifica o usuário
    toast.add({ ... });
    
    // 5. Botão "Salvar" na header fica habilitado
    // (disabled={!isDirty})
}

// 6. Usuário clica "Aplicar ao App"
applyObjectChanges() {
    // 7. Objeto com propriedades reordenadas é atualizado no selectedApp
    selectedApp.value.objects[idx] = editingObject.value;
    
    // 8. isDirty permanece true até salvar
}

// 9. Usuário clica "Salvar"
saveChanges() {
    // 10. Payload é enviado para API
    await $fetch(`/api/app/${payload.id}`, {
        method: 'PATCH',
        body: payload
    });
    
    // 11. isDirty é resetado
    isDirty.value = false;
    
    // 12. Apps são refreshed e estado sincronizado
}
```

## Estilos e Animações

### Classes CSS Personalizadas

```css
/* Drag container */
.drag-list-move {
  transition: transform 0.2s cubic-bezier(0.4, 0, 0.2, 1);
}

/* Ghost state (elemento sendo arrastado) */
.ghost {
  opacity: 0.5;
  background: rgba(99, 102, 241, 0.1);
  border-color: rgba(99, 102, 241, 0.3);
}

/* Drag state (hover) */
.drag {
  opacity: 1;
  transform: rotate(2deg) scale(1.02);
  box-shadow: 0 5px 25px rgba(99, 102, 241, 0.3);
}

/* Handle cursor */
.drag-handle {
  cursor: grab;
}
.drag-handle:active {
  cursor: grabbing;
}
```

## Configuração Vuedraggable

```javascript
const dragOptions = computed(() => ({
  animation: 200,                    // Duração da animação (ms)
  group: "properties",               // Grupo para restricionar arraste
  ghostClass: "ghost",               // Classe do elemento sendo arrastado
  dragClass: "drag",                 // Classe durante arraste
  handle: ".drag-handle",            // Seletor do handle
  easing: "cubic-bezier(1, 0, 0, 1)" // Easing animation
}));
```

## Considerações de Performance

1. **Computed Properties**: Utilizadas para otimizar re-renders
2. **v-model Reativo**: Mantém sincronização entre componente pai e filho
3. **Watch com Deep**: Monitora mudanças profundas em propriedades
4. **Transition Groups**: Aplica animações apenas quando necessário

## Testes Recomendados

```
✓ Arrastar propriedade de cima para baixo
✓ Arrastar propriedade de baixo para cima
✓ Adicionar nova propriedade (deve aparecer no final)
✓ Remover propriedade (com confirmação)
✓ Editar nome/label durante reordenação
✓ isDirty deve ser true após qualquer mudança
✓ isDirty deve ser false após salvar
✓ Botão "Salvar" deve estar desabilitado quando isDirty=false
✓ Toast deve aparecer após reordenação
✓ Ordem deve persistir no banco após salvar
```

## Backward Compatibility

Os componentes mantêm retrocompatibilidade:
- `DynamicList.vue`: Funciona normalmente sem prop `sortable` (padrão: false)
- Propriedades antigas do componente continuam funcionando
- Eventos legados são mantidos
- A reordenação é uma opção, não obrigatória

## Próximas Melhorias (Sugestões)

1. **Persistência Automática**: Auto-save após 2 segundos de inatividade
2. **Undo/Redo**: Stack de mudanças para desfazer/refazer
3. **Vinculação a CRM**: Sincronizar ordem com renderização de formulários em tempo real
4. **Histórico de Mudanças**: Log de quem alterou e quando
5. **Validação Avançada**: Verificar dependências entre campos antes de reordenar
6. **Temas Customizáveis**: Cores e ícones configuráveis via props

## Referências

- **Vuedraggable**: https://github.com/SortableJS/vue.draggable.next
- **Sortable.js**: https://sortablejs.github.io/Sortable/
- **Vue 3 Composables**: https://vuejs.org/guide/extras/composition-api-faq.html
