/* -*- mode: js; js-basic-offset: 4; indent-tabs-mode: nil -*- */
/*
Monito Gnome-Shell extension
Copyright (C) 2021 Benjamin Drieu
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License along
with this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
SPDX-License-Identifier: GPL-2.0-or-later
*/
const Gio = imports.gi.Gio;
const GLib = imports.gi.GLib;
const Gtk = imports.gi.Gtk;
const Gdk = imports.gi.Gdk;
// It's common practice to keep GNOME API and JS imports in separate blocks
const Lang = imports.lang;
const ExtensionUtils = imports.misc.extensionUtils;
const Me = ExtensionUtils.getCurrentExtension();
const Convenience = Me.imports.convenience;
const Mainloop = imports.mainloop;
const Gettext = imports.gettext.domain('monito');
const _ = Gettext.gettext;
const N_ = function (e) {
return e;
};
const SETTINGS_SCHEMA = "org.gnome.shell.extensions.monito";
const SETTINGS_SCHEMA_ACCOUNT = "org.gnome.shell.extensions.monito.account";
const SETTINGS_SCHEMA_ACCOUNT_PATH = "/org/gnome/shell/extensions/monito/account";
const prefs = [
{ type: Gtk.Entry, category: 'Settings', label: _('Name'), key: 'name' },
{ type: Gtk.ComboBoxText, category: 'Settings', label: _('Type'), key: 'type' },
{ type: Gtk.Entry, category: 'Settings', label: _('Username'), key: 'username' },
{ type: Gtk.Entry, category: 'Settings', label: _('Password'), key: 'password' },
{ type: Gtk.Entry, category: 'Settings', label: _('URL CGI'), key: 'urlcgi' },
{ type: Gtk.ColorButton, category: 'Colors', label: _('OK background color'), key: 'ok-color', align: Gtk.Align.START },
{ type: Gtk.ColorButton, category: 'Colors', label: _('Warning background color'), key: 'warning-color', align: Gtk.Align.START },
{ type: Gtk.ColorButton, category: 'Colors', label: _('Critical background color'), key: 'critical-color', align: Gtk.Align.START },
{ type: Gtk.ColorButton, category: 'Colors', label: _('Unknown background color'), key: 'unknown-color', align: Gtk.Align.START },
{ type: Gtk.ColorButton, category: 'Colors', label: _('OK color'), key: 'ok-fg', align: Gtk.Align.START },
{ type: Gtk.ColorButton, category: 'Colors', label: _('Warning color'), key: 'warning-fg', align: Gtk.Align.START },
{ type: Gtk.ColorButton, category: 'Colors', label: _('Critical color'), key: 'critical-fg', align: Gtk.Align.START },
{ type: Gtk.ColorButton, category: 'Colors', label: _('Unknown color'), key: 'unknown-fg', align: Gtk.Align.START },
{ type: Gtk.Entry, category: 'Filters', label: _('Only display hosts matching'), key: 'host-grep' },
{ type: Gtk.Entry, category: 'Filters', label: _('Only display services matching'), key: 'service-grep' },
{ type: Gtk.Entry, category: 'Filters', label: _('Only display status info matching'), key: 'status-info-grep' },
{ type: Gtk.Entry, category: 'Filters', label: _('Do not display hosts matching'), key: 'host-filter-out' },
{ type: Gtk.Entry, category: 'Filters', label: _('Do not display services matching'), key: 'service-filter-out' },
{ type: Gtk.Entry, category: 'Filters', label: _('Do not display status info matching'), key: 'status-info-filter-out' },
{ type: Gtk.Entry, category: 'Replacements', label: _('Host regexp ...'), key: 'host-match' },
{ type: Gtk.Entry, category: 'Replacements', label: _('... to replace with'), key: 'host-replace' },
{ type: Gtk.Entry, category: 'Replacements', label: _('Service regexp ...'), key: 'service-match' },
{ type: Gtk.Entry, category: 'Replacements', label: _('... to replace with'), key: 'service-replace' },
{ type: Gtk.Entry, category: 'Replacements', label: _('Status info regexp ...'), key: 'status-info-match' },
{ type: Gtk.Entry, category: 'Replacements', label: _('... to replace with'), key: 'status-info-replace' },
];
// Like 'extension.js' this is used for any one-time setup like translations.
function init() {
monitoLog('initializing ${Me.metadata.name} Preferences');
this.settings = ExtensionUtils.getSettings(SETTINGS_SCHEMA);
monitoLog ( 'Foo: ' + Me.metadata );
}
// This function is called when the preferences window is first created to build
// and return a Gtk widget. As an example we'll create and return a GtkLabel.
function buildPrefsWidget() {
// Copy the same GSettings code from `extension.js`
this.settings = ExtensionUtils.getSettings(SETTINGS_SCHEMA);
let mainVbox = new Gtk.Box( { orientation: Gtk.Orientation.VERTICAL } );
let mainWidget = new Gtk.Notebook( { } );
let prefsWidget = new Gtk.Grid({
margin: 18,
column_spacing: 12,
row_spacing: 12,
column_homogeneous: false,
});
this.prefWidgets = { };
// Add a simple title and add it to the prefsWidget
let title = new Gtk.Label({
label: `${Me.metadata.name} Preferences`,
halign: Gtk.Align.START,
use_markup: true,
});
prefsWidget.attach(title, 0, 0, 2, 1);
let _label = new Gtk.Label({
label: 'Poll delay in seconds',
visible: true,
halign: Gtk.Align.START,
});
prefsWidget.attach ( _label, 0, 1, 1, 1 );
let _entry = new Gtk.SpinButton ({
numeric: true,
halign: Gtk.Align.FILL,
visible: true,
hexpand: true,
can_focus: true,
});
_entry.set_range ( 1, 1000 );
_entry.set_increments ( 1, 5 );
prefsWidget.attach ( _entry, 1, 1, 1, 1 );
this.settings.bind ( 'poll-delay', _entry, 'value', Gio.SettingsBindFlags.DEFAULT );
// Misc Settings (TBD)
mainWidget.append_page ( prefsWidget,
new Gtk.Label ( { label: 'General', } ) );
// Accounts
this._accountsWidgetContainer = new Gtk.Box( { orientation: Gtk.Orientation.HORIZONTAL,
homogeneous: false, } );
mainWidget.append_page ( this._accountsWidgetContainer,
new Gtk.Label ( { label: 'Servers', } ) );
let accountsChooserContainer = new Gtk.Box( { orientation: Gtk.Orientation.VERTICAL,
homogeneous: false, } );
this._accountsWidgetContainer.pack_start(accountsChooserContainer, true, true, 0);
this.accountsChooser = new Gtk.ListBox ( { valign: Gtk.Align.FILL,
hexpand: true,
vexpand: true } );
accountsChooserContainer.pack_start(this.accountsChooser, true, true, 0);
// Account list
for ( var server_id of this.getServersList ( ) )
this.addAccountLine ( server_id );
this.accountsChooser.connect ( 'row-activated', Lang.bind ( this, this.activateAccountRow ) );
// Action Bar
let accountsChooserActionBar = new Gtk.ActionBar ( { valign: Gtk.Align.END } );
accountsChooserContainer.pack_start(accountsChooserActionBar, true, true, 0);
let accountCreateButton = Gtk.Button.new_from_icon_name ( 'list-add',
Gtk.IconSize.BUTTON );
accountsChooserActionBar.add ( accountCreateButton );
accountCreateButton.connect ( 'clicked', Lang.bind ( this, this.createAccount ) );
let accountRemoveButton = Gtk.Button.new_from_icon_name ( 'list-remove',
Gtk.IconSize.BUTTON );
accountsChooserActionBar.add ( accountRemoveButton );
accountRemoveButton.connect ( 'clicked', Lang.bind ( this, this.removeAccount ) );
this.createAccountWidgets ( false ) ;
mainVbox.pack_start(mainWidget, true, true, 0);
mainVbox.show_all();
return mainVbox;
}
function getServersList ( )
{
if ( ! this.settings )
this.settings = ExtensionUtils.getSettings(SETTINGS_SCHEMA);
return this.settings.get_string ( 'servers' ) . split ( ',' );
}
function getAccountSettings ( id )
{
let _path = SETTINGS_SCHEMA_ACCOUNT_PATH + '/' + id + '/';
return Convenience.getSettings(SETTINGS_SCHEMA_ACCOUNT, _path);
}
function getSortOrder ( server )
{
return this.getAccountSettings ( server ) . get_strv ( 'columns-order' );
}
function setSortOrder ( server, sort_order )
{
return this.getAccountSettings ( server ) . set_strv ( 'columns-order', sort_order );
}
function getColumns ( server )
{
return this.getAccountSettings ( server ) . get_strv ( 'columns' );
}
function setColumns ( server, columns )
{
return this.getAccountSettings ( server ) . set_strv ( 'columns', columns );
}
function createAccountWidgets ( isActive )
{
this.prefWidgets = { };
this._accountsWidget = new Gtk.Notebook( { } );
this._accountsWidgetContainer.pack_start(this._accountsWidget, true, true, 0);
for ( var _tab of [ 'Settings', 'Colors', 'Filters', 'Replacements' ] )
{
this.createPrefWidgets ( _accountsWidget, _tab, isActive );
}
// Settings
this.prefWidgets['name'].connect('changed', Lang.bind(this, function () {
let _row = this.accountsChooser.get_selected_row();
_row.get_child().label = this.prefWidgets['name'].text;
} ) );
this._accountsWidget.show_all();
}
function createPrefWidgets ( noteBook, type, isActive )
{
let grid = new Gtk.Grid ( {
halign: Gtk.Align.FILL,
margin: 18,
column_spacing: 12,
row_spacing: 12,
visible: true,
column_homogeneous: false,
});
noteBook.append_page ( grid, new Gtk.Label ( { label: _(type), } ) );
let y = 0;
for ( var prefEntry of prefs )
{
if ( prefEntry.category != type )
continue;
let _label = new Gtk.Label({
label: prefEntry.label + ':',
visible: true,
halign: Gtk.Align.START,
use_markup: true,
});
grid.attach ( _label, 0, y, 1, 1 );
this.prefWidgets[prefEntry.key] = new prefEntry.type ( {
halign: ( prefEntry.align ? prefEntry.align : Gtk.Align.FILL ),
visible: true,
hexpand: true,
can_focus: isActive,
} );
let boundValue = 'text';
if ( prefEntry.key == 'password' )
{
this.prefWidgets[prefEntry.key].set_input_purpose ( Gtk.InputPurpose.PASSWORD );
this.prefWidgets[prefEntry.key].set_visibility ( false );
}
else if ( prefEntry.key == 'type' )
{
[ { name: 'Icinga', value: 'Icinga server' },
{ name: 'Icinga2', value: 'Icinga2 server (using Icingaweb2)' },
{ name: 'Icinga2API', value: 'Icinga2 server (using API)' } ].forEach((item) => {
this.prefWidgets[prefEntry.key].insert ( -1, item.name, item.value );
} );
}
grid.attach(this.prefWidgets[prefEntry.key], 1, y, 1, 1);
if ( prefEntry.type != Gtk.ComboBoxText )
{
// this.account_settings.bind(
// prefEntry.key,
// _entry,
// boundValue,
// Gio.SettingsBindFlags.DEFAULT
// );
}
y++;
}
}
function activateAccountRow ( ) {
if ( this._accountsWidget )
this._accountsWidget.destroy ( );
this.createAccountWidgets ( true );
let _row = this.accountsChooser.get_selected_row();
monitoLog('Active:' + _row.server);
let _account_settings = getAccountSettings ( _row.server );
if ( ! _account_settings )
return;
for ( var prefEntry of prefs )
{
if ( prefEntry.type == Gtk.Entry )
{
_account_settings.bind (
prefEntry.key,
this.prefWidgets[prefEntry.key],
'text',
Gio.SettingsBindFlags.DEFAULT
);
}
else if ( prefEntry.type == Gtk.ColorButton )
{
let _color = new Gdk.RGBA ( );
_color.parse (_account_settings.get_string(prefEntry.key) );
this.prefWidgets[prefEntry.key].set_use_alpha ( false );
this.prefWidgets[prefEntry.key].set_rgba ( _color );
this.prefWidgets[prefEntry.key].connect('color-set', Lang.bind ( { key: prefEntry.key, settings: _account_settings }, setColor ) );
}
else if ( prefEntry.type == Gtk.ComboBoxText )
{
this.prefWidgets[prefEntry.key].set_active(_account_settings.get_enum('type'));
this.prefWidgets[prefEntry.key].connect('changed', Lang.bind(this, function (e) {
monitoLog ( e ) ;
monitoLog('Active:' + this.prefWidgets['type'].get_active());
let _account_settings = getAccountSettings ( _row.server );
_account_settings.set_enum('type', this.prefWidgets['type'].get_active());
}));
}
}
}
function addAccountLine ( server_id )
{
monitoLog ( '> Add line ' + server_id );
let _account_settings = getAccountSettings ( server_id );
let row = new Gtk.ListBoxRow ( { hexpand: true,
halign: Gtk.Align.FILL } );
row.server = server_id;
let _label = new Gtk.Label ( { label: _account_settings.get_string('name'),
hexpand: true,
margin: 5,
halign: Gtk.Align.START,
expand: true } );
row.add ( _label );
this.accountsChooser.add ( row );
this.accountsChooser.show_all();
}
function createAccount ( ) {
monitoLog ( '> Create Account' );
let _servers = this.getServersList ( );
let _max = Math.max ( ..._servers );
let _server_id = _max + 1;
_servers.push ( _server_id );
let _account_settings = getAccountSettings ( _server_id );
_account_settings.set_string ( 'name', _('New server #') + _server_id );
this.addAccountLine ( _max + 1 );
this.settings.set_string ( 'servers', _servers.join(',') );
}
function removeAccount ( ) {
let _row = this.accountsChooser.get_selected_row();
monitoLog('Active:' + _row.server);
let _servers = this.getServersList ( );
_servers.splice ( _servers.indexOf ( _row.server ), 1 );
monitoLog ( _servers );
if ( ! _row )
return;
_row.destroy();
this.settings.set_string ( 'servers', _servers . join ( ',' ) );
}
function setColor ( color )
{
monitoLog ( 'Color ' + + ': ' + color );
let _output = '#%02x%02x%02x'.format(
255 * color.get_rgba().red,
255 * color.get_rgba().green,
255 * color.get_rgba().blue );
this.settings.set_string('' + this.key, _output);
}
function monitoLog ( msg )
{
log ( 'Monito: ' + msg );
}