- Rename app title to SUB-ALIGATOR (header, page titles, exports, README) - Add dark amber-terminal theme with a header toggle, persisted in localStorage - Add pool deletion (soft delete): allocations are kept in history and block the address space again when the same or an overlapping pool is re-added (re-enable on exact CIDR match, re-attach contained allocations) - Reject new pools that overlap an enabled pool - Move Home link into the page header, keep other links in the footer - Load app.js globally via base template, add theme.js (CSP-safe, no inline JS)
168 lines
4.2 KiB
Rust
168 lines
4.2 KiB
Rust
use crate::models::{AllocationDetail, AllocationListItem, AuditEventDisplay, Pool};
|
|
use askama::Template;
|
|
|
|
#[derive(Template)]
|
|
#[template(path = "base.html")]
|
|
pub struct BaseTemplate {
|
|
pub title: String,
|
|
}
|
|
|
|
#[derive(Template)]
|
|
#[template(path = "index.html")]
|
|
pub struct IndexTemplate {
|
|
pub pools: Vec<PoolTemplate>,
|
|
pub all_pools: Vec<Pool>,
|
|
pub allocations: Vec<AllocationListItem>,
|
|
pub page: i64,
|
|
pub total_pages: i64,
|
|
pub total_count: i64,
|
|
pub query: String,
|
|
pub pool_filter: String,
|
|
pub status_filter: String,
|
|
pub csrf_token: String,
|
|
pub flash: FlashData,
|
|
}
|
|
|
|
#[derive(Clone, Debug)]
|
|
pub struct PoolTemplate {
|
|
pub id: i64,
|
|
pub slug: String,
|
|
pub name: String,
|
|
pub cidr: String,
|
|
pub kind: String,
|
|
pub allowed_prefixes: Vec<String>,
|
|
pub allowed_prefixes_json: String,
|
|
}
|
|
|
|
impl From<Pool> for PoolTemplate {
|
|
fn from(p: Pool) -> Self {
|
|
let allowed: Vec<i32> = p.allowed_prefixes();
|
|
Self {
|
|
id: p.id,
|
|
slug: p.slug.clone(),
|
|
name: p.name,
|
|
cidr: p.cidr,
|
|
kind: p.kind,
|
|
allowed_prefixes_json: serde_json::to_string(&allowed).unwrap_or_default(),
|
|
allowed_prefixes: allowed.into_iter().map(|x| x.to_string()).collect(),
|
|
}
|
|
}
|
|
}
|
|
|
|
#[derive(Clone, Debug)]
|
|
pub struct SuccessMessage {
|
|
pub cidr: String,
|
|
pub note: String,
|
|
pub network: String,
|
|
pub broadcast: String,
|
|
pub first_host: String,
|
|
pub last_host: String,
|
|
pub usable_host_count: i32,
|
|
}
|
|
|
|
#[derive(Clone, Debug, Default)]
|
|
pub struct FlashData {
|
|
pub has_success: bool,
|
|
pub success_cidr: String,
|
|
pub success_note: String,
|
|
pub success_network: String,
|
|
pub success_broadcast: String,
|
|
pub success_first_host: String,
|
|
pub success_last_host: String,
|
|
pub success_usable_host_count: i32,
|
|
pub has_error: bool,
|
|
pub error: String,
|
|
}
|
|
|
|
impl From<Option<SuccessMessage>> for FlashData {
|
|
fn from(success: Option<SuccessMessage>) -> Self {
|
|
match success {
|
|
Some(s) => FlashData {
|
|
has_success: true,
|
|
success_cidr: s.cidr,
|
|
success_note: s.note,
|
|
success_network: s.network,
|
|
success_broadcast: s.broadcast,
|
|
success_first_host: s.first_host,
|
|
success_last_host: s.last_host,
|
|
success_usable_host_count: s.usable_host_count,
|
|
has_error: false,
|
|
error: String::new(),
|
|
},
|
|
None => FlashData::default(),
|
|
}
|
|
}
|
|
}
|
|
|
|
impl FlashData {
|
|
pub fn error(message: impl Into<String>) -> Self {
|
|
FlashData {
|
|
has_error: true,
|
|
error: message.into(),
|
|
..Default::default()
|
|
}
|
|
}
|
|
}
|
|
|
|
#[derive(Template)]
|
|
#[template(path = "partials/pool_preview.html")]
|
|
pub struct PoolPreviewTemplate {
|
|
pub cidr: String,
|
|
pub prefix_length: i32,
|
|
pub address_count: i32,
|
|
pub usable_host_count: i32,
|
|
pub has_error: bool,
|
|
pub error: String,
|
|
}
|
|
|
|
#[derive(Template)]
|
|
#[template(path = "fragments/flash.html")]
|
|
pub struct FlashTemplate {
|
|
pub flash: FlashData,
|
|
}
|
|
|
|
#[derive(Template)]
|
|
#[template(path = "fragments/allocations_table.html")]
|
|
pub struct AllocationsTableTemplate {
|
|
pub allocations: Vec<AllocationListItem>,
|
|
pub page: i64,
|
|
pub total_pages: i64,
|
|
pub total_count: i64,
|
|
pub query: String,
|
|
pub pool_filter: String,
|
|
pub status_filter: String,
|
|
pub csrf_token: String,
|
|
}
|
|
|
|
#[derive(Template)]
|
|
#[template(path = "allocation_detail.html")]
|
|
pub struct AllocationDetailTemplate {
|
|
pub allocation: AllocationDetail,
|
|
pub audit_events: Vec<AuditEventDisplay>,
|
|
pub csrf_token: String,
|
|
pub flash: FlashData,
|
|
}
|
|
|
|
#[derive(Template)]
|
|
#[template(path = "setup.html")]
|
|
pub struct SetupTemplate {
|
|
pub csrf_token: String,
|
|
pub error: String,
|
|
}
|
|
|
|
#[derive(Clone, Debug)]
|
|
pub struct PoolRow {
|
|
pub pool: Pool,
|
|
pub active_count: i64,
|
|
pub reserved_count: i64,
|
|
pub released_count: i64,
|
|
pub total_count: i64,
|
|
}
|
|
|
|
#[derive(Template)]
|
|
#[template(path = "pools.html")]
|
|
pub struct PoolListTemplate {
|
|
pub pools: Vec<PoolRow>,
|
|
pub csrf_token: String,
|
|
pub error: String,
|
|
}
|