Add server-side work item search
This commit is contained in:
@@ -4,8 +4,8 @@ use gotcha_gitea::{
|
||||
|
||||
use crate::{
|
||||
domain::{
|
||||
HistoryCommit, HomeData, IssueDetails, IssueDraft, IssueEditorData, MilestoneDetails,
|
||||
MilestoneDraft, Page, PullDetails, RepositoryData, Server,
|
||||
HistoryCommit, HomeData, IssueDetails, IssueDraft, IssueEditorData, IssueFilter,
|
||||
MilestoneDetails, MilestoneDraft, Page, PullDetails, RepositoryData, Server,
|
||||
},
|
||||
presentation::compact_date,
|
||||
};
|
||||
@@ -46,8 +46,7 @@ pub async fn load_issues(
|
||||
owner: &str,
|
||||
repository: &str,
|
||||
status: &str,
|
||||
labels: &[String],
|
||||
milestone: &str,
|
||||
filter: &IssueFilter,
|
||||
page: i32,
|
||||
) -> Result<Page<models::Issue>, String> {
|
||||
client(server)?
|
||||
@@ -55,8 +54,10 @@ pub async fn load_issues(
|
||||
&scope(owner, repository)?,
|
||||
&IssueQuery {
|
||||
state: status.into(),
|
||||
labels: (!labels.is_empty()).then(|| labels.join(",")),
|
||||
milestones: (!milestone.is_empty()).then(|| milestone.into()),
|
||||
labels: (!filter.labels.is_empty())
|
||||
.then(|| filter.labels.iter().cloned().collect::<Vec<_>>().join(",")),
|
||||
milestones: (!filter.milestone.is_empty()).then(|| filter.milestone.clone()),
|
||||
keyword: (!filter.search_text.is_empty()).then(|| filter.search_text.clone()),
|
||||
page,
|
||||
limit: PAGE_SIZE,
|
||||
..Default::default()
|
||||
@@ -150,12 +151,14 @@ pub async fn load_pulls(
|
||||
server: &Server,
|
||||
status: &str,
|
||||
milestone: &str,
|
||||
search_text: &str,
|
||||
page: i32,
|
||||
) -> Result<Page<models::Issue>, String> {
|
||||
client(server)?
|
||||
.search_pulls(
|
||||
status,
|
||||
(!milestone.is_empty()).then_some(milestone),
|
||||
(!search_text.is_empty()).then_some(search_text),
|
||||
page,
|
||||
PAGE_SIZE,
|
||||
)
|
||||
|
||||
@@ -84,6 +84,8 @@ pub struct IssueFilter {
|
||||
pub milestone: String,
|
||||
#[serde(default)]
|
||||
pub labels: BTreeSet<String>,
|
||||
#[serde(skip)]
|
||||
pub search_text: String,
|
||||
}
|
||||
|
||||
impl IssueFilter {
|
||||
@@ -96,6 +98,8 @@ impl IssueFilter {
|
||||
pub struct PullFilter {
|
||||
#[serde(default)]
|
||||
pub milestone: String,
|
||||
#[serde(skip)]
|
||||
pub search_text: String,
|
||||
}
|
||||
|
||||
impl PullFilter {
|
||||
@@ -185,8 +189,44 @@ mod tests {
|
||||
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,
|
||||
""
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -268,14 +268,12 @@ impl GotchaCore {
|
||||
.unwrap_or_default(),
|
||||
)
|
||||
};
|
||||
let labels: Vec<_> = filter.labels.into_iter().collect();
|
||||
let page = load_issues(
|
||||
&server,
|
||||
&owner,
|
||||
&repository,
|
||||
&status,
|
||||
&labels,
|
||||
&filter.milestone,
|
||||
&filter,
|
||||
valid_page(page)?,
|
||||
)
|
||||
.await?;
|
||||
@@ -333,6 +331,7 @@ impl GotchaCore {
|
||||
repository: String,
|
||||
milestone: String,
|
||||
labels: Vec<String>,
|
||||
search_text: String,
|
||||
) -> Result<(), GotchaError> {
|
||||
let owner = owner.trim();
|
||||
let repository = repository.trim();
|
||||
@@ -345,6 +344,7 @@ impl GotchaCore {
|
||||
.into_iter()
|
||||
.filter(|label| !label.is_empty())
|
||||
.collect(),
|
||||
search_text: search_text.trim().into(),
|
||||
};
|
||||
let mut state = self.state.lock().unwrap();
|
||||
let server = state
|
||||
@@ -585,8 +585,15 @@ impl GotchaCore {
|
||||
Ok(filter.is_active(&state.preferences.pull_status))
|
||||
}
|
||||
|
||||
pub fn set_pull_filters(&self, milestone: String) -> Result<(), GotchaError> {
|
||||
let filter = PullFilter { milestone };
|
||||
pub fn set_pull_filters(
|
||||
&self,
|
||||
milestone: String,
|
||||
search_text: String,
|
||||
) -> Result<(), GotchaError> {
|
||||
let filter = PullFilter {
|
||||
milestone,
|
||||
search_text: search_text.trim().into(),
|
||||
};
|
||||
let mut state = self.state.lock().unwrap();
|
||||
let server = state
|
||||
.active_server
|
||||
@@ -627,7 +634,14 @@ impl GotchaCore {
|
||||
.unwrap_or_default(),
|
||||
)
|
||||
};
|
||||
let page = load_pulls(&server, &status, &filter.milestone, valid_page(page)?).await?;
|
||||
let page = load_pulls(
|
||||
&server,
|
||||
&status,
|
||||
&filter.milestone,
|
||||
&filter.search_text,
|
||||
valid_page(page)?,
|
||||
)
|
||||
.await?;
|
||||
Ok(PullListPage {
|
||||
rows: pull_rows(&page.items),
|
||||
has_more: page.has_more,
|
||||
|
||||
@@ -114,6 +114,7 @@ pub struct IssueFilterOptions {
|
||||
pub unavailable_labels: Vec<String>,
|
||||
pub selected_milestone: String,
|
||||
pub selected_labels: Vec<String>,
|
||||
pub search_text: String,
|
||||
}
|
||||
|
||||
#[derive(Clone, uniffi::Record)]
|
||||
@@ -153,6 +154,7 @@ pub struct MilestoneEditorPage {
|
||||
pub struct PullFilterOptions {
|
||||
pub milestones: Vec<String>,
|
||||
pub selected_milestone: String,
|
||||
pub search_text: String,
|
||||
}
|
||||
|
||||
#[derive(Clone, uniffi::Record)]
|
||||
@@ -365,6 +367,7 @@ pub fn issue_filter_options(
|
||||
unavailable_labels,
|
||||
selected_milestone: filter.milestone.clone(),
|
||||
selected_labels: filter.labels.iter().cloned().collect(),
|
||||
search_text: filter.search_text.clone(),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -419,6 +422,7 @@ pub fn pull_filter_options(milestones: &[String], filter: &PullFilter) -> PullFi
|
||||
PullFilterOptions {
|
||||
milestones,
|
||||
selected_milestone: filter.milestone.clone(),
|
||||
search_text: filter.search_text.clone(),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1365,6 +1369,7 @@ mod tests {
|
||||
let filter = IssueFilter {
|
||||
milestone: "v3".into(),
|
||||
labels: ["bug".into(), "retired".into()].into(),
|
||||
search_text: "login".into(),
|
||||
};
|
||||
let options = issue_filter_options(
|
||||
&[
|
||||
@@ -1395,15 +1400,18 @@ mod tests {
|
||||
assert_eq!(options.milestones, ["v1", "v2", "v3"]);
|
||||
assert_eq!(options.selected_labels, ["bug", "retired"]);
|
||||
assert_eq!(options.selected_milestone, "v3");
|
||||
assert_eq!(options.search_text, "login");
|
||||
|
||||
let pull_options = pull_filter_options(
|
||||
&["v2".into(), "v1".into()],
|
||||
&PullFilter {
|
||||
milestone: "v3".into(),
|
||||
search_text: "review".into(),
|
||||
},
|
||||
);
|
||||
assert_eq!(pull_options.milestones, ["v1", "v2", "v3"]);
|
||||
assert_eq!(pull_options.selected_milestone, "v3");
|
||||
assert_eq!(pull_options.search_text, "review");
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
||||
@@ -70,6 +70,7 @@ impl Client {
|
||||
&self,
|
||||
state: &str,
|
||||
milestone: Option<&str>,
|
||||
keyword: Option<&str>,
|
||||
page: i32,
|
||||
limit: i32,
|
||||
) -> Result<Page<models::Issue>> {
|
||||
@@ -84,7 +85,7 @@ impl Client {
|
||||
Some(state),
|
||||
None,
|
||||
milestone,
|
||||
None,
|
||||
keyword,
|
||||
None,
|
||||
Some("pulls"),
|
||||
None,
|
||||
@@ -122,7 +123,7 @@ impl Client {
|
||||
let mut pulls = Vec::new();
|
||||
for page in 1.. {
|
||||
let batch = self
|
||||
.search_pulls(state, None, page, DEFAULT_PAGE_SIZE)
|
||||
.search_pulls(state, None, None, page, DEFAULT_PAGE_SIZE)
|
||||
.await?;
|
||||
pulls.extend(batch.items);
|
||||
if !batch.has_more {
|
||||
|
||||
Reference in New Issue
Block a user