fedimint_server_ui/dashboard/modules/
lnv2.rs
1use axum::extract::{Form, State};
2use axum::response::{IntoResponse, Redirect};
3use fedimint_core::util::SafeUrl;
4use fedimint_server_core::dashboard_ui::{DashboardApiModuleExt, DynDashboardApi};
5use maud::{Markup, html};
6
7use crate::auth::UserAuth;
8use crate::{ROOT_ROUTE, UiState};
9
10pub const LNV2_ADD_ROUTE: &str = "/lnv2/add";
12pub const LNV2_REMOVE_ROUTE: &str = "/lnv2/remove";
13
14#[derive(serde::Deserialize)]
16pub struct GatewayForm {
17 pub gateway_url: SafeUrl,
18}
19
20pub async fn render(lightning: &fedimint_lnv2_server::Lightning) -> Markup {
22 let gateways = lightning.gateways_ui().await;
23 let consensus_block_count = lightning.consensus_block_count_ui().await;
24 let consensus_unix_time = lightning.consensus_unix_time_ui().await;
25 let formatted_unix_time = chrono::DateTime::from_timestamp(consensus_unix_time as i64, 0)
26 .map(|dt| dt.to_rfc2822())
27 .unwrap_or("Invalid time".to_string());
28
29 html! {
30 div class="card h-100" {
31 div class="card-header dashboard-header" { "Lightning V2" }
32 div class="card-body" {
33 div class="mb-4" {
35 table
36 class="table"
37 id="lnv2-module-timers" hx-swap-oob=(true)
38 {
39 tr {
40 th { "Consensus Block Count" }
41 td { (consensus_block_count) }
42 }
43 tr {
44 th { "Consensus Unix Time" }
45 td { (formatted_unix_time) }
46 }
47 }
48 }
49
50 div {
52 div class="row" {
53 div class="col-lg-6 pe-lg-4 position-relative" {
55 div class="h-100" {
56 @if gateways.is_empty() {
57 div class="text-center p-4" {
58 p { "You need a Lightning gateway to connect to your federation and then add its URL here in the dashboard to enable V2 Lightning payments for your users. You can either run your own gateway or reach out to the Fedimint team on " a href="https://chat.fedimint.org/" { "Discord" } " - we are running our own gateway and are happy to get you started." }
59 }
60 } @else {
61 div class="table-responsive" {
62 table class="table table-hover" {
63 tbody {
64 @for gateway in &gateways {
65 tr {
66 td { (gateway.to_string()) }
67 td class="text-end" {
68 form action=(LNV2_REMOVE_ROUTE) method="post" style="display: inline;" {
69 input type="hidden" name="gateway_url" value=(gateway.to_string());
70 button type="submit" class="btn btn-sm btn-danger" {
71 "Remove"
72 }
73 }
74 }
75 }
76 }
77 }
78 }
79 }
80 }
81 }
82 div class="position-absolute end-0 top-0 bottom-0 d-none d-lg-block" style="width: 1px; background-color: #dee2e6;" {}
84 }
85
86 div class="col-lg-6 ps-lg-4" {
88 div class="d-flex flex-column align-items-center h-100" {
89 form action=(LNV2_ADD_ROUTE) method="post" class="w-100" style="max-width: 400px;" {
90 div class="mb-3" {
91 input
92 type="url"
93 class="form-control"
94 id="gateway-url"
95 name="gateway_url"
96 placeholder="Enter gateway URL"
97 required;
98 }
99 div class="text-muted mb-3 text-center" style="font-size: 0.875em;" {
100 "Please enter a valid URL starting with http:// or https://"
101 }
102 div class="text-center" {
103 button type="submit" class="btn btn-primary" style="min-width: 150px;" {
104 "Add Gateway"
105 }
106 }
107 }
108 }
109 }
110 }
111 }
112 }
113 }
114 }
115}
116
117pub async fn post_add(
119 State(state): State<UiState<DynDashboardApi>>,
120 _auth: UserAuth,
121 Form(form): Form<GatewayForm>,
122) -> impl IntoResponse {
123 state
124 .api
125 .get_module::<fedimint_lnv2_server::Lightning>()
126 .expect("Route only mounted when Lightning V2 module exists")
127 .add_gateway_ui(form.gateway_url)
128 .await;
129
130 Redirect::to(ROOT_ROUTE).into_response()
131}
132
133pub async fn post_remove(
135 State(state): State<UiState<DynDashboardApi>>,
136 _auth: UserAuth,
137 Form(form): Form<GatewayForm>,
138) -> impl IntoResponse {
139 state
140 .api
141 .get_module::<fedimint_lnv2_server::Lightning>()
142 .expect("Route only mounted when Lightning V2 module exists")
143 .remove_gateway_ui(form.gateway_url)
144 .await;
145
146 Redirect::to(ROOT_ROUTE).into_response()
147}