From af3abe66f4ceee6eadcd075d22d8414bf9756835 Mon Sep 17 00:00:00 2001 From: billz Date: Thu, 6 Feb 2025 02:44:37 -0800 Subject: [PATCH 01/54] Initial commit --- app/img/rpi3b-themecolor.svg | 4447 ++++++++++++++++++++++++++++++++++ 1 file changed, 4447 insertions(+) create mode 100644 app/img/rpi3b-themecolor.svg diff --git a/app/img/rpi3b-themecolor.svg b/app/img/rpi3b-themecolor.svg new file mode 100644 index 00000000..095ab12a --- /dev/null +++ b/app/img/rpi3b-themecolor.svg @@ -0,0 +1,4447 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + From 80c1a047972049136d0bf1830b84b3bd54f62c0f Mon Sep 17 00:00:00 2001 From: neo773 Date: Fri, 7 Feb 2025 01:18:33 +0530 Subject: [PATCH 02/54] feat: dashboard redesign --- app/css/all.css | 239 ++ app/img/dashed.svg | 10 + app/img/device.svg | 4445 ++++++++++++++++++++++++++++++++++++++ app/img/right-dashed.svg | 8 + app/img/right-solid.php | 51 + app/img/solid.php | 62 + templates/dashboard.php | 266 +-- 7 files changed, 4958 insertions(+), 123 deletions(-) create mode 100644 app/img/dashed.svg create mode 100644 app/img/device.svg create mode 100644 app/img/right-dashed.svg create mode 100644 app/img/right-solid.php create mode 100644 app/img/solid.php diff --git a/app/css/all.css b/app/css/all.css index 59f43cbb..3cdbfd85 100644 --- a/app/css/all.css +++ b/app/css/all.css @@ -377,3 +377,242 @@ button > i.fas { border: 1px solid #ced4da; } + + +.card-wrapper { + margin: 1rem; +} + +.dashboard-container { + display: flex; + position: relative; + width: 100%; + min-height: 400px; + padding: 2rem; +} + +.connections-left, +.connections-right { + position: relative; + display: flex; + flex-direction: column; + justify-content: space-between; +} + +.connection-item { + display: flex; + align-items: center; + gap: 0.5rem; + z-index: 5; +} + +.connection-right { + justify-content: flex-end; +} + +.connections-left i { + height: 40px; + display: flex; + align-items: center; + justify-content: left; +} + +.connections-left i:first-child { + margin-top: 0; +} + +.connections-left i:last-child { + margin-bottom: 0; +} + +.center-device { + display: flex; + flex-direction: column; + align-items: center; + text-align: center; + position: relative; + z-index: 1; +} + +.client-group { + display: flex; + align-items: center; + flex-direction: row-reverse; + gap: 0.5rem; +} + +.client-count { + text-align: right; +} + +.clients-status { + height: 100%; + display: flex; + flex-direction: column; + justify-content: space-between; + align-items: flex-end; + padding-right: 1rem; +} + +.dashed-lines, +.solid-lines { + position: absolute; + top: 0; + left: 0; + width: 100%; + height: 100%; + object-fit: contain; + padding: 1rem; + left: 112px; + z-index: 0; +} + +.dashed-lines-right, +.solid-lines-right { + left: -80px; +} + +.device-status { + display: flex; + flex-wrap: wrap; + gap: 1rem; + justify-content: center; + margin: 1rem 0; +} + +.wifi-bands { + display: flex; + gap: 0.5rem; +} + +.band { + padding: 0.25rem 1rem; + border: 2px solid #7D7E7E; + border-radius: 4px; + background: transparent; + font-weight: 600; + color: #7D7E7E; +} + +.band.active { + border-color: #008281; + color: #008281; +} + +.device-label { + font-size: 1.5rem; + text-align: center; + color: #008281; + margin-top: 1rem; +} + +.status-item { + display: flex; + flex-direction: column; + align-items: center; + gap: 1.3rem; +} + +.bottom { + display: flex; + flex-direction: column; + align-items: center; + gap: 1.3rem; + width: 100%; +} + +.connection-item>i { + color: #7D7E7E; +} + +.connections-left>.connection-item>span { + color: #7D7E7E; + margin-right: 0.5rem; +} + +@media (max-width: 1200px) { + .connection-item > span:not(.fa-stack) { + display: none!important; + } +} + +@media (max-width: 991px) { + .connections-right, + .connections-left { + display: none!important; + } + .dashboard-container { + width: auto; + padding: 0; + + } + .device-status { + gap: 0.5rem; + } + .clients-mobile { + display: flex!important; + flex-direction: row!important; + } +} +.connection-item.active > span { + color: #008281!important; +} +.connection-item.active > i { + color: #008281!important; +} +.status-item.active > span { + color: #008281!important; +} +.status-item.active > i { + color: #008281!important; +} +.clients-mobile { + display: none; + flex-direction: column; + gap: 1rem; + margin-top: 2rem; +} + +.client-type { + position: relative; + display: inline-flex; + align-items: center; + gap: 1rem; +} + +.client-type i { + font-size: 1.5rem; + color: #008281; + background: #fff; + width: 45px; + height: 45px; + border-radius: 50%; + display: flex; + align-items: center; + justify-content: center; + border: 2px solid #008281; +} + +.client-type i.badge-icon { + font-size: 0.7rem; + background: #008281; + color: white; + width: 20px; + height: 20px; + border: none; +} + +.client-count { + position: absolute; + top: -5px; + right: -5px; + background: #008281; + color: white; + border-radius: 50%; + width: 20px; + height: 20px; + display: flex; + align-items: center; + justify-content: center; + font-size: 0.8rem; +} \ No newline at end of file diff --git a/app/img/dashed.svg b/app/img/dashed.svg new file mode 100644 index 00000000..d5d57e59 --- /dev/null +++ b/app/img/dashed.svg @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/app/img/device.svg b/app/img/device.svg new file mode 100644 index 00000000..6c7d2e61 --- /dev/null +++ b/app/img/device.svg @@ -0,0 +1,4445 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/img/right-dashed.svg b/app/img/right-dashed.svg new file mode 100644 index 00000000..5a41449e --- /dev/null +++ b/app/img/right-dashed.svg @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/app/img/right-solid.php b/app/img/right-solid.php new file mode 100644 index 00000000..98d425c1 --- /dev/null +++ b/app/img/right-solid.php @@ -0,0 +1,51 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/img/solid.php b/app/img/solid.php new file mode 100644 index 00000000..5cb5ecf0 --- /dev/null +++ b/app/img/solid.php @@ -0,0 +1,62 @@ + + + + 0.75, + 'out' => 297.75, + 'device-2' => 198.75, + 'device-3' => 397.058, + 'device-4' => 595.211 +]; + +// Calculate joint line segments +if ($showJoint) { + $activeDevices = array_filter([$showDevice1, $showDevice2, $showDevice3, $showDevice4]); + $activeYs = []; + + foreach ($devicePositions as $device => $y) { + if (isset($_GET[$device])) { + $activeYs[] = $y; + } + } + + // Add top/bottom if first/last device is connected + if ($showDevice1) array_unshift($activeYs, 0); + if ($showDevice4) $activeYs[] = 596; + + // Draw segments between consecutive points + for ($i = 1; $i < count($activeYs); $i++) { + $y1 = $activeYs[$i-1]; + $y2 = $activeYs[$i]; + echo ""; + } +} +?> + + + + + + + + + + + + + + + + + diff --git a/templates/dashboard.php b/templates/dashboard.php index d85653c8..e9e373ef 100755 --- a/templates/dashboard.php +++ b/templates/dashboard.php @@ -3,140 +3,159 @@
-
- -
-
- -
+
+ + +
+
+ +
+
-
-
+
-
-
-
-

-
-
-
- +
+

+ +

+ +
+
+
+ Ethernet + +
+
+ Repeater + +
+
+ Tethering + +
+
+ Cellular + +
+ + +
+ +
+
+ Raspberry Pi +
Raspberry Pi 3 Model B+
+
+ +
+
+
+ + + + +
+
+ + + + +
+
+ + + + +
+
+ + + + +
+
+ + + + + + + +
+
+ +
+ 5G + 2.4G
-
-
-
-
-
-
-

-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+ +
+
-
- -
- -
+
+ + 3
-
-
-
-
-
-
-
-

-
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- 2) : ?> -
- -
- -
- -
-
-
-
-
+
+
-
-
-
- - - - " name="ifup_wlan0" /> - - " name="ifdown_wlan0" /> - - -
-
+
+ +
+
+
+ + + + " name="ifup_wlan0" /> + + " name="ifdown_wlan0" /> + + +
+
+ + +
@@ -144,6 +163,7 @@ + t[' send'] = ''; + t['receive'] = ' + '; + \ No newline at end of file From 6e1c3b95c2572490e477b7aea87326d1da12a11a Mon Sep 17 00:00:00 2001 From: Bill Zimmerman Date: Sat, 15 Mar 2025 17:44:31 +0100 Subject: [PATCH 03/54] Revise dashed .svg files --- app/img/dashed.svg | 58 +++++++++++++++++++++++++++++++++++----- app/img/right-dashed.svg | 42 +++++++++++++++++++++++++---- 2 files changed, 88 insertions(+), 12 deletions(-) diff --git a/app/img/dashed.svg b/app/img/dashed.svg index d5d57e59..01415d4c 100644 --- a/app/img/dashed.svg +++ b/app/img/dashed.svg @@ -1,10 +1,54 @@ - + + + + - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/img/right-dashed.svg b/app/img/right-dashed.svg index 5a41449e..282f0eab 100644 --- a/app/img/right-dashed.svg +++ b/app/img/right-dashed.svg @@ -1,8 +1,40 @@ - + + + + - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + From 781f376bea7b0a3fc2ba90f7b0eacd0312368131 Mon Sep 17 00:00:00 2001 From: billz Date: Sat, 15 Mar 2025 11:31:59 -0700 Subject: [PATCH 04/54] Standardize revision descriptions --- src/RaspAP/System/Sysinfo.php | 48 +++++++++++++++++------------------ 1 file changed, 24 insertions(+), 24 deletions(-) diff --git a/src/RaspAP/System/Sysinfo.php b/src/RaspAP/System/Sysinfo.php index 3cb493c9..7f5fbe09 100755 --- a/src/RaspAP/System/Sysinfo.php +++ b/src/RaspAP/System/Sysinfo.php @@ -100,31 +100,31 @@ class Sysinfo public function rpiRevision() { $revisions = array( - '0002' => 'Model B Revision 1.0', - '0003' => 'Model B Revision 1.0 + ECN0001', - '0004' => 'Model B Revision 2.0 (256 MB)', - '0005' => 'Model B Revision 2.0 (256 MB)', - '0006' => 'Model B Revision 2.0 (256 MB)', - '0007' => 'Model A', - '0008' => 'Model A', - '0009' => 'Model A', - '000d' => 'Model B Revision 2.0 (512 MB)', - '000e' => 'Model B Revision 2.0 (512 MB)', - '000f' => 'Model B Revision 2.0 (512 MB)', - '0010' => 'Model B+', - '0013' => 'Model B+', + '0002' => 'Raspberry Pi Model B Rev 1.0', + '0003' => 'Raspberry Pi Model B Rev 1.0', + '0004' => 'Raspberry Pi Model B Rev 2.0 (256 MB)', + '0005' => 'Raspberry Pi Model B Rev 2.0 (256 MB)', + '0006' => 'Raspberry Pi Model B Rev 2.0 (256 MB)', + '0007' => 'Raspberry Pi Model A', + '0008' => 'Raspberry Pi Model A', + '0009' => 'Raspberry Pi Model A', + '000d' => 'Raspberry Pi Model B Rev 2.0 (512 MB)', + '000e' => 'Raspberry Pi Model B Rev 2.0 (512 MB)', + '000f' => 'Raspberry Pi Model B Rev 2.0 (512 MB)', + '0010' => 'Raspberry Pi Model B+', + '0013' => 'Raspberry Pi Model B+', '0011' => 'Compute Module', - '0012' => 'Model A+', + '0012' => 'Raspberry Pi Model A+', 'a01041' => 'a01041', 'a21041' => 'a21041', - '900092' => 'PiZero 1.2', - '900093' => 'PiZero 1.3', - '9000c1' => 'PiZero W', - 'a02082' => 'Pi 3 Model B', - 'a22082' => 'Pi 3 Model B', - 'a32082' => 'Pi 3 Model B', - 'a52082' => 'Pi 3 Model B', - 'a020d3' => 'Pi 3 Model B+', + '900092' => 'Raspberry Pi Zero 1.2', + '900093' => 'Raspberry Pi Zero 1.3', + '9000c1' => 'Raspberry Pi Zero W', + 'a02082' => 'Raspberry Pi 3 Model B', + 'a22082' => 'Raspberry Pi 3 Model B', + 'a32082' => 'Raspberry Pi 3 Model B', + 'a52082' => 'Raspberry Pi 3 Model B', + 'a020d3' => 'Raspberry Pi 3 Model B+', 'a220a0' => 'Compute Module 3', 'a020a0' => 'Compute Module 3', 'a02100' => 'Compute Module 3+', @@ -135,8 +135,8 @@ class Sysinfo 'b03140' => 'Compute Module 4 (2 GB)', 'c03140' => 'Compute Module 4 (4 GB)', 'd03140' => 'Compute Module 4 (8 GB)', - 'c04170' => 'Pi 5 (4 GB)', - 'd04170' => 'Pi 5 (8 GB)' + 'c04170' => 'Raspberry Pi 5 (4 GB)', + 'd04170' => 'Raspberry Pi 5 (8 GB)' ); $cpuinfo_array = ''; From f608282aa5ba5992d63167c5c0cee15e68aa8300 Mon Sep 17 00:00:00 2001 From: billz Date: Sat, 15 Mar 2025 11:33:03 -0700 Subject: [PATCH 05/54] Define --raspap-text-light, replace hex colors w/ vars, tweaks --- app/css/all.css | 45 +++++++++++++++++++++++++++++---------------- 1 file changed, 29 insertions(+), 16 deletions(-) diff --git a/app/css/all.css b/app/css/all.css index 3cdbfd85..957f9795 100644 --- a/app/css/all.css +++ b/app/css/all.css @@ -9,6 +9,7 @@ License: GNU General Public License v3.0 :root { --raspap-content-main: #495057; --raspap-text-muted: #858796; + --raspap-text-light: #7d7e7e; --raspap-brand-color: #2b8080; --raspap-offwhite: #faf9f6; } @@ -377,8 +378,6 @@ button > i.fas { border: 1px solid #ced4da; } - - .card-wrapper { margin: 1rem; } @@ -400,14 +399,17 @@ button > i.fas { } .connection-item { + cursor: pointer; display: flex; align-items: center; gap: 0.5rem; z-index: 5; + color: var(--raspap-text-light); } .connection-right { - justify-content: flex-end; + align-items: center; + margin-left: 10rem; } .connections-left i { @@ -495,14 +497,14 @@ button > i.fas { } .band.active { - border-color: #008281; - color: #008281; + border-color: var(--raspap-brand-color); + color: var(--raspap-brand-color); } .device-label { font-size: 1.5rem; text-align: center; - color: #008281; + color: var(--raspap-brand-color); margin-top: 1rem; } @@ -511,6 +513,7 @@ button > i.fas { flex-direction: column; align-items: center; gap: 1.3rem; + color: var(--raspap-text-light); } .bottom { @@ -522,11 +525,15 @@ button > i.fas { } .connection-item>i { - color: #7D7E7E; + color: var(--raspap-text-light); +} + +.connection-item .fa-stack { + min-width: 2.5em; } .connections-left>.connection-item>span { - color: #7D7E7E; + color: var(--raspap-text-light); margin-right: 0.5rem; } @@ -555,16 +562,16 @@ button > i.fas { } } .connection-item.active > span { - color: #008281!important; + color: var(--raspap-brand-color)!important; } .connection-item.active > i { - color: #008281!important; + color: var(--raspap-brand-color)!important; } .status-item.active > span { - color: #008281!important; + color: var(--raspap-brand-color)!important; } .status-item.active > i { - color: #008281!important; + color: var(--raspap-brand-color)!important; } .clients-mobile { display: none; @@ -582,7 +589,7 @@ button > i.fas { .client-type i { font-size: 1.5rem; - color: #008281; + color: var(--raspap-brand-color); background: #fff; width: 45px; height: 45px; @@ -590,12 +597,12 @@ button > i.fas { display: flex; align-items: center; justify-content: center; - border: 2px solid #008281; + border: 2px solid var(--raspap-brand-color); } .client-type i.badge-icon { font-size: 0.7rem; - background: #008281; + background: var(--raspap-brand-color); color: white; width: 20px; height: 20px; @@ -615,4 +622,10 @@ button > i.fas { align-items: center; justify-content: center; font-size: 0.8rem; -} \ No newline at end of file +} + +.device-illustration { + min-width: 220px; +} + + From 2610c44ac9d55e2f6a25a212a2610c2dfe15e942 Mon Sep 17 00:00:00 2001 From: billz Date: Sat, 15 Mar 2025 11:34:49 -0700 Subject: [PATCH 06/54] Adjust stroke-width, remove rect w/ fill for dark mode support --- app/img/right-solid.php | 5 ----- app/img/solid.php | 2 +- 2 files changed, 1 insertion(+), 6 deletions(-) diff --git a/app/img/right-solid.php b/app/img/right-solid.php index 98d425c1..27ca8f79 100644 --- a/app/img/right-solid.php +++ b/app/img/right-solid.php @@ -6,12 +6,9 @@ $showDevice2 = isset($_GET['device-2']); ?> - - - - - diff --git a/app/img/solid.php b/app/img/solid.php index 5cb5ecf0..9419b6c2 100644 --- a/app/img/solid.php +++ b/app/img/solid.php @@ -45,7 +45,7 @@ if ($showJoint) { ?> - + From 24747658208cdde5f125cd6cc159d4866f800545 Mon Sep 17 00:00:00 2001 From: billz Date: Sat, 15 Mar 2025 15:18:24 -0700 Subject: [PATCH 07/54] Add device illustration to system basic tab --- templates/system/basic.php | 3 +++ 1 file changed, 3 insertions(+) diff --git a/templates/system/basic.php b/templates/system/basic.php index a238d629..73fc7901 100644 --- a/templates/system/basic.php +++ b/templates/system/basic.php @@ -9,6 +9,9 @@ include('includes/sysstats.php');

+
+ <?php echo htmlspecialchars($revision, ENT_QUOTES); ?> +
From fbcf9809c504b35a5702aeda0c0db4403798e589 Mon Sep 17 00:00:00 2001 From: billz Date: Sat, 15 Mar 2025 16:00:27 -0700 Subject: [PATCH 08/54] Update hotspot icon > fa-bullseye --- src/RaspAP/UI/Sidebar.php | 2 +- templates/hostapd.php | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/RaspAP/UI/Sidebar.php b/src/RaspAP/UI/Sidebar.php index 62408e27..8d79f9de 100644 --- a/src/RaspAP/UI/Sidebar.php +++ b/src/RaspAP/UI/Sidebar.php @@ -16,7 +16,7 @@ class Sidebar { public function __construct() { // Load default sidebar items $this->addItem(_('Dashboard'), 'fa-solid fa-gauge-high', 'wlan0_info', 10); - $this->addItem(_('Hotspot'), 'far fa-dot-circle', 'hostapd_conf', 20, + $this->addItem(_('Hotspot'), 'fas fa-bullseye', 'hostapd_conf', 20, fn() => RASPI_HOTSPOT_ENABLED ); $this->addItem(_('DHCP Server'), 'fas fa-exchange-alt', 'dhcpd_conf', 30, diff --git a/templates/hostapd.php b/templates/hostapd.php index 6e352fb2..e4eaee58 100755 --- a/templates/hostapd.php +++ b/templates/hostapd.php @@ -36,7 +36,7 @@
- +
@@ -21,11 +32,11 @@
+ showMessages(); ?>

-
@@ -50,8 +61,10 @@
<?php echo htmlspecialchars($revision, ENT_QUOTES); ?>
-
IP address:
-
SSID:
+
IP address:
+
Netmask:
+
MAC address:
+
SSID:
@@ -74,14 +87,16 @@
-
+ +
+
- + @@ -90,8 +105,8 @@
- 5G - 2.4G + 5G + 2.4G
@@ -140,14 +155,7 @@
- - - " name="ifup_wlan0" /> - - " name="ifdown_wlan0" /> - - -
From 4865e85655c21fcf2fd320db9d1403e22c72bad7 Mon Sep 17 00:00:00 2001 From: billz Date: Mon, 17 Mar 2025 04:07:27 -0700 Subject: [PATCH 18/54] Various minor tweaks --- app/css/all.css | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/app/css/all.css b/app/css/all.css index 7368a65d..d0a8e4a7 100644 --- a/app/css/all.css +++ b/app/css/all.css @@ -172,11 +172,6 @@ canvas#divDBChartBandwidthhourly { height: 350px!important; } -.chart-container { - height: 150px; - width: 200px; -} - .dbChart { display: flex; height: 80%; @@ -191,7 +186,7 @@ canvas#divDBChartBandwidthhourly { } .check-progress { - color: #999; + color: var(--raspap-text-light); } .fa-check { @@ -518,7 +513,7 @@ textarea.plugin-log { } .device-label { - font-size: 1.5rem; + font-size: 1.3rem; text-align: center; color: var(--raspap-brand-color); margin-top: 1rem; @@ -589,6 +584,7 @@ textarea.plugin-log { .status-item.active > i { color: var(--raspap-brand-color)!important; } + .clients-mobile { display: none; flex-direction: column; @@ -642,4 +638,6 @@ textarea.plugin-log { .device-illustration { min-width: 220px; + max-width: 250px; } + From 64d3a118669e4df93754cbb8df1250f013514e0e Mon Sep 17 00:00:00 2001 From: billz Date: Mon, 17 Mar 2025 06:02:48 -0700 Subject: [PATCH 19/54] Create getConnectionType(), getWirelessClients() getEthernetClients() --- includes/dashboard.php | 105 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 105 insertions(+) diff --git a/includes/dashboard.php b/includes/dashboard.php index bc91a8ed..3c20de43 100755 --- a/includes/dashboard.php +++ b/includes/dashboard.php @@ -28,7 +28,11 @@ function DisplayDashboard(): void $details = getInterfaceDetails($interface); $wireless = getWirelessDetails($interface); $connectedBSSID = getConnectedBSSID($interface); + $connectionType = getConnectionType(); $state = strtolower($details['state']); + $wirelessClientCount = getWirelessClients(); + $ethernetClientCount = getEthernetClients(); + $totalClients = $wirelessClientCount + $ethernetClientCount; $plugins = $pluginManager->getInstalledPlugins(); $arrHostapdConf = parse_ini_file(RASPI_CONFIG.'/hostapd.ini'); @@ -46,9 +50,15 @@ function DisplayDashboard(): void $ipv4Netmask = $details['ipv4_netmask']; $macAddress = $details['mac']; $ssid = $wireless['ssid']; + $ethernetActive = ($connectionType === 'ethernet') ? "active" : ""; + $wirelessActive = ($connectionType === 'wireless') ? "active" : ""; + $tetheringActive = ($connectionType === 'tethering') ? "active" : ""; + $cellularActive = ($connectionType === 'cellular') ? "active" : ""; $bridgedStatus = ($bridgedEnable == 1) ? "active" : ""; $hostapdStatus = ($hostapd[0] == 1) ? "active" : ""; $adblockStatus = ($adblock == true) ? "active" : ""; + $wirelessClientLabel = $wirelessClientCount. ' WLAN '.formatClientLabel($wirelessClientCount); + $ethernetClientLabel = $ethernetClientCount. ' LAN '.formatClientLabel($ethernerClientCount); $varName = "freq" . str_replace('.', '', $frequency) . "active"; $$varName = "active"; $vpnStatus = $vpn ? "active" : "inactive"; @@ -59,6 +69,7 @@ function DisplayDashboard(): void if (!$firewallInstalled) { $firewallUnavailable = ''; } + echo renderTemplate( "dashboard", compact( "clients", @@ -81,6 +92,14 @@ function DisplayDashboard(): void "frequency", "freq5active", "freq24active", + "wirelessClientLabel", + "ethernetClientLabel", + "totalClients", + "connectionType", + "ethernetActive", + "wirelessActive", + "tetheringActive", + "cellularActive", "revision" ) ); @@ -215,6 +234,92 @@ function getSSID(string $output): string { : '-'; } +/* + * Parses the output of iw to obtain a list of wireless clients + * + * @return integer $clientCount + */ +function getWirelessClients() { + exec('iw dev wlan0 station dump', $output, $status); + + if ($status !== 0) { + return 0; + } + // enumerate 'station' entries (each represents a wireless client) + $clientCount = 0; + foreach ($output as $line) { + if (strpos($line, 'Station') === 0) { + $clientCount++; + } + } + return $clientCount; +} + +/* + * Parses output from the system ARP cache to obtain a list of + * IPv4 network neighbors + * + * @return integer $clientCount + */ +function getEthernetClients() { + exec('arp -n', $output, $status); + + if ($status !== 0) { + return 0; // Return 0 if the command fails + } + // enumerate IP addresses (ethernet 'neighbors') in the output + $clientCount = 0; + foreach ($output as $line) { + // skip the first line (header) + if (strpos($line, 'Address') === false) { + $clientCount++; + } + } + return $clientCount; +} + +function formatClientLabel($clientCount) { + return $clientCount === 1 ? 'client' : 'clients'; +} + +/* + * Determines the device's primary connection type by + * parsing the output of ip route; the interface listed + * as the default gateway is used for internet connectivity. + * + * The following interface classifications are assumed: + * - ethernet (eth0, en*) + * - wireless (wlan0, wlan1, wlp*) + * - tethered USB (usb*, eth1) + * - cellular (ppp0, wwan0, wwp*) + * - fallback + * @return string + */ +function getConnectionType() { + // get the interface associated with the default route + $interface = trim(shell_exec("ip route show default | awk '{print $5}'")); + + if (empty($interface)) { + return 'unknown'; + } + // classify interface type + if (preg_match('/^eth\d+|enp\d+s\d+/', $interface)) { + return 'ethernet'; + } + if (preg_match('/^wlan\d+|wlp\d+s\d+/', $interface)) { + return 'wireless'; + } + if (preg_match('/^usb\d+|eth1$/', $interface)) { + return 'tethering'; + } + if (preg_match('/^ppp\d+|wwan\d+|wwp\d+s\d+/', $interface)) { + return 'cellular'; + } + + // if none match, return the interface name as a fallback + return "other ($interface)"; +} + /** * Handles dashboard page actions * From 182073f41e767db9a11f661ef4f0d0b29c6c6100 Mon Sep 17 00:00:00 2001 From: billz Date: Mon, 17 Mar 2025 06:04:02 -0700 Subject: [PATCH 20/54] Update placeholder values w/ template data + active route states --- templates/dashboard.php | 20 +++++++++----------- 1 file changed, 9 insertions(+), 11 deletions(-) diff --git a/templates/dashboard.php b/templates/dashboard.php index 2a0b8a43..4567dcf7 100755 --- a/templates/dashboard.php +++ b/templates/dashboard.php @@ -38,24 +38,24 @@
-
+
-
- +
+
-
+
>
-
+
- +
@@ -119,7 +119,7 @@
- 3 +
@@ -131,14 +131,14 @@ - 3 WLAN Clients +
- 1 LAN Client +
@@ -148,9 +148,7 @@
-
-
From d852990314ef288651e103a0628089edba3d50b7 Mon Sep 17 00:00:00 2001 From: billz Date: Mon, 17 Mar 2025 07:05:03 -0700 Subject: [PATCH 21/54] Replace var raspap-brand-color w/ raspap-theme-color --- app/css/all.css | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/app/css/all.css b/app/css/all.css index d0a8e4a7..23d869b9 100644 --- a/app/css/all.css +++ b/app/css/all.css @@ -508,14 +508,14 @@ textarea.plugin-log { } .band.active { - border-color: var(--raspap-brand-color); - color: var(--raspap-brand-color); + border-color: var(--raspap-theme-color); + color: var(--raspap-theme-color); } .device-label { font-size: 1.3rem; text-align: center; - color: var(--raspap-brand-color); + color: var(--raspap-theme-color); margin-top: 1rem; } @@ -573,16 +573,16 @@ textarea.plugin-log { } } .connection-item.active > span { - color: var(--raspap-brand-color)!important; + color: var(--raspap-theme-color)!important; } .connection-item.active > i { - color: var(--raspap-brand-color)!important; + color: var(--raspap-theme-color)!important; } .status-item.active > span { - color: var(--raspap-brand-color)!important; + color: var(--raspap-theme-color)!important; } .status-item.active > i { - color: var(--raspap-brand-color)!important; + color: var(--raspap-theme-color)!important; } .clients-mobile { @@ -601,7 +601,7 @@ textarea.plugin-log { .client-type i { font-size: 1.5rem; - color: var(--raspap-brand-color); + color: var(--raspap-theme-color); background: #fff; width: 45px; height: 45px; @@ -609,12 +609,12 @@ textarea.plugin-log { display: flex; align-items: center; justify-content: center; - border: 2px solid var(--raspap-brand-color); + border: 2px solid var(--raspap-theme-color); } .client-type i.badge-icon { font-size: 0.7rem; - background: var(--raspap-brand-color); + background: var(--raspap-theme-color); color: white; width: 20px; height: 20px; From b737b5c748618b0c904098b7a950a252ff482c89 Mon Sep 17 00:00:00 2001 From: billz Date: Mon, 17 Mar 2025 07:06:21 -0700 Subject: [PATCH 22/54] Use dynamic theme color w/ device svg --- app/img/device.php | 4450 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 4450 insertions(+) create mode 100644 app/img/device.php diff --git a/app/img/device.php b/app/img/device.php new file mode 100644 index 00000000..193e0130 --- /dev/null +++ b/app/img/device.php @@ -0,0 +1,4450 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + From 00c18451cced18fcdeda4187a9869a9199890b9f Mon Sep 17 00:00:00 2001 From: billz Date: Mon, 17 Mar 2025 07:07:25 -0700 Subject: [PATCH 23/54] Replace static svg w/ device.php --- templates/dashboard.php | 4 ++-- templates/system/basic.php | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/templates/dashboard.php b/templates/dashboard.php index 4567dcf7..8d2a2312 100755 --- a/templates/dashboard.php +++ b/templates/dashboard.php @@ -59,7 +59,7 @@
- <?php echo htmlspecialchars($revision, ENT_QUOTES); ?> + <?php echo htmlspecialchars($revision, ENT_QUOTES); ?>
IP address:
Netmask:
@@ -142,7 +142,7 @@
- +
diff --git a/templates/system/basic.php b/templates/system/basic.php index 8070de47..35a4509c 100644 --- a/templates/system/basic.php +++ b/templates/system/basic.php @@ -10,7 +10,7 @@ include('includes/sysstats.php');

- <?php echo htmlspecialchars($revision, ENT_QUOTES); ?> + <?php echo htmlspecialchars($revision, ENT_QUOTES); ?>
From 5ed1312406d7a97a9b553cc6777e24649b5e4ae3 Mon Sep 17 00:00:00 2001 From: billz Date: Mon, 17 Mar 2025 07:08:29 -0700 Subject: [PATCH 24/54] Revise getEthernetClients() w/ more robust method comparing arp + dhcp --- includes/dashboard.php | 35 ++++++++++++++++++++--------------- 1 file changed, 20 insertions(+), 15 deletions(-) diff --git a/includes/dashboard.php b/includes/dashboard.php index 3c20de43..09e21dc9 100755 --- a/includes/dashboard.php +++ b/includes/dashboard.php @@ -256,26 +256,31 @@ function getWirelessClients() { } /* - * Parses output from the system ARP cache to obtain a list of - * IPv4 network neighbors + * Retrieves ethernet neighbors from ARP cache, parses DHCP leases + * to find matching MAC addresses and returns only clients that + * exist in both sources * - * @return integer $clientCount + * @return int $clients */ -function getEthernetClients() { - exec('arp -n', $output, $status); +function getEthernetClients(): int { + $arpOutput = shell_exec("ip neigh show | awk '{print $5}' | sort -u"); + $arpMacs = array_filter(explode("\n", trim($arpOutput))); - if ($status !== 0) { - return 0; // Return 0 if the command fails - } - // enumerate IP addresses (ethernet 'neighbors') in the output - $clientCount = 0; - foreach ($output as $line) { - // skip the first line (header) - if (strpos($line, 'Address') === false) { - $clientCount++; + $leaseFile = RASPI_DNSMASQ_LEASES; + $dhcpMacs = []; + + if (file_exists($leaseFile)) { + $leases = file($leaseFile, FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES); + foreach ($leases as $lease) { + $parts = explode(' ', $lease); + if (isset($parts[1])) { + $dhcpMacs[] = $parts[1]; // MAC address from DHCP leases + } } } - return $clientCount; + // filter ARP results to include only DHCP clients + $clients = array_intersect($arpMacs, $dhcpMacs); + return count($clients); } function formatClientLabel($clientCount) { From f1c404a443dd99ecc1ba66a30f241e4f913c589e Mon Sep 17 00:00:00 2001 From: billz Date: Mon, 17 Mar 2025 07:09:10 -0700 Subject: [PATCH 25/54] Rename file to device.php --- app/img/device.svg | 4445 -------------------------------------------- 1 file changed, 4445 deletions(-) delete mode 100644 app/img/device.svg diff --git a/app/img/device.svg b/app/img/device.svg deleted file mode 100644 index 6c7d2e61..00000000 --- a/app/img/device.svg +++ /dev/null @@ -1,4445 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - From 64faf296a642691c96a63407f6a3de2a123287f9 Mon Sep 17 00:00:00 2001 From: billz Date: Mon, 17 Mar 2025 07:32:24 -0700 Subject: [PATCH 26/54] Apply dynamic theme color w/ rendered svg lines --- app/img/solid.php | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/app/img/solid.php b/app/img/solid.php index 9419b6c2..9952e7fa 100644 --- a/app/img/solid.php +++ b/app/img/solid.php @@ -1,6 +1,9 @@ "; + echo ""; } } ?> - + - + - + - + - + From 17fbbca04606b390d506529a56e9ed6e3d2e9236 Mon Sep 17 00:00:00 2001 From: billz Date: Mon, 17 Mar 2025 07:33:37 -0700 Subject: [PATCH 27/54] Create renderConnection(), update template --- includes/dashboard.php | 21 +++++++++++++++++++++ templates/dashboard.php | 4 ++-- 2 files changed, 23 insertions(+), 2 deletions(-) diff --git a/includes/dashboard.php b/includes/dashboard.php index 09e21dc9..285fc60c 100755 --- a/includes/dashboard.php +++ b/includes/dashboard.php @@ -325,6 +325,27 @@ function getConnectionType() { return "other ($interface)"; } +/** + * Renders a URL for an svg solid line representing the associated + * connection type + * + * @param string $connectionType + * @return string + */ +function renderConnection(string $connectionType): string +{ + $deviceMap = [ + 'ethernet' => 'device-1', + 'wireless' => 'device-2', + 'tethering' => 'device-3', + 'cellular' => 'device-4' + ]; + $device = $deviceMap[$connectionType] ?? 'device-unknown'; + + // return generated URL for solid.php + return sprintf('app/img/solid.php?joint&%s&out', $device); +} + /** * Handles dashboard page actions * diff --git a/templates/dashboard.php b/templates/dashboard.php index 8d2a2312..df0a3409 100755 --- a/templates/dashboard.php +++ b/templates/dashboard.php @@ -46,7 +46,7 @@
-
> +
@@ -55,7 +55,7 @@
- + Network connection
From 964d7b38a8ef2f1e0bef85ef273e20149be17652 Mon Sep 17 00:00:00 2001 From: billz Date: Mon, 17 Mar 2025 10:24:32 -0700 Subject: [PATCH 28/54] Create getConnectionIcon(), renderClientConnections() --- includes/dashboard.php | 106 ++++++++++++++++++++++++++++++++--------- 1 file changed, 84 insertions(+), 22 deletions(-) diff --git a/includes/dashboard.php b/includes/dashboard.php index 285fc60c..9a269a00 100755 --- a/includes/dashboard.php +++ b/includes/dashboard.php @@ -29,12 +29,12 @@ function DisplayDashboard(): void $wireless = getWirelessDetails($interface); $connectedBSSID = getConnectedBSSID($interface); $connectionType = getConnectionType(); + $connectionIcon = getConnectionIcon($connectionType); $state = strtolower($details['state']); - $wirelessClientCount = getWirelessClients(); - $ethernetClientCount = getEthernetClients(); - $totalClients = $wirelessClientCount + $ethernetClientCount; + $wirelessClients = getWirelessClients(); + $ethernetClients = getEthernetClients(); + $totalClients = $wirelessClients + $ethernetClients; $plugins = $pluginManager->getInstalledPlugins(); - $arrHostapdConf = parse_ini_file(RASPI_CONFIG.'/hostapd.ini'); $bridgedEnable = $arrHostapdConf['BridgedEnable']; @@ -57,8 +57,8 @@ function DisplayDashboard(): void $bridgedStatus = ($bridgedEnable == 1) ? "active" : ""; $hostapdStatus = ($hostapd[0] == 1) ? "active" : ""; $adblockStatus = ($adblock == true) ? "active" : ""; - $wirelessClientLabel = $wirelessClientCount. ' WLAN '.formatClientLabel($wirelessClientCount); - $ethernetClientLabel = $ethernetClientCount. ' LAN '.formatClientLabel($ethernerClientCount); + $wirelessClientLabel = $wirelessClients. ' WLAN '.formatClientLabel($wirelessClients); + $ethernetClientLabel = $ethernetClients. ' LAN '.formatClientLabel($ethernetClients); $varName = "freq" . str_replace('.', '', $frequency) . "active"; $$varName = "active"; $vpnStatus = $vpn ? "active" : "inactive"; @@ -72,7 +72,7 @@ function DisplayDashboard(): void echo renderTemplate( "dashboard", compact( - "clients", + "revision", "interface", "clientInterface", "state", @@ -82,7 +82,6 @@ function DisplayDashboard(): void "vpnStatus", "vpnManaged", "firewallUnavailable", - "status", "ipv4Address", "ipv4Netmask", "ipv6Address", @@ -92,15 +91,18 @@ function DisplayDashboard(): void "frequency", "freq5active", "freq24active", + "wirelessClients", + "ethernetClients", "wirelessClientLabel", "ethernetClientLabel", "totalClients", "connectionType", + "connectionIcon", "ethernetActive", "wirelessActive", "tetheringActive", "cellularActive", - "revision" + "status" ) ); } @@ -155,7 +157,8 @@ function getFrequencyBand(string $interface): ?string * @param string $interface * @return array */ -function getInterfaceDetails(string $interface): array { +function getInterfaceDetails(string $interface): array +{ $output = shell_exec('ip a show ' . escapeshellarg($interface)); if (!$output) { return [ @@ -177,11 +180,13 @@ function getInterfaceDetails(string $interface): array { ]; } -function getMacAddress(string $output): string { +function getMacAddress(string $output): string +{ return preg_match('/link\/ether ([0-9a-f:]+)/i', $output, $matches) ? $matches[1] : _('No MAC Address Found'); } -function getIPv4Addresses(string $output): string { +function getIPv4Addresses(string $output): string +{ if (!preg_match_all('/inet (\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})\/([0-3][0-9])/i', $output, $matches, PREG_SET_ORDER)) { return 'None'; } @@ -190,7 +195,8 @@ function getIPv4Addresses(string $output): string { return implode(' ', $addresses); } -function getIPv4Netmasks(string $output): string { +function getIPv4Netmasks(string $output): string +{ if (!preg_match_all('/inet (\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})\/([0-3][0-9])/i', $output, $matches, PREG_SET_ORDER)) { return '-'; } @@ -199,17 +205,20 @@ function getIPv4Netmasks(string $output): string { return implode(' ', $netmasks); } -function getIPv6Addresses(string $output): string { +function getIPv6Addresses(string $output): string +{ return preg_match_all('/inet6 ([a-f0-9:]+)/i', $output, $matches) && isset($matches[1]) ? implode(' ', $matches[1]) : _('No IPv6 Address Found'); } -function getInterfaceState(string $output): string { +function getInterfaceState(string $output): string +{ return preg_match('/state (UP|DOWN)/i', $output, $matches) ? $matches[1] : 'unknown'; } -function getWirelessDetails(string $interface): array { +function getWirelessDetails(string $interface): array +{ $output = shell_exec('iw dev ' . escapeshellarg($interface) . ' info'); if (!$output) { return ['bssid' => '-', 'ssid' => '-']; @@ -222,13 +231,15 @@ function getWirelessDetails(string $interface): array { ]; } -function getConnectedBSSID(string $output): string { +function getConnectedBSSID(string $output): string +{ return preg_match('/Connected to (([0-9A-Fa-f]{2}:){5}([0-9A-Fa-f]{2}))/i', $output, $matches) ? $matches[1] : '-'; } -function getSSID(string $output): string { +function getSSID(string $output): string +{ return preg_match('/ssid ([^\n\s]+)/i', $output, $matches) ? $matches[1] : '-'; @@ -239,7 +250,8 @@ function getSSID(string $output): string { * * @return integer $clientCount */ -function getWirelessClients() { +function getWirelessClients() +{ exec('iw dev wlan0 station dump', $output, $status); if ($status !== 0) { @@ -262,7 +274,8 @@ function getWirelessClients() { * * @return int $clients */ -function getEthernetClients(): int { +function getEthernetClients(): int +{ $arpOutput = shell_exec("ip neigh show | awk '{print $5}' | sort -u"); $arpMacs = array_filter(explode("\n", trim($arpOutput))); @@ -283,7 +296,8 @@ function getEthernetClients(): int { return count($clients); } -function formatClientLabel($clientCount) { +function formatClientLabel($clientCount) +{ return $clientCount === 1 ? 'client' : 'clients'; } @@ -300,7 +314,8 @@ function formatClientLabel($clientCount) { * - fallback * @return string */ -function getConnectionType() { +function getConnectionType(): string +{ // get the interface associated with the default route $interface = trim(shell_exec("ip route show default | awk '{print $5}'")); @@ -325,6 +340,29 @@ function getConnectionType() { return "other ($interface)"; } +/** + * Returns a fontawesome icon associated with a connection + * type/class + * + * @param $type + * @return string + */ +function getConnectionIcon($type): string +{ + switch (strtolower($type)) { + case 'ethernet': + return 'fa-ethernet'; + case 'wireless': + return 'fa-wifi'; + case 'tethering': + return 'fa-mobile-alt'; + case 'cellular': + return 'fa-broadcast-tower'; + default: + return 'fa-question-circle'; // unknown + } +} + /** * Renders a URL for an svg solid line representing the associated * connection type @@ -346,6 +384,30 @@ function renderConnection(string $connectionType): string return sprintf('app/img/solid.php?joint&%s&out', $device); } +/** + * Renders a URL for an svg solid line representing associated + * client connection(s) + * + * @param int $wirelessClients + * @param int $ethernetClients + * @return string + */ +function renderClientConnections(int $wirelessClients, int $ethernetClients): string +{ + $devices = []; + + if ($wirelessClients > 0) { + $devices[] = 'device-1&out'; + } + if ($ethernetClients > 0) { + $devices[] = 'device-2&out'; + } + return empty($devices) ? '' : sprintf( + 'Client connections', + implode('&', $devices) + ); +} + /** * Handles dashboard page actions * From 34f7563bed845862f1725b6c4182bef5b0342965 Mon Sep 17 00:00:00 2001 From: billz Date: Mon, 17 Mar 2025 10:25:04 -0700 Subject: [PATCH 29/54] Replace static placeholder with renderClientConnections --- templates/dashboard.php | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/templates/dashboard.php b/templates/dashboard.php index df0a3409..ccfd3ed8 100755 --- a/templates/dashboard.php +++ b/templates/dashboard.php @@ -43,7 +43,7 @@
- +
@@ -98,9 +98,7 @@ - - - +
@@ -114,7 +112,7 @@
- +
@@ -141,8 +139,7 @@
- - +
From 39cc92853ae17459ae810da56e5c2fdceac3c804 Mon Sep 17 00:00:00 2001 From: billz Date: Mon, 17 Mar 2025 10:32:32 -0700 Subject: [PATCH 30/54] Set z-index for solid + dashed-lines --- app/css/all.css | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/app/css/all.css b/app/css/all.css index 23d869b9..7f0013a9 100644 --- a/app/css/all.css +++ b/app/css/all.css @@ -477,7 +477,6 @@ textarea.plugin-log { object-fit: contain; padding: 1rem; left: 112px; - z-index: 0; } .dashed-lines-right, @@ -485,6 +484,14 @@ textarea.plugin-log { left: -80px; } +.solid-lines, .solid-lines-right { + z-index: 3; +} + +.dashed-lines, .dashed-lines-right { + z-index 0; +} + .device-status { display: flex; flex-wrap: wrap; From ed47a41c9c15afa5b73ae91cf82db6dd6c841660 Mon Sep 17 00:00:00 2001 From: billz Date: Mon, 17 Mar 2025 11:38:17 -0700 Subject: [PATCH 31/54] Initial commit --- src/RaspAP/UI/Dashboard.php | 332 ++++++++++++++++++++++++++++++++++++ 1 file changed, 332 insertions(+) create mode 100644 src/RaspAP/UI/Dashboard.php diff --git a/src/RaspAP/UI/Dashboard.php b/src/RaspAP/UI/Dashboard.php new file mode 100644 index 00000000..d4065dda --- /dev/null +++ b/src/RaspAP/UI/Dashboard.php @@ -0,0 +1,332 @@ + + * @license https://github.com/raspap/raspap-webgui/blob/master/LICENSE + */ + +namespace RaspAP\UI; + +class Dashboard { + + private string $firewallConfig; + + public function __construct() { + $this->firewallConfig = RASPI_CONFIG.'/networking/firewall.conf'; + } + + /* + * Returns the management page for an associated VPN + * + * @param string $interface + * @return string + */ + public function getVpnManged(?string $interface = null): ?string + { + return match ($interface) { + 'wg0' => 'wg_conf', + 'tun0' => 'openvpn_conf', + 'tailscale0' => 'plugin__Tailscale', + default => null, + }; + } + + /* + * Parses output of iw, extracts frequency (MHz) and classifies + * it as 2.4 or 5 GHz. Returns null if not found + * + * @param string $interface + * @return string frequency + */ + public function getFrequencyBand(string $interface): ?string + { + $output = shell_exec("iw dev " . escapeshellarg($interface) . " info 2>/dev/null"); + if (!$output) { + return null; + } + + if (preg_match('/channel\s+\d+\s+\((\d+)\s+MHz\)/', $output, $matches)) { + $frequency = (int)$matches[1]; + + if ($frequency >= 2400 && $frequency < 2500) { + return "2.4"; + } elseif ($frequency >= 5000 && $frequency < 6000) { + return "5"; + } + } + return null; + } + + /* + * Aggregate function that fetches output of ip and calls + * functions to parse output into discreet network properties + * + * @param string $interface + * @return array + */ + public function getInterfaceDetails(string $interface): array + { + $output = shell_exec('ip a show ' . escapeshellarg($interface)); + if (!$output) { + return [ + 'mac' => _('No MAC Address Found'), + 'ipv4' => 'None', + 'ipv4_netmask' => '-', + 'ipv6' => _('No IPv6 Address Found'), + 'state' => 'unknown' + ]; + } + $cleanOutput = preg_replace('/\s\s+/', ' ', implode(' ', explode("\n", $output))); + + return [ + 'mac' => $this->getMacAddress($cleanOutput), + 'ipv4' => $this->getIPv4Addresses($cleanOutput), + 'ipv4_netmask' => $this->getIPv4Netmasks($cleanOutput), + 'ipv6' => $this->getIPv6Addresses($cleanOutput), + 'state' => $this->getInterfaceState($cleanOutput), + ]; + } + + private function getMacAddress(string $output): string + { + return preg_match('/link\/ether ([0-9a-f:]+)/i', $output, $matches) ? $matches[1] : _('No MAC Address Found'); + } + + private function getIPv4Addresses(string $output): string + { + if (!preg_match_all('/inet (\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})\/([0-3][0-9])/i', $output, $matches, PREG_SET_ORDER)) { + return 'None'; + } + + $addresses = array_column($matches, 1); + return implode(' ', $addresses); + } + + private function getIPv4Netmasks(string $output): string + { + if (!preg_match_all('/inet (\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})\/([0-3][0-9])/i', $output, $matches, PREG_SET_ORDER)) { + return '-'; + } + + $netmasks = array_map(fn($match) => long2ip(-1 << (32 - (int)$match[2])), $matches); + return implode(' ', $netmasks); + } + + private function getIPv6Addresses(string $output): string + { + return preg_match_all('/inet6 ([a-f0-9:]+)/i', $output, $matches) && isset($matches[1]) + ? implode(' ', $matches[1]) + : _('No IPv6 Address Found'); + } + + private function getInterfaceState(string $output): string + { + return preg_match('/state (UP|DOWN)/i', $output, $matches) ? $matches[1] : 'unknown'; + } + + public function getWirelessDetails(string $interface): array + { + $output = shell_exec('iw dev ' . escapeshellarg($interface) . ' info'); + if (!$output) { + return ['bssid' => '-', 'ssid' => '-']; + } + $cleanOutput = preg_replace('/\s\s+/', ' ', trim($output)); // Fix here + + return [ + 'bssid' => $this->getConnectedBSSID($cleanOutput), + 'ssid' => $this->getSSID($cleanOutput), + ]; + } + + private function getConnectedBSSID(string $output): string + { + return preg_match('/Connected to (([0-9A-Fa-f]{2}:){5}([0-9A-Fa-f]{2}))/i', $output, $matches) + ? $matches[1] + : '-'; + } + + private function getSSID(string $output): string + { + return preg_match('/ssid ([^\n\s]+)/i', $output, $matches) + ? $matches[1] + : '-'; + } + + /* + * Parses the output of iw to obtain a list of wireless clients + * + * @return integer $clientCount + */ + public function getWirelessClients() + { + exec('iw dev wlan0 station dump', $output, $status); + + if ($status !== 0) { + return 0; + } + // enumerate 'station' entries (each represents a wireless client) + $clientCount = 0; + foreach ($output as $line) { + if (strpos($line, 'Station') === 0) { + $clientCount++; + } + } + return $clientCount; + } + + /* + * Retrieves ethernet neighbors from ARP cache, parses DHCP leases + * to find matching MAC addresses and returns only clients that + * exist in both sources + * + * @return int $clients + */ + public function getEthernetClients(): int + { + $arpOutput = shell_exec("ip neigh show | awk '{print $5}' | sort -u"); + $arpMacs = array_filter(explode("\n", trim($arpOutput))); + + $leaseFile = RASPI_DNSMASQ_LEASES; + $dhcpMacs = []; + + if (file_exists($leaseFile)) { + $leases = file($leaseFile, FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES); + foreach ($leases as $lease) { + $parts = explode(' ', $lease); + if (isset($parts[1])) { + $dhcpMacs[] = $parts[1]; // MAC address from DHCP leases + } + } + } + // filter ARP results to include only DHCP clients + $clients = array_intersect($arpMacs, $dhcpMacs); + return count($clients); + } + + public function formatClientLabel($clientCount) + { + return $clientCount === 1 ? 'client' : 'clients'; + } + + /* + * Determines the device's primary connection type by + * parsing the output of ip route; the interface listed + * as the default gateway is used for internet connectivity. + * + * The following interface classifications are assumed: + * - ethernet (eth0, en*) + * - wireless (wlan0, wlan1, wlp*) + * - tethered USB (usb*, eth1) + * - cellular (ppp0, wwan0, wwp*) + * - fallback + * @return string + */ + public function getConnectionType(): string + { + // get the interface associated with the default route + $interface = trim(shell_exec("ip route show default | awk '{print $5}'")); + + if (empty($interface)) { + return 'unknown'; + } + // classify interface type + if (preg_match('/^eth\d+|enp\d+s\d+/', $interface)) { + return 'ethernet'; + } + if (preg_match('/^wlan\d+|wlp\d+s\d+/', $interface)) { + return 'wireless'; + } + if (preg_match('/^usb\d+|eth1$/', $interface)) { + return 'tethering'; + } + if (preg_match('/^ppp\d+|wwan\d+|wwp\d+s\d+/', $interface)) { + return 'cellular'; + } + + // if none match, return the interface name as a fallback + return "other ($interface)"; + } + + /** + * Returns a fontawesome icon associated with a connection + * type/class + * + * @param $type + * @return string + */ + public function getConnectionIcon($type): string + { + switch (strtolower($type)) { + case 'ethernet': + return 'fa-ethernet'; + case 'wireless': + return 'fa-wifi'; + case 'tethering': + return 'fa-mobile-alt'; + case 'cellular': + return 'fa-broadcast-tower'; + default: + return 'fa-question-circle'; // unknown + } + } + + /** + * Retrieves the firewall's current status + * + * @return bool status + */ + public function firewallEnabled(): bool + { + $conf = array(); + if (file_exists($this->firewallConfig) ) { + $conf = parse_ini_file($this->firewallConfig); + } + if ( isset($conf["firewall-enable"]) ) { + return true; + } + return false; + } + + /** + * Handles dashboard page actions + * + * @param string $state + * @param array $post + * @param object $status + * @param string $interface + */ + public function handlePageAction(string $state, array $post, $status, string $interface): object + { + if (!RASPI_MONITOR_ENABLED) { + if (isset($post['ifdown_wlan0'])) { + if ($state === 'up') { + $status->addMessage(sprintf(_('Interface %s is going %s'), $interface, _('down')), 'warning'); + exec('sudo ip link set ' .escapeshellarg($interface). ' down'); + $status->addMessage(sprintf(_('Interface %s is %s'), $interface, _('down')), 'success'); + } elseif ($details['state'] === 'unknown') { + $status->addMessage(_('Interface state unknown'), 'danger'); + } else { + $status->addMessage(sprintf(_('Interface %s is already %s'), $interface, _('down')), 'warning'); + } + } elseif (isset($post['ifup_wlan0'])) { + if ($state === 'down') { + $status->addMessage(sprintf(_('Interface %s is going %s'), $interface, _('up')), 'warning'); + exec('sudo ip link set ' .escapeshellarg($interface). ' up'); + exec('sudo ip -s a f label ' .escapeshellarg($interface)); + usleep(250000); + $status->addMessage(sprintf(_('Interface %s is %s'), $interface, _('up')), 'success'); + } elseif ($state === 'unknown') { + $status->addMessage(_('Interface state unknown'), 'danger'); + } else { + $status->addMessage(sprintf(_('Interface %s is already %s'), $interface, _('up')), 'warning'); + } + } + return $status; + } + } + +} + From c00f006cdd60ab136d2f9e9d0277462f447b68f1 Mon Sep 17 00:00:00 2001 From: billz Date: Mon, 17 Mar 2025 11:41:22 -0700 Subject: [PATCH 32/54] Migrate inline functions to class methods in RaspAP\UI --- includes/dashboard.php | 328 +++-------------------------------------- 1 file changed, 19 insertions(+), 309 deletions(-) diff --git a/includes/dashboard.php b/includes/dashboard.php index 9a269a00..b2c022a4 100755 --- a/includes/dashboard.php +++ b/includes/dashboard.php @@ -10,8 +10,9 @@ require_once 'includes/functions.php'; function DisplayDashboard(): void { // instantiate RaspAP objects - $status = new \RaspAP\Messages\StatusMessage; $system = new \RaspAP\System\Sysinfo; + $dashboard = new \RaspAP\UI\Dashboard; + $status = new \RaspAP\Messages\StatusMessage; $pluginManager = \RaspAP\Plugins\PluginManager::getInstance(); // set AP and client interface session vars @@ -24,15 +25,14 @@ function DisplayDashboard(): void $hostapd = $system->hostapdStatus(); $adblock = $system->adBlockStatus(); $vpn = $system->getActiveVpnInterface(); - $frequency = getFrequencyBand($interface); - $details = getInterfaceDetails($interface); - $wireless = getWirelessDetails($interface); - $connectedBSSID = getConnectedBSSID($interface); - $connectionType = getConnectionType(); - $connectionIcon = getConnectionIcon($connectionType); + $frequency = $dashboard->getFrequencyBand($interface); + $details = $dashboard->getInterfaceDetails($interface); + $wireless = $dashboard->getWirelessDetails($interface); + $connectionType = $dashboard->getConnectionType(); + $connectionIcon = $dashboard->getConnectionIcon($connectionType); $state = strtolower($details['state']); - $wirelessClients = getWirelessClients(); - $ethernetClients = getEthernetClients(); + $wirelessClients = $dashboard->getWirelessClients(); + $ethernetClients = $dashboard->getEthernetClients(); $totalClients = $wirelessClients + $ethernetClients; $plugins = $pluginManager->getInstalledPlugins(); $arrHostapdConf = parse_ini_file(RASPI_CONFIG.'/hostapd.ini'); @@ -40,9 +40,9 @@ function DisplayDashboard(): void // handle page actions if (!empty($_POST)) { - $status = handlePageAction($state, $_POST, $status, $interface); + $status = $dashboard->handlePageAction($state, $_POST, $status, $interface); // refresh interface details + state - $details = getInterfaceDetails($interface); + $details = $dashboard->getInterfaceDetails($interface); $state = strtolower($details['state']); } @@ -57,17 +57,21 @@ function DisplayDashboard(): void $bridgedStatus = ($bridgedEnable == 1) ? "active" : ""; $hostapdStatus = ($hostapd[0] == 1) ? "active" : ""; $adblockStatus = ($adblock == true) ? "active" : ""; - $wirelessClientLabel = $wirelessClients. ' WLAN '.formatClientLabel($wirelessClients); - $ethernetClientLabel = $ethernetClients. ' LAN '.formatClientLabel($ethernetClients); + $wirelessClientLabel = $wirelessClients. ' WLAN '.$dashboard->formatClientLabel($wirelessClients); + $ethernetClientLabel = $ethernetClients. ' LAN '.$dashboard->formatClientLabel($ethernetClients); + $freq5active = $freq24active = ""; $varName = "freq" . str_replace('.', '', $frequency) . "active"; $$varName = "active"; $vpnStatus = $vpn ? "active" : "inactive"; if ($vpn) { - $vpnManaged = getVpnManged($vpn); + $vpnManaged = $dashboard->getVpnManged($vpn); } + $firewallStatus = ""; $firewallInstalled = array_filter($plugins, fn($p) => str_ends_with($p, 'Firewall')) ? true : false; if (!$firewallInstalled) { $firewallUnavailable = ''; + } else { + $firewallStatus = ($dashboard->firewallEnabled() == true) ? "active" : ""; } echo renderTemplate( @@ -82,12 +86,11 @@ function DisplayDashboard(): void "vpnStatus", "vpnManaged", "firewallUnavailable", + "firewallStatus", "ipv4Address", "ipv4Netmask", - "ipv6Address", "macAddress", "ssid", - "bssid", "frequency", "freq5active", "freq24active", @@ -107,262 +110,6 @@ function DisplayDashboard(): void ); } -/* - * Returns the management page for an associated VPN - * - * @param string $interface - * @return string - * @todo Determine if VPN provider is active - */ -function getVpnManged(?string $interface = null): ?string -{ - return match ($interface) { - 'wg0' => 'wg_conf', - 'tun0' => 'openvpn_conf', - 'tailscale0' => 'plugin__Tailscale', - default => null, - }; -} - -/* - * Parses output of iw, extracts frequency (MHz) and classifies - * it as 2.4 or 5 GHz. Returns null if not found - * - * @param string $interface - * @return string frequency - */ -function getFrequencyBand(string $interface): ?string -{ - $output = shell_exec("iw dev " . escapeshellarg($interface) . " info 2>/dev/null"); - if (!$output) { - return null; - } - - if (preg_match('/channel\s+\d+\s+\((\d+)\s+MHz\)/', $output, $matches)) { - $frequency = (int)$matches[1]; - - if ($frequency >= 2400 && $frequency < 2500) { - return "2.4"; - } elseif ($frequency >= 5000 && $frequency < 6000) { - return "5"; - } - } - return null; -} - -/* - * Aggregate function that fetches output of ip and calls - * functions to parse output into discreet network properties - * - * @param string $interface - * @return array - */ -function getInterfaceDetails(string $interface): array -{ - $output = shell_exec('ip a show ' . escapeshellarg($interface)); - if (!$output) { - return [ - 'mac' => _('No MAC Address Found'), - 'ipv4' => 'None', - 'ipv4_netmask' => '-', - 'ipv6' => _('No IPv6 Address Found'), - 'state' => 'unknown' - ]; - } - $cleanOutput = preg_replace('/\s\s+/', ' ', implode(' ', explode("\n", $output))); - - return [ - 'mac' => getMacAddress($cleanOutput), - 'ipv4' => getIPv4Addresses($cleanOutput), - 'ipv4_netmask' => getIPv4Netmasks($cleanOutput), - 'ipv6' => getIPv6Addresses($cleanOutput), - 'state' => getInterfaceState($cleanOutput), - ]; -} - -function getMacAddress(string $output): string -{ - return preg_match('/link\/ether ([0-9a-f:]+)/i', $output, $matches) ? $matches[1] : _('No MAC Address Found'); -} - -function getIPv4Addresses(string $output): string -{ - if (!preg_match_all('/inet (\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})\/([0-3][0-9])/i', $output, $matches, PREG_SET_ORDER)) { - return 'None'; - } - - $addresses = array_column($matches, 1); - return implode(' ', $addresses); -} - -function getIPv4Netmasks(string $output): string -{ - if (!preg_match_all('/inet (\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})\/([0-3][0-9])/i', $output, $matches, PREG_SET_ORDER)) { - return '-'; - } - - $netmasks = array_map(fn($match) => long2ip(-1 << (32 - (int)$match[2])), $matches); - return implode(' ', $netmasks); -} - -function getIPv6Addresses(string $output): string -{ - return preg_match_all('/inet6 ([a-f0-9:]+)/i', $output, $matches) && isset($matches[1]) - ? implode(' ', $matches[1]) - : _('No IPv6 Address Found'); -} - -function getInterfaceState(string $output): string -{ - return preg_match('/state (UP|DOWN)/i', $output, $matches) ? $matches[1] : 'unknown'; -} - -function getWirelessDetails(string $interface): array -{ - $output = shell_exec('iw dev ' . escapeshellarg($interface) . ' info'); - if (!$output) { - return ['bssid' => '-', 'ssid' => '-']; - } - $cleanOutput = preg_replace('/\s\s+/', ' ', trim($output)); // Fix here - - return [ - 'bssid' => getConnectedBSSID($cleanOutput), - 'ssid' => getSSID($cleanOutput), - ]; -} - -function getConnectedBSSID(string $output): string -{ - return preg_match('/Connected to (([0-9A-Fa-f]{2}:){5}([0-9A-Fa-f]{2}))/i', $output, $matches) - ? $matches[1] - : '-'; -} - -function getSSID(string $output): string -{ - return preg_match('/ssid ([^\n\s]+)/i', $output, $matches) - ? $matches[1] - : '-'; -} - -/* - * Parses the output of iw to obtain a list of wireless clients - * - * @return integer $clientCount - */ -function getWirelessClients() -{ - exec('iw dev wlan0 station dump', $output, $status); - - if ($status !== 0) { - return 0; - } - // enumerate 'station' entries (each represents a wireless client) - $clientCount = 0; - foreach ($output as $line) { - if (strpos($line, 'Station') === 0) { - $clientCount++; - } - } - return $clientCount; -} - -/* - * Retrieves ethernet neighbors from ARP cache, parses DHCP leases - * to find matching MAC addresses and returns only clients that - * exist in both sources - * - * @return int $clients - */ -function getEthernetClients(): int -{ - $arpOutput = shell_exec("ip neigh show | awk '{print $5}' | sort -u"); - $arpMacs = array_filter(explode("\n", trim($arpOutput))); - - $leaseFile = RASPI_DNSMASQ_LEASES; - $dhcpMacs = []; - - if (file_exists($leaseFile)) { - $leases = file($leaseFile, FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES); - foreach ($leases as $lease) { - $parts = explode(' ', $lease); - if (isset($parts[1])) { - $dhcpMacs[] = $parts[1]; // MAC address from DHCP leases - } - } - } - // filter ARP results to include only DHCP clients - $clients = array_intersect($arpMacs, $dhcpMacs); - return count($clients); -} - -function formatClientLabel($clientCount) -{ - return $clientCount === 1 ? 'client' : 'clients'; -} - -/* - * Determines the device's primary connection type by - * parsing the output of ip route; the interface listed - * as the default gateway is used for internet connectivity. - * - * The following interface classifications are assumed: - * - ethernet (eth0, en*) - * - wireless (wlan0, wlan1, wlp*) - * - tethered USB (usb*, eth1) - * - cellular (ppp0, wwan0, wwp*) - * - fallback - * @return string - */ -function getConnectionType(): string -{ - // get the interface associated with the default route - $interface = trim(shell_exec("ip route show default | awk '{print $5}'")); - - if (empty($interface)) { - return 'unknown'; - } - // classify interface type - if (preg_match('/^eth\d+|enp\d+s\d+/', $interface)) { - return 'ethernet'; - } - if (preg_match('/^wlan\d+|wlp\d+s\d+/', $interface)) { - return 'wireless'; - } - if (preg_match('/^usb\d+|eth1$/', $interface)) { - return 'tethering'; - } - if (preg_match('/^ppp\d+|wwan\d+|wwp\d+s\d+/', $interface)) { - return 'cellular'; - } - - // if none match, return the interface name as a fallback - return "other ($interface)"; -} - -/** - * Returns a fontawesome icon associated with a connection - * type/class - * - * @param $type - * @return string - */ -function getConnectionIcon($type): string -{ - switch (strtolower($type)) { - case 'ethernet': - return 'fa-ethernet'; - case 'wireless': - return 'fa-wifi'; - case 'tethering': - return 'fa-mobile-alt'; - case 'cellular': - return 'fa-broadcast-tower'; - default: - return 'fa-question-circle'; // unknown - } -} - /** * Renders a URL for an svg solid line representing the associated * connection type @@ -408,41 +155,4 @@ function renderClientConnections(int $wirelessClients, int $ethernetClients): st ); } -/** - * Handles dashboard page actions - * - * @param string $state - * @param array $post - * @param object $status - * @param string $interface - */ -function handlePageAction(string $state, array $post, $status, string $interface): object -{ - if (!RASPI_MONITOR_ENABLED) { - if (isset($post['ifdown_wlan0'])) { - if ($state === 'up') { - $status->addMessage(sprintf(_('Interface %s is going %s'), $interface, _('down')), 'warning'); - exec('sudo ip link set ' .escapeshellarg($interface). ' down'); - $status->addMessage(sprintf(_('Interface %s is %s'), $interface, _('down')), 'success'); - } elseif ($details['state'] === 'unknown') { - $status->addMessage(_('Interface state unknown'), 'danger'); - } else { - $status->addMessage(sprintf(_('Interface %s is already %s'), $interface, _('down')), 'warning'); - } - } elseif (isset($post['ifup_wlan0'])) { - if ($state === 'down') { - $status->addMessage(sprintf(_('Interface %s is going %s'), $interface, _('up')), 'warning'); - exec('sudo ip link set ' .escapeshellarg($interface). ' up'); - exec('sudo ip -s a f label ' .escapeshellarg($interface)); - usleep(250000); - $status->addMessage(sprintf(_('Interface %s is %s'), $interface, _('up')), 'success'); - } elseif ($state === 'unknown') { - $status->addMessage(_('Interface state unknown'), 'danger'); - } else { - $status->addMessage(sprintf(_('Interface %s is already %s'), $interface, _('up')), 'warning'); - } - } - return $status; - } -} From 24b292bf33a93a8190c3788fda241ac97e33038b Mon Sep 17 00:00:00 2001 From: billz Date: Mon, 17 Mar 2025 11:42:20 -0700 Subject: [PATCH 33/54] Replace static color values w/ --raspap-* vars --- app/css/all.css | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/app/css/all.css b/app/css/all.css index 7f0013a9..6fe82e86 100644 --- a/app/css/all.css +++ b/app/css/all.css @@ -609,7 +609,6 @@ textarea.plugin-log { .client-type i { font-size: 1.5rem; color: var(--raspap-theme-color); - background: #fff; width: 45px; height: 45px; border-radius: 50%; @@ -622,7 +621,7 @@ textarea.plugin-log { .client-type i.badge-icon { font-size: 0.7rem; background: var(--raspap-theme-color); - color: white; + color: var(--raspap-offwhite); width: 20px; height: 20px; border: none; @@ -632,8 +631,8 @@ textarea.plugin-log { position: absolute; top: -5px; right: -5px; - background: #008281; - color: white; + background: var(--raspap-theme-color); + color: var(--raspap-offwhite); border-radius: 50%; width: 20px; height: 20px; From 7091a4016aef7a984172fd100aee4f334db79435 Mon Sep 17 00:00:00 2001 From: billz Date: Tue, 18 Mar 2025 00:53:29 -0700 Subject: [PATCH 34/54] Update media query to reflect markup changes, add .inactive --- app/css/all.css | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/app/css/all.css b/app/css/all.css index 6fe82e86..8268a8db 100644 --- a/app/css/all.css +++ b/app/css/all.css @@ -432,6 +432,7 @@ textarea.plugin-log { .connections-left i:last-child { margin-bottom: 0; + margin-left: 0.5rem; } .center-device { @@ -555,8 +556,17 @@ textarea.plugin-log { margin-right: 0.5rem; } +.inactive { + color: var(--raspap-text-light)!important; +} + +a.inactive:hover, +a.inactive:focus { + color: var(--raspap-text-light) !important; +} + @media (max-width: 1200px) { - .connection-item > span:not(.fa-stack) { + .connection-item a > span:not(.fa-stack) { display: none!important; } } From ae4e9be739ba370f7735ad9b701e3393841d1ae3 Mon Sep 17 00:00:00 2001 From: billz Date: Tue, 18 Mar 2025 00:53:59 -0700 Subject: [PATCH 35/54] Change default SSID to RaspAP (finally) --- config/hostapd.conf | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/config/hostapd.conf b/config/hostapd.conf index b88b5469..944ce151 100644 --- a/config/hostapd.conf +++ b/config/hostapd.conf @@ -4,7 +4,7 @@ ctrl_interface_group=0 beacon_int=100 auth_algs=1 wpa_key_mgmt=WPA-PSK -ssid=raspi-webgui +ssid=RaspAP channel=1 hw_mode=g wpa_passphrase=ChangeMe From a82b30179bc636d57fda06909aa78fd7272c22ae Mon Sep 17 00:00:00 2001 From: billz Date: Tue, 18 Mar 2025 00:55:56 -0700 Subject: [PATCH 36/54] Add device, clients active/inactive states --- includes/dashboard.php | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/includes/dashboard.php b/includes/dashboard.php index b2c022a4..c6e2d686 100755 --- a/includes/dashboard.php +++ b/includes/dashboard.php @@ -50,15 +50,18 @@ function DisplayDashboard(): void $ipv4Netmask = $details['ipv4_netmask']; $macAddress = $details['mac']; $ssid = $wireless['ssid']; - $ethernetActive = ($connectionType === 'ethernet') ? "active" : ""; - $wirelessActive = ($connectionType === 'wireless') ? "active" : ""; - $tetheringActive = ($connectionType === 'tethering') ? "active" : ""; - $cellularActive = ($connectionType === 'cellular') ? "active" : ""; + $ethernetActive = ($connectionType === 'ethernet') ? "active" : "inactive"; + $wirelessActive = ($connectionType === 'wireless') ? "active" : "inactive"; + $tetheringActive = ($connectionType === 'tethering') ? "active" : "inactive"; + $cellularActive = ($connectionType === 'cellular') ? "active" : "inactive"; $bridgedStatus = ($bridgedEnable == 1) ? "active" : ""; $hostapdStatus = ($hostapd[0] == 1) ? "active" : ""; $adblockStatus = ($adblock == true) ? "active" : ""; + $wirelessClientActive = ($wirelessClients > 0) ? "active" : "inactive"; $wirelessClientLabel = $wirelessClients. ' WLAN '.$dashboard->formatClientLabel($wirelessClients); + $ethernetClientActive = ($ethernetClients > 0) ? "active" : "inactive"; $ethernetClientLabel = $ethernetClients. ' LAN '.$dashboard->formatClientLabel($ethernetClients); + $totalClientsActive = ($totalClients > 0) ? "active": "inactive"; $freq5active = $freq24active = ""; $varName = "freq" . str_replace('.', '', $frequency) . "active"; $$varName = "active"; @@ -95,10 +98,13 @@ function DisplayDashboard(): void "freq5active", "freq24active", "wirelessClients", - "ethernetClients", "wirelessClientLabel", + "wirelessClientActive", + "ethernetClients", "ethernetClientLabel", + "ethernetClientActive", "totalClients", + "totalClientsActive", "connectionType", "connectionIcon", "ethernetActive", From 677e99ffd9649b13e2878f67759b166eba4dc125 Mon Sep 17 00:00:00 2001 From: billz Date: Tue, 18 Mar 2025 00:57:04 -0700 Subject: [PATCH 37/54] Update w/ relevant href links, indicate active/inactive states --- templates/dashboard.php | 64 +++++++++++++++++++++++------------------ 1 file changed, 36 insertions(+), 28 deletions(-) diff --git a/templates/dashboard.php b/templates/dashboard.php index ccfd3ed8..3b9912bb 100755 --- a/templates/dashboard.php +++ b/templates/dashboard.php @@ -38,21 +38,21 @@
-
- - +
+ +
-
- - +
+ +
-
- - +
+ +
-
- - +
+ +
Network connection @@ -110,14 +110,18 @@
- -
- -
+ + +
+ +
+
- - + + + +
@@ -125,18 +129,22 @@
- - - - - + + + + + + +
- - - - - + + + + + + +
From 8846b96905fec91c2c024a7775a03538f23035d0 Mon Sep 17 00:00:00 2001 From: billz Date: Tue, 18 Mar 2025 01:45:10 -0700 Subject: [PATCH 38/54] Update function mappings for absolute paths --- src/RaspAP/UI/Dashboard.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/RaspAP/UI/Dashboard.php b/src/RaspAP/UI/Dashboard.php index d4065dda..8b2aad59 100644 --- a/src/RaspAP/UI/Dashboard.php +++ b/src/RaspAP/UI/Dashboard.php @@ -27,9 +27,9 @@ class Dashboard { public function getVpnManged(?string $interface = null): ?string { return match ($interface) { - 'wg0' => 'wg_conf', - 'tun0' => 'openvpn_conf', - 'tailscale0' => 'plugin__Tailscale', + 'wg0' => '/wg_conf', + 'tun0' => '/openvpn_conf', + 'tailscale0' => '/plugin__Tailscale', default => null, }; } From ac926e84d7ce9e62e6e626ad6d1903a531e381a7 Mon Sep 17 00:00:00 2001 From: billz Date: Tue, 18 Mar 2025 01:45:38 -0700 Subject: [PATCH 39/54] Style tweak for fa-stack status-item --- app/css/all.css | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/app/css/all.css b/app/css/all.css index 8268a8db..d95c8390 100644 --- a/app/css/all.css +++ b/app/css/all.css @@ -543,6 +543,10 @@ textarea.plugin-log { width: 100%; } +.status-item .fa-stack { + width: 1.5em!important; +} + .connection-item>i { color: var(--raspap-text-light); } From 615f2abed18a8705eeca5322d84248f177eb7a6c Mon Sep 17 00:00:00 2001 From: billz Date: Tue, 18 Mar 2025 01:45:56 -0700 Subject: [PATCH 40/54] Minor: formatting --- templates/dashboard.php | 32 ++++++++++++++++---------------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/templates/dashboard.php b/templates/dashboard.php index 3b9912bb..5e863262 100755 --- a/templates/dashboard.php +++ b/templates/dashboard.php @@ -70,28 +70,28 @@
-
- - -
+
+ + +
-
- - -
+
+ + +
-
- - -
+
+ + +
-
- - -
+
+ + +
From cfb84353731faf7ffefaf1173a47632ab127b935 Mon Sep 17 00:00:00 2001 From: billz Date: Tue, 18 Mar 2025 02:13:14 -0700 Subject: [PATCH 41/54] Revise formatClientLabel() w/ ngettext --- includes/dashboard.php | 12 ++++++++++-- src/RaspAP/UI/Dashboard.php | 2 +- 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/includes/dashboard.php b/includes/dashboard.php index c6e2d686..ddf8ab93 100755 --- a/includes/dashboard.php +++ b/includes/dashboard.php @@ -58,9 +58,17 @@ function DisplayDashboard(): void $hostapdStatus = ($hostapd[0] == 1) ? "active" : ""; $adblockStatus = ($adblock == true) ? "active" : ""; $wirelessClientActive = ($wirelessClients > 0) ? "active" : "inactive"; - $wirelessClientLabel = $wirelessClients. ' WLAN '.$dashboard->formatClientLabel($wirelessClients); + $wirelessClientLabel = sprintf( + _('%d WLAN %s'), + $wirelessClients, + $dashboard->formatClientLabel($wirelessClients) + ); $ethernetClientActive = ($ethernetClients > 0) ? "active" : "inactive"; - $ethernetClientLabel = $ethernetClients. ' LAN '.$dashboard->formatClientLabel($ethernetClients); + $ethernetClientLabel = sprintf( + _('%d LAN %s'), + $ethernetClients, + $dashboard->formatClientLabel($ethernetClients) + ); $totalClientsActive = ($totalClients > 0) ? "active": "inactive"; $freq5active = $freq24active = ""; $varName = "freq" . str_replace('.', '', $frequency) . "active"; diff --git a/src/RaspAP/UI/Dashboard.php b/src/RaspAP/UI/Dashboard.php index 8b2aad59..73d515c2 100644 --- a/src/RaspAP/UI/Dashboard.php +++ b/src/RaspAP/UI/Dashboard.php @@ -208,7 +208,7 @@ class Dashboard { public function formatClientLabel($clientCount) { - return $clientCount === 1 ? 'client' : 'clients'; + return ngettext('client', 'clients', $clientCount); } /* From e3f04192b80589810ecb0a6fee6abd9e1d18c1f0 Mon Sep 17 00:00:00 2001 From: billz Date: Tue, 18 Mar 2025 02:14:02 -0700 Subject: [PATCH 42/54] Replace static labels w/ gettext() for locale support --- templates/dashboard.php | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/templates/dashboard.php b/templates/dashboard.php index 5e863262..0ccc5dc0 100755 --- a/templates/dashboard.php +++ b/templates/dashboard.php @@ -61,10 +61,10 @@
<?php echo htmlspecialchars($revision, ENT_QUOTES); ?>
-
IP address:
-
Netmask:
-
MAC address:
-
SSID:
+
:
+
:
+
:
+
:
@@ -103,8 +103,8 @@
- 5G - 2.4G + +
From d5cc80d1f2dac9c8761aee3efc0555b728c66947 Mon Sep 17 00:00:00 2001 From: billz Date: Tue, 18 Mar 2025 02:15:09 -0700 Subject: [PATCH 43/54] Update en_US locale w/ new dashboard msgs + compile .mo --- locale/en_US/LC_MESSAGES/messages.mo | Bin 43019 -> 44957 bytes locale/en_US/LC_MESSAGES/messages.po | 49 ++++++++++++++++++++++++--- 2 files changed, 45 insertions(+), 4 deletions(-) diff --git a/locale/en_US/LC_MESSAGES/messages.mo b/locale/en_US/LC_MESSAGES/messages.mo index d1c38e1f3fe2e4aea23d38c09db8dde0ac69c255..076293f3307cb61db00e114649efa89e3f370ab2 100644 GIT binary patch literal 44957 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 LQHB5CA658226u~r delta 11441 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 A<^TWy diff --git a/locale/en_US/LC_MESSAGES/messages.po b/locale/en_US/LC_MESSAGES/messages.po index aa887cba..ce2b47d1 100644 --- a/locale/en_US/LC_MESSAGES/messages.po +++ b/locale/en_US/LC_MESSAGES/messages.po @@ -25,8 +25,8 @@ msgstr "RaspAP Wifi Configuration Portal" msgid "Toggle navigation" msgstr "Toggle navigation" -msgid "RaspAP Wifi Portal" -msgstr "RaspAP Wifi Portal" +msgid "RaspAP Admin Panel" +msgstr "RaspAP Admin Panel" msgid "Dashboard" msgstr "Dashboard" @@ -244,8 +244,8 @@ msgstr "Frequency" msgid "Link Quality" msgstr "Link Quality" -msgid "Information provided by ip and iw and from system" -msgstr "Information provided by ip and iw and from system" +msgid "Information provided by raspap.system" +msgstr "Information provided by raspap.system" msgid "No MAC Address Found" msgstr "No MAC Address Found" @@ -286,6 +286,47 @@ msgstr "Client: Ethernet cable" msgid "Ethernet" msgstr "Ethernet" +msgid "Repeater" +msgstr "Repeater" + +msgid "Tethering" +msgstr "Tethering" + +msgid "Cellular" +msgstr "Cellular" + +msgid "AP" +msgstr "AP" + +msgid "Bridged" +msgstr "Bridged" + +msgid "Adblock" +msgstr "Adblock" + +msgid "VPN" +msgstr "VPN" + +msgid "Firewall" +msgstr "Firewall" + +msgid "Netmask" +msgstr "Netmask" + +msgid "5G" +msgstr "5G" + +msgid "2.4G" +msgstr "2.4G" + +msgid "%d WLAN %s" +msgstr "%d WLAN %s" + +msgid "client" +msgid_plural "clients" +msgstr[0] "client" +msgstr[1] "clients" + msgid "Client: Smartphone (USB tethering)" msgstr "Client: Smartphone (USB tethering)" From 5ce06c62140b31d33a8acc02a73045e120d826ad Mon Sep 17 00:00:00 2001 From: billz Date: Tue, 18 Mar 2025 03:20:46 -0700 Subject: [PATCH 44/54] Revise dashed svg stroke width, color --- app/img/dashed.svg | 6 +++--- app/img/right-dashed.svg | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/app/img/dashed.svg b/app/img/dashed.svg index 01415d4c..6d6ea39f 100644 --- a/app/img/dashed.svg +++ b/app/img/dashed.svg @@ -3,9 +3,9 @@ diff --git a/app/img/right-dashed.svg b/app/img/right-dashed.svg index 282f0eab..1c5c3244 100644 --- a/app/img/right-dashed.svg +++ b/app/img/right-dashed.svg @@ -3,9 +3,9 @@ From ab77af9e5d39f43ddc54e6841831abdfd4967451 Mon Sep 17 00:00:00 2001 From: billz Date: Tue, 18 Mar 2025 03:22:03 -0700 Subject: [PATCH 45/54] Update firewallEnabled() config check --- src/RaspAP/UI/Dashboard.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/RaspAP/UI/Dashboard.php b/src/RaspAP/UI/Dashboard.php index 73d515c2..fca5b352 100644 --- a/src/RaspAP/UI/Dashboard.php +++ b/src/RaspAP/UI/Dashboard.php @@ -284,7 +284,7 @@ class Dashboard { if (file_exists($this->firewallConfig) ) { $conf = parse_ini_file($this->firewallConfig); } - if ( isset($conf["firewall-enable"]) ) { + if ($conf["firewall-enable"] == 1) { return true; } return false; From dfef9e5233e43ab5adae1844aca48c387a6076bd Mon Sep 17 00:00:00 2001 From: billz Date: Tue, 18 Mar 2025 03:23:25 -0700 Subject: [PATCH 46/54] Define firewallManaged when Firewall plugin is installed --- includes/dashboard.php | 2 ++ templates/dashboard.php | 16 +++++++++------- 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/includes/dashboard.php b/includes/dashboard.php index ddf8ab93..4cfe85f8 100755 --- a/includes/dashboard.php +++ b/includes/dashboard.php @@ -82,6 +82,7 @@ function DisplayDashboard(): void if (!$firewallInstalled) { $firewallUnavailable = ''; } else { + $firewallManaged = ''; $firewallStatus = ($dashboard->firewallEnabled() == true) ? "active" : ""; } @@ -98,6 +99,7 @@ function DisplayDashboard(): void "vpnManaged", "firewallUnavailable", "firewallStatus", + "firewallManaged", "ipv4Address", "ipv4Netmask", "macAddress", diff --git a/templates/dashboard.php b/templates/dashboard.php index 0ccc5dc0..160d1d68 100755 --- a/templates/dashboard.php +++ b/templates/dashboard.php @@ -93,13 +93,15 @@
-
- - - - - -
+ +
+ + + + + +
+
From f0a0c9228f7da635c271015ae54b7bd101150389 Mon Sep 17 00:00:00 2001 From: billz Date: Tue, 18 Mar 2025 04:11:47 -0700 Subject: [PATCH 47/54] Replace static labels w/ gettext() for locale support --- includes/footer.php | 4 ++-- templates/dashboard.php | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/includes/footer.php b/includes/footer.php index b12c0f1c..427d68a6 100755 --- a/includes/footer.php +++ b/includes/footer.php @@ -3,10 +3,10 @@
v | - Created by the RaspAP Team + %s'), 'https://github.com/RaspAP', _('RaspAP Team')); ?>
diff --git a/templates/dashboard.php b/templates/dashboard.php index 160d1d68..b5665a18 100755 --- a/templates/dashboard.php +++ b/templates/dashboard.php @@ -34,7 +34,7 @@
showMessages(); ?>

- +

From 6d6bacd6a12bd472c76398b7e60ce3e316516be4 Mon Sep 17 00:00:00 2001 From: billz Date: Tue, 18 Mar 2025 04:12:34 -0700 Subject: [PATCH 48/54] Update en_US locale msgs + compile .mo --- locale/en_US/LC_MESSAGES/messages.mo | Bin 44957 -> 45249 bytes locale/en_US/LC_MESSAGES/messages.po | 13 +++++++++++++ 2 files changed, 13 insertions(+) diff --git a/locale/en_US/LC_MESSAGES/messages.mo b/locale/en_US/LC_MESSAGES/messages.mo index 076293f3307cb61db00e114649efa89e3f370ab2..799128f8844724b6ba30de4743d4ba7139ef0641 100644 GIT binary patch delta 12159 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 delta 11957 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" +msgstr "Created by the %s" + +msgid "RaspAP Team" +msgstr "RaspAP Team" + +msgid "Get Insiders" +msgstr "Get Insiders" + #: includes/dhcp.php msgid "DHCP server settings" msgstr "DHCP server settings" From c987d2800de621f10c8b83ad5037afd0c1a1b639 Mon Sep 17 00:00:00 2001 From: billz Date: Tue, 18 Mar 2025 08:54:47 -0700 Subject: [PATCH 49/54] Fix php warning: define $firewallManaged --- includes/dashboard.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/includes/dashboard.php b/includes/dashboard.php index 4cfe85f8..f77c6e55 100755 --- a/includes/dashboard.php +++ b/includes/dashboard.php @@ -77,7 +77,7 @@ function DisplayDashboard(): void if ($vpn) { $vpnManaged = $dashboard->getVpnManged($vpn); } - $firewallStatus = ""; + $firewallManaged = $firewallStatus = ""; $firewallInstalled = array_filter($plugins, fn($p) => str_ends_with($p, 'Firewall')) ? true : false; if (!$firewallInstalled) { $firewallUnavailable = ''; From 52b20cb491659e8fc99256bd40c18e7bb9549760 Mon Sep 17 00:00:00 2001 From: billz Date: Tue, 18 Mar 2025 08:55:35 -0700 Subject: [PATCH 50/54] Revise getEthernetClients() w/ more robust method --- src/RaspAP/UI/Dashboard.php | 45 ++++++++++++++++++++++++------------- 1 file changed, 30 insertions(+), 15 deletions(-) diff --git a/src/RaspAP/UI/Dashboard.php b/src/RaspAP/UI/Dashboard.php index fca5b352..a08f6a49 100644 --- a/src/RaspAP/UI/Dashboard.php +++ b/src/RaspAP/UI/Dashboard.php @@ -182,28 +182,43 @@ class Dashboard { * to find matching MAC addresses and returns only clients that * exist in both sources * - * @return int $clients + * @return int $ethernetClients */ public function getEthernetClients(): int { - $arpOutput = shell_exec("ip neigh show | awk '{print $5}' | sort -u"); - $arpMacs = array_filter(explode("\n", trim($arpOutput))); + $ethernetClients = []; - $leaseFile = RASPI_DNSMASQ_LEASES; - $dhcpMacs = []; - - if (file_exists($leaseFile)) { - $leases = file($leaseFile, FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES); - foreach ($leases as $lease) { - $parts = explode(' ', $lease); - if (isset($parts[1])) { - $dhcpMacs[] = $parts[1]; // MAC address from DHCP leases + // Get ARP table entries and filter ethernet clients + $arpOutput = shell_exec("ip neigh show"); + if ($arpOutput) { + foreach (explode("\n", trim($arpOutput)) as $line) { + /* match both traditional interface names (eth0...n) and predictable names like + * enp3s0 (PCI ethernet) + * eno1 (onboard ethernet) + * ens160, etc. + * ...ignoring STALE entries + */ + if (preg_match('/^(\S+) dev (eth[0-9]+|en\w+) lladdr (\S+) (REACHABLE|DELAY|PROBE)/', $line, $matches)) { + $ethernetClients[$matches[3]] = $matches[1]; // MAC => IP } } } - // filter ARP results to include only DHCP clients - $clients = array_intersect($arpMacs, $dhcpMacs); - return count($clients); + + // compare against active DHCP leases + $leaseFile = RASPI_DNSMASQ_LEASES; + if (file_exists($leaseFile)) { + $leases = file($leaseFile, FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES); + $activeLeases = []; + foreach ($leases as $lease) { + $fields = preg_split('/\s+/', $lease); + if (count($fields) >= 3) { + $activeLeases[$fields[1]] = true; // MAC as key + } + } + // keep only clients that exist in the DHCP lease file + $ethernetClients = array_intersect_key($ethernetClients, $activeLeases); + } + return count($ethernetClients); } public function formatClientLabel($clientCount) From fd953e7a719d197d5cde766bc96a3221fbdbe949 Mon Sep 17 00:00:00 2001 From: billz Date: Tue, 18 Mar 2025 08:56:32 -0700 Subject: [PATCH 51/54] Remove obsolete svg file (replaced by device.php) --- app/img/rpi3b-themecolor.svg | 4447 ---------------------------------- 1 file changed, 4447 deletions(-) delete mode 100644 app/img/rpi3b-themecolor.svg diff --git a/app/img/rpi3b-themecolor.svg b/app/img/rpi3b-themecolor.svg deleted file mode 100644 index 095ab12a..00000000 --- a/app/img/rpi3b-themecolor.svg +++ /dev/null @@ -1,4447 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - From 5eca4c045b43db007f6420787c38937ba1f45c0d Mon Sep 17 00:00:00 2001 From: billz Date: Tue, 18 Mar 2025 12:10:47 -0700 Subject: [PATCH 52/54] Add event listener to activate tab on page load --- app/js/custom.js | 48 ++++++++++++++---------------------------------- 1 file changed, 14 insertions(+), 34 deletions(-) diff --git a/app/js/custom.js b/app/js/custom.js index 22f5a1dc..ed5ec2dd 100644 --- a/app/js/custom.js +++ b/app/js/custom.js @@ -994,42 +994,9 @@ function getCookie(cname) { // Define themes var themes = { "default": "custom.php", - "hackernews" : "hackernews.css", - "lightsout" : "lightsout.php", - "material-light" : "material-light.php", - "material-dark" : "material-dark.php", + "hackernews" : "hackernews.css" } -// Toggles the sidebar navigation. -// Overrides the default SB Admin 2 behavior -$("#sidebarToggleTopbar").on('click', function(e) { - $("body").toggleClass("sidebar-toggled"); - $(".sidebar").toggleClass("toggled d-none"); -}); - -// Overrides SB Admin 2 -$("#sidebarToggle, #sidebarToggleTop").on('click', function(e) { - var toggled = $(".sidebar").hasClass("toggled"); - // Persist state in cookie - setCookie('sidebarToggled',toggled, 90); -}); - -$(function() { - if ($(window).width() < 768) { - $('.sidebar').addClass('toggled'); - setCookie('sidebarToggled',false, 90); - } -}); - -$(window).on("load resize",function(e) { - if ($(window).width() > 768) { - $('.sidebar').removeClass('d-none d-md-block'); - if (getCookie('sidebarToggled') == 'false') { - $('.sidebar').removeClass('toggled'); - } - } -}); - // Adds active class to current nav-item $(window).bind("load", function() { var url = window.location; @@ -1038,6 +1005,19 @@ $(window).bind("load", function() { }).parent().addClass('active'); }); +// Sets focus on a specified tab +document.addEventListener("DOMContentLoaded", function () { + const params = new URLSearchParams(window.location.search); + const targetTab = params.get("tab"); + if (targetTab) { + let tabElement = document.querySelector(`[data-bs-toggle="tab"][href="#${targetTab}"]`); + if (tabElement) { + let tab = new bootstrap.Tab(tabElement); + tab.show(); + } + } +}); + $(document).ready(function() { const $htmlElement = $('html'); const $modeswitch = $('#night-mode'); From 66563c9d952cabd535da7d63295895e709ede4e4 Mon Sep 17 00:00:00 2001 From: billz Date: Tue, 18 Mar 2025 12:11:50 -0700 Subject: [PATCH 53/54] Update hrefs w/ tab param to load specific tabs on page load --- templates/dashboard.php | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/templates/dashboard.php b/templates/dashboard.php index b5665a18..b4c34cda 100755 --- a/templates/dashboard.php +++ b/templates/dashboard.php @@ -75,7 +75,7 @@
- +
@@ -131,22 +131,22 @@
From 304010db4015ad11ed878c174386a97c323941d5 Mon Sep 17 00:00:00 2001 From: billz Date: Tue, 18 Mar 2025 12:28:06 -0700 Subject: [PATCH 54/54] Update client lease ouput w/ human-readable timestamps --- templates/dhcp/clients.php | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/templates/dhcp/clients.php b/templates/dhcp/clients.php index c0d9d06d..14e9fa47 100644 --- a/templates/dhcp/clients.php +++ b/templates/dhcp/clients.php @@ -20,11 +20,17 @@ - - - + + + + - +