Compare commits
20 Commits
11_0_0-4_e
...
11_0_0-13_
Author | SHA1 | Date | |
---|---|---|---|
d16ea6a847 | |||
e70cc67430 | |||
b097acafab | |||
5d7655a709 | |||
a58df95aa9 | |||
251b454470 | |||
174d511899 | |||
4be8a1411f | |||
ba431a8a7d | |||
77a7849898 | |||
fb5b0942d6 | |||
5edc830f9b | |||
473cb57a47 | |||
55b85496d4 | |||
2fd6f8b630 | |||
a428e91c92 | |||
03955eecea | |||
891fc73ce3 | |||
e7d7b6afb8 | |||
1837bc9a18 |
59
README.md
59
README.md
@@ -17,6 +17,59 @@ Show list of outstanding bugs: [here](https://bugs.koozali.org/buglist.cgi?compo
|
||||
|
||||
## Description
|
||||
|
||||
<br />*This description has been generated by an LLM AI system and cannot be relied on to be fully correct.*
|
||||
*Once it has been checked, then this comment will be deleted*
|
||||
<br />
|
||||
The *smeserver-manager* is a web-based management interface for the SME Server (formerly known as e-smith server and gateway). SME Server is a Linux-based distribution designed for small to medium-sized enterprises, providing a wide range of network services and simplified server management.
|
||||
|
||||
It is based on the perl Mojolicious package. Mojolicious is a real-time web framework for Perl, which provides a range of functionalities that make it a powerful and flexible tool for web development.
|
||||
|
||||
### Features
|
||||
|
||||
#### Web-Based Management Interface:
|
||||
smeserver-manager provides an intuitive and user-friendly web interface that allows administrators to manage various aspects of the server without needing deep technical knowledge or command-line skills.
|
||||
|
||||
#### User and Group Management:
|
||||
Easily add, remove, and manage user accounts and groups. The interface simplifies creating email accounts, setting passwords, and configuring user permissions.
|
||||
|
||||
#### Network Configuration:
|
||||
Configures network settings such as IP addresses, DNS, DHCP, and gateway settings. The interface also provides options for setting up VPNs, remote access, and firewall rules.
|
||||
|
||||
#### File Sharing and Storage:
|
||||
Enables and manages file sharing services like Samba (for Windows file sharing) and NFS (for Unix/Linux file sharing). Administrators can easily create shared folders and manage permissions.
|
||||
|
||||
#### Email Services:
|
||||
Configure and manage email services, including setting up mail domains, user mailboxes, and SMTP/IMAP/POP3 settings. It also provides options for spam and virus filtering.
|
||||
|
||||
#### Web Services:
|
||||
Host and manage websites using the integrated web server (usually Apache). It supports virtual hosting, where multiple websites can be hosted on the same server.
|
||||
|
||||
#### Backup and Restore:
|
||||
Perform backups of essential data and server configurations. The interface provides options for scheduled backups and restoring from backup files.
|
||||
|
||||
#### Software Updates and Installation:
|
||||
Keep the server up-to-date with the latest security patches and software updates. The interface helps in installing and updating software packages and extensions.
|
||||
|
||||
#### Monitoring and Reporting:
|
||||
Monitor server performance and health. The interface provides logs, status reports, and alerts for various server components, including disk usage, network traffic, and system load.
|
||||
|
||||
|
||||
### Installation and Access
|
||||
|
||||
Typically, smeserver-manager is installed by default on SME Server. To access the interface:
|
||||
|
||||
Open a web browser on a device connected to the same network as the SME Server. Enter the server's IP address or hostname followed by /server-manager in the address bar (e.g., https://192.168.1.1/server-manager).
|
||||
You will be prompted to log in. Use the administrator credentials set during the SME Server installation.
|
||||
|
||||
### Benefits
|
||||
|
||||
Simplicity: Makes it easy for non-technical users to manage a server.
|
||||
Centralized Management: Provides a single point of control for various server functionalities.
|
||||
Efficiency: Saves time and reduces complexity in server management tasks.
|
||||
Security: Regular updates and built-in security features ensure the server remains secure.
|
||||
|
||||
### Considerations
|
||||
|
||||
Learning Curve: While designed to be user-friendly, some features may still require a basic understanding of server and network management concepts.
|
||||
Dependencies: Relies on specific packages and configurations of SME Server, and may not be directly applicable to other Linux distributions.
|
||||
|
||||
### Summary
|
||||
|
||||
SMEserver-manager is a powerful tool that brings simplicity and efficiency to server management for small to medium-sized enterprises. By providing a centralized, web-based interface, it allows administrators to manage users, network settings, file sharing, email services, web hosting, and more, all from a single location.
|
@@ -47,6 +47,9 @@ for my $event ( qw( smeserver-manager-update smanager-refresh bootstrap-console-
|
||||
|
||||
event_link('systemd-default', "smeserver-manager-update", '88');
|
||||
event_link('systemd-reload', "smeserver-manager-update", '89');
|
||||
templates2events("/etc/rsyslog.conf", "smeserver-manager-update");
|
||||
safe_symlink("restart",
|
||||
"root/etc/e-smith/events/smeserver-manager-update/services2adjust/rsyslog");
|
||||
|
||||
use esmith::Build::Backup qw(:all);
|
||||
backup_includes("smeserver-manager", qw(
|
||||
|
@@ -33,6 +33,8 @@ use esmith::I18N;
|
||||
|
||||
use Data::Dumper; # activate if DEBUG
|
||||
|
||||
binmode(STDOUT, ":encoding(UTF-8)");
|
||||
|
||||
my $navigation_ignore =
|
||||
"(\.\.?|Swttheme\.pm|Login\.pm|Request\.pm|Modules\.pm(-.*)?)";
|
||||
|
||||
@@ -46,131 +48,193 @@ my @files = grep (!/^${navigation_ignore}$/, readdir (FUNCTIONS));
|
||||
closedir FUNCTIONS;
|
||||
|
||||
my @langs = $i18n->availableLanguages();
|
||||
#my @langs = ('en', 'fr');
|
||||
#print Dumper(\@langs);
|
||||
#my @langs = ('tr'); #Temp override
|
||||
|
||||
|
||||
foreach my $lang (@langs)
|
||||
{
|
||||
my $long_lex = SMNGR_LIB.'/'.I18NMODULES."/General/general_$lang.lex";
|
||||
next unless ( -e $long_lex );
|
||||
my $long_lex = SMNGR_LIB.'/'.I18NMODULES."/General/general_$lang.lex";
|
||||
next unless ( -e $long_lex );
|
||||
|
||||
open(LEX, '<:encoding(UTF-8)', $long_lex)
|
||||
or die "Couldn't open ", $long_lex, " for reading.\n";
|
||||
my @gen_lex = <LEX>;
|
||||
close LEX;
|
||||
open(LEX, '<:encoding(UTF-8)', $long_lex)
|
||||
or die "Couldn't open ", $long_lex, " for reading.\n";
|
||||
my @gen_lex = <LEX>;
|
||||
close LEX;
|
||||
|
||||
foreach my $file (@files)
|
||||
{
|
||||
next if (-d SMNGR_LIB.'/'.WEBFUNCTIONS . "/$file");
|
||||
# next unless ( $file =~ m/D.*\.pm$/ );
|
||||
next unless ( $file =~ m/[A-Z].*\.pm$/ );
|
||||
|
||||
my $file2 = lc($file);
|
||||
$file2 =~ s/\.pm$//;
|
||||
|
||||
#--------------------------------------------------
|
||||
# extract heading, description and weight information
|
||||
# from Mojo controller
|
||||
#--------------------------------------------------
|
||||
open(SCRIPT, SMNGR_LIB.'/'.WEBFUNCTIONS . "/$file");
|
||||
my $heading = undef;
|
||||
my $description = undef;
|
||||
my $heading_weight = undef;
|
||||
my $description_weight = undef;
|
||||
my $menucat = undef;
|
||||
my $routes = undef;
|
||||
|
||||
while ( <SCRIPT> )
|
||||
#my @files = ('Portforwarding.pm'); #Temp override
|
||||
foreach my $file (@files)
|
||||
{
|
||||
$heading = $1 if (/^\s*#\s*heading\s*:\s*(.+?)\s*$/);
|
||||
$description = $1
|
||||
if (/^\s*#\s*description\s*:\s*(.+?)\s*$/);
|
||||
($heading_weight, $description_weight) = ($1, $2)
|
||||
if (/^\s*#\s*navigation\s*:\s*(\d+?)\s+(\d+?)\s*$/);
|
||||
$menucat = $1
|
||||
if (/^\s*#\s*menu\s*:\s*(.+?)\s*$/);
|
||||
next if (-d SMNGR_LIB.'/'.WEBFUNCTIONS . "/$file");
|
||||
# next unless ( $file =~ m/D.*\.pm$/ );
|
||||
next unless ( $file =~ m/[A-Z].*\.pm$/ );
|
||||
|
||||
last if (defined $heading and
|
||||
defined $description and
|
||||
defined $heading_weight and
|
||||
defined $description_weight and
|
||||
defined $menucat);
|
||||
my $file2 = lc($file);
|
||||
$file2 =~ s/\.pm$//;
|
||||
#--------------------------------------------------
|
||||
# extract heading, description and weight information
|
||||
# from Mojo controller
|
||||
#--------------------------------------------------
|
||||
open(SCRIPT, SMNGR_LIB.'/'.WEBFUNCTIONS . "/$file");
|
||||
my $heading = undef;
|
||||
my $description = undef;
|
||||
my $heading_weight = undef;
|
||||
my $description_weight = undef;
|
||||
my $menucat = undef;
|
||||
my $routes = undef;
|
||||
|
||||
# routes : end (stop before eof if 'menu' is not here before 'routes'!!!
|
||||
$routes = $1 if (/^\s*#\s*routes\s*:\s*(.+?)\s*$/);
|
||||
last if (defined $routes and $routes eq 'end');
|
||||
while ( <SCRIPT> )
|
||||
{
|
||||
$heading = $1 if (/^\s*#\s*heading\s*:\s*(.+?)\s*$/);
|
||||
$description = $1
|
||||
if (/^\s*#\s*description\s*:\s*(.+?)\s*$/);
|
||||
($heading_weight, $description_weight) = ($1, $2)
|
||||
if (/^\s*#\s*navigation\s*:\s*(\d+?)\s+(\d+?)\s*$/);
|
||||
$menucat = $1
|
||||
if (/^\s*#\s*menu\s*:\s*(.+?)\s*$/);
|
||||
|
||||
last if (defined $heading and
|
||||
defined $description and
|
||||
defined $heading_weight and
|
||||
defined $description_weight and
|
||||
defined $menucat);
|
||||
|
||||
# routes : end (stop before eof if 'menu' is not here before 'routes'!!!
|
||||
$routes = $1 if (/^\s*#\s*routes\s*:\s*(.+?)\s*$/);
|
||||
last if (defined $routes and $routes eq 'end');
|
||||
}
|
||||
close SCRIPT;
|
||||
|
||||
print "updating script $file for lang $lang\n"if DEBUG;
|
||||
my $navdb = $navdbs{$lang};
|
||||
my $navinfo = NAVDIR.'/'.NAVIGATIONDIR . "/navigation.$lang";
|
||||
$navdb ||= esmith::NavigationDB->open($navinfo);
|
||||
$navdb ||= esmith::NavigationDB->create($navinfo) or
|
||||
die "Couldn't create $navinfo\n";
|
||||
$navdbs{$lang} ||= $navdb;
|
||||
my $rec = $navdb->get($file2) ||
|
||||
$navdb->new_record($file2, { type => 'panel' } );
|
||||
|
||||
my @panel_lex = ();
|
||||
$long_lex = SMNGR_LIB.'/'.I18NMODULES.'/'.ucfirst($file2)."/${file2}_$lang.lex";
|
||||
if ( -e $long_lex ) {
|
||||
open(LEX, '<:encoding(UTF-8)', $long_lex)
|
||||
or die "Couldn't open ", $long_lex, " for reading.\n";
|
||||
@panel_lex = <LEX>;
|
||||
close LEX;
|
||||
}
|
||||
#Extract the prefix for this module
|
||||
my @keys = values @panel_lex; # Get all values from the array
|
||||
|
||||
my $i = 0; # Initialize the index
|
||||
my $found = 0; # Flag to check if the prefix was found
|
||||
my $prefix = "xx_"; # Probably never match!!
|
||||
|
||||
while ($i < @keys) { # Loop until we run out of entries
|
||||
my $extracted_value = $keys[$i] || ""; # The current entry
|
||||
#print("Extracted val: ".$extracted_value."\n");
|
||||
|
||||
# Extract prefix from the second value (up to and including the first underscore)
|
||||
#my ($prefix) = $second_value =~ /^'(.*?_)/; # Match everything up to and including the first underscore
|
||||
($prefix) = $extracted_value =~ /^'(.*?_)/; # Match everything up to and including the first underscore
|
||||
|
||||
if (defined $prefix) {
|
||||
$found = 1; # Set found flag to true
|
||||
last; # Exit the loop if prefix is found
|
||||
} else {
|
||||
#print("Extracted Val: " . $extracted_value . "\n");
|
||||
}
|
||||
|
||||
$i++; # Increment the index to check the next entry
|
||||
}
|
||||
|
||||
if (!$found) {
|
||||
print(STDERR "No valid prefix found in any entries: ".$file2." (".$lang.")\n"); # if DEBUG;
|
||||
$prefix = "xx_"; # Probably never match!!
|
||||
|
||||
}
|
||||
#print("Prefix: ".$prefix." ".$file2." (".$lang.")\n");
|
||||
|
||||
my %Lexicon = ();
|
||||
push(@panel_lex, @gen_lex);
|
||||
my $top_error = 0;
|
||||
|
||||
chomp @panel_lex;
|
||||
for (@panel_lex) {
|
||||
next unless $_; # first one empty
|
||||
my ($k, $v) = split / => /, $_;
|
||||
# errors on split to $v (use DEBUG to see)
|
||||
if ( $k and $v ) {
|
||||
$k =~ s/\'//g;
|
||||
$v =~ s/\'//g;
|
||||
$v =~ s/,$//g;
|
||||
$Lexicon{ lc($k) } = $v;
|
||||
} else {
|
||||
$k = "?" unless ($k);
|
||||
print STDERR "Error for $lang $file2 on $k \n" if DEBUG;
|
||||
$top_error++;
|
||||
}
|
||||
}
|
||||
if ( $top_error > 0) {
|
||||
if ( DEBUG ) {
|
||||
print STDERR "$top_error errors for $lang $file2\n";
|
||||
# print Dumper(\@panel_lex);
|
||||
# print Dumper(\%Lexicon);
|
||||
# exit 1;
|
||||
}
|
||||
}
|
||||
$heading = "" unless defined $heading;
|
||||
$description = "" unless defined $description;
|
||||
# Get the base language code from $lang
|
||||
my $base_lang = (split('-', $lang))[0];
|
||||
my $loc_heading = process_localization( \%Lexicon, $heading, $lang, $prefix );
|
||||
my $loc_description = process_localization( \%Lexicon, $description, $lang, $prefix );
|
||||
$loc_heading =~ s/^\s*(\w.*?)\s*$/$1/;
|
||||
$loc_description =~ s/^\s*(\w.*?)\s*$/$1/;
|
||||
|
||||
$rec->merge_props(
|
||||
Heading => $loc_heading,
|
||||
Description => $loc_description,
|
||||
HeadingWeight => localise( \%Lexicon, $heading_weight ),
|
||||
DescriptionWeight => localise( \%Lexicon, $description_weight ),
|
||||
MenuCat => (defined $menucat ? $menucat : 'A'));
|
||||
}
|
||||
close SCRIPT;
|
||||
|
||||
print "updating script $file for lang $lang\n" if DEBUG;
|
||||
#warn "trying to close for lang $lang\n";
|
||||
my $navdb = $navdbs{$lang};
|
||||
my $navinfo = NAVDIR.'/'.NAVIGATIONDIR . "/navigation.$lang";
|
||||
$navdb ||= esmith::NavigationDB->open($navinfo);
|
||||
$navdb ||= esmith::NavigationDB->create($navinfo) or
|
||||
die "Couldn't create $navinfo\n";
|
||||
$navdbs{$lang} ||= $navdb;
|
||||
my $rec = $navdb->get($file2) ||
|
||||
$navdb->new_record($file2, { type => 'panel' } );
|
||||
|
||||
my @panel_lex = ();
|
||||
$long_lex = SMNGR_LIB.'/'.I18NMODULES.'/'.ucfirst($file2)."/${file2}_$lang.lex";
|
||||
if ( -e $long_lex ) {
|
||||
open(LEX, '<:encoding(UTF-8)', $long_lex)
|
||||
or die "Couldn't open ", $long_lex, " for reading.\n";
|
||||
@panel_lex = <LEX>;
|
||||
close LEX;
|
||||
}
|
||||
|
||||
my %Lexicon = ();
|
||||
push(@panel_lex, @gen_lex);
|
||||
my $top_error = 0;
|
||||
|
||||
chomp @panel_lex;
|
||||
for (@panel_lex) {
|
||||
next unless $_; # first one empty
|
||||
my ($k, $v) = split / => /, $_;
|
||||
# errors on split to $v (use DEBUG to see)
|
||||
if ( $k and $v ) {
|
||||
$k =~ s/\'//g;
|
||||
$v =~ s/\'//g;
|
||||
$v =~ s/,$//g;
|
||||
$Lexicon{ $k } = $v;
|
||||
} else {
|
||||
$k = "?" unless ($k);
|
||||
print STDERR "Error for $lang $file2 on $k \n" if DEBUG;
|
||||
$top_error++;
|
||||
}
|
||||
}
|
||||
if ( $top_error > 0) {
|
||||
if ( DEBUG ) {
|
||||
print STDERR "$top_error errors for $lang $file2\n";
|
||||
# print Dumper(\@panel_lex);
|
||||
# print Dumper(\%Lexicon);
|
||||
# exit 1;
|
||||
}
|
||||
}
|
||||
|
||||
my $loc_heading = localise( \%Lexicon, $heading );
|
||||
my $loc_description = localise( \%Lexicon, $description );
|
||||
$loc_heading =~ s/^\s*(\w.*?)\s*$/$1/;
|
||||
$loc_description =~ s/^\s*(\w.*?)\s*$/$1/;
|
||||
|
||||
$rec->merge_props(
|
||||
Heading => $loc_heading,
|
||||
Description => $loc_description,
|
||||
HeadingWeight => localise( \%Lexicon, $heading_weight ),
|
||||
DescriptionWeight => localise( \%Lexicon, $description_weight ),
|
||||
MenuCat => (defined $menucat ? $menucat : 'A'));
|
||||
}
|
||||
#warn "trying to close for lang $lang\n";
|
||||
my $navdb = $navdbs{$lang};
|
||||
$navdb->close();
|
||||
$navdb->close();
|
||||
}
|
||||
|
||||
|
||||
sub localise {
|
||||
my ($lexicon, $string) = @_;
|
||||
#print("Looking up:".$string."\n");
|
||||
$string = "" unless defined $string;
|
||||
return $lexicon->{$string} || $string;
|
||||
my $lc_string = lc($string);
|
||||
my $res = $lexicon->{$lc_string} || $string;
|
||||
#print("Returning:".$res."\n");
|
||||
return $res;
|
||||
}
|
||||
|
||||
# Subroutine to process localization
|
||||
sub process_localization {
|
||||
my ($lexicon_ref, $heading, $lang, $prefix) = @_;
|
||||
|
||||
# Localized heading based on original heading
|
||||
my $loc_heading = localise($lexicon_ref, $heading);
|
||||
|
||||
# Get the base language code from $lang
|
||||
my $base_lang = (split('-', $lang))[0];
|
||||
|
||||
# Check the condition
|
||||
if ($loc_heading eq $heading && $base_lang ne 'en') {
|
||||
# Construct the new key by combining the prefix and the original heading
|
||||
my $key = $prefix . $heading;
|
||||
# Localize using the constructed key
|
||||
$loc_heading = localise($lexicon_ref, $key);
|
||||
# See if it got a hit
|
||||
if ($loc_heading eq $key){
|
||||
$loc_heading = $heading;
|
||||
}
|
||||
}
|
||||
|
||||
return $loc_heading; # Optionally return the localized heading
|
||||
}
|
||||
|
4
root/etc/e-smith/templates/etc/rsyslog.conf/32smanager
Normal file
4
root/etc/e-smith/templates/etc/rsyslog.conf/32smanager
Normal file
@@ -0,0 +1,4 @@
|
||||
#smanager
|
||||
:programname, isequal, "smanager" /var/log/smanager/smanager.log
|
||||
& stop
|
||||
|
@@ -234,7 +234,7 @@ a.menu-title {
|
||||
width: 100%;
|
||||
}
|
||||
#h2e11 {
|
||||
width: 70%;
|
||||
width: 50%;
|
||||
float: left;
|
||||
}
|
||||
#h2e12 {
|
||||
@@ -257,9 +257,9 @@ a.menu-title {
|
||||
width: 70%;
|
||||
}
|
||||
|
||||
#h2e22,#h2e23 {
|
||||
#h2e22,#h2e23,#h2e12 {
|
||||
float: left;
|
||||
width: 10%;
|
||||
width: 14em;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
@@ -273,6 +273,7 @@ a.menu-title {
|
||||
left: 2px;
|
||||
}
|
||||
|
||||
|
||||
/*end*/
|
||||
EOF
|
||||
}
|
||||
|
@@ -0,0 +1,27 @@
|
||||
document.addEventListener('DOMContentLoaded', () => {
|
||||
const flagContainer = document.getElementById('flag-container');
|
||||
|
||||
// Function to get the browser's locale
|
||||
function getBrowserLocale() {
|
||||
return navigator.language || navigator.userLanguage;
|
||||
}
|
||||
|
||||
// Function to map locale to country code
|
||||
function getCountryCodeFromLocale(locale) {
|
||||
const localeParts = locale.split('-');
|
||||
return localeParts.length > 1 ? localeParts[1] : localeParts[0];
|
||||
}
|
||||
|
||||
// Function to create and display the flag icon
|
||||
function displayFlagIcon(countryCode) {
|
||||
const flagIcon = document.createElement('span');
|
||||
flagIcon.className = `flag-icon flag-icon-${countryCode.toLowerCase()}`;
|
||||
flagIcon.id = 'flag-icon';
|
||||
flagContainer.appendChild(flagIcon);
|
||||
}
|
||||
|
||||
// Main logic
|
||||
const locale = getBrowserLocale();
|
||||
const countryCode = getCountryCodeFromLocale(locale);
|
||||
displayFlagIcon(countryCode);
|
||||
});
|
@@ -1,4 +1,6 @@
|
||||
/usr/share/smanager/log/production.log {
|
||||
/var/log/smanager/smanager.log {
|
||||
su root root
|
||||
create 600 root root
|
||||
weekly
|
||||
copytruncate
|
||||
rotate 12
|
||||
|
@@ -7,7 +7,7 @@ After=network.target
|
||||
Type=simple
|
||||
SyslogIdentifier=smanager
|
||||
WorkingDirectory=/usr/share/smanager/script
|
||||
PIDFile=/var/run/smanager.pid
|
||||
PIDFile=/run/smanager.pid
|
||||
ExecStartPre=/sbin/e-smith/service-status smanager
|
||||
ExecStart=/usr/bin/hypnotoad srvmngr -f
|
||||
ExecStop=/usr/bin/hypnotoad -s srvmngr
|
||||
|
@@ -624,7 +624,7 @@ sub getNavigation {
|
||||
{
|
||||
$heading = $rec->prop('Heading');
|
||||
$description = $rec->prop('Description');
|
||||
$headingWeight = $rec->prop('HeadingWeight');
|
||||
$headingWeight = $rec->prop('HeadingWeight') || 99999; #Stop noise in logs if file in dir does not have nav header.
|
||||
$descriptionWeight = $rec->prop('DescriptionWeight');
|
||||
$urlpath = $rec->prop('UrlPath') || '';
|
||||
$menucat = $rec->prop('MenuCat') || 'A'; # admin menu (default)
|
||||
|
@@ -37,6 +37,8 @@ use esmith::BackupHistoryDB;
|
||||
use esmith::util;
|
||||
use esmith::lockfile;
|
||||
|
||||
use esmith::BlockDevices;
|
||||
|
||||
use constant DEBUG => $ENV{MOJO_SMANAGER_DEBUG} || 0;
|
||||
|
||||
our $cdb = esmith::ConfigDB->open || die "Couldn't open config db";
|
||||
@@ -1576,19 +1578,33 @@ sub get_BackupwkDest_options {
|
||||
my @usbdisks = ();
|
||||
|
||||
if ( $VFSType eq 'usb' ) {
|
||||
foreach my $udi (qx(hal-find-by-property --key volume.fsusage --string filesystem)) {
|
||||
$udi =~ m/^(\S+)/;
|
||||
my $devices = esmith::BlockDevices->new ('allowmount' => 'disabled');
|
||||
my ($valid, $invalid) = $devices->checkBackupDrives(0);
|
||||
|
||||
my $is_mounted = qx(hal-get-property --udi $1 --key volume.is_mounted);
|
||||
|
||||
if ($is_mounted eq "false\n") {
|
||||
my $vollbl = qx(hal-get-property --udi $1 --key volume.label);
|
||||
$vollbl =~ m/^(\S+)/;
|
||||
if ($vollbl =~ /^\s/) {$vollbl = 'nolabel';}
|
||||
chomp $vollbl;
|
||||
push @usbdisks, $vollbl;
|
||||
if ( ${$valid}[0] ) {
|
||||
foreach ( @{$valid} ) {
|
||||
push @usbdisks, $devices->label($_);
|
||||
}
|
||||
}
|
||||
|
||||
if (!$usbdisks[0]){
|
||||
push (@usbdisks,$c->l('bac_No suitable local devices found'));
|
||||
}
|
||||
$devices->destroy;
|
||||
|
||||
#foreach my $udi (qx(hal-find-by-property --key volume.fsusage --string filesystem)) {
|
||||
#$udi =~ m/^(\S+)/;
|
||||
|
||||
#my $is_mounted = qx(hal-get-property --udi $1 --key volume.is_mounted);
|
||||
|
||||
#if ($is_mounted eq "false\n") {
|
||||
#my $vollbl = qx(hal-get-property --udi $1 --key volume.label);
|
||||
#$vollbl =~ m/^(\S+)/;
|
||||
#if ($vollbl =~ /^\s/) {$vollbl = 'nolabel';}
|
||||
#chomp $vollbl;
|
||||
#push @usbdisks, $vollbl;
|
||||
#}
|
||||
#}
|
||||
# return undef unless ($usbdisks[0]);
|
||||
}
|
||||
|
||||
@@ -1985,31 +2001,50 @@ sub dmount {
|
||||
return ( qx(/bin/mount -t nfs -o nolock "$host:/$share" $mountdir 2>&1) );
|
||||
}
|
||||
elsif ($VFSType eq 'usb') {
|
||||
my $device = "";
|
||||
my $blkdev = "";
|
||||
my $device = "";
|
||||
my $vollbl = "";
|
||||
foreach my $udi (qx(hal-find-by-property --key volume.fsusage --string filesystem)) {
|
||||
$udi =~ m/^(\S+)/;
|
||||
my $is_mounted = qx(hal-get-property --udi $1 --key volume.is_mounted);
|
||||
|
||||
if ($is_mounted eq "false\n") {
|
||||
$blkdev = qx(hal-get-property --udi $1 --key block.device);
|
||||
if ($blkdev =~ m/^(\S+)/) {$blkdev = $1;}
|
||||
}
|
||||
if ($is_mounted eq "false\n") {
|
||||
$vollbl = qx(hal-get-property --udi $1 --key volume.label);
|
||||
$vollbl =~ m/^(\S+)/;
|
||||
if ($vollbl =~ /^\s/) {$vollbl = 'nolabel';}
|
||||
}
|
||||
my $devices = esmith::BlockDevices->new ('allowmount' => 'disabled');
|
||||
my ($valid, $invalid) = $devices->checkBackupDrives(0);
|
||||
|
||||
chomp $vollbl;
|
||||
chomp $blkdev;
|
||||
$vollbl = "media/$vollbl";
|
||||
if ($vollbl eq $share) {
|
||||
$device = $blkdev;
|
||||
}
|
||||
if ( ${$valid}[0] ) {
|
||||
foreach ( @{$valid} ) {
|
||||
$vollbl = $devices->label($_);
|
||||
if ( $share eq "media/$vollbl" ) {
|
||||
$device = "/dev/$_";
|
||||
}
|
||||
}
|
||||
}
|
||||
return ( qx(/bin/mount $device "/$share" 2>&1) );
|
||||
$devices->destroy;
|
||||
return ( qx (mount $device /$share 2>&1) );
|
||||
|
||||
#-------------------------------------------------------------------------------------------------------
|
||||
#my $device = "";
|
||||
#my $blkdev = "";
|
||||
#my $vollbl = "";
|
||||
#foreach my $udi (qx(hal-find-by-property --key volume.fsusage --string filesystem)) {
|
||||
#$udi =~ m/^(\S+)/;
|
||||
#my $is_mounted = qx(hal-get-property --udi $1 --key volume.is_mounted);
|
||||
|
||||
#if ($is_mounted eq "false\n") {
|
||||
#$blkdev = qx(hal-get-property --udi $1 --key block.device);
|
||||
#if ($blkdev =~ m/^(\S+)/) {$blkdev = $1;}
|
||||
#}
|
||||
#if ($is_mounted eq "false\n") {
|
||||
#$vollbl = qx(hal-get-property --udi $1 --key volume.label);
|
||||
#$vollbl =~ m/^(\S+)/;
|
||||
#if ($vollbl =~ /^\s/) {$vollbl = 'nolabel';}
|
||||
#}
|
||||
|
||||
#chomp $vollbl;
|
||||
#chomp $blkdev;
|
||||
#$vollbl = "media/$vollbl";
|
||||
#if ($vollbl eq $share) {
|
||||
#$device = $blkdev;
|
||||
#}
|
||||
#}
|
||||
#return ( qx(/bin/mount $device "/$share" 2>&1) );
|
||||
#-------------------------------------------------------------------------------------------------------
|
||||
} else {
|
||||
return ("Error while mounting $host/$share : $VFSType not supported.\n");
|
||||
}
|
||||
|
@@ -1,3 +1,4 @@
|
||||
'bac_No suitable local devices found' => 'No suitable local devices found',
|
||||
'bac_BACKUP_TITLE' => 'Backup or restore server data',
|
||||
'bac_BACKUP_DESC' => '<P>The server provides two ways to back up and restore
|
||||
your server: using your local desktop or a tape drive.</P>
|
||||
|
Binary file not shown.
After Width: | Height: | Size: 10 KiB |
@@ -0,0 +1,63 @@
|
||||
document.addEventListener('DOMContentLoaded', () => {
|
||||
const flagContainer = document.getElementById('flag-container');
|
||||
|
||||
// Function to get the browser's locale
|
||||
function getBrowserLocale() {
|
||||
return navigator.language || navigator.userLanguage;
|
||||
}
|
||||
|
||||
// Function to map locale to country code
|
||||
function getCountryCodeFromLocale(locale) {
|
||||
const localeParts = locale.split('-');
|
||||
return localeParts.length > 1 ? localeParts[1] : localeParts[0];
|
||||
}
|
||||
|
||||
// Function to fetch country names from a CDN
|
||||
async function fetchCountryNames() {
|
||||
const response = await fetch('https://restcountries.com/v3.1/all');
|
||||
const countries = await response.json();
|
||||
const countryNames = {};
|
||||
for (const country of countries) {
|
||||
const code = country.cca2.toLowerCase(); // Country code (ISO 3166-1 alpha-2)
|
||||
const name = country.name.common; // Common name of the country
|
||||
countryNames[code] = name;
|
||||
}
|
||||
return countryNames;
|
||||
}
|
||||
|
||||
// Function to create and display the flag icon
|
||||
function displayFlagIcon(countryCode, countryName) {
|
||||
const flagIcon = document.createElement('span');
|
||||
flagIcon.className = `flag-icon flag-icon-${countryCode.toLowerCase()}`;
|
||||
flagIcon.id = 'flag-icon';
|
||||
flagIcon.title = countryName; // Set the title for the tooltip
|
||||
|
||||
// If you want a custom tooltip instead (uncomment the lines below):
|
||||
/*
|
||||
const tooltip = document.createElement('span');
|
||||
tooltip.className = 'tooltip';
|
||||
tooltip.innerText = countryName;
|
||||
flagIcon.appendChild(tooltip);
|
||||
|
||||
flagIcon.addEventListener('mouseenter', () => {
|
||||
tooltip.style.display = 'block';
|
||||
});
|
||||
|
||||
flagIcon.addEventListener('mouseleave', () => {
|
||||
tooltip.style.display = 'none';
|
||||
});
|
||||
*/
|
||||
|
||||
flagContainer.appendChild(flagIcon);
|
||||
}
|
||||
|
||||
// Main logic
|
||||
(async () => {
|
||||
const locale = getBrowserLocale();
|
||||
const countryCode = getCountryCodeFromLocale(locale);
|
||||
const countryNames = await fetchCountryNames(); // Fetch country names
|
||||
|
||||
const countryName = countryNames[countryCode.toLowerCase()] || 'Unknown Country'; // Get the country name
|
||||
displayFlagIcon(countryCode, countryName); // Display the flag with country name
|
||||
})();
|
||||
});
|
@@ -19,17 +19,21 @@
|
||||
%= content_for 'refresh'
|
||||
|
||||
%= stylesheet '/js/datatables.min.css'
|
||||
%= javascript '/js/datatables.min.js'
|
||||
%= stylesheet '/js/jquery-ui.min.css'
|
||||
%= javascript '/js/jquery-ui.min.js'
|
||||
|
||||
%= stylesheet '/js/dataTables.buttons.min.js'
|
||||
%= stylesheet '/js/jszip.min.js'
|
||||
%= stylesheet '/js/pdfmake.min.js'
|
||||
%= stylesheet '/js/vfs_fonts.js'
|
||||
%= stylesheet '/js/buttons.html5.min.js'
|
||||
%= stylesheet '/js/buttons.print.min.js'
|
||||
|
||||
%= javascript '/js/datatables.min.js'
|
||||
|
||||
%= stylesheet '/js/jquery-ui.min.css'
|
||||
|
||||
%= javascript '/js/jquery-ui.min.js'
|
||||
%= javascript '/js/dataTables.buttons.min.js'
|
||||
%= javascript '/js/jszip.min.js'
|
||||
%= javascript '/js/pdfmake.min.js'
|
||||
%= javascript '/js/vfs_fonts.js'
|
||||
%= javascript '/js/buttons.html5.min.js'
|
||||
%= javascript '/js/buttons.print.min.js'
|
||||
%= javascript '/js/flag-by-locale.js'
|
||||
|
||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/flag-icon-css/3.5.0/css/flag-icon.min.css">
|
||||
%= stylesheet '/css/sme-jquery-overrides.css'
|
||||
|
||||
</head>
|
||||
@@ -90,47 +94,6 @@
|
||||
% }
|
||||
|
||||
%= javascript '/js/sme-dataTable-setup.js'
|
||||
|
||||
%= javascript begin
|
||||
//Set menu to initial condition based on localStorage
|
||||
$(document).ready(function() {
|
||||
let menunavflag = window.localStorage.getItem('menunav');
|
||||
if (menunavflag != "false"){
|
||||
$('#menunav').toggle(true);
|
||||
} else {
|
||||
$('#menunav').toggle(false);
|
||||
}
|
||||
|
||||
let menuadmflag = window.localStorage.getItem('menuadm');
|
||||
if (menuadmflag != "false"){
|
||||
$('#menuadm').toggle(true);
|
||||
} else {
|
||||
$('#menuadm').toggle(false);
|
||||
}
|
||||
|
||||
let menuuserflag = window.localStorage.getItem('menuuser');
|
||||
if (menuuserflag != "false"){
|
||||
$('#menuuser').toggle(true);
|
||||
} else {
|
||||
$('#menuuser').toggle(false);
|
||||
}
|
||||
|
||||
var sections = document.getElementsByClassName("section-title");
|
||||
for (var i = 0, len = sections.length; i < len; i++) {
|
||||
var jqObj = $(sections[i]);
|
||||
var $section = jqObj.parent().next('div');
|
||||
if(!$section.length){
|
||||
return false;
|
||||
}
|
||||
let localStorageTag = "admSection-"+sections[i].innerHTML;
|
||||
if (window.localStorage.getItem(localStorageTag) != "false"){
|
||||
$section.toggle(true);
|
||||
} else {
|
||||
$section.toggle(false);
|
||||
}
|
||||
}
|
||||
})
|
||||
%end
|
||||
|
||||
</body>
|
||||
</html>
|
||||
|
@@ -1,5 +1,6 @@
|
||||
<div id="footer">
|
||||
<div id="footer" width=100%>
|
||||
<HR class="sme-copyrightbar">
|
||||
<a href="https://mojolicious.org" target="_blank"><img src="images/sme-mojo-logo-white.png" style="position:relative;"></a>
|
||||
<font class="sme-copyright">
|
||||
% if ( $c->is_logged_in ) {
|
||||
SME Server <%= session 'releaseVersion' %> - Manager <%= $c->app->VERSION %>
|
||||
|
@@ -1,27 +1,128 @@
|
||||
<style>
|
||||
#h2l1 {
|
||||
display: flex; /* Use flexbox layout */
|
||||
justify-content: space-between; /* Space between child elements */
|
||||
align-items: center; /* Center items vertically */
|
||||
}
|
||||
|
||||
#h2e11 {
|
||||
flex: 1; /* Allow the first div to take available space on the left */
|
||||
}
|
||||
|
||||
#h2e12 {
|
||||
display: flex; /* Make this div a flex container */
|
||||
align-items: center; /* Vertically center content in this div */
|
||||
margin-left: 20px; /* Add margin to the left of this div */
|
||||
}
|
||||
|
||||
#flag-container {
|
||||
display: flex; /* Make this div a flex container */
|
||||
align-items: center; /* Vertically center content in this div */
|
||||
margin-left: 20px; /* Add margin to the left of the flag container */
|
||||
padding-right: 20px; /* Add padding to the right side of the flag container */
|
||||
}
|
||||
|
||||
.flag-icon {
|
||||
width: 43px;
|
||||
font-size: 20px;
|
||||
}
|
||||
|
||||
#legacy-button button {
|
||||
background-color: #98d36e; /* Button background color */
|
||||
font-weight: lighter; /* Lighter text for the button */
|
||||
color: #063; /* Button text color */
|
||||
padding: 5px 10px; /* Padding for the button */
|
||||
border: none; /* Remove default button border */
|
||||
border-radius: 4px; /* Rounded corners for button */
|
||||
cursor: pointer; /* Change cursor on hover */
|
||||
}
|
||||
|
||||
#legacy-button button:hover {
|
||||
background-color: #82c961; /* Change color on hover */
|
||||
}
|
||||
|
||||
.infobar {
|
||||
display: flex; /* Use flexbox for alignment */
|
||||
justify-content: space-between; /* Space between child elements */
|
||||
align-items: center; /* Center items vertically */
|
||||
padding: 10px; /* Adjust padding as desired */
|
||||
}
|
||||
|
||||
#h2e21 {
|
||||
flex: 1; /* Allow the first div to take available space on the left */
|
||||
}
|
||||
|
||||
#h2e22 {
|
||||
display: flex; /* Make this div a flex container */
|
||||
justify-content: center; /* Center the help button */
|
||||
align-items: center; /* Center vertically */
|
||||
flex: none; /* Prevent this div from growing */
|
||||
position: relative; /* Relative position for centering */
|
||||
width: 100px; /* Set a width for the help button container */
|
||||
}
|
||||
|
||||
#h2e23 {
|
||||
margin-left: auto; /* Push the third div to the right */
|
||||
}
|
||||
|
||||
.login-button {
|
||||
background-color: #98d36e; /* Button background color */
|
||||
font-weight: bold; /* Bold text */
|
||||
xxcolor: #ffffff; /* Button text color */
|
||||
padding: 8px 12px; /* Adjust padding for button height */
|
||||
border: none; /* Remove default border */
|
||||
border-radius: 4px; /* Rounded corners */
|
||||
cursor: pointer; /* Change cursor on hover */
|
||||
}
|
||||
|
||||
.login-button:hover {
|
||||
background-color: #82c961; /* Change color on hover */
|
||||
}
|
||||
|
||||
#help-button {
|
||||
text-decoration: none; /* Remove underline from link */
|
||||
font-size: 20px; /* Adjust font size as needed */
|
||||
padding: 8px 12px; /* Add padding to the help link */
|
||||
background-color: #98d36e; /* Background for visibility */
|
||||
border-radius: 4px; /* Rounded corners */
|
||||
color: #000; /* Button text color */
|
||||
}
|
||||
|
||||
#help-button:hover {
|
||||
background-color: #82c961; /* Change background on hover */
|
||||
}
|
||||
</style>
|
||||
|
||||
<div id="header2" class="hd2">
|
||||
<div id="h2l1">
|
||||
<div id="h2e11">
|
||||
<a target='_blank' href="http://www.koozali.org"><img src="images/smeserver_logo.jpg" height="40" alt="SME Server"></a>
|
||||
</div>
|
||||
<!-- <div id="h2e12"><h5><a href="initial">Server Manager</a>
|
||||
<a href="/server-manager" target='_blank'>    (Prev SM)</a></h5> -->
|
||||
<div id="h2e12" style="float:right;"><br><a href="/server-manager" target='_blank'><button style="background-color:#98d36e;font-weight:bold;color:#063;">Legacy SM</button></a></div>
|
||||
</div>
|
||||
<div id="h2e11">
|
||||
<a target='_blank' href="http://www.koozali.org"><img src="images/smeserver_logo.jpg" height="40" alt="SME Server"></a>
|
||||
</div>
|
||||
|
||||
<div id="h2l2" class="infobar">
|
||||
<div id="h2e21">
|
||||
<b>
|
||||
<%= session 'SystemName' %>@<%= session 'DomainName' %></b>
|
||||
</div>
|
||||
<div id="h2e22">
|
||||
<a target="_parent" href="manual"> <b> ? </b> </a>
|
||||
</div>
|
||||
<div id="h2e23">
|
||||
% if ( not defined $c->session->{username} ) {
|
||||
<a target="_parent" href="login"><b>Login</b></a>
|
||||
% } else {
|
||||
<a target="_parent" href="logout"><b><%= $c->session->{username} %> Logout</b></a>
|
||||
% }
|
||||
</div>
|
||||
<div id="h2e22">
|
||||
<a id="help-button" target="_parent" href="manual"><button> ? </button></a>
|
||||
</div>
|
||||
|
||||
<div id="h2e12">
|
||||
<a id="legacy-button" href="/server-manager" target='_blank'><button>Legacy SM</button></a>
|
||||
</div>
|
||||
<div id="h2e23">
|
||||
% if ( not defined $c->session->{username} ) {
|
||||
<a target="_parent" href="login"><button class="login-button">Login</button></a>
|
||||
% } else {
|
||||
<a target="_parent" href="logout"><button class="login-button"><%= $c->session->{username} %> Logout</button></a>
|
||||
% }
|
||||
</div>
|
||||
<div id="flag-container">
|
||||
<!-- The flag icon will be inserted here -->
|
||||
</div>
|
||||
</div>
|
||||
<div id="h2l2" class="infobar">
|
||||
<div id="h2e21">
|
||||
<b>
|
||||
<%= session 'SystemName' %>@<%= session 'DomainName' %></b>
|
||||
</div>
|
||||
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
@@ -9,6 +9,7 @@
|
||||
<br>
|
||||
%= submit_button "$btn", class => 'action'
|
||||
</p>
|
||||
%= hidden_field 'trt' => 'ADD';
|
||||
|
||||
% end
|
||||
|
||||
@@ -71,9 +72,7 @@
|
||||
% }
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
<%} %>
|
||||
|
||||
%= hidden_field 'trt' => $iba_datas->{trt}
|
||||
|
||||
</div>
|
||||
|
@@ -60,9 +60,10 @@
|
||||
<span class=data>
|
||||
%=text_field 'networkRouter'
|
||||
</span><br><br>
|
||||
<div class='center'>
|
||||
%= submit_button "$btn", class => 'action'
|
||||
</div>
|
||||
<p>
|
||||
<br>
|
||||
%= submit_button "$btn", class => 'action'
|
||||
</p>
|
||||
%end
|
||||
|
||||
</div>
|
||||
|
@@ -49,9 +49,11 @@
|
||||
</span><br><br>
|
||||
%}
|
||||
%= hidden_field localnetwork=>$localnetwork
|
||||
<div class='center'>
|
||||
%= submit_button "$btn", class => 'action'
|
||||
</div>
|
||||
<p>
|
||||
<br>
|
||||
%= submit_button "$btn", class => 'action'
|
||||
</p>
|
||||
|
||||
%end
|
||||
|
||||
</div>
|
||||
|
@@ -37,10 +37,12 @@
|
||||
%= $c->render_to_string(inline => l($ret{ret},$var1,$var2,$var3,$var4,$var5,$var6,$var7));
|
||||
</div>
|
||||
%}
|
||||
<br><br>
|
||||
<div class='center'>
|
||||
|
||||
<p>
|
||||
<br>
|
||||
%= submit_button "$btn", class => 'action'
|
||||
</div>
|
||||
</p>
|
||||
|
||||
% end
|
||||
|
||||
<br>
|
||||
|
@@ -77,9 +77,11 @@
|
||||
<span class=data>
|
||||
%=text_field 'cmmnt'
|
||||
</span><br><br>
|
||||
<div class='center'>
|
||||
%= submit_button "$btn", class => 'action'
|
||||
</div>
|
||||
<p>
|
||||
<br>
|
||||
%= submit_button "$btn", class => 'action'
|
||||
</p>
|
||||
|
||||
%end
|
||||
|
||||
</div>
|
||||
|
@@ -57,9 +57,10 @@
|
||||
%#}
|
||||
%= hidden_field sport=>$sport
|
||||
%= hidden_field proto=>$proto
|
||||
<div class='center'>
|
||||
%= submit_button "$btn", class => 'action'
|
||||
</div>
|
||||
<br>
|
||||
%= submit_button "$btn", class => 'action'
|
||||
</p>
|
||||
|
||||
%end
|
||||
|
||||
</div>
|
||||
|
@@ -18,8 +18,6 @@
|
||||
% my $var5 = @vars[4];
|
||||
% my $var6 = @vars[5];
|
||||
|
||||
|
||||
|
||||
%if ($ret{ret} eq "") {
|
||||
%= $c->render_to_string(inline => l('pf_FIRST_PAGE_DESCRIPTION'));
|
||||
%} elsif (index($ret{ret},"SUCCESS") != -1) {
|
||||
@@ -33,21 +31,22 @@
|
||||
%= $c->l($ret{ret},$var1,$var2,$var3,$var4,$var5,$var6);
|
||||
</div>
|
||||
%}
|
||||
<br><br>
|
||||
<div class='center'>
|
||||
|
||||
<p>
|
||||
<br>
|
||||
%= submit_button "$btn", class => 'action'
|
||||
</div>
|
||||
</p>
|
||||
|
||||
|
||||
% end
|
||||
|
||||
<br>
|
||||
|
||||
% if ($empty){
|
||||
<br>
|
||||
%=l 'pf_NO_FORWARDS'
|
||||
% } else {
|
||||
<br>
|
||||
%=l 'pf_SHOW_FORWARDS'
|
||||
<br>
|
||||
<br><br />
|
||||
<table class="sme-border TableSort"><thead>
|
||||
<tr>
|
||||
<th class='sme-border'>
|
||||
|
@@ -213,10 +213,10 @@
|
||||
</p>
|
||||
%}
|
||||
|
||||
|
||||
<div class='center'>
|
||||
<p>
|
||||
<br>
|
||||
%= submit_button "$btn", class => 'action'
|
||||
</div>
|
||||
</p>
|
||||
|
||||
% end
|
||||
|
||||
|
@@ -66,9 +66,10 @@
|
||||
</span>
|
||||
<br><br></p>
|
||||
|
||||
<div class='center'>
|
||||
%= submit_button "$btn", class => 'action'
|
||||
</div>
|
||||
<p>
|
||||
<br>
|
||||
%= submit_button "$btn", class => 'action'
|
||||
</p>
|
||||
|
||||
% end
|
||||
|
||||
|
0
root/var/log/smanager/.gitignore
vendored
Normal file
0
root/var/log/smanager/.gitignore
vendored
Normal file
@@ -2,7 +2,7 @@ Summary: Sme server navigation module : manager 2
|
||||
%define name smeserver-manager
|
||||
Name: %{name}
|
||||
%define version 11.0.0
|
||||
%define release 4
|
||||
%define release 12
|
||||
Version: %{version}
|
||||
Release: %{release}%{?dist}
|
||||
License: GPL
|
||||
@@ -108,6 +108,32 @@ true
|
||||
%defattr(-,root,root)
|
||||
|
||||
%changelog
|
||||
* Sun Jul 28 2024 Brian Read <brianr@koozali.org> 11.0.0-12.sme
|
||||
- correct positio of flag-icon [SME: 12706]
|
||||
|
||||
* Sat Jul 27 2024 Brian Read <brianr@koozali.org> 11.0.0-11.sme
|
||||
- Add in flag icon indication of locale [SME: 12706]
|
||||
|
||||
* Fri Jul 26 2024 Brian Read <brianr@koozali.org> 11.0.0-10.sme
|
||||
- fix navigation2.conf to more correctly translate menus [SME: 12714]
|
||||
|
||||
* Thu May 09 2024 Brian Read <brianr@koozali.org> 11.0.0-9.sme
|
||||
- Add mojo logo to footer [SME: 12679]
|
||||
- Fix default for HeaderWeight to avoid noise in logs if no Nav header in file
|
||||
- Align buttons consistently [SME: 12680]
|
||||
|
||||
* Tue Apr 30 2024 Jean-Philippe Pialasse <jpp@koozali.org> 11.0.0-8.sme
|
||||
- create dedicated log files and logrotate [SME: 12664]
|
||||
|
||||
* Tue Apr 30 2024 Brian Read <brianr@koozali.org> 11.0.0-7.sme
|
||||
- Remove use of hel command and replace by call to BlockDevices lib [SME: 12644]
|
||||
|
||||
* Mon Apr 29 2024 Brian Read <brianr@koozali.org> 11.0.0-6.sme
|
||||
- Update layout for table extras [SME: 12656]
|
||||
|
||||
* Sun Apr 28 2024 Brian Read <brianr@koozali.org> 11.0.0-5.sme
|
||||
- Ibay create not getting into panel [SME: 12652]
|
||||
|
||||
* Tue Apr 23 2024 Brian Read <brianr@koozali.org> 11.0.0-4.sme
|
||||
- add in Nav numbers for Legacypanels.pm and ignore it when generating nav menu [SME:12643]
|
||||
|
||||
|
Reference in New Issue
Block a user