crates/monetize-ui-web/src/pages/mod.rs
//! The console's pages. The JSON shapes they read live in [`crate::model`],
//! compiled for the host as well, so every decision over them is testable
//! without a browser.
//!
//! Since 2026-10-02 the ESTATE is the top level: [`overview`] is the one page
//! that spans every estate, and everything else is one estate's, under
//! `/e/<estate>/…` with the same left menu for every estate ([`shell`]).
/// Every (product, tenant) account of ONE monetize, and one account's rows (5.4).
pub mod accounts;
pub mod guardian;
/// The invite page and the Operators panel (owner 2026-11-03): one-time per-person invites.
pub mod invite;
/// The account's iron, the operator's (MAP-SEG 1).
pub mod iron;
/// The data-set growth panel: the OUTSIDE actor's state, on the estate's Map.
pub mod ledger;
pub mod login;
/// ★ UW-3: the operator's money fixes (refund, hand-settle, an order's settle), as buttons.
pub mod money;
/// Every estate, one row each — the only page that spans them all.
pub mod overview;
/// The product lines, the spend against the ceilings, and the terms — pieces
/// of an estate's Map, Money and Offer.
pub mod products;
/// One estate's Settings: which keys, which names, which key this console signs with.
pub mod settings;
/// One estate: the left menu, and its Map, Customers, Money, Offer and Events.
pub mod shell;
/// The operator's TEST BUTTON: each product's declared test actions and their runs.
pub mod sites;
pub mod tax;
pub mod tenant;
pub mod tenants;
pub mod test_buy;
pub use crate::model::*;
/// Milliseconds since the Unix epoch, from the browser's clock.
pub fn now_ms() -> u64 {
js_sys::Date::now() as u64
}
/// `/e/<estate>/<section>` for the estate the shell is showing; `/` (the
/// Overview) when none is.
pub fn here(section: &str) -> String {
match crate::api::estate() {
Some(e) => crate::estate::estate_href(&e, section),
None => "/".to_owned(),
}
}
/// The tenant page's address — a customer of the estate being shown. The
/// tenant rides in the query because tenant names carry slashes (`team/sub`).
pub fn tenant_href(product: &str, tenant: &str) -> String {
format!(
"{}?product={}&tenant={}",
here("customer"),
crate::fmt::percent_encode(product),
crate::fmt::percent_encode(tenant)
)
}
/// One product's customers, in the estate being shown.
pub fn product_href(product: &str) -> String {
format!(
"{}?product={}",
here("customers"),
crate::fmt::percent_encode(product)
)
}
/// The estate's Money, scoped to one product and optionally one tenant.
pub fn activity_href(product: &str, tenant: Option<&str>) -> String {
match tenant {
Some(t) => format!(
"{}?product={}&tenant={}",
here("money"),
crate::fmt::percent_encode(product),
crate::fmt::percent_encode(t)
),
None => format!(
"{}?product={}",
here("money"),
crate::fmt::percent_encode(product)
),
}
}
/// ★ Owner 2026-10-12: no file names, internal terms or mechanism talk on any
/// console page. Every page's source is held to it, so a reword cannot come back.
#[cfg(test)]
mod plain_words_tests {
const PAGES: [(&str, &str); 15] = [
("accounts", include_str!("accounts.rs")),
("guardian", include_str!("guardian.rs")),
("ledger", include_str!("ledger.rs")),
("login", include_str!("login.rs")),
("money", include_str!("money.rs")),
("overview", include_str!("overview.rs")),
("products", include_str!("products.rs")),
("settings", include_str!("settings.rs")),
("shell", include_str!("shell.rs")),
("tax", include_str!("tax.rs")),
("tenant", include_str!("tenant.rs")),
("tenants", include_str!("tenants.rs")),
("sites", include_str!("sites.rs")),
("test_buy", include_str!("test_buy.rs")),
("ui", include_str!("../ui.rs")),
];
const BANNED: [&str; 10] = [
"monetize.toml",
"\"Market\"",
"every market",
"[machines.*]",
"the poller",
"webhook captures",
"priced on the difference",
"MONETIZE_UI_",
"open-source answer",
"EstateAdmin.Draw",
];
#[test]
fn no_page_shows_file_names_internal_terms_or_mechanisms() {
for (page, src) in PAGES {
// Only what is shown: lines outside comments.
for line in src.lines().filter(|l| !l.trim_start().starts_with("//")) {
for word in BANNED {
assert!(
!line.contains(word),
"page {page} shows {word:?}: {}",
line.trim()
);
}
}
}
}
}