feat(api): reshape raw events into TimelineItem
GET /v1/events now returns the presentation form rather than raw
upstream payloads. The frontend stays dumb: it renders title /
subtitle / body segments and picks an icon from a small kebab-case
enum. Title and subtitle are arrays of {text} | {text, url} segments
so the UI can interleave plain copy with anchors without parsing.
New entities (in moments-entities):
TimelineItem — id, source, action, occurred_at, icon, title, subtitle, body
TitleSegment — Text | Link
TimelineBody — Markdown | Commits | Links
CommitSummary — sha, short_sha, message, url, author
TimelineIcon — kebab-case enum; UI falls back to Generic on unknowns
Reshape lives in moments-core::presentation, dispatched by source.
github.rs covers the event types observed on grenade's feed:
PushEvent, PullRequest{,Review,ReviewComment}Event, Issues{,Comment}Event,
Create/Delete/Fork/Watch/Release/CommitComment/PublicEvent.
Anything else falls back to a generic "<action> on <repo>" line.
Other sources (gitea, hg, bugzilla) currently use a stub fallback;
they get their own reshape modules in steps 5 and 6.
4 unit tests cover the load-bearing cases (push commit list, merged
PR icon swap, issue-comment markdown body, unknown-event fallback).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
31
crates/moments-core/src/presentation.rs
Normal file
31
crates/moments-core/src/presentation.rs
Normal file
@@ -0,0 +1,31 @@
|
||||
//! Reshape raw stored events into the presentation shape consumed by the UI.
|
||||
//!
|
||||
//! Storage holds the upstream payload verbatim; transformation lives here so
|
||||
//! the rendering can evolve without re-fetching upstream data.
|
||||
|
||||
use moments_entities::{Event, Source, TimelineIcon, TimelineItem, TitleSegment};
|
||||
|
||||
mod github;
|
||||
|
||||
pub fn reshape(event: &Event) -> TimelineItem {
|
||||
match event.source {
|
||||
Source::Github => github::reshape(event),
|
||||
Source::Gitea | Source::Hg | Source::Bugzilla => generic_fallback(event),
|
||||
}
|
||||
}
|
||||
|
||||
fn generic_fallback(event: &Event) -> TimelineItem {
|
||||
TimelineItem {
|
||||
id: event.id.clone(),
|
||||
source: event.source,
|
||||
action: event.action.clone(),
|
||||
occurred_at: event.occurred_at,
|
||||
icon: TimelineIcon::Generic,
|
||||
title: vec![
|
||||
TitleSegment::text(format!("{} from ", event.action)),
|
||||
TitleSegment::text(event.source.as_str().to_string()),
|
||||
],
|
||||
subtitle: None,
|
||||
body: None,
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user