* Tue Jun 24 2025 Brian Read <brianr@koozali.org> 11.0.0-95.sme
- Add clock ticker to datetime panel [SME: 13054] - Add Test Server button for ntp server [SME: 13048] - Add checking that date is fully valid [SME: 13055]
This commit is contained in:
parent
0341d02608
commit
0f2e2b82aa
@ -37,7 +37,7 @@ use esmith::NavigationDB; # no UTF8 raw is ok for ASCII only flat file
|
|||||||
use SrvMngr_Auth qw(check_admin_access);
|
use SrvMngr_Auth qw(check_admin_access);
|
||||||
|
|
||||||
#this is overwrittrn with the "release" by the spec file - release can be "99.el8.sme"
|
#this is overwrittrn with the "release" by the spec file - release can be "99.el8.sme"
|
||||||
our $VERSION = '93.el8.sme';
|
our $VERSION = '94.el8.sme';
|
||||||
#Extract the release value
|
#Extract the release value
|
||||||
if ($VERSION =~ /^(\d+)/) {
|
if ($VERSION =~ /^(\d+)/) {
|
||||||
$VERSION = $1; # $1 contains the matched numeric digits
|
$VERSION = $1; # $1 contains the matched numeric digits
|
||||||
@ -328,6 +328,7 @@ sub setup_routing {
|
|||||||
$if_admin->get('/datetime')->to('datetime#main')->name('datetime');
|
$if_admin->get('/datetime')->to('datetime#main')->name('datetime');
|
||||||
$if_admin->post('/datetimeu')->to('datetime#do_update')->name('datetimeu');
|
$if_admin->post('/datetimeu')->to('datetime#do_update')->name('datetimeu');
|
||||||
$if_admin->get('/datetimed')->to('datetime#do_display')->name('datetimed');
|
$if_admin->get('/datetimed')->to('datetime#do_display')->name('datetimed');
|
||||||
|
$if_admin->post('/datetimet')->to('datetime#do_testntp')->name('datetimet');
|
||||||
|
|
||||||
|
|
||||||
$if_admin->get('/directory')->to('directory#main')->name('directory');
|
$if_admin->get('/directory')->to('directory#main')->name('directory');
|
||||||
|
@ -13,6 +13,8 @@ use esmith::NetworksDB::UTF8;
|
|||||||
use esmith::HostsDB;
|
use esmith::HostsDB;
|
||||||
use esmith::DomainsDB::UTF8;
|
use esmith::DomainsDB::UTF8;
|
||||||
|
|
||||||
|
use DateTime;
|
||||||
|
|
||||||
use constant FALSE => 0;
|
use constant FALSE => 0;
|
||||||
use constant TRUE => 1;
|
use constant TRUE => 1;
|
||||||
|
|
||||||
@ -79,6 +81,7 @@ my $ddb;
|
|||||||
my $now_sec = sprintf('%02d', $today_sec);
|
my $now_sec = sprintf('%02d', $today_sec);
|
||||||
my $current_year = $today_year;
|
my $current_year = $today_year;
|
||||||
my $ntpserverurl = $cdb->get_prop('ntpd','NTPServer');
|
my $ntpserverurl = $cdb->get_prop('ntpd','NTPServer');
|
||||||
|
my $now = DateTime->now( time_zone => 'local' );
|
||||||
my %ret = (
|
my %ret = (
|
||||||
# fields from Inputs
|
# fields from Inputs
|
||||||
'time_mode'=>($ntpserverurl eq '' ? 'dat_manually_set' : 'dat_ntp_server'),
|
'time_mode'=>($ntpserverurl eq '' ? 'dat_manually_set' : 'dat_ntp_server'),
|
||||||
@ -90,6 +93,8 @@ my $ddb;
|
|||||||
'minute'=>"$now_min",
|
'minute'=>"$now_min",
|
||||||
'second'=>"$now_sec",
|
'second'=>"$now_sec",
|
||||||
'ntpstatus' => $cdb->get_prop('ntpd','status') || 'disabled',
|
'ntpstatus' => $cdb->get_prop('ntpd','status') || 'disabled',
|
||||||
|
# and the current time as a full format
|
||||||
|
'currentdatetime' => $now->strftime('%Y-%m-%dT%H:%M:%S')
|
||||||
|
|
||||||
);
|
);
|
||||||
return %ret;
|
return %ret;
|
||||||
@ -224,38 +229,12 @@ sub validate_change_datetime {
|
|||||||
$timezone = "US/Eastern";
|
$timezone = "US/Eastern";
|
||||||
}
|
}
|
||||||
my $month = $c->param('month');
|
my $month = $c->param('month');
|
||||||
|
|
||||||
if ($month =~ /^(\d{1,2})$/) {
|
|
||||||
$month = $1;
|
|
||||||
} else {
|
|
||||||
$month = "1";
|
|
||||||
}
|
|
||||||
|
|
||||||
if (($month < 1) || ($month > 12)) {
|
|
||||||
return $c->l('dat_INVALID_MONTH') . " $month. " . $c->l('dat_MONTH_BETWEEN_1_AND_12');
|
|
||||||
}
|
|
||||||
my $day = $c->param('day');
|
my $day = $c->param('day');
|
||||||
|
|
||||||
if ($day =~ /^(\d{1,2})$/) {
|
|
||||||
$day = $1;
|
|
||||||
} else {
|
|
||||||
$day = "1";
|
|
||||||
}
|
|
||||||
|
|
||||||
if (($day < 1) || ($day > 31)) {
|
|
||||||
return $c->l('dat_INVALID_DAY') . " $day. " . $c->l('dat_BETWEEN_1_AND_31');
|
|
||||||
}
|
|
||||||
my $year = $c->param('year');
|
my $year = $c->param('year');
|
||||||
|
if (!is_valid_date($year, $month, $day)){
|
||||||
|
return $c->l('dat_Invalid_date')
|
||||||
|
}
|
||||||
|
|
||||||
if ($year =~ /^(\d{4})$/) {
|
|
||||||
$year = $1;
|
|
||||||
} else {
|
|
||||||
$year = "2000";
|
|
||||||
}
|
|
||||||
|
|
||||||
if (($year < 1900) || ($year > 2200)) {
|
|
||||||
return $c->l('dat_INVALID_YEAR') . " $year. " . $c->l('dat_FOUR_DIGIT_YEAR');
|
|
||||||
}
|
|
||||||
my $hour = $c->param('hour');
|
my $hour = $c->param('hour');
|
||||||
|
|
||||||
if ($hour =~ /^(\d{1,2})$/) {
|
if ($hour =~ /^(\d{1,2})$/) {
|
||||||
@ -289,24 +268,6 @@ sub validate_change_datetime {
|
|||||||
if (($second < 0) || ($second > 59)) {
|
if (($second < 0) || ($second > 59)) {
|
||||||
return $c->l('dat_INVALID_SECOND') . " $second. " . $c->l('dat_BETWEEN_0_AND_59');
|
return $c->l('dat_INVALID_SECOND') . " $second. " . $c->l('dat_BETWEEN_0_AND_59');
|
||||||
}
|
}
|
||||||
#my $ampm = $c->param('Ampm');
|
|
||||||
|
|
||||||
#Move to 24 hours clock - not using AM/PM.
|
|
||||||
#if ($ampm =~ /^(AM|PM)$/) {
|
|
||||||
#$ampm = $1;
|
|
||||||
#} else {
|
|
||||||
#$ampm = "AM";
|
|
||||||
#}
|
|
||||||
# force AM so that it actually works on 24hr clock.
|
|
||||||
#$ampm = "AM";
|
|
||||||
|
|
||||||
|
|
||||||
# convert to 24 hour time
|
|
||||||
#$hour = $hour % 12;
|
|
||||||
|
|
||||||
#if ($ampm eq "PM") {
|
|
||||||
# $hour = $hour + 12;
|
|
||||||
#}
|
|
||||||
|
|
||||||
#--------------------------------------------------
|
#--------------------------------------------------
|
||||||
# Store time zone in configuration database
|
# Store time zone in configuration database
|
||||||
@ -325,10 +286,27 @@ sub validate_change_datetime {
|
|||||||
# and hardware clock
|
# and hardware clock
|
||||||
#--------------------------------------------------
|
#--------------------------------------------------
|
||||||
my $newdate = sprintf "%02d%02d%02d%02d%04d.%02d", $month, $day, $hour, $minute, $year, $second;
|
my $newdate = sprintf "%02d%02d%02d%02d%04d.%02d", $month, $day, $hour, $minute, $year, $second;
|
||||||
esmith::util::backgroundCommand(2, "/sbin/e-smith/signal-event", "timezone-update", $newdate);
|
$c->app->log->info("Changing date manually to $newdate");
|
||||||
|
esmith::util::backgroundCommand(2, "/sbin/e-smith/signal-event", "timezone-update", $newdate); #TEMP!!!
|
||||||
return '';
|
return '';
|
||||||
} ## end sub validate_change_datetime
|
} ## end sub validate_change_datetime
|
||||||
|
|
||||||
|
sub is_valid_date {
|
||||||
|
my ($year, $month, $day) = @_;
|
||||||
|
|
||||||
|
# Check if all parts are defined and integers
|
||||||
|
return 0 unless defined $year && defined $month && defined $day;
|
||||||
|
return 0 unless $year =~ /^\d+$/ && $month =~ /^\d+$/ && $day =~ /^\d+$/;
|
||||||
|
|
||||||
|
# Try to construct a DateTime object
|
||||||
|
eval {
|
||||||
|
DateTime->new(year => $year, month => $month, day => $day);
|
||||||
|
1;
|
||||||
|
} or return 0;
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
sub update_ntpserver {
|
sub update_ntpserver {
|
||||||
my $c = shift;
|
my $c = shift;
|
||||||
my $ntpserver = shift;
|
my $ntpserver = shift;
|
||||||
@ -378,6 +356,4 @@ sub disable_ntp {
|
|||||||
return '';
|
return '';
|
||||||
} ## end sub disable_ntp
|
} ## end sub disable_ntp
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
1;
|
1;
|
@ -8,6 +8,9 @@ package SrvMngr::Controller::Datetime;
|
|||||||
# heading : System
|
# heading : System
|
||||||
# description : Date and time
|
# description : Date and time
|
||||||
# navigation : 4000 300
|
# navigation : 4000 300
|
||||||
|
#
|
||||||
|
# ######name : datetimet, method : post, url : /datetimet, ctlact : datetime#testntp
|
||||||
|
#
|
||||||
# routes : end
|
# routes : end
|
||||||
#
|
#
|
||||||
# Documentation: https://wiki.contribs.org/Datetime
|
# Documentation: https://wiki.contribs.org/Datetime
|
||||||
@ -115,7 +118,7 @@ sub do_update {
|
|||||||
my $c = shift;
|
my $c = shift;
|
||||||
$c->app->log->info($c->log_req);
|
$c->app->log->info($c->log_req);
|
||||||
|
|
||||||
$c->app->log->info($c->param('month'));
|
#$c->app->log->info($c->param('month'));
|
||||||
|
|
||||||
|
|
||||||
#The most common ones - you might want to delete some of these if they are not used.
|
#The most common ones - you might want to delete some of these if they are not used.
|
||||||
@ -173,7 +176,7 @@ sub do_update {
|
|||||||
$c->render(template => "datetime");
|
$c->render(template => "datetime");
|
||||||
return
|
return
|
||||||
} else {
|
} else {
|
||||||
if ($c->param('time_mode') eq 'data_manually_set') {
|
if ($c->param('time_mode') eq 'dat_manually_set') {
|
||||||
$c->stash( success => $c->l('dat_UPDATING_CLOCK'));
|
$c->stash( success => $c->l('dat_UPDATING_CLOCK'));
|
||||||
} else {
|
} else {
|
||||||
$c->stash( success => $c->l('dat_SETTINGS_CHANGED'));
|
$c->stash( success => $c->l('dat_SETTINGS_CHANGED'));
|
||||||
@ -280,4 +283,51 @@ sub do_display {
|
|||||||
);
|
);
|
||||||
$c->render(template => "datetime");
|
$c->render(template => "datetime");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
sub do_testntp {
|
||||||
|
my $c = shift;
|
||||||
|
my $server = $c->req->json->{ntpserver} // '';
|
||||||
|
|
||||||
|
# Strict validation: hostname or IPv4
|
||||||
|
unless ($server =~ /^(?=.{1,253}$)([a-zA-Z0-9](?:[a-zA-Z0-9\-]{0,61}[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[a-zA-Z0-9\-]{0,61}[a-zA-Z0-9])?)*|\d{1,3}(?:\.\d{1,3}){3})$/) {
|
||||||
|
return $c->render(json => { success => 0, error => 'Invalid server name or IP' });
|
||||||
|
}
|
||||||
|
|
||||||
|
my $timeout = 5;
|
||||||
|
my @cmd = ('timeout', $timeout, 'ntpdate', '-q', $server);
|
||||||
|
|
||||||
|
# Run ntpdate and capture output
|
||||||
|
my $output = qx{@cmd 2>&1};
|
||||||
|
$c->app->log->info($output);
|
||||||
|
my $exit_code = $? >> 8;
|
||||||
|
|
||||||
|
# Parse for known errors
|
||||||
|
if ($exit_code == 124) {
|
||||||
|
return $c->render(json => { success => 0, error => "Timeout: NTP server did not respond within $timeout seconds" });
|
||||||
|
}
|
||||||
|
if ($output =~ /no server suitable for synchronization found/i) {
|
||||||
|
return $c->render(json => { success => 0, error => "No suitable NTP server found or server unreachable" });
|
||||||
|
}
|
||||||
|
if ($output =~ /Name or service not known|Temporary failure in name resolution/i) {
|
||||||
|
return $c->render(json => { success => 0, error => "DNS resolution failed for $server" });
|
||||||
|
}
|
||||||
|
if ($output =~ /ntpdig: no eligible servers/i) {
|
||||||
|
return $c->render(json => { success => 0, error => "Not a an NTP server" });
|
||||||
|
}
|
||||||
|
if ($output =~ /permission denied/i) {
|
||||||
|
return $c->render(json => { success => 0, error => "Permission denied running ntpdate" });
|
||||||
|
}
|
||||||
|
if ($exit_code != 0) {
|
||||||
|
return $c->render(json => { success => 0, error => "ntpdate failed (exit code $exit_code): $output" });
|
||||||
|
}
|
||||||
|
|
||||||
|
# Extract date and time down to seconds from adjust line
|
||||||
|
my ($datetime) = $output =~ /^(\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2})/m;
|
||||||
|
|
||||||
|
if ($datetime) {
|
||||||
|
return $c->render(json => { success => 1, time => $datetime });
|
||||||
|
} else {
|
||||||
|
return $c->render(json => { success => 0, error => "Could not parse date/time from NTP server response." });}
|
||||||
|
}
|
||||||
|
|
||||||
1;
|
1;
|
@ -1,5 +1,5 @@
|
|||||||
|
|
||||||
'dat_FORM_TITLE' => 'Date and time configuration',
|
'dat_FORM_TITLE' => 'Date and time configuration',
|
||||||
|
'dat_The_time_is_currently' => 'The time is currently:',
|
||||||
'dat_INITIAL_DESC' => 'This is where you configure the date and time of this server. You may use an existing network time server or
|
'dat_INITIAL_DESC' => 'This is where you configure the date and time of this server. You may use an existing network time server or
|
||||||
manually set the date and time for your time zone.',
|
manually set the date and time for your time zone.',
|
||||||
'dat_SET_DATE_TITLE' => 'Set Date and Time',
|
'dat_SET_DATE_TITLE' => 'Set Date and Time',
|
||||||
@ -59,3 +59,4 @@ clock, and <b>will not</b> try to synchronize from a time server.',
|
|||||||
'dat_manually_set' => 'Set manually',
|
'dat_manually_set' => 'Set manually',
|
||||||
'dat_NTP_Server_URL' =>'NTP Server URL:',
|
'dat_NTP_Server_URL' =>'NTP Server URL:',
|
||||||
'dat_set_manually' =>'Set Date and Time:',
|
'dat_set_manually' =>'Set Date and Time:',
|
||||||
|
'dat_Invalid_date' => 'Invalid date',
|
@ -7,7 +7,7 @@
|
|||||||
.datetime-label-col {
|
.datetime-label-col {
|
||||||
background: #e8f3e2; /* light green */
|
background: #e8f3e2; /* light green */
|
||||||
padding: 1em 0em 0em 0em;
|
padding: 1em 0em 0em 0em;
|
||||||
min-width: 192px;
|
min-width: 30%;
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: flex-start;
|
align-items: flex-start;
|
||||||
justify-content: flex-end;
|
justify-content: flex-end;
|
||||||
@ -16,7 +16,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.datetime-label {
|
.datetime-label {
|
||||||
display: block;
|
display:inline-flex;
|
||||||
}
|
}
|
||||||
|
|
||||||
.datetime-fields-col {
|
.datetime-fields-col {
|
||||||
@ -27,3 +27,25 @@
|
|||||||
border-left: none;
|
border-left: none;
|
||||||
border-radius: 0 4px 4px 0;
|
border-radius: 0 4px 4px 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.datetime-clock {
|
||||||
|
min-width: 20em;
|
||||||
|
display:inline-flex;
|
||||||
|
border:0px;
|
||||||
|
padding:5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.datetime-clock-label {
|
||||||
|
background-color:#e8f3e2;
|
||||||
|
display:inline-flex;
|
||||||
|
width:30%;
|
||||||
|
font-weight:bold;
|
||||||
|
text-align:right;
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
.ntp-test-result { font-weight: bold; }
|
||||||
|
.ntp-test-success { color: green; }
|
||||||
|
.ntp-test-error { color: red; }
|
||||||
|
.ntp-test-wait { color: #333; }
|
@ -16,3 +16,86 @@ document.addEventListener('DOMContentLoaded', function() {
|
|||||||
select.addEventListener('change', toggleSections);
|
select.addEventListener('change', toggleSections);
|
||||||
toggleSections(); // Set initial state
|
toggleSections(); // Set initial state
|
||||||
});
|
});
|
||||||
|
|
||||||
|
document.addEventListener('DOMContentLoaded', function() {
|
||||||
|
// Parse the initial server time from the input value
|
||||||
|
const clockElement = document.getElementById('real-time-clock');
|
||||||
|
if (!clockElement) return;
|
||||||
|
|
||||||
|
// Get the initial server time from the input's value
|
||||||
|
let serverTime = new Date(clockElement.value.replace(' ', 'T'));
|
||||||
|
|
||||||
|
function updateDateTime() {
|
||||||
|
// Format the date/time string as desired
|
||||||
|
const daysOfWeek = ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday'];
|
||||||
|
const months = ['January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December'];
|
||||||
|
|
||||||
|
const dayOfWeek = daysOfWeek[serverTime.getDay()];
|
||||||
|
const month = months[serverTime.getMonth()];
|
||||||
|
const day = serverTime.getDate();
|
||||||
|
const year = serverTime.getFullYear();
|
||||||
|
|
||||||
|
let hours = serverTime.getHours();
|
||||||
|
const ampm = hours >= 12 ? 'PM' : 'AM';
|
||||||
|
hours = hours % 12 || 12;
|
||||||
|
|
||||||
|
const minutes = serverTime.getMinutes().toString().padStart(2, '0');
|
||||||
|
const seconds = serverTime.getSeconds().toString().padStart(2, '0');
|
||||||
|
|
||||||
|
const dateTimeString = `${dayOfWeek}, ${month} ${day}, ${year} ${hours}:${minutes}:${seconds} ${ampm}`;
|
||||||
|
clockElement.value = dateTimeString;
|
||||||
|
|
||||||
|
// Advance serverTime by one second
|
||||||
|
serverTime.setSeconds(serverTime.getSeconds() + 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
updateDateTime();
|
||||||
|
setInterval(updateDateTime, 1000);
|
||||||
|
});
|
||||||
|
|
||||||
|
document.addEventListener('DOMContentLoaded', function() {
|
||||||
|
const btn = document.getElementById('test-ntp-btn');
|
||||||
|
const input = document.getElementById('ntpserver');
|
||||||
|
const result = document.getElementById('ntp-test-result');
|
||||||
|
|
||||||
|
btn.addEventListener('click', function() {
|
||||||
|
const server = input.value.trim();
|
||||||
|
result.className = 'ntp-test-result'; // reset
|
||||||
|
|
||||||
|
if (!server) {
|
||||||
|
result.textContent = "Please enter a server address.";
|
||||||
|
result.classList.add('ntp-test-error');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
result.textContent = "Testing...";
|
||||||
|
result.classList.add('ntp-test-wait');
|
||||||
|
|
||||||
|
fetch('/smanager/datetimet', {
|
||||||
|
method: 'POST',
|
||||||
|
headers: {'Content-Type': 'application/json'},
|
||||||
|
body: JSON.stringify({ ntpserver: server })
|
||||||
|
})
|
||||||
|
.then(response => {
|
||||||
|
if (!response.ok) {
|
||||||
|
// HTTP error, e.g., 404, 500
|
||||||
|
throw new Error(`HTTP error: ${response.status} ${response.statusText}`);
|
||||||
|
}
|
||||||
|
return response.json();
|
||||||
|
})
|
||||||
|
.then(data => {
|
||||||
|
result.className = 'ntp-test-result'; // reset
|
||||||
|
if (data.success) {
|
||||||
|
result.textContent = `Server time: ${data.time}`;
|
||||||
|
result.classList.add('ntp-test-success');
|
||||||
|
} else {
|
||||||
|
result.textContent = `Error: ${data.error}`;
|
||||||
|
result.classList.add('ntp-test-error');
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.catch(error => {
|
||||||
|
// Network error or thrown HTTP error
|
||||||
|
result.className = 'ntp-test-result ntp-test-error';
|
||||||
|
result.textContent = `Request failed: ${error.message}`;
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
@ -27,7 +27,15 @@
|
|||||||
<h1><%= $title %></h1><br>
|
<h1><%= $title %></h1><br>
|
||||||
%= $modul
|
%= $modul
|
||||||
<% my $btn = l('SAVE'); %>
|
<% my $btn = l('SAVE'); %>
|
||||||
<p>
|
<br /><br />
|
||||||
|
<span>
|
||||||
|
%= label_for 'real-time-clock' => $c->l('dat_The_time_is_currently'), class => 'datetime-clock-label'
|
||||||
|
</span><span class=data2>
|
||||||
|
<!--
|
||||||
|
<div id="real-time-clock"></div>
|
||||||
|
-->
|
||||||
|
%= text_field 'clock', id => 'real-time-clock', readonly => 'readonly', class => 'datetime-clock' , value => $dat_data->{currentdatetime}
|
||||||
|
</span>
|
||||||
% if ($dat_data->{ntpstatus} eq 'disabled') {
|
% if ($dat_data->{ntpstatus} eq 'disabled') {
|
||||||
<div class='datetime-set-ntp'>
|
<div class='datetime-set-ntp'>
|
||||||
%=l 'dat_NTP_ENABLE_DESC'
|
%=l 'dat_NTP_ENABLE_DESC'
|
||||||
@ -68,7 +76,9 @@
|
|||||||
<div class=datetime-fields-col>
|
<div class=datetime-fields-col>
|
||||||
% my $server_check = '^([a-zA-Z0-9][a-zA-Z0-9\.\-]{0,253}[a-zA-Z0-9]|(\d{1,3}\.){3}\d{1,3})$';
|
% my $server_check = '^([a-zA-Z0-9][a-zA-Z0-9\.\-]{0,253}[a-zA-Z0-9]|(\d{1,3}\.){3}\d{1,3})$';
|
||||||
% param 'ntpserver' => $dat_data->{ntpserver} unless param 'ntpserver';
|
% param 'ntpserver' => $dat_data->{ntpserver} unless param 'ntpserver';
|
||||||
%= text_field ntpserver => placeholder => 'e.g. smeserver.pool.ntp.org',id => 'ntpserver', pattern => $server_check, title => 'Enter a valid hostname or IPv4 address',required => 'required'
|
%= text_field ntpserver => placeholder => 'e.g. smeserver.pool.ntp.org', id => 'ntpserver', pattern => $server_check, title => 'Enter a valid hostname or IPv4 address', required => 'required'
|
||||||
|
<button type="button" id="test-ntp-btn" class="btn btn-primary ml-2">Test Server</button>
|
||||||
|
<span id="ntp-test-result" class="ntp-test-result ml-2"></span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -2,7 +2,7 @@ Summary: Sme server navigation module : manager 2
|
|||||||
%define name smeserver-manager
|
%define name smeserver-manager
|
||||||
Name: %{name}
|
Name: %{name}
|
||||||
%define version 11.0.0
|
%define version 11.0.0
|
||||||
%define release 94
|
%define release 95
|
||||||
Version: %{version}
|
Version: %{version}
|
||||||
Release: %{release}%{?dist}
|
Release: %{release}%{?dist}
|
||||||
License: GPL
|
License: GPL
|
||||||
@ -144,6 +144,11 @@ true
|
|||||||
%defattr(-,root,root)
|
%defattr(-,root,root)
|
||||||
|
|
||||||
%changelog
|
%changelog
|
||||||
|
* Tue Jun 24 2025 Brian Read <brianr@koozali.org> 11.0.0-95.sme
|
||||||
|
- Add clock ticker to datetime panel [SME: 13054]
|
||||||
|
- Add Test Server button for ntp server [SME: 13048]
|
||||||
|
- Add checking that date is fully valid [SME: 13055]
|
||||||
|
|
||||||
* Thu Jun 19 2025 Brian Read <brianr@koozali.org> 11.0.0-94.sme
|
* Thu Jun 19 2025 Brian Read <brianr@koozali.org> 11.0.0-94.sme
|
||||||
- re-instate datetime routes in SrvMngr.pm - removed by mistake [SME: 13053]
|
- re-instate datetime routes in SrvMngr.pm - removed by mistake [SME: 13053]
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user