Implement column ordering + variable columns (need conf tool in the prfs window)

This commit is contained in:
Benjamin Drieu 2021-11-19 17:46:36 +01:00 committed by Benjamin Drieu
parent 0ab8b79ae1
commit 4a66c46042
6 changed files with 216 additions and 80 deletions

View File

@ -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 SETTINGS_SCHEMA_ACCOUNT_PATH = "/org/gnome/shell/extensions/monito/account";
const Convenience = Me.imports.convenience; const Convenience = Me.imports.convenience;
const GenericServer = Me.imports.servers.genericserver.GenericServer;
const Icinga = Me.imports.servers.icinga.Icinga; const Icinga = Me.imports.servers.icinga.Icinga;
const Icinga2 = Me.imports.servers.icinga2.Icinga2; const Icinga2 = Me.imports.servers.icinga2.Icinga2;
const Preferences = Me.imports.prefs; const Preferences = Me.imports.prefs;
@ -53,14 +54,14 @@ const Preferences = Me.imports.prefs;
let settings = Convenience.getSettings(SETTINGS_SCHEMA); let settings = Convenience.getSettings(SETTINGS_SCHEMA);
let account_settings = [ ]; let account_settings = [ ];
const column_definitions = [ const column_definitions = {
{ name: 'status', width: 50, expand: false, }, status: { label: _('Status'), width: 50, expand: false, },
{ name: 'host_name', width: 300, expand: false, }, host_name: { label: _('Host name'), width: 300, expand: false, },
{ name: 'service_display_name', width: 300, expand: false, }, service_display_name: { label: _('Service'), width: 300, expand: false, },
{ name: 'last_check', width: 200, expand: false, }, last_check: { label: _('Last check'), width: 200, expand: false, },
{ name: 'attempts', width: 50, expand: false, }, attempts: { label: _('Attempts'), width: 50, expand: false, },
{ name: 'status_information', width: 600, expand: true, }, status_information: { label: _('Information'), width: 600, expand: true, },
]; };
const Indicator = GObject.registerClass( const Indicator = GObject.registerClass(
@ -77,6 +78,16 @@ class Indicator extends PanelMenu.Button {
this.criticalBoxes = { }; this.criticalBoxes = { };
this.unknownBoxes = { }; 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 ( ); this.initUI ( );
} }
@ -85,32 +96,30 @@ class Indicator extends PanelMenu.Button {
this.add_child(box); this.add_child(box);
monitoLog ( '> Server ' + this.server ); 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' } ); let serverBox = new St.BoxLayout ( { style_class: 'monito-serverbox' } );
box.add_child(serverBox); box.add_child(serverBox);
let name_box = new St.BoxLayout( { style_class: 'monito-namebox' } ); 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 ] ); name_box.add_child ( this.namesBoxes [ this.server ] );
serverBox.add_child(name_box); 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 ); } ) ); 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' }); 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' ) ); warning_box.set_style ( 'background-color: ' + this.account_settings.get_string ( 'warning-color' ) );
_account_settings.connect("changed::warning-color", Lang.bind ( { widget: warning_box }, setColor ) ); this.account_settings.connect("changed::warning-color", Lang.bind ( { widget: warning_box }, setColor ) );
this.warningBoxes [ this.server ] = new St.Label({ text: String(_status['WARNING']) }) this.warningBoxes [ this.server ] = new St.Label({ text: String(_status['WARNING']) })
warning_box.add_child ( this.warningBoxes [ this.server ] ); warning_box.add_child ( this.warningBoxes [ this.server ] );
serverBox.add_child(warning_box); serverBox.add_child(warning_box);
let critical_box = new St.BoxLayout({ style_class: 'monito-critical-box monito-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' ) ); critical_box.set_style ( 'background-color: ' + this.account_settings.get_string ( 'critical-color' ) );
_account_settings.connect("changed::critical-color", Lang.bind ( { widget: critical_box }, setColor ) ); this.account_settings.connect("changed::critical-color", Lang.bind ( { widget: critical_box }, setColor ) );
this.criticalBoxes [ this.server ] = new St.Label({ text: String(_status['CRITICAL']) }) this.criticalBoxes [ this.server ] = new St.Label({ text: String(_status['CRITICAL']) })
critical_box.add_child ( this.criticalBoxes [ this.server ] ); critical_box.add_child ( this.criticalBoxes [ this.server ] );
@ -135,7 +144,7 @@ class Indicator extends PanelMenu.Button {
_iconBin.child = _icon; _iconBin.child = _icon;
this._buttonMenu.actor.add_actor(_iconBin); 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._buttonMenu.actor.add_actor(this._mainLabel);
this._prefsButton = this._createButton ( 'preferences-system-symbolic', 'Preferences', this._onPreferencesActivate ); this._prefsButton = this._createButton ( 'preferences-system-symbolic', 'Preferences', this._onPreferencesActivate );
@ -184,57 +193,63 @@ class Indicator extends PanelMenu.Button {
updateStatus ( ) updateStatus ( )
{ {
for ( let _server of Preferences.getServersList() ) if ( ! this.serverlogic.refresh ( this ) )
{ {
let _account_settings = Preferences.getAccountSettings ( this.server ); this.warningBoxes[this.server].set_text ( '…' );
this.criticalBoxes[this.server].set_text ( '…' );
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.setupTimeout ( ); this.setupTimeout ( );
} }
createHeaderBin ( status, text, col ) { createHeaderBin ( colName ) {
let _widths = [ 300, 300, 200, 50, 600 ]; let col = column_definitions [ colName ];
let _bin = new St.Bin({
style_class: 'monito-service-' + status, let _box = new St.BoxLayout ( { vertical: false,
width: col.width, x_expand: true } );
x_expand: col.expand, _box.add_child ( new St.Label ( { text: col.label,
child: new St.Button ( { 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, x_align: Clutter.ActorAlign.START,
y_align: Clutter.ActorAlign.CENTER, y_align: Clutter.ActorAlign.CENTER,
width: col.width, width: col.width,
reactive: true, reactive: true,
can_focus: true, can_focus: true,
track_hover: true, track_hover: true,
accessible_name: text, accessible_name: col.label,
style_class: 'button', 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; return _bin;
} }
@ -249,14 +264,14 @@ class Indicator extends PanelMenu.Button {
return _bin; return _bin;
} }
refreshUI ( serverLogic ) { refreshUI ( ) {
this.initStatus ( ); // Specialize ! this.initStatus ( );
this._box.remove_all_children(); 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; return;
} }
@ -265,8 +280,10 @@ class Indicator extends PanelMenu.Button {
x_expand: true x_expand: true
}); });
this._box.add_child(headerBox); 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, let scrollBox = new St.ScrollView ( { hscrollbar_policy: St.PolicyType.NEVER,
enable_mouse_scrolling: true, } ); enable_mouse_scrolling: true, } );
@ -279,29 +296,28 @@ class Indicator extends PanelMenu.Button {
}); });
scrollBox.add_actor(tableBox); 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 ] ++; _status [ entry.status ] ++;
if ( serverLogic.status.service_status[i].status != 'OK' ) if ( entry.status != 'OK' )
{ {
let infoBox = new St.BoxLayout({ 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, track_hover: true,
x_expand: true, x_expand: true,
}); });
tableBox.add_child(infoBox); 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, infoBox.add_child ( this.createBin ( entry.status, entry [ _col ], column_definitions [ _col ] ) );
serverLogic.status.service_status[i][col.name],
col ) );
} }
} }
} }
this.warningBoxes[serverLogic.server].set_text ( String(_status.WARNING) ); this.warningBoxes[this.serverlogic.server].set_text ( String(_status.WARNING) );
this.criticalBoxes[serverLogic.server].set_text ( String(_status.CRITICAL) ); this.criticalBoxes[this.serverlogic.server].set_text ( String(_status.CRITICAL) );
return; return;
} }
@ -319,6 +335,26 @@ class Indicator extends PanelMenu.Button {
return 0; 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 ) { _createButton ( icon, text, callback ) {
let button = new St.Button({ let button = new St.Button({
x_align: Clutter.ActorAlign.END, x_align: Clutter.ActorAlign.END,

View File

@ -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 ) function createAccountWidgets ( isActive )
{ {
// Accounts // Accounts

View File

@ -93,11 +93,11 @@
</key> </key>
<key name="columns" type="as"> <key name="columns" type="as">
<default>['service_description']</default> <default>['status','host_name','service_display_name','last_check','attempts','status_information']</default>
</key> </key>
<key name="columns-order" type="ai"> <key name="columns-order" type="as">
<default>[0]</default> <default>['host_name+','service_display_name+']</default>
</key> </key>
</schema> </schema>

76
servers/genericserver.js Normal file
View File

@ -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;
}
}

View File

@ -27,14 +27,14 @@ const Lang = imports.lang;
const Main = imports.ui.main; const Main = imports.ui.main;
const Me = ExtensionUtils.getCurrentExtension(); const Me = ExtensionUtils.getCurrentExtension();
const Preferences = Me.imports.prefs; const Preferences = Me.imports.prefs;
const GenericServer = Me.imports.servers.genericserver.GenericServer;
let _httpSession; let _httpSession;
class Icinga { class Icinga extends GenericServer {
constructor ( _server ) { constructor ( _server ) {
log ( '>>> New Icinga #' + _server ); super(_server, 'Icinga');
this.server = _server
} }
refresh ( extension ) { refresh ( extension ) {

View File

@ -27,15 +27,15 @@ const Lang = imports.lang;
const Main = imports.ui.main; const Main = imports.ui.main;
const Me = ExtensionUtils.getCurrentExtension(); const Me = ExtensionUtils.getCurrentExtension();
const Preferences = Me.imports.prefs; const Preferences = Me.imports.prefs;
const GenericServer = Me.imports.servers.genericserver.GenericServer;
let _httpSession; let _httpSession;
class Icinga2 { class Icinga2 extends GenericServer {
constructor ( _server ) { constructor ( _server ) {
log ( '>>> New Icinga2 #' + _server ); super(_server, 'Icinga2');
this.server = _server }
}
refresh ( extension ) { refresh ( extension ) {
this.extension = extension; this.extension = extension;