Skip to main content

radicle_cli/commands/inbox/
args.rs

1use std::{fmt::Display, str::FromStr};
2
3use clap::{Parser, Subcommand, ValueEnum};
4use radicle::{node::notifications::NotificationId, prelude::RepoId};
5
6const ABOUT: &str = "Manage your Radicle notifications";
7
8const LONG_ABOUT: &str = r#"
9By default, this command lists all items in your inbox.
10If your working directory is a Radicle repository, it only shows items
11belonging to this repository, unless `--all` is used.
12
13The `show` subcommand takes a notification ID (which can be found in
14the output of the `list` subcommand) and displays the information related to that
15notification. This will mark the notification as read.
16
17The `clear` subcommand will clear all notifications with given IDs,
18or all notifications if no IDs are given. Cleared notifications are
19deleted and cannot be restored.
20"#;
21
22#[derive(Clone, Debug, Parser)]
23#[command(about = ABOUT, long_about = LONG_ABOUT, disable_version_flag = true)]
24pub struct Args {
25    #[command(subcommand)]
26    pub(super) command: Option<Command>,
27
28    #[clap(flatten)]
29    pub(super) empty: EmptyArgs,
30}
31
32#[derive(Subcommand, Clone, Debug)]
33pub(super) enum Command {
34    /// List all items in your inbox
35    List(ListArgs),
36    /// Show a notification
37    ///
38    /// The NOTIFICATION_ID can be found by listing the items in your inbox
39    ///
40    /// Showing a notification will mark that notification as read
41    Show {
42        /// The notification to display
43        #[arg(value_name = "NOTIFICATION_ID")]
44        id: NotificationId,
45    },
46    /// Clear notifications
47    ///
48    /// This will clear all given notifications
49    ///
50    /// If no notifications are specified then all notifications are cleared
51    Clear(ClearArgs),
52}
53
54#[derive(Parser, Clone, Copy, Debug)]
55pub(super) struct EmptyArgs {
56    /// Sort by column
57    #[arg(long, value_enum, default_value_t, hide = true)]
58    sort_by: SortBy,
59
60    /// Reverse the list
61    #[arg(short, long, hide = true)]
62    reverse: bool,
63
64    /// Show any updates that were not recognized
65    #[arg(long, hide = true)]
66    show_unknown: bool,
67
68    /// Operate on a given repository [default: cwd]
69    #[arg(value_name = "RID")]
70    #[arg(long, hide = true)]
71    repo: Option<RepoId>,
72
73    /// Operate on all repositories
74    #[arg(short, long, conflicts_with = "repo", hide = true)]
75    all: bool,
76}
77
78#[derive(Parser, Clone, Copy, Debug)]
79pub(super) struct ListArgs {
80    /// Sort by column
81    #[arg(long, value_enum, default_value_t)]
82    pub(super) sort_by: SortBy,
83
84    /// Reverse the list
85    #[arg(short, long)]
86    pub(super) reverse: bool,
87
88    /// Show any updates that were not recognized
89    #[arg(long)]
90    pub(super) show_unknown: bool,
91
92    /// Operate on a given repository [default: cwd]
93    #[arg(long, value_name = "RID")]
94    pub(super) repo: Option<RepoId>,
95
96    /// Operate on all repositories
97    #[arg(short, long, conflicts_with = "repo")]
98    pub(super) all: bool,
99}
100
101impl From<ListArgs> for ListMode {
102    fn from(args: ListArgs) -> Self {
103        if args.all {
104            assert!(args.repo.is_none());
105            return Self::All;
106        }
107
108        if let Some(repo) = args.repo {
109            return Self::ByRepo(repo);
110        }
111
112        Self::Contextual
113    }
114}
115
116impl From<EmptyArgs> for ListArgs {
117    fn from(
118        EmptyArgs {
119            sort_by,
120            reverse,
121            show_unknown,
122            repo,
123            all,
124        }: EmptyArgs,
125    ) -> Self {
126        Self {
127            sort_by,
128            reverse,
129            show_unknown,
130            repo,
131            all,
132        }
133    }
134}
135
136#[derive(Parser, Clone, Debug)]
137pub(super) struct ClearArgs {
138    /// Operate on a given repository [default: cwd]
139    #[arg(long, value_name = "RID")]
140    repo: Option<RepoId>,
141
142    /// Operate on all repositories
143    #[arg(short, long, conflicts_with = "repo")]
144    all: bool,
145
146    /// A list of notifications to clear
147    ///
148    /// The --repo or --all options are ignored when the notification ID's are
149    /// specified
150    #[arg(value_name = "NOTIFICATION_ID")]
151    ids: Option<Vec<NotificationId>>,
152}
153
154impl From<ClearArgs> for ClearMode {
155    fn from(ClearArgs { repo, all, ids }: ClearArgs) -> Self {
156        if let Some(ids) = ids {
157            return Self::ByNotifications(ids);
158        }
159
160        if all {
161            assert!(repo.is_none());
162            return Self::All;
163        }
164
165        if let Some(repo) = repo {
166            return Self::ByRepo(repo);
167        }
168
169        Self::Contextual
170    }
171}
172
173#[derive(ValueEnum, Clone, Copy, Default, Debug)]
174pub enum SortBy {
175    Id,
176    #[default]
177    Timestamp,
178}
179
180impl Display for SortBy {
181    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
182        match self {
183            Self::Id => write!(f, "rowid"),
184            Self::Timestamp => write!(f, "timestamp"),
185        }
186    }
187}
188
189impl FromStr for SortBy {
190    type Err = String;
191
192    fn from_str(s: &str) -> Result<Self, Self::Err> {
193        match s {
194            "id" => Ok(Self::Id),
195            "timestamp" => Ok(Self::Timestamp),
196            _ => Err(format!("'{s}' is not a valid sort by column")),
197        }
198    }
199}
200
201pub(super) enum ListMode {
202    /// List the notifications of the current repository, if in a working
203    /// directory, otherwise all the repositories.
204    Contextual,
205    /// List the notifications for a all repositories.
206    All,
207    /// List the notifications for a specific repository.
208    ByRepo(RepoId),
209}
210
211pub(super) enum ClearMode {
212    /// Clear the specified notifications.
213    ///
214    /// Note that this does not require a `RepoId` since the IDs are globally
215    /// unique due to the use of a single sqlite table.
216    ByNotifications(Vec<NotificationId>),
217    /// Clear the notifications of a specific repository.
218    ByRepo(RepoId),
219    /// Clear all notifications of all repositories.
220    All,
221    /// Clear the notifications of the current repository, only if in a working
222    /// directory.
223    Contextual,
224}