Skip to content

Commit

Permalink
Merge pull request #2 from jlefkoff/j/add_alias_ref
Browse files Browse the repository at this point in the history
Add alias file reference
  • Loading branch information
Celeo authored Dec 18, 2024
2 parents 19cdaab + 90db8b0 commit 953deef
Show file tree
Hide file tree
Showing 5 changed files with 171 additions and 0 deletions.
1 change: 1 addition & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions vzdv-site/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ publish = false
[dependencies]
vzdv = { path = "../vzdv" }

indexmap = "2.0"
anyhow = "1.0.86"
axum = { version = "0.7.4", features = ["multipart"] }
axum-extra = "0.9.3"
Expand Down
69 changes: 69 additions & 0 deletions vzdv-site/src/endpoints/facility.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ use axum::{
Form, Router,
};
use chrono::{DateTime, Months, Utc};
use indexmap::IndexMap;
use itertools::Itertools;
use log::{error, warn};
use minijinja::context;
Expand Down Expand Up @@ -38,6 +39,8 @@ struct StaffPosition {
description: &'static str,
}

type ParsedAlias = Vec<(String, Vec<(String, Vec<String>)>)>;

fn generate_staff_outline(config: &Config) -> HashMap<&'static str, StaffPosition> {
let email_domain = &config.staff.email_domain;
HashMap::from([
Expand Down Expand Up @@ -397,6 +400,71 @@ async fn page_resources(
Ok(Html(rendered))
}

pub async fn fetch_and_parse_alias_file() -> Result<ParsedAlias, reqwest::Error> {
let url = "https://data-api.vnas.vatsim.net/Files/Aliases/ZDV.txt";
let response = reqwest::get(url).await?.text().await?;

let mut parsed_data: IndexMap<String, IndexMap<String, Vec<String>>> = IndexMap::new();
let mut current_h1 = String::new();
let mut current_h2 = String::new();

for line in response.lines() {
if line.starts_with(";;;;") {
// New Heading 1
current_h1 = line.strip_prefix(";;;;").unwrap_or(line).trim().to_string();
parsed_data.entry(current_h1.clone()).or_default();
current_h2 = String::new(); // Reset H2
} else if line.starts_with(";;;") {
// New Heading 2
current_h2 = line.strip_prefix(";;;").unwrap_or(line).trim().to_string();
parsed_data
.entry(current_h1.clone())
.or_default()
.entry(current_h2.clone())
.or_default();
} else if line.starts_with('.') {
// Command under current H1 or H2
if !current_h1.is_empty() {
if !current_h2.is_empty() {
parsed_data
.entry(current_h1.clone())
.or_default()
.entry(current_h2.clone())
.or_default()
.push(line.trim().to_string());
} else {
// Command directly under H1
parsed_data
.entry(current_h1.clone())
.or_default()
.entry("__root__".to_string())
.or_default()
.push(line.trim().to_string());
}
}
}
}

// Convert IndexMap to Vec for Jinja compatibility
let parsed_vec: ParsedAlias = parsed_data
.into_iter()
.map(|(h1, h2_map)| {
let h2_vec = h2_map.into_iter().collect();
(h1, h2_vec)
})
.collect();

Ok(parsed_vec)
}

/// View Alias commands for the facility. (Polled from the vNAS API)
async fn alias_ref(State(state): State<Arc<AppState>>) -> Result<Html<String>, AppError> {
let template = state.templates.get_template("facility/aliasref.jinja")?;
let alias_ref = fetch_and_parse_alias_file().await?;
let rendered = template.render(context! { alias_ref })?;
Ok(Html(rendered))
}

/// Check visitor requirements and submit an application.
async fn page_visitor_application(
State(state): State<Arc<AppState>>,
Expand Down Expand Up @@ -583,6 +651,7 @@ pub fn router() -> Router<Arc<AppState>> {
.route("/facility/staff", get(page_staff))
.route("/facility/activity", get(page_activity))
.route("/facility/resources", get(page_resources))
.route("/facility/aliasref", get(alias_ref))
.route(
"/facility/visitor_application",
get(page_visitor_application),
Expand Down
1 change: 1 addition & 0 deletions vzdv-site/templates/_layout.jinja
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,7 @@
<li><a class="dropdown-item" href="/facility/roster">Roster</a></li>
<li><a class="dropdown-item" href="/facility/activity">Activity</a></li>
<li><a class="dropdown-item" href="/facility/resources">Resources</a></li>
<li><a class="dropdown-item" href="/facility/aliasref">Alias Reference</a></li>
<li><a class="dropdown-item" href="/facility/visitor_application">Visitor Application</a></li>
</ul>
</li>
Expand Down
99 changes: 99 additions & 0 deletions vzdv-site/templates/facility/aliasref.jinja
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
{% extends "_layout.jinja" %}

{% block title %}Alias Reference | {{ super() }}{% endblock %}

{% block body %}

<h2>Alias Reference</h2>
<input type="text" id="searchBar" placeholder="Search commands or contents..." class="form-control mb-3">

<div class="list-group" id="aliasContainer">
{% for h1, h2_list in alias_ref %}
<!-- Top-Level Heading -->
<a href="#heading-{{ loop.index }}" class="list-group-item list-group-item-action" data-bs-toggle="collapse">
<strong>{{ h1 }}</strong>
</a>
<div class="collapse list-group" id="heading-{{ loop.index }}">
{% set parent_index = loop.index %}
{% for h2, commands in h2_list %}
{% if h2 == "__root__" %}
<!-- Commands directly under H1 -->
{% for command in commands %}
<div class="list-group-item" style="padding-left: 30px;">
{{ command }}
</div>
{% endfor %}
{% else %}
<!-- Subheading -->
<a href="#subheading-{{ parent_index }}-{{ loop.index }}"
class="list-group-item list-group-item-action"
data-bs-toggle="collapse"
style="padding-left: 30px;">
{{ h2 }}
</a>
<div class="collapse list-group" id="subheading-{{ parent_index }}-{{ loop.index }}">
{% for command in commands %}
<!-- Commands under H2 -->
<div class="list-group-item" style="padding-left: 45px;">
{{ command }}
</div>
{% endfor %}
</div>
{% endif %}
{% endfor %}
</div>
{% endfor %}
</div>

<script>
const searchBar = document.getElementById('searchBar');
const aliasContainer = document.getElementById('aliasContainer');
searchBar.addEventListener('input', function () {
const query = searchBar.value.toLowerCase();
const allItems = aliasContainer.querySelectorAll('.list-group-item'); // All items
const allCollapsibles = aliasContainer.querySelectorAll('.collapse'); // All collapsible sections
// Collapse all sections initially
allCollapsibles.forEach(collapse => collapse.classList.remove('show'));
let hasMatch = false;
allItems.forEach(item => {
const text = item.textContent.toLowerCase();
if (text.includes(query)) {
// Show matching items
item.style.display = '';
hasMatch = true;
// Expand parent collapsible sections
let parentCollapse = item.closest('.collapse');
while (parentCollapse) {
parentCollapse.classList.add('show'); // Expand the collapsible
parentCollapse = parentCollapse.parentElement.closest('.collapse');
}
// Show parent H2 or H1 explicitly
let currentElement = item;
while (currentElement) {
const siblingHeading = currentElement.previousElementSibling;
if (siblingHeading && siblingHeading.classList.contains('list-group-item')) {
siblingHeading.style.display = ''; // Show the immediate heading (H2 or H1)
}
currentElement = currentElement.closest('.collapse')?.previousElementSibling;
}
} else {
// Hide non-matching items
item.style.display = 'none';
}
});
// If no matches are found, collapse all sections
if (!hasMatch) {
allCollapsibles.forEach(collapse => collapse.classList.remove('show'));
}
});
</script>
{% endblock %}

0 comments on commit 953deef

Please sign in to comment.