Skip to content

Commit

Permalink
Tracing history + Live tracing
Browse files Browse the repository at this point in the history
  • Loading branch information
mdecimus committed Aug 20, 2024
1 parent aba99dd commit 7f5244e
Show file tree
Hide file tree
Showing 20 changed files with 1,704 additions and 170 deletions.
249 changes: 142 additions & 107 deletions Cargo.lock

Large diffs are not rendered by default.

3 changes: 2 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,8 @@ console_error_panic_hook = "0.1.7"
leptos = { version = "0.6.9", features = ["csr"] }
leptos_meta = { version = "0.6.9", features = ["csr"] }
leptos_router = { version = "0.6.9", features = ["csr"] }
leptos-use = "0.11"
leptos-use = "0.12"
codee = { version = "0.1.2", features = ["json_serde"] }
gloo-net = { version = "0.6", features = ["http"] }
gloo-storage = "0.3.0"
serde = { version = "1", features = ["derive", "rc"] }
Expand Down
16 changes: 16 additions & 0 deletions src/components/icon.rs
Original file line number Diff line number Diff line change
Expand Up @@ -607,3 +607,19 @@ pub fn IconThreeDots(
</SvgWrapper>
}
}

#[component]
pub fn IconChatBubbleBottom(
#[prop(optional)] size: Option<usize>,
#[prop(attrs)] attrs: Vec<(&'static str, Attribute)>,
) -> impl IntoView {
view! {
<SvgWrapper size attrs>
<path
stroke-linecap="round"
stroke-linejoin="round"
d="M7.5 8.25h9m-9 3H12m-9.75 1.51c0 1.6 1.123 2.994 2.707 3.227 1.129.166 2.27.293 3.423.379.35.026.67.21.865.501L12 21l2.755-4.133a1.14 1.14 0 0 1 .865-.501 48.172 48.172 0 0 0 3.423-.379c1.584-.233 2.707-1.626 2.707-3.228V6.741c0-1.602-1.123-2.995-2.707-3.228A48.394 48.394 0 0 0 12 3c-2.392 0-4.744.175-7.043.513C3.373 3.746 2.25 5.14 2.25 6.741v6.018Z"
></path>
</SvgWrapper>
}
}
58 changes: 44 additions & 14 deletions src/components/messages/alert.rs
Original file line number Diff line number Diff line change
Expand Up @@ -204,8 +204,7 @@ impl Alert {
self
}

pub fn with_details(mut self, details: impl Into<String>) -> Self {
let details = details.into();
pub fn with_details(mut self, details: impl IntoView) -> Self {
self.details = Some(details.into_view());
self
}
Expand Down Expand Up @@ -252,31 +251,62 @@ impl From<http::Error> for Alert {
Alert::error("Failed to deserialize response").with_details(error)
}
http::Error::Server(error) => {
let (title, details) = match error {
let (alert, title, details) = match error {
ManagementApiError::FieldAlreadyExists { field, value } => (
AlertType::Error,
"Field already exists".to_string(),
format!("Another record exists with value {value:?} in field {field:?}."),
format!("Another record exists with value {value:?} in field {field:?}.")
.into_view(),
),
ManagementApiError::FieldMissing { field } => (
AlertType::Error,
"Missing required field".to_string(),
format!("Field {} is missing", field),
format!("Field {} is missing", field).into_view(),
),
ManagementApiError::NotFound { item } => (
AlertType::Error,
"Not found".to_string(),
format!("{item} was not found").into_view(),
),
ManagementApiError::NotFound { item } => {
("Not found".to_string(), format!("{item} was not found"))
}
ManagementApiError::Unsupported { details } => {
("Operation not allowed".to_string(), details)
if !details.starts_with("Enterprise") {
(
AlertType::Error,
"Operation not allowed".to_string(),
details.into_view(),
)
} else {
(
AlertType::Warning,
"Enterprise feature".to_string(),
view! {
<div>
{"This feature is only available in the enterprise version of the software. "}
<a
href="https://stalw.art/contact/"
class="text-yellow-800 underline decoration-yellow-800 hover:opacity-80 focus:outline-none focus:opacity-80"
target="_blank"
>
Request trial.
</a>
</div>
}.into_view(),
)
}
}
ManagementApiError::AssertFailed => (
AlertType::Error,
"Record already exists".to_string(),
"Another record with the same ID already exists".to_string(),
"Another record with the same ID already exists".into_view(),
),
ManagementApiError::Other { details } => (
AlertType::Error,
"Operation failed".to_string(),
details.into_view(),
),
ManagementApiError::Other { details } => {
("Operation failed".to_string(), details)
}
};

Alert::error(title).with_details(details)
Alert::new(alert, title).with_details(details)
}
http::Error::NotFound => Alert::error("Not found"),
http::Error::Forbidden => Alert::error("Forbidden"),
Expand Down
8 changes: 6 additions & 2 deletions src/core/url.rs
Original file line number Diff line number Diff line change
Expand Up @@ -35,14 +35,18 @@ impl UrlBuilder {
self
}

pub fn with_parameter(mut self, key: &'static str, value: impl Into<String>) -> Self {
pub fn with_parameter(
mut self,
key: impl Into<Cow<'static, str>>,
value: impl Into<String>,
) -> Self {
self.params.insert(key.into(), value.into());
self
}

pub fn with_optional_parameter(
mut self,
key: &'static str,
key: impl Into<Cow<'static, str>>,
value: Option<impl Into<String>>,
) -> Self {
if let Some(value) = value {
Expand Down
56 changes: 46 additions & 10 deletions src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,12 @@ use std::{sync::Arc, time::Duration};

use components::{
icon::{
IconAdjustmentsHorizontal, IconDocumentChartBar, IconDocumentText, IconKey, IconLockClosed,
IconQueueList, IconShieldCheck, IconSquare2x2, IconUserGroup, IconWrench,
IconAdjustmentsHorizontal, IconClock, IconDocumentChartBar, IconDocumentText, IconKey,
IconLockClosed, IconQueueList, IconShieldCheck, IconSquare2x2, IconUserGroup, IconWrench,
},
layout::MenuItem,
};

use gloo_storage::{SessionStorage, Storage};
use leptos::*;
use leptos_meta::*;
Expand All @@ -25,7 +26,10 @@ use pages::{
mfa::ManageMfa,
},
config::edit::DEFAULT_SETTINGS_URL,
enterprise::undelete::UndeleteList,
enterprise::{
tracing::{display::SpanDisplay, list::SpanList, live::LiveTracing},
undelete::UndeleteList,
},
manage::spam::{SpamTest, SpamTrain},
};

Expand Down Expand Up @@ -138,7 +142,6 @@ pub fn App() -> impl IntoView {

let is_logged_in = create_memo(move |_| auth_token.get().is_logged_in());
let is_admin = create_memo(move |_| auth_token.get().is_admin());
let is_enterprise = create_memo(move |_| auth_token.get().is_enterprise());

view! {
<Router>
Expand Down Expand Up @@ -247,7 +250,25 @@ pub fn App() -> impl IntoView {
path="/undelete/:id"
view=UndeleteList
redirect_path="/login"
condition=move || is_admin.get() && is_enterprise.get()
condition=move || is_admin.get()
/>
<ProtectedRoute
path="/tracing/span/:id"
view=SpanDisplay
redirect_path="/login"
condition=move || is_admin.get()
/>
<ProtectedRoute
path="/tracing/live"
view=LiveTracing
redirect_path="/login"
condition=move || is_admin.get()
/>
<ProtectedRoute
path="/tracing/:object"
view=SpanList
redirect_path="/login"
condition=move || is_admin.get()
/>
</ProtectedRoute>
<ProtectedRoute
Expand Down Expand Up @@ -369,7 +390,25 @@ impl LayoutBuilder {
.route("/reports/arf")
.insert()
.insert()
.create("SPAM Filter")
.create("History")
.icon(view! { <IconClock/> })
.create("Received Messages")
.route("/tracing/received")
.insert()
.create("Delivery Attempts")
.route("/tracing/delivery")
.insert()
.insert()
.create("Tracing")
.icon(view! { <IconDocumentText/> })
.create("Logs")
.route("/logs")
.insert()
.create("Live tracing")
.route("/tracing/live")
.insert()
.insert()
.create("Antispam")
.icon(view! { <IconShieldCheck/> })
.create("Train")
.route("/spam/train")
Expand All @@ -378,10 +417,6 @@ impl LayoutBuilder {
.route("/spam/test")
.insert()
.insert()
.create("Logs")
.icon(view! { <IconDocumentText/> })
.route("/logs")
.insert()
.create("Settings")
.icon(view! { <IconAdjustmentsHorizontal/> })
.raw_route(DEFAULT_SETTINGS_URL)
Expand Down Expand Up @@ -441,6 +476,7 @@ pub fn build_schemas() -> Arc<Schemas> {
.build_authorize()
.build_mfa()
.build_app_passwords()
.build_live_tracing()
.build()
.into()
}
1 change: 1 addition & 0 deletions src/pages/config/edit.rs
Original file line number Diff line number Diff line change
Expand Up @@ -453,6 +453,7 @@ pub fn SettingsEdit() -> impl IntoView {
label=field_label
tooltip=help.unwrap_or_default()
element=FormElement::new(field.id, data)
disabled=is_disabled
/>
}
.into_view()
Expand Down
3 changes: 3 additions & 0 deletions src/pages/config/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -341,6 +341,9 @@ impl LayoutBuilder {
.create("Stores")
.route("/store")
.insert()
.create("History")
.route("/history/edit")
.insert()
.insert()
// Authentication
.create("Authentication")
Expand Down
4 changes: 2 additions & 2 deletions src/pages/config/schema/storage.rs
Original file line number Diff line number Diff line change
Expand Up @@ -164,7 +164,7 @@ impl Builder<Schemas, ()> {
.default("30d")
.typ(Type::Duration)
.build()
.new_field("storage.undelete.hold-for")
.new_field("storage.undelete.retention")
.label("Un-delete period ⭐")
.help(concat!(
"How long to keep deleted emails before they are permanently ",
Expand All @@ -184,7 +184,7 @@ impl Builder<Schemas, ()> {
.build()
.new_form_section()
.title("Blob Store")
.fields(["storage.blob", "storage.undelete.hold-for"])
.fields(["storage.blob", "storage.undelete.retention"])
.build()
.new_form_section()
.title("Full Text Index Store")
Expand Down
Loading

0 comments on commit 7f5244e

Please sign in to comment.