wsb 0.164.718

Workspace - A tool suite for file operations, version management, and development workflow automation
use crate::prelude::*;
use axum::{
    extract::{Query, State},
    http::StatusCode,
    Json,
};

use super::sessions::ErrorResponse;
use crate::fleet::config::GitModules;
use crate::fleet::error::SuperGitError;
use crate::web::notes;
use crate::web::state::WebState;

fn internal_err(e: anyhow::Error) -> (StatusCode, Json<ErrorResponse>) {
    (
        StatusCode::INTERNAL_SERVER_ERROR,
        Json(ErrorResponse { error: e.to_string() }),
    )
}

#[derive(Deserialize)]
pub struct PathQuery {
    pub path: Option<String>,
}

/// GET /path-notes?path=<linked_path>
/// Returns notes whose content contains a markdown link to `path`.
/// Without `?path=`, returns all notes in the workspace.
pub async fn list_path_notes(
    State(state): State<WebState>,
    Query(q): Query<PathQuery>,
) -> Result<Json<serde_json::Value>, (StatusCode, Json<ErrorResponse>)> {
    let root = state.workspace_root.clone();
    let notes = match q.path {
        Some(ref path) => notes::list_path_notes(&root, path).map_err(internal_err)?,
        None => notes::list_all_notes(&root).map_err(internal_err)?,
    };
    Ok(Json(serde_json::json!({ "notes": notes })))
}

#[derive(Deserialize)]
pub struct CreateNoteBody {
    /// Workspace-relative path the new note should link to.
    pub path: String,
}

/// POST /path-notes
/// Creates a new `.md` file in `docs/` (or `<submodule>/docs/`) pre-seeded
/// with a link to `path`.  Returns the note metadata; the client should open
/// `note.path` in an editor tab.
pub async fn create_path_note(
    State(state): State<WebState>,
    Json(body): Json<CreateNoteBody>,
) -> Result<(StatusCode, Json<serde_json::Value>), (StatusCode, Json<ErrorResponse>)> {
    if body.path.trim().is_empty() {
        return Err((
            StatusCode::UNPROCESSABLE_ENTITY,
            Json(ErrorResponse { error: "path must not be empty".to_string() }),
        ));
    }

    let root = state.workspace_root.clone();

    // Discover submodule paths so create_path_note can choose the right docs/ directory.
    let submodule_paths: Vec<String> = match GitModules::parse(&root) {
        Ok(gm) => gm
            .submodules
            .iter()
            .map(|s| s.path.to_string_lossy().into_owned())
            .collect(),
        Err(SuperGitError::NoSubmodules) => vec![],
        Err(e) => return Err(internal_err(e.into())),
    };

    let note = notes::create_path_note(&root, &body.path, &submodule_paths)
        .map_err(internal_err)?;
    Ok((StatusCode::CREATED, Json(serde_json::json!({ "note": note }))))
}