2024-05-13 19:13:40 +02:00
|
|
|
use leptos::*;
|
2024-05-22 23:54:00 +02:00
|
|
|
use leptos_router::*;
|
2024-05-13 19:13:40 +02:00
|
|
|
use crate::prelude::*;
|
|
|
|
|
|
|
|
#[component]
|
|
|
|
pub fn DebugPage() -> impl IntoView {
|
2024-05-22 23:54:00 +02:00
|
|
|
let query_params = use_query_map();
|
2024-05-13 19:13:40 +02:00
|
|
|
let auth = use_context::<Auth>().expect("missing auth context");
|
2024-05-23 01:26:38 +02:00
|
|
|
let (cached, set_cached) = create_signal(false);
|
2024-05-23 03:37:37 +02:00
|
|
|
let (error, set_error) = create_signal(false);
|
2024-05-23 01:05:59 +02:00
|
|
|
let (plain, set_plain) = create_signal(false);
|
2024-05-22 23:54:00 +02:00
|
|
|
let (text, set_text) = create_signal("".to_string());
|
|
|
|
let navigate = use_navigate();
|
|
|
|
|
2024-05-23 01:26:38 +02:00
|
|
|
let cached_query = move || (
|
|
|
|
query_params.with(|params| params.get("q").cloned().unwrap_or_default()),
|
|
|
|
cached.get(),
|
|
|
|
);
|
2024-05-22 23:54:00 +02:00
|
|
|
let object = create_local_resource(
|
2024-05-23 01:26:38 +02:00
|
|
|
cached_query,
|
|
|
|
move |(query, cached)| async move {
|
|
|
|
set_text.set(query.clone());
|
2024-05-23 16:15:39 +02:00
|
|
|
set_error.set(false);
|
2024-05-23 01:26:38 +02:00
|
|
|
if query.is_empty() { return serde_json::Value::Null };
|
2024-05-22 23:54:00 +02:00
|
|
|
if cached {
|
2024-05-23 01:26:38 +02:00
|
|
|
match CACHE.get(&query) {
|
2024-05-22 23:54:00 +02:00
|
|
|
Some(x) => (*x).clone(),
|
2024-05-23 16:15:39 +02:00
|
|
|
None => {
|
|
|
|
set_error.set(true);
|
|
|
|
serde_json::Value::Null
|
|
|
|
},
|
2024-05-22 23:54:00 +02:00
|
|
|
}
|
|
|
|
} else {
|
2024-05-23 03:37:37 +02:00
|
|
|
debug_fetch(&format!("{URL_BASE}/proxy?id={query}"), auth, set_error).await
|
2024-05-22 23:54:00 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
);
|
|
|
|
let loading = object.loading();
|
|
|
|
|
|
|
|
|
2024-05-13 19:13:40 +02:00
|
|
|
view! {
|
|
|
|
<div>
|
|
|
|
<Breadcrumb back=true>config :: devtools</Breadcrumb>
|
|
|
|
<div class="mt-1" >
|
|
|
|
<form on:submit=move|ev| {
|
|
|
|
ev.prevent_default();
|
2024-05-22 23:54:00 +02:00
|
|
|
navigate(&format!("/web/config/dev?q={}", text.get()), NavigateOptions::default());
|
2024-05-13 19:13:40 +02:00
|
|
|
} >
|
2024-05-23 01:45:34 +02:00
|
|
|
<table class="align w-100">
|
|
|
|
<tr>
|
|
|
|
<td class="w-100">
|
|
|
|
<input class="w-100" type="text"
|
|
|
|
prop:value=text
|
|
|
|
on:input=move|ev| set_text.set(event_target_value(&ev))
|
|
|
|
placeholder="AP id"
|
|
|
|
/>
|
|
|
|
</td>
|
|
|
|
<td>
|
|
|
|
<input type="submit" class="w-100" value="fetch" />
|
|
|
|
</td>
|
|
|
|
<td>
|
|
|
|
<input type="checkbox" title="load from local cache" value="cached"
|
2024-05-23 15:07:59 +02:00
|
|
|
class:spinner=loading
|
2024-05-23 01:45:34 +02:00
|
|
|
prop:checked=cached
|
|
|
|
on:input=move |ev| set_cached.set(event_target_checked(&ev))
|
|
|
|
/>
|
|
|
|
</td>
|
|
|
|
</tr>
|
|
|
|
</table>
|
2024-05-13 19:13:40 +02:00
|
|
|
</form>
|
|
|
|
</div>
|
2024-05-23 03:37:37 +02:00
|
|
|
<pre class="ma-1" class:striped=error>
|
2024-05-23 04:07:43 +02:00
|
|
|
{move || match object.get() {
|
|
|
|
None => view! { <p class="center"><span class="dots"></span></p> }.into_view(),
|
|
|
|
Some(o) => if plain.get() {
|
|
|
|
serde_json::to_string_pretty(&o).unwrap_or_else(|e| e.to_string()).into_view()
|
|
|
|
} else {
|
|
|
|
view! { <DocumentNode obj=o /> }.into_view()
|
|
|
|
},
|
|
|
|
}}
|
2024-05-13 19:13:40 +02:00
|
|
|
</pre>
|
2024-05-23 01:05:59 +02:00
|
|
|
<p class="center">
|
2024-05-23 01:45:34 +02:00
|
|
|
<input type="checkbox" title="show plain (and valid) json" value="plain" prop:checked=plain on:input=move |ev| set_plain.set(event_target_checked(&ev)) />
|
2024-05-23 02:32:52 +02:00
|
|
|
" raw :: "
|
2024-05-23 01:45:34 +02:00
|
|
|
<a href={move|| Uri::web(U::Object, &text.get())} >obj</a>
|
|
|
|
" :: "
|
2024-05-29 21:36:55 +02:00
|
|
|
<a href={move|| Uri::web(U::Actor, &text.get())} >usr</a>
|
2024-05-23 01:45:34 +02:00
|
|
|
" :: "
|
|
|
|
<a href=move || cached_query().0 target="_blank" rel="nofollow noreferrer">ext</a>
|
|
|
|
" :: "
|
|
|
|
<a href="#"
|
|
|
|
onclick={move ||
|
|
|
|
format!(
|
|
|
|
"javascript:navigator.clipboard.writeText(`{}`)",
|
|
|
|
object.get().map(|x| serde_json::to_string(&x).unwrap_or_default()).unwrap_or_default()
|
|
|
|
)
|
|
|
|
} >copy</a>
|
2024-05-23 01:05:59 +02:00
|
|
|
</p>
|
2024-05-13 19:13:40 +02:00
|
|
|
</div>
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// this is a rather weird way to fetch but i want to see the bare error text if it fails!
|
2024-05-23 03:37:37 +02:00
|
|
|
async fn debug_fetch(url: &str, token: Auth, error: WriteSignal<bool>) -> serde_json::Value {
|
2024-05-13 19:13:40 +02:00
|
|
|
match Http::request::<()>(reqwest::Method::GET, url, None, token).await {
|
2024-05-23 03:37:37 +02:00
|
|
|
Ok(res) => {
|
|
|
|
if res.error_for_status_ref().is_err() {
|
|
|
|
error.set(true); // this is an error but body could still be useful json
|
|
|
|
}
|
|
|
|
match res.text().await {
|
|
|
|
Ok(x) => match serde_json::from_str(&x) {
|
|
|
|
Ok(v) => v,
|
|
|
|
Err(_) => {
|
|
|
|
error.set(true);
|
|
|
|
serde_json::Value::String(x)
|
|
|
|
},
|
|
|
|
},
|
|
|
|
Err(e) => {
|
|
|
|
error.set(true);
|
|
|
|
serde_json::Value::String(format!("[!] invalid response body: {e}"))
|
|
|
|
},
|
|
|
|
}
|
|
|
|
},
|
|
|
|
Err(e) => {
|
|
|
|
error.set(true);
|
|
|
|
serde_json::Value::String(format!("[!] failed sending request: {e}"))
|
|
|
|
},
|
2024-05-13 19:13:40 +02:00
|
|
|
}
|
|
|
|
}
|
2024-05-22 23:54:00 +02:00
|
|
|
|
|
|
|
#[component]
|
|
|
|
fn DocumentNode(obj: serde_json::Value, #[prop(optional)] depth: usize) -> impl IntoView {
|
|
|
|
let prefix = " ".repeat(depth);
|
2024-05-23 01:26:38 +02:00
|
|
|
let newline_replace = format!("\n{prefix} ");
|
2024-05-22 23:54:00 +02:00
|
|
|
match obj {
|
|
|
|
serde_json::Value::Null => view! { <b>null</b> }.into_view(),
|
|
|
|
serde_json::Value::Bool(x) => view! { <b>{x}</b> }.into_view(),
|
|
|
|
serde_json::Value::Number(n) => view! { <b>{n.to_string()}</b> }.into_view(),
|
|
|
|
serde_json::Value::String(s) => {
|
|
|
|
if s.starts_with("https://") || s.starts_with("http://") {
|
|
|
|
view! {
|
2024-05-23 01:05:59 +02:00
|
|
|
<a href=format!("/web/config/dev?q={s}")>{s}</a>
|
2024-05-22 23:54:00 +02:00
|
|
|
}.into_view()
|
|
|
|
} else {
|
2024-05-23 23:09:11 +02:00
|
|
|
let pretty_string = s
|
|
|
|
.replace("<br/>", "<br/>\n")
|
|
|
|
.replace("<br>", "<br>\n")
|
|
|
|
.replace('\n', &newline_replace);
|
2024-05-22 23:54:00 +02:00
|
|
|
view! {
|
2024-05-23 23:09:11 +02:00
|
|
|
"\""<span class="json-text"><i>{pretty_string}</i></span>"\""
|
2024-05-22 23:54:00 +02:00
|
|
|
}.into_view()
|
|
|
|
}
|
|
|
|
},
|
|
|
|
serde_json::Value::Array(arr) => if arr.is_empty() {
|
|
|
|
view! { "[]" }.into_view()
|
|
|
|
} else {
|
|
|
|
view! {
|
|
|
|
"[\n"
|
|
|
|
{arr.into_iter().map(|x| view! {
|
2024-05-23 01:05:59 +02:00
|
|
|
{prefix.clone()}" "<DocumentNode obj=x depth=depth+1 />"\n"
|
2024-05-22 23:54:00 +02:00
|
|
|
}).collect_view()}
|
|
|
|
{prefix.clone()}"]"
|
|
|
|
}.into_view()
|
|
|
|
},
|
|
|
|
serde_json::Value::Object(map) => if map.is_empty() {
|
|
|
|
view! { "{}" }.into_view()
|
|
|
|
} else {
|
|
|
|
view! {
|
|
|
|
"{\n"
|
|
|
|
{
|
|
|
|
map.into_iter()
|
|
|
|
.map(|(k, v)| view! {
|
2024-05-23 01:05:59 +02:00
|
|
|
{prefix.clone()}" "<span class="json-key"><b>{k}</b></span>": "<DocumentNode obj=v depth=depth+1 />"\n"
|
2024-05-22 23:54:00 +02:00
|
|
|
})
|
|
|
|
.collect_view()
|
|
|
|
}
|
|
|
|
{prefix.clone()}"}"
|
|
|
|
}.into_view()
|
|
|
|
},
|
|
|
|
}
|
|
|
|
}
|