various: markdown improvements

Signed-off-by: NotAShelf <raf@notashelf.dev>
Change-Id: I81fda8247814da19eed1e76dbe97bd5b6a6a6964
This commit is contained in:
raf 2026-02-05 15:39:05 +03:00
commit 80a8b5c7ca
Signed by: NotAShelf
GPG key ID: 29D95B64378DB4BF
23 changed files with 3458 additions and 30 deletions

View file

@ -277,6 +277,74 @@ pub struct DatabaseStatsResponse {
pub backend_name: String,
}
// ── Markdown Notes/Links Response Types ──
#[derive(Debug, Clone, PartialEq, Deserialize)]
pub struct BacklinksResponse {
pub backlinks: Vec<BacklinkItem>,
pub count: usize,
}
#[derive(Debug, Clone, PartialEq, Deserialize)]
pub struct BacklinkItem {
pub link_id: String,
pub source_id: String,
pub source_title: Option<String>,
pub source_path: String,
pub link_text: Option<String>,
pub line_number: Option<i32>,
pub context: Option<String>,
pub link_type: String,
}
#[derive(Debug, Clone, PartialEq, Deserialize)]
pub struct OutgoingLinksResponse {
pub links: Vec<OutgoingLinkItem>,
pub count: usize,
}
#[derive(Debug, Clone, PartialEq, Deserialize)]
pub struct OutgoingLinkItem {
pub id: String,
pub target_path: String,
pub target_id: Option<String>,
pub link_text: Option<String>,
pub line_number: Option<i32>,
pub link_type: String,
pub is_resolved: bool,
}
#[derive(Debug, Clone, PartialEq, Deserialize)]
pub struct GraphResponse {
pub nodes: Vec<GraphNodeResponse>,
pub edges: Vec<GraphEdgeResponse>,
pub node_count: usize,
pub edge_count: usize,
}
#[derive(Debug, Clone, PartialEq, Deserialize)]
pub struct GraphNodeResponse {
pub id: String,
pub label: String,
pub title: Option<String>,
pub media_type: String,
pub link_count: u32,
pub backlink_count: u32,
}
#[derive(Debug, Clone, PartialEq, Deserialize)]
pub struct GraphEdgeResponse {
pub source: String,
pub target: String,
pub link_type: String,
}
#[derive(Debug, Clone, PartialEq, Deserialize)]
pub struct ReindexLinksResponse {
pub message: String,
pub links_extracted: usize,
}
#[derive(Debug, Clone, PartialEq, Deserialize, Serialize)]
pub struct SavedSearchResponse {
pub id: String,
@ -1073,6 +1141,85 @@ impl ApiClient {
Ok(())
}
// ── Markdown Notes/Links ──
/// Get backlinks (incoming links) to a media item.
pub async fn get_backlinks(&self, id: &str) -> Result<BacklinksResponse> {
Ok(self
.client
.get(self.url(&format!("/media/{id}/backlinks")))
.send()
.await?
.error_for_status()?
.json()
.await?)
}
/// Get outgoing links from a media item.
pub async fn get_outgoing_links(&self, id: &str) -> Result<OutgoingLinksResponse> {
Ok(self
.client
.get(self.url(&format!("/media/{id}/outgoing-links")))
.send()
.await?
.error_for_status()?
.json()
.await?)
}
/// Get graph data for visualization.
pub async fn get_graph(&self, center_id: Option<&str>, depth: Option<u32>) -> Result<GraphResponse> {
let mut url = self.url("/notes/graph");
let mut query_parts = Vec::new();
if let Some(center) = center_id {
query_parts.push(format!("center={}", center));
}
if let Some(d) = depth {
query_parts.push(format!("depth={}", d));
}
if !query_parts.is_empty() {
url = format!("{}?{}", url, query_parts.join("&"));
}
Ok(self
.client
.get(&url)
.send()
.await?
.error_for_status()?
.json()
.await?)
}
/// Re-extract links from a media item.
pub async fn reindex_links(&self, id: &str) -> Result<ReindexLinksResponse> {
Ok(self
.client
.post(self.url(&format!("/media/{id}/reindex-links")))
.send()
.await?
.error_for_status()?
.json()
.await?)
}
/// Get count of unresolved links.
pub async fn get_unresolved_links_count(&self) -> Result<u64> {
#[derive(Deserialize)]
struct CountResp {
count: u64,
}
let resp: CountResp = self
.client
.get(self.url("/notes/unresolved-count"))
.send()
.await?
.error_for_status()?
.json()
.await?;
Ok(resp.count)
}
pub fn set_token(&mut self, token: &str) {
let mut headers = header::HeaderMap::new();
if let Ok(val) = header::HeaderValue::from_str(&format!("Bearer {token}")) {