fix: add an action field to timeline events
This commit is contained in:
parent
144257c2c8
commit
f750107bb1
8 changed files with 22 additions and 20 deletions
1
migrations/0005_add_action_to_timeline.sql
Normal file
1
migrations/0005_add_action_to_timeline.sql
Normal file
|
|
@ -0,0 +1 @@
|
|||
ALTER TABLE timeline_events ADD COLUMN action TEXT NOT NULL DEFAULT 'added';
|
||||
|
|
@ -139,6 +139,7 @@ pub(crate) async fn create_bag(
|
|||
let event = NewTimelineEvent {
|
||||
entity_type: "bag".to_string(),
|
||||
entity_id: bag.id.into_inner(),
|
||||
action: "added".to_string(),
|
||||
occurred_at: chrono::Utc::now(),
|
||||
title: roast.name.to_string(),
|
||||
details: vec![
|
||||
|
|
@ -235,6 +236,7 @@ pub(crate) async fn update_bag(
|
|||
let event = NewTimelineEvent {
|
||||
entity_type: "bag".to_string(),
|
||||
entity_id: bag.id.into_inner(),
|
||||
action: "finished".to_string(),
|
||||
occurred_at: chrono::Utc::now(),
|
||||
title: format!("{}", roast.name),
|
||||
details: vec![TimelineEventDetail {
|
||||
|
|
|
|||
|
|
@ -15,6 +15,7 @@ pub struct TimelineEvent {
|
|||
pub id: TimelineEventId,
|
||||
pub entity_type: String,
|
||||
pub entity_id: i64,
|
||||
pub action: String,
|
||||
pub occurred_at: DateTime<Utc>,
|
||||
pub title: String,
|
||||
pub details: Vec<TimelineEventDetail>,
|
||||
|
|
@ -27,6 +28,7 @@ pub struct TimelineEvent {
|
|||
pub struct NewTimelineEvent {
|
||||
pub entity_type: String,
|
||||
pub entity_id: i64,
|
||||
pub action: String,
|
||||
pub occurred_at: DateTime<Utc>,
|
||||
pub title: String,
|
||||
pub details: Vec<TimelineEventDetail>,
|
||||
|
|
|
|||
|
|
@ -130,10 +130,11 @@ impl RoasterRepository for SqlRoasterRepository {
|
|||
let details_json = Self::details_for_roaster(&roaster)?;
|
||||
|
||||
query(
|
||||
"INSERT INTO timeline_events (entity_type, entity_id, occurred_at, title, details_json, tasting_notes_json) VALUES (?, ?, ?, ?, ?, ?)",
|
||||
"INSERT INTO timeline_events (entity_type, entity_id, action, occurred_at, title, details_json, tasting_notes_json) VALUES (?, ?, ?, ?, ?, ?, ?)",
|
||||
)
|
||||
.bind("roaster")
|
||||
.bind(i64::from(roaster.id))
|
||||
.bind("added")
|
||||
.bind(roaster.created_at)
|
||||
.bind(&roaster.name)
|
||||
.bind(details_json)
|
||||
|
|
|
|||
|
|
@ -166,10 +166,11 @@ impl RoastRepository for SqlRoastRepository {
|
|||
};
|
||||
|
||||
query(
|
||||
"INSERT INTO timeline_events (entity_type, entity_id, occurred_at, title, details_json, tasting_notes_json) VALUES (?, ?, ?, ?, ?, ?)",
|
||||
"INSERT INTO timeline_events (entity_type, entity_id, action, occurred_at, title, details_json, tasting_notes_json) VALUES (?, ?, ?, ?, ?, ?, ?)",
|
||||
)
|
||||
.bind("roast")
|
||||
.bind(i64::from(roast.id))
|
||||
.bind("added")
|
||||
.bind(roast.created_at)
|
||||
.bind(&roast.name)
|
||||
.bind(details_json)
|
||||
|
|
|
|||
|
|
@ -25,9 +25,9 @@ impl SqlTimelineEventRepository {
|
|||
impl TimelineEventRepository for SqlTimelineEventRepository {
|
||||
async fn insert(&self, event: NewTimelineEvent) -> Result<TimelineEvent, RepositoryError> {
|
||||
let query = r#"
|
||||
INSERT INTO timeline_events (entity_type, entity_id, occurred_at, title, details_json, tasting_notes_json)
|
||||
VALUES (?, ?, ?, ?, ?, ?)
|
||||
RETURNING id, entity_type, entity_id, occurred_at, title, details_json, tasting_notes_json
|
||||
INSERT INTO timeline_events (entity_type, entity_id, action, occurred_at, title, details_json, tasting_notes_json)
|
||||
VALUES (?, ?, ?, ?, ?, ?, ?)
|
||||
RETURNING id, entity_type, entity_id, action, occurred_at, title, details_json, tasting_notes_json
|
||||
"#;
|
||||
|
||||
let details_json = serde_json::to_string(&event.details).map_err(|err| {
|
||||
|
|
@ -43,6 +43,7 @@ impl TimelineEventRepository for SqlTimelineEventRepository {
|
|||
let record = sqlx::query_as::<_, TimelineEventRecord>(query)
|
||||
.bind(event.entity_type)
|
||||
.bind(event.entity_id)
|
||||
.bind(event.action)
|
||||
.bind(event.occurred_at)
|
||||
.bind(event.title)
|
||||
.bind(details_json)
|
||||
|
|
@ -65,7 +66,7 @@ impl TimelineEventRepository for SqlTimelineEventRepository {
|
|||
|
||||
let order_clause = format!("t.occurred_at {direction_sql}, t.id DESC");
|
||||
let base_query = "SELECT
|
||||
t.id, t.entity_type, t.entity_id, t.occurred_at, t.title, t.details_json, t.tasting_notes_json,
|
||||
t.id, t.entity_type, t.entity_id, t.action, t.occurred_at, t.title, t.details_json, t.tasting_notes_json,
|
||||
CASE
|
||||
WHEN t.entity_type = 'roaster' THEN r.slug
|
||||
WHEN t.entity_type = 'roast' THEN rst.slug
|
||||
|
|
@ -103,6 +104,7 @@ struct TimelineEventRecord {
|
|||
id: i64,
|
||||
entity_type: String,
|
||||
entity_id: i64,
|
||||
action: String,
|
||||
occurred_at: DateTime<Utc>,
|
||||
title: String,
|
||||
details_json: Option<String>,
|
||||
|
|
@ -137,6 +139,7 @@ impl TimelineEventRecord {
|
|||
id: TimelineEventId::from(self.id),
|
||||
entity_type: self.entity_type,
|
||||
entity_id: self.entity_id,
|
||||
action: self.action,
|
||||
occurred_at: self.occurred_at,
|
||||
title: self.title,
|
||||
details,
|
||||
|
|
|
|||
|
|
@ -440,6 +440,7 @@ impl TimelineEventView {
|
|||
id,
|
||||
entity_type,
|
||||
entity_id,
|
||||
action,
|
||||
occurred_at,
|
||||
title,
|
||||
details,
|
||||
|
|
@ -448,16 +449,11 @@ impl TimelineEventView {
|
|||
roaster_slug,
|
||||
} = event;
|
||||
|
||||
let kind_label = match entity_type.as_str() {
|
||||
"roaster" => "Roaster Added",
|
||||
"roast" => "Roast Added",
|
||||
"bag" => {
|
||||
if title.starts_with("Finished") {
|
||||
"Bag Finished"
|
||||
} else {
|
||||
"Bag Added"
|
||||
}
|
||||
}
|
||||
let kind_label = match (entity_type.as_str(), action.as_str()) {
|
||||
("roaster", "added") => "Roaster Added",
|
||||
("roast", "added") => "Roast Added",
|
||||
("bag", "added") => "Bag Added",
|
||||
("bag", "finished") => "Bag Finished",
|
||||
_ => "Event",
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -410,8 +410,4 @@ async fn closing_a_bag_surfaces_on_the_timeline() {
|
|||
body.contains("Bag Finished"),
|
||||
"Expected 'Bag Finished' badge in timeline HTML, got: {body}"
|
||||
);
|
||||
assert!(
|
||||
body.contains(&format!("Finished: {}", roast_name)),
|
||||
"Expected bag finished title to appear in timeline HTML, got: {body}"
|
||||
);
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue