Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
6 changes: 6 additions & 0 deletions internal/api/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,12 @@ func New(token string) *Client {
return &Client{token: token, http: &http.Client{}, baseURL: BaseURL}
}

// Token is what this client sends. The panel builds a client once, at start,
// and has to build another when a member signs in from inside it - a client
// still holding the token it started with sends an empty cookie and the
// platform answers `unauthorized`, which reads exactly like a failed login.
func (c *Client) Token() string { return c.token }

func (c *Client) get(path string) ([]byte, error) {
base := c.baseURL
if base == "" {
Expand Down
57 changes: 57 additions & 0 deletions internal/tui/config_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import (
"testing"
"time"

tea "github.com/charmbracelet/bubbletea"
"github.com/charmbracelet/lipgloss"

"github.com/nxssie/nan-cli/internal/api"
Expand Down Expand Up @@ -1170,3 +1171,59 @@ func TestSignInKeyIsNotOneThatAlreadyMoves(t *testing.T) {
}
}
}

// Signing in from the panel wrote the session and left the API client holding
// the token it was built with at start-up, which on a fresh machine is none.
// So it signed a member in and then answered every tab `unauthorized` - which
// reads exactly like the login having failed, and was reported as such.
func TestSigningInGivesTheClientTheNewToken(t *testing.T) {
home := t.TempDir()
t.Setenv("HOME", home)
t.Setenv("USERPROFILE", home)
t.Setenv("HERMES_HOME", filepath.Join(home, "h"))

m := newModel(api.New(""), &session.Session{})
if m.client.Token() != "" {
t.Fatal("this test starts from a client with no token")
}

// What the flow leaves on disk before the panel is told about it.
if err := session.Save(&session.Session{Token: "a-fresh-session-token"}); err != nil {
t.Fatal(err)
}

updated, _ := m.Update(signedInMsg{nil})
after := updated.(model)

if after.sess.Token != "a-fresh-session-token" {
t.Errorf("the panel did not pick up the session: %q", after.sess.Token)
}
if got := after.client.Token(); got != "a-fresh-session-token" {
t.Errorf("the client still sends %q, so every tab answers unauthorized", got)
}
if after.loginStage != loginOff {
t.Error("the sign-in is still on screen after it succeeded")
}
if len(after.cache) != 0 {
t.Error("the tabs keep the answers they got before signing in")
}
}

// `e` is published on Home as the way to set the API key, and Home is not
// Setup. It did nothing at all anywhere but Setup - which is the tab you have
// to already be on to know that.
func TestTheKeyForTheKeyWorksFromWhereItIsAdvertised(t *testing.T) {
m := setupModel(t, &session.Session{Token: "t"})
m.lay = newLayout(90, 30)
m.active = tabIndex(tabHome)

updated, _ := m.Update(tea.KeyMsg{Type: tea.KeyRunes, Runes: []rune{'e'}})
after := updated.(model)

if !after.editingKey {
t.Error("e from Home does nothing, which is where Home tells you to press it")
}
if after.activeID() != tabSetup {
t.Error("e opened the key editor without moving to the tab that shows it")
}
}
26 changes: 24 additions & 2 deletions internal/tui/tui.go
Original file line number Diff line number Diff line change
Expand Up @@ -206,6 +206,16 @@ func (m model) Init() tea.Cmd {

func (m model) activeID() tabID { return tabDefs[m.active].id }

// Where a tab sits in the bar, for the keys that jump straight to one.
func tabIndex(id tabID) int {
for i, t := range tabDefs {
if t.id == id {
return i
}
}
return 0
}

// ── update ────────────────────────────────────────────────────────────────────

func (m model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
Expand Down Expand Up @@ -256,6 +266,11 @@ func (m model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
if sess, err := session.Load(); err == nil {
m.sess = sess
}
// And a client that carries it. The old one was built at start-up with
// whatever token existed then - none - so leaving it in place signed a
// member in and then answered every tab `unauthorized`, which reads
// exactly like the login having failed.
m.client = api.New(m.sess.Token)
m.cancelLogin()
m.cache = make(map[tabID]any)
m.err = nil
Expand Down Expand Up @@ -420,7 +435,14 @@ func (m model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
}

case "e":
if !m.showHelp && m.activeID() == tabSetup {
// From any tab. It used to do nothing at all anywhere but Setup,
// which is the tab you have to already be on to know that - and
// Home tells everyone to press `e` from Home.
if !m.showHelp && m.loginStage == loginOff {
if m.activeID() != tabSetup {
m.active = tabIndex(tabSetup)
m.scrollY = 0
}
m.editingKey = true
m.keyInput.SetValue("")
m.keyInput.Focus()
Expand Down Expand Up @@ -2351,7 +2373,7 @@ func (m model) renderSetup(l layout) string {

// ── about renderer ───────────────────────────────────────────────────────────

const Version = "0.1.10"
const Version = "0.1.11"

func renderAbout(l layout) string {
var b strings.Builder
Expand Down
2 changes: 1 addition & 1 deletion scripts/install.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -118,7 +118,7 @@ function Get-LatestVersion {
could not work out the latest version from the GitHub API
it rate limits unauthenticated requests, so this is usually temporary
wait a few minutes, or pick a version yourself:
& ([scriptblock]::Create((irm https://nan.builders/install.ps1))) -Version v0.1.10
& ([scriptblock]::Create((irm https://nan.builders/install.ps1))) -Version v0.1.11
the releases are at https://github.com/$Repo/releases
"@
}
Expand Down
2 changes: 1 addition & 1 deletion scripts/install.sh
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ require_version() {
err "could not work out the latest version from the GitHub API"
err "it rate limits unauthenticated requests, so this is usually temporary"
err "wait a few minutes, or pick a version yourself:"
printf " VERSION=v0.1.10 curl -fsSL https://nan.builders/install | bash
printf " VERSION=v0.1.11 curl -fsSL https://nan.builders/install | bash
" >&2
err "the releases are at https://github.com/$REPO/releases"
exit 1
Expand Down
Loading