Skip to content

SmartInventory Web UI — Splicing/Connectivity, OLT Patching & Entity Attribute Forms

Source-grounded documentation of three data-dependent screens that are hard to reach in the live demo (which has no loaded project data at the demo extent). Authoritative source = the repo references/SmartInventory-3.0/Source/SmartInventory/, cross-referenced to the live demo (http://networkaccess.st.leptonsoftware.com, product v8.16.4.0, admin login) and to docs/database/04-isp-ports-splicing-connectivity.md. READ-ONLY exploration — no form was ever submitted, no Save/Delete/Update clicked, no DB row mutated.

Repo paths below are relative to Source/SmartInventory/ unless noted. The repo (branded “SmartInventory-3.0”) and the live demo differ slightly in version/customer config; where they diverge it is called out. Some controller line numbers cited by automated tracing are approximate — file paths, action/JS/view names, endpoints, fn_* names and DB tables are verified.


0. Shared conventions (apply to all three screens)

  • 3-layer flow: Controller (SmartInventory/Controllers/*.cs) → BusinessLogics/BL*.csDataAccess/DA*.cs → PostgreSQL fn_* stored procedure. UI is server-rendered Razor partial views loaded by jQuery AJAX into modals/panels. No SPA, no module bundler.
  • Two parallel web apps render splice/patch UIs from near-identical view trees: the main app SmartInventory/ and the mobile/API app SmartInventoryServices/ (its own Content/js/Splice/ and Views/Splicing/).
  • Global JS namespaces (verified live): si.* (735 functions — map, entities, info windows) and splicing.* (80 functions — splicing, patching, path-find). The splicing object is aliased app inside Splicing.js.
  • Connectivity is an explicit directed edge table connection_info (26,325 rows in QA), keyed by composite logical endpoints (entity_type, system_id, port_no) — not FKs. Traversal is procedural PL/pgSQL (temp-table cursor walk + final recursive CTE). See docs/database/04-isp-ports-splicing-connectivity.md for the full data-model analysis.

1. Splicing / connectivity diagram UI

1.1 What it is

A jsPlumb drag-to-connect port diagram. Confirmed live: splicing.createConnection() runs app.mainJSPlumb = jsPlumb.getInstance() and draws Bezier connectors between port DOM nodes. The bundled library is jsPlumb 1.4.1 (SmartInventory/Content/js/Splice/Js-Plumb-1.4.1.min.js); the SmartInventoryServices splice app additionally bundles html2canvas and canvg.min.js (SmartInventoryServices/Content/js/Splice/) to export the diagram to an image/PDF.

1.2 Entry point and the splice entity panel

The user activates the splice tool from the map toolbar (live: button title “Manual Splicing”onclick="splicing.spliceHere(this)"). When the map is zoomed in past level 18 and the user clicks a location, splicing.initiateSplicing(e) fires:

ajaxReq('Splicing/Index', { latitude, longitude, bufferRadius }, ...) // splicing.initiateSplicing
  • Controller: SplicingController.Index(double latitude, double longitude, double bufferRadius)BLOSPSplicing.getEntityForSplicing(lat,lng,bufferRadius,role_id)PartialView("_Splicing", …).
  • DA → DB: DAOSPSplicingfn_splicing_get_entity(longitude, latitude, p_buffer_radius, p_role_id) (returns equipment within the buffer).
  • View: SmartInventory/Views/Splicing/_Splicing.cshtml — the splice entry panel. Live capture (splice-03-entitypanel.png) shows: two modes “Cable to Equipment” and “CPE to Customer”; a “Filter cables on device only” checkbox; Equipment / Left Cable / Right Cable pickers; a port-status legend (Selected / ISP Equipment / Virtual); and the Splice button.

1.3 The connection diagram (nodes & edges)

Choosing the source/destination opens the diagram via a POST to one of:

  • SplicingController.CableToCable(connectionInput)_CableToCable.cshtml (cable↔cable, or cable↔equipment).
  • SplicingController.ODFToCable(connectionInput)_ODFToCable.cshtml.
  • SplicingController.CPEToCustomer(connectionInput)_CPEToCustomer.cshtml (manual CPE→customer).

Which one is chosen is driven by the connecting entity’s capability flags, decided in JS (splicing.splicingWindow — verified live):

let _isMiddlewareEntity = $(... ':selected').attr('data-is-middleware-entity') == 'true';
if (_isMiddlewareEntity) { app.FMSSplicingWindow(); } else { app.cableToCableSplicing(); }

is_middleware_entity is a layer_details flag — in QA only FMS is middleware (see DB doc).

Visual NODES rendered in the diagram are ports, laid out as left/right columns:

  • Cables (.leftFiber / .rightFiber containers) decomposed to tube → core → fiber strand elements (.tube, .innerFiber/.otherEndFiber). A cable’s “ports” are fiber strands from att_details_cable_info (one row per cable/tube/core/fiber; ~1.0M rows in QA), carrying tube_color / core_color / fiber_usage_status / is_connected.
  • Equipment ports (ODF/FMS/Splitter/HTB/ONT/PatchPanel) from isp_port_info (port_number, input_output I/O, port_status_id).
  • Each port DOM node carries data-system-id, data-entity-type, data-port-no, data-is-connected, data-status-id, data-is-cable-a-end, data-network-id, data-link-id, and data-is-multiconnection. Port-id pattern: Left_<sysid>_CABLE_<core>, Right_<sysid>_CABLE_<core>, <sysid>_<TYPE>_<port>.

Edges (splices) are jsPlumb connectors:

  • Connected = teal #00ba8a; through-connection (straight pass-through, same core both sides) = grey #808080; vacant = grey. jsPlumb endpoints are Dot (radius ~3.5), connector = Bezier (curviness ~100), maxConnections: 1 per port.
  • splicing.InitilizeJsPlumb() adds endpoints to .src/.trg nodes; splicing.getConnections() reads existing connections from the rendered DOM (data-is-connected-to-same) and calls splicing.createConnection(sourceId, targetId) to draw them.

1.4 Tube / core color coding (12-color fiber standard)

Configured in the admin OSP settings, not hard-coded:

  • Admin/OSPSettings/TubeCoreColorSettings — grid Number | Color Character | Color, with a type selector of Tube / Core. This is the 12-color (Blue, Orange, Green, …) fiber position standard, editable per deployment.
  • Admin/OSPSettings/ViewCableMapColorSettings — per cable_type (Underground/Aerial/Overhead) × cable_category × fiber_count (2/6/12/24/48/96/144/192/288) color codes. The colors come back on the strands via att_details_cable_info.tube_color/core_color and are surfaced in the diagram (fn_get_schematic_view resolves color codes per hop).

1.5 Loading existing connections (read path)

  • List/grid: SplicingController.GetConnectionInfo(...)DAOSPSplicingfn_get_connection_info.
  • Splice diagram port+connection state: CableToCableBLOSPSplicing.getSplicingInfo(connectionInput, …)fn_splicing_get_connection. The action also loads the port-status legend via BLPortStatus().getPortStatus(), the available-port count via getAvailablePorts, and gates editing behind the EDS module permission (lstUserModule.Contains("EDS")).
  • Schematic / path view: SplicingController.SchematicView(...)DAOSPSplicingfn_get_schematic_view (478-line traversal: imperative edge-walk over connection_info into a CPF_TEMP_RESULT temp table, finished with a WITH RECURSIVE CTE in fn_getchildren_connection_info_path). View: Views/Splicing/SchematicView.cshtml (+ _EntityLogicalView.cshtml, _EntityLogicalViewDiagram.cshtml).

1.6 Creating a splice (save path — described, NOT executed)

  1. User drags a connector between two ports; splicing.crossConnect() / splicing.getConnectionsData() build connection objects (range-based bulk via splicing.spliceAll / splicing.cableToCableSplicing).
  2. JS posts the array to POST Splicing/SaveConnectionInfoSplicingController.SaveConnectionInfo(List<ConnectionInfoMaster> objConnectionInfo).
  3. BLOSPSplicing.SaveConnectionInfo(JsonConvert.SerializeObject(objConnectionInfo))DAOSPSplicing.DAConnectionInfofn_splicing_save_connections(p_connections := <json>) (405-line proc): validates (fn_validate_splicing), inserts into connection_info, and the fn_trg_update_core_port_status trigger flips att_details_cable_info.is_connected and isp_port_info.port_status. OSP/ISP cable-split re-pointing uses fn_splicing_save_osp_split_connection / fn_splicing_save_isp_split_connection.
  4. ConnectionInfoMaster fields: source_* / destination_* (system_id, entity_type, port_no, network_id), is_source_cable_a_end, equipment_system_id/equipment_entity_type, equipment_tray_system_id, is_through_connection, splicing_source (OSP_SPLICING / ISP_SPLICING / …).
  • Delete: Splicing/deleteConnectionfn_splicing_delete_connection.
  • Bulk upload: live splicing.toggleConnectionUpload() → modal Splicing/UploadConnection_UploadConnection.cshtml (Excel/CSV bulk splice import).

1.7 OSP vs ISP vs SpliceTray

PlantEntitiesView / JSsplicing_source
OSP spliceOutsideCable ↔ SpliceClosure (att_details_spliceclosure), FMS, ODF, distribution boxes (ADB/BDB/CDB), Cabinet_CableToCable.cshtml, _ODFToCable.cshtml; Splicing.js, OSPSplice.jsOSP_SPLICING / OSP SPLIT
ISP spliceInside (building)HTB / FDB / Splitter / ONT / PatchPanel in floor/shaft/roomISPSplice.js (jsPlumb on a room/building diagram), room-view/ConnectionBuilder.js, _ModelConnections.cshtmlISP_SPLICING
Splice trayEitherTrays inside a closure (att_details_splice_tray: parent_system_id→closure, tray_number, no_of_ports)SpliceTray.js; tray recorded on the edge via connection_info.source_tray_system_id/destination_tray_system_id (21,408/26,325 edges reference a tray)

1.8 FiberAllocationTool (FAT) and Connection Path Finder

  • FAT (auto-splice from geometry): Controllers/FiberAllocationToolController.csBLFATConnectionDAFATConnection. Commands call fn_fat_getconnection_details, fn_fat_generate_splicing (2,895-line proc — follows cables that spatially ST_INTERSECTS/snap to a feeding FDP/closure and auto-generates splices into fat_connection_info), and fn_fat_update_connection_status (Accept/Reset temp splicing). View: Views/FiberAllocationTool/_FAT_Allocation.cshtml. Live: the layer tree shows FAT as a layer (mapped from internal FDB).
  • Connection Path Finder: live toolbar “Connection Path Finder”splicing.SinglePathFind(value) opens modal Splicing/ConnectionPathFinder (_ConnectionPathFinder.cshtml); trace data from fn_get_connection_info_path. A separate “Common Path Finder”si.openLinkSearch(). Optical-link budget views: _OpticalLinkBudget.cshtml, _ViewLinkBudgetDetail.cshtml, _viewlossdetails.cshtml.

2. OLT Patching UI

2.1 What / where it is

In the live admin nav (/Products/Admin/...) “OLT Patching” is a top-level item with href="#" (a dynamic-module menu entry, no literal string in the repo source — it comes from the module_master/sub_module_master config tables, so the label is deployment-specific). It opens the equipment connection editor, which is served by the Splicing controller, not a dedicated OLT controller. (The repo has no OltPatching/OLTPatching controller; the live demo’s separate “Equipment Config” group — EquipmentModelConfig controller with ViewAttributeDefs / ViewSectionConfigs / Dependencies — is a newer addition not present in this repo snapshot.)

2.2 The patch editor (grid/matrix)

  • JS: SmartInventory/Content/js/room-view/ConnectionBuilder.js (object connectionBuilder, instantiated as conBuilder). It is jsPlumb-based (this.mainJSPlumb, InitilizeJsPlumb(), addEndPoint() adding endpoints to .src/.trg nodes filtered by data-is-multiconnection and data-status-id). Opens the editor via:
    ajaxReq('Splicing/ModelConnections', _data, ...) // ConnectionBuilder.js:870
    var dataURL = 'Splicing/ConnectionEditor'; // ConnectionBuilder.js:207 (and Splicing.js:2865)
    var dataURL = 'Splicing/FilterConnection'; // ConnectionBuilder.js:927
  • Controller: SplicingController
    • ConnectionEditor()PartialView("_ConnectionEditor", PatchingViewModel) — the editor shell.
    • FilterConnection(ConnectionFilter)getModelSplicingInfo(SourceEquipmentId, "Equipment", DestinationEquipmentId, "Equipment", isInsideConnectivity)_ConnectionEditor.
    • ModelConnections(ConnectionFilter) → same BL, returns _ModelConnections (the inner connection grid).
  • Views: Views/Splicing/_ConnectionEditor.cshtml (source/destination equipment dropdowns ddlSourcePort/ddlDestinationPortconBuilder.filterConnections(this,…); port-status legend; Save-as-PDF; Unlink-All; renders @Html.Partial("_ModelConnections", Model) for the matrix) and Views/Splicing/_ConnectionFilter.cshtml.
  • Live capture (olt-04-connectioneditor.png): the editor scaffold — “Select the equipment to view the connections” + Filter button. The port matrix renders only after two equipment units are selected (needs loaded equipment data — none in the demo extent).

2.3 What it patches & the port hierarchy

Patches OLT/equipment ports ↔ ODF / splitter / equipment ports (left equipment ports → right equipment ports, organized by the parent Chassis/Card). Ports come from isp_port_info (port_number, input_output, port_status_id, parent_system_id, parent_entity_type such as equipment/Splitter/PatchPanel; port_type includes ODFPORT, OpticalPort, PowerPort). Loaded via:

  • DAOSPSplicingfn_splicing_isp_model_get_connection(p_source_system_id, p_source_entity_type, p_destination_system_id, p_destination_entity_type, p_port_type) — the model-rule-aware patch matrix (applies the isp_model_* parent/child rules to decide which ports may legally connect).
  • Port list per equipment: fn_get_equipement_port(p_system_id, p_entity_type).
  • Export: fn_export_patching_report.

The equipment-model port hierarchy is Equipment → Chassis → Slot → Card → Port → Tray, defined in the Equipment Builder (live admin: Admin/Equipment/CreateModel, ViewModels). Model/port templates live in the isp_model_* catalogue (isp_model_info, isp_model_mapping, isp_model_rules, isp_model_type_master, isp_base_model, plus isp_template_*) and parent/child model_id rules; specifications seen live include “22 Port OLT”, “96 Port ODF”, “16 Port”, “Generic”. The placed-equipment instance lives in the att_details_model table; its ports in isp_port_info.

2.4 Port status (Is Splicing Allowed / Is Active / Is Manual)

The legend and per-port connectability come from the Core/Port Status master (live admin: Admin/Miscellaneous/ViewPortStatus — columns Status, Color Code, Is Active, Is Manual, Is Splicing Allowed), loaded by BLPortStatus().getPortStatus() and rendered into _ConnectionEditor.cshtml/_ModelConnections.cshtml. Each port node’s data-status-id controls whether jsPlumb lets it accept a connector (blocked statuses are non-droppable); status 1 = vacant. Saving a patch flips the port status (and, for cable strands, att_details_cable_info) via the fn_trg_update_core_port_status trigger.

2.5 Save path (described, NOT executed)

Patches are posted to Splicing/SaveConnectionInfoBLOSPSplicing.SaveConnectionInfo(json)fn_splicing_save_connections, writing rows to connection_info (same edge table as splices; the connection_info_master name some traces use is incorrect — the live table is connection_info). Delete = Splicing/deleteConnectionfn_splicing_delete_connection.


3. Entity attribute form (add / edit / info)

3.1 How it is built — schema-driven, two-part

The add/edit form is not hand-coded per entity. It is composed of (a) a per-entity Razor partial that lays out the fixed/known tabs, plus (b) a dynamic EAV section generated from the dynamic_controls table. Routing is data-driven from layer_details.

Live proof (NE Library DOM, entform-04-nelibrary.png + pass4 capture): every layer in the left “NETWORK LAYERS” / NE-Library tree carries its full add/edit contract as data-* attributes, e.g. for Pole:

data-lyrname="Pole" data-title="Pole" data-geomtype="Point" data-networkidtype="A"
data-istemplate="True" data-isdirectsave="False"
data-href="Library/AddPole" (= layer_details.layer_form_url)
data-save-url="Library/SavePole" (= layer_details.save_entity_url)

The full set captured live includes Pole, WallMount, Manhole, Building, Tree, Handhole, CDB, Cable(Line), Trench(Line), Duct(Line), Cabinet, Tower, ROW, CSA/SurveyArea(Polygon), Fault, Customer, and the equipment entities under their customer display labels that differ from the internal data-lyrname: FAT→FDB, Central_Office→POD, CPE→ONT, ATB→HTB, FDP→FMS, PDP→ADB, FDC→BDB. (This label/entity remapping is exactly the customer-spec relabeling driven by layer_details.)

3.2 The endpoints and JS that open the form

  • Open (JS): si.GetEntityAttrDetails(libItem) reads the data-* off the clicked library item; si.SetEntityAttributes(layerDetails) (from a layer_details object); si.CreateEntityFromInfo(_data) (re-create from an info window). These resolve layer_form_url / save_entity_url / is_direct_save / is_template_required and call popup.LoadModalDialog(..., pageUrl, ...). si.geomToForm(...) binds the drawn map geometry to the form. (Live: SetEntityAttributes('Pole') opens the dialog but it renders empty without a drawn geometry/system_id — the form is geometry-bound and needs project data.)
  • Controller action that RETURNS the form: <Controller>.Add<Entity>() returns PartialView("_Add<Entity>", model). Two controllers:
    • Controllers/LibraryController.cs — OSP/outdoor + most layers: AddPole/SavePole, AddCable/SaveCable, AddSpliceClosure, AddFMS, AddFDB, AddHTB, AddBuilding, AddManhole, etc. (URLs verified live from data-href/data-save-url).
    • Controllers/ISPController.cs — inside-plant entities (Splitter, BDB/ADB/CDB, Room, ONT, Customer, Rack, Equipment, OpticalRepeater).
    • Direct GET of Library/AddPole returns an Error page — these are POST-only partials requiring session form-state; they are only reachable through the JS add flow with a geometry. (Hence no clean blank-form screenshot — see §4.)
  • Info/edit on an existing feature: si.OpenElementInfoWindow / si.showElementInfo / si.ShowDetailFromInfo open the info window; edit reuses Add<Entity> partial pre-filled by system_id.

3.3 The dynamic field section (EAV)

  • Controller calls BLDynamicAttributes.GetDynanicControlsById(layer_id) (→ DADynamicAttributes, EF query on DbSet<DynamicControls> where entity_id == layer_id && is_visible, ordered by field_order) and GetDDLByControlsId(...) for dropdown options.
  • Model: Models/AdditionalAttributes.csDynamicControls (field_label, field_name, control_type, is_mandatory, is_visible, min_length, max_length, format, default_value, placeholder_text, control_css_class, field_order), DynamicControlsDDLMaster (control_id, value_text, display_text, is_default), and the view-model vm_dynamic_form (lstFormControls, lstFormDDLValues).
  • Partial (verified): Views/Shared/_AdditionalAttributesForm.cshtml renders a 2-column chunked layout, switching on control_type.ToUpper():
    • TEXT<input type=text> with minlength/maxlength/data-val-required.
    • DATETIME → readonly <input> + calendar picker (si.setDateTimeCalendar).
    • DROPDOWN<select> populated from lstFormDDLValues.Where(x => x.control_id == item.id); validated by fnValidateDropdownValue(...).
    • Mandatory fields marked <i class="clsMandatory">*</i>.
  • Tabs in the per-entity partial (_Add<Entity>.cshtml): GIS info, Item Spec (vendor/template), Port info (equipment), Barcode (if is_barcode_enabled), POD association, Additional Attributes (the EAV partial), Reference/attachments. Shared tab partials: _ProjectSpecification.cshtml, _OwnershipInfo.cshtml, _Reference.cshtml, _GeographicDetails.cshtml.

3.4 Field types, masters, barcode, attachments

  • Master dropdowns are populated from drop-down master tables (admin: Admin/Miscellaneous/DropDownMaster, ManageDropdownValues) and DynamicControlsDDLMaster.
  • Vendor-spec / template pickers: controlled by layer_details.is_vendor_spec_required and the live data-istemplate (= is_template_required). Bound via BLItemTemplate.Instance.BindItemDropdowns(model, entityType); fields specification, category, subcategory1..3, item_code, vendor_id, etc. Catalog admin: Admin/VendorSpecification/*, Admin/Template/*item_template_* tables.
  • Barcode: layer_details.barcode_column + is_barcode_enabled; helper in SmartInventory/Helper/ (barcode generator).
  • Attachments/photos: si.uploadDocumentFile / si.deleteEntityImage / downloadDocsFullParams.

3.5 network_status context (Planned / As-Built / Dormant)

Stored on each entity as network_status (single-char: P Planned / B As-Built / D Dormant). On save, DA<Entity> defaults it to "P" if empty. The form shows it via Utility.MiscHelper.GetNetworkStatus(network_status.ToUpper()), and edit permission is gated by status (Utility.MiscHelper.GetLayerEditPermission(system_id, …, network_status, …)) — e.g. As-Built may be locked from casual edits.

3.6 Save mapping

On submit, JS serializes the dynamic section to JSON into hidden #hdnOtherInfo (AdditionalAttributesUtility.SetJsonValue(...) in Content/js/Utility.js) and POSTs to the layer’s save_entity_url (e.g. Library/SavePole). <Controller>.Save<Entity>(model)BL<Entity>.Save<Entity>EntityDA<Entity> writes the fixed columns to att_details_<entity> (e.g. att_details_pole, att_details_spliceclosure, att_details_building) and stores the EAV blob in the entity’s other_info JSON column; masters resolve to item_template_* / drop-down master tables. The geometry is written to point_master / line_master.


4. Live capture attempt (read-only)

Re-logged in fresh (admin / Demo@2023/Products/main), enumerated si.* (735 fns) and splicing.* (80 fns), and exercised the JS entry points. No form was submitted; no Save/Delete/Update clicked. Screenshots saved under references/ui-exploration/shots/detail/. Capture scripts: capture_three_screens.py, capture_pass2.py, capture_pass3.py, capture_pass4.py, capture_pass5.py (findings JSON alongside).

ScreenCapturedWhat it shows
Splice entity panelsplice-03-entitypanel.pngReal _Splicing partial: Cable-to-Equipment / CPE-to-Customer modes, cable pickers, Selected/ISP-Equipment/Virtual legend, Splice button
Connection Path Findersplice-01-pathfinder.pngSplicing/ConnectionPathFinder modal (splicing.SinglePathFind)
Bulk Splicing uploadsplice-02-bulkupload.pngSplicing/UploadConnection modal
OLT Patching editorolt-04-connectioneditor.pngReal _ConnectionEditor scaffold (“Select the equipment to view the connections” + Filter).
OLT Patching nav / adminolt-02-patching.png, olt-03-adminhome.pngAdmin nav showing top-level OLT Patching (href="#"), Equipment Builder, Core/Port Status
NE Library / layer treeentform-04-nelibrary.png (+ entform-01/02, ne-01-library.png)Left “NETWORK LAYERS” tree = the add-entity palette; full data-href/data-save-url/data-istemplate contract per layer read from the DOM

Unreachable live (and why):

  • The fully-rendered jsPlumb splice diagram (cores connected to ports): needs a real cable+equipment pair with ports; the demo has no project data at the demo extent (Select-All loaded no WMS feature tiles), so the diagram body renders empty. The entry panel was captured; the diagram structure is documented from _CableToCable.cshtml/Splicing.js.
  • The OLT patch matrix populated with ports: same reason — _ConnectionEditor shows only the “select equipment” prompt; no equipment models exist to select. Scaffold captured.
  • The populated entity add/edit form: Library/Add<Entity> is a POST-only partial bound to a drawn geometry/system_id; calling si.SetEntityAttributes('Pole') opens an empty dialog (no geometry), and a direct GET returns an Error page. The form’s exact field set is documented from _AdditionalAttributesForm.cshtml + layer_details + the live data-* contract instead.

5. Implications for the new platform

  1. Replace the jsPlumb-over-Razor splice editor with a real graph-backed splice editor. Today the diagram is reconstructed in the browser from server-rendered DOM nodes whose connectivity is re-derived (getConnections() reads data-is-connected-to-same), and persisted through a 405-line fn_splicing_save_connections + a trigger that mutates two other tables. The new platform should drive the editor directly off a typed (node, edge) graph: ports are first-class nodes (cable strand = att_details_cable_info granularity preserved), splices are edges with provenance (splicing_source, fat_process_id), and the editor reads/writes the graph API rather than HTML. Keep the through-connection and A/B cable-end concepts as edge metadata.
  2. Model ports/patching as a typed component+port template system. The Equipment→Chassis→Slot→Card→Port→Tray hierarchy and the isp_model_* parent/child rules are sound config-driven concepts — carry them forward as a component/port-template catalogue, but enforce port direction (I/O), capacity, and “splicing allowed” as constraints, not the current free-varchar port_status + function-only checks. OLT patching and OSP splicing should be one connection model with different endpoint types, not two parallel code paths (ConnectionEditor vs _CableToCable) over the same connection_info table.
  3. Make the entity form genuinely schema-driven and decouple it from .cshtml partials. The good bones already exist: layer_details (form URL, save URL, flags) + dynamic_controls EAV + _AdditionalAttributesForm.cshtml. But fixed fields still live in ~40 hand-written _Add<Entity>.cshtml partials, EAV values are dumped into an opaque other_info JSON blob, and labels are remapped per customer in layer_details. The rewrite should serve one schema endpoint returning a full field manifest (fixed + dynamic, types, validation, masters, vendor/template pickers, barcode, attachments, network_status rules) and render it with a single generic form renderer — eliminating per-entity views and the JSON-blob round-trip, while keeping network_status (Planned/As-Built/Dormant) as a first-class lifecycle attribute with edit-gating.

Appendix — key source paths

  • Splicing JS: SmartInventory/Content/js/Splicing.js, OSPSplice.js, ISPSplice.js, SpliceTray.js; Content/js/room-view/ConnectionBuilder.js, EquipmentEditor.js, rack-manager.js, room-manager.js; Content/js/Splice/Js-Plumb-1.4.1.min.js. API app: SmartInventoryServices/Content/js/Splice/ (Js-Plumb-1.4.1, html2canvas.js, canvg.min.js).
  • Splicing views: SmartInventory/Views/Splicing/ (_Splicing, _CableToCable, _ODFToCable, _CPEToCustomer, _ConnectionEditor, _ConnectionFilter, _ModelConnections, _ConnectionPathFinder, SchematicView, _OpticalLinkBudget, _UploadConnection, _ViewPortHistory, …). FAT: Views/FiberAllocationTool/_FAT_Allocation.cshtml.
  • Controllers: Controllers/SplicingController.cs (Index, CableToCable, ODFToCable, CPEToCustomer, SaveConnectionInfo, deleteConnection, ConnectionEditor, FilterConnection, ModelConnections, SchematicView, GetConnectionInfo), Controllers/FiberAllocationToolController.cs, Controllers/LibraryController.cs, Controllers/ISPController.cs.
  • BL/DA: BusinessLogics/BLOSPSplicing.cs, BLFATConnection.cs, BLSpliceTray.cs, BLDynamicAttributes.cs, BLPortStatus.cs/BLMisc.cs; DataAccess/DAOSPSplicing.cs, DAFATConnection.cs, DADynamicAttributes.cs.
  • Entity form: Views/Shared/_AdditionalAttributesForm.cshtml, Views/ISP/_Add*.cshtml, Models/AdditionalAttributes.cs, Content/js/Utility.js (AdditionalAttributesUtility), Content/js/ISP.js, Content/js/DynamicForms/dynamic.js.
  • DB: connection_info, fat_connection_info, att_details_cable_info, isp_port_info, att_details_spliceclosure, att_details_splice_tray, att_details_patchpanel, att_details_model, isp_model_*, item_template_*, att_details_<entity>, layer_details, dynamic_controls, dynamic_controls_dropdown_master. Procs: fn_splicing_get_entity, fn_splicing_get_connection, fn_get_connection_info, fn_get_schematic_view, fn_get_connection_info_path, fn_splicing_isp_model_get_connection, fn_get_equipement_port, fn_splicing_save_connections, fn_splicing_delete_connection, fn_validate_splicing, fn_trg_update_core_port_status, fn_fat_generate_splicing, fn_fat_getconnection_details, fn_fat_update_connection_status, fn_export_patching_report.