mirror of
https://github.com/shokinn/hosts-go.git
synced 2025-08-23 08:33:02 +00:00
Add edit mode toggle and entry activation
This commit is contained in:
parent
0c60248d75
commit
51966f766c
6 changed files with 69 additions and 17 deletions
|
@ -111,3 +111,8 @@ func (m Model) SelectedEntry() *core.HostEntry {
|
||||||
}
|
}
|
||||||
return m.hosts.Entries[idx]
|
return m.hosts.Entries[idx]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Mode returns the current operating mode of the TUI.
|
||||||
|
func (m Model) Mode() Mode {
|
||||||
|
return m.mode
|
||||||
|
}
|
||||||
|
|
|
@ -18,6 +18,20 @@ func (m Model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
|
||||||
} else {
|
} else {
|
||||||
m.focus = listPane
|
m.focus = listPane
|
||||||
}
|
}
|
||||||
|
case "e":
|
||||||
|
if m.mode == ViewMode {
|
||||||
|
m.mode = EditMode
|
||||||
|
} else {
|
||||||
|
m.mode = ViewMode
|
||||||
|
}
|
||||||
|
case "a":
|
||||||
|
if m.mode == EditMode {
|
||||||
|
if entry := m.SelectedEntry(); entry != nil {
|
||||||
|
entry.Active = !entry.Active
|
||||||
|
m.list.SetItem(m.list.Index(), entryItem{entry})
|
||||||
|
m.refreshDetail()
|
||||||
|
}
|
||||||
|
}
|
||||||
case "up", "k":
|
case "up", "k":
|
||||||
if m.focus == detailPane {
|
if m.focus == detailPane {
|
||||||
m.detail.LineUp(1)
|
m.detail.LineUp(1)
|
||||||
|
|
|
@ -47,7 +47,11 @@ func (m Model) View() string {
|
||||||
|
|
||||||
// join panes and status bar
|
// join panes and status bar
|
||||||
panes := lipgloss.JoinHorizontal(lipgloss.Top, left, right)
|
panes := lipgloss.JoinHorizontal(lipgloss.Top, left, right)
|
||||||
status := fmt.Sprintf("VIEW MODE • %d entries", len(m.hosts.Entries))
|
modeLabel := "VIEW"
|
||||||
|
if m.mode == EditMode {
|
||||||
|
modeLabel = "EDIT"
|
||||||
|
}
|
||||||
|
status := fmt.Sprintf("%s MODE • %d entries", modeLabel, len(m.hosts.Entries))
|
||||||
bar := statusStyle.Width(m.width).Render(status)
|
bar := statusStyle.Width(m.width).Render(status)
|
||||||
return lipgloss.JoinVertical(lipgloss.Left, panes, bar)
|
return lipgloss.JoinVertical(lipgloss.Left, panes, bar)
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,8 +2,8 @@
|
||||||
|
|
||||||
## Current Work Focus
|
## Current Work Focus
|
||||||
|
|
||||||
**Status**: Phase 2 Complete - Basic TUI prototype finished
|
**Status**: Phase 3 In Progress - Edit mode basics implemented
|
||||||
**Priority**: Begin Phase 3 - Edit mode and file integration
|
**Priority**: Expand Phase 3 with file integration and advanced editing
|
||||||
|
|
||||||
## Recent Changes
|
## Recent Changes
|
||||||
|
|
||||||
|
@ -23,6 +23,11 @@
|
||||||
- ✅ **View mode** showing entry details and status bar
|
- ✅ **View mode** showing entry details and status bar
|
||||||
- ✅ **Parser integration** loading `/etc/hosts` into the UI
|
- ✅ **Parser integration** loading `/etc/hosts` into the UI
|
||||||
|
|
||||||
|
### Phase 3: Edit Mode (IN PROGRESS)
|
||||||
|
- 🔄 **Edit mode toggle** via 'e' key with status bar indication
|
||||||
|
- 🔄 **Entry activation toggle** using 'a' key
|
||||||
|
- 🔄 **Model tests** covering edit mode behavior
|
||||||
|
|
||||||
### Parser Capabilities Achieved
|
### Parser Capabilities Achieved
|
||||||
- ✅ **Standard entries**: IPv4, IPv6, multiple aliases, inline comments
|
- ✅ **Standard entries**: IPv4, IPv6, multiple aliases, inline comments
|
||||||
- ✅ **Disabled entries**: Commented lines with `# IP hostname` format detection
|
- ✅ **Disabled entries**: Commented lines with `# IP hostname` format detection
|
||||||
|
@ -43,19 +48,19 @@
|
||||||
|
|
||||||
### Immediate (Phase 3 - Current Priority)
|
### Immediate (Phase 3 - Current Priority)
|
||||||
1. **Edit Mode Implementation**
|
1. **Edit Mode Implementation**
|
||||||
- Explicit mode transition with visual indicators
|
- ✅ Explicit mode transition with visual indicators
|
||||||
- Permission handling with sudo request
|
- 🔄 Permission handling with sudo request
|
||||||
- Entry modification forms with validation
|
- 🔄 Entry modification forms with validation
|
||||||
|
|
||||||
2. **File Integration**
|
2. **File Integration**
|
||||||
- Connect TUI with existing parser functionality for writes
|
- 🔄 Connect TUI with existing parser functionality for writes
|
||||||
- Real-time display of actual `/etc/hosts` content
|
- 🔄 Real-time display of actual `/etc/hosts` content
|
||||||
- Live validation and formatting preview
|
- 🔄 Live validation and formatting preview
|
||||||
|
|
||||||
3. **Advanced Features**
|
3. **Advanced Features**
|
||||||
- Entry toggle (activate/deactivate)
|
- ✅ Entry toggle (activate/deactivate)
|
||||||
- Add/edit/delete operations
|
- 🔄 Add/edit/delete operations
|
||||||
- Sorting and filtering capabilities
|
- 🔄 Sorting and filtering capabilities
|
||||||
|
|
||||||
## Active Decisions and Considerations
|
## Active Decisions and Considerations
|
||||||
|
|
||||||
|
|
|
@ -53,9 +53,10 @@
|
||||||
- [x] **Integration**: Connect TUI with existing parser functionality
|
- [x] **Integration**: Connect TUI with existing parser functionality
|
||||||
|
|
||||||
### 🔧 Edit Functionality (Phase 3)
|
### 🔧 Edit Functionality (Phase 3)
|
||||||
- [ ] **Edit mode transition**: Explicit mode switching with visual indicators
|
- [x] **Edit mode transition**: Explicit mode switching with visual indicators
|
||||||
- [ ] **Permission handling**: Request sudo access when entering edit mode
|
- [ ] **Permission handling**: Request sudo access when entering edit mode
|
||||||
- [ ] **Entry modification**: Add, edit, delete, toggle active status
|
- [x] **Entry modification**: Toggle active status
|
||||||
|
- [ ] **Entry modification**: Add, edit, delete operations
|
||||||
- [ ] **File writing**: Atomic updates with backup and rollback
|
- [ ] **File writing**: Atomic updates with backup and rollback
|
||||||
- [ ] **Input validation**: Real-time validation of IP and hostname inputs
|
- [ ] **Input validation**: Real-time validation of IP and hostname inputs
|
||||||
|
|
||||||
|
@ -67,7 +68,7 @@
|
||||||
- [ ] **Search/filter**: Find entries quickly in large files
|
- [ ] **Search/filter**: Find entries quickly in large files
|
||||||
|
|
||||||
### 🧪 Testing & Quality (Ongoing)
|
### 🧪 Testing & Quality (Ongoing)
|
||||||
- [ ] **TUI tests**: User interactions, state transitions
|
- [x] **TUI tests**: User interactions, state transitions
|
||||||
- [ ] **Integration tests**: Complete TUI workflows with file operations
|
- [ ] **Integration tests**: Complete TUI workflows with file operations
|
||||||
- [ ] **Permission tests**: sudo scenarios, graceful degradation
|
- [ ] **Permission tests**: sudo scenarios, graceful degradation
|
||||||
- [ ] **End-to-end tests**: Full application workflows
|
- [ ] **End-to-end tests**: Full application workflows
|
||||||
|
@ -75,8 +76,8 @@
|
||||||
## Current Status
|
## Current Status
|
||||||
|
|
||||||
### Project Phase: **Phase 2 Complete → Phase 3 (Edit Mode Implementation)**
|
### Project Phase: **Phase 2 Complete → Phase 3 (Edit Mode Implementation)**
|
||||||
- **Completion**: ~75% (parser and basic TUI implemented)
|
- **Completion**: ~80% (parser, TUI, and basic edit mode implemented)
|
||||||
- **Active work**: Begin edit mode and file integration (Phase 3)
|
- **Active work**: Expand edit mode with file integration and advanced editing
|
||||||
- **Blockers**: None - comprehensive parser foundation with 54 tests completed
|
- **Blockers**: None - comprehensive parser foundation with 54 tests completed
|
||||||
- **Parser status**: Production-ready with all safety features implemented
|
- **Parser status**: Production-ready with all safety features implemented
|
||||||
|
|
||||||
|
|
|
@ -62,3 +62,26 @@ func TestPaneSwitching(t *testing.T) {
|
||||||
m = nm.(tui.Model)
|
m = nm.(tui.Model)
|
||||||
assert.Equal(t, "localhost", m.SelectedEntry().Hostname)
|
assert.Equal(t, "localhost", m.SelectedEntry().Hostname)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestEditModeToggleAndActivation(t *testing.T) {
|
||||||
|
sample := "127.0.0.1 localhost\n192.168.1.10 example.com"
|
||||||
|
lines := strings.Split(sample, "\n")
|
||||||
|
hf, _, err := core.ParseHostsContent(lines)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
m := tui.NewModel(hf)
|
||||||
|
|
||||||
|
// enter edit mode
|
||||||
|
nm, _ := m.Update(tea.KeyMsg{Type: tea.KeyRunes, Runes: []rune{'e'}})
|
||||||
|
m = nm.(tui.Model)
|
||||||
|
assert.Equal(t, tui.EditMode, m.Mode())
|
||||||
|
|
||||||
|
// toggle active state of first entry
|
||||||
|
nm, _ = m.Update(tea.KeyMsg{Type: tea.KeyRunes, Runes: []rune{'a'}})
|
||||||
|
m = nm.(tui.Model)
|
||||||
|
assert.False(t, m.SelectedEntry().Active)
|
||||||
|
|
||||||
|
// status bar should reflect edit mode
|
||||||
|
view := m.View()
|
||||||
|
assert.Contains(t, view, "EDIT MODE")
|
||||||
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue