unifi-network-maps 1.4.4__py3-none-any.whl → 1.4.6__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (34) hide show
  1. unifi_network_maps/__init__.py +1 -1
  2. unifi_network_maps/cli/__init__.py +2 -38
  3. unifi_network_maps/cli/args.py +166 -0
  4. unifi_network_maps/cli/main.py +23 -753
  5. unifi_network_maps/cli/render.py +255 -0
  6. unifi_network_maps/cli/runtime.py +157 -0
  7. unifi_network_maps/io/mkdocs_assets.py +21 -0
  8. unifi_network_maps/io/mock_generate.py +2 -294
  9. unifi_network_maps/model/mock.py +307 -0
  10. unifi_network_maps/render/device_ports_md.py +44 -27
  11. unifi_network_maps/render/legend.py +30 -0
  12. unifi_network_maps/render/lldp_md.py +81 -60
  13. unifi_network_maps/render/markdown_tables.py +21 -0
  14. unifi_network_maps/render/mermaid.py +72 -85
  15. unifi_network_maps/render/mkdocs.py +167 -0
  16. unifi_network_maps/render/svg.py +34 -3
  17. unifi_network_maps/render/templates/device_port_block.md.j2 +5 -0
  18. unifi_network_maps/render/templates/legend_compact.html.j2 +14 -0
  19. unifi_network_maps/render/templates/lldp_device_section.md.j2 +15 -0
  20. unifi_network_maps/render/templates/markdown_section.md.j2 +3 -0
  21. unifi_network_maps/render/templates/mermaid_legend.mmd.j2 +30 -0
  22. unifi_network_maps/render/templates/mkdocs_document.md.j2 +23 -0
  23. unifi_network_maps/render/templates/mkdocs_dual_theme_style.html.j2 +8 -0
  24. unifi_network_maps/render/templates/mkdocs_html_block.html.j2 +2 -0
  25. unifi_network_maps/render/templates/mkdocs_legend.css.j2 +29 -0
  26. unifi_network_maps/render/templates/mkdocs_legend.js.j2 +18 -0
  27. unifi_network_maps/render/templates/mkdocs_mermaid_block.md.j2 +4 -0
  28. unifi_network_maps/render/templating.py +19 -0
  29. {unifi_network_maps-1.4.4.dist-info → unifi_network_maps-1.4.6.dist-info}/METADATA +7 -1
  30. {unifi_network_maps-1.4.4.dist-info → unifi_network_maps-1.4.6.dist-info}/RECORD +34 -14
  31. {unifi_network_maps-1.4.4.dist-info → unifi_network_maps-1.4.6.dist-info}/WHEEL +0 -0
  32. {unifi_network_maps-1.4.4.dist-info → unifi_network_maps-1.4.6.dist-info}/entry_points.txt +0 -0
  33. {unifi_network_maps-1.4.4.dist-info → unifi_network_maps-1.4.6.dist-info}/licenses/LICENSE +0 -0
  34. {unifi_network_maps-1.4.4.dist-info → unifi_network_maps-1.4.6.dist-info}/top_level.txt +0 -0
@@ -6,6 +6,7 @@ import base64
6
6
  import math
7
7
  from collections.abc import Callable
8
8
  from dataclasses import dataclass
9
+ from html import escape as _escape_attr
9
10
  from pathlib import Path
10
11
 
11
12
  from ..model.topology import Edge
@@ -472,6 +473,7 @@ def render_svg(
472
473
  edges: list[Edge],
473
474
  *,
474
475
  node_types: dict[str, str],
476
+ node_data: dict[str, dict[str, str]] | None = None,
475
477
  options: SvgOptions | None = None,
476
478
  theme: SvgTheme = DEFAULT_THEME,
477
479
  ) -> str:
@@ -503,6 +505,7 @@ def render_svg(
503
505
  node_port_prefix,
504
506
  icons,
505
507
  options,
508
+ node_data,
506
509
  )
507
510
 
508
511
  lines.append("</svg>")
@@ -519,6 +522,8 @@ def _render_svg_edges(
519
522
  node_port_labels: dict[str, str] = {}
520
523
  node_port_prefix: dict[str, str] = {}
521
524
  for edge in edges:
525
+ _record_edge_labels(edge, node_types, node_port_labels, node_port_prefix)
526
+ for edge in sorted(edges, key=lambda item: item.poe):
522
527
  if edge.left not in positions or edge.right not in positions:
523
528
  continue
524
529
  src_x, src_y = positions[edge.left]
@@ -530,7 +535,17 @@ def _render_svg_edges(
530
535
  mid_y = (src_bottom + dst_top) / 2
531
536
  color = "url(#link-poe)" if edge.poe else "url(#link-standard)"
532
537
  width_px = 2 if edge.poe else 1
533
- path = f"M {src_cx} {src_bottom} L {src_cx} {mid_y} L {dst_cx} {mid_y} L {dst_cx} {dst_top}"
538
+ if math.isclose(src_cx, dst_cx, abs_tol=0.01):
539
+ elbow_x = src_cx + 0.5
540
+ path = (
541
+ f"M {src_cx} {src_bottom} L {src_cx} {mid_y} "
542
+ f"L {elbow_x} {mid_y} L {dst_cx} {mid_y} L {dst_cx} {dst_top}"
543
+ )
544
+ else:
545
+ path = (
546
+ f"M {src_cx} {src_bottom} L {src_cx} {mid_y} "
547
+ f"L {dst_cx} {mid_y} L {dst_cx} {dst_top}"
548
+ )
534
549
  dash = ' stroke-dasharray="6 4"' if edge.wireless else ""
535
550
  lines.append(
536
551
  f'<path d="{path}" stroke="{color}" stroke-width="{width_px}" fill="none"{dash}/>'
@@ -542,7 +557,6 @@ def _render_svg_edges(
542
557
  f'<text x="{icon_x}" y="{icon_y}" text-anchor="middle" fill="#1e88e5" '
543
558
  f'font-size="{max(options.font_size, 10)}">⚡</text>'
544
559
  )
545
- _record_edge_labels(edge, node_types, node_port_labels, node_port_prefix)
546
560
  return node_port_labels, node_port_prefix
547
561
 
548
562
 
@@ -589,11 +603,15 @@ def _render_svg_nodes(
589
603
  node_port_prefix: dict[str, str],
590
604
  icons: dict[str, str],
591
605
  options: SvgOptions,
606
+ node_data: dict[str, dict[str, str]] | None,
592
607
  ) -> None:
593
608
  for name, (x, y) in positions.items():
594
609
  node_type = node_types.get(name, "other")
595
610
  fill, stroke = _TYPE_COLORS.get(node_type, _TYPE_COLORS["other"])
596
611
  fill = f"url(#node-{node_type})"
612
+ extra_attrs = _svg_node_attrs(node_data, name)
613
+ if extra_attrs:
614
+ lines.append(f"<g{extra_attrs}>")
597
615
  lines.append(
598
616
  f'<rect x="{x}" y="{y}" width="{options.node_width}" height="{options.node_height}" '
599
617
  f'rx="6" ry="6" fill="{fill}" stroke="{stroke}" stroke-width="1"/>'
@@ -631,6 +649,18 @@ def _render_svg_nodes(
631
649
  lines.append(
632
650
  f'<text x="{text_x}" y="{text_y}" fill="#1f1f1f" text-anchor="start">{safe_name}</text>'
633
651
  )
652
+ if extra_attrs:
653
+ lines.append("</g>")
654
+
655
+
656
+ def _svg_node_attrs(node_data: dict[str, dict[str, str]] | None, name: str) -> str:
657
+ if not node_data:
658
+ return ""
659
+ attrs = node_data.get(name)
660
+ if not attrs:
661
+ return ""
662
+ rendered = [f' {key}="{_escape_attr(value, quote=True)}"' for key, value in attrs.items()]
663
+ return "".join(rendered)
634
664
 
635
665
 
636
666
  def _iso_project(layout: IsoLayout, gx: float, gy: float) -> tuple[float, float]:
@@ -759,6 +789,8 @@ def _render_iso_edges(
759
789
  node_port_prefix: dict[str, str],
760
790
  ) -> None:
761
791
  for edge in edges:
792
+ _record_iso_edge_label(edge, node_types, node_port_labels, node_port_prefix)
793
+ for edge in sorted(edges, key=lambda item: item.poe):
762
794
  if edge.left not in positions or edge.right not in positions:
763
795
  continue
764
796
  src_grid = grid_positions.get(edge.left)
@@ -800,7 +832,6 @@ def _render_iso_edges(
800
832
  f'<text x="{icon_x}" y="{icon_y}" text-anchor="middle" fill="#1e88e5" '
801
833
  f'font-size="{max(options.font_size, 10)}">⚡</text>'
802
834
  )
803
- _record_iso_edge_label(edge, node_types, node_port_labels, node_port_prefix)
804
835
 
805
836
 
806
837
  def _iso_edge_path(
@@ -0,0 +1,5 @@
1
+ ### {{ device_name }}
2
+
3
+ {{ details }}
4
+
5
+ {{ ports }}
@@ -0,0 +1,14 @@
1
+ <table class="unifi-legend-table">
2
+ <tbody>
3
+ {% for row in rows %}
4
+ <tr><td>
5
+ {% if row.kind == "swatch" %}
6
+ <span style="display:inline-block;width:12px;height:12px;background:{{ row.fill }};border:1px solid {{ row.stroke }};border-radius:2px;margin-right:6px;"></span>{{ row.label }}
7
+ {% else %}
8
+ <span style="display:inline-flex;align-items:center;gap:6px;">
9
+ <svg width="42" height="10" viewBox="0 0 42 10" xmlns="http://www.w3.org/2000/svg" aria-hidden="true"><line x1="2" y1="5" x2="40" y2="5" stroke="{{ row.color }}" stroke-width="{{ row.width }}"{% if row.dashed %} stroke-dasharray="5 4"{% endif %} /></svg>{{ row.label }}{%- if row.bolt %} ⚡{%- endif %}</span>
10
+ {% endif %}
11
+ </td></tr>
12
+ {% endfor %}
13
+ </tbody>
14
+ </table>
@@ -0,0 +1,15 @@
1
+ ## {{ device_name }}
2
+
3
+ {{ details }}
4
+ {% if ports_section %}
5
+
6
+ {{ ports_section }}
7
+ {% endif %}
8
+ {% if lldp_section %}
9
+
10
+ {{ lldp_section }}
11
+ {% endif %}
12
+ {% if clients_section %}
13
+
14
+ {{ clients_section }}
15
+ {% endif %}
@@ -0,0 +1,3 @@
1
+ ## {{ title }}
2
+
3
+ {{ body }}
@@ -0,0 +1,30 @@
1
+ %%{init: {"flowchart": {"nodeSpacing": {{ node_spacing }}, "rankSpacing": {{ rank_spacing }}}, "themeVariables": {"fontSize": "{{ legend_font_size }}px", "nodePadding": {{ node_padding }}}}}%%
2
+ graph TB
3
+ subgraph legend["Legend"];
4
+ legend_gateway["Gateway"];
5
+ legend_switch["Switch"];
6
+ legend_ap["AP"];
7
+ legend_client["Client"];
8
+ legend_other["Other"];
9
+ legend_poe_a["PoE Link A"];
10
+ legend_poe_b["PoE Link B"];
11
+ legend_no_poe_a["Link A"];
12
+ legend_no_poe_b["Link B"];
13
+ legend_poe_a ---|⚡| legend_poe_b;
14
+ legend_no_poe_a --- legend_no_poe_b;
15
+ linkStyle 0 arrowhead:none;
16
+ linkStyle 1 arrowhead:none;
17
+ end
18
+ class legend_gateway node_gateway;
19
+ class legend_switch node_switch;
20
+ class legend_ap node_ap;
21
+ class legend_client node_client;
22
+ class legend_other node_other;
23
+ class legend_poe_a node_legend;
24
+ class legend_poe_b node_legend;
25
+ class legend_no_poe_a node_legend;
26
+ class legend_no_poe_b node_legend;
27
+ {{ class_defs }}
28
+ classDef node_legend font-size:{{ legend_font_size }}px;
29
+ linkStyle 0 stroke:{{ poe_link }},stroke-width:{{ poe_link_width }}px,arrowhead:{{ poe_link_arrow }};
30
+ linkStyle 1 stroke:{{ standard_link }},stroke-width:{{ standard_link_width }}px,arrowhead:{{ standard_link_arrow }};
@@ -0,0 +1,23 @@
1
+ # {{ title }}
2
+
3
+ {% if timestamp_line -%}
4
+ {{ timestamp_line }}
5
+
6
+ {% endif -%}
7
+ {% if dual_style -%}
8
+ {{ dual_style }}{% endif -%}
9
+ {% set title = "Map" %}
10
+ {% set body = map_block %}
11
+ {% include "markdown_section.md.j2" %}
12
+
13
+ {% if legend_title -%}
14
+ {% set title = legend_title %}
15
+ {% set body = legend_block %}
16
+ {% include "markdown_section.md.j2" %}
17
+
18
+ {% else -%}
19
+ {{ legend_block }}
20
+
21
+ {% endif -%}
22
+
23
+ {{ device_overview }}
@@ -0,0 +1,8 @@
1
+ <style>
2
+ .unifi-mermaid--light,.unifi-legend--light{display:none;}
3
+ .unifi-mermaid--dark,.unifi-legend--dark{display:none;}
4
+ [data-md-color-scheme="default"] .unifi-mermaid--light{display:block;}
5
+ [data-md-color-scheme="default"] .unifi-legend--light{display:block;}
6
+ [data-md-color-scheme="slate"] .unifi-mermaid--dark{display:block;}
7
+ [data-md-color-scheme="slate"] .unifi-legend--dark{display:block;}
8
+ </style>
@@ -0,0 +1,2 @@
1
+ <div class="{{ class_name }}"{% if data_unifi_legend %} data-unifi-legend{% endif %}>
2
+ {{ content | safe }}</div>
@@ -0,0 +1,29 @@
1
+ .unifi-legend-hidden,
2
+ .unifi-legend-hidden.unifi-legend,
3
+ .unifi-legend-hidden.unifi-legend--light,
4
+ .unifi-legend-hidden.unifi-legend--dark {
5
+ display: none !important;
6
+ }
7
+ .unifi-legend-sidebar {
8
+ margin-top: 1rem;
9
+ padding: 0.5rem 0.75rem;
10
+ border: 1px solid rgba(0, 0, 0, 0.08);
11
+ border-radius: 6px;
12
+ font-size: 0.75rem;
13
+ }
14
+ .unifi-legend-title {
15
+ font-weight: 600;
16
+ margin-bottom: 0.5rem;
17
+ }
18
+ .unifi-legend-sidebar table {
19
+ width: 100%;
20
+ border-collapse: collapse;
21
+ }
22
+ .unifi-legend-sidebar td,
23
+ .unifi-legend-sidebar th {
24
+ border: 0;
25
+ padding: 0.15rem 0;
26
+ }
27
+ .unifi-legend-sidebar svg {
28
+ display: block;
29
+ }
@@ -0,0 +1,18 @@
1
+ document.addEventListener("DOMContentLoaded", () => {
2
+ const legends = document.querySelectorAll("[data-unifi-legend]");
3
+ const sidebar = document.querySelector(".md-sidebar--secondary .md-sidebar__scrollwrap");
4
+ if (!legends.length || !sidebar) {
5
+ return;
6
+ }
7
+ const wrapper = document.createElement("div");
8
+ wrapper.className = "unifi-legend-sidebar";
9
+ const title = document.createElement("div");
10
+ title.className = "unifi-legend-title";
11
+ title.textContent = "Legend";
12
+ wrapper.appendChild(title);
13
+ legends.forEach((legend) => {
14
+ wrapper.appendChild(legend.cloneNode(true));
15
+ legend.classList.add("unifi-legend-hidden");
16
+ });
17
+ sidebar.appendChild(wrapper);
18
+ });
@@ -0,0 +1,4 @@
1
+ <div class="{{ class_name }}">
2
+ ```mermaid
3
+ {{ content }}```
4
+ </div>
@@ -0,0 +1,19 @@
1
+ """Jinja2 helpers for Markdown/HTML rendering."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from jinja2 import Environment, PackageLoader, StrictUndefined, select_autoescape
6
+
7
+ _ENV = Environment(
8
+ loader=PackageLoader("unifi_network_maps.render", "templates"),
9
+ autoescape=select_autoescape(enabled_extensions=("html", "xml")),
10
+ trim_blocks=True,
11
+ lstrip_blocks=True,
12
+ keep_trailing_newline=True,
13
+ undefined=StrictUndefined,
14
+ )
15
+
16
+
17
+ def render_template(name: str, **context: object) -> str:
18
+ template = _ENV.get_template(name)
19
+ return template.render(**context)
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: unifi-network-maps
3
- Version: 1.4.4
3
+ Version: 1.4.6
4
4
  Summary: Dynamic UniFi -> network maps in mermaid or svg
5
5
  Author: Merlijn
6
6
  License-Expression: MIT
@@ -23,6 +23,7 @@ License-File: LICENSE
23
23
  Requires-Dist: unifi-controller-api==0.3.2
24
24
  Requires-Dist: python-dotenv==1.2.1
25
25
  Requires-Dist: PyYAML==6.0.3
26
+ Requires-Dist: Jinja2==3.1.6
26
27
  Provides-Extra: dev
27
28
  Requires-Dist: Faker==40.1.0; extra == "dev"
28
29
  Requires-Dist: behave==1.3.3; extra == "dev"
@@ -143,6 +144,11 @@ Legend only:
143
144
  unifi-network-maps --legend-only --stdout
144
145
  ```
145
146
 
147
+ ## Home Assistant integration
148
+
149
+ The live Home Assistant integration (Config Flow + coordinator + custom card) lives in a separate repo:
150
+ - https://github.com/merlijntishauser/unifi-network-maps-ha
151
+
146
152
  ## Examples (mock data)
147
153
 
148
154
  These examples are generated from `examples/mock_data.json` (safe, anonymized fixture).
@@ -1,4 +1,4 @@
1
- unifi_network_maps/__init__.py,sha256=6stz_YFBRP_lguydVylsTgSmj3VTb6WFq8Sp45WYQyY,22
1
+ unifi_network_maps/__init__.py,sha256=0optyte4cOxIRRV4Vdh_XYGrxTLJSuPWvhUDQkXvb4U,22
2
2
  unifi_network_maps/__main__.py,sha256=XsOjaqslAVgyVlOTokjVddZ2iT8apZXpJ_OB-9WEEe4,179
3
3
  unifi_network_maps/adapters/__init__.py,sha256=nzx1KsiYalL_YuXKE6acW8Dj5flmMg0-i4gyYO0gV54,22
4
4
  unifi_network_maps/adapters/config.py,sha256=Bx9JDZxxY7Gjxyb8FDT0dxiKfgXt_TmzTDbgvpwB53s,1548
@@ -50,30 +50,50 @@ unifi_network_maps/assets/icons/isometric/user.svg,sha256=bYpr0t8rETJ1M7RDTWaNkK
50
50
  unifi_network_maps/assets/icons/isometric/vm.svg,sha256=in6x9cdS6JgQVJl0KAbA79rap4X140dfIBCuxmgQI7s,3694
51
51
  unifi_network_maps/assets/themes/dark.yaml,sha256=6n4_H6MZbA6DKLdF2eaNcCXYLKNJjVjNN9gmwZX97sA,932
52
52
  unifi_network_maps/assets/themes/default.yaml,sha256=F2Jj18NmdaJ_zyERvGAn8NEWBwapjtozrtZUxayd5AU,849
53
- unifi_network_maps/cli/__init__.py,sha256=2FdmLMpYFh_7P0ew2LnieLANf6ni43Ht9FKzYUDiNis,770
53
+ unifi_network_maps/cli/__init__.py,sha256=cds9GvFNZmYAR22Ab3TSzfriSAW--kf9jvC5U-21AoA,70
54
54
  unifi_network_maps/cli/__main__.py,sha256=nK_jh78VW3h3DRvSpjzpcf64zkCqniP2k82xUR9Hw2I,147
55
- unifi_network_maps/cli/main.py,sha256=klDyfD-wPr3vTRulNzfOcslERcONMpxf4iTtrCJpyMQ,27582
55
+ unifi_network_maps/cli/args.py,sha256=lIgQDeob_SIhjXg76hJsnpgNOKupSjSYum_MqarWOkE,5552
56
+ unifi_network_maps/cli/main.py,sha256=jQXesuHJLTQl4lBk1DD6em67Wj9oEjBmH9X-X1zA6MI,4150
57
+ unifi_network_maps/cli/render.py,sha256=sUyDWm_I_zbEcKuNEpKUXDxhe1XptgOYsmdMP9BJ3Eg,7040
58
+ unifi_network_maps/cli/runtime.py,sha256=Hln4LMpuTrEsy6gIBmqkOrUpMb4nTeZ-AH72KyxpZwA,4723
56
59
  unifi_network_maps/io/__init__.py,sha256=nzx1KsiYalL_YuXKE6acW8Dj5flmMg0-i4gyYO0gV54,22
57
60
  unifi_network_maps/io/debug.py,sha256=eUVs6GLfs6VqI6ma8ra7NLhC3q4ek2K8OSRLnpQDF9s,1745
58
61
  unifi_network_maps/io/export.py,sha256=2vURunQDja-_fKKMb-gQG-n34aeM8GFprNJqcGaP4qg,843
62
+ unifi_network_maps/io/mkdocs_assets.py,sha256=oueDLiiIW05mN-mZ2BWV7oECX-EXDjJt8msCJHMcQwg,596
59
63
  unifi_network_maps/io/mock_data.py,sha256=uiQ8Ta8oxs5D1MUA1ONWmp09sxH0-FNlz3SJBXMeezo,714
60
- unifi_network_maps/io/mock_generate.py,sha256=xKaPRj-STtI154SMTPP9iCl0s7AVZekX4uPb-bMxRvA,8508
64
+ unifi_network_maps/io/mock_generate.py,sha256=xiJz_qtNW7iVj7dezLNyVXAHtCHAi8U5CSXK5mrJE4U,233
61
65
  unifi_network_maps/model/__init__.py,sha256=nzx1KsiYalL_YuXKE6acW8Dj5flmMg0-i4gyYO0gV54,22
62
66
  unifi_network_maps/model/labels.py,sha256=m_k8mbzWtOSDOjjHhLUqwIw93pg98HAtGtHkiERXmek,1135
63
67
  unifi_network_maps/model/lldp.py,sha256=SrPW5XC2lfJgaGeVx-KnSFNltyok7gIWWQNg1SkOaj4,3300
68
+ unifi_network_maps/model/mock.py,sha256=kd1MSiIn-7KKu_nMVmheYPfTyAN5DHt4dzRrBifF_lI,8706
64
69
  unifi_network_maps/model/ports.py,sha256=o3NBlXcC5VV5iPWJsO4Ll1mRKJZC0f8zTHdlkkE34GU,609
65
70
  unifi_network_maps/model/topology.py,sha256=JfpY6Pam_pgqnnmsBmzy3oDv4OCi4Ezc8msxvp5Z5NQ,26784
66
71
  unifi_network_maps/render/__init__.py,sha256=nzx1KsiYalL_YuXKE6acW8Dj5flmMg0-i4gyYO0gV54,22
67
- unifi_network_maps/render/device_ports_md.py,sha256=QoRiuP9l2CH8BYRHXRaWM5wyucAURz-zByzwMetnND4,15473
68
- unifi_network_maps/render/lldp_md.py,sha256=Eg5c5SWEwTfEn6AN0fOfD3f41GlsqwZQRO8AzIXFQf4,10753
69
- unifi_network_maps/render/mermaid.py,sha256=GVn7VN0xdmweDnjk-0Q8nuivqOZ3YFBQ_iTonNydy28,9675
72
+ unifi_network_maps/render/device_ports_md.py,sha256=vt5kGFSIAabMbcSxIuVVLSzdb_i58NHGi4hJM2ZLZR4,15975
73
+ unifi_network_maps/render/legend.py,sha256=TmZsxgCVOM2CZImI9zgRVyzrcg01HZFDj9F715d4CGo,772
74
+ unifi_network_maps/render/lldp_md.py,sha256=K6qTaI8HPsU7Cn0rNCJxn-Gvzkol1-m4kt0atI2NAXA,11347
75
+ unifi_network_maps/render/markdown_tables.py,sha256=VvM0fSnSmpeeDPcD5pXaL_j_PTF0STrMCaqnr2BVHn4,547
76
+ unifi_network_maps/render/mermaid.py,sha256=xsC57Xg-nKhmlVATzEbwLkMM2BOeDYlBjZuxBIPhHeI,8324
70
77
  unifi_network_maps/render/mermaid_theme.py,sha256=7nqLlvhaUA4z0YOs0ByEx_yHWcQD_hJJjhDtRcbSpg4,1781
71
- unifi_network_maps/render/svg.py,sha256=RHmSmlKxrS8m3-zYsTJu-GZugsZt8X8TDsPpK7DA6tg,38807
78
+ unifi_network_maps/render/mkdocs.py,sha256=EOST9_eP1ZoZQax-p-2fjlelrl3AKEJ9Gn-KXW8TI-o,5389
79
+ unifi_network_maps/render/svg.py,sha256=KLsQKmk1ActaMYnVnhta3BNCF4HrlcGJYhV8F8VTMmg,39924
72
80
  unifi_network_maps/render/svg_theme.py,sha256=Si1ArM3v_-wAvHZyLFPiOZ0ohQRd6ezIckwC3_b-WIw,2684
81
+ unifi_network_maps/render/templating.py,sha256=VJbXzZFBPjL8LFFPcLf_EU5Eu53GN9_vpten2Mf9A-k,576
73
82
  unifi_network_maps/render/theme.py,sha256=vKYdPhcGEOV1o_irwqzJlIXPgRvZqQEzYYV2_TxZn4E,4301
74
- unifi_network_maps-1.4.4.dist-info/licenses/LICENSE,sha256=mYo1siIIfIwyfdOuK2-Zt0ij2xBTii2hnpeTu79nD80,1074
75
- unifi_network_maps-1.4.4.dist-info/METADATA,sha256=HqLRtIKBUEZDxWvBZxO6DdcnLroyEasUG5O7CwKKIOc,9529
76
- unifi_network_maps-1.4.4.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
77
- unifi_network_maps-1.4.4.dist-info/entry_points.txt,sha256=cdJ7jsBgNgHxSflYUOqgz5BbvuM0Nnh-x8_Hbyh_LFg,67
78
- unifi_network_maps-1.4.4.dist-info/top_level.txt,sha256=G0rUX1PNfVCn1u-KtB6QjFQHopCOVLnPMczvPOoraHg,19
79
- unifi_network_maps-1.4.4.dist-info/RECORD,,
83
+ unifi_network_maps/render/templates/device_port_block.md.j2,sha256=ZfyE_lEHz6ZyYRxAYhAhwpxlLczn_U9eTkRLUrwU5Io,50
84
+ unifi_network_maps/render/templates/legend_compact.html.j2,sha256=DaY2m6N6Yd7qNKLuB5Bc395MHfrKOU9myAZvgcJrhpE,738
85
+ unifi_network_maps/render/templates/lldp_device_section.md.j2,sha256=ewX-SBrL5Hn1kuwDKo4fqqetj9tTpR7LQavSn6No_yY,206
86
+ unifi_network_maps/render/templates/markdown_section.md.j2,sha256=ZKWErGcMoLtrZ3AsXVFqf04sFW4E_cYQBpa0DX1koOY,27
87
+ unifi_network_maps/render/templates/mermaid_legend.mmd.j2,sha256=nuamV8SAaFuA3Fp9rkAmoIIJSsG-DKjWDDCIRhTQlh4,1253
88
+ unifi_network_maps/render/templates/mkdocs_document.md.j2,sha256=SW52jDxyyunC2ZOjp-n3iaFQzYB0mfCIqbDdJjAl9V8,408
89
+ unifi_network_maps/render/templates/mkdocs_dual_theme_style.html.j2,sha256=n1LTmihCHThKhKXhNcYeVlQxcfjnSd8o43Xky1RsLTE,407
90
+ unifi_network_maps/render/templates/mkdocs_html_block.html.j2,sha256=5l5-BbNujOcERnWwVlaQ4H3qZ3GTEn_KLBwIMHjwj5w,113
91
+ unifi_network_maps/render/templates/mkdocs_legend.css.j2,sha256=tkTI-RagBSgdjUygVenlTsQFenU09ePbXOfDt_Q7YRM,612
92
+ unifi_network_maps/render/templates/mkdocs_legend.js.j2,sha256=qMYyCKsJ84uXf1wGgzbc7Bc49RU4oyuaGK9KrgQDQEI,685
93
+ unifi_network_maps/render/templates/mkdocs_mermaid_block.md.j2,sha256=9IncllWQpoI8BN3A7b2zOQ5cksj97ddsjHJ-aBhpw7o,66
94
+ unifi_network_maps-1.4.6.dist-info/licenses/LICENSE,sha256=mYo1siIIfIwyfdOuK2-Zt0ij2xBTii2hnpeTu79nD80,1074
95
+ unifi_network_maps-1.4.6.dist-info/METADATA,sha256=pQZefF7brMQc9vGxphkG7AzFaQNrotEy3amCA3sFrYc,9754
96
+ unifi_network_maps-1.4.6.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
97
+ unifi_network_maps-1.4.6.dist-info/entry_points.txt,sha256=cdJ7jsBgNgHxSflYUOqgz5BbvuM0Nnh-x8_Hbyh_LFg,67
98
+ unifi_network_maps-1.4.6.dist-info/top_level.txt,sha256=G0rUX1PNfVCn1u-KtB6QjFQHopCOVLnPMczvPOoraHg,19
99
+ unifi_network_maps-1.4.6.dist-info/RECORD,,