Remove scope page

Signed-off-by: Hadi <112569860+anotherhadi@users.noreply.github.com>
This commit is contained in:
Hadi
2026-05-12 22:01:29 +02:00
parent 329216c082
commit 7879720d07
15 changed files with 30 additions and 489 deletions
-7
View File
@@ -22,7 +22,6 @@ import (
interceptUI "github.com/anotherhadi/spilltea/internal/ui/intercept"
pluginsUI "github.com/anotherhadi/spilltea/internal/ui/plugins"
replayUI "github.com/anotherhadi/spilltea/internal/ui/replay"
scopeUI "github.com/anotherhadi/spilltea/internal/ui/scope"
"github.com/sirupsen/logrus"
)
@@ -64,7 +63,6 @@ type Model struct {
replay replayUI.Model
diff diffUI.Model
docs docsUI.Model
scope scopeUI.Model
pluginsPage pluginsUI.Model
findingsPage findingsUI.Model
copyAs copyasUI.Model
@@ -86,7 +84,6 @@ func New(broker *intercept.Broker, name, path string) Model {
replay: replayUI.New(),
diff: diffUI.New(),
docs: docsUI.New(),
scope: scopeUI.New(name, path),
pluginsPage: pluginsUI.New(mgr),
findingsPage: findingsUI.New(),
copyAs: copyasUI.New(),
@@ -101,10 +98,6 @@ func New(broker *intercept.Broker, name, path string) Model {
m.replay.SetDB(d)
m.findingsPage.SetDB(d)
mgr.SetDB(d)
if wl, bl, err := d.LoadScope(); err == nil {
broker.SetScope(wl, bl)
m.scope.SetScope(wl, bl)
}
}
pluginsDir := config.ExpandPath(cfg.App.PluginsDir)
-15
View File
@@ -10,7 +10,6 @@ import (
interceptUI "github.com/anotherhadi/spilltea/internal/ui/intercept"
pluginsUI "github.com/anotherhadi/spilltea/internal/ui/plugins"
replayUI "github.com/anotherhadi/spilltea/internal/ui/replay"
scopeUI "github.com/anotherhadi/spilltea/internal/ui/scope"
)
type page string
@@ -20,7 +19,6 @@ const (
pageHistory page = "History"
pageReplay page = "Replay"
pageDiff page = "Diff"
pageScopes page = "Scopes"
pagePlugins page = "Plugins"
pageFindings page = "Findings"
pageDocs page = "Docs"
@@ -93,19 +91,6 @@ var pageRegistry = []pageEntry{
},
resize: func(m *Model, w, h int) { m.diff.SetSize(w, h) },
},
{
id: pageScopes,
icon: func() string { return icons.I.Scope },
render: func(m *Model) string { return m.scope.View().Content },
update: func(m *Model, msg tea.Msg) tea.Cmd {
updated, cmd := m.scope.Update(msg)
m.scope = updated.(scopeUI.Model)
return cmd
},
isEditing: func(m *Model) bool { return m.scope.IsEditing() },
resize: func(m *Model, w, h int) { m.scope.SetSize(w, h) },
},
{
id: pagePlugins,
icon: func() string { return icons.I.Plugin },
-10
View File
@@ -20,7 +20,6 @@ import (
historyUI "github.com/anotherhadi/spilltea/internal/ui/history"
interceptUI "github.com/anotherhadi/spilltea/internal/ui/intercept"
replayUI "github.com/anotherhadi/spilltea/internal/ui/replay"
scopeUI "github.com/anotherhadi/spilltea/internal/ui/scope"
)
func (m Model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
@@ -79,15 +78,6 @@ func (m Model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
m.height = msg.Height
m.resizeChildren()
case scopeUI.ScopeChangedMsg:
m.broker.SetScope(msg.Whitelist, msg.Blacklist)
if m.database != nil {
if err := m.database.SaveScope(msg.Whitelist, msg.Blacklist); err != nil {
log.Printf("failed to persist scope: %v", err)
}
}
return m, nil
case proxyPkg.ErrMsg:
if msg.Err != nil {
log.Printf("proxy error: %v", msg.Err)
-1
View File
@@ -19,7 +19,6 @@ var contentMarkdown = strings.Join([]string{
readDoc("proxy.md"),
readDoc("certificate.md"),
readDoc("history.md"),
readDoc("scopes.md"),
}, "\n")
type Model struct {
-150
View File
@@ -1,150 +0,0 @@
package scope
import (
"strings"
"charm.land/bubbles/v2/help"
"charm.land/bubbles/v2/key"
"charm.land/bubbles/v2/textarea"
tea "charm.land/bubbletea/v2"
"charm.land/lipgloss/v2"
"github.com/anotherhadi/spilltea/internal/keys"
"github.com/anotherhadi/spilltea/internal/style"
)
const (
fieldNone = -1
fieldWhitelist = 0
fieldBlacklist = 1
)
const (
minTaH = 3
maxTaH = 12
fixedH = 8 // (blank + label + desc + blank) x2
)
type ScopeChangedMsg struct {
Whitelist []string
Blacklist []string
}
type Model struct {
focusIdx int
wlTextarea textarea.Model
blTextarea textarea.Model
innerH int
width int
height int
help help.Model
}
func New(name, path string) Model {
wl := style.NewTextarea(true)
wl.Placeholder = "one pattern per line..."
bl := style.NewTextarea(true)
bl.Placeholder = "one pattern per line..."
bl.Blur()
return Model{
focusIdx: fieldNone,
wlTextarea: wl,
blTextarea: bl,
help: style.NewHelp(),
}
}
func (m Model) Init() tea.Cmd { return nil }
func (m *Model) SetScope(whitelist, blacklist []string) {
m.wlTextarea.SetValue(strings.Join(whitelist, "\n"))
m.blTextarea.SetValue(strings.Join(blacklist, "\n"))
}
func (m *Model) SetSize(w, h int) {
m.width = w
m.height = h
m.syncLayout()
}
func (m *Model) syncLayout() {
if m.width == 0 {
return
}
m.help.SetWidth(m.width - 2)
statusH := strings.Count(m.renderStatusBar(), "\n") + 1
panelH := m.height - statusH
m.innerH = max(1, style.PanelContentH(panelH))
taH := (m.innerH - fixedH) / 2
if taH < minTaH {
taH = minTaH
}
if taH > maxTaH {
taH = maxTaH
}
// width - 2 (panel border) - 1 (leading space in view) - 3 (right margin + cursor)
taW := max(1, m.width-6)
m.wlTextarea.SetWidth(taW)
m.wlTextarea.SetHeight(taH)
m.blTextarea.SetWidth(taW)
m.blTextarea.SetHeight(taH)
}
func (m Model) IsEditing() bool {
return m.focusIdx == fieldWhitelist || m.focusIdx == fieldBlacklist
}
func (m *Model) scopeChangedCmd() tea.Cmd {
wl := parseLines(m.wlTextarea.Value())
bl := parseLines(m.blTextarea.Value())
return func() tea.Msg {
return ScopeChangedMsg{Whitelist: wl, Blacklist: bl}
}
}
func parseLines(s string) []string {
var out []string
for _, line := range strings.Split(s, "\n") {
if t := strings.TrimSpace(line); t != "" {
out = append(out, t)
}
}
return out
}
func (m Model) renderStatusBar() string {
return lipgloss.NewStyle().Padding(0, 1).Render(
m.help.View(formKeyMap{focusIdx: m.focusIdx}),
)
}
type formKeyMap struct {
focusIdx int
}
func (k formKeyMap) ShortHelp() []key.Binding {
cycle := keys.Keys.Global.CycleFocus
hlp := keys.Keys.Global.Help
switch k.focusIdx {
case fieldWhitelist, fieldBlacklist:
esc := keys.Keys.Global.Escape
escBinding := key.NewBinding(key.WithKeys(esc.Keys()...), key.WithHelp(esc.Help().Key, "unfocus"))
return []key.Binding{
key.NewBinding(key.WithKeys("enter"), key.WithHelp("enter", "new line")),
escBinding,
cycle,
}
}
return []key.Binding{cycle, hlp}
}
func (k formKeyMap) FullHelp() [][]key.Binding {
return [][]key.Binding{k.ShortHelp()}
}
-70
View File
@@ -1,70 +0,0 @@
package scope
import (
"charm.land/bubbles/v2/key"
tea "charm.land/bubbletea/v2"
"github.com/anotherhadi/spilltea/internal/keys"
)
func (m Model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
kp, isKey := msg.(tea.KeyPressMsg)
if !isKey {
return m, nil
}
if key.Matches(kp, keys.Keys.Global.CycleFocus) {
return m.cycleFocus()
}
if key.Matches(kp, keys.Keys.Global.Help) && !m.IsEditing() {
m.help.ShowAll = !m.help.ShowAll
return m, nil
}
switch m.focusIdx {
case fieldWhitelist:
if key.Matches(kp, keys.Keys.Global.Escape) {
return m.blurAll()
}
var cmd tea.Cmd
m.wlTextarea, cmd = m.wlTextarea.Update(kp)
return m, cmd
case fieldBlacklist:
if key.Matches(kp, keys.Keys.Global.Escape) {
return m.blurAll()
}
var cmd tea.Cmd
m.blTextarea, cmd = m.blTextarea.Update(kp)
return m, cmd
}
return m, nil
}
func (m Model) blurAll() (tea.Model, tea.Cmd) {
m.wlTextarea.Blur()
m.blTextarea.Blur()
m.focusIdx = fieldNone
m.syncLayout()
return m, m.scopeChangedCmd()
}
func (m Model) cycleFocus() (tea.Model, tea.Cmd) {
scopeCmd := m.scopeChangedCmd()
var focusCmd tea.Cmd
switch m.focusIdx {
case fieldNone, fieldBlacklist:
m.blTextarea.Blur()
m.focusIdx = fieldWhitelist
focusCmd = m.wlTextarea.Focus()
case fieldWhitelist:
m.wlTextarea.Blur()
m.focusIdx = fieldBlacklist
focusCmd = m.blTextarea.Focus()
}
m.syncLayout()
return m, tea.Batch(focusCmd, scopeCmd)
}
-84
View File
@@ -1,84 +0,0 @@
package scope
import (
"strings"
tea "charm.land/bubbletea/v2"
"charm.land/lipgloss/v2"
"github.com/anotherhadi/spilltea/internal/icons"
"github.com/anotherhadi/spilltea/internal/style"
)
func (m Model) View() tea.View {
if m.width == 0 {
return tea.NewView("")
}
s := style.S
statusBar := m.renderStatusBar()
statusH := strings.Count(statusBar, "\n") + 1
panelH := m.height - statusH
innerH := max(1, style.PanelContentH(panelH))
taH := (innerH - fixedH) / 2
if taH < minTaH {
taH = minTaH
}
if taH > maxTaH {
taH = maxTaH
}
var lines []string
add := func(l string) { lines = append(lines, l) }
add("")
add(fieldLabel("Whitelist", m.focusIdx == fieldWhitelist))
add(" " + s.Faint.Render("If non-empty, only matching requests are intercepted."))
add("")
wlContentLines := strings.Count(m.wlTextarea.Value(), "\n") + 1
for _, l := range taLines(m.wlTextarea.View(), taH, wlContentLines) {
add(" " + l)
}
add("")
add(fieldLabel("Blacklist", m.focusIdx == fieldBlacklist))
add(" " + s.Faint.Render("Matching requests are always excluded from history."))
add("")
blContentLines := strings.Count(m.blTextarea.Value(), "\n") + 1
for _, l := range taLines(m.blTextarea.View(), taH, blContentLines) {
add(" " + l)
}
for len(lines) < innerH {
lines = append(lines, "")
}
content := strings.Join(lines[:innerH], "\n")
panel := style.RenderWithTitle(s.PanelFocused, icons.I.Scope+"Scopes", content, m.width, panelH)
return tea.NewView(lipgloss.JoinVertical(lipgloss.Left, panel, statusBar))
}
func fieldLabel(name string, focused bool) string {
s := style.S
c := s.MutedFg
if focused {
c = s.Primary
}
return " " + lipgloss.NewStyle().Foreground(c).Bold(focused).Render(name)
}
func taLines(view string, h int, contentLines int) []string {
raw := strings.Split(strings.TrimRight(view, "\n"), "\n")
tilde := style.S.Faint.Render("~")
for len(raw) < h {
raw = append(raw, tilde)
}
if len(raw) > h {
raw = raw[:h]
}
for i := contentLines; i < len(raw); i++ {
raw[i] = tilde
}
return raw
}