Skip to content

Commit

Permalink
support non-numeric dashboard file names (fix #1081)
Browse files Browse the repository at this point in the history
  • Loading branch information
sni committed Apr 27, 2022
1 parent aced809 commit 928ab69
Show file tree
Hide file tree
Showing 11 changed files with 122 additions and 43 deletions.
5 changes: 5 additions & 0 deletions Changes
Original file line number Diff line number Diff line change
@@ -1,5 +1,10 @@
This file documents the revision history for the Monitoring Webinterface Thruk.

next:
- Panorama:
- support non-numeric dashboard file names
- dashboard save file can be renamed

2.48 Sat Apr 2 17:04:45 CEST 2022
- add filter to tactical overview page
- fix hostgroup overview totals when using LMD
Expand Down
2 changes: 1 addition & 1 deletion plugins/plugins-available/panorama/0.tab
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,7 @@ if(scalar @{$own} > 0) {
$dashboard->{'panlet_'.++$nr} = &{$_add_label}(20, 190, "Open Existing Dashboards:");
for my $d (@{$own}) {
last if $shown >= $maximum_number;
next if $d->{'nr'} == $dashboard->{'nr'}; # avoid recursion
next if $d->{'nr'} eq $dashboard->{'nr'}; # avoid recursion
if($x > 650) {
$x = 20;
$y = $y + 90;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -775,9 +775,9 @@ sub _task_uploadecho {
sub _task_save_dashboard {
my($c) = @_;

my $nr = $c->req->parameters->{'nr'} || die('no number supplied');
$nr =~ s/^pantab_//gmx;
my $d = Thruk::Utils::Panorama::load_dashboard($c, $nr);
my $nr = $c->req->parameters->{'nr'} || die('no number supplied');
$nr =~ s/^pantab_//gmx;
my $d = Thruk::Utils::Panorama::load_dashboard($c, $nr);
return unless Thruk::Utils::Panorama::is_authorized_for_dashboard($c, $nr, $d) >= ACCESS_READONLY;

my $data = {
Expand Down Expand Up @@ -2791,9 +2791,9 @@ sub _task_service_detail {
##########################################################
sub _task_dashboard_save_states {
my($c) = @_;
my $nr = $c->req->parameters->{'nr'} || die('no number supplied');
$nr =~ s/^pantab_//gmx;

my $nr = $c->req->parameters->{'nr'} || die('no number supplied');
$nr =~ s/^pantab_//gmx;
my $dashboard = Thruk::Utils::Panorama::load_dashboard($c, $nr, 1);
my $states;
eval {
Expand Down Expand Up @@ -2881,7 +2881,7 @@ sub _get_dashboard_by_name {
return unless $name;

for my $file (glob($c->{'panorama_etc'}.'/*.tab')) {
if($file =~ s/^.*\/(\d+)\.tab$//mx) {
if($file =~ s/^.*\/([a-zA-Z_\-\d]+)\.tab$//mx) {
my $d = Thruk::Utils::Panorama::load_dashboard($c, $1, 1);
if($d) {
if( ($d->{'tab'}->{'xdata'}->{'title'} && $d->{'tab'}->{'xdata'}->{'title'} eq $name)
Expand Down Expand Up @@ -3060,8 +3060,8 @@ sub _task_dashboard_restore {
my($c) = @_;

my $nr = $c->req->parameters->{'nr'};
my $mode = $c->req->parameters->{'mode'};
$nr =~ s/^pantab_//gmx;
my $mode = $c->req->parameters->{'mode'};
my $timestamp = $c->req->parameters->{'timestamp'};
my $dashboard = Thruk::Utils::Panorama::load_dashboard($c, $nr, 1);
my $permission = Thruk::Utils::Panorama::is_authorized_for_dashboard($c, $nr, $dashboard);
Expand Down Expand Up @@ -3525,10 +3525,10 @@ sub _add_json_dashboard_timestamps {
}
if($tab) {
my $nr = $tab;
$nr =~ s/^pantab_//gmx;
$json->{'dashboard_ts'} = {};
$nr =~ s/^pantab_//gmx;
my $file = $c->{'panorama_etc'}.'/'.$nr.'.tab';
if($nr == 0 && !-s $file) {
if($nr eq "0" && !-s $file) {
$file = $c->config->{'plugin_path'}.'/plugins-enabled/panorama/0.tab';
}
my @stat = stat($file);
Expand Down
67 changes: 58 additions & 9 deletions plugins/plugins-available/panorama/lib/Thruk/Utils/Panorama.pm
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ use warnings;
use strict;
use Cpanel::JSON::XS;
use Exporter 'import';
use File::Copy qw/move/;

use Thruk::Backend::Manager ();
use Thruk::Utils ();
Expand Down Expand Up @@ -115,9 +116,9 @@ sub get_dashboard_list {

my $dashboards = [];
for my $file (glob($c->config->{'etc_path'}.'/panorama/*.tab')) {
if($file =~ s/^.*\/(\d+)\.tab$//mx) {
if($file =~ s/^.*\/([a-zA-Z_\-\d]+)\.tab$//mx) {
my $nr = $1;
next if $nr == 0;
next if $nr eq "0";
my $d = load_dashboard($c, $nr, 1);
if($d) {
if($type eq 'all') {
Expand Down Expand Up @@ -173,7 +174,7 @@ sub get_dashboard_list {
push @{$dashboards}, {
id => $d->{'id'},
nr => $d->{'nr'},
name => $d->{'tab'}->{'xdata'}->{'title'},
name => $d->{'tab'}->{'xdata'}->{'title'} // '',
user => $d->{'user'},
perm_rw => $perm_rw,
perm_ro => $perm_ro,
Expand Down Expand Up @@ -208,14 +209,15 @@ return dashboard data.
=cut
sub load_dashboard {
my($c, $nr, $meta_data_only, $file) = @_;
$nr =~ s/^pantab_//gmx;
$file = $c->config->{'etc_path'}.'/panorama/'.$nr.'.tab' unless $file;

# only numbers allowed
return if $nr !~ m/^\-?\d+$/gmx;
$nr =~ s/^pantab_//gmx;
$file = $c->config->{'etc_path'}.'/panorama/'.$nr.'.tab' unless $file;

# only numbers and letters allowed
return if $nr !~ m/^\-?[a-zA-Z_\-\d]+$/gmx;

# startpage can be overridden, only load original file if there is none in etc/
if($nr == 0 && !-s $file) {
if($nr eq "0" && !-s $file) {
$file = $c->config->{'plugin_path'}.'/plugins-enabled/panorama/0.tab';
}

Expand Down Expand Up @@ -251,7 +253,7 @@ sub load_dashboard {
my @stat = stat($file);
$dashboard->{'ts'} = $stat[9] unless ($scripted && $dashboard->{'ts'});
$dashboard->{'nr'} = $nr;
$dashboard->{'id'} = 'pantab_'.$nr unless $nr < 0;
$dashboard->{'id'} = 'pantab_'.$nr unless $nr =~ m/^\-\d+\$/mx;
$dashboard->{'file'} = $file;
$dashboard->{'scripted'} = $scripted;

Expand Down Expand Up @@ -300,6 +302,7 @@ sub load_dashboard {
$dashboard->{'tab'}->{'xdata'}->{'state_type'} = 'soft' unless defined $dashboard->{'tab'}->{'xdata'}->{'state_type'};
$dashboard->{'tab'}->{'xdata'}->{'owner'} = $dashboard->{'user'};
$dashboard->{'tab'}->{'xdata'}->{'backends'} = Thruk::Utils::backends_hash_to_list($c, $dashboard->{'tab'}->{'xdata'}->{'backends'});
$dashboard->{'tab'}->{'xdata'}->{'file'} = $nr.".tab";

for my $key (keys %{$dashboard}) {
if($key =~ m/_panlet_(\d+)$/mx) {
Expand Down Expand Up @@ -373,6 +376,7 @@ sub save_dashboard {
delete $dashboard->{'locked'};
delete $dashboard->{'tab'}->{'xdata'}->{'owner'};
delete $dashboard->{'tab'}->{'xdata'}->{''};
my $newfile = delete $dashboard->{'tab'}->{'xdata'}->{'file'};
delete $dashboard->{'tab'}->{'readonly'};
delete $dashboard->{'tab'}->{'user'};
delete $dashboard->{'tab'}->{'ts'};
Expand Down Expand Up @@ -400,6 +404,12 @@ sub save_dashboard {
$dashboard->{'nr'} = $nr;
$dashboard->{'id'} = 'pantab_'.$nr;
$dashboard->{'ts'} = [stat($file)]->[9];

my $filename = $nr.'.tab';
if($newfile && $newfile ne $filename) {
$dashboard = move_dashboard($c, $dashboard, $filename, $newfile);
}

return $dashboard;
}

Expand Down Expand Up @@ -445,6 +455,7 @@ returns:
sub is_authorized_for_dashboard {
my($c, $nr, $dashboard) = @_;
$nr =~ s/^pantab_//gmx;

my $file = $c->config->{'etc_path'}.'/panorama/'.$nr.'.tab';

# super user have permission for all reports
Expand Down Expand Up @@ -513,6 +524,44 @@ sub delete_dashboard {

##########################################################

=head2 move_dashboard
move_dashboard($c, $dashboard, $filename, $newfile)
rename dashboard file and return new dashboard data
=cut
sub move_dashboard {
my($c, $dashboard, $filename, $newfile) = @_;

if($newfile !~ m/^[a-zA-Z0-9_\-]+\.tab$/gmx) {
Thruk::Utils::set_message($c, 'fail_message', 'Renaming dashboard failed, invalid filename.');
return($dashboard);
}

my $newnr = $newfile;
$newnr =~ s/\.tab//gmx;
my $oldnr = $dashboard->{'id'};
$oldnr =~ s/^pantab_//gmx;

if(-e $c->config->{'etc_path'}.'/panorama/'.$newfile) {
Thruk::Utils::set_message($c, 'fail_message', 'Renaming dashboard failed, '.$newfile.' does already exist.');
return($dashboard);
}
for my $folder ($c->config->{'etc_path'}.'/panorama', $c->config->{'var_path'}.'/panorama') {
for my $file (glob($folder.'/'.$oldnr.'.*')) {
my $movedfile = $file;
$movedfile =~ s/^.*\///gmx;
$movedfile =~ s/^\Q$oldnr\E/\Q$newnr\E/gmx;
move($file, $folder.'/'.$movedfile);
}
}
Thruk::Utils::set_message($c, 'success_message', 'Renamed dashboard to: '.$newfile);
return(load_dashboard($c, $newnr));
}

##########################################################

=head2 get_runtime_file
get_runtime_file($c, $nr)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -133,9 +133,10 @@ sub _cleanup_dashboard {
##############################################
sub _merge_meta {
my($dashboard, $meta) = @_;
$dashboard->{'tab'}->{'xdata'}->{'title'} = $meta->{'title'} unless defined $dashboard->{'tab'}->{'xdata'}->{'title'};
$dashboard->{'tab'}->{'xdata'}->{'groups'} = $meta->{'groups'} unless defined $dashboard->{'tab'}->{'xdata'}->{'groups'};
$dashboard->{'user'} = $meta->{'user'} unless defined $dashboard->{'user'};
$dashboard->{'tab'}->{'xdata'}->{'title'} = $meta->{'title'} unless defined $dashboard->{'tab'}->{'xdata'}->{'title'};
$dashboard->{'tab'}->{'xdata'}->{'groups'} = $meta->{'groups'} unless defined $dashboard->{'tab'}->{'xdata'}->{'groups'};
$dashboard->{'tab'}->{'xdata'}->{'file'} = $meta->{'nr'}.'.tab' unless defined $dashboard->{'tab'}->{'xdata'}->{'file'};
$dashboard->{'user'} = $meta->{'user'} unless defined $dashboard->{'user'};
$dashboard->{'nr'} = $meta->{'nr'};
return($dashboard);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,7 @@ var TP = {
add_pantab: function(opt) {
if(!Ext.isObject(opt)) { opt = { id: opt }; }
var id = opt.id;
if(id && Ext.isNumeric(String(id))) {
if(id && id != "new" && id != "new_geo" && id != "new_or_empty") {
id = TP.nr2TabId(id);
}
var tabbar = Ext.getCmp('tabbar');
Expand Down Expand Up @@ -325,8 +325,8 @@ var TP = {

// add additionall hidden dashboards required from icons
for(var key in data) {
var matches = key.match(/^pantab_\d+$/);
if(matches && matches[0] != opt.id && !Ext.getCmp(matches[0])) {
var matches = key.match(/^pantab_.*/);
if(matches && !matches[0].match(/^pantab_.*_panlet_\d+/) && matches[0] != opt.id && !Ext.getCmp(matches[0])) {
TP.add_pantab({ id: matches[0], hidden: true });
}
}
Expand Down Expand Up @@ -2116,7 +2116,7 @@ var TP = {
for(var key in data) {
var cfg = anyDecode(data[key]);
var p = Ext.getCmp(key);
if(p && key.search(/pantab_\d+$/) != -1) {
if(p && key.match(/^pantab_/) && !key.match(/^pantab_.*_panlet_\d+/)) {
if((p.xdata.map && !cfg.xdata.map) || (!p.xdata.map && cfg.xdata.map)) { mapChanged = true; }
/* changes in our dashboard itself */
Ext.apply(p, cfg);
Expand All @@ -2133,7 +2133,7 @@ var TP = {
var cfg = anyDecode(data[key]);
var p = Ext.getCmp(key);

if(key.search(/pantab_\d+$/) != -1 || key == "tabbar") {
if((key.match(/pantab_/) && !key.match(/pantab_.*_panlet_\d+/)) || key == "tabbar") {
/* tab has been updated already */
continue;
}
Expand Down Expand Up @@ -2438,7 +2438,7 @@ var TP = {
var numbers = [];
for(var nr=0; nr<open_tabs.length; nr++) {
var num = open_tabs[nr].replace(/^pantab_/, '');
if(num > 0) {
if(num != "0") {
numbers.push(num);
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -314,7 +314,7 @@ TP.iconClickHandlerExec = function(id, link, panel, target, config, extraOptions
var menu = link.match(/menu:\/\/(.+)$/);
if(special && special[1]) {
link = undefined;
if(special[1].match(/^\d+$/)) {
if(special[1].match(/^[a-zA-Z_\-\d]+$/)) {
// is that tab already open?
var tabbar = Ext.getCmp('tabbar');
var tab_id = "pantab_"+special[1];
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ Ext.define('TP.Pantab', {
// fetch window ids from state
this.window_ids = [];
for(var key in TP.cp.state) {
var matches = key.match(/^(pantab_\d+)_panlet_(\d+)$/);
var matches = key.match(/^(pantab_.+)_panlet_(\d+)$/);
if(matches && matches[1] == this.id) {
this.window_ids.push(key);
}
Expand Down Expand Up @@ -238,7 +238,7 @@ Ext.define('TP.Pantab', {
}
}

var text = "double click to open settings (dashboard #"+tab.nr()+")";
var text = "double click to open settings ("+tab.nr()+".tab)";
if(readonly || dashboard_ignore_changes) {
text = "this is dashboard #"+tab.nr();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -550,11 +550,25 @@ TP.tabSettingsWindowDo = function(mask, nr, closeAfterEdit) {
boxLabel: '(disables dashboard editing)',
handler: function(el, checked) { TP.tabSettingsWindowLocked(tab, checked); }
}, {
/* tab title */
xtype: 'textfield',
name: 'title',
fieldLabel: 'Title',
listeners: { change: function(This, newValue, oldValue, eOpts) { document.title = newValue; } }
xtype: 'fieldcontainer',
layout: 'hbox',
items: [{
/* tab title */
xtype: 'textfield',
name: 'title',
flex: 1,
listeners: { change: function(This, newValue, oldValue, eOpts) { document.title = newValue; } }
},
{ xtype: 'label', text: 'File:', style: 'margin-left: 10px; margin-right: 2px; text-align: right;', cls: 'x-form-item-label' },
{
/* file name */
xtype: 'textfield',
name: 'file',
flex: 1,
regex: RegExp(/^[a-zA-Z_\-\d]+.tab$/),
regexText: 'the filename must have the form: [a-zA-Z0-9_-].tab'
}]
}, {
/* tab description */
xtype: 'textarea',
Expand Down Expand Up @@ -1002,7 +1016,7 @@ TP.tabSettingsWindowDo = function(mask, nr, closeAfterEdit) {
modal: true,
width: 620,
height: 400,
title: 'Settings: '+(tab.xdata.title ? tab.xdata.title+' - ' : '')+'#'+tab.nr(),
title: 'Settings: '+(tab.xdata.title ? tab.xdata.title+' - ' : '')+tab.nr()+'.tab',
layout : 'fit',
buttonAlign: 'center',
items: tabPanel,
Expand Down Expand Up @@ -1146,10 +1160,16 @@ TP.tabSettingsWindowDo = function(mask, nr, closeAfterEdit) {
/* reload, permissions might have changed */
tab.addMask("reloading dashboard...");
TP.cp.saveChanges(null, function() {
TP.renewDashboardDo(tab, function() {
var newName = tab.xdata['file'].replace(/\.tab$/, '');
if(newName != tab.nr()) {
tab_win_settings.destroy();
tab.setLock(locked);
});
TP.add_pantab({ id: newName, replace_id: tab.id });
} else {
TP.renewDashboardDo(tab, function() {
tab_win_settings.destroy();
tab.setLock(locked);
});
}
});
}
}
Expand Down
Loading

0 comments on commit 928ab69

Please sign in to comment.