From 53b15e3e4147a2146daad1f6c907dfd1b48a1d49 Mon Sep 17 00:00:00 2001 From: Elliott Balsley <3991046+llamafilm@users.noreply.github.com> Date: Tue, 9 Sep 2025 19:07:17 -0700 Subject: [PATCH 1/4] add global search hotkey --- netbox/project-static/dist/netbox.js | Bin 382999 -> 383349 bytes netbox/project-static/dist/netbox.js.map | Bin 1773948 -> 1775252 bytes netbox/project-static/src/hotkeys.ts | 28 +++++++++++++++++++++++ netbox/project-static/src/netbox.ts | 2 ++ 4 files changed, 30 insertions(+) create mode 100644 netbox/project-static/src/hotkeys.ts diff --git a/netbox/project-static/dist/netbox.js b/netbox/project-static/dist/netbox.js index 1f5e199d8e78425e2b7233f80d6fad1a4a9bd3e4..0da82721ccbd3755937a080bc4c74893d3944683 100644 GIT binary patch delta 8164 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 diff --git a/netbox/project-static/dist/netbox.js.map b/netbox/project-static/dist/netbox.js.map index 2d0c72c2dd6f92d0ad3a0e365857260d1e50dce0..18d8f79359fdcb76f4d34d860e77e8300d970d25 100644 GIT binary patch delta 1264 zcmZWp&uZL!nC5LI1UdN?3jXaOU=-8fEgqhOpAB8<>x{bFxe@20zJ zf`KR!Jw!rCT#(+qhu$hxsw!7K@E;)c&7vPp>H!na5?lxQiZ9zK=+n&`8 zDvq~hI(1?CR+}~4{c{bs;cjI*4tCy|##_KrJ4$=eg z{D{!;nx+Fb26hFG4`6RYKGH0Prr#1Fm;scdv_i3ChE`hyc})$;AQZQeB}|5GI>HLI z!XVtcC*8LLS;_uNrpA^2aT3=GvUWZ(cPjc~ZPRT!XjbXJZ+A`2QN#_ou1ujmj>RmM zC^!C?$ff||SY96JV_6BA@uB2$v{~}un{*+I3gnB%VrJ}9;hcQ>GF|%h&&-blpWB^X z&kx})x@w1UHtfT;?{z>cF2okf6R*>={Re}YZejwBc}G2bHIzZjB0fTVjQ9j`6p`(} z8p{1PaBxQFY=!gHE3CqKU@(IlCk={J4OZsHC47`Qt8-pgyc0Sxwp4&woVN_Nr*poi z6ZuY=t)dhi9i7!UuSM^tk#Sljo}mJYNLxG;I zE~Cm-q_GXoH=@@~&Nr#*LItxbOKKpcyK#|{YL!S4k90D=)M>(%Zx&hkDpeAk3yS*~ z$I>-Ae@hLmDS2gwr}}q{sGyAv**bM_Wtmb;a%Fds8OC~K){6W+nd`}^k=!t#+7d~Y zcgQ7d9F^DU5m9gU>m#|HM8Z9MGMei@8J+uV_)`3zm}fBm!7qS<(Qd^XLjkpv?{0iL UzPAYdzo+KDO8mcnlQVPfzcdz=`~Uy| delta 209 zcmbQTHs{ZxoDEIt&C}J}r>ippF%u9o12GE_vjQ<25VHd@2M}`tF&7YX12GQ}^8zs+ z5c31E01yjqpRO(>cXRsuEnJ-2&oK*MWZHg`O}Le@J%K|Qh(&-{6o|!uSR9BYfLL;S z0*BOQCXOgaonS}D;PC00JW`d@xogBZ#WS3ATpb;~b(|etLqG&XMdo%6Ua2fb#+>$I YKB?`+e9|gx+h2=Fn=nq-6O&E@09ipnz5oCK diff --git a/netbox/project-static/src/hotkeys.ts b/netbox/project-static/src/hotkeys.ts new file mode 100644 index 000000000..9764fba97 --- /dev/null +++ b/netbox/project-static/src/hotkeys.ts @@ -0,0 +1,28 @@ +const HOTKEYS: Record void> = { + '/': focusGlobalSearch, +}; + +function focusGlobalSearch(): void { + const searchInput = document.querySelector('header input[name="q"]')!; + searchInput.focus(); + console.debug('Focused global search input'); +} + +function handleKeydown(event: KeyboardEvent): void { + // Ignore hotkeys when focused on form elements or when modal is open + if ((event.target as Element).matches('input, textarea, select') || document.body.classList.contains('modal-open')) { + return; + } + + const handler = HOTKEYS[event.key]; + if (!handler) { + return; + } + + event.preventDefault(); + handler(); +} + +export function initHotkeys(): void { + document.addEventListener('keydown', handleKeydown); +} diff --git a/netbox/project-static/src/netbox.ts b/netbox/project-static/src/netbox.ts index ce0aad93f..68b77baee 100644 --- a/netbox/project-static/src/netbox.ts +++ b/netbox/project-static/src/netbox.ts @@ -14,6 +14,7 @@ import { initDashboard } from './dashboard'; import { initRackElevation } from './racks'; import { initHtmx } from './htmx'; import { initSavedFilterSelect } from './forms/savedFiltersSelect'; +import { initHotkeys } from './hotkeys'; function initDocument(): void { for (const init of [ @@ -33,6 +34,7 @@ function initDocument(): void { initRackElevation, initHtmx, initSavedFilterSelect, + initHotkeys, ]) { init(); } From 03a6032f36b715fd93618b577ff0ff1c2b44479d Mon Sep 17 00:00:00 2001 From: Elliott Balsley <3991046+llamafilm@users.noreply.github.com> Date: Sat, 13 Sep 2025 11:45:17 -0700 Subject: [PATCH 2/4] remove debug line --- netbox/project-static/dist/netbox.js | Bin 383349 -> 383304 bytes netbox/project-static/dist/netbox.js.map | Bin 1775252 -> 1775180 bytes netbox/project-static/src/hotkeys.ts | 1 - 3 files changed, 1 deletion(-) diff --git a/netbox/project-static/dist/netbox.js b/netbox/project-static/dist/netbox.js index 0da82721ccbd3755937a080bc4c74893d3944683..12c48b79e32619128fdd9af6ff4379ab02ac85ac 100644 GIT binary patch delta 25 hcmeymN&Lhn@rD-07N!>F7M3ln2QP1bcbT=F6#$j53qSw> delta 70 zcmX@HN&M?3@rD-07N!>F7M3ln2QTaBBR=j10P a<|q`WCKe@UC}idpl$I!MKX93~gB1YQI~zX$ diff --git a/netbox/project-static/dist/netbox.js.map b/netbox/project-static/dist/netbox.js.map index 18d8f79359fdcb76f4d34d860e77e8300d970d25..e38efc5943588ae0d296ded1d8338817dd9483b4 100644 GIT binary patch delta 104 zcmbQTHs{QmoQ4+07N!>F7M2#)7Pc1l7LFFq7OocV7M>Q~7QPn#7J(MQ7NIS|3mMxl zF$x2*2oQ?`u^14G1F-}UOK!i!C^eOn)!EUxz-f9jx70nxp!OslsqINT(neeWRFxt* delta 173 zcmX@JCTGgpoQ4+07N!>F7M2#)7Pc1l7LFFq7OocV7M>Q~7QPn#7J(MQ7NIS|3mJ74 z6q57vit}?)^-@xkO4Bve-SU%5i&Ik+(sS~Y5_1%aQxl7lGZZrO3Q9}V+vhS01F;AY zivqD25Q_t`1Q1JZpUWsUlT*gk(K*LSC(zL`P{-HN(O1XJ$ void> = { function focusGlobalSearch(): void { const searchInput = document.querySelector('header input[name="q"]')!; searchInput.focus(); - console.debug('Focused global search input'); } function handleKeydown(event: KeyboardEvent): void { From f2097cce3309fd544744616741dbadf6a132ae8f Mon Sep 17 00:00:00 2001 From: Elliott Balsley <3991046+llamafilm@users.noreply.github.com> Date: Tue, 16 Sep 2025 20:05:35 -0700 Subject: [PATCH 3/4] no search at login page --- netbox/project-static/dist/netbox.js | Bin 383113 -> 383429 bytes netbox/project-static/dist/netbox.js.map | Bin 1775270 -> 1776570 bytes netbox/project-static/src/hotkeys.ts | 4 +++- 3 files changed, 3 insertions(+), 1 deletion(-) diff --git a/netbox/project-static/dist/netbox.js b/netbox/project-static/dist/netbox.js index b6f1b04c32e3bbaf328808393406fd5ce90982d7..3f72ff62b307428a488303d7a592a9fe53ca7ac1 100644 GIT binary patch delta 8171 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 A`2YX_ diff --git a/netbox/project-static/dist/netbox.js.map b/netbox/project-static/dist/netbox.js.map index 0b26ddca2d416d5dc6c85ad55a1e1ddc20091d9e..4092398724eee4b9efc79b529cd3e7ffe97f7a2f 100644 GIT binary patch delta 1201 zcmZWoK~EDw6i%T?Z7HBtphc6Rm+dBF(WsFqm`s;an$ln?XwVw7ZU?%hoyFZnY?Ki7 zK>Pt_ZblR1%|tIY!GrPa$)hn|J?c#pFZyP7l@br%X7-!!z4yJhZ(qD@?6w=P9w@yv z%Uz=_=b@|YxJm%f1?UC@0X={NfL=fda1am%L;!t&D4-uO02l-uYP-teu`gA_VvdVu z=NAjv;yDw?{8Zd+#cBAP;XD-0oJTse*iwz9zt*R)utgl~TeCnAm%=Gpp&%kMuw9OvrSNNi52QN2oSWD5Qo)0=dv zlDt((URTsHNQjWRf>Ir!s^JJfZ)~N51R*|%8HxX^nCdeIR*`AAr?qo(N>QYe@3S!7hY!I@l z;mr&on;8*UpCOP@gC}T~aS=*DWY!h&enJfd+r*Gr&PcvKEnF02OcBo$(#+rzAtl^` zyseD9^vV@LhL;Fg@?Muk4X8SvgQ(n$>`3NaniD~#yl_zz$DELz&4>o_bJKWP@{|xN zcpG>iO5%K37@e2tWw(~>yrFpoO)z9;go7)yB19KsS)az5cG;U&p1CWAv0TF{0LbfKrn5NWo#ASWOS=FWs@=Q void> = { function focusGlobalSearch(): void { const searchInput = document.querySelector('header input[name="q"]')!; - searchInput.focus(); + if (searchInput) { + searchInput.focus(); + } } function handleKeydown(event: KeyboardEvent): void { From a4f0b76cb52610f966b253bdea2aa08ba0bf0214 Mon Sep 17 00:00:00 2001 From: Jeremy Stretch Date: Wed, 17 Sep 2025 12:31:11 -0400 Subject: [PATCH 4/4] Closes #20367: Document best practices for modeling SFPs (#20377) --- .../modeling-pluggable-transceivers.md | 74 +++++++++++++++++++ mkdocs.yml | 2 + 2 files changed, 76 insertions(+) create mode 100644 docs/best-practices/modeling-pluggable-transceivers.md diff --git a/docs/best-practices/modeling-pluggable-transceivers.md b/docs/best-practices/modeling-pluggable-transceivers.md new file mode 100644 index 000000000..fe05ab546 --- /dev/null +++ b/docs/best-practices/modeling-pluggable-transceivers.md @@ -0,0 +1,74 @@ +# Modeling Pluggable Transceivers + +## Use Case + +Many network devices utilize field-swappable [small-form factor pluggable transceivers (SFPs)](https://en.wikipedia.org/wiki/Small_Form-factor_Pluggable) to enable changing the physical media type of a fixed interface. For example, a 10 Gigabit Ethernet interface might be connected using copper, multimode fiber, or single-mode fiber, each of which requires a different type of SFP+ transceiver. + +It can be challenging to model SFPs given their dynamic nature. This guide intends to capture the recommended strategy for modeling SFPs on NetBox v4.4 and later. + +## Modeling Strategy + +Pluggable transceivers are most accurately represented in NetBox as discrete [modules](../models/dcim/module.md) which are installed within [module bays](../models/dcim/modulebay.md). A module can deliver one or more [interfaces](../models/dcim/interface.md) (or other components) to the device in which it is installed. This approach ensures that a new interface is automatically created on the device when the module is installed, and deleted when the module is removed. + +```mermaid +flowchart BT + interface1[Interface 1/1]--> module1[SFP] + interface2[Interface 2/1]--> module2[SFP] + interface3[Interface 3/1] & interface4[Interface 3/2]--> module3[SFP] + module1 --> modulebay1[Module Bay 1] + module2 --> modulebay2[Module Bay 2] + module3 --> modulebay3[Module Bay 3] + modulebay1 & modulebay2 & modulebay3 --> device[Device] +``` + +### 1. Create an SFP Module Type Profile + +If one has not already been defined, create a [module type profile](../models/dcim/moduletypeprofile.md) for SFPs. This profile will be assigned for all module types which represent a pluggable transceiver. Typically, you will need only one profile for all pluggable transceivers. + +You might opt to define custom attributes for the profile by defining a custom [JSON schema](https://json-schema.org/). Profile attributes might be used to define characteristics unique to transceivers, such as optical wavelength and power ranges. Adding profile attributes is optional, and can be done at a later point. + +!!! note + Creating a module type profile is optional, but recommended as it allows for defining custom module attributes. + +### 2. Create a Module Type for Each SFP Model in Inventory + +Next, create a [module type](../models/dcim/moduletype.md) to represent each unique SFP model present in your network. Each module type should define a manufacturer and a unique model name, and may also include a part number. For example, you might create a module type for each of the following transceivers: + +| Manufacturer | Model | Media Type | +|--------------|------------------|------------| +| Cisco | SFP-10G-SR | 10GE MMF | +| Cisco | SFP-10G-LR | 10GE SMF | +| Juniper | QFX-QSFP-40G-SR4 | 40GE MMF | +| Juniper | JNP-QSFP-DAC-5M | 40GE DAC | + +### 3. Add an Interface to the Module Type + +After creating each module type, create an interface template on it to represent its physical interface. The definition of this interface template will depend on the transceiver's physical media type. (Reference the table above for examples.) When a new module is "installed" within a module bay on a device, its templated interface(s) will be automatically instantiated on that device as child interfaces of the module. + +Determining which name to use for the transceiver's interface can be tricky, as the interface name might depend on the type of device in which the SFP is installed. To avoid having to rename interfaces, consider using the `{module}` token in place of a static interface name. The interface's name will inherit the position of the bay in which its parent module is installed. If creating multiple interfaces on a module, be sure to append a unique ID (e.g. `{module}:1`) to ensure each interface gets assigned a unique name. + +### 4. Create Device Types + +If you haven't already, create a [device type](../models/dcim/devicetype.md) to represent each unique device model in your network. + +!!! note + Skip this step if you've already created the necessary device types. + +### 5. Add Module Bays to the Device Type + +Once you've created a device type, add the appropriate number of module bays on each device type to represent its SFP slots. For example, a Juniper QFX5110 would have module bays numbered `0/0/0` through `0/0/55`: 48 SFP+ bays and 8 QSFP28 bays (56 total). + +Be sure to define both the name **and position** of each module bay with a unique value. The module bay's position will be used to automatically name SFP interfaces. + +### 6. Create a Device + +Create a new device using the device type added in the previous step. The module bays (and any other components) defined on the device type will be instantiated on the new device automatically. + +!!! note + If you've already created the necessary devices in NetBox, you'll need to add their module bays manually. You can add multiple module bays at once by selecting the desired devices from the device list and selecting **Add Components > Module Bays** at the bottom of the page. + +### 7. Add the SFP Modules + +Finally, create each SFP in the new device by "installing" a new module of the appropriate type in each module bay. The interface(s) defined on the selected module type will be automatically populated on the new module. If present, the `{module}` token in the name of each interface template will be replaced with the position of the bay in which the module is being installed. For example, an interface template with the name `et-{module}` being created on a module installed in a bay with position `0/0/14` will create an interface named `et-0/0/14`. + +When adding many modules at once, you may find it helpful to utilize NetBox's bulk import functionality. This allows you to create many modules at once from CSV, JSON, or YAML data. diff --git a/mkdocs.yml b/mkdocs.yml index d8524e593..ece0f6e3d 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -124,6 +124,8 @@ nav: - Export Templates: 'customization/export-templates.md' - Reports: 'customization/reports.md' - Custom Scripts: 'customization/custom-scripts.md' + - Best Practices: + - Modeling Pluggable Transceivers: 'best-practices/modeling-pluggable-transceivers.md' - Integrations: - REST API: 'integrations/rest-api.md' - GraphQL API: 'integrations/graphql-api.md'