Skip to content

Commit e8c0c49

Browse files
committed
fix(codex-auth): keep tickets beside next-session badge
1 parent 54e73bf commit e8c0c49

4 files changed

Lines changed: 25 additions & 7 deletions

File tree

devlog/290_rate-limit-reset-credits/02_ui-spec.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -248,6 +248,8 @@ function TicketBadge({ account, onClick }: { account: AccountEntry; onClick: ()
248248
Uses `<button>` instead of `<span>` for accessibility (keyboard focus, screen reader).
249249
The `badge-clickable` class must not override `background`, `border`, or `font`;
250250
the visual badge variant (`badge-amber`, `badge-muted`, `badge-primary`) owns those styles.
251+
Ticket, plan, and session-state badges must render inside the same `card-badges`
252+
inline-flex group, so a reset ticket never replaces or overlaps `NEXT SESSION`.
251253

252254
### Reset Credit Popup (new modal, after existing confirm modal)
253255

gui/src/pages/CodexAuth.tsx

Lines changed: 11 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -159,9 +159,11 @@ export default function CodexAuth({ apiBase }: { apiBase: string }) {
159159
<div className="card-head">
160160
<span className="dot dot-green" />
161161
<strong>{t("codexAuth.mainAccount")}</strong>
162-
{main && <TicketBadge account={{ ...main, id: "__main__" } as AccountEntry} onClick={() => openResetPopup({ ...main, id: "__main__" } as AccountEntry)} />}
163-
<span className={`badge ${!activeId ? "badge-primary" : "badge-muted"}`}>
164-
{!activeId ? t("codexAuth.nextSession") : t("codexAuth.current")}
162+
<span className="card-badges">
163+
{main && <TicketBadge account={{ ...main, id: "__main__" } as AccountEntry} onClick={() => openResetPopup({ ...main, id: "__main__" } as AccountEntry)} />}
164+
<span className={`badge ${!activeId ? "badge-primary" : "badge-muted"}`}>
165+
{!activeId ? t("codexAuth.nextSession") : t("codexAuth.current")}
166+
</span>
165167
</span>
166168
<span className="card-right"><IconLock width={14} /> {t("codexAuth.appLogin")}</span>
167169
</div>
@@ -185,10 +187,12 @@ export default function CodexAuth({ apiBase }: { apiBase: string }) {
185187
<div className="card-head">
186188
<span className={`dot ${a.needsReauth ? "dot-amber" : isNext(a.id) ? "dot-blue" : "dot-muted"}`} />
187189
<strong>{a.email}</strong>
188-
{a.plan && <span className="badge badge-green">{a.plan}</span>}
189-
<TicketBadge account={a} onClick={() => openResetPopup(a)} />
190-
{a.needsReauth && <span className="badge badge-amber">{t("codexAuth.needsReauth")}</span>}
191-
{isNext(a.id) && !a.needsReauth && <span className="badge badge-primary">{t("codexAuth.nextSession")}</span>}
190+
<span className="card-badges">
191+
{a.plan && <span className="badge badge-green">{a.plan}</span>}
192+
<TicketBadge account={a} onClick={() => openResetPopup(a)} />
193+
{a.needsReauth && <span className="badge badge-amber">{t("codexAuth.needsReauth")}</span>}
194+
{isNext(a.id) && !a.needsReauth && <span className="badge badge-primary">{t("codexAuth.nextSession")}</span>}
195+
</span>
192196
<button
193197
className="btn-icon btn-icon-danger card-right"
194198
aria-label={t("common.remove")}

gui/src/styles.css

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -191,6 +191,8 @@ input[type="checkbox"], input[type="radio"] { accent-color: var(--accent); }
191191
.badge-clickable { cursor: pointer; transition: filter 0.12s; appearance: none; }
192192
.badge-clickable:hover { filter: brightness(1.1); }
193193
.badge-disabled { opacity: 0.5; cursor: default; }
194+
.card-badges { display: inline-flex; align-items: center; gap: 8px; flex-wrap: wrap; min-width: 0; }
195+
.card-badges .badge { flex-shrink: 0; }
194196
.confirm-icon { width: 44px; height: 44px; border-radius: 50%; background: var(--amber-soft); display: flex; align-items: center; justify-content: center; margin: 0 auto 12px; color: var(--amber); }
195197
.credit-list { display: flex; flex-direction: column; gap: 6px; }
196198
.credit-item { padding: 8px 10px; border: 1px solid var(--border); border-radius: var(--radius-sm); background: var(--raised); transition: border-color 0.12s; }

tests/rate-limit-reset-credits.test.ts

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,16 @@ describe("rate-limit reset credits", () => {
107107
expect(match![1]).not.toContain("border: none");
108108
expect(styles).toContain("border: 1px solid transparent");
109109
});
110+
111+
it("renders reset tickets beside next-session badges instead of replacing them", async () => {
112+
const source = await Bun.file("gui/src/pages/CodexAuth.tsx").text();
113+
expect(source).toContain("className=\"card-badges\"");
114+
expect(source).toContain("<TicketBadge account={a} onClick={() => openResetPopup(a)} />");
115+
expect(source).toContain("{isNext(a.id) && !a.needsReauth && <span className=\"badge badge-primary\">{t(\"codexAuth.nextSession\")}</span>}");
116+
const styles = await Bun.file("gui/src/styles.css").text();
117+
expect(styles).toContain(".card-badges { display: inline-flex; align-items: center; gap: 8px; flex-wrap: wrap; min-width: 0; }");
118+
expect(styles).toContain(".card-badges .badge { flex-shrink: 0; }");
119+
});
110120
});
111121

112122
describe("updateAccountQuota resetCredits", () => {

0 commit comments

Comments
 (0)