Skip to content

Latest commit

 

History

History
455 lines (398 loc) · 23 KB

File metadata and controls

455 lines (398 loc) · 23 KB

Changelog

All notable changes to netbox-osp are documented here. The format follows Keep a Changelog and this project adheres to Semantic Versioning.

Per-release NetBox / Python compatibility lives in COMPATIBILITY.md.

0.3.8 — 2026-05-19

Fixed

  • "Trace this core" button no longer appears twice on the Strand detail page. v0.3.7 wired the plugin_right_page slot into strand.html, which made the StrandTraceButton PluginTemplateExtension fire — but the template also kept the pre-v0.3.1 inline {% include 'netbox_osp/inc/trace_button.html' %} workaround, so the button rendered twice. Removed the inline include; the extension is now the single source of truth.

0.3.7 — 2026-05-19

Three audit fixes bundled together.

Fixed

  • Brown strand colour badges now render in actual brown. TIA-598 position 4 is Brown; NetBox doesn't ship text-bg-brown in its badge palette so the class fell through to a near-black default. Added an explicit CSS override (#8b4513 saddle brown) so a Brown strand looks brown on the strand list, tube list, and detail pages.
  • Strand detail page Colour badge now uses the helper. The strand.html template called {% badge object.get_color_display %} without bg_color, so even though v0.3.5 added the get_color_color() helper, the detail page kept rendering Colour as grey. Now passes bg_color=object.get_color_color and matches the list-view colour fidelity.
  • strand.html and trunkbreakout.html now render plugin template-extension slots. v0.3.1 wired {% plugin_left_page %} / {% plugin_right_page %} / {% plugin_full_width_page %} into the other custom OSP detail templates, but the strand and trunkbreakout templates were missed. Attachments, Documents, and any other plugin's per-object cards are now visible on these two pages.

0.3.5 — 2026-05-19

Fixed

  • TIA-598 strand colour badges now actually use their named colour. v0.3.4 added CSS overrides for text-bg-blue / text-bg-black / text-bg-white — but they had no effect because NetBox's ChoiceFieldColumn was rendering every TIA-598 colour as text-bg-secondary (grey). Root cause: neither Strand nor Tube defined a get_color_color() method, so the column couldn't look up the badge colour from TIA598ColorChoices. Added the helper on both models — colour codes now render in their actual colour (Blue is blue, Orange is orange, Brown is brown, etc.).

0.3.4 — 2026-05-19

Fixed

  • TIA-598 strand colour badges now legible on dark theme. NetBox's default palette desaturated blue to near-grey, black was invisible, and white rendered with poor contrast. Added explicit CSS overrides for .badge.text-bg-blue (vivid #1976d2), .badge.text-bg-black (#1a1a1a + light text + outline), and .badge.text-bg-white (light bg + dark text + outline). Strand colour codes are functional information — operators identify a fibre by its position colour — so badge fidelity matters. Overrides intentionally apply globally; boosting these three is a net improvement across all NetBox badges.
  • Core tracer hop nodes are easier to read. Bumped .osp-tracer-node min-width from 120 → 160 px, font-size 12 → 13 px, and increased the kind / meta sub-font sizes for better legibility at typical viewport widths.

0.3.3 — 2026-05-19

Fixed

  • FibreLink loss-budget gauge is now readable on dark theme. The prior gauge inlined the numeric readout inside the SVG at font-size: 5.5 viewBox units with a near-black fill (#1a1a1a) — effectively invisible on NetBox's dark theme. The numbers are now rendered as a bold <strong> outside the SVG, the percent appears as a coloured Bootstrap badge (text-bg-success / warning / danger matching the band), and the SVG is now a pure visual bar (~18px tall, full container width) with no text. A short legend underneath explains the thresholds. Long-standing UX bug spotted during the v0.3.x walkthrough.

0.3.2 — 2026-05-18

Fixed

  • MTP harness deploy form now exposes the polarity selector. v0.3.0 added a polarity ChoiceField to MtpHarnessForm but mtp_harness_deploy.html renders each field explicitly via {% render_field form.X %} rather than iterating the form, so the new field never appeared in the UI. Added {% render_field form.polarity %} between trunk_type and fibre_count so operators can pick the MPO polarity when deploying a harness.
  • Per-object detail-page maps now use the shared base-layer manager (spliceclosure.html, ospcable.html). The detail maps previously only fetched from the local MBTiles proxy, which bundles tiles for a Wheatstone bbox only — Perth-metro or any other location rendered as a blank dark canvas with just the marker pin. They now hook OspBaseLayers.attach(map, null, tileUrl) so they start on the preferred online layer and auto-fall-back to the bundled MBTiles after three tile errors, matching the main network map's behaviour. No dropdown UI is rendered (passing null skips the menu); operators get a working map at any geography out of the box. Pre-existing bug noticed during the v0.3.1 live-verify.

0.3.1 — 2026-05-18

Fixed

  • PluginTemplateExtension hooks now render on custom detail templates. v0.3.0 shipped two new PluginTemplateExtension classes (SpliceClosureQrCode, SpliceTrayQrCode) plus enabled third-party plugins like netbox-attachments to target our models — but our custom detail templates (spliceclosure.html, splicetray.html, fibretrunk.html, ospcable.html, fibrelink.html) override the content block of generic/object.html wholesale, which silently swallows the slot where NetBox renders plugin extensions. The Field QR code panel and the Attachments card never appeared. Each affected template now loads {% load plugins %} and renders {% plugin_right_page object %}, {% plugin_left_page object %}, and {% plugin_full_width_page object %} so any plugin's hooks fire. Note that netbox-osp[qrcode] users on v0.3.0 will see the QR panel only after upgrading to v0.3.1.

0.3.0 — 2026-05-18

Three-PR ecosystem sprint per the v0.3 moat plan §v0.3.0 quick wins. Two integrations + one operations feature; no breaking changes. Migration 0005_fibretrunk_polarity is additive and non-destructive.

Added

  • MPO polarity tracking on FibreTrunk — adds MpoPolarityChoices (Type A / B / C / D per TIA-568.3-D) and a new polarity CharField on FibreTrunk. Surfaced on the detail page (badge next to Type), table column, filter UI, REST API, REST bulk-import + bulk-edit, GraphQL filter, and the MTP harness one-click deploy wizard. Blank is permitted for non-MPO trunk types (Ribbon / Loose-tube) and unknown-polarity legacy data. Addresses NetBox core issue #5798 and the VIAVI "40 % of hyperscale downtime is fibre alignment / connector issues" stat. Migration 0005_fibretrunk_polarity is additive and non-destructive (empty-string default for existing rows).
  • Field QR codes on SpliceClosure and SpliceTray — two new PluginTemplateExtension classes (SpliceClosureQrCode, SpliceTrayQrCode) inject a Field QR code panel into the right-page area of closure / tray detail pages. The QR encodes the absolute URL of the page so a field tech can scan a printed closure label and land on the splice plan with attached photos. Uses the qrcode Python library's pure-Python SVG factory (no Pillow dependency). Install with pip install netbox-osp[qrcode]. The panel quietly hides on installs without the extra so the base install isn't affected. No PLUGINS_CONFIG changes required. See docs/integrations.md for rationale on why we use qrcode directly rather than wrapping netbox-qrcode (which hardcodes its supported model list at the class level).
  • netbox-attachments integration — documented scope_filter configuration for netbox-attachments covering all 10 OSP models (OspCable, Tube, Strand, Splice, SpliceClosure, SpliceTray, FibreLink, FibreTrunk, TrunkBreakout, LocationGeo). Operators can now attach OTDR .sor traces, splice photos, as-built PDFs, and acceptance-test certificates to any OSP record. Install with pip install netbox-osp[attachments]. Zero plugin code — pure composition via the upstream scope_filter setting. See docs/integrations.md. Sets up the file-storage layer that the upcoming v0.3.5 OTDR moat work will read .sor files from.

0.2.2 — 2026-05-18

Docs

  • README screenshots now use absolute raw.githubusercontent.com URLs so they render inline on the PyPI project page (relative docs/ paths in the previous releases pointed at files PyPI doesn't bundle).
  • Added an 8-step demo walkthrough at /demo/ on the docs site with 10 screenshots captured live from the public demo, covering the OSP model, splice closures, loss-budget gauge, MTP harness deploy form, visual core tracer, and the plant map.
  • README gains a "demo walkthrough" badge linking to the new page.
  • No code changes — pip install -U netbox-osp is metadata-only.

0.2.1 — 2026-05-14

Fixed

  • Visual core tracer (introduced in 0.2.0) rendered an empty Path graph because dagre-d3.min.js declares an external d3 dependency rather than inlining it. The loss-budget band and hop legend rendered fine but the graph itself stayed blank with "Renderer JS not loaded". Vendored d3.v5.min.js alongside the dagre-d3 bundle and added the <script> tag in strand_tracer.html ahead of dagre-d3.

0.2.0 — 2026-05-13

Five-PR cycle adding inter-rack fibre infrastructure: MPO/MTP trunks with breakouts to cassettes, one-click harness deploy, cassette device-type catalogue, and an end-to-end visual core tracer.

Added

  • FibreTrunk model — parent for multi-fibre rack-to-rack physical trunks (MPO/MTP 12/24/72-fibre, Ribbon 144-fibre, loose-tube indoor runs). Carries cid, trunk_type, fibre_count, manufacturer, length_m, status (reuses OspStatusChoices), GeoJSON route with show_on_map opt-out, description, comments, tenant, tags. DB-level CheckConstraint on fibre_count > 0 plus a form-friendly validation surfacing the same on the fibre_count field. New TrunkTypeChoices palette (mpo-12, mpo-24, mpo-72, ribbon-144, loose-tube-n, other) with a per-type DEFAULT_FIBRE_COUNT mapping ready for a follow-up auto-fill.

  • REST CRUD under /api/plugins/osp/trunks/ (full serializer, viewset, filter-set, router registration).

  • GraphQLosp_fibre_trunk and osp_fibre_trunk_list queries via the new FibreTrunkType / FibreTrunkFilter.

  • Admin chrome — list / add / edit / delete / bulk-edit / bulk-delete / bulk-import / changelog views, table with status + trunk-type colour columns, filter form, sidebar entry under a new "Trunks" group with Add + Import buttons, search-index registration.

  • Teststests/test_fibretrunk.py covering __str__, defaults, clean() (fibre_count guard and GeoJSON shape), tagging, REST CRUD with auth, and GraphQL module-level exposure.

  • TrunkBreakout through-table bridging FibreTrunk to NetBox's native dcim.Cable. Captures the trunk-with-breakouts pattern: operators express "24F MTP trunk → 12F breakout to rack A + 12F breakout to rack B" as one cohesive entity with the trunk identity preserved across child cables. Fields: trunk FK (CASCADE), cable FK (PROTECT), fibre_range_start / fibre_range_end (1-indexed PositiveSmallIntegerField), description, tags. CheckConstraints enforce start >= 1 and end >= start; two unique_together (trunk, cable and trunk, fibre_range_start) catch double-allocation. clean() rejects ranges that exceed parent fibre_count or overlap a sibling breakout — all field-keyed.

  • FibreTrunk.clean() now enforces sum of child-breakout ranges ≤ fibre_count (the PR-A # TODO(PR-B) marker is wired up).

  • FibreTrunk.fibres_used / fibres_remaining / fibres_utilization_pct computed properties feed the admin table's utilisation column.

  • "Import from cables" wizard at /plugins/osp/trunks/<trunk_id>/import-cables/ — multi-select unbound dcim.Cables and assign fibre ranges atomically. All-or-nothing via transaction.atomic(); surfaces both ValidationError and IntegrityError race-loser collisions as form errors.

  • REST + GraphQL for TrunkBreakout: CRUD at /api/plugins/osp/trunk-breakouts/, GraphQL osp_trunk_breakout and osp_trunk_breakout_list queries via FibreTrunkBreakoutType / FibreTrunkBreakoutFilter.

  • Admin chrome for TrunkBreakout — list / add / edit / delete / bulk-edit / bulk-delete / bulk-import / changelog views, table with parent-trunk + cable + range columns, filter form, "Trunk Breakouts" sidebar entry under the existing Trunks group, search-index registration.

  • CSV bulk importtrunk_cid,cable_label,fibre_range_start,fibre_range_end with friendly errors on ambiguous / missing cable labels.

  • Teststests/test_trunkbreakout.py (31 cases) covering model clean() field-keyed errors, unique_together enforcement, FibreTrunk utilisation arithmetic, REST CRUD with auth, GraphQL surface, and the import-cables wizard view (GET, POST happy path, POST validation failure). Import-form tests added to tests/test_imports.py.

  • MTP harness one-click deploy form at /plugins/osp/trunks/deploy-harness/ — a single form submit creates the parent FibreTrunk + N cassette dcim.Devices + N dcim.Cables linking the source patch-panel RearPort to each new cassette's RearPort + N TrunkBreakout rows binding the cables to the trunk at chosen fibre ranges. Atomic — the whole batch rolls back if any row fails validation. Two-step preview/confirm flow uses django.core.signing.dumps (base64-encoded, HTML-safe) to round-trip the cleaned form state safely between the preview and confirm POST steps with a 600s expiry. Sidebar entry under the existing "Trunks" group plus a green button on the FibreTrunk detail page next to "Add Breakout" / "Import from Cables". New plugin setting default_cable_type (default "smf"). Exception ladder mirrors PR B's import wizard: ValidationError → form-keyed errors, IntegrityError → race-condition message, AbortRequest → cable-path-impossible message. Tests in tests/test_mtp_harness.py cover GET auth, N=2 / N=3 happy paths, overlap rollback, missing-rack rollback, fibre-sum overflow, duplicate-rack rejection, preview-then-confirm round-trip, and permission denial.

  • Bundled cassette catalogue — five DeviceType JSON templates at netbox_osp/device_types/cassettes/ covering the standard MPO/MTP fibre-cassette and LC patch-panel shapes that pair with the MTP harness deploy form: mpo-12f-lc-cassette (1× MPO-12 rear → 12× LC), mpo-24f-lc-cassette (1× MPO-24 rear → 24× LC), mpo-12f-mpo-cassette (MPO pass-through), lgx-lc-12f-panel (1U LGX), ru1-lc-24f-panel (1U 24F with 2× MPO-12 rears). JSON follows the netbox-community/devicetype-library schema (hyphenated rear-ports / front-ports keys), so the same files import via the upstream loader too.

  • load_osp_cassettes management commandpython manage.py load_osp_cassettes seeds all five cassettes into the live DB. Idempotent (slug-keyed update_or_create), wraps each cassette in one transaction.atomic(), materialises RearPortTemplate + FrontPortTemplate + PortTemplateMapping rows with front-to- rear pin maps preserved. Ships a --dry-run flag for safe inspection.

  • Cassette teststests/test_cassettes.py covering JSON validity, required-key presence, cross-reference integrity (every rear_port referent exists, every rear_port_position is within bounds), management-command happy-path + idempotency contract, a spot check on the MPO-12F-LC port-template materialisation, and a forbidden-token guard so operator-site names never bake into the generic catalogue.

  • Visual core tracer (PR E) — click "Trace this core" on a Strand, dcim.FrontPort, or dcim.Interface detail page to render an end-to-end fibre path as a clickable dagre-d3 graph. Each hop — interface, patch cord, cassette pass-through, MPO/MTP trunk, splice, OSP strand — shows inline loss + length; the summary band above the graph shows total dB used against the strand's parent FibreLink budget (or a configurable default), colour-coded ok / warn / fail. New JSON endpoint at GET /api/plugins/osp/cores/<strand_id>/trace/ returns the hop list for external tooling. dagre-d3 v0.6.4 (~700 KB minified) ships vendored in static/netbox_osp/js/dagre-d3.min.js. Three new PluginTemplateExtension subclasses inject the trace button onto dcim.Interface, dcim.FrontPort, and netbox-osp Strand detail pages. New optional config keys under PLUGINS_CONFIG["netbox_osp"]: default_cassette_loss_db (0.5), default_patch_cord_loss_db (0.1), default_loss_budget_db (8.0). Zero new migrations — the tracer is read-only over the existing data model. Tests in tests/test_core_tracer.py cover the JSON endpoint, the full-page HTML view, splice-chain walking, loss-math summation, the "incomplete" flag, and the trace-button template integration.

Notes for upcoming v0.2 PRs

  • PR E — visual core tracer.

The 0.2.0 release tag fires once all five v0.2 PRs land. This entry documents PRs A, B, C, D, and E. All five v0.2 features landed; v0.2.0 is ready to tag.

0.1.1 — 2026-05-13

Fixed

  • Corrected author / maintainer name in package metadata, PluginConfig, mkdocs.yml copyright, and the icon SVG copyright comment from "John McKenzie" to "John McKean". 0.1.0 shipped with the wrong spelling and PyPI does not permit re-uploading a published version, so this metadata-only patch ships the correction.

0.1.0 — 2026-05-13

First functional release. Covers the full OSP fibre data model, the interactive plant map with online + offline base layers, REST + GraphQL APIs, bulk-import / bulk-edit, plant-boundary validation, and per-Location GPS markers.

Added

  • Data modelOspCable, Tube, Strand, SpliceClosure, SpliceTray, Splice, FibreLink, FibreLinkStrand, LocationGeo with TIA-598-C auto-colours, capacity / utilisation accounting, and the fibre_count == tube_count × fibres_per_tube invariant enforced in clean().
  • Fibre-link loss budget — strand attenuation × length + per-splice loss + per-connector loss, with ok / warn / fail band against a configurable target. SVG gauge bar rendered on the FibreLink detail page.
  • Network map — full-screen Leaflet at /plugins/osp/map/, filterable by status, with 7 online base layers (OSM, HOT OSM, CartoDB Positron / Dark Matter, OpenTopoMap, CyclOSM, Esri World Imagery) plus a bundled offline MBTiles bundle. Auto-falls back to offline after three tile errors within five seconds. User's explicit choice persists across reloads via localStorage.
  • GeoJSON cable-route editor — leaflet-geoman drag-to-edit with the same base-layer machinery as the main map.
  • Plant-boundary trace tool — operator drags vertices to draw the plant outline; exports a [lon, lat] coordinate list for the plant_boundary setting.
  • Optional plant-boundary validation — set PLUGINS_CONFIG['netbox_osp'] ['plant_boundary'] and OspCable.clean() rejects any cable whose route falls outside the polygon. Pure-Python ray-casting; no PostGIS required.
  • Per-Location GPS markers (LocationGeo) — 1:1 side-table on dcim.Location adding latitude / longitude / elevation_m / marker_color. Rendered as L.circleMarker overlay on the map and injected as a panel on the dcim.Location detail page.
  • Bulk-import / bulk-edit forms for Tube, Strand, Splice, SpliceTray, SpliceClosure, and LocationGeo — closes a ~300-click data-entry gap for a 288-strand cable.
  • GraphQL types for all nine plugin models via strawberry-django, registered with NetBox's /graphql/ endpoint.
  • REST API under /api/plugins/osp/... with full CRUD on every model, filter-sets aligned with the UI list views.
  • Offline-first tile proxy at /plugins/osp/tiles/<z>/<x>/<y>.<ext> serving PNG / JPEG / WebP tiles from one or more MBTiles files, with per-tile ETag + 304 Not Modified and transparent-PNG fallback for missing tiles.
  • Permission-matrix tests — auto-generated coverage of GET / list / create / edit / delete and their bulk variants for the SpliceClosure view set (canary; remaining seven models follow a known pattern).
  • MkDocs Material docs site at https://iamjohnnymac.github.io/netbox-osp/.

Infrastructure

  • Public GitHub repo with PyPI Trusted Publishing via OIDC (no API tokens).
  • CI matrix: Python 3.12 / 3.13 × NetBox 4.6 on Postgres 17 + Redis 7.
  • mkdocs.yml + GitHub Pages auto-deploy on every main push.
  • .pre-commit-config.yaml with ruff (lint + format), configured to match the NetBox plugin ecosystem.
  • Apache-2.0 license.

Known limitations

  • GraphQL schema registers cleanly but osp_<model>_list query fields don't surface in the merged global Query yet — being debugged against a live /graphql/ endpoint. REST API is fully functional in the meantime.
  • Permission-matrix tests cover the SpliceClosure canary; the remaining primary-object view sets will be added in a focused follow-up. REST APIViewTestCase permission tests are deferred until CI wires API_TOKEN_PEPPERS.

0.0.1 — 2026-05-13

  • PyPI name-reservation placeholder. Not functional.