Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

WIP: Upgrade to Leptos 0.5 #78

Closed
wants to merge 2 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
699 changes: 261 additions & 438 deletions Cargo.lock

Large diffs are not rendered by default.

10 changes: 5 additions & 5 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,10 @@ repository = "https://github.com/juspay/nix-browser"
cfg-if = "1"
clap = { version = "4.3", features = ["derive", "env"] }
human-panic = "1.1.5"
leptos = { version = "0.4", features = ["serde", "nightly"] }
leptos_meta = { version = "0.4", features = ["nightly"] }
leptos_router = { version = "0.4", features = ["nightly"] }
leptos_query = "0.2"
leptos = { version = "0.5", features = ["serde", "nightly"] }
leptos_meta = { version = "0.5", features = ["nightly"] }
leptos_router = { version = "0.5", features = ["nightly"] }
leptos_query = "0.3"
tracing = "0.1"
tracing-subscriber = { version = "0.3", features = ["env-filter"] }
tracing-subscriber-wasm = "0.1"
Expand Down Expand Up @@ -53,7 +53,7 @@ http = { version = "0.2", optional = true }
human-panic.workspace = true
hyper = { version = "0.14", features = ["server"], optional = true }
leptos.workspace = true
leptos_axum = { version = "0.4", optional = true }
leptos_axum = { version = "0.5", optional = true }
leptos_meta.workspace = true
leptos_router.workspace = true
leptos_query.workspace = true
Expand Down
9 changes: 3 additions & 6 deletions crates/leptos_extra/src/query.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,14 +29,13 @@ pub fn query_options<V>() -> QueryOptions<V> {
/// * `fetcher`: The server fn to call
#[instrument(
name = "use_server_query",
skip(cx, k, fetcher),
skip(k, fetcher),
fields(
fetcher = std::any::type_name::<F>(),
render_mode=LEPTOS_MODE
)
)]
pub fn use_server_query<K, V, F, Fu>(
cx: Scope,
k: impl Fn() -> K + 'static,
fetcher: F,
) -> QueryResult<ServerFnResult<V>, impl RefetchFn>
Expand All @@ -49,7 +48,6 @@ where
let span = tracing::Span::current();
tracing::debug!("use_query");
leptos_query::use_query(
cx,
k,
move |k| {
let _enter = span.enter();
Expand Down Expand Up @@ -77,7 +75,6 @@ const LEPTOS_MODE: &str = {
/// * `query`: The value to pass to [invalidate_query]
#[component]
pub fn RefetchQueryButton<K, V, R, F>(
cx: Scope,
result: QueryResult<ServerFnResult<V>, R>,
query: F,
) -> impl IntoView
Expand All @@ -87,14 +84,14 @@ where
R: RefetchFn,
F: Fn() -> K + 'static,
{
view! { cx,
view! {
<button
class="p-1 text-white shadow border-1 bg-primary-700 disabled:bg-base-400 disabled:text-black"
disabled=move || result.is_fetching.get()
on:click=move |_| {
let k = query();
tracing::debug!("Invalidating query");
use_query_client(cx).invalidate_query::<K, ServerFnResult<V>>(k);
use_query_client().invalidate_query::<K, ServerFnResult<V>>(k);
}
>

Expand Down
12 changes: 6 additions & 6 deletions crates/leptos_extra/src/signal.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,18 +3,18 @@ use leptos::*;
use tracing::instrument;

/// [provide_context] a new signal of type `T` in the current scope
pub fn provide_signal<T: 'static>(cx: Scope, default: T) {
let sig = create_rw_signal(cx, default);
provide_context(cx, sig);
pub fn provide_signal<T: 'static>(default: T) {
let sig = create_rw_signal(default);
provide_context(sig);
}

/// [use_context] the signal of type `T` in the current scope
///
/// If the signal was not provided in a top-level scope (via [provide_signal])
/// this method will panic after tracing an error.
#[instrument(name = "use_signal")]
pub fn use_signal<T>(cx: Scope) -> RwSignal<T> {
use_context(cx)
pub fn use_signal<T>() -> RwSignal<T> {
use_context()
.ok_or_else(|| {
// This happens if the dev forgets to call `provide_signal::<T>` in
// the parent scope
Expand All @@ -30,7 +30,7 @@ pub fn use_signal<T>(cx: Scope) -> RwSignal<T> {

/// Extends [SignalWith] to add a `with_result` method that operates on the
/// inner value, avoiding the need to clone it.
pub trait SignalWithResult<T, E>: SignalWith<Option<Result<T, E>>> {
pub trait SignalWithResult<T, E>: SignalWith<Value = Option<Result<T, E>>> {
/// Like [SignalWith::with] but operates on the inner [Result] value without cloning it.
fn with_result<U>(&self, f: impl Fn(&T) -> U + 'static) -> Option<Result<U, E>>
where
Expand Down
101 changes: 51 additions & 50 deletions src/app/flake.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
//! UI for /flake segment of the app

// https://github.com/leptos-rs/leptos/issues/1825
#![allow(clippy::needless_lifetimes)]

use std::collections::BTreeMap;

use leptos::*;
Expand All @@ -23,13 +26,13 @@ use crate::widget::*;

/// Nix flake dashboard
#[component]
pub fn NixFlakeRoute(cx: Scope) -> impl IntoView {
pub fn NixFlakeRoute() -> impl IntoView {
let suggestions = FlakeUrl::suggestions();
let url = use_signal::<FlakeUrl>(cx);
let refresh = use_signal::<Refresh>(cx);
let url = use_signal::<FlakeUrl>();
let refresh = use_signal::<Refresh>();
let query = move || (url(), refresh());
let result = query::use_server_query(cx, query, get_flake);
view! { cx,
let result = query::use_server_query(query, get_flake);
view! {
<Title text="Nix Flake"/>
<h1 class="text-5xl font-bold">{"Nix Flake"}</h1>
<TextInput id="nix-flake-input" label="Load a Nix Flake" val=url suggestions/>
Expand All @@ -39,18 +42,18 @@ pub fn NixFlakeRoute(cx: Scope) -> impl IntoView {
}

#[component]
pub fn NixFlakeHomeRoute(cx: Scope) -> impl IntoView {
let url = use_signal::<FlakeUrl>(cx);
let refresh = use_signal::<Refresh>(cx);
pub fn NixFlakeHomeRoute() -> impl IntoView {
let url = use_signal::<FlakeUrl>();
let refresh = use_signal::<Refresh>();
let query = move || (url(), refresh());
let result = query::use_server_query(cx, query, get_flake);
let result = query::use_server_query(query, get_flake);
let data = result.data;
view! { cx,
view! {
<div class="p-2 my-1">
<SuspenseWithErrorHandling>
{move || {
data.with_result(move |flake| {
view! { cx, <FlakeView flake/> }
view! { <FlakeView flake/> }
})
}}

Expand All @@ -60,21 +63,21 @@ pub fn NixFlakeHomeRoute(cx: Scope) -> impl IntoView {
}

#[component]
pub fn NixFlakeRawRoute(cx: Scope) -> impl IntoView {
let url = use_signal::<FlakeUrl>(cx);
let refresh = use_signal::<Refresh>(cx);
pub fn NixFlakeRawRoute() -> impl IntoView {
let url = use_signal::<FlakeUrl>();
let refresh = use_signal::<Refresh>();
let query = move || (url(), refresh());
let result = query::use_server_query(cx, query, get_flake);
let result = query::use_server_query(query, get_flake);
let data = result.data;
view! { cx,
view! {
<div>
<A href="/flake">"< Back"</A>
</div>
<div class="px-4 py-2 font-mono text-xs text-left text-gray-500 border-2 border-black">
<SuspenseWithErrorHandling>
{move || {
data.with_result(move |r| {
view! { cx, <FlakeOutputsRawView outs=&r.output/> }
view! { <FlakeOutputsRawView outs=&r.output/> }
})
}}

Expand All @@ -84,8 +87,8 @@ pub fn NixFlakeRawRoute(cx: Scope) -> impl IntoView {
}

#[component]
fn FlakeView<'a>(cx: Scope, flake: &'a Flake) -> impl IntoView {
view! { cx,
fn FlakeView<'a>(flake: &'a Flake) -> impl IntoView {
view! {
<div class="flex flex-col my-4">
<h3 class="text-lg font-bold">{flake.url.to_string()}</h3>
<div class="text-sm italic text-gray-600">
Expand All @@ -101,18 +104,18 @@ fn FlakeView<'a>(cx: Scope, flake: &'a Flake) -> impl IntoView {
}

#[component]
fn SectionHeading(cx: Scope, title: &'static str) -> impl IntoView {
view! { cx,
fn SectionHeading(title: &'static str) -> impl IntoView {
view! {
<h3 class="p-2 mt-4 mb-2 font-bold bg-gray-300 border-b-2 border-l-2 border-black text-l">
{title}
</h3>
}
}

#[component]
fn FlakeSchemaView<'a>(cx: Scope, schema: &'a FlakeSchema) -> impl IntoView {
fn FlakeSchemaView<'a>(schema: &'a FlakeSchema) -> impl IntoView {
let system = &schema.system.clone();
view! { cx,
view! {
<div>
<h2 class="my-2 ">
<div class="text-xl font-bold text-primary-600">{system.human_readable()}</div>
Expand All @@ -133,16 +136,18 @@ fn FlakeSchemaView<'a>(cx: Scope, schema: &'a FlakeSchema) -> impl IntoView {
.map(|v| {
let default = "formatter".to_string();
let k = v.name.as_ref().unwrap_or(&default);
view! { cx, <FlakeValView k v/> }
view! { <FlakeValView k v/> }
})}

<SectionHeading title="Other"/>
{schema
.other
.as_ref()
.map(|v| {
// TODO: Use a non-recursive rendering component?
view! { cx, <FlakeOutputsRawView outs=&FlakeOutputs::Attrset(v.clone())/> }
view! {
// TODO: Use a non-recursive rendering component?
<FlakeOutputsRawView outs=&FlakeOutputs::Attrset(v.clone())/>
}
})}

</div>
Expand All @@ -151,31 +156,27 @@ fn FlakeSchemaView<'a>(cx: Scope, schema: &'a FlakeSchema) -> impl IntoView {
}

#[component]
fn BTreeMapView<'a>(
cx: Scope,
title: &'static str,
tree: &'a BTreeMap<String, Val>,
) -> impl IntoView {
fn BTreeMapView<'a>(title: &'static str, tree: &'a BTreeMap<String, Val>) -> impl IntoView {
(!tree.is_empty()).then(move || {
view! { cx,
view! {
<SectionHeading title/>
<BTreeMapBodyView tree/>
}
})
}

#[component]
fn BTreeMapBodyView<'a>(cx: Scope, tree: &'a BTreeMap<String, Val>) -> impl IntoView {
view! { cx,
fn BTreeMapBodyView<'a>(tree: &'a BTreeMap<String, Val>) -> impl IntoView {
view! {
<div class="flex flex-wrap justify-start">
{tree.iter().map(|(k, v)| view! { cx, <FlakeValView k v/> }).collect_view(cx)}
{tree.iter().map(|(k, v)| view! { <FlakeValView k v/> }).collect_view()}
</div>
}
}

#[component]
fn FlakeValView<'a>(cx: Scope, k: &'a String, v: &'a Val) -> impl IntoView {
view! { cx,
fn FlakeValView<'a>(k: &'a String, v: &'a Val) -> impl IntoView {
view! {
<div
title=format!("{:?}", v.type_)
class="flex flex-col p-2 my-2 mr-2 space-y-2 bg-white border-4 border-gray-300 rounded hover:border-gray-400"
Expand All @@ -188,14 +189,14 @@ fn FlakeValView<'a>(cx: Scope, k: &'a String, v: &'a Val) -> impl IntoView {
.name
.as_ref()
.map(|v| {
view! { cx, <div class="font-mono text-xs text-gray-500">{v}</div> }
view! { <div class="font-mono text-xs text-gray-500">{v}</div> }
})}

{v
.description
.as_ref()
.map(|v| {
view! { cx, <div class="font-light">{v}</div> }
view! { <div class="font-light">{v}</div> }
})}

</div>
Expand All @@ -207,9 +208,9 @@ fn FlakeValView<'a>(cx: Scope, k: &'a String, v: &'a Val) -> impl IntoView {
///
/// WARNING: This may cause performance problems if the tree is large.
#[component]
fn FlakeOutputsRawView<'a>(cx: Scope, outs: &'a FlakeOutputs) -> impl IntoView {
fn view_val<'b>(cx: Scope, val: &'b Val) -> View {
view! { cx,
fn FlakeOutputsRawView<'a>(outs: &'a FlakeOutputs) -> impl IntoView {
fn view_val(val: &Val) -> View {
view! {
<span>
<b>{val.name.clone()}</b>
" ("
Expand All @@ -218,12 +219,12 @@ fn FlakeOutputsRawView<'a>(cx: Scope, outs: &'a FlakeOutputs) -> impl IntoView {
<em>{val.description.clone()}</em>
</span>
}
.into_view(cx)
.into_view()
}

#[component]
fn TypeView<'b>(cx: Scope, type_: &'b Type) -> impl IntoView {
view! { cx,
fn TypeView<'b>(type_: &'b Type) -> impl IntoView {
view! {
<span>
{match type_ {
Type::NixosModule => "nixosModule ❄️",
Expand All @@ -237,23 +238,23 @@ fn FlakeOutputsRawView<'a>(cx: Scope, outs: &'a FlakeOutputs) -> impl IntoView {
}
}
match outs {
FlakeOutputs::Val(v) => view_val(cx, v),
FlakeOutputs::Attrset(v) => view! { cx,
FlakeOutputs::Val(v) => view_val(v),
FlakeOutputs::Attrset(v) => view! {
<ul class="list-disc">
{v
.iter()
.map(|(k, v)| {
view! { cx,
view! {
<li class="ml-4">
<span class="px-2 py-1 font-bold text-primary-500">{k}</span>
<FlakeOutputsRawView outs=v/>
</li>
}
})
.collect_view(cx)}
.collect_view()}
</ul>
}
.into_view(cx),
.into_view(),
}
}

Expand Down
Loading