/* -*- 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: _('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: 'Replacements', label: _('Host match regexp ...'), key: 'host-match' }, { type: Gtk.Entry, category: 'Replacements', label: _('... to replace with'), key: 'host-replace' }, { type: Gtk.Entry, category: 'Replacements', label: _('Service match regexp ...'), key: 'service-match' }, { type: Gtk.Entry, category: 'Replacements', label: _('... to replace with'), key: 'service-replace' }, { type: Gtk.Entry, category: 'Replacements', label: _('Status info match 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, }); 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' ) { [ 'Icinga', 'Icinga2' ].forEach((item) => { this.prefWidgets[prefEntry.key].append_text(item); } ); } 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 ); }