|
From: <bu...@us...> - 2006-03-30 15:10:15
|
Revision: 593 Author: bugant Date: 2006-03-30 07:09:58 -0800 (Thu, 30 Mar 2006) ViewCVS: http://svn.sourceforge.net/yaacs/?rev=593&view=rev Log Message: ----------- * new monitoring GUI; you need to properly update your db in order to have it works. * share/paul.png is just a funny photo ;) you must copy it in /usr/share/yaacs; Added Paths: ----------- trunk/share/paul.png trunk/yamon.tcl Added: trunk/share/paul.png =================================================================== (Binary files differ) Property changes on: trunk/share/paul.png ___________________________________________________________________ Name: svn:mime-type + application/octet-stream Added: trunk/yamon.tcl =================================================================== --- trunk/yamon.tcl (rev 0) +++ trunk/yamon.tcl 2006-03-30 15:09:58 UTC (rev 593) @@ -0,0 +1,625 @@ +#!/bin/sh +# This line continues for Tcl, but is a single line for 'sh' \ +exec wish "$0" -- ${1+"$@"} + +# This source code file is part of the YaaCs package. +# +# Copyright (C) 2002-2006 YaaCers +# +# 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 (probably in a file named "LICENSE"); +# if not, write to: +# +# Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + +package require yaacs +package require tkyaacs + +namespace import msgcat::* + +namespace eval ::yamon { + variable showPjs 1 + + #tktable buttons' order stuff + + variable toggleUser true + variable togglePj true + variable toggleComp true + variable toggleRefu true + variable toggleCbac true + variable toggleOthe true + variable toggleMean true + + variable idPj "" + variable pjslist [list] + + variable minRows 6 + + variable noUser [mc "no operator monitored"] + variable oneUser [mc "operator monitored"] + variable usrCount [mc "operators monitored"] +} + +proc ::yamon::confDb {dbs dbi} { + ::yadb::disconnect $::yamon::db_int + ::yadb::disconnect $::yamon::db_sample + + set ::yamon::db_sample $dbs + set ::yamon::db_int $dbi +} + +proc ::yamon::sortTable {table col {decreasing false}} { + set tabVar [$table cget -variable] + set cols [$table cget -cols] + global $tabVar + + array set ord [array get [list]] + for {set i 1} {$i < [$table cget -rows]} {incr i} { + set it $::yamon::T($i,$col) + set ord($it,$i) [list $i [.c$i cget -variable]] + } + + array set oldT [array get $tabVar] + array set newT [array get $tabVar] + + if {! $decreasing} { + set ordList [lsort [array names ord]] + } else { + set ordList [lsort -decreasing [array names ord]] + } + + set r 1 + foreach k $ordList { + set idx [lindex $ord($k) 0] + set var [lindex $ord($k) 1] + for {set j 0} {$j < $cols} {incr j} { + set newT($r,$j) $oldT($idx,$j) + } + incr r + } + + array set $tabVar [array get newT] +} + +proc ::yamon::clearTable {} { + set cols [.t cget -cols] + for {set i 1} {$i < [.t cget -rows]} {incr i} { + for {set c 0} {$c < $cols} {incr c} { + set ::yamon::T($i,$c) "" + } + } +} + +proc ::yamon::fillInTable {} { + ::yamon::clearTable + if {$::yamon::idPj eq ""} { + return + } + + if {$::yamon::idPj eq "All"} { + set pjs [lrange $::yamon::idpjs 0 end] + } else { + set pjs [list $::yamon::idPj] + } + + set r 1 + foreach pj $pjs { + array unset proj + set proj [::admin::getDataPj $::yamon::db_sample $pj] + set users [::mon::activeUsers $::yamon::db_sample $pj] + if {$users == -1} { + continue + } + foreach u $users { + set id [lindex $u 0] + set touch [lindex $u 1] + set ip [lindex $u 2] + + array unset op + array set op [::op::getOpById $::yamon::db_int $id] + set perfs [::cati::perfIdxCalc $::yamon::db_sample $::yamon::db_int $pj $touch $id] + set ::yamon::T($r,0) $op(login) + set ::yamon::T($r,1) [lindex $proj $::admin::TITLE] + set ::yamon::T($r,2) [lindex $perfs 0] + set ::yamon::T($r,3) [lindex $perfs 1] + set ::yamon::T($r,4) [lindex $perfs 2] + set ::yamon::T($r,5) [lindex $perfs 3] + set meanTimeCompleted [::bbtools::meanCallTimeUser $::yamon::db_int $pj $id "statistiche" 8 $touch] + if {$meanTimeCompleted == -1} { + ::yalog::error "cannot get mean time for completed state for user " + continue + } + if {[llength $meanTimeCompleted] == 0} { + set meanTimeCompleted " -- " + } + set ::yamon::T($r,6) $meanTimeCompleted + set voip [::yamisc::voipEnabled $::yamon::db_int $ip] + switch -- $voip { + -1 {::yalog::error "cannot get voip status for $ip"} + false {set ::yamon::T($r,7) [mc "No"]} + true {set ::yamon::T($r,7) [mc "Yes"]} + } + set ::yamon::T($r,touch) $touch + incr r + } + } + + if {$r > $::yamon::minRows} { + .t configure -rows [expr $r + 1] + } else { + .t configure -rows $::yamon::minRows + } + + switch -exact -- $r { + 1 {set msg $::yamon::noUser} + 2 {set msg "1 $::yamon::oneUser"} + default {set msg "[expr $r - 1] $::yamon::userCount"} + } + + .fr.info configure -text $msg +} + +# command-line options handling + +proc ::yamon::cmderrmsg {msg opts usage} { + puts $msg + puts [::cmdline::usage $opts $usage] +} + +set parg [list "p.arg" "" [mc "project's id"]] +set oarg [list "c.arg" "/etc/yaacs/yaacs.conf" [mc "config file"]] +set larg [list "l.arg" "" [mc "log level"]] +set yamonoptions [list $parg $oarg $larg] + +set yamonusage "yamon: \[-p <project's id>\] \[-c <config file>\] \[-l <log level>\]" + +if { [catch {array set gettedopts [::cmdline::getoptions argv $yamonoptions $yamonusage]} err] } { + ::yamon::cmderrmsg "" $yamonoptions $yamonusage + exit 1 +} + +if { ($gettedopts(p) != "") && ( [string match {[0-9]*} $gettedopts(p)] != 1) } { + ::yamon::cmderrmsg [mc "error: project's id must be a number!"] $yamonoptions $yamonusage + exit 1 +} + +if { !([file exists $gettedopts(c)] && [file isfile $gettedopts(c)]) } { + set errf [mc "error: couldn't find %s" $gettedopts(c)] + ::yamon::cmderrmsg "$errf" $yamonoptions $yamonusage + exit 1 +} + +if {$gettedopts(p) != ""} { + set ::yamon::idPj $gettedopts(p) +} + +set yaacsHome [::yaconf::checkLocalConf] +array set ::yamon::config [::yaconf::conf $gettedopts(c)] +array set userconf [::yaconf::conf "$yaacsHome/yamon"] +foreach k [array names userconf] { + set ::yamon::config($k) $userconf($k) +} + +if {[info exists ::yamon::config(THEME)]} { + ::yatk_themes::init $::yamon::config(THEME) +} else { + ::yatk_themes::init +} + +#log settings + +#default settings + +::yalog::setFile [yaconf::getLogFile] +::yalog::setLevel error + +if { ($gettedopts(l)!="") } { + ::yalog::setLevel $gettedopts(l) + ::yalog::log $gettedopts(l) "Forcing log level to $gettedopts(l)" +} else { + if {[info exists ::yamon::config(LOG_LEVEL)] && ($::yamon::config(LOG_LEVEL)!="")} { + ::yalog::setLevel $::yamon::config(LOG_LEVEL) + } else { + ::yalog::setLevel error + ::yalog::error "No log level setting in yaacs.conf\ + log level setted to 'error'" + } +} + +# db(s) connection + +set ::yamon::db_sample [::yadb::connect $::yamon::config(DB_SAMPLE) $::yamon::config(HOST_SAMPLE) \ + $::yamon::config(USER_SAMPLE) $::yamon::config(PORT_SAMPLE)] +if {$::yamon::db_sample == -1} { + set msg "cannot connect to database $::yamon::config(DB_SAMPLE) hosted at $::yamon::config(HOST_SAMPLE) \ + (port $::yamon::config(PORT_SAMPLE)) via user $::yamon::config(USER_SAMPLE)" + ::yalog::error $dberr + puts $msg + exit 1 +} + +set ::yamon::db_int [::yadb::connect $::yamon::config(DB_INT) $::yamon::config(HOST_INT) $::yamon::config(USER_INT) $::yamon::config(PORT_INT)] +if {$::yamon::db_int == -1} { + set msg "cannot connect to database $::yamon::config(DB_INT) hosted at $::yamon::config(HOST_INT) \ + (port $::yamon::config(PORT_INT)) via user $::yamon::config(USER_INT)" + ::yalog::error $dberr + puts $msg + exit 1 +} + +set loss_sample { + ::yadb::disconnect $::yamon::db_sample + set ::yamon::db_sample [::yadb::connect $::yamon::config(DB_SAMPLE) $::yamon::config(HOST_SAMPLE) \ + $::yamon::config(USER_SAMPLE) $::yamon::config(PORT_SAMPLE)] + if {$::yamon::db_sample == -1} { + ::yalog::error "Connection to $::yamon::config(DB_SAMPLE) lost cannot be repaired. Exit." + ::yatk_dlg::error [mc "Connection to database lost cannot be repaired. \ + Please check your network availability and your db server's status. \ + It's safer exit now!"] + exit 1 + } + ::yadb::onConnectionLoss $::yamon::db_sample $loss_sample + ::yalog::debug "Connection lost on $::yamon::config(DB_SAMPLE) has been repaired (re-connection occurs).\ + You should check if everything is ok." +} + +set loss_int { + ::yadb::disconnect $::yamon::db_int + set ::yamon::db_int [::yadb::connect $::yamon::config(DB_INT) $::yamon::config(HOST_INT) \ + $::yamon::config(USER_INT) $::yamon::config(PORT_INT)] + if {$::yamon::db_int == -1} { + ::yalog::error "Connection to $::yamon::config(DB_INT) lost cannot be repaired. Exit." + ::yatk_dlg::error [mc "Connection to db lost but cannot be repaired. \ + Please check your network db server's status. \ + It's safer exit now!"] + exit 1 + } + ::yadb::onConnectionLoss $::yamon::db_int $loss_int + ::yalog::debug "Connection lost to $::yamon::config(DB_INT) has been repaired (re-connection occurs). \ + You should check if everything is ok." +} + +::yadb::onConnectionLoss $::yamon::db_sample $loss_sample +::yadb::onConnectionLoss $::yamon::db_int $loss_int + +# find out "interesting" projects + +set plist [::mon::onGoingPjs $::yamon::db_sample] +if {$plist == -1} { + ::yalog::error "cannot get on-going projects" + ::yatk_dlg::info [mc "Cannot get on-going projects. Check your network connection \ + and the database satus. If all the above are ok please report a bug to the project."] + exit 0 +} + +set ::yamon::pjslist [list] +set ::yamon::idpjs [list] +foreach p $plist { + lappend ::yamon::pjslist [lindex $p 1] + lappend ::yamon::idpjs [lindex $p 0] +} + +set ::yamon::pjslist [linsert $::yamon::pjslist 0 [mc "All"]] + +if {$::yamon::idPj ne ""} { + set ::yamon::showPjs 0 +} + +# GUI STUFF + +set fr [frame .fr] +set show [button $fr.show -relief groove -command { + switch -exact -- $::yamon::showPjs { + 1 { + .fr.show configure -image $::yatk_icons::sidehide + ::yatk_balloon::balloon .fr.show [mc "Hide projects' sidebar"] + grid .pjs + set ::yamon::showPjs 0 + } + 0 { + .fr.show configure -image $::yatk_icons::sideview + ::yatk_balloon::balloon .fr.show [mc "Show projects' sidebar"] + grid remove .pjs + set ::yamon::showPjs 1 + } + } + }] + +set refresh [button $fr.refresh -relief groove -image $::yatk_icons::refresh] +set info [label $fr.info -text $::yamon::noUser] +grid $show $refresh $info -padx 6 -pady 6 -ipadx 5 -ipady 5 -sticky nsw + +::yatk_balloon::balloon .fr.refresh [mc "Refresh"] + +set pref [button .pref -image $::yatk_icons::preferences -relief groove \ + -command {::yatk_settings::settings "yamon"}] + +set pjs [frame .pjs -relief solid -bd 2] +set pjslbl [label $pjs.lbl -text [mc "Choose a project"]] +set pjssb [scrollbar $pjs.sb -orient vertical -command {.pjs.list yview} -borderwidth 0 \ + -takefocus 0] +set pjslist [listbox $pjs.list -listvariable ::yamon::pjslist -bg white \ + -yscrollcommand {.pjs.sb set} -width 15] +bind $pjslist <<ListboxSelect>> { + set sel [.pjs.list curselection] + if {$sel == 0} { + set ::yamon::idPj "All" + } else { + set ::yamon::idPj [lindex $::yamon::idpjs [expr $sel - 1]] + } + ::yamon::fillInTable +} + +grid $pjslbl -pady 6 -padx 6 -sticky nw +grid $pjslist $pjssb -sticky nsw -pady [list 0 6] +grid configure $pjslist -padx [list 6 0] +grid configure $pjssb -padx [list 0 6] + +scrollbar .sb -orient vertical -command {.t yview} -borderwidth 0 \ + -takefocus 0 +table .t -rows $::yamon::minRows -cols 8 -state disable -variable ::yamon::T -titlerows 1 \ + -colstretchmode all -colwidth 12 -rowheight 2 -selecttype row -maxheight 200 \ + -yscrollcommand {.sb set} -bg white -wrap 1 -rowstretchmode all + +bind .t <Double-Button-1> { + set coord [.t curselection] + set coord [split $coord ,] + set r [lindex $coord 0] + set c [lindex $coord 1] + + set login $::yamon::T($r,0) + if {$login eq ""} { + return + } + + array set op [::op::getOpByLogin $::yamon::db_int $login] + if {[llength [array names op]] == 0} { + ::yalog::error "no user information available" + ::yatk_dlg::error "Cannot retrive details for this user. An error occured." + return + } + + if {$::yamon::idPj eq "All"} { + set pj [lindex $::yamon::idpjs [expr [lsearch -exact $::yamon::pjslist $::yamon::T($r,1)] - 1]] + } else { + set pj $::yamon::idPj + } + + array set cases [::bbtools::outcomeCases $::yamon::db_sample $::yamon::db_int $pj $op(id) $::yamon::T($r,touch)] + set com $cases(8) + set ref $cases(6) + set cal [expr $cases(7) + $cases(9)] + set oth [expr $cases(1) + $cases(2) + $cases(3) \ + + $cases(4) + $cases(5)] + + set pastData [::bbtools::lastNCompPerf $::yamon::db_int $op(id) 4] + set pastPerf [list] + set pastWhen [list] + + if {$pastData == -1} { + ::yalog::debug "cannot get past performance indexes. I'm going to set them to 0s" + set pastPerf [list 0 0 0 0] + set pastWhen [list "-" "-" "-" "-"] + + } else { + foreach p $pastData { + lappend pastPerf [lindex $p 0] + lappend pastWhen [lindex $p 1] + } + } + + set w .mondet + set title "yamon - $login" + + toplevel $w + wm title $w $title + wm iconname $w $title + wm transient $w [winfo toplevel [winfo parent $w]] + + set paul [file join $::yaconf::sharePath "paul.png"] + set pho [image create photo pho -file $paul] + label $w.photo -image $pho + label $w.lblLog -text [mc "User: "] + label $w.log -text $login + label $w.lblSur -text [mc "Surname: "] + label $w.sur -text $op(cognome) + label $w.lblNam -text [mc "Name: "] + label $w.nam -text $op(nome) + + label $w.lblPerf -text [mc "Performances"] + + set sumTab [table $w.idx -rows 5 -cols 3 -state disable -variable summ -titlerows 1 \ + -colstretchmode all -colwidth 20 -bg white -titlecols 0 -titlerows 1 \ + -selectmode extended] + + set summ(0,1) "Outcomes' cases" + set summ(0,2) "Performance Indexes" + set summ(1,0) "Completed" + set summ(2,0) "Refused" + set summ(3,0) "Call-back" + set summ(4,0) "Others" + + set summ(1,1) $com + set summ(1,2) $::yamon::T($r,2) + + set summ(2,1) $ref + set summ(2,2) $::yamon::T($r,3) + + set summ(3,1) $cal + set summ(3,2) $::yamon::T($r,4) + + set summ(4,1) $oth + set summ(4,2) $::yamon::T($r,5) + + label $w.lblStory -text [mc "Past 'Completed' performances"] + set pastTab [table $w.past -rows 5 -cols 2 -state disable -variable past -titlerows 1 \ + -colstretchmode all -colwidth 20 -bg white -titlecols 0 -titlerows 1 \ + -selectmode extended] + + set past(0,0) "Date/Time" + set past(0,1) "Completed performance" + + set past(1,0) [lindex $pastWhen 0] + set past(1,1) [lindex $pastPerf 0] + + set past(2,0) [lindex $pastWhen 1] + set past(2,1) [lindex $pastPerf 1] + + set past(3,0) [lindex $pastWhen 2] + set past(3,1) [lindex $pastPerf 2] + + set past(4,0) [lindex $pastWhen 3] + set past(4,1) [lindex $pastPerf 3] + + set nofr [frame $w.no] + label $nofr.lblNotes -text [mc "Operator's note"] + button $nofr.saveNotes -image $::yatk_icons::save -relief groove \ + -command { + set note [.mondet.notes get 0.0 end] + regsub -all \n $note " " note + set note [string trim $note] + if {[::op::updateOpNote $::yamon::db_int $op(id) $note] == -1} { + ::yalog::error "cannot save new note for user $op(id)." + ::yatk_dlg::error "Cannot save new note for $op(login)." + } else { + ::yatk_dlg::info "New note saved for $op(login)" + } + } + ::yatk_balloon::balloon $nofr.saveNotes [mc "Save operator's note"] + + grid $nofr.lblNotes $nofr.saveNotes -padx [list 0 3] -sticky nsw + grid configure $nofr.saveNotes -ipadx 5 -ipady 5 + + text $w.notes -height 4 -bg white + $w.notes insert 0.0 $op(note) + button $w.close -image $::yatk_icons::cancel -text [mc "Close"] \ + -compound left -command {destroy .mondet} + + grid $w.photo -padx 6 -pady 6 + grid ^ $w.lblLog $w.log -padx 6 -pady [list 12 6] -sticky nsw + grid ^ $w.lblSur $w.sur -padx 6 -pady 6 -sticky nsw + grid ^ $w.lblNam $w.nam -padx 6 -pady 6 -sticky nsw + grid $w.lblPerf - - -padx 6 -pady 12 -sticky nws + grid $sumTab - - -padx 6 -pady 6 -sticky news + grid $w.lblStory - - -padx 6 -pady 12 -sticky nws + grid $pastTab - - -padx 6 -pady 6 -sticky news + grid $nofr - - -padx 6 -pady [list 6 3] -sticky nsw + grid $w.notes - - -padx 6 -pady [list 3 6] -sticky news + grid $w.close - - -padx 6 -pady [list 24 6] -sticky se + + grid configure $w.lblLog -sticky nse + grid configure $w.lblSur -sticky nse + grid configure $w.lblNam -sticky nse +} + +set ::yamon::T(0,0) "User" +set ::yamon::T(0,1) "Project" +set ::yamon::T(0,2) "Completed" +set ::yamon::T(0,3) "Refused" +set ::yamon::T(0,4) "Call-back" +set ::yamon::T(0,5) "Other" +set ::yamon::T(0,6) "Mean time" +set ::yamon::T(0,7) "VoIP" + +button .use -text "User" -relief flat -bd 0 -bg grey -command { + if {$::yamon::toggleUser} { + set ::yamon::toggleUser false + } else { + set ::yamon::toggleUser true + } + ::yamon::sortTable .t 0 $::yamon::toggleUser +} + +button .pj -text "Project" -relief flat -bg grey -command { + if {$::yamon::togglePj} { + set ::yamon::togglePj false + } else { + set ::yamon::togglePj true + } + ::yamon::sortTable .t 1 $::yamon::togglePj +} + +button .comp -text "Completed" -relief flat -bg grey -command { + if {$::yamon::toggleComp} { + set ::yamon::toggleComp false + } else { + set ::yamon::toggleComp true + } + ::yamon::sortTable .t 2 $::yamon::toggleComp +} + +button .refu -text "Refused" -relief flat -bg grey -command { + if {$::yamon::toggleRefu} { + set ::yamon::toggleRefu false + } else { + set ::yamon::toggleRefu true + } + ::yamon::sortTable .t 3 $::yamon::toggleRefu +} + +button .cbac -text "Call-back" -relief flat -bg grey -command { + if {$::yamon::toggleCbac} { + set ::yamon::toggleCbac false + } else { + set ::yamon::toggleCbac true + } + ::yamon::sortTable .t 4 $::yamon::toggleCbac +} + +button .othe -text "Others" -relief flat -bg grey -command { + if {$::yamon::toggleOthe} { + set ::yamon::toggleOthe false + } else { + set ::yamon::toggleOthe true + } + ::yamon::sortTable .t 5 $::yamon::toggleOthe +} + +button .mean -text "Mean time" -relief flat -bg grey -command { + if {$::yamon::toggleMean} { + set ::yamon::toggleMean false + } else { + set ::yamon::toggleMean true + } + ::yamon::sortTable .t 6 $::yamon::toggleMean +} + +button .voip -text "VoIP" -relief flat -bg grey + +.t window configure 0,0 -window .use -bg grey -sticky news +.t window configure 0,1 -window .pj -bg grey -sticky news +.t window configure 0,2 -window .comp -bg grey -sticky news +.t window configure 0,3 -window .refu -bg grey -sticky news +.t window configure 0,4 -window .cbac -bg grey -sticky news +.t window configure 0,5 -window .othe -bg grey -sticky news +.t window configure 0,6 -window .mean -bg grey -sticky news +.t window configure 0,7 -window .voip -bg grey -sticky news + +button .quit -text Quit -image $::yatk_icons::exit \ + -command {exit} -compound left + +grid $fr - $pref -sticky nsw -padx 6 -pady 6 +grid $pjs .t .sb -pady 6 -sticky nws +grid .quit - - -sticky se -padx 6 -pady 12 + +grid configure $pjs -padx 6 -sticky nw +grid configure .t -padx [list 6 0] +grid configure .sb -padx [list 0 6] +grid configure $pref -ipadx 5 -ipady 5 -sticky we + +wm title . yamon +wm iconname . yamon + +.fr.show invoke +::yamon::fillInTable Property changes on: trunk/yamon.tcl ___________________________________________________________________ Name: svn:executable + * This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |