use crate::brain::Brain;
use crate::model::{Asked, Author, Comment, Kind, Task, fmt_ts, now};
use serde::Serialize;
#[derive(Debug, Serialize)]
pub struct Entry<'a> {
pub id: u32,
pub kind: &'static str,
pub title: &'a str,
#[serde(skip_serializing_if = "Option::is_none")]
pub status: Option<&'static str>,
#[serde(skip_serializing_if = "Option::is_none")]
pub decision: Option<&'static str>,
#[serde(skip_serializing_if = "Option::is_none")]
pub asked: Option<&'static str>,
pub tags: &'a [String],
#[serde(skip_serializing_if = "<[u32]>::is_empty")]
pub links: &'a [u32],
#[serde(skip_serializing_if = "Vec::is_empty")]
pub repo_links: Vec<String>,
#[serde(skip_serializing_if = "Vec::is_empty")]
pub linked_from: Vec<u32>,
pub created: String,
#[serde(skip_serializing_if = "str::is_empty")]
pub description: &'a str,
#[serde(skip_serializing_if = "Vec::is_empty")]
pub comments: Vec<EntryComment<'a>>,
#[serde(skip_serializing_if = "Option::is_none")]
pub tracked_minutes: Option<i64>,
#[serde(skip_serializing_if = "std::ops::Not::not")]
pub running: bool,
#[serde(skip_serializing_if = "Option::is_none")]
pub path: Option<String>,
}
#[derive(Debug, Serialize)]
pub struct EntryComment<'a> {
pub created: String,
#[serde(skip_serializing_if = "Option::is_none")]
pub edited: Option<String>,
pub body: &'a str,
#[serde(skip_serializing_if = "Option::is_none")]
pub author: Option<&'static str>,
#[serde(skip_serializing_if = "std::ops::Not::not")]
pub question: bool,
}
#[derive(Debug, Serialize)]
pub struct Summary<'a> {
pub id: u32,
pub kind: &'static str,
pub title: &'a str,
#[serde(skip_serializing_if = "Option::is_none")]
pub status: Option<&'static str>,
#[serde(skip_serializing_if = "Option::is_none")]
pub decision: Option<&'static str>,
#[serde(skip_serializing_if = "Option::is_none")]
pub asked: Option<&'static str>,
pub tags: &'a [String],
}
impl<'a> Entry<'a> {
pub fn new(brain: &Brain, task: &'a Task) -> Self {
let now = now();
Self {
id: task.id,
kind: task.kind.as_str(),
title: &task.title,
status: task.is_task().then(|| task.status.as_str()),
decision: decision(task),
asked: asked(task),
tags: &task.tags,
links: &task.links,
repo_links: task.repo_links.iter().map(ToString::to_string).collect(),
linked_from: brain.backlinks(task.id).iter().map(|t| t.id).collect(),
created: fmt_ts(task.created),
description: &task.description,
comments: task.comments.iter().map(EntryComment::new).collect(),
tracked_minutes: (!task.sessions.is_empty()).then(|| task.total(now).num_minutes()),
running: task.is_running(),
path: task.path.as_ref().map(|p| p.display().to_string()),
}
}
}
impl<'a> EntryComment<'a> {
fn new(comment: &'a Comment) -> Self {
Self {
created: fmt_ts(comment.created),
edited: comment.edited.map(fmt_ts),
body: &comment.body,
author: (comment.author != Author::Human).then(|| comment.author.as_str()),
question: comment.question,
}
}
}
impl<'a> Summary<'a> {
pub fn new(task: &'a Task) -> Self {
Self {
id: task.id,
kind: task.kind.as_str(),
title: &task.title,
status: task.is_task().then(|| task.status.as_str()),
decision: decision(task),
asked: asked(task),
tags: &task.tags,
}
}
}
fn decision(task: &Task) -> Option<&'static str> {
(task.kind == Kind::Decision).then(|| task.decision.as_str())
}
fn asked(task: &Task) -> Option<&'static str> {
task.asked().map(|asked| match asked {
Asked::Waiting(_) => "waiting for an answer",
Asked::Answered(_) => "answered",
})
}