refactor(console): migrate view layer to OpenAPI client (replaces #187)#241
refactor(console): migrate view layer to OpenAPI client (replaces #187)#241jeroenrinzema wants to merge 28 commits into
Conversation
Add store-level tests asserting ListUserSchedules / ListOrganizationSchedules report has_pending_events=true while events are unfired and flip to false once all events are marked fired. Guards the badge-stays-lit-forever regression that this branch fixes.
- Regenerate console management OpenAPI bindings after the inbox open->read rename (read_at, /read paths) - Update inbox-detail-table console consumer to the read terminology so it typechecks against the regenerated types; fixes prettier formatting - Restore oapi.ListStateDraft/ListStateReady constants in lists_test.go - Use *int16 (ptr.To) for InboxMessage.Priority in consumer test - Fix client inbox spec tests: /inbox/read path and required identifier
- SMS template data: align textTemplateDataSchema and TextTemplateData to
the API shape ({ body }); fix SMS preview reading data.text -> data.body
- Enable mode: "onChange" on NewCampaign and ProjectOnboardingDomain forms
so formState.isValid updates and the submit button isn't stuck disabled
- optionalPhoneSchema: accept "" so an InlineEdit phone can be cleared
- Trim names/IDs in list, journey, and device form schemas to reject
whitespace-only input
- Users.createUser: optional-chain optional fields to avoid a TypeError
when only some identity fields are provided
- EmailContentPreview: drop render-phase setCompiledHtml("") (effect already
clears it) and return null instead of undefined for non-email templates
- searchTimeoutRef: initialize empty instead of scheduling a throwaway timer
Replace the hand-rolled SHA-256/HMAC implementation with crypto/sha256 + crypto/hmac. The "stdlib panics under WASM" rationale does not hold for the current TinyGo wasi toolchain (verified: stdlib sha256/hmac produce correct known-answer values under tinygo 0.40.1 + wasmtime), and the Mailgun provider already relies on stdlib crypto. This removes ~130 lines of unaudited custom crypto from the SES request signer. Also set Spec.Webhook to false: WebhookHandler is a no-op stub that drops all events (SNS parsing is unimplemented), so advertising webhook support would register an endpoint that silently discards every delivery/bounce event.
The unused linter now flags it since the consumer test package compiles again (it was masked by the prior inbox_test.go compile error).
Amazon SES and Mailgun declared Platforms: [PlatformEmail], but Spec.Platforms is the push-platform list. On provider creation, autoAssignPushProvider upserts the provider as the default push provider for every platform it lists, bypassing the validPlatforms allowlist (ios/android/web only). This wrote an invalid "email" row into project_push_providers for what are email-channel providers. Email providers are identified by Channels: [ChannelEmail] (as resend already does); they have no push platform. Drop the Platforms declaration from both and remove the now-unused PlatformEmail constant, reverting channel.go to its prior state.
Route due inbox messages through the inbox process pipeline (with a stable Msg-Id for idempotent re-injection) instead of emitting an analytics event, and gate dispatch on IsDue() so future-scheduled messages published immediately by the client/campaign paths wait for the scheduler. Also guard generic email/SMS composition against an empty recipient.
Move the destructive 'DROP TABLE campaign_sends' out of the inbox-table creation migration into its own migration with a down migration that recreates the table structure (its final post-broadcast_id, composite-PK shape). The inbox migration's down is now a clean inverse. Also correct the ScanDue* comments: FOR UPDATE SKIP LOCKED is not run in a held transaction, so idempotency actually comes from the scheduler's stable Msg-Id and the sent_at guard, not the row lock.
Backend - Fix UnarchiveList: drop the GetList pre-check that filtered deleted_at IS NULL, which made every restore return 404; rely on the store returning sql.ErrNoRows on zero rows affected. - Fix UnarchiveCampaign handler: add the missing generic error branch so non-ErrNoRows DB errors no longer fall through to a false 204. - Make UnarchiveJourney store return sql.ErrNoRows on zero rows affected, matching the list/campaign stores, and simplify the handler. - Change the list filter semantics from "include deleted (both)" to "archived only" so the archived view can paginate server-side with a correct total_count. Renamed the store/controller param to archivedOnly and updated the include_deleted OAPI parameter description accordingly. Frontend - Replace the client-side limit:100 + .filter() archived view with real server-side offset pagination in the Lists, Campaigns and Journeys views (dedicated archivedOffset, prev/next, footer shown in both views, offset reset on toggle/search/unarchive). Tests - Add store tests covering the archived-only filter and the unarchive happy path plus ErrNoRows on already-active and non-existent rows, for lists, campaigns and journeys.
fix: add has_pending_events field to user and organization schedules
…-components-and-provider-crud fix: enhance components with error handling and improve rate limit logic
…lidation # Conflicts: # console/src/views/settings/IntegrationSetup.tsx # console/src/views/users/ListCreateForm.tsx
Normalize arbitrary timezone formats (GMT+2, EST, UTC+05:30, etc) to canonical IANA strings during CSV import. Includes timezone resolver, tests, and timezone selection UI improvements.
…lidation # Conflicts: # console/src/views/users/Users.tsx
Feat/frontend form validation
# Conflicts: # internal/http/controllers/v1/client/oapi/resources_gen.go # internal/http/controllers/v1/management/oapi/resources_gen.go # internal/wasm/test/provider.wasm
Add inbox messaging system for organizations and users
…s-provider # Conflicts: # go.mod # go.sum # internal/http/controllers/v1/client/oapi/resources_gen.go # internal/http/controllers/v1/management/oapi/resources_gen.go # internal/wasm/test/action.wasm # internal/wasm/test/provider.wasm
…-files # Conflicts: # go.mod # go.sum # internal/http/controllers/v1/client/oapi/resources_gen.go # internal/http/controllers/v1/management/oapi/resources_gen.go # internal/store/journey/journeys_test.go
Feat: Added new email providers
feat: enhance journey, campaign, and list management with unarchive f…
Implements the SendGrid email provider WASM module: API-based email sending, webhook event handling mapped to canonical events, configuration schema (API key + webhook verification key), and tests. Closes #216.
…s/subscriptions to oapiClient Establishes the openapi-fetch migration pattern: replace the legacy axios 'api' object with the typed oapiClient. Adds src/lib/path-suggestions.ts to replace the api.projects.pathSuggestions aggregator.
…lient
Replaces the legacy axios-based `api` object with the typed openapi-fetch
`oapiClient` across the users, campaign, journey, project, settings and
broadcast views. Each call was verified against the generated OpenAPI types
(tsc is a hard gate, since openapi-fetch is fully typed).
Calls with no management-spec endpoint are intentionally left on the legacy
client: journey entrances / step-users / skip-delay / remove-from-journey,
list user upload, multipart imports (users/documents), the broadcast SSE
progress stream, the auth flows, and the generic ProjectEntityPath route
abstraction.
Note: getCampaign is declared in the spec as { data: Campaign } but the
backend returns the Campaign directly; the client reads it per the backend
(documented inline) pending a spec correction.
26d2a36 to
c4a44f7
Compare
c4a44f7 to
6f5c784
Compare
The getCampaign OpenAPI response was declared as { data: Campaign }, but the
handler (campaigns.go GetCampaign) returns the Campaign directly via
json.Write(w, ..., campaign.OAPI()) — matching every other single-resource GET
(getJourney/getProject/getUser/getList). The wrapper was an outlier that made
the generated clients describe a response shape the backend never sends.
Corrects the spec and regenerates the Go (resources_gen.go) and TypeScript
(management.generated.ts) bindings. No Go code consumed the old wrapped shape.
|
Closing as superseded. Most of this PR's diff already landed on The genuinely salvageable part — the view-layer migration from the legacy API client to the generated OpenAPI client ( Still needs a manual re-migration on top of main (NOT done in #269)These 22 files were changed by both
Additionally, 12 view files that only this PR migrated could not be relanded cleanly because they depend on this PR's migrated |
refactor(console): reland oapiClient view-layer migration (supersedes #241)
Summary
Replacement for #187 (closed). Migrates the Console view layer from the legacy axios-based
apiclient to the typedopenapi-fetchclient (oapiClient), against the current management OpenAPI spec.Unlike #187 (which was ~3 months stale, built against an old spec with wrong paths, and accumulated ~25 unaddressed review items), this PR is built fresh on
main, and every call is verified bytsc—openapi-fetchis fully typed, so an incorrect path/param/body fails to compile.What changed
src/lib/path-suggestions.ts—fetchPathSuggestions(), a typed replacement for theapi.projects.pathSuggestionsaggregator.oapiClient.status/tags,entrance_id, cursor pagination) to scoped, documented casts rather than blanketas never.Intentionally left on the legacy client
These have no endpoint in the management spec (the same gaps that blocked #187) or no clean openapi-fetch equivalent:
entrances(search/log),steps/{stepID}/users, userskip-delay/remove-from-journeyPOST /lists/{listID}/users) and multipart imports (users/documents)apiUrl+ EventSource)Login,LoginCallback)ProjectEntityPathroute abstraction (router.tsx,createStatefulRoute.tsx) and themod.tsSDK re-exportapi.tstherefore remains (it is not dead) — this continuesmain's incremental migration.Known spec inaccuracy (follow-up)
getCampaignis declared inresources.ymlas{ data: Campaign }, but the Go handler (campaigns.go:204) returns theCampaigndirectly viajson.Write(..., campaign.OAPI()). The client reads it per the backend reality (documented inline). The spec should be corrected (and Go/TS types regenerated) in a follow-up — out of scope here to keep this PR focused and avoid regenerating backend bindings.Verification
tsc --noEmit: 0 errorspnpm build: succeedseslinton changed files: clean (remaining repo warnings are pre-existing, in untouched files)vitestfinds no test files){data}-wrapper / direct-response mismatches remain beyond the documentedgetCampaigncase.