diff --git a/docs/NETWORK_TREE.md b/docs/NETWORK_TREE.md index fe113845..e6914264 100755 --- a/docs/NETWORK_TREE.md +++ b/docs/NETWORK_TREE.md @@ -3,13 +3,15 @@ The **Network** page lets you map how devices connect — visually and logically. It’s especially useful for planning infrastructure, assigning parent-child relationships, and spotting gaps. +![Network tree details](./img/NETWORK_TREE/Network_Sample.png) + To get started, you’ll need to define at least one root node and mark certain devices as network nodes (like Switches or Routers). --- Start by creating a root device with the MAC address `Internet`, if the application didn’t create one already. -This is the only MAC currently supported as a root network node. -Set its **Type** to something valid in a networking context — for example: `Router` or `Gateway`. +This special MAC address (`Internet`) is required for the root network node — no other value is currently supported. +Set its **Type** to a valid network type — such as `Router` or `Gateway`. > [!TIP] > If you don’t have one, use the [Create new device](./DEVICE_MANAGEMENT.md#dummy-devices) button on the **Devices** page to add a root device. @@ -19,7 +21,7 @@ Set its **Type** to something valid in a networking context — for example: `Ro ## ⚡ Quick Setup 1. Open the device you want to use as a network node (e.g. a Switch). -2. Set its **Type** to one of the following: +2. Set its **Type** to one of the following: `AP`, `Firewall`, `Gateway`, `PLC`, `Powerline`, `Router`, `Switch`, `USB LAN Adapter`, `USB WIFI Adapter`, `WLAN` *(Or add custom types under **Settings → General → `NETWORK_DEVICE_TYPES`**.)* 3. Save the device. @@ -27,8 +29,6 @@ Set its **Type** to something valid in a networking context — for example: `Ro 5. Use the **Assign** button to connect unassigned devices to a network node. 6. If the **Port** is `0` or empty, a Wi-Fi icon is shown. Otherwise, an Ethernet icon appears. -![Network tree details](./img/NETWORK_TREE/Network_Sample.png) - > [!NOTE] > Use [bulk editing](./DEVICES_BULK_EDITING.md) with _CSV Export_ to fix `Internet` root assignments or update many devices at once. @@ -44,14 +44,12 @@ Let’s walk through setting up a device named `raspberrypi` to act as a network - Go to the **Devices** page - Open the device detail view for `raspberrypi` +- In the **Type** dropdown, select `Switch` ![Device details](./img/NETWORK_TREE/Network_Device_Details.png) -- In the **Type** dropdown, select `Switch` - -![Parent Node dropdown](./img/NETWORK_TREE/Network_Device_ParentDropdown.png) - -- Optionally assign a **Parent Node** (where this device connects to) and the **Relationship type** of the connection. The `nic` relationship type can affect parent notifications — see the setting description and [Notifications documentation](./NOTIFICATIONS.md) for more. +- Optionally assign a **Parent Node** (where this device connects to) and the **Relationship type** of the connection. + The `nic` relationship type can affect parent notifications — see the setting description and [Notifications documentation](./NOTIFICATIONS.md) for more. > [!NOTE] > Only certain device types can act as network nodes: @@ -64,24 +62,41 @@ Let’s walk through setting up a device named `raspberrypi` to act as a network ### 2. Confirm It Appears as a Network Node -- Go to the **Network** page +You can confirm that `raspberrypi` now acts as a network device in two places: + +- Navigate to a different device and verify that `raspberrypi` now appears as an option for a **Parent Node**: + +![Parent Node dropdown](./img/NETWORK_TREE/Network_Device_ParentDropdown.png) + +- Go to the **Network** page — you'll now see a `raspberrypi` tab, meaning it's recognized as a network node (Switch): ![Network page](./img/NETWORK_TREE/Network_Assign.png) -- You’ll now see a `raspberrypi` tab — it’s recognized as a network node (Switch) -- You can assign other devices to it +- You can now assign other devices to it. --- ### 3. Assign Connected Devices -- Use the **Assign** button to link other devices (e.g. PCs) to `raspberrypi` +- Use the **Assign** button to link other devices (e.g. PCs) to `raspberrypi`. +- After assigning, connected devices will appear beneath the `raspberrypi` switch node. ![Assigned nodes](./img/NETWORK_TREE/Network_Assigned_Nodes.png) -- Once assigned, devices will show as connected to the `raspberrypi` switch node -- Relationship lines may vary in color based on the selected Relationship type. These are editable on the device details. +- Relationship lines may vary in color based on the selected Relationship type. These are editable on the device details page where you assign a parent node. ![Hover detail](./img/NETWORK_TREE/Network_tree_setup_hover.png) -Happy with your setup? [Back it up](./BACKUPS.md). +> Hovering over devices in the tree reveals connection details and tooltips for quick inspection. + +--- + +## ✅ Summary + +To configure devices on the **Network** page: + +- Ensure a device with MAC `Internet` is set up as the root +- Assign valid **Type** values to switches, routers, and other supported nodes that represent network devices +- Use the **Assign** button to connect devices logically to their parent node + +Need to reset or undo changes? [Use backups](./BACKUPS.md) or [bulk editing](./DEVICES_BULK_EDITING.md) to manage devices at scale. You can also automate device assignment with [Workflows](./WORKFLOWS.md). diff --git a/front/css/app.css b/front/css/app.css index e3f7c8fa..ef7feb7c 100755 --- a/front/css/app.css +++ b/front/css/app.css @@ -340,6 +340,11 @@ body width: 100%; } +.networkTable .nav-tabs-custom +{ + margin-bottom: 0px; +} + .pa-small-box-2 .inner h3 { margin-left: 0em; margin-bottom: 1.3em; @@ -1785,6 +1790,16 @@ input[readonly] { /* margin-left: 0.2em; */ } +.networkNodeTabHeaders .icon i +{ + padding-top: 8px !important; + padding-left: 6px !important; +} + +.networkTable .box-body { + padding-top: 5px; +} + .networkTable .networkNodeTabHeaders a { display: block; height: 3em; @@ -1813,6 +1828,8 @@ input[readonly] { text-wrap: nowrap; } + + @media (max-width: 767px) { .networkNodeTabHeaders .node-name diff --git a/front/js/ui_components.js b/front/js/ui_components.js index fc7b63de..cd7da334 100755 --- a/front/js/ui_components.js +++ b/front/js/ui_components.js @@ -568,23 +568,23 @@ function getColumnNameFromLangString(headStringKey) { //-------------------------------------------------------------- // Generating the device status chip -function getStatusBadgeParts(tmp_devPresentLastScan, tmp_devAlertDown, macAddress, statusText = '') { +function getStatusBadgeParts(devPresentLastScan, devAlertDown, devMac, statusText = '') { let css = 'bg-gray text-white statusUnknown'; let icon = ''; let status = 'unknown'; let cssText = ''; - if (tmp_devPresentLastScan == 1) { + if (devPresentLastScan == 1) { css = 'bg-green text-white statusOnline'; cssText = 'text-green'; icon = ''; status = 'online'; - } else if (tmp_devAlertDown == 1) { + } else if (devAlertDown == 1) { css = 'bg-red text-white statusDown'; cssText = 'text-red'; icon = ''; status = 'down'; - } else if (tmp_devPresentLastScan != 1) { + } else if (devPresentLastScan != 1) { css = 'bg-gray text-white statusOffline'; cssText = 'text-gray50'; icon = ''; @@ -592,13 +592,13 @@ function getStatusBadgeParts(tmp_devPresentLastScan, tmp_devAlertDown, macAddres } const cleanedText = statusText.replace(/-/g, ''); - const url = `deviceDetails.php?mac=${encodeURIComponent(macAddress)}`; + const url = `deviceDetails.php?mac=${encodeURIComponent(devMac)}`; return { cssClass: css, cssText: cssText, iconHtml: icon, - mac: macAddress, + mac: devMac, text: cleanedText, status: status, url: url diff --git a/front/network.php b/front/network.php index 3cd00cc2..a7a0bdeb 100755 --- a/front/network.php +++ b/front/network.php @@ -2,476 +2,337 @@ require 'php/templates/header.php'; require 'php/templates/notification.php'; - - // online / offline badges HTML snippets - define('badge_online', '
Online
'); - define('badge_offline', '
Offline
'); - define('sortable_column', ' '); ?> + + - +
+ + + + + - - - -
+
+ +
- - - ' // _id is added so it doesn't conflict with AdminLTE tab behavior - .'
'.$decoded_icon.'
'.$node_name.'' .$str_port. - '
- '; - - echo $str_tab_header; - - } - - // Create pane content (displayed inside of the tabs) - function createPane($node_mac, $node_name, $node_status, $node_type, $node_ports_count, $node_parent_mac, $activetab){ - - // online/offline status circle (red/green) - $node_badge = ""; - if($node_status == 1) // 1 means online, 0 offline - { - $node_badge = badge_online; - } else - { - $node_badge = badge_offline; - } - - $idFromMac = str_replace(":", "_", $node_mac); - $idParentMac = str_replace(":", "_", $node_parent_mac); - $str_tab_pane = '
-
- -
- - - - - - - - - - - - - - - - - - - - - - - -
- '.lang('Network_Node').' - - - '.$node_name.' - -
- MAC - ' - .$node_mac. - '
- '.lang('Device_TableHead_Type').' - - ' .$node_type. ' -
- '.lang('Network_Table_State').' - ' - .$node_badge. - '
- '.lang('Network_Parent').' - - - - '.$node_parent_mac.' - - - -
-
- - '; - - $str_table = ' - - - - - - - - - - - - - '; - - // Prepare Array for Devices with Port value - // If no Port is set, the Port number is set to 0 - if ($node_ports_count == "") { - $node_ports_count = 0; - } - - // Get all leafs connected to a node based on the node_mac - $func_sql = 'SELECT devParentPort as port, - devMac as mac, - devPresentLastScan as online, - devName as name, - devType as type, - devLastIP as last_ip, - (select devType from Devices a where devMac = "'.$node_mac.'") as node_type - FROM Devices WHERE devParentMAC = "'.$node_mac.'" and devIsArchived = 0 order by port, name asc'; - - global $db; - $func_result = $db->query($func_sql); - - // array - $tableData = array(); - while ($row = $func_result -> fetchArray (SQLITE3_ASSOC)) { - // Push row data - $tableData[] = array( 'port' => $row['port'], - 'mac' => $row['mac'], - 'online' => $row['online'], - 'name' => $row['name'], - 'type' => $row['type'], - 'last_ip' => $row['last_ip'], - 'node_type' => $row['node_type']); - } - - // Control no rows - if (empty($tableData)) { - $tableData = []; - } - - $str_table_rows = ""; - - foreach ($tableData as $row) { - - if ($row['online'] == 1) { - $port_state = badge_online; - } else { - $port_state = badge_offline; - } - - // prepare HTML for the port table column cell - $port_content = "N/A"; - - if (($row['node_type'] == "WLAN" || $row['node_type'] == "AP" ) && ($row['port'] == NULL || $row['port'] == "") ){ - $port_content = ''; - } elseif ($row['node_type'] == "Powerline") - { - $port_content = ''; - } elseif ($row['port'] != NULL && $row['port'] != "") - { - $port_content = $row['port']; - } - - $str_table_rows = $str_table_rows. - ' - - - - - - '; - - } - - $str_table_close = ' -
Port'.lang('Network_Table_State').''.lang('Network_Table_Hostname').sortable_column.''.lang('Network_Table_IP').sortable_column.''.lang('Network_ManageLeaf').'
- '.$port_content.' - ' - .$port_state. - ' - - '.$row['name'].' - - ' - .$row['last_ip']. - ' - -
'; - - // no connected device - don't render table, just display some info - if($str_table_rows == "") - { - $str_table = "
-
- ".lang("Network_NoAssignedDevices")." -
-
"; - $str_table_close = ""; - } - - $str_close_pane = '
-
'; - - // write the HTML - echo ''.$str_tab_pane. - $str_table. - $str_table_rows. - $str_table_close. - $str_close_pane; - } - - - // Create Top level tabs (List of network devices), explanation of the terminology below: - // - // Switch 1 (node) - // /(p1) \ (p2) <----- port numbers - // / \ - // Smart TV (leaf) Switch 2 (node (for the PC) and leaf (for Switch 1)) - // \ - // PC (leaf) <------- leafs are not included in this SQL query - - $networkDeviceTypes = str_replace("]", "",(str_replace("[", "", getSettingValue("NETWORK_DEVICE_TYPES")))); - - $sql = "SELECT node_name, node_mac, online, node_type, node_ports_count, parent_mac, node_icon, node_alert - FROM - ( - SELECT a.devName as node_name, - a.devMac as node_mac, - a.devPresentLastScan as online, - a.devType as node_type, - a.devParentMAC as parent_mac, - a.devIcon as node_icon, - a.devAlertDown as node_alert - FROM Devices a - WHERE a.devType in (".$networkDeviceTypes.") - AND devIsArchived = 0 - ) t1 - LEFT JOIN - ( - SELECT b.devParentMAC as node_mac_2, - count() as node_ports_count - FROM Devices b - WHERE b.devParentMAC NOT NULL group by b.devParentMAC - ) t2 - ON (t1.node_mac = t2.node_mac_2); - "; - - $result = $db->query($sql); - - // array - $tableData = array(); - while ($row = $result -> fetchArray (SQLITE3_ASSOC)) { - // Push row data - $tableData[] = array( 'node_mac' => $row['node_mac'], - 'node_name' => $row['node_name'], - 'online' => $row['online'], - 'node_type' => $row['node_type'], - 'parent_mac' => $row['parent_mac'], - 'node_icon' => $row['node_icon'], - 'node_ports_count' => $row['node_ports_count'], - 'node_alert' => $row['node_alert'] - ); - } - - // Control no rows - if (empty($tableData)) { - $tableData = []; - } - - echo '
- - - query($func_sql); - - // array - $tableData = array(); - while ($row = $func_result -> fetchArray (SQLITE3_ASSOC)) { - // Push row data - $tableData[] = array( 'mac' => $row['mac'], - 'online' => $row['online'], - 'name' => $row['name'], - 'last_ip' => $row['last_ip']); - } - - // Don't do anything if empty - if (!(empty($tableData))) { - $str_table_header = ' -
-
-
-

- '.lang('Network_UnassignedDevices').' -

- - - - - - - - - - - - - - '; - - $str_table_rows = ""; - - foreach ($tableData as $row) { - - if ($row['online'] == 1) { - $state = badge_online; - } else { - $state = badge_offline; - } - - $str_table_rows = $str_table_rows. - ' - - - - - - - '; - } - - $str_table_close = ' -
'.lang('Network_Table_State').''.lang('Network_Table_Hostname').sortable_column.''.lang('Network_Table_IP').sortable_column.''.lang('Network_Assign').'
' - .$state. - ' - - '.$row['name'].' - - ' - .$row['last_ip']. - ' - -
-
-
-
'; - - // write the html - echo $str_table_header.$str_table_rows.$str_table_close; - } - - - ?> - -
- - + +
+ +
+ +
+ +
+ + + - - -