# feat\(webapp\): add draggable chart reordering on main page \(\#30\) · flambo/atlantis

[View on GitCafe](https://git.cafe/flambo/atlantis/commit/8e7e84510a81f0f68917ee3ddc43ee672bfad55e)

Repository: [flambo/atlantis](https://git.cafe/flambo/atlantis)

Visibility: public

Requested revision: 8e7e84510a81f0f68917ee3ddc43ee672bfad55e

Requested commit: 8e7e84510a81f0f68917ee3ddc43ee672bfad55e

Commit: 8e7e84510a81f0f68917ee3ddc43ee672bfad55e

Tree: 67e76644d5640ba61e41677737936f1c7ced4e7b

Author: oliver

Committer: GitHub

## Message

````
feat(webapp): add draggable chart reordering on main page (#30)

<!-- greptile_comment -->

<h3>Greptile Summary</h3>

This PR adds drag-and-drop reordering for the four main chart cards on the dashboard page. The implementation uses the native HTML5 drag-and-drop API with `draggable` headers as grab handles, visual drop-target highlighting, a full-card clone for the drag image, and `localStorage` persistence of the user's preferred order. The chart order is validated on load to guard against corrupted storage.

- The `+page.svelte` file gains ~125 lines of drag state management, event handlers (`dragstart`, `dragover`, `drop`, `dragend`), localStorage load/persist logic, and a keyed `{#each}` block that conditionally renders the correct chart component per ID.
- All four chart components (`IPChart`, `ProtocolChart`, `SpectrumStatsChart`, `NetflowDashboard`) receive identical changes: `draggable="true"` + `data-drag-handle` on the header div, plus a 6-dot grip icon overlay.
- The drag-handle grip icon markup is duplicated verbatim across all four components and could be extracted into a shared component.
- A missing `ondragleave` handler means the blue drop-target highlight ring can persist on the last-hovered card when dragging into empty space between cards.

<h3>Confidence Score: 4/5</h3>

- This PR is safe to merge with minor polish improvements recommended.
- The drag-and-drop implementation is solid: validation logic is correct, state management is clean, and the feature degrades gracefully (falls back to default order on invalid localStorage). The two issues found are a stale highlight ring (cosmetic UX) and duplicated markup (maintainability). No runtime bugs or security concerns.
- `netflow-webapp/src/routes/+page.svelte` needs a minor `ondragleave` handler to clear the highlight ring properly.

<h3>Important Files Changed</h3>




| Filename | Overview |
|----------|----------|
| netflow-webapp/src/routes/+page.svelte | Core drag-and-drop orchestration: adds state, event handlers, localStorage persistence, and keyed-each rendering. Missing `ondragleave` handler causes stale highlight ring. |
| netflow-webapp/src/lib/components/charts/IPChart.svelte | Adds `draggable="true"`, `data-drag-handle` attribute, and a 6-dot grip icon to the header. Markup is duplicated across all chart components. |
| netflow-webapp/src/lib/components/charts/ProtocolChart.svelte | Same drag-handle changes as IPChart: adds draggable header with grip icon. Identical markup duplication. |
| netflow-webapp/src/lib/components/charts/SpectrumStatsChart.svelte | Same drag-handle pattern applied. Minor structural simplification: removed the wrapper div around the h3 heading. |
| netflow-webapp/src/lib/components/netflow/NetflowDashboard.svelte | Same drag-handle pattern applied to the NetFlow Visualization card header. Consistent with other chart components. |

</details>



<h3>Sequence Diagram</h3>

```mermaid
sequenceDiagram
    participant User
    participant Header as Chart Header (drag handle)
    participant Section as Section [data-chart-card]
    participant Page as +page.svelte state
    participant LS as localStorage

    User->>Header: mousedown + drag
    Header->>Section: dragstart (bubbles)
    Section->>Page: handleChartDragStart(chartId)
    Page->>Page: set draggedChartId, create clone drag image

    User->>Section: drag over target card
    Section->>Page: handleChartDragOver(targetId)
    Page->>Page: set dropTargetChartId → show ring highlight

    alt Drop on different card
        User->>Section: drop
        Section->>Page: handleChartDrop(targetId)
        Page->>Page: moveChartCard(dragged, target)
        Page->>LS: persistChartOrder()
        Page->>Page: clear drag state, remove clone
    else Drag cancelled
        User->>Section: dragend
        Section->>Page: handleChartDragEnd()
        Page->>Page: clear drag state, remove clone
    end

    Note over Page,LS: On mount, loadChartOrder() reads from localStorage
```

<sub>Last reviewed commit: 5851973</sub>

<!-- greptile_other_comments_section -->

**Context used:**

- Context from `dashboard` - .cursor/rules/svelte.mdc ([source](https://app.greptile.com/review/custom-context?memory=591a6ea0-1733-46da-9c1e-60a7c778920e))

<!-- /greptile_comment -->
````

## Parents

- [7c17d05f4078d36c0174fe2bd3e1b480f41c5019](https://git.cafe/flambo/atlantis/commit/7c17d05f4078d36c0174fe2bd3e1b480f41c5019?format=markdown)

- [8b4c5e399b08bfa0fb7ab70d400cdb1513ae1fba](https://git.cafe/flambo/atlantis/commit/8b4c5e399b08bfa0fb7ab70d400cdb1513ae1fba?format=markdown)

[Source at this commit](https://git.cafe/flambo/atlantis/tree/8e7e84510a81f0f68917ee3ddc43ee672bfad55e?format=markdown)
