* Tue Apr 22 2025 Brian Read <brianr@koozali.org> 11.0.0-2.sme

- Add some styling to the hardware information and quick navigation
This commit is contained in:
Brian Read 2025-04-22 15:54:58 +01:00
parent 79899ec4a4
commit a369b719c5
7 changed files with 452 additions and 3 deletions

2
.gitignore vendored
View File

@ -1,4 +1,4 @@
*.rpm
*.log
*spec-20*
*.tar.gz
*.tar.xz

View File

@ -0,0 +1,41 @@
package SrvMngr::Controller::Hwinfo;
#----------------------------------------------------------------------
# heading : Investigation
# description : Hardware Info
# navigation : 4000 800
#----------------------------------------------------------------------
#----------------------------------------------------------------------
# name : hwinfo, method : get, url : /hwinfo, ctlact : Hwinfo#main
#
# routes : end
#----------------------------------------------------------------------
use strict;
use warnings;
use Mojo::Base 'Mojolicious::Controller';
use Locale::gettext;
use SrvMngr::I18N;
use SrvMngr qw(theme_list init_session);
#use SrvMngr::Model::Main;
sub main {
my $c = shift;
$c->app->log->info($c->log_req);
my $title = $c->l('hwinfo_panel');
my $hwinfo_height = $c->param('height') || '600';
my $hwinfo_full_html = qx(perl -T /etc/e-smith/web/functions/hwinfo);
my ($hwinfo_html) = $hwinfo_full_html =~ m{<body[^>]*>(.*?)</body>}si;
$hwinfo_html = '<head><link rel="stylesheet" href="css/hwinfo.css"></head>'.$hwinfo_html;
$hwinfo_html =~ s/<div class="indented">|<\/div>//g;
# Remove lines starting with the specified phrases
$hwinfo_html =~ s/^( SME Server|<BR>Copyright \(c\)).*\n//gmi;
open(my $fh, '>', '/root/hwinfo.txt') or die $!;
print $fh $hwinfo_html;
close($fh);
$c->stash(title => $title, hwinfo => $hwinfo_html, height => $hwinfo_height);
#die("$hwinfo_html");
$c->render(template => 'hwinfo');
} ## end sub main
1;

View File

@ -0,0 +1,2 @@
'hwi_FUll_description' => 'Full description',
'hwi_hwinfo' => 'Hardware Information'

View File

@ -0,0 +1,181 @@
/*
* Koozali SME Server Table Styling
*
* This CSS makes tables look good with colors matching the Koozali SME Server interface.
* Compatible with all modern browsers and IE9+.
*/
/* Basic table styling */
table.node {
border-collapse: collapse;
width: 100%;
margin: 20px 0;
-webkit-box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);
border: 1px solid #d5e5c0;
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Arial, sans-serif;
background-color: white;
max-width: 700px;
}
/* Table header styling */
table.node thead {
background-color: #e6f2d5;
border-bottom: 1px solid #d5e5c0;
}
/* Table header cells */
table.node thead td {
padding: 12px 15px;
font-weight: bold;
color: #006600;
}
/* Table data cells */
table.node td {
padding: 10px 15px;
border-bottom: 1px solid #e6f2d5;
line-height: 1.4;
word-wrap: break-word;
-ms-word-break: break-word;
word-break: break-word;
-webkit-hyphens: auto;
-ms-hyphens: auto;
hyphens: auto;
}
/* First column styling (labels) */
table.node td.first {
width: 25%;
font-weight: bold;
color: #333;
background-color: #e8f3e1;
}
/* Second column styling (values) */
table.node td.second {
width: 75%;
}
/* Zebra striping for better readability */
table.node tbody tr:nth-child(even) {
background-color: #fafdf7;
}
/* Hover effect for rows */
table.node tbody tr:hover {
background-color: #edf5e2;
}
/* Nested tables styling */
table.node table {
width: 100%;
border: none;
-webkit-box-shadow: none;
box-shadow: none;
margin: 0;
}
table.node table td {
padding: 4px 6px;
border: none;
background-color: transparent !important;
}
/* ID styling */
.id {
font-family: monospace;
background-color: #f5f9ef;
padding: 2px 4px;
border: 1px solid #d5e5c0;
border-radius: 3px;
font-size: 0.9em;
}
/* Help styling for dfn elements */
dfn {
cursor: help;
border-bottom: 1px dotted #006600;
font-style: normal;
}
/* Add some spacing between tables */
table.node + table.node {
margin-top: 30px;
}
/* Fix for older browsers */
@media screen and (-ms-high-contrast: active), (-ms-high-contrast: none) {
/* IE10+ specific styles */
table.node td {
word-break: break-all;
}
table.node td.first {
word-break: normal;
}
}
/* Make sure tables don't overflow on small screens */
@media (max-width: 768px) {
table.node {
font-size: 14px;
}
table.node td {
padding: 8px 10px;
}
table.node td.first {
width: 35%;
}
table.node td.second {
width: 65%;
}
}
/* Very small screens */
@media (max-width: 480px) {
table.node {
font-size: 13px;
}
table.node td {
padding: 6px 8px;
}
table.node td.first {
width: 40%;
}
table.node td.second {
width: 60%;
}
}
/* Print styles */
@media print {
table.node {
-webkit-box-shadow: none;
box-shadow: none;
border: 1px solid #999;
page-break-inside: avoid;
}
table.node + table.node {
margin-top: 20px;
}
table.node thead {
background-color: #f5f9ef !important;
-webkit-print-color-adjust: exact;
color-adjust: exact;
}
table.node td.first {
background-color: #f9fcf5 !important;
-webkit-print-color-adjust: exact;
color-adjust: exact;
}
}

View File

@ -0,0 +1,194 @@
/**
* Table Navigation Dropdown - JavaScript Only Solution for Mojolicious Sites
*
* This script automatically creates a dropdown menu to navigate between tables
* on a page without requiring any HTML modifications.
*
* Compatible with all modern browsers and IE11+.
*
* How to use:
* 1. Add this script to your Mojolicious site using a <script> tag
* 2. The script will automatically run when the page loads
* 3. A dropdown menu will be created at the top of the page
*/
(function() {
// Function to run when DOM is fully loaded
function initTableNavigation() {
// Find all tables with class 'node' (based on your HTML structure)
var tables = document.querySelectorAll('table.node');
if (!tables || tables.length === 0) {
console.log('No tables found with class "node"');
return;
}
// Create container for the dropdown
var navContainer = document.createElement('div');
navContainer.style.position = 'sticky';
navContainer.style.top = '0';
navContainer.style.backgroundColor = '#fff';
navContainer.style.padding = '10px 0';
navContainer.style.marginBottom = '20px';
navContainer.style.zIndex = '100';
navContainer.style.borderBottom = '1px solid #ddd';
navContainer.style.width = '300px';
// Create the select element
var select = document.createElement('select');
select.style.width = '100%';
select.style.padding = '10px';
select.style.fontSize = '16px';
select.style.border = '1px solid #ddd';
select.style.borderRadius = '4px';
select.style.backgroundColor = '#f8f8f8';
select.style.cursor = 'pointer';
// Add default option
var defaultOption = document.createElement('option');
defaultOption.value = '';
defaultOption.textContent = '-- Jump to a table --';
select.appendChild(defaultOption);
// Process each table and add to dropdown
for (var i = 0; i < tables.length; i++) {
var table = tables[i];
// Try to get table ID from the first row if it contains "id:"
var tableId = 'table-' + i;
var tableName = 'Table ' + (i + 1);
// Look for the ID in the table header
var idCell = table.querySelector('thead td.first');
var idValue = table.querySelector('thead td.second');
if (idCell && idValue && idCell.textContent.trim().toLowerCase() === 'id:') {
// Get the ID value (might be in a div with class 'id')
var idDiv = idValue.querySelector('.id');
if (idDiv) {
tableId = idDiv.textContent.trim();
tableName = tableId;
} else if (idValue.textContent.trim()) {
tableId = idValue.textContent.trim();
tableName = tableId;
}
}
// Try to get a better name from the description if available
var descRows = table.querySelectorAll('tbody tr');
for (var j = 0; j < descRows.length; j++) {
var descRow = descRows[j];
var descCell = descRow.querySelector('td.first');
var descValue = descRow.querySelector('td.second');
if (descCell && descValue &&
descCell.textContent.trim().toLowerCase().includes('description') &&
descValue.textContent.trim()) {
tableName = descValue.textContent.trim() + ' (' + tableName + ')';
break;
}
}
// Create a unique ID for the table if it doesn't have one
if (!table.id) {
// Clean the ID to make it valid for HTML
var safeId = tableId.replace(/[^a-z0-9]/gi, '_').toLowerCase();
table.id = safeId;
}
// Add option to dropdown
var option = document.createElement('option');
option.value = table.id;
option.textContent = tableName;
select.appendChild(option);
// Add scroll margin to the table
table.style.scrollMarginTop = '70px';
}
// Add event listener to the select element
if (select.addEventListener) {
// Modern browsers
select.addEventListener('change', handleSelectChange);
} else if (select.attachEvent) {
// IE8 and below
select.attachEvent('onchange', handleSelectChange);
}
// Add the select to the container
navContainer.appendChild(select);
// Insert the container at the top of the body or after the first heading
var heading = document.querySelector('h1, h2');
if (heading && heading.parentNode) {
heading.parentNode.insertBefore(navContainer, heading.nextSibling);
} else {
var body = document.body;
if (body.firstChild) {
body.insertBefore(navContainer, body.firstChild);
} else {
body.appendChild(navContainer);
}
}
}
// Function to handle select change
function handleSelectChange() {
var selectedValue = this.value;
if (selectedValue) {
var element = document.getElementById(selectedValue);
if (element) {
// Scroll to the selected element
scrollToElement(element);
// Highlight the selected table briefly
var originalBackground = element.style.backgroundColor || '';
element.style.backgroundColor = '#ffffd0';
// Use setTimeout for the highlight effect
setTimeout(function() {
element.style.backgroundColor = originalBackground;
}, 1500);
}
}
}
// Cross-browser scroll function
function scrollToElement(element) {
// Check if scrollIntoView is supported
if (element.scrollIntoView) {
// Try smooth scrolling if supported
try {
element.scrollIntoView({ behavior: 'smooth' });
} catch (error) {
// Fallback for browsers that don't support smooth scrolling
element.scrollIntoView();
}
} else {
// Manual scroll fallback
var rect = element.getBoundingClientRect();
var scrollTop = window.pageYOffset || document.documentElement.scrollTop;
var targetY = rect.top + scrollTop - 70; // 70px offset for the sticky header
window.scrollTo(0, targetY);
}
}
// Cross-browser DOM ready function
function ready(fn) {
if (document.readyState !== 'loading') {
fn();
} else if (document.addEventListener) {
document.addEventListener('DOMContentLoaded', fn);
} else {
document.attachEvent('onreadystatechange', function() {
if (document.readyState !== 'loading') {
fn();
}
});
}
}
// Initialize when DOM is ready
ready(initTableNavigation);
})();

View File

@ -0,0 +1,25 @@
% layout 'default', title => "Sme server 2 - Disk usage";
% content_for 'module' => begin
%= javascript 'js/hwinfo.js'
<div id='Hwinfo' class='module hwinfo-panel'>
% if (config->{debug} == 1) {
<pre>
%= dumper $c->current_route
%= dumper $c->stash('hwinfo')
</pre>
% }
% if ( stash 'error' ) {
<br><div class=sme-error>
%= $c->render_to_string(inline => stash 'error')
</div>
%}
<!--<h1>Legacy-<%#=l('hwi_hwinfo') %></h1><br>-->
% my $height = $c->stash('height') | '600';
% if ($height !~ /px$/) { $height = $height.'px';}
%== $c->stash('hwinfo');
</div>
%end

View File

@ -3,8 +3,8 @@
# Name: Jean-Paul Leclère
%define name smeserver-hwinfo
%define version 1.2
%define release 7
%define version 11.0.0
%define release 2
Summary: Harware info panel for SME Server.
Name: %{name}
@ -25,6 +25,12 @@ AutoReqProv: no
smeserver-hwinfo adds panel providing informations about server harware configuration
%changelog
* Tue Apr 22 2025 Brian Read <brianr@koozali.org> 11.0.0-2.sme
- Add some styling to the hardware information and quick navigation
* Tue Apr 22 2025 Brian Read <brianr@koozali.org> 11.0.0.0-1.sme
- Add in SM2 code, calling the FM (SM1) code without conversion
* Sun Sep 08 2024 fix-e-smith-pkg.sh by Trevor Batley <trevor@batley.id.au> 1.2-7.sme
- Fix e-smith references in smeserver-hwinfo [SME: 12732]