summaryrefslogtreecommitdiff
path: root/internal/ui/inspector.go
blob: 600cb173b06fcad555f1d615d12726a05aebb020 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
package ui

import (
	"net/http"
	"sort"
	"strings"

	"fyne.io/fyne/v2"
	"fyne.io/fyne/v2/container"
	"fyne.io/fyne/v2/dialog"
	"fyne.io/fyne/v2/widget"

	"github.com/shiv/internal/store"
	"github.com/shiv/internal/ui/widgets"
)

func showInspectorDialog(tx store.Transaction, win fyne.Window) {
	tabs := container.NewAppTabs()

	if len(tx.ReqHeaders) > 0 {
		tabs.Append(container.NewTabItem("Req Headers", buildHeadersList(tx.ReqHeaders)))
	}
	if len(tx.ReqBody) > 0 {
		body := widgets.NewTextView()
		body.SetWindow(win)
		body.SetText(string(PrettyJSON(tx.ReqBody)))
		tabs.Append(container.NewTabItem("Req Body", body.Build()))
	}

	tabs.Append(container.NewTabItem("Resp Headers", buildHeadersList(tx.RespHeaders)))

	cookies := parseCookies(tx.RespHeaders)
	tabs.Append(container.NewTabItem("Cookies", buildKVTable(cookies)))

	if len(tx.RespBody) > 0 {
		body := widgets.NewTextView()
		body.SetWindow(win)
		ct := tx.RespHeaders.Get("Content-Type")
		if strings.Contains(ct, "application/json") {
			body.SetText(string(PrettyJSON(tx.RespBody)))
			tabs.Append(container.NewTabItem("JSON", body.Build()))
		} else {
			body.SetText(string(tx.RespBody))
			tabs.Append(container.NewTabItem("Resp Body", body.Build()))
		}
	}

	d := dialog.NewCustom("Inspector", "Close", tabs, win)
	d.Resize(fyne.NewSize(700, 500))
	closeOnEscape(win, d.Dismiss)
	d.Show()
}

func parseCookies(headers http.Header) [][2]string {
	var result [][2]string
	for _, line := range headers["Set-Cookie"] {
		parts := strings.SplitN(line, ";", 2)
		cookieParts := strings.SplitN(strings.TrimSpace(parts[0]), "=", 2)
		if len(cookieParts) == 2 {
			result = append(result, [2]string{cookieParts[0], cookieParts[1]})
		} else if len(cookieParts) == 1 {
			result = append(result, [2]string{cookieParts[0], ""})
		}
		if len(parts) > 1 {
			for attr := range strings.SplitSeq(parts[1], ";") {
				attr = strings.TrimSpace(attr)
				if attr == "" {
					continue
				}
				attrParts := strings.SplitN(attr, "=", 2)
				if len(attrParts) == 2 {
					result = append(result, [2]string{"  " + attrParts[0], attrParts[1]})
				} else {
					result = append(result, [2]string{"  " + attrParts[0], ""})
				}
			}
		}
	}
	return result
}

func buildHeadersList(headers http.Header) fyne.CanvasObject {
	keys := make([]string, 0, len(headers))
	for k := range headers {
		keys = append(keys, k)
	}
	sort.Strings(keys)

	var pairs [][2]string
	for _, k := range keys {
		for _, v := range headers[k] {
			pairs = append(pairs, [2]string{k, v})
		}
	}
	return buildKVTable(pairs)
}

func buildKVTable(pairs [][2]string) fyne.CanvasObject {
	if len(pairs) == 0 {
		l := widget.NewLabel("None")
		l.Importance = widget.LowImportance
		return container.NewCenter(l)
	}
	t := widget.NewTable(
		func() (int, int) { return len(pairs), 2 },
		func() fyne.CanvasObject {
			l := widget.NewLabel("")
			l.Truncation = fyne.TextTruncateEllipsis
			return l
		},
		func(id widget.TableCellID, obj fyne.CanvasObject) {
			l := obj.(*widget.Label)
			if id.Col == 0 {
				l.TextStyle = fyne.TextStyle{Bold: true}
				l.SetText(pairs[id.Row][0])
			} else {
				l.TextStyle = fyne.TextStyle{}
				l.SetText(pairs[id.Row][1])
			}
		},
	)
	t.SetColumnWidth(0, 200)
	t.SetColumnWidth(1, 450)
	return t
}