Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
131 commits
Select commit Hold shift + click to select a range
ac3b4c5
Feature: IP Scanner: Show which probe found a host (A1)
BornToBeRoot Oct 30, 2026
a4250a3
Fix: IP Scanner: Export empty values for disabled probes (A2a)
BornToBeRoot Oct 30, 2026
18efed3
Feature: IP Scanner: Option to disable the ping (A2)
BornToBeRoot Oct 30, 2026
dc2e045
Fix: Neighbor Table: State shifted by one (A3a)
BornToBeRoot Oct 30, 2026
7a81281
Feature: IP Scanner: Find hosts in the local subnet via ARP / NDP (A3)
BornToBeRoot Oct 30, 2026
f0244e9
Feature: IP Scanner: Choose the network interface for Detect local su…
BornToBeRoot Oct 30, 2026
04998ff
Feature: IP Scanner / Port Scanner / Ping Monitor: Exclude IP address…
BornToBeRoot Oct 30, 2026
d10ea63
Feature: IP Scanner: OS guess from TTL (B1)
BornToBeRoot Oct 30, 2026
7a33c10
Feature: IP Scanner: Mark own computer, default gateway, DNS and DHCP…
BornToBeRoot Oct 30, 2026
056fc9e
Refactor: IP Scanner: UdpRequest for NetBIOS (C1a)
BornToBeRoot Oct 30, 2026
255ff79
Feature: IP Scanner: Resolve mDNS hostname (C1)
BornToBeRoot Oct 30, 2026
70d7dfb
Feature: IP Scanner: Read the title of web pages (C2)
BornToBeRoot Oct 30, 2026
9007e68
Feature: IP Scanner: Read the SNMP system information (C3)
BornToBeRoot Oct 30, 2026
a6a11de
Feature: IP Scanner: Configurable ports for the web page title (C2b)
BornToBeRoot Oct 30, 2026
a9deae3
Feature: IP Scanner: ARP / NDP settings section with help (A3b)
BornToBeRoot Oct 30, 2026
79aefab
Feature: IP Scanner: Labels for Detected by (A1b)
BornToBeRoot Oct 30, 2026
d43f752
Feature: IP Scanner: Show "..." while lookups are running (C4)
BornToBeRoot Oct 30, 2026
83aa2cf
Feature: IP Scanner: Status code, Server and X-Powered-By of web page…
BornToBeRoot Oct 30, 2026
acd882c
Feature: IP Scanner: Row details for hostnames, web page and SNMP (C5)
BornToBeRoot Oct 30, 2026
27c3bf5
Feature: IP Scanner: SNMP answer marks a host as up (C3b)
BornToBeRoot Oct 30, 2026
852a525
Feature: IP Scanner: Row details in four columns with up / down label…
BornToBeRoot Oct 30, 2026
e9c7bb1
Feature: IP Scanner: Hostname and MAC address pending until all sourc…
BornToBeRoot Oct 30, 2026
d515c03
Feature: IP Scanner: Status icons with details in the tooltip (C5c)
BornToBeRoot Oct 30, 2026
9bb40b9
Feature: IP Scanner: Icon for the OS guess (B1b)
BornToBeRoot Oct 30, 2026
c2fb1bb
Feature: IP Scanner: Rename "Web title" to "Web" (C2d)
BornToBeRoot Oct 30, 2026
0263cdf
Feature: IP Scanner: Realm of the login prompt and redirect target of…
BornToBeRoot Oct 30, 2026
7019284
Feature: IP Scanner: TLS certificate of web pages (C2f)
BornToBeRoot Oct 30, 2026
f1c444e
Fix: IP Scanner: Scan with SNMP as the only probe (R1)
BornToBeRoot Oct 30, 2026
8407cde
Fix: IP Scanner: Invalid web page URL ended the scan (R2)
BornToBeRoot Oct 30, 2026
7a9aa27
Fix: IP Scanner: ARP / NDP reported hosts that were gone as up (R3)
BornToBeRoot Oct 30, 2026
406d9ed
Fix: IP Scanner: Lookups stayed "..." after Cancel (R4)
BornToBeRoot Oct 30, 2026
10a021a
Fix: IP Scanner: ARP verification still running after a canceled scan…
BornToBeRoot Oct 30, 2026
4a693e8
Fix: IP Scanner / Port Scanner / Ping Monitor: No message if all IP a…
BornToBeRoot Oct 30, 2026
4b04030
Fix: IP Scanner: Neighbor table lookups waited for the lock (R7)
BornToBeRoot Oct 30, 2026
1840ae0
Refactor: IP Scanner: Gateways of the neighbor check once per scan (R8)
BornToBeRoot Oct 30, 2026
0fb1487
Refactor: IP Scanner: One "host found" block (R9)
BornToBeRoot Oct 30, 2026
f9fa683
Fix: IP Scanner: Slow https attempt on plain http ports (R10)
BornToBeRoot Oct 30, 2026
295a054
Feature: IP Scanner: Copy the values of the optional requests (R11)
BornToBeRoot Oct 30, 2026
b3fa524
Docs: IP Scanner: Restructure the result documentation (R12)
BornToBeRoot Oct 30, 2026
29806e9
Fix: IP Scanner / Port Scanner / Ping Monitor: Exclude all addresses …
BornToBeRoot Oct 31, 2026
df47765
Fix: IP Scanner / Port Scanner / Ping Monitor: No message if all IP a…
BornToBeRoot Oct 31, 2026
3ce934c
Fix: IP Scanner: Error reading the neighbor table ended the scan (R15)
BornToBeRoot Oct 31, 2026
fe2f58e
Fix: IP Scanner: Read web pages tried http on https ports (R16)
BornToBeRoot Oct 31, 2026
beeb475
Fix: IP Scanner: Title of web pages with a code page charset (R17)
BornToBeRoot Oct 31, 2026
9919c8d
Fix: IP Scanner: Certificate of a web page after a redirect to http (…
BornToBeRoot Oct 31, 2026
a753ebd
Fix: IP Scanner: ARP / NDP used an old snapshot for the state before …
BornToBeRoot Oct 31, 2026
6499bee
Docs: IP Scanner: DetectedBy is not the last export column anymore (R20)
BornToBeRoot Oct 31, 2026
ccf6780
Docs: IP Scanner: DNSHostname is not the last export column anymore
BornToBeRoot Oct 31, 2026
c988306
Docs: Changelog: PR number #3685 of the IP Scanner discovery changes
BornToBeRoot Oct 31, 2026
22f1ab4
Chore: Adjust skill
BornToBeRoot Oct 31, 2026
32e628b
Fix: IP Scanner: Double spaces in the SNMP description (B1)
BornToBeRoot Oct 31, 2026
97e6715
Refactor: IP Scanner: Clone the host result with CopyFrom (R27)
BornToBeRoot Oct 31, 2026
e0cb402
Refactor: IP Scanner: Result options from the scan options (R28)
BornToBeRoot Oct 31, 2026
7a43ef0
Refactor: IP Scanner / Ping Monitor: AddStatusMessage like the Port S…
BornToBeRoot Oct 31, 2026
f47e872
Refactor: IP Scanner / Port Scanner / Ping Monitor: One parser for th…
BornToBeRoot Oct 31, 2026
759687e
Refactor: IP Scanner: One field list for the CSV, XML and JSON export…
BornToBeRoot Oct 31, 2026
637c3da
Refactor: IP Scanner: Neighbor table of a scan in its own class (R23)
BornToBeRoot Oct 31, 2026
b83b450
Refactor: IP Scanner: Shared styles for the row details (R24)
BornToBeRoot Oct 31, 2026
dff2fd3
Fix: IP Scanner / Port Scanner / Ping Monitor: Excluded host scanned …
BornToBeRoot Oct 31, 2026
20d574a
Fix: IP Scanner: Control characters in the mDNS hostname (F2)
BornToBeRoot Oct 31, 2026
30771d2
Fix: IP Scanner: Export of web values without the port scan (F3)
BornToBeRoot Oct 31, 2026
17ad7af
Fix: IP Scanner: Local subnet of an adapter that is down (F4)
BornToBeRoot Oct 31, 2026
4db301c
Fix: IP Scanner: TTL in the tooltip of the ping status from the strin…
BornToBeRoot Oct 31, 2026
40a5fc6
Fix: IP Scanner: Web section of the row details empty without the por…
BornToBeRoot Oct 31, 2026
827f8a0
IP Scanner: Web and port scan settings disabled while the port scan i…
BornToBeRoot Oct 31, 2026
78ad767
IP Scanner: Options button to turn the scan options on or off (F1)
BornToBeRoot Oct 31, 2026
6c79f2a
Menus: Checkmark of checkable menu items in Gray3 instead of the acce…
BornToBeRoot Oct 31, 2026
748cd9e
Fix: Connections / Listeners / Neighbor Table / WiFi: Auto refresh of…
BornToBeRoot Nov 1, 2026
4d88bdf
Refactor: Shared auto refresh timer and control
BornToBeRoot Nov 1, 2026
6930379
Refactor: Connections: Shared auto refresh timer and control
BornToBeRoot Nov 1, 2026
cac4c31
Refactor: Listeners: Shared auto refresh timer and control
BornToBeRoot Nov 1, 2026
b78689d
Refactor: Neighbor Table: Shared auto refresh timer and control
BornToBeRoot Nov 1, 2026
4b66640
Refactor: WiFi: Shared auto refresh timer and control
BornToBeRoot Nov 1, 2026
8ddb089
Refresh icon: Spins until the reload is finished, completes its turn
BornToBeRoot Nov 1, 2026
376c9e7
TaskHelper: Run an action with a minimum duration
BornToBeRoot Nov 1, 2026
579cb92
Connections: Minimum duration of a refresh runs while loading
BornToBeRoot Nov 1, 2026
9a1259d
Listeners: Minimum duration of a refresh runs while loading
BornToBeRoot Nov 1, 2026
8b4a0a1
Neighbor Table: Minimum duration of a refresh runs while loading
BornToBeRoot Nov 1, 2026
a2fe828
Fix: Hosts File Editor: Retry of a locked hosts file waited twice
BornToBeRoot Nov 1, 2026
5fed4b4
Hosts File Editor: Minimum duration of a refresh runs while loading
BornToBeRoot Nov 1, 2026
1c2cb66
Firewall: Minimum duration of a refresh runs while loading
BornToBeRoot Nov 1, 2026
4b52b21
WiFi: Minimum duration of reloading the adapters runs while loading
BornToBeRoot Nov 1, 2026
3d8b156
Dashboard: Minimum duration of the IP geolocation / DNS resolver chec…
BornToBeRoot Nov 1, 2026
0351c3a
Refresh status in the header: shared control and countdown format
BornToBeRoot Nov 1, 2026
9613229
Connections: Refresh status in the header, countdown to the next refresh
BornToBeRoot Nov 1, 2026
5c88edc
Listeners: Refresh status in the header, countdown to the next refresh
BornToBeRoot Nov 1, 2026
e99f787
Neighbor Table: Refresh status in the header, countdown to the next r…
BornToBeRoot Nov 1, 2026
2dc51a7
Hosts File Editor: Refresh status in the header
BornToBeRoot Nov 1, 2026
ed5caf2
Firewall: Refresh status in the header
BornToBeRoot Nov 1, 2026
96d0f69
WiFi: Scan status in the header of the networks, countdown to the nex…
BornToBeRoot Nov 1, 2026
9a15f1d
IP Scanner: Changes since the last scan (E1)
BornToBeRoot Nov 1, 2026
e9d0f56
Port Scanner: Changes since the last scan (E1)
BornToBeRoot Nov 1, 2026
52ae9d7
IP Scanner: Repeat the scan automatically (E2)
BornToBeRoot Nov 1, 2026
aee5632
Port Scanner: Repeat the scan automatically (E2)
BornToBeRoot Nov 1, 2026
6662bc8
IP Scanner: Notification of the changes of a repeated scan
BornToBeRoot Nov 1, 2026
7a7bd12
Port Scanner: Notification of the changes of a repeated scan
BornToBeRoot Nov 1, 2026
6e98ad7
Fix: IP Scanner: Gone host of a repeated scan without the previous ho…
BornToBeRoot Nov 1, 2026
4e06d74
Refactor: IP Scanner / Port Scanner: Shared repeat of the scan (ScanR…
BornToBeRoot Nov 1, 2026
17610d4
Fix: IP Scanner / Port Scanner: Input changed during a scan was repea…
BornToBeRoot Nov 1, 2026
37d3750
IP Scanner / Port Scanner: A failed repeated scan is tried again
BornToBeRoot Nov 1, 2026
002729b
Fix: IP Scanner / Port Scanner: Counters of a canceled repeated scan
BornToBeRoot Nov 1, 2026
fcf88de
Fix: IP Scanner / Port Scanner: Change of a rescanned host / port not…
BornToBeRoot Nov 1, 2026
2b63775
Fix: Port Scanner: Notification titled with the current instead of th…
BornToBeRoot Nov 1, 2026
db06a7f
Fix: IP Scanner: Row of an address no longer in the input stays after…
BornToBeRoot Nov 1, 2026
37adabb
IP Scanner: Repeated scan reports only the down hosts with a row
BornToBeRoot Nov 1, 2026
8431900
IP Scanner: Rows of the gone hosts looked up once, not searched per host
BornToBeRoot Nov 1, 2026
69ee69c
Refactor: Shared up / down notification (Ping Monitor, IP Scanner, Po…
BornToBeRoot Nov 1, 2026
3f90031
IP Scanner / Port Scanner: Column "Since last scan" in the design of …
BornToBeRoot Nov 1, 2026
e4a9317
Refactor: Notifications: one model (NotificationInfo, NotificationSta…
BornToBeRoot Nov 1, 2026
dd45354
Notifications: Header with the tool that sent it
BornToBeRoot Nov 1, 2026
026b0d3
Notifications: A click opens the tool and the tab that sent it
BornToBeRoot Nov 1, 2026
cd6885b
Docs: Notifications with the tool in the header, status colors, click
BornToBeRoot Nov 1, 2026
462e7c8
Changelog: Shorten / consolidate the entries of this branch
BornToBeRoot Nov 1, 2026
df7e96d
Fix: Exclusion of a hostname: a failed A or AAAA query excluded only …
BornToBeRoot Nov 1, 2026
530c8e3
IP Scanner / Port Scanner: Counters below the Result header, header n…
BornToBeRoot Nov 1, 2026
76b9ce6
Notifications: One line per change "address · details · status", the …
BornToBeRoot Nov 1, 2026
ea15163
Fix: IP Scanner / Port Scanner: Repeated scan without a host to scan …
BornToBeRoot Nov 1, 2026
68a751a
Fix: IP Scanner / Port Scanner: Repeat started a second scan while a …
BornToBeRoot Nov 1, 2026
797bff3
Fix: IP Scanner: Row of a gone host without its role (review #5)
BornToBeRoot Nov 1, 2026
e8eced1
Refactor: SNMP: SNMPv3 privacy provider and error codes in SNMPV3Helper
BornToBeRoot Nov 1, 2026
16eb073
IP Scanner: SNMPv3 for the SNMP system information, error of a host i…
BornToBeRoot Nov 1, 2026
8f5eff4
Profiles: SNMP override of the IP Scanner in profiles and groups
BornToBeRoot Nov 1, 2026
7640096
Profiles: SNMP override of the IP Scanner in the profile and group di…
BornToBeRoot Nov 1, 2026
f30c987
IP Scanner: A tab opened with a profile uses the SNMP version and cre…
BornToBeRoot Nov 1, 2026
9a95025
Profiles: IP Scanner SNMP secrets in the order of the tools
BornToBeRoot Nov 1, 2026
3724e3d
Refactor: SNMP: Version and credentials of the profile and group dial…
BornToBeRoot Nov 1, 2026
7a2dc7a
Ping Monitor / IP Scanner / Port Scanner: Notification popup on, soun…
BornToBeRoot Nov 1, 2026
3316836
Fix: IP Scanner: Roles of IPv6 link-local hosts matched across interf…
BornToBeRoot Nov 1, 2026
eae676c
Fix: IP Scanner: Tooltip of the port status said Closed for ports tha…
BornToBeRoot Nov 1, 2026
b04935a
IP Scanner: SNMP credentials of a profile / group in plain text only …
BornToBeRoot Nov 1, 2026
eb40d3e
Fix: Ping Monitor: Still canceling after a stop when no host was left…
BornToBeRoot Nov 1, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
76 changes: 66 additions & 10 deletions .claude/skills/feature-review/SKILL.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
---
name: feature-review
description: In-depth review of one NETworkManager feature/tool (e.g. Port Scanner, Hosts File Editor, Firewall), one settings page, or one cross-cutting area (profiles, export, status window, dashboard). First builds an understanding of how the feature works and how it integrates (models, view models, views, settings, profiles, docs), then looks for bugs and logic errors, inconsistencies within the feature and against the rest of the application (UI, icons, spacing, context menus, load/refresh/scan logic, texts), performance problems (scan logic and UI responsiveness), and missing essential functions. Use this whenever the user wants to review, audit, check, or go through a NETworkManager tool, feature, settings page or area, or asks what is wrong/missing/inconsistent in a specific part of the app, even if they don't say "review". Not for reviewing a diff/PR (use code-review for that).
description: In-depth review of one NETworkManager feature/tool (e.g. Port Scanner, Hosts File Editor, Firewall), one settings page, or one cross-cutting area (profiles, export, status window, dashboard). First builds an understanding of how the feature works and how it integrates (models, view models, views, settings, profiles, docs), then looks for bugs and logic errors, inconsistencies within the feature and against the rest of the application (UI, icons, spacing, context menus, load/refresh/scan logic, texts), performance problems (scan logic and UI responsiveness), missing essential functions, and refactorings that reduce duplication or complexity while keeping the code simple (no over-engineering). Use this whenever the user wants to review, audit, check, or go through a NETworkManager tool, feature, settings page or area, or asks what is wrong/missing/inconsistent in a specific part of the app, even if they don't say "review". Not for reviewing a diff/PR (use code-review for that).
---

# NETworkManager feature review
Expand All @@ -14,8 +14,9 @@ If no scope is given, ask which one, and offer the list of review units from
[references/integration-map.md](references/integration-map.md).

The goal is a short, trustworthy list of findings the user can act on — not a long list of maybes.
The application deliberately keeps its code simple and similar across tools; fixes should follow the
existing patterns and not introduce new abstractions unless the same problem exists in several places.
The application deliberately keeps its code simple and similar across tools: fixes and refactorings follow the
existing patterns, and the code after a change should be as simple or simpler than before — never more abstract than
the problem needs.

## Workflow

Expand Down Expand Up @@ -67,7 +68,10 @@ Go through these areas. Skip an area if it doesn't apply, but say so in one line
ranges, invalid/duplicate/overlapping entries, no network adapter, no admin rights), wrong disposal / event handlers
that are never unsubscribed (static events!), status messages overwritten by a later event (e.g. a completion
event after cancel or after an input error), exceptions in fire-and-forget `async Task` methods (`_ = Start()`)
that leave flags set.
that leave flags set, a failing optional step (one lookup, one host, a system API call) that ends the whole action
instead of only leaving that value empty, state carried over from the previous loop iteration / item (e.g. a value
of the first redirect kept for the last one), caches or snapshots used without checking their age, and conditions
where an unrelated case suppresses a message or action (e.g. "show X if nothing else failed").
2. **Consistency within the feature** — the same action behaving differently depending on where it is
triggered (button vs. context menu vs. keyboard shortcut vs. profile vs. run command / other tool), single vs. multi selection,
texts/terms that differ inside the feature.
Expand Down Expand Up @@ -95,6 +99,50 @@ Go through these areas. Skip an area if it doesn't apply, but say so in one line
placeholders (`{0}`) that translations may break, missing `...` on items that open a dialog.
8. **Documentation and changelog** — does `Website/docs/application/<feature>.md` (and settings/profile docs)
match the actual behaviour, options, defaults, context menu and shortcuts?
9. **Refactoring and simplification** — duplicated or needlessly complex code that makes the feature harder to
change, see the rules below. Look at it last, when you know how the feature works. Hints: a file much larger
than the same kind of file in the comparison features (`wc -l`), a file that grew a lot (`git log --stat`), the same
lines found twice with `git grep`, a helper from the "Shared helpers" list in
[references/conventions.md](references/conventions.md) re-implemented in the feature.

#### Refactoring: only if the code gets simpler

Report a refactoring only if it removes real duplication or complexity and the result is simpler than the code
today. Good reasons:

- **Duplicated logic that must change together**: the same parsing, validation, mapping or field list in two or more
places (e.g. an input format parsed by the validator, the model and a count method; CSV, XML and JSON export each
listing the same fields; the same command code in several view models). Strongest when the copies already drifted
(a case handled in one copy only) — then it is also a bug finding.
- **Copy-pasted XAML**: the same block repeated for every section or column (cell templates, section headers with a
status icon, label/value rows) → a `Style`, `DataTemplate` or small `UserControl`, like the existing ones.
- **A class or method with several jobs** that are hard to follow together (e.g. a cache with its own locking and
timing inside a scanner, a 300-line `Start()`): extract the separate job into a method or a small class when that
makes fixes and tests local.
- **Dead or needless code**: unused settings, parameters, properties and events, branches that can't be reached,
interfaces or base classes with one implementation, helpers with one caller that only wrap another call. Removing
code is the simplest refactoring.

Don't report:

- Style preferences, renames for taste, "modernizing" code that works, or rewriting a feature.
- New layers or patterns for a single use: interfaces, base classes, factories, generic frameworks, dependency
injection, event aggregators, settings nobody needs, extension points "for later".
- Merging code that only looks similar but changes for different reasons (e.g. the ping loops of the scanners, the
Ping Monitor and the Traceroute): share the small pieces, not the loops.

Rules for the proposal:

- **Name the gain**: fewer lines and fewer places to touch for the next change (e.g. "3 field lists → 1, about −150
lines", "a new input format is added in one place"). If the result isn't shorter or clearer, drop the finding.
- **Smallest construct that works**: a private method, a static helper, a record or a table/list that drives a loop
before a new class; a new class before a project-wide abstraction. Reuse the helpers that already exist
(`Utilities`, `Converters`, `Validators`, styles).
- **Behaviour stays identical**: name what must not change (export column order and names, settings names, file
formats, texts, public behaviour) and how it is proven (existing unit tests, or a test written *before* the
refactoring that compares the old and the new output). Never mix a behaviour change into a refactoring commit.
- **Order**: after the bug fixes; code-only refactorings first, XAML refactorings only after the current UI was tested
on Windows (so visual differences can be attributed), performance refactorings only after measuring.

### 5. Verify every finding

Expand Down Expand Up @@ -136,15 +184,19 @@ Compared with: <features from step 3>
### Other (security, localization, docs)
| # | Finding | Proposed fix |

### Refactoring / simplification
| # | Where | Problem (duplication / complexity) | Proposal | Gain | Must stay identical / test |

## Not reviewed / unverified
<areas skipped, findings that need a Windows test>

## Suggested order
<what to fix first and what to group into one PR>
```

Reference code as `path:line`. Rate each finding (High / Medium / Low) in the finding text when it helps
prioritize. Proposed fixes describe the smallest change that follows the existing patterns.
Reference code as `path:line`. Give every finding a short ID that stays the same until it is done (e.g. `B3` for a
bug, `R2` for a refactoring) — commits and handover files reference it. Rate each finding (High / Medium / Low) in the
finding text when it helps prioritize. Proposed fixes describe the smallest change that follows the existing patterns.

For larger missing features, add an issue draft at the end that follows the repository's feature request
form (`.github/ISSUE_TEMPLATE/feature_request.yml`): a short title, the affected feature, "Problem / motivation",
Expand All @@ -156,14 +208,18 @@ Don't change code during the review. Ask the user which findings to fix.

When the user wants the work handed over (to another agent or for later), write the result to
`.claude/reviews/<feature>.md` (kebab-case, e.g. `ip-scanner.md`; the folder is not committed). Write it as an
implementation plan, not as a report: verified findings with `path:line`, the concrete fix, the work packages / PR
order, decisions taken and still open, and what must be tested on Windows. Read existing files in `.claude/reviews/`
and `.claude/plans/` for the area first — they record earlier decisions.
implementation plan, not as a report: verified findings with ID, severity, `path:line`, scenario and the concrete fix
(bugs and refactorings in separate tables, refactorings after the bugs), the work packages / PR order, decisions taken
and still open, and what must be tested on Windows. Read existing files in `.claude/reviews/` and `.claude/plans/`
for the area first — they record earlier decisions. These files only track **open** work: when an item is done,
remove it (and its manual tests once they passed); the history is in git and the PRs.

When fixing:

- Follow the conventions and keep the change minimal; extract shared helpers only when the same code
already exists in two or more places.
already exists in two or more places. Keep the code simple: no new abstraction for a single use.
- One commit per finding, with its ID in the subject (e.g. `Fix: Port Scanner: ... (B3)`); a refactoring gets its own
commit without behaviour changes.
- Add strings to `Strings.resx` and, in alphabetical order, to `Strings.Designer.cs`.
- Update the feature documentation and add a changelog entry in `Website/docs/changelog/next-release.md`.
- Never modify `Source/3rdparty/`.
19 changes: 19 additions & 0 deletions .claude/skills/feature-review/references/conventions.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ report that too.
- Settings and profiles
- Navigation and run command
- PowerShell and external processes
- Shared helpers (reuse before writing new code)
- Strings, docs and changelog

## View model basics
Expand Down Expand Up @@ -221,6 +222,24 @@ Reference: `Source/NETworkManager.Models/Firewall/Firewall.cs`.
untrusted: with `cmd.exe /c ...` characters like `&` or `|` run other commands. Only insert values that match the
expected format (IP address, hostname regex).

## Shared helpers (reuse before writing new code)

Duplicated code often re-implements one of these. A refactoring proposal should use them (or extend them) before it
adds a new helper. Check the class for the exact methods.

- Host and port input: `HostRangeHelper` (Models: `CreateListFromInput`, `GetHostCount`, `ResolveAsync` with `!`
exclusions - IP Scanner, Port Scanner, Ping Monitor), `PortRangeHelper` (Utilities), validators in
`NETworkManager.Validators` (one per input format, used by tool, profile dialog and run command).
- Addresses and names: `IPAddressHelper` (compare / sort, private range, scope id), `MACAddressHelper` (format,
compare), `DNSClientHelper` / `DNSClient` (resolve A / AAAA / PTR with the app's DNS settings), `RegexHelper`.
- Lists and texts: `ListHelper.Modify` (history), `PlaceholderHelper` (`{{Name}}` placeholders), `DateTimeHelper`,
`ClipboardHelper`, `DialogHelper` (confirmations, `FormatItemList`).
- WPF: `BindingProxy`, `DataGridHelper`, `SearchTextBoxHelper`, `PermissionToolTipHelper` (Utilities.WPF),
`ObservableRangeCollection` (Controls), converters in `NETworkManager.Converters` (e.g. `PendingToStringConverter`),
shared styles in `Source/NETworkManager/Resources/Styles/`.
- PowerShell: `PowerShellHelper.EscapeSingleQuotes`; arrays (`ToPsArray`) and the shared runspace are still private to
`Firewall.cs` - a second user of them is a reason to move them to `PowerShellHelper`.

## Strings, docs and changelog

- User-visible text comes from `Strings.resx` (English only; other languages via Transifex), added in
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Windows.Data;
using NETworkManager.Localization.Resources;
using NETworkManager.Models.Network;

namespace NETworkManager.Converters;

/// <summary>
/// Convert the <see cref="IPScannerDetectionMethod" /> of a host to a translated <see cref="string" />
/// (e.g. "Ping, TCP").
/// </summary>
public sealed class IPScannerDetectionMethodToStringConverter : IValueConverter
{
/// <summary>
/// Convert the <see cref="IPScannerDetectionMethod" /> of a host to a translated <see cref="string" />.
/// </summary>
/// <param name="value">Probes the host answered as <see cref="IPScannerDetectionMethod" />.</param>
/// <param name="targetType"></param>
/// <param name="parameter">"Status" to get the status of the host ("Up (detected by Ping, TCP)" / "Down").</param>
/// <param name="culture"></param>
/// <returns>Translated, comma-separated probes, "-/-" if the host didn't answer any probe.</returns>
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
var detectedBy = value is IPScannerDetectionMethod method ? method : IPScannerDetectionMethod.None;

var names = GetNames(detectedBy);

if (parameter as string == "Status")
return detectedBy == IPScannerDetectionMethod.None
? Strings.Down
: string.Format(Strings.UpDetectedByX, string.Join(", ", names));

return detectedBy == IPScannerDetectionMethod.None ? "-/-" : string.Join(", ", names);
}

/// <summary>
/// Gets the translated names of the probes a host answered.
/// </summary>
/// <param name="detectedBy">Probes the host answered.</param>
/// <returns>Translated names, empty if the host didn't answer any probe.</returns>
private static List<string> GetNames(IPScannerDetectionMethod detectedBy)
{
var names = new List<string>(5);

if (detectedBy.HasFlag(IPScannerDetectionMethod.ICMP))
names.Add(Strings.Ping);

if (detectedBy.HasFlag(IPScannerDetectionMethod.TCP))
names.Add(Strings.TCP);

if (detectedBy.HasFlag(IPScannerDetectionMethod.NetBIOS))
names.Add(Strings.NetBIOS);

if (detectedBy.HasFlag(IPScannerDetectionMethod.SNMP))
names.Add(Strings.SNMP);

if (detectedBy.HasFlag(IPScannerDetectionMethod.ARP))
names.Add(Strings.ARPNDP);

return names;
}

/// <summary>
/// !!! Method not implemented !!!
/// </summary>
/// <param name="value"></param>
/// <param name="targetType"></param>
/// <param name="parameter"></param>
/// <param name="culture"></param>
/// <returns></returns>
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
using System;
using System.Globalization;
using System.Windows.Data;
using NETworkManager.Localization.Resources;
using NETworkManager.Models.Network;

namespace NETworkManager.Converters;

/// <summary>
/// Convert the <see cref="IPScannerHostChange" /> of a host (since the previous scan) to a translated
/// <see cref="string" /> (e.g. "New").
/// </summary>
public sealed class IPScannerHostChangeToStringConverter : IValueConverter
{
/// <summary>
/// Convert the <see cref="IPScannerHostChange" /> of a host to a translated <see cref="string" />.
/// </summary>
/// <param name="value">Change of the host as <see cref="IPScannerHostChange" />.</param>
/// <param name="targetType"></param>
/// <param name="parameter"></param>
/// <param name="culture"></param>
/// <returns>Translated change, empty if there is none.</returns>
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
return value is IPScannerHostChange change ? ToLocalizedString(change) : string.Empty;
}

/// <summary>
/// Gets the translated change of a host.
/// </summary>
/// <param name="change">Change of the host.</param>
/// <returns>Translated change, empty for <see cref="IPScannerHostChange.None" />.</returns>
public static string ToLocalizedString(IPScannerHostChange change)
{
return change switch
{
IPScannerHostChange.New => Strings.HostChange_New,
IPScannerHostChange.Gone => Strings.HostChange_Gone,
IPScannerHostChange.MACChanged => Strings.HostChange_MACChanged,
_ => string.Empty
};
}

/// <summary>
/// !!! Method not implemented !!!
/// </summary>
/// <param name="value"></param>
/// <param name="targetType"></param>
/// <param name="parameter"></param>
/// <param name="culture"></param>
/// <returns></returns>
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}
Loading
Loading