feat(feed): optional per-feed sender-in-title toggle

Add a per-feed senderInTitle flag (domain FeedState.senderInTitle ↔
FeedConfig.sender_in_title). When set, the feed generator prefixes each
entry title with [Sender] (display name, falling back to the address).
Exposed as an admin edit-form checkbox and across the REST API
create/update/response schemas.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
Julien Herr
2026-05-25 15:48:31 +02:00
parent 7086526670
commit e86beeeb8a
14 changed files with 234 additions and 2 deletions
+19
View File
@@ -269,6 +269,23 @@ feedsRouter.get("/:feedId/edit", async (c) => {
</small>
</div>
<div class="form-group">
<label class="checkbox-label">
<input
type="checkbox"
name="sender_in_title"
value="true"
checked={feedConfig.sender_in_title ?? false}
disabled={isExpired}
/>
Show sender in entry titles
</label>
<small>
Render each entry's title as <code>[Sender] Subject</code> for
at-a-glance scanning in your reader.
</small>
</div>
<div class="form-group">
<label for="lifetime_hours">Lifetime (hours)</label>
<input
@@ -322,6 +339,7 @@ feedsRouter.post("/:feedId/edit", async (c) => {
const blockedSenders = parseAllowedSenders(
formData.get("blocked_senders")?.toString() || "",
);
const senderInTitle = formData.get("sender_in_title") === "true";
const lifetimeHoursRaw = formData.get("lifetime_hours")?.toString();
const parsedData = updateFeedSchema.parse({
@@ -338,6 +356,7 @@ feedsRouter.post("/:feedId/edit", async (c) => {
language: parsedData.language,
allowedSenders: parsedData.allowedSenders,
blockedSenders: parsedData.blockedSenders,
senderInTitle,
lifetimeHours: lifetimeHoursRaw
? parseInt(lifetimeHoursRaw, 10)
: undefined,