Files
Gotcha/crates/app/src/domain.rs
2026-08-03 20:34:39 +02:00

214 lines
5.2 KiB
Rust

use std::collections::{BTreeMap, BTreeSet};
pub use gotcha_gitea::{
HistoryCommit, HomeData, IssueDetails, IssueEditorData, MilestoneDetails, Page, PullDetails,
civil_from_days, days_from_civil, parse_api_date,
};
use serde::{Deserialize, Serialize};
#[derive(Clone, Copy, Debug, Default, Deserialize, Eq, PartialEq, Serialize)]
#[serde(rename_all = "lowercase")]
pub enum AppearanceMode {
Light,
Dark,
#[default]
#[serde(other)]
Auto,
}
impl AppearanceMode {
pub fn index(self) -> i32 {
match self {
Self::Auto => 0,
Self::Light => 1,
Self::Dark => 2,
}
}
pub fn from_index(index: i32) -> Option<Self> {
match index {
0 => Some(Self::Auto),
1 => Some(Self::Light),
2 => Some(Self::Dark),
_ => None,
}
}
}
#[derive(Clone, Deserialize, Serialize)]
pub struct Server {
pub name: String,
pub url: String,
#[serde(default)]
pub provider: gotcha_gitea::Provider,
#[serde(default)]
pub credential_account: String,
#[serde(skip)]
pub token: String,
}
#[derive(Clone, Deserialize, Serialize)]
pub struct Preferences {
#[serde(default)]
pub servers: Vec<Server>,
#[serde(default)]
pub favorites: BTreeSet<String>,
#[serde(default)]
pub last_server: Option<usize>,
#[serde(default = "open_status")]
pub issue_status: String,
#[serde(default)]
pub issue_filters: BTreeMap<String, IssueFilter>,
#[serde(default = "open_status")]
pub pull_status: String,
#[serde(default)]
pub pull_filters: BTreeMap<String, PullFilter>,
#[serde(default)]
pub appearance: AppearanceMode,
}
impl Default for Preferences {
fn default() -> Self {
Self {
servers: Vec::new(),
favorites: BTreeSet::new(),
last_server: None,
issue_status: open_status(),
issue_filters: BTreeMap::new(),
pull_status: open_status(),
pull_filters: BTreeMap::new(),
appearance: AppearanceMode::default(),
}
}
}
#[derive(Clone, Default, Deserialize, Eq, PartialEq, Serialize)]
pub struct IssueFilter {
#[serde(default)]
pub milestone: String,
#[serde(default)]
pub labels: BTreeSet<String>,
#[serde(skip)]
pub search_text: String,
}
impl IssueFilter {
pub fn is_active(&self, status: &str) -> bool {
status != "open" || self != &Self::default()
}
}
#[derive(Clone, Default, Deserialize, Eq, PartialEq, Serialize)]
pub struct PullFilter {
#[serde(default)]
pub milestone: String,
#[serde(skip)]
pub search_text: String,
}
impl PullFilter {
pub fn is_active(&self, status: &str) -> bool {
status != "open" || self != &Self::default()
}
}
#[derive(Clone)]
pub struct RepositoryData {
pub owner: String,
pub name: String,
pub description: String,
pub language: String,
pub open_issues: i64,
pub updated: String,
pub default_branch: String,
}
#[derive(Default)]
pub struct State {
pub preferences: Preferences,
pub active_server: Option<usize>,
pub repositories: Vec<RepositoryData>,
}
pub struct IssueDraft {
pub title: String,
pub body: String,
pub label_ids: Vec<i64>,
pub milestone_id: Option<i64>,
pub due_date: Option<i64>,
pub closed: bool,
}
pub struct MilestoneDraft {
pub title: String,
pub description: String,
pub due_date: Option<i64>,
pub closed: bool,
}
pub fn open_status() -> String {
"open".into()
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn issue_filter_default_state_is_owned_by_rust() {
assert!(!IssueFilter::default().is_active("open"));
assert!(IssueFilter::default().is_active("closed"));
assert!(
IssueFilter {
milestone: "v1".into(),
..Default::default()
}
.is_active("open")
);
assert!(!PullFilter::default().is_active("open"));
assert!(PullFilter::default().is_active("closed"));
assert!(
PullFilter {
milestone: "v1".into(),
..Default::default()
}
.is_active("open")
);
assert!(
IssueFilter {
search_text: "needle".into(),
..Default::default()
}
.is_active("open")
);
assert!(
PullFilter {
search_text: "needle".into(),
..Default::default()
}
.is_active("open")
);
}
#[test]
fn search_text_is_session_only() {
let issue = IssueFilter {
search_text: "needle".into(),
..Default::default()
};
let pull = PullFilter {
search_text: "needle".into(),
..Default::default()
};
assert!(!serde_json::to_string(&issue).unwrap().contains("needle"));
assert!(!serde_json::to_string(&pull).unwrap().contains("needle"));
assert_eq!(
serde_json::from_str::<IssueFilter>(r#"{"milestone":"v1"}"#)
.unwrap()
.search_text,
""
);
}
}