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
16 changes: 12 additions & 4 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,16 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
## [Unreleased]

### Added
- **Autosave to localStorage:** the working session (all open requests + payloads) is
mirrored to browser `localStorage` on every change, in addition to the durable Go store.
On launch the local draft is restored instantly (falling back to the Go store), and an
"Autosaved HH:MM:SS" indicator in the top bar shows the last save time.
- **Two-level request/payload model:** the UI now has top-level **request tabs** (each with
its own URL, method, auth, and settings) and, within each, inner **payload tabs** that share
the request's URL/method/auth/settings but each carry their own headers, params, body, and
response. This restores Hypr's core premise — comparing multiple payloads against one URL —
while letting several independent requests stay open side by side. "New Request" (sidebar +
top "+") adds a top-level request; the "+" on the Payloads strip adds a payload.
- **v0.3 — Persistence:** JSON store at `$OS_CONFIG_DIR/hypr/store.json`; data survives restart.
- **Collections:** create named collections, save requests to them (name + target collection dialog),
load saved requests into any tab with one click, delete collections and individual requests.
Expand All @@ -17,10 +27,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
on every meaningful action and restored on the next launch.
- **Sidebar:** collapsible left panel (toggle via `PanelLeftClose`/`PanelLeftOpen` icon) with
Collections and History sections; each section independently collapsible.
- Per-tab method and URL are now properly isolated — switching tabs restores each tab's method+URL
(previously method and URL were shared across all tabs).
- 5 new Go tests in `store_test.go` covering collection CRUD, request save/delete,
history append/clear/cap, and session save/restore (total: 34 tests).
- Go tests in `store_test.go` covering collection CRUD, request save/delete (incl. payload
round-trip), history append/clear/cap, and session save/restore.

### Changed
- Backend: added `Store` type backed by JSON, 10 new bound methods
Expand Down
10 changes: 9 additions & 1 deletion CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,15 @@ The frontend↔backend boundary is the only non-obvious part. Wails binds the Go

**Curl parsing** (`parse_curl.go`): a hand-written state machine over `go-shellwords` tokens. Supports `-X/--request`, `-H/--header`, `-d/--data[-ascii|-raw]`, `-A/--user-agent`, `-u/--user` (→ Basic auth), `-I/--head`, `-b/--cookie`. Does **not** handle `--data-binary`, `--data-urlencode`, or multipart. Input must start with `curl `.

**Frontend state** (`frontend/src/App.tsx`): the UI is multi-tab ("Request 1", "Request 2", …). State is held as **parallel arrays indexed by tab** — `reqBodies[]`, `reqHeaders[][]`, `responses[]` — all kept in sync in `addNewTab`/`closeTab`. When editing tab logic, update all three arrays together or they desync. Headers in the UI are `{Key, Value}` objects (`src/lib/header.ts`); they're converted to a plain `Record<string, string>` before being passed to Go (which expects `main.Headers`).
**Core premise:** Hypr's reason to exist vs. Postman/Insomnia is testing **multiple payloads against a single request URL** on one screen. This is encoded in a **two-level tab model** — don't collapse it.

**Frontend state** (`frontend/src/App.tsx`, types in `src/lib/model.ts`): a single nested structure, **not** parallel arrays.
- Top level: `requests: RequestTab[]` + `activeRequest` index. Each `RequestTab` owns the **shared** `method`, `url`, `auth`, `settings`, plus `payloads: Payload[]` and `activePayload`.
- Inner level: each `Payload` owns its own `headers`, `params`, `bodyType`/`jsonBody`/`rawBody`/`formRows`, and `response`. All payloads of a request share that request's url/method/auth/settings.
- All edits go through the immutable updaters `updateRequest(requests, ri, patch)` and `updatePayload(requests, ri, pi, patch)` in `model.ts`. Per-payload KV-row edits use `setRow`/`dropRow`/`appendRow` from `src/lib/kv.ts`.
- **URL ↔ params is one-way at send time only**: the URL bar is the shared base URL; the Params tab edits the active payload; `buildSpec()` merges `req.url` + payload params + auth query when sending. Editing one does not rewrite the other.
- `response` is **never persisted**; `toStoredPayload()` strips it before saving. Session/collections persist via the Go store (`store.go`): `Session.openRequests`/`activeRequest`, `SavedRequest` carries all payloads.
- Headers in the UI are `{Key, Value}` objects (`src/lib/kv.ts`); converted to a plain `Record<string, string>` before being passed to Go.

**UI stack**: the frontend uses **Tailwind CSS + shadcn/ui** (Radix primitives in `frontend/src/components/ui/`, `cn` helper in `src/lib/utils.ts`, design tokens as CSS variables in `src/index.css`, theme in `tailwind.config.js`). Icons are `lucide-react`. JSON responses are highlighted by the in-house `src/components/json-view.tsx` (no `react-json-pretty`). The `@/*` import alias maps to `src/`.

Expand Down
2 changes: 1 addition & 1 deletion frontend/package.json.md5
Original file line number Diff line number Diff line change
@@ -1 +1 @@
d3c70ad3166b11f53dac87fb2b41f3c2
cec421cd25fd35fe8f5916df0826d3d0
Loading
Loading