mirror of
				https://github.com/shokinn/hosts-go.git
				synced 2025-11-04 12:38:34 +00:00 
			
		
		
		
	Merge pull request #4 from shokinn/codex/implement-phase-3-and-perform-interactive-testing
Add edit mode toggle with entry activation
This commit is contained in:
		
						commit
						250091bb8a
					
				
					 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