Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
19 commits
Select commit Hold shift + click to select a range
555996b
antigravity: interim changes before upstream sync for task move_tab_e…
Sep 10, 2026
a12ca65
fix(tabs): eliminate dead code branches, fix premature drop, and add …
Sep 10, 2026
37dfa66
fix(tabs): harden drag button detection, prevent stuck drag starvatio…
Sep 10, 2026
3dea606
antigravity: automated changes & plan artifacts for task move_tab_editor
Sep 10, 2026
37284bb
fix(docs): restore root implementation_plan.md and walkthrough.md, re…
Sep 10, 2026
bc1b56a
docs: document root documentation and permission integrity in walkthr…
Sep 10, 2026
0a11b1c
antigravity: interim changes before upstream sync for task move_tab_e…
Sep 10, 2026
81abd83
fix(docs): restore root implementation_plan.md and walkthrough.md to …
Sep 10, 2026
ddd4cfd
fix(updater): remove unused debug import
Sep 10, 2026
2a0ab25
docs: document warning cleanup and documentation integrity verification
Sep 10, 2026
349d8b8
antigravity: automated changes & plan artifacts for task move_tab_editor
Sep 10, 2026
b1bb288
fix(docs): restore root implementation_plan.md and walkthrough.md and…
Sep 10, 2026
31f3fd9
antigravity: interim changes before upstream sync for task move_tab_e…
Sep 10, 2026
ddd17f6
antigravity: automated changes & plan artifacts for task move_tab_editor
Sep 10, 2026
c6ddadb
fix(perms): restore script executable permissions to 100644
Sep 10, 2026
e1d6921
docs(tabs): add test execution results and usage guide to walkthrough
Sep 10, 2026
2d184dc
antigravity: automated changes & plan artifacts for task move_tab_editor
Sep 10, 2026
b5f9e17
feat: add comprehensive logging and unit tests for tab reordering and…
Sep 10, 2026
6f6dd1b
Merge branch 'origin/main' into move_tab_editor
Sep 10, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 16 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,15 +31,30 @@ Tabular is a lightweight, native database client built with the `eframe`/`egui`
- **Integrated HTTP Client**: REST API tester supporting JSON, form-data, custom auth, headers, and code export
- **Smart Sidebar Tree Search**: Case-insensitive instant filtering across Connections, Queries, History, and HTTP Collections. When searching for a folder name, the folder and all of its contents (connections, queries, history entries, subfolders) remain fully displayed and automatically expanded.
- **AI Assistant (`Cmd+Shift+A`)**: Schema-aware SQL completion with OpenAI, Anthropic Claude, Groq, GitHub Copilot, or custom endpoints
- **Editor Tab Drag & Drop Reordering & Pin Tab**: Group and reorder tabs via intuitive horizontal drag-and-drop, pin important queries/tables with 📌, prevent accidental closures, and manage tabs with full context menus

---

### Editor Tab Drag & Drop & Tab Pinning (New in v0.15)
Organize and group editor tabs seamlessly to enhance workflow when dealing with many queries, tables, and API requests.
- **Interactive Drag-and-Drop Reordering**: Drag tabs horizontally to reorder them and group related tabs together. Visual feedback includes grabbing cursor, floating badge tooltip with tab title, and a real-time vertical insertion indicator line between candidate slots.
- **Pin Tab (📌)**: Pin essential tabs to keep them docked on the left side of the tab bar. Pinned tabs feature a distinctive 📌 indicator, warm styling tint, and an optional separator dividing pinned from unpinned tabs.
- **Accidental Close Prevention**: Pinned tabs replace the "×" close button with the pin icon so they cannot be accidentally closed during rapid navigation. Clicking the pin icon directly unpins the tab.
- **Quick Hover Pin Button**: Hovering over any unpinned tab reveals a convenient quick-pin button beside the close icon.
- **Smart Boundary Synchronization**: Dragging an unpinned tab into the pinned region automatically pins it, and dragging a pinned tab past the pinned zone automatically unpins it.
- **Full Tab Context Menu**: Right-click on any tab to access:
- 📌 **Pin Tab** / 📌 **Unpin Tab**
- ⬅ **Move Tab Left** / ➡ **Move Tab Right**
- ✕ **Close Tab**
- **Close Other Tabs** (safely preserves pinned tabs)
- **Close Tabs to the Right** (safely preserves pinned tabs)
- **Middle-Click to Close**: Middle-clicking any unpinned tab quickly closes it.

### Smart Sidebar Tree Search & Folder Content Preservation
Instant in-memory filtering for all sidebar navigation panels (Connections, Saved Queries, History, and HTTP Collections).
- **Folder Search Preservation**: When typing a search query matching a folder name (such as custom connection folders, query categories, date folders, or HTTP collection folders), the matching folder is displayed and automatically expanded with all of its child contents intact.
- **Hierarchical Context**: When searching for specific tables, queries, or history items, the sidebar displays matching items while maintaining their parent directory structure for clear visual context.


### Visual Query Profiler (New in v0.13)
Analyze and optimize slow queries with interactive visual graphs instead of deciphering raw JSON outputs.
- Supports PostgreSQL (`EXPLAIN (ANALYZE, BUFFERS, FORMAT JSON)`), MySQL (`EXPLAIN FORMAT=JSON`), and Microsoft SQL Server ShowPlan.
Expand Down
92 changes: 92 additions & 0 deletions implementation_plan_move_tab_editor.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
# Rencana Teknis Implementasi: Drag & Drop Tab Editor & Fitur Pin Tab

Dokumen ini menjelaskan rancangan teknis dan arsitektur fitur **Drag & Drop Tab Editor** dan **Pin Tab** pada Tabular, termasuk perbaikan hasil adversarial code review.

---

## 1. Analisis Kebutuhan (Requirements Analysis)

### 1.1 Latar Belakang & Masalah
Saat bekerja dengan banyak tab query SQL, tabel basis data, dan endpoint HTTP, pengguna memerlukan mekanisme untuk:
1. Mengelompokkan tab-tab yang saling terkait secara bebas dengan menggeser/menyeret tab (drag-and-drop).
2. Menyematkan (pin) tab penting agar selalu berada di posisi kiri tab bar dan terlindungi dari penutupan massal atau tidak sengaja.
3. Menyediakan kontrol navigasi tab lengkap melalui menu konteks (klik kanan) dan shortcut mouse (middle-click).

### 1.2 Ruang Lingkup Fitur
1. **Interactive Drag-and-Drop Tab Reordering**:
- Mendukung penyeretan tab horizontal secara visual.
- Ghost badge melayang mengikuti posisi kursor dengan ikon status (📌 / 📑) dan judul tab.
- Indikator garis vertikal interaktif dengan aksen warna tema menandai slot penyisipan tab target.
- Pembatalan drag secara mulus melalui penekanan tombol `Escape` atau menyeret kursor keluar dari batas vertikal tab bar.
- Deteksi tombol mouse primer (`PointerButton::Primary`) guna mencegah pemicuan drop prematur dari tombol mouse lain.

2. **Fitur Pin Tab (📌)**:
- Status `is_pinned: bool` pada setiap objek `QueryTab`.
- Tab yang disematkan terkumpul rapi di sebelah kiri tab bar sebelum tab-tab biasa (unpinned).
- Tombol close ("×") digantikan ikon pin ("📌") pada tab yang dipin untuk mencegah penutupan tak sengaja.
- Tombol quick-pin muncul saat hover pada tab unpinned.
- Garis pemisah vertikal membedakan grup tab pinned dengan unpinned.
- Sinkronisasi otomatis saat drag-and-drop: tab biasa yang diseret masuk ke area pinned otomatis menjadi pinned, dan sebaliknya.

3. **Menu Konteks & Aksi Tab Lengkap**:
- 📌 **Pin Tab** / 📌 **Unpin Tab**
- ⬅ **Move Tab Left** / ➡ **Move Tab Right**
- ✕ **Close Tab**
- **Close Other Tabs** (melindungi tab yang sedang dipin)
- **Close Tabs to the Right** (melindungi tab yang sedang dipin)
- Middle-click untuk menutup tab unpinned.

---

## 2. Perubahan Arsitektur & Struktur Berkas

### 2.1 Model Data (`src/models/structs.rs`)
- Menambahkan field `pub is_pinned: bool` pada struct `QueryTab`.
- Default bernilai `false` pada instansiasi tab baru.

### 2.2 Logika Tab Management (`src/editor.rs`)
- `move_tab(tabular: &mut Tabular, from: usize, to: usize)`:
- Memindahkan posisi tab langsung pada vektor `query_tabs`.
- Menyesuaikan `active_tab_index` secara matematis tanpa merusak fokus aktif pengguna.
- Memperbarui status `is_pinned` saat tab melintasi batas pemisah pinned/unpinned.
- `reorder_tab(tabular: &mut Tabular, from: usize, insert_at: usize)`:
- Mengonversi slot penyisipan UI (0..=n) ke indeks target pemindahan.
- `pin_tab(tabular: &mut Tabular, tab_index: usize)`:
- Menandai tab sebagai pinned dan memindahkannya ke akhir grup pinned.
- Menyesuaikan `active_tab_index` secara tepat tanpa dead code branch.
- `unpin_tab(tabular: &mut Tabular, tab_index: usize)`:
- Melepas pin tab dan memindahkannya ke posisi setelah seluruh tab pinned yang tersisa.
- Menyesuaikan `active_tab_index` secara tepat tanpa dead code branch.
- `toggle_pin_tab(tabular: &mut Tabular, tab_index: usize)`:
- Toggle antara `pin_tab` dan `unpin_tab`.
- `close_other_tabs(tabular: &mut Tabular, keep_index: usize)`:
- Menutup semua tab kecuali tab target dan seluruh tab yang berstatus pinned.
- `close_tabs_to_the_right(tabular: &mut Tabular, tab_index: usize)`:
- Menutup seluruh tab unpinned di sebelah kanan `tab_index`.

### 2.3 Antarmuka GUI (`src/window_egui/app_impl.rs`)
- Menambahkan field `dragged_tab_index: Option<usize>` pada state `Tabular`.
- Render strip tab dengan alokasi drag & click (`egui::Sense::click_and_drag()`).
- Deteksi pelepasan tombol primer (`PointerButton::Primary`).
- Pengecekan batas vertikal (`is_within_tab_bar_y`) dengan toleransi margin 20px agar pengguna dapat membatalkan drag dengan menggeser pointer keluar tab bar.
- Repaint rendering loop saat mouse dilepaskan untuk menjamin responsivitas UI instan.

---

## 3. Hasil Perbaikan Adversarial Code Review

1. **Pembersihan Dead Code pada `pin_tab`**:
- Menghilangkan cabang kontradiktif `else if tab_index < first_unpinned` di dalam blok `if tab_index > first_unpinned`.
2. **Pembersihan Dead Code pada `unpin_tab`**:
- Menghilangkan cabang unreachable `else` di dalam blok `if tab_index < last_p`.
3. **Pembersihan Dead Logic pada `close_tabs_to_the_right`**:
- Menghapus decrement indeks yang redundan (`tabular.active_tab_index >= i`) yang mustahil terpenuhi.
4. **Pencegahan Premature Drop**:
- Mengganti `any_released()` dengan `button_released(egui::PointerButton::Primary)`.
5. **Validasi Batas Vertikal**:
- Menambahkan `is_within_tab_bar_y` pada kalkulasi slot drop `candidate_insert_at`.
6. **Pemicuan Drag Tombol Non-Primer**:
- Membatasi inisiasi drag hanya pada tombol mouse primer melalui `drag_started_by(egui::PointerButton::Primary)`.
7. **Pencegahan Starvation / UI Stuck State**:
- Menambahkan mekanisme reset `self.dragged_tab_index = None` saat pointer primer tidak lagi ditekan (`!primary_down`) atau saat jumlah tab berubah.

Loading
Loading