diff --git a/.claude/skills/plugin-readme/SKILL.md b/.claude/skills/plugin-readme/SKILL.md index 4a52e0296..380f731b2 100644 --- a/.claude/skills/plugin-readme/SKILL.md +++ b/.claude/skills/plugin-readme/SKILL.md @@ -41,7 +41,7 @@ Before concluding a plugin has no attribution to record, grep its script for a c - `TBC` or similarly empty content, especially for a prominent feature. - Duplicate or orphaned sections (e.g. two `### Usage` headings) - usually a merge/edit artifact. - Sibling non-README files (a provider-specific sub-guide, a translated `README_.md`) that aren't linked from the plugin's own `README.md` - `docs/gen_plugin_pages.py` generates a page for every `*.md` in the plugin folder, but only reachable if something links to it. -- A table (or any multi-line block) indented under a bullet as that list item's continuation. GitHub's renderer tolerates this, but the docs site (`mkdocs`, Python-Markdown) terminates the list right there - the table and everything after it fall out as orphaned paragraphs, and the *next* bullet renders as a literal `-`-prefixed line of text instead of a list item. Looks fine in the PR diff on GitHub, breaks only once published. Fix: de-nest it - end the bullet's text, blank line, then the table/block as top-level (unindented) content, blank line, then resume the list as a fresh block. +- A table (or any multi-line block) indented under a bullet as that list item's continuation. GitHub's renderer tolerates loose (2-3 space) indentation; the docs site (`mkdocs`, Python-Markdown) only keeps the block nested inside that list item at a full 4-space indent - anything less and the block falls out as an orphaned, unindented paragraph/table right after the list closes. Separately, and regardless of indent width: a bullet that follows the block *without* a blank line in between merges into it as plain text instead of parsing as a new list item - confirmed this still breaks even at the correct 4-space indent, so fixing the indent alone isn't sufficient. Looks fine in the PR diff on GitHub, breaks only once published. Simplest, most portable fix (works regardless of either rule): de-nest it - end the bullet's text, blank line, then the table/block as top-level (unindented) content, blank line, then resume the list as a fresh block. ## Reference diff --git a/.gemini/skills/plugin-readme/plugin-readme-skill.md b/.gemini/skills/plugin-readme/plugin-readme-skill.md index 8eb6e9f6b..5a1307d15 100644 --- a/.gemini/skills/plugin-readme/plugin-readme-skill.md +++ b/.gemini/skills/plugin-readme/plugin-readme-skill.md @@ -41,7 +41,7 @@ Before concluding a plugin has no attribution to record, grep its script for a c - `TBC` or similarly empty content, especially for a prominent feature. - Duplicate or orphaned sections (e.g. two `### Usage` headings) - usually a merge/edit artifact. - Sibling non-README files (a provider-specific sub-guide, a translated `README_.md`) that aren't linked from the plugin's own `README.md` - `docs/gen_plugin_pages.py` generates a page for every `*.md` in the plugin folder, but only reachable if something links to it. -- A table (or any multi-line block) indented under a bullet as that list item's continuation. GitHub's renderer tolerates this, but the docs site (`mkdocs`, Python-Markdown) terminates the list right there - the table and everything after it fall out as orphaned paragraphs, and the *next* bullet renders as a literal `-`-prefixed line of text instead of a list item. Looks fine in the PR diff on GitHub, breaks only once published. Fix: de-nest it - end the bullet's text, blank line, then the table/block as top-level (unindented) content, blank line, then resume the list as a fresh block. +- A table (or any multi-line block) indented under a bullet as that list item's continuation. GitHub's renderer tolerates loose (2-3 space) indentation; the docs site (`mkdocs`, Python-Markdown) only keeps the block nested inside that list item at a full 4-space indent - anything less and the block falls out as an orphaned, unindented paragraph/table right after the list closes. Separately, and regardless of indent width: a bullet that follows the block *without* a blank line in between merges into it as plain text instead of parsing as a new list item - confirmed this still breaks even at the correct 4-space indent, so fixing the indent alone isn't sufficient. Looks fine in the PR diff on GitHub, breaks only once published. Simplest, most portable fix (works regardless of either rule): de-nest it - end the bullet's text, blank line, then the table/block as top-level (unindented) content, blank line, then resume the list as a fresh block. ## Reference diff --git a/.github/skills/plugin-readme/SKILL.md b/.github/skills/plugin-readme/SKILL.md index 48d860db8..0a952957a 100644 --- a/.github/skills/plugin-readme/SKILL.md +++ b/.github/skills/plugin-readme/SKILL.md @@ -41,7 +41,7 @@ Before concluding a plugin has no attribution to record, grep its script for a c - `TBC` or similarly empty content, especially for a prominent feature. - Duplicate or orphaned sections (e.g. two `### Usage` headings) - usually a merge/edit artifact. - Sibling non-README files (a provider-specific sub-guide, a translated `README_.md`) that aren't linked from the plugin's own `README.md` - `docs/gen_plugin_pages.py` generates a page for every `*.md` in the plugin folder, but only reachable if something links to it. -- A table (or any multi-line block) indented under a bullet as that list item's continuation. GitHub's renderer tolerates this, but the docs site (`mkdocs`, Python-Markdown) terminates the list right there - the table and everything after it fall out as orphaned paragraphs, and the *next* bullet renders as a literal `-`-prefixed line of text instead of a list item. Looks fine in the PR diff on GitHub, breaks only once published. Fix: de-nest it - end the bullet's text, blank line, then the table/block as top-level (unindented) content, blank line, then resume the list as a fresh block. +- A table (or any multi-line block) indented under a bullet as that list item's continuation. GitHub's renderer tolerates loose (2-3 space) indentation; the docs site (`mkdocs`, Python-Markdown) only keeps the block nested inside that list item at a full 4-space indent - anything less and the block falls out as an orphaned, unindented paragraph/table right after the list closes. Separately, and regardless of indent width: a bullet that follows the block *without* a blank line in between merges into it as plain text instead of parsing as a new list item - confirmed this still breaks even at the correct 4-space indent, so fixing the indent alone isn't sufficient. Looks fine in the PR diff on GitHub, breaks only once published. Simplest, most portable fix (works regardless of either rule): de-nest it - end the bullet's text, blank line, then the table/block as top-level (unindented) content, blank line, then resume the list as a fresh block. ## Reference diff --git a/docs/PLUGINS_OVERVIEW.md b/docs/PLUGINS_OVERVIEW.md index dd379b061..811930ec5 100644 --- a/docs/PLUGINS_OVERVIEW.md +++ b/docs/PLUGINS_OVERVIEW.md @@ -58,6 +58,7 @@ The **Plugin docs** links below open each plugin's README rendered as part of th | `DHCPLSS` | [dhcp_leases](plugins/dhcp_leases.md) | 📥/🆎 | Import devices from DHCP leases | | | | `DHCPSRVS` | [dhcp_servers](plugins/dhcp_servers.md) | ♻ | DHCP servers | | | | `DIGSCAN` | [dig_scan](plugins/dig_scan.md) | 🆎 | Dig (DNS) Name resolution | | | +| `DOCKERDISC` | [dockerdisc](plugins/dockerdisc.md) | ♻ | Enriches known Docker hosts with their running containers | | | | `FREEBOX` | [freebox](plugins/freebox.md) |📥/♻/🆎 | Pull data and names from Freebox/Iliadbox | | | | `FRITZBOX` | [fritzbox](plugins/fritzbox.md) | 📥 | Fritz!Box device scanner via TR-064 | | | | `ICMP` | [icmp_scan](plugins/icmp_scan.md) | ♻ | ICMP (ping) status checker | | | diff --git a/server/plugins/pihole_monitor/config.json b/server/plugins/pihole_monitor/config.json index 5bc30d583..2f170bec9 100644 --- a/server/plugins/pihole_monitor/config.json +++ b/server/plugins/pihole_monitor/config.json @@ -524,7 +524,6 @@ }, { "column": "extra", - "mapped_to_column": "scanSourcePlugin", "css_classes": "col-sm-3", "show": true, "type": "label", @@ -533,6 +532,20 @@ "localized": ["name"], "name": [{ "language_code": "en_us", "string": "Detail" }] }, + { + "column": "Dummy", + "mapped_to_column": "scanSourcePlugin", + "mapped_to_column_data": { + "value": "PIHOLEMON" + }, + "css_classes": "col-sm-2", + "show": false, + "type": "none", + "default_value": "", + "options": [], + "localized": ["name"], + "name": [{ "language_code": "en_us", "string": "N/A" }] + }, { "column": "dateTimeChanged", "css_classes": "col-sm-2", diff --git a/test/plugins/test_adguard_import.py b/test/plugins/test_adguard_import.py index ce10f88d9..98385a84c 100644 --- a/test/plugins/test_adguard_import.py +++ b/test/plugins/test_adguard_import.py @@ -17,9 +17,11 @@ is a permanent binding, not evidence of current connectivity), passed via helpVal4 (config.json maps helpVal4 -> scanPresence). """ +import importlib.util import os import sys import types +from pathlib import Path from unittest.mock import MagicMock, patch import pytest @@ -47,8 +49,6 @@ def _load_adguard_import_module(): stub("conf", tz=None) stub("pytz", timezone=MagicMock(return_value="UTC")) - import importlib.util - from pathlib import Path module_path = Path(__file__).resolve().parents[2] / "server" / "plugins" / "adguard_import" / "adguard_import.py" spec = importlib.util.spec_from_file_location("adguard_import_script", module_path) module = importlib.util.module_from_spec(spec) diff --git a/test/plugins/test_plugin_conventions.py b/test/plugins/test_plugin_conventions.py index 2a4fce918..939e6deab 100644 --- a/test/plugins/test_plugin_conventions.py +++ b/test/plugins/test_plugin_conventions.py @@ -415,8 +415,16 @@ def test_scan_source_plugin_matches_unique_prefix(plugin_name): if col.get('mapped_to_column') != 'scanSourcePlugin': continue value = (col.get('mapped_to_column_data') or {}).get('value') - if value is None: - continue + assert value is not None, ( + f"{plugin_name}: column {col.get('column')!r} maps to scanSourcePlugin " + f"but has no static \"mapped_to_column_data\": {{\"value\": ...}} - scanSourcePlugin " + f"identifies which plugin produced a CurrentScan row and must be a single static " + f"value (its own unique_prefix, {prefix!r}), not a per-row value from another " + f"field. Mapping a per-row field here (e.g. a free-text detail column) writes " + f"that field's actual value into scanSourcePlugin instead, breaking " + f"update_devices_data_from_scan()'s per-plugin grouping the same way a wrong " + f"static value does." + ) assert value == prefix, ( f"{plugin_name}: scanSourcePlugin's static value is {value!r}, but " f"unique_prefix is {prefix!r}. These must match exactly - "