From 92009db2a95e65539b6c2da48b941ceda061cff3 Mon Sep 17 00:00:00 2001 From: oppiliappan Date: Thu, 23 Apr 2026 14:47:36 +0000 Subject: [PATCH] appview/db: fix up nits with newsletter handlers Signed-off-by: oppiliappan --- flake.lock | 4 ++-- appview/db/db.go | 24 +++++++++--------------- appview/db/newsletter.go | 5 +---- appview/db/star.go | 2 +- appview/state/state.go | 7 +++++++ appview/pages/templates/timeline/timeline.html | 52 +++++++++------------------------------------------- appview/pages/templates/timeline/fragments/newsletterForm.html | 16 +++------------- appview/pages/templates/timeline/fragments/trendingSidebar.html | 6 +++--- 8 file(s) changed, 35 insertion(s)(+), 81 deletion(s)(-) diff --git a/flake.lock b/flake.lock --- a/flake.lock +++ b/flake.lock @@ -120,11 +120,11 @@ "lastModified": 1731402384, "narHash": "sha256-OwUmrPfEehLDz0fl2ChYLK8FQM2p0G1+EMrGsYEq+6g=", "type": "tarball", - "url": "https://github.com/IBM/plex/releases/download/@ibm/plex-mono@1.1.0/ibm-plex-mono.zip" + "url": "https://github.com/IBM/plex/releases/download/@ibm%2Fplex-mono@1.1.0/ibm-plex-mono.zip" }, "original": { "type": "tarball", - "url": "https://github.com/IBM/plex/releases/download/@ibm/plex-mono@1.1.0/ibm-plex-mono.zip" + "url": "https://github.com/IBM/plex/releases/download/@ibm%2Fplex-mono@1.1.0/ibm-plex-mono.zip" } }, "indigo": { diff --git a/appview/db/db.go b/appview/db/db.go --- a/appview/db/db.go +++ b/appview/db/db.go @@ -652,6 +652,14 @@ hide_others integer default 0 ); + create table if not exists newsletter_preferences ( + id integer primary key autoincrement, + user_did text not null unique, + status text not null check (status in ('subscribed', 'dismissed')), + email text, + updated_at text not null default (strftime('%Y-%m-%dT%H:%M:%SZ', 'now')) + ); + -- indexes for better performance create index if not exists idx_notifications_recipient_created on notifications(recipient_did, created desc); create index if not exists idx_notifications_recipient_read on notifications(recipient_did, read); @@ -660,6 +668,7 @@ create index if not exists idx_webhooks_repo_at on webhooks(repo_at); create index if not exists idx_webhook_deliveries_webhook_id on webhook_deliveries(webhook_id); create index if not exists idx_site_deploys_repo_at on site_deploys(repo_at); + create index if not exists idx_newsletter_prefs_user_did on newsletter_preferences(user_did); `) if err != nil { return nil, err @@ -1406,21 +1415,6 @@ alter table pulls drop column stack_id; `) - return err - }) - - orm.RunMigration(conn, logger, "add-newsletter-preferences", func(tx *sql.Tx) error { - _, err := tx.Exec(` - create table if not exists newsletter_preferences ( - id integer primary key autoincrement, - user_did text not null unique, - status text not null check (status in ('subscribed', 'dismissed')), - email text, - updated_at text not null default (strftime('%Y-%m-%dT%H:%M:%SZ', 'now')) - ); - create index if not exists idx_newsletter_prefs_user_did - on newsletter_preferences(user_did); - `) return err }) diff --git a/appview/db/newsletter.go b/appview/db/newsletter.go --- a/appview/db/newsletter.go +++ b/appview/db/newsletter.go @@ -47,10 +47,7 @@ if email.Valid { pref.Email = email.String } - // Best-effort: the column's default format is ISO-8601, but older rows - // (or manual inserts) might use other layouts. A parse failure is not - // fatal — the zero time is acceptable for a UI gating check. - if t, perr := time.Parse("2006-01-02T15:04:05Z", updatedAt); perr == nil { + if t, perr := time.Parse(time.RFC3339, updatedAt); perr == nil { pref.UpdatedAt = t } diff --git a/appview/db/star.go b/appview/db/star.go --- a/appview/db/star.go +++ b/appview/db/star.go @@ -304,7 +304,7 @@ select rsc.subject_at from repo_star_counts rsc order by rsc.stars_gained_last_week desc - limit 8 + limit 5 ` rows, err := e.Query(query) diff --git a/appview/state/state.go b/appview/state/state.go --- a/appview/state/state.go +++ b/appview/state/state.go @@ -362,6 +362,13 @@ s.logger.Error("failed to add newsletter contact", "error", err) } }() + } else { + s.logger.Error( + "failed to add newsletter contact, missing resend config", + "isKeyPresent", s.config.Resend.ApiKey != "", + "isSegmentIdPresent", s.config.Resend.NewsletterSegmentId != "", + "emailAddr", emailAddr, + ) } s.pages.NewsletterResponse(w, pages.NewsletterResponseParams{Id: target}) diff --git a/appview/pages/templates/timeline/timeline.html b/appview/pages/templates/timeline/timeline.html --- a/appview/pages/templates/timeline/timeline.html +++ b/appview/pages/templates/timeline/timeline.html @@ -9,51 +9,25 @@ {{ define "mainLayout" }}
-
+
{{ block "content" . }}{{ end }}
{{ end }} {{ define "content" }} -{{/* - Single responsive grid. Every fragment is rendered once, with CSS alone - handling the mobile → desktop reflow. Only trending has two variants - (horizontal scroll for mobile, vertical sidebar for desktop); both are - present in the DOM and toggled via utility classes. +
- Desktop grid (lg+): - row 1: [ gfi-banner (col-span-2) ] [ newsletter (col 3) ] - row 2: [ timeline (col-span-2) ] [ trendingSidebar (col 3) ] - - When the newsletter is hidden (server-side via .ShowNewsletter, or - client-side via the dismiss button + localStorage), the gfi-banner - widens to col-span-3. -*/}} -
- - {{ if .ShowNewsletter }} -
- {{ template "timeline/fragments/newsletterWidget" . }} -
- {{ end }} - -
- {{ template "timeline/fragments/goodfirstissues" . }} -
- -
+
{{ template "timeline/fragments/timeline" . }}
-
- {{ template "timeline/fragments/trending" . }} -
- - @@ -63,14 +37,7 @@ (function() { var DISMISS_KEY = 'newsletter-dismissed'; var newsletterCol = document.getElementById('newsletter-col'); - var gfi = document.getElementById('gfi-banner'); if (!newsletterCol) return; - - function widenGfi() { - if (!gfi) return; - gfi.classList.remove('lg:col-span-2'); - gfi.classList.add('lg:col-span-3', 'lg:max-w-4xl', 'lg:mx-auto'); - } // hide removes the widget from the DOM without persisting anything. // Used when this browser's localStorage says we already dismissed in a @@ -80,7 +47,6 @@ // device after this localStorage entry was set. function hide() { newsletterCol.remove(); - widenGfi(); } // dismiss is the user-initiated path. Persists both locally and (for diff --git a/appview/pages/templates/timeline/fragments/newsletterForm.html b/appview/pages/templates/timeline/fragments/newsletterForm.html --- a/appview/pages/templates/timeline/fragments/newsletterForm.html +++ b/appview/pages/templates/timeline/fragments/newsletterForm.html @@ -1,13 +1,3 @@ -{{/* - Shared newsletter signup form. Variants style the form differently, but the - POST target, response-target id and request plumbing stay identical. - - Params (dict): - Id string - unique id suffix (e.g. "widget", "home"); used to build - the response span's id so multiple signup forms can - coexist on one page without colliding. - Variant string - "card" (compact sidebar card) | "hero" (large CTA) -*/}} {{ define "timeline/fragments/newsletterForm" }} {{ $id := .Id }} {{ $variant := .Variant }} @@ -38,14 +28,14 @@ hx-target="#newsletter-msg-{{ $id }}" hx-swap="outerHTML" hx-vals='{"target":"{{ $id }}"}'> - + - diff --git a/appview/pages/templates/timeline/fragments/trendingSidebar.html b/appview/pages/templates/timeline/fragments/trendingSidebar.html --- a/appview/pages/templates/timeline/fragments/trendingSidebar.html +++ b/appview/pages/templates/timeline/fragments/trendingSidebar.html @@ -1,13 +1,13 @@ {{ define "timeline/fragments/trendingSidebar" }} -
+

Trending {{ i "trending-up" "size-4 flex-shrink-0" }}

{{ if .Repos }} -
+
{{ range $index, $repo := .Repos }} -
+
{{ template "user/fragments/repoCard" (list $ $repo true) }}
{{ end }} -- tangled.sh