flams_router_dashboard/
query.rs1use flams_web_utils::inject_css;
2use leptos::prelude::*;
3
4#[server(QueryApi,
5 prefix="/api/backend",
6 endpoint="query",
7 input=server_fn::codec::PostUrl,
8 output=server_fn::codec::Json
9)]
10#[cfg_attr(
11 feature = "ssr",
12 tracing::instrument(level = "info", name = "query", target = "query", skip_all)
13)]
14pub async fn query_api(query: String) -> Result<String, ServerFnError<String>> {
15 use flams_system::backend::GlobalBackend;
16 use flams_system::backend::rdf::QueryResult;
17 tracing::info!("Query: {query}");
18 let r = tokio::task::spawn_blocking(move || {
19 GlobalBackend::get()
20 .triple_store()
21 .query_str(&query)
22 .map(QueryResult::into_json)
23 })
24 .await; match r {
26 Ok(Ok(Ok(r))) => Ok(r),
27 Ok(Ok(Err(e)) | Err(e)) => Err(ServerFnError::WrappedServerError(e.to_string())),
28 Err(e) => Err(ServerFnError::WrappedServerError(e.to_string())),
29 }
30}
31
32const QUERY: &str = r"SELECT ?x ?y WHERE {
33 ?x rdf:type ulo:declaration .
34 ?y rdf:type ulo:notation .
35 ?y ulo:notation-for ?x.
36}";
37
38#[component]
39pub fn Query() -> impl IntoView {
40 use leptos::form::ActionForm;
41 inject_css("flams-query", include_str!("query.css"));
42
43 let action = ServerAction::<QueryApi>::new();
44 let rf = NodeRef::<leptos::html::Div>::new();
45 let result = Memo::new(move |_| {
46 action.value().get().map(|result| match result {
47 Ok(r) => r,
48 Err(e) => format!("Error: {e}"),
49 })
50 });
51
52 view! {
53 <div>
54 <h1>Query</h1>
55 <ActionForm action>
56 <span class="flams-query-container">
57 <textarea name="query" class="flams-query-inner">{QUERY.to_string()}</textarea>
58 </span>
59 <br/><input type="submit" value="Query"/>
60 </ActionForm>
61 <div node_ref=rf style="text-align:left;margin:10px;font-family:monospace;white-space:pre;border:var(--strokeWidthThickest) solid var(--colorNeutralStroke1);text-wrap:pretty;">
62 {move || result.get().unwrap_or_default()}
63 </div>
64 </div>
65 }
66}