diff --git a/extension.js b/extension.js index 51baaef..5ab724f 100644 --- a/extension.js +++ b/extension.js @@ -46,6 +46,7 @@ const SETTINGS_SCHEMA_ACCOUNT = "org.gnome.shell.extensions.monito.account"; const SETTINGS_SCHEMA_ACCOUNT_PATH = "/org/gnome/shell/extensions/monito/account"; const Convenience = Me.imports.convenience; +const GenericServer = Me.imports.servers.genericserver.GenericServer; const Icinga = Me.imports.servers.icinga.Icinga; const Icinga2 = Me.imports.servers.icinga2.Icinga2; const Preferences = Me.imports.prefs; @@ -53,14 +54,14 @@ const Preferences = Me.imports.prefs; let settings = Convenience.getSettings(SETTINGS_SCHEMA); let account_settings = [ ]; -const column_definitions = [ - { name: 'status', width: 50, expand: false, }, - { name: 'host_name', width: 300, expand: false, }, - { name: 'service_display_name', width: 300, expand: false, }, - { name: 'last_check', width: 200, expand: false, }, - { name: 'attempts', width: 50, expand: false, }, - { name: 'status_information', width: 600, expand: true, }, -]; +const column_definitions = { + status: { label: _('Status'), width: 50, expand: false, }, + host_name: { label: _('Host name'), width: 300, expand: false, }, + service_display_name: { label: _('Service'), width: 300, expand: false, }, + last_check: { label: _('Last check'), width: 200, expand: false, }, + attempts: { label: _('Attempts'), width: 50, expand: false, }, + status_information: { label: _('Information'), width: 600, expand: true, }, +}; const Indicator = GObject.registerClass( @@ -77,6 +78,16 @@ class Indicator extends PanelMenu.Button { this.criticalBoxes = { }; this.unknownBoxes = { }; + this.sortIcons = { }; + account_settings [ server ] = Preferences.getAccountSettings ( this.server ); + this.account_settings = account_settings [ server ]; + + let type = this.account_settings.get_string ( "type" ); + if ( type == 'Icinga' ) + this.serverlogic = new Icinga ( this.server ); + else if ( type == 'Icinga2' ) + this.serverlogic = new Icinga2 ( this.server ); + this.initUI ( ); } @@ -85,32 +96,30 @@ class Indicator extends PanelMenu.Button { this.add_child(box); monitoLog ( '> Server ' + this.server ); - account_settings [ this.server ] = Preferences.getAccountSettings ( this.server ); - let _account_settings = account_settings [ this.server ]; let serverBox = new St.BoxLayout ( { style_class: 'monito-serverbox' } ); box.add_child(serverBox); let name_box = new St.BoxLayout( { style_class: 'monito-namebox' } ); - this.namesBoxes [ this.server ] = new St.Label ( { text: _account_settings.get_string ( 'name' ) } ); + this.namesBoxes [ this.server ] = new St.Label ( { text: this.account_settings.get_string ( 'name' ) } ); name_box.add_child ( this.namesBoxes [ this.server ] ); serverBox.add_child(name_box); - _account_settings.bind ( 'name', this.namesBoxes [ this.server ], 'text', Gio.SettingsBindFlags.GET ); + this.account_settings.bind ( 'name', this.namesBoxes [ this.server ], 'text', Gio.SettingsBindFlags.GET ); this.namesBoxes [ this.server ].connect ( 'button-press-event', Lang.bind ( this, function ( ) { this.setMenu ( this.menu ); } ) ); let warning_box = new St.BoxLayout({ style_class: 'monito-warning-box monito-box' }); - warning_box.set_style ( 'background-color: ' + _account_settings.get_string ( 'warning-color' ) ); - _account_settings.connect("changed::warning-color", Lang.bind ( { widget: warning_box }, setColor ) ); + warning_box.set_style ( 'background-color: ' + this.account_settings.get_string ( 'warning-color' ) ); + this.account_settings.connect("changed::warning-color", Lang.bind ( { widget: warning_box }, setColor ) ); this.warningBoxes [ this.server ] = new St.Label({ text: String(_status['WARNING']) }) warning_box.add_child ( this.warningBoxes [ this.server ] ); serverBox.add_child(warning_box); let critical_box = new St.BoxLayout({ style_class: 'monito-critical-box monito-box' }); - critical_box.set_style ( 'background-color: ' + _account_settings.get_string ( 'critical-color' ) ); - _account_settings.connect("changed::critical-color", Lang.bind ( { widget: critical_box }, setColor ) ); + critical_box.set_style ( 'background-color: ' + this.account_settings.get_string ( 'critical-color' ) ); + this.account_settings.connect("changed::critical-color", Lang.bind ( { widget: critical_box }, setColor ) ); this.criticalBoxes [ this.server ] = new St.Label({ text: String(_status['CRITICAL']) }) critical_box.add_child ( this.criticalBoxes [ this.server ] ); @@ -135,7 +144,7 @@ class Indicator extends PanelMenu.Button { _iconBin.child = _icon; this._buttonMenu.actor.add_actor(_iconBin); - this._mainLabel = new St.Label({ style_class: 'monito-title', text: 'Monito Checker', x_expand: true }); + this._mainLabel = new St.Label ( { style_class: 'monito-title', text: 'Monito Checker', x_expand: true } ); this._buttonMenu.actor.add_actor(this._mainLabel); this._prefsButton = this._createButton ( 'preferences-system-symbolic', 'Preferences', this._onPreferencesActivate ); @@ -184,57 +193,63 @@ class Indicator extends PanelMenu.Button { updateStatus ( ) { - for ( let _server of Preferences.getServersList() ) + if ( ! this.serverlogic.refresh ( this ) ) { - let _account_settings = Preferences.getAccountSettings ( this.server ); - - let type = _account_settings.get_string("type"); - let username = _account_settings.get_string("username"); - let password = _account_settings.get_string("password"); - let urlcgi = _account_settings.get_string("urlcgi"); - - if ( ! urlcgi ) - { - monitoLog ( 'Not updating monito because no URL configured' ); - } - else - { - let _serverLogic; - if ( type == 'Icinga' ) - _serverLogic = new Icinga ( this.server ); - else if ( type == 'Icinga2' ) - _serverLogic = new Icinga2 ( this.server ); - - if ( ! _serverLogic.refresh ( this ) ) - { - this.warningBoxes[this.server].set_text ( '…' ); - this.criticalBoxes[this.server].set_text ( '…' ); - // TODO: Add display of error if any - } - } + this.warningBoxes[this.server].set_text ( '…' ); + this.criticalBoxes[this.server].set_text ( '…' ); } this.setupTimeout ( ); } - createHeaderBin ( status, text, col ) { - let _widths = [ 300, 300, 200, 50, 600 ]; - let _bin = new St.Bin({ - style_class: 'monito-service-' + status, - width: col.width, - x_expand: col.expand, - child: new St.Button ( { + createHeaderBin ( colName ) { + let col = column_definitions [ colName ]; + + let _box = new St.BoxLayout ( { vertical: false, + x_expand: true } ); + _box.add_child ( new St.Label ( { text: col.label, + x_expand: true, + x_align: Clutter.ActorAlign.START } ) ); + + let _iconBin = new St.Bin ( { x_align: Clutter.ActorAlign.END }); + _box.add_child ( _iconBin ); + + let _iconName = ''; + let _sortOrder = Preferences.getSortOrder ( this.server ); + if ( _sortOrder.indexOf ( colName + '+' ) >= 0 ) + _iconName = 'view-sort-descending-symbolic'; + else if ( _sortOrder.indexOf ( colName + '-' ) >= 0 ) + _iconName = 'view-sort-ascending-symbolic'; + + this.sortIcons [ colName ] = new St.Icon ( { + style_class: 'monito-button-icon', + icon_name: _iconName, + icon_size: 16, + } ); + _iconBin.child = this.sortIcons [ colName ]; + + let _button = new St.Button ( { x_align: Clutter.ActorAlign.START, y_align: Clutter.ActorAlign.CENTER, width: col.width, reactive: true, can_focus: true, track_hover: true, - accessible_name: text, + accessible_name: col.label, style_class: 'button', - label: col.name, - }) + } ); + _button.column = colName; + + _button.add_actor ( _box ); + _button.connect ( 'clicked', Lang.bind ( this, this._onSortColumnClick ) ); + + let _bin = new St.Bin({ + style_class: 'monito-service', + width: col.width, + x_expand: col.expand, + child: _button, }); + return _bin; } @@ -249,14 +264,14 @@ class Indicator extends PanelMenu.Button { return _bin; } - refreshUI ( serverLogic ) { - this.initStatus ( ); // Specialize ! + refreshUI ( ) { + this.initStatus ( ); this._box.remove_all_children(); - if ( serverLogic.error ) + if ( this.serverlogic.error ) { - this._box.add_child ( new St.Label ( { style_class: 'monito-network-error', text: serverLogic.error } ) ); + this._box.add_child ( new St.Label ( { style_class: 'monito-network-error', text: this.serverlogic.error } ) ); return; } @@ -265,8 +280,10 @@ class Indicator extends PanelMenu.Button { x_expand: true }); this._box.add_child(headerBox); - for ( let col of column_definitions ) - headerBox.add_child ( this.createHeaderBin ( '', col.name, col ) ); + + let _columns = Preferences.getColumns ( this.server ); + for ( let _col of _columns ) + headerBox.add_child ( this.createHeaderBin ( _col ) ); let scrollBox = new St.ScrollView ( { hscrollbar_policy: St.PolicyType.NEVER, enable_mouse_scrolling: true, } ); @@ -279,29 +296,28 @@ class Indicator extends PanelMenu.Button { }); scrollBox.add_actor(tableBox); - for ( let i = 0 ; i < serverLogic.status.service_status.length ; i ++ ) + for ( let entry of this.serverlogic.getProcessedStatus ( ) ) { - _status [ serverLogic.status.service_status[i].status ] ++; - if ( serverLogic.status.service_status[i].status != 'OK' ) + _status [ entry.status ] ++; + if ( entry.status != 'OK' ) { let infoBox = new St.BoxLayout({ - style_class: 'monito-service-line monito-service-line-' + serverLogic.status.service_status[i].status, + style_class: 'monito-service-line monito-service-line-' + entry.status, track_hover: true, x_expand: true, }); tableBox.add_child(infoBox); - for ( let col of column_definitions ) + let _columns = Preferences.getColumns ( this.server ); + for ( let _col of _columns ) { - infoBox.add_child ( this.createBin ( serverLogic.status.service_status[i].status, - serverLogic.status.service_status[i][col.name], - col ) ); + infoBox.add_child ( this.createBin ( entry.status, entry [ _col ], column_definitions [ _col ] ) ); } } } - this.warningBoxes[serverLogic.server].set_text ( String(_status.WARNING) ); - this.criticalBoxes[serverLogic.server].set_text ( String(_status.CRITICAL) ); + this.warningBoxes[this.serverlogic.server].set_text ( String(_status.WARNING) ); + this.criticalBoxes[this.serverlogic.server].set_text ( String(_status.CRITICAL) ); return; } @@ -319,6 +335,26 @@ class Indicator extends PanelMenu.Button { return 0; } + _onSortColumnClick ( button ) { + monitoLog ( 'column >> ' + button.column ); + + let _sortOrder = Preferences.getSortOrder ( this.server ); + let _columns = Preferences.getColumns ( this.server ); + + let _indexPlus = _sortOrder.indexOf ( button.column + '+' ); + let _indexMinus = _sortOrder.indexOf ( button.column + '-' ); + + if ( _indexPlus >= 0 ) + _sortOrder [ _indexPlus ] = button.column + '-'; + else if ( _indexMinus >= 0 ) + _sortOrder.splice ( _indexMinus, 1 ); + else + _sortOrder.unshift ( button.column + '+' ); + + Preferences.setSortOrder ( this.server, _sortOrder ); + this.refreshUI ( ); + } + _createButton ( icon, text, callback ) { let button = new St.Button({ x_align: Clutter.ActorAlign.END, diff --git a/prefs.js b/prefs.js index 4c8fc44..6907999 100644 --- a/prefs.js +++ b/prefs.js @@ -174,6 +174,30 @@ function getAccountSettings ( id ) } +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 ) { // Accounts diff --git a/schemas/org.gnome.shell.extensions.monito@drieu.org.gschema.xml b/schemas/org.gnome.shell.extensions.monito@drieu.org.gschema.xml index 228d517..95bdcf0 100644 --- a/schemas/org.gnome.shell.extensions.monito@drieu.org.gschema.xml +++ b/schemas/org.gnome.shell.extensions.monito@drieu.org.gschema.xml @@ -93,11 +93,11 @@ - ['service_description'] + ['status','host_name','service_display_name','last_check','attempts','status_information'] - - [0] + + ['host_name+','service_display_name+'] diff --git a/servers/genericserver.js b/servers/genericserver.js new file mode 100644 index 0000000..e399943 --- /dev/null +++ b/servers/genericserver.js @@ -0,0 +1,76 @@ +/* -*- 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 { Soup } = imports.gi; + +const ExtensionUtils = imports.misc.extensionUtils; +const Lang = imports.lang; +const Main = imports.ui.main; +const Me = ExtensionUtils.getCurrentExtension(); +const Preferences = Me.imports.prefs; + +let _httpSession; + + +class GenericServer { + constructor ( _server, _serverType = 'Generic' ) + { + log ( '>>> New %s server #%s'.format ( _serverType, _server ) ); + + this.server = _server; + } + + getProcessedStatus ( ) + { + let status = this.status.service_status; + + this.columns = Preferences.getColumns(this.server); + this.sortOrder = Preferences.getSortOrder(this.server); + + log ( this.sortOrder ); + status = status.sort ( Lang.bind ( this, this.compareServices ) ); + + return status; + } + + + compareServices ( a, b ) + { + for ( let _comparison of this.sortOrder ) + { + let _name = _comparison.substring ( 0, _comparison.length - 1 ); + let _order = _comparison.substring ( _comparison.length - 1, _comparison.length ); + if ( _name && _order && _name in a && _name in b ) + { + let _result = a [ _name ] . localeCompare ( b [ _name ] ); + if ( _result != 0 ) + { + if ( _order == '-' ) + return - _result; + else + return _result; + } + } + } + return 0; + } +} diff --git a/servers/icinga.js b/servers/icinga.js index bf46a6f..bb34d84 100644 --- a/servers/icinga.js +++ b/servers/icinga.js @@ -27,14 +27,14 @@ const Lang = imports.lang; const Main = imports.ui.main; const Me = ExtensionUtils.getCurrentExtension(); const Preferences = Me.imports.prefs; +const GenericServer = Me.imports.servers.genericserver.GenericServer; let _httpSession; -class Icinga { +class Icinga extends GenericServer { constructor ( _server ) { - log ( '>>> New Icinga #' + _server ); - this.server = _server + super(_server, 'Icinga'); } refresh ( extension ) { diff --git a/servers/icinga2.js b/servers/icinga2.js index b78ea26..12f7d47 100644 --- a/servers/icinga2.js +++ b/servers/icinga2.js @@ -27,15 +27,15 @@ const Lang = imports.lang; const Main = imports.ui.main; const Me = ExtensionUtils.getCurrentExtension(); const Preferences = Me.imports.prefs; +const GenericServer = Me.imports.servers.genericserver.GenericServer; let _httpSession; -class Icinga2 { +class Icinga2 extends GenericServer { constructor ( _server ) { - log ( '>>> New Icinga2 #' + _server ); - this.server = _server - } + super(_server, 'Icinga2'); + } refresh ( extension ) { this.extension = extension;