web: add mark as spam buttons

This commit is contained in:
Bill Thiede 2024-04-03 21:07:56 -07:00
parent 1b196a2703
commit 8abf9398e9
6 changed files with 210 additions and 1 deletions

View File

@ -0,0 +1,3 @@
mutation AddTagMutation($query: String!, $tag: String!) {
tagAdd(query:$query, tag:$tag)
}

View File

@ -0,0 +1,3 @@
mutation RemoveTagMutation($query: String!, $tag: String!) {
tagRemove(query:$query, tag:$tag)
}

View File

@ -693,6 +693,96 @@
"ofType": null
}
}
},
{
"args": [
{
"defaultValue": null,
"description": null,
"name": "query",
"type": {
"kind": "NON_NULL",
"name": null,
"ofType": {
"kind": "SCALAR",
"name": "String",
"ofType": null
}
}
},
{
"defaultValue": null,
"description": null,
"name": "tag",
"type": {
"kind": "NON_NULL",
"name": null,
"ofType": {
"kind": "SCALAR",
"name": "String",
"ofType": null
}
}
}
],
"deprecationReason": null,
"description": null,
"isDeprecated": false,
"name": "tagAdd",
"type": {
"kind": "NON_NULL",
"name": null,
"ofType": {
"kind": "SCALAR",
"name": "Boolean",
"ofType": null
}
}
},
{
"args": [
{
"defaultValue": null,
"description": null,
"name": "query",
"type": {
"kind": "NON_NULL",
"name": null,
"ofType": {
"kind": "SCALAR",
"name": "String",
"ofType": null
}
}
},
{
"defaultValue": null,
"description": null,
"name": "tag",
"type": {
"kind": "NON_NULL",
"name": null,
"ofType": {
"kind": "SCALAR",
"name": "String",
"ofType": null
}
}
}
],
"deprecationReason": null,
"description": null,
"isDeprecated": false,
"name": "tagRemove",
"type": {
"kind": "NON_NULL",
"name": null,
"ofType": {
"kind": "SCALAR",
"name": "Boolean",
"ofType": null
}
}
}
],
"inputFields": null,

View File

@ -28,6 +28,22 @@ pub struct ShowThreadQuery;
)]
pub struct MarkReadMutation;
#[derive(GraphQLQuery)]
#[graphql(
schema_path = "graphql/schema.json",
query_path = "graphql/add_tag.graphql",
response_derives = "Debug"
)]
pub struct AddTagMutation;
#[derive(GraphQLQuery)]
#[graphql(
schema_path = "graphql/schema.json",
query_path = "graphql/remove_tag.graphql",
response_derives = "Debug"
)]
pub struct RemoveTagMutation;
pub async fn send_graphql<Body, Resp>(body: Body) -> Result<graphql_client::Response<Resp>, Error>
where
Body: Serialize,

View File

@ -184,6 +184,52 @@ pub fn update(msg: Msg, model: &mut Model, orders: &mut impl Orders<Msg>) {
Msg::Noop
});
}
Msg::AddTag(query, tag) => {
let search_url = urls::search(&model.query, 0).to_string();
orders.skip().perform_cmd(async move {
let res: Result<
graphql_client::Response<graphql::add_tag_mutation::ResponseData>,
gloo_net::Error,
> = send_graphql(graphql::AddTagMutation::build_query(
graphql::add_tag_mutation::Variables {
query: query.clone(),
tag: tag.clone(),
},
))
.await;
if let Err(e) = res {
error!("Failed to add tag {tag} to {query}: {e}");
}
seed::window()
.location()
.set_href(&search_url)
.expect("failed to change location");
Msg::Noop
});
}
Msg::RemoveTag(query, tag) => {
let search_url = urls::search(&model.query, 0).to_string();
orders.skip().perform_cmd(async move {
let res: Result<
graphql_client::Response<graphql::remove_tag_mutation::ResponseData>,
gloo_net::Error,
> = send_graphql(graphql::RemoveTagMutation::build_query(
graphql::remove_tag_mutation::Variables {
query: query.clone(),
tag: tag.clone(),
},
))
.await;
if let Err(e) = res {
error!("Failed to remove tag {tag} to {query}: {e}");
}
seed::window()
.location()
.set_href(&search_url)
.expect("failed to change location");
Msg::Noop
});
}
Msg::FrontPageRequest {
query,
@ -311,6 +357,36 @@ pub fn update(msg: Msg, model: &mut Model, orders: &mut impl Orders<Msg>) {
*selected_threads = results.iter().map(|node| node.thread.clone()).collect();
}
}
Msg::SelectionAddTag(tag) => {
if let Context::SearchResult {
selected_threads, ..
} = &mut model.context
{
let threads = selected_threads
.iter()
.map(|tid| format!("thread:{tid}"))
.collect::<Vec<_>>()
.join(" ");
orders
.skip()
.perform_cmd(async move { Msg::AddTag(threads, tag) });
}
}
Msg::SelectionRemoveTag(tag) => {
if let Context::SearchResult {
selected_threads, ..
} = &mut model.context
{
let threads = selected_threads
.iter()
.map(|tid| format!("thread:{tid}"))
.collect::<Vec<_>>()
.join(" ");
orders
.skip()
.perform_cmd(async move { Msg::RemoveTag(threads, tag) });
}
}
Msg::SelectionMarkAsRead => {
if let Context::SearchResult {
selected_threads, ..
@ -435,6 +511,8 @@ pub enum Msg {
SearchQuery(String),
SetUnread(String, bool),
AddTag(String, String),
RemoveTag(String, String),
FrontPageRequest {
query: String,
@ -455,6 +533,8 @@ pub enum Msg {
SelectionSetNone,
SelectionSetAll,
SelectionAddTag(String),
SelectionRemoveTag(String),
SelectionMarkAsRead,
SelectionMarkAsUnread,
SelectionAddThread(String),

View File

@ -261,6 +261,13 @@ fn search_toolbar(
span![
// TODO(wathiede): add "Mark as spam"
C!["level-item", "buttons", "has-addons"],
button![
C!["button"],
attrs!{At::Title => "Mark as spam"},
span![C!["icon", "is-small"], i![C!["far", "fa-hand"]]],
span!["Spam"],
ev(Ev::Click, |_| Msg::SelectionAddTag("Spam".to_string()))
],
button![
C!["button"],
attrs!{At::Title => "Mark as read"},
@ -721,13 +728,23 @@ fn thread(thread: &ShowThreadQueryThread, open_messages: &HashSet<String>) -> No
});
let read_thread_id = thread.thread_id.clone();
let unread_thread_id = thread.thread_id.clone();
let spam_thread_id = thread.thread_id.clone();
div![
C!["thread"],
h3![C!["is-size-5"], subject],
span![C!["tags"], tags_chiclet(&tags, false)],
span![
// TODO(wathiede): add "Mark as spam"
C!["level-item", "buttons", "has-addons"],
button![
C!["button"],
attrs! {At::Title => "Spam"},
span![C!["icon", "is-small"], i![C!["far", "fa-hand"]]],
span!["Spam"],
ev(Ev::Click, move |_| Msg::AddTag(
format!("thread:{spam_thread_id}"),
"Spam".to_string()
)),
],
button![
C!["button"],
attrs! {At::Title => "Mark as read"},