Refactored code and implemented new childrens loading

This commit is contained in:
Kevin Veen-Birkenbach 2025-01-15 01:35:50 +01:00
parent c01e9125aa
commit 9ff356ba70
3 changed files with 344 additions and 304 deletions

View File

@ -4,12 +4,12 @@ accounts:
description: My Online Accounts
icon:
class: fa-solid fa-users
subitems:
children:
- name: Publications
description: My Publications
icon:
class: fas fa-newspaper
subitems:
children:
- name: Microblog
description: Read my microblogs
icon:
@ -19,7 +19,7 @@ accounts:
- name: Pictures
icon:
class: fa-solid fa-images
subitems:
children:
- name: Pixelfed
description: View my photo gallery
icon:
@ -49,7 +49,7 @@ accounts:
icon:
class: fa-solid fa-laptop-code
description: Check out my Code
subitems:
children:
- name: Github
description: View my GitHub profile
icon:
@ -66,7 +66,7 @@ accounts:
icon:
class: fa-brands fa-meta
url:
subitems:
children:
- name: Facebook
description: Like my Facebook page
icon:
@ -76,7 +76,7 @@ accounts:
- name: Carreer Profiles
icon:
class: fa-solid fa-user-tie
subitems:
children:
- name: XING
description: Visit my XING profile
icon:
@ -94,7 +94,7 @@ accounts:
icon:
class: fa-solid fa-running
url:
subitems:
children:
- name: Garmin
description: My Garmin activities
icon:
@ -251,16 +251,18 @@ company:
imprint_url: https://s.veen.world/imprint
navigation:
header:
children:
- link: accounts.publications.children
- name: Contact
description: Get in touch
icon:
class: fa-solid fa-envelope
subitems:
children:
- name: Email
description: Send me an email
icon:
class: fa-solid fa-envelope
subitems:
children:
- name: Email
description: Send me an email
icon:
@ -298,7 +300,7 @@ navigation:
description: Social and developer networks
icon:
class: fa-solid fa-comments
subitems:
children:
- name: Matrix
description: Chat with me on Matrix
icon:
@ -345,20 +347,20 @@ navigation:
- link: navigation.header.contact.messenger.matrix
- link: navigation.header.contact.messenger.signal
- link: navigation.header.contact.messenger.telegram
footer:
children:
- link: accounts
- name: Solution Hub
description: Curated collection of self hosted tools
icon:
class: fa-solid fa-network-wired
url:
subitems:
children:
- name: Community
description: Tools to manage the community
icon:
class: fa-solid fa-users
subitems:
children:
- name: Forum
description: Join the discussion
icon:
@ -378,7 +380,7 @@ navigation:
description: Project Management Tools
icon:
class: fa-solid fa-chart-line
subitems:
children:
- name: Open Project
description: Explore my projects
icon:
@ -394,7 +396,7 @@ navigation:
- name: Communication
icon:
class: fa-solid fa-comments
subitems:
children:
- name: Elements
description: Chat with me
icon:
@ -415,7 +417,7 @@ navigation:
- name: Tools
icon:
class: fas fa-tools
subitems:
children:
- name: Matomo
description: Analyze with Matomo
icon:
@ -443,12 +445,12 @@ navigation:
description: All information about me
icon:
class: fa-solid fa-user
subitems:
children:
- name: Logbooks
description: Access my personal logbooks (diving, flying, sailing)
icon:
class: fa-solid fa-book
subitems:
children:
- name: Skydiver
description: View my skydiving logs
icon:
@ -483,11 +485,12 @@ navigation:
icon:
class: fa-solid fa-file-lines
url: https://s.veen.world/lebenslauf
- link: accounts
- name: Credentials
description: Access my certifications, degrees, and professional records
icon:
class: fa-solid fa-id-card
subitems:
children:
- name: Degrees
description: View my academic degrees
icon:
@ -503,10 +506,10 @@ navigation:
icon:
class: fa-solid fa-scroll
url: https://s.veen.world/certifications
- link: accounts
- name: Imprint
description: Check out the imprint information
icon:
class: fa-solid fa-scale-balanced
url: https://s.veen.world/imprint

View File

@ -1,33 +1,33 @@
<!-- Template for Subitems -->
{% macro render_subitems(subitems) %}
{% for subitem in subitems %}
{% if subitem.subitems %}
<li class="dropdown-submenu position-relative">
<a class="dropdown-item dropdown-toggle" href="#" title="{{ subitem.description }}">
{% if subitem.icon is defined and subitem.icon.class is defined %}
<i class="{{ subitem.icon.class }}"></i> {{ subitem.name }}
{% macro render_icon_and_name(item) %}
<i class="{{ item.icon.class if item.icon is defined and item.icon.class is defined else 'fa-solid fa-link' }}"></i>
{% if item.name is defined %}
{{ item.name }}
{% else %}
<p>Missing icon in subitem: {{ subitem }}</p>
Unnamed Item: {{item}}
{% endif %}
{% endmacro %}
<!-- Template for children -->
{% macro render_children(children) %}
{% for children in children %}
{% if children.children %}
<li class="dropdown-submenu position-relative">
<a class="dropdown-item dropdown-toggle" href="#" title="{{ children.description }}">
{{ render_icon_and_name(children) }}
</a>
<ul class="dropdown-menu">
{{ render_subitems(subitem.subitems) }}
{{ render_children(children.children) }}
</ul>
</li>
{% elif subitem.identifier or subitem.warning or subitem.info %}
{% elif children.identifier or children.warning or children.info %}
<li>
<a class="dropdown-item" onclick='openDynamicPopup({{ subitem|tojson|safe }})' data-bs-toggle="tooltip" title="{{ subitem.description }}">
<i class="{{ subitem.icon.class }}"></i> {{ subitem.name }}
<a class="dropdown-item" onclick='openDynamicPopup({{ children|tojson|safe }})' data-bs-toggle="tooltip" title="{{ children.description }}">
{{ render_icon_and_name(children) }}
</a>
</li>
{% else %}
<li>
<a class="dropdown-item" href="{{ subitem.url }}" target="{{ subitem.target|default('_blank') }}" data-bs-toggle="tooltip" title="{{ subitem.description }}">
{% if subitem.icon is defined and subitem.icon.class is defined %}
<i class="{{ subitem.icon.class }}"></i> {{ subitem.name }}
{% else %}
<p>Missing icon in subitem: {{ subitem }}</p>
{% endif %}
<a class="dropdown-item" href="{{ children.url }}" target="{{ children.target|default('_blank') }}" data-bs-toggle="tooltip" title="{{ children.description }}">
{{ render_icon_and_name(children) }}
</a>
</li>
{% endif %}
@ -42,12 +42,12 @@
</button>
<div class="collapse navbar-collapse" id="navbarNav{{menu_type}}">
<ul class="navbar-nav {% if menu_type == 'header' %}ms-auto{% endif %}">
{% for item in navigation[menu_type] %}
{% for item in navigation[menu_type].children %}
{% if item.url %}
<!-- Single Item -->
<li class="nav-item">
<a class="nav-link" href="{{ item.url }}" target="{{ item.target|default('_blank') }}" data-bs-toggle="tooltip" title="{{ item.description }}">
<i class="{{ item.icon.class }}"></i> {{ item.name }}
{{ render_icon_and_name(item) }}
</a>
</li>
{% else %}
@ -55,13 +55,13 @@
<li class="nav-item dropdown">
<a class="nav-link dropdown-toggle" href="#" id="navbarDropdown{{ loop.index }}" role="button" data-bs-toggle="dropdown" data-bs-display="dynamic" aria-expanded="false">
{% if item.icon is defined and item.icon.class is defined %}
<i class="{{ item.icon.class }}"></i> {{ item.name }}
{{ render_icon_and_name(item) }}
{% else %}
<p>Missing icon in item: {{ item }}</p>
{% endif %}
</a>
<ul class="dropdown-menu">
{{ render_subitems(item.subitems) }}
{{ render_children(item.children) }}
</ul>
</li>
{% endif %}

View File

@ -2,7 +2,7 @@ from pprint import pprint
class ConfigurationResolver:
"""
A class to resolve `link` entries in a nested configuration structure.
Supports navigation through dictionaries, lists, and `subitems`.
Supports navigation through dictionaries, lists, and `children`.
"""
def __init__(self, config):
@ -14,23 +14,58 @@ class ConfigurationResolver:
"""
self._recursive_resolve(self.config, self.config)
def __load_children(self,path):
"""
Check if explicitly children should be loaded and not parent
"""
return path.split('.').pop() == "children"
def _replace_in_dict_by_dict(self, dict_origine, old_key, new_dict):
if old_key in dict_origine:
# Entferne den alten Key
old_value = dict_origine.pop(old_key)
# Füge die neuen Key-Value-Paare hinzu
dict_origine.update(new_dict)
def _replace_in_list_by_list(self, list_origine, old_element, new_elements):
index = list_origine.index(old_element)
list_origine[index:index+1] = new_elements
def _replace_element_in_list(self, list_origine, old_element, new_element):
index = list_origine.index(old_element)
list_origine[index] = new_element
def _recursive_resolve(self, current_config, root_config):
"""
Recursively resolves `link` entries in the configuration.
"""
if isinstance(current_config, dict):
for key, value in list(current_config.items()):
if key == "link":
if key == "children":
for item in value:
if "link" in item:
loaded_link = self._find_entry(root_config, item['link'].lower(), False)
if isinstance(loaded_link, list):
self._replace_in_list_by_list(value,item,loaded_link)
else:
self._replace_element_in_list(value,item,loaded_link)
elif key == "link":
try:
target = self._find_entry(root_config, value.lower(), True)
if isinstance(target, list) and len(target) > 2:
target = self._find_entry(root_config, value.lower(), False)
if self.__load_children(value):
loaded = self._find_entry(root_config, value.lower(), False)
self._replace_in_dict_by_dict(
current_config,key,loaded
)
else:
loaded = self._find_entry(root_config, value.lower(), True)
if isinstance(loaded, list) and len(loaded) > 2:
loaded = self._find_entry(root_config, value.lower(), False)
current_config.clear()
current_config.update(target)
current_config.update(loaded)
except Exception as e:
raise ValueError(
f"Error resolving link '{value}': {str(e)}. "
f"Current path: {key}, Current config: {current_config}"
f"Current path: {key}, Current config: {current_config}" + (f", Loaded: {loaded}" if 'loaded' in locals() or 'loaded' in globals() else "")
)
else:
self._recursive_resolve(value, root_config)
@ -38,9 +73,9 @@ class ConfigurationResolver:
for item in current_config:
self._recursive_resolve(item, root_config)
def _get_subitems(self,current):
if isinstance(current, dict) and ("subitems" in current and current["subitems"]):
current = current["subitems"]
def _get_children(self,current):
if isinstance(current, dict) and ("children" in current and current["children"]):
current = current["children"]
return current
def _find_by_name(self,current, part):
@ -49,18 +84,21 @@ class ConfigurationResolver:
None
)
def _find_entry(self, config, path, subitems):
def _find_entry(self, config, path, children):
"""
Finds an entry in the configuration by a dot-separated path.
Supports both dictionaries and lists with `subitems` navigation.
Supports both dictionaries and lists with `children` navigation.
"""
parts = path.split('.')
current = config
for part in parts:
if isinstance(current, list):
# If children explicit declared just load children
if part != "children":
# Look for a matching name in the list
found = self._find_by_name(current,part)
if found:
current = found
print(
f"Matching entry for '{part}' in list. Path so far: {' > '.join(parts[:parts.index(part)+1])}. "
f"Current list: {current}"
@ -70,12 +108,11 @@ class ConfigurationResolver:
f"No matching entry for '{part}' in list. Path so far: {' > '.join(parts[:parts.index(part)+1])}. "
f"Current list: {current}"
)
current = found
elif isinstance(current, dict):
# Case-insensitive dictionary lookup
key = next((k for k in current if k.lower() == part), None)
if key is None:
current = self._find_by_name(current["subitems"],part)
current = self._find_by_name(current["children"],part)
if not current:
raise KeyError(
f"Key '{part}' not found in dictionary. Path so far: {' > '.join(parts[:parts.index(part)+1])}. "
@ -89,8 +126,8 @@ class ConfigurationResolver:
f"Invalid path segment '{part}'. Current type: {type(current)}. "
f"Path so far: {' > '.join(parts[:parts.index(part)+1])}"
)
if subitems:
current = self._get_subitems(current)
if children:
current = self._get_children(current)
return current